11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/nfsd/nfsctl.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Syscall interface to knfsd. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds #include <linux/config.h> 101da177e4SLinus Torvalds #include <linux/module.h> 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/linkage.h> 131da177e4SLinus Torvalds #include <linux/time.h> 141da177e4SLinus Torvalds #include <linux/errno.h> 151da177e4SLinus Torvalds #include <linux/fs.h> 161da177e4SLinus Torvalds #include <linux/fcntl.h> 171da177e4SLinus Torvalds #include <linux/net.h> 181da177e4SLinus Torvalds #include <linux/in.h> 191da177e4SLinus Torvalds #include <linux/syscalls.h> 201da177e4SLinus Torvalds #include <linux/unistd.h> 211da177e4SLinus Torvalds #include <linux/slab.h> 221da177e4SLinus Torvalds #include <linux/proc_fs.h> 231da177e4SLinus Torvalds #include <linux/seq_file.h> 241da177e4SLinus Torvalds #include <linux/pagemap.h> 251da177e4SLinus Torvalds #include <linux/init.h> 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds #include <linux/nfs.h> 281da177e4SLinus Torvalds #include <linux/nfsd_idmap.h> 291da177e4SLinus Torvalds #include <linux/sunrpc/svc.h> 301da177e4SLinus Torvalds #include <linux/nfsd/nfsd.h> 311da177e4SLinus Torvalds #include <linux/nfsd/cache.h> 321da177e4SLinus Torvalds #include <linux/nfsd/xdr.h> 331da177e4SLinus Torvalds #include <linux/nfsd/syscall.h> 341da177e4SLinus Torvalds #include <linux/nfsd/interface.h> 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds #include <asm/uaccess.h> 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds /* 391da177e4SLinus Torvalds * We have a single directory with 9 nodes in it. 401da177e4SLinus Torvalds */ 411da177e4SLinus Torvalds enum { 421da177e4SLinus Torvalds NFSD_Root = 1, 431da177e4SLinus Torvalds NFSD_Svc, 441da177e4SLinus Torvalds NFSD_Add, 451da177e4SLinus Torvalds NFSD_Del, 461da177e4SLinus Torvalds NFSD_Export, 471da177e4SLinus Torvalds NFSD_Unexport, 481da177e4SLinus Torvalds NFSD_Getfd, 491da177e4SLinus Torvalds NFSD_Getfs, 501da177e4SLinus Torvalds NFSD_List, 511da177e4SLinus Torvalds NFSD_Fh, 521da177e4SLinus Torvalds NFSD_Threads, 531da177e4SLinus Torvalds NFSD_Leasetime, 540964a3d3SNeilBrown NFSD_RecoveryDir, 551da177e4SLinus Torvalds }; 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds /* 581da177e4SLinus Torvalds * write() for these nodes. 591da177e4SLinus Torvalds */ 601da177e4SLinus Torvalds static ssize_t write_svc(struct file *file, char *buf, size_t size); 611da177e4SLinus Torvalds static ssize_t write_add(struct file *file, char *buf, size_t size); 621da177e4SLinus Torvalds static ssize_t write_del(struct file *file, char *buf, size_t size); 631da177e4SLinus Torvalds static ssize_t write_export(struct file *file, char *buf, size_t size); 641da177e4SLinus Torvalds static ssize_t write_unexport(struct file *file, char *buf, size_t size); 651da177e4SLinus Torvalds static ssize_t write_getfd(struct file *file, char *buf, size_t size); 661da177e4SLinus Torvalds static ssize_t write_getfs(struct file *file, char *buf, size_t size); 671da177e4SLinus Torvalds static ssize_t write_filehandle(struct file *file, char *buf, size_t size); 681da177e4SLinus Torvalds static ssize_t write_threads(struct file *file, char *buf, size_t size); 691da177e4SLinus Torvalds static ssize_t write_leasetime(struct file *file, char *buf, size_t size); 700964a3d3SNeilBrown static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds static ssize_t (*write_op[])(struct file *, char *, size_t) = { 731da177e4SLinus Torvalds [NFSD_Svc] = write_svc, 741da177e4SLinus Torvalds [NFSD_Add] = write_add, 751da177e4SLinus Torvalds [NFSD_Del] = write_del, 761da177e4SLinus Torvalds [NFSD_Export] = write_export, 771da177e4SLinus Torvalds [NFSD_Unexport] = write_unexport, 781da177e4SLinus Torvalds [NFSD_Getfd] = write_getfd, 791da177e4SLinus Torvalds [NFSD_Getfs] = write_getfs, 801da177e4SLinus Torvalds [NFSD_Fh] = write_filehandle, 811da177e4SLinus Torvalds [NFSD_Threads] = write_threads, 821da177e4SLinus Torvalds [NFSD_Leasetime] = write_leasetime, 830964a3d3SNeilBrown [NFSD_RecoveryDir] = write_recoverydir, 841da177e4SLinus Torvalds }; 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) 871da177e4SLinus Torvalds { 881da177e4SLinus Torvalds ino_t ino = file->f_dentry->d_inode->i_ino; 891da177e4SLinus Torvalds char *data; 901da177e4SLinus Torvalds ssize_t rv; 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds if (ino >= sizeof(write_op)/sizeof(write_op[0]) || !write_op[ino]) 931da177e4SLinus Torvalds return -EINVAL; 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds data = simple_transaction_get(file, buf, size); 961da177e4SLinus Torvalds if (IS_ERR(data)) 971da177e4SLinus Torvalds return PTR_ERR(data); 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds rv = write_op[ino](file, data, size); 1001da177e4SLinus Torvalds if (rv>0) { 1011da177e4SLinus Torvalds simple_transaction_set(file, rv); 1021da177e4SLinus Torvalds rv = size; 1031da177e4SLinus Torvalds } 1041da177e4SLinus Torvalds return rv; 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds 1077390022dSNeilBrown static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos) 1087390022dSNeilBrown { 1097390022dSNeilBrown if (! file->private_data) { 1107390022dSNeilBrown /* An attempt to read a transaction file without writing 1117390022dSNeilBrown * causes a 0-byte write so that the file can return 1127390022dSNeilBrown * state information 1137390022dSNeilBrown */ 1147390022dSNeilBrown ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos); 1157390022dSNeilBrown if (rv < 0) 1167390022dSNeilBrown return rv; 1177390022dSNeilBrown } 1187390022dSNeilBrown return simple_transaction_read(file, buf, size, pos); 1197390022dSNeilBrown } 1207390022dSNeilBrown 1211da177e4SLinus Torvalds static struct file_operations transaction_ops = { 1221da177e4SLinus Torvalds .write = nfsctl_transaction_write, 1237390022dSNeilBrown .read = nfsctl_transaction_read, 1241da177e4SLinus Torvalds .release = simple_transaction_release, 1251da177e4SLinus Torvalds }; 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds extern struct seq_operations nfs_exports_op; 1281da177e4SLinus Torvalds static int exports_open(struct inode *inode, struct file *file) 1291da177e4SLinus Torvalds { 1301da177e4SLinus Torvalds return seq_open(file, &nfs_exports_op); 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds static struct file_operations exports_operations = { 1341da177e4SLinus Torvalds .open = exports_open, 1351da177e4SLinus Torvalds .read = seq_read, 1361da177e4SLinus Torvalds .llseek = seq_lseek, 1371da177e4SLinus Torvalds .release = seq_release, 1381da177e4SLinus Torvalds }; 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds /*----------------------------------------------------------------------------*/ 1411da177e4SLinus Torvalds /* 1421da177e4SLinus Torvalds * payload - write methods 1431da177e4SLinus Torvalds * If the method has a response, the response should be put in buf, 1441da177e4SLinus Torvalds * and the length returned. Otherwise return 0 or and -error. 1451da177e4SLinus Torvalds */ 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds static ssize_t write_svc(struct file *file, char *buf, size_t size) 1481da177e4SLinus Torvalds { 1491da177e4SLinus Torvalds struct nfsctl_svc *data; 1501da177e4SLinus Torvalds if (size < sizeof(*data)) 1511da177e4SLinus Torvalds return -EINVAL; 1521da177e4SLinus Torvalds data = (struct nfsctl_svc*) buf; 1531da177e4SLinus Torvalds return nfsd_svc(data->svc_port, data->svc_nthreads); 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds static ssize_t write_add(struct file *file, char *buf, size_t size) 1571da177e4SLinus Torvalds { 1581da177e4SLinus Torvalds struct nfsctl_client *data; 1591da177e4SLinus Torvalds if (size < sizeof(*data)) 1601da177e4SLinus Torvalds return -EINVAL; 1611da177e4SLinus Torvalds data = (struct nfsctl_client *)buf; 1621da177e4SLinus Torvalds return exp_addclient(data); 1631da177e4SLinus Torvalds } 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds static ssize_t write_del(struct file *file, char *buf, size_t size) 1661da177e4SLinus Torvalds { 1671da177e4SLinus Torvalds struct nfsctl_client *data; 1681da177e4SLinus Torvalds if (size < sizeof(*data)) 1691da177e4SLinus Torvalds return -EINVAL; 1701da177e4SLinus Torvalds data = (struct nfsctl_client *)buf; 1711da177e4SLinus Torvalds return exp_delclient(data); 1721da177e4SLinus Torvalds } 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds static ssize_t write_export(struct file *file, char *buf, size_t size) 1751da177e4SLinus Torvalds { 1761da177e4SLinus Torvalds struct nfsctl_export *data; 1771da177e4SLinus Torvalds if (size < sizeof(*data)) 1781da177e4SLinus Torvalds return -EINVAL; 1791da177e4SLinus Torvalds data = (struct nfsctl_export*)buf; 1801da177e4SLinus Torvalds return exp_export(data); 1811da177e4SLinus Torvalds } 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds static ssize_t write_unexport(struct file *file, char *buf, size_t size) 1841da177e4SLinus Torvalds { 1851da177e4SLinus Torvalds struct nfsctl_export *data; 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds if (size < sizeof(*data)) 1881da177e4SLinus Torvalds return -EINVAL; 1891da177e4SLinus Torvalds data = (struct nfsctl_export*)buf; 1901da177e4SLinus Torvalds return exp_unexport(data); 1911da177e4SLinus Torvalds } 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds static ssize_t write_getfs(struct file *file, char *buf, size_t size) 1941da177e4SLinus Torvalds { 1951da177e4SLinus Torvalds struct nfsctl_fsparm *data; 1961da177e4SLinus Torvalds struct sockaddr_in *sin; 1971da177e4SLinus Torvalds struct auth_domain *clp; 1981da177e4SLinus Torvalds int err = 0; 1991da177e4SLinus Torvalds struct knfsd_fh *res; 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds if (size < sizeof(*data)) 2021da177e4SLinus Torvalds return -EINVAL; 2031da177e4SLinus Torvalds data = (struct nfsctl_fsparm*)buf; 2041da177e4SLinus Torvalds err = -EPROTONOSUPPORT; 2051da177e4SLinus Torvalds if (data->gd_addr.sa_family != AF_INET) 2061da177e4SLinus Torvalds goto out; 2071da177e4SLinus Torvalds sin = (struct sockaddr_in *)&data->gd_addr; 2081da177e4SLinus Torvalds if (data->gd_maxlen > NFS3_FHSIZE) 2091da177e4SLinus Torvalds data->gd_maxlen = NFS3_FHSIZE; 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds res = (struct knfsd_fh*)buf; 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds exp_readlock(); 2141da177e4SLinus Torvalds if (!(clp = auth_unix_lookup(sin->sin_addr))) 2151da177e4SLinus Torvalds err = -EPERM; 2161da177e4SLinus Torvalds else { 2171da177e4SLinus Torvalds err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen); 2181da177e4SLinus Torvalds auth_domain_put(clp); 2191da177e4SLinus Torvalds } 2201da177e4SLinus Torvalds exp_readunlock(); 2211da177e4SLinus Torvalds if (err == 0) 2221da177e4SLinus Torvalds err = res->fh_size + (int)&((struct knfsd_fh*)0)->fh_base; 2231da177e4SLinus Torvalds out: 2241da177e4SLinus Torvalds return err; 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds static ssize_t write_getfd(struct file *file, char *buf, size_t size) 2281da177e4SLinus Torvalds { 2291da177e4SLinus Torvalds struct nfsctl_fdparm *data; 2301da177e4SLinus Torvalds struct sockaddr_in *sin; 2311da177e4SLinus Torvalds struct auth_domain *clp; 2321da177e4SLinus Torvalds int err = 0; 2331da177e4SLinus Torvalds struct knfsd_fh fh; 2341da177e4SLinus Torvalds char *res; 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds if (size < sizeof(*data)) 2371da177e4SLinus Torvalds return -EINVAL; 2381da177e4SLinus Torvalds data = (struct nfsctl_fdparm*)buf; 2391da177e4SLinus Torvalds err = -EPROTONOSUPPORT; 2401da177e4SLinus Torvalds if (data->gd_addr.sa_family != AF_INET) 2411da177e4SLinus Torvalds goto out; 2421da177e4SLinus Torvalds err = -EINVAL; 2431da177e4SLinus Torvalds if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS) 2441da177e4SLinus Torvalds goto out; 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds res = buf; 2471da177e4SLinus Torvalds sin = (struct sockaddr_in *)&data->gd_addr; 2481da177e4SLinus Torvalds exp_readlock(); 2491da177e4SLinus Torvalds if (!(clp = auth_unix_lookup(sin->sin_addr))) 2501da177e4SLinus Torvalds err = -EPERM; 2511da177e4SLinus Torvalds else { 2521da177e4SLinus Torvalds err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE); 2531da177e4SLinus Torvalds auth_domain_put(clp); 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds exp_readunlock(); 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds if (err == 0) { 2581da177e4SLinus Torvalds memset(res,0, NFS_FHSIZE); 2591da177e4SLinus Torvalds memcpy(res, &fh.fh_base, fh.fh_size); 2601da177e4SLinus Torvalds err = NFS_FHSIZE; 2611da177e4SLinus Torvalds } 2621da177e4SLinus Torvalds out: 2631da177e4SLinus Torvalds return err; 2641da177e4SLinus Torvalds } 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds static ssize_t write_filehandle(struct file *file, char *buf, size_t size) 2671da177e4SLinus Torvalds { 2681da177e4SLinus Torvalds /* request is: 2691da177e4SLinus Torvalds * domain path maxsize 2701da177e4SLinus Torvalds * response is 2711da177e4SLinus Torvalds * filehandle 2721da177e4SLinus Torvalds * 2731da177e4SLinus Torvalds * qword quoting is used, so filehandle will be \x.... 2741da177e4SLinus Torvalds */ 2751da177e4SLinus Torvalds char *dname, *path; 2761da177e4SLinus Torvalds int maxsize; 2771da177e4SLinus Torvalds char *mesg = buf; 2781da177e4SLinus Torvalds int len; 2791da177e4SLinus Torvalds struct auth_domain *dom; 2801da177e4SLinus Torvalds struct knfsd_fh fh; 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds if (buf[size-1] != '\n') 2831da177e4SLinus Torvalds return -EINVAL; 2841da177e4SLinus Torvalds buf[size-1] = 0; 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds dname = mesg; 2871da177e4SLinus Torvalds len = qword_get(&mesg, dname, size); 2881da177e4SLinus Torvalds if (len <= 0) return -EINVAL; 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds path = dname+len+1; 2911da177e4SLinus Torvalds len = qword_get(&mesg, path, size); 2921da177e4SLinus Torvalds if (len <= 0) return -EINVAL; 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds len = get_int(&mesg, &maxsize); 2951da177e4SLinus Torvalds if (len) 2961da177e4SLinus Torvalds return len; 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds if (maxsize < NFS_FHSIZE) 2991da177e4SLinus Torvalds return -EINVAL; 3001da177e4SLinus Torvalds if (maxsize > NFS3_FHSIZE) 3011da177e4SLinus Torvalds maxsize = NFS3_FHSIZE; 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds if (qword_get(&mesg, mesg, size)>0) 3041da177e4SLinus Torvalds return -EINVAL; 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds /* we have all the words, they are in buf.. */ 3071da177e4SLinus Torvalds dom = unix_domain_find(dname); 3081da177e4SLinus Torvalds if (!dom) 3091da177e4SLinus Torvalds return -ENOMEM; 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds len = exp_rootfh(dom, path, &fh, maxsize); 3121da177e4SLinus Torvalds auth_domain_put(dom); 3131da177e4SLinus Torvalds if (len) 3141da177e4SLinus Torvalds return len; 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds mesg = buf; len = SIMPLE_TRANSACTION_LIMIT; 3171da177e4SLinus Torvalds qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size); 3181da177e4SLinus Torvalds mesg[-1] = '\n'; 3191da177e4SLinus Torvalds return mesg - buf; 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds extern int nfsd_nrthreads(void); 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds static ssize_t write_threads(struct file *file, char *buf, size_t size) 3251da177e4SLinus Torvalds { 3261da177e4SLinus Torvalds /* if size > 0, look for a number of threads and call nfsd_svc 3271da177e4SLinus Torvalds * then write out number of threads as reply 3281da177e4SLinus Torvalds */ 3291da177e4SLinus Torvalds char *mesg = buf; 3301da177e4SLinus Torvalds int rv; 3311da177e4SLinus Torvalds if (size > 0) { 3321da177e4SLinus Torvalds int newthreads; 3331da177e4SLinus Torvalds rv = get_int(&mesg, &newthreads); 3341da177e4SLinus Torvalds if (rv) 3351da177e4SLinus Torvalds return rv; 3361da177e4SLinus Torvalds if (newthreads <0) 3371da177e4SLinus Torvalds return -EINVAL; 3381da177e4SLinus Torvalds rv = nfsd_svc(2049, newthreads); 3391da177e4SLinus Torvalds if (rv) 3401da177e4SLinus Torvalds return rv; 3411da177e4SLinus Torvalds } 3421da177e4SLinus Torvalds sprintf(buf, "%d\n", nfsd_nrthreads()); 3431da177e4SLinus Torvalds return strlen(buf); 3441da177e4SLinus Torvalds } 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds extern time_t nfs4_leasetime(void); 3471da177e4SLinus Torvalds 3481da177e4SLinus Torvalds static ssize_t write_leasetime(struct file *file, char *buf, size_t size) 3491da177e4SLinus Torvalds { 3501da177e4SLinus Torvalds /* if size > 10 seconds, call 3511da177e4SLinus Torvalds * nfs4_reset_lease() then write out the new lease (seconds) as reply 3521da177e4SLinus Torvalds */ 3531da177e4SLinus Torvalds char *mesg = buf; 3541da177e4SLinus Torvalds int rv; 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds if (size > 0) { 3571da177e4SLinus Torvalds int lease; 3581da177e4SLinus Torvalds rv = get_int(&mesg, &lease); 3591da177e4SLinus Torvalds if (rv) 3601da177e4SLinus Torvalds return rv; 3611da177e4SLinus Torvalds if (lease < 10 || lease > 3600) 3621da177e4SLinus Torvalds return -EINVAL; 3631da177e4SLinus Torvalds nfs4_reset_lease(lease); 3641da177e4SLinus Torvalds } 3651da177e4SLinus Torvalds sprintf(buf, "%ld\n", nfs4_lease_time()); 3661da177e4SLinus Torvalds return strlen(buf); 3671da177e4SLinus Torvalds } 3681da177e4SLinus Torvalds 3690964a3d3SNeilBrown static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) 3700964a3d3SNeilBrown { 3710964a3d3SNeilBrown char *mesg = buf; 3720964a3d3SNeilBrown char *recdir; 3730964a3d3SNeilBrown int len, status; 3740964a3d3SNeilBrown 3750964a3d3SNeilBrown if (size > PATH_MAX || buf[size-1] != '\n') 3760964a3d3SNeilBrown return -EINVAL; 3770964a3d3SNeilBrown buf[size-1] = 0; 3780964a3d3SNeilBrown 3790964a3d3SNeilBrown recdir = mesg; 3800964a3d3SNeilBrown len = qword_get(&mesg, recdir, size); 3810964a3d3SNeilBrown if (len <= 0) 3820964a3d3SNeilBrown return -EINVAL; 3830964a3d3SNeilBrown 3840964a3d3SNeilBrown status = nfs4_reset_recoverydir(recdir); 3850964a3d3SNeilBrown return strlen(buf); 3860964a3d3SNeilBrown } 3870964a3d3SNeilBrown 3881da177e4SLinus Torvalds /*----------------------------------------------------------------------------*/ 3891da177e4SLinus Torvalds /* 3901da177e4SLinus Torvalds * populating the filesystem. 3911da177e4SLinus Torvalds */ 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds static int nfsd_fill_super(struct super_block * sb, void * data, int silent) 3941da177e4SLinus Torvalds { 3951da177e4SLinus Torvalds static struct tree_descr nfsd_files[] = { 3961da177e4SLinus Torvalds [NFSD_Svc] = {".svc", &transaction_ops, S_IWUSR}, 3971da177e4SLinus Torvalds [NFSD_Add] = {".add", &transaction_ops, S_IWUSR}, 3981da177e4SLinus Torvalds [NFSD_Del] = {".del", &transaction_ops, S_IWUSR}, 3991da177e4SLinus Torvalds [NFSD_Export] = {".export", &transaction_ops, S_IWUSR}, 4001da177e4SLinus Torvalds [NFSD_Unexport] = {".unexport", &transaction_ops, S_IWUSR}, 4011da177e4SLinus Torvalds [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR}, 4021da177e4SLinus Torvalds [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR}, 4031da177e4SLinus Torvalds [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, 4041da177e4SLinus Torvalds [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, 4051da177e4SLinus Torvalds [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, 4061da177e4SLinus Torvalds #ifdef CONFIG_NFSD_V4 4071da177e4SLinus Torvalds [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, 4080964a3d3SNeilBrown [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, 4091da177e4SLinus Torvalds #endif 4101da177e4SLinus Torvalds /* last one */ {""} 4111da177e4SLinus Torvalds }; 4121da177e4SLinus Torvalds return simple_fill_super(sb, 0x6e667364, nfsd_files); 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds static struct super_block *nfsd_get_sb(struct file_system_type *fs_type, 4161da177e4SLinus Torvalds int flags, const char *dev_name, void *data) 4171da177e4SLinus Torvalds { 4181da177e4SLinus Torvalds return get_sb_single(fs_type, flags, data, nfsd_fill_super); 4191da177e4SLinus Torvalds } 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds static struct file_system_type nfsd_fs_type = { 4221da177e4SLinus Torvalds .owner = THIS_MODULE, 4231da177e4SLinus Torvalds .name = "nfsd", 4241da177e4SLinus Torvalds .get_sb = nfsd_get_sb, 4251da177e4SLinus Torvalds .kill_sb = kill_litter_super, 4261da177e4SLinus Torvalds }; 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds static int __init init_nfsd(void) 4291da177e4SLinus Torvalds { 4301da177e4SLinus Torvalds int retval; 4311da177e4SLinus Torvalds printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n"); 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds nfsd_stat_init(); /* Statistics */ 4341da177e4SLinus Torvalds nfsd_cache_init(); /* RPC reply cache */ 4351da177e4SLinus Torvalds nfsd_export_init(); /* Exports table */ 4361da177e4SLinus Torvalds nfsd_lockd_init(); /* lockd->nfsd callbacks */ 437ac4d8ff2SNeilBrown nfs4_state_init(); /* NFSv4 locking state */ 4381da177e4SLinus Torvalds nfsd_idmap_init(); /* Name to ID mapping */ 4391da177e4SLinus Torvalds if (proc_mkdir("fs/nfs", NULL)) { 4401da177e4SLinus Torvalds struct proc_dir_entry *entry; 4411da177e4SLinus Torvalds entry = create_proc_entry("fs/nfs/exports", 0, NULL); 4421da177e4SLinus Torvalds if (entry) 4431da177e4SLinus Torvalds entry->proc_fops = &exports_operations; 4441da177e4SLinus Torvalds } 4451da177e4SLinus Torvalds retval = register_filesystem(&nfsd_fs_type); 4461da177e4SLinus Torvalds if (retval) { 4471da177e4SLinus Torvalds nfsd_export_shutdown(); 4481da177e4SLinus Torvalds nfsd_cache_shutdown(); 4491da177e4SLinus Torvalds remove_proc_entry("fs/nfs/exports", NULL); 4501da177e4SLinus Torvalds remove_proc_entry("fs/nfs", NULL); 4511da177e4SLinus Torvalds nfsd_stat_shutdown(); 4521da177e4SLinus Torvalds nfsd_lockd_shutdown(); 4531da177e4SLinus Torvalds } 4541da177e4SLinus Torvalds return retval; 4551da177e4SLinus Torvalds } 4561da177e4SLinus Torvalds 4571da177e4SLinus Torvalds static void __exit exit_nfsd(void) 4581da177e4SLinus Torvalds { 4591da177e4SLinus Torvalds nfsd_export_shutdown(); 4601da177e4SLinus Torvalds nfsd_cache_shutdown(); 4611da177e4SLinus Torvalds remove_proc_entry("fs/nfs/exports", NULL); 4621da177e4SLinus Torvalds remove_proc_entry("fs/nfs", NULL); 4631da177e4SLinus Torvalds nfsd_stat_shutdown(); 4641da177e4SLinus Torvalds nfsd_lockd_shutdown(); 4651da177e4SLinus Torvalds nfsd_idmap_shutdown(); 4661da177e4SLinus Torvalds unregister_filesystem(&nfsd_fs_type); 4671da177e4SLinus Torvalds } 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); 4701da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 4711da177e4SLinus Torvalds module_init(init_nfsd) 4721da177e4SLinus Torvalds module_exit(exit_nfsd) 473