]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/nfs/nfs4proc.c
nfs: fix compilation warning
[mv-sheeva.git] / fs / nfs / nfs4proc.c
index 4435e5e1f904e3e5ba26f4eb578fc30c5f6d997b..b07d4e23b8760b1612e69d3a13b5dad62a493a66 100644 (file)
@@ -49,6 +49,9 @@
 #include <linux/mount.h>
 #include <linux/module.h>
 #include <linux/sunrpc/bc_xprt.h>
+#include <linux/xattr.h>
+#include <linux/utsname.h>
+#include <linux/mm.h>
 
 #include "nfs4_fs.h"
 #include "delegation.h"
@@ -355,9 +358,9 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *free_slot)
 }
 
 /*
- * Signal state manager thread if session is drained
+ * Signal state manager thread if session fore channel is drained
  */
-static void nfs41_check_drain_session_complete(struct nfs4_session *ses)
+static void nfs4_check_drain_fc_complete(struct nfs4_session *ses)
 {
        struct rpc_task *task;
 
@@ -371,8 +374,20 @@ static void nfs41_check_drain_session_complete(struct nfs4_session *ses)
        if (ses->fc_slot_table.highest_used_slotid != -1)
                return;
 
-       dprintk("%s COMPLETE: Session Drained\n", __func__);
-       complete(&ses->complete);
+       dprintk("%s COMPLETE: Session Fore Channel Drained\n", __func__);
+       complete(&ses->fc_slot_table.complete);
+}
+
+/*
+ * Signal state manager thread if session back channel is drained
+ */
+void nfs4_check_drain_bc_complete(struct nfs4_session *ses)
+{
+       if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state) ||
+           ses->bc_slot_table.highest_used_slotid != -1)
+               return;
+       dprintk("%s COMPLETE: Session Back Channel Drained\n", __func__);
+       complete(&ses->bc_slot_table.complete);
 }
 
 static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
@@ -389,7 +404,7 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
 
        spin_lock(&tbl->slot_tbl_lock);
        nfs4_free_slot(tbl, res->sr_slot);
-       nfs41_check_drain_session_complete(res->sr_session);
+       nfs4_check_drain_fc_complete(res->sr_session);
        spin_unlock(&tbl->slot_tbl_lock);
        res->sr_slot = NULL;
 }
@@ -1826,6 +1841,8 @@ struct nfs4_closedata {
        struct nfs_closeres res;
        struct nfs_fattr fattr;
        unsigned long timestamp;
+       bool roc;
+       u32 roc_barrier;
 };
 
 static void nfs4_free_closedata(void *data)
@@ -1833,6 +1850,8 @@ static void nfs4_free_closedata(void *data)
        struct nfs4_closedata *calldata = data;
        struct nfs4_state_owner *sp = calldata->state->owner;
 
+       if (calldata->roc)
+               pnfs_roc_release(calldata->state->inode);
        nfs4_put_open_state(calldata->state);
        nfs_free_seqid(calldata->arg.seqid);
        nfs4_put_state_owner(sp);
@@ -1865,6 +1884,9 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
         */
        switch (task->tk_status) {
                case 0:
+                       if (calldata->roc)
+                               pnfs_roc_set_barrier(state->inode,
+                                                    calldata->roc_barrier);
                        nfs_set_open_stateid(state, &calldata->res.stateid, 0);
                        renew_lease(server, calldata->timestamp);
                        nfs4_close_clear_stateid_flags(state,
@@ -1917,8 +1939,15 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
                return;
        }
 
-       if (calldata->arg.fmode == 0)
+       if (calldata->arg.fmode == 0) {
                task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
+               if (calldata->roc &&
+                   pnfs_roc_drain(calldata->inode, &calldata->roc_barrier)) {
+                       rpc_sleep_on(&NFS_SERVER(calldata->inode)->roc_rpcwaitq,
+                                    task, NULL);
+                       return;
+               }
+       }
 
        nfs_fattr_init(calldata->res.fattr);
        calldata->timestamp = jiffies;
@@ -1946,7 +1975,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, gfp_t gfp_mask, int wait)
+int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc)
 {
        struct nfs_server *server = NFS_SERVER(state->inode);
        struct nfs4_closedata *calldata;
@@ -1981,11 +2010,12 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, i
        calldata->res.fattr = &calldata->fattr;
        calldata->res.seqid = calldata->arg.seqid;
        calldata->res.server = server;
+       calldata->roc = roc;
        path_get(path);
        calldata->path = *path;
 
-       msg.rpc_argp = &calldata->arg,
-       msg.rpc_resp = &calldata->res,
+       msg.rpc_argp = &calldata->arg;
+       msg.rpc_resp = &calldata->res;
        task_setup_data.callback_data = calldata;
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
@@ -1998,6 +2028,8 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, i
 out_free_calldata:
        kfree(calldata);
 out:
+       if (roc)
+               pnfs_roc_release(state->inode);
        nfs4_put_open_state(state);
        nfs4_put_state_owner(sp);
        return status;
@@ -2486,6 +2518,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                path = &ctx->path;
                fmode = ctx->mode;
        }
+       sattr->ia_mode &= ~current_umask();
        state = nfs4_do_open(dir, path, fmode, flags, sattr, cred);
        d_drop(dentry);
        if (IS_ERR(state)) {
@@ -2816,6 +2849,8 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 {
        struct nfs4_exception exception = { };
        int err;
+
+       sattr->ia_mode &= ~current_umask();
        do {
                err = nfs4_handle_exception(NFS_SERVER(dir),
                                _nfs4_proc_mkdir(dir, dentry, sattr),
@@ -2916,6 +2951,8 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 {
        struct nfs4_exception exception = { };
        int err;
+
+       sattr->ia_mode &= ~current_umask();
        do {
                err = nfs4_handle_exception(NFS_SERVER(dir),
                                _nfs4_proc_mknod(dir, dentry, sattr, rdev),
@@ -3216,6 +3253,35 @@ static void buf_to_pages(const void *buf, size_t buflen,
        }
 }
 
+static int buf_to_pages_noslab(const void *buf, size_t buflen,
+               struct page **pages, unsigned int *pgbase)
+{
+       struct page *newpage, **spages;
+       int rc = 0;
+       size_t len;
+       spages = pages;
+
+       do {
+               len = min_t(size_t, PAGE_CACHE_SIZE, buflen);
+               newpage = alloc_page(GFP_KERNEL);
+
+               if (newpage == NULL)
+                       goto unwind;
+               memcpy(page_address(newpage), buf, len);
+                buf += len;
+                buflen -= len;
+               *pages++ = newpage;
+               rc++;
+       } while (buflen != 0);
+
+       return rc;
+
+unwind:
+       for(; rc > 0; rc--)
+               __free_page(spages[rc-1]);
+       return -ENOMEM;
+}
+
 struct nfs4_cached_acl {
        int cached;
        size_t len;
@@ -3384,13 +3450,23 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
                .rpc_argp       = &arg,
                .rpc_resp       = &res,
        };
-       int ret;
+       int ret, i;
 
        if (!nfs4_server_supports_acls(server))
                return -EOPNOTSUPP;
+       i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
+       if (i < 0)
+               return i;
        nfs_inode_return_delegation(inode);
-       buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
        ret = nfs4_call_sync(server, &msg, &arg, &res, 1);
+
+       /*
+        * Free each page after tx, so the only ref left is
+        * held by the network stack
+        */
+       for (; i > 0; i--)
+               put_page(pages[i-1]);
+
        /*
         * Acl update can result in inode attribute update.
         * so mark the attribute cache invalid.
@@ -3478,6 +3554,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
        struct nfs4_setclientid setclientid = {
                .sc_verifier = &sc_verifier,
                .sc_prog = program,
+               .sc_cb_ident = clp->cl_cb_ident,
        };
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID],
@@ -3517,7 +3594,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
                if (signalled())
                        break;
                if (loop++ & 1)
-                       ssleep(clp->cl_lease_time + 1);
+                       ssleep(clp->cl_lease_time / HZ + 1);
                else
                        if (++clp->cl_id_uniquifier == 0)
                                break;
@@ -3663,8 +3740,8 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
        data->rpc_status = 0;
 
        task_setup_data.callback_data = data;
-       msg.rpc_argp = &data->args,
-       msg.rpc_resp = &data->res,
+       msg.rpc_argp = &data->args;
+       msg.rpc_resp = &data->res;
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
@@ -3743,6 +3820,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
                goto out;
        lsp = request->fl_u.nfs4_fl.owner;
        arg.lock_owner.id = lsp->ls_id.id;
+       arg.lock_owner.s_dev = server->s_dev;
        status = nfs4_call_sync(server, &msg, &arg, &res, 1);
        switch (status) {
                case 0:
@@ -3908,8 +3986,8 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
                return ERR_PTR(-ENOMEM);
        }
 
-       msg.rpc_argp = &data->arg,
-       msg.rpc_resp = &data->res,
+       msg.rpc_argp = &data->arg;
+       msg.rpc_resp = &data->res;
        task_setup_data.callback_data = data;
        return rpc_run_task(&task_setup_data);
 }
@@ -3988,6 +4066,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
        p->arg.lock_stateid = &lsp->ls_stateid;
        p->arg.lock_owner.clientid = server->nfs_client->cl_clientid;
        p->arg.lock_owner.id = lsp->ls_id.id;
+       p->arg.lock_owner.s_dev = server->s_dev;
        p->res.lock_seqid = p->arg.lock_seqid;
        p->lsp = lsp;
        p->server = server;
@@ -4071,7 +4150,7 @@ static void nfs4_lock_release(void *calldata)
                task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp,
                                data->arg.lock_seqid);
                if (!IS_ERR(task))
-                       rpc_put_task(task);
+                       rpc_put_task_async(task);
                dprintk("%s: cancelling lock!\n", __func__);
        } else
                nfs_free_seqid(data->arg.lock_seqid);
@@ -4145,8 +4224,8 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
                        data->arg.reclaim = NFS_LOCK_RECLAIM;
                task_setup_data.callback_ops = &nfs4_recover_lock_ops;
        }
-       msg.rpc_argp = &data->arg,
-       msg.rpc_resp = &data->res,
+       msg.rpc_argp = &data->arg;
+       msg.rpc_resp = &data->res;
        task_setup_data.callback_data = data;
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
@@ -4392,48 +4471,43 @@ void nfs4_release_lockowner(const struct nfs4_lock_state *lsp)
                return;
        args->lock_owner.clientid = server->nfs_client->cl_clientid;
        args->lock_owner.id = lsp->ls_id.id;
+       args->lock_owner.s_dev = server->s_dev;
        msg.rpc_argp = args;
        rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, args);
 }
 
 #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
 
-int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf,
-               size_t buflen, int flags)
+static int nfs4_xattr_set_nfs4_acl(struct dentry *dentry, const char *key,
+                                  const void *buf, size_t buflen,
+                                  int flags, int type)
 {
-       struct inode *inode = dentry->d_inode;
-
-       if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0)
-               return -EOPNOTSUPP;
+       if (strcmp(key, "") != 0)
+               return -EINVAL;
 
-       return nfs4_proc_set_acl(inode, buf, buflen);
+       return nfs4_proc_set_acl(dentry->d_inode, buf, buflen);
 }
 
-/* The getxattr man page suggests returning -ENODATA for unknown attributes,
- * and that's what we'll do for e.g. user attributes that haven't been set.
- * But we'll follow ext2/ext3's lead by returning -EOPNOTSUPP for unsupported
- * attributes in kernel-managed attribute namespaces. */
-ssize_t nfs4_getxattr(struct dentry *dentry, const char *key, void *buf,
-               size_t buflen)
+static int nfs4_xattr_get_nfs4_acl(struct dentry *dentry, const char *key,
+                                  void *buf, size_t buflen, int type)
 {
-       struct inode *inode = dentry->d_inode;
-
-       if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0)
-               return -EOPNOTSUPP;
+       if (strcmp(key, "") != 0)
+               return -EINVAL;
 
-       return nfs4_proc_get_acl(inode, buf, buflen);
+       return nfs4_proc_get_acl(dentry->d_inode, buf, buflen);
 }
 
-ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
+static size_t nfs4_xattr_list_nfs4_acl(struct dentry *dentry, char *list,
+                                      size_t list_len, const char *name,
+                                      size_t name_len, int type)
 {
-       size_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1;
+       size_t len = sizeof(XATTR_NAME_NFSV4_ACL);
 
        if (!nfs4_server_supports_acls(NFS_SERVER(dentry->d_inode)))
                return 0;
-       if (buf && buflen < len)
-               return -ERANGE;
-       if (buf)
-               memcpy(buf, XATTR_NAME_NFSV4_ACL, len);
+
+       if (list && len <= list_len)
+               memcpy(list, XATTR_NAME_NFSV4_ACL, len);
        return len;
 }
 
@@ -4485,6 +4559,25 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
 }
 
 #ifdef CONFIG_NFS_V4_1
+/*
+ * Check the exchange flags returned by the server for invalid flags, having
+ * both PNFS and NON_PNFS flags set, and not having one of NON_PNFS, PNFS, or
+ * DS flags set.
+ */
+static int nfs4_check_cl_exchange_flags(u32 flags)
+{
+       if (flags & ~EXCHGID4_FLAG_MASK_R)
+               goto out_inval;
+       if ((flags & EXCHGID4_FLAG_USE_PNFS_MDS) &&
+           (flags & EXCHGID4_FLAG_USE_NON_PNFS))
+               goto out_inval;
+       if (!(flags & (EXCHGID4_FLAG_MASK_PNFS)))
+               goto out_inval;
+       return NFS_OK;
+out_inval:
+       return -NFS4ERR_INVAL;
+}
+
 /*
  * nfs4_proc_exchange_id()
  *
@@ -4498,7 +4591,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
        nfs4_verifier verifier;
        struct nfs41_exchange_id_args args = {
                .client = clp,
-               .flags = clp->cl_exchange_flags,
+               .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER,
        };
        struct nfs41_exchange_id_res res = {
                .client = clp,
@@ -4515,34 +4608,21 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
        dprintk("--> %s\n", __func__);
        BUG_ON(clp == NULL);
 
-       /* Remove server-only flags */
-       args.flags &= ~EXCHGID4_FLAG_CONFIRMED_R;
-
        p = (u32 *)verifier.data;
        *p++ = htonl((u32)clp->cl_boot_time.tv_sec);
        *p = htonl((u32)clp->cl_boot_time.tv_nsec);
        args.verifier = &verifier;
 
-       while (1) {
-               args.id_len = scnprintf(args.id, sizeof(args.id),
-                                       "%s/%s %u",
-                                       clp->cl_ipaddr,
-                                       rpc_peeraddr2str(clp->cl_rpcclient,
-                                                        RPC_DISPLAY_ADDR),
-                                       clp->cl_id_uniquifier);
-
-               status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
-
-               if (status != -NFS4ERR_CLID_INUSE)
-                       break;
-
-               if (signalled())
-                       break;
-
-               if (++clp->cl_id_uniquifier == 0)
-                       break;
-       }
+       args.id_len = scnprintf(args.id, sizeof(args.id),
+                               "%s/%s.%s/%u",
+                               clp->cl_ipaddr,
+                               init_utsname()->nodename,
+                               init_utsname()->domainname,
+                               clp->cl_rpcclient->cl_auth->au_flavor);
 
+       status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
+       if (!status)
+               status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags);
        dprintk("<-- %s status= %d\n", __func__, status);
        return status;
 }
@@ -4776,17 +4856,17 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
        if (!session)
                return NULL;
 
-       init_completion(&session->complete);
-
        tbl = &session->fc_slot_table;
        tbl->highest_used_slotid = -1;
        spin_lock_init(&tbl->slot_tbl_lock);
        rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table");
+       init_completion(&tbl->complete);
 
        tbl = &session->bc_slot_table;
        tbl->highest_used_slotid = -1;
        spin_lock_init(&tbl->slot_tbl_lock);
        rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");
+       init_completion(&tbl->complete);
 
        session->session_state = 1<<NFS4_SESSION_INITING;
 
@@ -5147,7 +5227,7 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cr
        if (IS_ERR(task))
                ret = PTR_ERR(task);
        else
-               rpc_put_task(task);
+               rpc_put_task_async(task);
        dprintk("<-- %s status=%d\n", __func__, ret);
        return ret;
 }
@@ -5280,13 +5360,23 @@ static void
 nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs4_layoutget *lgp = calldata;
-       struct inode *ino = lgp->args.inode;
-       struct nfs_server *server = NFS_SERVER(ino);
+       struct nfs_server *server = NFS_SERVER(lgp->args.inode);
 
        dprintk("--> %s\n", __func__);
+       /* Note the is a race here, where a CB_LAYOUTRECALL can come in
+        * right now covering the LAYOUTGET we are about to send.
+        * However, that is not so catastrophic, and there seems
+        * to be no way to prevent it completely.
+        */
        if (nfs4_setup_sequence(server, &lgp->args.seq_args,
                                &lgp->res.seq_res, 0, task))
                return;
+       if (pnfs_choose_layoutget_stateid(&lgp->args.stateid,
+                                         NFS_I(lgp->args.inode)->layout,
+                                         lgp->args.ctx->state)) {
+               rpc_exit(task, NFS4_OK);
+               return;
+       }
        rpc_call_start(task);
 }
 
@@ -5313,7 +5403,6 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
                        return;
                }
        }
-       lgp->status = task->tk_status;
        dprintk("<-- %s\n", __func__);
 }
 
@@ -5322,7 +5411,6 @@ static void nfs4_layoutget_release(void *calldata)
        struct nfs4_layoutget *lgp = calldata;
 
        dprintk("--> %s\n", __func__);
-       put_layout_hdr(lgp->args.inode);
        if (lgp->res.layout.buf != NULL)
                free_page((unsigned long) lgp->res.layout.buf);
        put_nfs_open_context(lgp->args.ctx);
@@ -5367,13 +5455,10 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
        if (IS_ERR(task))
                return PTR_ERR(task);
        status = nfs4_wait_for_completion_rpc_task(task);
-       if (status != 0)
-               goto out;
-       status = lgp->status;
-       if (status != 0)
-               goto out;
-       status = pnfs_layout_process(lgp);
-out:
+       if (status == 0)
+               status = task->tk_status;
+       if (status == 0)
+               status = pnfs_layout_process(lgp);
        rpc_put_task(task);
        dprintk("<-- %s status=%d\n", __func__, status);
        return status;
@@ -5504,9 +5589,10 @@ static const struct inode_operations nfs4_file_inode_operations = {
        .permission     = nfs_permission,
        .getattr        = nfs_getattr,
        .setattr        = nfs_setattr,
-       .getxattr       = nfs4_getxattr,
-       .setxattr       = nfs4_setxattr,
-       .listxattr      = nfs4_listxattr,
+       .getxattr       = generic_getxattr,
+       .setxattr       = generic_setxattr,
+       .listxattr      = generic_listxattr,
+       .removexattr    = generic_removexattr,
 };
 
 const struct nfs_rpc_ops nfs_v4_clientops = {
@@ -5551,6 +5637,18 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .open_context   = nfs4_atomic_open,
 };
 
+static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
+       .prefix = XATTR_NAME_NFSV4_ACL,
+       .list   = nfs4_xattr_list_nfs4_acl,
+       .get    = nfs4_xattr_get_nfs4_acl,
+       .set    = nfs4_xattr_set_nfs4_acl,
+};
+
+const struct xattr_handler *nfs4_xattr_handlers[] = {
+       &nfs4_xattr_nfs4_acl_handler,
+       NULL
+};
+
 /*
  * Local variables:
  *  c-basic-offset: 8