]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - fs/nfs/nfs4proc.c
Merge branch 'writeback-for-2.6.34' into nfs-for-2.6.34
[net-next-2.6.git] / fs / nfs / nfs4proc.c
index 84d83be25a98b4d8456fdaeb321f086d313b0e3f..eda74c42d552a044b5ba3b8541b9034cc29afff8 100644 (file)
@@ -281,6 +281,7 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
                        }
                case -NFS4ERR_GRACE:
                case -NFS4ERR_DELAY:
+               case -EKEYEXPIRED:
                        ret = nfs4_delay(server->client, &exception->timeout);
                        if (ret != 0)
                                break;
@@ -418,7 +419,8 @@ static void nfs41_sequence_done(struct nfs_client *clp,
                        clp->cl_last_renewal = timestamp;
                spin_unlock(&clp->cl_lock);
                /* Check sequence flags */
-               nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
+               if (atomic_read(&clp->cl_count) > 1)
+                       nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
        }
 out:
        /* The session may be reset by one of the error handlers. */
@@ -1163,7 +1165,7 @@ static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state
        int err;
        do {
                err = _nfs4_do_open_reclaim(ctx, state);
-               if (err != -NFS4ERR_DELAY)
+               if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED)
                        break;
                nfs4_handle_exception(server, err, &exception);
        } while (exception.retry);
@@ -1582,6 +1584,7 @@ static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state
                        goto out;
                case -NFS4ERR_GRACE:
                case -NFS4ERR_DELAY:
+               case -EKEYEXPIRED:
                        nfs4_handle_exception(server, err, &exception);
                        err = 0;
                }
@@ -3145,10 +3148,19 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa
  * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special
  * standalone procedure for queueing an asynchronous RENEW.
  */
+static void nfs4_renew_release(void *data)
+{
+       struct nfs_client *clp = data;
+
+       if (atomic_read(&clp->cl_count) > 1)
+               nfs4_schedule_state_renewal(clp);
+       nfs_put_client(clp);
+}
+
 static void nfs4_renew_done(struct rpc_task *task, void *data)
 {
-       struct nfs_client *clp = (struct nfs_client *)task->tk_msg.rpc_argp;
-       unsigned long timestamp = (unsigned long)data;
+       struct nfs_client *clp = data;
+       unsigned long timestamp = task->tk_start;
 
        if (task->tk_status < 0) {
                /* Unless we're shutting down, schedule state recovery! */
@@ -3164,6 +3176,7 @@ static void nfs4_renew_done(struct rpc_task *task, void *data)
 
 static const struct rpc_call_ops nfs4_renew_ops = {
        .rpc_call_done = nfs4_renew_done,
+       .rpc_release = nfs4_renew_release,
 };
 
 int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred)
@@ -3174,8 +3187,10 @@ int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred)
                .rpc_cred       = cred,
        };
 
+       if (!atomic_inc_not_zero(&clp->cl_count))
+               return -EIO;
        return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT,
-                       &nfs4_renew_ops, (void *)jiffies);
+                       &nfs4_renew_ops, clp);
 }
 
 int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred)
@@ -3452,6 +3467,7 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
                        if (server)
                                nfs_inc_server_stats(server, NFSIOS_DELAY);
                case -NFS4ERR_GRACE:
+               case -EKEYEXPIRED:
                        rpc_delay(task, NFS4_POLL_RETRY_MAX);
                        task->tk_status = 0;
                        return -EAGAIN;
@@ -3564,6 +3580,7 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred)
                        case -NFS4ERR_RESOURCE:
                                /* The IBM lawyers misread another document! */
                        case -NFS4ERR_DELAY:
+                       case -EKEYEXPIRED:
                                err = nfs4_delay(clp->cl_rpcclient, &timeout);
                }
        } while (err == 0);
@@ -4179,7 +4196,7 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request
                if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
                        return 0;
                err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM);
-               if (err != -NFS4ERR_DELAY)
+               if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED)
                        break;
                nfs4_handle_exception(server, err, &exception);
        } while (exception.retry);
@@ -4204,6 +4221,7 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
                        goto out;
                case -NFS4ERR_GRACE:
                case -NFS4ERR_DELAY:
+               case -EKEYEXPIRED:
                        nfs4_handle_exception(server, err, &exception);
                        err = 0;
                }
@@ -4355,6 +4373,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
                                err = 0;
                                goto out;
                        case -NFS4ERR_DELAY:
+                       case -EKEYEXPIRED:
                                break;
                }
                err = nfs4_handle_exception(server, err, &exception);
@@ -4500,7 +4519,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
 
                status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
 
-               if (status != NFS4ERR_CLID_INUSE)
+               if (status != -NFS4ERR_CLID_INUSE)
                        break;
 
                if (signalled())
@@ -4554,6 +4573,7 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
        switch (task->tk_status) {
        case -NFS4ERR_DELAY:
        case -NFS4ERR_GRACE:
+       case -EKEYEXPIRED:
                dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status);
                rpc_delay(task, NFS4_POLL_RETRY_MIN);
                task->tk_status = 0;
@@ -4611,26 +4631,32 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
 /*
  * Reset a slot table
  */
-static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, int max_slots,
-               int old_max_slots, int ivalue)
+static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs,
+                                int ivalue)
 {
+       struct nfs4_slot *new = NULL;
        int i;
        int ret = 0;
 
-       dprintk("--> %s: max_reqs=%u, tbl %p\n", __func__, max_slots, tbl);
+       dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__,
+               max_reqs, tbl->max_slots);
 
-       /*
-        * Until we have dynamic slot table adjustment, insist
-        * upon the same slot table size
-        */
-       if (max_slots != old_max_slots) {
-               dprintk("%s reset slot table does't match old\n",
-                       __func__);
-               ret = -EINVAL; /*XXX NFS4ERR_REQ_TOO_BIG ? */
-               goto out;
+       /* Does the newly negotiated max_reqs match the existing slot table? */
+       if (max_reqs != tbl->max_slots) {
+               ret = -ENOMEM;
+               new = kmalloc(max_reqs * sizeof(struct nfs4_slot),
+                             GFP_KERNEL);
+               if (!new)
+                       goto out;
+               ret = 0;
+               kfree(tbl->slots);
        }
        spin_lock(&tbl->slot_tbl_lock);
-       for (i = 0; i < max_slots; ++i)
+       if (new) {
+               tbl->slots = new;
+               tbl->max_slots = max_reqs;
+       }
+       for (i = 0; i < tbl->max_slots; ++i)
                tbl->slots[i].seq_nr = ivalue;
        spin_unlock(&tbl->slot_tbl_lock);
        dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__,
@@ -4648,16 +4674,12 @@ static int nfs4_reset_slot_tables(struct nfs4_session *session)
        int status;
 
        status = nfs4_reset_slot_table(&session->fc_slot_table,
-                       session->fc_attrs.max_reqs,
-                       session->fc_slot_table.max_slots,
-                       1);
+                       session->fc_attrs.max_reqs, 1);
        if (status)
                return status;
 
        status = nfs4_reset_slot_table(&session->bc_slot_table,
-                       session->bc_attrs.max_reqs,
-                       session->bc_slot_table.max_slots,
-                       0);
+                       session->bc_attrs.max_reqs, 0);
        return status;
 }
 
@@ -4798,16 +4820,14 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args)
        args->fc_attrs.headerpadsz = 0;
        args->fc_attrs.max_rqst_sz = mxrqst_sz;
        args->fc_attrs.max_resp_sz = mxresp_sz;
-       args->fc_attrs.max_resp_sz_cached = mxresp_sz;
        args->fc_attrs.max_ops = NFS4_MAX_OPS;
        args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs;
 
        dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u "
-               "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n",
+               "max_ops=%u max_reqs=%u\n",
                __func__,
                args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz,
-               args->fc_attrs.max_resp_sz_cached, args->fc_attrs.max_ops,
-               args->fc_attrs.max_reqs);
+               args->fc_attrs.max_ops, args->fc_attrs.max_reqs);
 
        /* Back channel attributes */
        args->bc_attrs.headerpadsz = 0;
@@ -5016,7 +5036,16 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
                                       &res, args.sa_cache_this, 1);
 }
 
-void nfs41_sequence_call_done(struct rpc_task *task, void *data)
+static void nfs41_sequence_release(void *data)
+{
+       struct nfs_client *clp = (struct nfs_client *)data;
+
+       if (atomic_read(&clp->cl_count) > 1)
+               nfs4_schedule_state_renewal(clp);
+       nfs_put_client(clp);
+}
+
+static void nfs41_sequence_call_done(struct rpc_task *task, void *data)
 {
        struct nfs_client *clp = (struct nfs_client *)data;
 
@@ -5024,6 +5053,8 @@ void nfs41_sequence_call_done(struct rpc_task *task, void *data)
 
        if (task->tk_status < 0) {
                dprintk("%s ERROR %d\n", __func__, task->tk_status);
+               if (atomic_read(&clp->cl_count) == 1)
+                       goto out;
 
                if (_nfs4_async_handle_error(task, NULL, clp, NULL)
                                                                == -EAGAIN) {
@@ -5032,7 +5063,7 @@ void nfs41_sequence_call_done(struct rpc_task *task, void *data)
                }
        }
        dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred);
-
+out:
        kfree(task->tk_msg.rpc_argp);
        kfree(task->tk_msg.rpc_resp);
 
@@ -5057,6 +5088,7 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data)
 static const struct rpc_call_ops nfs41_sequence_ops = {
        .rpc_call_done = nfs41_sequence_call_done,
        .rpc_call_prepare = nfs41_sequence_prepare,
+       .rpc_release = nfs41_sequence_release,
 };
 
 static int nfs41_proc_async_sequence(struct nfs_client *clp,
@@ -5069,12 +5101,13 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp,
                .rpc_cred = cred,
        };
 
+       if (!atomic_inc_not_zero(&clp->cl_count))
+               return -EIO;
        args = kzalloc(sizeof(*args), GFP_KERNEL);
-       if (!args)
-               return -ENOMEM;
        res = kzalloc(sizeof(*res), GFP_KERNEL);
-       if (!res) {
+       if (!args || !res) {
                kfree(args);
+               nfs_put_client(clp);
                return -ENOMEM;
        }
        res->sr_slotid = NFS4_MAX_SLOT_TABLE;