NFSv4: Remove redundant RENEW calls if we know the lease has expired
[pandora-kernel.git] / fs / nfs / nfs4proc.c
index 83e700a..780ba00 100644 (file)
@@ -344,7 +344,7 @@ static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_fla
 {
        if ((delegation->type & open_flags) != open_flags)
                return 0;
-       if (delegation->flags & NFS_DELEGATION_NEED_RECLAIM)
+       if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
                return 0;
        return 1;
 }
@@ -388,9 +388,8 @@ static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid
        write_sequnlock(&state->seqlock);
 }
 
-static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags)
+static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, int open_flags)
 {
-       open_flags &= (FMODE_READ|FMODE_WRITE);
        /*
         * Protect the call to nfs4_state_set_mode_locked and
         * serialise the stateid update
@@ -408,6 +407,45 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_sta
        spin_unlock(&state->owner->so_lock);
 }
 
+static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *delegation, int open_flags)
+{
+       struct nfs_inode *nfsi = NFS_I(state->inode);
+       struct nfs_delegation *deleg_cur;
+       int ret = 0;
+
+       open_flags &= (FMODE_READ|FMODE_WRITE);
+
+       rcu_read_lock();
+       deleg_cur = rcu_dereference(nfsi->delegation);
+       if (deleg_cur == NULL)
+               goto no_delegation;
+
+       spin_lock(&deleg_cur->lock);
+       if (nfsi->delegation != deleg_cur ||
+           (deleg_cur->type & open_flags) != open_flags)
+               goto no_delegation_unlock;
+
+       if (delegation == NULL)
+               delegation = &deleg_cur->stateid;
+       else if (memcmp(deleg_cur->stateid.data, delegation->data, NFS4_STATEID_SIZE) != 0)
+               goto no_delegation_unlock;
+
+       __update_open_stateid(state, open_stateid, &deleg_cur->stateid, open_flags);
+       ret = 1;
+no_delegation_unlock:
+       spin_unlock(&deleg_cur->lock);
+no_delegation:
+       rcu_read_unlock();
+
+       if (!ret && open_stateid != NULL) {
+               __update_open_stateid(state, open_stateid, NULL, open_flags);
+               ret = 1;
+       }
+
+       return ret;
+}
+
+
 static void nfs4_return_incompatible_delegation(struct inode *inode, mode_t open_flags)
 {
        struct nfs_delegation *delegation;
@@ -431,23 +469,23 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
        nfs4_stateid stateid;
        int ret = -EAGAIN;
 
-       rcu_read_lock();
-       delegation = rcu_dereference(nfsi->delegation);
        for (;;) {
                if (can_open_cached(state, open_mode)) {
                        spin_lock(&state->owner->so_lock);
                        if (can_open_cached(state, open_mode)) {
                                update_open_stateflags(state, open_mode);
                                spin_unlock(&state->owner->so_lock);
-                               rcu_read_unlock();
                                goto out_return_state;
                        }
                        spin_unlock(&state->owner->so_lock);
                }
-               if (delegation == NULL)
-                       break;
-               if (!can_open_delegated(delegation, open_mode))
+               rcu_read_lock();
+               delegation = rcu_dereference(nfsi->delegation);
+               if (delegation == NULL ||
+                   !can_open_delegated(delegation, open_mode)) {
+                       rcu_read_unlock();
                        break;
+               }
                /* Save the delegation */
                memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data));
                rcu_read_unlock();
@@ -455,19 +493,11 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
                if (ret != 0)
                        goto out;
                ret = -EAGAIN;
-               rcu_read_lock();
-               delegation = rcu_dereference(nfsi->delegation);
-               /* If no delegation, try a cached open */
-               if (delegation == NULL)
-                       continue;
-               /* Is the delegation still valid? */
-               if (memcmp(stateid.data, delegation->stateid.data, sizeof(stateid.data)) != 0)
-                       continue;
-               rcu_read_unlock();
-               update_open_stateid(state, NULL, &stateid, open_mode);
-               goto out_return_state;
+
+               /* Try to update the stateid using the delegation */
+               if (update_open_stateid(state, NULL, &stateid, open_mode))
+                       goto out_return_state;
        }
-       rcu_read_unlock();
 out:
        return ERR_PTR(ret);
 out_return_state:
@@ -480,7 +510,6 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
        struct inode *inode;
        struct nfs4_state *state = NULL;
        struct nfs_delegation *delegation;
-       nfs4_stateid *deleg_stateid = NULL;
        int ret;
 
        if (!data->rpc_done) {
@@ -507,7 +536,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
                if (delegation)
                        delegation_flags = delegation->flags;
                rcu_read_unlock();
-               if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM))
+               if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
                        nfs_inode_set_delegation(state->inode,
                                        data->owner->so_cred,
                                        &data->o_res);
@@ -516,12 +545,9 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
                                        data->owner->so_cred,
                                        &data->o_res);
        }
-       rcu_read_lock();
-       delegation = rcu_dereference(NFS_I(inode)->delegation);
-       if (delegation != NULL)
-               deleg_stateid = &delegation->stateid;
-       update_open_stateid(state, &data->o_res.stateid, deleg_stateid, data->o_arg.open_flags);
-       rcu_read_unlock();
+
+       update_open_stateid(state, &data->o_res.stateid, NULL,
+                       data->o_arg.open_flags);
        iput(inode);
 out:
        return state;
@@ -641,7 +667,7 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state
        opendata->o_arg.fh = NFS_FH(state->inode);
        rcu_read_lock();
        delegation = rcu_dereference(NFS_I(state->inode)->delegation);
-       if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) != 0)
+       if (delegation != NULL && test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) != 0)
                delegation_type = delegation->type;
        rcu_read_unlock();
        opendata->o_arg.u.delegation_type = delegation_type;
@@ -813,7 +839,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
                rcu_read_lock();
                delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
                if (delegation != NULL &&
-                  (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) {
+                   test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) == 0) {
                        rcu_read_unlock();
                        goto out_no_action;
                }
@@ -958,7 +984,8 @@ static int nfs4_recover_expired_lease(struct nfs_server *server)
                ret = nfs4_wait_clnt_recover(server->client, clp);
                if (ret != 0)
                        return ret;
-               if (!test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
+               if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) &&
+                   !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state))
                        break;
                nfs4_schedule_state_recovery(clp);
        }
@@ -2916,7 +2943,6 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cre
                spin_lock(&clp->cl_lock);
                clp->cl_lease_time = fsinfo.lease_time * HZ;
                clp->cl_last_renewal = now;
-               clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
                spin_unlock(&clp->cl_lock);
        }
        return status;
@@ -3664,11 +3690,13 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
 }
 
 struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = {
+       .state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
        .recover_open   = nfs4_open_reclaim,
        .recover_lock   = nfs4_lock_reclaim,
 };
 
-struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops = {
+struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops = {
+       .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
        .recover_open   = nfs4_open_expired,
        .recover_lock   = nfs4_lock_expired,
 };