--- linux-2.6.11/fs/nfsd/nfs4state.c.orig 2005-03-02 02:38:13.000000000 -0500 +++ linux-2.6.11/fs/nfsd/nfs4state.c 2005-03-18 06:59:15.000000000 -0500 @@ -3250,6 +3250,8 @@ __nfs4_state_shutdown(void) void nfs4_state_shutdown(void) { + if (!nfs4_init) + return; nfs4_lock_state(); nfs4_release_reclaim(); __nfs4_state_shutdown(); --- linux-2.6.11/fs/nfsd/nfssvc.c.orig 2005-03-02 02:38:10.000000000 -0500 +++ linux-2.6.11/fs/nfsd/nfssvc.c 2005-03-18 08:39:53.000000000 -0500 @@ -30,6 +30,7 @@ #include #include #include +#include #include #define NFSDDBG_FACILITY NFSDDBG_SVC @@ -62,6 +63,29 @@ struct nfsd_list { }; struct list_head nfsd_list = LIST_HEAD_INIT(nfsd_list); +extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; + +static struct svc_version * nfsd_version[] = { + [2] = &nfsd_version2, +#if defined(CONFIG_NFSD_V3) + [3] = &nfsd_version3, +#endif +#if defined(CONFIG_NFSD_V4) + [4] = &nfsd_version4, +#endif +}; + +#define NFSD_MINVERS 2 +#define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0])) +struct svc_program nfsd_program = { + .pg_prog = NFS_PROGRAM, /* program number */ + .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ + .pg_vers = nfsd_version, /* version table */ + .pg_name = "nfsd", /* program name */ + .pg_class = "nfsd", /* authentication class */ + .pg_stats = &nfsd_svcstats, /* version table */ +}; + /* * Maximum number of nfsd processes */ @@ -76,23 +100,47 @@ int nfsd_nrthreads(void) } int -nfsd_svc(unsigned short port, int nrservs) +nfsd_svc(unsigned short port, int nrservs, unsigned int ctlbits) { int error; - int none_left; + int none_left, found_one, i; struct list_head *victim; + dprintk("nfsd: creating service (port %d nserver %d ctlbits 0x%x)\n", + port, nrservs, ctlbits); + lock_kernel(); - dprintk("nfsd: creating service\n"); error = -EINVAL; if (nrservs <= 0) nrservs = 0; if (nrservs > NFSD_MAXSERVS) nrservs = NFSD_MAXSERVS; - + /* + * If set, use the ctlbits to define the + * services that will be advertised + */ + if (ctlbits) { + found_one = 0; + for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) { + if (NFSCTL_VERISSET(ctlbits, i)) { + nfsd_program.pg_vers[i] = nfsd_version[i]; + found_one = 1; + } else + nfsd_program.pg_vers[i] = NULL; + } + if (!found_one) { + printk(KERN_ERR "nfsd: no version set (cltbits 0x%x)\n", ctlbits); + goto out; + } + } else { /* otherwise, turn everthing on */ + ctlbits = ~0; + nfsd_program.pg_vers = nfsd_version; + } + /* Readahead param cache - will no-op if it already exists */ error = nfsd_racache_init(2*nrservs); - nfs4_state_init(); + if (NFSCTL_VERISSET(ctlbits, 4)) + nfs4_state_init(); if (error<0) goto out; if (!nfsd_serv) { @@ -101,14 +149,17 @@ nfsd_svc(unsigned short port, int nrserv nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE); if (nfsd_serv == NULL) goto out; - error = svc_makesock(nfsd_serv, IPPROTO_UDP, port); - if (error < 0) - goto failure; - + if (NFSCTL_UDPISSET(ctlbits)) { + error = svc_makesock(nfsd_serv, IPPROTO_UDP, port); + if (error < 0) + goto failure; + } #ifdef CONFIG_NFSD_TCP - error = svc_makesock(nfsd_serv, IPPROTO_TCP, port); - if (error < 0) - goto failure; + if (NFSCTL_TCPISSET(ctlbits)) { + error = svc_makesock(nfsd_serv, IPPROTO_TCP, port); + if (error < 0) + goto failure; + } #endif do_gettimeofday(&nfssvc_boot); /* record boot time */ } else @@ -358,24 +409,3 @@ nfsd_dispatch(struct svc_rqst *rqstp, u3 return 1; } -extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; - -static struct svc_version * nfsd_version[] = { - [2] = &nfsd_version2, -#if defined(CONFIG_NFSD_V3) - [3] = &nfsd_version3, -#endif -#if defined(CONFIG_NFSD_V4) - [4] = &nfsd_version4, -#endif -}; - -#define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0])) -struct svc_program nfsd_program = { - .pg_prog = NFS_PROGRAM, /* program number */ - .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ - .pg_vers = nfsd_version, /* version table */ - .pg_name = "nfsd", /* program name */ - .pg_class = "nfsd", /* authentication class */ - .pg_stats = &nfsd_svcstats, /* version table */ -}; --- linux-2.6.11/fs/nfsd/nfsctl.c.orig 2005-03-18 07:21:19.000000000 -0500 +++ linux-2.6.11/fs/nfsd/nfsctl.c 2005-03-22 07:41:34.000000000 -0500 @@ -49,7 +49,7 @@ enum { NFSD_Getfs, NFSD_List, NFSD_Fh, - NFSD_Threads, + NFSD_Config, NFSD_Leasetime, }; @@ -64,7 +64,7 @@ static ssize_t write_unexport(struct fil static ssize_t write_getfd(struct file *file, char *buf, size_t size); static ssize_t write_getfs(struct file *file, char *buf, size_t size); static ssize_t write_filehandle(struct file *file, char *buf, size_t size); -static ssize_t write_threads(struct file *file, char *buf, size_t size); +static ssize_t write_config(struct file *file, char *buf, size_t size); static ssize_t write_leasetime(struct file *file, char *buf, size_t size); static ssize_t (*write_op[])(struct file *, char *, size_t) = { @@ -76,7 +76,7 @@ static ssize_t (*write_op[])(struct file [NFSD_Getfd] = write_getfd, [NFSD_Getfs] = write_getfs, [NFSD_Fh] = write_filehandle, - [NFSD_Threads] = write_threads, + [NFSD_Config] = write_config, [NFSD_Leasetime] = write_leasetime, }; @@ -133,7 +133,7 @@ static ssize_t write_svc(struct file *fi if (size < sizeof(*data)) return -EINVAL; data = (struct nfsctl_svc*) buf; - return nfsd_svc(data->svc_port, data->svc_nthreads); + return nfsd_svc(data->svc_port, data->svc_nthreads, 0); } static ssize_t write_add(struct file *file, char *buf, size_t size) @@ -304,13 +304,16 @@ static ssize_t write_filehandle(struct f extern int nfsd_nrthreads(void); -static ssize_t write_threads(struct file *file, char *buf, size_t size) +static ssize_t write_config(struct file *file, char *buf, size_t size) { /* if size > 0, look for a number of threads and call nfsd_svc * then write out number of threads as reply */ char *mesg = buf; int rv; + unsigned int ctlbits = 0; + unsigned int port = 0; + if (size > 0) { int newthreads; rv = get_int(&mesg, &newthreads); @@ -318,11 +321,30 @@ static ssize_t write_threads(struct file return rv; if (newthreads <0) return -EINVAL; - rv = nfsd_svc(2049, newthreads); + rv = get_int(&mesg, &port); + if (rv) { + /* + * its possible the rpc.nfsd does not + * have the ctlbits support, so just + * fill in with default values + */ + port = 2049; + ctlbits = ~0; + sprintf(buf, "%d\n", newthreads); + } else { + rv = get_int(&mesg, &ctlbits); + if (rv) { + ctlbits = ~0; + sprintf(buf, "%d %d\n", nfsd_nrthreads(), port); + } else + sprintf(buf, "%d %d %d\n", nfsd_nrthreads(), port, ctlbits); + } + rv = nfsd_svc((unsigned short)port, newthreads, ctlbits); if (rv) return rv; - } - sprintf(buf, "%d\n", nfsd_nrthreads()); + } else + sprintf(buf, "%d\n", nfsd_nrthreads()); + return strlen(buf); } @@ -366,7 +388,7 @@ static int nfsd_fill_super(struct super_ [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, - [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, + [NFSD_Config] = {"config", &transaction_ops, S_IWUSR|S_IRUSR}, #ifdef CONFIG_NFSD_V4 [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, #endif --- linux-2.6.11/include/linux/nfsd/syscall.h.orig 2005-03-02 02:38:38.000000000 -0500 +++ linux-2.6.11/include/linux/nfsd/syscall.h 2005-03-18 07:30:26.000000000 -0500 @@ -39,6 +39,14 @@ #define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */ #define NFSCTL_GETFS 8 /* get an fh by path with max FH len */ +#define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << ((_v) - 1))) +#define NFSCTL_UDPUNSET(_cltbits) ((_cltbits) &= ~(1 << (17 - 1))) +#define NFSCTL_TCPUNSET(_cltbits) ((_cltbits) &= ~(1 << (18 - 1))) + +#define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << ((_v) - 1))) +#define NFSCTL_UDPISSET(_cltbits) ((_cltbits) & (1 << (17 - 1))) +#define NFSCTL_TCPISSET(_cltbits) ((_cltbits) & (1 << (18 - 1))) + /* SVC */ struct nfsctl_svc { unsigned short svc_port; --- linux-2.6.11/include/linux/nfsd/nfsd.h.orig 2005-03-02 02:38:32.000000000 -0500 +++ linux-2.6.11/include/linux/nfsd/nfsd.h 2005-03-18 05:08:55.000000000 -0500 @@ -63,7 +63,7 @@ extern struct svc_version nfsd_version2, /* * Function prototypes. */ -int nfsd_svc(unsigned short port, int nrservs); +int nfsd_svc(unsigned short port, int nrservs, unsigned int ctlbits); int nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp); /* nfsd/vfs.c */