lkml.org 
[lkml]   [2000]   [Aug]   [2]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject2.4.0-test5 [PATCH]: bypass ngroups limitation (16) in NFS/RPC protocol

The RPC layer used by the NFS client restricts the number
of groups to 16. This seems to be a hard protocol limit. The
patch below gets around this limitation by implementing
a group id cache in the RPC layer.

Permission checking is still done at the server but now
the secondary group list is truncated in a more intelligent
way. A similar effect could be achieved when the user calls
setgroups() to reorder the secondary group list based on
the exepected UNIX permission checks performed at the server
(AUTH_UNIX). Of course that is not possible unless you're root.
If RPC is going to truncate the secondary group list then we
might just as well choose the groups from the group list.

The fast path is for processes with <16 groups of course.

comments? flames?

--
Frank
diff -u linux/fs/nfs/dir.c.nfs-ngroups linux/fs/nfs/dir.c
--- linux/fs/nfs/dir.c.nfs-ngroups Mon Jul 31 23:49:39 2000
+++ linux/fs/nfs/dir.c Wed Aug 2 22:52:04 2000
@@ -521,6 +521,9 @@
/*
* Do a new lookup and check the dentry attributes.
*/
+ if (__rpc_register_group(dir_i->i_gid))
+ goto out_bad; /* no way to pass -ENOMEM back */
+
error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name, &fhandle,
&fattr);
if (error)
@@ -638,6 +641,9 @@

dfprintk(VFS, "NFS: lookup(%s/%s)\n",
dir->d_name.name, dentry->d_name.name);
+ error = __rpc_register_group(dir_i->i_gid);
+ if (error)
+ goto out;

error = -ENAMETOOLONG;
if (dentry->d_name.len > NFS_SERVER(dir_i)->namelen)
@@ -704,6 +710,9 @@

dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+ error = __rpc_register_group(dir_i->i_gid);
+ if (error)
+ goto out;

attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;
@@ -721,6 +730,7 @@
error = nfs_instantiate(dentry, &fhandle, &fattr);
if (error || fhandle.size == 0)
d_drop(dentry);
+out:
return error;
}

@@ -737,6 +747,9 @@

dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+ error = __rpc_register_group(dir_i->i_gid);
+ if (error)
+ goto out;

attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;
@@ -748,6 +761,7 @@
error = nfs_instantiate(dentry, &fhandle, &fattr);
if (error || fhandle.size == 0)
d_drop(dentry);
+out:
return error;
}

@@ -764,6 +778,9 @@

dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+ error = __rpc_register_group(dir_i->i_gid);
+ if (error)
+ goto out;

attr.ia_valid = ATTR_MODE;
attr.ia_mode = mode | S_IFDIR;
@@ -784,6 +801,7 @@
error = nfs_instantiate(dentry, &fhandle, &fattr);
if (error || fhandle.size == 0)
d_drop(dentry);
+out:
return error;
}

@@ -794,9 +812,12 @@

dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+ error = __rpc_register_group(dir_i->i_gid);

- nfs_zap_caches(dir_i);
- error = NFS_PROTO(dir_i)->rmdir(dir, &dentry->d_name);
+ if (!error) {
+ nfs_zap_caches(dir_i);
+ error = NFS_PROTO(dir_i)->rmdir(dir, &dentry->d_name);
+ }

return error;
}
@@ -935,6 +956,10 @@

dfprintk(VFS, "NFS: unlink(%x/%ld, %s)\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
+ if ( (error = __rpc_register_group(dentry->d_inode->i_gid))
+ || (error = __rpc_register_group(dir->i_gid))
+ )
+ goto out;

error = nfs_sillyrename(dir, dentry);
if (error && error != -EBUSY) {
@@ -943,6 +968,7 @@
nfs_renew_times(dentry);
}
}
+out:
return error;
}

@@ -959,6 +985,9 @@

dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
dir_i->i_dev, dir_i->i_ino, dentry->d_name.name, symname);
+ error = __rpc_register_group(dir_i->i_gid);
+ if (error)
+ goto out;

error = -ENAMETOOLONG;
maxlen = (NFS_PROTO(dir_i)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN;
@@ -1006,6 +1035,9 @@
dfprintk(VFS, "NFS: link(%s/%s -> %s/%s)\n",
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
dentry->d_parent->d_name.name, dentry->d_name.name);
+ error = __rpc_register_group(dir_i->i_gid);
+ if (error)
+ goto out;

/*
* Drop the dentry in advance to force a new lookup.
@@ -1016,6 +1048,7 @@
nfs_zap_caches(dir_i);
NFS_CACHEINV(inode);
error = NFS_PROTO(dir_i)->link(old_dentry, dir, &dentry->d_name);
+out:
return error;
}

@@ -1049,7 +1082,7 @@
struct inode *old_inode = old_dentry->d_inode;
struct inode *new_inode = new_dentry->d_inode;
struct dentry *dentry = NULL, *rehash = NULL;
- int error = -EBUSY;
+ int error;

/*
* To prevent any new references to the target during the rename,
@@ -1064,6 +1097,11 @@
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
atomic_read(&new_dentry->d_count));
+ if ( (error = __rpc_register_group(old_inode->i_gid))
+ || (error = __rpc_register_group(old_dir->i_gid))
+ || (error = __rpc_register_group(new_dir->i_gid))
+ )
+ goto out;

/*
* First check whether the target is busy ... we can't
@@ -1073,6 +1111,7 @@
* silly-rename. If the silly-rename succeeds, the
* copied dentry is hashed and becomes the new target.
*/
+ error = -EBUSY;
if (!new_inode)
goto go_ahead;
if (S_ISDIR(new_inode->i_mode))
diff -u linux/fs/nfs/inode.c.nfs-ngroups linux/fs/nfs/inode.c
--- linux/fs/nfs/inode.c.nfs-ngroups Mon Jul 31 23:50:00 2000
+++ linux/fs/nfs/inode.c Wed Aug 2 22:46:17 2000
@@ -816,6 +816,11 @@

if (!S_ISREG(inode->i_mode))
attr->ia_valid &= ~ATTR_SIZE;
+ if (attr->ia_valid & ATTR_GID) {
+ error = __rpc_register_group(attr->ia_gid);
+ if (error)
+ goto out;
+ }

error = nfs_wb_all(inode);
if (error)
@@ -886,13 +891,17 @@
{
struct rpc_auth *auth;
struct rpc_cred *cred;
+ int error;

- lock_kernel();
- auth = NFS_CLIENT(inode)->cl_auth;
- cred = rpcauth_lookupcred(auth, 0);
- filp->private_data = cred;
- unlock_kernel();
- return 0;
+ error = __rpc_register_group(inode->i_gid);
+ if (!error) {
+ lock_kernel();
+ auth = NFS_CLIENT(inode)->cl_auth;
+ cred = rpcauth_lookupcred(auth, 0);
+ filp->private_data = cred;
+ unlock_kernel();
+ }
+ return error;
}

int nfs_release(struct inode *inode, struct file *filp)
@@ -942,6 +951,10 @@
}
}
NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
+
+ status = __rpc_register_group(inode->i_gid);
+ if (status)
+ goto out;

status = NFS_PROTO(inode)->getattr(dentry, &fattr);
if (status) {
diff -u linux/kernel/fork.c.nfs-ngroups linux/kernel/fork.c
--- linux/kernel/fork.c.nfs-ngroups Mon Jul 31 23:50:24 2000
+++ linux/kernel/fork.c Mon Jul 31 23:50:27 2000
@@ -18,6 +18,7 @@
#include <linux/smp_lock.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
+#include <linux/sunrpc/gidcache.h>

#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -636,6 +637,18 @@
p->flags = new_flags;
}

+static inline int copy_gidcache(struct task_struct *p)
+{
+ struct rpc_gidcache *gidcache = p->gidcache;
+
+ if (gidcache) {
+ p->gidcache = rpc_gidcache_dup(gidcache);
+ if (p->gidcache == NULL)
+ return -1;
+ }
+ return 0;
+}
+
/*
* Ok, this is the main fork-routine. It copies the system process
* information (task[nr]) and sets up the necessary registers. It
@@ -739,11 +752,13 @@
goto bad_fork_cleanup_files;
if (copy_sighand(clone_flags, p))
goto bad_fork_cleanup_fs;
- if (copy_mm(clone_flags, p))
+ if (copy_gidcache(p))
goto bad_fork_cleanup_sighand;
+ if (copy_mm(clone_flags, p))
+ goto bad_fork_cleanup_gidcache;
retval = copy_thread(0, clone_flags, usp, p, regs);
if (retval)
- goto bad_fork_cleanup_sighand;
+ goto bad_fork_cleanup_gidcache;
p->semundo = NULL;

/* Our parent execution domain becomes current domain
@@ -790,6 +805,8 @@
down(&sem);
return retval;

+bad_fork_cleanup_gidcache:
+ exit_gidcache(p);
bad_fork_cleanup_sighand:
exit_sighand(p);
bad_fork_cleanup_fs:
diff -u linux/kernel/exit.c.nfs-ngroups linux/kernel/exit.c
--- linux/kernel/exit.c.nfs-ngroups Mon Jul 31 23:50:24 2000
+++ linux/kernel/exit.c Mon Jul 31 23:50:27 2000
@@ -12,6 +12,7 @@
#ifdef CONFIG_BSD_PROCESS_ACCT
#include <linux/acct.h>
#endif
+#include <linux/sunrpc/gidcache.h>

#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -271,6 +272,19 @@
__exit_sighand(tsk);
}

+static inline void __exit_gidcache(struct task_struct *tsk)
+{
+ if (tsk->gidcache) {
+ rpc_gidcache_del(tsk->gidcache);
+ tsk->gidcache = NULL;
+ }
+}
+
+void exit_gidcache(struct task_struct *tsk)
+{
+ __exit_gidcache(tsk);
+}
+
/*
* We can use these to temporarily drop into
* "lazy TLB" mode and back.
@@ -440,6 +454,7 @@
#ifdef CONFIG_BSD_PROCESS_ACCT
acct_process(code);
#endif
+ __exit_gidcache(tsk);
lock_kernel();
sem_exit();
__exit_mm(tsk);
diff -u linux/kernel/sys.c.nfs-ngroups linux/kernel/sys.c
--- linux/kernel/sys.c.nfs-ngroups Mon Jul 31 23:50:25 2000
+++ linux/kernel/sys.c Mon Jul 31 23:50:27 2000
@@ -911,6 +911,7 @@
if(copy_from_user(current->groups, grouplist, gidsetsize * sizeof(gid_t)))
return -EFAULT;
current->ngroups = gidsetsize;
+ exit_gidcache(current);
return 0;
}

diff -u linux/include/linux/sunrpc/clnt.h.nfs-ngroups linux/include/linux/sunrpc/clnt.h
--- linux/include/linux/sunrpc/clnt.h.nfs-ngroups Mon Jul 31 23:49:12 2000
+++ linux/include/linux/sunrpc/clnt.h Mon Jul 31 23:55:09 2000
@@ -120,6 +120,15 @@
void rpc_restart_call(struct rpc_task *);
void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset);
void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset);
+int rpc_register_group(gid_t gid);
+
+static __inline__
+int __rpc_register_group(gid_t gid)
+{
+ if (current->ngroups <= RPC_NGROUPS || gid == current->fsgid)
+ return 0;
+ return rpc_register_group(gid);
+}

static __inline__
int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
diff -u linux/include/linux/sunrpc/msg_prot.h.nfs-ngroups linux/include/linux/sunrpc/msg_prot.h
--- linux/include/linux/sunrpc/msg_prot.h.nfs-ngroups Mon Apr 7 20:35:32 1997
+++ linux/include/linux/sunrpc/msg_prot.h Mon Jul 31 23:50:27 2000
@@ -57,6 +57,7 @@
#define RPC_PMAP_PORT 111

#define RPC_MAXNETNAMELEN 256
+#define RPC_NGROUPS 16

#endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_MSGPROT_H_ */
diff -u linux/include/linux/sunrpc/gidcache.h.nfs-ngroups linux/include/linux/sunrpc/gidcache.h
--- linux/include/linux/sunrpc/gidcache.h.nfs-ngroups Mon Jul 31 23:50:27 2000
+++ linux/include/linux/sunrpc/gidcache.h Mon Jul 31 23:50:27 2000
@@ -0,0 +1,48 @@
+/*
+ * include/linux/sunrpc/gidcache.h
+ *
+ * Copyright (C) 2000, Frank van Maarseveen <fvm@tasking.nl>
+ */
+
+#ifndef _LINUX_SUNRPC_RPCGIDCACHE_H_
+#define _LINUX_SUNRPC_RPCGIDCACHE_H_
+
+#ifdef __KERNEL__
+
+#include <linux/sunrpc/msg_prot.h>
+
+struct rpc_gidcache {
+ int ngroups;
+ gid_t groups[RPC_NGROUPS];
+ unsigned short lru[RPC_NGROUPS];
+};
+
+static inline struct rpc_gidcache *rpc_gidcache_new(void)
+{
+ struct rpc_gidcache *gidcache;
+
+ gidcache = kmalloc(sizeof(struct rpc_gidcache), GFP_KERNEL);
+ if (gidcache) {
+ gidcache->ngroups = 0;
+ }
+ return gidcache;
+}
+
+static inline void rpc_gidcache_del(struct rpc_gidcache *gidcache)
+{
+ kfree(gidcache);
+}
+
+static inline struct rpc_gidcache *rpc_gidcache_dup(struct rpc_gidcache *p)
+{
+ struct rpc_gidcache *gidcache;
+
+ gidcache = kmalloc(sizeof(struct rpc_gidcache), GFP_KERNEL);
+ if (gidcache) {
+ memcpy(gidcache, p, sizeof(*gidcache));
+ }
+ return gidcache;
+}
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_SUNRPC_RPCGIDCACHE_H_ */
diff -u linux/include/linux/sched.h.nfs-ngroups linux/include/linux/sched.h
--- linux/include/linux/sched.h.nfs-ngroups Mon Jul 31 23:50:24 2000
+++ linux/include/linux/sched.h Mon Jul 31 23:52:21 2000
@@ -330,6 +330,7 @@
kernel_cap_t cap_effective, cap_inheritable, cap_permitted;
int keep_capabilities:1;
struct user_struct *user;
+ struct rpc_gidcache *gidcache;
/* limits */
struct rlimit rlim[RLIM_NLIMITS];
unsigned short used_math;
@@ -689,6 +690,7 @@
extern void exit_mm(struct task_struct *);
extern void exit_files(struct task_struct *);
extern void exit_sighand(struct task_struct *);
+extern void exit_gidcache(struct task_struct *);

extern void daemonize(void);

diff -u linux/net/sunrpc/auth_unix.c.nfs-ngroups linux/net/sunrpc/auth_unix.c
--- linux/net/sunrpc/auth_unix.c.nfs-ngroups Mon Mar 20 17:14:04 2000
+++ linux/net/sunrpc/auth_unix.c Mon Jul 31 23:50:27 2000
@@ -12,13 +12,13 @@
#include <linux/in.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/auth.h>
+#include <linux/sunrpc/gidcache.h>

-#define NFS_NGROUPS 16
struct unx_cred {
struct rpc_cred uc_base;
uid_t uc_fsuid;
gid_t uc_gid, uc_fsgid;
- gid_t uc_gids[NFS_NGROUPS];
+ gid_t uc_gids[RPC_NGROUPS];
};
#define uc_uid uc_base.cr_uid
#define uc_count uc_base.cr_count
@@ -78,18 +78,28 @@
cred->uc_gid = cred->uc_fsgid = 0;
cred->uc_gids[0] = NOGROUP;
} else {
- int groups = current->ngroups;
- if (groups > NFS_NGROUPS)
- groups = NFS_NGROUPS;
+ int ngroups;
+ gid_t *groups;

+ if (current->gidcache) {
+ ngroups = current->gidcache->ngroups;
+ groups = current->gidcache->groups;
+ } else {
+ ngroups = current->ngroups;
+ groups = current->groups;
+ }
+ if (ngroups > RPC_NGROUPS) {
+ ngroups = RPC_NGROUPS;
+ printk(KERN_WARNING "unx_create_cred: too many groups.\n");
+ }
cred->uc_uid = current->uid;
cred->uc_gid = current->gid;
cred->uc_fsuid = current->fsuid;
cred->uc_fsgid = current->fsgid;
- for (i = 0; i < groups; i++)
- cred->uc_gids[i] = (gid_t) current->groups[i];
- if (i < NFS_NGROUPS)
- cred->uc_gids[i] = NOGROUP;
+ for (i = 0; i < ngroups; i++)
+ cred->uc_gids[i] = groups[i];
+ if (i < RPC_NGROUPS)
+ cred->uc_gids[i] = NOGROUP;
}

return (struct rpc_cred *) cred;
@@ -135,7 +145,8 @@
int i;

if (!(taskflags & RPC_TASK_ROOTCREDS)) {
- int groups;
+ int ngroups;
+ gid_t *groups;

if (cred->uc_uid != current->uid
|| cred->uc_gid != current->gid
@@ -143,11 +154,19 @@
|| cred->uc_fsgid != current->fsgid)
return 0;

- groups = current->ngroups;
- if (groups > NFS_NGROUPS)
- groups = NFS_NGROUPS;
- for (i = 0; i < groups ; i++)
- if (cred->uc_gids[i] != (gid_t) current->groups[i])
+ if (current->gidcache) {
+ ngroups = current->gidcache->ngroups;
+ groups = current->gidcache->groups;
+ } else {
+ ngroups = current->ngroups;
+ groups = current->groups;
+ }
+ if (ngroups > RPC_NGROUPS) {
+ ngroups = RPC_NGROUPS;
+ printk(KERN_WARNING "unx_match: too many groups.\n");
+ }
+ for (i = 0; i < ngroups ; i++)
+ if (cred->uc_gids[i] != groups[i])
return 0;
return 1;
}
@@ -188,7 +207,7 @@
*p++ = htonl((u32) cred->uc_fsgid);
}
hold = p++;
- for (i = 0; i < 16 && cred->uc_gids[i] != (gid_t) NOGROUP; i++)
+ for (i = 0; i < RPC_NGROUPS && 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 -u linux/net/sunrpc/clnt.c.nfs-ngroups linux/net/sunrpc/clnt.c
--- linux/net/sunrpc/clnt.c.nfs-ngroups Mon Jul 31 23:49:47 2000
+++ linux/net/sunrpc/clnt.c Mon Jul 31 23:50:27 2000
@@ -19,6 +19,11 @@
*
* Copyright (C) 1992,1993 Rick Sladkey <jrs@world.std.com>
* Copyright (C) 1995,1996 Olaf Kirch <okir@monad.swb.de>
+ *
+ * CHANGES
+ * 2000-07-26 Added rpc_register_group(), allowing a way to get around the
+ * RPC limit of 16 groups on NFS mounted filesystems (AUTH_UNIX).
+ * -- Frank van Maarseveen <fvm@tasking.nl>
*/

#include <asm/system.h>
@@ -30,6 +35,7 @@
#include <linux/utsname.h>

#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/gidcache.h>

#include <linux/nfs.h>

@@ -348,6 +354,89 @@

task->tk_action = call_reserve;
rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
+}
+
+/*
+ * Update the per-process group id cache.
+ *
+ * In rpc_gidcache, groups[n] corresponds with lru[n]. All lru[]
+ * numbers are unique and identify the order in which the groups have been
+ * registered by this function, numbering from 1 to ngroups. The oldest
+ * registered group has value 1. The groups array is kept sorted to avoid
+ * blowing up the RPC credential cache.
+ * The memmoves below could be replaced by something fancier but it would only
+ * make a difference in really awkward situations. RPC_NGROUPS is 16 at most.
+ *
+ * This function is called via __rpc_register_group(), but only when the
+ * process is a member of too many groups for RPC.
+ */
+int
+rpc_register_group(gid_t gid)
+{
+ int ngroups, i, j, n;
+ gid_t *groups;
+ unsigned short *lru;
+ struct rpc_gidcache *gidcache = current->gidcache;
+
+ if (gidcache == NULL) {
+ gidcache = rpc_gidcache_new();
+ if (gidcache == NULL)
+ return -ENOMEM;
+ current->gidcache = gidcache;
+ }
+
+ ngroups = gidcache->ngroups;
+ groups = gidcache->groups;
+ lru = gidcache->lru;
+ for (i = 0; i < ngroups; ++i) {
+ if (groups[i] == gid)
+ break;
+ }
+ if (i < ngroups) {
+ unsigned short order = lru[i];
+ if (order != (unsigned short)ngroups) {
+ for (j = 0; j < ngroups; ++j) {
+ if (lru[j] > order)
+ --lru[j];
+ }
+ lru[i] = (unsigned short)ngroups;
+ }
+ return 0; /* ok: group already cached, lru[] updated */
+ }
+ if (!in_group_p(gid))
+ return 0; /* ignore: we're not a member */
+
+ /*
+ * Delete the oldest group (lru[] == 1) when all groups are in use.
+ */
+ if (ngroups == RPC_NGROUPS) {
+ j = 0;
+ for (i = 0; i < ngroups; ++i) {
+ if (!--lru[i])
+ j = i;
+ }
+ n = ngroups - (j + 1);
+ memmove(&groups[j], &groups[j + 1], n * sizeof(*groups));
+ memmove(&lru[j], &lru[j + 1], n * sizeof(*lru));
+ --ngroups;
+ }
+
+ /*
+ * Insert the new group. First find the insertion point.
+ */
+ for (i = 0; i < ngroups; ++i) {
+ if (groups[i] > gid) {
+ break;
+ }
+ }
+ n = ngroups - i;
+ memmove(&groups[i + 1], &groups[i], n * sizeof(*groups));
+ memmove(&lru[i + 1], &lru[i], n * sizeof(*lru));
+ ++ngroups;
+ groups[i] = gid;
+ lru[i] = (unsigned short)ngroups;
+ gidcache->ngroups = ngroups;
+ return 0;
}

/*
diff -u linux/net/sunrpc/sunrpc_syms.c.nfs-ngroups linux/net/sunrpc/sunrpc_syms.c
--- linux/net/sunrpc/sunrpc_syms.c.nfs-ngroups Sat Apr 22 01:08:52 2000
+++ linux/net/sunrpc/sunrpc_syms.c Mon Jul 31 23:50:27 2000
@@ -49,6 +49,7 @@
EXPORT_SYMBOL(rpc_clnt_sigunmask);
EXPORT_SYMBOL(rpc_delay);
EXPORT_SYMBOL(rpc_restart_call);
+EXPORT_SYMBOL(rpc_register_group);

/* Client transport */
EXPORT_SYMBOL(xprt_create_proto);
diff -u linux/net/sunrpc/svcauth.c.nfs-ngroups linux/net/sunrpc/svcauth.c
--- linux/net/sunrpc/svcauth.c.nfs-ngroups Sat Apr 29 07:50:39 2000
+++ linux/net/sunrpc/svcauth.c Mon Jul 31 23:50:27 2000
@@ -138,7 +138,7 @@
cred->cr_gid = ntohl(*bufp++); /* gid */

slen = ntohl(*bufp++); /* gids length */
- if (slen > 16 || (len -= slen + 2) < 0)
+ if (slen > RPC_NGROUPS || (len -= slen + 2) < 0)
goto badcred;
for (i = 0; i < NGROUPS && i < slen; i++)
cred->cr_groups[i] = ntohl(*bufp++);
\
 
 \ /
  Last update: 2005-03-22 13:57    [W:0.051 / U:0.188 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site