summaryrefslogtreecommitdiffstats
path: root/fs/nfs/pnfs.c
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2016-07-14 18:34:12 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2016-07-19 16:22:47 -0400
commit56b38a1f7c781519eef09c1668a3c97ea911f86b (patch)
treeb9f1ebb18cf397a61fb38a6cdd6f43243078bc60 /fs/nfs/pnfs.c
parent8487c479e2668dd1231e9c3c77a203d744aec081 (diff)
pNFS: Fix post-layoutget error handling in pnfs_update_layout()
The non-retry error path is currently broken and ends up releasing the reference to the layout twice. It also can end up clearing the NFS_LAYOUT_FIRST_LAYOUTGET flag twice, causing a race. In addition, the retry path will fail to decrement the plh_outstanding counter. Fixes: 183d9e7b112aa ("pnfs: rework LAYOUTGET retry handling") Cc: stable@vger.kernel.org # 4.7 Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> Reviewed-by: Jeff Layton <jlayton@redhat.com>
Diffstat (limited to 'fs/nfs/pnfs.c')
-rw-r--r--fs/nfs/pnfs.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 0fbe734cc38c..563f131c9abe 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1645,6 +1645,7 @@ lookup_again:
1645 lseg = send_layoutget(lo, ctx, &stateid, &arg, &timeout, gfp_flags); 1645 lseg = send_layoutget(lo, ctx, &stateid, &arg, &timeout, gfp_flags);
1646 trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg, 1646 trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
1647 PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET); 1647 PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET);
1648 atomic_dec(&lo->plh_outstanding);
1648 if (IS_ERR(lseg)) { 1649 if (IS_ERR(lseg)) {
1649 switch(PTR_ERR(lseg)) { 1650 switch(PTR_ERR(lseg)) {
1650 case -ERECALLCONFLICT: 1651 case -ERECALLCONFLICT:
@@ -1652,26 +1653,26 @@ lookup_again:
1652 lseg = NULL; 1653 lseg = NULL;
1653 /* Fallthrough */ 1654 /* Fallthrough */
1654 case -EAGAIN: 1655 case -EAGAIN:
1655 pnfs_put_layout_hdr(lo); 1656 break;
1656 if (first)
1657 pnfs_clear_first_layoutget(lo);
1658 if (lseg) {
1659 trace_pnfs_update_layout(ino, pos, count,
1660 iomode, lo, lseg, PNFS_UPDATE_LAYOUT_RETRY);
1661 goto lookup_again;
1662 }
1663 /* Fallthrough */
1664 default: 1657 default:
1665 if (!nfs_error_is_fatal(PTR_ERR(lseg))) { 1658 if (!nfs_error_is_fatal(PTR_ERR(lseg))) {
1666 pnfs_layout_clear_fail_bit(lo, pnfs_iomode_to_fail_bit(iomode)); 1659 pnfs_layout_clear_fail_bit(lo, pnfs_iomode_to_fail_bit(iomode));
1667 lseg = NULL; 1660 lseg = NULL;
1668 } 1661 }
1662 goto out_put_layout_hdr;
1663 }
1664 if (lseg) {
1665 if (first)
1666 pnfs_clear_first_layoutget(lo);
1667 trace_pnfs_update_layout(ino, pos, count,
1668 iomode, lo, lseg, PNFS_UPDATE_LAYOUT_RETRY);
1669 pnfs_put_layout_hdr(lo);
1670 goto lookup_again;
1669 } 1671 }
1670 } else { 1672 } else {
1671 pnfs_layout_clear_fail_bit(lo, pnfs_iomode_to_fail_bit(iomode)); 1673 pnfs_layout_clear_fail_bit(lo, pnfs_iomode_to_fail_bit(iomode));
1672 } 1674 }
1673 1675
1674 atomic_dec(&lo->plh_outstanding);
1675out_put_layout_hdr: 1676out_put_layout_hdr:
1676 if (first) 1677 if (first)
1677 pnfs_clear_first_layoutget(lo); 1678 pnfs_clear_first_layoutget(lo);