aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2
diff options
context:
space:
mode:
authorKurt Hackel <kurt.hackel@oracle.com>2007-01-05 18:00:17 -0500
committerMark Fasheh <mark.fasheh@oracle.com>2007-02-07 15:00:57 -0500
commitddc09c8ddac8d0f170ba8caa8128801f358dccff (patch)
treebba638e3017266b87e165eb0312d0671164f8917 /fs/ocfs2
parentfaf0ec9f13defb57f4269ecb22ed86f2874ee89a (diff)
ocfs2_dlm: Fixes race between migrate and dirty
dlmthread was removing lockres' from the dirty list and resetting the dirty flag before shuffling the list. This patch retains the dirty state flag until the lists are shuffled. Signed-off-by: Kurt Hackel <kurt.hackel@oracle.com> Signed-off-by: Sunil Mushran <Sunil.Mushran@oracle.com> Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
Diffstat (limited to 'fs/ocfs2')
-rw-r--r--fs/ocfs2/dlm/dlmcommon.h1
-rw-r--r--fs/ocfs2/dlm/dlmmaster.c16
-rw-r--r--fs/ocfs2/dlm/dlmthread.c30
3 files changed, 33 insertions, 14 deletions
diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h
index 04048bb1a1bd..e95ecb2aaf14 100644
--- a/fs/ocfs2/dlm/dlmcommon.h
+++ b/fs/ocfs2/dlm/dlmcommon.h
@@ -223,6 +223,7 @@ static inline void __dlm_set_joining_node(struct dlm_ctxt *dlm,
223#define DLM_LOCK_RES_IN_PROGRESS 0x00000010 223#define DLM_LOCK_RES_IN_PROGRESS 0x00000010
224#define DLM_LOCK_RES_MIGRATING 0x00000020 224#define DLM_LOCK_RES_MIGRATING 0x00000020
225#define DLM_LOCK_RES_DROPPING_REF 0x00000040 225#define DLM_LOCK_RES_DROPPING_REF 0x00000040
226#define DLM_LOCK_RES_BLOCK_DIRTY 0x00001000
226 227
227/* max milliseconds to wait to sync up a network failure with a node death */ 228/* max milliseconds to wait to sync up a network failure with a node death */
228#define DLM_NODE_DEATH_WAIT_MAX (5 * 1000) 229#define DLM_NODE_DEATH_WAIT_MAX (5 * 1000)
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
index 251c48028ea3..a65a87726d6a 100644
--- a/fs/ocfs2/dlm/dlmmaster.c
+++ b/fs/ocfs2/dlm/dlmmaster.c
@@ -2707,8 +2707,15 @@ static int dlm_mark_lockres_migrating(struct dlm_ctxt *dlm,
2707 __dlm_lockres_reserve_ast(res); 2707 __dlm_lockres_reserve_ast(res);
2708 spin_unlock(&res->spinlock); 2708 spin_unlock(&res->spinlock);
2709 2709
2710 /* now flush all the pending asts.. hang out for a bit */ 2710 /* now flush all the pending asts */
2711 dlm_kick_thread(dlm, res); 2711 dlm_kick_thread(dlm, res);
2712 /* before waiting on DIRTY, block processes which may
2713 * try to dirty the lockres before MIGRATING is set */
2714 spin_lock(&res->spinlock);
2715 BUG_ON(res->state & DLM_LOCK_RES_BLOCK_DIRTY);
2716 res->state |= DLM_LOCK_RES_BLOCK_DIRTY;
2717 spin_unlock(&res->spinlock);
2718 /* now wait on any pending asts and the DIRTY state */
2712 wait_event(dlm->ast_wq, !dlm_lockres_is_dirty(dlm, res)); 2719 wait_event(dlm->ast_wq, !dlm_lockres_is_dirty(dlm, res));
2713 dlm_lockres_release_ast(dlm, res); 2720 dlm_lockres_release_ast(dlm, res);
2714 2721
@@ -2734,6 +2741,13 @@ again:
2734 mlog(0, "trying again...\n"); 2741 mlog(0, "trying again...\n");
2735 goto again; 2742 goto again;
2736 } 2743 }
2744 /* now that we are sure the MIGRATING state is there, drop
2745 * the unneded state which blocked threads trying to DIRTY */
2746 spin_lock(&res->spinlock);
2747 BUG_ON(!(res->state & DLM_LOCK_RES_BLOCK_DIRTY));
2748 BUG_ON(!(res->state & DLM_LOCK_RES_MIGRATING));
2749 res->state &= ~DLM_LOCK_RES_BLOCK_DIRTY;
2750 spin_unlock(&res->spinlock);
2737 2751
2738 /* did the target go down or die? */ 2752 /* did the target go down or die? */
2739 spin_lock(&dlm->spinlock); 2753 spin_lock(&dlm->spinlock);
diff --git a/fs/ocfs2/dlm/dlmthread.c b/fs/ocfs2/dlm/dlmthread.c
index baa99979904c..3b94e4dec351 100644
--- a/fs/ocfs2/dlm/dlmthread.c
+++ b/fs/ocfs2/dlm/dlmthread.c
@@ -95,7 +95,7 @@ int __dlm_lockres_has_locks(struct dlm_lock_resource *res)
95int __dlm_lockres_unused(struct dlm_lock_resource *res) 95int __dlm_lockres_unused(struct dlm_lock_resource *res)
96{ 96{
97 if (!__dlm_lockres_has_locks(res) && 97 if (!__dlm_lockres_has_locks(res) &&
98 list_empty(&res->dirty)) { 98 (list_empty(&res->dirty) && !(res->state & DLM_LOCK_RES_DIRTY))) {
99 /* try not to scan the bitmap unless the first two 99 /* try not to scan the bitmap unless the first two
100 * conditions are already true */ 100 * conditions are already true */
101 int bit = find_next_bit(res->refmap, O2NM_MAX_NODES, 0); 101 int bit = find_next_bit(res->refmap, O2NM_MAX_NODES, 0);
@@ -455,12 +455,17 @@ void __dlm_dirty_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res)
455 assert_spin_locked(&res->spinlock); 455 assert_spin_locked(&res->spinlock);
456 456
457 /* don't shuffle secondary queues */ 457 /* don't shuffle secondary queues */
458 if ((res->owner == dlm->node_num) && 458 if ((res->owner == dlm->node_num)) {
459 !(res->state & DLM_LOCK_RES_DIRTY)) { 459 if (res->state & (DLM_LOCK_RES_MIGRATING |
460 /* ref for dirty_list */ 460 DLM_LOCK_RES_BLOCK_DIRTY))
461 dlm_lockres_get(res); 461 return;
462 list_add_tail(&res->dirty, &dlm->dirty_list); 462
463 res->state |= DLM_LOCK_RES_DIRTY; 463 if (list_empty(&res->dirty)) {
464 /* ref for dirty_list */
465 dlm_lockres_get(res);
466 list_add_tail(&res->dirty, &dlm->dirty_list);
467 res->state |= DLM_LOCK_RES_DIRTY;
468 }
464 } 469 }
465} 470}
466 471
@@ -639,7 +644,7 @@ static int dlm_thread(void *data)
639 dlm_lockres_get(res); 644 dlm_lockres_get(res);
640 645
641 spin_lock(&res->spinlock); 646 spin_lock(&res->spinlock);
642 res->state &= ~DLM_LOCK_RES_DIRTY; 647 /* We clear the DLM_LOCK_RES_DIRTY state once we shuffle lists below */
643 list_del_init(&res->dirty); 648 list_del_init(&res->dirty);
644 spin_unlock(&res->spinlock); 649 spin_unlock(&res->spinlock);
645 spin_unlock(&dlm->spinlock); 650 spin_unlock(&dlm->spinlock);
@@ -663,10 +668,11 @@ static int dlm_thread(void *data)
663 /* it is now ok to move lockreses in these states 668 /* it is now ok to move lockreses in these states
664 * to the dirty list, assuming that they will only be 669 * to the dirty list, assuming that they will only be
665 * dirty for a short while. */ 670 * dirty for a short while. */
671 BUG_ON(res->state & DLM_LOCK_RES_MIGRATING);
666 if (res->state & (DLM_LOCK_RES_IN_PROGRESS | 672 if (res->state & (DLM_LOCK_RES_IN_PROGRESS |
667 DLM_LOCK_RES_MIGRATING |
668 DLM_LOCK_RES_RECOVERING)) { 673 DLM_LOCK_RES_RECOVERING)) {
669 /* move it to the tail and keep going */ 674 /* move it to the tail and keep going */
675 res->state &= ~DLM_LOCK_RES_DIRTY;
670 spin_unlock(&res->spinlock); 676 spin_unlock(&res->spinlock);
671 mlog(0, "delaying list shuffling for in-" 677 mlog(0, "delaying list shuffling for in-"
672 "progress lockres %.*s, state=%d\n", 678 "progress lockres %.*s, state=%d\n",
@@ -687,6 +693,7 @@ static int dlm_thread(void *data)
687 693
688 /* called while holding lockres lock */ 694 /* called while holding lockres lock */
689 dlm_shuffle_lists(dlm, res); 695 dlm_shuffle_lists(dlm, res);
696 res->state &= ~DLM_LOCK_RES_DIRTY;
690 spin_unlock(&res->spinlock); 697 spin_unlock(&res->spinlock);
691 698
692 dlm_lockres_calc_usage(dlm, res); 699 dlm_lockres_calc_usage(dlm, res);
@@ -697,11 +704,8 @@ in_progress:
697 /* if the lock was in-progress, stick 704 /* if the lock was in-progress, stick
698 * it on the back of the list */ 705 * it on the back of the list */
699 if (delay) { 706 if (delay) {
700 /* ref for dirty_list */
701 dlm_lockres_get(res);
702 spin_lock(&res->spinlock); 707 spin_lock(&res->spinlock);
703 list_add_tail(&res->dirty, &dlm->dirty_list); 708 __dlm_dirty_lockres(dlm, res);
704 res->state |= DLM_LOCK_RES_DIRTY;
705 spin_unlock(&res->spinlock); 709 spin_unlock(&res->spinlock);
706 } 710 }
707 dlm_lockres_put(res); 711 dlm_lockres_put(res);