#include <asm/uaccess.h>
-int nfsd_port = 2049;
-unsigned int nfsd_portbits = 0;
-unsigned int nfsd_versbits = 0;
+unsigned int nfsd_versbits = ~0;
/*
* We have a single directory with 9 nodes in it.
NFSD_List,
NFSD_Fh,
NFSD_Threads,
- NFSD_Leasetime,
- NFSD_Ports,
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
};
/*
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_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);
+#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,
[NFSD_Getfs] = write_getfs,
[NFSD_Fh] = write_filehandle,
[NFSD_Threads] = write_threads,
- [NFSD_Leasetime] = write_leasetime,
- [NFSD_Ports] = write_ports,
[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)
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);
return rv;
}
+static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
+{
+ if (! file->private_data) {
+ /* An attempt to read a transaction file without writing
+ * causes a 0-byte write so that the file can return
+ * state information
+ */
+ ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos);
+ if (rv < 0)
+ return rv;
+ }
+ return simple_transaction_read(file, buf, size, pos);
+}
+
static struct file_operations transaction_ops = {
.write = nfsctl_transaction_write,
- .read = simple_transaction_read,
+ .read = nfsctl_transaction_read,
.release = simple_transaction_release,
};
* qword quoting is used, so filehandle will be \x....
*/
char *dname, *path;
- int maxsize = 0;
+ int maxsize;
char *mesg = buf;
int len;
struct auth_domain *dom;
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 address port
- */
- char *mesg = buf;
- char *family, *proto, *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;
- proto = family+len+1;
- len = qword_get(&mesg, proto, size);
- if (len <= 0) return -EINVAL;
- tlen += len;
- addr = proto+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(proto, "tcp") == 0 || strcmp(proto, "TCP") == 0)
- NFSCTL_TCPSET(nfsd_portbits);
- if (strcmp(proto, "udp") == 0 || strcmp(proto, "UDP") == 0)
- NFSCTL_UDPSET(nfsd_portbits);
-
- return tlen;
-}
static ssize_t write_versions(struct file *file, char *buf, size_t size)
{
/*
char *vers, sign;
int len, num;
ssize_t tlen = 0;
+ char *sep;
- 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:
+ 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 = " ";
}
- vers += len + 1;
- tlen += len;
- } while ((len = qword_get(&mesg, vers, size)) > 0);
-
- return tlen;
+ 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)
return strlen(buf);
}
+static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
+{
+ char *mesg = buf;
+ char *recdir;
+ int len, status;
+
+ if (size > PATH_MAX || buf[size-1] != '\n')
+ return -EINVAL;
+ buf[size-1] = 0;
+
+ recdir = mesg;
+ len = qword_get(&mesg, recdir, size);
+ if (len <= 0)
+ return -EINVAL;
+
+ status = nfs4_reset_recoverydir(recdir);
+ return strlen(buf);
+}
+#endif
+
/*----------------------------------------------------------------------------*/
/*
* populating the filesystem.
[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},
#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);
nfsd_cache_init(); /* RPC reply cache */
nfsd_export_init(); /* Exports table */
nfsd_lockd_init(); /* lockd->nfsd callbacks */
-#ifdef CONFIG_NFSD_V4
+ nfs4_state_init(); /* NFSv4 locking state */
nfsd_idmap_init(); /* Name to ID mapping */
-#endif /* CONFIG_NFSD_V4 */
if (proc_mkdir("fs/nfs", NULL)) {
struct proc_dir_entry *entry;
entry = create_proc_entry("fs/nfs/exports", 0, NULL);
remove_proc_entry("fs/nfs", NULL);
nfsd_stat_shutdown();
nfsd_lockd_shutdown();
-#ifdef CONFIG_NFSD_V4
nfsd_idmap_shutdown();
-#endif /* CONFIG_NFSD_V4 */
unregister_filesystem(&nfsd_fs_type);
}