diff options
| -rw-r--r-- | fs/nfsd/nfsctl.c | 82 | ||||
| -rw-r--r-- | fs/nfsd/nfssvc.c | 79 | ||||
| -rw-r--r-- | include/linux/nfsd/nfsd.h | 2 | ||||
| -rw-r--r-- | include/linux/nfsd/syscall.h | 17 |
4 files changed, 151 insertions, 29 deletions
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 2a99a0bf54f6..a0871b3efeb7 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/seq_file.h> | 23 | #include <linux/seq_file.h> |
| 24 | #include <linux/pagemap.h> | 24 | #include <linux/pagemap.h> |
| 25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
| 26 | #include <linux/string.h> | ||
| 26 | 27 | ||
| 27 | #include <linux/nfs.h> | 28 | #include <linux/nfs.h> |
| 28 | #include <linux/nfsd_idmap.h> | 29 | #include <linux/nfsd_idmap.h> |
| @@ -35,6 +36,8 @@ | |||
| 35 | 36 | ||
| 36 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
| 37 | 38 | ||
| 39 | unsigned int nfsd_versbits = ~0; | ||
| 40 | |||
| 38 | /* | 41 | /* |
| 39 | * We have a single directory with 9 nodes in it. | 42 | * We have a single directory with 9 nodes in it. |
| 40 | */ | 43 | */ |
| @@ -50,8 +53,15 @@ enum { | |||
| 50 | NFSD_List, | 53 | NFSD_List, |
| 51 | NFSD_Fh, | 54 | NFSD_Fh, |
| 52 | NFSD_Threads, | 55 | NFSD_Threads, |
| 56 | NFSD_Versions, | ||
| 57 | /* | ||
| 58 | * The below MUST come last. Otherwise we leave a hole in nfsd_files[] | ||
| 59 | * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops | ||
| 60 | */ | ||
| 61 | #ifdef CONFIG_NFSD_V4 | ||
| 53 | NFSD_Leasetime, | 62 | NFSD_Leasetime, |
| 54 | NFSD_RecoveryDir, | 63 | NFSD_RecoveryDir, |
| 64 | #endif | ||
| 55 | }; | 65 | }; |
| 56 | 66 | ||
| 57 | /* | 67 | /* |
| @@ -66,8 +76,11 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size); | |||
| 66 | static ssize_t write_getfs(struct file *file, char *buf, size_t size); | 76 | static ssize_t write_getfs(struct file *file, char *buf, size_t size); |
| 67 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size); | 77 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size); |
| 68 | static ssize_t write_threads(struct file *file, char *buf, size_t size); | 78 | static ssize_t write_threads(struct file *file, char *buf, size_t size); |
| 79 | static ssize_t write_versions(struct file *file, char *buf, size_t size); | ||
| 80 | #ifdef CONFIG_NFSD_V4 | ||
| 69 | static ssize_t write_leasetime(struct file *file, char *buf, size_t size); | 81 | static ssize_t write_leasetime(struct file *file, char *buf, size_t size); |
| 70 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); | 82 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); |
| 83 | #endif | ||
| 71 | 84 | ||
| 72 | static ssize_t (*write_op[])(struct file *, char *, size_t) = { | 85 | static ssize_t (*write_op[])(struct file *, char *, size_t) = { |
| 73 | [NFSD_Svc] = write_svc, | 86 | [NFSD_Svc] = write_svc, |
| @@ -79,8 +92,11 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = { | |||
| 79 | [NFSD_Getfs] = write_getfs, | 92 | [NFSD_Getfs] = write_getfs, |
| 80 | [NFSD_Fh] = write_filehandle, | 93 | [NFSD_Fh] = write_filehandle, |
| 81 | [NFSD_Threads] = write_threads, | 94 | [NFSD_Threads] = write_threads, |
| 95 | [NFSD_Versions] = write_versions, | ||
| 96 | #ifdef CONFIG_NFSD_V4 | ||
| 82 | [NFSD_Leasetime] = write_leasetime, | 97 | [NFSD_Leasetime] = write_leasetime, |
| 83 | [NFSD_RecoveryDir] = write_recoverydir, | 98 | [NFSD_RecoveryDir] = write_recoverydir, |
| 99 | #endif | ||
| 84 | }; | 100 | }; |
| 85 | 101 | ||
| 86 | static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) | 102 | static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) |
| @@ -343,6 +359,70 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) | |||
| 343 | return strlen(buf); | 359 | return strlen(buf); |
| 344 | } | 360 | } |
| 345 | 361 | ||
| 362 | static ssize_t write_versions(struct file *file, char *buf, size_t size) | ||
| 363 | { | ||
| 364 | /* | ||
| 365 | * Format: | ||
| 366 | * [-/+]vers [-/+]vers ... | ||
| 367 | */ | ||
| 368 | char *mesg = buf; | ||
| 369 | char *vers, sign; | ||
| 370 | int len, num; | ||
| 371 | ssize_t tlen = 0; | ||
| 372 | char *sep; | ||
| 373 | |||
| 374 | if (size>0) { | ||
| 375 | if (nfsd_serv) | ||
| 376 | return -EBUSY; | ||
| 377 | if (buf[size-1] != '\n') | ||
| 378 | return -EINVAL; | ||
| 379 | buf[size-1] = 0; | ||
| 380 | |||
| 381 | vers = mesg; | ||
| 382 | len = qword_get(&mesg, vers, size); | ||
| 383 | if (len <= 0) return -EINVAL; | ||
| 384 | do { | ||
| 385 | sign = *vers; | ||
| 386 | if (sign == '+' || sign == '-') | ||
| 387 | num = simple_strtol((vers+1), NULL, 0); | ||
| 388 | else | ||
| 389 | num = simple_strtol(vers, NULL, 0); | ||
| 390 | switch(num) { | ||
| 391 | case 2: | ||
| 392 | case 3: | ||
| 393 | case 4: | ||
| 394 | if (sign != '-') | ||
| 395 | NFSCTL_VERSET(nfsd_versbits, num); | ||
| 396 | else | ||
| 397 | NFSCTL_VERUNSET(nfsd_versbits, num); | ||
| 398 | break; | ||
| 399 | default: | ||
| 400 | return -EINVAL; | ||
| 401 | } | ||
| 402 | vers += len + 1; | ||
| 403 | tlen += len; | ||
| 404 | } while ((len = qword_get(&mesg, vers, size)) > 0); | ||
| 405 | /* If all get turned off, turn them back on, as | ||
| 406 | * having no versions is BAD | ||
| 407 | */ | ||
| 408 | if ((nfsd_versbits & NFSCTL_VERALL)==0) | ||
| 409 | nfsd_versbits = NFSCTL_VERALL; | ||
| 410 | } | ||
| 411 | /* Now write current state into reply buffer */ | ||
| 412 | len = 0; | ||
| 413 | sep = ""; | ||
| 414 | for (num=2 ; num <= 4 ; num++) | ||
| 415 | if (NFSCTL_VERISSET(NFSCTL_VERALL, num)) { | ||
| 416 | len += sprintf(buf+len, "%s%c%d", sep, | ||
| 417 | NFSCTL_VERISSET(nfsd_versbits, num)?'+':'-', | ||
| 418 | num); | ||
| 419 | sep = " "; | ||
| 420 | } | ||
| 421 | len += sprintf(buf+len, "\n"); | ||
| 422 | return len; | ||
| 423 | } | ||
| 424 | |||
| 425 | #ifdef CONFIG_NFSD_V4 | ||
| 346 | extern time_t nfs4_leasetime(void); | 426 | extern time_t nfs4_leasetime(void); |
| 347 | 427 | ||
| 348 | static ssize_t write_leasetime(struct file *file, char *buf, size_t size) | 428 | static ssize_t write_leasetime(struct file *file, char *buf, size_t size) |
| @@ -384,6 +464,7 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) | |||
| 384 | status = nfs4_reset_recoverydir(recdir); | 464 | status = nfs4_reset_recoverydir(recdir); |
| 385 | return strlen(buf); | 465 | return strlen(buf); |
| 386 | } | 466 | } |
| 467 | #endif | ||
| 387 | 468 | ||
| 388 | /*----------------------------------------------------------------------------*/ | 469 | /*----------------------------------------------------------------------------*/ |
| 389 | /* | 470 | /* |
| @@ -403,6 +484,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) | |||
| 403 | [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, | 484 | [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, |
| 404 | [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, | 485 | [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, |
| 405 | [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, | 486 | [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, |
| 487 | [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR}, | ||
| 406 | #ifdef CONFIG_NFSD_V4 | 488 | #ifdef CONFIG_NFSD_V4 |
| 407 | [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, | 489 | [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, |
| 408 | [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, | 490 | [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 1697539a7171..0568ff8565b1 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <linux/nfsd/nfsd.h> | 30 | #include <linux/nfsd/nfsd.h> |
| 31 | #include <linux/nfsd/stats.h> | 31 | #include <linux/nfsd/stats.h> |
| 32 | #include <linux/nfsd/cache.h> | 32 | #include <linux/nfsd/cache.h> |
| 33 | #include <linux/nfsd/syscall.h> | ||
| 33 | #include <linux/lockd/bind.h> | 34 | #include <linux/lockd/bind.h> |
| 34 | #include <linux/nfsacl.h> | 35 | #include <linux/nfsacl.h> |
| 35 | 36 | ||
| @@ -52,7 +53,7 @@ | |||
| 52 | extern struct svc_program nfsd_program; | 53 | extern struct svc_program nfsd_program; |
| 53 | static void nfsd(struct svc_rqst *rqstp); | 54 | static void nfsd(struct svc_rqst *rqstp); |
| 54 | struct timeval nfssvc_boot; | 55 | struct timeval nfssvc_boot; |
| 55 | static struct svc_serv *nfsd_serv; | 56 | struct svc_serv *nfsd_serv; |
| 56 | static atomic_t nfsd_busy; | 57 | static atomic_t nfsd_busy; |
| 57 | static unsigned long nfsd_last_call; | 58 | static unsigned long nfsd_last_call; |
| 58 | static DEFINE_SPINLOCK(nfsd_call_lock); | 59 | static DEFINE_SPINLOCK(nfsd_call_lock); |
| @@ -63,6 +64,31 @@ struct nfsd_list { | |||
| 63 | }; | 64 | }; |
| 64 | static struct list_head nfsd_list = LIST_HEAD_INIT(nfsd_list); | 65 | static struct list_head nfsd_list = LIST_HEAD_INIT(nfsd_list); |
| 65 | 66 | ||
| 67 | static struct svc_version * nfsd_version[] = { | ||
| 68 | [2] = &nfsd_version2, | ||
| 69 | #if defined(CONFIG_NFSD_V3) | ||
| 70 | [3] = &nfsd_version3, | ||
| 71 | #endif | ||
| 72 | #if defined(CONFIG_NFSD_V4) | ||
| 73 | [4] = &nfsd_version4, | ||
| 74 | #endif | ||
| 75 | }; | ||
| 76 | |||
| 77 | #define NFSD_MINVERS 2 | ||
| 78 | #define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0])) | ||
| 79 | static struct svc_version *nfsd_versions[NFSD_NRVERS]; | ||
| 80 | |||
| 81 | struct svc_program nfsd_program = { | ||
| 82 | .pg_prog = NFS_PROGRAM, /* program number */ | ||
| 83 | .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ | ||
| 84 | .pg_vers = nfsd_versions, /* version table */ | ||
| 85 | .pg_name = "nfsd", /* program name */ | ||
| 86 | .pg_class = "nfsd", /* authentication class */ | ||
| 87 | .pg_stats = &nfsd_svcstats, /* version table */ | ||
| 88 | .pg_authenticate = &svc_set_client, /* export authentication */ | ||
| 89 | |||
| 90 | }; | ||
| 91 | |||
| 66 | /* | 92 | /* |
| 67 | * Maximum number of nfsd processes | 93 | * Maximum number of nfsd processes |
| 68 | */ | 94 | */ |
| @@ -80,11 +106,12 @@ int | |||
| 80 | nfsd_svc(unsigned short port, int nrservs) | 106 | nfsd_svc(unsigned short port, int nrservs) |
| 81 | { | 107 | { |
| 82 | int error; | 108 | int error; |
| 83 | int none_left; | 109 | int none_left, found_one, i; |
| 84 | struct list_head *victim; | 110 | struct list_head *victim; |
| 85 | 111 | ||
| 86 | lock_kernel(); | 112 | lock_kernel(); |
| 87 | dprintk("nfsd: creating service\n"); | 113 | dprintk("nfsd: creating service: vers 0x%x\n", |
| 114 | nfsd_versbits); | ||
| 88 | error = -EINVAL; | 115 | error = -EINVAL; |
| 89 | if (nrservs <= 0) | 116 | if (nrservs <= 0) |
| 90 | nrservs = 0; | 117 | nrservs = 0; |
| @@ -99,6 +126,27 @@ nfsd_svc(unsigned short port, int nrservs) | |||
| 99 | if (error<0) | 126 | if (error<0) |
| 100 | goto out; | 127 | goto out; |
| 101 | if (!nfsd_serv) { | 128 | if (!nfsd_serv) { |
| 129 | /* | ||
| 130 | * Use the nfsd_ctlbits to define which | ||
| 131 | * versions that will be advertised. | ||
| 132 | * If nfsd_ctlbits doesn't list any version, | ||
| 133 | * export them all. | ||
| 134 | */ | ||
| 135 | found_one = 0; | ||
| 136 | |||
| 137 | for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) { | ||
| 138 | if (NFSCTL_VERISSET(nfsd_versbits, i)) { | ||
| 139 | nfsd_program.pg_vers[i] = nfsd_version[i]; | ||
| 140 | found_one = 1; | ||
| 141 | } else | ||
| 142 | nfsd_program.pg_vers[i] = NULL; | ||
| 143 | } | ||
| 144 | |||
| 145 | if (!found_one) { | ||
| 146 | for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) | ||
| 147 | nfsd_program.pg_vers[i] = nfsd_version[i]; | ||
| 148 | } | ||
| 149 | |||
| 102 | atomic_set(&nfsd_busy, 0); | 150 | atomic_set(&nfsd_busy, 0); |
| 103 | error = -ENOMEM; | 151 | error = -ENOMEM; |
| 104 | nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE); | 152 | nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE); |
| @@ -389,28 +437,3 @@ static struct svc_stat nfsd_acl_svcstats = { | |||
| 389 | #else | 437 | #else |
| 390 | #define nfsd_acl_program_p NULL | 438 | #define nfsd_acl_program_p NULL |
| 391 | #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ | 439 | #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ |
| 392 | |||
| 393 | extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; | ||
| 394 | |||
| 395 | static struct svc_version * nfsd_version[] = { | ||
| 396 | [2] = &nfsd_version2, | ||
| 397 | #if defined(CONFIG_NFSD_V3) | ||
| 398 | [3] = &nfsd_version3, | ||
| 399 | #endif | ||
| 400 | #if defined(CONFIG_NFSD_V4) | ||
| 401 | [4] = &nfsd_version4, | ||
| 402 | #endif | ||
| 403 | }; | ||
| 404 | |||
| 405 | #define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0])) | ||
| 406 | struct svc_program nfsd_program = { | ||
| 407 | .pg_next = nfsd_acl_program_p, | ||
| 408 | .pg_prog = NFS_PROGRAM, /* program number */ | ||
| 409 | .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ | ||
| 410 | .pg_vers = nfsd_version, /* version table */ | ||
| 411 | .pg_name = "nfsd", /* program name */ | ||
| 412 | .pg_class = "nfsd", /* authentication class */ | ||
| 413 | .pg_stats = &nfsd_svcstats, /* version table */ | ||
| 414 | .pg_authenticate = &svc_set_client, /* export authentication */ | ||
| 415 | |||
| 416 | }; | ||
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 6d5a24f3fc6d..51c231a1e5a6 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h | |||
| @@ -60,7 +60,7 @@ typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int); | |||
| 60 | extern struct svc_program nfsd_program; | 60 | extern struct svc_program nfsd_program; |
| 61 | extern struct svc_version nfsd_version2, nfsd_version3, | 61 | extern struct svc_version nfsd_version2, nfsd_version3, |
| 62 | nfsd_version4; | 62 | nfsd_version4; |
| 63 | 63 | extern struct svc_serv *nfsd_serv; | |
| 64 | /* | 64 | /* |
| 65 | * Function prototypes. | 65 | * Function prototypes. |
| 66 | */ | 66 | */ |
diff --git a/include/linux/nfsd/syscall.h b/include/linux/nfsd/syscall.h index e65c9db6d13f..781efbf94ed3 100644 --- a/include/linux/nfsd/syscall.h +++ b/include/linux/nfsd/syscall.h | |||
| @@ -39,6 +39,21 @@ | |||
| 39 | #define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */ | 39 | #define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */ |
| 40 | #define NFSCTL_GETFS 8 /* get an fh by path with max FH len */ | 40 | #define NFSCTL_GETFS 8 /* get an fh by path with max FH len */ |
| 41 | 41 | ||
| 42 | /* | ||
| 43 | * Macros used to set version | ||
| 44 | */ | ||
| 45 | #define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << (_v))) | ||
| 46 | #define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << (_v))) | ||
| 47 | #define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << (_v))) | ||
| 48 | |||
| 49 | #if defined(CONFIG_NFSD_V4) | ||
| 50 | #define NFSCTL_VERALL (0x1c /* 0b011100 */) | ||
| 51 | #elif defined(CONFIG_NFSD_V3) | ||
| 52 | #define NFSCTL_VERALL (0x0c /* 0b001100 */) | ||
| 53 | #else | ||
| 54 | #define NFSCTL_VERALL (0x04 /* 0b000100 */) | ||
| 55 | #endif | ||
| 56 | |||
| 42 | /* SVC */ | 57 | /* SVC */ |
| 43 | struct nfsctl_svc { | 58 | struct nfsctl_svc { |
| 44 | unsigned short svc_port; | 59 | unsigned short svc_port; |
| @@ -120,6 +135,8 @@ extern int exp_delclient(struct nfsctl_client *ncp); | |||
| 120 | extern int exp_export(struct nfsctl_export *nxp); | 135 | extern int exp_export(struct nfsctl_export *nxp); |
| 121 | extern int exp_unexport(struct nfsctl_export *nxp); | 136 | extern int exp_unexport(struct nfsctl_export *nxp); |
| 122 | 137 | ||
| 138 | extern unsigned int nfsd_versbits; | ||
| 139 | |||
| 123 | #endif /* __KERNEL__ */ | 140 | #endif /* __KERNEL__ */ |
| 124 | 141 | ||
| 125 | #endif /* NFSD_SYSCALL_H */ | 142 | #endif /* NFSD_SYSCALL_H */ |
