diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-07-14 18:34:12 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2016-07-19 16:22:47 -0400 |
commit | 56b38a1f7c781519eef09c1668a3c97ea911f86b (patch) | |
tree | b9f1ebb18cf397a61fb38a6cdd6f43243078bc60 /fs/nfs/pnfs.c | |
parent | 8487c479e2668dd1231e9c3c77a203d744aec081 (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.c | 21 |
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); | ||
1675 | out_put_layout_hdr: | 1676 | out_put_layout_hdr: |
1676 | if (first) | 1677 | if (first) |
1677 | pnfs_clear_first_layoutget(lo); | 1678 | pnfs_clear_first_layoutget(lo); |