📄 nfsctl.c
字号:
/* * linux/fs/nfsd/nfsctl.c * * Syscall interface to knfsd. * * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */#include <linux/module.h>#include <linux/linkage.h>#include <linux/time.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/fcntl.h>#include <linux/net.h>#include <linux/in.h>#include <linux/syscalls.h>#include <linux/unistd.h>#include <linux/slab.h>#include <linux/proc_fs.h>#include <linux/seq_file.h>#include <linux/pagemap.h>#include <linux/init.h>#include <linux/string.h>#include <linux/smp_lock.h>#include <linux/ctype.h>#include <linux/nfs.h>#include <linux/nfsd_idmap.h>#include <linux/lockd/bind.h>#include <linux/sunrpc/svc.h>#include <linux/sunrpc/svcsock.h>#include <linux/nfsd/nfsd.h>#include <linux/nfsd/cache.h>#include <linux/nfsd/xdr.h>#include <linux/nfsd/syscall.h>#include <asm/uaccess.h>/* * We have a single directory with 9 nodes in it. */enum { NFSD_Root = 1, NFSD_Svc, NFSD_Add, NFSD_Del, NFSD_Export, NFSD_Unexport, NFSD_Getfd, NFSD_Getfs, NFSD_List, NFSD_Fh, NFSD_Threads, NFSD_Pool_Threads, NFSD_Versions, NFSD_Ports, NFSD_MaxBlkSize, /* * 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};/* * write() for these nodes. */static ssize_t write_svc(struct file *file, char *buf, size_t size);static ssize_t write_add(struct file *file, char *buf, size_t size);static ssize_t write_del(struct file *file, char *buf, size_t size);static ssize_t write_export(struct file *file, char *buf, size_t size);static ssize_t write_unexport(struct file *file, char *buf, size_t size);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_pool_threads(struct file *file, char *buf, size_t size);static ssize_t write_versions(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_maxblksize(struct file *file, char *buf, size_t size);#ifdef CONFIG_NFSD_V4static 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);#endifstatic ssize_t (*write_op[])(struct file *, char *, size_t) = { [NFSD_Svc] = write_svc, [NFSD_Add] = write_add, [NFSD_Del] = write_del, [NFSD_Export] = write_export, [NFSD_Unexport] = write_unexport, [NFSD_Getfd] = write_getfd, [NFSD_Getfs] = write_getfs, [NFSD_Fh] = write_filehandle, [NFSD_Threads] = write_threads, [NFSD_Pool_Threads] = write_pool_threads, [NFSD_Versions] = write_versions, [NFSD_Ports] = write_ports, [NFSD_MaxBlkSize] = write_maxblksize,#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_path.dentry->d_inode->i_ino; char *data; ssize_t rv; if (ino >= ARRAY_SIZE(write_op) || !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); rv = size; } 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 const struct file_operations transaction_ops = { .write = nfsctl_transaction_write, .read = nfsctl_transaction_read, .release = simple_transaction_release,};extern struct seq_operations nfs_exports_op;static int exports_open(struct inode *inode, struct file *file){ return seq_open(file, &nfs_exports_op);}static const struct file_operations exports_operations = { .open = exports_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release,};/*----------------------------------------------------------------------------*//* * payload - write methods * If the method has a response, the response should be put in buf, * and the length returned. Otherwise return 0 or and -error. */static ssize_t write_svc(struct file *file, char *buf, size_t size){ struct nfsctl_svc *data; if (size < sizeof(*data)) return -EINVAL; data = (struct nfsctl_svc*) buf; return nfsd_svc(data->svc_port, data->svc_nthreads);}static ssize_t write_add(struct file *file, char *buf, size_t size){ struct nfsctl_client *data; if (size < sizeof(*data)) return -EINVAL; data = (struct nfsctl_client *)buf; return exp_addclient(data);}static ssize_t write_del(struct file *file, char *buf, size_t size){ struct nfsctl_client *data; if (size < sizeof(*data)) return -EINVAL; data = (struct nfsctl_client *)buf; return exp_delclient(data);}static ssize_t write_export(struct file *file, char *buf, size_t size){ struct nfsctl_export *data; if (size < sizeof(*data)) return -EINVAL; data = (struct nfsctl_export*)buf; return exp_export(data);}static ssize_t write_unexport(struct file *file, char *buf, size_t size){ struct nfsctl_export *data; if (size < sizeof(*data)) return -EINVAL; data = (struct nfsctl_export*)buf; return exp_unexport(data);}static ssize_t write_getfs(struct file *file, char *buf, size_t size){ struct nfsctl_fsparm *data; struct sockaddr_in *sin; struct auth_domain *clp; int err = 0; struct knfsd_fh *res; if (size < sizeof(*data)) return -EINVAL; data = (struct nfsctl_fsparm*)buf; err = -EPROTONOSUPPORT; if (data->gd_addr.sa_family != AF_INET) goto out; sin = (struct sockaddr_in *)&data->gd_addr; if (data->gd_maxlen > NFS3_FHSIZE) data->gd_maxlen = NFS3_FHSIZE; res = (struct knfsd_fh*)buf; exp_readlock(); if (!(clp = auth_unix_lookup(sin->sin_addr))) err = -EPERM; else { err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen); auth_domain_put(clp); } exp_readunlock(); if (err == 0) err = res->fh_size + offsetof(struct knfsd_fh, fh_base); out: return err;}static ssize_t write_getfd(struct file *file, char *buf, size_t size){ struct nfsctl_fdparm *data; struct sockaddr_in *sin; struct auth_domain *clp; int err = 0; struct knfsd_fh fh; char *res; if (size < sizeof(*data)) return -EINVAL; data = (struct nfsctl_fdparm*)buf; err = -EPROTONOSUPPORT; if (data->gd_addr.sa_family != AF_INET) goto out; err = -EINVAL; if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS) goto out; res = buf; sin = (struct sockaddr_in *)&data->gd_addr; exp_readlock(); if (!(clp = auth_unix_lookup(sin->sin_addr))) err = -EPERM; else { err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE); auth_domain_put(clp); } exp_readunlock(); if (err == 0) { memset(res,0, NFS_FHSIZE); memcpy(res, &fh.fh_base, fh.fh_size); err = NFS_FHSIZE; } out: return err;}static ssize_t write_filehandle(struct file *file, char *buf, size_t size){ /* request is: * domain path maxsize * response is * filehandle * * qword quoting is used, so filehandle will be \x.... */ char *dname, *path; int uninitialized_var(maxsize); char *mesg = buf; int len; struct auth_domain *dom; struct knfsd_fh fh; if (buf[size-1] != '\n') return -EINVAL; buf[size-1] = 0; dname = mesg; len = qword_get(&mesg, dname, size); if (len <= 0) return -EINVAL; path = dname+len+1; len = qword_get(&mesg, path, size); if (len <= 0) return -EINVAL; len = get_int(&mesg, &maxsize); if (len) return len; if (maxsize < NFS_FHSIZE) return -EINVAL; if (maxsize > NFS3_FHSIZE) maxsize = NFS3_FHSIZE; if (qword_get(&mesg, mesg, size)>0) return -EINVAL; /* we have all the words, they are in buf.. */ dom = unix_domain_find(dname); if (!dom) return -ENOMEM; len = exp_rootfh(dom, path, &fh, maxsize); auth_domain_put(dom); if (len) return len; mesg = buf; len = SIMPLE_TRANSACTION_LIMIT; qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size); mesg[-1] = '\n'; return mesg - buf; }extern int nfsd_nrthreads(void);static ssize_t write_threads(struct file *file, char *buf, size_t size){ /* if size > 0, look for a number of threads and call nfsd_svc * then write out number of threads as reply */ char *mesg = buf; int rv; if (size > 0) { int newthreads; rv = get_int(&mesg, &newthreads); if (rv) return rv; if (newthreads <0) return -EINVAL; rv = nfsd_svc(2049, newthreads);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -