- more 2.6.17 port work (still does not build)
[linux-flexiantxendom0-3.2.10.git] / fs / ocfs2 / cluster / user_heartbeat.c
1
2 /* The userspace cluster heartbeat directory will be populated with symbolic
3  * links to the nodes who are heartbeating in the given group */
4
5 #include <linux/configfs.h>
6 #include "heartbeat.h"
7 #include "tcp.h"
8 #include "nodemanager.h"
9
10 struct o2hb_user_region {
11         struct o2hb_heartbeat_resource hr_res;
12         unsigned long hr_live_bitmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
13 };
14
15 static inline struct o2hb_user_region *to_o2hb_user_region(struct o2hb_heartbeat_resource *hbres)
16 {
17         return container_of(hbres, struct o2hb_user_region, hr_res);
18 }
19
20 static inline struct o2hb_user_region *item_to_o2hb_user_region(struct config_item *item)
21 {
22         return to_o2hb_user_region(to_o2hb_heartbeat_resource(item));
23 }
24
25 static inline void o2hb_user_region_get(struct o2hb_user_region *region)
26 {
27         o2hb_heartbeat_resource_get(&region->hr_res);
28 }
29
30 static inline void o2hb_user_region_put(struct o2hb_user_region *region)
31 {
32         o2hb_heartbeat_resource_put(&region->hr_res);
33 }
34 static int o2hb_user_group_allow_link(struct config_item *src,
35                                       struct config_item *target)
36 {
37         struct o2nm_node *node = to_o2nm_node(target);
38         struct o2hb_user_region *hbr = item_to_o2hb_user_region(src);
39
40         struct o2hb_node_event event = {
41                 .hn_item = LIST_HEAD_INIT(event.hn_item),
42                 .hn_res = &hbr->hr_res,
43         };
44
45         /* Make sure the target is within the same cluster */
46         if (src->ci_parent->ci_parent != target->ci_parent->ci_parent)
47                 return -EPERM;
48
49         printk ("Node %s is up in group %s\n", target->ci_name, src->ci_name);
50
51         spin_lock(&o2hb_live_lock);
52         set_bit(node->nd_num, hbr->hr_live_bitmap);
53
54         /* also add a link back to the node */
55
56         /* Notify listeners that this node is up */
57         o2hb_queue_node_event(&event, O2HB_NODE_UP_CB, node, node->nd_num);
58         spin_unlock(&o2hb_live_lock);
59
60         o2hb_run_event_list (&event);
61
62         return 0;
63 }
64
65 static int o2hb_user_group_drop_link(struct config_item *src,
66                                      struct config_item *target)
67 {
68         struct o2nm_node *node = to_o2nm_node(target);
69         struct o2hb_user_region *hbr = item_to_o2hb_user_region(src);
70
71         struct o2hb_node_event event = {
72                 .hn_item = LIST_HEAD_INIT(event.hn_item),
73                 .hn_res = &hbr->hr_res,
74         };
75
76         /* Somehow notify listeners that this node is down */
77         printk ("Node %s is down in group %s\n", target->ci_name,
78                                                  src->ci_name);
79
80         spin_lock(&o2hb_live_lock);
81         clear_bit(node->nd_num, hbr->hr_live_bitmap);
82
83         /* Notify listeners that this node is down */
84         o2hb_queue_node_event (&event, O2HB_NODE_DOWN_CB, node, node->nd_num);
85         spin_unlock(&o2hb_live_lock);
86
87         o2hb_run_event_list (&event);
88
89         return 0;
90 }
91
92 static struct configfs_item_operations o2hb_user_region_ops = {
93         .allow_link     = o2hb_user_group_allow_link,
94         .drop_link      = o2hb_user_group_drop_link,
95 };
96
97 struct config_item_type o2hb_user_region_type = {
98         .ct_item_ops    = &o2hb_user_region_ops,
99         .ct_owner       = THIS_MODULE,
100 };
101
102 /* How to create a heartbeat region */
103 static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *group,
104                                                           const char *name)
105 {
106         struct o2hb_user_region *region;
107         struct config_item *ret = NULL;
108
109         region = kzalloc(sizeof (*region), GFP_KERNEL);
110         if (region == NULL)
111                 goto out;
112
113         /* mkdir <fs uuid> */
114         config_item_init_type_name(&region->hr_res.hr_item, name,
115                                     &o2hb_user_region_type);
116
117         ret = &region->hr_res.hr_item;
118
119 out:
120         if (ret == NULL)
121                 kfree(region);
122         return ret;
123 }
124
125 /* How to remove a heartbeat region */
126 static void o2hb_heartbeat_group_drop_item(struct config_group *group,
127                                            struct config_item *item)
128 {
129         config_item_put (item);
130 }
131
132 static struct configfs_group_operations o2hb_user_heartbeat_root_ops = {
133         .make_item      = o2hb_heartbeat_group_make_item,
134         .drop_item      = o2hb_heartbeat_group_drop_item,
135 };
136
137 static inline struct o2hb_user_region *o2hb_user_region_get_by_name(const char *resource)
138 {
139         struct o2hb_heartbeat_resource *hbr;
140         struct o2hb_user_region *region = NULL;
141
142         hbr = o2hb_heartbeat_resource_get_by_name(resource);
143         if (hbr != NULL)
144                 region = to_o2hb_user_region(hbr);
145
146         return region;
147 }
148
149 static int o2hb_user_fill_node_map(const char *resource, unsigned long *map,
150                                    size_t len)
151 {
152         struct o2hb_user_region *region;
153         if (resource == NULL)
154                 return -EINVAL;
155
156         if (len > BITS_TO_LONGS(O2NM_MAX_NODES) * sizeof (*map))
157                 return -EFAULT;
158
159         region = o2hb_user_region_get_by_name(resource);
160         if (region == NULL)
161                 return -ENOENT;
162
163         memcpy (map, region->hr_live_bitmap, len);
164
165         o2hb_user_region_put(region);
166
167         return 0;
168 }
169
170 static int o2hb_user_check_node_status(const char *resource, u8 node_num)
171 {
172         int ret = 0;
173
174         if (resource) {
175                 struct o2hb_user_region *region;
176                 region = o2hb_user_region_get_by_name(resource);
177                 if (region == NULL)
178                         goto out;
179
180                 ret = test_bit(node_num, region->hr_live_bitmap);
181                 o2hb_user_region_put(region);
182         } else {
183                 struct o2nm_node *node = o2nm_get_node_by_num(node_num);
184                 ret = (node && atomic_read(&node->nd_count));
185         }
186 out:
187         return ret;
188 }
189
190 static struct o2hb_heartbeat_group user_heartbeat_group = {
191         .hs_type = {
192                 .ct_group_ops   = &o2hb_user_heartbeat_root_ops,
193                 .ct_owner       = THIS_MODULE,
194         },
195         .hs_name                = "user",
196         .fill_node_map          = o2hb_user_fill_node_map,
197         .check_node_status      = o2hb_user_check_node_status,
198 };
199
200 static int __init o2hb_user_heartbeat_init(void)
201 {
202         return o2hb_register_heartbeat_group(&user_heartbeat_group);
203 }
204
205 static void __exit o2hb_user_heartbeat_exit(void)
206 {
207         o2hb_unregister_heartbeat_group(&user_heartbeat_group);
208 }
209
210 MODULE_AUTHOR("Novell");
211 MODULE_LICENSE("GPL");
212
213 module_init(o2hb_user_heartbeat_init);
214 module_exit(o2hb_user_heartbeat_exit);