[pnfs] [PATCH 02/10] pnfsd: Helper functions for layout stateid processing.

andros at netapp.com andros at netapp.com
Wed May 7 16:53:37 EDT 2008


From: Andy Adamson <andros at umich.edu>

Add a list of per clientid reference counted layout state structures (struct
nfs4_layout_state) to struct nfs4_file to track the layout stateid usage.

A struct nfs4_layout_state is created upon first LAYOUTGET operation from a
clientid on the file. Each successful LAYOUTGET from a clientid on the file
that adds a nfsd4_layout_seg bumps the struct nfs4_layout_state reference
count, and the nfsd4_layout_seg is added to the nfs4_layout_state
ls_state list.

LAYOUTRETURNS that remove nfsd4_layout_segs decrement the nfs4_layout_state
reference count.  A struct nfs4_layout_state is reaped when it's reference
count goes to zero and the ls_state list is empty.

A delegation stateid is identified by a zero si_fileid field, an open/lock
stateid has non-zero si_stateownerid and si_fileid field, a layout stateid
is identified by a zero si_stateownerid field. The layout stateid
si_fileid field is used (reset) as a uniqifier.

NOTE: A design point of this architecture was to leave the nfs4_file fi_layouts
list alone so as not to disturb server implementations just prior to
Connectathon. We might want to get rid of the fi_layouts list and just
use the fi_layout_state list.

Signed-off-by: Andy Adamson<andros at netapp.com>
---
 fs/nfsd/nfs4state.c        |  102 +++++++++++++++++++++++++++++++++++++++++---
 include/linux/nfsd/state.h |   23 ++++++++--
 2 files changed, 114 insertions(+), 11 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index d91f5ad..608d5b2 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -76,6 +76,7 @@ static int in_grace = 1;
 static u32 current_ownerid = 1;
 static u32 current_fileid = 1;
 static u32 current_delegid = 1;
+static u32 current_layoutid = 1;
 static u32 nfs4_init;
 static stateid_t zerostateid;             /* bits all 0 */
 static stateid_t onestateid;              /* bits all 1 */
@@ -1410,6 +1411,7 @@ alloc_init_file(struct inode *ino, struct svc_fh *current_fh)
 		INIT_LIST_HEAD(&fp->fi_delegations);
 #if defined(CONFIG_PNFSD)
 		INIT_LIST_HEAD(&fp->fi_layouts);
+		INIT_LIST_HEAD(&fp->fi_layout_states);
 #endif /* CONFIG_PNFSD */
 		list_add(&fp->fi_hash, &file_hashtbl[hashval]);
 		fp->fi_inode = igrab(ino);
@@ -4046,6 +4048,82 @@ nfs4_reset_lease(time_t leasetime)
 }
 
 #if defined(CONFIG_PNFSD)
+static struct nfs4_layout_state *
+alloc_init_layout_state(struct nfs4_client *clp, struct nfs4_file *fp,
+			stateid_t *stateid)
+{
+	struct nfs4_layout_state *new;
+
+	/* use a kmem_cache */
+	new = kzalloc(sizeof(*new), GFP_KERNEL);
+	if (!new)
+		return new;
+	get_nfs4_file(fp);
+	INIT_LIST_HEAD(&new->ls_perfile);
+	INIT_LIST_HEAD(&new->ls_layouts);
+	list_add(&new->ls_perfile, &fp->fi_layout_states);
+	kref_init(&new->ls_ref);
+	new->ls_client = clp;
+	new->ls_file = fp;
+	new->ls_stateid.si_boot = stateid->si_boot;
+	new->ls_stateid.si_stateownerid = 0; /* identifies layout stateid */
+	new->ls_stateid.si_fileid = current_layoutid++;
+	new->ls_stateid.si_generation = 1;
+	return new;
+}
+
+static inline void
+get_layout_state(struct nfs4_layout_state *ls)
+{
+	kref_get(&ls->ls_ref);
+}
+
+static void
+destroy_layout_state(struct kref *kref)
+{
+	struct nfs4_layout_state *ls =
+			container_of(kref, struct nfs4_layout_state, ls_ref);
+	struct nfs4_file *fp = ls->ls_file;
+
+	dprintk("pNFS %s: ls %p fp %p clp %p\n", __func__, ls, fp,
+				ls->ls_client);
+	BUG_ON(!list_empty(&ls->ls_layouts));
+	list_del(&ls->ls_perfile);
+	kfree(ls);
+	put_nfs4_file(fp);
+}
+
+static inline void
+put_layout_state(struct nfs4_layout_state *ls)
+{
+	dprintk("pNFS %s: ls %p ls_ref %d\n", __func__, ls,
+				atomic_read(&ls->ls_ref.refcount));
+	kref_put(&ls->ls_ref, destroy_layout_state);
+}
+
+/*
+ * Search the fp->fi_layout_state list for a layout state with the clientid.
+ * If not found, then this is a 'first open/delegation/lock stateid' from
+ * the client for this file.
+ */
+struct nfs4_layout_state *
+find_get_layout_state(struct nfs4_client *clp, struct nfs4_file *fp)
+{
+	struct nfs4_layout_state *ls;
+
+	BUG_ON_UNLOCKED_STATE();
+	list_for_each_entry(ls, &fp->fi_layout_states, ls_perfile) {
+		if (ls->ls_client == clp) {
+			dprintk("pNFS %s: before GET ls %p ls_ref %d\n",
+					__func__, ls,
+					atomic_read(&ls->ls_ref.refcount));
+			get_layout_state(ls);
+			return ls;
+		}
+	}
+	return NULL;
+}
+
 static inline struct nfs4_layout *
 alloc_layout(void)
 {
@@ -4059,19 +4137,23 @@ free_layout(struct nfs4_layout *lp)
 }
 
 static void
-init_layout(struct nfs4_layout *lp,
+init_layout(struct nfs4_layout_state *ls,
+	    struct nfs4_layout *lp,
 	    struct nfs4_file *fp,
 	    struct nfs4_client *clp,
 	    struct svc_fh *current_fh,
 	    struct nfsd4_layout_seg *seg)
 {
-	dprintk("pNFS %s: lp %p clp %p fp %p ino %p\n", __func__,
-		lp, clp, fp, fp->fi_inode);
+	dprintk("pNFS %s: ls %p lp %p clp %p fp %p ino %p\n", __func__,
+		ls, lp, clp, fp, fp->fi_inode);
 
 	get_nfs4_file(fp);
 	lp->lo_client = clp;
 	lp->lo_file = fp;
+	get_layout_state(ls);
+	lp->lo_state = ls;
 	memcpy(&lp->lo_seg, seg, sizeof(lp->lo_seg));
+	list_add_tail(&lp->lo_perstate, &ls->ls_layouts);
 	list_add_tail(&lp->lo_perclnt, &clp->cl_layouts);
 	list_add_tail(&lp->lo_perfile, &fp->fi_layouts);
 	dprintk("pNFS %s end\n", __func__);
@@ -4082,15 +4164,22 @@ destroy_layout(struct nfs4_layout *lp)
 {
 	struct nfs4_client *clp;
 	struct nfs4_file *fp;
+	struct nfs4_layout_state *ls;
 
 	list_del(&lp->lo_perclnt);
 	list_del(&lp->lo_perfile);
+	list_del(&lp->lo_perstate);
 	clp = lp->lo_client;
 	fp = lp->lo_file;
-	dprintk("pNFS %s: lp %p clp %p fp %p ino %p\n", __FUNCTION__,
-		lp, clp, fp, fp->fi_inode);
+	ls = lp->lo_state;
+	dprintk("pNFS %s: lp %p clp %p fp %p ino %p ls_layouts empty %d\n",
+		__func__, lp, clp, fp, fp->fi_inode,
+		list_empty(&ls->ls_layouts));
 
 	kmem_cache_free(pnfs_layout_slab, lp);
+	put_layout_state(ls);
+	if (list_empty(&ls->ls_layouts))
+		put_layout_state(ls); /* Final put */
 	put_nfs4_file(fp);
 }
 
@@ -4358,6 +4447,7 @@ nfs4_pnfs_get_layout(struct svc_fh *current_fh,
 	struct nfs4_file *fp;
 	struct nfs4_client *clp;
 	struct nfs4_layout *lp = NULL;
+	struct nfs4_layout_state *ls = NULL;
 
 	dprintk("NFSD: %s Begin\n", __func__);
 
@@ -4422,7 +4512,7 @@ nfs4_pnfs_get_layout(struct svc_fh *current_fh,
 		goto out_freelayout;
 
 	/* Can't merge, so let's initialize this new layout */
-	init_layout(lp, fp, clp, current_fh, &args->seg);
+	init_layout(ls, lp, fp, clp, current_fh, &args->seg);
 out:
 	if (fp)
 		put_nfs4_file(fp);
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index 9f6bb8f..ac3a40e 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -255,13 +255,25 @@ struct nfs4_fsid {
 
 #include <linux/nfsd/nfsd4_pnfs.h>
 
+/* outstanding layout stateid */
+struct nfs4_layout_state {
+	struct list_head	ls_perfile;
+	struct list_head	ls_layouts; /* list of nfs4_layouts */
+	struct kref		ls_ref;
+	struct nfs4_client	*ls_client;
+	struct nfs4_file	*ls_file;
+	stateid_t		ls_stateid;
+};
+
 /* outstanding layout */
 struct nfs4_layout {
-	struct list_head	lo_perfile;	/* hash by f_id */
-	struct list_head	lo_perclnt;	/* hash by clientid */
-	struct nfs4_file	*lo_file;	/* backpointer */
-	struct nfs4_client	*lo_client;
-	struct nfsd4_layout_seg lo_seg;
+	struct list_head		lo_perfile;	/* hash by f_id */
+	struct list_head		lo_perclnt;	/* hash by clientid */
+	struct list_head		lo_perstate;
+	struct nfs4_file		*lo_file;	/* backpointer */
+	struct nfs4_client		*lo_client;
+	struct nfs4_layout_state	*lo_state;
+	struct nfsd4_layout_seg 	lo_seg;
 };
 
 /* layoutrecall request (from exported filesystem) */
@@ -367,6 +379,7 @@ struct nfs4_file {
 	struct list_head	fi_delegations;
 #if defined(CONFIG_PNFSD)
 	struct list_head	fi_layouts;
+	struct list_head	fi_layout_states;
 #endif /* CONFIG_PNFSD */
 	struct inode		*fi_inode;
 	u32                     fi_id;      /* used with stateowner->so_id 
-- 
1.5.4.1



More information about the pNFS mailing list