aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 {