[pnfs] [PATCH 20/38] [v1] pnfs: client layout cache: allow waiting for alloc_layout
Benny Halevy
bhalevy at panasas.com
Fri Jan 4 05:52:39 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 | 39 +++++++++++++++++++++++++++++++++++++--
include/linux/nfs_fs.h | 2 ++
3 files changed, 42 insertions(+), 2 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 b91f5d7..6757608 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -446,6 +446,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
*/
@@ -455,13 +463,40 @@ 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__);
- if ((lo = nfsi->current_layout) == NULL) {
- lo = nfsi->current_layout = alloc_init_layout(ino, io_ops);
+ while ((lo = nfsi->current_layout) == NULL) {
+ /* Compete against other threads on who's doing the allocation,
+ * wait until bit is cleared if we lost this race.
+ */
+ res = wait_on_bit_lock(
+ &nfsi->pnfs_layout_state, NFS_INO_LAYOUT_ALLOC,
+ pnfs_wait_schedule, TASK_INTERRUPTIBLE);
+ if (res) {
+ lo = ERR_PTR(res);
+ break;
+ }
+
+ /* Was current_layout already allocated while we slept?
+ * If not, allocate it.
+ */
+ lo = nfsi->current_layout;
+ if (!lo)
+ lo = nfsi->current_layout =
+ alloc_init_layout(ino, io_ops);
+
+ /* release the NFS_INO_LAYOUT_ALLOC bit and wake up waiters */
+ clear_bit_unlock(NFS_INO_LAYOUT_ALLOC, &nfsi->pnfs_layout_state);
+ wake_up_bit(&nfsi->pnfs_layout_state, NFS_INO_LAYOUT_ALLOC);
+
+ /* we're done here.
+ * just check whether alloc_init_layout succeeded.
+ */
if (!lo)
lo = ERR_PTR(-ENOMEM);
+ break;
}
#ifdef NFS_DEBUG
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