[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#592557: Patch



Hi,

Attached is a working patch for 2.6.26-24.

Regards,
  Frodo

-- 
Frodo Looijaard <frodo@frodo.looijaard.name> (See http://frodo.looijaard.name/)
Defenestration n. (formal or joc.):
  The act of removing Windows from your computer in disgust, usually followed
  by the installation of Linux or some other Unix-like operating system.
diff -Nurp linux-source-2.6.26.orig/fs/nfs/dir.c linux-source-2.6.26/fs/nfs/dir.c
--- linux-source-2.6.26.orig/fs/nfs/dir.c	2010-08-11 10:07:24.000000000 +0200
+++ linux-source-2.6.26/fs/nfs/dir.c	2010-08-11 13:23:12.000000000 +0200
@@ -765,6 +765,7 @@ static int nfs_lookup_revalidate(struct 
 	int error;
 	struct nfs_fh fhandle;
 	struct nfs_fattr fattr;
+	struct rpc_groups fsg;
 
 	parent = dget_parent(dentry);
 	lock_kernel();
@@ -795,7 +796,9 @@ static int nfs_lookup_revalidate(struct 
 	if (NFS_STALE(inode))
 		goto out_bad;
 
-	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
+	fsg.ngroups = 1;
+	fsg.groups[0] = dir->i_gid;
+	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr, &fsg);
 	if (error)
 		goto out_bad;
 	if (nfs_compare_fh(NFS_FH(inode), &fhandle))
@@ -891,6 +894,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);
@@ -918,7 +922,9 @@ static struct dentry *nfs_lookup(struct 
 	parent = dentry->d_parent;
 	/* Protect against concurrent sillydeletes */
 	nfs_block_sillyrename(parent);
-	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
+	fsg.ngroups = 1;
+	fsg.groups[0] = dir->i_gid;
+	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr, &fsg);
 	if (error == -ENOENT)
 		goto no_entry;
 	if (error < 0) {
@@ -1158,7 +1164,7 @@ out_renew:
  * Code common to create, mkdir, and mknod.
  */
 int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
-				struct nfs_fattr *fattr)
+				struct nfs_fattr *fattr, struct rpc_groups *fsg)
 {
 	struct dentry *parent = dget_parent(dentry);
 	struct inode *dir = parent->d_inode;
@@ -1171,7 +1177,7 @@ int nfs_instantiate(struct dentry *dentr
 	if (dentry->d_inode)
 		goto out;
 	if (fhandle->size == 0) {
-		error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
+		error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, fsg);
 		if (error)
 			goto out_error;
 	}
@@ -1208,6 +1214,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);
@@ -1219,7 +1226,7 @@ static int nfs_create(struct inode *dir,
 		open_flags = nd->intent.open.flags;
 
 	lock_kernel();
-	error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd);
+	error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd, &fsg);
 	if (error != 0)
 		goto out_err;
 	unlock_kernel();
@@ -1238,6 +1245,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);
@@ -1249,7 +1257,7 @@ nfs_mknod(struct inode *dir, struct dent
 	attr.ia_valid = ATTR_MODE;
 
 	lock_kernel();
-	status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev);
+	status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev, &fsg);
 	if (status != 0)
 		goto out_err;
 	unlock_kernel();
@@ -1267,6 +1275,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);
@@ -1275,7 +1284,7 @@ static int nfs_mkdir(struct inode *dir, 
 	attr.ia_mode = mode | S_IFDIR;
 
 	lock_kernel();
-	error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr);
+	error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr, &fsg);
 	if (error != 0)
 		goto out_err;
 	unlock_kernel();
@@ -1295,12 +1304,13 @@ static void nfs_dentry_handle_enoent(str
 static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	int error;
+	struct rpc_groups fsg = { 1, { dir->i_gid } };
 
 	dfprintk(VFS, "NFS: rmdir(%s/%ld), %s\n",
 			dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
 
 	lock_kernel();
-	error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
+	error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name, &fsg);
 	/* Ensure the VFS deletes this inode */
 	if (error == 0 && dentry->d_inode != NULL)
 		clear_nlink(dentry->d_inode);
@@ -1321,6 +1331,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, 
@@ -1365,11 +1376,11 @@ static int nfs_sillyrename(struct inode 
 	qsilly.len  = strlen(silly);
 	if (dentry->d_inode) {
 		error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
-				dir, &qsilly);
+				dir, &qsilly, &fsg);
 		nfs_mark_for_revalidate(dentry->d_inode);
 	} else
 		error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
-				dir, &qsilly);
+				dir, &qsilly, &fsg);
 	if (!error) {
 		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 		d_move(dentry, sdentry);
@@ -1392,6 +1403,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",
@@ -1405,13 +1417,13 @@ static int nfs_safe_remove(struct dentry
 
 	if (inode != NULL) {
 		nfs_inode_return_delegation(inode);
-		error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
+		error = NFS_PROTO(dir)->remove(dir, &dentry->d_name, &fsg);
 		/* The VFS may want to delete this inode */
 		if (error == 0)
 			drop_nlink(inode);
 		nfs_mark_for_revalidate(inode);
 	} else
-		error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
+		error = NFS_PROTO(dir)->remove(dir, &dentry->d_name, &fsg);
 	if (error == -ENOENT)
 		nfs_dentry_handle_enoent(dentry);
 out:
@@ -1481,6 +1493,7 @@ static int nfs_symlink(struct inode *dir
 	struct iattr attr;
 	unsigned int pathlen = strlen(symname);
 	int error;
+	struct rpc_groups fsg = { 1, { dir->i_gid } };
 
 	dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id,
 		dir->i_ino, dentry->d_name.name, symname);
@@ -1505,7 +1518,7 @@ static int nfs_symlink(struct inode *dir
 		memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen);
 	kunmap_atomic(kaddr, KM_USER0);
 
-	error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr);
+	error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr, &fsg);
 	if (error != 0) {
 		dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n",
 			dir->i_sb->s_id, dir->i_ino,
@@ -1538,6 +1551,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",
@@ -1546,7 +1560,7 @@ nfs_link(struct dentry *old_dentry, stru
 
 	lock_kernel();
 	d_drop(dentry);
-	error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
+	error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name, &fsg);
 	if (error == 0) {
 		atomic_inc(&inode->i_count);
 		d_add(dentry, inode);
@@ -1585,6 +1599,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;
 
 	/*
@@ -1654,7 +1676,7 @@ go_ahead:
 	}
 
 	error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
-					   new_dir, &new_dentry->d_name);
+					   new_dir, &new_dentry->d_name, &fsg);
 	nfs_mark_for_revalidate(old_inode);
 out:
 	if (rehash)
@@ -1902,6 +1924,8 @@ static int nfs_do_access(struct inode *i
 	cache.cred = cred;
 	cache.jiffies = jiffies;
 	status = NFS_PROTO(inode)->access(inode, &cache);
+	dfprintk(VFS, "NFS: access()=%d for ino %lu, cred %p, mask 0x%x->0x%x\n",
+	         status, inode->i_ino, cred, mask, cache.mask);
 	if (status != 0) {
 		if (status == -ESTALE) {
 			nfs_zap_caches(inode);
@@ -1974,7 +1998,12 @@ force_lookup:
 	if (!NFS_PROTO(inode)->access)
 		goto out_notsup;
 
-	cred = rpc_lookup_cred();
+	if (NFS_PROTO(inode)->version > 3)
+		cred = rpc_lookup_cred(NULL);
+	else {
+		struct rpc_groups fsg = { 1, { inode->i_gid } };
+		cred = rpc_lookup_cred(&fsg);
+	}
 	if (!IS_ERR(cred)) {
 		res = nfs_do_access(inode, cred, mask);
 		put_rpccred(cred);
diff -Nurp linux-source-2.6.26.orig/fs/nfs/inode.c linux-source-2.6.26/fs/nfs/inode.c
--- linux-source-2.6.26.orig/fs/nfs/inode.c	2010-08-11 10:07:24.000000000 +0200
+++ linux-source-2.6.26/fs/nfs/inode.c	2010-08-11 13:23:12.000000000 +0200
@@ -352,6 +352,7 @@ nfs_setattr(struct dentry *dentry, struc
 {
 	struct inode *inode = dentry->d_inode;
 	struct nfs_fattr fattr;
+	struct rpc_groups fsg;
 	int error;
 
 	nfs_inc_stats(inode, NFSIOS_VFSSETATTR);
@@ -381,7 +382,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);
 	unlock_kernel();
@@ -611,7 +616,12 @@ int nfs_open(struct inode *inode, struct
 	struct nfs_open_context *ctx;
 	struct rpc_cred *cred;
 
-	cred = rpc_lookup_cred();
+	if (NFS_PROTO(inode)->version > 3)
+		cred = rpc_lookup_cred(NULL);
+	else {
+		struct rpc_groups fsg = { 1, { inode->i_gid } };
+		cred = rpc_lookup_cred(&fsg);
+	}
 	if (IS_ERR(cred))
 		return PTR_ERR(cred);
 	ctx = alloc_nfs_open_context(filp->f_path.mnt, filp->f_path.dentry, cred);
diff -Nurp linux-source-2.6.26.orig/fs/nfs/namespace.c linux-source-2.6.26/fs/nfs/namespace.c
--- linux-source-2.6.26.orig/fs/nfs/namespace.c	2010-08-11 10:07:24.000000000 +0200
+++ linux-source-2.6.26/fs/nfs/namespace.c	2010-08-11 13:23:12.000000000 +0200
@@ -101,6 +101,7 @@ static void * nfs_follow_mountpoint(stru
 	struct dentry *parent;
 	struct nfs_fh fh;
 	struct nfs_fattr fattr;
+	struct rpc_groups fsg;
 	int err;
 
 	dprintk("--> nfs_follow_mountpoint()\n");
@@ -112,9 +113,11 @@ static void * nfs_follow_mountpoint(stru
 
 	/* Look it up again */
 	parent = dget_parent(nd->path.dentry);
+	fsg.ngroups = 1;
+	fsg.groups[0] = parent->d_inode->i_gid;
 	err = server->nfs_client->rpc_ops->lookup(parent->d_inode,
 						  &nd->path.dentry->d_name,
-						  &fh, &fattr);
+						  &fh, &fattr, &fsg);
 	dput(parent);
 	if (err != 0)
 		goto out_err;
diff -Nurp linux-source-2.6.26.orig/fs/nfs/nfs3proc.c linux-source-2.6.26/fs/nfs/nfs3proc.c
--- linux-source-2.6.26.orig/fs/nfs/nfs3proc.c	2010-08-11 10:07:24.000000000 +0200
+++ linux-source-2.6.26/fs/nfs/nfs3proc.c	2010-08-11 13:23:12.000000000 +0200
@@ -25,11 +25,19 @@
 
 /* A wrapper to handle the EJUKEBOX error message */
 static int
-nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
+nfs3_rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp,
+	      struct rpc_cred *cred, int flags)
 {
+	struct rpc_message msg = {
+		.rpc_proc	= &nfs3_procedures[proc],
+		.rpc_argp	= argp,
+		.rpc_resp	= resp,
+		.rpc_cred	= cred,
+	};
 	int res;
+
 	do {
-		res = rpc_call_sync(clnt, msg, flags);
+		res = rpc_call_sync(clnt, &msg, flags);
 		if (res != -EJUKEBOX)
 			break;
 		schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME);
@@ -38,7 +46,20 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, 
 	return res;
 }
 
-#define rpc_call_sync(clnt, msg, flags)	nfs3_rpc_wrapper(clnt, msg, flags)
+static int
+nfs3_rpc(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp,
+	 struct rpc_groups *fsg)
+{
+	struct rpc_cred	*cred;
+	int		res;
+
+	cred = rpcauth_lookupcred(clnt->cl_auth, fsg, 0);
+	if (IS_ERR(cred))
+		return PTR_ERR(cred);
+	res = nfs3_rpc_call(clnt, proc, argp, resp, cred, 0);
+	put_rpccred(cred);
+	return res;
+}
 
 static int
 nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode)
@@ -56,21 +77,14 @@ static int
 do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle,
 		 struct nfs_fsinfo *info)
 {
-	struct rpc_message msg = {
-		.rpc_proc	= &nfs3_procedures[NFS3PROC_FSINFO],
-		.rpc_argp	= fhandle,
-		.rpc_resp	= info,
-	};
 	int	status;
 
 	dprintk("%s: call  fsinfo\n", __func__);
 	nfs_fattr_init(info->fattr);
-	status = rpc_call_sync(client, &msg, 0);
+	status = nfs3_rpc(client, NFS3PROC_FSINFO, fhandle, info, NULL);
 	dprintk("%s: reply fsinfo: %d\n", __func__, status);
 	if (!(info->fattr->valid & NFS_ATTR_FATTR)) {
-		msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR];
-		msg.rpc_resp = info->fattr;
-		status = rpc_call_sync(client, &msg, 0);
+		status = nfs3_rpc(client, NFS3PROC_GETATTR, fhandle, info->fattr, NULL);
 		dprintk("%s: reply getattr: %d\n", __func__, status);
 	}
 	return status;
@@ -98,39 +112,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);
@@ -139,7 +143,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 = {
@@ -152,23 +157,16 @@ nfs3_proc_lookup(struct inode *dir, stru
 		.fh		= fhandle,
 		.fattr		= fattr
 	};
-	struct rpc_message msg = {
-		.rpc_proc	= &nfs3_procedures[NFS3PROC_LOOKUP],
-		.rpc_argp	= &arg,
-		.rpc_resp	= &res,
-	};
 	int			status;
 
 	dprintk("NFS call  lookup %s\n", name->name);
 	nfs_fattr_init(&dir_attr);
 	nfs_fattr_init(fattr);
-	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	status = nfs3_rpc(NFS_CLIENT(dir), NFS3PROC_LOOKUP, &arg, &res, fsg);
 	nfs_refresh_inode(dir, &dir_attr);
 	if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) {
-		msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR];
-		msg.rpc_argp = fhandle;
-		msg.rpc_resp = fattr;
-		status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+		status = nfs3_rpc(NFS_CLIENT(dir), NFS3PROC_GETATTR,
+				  fhandle, fattr, NULL);
 	}
 	dprintk("NFS reply lookup: %d\n", status);
 	return status;
@@ -183,12 +181,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;
 
@@ -208,7 +200,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;
@@ -233,16 +226,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;
@@ -254,7 +242,7 @@ static int nfs3_proc_readlink(struct ino
  */
 static int
 nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
-		 int flags, struct nameidata *nd)
+		 int flags, struct nameidata *nd, struct rpc_groups *fsg)
 {
 	struct nfs_fh		fhandle;
 	struct nfs_fattr	fattr;
@@ -270,11 +258,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;
 
@@ -291,7 +274,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,
@@ -313,7 +296,7 @@ again:
 	}
 
 	if (status == 0)
-		status = nfs_instantiate(dentry, &fhandle, &fattr);
+		status = nfs_instantiate(dentry, &fhandle, &fattr, fsg);
 	if (status != 0)
 		goto out;
 
@@ -330,7 +313,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);
 		nfs_post_op_update_inode(dentry->d_inode, &fattr);
 		dprintk("NFS reply setattr (post-create): %d\n", status);
 	}
@@ -343,7 +326,7 @@ out:
 }
 
 static int
-nfs3_proc_remove(struct inode *dir, struct qstr *name)
+nfs3_proc_remove(struct inode *dir, struct qstr *name, struct rpc_groups *fsg)
 {
 	struct nfs_removeargs arg = {
 		.fh = NFS_FH(dir),
@@ -351,16 +334,11 @@ nfs3_proc_remove(struct inode *dir, stru
 		.name.name = name->name,
 	};
 	struct nfs_removeres res;
-	struct rpc_message msg = {
-		.rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE],
-		.rpc_argp = &arg,
-		.rpc_resp = &res,
-	};
 	int			status;
 
 	dprintk("NFS call  remove %s\n", name->name);
 	nfs_fattr_init(&res.dir_attr);
-	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	status = nfs3_rpc(NFS_CLIENT(dir), NFS3PROC_REMOVE, &arg, &res, fsg);
 	nfs_post_op_update_inode(dir, &res.dir_attr);
 	dprintk("NFS reply remove: %d\n", status);
 	return status;
@@ -385,7 +363,8 @@ nfs3_proc_unlink_done(struct rpc_task *t
 
 static int
 nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name,
-		 struct inode *new_dir, struct qstr *new_name)
+		 struct inode *new_dir, struct qstr *new_name,
+		 struct rpc_groups *fsg)
 {
 	struct nfs_fattr	old_dir_attr, new_dir_attr;
 	struct nfs3_renameargs	arg = {
@@ -400,17 +379,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);
@@ -418,7 +392,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 = {
@@ -431,17 +406,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);
@@ -450,7 +420,7 @@ nfs3_proc_link(struct inode *inode, stru
 
 static int
 nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
-		  unsigned int len, struct iattr *sattr)
+		  unsigned int len, struct iattr *sattr, struct rpc_groups *fsg)
 {
 	struct nfs_fh fhandle;
 	struct nfs_fattr fattr, dir_attr;
@@ -467,11 +437,6 @@ nfs3_proc_symlink(struct inode *dir, str
 		.fh		= &fhandle,
 		.fattr		= &fattr
 	};
-	struct rpc_message msg = {
-		.rpc_proc	= &nfs3_procedures[NFS3PROC_SYMLINK],
-		.rpc_argp	= &arg,
-		.rpc_resp	= &res,
-	};
 	int			status;
 
 	if (len > NFS3_MAXPATHLEN)
@@ -481,18 +446,19 @@ nfs3_proc_symlink(struct inode *dir, str
 
 	nfs_fattr_init(&dir_attr);
 	nfs_fattr_init(&fattr);
-	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	status = nfs3_rpc(NFS_CLIENT(dir), NFS3PROC_SYMLINK, &arg, &res, fsg);
 	nfs_post_op_update_inode(dir, &dir_attr);
 	if (status != 0)
 		goto out;
-	status = nfs_instantiate(dentry, &fhandle, &fattr);
+	status = nfs_instantiate(dentry, &fhandle, &fattr, fsg);
 out:
 	dprintk("NFS reply symlink: %d\n", status);
 	return status;
 }
 
 static int
-nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
+nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
+		struct rpc_groups *fsg)
 {
 	struct nfs_fh fhandle;
 	struct nfs_fattr fattr, dir_attr;
@@ -507,11 +473,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;
 
@@ -521,11 +482,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);
@@ -535,7 +496,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 = {
@@ -543,16 +504,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;
@@ -587,22 +543,17 @@ nfs3_proc_readdir(struct dentry *dentry,
 		.verf		= verf,
 		.plus		= plus
 	};
-	struct rpc_message	msg = {
-		.rpc_proc	= &nfs3_procedures[NFS3PROC_READDIR],
-		.rpc_argp	= &arg,
-		.rpc_resp	= &res,
-		.rpc_cred	= cred
-	};
 	int			status;
+	u32			proc = NFS3PROC_READDIR;
 
 	if (plus)
-		msg.rpc_proc = &nfs3_procedures[NFS3PROC_READDIRPLUS];
+		proc = NFS3PROC_READDIRPLUS;
 
 	dprintk("NFS call  readdir%s %d\n",
 			plus? "plus" : "", (unsigned int) cookie);
 
 	nfs_fattr_init(&dir_attr);
-	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	status = nfs3_rpc_call(NFS_CLIENT(dir), proc, &arg, &res, cred, 0);
 
 	nfs_invalidate_atime(dir);
 
@@ -613,7 +564,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;
@@ -629,11 +580,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;
 
@@ -652,11 +598,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);
@@ -669,16 +615,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;
 }
@@ -687,16 +628,11 @@ static int
 do_proc_fsinfo(struct rpc_clnt *client, struct nfs_fh *fhandle,
 		 struct nfs_fsinfo *info)
 {
-	struct rpc_message msg = {
-		.rpc_proc	= &nfs3_procedures[NFS3PROC_FSINFO],
-		.rpc_argp	= fhandle,
-		.rpc_resp	= info,
-	};
 	int	status;
 
 	dprintk("NFS call  fsinfo\n");
 	nfs_fattr_init(info->fattr);
-	status = rpc_call_sync(client, &msg, 0);
+	status = nfs3_rpc(client, NFS3PROC_FSINFO, fhandle, info, NULL);
 	dprintk("NFS reply fsinfo: %d\n", status);
 	return status;
 }
@@ -721,16 +657,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 linux-source-2.6.26.orig/fs/nfs/nfs4proc.c linux-source-2.6.26/fs/nfs/nfs4proc.c
--- linux-source-2.6.26.orig/fs/nfs/nfs4proc.c	2010-08-11 10:07:24.000000000 +0200
+++ linux-source-2.6.26/fs/nfs/nfs4proc.c	2010-08-11 13:23:12.000000000 +0200
@@ -1403,7 +1403,7 @@ nfs4_atomic_open(struct inode *dir, stru
 		BUG_ON(nd->intent.open.flags & O_CREAT);
 	}
 
-	cred = rpc_lookup_cred();
+	cred = rpc_lookup_cred(NULL);
 	if (IS_ERR(cred))
 		return (struct dentry *)cred;
 	parent = dentry->d_parent;
@@ -1438,7 +1438,7 @@ nfs4_open_revalidate(struct inode *dir, 
 	struct rpc_cred *cred;
 	struct nfs4_state *state;
 
-	cred = rpc_lookup_cred();
+	cred = rpc_lookup_cred(NULL);
 	if (IS_ERR(cred))
 		return PTR_ERR(cred);
 	state = nfs4_do_open(dir, &path, openflags, NULL, cred);
@@ -1645,7 +1645,7 @@ static int nfs4_proc_getattr(struct nfs_
  */
 static int
 nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
-		  struct iattr *sattr)
+		  struct iattr *sattr, struct rpc_groups *fsg)
 {
 	struct rpc_cred *cred;
 	struct inode *inode = dentry->d_inode;
@@ -1655,7 +1655,7 @@ nfs4_proc_setattr(struct dentry *dentry,
 
 	nfs_fattr_init(fattr);
 	
-	cred = rpc_lookup_cred();
+	cred = rpc_lookup_cred(NULL);
 	if (IS_ERR(cred))
 		return PTR_ERR(cred);
 
@@ -1733,7 +1733,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;
@@ -1881,7 +1883,7 @@ static int nfs4_proc_readlink(struct ino
 
 static int
 nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
-                 int flags, struct nameidata *nd)
+                 int flags, struct nameidata *nd, struct rpc_groups *fsg)
 {
 	struct path path = {
 		.mnt = nd->path.mnt,
@@ -1891,7 +1893,7 @@ nfs4_proc_create(struct inode *dir, stru
 	struct rpc_cred *cred;
 	int status = 0;
 
-	cred = rpc_lookup_cred();
+	cred = rpc_lookup_cred(NULL);
 	if (IS_ERR(cred)) {
 		status = PTR_ERR(cred);
 		goto out;
@@ -1948,7 +1950,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;
@@ -2020,7 +2023,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;
@@ -2067,7 +2071,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;
@@ -2118,13 +2123,14 @@ static int _nfs4_proc_symlink(struct ino
 	if (!status) {
 		update_changeattr(dir, &res.dir_cinfo);
 		nfs_post_op_update_inode(dir, res.dir_fattr);
-		status = nfs_instantiate(dentry, &fhandle, &fattr);
+		status = nfs_instantiate(dentry, &fhandle, &fattr, NULL);
 	}
 	return status;
 }
 
 static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
-		struct page *page, unsigned int len, struct iattr *sattr)
+		struct page *page, unsigned int len, struct iattr *sattr,
+		struct rpc_groups *fsg)
 {
 	struct nfs4_exception exception = { };
 	int err;
@@ -2171,13 +2177,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;
@@ -2290,13 +2296,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 linux-source-2.6.26.orig/fs/nfs/proc.c linux-source-2.6.26/fs/nfs/proc.c
--- linux-source-2.6.26.orig/fs/nfs/proc.c	2010-08-11 10:07:24.000000000 +0200
+++ linux-source-2.6.26/fs/nfs/proc.c	2010-08-11 13:23:12.000000000 +0200
@@ -6,7 +6,7 @@
  *  OS-independent nfs remote procedure call functions
  *
  *  Tuned by Alan Cox <A.Cox@swansea.ac.uk> for >3K buffers
- *  so at last we can have decent(ish) throughput off a 
+ *  so at last we can have decent(ish) throughput off a
  *  Sun server.
  *
  *  Coding optimized and cleaned up by Florian La Roche.
@@ -47,6 +47,34 @@
 
 #define NFSDBG_FACILITY		NFSDBG_PROC
 
+static __inline__ int
+nfs2_rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp,
+	      struct rpc_cred *cred, int flags)
+{
+	struct rpc_message msg = {
+		.rpc_proc	= &nfs_procedures[proc],
+		.rpc_argp	= argp,
+		.rpc_resp	= resp,
+		.rpc_cred	= cred,
+	};
+	return rpc_call_sync(clnt, &msg, flags);
+}
+
+static int
+nfs2_rpc(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp,
+	 struct rpc_groups *fsg)
+{
+	struct rpc_cred	*cred;
+	int		res;
+
+	cred = rpcauth_lookupcred(clnt->cl_auth, fsg, 0);
+	if (IS_ERR(cred))
+		return PTR_ERR(cred);
+	res = nfs2_rpc_call(clnt, proc, argp, resp, cred, 0);
+	put_rpccred(cred);
+	return res;
+}
+
 /*
  * Bare-bones access to getattr: this is for nfs_read_super.
  */
@@ -56,29 +84,16 @@ nfs_proc_get_root(struct nfs_server *ser
 {
 	struct nfs_fattr *fattr = info->fattr;
 	struct nfs2_fsstat fsinfo;
-	struct rpc_message msg = {
-		.rpc_proc	= &nfs_procedures[NFSPROC_GETATTR],
-		.rpc_argp	= fhandle,
-		.rpc_resp	= fattr,
-	};
 	int status;
 
 	dprintk("%s: call getattr\n", __func__);
 	nfs_fattr_init(fattr);
-	status = rpc_call_sync(server->client, &msg, 0);
-	/* Retry with default authentication if different */
-	if (status && server->nfs_client->cl_rpcclient != server->client)
-		status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0);
+	status = nfs2_rpc(server->nfs_client->cl_rpcclient, NFSPROC_GETATTR, fhandle, fattr, NULL);
 	dprintk("%s: reply getattr: %d\n", __func__, status);
 	if (status)
 		return status;
 	dprintk("%s: call statfs\n", __func__);
-	msg.rpc_proc = &nfs_procedures[NFSPROC_STATFS];
-	msg.rpc_resp = &fsinfo;
-	status = rpc_call_sync(server->client, &msg, 0);
-	/* Retry with default authentication if different */
-	if (status && server->nfs_client->cl_rpcclient != server->client)
-		status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0);
+	status = nfs2_rpc(server->nfs_client->cl_rpcclient, NFSPROC_STATFS, fhandle, &fsinfo, NULL);
 	dprintk("%s: reply statfs: %d\n", __func__, status);
 	if (status)
 		return status;
@@ -101,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 */
@@ -136,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);
@@ -145,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),
@@ -156,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;
 }
@@ -179,21 +180,17 @@ static int nfs_proc_readlink(struct inod
 		.pglen		= pglen,
 		.pages		= &page
 	};
-	struct rpc_message msg = {
-		.rpc_proc	= &nfs_procedures[NFSPROC_READLINK],
-		.rpc_argp	= &args,
-	};
 	int			status;
 
 	dprintk("NFS call  readlink\n");
-	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
+	status = nfs2_rpc(NFS_CLIENT(inode), NFSPROC_READLINK, &args, NULL, NULL);
 	dprintk("NFS reply readlink: %d\n", status);
 	return status;
 }
 
 static int
 nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
-		int flags, struct nameidata *nd)
+		int flags, struct nameidata *nd, struct rpc_groups *fsg)
 {
 	struct nfs_fh		fhandle;
 	struct nfs_fattr	fattr;
@@ -207,19 +204,14 @@ nfs_proc_create(struct inode *dir, struc
 		.fh		= &fhandle,
 		.fattr		= &fattr
 	};
-	struct rpc_message msg = {
-		.rpc_proc	= &nfs_procedures[NFSPROC_CREATE],
-		.rpc_argp	= &arg,
-		.rpc_resp	= &res,
-	};
 	int			status;
 
 	nfs_fattr_init(&fattr);
 	dprintk("NFS call  create %s\n", dentry->d_name.name);
-	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, fsg);
 	nfs_mark_for_revalidate(dir);
 	if (status == 0)
-		status = nfs_instantiate(dentry, &fhandle, &fattr);
+		status = nfs_instantiate(dentry, &fhandle, &fattr, fsg);
 	dprintk("NFS reply create: %d\n", status);
 	return status;
 }
@@ -229,7 +221,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;
@@ -243,11 +235,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);
@@ -262,36 +249,32 @@ nfs_proc_mknod(struct inode *dir, struct
 	}
 
 	nfs_fattr_init(&fattr);
-	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, fsg);
 	nfs_mark_for_revalidate(dir);
 
 	if (status == -EINVAL && S_ISFIFO(mode)) {
 		sattr->ia_mode = mode;
 		nfs_fattr_init(&fattr);
-		status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+		status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, fsg);
 	}
 	if (status == 0)
-		status = nfs_instantiate(dentry, &fhandle, &fattr);
+		status = nfs_instantiate(dentry, &fhandle, &fattr, fsg);
 	dprintk("NFS reply mknod: %d\n", status);
 	return status;
 }
   
 static int
-nfs_proc_remove(struct inode *dir, struct qstr *name)
+nfs_proc_remove(struct inode *dir, struct qstr *name, struct rpc_groups *fsg)
 {
 	struct nfs_removeargs arg = {
 		.fh = NFS_FH(dir),
 		.name.len = name->len,
 		.name.name = name->name,
 	};
-	struct rpc_message msg = { 
-		.rpc_proc = &nfs_procedures[NFSPROC_REMOVE],
-		.rpc_argp = &arg,
-	};
 	int			status;
 
 	dprintk("NFS call  remove %s\n", name->name);
-	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_REMOVE, &arg, NULL, fsg);
 	nfs_mark_for_revalidate(dir);
 
 	dprintk("NFS reply remove: %d\n", status);
@@ -312,7 +295,8 @@ static int nfs_proc_unlink_done(struct r
 
 static int
 nfs_proc_rename(struct inode *old_dir, struct qstr *old_name,
-		struct inode *new_dir, struct qstr *new_name)
+		struct inode *new_dir, struct qstr *new_name,
+		struct rpc_groups *fsg)
 {
 	struct nfs_renameargs	arg = {
 		.fromfh		= NFS_FH(old_dir),
@@ -322,14 +306,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);
@@ -337,7 +317,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),
@@ -345,14 +326,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);
@@ -361,7 +338,7 @@ nfs_proc_link(struct inode *inode, struc
 
 static int
 nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
-		 unsigned int len, struct iattr *sattr)
+		 unsigned int len, struct iattr *sattr, struct rpc_groups *fsg)
 {
 	struct nfs_fh fhandle;
 	struct nfs_fattr fattr;
@@ -373,10 +350,6 @@ nfs_proc_symlink(struct inode *dir, stru
 		.pathlen	= len,
 		.sattr		= sattr
 	};
-	struct rpc_message msg = {
-		.rpc_proc	= &nfs_procedures[NFSPROC_SYMLINK],
-		.rpc_argp	= &arg,
-	};
 	int			status;
 
 	if (len > NFS2_MAXPATHLEN)
@@ -384,7 +357,7 @@ nfs_proc_symlink(struct inode *dir, stru
 
 	dprintk("NFS call  symlink %s\n", dentry->d_name.name);
 
-	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	status = nfs2_rpc(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, fsg);
 	nfs_mark_for_revalidate(dir);
 
 	/*
@@ -395,7 +368,7 @@ nfs_proc_symlink(struct inode *dir, stru
 	if (status == 0) {
 		nfs_fattr_init(&fattr);
 		fhandle.size = 0;
-		status = nfs_instantiate(dentry, &fhandle, &fattr);
+		status = nfs_instantiate(dentry, &fhandle, &fattr, fsg);
 	}
 
 	dprintk("NFS reply symlink: %d\n", status);
@@ -403,7 +376,8 @@ nfs_proc_symlink(struct inode *dir, stru
 }
 
 static int
-nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
+nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
+	       struct rpc_groups *fsg)
 {
 	struct nfs_fh fhandle;
 	struct nfs_fattr fattr;
@@ -417,39 +391,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;
@@ -473,15 +438,10 @@ nfs_proc_readdir(struct dentry *dentry, 
 		.count		= count,
 		.pages		= &page,
 	};
-	struct rpc_message	msg = {
-		.rpc_proc	= &nfs_procedures[NFSPROC_READDIR],
-		.rpc_argp	= &arg,
-		.rpc_cred	= cred,
-	};
 	int			status;
 
 	dprintk("NFS call  readdir %d\n", (unsigned int)cookie);
-	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	status = nfs2_rpc_call(NFS_CLIENT(dir), NFSPROC_READDIR, &arg, NULL, cred, 0);
 
 	nfs_invalidate_atime(dir);
 
@@ -494,16 +454,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;
@@ -522,16 +477,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 linux-source-2.6.26.orig/fs/nfs/unlink.c linux-source-2.6.26/fs/nfs/unlink.c
--- linux-source-2.6.26.orig/fs/nfs/unlink.c	2010-08-11 10:07:24.000000000 +0200
+++ linux-source-2.6.26/fs/nfs/unlink.c	2010-08-11 13:23:12.000000000 +0200
@@ -234,7 +234,12 @@ nfs_async_unlink(struct inode *dir, stru
 	if (data == NULL)
 		goto out;
 
-	data->cred = rpc_lookup_cred();
+	if (NFS_PROTO(dir)->version > 3)
+		data->cred = rpc_lookup_cred(NULL);
+	else {
+		struct rpc_groups fsg = { 1, { dir->i_gid } };
+		data->cred = rpc_lookup_cred(&fsg);
+	}
 	if (IS_ERR(data->cred)) {
 		status = PTR_ERR(data->cred);
 		goto out_free;
diff -Nurp linux-source-2.6.26.orig/include/linux/nfs_fs.h linux-source-2.6.26/include/linux/nfs_fs.h
--- linux-source-2.6.26.orig/include/linux/nfs_fs.h	2010-08-11 10:07:36.000000000 +0200
+++ linux-source-2.6.26/include/linux/nfs_fs.h	2010-08-11 13:23:12.000000000 +0200
@@ -407,7 +407,8 @@ extern const struct file_operations nfs_
 extern struct dentry_operations nfs_dentry_operations;
 
 extern void nfs_force_lookup_revalidate(struct inode *dir);
-extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr);
+extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh,
+			   struct nfs_fattr *fattr, struct rpc_groups *fsg);
 extern int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags);
 extern void nfs_access_zap_cache(struct inode *inode);
 
diff -Nurp linux-source-2.6.26.orig/include/linux/nfs_xdr.h linux-source-2.6.26/include/linux/nfs_xdr.h
--- linux-source-2.6.26.orig/include/linux/nfs_xdr.h	2010-08-11 10:07:36.000000000 +0200
+++ linux-source-2.6.26/include/linux/nfs_xdr.h	2010-08-11 13:23:12.000000000 +0200
@@ -777,7 +777,7 @@ struct nfs_write_data {
 struct nfs_access_entry;
 
 /*
- * RPC procedure vector for NFSv2/NFSv3 demuxing
+ * RPC procedure vector for NFSv2/NFSv3/NFSv4 demuxing
  */
 struct nfs_rpc_ops {
 	u32	version;		/* Protocol version */
@@ -793,28 +793,32 @@ struct nfs_rpc_ops {
 	int	(*getattr) (struct nfs_server *, struct nfs_fh *,
 			    struct nfs_fattr *);
 	int	(*setattr) (struct dentry *, struct nfs_fattr *,
-			    struct iattr *);
+			    struct iattr *, struct rpc_groups *);
 	int	(*lookup)  (struct inode *, struct qstr *,
-			    struct nfs_fh *, struct nfs_fattr *);
+			    struct nfs_fh *, struct nfs_fattr *,
+			    struct rpc_groups *);
 	int	(*access)  (struct inode *, struct nfs_access_entry *);
 	int	(*readlink)(struct inode *, struct page *, unsigned int,
 			    unsigned int);
 	int	(*create)  (struct inode *, struct dentry *,
-			    struct iattr *, int, struct nameidata *);
-	int	(*remove)  (struct inode *, struct qstr *);
+			    struct iattr *, int, struct nameidata *,
+			    struct rpc_groups *);
+	int	(*remove)  (struct inode *, struct qstr *, struct rpc_groups *);
 	void	(*unlink_setup)  (struct rpc_message *, struct inode *dir);
 	int	(*unlink_done) (struct rpc_task *, struct inode *);
 	int	(*rename)  (struct inode *, struct qstr *,
-			    struct inode *, struct qstr *);
-	int	(*link)    (struct inode *, struct inode *, struct qstr *);
+			    struct inode *, struct qstr *, struct rpc_groups *);
+	int	(*link)    (struct inode *, struct inode *, struct qstr *,
+			    struct rpc_groups *);
 	int	(*symlink) (struct inode *, struct dentry *, struct page *,
-			    unsigned int, struct iattr *);
-	int	(*mkdir)   (struct inode *, struct dentry *, struct iattr *);
-	int	(*rmdir)   (struct inode *, struct qstr *);
+			    unsigned int, struct iattr *, struct rpc_groups *);
+	int	(*mkdir)   (struct inode *, struct dentry *, struct iattr *,
+			    struct rpc_groups *);
+	int	(*rmdir)   (struct inode *, struct qstr *, struct rpc_groups *);
 	int	(*readdir) (struct dentry *, struct rpc_cred *,
 			    u64, struct page *, unsigned int, int);
 	int	(*mknod)   (struct inode *, struct dentry *, struct iattr *,
-			    dev_t);
+			    dev_t, struct rpc_groups *);
 	int	(*statfs)  (struct nfs_server *, struct nfs_fh *,
 			    struct nfs_fsstat *);
 	int	(*fsinfo)  (struct nfs_server *, struct nfs_fh *,
diff -Nurp linux-source-2.6.26.orig/include/linux/sunrpc/auth.h linux-source-2.6.26/include/linux/sunrpc/auth.h
--- linux-source-2.6.26.orig/include/linux/sunrpc/auth.h	2010-08-11 10:07:37.000000000 +0200
+++ linux-source-2.6.26/include/linux/sunrpc/auth.h	2010-08-11 13:23:12.000000000 +0200
@@ -15,17 +15,23 @@
 #include <linux/sunrpc/msg_prot.h>
 #include <linux/sunrpc/xdr.h>
 
+#include <linux/sched.h>
 #include <asm/atomic.h>
 #include <linux/rcupdate.h>
 
 /* size of the nodename buffer */
 #define UNX_MAXNODENAME	32
 
+struct rpc_groups {
+	int	ngroups;
+	gid_t	groups[RPC_MAXGROUPS];
+};
+
 /* Work around the lack of a VFS credential */
 struct auth_cred {
 	uid_t	uid;
 	gid_t	gid;
-	struct group_info *group_info;
+	struct rpc_groups rg;
 	unsigned char machine_cred : 1;
 };
 
@@ -130,7 +136,7 @@ void __init		rpcauth_init_module(void);
 void __exit		rpcauth_remove_module(void);
 void __exit		rpc_destroy_generic_auth(void);
 
-struct rpc_cred *	rpc_lookup_cred(void);
+struct rpc_cred *	rpc_lookup_cred(struct rpc_groups *);
 struct rpc_cred *	rpc_lookup_machine_cred(void);
 int			rpcauth_register(const struct rpc_authops *);
 int			rpcauth_unregister(const struct rpc_authops *);
@@ -138,7 +144,7 @@ struct rpc_auth *	rpcauth_create(rpc_aut
 void			rpcauth_release(struct rpc_auth *);
 struct rpc_cred *	rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int);
 void			rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *);
-struct rpc_cred *	rpcauth_lookupcred(struct rpc_auth *, int);
+struct rpc_cred *	rpcauth_lookupcred(struct rpc_auth *, struct rpc_groups *, int);
 void			rpcauth_bindcred(struct rpc_task *, struct rpc_cred *, int);
 void			rpcauth_generic_bind_cred(struct rpc_task *, struct rpc_cred *);
 void			put_rpccred(struct rpc_cred *);
diff -Nurp linux-source-2.6.26.orig/include/linux/sunrpc/msg_prot.h linux-source-2.6.26/include/linux/sunrpc/msg_prot.h
--- linux-source-2.6.26.orig/include/linux/sunrpc/msg_prot.h	2010-08-11 10:07:37.000000000 +0200
+++ linux-source-2.6.26/include/linux/sunrpc/msg_prot.h	2010-08-11 13:23:12.000000000 +0200
@@ -79,6 +79,7 @@ enum rpc_auth_stat {
 };
 
 #define RPC_MAXNETNAMELEN	256
+#define RPC_MAXGROUPS		16
 
 /*
  * From RFC 1831:
diff -Nurp linux-source-2.6.26.orig/include/linux/sunrpc/svcauth.h linux-source-2.6.26/include/linux/sunrpc/svcauth.h
--- linux-source-2.6.26.orig/include/linux/sunrpc/svcauth.h	2010-08-11 10:07:37.000000000 +0200
+++ linux-source-2.6.26/include/linux/sunrpc/svcauth.h	2010-08-11 13:23:12.000000000 +0200
@@ -16,7 +16,6 @@
 #include <linux/sunrpc/cache.h>
 #include <linux/hash.h>
 
-#define SVC_CRED_NGROUPS	32
 struct svc_cred {
 	uid_t			cr_uid;
 	gid_t			cr_gid;
diff -Nurp linux-source-2.6.26.orig/net/sunrpc/auth.c linux-source-2.6.26/net/sunrpc/auth.c
--- linux-source-2.6.26.orig/net/sunrpc/auth.c	2010-08-11 10:07:43.000000000 +0200
+++ linux-source-2.6.26/net/sunrpc/auth.c	2010-08-11 13:23:12.000000000 +0200
@@ -17,8 +17,11 @@
 
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY	RPCDBG_AUTH
+# define RG(rg,i)		((i) < (rg).ngroups ? (int)(rg).groups[i] : -1)
 #endif
 
+static void rpcauth_add_groups(struct auth_cred *acred, struct rpc_groups *rg);
+
 static DEFINE_SPINLOCK(rpc_authflavor_lock);
 static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = {
 	&authnull_ops,		/* AUTH_NULL */
@@ -348,22 +351,22 @@ out:
 EXPORT_SYMBOL_GPL(rpcauth_lookup_credcache);
 
 struct rpc_cred *
-rpcauth_lookupcred(struct rpc_auth *auth, int flags)
+rpcauth_lookupcred(struct rpc_auth *auth, struct rpc_groups *rg, int flags)
 {
 	struct auth_cred acred = {
 		.uid = current->fsuid,
-		.gid = current->fsgid,
-		.group_info = current->group_info,
 	};
 	struct rpc_cred *ret;
 
-	dprintk("RPC:       looking up %s cred\n",
-		auth->au_ops->au_name);
-	get_group_info(acred.group_info);
+	dprintk("RPC:      looking up %s cred\n", auth->au_ops->au_name);
+
+	rpcauth_add_groups(&acred, rg);
 	ret = auth->au_ops->lookup_cred(auth, &acred, flags);
-	put_group_info(acred.group_info);
+
+	dprintk("RPC:      cred %p\n", ret);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(rpcauth_lookupcred);
 
 void
 rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred,
@@ -382,6 +385,41 @@ rpcauth_init_cred(struct rpc_cred *cred,
 }
 EXPORT_SYMBOL_GPL(rpcauth_init_cred);
 
+/*
+ * Generic function for adding groups to acred. When there are too many then
+ * try to be smart by picking only the relevant ones from our secondary group list.
+ */
+static void rpcauth_add_groups(struct auth_cred *acred, struct rpc_groups *rg)
+{
+	int	i, n, ngroups;
+	gid_t	gid;
+
+	acred->gid = current->fsgid;
+	ngroups = current->group_info ? current->group_info->ngroups : 0;
+	n = ngroups;
+	if (n <= RPC_MAXGROUPS)
+		rg = NULL;
+	else
+		n = RPC_MAXGROUPS;	/* too many groups for AUTH_UNIX */
+	if (rg) {
+		n = 0;	/* pick the few relevant groups we're a member of */
+		for (i = 0; i < rg->ngroups; ++i) {
+			gid = rg->groups[i];
+			if (in_group_p(gid))
+				acred->rg.groups[n++] = gid;
+		}
+		acred->rg.ngroups = n;
+		dprintk("RPC:      %s(): rg=%d:%d,%d,%d -> %d:%d,%d,%d\n", __func__,
+			rg->ngroups, RG(*rg, 0), RG(*rg, 1), RG(*rg, 2),
+			n, RG(acred->rg, 0), RG(acred->rg, 1), RG(acred->rg, 2));
+	} else {
+		dprintk("RPC:      %s(): ngroups=%d\n", __func__, ngroups);
+		for (i = 0; i < n; ++i)
+			acred->rg.groups[i] = GROUP_AT(current->group_info, i);
+		acred->rg.ngroups = n;
+	}
+}
+
 void
 rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred)
 {
@@ -418,7 +456,7 @@ rpcauth_bind_new_cred(struct rpc_task *t
 
 	dprintk("RPC: %5u looking up %s cred\n",
 		task->tk_pid, auth->au_ops->au_name);
-	ret = rpcauth_lookupcred(auth, 0);
+	ret = rpcauth_lookupcred(auth, NULL, 0);
 	if (!IS_ERR(ret))
 		task->tk_msg.rpc_cred = ret;
 	else
diff -Nurp linux-source-2.6.26.orig/net/sunrpc/auth_generic.c linux-source-2.6.26/net/sunrpc/auth_generic.c
--- linux-source-2.6.26.orig/net/sunrpc/auth_generic.c	2010-08-11 10:07:43.000000000 +0200
+++ linux-source-2.6.26/net/sunrpc/auth_generic.c	2010-08-11 13:23:21.000000000 +0200
@@ -32,9 +32,9 @@ static const struct rpc_credops generic_
 /*
  * Public call interface
  */
-struct rpc_cred *rpc_lookup_cred(void)
+struct rpc_cred *rpc_lookup_cred(struct rpc_groups *rg)
 {
-	return rpcauth_lookupcred(&generic_auth, 0);
+	return rpcauth_lookupcred(&generic_auth, rg, 0);
 }
 EXPORT_SYMBOL_GPL(rpc_lookup_cred);
 
@@ -89,12 +89,7 @@ generic_create_cred(struct rpc_auth *aut
 	rpcauth_init_cred(&gcred->gc_base, acred, &generic_auth, &generic_credops);
 	gcred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
 
-	gcred->acred.uid = acred->uid;
-	gcred->acred.gid = acred->gid;
-	gcred->acred.group_info = acred->group_info;
-	if (gcred->acred.group_info != NULL)
-		get_group_info(gcred->acred.group_info);
-	gcred->acred.machine_cred = acred->machine_cred;
+	gcred->acred = *acred;
 
 	dprintk("RPC:       allocated %s cred %p for uid %d gid %d\n",
 			gcred->acred.machine_cred ? "machine" : "generic",
@@ -108,8 +103,6 @@ generic_free_cred(struct rpc_cred *cred)
 	struct generic_cred *gcred = container_of(cred, struct generic_cred, gc_base);
 
 	dprintk("RPC:       generic_free_cred %p\n", gcred);
-	if (gcred->acred.group_info != NULL)
-		put_group_info(gcred->acred.group_info);
 	kfree(gcred);
 }
 
@@ -133,29 +126,14 @@ static int
 generic_match(struct auth_cred *acred, struct rpc_cred *cred, int flags)
 {
 	struct generic_cred *gcred = container_of(cred, struct generic_cred, gc_base);
-	int i;
 
 	if (gcred->acred.uid != acred->uid ||
 	    gcred->acred.gid != acred->gid ||
+	    gcred->acred.rg.ngroups != acred->rg.ngroups ||
+	    memcmp(gcred->acred.rg.groups, acred->rg.groups, acred->rg.ngroups * sizeof (gid_t)) ||
 	    gcred->acred.machine_cred != acred->machine_cred)
-		goto out_nomatch;
-
-	/* Optimisation in the case where pointers are identical... */
-	if (gcred->acred.group_info == acred->group_info)
-		goto out_match;
-
-	/* Slow path... */
-	if (gcred->acred.group_info->ngroups != acred->group_info->ngroups)
-		goto out_nomatch;
-	for (i = 0; i < gcred->acred.group_info->ngroups; i++) {
-		if (GROUP_AT(gcred->acred.group_info, i) !=
-				GROUP_AT(acred->group_info, i))
-			goto out_nomatch;
-	}
-out_match:
+		return 0;
 	return 1;
-out_nomatch:
-	return 0;
 }
 
 void __init rpc_init_generic_auth(void)
diff -Nurp linux-source-2.6.26.orig/net/sunrpc/auth_gss/auth_gss.c linux-source-2.6.26/net/sunrpc/auth_gss/auth_gss.c
--- linux-source-2.6.26.orig/net/sunrpc/auth_gss/auth_gss.c	2010-08-11 10:07:43.000000000 +0200
+++ linux-source-2.6.26/net/sunrpc/auth_gss/auth_gss.c	2010-08-11 13:23:12.000000000 +0200
@@ -63,8 +63,6 @@ static const struct rpc_credops gss_null
 # define RPCDBG_FACILITY	RPCDBG_AUTH
 #endif
 
-#define NFS_NGROUPS	16
-
 #define GSS_CRED_SLACK		1024		/* XXX: unused */
 /* length of a krb5 verifier (48), plus data added before arguments when
  * using integrity (two 4-byte integers): */
diff -Nurp linux-source-2.6.26.orig/net/sunrpc/auth_unix.c linux-source-2.6.26/net/sunrpc/auth_unix.c
--- linux-source-2.6.26.orig/net/sunrpc/auth_unix.c	2010-08-11 10:07:43.000000000 +0200
+++ linux-source-2.6.26/net/sunrpc/auth_unix.c	2010-08-11 13:23:12.000000000 +0200
@@ -12,12 +12,10 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/auth.h>
 
-#define NFS_NGROUPS	16
-
 struct unx_cred {
 	struct rpc_cred		uc_base;
 	gid_t			uc_gid;
-	gid_t			uc_gids[NFS_NGROUPS];
+	gid_t			uc_gids[RPC_MAXGROUPS];
 };
 #define uc_uid			uc_base.cr_uid
 
@@ -60,8 +58,7 @@ static struct rpc_cred *
 unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
 {
 	struct unx_cred	*cred;
-	unsigned int groups = 0;
-	unsigned int i;
+	int n;
 
 	dprintk("RPC:       allocating UNIX cred for uid %d gid %d\n",
 			acred->uid, acred->gid);
@@ -72,16 +69,11 @@ unx_create_cred(struct rpc_auth *auth, s
 	rpcauth_init_cred(&cred->uc_base, acred, auth, &unix_credops);
 	cred->uc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
 
-	if (acred->group_info != NULL)
-		groups = acred->group_info->ngroups;
-	if (groups > NFS_NGROUPS)
-		groups = NFS_NGROUPS;
-
+	n = acred->rg.ngroups;
 	cred->uc_gid = acred->gid;
-	for (i = 0; i < groups; i++)
-		cred->uc_gids[i] = GROUP_AT(acred->group_info, i);
-	if (i < NFS_NGROUPS)
-		cred->uc_gids[i] = NOGROUP;
+	memcpy(cred->uc_gids, acred->rg.groups, n * sizeof (gid_t));
+	if (n < RPC_MAXGROUPS)
+		cred->uc_gids[n] = NOGROUP;
 
 	return &cred->uc_base;
 }
@@ -115,21 +107,12 @@ static int
 unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags)
 {
 	struct unx_cred	*cred = container_of(rcred, struct unx_cred, uc_base);
-	unsigned int groups = 0;
-	unsigned int i;
-
+	int n = acred->rg.ngroups;
 
 	if (cred->uc_uid != acred->uid || cred->uc_gid != acred->gid)
 		return 0;
 
-	if (acred->group_info != NULL)
-		groups = acred->group_info->ngroups;
-	if (groups > NFS_NGROUPS)
-		groups = NFS_NGROUPS;
-	for (i = 0; i < groups ; i++)
-		if (cred->uc_gids[i] != GROUP_AT(acred->group_info, i))
-			return 0;
-	return 1;
+	return !memcmp(cred->uc_gids, acred->rg.groups, n * sizeof (gid_t));
 }
 
 /*
@@ -156,7 +139,7 @@ unx_marshal(struct rpc_task *task, __be3
 	*p++ = htonl((u32) cred->uc_uid);
 	*p++ = htonl((u32) cred->uc_gid);
 	hold = p++;
-	for (i = 0; i < 16 && cred->uc_gids[i] != (gid_t) NOGROUP; i++)
+	for (i = 0; i < RPC_MAXGROUPS && cred->uc_gids[i] != (gid_t) NOGROUP; i++)
 		*p++ = htonl((u32) cred->uc_gids[i]);
 	*hold = htonl(p - hold - 1);		/* gid array length */
 	*base = htonl((p - base - 1) << 2);	/* cred length */
diff -Nurp linux-source-2.6.26.orig/net/sunrpc/svcauth_unix.c linux-source-2.6.26/net/sunrpc/svcauth_unix.c
--- linux-source-2.6.26.orig/net/sunrpc/svcauth_unix.c	2010-08-11 10:07:43.000000000 +0200
+++ linux-source-2.6.26/net/sunrpc/svcauth_unix.c	2010-08-11 13:23:12.000000000 +0200
@@ -815,7 +815,7 @@ svcauth_unix_accept(struct svc_rqst *rqs
 	cred->cr_uid = svc_getnl(argv);		/* uid */
 	cred->cr_gid = svc_getnl(argv);		/* gid */
 	slen = svc_getnl(argv);			/* gids length */
-	if (slen > 16 || (len -= (slen + 2)*4) < 0)
+	if (slen > RPC_MAXGROUPS || (len -= (slen + 2)*4) < 0)
 		goto badcred;
 	if (unix_gid_find(cred->cr_uid, &cred->cr_group_info, rqstp)
 	    == -EAGAIN)

Reply to: