pNFS: Don't discard layout segments that are marked for return
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Sat, 23 Jun 2018 14:28:40 +0000 (10:28 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Thu, 26 Jul 2018 20:25:24 +0000 (16:25 -0400)
If there are layout segments that are marked for return, then we need
to ensure that pnfs_mark_matching_lsegs_return() does not just
silently discard them, but it should tell the caller that there is a
layoutreturn scheduled.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/callback_proc.c
fs/nfs/pnfs.c

index 64c214fb9da67d5ba0ce6fb732a6c3df963823cf..af2322256aa4fcc50013485ed2a9aeb982eec618 100644 (file)
@@ -283,19 +283,22 @@ static u32 initiate_file_draining(struct nfs_client *clp,
                goto unlock;
        }
 
-       if (pnfs_mark_matching_lsegs_return(lo, &free_me_list,
+       switch (pnfs_mark_matching_lsegs_return(lo, &free_me_list,
                                &args->cbl_range,
                                be32_to_cpu(args->cbl_stateid.seqid))) {
+       case 0:
+       case -EBUSY:
+               /* There are layout segments that need to be returned */
                rv = NFS4_OK;
-               goto unlock;
-       }
-
-       /* Embrace your forgetfulness! */
-       rv = NFS4ERR_NOMATCHING_LAYOUT;
+               break;
+       case -ENOENT:
+               /* Embrace your forgetfulness! */
+               rv = NFS4ERR_NOMATCHING_LAYOUT;
 
-       if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) {
-               NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo,
-                       &args->cbl_range);
+               if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) {
+                       NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo,
+                               &args->cbl_range);
+               }
        }
 unlock:
        spin_unlock(&ino->i_lock);
index bcc3addec3c5376436f55f4d7cabad564bc41ea7..17776ef734d73f04e216dea166100c57ff19b864 100644 (file)
@@ -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;