|
@@ -2238,15 +2238,31 @@ out_forget:
|
|
|
return ERR_PTR(-EAGAIN);
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+mark_lseg_invalid_or_return(struct pnfs_layout_segment *lseg,
|
|
|
+ struct list_head *tmp_list)
|
|
|
+{
|
|
|
+ if (!mark_lseg_invalid(lseg, tmp_list))
|
|
|
+ return 0;
|
|
|
+ pnfs_cache_lseg_for_layoutreturn(lseg->pls_layout, lseg);
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* pnfs_mark_matching_lsegs_return - Free or return matching layout segments
|
|
|
* @lo: pointer to layout header
|
|
|
* @tmp_list: list header to be used with pnfs_free_lseg_list()
|
|
|
* @return_range: describe layout segment ranges to be returned
|
|
|
+ * @seq: stateid seqid to match
|
|
|
*
|
|
|
* This function is mainly intended for use by layoutrecall. It attempts
|
|
|
* to free the layout segment immediately, or else to mark it for return
|
|
|
* as soon as its reference count drops to zero.
|
|
|
+ *
|
|
|
+ * Returns
|
|
|
+ * - 0: a layoutreturn needs to be scheduled.
|
|
|
+ * - EBUSY: there are layout segment that are still in use.
|
|
|
+ * - ENOENT: there are no layout segments that need to be returned.
|
|
|
*/
|
|
|
int
|
|
|
pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
|
|
@@ -2259,9 +2275,6 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
|
|
|
|
|
|
dprintk("%s:Begin lo %p\n", __func__, lo);
|
|
|
|
|
|
- if (list_empty(&lo->plh_segs))
|
|
|
- return 0;
|
|
|
-
|
|
|
assert_spin_locked(&lo->plh_inode->i_lock);
|
|
|
|
|
|
list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list)
|
|
@@ -2271,16 +2284,23 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
|
|
|
lseg, lseg->pls_range.iomode,
|
|
|
lseg->pls_range.offset,
|
|
|
lseg->pls_range.length);
|
|
|
- if (mark_lseg_invalid(lseg, tmp_list))
|
|
|
+ if (mark_lseg_invalid_or_return(lseg, tmp_list))
|
|
|
continue;
|
|
|
remaining++;
|
|
|
set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags);
|
|
|
}
|
|
|
|
|
|
- if (remaining)
|
|
|
+ if (remaining) {
|
|
|
pnfs_set_plh_return_info(lo, return_range->iomode, seq);
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
|
|
|
- return remaining;
|
|
|
+ if (!list_empty(&lo->plh_return_segs)) {
|
|
|
+ pnfs_set_plh_return_info(lo, return_range->iomode, seq);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ return -ENOENT;
|
|
|
}
|
|
|
|
|
|
void pnfs_error_mark_layout_for_return(struct inode *inode,
|
|
@@ -2305,7 +2325,7 @@ 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, &lo->plh_return_segs, &range, 0)) {
|
|
|
+ if (pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs, &range, 0) != -EBUSY) {
|
|
|
nfs4_stateid stateid;
|
|
|
enum pnfs_iomode iomode;
|
|
|
|