aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfsctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfsctl.c')
-rw-r--r--fs/nfsd/nfsctl.c98
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
39unsigned 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);
66static ssize_t write_getfs(struct file *file, char *buf, size_t size); 76static ssize_t write_getfs(struct file *file, char *buf, size_t size);
67static ssize_t write_filehandle(struct file *file, char *buf, size_t size); 77static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
68static ssize_t write_threads(struct file *file, char *buf, size_t size); 78static ssize_t write_threads(struct file *file, char *buf, size_t size);
79static ssize_t write_versions(struct file *file, char *buf, size_t size);
80#ifdef CONFIG_NFSD_V4
69static ssize_t write_leasetime(struct file *file, char *buf, size_t size); 81static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
70static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); 82static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
83#endif
71 84
72static ssize_t (*write_op[])(struct file *, char *, size_t) = { 85static 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
86static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) 102static 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
123static 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
107static struct file_operations transaction_ops = { 137static 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
362static 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
332extern time_t nfs4_leasetime(void); 426extern time_t nfs4_leasetime(void);
333 427
334static ssize_t write_leasetime(struct file *file, char *buf, size_t size) 428static 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},