[Ocfs2-devel] ocfs2/dlm: continue to purge recovery lockres when recovery master goes down

Joseph Qi joseph.qi at huawei.com
Sun Jul 10 19:09:21 PDT 2016


On 2016/7/10 18:04, piaojun wrote:
> 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: 8c0343968163 ("ocfs2/dlm: clear DROPPING_REF flag when the master goes down")
> Signed-off-by: Jun Piao <piaojun at huawei.com>
Looks good to me, thanks.

Thanks,
Joseph

> ---
>  fs/ocfs2/dlm/dlmcommon.h   |  2 ++
>  fs/ocfs2/dlm/dlmmaster.c   | 38 +++-----------------------------------
>  fs/ocfs2/dlm/dlmrecovery.c | 30 ++++++++++++++++++++++--------
>  fs/ocfs2/dlm/dlmthread.c   | 46 ++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 73 insertions(+), 43 deletions(-)
> 
> diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h
> index 004f2cb..3e3e9ba8 100644
> --- a/fs/ocfs2/dlm/dlmcommon.h
> +++ b/fs/ocfs2/dlm/dlmcommon.h
> @@ -1004,6 +1004,8 @@ int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data,
>  int dlm_do_master_requery(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
>  			  u8 nodenum, u8 *real_master);
>  
> +void __dlm_do_purge_lockres(struct dlm_ctxt *dlm,
> +		struct dlm_lock_resource *res);
>  
>  int dlm_dispatch_assert_master(struct dlm_ctxt *dlm,
>  			       struct dlm_lock_resource *res,
> diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
> index 8c84641..c0b560d 100644
> --- a/fs/ocfs2/dlm/dlmmaster.c
> +++ b/fs/ocfs2/dlm/dlmmaster.c
> @@ -2425,51 +2425,19 @@ int dlm_deref_lockres_done_handler(struct o2net_msg *msg, u32 len, void *data,
>  		mlog(ML_NOTICE, "%s:%.*s: node %u sends deref done "
>  			"but it is already derefed!\n", dlm->name,
>  			res->lockname.len, res->lockname.name, node);
> -		dlm_lockres_put(res);
>  		goto done;
>  	}
> -
> -	if (!list_empty(&res->purge)) {
> -		mlog(0, "%s: Removing res %.*s from purgelist\n",
> -			dlm->name, res->lockname.len, res->lockname.name);
> -		list_del_init(&res->purge);
> -		dlm_lockres_put(res);
> -		dlm->purge_count--;
> -	}
> -
> -	if (!__dlm_lockres_unused(res)) {
> -		mlog(ML_ERROR, "%s: res %.*s in use after deref\n",
> -			dlm->name, res->lockname.len, res->lockname.name);
> -		__dlm_print_one_lock_resource(res);
> -		BUG();
> -	}
> -
> -	__dlm_unhash_lockres(dlm, res);
> -
> -	spin_lock(&dlm->track_lock);
> -	if (!list_empty(&res->tracking))
> -		list_del_init(&res->tracking);
> -	else {
> -		mlog(ML_ERROR, "%s: Resource %.*s not on the Tracking list\n",
> -		     dlm->name, res->lockname.len, res->lockname.name);
> -		__dlm_print_one_lock_resource(res);
> -	}
> -	spin_unlock(&dlm->track_lock);
> -
> -	/* lockres is not in the hash now. drop the flag and wake up
> -	 * any processes waiting in dlm_get_lock_resource.
> -	 */
> -	res->state &= ~DLM_LOCK_RES_DROPPING_REF;
> +	__dlm_do_purge_lockres(dlm, res);
>  	spin_unlock(&res->spinlock);
>  	wake_up(&res->wq);
>  
> -	dlm_lockres_put(res);
> -
>  	spin_unlock(&dlm->spinlock);
>  
>  	ret = 0;
>  
>  done:
> +	if (res)
> +		dlm_lockres_put(res);
>  	dlm_put(dlm);
>  	return ret;
>  }
> diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
> index f6b3138..d926887 100644
> --- a/fs/ocfs2/dlm/dlmrecovery.c
> +++ b/fs/ocfs2/dlm/dlmrecovery.c
> @@ -2343,6 +2343,7 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
>  	struct dlm_lock_resource *res;
>  	int i;
>  	struct hlist_head *bucket;
> +	struct hlist_node *tmp;
>  	struct dlm_lock *lock;
>  
>  
> @@ -2365,7 +2366,7 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
>  	 */
>  	for (i = 0; i < DLM_HASH_BUCKETS; i++) {
>  		bucket = dlm_lockres_hash(dlm, i);
> -		hlist_for_each_entry(res, bucket, hash_node) {
> +		hlist_for_each_entry_safe(res, tmp, bucket, hash_node) {
>   			/* always prune any $RECOVERY entries for dead nodes,
>   			 * otherwise hangs can occur during later recovery */
>  			if (dlm_is_recovery_lock(res->lockname.name,
> @@ -2386,8 +2387,18 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
>  						break;
>  					}
>  				}
> -				dlm_lockres_clear_refmap_bit(dlm, res,
> -						dead_node);
> +
> +				if ((res->owner == dead_node) &&
> +				    (res->state & DLM_LOCK_RES_DROPPING_REF)) {
> +					dlm_lockres_get(res);
> +					__dlm_do_purge_lockres(dlm, res);
> +					spin_unlock(&res->spinlock);
> +					wake_up(&res->wq);
> +					dlm_lockres_put(res);
> +					continue;
> +				} else if (res->owner == dlm->node_num)
> +					dlm_lockres_clear_refmap_bit(dlm, res,
> +					    dead_node);
>  				spin_unlock(&res->spinlock);
>  				continue;
>  			}
> @@ -2398,14 +2409,17 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
>  				if (res->state & DLM_LOCK_RES_DROPPING_REF) {
>  					mlog(0, "%s:%.*s: owned by "
>  						"dead node %u, this node was "
> -						"dropping its ref when it died. "
> -						"continue, dropping the flag.\n",
> +						"dropping its ref when master died. "
> +						"continue, purging the lockres.\n",
>  						dlm->name, res->lockname.len,
>  						res->lockname.name, dead_node);
> +					dlm_lockres_get(res);
> +					__dlm_do_purge_lockres(dlm, res);
> +					spin_unlock(&res->spinlock);
> +					wake_up(&res->wq);
> +					dlm_lockres_put(res);
> +					continue;
>  				}
> -				res->state &= ~DLM_LOCK_RES_DROPPING_REF;
> -				dlm_move_lockres_to_recovery_list(dlm,
> -						res);
>  			} else if (res->owner == dlm->node_num) {
>  				dlm_free_dead_locks(dlm, res, dead_node);
>  				__dlm_lockres_calc_usage(dlm, res);
> diff --git a/fs/ocfs2/dlm/dlmthread.c b/fs/ocfs2/dlm/dlmthread.c
> index ce39722..a63e915 100644
> --- a/fs/ocfs2/dlm/dlmthread.c
> +++ b/fs/ocfs2/dlm/dlmthread.c
> @@ -160,6 +160,52 @@ void dlm_lockres_calc_usage(struct dlm_ctxt *dlm,
>  	spin_unlock(&dlm->spinlock);
>  }
>  
> +/*
> + * Do the real purge work:
> + *     unhash the lockres, and
> + *     clear flag DLM_LOCK_RES_DROPPING_REF.
> + * It requires dlm and lockres spinlock to be taken.
> + */
> +void __dlm_do_purge_lockres(struct dlm_ctxt *dlm,
> +		struct dlm_lock_resource *res)
> +{
> +	assert_spin_locked(&dlm->spinlock);
> +	assert_spin_locked(&res->spinlock);
> +
> +	if (!list_empty(&res->purge)) {
> +		mlog(0, "%s: Removing res %.*s from purgelist\n",
> +		     dlm->name, res->lockname.len, res->lockname.name);
> +		list_del_init(&res->purge);
> +		dlm_lockres_put(res);
> +		dlm->purge_count--;
> +	}
> +
> +	if (!__dlm_lockres_unused(res)) {
> +		mlog(ML_ERROR, "%s: res %.*s in use after deref\n",
> +		     dlm->name, res->lockname.len, res->lockname.name);
> +		__dlm_print_one_lock_resource(res);
> +		BUG();
> +	}
> +
> +	__dlm_unhash_lockres(dlm, res);
> +
> +	spin_lock(&dlm->track_lock);
> +	if (!list_empty(&res->tracking))
> +		list_del_init(&res->tracking);
> +	else {
> +		mlog(ML_ERROR, "%s: Resource %.*s not on the Tracking list\n",
> +		     dlm->name, res->lockname.len, res->lockname.name);
> +		__dlm_print_one_lock_resource(res);
> +	}
> +	spin_unlock(&dlm->track_lock);
> +
> +	/*
> +	 * lockres is not in the hash now. drop the flag and wake up
> +	 * any processes waiting in dlm_get_lock_resource.
> +	 */
> +	res->state &= ~DLM_LOCK_RES_DROPPING_REF;
> +}
> +
>  static void dlm_purge_lockres(struct dlm_ctxt *dlm,
>  			     struct dlm_lock_resource *res)
>  {
> 





More information about the Ocfs2-devel mailing list