[pnfs] [PATCH 2/2] layoutrecall: look for layout on all inodes

Benny Halevy bhalevy at panasas.com
Mon Sep 10 07:11:35 EDT 2007


fast path lookup, nfs_layout_find_inode, goes only through inodes
with open state only (and only for the RECALL_FILE case), if not found
or if recall is for fsid or all we look through all inodes associated
with this client.

TODO: index all layouts in a hash table with a hash of the filehandle as key.

Signed-off-by: Benny Halevy <bhalevy at panasas.com>
---
 fs/inode.c             |    2 +
 fs/nfs/callback_proc.c |   35 +++++++++++--------
 fs/nfs/delegation.c    |   88 ++++++++++++++++++++++++++++++++++++------------
 fs/nfs/delegation.h    |    3 +-
 4 files changed, 91 insertions(+), 37 deletions(-)

diff --git a/fs/inode.c b/fs/inode.c
index 35a057b..797af77 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -235,6 +235,8 @@ void __iget(struct inode * inode)
 	inodes_stat.nr_unused--;
 }
 
+EXPORT_SYMBOL(__iget);
+
 /**
  * clear_inode - clear an inode
  * @inode: inode to clear
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 920a00f..0fae772 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -86,6 +86,7 @@ out:
 	return res;
 }
 
+#if defined(CONFIG_NFSD_V4_1)
 unsigned nfs4_callback_sequence(struct cb_sequenceargs *args,
 				struct cb_sequenceres *res)
 {
@@ -102,7 +103,9 @@ unsigned nfs4_callback_sequence(struct cb_sequenceargs *args,
 	res->cbsr_status = status;
 	return status;
 }
+#endif /* defined(CONFIG_NFSD_V4_1) */
 
+#if defined(CONFIG_PNFS)
 /*
  * Layout is not actually returned until the client executes the
  * LAYOUTRETURN operation.
@@ -119,7 +122,7 @@ unsigned nfs4_callback_pnfs_layoutrecall(struct cb_pnfs_layoutrecallargs *args,
 	struct inode *inode = NULL;
 	unsigned res;
 
-	res = htonl(NFS4ERR_BADHANDLE);
+	res = htonl(NFS4ERR_INVAL);
 	clp = nfs4_find_client(args->cbl_addr);
 	if (clp == NULL) {
 		dprintk("%s: no client for addr %u.%u.%u.%u\n",
@@ -127,8 +130,14 @@ unsigned nfs4_callback_pnfs_layoutrecall(struct cb_pnfs_layoutrecallargs *args,
 		
 		goto out;
 	}
-	if (args->cbl_recall_type == RECALL_FILE) {
+
+	res = htonl(NFS4ERR_NOMATCHING_LAYOUT);
+	/* try fast path lookup first */
+	if (args->cbl_recall_type == RECALL_FILE)
 		inode = nfs_layout_find_inode(clp, &args->cbl_fh);
+
+	if (inode == NULL) {
+		inode = nfs_layoutrecall_find_inode(clp, args);
 		if (inode == NULL) {
 			dprintk("%s: no inode for RECALL_FILE\n", __FUNCTION__);
 
@@ -136,22 +145,20 @@ unsigned nfs4_callback_pnfs_layoutrecall(struct cb_pnfs_layoutrecallargs *args,
 		}
 	}
 
+	if (args->cbl_recall_type == RECALL_FILE &&
+	    !NFS_I(inode)->current_layout)
+		goto out_putinode;
+
+	res = 0;
 	/* Set up a helper thread to actually return the delegation */
-	switch(nfs_async_return_layout(clp, inode, args)) {
-		case 0:
-			res = 0;
-			break;
-		case -ENOENT:
-			res = htonl(NFS4ERR_NOMATCHING_LAYOUT);
-			break;
-		default:
-			res = htonl(NFS4ERR_RESOURCE);
-	}
-	if (inode)
-		iput(inode);
+	if (nfs_async_return_layout(clp, inode, args))
+		res = htonl(NFS4ERR_RESOURCE);
+out_putinode:
+	iput(inode);
 out_putclient:
 	nfs4_put_client(clp);
 out:
 	dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res));
 	return res;
 }
+#endif /* defined(CONFIG_PNFS) */
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 02f706a..0b73e0a 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -459,7 +459,7 @@ struct recall_layout_threadargs {
 
 static int recall_layout_thread(void *data)
 {
-	struct inode *inode = NULL;
+	struct inode *ino;
 	struct nfs4_client *clp;
 	struct nfs_server *server = NULL;
 	struct super_block *sb = NULL;
@@ -470,8 +470,9 @@ static int recall_layout_thread(void *data)
 
 	daemonize("nfsv4-layoutreturn");
 
-	dprintk("%s: fsid 0x%llx-0x%llx start\n",
-		__FUNCTION__, args->rl.cbl_fsid.major, args->rl.cbl_fsid.minor);
+	dprintk("%s: recall_type=%d fsid 0x%llx-0x%llx start\n",
+		__FUNCTION__, args->rl.cbl_recall_type,
+		args->rl.cbl_fsid.major, args->rl.cbl_fsid.minor);
 
 	clp = args->clp;
 	args->result = 0;
@@ -506,14 +507,16 @@ static int recall_layout_thread(void *data)
 			sb = server->sb;
 			if (!sb)
 				continue;
-			/* XXX UGLY UGLY hack alert! */
+			/* FIXME: This loop is inefficient, running in O(|s_inodes|^2)
+			   since we don't want to return each file's layout under the inode_lock.
+			   we need to go over the list once, grab the relevant inodes and
+			   enlist them for further processing outside the inode_lock */
 			do {
-				struct inode *ino;
-
 				found = 0;
 				spin_lock(&inode_lock);
 				list_for_each_entry(ino, &sb->s_inodes, i_sb_list) {
 					if (NFS_I(ino)->current_layout) {
+						__iget(ino);
 						found = 1;
 						break;
 					}
@@ -521,12 +524,8 @@ static int recall_layout_thread(void *data)
 				spin_unlock(&inode_lock);
 
 				if (found) {
-					if (inode)
-						iput(inode);
-					inode = ino;
-					igrab(inode);
-					pnfs_return_layout(inode, &args->rl.cbl_seg);
-					/* keep inode for later */
+					pnfs_return_layout(ino, &args->rl.cbl_seg);
+					iput(ino);
 				}
 			} while(found);
 
@@ -535,15 +534,13 @@ static int recall_layout_thread(void *data)
 		}
 
 		/* send final layoutreturn */
-		BUG_ON(inode == NULL);	/* should have returned NFS4ERR_NOMATCHING_LAYOUT */
 		lr_arg.reclaim = 0;
-		lr_arg.layout_type = NFS_SERVER(inode)->pnfs_curr_ld->id;
+		lr_arg.layout_type = NFS_SERVER(args->inode)->pnfs_curr_ld->id;
 		lr_arg.return_type = args->rl.cbl_recall_type;
 		lr_arg.lseg = args->rl.cbl_seg;
-		lr_arg.inode = inode;
+		lr_arg.inode = args->inode;
 
 		status = pnfs_return_layout_rpc(server, &lr_arg);
-		iput(inode);
 		if (status)
 			printk("%s: ignoring pnfs_return_layout_rpc status=%d\n",
 			       __FUNCTION__, status);
@@ -559,21 +556,19 @@ out:
 /*
  * Asynchronous layout recall!
  */
-int nfs_async_return_layout(struct nfs4_client *clp, struct inode *inode, void *args)
+int nfs_async_return_layout(struct nfs4_client *clp, struct inode *inode,
+                            struct cb_pnfs_layoutrecallargs *rl)
 {
-	struct cb_pnfs_layoutrecallargs *rl = args;
 	struct recall_layout_threadargs data = {
 		.clp = clp,
 		.inode = inode,
 	};
 	int status;
 
-	/* FIXME: check first if there are any layouts to returns,
-	 * otherwise return -ENOENT (for NFS4ERR_NOMATCHING_LAYOUT)
-	 */
+	BUG_ON(inode == NULL);	/* should have returned NFS4ERR_NOMATCHING_LAYOUT */
 
 	data.rl = *rl;
-	
+
 	init_completion(&data.started);
 	__module_get(THIS_MODULE);
 	status = kernel_thread(recall_layout_thread, &data, CLONE_KERNEL);
@@ -611,4 +606,53 @@ struct inode *nfs_layout_find_inode(struct nfs4_client *clp, const struct nfs_fh
 	return res;
 }
 
+static inline int
+found_inode(struct inode *ino, int recall_type,
+            const struct nfs_fh *cbl_fh)
+{
+	if (recall_type == RECALL_FILE)
+		return nfs_compare_fh(cbl_fh, &NFS_I(ino)->fh) == 0;
+	else
+		return NFS_I(ino)->current_layout != NULL;
+}
+
+/*
+ * Retrieve an inode based on layout recall parameters
+ */
+struct inode *
+nfs_layoutrecall_find_inode(struct nfs4_client *clp,
+                            const struct cb_pnfs_layoutrecallargs *args)
+{
+	struct nfs_server *server = NULL;
+	struct super_block *sb = NULL;
+	struct inode *ino;
+
+	dprintk("%s: Begin recall_type=%d\n", __FUNCTION__, args->cbl_recall_type);
+	down_read(&clp->cl_sem);
+	list_for_each_entry(server, &clp->cl_superblocks, nfs4_siblings) {
+		sb = server->sb;
+		if (!sb)
+			continue;
+		if (args->cbl_recall_type == RECALL_FSID &&
+		    (server->fsid.major != args->cbl_fsid.major ||
+		     server->fsid.minor != args->cbl_fsid.minor))
+			continue;
+		spin_lock(&inode_lock);
+		list_for_each_entry(ino, &sb->s_inodes, i_sb_list)
+			if (found_inode(ino, args->cbl_recall_type,
+			                &args->cbl_fh)) {
+				__iget(ino);
+				spin_unlock(&inode_lock);
+				up_read(&clp->cl_sem);
+				dprintk("%s: Return inode=%p\n", __FUNCTION__, ino);
+				return ino;
+			}
+		spin_unlock(&inode_lock);
+	}
+	up_read(&clp->cl_sem);
+
+	dprintk("%s: Return NULL. inode not found.\n", __FUNCTION__);
+	return NULL;
+}
+
 #endif /* defined(CONFIG_PNFS) */
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
index 6db79de..202c38b 100644
--- a/fs/nfs/delegation.h
+++ b/fs/nfs/delegation.h
@@ -64,8 +64,9 @@ static inline int nfs_inode_return_delegation(struct inode *inode)
 }
 
 #if defined(CONFIG_PNFS)
-int nfs_async_return_layout(struct nfs4_client *clp, struct inode *inode, void *arg);
+int nfs_async_return_layout(struct nfs4_client *clp, struct inode *inode, struct cb_pnfs_layoutrecallargs *rl);
 struct inode *nfs_layout_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle);
+struct inode *nfs_layoutrecall_find_inode(struct nfs4_client *clp, const struct cb_pnfs_layoutrecallargs *args);
 #endif /* defined(CONFIG_PNFS) */
 
 #else /* defined(CONFIG_NFS_V4) */
-- 
1.5.3.1




More information about the pNFS mailing list