This kernel patch allows the setting of the port and network transport on which kNFSD will listen on and which protocol version will be advertised. Signed-off: Steve Dickson ------------------------------- --- linux-2.6.12/fs/nfsd/nfs4state.c.orig 2005-06-17 15:48:29.000000000 -0400 +++ linux-2.6.12/fs/nfsd/nfs4state.c 2005-07-11 07:57:11.000000000 -0400 @@ -3256,6 +3256,9 @@ __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.12/fs/nfsd/nfsctl.c.orig 2005-06-17 15:48:29.000000000 -0400 +++ linux-2.6.12/fs/nfsd/nfsctl.c 2005-07-11 13:59:46.000000000 -0400 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,10 @@ #include +int nfsd_port = 2049; +unsigned int nfsd_portbits = 0; +unsigned int nfsd_versbits = 0; + /* * We have a single directory with 9 nodes in it. */ @@ -51,6 +56,8 @@ enum { NFSD_Fh, NFSD_Threads, NFSD_Leasetime, + NFSD_Ports, + NFSD_Versions, }; /* @@ -66,6 +73,8 @@ static ssize_t write_getfs(struct file * 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_leasetime(struct file *file, char *buf, size_t size); +static ssize_t write_ports(struct file *file, char *buf, size_t size); +static ssize_t write_versions(struct file *file, char *buf, size_t size); static ssize_t (*write_op[])(struct file *, char *, size_t) = { [NFSD_Svc] = write_svc, @@ -78,6 +87,8 @@ static ssize_t (*write_op[])(struct file [NFSD_Fh] = write_filehandle, [NFSD_Threads] = write_threads, [NFSD_Leasetime] = write_leasetime, + [NFSD_Ports] = write_ports, + [NFSD_Versions] = write_versions, }; static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) @@ -85,14 +96,12 @@ static ssize_t nfsctl_transaction_write( ino_t ino = file->f_dentry->d_inode->i_ino; char *data; ssize_t rv; - if (ino >= sizeof(write_op)/sizeof(write_op[0]) || !write_op[ino]) return -EINVAL; data = simple_transaction_get(file, buf, size); if (IS_ERR(data)) return PTR_ERR(data); - rv = write_op[ino](file, data, size); if (rv>0) { simple_transaction_set(file, rv); @@ -256,7 +265,7 @@ static ssize_t write_filehandle(struct f * qword quoting is used, so filehandle will be \x.... */ char *dname, *path; - int maxsize; + int maxsize = 0; char *mesg = buf; int len; struct auth_domain *dom; @@ -325,6 +334,92 @@ static ssize_t write_threads(struct file sprintf(buf, "%d\n", nfsd_nrthreads()); return strlen(buf); } +static ssize_t write_ports(struct file *file, char *buf, size_t size) +{ + /* + * Format: + * family proto address port + */ + char *mesg = buf; + char *family, *proto, *addr; + int len, port = 0; + ssize_t tlen = 0; + + if (buf[size-1] != '\n') + return -EINVAL; + buf[size-1] = 0; + + family = mesg; + len = qword_get(&mesg, family, size); + if (len <= 0) return -EINVAL; + + tlen += len; + proto = family+len+1; + len = qword_get(&mesg, proto, size); + if (len <= 0) return -EINVAL; + + tlen += len; + addr = proto+len+1; + len = qword_get(&mesg, addr, size); + if (len <= 0) return -EINVAL; + + len = get_int(&mesg, &port); + if (len) + return len; + + tlen += sizeof(port); + if (port) + nfsd_port = port; + + if (strcmp(proto, "tcp") == 0 || strcmp(proto, "TCP") == 0) + NFSCTL_TCPSET(nfsd_portbits); + if (strcmp(proto, "udp") == 0 || strcmp(proto, "UDP") == 0) + NFSCTL_UDPSET(nfsd_portbits); + + return tlen; +} +static ssize_t write_versions(struct file *file, char *buf, size_t size) +{ + /* + * Format: + * [-/+]vers [-/+]vers ... + */ + char *mesg = buf; + char *vers, sign; + int len, num; + ssize_t tlen = 0; + + if (buf[size-1] != '\n') + return -EINVAL; + buf[size-1] = 0; + + vers = mesg; + len = qword_get(&mesg, vers, size); + if (len <= 0) return -EINVAL; + do { + sign = *vers; + if (sign == '+' || sign == '-') + num = simple_strtol((vers+1), NULL, 0); + else + num = simple_strtol(vers, NULL, 0); + switch(num) { + case 2: + case 3: + case 4: + if (sign != '-') + NFSCTL_VERSET(nfsd_versbits, num); + else + NFSCTL_VERUNSET(nfsd_versbits, num); + break; + default: + return -EINVAL; + } + vers += len + 1; + tlen += len; + } while ((len = qword_get(&mesg, vers, size)) > 0); + + return tlen; +} extern time_t nfs4_leasetime(void); @@ -370,6 +465,8 @@ static int nfsd_fill_super(struct super_ #ifdef CONFIG_NFSD_V4 [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, #endif + [NFSD_Ports] = {"ports", &transaction_ops, S_IWUSR|S_IRUSR}, + [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR}, /* last one */ {""} }; return simple_fill_super(sb, 0x6e667364, nfsd_files); --- linux-2.6.12/fs/nfsd/nfssvc.c.orig 2005-06-17 15:48:29.000000000 -0400 +++ linux-2.6.12/fs/nfsd/nfssvc.c 2005-07-11 11:36:04.000000000 -0400 @@ -30,6 +30,7 @@ #include #include #include +#include #include #define NFSDDBG_FACILITY NFSDDBG_SVC @@ -51,10 +52,7 @@ extern struct svc_program nfsd_program; static void nfsd(struct svc_rqst *rqstp); struct timeval nfssvc_boot; -static struct svc_serv *nfsd_serv; -static atomic_t nfsd_busy; -static unsigned long nfsd_last_call; -static DEFINE_SPINLOCK(nfsd_call_lock); +static struct svc_serv *nfsd_serv; static atomic_t nfsd_busy; static unsigned long nfsd_last_call; static DEFINE_SPINLOCK(nfsd_call_lock); struct nfsd_list { struct list_head list; @@ -62,6 +60,31 @@ struct nfsd_list { }; static 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 */ + .pg_authenticate = &svc_set_client, /* export authentication */ + +}; + /* * Maximum number of nfsd processes */ @@ -79,17 +102,37 @@ int nfsd_svc(unsigned short port, int nrservs) { int error; - int none_left; + int none_left, found_one, i; struct list_head *victim; lock_kernel(); - dprintk("nfsd: creating service\n"); + dprintk("nfsd: creating service: port %d vers 0x%x proto 0x%x\n", + nfsd_port, nfsd_versbits, nfsd_portbits); error = -EINVAL; if (nrservs <= 0) nrservs = 0; if (nrservs > NFSD_MAXSERVS) nrservs = NFSD_MAXSERVS; + /* + * If set, use the nfsd_ctlbits to define which + * versions that will be advertised + */ + found_one = 0; + if (nfsd_versbits) { + for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) { + if (NFSCTL_VERISSET(nfsd_versbits, i)) { + nfsd_program.pg_vers[i] = nfsd_version[i]; + found_one = 1; + } else + nfsd_program.pg_vers[i] = NULL; + } + } + if (!found_one) { + for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) + nfsd_program.pg_vers[i] = nfsd_version[i]; + } + /* Readahead param cache - will no-op if it already exists */ error = nfsd_racache_init(2*nrservs); if (error<0) @@ -97,20 +140,24 @@ nfsd_svc(unsigned short port, int nrserv error = nfs4_state_init(); if (error<0) goto out; + if (!nfsd_serv) { atomic_set(&nfsd_busy, 0); error = -ENOMEM; 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 (!nfsd_portbits || NFSCTL_UDPISSET(nfsd_portbits)) { + error = svc_makesock(nfsd_serv, IPPROTO_UDP, nfsd_port); + if (error < 0) + goto failure; + } #ifdef CONFIG_NFSD_TCP - error = svc_makesock(nfsd_serv, IPPROTO_TCP, port); - if (error < 0) - goto failure; + if (!nfsd_portbits || NFSCTL_TCPISSET(nfsd_portbits)) { + error = svc_makesock(nfsd_serv, IPPROTO_TCP, nfsd_port); + if (error < 0) + goto failure; + } #endif do_gettimeofday(&nfssvc_boot); /* record boot time */ } else @@ -362,26 +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 */ - .pg_authenticate = &svc_set_client, /* export authentication */ - -}; --- linux-2.6.12/include/linux/nfsd/syscall.h.orig 2005-06-17 15:48:29.000000000 -0400 +++ linux-2.6.12/include/linux/nfsd/syscall.h 2005-07-11 11:31:21.000000000 -0400 @@ -39,6 +39,22 @@ #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 */ +/* + * Macros used to set version and protocol + */ +#define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << ((_v) - 1))) +#define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << ((_v) - 1))) +#define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << ((_v) - 1))) + +#define NFSCTL_UDPSET(_cltbits) ((_cltbits) |= (1 << (17 - 1))) +#define NFSCTL_UDPUNSET(_cltbits) ((_cltbits) &= ~(1 << (17 - 1))) +#define NFSCTL_UDPISSET(_cltbits) ((_cltbits) & (1 << (17 - 1))) + +#define NFSCTL_TCPSET(_cltbits) ((_cltbits) |= (1 << (18 - 1))) +#define NFSCTL_TCPUNSET(_cltbits) ((_cltbits) &= ~(1 << (18 - 1))) +#define NFSCTL_TCPISSET(_cltbits) ((_cltbits) & (1 << (18 - 1))) + + /* SVC */ struct nfsctl_svc { unsigned short svc_port; @@ -120,6 +136,9 @@ extern int exp_delclient(struct nfsctl_ extern int exp_export(struct nfsctl_export *nxp); extern int exp_unexport(struct nfsctl_export *nxp); +extern int nfsd_port; +extern unsigned int nfsd_versbits, nfsd_portbits; + #endif /* __KERNEL__ */ #endif /* NFSD_SYSCALL_H */