aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFred Isaman <iisaman@netapp.com>2011-01-06 06:36:25 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2011-01-06 14:46:31 -0500
commitcf7d63f1f9895713551df2e6d18b006f8af26e91 (patch)
treefc3dbfc12332878a832c11b5ae47ff259bb1bc32
parentc31663d4a1fac5ce1954d656cbcf80eb883b814a (diff)
pnfs: serialize LAYOUTGET(openstateid)
We shouldn't send a LAYOUTGET(openstateid) unless all outstanding RPCs using the previous stateid are completed. This requires choosing the stateid to encode earlier, so we can abort if one is not available (we want to use the open stateid, but a LAYOUTGET is already out using it), and adding a count of the number of outstanding rpc calls using layout state (which for now consist solely of LAYOUTGETs). Signed-off-by: Fred Isaman <iisaman@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/nfs4proc.c7
-rw-r--r--fs/nfs/nfs4xdr.c5
-rw-r--r--fs/nfs/pnfs.c24
-rw-r--r--fs/nfs/pnfs.h1
-rw-r--r--include/linux/nfs_xdr.h1
5 files changed, 28 insertions, 10 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 5bee453d36d6..a3549ce72ab2 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -5304,6 +5304,12 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
5304 if (nfs4_setup_sequence(server, &lgp->args.seq_args, 5304 if (nfs4_setup_sequence(server, &lgp->args.seq_args,
5305 &lgp->res.seq_res, 0, task)) 5305 &lgp->res.seq_res, 0, task))
5306 return; 5306 return;
5307 if (pnfs_choose_layoutget_stateid(&lgp->args.stateid,
5308 NFS_I(lgp->args.inode)->layout,
5309 lgp->args.ctx->state)) {
5310 rpc_exit(task, NFS4_OK);
5311 return;
5312 }
5307 rpc_call_start(task); 5313 rpc_call_start(task);
5308} 5314}
5309 5315
@@ -5338,7 +5344,6 @@ static void nfs4_layoutget_release(void *calldata)
5338 struct nfs4_layoutget *lgp = calldata; 5344 struct nfs4_layoutget *lgp = calldata;
5339 5345
5340 dprintk("--> %s\n", __func__); 5346 dprintk("--> %s\n", __func__);
5341 put_layout_hdr(lgp->args.inode);
5342 if (lgp->res.layout.buf != NULL) 5347 if (lgp->res.layout.buf != NULL)
5343 free_page((unsigned long) lgp->res.layout.buf); 5348 free_page((unsigned long) lgp->res.layout.buf);
5344 put_nfs_open_context(lgp->args.ctx); 5349 put_nfs_open_context(lgp->args.ctx);
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 4e28242360d6..3cbdd0c80a2d 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -1787,7 +1787,6 @@ encode_layoutget(struct xdr_stream *xdr,
1787 const struct nfs4_layoutget_args *args, 1787 const struct nfs4_layoutget_args *args,
1788 struct compound_hdr *hdr) 1788 struct compound_hdr *hdr)
1789{ 1789{
1790 nfs4_stateid stateid;
1791 __be32 *p; 1790 __be32 *p;
1792 1791
1793 p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE); 1792 p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE);
@@ -1798,9 +1797,7 @@ encode_layoutget(struct xdr_stream *xdr,
1798 p = xdr_encode_hyper(p, args->range.offset); 1797 p = xdr_encode_hyper(p, args->range.offset);
1799 p = xdr_encode_hyper(p, args->range.length); 1798 p = xdr_encode_hyper(p, args->range.length);
1800 p = xdr_encode_hyper(p, args->minlength); 1799 p = xdr_encode_hyper(p, args->minlength);
1801 pnfs_choose_layoutget_stateid(&stateid, NFS_I(args->inode)->layout, 1800 p = xdr_encode_opaque_fixed(p, &args->stateid.data, NFS4_STATEID_SIZE);
1802 args->ctx->state);
1803 p = xdr_encode_opaque_fixed(p, &stateid.data, NFS4_STATEID_SIZE);
1804 *p = cpu_to_be32(args->maxcount); 1801 *p = cpu_to_be32(args->maxcount);
1805 1802
1806 dprintk("%s: 1st type:0x%x iomode:%d off:%lu len:%lu mc:%d\n", 1803 dprintk("%s: 1st type:0x%x iomode:%d off:%lu len:%lu mc:%d\n",
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 212cbc22c59d..59ed68bf79fa 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -371,6 +371,14 @@ pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo,
371 memcpy(&lo->plh_stateid, &new->stateid, sizeof(new->stateid)); 371 memcpy(&lo->plh_stateid, &new->stateid, sizeof(new->stateid));
372} 372}
373 373
374/* lget is set to 1 if called from inside send_layoutget call chain */
375static bool
376pnfs_layoutgets_blocked(struct pnfs_layout_hdr *lo, int lget)
377{
378 return (list_empty(&lo->plh_segs) &&
379 (atomic_read(&lo->plh_outstanding) > lget));
380}
381
374int 382int
375pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo, 383pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
376 struct nfs4_state *open_state) 384 struct nfs4_state *open_state)
@@ -379,7 +387,9 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
379 387
380 dprintk("--> %s\n", __func__); 388 dprintk("--> %s\n", __func__);
381 spin_lock(&lo->plh_inode->i_lock); 389 spin_lock(&lo->plh_inode->i_lock);
382 if (list_empty(&lo->plh_segs)) { 390 if (pnfs_layoutgets_blocked(lo, 1)) {
391 status = -EAGAIN;
392 } else if (list_empty(&lo->plh_segs)) {
383 int seq; 393 int seq;
384 394
385 do { 395 do {
@@ -414,10 +424,8 @@ send_layoutget(struct pnfs_layout_hdr *lo,
414 424
415 BUG_ON(ctx == NULL); 425 BUG_ON(ctx == NULL);
416 lgp = kzalloc(sizeof(*lgp), GFP_KERNEL); 426 lgp = kzalloc(sizeof(*lgp), GFP_KERNEL);
417 if (lgp == NULL) { 427 if (lgp == NULL)
418 put_layout_hdr(lo->plh_inode);
419 return NULL; 428 return NULL;
420 }
421 lgp->args.minlength = NFS4_MAX_UINT64; 429 lgp->args.minlength = NFS4_MAX_UINT64;
422 lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE; 430 lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE;
423 lgp->args.range.iomode = iomode; 431 lgp->args.range.iomode = iomode;
@@ -613,10 +621,16 @@ pnfs_update_layout(struct inode *ino,
613 if (test_bit(lo_fail_bit(iomode), &nfsi->layout->plh_flags)) 621 if (test_bit(lo_fail_bit(iomode), &nfsi->layout->plh_flags))
614 goto out_unlock; 622 goto out_unlock;
615 623
616 get_layout_hdr_locked(lo); /* Matched in nfs4_layoutget_release */ 624 if (pnfs_layoutgets_blocked(lo, 0))
625 goto out_unlock;
626 atomic_inc(&lo->plh_outstanding);
627
628 get_layout_hdr_locked(lo);
617 spin_unlock(&ino->i_lock); 629 spin_unlock(&ino->i_lock);
618 630
619 lseg = send_layoutget(lo, ctx, iomode); 631 lseg = send_layoutget(lo, ctx, iomode);
632 atomic_dec(&lo->plh_outstanding);
633 put_layout_hdr(ino);
620out: 634out:
621 dprintk("%s end, state 0x%lx lseg %p\n", __func__, 635 dprintk("%s end, state 0x%lx lseg %p\n", __func__,
622 nfsi->layout->plh_flags, lseg); 636 nfsi->layout->plh_flags, lseg);
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 787253e6fca3..698380da24cc 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -69,6 +69,7 @@ struct pnfs_layout_hdr {
69 struct list_head plh_layouts; /* other client layouts */ 69 struct list_head plh_layouts; /* other client layouts */
70 struct list_head plh_segs; /* layout segments list */ 70 struct list_head plh_segs; /* layout segments list */
71 nfs4_stateid plh_stateid; 71 nfs4_stateid plh_stateid;
72 atomic_t plh_outstanding; /* number of RPCs out */
72 unsigned long plh_flags; 73 unsigned long plh_flags;
73 struct inode *plh_inode; 74 struct inode *plh_inode;
74}; 75};
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 8fcc54267bba..83d36d3a12e6 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -208,6 +208,7 @@ struct nfs4_layoutget_args {
208 struct inode *inode; 208 struct inode *inode;
209 struct nfs_open_context *ctx; 209 struct nfs_open_context *ctx;
210 struct nfs4_sequence_args seq_args; 210 struct nfs4_sequence_args seq_args;
211 nfs4_stateid stateid;
211}; 212};
212 213
213struct nfs4_layoutget_res { 214struct nfs4_layoutget_res {