[pnfs] [PATCH 19/37] pnfs: client layout cache: allow waiting for alloc_layout

Benny Halevy bhalevy at panasas.com
Tue Jan 1 05:50:48 EST 2008


we want one thread only calling alloc_layout and waiting for it.
The NFS_INO_LAYOUT_ALLOC bit in pnfs_layout_state is used
for mutual exclusion and nfs_inode.lo_waitq is used for waiting
on alloc_layout.

Signed-off-by: Benny Halevy <bhalevy at panasas.com>
---
 fs/nfs/inode.c         |    3 +++
 fs/nfs/pnfs.c          |   26 ++++++++++++++++++++++++++
 include/linux/nfs_fs.h |    2 ++
 3 files changed, 31 insertions(+), 0 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 4c47ecb..c891492 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1182,6 +1182,9 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi)
 	nfsi->delegation_state = 0;
 	init_rwsem(&nfsi->rwsem);
 #endif
+#ifdef CONFIG_PNFS
+	init_waitqueue_head(&nfsi->lo_waitq);
+#endif /* CONFIG_PNFS */
 }
 
 static void init_once(struct kmem_cache * cachep, void *foo)
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index bd10670..714de9d 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -433,6 +433,14 @@ alloc_init_layout(struct inode *ino, struct layoutdriver_io_operations *io_ops)
 	return lo;
 }
 
+static int pnfs_wait_schedule(void *word)
+{
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+	schedule();
+	return 0;
+}
+
 /*
  * get, possibly allocate current_layout
  */
@@ -442,14 +450,32 @@ get_alloc_layout(struct inode *ino,
 {
 	struct nfs_inode *nfsi = NFS_I(ino);
 	struct pnfs_layout_type *lo;
+	int res;
 
 	dprintk("%s Begin\n", __FUNCTION__);
 
+retry:
 	lo = nfsi->current_layout;
 	if (lo)
 		goto out;
 
+	res = wait_on_bit_lock(&nfsi->pnfs_layout_state, NFS_INO_LAYOUT_ALLOC,
+			       pnfs_wait_schedule, TASK_INTERRUPTIBLE);
+	if (res) {
+		lo = ERR_PTR(res);
+		goto err;
+	}
+
+	if (nfsi->current_layout) {
+		clear_bit_unlock(NFS_INO_LAYOUT_ALLOC,
+				 &nfsi->pnfs_layout_state);
+		goto retry;
+	}
+
 	lo = nfsi->current_layout = alloc_init_layout(ino, io_ops);
+	clear_bit_unlock(NFS_INO_LAYOUT_ALLOC, &nfsi->pnfs_layout_state);
+	wake_up_bit(&nfsi->pnfs_layout_state, NFS_INO_LAYOUT_ALLOC);
+
 	if (!lo) {
 		lo = ERR_PTR(-ENOMEM);
 		goto err;
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 3d6bfbf..1a093b1 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -178,7 +178,9 @@ struct nfs_inode {
 #if defined(CONFIG_PNFS)
 	unsigned long pnfs_layout_state;
 #define NFS_INO_LAYOUT_FAILED	0x0001	/* get layout failed, stop trying */
+#define NFS_INO_LAYOUT_ALLOC	0x0002	/* get layout failed, stop trying */
 	time_t pnfs_layout_suspend;
+	wait_queue_head_t lo_waitq;
 	struct pnfs_layout_type *current_layout;
 	/* use rpc_creds in this open_context to send LAYOUTCOMMIT to MDS */
 	struct nfs_open_context *layoutcommit_ctx;
-- 
1.5.3.3



More information about the pNFS mailing list