[Ocfs2-devel] [PATCH] o2dlm: check lockres validity in createlock

Sunil Mushran sunil.mushran at oracle.com
Wed May 11 12:06:48 PDT 2011


On 05/11/2011 08:38 AM, Sunil Mushran wrote:
> On 05/11/2011 04:47 AM, Wengang Wang wrote:
>> When we are to purge a lockres, we check if it's unused.
>> the check includes
>> 1. no locks attached to the lockres.
>> 2. not dirty.
>> 3. not in recovery.
>> 4. no interested nodes in refmap.
>> If the the above four are satisfied, we are going to purge it(remove it
>> from hash table).
>>
>> While, when a "create lock" is in progress especially when lockres is owned
>> remotely(spinlocks are dropped when networking), the lockres can satisfy above
>> four condition. If it's put to purge list, it can be purged out from hash table
>> when we are still accessing on it(sending request to owner for example). That's
>> not what we want.
> Create lock follows master query. And in master query handler we add
> the node to the refmap. That's the race refmap was created to close.
> Meaning we should not run into this condition.
>
> Which version did this problem reproduce in?
>
>> I have met such a problem (orabug 12405575).
>> The lockres is in the purge list already(there is a delay for real purge work)
>> and the create lock request comes. When we are sending network message to the
>> owner in dlmlock_remote(), the owner crashed. So we get DLM_RECOVERING as return
>> value and retries dlmlock_remote(). And before the owner crash, we have purged
>> the lockres. So the lockres become stale(on lockres->onwer). Thus the code calls
>> dlmlock_remote() infinitely.


Oh a remote master. So ignore my previous reply.

Yes, I can see the race. But the fix below lets the purge to continue
and handles it afterwards. A better approach (and more efficient)
would be to remove the lockres from the purge list itself.

So the race window is between the first block in dlm_get_lock_resource()
and dlm_lock_remote().

See dlm->inflight_locks. Currently we use this when lockres is locally
mastered. Maybe we could use the same for locally mastered too.


>> fix 1
>> This patch tries to fix it by checking if the lockres is still valid(in hash table)
>> before make request on it for each retry. It passed regression test.
>>
>> fix 2
>> Another approch(not in this patch) is that we remove the lockres from purge list if
>> it's there in dlm_get_lock_resource() which is called for only createlock case. So
>> that the lockres can't be purged when we are in progress of createlock.
>> I didn't test it.
>>
>> I think fix 1 is the safer and fix 2 is the better. I choosed fix 1.
>>
>> Sunil, what's your comment?
>>
>> Signed-off-by: Wengang Wang<wen.gang.wang at oracle.com>
>> ---
>>    fs/ocfs2/dlm/dlmlock.c |   28 ++++++++++++++++++++++++++++
>>    1 files changed, 28 insertions(+), 0 deletions(-)
>>
>> diff --git a/fs/ocfs2/dlm/dlmlock.c b/fs/ocfs2/dlm/dlmlock.c
>> index 8d39e0f..02abaa1 100644
>> --- a/fs/ocfs2/dlm/dlmlock.c
>> +++ b/fs/ocfs2/dlm/dlmlock.c
>> @@ -570,6 +570,7 @@ enum dlm_status dlmlock(struct dlm_ctxt *dlm, int mode,
>>    	struct dlm_lock_resource *res = NULL;
>>    	struct dlm_lock *lock = NULL;
>>    	int convert = 0, recovery = 0;
>> +	bool lockres_purged = false;
>>
>>    	/* yes this function is a mess.
>>    	 * TODO: clean this up.  lots of common code in the
>> @@ -681,6 +682,7 @@ retry_convert:
>>    		if (!recovery)
>>    			dlm_wait_for_recovery(dlm);
>>
>> +lookup_res:
>>    		/* find or create the lock resource */
>>    		res = dlm_get_lock_resource(dlm, name, namelen, flags);
>>    		if (!res) {
>> @@ -698,6 +700,32 @@ retry_convert:
>>    		lock->astdata = data;
>>
>>    retry_lock:
>> +		/* there is a chance that the lockres is already be purged out
>> +		 * from the hash table and it can become a stale one. obviously
>> +		 * accessing on a stale lockres is not what we want. the case
>> +		 * we ever see is the owner dead(recovery didn't take care of
>> +		 * this lockres since it's not in hashtable), and the code keep
>> +		 * sending request to the dead node and getting DLM_RECOVERING
>> +		 * and then retrying infinitely.
>> +		 * we check if the lockres has been purged here and redo the
>> +		 * lookup if it has been to avoid infinite loop.
>> +		 */
>> +		lockres_purged = false;
>> +		spin_lock(&dlm->spinlock);
>> +		spin_lock(&res->spinlock);
>> +		if (unlikely(hlist_unhashed(&res->hash_node))) {
>> +			lockres_purged = true;
>> +		}
>> +		spin_unlock(&res->spinlock);
>> +		spin_unlock(&dlm->spinlock);
>> +		if (lockres_purged) {
>> +			dlm_lock_detach_lockres(lock);
>> +			mlog(ML_NOTICE, "going to relookup lockres %.*s\n", res->lockname.len, res->lockname.name);
>> +			dlm_lockres_put(res);
>> +			res = NULL;
>> +			goto lookup_res;
>> +		}
>> +
>>    		if (flags&   LKM_VALBLK) {
>>    			mlog(0, "LKM_VALBLK passed by caller\n");
>>
>
> _______________________________________________
> Ocfs2-devel mailing list
> Ocfs2-devel at oss.oracle.com
> http://oss.oracle.com/mailman/listinfo/ocfs2-devel




More information about the Ocfs2-devel mailing list