Merge branch 'linus' into perf/core
[safe/jmp/linux-2.6] / fs / nfs / nfs4proc.c
index 84b53d3..6380670 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/string.h>
+#include <linux/slab.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfs.h>
 #include <linux/nfs4.h>
@@ -419,7 +420,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. */
@@ -725,8 +727,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
        p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid);
        if (p->o_arg.seqid == NULL)
                goto err_free;
-       p->path.mnt = mntget(path->mnt);
-       p->path.dentry = dget(path->dentry);
+       path_get(path);
+       p->path = *path;
        p->dir = parent;
        p->owner = sp;
        atomic_inc(&sp->so_count);
@@ -1521,6 +1523,8 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
                nfs_post_op_update_inode(dir, o_res->dir_attr);
        } else
                nfs_refresh_inode(dir, o_res->dir_attr);
+       if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0)
+               server->caps &= ~NFS_CAP_POSIX_LOCK;
        if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
                status = _nfs4_proc_open_confirm(data);
                if (status != 0)
@@ -1662,7 +1666,7 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in
        status = PTR_ERR(state);
        if (IS_ERR(state))
                goto err_opendata_put;
-       if ((opendata->o_res.rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) != 0)
+       if (server->caps & NFS_CAP_POSIX_LOCK)
                set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
        nfs4_opendata_put(opendata);
        nfs4_put_state_owner(sp);
@@ -1946,8 +1950,8 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
        calldata->res.seqid = calldata->arg.seqid;
        calldata->res.server = server;
        calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
-       calldata->path.mnt = mntget(path->mnt);
-       calldata->path.dentry = dget(path->dentry);
+       path_get(path);
+       calldata->path = *path;
 
        msg.rpc_argp = &calldata->arg,
        msg.rpc_resp = &calldata->res,
@@ -2066,8 +2070,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
                        case -EDQUOT:
                        case -ENOSPC:
                        case -EROFS:
-                               lookup_instantiate_filp(nd, (struct dentry *)state, NULL);
-                               return 1;
+                               return PTR_ERR(state);
                        default:
                                goto out_drop;
                }
@@ -3147,10 +3150,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! */
@@ -3166,6 +3178,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)
@@ -3176,8 +3189,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)
@@ -4506,7 +4521,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())
@@ -5023,7 +5038,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;
 
@@ -5031,6 +5055,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) {
@@ -5039,7 +5065,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);
 
@@ -5064,6 +5090,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,
@@ -5076,12 +5103,14 @@ 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);
+               kfree(res);
+               nfs_put_client(clp);
                return -ENOMEM;
        }
        res->sr_slotid = NFS4_MAX_SLOT_TABLE;