aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/cluster
diff options
context:
space:
mode:
authorSunil Mushran <sunil.mushran@oracle.com>2010-12-14 17:14:29 -0500
committerJoel Becker <joel.becker@oracle.com>2010-12-16 03:47:44 -0500
commit58a3158a5d17ddf4894db9e8ccaf92093ff8e42e (patch)
tree8d60017f95fccd425bb20c13a8b2e3bc7233d543 /fs/ocfs2/cluster
parentffee223a9af4c5124beb56fa5c84132949923d23 (diff)
ocfs2/cluster: Pin/unpin o2hb regions
This patch adds support for pinning o2hb regions in configfs. Pinning disallows a region to be cleanly stopped as long as it has an active dependent user (read o2dlm). In local heartbeat mode, the region uuid matching the domain name is pinned as long as the o2dlm domain is active. In global heartbeat mode, all regions are pinned as long as there is atleast one dependent user and the region count is 3 or less. All regions are unpinned if the number of dependent users is zero or region count is greater than 3. Signed-off-by: Sunil Mushran <sunil.mushran@oracle.com> Signed-off-by: Joel Becker <joel.becker@oracle.com>
Diffstat (limited to 'fs/ocfs2/cluster')
-rw-r--r--fs/ocfs2/cluster/heartbeat.c216
1 files changed, 178 insertions, 38 deletions
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index 9f21dd78536..ad2e41d6879 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -132,6 +132,33 @@ char *o2hb_heartbeat_mode_desc[O2HB_HEARTBEAT_NUM_MODES] = {
132unsigned int o2hb_dead_threshold = O2HB_DEFAULT_DEAD_THRESHOLD; 132unsigned int o2hb_dead_threshold = O2HB_DEFAULT_DEAD_THRESHOLD;
133unsigned int o2hb_heartbeat_mode = O2HB_HEARTBEAT_LOCAL; 133unsigned int o2hb_heartbeat_mode = O2HB_HEARTBEAT_LOCAL;
134 134
135/*
136 * o2hb_dependent_users tracks the number of registered callbacks that depend
137 * on heartbeat. o2net and o2dlm are two entities that register this callback.
138 * However only o2dlm depends on the heartbeat. It does not want the heartbeat
139 * to stop while a dlm domain is still active.
140 */
141unsigned int o2hb_dependent_users;
142
143/*
144 * In global heartbeat mode, all regions are pinned if there are one or more
145 * dependent users and the quorum region count is <= O2HB_PIN_CUT_OFF. All
146 * regions are unpinned if the region count exceeds the cut off or the number
147 * of dependent users falls to zero.
148 */
149#define O2HB_PIN_CUT_OFF 3
150
151/*
152 * In local heartbeat mode, we assume the dlm domain name to be the same as
153 * region uuid. This is true for domains created for the file system but not
154 * necessarily true for userdlm domains. This is a known limitation.
155 *
156 * In global heartbeat mode, we pin/unpin all o2hb regions. This solution
157 * works for both file system and userdlm domains.
158 */
159static int o2hb_region_pin(const char *region_uuid);
160static void o2hb_region_unpin(const char *region_uuid);
161
135/* Only sets a new threshold if there are no active regions. 162/* Only sets a new threshold if there are no active regions.
136 * 163 *
137 * No locking or otherwise interesting code is required for reading 164 * No locking or otherwise interesting code is required for reading
@@ -186,7 +213,9 @@ struct o2hb_region {
186 struct config_item hr_item; 213 struct config_item hr_item;
187 214
188 struct list_head hr_all_item; 215 struct list_head hr_all_item;
189 unsigned hr_unclean_stop:1; 216 unsigned hr_unclean_stop:1,
217 hr_item_pinned:1,
218 hr_item_dropped:1;
190 219
191 /* protected by the hr_callback_sem */ 220 /* protected by the hr_callback_sem */
192 struct task_struct *hr_task; 221 struct task_struct *hr_task;
@@ -702,6 +731,14 @@ static void o2hb_set_quorum_device(struct o2hb_region *reg,
702 config_item_name(&reg->hr_item)); 731 config_item_name(&reg->hr_item));
703 732
704 set_bit(reg->hr_region_num, o2hb_quorum_region_bitmap); 733 set_bit(reg->hr_region_num, o2hb_quorum_region_bitmap);
734
735 /*
736 * If global heartbeat active, unpin all regions if the
737 * region count > CUT_OFF
738 */
739 if (o2hb_pop_count(&o2hb_quorum_region_bitmap,
740 O2NM_MAX_REGIONS) > O2HB_PIN_CUT_OFF)
741 o2hb_region_unpin(NULL);
705} 742}
706 743
707static int o2hb_check_slot(struct o2hb_region *reg, 744static int o2hb_check_slot(struct o2hb_region *reg,
@@ -1316,6 +1353,8 @@ int o2hb_init(void)
1316 memset(o2hb_quorum_region_bitmap, 0, sizeof(o2hb_quorum_region_bitmap)); 1353 memset(o2hb_quorum_region_bitmap, 0, sizeof(o2hb_quorum_region_bitmap));
1317 memset(o2hb_failed_region_bitmap, 0, sizeof(o2hb_failed_region_bitmap)); 1354 memset(o2hb_failed_region_bitmap, 0, sizeof(o2hb_failed_region_bitmap));
1318 1355
1356 o2hb_dependent_users = 0;
1357
1319 return o2hb_debug_init(); 1358 return o2hb_debug_init();
1320} 1359}
1321 1360
@@ -2003,16 +2042,20 @@ static void o2hb_heartbeat_group_drop_item(struct config_group *group,
2003{ 2042{
2004 struct task_struct *hb_task; 2043 struct task_struct *hb_task;
2005 struct o2hb_region *reg = to_o2hb_region(item); 2044 struct o2hb_region *reg = to_o2hb_region(item);
2045 int quorum_region = 0;
2006 2046
2007 /* stop the thread when the user removes the region dir */ 2047 /* stop the thread when the user removes the region dir */
2008 spin_lock(&o2hb_live_lock); 2048 spin_lock(&o2hb_live_lock);
2009 if (o2hb_global_heartbeat_active()) { 2049 if (o2hb_global_heartbeat_active()) {
2010 clear_bit(reg->hr_region_num, o2hb_region_bitmap); 2050 clear_bit(reg->hr_region_num, o2hb_region_bitmap);
2011 clear_bit(reg->hr_region_num, o2hb_live_region_bitmap); 2051 clear_bit(reg->hr_region_num, o2hb_live_region_bitmap);
2052 if (test_bit(reg->hr_region_num, o2hb_quorum_region_bitmap))
2053 quorum_region = 1;
2012 clear_bit(reg->hr_region_num, o2hb_quorum_region_bitmap); 2054 clear_bit(reg->hr_region_num, o2hb_quorum_region_bitmap);
2013 } 2055 }
2014 hb_task = reg->hr_task; 2056 hb_task = reg->hr_task;
2015 reg->hr_task = NULL; 2057 reg->hr_task = NULL;
2058 reg->hr_item_dropped = 1;
2016 spin_unlock(&o2hb_live_lock); 2059 spin_unlock(&o2hb_live_lock);
2017 2060
2018 if (hb_task) 2061 if (hb_task)
@@ -2030,7 +2073,27 @@ static void o2hb_heartbeat_group_drop_item(struct config_group *group,
2030 if (o2hb_global_heartbeat_active()) 2073 if (o2hb_global_heartbeat_active())
2031 printk(KERN_NOTICE "o2hb: Heartbeat stopped on region %s\n", 2074 printk(KERN_NOTICE "o2hb: Heartbeat stopped on region %s\n",
2032 config_item_name(&reg->hr_item)); 2075 config_item_name(&reg->hr_item));
2076
2033 config_item_put(item); 2077 config_item_put(item);
2078
2079 if (!o2hb_global_heartbeat_active() || !quorum_region)
2080 return;
2081
2082 /*
2083 * If global heartbeat active and there are dependent users,
2084 * pin all regions if quorum region count <= CUT_OFF
2085 */
2086 spin_lock(&o2hb_live_lock);
2087
2088 if (!o2hb_dependent_users)
2089 goto unlock;
2090
2091 if (o2hb_pop_count(&o2hb_quorum_region_bitmap,
2092 O2NM_MAX_REGIONS) <= O2HB_PIN_CUT_OFF)
2093 o2hb_region_pin(NULL);
2094
2095unlock:
2096 spin_unlock(&o2hb_live_lock);
2034} 2097}
2035 2098
2036struct o2hb_heartbeat_group_attribute { 2099struct o2hb_heartbeat_group_attribute {
@@ -2216,63 +2279,138 @@ void o2hb_setup_callback(struct o2hb_callback_func *hc,
2216} 2279}
2217EXPORT_SYMBOL_GPL(o2hb_setup_callback); 2280EXPORT_SYMBOL_GPL(o2hb_setup_callback);
2218 2281
2219static struct o2hb_region *o2hb_find_region(const char *region_uuid) 2282/*
2283 * In local heartbeat mode, region_uuid passed matches the dlm domain name.
2284 * In global heartbeat mode, region_uuid passed is NULL.
2285 *
2286 * In local, we only pin the matching region. In global we pin all the active
2287 * regions.
2288 */
2289static int o2hb_region_pin(const char *region_uuid)
2220{ 2290{
2221 struct o2hb_region *p, *reg = NULL; 2291 int ret = 0, found = 0;
2292 struct o2hb_region *reg;
2293 char *uuid;
2222 2294
2223 assert_spin_locked(&o2hb_live_lock); 2295 assert_spin_locked(&o2hb_live_lock);
2224 2296
2225 list_for_each_entry(p, &o2hb_all_regions, hr_all_item) { 2297 list_for_each_entry(reg, &o2hb_all_regions, hr_all_item) {
2226 if (!strcmp(region_uuid, config_item_name(&p->hr_item))) { 2298 uuid = config_item_name(&reg->hr_item);
2227 reg = p; 2299
2228 break; 2300 /* local heartbeat */
2301 if (region_uuid) {
2302 if (strcmp(region_uuid, uuid))
2303 continue;
2304 found = 1;
2229 } 2305 }
2306
2307 if (reg->hr_item_pinned || reg->hr_item_dropped)
2308 goto skip_pin;
2309
2310 /* Ignore ENOENT only for local hb (userdlm domain) */
2311 ret = o2nm_depend_item(&reg->hr_item);
2312 if (!ret) {
2313 mlog(ML_CLUSTER, "Pin region %s\n", uuid);
2314 reg->hr_item_pinned = 1;
2315 } else {
2316 if (ret == -ENOENT && found)
2317 ret = 0;
2318 else {
2319 mlog(ML_ERROR, "Pin region %s fails with %d\n",
2320 uuid, ret);
2321 break;
2322 }
2323 }
2324skip_pin:
2325 if (found)
2326 break;
2230 } 2327 }
2231 2328
2232 return reg; 2329 return ret;
2233} 2330}
2234 2331
2235static int o2hb_region_get(const char *region_uuid) 2332/*
2333 * In local heartbeat mode, region_uuid passed matches the dlm domain name.
2334 * In global heartbeat mode, region_uuid passed is NULL.
2335 *
2336 * In local, we only unpin the matching region. In global we unpin all the
2337 * active regions.
2338 */
2339static void o2hb_region_unpin(const char *region_uuid)
2236{ 2340{
2237 int ret = 0;
2238 struct o2hb_region *reg; 2341 struct o2hb_region *reg;
2342 char *uuid;
2343 int found = 0;
2239 2344
2240 spin_lock(&o2hb_live_lock); 2345 assert_spin_locked(&o2hb_live_lock);
2241 2346
2242 reg = o2hb_find_region(region_uuid); 2347 list_for_each_entry(reg, &o2hb_all_regions, hr_all_item) {
2243 if (!reg) 2348 uuid = config_item_name(&reg->hr_item);
2244 ret = -ENOENT; 2349 if (region_uuid) {
2245 spin_unlock(&o2hb_live_lock); 2350 if (strcmp(region_uuid, uuid))
2351 continue;
2352 found = 1;
2353 }
2246 2354
2247 if (ret) 2355 if (reg->hr_item_pinned) {
2248 goto out; 2356 mlog(ML_CLUSTER, "Unpin region %s\n", uuid);
2357 o2nm_undepend_item(&reg->hr_item);
2358 reg->hr_item_pinned = 0;
2359 }
2360 if (found)
2361 break;
2362 }
2363}
2249 2364
2250 ret = o2nm_depend_this_node(); 2365static int o2hb_region_inc_user(const char *region_uuid)
2251 if (ret) 2366{
2252 goto out; 2367 int ret = 0;
2253 2368
2254 ret = o2nm_depend_item(&reg->hr_item); 2369 spin_lock(&o2hb_live_lock);
2255 if (ret)
2256 o2nm_undepend_this_node();
2257 2370
2258out: 2371 /* local heartbeat */
2372 if (!o2hb_global_heartbeat_active()) {
2373 ret = o2hb_region_pin(region_uuid);
2374 goto unlock;
2375 }
2376
2377 /*
2378 * if global heartbeat active and this is the first dependent user,
2379 * pin all regions if quorum region count <= CUT_OFF
2380 */
2381 o2hb_dependent_users++;
2382 if (o2hb_dependent_users > 1)
2383 goto unlock;
2384
2385 if (o2hb_pop_count(&o2hb_quorum_region_bitmap,
2386 O2NM_MAX_REGIONS) <= O2HB_PIN_CUT_OFF)
2387 ret = o2hb_region_pin(NULL);
2388
2389unlock:
2390 spin_unlock(&o2hb_live_lock);
2259 return ret; 2391 return ret;
2260} 2392}
2261 2393
2262static void o2hb_region_put(const char *region_uuid) 2394void o2hb_region_dec_user(const char *region_uuid)
2263{ 2395{
2264 struct o2hb_region *reg;
2265
2266 spin_lock(&o2hb_live_lock); 2396 spin_lock(&o2hb_live_lock);
2267 2397
2268 reg = o2hb_find_region(region_uuid); 2398 /* local heartbeat */
2399 if (!o2hb_global_heartbeat_active()) {
2400 o2hb_region_unpin(region_uuid);
2401 goto unlock;
2402 }
2269 2403
2270 spin_unlock(&o2hb_live_lock); 2404 /*
2405 * if global heartbeat active and there are no dependent users,
2406 * unpin all quorum regions
2407 */
2408 o2hb_dependent_users--;
2409 if (!o2hb_dependent_users)
2410 o2hb_region_unpin(NULL);
2271 2411
2272 if (reg) { 2412unlock:
2273 o2nm_undepend_item(&reg->hr_item); 2413 spin_unlock(&o2hb_live_lock);
2274 o2nm_undepend_this_node();
2275 }
2276} 2414}
2277 2415
2278int o2hb_register_callback(const char *region_uuid, 2416int o2hb_register_callback(const char *region_uuid,
@@ -2293,9 +2431,11 @@ int o2hb_register_callback(const char *region_uuid,
2293 } 2431 }
2294 2432
2295 if (region_uuid) { 2433 if (region_uuid) {
2296 ret = o2hb_region_get(region_uuid); 2434 ret = o2hb_region_inc_user(region_uuid);
2297 if (ret) 2435 if (ret) {
2436 mlog_errno(ret);
2298 goto out; 2437 goto out;
2438 }
2299 } 2439 }
2300 2440
2301 down_write(&o2hb_callback_sem); 2441 down_write(&o2hb_callback_sem);
@@ -2313,7 +2453,7 @@ int o2hb_register_callback(const char *region_uuid,
2313 up_write(&o2hb_callback_sem); 2453 up_write(&o2hb_callback_sem);
2314 ret = 0; 2454 ret = 0;
2315out: 2455out:
2316 mlog(ML_HEARTBEAT, "returning %d on behalf of %p for funcs %p\n", 2456 mlog(ML_CLUSTER, "returning %d on behalf of %p for funcs %p\n",
2317 ret, __builtin_return_address(0), hc); 2457 ret, __builtin_return_address(0), hc);
2318 return ret; 2458 return ret;
2319} 2459}
@@ -2324,7 +2464,7 @@ void o2hb_unregister_callback(const char *region_uuid,
2324{ 2464{
2325 BUG_ON(hc->hc_magic != O2HB_CB_MAGIC); 2465 BUG_ON(hc->hc_magic != O2HB_CB_MAGIC);
2326 2466
2327 mlog(ML_HEARTBEAT, "on behalf of %p for funcs %p\n", 2467 mlog(ML_CLUSTER, "on behalf of %p for funcs %p\n",
2328 __builtin_return_address(0), hc); 2468 __builtin_return_address(0), hc);
2329 2469
2330 /* XXX Can this happen _with_ a region reference? */ 2470 /* XXX Can this happen _with_ a region reference? */
@@ -2332,7 +2472,7 @@ void o2hb_unregister_callback(const char *region_uuid,
2332 return; 2472 return;
2333 2473
2334 if (region_uuid) 2474 if (region_uuid)
2335 o2hb_region_put(region_uuid); 2475 o2hb_region_dec_user(region_uuid);
2336 2476
2337 down_write(&o2hb_callback_sem); 2477 down_write(&o2hb_callback_sem);
2338 2478