NFSv4: Don't recheck permissions on open in case of recovery cached open
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 23 Apr 2013 18:52:44 +0000 (14:52 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 23 Apr 2013 18:52:44 +0000 (14:52 -0400)
If we already checked the user access permissions on the original open,
then don't bother checking again on recovery. Doing so can cause a
deadlock with NFSv4.1, since the may_open() operation is not privileged.
Furthermore, we can't report an access permission failure here anyway.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/nfs4proc.c

index ea50807..e18b3b4 100644 (file)
@@ -769,6 +769,7 @@ struct nfs4_opendata {
        struct iattr attrs;
        unsigned long timestamp;
        unsigned int rpc_done : 1;
+       unsigned int is_recover : 1;
        int rpc_status;
        int cancelled;
 };
@@ -1101,9 +1102,11 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
                /* Save the delegation */
                nfs4_stateid_copy(&stateid, &delegation->stateid);
                rcu_read_unlock();
-               ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
-               if (ret != 0)
-                       goto out;
+               if (!opendata->is_recover) {
+                       ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
+                       if (ret != 0)
+                               goto out;
+               }
                ret = -EAGAIN;
 
                /* Try to update the stateid using the delegation */
@@ -1670,8 +1673,11 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
        data->rpc_done = 0;
        data->rpc_status = 0;
        data->cancelled = 0;
-       if (isrecover)
+       data->is_recover = 0;
+       if (isrecover) {
                nfs4_set_sequence_privileged(&o_arg->seq_args);
+               data->is_recover = 1;
+       }
        task = rpc_run_task(&task_setup_data);
         if (IS_ERR(task))
                 return PTR_ERR(task);