|
@@ -23,6 +23,7 @@
|
|
|
#include <linux/seq_file.h>
|
|
|
#include <linux/pagemap.h>
|
|
|
#include <linux/init.h>
|
|
|
+#include <linux/string.h>
|
|
|
|
|
|
#include <linux/nfs.h>
|
|
|
#include <linux/nfsd_idmap.h>
|
|
@@ -35,6 +36,8 @@
|
|
|
|
|
|
#include <asm/uaccess.h>
|
|
|
|
|
|
+unsigned int nfsd_versbits = ~0;
|
|
|
+
|
|
|
/*
|
|
|
* We have a single directory with 9 nodes in it.
|
|
|
*/
|
|
@@ -50,8 +53,15 @@ enum {
|
|
|
NFSD_List,
|
|
|
NFSD_Fh,
|
|
|
NFSD_Threads,
|
|
|
+ NFSD_Versions,
|
|
|
+ /*
|
|
|
+ * The below MUST come last. Otherwise we leave a hole in nfsd_files[]
|
|
|
+ * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
|
|
|
+ */
|
|
|
+#ifdef CONFIG_NFSD_V4
|
|
|
NFSD_Leasetime,
|
|
|
NFSD_RecoveryDir,
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
/*
|
|
@@ -66,8 +76,11 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size);
|
|
|
static ssize_t write_getfs(struct file *file, char *buf, size_t size);
|
|
|
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_versions(struct file *file, char *buf, size_t size);
|
|
|
+#ifdef CONFIG_NFSD_V4
|
|
|
static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
|
|
|
static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
|
|
|
+#endif
|
|
|
|
|
|
static ssize_t (*write_op[])(struct file *, char *, size_t) = {
|
|
|
[NFSD_Svc] = write_svc,
|
|
@@ -79,8 +92,11 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
|
|
|
[NFSD_Getfs] = write_getfs,
|
|
|
[NFSD_Fh] = write_filehandle,
|
|
|
[NFSD_Threads] = write_threads,
|
|
|
+ [NFSD_Versions] = write_versions,
|
|
|
+#ifdef CONFIG_NFSD_V4
|
|
|
[NFSD_Leasetime] = write_leasetime,
|
|
|
[NFSD_RecoveryDir] = write_recoverydir,
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
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)
|
|
|
return strlen(buf);
|
|
|
}
|
|
|
|
|
|
+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;
|
|
|
+ char *sep;
|
|
|
+
|
|
|
+ if (size>0) {
|
|
|
+ if (nfsd_serv)
|
|
|
+ return -EBUSY;
|
|
|
+ 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);
|
|
|
+ /* If all get turned off, turn them back on, as
|
|
|
+ * having no versions is BAD
|
|
|
+ */
|
|
|
+ if ((nfsd_versbits & NFSCTL_VERALL)==0)
|
|
|
+ nfsd_versbits = NFSCTL_VERALL;
|
|
|
+ }
|
|
|
+ /* Now write current state into reply buffer */
|
|
|
+ len = 0;
|
|
|
+ sep = "";
|
|
|
+ for (num=2 ; num <= 4 ; num++)
|
|
|
+ if (NFSCTL_VERISSET(NFSCTL_VERALL, num)) {
|
|
|
+ len += sprintf(buf+len, "%s%c%d", sep,
|
|
|
+ NFSCTL_VERISSET(nfsd_versbits, num)?'+':'-',
|
|
|
+ num);
|
|
|
+ sep = " ";
|
|
|
+ }
|
|
|
+ len += sprintf(buf+len, "\n");
|
|
|
+ return len;
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef CONFIG_NFSD_V4
|
|
|
extern time_t nfs4_leasetime(void);
|
|
|
|
|
|
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)
|
|
|
status = nfs4_reset_recoverydir(recdir);
|
|
|
return strlen(buf);
|
|
|
}
|
|
|
+#endif
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
/*
|
|
@@ -403,6 +484,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
|
|
|
[NFSD_List] = {"exports", &exports_operations, S_IRUGO},
|
|
|
[NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
|
|
|
[NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
|
|
|
+ [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
|
|
|
#ifdef CONFIG_NFSD_V4
|
|
|
[NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
|
|
|
[NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
|