diff options
| author | Sunil Mushran <sunil.mushran@oracle.com> | 2010-11-19 18:06:50 -0500 |
|---|---|---|
| committer | Joel Becker <joel.becker@oracle.com> | 2010-12-09 18:36:00 -0500 |
| commit | 388c4bcb4e63e88fb1f312a2f5f9eb2623afcf5b (patch) | |
| tree | a8688b4db823bddba613dff2c613260b2e92f23a /fs/ocfs2 | |
| parent | 771f8bc71c31c6bd103cdec283012253f352ab1c (diff) | |
ocfs2/dlm: Migrate lockres with no locks if it has a reference
o2dlm was not migrating resources with zero locks because it assumed that that
resource would get purged by dlm_thread. However, some usage patterns involve
creating and dropping locks at a high rate leading to the migrate thread seeing
zero locks but the purge thread seeing an active reference. When this happens,
the dlm_thread cannot purge the resource and the migrate thread sees no reason
to migrate that resource. The spell is broken when the migrate thread catches
the resource with a lock.
The fix is to make the migrate thread also consider the reference map.
This usage pattern can be triggered by userspace on userdlm locks and flocks.
Signed-off-by: Sunil Mushran <sunil.mushran@oracle.com>
Signed-off-by: Joel Becker <joel.becker@oracle.com>
Diffstat (limited to 'fs/ocfs2')
| -rw-r--r-- | fs/ocfs2/dlm/dlmmaster.c | 40 |
1 files changed, 27 insertions, 13 deletions
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index f564b0e5f80d..59f0f6bdfc62 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c | |||
| @@ -2346,7 +2346,8 @@ static void dlm_deref_lockres_worker(struct dlm_work_item *item, void *data) | |||
| 2346 | */ | 2346 | */ |
| 2347 | static int dlm_is_lockres_migrateable(struct dlm_ctxt *dlm, | 2347 | static int dlm_is_lockres_migrateable(struct dlm_ctxt *dlm, |
| 2348 | struct dlm_lock_resource *res, | 2348 | struct dlm_lock_resource *res, |
| 2349 | int *numlocks) | 2349 | int *numlocks, |
| 2350 | int *hasrefs) | ||
| 2350 | { | 2351 | { |
| 2351 | int ret; | 2352 | int ret; |
| 2352 | int i; | 2353 | int i; |
| @@ -2356,6 +2357,9 @@ static int dlm_is_lockres_migrateable(struct dlm_ctxt *dlm, | |||
| 2356 | 2357 | ||
| 2357 | assert_spin_locked(&res->spinlock); | 2358 | assert_spin_locked(&res->spinlock); |
| 2358 | 2359 | ||
| 2360 | *numlocks = 0; | ||
| 2361 | *hasrefs = 0; | ||
| 2362 | |||
| 2359 | ret = -EINVAL; | 2363 | ret = -EINVAL; |
| 2360 | if (res->owner == DLM_LOCK_RES_OWNER_UNKNOWN) { | 2364 | if (res->owner == DLM_LOCK_RES_OWNER_UNKNOWN) { |
| 2361 | mlog(0, "cannot migrate lockres with unknown owner!\n"); | 2365 | mlog(0, "cannot migrate lockres with unknown owner!\n"); |
| @@ -2386,7 +2390,13 @@ static int dlm_is_lockres_migrateable(struct dlm_ctxt *dlm, | |||
| 2386 | } | 2390 | } |
| 2387 | 2391 | ||
| 2388 | *numlocks = count; | 2392 | *numlocks = count; |
| 2389 | mlog(0, "migrateable lockres having %d locks\n", *numlocks); | 2393 | |
| 2394 | count = find_next_bit(res->refmap, O2NM_MAX_NODES, 0); | ||
| 2395 | if (count < O2NM_MAX_NODES) | ||
| 2396 | *hasrefs = 1; | ||
| 2397 | |||
| 2398 | mlog(0, "%s: res %.*s, Migrateable, locks %d, refs %d\n", dlm->name, | ||
| 2399 | res->lockname.len, res->lockname.name, *numlocks, *hasrefs); | ||
| 2390 | 2400 | ||
| 2391 | leave: | 2401 | leave: |
| 2392 | return ret; | 2402 | return ret; |
| @@ -2408,7 +2418,7 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm, | |||
| 2408 | const char *name; | 2418 | const char *name; |
| 2409 | unsigned int namelen; | 2419 | unsigned int namelen; |
| 2410 | int mle_added = 0; | 2420 | int mle_added = 0; |
| 2411 | int numlocks; | 2421 | int numlocks, hasrefs; |
| 2412 | int wake = 0; | 2422 | int wake = 0; |
| 2413 | 2423 | ||
| 2414 | if (!dlm_grab(dlm)) | 2424 | if (!dlm_grab(dlm)) |
| @@ -2417,13 +2427,13 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm, | |||
| 2417 | name = res->lockname.name; | 2427 | name = res->lockname.name; |
| 2418 | namelen = res->lockname.len; | 2428 | namelen = res->lockname.len; |
| 2419 | 2429 | ||
| 2420 | mlog(0, "migrating %.*s to %u\n", namelen, name, target); | 2430 | mlog(0, "%s: Migrating %.*s to %u\n", dlm->name, namelen, name, target); |
| 2421 | 2431 | ||
| 2422 | /* | 2432 | /* |
| 2423 | * ensure this lockres is a proper candidate for migration | 2433 | * ensure this lockres is a proper candidate for migration |
| 2424 | */ | 2434 | */ |
| 2425 | spin_lock(&res->spinlock); | 2435 | spin_lock(&res->spinlock); |
| 2426 | ret = dlm_is_lockres_migrateable(dlm, res, &numlocks); | 2436 | ret = dlm_is_lockres_migrateable(dlm, res, &numlocks, &hasrefs); |
| 2427 | if (ret < 0) { | 2437 | if (ret < 0) { |
| 2428 | spin_unlock(&res->spinlock); | 2438 | spin_unlock(&res->spinlock); |
| 2429 | goto leave; | 2439 | goto leave; |
| @@ -2431,10 +2441,8 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm, | |||
| 2431 | spin_unlock(&res->spinlock); | 2441 | spin_unlock(&res->spinlock); |
| 2432 | 2442 | ||
| 2433 | /* no work to do */ | 2443 | /* no work to do */ |
| 2434 | if (numlocks == 0) { | 2444 | if (numlocks == 0 && !hasrefs) |
| 2435 | mlog(0, "no locks were found on this lockres! done!\n"); | ||
| 2436 | goto leave; | 2445 | goto leave; |
| 2437 | } | ||
| 2438 | 2446 | ||
| 2439 | /* | 2447 | /* |
| 2440 | * preallocate up front | 2448 | * preallocate up front |
| @@ -2459,14 +2467,14 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm, | |||
| 2459 | * find a node to migrate the lockres to | 2467 | * find a node to migrate the lockres to |
| 2460 | */ | 2468 | */ |
| 2461 | 2469 | ||
| 2462 | mlog(0, "picking a migration node\n"); | ||
| 2463 | spin_lock(&dlm->spinlock); | 2470 | spin_lock(&dlm->spinlock); |
| 2464 | /* pick a new node */ | 2471 | /* pick a new node */ |
| 2465 | if (!test_bit(target, dlm->domain_map) || | 2472 | if (!test_bit(target, dlm->domain_map) || |
| 2466 | target >= O2NM_MAX_NODES) { | 2473 | target >= O2NM_MAX_NODES) { |
| 2467 | target = dlm_pick_migration_target(dlm, res); | 2474 | target = dlm_pick_migration_target(dlm, res); |
| 2468 | } | 2475 | } |
| 2469 | mlog(0, "node %u chosen for migration\n", target); | 2476 | mlog(0, "%s: res %.*s, Node %u chosen for migration\n", dlm->name, |
| 2477 | namelen, name, target); | ||
| 2470 | 2478 | ||
| 2471 | if (target >= O2NM_MAX_NODES || | 2479 | if (target >= O2NM_MAX_NODES || |
| 2472 | !test_bit(target, dlm->domain_map)) { | 2480 | !test_bit(target, dlm->domain_map)) { |
| @@ -2667,7 +2675,7 @@ int dlm_empty_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) | |||
| 2667 | { | 2675 | { |
| 2668 | int ret; | 2676 | int ret; |
| 2669 | int lock_dropped = 0; | 2677 | int lock_dropped = 0; |
| 2670 | int numlocks; | 2678 | int numlocks, hasrefs; |
| 2671 | 2679 | ||
| 2672 | spin_lock(&res->spinlock); | 2680 | spin_lock(&res->spinlock); |
| 2673 | if (res->owner != dlm->node_num) { | 2681 | if (res->owner != dlm->node_num) { |
| @@ -2681,8 +2689,8 @@ int dlm_empty_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) | |||
| 2681 | } | 2689 | } |
| 2682 | 2690 | ||
| 2683 | /* No need to migrate a lockres having no locks */ | 2691 | /* No need to migrate a lockres having no locks */ |
| 2684 | ret = dlm_is_lockres_migrateable(dlm, res, &numlocks); | 2692 | ret = dlm_is_lockres_migrateable(dlm, res, &numlocks, &hasrefs); |
| 2685 | if (ret >= 0 && numlocks == 0) { | 2693 | if (ret >= 0 && numlocks == 0 && !hasrefs) { |
| 2686 | spin_unlock(&res->spinlock); | 2694 | spin_unlock(&res->spinlock); |
| 2687 | goto leave; | 2695 | goto leave; |
| 2688 | } | 2696 | } |
| @@ -2915,6 +2923,12 @@ static u8 dlm_pick_migration_target(struct dlm_ctxt *dlm, | |||
| 2915 | } | 2923 | } |
| 2916 | queue++; | 2924 | queue++; |
| 2917 | } | 2925 | } |
| 2926 | |||
| 2927 | nodenum = find_next_bit(res->refmap, O2NM_MAX_NODES, 0); | ||
| 2928 | if (nodenum < O2NM_MAX_NODES) { | ||
| 2929 | spin_unlock(&res->spinlock); | ||
| 2930 | return nodenum; | ||
| 2931 | } | ||
| 2918 | spin_unlock(&res->spinlock); | 2932 | spin_unlock(&res->spinlock); |
| 2919 | mlog(0, "have not found a suitable target yet! checking domain map\n"); | 2933 | mlog(0, "have not found a suitable target yet! checking domain map\n"); |
| 2920 | 2934 | ||
