From: Greg Kroah-Hartman Date: Thu, 2 Oct 2014 23:52:43 +0000 (-0700) Subject: 3.16-stable patches X-Git-Tag: v3.16.4~53 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7057d1aa6f5c7fa623963a7deca6fd5fccd17ff2;p=thirdparty%2Fkernel%2Fstable-queue.git 3.16-stable patches added patches: acpi-lpss-complete-pm-entries-for-lpss-power-domain.patch acpi-rtc-fix-cmos-rtc-opregion-handler-accesses-to-wrong-addresses.patch cgroup-check-cgroup-liveliness-before-unbreaking-kernfs.patch iommu-arm-smmu-fix-programming-of-smmu_cbn_tcr-for-stage-1.patch iommu-fsl-fix-warning-resulting-from-adding-pci-device-twice.patch iommu-vt-d-check-return-value-of-acpi_bus_get_device.patch nfs-can_coalesce_requests-must-enforce-contiguity.patch nfs-change-nfs_page_group_lock-argument.patch nfs-check-wait_on_bit_lock-err-in-page_group_lock.patch nfs-clear_request_commit-while-holding-i_lock.patch nfs-disallow-duplicate-pages-in-pgio-page-vectors.patch nfs-don-t-sleep-with-inode-lock-in-lock_and_join_requests.patch nfs-fix-error-handling-in-lock_and_join_requests.patch nfs-fix-nonblocking-calls-to-nfs_page_group_lock.patch nfs-merge-nfs_pgio_data-into-_header.patch nfs-move-nfs_pgio_data-and-remove-nfs_rw_header.patch nfs-remove-pgio_header-refcount-related-cleanup.patch nfs-rename-members-of-nfs_pgio_data.patch nfs-use-blocking-page_group_lock-in-add_request.patch nfsd4-fix-corruption-of-nfsv4-read-data.patch nfsd4-fix-rd_dircount-enforcement.patch nfsv4-fix-another-bug-in-the-close-open_downgrade-code.patch nfsv4-nfs4_state_manager-vs.-nfs_server_remove_lists.patch pnfs-add-pnfs_put_lseg_async.patch revert-acpi-battery-fix-wrong-value-of-capacity_now-reported-when-fully-charged.patch --- diff --git a/queue-3.16/acpi-lpss-complete-pm-entries-for-lpss-power-domain.patch b/queue-3.16/acpi-lpss-complete-pm-entries-for-lpss-power-domain.patch new file mode 100644 index 00000000000..a717579a62c --- /dev/null +++ b/queue-3.16/acpi-lpss-complete-pm-entries-for-lpss-power-domain.patch @@ -0,0 +1,56 @@ +From f4168b617ac09986c4333accaff5d8ba5a9db7bf Mon Sep 17 00:00:00 2001 +From: Fu Zhonghui +Date: Tue, 9 Sep 2014 16:30:06 +0200 +Subject: ACPI / LPSS: complete PM entries for LPSS power domain + +From: Fu Zhonghui + +commit f4168b617ac09986c4333accaff5d8ba5a9db7bf upstream. + +PM entries of LPSS power domain were not implemented correctly +in commit c78b0830667a "ACPI / LPSS: custom power domain for LPSS". + +This patch fixes and completes these PM entries. + +Fixes: c78b0830667a (ACPI / LPSS: custom power domain for LPSS) +Signed-off-by: Li Aubrey +Signed-off-by: Mika Westerberg +Signed-off-by: Fu Zhonghui +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/acpi_lpss.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/acpi/acpi_lpss.c ++++ b/drivers/acpi/acpi_lpss.c +@@ -583,7 +583,7 @@ static int acpi_lpss_suspend_late(struct + return acpi_dev_suspend_late(dev); + } + +-static int acpi_lpss_restore_early(struct device *dev) ++static int acpi_lpss_resume_early(struct device *dev) + { + int ret = acpi_dev_resume_early(dev); + +@@ -623,15 +623,15 @@ static int acpi_lpss_runtime_resume(stru + static struct dev_pm_domain acpi_lpss_pm_domain = { + .ops = { + #ifdef CONFIG_PM_SLEEP +- .suspend_late = acpi_lpss_suspend_late, +- .restore_early = acpi_lpss_restore_early, + .prepare = acpi_subsys_prepare, + .complete = acpi_subsys_complete, + .suspend = acpi_subsys_suspend, +- .resume_early = acpi_subsys_resume_early, ++ .suspend_late = acpi_lpss_suspend_late, ++ .resume_early = acpi_lpss_resume_early, + .freeze = acpi_subsys_freeze, + .poweroff = acpi_subsys_suspend, +- .poweroff_late = acpi_subsys_suspend_late, ++ .poweroff_late = acpi_lpss_suspend_late, ++ .restore_early = acpi_lpss_resume_early, + #endif + #ifdef CONFIG_PM_RUNTIME + .runtime_suspend = acpi_lpss_runtime_suspend, diff --git a/queue-3.16/acpi-rtc-fix-cmos-rtc-opregion-handler-accesses-to-wrong-addresses.patch b/queue-3.16/acpi-rtc-fix-cmos-rtc-opregion-handler-accesses-to-wrong-addresses.patch new file mode 100644 index 00000000000..9491861413d --- /dev/null +++ b/queue-3.16/acpi-rtc-fix-cmos-rtc-opregion-handler-accesses-to-wrong-addresses.patch @@ -0,0 +1,35 @@ +From 9389f46e9782ea5e56fbd7b2e59ba7c08f3ba86b Mon Sep 17 00:00:00 2001 +From: "Lee, Chun-Yi" +Date: Thu, 4 Sep 2014 15:13:39 +0800 +Subject: ACPI / RTC: Fix CMOS RTC opregion handler accesses to wrong addresses + +From: "Lee, Chun-Yi" + +commit 9389f46e9782ea5e56fbd7b2e59ba7c08f3ba86b upstream. + +The value64 parameter is an u64 point that used to transfer the value +for write to CMOS, or used to return the value that's read from CMOS. + +The value64 is an u64 point, so don't need get address again. It causes +acpi_cmos_rtc_space_handler always return 0 to reader and didn't write +expected value to CMOS. + +Signed-off-by: Lee, Chun-Yi +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/acpi_cmos_rtc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/acpi/acpi_cmos_rtc.c ++++ b/drivers/acpi/acpi_cmos_rtc.c +@@ -33,7 +33,7 @@ acpi_cmos_rtc_space_handler(u32 function + void *handler_context, void *region_context) + { + int i; +- u8 *value = (u8 *)&value64; ++ u8 *value = (u8 *)value64; + + if (address > 0xff || !value64) + return AE_BAD_PARAMETER; diff --git a/queue-3.16/cgroup-check-cgroup-liveliness-before-unbreaking-kernfs.patch b/queue-3.16/cgroup-check-cgroup-liveliness-before-unbreaking-kernfs.patch new file mode 100644 index 00000000000..9df31b8d111 --- /dev/null +++ b/queue-3.16/cgroup-check-cgroup-liveliness-before-unbreaking-kernfs.patch @@ -0,0 +1,72 @@ +From aa32362f011c6e863132b16c1761487166a4bad2 Mon Sep 17 00:00:00 2001 +From: Li Zefan +Date: Thu, 4 Sep 2014 14:43:38 +0800 +Subject: cgroup: check cgroup liveliness before unbreaking kernfs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Li Zefan + +commit aa32362f011c6e863132b16c1761487166a4bad2 upstream. + +When cgroup_kn_lock_live() is called through some kernfs operation and +another thread is calling cgroup_rmdir(), we'll trigger the warning in +cgroup_get(). + +------------[ cut here ]------------ +WARNING: CPU: 1 PID: 1228 at kernel/cgroup.c:1034 cgroup_get+0x89/0xa0() +... +Call Trace: + [] dump_stack+0x41/0x52 + [] warn_slowpath_common+0x7f/0xa0 + [] warn_slowpath_null+0x1d/0x20 + [] cgroup_get+0x89/0xa0 + [] cgroup_kn_lock_live+0x28/0x70 + [] __cgroup_procs_write.isra.26+0x51/0x230 + [] cgroup_tasks_write+0x12/0x20 + [] cgroup_file_write+0x40/0x130 + [] kernfs_fop_write+0xd1/0x160 + [] vfs_write+0x98/0x1e0 + [] SyS_write+0x4d/0xa0 + [] sysenter_do_call+0x12/0x12 +---[ end trace 6f2e0c38c2108a74 ]--- + +Fix this by calling css_tryget() instead of cgroup_get(). + +v2: +- move cgroup_tryget() right below cgroup_get() definition. (Tejun) + +Reported-by: Toralf Förster +Signed-off-by: Zefan Li +Signed-off-by: Tejun Heo +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/cgroup.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/kernel/cgroup.c ++++ b/kernel/cgroup.c +@@ -1031,6 +1031,11 @@ static void cgroup_get(struct cgroup *cg + css_get(&cgrp->self); + } + ++static bool cgroup_tryget(struct cgroup *cgrp) ++{ ++ return css_tryget(&cgrp->self); ++} ++ + static void cgroup_put(struct cgroup *cgrp) + { + css_put(&cgrp->self); +@@ -1091,7 +1096,8 @@ static struct cgroup *cgroup_kn_lock_liv + * protection against removal. Ensure @cgrp stays accessible and + * break the active_ref protection. + */ +- cgroup_get(cgrp); ++ if (!cgroup_tryget(cgrp)) ++ return NULL; + kernfs_break_active_protection(kn); + + mutex_lock(&cgroup_mutex); diff --git a/queue-3.16/iommu-arm-smmu-fix-programming-of-smmu_cbn_tcr-for-stage-1.patch b/queue-3.16/iommu-arm-smmu-fix-programming-of-smmu_cbn_tcr-for-stage-1.patch new file mode 100644 index 00000000000..9732f0f5301 --- /dev/null +++ b/queue-3.16/iommu-arm-smmu-fix-programming-of-smmu_cbn_tcr-for-stage-1.patch @@ -0,0 +1,39 @@ +From 1fc870c7efa364862c3bc792cfbdb38afea26742 Mon Sep 17 00:00:00 2001 +From: Olav Haugan +Date: Mon, 4 Aug 2014 19:01:02 +0100 +Subject: iommu/arm-smmu: fix programming of SMMU_CBn_TCR for stage 1 + +From: Olav Haugan + +commit 1fc870c7efa364862c3bc792cfbdb38afea26742 upstream. + +Stage-1 context banks do not have the SMMU_CBn_TCR[SL0] field since it +is only applicable to stage-2 context banks. + +This patch ensures that we don't set the reserved TCR bits for stage-1 +translations. + +Signed-off-by: Olav Haugan +Signed-off-by: Will Deacon +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/iommu/arm-smmu.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/iommu/arm-smmu.c ++++ b/drivers/iommu/arm-smmu.c +@@ -830,8 +830,11 @@ static void arm_smmu_init_context_bank(s + reg |= TTBCR_EAE | + (TTBCR_SH_IS << TTBCR_SH0_SHIFT) | + (TTBCR_RGN_WBWA << TTBCR_ORGN0_SHIFT) | +- (TTBCR_RGN_WBWA << TTBCR_IRGN0_SHIFT) | +- (TTBCR_SL0_LVL_1 << TTBCR_SL0_SHIFT); ++ (TTBCR_RGN_WBWA << TTBCR_IRGN0_SHIFT); ++ ++ if (!stage1) ++ reg |= (TTBCR_SL0_LVL_1 << TTBCR_SL0_SHIFT); ++ + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR); + + /* MAIR0 (stage-1 only) */ diff --git a/queue-3.16/iommu-fsl-fix-warning-resulting-from-adding-pci-device-twice.patch b/queue-3.16/iommu-fsl-fix-warning-resulting-from-adding-pci-device-twice.patch new file mode 100644 index 00000000000..47281a294b9 --- /dev/null +++ b/queue-3.16/iommu-fsl-fix-warning-resulting-from-adding-pci-device-twice.patch @@ -0,0 +1,92 @@ +From 5a9137a66b521d667236e95c307b92af532fe600 Mon Sep 17 00:00:00 2001 +From: Varun Sethi +Date: Thu, 4 Sep 2014 17:08:45 +0530 +Subject: iommu/fsl: Fix warning resulting from adding PCI device twice + +From: Varun Sethi + +commit 5a9137a66b521d667236e95c307b92af532fe600 upstream. + +iommu_group_get_for_dev determines the iommu group for the PCI device and adds +the device to the group. + +In the PAMU driver we were again adding the device to the same group without checking +if the device already had an iommu group. This resulted in the following warning. + +sysfs: cannot create duplicate filename '/devices/ffe200000.pcie/pci0000:00/0000:00:00.0/iommu_group' +------------[ cut here ]------------ +WARNING: at fs/sysfs/dir.c:31 +Modules linked in: +CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.17.0-rc3-00002-g7505cea-dirty #126 +task: c0000001fe0a0000 ti: c0000001fe044000 task.ti: c0000001fe044000 +NIP: c00000000018879c LR: c000000000188798 CTR: c00000000001ea50 +REGS: c0000001fe047040 TRAP: 0700 Not tainted (3.17.0-rc3-00002-g7505cea-dirty) +MSR: 0000000080029000 CR: 24ad8e22 XER: 20000000 +SOFTE: 1 +GPR00: c000000000188798 c0000001fe0472c0 c0000000009a52e0 0000000000000065 +GPR04: 0000000000000001 0000000000000000 3a30303a00000000 0000000027000000 +GPR08: 2f696f6d00000000 c0000000008d3830 c0000000009b3938 c0000000009bb3d0 +GPR12: 0000000028ad8e24 c00000000fff4000 c00000000000205c 0000000000000000 +GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 +GPR20: 0000000000000000 0000000000000000 0000000000000000 c0000000008a4c70 +GPR24: c0000000007e9010 c0000001fe0140a8 ffffffffffffffef 0000000000000001 +GPR28: c0000001fe22ebb8 c0000000007e9010 c00000000090bf10 c0000001fe220000 +NIP [c00000000018879c] .sysfs_warn_dup+0x74/0xa4 +LR [c000000000188798] .sysfs_warn_dup+0x70/0xa4 +Call Trace: +[c0000001fe0472c0] [c000000000188798] .sysfs_warn_dup+0x70/0xa4 (unreliable) +[c0000001fe047350] [c000000000188d34] .sysfs_do_create_link_sd.clone.2+0x168/0x174 +[c0000001fe047400] [c0000000004b3cf8] .iommu_group_add_device+0x78/0x244 +[c0000001fe0474b0] [c0000000004b6964] .fsl_pamu_add_device+0x88/0x1a8 +[c0000001fe047570] [c0000000004b3960] .iommu_bus_notifier+0xdc/0x15c +[c0000001fe047600] [c000000000059848] .notifier_call_chain+0x8c/0xe8 +[c0000001fe0476a0] [c000000000059d04] .__blocking_notifier_call_chain+0x58/0x84 +[c0000001fe047750] [c00000000036619c] .device_add+0x464/0x5c8 +[c0000001fe047820] [c000000000300ebc] .pci_device_add+0x14c/0x17c +[c0000001fe0478c0] [c000000000300fbc] .pci_scan_single_device+0xd0/0xf4 +[c0000001fe047970] [c00000000030104c] .pci_scan_slot+0x6c/0x18c +[c0000001fe047a10] [c00000000030226c] .pci_scan_child_bus+0x40/0x114 +[c0000001fe047ac0] [c000000000021974] .pcibios_scan_phb+0x240/0x2c8 +[c0000001fe047b70] [c00000000085a970] .pcibios_init+0x64/0xc8 +[c0000001fe047c00] [c000000000001884] .do_one_initcall+0xbc/0x224 +[c0000001fe047d00] [c000000000852d50] .kernel_init_freeable+0x14c/0x21c +[c0000001fe047db0] [c000000000002078] .kernel_init+0x1c/0xfa4 +[c0000001fe047e30] [c000000000000884] .ret_from_kernel_thread+0x58/0xd4 +Instruction dump: +7c7f1b79 4182001c 7fe4fb78 7f83e378 38a01000 4bffc905 60000000 7c641b78 +e87e8008 7fa5eb78 48482ff5 60000000 <0fe00000> 7fe3fb78 4bf7bd39 60000000 + +Signed-off-by: Varun Sethi +Signed-off-by: Joerg Roedel +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/iommu/fsl_pamu_domain.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- a/drivers/iommu/fsl_pamu_domain.c ++++ b/drivers/iommu/fsl_pamu_domain.c +@@ -1048,7 +1048,7 @@ static int fsl_pamu_add_device(struct de + struct iommu_group *group = ERR_PTR(-ENODEV); + struct pci_dev *pdev; + const u32 *prop; +- int ret, len; ++ int ret = 0, len; + + /* + * For platform devices we allocate a separate group for +@@ -1071,7 +1071,13 @@ static int fsl_pamu_add_device(struct de + if (IS_ERR(group)) + return PTR_ERR(group); + +- ret = iommu_group_add_device(group, dev); ++ /* ++ * Check if device has already been added to an iommu group. ++ * Group could have already been created for a PCI device in ++ * the iommu_group_get_for_dev path. ++ */ ++ if (!dev->iommu_group) ++ ret = iommu_group_add_device(group, dev); + + iommu_group_put(group); + return ret; diff --git a/queue-3.16/iommu-vt-d-check-return-value-of-acpi_bus_get_device.patch b/queue-3.16/iommu-vt-d-check-return-value-of-acpi_bus_get_device.patch new file mode 100644 index 00000000000..9943d74a2bf --- /dev/null +++ b/queue-3.16/iommu-vt-d-check-return-value-of-acpi_bus_get_device.patch @@ -0,0 +1,36 @@ +From c0df975f9045d6b2b13d88746e628ac308ff49ea Mon Sep 17 00:00:00 2001 +From: Joerg Roedel +Date: Thu, 21 Aug 2014 23:06:48 +0200 +Subject: iommu/vt-d: Check return value of acpi_bus_get_device() + +From: Joerg Roedel + +commit c0df975f9045d6b2b13d88746e628ac308ff49ea upstream. + +Checking adev == NULL is not sufficient as +acpi_bus_get_device() might not touch the value of this +parameter in an error case, so check the return value +directly. + +Fixes: ed40356b5fcf1ce28e026ab39c5b2b6939068b50 +Cc: David Woodhouse +Signed-off-by: Joerg Roedel +Reviewed-by: Alex Williamson +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/iommu/dmar.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/iommu/dmar.c ++++ b/drivers/iommu/dmar.c +@@ -677,8 +677,7 @@ static int __init dmar_acpi_dev_scope_in + andd->object_name); + continue; + } +- acpi_bus_get_device(h, &adev); +- if (!adev) { ++ if (acpi_bus_get_device(h, &adev)) { + pr_err("Failed to get device for ACPI object %s\n", + andd->object_name); + continue; diff --git a/queue-3.16/nfs-can_coalesce_requests-must-enforce-contiguity.patch b/queue-3.16/nfs-can_coalesce_requests-must-enforce-contiguity.patch new file mode 100644 index 00000000000..5a366f67ac6 --- /dev/null +++ b/queue-3.16/nfs-can_coalesce_requests-must-enforce-contiguity.patch @@ -0,0 +1,49 @@ +From trond.myklebust@primarydata.com Thu Oct 2 16:50:10 2014 +From: Trond Myklebust +Date: Mon, 15 Sep 2014 14:14:45 -0400 +Subject: nfs: can_coalesce_requests must enforce contiguity +To: stable@vger.kernel.org +Cc: Weston Andros Adamson , linux-nfs@vger.kernel.org +Message-ID: <1410804885-17228-15-git-send-email-trond.myklebust@primarydata.com> + + +From: Weston Andros Adamson + +commit 78270e8fbc2916bfc8305b8f58f33474cce1ec0e upstream. + +Commit 6094f83864c1d1296566a282cba05ba613f151ee +"nfs: allow coalescing of subpage requests" got rid of the requirement +that requests cover whole pages, but it made some incorrect assumptions. + +It turns out that callers of this interface can map adjacent requests +(by file position as seen by req_offset + req->wb_bytes) to different pages, +even when they could share a page. An example is the direct I/O interface - +iov_iter_get_pages_alloc may return one segment with a partial page filled +and the next segment (which is adjacent in the file position) starts with a +new page. + +Reported-by: Toralf Förster +Signed-off-by: Weston Andros Adamson +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/pagelist.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -833,6 +833,14 @@ static bool nfs_can_coalesce_requests(st + return false; + if (req_offset(req) != req_offset(prev) + prev->wb_bytes) + return false; ++ if (req->wb_page == prev->wb_page) { ++ if (req->wb_pgbase != prev->wb_pgbase + prev->wb_bytes) ++ return false; ++ } else { ++ if (req->wb_pgbase != 0 || ++ prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE) ++ return false; ++ } + } + size = pgio->pg_ops->pg_test(pgio, prev, req); + WARN_ON_ONCE(size > req->wb_bytes); diff --git a/queue-3.16/nfs-change-nfs_page_group_lock-argument.patch b/queue-3.16/nfs-change-nfs_page_group_lock-argument.patch new file mode 100644 index 00000000000..9a6c7394b3f --- /dev/null +++ b/queue-3.16/nfs-change-nfs_page_group_lock-argument.patch @@ -0,0 +1,99 @@ +From trond.myklebust@primarydata.com Thu Oct 2 16:49:24 2014 +From: Trond Myklebust +Date: Mon, 15 Sep 2014 14:14:39 -0400 +Subject: nfs: change nfs_page_group_lock argument +To: stable@vger.kernel.org +Cc: Weston Andros Adamson , linux-nfs@vger.kernel.org +Message-ID: <1410804885-17228-9-git-send-email-trond.myklebust@primarydata.com> + + +From: Weston Andros Adamson + +commit fd2f3a06d30c85a17cf035ebc60c88c2a13a8ece upstream. + +Flip the meaning of the second argument from 'wait' to 'nonblock' to +match related functions. Update all five calls to reflect this change. + +Signed-off-by: Weston Andros Adamson +Reviewed-by: Peng Tao +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/pagelist.c | 11 ++++++----- + fs/nfs/write.c | 4 ++-- + 2 files changed, 8 insertions(+), 7 deletions(-) + +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -145,13 +145,14 @@ static int nfs_wait_bit_uninterruptible( + /* + * nfs_page_group_lock - lock the head of the page group + * @req - request in group that is to be locked ++ * @nonblock - if true don't block waiting for lock + * + * this lock must be held if modifying the page group list + * + * returns result from wait_on_bit_lock: 0 on success, < 0 on error + */ + int +-nfs_page_group_lock(struct nfs_page *req, bool wait) ++nfs_page_group_lock(struct nfs_page *req, bool nonblock) + { + struct nfs_page *head = req->wb_head; + int ret; +@@ -162,7 +163,7 @@ nfs_page_group_lock(struct nfs_page *req + ret = wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK, + nfs_wait_bit_uninterruptible, + TASK_UNINTERRUPTIBLE); +- } while (wait && ret != 0); ++ } while (!nonblock && ret != 0); + + WARN_ON_ONCE(ret > 0); + return ret; +@@ -226,7 +227,7 @@ bool nfs_page_group_sync_on_bit(struct n + { + bool ret; + +- nfs_page_group_lock(req, true); ++ nfs_page_group_lock(req, false); + ret = nfs_page_group_sync_on_bit_locked(req, bit); + nfs_page_group_unlock(req); + +@@ -869,7 +870,7 @@ static int __nfs_pageio_add_request(stru + unsigned int offset, pgbase; + int ret; + +- ret = nfs_page_group_lock(req, false); ++ ret = nfs_page_group_lock(req, true); + if (ret < 0) { + desc->pg_error = ret; + return 0; +@@ -895,7 +896,7 @@ static int __nfs_pageio_add_request(stru + if (desc->pg_recoalesce) + return 0; + /* retry add_request for this subreq */ +- ret = nfs_page_group_lock(req, false); ++ ret = nfs_page_group_lock(req, true); + if (ret < 0) { + desc->pg_error = ret; + return 0; +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -216,7 +216,7 @@ static bool nfs_page_group_covers_page(s + unsigned int pos = 0; + unsigned int len = nfs_page_length(req->wb_page); + +- nfs_page_group_lock(req, true); ++ nfs_page_group_lock(req, false); + + do { + tmp = nfs_page_group_search_locked(req->wb_head, pos); +@@ -454,7 +454,7 @@ try_again: + } + + /* lock each request in the page group */ +- ret = nfs_page_group_lock(head, false); ++ ret = nfs_page_group_lock(head, true); + if (ret < 0) + return ERR_PTR(ret); + subreq = head; diff --git a/queue-3.16/nfs-check-wait_on_bit_lock-err-in-page_group_lock.patch b/queue-3.16/nfs-check-wait_on_bit_lock-err-in-page_group_lock.patch new file mode 100644 index 00000000000..7d67e5164bf --- /dev/null +++ b/queue-3.16/nfs-check-wait_on_bit_lock-err-in-page_group_lock.patch @@ -0,0 +1,129 @@ +From trond.myklebust@primarydata.com Thu Oct 2 16:48:54 2014 +From: Trond Myklebust +Date: Mon, 15 Sep 2014 14:14:36 -0400 +Subject: nfs: check wait_on_bit_lock err in page_group_lock +To: stable@vger.kernel.org +Cc: Weston Andros Adamson , linux-nfs@vger.kernel.org +Message-ID: <1410804885-17228-6-git-send-email-trond.myklebust@primarydata.com> + + +From: Weston Andros Adamson + +commit e7029206ff43f6cf7d6fcb741adb126f47200516 upstream. + +Return errors from wait_on_bit_lock from nfs_page_group_lock. + +Add a bool argument @wait to nfs_page_group_lock. If true, loop over +wait_on_bit_lock until it returns cleanly. If false, return the error +from wait_on_bit_lock. + +Signed-off-by: Weston Andros Adamson +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/pagelist.c | 29 +++++++++++++++++++++++------ + fs/nfs/write.c | 6 ++++-- + include/linux/nfs_page.h | 2 +- + 3 files changed, 28 insertions(+), 9 deletions(-) + +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -147,17 +147,25 @@ static int nfs_wait_bit_uninterruptible( + * @req - request in group that is to be locked + * + * this lock must be held if modifying the page group list ++ * ++ * returns result from wait_on_bit_lock: 0 on success, < 0 on error + */ +-void +-nfs_page_group_lock(struct nfs_page *req) ++int ++nfs_page_group_lock(struct nfs_page *req, bool wait) + { + struct nfs_page *head = req->wb_head; ++ int ret; + + WARN_ON_ONCE(head != head->wb_head); + +- wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK, ++ do { ++ ret = wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK, + nfs_wait_bit_uninterruptible, + TASK_UNINTERRUPTIBLE); ++ } while (wait && ret != 0); ++ ++ WARN_ON_ONCE(ret > 0); ++ return ret; + } + + /* +@@ -218,7 +226,7 @@ bool nfs_page_group_sync_on_bit(struct n + { + bool ret; + +- nfs_page_group_lock(req); ++ nfs_page_group_lock(req, true); + ret = nfs_page_group_sync_on_bit_locked(req, bit); + nfs_page_group_unlock(req); + +@@ -859,8 +867,13 @@ static int __nfs_pageio_add_request(stru + struct nfs_page *subreq; + unsigned int bytes_left = 0; + unsigned int offset, pgbase; ++ int ret; + +- nfs_page_group_lock(req); ++ ret = nfs_page_group_lock(req, false); ++ if (ret < 0) { ++ desc->pg_error = ret; ++ return 0; ++ } + + subreq = req; + bytes_left = subreq->wb_bytes; +@@ -882,7 +895,11 @@ static int __nfs_pageio_add_request(stru + if (desc->pg_recoalesce) + return 0; + /* retry add_request for this subreq */ +- nfs_page_group_lock(req); ++ ret = nfs_page_group_lock(req, false); ++ if (ret < 0) { ++ desc->pg_error = ret; ++ return 0; ++ } + continue; + } + +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -216,7 +216,7 @@ static bool nfs_page_group_covers_page(s + unsigned int pos = 0; + unsigned int len = nfs_page_length(req->wb_page); + +- nfs_page_group_lock(req); ++ nfs_page_group_lock(req, true); + + do { + tmp = nfs_page_group_search_locked(req->wb_head, pos); +@@ -456,7 +456,9 @@ try_again: + } + + /* lock each request in the page group */ +- nfs_page_group_lock(head); ++ ret = nfs_page_group_lock(head, false); ++ if (ret < 0) ++ return ERR_PTR(ret); + subreq = head; + do { + /* +--- a/include/linux/nfs_page.h ++++ b/include/linux/nfs_page.h +@@ -120,7 +120,7 @@ extern size_t nfs_generic_pg_test(struct + extern int nfs_wait_on_request(struct nfs_page *); + extern void nfs_unlock_request(struct nfs_page *req); + extern void nfs_unlock_and_release_request(struct nfs_page *); +-extern void nfs_page_group_lock(struct nfs_page *); ++extern int nfs_page_group_lock(struct nfs_page *, bool); + extern void nfs_page_group_unlock(struct nfs_page *); + extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int); + diff --git a/queue-3.16/nfs-clear_request_commit-while-holding-i_lock.patch b/queue-3.16/nfs-clear_request_commit-while-holding-i_lock.patch new file mode 100644 index 00000000000..78986e4ae8a --- /dev/null +++ b/queue-3.16/nfs-clear_request_commit-while-holding-i_lock.patch @@ -0,0 +1,115 @@ +From trond.myklebust@primarydata.com Thu Oct 2 16:49:13 2014 +From: Trond Myklebust +Date: Mon, 15 Sep 2014 14:14:38 -0400 +Subject: nfs: clear_request_commit while holding i_lock +To: stable@vger.kernel.org +Cc: Weston Andros Adamson , linux-nfs@vger.kernel.org +Message-ID: <1410804885-17228-8-git-send-email-trond.myklebust@primarydata.com> + + +From: Weston Andros Adamson + +commit 411a99adffb4f993eee29759f744de01487044ac upstream. + +Signed-off-by: Weston Andros Adamson +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/filelayout/filelayout.c | 5 ++--- + fs/nfs/write.c | 15 ++++----------- + 2 files changed, 6 insertions(+), 14 deletions(-) + +--- a/fs/nfs/filelayout/filelayout.c ++++ b/fs/nfs/filelayout/filelayout.c +@@ -1015,6 +1015,7 @@ static u32 select_bucket_index(struct nf + + /* The generic layer is about to remove the req from the commit list. + * If this will make the bucket empty, it will need to put the lseg reference. ++ * Note this is must be called holding the inode (/cinfo) lock + */ + static void + filelayout_clear_request_commit(struct nfs_page *req, +@@ -1022,7 +1023,6 @@ filelayout_clear_request_commit(struct n + { + struct pnfs_layout_segment *freeme = NULL; + +- spin_lock(cinfo->lock); + if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags)) + goto out; + cinfo->ds->nwritten--; +@@ -1037,8 +1037,7 @@ filelayout_clear_request_commit(struct n + } + out: + nfs_request_remove_commit_list(req, cinfo); +- spin_unlock(cinfo->lock); +- pnfs_put_lseg(freeme); ++ pnfs_put_lseg_async(freeme); + } + + static struct list_head * +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -379,8 +379,6 @@ nfs_destroy_unlinked_subrequests(struct + subreq->wb_head = subreq; + subreq->wb_this_page = subreq; + +- nfs_clear_request_commit(subreq); +- + /* subreq is now totally disconnected from page group or any + * write / commit lists. last chance to wake any waiters */ + nfs_unlock_request(subreq); +@@ -490,7 +488,7 @@ try_again: + * Commit list removal accounting is done after locks are dropped */ + subreq = head; + do { +- nfs_list_remove_request(subreq); ++ nfs_clear_request_commit(subreq); + subreq = subreq->wb_this_page; + } while (subreq != head); + +@@ -520,15 +518,11 @@ try_again: + + nfs_page_group_unlock(head); + +- /* drop lock to clear_request_commit the head req and clean up +- * requests on destroy list */ ++ /* drop lock to clean uprequests on destroy list */ + spin_unlock(&inode->i_lock); + + nfs_destroy_unlinked_subrequests(destroy_list, head); + +- /* clean up commit list state */ +- nfs_clear_request_commit(head); +- + /* still holds ref on head from nfs_page_find_head_request_locked + * and still has lock on head from lock loop */ + return head; +@@ -810,6 +804,7 @@ nfs_clear_page_commit(struct page *page) + dec_bdi_stat(page_file_mapping(page)->backing_dev_info, BDI_RECLAIMABLE); + } + ++/* Called holding inode (/cinfo) lock */ + static void + nfs_clear_request_commit(struct nfs_page *req) + { +@@ -819,9 +814,7 @@ nfs_clear_request_commit(struct nfs_page + + nfs_init_cinfo_from_inode(&cinfo, inode); + if (!pnfs_clear_request_commit(req, &cinfo)) { +- spin_lock(cinfo.lock); + nfs_request_remove_commit_list(req, &cinfo); +- spin_unlock(cinfo.lock); + } + nfs_clear_page_commit(req->wb_page); + } +@@ -1040,9 +1033,9 @@ static struct nfs_page *nfs_try_to_updat + else + req->wb_bytes = rqend - req->wb_offset; + out_unlock: +- spin_unlock(&inode->i_lock); + if (req) + nfs_clear_request_commit(req); ++ spin_unlock(&inode->i_lock); + return req; + out_flushme: + spin_unlock(&inode->i_lock); diff --git a/queue-3.16/nfs-disallow-duplicate-pages-in-pgio-page-vectors.patch b/queue-3.16/nfs-disallow-duplicate-pages-in-pgio-page-vectors.patch new file mode 100644 index 00000000000..cdb82ae83c1 --- /dev/null +++ b/queue-3.16/nfs-disallow-duplicate-pages-in-pgio-page-vectors.patch @@ -0,0 +1,74 @@ +From trond.myklebust@primarydata.com Thu Oct 2 16:50:02 2014 +From: Trond Myklebust +Date: Mon, 15 Sep 2014 14:14:44 -0400 +Subject: nfs: disallow duplicate pages in pgio page vectors +To: stable@vger.kernel.org +Cc: Weston Andros Adamson , linux-nfs@vger.kernel.org +Message-ID: <1410804885-17228-14-git-send-email-trond.myklebust@primarydata.com> + + +From: Weston Andros Adamson + +commit bba5c1887a925a9945d22217d38d58d8b3ba1043 upstream. + +Adjacent requests that share the same page are allowed, but should only +use one entry in the page vector. This avoids overruning the page +vector - it is sized based on how many bytes there are, not by +request count. + +This fixes issues that manifest as "Redzone overwritten" bugs (the +vector overrun) and hangs waiting on page read / write, as it waits on +the same page more than once. + +This also adds bounds checking to the page vector with a graceful failure +(WARN_ON_ONCE and pgio error returned to application). + +Reported-by: Toralf Förster +Signed-off-by: Weston Andros Adamson +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/pagelist.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -734,10 +734,11 @@ int nfs_generic_pgio(struct nfs_pageio_d + struct nfs_pgio_header *hdr) + { + struct nfs_page *req; +- struct page **pages; ++ struct page **pages, ++ *last_page; + struct list_head *head = &desc->pg_list; + struct nfs_commit_info cinfo; +- unsigned int pagecount; ++ unsigned int pagecount, pageused; + + pagecount = nfs_page_array_len(desc->pg_base, desc->pg_count); + if (!nfs_pgarray_set(&hdr->page_array, pagecount)) +@@ -745,12 +746,23 @@ int nfs_generic_pgio(struct nfs_pageio_d + + nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq); + pages = hdr->page_array.pagevec; ++ last_page = NULL; ++ pageused = 0; + while (!list_empty(head)) { + req = nfs_list_entry(head->next); + nfs_list_remove_request(req); + nfs_list_add_request(req, &hdr->pages); +- *pages++ = req->wb_page; ++ ++ if (WARN_ON_ONCE(pageused >= pagecount)) ++ return nfs_pgio_error(desc, hdr); ++ ++ if (!last_page || last_page != req->wb_page) { ++ *pages++ = last_page = req->wb_page; ++ pageused++; ++ } + } ++ if (WARN_ON_ONCE(pageused != pagecount)) ++ return nfs_pgio_error(desc, hdr); + + if ((desc->pg_ioflags & FLUSH_COND_STABLE) && + (desc->pg_moreio || nfs_reqs_to_commit(&cinfo))) diff --git a/queue-3.16/nfs-don-t-sleep-with-inode-lock-in-lock_and_join_requests.patch b/queue-3.16/nfs-don-t-sleep-with-inode-lock-in-lock_and_join_requests.patch new file mode 100644 index 00000000000..1836fdcf62a --- /dev/null +++ b/queue-3.16/nfs-don-t-sleep-with-inode-lock-in-lock_and_join_requests.patch @@ -0,0 +1,94 @@ +From trond.myklebust@primarydata.com Thu Oct 2 16:49:54 2014 +From: Trond Myklebust +Date: Mon, 15 Sep 2014 14:14:43 -0400 +Subject: nfs: don't sleep with inode lock in lock_and_join_requests +To: stable@vger.kernel.org +Cc: Weston Andros Adamson , linux-nfs@vger.kernel.org +Message-ID: <1410804885-17228-13-git-send-email-trond.myklebust@primarydata.com> + + +From: Weston Andros Adamson + +commit 7c3af975257383ece54b83c0505d3e0656cb7daf upstream. + +This handles the 'nonblock=false' case in nfs_lock_and_join_requests. +If the group is already locked and blocking is allowed, drop the inode lock +and wait for the group lock to be cleared before trying it all again. +This should fix warnings found in peterz's tree (sched/wait branch), where +might_sleep() checks are added to wait.[ch]. + +Reported-by: Fengguang Wu +Signed-off-by: Weston Andros Adamson +Reviewed-by: Peng Tao +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/pagelist.c | 18 ++++++++++++++++++ + fs/nfs/write.c | 12 +++++++++++- + include/linux/nfs_page.h | 1 + + 3 files changed, 30 insertions(+), 1 deletion(-) + +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -175,6 +175,24 @@ nfs_page_group_lock(struct nfs_page *req + } + + /* ++ * nfs_page_group_lock_wait - wait for the lock to clear, but don't grab it ++ * @req - a request in the group ++ * ++ * This is a blocking call to wait for the group lock to be cleared. ++ */ ++void ++nfs_page_group_lock_wait(struct nfs_page *req) ++{ ++ struct nfs_page *head = req->wb_head; ++ ++ WARN_ON_ONCE(head != head->wb_head); ++ ++ wait_on_bit(&head->wb_flags, PG_HEADLOCK, ++ nfs_wait_bit_uninterruptible, ++ TASK_UNINTERRUPTIBLE); ++} ++ ++/* + * nfs_page_group_unlock - unlock the head of the page group + * @req - request in group that is to be unlocked + */ +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -453,13 +453,23 @@ try_again: + return NULL; + } + +- /* lock each request in the page group */ ++ /* holding inode lock, so always make a non-blocking call to try the ++ * page group lock */ + ret = nfs_page_group_lock(head, true); + if (ret < 0) { + spin_unlock(&inode->i_lock); ++ ++ if (!nonblock && ret == -EAGAIN) { ++ nfs_page_group_lock_wait(head); ++ nfs_release_request(head); ++ goto try_again; ++ } ++ + nfs_release_request(head); + return ERR_PTR(ret); + } ++ ++ /* lock each request in the page group */ + subreq = head; + do { + /* +--- a/include/linux/nfs_page.h ++++ b/include/linux/nfs_page.h +@@ -121,6 +121,7 @@ extern int nfs_wait_on_request(struct n + extern void nfs_unlock_request(struct nfs_page *req); + extern void nfs_unlock_and_release_request(struct nfs_page *); + extern int nfs_page_group_lock(struct nfs_page *, bool); ++extern void nfs_page_group_lock_wait(struct nfs_page *); + extern void nfs_page_group_unlock(struct nfs_page *); + extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int); + diff --git a/queue-3.16/nfs-fix-error-handling-in-lock_and_join_requests.patch b/queue-3.16/nfs-fix-error-handling-in-lock_and_join_requests.patch new file mode 100644 index 00000000000..a2c81d3992f --- /dev/null +++ b/queue-3.16/nfs-fix-error-handling-in-lock_and_join_requests.patch @@ -0,0 +1,41 @@ +From trond.myklebust@primarydata.com Thu Oct 2 16:49:47 2014 +From: Trond Myklebust +Date: Mon, 15 Sep 2014 14:14:42 -0400 +Subject: nfs: fix error handling in lock_and_join_requests +To: stable@vger.kernel.org +Cc: Weston Andros Adamson , linux-nfs@vger.kernel.org +Message-ID: <1410804885-17228-12-git-send-email-trond.myklebust@primarydata.com> + + +From: Weston Andros Adamson + +commit 94970014c46223cbcdfbfc67b89596a412f9e3dd upstream. + +This fixes handling of errors from nfs_page_group_lock in +nfs_lock_and_join_requests. It now releases the inode lock and the +reference to the head request. + +Reported-by: Peng Tao +Signed-off-by: Weston Andros Adamson +Reviewed-by: Peng Tao +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/write.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -455,8 +455,11 @@ try_again: + + /* lock each request in the page group */ + ret = nfs_page_group_lock(head, true); +- if (ret < 0) ++ if (ret < 0) { ++ spin_unlock(&inode->i_lock); ++ nfs_release_request(head); + return ERR_PTR(ret); ++ } + subreq = head; + do { + /* diff --git a/queue-3.16/nfs-fix-nonblocking-calls-to-nfs_page_group_lock.patch b/queue-3.16/nfs-fix-nonblocking-calls-to-nfs_page_group_lock.patch new file mode 100644 index 00000000000..a0cb548502e --- /dev/null +++ b/queue-3.16/nfs-fix-nonblocking-calls-to-nfs_page_group_lock.patch @@ -0,0 +1,67 @@ +From trond.myklebust@primarydata.com Thu Oct 2 16:49:33 2014 +From: Trond Myklebust +Date: Mon, 15 Sep 2014 14:14:40 -0400 +Subject: nfs: fix nonblocking calls to nfs_page_group_lock +To: stable@vger.kernel.org +Cc: Weston Andros Adamson , linux-nfs@vger.kernel.org +Message-ID: <1410804885-17228-10-git-send-email-trond.myklebust@primarydata.com> + + +From: Weston Andros Adamson + +commit bc8a309e88a86205fc3e17f06e42a2e56fc6f807 upstream. + +nfs_page_group_lock was calling wait_on_bit_lock even when told not to +block. Fix by first trying test_and_set_bit, followed by wait_on_bit_lock +if and only if blocking is allowed. Return -EAGAIN if nonblocking and the +test_and_set of the bit was already locked. + +Signed-off-by: Weston Andros Adamson +Reviewed-by: Peng Tao +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/pagelist.c | 23 ++++++++++++++--------- + 1 file changed, 14 insertions(+), 9 deletions(-) + +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -149,24 +149,29 @@ static int nfs_wait_bit_uninterruptible( + * + * this lock must be held if modifying the page group list + * +- * returns result from wait_on_bit_lock: 0 on success, < 0 on error ++ * return 0 on success, < 0 on error: -EDELAY if nonblocking or the ++ * result from wait_on_bit_lock ++ * ++ * NOTE: calling with nonblock=false should always have set the ++ * lock bit (see fs/buffer.c and other uses of wait_on_bit_lock ++ * with TASK_UNINTERRUPTIBLE), so there is no need to check the result. + */ + int + nfs_page_group_lock(struct nfs_page *req, bool nonblock) + { + struct nfs_page *head = req->wb_head; +- int ret; + + WARN_ON_ONCE(head != head->wb_head); + +- do { +- ret = wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK, +- nfs_wait_bit_uninterruptible, +- TASK_UNINTERRUPTIBLE); +- } while (!nonblock && ret != 0); ++ if (!test_and_set_bit(PG_HEADLOCK, &head->wb_flags)) ++ return 0; ++ ++ if (!nonblock) ++ return wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK, ++ nfs_wait_bit_uninterruptible, ++ TASK_UNINTERRUPTIBLE); + +- WARN_ON_ONCE(ret > 0); +- return ret; ++ return -EAGAIN; + } + + /* diff --git a/queue-3.16/nfs-merge-nfs_pgio_data-into-_header.patch b/queue-3.16/nfs-merge-nfs_pgio_data-into-_header.patch new file mode 100644 index 00000000000..c0344dcafca --- /dev/null +++ b/queue-3.16/nfs-merge-nfs_pgio_data-into-_header.patch @@ -0,0 +1,2234 @@ +From trond.myklebust@primarydata.com Thu Oct 2 16:46:47 2014 +From: Trond Myklebust +Date: Mon, 15 Sep 2014 14:14:34 -0400 +Subject: nfs: merge nfs_pgio_data into _header +To: stable@vger.kernel.org +Cc: Weston Andros Adamson , linux-nfs@vger.kernel.org +Message-ID: <1410804885-17228-4-git-send-email-trond.myklebust@primarydata.com> + + +From: Weston Andros Adamson + +commit d45f60c67848b9f19160692581d78e5b4757a000 upstream. + +struct nfs_pgio_data only exists as a member of nfs_pgio_header, but is +passed around everywhere, because there used to be multiple _data structs +per _header. Many of these functions then use the _data to find a pointer +to the _header. This patch cleans this up by merging the nfs_pgio_data +structure into nfs_pgio_header and passing nfs_pgio_header around instead. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Weston Andros Adamson +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/blocklayout/blocklayout.c | 98 ++++++++++------------ + fs/nfs/direct.c | 8 - + fs/nfs/filelayout/filelayout.c | 170 ++++++++++++++++++--------------------- + fs/nfs/internal.h | 6 - + fs/nfs/nfs3proc.c | 21 ++-- + fs/nfs/nfs4_fs.h | 6 - + fs/nfs/nfs4proc.c | 105 ++++++++++++------------ + fs/nfs/nfs4trace.h | 28 +++--- + fs/nfs/objlayout/objio_osd.c | 24 ++--- + fs/nfs/objlayout/objlayout.c | 81 ++++++++---------- + fs/nfs/objlayout/objlayout.h | 8 - + fs/nfs/pagelist.c | 120 +++++++++++++-------------- + fs/nfs/pnfs.c | 80 +++++++----------- + fs/nfs/pnfs.h | 10 +- + fs/nfs/proc.c | 27 +++--- + fs/nfs/read.c | 42 +++++---- + fs/nfs/write.c | 56 ++++++------ + include/linux/nfs_page.h | 9 +- + include/linux/nfs_xdr.h | 43 ++++----- + 19 files changed, 460 insertions(+), 482 deletions(-) + +--- a/fs/nfs/blocklayout/blocklayout.c ++++ b/fs/nfs/blocklayout/blocklayout.c +@@ -210,8 +210,7 @@ static void bl_end_io_read(struct bio *b + SetPageUptodate(bvec->bv_page); + + if (err) { +- struct nfs_pgio_data *rdata = par->data; +- struct nfs_pgio_header *header = rdata->header; ++ struct nfs_pgio_header *header = par->data; + + if (!header->pnfs_error) + header->pnfs_error = -EIO; +@@ -224,44 +223,44 @@ static void bl_end_io_read(struct bio *b + static void bl_read_cleanup(struct work_struct *work) + { + struct rpc_task *task; +- struct nfs_pgio_data *rdata; ++ struct nfs_pgio_header *hdr; + dprintk("%s enter\n", __func__); + task = container_of(work, struct rpc_task, u.tk_work); +- rdata = container_of(task, struct nfs_pgio_data, task); +- pnfs_ld_read_done(rdata); ++ hdr = container_of(task, struct nfs_pgio_header, task); ++ pnfs_ld_read_done(hdr); + } + + static void + bl_end_par_io_read(void *data, int unused) + { +- struct nfs_pgio_data *rdata = data; ++ struct nfs_pgio_header *hdr = data; + +- rdata->task.tk_status = rdata->header->pnfs_error; +- INIT_WORK(&rdata->task.u.tk_work, bl_read_cleanup); +- schedule_work(&rdata->task.u.tk_work); ++ hdr->task.tk_status = hdr->pnfs_error; ++ INIT_WORK(&hdr->task.u.tk_work, bl_read_cleanup); ++ schedule_work(&hdr->task.u.tk_work); + } + + static enum pnfs_try_status +-bl_read_pagelist(struct nfs_pgio_data *rdata) ++bl_read_pagelist(struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *header = rdata->header; ++ struct nfs_pgio_header *header = hdr; + int i, hole; + struct bio *bio = NULL; + struct pnfs_block_extent *be = NULL, *cow_read = NULL; + sector_t isect, extent_length = 0; + struct parallel_io *par; +- loff_t f_offset = rdata->args.offset; +- size_t bytes_left = rdata->args.count; ++ loff_t f_offset = hdr->args.offset; ++ size_t bytes_left = hdr->args.count; + unsigned int pg_offset, pg_len; +- struct page **pages = rdata->args.pages; +- int pg_index = rdata->args.pgbase >> PAGE_CACHE_SHIFT; ++ struct page **pages = hdr->args.pages; ++ int pg_index = hdr->args.pgbase >> PAGE_CACHE_SHIFT; + const bool is_dio = (header->dreq != NULL); + + dprintk("%s enter nr_pages %u offset %lld count %u\n", __func__, +- rdata->page_array.npages, f_offset, +- (unsigned int)rdata->args.count); ++ hdr->page_array.npages, f_offset, ++ (unsigned int)hdr->args.count); + +- par = alloc_parallel(rdata); ++ par = alloc_parallel(hdr); + if (!par) + goto use_mds; + par->pnfs_callback = bl_end_par_io_read; +@@ -269,7 +268,7 @@ bl_read_pagelist(struct nfs_pgio_data *r + + isect = (sector_t) (f_offset >> SECTOR_SHIFT); + /* Code assumes extents are page-aligned */ +- for (i = pg_index; i < rdata->page_array.npages; i++) { ++ for (i = pg_index; i < hdr->page_array.npages; i++) { + if (!extent_length) { + /* We've used up the previous extent */ + bl_put_extent(be); +@@ -319,7 +318,7 @@ bl_read_pagelist(struct nfs_pgio_data *r + + be_read = (hole && cow_read) ? cow_read : be; + bio = do_add_page_to_bio(bio, +- rdata->page_array.npages - i, ++ hdr->page_array.npages - i, + READ, + isect, pages[i], be_read, + bl_end_io_read, par, +@@ -334,10 +333,10 @@ bl_read_pagelist(struct nfs_pgio_data *r + extent_length -= PAGE_CACHE_SECTORS; + } + if ((isect << SECTOR_SHIFT) >= header->inode->i_size) { +- rdata->res.eof = 1; +- rdata->res.count = header->inode->i_size - rdata->args.offset; ++ hdr->res.eof = 1; ++ hdr->res.count = header->inode->i_size - hdr->args.offset; + } else { +- rdata->res.count = (isect << SECTOR_SHIFT) - rdata->args.offset; ++ hdr->res.count = (isect << SECTOR_SHIFT) - hdr->args.offset; + } + out: + bl_put_extent(be); +@@ -392,8 +391,7 @@ static void bl_end_io_write_zero(struct + } + + if (unlikely(err)) { +- struct nfs_pgio_data *data = par->data; +- struct nfs_pgio_header *header = data->header; ++ struct nfs_pgio_header *header = par->data; + + if (!header->pnfs_error) + header->pnfs_error = -EIO; +@@ -407,8 +405,7 @@ static void bl_end_io_write(struct bio * + { + struct parallel_io *par = bio->bi_private; + const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); +- struct nfs_pgio_data *data = par->data; +- struct nfs_pgio_header *header = data->header; ++ struct nfs_pgio_header *header = par->data; + + if (!uptodate) { + if (!header->pnfs_error) +@@ -425,32 +422,32 @@ static void bl_end_io_write(struct bio * + static void bl_write_cleanup(struct work_struct *work) + { + struct rpc_task *task; +- struct nfs_pgio_data *wdata; ++ struct nfs_pgio_header *hdr; + dprintk("%s enter\n", __func__); + task = container_of(work, struct rpc_task, u.tk_work); +- wdata = container_of(task, struct nfs_pgio_data, task); +- if (likely(!wdata->header->pnfs_error)) { ++ hdr = container_of(task, struct nfs_pgio_header, task); ++ if (likely(!hdr->pnfs_error)) { + /* Marks for LAYOUTCOMMIT */ +- mark_extents_written(BLK_LSEG2EXT(wdata->header->lseg), +- wdata->args.offset, wdata->args.count); ++ mark_extents_written(BLK_LSEG2EXT(hdr->lseg), ++ hdr->args.offset, hdr->args.count); + } +- pnfs_ld_write_done(wdata); ++ pnfs_ld_write_done(hdr); + } + + /* Called when last of bios associated with a bl_write_pagelist call finishes */ + static void bl_end_par_io_write(void *data, int num_se) + { +- struct nfs_pgio_data *wdata = data; ++ struct nfs_pgio_header *hdr = data; + +- if (unlikely(wdata->header->pnfs_error)) { +- bl_free_short_extents(&BLK_LSEG2EXT(wdata->header->lseg)->bl_inval, ++ if (unlikely(hdr->pnfs_error)) { ++ bl_free_short_extents(&BLK_LSEG2EXT(hdr->lseg)->bl_inval, + num_se); + } + +- wdata->task.tk_status = wdata->header->pnfs_error; +- wdata->writeverf.committed = NFS_FILE_SYNC; +- INIT_WORK(&wdata->task.u.tk_work, bl_write_cleanup); +- schedule_work(&wdata->task.u.tk_work); ++ hdr->task.tk_status = hdr->pnfs_error; ++ hdr->writeverf.committed = NFS_FILE_SYNC; ++ INIT_WORK(&hdr->task.u.tk_work, bl_write_cleanup); ++ schedule_work(&hdr->task.u.tk_work); + } + + /* FIXME STUB - mark intersection of layout and page as bad, so is not +@@ -675,18 +672,17 @@ check_page: + } + + static enum pnfs_try_status +-bl_write_pagelist(struct nfs_pgio_data *wdata, int sync) ++bl_write_pagelist(struct nfs_pgio_header *header, int sync) + { +- struct nfs_pgio_header *header = wdata->header; + int i, ret, npg_zero, pg_index, last = 0; + struct bio *bio = NULL; + struct pnfs_block_extent *be = NULL, *cow_read = NULL; + sector_t isect, last_isect = 0, extent_length = 0; + struct parallel_io *par = NULL; +- loff_t offset = wdata->args.offset; +- size_t count = wdata->args.count; ++ loff_t offset = header->args.offset; ++ size_t count = header->args.count; + unsigned int pg_offset, pg_len, saved_len; +- struct page **pages = wdata->args.pages; ++ struct page **pages = header->args.pages; + struct page *page; + pgoff_t index; + u64 temp; +@@ -701,11 +697,11 @@ bl_write_pagelist(struct nfs_pgio_data * + dprintk("pnfsblock nonblock aligned DIO writes. Resend MDS\n"); + goto out_mds; + } +- /* At this point, wdata->page_aray is a (sequential) list of nfs_pages. ++ /* At this point, header->page_aray is a (sequential) list of nfs_pages. + * We want to write each, and if there is an error set pnfs_error + * to have it redone using nfs. + */ +- par = alloc_parallel(wdata); ++ par = alloc_parallel(header); + if (!par) + goto out_mds; + par->pnfs_callback = bl_end_par_io_write; +@@ -792,8 +788,8 @@ next_page: + bio = bl_submit_bio(WRITE, bio); + + /* Middle pages */ +- pg_index = wdata->args.pgbase >> PAGE_CACHE_SHIFT; +- for (i = pg_index; i < wdata->page_array.npages; i++) { ++ pg_index = header->args.pgbase >> PAGE_CACHE_SHIFT; ++ for (i = pg_index; i < header->page_array.npages; i++) { + if (!extent_length) { + /* We've used up the previous extent */ + bl_put_extent(be); +@@ -864,7 +860,7 @@ next_page: + } + + +- bio = do_add_page_to_bio(bio, wdata->page_array.npages - i, ++ bio = do_add_page_to_bio(bio, header->page_array.npages - i, + WRITE, + isect, pages[i], be, + bl_end_io_write, par, +@@ -893,7 +889,7 @@ next_page: + } + + write_done: +- wdata->res.count = wdata->args.count; ++ header->res.count = header->args.count; + out: + bl_put_extent(be); + bl_put_extent(cow_read); +--- a/fs/nfs/direct.c ++++ b/fs/nfs/direct.c +@@ -148,8 +148,8 @@ static void nfs_direct_set_hdr_verf(stru + { + struct nfs_writeverf *verfp; + +- verfp = nfs_direct_select_verf(dreq, hdr->data.ds_clp, +- hdr->data.ds_idx); ++ verfp = nfs_direct_select_verf(dreq, hdr->ds_clp, ++ hdr->ds_idx); + WARN_ON_ONCE(verfp->committed >= 0); + memcpy(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); + WARN_ON_ONCE(verfp->committed < 0); +@@ -169,8 +169,8 @@ static int nfs_direct_set_or_cmp_hdr_ver + { + struct nfs_writeverf *verfp; + +- verfp = nfs_direct_select_verf(dreq, hdr->data.ds_clp, +- hdr->data.ds_idx); ++ verfp = nfs_direct_select_verf(dreq, hdr->ds_clp, ++ hdr->ds_idx); + if (verfp->committed < 0) { + nfs_direct_set_hdr_verf(dreq, hdr); + return 0; +--- a/fs/nfs/filelayout/filelayout.c ++++ b/fs/nfs/filelayout/filelayout.c +@@ -84,19 +84,18 @@ filelayout_get_dserver_offset(struct pnf + BUG(); + } + +-static void filelayout_reset_write(struct nfs_pgio_data *data) ++static void filelayout_reset_write(struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = data->header; +- struct rpc_task *task = &data->task; ++ struct rpc_task *task = &hdr->task; + + if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { + dprintk("%s Reset task %5u for i/o through MDS " + "(req %s/%llu, %u bytes @ offset %llu)\n", __func__, +- data->task.tk_pid, ++ hdr->task.tk_pid, + hdr->inode->i_sb->s_id, + (unsigned long long)NFS_FILEID(hdr->inode), +- data->args.count, +- (unsigned long long)data->args.offset); ++ hdr->args.count, ++ (unsigned long long)hdr->args.offset); + + task->tk_status = pnfs_write_done_resend_to_mds(hdr->inode, + &hdr->pages, +@@ -105,19 +104,18 @@ static void filelayout_reset_write(struc + } + } + +-static void filelayout_reset_read(struct nfs_pgio_data *data) ++static void filelayout_reset_read(struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = data->header; +- struct rpc_task *task = &data->task; ++ struct rpc_task *task = &hdr->task; + + if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { + dprintk("%s Reset task %5u for i/o through MDS " + "(req %s/%llu, %u bytes @ offset %llu)\n", __func__, +- data->task.tk_pid, ++ hdr->task.tk_pid, + hdr->inode->i_sb->s_id, + (unsigned long long)NFS_FILEID(hdr->inode), +- data->args.count, +- (unsigned long long)data->args.offset); ++ hdr->args.count, ++ (unsigned long long)hdr->args.offset); + + task->tk_status = pnfs_read_done_resend_to_mds(hdr->inode, + &hdr->pages, +@@ -243,18 +241,17 @@ wait_on_recovery: + /* NFS_PROTO call done callback routines */ + + static int filelayout_read_done_cb(struct rpc_task *task, +- struct nfs_pgio_data *data) ++ struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = data->header; + int err; + +- trace_nfs4_pnfs_read(data, task->tk_status); +- err = filelayout_async_handle_error(task, data->args.context->state, +- data->ds_clp, hdr->lseg); ++ trace_nfs4_pnfs_read(hdr, task->tk_status); ++ err = filelayout_async_handle_error(task, hdr->args.context->state, ++ hdr->ds_clp, hdr->lseg); + + switch (err) { + case -NFS4ERR_RESET_TO_MDS: +- filelayout_reset_read(data); ++ filelayout_reset_read(hdr); + return task->tk_status; + case -EAGAIN: + rpc_restart_call_prepare(task); +@@ -270,15 +267,14 @@ static int filelayout_read_done_cb(struc + * rfc5661 is not clear about which credential should be used. + */ + static void +-filelayout_set_layoutcommit(struct nfs_pgio_data *wdata) ++filelayout_set_layoutcommit(struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = wdata->header; + + if (FILELAYOUT_LSEG(hdr->lseg)->commit_through_mds || +- wdata->res.verf->committed == NFS_FILE_SYNC) ++ hdr->res.verf->committed == NFS_FILE_SYNC) + return; + +- pnfs_set_layoutcommit(wdata); ++ pnfs_set_layoutcommit(hdr); + dprintk("%s inode %lu pls_end_pos %lu\n", __func__, hdr->inode->i_ino, + (unsigned long) NFS_I(hdr->inode)->layout->plh_lwb); + } +@@ -305,83 +301,82 @@ filelayout_reset_to_mds(struct pnfs_layo + */ + static void filelayout_read_prepare(struct rpc_task *task, void *data) + { +- struct nfs_pgio_data *rdata = data; ++ struct nfs_pgio_header *hdr = data; + +- if (unlikely(test_bit(NFS_CONTEXT_BAD, &rdata->args.context->flags))) { ++ if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) { + rpc_exit(task, -EIO); + return; + } +- if (filelayout_reset_to_mds(rdata->header->lseg)) { ++ if (filelayout_reset_to_mds(hdr->lseg)) { + dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid); +- filelayout_reset_read(rdata); ++ filelayout_reset_read(hdr); + rpc_exit(task, 0); + return; + } +- rdata->pgio_done_cb = filelayout_read_done_cb; ++ hdr->pgio_done_cb = filelayout_read_done_cb; + +- if (nfs41_setup_sequence(rdata->ds_clp->cl_session, +- &rdata->args.seq_args, +- &rdata->res.seq_res, ++ if (nfs41_setup_sequence(hdr->ds_clp->cl_session, ++ &hdr->args.seq_args, ++ &hdr->res.seq_res, + task)) + return; +- if (nfs4_set_rw_stateid(&rdata->args.stateid, rdata->args.context, +- rdata->args.lock_context, FMODE_READ) == -EIO) ++ if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context, ++ hdr->args.lock_context, FMODE_READ) == -EIO) + rpc_exit(task, -EIO); /* lost lock, terminate I/O */ + } + + static void filelayout_read_call_done(struct rpc_task *task, void *data) + { +- struct nfs_pgio_data *rdata = data; ++ struct nfs_pgio_header *hdr = data; + + dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status); + +- if (test_bit(NFS_IOHDR_REDO, &rdata->header->flags) && ++ if (test_bit(NFS_IOHDR_REDO, &hdr->flags) && + task->tk_status == 0) { +- nfs41_sequence_done(task, &rdata->res.seq_res); ++ nfs41_sequence_done(task, &hdr->res.seq_res); + return; + } + + /* Note this may cause RPC to be resent */ +- rdata->header->mds_ops->rpc_call_done(task, data); ++ hdr->mds_ops->rpc_call_done(task, data); + } + + static void filelayout_read_count_stats(struct rpc_task *task, void *data) + { +- struct nfs_pgio_data *rdata = data; ++ struct nfs_pgio_header *hdr = data; + +- rpc_count_iostats(task, NFS_SERVER(rdata->header->inode)->client->cl_metrics); ++ rpc_count_iostats(task, NFS_SERVER(hdr->inode)->client->cl_metrics); + } + + static void filelayout_read_release(void *data) + { +- struct nfs_pgio_data *rdata = data; +- struct pnfs_layout_hdr *lo = rdata->header->lseg->pls_layout; ++ struct nfs_pgio_header *hdr = data; ++ struct pnfs_layout_hdr *lo = hdr->lseg->pls_layout; + + filelayout_fenceme(lo->plh_inode, lo); +- nfs_put_client(rdata->ds_clp); +- rdata->header->mds_ops->rpc_release(data); ++ nfs_put_client(hdr->ds_clp); ++ hdr->mds_ops->rpc_release(data); + } + + static int filelayout_write_done_cb(struct rpc_task *task, +- struct nfs_pgio_data *data) ++ struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = data->header; + int err; + +- trace_nfs4_pnfs_write(data, task->tk_status); +- err = filelayout_async_handle_error(task, data->args.context->state, +- data->ds_clp, hdr->lseg); ++ trace_nfs4_pnfs_write(hdr, task->tk_status); ++ err = filelayout_async_handle_error(task, hdr->args.context->state, ++ hdr->ds_clp, hdr->lseg); + + switch (err) { + case -NFS4ERR_RESET_TO_MDS: +- filelayout_reset_write(data); ++ filelayout_reset_write(hdr); + return task->tk_status; + case -EAGAIN: + rpc_restart_call_prepare(task); + return -EAGAIN; + } + +- filelayout_set_layoutcommit(data); ++ filelayout_set_layoutcommit(hdr); + return 0; + } + +@@ -419,57 +414,57 @@ static int filelayout_commit_done_cb(str + + static void filelayout_write_prepare(struct rpc_task *task, void *data) + { +- struct nfs_pgio_data *wdata = data; ++ struct nfs_pgio_header *hdr = data; + +- if (unlikely(test_bit(NFS_CONTEXT_BAD, &wdata->args.context->flags))) { ++ if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) { + rpc_exit(task, -EIO); + return; + } +- if (filelayout_reset_to_mds(wdata->header->lseg)) { ++ if (filelayout_reset_to_mds(hdr->lseg)) { + dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid); +- filelayout_reset_write(wdata); ++ filelayout_reset_write(hdr); + rpc_exit(task, 0); + return; + } +- if (nfs41_setup_sequence(wdata->ds_clp->cl_session, +- &wdata->args.seq_args, +- &wdata->res.seq_res, ++ if (nfs41_setup_sequence(hdr->ds_clp->cl_session, ++ &hdr->args.seq_args, ++ &hdr->res.seq_res, + task)) + return; +- if (nfs4_set_rw_stateid(&wdata->args.stateid, wdata->args.context, +- wdata->args.lock_context, FMODE_WRITE) == -EIO) ++ if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context, ++ hdr->args.lock_context, FMODE_WRITE) == -EIO) + rpc_exit(task, -EIO); /* lost lock, terminate I/O */ + } + + static void filelayout_write_call_done(struct rpc_task *task, void *data) + { +- struct nfs_pgio_data *wdata = data; ++ struct nfs_pgio_header *hdr = data; + +- if (test_bit(NFS_IOHDR_REDO, &wdata->header->flags) && ++ if (test_bit(NFS_IOHDR_REDO, &hdr->flags) && + task->tk_status == 0) { +- nfs41_sequence_done(task, &wdata->res.seq_res); ++ nfs41_sequence_done(task, &hdr->res.seq_res); + return; + } + + /* Note this may cause RPC to be resent */ +- wdata->header->mds_ops->rpc_call_done(task, data); ++ hdr->mds_ops->rpc_call_done(task, data); + } + + static void filelayout_write_count_stats(struct rpc_task *task, void *data) + { +- struct nfs_pgio_data *wdata = data; ++ struct nfs_pgio_header *hdr = data; + +- rpc_count_iostats(task, NFS_SERVER(wdata->header->inode)->client->cl_metrics); ++ rpc_count_iostats(task, NFS_SERVER(hdr->inode)->client->cl_metrics); + } + + static void filelayout_write_release(void *data) + { +- struct nfs_pgio_data *wdata = data; +- struct pnfs_layout_hdr *lo = wdata->header->lseg->pls_layout; ++ struct nfs_pgio_header *hdr = data; ++ struct pnfs_layout_hdr *lo = hdr->lseg->pls_layout; + + filelayout_fenceme(lo->plh_inode, lo); +- nfs_put_client(wdata->ds_clp); +- wdata->header->mds_ops->rpc_release(data); ++ nfs_put_client(hdr->ds_clp); ++ hdr->mds_ops->rpc_release(data); + } + + static void filelayout_commit_prepare(struct rpc_task *task, void *data) +@@ -529,19 +524,18 @@ static const struct rpc_call_ops filelay + }; + + static enum pnfs_try_status +-filelayout_read_pagelist(struct nfs_pgio_data *data) ++filelayout_read_pagelist(struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = data->header; + struct pnfs_layout_segment *lseg = hdr->lseg; + struct nfs4_pnfs_ds *ds; + struct rpc_clnt *ds_clnt; +- loff_t offset = data->args.offset; ++ loff_t offset = hdr->args.offset; + u32 j, idx; + struct nfs_fh *fh; + + dprintk("--> %s ino %lu pgbase %u req %Zu@%llu\n", + __func__, hdr->inode->i_ino, +- data->args.pgbase, (size_t)data->args.count, offset); ++ hdr->args.pgbase, (size_t)hdr->args.count, offset); + + /* Retrieve the correct rpc_client for the byte range */ + j = nfs4_fl_calc_j_index(lseg, offset); +@@ -559,30 +553,29 @@ filelayout_read_pagelist(struct nfs_pgio + + /* No multipath support. Use first DS */ + atomic_inc(&ds->ds_clp->cl_count); +- data->ds_clp = ds->ds_clp; +- data->ds_idx = idx; ++ hdr->ds_clp = ds->ds_clp; ++ hdr->ds_idx = idx; + fh = nfs4_fl_select_ds_fh(lseg, j); + if (fh) +- data->args.fh = fh; ++ hdr->args.fh = fh; + +- data->args.offset = filelayout_get_dserver_offset(lseg, offset); +- data->mds_offset = offset; ++ hdr->args.offset = filelayout_get_dserver_offset(lseg, offset); ++ hdr->mds_offset = offset; + + /* Perform an asynchronous read to ds */ +- nfs_initiate_pgio(ds_clnt, data, ++ nfs_initiate_pgio(ds_clnt, hdr, + &filelayout_read_call_ops, 0, RPC_TASK_SOFTCONN); + return PNFS_ATTEMPTED; + } + + /* Perform async writes. */ + static enum pnfs_try_status +-filelayout_write_pagelist(struct nfs_pgio_data *data, int sync) ++filelayout_write_pagelist(struct nfs_pgio_header *hdr, int sync) + { +- struct nfs_pgio_header *hdr = data->header; + struct pnfs_layout_segment *lseg = hdr->lseg; + struct nfs4_pnfs_ds *ds; + struct rpc_clnt *ds_clnt; +- loff_t offset = data->args.offset; ++ loff_t offset = hdr->args.offset; + u32 j, idx; + struct nfs_fh *fh; + +@@ -598,21 +591,20 @@ filelayout_write_pagelist(struct nfs_pgi + return PNFS_NOT_ATTEMPTED; + + dprintk("%s ino %lu sync %d req %Zu@%llu DS: %s cl_count %d\n", +- __func__, hdr->inode->i_ino, sync, (size_t) data->args.count, ++ __func__, hdr->inode->i_ino, sync, (size_t) hdr->args.count, + offset, ds->ds_remotestr, atomic_read(&ds->ds_clp->cl_count)); + +- data->pgio_done_cb = filelayout_write_done_cb; ++ hdr->pgio_done_cb = filelayout_write_done_cb; + atomic_inc(&ds->ds_clp->cl_count); +- data->ds_clp = ds->ds_clp; +- data->ds_idx = idx; ++ hdr->ds_clp = ds->ds_clp; ++ hdr->ds_idx = idx; + fh = nfs4_fl_select_ds_fh(lseg, j); + if (fh) +- data->args.fh = fh; +- +- data->args.offset = filelayout_get_dserver_offset(lseg, offset); ++ hdr->args.fh = fh; ++ hdr->args.offset = filelayout_get_dserver_offset(lseg, offset); + + /* Perform an asynchronous write */ +- nfs_initiate_pgio(ds_clnt, data, ++ nfs_initiate_pgio(ds_clnt, hdr, + &filelayout_write_call_ops, sync, + RPC_TASK_SOFTCONN); + return PNFS_ATTEMPTED; +--- a/fs/nfs/internal.h ++++ b/fs/nfs/internal.h +@@ -240,9 +240,9 @@ int nfs_iocounter_wait(struct nfs_io_cou + extern const struct nfs_pageio_ops nfs_pgio_rw_ops; + struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *); + void nfs_pgio_header_free(struct nfs_pgio_header *); +-void nfs_pgio_data_destroy(struct nfs_pgio_data *); ++void nfs_pgio_data_destroy(struct nfs_pgio_header *); + int nfs_generic_pgio(struct nfs_pageio_descriptor *, struct nfs_pgio_header *); +-int nfs_initiate_pgio(struct rpc_clnt *, struct nfs_pgio_data *, ++int nfs_initiate_pgio(struct rpc_clnt *, struct nfs_pgio_header *, + const struct rpc_call_ops *, int, int); + void nfs_free_request(struct nfs_page *req); + +@@ -482,7 +482,7 @@ static inline void nfs_inode_dio_wait(st + extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq); + + /* nfs4proc.c */ +-extern void __nfs4_read_done_cb(struct nfs_pgio_data *); ++extern void __nfs4_read_done_cb(struct nfs_pgio_header *); + extern struct nfs_client *nfs4_init_client(struct nfs_client *clp, + const struct rpc_timeout *timeparms, + const char *ip_addr); +--- a/fs/nfs/nfs3proc.c ++++ b/fs/nfs/nfs3proc.c +@@ -795,41 +795,44 @@ nfs3_proc_pathconf(struct nfs_server *se + return status; + } + +-static int nfs3_read_done(struct rpc_task *task, struct nfs_pgio_data *data) ++static int nfs3_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr) + { +- struct inode *inode = data->header->inode; ++ struct inode *inode = hdr->inode; + + if (nfs3_async_handle_jukebox(task, inode)) + return -EAGAIN; + + nfs_invalidate_atime(inode); +- nfs_refresh_inode(inode, &data->fattr); ++ nfs_refresh_inode(inode, &hdr->fattr); + return 0; + } + +-static void nfs3_proc_read_setup(struct nfs_pgio_data *data, struct rpc_message *msg) ++static void nfs3_proc_read_setup(struct nfs_pgio_header *hdr, ++ struct rpc_message *msg) + { + msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ]; + } + +-static int nfs3_proc_pgio_rpc_prepare(struct rpc_task *task, struct nfs_pgio_data *data) ++static int nfs3_proc_pgio_rpc_prepare(struct rpc_task *task, ++ struct nfs_pgio_header *hdr) + { + rpc_call_start(task); + return 0; + } + +-static int nfs3_write_done(struct rpc_task *task, struct nfs_pgio_data *data) ++static int nfs3_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr) + { +- struct inode *inode = data->header->inode; ++ struct inode *inode = hdr->inode; + + if (nfs3_async_handle_jukebox(task, inode)) + return -EAGAIN; + if (task->tk_status >= 0) +- nfs_post_op_update_inode_force_wcc(inode, data->res.fattr); ++ nfs_post_op_update_inode_force_wcc(inode, hdr->res.fattr); + return 0; + } + +-static void nfs3_proc_write_setup(struct nfs_pgio_data *data, struct rpc_message *msg) ++static void nfs3_proc_write_setup(struct nfs_pgio_header *hdr, ++ struct rpc_message *msg) + { + msg->rpc_proc = &nfs3_procedures[NFS3PROC_WRITE]; + } +--- a/fs/nfs/nfs4_fs.h ++++ b/fs/nfs/nfs4_fs.h +@@ -337,11 +337,11 @@ nfs4_state_protect(struct nfs_client *cl + */ + static inline void + nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp, +- struct rpc_message *msg, struct nfs_pgio_data *wdata) ++ struct rpc_message *msg, struct nfs_pgio_header *hdr) + { + if (_nfs4_state_protect(clp, NFS_SP4_MACH_CRED_WRITE, clntp, msg) && + !test_bit(NFS_SP4_MACH_CRED_COMMIT, &clp->cl_sp4_flags)) +- wdata->args.stable = NFS_FILE_SYNC; ++ hdr->args.stable = NFS_FILE_SYNC; + } + #else /* CONFIG_NFS_v4_1 */ + static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server) +@@ -369,7 +369,7 @@ nfs4_state_protect(struct nfs_client *cl + + static inline void + nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp, +- struct rpc_message *msg, struct nfs_pgio_data *wdata) ++ struct rpc_message *msg, struct nfs_pgio_header *hdr) + { + } + #endif /* CONFIG_NFS_V4_1 */ +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -4041,24 +4041,25 @@ static bool nfs4_error_stateid_expired(i + return false; + } + +-void __nfs4_read_done_cb(struct nfs_pgio_data *data) ++void __nfs4_read_done_cb(struct nfs_pgio_header *hdr) + { +- nfs_invalidate_atime(data->header->inode); ++ nfs_invalidate_atime(hdr->inode); + } + +-static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_pgio_data *data) ++static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_pgio_header *hdr) + { +- struct nfs_server *server = NFS_SERVER(data->header->inode); ++ struct nfs_server *server = NFS_SERVER(hdr->inode); + +- trace_nfs4_read(data, task->tk_status); +- if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { ++ trace_nfs4_read(hdr, task->tk_status); ++ if (nfs4_async_handle_error(task, server, ++ hdr->args.context->state) == -EAGAIN) { + rpc_restart_call_prepare(task); + return -EAGAIN; + } + +- __nfs4_read_done_cb(data); ++ __nfs4_read_done_cb(hdr); + if (task->tk_status > 0) +- renew_lease(server, data->timestamp); ++ renew_lease(server, hdr->timestamp); + return 0; + } + +@@ -4076,54 +4077,59 @@ static bool nfs4_read_stateid_changed(st + return true; + } + +-static int nfs4_read_done(struct rpc_task *task, struct nfs_pgio_data *data) ++static int nfs4_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr) + { + + dprintk("--> %s\n", __func__); + +- if (!nfs4_sequence_done(task, &data->res.seq_res)) ++ if (!nfs4_sequence_done(task, &hdr->res.seq_res)) + return -EAGAIN; +- if (nfs4_read_stateid_changed(task, &data->args)) ++ if (nfs4_read_stateid_changed(task, &hdr->args)) + return -EAGAIN; +- return data->pgio_done_cb ? data->pgio_done_cb(task, data) : +- nfs4_read_done_cb(task, data); ++ return hdr->pgio_done_cb ? hdr->pgio_done_cb(task, hdr) : ++ nfs4_read_done_cb(task, hdr); + } + +-static void nfs4_proc_read_setup(struct nfs_pgio_data *data, struct rpc_message *msg) ++static void nfs4_proc_read_setup(struct nfs_pgio_header *hdr, ++ struct rpc_message *msg) + { +- data->timestamp = jiffies; +- data->pgio_done_cb = nfs4_read_done_cb; ++ hdr->timestamp = jiffies; ++ hdr->pgio_done_cb = nfs4_read_done_cb; + msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ]; +- nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0); ++ nfs4_init_sequence(&hdr->args.seq_args, &hdr->res.seq_res, 0); + } + +-static int nfs4_proc_pgio_rpc_prepare(struct rpc_task *task, struct nfs_pgio_data *data) ++static int nfs4_proc_pgio_rpc_prepare(struct rpc_task *task, ++ struct nfs_pgio_header *hdr) + { +- if (nfs4_setup_sequence(NFS_SERVER(data->header->inode), +- &data->args.seq_args, +- &data->res.seq_res, ++ if (nfs4_setup_sequence(NFS_SERVER(hdr->inode), ++ &hdr->args.seq_args, ++ &hdr->res.seq_res, + task)) + return 0; +- if (nfs4_set_rw_stateid(&data->args.stateid, data->args.context, +- data->args.lock_context, data->header->rw_ops->rw_mode) == -EIO) ++ if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context, ++ hdr->args.lock_context, ++ hdr->rw_ops->rw_mode) == -EIO) + return -EIO; +- if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags))) ++ if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) + return -EIO; + return 0; + } + +-static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_pgio_data *data) ++static int nfs4_write_done_cb(struct rpc_task *task, ++ struct nfs_pgio_header *hdr) + { +- struct inode *inode = data->header->inode; ++ struct inode *inode = hdr->inode; + +- trace_nfs4_write(data, task->tk_status); +- if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { ++ trace_nfs4_write(hdr, task->tk_status); ++ if (nfs4_async_handle_error(task, NFS_SERVER(inode), ++ hdr->args.context->state) == -EAGAIN) { + rpc_restart_call_prepare(task); + return -EAGAIN; + } + if (task->tk_status >= 0) { +- renew_lease(NFS_SERVER(inode), data->timestamp); +- nfs_post_op_update_inode_force_wcc(inode, &data->fattr); ++ renew_lease(NFS_SERVER(inode), hdr->timestamp); ++ nfs_post_op_update_inode_force_wcc(inode, &hdr->fattr); + } + return 0; + } +@@ -4142,23 +4148,21 @@ static bool nfs4_write_stateid_changed(s + return true; + } + +-static int nfs4_write_done(struct rpc_task *task, struct nfs_pgio_data *data) ++static int nfs4_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr) + { +- if (!nfs4_sequence_done(task, &data->res.seq_res)) ++ if (!nfs4_sequence_done(task, &hdr->res.seq_res)) + return -EAGAIN; +- if (nfs4_write_stateid_changed(task, &data->args)) ++ if (nfs4_write_stateid_changed(task, &hdr->args)) + return -EAGAIN; +- return data->pgio_done_cb ? data->pgio_done_cb(task, data) : +- nfs4_write_done_cb(task, data); ++ return hdr->pgio_done_cb ? hdr->pgio_done_cb(task, hdr) : ++ nfs4_write_done_cb(task, hdr); + } + + static +-bool nfs4_write_need_cache_consistency_data(const struct nfs_pgio_data *data) ++bool nfs4_write_need_cache_consistency_data(struct nfs_pgio_header *hdr) + { +- const struct nfs_pgio_header *hdr = data->header; +- + /* Don't request attributes for pNFS or O_DIRECT writes */ +- if (data->ds_clp != NULL || hdr->dreq != NULL) ++ if (hdr->ds_clp != NULL || hdr->dreq != NULL) + return false; + /* Otherwise, request attributes if and only if we don't hold + * a delegation +@@ -4166,23 +4170,24 @@ bool nfs4_write_need_cache_consistency_d + return nfs4_have_delegation(hdr->inode, FMODE_READ) == 0; + } + +-static void nfs4_proc_write_setup(struct nfs_pgio_data *data, struct rpc_message *msg) ++static void nfs4_proc_write_setup(struct nfs_pgio_header *hdr, ++ struct rpc_message *msg) + { +- struct nfs_server *server = NFS_SERVER(data->header->inode); ++ struct nfs_server *server = NFS_SERVER(hdr->inode); + +- if (!nfs4_write_need_cache_consistency_data(data)) { +- data->args.bitmask = NULL; +- data->res.fattr = NULL; ++ if (!nfs4_write_need_cache_consistency_data(hdr)) { ++ hdr->args.bitmask = NULL; ++ hdr->res.fattr = NULL; + } else +- data->args.bitmask = server->cache_consistency_bitmask; ++ hdr->args.bitmask = server->cache_consistency_bitmask; + +- if (!data->pgio_done_cb) +- data->pgio_done_cb = nfs4_write_done_cb; +- data->res.server = server; +- data->timestamp = jiffies; ++ if (!hdr->pgio_done_cb) ++ hdr->pgio_done_cb = nfs4_write_done_cb; ++ hdr->res.server = server; ++ hdr->timestamp = jiffies; + + msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE]; +- nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1); ++ nfs4_init_sequence(&hdr->args.seq_args, &hdr->res.seq_res, 1); + } + + static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data) +--- a/fs/nfs/nfs4trace.h ++++ b/fs/nfs/nfs4trace.h +@@ -932,11 +932,11 @@ DEFINE_NFS4_IDMAP_EVENT(nfs4_map_gid_to_ + + DECLARE_EVENT_CLASS(nfs4_read_event, + TP_PROTO( +- const struct nfs_pgio_data *data, ++ const struct nfs_pgio_header *hdr, + int error + ), + +- TP_ARGS(data, error), ++ TP_ARGS(hdr, error), + + TP_STRUCT__entry( + __field(dev_t, dev) +@@ -948,12 +948,12 @@ DECLARE_EVENT_CLASS(nfs4_read_event, + ), + + TP_fast_assign( +- const struct inode *inode = data->header->inode; ++ const struct inode *inode = hdr->inode; + __entry->dev = inode->i_sb->s_dev; + __entry->fileid = NFS_FILEID(inode); + __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode)); +- __entry->offset = data->args.offset; +- __entry->count = data->args.count; ++ __entry->offset = hdr->args.offset; ++ __entry->count = hdr->args.count; + __entry->error = error; + ), + +@@ -972,10 +972,10 @@ DECLARE_EVENT_CLASS(nfs4_read_event, + #define DEFINE_NFS4_READ_EVENT(name) \ + DEFINE_EVENT(nfs4_read_event, name, \ + TP_PROTO( \ +- const struct nfs_pgio_data *data, \ ++ const struct nfs_pgio_header *hdr, \ + int error \ + ), \ +- TP_ARGS(data, error)) ++ TP_ARGS(hdr, error)) + DEFINE_NFS4_READ_EVENT(nfs4_read); + #ifdef CONFIG_NFS_V4_1 + DEFINE_NFS4_READ_EVENT(nfs4_pnfs_read); +@@ -983,11 +983,11 @@ DEFINE_NFS4_READ_EVENT(nfs4_pnfs_read); + + DECLARE_EVENT_CLASS(nfs4_write_event, + TP_PROTO( +- const struct nfs_pgio_data *data, ++ const struct nfs_pgio_header *hdr, + int error + ), + +- TP_ARGS(data, error), ++ TP_ARGS(hdr, error), + + TP_STRUCT__entry( + __field(dev_t, dev) +@@ -999,12 +999,12 @@ DECLARE_EVENT_CLASS(nfs4_write_event, + ), + + TP_fast_assign( +- const struct inode *inode = data->header->inode; ++ const struct inode *inode = hdr->inode; + __entry->dev = inode->i_sb->s_dev; + __entry->fileid = NFS_FILEID(inode); + __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode)); +- __entry->offset = data->args.offset; +- __entry->count = data->args.count; ++ __entry->offset = hdr->args.offset; ++ __entry->count = hdr->args.count; + __entry->error = error; + ), + +@@ -1024,10 +1024,10 @@ DECLARE_EVENT_CLASS(nfs4_write_event, + #define DEFINE_NFS4_WRITE_EVENT(name) \ + DEFINE_EVENT(nfs4_write_event, name, \ + TP_PROTO( \ +- const struct nfs_pgio_data *data, \ ++ const struct nfs_pgio_header *hdr, \ + int error \ + ), \ +- TP_ARGS(data, error)) ++ TP_ARGS(hdr, error)) + DEFINE_NFS4_WRITE_EVENT(nfs4_write); + #ifdef CONFIG_NFS_V4_1 + DEFINE_NFS4_WRITE_EVENT(nfs4_pnfs_write); +--- a/fs/nfs/objlayout/objio_osd.c ++++ b/fs/nfs/objlayout/objio_osd.c +@@ -439,22 +439,21 @@ static void _read_done(struct ore_io_sta + objlayout_read_done(&objios->oir, status, objios->sync); + } + +-int objio_read_pagelist(struct nfs_pgio_data *rdata) ++int objio_read_pagelist(struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = rdata->header; + struct objio_state *objios; + int ret; + + ret = objio_alloc_io_state(NFS_I(hdr->inode)->layout, true, +- hdr->lseg, rdata->args.pages, rdata->args.pgbase, +- rdata->args.offset, rdata->args.count, rdata, ++ hdr->lseg, hdr->args.pages, hdr->args.pgbase, ++ hdr->args.offset, hdr->args.count, hdr, + GFP_KERNEL, &objios); + if (unlikely(ret)) + return ret; + + objios->ios->done = _read_done; + dprintk("%s: offset=0x%llx length=0x%x\n", __func__, +- rdata->args.offset, rdata->args.count); ++ hdr->args.offset, hdr->args.count); + ret = ore_read(objios->ios); + if (unlikely(ret)) + objio_free_result(&objios->oir); +@@ -487,11 +486,11 @@ static void _write_done(struct ore_io_st + static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate) + { + struct objio_state *objios = priv; +- struct nfs_pgio_data *wdata = objios->oir.rpcdata; +- struct address_space *mapping = wdata->header->inode->i_mapping; ++ struct nfs_pgio_header *hdr = objios->oir.rpcdata; ++ struct address_space *mapping = hdr->inode->i_mapping; + pgoff_t index = offset / PAGE_SIZE; + struct page *page; +- loff_t i_size = i_size_read(wdata->header->inode); ++ loff_t i_size = i_size_read(hdr->inode); + + if (offset >= i_size) { + *uptodate = true; +@@ -531,15 +530,14 @@ static const struct _ore_r4w_op _r4w_op + .put_page = &__r4w_put_page, + }; + +-int objio_write_pagelist(struct nfs_pgio_data *wdata, int how) ++int objio_write_pagelist(struct nfs_pgio_header *hdr, int how) + { +- struct nfs_pgio_header *hdr = wdata->header; + struct objio_state *objios; + int ret; + + ret = objio_alloc_io_state(NFS_I(hdr->inode)->layout, false, +- hdr->lseg, wdata->args.pages, wdata->args.pgbase, +- wdata->args.offset, wdata->args.count, wdata, GFP_NOFS, ++ hdr->lseg, hdr->args.pages, hdr->args.pgbase, ++ hdr->args.offset, hdr->args.count, hdr, GFP_NOFS, + &objios); + if (unlikely(ret)) + return ret; +@@ -551,7 +549,7 @@ int objio_write_pagelist(struct nfs_pgio + objios->ios->done = _write_done; + + dprintk("%s: offset=0x%llx length=0x%x\n", __func__, +- wdata->args.offset, wdata->args.count); ++ hdr->args.offset, hdr->args.count); + ret = ore_write(objios->ios); + if (unlikely(ret)) { + objio_free_result(&objios->oir); +--- a/fs/nfs/objlayout/objlayout.c ++++ b/fs/nfs/objlayout/objlayout.c +@@ -229,36 +229,36 @@ objlayout_io_set_result(struct objlayout + static void _rpc_read_complete(struct work_struct *work) + { + struct rpc_task *task; +- struct nfs_pgio_data *rdata; ++ struct nfs_pgio_header *hdr; + + dprintk("%s enter\n", __func__); + task = container_of(work, struct rpc_task, u.tk_work); +- rdata = container_of(task, struct nfs_pgio_data, task); ++ hdr = container_of(task, struct nfs_pgio_header, task); + +- pnfs_ld_read_done(rdata); ++ pnfs_ld_read_done(hdr); + } + + void + objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync) + { +- struct nfs_pgio_data *rdata = oir->rpcdata; ++ struct nfs_pgio_header *hdr = oir->rpcdata; + +- oir->status = rdata->task.tk_status = status; ++ oir->status = hdr->task.tk_status = status; + if (status >= 0) +- rdata->res.count = status; ++ hdr->res.count = status; + else +- rdata->header->pnfs_error = status; ++ hdr->pnfs_error = status; + objlayout_iodone(oir); + /* must not use oir after this point */ + + dprintk("%s: Return status=%zd eof=%d sync=%d\n", __func__, +- status, rdata->res.eof, sync); ++ status, hdr->res.eof, sync); + + if (sync) +- pnfs_ld_read_done(rdata); ++ pnfs_ld_read_done(hdr); + else { +- INIT_WORK(&rdata->task.u.tk_work, _rpc_read_complete); +- schedule_work(&rdata->task.u.tk_work); ++ INIT_WORK(&hdr->task.u.tk_work, _rpc_read_complete); ++ schedule_work(&hdr->task.u.tk_work); + } + } + +@@ -266,12 +266,11 @@ objlayout_read_done(struct objlayout_io_ + * Perform sync or async reads. + */ + enum pnfs_try_status +-objlayout_read_pagelist(struct nfs_pgio_data *rdata) ++objlayout_read_pagelist(struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = rdata->header; + struct inode *inode = hdr->inode; +- loff_t offset = rdata->args.offset; +- size_t count = rdata->args.count; ++ loff_t offset = hdr->args.offset; ++ size_t count = hdr->args.count; + int err; + loff_t eof; + +@@ -279,23 +278,23 @@ objlayout_read_pagelist(struct nfs_pgio_ + if (unlikely(offset + count > eof)) { + if (offset >= eof) { + err = 0; +- rdata->res.count = 0; +- rdata->res.eof = 1; ++ hdr->res.count = 0; ++ hdr->res.eof = 1; + /*FIXME: do we need to call pnfs_ld_read_done() */ + goto out; + } + count = eof - offset; + } + +- rdata->res.eof = (offset + count) >= eof; +- _fix_verify_io_params(hdr->lseg, &rdata->args.pages, +- &rdata->args.pgbase, +- rdata->args.offset, rdata->args.count); ++ hdr->res.eof = (offset + count) >= eof; ++ _fix_verify_io_params(hdr->lseg, &hdr->args.pages, ++ &hdr->args.pgbase, ++ hdr->args.offset, hdr->args.count); + + dprintk("%s: inode(%lx) offset 0x%llx count 0x%Zx eof=%d\n", +- __func__, inode->i_ino, offset, count, rdata->res.eof); ++ __func__, inode->i_ino, offset, count, hdr->res.eof); + +- err = objio_read_pagelist(rdata); ++ err = objio_read_pagelist(hdr); + out: + if (unlikely(err)) { + hdr->pnfs_error = err; +@@ -312,38 +311,38 @@ objlayout_read_pagelist(struct nfs_pgio_ + static void _rpc_write_complete(struct work_struct *work) + { + struct rpc_task *task; +- struct nfs_pgio_data *wdata; ++ struct nfs_pgio_header *hdr; + + dprintk("%s enter\n", __func__); + task = container_of(work, struct rpc_task, u.tk_work); +- wdata = container_of(task, struct nfs_pgio_data, task); ++ hdr = container_of(task, struct nfs_pgio_header, task); + +- pnfs_ld_write_done(wdata); ++ pnfs_ld_write_done(hdr); + } + + void + objlayout_write_done(struct objlayout_io_res *oir, ssize_t status, bool sync) + { +- struct nfs_pgio_data *wdata = oir->rpcdata; ++ struct nfs_pgio_header *hdr = oir->rpcdata; + +- oir->status = wdata->task.tk_status = status; ++ oir->status = hdr->task.tk_status = status; + if (status >= 0) { +- wdata->res.count = status; +- wdata->writeverf.committed = oir->committed; ++ hdr->res.count = status; ++ hdr->writeverf.committed = oir->committed; + } else { +- wdata->header->pnfs_error = status; ++ hdr->pnfs_error = status; + } + objlayout_iodone(oir); + /* must not use oir after this point */ + + dprintk("%s: Return status %zd committed %d sync=%d\n", __func__, +- status, wdata->writeverf.committed, sync); ++ status, hdr->writeverf.committed, sync); + + if (sync) +- pnfs_ld_write_done(wdata); ++ pnfs_ld_write_done(hdr); + else { +- INIT_WORK(&wdata->task.u.tk_work, _rpc_write_complete); +- schedule_work(&wdata->task.u.tk_work); ++ INIT_WORK(&hdr->task.u.tk_work, _rpc_write_complete); ++ schedule_work(&hdr->task.u.tk_work); + } + } + +@@ -351,17 +350,15 @@ objlayout_write_done(struct objlayout_io + * Perform sync or async writes. + */ + enum pnfs_try_status +-objlayout_write_pagelist(struct nfs_pgio_data *wdata, +- int how) ++objlayout_write_pagelist(struct nfs_pgio_header *hdr, int how) + { +- struct nfs_pgio_header *hdr = wdata->header; + int err; + +- _fix_verify_io_params(hdr->lseg, &wdata->args.pages, +- &wdata->args.pgbase, +- wdata->args.offset, wdata->args.count); ++ _fix_verify_io_params(hdr->lseg, &hdr->args.pages, ++ &hdr->args.pgbase, ++ hdr->args.offset, hdr->args.count); + +- err = objio_write_pagelist(wdata, how); ++ err = objio_write_pagelist(hdr, how); + if (unlikely(err)) { + hdr->pnfs_error = err; + dprintk("%s: Returned Error %d\n", __func__, err); +--- a/fs/nfs/objlayout/objlayout.h ++++ b/fs/nfs/objlayout/objlayout.h +@@ -119,8 +119,8 @@ extern void objio_free_lseg(struct pnfs_ + */ + extern void objio_free_result(struct objlayout_io_res *oir); + +-extern int objio_read_pagelist(struct nfs_pgio_data *rdata); +-extern int objio_write_pagelist(struct nfs_pgio_data *wdata, int how); ++extern int objio_read_pagelist(struct nfs_pgio_header *rdata); ++extern int objio_write_pagelist(struct nfs_pgio_header *wdata, int how); + + /* + * callback API +@@ -168,10 +168,10 @@ extern struct pnfs_layout_segment *objla + extern void objlayout_free_lseg(struct pnfs_layout_segment *); + + extern enum pnfs_try_status objlayout_read_pagelist( +- struct nfs_pgio_data *); ++ struct nfs_pgio_header *); + + extern enum pnfs_try_status objlayout_write_pagelist( +- struct nfs_pgio_data *, ++ struct nfs_pgio_header *, + int how); + + extern void objlayout_encode_layoutcommit( +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -494,8 +494,7 @@ EXPORT_SYMBOL_GPL(nfs_pgio_header_free); + static bool nfs_pgio_data_init(struct nfs_pgio_header *hdr, + unsigned int pagecount) + { +- if (nfs_pgarray_set(&hdr->data.page_array, pagecount)) { +- hdr->data.header = hdr; ++ if (nfs_pgarray_set(&hdr->page_array, pagecount)) { + atomic_inc(&hdr->refcnt); + return true; + } +@@ -503,16 +502,14 @@ static bool nfs_pgio_data_init(struct nf + } + + /** +- * nfs_pgio_data_destroy - Properly free pageio data +- * @data: The data to destroy ++ * nfs_pgio_data_destroy - Properly release pageio data ++ * @hdr: The header with data to destroy + */ +-void nfs_pgio_data_destroy(struct nfs_pgio_data *data) ++void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = data->header; +- +- put_nfs_open_context(data->args.context); +- if (data->page_array.pagevec != data->page_array.page_array) +- kfree(data->page_array.pagevec); ++ put_nfs_open_context(hdr->args.context); ++ if (hdr->page_array.pagevec != hdr->page_array.page_array) ++ kfree(hdr->page_array.pagevec); + if (atomic_dec_and_test(&hdr->refcnt)) + hdr->completion_ops->completion(hdr); + } +@@ -520,31 +517,31 @@ EXPORT_SYMBOL_GPL(nfs_pgio_data_destroy) + + /** + * nfs_pgio_rpcsetup - Set up arguments for a pageio call +- * @data: The pageio data ++ * @hdr: The pageio hdr + * @count: Number of bytes to read + * @offset: Initial offset + * @how: How to commit data (writes only) + * @cinfo: Commit information for the call (writes only) + */ +-static void nfs_pgio_rpcsetup(struct nfs_pgio_data *data, ++static void nfs_pgio_rpcsetup(struct nfs_pgio_header *hdr, + unsigned int count, unsigned int offset, + int how, struct nfs_commit_info *cinfo) + { +- struct nfs_page *req = data->header->req; ++ struct nfs_page *req = hdr->req; + + /* Set up the RPC argument and reply structs +- * NB: take care not to mess about with data->commit et al. */ ++ * NB: take care not to mess about with hdr->commit et al. */ + +- data->args.fh = NFS_FH(data->header->inode); +- data->args.offset = req_offset(req) + offset; ++ hdr->args.fh = NFS_FH(hdr->inode); ++ hdr->args.offset = req_offset(req) + offset; + /* pnfs_set_layoutcommit needs this */ +- data->mds_offset = data->args.offset; +- data->args.pgbase = req->wb_pgbase + offset; +- data->args.pages = data->page_array.pagevec; +- data->args.count = count; +- data->args.context = get_nfs_open_context(req->wb_context); +- data->args.lock_context = req->wb_lock_context; +- data->args.stable = NFS_UNSTABLE; ++ hdr->mds_offset = hdr->args.offset; ++ hdr->args.pgbase = req->wb_pgbase + offset; ++ hdr->args.pages = hdr->page_array.pagevec; ++ hdr->args.count = count; ++ hdr->args.context = get_nfs_open_context(req->wb_context); ++ hdr->args.lock_context = req->wb_lock_context; ++ hdr->args.stable = NFS_UNSTABLE; + switch (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) { + case 0: + break; +@@ -552,59 +549,60 @@ static void nfs_pgio_rpcsetup(struct nfs + if (nfs_reqs_to_commit(cinfo)) + break; + default: +- data->args.stable = NFS_FILE_SYNC; ++ hdr->args.stable = NFS_FILE_SYNC; + } + +- data->res.fattr = &data->fattr; +- data->res.count = count; +- data->res.eof = 0; +- data->res.verf = &data->writeverf; +- nfs_fattr_init(&data->fattr); ++ hdr->res.fattr = &hdr->fattr; ++ hdr->res.count = count; ++ hdr->res.eof = 0; ++ hdr->res.verf = &hdr->writeverf; ++ nfs_fattr_init(&hdr->fattr); + } + + /** +- * nfs_pgio_prepare - Prepare pageio data to go over the wire ++ * nfs_pgio_prepare - Prepare pageio hdr to go over the wire + * @task: The current task +- * @calldata: pageio data to prepare ++ * @calldata: pageio header to prepare + */ + static void nfs_pgio_prepare(struct rpc_task *task, void *calldata) + { +- struct nfs_pgio_data *data = calldata; ++ struct nfs_pgio_header *hdr = calldata; + int err; +- err = NFS_PROTO(data->header->inode)->pgio_rpc_prepare(task, data); ++ err = NFS_PROTO(hdr->inode)->pgio_rpc_prepare(task, hdr); + if (err) + rpc_exit(task, err); + } + +-int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_data *data, ++int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr, + const struct rpc_call_ops *call_ops, int how, int flags) + { ++ struct inode *inode = hdr->inode; + struct rpc_task *task; + struct rpc_message msg = { +- .rpc_argp = &data->args, +- .rpc_resp = &data->res, +- .rpc_cred = data->header->cred, ++ .rpc_argp = &hdr->args, ++ .rpc_resp = &hdr->res, ++ .rpc_cred = hdr->cred, + }; + struct rpc_task_setup task_setup_data = { + .rpc_client = clnt, +- .task = &data->task, ++ .task = &hdr->task, + .rpc_message = &msg, + .callback_ops = call_ops, +- .callback_data = data, ++ .callback_data = hdr, + .workqueue = nfsiod_workqueue, + .flags = RPC_TASK_ASYNC | flags, + }; + int ret = 0; + +- data->header->rw_ops->rw_initiate(data, &msg, &task_setup_data, how); ++ hdr->rw_ops->rw_initiate(hdr, &msg, &task_setup_data, how); + + dprintk("NFS: %5u initiated pgio call " + "(req %s/%llu, %u bytes @ offset %llu)\n", +- data->task.tk_pid, +- data->header->inode->i_sb->s_id, +- (unsigned long long)NFS_FILEID(data->header->inode), +- data->args.count, +- (unsigned long long)data->args.offset); ++ hdr->task.tk_pid, ++ inode->i_sb->s_id, ++ (unsigned long long)NFS_FILEID(inode), ++ hdr->args.count, ++ (unsigned long long)hdr->args.offset); + + task = rpc_run_task(&task_setup_data); + if (IS_ERR(task)) { +@@ -631,21 +629,21 @@ static int nfs_pgio_error(struct nfs_pag + struct nfs_pgio_header *hdr) + { + set_bit(NFS_IOHDR_REDO, &hdr->flags); +- nfs_pgio_data_destroy(&hdr->data); ++ nfs_pgio_data_destroy(hdr); + desc->pg_completion_ops->error_cleanup(&desc->pg_list); + return -ENOMEM; + } + + /** + * nfs_pgio_release - Release pageio data +- * @calldata: The pageio data to release ++ * @calldata: The pageio header to release + */ + static void nfs_pgio_release(void *calldata) + { +- struct nfs_pgio_data *data = calldata; +- if (data->header->rw_ops->rw_release) +- data->header->rw_ops->rw_release(data); +- nfs_pgio_data_destroy(data); ++ struct nfs_pgio_header *hdr = calldata; ++ if (hdr->rw_ops->rw_release) ++ hdr->rw_ops->rw_release(hdr); ++ nfs_pgio_data_destroy(hdr); + } + + /** +@@ -686,22 +684,22 @@ EXPORT_SYMBOL_GPL(nfs_pageio_init); + /** + * nfs_pgio_result - Basic pageio error handling + * @task: The task that ran +- * @calldata: Pageio data to check ++ * @calldata: Pageio header to check + */ + static void nfs_pgio_result(struct rpc_task *task, void *calldata) + { +- struct nfs_pgio_data *data = calldata; +- struct inode *inode = data->header->inode; ++ struct nfs_pgio_header *hdr = calldata; ++ struct inode *inode = hdr->inode; + + dprintk("NFS: %s: %5u, (status %d)\n", __func__, + task->tk_pid, task->tk_status); + +- if (data->header->rw_ops->rw_done(task, data, inode) != 0) ++ if (hdr->rw_ops->rw_done(task, hdr, inode) != 0) + return; + if (task->tk_status < 0) +- nfs_set_pgio_error(data->header, task->tk_status, data->args.offset); ++ nfs_set_pgio_error(hdr, task->tk_status, hdr->args.offset); + else +- data->header->rw_ops->rw_result(task, data); ++ hdr->rw_ops->rw_result(task, hdr); + } + + /* +@@ -717,7 +715,6 @@ int nfs_generic_pgio(struct nfs_pageio_d + { + struct nfs_page *req; + struct page **pages; +- struct nfs_pgio_data *data; + struct list_head *head = &desc->pg_list; + struct nfs_commit_info cinfo; + +@@ -725,9 +722,8 @@ int nfs_generic_pgio(struct nfs_pageio_d + desc->pg_count))) + return nfs_pgio_error(desc, hdr); + +- data = &hdr->data; + nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq); +- pages = data->page_array.pagevec; ++ pages = hdr->page_array.pagevec; + while (!list_empty(head)) { + req = nfs_list_entry(head->next); + nfs_list_remove_request(req); +@@ -740,7 +736,7 @@ int nfs_generic_pgio(struct nfs_pageio_d + desc->pg_ioflags &= ~FLUSH_COND_STABLE; + + /* Set up the argument struct */ +- nfs_pgio_rpcsetup(data, desc->pg_count, 0, desc->pg_ioflags, &cinfo); ++ nfs_pgio_rpcsetup(hdr, desc->pg_count, 0, desc->pg_ioflags, &cinfo); + desc->pg_rpc_callops = &nfs_pgio_common_ops; + return 0; + } +@@ -761,7 +757,7 @@ static int nfs_generic_pg_pgios(struct n + ret = nfs_generic_pgio(desc, hdr); + if (ret == 0) + ret = nfs_initiate_pgio(NFS_CLIENT(hdr->inode), +- &hdr->data, desc->pg_rpc_callops, ++ hdr, desc->pg_rpc_callops, + desc->pg_ioflags, 0); + if (atomic_dec_and_test(&hdr->refcnt)) + hdr->completion_ops->completion(hdr); +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -1502,9 +1502,8 @@ int pnfs_write_done_resend_to_mds(struct + } + EXPORT_SYMBOL_GPL(pnfs_write_done_resend_to_mds); + +-static void pnfs_ld_handle_write_error(struct nfs_pgio_data *data) ++static void pnfs_ld_handle_write_error(struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = data->header; + + dprintk("pnfs write error = %d\n", hdr->pnfs_error); + if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & +@@ -1512,7 +1511,7 @@ static void pnfs_ld_handle_write_error(s + pnfs_return_layout(hdr->inode); + } + if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) +- data->task.tk_status = pnfs_write_done_resend_to_mds(hdr->inode, ++ hdr->task.tk_status = pnfs_write_done_resend_to_mds(hdr->inode, + &hdr->pages, + hdr->completion_ops, + hdr->dreq); +@@ -1521,41 +1520,36 @@ static void pnfs_ld_handle_write_error(s + /* + * Called by non rpc-based layout drivers + */ +-void pnfs_ld_write_done(struct nfs_pgio_data *data) ++void pnfs_ld_write_done(struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = data->header; +- +- trace_nfs4_pnfs_write(data, hdr->pnfs_error); ++ trace_nfs4_pnfs_write(hdr, hdr->pnfs_error); + if (!hdr->pnfs_error) { +- pnfs_set_layoutcommit(data); +- hdr->mds_ops->rpc_call_done(&data->task, data); ++ pnfs_set_layoutcommit(hdr); ++ hdr->mds_ops->rpc_call_done(&hdr->task, hdr); + } else +- pnfs_ld_handle_write_error(data); +- hdr->mds_ops->rpc_release(data); ++ pnfs_ld_handle_write_error(hdr); ++ hdr->mds_ops->rpc_release(hdr); + } + EXPORT_SYMBOL_GPL(pnfs_ld_write_done); + + static void + pnfs_write_through_mds(struct nfs_pageio_descriptor *desc, +- struct nfs_pgio_data *data) ++ struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = data->header; +- + if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { + list_splice_tail_init(&hdr->pages, &desc->pg_list); + nfs_pageio_reset_write_mds(desc); + desc->pg_recoalesce = 1; + } +- nfs_pgio_data_destroy(data); ++ nfs_pgio_data_destroy(hdr); + } + + static enum pnfs_try_status +-pnfs_try_to_write_data(struct nfs_pgio_data *wdata, ++pnfs_try_to_write_data(struct nfs_pgio_header *hdr, + const struct rpc_call_ops *call_ops, + struct pnfs_layout_segment *lseg, + int how) + { +- struct nfs_pgio_header *hdr = wdata->header; + struct inode *inode = hdr->inode; + enum pnfs_try_status trypnfs; + struct nfs_server *nfss = NFS_SERVER(inode); +@@ -1563,8 +1557,8 @@ pnfs_try_to_write_data(struct nfs_pgio_d + hdr->mds_ops = call_ops; + + dprintk("%s: Writing ino:%lu %u@%llu (how %d)\n", __func__, +- inode->i_ino, wdata->args.count, wdata->args.offset, how); +- trypnfs = nfss->pnfs_curr_ld->write_pagelist(wdata, how); ++ inode->i_ino, hdr->args.count, hdr->args.offset, how); ++ trypnfs = nfss->pnfs_curr_ld->write_pagelist(hdr, how); + if (trypnfs != PNFS_NOT_ATTEMPTED) + nfs_inc_stats(inode, NFSIOS_PNFS_WRITE); + dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); +@@ -1575,15 +1569,14 @@ static void + pnfs_do_write(struct nfs_pageio_descriptor *desc, + struct nfs_pgio_header *hdr, int how) + { +- struct nfs_pgio_data *data = &hdr->data; + const struct rpc_call_ops *call_ops = desc->pg_rpc_callops; + struct pnfs_layout_segment *lseg = desc->pg_lseg; + enum pnfs_try_status trypnfs; + + desc->pg_lseg = NULL; +- trypnfs = pnfs_try_to_write_data(data, call_ops, lseg, how); ++ trypnfs = pnfs_try_to_write_data(hdr, call_ops, lseg, how); + if (trypnfs == PNFS_NOT_ATTEMPTED) +- pnfs_write_through_mds(desc, data); ++ pnfs_write_through_mds(desc, hdr); + pnfs_put_lseg(lseg); + } + +@@ -1650,17 +1643,15 @@ int pnfs_read_done_resend_to_mds(struct + } + EXPORT_SYMBOL_GPL(pnfs_read_done_resend_to_mds); + +-static void pnfs_ld_handle_read_error(struct nfs_pgio_data *data) ++static void pnfs_ld_handle_read_error(struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = data->header; +- + dprintk("pnfs read error = %d\n", hdr->pnfs_error); + if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & + PNFS_LAYOUTRET_ON_ERROR) { + pnfs_return_layout(hdr->inode); + } + if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) +- data->task.tk_status = pnfs_read_done_resend_to_mds(hdr->inode, ++ hdr->task.tk_status = pnfs_read_done_resend_to_mds(hdr->inode, + &hdr->pages, + hdr->completion_ops, + hdr->dreq); +@@ -1669,43 +1660,38 @@ static void pnfs_ld_handle_read_error(st + /* + * Called by non rpc-based layout drivers + */ +-void pnfs_ld_read_done(struct nfs_pgio_data *data) ++void pnfs_ld_read_done(struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = data->header; +- +- trace_nfs4_pnfs_read(data, hdr->pnfs_error); ++ trace_nfs4_pnfs_read(hdr, hdr->pnfs_error); + if (likely(!hdr->pnfs_error)) { +- __nfs4_read_done_cb(data); +- hdr->mds_ops->rpc_call_done(&data->task, data); ++ __nfs4_read_done_cb(hdr); ++ hdr->mds_ops->rpc_call_done(&hdr->task, hdr); + } else +- pnfs_ld_handle_read_error(data); +- hdr->mds_ops->rpc_release(data); ++ pnfs_ld_handle_read_error(hdr); ++ hdr->mds_ops->rpc_release(hdr); + } + EXPORT_SYMBOL_GPL(pnfs_ld_read_done); + + static void + pnfs_read_through_mds(struct nfs_pageio_descriptor *desc, +- struct nfs_pgio_data *data) ++ struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = data->header; +- + if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { + list_splice_tail_init(&hdr->pages, &desc->pg_list); + nfs_pageio_reset_read_mds(desc); + desc->pg_recoalesce = 1; + } +- nfs_pgio_data_destroy(data); ++ nfs_pgio_data_destroy(hdr); + } + + /* + * Call the appropriate parallel I/O subsystem read function. + */ + static enum pnfs_try_status +-pnfs_try_to_read_data(struct nfs_pgio_data *rdata, ++pnfs_try_to_read_data(struct nfs_pgio_header *hdr, + const struct rpc_call_ops *call_ops, + struct pnfs_layout_segment *lseg) + { +- struct nfs_pgio_header *hdr = rdata->header; + struct inode *inode = hdr->inode; + struct nfs_server *nfss = NFS_SERVER(inode); + enum pnfs_try_status trypnfs; +@@ -1713,9 +1699,9 @@ pnfs_try_to_read_data(struct nfs_pgio_da + hdr->mds_ops = call_ops; + + dprintk("%s: Reading ino:%lu %u@%llu\n", +- __func__, inode->i_ino, rdata->args.count, rdata->args.offset); ++ __func__, inode->i_ino, hdr->args.count, hdr->args.offset); + +- trypnfs = nfss->pnfs_curr_ld->read_pagelist(rdata); ++ trypnfs = nfss->pnfs_curr_ld->read_pagelist(hdr); + if (trypnfs != PNFS_NOT_ATTEMPTED) + nfs_inc_stats(inode, NFSIOS_PNFS_READ); + dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); +@@ -1725,15 +1711,14 @@ pnfs_try_to_read_data(struct nfs_pgio_da + static void + pnfs_do_read(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_data *data = &hdr->data; + const struct rpc_call_ops *call_ops = desc->pg_rpc_callops; + struct pnfs_layout_segment *lseg = desc->pg_lseg; + enum pnfs_try_status trypnfs; + + desc->pg_lseg = NULL; +- trypnfs = pnfs_try_to_read_data(data, call_ops, lseg); ++ trypnfs = pnfs_try_to_read_data(hdr, call_ops, lseg); + if (trypnfs == PNFS_NOT_ATTEMPTED) +- pnfs_read_through_mds(desc, data); ++ pnfs_read_through_mds(desc, hdr); + pnfs_put_lseg(lseg); + } + +@@ -1816,12 +1801,11 @@ void pnfs_set_lo_fail(struct pnfs_layout + EXPORT_SYMBOL_GPL(pnfs_set_lo_fail); + + void +-pnfs_set_layoutcommit(struct nfs_pgio_data *wdata) ++pnfs_set_layoutcommit(struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = wdata->header; + struct inode *inode = hdr->inode; + struct nfs_inode *nfsi = NFS_I(inode); +- loff_t end_pos = wdata->mds_offset + wdata->res.count; ++ loff_t end_pos = hdr->mds_offset + hdr->res.count; + bool mark_as_dirty = false; + + spin_lock(&inode->i_lock); +--- a/fs/nfs/pnfs.h ++++ b/fs/nfs/pnfs.h +@@ -113,8 +113,8 @@ struct pnfs_layoutdriver_type { + * Return PNFS_ATTEMPTED to indicate the layout code has attempted + * I/O, else return PNFS_NOT_ATTEMPTED to fall back to normal NFS + */ +- enum pnfs_try_status (*read_pagelist) (struct nfs_pgio_data *nfs_data); +- enum pnfs_try_status (*write_pagelist) (struct nfs_pgio_data *nfs_data, int how); ++ enum pnfs_try_status (*read_pagelist)(struct nfs_pgio_header *); ++ enum pnfs_try_status (*write_pagelist)(struct nfs_pgio_header *, int); + + void (*free_deviceid_node) (struct nfs4_deviceid_node *); + +@@ -213,13 +213,13 @@ bool pnfs_roc(struct inode *ino); + void pnfs_roc_release(struct inode *ino); + void pnfs_roc_set_barrier(struct inode *ino, u32 barrier); + bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task); +-void pnfs_set_layoutcommit(struct nfs_pgio_data *wdata); ++void pnfs_set_layoutcommit(struct nfs_pgio_header *); + void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data); + int pnfs_layoutcommit_inode(struct inode *inode, bool sync); + int _pnfs_return_layout(struct inode *); + int pnfs_commit_and_return_layout(struct inode *); +-void pnfs_ld_write_done(struct nfs_pgio_data *); +-void pnfs_ld_read_done(struct nfs_pgio_data *); ++void pnfs_ld_write_done(struct nfs_pgio_header *); ++void pnfs_ld_read_done(struct nfs_pgio_header *); + struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino, + struct nfs_open_context *ctx, + loff_t pos, +--- a/fs/nfs/proc.c ++++ b/fs/nfs/proc.c +@@ -578,46 +578,49 @@ nfs_proc_pathconf(struct nfs_server *ser + return 0; + } + +-static int nfs_read_done(struct rpc_task *task, struct nfs_pgio_data *data) ++static int nfs_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr) + { +- struct inode *inode = data->header->inode; ++ struct inode *inode = hdr->inode; + + nfs_invalidate_atime(inode); + if (task->tk_status >= 0) { +- nfs_refresh_inode(inode, data->res.fattr); ++ nfs_refresh_inode(inode, hdr->res.fattr); + /* Emulate the eof flag, which isn't normally needed in NFSv2 + * as it is guaranteed to always return the file attributes + */ +- if (data->args.offset + data->res.count >= data->res.fattr->size) +- data->res.eof = 1; ++ if (hdr->args.offset + hdr->res.count >= hdr->res.fattr->size) ++ hdr->res.eof = 1; + } + return 0; + } + +-static void nfs_proc_read_setup(struct nfs_pgio_data *data, struct rpc_message *msg) ++static void nfs_proc_read_setup(struct nfs_pgio_header *hdr, ++ struct rpc_message *msg) + { + msg->rpc_proc = &nfs_procedures[NFSPROC_READ]; + } + +-static int nfs_proc_pgio_rpc_prepare(struct rpc_task *task, struct nfs_pgio_data *data) ++static int nfs_proc_pgio_rpc_prepare(struct rpc_task *task, ++ struct nfs_pgio_header *hdr) + { + rpc_call_start(task); + return 0; + } + +-static int nfs_write_done(struct rpc_task *task, struct nfs_pgio_data *data) ++static int nfs_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr) + { +- struct inode *inode = data->header->inode; ++ struct inode *inode = hdr->inode; + + if (task->tk_status >= 0) +- nfs_post_op_update_inode_force_wcc(inode, data->res.fattr); ++ nfs_post_op_update_inode_force_wcc(inode, hdr->res.fattr); + return 0; + } + +-static void nfs_proc_write_setup(struct nfs_pgio_data *data, struct rpc_message *msg) ++static void nfs_proc_write_setup(struct nfs_pgio_header *hdr, ++ struct rpc_message *msg) + { + /* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */ +- data->args.stable = NFS_FILE_SYNC; ++ hdr->args.stable = NFS_FILE_SYNC; + msg->rpc_proc = &nfs_procedures[NFSPROC_WRITE]; + } + +--- a/fs/nfs/read.c ++++ b/fs/nfs/read.c +@@ -172,14 +172,15 @@ out: + hdr->release(hdr); + } + +-static void nfs_initiate_read(struct nfs_pgio_data *data, struct rpc_message *msg, ++static void nfs_initiate_read(struct nfs_pgio_header *hdr, ++ struct rpc_message *msg, + struct rpc_task_setup *task_setup_data, int how) + { +- struct inode *inode = data->header->inode; ++ struct inode *inode = hdr->inode; + int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; + + task_setup_data->flags |= swap_flags; +- NFS_PROTO(inode)->read_setup(data, msg); ++ NFS_PROTO(inode)->read_setup(hdr, msg); + } + + static void +@@ -203,14 +204,15 @@ static const struct nfs_pgio_completion_ + * This is the callback from RPC telling us whether a reply was + * received or some error occurred (timeout or socket shutdown). + */ +-static int nfs_readpage_done(struct rpc_task *task, struct nfs_pgio_data *data, ++static int nfs_readpage_done(struct rpc_task *task, ++ struct nfs_pgio_header *hdr, + struct inode *inode) + { +- int status = NFS_PROTO(inode)->read_done(task, data); ++ int status = NFS_PROTO(inode)->read_done(task, hdr); + if (status != 0) + return status; + +- nfs_add_stats(inode, NFSIOS_SERVERREADBYTES, data->res.count); ++ nfs_add_stats(inode, NFSIOS_SERVERREADBYTES, hdr->res.count); + + if (task->tk_status == -ESTALE) { + set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); +@@ -219,34 +221,34 @@ static int nfs_readpage_done(struct rpc_ + return 0; + } + +-static void nfs_readpage_retry(struct rpc_task *task, struct nfs_pgio_data *data) ++static void nfs_readpage_retry(struct rpc_task *task, ++ struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_args *argp = &data->args; +- struct nfs_pgio_res *resp = &data->res; ++ struct nfs_pgio_args *argp = &hdr->args; ++ struct nfs_pgio_res *resp = &hdr->res; + + /* This is a short read! */ +- nfs_inc_stats(data->header->inode, NFSIOS_SHORTREAD); ++ nfs_inc_stats(hdr->inode, NFSIOS_SHORTREAD); + /* Has the server at least made some progress? */ + if (resp->count == 0) { +- nfs_set_pgio_error(data->header, -EIO, argp->offset); ++ nfs_set_pgio_error(hdr, -EIO, argp->offset); + return; + } +- /* Yes, so retry the read at the end of the data */ +- data->mds_offset += resp->count; ++ /* Yes, so retry the read at the end of the hdr */ ++ hdr->mds_offset += resp->count; + argp->offset += resp->count; + argp->pgbase += resp->count; + argp->count -= resp->count; + rpc_restart_call_prepare(task); + } + +-static void nfs_readpage_result(struct rpc_task *task, struct nfs_pgio_data *data) ++static void nfs_readpage_result(struct rpc_task *task, ++ struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = data->header; +- +- if (data->res.eof) { ++ if (hdr->res.eof) { + loff_t bound; + +- bound = data->args.offset + data->res.count; ++ bound = hdr->args.offset + hdr->res.count; + spin_lock(&hdr->lock); + if (bound < hdr->io_start + hdr->good_bytes) { + set_bit(NFS_IOHDR_EOF, &hdr->flags); +@@ -254,8 +256,8 @@ static void nfs_readpage_result(struct r + hdr->good_bytes = bound - hdr->io_start; + } + spin_unlock(&hdr->lock); +- } else if (data->res.count != data->args.count) +- nfs_readpage_retry(task, data); ++ } else if (hdr->res.count != hdr->args.count) ++ nfs_readpage_retry(task, hdr); + } + + /* +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -826,11 +826,11 @@ nfs_clear_request_commit(struct nfs_page + } + + static inline +-int nfs_write_need_commit(struct nfs_pgio_data *data) ++int nfs_write_need_commit(struct nfs_pgio_header *hdr) + { +- if (data->writeverf.committed == NFS_DATA_SYNC) +- return data->header->lseg == NULL; +- return data->writeverf.committed != NFS_FILE_SYNC; ++ if (hdr->writeverf.committed == NFS_DATA_SYNC) ++ return hdr->lseg == NULL; ++ return hdr->writeverf.committed != NFS_FILE_SYNC; + } + + #else +@@ -857,7 +857,7 @@ nfs_clear_request_commit(struct nfs_page + } + + static inline +-int nfs_write_need_commit(struct nfs_pgio_data *data) ++int nfs_write_need_commit(struct nfs_pgio_header *hdr) + { + return 0; + } +@@ -1241,17 +1241,18 @@ static int flush_task_priority(int how) + return RPC_PRIORITY_NORMAL; + } + +-static void nfs_initiate_write(struct nfs_pgio_data *data, struct rpc_message *msg, ++static void nfs_initiate_write(struct nfs_pgio_header *hdr, ++ struct rpc_message *msg, + struct rpc_task_setup *task_setup_data, int how) + { +- struct inode *inode = data->header->inode; ++ struct inode *inode = hdr->inode; + int priority = flush_task_priority(how); + + task_setup_data->priority = priority; +- NFS_PROTO(inode)->write_setup(data, msg); ++ NFS_PROTO(inode)->write_setup(hdr, msg); + + nfs4_state_protect_write(NFS_SERVER(inode)->nfs_client, +- &task_setup_data->rpc_client, msg, data); ++ &task_setup_data->rpc_client, msg, hdr); + } + + /* If a nfs_flush_* function fails, it should remove reqs from @head and +@@ -1313,19 +1314,17 @@ void nfs_commit_prepare(struct rpc_task + NFS_PROTO(data->inode)->commit_rpc_prepare(task, data); + } + +-static void nfs_writeback_release_common(struct nfs_pgio_data *data) ++static void nfs_writeback_release_common(struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_header *hdr = data->header; +- int status = data->task.tk_status; ++ int status = hdr->task.tk_status; + +- if ((status >= 0) && nfs_write_need_commit(data)) { ++ if ((status >= 0) && nfs_write_need_commit(hdr)) { + spin_lock(&hdr->lock); + if (test_bit(NFS_IOHDR_NEED_RESCHED, &hdr->flags)) + ; /* Do nothing */ + else if (!test_and_set_bit(NFS_IOHDR_NEED_COMMIT, &hdr->flags)) +- memcpy(&hdr->verf, &data->writeverf, sizeof(hdr->verf)); +- else if (memcmp(&hdr->verf, &data->writeverf, +- sizeof(hdr->verf))) ++ memcpy(&hdr->verf, &hdr->writeverf, sizeof(hdr->verf)); ++ else if (memcmp(&hdr->verf, &hdr->writeverf, sizeof(hdr->verf))) + set_bit(NFS_IOHDR_NEED_RESCHED, &hdr->flags); + spin_unlock(&hdr->lock); + } +@@ -1359,7 +1358,8 @@ static int nfs_should_remove_suid(const + /* + * This function is called when the WRITE call is complete. + */ +-static int nfs_writeback_done(struct rpc_task *task, struct nfs_pgio_data *data, ++static int nfs_writeback_done(struct rpc_task *task, ++ struct nfs_pgio_header *hdr, + struct inode *inode) + { + int status; +@@ -1371,13 +1371,14 @@ static int nfs_writeback_done(struct rpc + * another writer had changed the file, but some applications + * depend on tighter cache coherency when writing. + */ +- status = NFS_PROTO(inode)->write_done(task, data); ++ status = NFS_PROTO(inode)->write_done(task, hdr); + if (status != 0) + return status; +- nfs_add_stats(inode, NFSIOS_SERVERWRITTENBYTES, data->res.count); ++ nfs_add_stats(inode, NFSIOS_SERVERWRITTENBYTES, hdr->res.count); + + #if IS_ENABLED(CONFIG_NFS_V3) || IS_ENABLED(CONFIG_NFS_V4) +- if (data->res.verf->committed < data->args.stable && task->tk_status >= 0) { ++ if (hdr->res.verf->committed < hdr->args.stable && ++ task->tk_status >= 0) { + /* We tried a write call, but the server did not + * commit data to stable storage even though we + * requested it. +@@ -1393,7 +1394,7 @@ static int nfs_writeback_done(struct rpc + dprintk("NFS: faulty NFS server %s:" + " (committed = %d) != (stable = %d)\n", + NFS_SERVER(inode)->nfs_client->cl_hostname, +- data->res.verf->committed, data->args.stable); ++ hdr->res.verf->committed, hdr->args.stable); + complain = jiffies + 300 * HZ; + } + } +@@ -1408,16 +1409,17 @@ static int nfs_writeback_done(struct rpc + /* + * This function is called when the WRITE call is complete. + */ +-static void nfs_writeback_result(struct rpc_task *task, struct nfs_pgio_data *data) ++static void nfs_writeback_result(struct rpc_task *task, ++ struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_args *argp = &data->args; +- struct nfs_pgio_res *resp = &data->res; ++ struct nfs_pgio_args *argp = &hdr->args; ++ struct nfs_pgio_res *resp = &hdr->res; + + if (resp->count < argp->count) { + static unsigned long complain; + + /* This a short write! */ +- nfs_inc_stats(data->header->inode, NFSIOS_SHORTWRITE); ++ nfs_inc_stats(hdr->inode, NFSIOS_SHORTWRITE); + + /* Has the server at least made some progress? */ + if (resp->count == 0) { +@@ -1427,14 +1429,14 @@ static void nfs_writeback_result(struct + argp->count); + complain = jiffies + 300 * HZ; + } +- nfs_set_pgio_error(data->header, -EIO, argp->offset); ++ nfs_set_pgio_error(hdr, -EIO, argp->offset); + task->tk_status = -EIO; + return; + } + /* Was this an NFSv2 write or an NFSv3 stable write? */ + if (resp->verf->committed != NFS_UNSTABLE) { + /* Resend from where the server left off */ +- data->mds_offset += resp->count; ++ hdr->mds_offset += resp->count; + argp->offset += resp->count; + argp->pgbase += resp->count; + argp->count -= resp->count; +--- a/include/linux/nfs_page.h ++++ b/include/linux/nfs_page.h +@@ -64,10 +64,11 @@ struct nfs_rw_ops { + const fmode_t rw_mode; + struct nfs_pgio_header *(*rw_alloc_header)(void); + void (*rw_free_header)(struct nfs_pgio_header *); +- void (*rw_release)(struct nfs_pgio_data *); +- int (*rw_done)(struct rpc_task *, struct nfs_pgio_data *, struct inode *); +- void (*rw_result)(struct rpc_task *, struct nfs_pgio_data *); +- void (*rw_initiate)(struct nfs_pgio_data *, struct rpc_message *, ++ void (*rw_release)(struct nfs_pgio_header *); ++ int (*rw_done)(struct rpc_task *, struct nfs_pgio_header *, ++ struct inode *); ++ void (*rw_result)(struct rpc_task *, struct nfs_pgio_header *); ++ void (*rw_initiate)(struct nfs_pgio_header *, struct rpc_message *, + struct rpc_task_setup *, int); + }; + +--- a/include/linux/nfs_xdr.h ++++ b/include/linux/nfs_xdr.h +@@ -1257,27 +1257,10 @@ enum { + NFS_IOHDR_NEED_RESCHED, + }; + +-struct nfs_pgio_data { +- struct nfs_pgio_header *header; +- struct list_head list; +- struct rpc_task task; +- struct nfs_fattr fattr; +- struct nfs_writeverf writeverf; /* Used for writes */ +- struct nfs_pgio_args args; /* argument struct */ +- struct nfs_pgio_res res; /* result struct */ +- unsigned long timestamp; /* For lease renewal */ +- int (*pgio_done_cb)(struct rpc_task *task, struct nfs_pgio_data *data); +- __u64 mds_offset; /* Filelayout dense stripe */ +- struct nfs_page_array page_array; +- struct nfs_client *ds_clp; /* pNFS data server */ +- int ds_idx; /* ds index if ds_clp is set */ +-}; +- + struct nfs_pgio_header { + struct inode *inode; + struct rpc_cred *cred; + struct list_head pages; +- struct nfs_pgio_data data; + atomic_t refcnt; + struct nfs_page *req; + struct nfs_writeverf verf; /* Used for writes */ +@@ -1295,6 +1278,21 @@ struct nfs_pgio_header { + int error; /* merge with pnfs_error */ + unsigned long good_bytes; /* boundary of good data */ + unsigned long flags; ++ ++ /* ++ * rpc data ++ */ ++ struct rpc_task task; ++ struct nfs_fattr fattr; ++ struct nfs_writeverf writeverf; /* Used for writes */ ++ struct nfs_pgio_args args; /* argument struct */ ++ struct nfs_pgio_res res; /* result struct */ ++ unsigned long timestamp; /* For lease renewal */ ++ int (*pgio_done_cb)(struct rpc_task *, struct nfs_pgio_header *); ++ __u64 mds_offset; /* Filelayout dense stripe */ ++ struct nfs_page_array page_array; ++ struct nfs_client *ds_clp; /* pNFS data server */ ++ int ds_idx; /* ds index if ds_clp is set */ + }; + + struct nfs_mds_commit_info { +@@ -1426,11 +1424,12 @@ struct nfs_rpc_ops { + struct nfs_pathconf *); + int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); + int (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, int); +- int (*pgio_rpc_prepare)(struct rpc_task *, struct nfs_pgio_data *); +- void (*read_setup) (struct nfs_pgio_data *, struct rpc_message *); +- int (*read_done) (struct rpc_task *, struct nfs_pgio_data *); +- void (*write_setup) (struct nfs_pgio_data *, struct rpc_message *); +- int (*write_done) (struct rpc_task *, struct nfs_pgio_data *); ++ int (*pgio_rpc_prepare)(struct rpc_task *, ++ struct nfs_pgio_header *); ++ void (*read_setup)(struct nfs_pgio_header *, struct rpc_message *); ++ int (*read_done)(struct rpc_task *, struct nfs_pgio_header *); ++ void (*write_setup)(struct nfs_pgio_header *, struct rpc_message *); ++ int (*write_done)(struct rpc_task *, struct nfs_pgio_header *); + void (*commit_setup) (struct nfs_commit_data *, struct rpc_message *); + void (*commit_rpc_prepare)(struct rpc_task *, struct nfs_commit_data *); + int (*commit_done) (struct rpc_task *, struct nfs_commit_data *); diff --git a/queue-3.16/nfs-move-nfs_pgio_data-and-remove-nfs_rw_header.patch b/queue-3.16/nfs-move-nfs_pgio_data-and-remove-nfs_rw_header.patch new file mode 100644 index 00000000000..ce60036a26d --- /dev/null +++ b/queue-3.16/nfs-move-nfs_pgio_data-and-remove-nfs_rw_header.patch @@ -0,0 +1,487 @@ +From trond.myklebust@primarydata.com Thu Oct 2 16:46:24 2014 +From: Trond Myklebust +Date: Mon, 15 Sep 2014 14:14:32 -0400 +Subject: nfs: move nfs_pgio_data and remove nfs_rw_header +To: stable@vger.kernel.org +Cc: Weston Andros Adamson , linux-nfs@vger.kernel.org +Message-ID: <1410804885-17228-2-git-send-email-trond.myklebust@primarydata.com> + +From: Weston Andros Adamson + +commit 1e7f3a485922211b6e4a082ebc6bf05810b0b6ea upstream. + +nfs_rw_header was used to allocate an nfs_pgio_header along with an +nfs_pgio_data, because a _header would need at least one _data. + +Now there is only ever one nfs_pgio_data for each nfs_pgio_header -- move +it to nfs_pgio_header and get rid of nfs_rw_header. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Weston Andros Adamson +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/direct.c | 8 ++-- + fs/nfs/internal.h | 6 +-- + fs/nfs/pagelist.c | 94 ++++++++++++++--------------------------------- + fs/nfs/pnfs.c | 24 +++++------- + fs/nfs/read.c | 6 +-- + fs/nfs/write.c | 10 ++--- + include/linux/nfs_page.h | 4 +- + include/linux/nfs_xdr.h | 38 ++++++++----------- + 8 files changed, 71 insertions(+), 119 deletions(-) + +--- a/fs/nfs/direct.c ++++ b/fs/nfs/direct.c +@@ -148,8 +148,8 @@ static void nfs_direct_set_hdr_verf(stru + { + struct nfs_writeverf *verfp; + +- verfp = nfs_direct_select_verf(dreq, hdr->data->ds_clp, +- hdr->data->ds_idx); ++ verfp = nfs_direct_select_verf(dreq, hdr->data.ds_clp, ++ hdr->data.ds_idx); + WARN_ON_ONCE(verfp->committed >= 0); + memcpy(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); + WARN_ON_ONCE(verfp->committed < 0); +@@ -169,8 +169,8 @@ static int nfs_direct_set_or_cmp_hdr_ver + { + struct nfs_writeverf *verfp; + +- verfp = nfs_direct_select_verf(dreq, hdr->data->ds_clp, +- hdr->data->ds_idx); ++ verfp = nfs_direct_select_verf(dreq, hdr->data.ds_clp, ++ hdr->data.ds_idx); + if (verfp->committed < 0) { + nfs_direct_set_hdr_verf(dreq, hdr); + return 0; +--- a/fs/nfs/internal.h ++++ b/fs/nfs/internal.h +@@ -238,9 +238,9 @@ void nfs_set_pgio_error(struct nfs_pgio_ + int nfs_iocounter_wait(struct nfs_io_counter *c); + + extern const struct nfs_pageio_ops nfs_pgio_rw_ops; +-struct nfs_rw_header *nfs_rw_header_alloc(const struct nfs_rw_ops *); +-void nfs_rw_header_free(struct nfs_pgio_header *); +-void nfs_pgio_data_release(struct nfs_pgio_data *); ++struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *); ++void nfs_pgio_header_free(struct nfs_pgio_header *); ++void nfs_pgio_data_destroy(struct nfs_pgio_data *); + int nfs_generic_pgio(struct nfs_pageio_descriptor *, struct nfs_pgio_header *); + int nfs_initiate_pgio(struct rpc_clnt *, struct nfs_pgio_data *, + const struct rpc_call_ops *, int, int); +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -462,95 +462,61 @@ size_t nfs_generic_pg_test(struct nfs_pa + } + EXPORT_SYMBOL_GPL(nfs_generic_pg_test); + +-static inline struct nfs_rw_header *NFS_RW_HEADER(struct nfs_pgio_header *hdr) ++struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *ops) + { +- return container_of(hdr, struct nfs_rw_header, header); +-} +- +-/** +- * nfs_rw_header_alloc - Allocate a header for a read or write +- * @ops: Read or write function vector +- */ +-struct nfs_rw_header *nfs_rw_header_alloc(const struct nfs_rw_ops *ops) +-{ +- struct nfs_rw_header *header = ops->rw_alloc_header(); +- +- if (header) { +- struct nfs_pgio_header *hdr = &header->header; ++ struct nfs_pgio_header *hdr = ops->rw_alloc_header(); + ++ if (hdr) { + INIT_LIST_HEAD(&hdr->pages); + spin_lock_init(&hdr->lock); + atomic_set(&hdr->refcnt, 0); + hdr->rw_ops = ops; + } +- return header; ++ return hdr; + } +-EXPORT_SYMBOL_GPL(nfs_rw_header_alloc); ++EXPORT_SYMBOL_GPL(nfs_pgio_header_alloc); + + /* +- * nfs_rw_header_free - Free a read or write header ++ * nfs_pgio_header_free - Free a read or write header + * @hdr: The header to free + */ +-void nfs_rw_header_free(struct nfs_pgio_header *hdr) ++void nfs_pgio_header_free(struct nfs_pgio_header *hdr) + { +- hdr->rw_ops->rw_free_header(NFS_RW_HEADER(hdr)); ++ hdr->rw_ops->rw_free_header(hdr); + } +-EXPORT_SYMBOL_GPL(nfs_rw_header_free); ++EXPORT_SYMBOL_GPL(nfs_pgio_header_free); + + /** + * nfs_pgio_data_alloc - Allocate pageio data + * @hdr: The header making a request + * @pagecount: Number of pages to create + */ +-static struct nfs_pgio_data *nfs_pgio_data_alloc(struct nfs_pgio_header *hdr, +- unsigned int pagecount) ++static bool nfs_pgio_data_init(struct nfs_pgio_header *hdr, ++ unsigned int pagecount) + { +- struct nfs_pgio_data *data, *prealloc; +- +- prealloc = &NFS_RW_HEADER(hdr)->rpc_data; +- if (prealloc->header == NULL) +- data = prealloc; +- else +- data = kzalloc(sizeof(*data), GFP_KERNEL); +- if (!data) +- goto out; +- +- if (nfs_pgarray_set(&data->pages, pagecount)) { +- data->header = hdr; ++ if (nfs_pgarray_set(&hdr->data.pages, pagecount)) { ++ hdr->data.header = hdr; + atomic_inc(&hdr->refcnt); +- } else { +- if (data != prealloc) +- kfree(data); +- data = NULL; ++ return true; + } +-out: +- return data; ++ return false; + } + + /** +- * nfs_pgio_data_release - Properly free pageio data +- * @data: The data to release ++ * nfs_pgio_data_destroy - Properly free pageio data ++ * @data: The data to destroy + */ +-void nfs_pgio_data_release(struct nfs_pgio_data *data) ++void nfs_pgio_data_destroy(struct nfs_pgio_data *data) + { + struct nfs_pgio_header *hdr = data->header; +- struct nfs_rw_header *pageio_header = NFS_RW_HEADER(hdr); + + put_nfs_open_context(data->args.context); + if (data->pages.pagevec != data->pages.page_array) + kfree(data->pages.pagevec); +- if (data == &pageio_header->rpc_data) { +- data->header = NULL; +- data = NULL; +- } + if (atomic_dec_and_test(&hdr->refcnt)) + hdr->completion_ops->completion(hdr); +- /* Note: we only free the rpc_task after callbacks are done. +- * See the comment in rpc_free_task() for why +- */ +- kfree(data); + } +-EXPORT_SYMBOL_GPL(nfs_pgio_data_release); ++EXPORT_SYMBOL_GPL(nfs_pgio_data_destroy); + + /** + * nfs_pgio_rpcsetup - Set up arguments for a pageio call +@@ -665,8 +631,7 @@ static int nfs_pgio_error(struct nfs_pag + struct nfs_pgio_header *hdr) + { + set_bit(NFS_IOHDR_REDO, &hdr->flags); +- nfs_pgio_data_release(hdr->data); +- hdr->data = NULL; ++ nfs_pgio_data_destroy(&hdr->data); + desc->pg_completion_ops->error_cleanup(&desc->pg_list); + return -ENOMEM; + } +@@ -680,7 +645,7 @@ static void nfs_pgio_release(void *calld + struct nfs_pgio_data *data = calldata; + if (data->header->rw_ops->rw_release) + data->header->rw_ops->rw_release(data); +- nfs_pgio_data_release(data); ++ nfs_pgio_data_destroy(data); + } + + /** +@@ -756,11 +721,11 @@ int nfs_generic_pgio(struct nfs_pageio_d + struct list_head *head = &desc->pg_list; + struct nfs_commit_info cinfo; + +- data = nfs_pgio_data_alloc(hdr, nfs_page_array_len(desc->pg_base, +- desc->pg_count)); +- if (!data) ++ if (!nfs_pgio_data_init(hdr, nfs_page_array_len(desc->pg_base, ++ desc->pg_count))) + return nfs_pgio_error(desc, hdr); + ++ data = &hdr->data; + nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq); + pages = data->pages.pagevec; + while (!list_empty(head)) { +@@ -776,7 +741,6 @@ int nfs_generic_pgio(struct nfs_pageio_d + + /* Set up the argument struct */ + nfs_pgio_rpcsetup(data, desc->pg_count, 0, desc->pg_ioflags, &cinfo); +- hdr->data = data; + desc->pg_rpc_callops = &nfs_pgio_common_ops; + return 0; + } +@@ -784,22 +748,20 @@ EXPORT_SYMBOL_GPL(nfs_generic_pgio); + + static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc) + { +- struct nfs_rw_header *rw_hdr; + struct nfs_pgio_header *hdr; + int ret; + +- rw_hdr = nfs_rw_header_alloc(desc->pg_rw_ops); +- if (!rw_hdr) { ++ hdr = nfs_pgio_header_alloc(desc->pg_rw_ops); ++ if (!hdr) { + desc->pg_completion_ops->error_cleanup(&desc->pg_list); + return -ENOMEM; + } +- hdr = &rw_hdr->header; +- nfs_pgheader_init(desc, hdr, nfs_rw_header_free); ++ nfs_pgheader_init(desc, hdr, nfs_pgio_header_free); + atomic_inc(&hdr->refcnt); + ret = nfs_generic_pgio(desc, hdr); + if (ret == 0) + ret = nfs_initiate_pgio(NFS_CLIENT(hdr->inode), +- hdr->data, desc->pg_rpc_callops, ++ &hdr->data, desc->pg_rpc_callops, + desc->pg_ioflags, 0); + if (atomic_dec_and_test(&hdr->refcnt)) + hdr->completion_ops->completion(hdr); +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -1546,7 +1546,7 @@ pnfs_write_through_mds(struct nfs_pageio + nfs_pageio_reset_write_mds(desc); + desc->pg_recoalesce = 1; + } +- nfs_pgio_data_release(data); ++ nfs_pgio_data_destroy(data); + } + + static enum pnfs_try_status +@@ -1575,7 +1575,7 @@ static void + pnfs_do_write(struct nfs_pageio_descriptor *desc, + struct nfs_pgio_header *hdr, int how) + { +- struct nfs_pgio_data *data = hdr->data; ++ struct nfs_pgio_data *data = &hdr->data; + const struct rpc_call_ops *call_ops = desc->pg_rpc_callops; + struct pnfs_layout_segment *lseg = desc->pg_lseg; + enum pnfs_try_status trypnfs; +@@ -1590,25 +1590,23 @@ pnfs_do_write(struct nfs_pageio_descript + static void pnfs_writehdr_free(struct nfs_pgio_header *hdr) + { + pnfs_put_lseg(hdr->lseg); +- nfs_rw_header_free(hdr); ++ nfs_pgio_header_free(hdr); + } + EXPORT_SYMBOL_GPL(pnfs_writehdr_free); + + int + pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc) + { +- struct nfs_rw_header *whdr; + struct nfs_pgio_header *hdr; + int ret; + +- whdr = nfs_rw_header_alloc(desc->pg_rw_ops); +- if (!whdr) { ++ hdr = nfs_pgio_header_alloc(desc->pg_rw_ops); ++ if (!hdr) { + desc->pg_completion_ops->error_cleanup(&desc->pg_list); + pnfs_put_lseg(desc->pg_lseg); + desc->pg_lseg = NULL; + return -ENOMEM; + } +- hdr = &whdr->header; + nfs_pgheader_init(desc, hdr, pnfs_writehdr_free); + hdr->lseg = pnfs_get_lseg(desc->pg_lseg); + atomic_inc(&hdr->refcnt); +@@ -1696,7 +1694,7 @@ pnfs_read_through_mds(struct nfs_pageio_ + nfs_pageio_reset_read_mds(desc); + desc->pg_recoalesce = 1; + } +- nfs_pgio_data_release(data); ++ nfs_pgio_data_destroy(data); + } + + /* +@@ -1727,7 +1725,7 @@ pnfs_try_to_read_data(struct nfs_pgio_da + static void + pnfs_do_read(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr) + { +- struct nfs_pgio_data *data = hdr->data; ++ struct nfs_pgio_data *data = &hdr->data; + const struct rpc_call_ops *call_ops = desc->pg_rpc_callops; + struct pnfs_layout_segment *lseg = desc->pg_lseg; + enum pnfs_try_status trypnfs; +@@ -1742,26 +1740,24 @@ pnfs_do_read(struct nfs_pageio_descripto + static void pnfs_readhdr_free(struct nfs_pgio_header *hdr) + { + pnfs_put_lseg(hdr->lseg); +- nfs_rw_header_free(hdr); ++ nfs_pgio_header_free(hdr); + } + EXPORT_SYMBOL_GPL(pnfs_readhdr_free); + + int + pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) + { +- struct nfs_rw_header *rhdr; + struct nfs_pgio_header *hdr; + int ret; + +- rhdr = nfs_rw_header_alloc(desc->pg_rw_ops); +- if (!rhdr) { ++ hdr = nfs_pgio_header_alloc(desc->pg_rw_ops); ++ if (!hdr) { + desc->pg_completion_ops->error_cleanup(&desc->pg_list); + ret = -ENOMEM; + pnfs_put_lseg(desc->pg_lseg); + desc->pg_lseg = NULL; + return ret; + } +- hdr = &rhdr->header; + nfs_pgheader_init(desc, hdr, pnfs_readhdr_free); + hdr->lseg = pnfs_get_lseg(desc->pg_lseg); + atomic_inc(&hdr->refcnt); +--- a/fs/nfs/read.c ++++ b/fs/nfs/read.c +@@ -33,12 +33,12 @@ static const struct nfs_rw_ops nfs_rw_re + + static struct kmem_cache *nfs_rdata_cachep; + +-static struct nfs_rw_header *nfs_readhdr_alloc(void) ++static struct nfs_pgio_header *nfs_readhdr_alloc(void) + { + return kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL); + } + +-static void nfs_readhdr_free(struct nfs_rw_header *rhdr) ++static void nfs_readhdr_free(struct nfs_pgio_header *rhdr) + { + kmem_cache_free(nfs_rdata_cachep, rhdr); + } +@@ -404,7 +404,7 @@ out: + int __init nfs_init_readpagecache(void) + { + nfs_rdata_cachep = kmem_cache_create("nfs_read_data", +- sizeof(struct nfs_rw_header), ++ sizeof(struct nfs_pgio_header), + 0, SLAB_HWCACHE_ALIGN, + NULL); + if (nfs_rdata_cachep == NULL) +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -71,18 +71,18 @@ void nfs_commit_free(struct nfs_commit_d + } + EXPORT_SYMBOL_GPL(nfs_commit_free); + +-static struct nfs_rw_header *nfs_writehdr_alloc(void) ++static struct nfs_pgio_header *nfs_writehdr_alloc(void) + { +- struct nfs_rw_header *p = mempool_alloc(nfs_wdata_mempool, GFP_NOIO); ++ struct nfs_pgio_header *p = mempool_alloc(nfs_wdata_mempool, GFP_NOIO); + + if (p) + memset(p, 0, sizeof(*p)); + return p; + } + +-static void nfs_writehdr_free(struct nfs_rw_header *whdr) ++static void nfs_writehdr_free(struct nfs_pgio_header *hdr) + { +- mempool_free(whdr, nfs_wdata_mempool); ++ mempool_free(hdr, nfs_wdata_mempool); + } + + static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error) +@@ -1884,7 +1884,7 @@ int nfs_migrate_page(struct address_spac + int __init nfs_init_writepagecache(void) + { + nfs_wdata_cachep = kmem_cache_create("nfs_write_data", +- sizeof(struct nfs_rw_header), ++ sizeof(struct nfs_pgio_header), + 0, SLAB_HWCACHE_ALIGN, + NULL); + if (nfs_wdata_cachep == NULL) +--- a/include/linux/nfs_page.h ++++ b/include/linux/nfs_page.h +@@ -62,8 +62,8 @@ struct nfs_pageio_ops { + + struct nfs_rw_ops { + const fmode_t rw_mode; +- struct nfs_rw_header *(*rw_alloc_header)(void); +- void (*rw_free_header)(struct nfs_rw_header *); ++ struct nfs_pgio_header *(*rw_alloc_header)(void); ++ void (*rw_free_header)(struct nfs_pgio_header *); + void (*rw_release)(struct nfs_pgio_data *); + int (*rw_done)(struct rpc_task *, struct nfs_pgio_data *, struct inode *); + void (*rw_result)(struct rpc_task *, struct nfs_pgio_data *); +--- a/include/linux/nfs_xdr.h ++++ b/include/linux/nfs_xdr.h +@@ -1257,13 +1257,27 @@ enum { + NFS_IOHDR_NEED_RESCHED, + }; + +-struct nfs_pgio_data; ++struct nfs_pgio_data { ++ struct nfs_pgio_header *header; ++ struct list_head list; ++ struct rpc_task task; ++ struct nfs_fattr fattr; ++ struct nfs_writeverf verf; /* Used for writes */ ++ struct nfs_pgio_args args; /* argument struct */ ++ struct nfs_pgio_res res; /* result struct */ ++ unsigned long timestamp; /* For lease renewal */ ++ int (*pgio_done_cb)(struct rpc_task *task, struct nfs_pgio_data *data); ++ __u64 mds_offset; /* Filelayout dense stripe */ ++ struct nfs_page_array pages; ++ struct nfs_client *ds_clp; /* pNFS data server */ ++ int ds_idx; /* ds index if ds_clp is set */ ++}; + + struct nfs_pgio_header { + struct inode *inode; + struct rpc_cred *cred; + struct list_head pages; +- struct nfs_pgio_data *data; ++ struct nfs_pgio_data data; + atomic_t refcnt; + struct nfs_page *req; + struct nfs_writeverf verf; /* Used for writes */ +@@ -1283,26 +1297,6 @@ struct nfs_pgio_header { + unsigned long flags; + }; + +-struct nfs_pgio_data { +- struct nfs_pgio_header *header; +- struct rpc_task task; +- struct nfs_fattr fattr; +- struct nfs_writeverf verf; /* Used for writes */ +- struct nfs_pgio_args args; /* argument struct */ +- struct nfs_pgio_res res; /* result struct */ +- unsigned long timestamp; /* For lease renewal */ +- int (*pgio_done_cb) (struct rpc_task *task, struct nfs_pgio_data *data); +- __u64 mds_offset; /* Filelayout dense stripe */ +- struct nfs_page_array pages; +- struct nfs_client *ds_clp; /* pNFS data server */ +- int ds_idx; /* ds index if ds_clp is set */ +-}; +- +-struct nfs_rw_header { +- struct nfs_pgio_header header; +- struct nfs_pgio_data rpc_data; +-}; +- + struct nfs_mds_commit_info { + atomic_t rpcs_out; + unsigned long ncommit; diff --git a/queue-3.16/nfs-remove-pgio_header-refcount-related-cleanup.patch b/queue-3.16/nfs-remove-pgio_header-refcount-related-cleanup.patch new file mode 100644 index 00000000000..b167dcb5e58 --- /dev/null +++ b/queue-3.16/nfs-remove-pgio_header-refcount-related-cleanup.patch @@ -0,0 +1,163 @@ +From trond.myklebust@primarydata.com Thu Oct 2 16:48:39 2014 +From: Trond Myklebust +Date: Mon, 15 Sep 2014 14:14:35 -0400 +Subject: nfs: remove pgio_header refcount, related cleanup +To: stable@vger.kernel.org +Cc: Weston Andros Adamson , linux-nfs@vger.kernel.org +Message-ID: <1410804885-17228-5-git-send-email-trond.myklebust@primarydata.com> + + +From: Weston Andros Adamson + +commit 4714fb51fd03a14d8c73001438283e7f7b752f1e upstream. + +The refcounting on nfs_pgio_header was related to there being (possibly) +more than one nfs_pgio_data. Now that nfs_pgio_data has been merged into +nfs_pgio_header, there is no reason to do this ref counting. Just call +the completion callback on nfs_pgio_release/nfs_pgio_error. + +Signed-off-by: Weston Andros Adamson +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/pagelist.c | 36 +++++++++++------------------------- + fs/nfs/pnfs.c | 6 ------ + include/linux/nfs_xdr.h | 1 - + 3 files changed, 11 insertions(+), 32 deletions(-) + +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -469,7 +469,6 @@ struct nfs_pgio_header *nfs_pgio_header_ + if (hdr) { + INIT_LIST_HEAD(&hdr->pages); + spin_lock_init(&hdr->lock); +- atomic_set(&hdr->refcnt, 0); + hdr->rw_ops = ops; + } + return hdr; +@@ -487,31 +486,18 @@ void nfs_pgio_header_free(struct nfs_pgi + EXPORT_SYMBOL_GPL(nfs_pgio_header_free); + + /** +- * nfs_pgio_data_alloc - Allocate pageio data +- * @hdr: The header making a request +- * @pagecount: Number of pages to create +- */ +-static bool nfs_pgio_data_init(struct nfs_pgio_header *hdr, +- unsigned int pagecount) +-{ +- if (nfs_pgarray_set(&hdr->page_array, pagecount)) { +- atomic_inc(&hdr->refcnt); +- return true; +- } +- return false; +-} +- +-/** +- * nfs_pgio_data_destroy - Properly release pageio data +- * @hdr: The header with data to destroy ++ * nfs_pgio_data_destroy - make @hdr suitable for reuse ++ * ++ * Frees memory and releases refs from nfs_generic_pgio, so that it may ++ * be called again. ++ * ++ * @hdr: A header that has had nfs_generic_pgio called + */ + void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr) + { + put_nfs_open_context(hdr->args.context); + if (hdr->page_array.pagevec != hdr->page_array.page_array) + kfree(hdr->page_array.pagevec); +- if (atomic_dec_and_test(&hdr->refcnt)) +- hdr->completion_ops->completion(hdr); + } + EXPORT_SYMBOL_GPL(nfs_pgio_data_destroy); + +@@ -630,6 +616,7 @@ static int nfs_pgio_error(struct nfs_pag + { + set_bit(NFS_IOHDR_REDO, &hdr->flags); + nfs_pgio_data_destroy(hdr); ++ hdr->completion_ops->completion(hdr); + desc->pg_completion_ops->error_cleanup(&desc->pg_list); + return -ENOMEM; + } +@@ -644,6 +631,7 @@ static void nfs_pgio_release(void *calld + if (hdr->rw_ops->rw_release) + hdr->rw_ops->rw_release(hdr); + nfs_pgio_data_destroy(hdr); ++ hdr->completion_ops->completion(hdr); + } + + /** +@@ -717,9 +705,10 @@ int nfs_generic_pgio(struct nfs_pageio_d + struct page **pages; + struct list_head *head = &desc->pg_list; + struct nfs_commit_info cinfo; ++ unsigned int pagecount; + +- if (!nfs_pgio_data_init(hdr, nfs_page_array_len(desc->pg_base, +- desc->pg_count))) ++ pagecount = nfs_page_array_len(desc->pg_base, desc->pg_count); ++ if (!nfs_pgarray_set(&hdr->page_array, pagecount)) + return nfs_pgio_error(desc, hdr); + + nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq); +@@ -753,14 +742,11 @@ static int nfs_generic_pg_pgios(struct n + return -ENOMEM; + } + nfs_pgheader_init(desc, hdr, nfs_pgio_header_free); +- atomic_inc(&hdr->refcnt); + ret = nfs_generic_pgio(desc, hdr); + if (ret == 0) + ret = nfs_initiate_pgio(NFS_CLIENT(hdr->inode), + hdr, desc->pg_rpc_callops, + desc->pg_ioflags, 0); +- if (atomic_dec_and_test(&hdr->refcnt)) +- hdr->completion_ops->completion(hdr); + return ret; + } + +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -1602,15 +1602,12 @@ pnfs_generic_pg_writepages(struct nfs_pa + } + nfs_pgheader_init(desc, hdr, pnfs_writehdr_free); + hdr->lseg = pnfs_get_lseg(desc->pg_lseg); +- atomic_inc(&hdr->refcnt); + ret = nfs_generic_pgio(desc, hdr); + if (ret != 0) { + pnfs_put_lseg(desc->pg_lseg); + desc->pg_lseg = NULL; + } else + pnfs_do_write(desc, hdr, desc->pg_ioflags); +- if (atomic_dec_and_test(&hdr->refcnt)) +- hdr->completion_ops->completion(hdr); + return ret; + } + EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages); +@@ -1745,15 +1742,12 @@ pnfs_generic_pg_readpages(struct nfs_pag + } + nfs_pgheader_init(desc, hdr, pnfs_readhdr_free); + hdr->lseg = pnfs_get_lseg(desc->pg_lseg); +- atomic_inc(&hdr->refcnt); + ret = nfs_generic_pgio(desc, hdr); + if (ret != 0) { + pnfs_put_lseg(desc->pg_lseg); + desc->pg_lseg = NULL; + } else + pnfs_do_read(desc, hdr); +- if (atomic_dec_and_test(&hdr->refcnt)) +- hdr->completion_ops->completion(hdr); + return ret; + } + EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages); +--- a/include/linux/nfs_xdr.h ++++ b/include/linux/nfs_xdr.h +@@ -1261,7 +1261,6 @@ struct nfs_pgio_header { + struct inode *inode; + struct rpc_cred *cred; + struct list_head pages; +- atomic_t refcnt; + struct nfs_page *req; + struct nfs_writeverf verf; /* Used for writes */ + struct pnfs_layout_segment *lseg; diff --git a/queue-3.16/nfs-rename-members-of-nfs_pgio_data.patch b/queue-3.16/nfs-rename-members-of-nfs_pgio_data.patch new file mode 100644 index 00000000000..63e13378474 --- /dev/null +++ b/queue-3.16/nfs-rename-members-of-nfs_pgio_data.patch @@ -0,0 +1,209 @@ +From trond.myklebust@primarydata.com Thu Oct 2 16:46:37 2014 +From: Trond Myklebust +Date: Mon, 15 Sep 2014 14:14:33 -0400 +Subject: nfs: rename members of nfs_pgio_data +To: stable@vger.kernel.org +Cc: Weston Andros Adamson , linux-nfs@vger.kernel.org +Message-ID: <1410804885-17228-3-git-send-email-trond.myklebust@primarydata.com> + + +From: Weston Andros Adamson + +commit 823b0c9d9800e712374cda89ac3565bd29f6701b upstream. + +Rename "verf" to "writeverf" and "pages" to "page_array" to prepare for +merge of nfs_pgio_data and nfs_pgio_header. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Weston Andros Adamson +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/blocklayout/blocklayout.c | 17 ++++++++++------- + fs/nfs/objlayout/objlayout.c | 4 ++-- + fs/nfs/pagelist.c | 12 ++++++------ + fs/nfs/write.c | 9 +++++---- + include/linux/nfs_xdr.h | 4 ++-- + 5 files changed, 25 insertions(+), 21 deletions(-) + +--- a/fs/nfs/blocklayout/blocklayout.c ++++ b/fs/nfs/blocklayout/blocklayout.c +@@ -258,7 +258,8 @@ bl_read_pagelist(struct nfs_pgio_data *r + const bool is_dio = (header->dreq != NULL); + + dprintk("%s enter nr_pages %u offset %lld count %u\n", __func__, +- rdata->pages.npages, f_offset, (unsigned int)rdata->args.count); ++ rdata->page_array.npages, f_offset, ++ (unsigned int)rdata->args.count); + + par = alloc_parallel(rdata); + if (!par) +@@ -268,7 +269,7 @@ bl_read_pagelist(struct nfs_pgio_data *r + + isect = (sector_t) (f_offset >> SECTOR_SHIFT); + /* Code assumes extents are page-aligned */ +- for (i = pg_index; i < rdata->pages.npages; i++) { ++ for (i = pg_index; i < rdata->page_array.npages; i++) { + if (!extent_length) { + /* We've used up the previous extent */ + bl_put_extent(be); +@@ -317,7 +318,8 @@ bl_read_pagelist(struct nfs_pgio_data *r + struct pnfs_block_extent *be_read; + + be_read = (hole && cow_read) ? cow_read : be; +- bio = do_add_page_to_bio(bio, rdata->pages.npages - i, ++ bio = do_add_page_to_bio(bio, ++ rdata->page_array.npages - i, + READ, + isect, pages[i], be_read, + bl_end_io_read, par, +@@ -446,7 +448,7 @@ static void bl_end_par_io_write(void *da + } + + wdata->task.tk_status = wdata->header->pnfs_error; +- wdata->verf.committed = NFS_FILE_SYNC; ++ wdata->writeverf.committed = NFS_FILE_SYNC; + INIT_WORK(&wdata->task.u.tk_work, bl_write_cleanup); + schedule_work(&wdata->task.u.tk_work); + } +@@ -699,7 +701,7 @@ bl_write_pagelist(struct nfs_pgio_data * + dprintk("pnfsblock nonblock aligned DIO writes. Resend MDS\n"); + goto out_mds; + } +- /* At this point, wdata->pages is a (sequential) list of nfs_pages. ++ /* At this point, wdata->page_aray is a (sequential) list of nfs_pages. + * We want to write each, and if there is an error set pnfs_error + * to have it redone using nfs. + */ +@@ -791,7 +793,7 @@ next_page: + + /* Middle pages */ + pg_index = wdata->args.pgbase >> PAGE_CACHE_SHIFT; +- for (i = pg_index; i < wdata->pages.npages; i++) { ++ for (i = pg_index; i < wdata->page_array.npages; i++) { + if (!extent_length) { + /* We've used up the previous extent */ + bl_put_extent(be); +@@ -862,7 +864,8 @@ next_page: + } + + +- bio = do_add_page_to_bio(bio, wdata->pages.npages - i, WRITE, ++ bio = do_add_page_to_bio(bio, wdata->page_array.npages - i, ++ WRITE, + isect, pages[i], be, + bl_end_io_write, par, + pg_offset, pg_len); +--- a/fs/nfs/objlayout/objlayout.c ++++ b/fs/nfs/objlayout/objlayout.c +@@ -329,7 +329,7 @@ objlayout_write_done(struct objlayout_io + oir->status = wdata->task.tk_status = status; + if (status >= 0) { + wdata->res.count = status; +- wdata->verf.committed = oir->committed; ++ wdata->writeverf.committed = oir->committed; + } else { + wdata->header->pnfs_error = status; + } +@@ -337,7 +337,7 @@ objlayout_write_done(struct objlayout_io + /* must not use oir after this point */ + + dprintk("%s: Return status %zd committed %d sync=%d\n", __func__, +- status, wdata->verf.committed, sync); ++ status, wdata->writeverf.committed, sync); + + if (sync) + pnfs_ld_write_done(wdata); +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -494,7 +494,7 @@ EXPORT_SYMBOL_GPL(nfs_pgio_header_free); + static bool nfs_pgio_data_init(struct nfs_pgio_header *hdr, + unsigned int pagecount) + { +- if (nfs_pgarray_set(&hdr->data.pages, pagecount)) { ++ if (nfs_pgarray_set(&hdr->data.page_array, pagecount)) { + hdr->data.header = hdr; + atomic_inc(&hdr->refcnt); + return true; +@@ -511,8 +511,8 @@ void nfs_pgio_data_destroy(struct nfs_pg + struct nfs_pgio_header *hdr = data->header; + + put_nfs_open_context(data->args.context); +- if (data->pages.pagevec != data->pages.page_array) +- kfree(data->pages.pagevec); ++ if (data->page_array.pagevec != data->page_array.page_array) ++ kfree(data->page_array.pagevec); + if (atomic_dec_and_test(&hdr->refcnt)) + hdr->completion_ops->completion(hdr); + } +@@ -540,7 +540,7 @@ static void nfs_pgio_rpcsetup(struct nfs + /* pnfs_set_layoutcommit needs this */ + data->mds_offset = data->args.offset; + data->args.pgbase = req->wb_pgbase + offset; +- data->args.pages = data->pages.pagevec; ++ data->args.pages = data->page_array.pagevec; + data->args.count = count; + data->args.context = get_nfs_open_context(req->wb_context); + data->args.lock_context = req->wb_lock_context; +@@ -558,7 +558,7 @@ static void nfs_pgio_rpcsetup(struct nfs + data->res.fattr = &data->fattr; + data->res.count = count; + data->res.eof = 0; +- data->res.verf = &data->verf; ++ data->res.verf = &data->writeverf; + nfs_fattr_init(&data->fattr); + } + +@@ -727,7 +727,7 @@ int nfs_generic_pgio(struct nfs_pageio_d + + data = &hdr->data; + nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq); +- pages = data->pages.pagevec; ++ pages = data->page_array.pagevec; + while (!list_empty(head)) { + req = nfs_list_entry(head->next); + nfs_list_remove_request(req); +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -828,9 +828,9 @@ nfs_clear_request_commit(struct nfs_page + static inline + int nfs_write_need_commit(struct nfs_pgio_data *data) + { +- if (data->verf.committed == NFS_DATA_SYNC) ++ if (data->writeverf.committed == NFS_DATA_SYNC) + return data->header->lseg == NULL; +- return data->verf.committed != NFS_FILE_SYNC; ++ return data->writeverf.committed != NFS_FILE_SYNC; + } + + #else +@@ -1323,8 +1323,9 @@ static void nfs_writeback_release_common + if (test_bit(NFS_IOHDR_NEED_RESCHED, &hdr->flags)) + ; /* Do nothing */ + else if (!test_and_set_bit(NFS_IOHDR_NEED_COMMIT, &hdr->flags)) +- memcpy(&hdr->verf, &data->verf, sizeof(hdr->verf)); +- else if (memcmp(&hdr->verf, &data->verf, sizeof(hdr->verf))) ++ memcpy(&hdr->verf, &data->writeverf, sizeof(hdr->verf)); ++ else if (memcmp(&hdr->verf, &data->writeverf, ++ sizeof(hdr->verf))) + set_bit(NFS_IOHDR_NEED_RESCHED, &hdr->flags); + spin_unlock(&hdr->lock); + } +--- a/include/linux/nfs_xdr.h ++++ b/include/linux/nfs_xdr.h +@@ -1262,13 +1262,13 @@ struct nfs_pgio_data { + struct list_head list; + struct rpc_task task; + struct nfs_fattr fattr; +- struct nfs_writeverf verf; /* Used for writes */ ++ struct nfs_writeverf writeverf; /* Used for writes */ + struct nfs_pgio_args args; /* argument struct */ + struct nfs_pgio_res res; /* result struct */ + unsigned long timestamp; /* For lease renewal */ + int (*pgio_done_cb)(struct rpc_task *task, struct nfs_pgio_data *data); + __u64 mds_offset; /* Filelayout dense stripe */ +- struct nfs_page_array pages; ++ struct nfs_page_array page_array; + struct nfs_client *ds_clp; /* pNFS data server */ + int ds_idx; /* ds index if ds_clp is set */ + }; diff --git a/queue-3.16/nfs-use-blocking-page_group_lock-in-add_request.patch b/queue-3.16/nfs-use-blocking-page_group_lock-in-add_request.patch new file mode 100644 index 00000000000..d74085d8ca8 --- /dev/null +++ b/queue-3.16/nfs-use-blocking-page_group_lock-in-add_request.patch @@ -0,0 +1,58 @@ +From trond.myklebust@primarydata.com Thu Oct 2 16:49:39 2014 +From: Trond Myklebust +Date: Mon, 15 Sep 2014 14:14:41 -0400 +Subject: nfs: use blocking page_group_lock in add_request +To: stable@vger.kernel.org +Cc: Weston Andros Adamson , linux-nfs@vger.kernel.org +Message-ID: <1410804885-17228-11-git-send-email-trond.myklebust@primarydata.com> + + +From: Weston Andros Adamson + +commit bfd484a5606d6a0379a0a2f04251b1e5c1f8995c upstream. + +__nfs_pageio_add_request was calling nfs_page_group_lock nonblocking, but +this can return -EAGAIN which would end up passing -EIO to the application. + +There is no reason not to block in this path, so change the two calls to +do so. Also, there is no need to check the return value of +nfs_page_group_lock when nonblock=false, so remove the error handling code. + +Signed-off-by: Weston Andros Adamson +Reviewed-by: Peng Tao +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/pagelist.c | 13 ++----------- + 1 file changed, 2 insertions(+), 11 deletions(-) + +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -873,13 +873,8 @@ static int __nfs_pageio_add_request(stru + struct nfs_page *subreq; + unsigned int bytes_left = 0; + unsigned int offset, pgbase; +- int ret; + +- ret = nfs_page_group_lock(req, true); +- if (ret < 0) { +- desc->pg_error = ret; +- return 0; +- } ++ nfs_page_group_lock(req, false); + + subreq = req; + bytes_left = subreq->wb_bytes; +@@ -901,11 +896,7 @@ static int __nfs_pageio_add_request(stru + if (desc->pg_recoalesce) + return 0; + /* retry add_request for this subreq */ +- ret = nfs_page_group_lock(req, true); +- if (ret < 0) { +- desc->pg_error = ret; +- return 0; +- } ++ nfs_page_group_lock(req, false); + continue; + } + diff --git a/queue-3.16/nfsd4-fix-corruption-of-nfsv4-read-data.patch b/queue-3.16/nfsd4-fix-corruption-of-nfsv4-read-data.patch new file mode 100644 index 00000000000..f894b298526 --- /dev/null +++ b/queue-3.16/nfsd4-fix-corruption-of-nfsv4-read-data.patch @@ -0,0 +1,50 @@ +From 15b23ef5d348ea51c5e7573e2ef4116fbc7cb099 Mon Sep 17 00:00:00 2001 +From: "J. Bruce Fields" +Date: Wed, 24 Sep 2014 16:32:34 -0400 +Subject: nfsd4: fix corruption of NFSv4 read data + +From: "J. Bruce Fields" + +commit 15b23ef5d348ea51c5e7573e2ef4116fbc7cb099 upstream. + +The calculation of page_ptr here is wrong in the case the read doesn't +start at an offset that is a multiple of a page. + +The result is that nfs4svc_encode_compoundres sets rq_next_page to a +value one too small, and then the loop in svc_free_res_pages may +incorrectly fail to clear a page pointer in rq_respages[]. + +Pages left in rq_respages[] are available for the next rpc request to +use, so xdr data may be written to that page, which may hold data still +waiting to be transmitted to the client or data in the page cache. + +The observed result was silent data corruption seen on an NFSv4 client. + +We tag this as "fixing" 05638dc73af2 because that commit exposed this +bug, though the incorrect calculation predates it. + +Particular thanks to Andrea Arcangeli and David Gilbert for analysis and +testing. + +Fixes: 05638dc73af2 "nfsd4: simplify server xdr->next_page use" +Reported-by: Andrea Arcangeli +Tested-by: "Dr. David Alan Gilbert" +Signed-off-by: J. Bruce Fields +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfsd/nfs4xdr.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -3112,7 +3112,8 @@ static __be32 nfsd4_encode_splice_read( + + buf->page_len = maxcount; + buf->len += maxcount; +- xdr->page_ptr += (maxcount + PAGE_SIZE - 1) / PAGE_SIZE; ++ xdr->page_ptr += (buf->page_base + maxcount + PAGE_SIZE - 1) ++ / PAGE_SIZE; + + /* Use rest of head for padding and remaining ops: */ + buf->tail[0].iov_base = xdr->p; diff --git a/queue-3.16/nfsd4-fix-rd_dircount-enforcement.patch b/queue-3.16/nfsd4-fix-rd_dircount-enforcement.patch new file mode 100644 index 00000000000..29b30d12118 --- /dev/null +++ b/queue-3.16/nfsd4-fix-rd_dircount-enforcement.patch @@ -0,0 +1,60 @@ +From aee3776441461c14ba6d8ed9e2149933e65abb6e Mon Sep 17 00:00:00 2001 +From: "J. Bruce Fields" +Date: Wed, 20 Aug 2014 14:49:50 -0400 +Subject: nfsd4: fix rd_dircount enforcement + +From: "J. Bruce Fields" + +commit aee3776441461c14ba6d8ed9e2149933e65abb6e upstream. + +Commit 3b299709091b "nfsd4: enforce rd_dircount" totally misunderstood +rd_dircount; it refers to total non-attribute bytes returned, not number +of directory entries returned. + +Bring the code into agreement with RFC 3530 section 14.2.24. + +Fixes: 3b299709091b "nfsd4: enforce rd_dircount" +Signed-off-by: J. Bruce Fields +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfsd/nfs4xdr.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2662,6 +2662,7 @@ nfsd4_encode_dirent(void *ccdv, const ch + struct xdr_stream *xdr = cd->xdr; + int start_offset = xdr->buf->len; + int cookie_offset; ++ u32 name_and_cookie; + int entry_bytes; + __be32 nfserr = nfserr_toosmall; + __be64 wire_offset; +@@ -2723,7 +2724,14 @@ nfsd4_encode_dirent(void *ccdv, const ch + cd->rd_maxcount -= entry_bytes; + if (!cd->rd_dircount) + goto fail; +- cd->rd_dircount--; ++ /* ++ * RFC 3530 14.2.24 describes rd_dircount as only a "hint", so ++ * let's always let through the first entry, at least: ++ */ ++ name_and_cookie = 4 * XDR_QUADLEN(namlen) + 8; ++ if (name_and_cookie > cd->rd_dircount && cd->cookie_offset) ++ goto fail; ++ cd->rd_dircount -= min(cd->rd_dircount, name_and_cookie); + cd->cookie_offset = cookie_offset; + skip_entry: + cd->common.err = nfs_ok; +@@ -3333,6 +3341,10 @@ nfsd4_encode_readdir(struct nfsd4_compou + } + maxcount = min_t(int, maxcount-16, bytes_left); + ++ /* RFC 3530 14.2.24 allows us to ignore dircount when it's 0: */ ++ if (!readdir->rd_dircount) ++ readdir->rd_dircount = INT_MAX; ++ + readdir->xdr = xdr; + readdir->rd_maxcount = maxcount; + readdir->common.err = 0; diff --git a/queue-3.16/nfsv4-fix-another-bug-in-the-close-open_downgrade-code.patch b/queue-3.16/nfsv4-fix-another-bug-in-the-close-open_downgrade-code.patch new file mode 100644 index 00000000000..b1341d21ec4 --- /dev/null +++ b/queue-3.16/nfsv4-fix-another-bug-in-the-close-open_downgrade-code.patch @@ -0,0 +1,65 @@ +From cd9288ffaea4359d5cfe2b8d264911506aed26a4 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Thu, 18 Sep 2014 11:51:32 -0400 +Subject: NFSv4: Fix another bug in the close/open_downgrade code + +From: Trond Myklebust + +commit cd9288ffaea4359d5cfe2b8d264911506aed26a4 upstream. + +James Drew reports another bug whereby the NFS client is now sending +an OPEN_DOWNGRADE in a situation where it should really have sent a +CLOSE: the client is opening the file for O_RDWR, but then trying to +do a downgrade to O_RDONLY, which is not allowed by the NFSv4 spec. + +Reported-by: James Drews +Link: http://lkml.kernel.org/r/541AD7E5.8020409@engr.wisc.edu +Fixes: aee7af356e15 (NFSv4: Fix problems with close in the presence...) +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs4proc.c | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -2599,23 +2599,23 @@ static void nfs4_close_prepare(struct rp + is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags); + is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags); + is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags); +- /* Calculate the current open share mode */ +- calldata->arg.fmode = 0; +- if (is_rdonly || is_rdwr) +- calldata->arg.fmode |= FMODE_READ; +- if (is_wronly || is_rdwr) +- calldata->arg.fmode |= FMODE_WRITE; + /* Calculate the change in open mode */ ++ calldata->arg.fmode = 0; + if (state->n_rdwr == 0) { +- if (state->n_rdonly == 0) { +- call_close |= is_rdonly || is_rdwr; +- calldata->arg.fmode &= ~FMODE_READ; +- } +- if (state->n_wronly == 0) { +- call_close |= is_wronly || is_rdwr; +- calldata->arg.fmode &= ~FMODE_WRITE; +- } +- } ++ if (state->n_rdonly == 0) ++ call_close |= is_rdonly; ++ else if (is_rdonly) ++ calldata->arg.fmode |= FMODE_READ; ++ if (state->n_wronly == 0) ++ call_close |= is_wronly; ++ else if (is_wronly) ++ calldata->arg.fmode |= FMODE_WRITE; ++ } else if (is_rdwr) ++ calldata->arg.fmode |= FMODE_READ|FMODE_WRITE; ++ ++ if (calldata->arg.fmode == 0) ++ call_close |= is_rdwr; ++ + if (!nfs4_valid_open_stateid(state)) + call_close = 0; + spin_unlock(&state->owner->so_lock); diff --git a/queue-3.16/nfsv4-nfs4_state_manager-vs.-nfs_server_remove_lists.patch b/queue-3.16/nfsv4-nfs4_state_manager-vs.-nfs_server_remove_lists.patch new file mode 100644 index 00000000000..5654486c08d --- /dev/null +++ b/queue-3.16/nfsv4-nfs4_state_manager-vs.-nfs_server_remove_lists.patch @@ -0,0 +1,101 @@ +From 080af20cc945d110f9912d01cf6b66f94a375b8d Mon Sep 17 00:00:00 2001 +From: Steve Dickson +Date: Thu, 18 Sep 2014 09:13:17 -0400 +Subject: NFSv4: nfs4_state_manager() vs. nfs_server_remove_lists() + +From: Steve Dickson + +commit 080af20cc945d110f9912d01cf6b66f94a375b8d upstream. + +There is a race between nfs4_state_manager() and +nfs_server_remove_lists() that happens during a nfsv3 mount. + +The v3 mount notices there is already a supper block so +nfs_server_remove_lists() called which uses the nfs_client_lock +spin lock to synchronize access to the client list. + +At the same time nfs4_state_manager() is running through +the client list looking for work to do, using the same +lock. When nfs4_state_manager() wins the race to the +list, a v3 client pointer is found and not ignored +properly which causes the panic. + +Moving some protocol checks before the state checking +avoids the panic. + +Signed-off-by: Steve Dickson +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs4client.c | 38 ++++++++++++++++++++------------------ + 1 file changed, 20 insertions(+), 18 deletions(-) + +--- a/fs/nfs/nfs4client.c ++++ b/fs/nfs/nfs4client.c +@@ -482,6 +482,16 @@ int nfs40_walk_client_list(struct nfs_cl + + spin_lock(&nn->nfs_client_lock); + list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { ++ ++ if (pos->rpc_ops != new->rpc_ops) ++ continue; ++ ++ if (pos->cl_proto != new->cl_proto) ++ continue; ++ ++ if (pos->cl_minorversion != new->cl_minorversion) ++ continue; ++ + /* If "pos" isn't marked ready, we can't trust the + * remaining fields in "pos" */ + if (pos->cl_cons_state > NFS_CS_READY) { +@@ -501,15 +511,6 @@ int nfs40_walk_client_list(struct nfs_cl + if (pos->cl_cons_state != NFS_CS_READY) + continue; + +- if (pos->rpc_ops != new->rpc_ops) +- continue; +- +- if (pos->cl_proto != new->cl_proto) +- continue; +- +- if (pos->cl_minorversion != new->cl_minorversion) +- continue; +- + if (pos->cl_clientid != new->cl_clientid) + continue; + +@@ -622,6 +623,16 @@ int nfs41_walk_client_list(struct nfs_cl + + spin_lock(&nn->nfs_client_lock); + list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { ++ ++ if (pos->rpc_ops != new->rpc_ops) ++ continue; ++ ++ if (pos->cl_proto != new->cl_proto) ++ continue; ++ ++ if (pos->cl_minorversion != new->cl_minorversion) ++ continue; ++ + /* If "pos" isn't marked ready, we can't trust the + * remaining fields in "pos", especially the client + * ID and serverowner fields. Wait for CREATE_SESSION +@@ -647,15 +658,6 @@ int nfs41_walk_client_list(struct nfs_cl + if (pos->cl_cons_state != NFS_CS_READY) + continue; + +- if (pos->rpc_ops != new->rpc_ops) +- continue; +- +- if (pos->cl_proto != new->cl_proto) +- continue; +- +- if (pos->cl_minorversion != new->cl_minorversion) +- continue; +- + if (!nfs4_match_clientids(pos, new)) + continue; + diff --git a/queue-3.16/pnfs-add-pnfs_put_lseg_async.patch b/queue-3.16/pnfs-add-pnfs_put_lseg_async.patch new file mode 100644 index 00000000000..01820fb5a70 --- /dev/null +++ b/queue-3.16/pnfs-add-pnfs_put_lseg_async.patch @@ -0,0 +1,86 @@ +From trond.myklebust@primarydata.com Thu Oct 2 16:49:03 2014 +From: Trond Myklebust +Date: Mon, 15 Sep 2014 14:14:37 -0400 +Subject: pnfs: add pnfs_put_lseg_async +To: stable@vger.kernel.org +Cc: Weston Andros Adamson , linux-nfs@vger.kernel.org +Message-ID: <1410804885-17228-7-git-send-email-trond.myklebust@primarydata.com> + + +From: Weston Andros Adamson + +commit e6cf82d1830f5e16a10d566f58db70f297ba5da8 upstream. + +This is useful when lsegs need to be released while holding locks. + +Signed-off-by: Weston Andros Adamson +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/pnfs.c | 17 +++++++++++++++++ + fs/nfs/pnfs.h | 7 +++++++ + 2 files changed, 24 insertions(+) + +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -361,6 +361,23 @@ pnfs_put_lseg(struct pnfs_layout_segment + } + EXPORT_SYMBOL_GPL(pnfs_put_lseg); + ++static void pnfs_put_lseg_async_work(struct work_struct *work) ++{ ++ struct pnfs_layout_segment *lseg; ++ ++ lseg = container_of(work, struct pnfs_layout_segment, pls_work); ++ ++ pnfs_put_lseg(lseg); ++} ++ ++void ++pnfs_put_lseg_async(struct pnfs_layout_segment *lseg) ++{ ++ INIT_WORK(&lseg->pls_work, pnfs_put_lseg_async_work); ++ schedule_work(&lseg->pls_work); ++} ++EXPORT_SYMBOL_GPL(pnfs_put_lseg_async); ++ + static u64 + end_offset(u64 start, u64 len) + { +--- a/fs/nfs/pnfs.h ++++ b/fs/nfs/pnfs.h +@@ -32,6 +32,7 @@ + + #include + #include ++#include + + enum { + NFS_LSEG_VALID = 0, /* cleared when lseg is recalled/returned */ +@@ -46,6 +47,7 @@ struct pnfs_layout_segment { + atomic_t pls_refcount; + unsigned long pls_flags; + struct pnfs_layout_hdr *pls_layout; ++ struct work_struct pls_work; + }; + + enum pnfs_try_status { +@@ -179,6 +181,7 @@ extern int nfs4_proc_layoutreturn(struct + /* pnfs.c */ + void pnfs_get_layout_hdr(struct pnfs_layout_hdr *lo); + void pnfs_put_lseg(struct pnfs_layout_segment *lseg); ++void pnfs_put_lseg_async(struct pnfs_layout_segment *lseg); + + void set_pnfs_layoutdriver(struct nfs_server *, const struct nfs_fh *, u32); + void unset_pnfs_layoutdriver(struct nfs_server *); +@@ -410,6 +413,10 @@ static inline void pnfs_put_lseg(struct + { + } + ++static inline void pnfs_put_lseg_async(struct pnfs_layout_segment *lseg) ++{ ++} ++ + static inline int pnfs_return_layout(struct inode *ino) + { + return 0; diff --git a/queue-3.16/revert-acpi-battery-fix-wrong-value-of-capacity_now-reported-when-fully-charged.patch b/queue-3.16/revert-acpi-battery-fix-wrong-value-of-capacity_now-reported-when-fully-charged.patch new file mode 100644 index 00000000000..c4f00070f4f --- /dev/null +++ b/queue-3.16/revert-acpi-battery-fix-wrong-value-of-capacity_now-reported-when-fully-charged.patch @@ -0,0 +1,65 @@ +From 508b3c677601797f2d51df3df5caa436dd235cb9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= +Date: Tue, 9 Sep 2014 10:45:18 +0200 +Subject: Revert "ACPI / battery: fix wrong value of capacity_now reported when fully charged" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= + +commit 508b3c677601797f2d51df3df5caa436dd235cb9 upstream. + +This reverts commit 232de5143790 ("ACPI / battery: fix wrong value of +capacity_now reported when fully charged") + +There is nothing wrong or unexpected about 'capacity_now' increasing above +the last 'full_charge_capacity' value. Different charging cycles will cause +'full_charge_capacity' to vary, both up and down. Good battery firmwares +will update 'full_charge_capacity' when the current charging cycle is +complete, increasing it if necessary. It might even go above +'design_capacity' on a fresh and healthy battery. + +Capping 'capacity_now' to 'full_charge_capacity' is plain wrong, and +printing a warning if this doesn't happen to match the 'design_capacity' +is both annoying and terribly wrong. + +This results in bogus warnings on perfectly working systems/firmwares: + + [Firmware Bug]: battery: reported current charge level (39800) is higher than reported maximum charge level (39800). + +and wrong values being reported for 'capacity_now' and +'full_charge_capacity' after the warning has been triggered. + +Fixes: 232de5143790 ("ACPI / battery: fix wrong value of capacity_now reported when fully charged") +Signed-off-by: Bjørn Mork +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/battery.c | 14 -------------- + 1 file changed, 14 deletions(-) + +--- a/drivers/acpi/battery.c ++++ b/drivers/acpi/battery.c +@@ -535,20 +535,6 @@ static int acpi_battery_get_state(struct + " invalid.\n"); + } + +- /* +- * When fully charged, some batteries wrongly report +- * capacity_now = design_capacity instead of = full_charge_capacity +- */ +- if (battery->capacity_now > battery->full_charge_capacity +- && battery->full_charge_capacity != ACPI_BATTERY_VALUE_UNKNOWN) { +- battery->capacity_now = battery->full_charge_capacity; +- if (battery->capacity_now != battery->design_capacity) +- printk_once(KERN_WARNING FW_BUG +- "battery: reported current charge level (%d) " +- "is higher than reported maximum charge level (%d).\n", +- battery->capacity_now, battery->full_charge_capacity); +- } +- + if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags) + && battery->capacity_now >= 0 && battery->capacity_now <= 100) + battery->capacity_now = (battery->capacity_now * diff --git a/queue-3.16/series b/queue-3.16/series index 89825baa308..fa3dda18446 100644 --- a/queue-3.16/series +++ b/queue-3.16/series @@ -146,3 +146,28 @@ usb-dwc2-gadget-break-infinite-loop-in-endpoint-disable-code.patch usb-dwc2-gadget-do-not-call-disconnect-method-in-pullup.patch usb-dwc2-gadget-delay-enabling-irq-once-hardware-is-configured-properly.patch usb-dwc2-gadget-avoid-disabling-ep0.patch +acpi-rtc-fix-cmos-rtc-opregion-handler-accesses-to-wrong-addresses.patch +acpi-lpss-complete-pm-entries-for-lpss-power-domain.patch +revert-acpi-battery-fix-wrong-value-of-capacity_now-reported-when-fully-charged.patch +iommu-vt-d-check-return-value-of-acpi_bus_get_device.patch +iommu-fsl-fix-warning-resulting-from-adding-pci-device-twice.patch +iommu-arm-smmu-fix-programming-of-smmu_cbn_tcr-for-stage-1.patch +nfsd4-fix-rd_dircount-enforcement.patch +cgroup-check-cgroup-liveliness-before-unbreaking-kernfs.patch +nfsv4-nfs4_state_manager-vs.-nfs_server_remove_lists.patch +nfsv4-fix-another-bug-in-the-close-open_downgrade-code.patch +nfsd4-fix-corruption-of-nfsv4-read-data.patch +nfs-move-nfs_pgio_data-and-remove-nfs_rw_header.patch +nfs-rename-members-of-nfs_pgio_data.patch +nfs-merge-nfs_pgio_data-into-_header.patch +nfs-remove-pgio_header-refcount-related-cleanup.patch +nfs-check-wait_on_bit_lock-err-in-page_group_lock.patch +pnfs-add-pnfs_put_lseg_async.patch +nfs-clear_request_commit-while-holding-i_lock.patch +nfs-change-nfs_page_group_lock-argument.patch +nfs-fix-nonblocking-calls-to-nfs_page_group_lock.patch +nfs-use-blocking-page_group_lock-in-add_request.patch +nfs-fix-error-handling-in-lock_and_join_requests.patch +nfs-don-t-sleep-with-inode-lock-in-lock_and_join_requests.patch +nfs-disallow-duplicate-pages-in-pgio-page-vectors.patch +nfs-can_coalesce_requests-must-enforce-contiguity.patch