aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dlm
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2006-05-02 13:34:03 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2006-05-02 13:34:03 -0400
commit97a35d1e5fab9ff8de27814082b78b2fc9ad94f0 (patch)
tree551025da17641ccc4df7378da2bb94cedfb2482e /fs/dlm
parentd2d7b8a2a756fb520792ca3db3abdeed9214ae5b (diff)
[DLM] fix grant_after_purge softlockup
In dlm_grant_after_purge() we were holding a hash table read_lock while calling put_rsb() which potentially removes the rsb from the hash table, taking the same lock in write. Fix this by flagging rsb's ahead of time that have been purged. Then iteratively read_lock the hash table, find a flagged rsb, unlock, process rsb. Signed-off-by: David Teigland <teigland@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/dlm')
-rw-r--r--fs/dlm/dlm_internal.h1
-rw-r--r--fs/dlm/lock.c42
-rw-r--r--fs/dlm/lock.h2
3 files changed, 30 insertions, 15 deletions
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index c3299020c8f3..149106f2b80f 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -280,6 +280,7 @@ enum rsb_flags {
280 RSB_NEW_MASTER, 280 RSB_NEW_MASTER,
281 RSB_NEW_MASTER2, 281 RSB_NEW_MASTER2,
282 RSB_RECOVER_CONVERT, 282 RSB_RECOVER_CONVERT,
283 RSB_LOCKS_PURGED,
283}; 284};
284 285
285static inline void rsb_set_flag(struct dlm_rsb *r, enum rsb_flags flag) 286static inline void rsb_set_flag(struct dlm_rsb *r, enum rsb_flags flag)
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index 85a0e73ba808..5f6963904107 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -3278,6 +3278,7 @@ static void purge_queue(struct dlm_rsb *r, struct list_head *queue,
3278 3278
3279 list_for_each_entry_safe(lkb, safe, queue, lkb_statequeue) { 3279 list_for_each_entry_safe(lkb, safe, queue, lkb_statequeue) {
3280 if (test(ls, lkb)) { 3280 if (test(ls, lkb)) {
3281 rsb_set_flag(r, RSB_LOCKS_PURGED);
3281 del_lkb(r, lkb); 3282 del_lkb(r, lkb);
3282 /* this put should free the lkb */ 3283 /* this put should free the lkb */
3283 if (!dlm_put_lkb(lkb)) 3284 if (!dlm_put_lkb(lkb))
@@ -3334,27 +3335,40 @@ int dlm_purge_locks(struct dlm_ls *ls)
3334 return 0; 3335 return 0;
3335} 3336}
3336 3337
3337int dlm_grant_after_purge(struct dlm_ls *ls) 3338static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket)
3339{
3340 struct dlm_rsb *r, *r_ret = NULL;
3341
3342 read_lock(&ls->ls_rsbtbl[bucket].lock);
3343 list_for_each_entry(r, &ls->ls_rsbtbl[bucket].list, res_hashchain) {
3344 if (!rsb_flag(r, RSB_LOCKS_PURGED))
3345 continue;
3346 hold_rsb(r);
3347 rsb_clear_flag(r, RSB_LOCKS_PURGED);
3348 r_ret = r;
3349 break;
3350 }
3351 read_unlock(&ls->ls_rsbtbl[bucket].lock);
3352 return r_ret;
3353}
3354
3355void dlm_grant_after_purge(struct dlm_ls *ls)
3338{ 3356{
3339 struct dlm_rsb *r; 3357 struct dlm_rsb *r;
3340 int i; 3358 int i;
3341 3359
3342 for (i = 0; i < ls->ls_rsbtbl_size; i++) { 3360 for (i = 0; i < ls->ls_rsbtbl_size; i++) {
3343 read_lock(&ls->ls_rsbtbl[i].lock); 3361 r = find_purged_rsb(ls, i);
3344 list_for_each_entry(r, &ls->ls_rsbtbl[i].list, res_hashchain) { 3362 if (!r)
3345 hold_rsb(r); 3363 continue;
3346 lock_rsb(r); 3364 lock_rsb(r);
3347 if (is_master(r)) { 3365 if (is_master(r)) {
3348 grant_pending_locks(r); 3366 grant_pending_locks(r);
3349 confirm_master(r, 0); 3367 confirm_master(r, 0);
3350 }
3351 unlock_rsb(r);
3352 put_rsb(r);
3353 } 3368 }
3354 read_unlock(&ls->ls_rsbtbl[i].lock); 3369 unlock_rsb(r);
3370 put_rsb(r);
3355 } 3371 }
3356
3357 return 0;
3358} 3372}
3359 3373
3360static struct dlm_lkb *search_remid_list(struct list_head *head, int nodeid, 3374static struct dlm_lkb *search_remid_list(struct list_head *head, int nodeid,
diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h
index bffab9c88b1d..56cdc073b1f6 100644
--- a/fs/dlm/lock.h
+++ b/fs/dlm/lock.h
@@ -25,7 +25,7 @@ void dlm_scan_rsbs(struct dlm_ls *ls);
25 25
26int dlm_purge_locks(struct dlm_ls *ls); 26int dlm_purge_locks(struct dlm_ls *ls);
27void dlm_purge_mstcpy_locks(struct dlm_rsb *r); 27void dlm_purge_mstcpy_locks(struct dlm_rsb *r);
28int dlm_grant_after_purge(struct dlm_ls *ls); 28void dlm_grant_after_purge(struct dlm_ls *ls);
29int dlm_recover_waiters_post(struct dlm_ls *ls); 29int dlm_recover_waiters_post(struct dlm_ls *ls);
30void dlm_recover_waiters_pre(struct dlm_ls *ls); 30void dlm_recover_waiters_pre(struct dlm_ls *ls);
31int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc); 31int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc);