|
@@ -270,7 +270,7 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo,
|
|
|
};
|
|
|
|
|
|
set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
|
|
|
- return pnfs_mark_matching_lsegs_invalid(lo, lseg_list, &range);
|
|
|
+ return pnfs_mark_matching_lsegs_invalid(lo, lseg_list, &range, 0);
|
|
|
}
|
|
|
|
|
|
static int
|
|
@@ -308,7 +308,7 @@ pnfs_layout_io_set_failed(struct pnfs_layout_hdr *lo, u32 iomode)
|
|
|
|
|
|
spin_lock(&inode->i_lock);
|
|
|
pnfs_layout_set_fail_bit(lo, pnfs_iomode_to_fail_bit(iomode));
|
|
|
- pnfs_mark_matching_lsegs_invalid(lo, &head, &range);
|
|
|
+ pnfs_mark_matching_lsegs_invalid(lo, &head, &range, 0);
|
|
|
spin_unlock(&inode->i_lock);
|
|
|
pnfs_free_lseg_list(&head);
|
|
|
dprintk("%s Setting layout IOMODE_%s fail bit\n", __func__,
|
|
@@ -522,13 +522,35 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
|
|
|
return rv;
|
|
|
}
|
|
|
|
|
|
-/* Returns count of number of matching invalid lsegs remaining in list
|
|
|
- * after call.
|
|
|
+/*
|
|
|
+ * Compare 2 layout stateid sequence ids, to see which is newer,
|
|
|
+ * taking into account wraparound issues.
|
|
|
+ */
|
|
|
+static bool pnfs_seqid_is_newer(u32 s1, u32 s2)
|
|
|
+{
|
|
|
+ return (s32)(s1 - s2) > 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * pnfs_mark_matching_lsegs_invalid - tear down lsegs or mark them for later
|
|
|
+ * @lo: layout header containing the lsegs
|
|
|
+ * @tmp_list: list head where doomed lsegs should go
|
|
|
+ * @recall_range: optional recall range argument to match (may be NULL)
|
|
|
+ * @seq: only invalidate lsegs obtained prior to this sequence (may be 0)
|
|
|
+ *
|
|
|
+ * Walk the list of lsegs in the layout header, and tear down any that should
|
|
|
+ * be destroyed. If "recall_range" is specified then the segment must match
|
|
|
+ * that range. If "seq" is non-zero, then only match segments that were handed
|
|
|
+ * out at or before that sequence.
|
|
|
+ *
|
|
|
+ * Returns number of matching invalid lsegs remaining in list after scanning
|
|
|
+ * it and purging them.
|
|
|
*/
|
|
|
int
|
|
|
pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
|
|
|
struct list_head *tmp_list,
|
|
|
- const struct pnfs_layout_range *recall_range)
|
|
|
+ const struct pnfs_layout_range *recall_range,
|
|
|
+ u32 seq)
|
|
|
{
|
|
|
struct pnfs_layout_segment *lseg, *next;
|
|
|
int remaining = 0;
|
|
@@ -540,10 +562,12 @@ pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
|
|
|
list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list)
|
|
|
if (!recall_range ||
|
|
|
should_free_lseg(&lseg->pls_range, recall_range)) {
|
|
|
- dprintk("%s: freeing lseg %p iomode %d "
|
|
|
+ if (seq && pnfs_seqid_is_newer(lseg->pls_seq, seq))
|
|
|
+ continue;
|
|
|
+ dprintk("%s: freeing lseg %p iomode %d seq %u"
|
|
|
"offset %llu length %llu\n", __func__,
|
|
|
- lseg, lseg->pls_range.iomode, lseg->pls_range.offset,
|
|
|
- lseg->pls_range.length);
|
|
|
+ lseg, lseg->pls_range.iomode, lseg->pls_seq,
|
|
|
+ lseg->pls_range.offset, lseg->pls_range.length);
|
|
|
if (!mark_lseg_invalid(lseg, tmp_list))
|
|
|
remaining++;
|
|
|
}
|
|
@@ -730,15 +754,6 @@ pnfs_destroy_all_layouts(struct nfs_client *clp)
|
|
|
pnfs_destroy_layouts_byclid(clp, false);
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Compare 2 layout stateid sequence ids, to see which is newer,
|
|
|
- * taking into account wraparound issues.
|
|
|
- */
|
|
|
-static bool pnfs_seqid_is_newer(u32 s1, u32 s2)
|
|
|
-{
|
|
|
- return (s32)(s1 - s2) > 0;
|
|
|
-}
|
|
|
-
|
|
|
/* update lo->plh_stateid with new if is more recent */
|
|
|
void
|
|
|
pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new,
|
|
@@ -1014,7 +1029,7 @@ _pnfs_return_layout(struct inode *ino)
|
|
|
pnfs_get_layout_hdr(lo);
|
|
|
empty = list_empty(&lo->plh_segs);
|
|
|
pnfs_clear_layoutcommit(ino, &tmp_list);
|
|
|
- pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
|
|
|
+ pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL, 0);
|
|
|
|
|
|
if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) {
|
|
|
struct pnfs_layout_range range = {
|
|
@@ -1721,7 +1736,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
|
|
|
* inode invalid, and don't bother validating the stateid
|
|
|
* sequence number.
|
|
|
*/
|
|
|
- pnfs_mark_matching_lsegs_invalid(lo, &free_me, NULL);
|
|
|
+ pnfs_mark_matching_lsegs_invalid(lo, &free_me, NULL, 0);
|
|
|
|
|
|
nfs4_stateid_copy(&lo->plh_stateid, &res->stateid);
|
|
|
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,
|
|
|
int
|
|
|
pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
|
|
|
struct list_head *tmp_list,
|
|
|
- const struct pnfs_layout_range *return_range)
|
|
|
+ const struct pnfs_layout_range *return_range,
|
|
|
+ u32 seq)
|
|
|
{
|
|
|
struct pnfs_layout_segment *lseg, *next;
|
|
|
int remaining = 0;
|
|
@@ -1798,8 +1814,11 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
|
|
|
continue;
|
|
|
remaining++;
|
|
|
set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags);
|
|
|
- pnfs_set_plh_return_info(lo, return_range->iomode, lseg->pls_seq);
|
|
|
}
|
|
|
+
|
|
|
+ if (remaining)
|
|
|
+ pnfs_set_plh_return_info(lo, return_range->iomode, seq);
|
|
|
+
|
|
|
return remaining;
|
|
|
}
|
|
|
|
|
@@ -1822,7 +1841,8 @@ void pnfs_error_mark_layout_for_return(struct inode *inode,
|
|
|
* segments at hand when sending layoutreturn. See pnfs_put_lseg()
|
|
|
* for how it works.
|
|
|
*/
|
|
|
- if (!pnfs_mark_matching_lsegs_return(lo, &free_me, &range)) {
|
|
|
+ if (!pnfs_mark_matching_lsegs_return(lo, &free_me,
|
|
|
+ &range, lseg->pls_seq)) {
|
|
|
nfs4_stateid stateid;
|
|
|
enum pnfs_iomode iomode = lo->plh_return_iomode;
|
|
|
|