[PATCH] layout recall changes for nfsd layout cache

Benny Halevy bhalevy at ns1.bhalevy.com
Mon May 7 12:44:55 EDT 2007


---
 fs/nfsd/export.c                |    6 +-
 fs/nfsd/nfs4callback.c          |   90 +++++------
 fs/nfsd/nfs4state.c             |  323 +++++++++++++++++++++++++++++++--------
 include/linux/nfsd/nfsd4_pnfs.h |    6 +
 include/linux/nfsd/pnfsd.h      |    2 +-
 include/linux/nfsd/state.h      |   35 +++--
 6 files changed, 330 insertions(+), 132 deletions(-)

diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index f629a3b..b5ea034 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -372,13 +372,11 @@ EXPORT_SYMBOL(cb_change_state);
 static int cb_layout_recall(struct super_block *sb, struct inode *inode,
 void *p)
 {
-	struct nfs4_cb_layout *lr = (struct nfs4_cb_layout *)p;
+	struct nfsd4_pnfs_cb_layout *lr = p;
 
 	dprintk("cb_layout_recall lr %p\n", lr);
 
-        nfsd_layout_recall_cb(lr);
-
-        return 0;
+	return nfsd_layout_recall_cb(inode, lr);
 }
 EXPORT_SYMBOL(cb_layout_recall);
 
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 6caca21..3abaf04 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -249,36 +249,41 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec)
 }
 
 static int
-encode_cb_layout(struct xdr_stream *xdr, struct nfs4_cb_layout *lr)
+encode_cb_layout(struct xdr_stream *xdr, struct nfs4_layoutrecall *clr)
 {
 	u32 *p;
-	int len = lr->cbl_fhlen;
+	int len = clr->cb.cbl_recall_type == RECALL_FILE ?
+	          clr->clr_file->fi_fhlen : 0;
 
-	RESERVE_SPACE(48 + len);
+	RESERVE_SPACE(40 + len);
 
 	WRITE32(OP_CB_LAYOUT);
-	WRITE32(lr->cbl_layout_type);
-	WRITE32(lr->cbl_iomode);
-	WRITE32(lr->cbl_layoutchanged);
-	WRITE32(lr->cbl_recall_type);
-	if (lr->cbl_recall_type == RECALL_FSID) {
-		WRITE64(lr->cbl_fsid.major);
-		WRITE64(lr->cbl_fsid.minor);
+	WRITE32(clr->cb.cbl_seg.layout_type);
+	WRITE32(clr->cb.cbl_seg.iomode);
+	WRITE32(clr->cb.cbl_layoutchanged);
+	WRITE32(clr->cb.cbl_recall_type);
+	if (unlikely(clr->cb.cbl_recall_type == RECALL_FSID)) {
+		struct nfs4_fsid fsid = clr->clr_file->fi_fsid;
+		WRITE64(fsid.major);
+		WRITE64(fsid.minor);
 		dprintk("%s: type %d iomode %d changed %d recall_type %d fsid 0x%llx-0x%llx\n",
-			__FUNCTION__, lr->cbl_layout_type, lr->cbl_iomode,
-			lr->cbl_layoutchanged, lr->cbl_recall_type,
-			lr->cbl_fsid.major, lr->cbl_fsid.minor);
+			__FUNCTION__, clr->cb.cbl_seg.layout_type, clr->cb.cbl_seg.iomode,
+			clr->cb.cbl_layoutchanged, clr->cb.cbl_recall_type,
+			fsid.major, fsid.minor);
 	}
-	else if (lr->cbl_recall_type == RECALL_FILE) {
+	else if (clr->cb.cbl_recall_type == RECALL_FILE) {
 		WRITE32(len);
-		WRITEMEM(lr->cbl_fhval, len);
-		WRITE64(lr->cbl_offset);
-		WRITE64(lr->cbl_length);
+		WRITEMEM(clr->clr_file->fi_fhval, len);
+		WRITE64(clr->cb.cbl_seg.offset);
+		WRITE64(clr->cb.cbl_seg.length);
 		dprintk("%s: type %d iomode %d changed %d recall_type %d offset %lld length %lld\n",
-			__FUNCTION__, lr->cbl_layout_type, lr->cbl_iomode,
-			lr->cbl_layoutchanged, lr->cbl_recall_type,
-			lr->cbl_offset,	lr->cbl_length);
-	}
+			__FUNCTION__, clr->cb.cbl_seg.layout_type, clr->cb.cbl_seg.iomode,
+			clr->cb.cbl_layoutchanged, clr->cb.cbl_recall_type,
+			clr->cb.cbl_seg.offset, clr->cb.cbl_seg.length);
+	} else
+		dprintk("%s: type %d iomode %d changed %d recall_type %d\n",
+			__FUNCTION__, clr->cb.cbl_seg.layout_type, clr->cb.cbl_seg.iomode,
+			clr->cb.cbl_layoutchanged, clr->cb.cbl_recall_type);
 	return 0;
 }
 
@@ -308,7 +313,7 @@ nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, u32 *p, struct nfs4_cb_recall *args
 }
 
 static int
-nfs4_xdr_enc_cb_layout(struct rpc_rqst *req, u32 *p, struct nfs4_cb_layout *args)
+nfs4_xdr_enc_cb_layout(struct rpc_rqst *req, u32 *p, struct nfs4_layoutrecall *args)
 {
 	struct xdr_stream xdr;
 
@@ -632,51 +637,38 @@ out:
  * called with dp->dl_count inc'ed.
  * nfs4_lock_state() may or may not have been called.
  */
-void
-nfsd4_cb_layout(struct nfs4_cb_layout *cbl)
+int
+nfsd4_cb_layout(struct nfs4_layoutrecall *clr)
 {
-	struct nfs4_client *clp = cbl->cbl_client;
+	struct nfs4_client *clp = clr->clr_client;
 	struct rpc_clnt *clnt = NULL;
 	struct rpc_message msg = {
 		.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_LAYOUT],
-		.rpc_argp = cbl,
+		.rpc_argp = clr,
 	};
-	int retries = 1;
-	int status = 0;
 
 	if (clp)
 		clnt = clp->cl_callback.cb_client;
 
+	clr->clr_status = -EIO;
 	if ((!atomic_read(&clp->cl_callback.cb_set)) || !clnt)
-		return;
+		goto out;
 
 	msg.rpc_cred = nfsd4_lookupcred(clp, 0);
-	if (IS_ERR(msg.rpc_cred))
+	if (IS_ERR(msg.rpc_cred)) {
+		clr->clr_status = PTR_ERR(msg.rpc_cred);
 		goto out;
-
-	status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
-	while (retries--) {
-		switch (status) {
-			case -EIO:
-				/* Network partition? */
-			case -EBADHANDLE:
-				break;
-			default:
-				goto out_put_cred;
-		}
-		ssleep(2);
-		status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
 	}
 
-out_put_cred:
+	clr->clr_status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
+
 	put_rpccred(msg.rpc_cred);
 
-out:
-	if (status == -EIO)
+	if (clr->clr_status == -EIO)
 		atomic_set(&clp->cl_callback.cb_set, 0);
+out:
 	/* Success or failure, now we're either waiting for lease expiration
 	   or layout_return. */
-	dprintk("NFSD: nfsd4_cb_layout: status %d\n", status);
-
-	return;
+	dprintk("NFSD: nfsd4_cb_layout: status %d\n", clr->clr_status);
+	return clr->clr_status;
 }
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 3d438e4..6a65586 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -87,9 +87,9 @@ static void nfs4_set_recdir(char *recdir);
 /*
  * Layout state - NFSv4.1 pNFS
  */
-static struct list_head layout_recall_lru;
 static kmem_cache_t *pnfs_layout_slab = NULL;
-static void destroy_layout(struct nfs4_layout *lp);
+static kmem_cache_t *pnfs_layoutrecall_slab = NULL;
+static void destroy_layoutrecall(struct nfs4_layoutrecall *lrp);
 static void release_pnfs_ds_dev_list(struct nfs4_stateid *stp);
 #endif /* CONFIG_PNFS */
 
@@ -547,6 +547,8 @@ static void
 free_nfs4_client(struct kref *kref)
 {
 	struct nfs4_client *clp = container_of(kref, struct nfs4_client, cl_ref);
+	BUG_ON(!list_empty(&clp->cl_layouts));
+	BUG_ON(!list_empty(&clp->cl_layoutrecalls));
 	if (clp->cl_cred.cr_group_info)
 		put_group_info(clp->cl_cred.cr_group_info);
 	kfree(clp->cl_name.data);
@@ -578,7 +580,7 @@ expire_client(struct nfs4_client *clp)
 {
 	struct nfs4_stateowner *sop;
 	struct nfs4_delegation *dp;
-	struct nfs4_layout *lp;
+	struct nfs4_layoutrecall *lrp;
 	struct nfs41_session  *ses;
 	struct list_head reaplist;
 
@@ -606,22 +608,14 @@ expire_client(struct nfs4_client *clp)
 	list_del(&clp->cl_strhash);
 	list_del(&clp->cl_lru);
 #if defined(CONFIG_PNFS)
-	spin_lock(&recall_lock);
-	while (!list_empty(&clp->cl_layouts)) {
-		lp = list_entry(clp->cl_layouts.next, struct nfs4_layout, lo_perclnt);
-		dprintk("NFSD: expire client. lp %p, fp %p\n", lp,
-				lp->lo_file);
-		BUG_ON(lp->lo_client != clp);
-		list_del_init(&lp->lo_perclnt);
-		list_move(&lp->lo_recall_lru, &reaplist);
+	while (!list_empty(&clp->cl_layoutrecalls)) {
+		lrp = list_entry(clp->cl_layoutrecalls.next,
+		                 struct nfs4_layoutrecall, clr_perclnt);
+		dprintk("NFSD: expire client. lrp %p, fp %p\n", lrp,
+				lrp->clr_file);
+		BUG_ON(lrp->clr_client != clp);
+		destroy_layoutrecall(lrp);
 	}
-	spin_unlock(&recall_lock);
-	while (!list_empty(&reaplist)) {
-		lp = list_entry(reaplist.next, struct nfs4_layout, lo_recall_lru);
-		list_del_init(&lp->lo_recall_lru);
-		destroy_layout(lp);
-	}
-
 #endif
 	while (!list_empty(&clp->cl_openowners)) {
 		sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient);
@@ -648,6 +642,7 @@ create_client(struct xdr_netobj name, char *recdir) {
 	INIT_LIST_HEAD(&clp->cl_openowners);
 	INIT_LIST_HEAD(&clp->cl_delegations);
 	INIT_LIST_HEAD(&clp->cl_layouts);
+	INIT_LIST_HEAD(&clp->cl_layoutrecalls);
 	INIT_LIST_HEAD(&clp->cl_sessions);
 	INIT_LIST_HEAD(&clp->cl_lru);
 out:
@@ -1454,6 +1449,7 @@ nfsd4_free_slabs(void)
 	nfsd4_free_slab(&deleg_slab);
 #if defined(CONFIG_PNFS)
 	nfsd4_free_slab(&pnfs_layout_slab);
+	nfsd4_free_slab(&pnfs_layoutrecall_slab);
 #endif /* CONFIG_PNFS */
 }
 
@@ -1481,6 +1477,10 @@ nfsd4_init_slabs(void)
 			sizeof(struct nfs4_layout), 0, 0, NULL, NULL);
 	if (pnfs_layout_slab == NULL)
 		goto out_nomem;
+	pnfs_layoutrecall_slab = kmem_cache_create("pnfs_layoutrecalls",
+			sizeof(struct nfs4_layoutrecall), 0, 0, NULL, NULL);
+	if (pnfs_layoutrecall_slab == NULL)
+		goto out_nomem;
 #endif /* CONFIG_PNFS */
 
 	return 0;
@@ -3927,10 +3927,60 @@ destroy_layout(struct nfs4_layout *lp)
 	put_nfs4_file(fp);
 }
 
+/*
+ * Create a layoutrecall structure
+ * An optional layoutrecall can be cloned (except for the layoutrecall lists)
+ */
+static struct nfs4_layoutrecall *
+alloc_init_layoutrecall(struct nfs4_layoutrecall *clone)
+{
+	struct nfs4_layoutrecall *clr;
+
+	dprintk("NFSD %s\n", __FUNCTION__);
+	clr = kmem_cache_alloc(pnfs_layoutrecall_slab, GFP_KERNEL);
+	if (clr == NULL)
+		return clr;
+
+	dprintk("NFSD %s clr %p clone %p\n", __FUNCTION__, clr, clone);
+
+	if (clone)
+		memcpy(clr, clone, sizeof(*clr));
+	else
+		memset(clr, 0, sizeof(*clr));
+	INIT_LIST_HEAD(&clr->clr_perclnt);
+
+	dprintk("NFSD %s return %p\n", __FUNCTION__, clr);
+	return clr;
+}
+
 static void
-pnfs_hash_cb_layout(struct nfs4_layout *lp)
+hash_layoutrecall(struct nfs4_layoutrecall *clr)
 {
-	list_add(&lp->lo_recall_lru, &layout_recall_lru);
+	struct nfs4_client *clp = clr->clr_client;
+	struct nfs4_file *fp = clr->clr_file;
+
+	dprintk("NFSD %s clr %p clp %p fp %p\n", __FUNCTION__, clr, clp, fp);
+	get_nfs4_client(clp);
+	list_add(&clr->clr_perclnt, &clp->cl_layoutrecalls);
+	if (fp)
+		get_nfs4_file(fp);
+	dprintk("NFSD %s exit\n", __FUNCTION__);
+}
+
+static void
+destroy_layoutrecall(struct nfs4_layoutrecall *clr)
+{
+	int did_lock;
+
+	dprintk("pNFS %s: clr %p fp %p clp %p\n", __FUNCTION__, clr,
+	        clr->clr_file, clr->clr_client);
+	did_lock = nfs4_trylock_state();
+	list_del(&clr->clr_perclnt);
+	put_nfs4_client(clr->clr_client);
+	put_nfs4_file(clr->clr_file);
+	nfs4_unlock_state();
+
+	kmem_cache_free(pnfs_layoutrecall_slab, clr);
 }
 
 /*
@@ -3990,6 +4040,36 @@ same_fsid(struct nfs4_fsid *fsid, struct svc_fh *current_fh)
 }
 
 /*
+ * find a layout recall conflicting with the specified layoutget
+ */
+static int
+is_layout_recalled(struct nfs4_client *clp, struct svc_fh *current_fh,
+                   struct nfsd4_pnfs_layoutget *lgp)
+{
+	struct nfs4_layoutrecall *clr;
+
+	list_for_each_entry (clr, &clp->cl_layoutrecalls, clr_perclnt) {
+		if ((clr->clr_flags & LAYOUTRECALL_FLAG_DONE) ||
+		    clr->cb.cbl_seg.layout_type != lgp->lg_seg.layout_type)
+			continue;
+
+		if (clr->cb.cbl_recall_type == RECALL_ALL)
+			return 1;
+		if (clr->cb.cbl_recall_type == RECALL_FSID) {
+			if (same_fsid(&clr->clr_file->fi_fsid, current_fh))
+				return 1;
+			else
+				continue;
+		}
+		BUG_ON(clr->cb.cbl_recall_type != RECALL_FILE);
+		if (clr->cb.cbl_seg.clientid == lgp->lg_seg.clientid &&
+		    lo_seg_overlapping(&clr->cb.cbl_seg, &lgp->lg_seg))
+			return 1;
+	}
+	return 0;
+}
+
+/*
  * are two octet ranges overlapping or adjacent?
  */
 static inline int
@@ -4080,6 +4160,11 @@ int nfs4_pnfs_get_layout(struct super_block *sb, struct svc_fh *current_fh,
 	if (!fp || !clp)
 	        goto out;
 
+	if (is_layout_recalled(clp, current_fh, lgp)) {
+		status = nfserr_recallconflict;
+		goto out;
+	}
+
 	can_merge = sb->s_export_op->can_merge_layouts != NULL &&
 	            sb->s_export_op->can_merge_layouts(lgp->lg_seg.layout_type);
 
@@ -4225,49 +4310,127 @@ out:
 	return status;
 }
 
+static int
+cl_has_file_layout(struct nfs4_client *clp, struct nfs4_layoutrecall *clr)
+{
+	struct nfs4_layout *lp;
+
+	list_for_each_entry(lp, &clp->cl_layouts, lo_perclnt)
+		if (lp->lo_file == clr->clr_file)
+			return 1;
+
+	return 0;
+}
+
+static int
+cl_has_fsid_layout(struct nfs4_client *clp, struct nfs4_layoutrecall *clr)
+{
+	struct nfs4_layout *lp;
+
+	/* note: minor version unused */
+	list_for_each_entry(lp, &clp->cl_layouts, lo_perclnt)
+		if (lp->lo_file->fi_fsid.major == clr->clr_file->fi_fsid.major)
+			return 1;
+
+	return 0;
+}
+
+static int
+cl_has_any_layout(struct nfs4_client *clp, struct nfs4_layoutrecall *dummy)
+{
+	return !list_empty(&clp->cl_layouts);
+}
+
 /*
- * Recall a layout
+ * Recall a layout asynchronously
+ * FIXME: Failures are nor reported back
  */
 static int
-do_layout_recall(void *__lr)
+do_layout_recall(void *__clr)
 {
-	struct nfs4_cb_layout *lr = __lr;
+	struct nfs4_layoutrecall *pending, *clr = __clr;
 	struct nfs4_client *clp = NULL;
-        unsigned int i;
+	unsigned int i;
+	int status;
+	struct list_head todolist;
+	static int (*__has_layout)(struct nfs4_client *,
+	                           struct nfs4_layoutrecall *);
 
 	daemonize("nfsv4-layout");
 
-	if (lr->cbl_recall_type == RECALL_ALL) {
-		for (i = 0; i < CLIENT_HASH_SIZE; i++) {
-			list_for_each_entry(clp, &conf_str_hashtbl[i], cl_strhash) {
-				if (clp) {
-					if (!clp->cl_callback.cb_client)
-						continue;
-//??? check if this client has any layouts
-					lr->cbl_client = clp;
-					nfsd4_cb_layout(lr);
-				}
-			}
-		}
+	INIT_LIST_HEAD(&todolist);
+
+	/* specific client */
+	if (clr->clr_client) {
+		list_add(&clr->clr_perclnt, &todolist);
+		clr = NULL;	/* so it won't be destroyed here */
+		goto doit;
 	}
-	if (lr->cbl_recall_type == RECALL_FSID) {
-		for (i = 0; i < CLIENT_HASH_SIZE; i++) {
-			list_for_each_entry(clp, &conf_str_hashtbl[i], cl_strhash) {
-				if (clp) {
-					if (!clp->cl_callback.cb_client)
-						continue;
-//??? check if this client has any layouts for this FSID
-					lr->cbl_client = clp;
-					nfsd4_cb_layout(lr);
-				}
+
+	switch (clr->cb.cbl_recall_type) {
+	case RECALL_FILE:
+		__has_layout = cl_has_file_layout;
+		break;
+	case RECALL_FSID:
+		__has_layout = cl_has_fsid_layout;
+		break;
+	case RECALL_ALL:
+		__has_layout = cl_has_any_layout;
+		break;
+	}
+
+	nfs4_lock_state();
+	for (i = 0; i < CLIENT_HASH_SIZE; i++)
+		list_for_each_entry(clp, &conf_str_hashtbl[i], cl_strhash)
+			if (__has_layout(clp, clr)) {
+				pending = alloc_init_layoutrecall(clr);
+				if (!pending)
+					goto doit;
+				pending->clr_client = clp;
+				list_add(&pending->clr_perclnt, &todolist);
 			}
+	nfs4_unlock_state();
+
+	/* cleanup only in the multi client, single client went into todolist */
+	destroy_layoutrecall(clr);
+
+doit:
+	while (!list_empty(&todolist)) {
+		pending = list_entry(todolist.next, struct nfs4_layoutrecall,
+		                     clr_perclnt);
+		list_del(&pending->clr_perclnt);
+		dprintk("%s: clp %p cb_client %p fp %p\n", __FUNCTION__,
+		        pending->clr_client,
+		        pending->clr_client->cl_callback.cb_client,
+		        pending->clr_file);
+		if (unlikely(!pending->clr_client->cl_callback.cb_client)) {
+			printk("%s: clientid %llx has no callback path\n",
+			       __FUNCTION__,
+			       (unsigned long long)clr->cb.cbl_seg.clientid);
+			destroy_layoutrecall(pending);
+			continue;
 		}
+		pending->clr_flags = LAYOUTRECALL_FLAG_PENDING;
+		pending->clr_time = CURRENT_TIME;
+		nfs4_lock_state();
+		hash_layoutrecall(pending);
+		nfs4_unlock_state();
+		status = nfsd4_cb_layout(pending);
+		if (status && status != NFSERR_NOMATCHING_LAYOUT)
+			printk("%s: clp %p cb_client %p fp %p "
+			       "failed with status %d\n", __FUNCTION__,
+			        pending->clr_client,
+			        pending->clr_client->cl_callback.cb_client,
+			        pending->clr_file,
+			        status);
+		nfs4_lock_state();
+		if (!status && !(pending->clr_flags & LAYOUTRECALL_FLAG_DONE))
+			pending->clr_flags &= ~LAYOUTRECALL_FLAG_PENDING;
+		else
+			destroy_layoutrecall(pending);
+		nfs4_unlock_state();
 	}
-	if (lr->cbl_recall_type == RECALL_FILE) {
-//??? find layout for this file (given by inode)
-		if (lr->cbl_client)
-			nfsd4_cb_layout(lr);
-	}
+
 	return 0;
 }
 
@@ -4275,22 +4438,60 @@ do_layout_recall(void *__lr)
  * Spawn a thread to perform a recall layout
  *
  */
-void nfsd_layout_recall_cb(struct nfs4_cb_layout *lr)
+int nfsd_layout_recall_cb(struct inode *inode, struct nfsd4_pnfs_cb_layout *cbl)
 {
+	int status;
+	struct nfs4_layoutrecall *clr = NULL;
 	struct task_struct *t;
 
-	dprintk("NFSD nfsd_layout_recall_cb: lp %p\n",lr);
-	if (!lr)
-		return;
+	dprintk("NFSD nfsd_layout_recall_cb: inode %p cbl %p\n", inode, cbl);
+	BUG_ON(!cbl);
+	BUG_ON(cbl->cbl_recall_type != RECALL_FILE &&
+	       cbl->cbl_recall_type != RECALL_FSID &&
+	       cbl->cbl_recall_type != RECALL_ALL);
+	BUG_ON(cbl->cbl_recall_type != RECALL_ALL && !inode);
 
-	t = kthread_run(do_layout_recall, lr, "%s", "nfs4_cb_recall");
-	if (IS_ERR(t)) {
-		struct nfs4_client *clp = lr->cbl_client;
+	clr = alloc_init_layoutrecall(NULL);
+	if (!clr)
+		return -ENOMEM;
+	clr->cb = *cbl;
 
-		printk(KERN_INFO "NFSD: Callback thread failed for "
-			"for client (clientid %08x/%08x)\n",
-			clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
+	INIT_LIST_HEAD(&clr->clr_perclnt);
+	clr->clr_client = NULL;
+	clr->clr_file = NULL;
+
+	nfs4_lock_state();
+	status = -ENOENT;
+	if (clr->cb.cbl_seg.clientid) {
+		clr->clr_client =
+		  find_confirmed_client((clientid_t *)&clr->cb.cbl_seg.clientid);
+		if (!clr->clr_client) {
+			printk("%s: clientid %llx not found\n", __FUNCTION__,
+			       (unsigned long long)clr->cb.cbl_seg.clientid);
+			goto err;
+		}
+	}
+	if (inode) {
+		clr->clr_file = find_file(inode);
+		if (!clr->clr_file) {
+			dprintk("NFSD nfsd_layout_recall_cb: nfs4_file not found\n");
+			goto err;
+		}
 	}
+	nfs4_unlock_state();
+
+	t = kthread_run(do_layout_recall, clr, "%s", "nfs4_cb_recall");
+	if (!IS_ERR(t))
+		return 0;	/* Success!, refcounts handled by kthread */
+
+	status = PTR_ERR(t);
+	nfs4_lock_state();
+err:
+	put_nfs4_client(clr->clr_client);
+	put_nfs4_file(clr->clr_file);
+	nfs4_unlock_state();
+	destroy_layoutrecall(clr);
+	return status;
 }
 
 #endif /* CONFIG_PNFS */
diff --git a/include/linux/nfsd/nfsd4_pnfs.h b/include/linux/nfsd/nfsd4_pnfs.h
index c63c5a9..e133c9c 100644
--- a/include/linux/nfsd/nfsd4_pnfs.h
+++ b/include/linux/nfsd/nfsd4_pnfs.h
@@ -113,4 +113,10 @@ struct nfsd4_pnfs_layoutreturn {
 	u32				lr_flags;
 };
 
+struct nfsd4_pnfs_cb_layout {
+	u32                     cbl_recall_type;	/* request */
+	struct nfsd4_layout_seg cbl_seg;		/* request */
+	u32                     cbl_layoutchanged;	/* request */
+};
+
 #endif /* _LINUX_NFSD_NFSD4_PNFS_H */
diff --git a/include/linux/nfsd/pnfsd.h b/include/linux/nfsd/pnfsd.h
index 04db406..8311d2d 100644
--- a/include/linux/nfsd/pnfsd.h
+++ b/include/linux/nfsd/pnfsd.h
@@ -78,7 +78,7 @@ struct pnfs_mds_id {
 	time_t			di_mdsboot;	/* mds boot time */
 };
 
-void nfsd_layout_recall_cb(struct nfs4_cb_layout *);
+int nfsd_layout_recall_cb(struct inode *inode, struct nfsd4_pnfs_cb_layout *);
 int nfs4_pnfs_cb_get_state(struct pnfs_get_state *);
 void nfs4_pnfs_state_init(void);
 int nfs4_pnfs_get_layout(struct super_block *, struct svc_fh *,
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index 5040b6f..18b8b99 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -202,6 +202,7 @@ struct nfs4_client {
 	struct list_head	cl_delegations;
 #ifdef CONFIG_PNFS
 	struct list_head	cl_layouts;	/* outstanding layouts */
+	struct list_head	cl_layoutrecalls; /* outstanding layoutrecall callbacks */
 #endif /* CONFIG_PNFS */
 	struct list_head	cl_sessions;
 	struct list_head        cl_lru;         /* tail queue */
@@ -230,31 +231,31 @@ struct nfs4_fsid {
 #ifdef CONFIG_PNFS
 #include <linux/nfsd/nfsd4_pnfs.h>
 
-struct nfs4_cb_layout {
-	struct super_block	*cbl_sb;
-	struct nfs4_client	*cbl_client;
-	u32			cbl_ident;
-	u32			cbl_recall_type;
-	u32			cbl_layout_type;
-	u32			cbl_iomode;
-	u32			cbl_layoutchanged;
-	u64			cbl_offset;
-	u64			cbl_length;
-	struct nfs4_fsid	cbl_fsid;
-	u32			cbl_fhlen;
-	u32			cbl_fhval[NFS4_FHSIZE];
-};
-
 /* outstanding layout */
 struct nfs4_layout {
 	struct list_head	lo_perfile;    /* hash by f_id */
 	struct list_head	lo_perclnt;    /* hash by clientid */
-	struct list_head	lo_recall_lru; /* when in recall */
 	struct nfs4_file        *lo_file;      /* backpointer */
 	struct nfs4_client      *lo_client;
 	struct nfsd4_layout_seg lo_seg;
 };
 
+enum {
+	LAYOUTRECALL_FLAG_PENDING = 1<<0,
+	LAYOUTRECALL_FLAG_DONE    = 1<<1,
+};
+
+/* layoutrecall request (from exported filesystem) */
+struct nfs4_layoutrecall {
+	struct nfsd4_pnfs_cb_layout     cb;         /* request */
+	struct list_head                clr_perclnt;    /* on cl_layoutrecalls */
+	struct nfs4_client             *clr_client;
+	struct nfs4_file               *clr_file;
+	int                             clr_status;
+	unsigned                        clr_flags;
+	struct timespec                 clr_time;       /* last activity */
+};
+
 #endif /* CONFIG_PNFS */
 
 /* struct nfs4_client_reset
@@ -430,7 +431,7 @@ extern void nfs4_free_stateowner(struct kref *kref);
 extern void nfsd4_probe_callback(struct nfs4_client *clp);
 extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
 #ifdef CONFIG_PNFS
-extern void nfsd4_cb_layout(struct nfs4_cb_layout *lp);
+extern int nfsd4_cb_layout(struct nfs4_layoutrecall *lp);
 #endif /* CONFIG_PNFS */
 extern void nfs4_put_delegation(struct nfs4_delegation *dp);
 extern int nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
-- 
1.5.1


--------------070205060706090907070607--


More information about the pNFS mailing list