| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Module for pnfs flexfile layout driver. |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 7 | 8 | */ |
|---|
| 8 | 9 | |
|---|
| 9 | 10 | #include <linux/nfs_fs.h> |
|---|
| 11 | +#include <linux/nfs_mount.h> |
|---|
| 10 | 12 | #include <linux/nfs_page.h> |
|---|
| 11 | 13 | #include <linux/module.h> |
|---|
| 14 | +#include <linux/sched/mm.h> |
|---|
| 12 | 15 | |
|---|
| 13 | 16 | #include <linux/sunrpc/metrics.h> |
|---|
| 14 | 17 | |
|---|
| .. | .. |
|---|
| 27 | 30 | #define FF_LAYOUT_POLL_RETRY_MAX (15*HZ) |
|---|
| 28 | 31 | #define FF_LAYOUTRETURN_MAXERR 20 |
|---|
| 29 | 32 | |
|---|
| 33 | +static unsigned short io_maxretrans; |
|---|
| 30 | 34 | |
|---|
| 31 | | -static struct group_info *ff_zero_group; |
|---|
| 32 | | - |
|---|
| 35 | +static const struct pnfs_commit_ops ff_layout_commit_ops; |
|---|
| 33 | 36 | static void ff_layout_read_record_layoutstats_done(struct rpc_task *task, |
|---|
| 34 | 37 | struct nfs_pgio_header *hdr); |
|---|
| 35 | 38 | static int ff_layout_mirror_prepare_stats(struct pnfs_layout_hdr *lo, |
|---|
| .. | .. |
|---|
| 46 | 49 | |
|---|
| 47 | 50 | ffl = kzalloc(sizeof(*ffl), gfp_flags); |
|---|
| 48 | 51 | if (ffl) { |
|---|
| 52 | + pnfs_init_ds_commit_info(&ffl->commit_info); |
|---|
| 49 | 53 | INIT_LIST_HEAD(&ffl->error_list); |
|---|
| 50 | 54 | INIT_LIST_HEAD(&ffl->mirrors); |
|---|
| 51 | 55 | ffl->last_report_time = ktime_get(); |
|---|
| 56 | + ffl->commit_info.ops = &ff_layout_commit_ops; |
|---|
| 52 | 57 | return &ffl->generic_hdr; |
|---|
| 53 | 58 | } else |
|---|
| 54 | 59 | return NULL; |
|---|
| .. | .. |
|---|
| 57 | 62 | static void |
|---|
| 58 | 63 | ff_layout_free_layout_hdr(struct pnfs_layout_hdr *lo) |
|---|
| 59 | 64 | { |
|---|
| 65 | + struct nfs4_flexfile_layout *ffl = FF_LAYOUT_FROM_HDR(lo); |
|---|
| 60 | 66 | struct nfs4_ff_layout_ds_err *err, *n; |
|---|
| 61 | 67 | |
|---|
| 62 | | - list_for_each_entry_safe(err, n, &FF_LAYOUT_FROM_HDR(lo)->error_list, |
|---|
| 63 | | - list) { |
|---|
| 68 | + list_for_each_entry_safe(err, n, &ffl->error_list, list) { |
|---|
| 64 | 69 | list_del(&err->list); |
|---|
| 65 | 70 | kfree(err); |
|---|
| 66 | 71 | } |
|---|
| 67 | | - kfree(FF_LAYOUT_FROM_HDR(lo)); |
|---|
| 72 | + kfree_rcu(ffl, generic_hdr.plh_rcu); |
|---|
| 68 | 73 | } |
|---|
| 69 | 74 | |
|---|
| 70 | 75 | static int decode_pnfs_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) |
|---|
| .. | .. |
|---|
| 226 | 231 | |
|---|
| 227 | 232 | static void ff_layout_free_mirror(struct nfs4_ff_layout_mirror *mirror) |
|---|
| 228 | 233 | { |
|---|
| 229 | | - struct rpc_cred *cred; |
|---|
| 234 | + const struct cred *cred; |
|---|
| 230 | 235 | |
|---|
| 231 | 236 | ff_layout_remove_mirror(mirror); |
|---|
| 232 | 237 | kfree(mirror->fh_versions); |
|---|
| 233 | 238 | cred = rcu_access_pointer(mirror->ro_cred); |
|---|
| 234 | | - if (cred) |
|---|
| 235 | | - put_rpccred(cred); |
|---|
| 239 | + put_cred(cred); |
|---|
| 236 | 240 | cred = rcu_access_pointer(mirror->rw_cred); |
|---|
| 237 | | - if (cred) |
|---|
| 238 | | - put_rpccred(cred); |
|---|
| 241 | + put_cred(cred); |
|---|
| 239 | 242 | nfs4_ff_layout_put_deviceid(mirror->mirror_ds); |
|---|
| 240 | 243 | kfree(mirror); |
|---|
| 241 | 244 | } |
|---|
| .. | .. |
|---|
| 248 | 251 | |
|---|
| 249 | 252 | static void ff_layout_free_mirror_array(struct nfs4_ff_layout_segment *fls) |
|---|
| 250 | 253 | { |
|---|
| 251 | | - int i; |
|---|
| 254 | + u32 i; |
|---|
| 252 | 255 | |
|---|
| 253 | | - if (fls->mirror_array) { |
|---|
| 254 | | - for (i = 0; i < fls->mirror_array_cnt; i++) { |
|---|
| 255 | | - /* normally mirror_ds is freed in |
|---|
| 256 | | - * .free_deviceid_node but we still do it here |
|---|
| 257 | | - * for .alloc_lseg error path */ |
|---|
| 258 | | - ff_layout_put_mirror(fls->mirror_array[i]); |
|---|
| 259 | | - } |
|---|
| 260 | | - kfree(fls->mirror_array); |
|---|
| 261 | | - fls->mirror_array = NULL; |
|---|
| 262 | | - } |
|---|
| 263 | | -} |
|---|
| 264 | | - |
|---|
| 265 | | -static int ff_layout_check_layout(struct nfs4_layoutget_res *lgr) |
|---|
| 266 | | -{ |
|---|
| 267 | | - int ret = 0; |
|---|
| 268 | | - |
|---|
| 269 | | - dprintk("--> %s\n", __func__); |
|---|
| 270 | | - |
|---|
| 271 | | - /* FIXME: remove this check when layout segment support is added */ |
|---|
| 272 | | - if (lgr->range.offset != 0 || |
|---|
| 273 | | - lgr->range.length != NFS4_MAX_UINT64) { |
|---|
| 274 | | - dprintk("%s Only whole file layouts supported. Use MDS i/o\n", |
|---|
| 275 | | - __func__); |
|---|
| 276 | | - ret = -EINVAL; |
|---|
| 277 | | - } |
|---|
| 278 | | - |
|---|
| 279 | | - dprintk("--> %s returns %d\n", __func__, ret); |
|---|
| 280 | | - return ret; |
|---|
| 256 | + for (i = 0; i < fls->mirror_array_cnt; i++) |
|---|
| 257 | + ff_layout_put_mirror(fls->mirror_array[i]); |
|---|
| 281 | 258 | } |
|---|
| 282 | 259 | |
|---|
| 283 | 260 | static void _ff_layout_free_lseg(struct nfs4_ff_layout_segment *fls) |
|---|
| .. | .. |
|---|
| 286 | 263 | ff_layout_free_mirror_array(fls); |
|---|
| 287 | 264 | kfree(fls); |
|---|
| 288 | 265 | } |
|---|
| 266 | +} |
|---|
| 267 | + |
|---|
| 268 | +static bool |
|---|
| 269 | +ff_lseg_match_mirrors(struct pnfs_layout_segment *l1, |
|---|
| 270 | + struct pnfs_layout_segment *l2) |
|---|
| 271 | +{ |
|---|
| 272 | + const struct nfs4_ff_layout_segment *fl1 = FF_LAYOUT_LSEG(l1); |
|---|
| 273 | + const struct nfs4_ff_layout_segment *fl2 = FF_LAYOUT_LSEG(l1); |
|---|
| 274 | + u32 i; |
|---|
| 275 | + |
|---|
| 276 | + if (fl1->mirror_array_cnt != fl2->mirror_array_cnt) |
|---|
| 277 | + return false; |
|---|
| 278 | + for (i = 0; i < fl1->mirror_array_cnt; i++) { |
|---|
| 279 | + if (fl1->mirror_array[i] != fl2->mirror_array[i]) |
|---|
| 280 | + return false; |
|---|
| 281 | + } |
|---|
| 282 | + return true; |
|---|
| 289 | 283 | } |
|---|
| 290 | 284 | |
|---|
| 291 | 285 | static bool |
|---|
| .. | .. |
|---|
| 322 | 316 | new_end = pnfs_calc_offset_end(new->pls_range.offset, |
|---|
| 323 | 317 | new->pls_range.length); |
|---|
| 324 | 318 | if (new_end < old->pls_range.offset) |
|---|
| 319 | + return false; |
|---|
| 320 | + if (!ff_lseg_match_mirrors(new, old)) |
|---|
| 325 | 321 | return false; |
|---|
| 326 | 322 | |
|---|
| 327 | 323 | /* Mergeable: copy info from 'old' to 'new' */ |
|---|
| .. | .. |
|---|
| 400 | 396 | goto out_err_free; |
|---|
| 401 | 397 | |
|---|
| 402 | 398 | rc = -ENOMEM; |
|---|
| 403 | | - fls = kzalloc(sizeof(*fls), gfp_flags); |
|---|
| 399 | + fls = kzalloc(struct_size(fls, mirror_array, mirror_array_cnt), |
|---|
| 400 | + gfp_flags); |
|---|
| 404 | 401 | if (!fls) |
|---|
| 405 | 402 | goto out_err_free; |
|---|
| 406 | 403 | |
|---|
| 407 | 404 | fls->mirror_array_cnt = mirror_array_cnt; |
|---|
| 408 | 405 | fls->stripe_unit = stripe_unit; |
|---|
| 409 | | - fls->mirror_array = kcalloc(fls->mirror_array_cnt, |
|---|
| 410 | | - sizeof(fls->mirror_array[0]), gfp_flags); |
|---|
| 411 | | - if (fls->mirror_array == NULL) |
|---|
| 412 | | - goto out_err_free; |
|---|
| 413 | 406 | |
|---|
| 414 | 407 | for (i = 0; i < fls->mirror_array_cnt; i++) { |
|---|
| 415 | 408 | struct nfs4_ff_layout_mirror *mirror; |
|---|
| 416 | | - struct auth_cred acred = { .group_info = ff_zero_group }; |
|---|
| 417 | | - struct rpc_cred __rcu *cred; |
|---|
| 409 | + struct cred *kcred; |
|---|
| 410 | + const struct cred __rcu *cred; |
|---|
| 411 | + kuid_t uid; |
|---|
| 412 | + kgid_t gid; |
|---|
| 418 | 413 | u32 ds_count, fh_count, id; |
|---|
| 419 | 414 | int j; |
|---|
| 420 | 415 | |
|---|
| .. | .. |
|---|
| 482 | 477 | if (rc) |
|---|
| 483 | 478 | goto out_err_free; |
|---|
| 484 | 479 | |
|---|
| 485 | | - acred.uid = make_kuid(&init_user_ns, id); |
|---|
| 480 | + uid = make_kuid(&init_user_ns, id); |
|---|
| 486 | 481 | |
|---|
| 487 | 482 | /* group */ |
|---|
| 488 | 483 | rc = decode_name(&stream, &id); |
|---|
| 489 | 484 | if (rc) |
|---|
| 490 | 485 | goto out_err_free; |
|---|
| 491 | 486 | |
|---|
| 492 | | - acred.gid = make_kgid(&init_user_ns, id); |
|---|
| 487 | + gid = make_kgid(&init_user_ns, id); |
|---|
| 493 | 488 | |
|---|
| 494 | | - /* find the cred for it */ |
|---|
| 495 | | - rcu_assign_pointer(cred, rpc_lookup_generic_cred(&acred, 0, gfp_flags)); |
|---|
| 496 | | - if (IS_ERR(cred)) { |
|---|
| 497 | | - rc = PTR_ERR(cred); |
|---|
| 498 | | - goto out_err_free; |
|---|
| 489 | + if (gfp_flags & __GFP_FS) |
|---|
| 490 | + kcred = prepare_kernel_cred(NULL); |
|---|
| 491 | + else { |
|---|
| 492 | + unsigned int nofs_flags = memalloc_nofs_save(); |
|---|
| 493 | + kcred = prepare_kernel_cred(NULL); |
|---|
| 494 | + memalloc_nofs_restore(nofs_flags); |
|---|
| 499 | 495 | } |
|---|
| 496 | + rc = -ENOMEM; |
|---|
| 497 | + if (!kcred) |
|---|
| 498 | + goto out_err_free; |
|---|
| 499 | + kcred->fsuid = uid; |
|---|
| 500 | + kcred->fsgid = gid; |
|---|
| 501 | + cred = RCU_INITIALIZER(kcred); |
|---|
| 500 | 502 | |
|---|
| 501 | 503 | if (lgr->range.iomode == IOMODE_READ) |
|---|
| 502 | 504 | rcu_assign_pointer(fls->mirror_array[i]->ro_cred, cred); |
|---|
| .. | .. |
|---|
| 519 | 521 | |
|---|
| 520 | 522 | dprintk("%s: iomode %s uid %u gid %u\n", __func__, |
|---|
| 521 | 523 | lgr->range.iomode == IOMODE_READ ? "READ" : "RW", |
|---|
| 522 | | - from_kuid(&init_user_ns, acred.uid), |
|---|
| 523 | | - from_kgid(&init_user_ns, acred.gid)); |
|---|
| 524 | + from_kuid(&init_user_ns, uid), |
|---|
| 525 | + from_kgid(&init_user_ns, gid)); |
|---|
| 524 | 526 | } |
|---|
| 525 | 527 | |
|---|
| 526 | 528 | p = xdr_inline_decode(&stream, 4); |
|---|
| .. | .. |
|---|
| 536 | 538 | |
|---|
| 537 | 539 | out_sort_mirrors: |
|---|
| 538 | 540 | ff_layout_sort_mirrors(fls); |
|---|
| 539 | | - rc = ff_layout_check_layout(lgr); |
|---|
| 540 | | - if (rc) |
|---|
| 541 | | - goto out_err_free; |
|---|
| 542 | 541 | ret = &fls->generic_hdr; |
|---|
| 543 | 542 | dprintk("<-- %s (success)\n", __func__); |
|---|
| 544 | 543 | out_free_page: |
|---|
| .. | .. |
|---|
| 549 | 548 | ret = ERR_PTR(rc); |
|---|
| 550 | 549 | dprintk("<-- %s (%d)\n", __func__, rc); |
|---|
| 551 | 550 | goto out_free_page; |
|---|
| 552 | | -} |
|---|
| 553 | | - |
|---|
| 554 | | -static bool ff_layout_has_rw_segments(struct pnfs_layout_hdr *layout) |
|---|
| 555 | | -{ |
|---|
| 556 | | - struct pnfs_layout_segment *lseg; |
|---|
| 557 | | - |
|---|
| 558 | | - list_for_each_entry(lseg, &layout->plh_segs, pls_list) |
|---|
| 559 | | - if (lseg->pls_range.iomode == IOMODE_RW) |
|---|
| 560 | | - return true; |
|---|
| 561 | | - |
|---|
| 562 | | - return false; |
|---|
| 563 | 551 | } |
|---|
| 564 | 552 | |
|---|
| 565 | 553 | static void |
|---|
| .. | .. |
|---|
| 576 | 564 | ffl = FF_LAYOUT_FROM_HDR(lseg->pls_layout); |
|---|
| 577 | 565 | inode = ffl->generic_hdr.plh_inode; |
|---|
| 578 | 566 | spin_lock(&inode->i_lock); |
|---|
| 579 | | - if (!ff_layout_has_rw_segments(lseg->pls_layout)) { |
|---|
| 580 | | - ffl->commit_info.nbuckets = 0; |
|---|
| 581 | | - kfree(ffl->commit_info.buckets); |
|---|
| 582 | | - ffl->commit_info.buckets = NULL; |
|---|
| 583 | | - } |
|---|
| 567 | + pnfs_generic_ds_cinfo_release_lseg(&ffl->commit_info, lseg); |
|---|
| 584 | 568 | spin_unlock(&inode->i_lock); |
|---|
| 585 | 569 | } |
|---|
| 586 | 570 | _ff_layout_free_lseg(fls); |
|---|
| 587 | | -} |
|---|
| 588 | | - |
|---|
| 589 | | -/* Return 1 until we have multiple lsegs support */ |
|---|
| 590 | | -static int |
|---|
| 591 | | -ff_layout_get_lseg_count(struct nfs4_ff_layout_segment *fls) |
|---|
| 592 | | -{ |
|---|
| 593 | | - return 1; |
|---|
| 594 | 571 | } |
|---|
| 595 | 572 | |
|---|
| 596 | 573 | static void |
|---|
| .. | .. |
|---|
| 737 | 714 | spin_unlock(&mirror->lock); |
|---|
| 738 | 715 | } |
|---|
| 739 | 716 | |
|---|
| 740 | | -static int |
|---|
| 741 | | -ff_layout_alloc_commit_info(struct pnfs_layout_segment *lseg, |
|---|
| 742 | | - struct nfs_commit_info *cinfo, |
|---|
| 743 | | - gfp_t gfp_flags) |
|---|
| 717 | +static void |
|---|
| 718 | +ff_layout_mark_ds_unreachable(struct pnfs_layout_segment *lseg, u32 idx) |
|---|
| 719 | +{ |
|---|
| 720 | + struct nfs4_deviceid_node *devid = FF_LAYOUT_DEVID_NODE(lseg, idx); |
|---|
| 721 | + |
|---|
| 722 | + if (devid) |
|---|
| 723 | + nfs4_mark_deviceid_unavailable(devid); |
|---|
| 724 | +} |
|---|
| 725 | + |
|---|
| 726 | +static void |
|---|
| 727 | +ff_layout_mark_ds_reachable(struct pnfs_layout_segment *lseg, u32 idx) |
|---|
| 728 | +{ |
|---|
| 729 | + struct nfs4_deviceid_node *devid = FF_LAYOUT_DEVID_NODE(lseg, idx); |
|---|
| 730 | + |
|---|
| 731 | + if (devid) |
|---|
| 732 | + nfs4_mark_deviceid_available(devid); |
|---|
| 733 | +} |
|---|
| 734 | + |
|---|
| 735 | +static struct nfs4_pnfs_ds * |
|---|
| 736 | +ff_layout_choose_ds_for_read(struct pnfs_layout_segment *lseg, |
|---|
| 737 | + u32 start_idx, u32 *best_idx, |
|---|
| 738 | + bool check_device) |
|---|
| 744 | 739 | { |
|---|
| 745 | 740 | struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg); |
|---|
| 746 | | - struct pnfs_commit_bucket *buckets; |
|---|
| 747 | | - int size; |
|---|
| 741 | + struct nfs4_ff_layout_mirror *mirror; |
|---|
| 742 | + struct nfs4_pnfs_ds *ds; |
|---|
| 743 | + bool fail_return = false; |
|---|
| 744 | + u32 idx; |
|---|
| 748 | 745 | |
|---|
| 749 | | - if (cinfo->ds->nbuckets != 0) { |
|---|
| 750 | | - /* This assumes there is only one RW lseg per file. |
|---|
| 751 | | - * To support multiple lseg per file, we need to |
|---|
| 752 | | - * change struct pnfs_commit_bucket to allow dynamic |
|---|
| 753 | | - * increasing nbuckets. |
|---|
| 754 | | - */ |
|---|
| 755 | | - return 0; |
|---|
| 746 | + /* mirrors are initially sorted by efficiency */ |
|---|
| 747 | + for (idx = start_idx; idx < fls->mirror_array_cnt; idx++) { |
|---|
| 748 | + if (idx+1 == fls->mirror_array_cnt) |
|---|
| 749 | + fail_return = !check_device; |
|---|
| 750 | + |
|---|
| 751 | + mirror = FF_LAYOUT_COMP(lseg, idx); |
|---|
| 752 | + ds = nfs4_ff_layout_prepare_ds(lseg, mirror, fail_return); |
|---|
| 753 | + if (!ds) |
|---|
| 754 | + continue; |
|---|
| 755 | + |
|---|
| 756 | + if (check_device && |
|---|
| 757 | + nfs4_test_deviceid_unavailable(&mirror->mirror_ds->id_node)) |
|---|
| 758 | + continue; |
|---|
| 759 | + |
|---|
| 760 | + *best_idx = idx; |
|---|
| 761 | + return ds; |
|---|
| 756 | 762 | } |
|---|
| 757 | 763 | |
|---|
| 758 | | - size = ff_layout_get_lseg_count(fls) * FF_LAYOUT_MIRROR_COUNT(lseg); |
|---|
| 764 | + return NULL; |
|---|
| 765 | +} |
|---|
| 759 | 766 | |
|---|
| 760 | | - buckets = kcalloc(size, sizeof(struct pnfs_commit_bucket), |
|---|
| 761 | | - gfp_flags); |
|---|
| 762 | | - if (!buckets) |
|---|
| 763 | | - return -ENOMEM; |
|---|
| 764 | | - else { |
|---|
| 765 | | - int i; |
|---|
| 767 | +static struct nfs4_pnfs_ds * |
|---|
| 768 | +ff_layout_choose_any_ds_for_read(struct pnfs_layout_segment *lseg, |
|---|
| 769 | + u32 start_idx, u32 *best_idx) |
|---|
| 770 | +{ |
|---|
| 771 | + return ff_layout_choose_ds_for_read(lseg, start_idx, best_idx, false); |
|---|
| 772 | +} |
|---|
| 766 | 773 | |
|---|
| 767 | | - spin_lock(&cinfo->inode->i_lock); |
|---|
| 768 | | - if (cinfo->ds->nbuckets != 0) |
|---|
| 769 | | - kfree(buckets); |
|---|
| 770 | | - else { |
|---|
| 771 | | - cinfo->ds->buckets = buckets; |
|---|
| 772 | | - cinfo->ds->nbuckets = size; |
|---|
| 773 | | - for (i = 0; i < size; i++) { |
|---|
| 774 | | - INIT_LIST_HEAD(&buckets[i].written); |
|---|
| 775 | | - INIT_LIST_HEAD(&buckets[i].committing); |
|---|
| 776 | | - /* mark direct verifier as unset */ |
|---|
| 777 | | - buckets[i].direct_verf.committed = |
|---|
| 778 | | - NFS_INVALID_STABLE_HOW; |
|---|
| 779 | | - } |
|---|
| 780 | | - } |
|---|
| 781 | | - spin_unlock(&cinfo->inode->i_lock); |
|---|
| 782 | | - return 0; |
|---|
| 783 | | - } |
|---|
| 774 | +static struct nfs4_pnfs_ds * |
|---|
| 775 | +ff_layout_choose_valid_ds_for_read(struct pnfs_layout_segment *lseg, |
|---|
| 776 | + u32 start_idx, u32 *best_idx) |
|---|
| 777 | +{ |
|---|
| 778 | + return ff_layout_choose_ds_for_read(lseg, start_idx, best_idx, true); |
|---|
| 784 | 779 | } |
|---|
| 785 | 780 | |
|---|
| 786 | 781 | static struct nfs4_pnfs_ds * |
|---|
| 787 | 782 | ff_layout_choose_best_ds_for_read(struct pnfs_layout_segment *lseg, |
|---|
| 788 | | - int start_idx, |
|---|
| 789 | | - int *best_idx) |
|---|
| 783 | + u32 start_idx, u32 *best_idx) |
|---|
| 790 | 784 | { |
|---|
| 791 | | - struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg); |
|---|
| 792 | 785 | struct nfs4_pnfs_ds *ds; |
|---|
| 793 | | - bool fail_return = false; |
|---|
| 794 | | - int idx; |
|---|
| 795 | 786 | |
|---|
| 796 | | - /* mirrors are sorted by efficiency */ |
|---|
| 797 | | - for (idx = start_idx; idx < fls->mirror_array_cnt; idx++) { |
|---|
| 798 | | - if (idx+1 == fls->mirror_array_cnt) |
|---|
| 799 | | - fail_return = true; |
|---|
| 800 | | - ds = nfs4_ff_layout_prepare_ds(lseg, idx, fail_return); |
|---|
| 801 | | - if (ds) { |
|---|
| 802 | | - *best_idx = idx; |
|---|
| 803 | | - return ds; |
|---|
| 804 | | - } |
|---|
| 805 | | - } |
|---|
| 787 | + ds = ff_layout_choose_valid_ds_for_read(lseg, start_idx, best_idx); |
|---|
| 788 | + if (ds) |
|---|
| 789 | + return ds; |
|---|
| 790 | + return ff_layout_choose_any_ds_for_read(lseg, start_idx, best_idx); |
|---|
| 791 | +} |
|---|
| 806 | 792 | |
|---|
| 807 | | - return NULL; |
|---|
| 793 | +static struct nfs4_pnfs_ds * |
|---|
| 794 | +ff_layout_get_ds_for_read(struct nfs_pageio_descriptor *pgio, |
|---|
| 795 | + u32 *best_idx) |
|---|
| 796 | +{ |
|---|
| 797 | + struct pnfs_layout_segment *lseg = pgio->pg_lseg; |
|---|
| 798 | + struct nfs4_pnfs_ds *ds; |
|---|
| 799 | + |
|---|
| 800 | + ds = ff_layout_choose_best_ds_for_read(lseg, pgio->pg_mirror_idx, |
|---|
| 801 | + best_idx); |
|---|
| 802 | + if (ds || !pgio->pg_mirror_idx) |
|---|
| 803 | + return ds; |
|---|
| 804 | + return ff_layout_choose_best_ds_for_read(lseg, 0, best_idx); |
|---|
| 808 | 805 | } |
|---|
| 809 | 806 | |
|---|
| 810 | 807 | static void |
|---|
| .. | .. |
|---|
| 814 | 811 | { |
|---|
| 815 | 812 | pnfs_put_lseg(pgio->pg_lseg); |
|---|
| 816 | 813 | pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, |
|---|
| 817 | | - req->wb_context, |
|---|
| 818 | | - 0, |
|---|
| 819 | | - NFS4_MAX_UINT64, |
|---|
| 814 | + nfs_req_openctx(req), |
|---|
| 815 | + req_offset(req), |
|---|
| 816 | + req->wb_bytes, |
|---|
| 820 | 817 | IOMODE_READ, |
|---|
| 821 | 818 | strict_iomode, |
|---|
| 822 | 819 | GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 827 | 824 | } |
|---|
| 828 | 825 | |
|---|
| 829 | 826 | static void |
|---|
| 827 | +ff_layout_pg_check_layout(struct nfs_pageio_descriptor *pgio, |
|---|
| 828 | + struct nfs_page *req) |
|---|
| 829 | +{ |
|---|
| 830 | + pnfs_generic_pg_check_layout(pgio); |
|---|
| 831 | + pnfs_generic_pg_check_range(pgio, req); |
|---|
| 832 | +} |
|---|
| 833 | + |
|---|
| 834 | +static void |
|---|
| 830 | 835 | ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio, |
|---|
| 831 | 836 | struct nfs_page *req) |
|---|
| 832 | 837 | { |
|---|
| 833 | 838 | struct nfs_pgio_mirror *pgm; |
|---|
| 834 | 839 | struct nfs4_ff_layout_mirror *mirror; |
|---|
| 835 | 840 | struct nfs4_pnfs_ds *ds; |
|---|
| 836 | | - int ds_idx; |
|---|
| 841 | + u32 ds_idx; |
|---|
| 837 | 842 | |
|---|
| 838 | 843 | retry: |
|---|
| 839 | | - pnfs_generic_pg_check_layout(pgio); |
|---|
| 844 | + ff_layout_pg_check_layout(pgio, req); |
|---|
| 840 | 845 | /* Use full layout for now */ |
|---|
| 841 | 846 | if (!pgio->pg_lseg) { |
|---|
| 842 | 847 | ff_layout_pg_get_read(pgio, req, false); |
|---|
| .. | .. |
|---|
| 849 | 854 | goto out_nolseg; |
|---|
| 850 | 855 | } |
|---|
| 851 | 856 | |
|---|
| 852 | | - ds = ff_layout_choose_best_ds_for_read(pgio->pg_lseg, 0, &ds_idx); |
|---|
| 857 | + ds = ff_layout_get_ds_for_read(pgio, &ds_idx); |
|---|
| 853 | 858 | if (!ds) { |
|---|
| 854 | 859 | if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg)) |
|---|
| 855 | 860 | goto out_mds; |
|---|
| 856 | | - pnfs_put_lseg(pgio->pg_lseg); |
|---|
| 857 | | - pgio->pg_lseg = NULL; |
|---|
| 861 | + pnfs_generic_pg_cleanup(pgio); |
|---|
| 858 | 862 | /* Sleep for 1 second before retrying */ |
|---|
| 859 | 863 | ssleep(1); |
|---|
| 860 | 864 | goto retry; |
|---|
| 861 | 865 | } |
|---|
| 862 | 866 | |
|---|
| 863 | 867 | mirror = FF_LAYOUT_COMP(pgio->pg_lseg, ds_idx); |
|---|
| 864 | | - |
|---|
| 865 | | - pgio->pg_mirror_idx = ds_idx; |
|---|
| 866 | | - |
|---|
| 867 | | - /* read always uses only one mirror - idx 0 for pgio layer */ |
|---|
| 868 | 868 | pgm = &pgio->pg_mirrors[0]; |
|---|
| 869 | 869 | pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].rsize; |
|---|
| 870 | 870 | |
|---|
| 871 | + pgio->pg_mirror_idx = ds_idx; |
|---|
| 872 | + |
|---|
| 873 | + if (NFS_SERVER(pgio->pg_inode)->flags & |
|---|
| 874 | + (NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR)) |
|---|
| 875 | + pgio->pg_maxretrans = io_maxretrans; |
|---|
| 871 | 876 | return; |
|---|
| 872 | 877 | out_nolseg: |
|---|
| 873 | 878 | if (pgio->pg_error < 0) |
|---|
| 874 | 879 | return; |
|---|
| 875 | 880 | out_mds: |
|---|
| 876 | | - pnfs_put_lseg(pgio->pg_lseg); |
|---|
| 877 | | - pgio->pg_lseg = NULL; |
|---|
| 881 | + trace_pnfs_mds_fallback_pg_init_read(pgio->pg_inode, |
|---|
| 882 | + 0, NFS4_MAX_UINT64, IOMODE_READ, |
|---|
| 883 | + NFS_I(pgio->pg_inode)->layout, |
|---|
| 884 | + pgio->pg_lseg); |
|---|
| 885 | + pgio->pg_maxretrans = 0; |
|---|
| 878 | 886 | nfs_pageio_reset_read_mds(pgio); |
|---|
| 879 | 887 | } |
|---|
| 880 | 888 | |
|---|
| .. | .. |
|---|
| 884 | 892 | { |
|---|
| 885 | 893 | struct nfs4_ff_layout_mirror *mirror; |
|---|
| 886 | 894 | struct nfs_pgio_mirror *pgm; |
|---|
| 887 | | - struct nfs_commit_info cinfo; |
|---|
| 888 | 895 | struct nfs4_pnfs_ds *ds; |
|---|
| 889 | | - int i; |
|---|
| 890 | | - int status; |
|---|
| 896 | + u32 i; |
|---|
| 891 | 897 | |
|---|
| 892 | 898 | retry: |
|---|
| 893 | | - pnfs_generic_pg_check_layout(pgio); |
|---|
| 899 | + ff_layout_pg_check_layout(pgio, req); |
|---|
| 894 | 900 | if (!pgio->pg_lseg) { |
|---|
| 895 | 901 | pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, |
|---|
| 896 | | - req->wb_context, |
|---|
| 897 | | - 0, |
|---|
| 898 | | - NFS4_MAX_UINT64, |
|---|
| 902 | + nfs_req_openctx(req), |
|---|
| 903 | + req_offset(req), |
|---|
| 904 | + req->wb_bytes, |
|---|
| 899 | 905 | IOMODE_RW, |
|---|
| 900 | 906 | false, |
|---|
| 901 | 907 | GFP_NOFS); |
|---|
| .. | .. |
|---|
| 909 | 915 | if (pgio->pg_lseg == NULL) |
|---|
| 910 | 916 | goto out_mds; |
|---|
| 911 | 917 | |
|---|
| 912 | | - nfs_init_cinfo(&cinfo, pgio->pg_inode, pgio->pg_dreq); |
|---|
| 913 | | - status = ff_layout_alloc_commit_info(pgio->pg_lseg, &cinfo, GFP_NOFS); |
|---|
| 914 | | - if (status < 0) |
|---|
| 915 | | - goto out_mds; |
|---|
| 916 | | - |
|---|
| 917 | 918 | /* Use a direct mapping of ds_idx to pgio mirror_idx */ |
|---|
| 918 | 919 | if (pgio->pg_mirror_count != FF_LAYOUT_MIRROR_COUNT(pgio->pg_lseg)) |
|---|
| 919 | 920 | goto out_eagain; |
|---|
| 920 | 921 | |
|---|
| 921 | 922 | for (i = 0; i < pgio->pg_mirror_count; i++) { |
|---|
| 922 | | - ds = nfs4_ff_layout_prepare_ds(pgio->pg_lseg, i, true); |
|---|
| 923 | + mirror = FF_LAYOUT_COMP(pgio->pg_lseg, i); |
|---|
| 924 | + ds = nfs4_ff_layout_prepare_ds(pgio->pg_lseg, mirror, true); |
|---|
| 923 | 925 | if (!ds) { |
|---|
| 924 | 926 | if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg)) |
|---|
| 925 | 927 | goto out_mds; |
|---|
| 926 | | - pnfs_put_lseg(pgio->pg_lseg); |
|---|
| 927 | | - pgio->pg_lseg = NULL; |
|---|
| 928 | + pnfs_generic_pg_cleanup(pgio); |
|---|
| 928 | 929 | /* Sleep for 1 second before retrying */ |
|---|
| 929 | 930 | ssleep(1); |
|---|
| 930 | 931 | goto retry; |
|---|
| 931 | 932 | } |
|---|
| 932 | 933 | pgm = &pgio->pg_mirrors[i]; |
|---|
| 933 | | - mirror = FF_LAYOUT_COMP(pgio->pg_lseg, i); |
|---|
| 934 | 934 | pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].wsize; |
|---|
| 935 | 935 | } |
|---|
| 936 | 936 | |
|---|
| 937 | + if (NFS_SERVER(pgio->pg_inode)->flags & |
|---|
| 938 | + (NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR)) |
|---|
| 939 | + pgio->pg_maxretrans = io_maxretrans; |
|---|
| 937 | 940 | return; |
|---|
| 938 | 941 | out_eagain: |
|---|
| 939 | 942 | pnfs_generic_pg_cleanup(pgio); |
|---|
| 940 | 943 | pgio->pg_error = -EAGAIN; |
|---|
| 941 | 944 | return; |
|---|
| 942 | 945 | out_mds: |
|---|
| 943 | | - pnfs_put_lseg(pgio->pg_lseg); |
|---|
| 944 | | - pgio->pg_lseg = NULL; |
|---|
| 946 | + trace_pnfs_mds_fallback_pg_init_write(pgio->pg_inode, |
|---|
| 947 | + 0, NFS4_MAX_UINT64, IOMODE_RW, |
|---|
| 948 | + NFS_I(pgio->pg_inode)->layout, |
|---|
| 949 | + pgio->pg_lseg); |
|---|
| 950 | + pgio->pg_maxretrans = 0; |
|---|
| 945 | 951 | nfs_pageio_reset_write_mds(pgio); |
|---|
| 946 | 952 | pgio->pg_error = -EAGAIN; |
|---|
| 947 | 953 | } |
|---|
| .. | .. |
|---|
| 952 | 958 | { |
|---|
| 953 | 959 | if (!pgio->pg_lseg) { |
|---|
| 954 | 960 | pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, |
|---|
| 955 | | - req->wb_context, |
|---|
| 956 | | - 0, |
|---|
| 957 | | - NFS4_MAX_UINT64, |
|---|
| 961 | + nfs_req_openctx(req), |
|---|
| 962 | + req_offset(req), |
|---|
| 963 | + req->wb_bytes, |
|---|
| 958 | 964 | IOMODE_RW, |
|---|
| 959 | 965 | false, |
|---|
| 960 | 966 | GFP_NOFS); |
|---|
| .. | .. |
|---|
| 967 | 973 | if (pgio->pg_lseg) |
|---|
| 968 | 974 | return FF_LAYOUT_MIRROR_COUNT(pgio->pg_lseg); |
|---|
| 969 | 975 | |
|---|
| 976 | + trace_pnfs_mds_fallback_pg_get_mirror_count(pgio->pg_inode, |
|---|
| 977 | + 0, NFS4_MAX_UINT64, IOMODE_RW, |
|---|
| 978 | + NFS_I(pgio->pg_inode)->layout, |
|---|
| 979 | + pgio->pg_lseg); |
|---|
| 970 | 980 | /* no lseg means that pnfs is not in use, so no mirroring here */ |
|---|
| 971 | 981 | nfs_pageio_reset_write_mds(pgio); |
|---|
| 972 | 982 | out: |
|---|
| 973 | 983 | return 1; |
|---|
| 984 | +} |
|---|
| 985 | + |
|---|
| 986 | +static u32 |
|---|
| 987 | +ff_layout_pg_set_mirror_write(struct nfs_pageio_descriptor *desc, u32 idx) |
|---|
| 988 | +{ |
|---|
| 989 | + u32 old = desc->pg_mirror_idx; |
|---|
| 990 | + |
|---|
| 991 | + desc->pg_mirror_idx = idx; |
|---|
| 992 | + return old; |
|---|
| 993 | +} |
|---|
| 994 | + |
|---|
| 995 | +static struct nfs_pgio_mirror * |
|---|
| 996 | +ff_layout_pg_get_mirror_write(struct nfs_pageio_descriptor *desc, u32 idx) |
|---|
| 997 | +{ |
|---|
| 998 | + return &desc->pg_mirrors[idx]; |
|---|
| 974 | 999 | } |
|---|
| 975 | 1000 | |
|---|
| 976 | 1001 | static const struct nfs_pageio_ops ff_layout_pg_read_ops = { |
|---|
| .. | .. |
|---|
| 986 | 1011 | .pg_doio = pnfs_generic_pg_writepages, |
|---|
| 987 | 1012 | .pg_get_mirror_count = ff_layout_pg_get_mirror_count_write, |
|---|
| 988 | 1013 | .pg_cleanup = pnfs_generic_pg_cleanup, |
|---|
| 1014 | + .pg_get_mirror = ff_layout_pg_get_mirror_write, |
|---|
| 1015 | + .pg_set_mirror = ff_layout_pg_set_mirror_write, |
|---|
| 989 | 1016 | }; |
|---|
| 990 | 1017 | |
|---|
| 991 | 1018 | static void ff_layout_reset_write(struct nfs_pgio_header *hdr, bool retry_pnfs) |
|---|
| .. | .. |
|---|
| 1016 | 1043 | hdr->args.count, |
|---|
| 1017 | 1044 | (unsigned long long)hdr->args.offset); |
|---|
| 1018 | 1045 | |
|---|
| 1046 | + trace_pnfs_mds_fallback_write_done(hdr->inode, |
|---|
| 1047 | + hdr->args.offset, hdr->args.count, |
|---|
| 1048 | + IOMODE_RW, NFS_I(hdr->inode)->layout, |
|---|
| 1049 | + hdr->lseg); |
|---|
| 1019 | 1050 | task->tk_status = pnfs_write_done_resend_to_mds(hdr); |
|---|
| 1020 | 1051 | } |
|---|
| 1052 | +} |
|---|
| 1053 | + |
|---|
| 1054 | +static void ff_layout_resend_pnfs_read(struct nfs_pgio_header *hdr) |
|---|
| 1055 | +{ |
|---|
| 1056 | + u32 idx = hdr->pgio_mirror_idx + 1; |
|---|
| 1057 | + u32 new_idx = 0; |
|---|
| 1058 | + |
|---|
| 1059 | + if (ff_layout_choose_any_ds_for_read(hdr->lseg, idx, &new_idx)) |
|---|
| 1060 | + ff_layout_send_layouterror(hdr->lseg); |
|---|
| 1061 | + else |
|---|
| 1062 | + pnfs_error_mark_layout_for_return(hdr->inode, hdr->lseg); |
|---|
| 1063 | + pnfs_read_resend_pnfs(hdr, new_idx); |
|---|
| 1021 | 1064 | } |
|---|
| 1022 | 1065 | |
|---|
| 1023 | 1066 | static void ff_layout_reset_read(struct nfs_pgio_header *hdr) |
|---|
| .. | .. |
|---|
| 1025 | 1068 | struct rpc_task *task = &hdr->task; |
|---|
| 1026 | 1069 | |
|---|
| 1027 | 1070 | pnfs_layoutcommit_inode(hdr->inode, false); |
|---|
| 1071 | + pnfs_error_mark_layout_for_return(hdr->inode, hdr->lseg); |
|---|
| 1028 | 1072 | |
|---|
| 1029 | 1073 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { |
|---|
| 1030 | 1074 | dprintk("%s Reset task %5u for i/o through MDS " |
|---|
| .. | .. |
|---|
| 1035 | 1079 | hdr->args.count, |
|---|
| 1036 | 1080 | (unsigned long long)hdr->args.offset); |
|---|
| 1037 | 1081 | |
|---|
| 1082 | + trace_pnfs_mds_fallback_read_done(hdr->inode, |
|---|
| 1083 | + hdr->args.offset, hdr->args.count, |
|---|
| 1084 | + IOMODE_READ, NFS_I(hdr->inode)->layout, |
|---|
| 1085 | + hdr->lseg); |
|---|
| 1038 | 1086 | task->tk_status = pnfs_read_done_resend_to_mds(hdr); |
|---|
| 1039 | 1087 | } |
|---|
| 1040 | 1088 | } |
|---|
| .. | .. |
|---|
| 1043 | 1091 | struct nfs4_state *state, |
|---|
| 1044 | 1092 | struct nfs_client *clp, |
|---|
| 1045 | 1093 | struct pnfs_layout_segment *lseg, |
|---|
| 1046 | | - int idx) |
|---|
| 1094 | + u32 idx) |
|---|
| 1047 | 1095 | { |
|---|
| 1048 | 1096 | struct pnfs_layout_hdr *lo = lseg->pls_layout; |
|---|
| 1049 | 1097 | struct inode *inode = lo->plh_inode; |
|---|
| .. | .. |
|---|
| 1101 | 1149 | nfs4_delete_deviceid(devid->ld, devid->nfs_client, |
|---|
| 1102 | 1150 | &devid->deviceid); |
|---|
| 1103 | 1151 | rpc_wake_up(&tbl->slot_tbl_waitq); |
|---|
| 1104 | | - /* fall through */ |
|---|
| 1152 | + fallthrough; |
|---|
| 1105 | 1153 | default: |
|---|
| 1106 | 1154 | if (ff_layout_avoid_mds_available_ds(lseg)) |
|---|
| 1107 | 1155 | return -NFS4ERR_RESET_TO_PNFS; |
|---|
| .. | .. |
|---|
| 1117 | 1165 | /* Retry all errors through either pNFS or MDS except for -EJUKEBOX */ |
|---|
| 1118 | 1166 | static int ff_layout_async_handle_error_v3(struct rpc_task *task, |
|---|
| 1119 | 1167 | struct pnfs_layout_segment *lseg, |
|---|
| 1120 | | - int idx) |
|---|
| 1168 | + u32 idx) |
|---|
| 1121 | 1169 | { |
|---|
| 1122 | 1170 | struct nfs4_deviceid_node *devid = FF_LAYOUT_DEVID_NODE(lseg, idx); |
|---|
| 1123 | 1171 | |
|---|
| .. | .. |
|---|
| 1152 | 1200 | struct nfs4_state *state, |
|---|
| 1153 | 1201 | struct nfs_client *clp, |
|---|
| 1154 | 1202 | struct pnfs_layout_segment *lseg, |
|---|
| 1155 | | - int idx) |
|---|
| 1203 | + u32 idx) |
|---|
| 1156 | 1204 | { |
|---|
| 1157 | 1205 | int vers = clp->cl_nfs_mod->rpc_vers->number; |
|---|
| 1158 | 1206 | |
|---|
| 1159 | | - if (task->tk_status >= 0) |
|---|
| 1207 | + if (task->tk_status >= 0) { |
|---|
| 1208 | + ff_layout_mark_ds_reachable(lseg, idx); |
|---|
| 1160 | 1209 | return 0; |
|---|
| 1210 | + } |
|---|
| 1161 | 1211 | |
|---|
| 1162 | 1212 | /* Handle the case of an invalid layout segment */ |
|---|
| 1163 | 1213 | if (!pnfs_is_valid_lseg(lseg)) |
|---|
| .. | .. |
|---|
| 1177 | 1227 | } |
|---|
| 1178 | 1228 | |
|---|
| 1179 | 1229 | static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg, |
|---|
| 1180 | | - int idx, u64 offset, u64 length, |
|---|
| 1181 | | - u32 status, int opnum, int error) |
|---|
| 1230 | + u32 idx, u64 offset, u64 length, |
|---|
| 1231 | + u32 *op_status, int opnum, int error) |
|---|
| 1182 | 1232 | { |
|---|
| 1183 | 1233 | struct nfs4_ff_layout_mirror *mirror; |
|---|
| 1234 | + u32 status = *op_status; |
|---|
| 1184 | 1235 | int err; |
|---|
| 1185 | 1236 | |
|---|
| 1186 | 1237 | if (status == 0) { |
|---|
| .. | .. |
|---|
| 1189 | 1240 | case -EPFNOSUPPORT: |
|---|
| 1190 | 1241 | case -EPROTONOSUPPORT: |
|---|
| 1191 | 1242 | case -EOPNOTSUPP: |
|---|
| 1243 | + case -EINVAL: |
|---|
| 1192 | 1244 | case -ECONNREFUSED: |
|---|
| 1193 | 1245 | case -ECONNRESET: |
|---|
| 1194 | 1246 | case -EHOSTDOWN: |
|---|
| .. | .. |
|---|
| 1198 | 1250 | case -ENOBUFS: |
|---|
| 1199 | 1251 | case -EPIPE: |
|---|
| 1200 | 1252 | case -EPERM: |
|---|
| 1201 | | - status = NFS4ERR_NXIO; |
|---|
| 1253 | + *op_status = status = NFS4ERR_NXIO; |
|---|
| 1202 | 1254 | break; |
|---|
| 1203 | 1255 | case -EACCES: |
|---|
| 1204 | | - status = NFS4ERR_ACCESS; |
|---|
| 1256 | + *op_status = status = NFS4ERR_ACCESS; |
|---|
| 1205 | 1257 | break; |
|---|
| 1206 | 1258 | default: |
|---|
| 1207 | 1259 | return; |
|---|
| 1208 | 1260 | } |
|---|
| 1209 | 1261 | } |
|---|
| 1210 | 1262 | |
|---|
| 1211 | | - switch (status) { |
|---|
| 1212 | | - case NFS4ERR_DELAY: |
|---|
| 1213 | | - case NFS4ERR_GRACE: |
|---|
| 1214 | | - return; |
|---|
| 1215 | | - default: |
|---|
| 1216 | | - break; |
|---|
| 1217 | | - } |
|---|
| 1218 | | - |
|---|
| 1219 | 1263 | mirror = FF_LAYOUT_COMP(lseg, idx); |
|---|
| 1220 | 1264 | err = ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout), |
|---|
| 1221 | 1265 | mirror, offset, length, status, opnum, |
|---|
| 1222 | 1266 | GFP_NOIO); |
|---|
| 1223 | | - pnfs_error_mark_layout_for_return(lseg->pls_layout->plh_inode, lseg); |
|---|
| 1267 | + |
|---|
| 1268 | + switch (status) { |
|---|
| 1269 | + case NFS4ERR_DELAY: |
|---|
| 1270 | + case NFS4ERR_GRACE: |
|---|
| 1271 | + break; |
|---|
| 1272 | + case NFS4ERR_NXIO: |
|---|
| 1273 | + ff_layout_mark_ds_unreachable(lseg, idx); |
|---|
| 1274 | + /* |
|---|
| 1275 | + * Don't return the layout if this is a read and we still |
|---|
| 1276 | + * have layouts to try |
|---|
| 1277 | + */ |
|---|
| 1278 | + if (opnum == OP_READ) |
|---|
| 1279 | + break; |
|---|
| 1280 | + fallthrough; |
|---|
| 1281 | + default: |
|---|
| 1282 | + pnfs_error_mark_layout_for_return(lseg->pls_layout->plh_inode, |
|---|
| 1283 | + lseg); |
|---|
| 1284 | + } |
|---|
| 1285 | + |
|---|
| 1224 | 1286 | dprintk("%s: err %d op %d status %u\n", __func__, err, opnum, status); |
|---|
| 1225 | 1287 | } |
|---|
| 1226 | 1288 | |
|---|
| .. | .. |
|---|
| 1230 | 1292 | { |
|---|
| 1231 | 1293 | int err; |
|---|
| 1232 | 1294 | |
|---|
| 1233 | | - trace_nfs4_pnfs_read(hdr, task->tk_status); |
|---|
| 1234 | | - if (task->tk_status < 0) |
|---|
| 1295 | + if (task->tk_status < 0) { |
|---|
| 1235 | 1296 | ff_layout_io_track_ds_error(hdr->lseg, hdr->pgio_mirror_idx, |
|---|
| 1236 | 1297 | hdr->args.offset, hdr->args.count, |
|---|
| 1237 | | - hdr->res.op_status, OP_READ, |
|---|
| 1298 | + &hdr->res.op_status, OP_READ, |
|---|
| 1238 | 1299 | task->tk_status); |
|---|
| 1300 | + trace_ff_layout_read_error(hdr); |
|---|
| 1301 | + } |
|---|
| 1302 | + |
|---|
| 1239 | 1303 | err = ff_layout_async_handle_error(task, hdr->args.context->state, |
|---|
| 1240 | 1304 | hdr->ds_clp, hdr->lseg, |
|---|
| 1241 | 1305 | hdr->pgio_mirror_idx); |
|---|
| 1242 | 1306 | |
|---|
| 1307 | + trace_nfs4_pnfs_read(hdr, err); |
|---|
| 1243 | 1308 | clear_bit(NFS_IOHDR_RESEND_PNFS, &hdr->flags); |
|---|
| 1244 | 1309 | clear_bit(NFS_IOHDR_RESEND_MDS, &hdr->flags); |
|---|
| 1245 | 1310 | switch (err) { |
|---|
| 1246 | 1311 | case -NFS4ERR_RESET_TO_PNFS: |
|---|
| 1247 | | - if (ff_layout_choose_best_ds_for_read(hdr->lseg, |
|---|
| 1248 | | - hdr->pgio_mirror_idx + 1, |
|---|
| 1249 | | - &hdr->pgio_mirror_idx)) |
|---|
| 1250 | | - goto out_eagain; |
|---|
| 1251 | 1312 | set_bit(NFS_IOHDR_RESEND_PNFS, &hdr->flags); |
|---|
| 1252 | 1313 | return task->tk_status; |
|---|
| 1253 | 1314 | case -NFS4ERR_RESET_TO_MDS: |
|---|
| .. | .. |
|---|
| 1291 | 1352 | (unsigned long long) NFS_I(inode)->layout->plh_lwb); |
|---|
| 1292 | 1353 | } |
|---|
| 1293 | 1354 | |
|---|
| 1294 | | -static bool |
|---|
| 1295 | | -ff_layout_device_unavailable(struct pnfs_layout_segment *lseg, int idx) |
|---|
| 1296 | | -{ |
|---|
| 1297 | | - /* No mirroring for now */ |
|---|
| 1298 | | - struct nfs4_deviceid_node *node = FF_LAYOUT_DEVID_NODE(lseg, idx); |
|---|
| 1299 | | - |
|---|
| 1300 | | - return ff_layout_test_devid_unavailable(node); |
|---|
| 1301 | | -} |
|---|
| 1302 | | - |
|---|
| 1303 | 1355 | static void ff_layout_read_record_layoutstats_start(struct rpc_task *task, |
|---|
| 1304 | 1356 | struct nfs_pgio_header *hdr) |
|---|
| 1305 | 1357 | { |
|---|
| .. | .. |
|---|
| 1329 | 1381 | if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) { |
|---|
| 1330 | 1382 | rpc_exit(task, -EIO); |
|---|
| 1331 | 1383 | return -EIO; |
|---|
| 1332 | | - } |
|---|
| 1333 | | - if (ff_layout_device_unavailable(hdr->lseg, hdr->pgio_mirror_idx)) { |
|---|
| 1334 | | - rpc_exit(task, -EHOSTDOWN); |
|---|
| 1335 | | - return -EAGAIN; |
|---|
| 1336 | 1384 | } |
|---|
| 1337 | 1385 | |
|---|
| 1338 | 1386 | ff_layout_read_record_layoutstats_start(task, hdr); |
|---|
| .. | .. |
|---|
| 1398 | 1446 | |
|---|
| 1399 | 1447 | ff_layout_read_record_layoutstats_done(&hdr->task, hdr); |
|---|
| 1400 | 1448 | if (test_bit(NFS_IOHDR_RESEND_PNFS, &hdr->flags)) |
|---|
| 1401 | | - pnfs_read_resend_pnfs(hdr); |
|---|
| 1449 | + ff_layout_resend_pnfs_read(hdr); |
|---|
| 1402 | 1450 | else if (test_bit(NFS_IOHDR_RESEND_MDS, &hdr->flags)) |
|---|
| 1403 | 1451 | ff_layout_reset_read(hdr); |
|---|
| 1404 | 1452 | pnfs_generic_rw_release(data); |
|---|
| .. | .. |
|---|
| 1411 | 1459 | loff_t end_offs = 0; |
|---|
| 1412 | 1460 | int err; |
|---|
| 1413 | 1461 | |
|---|
| 1414 | | - trace_nfs4_pnfs_write(hdr, task->tk_status); |
|---|
| 1415 | | - if (task->tk_status < 0) |
|---|
| 1462 | + if (task->tk_status < 0) { |
|---|
| 1416 | 1463 | ff_layout_io_track_ds_error(hdr->lseg, hdr->pgio_mirror_idx, |
|---|
| 1417 | 1464 | hdr->args.offset, hdr->args.count, |
|---|
| 1418 | | - hdr->res.op_status, OP_WRITE, |
|---|
| 1465 | + &hdr->res.op_status, OP_WRITE, |
|---|
| 1419 | 1466 | task->tk_status); |
|---|
| 1467 | + trace_ff_layout_write_error(hdr); |
|---|
| 1468 | + } |
|---|
| 1469 | + |
|---|
| 1420 | 1470 | err = ff_layout_async_handle_error(task, hdr->args.context->state, |
|---|
| 1421 | 1471 | hdr->ds_clp, hdr->lseg, |
|---|
| 1422 | 1472 | hdr->pgio_mirror_idx); |
|---|
| 1423 | 1473 | |
|---|
| 1474 | + trace_nfs4_pnfs_write(hdr, err); |
|---|
| 1424 | 1475 | clear_bit(NFS_IOHDR_RESEND_PNFS, &hdr->flags); |
|---|
| 1425 | 1476 | clear_bit(NFS_IOHDR_RESEND_MDS, &hdr->flags); |
|---|
| 1426 | 1477 | switch (err) { |
|---|
| .. | .. |
|---|
| 1454 | 1505 | { |
|---|
| 1455 | 1506 | int err; |
|---|
| 1456 | 1507 | |
|---|
| 1457 | | - trace_nfs4_pnfs_commit_ds(data, task->tk_status); |
|---|
| 1458 | | - if (task->tk_status < 0) |
|---|
| 1508 | + if (task->tk_status < 0) { |
|---|
| 1459 | 1509 | ff_layout_io_track_ds_error(data->lseg, data->ds_commit_index, |
|---|
| 1460 | 1510 | data->args.offset, data->args.count, |
|---|
| 1461 | | - data->res.op_status, OP_COMMIT, |
|---|
| 1511 | + &data->res.op_status, OP_COMMIT, |
|---|
| 1462 | 1512 | task->tk_status); |
|---|
| 1513 | + trace_ff_layout_commit_error(data); |
|---|
| 1514 | + } |
|---|
| 1515 | + |
|---|
| 1463 | 1516 | err = ff_layout_async_handle_error(task, NULL, data->ds_clp, |
|---|
| 1464 | 1517 | data->lseg, data->ds_commit_index); |
|---|
| 1465 | 1518 | |
|---|
| 1519 | + trace_nfs4_pnfs_commit_ds(data, err); |
|---|
| 1466 | 1520 | switch (err) { |
|---|
| 1467 | 1521 | case -NFS4ERR_RESET_TO_PNFS: |
|---|
| 1468 | 1522 | pnfs_generic_prepare_to_resend_writes(data); |
|---|
| .. | .. |
|---|
| 1509 | 1563 | if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) { |
|---|
| 1510 | 1564 | rpc_exit(task, -EIO); |
|---|
| 1511 | 1565 | return -EIO; |
|---|
| 1512 | | - } |
|---|
| 1513 | | - |
|---|
| 1514 | | - if (ff_layout_device_unavailable(hdr->lseg, hdr->pgio_mirror_idx)) { |
|---|
| 1515 | | - rpc_exit(task, -EHOSTDOWN); |
|---|
| 1516 | | - return -EAGAIN; |
|---|
| 1517 | 1566 | } |
|---|
| 1518 | 1567 | |
|---|
| 1519 | 1568 | ff_layout_write_record_layoutstats_start(task, hdr); |
|---|
| .. | .. |
|---|
| 1571 | 1620 | struct nfs_pgio_header *hdr = data; |
|---|
| 1572 | 1621 | |
|---|
| 1573 | 1622 | ff_layout_write_record_layoutstats_done(&hdr->task, hdr); |
|---|
| 1574 | | - if (test_bit(NFS_IOHDR_RESEND_PNFS, &hdr->flags)) |
|---|
| 1623 | + if (test_bit(NFS_IOHDR_RESEND_PNFS, &hdr->flags)) { |
|---|
| 1624 | + ff_layout_send_layouterror(hdr->lseg); |
|---|
| 1575 | 1625 | ff_layout_reset_write(hdr, true); |
|---|
| 1576 | | - else if (test_bit(NFS_IOHDR_RESEND_MDS, &hdr->flags)) |
|---|
| 1626 | + } else if (test_bit(NFS_IOHDR_RESEND_MDS, &hdr->flags)) |
|---|
| 1577 | 1627 | ff_layout_reset_write(hdr, false); |
|---|
| 1578 | 1628 | pnfs_generic_rw_release(data); |
|---|
| 1579 | 1629 | } |
|---|
| .. | .. |
|---|
| 1701 | 1751 | struct pnfs_layout_segment *lseg = hdr->lseg; |
|---|
| 1702 | 1752 | struct nfs4_pnfs_ds *ds; |
|---|
| 1703 | 1753 | struct rpc_clnt *ds_clnt; |
|---|
| 1704 | | - struct rpc_cred *ds_cred; |
|---|
| 1754 | + struct nfs4_ff_layout_mirror *mirror; |
|---|
| 1755 | + const struct cred *ds_cred; |
|---|
| 1705 | 1756 | loff_t offset = hdr->args.offset; |
|---|
| 1706 | 1757 | u32 idx = hdr->pgio_mirror_idx; |
|---|
| 1707 | 1758 | int vers; |
|---|
| .. | .. |
|---|
| 1711 | 1762 | __func__, hdr->inode->i_ino, |
|---|
| 1712 | 1763 | hdr->args.pgbase, (size_t)hdr->args.count, offset); |
|---|
| 1713 | 1764 | |
|---|
| 1714 | | - ds = nfs4_ff_layout_prepare_ds(lseg, idx, false); |
|---|
| 1765 | + mirror = FF_LAYOUT_COMP(lseg, idx); |
|---|
| 1766 | + ds = nfs4_ff_layout_prepare_ds(lseg, mirror, false); |
|---|
| 1715 | 1767 | if (!ds) |
|---|
| 1716 | 1768 | goto out_failed; |
|---|
| 1717 | 1769 | |
|---|
| 1718 | | - ds_clnt = nfs4_ff_find_or_create_ds_client(lseg, idx, ds->ds_clp, |
|---|
| 1770 | + ds_clnt = nfs4_ff_find_or_create_ds_client(mirror, ds->ds_clp, |
|---|
| 1719 | 1771 | hdr->inode); |
|---|
| 1720 | 1772 | if (IS_ERR(ds_clnt)) |
|---|
| 1721 | 1773 | goto out_failed; |
|---|
| 1722 | 1774 | |
|---|
| 1723 | | - ds_cred = ff_layout_get_ds_cred(lseg, idx, hdr->cred); |
|---|
| 1775 | + ds_cred = ff_layout_get_ds_cred(mirror, &lseg->pls_range, hdr->cred); |
|---|
| 1724 | 1776 | if (!ds_cred) |
|---|
| 1725 | 1777 | goto out_failed; |
|---|
| 1726 | 1778 | |
|---|
| 1727 | | - vers = nfs4_ff_layout_ds_version(lseg, idx); |
|---|
| 1779 | + vers = nfs4_ff_layout_ds_version(mirror); |
|---|
| 1728 | 1780 | |
|---|
| 1729 | 1781 | dprintk("%s USE DS: %s cl_count %d vers %d\n", __func__, |
|---|
| 1730 | 1782 | ds->ds_remotestr, refcount_read(&ds->ds_clp->cl_count), vers); |
|---|
| .. | .. |
|---|
| 1732 | 1784 | hdr->pgio_done_cb = ff_layout_read_done_cb; |
|---|
| 1733 | 1785 | refcount_inc(&ds->ds_clp->cl_count); |
|---|
| 1734 | 1786 | hdr->ds_clp = ds->ds_clp; |
|---|
| 1735 | | - fh = nfs4_ff_layout_select_ds_fh(lseg, idx); |
|---|
| 1787 | + fh = nfs4_ff_layout_select_ds_fh(mirror); |
|---|
| 1736 | 1788 | if (fh) |
|---|
| 1737 | 1789 | hdr->args.fh = fh; |
|---|
| 1738 | 1790 | |
|---|
| 1739 | | - if (vers == 4 && |
|---|
| 1740 | | - !nfs4_ff_layout_select_ds_stateid(lseg, idx, &hdr->args.stateid)) |
|---|
| 1741 | | - goto out_failed; |
|---|
| 1791 | + nfs4_ff_layout_select_ds_stateid(mirror, &hdr->args.stateid); |
|---|
| 1742 | 1792 | |
|---|
| 1743 | 1793 | /* |
|---|
| 1744 | 1794 | * Note that if we ever decide to split across DSes, |
|---|
| .. | .. |
|---|
| 1752 | 1802 | vers == 3 ? &ff_layout_read_call_ops_v3 : |
|---|
| 1753 | 1803 | &ff_layout_read_call_ops_v4, |
|---|
| 1754 | 1804 | 0, RPC_TASK_SOFTCONN); |
|---|
| 1755 | | - put_rpccred(ds_cred); |
|---|
| 1805 | + put_cred(ds_cred); |
|---|
| 1756 | 1806 | return PNFS_ATTEMPTED; |
|---|
| 1757 | 1807 | |
|---|
| 1758 | 1808 | out_failed: |
|---|
| 1759 | 1809 | if (ff_layout_avoid_mds_available_ds(lseg)) |
|---|
| 1760 | 1810 | return PNFS_TRY_AGAIN; |
|---|
| 1811 | + trace_pnfs_mds_fallback_read_pagelist(hdr->inode, |
|---|
| 1812 | + hdr->args.offset, hdr->args.count, |
|---|
| 1813 | + IOMODE_READ, NFS_I(hdr->inode)->layout, lseg); |
|---|
| 1761 | 1814 | return PNFS_NOT_ATTEMPTED; |
|---|
| 1762 | 1815 | } |
|---|
| 1763 | 1816 | |
|---|
| .. | .. |
|---|
| 1768 | 1821 | struct pnfs_layout_segment *lseg = hdr->lseg; |
|---|
| 1769 | 1822 | struct nfs4_pnfs_ds *ds; |
|---|
| 1770 | 1823 | struct rpc_clnt *ds_clnt; |
|---|
| 1771 | | - struct rpc_cred *ds_cred; |
|---|
| 1824 | + struct nfs4_ff_layout_mirror *mirror; |
|---|
| 1825 | + const struct cred *ds_cred; |
|---|
| 1772 | 1826 | loff_t offset = hdr->args.offset; |
|---|
| 1773 | 1827 | int vers; |
|---|
| 1774 | 1828 | struct nfs_fh *fh; |
|---|
| 1775 | | - int idx = hdr->pgio_mirror_idx; |
|---|
| 1829 | + u32 idx = hdr->pgio_mirror_idx; |
|---|
| 1776 | 1830 | |
|---|
| 1777 | | - ds = nfs4_ff_layout_prepare_ds(lseg, idx, true); |
|---|
| 1831 | + mirror = FF_LAYOUT_COMP(lseg, idx); |
|---|
| 1832 | + ds = nfs4_ff_layout_prepare_ds(lseg, mirror, true); |
|---|
| 1778 | 1833 | if (!ds) |
|---|
| 1779 | 1834 | goto out_failed; |
|---|
| 1780 | 1835 | |
|---|
| 1781 | | - ds_clnt = nfs4_ff_find_or_create_ds_client(lseg, idx, ds->ds_clp, |
|---|
| 1836 | + ds_clnt = nfs4_ff_find_or_create_ds_client(mirror, ds->ds_clp, |
|---|
| 1782 | 1837 | hdr->inode); |
|---|
| 1783 | 1838 | if (IS_ERR(ds_clnt)) |
|---|
| 1784 | 1839 | goto out_failed; |
|---|
| 1785 | 1840 | |
|---|
| 1786 | | - ds_cred = ff_layout_get_ds_cred(lseg, idx, hdr->cred); |
|---|
| 1841 | + ds_cred = ff_layout_get_ds_cred(mirror, &lseg->pls_range, hdr->cred); |
|---|
| 1787 | 1842 | if (!ds_cred) |
|---|
| 1788 | 1843 | goto out_failed; |
|---|
| 1789 | 1844 | |
|---|
| 1790 | | - vers = nfs4_ff_layout_ds_version(lseg, idx); |
|---|
| 1845 | + vers = nfs4_ff_layout_ds_version(mirror); |
|---|
| 1791 | 1846 | |
|---|
| 1792 | 1847 | dprintk("%s ino %lu sync %d req %zu@%llu DS: %s cl_count %d vers %d\n", |
|---|
| 1793 | 1848 | __func__, hdr->inode->i_ino, sync, (size_t) hdr->args.count, |
|---|
| .. | .. |
|---|
| 1798 | 1853 | refcount_inc(&ds->ds_clp->cl_count); |
|---|
| 1799 | 1854 | hdr->ds_clp = ds->ds_clp; |
|---|
| 1800 | 1855 | hdr->ds_commit_idx = idx; |
|---|
| 1801 | | - fh = nfs4_ff_layout_select_ds_fh(lseg, idx); |
|---|
| 1856 | + fh = nfs4_ff_layout_select_ds_fh(mirror); |
|---|
| 1802 | 1857 | if (fh) |
|---|
| 1803 | 1858 | hdr->args.fh = fh; |
|---|
| 1804 | 1859 | |
|---|
| 1805 | | - if (vers == 4 && |
|---|
| 1806 | | - !nfs4_ff_layout_select_ds_stateid(lseg, idx, &hdr->args.stateid)) |
|---|
| 1807 | | - goto out_failed; |
|---|
| 1860 | + nfs4_ff_layout_select_ds_stateid(mirror, &hdr->args.stateid); |
|---|
| 1808 | 1861 | |
|---|
| 1809 | 1862 | /* |
|---|
| 1810 | 1863 | * Note that if we ever decide to split across DSes, |
|---|
| .. | .. |
|---|
| 1817 | 1870 | vers == 3 ? &ff_layout_write_call_ops_v3 : |
|---|
| 1818 | 1871 | &ff_layout_write_call_ops_v4, |
|---|
| 1819 | 1872 | sync, RPC_TASK_SOFTCONN); |
|---|
| 1820 | | - put_rpccred(ds_cred); |
|---|
| 1873 | + put_cred(ds_cred); |
|---|
| 1821 | 1874 | return PNFS_ATTEMPTED; |
|---|
| 1822 | 1875 | |
|---|
| 1823 | 1876 | out_failed: |
|---|
| 1824 | 1877 | if (ff_layout_avoid_mds_available_ds(lseg)) |
|---|
| 1825 | 1878 | return PNFS_TRY_AGAIN; |
|---|
| 1879 | + trace_pnfs_mds_fallback_write_pagelist(hdr->inode, |
|---|
| 1880 | + hdr->args.offset, hdr->args.count, |
|---|
| 1881 | + IOMODE_RW, NFS_I(hdr->inode)->layout, lseg); |
|---|
| 1826 | 1882 | return PNFS_NOT_ATTEMPTED; |
|---|
| 1827 | 1883 | } |
|---|
| 1828 | 1884 | |
|---|
| .. | .. |
|---|
| 1847 | 1903 | struct pnfs_layout_segment *lseg = data->lseg; |
|---|
| 1848 | 1904 | struct nfs4_pnfs_ds *ds; |
|---|
| 1849 | 1905 | struct rpc_clnt *ds_clnt; |
|---|
| 1850 | | - struct rpc_cred *ds_cred; |
|---|
| 1906 | + struct nfs4_ff_layout_mirror *mirror; |
|---|
| 1907 | + const struct cred *ds_cred; |
|---|
| 1851 | 1908 | u32 idx; |
|---|
| 1852 | 1909 | int vers, ret; |
|---|
| 1853 | 1910 | struct nfs_fh *fh; |
|---|
| .. | .. |
|---|
| 1857 | 1914 | goto out_err; |
|---|
| 1858 | 1915 | |
|---|
| 1859 | 1916 | idx = calc_ds_index_from_commit(lseg, data->ds_commit_index); |
|---|
| 1860 | | - ds = nfs4_ff_layout_prepare_ds(lseg, idx, true); |
|---|
| 1917 | + mirror = FF_LAYOUT_COMP(lseg, idx); |
|---|
| 1918 | + ds = nfs4_ff_layout_prepare_ds(lseg, mirror, true); |
|---|
| 1861 | 1919 | if (!ds) |
|---|
| 1862 | 1920 | goto out_err; |
|---|
| 1863 | 1921 | |
|---|
| 1864 | | - ds_clnt = nfs4_ff_find_or_create_ds_client(lseg, idx, ds->ds_clp, |
|---|
| 1922 | + ds_clnt = nfs4_ff_find_or_create_ds_client(mirror, ds->ds_clp, |
|---|
| 1865 | 1923 | data->inode); |
|---|
| 1866 | 1924 | if (IS_ERR(ds_clnt)) |
|---|
| 1867 | 1925 | goto out_err; |
|---|
| 1868 | 1926 | |
|---|
| 1869 | | - ds_cred = ff_layout_get_ds_cred(lseg, idx, data->cred); |
|---|
| 1927 | + ds_cred = ff_layout_get_ds_cred(mirror, &lseg->pls_range, data->cred); |
|---|
| 1870 | 1928 | if (!ds_cred) |
|---|
| 1871 | 1929 | goto out_err; |
|---|
| 1872 | 1930 | |
|---|
| 1873 | | - vers = nfs4_ff_layout_ds_version(lseg, idx); |
|---|
| 1931 | + vers = nfs4_ff_layout_ds_version(mirror); |
|---|
| 1874 | 1932 | |
|---|
| 1875 | 1933 | dprintk("%s ino %lu, how %d cl_count %d vers %d\n", __func__, |
|---|
| 1876 | 1934 | data->inode->i_ino, how, refcount_read(&ds->ds_clp->cl_count), |
|---|
| .. | .. |
|---|
| 1887 | 1945 | vers == 3 ? &ff_layout_commit_call_ops_v3 : |
|---|
| 1888 | 1946 | &ff_layout_commit_call_ops_v4, |
|---|
| 1889 | 1947 | how, RPC_TASK_SOFTCONN); |
|---|
| 1890 | | - put_rpccred(ds_cred); |
|---|
| 1948 | + put_cred(ds_cred); |
|---|
| 1891 | 1949 | return ret; |
|---|
| 1892 | 1950 | out_err: |
|---|
| 1893 | 1951 | pnfs_generic_prepare_to_resend_writes(data); |
|---|
| .. | .. |
|---|
| 1912 | 1970 | return NULL; |
|---|
| 1913 | 1971 | |
|---|
| 1914 | 1972 | return &FF_LAYOUT_FROM_HDR(layout)->commit_info; |
|---|
| 1973 | +} |
|---|
| 1974 | + |
|---|
| 1975 | +static void |
|---|
| 1976 | +ff_layout_setup_ds_info(struct pnfs_ds_commit_info *fl_cinfo, |
|---|
| 1977 | + struct pnfs_layout_segment *lseg) |
|---|
| 1978 | +{ |
|---|
| 1979 | + struct nfs4_ff_layout_segment *flseg = FF_LAYOUT_LSEG(lseg); |
|---|
| 1980 | + struct inode *inode = lseg->pls_layout->plh_inode; |
|---|
| 1981 | + struct pnfs_commit_array *array, *new; |
|---|
| 1982 | + |
|---|
| 1983 | + new = pnfs_alloc_commit_array(flseg->mirror_array_cnt, GFP_NOIO); |
|---|
| 1984 | + if (new) { |
|---|
| 1985 | + spin_lock(&inode->i_lock); |
|---|
| 1986 | + array = pnfs_add_commit_array(fl_cinfo, new, lseg); |
|---|
| 1987 | + spin_unlock(&inode->i_lock); |
|---|
| 1988 | + if (array != new) |
|---|
| 1989 | + pnfs_free_commit_array(new); |
|---|
| 1990 | + } |
|---|
| 1991 | +} |
|---|
| 1992 | + |
|---|
| 1993 | +static void |
|---|
| 1994 | +ff_layout_release_ds_info(struct pnfs_ds_commit_info *fl_cinfo, |
|---|
| 1995 | + struct inode *inode) |
|---|
| 1996 | +{ |
|---|
| 1997 | + spin_lock(&inode->i_lock); |
|---|
| 1998 | + pnfs_generic_ds_cinfo_destroy(fl_cinfo); |
|---|
| 1999 | + spin_unlock(&inode->i_lock); |
|---|
| 1915 | 2000 | } |
|---|
| 1916 | 2001 | |
|---|
| 1917 | 2002 | static void |
|---|
| .. | .. |
|---|
| 2034 | 2119 | |
|---|
| 2035 | 2120 | dprintk("%s: Begin\n", __func__); |
|---|
| 2036 | 2121 | |
|---|
| 2037 | | - xdr_init_encode(&tmp_xdr, &tmp_buf, NULL); |
|---|
| 2122 | + xdr_init_encode(&tmp_xdr, &tmp_buf, NULL, NULL); |
|---|
| 2038 | 2123 | |
|---|
| 2039 | 2124 | ff_layout_encode_ioerr(&tmp_xdr, args, ff_args); |
|---|
| 2040 | 2125 | ff_layout_encode_iostats_array(&tmp_xdr, args, ff_args); |
|---|
| .. | .. |
|---|
| 2099 | 2184 | out_nomem: |
|---|
| 2100 | 2185 | return -ENOMEM; |
|---|
| 2101 | 2186 | } |
|---|
| 2187 | + |
|---|
| 2188 | +#ifdef CONFIG_NFS_V4_2 |
|---|
| 2189 | +void |
|---|
| 2190 | +ff_layout_send_layouterror(struct pnfs_layout_segment *lseg) |
|---|
| 2191 | +{ |
|---|
| 2192 | + struct pnfs_layout_hdr *lo = lseg->pls_layout; |
|---|
| 2193 | + struct nfs42_layout_error *errors; |
|---|
| 2194 | + LIST_HEAD(head); |
|---|
| 2195 | + |
|---|
| 2196 | + if (!nfs_server_capable(lo->plh_inode, NFS_CAP_LAYOUTERROR)) |
|---|
| 2197 | + return; |
|---|
| 2198 | + ff_layout_fetch_ds_ioerr(lo, &lseg->pls_range, &head, -1); |
|---|
| 2199 | + if (list_empty(&head)) |
|---|
| 2200 | + return; |
|---|
| 2201 | + |
|---|
| 2202 | + errors = kmalloc_array(NFS42_LAYOUTERROR_MAX, |
|---|
| 2203 | + sizeof(*errors), GFP_NOFS); |
|---|
| 2204 | + if (errors != NULL) { |
|---|
| 2205 | + const struct nfs4_ff_layout_ds_err *pos; |
|---|
| 2206 | + size_t n = 0; |
|---|
| 2207 | + |
|---|
| 2208 | + list_for_each_entry(pos, &head, list) { |
|---|
| 2209 | + errors[n].offset = pos->offset; |
|---|
| 2210 | + errors[n].length = pos->length; |
|---|
| 2211 | + nfs4_stateid_copy(&errors[n].stateid, &pos->stateid); |
|---|
| 2212 | + errors[n].errors[0].dev_id = pos->deviceid; |
|---|
| 2213 | + errors[n].errors[0].status = pos->status; |
|---|
| 2214 | + errors[n].errors[0].opnum = pos->opnum; |
|---|
| 2215 | + n++; |
|---|
| 2216 | + if (!list_is_last(&pos->list, &head) && |
|---|
| 2217 | + n < NFS42_LAYOUTERROR_MAX) |
|---|
| 2218 | + continue; |
|---|
| 2219 | + if (nfs42_proc_layouterror(lseg, errors, n) < 0) |
|---|
| 2220 | + break; |
|---|
| 2221 | + n = 0; |
|---|
| 2222 | + } |
|---|
| 2223 | + kfree(errors); |
|---|
| 2224 | + } |
|---|
| 2225 | + ff_layout_free_ds_ioerr(&head); |
|---|
| 2226 | +} |
|---|
| 2227 | +#else |
|---|
| 2228 | +void |
|---|
| 2229 | +ff_layout_send_layouterror(struct pnfs_layout_segment *lseg) |
|---|
| 2230 | +{ |
|---|
| 2231 | +} |
|---|
| 2232 | +#endif |
|---|
| 2102 | 2233 | |
|---|
| 2103 | 2234 | static int |
|---|
| 2104 | 2235 | ff_layout_ntop4(const struct sockaddr *sap, char *buf, const size_t buflen) |
|---|
| .. | .. |
|---|
| 2353 | 2484 | return 0; |
|---|
| 2354 | 2485 | } |
|---|
| 2355 | 2486 | |
|---|
| 2487 | +static const struct pnfs_commit_ops ff_layout_commit_ops = { |
|---|
| 2488 | + .setup_ds_info = ff_layout_setup_ds_info, |
|---|
| 2489 | + .release_ds_info = ff_layout_release_ds_info, |
|---|
| 2490 | + .mark_request_commit = pnfs_layout_mark_request_commit, |
|---|
| 2491 | + .clear_request_commit = pnfs_generic_clear_request_commit, |
|---|
| 2492 | + .scan_commit_lists = pnfs_generic_scan_commit_lists, |
|---|
| 2493 | + .recover_commit_reqs = pnfs_generic_recover_commit_reqs, |
|---|
| 2494 | + .commit_pagelist = ff_layout_commit_pagelist, |
|---|
| 2495 | +}; |
|---|
| 2496 | + |
|---|
| 2356 | 2497 | static struct pnfs_layoutdriver_type flexfilelayout_type = { |
|---|
| 2357 | 2498 | .id = LAYOUT_FLEX_FILES, |
|---|
| 2358 | 2499 | .name = "LAYOUT_FLEX_FILES", |
|---|
| 2359 | 2500 | .owner = THIS_MODULE, |
|---|
| 2360 | 2501 | .flags = PNFS_LAYOUTGET_ON_OPEN, |
|---|
| 2502 | + .max_layoutget_response = 4096, /* 1 page or so... */ |
|---|
| 2361 | 2503 | .set_layoutdriver = ff_layout_set_layoutdriver, |
|---|
| 2362 | 2504 | .alloc_layout_hdr = ff_layout_alloc_layout_hdr, |
|---|
| 2363 | 2505 | .free_layout_hdr = ff_layout_free_layout_hdr, |
|---|
| .. | .. |
|---|
| 2368 | 2510 | .pg_write_ops = &ff_layout_pg_write_ops, |
|---|
| 2369 | 2511 | .get_ds_info = ff_layout_get_ds_info, |
|---|
| 2370 | 2512 | .free_deviceid_node = ff_layout_free_deviceid_node, |
|---|
| 2371 | | - .mark_request_commit = pnfs_layout_mark_request_commit, |
|---|
| 2372 | | - .clear_request_commit = pnfs_generic_clear_request_commit, |
|---|
| 2373 | | - .scan_commit_lists = pnfs_generic_scan_commit_lists, |
|---|
| 2374 | | - .recover_commit_reqs = pnfs_generic_recover_commit_reqs, |
|---|
| 2375 | | - .commit_pagelist = ff_layout_commit_pagelist, |
|---|
| 2376 | 2513 | .read_pagelist = ff_layout_read_pagelist, |
|---|
| 2377 | 2514 | .write_pagelist = ff_layout_write_pagelist, |
|---|
| 2378 | 2515 | .alloc_deviceid_node = ff_layout_alloc_deviceid_node, |
|---|
| .. | .. |
|---|
| 2385 | 2522 | { |
|---|
| 2386 | 2523 | printk(KERN_INFO "%s: NFSv4 Flexfile Layout Driver Registering...\n", |
|---|
| 2387 | 2524 | __func__); |
|---|
| 2388 | | - if (!ff_zero_group) { |
|---|
| 2389 | | - ff_zero_group = groups_alloc(0); |
|---|
| 2390 | | - if (!ff_zero_group) |
|---|
| 2391 | | - return -ENOMEM; |
|---|
| 2392 | | - } |
|---|
| 2393 | 2525 | return pnfs_register_layoutdriver(&flexfilelayout_type); |
|---|
| 2394 | 2526 | } |
|---|
| 2395 | 2527 | |
|---|
| .. | .. |
|---|
| 2398 | 2530 | printk(KERN_INFO "%s: NFSv4 Flexfile Layout Driver Unregistering...\n", |
|---|
| 2399 | 2531 | __func__); |
|---|
| 2400 | 2532 | pnfs_unregister_layoutdriver(&flexfilelayout_type); |
|---|
| 2401 | | - if (ff_zero_group) { |
|---|
| 2402 | | - put_group_info(ff_zero_group); |
|---|
| 2403 | | - ff_zero_group = NULL; |
|---|
| 2404 | | - } |
|---|
| 2405 | 2533 | } |
|---|
| 2406 | 2534 | |
|---|
| 2407 | 2535 | MODULE_ALIAS("nfs-layouttype4-4"); |
|---|
| .. | .. |
|---|
| 2411 | 2539 | |
|---|
| 2412 | 2540 | module_init(nfs4flexfilelayout_init); |
|---|
| 2413 | 2541 | module_exit(nfs4flexfilelayout_exit); |
|---|
| 2542 | + |
|---|
| 2543 | +module_param(io_maxretrans, ushort, 0644); |
|---|
| 2544 | +MODULE_PARM_DESC(io_maxretrans, "The number of times the NFSv4.1 client " |
|---|
| 2545 | + "retries an I/O request before returning an error. "); |
|---|