summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Gortmaker <paul.gortmaker@windriver.com>2018-07-25 14:06:20 -0400
committerPaul Gortmaker <paul.gortmaker@windriver.com>2018-07-25 14:06:20 -0400
commit2e50bfe923c04b2c251e99c362ccd5b54c1ec761 (patch)
tree2638f74609d74e5bfa25bb7d2448475c23bf912d
parent1332cc5301e2816a10bb799a2cdc8198302b9a6d (diff)
downloadlongterm-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.patch144
-rw-r--r--queue/NFS-Use-an-atomic_long_t-to-count-the-number-of-comm.patch90
-rw-r--r--queue/series2
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