diff options
author | Paul Gortmaker <paul.gortmaker@windriver.com> | 2018-07-25 14:06:20 -0400 |
---|---|---|
committer | Paul Gortmaker <paul.gortmaker@windriver.com> | 2018-07-25 14:06:20 -0400 |
commit | 2e50bfe923c04b2c251e99c362ccd5b54c1ec761 (patch) | |
tree | 2638f74609d74e5bfa25bb7d2448475c23bf912d | |
parent | 1332cc5301e2816a10bb799a2cdc8198302b9a6d (diff) | |
download | longterm-queue-4.12-2e50bfe923c04b2c251e99c362ccd5b54c1ec761.tar.gz |
nfs: add fix for fixes
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
-rw-r--r-- | queue/NFS-Fix-unstable-write-completion.patch | 144 | ||||
-rw-r--r-- | queue/NFS-Use-an-atomic_long_t-to-count-the-number-of-comm.patch | 90 | ||||
-rw-r--r-- | queue/series | 2 |
3 files changed, 236 insertions, 0 deletions
diff --git a/queue/NFS-Fix-unstable-write-completion.patch b/queue/NFS-Fix-unstable-write-completion.patch new file mode 100644 index 0000000..5662eb1 --- /dev/null +++ b/queue/NFS-Fix-unstable-write-completion.patch @@ -0,0 +1,144 @@ +From c4f24df942a181699c5bab01b8e5e82b925f77f3 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust <trond.myklebust@primarydata.com> +Date: Wed, 7 Mar 2018 15:22:31 -0500 +Subject: [PATCH] NFS: Fix unstable write completion + +commit c4f24df942a181699c5bab01b8e5e82b925f77f3 upstream. + +We do want to respect the FLUSH_SYNC argument to nfs_commit_inode() to +ensure that all outstanding COMMIT requests to the inode in question are +complete. Currently we may exit early from both nfs_commit_inode() and +nfs_write_inode() even if there are COMMIT requests in flight, or unstable +writes on the commit list. + +In order to get the right semantics w.r.t. sync_inode(), we don't need +to have nfs_commit_inode() reset the inode dirty flags when called from +nfs_wb_page() and/or nfs_wb_all(). We just need to ensure that +nfs_write_inode() leaves them in the right state if there are outstanding +commits, or stable pages. + +Reported-by: Scott Mayhew <smayhew@redhat.com> +Fixes: dc4fd9ab01ab ("nfs: don't wait on commit in nfs_commit_inode()...") +Cc: stable@vger.kernel.org # v4.14+ +Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> + +diff --git a/fs/nfs/write.c b/fs/nfs/write.c +index 7428a669d7a7..e7d8ceae8f26 100644 +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -1876,40 +1876,43 @@ int nfs_generic_commit_list(struct inode *inode, struct list_head *head, + return status; + } + +-int nfs_commit_inode(struct inode *inode, int how) ++static int __nfs_commit_inode(struct inode *inode, int how, ++ struct writeback_control *wbc) + { + LIST_HEAD(head); + struct nfs_commit_info cinfo; + int may_wait = how & FLUSH_SYNC; +- int error = 0; +- int res; ++ int ret, nscan; + + nfs_init_cinfo_from_inode(&cinfo, inode); + nfs_commit_begin(cinfo.mds); +- res = nfs_scan_commit(inode, &head, &cinfo); +- if (res) +- error = nfs_generic_commit_list(inode, &head, how, &cinfo); ++ for (;;) { ++ ret = nscan = nfs_scan_commit(inode, &head, &cinfo); ++ if (ret <= 0) ++ break; ++ ret = nfs_generic_commit_list(inode, &head, how, &cinfo); ++ if (ret < 0) ++ break; ++ ret = 0; ++ if (wbc && wbc->sync_mode == WB_SYNC_NONE) { ++ if (nscan < wbc->nr_to_write) ++ wbc->nr_to_write -= nscan; ++ else ++ wbc->nr_to_write = 0; ++ } ++ if (nscan < INT_MAX) ++ break; ++ cond_resched(); ++ } + nfs_commit_end(cinfo.mds); +- if (res == 0) +- return res; +- if (error < 0) +- goto out_error; +- if (!may_wait) +- goto out_mark_dirty; +- error = wait_on_commit(cinfo.mds); +- if (error < 0) +- return error; +- return res; +-out_error: +- res = error; +- /* Note: If we exit without ensuring that the commit is complete, +- * we must mark the inode as dirty. Otherwise, future calls to +- * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure +- * that the data is on the disk. +- */ +-out_mark_dirty: +- __mark_inode_dirty(inode, I_DIRTY_DATASYNC); +- return res; ++ if (ret || !may_wait) ++ return ret; ++ return wait_on_commit(cinfo.mds); ++} ++ ++int nfs_commit_inode(struct inode *inode, int how) ++{ ++ return __nfs_commit_inode(inode, how, NULL); + } + EXPORT_SYMBOL_GPL(nfs_commit_inode); + +@@ -1919,11 +1922,11 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) + int flags = FLUSH_SYNC; + int ret = 0; + +- /* no commits means nothing needs to be done */ +- if (!atomic_long_read(&nfsi->commit_info.ncommit)) +- return ret; +- + if (wbc->sync_mode == WB_SYNC_NONE) { ++ /* no commits means nothing needs to be done */ ++ if (!atomic_long_read(&nfsi->commit_info.ncommit)) ++ goto check_requests_outstanding; ++ + /* Don't commit yet if this is a non-blocking flush and there + * are a lot of outstanding writes for this mapping. + */ +@@ -1934,16 +1937,16 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) + flags = 0; + } + +- ret = nfs_commit_inode(inode, flags); +- if (ret >= 0) { +- if (wbc->sync_mode == WB_SYNC_NONE) { +- if (ret < wbc->nr_to_write) +- wbc->nr_to_write -= ret; +- else +- wbc->nr_to_write = 0; +- } +- return 0; +- } ++ ret = __nfs_commit_inode(inode, flags, wbc); ++ if (!ret) { ++ if (flags & FLUSH_SYNC) ++ return 0; ++ } else if (atomic_long_read(&nfsi->commit_info.ncommit)) ++ goto out_mark_dirty; ++ ++check_requests_outstanding: ++ if (!atomic_read(&nfsi->commit_info.rpcs_out)) ++ return ret; + out_mark_dirty: + __mark_inode_dirty(inode, I_DIRTY_DATASYNC); + return ret; +-- +2.15.0 + diff --git a/queue/NFS-Use-an-atomic_long_t-to-count-the-number-of-comm.patch b/queue/NFS-Use-an-atomic_long_t-to-count-the-number-of-comm.patch new file mode 100644 index 0000000..d7fd433 --- /dev/null +++ b/queue/NFS-Use-an-atomic_long_t-to-count-the-number-of-comm.patch @@ -0,0 +1,90 @@ +From 5cb953d4b1e70a09084f71594c45d47458346bc2 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust <trond.myklebust@primarydata.com> +Date: Tue, 1 Aug 2017 17:04:12 -0400 +Subject: [PATCH] NFS: Use an atomic_long_t to count the number of commits + +commit 5cb953d4b1e70a09084f71594c45d47458346bc2 upstream. + +Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> + +diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c +index 0480eb02299a..134d9f560240 100644 +--- a/fs/nfs/inode.c ++++ b/fs/nfs/inode.c +@@ -2012,7 +2012,7 @@ static void init_once(void *foo) + INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); + INIT_LIST_HEAD(&nfsi->commit_info.list); + atomic_long_set(&nfsi->nrequests, 0); +- nfsi->commit_info.ncommit = 0; ++ atomic_long_set(&nfsi->commit_info.ncommit, 0); + atomic_set(&nfsi->commit_info.rpcs_out, 0); + init_rwsem(&nfsi->rmdir_sem); + mutex_init(&nfsi->commit_mutex); +diff --git a/fs/nfs/write.c b/fs/nfs/write.c +index 08093552f115..12479c25028e 100644 +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -857,7 +857,7 @@ nfs_request_add_commit_list_locked(struct nfs_page *req, struct list_head *dst, + { + set_bit(PG_CLEAN, &req->wb_flags); + nfs_list_add_request(req, dst); +- cinfo->mds->ncommit++; ++ atomic_long_inc(&cinfo->mds->ncommit); + } + EXPORT_SYMBOL_GPL(nfs_request_add_commit_list_locked); + +@@ -903,7 +903,7 @@ nfs_request_remove_commit_list(struct nfs_page *req, + if (!test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) + return; + nfs_list_remove_request(req); +- cinfo->mds->ncommit--; ++ atomic_long_dec(&cinfo->mds->ncommit); + } + EXPORT_SYMBOL_GPL(nfs_request_remove_commit_list); + +@@ -1017,7 +1017,7 @@ static void nfs_write_completion(struct nfs_pgio_header *hdr) + unsigned long + nfs_reqs_to_commit(struct nfs_commit_info *cinfo) + { +- return cinfo->mds->ncommit; ++ return atomic_long_read(&cinfo->mds->ncommit); + } + + /* NFS_I(cinfo->inode)->commit_mutex held by caller */ +@@ -1057,8 +1057,10 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, + { + int ret = 0; + ++ if (!atomic_long_read(&cinfo->mds->ncommit)) ++ return 0; + mutex_lock(&NFS_I(cinfo->inode)->commit_mutex); +- if (cinfo->mds->ncommit > 0) { ++ if (atomic_long_read(&cinfo->mds->ncommit) > 0) { + const int max = INT_MAX; + + ret = nfs_scan_commit_list(&cinfo->mds->list, dst, +@@ -1890,7 +1892,7 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) + int ret = 0; + + /* no commits means nothing needs to be done */ +- if (!nfsi->commit_info.ncommit) ++ if (!atomic_long_read(&nfsi->commit_info.ncommit)) + return ret; + + if (wbc->sync_mode == WB_SYNC_NONE) { +diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h +index 62cbcb842f99..164d5359d4ab 100644 +--- a/include/linux/nfs_xdr.h ++++ b/include/linux/nfs_xdr.h +@@ -1476,7 +1476,7 @@ struct nfs_pgio_header { + + struct nfs_mds_commit_info { + atomic_t rpcs_out; +- unsigned long ncommit; ++ atomic_long_t ncommit; + struct list_head list; + }; + +-- +2.15.0 + diff --git a/queue/series b/queue/series index 4e2c58a..98c9163 100644 --- a/queue/series +++ b/queue/series @@ -13,6 +13,8 @@ ceph-drop-negative-child-dentries-before-try-pruning.patch usb-xhci-fix-TDS-for-MTK-xHCI1.1.patch xhci-Don-t-add-a-virt_dev-to-the-devs-array-before-i.patch nfs-don-t-wait-on-commit-in-nfs_commit_inode-if-ther.patch +NFS-Use-an-atomic_long_t-to-count-the-number-of-comm.patch +NFS-Fix-unstable-write-completion.patch scsi-core-Fix-a-scsi_show_rq-NULL-pointer-dereferenc.patch dm-fix-various-targets-to-dm_register_target-after-m.patch iw_cxgb4-only-insert-drain-cqes-if-wq-is-flushed.patch |