diff -Nurp a/fs/nfs/dir.c b/fs/nfs/dir.c --- a/fs/nfs/dir.c 2013-02-14 09:31:51.021507241 +0100 +++ b/fs/nfs/dir.c 2013-02-14 09:38:11.412586807 +0100 @@ -101,7 +101,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); @@ -1035,6 +1040,7 @@ static int nfs_lookup_revalidate(struct struct dentry *parent; struct nfs_fh *fhandle = NULL; struct nfs_fattr *fattr = NULL; + struct rpc_groups fsg; int error; if (flags & LOOKUP_RCU) @@ -1077,7 +1083,9 @@ static int nfs_lookup_revalidate(struct if (fhandle == NULL || fattr == NULL) goto out_error; - error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); + fsg.ngroups = 1; + fsg.groups[0] = dir->i_gid; + error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, &fsg); if (error) goto out_bad; if (nfs_compare_fh(NFS_FH(inode), fhandle)) @@ -1211,6 +1219,7 @@ struct dentry *nfs_lookup(struct inode * struct inode *inode = NULL; struct nfs_fh *fhandle = NULL; struct nfs_fattr *fattr = NULL; + struct rpc_groups fsg; int error; dfprintk(VFS, "NFS: lookup(%s/%s)\n", @@ -1240,7 +1249,9 @@ struct dentry *nfs_lookup(struct inode * parent = dentry->d_parent; /* Protect against concurrent sillydeletes */ nfs_block_sillyrename(parent); - error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); + fsg.ngroups = 1; + fsg.groups[0] = dir->i_gid; + error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, &fsg); if (error == -ENOENT) goto no_entry; if (error < 0) { @@ -1481,7 +1492,7 @@ no_open: * Code common to create, mkdir, and mknod. */ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, - struct nfs_fattr *fattr) + struct nfs_fattr *fattr, struct rpc_groups *fsg) { struct dentry *parent = dget_parent(dentry); struct inode *dir = parent->d_inode; @@ -1494,7 +1505,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); + error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, fsg); if (error) goto out_error; } @@ -1531,6 +1542,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", @@ -1539,7 +1551,7 @@ int nfs_create(struct inode *dir, struct attr.ia_mode = mode; attr.ia_valid = ATTR_MODE; - error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags); + error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, &fsg); if (error != 0) goto out_err; return 0; @@ -1557,6 +1569,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); @@ -1567,7 +1580,7 @@ nfs_mknod(struct inode *dir, struct dent attr.ia_mode = mode; attr.ia_valid = ATTR_MODE; - status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev); + status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev, &fsg); if (status != 0) goto out_err; return 0; @@ -1584,6 +1597,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); @@ -1591,7 +1605,7 @@ int nfs_mkdir(struct inode *dir, struct attr.ia_valid = ATTR_MODE; attr.ia_mode = mode | S_IFDIR; - error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr); + error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr, &fsg); if (error != 0) goto out_err; return 0; @@ -1610,11 +1624,12 @@ 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); - 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 */ if (error == 0 && dentry->d_inode != NULL) clear_nlink(dentry->d_inode); @@ -1636,6 +1651,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", @@ -1649,11 +1665,11 @@ static int nfs_safe_remove(struct 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); out: @@ -1718,6 +1734,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); @@ -1738,7 +1755,7 @@ int nfs_symlink(struct inode *dir, struc memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen); kunmap_atomic(kaddr); - error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr); + error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr, &fsg); if (error != 0) { dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n", dir->i_sb->s_id, dir->i_ino, @@ -1770,6 +1787,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", @@ -1779,7 +1797,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); @@ -1818,6 +1836,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", @@ -1866,7 +1892,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) @@ -2129,6 +2155,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); @@ -2206,7 +2234,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 2012-12-15 13:25:14.757087243 +0100 +++ b/fs/nfs/inode.c 2013-02-14 09:32:45.757234956 +0100 @@ -404,6 +404,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); @@ -436,7 +437,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) nfs_refresh_inode(inode, fattr); nfs_free_fattr(fattr); @@ -636,7 +641,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_PROTO(dentry->d_inode)->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-02-14 09:31:51.036507459 +0100 +++ b/fs/nfs/namespace.c 2013-02-14 09:32:45.766235147 +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); + err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &dentry->d_name, fh, fattr, 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 2012-10-07 21:11:54.088310983 +0200 +++ b/fs/nfs/nfs3proc.c 2013-02-14 09:32:45.782235349 +0100 @@ -26,11 +26,19 @@ /* A wrapper to handle the EJUKEBOX and EKEYEXPIRED 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 && res != -EKEYEXPIRED) break; freezable_schedule_timeout_killable(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 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); @@ -143,7 +157,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 nfs_fh *fhandle, struct nfs_fattr *fattr, struct rpc_groups *fsg) { struct nfs3_diropargs arg = { .fh = NFS_FH(dir), @@ -154,11 +168,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); @@ -167,13 +176,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); @@ -186,12 +193,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; @@ -215,7 +216,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; @@ -242,19 +244,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: @@ -263,7 +260,8 @@ out: } struct nfs3_createdata { - struct rpc_message msg; + u32 proc; + struct rpc_groups *fsg; union { struct nfs3_createargs create; struct nfs3_mkdirargs mkdir; @@ -282,8 +280,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; @@ -297,10 +293,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); + status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->fsg); return status; } @@ -314,7 +310,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; @@ -326,7 +322,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; @@ -380,7 +377,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) @@ -394,18 +391,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); @@ -413,7 +405,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: @@ -471,7 +463,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), @@ -480,11 +473,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); @@ -494,7 +482,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: @@ -505,7 +493,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), @@ -514,11 +503,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); @@ -527,7 +511,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: @@ -539,7 +523,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; @@ -552,7 +536,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; @@ -569,7 +554,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; @@ -583,7 +569,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; @@ -601,7 +588,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 = { @@ -609,10 +596,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); @@ -620,8 +603,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: @@ -656,16 +638,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); @@ -674,7 +651,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); @@ -688,7 +665,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; @@ -703,7 +680,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; @@ -742,16 +720,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; } @@ -760,16 +733,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; } @@ -794,16 +762,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 2013-02-14 09:31:51.088508160 +0100 +++ b/fs/nfs/nfs4proc.c 2013-02-14 09:32:45.792235492 +0100 @@ -2702,7 +2702,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; @@ -2819,7 +2819,8 @@ out: } static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, - struct nfs_fh *fhandle, struct nfs_fattr *fattr) + struct nfs_fh *fhandle, struct nfs_fattr *fattr, + struct rpc_groups *fsg) { int status; struct rpc_clnt *client = NFS_CLIENT(dir); @@ -2967,7 +2968,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 nfs_open_context *ctx; struct nfs4_state *state; @@ -3017,7 +3018,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; @@ -3127,7 +3129,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; @@ -3173,7 +3176,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; @@ -3225,7 +3229,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); + status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL); } return status; } @@ -3261,7 +3265,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 = { }; int err; @@ -3292,7 +3297,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 = { }; int err; @@ -3394,7 +3399,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 = { }; int err; diff -Nurp a/fs/nfs/proc.c b/fs/nfs/proc.c --- a/fs/nfs/proc.c 2012-10-07 21:11:54.199312826 +0200 +++ b/fs/nfs/proc.c 2013-02-14 09:32:45.839236097 +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. @@ -52,12 +52,20 @@ * support the NFSERR_JUKEBOX error code, but we handle this situation in the * same way that we handle that error with NFSv3. */ -static int -nfs_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) +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; + do { - res = rpc_call_sync(clnt, msg, flags); + res = rpc_call_sync(clnt, &msg, flags); if (res != -EKEYEXPIRED) break; freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME); @@ -66,7 +74,20 @@ nfs_rpc_wrapper(struct rpc_clnt *clnt, s return res; } -#define rpc_call_sync(clnt, msg, flags) nfs_rpc_wrapper(clnt, msg, flags) +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; +} static int nfs_async_handle_expired_key(struct rpc_task *task) @@ -88,29 +109,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; @@ -133,44 +147,44 @@ static int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { - 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); @@ -179,7 +193,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 nfs_fh *fhandle, struct nfs_fattr *fattr, struct rpc_groups *fsg) { struct nfs_diropargs arg = { .fh = NFS_FH(dir), @@ -190,16 +204,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; } @@ -213,14 +222,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; } @@ -259,24 +264,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); + status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, fsg); nfs_free_createdata(data); out: dprintk("NFS reply create: %d\n", status); @@ -288,12 +288,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; @@ -311,19 +308,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); + status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, fsg); nfs_free_createdata(data); out: dprintk("NFS reply mknod: %d\n", status); @@ -331,20 +326,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); @@ -394,7 +385,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), @@ -402,14 +394,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); @@ -417,7 +405,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), @@ -425,14 +414,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); @@ -441,7 +426,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; @@ -453,10 +438,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); @@ -470,7 +451,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); /* @@ -479,7 +460,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); + status = nfs_instantiate(dentry, fh, fattr, fsg); out_free: nfs_free_fattr(fattr); @@ -490,25 +471,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); + status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, fsg); nfs_free_createdata(data); out: dprintk("NFS reply mkdir: %d\n", status); @@ -516,21 +493,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; @@ -554,15 +527,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); @@ -575,16 +543,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; @@ -603,16 +566,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 2012-12-15 13:25:15.128092861 +0100 +++ b/fs/nfs/unlink.c 2013-02-14 09:32:45.867236522 +0100 @@ -248,7 +248,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; @@ -413,7 +418,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 2012-12-15 13:25:22.359201949 +0100 +++ b/include/linux/nfs_fs.h 2013-02-14 09:32:45.900236982 +0100 @@ -460,7 +460,8 @@ extern const struct file_operations nfs_ extern const struct dentry_operations nfs_dentry_operations; extern void nfs_force_lookup_revalidate(struct inode *dir); -extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr); +extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, + struct nfs_fattr *fattr, 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 2012-12-15 13:25:22.385202313 +0100 +++ b/include/linux/nfs_xdr.h 2013-02-14 09:32:45.909237053 +0100 @@ -1357,13 +1357,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 */ @@ -1381,32 +1382,35 @@ struct nfs_rpc_ops { int (*getattr) (struct nfs_server *, struct nfs_fh *, struct nfs_fattr *); 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 nfs_fh *, struct nfs_fattr *, + 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 2012-10-07 21:12:02.300447230 +0200 +++ b/include/linux/sunrpc/auth.h 2013-02-14 09:32:45.950237567 +0100 @@ -21,11 +21,16 @@ /* size of the nodename buffer */ #define UNX_MAXNODENAME 32 +struct rpc_groups { + int ngroups; + gid_t groups[RPC_MAXGROUPS]; +}; + /* Work around the lack of a VFS credential */ struct auth_cred { uid_t uid; gid_t gid; - struct group_info *group_info; + struct rpc_groups rg; const char *principal; unsigned char machine_cred : 1; }; @@ -130,7 +135,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 *); @@ -139,7 +144,7 @@ void rpcauth_release(struct rpc_auth * 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 2011-10-24 09:10:05.000000000 +0200 +++ b/include/linux/sunrpc/msg_prot.h 2013-02-14 09:32:46.001238299 +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 2012-10-07 21:12:11.136593708 +0200 +++ b/net/sunrpc/auth.c 2013-02-14 09:32:46.057239036 +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)(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; @@ -469,24 +473,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, @@ -535,7 +539,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 @@ -561,6 +565,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; + gid_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 2012-07-29 19:44:33.820217941 +0200 +++ b/net/sunrpc/auth_generic.c 2013-02-14 09:32:46.078239336 +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,13 +86,7 @@ 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; - 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; + gcred->acred = *acred; dprintk("RPC: allocated %s cred %p for uid %d gid %d\n", gcred->acred.machine_cred ? "machine" : "generic", @@ -106,8 +100,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); } @@ -142,32 +134,17 @@ static int generic_match(struct auth_cred *acred, struct rpc_cred *cred, int flags) { struct generic_cred *gcred = container_of(cred, struct generic_cred, gc_base); - int i; if (acred->machine_cred) return machine_cred_match(acred, gcred, flags); if (gcred->acred.uid != acred->uid || gcred->acred.gid != acred->gid || + gcred->acred.rg.ngroups != acred->rg.ngroups || + memcmp(gcred->acred.rg.groups, acred->rg.groups, acred->rg.ngroups * sizeof (gid_t)) || 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) - 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))) - goto out_nomatch; - } -out_match: + return 0; return 1; -out_nomatch: - return 0; } int __init rpc_init_generic_auth(void) diff -Nurp a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c --- a/net/sunrpc/auth_unix.c 2012-07-29 19:44:33.822218001 +0200 +++ b/net/sunrpc/auth_unix.c 2013-02-14 09:32:46.085239426 +0100 @@ -12,14 +12,11 @@ #include #include #include -#include - -#define NFS_NGROUPS 16 struct unx_cred { struct rpc_cred uc_base; gid_t uc_gid; - gid_t uc_gids[NFS_NGROUPS]; + gid_t uc_gids[RPC_MAXGROUPS]; }; #define uc_uid uc_base.cr_uid @@ -61,8 +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 i; + int n; dprintk("RPC: allocating UNIX cred for uid %d gid %d\n", acred->uid, acred->gid); @@ -73,19 +69,11 @@ 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; - + n = acred->rg.ngroups; cred->uc_gid = acred->gid; - for (i = 0; i < groups; i++) { - gid_t gid; - gid = from_kgid(&init_user_ns, GROUP_AT(acred->group_info, i)); - cred->uc_gids[i] = gid; - } - if (i < NFS_NGROUPS) - cred->uc_gids[i] = NOGROUP; + memcpy(cred->uc_gids, acred->rg.groups, n * sizeof (gid_t)); + if (n < RPC_MAXGROUPS) + cred->uc_gids[n] = NOGROUP; return &cred->uc_base; } @@ -119,25 +107,14 @@ 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 i; - + int n = acred->rg.ngroups; if (cred->uc_uid != acred->uid || 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++) { - gid_t gid; - gid = from_kgid(&init_user_ns, GROUP_AT(acred->group_info, i)); - if (cred->uc_gids[i] != gid) - return 0; - } - if (groups < NFS_NGROUPS && - cred->uc_gids[groups] != NOGROUP) + if (memcmp(cred->uc_gids, acred->rg.groups, n * sizeof (gid_t))) + return 0; + if (n < RPC_MAXGROUPS && + cred->uc_gids[n] != NOGROUP) return 0; return 1; } @@ -166,7 +143,7 @@ unx_marshal(struct rpc_task *task, __be3 *p++ = htonl((u32) cred->uc_uid); *p++ = htonl((u32) cred->uc_gid); hold = p++; - for (i = 0; i < 16 && cred->uc_gids[i] != (gid_t) NOGROUP; i++) + for (i = 0; i < RPC_MAXGROUPS && cred->uc_gids[i] != (gid_t) NOGROUP; i++) *p++ = htonl((u32) 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 2012-10-07 21:12:11.212594963 +0200 +++ b/net/sunrpc/svcauth_unix.c 2013-02-14 09:32:46.094239550 +0100 @@ -815,7 +815,7 @@ svcauth_unix_accept(struct svc_rqst *rqs cred->cr_uid = svc_getnl(argv); /* uid */ cred->cr_gid = 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)