- patches.arch/x86_mce_intel_decode_physical_address.patch:
[linux-flexiantxendom0-3.2.10.git] / fs / nfs / nfs4proc.c
index 071fced..70015dd 100644 (file)
@@ -70,6 +70,9 @@ static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinf
 static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *);
 static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
 static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
+static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
+                           struct nfs_fattr *fattr, struct iattr *sattr,
+                           struct nfs4_state *state);
 
 /* Prevent leaks of NFSv4 errors into userland */
 static int nfs4_map_errors(int err)
@@ -714,17 +717,18 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
 
 static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
                struct nfs4_state_owner *sp, fmode_t fmode, int flags,
-               const struct iattr *attrs)
+               const struct iattr *attrs,
+               gfp_t gfp_mask)
 {
        struct dentry *parent = dget_parent(path->dentry);
        struct inode *dir = parent->d_inode;
        struct nfs_server *server = NFS_SERVER(dir);
        struct nfs4_opendata *p;
 
-       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       p = kzalloc(sizeof(*p), gfp_mask);
        if (p == NULL)
                goto err;
-       p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid);
+       p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask);
        if (p->o_arg.seqid == NULL)
                goto err_free;
        path_get(path);
@@ -1060,7 +1064,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
 {
        struct nfs4_opendata *opendata;
 
-       opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, 0, NULL);
+       opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, 0, NULL, GFP_NOFS);
        if (opendata == NULL)
                return ERR_PTR(-ENOMEM);
        opendata->state = state;
@@ -1648,7 +1652,7 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in
        if (path->dentry->d_inode != NULL)
                nfs4_return_incompatible_delegation(path->dentry->d_inode, fmode);
        status = -ENOMEM;
-       opendata = nfs4_opendata_alloc(path, sp, fmode, flags, sattr);
+       opendata = nfs4_opendata_alloc(path, sp, fmode, flags, sattr, GFP_KERNEL);
        if (opendata == NULL)
                goto err_put_state_owner;
 
@@ -1659,15 +1663,24 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in
        if (status != 0)
                goto err_opendata_put;
 
-       if (opendata->o_arg.open_flags & O_EXCL)
-               nfs4_exclusive_attrset(opendata, sattr);
-
        state = nfs4_opendata_to_nfs4_state(opendata);
        status = PTR_ERR(state);
        if (IS_ERR(state))
                goto err_opendata_put;
        if (server->caps & NFS_CAP_POSIX_LOCK)
                set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
+
+       if (opendata->o_arg.open_flags & O_EXCL) {
+               nfs4_exclusive_attrset(opendata, sattr);
+
+               nfs_fattr_init(opendata->o_res.f_attr);
+               status = nfs4_do_setattr(state->inode, cred,
+                               opendata->o_res.f_attr, sattr,
+                               state);
+               if (status == 0)
+                       nfs_setattr_update_inode(state->inode, sattr);
+               nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr);
+       }
        nfs4_opendata_put(opendata);
        nfs4_put_state_owner(sp);
        *res = state;
@@ -1914,7 +1927,7 @@ static const struct rpc_call_ops nfs4_close_ops = {
  *
  * NOTE: Caller must be holding the sp->so_owner semaphore!
  */
-int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
+int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait)
 {
        struct nfs_server *server = NFS_SERVER(state->inode);
        struct nfs4_closedata *calldata;
@@ -1933,7 +1946,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
        };
        int status = -ENOMEM;
 
-       calldata = kzalloc(sizeof(*calldata), GFP_KERNEL);
+       calldata = kzalloc(sizeof(*calldata), gfp_mask);
        if (calldata == NULL)
                goto out;
        calldata->inode = state->inode;
@@ -1941,7 +1954,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
        calldata->arg.fh = NFS_FH(state->inode);
        calldata->arg.stateid = &state->open_stateid;
        /* Serialization for the sequence id */
-       calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid);
+       calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid, gfp_mask);
        if (calldata->arg.seqid == NULL)
                goto out_free_calldata;
        calldata->arg.fmode = 0;
@@ -2404,14 +2417,12 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh
 static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
 {
        struct nfs_server *server = NFS_SERVER(inode);
-       struct nfs_fattr fattr;
        struct nfs4_accessargs args = {
                .fh = NFS_FH(inode),
                .bitmask = server->attr_bitmask,
        };
        struct nfs4_accessres res = {
                .server = server,
-               .fattr = &fattr,
        };
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
@@ -2438,7 +2449,11 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
                if (mode & MAY_EXEC)
                        args.access |= NFS4_ACCESS_EXECUTE;
        }
-       nfs_fattr_init(&fattr);
+
+       res.fattr = nfs_alloc_fattr();
+       if (res.fattr == NULL)
+               return -ENOMEM;
+
        status = nfs4_call_sync(server, &msg, &args, &res, 0);
        if (!status) {
                entry->mask = 0;
@@ -2448,8 +2463,9 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
                        entry->mask |= MAY_WRITE;
                if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))
                        entry->mask |= MAY_EXEC;
-               nfs_refresh_inode(inode, &fattr);
+               nfs_refresh_inode(inode, res.fattr);
        }
+       nfs_free_fattr(res.fattr);
        return status;
 }
 
@@ -2562,13 +2578,6 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
        }
        d_add(dentry, igrab(state->inode));
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
-       if (flags & O_EXCL) {
-               struct nfs_fattr fattr;
-               status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, state);
-               if (status == 0)
-                       nfs_setattr_update_inode(state->inode, sattr);
-               nfs_post_op_update_inode(state->inode, &fattr);
-       }
        if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
                status = nfs4_intent_set_file(nd, &path, state, fmode);
        else
@@ -2596,14 +2605,19 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
-       int                     status;
+       int status = -ENOMEM;
+
+       res.dir_attr = nfs_alloc_fattr();
+       if (res.dir_attr == NULL)
+               goto out;
 
-       nfs_fattr_init(&res.dir_attr);
        status = nfs4_call_sync(server, &msg, &args, &res, 1);
        if (status == 0) {
                update_changeattr(dir, &res.cinfo);
-               nfs_post_op_update_inode(dir, &res.dir_attr);
+               nfs_post_op_update_inode(dir, res.dir_attr);
        }
+       nfs_free_fattr(res.dir_attr);
+out:
        return status;
 }
 
@@ -2638,7 +2652,7 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
        if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
                return 0;
        update_changeattr(dir, &res->cinfo);
-       nfs_post_op_update_inode(dir, &res->dir_attr);
+       nfs_post_op_update_inode(dir, res->dir_attr);
        return 1;
 }
 
@@ -2653,29 +2667,31 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
                .new_name = new_name,
                .bitmask = server->attr_bitmask,
        };
-       struct nfs_fattr old_fattr, new_fattr;
        struct nfs4_rename_res res = {
                .server = server,
-               .old_fattr = &old_fattr,
-               .new_fattr = &new_fattr,
        };
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME],
                .rpc_argp = &arg,
                .rpc_resp = &res,
        };
-       int                     status;
+       int status = -ENOMEM;
        
-       nfs_fattr_init(res.old_fattr);
-       nfs_fattr_init(res.new_fattr);
-       status = nfs4_call_sync(server, &msg, &arg, &res, 1);
+       res.old_fattr = nfs_alloc_fattr();
+       res.new_fattr = nfs_alloc_fattr();
+       if (res.old_fattr == NULL || res.new_fattr == NULL)
+               goto out;
 
+       status = nfs4_call_sync(server, &msg, &arg, &res, 1);
        if (!status) {
                update_changeattr(old_dir, &res.old_cinfo);
                nfs_post_op_update_inode(old_dir, res.old_fattr);
                update_changeattr(new_dir, &res.new_cinfo);
                nfs_post_op_update_inode(new_dir, res.new_fattr);
        }
+out:
+       nfs_free_fattr(res.new_fattr);
+       nfs_free_fattr(res.old_fattr);
        return status;
 }
 
@@ -2702,28 +2718,30 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
                .name   = name,
                .bitmask = server->attr_bitmask,
        };
-       struct nfs_fattr fattr, dir_attr;
        struct nfs4_link_res res = {
                .server = server,
-               .fattr = &fattr,
-               .dir_attr = &dir_attr,
        };
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK],
                .rpc_argp = &arg,
                .rpc_resp = &res,
        };
-       int                     status;
+       int status = -ENOMEM;
+
+       res.fattr = nfs_alloc_fattr();
+       res.dir_attr = nfs_alloc_fattr();
+       if (res.fattr == NULL || res.dir_attr == NULL)
+               goto out;
 
-       nfs_fattr_init(res.fattr);
-       nfs_fattr_init(res.dir_attr);
        status = nfs4_call_sync(server, &msg, &arg, &res, 1);
        if (!status) {
                update_changeattr(dir, &res.cinfo);
                nfs_post_op_update_inode(dir, res.dir_attr);
                nfs_post_op_update_inode(inode, res.fattr);
        }
-
+out:
+       nfs_free_fattr(res.dir_attr);
+       nfs_free_fattr(res.fattr);
        return status;
 }
 
@@ -3146,23 +3164,31 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
 }
 
+struct nfs4_renewdata {
+       struct nfs_client       *client;
+       unsigned long           timestamp;
+};
+
 /*
  * 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)
+static void nfs4_renew_release(void *calldata)
 {
-       struct nfs_client *clp = data;
+       struct nfs4_renewdata *data = calldata;
+       struct nfs_client *clp = data->client;
 
        if (atomic_read(&clp->cl_count) > 1)
                nfs4_schedule_state_renewal(clp);
        nfs_put_client(clp);
+       kfree(data);
 }
 
-static void nfs4_renew_done(struct rpc_task *task, void *data)
+static void nfs4_renew_done(struct rpc_task *task, void *calldata)
 {
-       struct nfs_client *clp = data;
-       unsigned long timestamp = task->tk_start;
+       struct nfs4_renewdata *data = calldata;
+       struct nfs_client *clp = data->client;
+       unsigned long timestamp = data->timestamp;
 
        if (task->tk_status < 0) {
                /* Unless we're shutting down, schedule state recovery! */
@@ -3188,11 +3214,17 @@ int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred)
                .rpc_argp       = clp,
                .rpc_cred       = cred,
        };
+       struct nfs4_renewdata *data;
 
        if (!atomic_inc_not_zero(&clp->cl_count))
                return -EIO;
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
+       if (data == NULL)
+               return -ENOMEM;
+       data->client = clp;
+       data->timestamp = jiffies;
        return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT,
-                       &nfs4_renew_ops, clp);
+                       &nfs4_renew_ops, data);
 }
 
 int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred)
@@ -3494,7 +3526,9 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
        return _nfs4_async_handle_error(task, server, server->nfs_client, state);
 }
 
-int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred)
+int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
+               unsigned short port, struct rpc_cred *cred,
+               struct nfs4_setclientid_res *res)
 {
        nfs4_verifier sc_verifier;
        struct nfs4_setclientid setclientid = {
@@ -3504,7 +3538,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID],
                .rpc_argp = &setclientid,
-               .rpc_resp = clp,
+               .rpc_resp = res,
                .rpc_cred = cred,
        };
        __be32 *p;
@@ -3547,12 +3581,14 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po
        return status;
 }
 
-static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred)
+static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp,
+               struct nfs4_setclientid_res *arg,
+               struct rpc_cred *cred)
 {
        struct nfs_fsinfo fsinfo;
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM],
-               .rpc_argp = clp,
+               .rpc_argp = arg,
                .rpc_resp = &fsinfo,
                .rpc_cred = cred,
        };
@@ -3570,12 +3606,14 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cre
        return status;
 }
 
-int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred)
+int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
+               struct nfs4_setclientid_res *arg,
+               struct rpc_cred *cred)
 {
        long timeout = 0;
        int err;
        do {
-               err = _nfs4_proc_setclientid_confirm(clp, cred);
+               err = _nfs4_proc_setclientid_confirm(clp, arg, cred);
                switch (err) {
                        case 0:
                                return err;
@@ -3667,7 +3705,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
        };
        int status = 0;
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       data = kzalloc(sizeof(*data), GFP_NOFS);
        if (data == NULL)
                return -ENOMEM;
        data->args.fhandle = &data->fh;
@@ -3823,7 +3861,7 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
        struct nfs4_unlockdata *p;
        struct inode *inode = lsp->ls_state->inode;
 
-       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       p = kzalloc(sizeof(*p), GFP_NOFS);
        if (p == NULL)
                return NULL;
        p->arg.fh = NFS_FH(inode);
@@ -3961,7 +3999,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
        if (test_bit(NFS_DELEGATED_STATE, &state->flags))
                goto out;
        lsp = request->fl_u.nfs4_fl.owner;
-       seqid = nfs_alloc_seqid(&lsp->ls_seqid);
+       seqid = nfs_alloc_seqid(&lsp->ls_seqid, GFP_KERNEL);
        status = -ENOMEM;
        if (seqid == NULL)
                goto out;
@@ -3989,22 +4027,23 @@ struct nfs4_lockdata {
 };
 
 static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
-               struct nfs_open_context *ctx, struct nfs4_lock_state *lsp)
+               struct nfs_open_context *ctx, struct nfs4_lock_state *lsp,
+               gfp_t gfp_mask)
 {
        struct nfs4_lockdata *p;
        struct inode *inode = lsp->ls_state->inode;
        struct nfs_server *server = NFS_SERVER(inode);
 
-       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       p = kzalloc(sizeof(*p), gfp_mask);
        if (p == NULL)
                return NULL;
 
        p->arg.fh = NFS_FH(inode);
        p->arg.fl = &p->fl;
-       p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid);
+       p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid, gfp_mask);
        if (p->arg.open_seqid == NULL)
                goto out_free;
-       p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid);
+       p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid, gfp_mask);
        if (p->arg.lock_seqid == NULL)
                goto out_free_seqid;
        p->arg.lock_stateid = &lsp->ls_stateid;
@@ -4158,7 +4197,8 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
 
        dprintk("%s: begin!\n", __func__);
        data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file),
-                       fl->fl_u.nfs4_fl.owner);
+                       fl->fl_u.nfs4_fl.owner,
+                       recovery_type == NFS_LOCK_NEW ? GFP_KERNEL : GFP_NOFS);
        if (data == NULL)
                return -ENOMEM;
        if (IS_SETLKW(cmd))
@@ -4647,7 +4687,7 @@ static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs,
        if (max_reqs != tbl->max_slots) {
                ret = -ENOMEM;
                new = kmalloc(max_reqs * sizeof(struct nfs4_slot),
-                             GFP_KERNEL);
+                             GFP_NOFS);
                if (!new)
                        goto out;
                ret = 0;
@@ -4712,7 +4752,7 @@ static int nfs4_init_slot_table(struct nfs4_slot_table *tbl,
 
        dprintk("--> %s: max_reqs=%u\n", __func__, max_slots);
 
-       slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL);
+       slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_NOFS);
        if (!slot)
                goto out;
        ret = 0;
@@ -4761,7 +4801,7 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
        struct nfs4_session *session;
        struct nfs4_slot_table *tbl;
 
-       session = kzalloc(sizeof(struct nfs4_session), GFP_KERNEL);
+       session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS);
        if (!session)
                return NULL;
 
@@ -5105,8 +5145,8 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp,
 
        if (!atomic_inc_not_zero(&clp->cl_count))
                return -EIO;
-       args = kzalloc(sizeof(*args), GFP_KERNEL);
-       res = kzalloc(sizeof(*res), GFP_KERNEL);
+       args = kzalloc(sizeof(*args), GFP_NOFS);
+       res = kzalloc(sizeof(*res), GFP_NOFS);
        if (!args || !res) {
                kfree(args);
                kfree(res);
@@ -5207,7 +5247,7 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp)
        int status = -ENOMEM;
 
        dprintk("--> %s\n", __func__);
-       calldata = kzalloc(sizeof(*calldata), GFP_KERNEL);
+       calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
        if (calldata == NULL)
                goto out;
        calldata->clp = clp;