return 0;
 }
 
+/*
+ * It's possible that between opening the dentry and setting the delegation,
+ * that it has been renamed or unlinked. Redo the lookup to verify that this
+ * hasn't happened.
+ */
+static int
+nfsd4_verify_deleg_dentry(struct nfsd4_open *open, struct nfs4_file *fp,
+                         struct svc_fh *parent)
+{
+       struct svc_export *exp;
+       struct dentry *child;
+       __be32 err;
+
+       /* parent may already be locked, and it may get unlocked by
+        * this call, but that is safe.
+        */
+       err = nfsd_lookup_dentry(open->op_rqstp, parent,
+                                open->op_fname, open->op_fnamelen,
+                                &exp, &child);
+
+       if (err)
+               return -EAGAIN;
+
+       dput(child);
+       if (child != file_dentry(fp->fi_deleg_file->nf_file))
+               return -EAGAIN;
+
+       return 0;
+}
+
 static struct nfs4_delegation *
-nfs4_set_delegation(struct nfs4_client *clp,
-                   struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate)
+nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
+                   struct svc_fh *parent)
 {
        int status = 0;
+       struct nfs4_client *clp = stp->st_stid.sc_client;
+       struct nfs4_file *fp = stp->st_stid.sc_file;
+       struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate;
        struct nfs4_delegation *dp;
        struct nfsd_file *nf;
        struct file_lock *fl;
                locks_free_lock(fl);
        if (status)
                goto out_clnt_odstate;
+
+       if (parent) {
+               status = nfsd4_verify_deleg_dentry(open, fp, parent);
+               if (status)
+                       goto out_unlock;
+       }
+
        status = nfsd4_check_conflicting_opens(clp, fp);
        if (status)
                goto out_unlock;
  * proper support for them.
  */
 static void
-nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
+nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
+                    struct svc_fh *currentfh)
 {
        struct nfs4_delegation *dp;
        struct nfs4_openowner *oo = openowner(stp->st_stateowner);
        struct nfs4_client *clp = stp->st_stid.sc_client;
+       struct svc_fh *parent = NULL;
        int cb_up;
        int status = 0;
 
                                goto out_no_deleg;
                        break;
                case NFS4_OPEN_CLAIM_NULL:
+                       parent = currentfh;
+                       fallthrough;
                case NFS4_OPEN_CLAIM_FH:
                        /*
                         * Let's not give out any delegations till everyone's
                default:
                        goto out_no_deleg;
        }
-       dp = nfs4_set_delegation(clp, stp->st_stid.sc_file, stp->st_clnt_odstate);
+       dp = nfs4_set_delegation(open, stp, parent);
        if (IS_ERR(dp))
                goto out_no_deleg;
 
        * Attempt to hand out a delegation. No error return, because the
        * OPEN succeeds even if we fail.
        */
-       nfs4_open_delegation(open, stp);
+       nfs4_open_delegation(open, stp, &resp->cstate.current_fh);
 nodeleg:
        status = nfs_ok;
        trace_nfsd_open(&stp->st_stid.sc_stateid);