aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@poochiereds.net>2016-05-17 12:28:42 -0400
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2016-05-17 15:48:10 -0400
commit6d597e1750126a2c6fd99e4b2cc176955bb9972e (patch)
treeaf032e776b004aa26ad48c0e91123253e63b7e37
parent3982a6a2d0e64441c938f4e7f93985aff37d8fb3 (diff)
pnfs: only tear down lsegs that precede seqid in LAYOUTRETURN args
LAYOUTRETURN is "special" in that servers and clients are expected to work with old stateids. When the client sends a LAYOUTRETURN with an old stateid in it then the server is expected to only tear down layout segments that were present when that seqid was current. Ensure that the client handles its accounting accordingly. Signed-off-by: Jeff Layton <jeff.layton@primarydata.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
-rw-r--r--fs/nfs/callback_proc.c3
-rw-r--r--fs/nfs/nfs42proc.c2
-rw-r--r--fs/nfs/nfs4proc.c5
-rw-r--r--fs/nfs/pnfs.c64
-rw-r--r--fs/nfs/pnfs.h6
5 files changed, 52 insertions, 28 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 7c9fbf504f07..aaa2e8d3df6f 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -217,7 +217,8 @@ static u32 initiate_file_draining(struct nfs_client *clp,
217 } 217 }
218 218
219 if (pnfs_mark_matching_lsegs_return(lo, &free_me_list, 219 if (pnfs_mark_matching_lsegs_return(lo, &free_me_list,
220 &args->cbl_range)) { 220 &args->cbl_range,
221 be32_to_cpu(args->cbl_stateid.seqid))) {
221 rv = NFS4_OK; 222 rv = NFS4_OK;
222 goto unlock; 223 goto unlock;
223 } 224 }
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 579ee20e4120..20c44d1209dc 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -337,7 +337,7 @@ nfs42_layoutstat_done(struct rpc_task *task, void *calldata)
337 * with the current stateid. 337 * with the current stateid.
338 */ 338 */
339 set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); 339 set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
340 pnfs_mark_matching_lsegs_invalid(lo, &head, NULL); 340 pnfs_mark_matching_lsegs_invalid(lo, &head, NULL, 0);
341 spin_unlock(&inode->i_lock); 341 spin_unlock(&inode->i_lock);
342 pnfs_free_lseg_list(&head); 342 pnfs_free_lseg_list(&head);
343 } else 343 } else
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index c9b66085d392..2a29f5d12aeb 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -7953,7 +7953,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
7953 * with the current stateid. 7953 * with the current stateid.
7954 */ 7954 */
7955 set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); 7955 set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
7956 pnfs_mark_matching_lsegs_invalid(lo, &head, NULL); 7956 pnfs_mark_matching_lsegs_invalid(lo, &head, NULL, 0);
7957 spin_unlock(&inode->i_lock); 7957 spin_unlock(&inode->i_lock);
7958 pnfs_free_lseg_list(&head); 7958 pnfs_free_lseg_list(&head);
7959 } else 7959 } else
@@ -8145,7 +8145,8 @@ static void nfs4_layoutreturn_release(void *calldata)
8145 8145
8146 dprintk("--> %s\n", __func__); 8146 dprintk("--> %s\n", __func__);
8147 spin_lock(&lo->plh_inode->i_lock); 8147 spin_lock(&lo->plh_inode->i_lock);
8148 pnfs_mark_matching_lsegs_invalid(lo, &freeme, &lrp->args.range); 8148 pnfs_mark_matching_lsegs_invalid(lo, &freeme, &lrp->args.range,
8149 be32_to_cpu(lrp->args.stateid.seqid));
8149 pnfs_mark_layout_returned_if_empty(lo); 8150 pnfs_mark_layout_returned_if_empty(lo);
8150 if (lrp->res.lrs_present) 8151 if (lrp->res.lrs_present)
8151 pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); 8152 pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 3ad6bd377d35..21ff53fe7a9e 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -270,7 +270,7 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo,
270 }; 270 };
271 271
272 set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); 272 set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
273 return pnfs_mark_matching_lsegs_invalid(lo, lseg_list, &range); 273 return pnfs_mark_matching_lsegs_invalid(lo, lseg_list, &range, 0);
274} 274}
275 275
276static int 276static int
@@ -308,7 +308,7 @@ pnfs_layout_io_set_failed(struct pnfs_layout_hdr *lo, u32 iomode)
308 308
309 spin_lock(&inode->i_lock); 309 spin_lock(&inode->i_lock);
310 pnfs_layout_set_fail_bit(lo, pnfs_iomode_to_fail_bit(iomode)); 310 pnfs_layout_set_fail_bit(lo, pnfs_iomode_to_fail_bit(iomode));
311 pnfs_mark_matching_lsegs_invalid(lo, &head, &range); 311 pnfs_mark_matching_lsegs_invalid(lo, &head, &range, 0);
312 spin_unlock(&inode->i_lock); 312 spin_unlock(&inode->i_lock);
313 pnfs_free_lseg_list(&head); 313 pnfs_free_lseg_list(&head);
314 dprintk("%s Setting layout IOMODE_%s fail bit\n", __func__, 314 dprintk("%s Setting layout IOMODE_%s fail bit\n", __func__,
@@ -522,13 +522,35 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
522 return rv; 522 return rv;
523} 523}
524 524
525/* Returns count of number of matching invalid lsegs remaining in list 525/*
526 * after call. 526 * Compare 2 layout stateid sequence ids, to see which is newer,
527 * taking into account wraparound issues.
528 */
529static bool pnfs_seqid_is_newer(u32 s1, u32 s2)
530{
531 return (s32)(s1 - s2) > 0;
532}
533
534/**
535 * pnfs_mark_matching_lsegs_invalid - tear down lsegs or mark them for later
536 * @lo: layout header containing the lsegs
537 * @tmp_list: list head where doomed lsegs should go
538 * @recall_range: optional recall range argument to match (may be NULL)
539 * @seq: only invalidate lsegs obtained prior to this sequence (may be 0)
540 *
541 * Walk the list of lsegs in the layout header, and tear down any that should
542 * be destroyed. If "recall_range" is specified then the segment must match
543 * that range. If "seq" is non-zero, then only match segments that were handed
544 * out at or before that sequence.
545 *
546 * Returns number of matching invalid lsegs remaining in list after scanning
547 * it and purging them.
527 */ 548 */
528int 549int
529pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo, 550pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
530 struct list_head *tmp_list, 551 struct list_head *tmp_list,
531 const struct pnfs_layout_range *recall_range) 552 const struct pnfs_layout_range *recall_range,
553 u32 seq)
532{ 554{
533 struct pnfs_layout_segment *lseg, *next; 555 struct pnfs_layout_segment *lseg, *next;
534 int remaining = 0; 556 int remaining = 0;
@@ -540,10 +562,12 @@ pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
540 list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) 562 list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list)
541 if (!recall_range || 563 if (!recall_range ||
542 should_free_lseg(&lseg->pls_range, recall_range)) { 564 should_free_lseg(&lseg->pls_range, recall_range)) {
543 dprintk("%s: freeing lseg %p iomode %d " 565 if (seq && pnfs_seqid_is_newer(lseg->pls_seq, seq))
566 continue;
567 dprintk("%s: freeing lseg %p iomode %d seq %u"
544 "offset %llu length %llu\n", __func__, 568 "offset %llu length %llu\n", __func__,
545 lseg, lseg->pls_range.iomode, lseg->pls_range.offset, 569 lseg, lseg->pls_range.iomode, lseg->pls_seq,
546 lseg->pls_range.length); 570 lseg->pls_range.offset, lseg->pls_range.length);
547 if (!mark_lseg_invalid(lseg, tmp_list)) 571 if (!mark_lseg_invalid(lseg, tmp_list))
548 remaining++; 572 remaining++;
549 } 573 }
@@ -730,15 +754,6 @@ pnfs_destroy_all_layouts(struct nfs_client *clp)
730 pnfs_destroy_layouts_byclid(clp, false); 754 pnfs_destroy_layouts_byclid(clp, false);
731} 755}
732 756
733/*
734 * Compare 2 layout stateid sequence ids, to see which is newer,
735 * taking into account wraparound issues.
736 */
737static bool pnfs_seqid_is_newer(u32 s1, u32 s2)
738{
739 return (s32)(s1 - s2) > 0;
740}
741
742/* update lo->plh_stateid with new if is more recent */ 757/* update lo->plh_stateid with new if is more recent */
743void 758void
744pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new, 759pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new,
@@ -1014,7 +1029,7 @@ _pnfs_return_layout(struct inode *ino)
1014 pnfs_get_layout_hdr(lo); 1029 pnfs_get_layout_hdr(lo);
1015 empty = list_empty(&lo->plh_segs); 1030 empty = list_empty(&lo->plh_segs);
1016 pnfs_clear_layoutcommit(ino, &tmp_list); 1031 pnfs_clear_layoutcommit(ino, &tmp_list);
1017 pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL); 1032 pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL, 0);
1018 1033
1019 if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) { 1034 if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) {
1020 struct pnfs_layout_range range = { 1035 struct pnfs_layout_range range = {
@@ -1721,7 +1736,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
1721 * inode invalid, and don't bother validating the stateid 1736 * inode invalid, and don't bother validating the stateid
1722 * sequence number. 1737 * sequence number.
1723 */ 1738 */
1724 pnfs_mark_matching_lsegs_invalid(lo, &free_me, NULL); 1739 pnfs_mark_matching_lsegs_invalid(lo, &free_me, NULL, 0);
1725 1740
1726 nfs4_stateid_copy(&lo->plh_stateid, &res->stateid); 1741 nfs4_stateid_copy(&lo->plh_stateid, &res->stateid);
1727 lo->plh_barrier = be32_to_cpu(res->stateid.seqid); 1742 lo->plh_barrier = be32_to_cpu(res->stateid.seqid);
@@ -1775,7 +1790,8 @@ pnfs_set_plh_return_info(struct pnfs_layout_hdr *lo, enum pnfs_iomode iomode,
1775int 1790int
1776pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo, 1791pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
1777 struct list_head *tmp_list, 1792 struct list_head *tmp_list,
1778 const struct pnfs_layout_range *return_range) 1793 const struct pnfs_layout_range *return_range,
1794 u32 seq)
1779{ 1795{
1780 struct pnfs_layout_segment *lseg, *next; 1796 struct pnfs_layout_segment *lseg, *next;
1781 int remaining = 0; 1797 int remaining = 0;
@@ -1798,8 +1814,11 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
1798 continue; 1814 continue;
1799 remaining++; 1815 remaining++;
1800 set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags); 1816 set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags);
1801 pnfs_set_plh_return_info(lo, return_range->iomode, lseg->pls_seq);
1802 } 1817 }
1818
1819 if (remaining)
1820 pnfs_set_plh_return_info(lo, return_range->iomode, seq);
1821
1803 return remaining; 1822 return remaining;
1804} 1823}
1805 1824
@@ -1822,7 +1841,8 @@ void pnfs_error_mark_layout_for_return(struct inode *inode,
1822 * segments at hand when sending layoutreturn. See pnfs_put_lseg() 1841 * segments at hand when sending layoutreturn. See pnfs_put_lseg()
1823 * for how it works. 1842 * for how it works.
1824 */ 1843 */
1825 if (!pnfs_mark_matching_lsegs_return(lo, &free_me, &range)) { 1844 if (!pnfs_mark_matching_lsegs_return(lo, &free_me,
1845 &range, lseg->pls_seq)) {
1826 nfs4_stateid stateid; 1846 nfs4_stateid stateid;
1827 enum pnfs_iomode iomode = lo->plh_return_iomode; 1847 enum pnfs_iomode iomode = lo->plh_return_iomode;
1828 1848
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 3476c9850678..971068b58647 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -266,10 +266,12 @@ int pnfs_choose_layoutget_stateid(nfs4_stateid *dst,
266 struct nfs4_state *open_state); 266 struct nfs4_state *open_state);
267int pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo, 267int pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
268 struct list_head *tmp_list, 268 struct list_head *tmp_list,
269 const struct pnfs_layout_range *recall_range); 269 const struct pnfs_layout_range *recall_range,
270 u32 seq);
270int pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo, 271int pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
271 struct list_head *tmp_list, 272 struct list_head *tmp_list,
272 const struct pnfs_layout_range *recall_range); 273 const struct pnfs_layout_range *recall_range,
274 u32 seq);
273bool pnfs_roc(struct inode *ino); 275bool pnfs_roc(struct inode *ino);
274void pnfs_roc_release(struct inode *ino); 276void pnfs_roc_release(struct inode *ino);
275void pnfs_roc_set_barrier(struct inode *ino, u32 barrier); 277void pnfs_roc_set_barrier(struct inode *ino, u32 barrier);