diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-08-30 14:14:02 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-08-30 14:14:02 -0400 |
commit | 0cf21c6609c582690a9407bddb72aec2732c6178 (patch) | |
tree | 4535ff929a42d7e91811cb459e202014170cc7b9 | |
parent | 0d025d271e55f3de21f0aaaf54b42d20404d2b23 (diff) | |
parent | 98b0f80c2396224bbbed81792b526e6c72ba9efa (diff) |
Merge tag 'nfs-for-4.8-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust:
"Highlights include:
Stable patches:
- Fix a refcount leak in nfs_callback_up_net
- Fix an Oopsable condition when the flexfile pNFS driver connection
to the DS fails
- Fix an Oopsable condition in NFSv4.1 server callback races
- Ensure pNFS clients stop doing I/O to the DS if their lease has
expired, as required by the NFSv4.1 protocol
Bugfixes:
- Fix potential looping in the NFSv4.x migration code
- Patch series to close callback races for OPEN, LAYOUTGET and
LAYOUTRETURN
- Silence WARN_ON when NFSv4.1 over RDMA is in use
- Fix a LAYOUTCOMMIT race in the pNFS/blocks client
- Fix pNFS timeout issues when the DS fails"
* tag 'nfs-for-4.8-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
NFSv4.x: Fix a refcount leak in nfs_callback_up_net
NFS4: Avoid migration loops
pNFS/flexfiles: Fix an Oopsable condition when connection to the DS fails
NFSv4.1: Remove obsolete and incorrrect assignment in nfs4_callback_sequence
NFSv4.1: Close callback races for OPEN, LAYOUTGET and LAYOUTRETURN
NFSv4.1: Defer bumping the slot sequence number until we free the slot
NFSv4.1: Delay callback processing when there are referring triples
NFSv4.1: Fix Oopsable condition in server callback races
SUNRPC: Silence WARN_ON when NFSv4.1 over RDMA is in use
pnfs/blocklayout: update last_write_offset atomically with extents
pNFS: The client must not do I/O to the DS if it's lease has expired
pNFS: Handle NFS4ERR_OLD_STATEID correctly in LAYOUTSTAT calls
pNFS/flexfiles: Set reasonable default retrans values for the data channel
NFS: Allow the mount option retrans=0
pNFS/flexfiles: Fix layoutstat periodic reporting
-rw-r--r-- | fs/nfs/blocklayout/blocklayout.c | 2 | ||||
-rw-r--r-- | fs/nfs/blocklayout/blocklayout.h | 3 | ||||
-rw-r--r-- | fs/nfs/blocklayout/extent_tree.c | 10 | ||||
-rw-r--r-- | fs/nfs/callback.c | 1 | ||||
-rw-r--r-- | fs/nfs/callback_proc.c | 8 | ||||
-rw-r--r-- | fs/nfs/client.c | 10 | ||||
-rw-r--r-- | fs/nfs/flexfilelayout/flexfilelayout.c | 45 | ||||
-rw-r--r-- | fs/nfs/flexfilelayout/flexfilelayout.h | 2 | ||||
-rw-r--r-- | fs/nfs/flexfilelayout/flexfilelayoutdev.c | 23 | ||||
-rw-r--r-- | fs/nfs/internal.h | 5 | ||||
-rw-r--r-- | fs/nfs/nfs42proc.c | 34 | ||||
-rw-r--r-- | fs/nfs/nfs4client.c | 5 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 89 | ||||
-rw-r--r-- | fs/nfs/nfs4session.c | 53 | ||||
-rw-r--r-- | fs/nfs/nfs4session.h | 7 | ||||
-rw-r--r-- | fs/nfs/pnfs.c | 2 | ||||
-rw-r--r-- | fs/nfs/super.c | 19 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 4 |
18 files changed, 244 insertions, 78 deletions
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index f55a4e756047..217847679f0e 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c | |||
@@ -346,7 +346,7 @@ static void bl_write_cleanup(struct work_struct *work) | |||
346 | PAGE_SIZE - 1) & (loff_t)PAGE_MASK; | 346 | PAGE_SIZE - 1) & (loff_t)PAGE_MASK; |
347 | 347 | ||
348 | ext_tree_mark_written(bl, start >> SECTOR_SHIFT, | 348 | ext_tree_mark_written(bl, start >> SECTOR_SHIFT, |
349 | (end - start) >> SECTOR_SHIFT); | 349 | (end - start) >> SECTOR_SHIFT, end); |
350 | } | 350 | } |
351 | 351 | ||
352 | pnfs_ld_write_done(hdr); | 352 | pnfs_ld_write_done(hdr); |
diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h index 18e6fd0b9506..efc007f00742 100644 --- a/fs/nfs/blocklayout/blocklayout.h +++ b/fs/nfs/blocklayout/blocklayout.h | |||
@@ -141,6 +141,7 @@ struct pnfs_block_layout { | |||
141 | struct rb_root bl_ext_ro; | 141 | struct rb_root bl_ext_ro; |
142 | spinlock_t bl_ext_lock; /* Protects list manipulation */ | 142 | spinlock_t bl_ext_lock; /* Protects list manipulation */ |
143 | bool bl_scsi_layout; | 143 | bool bl_scsi_layout; |
144 | u64 bl_lwb; | ||
144 | }; | 145 | }; |
145 | 146 | ||
146 | static inline struct pnfs_block_layout * | 147 | static inline struct pnfs_block_layout * |
@@ -182,7 +183,7 @@ int ext_tree_insert(struct pnfs_block_layout *bl, | |||
182 | int ext_tree_remove(struct pnfs_block_layout *bl, bool rw, sector_t start, | 183 | int ext_tree_remove(struct pnfs_block_layout *bl, bool rw, sector_t start, |
183 | sector_t end); | 184 | sector_t end); |
184 | int ext_tree_mark_written(struct pnfs_block_layout *bl, sector_t start, | 185 | int ext_tree_mark_written(struct pnfs_block_layout *bl, sector_t start, |
185 | sector_t len); | 186 | sector_t len, u64 lwb); |
186 | bool ext_tree_lookup(struct pnfs_block_layout *bl, sector_t isect, | 187 | bool ext_tree_lookup(struct pnfs_block_layout *bl, sector_t isect, |
187 | struct pnfs_block_extent *ret, bool rw); | 188 | struct pnfs_block_extent *ret, bool rw); |
188 | int ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg); | 189 | int ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg); |
diff --git a/fs/nfs/blocklayout/extent_tree.c b/fs/nfs/blocklayout/extent_tree.c index 992bcb19c11e..c85fbfd2d0d9 100644 --- a/fs/nfs/blocklayout/extent_tree.c +++ b/fs/nfs/blocklayout/extent_tree.c | |||
@@ -402,7 +402,7 @@ ext_tree_split(struct rb_root *root, struct pnfs_block_extent *be, | |||
402 | 402 | ||
403 | int | 403 | int |
404 | ext_tree_mark_written(struct pnfs_block_layout *bl, sector_t start, | 404 | ext_tree_mark_written(struct pnfs_block_layout *bl, sector_t start, |
405 | sector_t len) | 405 | sector_t len, u64 lwb) |
406 | { | 406 | { |
407 | struct rb_root *root = &bl->bl_ext_rw; | 407 | struct rb_root *root = &bl->bl_ext_rw; |
408 | sector_t end = start + len; | 408 | sector_t end = start + len; |
@@ -471,6 +471,8 @@ ext_tree_mark_written(struct pnfs_block_layout *bl, sector_t start, | |||
471 | } | 471 | } |
472 | } | 472 | } |
473 | out: | 473 | out: |
474 | if (bl->bl_lwb < lwb) | ||
475 | bl->bl_lwb = lwb; | ||
474 | spin_unlock(&bl->bl_ext_lock); | 476 | spin_unlock(&bl->bl_ext_lock); |
475 | 477 | ||
476 | __ext_put_deviceids(&tmp); | 478 | __ext_put_deviceids(&tmp); |
@@ -518,7 +520,7 @@ static __be32 *encode_scsi_range(struct pnfs_block_extent *be, __be32 *p) | |||
518 | } | 520 | } |
519 | 521 | ||
520 | static int ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p, | 522 | static int ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p, |
521 | size_t buffer_size, size_t *count) | 523 | size_t buffer_size, size_t *count, __u64 *lastbyte) |
522 | { | 524 | { |
523 | struct pnfs_block_extent *be; | 525 | struct pnfs_block_extent *be; |
524 | int ret = 0; | 526 | int ret = 0; |
@@ -542,6 +544,8 @@ static int ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p, | |||
542 | p = encode_block_extent(be, p); | 544 | p = encode_block_extent(be, p); |
543 | be->be_tag = EXTENT_COMMITTING; | 545 | be->be_tag = EXTENT_COMMITTING; |
544 | } | 546 | } |
547 | *lastbyte = bl->bl_lwb - 1; | ||
548 | bl->bl_lwb = 0; | ||
545 | spin_unlock(&bl->bl_ext_lock); | 549 | spin_unlock(&bl->bl_ext_lock); |
546 | 550 | ||
547 | return ret; | 551 | return ret; |
@@ -564,7 +568,7 @@ ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg) | |||
564 | arg->layoutupdate_pages = &arg->layoutupdate_page; | 568 | arg->layoutupdate_pages = &arg->layoutupdate_page; |
565 | 569 | ||
566 | retry: | 570 | retry: |
567 | ret = ext_tree_encode_commit(bl, start_p + 1, buffer_size, &count); | 571 | ret = ext_tree_encode_commit(bl, start_p + 1, buffer_size, &count, &arg->lastbytewritten); |
568 | if (unlikely(ret)) { | 572 | if (unlikely(ret)) { |
569 | ext_tree_free_commitdata(arg, buffer_size); | 573 | ext_tree_free_commitdata(arg, buffer_size); |
570 | 574 | ||
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index a7f2e6e33305..52a28311e2a4 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -275,6 +275,7 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, | |||
275 | err_socks: | 275 | err_socks: |
276 | svc_rpcb_cleanup(serv, net); | 276 | svc_rpcb_cleanup(serv, net); |
277 | err_bind: | 277 | err_bind: |
278 | nn->cb_users[minorversion]--; | ||
278 | dprintk("NFS: Couldn't create callback socket: err = %d; " | 279 | dprintk("NFS: Couldn't create callback socket: err = %d; " |
279 | "net = %p\n", ret, net); | 280 | "net = %p\n", ret, net); |
280 | return ret; | 281 | return ret; |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index c92a75e066a6..f953ef6b2f2e 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -454,11 +454,8 @@ static bool referring_call_exists(struct nfs_client *clp, | |||
454 | ((u32 *)&rclist->rcl_sessionid.data)[3], | 454 | ((u32 *)&rclist->rcl_sessionid.data)[3], |
455 | ref->rc_sequenceid, ref->rc_slotid); | 455 | ref->rc_sequenceid, ref->rc_slotid); |
456 | 456 | ||
457 | spin_lock(&tbl->slot_tbl_lock); | 457 | status = nfs4_slot_wait_on_seqid(tbl, ref->rc_slotid, |
458 | status = (test_bit(ref->rc_slotid, tbl->used_slots) && | 458 | ref->rc_sequenceid, HZ >> 1) < 0; |
459 | tbl->slots[ref->rc_slotid].seq_nr == | ||
460 | ref->rc_sequenceid); | ||
461 | spin_unlock(&tbl->slot_tbl_lock); | ||
462 | if (status) | 459 | if (status) |
463 | goto out; | 460 | goto out; |
464 | } | 461 | } |
@@ -487,7 +484,6 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, | |||
487 | goto out; | 484 | goto out; |
488 | 485 | ||
489 | tbl = &clp->cl_session->bc_slot_table; | 486 | tbl = &clp->cl_session->bc_slot_table; |
490 | slot = tbl->slots + args->csa_slotid; | ||
491 | 487 | ||
492 | /* Set up res before grabbing the spinlock */ | 488 | /* Set up res before grabbing the spinlock */ |
493 | memcpy(&res->csr_sessionid, &args->csa_sessionid, | 489 | memcpy(&res->csr_sessionid, &args->csa_sessionid, |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 003ebce4bbc4..1e106780a237 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -426,7 +426,7 @@ EXPORT_SYMBOL_GPL(nfs_mark_client_ready); | |||
426 | * Initialise the timeout values for a connection | 426 | * Initialise the timeout values for a connection |
427 | */ | 427 | */ |
428 | void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | 428 | void nfs_init_timeout_values(struct rpc_timeout *to, int proto, |
429 | unsigned int timeo, unsigned int retrans) | 429 | int timeo, int retrans) |
430 | { | 430 | { |
431 | to->to_initval = timeo * HZ / 10; | 431 | to->to_initval = timeo * HZ / 10; |
432 | to->to_retries = retrans; | 432 | to->to_retries = retrans; |
@@ -434,9 +434,9 @@ void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | |||
434 | switch (proto) { | 434 | switch (proto) { |
435 | case XPRT_TRANSPORT_TCP: | 435 | case XPRT_TRANSPORT_TCP: |
436 | case XPRT_TRANSPORT_RDMA: | 436 | case XPRT_TRANSPORT_RDMA: |
437 | if (to->to_retries == 0) | 437 | if (retrans == NFS_UNSPEC_RETRANS) |
438 | to->to_retries = NFS_DEF_TCP_RETRANS; | 438 | to->to_retries = NFS_DEF_TCP_RETRANS; |
439 | if (to->to_initval == 0) | 439 | if (timeo == NFS_UNSPEC_TIMEO || to->to_retries == 0) |
440 | to->to_initval = NFS_DEF_TCP_TIMEO * HZ / 10; | 440 | to->to_initval = NFS_DEF_TCP_TIMEO * HZ / 10; |
441 | if (to->to_initval > NFS_MAX_TCP_TIMEOUT) | 441 | if (to->to_initval > NFS_MAX_TCP_TIMEOUT) |
442 | to->to_initval = NFS_MAX_TCP_TIMEOUT; | 442 | to->to_initval = NFS_MAX_TCP_TIMEOUT; |
@@ -449,9 +449,9 @@ void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | |||
449 | to->to_exponential = 0; | 449 | to->to_exponential = 0; |
450 | break; | 450 | break; |
451 | case XPRT_TRANSPORT_UDP: | 451 | case XPRT_TRANSPORT_UDP: |
452 | if (to->to_retries == 0) | 452 | if (retrans == NFS_UNSPEC_RETRANS) |
453 | to->to_retries = NFS_DEF_UDP_RETRANS; | 453 | to->to_retries = NFS_DEF_UDP_RETRANS; |
454 | if (!to->to_initval) | 454 | if (timeo == NFS_UNSPEC_TIMEO || to->to_initval == 0) |
455 | to->to_initval = NFS_DEF_UDP_TIMEO * HZ / 10; | 455 | to->to_initval = NFS_DEF_UDP_TIMEO * HZ / 10; |
456 | if (to->to_initval > NFS_MAX_UDP_TIMEOUT) | 456 | if (to->to_initval > NFS_MAX_UDP_TIMEOUT) |
457 | to->to_initval = NFS_MAX_UDP_TIMEOUT; | 457 | to->to_initval = NFS_MAX_UDP_TIMEOUT; |
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index e6206eaf2bdf..51b51369704c 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c | |||
@@ -37,6 +37,7 @@ ff_layout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags) | |||
37 | if (ffl) { | 37 | if (ffl) { |
38 | INIT_LIST_HEAD(&ffl->error_list); | 38 | INIT_LIST_HEAD(&ffl->error_list); |
39 | INIT_LIST_HEAD(&ffl->mirrors); | 39 | INIT_LIST_HEAD(&ffl->mirrors); |
40 | ffl->last_report_time = ktime_get(); | ||
40 | return &ffl->generic_hdr; | 41 | return &ffl->generic_hdr; |
41 | } else | 42 | } else |
42 | return NULL; | 43 | return NULL; |
@@ -640,19 +641,18 @@ nfs4_ff_layoutstat_start_io(struct nfs4_ff_layout_mirror *mirror, | |||
640 | { | 641 | { |
641 | static const ktime_t notime = {0}; | 642 | static const ktime_t notime = {0}; |
642 | s64 report_interval = FF_LAYOUTSTATS_REPORT_INTERVAL; | 643 | s64 report_interval = FF_LAYOUTSTATS_REPORT_INTERVAL; |
644 | struct nfs4_flexfile_layout *ffl = FF_LAYOUT_FROM_HDR(mirror->layout); | ||
643 | 645 | ||
644 | nfs4_ff_start_busy_timer(&layoutstat->busy_timer, now); | 646 | nfs4_ff_start_busy_timer(&layoutstat->busy_timer, now); |
645 | if (ktime_equal(mirror->start_time, notime)) | 647 | if (ktime_equal(mirror->start_time, notime)) |
646 | mirror->start_time = now; | 648 | mirror->start_time = now; |
647 | if (ktime_equal(mirror->last_report_time, notime)) | ||
648 | mirror->last_report_time = now; | ||
649 | if (mirror->report_interval != 0) | 649 | if (mirror->report_interval != 0) |
650 | report_interval = (s64)mirror->report_interval * 1000LL; | 650 | report_interval = (s64)mirror->report_interval * 1000LL; |
651 | else if (layoutstats_timer != 0) | 651 | else if (layoutstats_timer != 0) |
652 | report_interval = (s64)layoutstats_timer * 1000LL; | 652 | report_interval = (s64)layoutstats_timer * 1000LL; |
653 | if (ktime_to_ms(ktime_sub(now, mirror->last_report_time)) >= | 653 | if (ktime_to_ms(ktime_sub(now, ffl->last_report_time)) >= |
654 | report_interval) { | 654 | report_interval) { |
655 | mirror->last_report_time = now; | 655 | ffl->last_report_time = now; |
656 | return true; | 656 | return true; |
657 | } | 657 | } |
658 | 658 | ||
@@ -806,11 +806,14 @@ ff_layout_choose_best_ds_for_read(struct pnfs_layout_segment *lseg, | |||
806 | { | 806 | { |
807 | struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg); | 807 | struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg); |
808 | struct nfs4_pnfs_ds *ds; | 808 | struct nfs4_pnfs_ds *ds; |
809 | bool fail_return = false; | ||
809 | int idx; | 810 | int idx; |
810 | 811 | ||
811 | /* mirrors are sorted by efficiency */ | 812 | /* mirrors are sorted by efficiency */ |
812 | for (idx = start_idx; idx < fls->mirror_array_cnt; idx++) { | 813 | for (idx = start_idx; idx < fls->mirror_array_cnt; idx++) { |
813 | ds = nfs4_ff_layout_prepare_ds(lseg, idx, false); | 814 | if (idx+1 == fls->mirror_array_cnt) |
815 | fail_return = true; | ||
816 | ds = nfs4_ff_layout_prepare_ds(lseg, idx, fail_return); | ||
814 | if (ds) { | 817 | if (ds) { |
815 | *best_idx = idx; | 818 | *best_idx = idx; |
816 | return ds; | 819 | return ds; |
@@ -859,6 +862,7 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio, | |||
859 | struct nfs4_pnfs_ds *ds; | 862 | struct nfs4_pnfs_ds *ds; |
860 | int ds_idx; | 863 | int ds_idx; |
861 | 864 | ||
865 | retry: | ||
862 | /* Use full layout for now */ | 866 | /* Use full layout for now */ |
863 | if (!pgio->pg_lseg) | 867 | if (!pgio->pg_lseg) |
864 | ff_layout_pg_get_read(pgio, req, false); | 868 | ff_layout_pg_get_read(pgio, req, false); |
@@ -871,10 +875,13 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio, | |||
871 | 875 | ||
872 | ds = ff_layout_choose_best_ds_for_read(pgio->pg_lseg, 0, &ds_idx); | 876 | ds = ff_layout_choose_best_ds_for_read(pgio->pg_lseg, 0, &ds_idx); |
873 | if (!ds) { | 877 | if (!ds) { |
874 | if (ff_layout_no_fallback_to_mds(pgio->pg_lseg)) | 878 | if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg)) |
875 | goto out_pnfs; | ||
876 | else | ||
877 | goto out_mds; | 879 | goto out_mds; |
880 | pnfs_put_lseg(pgio->pg_lseg); | ||
881 | pgio->pg_lseg = NULL; | ||
882 | /* Sleep for 1 second before retrying */ | ||
883 | ssleep(1); | ||
884 | goto retry; | ||
878 | } | 885 | } |
879 | 886 | ||
880 | mirror = FF_LAYOUT_COMP(pgio->pg_lseg, ds_idx); | 887 | mirror = FF_LAYOUT_COMP(pgio->pg_lseg, ds_idx); |
@@ -890,12 +897,6 @@ out_mds: | |||
890 | pnfs_put_lseg(pgio->pg_lseg); | 897 | pnfs_put_lseg(pgio->pg_lseg); |
891 | pgio->pg_lseg = NULL; | 898 | pgio->pg_lseg = NULL; |
892 | nfs_pageio_reset_read_mds(pgio); | 899 | nfs_pageio_reset_read_mds(pgio); |
893 | return; | ||
894 | |||
895 | out_pnfs: | ||
896 | pnfs_set_lo_fail(pgio->pg_lseg); | ||
897 | pnfs_put_lseg(pgio->pg_lseg); | ||
898 | pgio->pg_lseg = NULL; | ||
899 | } | 900 | } |
900 | 901 | ||
901 | static void | 902 | static void |
@@ -909,6 +910,7 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio, | |||
909 | int i; | 910 | int i; |
910 | int status; | 911 | int status; |
911 | 912 | ||
913 | retry: | ||
912 | if (!pgio->pg_lseg) { | 914 | if (!pgio->pg_lseg) { |
913 | pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, | 915 | pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, |
914 | req->wb_context, | 916 | req->wb_context, |
@@ -940,10 +942,13 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio, | |||
940 | for (i = 0; i < pgio->pg_mirror_count; i++) { | 942 | for (i = 0; i < pgio->pg_mirror_count; i++) { |
941 | ds = nfs4_ff_layout_prepare_ds(pgio->pg_lseg, i, true); | 943 | ds = nfs4_ff_layout_prepare_ds(pgio->pg_lseg, i, true); |
942 | if (!ds) { | 944 | if (!ds) { |
943 | if (ff_layout_no_fallback_to_mds(pgio->pg_lseg)) | 945 | if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg)) |
944 | goto out_pnfs; | ||
945 | else | ||
946 | goto out_mds; | 946 | goto out_mds; |
947 | pnfs_put_lseg(pgio->pg_lseg); | ||
948 | pgio->pg_lseg = NULL; | ||
949 | /* Sleep for 1 second before retrying */ | ||
950 | ssleep(1); | ||
951 | goto retry; | ||
947 | } | 952 | } |
948 | pgm = &pgio->pg_mirrors[i]; | 953 | pgm = &pgio->pg_mirrors[i]; |
949 | mirror = FF_LAYOUT_COMP(pgio->pg_lseg, i); | 954 | mirror = FF_LAYOUT_COMP(pgio->pg_lseg, i); |
@@ -956,12 +961,6 @@ out_mds: | |||
956 | pnfs_put_lseg(pgio->pg_lseg); | 961 | pnfs_put_lseg(pgio->pg_lseg); |
957 | pgio->pg_lseg = NULL; | 962 | pgio->pg_lseg = NULL; |
958 | nfs_pageio_reset_write_mds(pgio); | 963 | nfs_pageio_reset_write_mds(pgio); |
959 | return; | ||
960 | |||
961 | out_pnfs: | ||
962 | pnfs_set_lo_fail(pgio->pg_lseg); | ||
963 | pnfs_put_lseg(pgio->pg_lseg); | ||
964 | pgio->pg_lseg = NULL; | ||
965 | } | 964 | } |
966 | 965 | ||
967 | static unsigned int | 966 | static unsigned int |
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.h b/fs/nfs/flexfilelayout/flexfilelayout.h index 1bcdb15d0c41..3ee0c9fcea76 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.h +++ b/fs/nfs/flexfilelayout/flexfilelayout.h | |||
@@ -84,7 +84,6 @@ struct nfs4_ff_layout_mirror { | |||
84 | struct nfs4_ff_layoutstat read_stat; | 84 | struct nfs4_ff_layoutstat read_stat; |
85 | struct nfs4_ff_layoutstat write_stat; | 85 | struct nfs4_ff_layoutstat write_stat; |
86 | ktime_t start_time; | 86 | ktime_t start_time; |
87 | ktime_t last_report_time; | ||
88 | u32 report_interval; | 87 | u32 report_interval; |
89 | }; | 88 | }; |
90 | 89 | ||
@@ -101,6 +100,7 @@ struct nfs4_flexfile_layout { | |||
101 | struct pnfs_ds_commit_info commit_info; | 100 | struct pnfs_ds_commit_info commit_info; |
102 | struct list_head mirrors; | 101 | struct list_head mirrors; |
103 | struct list_head error_list; /* nfs4_ff_layout_ds_err */ | 102 | struct list_head error_list; /* nfs4_ff_layout_ds_err */ |
103 | ktime_t last_report_time; /* Layoutstat report times */ | ||
104 | }; | 104 | }; |
105 | 105 | ||
106 | static inline struct nfs4_flexfile_layout * | 106 | static inline struct nfs4_flexfile_layout * |
diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c index 0aa36be71fce..f7a3f6b05369 100644 --- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c +++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c | |||
@@ -17,8 +17,8 @@ | |||
17 | 17 | ||
18 | #define NFSDBG_FACILITY NFSDBG_PNFS_LD | 18 | #define NFSDBG_FACILITY NFSDBG_PNFS_LD |
19 | 19 | ||
20 | static unsigned int dataserver_timeo = NFS4_DEF_DS_TIMEO; | 20 | static unsigned int dataserver_timeo = NFS_DEF_TCP_RETRANS; |
21 | static unsigned int dataserver_retrans = NFS4_DEF_DS_RETRANS; | 21 | static unsigned int dataserver_retrans; |
22 | 22 | ||
23 | void nfs4_ff_layout_put_deviceid(struct nfs4_ff_layout_ds *mirror_ds) | 23 | void nfs4_ff_layout_put_deviceid(struct nfs4_ff_layout_ds *mirror_ds) |
24 | { | 24 | { |
@@ -379,7 +379,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, | |||
379 | 379 | ||
380 | devid = &mirror->mirror_ds->id_node; | 380 | devid = &mirror->mirror_ds->id_node; |
381 | if (ff_layout_test_devid_unavailable(devid)) | 381 | if (ff_layout_test_devid_unavailable(devid)) |
382 | goto out; | 382 | goto out_fail; |
383 | 383 | ||
384 | ds = mirror->mirror_ds->ds; | 384 | ds = mirror->mirror_ds->ds; |
385 | /* matching smp_wmb() in _nfs4_pnfs_v3/4_ds_connect */ | 385 | /* matching smp_wmb() in _nfs4_pnfs_v3/4_ds_connect */ |
@@ -405,15 +405,16 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, | |||
405 | mirror->mirror_ds->ds_versions[0].rsize = max_payload; | 405 | mirror->mirror_ds->ds_versions[0].rsize = max_payload; |
406 | if (mirror->mirror_ds->ds_versions[0].wsize > max_payload) | 406 | if (mirror->mirror_ds->ds_versions[0].wsize > max_payload) |
407 | mirror->mirror_ds->ds_versions[0].wsize = max_payload; | 407 | mirror->mirror_ds->ds_versions[0].wsize = max_payload; |
408 | } else { | 408 | goto out; |
409 | ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout), | ||
410 | mirror, lseg->pls_range.offset, | ||
411 | lseg->pls_range.length, NFS4ERR_NXIO, | ||
412 | OP_ILLEGAL, GFP_NOIO); | ||
413 | if (fail_return || !ff_layout_has_available_ds(lseg)) | ||
414 | pnfs_error_mark_layout_for_return(ino, lseg); | ||
415 | ds = NULL; | ||
416 | } | 409 | } |
410 | ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout), | ||
411 | mirror, lseg->pls_range.offset, | ||
412 | lseg->pls_range.length, NFS4ERR_NXIO, | ||
413 | OP_ILLEGAL, GFP_NOIO); | ||
414 | out_fail: | ||
415 | if (fail_return || !ff_layout_has_available_ds(lseg)) | ||
416 | pnfs_error_mark_layout_for_return(ino, lseg); | ||
417 | ds = NULL; | ||
417 | out: | 418 | out: |
418 | return ds; | 419 | return ds; |
419 | } | 420 | } |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 7ce5e023c3c3..74935a19e4bf 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -58,6 +58,9 @@ struct nfs_clone_mount { | |||
58 | */ | 58 | */ |
59 | #define NFS_UNSPEC_PORT (-1) | 59 | #define NFS_UNSPEC_PORT (-1) |
60 | 60 | ||
61 | #define NFS_UNSPEC_RETRANS (UINT_MAX) | ||
62 | #define NFS_UNSPEC_TIMEO (UINT_MAX) | ||
63 | |||
61 | /* | 64 | /* |
62 | * Maximum number of pages that readdir can use for creating | 65 | * Maximum number of pages that readdir can use for creating |
63 | * a vmapped array of pages. | 66 | * a vmapped array of pages. |
@@ -156,7 +159,7 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *, | |||
156 | int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *, struct nfs_fattr *); | 159 | int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *, struct nfs_fattr *); |
157 | void nfs_server_insert_lists(struct nfs_server *); | 160 | void nfs_server_insert_lists(struct nfs_server *); |
158 | void nfs_server_remove_lists(struct nfs_server *); | 161 | void nfs_server_remove_lists(struct nfs_server *); |
159 | void nfs_init_timeout_values(struct rpc_timeout *, int, unsigned int, unsigned int); | 162 | void nfs_init_timeout_values(struct rpc_timeout *to, int proto, int timeo, int retrans); |
160 | int nfs_init_server_rpcclient(struct nfs_server *, const struct rpc_timeout *t, | 163 | int nfs_init_server_rpcclient(struct nfs_server *, const struct rpc_timeout *t, |
161 | rpc_authflavor_t); | 164 | rpc_authflavor_t); |
162 | struct nfs_server *nfs_alloc_server(void); | 165 | struct nfs_server *nfs_alloc_server(void); |
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index 6f4752734804..64b43b4ad9dd 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c | |||
@@ -318,10 +318,22 @@ static void | |||
318 | nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata) | 318 | nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata) |
319 | { | 319 | { |
320 | struct nfs42_layoutstat_data *data = calldata; | 320 | struct nfs42_layoutstat_data *data = calldata; |
321 | struct nfs_server *server = NFS_SERVER(data->args.inode); | 321 | struct inode *inode = data->inode; |
322 | struct nfs_server *server = NFS_SERVER(inode); | ||
323 | struct pnfs_layout_hdr *lo; | ||
322 | 324 | ||
325 | spin_lock(&inode->i_lock); | ||
326 | lo = NFS_I(inode)->layout; | ||
327 | if (!pnfs_layout_is_valid(lo)) { | ||
328 | spin_unlock(&inode->i_lock); | ||
329 | rpc_exit(task, 0); | ||
330 | return; | ||
331 | } | ||
332 | nfs4_stateid_copy(&data->args.stateid, &lo->plh_stateid); | ||
333 | spin_unlock(&inode->i_lock); | ||
323 | nfs41_setup_sequence(nfs4_get_session(server), &data->args.seq_args, | 334 | nfs41_setup_sequence(nfs4_get_session(server), &data->args.seq_args, |
324 | &data->res.seq_res, task); | 335 | &data->res.seq_res, task); |
336 | |||
325 | } | 337 | } |
326 | 338 | ||
327 | static void | 339 | static void |
@@ -341,11 +353,11 @@ nfs42_layoutstat_done(struct rpc_task *task, void *calldata) | |||
341 | case -NFS4ERR_ADMIN_REVOKED: | 353 | case -NFS4ERR_ADMIN_REVOKED: |
342 | case -NFS4ERR_DELEG_REVOKED: | 354 | case -NFS4ERR_DELEG_REVOKED: |
343 | case -NFS4ERR_STALE_STATEID: | 355 | case -NFS4ERR_STALE_STATEID: |
344 | case -NFS4ERR_OLD_STATEID: | ||
345 | case -NFS4ERR_BAD_STATEID: | 356 | case -NFS4ERR_BAD_STATEID: |
346 | spin_lock(&inode->i_lock); | 357 | spin_lock(&inode->i_lock); |
347 | lo = NFS_I(inode)->layout; | 358 | lo = NFS_I(inode)->layout; |
348 | if (lo && nfs4_stateid_match(&data->args.stateid, | 359 | if (pnfs_layout_is_valid(lo) && |
360 | nfs4_stateid_match(&data->args.stateid, | ||
349 | &lo->plh_stateid)) { | 361 | &lo->plh_stateid)) { |
350 | LIST_HEAD(head); | 362 | LIST_HEAD(head); |
351 | 363 | ||
@@ -359,11 +371,23 @@ nfs42_layoutstat_done(struct rpc_task *task, void *calldata) | |||
359 | } else | 371 | } else |
360 | spin_unlock(&inode->i_lock); | 372 | spin_unlock(&inode->i_lock); |
361 | break; | 373 | break; |
374 | case -NFS4ERR_OLD_STATEID: | ||
375 | spin_lock(&inode->i_lock); | ||
376 | lo = NFS_I(inode)->layout; | ||
377 | if (pnfs_layout_is_valid(lo) && | ||
378 | nfs4_stateid_match_other(&data->args.stateid, | ||
379 | &lo->plh_stateid)) { | ||
380 | /* Do we need to delay before resending? */ | ||
381 | if (!nfs4_stateid_is_newer(&lo->plh_stateid, | ||
382 | &data->args.stateid)) | ||
383 | rpc_delay(task, HZ); | ||
384 | rpc_restart_call_prepare(task); | ||
385 | } | ||
386 | spin_unlock(&inode->i_lock); | ||
387 | break; | ||
362 | case -ENOTSUPP: | 388 | case -ENOTSUPP: |
363 | case -EOPNOTSUPP: | 389 | case -EOPNOTSUPP: |
364 | NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTSTATS; | 390 | NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTSTATS; |
365 | default: | ||
366 | break; | ||
367 | } | 391 | } |
368 | 392 | ||
369 | dprintk("%s server returns %d\n", __func__, task->tk_status); | 393 | dprintk("%s server returns %d\n", __func__, task->tk_status); |
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 8d7d08d4f95f..cd3b7cfdde16 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c | |||
@@ -817,6 +817,11 @@ static int nfs4_set_client(struct nfs_server *server, | |||
817 | goto error; | 817 | goto error; |
818 | } | 818 | } |
819 | 819 | ||
820 | if (server->nfs_client == clp) { | ||
821 | error = -ELOOP; | ||
822 | goto error; | ||
823 | } | ||
824 | |||
820 | /* | 825 | /* |
821 | * Query for the lease time on clientid setup or renewal | 826 | * Query for the lease time on clientid setup or renewal |
822 | * | 827 | * |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 1949bbd806eb..f5aecaabcb7c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -634,15 +634,11 @@ out_sleep: | |||
634 | } | 634 | } |
635 | EXPORT_SYMBOL_GPL(nfs40_setup_sequence); | 635 | EXPORT_SYMBOL_GPL(nfs40_setup_sequence); |
636 | 636 | ||
637 | static int nfs40_sequence_done(struct rpc_task *task, | 637 | static void nfs40_sequence_free_slot(struct nfs4_sequence_res *res) |
638 | struct nfs4_sequence_res *res) | ||
639 | { | 638 | { |
640 | struct nfs4_slot *slot = res->sr_slot; | 639 | struct nfs4_slot *slot = res->sr_slot; |
641 | struct nfs4_slot_table *tbl; | 640 | struct nfs4_slot_table *tbl; |
642 | 641 | ||
643 | if (slot == NULL) | ||
644 | goto out; | ||
645 | |||
646 | tbl = slot->table; | 642 | tbl = slot->table; |
647 | spin_lock(&tbl->slot_tbl_lock); | 643 | spin_lock(&tbl->slot_tbl_lock); |
648 | if (!nfs41_wake_and_assign_slot(tbl, slot)) | 644 | if (!nfs41_wake_and_assign_slot(tbl, slot)) |
@@ -650,7 +646,13 @@ static int nfs40_sequence_done(struct rpc_task *task, | |||
650 | spin_unlock(&tbl->slot_tbl_lock); | 646 | spin_unlock(&tbl->slot_tbl_lock); |
651 | 647 | ||
652 | res->sr_slot = NULL; | 648 | res->sr_slot = NULL; |
653 | out: | 649 | } |
650 | |||
651 | static int nfs40_sequence_done(struct rpc_task *task, | ||
652 | struct nfs4_sequence_res *res) | ||
653 | { | ||
654 | if (res->sr_slot != NULL) | ||
655 | nfs40_sequence_free_slot(res); | ||
654 | return 1; | 656 | return 1; |
655 | } | 657 | } |
656 | 658 | ||
@@ -666,6 +668,11 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) | |||
666 | tbl = slot->table; | 668 | tbl = slot->table; |
667 | session = tbl->session; | 669 | session = tbl->session; |
668 | 670 | ||
671 | /* Bump the slot sequence number */ | ||
672 | if (slot->seq_done) | ||
673 | slot->seq_nr++; | ||
674 | slot->seq_done = 0; | ||
675 | |||
669 | spin_lock(&tbl->slot_tbl_lock); | 676 | spin_lock(&tbl->slot_tbl_lock); |
670 | /* Be nice to the server: try to ensure that the last transmitted | 677 | /* Be nice to the server: try to ensure that the last transmitted |
671 | * value for highest_user_slotid <= target_highest_slotid | 678 | * value for highest_user_slotid <= target_highest_slotid |
@@ -686,9 +693,12 @@ out_unlock: | |||
686 | res->sr_slot = NULL; | 693 | res->sr_slot = NULL; |
687 | if (send_new_highest_used_slotid) | 694 | if (send_new_highest_used_slotid) |
688 | nfs41_notify_server(session->clp); | 695 | nfs41_notify_server(session->clp); |
696 | if (waitqueue_active(&tbl->slot_waitq)) | ||
697 | wake_up_all(&tbl->slot_waitq); | ||
689 | } | 698 | } |
690 | 699 | ||
691 | int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) | 700 | static int nfs41_sequence_process(struct rpc_task *task, |
701 | struct nfs4_sequence_res *res) | ||
692 | { | 702 | { |
693 | struct nfs4_session *session; | 703 | struct nfs4_session *session; |
694 | struct nfs4_slot *slot = res->sr_slot; | 704 | struct nfs4_slot *slot = res->sr_slot; |
@@ -714,7 +724,7 @@ int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) | |||
714 | switch (res->sr_status) { | 724 | switch (res->sr_status) { |
715 | case 0: | 725 | case 0: |
716 | /* Update the slot's sequence and clientid lease timer */ | 726 | /* Update the slot's sequence and clientid lease timer */ |
717 | ++slot->seq_nr; | 727 | slot->seq_done = 1; |
718 | clp = session->clp; | 728 | clp = session->clp; |
719 | do_renew_lease(clp, res->sr_timestamp); | 729 | do_renew_lease(clp, res->sr_timestamp); |
720 | /* Check sequence flags */ | 730 | /* Check sequence flags */ |
@@ -769,16 +779,16 @@ int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) | |||
769 | goto retry_nowait; | 779 | goto retry_nowait; |
770 | default: | 780 | default: |
771 | /* Just update the slot sequence no. */ | 781 | /* Just update the slot sequence no. */ |
772 | ++slot->seq_nr; | 782 | slot->seq_done = 1; |
773 | } | 783 | } |
774 | out: | 784 | out: |
775 | /* The session may be reset by one of the error handlers. */ | 785 | /* The session may be reset by one of the error handlers. */ |
776 | dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); | 786 | dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); |
777 | nfs41_sequence_free_slot(res); | ||
778 | out_noaction: | 787 | out_noaction: |
779 | return ret; | 788 | return ret; |
780 | retry_nowait: | 789 | retry_nowait: |
781 | if (rpc_restart_call_prepare(task)) { | 790 | if (rpc_restart_call_prepare(task)) { |
791 | nfs41_sequence_free_slot(res); | ||
782 | task->tk_status = 0; | 792 | task->tk_status = 0; |
783 | ret = 0; | 793 | ret = 0; |
784 | } | 794 | } |
@@ -789,8 +799,37 @@ out_retry: | |||
789 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 799 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
790 | return 0; | 800 | return 0; |
791 | } | 801 | } |
802 | |||
803 | int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) | ||
804 | { | ||
805 | if (!nfs41_sequence_process(task, res)) | ||
806 | return 0; | ||
807 | if (res->sr_slot != NULL) | ||
808 | nfs41_sequence_free_slot(res); | ||
809 | return 1; | ||
810 | |||
811 | } | ||
792 | EXPORT_SYMBOL_GPL(nfs41_sequence_done); | 812 | EXPORT_SYMBOL_GPL(nfs41_sequence_done); |
793 | 813 | ||
814 | static int nfs4_sequence_process(struct rpc_task *task, struct nfs4_sequence_res *res) | ||
815 | { | ||
816 | if (res->sr_slot == NULL) | ||
817 | return 1; | ||
818 | if (res->sr_slot->table->session != NULL) | ||
819 | return nfs41_sequence_process(task, res); | ||
820 | return nfs40_sequence_done(task, res); | ||
821 | } | ||
822 | |||
823 | static void nfs4_sequence_free_slot(struct nfs4_sequence_res *res) | ||
824 | { | ||
825 | if (res->sr_slot != NULL) { | ||
826 | if (res->sr_slot->table->session != NULL) | ||
827 | nfs41_sequence_free_slot(res); | ||
828 | else | ||
829 | nfs40_sequence_free_slot(res); | ||
830 | } | ||
831 | } | ||
832 | |||
794 | int nfs4_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) | 833 | int nfs4_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) |
795 | { | 834 | { |
796 | if (res->sr_slot == NULL) | 835 | if (res->sr_slot == NULL) |
@@ -920,6 +959,17 @@ static int nfs4_setup_sequence(const struct nfs_server *server, | |||
920 | args, res, task); | 959 | args, res, task); |
921 | } | 960 | } |
922 | 961 | ||
962 | static int nfs4_sequence_process(struct rpc_task *task, struct nfs4_sequence_res *res) | ||
963 | { | ||
964 | return nfs40_sequence_done(task, res); | ||
965 | } | ||
966 | |||
967 | static void nfs4_sequence_free_slot(struct nfs4_sequence_res *res) | ||
968 | { | ||
969 | if (res->sr_slot != NULL) | ||
970 | nfs40_sequence_free_slot(res); | ||
971 | } | ||
972 | |||
923 | int nfs4_sequence_done(struct rpc_task *task, | 973 | int nfs4_sequence_done(struct rpc_task *task, |
924 | struct nfs4_sequence_res *res) | 974 | struct nfs4_sequence_res *res) |
925 | { | 975 | { |
@@ -1197,6 +1247,7 @@ static void nfs4_opendata_free(struct kref *kref) | |||
1197 | struct super_block *sb = p->dentry->d_sb; | 1247 | struct super_block *sb = p->dentry->d_sb; |
1198 | 1248 | ||
1199 | nfs_free_seqid(p->o_arg.seqid); | 1249 | nfs_free_seqid(p->o_arg.seqid); |
1250 | nfs4_sequence_free_slot(&p->o_res.seq_res); | ||
1200 | if (p->state != NULL) | 1251 | if (p->state != NULL) |
1201 | nfs4_put_open_state(p->state); | 1252 | nfs4_put_open_state(p->state); |
1202 | nfs4_put_state_owner(p->owner); | 1253 | nfs4_put_state_owner(p->owner); |
@@ -1656,9 +1707,14 @@ err: | |||
1656 | static struct nfs4_state * | 1707 | static struct nfs4_state * |
1657 | nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) | 1708 | nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) |
1658 | { | 1709 | { |
1710 | struct nfs4_state *ret; | ||
1711 | |||
1659 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) | 1712 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) |
1660 | return _nfs4_opendata_reclaim_to_nfs4_state(data); | 1713 | ret =_nfs4_opendata_reclaim_to_nfs4_state(data); |
1661 | return _nfs4_opendata_to_nfs4_state(data); | 1714 | else |
1715 | ret = _nfs4_opendata_to_nfs4_state(data); | ||
1716 | nfs4_sequence_free_slot(&data->o_res.seq_res); | ||
1717 | return ret; | ||
1662 | } | 1718 | } |
1663 | 1719 | ||
1664 | static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state) | 1720 | static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state) |
@@ -2056,7 +2112,7 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |||
2056 | 2112 | ||
2057 | data->rpc_status = task->tk_status; | 2113 | data->rpc_status = task->tk_status; |
2058 | 2114 | ||
2059 | if (!nfs4_sequence_done(task, &data->o_res.seq_res)) | 2115 | if (!nfs4_sequence_process(task, &data->o_res.seq_res)) |
2060 | return; | 2116 | return; |
2061 | 2117 | ||
2062 | if (task->tk_status == 0) { | 2118 | if (task->tk_status == 0) { |
@@ -7864,7 +7920,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) | |||
7864 | struct nfs4_layoutget *lgp = calldata; | 7920 | struct nfs4_layoutget *lgp = calldata; |
7865 | 7921 | ||
7866 | dprintk("--> %s\n", __func__); | 7922 | dprintk("--> %s\n", __func__); |
7867 | nfs41_sequence_done(task, &lgp->res.seq_res); | 7923 | nfs41_sequence_process(task, &lgp->res.seq_res); |
7868 | dprintk("<-- %s\n", __func__); | 7924 | dprintk("<-- %s\n", __func__); |
7869 | } | 7925 | } |
7870 | 7926 | ||
@@ -8080,6 +8136,7 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout, gfp_t gfp_flags) | |||
8080 | /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */ | 8136 | /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */ |
8081 | if (status == 0 && lgp->res.layoutp->len) | 8137 | if (status == 0 && lgp->res.layoutp->len) |
8082 | lseg = pnfs_layout_process(lgp); | 8138 | lseg = pnfs_layout_process(lgp); |
8139 | nfs4_sequence_free_slot(&lgp->res.seq_res); | ||
8083 | rpc_put_task(task); | 8140 | rpc_put_task(task); |
8084 | dprintk("<-- %s status=%d\n", __func__, status); | 8141 | dprintk("<-- %s status=%d\n", __func__, status); |
8085 | if (status) | 8142 | if (status) |
@@ -8106,7 +8163,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) | |||
8106 | 8163 | ||
8107 | dprintk("--> %s\n", __func__); | 8164 | dprintk("--> %s\n", __func__); |
8108 | 8165 | ||
8109 | if (!nfs41_sequence_done(task, &lrp->res.seq_res)) | 8166 | if (!nfs41_sequence_process(task, &lrp->res.seq_res)) |
8110 | return; | 8167 | return; |
8111 | 8168 | ||
8112 | server = NFS_SERVER(lrp->args.inode); | 8169 | server = NFS_SERVER(lrp->args.inode); |
@@ -8118,6 +8175,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) | |||
8118 | case -NFS4ERR_DELAY: | 8175 | case -NFS4ERR_DELAY: |
8119 | if (nfs4_async_handle_error(task, server, NULL, NULL) != -EAGAIN) | 8176 | if (nfs4_async_handle_error(task, server, NULL, NULL) != -EAGAIN) |
8120 | break; | 8177 | break; |
8178 | nfs4_sequence_free_slot(&lrp->res.seq_res); | ||
8121 | rpc_restart_call_prepare(task); | 8179 | rpc_restart_call_prepare(task); |
8122 | return; | 8180 | return; |
8123 | } | 8181 | } |
@@ -8138,6 +8196,7 @@ static void nfs4_layoutreturn_release(void *calldata) | |||
8138 | pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); | 8196 | pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); |
8139 | pnfs_clear_layoutreturn_waitbit(lo); | 8197 | pnfs_clear_layoutreturn_waitbit(lo); |
8140 | spin_unlock(&lo->plh_inode->i_lock); | 8198 | spin_unlock(&lo->plh_inode->i_lock); |
8199 | nfs4_sequence_free_slot(&lrp->res.seq_res); | ||
8141 | pnfs_free_lseg_list(&freeme); | 8200 | pnfs_free_lseg_list(&freeme); |
8142 | pnfs_put_layout_hdr(lrp->args.layout); | 8201 | pnfs_put_layout_hdr(lrp->args.layout); |
8143 | nfs_iput_and_deactive(lrp->inode); | 8202 | nfs_iput_and_deactive(lrp->inode); |
diff --git a/fs/nfs/nfs4session.c b/fs/nfs/nfs4session.c index 332d06e64fa9..b62973045a3e 100644 --- a/fs/nfs/nfs4session.c +++ b/fs/nfs/nfs4session.c | |||
@@ -28,6 +28,7 @@ static void nfs4_init_slot_table(struct nfs4_slot_table *tbl, const char *queue) | |||
28 | tbl->highest_used_slotid = NFS4_NO_SLOT; | 28 | tbl->highest_used_slotid = NFS4_NO_SLOT; |
29 | spin_lock_init(&tbl->slot_tbl_lock); | 29 | spin_lock_init(&tbl->slot_tbl_lock); |
30 | rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, queue); | 30 | rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, queue); |
31 | init_waitqueue_head(&tbl->slot_waitq); | ||
31 | init_completion(&tbl->complete); | 32 | init_completion(&tbl->complete); |
32 | } | 33 | } |
33 | 34 | ||
@@ -172,6 +173,58 @@ struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid) | |||
172 | return ERR_PTR(-E2BIG); | 173 | return ERR_PTR(-E2BIG); |
173 | } | 174 | } |
174 | 175 | ||
176 | static int nfs4_slot_get_seqid(struct nfs4_slot_table *tbl, u32 slotid, | ||
177 | u32 *seq_nr) | ||
178 | __must_hold(&tbl->slot_tbl_lock) | ||
179 | { | ||
180 | struct nfs4_slot *slot; | ||
181 | |||
182 | slot = nfs4_lookup_slot(tbl, slotid); | ||
183 | if (IS_ERR(slot)) | ||
184 | return PTR_ERR(slot); | ||
185 | *seq_nr = slot->seq_nr; | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * nfs4_slot_seqid_in_use - test if a slot sequence id is still in use | ||
191 | * | ||
192 | * Given a slot table, slot id and sequence number, determine if the | ||
193 | * RPC call in question is still in flight. This function is mainly | ||
194 | * intended for use by the callback channel. | ||
195 | */ | ||
196 | static bool nfs4_slot_seqid_in_use(struct nfs4_slot_table *tbl, | ||
197 | u32 slotid, u32 seq_nr) | ||
198 | { | ||
199 | u32 cur_seq; | ||
200 | bool ret = false; | ||
201 | |||
202 | spin_lock(&tbl->slot_tbl_lock); | ||
203 | if (nfs4_slot_get_seqid(tbl, slotid, &cur_seq) == 0 && | ||
204 | cur_seq == seq_nr && test_bit(slotid, tbl->used_slots)) | ||
205 | ret = true; | ||
206 | spin_unlock(&tbl->slot_tbl_lock); | ||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * nfs4_slot_wait_on_seqid - wait until a slot sequence id is complete | ||
212 | * | ||
213 | * Given a slot table, slot id and sequence number, wait until the | ||
214 | * corresponding RPC call completes. This function is mainly | ||
215 | * intended for use by the callback channel. | ||
216 | */ | ||
217 | int nfs4_slot_wait_on_seqid(struct nfs4_slot_table *tbl, | ||
218 | u32 slotid, u32 seq_nr, | ||
219 | unsigned long timeout) | ||
220 | { | ||
221 | if (wait_event_timeout(tbl->slot_waitq, | ||
222 | !nfs4_slot_seqid_in_use(tbl, slotid, seq_nr), | ||
223 | timeout) == 0) | ||
224 | return -ETIMEDOUT; | ||
225 | return 0; | ||
226 | } | ||
227 | |||
175 | /* | 228 | /* |
176 | * nfs4_alloc_slot - efficiently look for a free slot | 229 | * nfs4_alloc_slot - efficiently look for a free slot |
177 | * | 230 | * |
diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h index 5b51298d1d03..f703b755351b 100644 --- a/fs/nfs/nfs4session.h +++ b/fs/nfs/nfs4session.h | |||
@@ -21,7 +21,8 @@ struct nfs4_slot { | |||
21 | unsigned long generation; | 21 | unsigned long generation; |
22 | u32 slot_nr; | 22 | u32 slot_nr; |
23 | u32 seq_nr; | 23 | u32 seq_nr; |
24 | unsigned int interrupted : 1; | 24 | unsigned int interrupted : 1, |
25 | seq_done : 1; | ||
25 | }; | 26 | }; |
26 | 27 | ||
27 | /* Sessions */ | 28 | /* Sessions */ |
@@ -36,6 +37,7 @@ struct nfs4_slot_table { | |||
36 | unsigned long used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */ | 37 | unsigned long used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */ |
37 | spinlock_t slot_tbl_lock; | 38 | spinlock_t slot_tbl_lock; |
38 | struct rpc_wait_queue slot_tbl_waitq; /* allocators may wait here */ | 39 | struct rpc_wait_queue slot_tbl_waitq; /* allocators may wait here */ |
40 | wait_queue_head_t slot_waitq; /* Completion wait on slot */ | ||
39 | u32 max_slots; /* # slots in table */ | 41 | u32 max_slots; /* # slots in table */ |
40 | u32 max_slotid; /* Max allowed slotid value */ | 42 | u32 max_slotid; /* Max allowed slotid value */ |
41 | u32 highest_used_slotid; /* sent to server on each SEQ. | 43 | u32 highest_used_slotid; /* sent to server on each SEQ. |
@@ -78,6 +80,9 @@ extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl, | |||
78 | extern void nfs4_shutdown_slot_table(struct nfs4_slot_table *tbl); | 80 | extern void nfs4_shutdown_slot_table(struct nfs4_slot_table *tbl); |
79 | extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl); | 81 | extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl); |
80 | extern struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid); | 82 | extern struct nfs4_slot *nfs4_lookup_slot(struct nfs4_slot_table *tbl, u32 slotid); |
83 | extern int nfs4_slot_wait_on_seqid(struct nfs4_slot_table *tbl, | ||
84 | u32 slotid, u32 seq_nr, | ||
85 | unsigned long timeout); | ||
81 | extern bool nfs4_try_to_lock_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); | 86 | extern bool nfs4_try_to_lock_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); |
82 | extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); | 87 | extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot); |
83 | extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl); | 88 | extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl); |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 70806cae0d36..6daf034645c8 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -1555,6 +1555,7 @@ pnfs_update_layout(struct inode *ino, | |||
1555 | } | 1555 | } |
1556 | 1556 | ||
1557 | lookup_again: | 1557 | lookup_again: |
1558 | nfs4_client_recover_expired_lease(clp); | ||
1558 | first = false; | 1559 | first = false; |
1559 | spin_lock(&ino->i_lock); | 1560 | spin_lock(&ino->i_lock); |
1560 | lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags); | 1561 | lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags); |
@@ -2510,7 +2511,6 @@ pnfs_report_layoutstat(struct inode *inode, gfp_t gfp_flags) | |||
2510 | 2511 | ||
2511 | data->args.fh = NFS_FH(inode); | 2512 | data->args.fh = NFS_FH(inode); |
2512 | data->args.inode = inode; | 2513 | data->args.inode = inode; |
2513 | nfs4_stateid_copy(&data->args.stateid, &hdr->plh_stateid); | ||
2514 | status = ld->prepare_layoutstats(&data->args); | 2514 | status = ld->prepare_layoutstats(&data->args); |
2515 | if (status) | 2515 | if (status) |
2516 | goto out_free; | 2516 | goto out_free; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 18d446e1a82b..d39601381adf 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -923,6 +923,8 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void) | |||
923 | 923 | ||
924 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 924 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
925 | if (data) { | 925 | if (data) { |
926 | data->timeo = NFS_UNSPEC_TIMEO; | ||
927 | data->retrans = NFS_UNSPEC_RETRANS; | ||
926 | data->acregmin = NFS_DEF_ACREGMIN; | 928 | data->acregmin = NFS_DEF_ACREGMIN; |
927 | data->acregmax = NFS_DEF_ACREGMAX; | 929 | data->acregmax = NFS_DEF_ACREGMAX; |
928 | data->acdirmin = NFS_DEF_ACDIRMIN; | 930 | data->acdirmin = NFS_DEF_ACDIRMIN; |
@@ -1189,6 +1191,19 @@ static int nfs_get_option_ul(substring_t args[], unsigned long *option) | |||
1189 | return rc; | 1191 | return rc; |
1190 | } | 1192 | } |
1191 | 1193 | ||
1194 | static int nfs_get_option_ul_bound(substring_t args[], unsigned long *option, | ||
1195 | unsigned long l_bound, unsigned long u_bound) | ||
1196 | { | ||
1197 | int ret; | ||
1198 | |||
1199 | ret = nfs_get_option_ul(args, option); | ||
1200 | if (ret != 0) | ||
1201 | return ret; | ||
1202 | if (*option < l_bound || *option > u_bound) | ||
1203 | return -ERANGE; | ||
1204 | return 0; | ||
1205 | } | ||
1206 | |||
1192 | /* | 1207 | /* |
1193 | * Error-check and convert a string of mount options from user space into | 1208 | * Error-check and convert a string of mount options from user space into |
1194 | * a data structure. The whole mount string is processed; bad options are | 1209 | * a data structure. The whole mount string is processed; bad options are |
@@ -1352,12 +1367,12 @@ static int nfs_parse_mount_options(char *raw, | |||
1352 | mnt->bsize = option; | 1367 | mnt->bsize = option; |
1353 | break; | 1368 | break; |
1354 | case Opt_timeo: | 1369 | case Opt_timeo: |
1355 | if (nfs_get_option_ul(args, &option) || option == 0) | 1370 | if (nfs_get_option_ul_bound(args, &option, 1, INT_MAX)) |
1356 | goto out_invalid_value; | 1371 | goto out_invalid_value; |
1357 | mnt->timeo = option; | 1372 | mnt->timeo = option; |
1358 | break; | 1373 | break; |
1359 | case Opt_retrans: | 1374 | case Opt_retrans: |
1360 | if (nfs_get_option_ul(args, &option) || option == 0) | 1375 | if (nfs_get_option_ul_bound(args, &option, 0, INT_MAX)) |
1361 | goto out_invalid_value; | 1376 | goto out_invalid_value; |
1362 | mnt->retrans = option; | 1377 | mnt->retrans = option; |
1363 | break; | 1378 | break; |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 7f79fb7dc6a0..66f23b376fa0 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -453,7 +453,7 @@ static struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args, | |||
453 | struct rpc_xprt_switch *xps; | 453 | struct rpc_xprt_switch *xps; |
454 | 454 | ||
455 | if (args->bc_xprt && args->bc_xprt->xpt_bc_xps) { | 455 | if (args->bc_xprt && args->bc_xprt->xpt_bc_xps) { |
456 | WARN_ON(args->protocol != XPRT_TRANSPORT_BC_TCP); | 456 | WARN_ON_ONCE(!(args->protocol & XPRT_TRANSPORT_BC)); |
457 | xps = args->bc_xprt->xpt_bc_xps; | 457 | xps = args->bc_xprt->xpt_bc_xps; |
458 | xprt_switch_get(xps); | 458 | xprt_switch_get(xps); |
459 | } else { | 459 | } else { |
@@ -520,7 +520,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) | |||
520 | char servername[48]; | 520 | char servername[48]; |
521 | 521 | ||
522 | if (args->bc_xprt) { | 522 | if (args->bc_xprt) { |
523 | WARN_ON(args->protocol != XPRT_TRANSPORT_BC_TCP); | 523 | WARN_ON_ONCE(!(args->protocol & XPRT_TRANSPORT_BC)); |
524 | xprt = args->bc_xprt->xpt_bc_xprt; | 524 | xprt = args->bc_xprt->xpt_bc_xprt; |
525 | if (xprt) { | 525 | if (xprt) { |
526 | xprt_get(xprt); | 526 | xprt_get(xprt); |