Skip to content

Commit ee8f7fc

Browse files
JunPiaoHWtorvalds
authored andcommitted
ocfs2/dlm: continue to purge recovery lockres when recovery master goes down
We found a dlm-blocked situation caused by continuous breakdown of recovery masters described below. To solve this problem, we should purge recovery lock once detecting recovery master goes down. N3 N2 N1(reco master) go down pick up recovery lock and begin recoverying for N2 go down pick up recovery lock failed, then purge it: dlm_purge_lockres ->DROPPING_REF is set send deref to N1 failed, recovery lock is not purged find N1 go down, begin recoverying for N1, but blocked in dlm_do_recovery as DROPPING_REF is set: dlm_do_recovery ->dlm_pick_recovery_master ->dlmlock ->dlm_get_lock_resource ->__dlm_wait_on_lockres_flags(tmpres, DLM_LOCK_RES_DROPPING_REF); Fixes: 8c03439 ("ocfs2/dlm: clear DROPPING_REF flag when the master goes down") Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Jun Piao <[email protected]> Reviewed-by: Joseph Qi <[email protected]> Reviewed-by: Jiufei Xue <[email protected]> Reviewed-by: Mark Fasheh <[email protected]> Cc: Joel Becker <[email protected]> Cc: Junxiao Bi <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 309e919 commit ee8f7fc

File tree

4 files changed

+74
-46
lines changed

4 files changed

+74
-46
lines changed

fs/ocfs2/dlm/dlmcommon.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,8 @@ int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data,
10041004
int dlm_do_master_requery(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
10051005
u8 nodenum, u8 *real_master);
10061006

1007+
void __dlm_do_purge_lockres(struct dlm_ctxt *dlm,
1008+
struct dlm_lock_resource *res);
10071009

10081010
int dlm_dispatch_assert_master(struct dlm_ctxt *dlm,
10091011
struct dlm_lock_resource *res,

fs/ocfs2/dlm/dlmmaster.c

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2425,51 +2425,20 @@ int dlm_deref_lockres_done_handler(struct o2net_msg *msg, u32 len, void *data,
24252425
mlog(ML_NOTICE, "%s:%.*s: node %u sends deref done "
24262426
"but it is already derefed!\n", dlm->name,
24272427
res->lockname.len, res->lockname.name, node);
2428-
dlm_lockres_put(res);
24292428
ret = 0;
24302429
goto done;
24312430
}
24322431

2433-
if (!list_empty(&res->purge)) {
2434-
mlog(0, "%s: Removing res %.*s from purgelist\n",
2435-
dlm->name, res->lockname.len, res->lockname.name);
2436-
list_del_init(&res->purge);
2437-
dlm_lockres_put(res);
2438-
dlm->purge_count--;
2439-
}
2440-
2441-
if (!__dlm_lockres_unused(res)) {
2442-
mlog(ML_ERROR, "%s: res %.*s in use after deref\n",
2443-
dlm->name, res->lockname.len, res->lockname.name);
2444-
__dlm_print_one_lock_resource(res);
2445-
BUG();
2446-
}
2447-
2448-
__dlm_unhash_lockres(dlm, res);
2449-
2450-
spin_lock(&dlm->track_lock);
2451-
if (!list_empty(&res->tracking))
2452-
list_del_init(&res->tracking);
2453-
else {
2454-
mlog(ML_ERROR, "%s: Resource %.*s not on the Tracking list\n",
2455-
dlm->name, res->lockname.len, res->lockname.name);
2456-
__dlm_print_one_lock_resource(res);
2457-
}
2458-
spin_unlock(&dlm->track_lock);
2459-
2460-
/* lockres is not in the hash now. drop the flag and wake up
2461-
* any processes waiting in dlm_get_lock_resource.
2462-
*/
2463-
res->state &= ~DLM_LOCK_RES_DROPPING_REF;
2432+
__dlm_do_purge_lockres(dlm, res);
24642433
spin_unlock(&res->spinlock);
24652434
wake_up(&res->wq);
24662435

2467-
dlm_lockres_put(res);
2468-
24692436
spin_unlock(&dlm->spinlock);
24702437

24712438
ret = 0;
24722439
done:
2440+
if (res)
2441+
dlm_lockres_put(res);
24732442
dlm_put(dlm);
24742443
return ret;
24752444
}

fs/ocfs2/dlm/dlmrecovery.c

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2343,6 +2343,7 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
23432343
struct dlm_lock_resource *res;
23442344
int i;
23452345
struct hlist_head *bucket;
2346+
struct hlist_node *tmp;
23462347
struct dlm_lock *lock;
23472348

23482349

@@ -2365,7 +2366,7 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
23652366
*/
23662367
for (i = 0; i < DLM_HASH_BUCKETS; i++) {
23672368
bucket = dlm_lockres_hash(dlm, i);
2368-
hlist_for_each_entry(res, bucket, hash_node) {
2369+
hlist_for_each_entry_safe(res, tmp, bucket, hash_node) {
23692370
/* always prune any $RECOVERY entries for dead nodes,
23702371
* otherwise hangs can occur during later recovery */
23712372
if (dlm_is_recovery_lock(res->lockname.name,
@@ -2386,8 +2387,17 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
23862387
break;
23872388
}
23882389
}
2389-
dlm_lockres_clear_refmap_bit(dlm, res,
2390-
dead_node);
2390+
2391+
if ((res->owner == dead_node) &&
2392+
(res->state & DLM_LOCK_RES_DROPPING_REF)) {
2393+
dlm_lockres_get(res);
2394+
__dlm_do_purge_lockres(dlm, res);
2395+
spin_unlock(&res->spinlock);
2396+
wake_up(&res->wq);
2397+
dlm_lockres_put(res);
2398+
continue;
2399+
} else if (res->owner == dlm->node_num)
2400+
dlm_lockres_clear_refmap_bit(dlm, res, dead_node);
23912401
spin_unlock(&res->spinlock);
23922402
continue;
23932403
}
@@ -2398,14 +2408,17 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
23982408
if (res->state & DLM_LOCK_RES_DROPPING_REF) {
23992409
mlog(0, "%s:%.*s: owned by "
24002410
"dead node %u, this node was "
2401-
"dropping its ref when it died. "
2402-
"continue, dropping the flag.\n",
2411+
"dropping its ref when master died. "
2412+
"continue, purging the lockres.\n",
24032413
dlm->name, res->lockname.len,
24042414
res->lockname.name, dead_node);
2415+
dlm_lockres_get(res);
2416+
__dlm_do_purge_lockres(dlm, res);
2417+
spin_unlock(&res->spinlock);
2418+
wake_up(&res->wq);
2419+
dlm_lockres_put(res);
2420+
continue;
24052421
}
2406-
res->state &= ~DLM_LOCK_RES_DROPPING_REF;
2407-
dlm_move_lockres_to_recovery_list(dlm,
2408-
res);
24092422
} else if (res->owner == dlm->node_num) {
24102423
dlm_free_dead_locks(dlm, res, dead_node);
24112424
__dlm_lockres_calc_usage(dlm, res);

fs/ocfs2/dlm/dlmthread.c

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,52 @@ void dlm_lockres_calc_usage(struct dlm_ctxt *dlm,
160160
spin_unlock(&dlm->spinlock);
161161
}
162162

163+
/*
164+
* Do the real purge work:
165+
* unhash the lockres, and
166+
* clear flag DLM_LOCK_RES_DROPPING_REF.
167+
* It requires dlm and lockres spinlock to be taken.
168+
*/
169+
void __dlm_do_purge_lockres(struct dlm_ctxt *dlm,
170+
struct dlm_lock_resource *res)
171+
{
172+
assert_spin_locked(&dlm->spinlock);
173+
assert_spin_locked(&res->spinlock);
174+
175+
if (!list_empty(&res->purge)) {
176+
mlog(0, "%s: Removing res %.*s from purgelist\n",
177+
dlm->name, res->lockname.len, res->lockname.name);
178+
list_del_init(&res->purge);
179+
dlm_lockres_put(res);
180+
dlm->purge_count--;
181+
}
182+
183+
if (!__dlm_lockres_unused(res)) {
184+
mlog(ML_ERROR, "%s: res %.*s in use after deref\n",
185+
dlm->name, res->lockname.len, res->lockname.name);
186+
__dlm_print_one_lock_resource(res);
187+
BUG();
188+
}
189+
190+
__dlm_unhash_lockres(dlm, res);
191+
192+
spin_lock(&dlm->track_lock);
193+
if (!list_empty(&res->tracking))
194+
list_del_init(&res->tracking);
195+
else {
196+
mlog(ML_ERROR, "%s: Resource %.*s not on the Tracking list\n",
197+
dlm->name, res->lockname.len, res->lockname.name);
198+
__dlm_print_one_lock_resource(res);
199+
}
200+
spin_unlock(&dlm->track_lock);
201+
202+
/*
203+
* lockres is not in the hash now. drop the flag and wake up
204+
* any processes waiting in dlm_get_lock_resource.
205+
*/
206+
res->state &= ~DLM_LOCK_RES_DROPPING_REF;
207+
}
208+
163209
static void dlm_purge_lockres(struct dlm_ctxt *dlm,
164210
struct dlm_lock_resource *res)
165211
{
@@ -176,10 +222,8 @@ static void dlm_purge_lockres(struct dlm_ctxt *dlm,
176222

177223
if (!master) {
178224
if (res->state & DLM_LOCK_RES_DROPPING_REF) {
179-
mlog(ML_NOTICE, "%s: res %.*s already in "
180-
"DLM_LOCK_RES_DROPPING_REF state\n",
181-
dlm->name, res->lockname.len,
182-
res->lockname.name);
225+
mlog(ML_NOTICE, "%s: res %.*s already in DLM_LOCK_RES_DROPPING_REF state\n",
226+
dlm->name, res->lockname.len, res->lockname.name);
183227
spin_unlock(&res->spinlock);
184228
return;
185229
}

0 commit comments

Comments
 (0)