s->sc_type = 0;
 }
 
-static void
+/**
+ * nfs4_get_existing_delegation - Discover if this delegation already exists
+ * @clp:     a pointer to the nfs4_client we're granting a delegation to
+ * @fp:      a pointer to the nfs4_file we're granting a delegation on
+ *
+ * Return:
+ *      On success: NULL if an existing delegation was not found.
+ *
+ *      On error: -EAGAIN if one was previously granted to this nfs4_client
+ *                 for this nfs4_file.
+ *
+ */
+
+static int
+nfs4_get_existing_delegation(struct nfs4_client *clp, struct nfs4_file *fp)
+{
+       struct nfs4_delegation *searchdp = NULL;
+       struct nfs4_client *searchclp = NULL;
+
+       lockdep_assert_held(&state_lock);
+       lockdep_assert_held(&fp->fi_lock);
+
+       list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) {
+               searchclp = searchdp->dl_stid.sc_client;
+               if (clp == searchclp) {
+                       return -EAGAIN;
+               }
+       }
+       return 0;
+}
+
+/**
+ * hash_delegation_locked - Add a delegation to the appropriate lists
+ * @dp:     a pointer to the nfs4_delegation we are adding.
+ * @fp:     a pointer to the nfs4_file we're granting a delegation on
+ *
+ * Return:
+ *      On success: NULL if the delegation was successfully hashed.
+ *
+ *      On error: -EAGAIN if one was previously granted to this
+ *                 nfs4_client for this nfs4_file. Delegation is not hashed.
+ *
+ */
+
+static int
 hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
 {
+       int status;
+       struct nfs4_client *clp = dp->dl_stid.sc_client;
+
        lockdep_assert_held(&state_lock);
        lockdep_assert_held(&fp->fi_lock);
 
+       status = nfs4_get_existing_delegation(clp, fp);
+       if (status)
+               return status;
+       ++fp->fi_delegees;
        atomic_inc(&dp->dl_stid.sc_count);
        dp->dl_stid.sc_type = NFS4_DELEG_STID;
        list_add(&dp->dl_perfile, &fp->fi_delegations);
-       list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
+       list_add(&dp->dl_perclnt, &clp->cl_delegations);
+       return 0;
 }
 
 static bool
        return fl;
 }
 
+/**
+ * nfs4_setlease - Obtain a delegation by requesting lease from vfs layer
+ * @dp:   a pointer to the nfs4_delegation we're adding.
+ *
+ * Return:
+ *      On success: Return code will be 0 on success.
+ *
+ *      On error: -EAGAIN if there was an existing delegation.
+ *                 nonzero if there is an error in other cases.
+ *
+ */
+
 static int nfs4_setlease(struct nfs4_delegation *dp)
 {
        struct nfs4_file *fp = dp->dl_stid.sc_file;
                goto out_unlock;
        /* Race breaker */
        if (fp->fi_deleg_file) {
-               status = 0;
-               ++fp->fi_delegees;
-               hash_delegation_locked(dp, fp);
+               status = hash_delegation_locked(dp, fp);
                goto out_unlock;
        }
        fp->fi_deleg_file = filp;
-       fp->fi_delegees = 1;
-       hash_delegation_locked(dp, fp);
+       fp->fi_delegees = 0;
+       status = hash_delegation_locked(dp, fp);
        spin_unlock(&fp->fi_lock);
        spin_unlock(&state_lock);
+       if (status) {
+               /* Should never happen, this is a new fi_deleg_file  */
+               WARN_ON_ONCE(1);
+               goto out_fput;
+       }
        return 0;
 out_unlock:
        spin_unlock(&fp->fi_lock);
        if (fp->fi_had_conflict)
                return ERR_PTR(-EAGAIN);
 
+       spin_lock(&state_lock);
+       spin_lock(&fp->fi_lock);
+       status = nfs4_get_existing_delegation(clp, fp);
+       spin_unlock(&fp->fi_lock);
+       spin_unlock(&state_lock);
+
+       if (status)
+               return ERR_PTR(status);
+
        dp = alloc_init_deleg(clp, fh, odstate);
        if (!dp)
                return ERR_PTR(-ENOMEM);
                status = -EAGAIN;
                goto out_unlock;
        }
-       ++fp->fi_delegees;
-       hash_delegation_locked(dp, fp);
-       status = 0;
+       status = hash_delegation_locked(dp, fp);
 out_unlock:
        spin_unlock(&fp->fi_lock);
        spin_unlock(&state_lock);