aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/pnfs.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2013-03-20 12:34:32 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-03-21 10:31:19 -0400
commita073dbff359f4741013ae4b8395f5364c5e00b48 (patch)
tree511029ebb36cce1b4a03e4181da0dfe91cac268e /fs/nfs/pnfs.c
parent4376c94618c26225e69e17b7c91169c45a90b292 (diff)
NFSv4.1: Fix a race in pNFS layoutcommit
We need to clear the NFS_LSEG_LAYOUTCOMMIT bits atomically with the NFS_INO_LAYOUTCOMMIT bit, otherwise we may end up with situations where the two are out of sync. The first half of the problem is to ensure that pnfs_layoutcommit_inode clears the NFS_LSEG_LAYOUTCOMMIT bit through pnfs_list_write_lseg. We still need to keep the reference to those segments until the RPC call is finished, so in order to make it clear _where_ those references come from, we add a helper pnfs_list_write_lseg_done() that cleans up after pnfs_list_write_lseg. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Acked-by: Benny Halevy <bhalevy@tonian.com> Cc: stable@vger.kernel.org
Diffstat (limited to 'fs/nfs/pnfs.c')
-rw-r--r--fs/nfs/pnfs.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 48ac5aad6258..3d900916fd41 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1746,11 +1746,27 @@ static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp)
1746 1746
1747 list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) { 1747 list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) {
1748 if (lseg->pls_range.iomode == IOMODE_RW && 1748 if (lseg->pls_range.iomode == IOMODE_RW &&
1749 test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) 1749 test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
1750 list_add(&lseg->pls_lc_list, listp); 1750 list_add(&lseg->pls_lc_list, listp);
1751 } 1751 }
1752} 1752}
1753 1753
1754static void pnfs_list_write_lseg_done(struct inode *inode, struct list_head *listp)
1755{
1756 struct pnfs_layout_segment *lseg, *tmp;
1757 unsigned long *bitlock = &NFS_I(inode)->flags;
1758
1759 /* Matched by references in pnfs_set_layoutcommit */
1760 list_for_each_entry_safe(lseg, tmp, listp, pls_lc_list) {
1761 list_del_init(&lseg->pls_lc_list);
1762 pnfs_put_lseg(lseg);
1763 }
1764
1765 clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock);
1766 smp_mb__after_clear_bit();
1767 wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING);
1768}
1769
1754void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg) 1770void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg)
1755{ 1771{
1756 pnfs_layout_io_set_failed(lseg->pls_layout, lseg->pls_range.iomode); 1772 pnfs_layout_io_set_failed(lseg->pls_layout, lseg->pls_range.iomode);
@@ -1795,6 +1811,7 @@ void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data)
1795 1811
1796 if (nfss->pnfs_curr_ld->cleanup_layoutcommit) 1812 if (nfss->pnfs_curr_ld->cleanup_layoutcommit)
1797 nfss->pnfs_curr_ld->cleanup_layoutcommit(data); 1813 nfss->pnfs_curr_ld->cleanup_layoutcommit(data);
1814 pnfs_list_write_lseg_done(data->args.inode, &data->lseg_list);
1798} 1815}
1799 1816
1800/* 1817/*