[Ocfs2-devel] [PATCH 2/6] ocfs2/dlm: Add missing dlm_lockres_put()s in migration path

Joel Becker Joel.Becker at oracle.com
Sun Mar 2 18:14:30 PST 2008


On Sat, Mar 01, 2008 at 02:04:21PM -0800, Sunil Mushran wrote:
> During migration, the recovery master node may be asked to master a lockres
> it may not know about. In that case, it would not only have to create a
> lockres and add it to the hash, but also remember to to do the _put_
> corresponding to the kref_init in dlm_init_lockres(), as soon as the migration
> is completed. Yes, we don't wait for the dlm_purge_lockres() to do that
> matching put. Note the ref added for it being in the hash protects the lockres
> from being freed prematurely.
> 
> This patch adds that missing put, as described above, to plug a memleak.
> 
> Signed-off-by: Sunil Mushran <sunil.mushran at oracle.com>
Signed-off-by: Joel Becker <joel.becker at oracle.com>

> ---
>  fs/ocfs2/dlm/dlmcommon.h   |    1 +
>  fs/ocfs2/dlm/dlmrecovery.c |   40 ++++++++++++++++++++++++++++++++++------
>  2 files changed, 35 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h
> index 9843ee1..5b3607c 100644
> --- a/fs/ocfs2/dlm/dlmcommon.h
> +++ b/fs/ocfs2/dlm/dlmcommon.h
> @@ -176,6 +176,7 @@ struct dlm_mig_lockres_priv
>  {
>  	struct dlm_lock_resource *lockres;
>  	u8 real_master;
> +	u8 extra_ref;
>  };
>  
>  struct dlm_assert_master_priv
> diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
> index 8ef57c2..23e7b49 100644
> --- a/fs/ocfs2/dlm/dlmrecovery.c
> +++ b/fs/ocfs2/dlm/dlmrecovery.c
> @@ -1327,6 +1327,7 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data,
>  		(struct dlm_migratable_lockres *)msg->buf;
>  	int ret = 0;
>  	u8 real_master;
> +	u8 extra_refs = 0;
>  	char *buf = NULL;
>  	struct dlm_work_item *item = NULL;
>  	struct dlm_lock_resource *res = NULL;
> @@ -1404,16 +1405,28 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data,
>  		__dlm_insert_lockres(dlm, res);
>  		spin_unlock(&dlm->spinlock);
>  
> +		/* Add an extra ref for this lock-less lockres lest the
> +		 * dlm_thread purges it before we get the chance to add
> +		 * locks to it */
> +		dlm_lockres_get(res);
> +
> +		/* There are three refs that need to be put.
> +		 * 1. Taken above.
> +		 * 2. kref_init in dlm_new_lockres()->dlm_init_lockres().
> +		 * 3. dlm_lookup_lockres()
> +		 * The first one is handled at the end of this function. The
> +		 * other two are handled in the worker thread after locks have
> +		 * been attached. Yes, we don't wait for purge time to match
> +		 * kref_init. The lockres will still have atleast one ref
> +		 * added because it is in the hash __dlm_insert_lockres() */
> +		extra_refs++;
> +
>  		/* now that the new lockres is inserted,
>  		 * make it usable by other processes */
>  		spin_lock(&res->spinlock);
>  		res->state &= ~DLM_LOCK_RES_IN_PROGRESS;
>  		spin_unlock(&res->spinlock);
>  		wake_up(&res->wq);
> -
> -		/* add an extra ref for just-allocated lockres 
> -		 * otherwise the lockres will be purged immediately */
> -		dlm_lockres_get(res);
>  	}
>  
>  	/* at this point we have allocated everything we need,
> @@ -1443,12 +1456,17 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data,
>  	dlm_init_work_item(dlm, item, dlm_mig_lockres_worker, buf);
>  	item->u.ml.lockres = res; /* already have a ref */
>  	item->u.ml.real_master = real_master;
> +	item->u.ml.extra_ref = extra_refs;
>  	spin_lock(&dlm->work_lock);
>  	list_add_tail(&item->list, &dlm->work_list);
>  	spin_unlock(&dlm->work_lock);
>  	queue_work(dlm->dlm_worker, &dlm->dispatched_work);
>  
>  leave:
> +	/* One extra ref taken needs to be put here */
> +	if (extra_refs)
> +		dlm_lockres_put(res);
> +
>  	dlm_put(dlm);
>  	if (ret < 0) {
>  		if (buf)
> @@ -1464,17 +1482,19 @@ leave:
>  
>  static void dlm_mig_lockres_worker(struct dlm_work_item *item, void *data)
>  {
> -	struct dlm_ctxt *dlm = data;
> +	struct dlm_ctxt *dlm;
>  	struct dlm_migratable_lockres *mres;
>  	int ret = 0;
>  	struct dlm_lock_resource *res;
>  	u8 real_master;
> +	u8 extra_ref;
>  
>  	dlm = item->dlm;
>  	mres = (struct dlm_migratable_lockres *)data;
>  
>  	res = item->u.ml.lockres;
>  	real_master = item->u.ml.real_master;
> +	extra_ref = item->u.ml.extra_ref;
>  
>  	if (real_master == DLM_LOCK_RES_OWNER_UNKNOWN) {
>  		/* this case is super-rare. only occurs if
> @@ -1517,6 +1537,12 @@ again:
>  	}
>  
>  leave:
> +	/* See comment in dlm_mig_lockres_handler() */
> +	if (res) {
> +		if (extra_ref)
> +			dlm_lockres_put(res);
> +		dlm_lockres_put(res);
> +	}
>  	kfree(data);
>  	mlog_exit(ret);
>  }
> @@ -1644,7 +1670,8 @@ int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data,
>  				/* retry!? */
>  				BUG();
>  			}
> -		}
> +		} else /* put.. incase we are not the master */
> +			dlm_lockres_put(res);
>  		spin_unlock(&res->spinlock);
>  	}
>  	spin_unlock(&dlm->spinlock);
> @@ -1921,6 +1948,7 @@ void dlm_move_lockres_to_recovery_list(struct dlm_ctxt *dlm,
>  		     "Recovering res %s:%.*s, is already on recovery list!\n",
>  		     dlm->name, res->lockname.len, res->lockname.name);
>  		list_del_init(&res->recovering);
> +		dlm_lockres_put(res);
>  	}
>  	/* We need to hold a reference while on the recovery list */
>  	dlm_lockres_get(res);
> -- 
> 1.5.3.6
> 
> 
> _______________________________________________
> Ocfs2-devel mailing list
> Ocfs2-devel at oss.oracle.com
> http://oss.oracle.com/mailman/listinfo/ocfs2-devel

-- 

Life's Little Instruction Book #396

	"Never give anyone a fruitcake."

Joel Becker
Principal Software Developer
Oracle
E-mail: joel.becker at oracle.com
Phone: (650) 506-8127



More information about the Ocfs2-devel mailing list