diff -Nurp a/fs/nfs/dir.c b/fs/nfs/dir.c --- a/fs/nfs/dir.c 2007-07-09 19:43:44.000000000 +0200 +++ b/fs/nfs/dir.c 2007-07-09 20:25:46.000000000 +0200 @@ -760,6 +760,7 @@ static int nfs_lookup_revalidate(struct struct nfs_fh fhandle; struct nfs_fattr fattr; unsigned long verifier; + struct rpc_groups fsg; parent = dget_parent(dentry); lock_kernel(); @@ -795,7 +796,9 @@ static int nfs_lookup_revalidate(struct goto out_bad; verifier = nfs_save_change_attribute(dir); - 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)) @@ -915,6 +918,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); @@ -939,7 +943,9 @@ static struct dentry *nfs_lookup(struct goto out_unlock; } - 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) { @@ -1195,7 +1201,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 inode *inode; int error = -EACCES; @@ -1205,7 +1211,7 @@ int nfs_instantiate(struct dentry *dentr return 0; if (fhandle->size == 0) { struct inode *dir = dentry->d_parent->d_inode; - 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) return error; } @@ -1237,6 +1243,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); @@ -1249,7 +1256,7 @@ static int nfs_create(struct inode *dir, lock_kernel(); nfs_begin_data_update(dir); - error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd); + error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd, &fsg); nfs_end_data_update(dir); if (error != 0) goto out_err; @@ -1271,6 +1278,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); @@ -1283,7 +1291,7 @@ nfs_mknod(struct inode *dir, struct dent lock_kernel(); nfs_begin_data_update(dir); - status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev); + status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev, &fsg); nfs_end_data_update(dir); if (status != 0) goto out_err; @@ -1304,6 +1312,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); @@ -1313,7 +1322,7 @@ static int nfs_mkdir(struct inode *dir, lock_kernel(); nfs_begin_data_update(dir); - error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr); + error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr, &fsg); nfs_end_data_update(dir); if (error != 0) goto out_err; @@ -1330,13 +1339,14 @@ out_err: 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); lock_kernel(); nfs_begin_data_update(dir); - 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); @@ -1356,6 +1366,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, @@ -1401,12 +1412,12 @@ static int nfs_sillyrename(struct inode if (dentry->d_inode) { nfs_begin_data_update(dentry->d_inode); error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, - dir, &qsilly); + dir, &qsilly, &fsg); nfs_mark_for_revalidate(dentry->d_inode); nfs_end_data_update(dentry->d_inode); } else error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, - dir, &qsilly); + dir, &qsilly, &fsg); nfs_end_data_update(dir); if (!error) { nfs_renew_times(dentry); @@ -1431,6 +1442,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", @@ -1446,14 +1458,14 @@ static int nfs_safe_remove(struct dentry if (inode != NULL) { nfs_inode_return_delegation(inode); nfs_begin_data_update(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) drop_nlink(inode); nfs_mark_for_revalidate(inode); nfs_end_data_update(inode); } else - error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); + error = NFS_PROTO(dir)->remove(dir, &dentry->d_name, &fsg); nfs_end_data_update(dir); out: return error; @@ -1523,6 +1535,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); @@ -1548,7 +1561,7 @@ static int nfs_symlink(struct inode *dir kunmap_atomic(kaddr, KM_USER0); nfs_begin_data_update(dir); - error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr); + error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr, &fsg); nfs_end_data_update(dir); if (error != 0) { dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n", @@ -1582,6 +1595,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", @@ -1591,7 +1605,7 @@ nfs_link(struct dentry *old_dentry, stru lock_kernel(); nfs_begin_data_update(dir); nfs_begin_data_update(inode); - 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_instantiate(dentry, inode); @@ -1632,6 +1646,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; /* @@ -1704,7 +1726,7 @@ go_ahead: nfs_begin_data_update(new_dir); nfs_begin_data_update(old_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); nfs_end_data_update(old_inode); nfs_end_data_update(new_dir); @@ -1946,6 +1968,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); @@ -1993,7 +2017,12 @@ force_lookup: if (!NFS_PROTO(inode)->access) goto out_notsup; - cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); + if (NFS_PROTO(inode)->version > 3) + cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, NULL, 0); + else { + struct rpc_groups fsg = { 1, { inode->i_gid } }; + cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, &fsg, 0); + } 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 2007-07-09 19:43:44.000000000 +0200 +++ b/fs/nfs/inode.c 2007-07-09 20:25:46.000000000 +0200 @@ -323,6 +323,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); @@ -349,7 +350,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); nfs_end_data_update(inode); @@ -557,7 +562,12 @@ int nfs_open(struct inode *inode, struct struct nfs_open_context *ctx; struct rpc_cred *cred; - cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); + if (NFS_PROTO(inode)->version > 3) + cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, NULL, 0); + else { + struct rpc_groups fsg = { 1, { inode->i_gid } }; + cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, &fsg, 0); + } 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 2007-05-12 21:28:09.000000000 +0200 +++ b/fs/nfs/namespace.c 2007-07-09 20:25:46.000000000 +0200 @@ -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->dentry); + fsg.ngroups = 1; + fsg.groups[0] = parent->d_inode->i_gid; err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &nd->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 2007-07-09 19:43:44.000000000 +0200 +++ b/fs/nfs/nfs3proc.c 2007-07-09 20:25:46.000000000 +0200 @@ -25,13 +25,21 @@ /* 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) { - sigset_t oldset; - int res; + struct rpc_message msg = { + .rpc_proc = &nfs3_procedures[proc], + .rpc_argp = argp, + .rpc_resp = resp, + .rpc_cred = cred, + }; + sigset_t oldset; + int res; + rpc_clnt_sigmask(clnt, &oldset); do { - res = rpc_call_sync(clnt, msg, flags); + res = rpc_call_sync(clnt, &msg, flags); if (res != -EJUKEBOX) break; schedule_timeout_interruptible(NFS_JUKEBOX_RETRY_TIME); @@ -41,7 +49,19 @@ 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; + + if ((cred = rpcauth_lookupcred(clnt->cl_auth, fsg, 0)) == NULL) + return -ENOMEM; + 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) @@ -59,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", __FUNCTION__); 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", __FUNCTION__, 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", __FUNCTION__, status); } return status; @@ -101,39 +114,29 @@ 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; dprintk("NFS call setattr\n"); nfs_fattr_init(fattr); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); + status = nfs3_rpc(NFS_CLIENT(inode), NFS3PROC_SETATTR, &arg, fattr, fsg); if (status == 0) nfs_setattr_update_inode(inode, sattr); dprintk("NFS reply setattr: %d\n", status); @@ -142,7 +145,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 = { @@ -155,22 +159,15 @@ 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); 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); if (status >= 0) @@ -187,12 +184,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; @@ -212,7 +203,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; @@ -237,16 +229,11 @@ 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; @@ -258,7 +245,7 @@ static int nfs3_proc_readlink(struct ino */ 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 nfs_fh fhandle; struct nfs_fattr fattr; @@ -274,11 +261,6 @@ nfs3_proc_create(struct inode *dir, stru .fh = &fhandle, .fattr = &fattr }; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_CREATE], - .rpc_argp = &arg, - .rpc_resp = &res, - }; mode_t mode = sattr->ia_mode; int status; @@ -295,7 +277,7 @@ nfs3_proc_create(struct inode *dir, stru again: 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_CREATE, &arg, &res, fsg); nfs_refresh_inode(dir, &dir_attr); /* If the server doesn't support the exclusive creation semantics, @@ -317,7 +299,7 @@ again: } if (status == 0) - status = nfs_instantiate(dentry, &fhandle, &fattr); + status = nfs_instantiate(dentry, &fhandle, &fattr, fsg); if (status != 0) goto out; @@ -334,7 +316,7 @@ again: /* 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, &fattr, sattr); + status = nfs3_proc_setattr(dentry, &fattr, sattr, NULL); if (status == 0) nfs_setattr_update_inode(dentry->d_inode, sattr); nfs_refresh_inode(dentry->d_inode, &fattr); @@ -349,7 +331,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_fattr dir_attr; struct nfs3_diropargs arg = { @@ -357,16 +339,11 @@ nfs3_proc_remove(struct inode *dir, stru .name = name->name, .len = name->len }; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE], - .rpc_argp = &arg, - .rpc_resp = &dir_attr, - }; int status; dprintk("NFS call remove %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_REMOVE, &arg, &dir_attr, fsg); nfs_post_op_update_inode(dir, &dir_attr); dprintk("NFS reply remove: %d\n", status); return status; @@ -411,7 +388,8 @@ nfs3_proc_unlink_done(struct dentry *dir 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 = { @@ -426,17 +404,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); @@ -444,7 +417,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 = { @@ -457,17 +431,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); @@ -476,7 +445,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 nfs_fh fhandle; struct nfs_fattr fattr, dir_attr; @@ -493,11 +462,6 @@ nfs3_proc_symlink(struct inode *dir, str .fh = &fhandle, .fattr = &fattr }; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK], - .rpc_argp = &arg, - .rpc_resp = &res, - }; int status; if (len > NFS3_MAXPATHLEN) @@ -507,18 +471,19 @@ nfs3_proc_symlink(struct inode *dir, str 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_SYMLINK, &arg, &res, fsg); nfs_post_op_update_inode(dir, &dir_attr); if (status != 0) goto out; - status = nfs_instantiate(dentry, &fhandle, &fattr); + status = nfs_instantiate(dentry, &fhandle, &fattr, fsg); out: dprintk("NFS reply symlink: %d\n", status); return status; } 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 nfs_fh fhandle; struct nfs_fattr fattr, dir_attr; @@ -533,11 +498,6 @@ nfs3_proc_mkdir(struct inode *dir, struc .fh = &fhandle, .fattr = &fattr }; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR], - .rpc_argp = &arg, - .rpc_resp = &res, - }; int mode = sattr->ia_mode; int status; @@ -547,11 +507,11 @@ nfs3_proc_mkdir(struct inode *dir, struc 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_MKDIR, &arg, &res, fsg); nfs_post_op_update_inode(dir, &dir_attr); if (status != 0) goto out; - status = nfs_instantiate(dentry, &fhandle, &fattr); + status = nfs_instantiate(dentry, &fhandle, &fattr, fsg); if (status != 0) goto out; status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); @@ -561,7 +521,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 = { @@ -569,16 +529,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; @@ -613,22 +568,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_refresh_inode(dir, &dir_attr); dprintk("NFS reply readdir: %d\n", status); return status; @@ -636,7 +586,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 nfs_fh fh; struct nfs_fattr fattr, dir_attr; @@ -652,11 +602,6 @@ nfs3_proc_mknod(struct inode *dir, struc .fh = &fh, .fattr = &fattr }; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD], - .rpc_argp = &arg, - .rpc_resp = &res, - }; mode_t mode = sattr->ia_mode; int status; @@ -675,11 +620,11 @@ nfs3_proc_mknod(struct inode *dir, struc 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_MKNOD, &arg, &res, fsg); nfs_post_op_update_inode(dir, &dir_attr); if (status != 0) goto out; - status = nfs_instantiate(dentry, &fh, &fattr); + status = nfs_instantiate(dentry, &fh, &fattr, fsg); if (status != 0) goto out; status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode); @@ -692,16 +637,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; } @@ -710,16 +650,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; } @@ -728,16 +663,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 2007-07-09 19:43:44.000000000 +0200 +++ b/fs/nfs/nfs4proc.c 2007-07-09 20:25:46.000000000 +0200 @@ -1274,7 +1274,7 @@ nfs4_atomic_open(struct inode *dir, stru BUG_ON(nd->intent.open.flags & O_CREAT); } - cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); + cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, NULL, 0); if (IS_ERR(cred)) return (struct dentry *)cred; state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); @@ -1297,7 +1297,7 @@ nfs4_open_revalidate(struct inode *dir, struct rpc_cred *cred; struct nfs4_state *state; - cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); + cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, NULL, 0); if (IS_ERR(cred)) return PTR_ERR(cred); state = nfs4_open_delegated(dentry->d_inode, openflags, cred); @@ -1505,7 +1505,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 rpc_cred *cred; struct inode *inode = dentry->d_inode; @@ -1515,7 +1515,7 @@ nfs4_proc_setattr(struct dentry *dentry, nfs_fattr_init(fattr); - cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); + cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, NULL, 0); if (IS_ERR(cred)) return PTR_ERR(cred); @@ -1610,7 +1610,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; @@ -1750,13 +1752,13 @@ 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 nfs4_state *state; struct rpc_cred *cred; int status = 0; - cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); + cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, NULL, 0); if (IS_ERR(cred)) { status = PTR_ERR(cred); goto out; @@ -1811,7 +1813,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; @@ -1905,7 +1908,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; @@ -1952,7 +1956,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; @@ -2003,13 +2008,14 @@ static int _nfs4_proc_symlink(struct ino if (!status) { update_changeattr(dir, &res.dir_cinfo); nfs_post_op_update_inode(dir, res.dir_fattr); - status = nfs_instantiate(dentry, &fhandle, &fattr); + status = nfs_instantiate(dentry, &fhandle, &fattr, NULL); } return status; } 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; @@ -2056,13 +2062,13 @@ static int _nfs4_proc_mkdir(struct inode if (!status) { update_changeattr(dir, &res.dir_cinfo); nfs_post_op_update_inode(dir, res.dir_fattr); - status = nfs_instantiate(dentry, &fhandle, &fattr); + status = nfs_instantiate(dentry, &fhandle, &fattr, NULL); } return status; } 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; @@ -2172,13 +2178,13 @@ static int _nfs4_proc_mknod(struct inode if (status == 0) { update_changeattr(dir, &res.dir_cinfo); nfs_post_op_update_inode(dir, res.dir_fattr); - status = nfs_instantiate(dentry, &fh, &fattr); + status = nfs_instantiate(dentry, &fh, &fattr, NULL); } return status; } 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 2007-07-09 19:43:44.000000000 +0200 +++ b/fs/nfs/proc.c 2007-07-09 20:25:46.000000000 +0200 @@ -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,33 @@ #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; + + if ((cred = rpcauth_lookupcred(clnt->cl_auth, fsg, 0)) == NULL) + return -ENOMEM; + 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 +83,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", __FUNCTION__); 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", __FUNCTION__, status); if (status) return status; dprintk("%s: call statfs\n", __FUNCTION__); - 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", __FUNCTION__, status); if (status) return status; @@ -95,34 +115,24 @@ 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; /* Mask out the non-modebit related stuff from attr->ia_mode */ @@ -130,7 +140,7 @@ nfs_proc_setattr(struct dentry *dentry, dprintk("NFS call setattr\n"); nfs_fattr_init(fattr); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, fsg); if (status == 0) nfs_setattr_update_inode(inode, sattr); dprintk("NFS reply setattr: %d\n", status); @@ -139,7 +149,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), @@ -150,16 +161,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; } @@ -173,21 +179,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; @@ -201,18 +203,13 @@ 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); 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; } @@ -222,7 +219,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; @@ -236,11 +233,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); @@ -255,36 +247,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_diropargs arg = { .fh = NFS_FH(dir), .name = name->name, .len = name->len }; - 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); @@ -321,7 +309,8 @@ nfs_proc_unlink_done(struct dentry *dir, 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), @@ -331,14 +320,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); @@ -346,7 +331,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), @@ -354,14 +340,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); @@ -370,7 +352,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; @@ -382,10 +364,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) @@ -393,7 +371,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); /* @@ -404,7 +382,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); @@ -412,7 +390,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; @@ -426,39 +405,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; @@ -482,15 +452,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); dprintk("NFS reply readdir: %d\n", status); return status; @@ -501,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; @@ -529,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 2006-08-28 21:16:14.000000000 +0200 +++ b/fs/nfs/unlink.c 2007-07-09 20:25:46.000000000 +0200 @@ -167,7 +167,12 @@ nfs_async_unlink(struct dentry *dentry) if (!data) goto out; - data->cred = rpcauth_lookupcred(clnt->cl_auth, 0); + if (NFS_PROTO(dir->d_inode)->version > 3) + data->cred = rpcauth_lookupcred(clnt->cl_auth, NULL, 0); + else { + struct rpc_groups fsg = { 1, { dir->d_inode->i_gid } }; + data->cred = rpcauth_lookupcred(clnt->cl_auth, &fsg, 0); + } if (IS_ERR(data->cred)) { status = PTR_ERR(data->cred); goto out_free; diff -Nurp a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c --- a/fs/nfsd/nfs4callback.c 2007-07-09 19:43:44.000000000 +0200 +++ b/fs/nfsd/nfs4callback.c 2007-07-09 20:25:46.000000000 +0200 @@ -351,17 +351,18 @@ nfsd4_lookupcred(struct nfs4_client *clp { struct auth_cred acred; struct rpc_clnt *clnt = clp->cl_callback.cb_client; + struct svc_cred *cr = &clp->cl_cred; struct rpc_cred *ret; - get_group_info(clp->cl_cred.cr_group_info); - acred.uid = clp->cl_cred.cr_uid; - acred.gid = clp->cl_cred.cr_gid; - acred.group_info = clp->cl_cred.cr_group_info; - dprintk("NFSD: looking up %s cred\n", clnt->cl_auth->au_ops->au_name); + + acred.uid = cr->cr_uid; + if (clnt->cl_auth->au_ops->cr_add_groups) + clnt->cl_auth->au_ops->cr_add_groups(&acred, cr->cr_gid, cr->cr_group_info, NULL); ret = rpcauth_lookup_credcache(clnt->cl_auth, &acred, taskflags); - put_group_info(clp->cl_cred.cr_group_info); + + dprintk("NFSD: cred %p\n", ret); return ret; } diff -Nurp a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h --- a/include/linux/nfs_fs.h 2007-07-09 19:43:50.000000000 +0200 +++ b/include/linux/nfs_fs.h 2007-07-09 20:25:46.000000000 +0200 @@ -379,7 +379,8 @@ extern const struct inode_operations nfs extern const struct file_operations nfs_dir_operations; extern struct dentry_operations nfs_dentry_operations; -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); /* * linux/fs/nfs/symlink.c diff -Nurp a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h --- a/include/linux/nfs_xdr.h 2007-05-12 21:28:14.000000000 +0200 +++ b/include/linux/nfs_xdr.h 2007-07-09 20:25:46.000000000 +0200 @@ -762,7 +762,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 { int version; /* Protocol version */ @@ -778,29 +778,33 @@ 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 *); int (*unlink_setup) (struct rpc_message *, struct dentry *, struct qstr *); int (*unlink_done) (struct dentry *, struct rpc_task *); 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 2006-12-03 13:23:00.000000000 +0100 +++ b/include/linux/sunrpc/auth.h 2007-07-09 20:25:46.000000000 +0200 @@ -15,16 +15,22 @@ #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; + uid_t uid; + gid_t gid; + struct rpc_groups rg; }; /* @@ -98,6 +104,7 @@ struct rpc_authops { struct rpc_cred * (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int); struct rpc_cred * (*crcreate)(struct rpc_auth*, struct auth_cred *, int); + void (*cr_add_groups)(struct auth_cred *, gid_t, struct group_info *, struct rpc_groups *); }; struct rpc_credops { @@ -126,11 +133,8 @@ int rpcauth_unregister(struct rpc_auth struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *); void rpcauth_destroy(struct rpc_auth *); struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); -struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); -struct rpc_cred * rpcauth_bindcred(struct rpc_task *); -void rpcauth_holdcred(struct rpc_task *); +struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, struct rpc_groups *, int); void put_rpccred(struct rpc_cred *); -void rpcauth_unbindcred(struct rpc_task *); __be32 * rpcauth_marshcred(struct rpc_task *, __be32 *); __be32 * rpcauth_checkverf(struct rpc_task *, __be32 *); int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, __be32 *data, void *obj); diff -Nurp a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h --- a/include/linux/sunrpc/msg_prot.h 2007-07-09 19:43:50.000000000 +0200 +++ b/include/linux/sunrpc/msg_prot.h 2007-07-09 20:25:46.000000000 +0200 @@ -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 2006-12-03 13:23:00.000000000 +0100 +++ b/include/linux/sunrpc/svcauth.h 2007-07-09 20:25:46.000000000 +0200 @@ -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 2007-05-12 21:28:21.000000000 +0200 +++ b/net/sunrpc/auth.c 2007-07-09 20:25:46.000000000 +0200 @@ -254,61 +254,25 @@ retry: } } - return (struct rpc_cred *) cred; + return cred; } 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); - ret = auth->au_ops->lookup_cred(auth, &acred, flags); - put_group_info(acred.group_info); - return ret; -} - -struct rpc_cred * -rpcauth_bindcred(struct rpc_task *task) -{ - struct rpc_auth *auth = task->tk_auth; - struct auth_cred acred = { - .uid = current->fsuid, - .gid = current->fsgid, - .group_info = current->group_info, - }; - struct rpc_cred *ret; - int flags = 0; + dprintk("RPC: looking up %s cred\n", auth->au_ops->au_name); - dprintk("RPC: %5u looking up %s cred\n", - task->tk_pid, task->tk_auth->au_ops->au_name); - get_group_info(acred.group_info); - if (task->tk_flags & RPC_TASK_ROOTCREDS) - flags |= RPCAUTH_LOOKUP_ROOTCREDS; + if (auth->au_ops->cr_add_groups) + auth->au_ops->cr_add_groups(&acred, current->fsgid, current->group_info, rg); ret = auth->au_ops->lookup_cred(auth, &acred, flags); - if (!IS_ERR(ret)) - task->tk_msg.rpc_cred = ret; - else - task->tk_status = PTR_ERR(ret); - put_group_info(acred.group_info); - return ret; -} -void -rpcauth_holdcred(struct rpc_task *task) -{ - dprintk("RPC: %5u holding %s cred %p\n", - task->tk_pid, task->tk_auth->au_ops->au_name, - task->tk_msg.rpc_cred); - if (task->tk_msg.rpc_cred) - get_rpccred(task->tk_msg.rpc_cred); + dprintk("RPC: cred %p\n", ret); + return ret; } void @@ -320,18 +284,6 @@ put_rpccred(struct rpc_cred *cred) cred->cr_ops->crdestroy(cred); } -void -rpcauth_unbindcred(struct rpc_task *task) -{ - struct rpc_cred *cred = task->tk_msg.rpc_cred; - - dprintk("RPC: %5u releasing %s cred %p\n", - task->tk_pid, task->tk_auth->au_ops->au_name, cred); - - put_rpccred(cred); - task->tk_msg.rpc_cred = NULL; -} - __be32 * rpcauth_marshcred(struct rpc_task *task, __be32 *p) { diff -Nurp a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c --- a/net/sunrpc/auth_gss/auth_gss.c 2007-05-12 21:28:21.000000000 +0200 +++ b/net/sunrpc/auth_gss/auth_gss.c 2007-07-09 20:25:46.000000000 +0200 @@ -62,8 +62,6 @@ static struct rpc_credops gss_credops; # define RPCDBG_FACILITY RPCDBG_AUTH #endif -#define NFS_NGROUPS 16 - #define GSS_CRED_EXPIRE (60 * HZ) /* XXX: reasonable? */ #define GSS_CRED_SLACK 1024 /* XXX: unused */ /* length of a krb5 verifier (48), plus data added before arguments when diff -Nurp a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c --- a/net/sunrpc/auth_unix.c 2007-05-12 21:28:21.000000000 +0200 +++ b/net/sunrpc/auth_unix.c 2007-07-09 20:25:46.000000000 +0200 @@ -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 #define uc_count uc_base.cr_count @@ -30,6 +28,7 @@ struct unx_cred { #ifdef RPC_DEBUG # define RPCDBG_FACILITY RPCDBG_AUTH +# define RG(rg,i) ((i) < (rg).ngroups ? (int)(rg).groups[i] : -1) #endif static struct rpc_auth unix_auth; @@ -66,7 +65,6 @@ static struct rpc_cred * unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) { struct unx_cred *cred; - int i; dprintk("RPC: allocating UNIX cred for uid %d gid %d\n", acred->uid, acred->gid); @@ -81,22 +79,54 @@ unx_create_cred(struct rpc_auth *auth, s cred->uc_gid = 0; cred->uc_gids[0] = NOGROUP; } else { - int groups = acred->group_info->ngroups; - if (groups > NFS_NGROUPS) - groups = NFS_NGROUPS; - + int n = acred->rg.ngroups; cred->uc_uid = acred->uid; 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; } cred->uc_base.cr_ops = &unix_credops; return (struct rpc_cred *) cred; } +/* + * Add 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 +unx_add_groups(struct auth_cred *acred, gid_t gid, struct group_info *gi, struct rpc_groups *rg) +{ + int i, n; + + acred->gid = gid; + get_group_info(gi); + n = gi->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: unx_add_groups(): rg=%d:%d,%d,%d -> %d:%d,%d,%d\n", + 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: unx_add_groups(): ngroups=%d\n", gi->ngroups); + for (i = 0; i < n; ++i) + acred->rg.groups[i] = GROUP_AT(gi, i); + acred->rg.ngroups = n; + } + put_group_info(gi); +} + static void unx_destroy_cred(struct rpc_cred *cred) { @@ -112,22 +142,19 @@ static int unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags) { struct unx_cred *cred = (struct unx_cred *) rcred; - int i; if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) { - int groups; + int n = acred->rg.ngroups; if (cred->uc_uid != acred->uid || cred->uc_gid != acred->gid) return 0; - 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; + if (n < RPC_MAXGROUPS && cred->uc_gids[n] != NOGROUP) + return 0; + + return !memcmp(cred->uc_gids, acred->rg.groups, + n * sizeof (gid_t)); } return (cred->uc_uid == 0 && cred->uc_gid == 0 @@ -158,7 +185,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 */ @@ -214,6 +241,7 @@ struct rpc_authops authunix_ops = { .destroy = unx_destroy, .lookup_cred = unx_lookup_cred, .crcreate = unx_create_cred, + .cr_add_groups = unx_add_groups, }; static diff -Nurp a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c --- a/net/sunrpc/clnt.c 2007-07-09 19:43:54.000000000 +0200 +++ b/net/sunrpc/clnt.c 2007-07-09 20:25:46.000000000 +0200 @@ -548,13 +548,22 @@ out_release: void rpc_call_setup(struct rpc_task *task, struct rpc_message *msg, int flags) { + struct rpc_cred *cred; + task->tk_msg = *msg; - task->tk_flags |= flags; - /* Bind the user cred */ - if (task->tk_msg.rpc_cred != NULL) - rpcauth_holdcred(task); - else - rpcauth_bindcred(task); + + if (task->tk_msg.rpc_cred) { + /* we copied msg->rpc_cred, hold it */ + get_rpccred(task->tk_msg.rpc_cred); + } else { + if (task->tk_flags & RPC_TASK_ROOTCREDS) + flags |= RPCAUTH_LOOKUP_ROOTCREDS; + cred = rpcauth_lookupcred(task->tk_auth, NULL, flags); + if (!IS_ERR(cred)) + task->tk_msg.rpc_cred = cred; + else + task->tk_status = PTR_ERR(cred); + } if (task->tk_status == 0) task->tk_action = call_start; diff -Nurp a/net/sunrpc/sched.c b/net/sunrpc/sched.c --- a/net/sunrpc/sched.c 2007-07-09 19:43:54.000000000 +0200 +++ b/net/sunrpc/sched.c 2007-07-09 20:25:46.000000000 +0200 @@ -901,8 +901,10 @@ void rpc_put_task(struct rpc_task *task) /* Release resources */ if (task->tk_rqstp) xprt_release(task); - if (task->tk_msg.rpc_cred) - rpcauth_unbindcred(task); + if (task->tk_msg.rpc_cred) { + put_rpccred(task->tk_msg.rpc_cred); + task->tk_msg.rpc_cred = NULL; + } if (task->tk_client) { rpc_release_client(task->tk_client); task->tk_client = NULL; diff -Nurp a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c --- a/net/sunrpc/svcauth_unix.c 2007-07-09 19:43:54.000000000 +0200 +++ b/net/sunrpc/svcauth_unix.c 2007-07-09 20:25:46.000000000 +0200 @@ -760,7 +760,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)