[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