diff -Nurp a/fs/nfs/dir.c b/fs/nfs/dir.c --- a/fs/nfs/dir.c 2006-10-22 11:41:08.000000000 +0200 +++ b/fs/nfs/dir.c 2006-10-22 11:50:33.000000000 +0200 @@ -737,6 +737,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(); @@ -772,7 +773,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)) @@ -888,6 +891,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); @@ -906,7 +910,9 @@ static struct dentry *nfs_lookup(struct if (nfs_is_exclusive_create(dir, nd)) goto no_entry; - 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) { @@ -1131,7 +1137,7 @@ static struct dentry *nfs_readdir_lookup * 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; @@ -1141,7 +1147,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) goto out_err; } @@ -1174,6 +1180,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); @@ -1186,7 +1193,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; @@ -1208,6 +1215,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); @@ -1220,7 +1228,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; @@ -1241,6 +1249,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); @@ -1250,7 +1259,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; @@ -1267,13 +1276,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) dentry->d_inode->i_nlink = 0; @@ -1293,6 +1303,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, @@ -1343,12 +1354,12 @@ dentry->d_parent->d_name.name, dentry->d 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); @@ -1373,6 +1384,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", @@ -1388,14 +1400,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) inode->i_nlink--; 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; @@ -1448,6 +1460,7 @@ nfs_symlink(struct inode *dir, struct de struct nfs_fh sym_fh; struct qstr qsymname; 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); @@ -1470,10 +1483,10 @@ dentry->d_parent->d_name.name, dentry->d lock_kernel(); nfs_begin_data_update(dir); error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname, - &attr, &sym_fh, &sym_attr); + &attr, &sym_fh, &sym_attr, &fsg); nfs_end_data_update(dir); if (!error) { - error = nfs_instantiate(dentry, &sym_fh, &sym_attr); + error = nfs_instantiate(dentry, &sym_fh, &sym_attr, &fsg); } else { if (error == -EEXIST) printk("nfs_proc_symlink: %s/%s already exists??\n", @@ -1488,6 +1501,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", @@ -1497,7 +1511,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); @@ -1538,6 +1552,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; /* @@ -1616,7 +1638,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); @@ -1683,6 +1705,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); @@ -1730,7 +1754,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 2006-10-22 11:41:08.000000000 +0200 +++ b/fs/nfs/inode.c 2006-10-22 11:50:33.000000000 +0200 @@ -315,6 +315,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); @@ -339,7 +340,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); @@ -546,7 +551,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_vfsmnt, filp->f_dentry, cred); diff -Nurp a/fs/nfs/namespace.c b/fs/nfs/namespace.c --- a/fs/nfs/namespace.c 2006-10-22 11:41:08.000000000 +0200 +++ b/fs/nfs/namespace.c 2006-10-22 13:47:46.000000000 +0200 @@ -94,6 +94,7 @@ static void * nfs_follow_mountpoint(stru struct dentry *parent; struct nfs_fh fh; struct nfs_fattr fattr; + struct rpc_groups fsg; int err; BUG_ON(IS_ROOT(dentry)); @@ -104,7 +105,9 @@ static void * nfs_follow_mountpoint(stru goto out_follow; /* Look it up again */ parent = dget_parent(nd->dentry); - err = server->rpc_ops->lookup(parent->d_inode, &nd->dentry->d_name, &fh, &fattr); + fsg.ngroups = 1; + fsg.groups[0] = parent->d_inode->i_gid; + err = server->rpc_ops->lookup(parent->d_inode, &nd->dentry->d_name, &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 2006-10-22 11:41:08.000000000 +0200 +++ b/fs/nfs/nfs3proc.c 2006-10-22 11:50:33.000000000 +0200 @@ -26,13 +26,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); @@ -42,7 +50,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) @@ -60,21 +80,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; @@ -102,39 +115,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); @@ -143,7 +146,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 = { @@ -156,22 +160,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) @@ -188,12 +185,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; @@ -213,7 +204,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; @@ -238,16 +230,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,18 +245,13 @@ static int nfs3_proc_read(struct nfs_rea int flags = rdata->flags; struct inode * inode = rdata->inode; struct nfs_fattr * fattr = rdata->res.fattr; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_READ], - .rpc_argp = &rdata->args, - .rpc_resp = &rdata->res, - .rpc_cred = rdata->cred, - }; int status; dprintk("NFS call read %d @ %Ld\n", rdata->args.count, (long long) rdata->args.offset); nfs_fattr_init(fattr); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); + status = nfs3_rpc_call(NFS_CLIENT(inode), NFS3PROC_READ, + &rdata->args, &rdata->res, rdata->cred, flags); if (status >= 0) nfs_refresh_inode(inode, fattr); dprintk("NFS reply read: %d\n", status); @@ -281,18 +263,13 @@ static int nfs3_proc_write(struct nfs_wr int rpcflags = wdata->flags; struct inode * inode = wdata->inode; struct nfs_fattr * fattr = wdata->res.fattr; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_WRITE], - .rpc_argp = &wdata->args, - .rpc_resp = &wdata->res, - .rpc_cred = wdata->cred, - }; int status; dprintk("NFS call write %d @ %Ld\n", wdata->args.count, (long long) wdata->args.offset); nfs_fattr_init(fattr); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags); + status = nfs3_rpc_call(NFS_CLIENT(inode), NFS3PROC_WRITE, + &wdata->args, &wdata->res, wdata->cred, rpcflags); if (status >= 0) nfs_post_op_update_inode(inode, fattr); dprintk("NFS reply write: %d\n", status); @@ -303,18 +280,13 @@ static int nfs3_proc_commit(struct nfs_w { struct inode * inode = cdata->inode; struct nfs_fattr * fattr = cdata->res.fattr; - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT], - .rpc_argp = &cdata->args, - .rpc_resp = &cdata->res, - .rpc_cred = cdata->cred, - }; int status; dprintk("NFS call commit %d @ %Ld\n", cdata->args.count, (long long) cdata->args.offset); nfs_fattr_init(fattr); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); + status = nfs3_rpc_call(NFS_CLIENT(inode), NFS3PROC_COMMIT, + &cdata->args, &cdata->res, cdata->cred, 0); if (status >= 0) nfs_post_op_update_inode(inode, fattr); dprintk("NFS reply commit: %d\n", status); @@ -327,7 +299,7 @@ static int nfs3_proc_commit(struct nfs_w */ 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; @@ -343,11 +315,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; @@ -364,7 +331,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, @@ -386,7 +353,7 @@ again: } if (status == 0) - status = nfs_instantiate(dentry, &fhandle, &fattr); + status = nfs_instantiate(dentry, &fhandle, &fattr, fsg); if (status != 0) goto out; @@ -403,7 +370,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); @@ -418,7 +385,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 = { @@ -426,16 +393,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; @@ -480,7 +442,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 = { @@ -495,17 +458,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); @@ -513,7 +471,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 = { @@ -526,17 +485,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); @@ -546,7 +500,7 @@ nfs3_proc_link(struct inode *inode, stru static int nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, - struct nfs_fattr *fattr) + struct nfs_fattr *fattr, struct rpc_groups *fsg) { struct nfs_fattr dir_attr; struct nfs3_symlinkargs arg = { @@ -562,11 +516,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 (path->len > NFS3_MAXPATHLEN) @@ -574,14 +523,15 @@ nfs3_proc_symlink(struct inode *dir, str dprintk("NFS call symlink %s -> %s\n", name->name, path->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_SYMLINK, &arg, &res, fsg); nfs_post_op_update_inode(dir, &dir_attr); 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; @@ -596,11 +546,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; @@ -610,11 +555,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); @@ -624,7 +569,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 = { @@ -632,16 +577,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; @@ -676,24 +616,19 @@ 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; lock_kernel(); 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); unlock_kernel(); @@ -702,7 +637,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; @@ -718,11 +653,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; @@ -741,11 +671,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); @@ -758,16 +688,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; } @@ -776,16 +701,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->client_sys, &msg, 0); + status = nfs3_rpc(server->client_sys, NFS3PROC_FSINFO, fhandle, info, NULL); dprintk("NFS reply fsinfo: %d\n", status); return status; } @@ -794,16 +714,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 2006-10-22 11:41:08.000000000 +0200 +++ b/fs/nfs/nfs4proc.c 2006-10-22 11:50:33.000000000 +0200 @@ -1268,7 +1268,7 @@ nfs4_atomic_open(struct inode *dir, stru BUG_ON(nd->intent.open.flags & O_CREAT); } - cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); + cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, NULL, 0); if (IS_ERR(cred)) return (struct dentry *)cred; state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); @@ -1291,7 +1291,7 @@ nfs4_open_revalidate(struct inode *dir, struct rpc_cred *cred; struct nfs4_state *state; - cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); + cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, NULL, 0); if (IS_ERR(cred)) return PTR_ERR(cred); state = nfs4_open_delegated(dentry->d_inode, openflags, cred); @@ -1555,7 +1555,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; @@ -1565,7 +1565,7 @@ nfs4_proc_setattr(struct dentry *dentry, nfs_fattr_init(fattr); - cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); + cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, NULL, 0); if (IS_ERR(cred)) return PTR_ERR(cred); @@ -1614,7 +1614,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; @@ -1875,13 +1877,13 @@ static int nfs4_proc_commit(struct nfs_w 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_SERVER(dir)->client->cl_auth, 0); + cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, NULL, 0); if (IS_ERR(cred)) { status = PTR_ERR(cred); goto out; @@ -1936,7 +1938,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; @@ -2030,7 +2033,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; @@ -2077,7 +2081,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; @@ -2131,7 +2136,7 @@ static int _nfs4_proc_symlink(struct ino static int nfs4_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, - struct nfs_fattr *fattr) + struct nfs_fattr *fattr, struct rpc_groups *fsg) { struct nfs4_exception exception = { }; int err; @@ -2178,13 +2183,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; @@ -2296,13 +2301,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 2006-10-22 11:41:08.000000000 +0200 +++ b/fs/nfs/proc.c 2006-10-22 11:50:33.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. @@ -48,6 +48,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. */ @@ -57,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", __FUNCTION__); nfs_fattr_init(fattr); - status = rpc_call_sync(server->client_sys, &msg, 0); + status = nfs2_rpc(server->client_sys, 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->client_sys, &msg, 0); + status = nfs2_rpc(server->client_sys, NFSPROC_STATFS, fhandle, &fsinfo, NULL); dprintk("%s: reply statfs: %d\n", __FUNCTION__, status); if (status) return status; @@ -96,34 +116,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 */ @@ -131,7 +141,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); @@ -140,7 +150,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), @@ -151,16 +162,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; } @@ -174,14 +180,10 @@ static int nfs_proc_readlink(struct inod .pglen = pglen, .pages = &page }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_READLINK], - .rpc_argp = &args, - }; int status; dprintk("NFS call readlink\n"); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); + status = nfs2_rpc(NFS_CLIENT(inode), NFSPROC_READLINK, &args, NULL, NULL); dprintk("NFS reply readlink: %d\n", status); return status; } @@ -191,18 +193,13 @@ static int nfs_proc_read(struct nfs_read int flags = rdata->flags; struct inode * inode = rdata->inode; struct nfs_fattr * fattr = rdata->res.fattr; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_READ], - .rpc_argp = &rdata->args, - .rpc_resp = &rdata->res, - .rpc_cred = rdata->cred, - }; int status; dprintk("NFS call read %d @ %Ld\n", rdata->args.count, (long long) rdata->args.offset); nfs_fattr_init(fattr); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); + status = nfs2_rpc_call(NFS_CLIENT(inode), NFSPROC_READ, &rdata->args, + &rdata->res, rdata->cred, flags); if (status >= 0) { nfs_refresh_inode(inode, fattr); /* Emulate the eof flag, which isn't normally needed in NFSv2 @@ -220,18 +217,13 @@ static int nfs_proc_write(struct nfs_wri int flags = wdata->flags; struct inode * inode = wdata->inode; struct nfs_fattr * fattr = wdata->res.fattr; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_WRITE], - .rpc_argp = &wdata->args, - .rpc_resp = &wdata->res, - .rpc_cred = wdata->cred, - }; int status; dprintk("NFS call write %d @ %Ld\n", wdata->args.count, (long long) wdata->args.offset); nfs_fattr_init(fattr); - status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); + status = nfs2_rpc_call(NFS_CLIENT(inode), NFSPROC_WRITE, &wdata->args, + &wdata->res, wdata->cred, flags); if (status >= 0) { nfs_post_op_update_inode(inode, fattr); wdata->res.count = wdata->args.count; @@ -243,7 +235,7 @@ static int nfs_proc_write(struct nfs_wri 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; @@ -257,18 +249,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; } @@ -278,7 +265,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; @@ -292,11 +279,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); @@ -311,36 +293,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); @@ -377,7 +355,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), @@ -387,14 +366,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); @@ -402,7 +377,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), @@ -410,14 +386,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); @@ -427,7 +399,7 @@ nfs_proc_link(struct inode *inode, struc static int nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, - struct nfs_fattr *fattr) + struct nfs_fattr *fattr, struct rpc_groups *fsg) { struct nfs_symlinkargs arg = { .fromfh = NFS_FH(dir), @@ -437,10 +409,6 @@ nfs_proc_symlink(struct inode *dir, stru .tolen = path->len, .sattr = sattr }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_SYMLINK], - .rpc_argp = &arg, - }; int status; if (path->len > NFS2_MAXPATHLEN) @@ -448,14 +416,15 @@ nfs_proc_symlink(struct inode *dir, stru dprintk("NFS call symlink %s -> %s\n", name->name, path->name); nfs_fattr_init(fattr); fhandle->size = 0; - 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); dprintk("NFS reply symlink: %d\n", status); return status; } 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; @@ -469,39 +438,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; @@ -525,17 +485,12 @@ 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; lock_kernel(); 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); unlock_kernel(); @@ -547,16 +502,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; @@ -575,16 +525,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 2006-10-22 11:50:33.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 2006-10-22 11:41:08.000000000 +0200 +++ b/fs/nfsd/nfs4callback.c 2006-10-22 11:50:33.000000000 +0200 @@ -353,17 +353,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 2006-10-22 11:41:15.000000000 +0200 +++ b/include/linux/nfs_fs.h 2006-10-22 11:50:33.000000000 +0200 @@ -383,7 +383,8 @@ extern struct inode_operations nfs3_dir_ 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 2006-10-22 11:41:15.000000000 +0200 +++ b/include/linux/nfs_xdr.h 2006-10-22 11:50:33.000000000 +0200 @@ -760,7 +760,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 */ @@ -773,9 +773,9 @@ struct nfs_rpc_ops { int (*getattr) (struct nfs_server *, struct nfs_fh *, struct nfs_fattr *); int (*setattr) (struct dentry *, struct nfs_fattr *, - struct iattr *); - int (*lookup) (struct inode *, struct qstr *, - struct nfs_fh *, struct nfs_fattr *); + struct iattr *, struct rpc_groups *); + int (*lookup) (struct inode *, struct qstr *, 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); @@ -783,23 +783,26 @@ struct nfs_rpc_ops { int (*write) (struct nfs_write_data *); int (*commit) (struct nfs_write_data *); 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 qstr *, struct qstr *, struct iattr *, struct nfs_fh *, - struct nfs_fattr *); - int (*mkdir) (struct inode *, struct dentry *, struct iattr *); - int (*rmdir) (struct inode *, struct qstr *); + struct nfs_fattr *, 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-10-22 11:41:15.000000000 +0200 +++ b/include/linux/sunrpc/auth.h 2006-10-22 13:39:44.000000000 +0200 @@ -15,6 +15,7 @@ #include #include +#include #include /* size of the nodename buffer */ @@ -23,11 +24,16 @@ /* Maximum size (in bytes) of an rpc credential or verifier */ #define RPC_MAX_AUTH_SIZE (400) +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; }; /* @@ -101,6 +107,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 { @@ -129,11 +136,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 *); u32 * rpcauth_marshcred(struct rpc_task *, u32 *); u32 * rpcauth_checkverf(struct rpc_task *, u32 *); int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, u32 *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 2006-04-23 17:35:06.000000000 +0200 +++ b/include/linux/sunrpc/msg_prot.h 2006-10-22 11:50:33.000000000 +0200 @@ -75,6 +75,7 @@ enum rpc_auth_stat { #define RPC_PMAP_PORT 111 #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-08-28 21:16:19.000000000 +0200 +++ b/include/linux/sunrpc/svcauth.h 2006-10-22 11:50:33.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 2006-08-28 21:16:21.000000000 +0200 +++ b/net/sunrpc/auth.c 2006-10-22 11:50:33.000000000 +0200 @@ -254,60 +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; -} + dprintk("RPC: looking up %s cred\n", auth->au_ops->au_name); -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: %4d 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: %4d 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 @@ -319,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: %4d 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; -} - u32 * rpcauth_marshcred(struct rpc_task *task, u32 *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 2006-10-22 11:41:18.000000000 +0200 +++ b/net/sunrpc/auth_gss/auth_gss.c 2006-10-22 11:50:33.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 2006-10-22 11:41:18.000000000 +0200 +++ b/net/sunrpc/auth_unix.c 2006-10-22 11:50:33.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; @@ -65,7 +64,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); @@ -80,22 +78,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) { @@ -111,22 +141,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 @@ -157,7 +184,7 @@ unx_marshal(struct rpc_task *task, u32 * *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 */ @@ -213,6 +240,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 2006-10-22 11:41:18.000000000 +0200 +++ b/net/sunrpc/clnt.c 2006-10-22 11:50:33.000000000 +0200 @@ -526,13 +526,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 2006-08-28 21:16:21.000000000 +0200 +++ b/net/sunrpc/sched.c 2006-10-22 11:50:33.000000000 +0200 @@ -893,8 +893,10 @@ void rpc_release_task(struct rpc_task *t /* 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 2006-08-28 21:16:21.000000000 +0200 +++ b/net/sunrpc/svcauth_unix.c 2006-10-22 11:50:33.000000000 +0200 @@ -497,7 +497,7 @@ svcauth_unix_accept(struct svc_rqst *rqs cred->cr_uid = ntohl(svc_getu32(argv)); /* uid */ cred->cr_gid = ntohl(svc_getu32(argv)); /* gid */ slen = ntohl(svc_getu32(argv)); /* gids length */ - if (slen > 16 || (len -= (slen + 2)*4) < 0) + if (slen > RPC_MAXGROUPS || (len -= (slen + 2)*4) < 0) goto badcred; cred->cr_group_info = groups_alloc(slen); if (cred->cr_group_info == NULL)