aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2015-09-29 20:34:05 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2015-12-31 13:53:48 -0500
commitaf7cf057933f01dc7f33ddfb5e436ad598ed17ad (patch)
treeb7a37c7c1767aa6b7fa3f9434dc56f9069031cd2 /fs/nfs
parentdc602dd706cb64036132a7903ead1c67d9a7bcb9 (diff)
NFS: Allow multiple commit requests in flight per file
Allow synchronous RPC calls to wait for pending RPC calls to finish, but also allow asynchronous ones to just fire off another commit. With this patch, the xfstests generic/074 test completes in 226s instead of 242s Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/direct.c6
-rw-r--r--fs/nfs/file.c2
-rw-r--r--fs/nfs/nfstrace.h1
-rw-r--r--fs/nfs/pnfs_nfs.c5
-rw-r--r--fs/nfs/write.c70
5 files changed, 35 insertions, 49 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index e73693f75dee..14f77df79c25 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -721,14 +721,8 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
721 nfs_direct_write_complete(dreq, data->inode); 721 nfs_direct_write_complete(dreq, data->inode);
722} 722}
723 723
724static void nfs_direct_error_cleanup(struct nfs_inode *nfsi)
725{
726 /* There is no lock to clear */
727}
728
729static const struct nfs_commit_completion_ops nfs_direct_commit_completion_ops = { 724static const struct nfs_commit_completion_ops nfs_direct_commit_completion_ops = {
730 .completion = nfs_direct_commit_complete, 725 .completion = nfs_direct_commit_complete,
731 .error_cleanup = nfs_direct_error_cleanup,
732}; 726};
733 727
734static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) 728static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq)
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 93e236429c5d..e6ef80ec699c 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -514,7 +514,7 @@ static void nfs_check_dirty_writeback(struct page *page,
514 * so it will not block due to pages that will shortly be freeable. 514 * so it will not block due to pages that will shortly be freeable.
515 */ 515 */
516 nfsi = NFS_I(mapping->host); 516 nfsi = NFS_I(mapping->host);
517 if (test_bit(NFS_INO_COMMIT, &nfsi->flags)) { 517 if (atomic_read(&nfsi->commit_info.rpcs_out)) {
518 *writeback = true; 518 *writeback = true;
519 return; 519 return;
520 } 520 }
diff --git a/fs/nfs/nfstrace.h b/fs/nfs/nfstrace.h
index 59f838cdc009..9f80a086b612 100644
--- a/fs/nfs/nfstrace.h
+++ b/fs/nfs/nfstrace.h
@@ -39,7 +39,6 @@
39 { 1 << NFS_INO_INVALIDATING, "INVALIDATING" }, \ 39 { 1 << NFS_INO_INVALIDATING, "INVALIDATING" }, \
40 { 1 << NFS_INO_FLUSHING, "FLUSHING" }, \ 40 { 1 << NFS_INO_FLUSHING, "FLUSHING" }, \
41 { 1 << NFS_INO_FSCACHE, "FSCACHE" }, \ 41 { 1 << NFS_INO_FSCACHE, "FSCACHE" }, \
42 { 1 << NFS_INO_COMMIT, "COMMIT" }, \
43 { 1 << NFS_INO_LAYOUTCOMMIT, "NEED_LAYOUTCOMMIT" }, \ 42 { 1 << NFS_INO_LAYOUTCOMMIT, "NEED_LAYOUTCOMMIT" }, \
44 { 1 << NFS_INO_LAYOUTCOMMITTING, "LAYOUTCOMMIT" }) 43 { 1 << NFS_INO_LAYOUTCOMMITTING, "LAYOUTCOMMIT" })
45 44
diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c
index 24655b807d44..3c8e3a44e6ea 100644
--- a/fs/nfs/pnfs_nfs.c
+++ b/fs/nfs/pnfs_nfs.c
@@ -266,17 +266,14 @@ pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
266 } else { 266 } else {
267 nfs_retry_commit(mds_pages, NULL, cinfo, 0); 267 nfs_retry_commit(mds_pages, NULL, cinfo, 0);
268 pnfs_generic_retry_commit(cinfo, 0); 268 pnfs_generic_retry_commit(cinfo, 0);
269 cinfo->completion_ops->error_cleanup(NFS_I(inode));
270 return -ENOMEM; 269 return -ENOMEM;
271 } 270 }
272 } 271 }
273 272
274 nreq += pnfs_generic_alloc_ds_commits(cinfo, &list); 273 nreq += pnfs_generic_alloc_ds_commits(cinfo, &list);
275 274
276 if (nreq == 0) { 275 if (nreq == 0)
277 cinfo->completion_ops->error_cleanup(NFS_I(inode));
278 goto out; 276 goto out;
279 }
280 277
281 atomic_add(nreq, &cinfo->mds->rpcs_out); 278 atomic_add(nreq, &cinfo->mds->rpcs_out);
282 279
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 0aa3e6b3db70..ae29f082c9c2 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -21,6 +21,8 @@
21#include <linux/nfs_page.h> 21#include <linux/nfs_page.h>
22#include <linux/backing-dev.h> 22#include <linux/backing-dev.h>
23#include <linux/export.h> 23#include <linux/export.h>
24#include <linux/freezer.h>
25#include <linux/wait.h>
24 26
25#include <asm/uaccess.h> 27#include <asm/uaccess.h>
26 28
@@ -1535,27 +1537,29 @@ static void nfs_writeback_result(struct rpc_task *task,
1535 } 1537 }
1536} 1538}
1537 1539
1540static int nfs_wait_atomic_killable(atomic_t *key)
1541{
1542 if (fatal_signal_pending(current))
1543 return -ERESTARTSYS;
1544 freezable_schedule_unsafe();
1545 return 0;
1546}
1538 1547
1539static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait) 1548static int wait_on_commit(struct nfs_mds_commit_info *cinfo)
1540{ 1549{
1541 int ret; 1550 return wait_on_atomic_t(&cinfo->rpcs_out,
1551 nfs_wait_atomic_killable, TASK_KILLABLE);
1552}
1542 1553
1543 if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags)) 1554static void nfs_commit_begin(struct nfs_mds_commit_info *cinfo)
1544 return 1; 1555{
1545 if (!may_wait) 1556 atomic_inc(&cinfo->rpcs_out);
1546 return 0;
1547 ret = out_of_line_wait_on_bit_lock(&nfsi->flags,
1548 NFS_INO_COMMIT,
1549 nfs_wait_bit_killable,
1550 TASK_KILLABLE);
1551 return (ret < 0) ? ret : 1;
1552} 1557}
1553 1558
1554static void nfs_commit_clear_lock(struct nfs_inode *nfsi) 1559static void nfs_commit_end(struct nfs_mds_commit_info *cinfo)
1555{ 1560{
1556 clear_bit(NFS_INO_COMMIT, &nfsi->flags); 1561 if (atomic_dec_and_test(&cinfo->rpcs_out))
1557 smp_mb__after_atomic(); 1562 wake_up_atomic_t(&cinfo->rpcs_out);
1558 wake_up_bit(&nfsi->flags, NFS_INO_COMMIT);
1559} 1563}
1560 1564
1561void nfs_commitdata_release(struct nfs_commit_data *data) 1565void nfs_commitdata_release(struct nfs_commit_data *data)
@@ -1693,7 +1697,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how,
1693 data->mds_ops, how, 0); 1697 data->mds_ops, how, 0);
1694 out_bad: 1698 out_bad:
1695 nfs_retry_commit(head, NULL, cinfo, 0); 1699 nfs_retry_commit(head, NULL, cinfo, 0);
1696 cinfo->completion_ops->error_cleanup(NFS_I(inode));
1697 return -ENOMEM; 1700 return -ENOMEM;
1698} 1701}
1699 1702
@@ -1755,8 +1758,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
1755 clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); 1758 clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC);
1756 1759
1757 nfs_init_cinfo(&cinfo, data->inode, data->dreq); 1760 nfs_init_cinfo(&cinfo, data->inode, data->dreq);
1758 if (atomic_dec_and_test(&cinfo.mds->rpcs_out)) 1761 nfs_commit_end(cinfo.mds);
1759 nfs_commit_clear_lock(NFS_I(data->inode));
1760} 1762}
1761 1763
1762static void nfs_commit_release(void *calldata) 1764static void nfs_commit_release(void *calldata)
@@ -1775,7 +1777,6 @@ static const struct rpc_call_ops nfs_commit_ops = {
1775 1777
1776static const struct nfs_commit_completion_ops nfs_commit_completion_ops = { 1778static const struct nfs_commit_completion_ops nfs_commit_completion_ops = {
1777 .completion = nfs_commit_release_pages, 1779 .completion = nfs_commit_release_pages,
1778 .error_cleanup = nfs_commit_clear_lock,
1779}; 1780};
1780 1781
1781int nfs_generic_commit_list(struct inode *inode, struct list_head *head, 1782int nfs_generic_commit_list(struct inode *inode, struct list_head *head,
@@ -1794,30 +1795,25 @@ int nfs_commit_inode(struct inode *inode, int how)
1794 LIST_HEAD(head); 1795 LIST_HEAD(head);
1795 struct nfs_commit_info cinfo; 1796 struct nfs_commit_info cinfo;
1796 int may_wait = how & FLUSH_SYNC; 1797 int may_wait = how & FLUSH_SYNC;
1798 int error = 0;
1797 int res; 1799 int res;
1798 1800
1799 res = nfs_commit_set_lock(NFS_I(inode), may_wait);
1800 if (res <= 0)
1801 goto out_mark_dirty;
1802 nfs_init_cinfo_from_inode(&cinfo, inode); 1801 nfs_init_cinfo_from_inode(&cinfo, inode);
1802 nfs_commit_begin(cinfo.mds);
1803 res = nfs_scan_commit(inode, &head, &cinfo); 1803 res = nfs_scan_commit(inode, &head, &cinfo);
1804 if (res) { 1804 if (res)
1805 int error;
1806
1807 error = nfs_generic_commit_list(inode, &head, how, &cinfo); 1805 error = nfs_generic_commit_list(inode, &head, how, &cinfo);
1808 if (error < 0) 1806 nfs_commit_end(cinfo.mds);
1809 return error; 1807 if (error < 0)
1810 if (!may_wait) 1808 goto out_error;
1811 goto out_mark_dirty; 1809 if (!may_wait)
1812 error = wait_on_bit_action(&NFS_I(inode)->flags, 1810 goto out_mark_dirty;
1813 NFS_INO_COMMIT, 1811 error = wait_on_commit(cinfo.mds);
1814 nfs_wait_bit_killable, 1812 if (error < 0)
1815 TASK_KILLABLE); 1813 return error;
1816 if (error < 0)
1817 return error;
1818 } else
1819 nfs_commit_clear_lock(NFS_I(inode));
1820 return res; 1814 return res;
1815out_error:
1816 res = error;
1821 /* Note: If we exit without ensuring that the commit is complete, 1817 /* Note: If we exit without ensuring that the commit is complete,
1822 * we must mark the inode as dirty. Otherwise, future calls to 1818 * we must mark the inode as dirty. Otherwise, future calls to
1823 * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure 1819 * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure