[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