This kernel patch allows the setting of the port and transport in which NFS server will listen on, as well as, which NFS protocol version will be advertised. Signed-off: Steve Dickson ----------------------------------------- --- linux-2.6.14-rc3/fs/nfsd/nfs4state.c.ctlbits 2005-10-07 11:21:41.652521000 -0400 +++ linux-2.6.14-rc3/fs/nfsd/nfs4state.c 2005-10-07 11:22:47.399369000 -0400 @@ -3319,6 +3319,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.14-rc3/fs/nfsd/nfsctl.c.ctlbits 2005-08-28 19:41:01.000000000 -0400 +++ linux-2.6.14-rc3/fs/nfsd/nfsctl.c 2005-10-07 11:22:47.406368000 -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, NFSD_RecoveryDir, }; @@ -67,6 +74,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_recoverydir(struct file *file, char *buf, size_t size); static ssize_t (*write_op[])(struct file *, char *, size_t) = { @@ -80,6 +89,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, [NFSD_RecoveryDir] = write_recoverydir, }; @@ -88,14 +99,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); @@ -259,7 +268,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; @@ -328,6 +337,102 @@ 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 proto address port + */ + char *mesg = buf; + char *family, *udp, *tcp, *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; + udp = family+len+1; + len = qword_get(&mesg, udp, size); + if (len <= 0) return -EINVAL; + + tlen += len; + tcp = udp+len+1; + len = qword_get(&mesg, tcp, size); + if (len <= 0) return -EINVAL; + + tlen += len; + addr = tcp+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(tcp, "tcp") == 0 || strcmp(tcp, "TCP") == 0) + NFSCTL_TCPSET(nfsd_portbits); + else + NFSCTL_TCPUNSET(nfsd_portbits); + + if (strcmp(udp, "udp") == 0 || strcmp(udp, "UDP") == 0) + NFSCTL_UDPSET(nfsd_portbits); + else + NFSCTL_UDPUNSET(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); @@ -393,6 +498,8 @@ static int nfsd_fill_super(struct super_ [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_RecoveryDir] = {"nfsv4recoverydir", &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.14-rc3/fs/nfsd/nfssvc.c.ctlbits 2005-08-28 19:41:01.000000000 -0400 +++ linux-2.6.14-rc3/fs/nfsd/nfssvc.c 2005-10-07 11:22:47.411370000 -0400 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,33 @@ 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])) +static struct svc_version *nfsd_versions[NFSD_NRVERS]; + +struct svc_program nfsd_program = { + .pg_prog = NFS_PROGRAM, /* program number */ + .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ + .pg_vers = nfsd_versions, /* 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 */ @@ -80,17 +108,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) @@ -104,14 +152,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 (!nfsd_portbits || NFSCTL_UDPISSET(nfsd_portbits)) { + 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 (!nfsd_portbits || NFSCTL_TCPISSET(nfsd_portbits)) { + error = svc_makesock(nfsd_serv, IPPROTO_TCP, port); + if (error < 0) + goto failure; + } #endif do_gettimeofday(&nfssvc_boot); /* record boot time */ } else @@ -389,28 +440,3 @@ static struct svc_stat nfsd_acl_svcstats #else #define nfsd_acl_program_p NULL #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ - -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_next = nfsd_acl_program_p, - .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.14-rc3/include/linux/nfsd/syscall.h.ctlbits 2005-08-28 19:41:01.000000000 -0400 +++ linux-2.6.14-rc3/include/linux/nfsd/syscall.h 2005-10-07 11:22:47.417368000 -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 */