Merge tag 'nios2-v5.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/lftan...
[linux-2.6-block.git] / fs / nfs / pnfs.c
index 4525d5acae3868c04440da5d51db0128ed2644bc..bb80034a7661956aafeb248f5e233554aa838b8b 100644 (file)
@@ -359,9 +359,10 @@ pnfs_clear_lseg_state(struct pnfs_layout_segment *lseg,
 }
 
 /*
- * Update the seqid of a layout stateid
+ * Update the seqid of a layout stateid after receiving
+ * NFS4ERR_OLD_STATEID
  */
-bool nfs4_layoutreturn_refresh_stateid(nfs4_stateid *dst,
+bool nfs4_layout_refresh_old_stateid(nfs4_stateid *dst,
                struct pnfs_layout_range *dst_range,
                struct inode *inode)
 {
@@ -377,7 +378,15 @@ bool nfs4_layoutreturn_refresh_stateid(nfs4_stateid *dst,
 
        spin_lock(&inode->i_lock);
        lo = NFS_I(inode)->layout;
-       if (lo && nfs4_stateid_match_other(dst, &lo->plh_stateid)) {
+       if (lo &&  pnfs_layout_is_valid(lo) &&
+           nfs4_stateid_match_other(dst, &lo->plh_stateid)) {
+               /* Is our call using the most recent seqid? If so, bump it */
+               if (!nfs4_stateid_is_newer(&lo->plh_stateid, dst)) {
+                       nfs4_stateid_seqid_inc(dst);
+                       ret = true;
+                       goto out;
+               }
+               /* Try to update the seqid to the most recent */
                err = pnfs_mark_matching_lsegs_return(lo, &head, &range, 0);
                if (err != -EBUSY) {
                        dst->seqid = lo->plh_stateid.seqid;
@@ -385,6 +394,7 @@ bool nfs4_layoutreturn_refresh_stateid(nfs4_stateid *dst,
                        ret = true;
                }
        }
+out:
        spin_unlock(&inode->i_lock);
        pnfs_free_lseg_list(&head);
        return ret;
@@ -1440,6 +1450,52 @@ out_noroc:
        return false;
 }
 
+int pnfs_roc_done(struct rpc_task *task, struct inode *inode,
+               struct nfs4_layoutreturn_args **argpp,
+               struct nfs4_layoutreturn_res **respp,
+               int *ret)
+{
+       struct nfs4_layoutreturn_args *arg = *argpp;
+       int retval = -EAGAIN;
+
+       if (!arg)
+               return 0;
+       /* Handle Layoutreturn errors */
+       switch (*ret) {
+       case 0:
+               retval = 0;
+               break;
+       case -NFS4ERR_NOMATCHING_LAYOUT:
+               /* Was there an RPC level error? If not, retry */
+               if (task->tk_rpc_status == 0)
+                       break;
+               /* If the call was not sent, let caller handle it */
+               if (!RPC_WAS_SENT(task))
+                       return 0;
+               /*
+                * Otherwise, assume the call succeeded and
+                * that we need to release the layout
+                */
+               *ret = 0;
+               (*respp)->lrs_present = 0;
+               retval = 0;
+               break;
+       case -NFS4ERR_DELAY:
+               /* Let the caller handle the retry */
+               *ret = -NFS4ERR_NOMATCHING_LAYOUT;
+               return 0;
+       case -NFS4ERR_OLD_STATEID:
+               if (!nfs4_layout_refresh_old_stateid(&arg->stateid,
+                                       &arg->range, inode))
+                       break;
+               *ret = -NFS4ERR_NOMATCHING_LAYOUT;
+               return -EAGAIN;
+       }
+       *argpp = NULL;
+       *respp = NULL;
+       return retval;
+}
+
 void pnfs_roc_release(struct nfs4_layoutreturn_args *args,
                struct nfs4_layoutreturn_res *res,
                int ret)
@@ -1449,10 +1505,15 @@ void pnfs_roc_release(struct nfs4_layoutreturn_args *args,
        const nfs4_stateid *res_stateid = NULL;
        struct nfs4_xdr_opaque_data *ld_private = args->ld_private;
 
-       if (ret == 0) {
-               arg_stateid = &args->stateid;
+       switch (ret) {
+       case -NFS4ERR_NOMATCHING_LAYOUT:
+               break;
+       case 0:
                if (res->lrs_present)
                        res_stateid = &res->stateid;
+               /* Fallthrough */
+       default:
+               arg_stateid = &args->stateid;
        }
        pnfs_layoutreturn_free_lsegs(lo, arg_stateid, &args->range,
                        res_stateid);