diff -ru a/fs/nfs/dir.c b/fs/nfs/dir.c --- a/fs/nfs/dir.c 2005-06-26 12:01:23.000000000 +0200 +++ b/fs/nfs/dir.c 2005-06-26 12:26:12.000000000 +0200 @@ -606,6 +606,7 @@ struct nfs_fh fhandle; struct nfs_fattr fattr; unsigned long verifier; + struct rpc_groups fsg; parent = dget_parent(dentry); lock_kernel(); @@ -639,7 +640,9 @@ 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)) @@ -737,6 +740,7 @@ 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); @@ -760,7 +764,9 @@ 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) { @@ -977,7 +983,7 @@ * 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; @@ -987,7 +993,7 @@ 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; } @@ -1020,6 +1026,7 @@ 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); @@ -1032,7 +1039,7 @@ lock_kernel(); nfs_begin_data_update(dir); - error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags); + error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, &fsg); nfs_end_data_update(dir); if (error != 0) goto out_err; @@ -1054,6 +1061,7 @@ { 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); @@ -1066,7 +1074,7 @@ 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; @@ -1087,6 +1095,7 @@ { 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); @@ -1096,7 +1105,7 @@ 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; @@ -1113,13 +1122,14 @@ 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; @@ -1139,6 +1149,7 @@ 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, @@ -1185,11 +1196,11 @@ 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_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); @@ -1214,6 +1225,7 @@ { 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", @@ -1228,13 +1240,13 @@ nfs_begin_data_update(dir); if (inode != NULL) { 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_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; @@ -1287,6 +1299,7 @@ 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); @@ -1309,10 +1322,10 @@ 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", @@ -1327,6 +1340,7 @@ 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", @@ -1343,7 +1357,7 @@ 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); nfs_end_data_update(inode); nfs_end_data_update(dir); unlock_kernel(); @@ -1380,6 +1394,14 @@ 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; /* @@ -1452,7 +1474,7 @@ 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_end_data_update(old_inode); nfs_end_data_update(new_dir); nfs_end_data_update(old_dir); @@ -1513,6 +1535,8 @@ 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); @@ -1558,7 +1582,12 @@ 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 -ru a/fs/nfs/file.c b/fs/nfs/file.c --- a/fs/nfs/file.c 2005-06-26 12:01:23.000000000 +0200 +++ b/fs/nfs/file.c 2005-06-26 12:26:12.000000000 +0200 @@ -99,7 +99,6 @@ return res; lock_kernel(); - /* Do NFSv4 open() call */ if ((open = server->rpc_ops->file_open) != NULL) res = open(inode, filp); unlock_kernel(); diff -ru a/fs/nfs/inode.c b/fs/nfs/inode.c --- a/fs/nfs/inode.c 2005-06-26 12:01:23.000000000 +0200 +++ b/fs/nfs/inode.c 2005-06-26 12:26:12.000000000 +0200 @@ -753,6 +753,7 @@ { struct inode *inode = dentry->d_inode; struct nfs_fattr fattr; + struct rpc_groups fsg; int error; if (attr->ia_valid & ATTR_SIZE) { @@ -773,7 +774,11 @@ filemap_fdatawait(inode->i_mapping); nfs_wb_all(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); if ((attr->ia_valid & ATTR_MODE) != 0) { @@ -934,7 +939,12 @@ 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_dentry, cred); @@ -1631,7 +1641,7 @@ clnt->cl_softrtry = 1; clnt->cl_chatty = 1; clp->cl_rpcclient = clnt; - clp->cl_cred = rpcauth_lookupcred(clnt->cl_auth, 0); + clp->cl_cred = rpcauth_lookupcred(clnt->cl_auth, NULL, 0); if (IS_ERR(clp->cl_cred)) { up_write(&clp->cl_sem); err = PTR_ERR(clp->cl_cred); diff -ru a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c --- a/fs/nfs/nfs3proc.c 2005-06-26 12:01:23.000000000 +0200 +++ b/fs/nfs/nfs3proc.c 2005-06-26 12:26:12.000000000 +0200 @@ -24,13 +24,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; set_current_state(TASK_INTERRUPTIBLE); @@ -41,21 +49,19 @@ return res; } -static inline int -nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) +static int +nfs3_rpc(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, + struct rpc_groups *fsg) { - struct rpc_message msg = { - .rpc_proc = &nfs3_procedures[proc], - .rpc_argp = argp, - .rpc_resp = resp, - }; - return nfs3_rpc_wrapper(clnt, &msg, flags); -} + struct rpc_cred *cred; + int res; -#define rpc_call(clnt, proc, argp, resp, flags) \ - nfs3_rpc_call_wrapper(clnt, proc, argp, resp, flags) -#define rpc_call_sync(clnt, msg, flags) \ - nfs3_rpc_wrapper(clnt, msg, flags) + 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) @@ -79,10 +85,11 @@ dprintk("%s: call fsinfo\n", __FUNCTION__); info->fattr->valid = 0; - status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0); + status = nfs3_rpc(server->client_sys, NFS3PROC_FSINFO, fhandle, info, NULL); dprintk("%s: reply fsinfo: %d\n", __FUNCTION__, status); if (!(info->fattr->valid & NFS_ATTR_FATTR)) { - status = rpc_call(server->client_sys, NFS3PROC_GETATTR, fhandle, info->fattr, 0); + status = nfs3_rpc(server->client_sys, NFS3PROC_GETATTR, fhandle, + info->fattr, NULL); dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); } return status; @@ -99,15 +106,14 @@ dprintk("NFS call getattr\n"); fattr->valid = 0; - status = rpc_call(server->client, NFS3PROC_GETATTR, - fhandle, fattr, 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 = { @@ -118,14 +124,15 @@ dprintk("NFS call setattr\n"); fattr->valid = 0; - status = rpc_call(NFS_CLIENT(inode), NFS3PROC_SETATTR, &arg, fattr, 0); + status = nfs3_rpc(NFS_CLIENT(inode), NFS3PROC_SETATTR, &arg, fattr, fsg); dprintk("NFS reply setattr: %d\n", status); return status; } 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 = { @@ -143,10 +150,10 @@ dprintk("NFS call lookup %s\n", name->name); dir_attr.valid = 0; fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir), NFS3PROC_LOOKUP, &arg, &res, 0); + status = nfs3_rpc(NFS_CLIENT(dir), NFS3PROC_LOOKUP, &arg, &res, fsg); if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) - status = rpc_call(NFS_CLIENT(dir), NFS3PROC_GETATTR, - fhandle, fattr, 0); + status = nfs3_rpc(NFS_CLIENT(dir), NFS3PROC_GETATTR, + fhandle, fattr, NULL); dprintk("NFS reply lookup: %d\n", status); if (status >= 0) status = nfs_refresh_inode(dir, &dir_attr); @@ -162,12 +169,6 @@ 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; @@ -187,7 +188,8 @@ if (mode & MAY_EXEC) arg.access |= NFS3_ACCESS_EXECUTE; } - 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; @@ -216,8 +218,7 @@ dprintk("NFS call readlink\n"); fattr.valid = 0; - status = rpc_call(NFS_CLIENT(inode), NFS3PROC_READLINK, - &args, &fattr, 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; @@ -228,18 +229,13 @@ 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); fattr->valid = 0; - 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); @@ -251,18 +247,13 @@ 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); fattr->valid = 0; - 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_refresh_inode(inode, fattr); dprintk("NFS reply write: %d\n", status); @@ -273,18 +264,13 @@ { 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); fattr->valid = 0; - 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_refresh_inode(inode, fattr); dprintk("NFS reply commit: %d\n", status); @@ -297,7 +283,7 @@ */ static int nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, - int flags) + int flags, struct rpc_groups *fsg) { struct nfs_fh fhandle; struct nfs_fattr fattr; @@ -326,7 +312,7 @@ again: dir_attr.valid = 0; fattr.valid = 0; - status = rpc_call(NFS_CLIENT(dir), NFS3PROC_CREATE, &arg, &res, 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, @@ -348,7 +334,7 @@ } if (status == 0) - status = nfs_instantiate(dentry, &fhandle, &fattr); + status = nfs_instantiate(dentry, &fhandle, &fattr, fsg); if (status != 0) goto out; @@ -365,7 +351,7 @@ /* 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); nfs_refresh_inode(dentry->d_inode, &fattr); dprintk("NFS reply setattr (post-create): %d\n", status); } @@ -375,7 +361,7 @@ } 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 = { @@ -383,16 +369,11 @@ .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); dir_attr.valid = 0; - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + status = nfs3_rpc(NFS_CLIENT(dir), NFS3PROC_REMOVE, &arg, &dir_attr, fsg); nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply remove: %d\n", status); return status; @@ -437,7 +418,8 @@ 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 = { @@ -457,7 +439,7 @@ dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); old_dir_attr.valid = 0; new_dir_attr.valid = 0; - status = rpc_call(NFS_CLIENT(old_dir), NFS3PROC_RENAME, &arg, &res, 0); + status = nfs3_rpc(NFS_CLIENT(old_dir), NFS3PROC_RENAME, &arg, &res, fsg); nfs_refresh_inode(old_dir, &old_dir_attr); nfs_refresh_inode(new_dir, &new_dir_attr); dprintk("NFS reply rename: %d\n", status); @@ -465,7 +447,8 @@ } 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 = { @@ -483,7 +466,7 @@ dprintk("NFS call link %s\n", name->name); dir_attr.valid = 0; fattr.valid = 0; - status = rpc_call(NFS_CLIENT(inode), NFS3PROC_LINK, &arg, &res, 0); + status = nfs3_rpc(NFS_CLIENT(inode), NFS3PROC_LINK, &arg, &res, fsg); nfs_refresh_inode(dir, &dir_attr); nfs_refresh_inode(inode, &fattr); dprintk("NFS reply link: %d\n", status); @@ -493,7 +476,7 @@ 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 = { @@ -516,14 +499,15 @@ dprintk("NFS call symlink %s -> %s\n", name->name, path->name); dir_attr.valid = 0; fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SYMLINK, &arg, &res, 0); + status = nfs3_rpc(NFS_CLIENT(dir), NFS3PROC_SYMLINK, &arg, &res, fsg); nfs_refresh_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; @@ -543,16 +527,16 @@ dprintk("NFS call mkdir %s\n", dentry->d_name.name); dir_attr.valid = 0; fattr.valid = 0; - status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0); + status = nfs3_rpc(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, fsg); nfs_refresh_inode(dir, &dir_attr); 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 -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 = { @@ -564,7 +548,7 @@ dprintk("NFS call rmdir %s\n", name->name); dir_attr.valid = 0; - status = rpc_call(NFS_CLIENT(dir), NFS3PROC_RMDIR, &arg, &dir_attr, 0); + status = nfs3_rpc(NFS_CLIENT(dir), NFS3PROC_RMDIR, &arg, &dir_attr, fsg); nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply rmdir: %d\n", status); return status; @@ -599,24 +583,19 @@ .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); dir_attr.valid = 0; - 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(); @@ -625,7 +604,7 @@ 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; @@ -655,10 +634,10 @@ MAJOR(rdev), MINOR(rdev)); dir_attr.valid = 0; fattr.valid = 0; - status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); + status = nfs3_rpc(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, fsg); nfs_refresh_inode(dir, &dir_attr); if (status == 0) - status = nfs_instantiate(dentry, &fh, &fattr); + status = nfs_instantiate(dentry, &fh, &fattr, fsg); dprintk("NFS reply mknod: %d\n", status); return status; } @@ -671,7 +650,7 @@ dprintk("NFS call fsstat\n"); stat->fattr->valid = 0; - status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, stat, 0); + status = nfs3_rpc(server->client, NFS3PROC_FSSTAT, fhandle, stat, NULL); dprintk("NFS reply statfs: %d\n", status); return status; } @@ -684,7 +663,7 @@ dprintk("NFS call fsinfo\n"); info->fattr->valid = 0; - status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0); + status = nfs3_rpc(server->client_sys, NFS3PROC_FSINFO, fhandle, info, NULL); dprintk("NFS reply fsinfo: %d\n", status); return status; } @@ -697,7 +676,7 @@ dprintk("NFS call pathconf\n"); info->fattr->valid = 0; - status = rpc_call(server->client, NFS3PROC_PATHCONF, fhandle, info, 0); + status = nfs3_rpc(server->client, NFS3PROC_PATHCONF, fhandle, info, NULL); dprintk("NFS reply pathconf: %d\n", status); return status; } diff -ru a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c --- a/fs/nfs/nfs4proc.c 2005-06-26 12:01:23.000000000 +0200 +++ b/fs/nfs/nfs4proc.c 2005-06-26 12:26:12.000000000 +0200 @@ -886,7 +886,7 @@ 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 inode *)cred; state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); @@ -903,7 +903,7 @@ struct nfs4_state *state; struct inode *inode; - 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); @@ -1114,7 +1114,7 @@ */ static int nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, - struct iattr *sattr) + struct iattr *sattr, struct rpc_groups *fsg) { struct inode * inode = dentry->d_inode; int size_change = sattr->ia_valid & ATTR_SIZE; @@ -1125,7 +1125,7 @@ fattr->valid = 0; if (size_change) { - struct rpc_cred *cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); + struct rpc_cred *cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, NULL, 0); if (IS_ERR(cred)) return PTR_ERR(cred); state = nfs4_find_state(inode, cred, FMODE_WRITE); @@ -1189,7 +1189,9 @@ 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; @@ -1436,13 +1438,13 @@ static int nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, - int flags) + int flags, 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; @@ -1487,7 +1489,8 @@ 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; @@ -1564,7 +1567,8 @@ } 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; @@ -1599,7 +1603,8 @@ 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; @@ -1649,7 +1654,7 @@ 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; @@ -1693,13 +1698,13 @@ status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); if (!status) { update_changeattr(dir, &res.dir_cinfo); - 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; @@ -1803,13 +1808,13 @@ status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); if (status == 0) { update_changeattr(dir, &res.dir_cinfo); - 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; @@ -2126,7 +2131,7 @@ /* Find our open stateid */ - 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); ctx = alloc_nfs_open_context(dentry, cred); diff -ru a/fs/nfs/proc.c b/fs/nfs/proc.c --- a/fs/nfs/proc.c 2005-06-26 12:01:23.000000000 +0200 +++ b/fs/nfs/proc.c 2005-06-26 12:26:12.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. @@ -49,6 +49,33 @@ extern struct rpc_procinfo nfs_procedures[]; +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. */ @@ -62,12 +89,12 @@ dprintk("%s: call getattr\n", __FUNCTION__); fattr->valid = 0; - status = rpc_call(server->client_sys, NFSPROC_GETATTR, fhandle, fattr, 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__); - status = rpc_call(server->client_sys, NFSPROC_STATFS, fhandle, &fsinfo, 0); + status = nfs2_rpc(server->client_sys, NFSPROC_STATFS, fhandle, &fsinfo, NULL); dprintk("%s: reply statfs: %d\n", __FUNCTION__, status); if (status) return status; @@ -94,18 +121,17 @@ dprintk("NFS call getattr\n"); fattr->valid = 0; - status = rpc_call(server->client, NFSPROC_GETATTR, - fhandle, fattr, 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 }; @@ -113,14 +139,15 @@ dprintk("NFS call setattr\n"); fattr->valid = 0; - status = rpc_call(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, 0); + status = nfs2_rpc(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, fsg); dprintk("NFS reply setattr: %d\n", status); return status; } 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), @@ -135,7 +162,7 @@ dprintk("NFS call lookup %s\n", name->name); fattr->valid = 0; - status = rpc_call(NFS_CLIENT(dir), NFSPROC_LOOKUP, &arg, &res, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_LOOKUP, &arg, &res, fsg); dprintk("NFS reply lookup: %d\n", status); return status; } @@ -152,7 +179,7 @@ int status; dprintk("NFS call readlink\n"); - status = rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK, &args, NULL, 0); + status = nfs2_rpc(NFS_CLIENT(inode), NFSPROC_READLINK, &args, NULL, NULL); dprintk("NFS reply readlink: %d\n", status); return status; } @@ -162,18 +189,13 @@ 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); fattr->valid = 0; - 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 @@ -191,18 +213,13 @@ 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); fattr->valid = 0; - 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_refresh_inode(inode, fattr); wdata->res.count = wdata->args.count; @@ -214,7 +231,7 @@ static int nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, - int flags) + int flags, struct rpc_groups *fsg) { struct nfs_fh fhandle; struct nfs_fattr fattr; @@ -232,9 +249,9 @@ fattr.valid = 0; dprintk("NFS call create %s\n", dentry->d_name.name); - status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 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; } @@ -244,7 +261,7 @@ */ 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; @@ -272,37 +289,31 @@ } fattr.valid = 0; - status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, fsg); if (status == -EINVAL && S_ISFIFO(mode)) { sattr->ia_mode = mode; fattr.valid = 0; - status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 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, - .rpc_resp = NULL, - .rpc_cred = NULL - }; 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); dprintk("NFS reply remove: %d\n", status); return status; @@ -336,7 +347,8 @@ 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), @@ -349,13 +361,14 @@ int status; dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); - status = rpc_call(NFS_CLIENT(old_dir), NFSPROC_RENAME, &arg, NULL, 0); + status = nfs2_rpc(NFS_CLIENT(old_dir), NFSPROC_RENAME, &arg, NULL, fsg); dprintk("NFS reply rename: %d\n", status); return status; } 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), @@ -366,7 +379,7 @@ int status; dprintk("NFS call link %s\n", name->name); - status = rpc_call(NFS_CLIENT(inode), NFSPROC_LINK, &arg, NULL, 0); + status = nfs2_rpc(NFS_CLIENT(inode), NFSPROC_LINK, &arg, NULL, fsg); dprintk("NFS reply link: %d\n", status); return status; } @@ -374,7 +387,7 @@ 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), @@ -391,13 +404,14 @@ dprintk("NFS call symlink %s -> %s\n", name->name, path->name); fattr->valid = 0; fhandle->size = 0; - status = rpc_call(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, fsg); 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; @@ -415,15 +429,15 @@ dprintk("NFS call mkdir %s\n", dentry->d_name.name); fattr.valid = 0; - status = rpc_call(NFS_CLIENT(dir), NFSPROC_MKDIR, &arg, &res, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_MKDIR, &arg, &res, fsg); 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), @@ -433,7 +447,7 @@ int status; dprintk("NFS call rmdir %s\n", name->name); - status = rpc_call(NFS_CLIENT(dir), NFSPROC_RMDIR, &arg, NULL, 0); + status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_RMDIR, &arg, NULL, fsg); dprintk("NFS reply rmdir: %d\n", status); return status; } @@ -456,18 +470,12 @@ .count = count, .pages = &page }; - struct rpc_message msg = { - .rpc_proc = &nfs_procedures[NFSPROC_READDIR], - .rpc_argp = &arg, - .rpc_resp = NULL, - .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(); @@ -483,7 +491,7 @@ dprintk("NFS call statfs\n"); stat->fattr->valid = 0; - status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &fsinfo, 0); + status = nfs2_rpc(server->client, NFSPROC_STATFS, fhandle, &fsinfo, NULL); dprintk("NFS reply statfs: %d\n", status); if (status) goto out; @@ -506,7 +514,7 @@ dprintk("NFS call fsinfo\n"); info->fattr->valid = 0; - status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &fsinfo, 0); + status = nfs2_rpc(server->client, NFSPROC_STATFS, fhandle, &fsinfo, NULL); dprintk("NFS reply fsinfo: %d\n", status); if (status) goto out; diff -ru a/fs/nfs/unlink.c b/fs/nfs/unlink.c --- a/fs/nfs/unlink.c 2005-06-26 12:01:23.000000000 +0200 +++ b/fs/nfs/unlink.c 2005-06-26 12:26:12.000000000 +0200 @@ -167,7 +167,12 @@ goto out; memset(data, 0, sizeof(*data)); - 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 -ru a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c --- a/fs/nfsd/nfs4callback.c 2005-06-26 12:01:23.000000000 +0200 +++ b/fs/nfsd/nfs4callback.c 2005-06-26 12:26:12.000000000 +0200 @@ -353,17 +353,18 @@ { 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 -ru a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h --- a/include/linux/nfs_fs.h 2005-06-26 12:01:33.000000000 +0200 +++ b/include/linux/nfs_fs.h 2005-06-26 12:26:12.000000000 +0200 @@ -345,7 +345,8 @@ extern 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 -ru a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h --- a/include/linux/nfs_xdr.h 2005-06-26 12:01:33.000000000 +0200 +++ b/include/linux/nfs_xdr.h 2005-06-26 12:26:12.000000000 +0200 @@ -661,7 +661,7 @@ 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 */ @@ -673,9 +673,9 @@ 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); @@ -683,23 +683,25 @@ int (*write) (struct nfs_write_data *); int (*commit) (struct nfs_write_data *); int (*create) (struct inode *, struct dentry *, - struct iattr *, int); - int (*remove) (struct inode *, struct qstr *); + struct iattr *, int, struct rpc_groups *); + int (*remove) (struct inode *, struct qstr *, struct rpc_groups *); 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 -ru a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h --- a/include/linux/sunrpc/auth.h 2005-06-26 12:01:34.000000000 +0200 +++ b/include/linux/sunrpc/auth.h 2005-06-26 12:26:12.000000000 +0200 @@ -12,6 +12,7 @@ #ifdef __KERNEL__ #include +#include #include #include #include @@ -24,11 +25,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; }; /* @@ -96,6 +102,7 @@ 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 { @@ -123,11 +130,8 @@ 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 -ru a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h --- a/include/linux/sunrpc/msg_prot.h 2004-05-10 04:32:54.000000000 +0200 +++ b/include/linux/sunrpc/msg_prot.h 2005-06-26 12:26:12.000000000 +0200 @@ -75,6 +75,7 @@ #define RPC_PMAP_PORT 111 #define RPC_MAXNETNAMELEN 256 +#define RPC_MAXGROUPS 16 #endif /* __KERNEL__ */ #endif /* _LINUX_SUNRPC_MSGPROT_H_ */ diff -ru a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h --- a/include/linux/sunrpc/svcauth.h 2005-06-26 12:01:34.000000000 +0200 +++ b/include/linux/sunrpc/svcauth.h 2005-06-26 12:26:12.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 -ru a/net/sunrpc/auth.c b/net/sunrpc/auth.c --- a/net/sunrpc/auth.c 2005-06-26 12:01:38.000000000 +0200 +++ b/net/sunrpc/auth.c 2005-06-26 12:26:12.000000000 +0200 @@ -235,60 +235,28 @@ cred = new; } - return (struct rpc_cred *) cred; + return cred; } struct rpc_cred * -rpcauth_lookupcred(struct rpc_auth *auth, int taskflags) +rpcauth_lookupcred(struct rpc_auth *auth, struct rpc_groups *rg, int taskflags) { 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, taskflags); - 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; + 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, taskflags); - dprintk("RPC: %4d looking up %s cred\n", - task->tk_pid, task->tk_auth->au_ops->au_name); - get_group_info(acred.group_info); - ret = auth->au_ops->lookup_cred(auth, &acred, task->tk_flags); - if (!IS_ERR(ret)) - task->tk_msg.rpc_cred = ret; - else - task->tk_status = PTR_ERR(ret); - put_group_info(acred.group_info); + dprintk("RPC: cred %p\n", ret); 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); -} - -void put_rpccred(struct rpc_cred *cred) { cred->cr_expire = jiffies; @@ -297,19 +265,6 @@ cred->cr_ops->crdestroy(cred); } -void -rpcauth_unbindcred(struct rpc_task *task) -{ - struct rpc_auth *auth = task->tk_auth; - struct rpc_cred *cred = task->tk_msg.rpc_cred; - - dprintk("RPC: %4d releasing %s cred %p\n", - task->tk_pid, 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 -ru a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c --- a/net/sunrpc/auth_gss/auth_gss.c 2005-06-26 12:01:38.000000000 +0200 +++ b/net/sunrpc/auth_gss/auth_gss.c 2005-06-26 12:26:12.000000000 +0200 @@ -63,8 +63,6 @@ # 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 -ru a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c --- a/net/sunrpc/auth_unix.c 2005-06-26 12:01:39.000000000 +0200 +++ b/net/sunrpc/auth_unix.c 2005-06-26 12:26:12.000000000 +0200 @@ -14,12 +14,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 @@ -32,6 +30,7 @@ #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; @@ -67,7 +66,6 @@ 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); @@ -82,22 +80,54 @@ 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) { @@ -113,22 +143,19 @@ unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags) { struct unx_cred *cred = (struct unx_cred *) rcred; - int i; if (!(taskflags & RPC_TASK_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 @@ -159,7 +186,7 @@ *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 */ @@ -215,6 +242,7 @@ .destroy = unx_destroy, .lookup_cred = unx_lookup_cred, .crcreate = unx_create_cred, + .cr_add_groups = unx_add_groups, }; static diff -ru a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c --- a/net/sunrpc/clnt.c 2005-06-26 12:01:39.000000000 +0200 +++ b/net/sunrpc/clnt.c 2005-06-26 12:26:12.000000000 +0200 @@ -423,13 +423,21 @@ 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 { + cred = rpcauth_lookupcred(task->tk_auth, NULL, task->tk_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 -ru a/net/sunrpc/sched.c b/net/sunrpc/sched.c --- a/net/sunrpc/sched.c 2005-06-26 12:01:39.000000000 +0200 +++ b/net/sunrpc/sched.c 2005-06-26 12:26:12.000000000 +0200 @@ -853,8 +853,10 @@ /* 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; + } rpc_free(task); if (task->tk_client) { rpc_release_client(task->tk_client); diff -ru a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c --- a/net/sunrpc/svcauth_unix.c 2005-06-26 12:01:39.000000000 +0200 +++ b/net/sunrpc/svcauth_unix.c 2005-06-26 12:26:12.000000000 +0200 @@ -450,7 +450,7 @@ 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)