mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-14 04:41:26 +00:00
[PATCH] knfsd: Allow run-time selection of NFS versions to export
Provide a file in the NFSD filesystem that allows setting and querying of which version of NFS are being exported. Changes are only allowed while no server is running. Signed-off-by: Steve Dickson <steved@redhat.com> Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
7390022d69
commit
70c3b76c28
@ -23,6 +23,7 @@
|
|||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
|
||||||
#include <linux/nfs.h>
|
#include <linux/nfs.h>
|
||||||
#include <linux/nfsd_idmap.h>
|
#include <linux/nfsd_idmap.h>
|
||||||
@ -35,6 +36,8 @@
|
|||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
|
unsigned int nfsd_versbits = ~0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have a single directory with 9 nodes in it.
|
* We have a single directory with 9 nodes in it.
|
||||||
*/
|
*/
|
||||||
@ -50,8 +53,15 @@ enum {
|
|||||||
NFSD_List,
|
NFSD_List,
|
||||||
NFSD_Fh,
|
NFSD_Fh,
|
||||||
NFSD_Threads,
|
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_Leasetime,
|
||||||
NFSD_RecoveryDir,
|
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_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_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_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_leasetime(struct file *file, char *buf, size_t size);
|
||||||
static ssize_t write_recoverydir(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) = {
|
static ssize_t (*write_op[])(struct file *, char *, size_t) = {
|
||||||
[NFSD_Svc] = write_svc,
|
[NFSD_Svc] = write_svc,
|
||||||
@ -79,8 +92,11 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
|
|||||||
[NFSD_Getfs] = write_getfs,
|
[NFSD_Getfs] = write_getfs,
|
||||||
[NFSD_Fh] = write_filehandle,
|
[NFSD_Fh] = write_filehandle,
|
||||||
[NFSD_Threads] = write_threads,
|
[NFSD_Threads] = write_threads,
|
||||||
|
[NFSD_Versions] = write_versions,
|
||||||
|
#ifdef CONFIG_NFSD_V4
|
||||||
[NFSD_Leasetime] = write_leasetime,
|
[NFSD_Leasetime] = write_leasetime,
|
||||||
[NFSD_RecoveryDir] = write_recoverydir,
|
[NFSD_RecoveryDir] = write_recoverydir,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
|
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);
|
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);
|
extern time_t nfs4_leasetime(void);
|
||||||
|
|
||||||
static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
|
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);
|
status = nfs4_reset_recoverydir(recdir);
|
||||||
return strlen(buf);
|
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_List] = {"exports", &exports_operations, S_IRUGO},
|
||||||
[NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
|
[NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
|
||||||
[NFSD_Threads] = {"threads", &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
|
#ifdef CONFIG_NFSD_V4
|
||||||
[NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
|
[NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
|
||||||
[NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
|
[NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include <linux/nfsd/nfsd.h>
|
#include <linux/nfsd/nfsd.h>
|
||||||
#include <linux/nfsd/stats.h>
|
#include <linux/nfsd/stats.h>
|
||||||
#include <linux/nfsd/cache.h>
|
#include <linux/nfsd/cache.h>
|
||||||
|
#include <linux/nfsd/syscall.h>
|
||||||
#include <linux/lockd/bind.h>
|
#include <linux/lockd/bind.h>
|
||||||
#include <linux/nfsacl.h>
|
#include <linux/nfsacl.h>
|
||||||
|
|
||||||
@ -52,7 +53,7 @@
|
|||||||
extern struct svc_program nfsd_program;
|
extern struct svc_program nfsd_program;
|
||||||
static void nfsd(struct svc_rqst *rqstp);
|
static void nfsd(struct svc_rqst *rqstp);
|
||||||
struct timeval nfssvc_boot;
|
struct timeval nfssvc_boot;
|
||||||
static struct svc_serv *nfsd_serv;
|
struct svc_serv *nfsd_serv;
|
||||||
static atomic_t nfsd_busy;
|
static atomic_t nfsd_busy;
|
||||||
static unsigned long nfsd_last_call;
|
static unsigned long nfsd_last_call;
|
||||||
static DEFINE_SPINLOCK(nfsd_call_lock);
|
static DEFINE_SPINLOCK(nfsd_call_lock);
|
||||||
@ -63,6 +64,31 @@ struct nfsd_list {
|
|||||||
};
|
};
|
||||||
static struct list_head nfsd_list = LIST_HEAD_INIT(nfsd_list);
|
static struct list_head nfsd_list = LIST_HEAD_INIT(nfsd_list);
|
||||||
|
|
||||||
|
static struct svc_version * nfsd_version[] = {
|
||||||
|
[2] = &nfsd_version2,
|
||||||
|
#if defined(CONFIG_NFSD_V3)
|
||||||
|
[3] = &nfsd_version3,
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_NFSD_V4)
|
||||||
|
[4] = &nfsd_version4,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NFSD_MINVERS 2
|
||||||
|
#define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0]))
|
||||||
|
static struct svc_version *nfsd_versions[NFSD_NRVERS];
|
||||||
|
|
||||||
|
struct svc_program nfsd_program = {
|
||||||
|
.pg_prog = NFS_PROGRAM, /* program number */
|
||||||
|
.pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */
|
||||||
|
.pg_vers = nfsd_versions, /* version table */
|
||||||
|
.pg_name = "nfsd", /* program name */
|
||||||
|
.pg_class = "nfsd", /* authentication class */
|
||||||
|
.pg_stats = &nfsd_svcstats, /* version table */
|
||||||
|
.pg_authenticate = &svc_set_client, /* export authentication */
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Maximum number of nfsd processes
|
* Maximum number of nfsd processes
|
||||||
*/
|
*/
|
||||||
@ -80,11 +106,12 @@ int
|
|||||||
nfsd_svc(unsigned short port, int nrservs)
|
nfsd_svc(unsigned short port, int nrservs)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
int none_left;
|
int none_left, found_one, i;
|
||||||
struct list_head *victim;
|
struct list_head *victim;
|
||||||
|
|
||||||
lock_kernel();
|
lock_kernel();
|
||||||
dprintk("nfsd: creating service\n");
|
dprintk("nfsd: creating service: vers 0x%x\n",
|
||||||
|
nfsd_versbits);
|
||||||
error = -EINVAL;
|
error = -EINVAL;
|
||||||
if (nrservs <= 0)
|
if (nrservs <= 0)
|
||||||
nrservs = 0;
|
nrservs = 0;
|
||||||
@ -99,6 +126,27 @@ nfsd_svc(unsigned short port, int nrservs)
|
|||||||
if (error<0)
|
if (error<0)
|
||||||
goto out;
|
goto out;
|
||||||
if (!nfsd_serv) {
|
if (!nfsd_serv) {
|
||||||
|
/*
|
||||||
|
* Use the nfsd_ctlbits to define which
|
||||||
|
* versions that will be advertised.
|
||||||
|
* If nfsd_ctlbits doesn't list any version,
|
||||||
|
* export them all.
|
||||||
|
*/
|
||||||
|
found_one = 0;
|
||||||
|
|
||||||
|
for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) {
|
||||||
|
if (NFSCTL_VERISSET(nfsd_versbits, i)) {
|
||||||
|
nfsd_program.pg_vers[i] = nfsd_version[i];
|
||||||
|
found_one = 1;
|
||||||
|
} else
|
||||||
|
nfsd_program.pg_vers[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_one) {
|
||||||
|
for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++)
|
||||||
|
nfsd_program.pg_vers[i] = nfsd_version[i];
|
||||||
|
}
|
||||||
|
|
||||||
atomic_set(&nfsd_busy, 0);
|
atomic_set(&nfsd_busy, 0);
|
||||||
error = -ENOMEM;
|
error = -ENOMEM;
|
||||||
nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE);
|
nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE);
|
||||||
@ -389,28 +437,3 @@ static struct svc_stat nfsd_acl_svcstats = {
|
|||||||
#else
|
#else
|
||||||
#define nfsd_acl_program_p NULL
|
#define nfsd_acl_program_p NULL
|
||||||
#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
|
#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
|
||||||
|
|
||||||
extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4;
|
|
||||||
|
|
||||||
static struct svc_version * nfsd_version[] = {
|
|
||||||
[2] = &nfsd_version2,
|
|
||||||
#if defined(CONFIG_NFSD_V3)
|
|
||||||
[3] = &nfsd_version3,
|
|
||||||
#endif
|
|
||||||
#if defined(CONFIG_NFSD_V4)
|
|
||||||
[4] = &nfsd_version4,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0]))
|
|
||||||
struct svc_program nfsd_program = {
|
|
||||||
.pg_next = nfsd_acl_program_p,
|
|
||||||
.pg_prog = NFS_PROGRAM, /* program number */
|
|
||||||
.pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */
|
|
||||||
.pg_vers = nfsd_version, /* version table */
|
|
||||||
.pg_name = "nfsd", /* program name */
|
|
||||||
.pg_class = "nfsd", /* authentication class */
|
|
||||||
.pg_stats = &nfsd_svcstats, /* version table */
|
|
||||||
.pg_authenticate = &svc_set_client, /* export authentication */
|
|
||||||
|
|
||||||
};
|
|
||||||
|
@ -60,7 +60,7 @@ typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int);
|
|||||||
extern struct svc_program nfsd_program;
|
extern struct svc_program nfsd_program;
|
||||||
extern struct svc_version nfsd_version2, nfsd_version3,
|
extern struct svc_version nfsd_version2, nfsd_version3,
|
||||||
nfsd_version4;
|
nfsd_version4;
|
||||||
|
extern struct svc_serv *nfsd_serv;
|
||||||
/*
|
/*
|
||||||
* Function prototypes.
|
* Function prototypes.
|
||||||
*/
|
*/
|
||||||
|
@ -39,6 +39,21 @@
|
|||||||
#define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */
|
#define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */
|
||||||
#define NFSCTL_GETFS 8 /* get an fh by path with max FH len */
|
#define NFSCTL_GETFS 8 /* get an fh by path with max FH len */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macros used to set version
|
||||||
|
*/
|
||||||
|
#define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << (_v)))
|
||||||
|
#define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << (_v)))
|
||||||
|
#define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << (_v)))
|
||||||
|
|
||||||
|
#if defined(CONFIG_NFSD_V4)
|
||||||
|
#define NFSCTL_VERALL (0x1c /* 0b011100 */)
|
||||||
|
#elif defined(CONFIG_NFSD_V3)
|
||||||
|
#define NFSCTL_VERALL (0x0c /* 0b001100 */)
|
||||||
|
#else
|
||||||
|
#define NFSCTL_VERALL (0x04 /* 0b000100 */)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* SVC */
|
/* SVC */
|
||||||
struct nfsctl_svc {
|
struct nfsctl_svc {
|
||||||
unsigned short svc_port;
|
unsigned short svc_port;
|
||||||
@ -120,6 +135,8 @@ extern int exp_delclient(struct nfsctl_client *ncp);
|
|||||||
extern int exp_export(struct nfsctl_export *nxp);
|
extern int exp_export(struct nfsctl_export *nxp);
|
||||||
extern int exp_unexport(struct nfsctl_export *nxp);
|
extern int exp_unexport(struct nfsctl_export *nxp);
|
||||||
|
|
||||||
|
extern unsigned int nfsd_versbits;
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
#endif /* __KERNEL__ */
|
||||||
|
|
||||||
#endif /* NFSD_SYSCALL_H */
|
#endif /* NFSD_SYSCALL_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user