diff options
Diffstat (limited to 'fs/nfsd/nfsctl.c')
-rw-r--r-- | fs/nfsd/nfsctl.c | 98 |
1 files changed, 97 insertions, 1 deletions
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 841c562991e8..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) |
@@ -104,9 +120,23 @@ static ssize_t nfsctl_transaction_write(struct file *file, const char __user *bu | |||
104 | return rv; | 120 | return rv; |
105 | } | 121 | } |
106 | 122 | ||
123 | static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos) | ||
124 | { | ||
125 | if (! file->private_data) { | ||
126 | /* An attempt to read a transaction file without writing | ||
127 | * causes a 0-byte write so that the file can return | ||
128 | * state information | ||
129 | */ | ||
130 | ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos); | ||
131 | if (rv < 0) | ||
132 | return rv; | ||
133 | } | ||
134 | return simple_transaction_read(file, buf, size, pos); | ||
135 | } | ||
136 | |||
107 | static struct file_operations transaction_ops = { | 137 | static struct file_operations transaction_ops = { |
108 | .write = nfsctl_transaction_write, | 138 | .write = nfsctl_transaction_write, |
109 | .read = simple_transaction_read, | 139 | .read = nfsctl_transaction_read, |
110 | .release = simple_transaction_release, | 140 | .release = simple_transaction_release, |
111 | }; | 141 | }; |
112 | 142 | ||
@@ -329,6 +359,70 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) | |||
329 | return strlen(buf); | 359 | return strlen(buf); |
330 | } | 360 | } |
331 | 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 | ||
332 | extern time_t nfs4_leasetime(void); | 426 | extern time_t nfs4_leasetime(void); |
333 | 427 | ||
334 | 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) |
@@ -370,6 +464,7 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) | |||
370 | status = nfs4_reset_recoverydir(recdir); | 464 | status = nfs4_reset_recoverydir(recdir); |
371 | return strlen(buf); | 465 | return strlen(buf); |
372 | } | 466 | } |
467 | #endif | ||
373 | 468 | ||
374 | /*----------------------------------------------------------------------------*/ | 469 | /*----------------------------------------------------------------------------*/ |
375 | /* | 470 | /* |
@@ -389,6 +484,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) | |||
389 | [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, | 484 | [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, |
390 | [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, | 485 | [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, |
391 | [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}, | ||
392 | #ifdef CONFIG_NFSD_V4 | 488 | #ifdef CONFIG_NFSD_V4 |
393 | [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, | 489 | [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, |
394 | [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, | 490 | [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, |