diff -Nurp a/fs/nfs/dir.c b/fs/nfs/dir.c --- a/fs/nfs/dir.c 2008-10-25 15:18:54.000000000 +0200 +++ b/fs/nfs/dir.c 2009-01-01 11:59:46.000000000 +0100 @@ -772,6 +772,7 @@ static int nfs_lookup_revalidate(struct int error; struct nfs_fh fhandle; struct nfs_fattr fattr; + struct rpc_groups fsg; parent = dget_parent(dentry); dir = parent->d_inode; @@ -801,7 +802,9 @@ static int nfs_lookup_revalidate(struct if (NFS_STALE(inode)) goto out_bad; - 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)) @@ -901,6 +904,7 @@ static struct dentry *nfs_lookup(struct int error; struct nfs_fh fhandle; struct nfs_fattr fattr; + struct rpc_groups fsg; dfprintk(VFS, "NFS: lookup(%s/%s)\n", dentry->d_parent->d_name.name, dentry->d_name.name); @@ -926,7 +930,9 @@ static struct dentry *nfs_lookup(struct 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) { @@ -1160,7 +1166,7 @@ out_renew: * 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; @@ -1173,7 +1179,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; } @@ -1210,6 +1216,7 @@ static int nfs_create(struct inode *dir, struct iattr attr; int error; int open_flags = 0; + struct rpc_groups fsg = { 1, { dir->i_gid } }; dfprintk(VFS, "NFS: create(%s/%ld), %s\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); @@ -1220,7 +1227,7 @@ static int nfs_create(struct inode *dir, if ((nd->flags & LOOKUP_CREATE) != 0) open_flags = nd->intent.open.flags; - error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd); + error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd, &fsg); if (error != 0) goto out_err; return 0; @@ -1237,6 +1244,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); @@ -1247,7 +1255,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; @@ -1263,6 +1271,7 @@ static int nfs_mkdir(struct inode *dir, { 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); @@ -1270,7 +1279,7 @@ static int nfs_mkdir(struct inode *dir, 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; @@ -1288,11 +1297,12 @@ static void nfs_dentry_handle_enoent(str static 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); @@ -1312,6 +1322,7 @@ static int nfs_sillyrename(struct inode struct qstr qsilly; struct dentry *sdentry; int error = -EIO; + struct rpc_groups fsg = { 1, { dir->i_gid } }; dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", dentry->d_parent->d_name.name, dentry->d_name.name, @@ -1356,11 +1367,11 @@ static int nfs_sillyrename(struct inode qsilly.len = strlen(silly); if (dentry->d_inode) { error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, - dir, &qsilly); + dir, &qsilly, &fsg); nfs_mark_for_revalidate(dentry->d_inode); } else error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, - dir, &qsilly); + dir, &qsilly, &fsg); if (!error) { nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); d_move(dentry, sdentry); @@ -1383,6 +1394,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", @@ -1396,13 +1408,13 @@ static int nfs_safe_remove(struct dentry if (inode != NULL) { nfs_inode_return_delegation(inode); - error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); + error = NFS_PROTO(dir)->remove(dir, &dentry->d_name, &fsg); /* The VFS may want to delete this inode */ if (error == 0) nfs_drop_nlink(inode); nfs_mark_for_revalidate(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: @@ -1469,6 +1481,7 @@ static int nfs_symlink(struct inode *dir 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); @@ -1489,7 +1502,7 @@ static int nfs_symlink(struct inode *dir memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen); kunmap_atomic(kaddr, KM_USER0); - 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, @@ -1520,6 +1533,7 @@ static 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", @@ -1527,7 +1541,7 @@ nfs_link(struct dentry *old_dentry, stru dentry->d_parent->d_name.name, dentry->d_name.name); 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) { atomic_inc(&inode->i_count); d_add(dentry, inode); @@ -1565,6 +1579,14 @@ static int nfs_rename(struct inode *old_ 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; /* @@ -1633,7 +1655,7 @@ go_ahead: } 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) @@ -1880,6 +1902,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) return status; nfs_access_add_cache(inode, &cache); @@ -1942,7 +1966,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 2008-10-25 15:18:54.000000000 +0200 +++ b/fs/nfs/inode.c 2009-01-01 11:59:46.000000000 +0100 @@ -352,6 +352,7 @@ nfs_setattr(struct dentry *dentry, struc { struct inode *inode = dentry->d_inode; struct nfs_fattr fattr; + struct rpc_groups fsg; int error; nfs_inc_stats(inode, NFSIOS_VFSSETATTR); @@ -380,7 +381,11 @@ nfs_setattr(struct dentry *dentry, struc */ if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) nfs_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); return error; @@ -664,7 +669,12 @@ int nfs_open(struct inode *inode, struct struct nfs_open_context *ctx; struct rpc_cred *cred; - 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_context(filp->f_path.mnt, filp->f_path.dentry, cred); diff -Nurp a/fs/nfs/namespace.c b/fs/nfs/namespace.c --- a/fs/nfs/namespace.c 2008-10-25 15:18:54.000000000 +0200 +++ b/fs/nfs/namespace.c 2009-01-01 11:59:46.000000000 +0100 @@ -101,6 +101,7 @@ static void * nfs_follow_mountpoint(stru struct dentry *parent; struct nfs_fh fh; struct nfs_fattr fattr; + struct rpc_groups fsg; int err; dprintk("--> nfs_follow_mountpoint()\n"); @@ -112,9 +113,11 @@ static void * nfs_follow_mountpoint(stru /* Look it up again */ parent = dget_parent(nd->path.dentry); + fsg.ngroups = 1; + fsg.groups[0] = parent->d_inode->i_gid; err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &nd->path.dentry->d_name, - &fh, &fattr); + &fh, &fattr, &fsg); dput(parent); if (err != 0) goto out_err; diff -Nurp a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c --- a/fs/nfs/nfs3proc.c 2008-10-25 15:18:54.000000000 +0200 +++ b/fs/nfs/nfs3proc.c 2009-01-01 11:59:46.000000000 +0100 @@ -25,11 +25,19 @@ /* A wrapper to handle the EJUKEBOX error message */ 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; schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME); @@ -38,7 +46,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) @@ -56,21 +77,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 (!(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; @@ -98,41 +112,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); @@ -141,7 +155,8 @@ 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 nfs_fattr dir_attr; struct nfs3_diropargs arg = { @@ -154,23 +169,16 @@ 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); nfs_fattr_init(&dir_attr); 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, &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); } dprintk("NFS reply lookup: %d\n", status); return status; @@ -185,12 +193,6 @@ static int nfs3_proc_access(struct inode struct nfs3_accessres res = { .fattr = &fattr, }; - 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; @@ -210,7 +212,8 @@ static int nfs3_proc_access(struct inode arg.access |= NFS3_ACCESS_EXECUTE; } nfs_fattr_init(&fattr); - 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, &fattr); if (status == 0) { entry->mask = 0; @@ -235,23 +238,19 @@ static int nfs3_proc_readlink(struct ino .pglen = pglen, .pages = &page }; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_READLINK], - .rpc_argp = &args, - .rpc_resp = &fattr, - }; int status; dprintk("NFS call readlink\n"); nfs_fattr_init(&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); dprintk("NFS reply readlink: %d\n", status); return status; } struct nfs3_createdata { - struct rpc_message msg; + u32 proc; + struct rpc_groups *fsg; union { struct nfs3_createargs create; struct nfs3_mkdirargs mkdir; @@ -270,8 +269,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; @@ -285,10 +282,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; } @@ -303,7 +300,7 @@ static void nfs3_free_createdata(struct */ static int nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, - int flags, struct nameidata *nd) + int flags, struct nameidata *nd, struct rpc_groups *fsg) { struct nfs3_createdata *data; mode_t mode = sattr->ia_mode; @@ -315,7 +312,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; @@ -369,7 +367,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) @@ -383,7 +381,7 @@ 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), @@ -391,16 +389,11 @@ nfs3_proc_remove(struct inode *dir, stru .name.name = name->name, }; struct nfs_removeres res; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE], - .rpc_argp = &arg, - .rpc_resp = &res, - }; int status; dprintk("NFS call remove %s\n", name->name); nfs_fattr_init(&res.dir_attr); - 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); dprintk("NFS reply remove: %d\n", status); return status; @@ -425,7 +418,8 @@ nfs3_proc_unlink_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_fattr old_dir_attr, new_dir_attr; struct nfs3_renameargs arg = { @@ -440,17 +434,12 @@ nfs3_proc_rename(struct inode *old_dir, .fromattr = &old_dir_attr, .toattr = &new_dir_attr }; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_RENAME], - .rpc_argp = &arg, - .rpc_resp = &res, - }; int status; dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); nfs_fattr_init(&old_dir_attr); nfs_fattr_init(&new_dir_attr); - 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, &old_dir_attr); nfs_post_op_update_inode(new_dir, &new_dir_attr); dprintk("NFS reply rename: %d\n", status); @@ -458,7 +447,8 @@ nfs3_proc_rename(struct inode *old_dir, } 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 nfs_fattr dir_attr, fattr; struct nfs3_linkargs arg = { @@ -471,17 +461,12 @@ nfs3_proc_link(struct inode *inode, stru .dir_attr = &dir_attr, .fattr = &fattr }; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_LINK], - .rpc_argp = &arg, - .rpc_resp = &res, - }; int status; dprintk("NFS call link %s\n", name->name); nfs_fattr_init(&dir_attr); nfs_fattr_init(&fattr); - 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, &dir_attr); nfs_post_op_update_inode(inode, &fattr); dprintk("NFS reply link: %d\n", status); @@ -490,7 +475,7 @@ nfs3_proc_link(struct inode *inode, stru 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; @@ -503,7 +488,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; @@ -520,7 +506,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; int mode = sattr->ia_mode; @@ -534,7 +521,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; @@ -552,7 +540,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 = { @@ -560,16 +548,11 @@ 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, - .rpc_resp = &dir_attr, - }; int status; dprintk("NFS call rmdir %s\n", name->name); nfs_fattr_init(&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); dprintk("NFS reply rmdir: %d\n", status); return status; @@ -604,22 +587,17 @@ 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; + 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); nfs_fattr_init(&dir_attr); - 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); @@ -630,7 +608,7 @@ nfs3_proc_readdir(struct dentry *dentry, 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; mode_t mode = sattr->ia_mode; @@ -645,7 +623,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; @@ -684,16 +663,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 statfs: %d\n", status); return status; } @@ -702,16 +676,11 @@ static int nfs3_proc_fsinfo(struct nfs_server *server, 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(server->nfs_client->cl_rpcclient, &msg, 0); + status = nfs3_rpc(server->nfs_client->cl_rpcclient, NFS3PROC_FSINFO, fhandle, info, NULL); dprintk("NFS reply fsinfo: %d\n", status); return status; } @@ -720,16 +689,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 2008-10-25 15:18:54.000000000 +0200 +++ b/fs/nfs/nfs4proc.c 2009-01-01 11:59:46.000000000 +0100 @@ -1403,7 +1403,7 @@ nfs4_atomic_open(struct inode *dir, stru BUG_ON(nd->intent.open.flags & O_CREAT); } - cred = rpc_lookup_cred(); + cred = rpc_lookup_cred(NULL); if (IS_ERR(cred)) return (struct dentry *)cred; parent = dentry->d_parent; @@ -1438,7 +1438,7 @@ nfs4_open_revalidate(struct inode *dir, struct rpc_cred *cred; struct nfs4_state *state; - cred = rpc_lookup_cred(); + cred = rpc_lookup_cred(NULL); if (IS_ERR(cred)) return PTR_ERR(cred); state = nfs4_do_open(dir, &path, openflags, NULL, cred); @@ -1645,7 +1645,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; @@ -1729,7 +1729,9 @@ static int _nfs4_proc_lookup(struct inod return status; } -static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) +static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, + struct nfs_fh *fhandle, struct nfs_fattr *fattr, + struct rpc_groups *fsg) { struct nfs4_exception exception = { }; int err; @@ -1877,7 +1879,7 @@ static int nfs4_proc_readlink(struct ino static int nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, - int flags, struct nameidata *nd) + int flags, struct nameidata *nd, struct rpc_groups *fsg) { struct path path = { .mnt = nd->path.mnt, @@ -1887,7 +1889,7 @@ nfs4_proc_create(struct inode *dir, stru struct rpc_cred *cred; int status = 0; - cred = rpc_lookup_cred(); + cred = rpc_lookup_cred(NULL); if (IS_ERR(cred)) { status = PTR_ERR(cred); goto out; @@ -1945,7 +1947,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; @@ -2017,7 +2020,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; @@ -2064,7 +2068,8 @@ static int _nfs4_proc_link(struct inode 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; @@ -2119,7 +2124,7 @@ static int nfs4_do_create(struct inode * if (status == 0) { update_changeattr(dir, &data->res.dir_cinfo); nfs_post_op_update_inode(dir, data->res.dir_fattr); - status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); + status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL); } return status; } @@ -2155,7 +2160,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; @@ -2186,7 +2192,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; @@ -2283,7 +2289,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 2008-10-25 15:18:54.000000000 +0200 +++ b/fs/nfs/proc.c 2009-01-01 11:59:46.000000000 +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. @@ -47,6 +47,34 @@ #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, + }; + return rpc_call_sync(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; +} + /* * Bare-bones access to getattr: this is for nfs_read_super. */ @@ -56,23 +84,16 @@ 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->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->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; @@ -95,44 +116,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); @@ -141,7 +162,8 @@ 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), @@ -152,16 +174,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; } @@ -175,21 +192,17 @@ 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; } static int nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, - int flags, struct nameidata *nd) + int flags, struct nameidata *nd, struct rpc_groups *fsg) { struct nfs_fh fhandle; struct nfs_fattr fattr; @@ -203,19 +216,14 @@ nfs_proc_create(struct inode *dir, struc .fh = &fhandle, .fattr = &fattr }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_CREATE], - .rpc_argp = &arg, - .rpc_resp = &res, - }; int status; nfs_fattr_init(&fattr); dprintk("NFS call create %s\n", dentry->d_name.name); - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, fsg); nfs_mark_for_revalidate(dir); if (status == 0) - status = nfs_instantiate(dentry, &fhandle, &fattr); + status = nfs_instantiate(dentry, &fhandle, &fattr, fsg); dprintk("NFS reply create: %d\n", status); return status; } @@ -225,7 +233,7 @@ nfs_proc_create(struct inode *dir, struc */ 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_fh fhandle; struct nfs_fattr fattr; @@ -239,11 +247,6 @@ nfs_proc_mknod(struct inode *dir, struct .fh = &fhandle, .fattr = &fattr }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_CREATE], - .rpc_argp = &arg, - .rpc_resp = &res, - }; int status, mode; dprintk("NFS call mknod %s\n", dentry->d_name.name); @@ -258,36 +261,32 @@ nfs_proc_mknod(struct inode *dir, struct } nfs_fattr_init(&fattr); - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, fsg); nfs_mark_for_revalidate(dir); if (status == -EINVAL && S_ISFIFO(mode)) { sattr->ia_mode = mode; nfs_fattr_init(&fattr); - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, fsg); } if (status == 0) - status = nfs_instantiate(dentry, &fhandle, &fattr); + status = nfs_instantiate(dentry, &fhandle, &fattr, fsg); dprintk("NFS reply mknod: %d\n", status); return status; } 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.len = name->len, .name.name = 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); @@ -308,7 +307,8 @@ static int nfs_proc_unlink_done(struct r 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 = { .fromfh = NFS_FH(old_dir), @@ -318,14 +318,10 @@ nfs_proc_rename(struct inode *old_dir, s .toname = new_name->name, .tolen = new_name->len }; - 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); @@ -333,7 +329,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), @@ -341,14 +338,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); @@ -357,7 +350,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 fhandle; struct nfs_fattr fattr; @@ -369,10 +362,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; if (len > NFS2_MAXPATHLEN) @@ -380,7 +369,7 @@ nfs_proc_symlink(struct inode *dir, stru dprintk("NFS call symlink %s\n", dentry->d_name.name); - 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); /* @@ -391,7 +380,7 @@ nfs_proc_symlink(struct inode *dir, stru if (status == 0) { nfs_fattr_init(&fattr); fhandle.size = 0; - status = nfs_instantiate(dentry, &fhandle, &fattr); + status = nfs_instantiate(dentry, &fhandle, &fattr, fsg); } dprintk("NFS reply symlink: %d\n", status); @@ -399,7 +388,8 @@ nfs_proc_symlink(struct inode *dir, stru } 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_fh fhandle; struct nfs_fattr fattr; @@ -413,39 +403,30 @@ nfs_proc_mkdir(struct inode *dir, struct .fh = &fhandle, .fattr = &fattr }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_MKDIR], - .rpc_argp = &arg, - .rpc_resp = &res, - }; int status; dprintk("NFS call mkdir %s\n", dentry->d_name.name); nfs_fattr_init(&fattr); - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_MKDIR, &arg, &res, fsg); nfs_mark_for_revalidate(dir); if (status == 0) - status = nfs_instantiate(dentry, &fhandle, &fattr); + status = nfs_instantiate(dentry, &fhandle, &fattr, fsg); dprintk("NFS reply mkdir: %d\n", status); return status; } 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; @@ -469,15 +450,10 @@ nfs_proc_readdir(struct dentry *dentry, .count = count, .pages = &page, }; - 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); @@ -490,16 +466,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; @@ -518,16 +489,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 2008-10-25 15:18:54.000000000 +0200 +++ b/fs/nfs/unlink.c 2009-01-01 11:59:46.000000000 +0100 @@ -235,7 +235,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; diff -Nurp a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h --- a/include/linux/nfs_fs.h 2008-10-25 15:19:07.000000000 +0200 +++ b/include/linux/nfs_fs.h 2009-01-01 11:59:46.000000000 +0100 @@ -416,7 +416,8 @@ extern const struct file_operations nfs_ extern 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 2008-10-25 15:19:07.000000000 +0200 +++ b/include/linux/nfs_xdr.h 2009-01-01 11:59:46.000000000 +0100 @@ -777,7 +777,7 @@ struct nfs_write_data { struct nfs_access_entry; /* - * RPC procedure vector for NFSv2/NFSv3 demuxing + * RPC procedure vector for NFSv2/NFSv3/NFSv4 demuxing */ struct nfs_rpc_ops { u32 version; /* Protocol version */ @@ -793,28 +793,32 @@ 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, struct nameidata *); - int (*remove) (struct inode *, struct qstr *); + struct iattr *, int, struct nameidata *, + struct rpc_groups *); + int (*remove) (struct inode *, struct qstr *, struct rpc_groups *); void (*unlink_setup) (struct rpc_message *, struct inode *dir); int (*unlink_done) (struct rpc_task *, struct inode *); int (*rename) (struct inode *, struct qstr *, - struct inode *, struct qstr *); - int (*link) (struct inode *, struct inode *, struct qstr *); + struct inode *, struct qstr *, struct rpc_groups *); + 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 2008-10-07 14:02:59.000000000 +0200 +++ b/include/linux/sunrpc/auth.h 2009-01-01 11:59:46.000000000 +0100 @@ -15,17 +15,23 @@ #include #include +#include #include #include /* 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; unsigned char machine_cred : 1; }; @@ -130,7 +136,7 @@ void __init rpcauth_init_module(void); void __exit rpcauth_remove_module(void); void __exit rpc_destroy_generic_auth(void); -struct rpc_cred * rpc_lookup_cred(void); +struct rpc_cred * rpc_lookup_cred(struct rpc_groups *); struct rpc_cred * rpc_lookup_machine_cred(void); int rpcauth_register(const struct rpc_authops *); int rpcauth_unregister(const struct rpc_authops *); @@ -138,7 +144,7 @@ struct rpc_auth * rpcauth_create(rpc_aut void rpcauth_release(struct rpc_auth *); 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); void rpcauth_bindcred(struct rpc_task *, struct rpc_cred *, int); void rpcauth_generic_bind_cred(struct rpc_task *, struct rpc_cred *); void put_rpccred(struct rpc_cred *); diff -Nurp a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h --- a/include/linux/sunrpc/msg_prot.h 2008-05-03 10:25:53.000000000 +0200 +++ b/include/linux/sunrpc/msg_prot.h 2009-01-01 11:59:46.000000000 +0100 @@ -79,6 +79,7 @@ enum rpc_auth_stat { }; #define RPC_MAXNETNAMELEN 256 +#define RPC_MAXGROUPS 16 /* * From RFC 1831: diff -Nurp a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h --- a/include/linux/sunrpc/svcauth.h 2008-10-07 14:02:59.000000000 +0200 +++ b/include/linux/sunrpc/svcauth.h 2009-01-01 11:59:46.000000000 +0100 @@ -16,7 +16,6 @@ #include #include -#define SVC_CRED_NGROUPS 32 struct svc_cred { uid_t cr_uid; gid_t cr_gid; diff -Nurp a/net/sunrpc/auth.c b/net/sunrpc/auth.c --- a/net/sunrpc/auth.c 2008-10-07 14:03:02.000000000 +0200 +++ b/net/sunrpc/auth.c 2009-01-01 11:59:46.000000000 +0100 @@ -17,8 +17,11 @@ #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); + static DEFINE_SPINLOCK(rpc_authflavor_lock); static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = { &authnull_ops, /* AUTH_NULL */ @@ -348,22 +351,22 @@ 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 = { .uid = current->fsuid, - .gid = current->fsgid, - .group_info = current->group_info, }; struct rpc_cred *ret; - dprintk("RPC: looking up %s cred\n", - auth->au_ops->au_name); - get_group_info(acred.group_info); + dprintk("RPC: looking up %s cred\n", auth->au_ops->au_name); + + 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, @@ -382,6 +385,41 @@ rpcauth_init_cred(struct rpc_cred *cred, } EXPORT_SYMBOL_GPL(rpcauth_init_cred); +/* + * 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; + + acred->gid = current->fsgid; + ngroups = current->group_info ? current->group_info->ngroups : 0; + 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] = GROUP_AT(current->group_info, i); + acred->rg.ngroups = n; + } +} + void rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred) { @@ -418,7 +456,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); - ret = rpcauth_lookupcred(auth, 0); + ret = rpcauth_lookupcred(auth, NULL, 0); if (!IS_ERR(ret)) task->tk_msg.rpc_cred = ret; else diff -Nurp a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c --- a/net/sunrpc/auth_generic.c 2008-12-30 20:38:51.000000000 +0100 +++ b/net/sunrpc/auth_generic.c 2009-01-01 11:59:46.000000000 +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); @@ -89,12 +89,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 = *acred; dprintk("RPC: allocated %s cred %p for uid %d gid %d\n", gcred->acred.machine_cred ? "machine" : "generic", @@ -108,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); } @@ -133,29 +126,14 @@ 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 (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 != acred->machine_cred) - 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 (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; } void __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 2008-10-25 15:19:11.000000000 +0200 +++ b/net/sunrpc/auth_unix.c 2009-01-01 11:59:46.000000000 +0100 @@ -12,12 +12,10 @@ #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 @@ -60,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); @@ -72,16 +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++) - cred->uc_gids[i] = GROUP_AT(acred->group_info, i); - 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; } @@ -115,21 +107,12 @@ 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++) - if (cred->uc_gids[i] != GROUP_AT(acred->group_info, i)) - return 0; - return 1; + return !memcmp(cred->uc_gids, acred->rg.groups, n * sizeof (gid_t)); } /* @@ -156,7 +139,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 2008-10-07 14:03:02.000000000 +0200 +++ b/net/sunrpc/svcauth_unix.c 2009-01-01 11:59:46.000000000 +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; if (unix_gid_find(cred->cr_uid, &cred->cr_group_info, rqstp) == -EAGAIN)