diff -Nurp a/fs/nfs/dir.c b/fs/nfs/dir.c --- a/fs/nfs/dir.c 2013-11-06 09:13:57.359645272 +0100 +++ b/fs/nfs/dir.c 2014-01-01 11:10:32.941284513 +0100 @@ -104,7 +104,12 @@ nfs_opendir(struct inode *inode, struct nfs_inc_stats(inode, NFSIOS_VFSOPEN); - cred = rpc_lookup_cred(); + if (NFS_PROTO(inode)->version > 3) + cred = rpc_lookup_cred(NULL); + else { + struct rpc_groups fsg = { 1, { inode->i_gid } }; + cred = rpc_lookup_cred(&fsg); + } if (IS_ERR(cred)) return PTR_ERR(cred); ctx = alloc_nfs_open_dir_context(inode, cred); @@ -1056,6 +1061,7 @@ static int nfs_lookup_revalidate(struct struct nfs_fh *fhandle = NULL; struct nfs_fattr *fattr = NULL; struct nfs4_label *label = NULL; + struct rpc_groups fsg; int error; if (flags & LOOKUP_RCU) @@ -1102,8 +1108,10 @@ static int nfs_lookup_revalidate(struct if (IS_ERR(label)) goto out_error; + fsg.ngroups = 1; + fsg.groups[0] = dir->i_gid; trace_nfs_lookup_revalidate_enter(dir, dentry, flags); - error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label); + error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label, &fsg); trace_nfs_lookup_revalidate_exit(dir, dentry, flags, error); if (error) goto out_bad; @@ -1284,6 +1292,7 @@ struct dentry *nfs_lookup(struct inode * struct nfs_fh *fhandle = NULL; struct nfs_fattr *fattr = NULL; struct nfs4_label *label = NULL; + struct rpc_groups fsg; int error; dfprintk(VFS, "NFS: lookup(%s/%s)\n", @@ -1318,7 +1327,9 @@ struct dentry *nfs_lookup(struct inode * /* Protect against concurrent sillydeletes */ trace_nfs_lookup_enter(dir, dentry, flags); nfs_block_sillyrename(parent); - error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label); + fsg.ngroups = 1; + fsg.groups[0] = dir->i_gid; + error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label, &fsg); if (error == -ENOENT) goto no_entry; if (error < 0) { @@ -1556,7 +1567,8 @@ no_open: */ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, struct nfs_fattr *fattr, - struct nfs4_label *label) + struct nfs4_label *label, + struct rpc_groups *fsg) { struct dentry *parent = dget_parent(dentry); struct inode *dir = parent->d_inode; @@ -1569,7 +1581,7 @@ int nfs_instantiate(struct dentry *dentr if (dentry->d_inode) goto out; if (fhandle->size == 0) { - error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, NULL); + error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, NULL, fsg); if (error) goto out_error; } @@ -1606,6 +1618,7 @@ int nfs_create(struct inode *dir, struct { struct iattr attr; int open_flags = excl ? O_CREAT | O_EXCL : O_CREAT; + struct rpc_groups fsg = { 1, { dir->i_gid } }; int error; dfprintk(VFS, "NFS: create(%s/%ld), %s\n", @@ -1615,7 +1628,7 @@ int nfs_create(struct inode *dir, struct attr.ia_valid = ATTR_MODE; trace_nfs_create_enter(dir, dentry, open_flags); - error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags); + error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, &fsg); trace_nfs_create_exit(dir, dentry, open_flags, error); if (error != 0) goto out_err; @@ -1634,6 +1647,7 @@ nfs_mknod(struct inode *dir, struct dent { struct iattr attr; int status; + struct rpc_groups fsg = { 1, { dir->i_gid } }; dfprintk(VFS, "NFS: mknod(%s/%ld), %s\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); @@ -1645,7 +1659,7 @@ nfs_mknod(struct inode *dir, struct dent attr.ia_valid = ATTR_MODE; trace_nfs_mknod_enter(dir, dentry); - status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev); + status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev, &fsg); trace_nfs_mknod_exit(dir, dentry, status); if (status != 0) goto out_err; @@ -1663,6 +1677,7 @@ int nfs_mkdir(struct inode *dir, struct { struct iattr attr; int error; + struct rpc_groups fsg = { 1, { dir->i_gid } }; dfprintk(VFS, "NFS: mkdir(%s/%ld), %s\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); @@ -1671,7 +1686,7 @@ int nfs_mkdir(struct inode *dir, struct attr.ia_mode = mode | S_IFDIR; trace_nfs_mkdir_enter(dir, dentry); - error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr); + error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr, &fsg); trace_nfs_mkdir_exit(dir, dentry, error); if (error != 0) goto out_err; @@ -1691,6 +1706,7 @@ static void nfs_dentry_handle_enoent(str int nfs_rmdir(struct inode *dir, struct dentry *dentry) { int error; + struct rpc_groups fsg = { 1, { dir->i_gid } }; dfprintk(VFS, "NFS: rmdir(%s/%ld), %s\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); @@ -1698,7 +1714,7 @@ int nfs_rmdir(struct inode *dir, struct trace_nfs_rmdir_enter(dir, dentry); if (dentry->d_inode) { nfs_wait_on_sillyrename(dentry); - error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); + error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name, &fsg); /* Ensure the VFS deletes this inode */ switch (error) { case 0: @@ -1708,7 +1724,7 @@ int nfs_rmdir(struct inode *dir, struct nfs_dentry_handle_enoent(dentry); } } else - error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); + error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name, &fsg); trace_nfs_rmdir_exit(dir, dentry, error); return error; @@ -1726,6 +1742,7 @@ static int nfs_safe_remove(struct dentry { struct inode *dir = dentry->d_parent->d_inode; struct inode *inode = dentry->d_inode; + struct rpc_groups fsg = { 1, { dir->i_gid } }; int error = -EBUSY; dfprintk(VFS, "NFS: safe_remove(%s/%s)\n", @@ -1740,11 +1757,11 @@ static int nfs_safe_remove(struct dentry trace_nfs_remove_enter(dir, dentry); if (inode != NULL) { NFS_PROTO(inode)->return_delegation(inode); - error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); + error = NFS_PROTO(dir)->remove(dir, &dentry->d_name, &fsg); if (error == 0) nfs_drop_nlink(inode); } else - error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); + error = NFS_PROTO(dir)->remove(dir, &dentry->d_name, &fsg); if (error == -ENOENT) nfs_dentry_handle_enoent(dentry); trace_nfs_remove_exit(dir, dentry, error); @@ -1812,6 +1829,7 @@ int nfs_symlink(struct inode *dir, struc struct iattr attr; unsigned int pathlen = strlen(symname); int error; + struct rpc_groups fsg = { 1, { dir->i_gid } }; dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name, symname); @@ -1833,7 +1851,7 @@ int nfs_symlink(struct inode *dir, struc kunmap_atomic(kaddr); trace_nfs_symlink_enter(dir, dentry); - error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr); + error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr, &fsg); trace_nfs_symlink_exit(dir, dentry, error); if (error != 0) { dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n", @@ -1863,6 +1881,7 @@ int nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { struct inode *inode = old_dentry->d_inode; + struct rpc_groups fsg = { 1, { dir->i_gid } }; int error; dfprintk(VFS, "NFS: link(%s/%s -> %s/%s)\n", @@ -1873,7 +1892,7 @@ nfs_link(struct dentry *old_dentry, stru NFS_PROTO(inode)->return_delegation(inode); d_drop(dentry); - error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name); + error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name, &fsg); if (error == 0) { ihold(inode); d_add(dentry, inode); @@ -1913,6 +1932,14 @@ int nfs_rename(struct inode *old_dir, st struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct dentry *dentry = NULL, *rehash = NULL; + struct rpc_groups fsg = { + .ngroups = 3, + .groups = { + old_dir->i_gid, + new_dir->i_gid, /* old_dir != new_dir */ + old_inode->i_gid /* reparent a dir */ + } + }; int error = -EBUSY; dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", @@ -1962,7 +1989,7 @@ int nfs_rename(struct inode *old_dir, st NFS_PROTO(new_inode)->return_delegation(new_inode); error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, - new_dir, &new_dentry->d_name); + new_dir, &new_dentry->d_name, &fsg); nfs_mark_for_revalidate(old_inode); out: if (rehash) @@ -2237,6 +2264,8 @@ static int nfs_do_access(struct inode *i cache.cred = cred; cache.jiffies = jiffies; status = NFS_PROTO(inode)->access(inode, &cache); + dfprintk(VFS, "NFS: access()=%d for ino %lu, cred %p, mask 0x%x->0x%x\n", + status, inode->i_ino, cred, mask, cache.mask); if (status != 0) { if (status == -ESTALE) { nfs_zap_caches(inode); @@ -2311,7 +2340,12 @@ force_lookup: if (!NFS_PROTO(inode)->access) goto out_notsup; - cred = rpc_lookup_cred(); + if (NFS_PROTO(inode)->version > 3) + cred = rpc_lookup_cred(NULL); + else { + struct rpc_groups fsg = { 1, { inode->i_gid } }; + cred = rpc_lookup_cred(&fsg); + } if (!IS_ERR(cred)) { res = nfs_do_access(inode, cred, mask); put_rpccred(cred); diff -Nurp a/fs/nfs/inode.c b/fs/nfs/inode.c --- a/fs/nfs/inode.c 2013-11-06 09:13:57.420646249 +0100 +++ b/fs/nfs/inode.c 2014-01-01 10:58:13.414971724 +0100 @@ -486,6 +486,7 @@ nfs_setattr(struct dentry *dentry, struc { struct inode *inode = dentry->d_inode; struct nfs_fattr *fattr; + struct rpc_groups fsg; int error = -ENOMEM; nfs_inc_stats(inode, NFSIOS_VFSSETATTR); @@ -520,7 +521,11 @@ nfs_setattr(struct dentry *dentry, struc */ if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) NFS_PROTO(inode)->return_delegation(inode); - error = NFS_PROTO(inode)->setattr(dentry, fattr, attr); + fsg.ngroups = 0; + fsg.groups[fsg.ngroups++] = inode->i_gid; /* ATTR_SIZE */ + if (attr->ia_valid & ATTR_GID) + fsg.groups[fsg.ngroups++] = attr->ia_gid; + error = NFS_PROTO(inode)->setattr(dentry, fattr, attr, &fsg); if (error == 0) error = nfs_refresh_inode(inode, fattr); nfs_free_fattr(fattr); @@ -723,7 +728,14 @@ EXPORT_SYMBOL_GPL(nfs_close_context); struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, fmode_t f_mode) { struct nfs_open_context *ctx; - struct rpc_cred *cred = rpc_lookup_cred(); + struct rpc_cred *cred; + + if (NFS_SB(dentry->d_sb)->nfs_client->rpc_ops->version > 3) + cred = rpc_lookup_cred(NULL); + else { + struct rpc_groups fsg = { 1, { dentry->d_inode->i_gid } }; + cred = rpc_lookup_cred(&fsg); + } if (IS_ERR(cred)) return ERR_CAST(cred); diff -Nurp a/fs/nfs/namespace.c b/fs/nfs/namespace.c --- a/fs/nfs/namespace.c 2013-09-07 16:11:44.709478475 +0200 +++ b/fs/nfs/namespace.c 2014-01-01 10:58:13.434972029 +0100 @@ -278,9 +278,17 @@ struct vfsmount *nfs_submount(struct nfs { int err; struct dentry *parent = dget_parent(dentry); + struct rpc_groups fsg, *pfsg; + if (NFS_PROTO(parent->d_inode)->version > 3) { + pfsg = NULL; + } else { + pfsg = &fsg; + pfsg->ngroups = 1; + pfsg->groups[0] = parent->d_inode->i_gid; + } /* Look it up again to get its attributes */ - err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &dentry->d_name, fh, fattr, NULL); + err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &dentry->d_name, fh, fattr, NULL, pfsg); dput(parent); if (err != 0) return ERR_PTR(err); diff -Nurp a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c --- a/fs/nfs/nfs3proc.c 2013-11-06 09:13:57.463646945 +0100 +++ b/fs/nfs/nfs3proc.c 2014-01-01 10:58:13.436972061 +0100 @@ -26,11 +26,19 @@ /* A wrapper to handle the EJUKEBOX error messages */ static int -nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) +nfs3_rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, + struct rpc_cred *cred, int flags) { + struct rpc_message msg = { + .rpc_proc = &nfs3_procedures[proc], + .rpc_argp = argp, + .rpc_resp = resp, + .rpc_cred = cred, + }; int res; + do { - res = rpc_call_sync(clnt, msg, flags); + res = rpc_call_sync(clnt, &msg, flags); if (res != -EJUKEBOX) break; freezable_schedule_timeout_killable_unsafe(NFS_JUKEBOX_RETRY_TIME); @@ -39,7 +47,20 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, return res; } -#define rpc_call_sync(clnt, msg, flags) nfs3_rpc_wrapper(clnt, msg, flags) +static int +nfs3_rpc(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, + struct rpc_groups *fsg) +{ + struct rpc_cred *cred; + int res; + + cred = rpcauth_lookupcred(clnt->cl_auth, fsg, 0); + if (IS_ERR(cred)) + return PTR_ERR(cred); + res = nfs3_rpc_call(clnt, proc, argp, resp, cred, 0); + put_rpccred(cred); + return res; +} static int nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode) @@ -58,21 +79,14 @@ static int do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle, struct nfs_fsinfo *info) { - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_FSINFO], - .rpc_argp = fhandle, - .rpc_resp = info, - }; int status; dprintk("%s: call fsinfo\n", __func__); nfs_fattr_init(info->fattr); - status = rpc_call_sync(client, &msg, 0); + status = nfs3_rpc(client, NFS3PROC_FSINFO, fhandle, info, NULL); dprintk("%s: reply fsinfo: %d\n", __func__, status); if (status == 0 && !(info->fattr->valid & NFS_ATTR_FATTR)) { - msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; - msg.rpc_resp = info->fattr; - status = rpc_call_sync(client, &msg, 0); + status = nfs3_rpc(client, NFS3PROC_GETATTR, fhandle, info->fattr, NULL); dprintk("%s: reply getattr: %d\n", __func__, status); } return status; @@ -100,41 +114,41 @@ static int nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label) { - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR], - .rpc_argp = fhandle, - .rpc_resp = fattr, - }; int status; dprintk("NFS call getattr\n"); nfs_fattr_init(fattr); - status = rpc_call_sync(server->client, &msg, 0); + status = nfs3_rpc(server->client, NFS3PROC_GETATTR, fhandle, fattr, NULL); dprintk("NFS reply getattr: %d\n", status); return status; } static int nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, - struct iattr *sattr) + struct iattr *sattr, struct rpc_groups *fsg) { struct inode *inode = dentry->d_inode; struct nfs3_sattrargs arg = { .fh = NFS_FH(inode), .sattr = sattr, }; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_SETATTR], - .rpc_argp = &arg, - .rpc_resp = fattr, - }; int status; + struct rpc_cred *cred; + struct rpc_clnt *clnt = NFS_CLIENT(inode); dprintk("NFS call setattr\n"); - if (sattr->ia_valid & ATTR_FILE) - msg.rpc_cred = nfs_file_cred(sattr->ia_file); + if (sattr->ia_valid & ATTR_FILE) { + cred = nfs_file_cred(sattr->ia_file); + get_rpccred(cred); + } else { + /* truncate() requires write access */ + cred = rpcauth_lookupcred(clnt->cl_auth, fsg, 0); + if (IS_ERR(cred)) + return PTR_ERR(cred); + } nfs_fattr_init(fattr); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); + status = nfs3_rpc_call(clnt, NFS3PROC_SETATTR, &arg, fattr, cred, 0); + put_rpccred(cred); if (status == 0) nfs_setattr_update_inode(inode, sattr); dprintk("NFS reply setattr: %d\n", status); @@ -144,7 +158,7 @@ nfs3_proc_setattr(struct dentry *dentry, static int nfs3_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr, - struct nfs4_label *label) + struct nfs4_label *label, struct rpc_groups *fsg) { struct nfs3_diropargs arg = { .fh = NFS_FH(dir), @@ -155,11 +169,6 @@ nfs3_proc_lookup(struct inode *dir, stru .fh = fhandle, .fattr = fattr }; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_LOOKUP], - .rpc_argp = &arg, - .rpc_resp = &res, - }; int status; dprintk("NFS call lookup %s\n", name->name); @@ -168,13 +177,11 @@ nfs3_proc_lookup(struct inode *dir, stru return -ENOMEM; nfs_fattr_init(fattr); - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs3_rpc(NFS_CLIENT(dir), NFS3PROC_LOOKUP, &arg, &res, fsg); nfs_refresh_inode(dir, res.dir_attr); if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) { - msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; - msg.rpc_argp = fhandle; - msg.rpc_resp = fattr; - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs3_rpc(NFS_CLIENT(dir), NFS3PROC_GETATTR, + fhandle, fattr, NULL); } nfs_free_fattr(res.dir_attr); dprintk("NFS reply lookup: %d\n", status); @@ -187,12 +194,6 @@ static int nfs3_proc_access(struct inode .fh = NFS_FH(inode), }; struct nfs3_accessres res; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_ACCESS], - .rpc_argp = &arg, - .rpc_resp = &res, - .rpc_cred = entry->cred, - }; int mode = entry->mask; int status = -ENOMEM; @@ -216,7 +217,8 @@ static int nfs3_proc_access(struct inode if (res.fattr == NULL) goto out; - status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); + status = nfs3_rpc_call(NFS_CLIENT(inode), NFS3PROC_ACCESS, + &arg, &res, entry->cred, 0); nfs_refresh_inode(inode, res.fattr); if (status == 0) { entry->mask = 0; @@ -243,19 +245,14 @@ static int nfs3_proc_readlink(struct ino .pglen = pglen, .pages = &page }; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_READLINK], - .rpc_argp = &args, - }; int status = -ENOMEM; dprintk("NFS call readlink\n"); fattr = nfs_alloc_fattr(); if (fattr == NULL) goto out; - msg.rpc_resp = fattr; - status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); + status = nfs3_rpc(NFS_CLIENT(inode), NFS3PROC_READLINK, &args, fattr, NULL); nfs_refresh_inode(inode, fattr); nfs_free_fattr(fattr); out: @@ -264,7 +261,8 @@ out: } struct nfs3_createdata { - struct rpc_message msg; + u32 proc; + struct rpc_groups *fsg; union { struct nfs3_createargs create; struct nfs3_mkdirargs mkdir; @@ -283,8 +281,6 @@ static struct nfs3_createdata *nfs3_allo data = kzalloc(sizeof(*data), GFP_KERNEL); if (data != NULL) { - data->msg.rpc_argp = &data->arg; - data->msg.rpc_resp = &data->res; data->res.fh = &data->fh; data->res.fattr = &data->fattr; data->res.dir_attr = &data->dir_attr; @@ -298,10 +294,10 @@ static int nfs3_do_create(struct inode * { int status; - status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0); + status = nfs3_rpc(NFS_CLIENT(dir), data->proc, &data->arg, &data->res, data->fsg); nfs_post_op_update_inode(dir, data->res.dir_attr); if (status == 0) - status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL); + status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL, data->fsg); return status; } @@ -315,7 +311,7 @@ static void nfs3_free_createdata(struct */ static int nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, - int flags) + int flags, struct rpc_groups *fsg) { struct nfs3_createdata *data; umode_t mode = sattr->ia_mode; @@ -327,7 +323,8 @@ nfs3_proc_create(struct inode *dir, stru if (data == NULL) goto out; - data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_CREATE]; + data->proc = NFS3PROC_CREATE; + data->fsg = fsg; data->arg.create.fh = NFS_FH(dir); data->arg.create.name = dentry->d_name.name; data->arg.create.len = dentry->d_name.len; @@ -381,7 +378,7 @@ nfs3_proc_create(struct inode *dir, stru /* Note: we could use a guarded setattr here, but I'm * not sure this buys us anything (and I'd have * to revamp the NFSv3 XDR code) */ - status = nfs3_proc_setattr(dentry, data->res.fattr, sattr); + status = nfs3_proc_setattr(dentry, data->res.fattr, sattr, NULL); nfs_post_op_update_inode(dentry->d_inode, data->res.fattr); dprintk("NFS reply setattr (post-create): %d\n", status); if (status != 0) @@ -395,18 +392,13 @@ out: } static int -nfs3_proc_remove(struct inode *dir, struct qstr *name) +nfs3_proc_remove(struct inode *dir, struct qstr *name, struct rpc_groups *fsg) { struct nfs_removeargs arg = { .fh = NFS_FH(dir), .name = *name, }; struct nfs_removeres res; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE], - .rpc_argp = &arg, - .rpc_resp = &res, - }; int status = -ENOMEM; dprintk("NFS call remove %s\n", name->name); @@ -414,7 +406,7 @@ nfs3_proc_remove(struct inode *dir, stru if (res.dir_attr == NULL) goto out; - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs3_rpc(NFS_CLIENT(dir), NFS3PROC_REMOVE, &arg, &res, fsg); nfs_post_op_update_inode(dir, res.dir_attr); nfs_free_fattr(res.dir_attr); out: @@ -472,7 +464,8 @@ nfs3_proc_rename_done(struct rpc_task *t static int nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, - struct inode *new_dir, struct qstr *new_name) + struct inode *new_dir, struct qstr *new_name, + struct rpc_groups *fsg) { struct nfs_renameargs arg = { .old_dir = NFS_FH(old_dir), @@ -481,11 +474,6 @@ nfs3_proc_rename(struct inode *old_dir, .new_name = new_name, }; struct nfs_renameres res; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_RENAME], - .rpc_argp = &arg, - .rpc_resp = &res, - }; int status = -ENOMEM; dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); @@ -495,7 +483,7 @@ nfs3_proc_rename(struct inode *old_dir, if (res.old_fattr == NULL || res.new_fattr == NULL) goto out; - status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); + status = nfs3_rpc(NFS_CLIENT(old_dir), NFS3PROC_RENAME, &arg, &res, fsg); nfs_post_op_update_inode(old_dir, res.old_fattr); nfs_post_op_update_inode(new_dir, res.new_fattr); out: @@ -506,7 +494,8 @@ out: } static int -nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) +nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name, + struct rpc_groups *fsg) { struct nfs3_linkargs arg = { .fromfh = NFS_FH(inode), @@ -515,11 +504,6 @@ nfs3_proc_link(struct inode *inode, stru .tolen = name->len }; struct nfs3_linkres res; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_LINK], - .rpc_argp = &arg, - .rpc_resp = &res, - }; int status = -ENOMEM; dprintk("NFS call link %s\n", name->name); @@ -528,7 +512,7 @@ nfs3_proc_link(struct inode *inode, stru if (res.fattr == NULL || res.dir_attr == NULL) goto out; - status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); + status = nfs3_rpc(NFS_CLIENT(inode), NFS3PROC_LINK, &arg, &res, fsg); nfs_post_op_update_inode(dir, res.dir_attr); nfs_post_op_update_inode(inode, res.fattr); out: @@ -540,7 +524,7 @@ out: static int nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, - unsigned int len, struct iattr *sattr) + unsigned int len, struct iattr *sattr, struct rpc_groups *fsg) { struct nfs3_createdata *data; int status = -ENOMEM; @@ -553,7 +537,8 @@ nfs3_proc_symlink(struct inode *dir, str data = nfs3_alloc_createdata(); if (data == NULL) goto out; - data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK]; + data->proc = NFS3PROC_SYMLINK; + data->fsg = fsg; data->arg.symlink.fromfh = NFS_FH(dir); data->arg.symlink.fromname = dentry->d_name.name; data->arg.symlink.fromlen = dentry->d_name.len; @@ -570,7 +555,8 @@ out: } static int -nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) +nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr, + struct rpc_groups *fsg) { struct nfs3_createdata *data; umode_t mode = sattr->ia_mode; @@ -584,7 +570,8 @@ nfs3_proc_mkdir(struct inode *dir, struc if (data == NULL) goto out; - data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR]; + data->proc = NFS3PROC_MKDIR; + data->fsg = fsg; data->arg.mkdir.fh = NFS_FH(dir); data->arg.mkdir.name = dentry->d_name.name; data->arg.mkdir.len = dentry->d_name.len; @@ -602,7 +589,7 @@ out: } static int -nfs3_proc_rmdir(struct inode *dir, struct qstr *name) +nfs3_proc_rmdir(struct inode *dir, struct qstr *name, struct rpc_groups *fsg) { struct nfs_fattr *dir_attr; struct nfs3_diropargs arg = { @@ -610,10 +597,6 @@ nfs3_proc_rmdir(struct inode *dir, struc .name = name->name, .len = name->len }; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_RMDIR], - .rpc_argp = &arg, - }; int status = -ENOMEM; dprintk("NFS call rmdir %s\n", name->name); @@ -621,8 +604,7 @@ nfs3_proc_rmdir(struct inode *dir, struc if (dir_attr == NULL) goto out; - msg.rpc_resp = dir_attr; - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs3_rpc(NFS_CLIENT(dir), NFS3PROC_RMDIR, &arg, dir_attr, fsg); nfs_post_op_update_inode(dir, dir_attr); nfs_free_fattr(dir_attr); out: @@ -657,16 +639,11 @@ nfs3_proc_readdir(struct dentry *dentry, .verf = verf, .plus = plus }; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_READDIR], - .rpc_argp = &arg, - .rpc_resp = &res, - .rpc_cred = cred - }; int status = -ENOMEM; + u32 proc = NFS3PROC_READDIR; if (plus) - msg.rpc_proc = &nfs3_procedures[NFS3PROC_READDIRPLUS]; + proc = NFS3PROC_READDIRPLUS; dprintk("NFS call readdir%s %d\n", plus? "plus" : "", (unsigned int) cookie); @@ -675,7 +652,7 @@ nfs3_proc_readdir(struct dentry *dentry, if (res.dir_attr == NULL) goto out; - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs3_rpc_call(NFS_CLIENT(dir), proc, &arg, &res, cred, 0); nfs_invalidate_atime(dir); nfs_refresh_inode(dir, res.dir_attr); @@ -689,7 +666,7 @@ out: static int nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, - dev_t rdev) + dev_t rdev, struct rpc_groups *fsg) { struct nfs3_createdata *data; umode_t mode = sattr->ia_mode; @@ -704,7 +681,8 @@ nfs3_proc_mknod(struct inode *dir, struc if (data == NULL) goto out; - data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD]; + data->proc = NFS3PROC_MKNOD; + data->fsg = fsg; data->arg.mknod.fh = NFS_FH(dir); data->arg.mknod.name = dentry->d_name.name; data->arg.mknod.len = dentry->d_name.len; @@ -743,16 +721,11 @@ static int nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *stat) { - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_FSSTAT], - .rpc_argp = fhandle, - .rpc_resp = stat, - }; int status; dprintk("NFS call fsstat\n"); nfs_fattr_init(stat->fattr); - status = rpc_call_sync(server->client, &msg, 0); + status = nfs3_rpc(server->client, NFS3PROC_FSSTAT, fhandle, stat, NULL); dprintk("NFS reply fsstat: %d\n", status); return status; } @@ -761,16 +734,11 @@ static int do_proc_fsinfo(struct rpc_clnt *client, struct nfs_fh *fhandle, struct nfs_fsinfo *info) { - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_FSINFO], - .rpc_argp = fhandle, - .rpc_resp = info, - }; int status; dprintk("NFS call fsinfo\n"); nfs_fattr_init(info->fattr); - status = rpc_call_sync(client, &msg, 0); + status = nfs3_rpc(client, NFS3PROC_FSINFO, fhandle, info, NULL); dprintk("NFS reply fsinfo: %d\n", status); return status; } @@ -795,16 +763,11 @@ static int nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_pathconf *info) { - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_PATHCONF], - .rpc_argp = fhandle, - .rpc_resp = info, - }; int status; dprintk("NFS call pathconf\n"); nfs_fattr_init(info->fattr); - status = rpc_call_sync(server->client, &msg, 0); + status = nfs3_rpc(server->client, NFS3PROC_PATHCONF, fhandle, info, NULL); dprintk("NFS reply pathconf: %d\n", status); return status; } diff -Nurp a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c --- a/fs/nfs/nfs4proc.c 2014-01-01 10:47:26.908081878 +0100 +++ b/fs/nfs/nfs4proc.c 2014-01-01 11:19:38.263626527 +0100 @@ -3053,7 +3053,7 @@ static int nfs4_proc_getattr(struct nfs_ */ static int nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, - struct iattr *sattr) + struct iattr *sattr, struct rpc_groups *fsg) { struct inode *inode = dentry->d_inode; struct rpc_cred *cred = NULL; @@ -3100,7 +3100,8 @@ nfs4_proc_setattr(struct dentry *dentry, static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, - struct nfs_fattr *fattr, struct nfs4_label *label) + struct nfs_fattr *fattr, struct nfs4_label *label, + struct rpc_groups *fsg) { struct nfs_server *server = NFS_SERVER(dir); int status; @@ -3147,7 +3148,7 @@ static int nfs4_proc_lookup_common(struc struct rpc_clnt *client = *clnt; int err; do { - err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr, label); + err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr, label, NULL); trace_nfs4_lookup(dir, name, err); switch (err) { case -NFS4ERR_BADNAME: @@ -3185,7 +3186,7 @@ out: static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr, - struct nfs4_label *label) + struct nfs4_label *label, struct rpc_groups *fsg) { int status; struct rpc_clnt *client = NFS_CLIENT(dir); @@ -3333,7 +3334,7 @@ static int nfs4_proc_readlink(struct ino */ static int nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, - int flags) + int flags, struct rpc_groups *fsg) { struct nfs4_label l, *ilabel = NULL; struct nfs_open_context *ctx; @@ -3382,7 +3383,8 @@ static int _nfs4_proc_remove(struct inod return status; } -static int nfs4_proc_remove(struct inode *dir, struct qstr *name) +static int nfs4_proc_remove(struct inode *dir, struct qstr *name, + struct rpc_groups *fsg) { struct nfs4_exception exception = { }; int err; @@ -3493,7 +3495,8 @@ static int _nfs4_proc_rename(struct inod } static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, - struct inode *new_dir, struct qstr *new_name) + struct inode *new_dir, struct qstr *new_name, + struct rpc_groups *fsg) { struct nfs4_exception exception = { }; int err; @@ -3554,7 +3557,8 @@ out: return status; } -static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) +static int nfs4_proc_link(struct inode *inode, struct inode *dir, + struct qstr *name, struct rpc_groups *fsg) { struct nfs4_exception exception = { }; int err; @@ -3615,7 +3619,7 @@ static int nfs4_do_create(struct inode * &data->arg.seq_args, &data->res.seq_res, 1); if (status == 0) { update_changeattr(dir, &data->res.dir_cinfo); - status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label); + status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label, NULL); } return status; } @@ -3654,7 +3658,8 @@ out: } static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, - struct page *page, unsigned int len, struct iattr *sattr) + struct page *page, unsigned int len, struct iattr *sattr, + struct rpc_groups *fsg) { struct nfs4_exception exception = { }; struct nfs4_label l, *label = NULL; @@ -3692,7 +3697,7 @@ out: } static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, - struct iattr *sattr) + struct iattr *sattr, struct rpc_groups *fsg) { struct nfs4_exception exception = { }; struct nfs4_label l, *label = NULL; @@ -3802,7 +3807,7 @@ out: } static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, - struct iattr *sattr, dev_t rdev) + struct iattr *sattr, dev_t rdev, struct rpc_groups *fsg) { struct nfs4_exception exception = { }; struct nfs4_label l, *label = NULL; @@ -4690,7 +4695,7 @@ nfs4_set_security_label(struct dentry *d ilabel.label = (char *)buf; ilabel.len = buflen; - cred = rpc_lookup_cred(); + cred = rpc_lookup_cred(NULL); if (IS_ERR(cred)) return PTR_ERR(cred); diff -Nurp a/fs/nfs/proc.c b/fs/nfs/proc.c --- a/fs/nfs/proc.c 2013-11-06 09:13:57.676650362 +0100 +++ b/fs/nfs/proc.c 2014-01-01 10:58:13.480972733 +0100 @@ -6,7 +6,7 @@ * OS-independent nfs remote procedure call functions * * Tuned by Alan Cox for >3K buffers - * so at last we can have decent(ish) throughput off a + * so at last we can have decent(ish) throughput off a * Sun server. * * Coding optimized and cleaned up by Florian La Roche. @@ -46,6 +46,37 @@ #define NFSDBG_FACILITY NFSDBG_PROC +static __inline__ int +nfs2_rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, + struct rpc_cred *cred, int flags) +{ + struct rpc_message msg = { + .rpc_proc = &nfs_procedures[proc], + .rpc_argp = argp, + .rpc_resp = resp, + .rpc_cred = cred, + }; + int res; + + res = rpc_call_sync(clnt, &msg, flags); + return res; +} + +static int +nfs2_rpc(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, + struct rpc_groups *fsg) +{ + struct rpc_cred *cred; + int res; + + cred = rpcauth_lookupcred(clnt->cl_auth, fsg, 0); + if (IS_ERR(cred)) + return PTR_ERR(cred); + res = nfs2_rpc_call(clnt, proc, argp, resp, cred, 0); + put_rpccred(cred); + return res; +} + /* * Bare-bones access to getattr: this is for nfs_read_super. */ @@ -55,29 +86,22 @@ nfs_proc_get_root(struct nfs_server *ser { struct nfs_fattr *fattr = info->fattr; struct nfs2_fsstat fsinfo; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_GETATTR], - .rpc_argp = fhandle, - .rpc_resp = fattr, - }; int status; dprintk("%s: call getattr\n", __func__); nfs_fattr_init(fattr); - status = rpc_call_sync(server->client, &msg, 0); + status = nfs2_rpc(server->client, NFSPROC_GETATTR, fhandle, fattr, NULL); /* Retry with default authentication if different */ if (status && server->nfs_client->cl_rpcclient != server->client) - status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0); + status = nfs2_rpc(server->nfs_client->cl_rpcclient, NFSPROC_GETATTR, fhandle, fattr, NULL); dprintk("%s: reply getattr: %d\n", __func__, status); if (status) return status; dprintk("%s: call statfs\n", __func__); - msg.rpc_proc = &nfs_procedures[NFSPROC_STATFS]; - msg.rpc_resp = &fsinfo; - status = rpc_call_sync(server->client, &msg, 0); + status = nfs2_rpc(server->client, NFSPROC_STATFS, fhandle, &fsinfo, NULL); /* Retry with default authentication if different */ if (status && server->nfs_client->cl_rpcclient != server->client) - status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0); + status = nfs2_rpc(server->nfs_client->cl_rpcclient, NFSPROC_STATFS, fhandle, &fsinfo, NULL); dprintk("%s: reply statfs: %d\n", __func__, status); if (status) return status; @@ -100,44 +124,44 @@ static int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label) { - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_GETATTR], - .rpc_argp = fhandle, - .rpc_resp = fattr, - }; int status; dprintk("NFS call getattr\n"); nfs_fattr_init(fattr); - status = rpc_call_sync(server->client, &msg, 0); + status = nfs2_rpc(server->client, NFSPROC_GETATTR, fhandle, fattr, NULL); dprintk("NFS reply getattr: %d\n", status); return status; } static int nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, - struct iattr *sattr) + struct iattr *sattr, struct rpc_groups *fsg) { struct inode *inode = dentry->d_inode; - struct nfs_sattrargs arg = { + struct nfs_sattrargs arg = { .fh = NFS_FH(inode), .sattr = sattr }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_SETATTR], - .rpc_argp = &arg, - .rpc_resp = fattr, - }; int status; + struct rpc_cred *cred; + struct rpc_clnt *clnt = NFS_CLIENT(inode); /* Mask out the non-modebit related stuff from attr->ia_mode */ sattr->ia_mode &= S_IALLUGO; dprintk("NFS call setattr\n"); - if (sattr->ia_valid & ATTR_FILE) - msg.rpc_cred = nfs_file_cred(sattr->ia_file); + if (sattr->ia_valid & ATTR_FILE) { + cred = nfs_file_cred(sattr->ia_file); + get_rpccred(cred); + } else { + /* truncate() requires write access */ + cred = rpcauth_lookupcred(clnt->cl_auth, fsg, 0); + if (IS_ERR(cred)) + return PTR_ERR(cred); + } nfs_fattr_init(fattr); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); + status = nfs2_rpc_call(clnt, NFSPROC_SETATTR, &arg, fattr, cred, 0); + put_rpccred(cred); if (status == 0) nfs_setattr_update_inode(inode, sattr); dprintk("NFS reply setattr: %d\n", status); @@ -147,7 +171,7 @@ nfs_proc_setattr(struct dentry *dentry, static int nfs_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr, - struct nfs4_label *label) + struct nfs4_label *label, struct rpc_groups *fsg) { struct nfs_diropargs arg = { .fh = NFS_FH(dir), @@ -158,16 +182,11 @@ nfs_proc_lookup(struct inode *dir, struc .fh = fhandle, .fattr = fattr }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_LOOKUP], - .rpc_argp = &arg, - .rpc_resp = &res, - }; int status; dprintk("NFS call lookup %s\n", name->name); nfs_fattr_init(fattr); - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_LOOKUP, &arg, &res, fsg); dprintk("NFS reply lookup: %d\n", status); return status; } @@ -181,14 +200,10 @@ static int nfs_proc_readlink(struct inod .pglen = pglen, .pages = &page }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_READLINK], - .rpc_argp = &args, - }; int status; dprintk("NFS call readlink\n"); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(inode), NFSPROC_READLINK, &args, NULL, NULL); dprintk("NFS reply readlink: %d\n", status); return status; } @@ -227,24 +242,19 @@ static void nfs_free_createdata(const st static int nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, - int flags) + int flags, struct rpc_groups *fsg) { struct nfs_createdata *data; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_CREATE], - }; int status = -ENOMEM; dprintk("NFS call create %s\n", dentry->d_name.name); data = nfs_alloc_createdata(dir, dentry, sattr); if (data == NULL) goto out; - msg.rpc_argp = &data->arg; - msg.rpc_resp = &data->res; - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_CREATE, &data->arg, &data->res, fsg); nfs_mark_for_revalidate(dir); if (status == 0) - status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL); + status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL, fsg); nfs_free_createdata(data); out: dprintk("NFS reply create: %d\n", status); @@ -256,12 +266,9 @@ out: */ static int nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, - dev_t rdev) + dev_t rdev, struct rpc_groups *fsg) { struct nfs_createdata *data; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_CREATE], - }; umode_t mode; int status = -ENOMEM; @@ -279,19 +286,17 @@ nfs_proc_mknod(struct inode *dir, struct data = nfs_alloc_createdata(dir, dentry, sattr); if (data == NULL) goto out; - msg.rpc_argp = &data->arg; - msg.rpc_resp = &data->res; - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_CREATE, &data->arg, &data->res, fsg); nfs_mark_for_revalidate(dir); if (status == -EINVAL && S_ISFIFO(mode)) { sattr->ia_mode = mode; nfs_fattr_init(data->res.fattr); - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_CREATE, &data->arg, &data->res, fsg); } if (status == 0) - status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL); + status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL, fsg); nfs_free_createdata(data); out: dprintk("NFS reply mknod: %d\n", status); @@ -299,20 +304,16 @@ out: } static int -nfs_proc_remove(struct inode *dir, struct qstr *name) +nfs_proc_remove(struct inode *dir, struct qstr *name, struct rpc_groups *fsg) { struct nfs_removeargs arg = { .fh = NFS_FH(dir), .name = *name, }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_REMOVE], - .rpc_argp = &arg, - }; int status; dprintk("NFS call remove %s\n", name->name); - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_REMOVE, &arg, NULL, fsg); nfs_mark_for_revalidate(dir); dprintk("NFS reply remove: %d\n", status); @@ -358,7 +359,8 @@ nfs_proc_rename_done(struct rpc_task *ta static int nfs_proc_rename(struct inode *old_dir, struct qstr *old_name, - struct inode *new_dir, struct qstr *new_name) + struct inode *new_dir, struct qstr *new_name, + struct rpc_groups *fsg) { struct nfs_renameargs arg = { .old_dir = NFS_FH(old_dir), @@ -366,14 +368,10 @@ nfs_proc_rename(struct inode *old_dir, s .new_dir = NFS_FH(new_dir), .new_name = new_name, }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_RENAME], - .rpc_argp = &arg, - }; int status; dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); - status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(old_dir), NFSPROC_RENAME, &arg, NULL, fsg); nfs_mark_for_revalidate(old_dir); nfs_mark_for_revalidate(new_dir); dprintk("NFS reply rename: %d\n", status); @@ -381,7 +379,8 @@ nfs_proc_rename(struct inode *old_dir, s } static int -nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) +nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name, + struct rpc_groups *fsg) { struct nfs_linkargs arg = { .fromfh = NFS_FH(inode), @@ -389,14 +388,10 @@ nfs_proc_link(struct inode *inode, struc .toname = name->name, .tolen = name->len }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_LINK], - .rpc_argp = &arg, - }; int status; dprintk("NFS call link %s\n", name->name); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(inode), NFSPROC_LINK, &arg, NULL, fsg); nfs_mark_for_revalidate(inode); nfs_mark_for_revalidate(dir); dprintk("NFS reply link: %d\n", status); @@ -405,7 +400,7 @@ nfs_proc_link(struct inode *inode, struc static int nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, - unsigned int len, struct iattr *sattr) + unsigned int len, struct iattr *sattr, struct rpc_groups *fsg) { struct nfs_fh *fh; struct nfs_fattr *fattr; @@ -417,10 +412,6 @@ nfs_proc_symlink(struct inode *dir, stru .pathlen = len, .sattr = sattr }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_SYMLINK], - .rpc_argp = &arg, - }; int status = -ENAMETOOLONG; dprintk("NFS call symlink %s\n", dentry->d_name.name); @@ -434,7 +425,7 @@ nfs_proc_symlink(struct inode *dir, stru if (fh == NULL || fattr == NULL) goto out_free; - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, fsg); nfs_mark_for_revalidate(dir); /* @@ -443,7 +434,7 @@ nfs_proc_symlink(struct inode *dir, stru * should fill in the data with a LOOKUP call on the wire. */ if (status == 0) - status = nfs_instantiate(dentry, fh, fattr, NULL); + status = nfs_instantiate(dentry, fh, fattr, NULL, fsg); out_free: nfs_free_fattr(fattr); @@ -454,25 +445,21 @@ out: } static int -nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) +nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr, + struct rpc_groups *fsg) { struct nfs_createdata *data; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_MKDIR], - }; int status = -ENOMEM; dprintk("NFS call mkdir %s\n", dentry->d_name.name); data = nfs_alloc_createdata(dir, dentry, sattr); if (data == NULL) goto out; - msg.rpc_argp = &data->arg; - msg.rpc_resp = &data->res; - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_MKDIR, &data->arg, &data->res, fsg); nfs_mark_for_revalidate(dir); if (status == 0) - status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL); + status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL, fsg); nfs_free_createdata(data); out: dprintk("NFS reply mkdir: %d\n", status); @@ -480,21 +467,17 @@ out: } static int -nfs_proc_rmdir(struct inode *dir, struct qstr *name) +nfs_proc_rmdir(struct inode *dir, struct qstr *name, struct rpc_groups *fsg) { struct nfs_diropargs arg = { .fh = NFS_FH(dir), .name = name->name, .len = name->len }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_RMDIR], - .rpc_argp = &arg, - }; int status; dprintk("NFS call rmdir %s\n", name->name); - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_RMDIR, &arg, NULL, fsg); nfs_mark_for_revalidate(dir); dprintk("NFS reply rmdir: %d\n", status); return status; @@ -518,15 +501,10 @@ nfs_proc_readdir(struct dentry *dentry, .count = count, .pages = pages, }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_READDIR], - .rpc_argp = &arg, - .rpc_cred = cred, - }; int status; dprintk("NFS call readdir %d\n", (unsigned int)cookie); - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs2_rpc_call(NFS_CLIENT(dir), NFSPROC_READDIR, &arg, NULL, cred, 0); nfs_invalidate_atime(dir); @@ -539,16 +517,11 @@ nfs_proc_statfs(struct nfs_server *serve struct nfs_fsstat *stat) { struct nfs2_fsstat fsinfo; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_STATFS], - .rpc_argp = fhandle, - .rpc_resp = &fsinfo, - }; int status; dprintk("NFS call statfs\n"); nfs_fattr_init(stat->fattr); - status = rpc_call_sync(server->client, &msg, 0); + status = nfs2_rpc(server->client, NFSPROC_STATFS, fhandle, &fsinfo, NULL); dprintk("NFS reply statfs: %d\n", status); if (status) goto out; @@ -567,16 +540,11 @@ nfs_proc_fsinfo(struct nfs_server *serve struct nfs_fsinfo *info) { struct nfs2_fsstat fsinfo; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_STATFS], - .rpc_argp = fhandle, - .rpc_resp = &fsinfo, - }; int status; dprintk("NFS call fsinfo\n"); nfs_fattr_init(info->fattr); - status = rpc_call_sync(server->client, &msg, 0); + status = nfs2_rpc(server->client, NFSPROC_STATFS, fhandle, &fsinfo, NULL); dprintk("NFS reply fsinfo: %d\n", status); if (status) goto out; diff -Nurp a/fs/nfs/unlink.c b/fs/nfs/unlink.c --- a/fs/nfs/unlink.c 2013-11-06 09:13:57.701650764 +0100 +++ b/fs/nfs/unlink.c 2014-01-01 10:58:13.481972748 +0100 @@ -258,7 +258,12 @@ nfs_async_unlink(struct inode *dir, stru if (data == NULL) goto out; - data->cred = rpc_lookup_cred(); + if (NFS_PROTO(dir)->version > 3) + data->cred = rpc_lookup_cred(NULL); + else { + struct rpc_groups fsg = { 1, { dir->i_gid } }; + data->cred = rpc_lookup_cred(&fsg); + } if (IS_ERR(data->cred)) { status = PTR_ERR(data->cred); goto out_free; @@ -418,7 +423,12 @@ nfs_async_rename(struct inode *old_dir, return ERR_PTR(-ENOMEM); task_setup_data.callback_data = data; - data->cred = rpc_lookup_cred(); + if (NFS_PROTO(old_dir)->version > 3) + data->cred = rpc_lookup_cred(NULL); + else { + struct rpc_groups fsg = { 2, { old_dir->i_gid, new_dir->i_gid } }; + data->cred = rpc_lookup_cred(&fsg); + } if (IS_ERR(data->cred)) { struct rpc_task *task = ERR_CAST(data->cred); kfree(data); diff -Nurp a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h --- a/include/linux/nfs_fs.h 2013-11-06 09:14:03.793748657 +0100 +++ b/include/linux/nfs_fs.h 2014-01-01 10:58:13.516973285 +0100 @@ -474,7 +474,8 @@ extern const struct dentry_operations nf extern void nfs_force_lookup_revalidate(struct inode *dir); extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, - struct nfs_fattr *fattr, struct nfs4_label *label); + struct nfs_fattr *fattr, struct nfs4_label *label, + struct rpc_groups *fsg); extern int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags); extern void nfs_access_zap_cache(struct inode *inode); diff -Nurp a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h --- a/include/linux/nfs_xdr.h 2013-11-06 09:14:03.809748914 +0100 +++ b/include/linux/nfs_xdr.h 2014-01-01 10:58:13.525973422 +0100 @@ -1376,13 +1376,14 @@ struct nfs_renamedata { struct nfs_access_entry; struct nfs_client; struct rpc_timeout; +struct rpc_groups; struct nfs_subversion; struct nfs_mount_info; struct nfs_client_initdata; struct nfs_pageio_descriptor; /* - * RPC procedure vector for NFSv2/NFSv3 demuxing + * RPC procedure vector for NFSv2/NFSv3/NFSv4 demuxing */ struct nfs_rpc_ops { u32 version; /* Protocol version */ @@ -1400,33 +1401,35 @@ struct nfs_rpc_ops { int (*getattr) (struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *); int (*setattr) (struct dentry *, struct nfs_fattr *, - struct iattr *); + struct iattr *, struct rpc_groups *); int (*lookup) (struct inode *, struct qstr *, struct nfs_fh *, struct nfs_fattr *, - struct nfs4_label *); + struct nfs4_label *, struct rpc_groups *); int (*access) (struct inode *, struct nfs_access_entry *); int (*readlink)(struct inode *, struct page *, unsigned int, unsigned int); int (*create) (struct inode *, struct dentry *, - struct iattr *, int); - int (*remove) (struct inode *, struct qstr *); + struct iattr *, int, struct rpc_groups *); + int (*remove) (struct inode *, struct qstr *, struct rpc_groups *); void (*unlink_setup) (struct rpc_message *, struct inode *dir); void (*unlink_rpc_prepare) (struct rpc_task *, struct nfs_unlinkdata *); int (*unlink_done) (struct rpc_task *, struct inode *); int (*rename) (struct inode *, struct qstr *, - struct inode *, struct qstr *); + struct inode *, struct qstr *, struct rpc_groups *); void (*rename_setup) (struct rpc_message *msg, struct inode *dir); void (*rename_rpc_prepare)(struct rpc_task *task, struct nfs_renamedata *); int (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir); - int (*link) (struct inode *, struct inode *, struct qstr *); + int (*link) (struct inode *, struct inode *, struct qstr *, + struct rpc_groups *); int (*symlink) (struct inode *, struct dentry *, struct page *, - unsigned int, struct iattr *); - int (*mkdir) (struct inode *, struct dentry *, struct iattr *); - int (*rmdir) (struct inode *, struct qstr *); + unsigned int, struct iattr *, struct rpc_groups *); + int (*mkdir) (struct inode *, struct dentry *, struct iattr *, + struct rpc_groups *); + int (*rmdir) (struct inode *, struct qstr *, struct rpc_groups *); int (*readdir) (struct dentry *, struct rpc_cred *, u64, struct page **, unsigned int, int); int (*mknod) (struct inode *, struct dentry *, struct iattr *, - dev_t); + dev_t, struct rpc_groups *); int (*statfs) (struct nfs_server *, struct nfs_fh *, struct nfs_fsstat *); int (*fsinfo) (struct nfs_server *, struct nfs_fh *, diff -Nurp a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h --- a/include/linux/sunrpc/auth.h 2013-11-06 09:14:05.051768872 +0100 +++ b/include/linux/sunrpc/auth.h 2014-01-01 10:58:13.568974076 +0100 @@ -32,11 +32,16 @@ enum { key will expire soon */ }; +struct rpc_groups { + int ngroups; + kgid_t groups[RPC_MAXGROUPS]; +}; + /* Work around the lack of a VFS credential */ struct auth_cred { kuid_t uid; kgid_t gid; - struct group_info *group_info; + struct rpc_groups rg; const char *principal; unsigned long ac_flags; unsigned char machine_cred : 1; @@ -152,7 +157,7 @@ void rpcauth_remove_module(void); void rpc_destroy_generic_auth(void); void rpc_destroy_authunix(void); -struct rpc_cred * rpc_lookup_cred(void); +struct rpc_cred * rpc_lookup_cred(struct rpc_groups *); struct rpc_cred * rpc_lookup_machine_cred(const char *service_name); int rpcauth_register(const struct rpc_authops *); int rpcauth_unregister(const struct rpc_authops *); @@ -166,7 +171,7 @@ int rpcauth_get_gssinfo(rpc_authflavor int rpcauth_list_flavors(rpc_authflavor_t *, int); struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); -struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); +struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, struct rpc_groups *, int); struct rpc_cred * rpcauth_generic_bind_cred(struct rpc_task *, struct rpc_cred *, int); void put_rpccred(struct rpc_cred *); __be32 * rpcauth_marshcred(struct rpc_task *, __be32 *); diff -Nurp a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h --- a/include/linux/sunrpc/msg_prot.h 2013-07-31 19:55:44.224386911 +0200 +++ b/include/linux/sunrpc/msg_prot.h 2014-01-01 10:58:13.575974186 +0100 @@ -79,6 +79,7 @@ enum rpc_auth_stat { }; #define RPC_MAXNETNAMELEN 256 +#define RPC_MAXGROUPS 16 /* * From RFC 1831: diff -Nurp a/net/sunrpc/auth.c b/net/sunrpc/auth.c --- a/net/sunrpc/auth.c 2013-11-06 09:14:15.604938450 +0100 +++ b/net/sunrpc/auth.c 2014-01-01 10:58:13.612974754 +0100 @@ -15,11 +15,15 @@ #include #include #include +#include #ifdef RPC_DEBUG # define RPCDBG_FACILITY RPCDBG_AUTH +# define RG(rg,i) ((i) < (rg).ngroups ? (int)from_kgid(&init_user_ns, (rg).groups[i]) : -1) #endif +static void rpcauth_add_groups(struct auth_cred *acred, struct rpc_groups *rg); + #define RPC_CREDCACHE_DEFAULT_HASHBITS (4) struct rpc_cred_cache { struct hlist_head *hashtable; @@ -574,24 +578,24 @@ out: EXPORT_SYMBOL_GPL(rpcauth_lookup_credcache); struct rpc_cred * -rpcauth_lookupcred(struct rpc_auth *auth, int flags) +rpcauth_lookupcred(struct rpc_auth *auth, struct rpc_groups *rg, int flags) { struct auth_cred acred; struct rpc_cred *ret; const struct cred *cred = current_cred(); - dprintk("RPC: looking up %s cred\n", - auth->au_ops->au_name); + dprintk("RPC: looking up %s cred\n", auth->au_ops->au_name); memset(&acred, 0, sizeof(acred)); acred.uid = cred->fsuid; - acred.gid = cred->fsgid; - acred.group_info = get_group_info(((struct cred *)cred)->group_info); + rpcauth_add_groups(&acred, rg); ret = auth->au_ops->lookup_cred(auth, &acred, flags); - put_group_info(acred.group_info); + + dprintk("RPC: cred %p\n", ret); return ret; } +EXPORT_SYMBOL_GPL(rpcauth_lookupcred); void rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, @@ -640,7 +644,7 @@ rpcauth_bind_new_cred(struct rpc_task *t dprintk("RPC: %5u looking up %s cred\n", task->tk_pid, auth->au_ops->au_name); - return rpcauth_lookupcred(auth, lookupflags); + return rpcauth_lookupcred(auth, NULL, lookupflags); } static int @@ -666,6 +670,44 @@ rpcauth_bindcred(struct rpc_task *task, return 0; } +/* + * Generic function for adding groups to acred. When there are too many then + * try to be smart by picking only the relevant ones from our secondary group list. + */ +static void rpcauth_add_groups(struct auth_cred *acred, struct rpc_groups *rg) +{ + int i, n, ngroups; + kgid_t gid; + const struct cred *cred = current_cred(); + + acred->gid = cred->fsgid; + get_group_info(cred->group_info); + ngroups = cred->group_info->ngroups; + n = ngroups; + if (n <= RPC_MAXGROUPS) + rg = NULL; + else + n = RPC_MAXGROUPS; /* too many groups for AUTH_UNIX */ + if (rg) { + n = 0; /* pick the few relevant groups we're a member of */ + for (i = 0; i < rg->ngroups; ++i) { + gid = rg->groups[i]; + if (in_group_p(gid)) + acred->rg.groups[n++] = gid; + } + acred->rg.ngroups = n; + dprintk("RPC: %s(): rg=%d:%d,%d,%d -> %d:%d,%d,%d\n", __func__, + rg->ngroups, RG(*rg, 0), RG(*rg, 1), RG(*rg, 2), + n, RG(acred->rg, 0), RG(acred->rg, 1), RG(acred->rg, 2)); + } else { + dprintk("RPC: %s(): ngroups=%d\n", __func__, ngroups); + for (i = 0; i < n; ++i) + acred->rg.groups[i] = from_kgid(&init_user_ns, GROUP_AT(cred->group_info, i)); + acred->rg.ngroups = n; + } + put_group_info(cred->group_info); +} + void put_rpccred(struct rpc_cred *cred) { diff -Nurp a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c --- a/net/sunrpc/auth_generic.c 2013-11-06 09:14:15.651939205 +0100 +++ b/net/sunrpc/auth_generic.c 2014-01-01 11:28:46.818017885 +0100 @@ -32,9 +32,9 @@ static const struct rpc_credops generic_ /* * Public call interface */ -struct rpc_cred *rpc_lookup_cred(void) +struct rpc_cred *rpc_lookup_cred(struct rpc_groups *rg) { - return rpcauth_lookupcred(&generic_auth, 0); + return rpcauth_lookupcred(&generic_auth, rg, 0); } EXPORT_SYMBOL_GPL(rpc_lookup_cred); @@ -86,14 +86,8 @@ generic_create_cred(struct rpc_auth *aut rpcauth_init_cred(&gcred->gc_base, acred, &generic_auth, &generic_credops); gcred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE; - gcred->acred.uid = acred->uid; - gcred->acred.gid = acred->gid; - gcred->acred.group_info = acred->group_info; + gcred->acred = *acred; gcred->acred.ac_flags = 0; - if (gcred->acred.group_info != NULL) - get_group_info(gcred->acred.group_info); - gcred->acred.machine_cred = acred->machine_cred; - gcred->acred.principal = acred->principal; dprintk("RPC: allocated %s cred %p for uid %d gid %d\n", gcred->acred.machine_cred ? "machine" : "generic", @@ -109,8 +103,6 @@ generic_free_cred(struct rpc_cred *cred) struct generic_cred *gcred = container_of(cred, struct generic_cred, gc_base); dprintk("RPC: generic_free_cred %p\n", gcred); - if (gcred->acred.group_info != NULL) - put_group_info(gcred->acred.group_info); kfree(gcred); } @@ -155,19 +147,12 @@ generic_match(struct auth_cred *acred, s gcred->acred.machine_cred != 0) goto out_nomatch; - /* Optimisation in the case where pointers are identical... */ - if (gcred->acred.group_info == acred->group_info) - goto out_match; - - /* Slow path... */ - if (gcred->acred.group_info->ngroups != acred->group_info->ngroups) + if (gcred->acred.rg.ngroups != acred->rg.ngroups) goto out_nomatch; - for (i = 0; i < gcred->acred.group_info->ngroups; i++) { - if (!gid_eq(GROUP_AT(gcred->acred.group_info, i), - GROUP_AT(acred->group_info, i))) + for (i = 0; i < gcred->acred.rg.ngroups; i++) { + if (!gid_eq(gcred->acred.rg.groups[i], acred->rg.groups[i])) goto out_nomatch; } -out_match: return 1; out_nomatch: return 0; diff -Nurp a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c --- a/net/sunrpc/auth_unix.c 2013-11-06 09:14:15.712940182 +0100 +++ b/net/sunrpc/auth_unix.c 2014-01-01 10:58:13.624974935 +0100 @@ -12,14 +12,11 @@ #include #include #include -#include - -#define NFS_NGROUPS 16 struct unx_cred { struct rpc_cred uc_base; kgid_t uc_gid; - kgid_t uc_gids[NFS_NGROUPS]; + kgid_t uc_gids[RPC_MAXGROUPS]; }; #define uc_uid uc_base.cr_uid @@ -61,7 +58,7 @@ static struct rpc_cred * unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) { struct unx_cred *cred; - unsigned int groups = 0; + unsigned int groups = acred->rg.ngroups; unsigned int i; dprintk("RPC: allocating UNIX cred for uid %d gid %d\n", @@ -74,15 +71,10 @@ unx_create_cred(struct rpc_auth *auth, s rpcauth_init_cred(&cred->uc_base, acred, auth, &unix_credops); cred->uc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE; - if (acred->group_info != NULL) - groups = acred->group_info->ngroups; - if (groups > NFS_NGROUPS) - groups = NFS_NGROUPS; - cred->uc_gid = acred->gid; for (i = 0; i < groups; i++) - cred->uc_gids[i] = GROUP_AT(acred->group_info, i); - if (i < NFS_NGROUPS) + cred->uc_gids[i] = acred->rg.groups[i]; + if (i < RPC_MAXGROUPS) cred->uc_gids[i] = INVALID_GID; return &cred->uc_base; @@ -117,21 +109,17 @@ static int unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags) { struct unx_cred *cred = container_of(rcred, struct unx_cred, uc_base); - unsigned int groups = 0; + unsigned int groups = acred->rg.ngroups; unsigned int i; if (!uid_eq(cred->uc_uid, acred->uid) || !gid_eq(cred->uc_gid, acred->gid)) return 0; - if (acred->group_info != NULL) - groups = acred->group_info->ngroups; - if (groups > NFS_NGROUPS) - groups = NFS_NGROUPS; for (i = 0; i < groups ; i++) - if (!gid_eq(cred->uc_gids[i], GROUP_AT(acred->group_info, i))) + if (!gid_eq(cred->uc_gids[i], acred->rg.groups[i])) return 0; - if (groups < NFS_NGROUPS && gid_valid(cred->uc_gids[groups])) + if (groups < RPC_MAXGROUPS && gid_valid(cred->uc_gids[groups])) return 0; return 1; } @@ -160,7 +148,7 @@ unx_marshal(struct rpc_task *task, __be3 *p++ = htonl((u32) from_kuid(&init_user_ns, cred->uc_uid)); *p++ = htonl((u32) from_kgid(&init_user_ns, cred->uc_gid)); hold = p++; - for (i = 0; i < 16 && gid_valid(cred->uc_gids[i]); i++) + for (i = 0; i < RPC_MAXGROUPS && gid_valid(cred->uc_gids[i]); i++) *p++ = htonl((u32) from_kgid(&init_user_ns, cred->uc_gids[i])); *hold = htonl(p - hold - 1); /* gid array length */ *base = htonl((p - base - 1) << 2); /* cred length */ diff -Nurp a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c --- a/net/sunrpc/svcauth_unix.c 2013-09-07 16:12:04.224793476 +0200 +++ b/net/sunrpc/svcauth_unix.c 2014-01-01 10:58:13.625974952 +0100 @@ -818,7 +818,7 @@ svcauth_unix_accept(struct svc_rqst *rqs cred->cr_uid = make_kuid(&init_user_ns, svc_getnl(argv)); /* uid */ cred->cr_gid = make_kgid(&init_user_ns, svc_getnl(argv)); /* gid */ slen = svc_getnl(argv); /* gids length */ - if (slen > 16 || (len -= (slen + 2)*4) < 0) + if (slen > RPC_MAXGROUPS || (len -= (slen + 2)*4) < 0) goto badcred; cred->cr_group_info = groups_alloc(slen); if (cred->cr_group_info == NULL)