From: Alexander Viro <viro@math.psu.edu> To: Linus Torvalds <torvalds@transmeta.com> Subject: [PATCH] nfsd as filesystem Date: Wed, 13 Mar 2002 02:42:47 -0500 (EST) Cc: linux-fsdevel@vger.kernel.org Patch below * introduces a new filesystem - nfsd. No, it's not a typo. It's a small tree with fixed topology defined by nfsd and IO on its files does what we used to do by hand in nfsctl.c. * turns sys_nfsservctl() into a sequence of open()/write()/read()/close() It works as it used to - we don't need nfsd to be mounted anywhere, etc. * nfsd_linkage ugliness is gone. * getfs and getfh demonstrate (rather trivial) example of "descriptor as transaction descriptor" behaviour. * we are fairly close to the situation when driver-defined filesystems can be done with practically zero code overhead. We are still not there, but it's a matter of adding a couple of helpers for populating the tree. One thing we get immediately is a cleanup of sys_nfsservctl() - it got _much_ better. Moreover, we get an alternative interface that uses normal file IO and can be used without magic syscalls. Patch is against 2.4.7-pre1 + ftp.math.psu.edu/pub/viro/[01]-*C7-pre1 (already sent to Linus - one of them adds a library of helper functions for simple filesystems, another plugs a leak in knfsd). It works here(tm). Enjoy. diff -urN C7-pre1-nfsd-fix/fs/Makefile C7-pre1-nfsd-fs/fs/Makefile --- C7-pre1-nfsd-fix/fs/Makefile Tue Mar 12 22:44:24 2002 +++ C7-pre1-nfsd-fs/fs/Makefile Wed Mar 13 02:16:27 2002 @@ -22,6 +22,12 @@ obj-y += noquot.o endif +ifneq ($(CONFIG_NFSD),n) +ifneq ($(CONFIG_NFSD),) +obj-y += nfsctl.o +endif +endif + subdir-$(CONFIG_PROC_FS) += proc subdir-y += partitions subdir-y += driverfs diff -urN C7-pre1-nfsd-fix/fs/dcache.c C7-pre1-nfsd-fs/fs/dcache.c --- C7-pre1-nfsd-fix/fs/dcache.c Fri Mar 8 02:09:51 2002 +++ C7-pre1-nfsd-fs/fs/dcache.c Wed Mar 13 02:16:27 2002 @@ -1252,6 +1252,7 @@ /* SLAB cache for buffer_head structures */ kmem_cache_t *bh_cachep; EXPORT_SYMBOL(bh_cachep); +EXPORT_SYMBOL(d_genocide); extern void bdev_cache_init(void); extern void cdev_cache_init(void); diff -urN C7-pre1-nfsd-fix/fs/filesystems.c C7-pre1-nfsd-fs/fs/filesystems.c --- C7-pre1-nfsd-fix/fs/filesystems.c Tue Feb 19 22:33:03 2002 +++ C7-pre1-nfsd-fs/fs/filesystems.c Wed Mar 13 02:16:27 2002 @@ -3,39 +3,10 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * - * nfsservctl system-call when nfsd is not compiled in. + * table of configured filesystems */ -#include <linux/config.h> -#include <linux/module.h> -#include <linux/time.h> -#include <linux/smp_lock.h> -#include <linux/kmod.h> -#include <linux/nfsd/interface.h> -#include <linux/linkage.h> - -#if ! defined(CONFIG_NFSD) -struct nfsd_linkage *nfsd_linkage; - -long -asmlinkage sys_nfsservctl(int cmd, void *argp, void *resp) -{ - int ret = -ENOSYS; - -#if defined(CONFIG_MODULES) - lock_kernel(); - - if (nfsd_linkage || - (request_module ("nfsd") == 0 && nfsd_linkage)) { - __MOD_INC_USE_COUNT(nfsd_linkage->owner); - unlock_kernel(); - ret = nfsd_linkage->do_nfsservctl(cmd, argp, resp); - __MOD_DEC_USE_COUNT(nfsd_linkage->owner); - } else - unlock_kernel(); -#endif - return ret; -} -EXPORT_SYMBOL(nfsd_linkage); - -#endif /* CONFIG_NFSD */ +/* + * Code will move here from fs/super.c and yes, it will be fs type handling + * stuff. + */ diff -urN C7-pre1-nfsd-fix/fs/nfsctl.c C7-pre1-nfsd-fs/fs/nfsctl.c --- C7-pre1-nfsd-fix/fs/nfsctl.c Wed Dec 31 19:00:00 1969 +++ C7-pre1-nfsd-fs/fs/nfsctl.c Wed Mar 13 02:16:27 2002 @@ -0,0 +1,87 @@ +/* + * fs/nfsctl.c + * + * This should eventually move to userland. + * + */ +#include <linux/config.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/sunrpc/svc.h> +#include <linux/nfsd/nfsd.h> +#include <linux/nfsd/syscall.h> +#include <linux/linkage.h> +#include <asm/uaccess.h> + +/* + * open a file on nfsd fs + */ + +struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data); + +static struct file *do_open(char *name, int flags) +{ + struct nameidata nd; + int error; + + nd.mnt = do_kern_mount("nfsd", 0, "nfsd", NULL); + + if (IS_ERR(nd.mnt)) + return (struct file *)nd.mnt; + + nd.dentry = dget(nd.mnt->mnt_root); + nd.last_type = LAST_ROOT; + nd.flags = 0; + + error = path_walk(name, &nd); + if (error) + return ERR_PTR(error); + + return dentry_open(nd.dentry, nd.mnt, flags); +} + +static struct { + char *name; int wsize; int rsize; +} map[] = { + [NFSCTL_SVC]={"svc", sizeof(struct nfsctl_svc)}, + [NFSCTL_ADDCLIENT]={"add", sizeof(struct nfsctl_client)}, + [NFSCTL_DELCLIENT]={"del", sizeof(struct nfsctl_client)}, + [NFSCTL_EXPORT]={"export", sizeof(struct nfsctl_export)}, + [NFSCTL_UNEXPORT]={"unexport", sizeof(struct nfsctl_export)}, +#ifdef notyet + [NFSCTL_UGIDUPDATE]={"ugid", sizeof(struct nfsctl_uidmap)}, +#endif + [NFSCTL_GETFD]={"getfd", sizeof(struct nfsctl_fdparm), NFS_FHSIZE}, + [NFSCTL_GETFS]={"getfs", sizeof(struct nfsctl_fsparm), sizeof(struct knfsd_fh)}, +}; + +long +asmlinkage sys_nfsservctl(int cmd, struct nfsctl_arg *arg, void *res) +{ + struct file *file; + void *p = &arg->u; + int version; + int err; + + if (copy_from_user(&version, &arg->ca_version, sizeof(int))) + return -EFAULT; + + if (version != NFSCTL_VERSION) { + printk(KERN_WARNING "nfsd: incompatible version in syscall.\n"); + return -EINVAL; + } + + if (cmd < 0 || cmd >= sizeof(map)/sizeof(map[0]) || !map[cmd].name) + return -EINVAL; + + file = do_open(map[cmd].name, map[cmd].rsize ? O_RDWR : O_WRONLY); + if (IS_ERR(file)) + return PTR_ERR(file); + err = file->f_op->write(file, p, map[cmd].wsize, &file->f_pos); + if (err >= 0 && map[cmd].rsize) + err = file->f_op->read(file, res, map[cmd].rsize, &file->f_pos); + if (err >= 0) + err = 0; + fput(file); + return err; +} diff -urN C7-pre1-nfsd-fix/fs/nfsd/nfsctl.c C7-pre1-nfsd-fs/fs/nfsd/nfsctl.c --- C7-pre1-nfsd-fix/fs/nfsd/nfsctl.c Fri Mar 8 02:09:52 2002 +++ C7-pre1-nfsd-fs/fs/nfsd/nfsctl.c Wed Mar 13 02:16:27 2002 @@ -21,6 +21,7 @@ #include <linux/slab.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/pagemap.h> #include <linux/nfs.h> #include <linux/sunrpc/svc.h> @@ -30,20 +31,96 @@ #include <linux/nfsd/syscall.h> #include <asm/uaccess.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/init.h> - -static int nfsctl_svc(struct nfsctl_svc *data); -static int nfsctl_addclient(struct nfsctl_client *data); -static int nfsctl_delclient(struct nfsctl_client *data); -static int nfsctl_export(struct nfsctl_export *data); -static int nfsctl_unexport(struct nfsctl_export *data); -static int nfsctl_getfd(struct nfsctl_fdparm *, __u8 *); -static int nfsctl_getfs(struct nfsctl_fsparm *, struct knfsd_fh *); -#ifdef notyet -static int nfsctl_ugidupdate(struct nfsctl_ugidmap *data); -#endif + +/* + * We have a single directory with 8 nodes in it. + */ +enum { + NFSD_Root = 1, + NFSD_Svc, + NFSD_Add, + NFSD_Del, + NFSD_Export, + NFSD_Unexport, + NFSD_Getfd, + NFSD_Getfs, + NFSD_List, +}; + +/* + * write() for these nodes. + */ +static ssize_t write_svc(struct file *file, const char *buf, size_t size); +static ssize_t write_add(struct file *file, const char *buf, size_t size); +static ssize_t write_del(struct file *file, const char *buf, size_t size); +static ssize_t write_export(struct file *file, const char *buf, size_t size); +static ssize_t write_unexport(struct file *file, const char *buf, size_t size); +static ssize_t write_getfd(struct file *file, const char *buf, size_t size); +static ssize_t write_getfs(struct file *file, const char *buf, size_t size); + +static ssize_t (*write_op[])(struct file *, const 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, +}; + +static ssize_t fs_write(struct file *file, const char *buf, size_t size, loff_t *pos) +{ + ino_t ino = file->f_dentry->d_inode->i_ino; + if (ino >= sizeof(write_op)/sizeof(write_op[0]) || !write_op[ino]) + return -EINVAL; + return write_op[ino](file, buf, size); +} + +/* + * read(), open() and release() for getfs and getfd (read/write ones). + * IO on these is a simple transaction - you open() the file, write() to it + * and that generates a (stored) response. After that read() will simply + * access that response. + */ + +static ssize_t TA_read(struct file *file, char *buf, size_t size, loff_t *pos) +{ + if (!file->private_data) + return 0; + if (*pos >= file->f_dentry->d_inode->i_size) + return 0; + if (*pos + size > file->f_dentry->d_inode->i_size) + size = file->f_dentry->d_inode->i_size - *pos; + if (copy_to_user(buf, file->private_data + *pos, size)) + return -EFAULT; + *pos += size; + return size; +} + +static ssize_t TA_open(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + return 0; +} + +static ssize_t TA_release(struct inode *inode, struct file *file) +{ + void *p = file->private_data; + file->private_data = NULL; + kfree(p); + return 0; +} + +static struct file_operations writer_ops = { + write: fs_write, +}; + +static struct file_operations reader_ops = { + write: fs_write, + read: TA_read, + open: TA_open, + release:TA_release, +}; extern struct seq_operations nfs_exports_op; static int exports_open(struct inode *inode, struct file *file) @@ -57,254 +134,277 @@ release: seq_release, }; -void proc_export_init(void) -{ - struct proc_dir_entry *entry; - if (!proc_mkdir("fs/nfs", 0)) - return; - entry = create_proc_entry("fs/nfs/exports", 0, NULL); - if (entry) - entry->proc_fops = &exports_operations; -} +/* + * Description of fs contents. + */ +static struct { char *name; struct file_operations *ops; int mode; } files[] = { + [NFSD_Svc] = {"svc", &writer_ops, S_IWUSR}, + [NFSD_Add] = {"add", &writer_ops, S_IWUSR}, + [NFSD_Del] = {"del", &writer_ops, S_IWUSR}, + [NFSD_Export] = {"export", &writer_ops, S_IWUSR}, + [NFSD_Unexport] = {"unexport", &writer_ops, S_IWUSR}, + [NFSD_Getfd] = {"getfd", &reader_ops, S_IWUSR|S_IRUSR}, + [NFSD_Getfs] = {"getfs", &reader_ops, S_IWUSR|S_IRUSR}, + [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, +}; -static inline int -nfsctl_svc(struct nfsctl_svc *data) -{ - return nfsd_svc(data->svc_port, data->svc_nthreads); -} +/*----------------------------------------------------------------------------*/ +/* + * payload - write methods + */ -static inline int -nfsctl_addclient(struct nfsctl_client *data) +static ssize_t write_svc(struct file *file, const char *buf, size_t size) { - return exp_addclient(data); + struct nfsctl_svc data; + if (size < sizeof(data)) + return -EINVAL; + if (copy_from_user(&data, buf, size)) + return -EFAULT; + return nfsd_svc(data.svc_port, data.svc_nthreads); } -static inline int -nfsctl_delclient(struct nfsctl_client *data) +static ssize_t write_add(struct file *file, const char *buf, size_t size) { - return exp_delclient(data); + struct nfsctl_client data; + if (size < sizeof(data)) + return -EINVAL; + if (copy_from_user(&data, buf, size)) + return -EFAULT; + return exp_addclient(&data); } -static inline int -nfsctl_export(struct nfsctl_export *data) +static ssize_t write_del(struct file *file, const char *buf, size_t size) { - return exp_export(data); + struct nfsctl_client data; + if (size < sizeof(data)) + return -EINVAL; + if (copy_from_user(&data, buf, size)) + return -EFAULT; + return exp_delclient(&data); } -static inline int -nfsctl_unexport(struct nfsctl_export *data) +static ssize_t write_export(struct file *file, const char *buf, size_t size) { - return exp_unexport(data); + struct nfsctl_export data; + if (size < sizeof(data)) + return -EINVAL; + if (copy_from_user(&data, buf, size)) + return -EFAULT; + return exp_export(&data); } -#ifdef notyet -static inline int -nfsctl_ugidupdate(nfs_ugidmap *data) +static ssize_t write_unexport(struct file *file, const char *buf, size_t size) { - return -EINVAL; + struct nfsctl_export data; + if (size < sizeof(data)) + return -EINVAL; + if (copy_from_user(&data, buf, size)) + return -EFAULT; + return exp_unexport(&data); } -#endif -static inline int -nfsctl_getfs(struct nfsctl_fsparm *data, struct knfsd_fh *res) +static ssize_t write_getfs(struct file *file, const char *buf, size_t size) { - struct sockaddr_in *sin; - struct svc_client *clp; - int err = 0; + struct nfsctl_fsparm data; + struct sockaddr_in *sin; + struct svc_client *clp; + int err = 0; + struct knfsd_fh *res; - if (data->gd_addr.sa_family != AF_INET) + if (file->private_data) + return -EINVAL; + if (size < sizeof(data)) + return -EINVAL; + if (copy_from_user(&data, buf, size)) + return -EFAULT; + if (data.gd_addr.sa_family != AF_INET) return -EPROTONOSUPPORT; - sin = (struct sockaddr_in *)&data->gd_addr; - if (data->gd_maxlen > NFS3_FHSIZE) - data->gd_maxlen = NFS3_FHSIZE; + sin = (struct sockaddr_in *)&data.gd_addr; + if (data.gd_maxlen > NFS3_FHSIZE) + data.gd_maxlen = NFS3_FHSIZE; + res = kmalloc(sizeof(struct knfsd_fh), GFP_KERNEL); + memset(res, 0, sizeof(struct knfsd_fh)); + if (!res) + return -ENOMEM; exp_readlock(); if (!(clp = exp_getclient(sin))) err = -EPERM; else - err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen); + err = exp_rootfh(clp, data.gd_path, res, data.gd_maxlen); exp_readunlock(); + + down(&file->f_dentry->d_inode->i_sem); + if (file->private_data) + err = -EINVAL; + if (err) + kfree(res); + else { + file->f_dentry->d_inode->i_size = res->fh_size + (int)&((struct knfsd_fh*)0)->fh_base; + file->private_data = res; + err = sizeof(data); + } + up(&file->f_dentry->d_inode->i_sem); + return err; } -static inline int -nfsctl_getfd(struct nfsctl_fdparm *data, __u8 *res) +static ssize_t write_getfd(struct file *file, const char *buf, size_t size) { - struct sockaddr_in *sin; - struct svc_client *clp; - int err = 0; - struct knfsd_fh fh; + struct nfsctl_fdparm data; + struct sockaddr_in *sin; + struct svc_client *clp; + int err = 0; + struct knfsd_fh fh; + char *res; - if (data->gd_addr.sa_family != AF_INET) + if (file->private_data) + return -EINVAL; + if (size < sizeof(data)) + return -EINVAL; + if (copy_from_user(&data, buf, size)) + return -EFAULT; + if (data.gd_addr.sa_family != AF_INET) return -EPROTONOSUPPORT; - if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS) + if (data.gd_version < 2 || data.gd_version > NFSSVC_MAXVERS) return -EINVAL; - sin = (struct sockaddr_in *)&data->gd_addr; - + res = kmalloc(NFS_FHSIZE, GFP_KERNEL); + if (!res) + return -ENOMEM; + sin = (struct sockaddr_in *)&data.gd_addr; exp_readlock(); if (!(clp = exp_getclient(sin))) err = -EPERM; else - err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE); + err = exp_rootfh(clp, data.gd_path, &fh, NFS_FHSIZE); exp_readunlock(); - if (err == 0) { - if (fh.fh_size > NFS_FHSIZE) - err = -EINVAL; - else { - memset(res,0, NFS_FHSIZE); - memcpy(res, &fh.fh_base, fh.fh_size); - } + down(&file->f_dentry->d_inode->i_sem); + if (file->private_data) + err = -EINVAL; + if (!err && fh.fh_size > NFS_FHSIZE) + err = -EINVAL; + if (err) + kfree(res); + else { + memset(res,0, NFS_FHSIZE); + memcpy(res, &fh.fh_base, fh.fh_size); + file->f_dentry->d_inode->i_size = NFS_FHSIZE; + file->private_data = res; + err = sizeof(data); } + up(&file->f_dentry->d_inode->i_sem); return err; } -#ifdef CONFIG_NFSD -#define handle_sys_nfsservctl sys_nfsservctl -#endif - -static struct { - int argsize, respsize; -} sizes[] = { - /* NFSCTL_SVC */ { sizeof(struct nfsctl_svc), 0 }, - /* NFSCTL_ADDCLIENT */ { sizeof(struct nfsctl_client), 0}, - /* NFSCTL_DELCLIENT */ { sizeof(struct nfsctl_client), 0}, - /* NFSCTL_EXPORT */ { sizeof(struct nfsctl_export), 0}, - /* NFSCTL_UNEXPORT */ { sizeof(struct nfsctl_export), 0}, - /* NFSCTL_UGIDUPDATE */ { sizeof(struct nfsctl_uidmap), 0}, - /* NFSCTL_GETFH */ { sizeof(struct nfsctl_fhparm), NFS_FHSIZE}, - /* NFSCTL_GETFD */ { sizeof(struct nfsctl_fdparm), NFS_FHSIZE}, - /* NFSCTL_GETFS */ { sizeof(struct nfsctl_fsparm), sizeof(struct knfsd_fh)}, +/*----------------------------------------------------------------------------*/ +/* + * populating the filesystem. + */ + +static struct super_operations s_ops = { + statfs: simple_statfs, }; -#define CMD_MAX (sizeof(sizes)/sizeof(sizes[0])-1) -long -asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp) +static int nfsd_fill_super(struct super_block * sb, void * data, int silent) { - struct nfsctl_arg * argp = opaque_argp; - union nfsctl_res * resp = opaque_resp; - struct nfsctl_arg * arg = NULL; - union nfsctl_res * res = NULL; - int err; - int argsize, respsize; - - - err = -EPERM; - if (!capable(CAP_SYS_ADMIN)) { - goto done; - } - err = -EINVAL; - if (cmd<0 || cmd > CMD_MAX) - goto done; - err = -EFAULT; - argsize = sizes[cmd].argsize + (int)&((struct nfsctl_arg *)0)->u; - respsize = sizes[cmd].respsize; /* maximum */ - if (!access_ok(VERIFY_READ, argp, argsize) - || (resp && !access_ok(VERIFY_WRITE, resp, respsize))) { - goto done; - } - err = -ENOMEM; /* ??? */ - if (!(arg = kmalloc(sizeof(*arg), GFP_USER)) || - (resp && !(res = kmalloc(sizeof(*res), GFP_USER)))) { - goto done; - } - - err = -EINVAL; - copy_from_user(arg, argp, argsize); - if (arg->ca_version != NFSCTL_VERSION) { - printk(KERN_WARNING "nfsd: incompatible version in syscall.\n"); - goto done; + struct inode *inode; + struct dentry *root; + struct dentry *dentry; + int i; + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = 0x6e667364; + sb->s_op = &s_ops; + + inode = new_inode(sb); + if (!inode) + return -ENOMEM; + inode->i_mode = S_IFDIR | 0755; + inode->i_uid = inode->i_gid = 0; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_op = &simple_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + root = d_alloc_root(inode); + if (!root) { + iput(inode); + return -ENOMEM; } - - switch(cmd) { - case NFSCTL_SVC: - err = nfsctl_svc(&arg->ca_svc); - break; - case NFSCTL_ADDCLIENT: - err = nfsctl_addclient(&arg->ca_client); - break; - case NFSCTL_DELCLIENT: - err = nfsctl_delclient(&arg->ca_client); - break; - case NFSCTL_EXPORT: - err = nfsctl_export(&arg->ca_export); - break; - case NFSCTL_UNEXPORT: - err = nfsctl_unexport(&arg->ca_export); - break; -#ifdef notyet - case NFSCTL_UGIDUPDATE: - err = nfsctl_ugidupdate(&arg->ca_umap); - break; -#endif - case NFSCTL_GETFD: - err = nfsctl_getfd(&arg->ca_getfd, res->cr_getfh); - break; - case NFSCTL_GETFS: - err = nfsctl_getfs(&arg->ca_getfs, &res->cr_getfs); - respsize = res->cr_getfs.fh_size+ (int)&((struct knfsd_fh*)0)->fh_base; - break; - default: - err = -EINVAL; + for (i = NFSD_Svc; i <= NFSD_List; i++) { + struct qstr name; + name.name = files[i].name; + name.len = strlen(name.name); + name.hash = full_name_hash(name.name, name.len); + dentry = d_alloc(root, &name); + if (!dentry) + goto out; + inode = new_inode(sb); + if (!inode) + goto out; + inode->i_mode = S_IFREG | files[i].mode; + inode->i_uid = inode->i_gid = 0; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_fop = files[i].ops; + inode->i_ino = i; + d_add(dentry, inode); } + sb->s_root = root; + return 0; - if (!err && resp && respsize) - copy_to_user(resp, res, respsize); - -done: - if (arg) - kfree(arg); - if (res) - kfree(res); - - return err; +out: + d_genocide(root); + dput(root); + return -ENOMEM; } -EXPORT_NO_SYMBOLS; -MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); -MODULE_LICENSE("GPL"); +static struct super_block *nfsd_get_sb(struct file_system_type *fs_type, + int flags, char *dev_name, void *data) +{ + return get_sb_single(fs_type, flags, data, nfsd_fill_super); +} -#ifdef MODULE -struct nfsd_linkage nfsd_linkage_s = { - do_nfsservctl: handle_sys_nfsservctl, - owner: THIS_MODULE, +static struct file_system_type nfsd_fs_type = { + owner: THIS_MODULE, + name: "nfsd", + get_sb: nfsd_get_sb, + kill_sb: kill_litter_super, }; -#endif -/* - * Initialize the module - */ -static int __init -nfsd_init(void) +static int __init init_nfsd(void) { printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n"); -#ifdef MODULE - nfsd_linkage = &nfsd_linkage_s; -#endif nfsd_stat_init(); /* Statistics */ nfsd_cache_init(); /* RPC reply cache */ nfsd_export_init(); /* Exports table */ nfsd_lockd_init(); /* lockd->nfsd callbacks */ - proc_export_init(); + if (proc_mkdir("fs/nfs", 0)) { + struct proc_dir_entry *entry; + entry = create_proc_entry("fs/nfs/exports", 0, NULL); + if (entry) + entry->proc_fops = &exports_operations; + } + register_filesystem(&nfsd_fs_type); return 0; } -/* - * Clean up the mess before unloading the module - */ -static void __exit -nfsd_exit(void) +static void __exit exit_nfsd(void) { -#ifdef MODULE - nfsd_linkage = NULL; -#endif nfsd_export_shutdown(); nfsd_cache_shutdown(); remove_proc_entry("fs/nfs/exports", NULL); remove_proc_entry("fs/nfs", NULL); nfsd_stat_shutdown(); nfsd_lockd_shutdown(); + unregister_filesystem(&nfsd_fs_type); } -module_init(nfsd_init); -module_exit(nfsd_exit); +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); +MODULE_LICENSE("GPL"); +module_init(init_nfsd) +module_exit(exit_nfsd) diff -urN C7-pre1-nfsd-fix/include/linux/nfsd/interface.h C7-pre1-nfsd-fs/include/linux/nfsd/interface.h --- C7-pre1-nfsd-fix/include/linux/nfsd/interface.h Fri Mar 8 02:09:56 2002 +++ C7-pre1-nfsd-fs/include/linux/nfsd/interface.h Wed Mar 13 02:16:27 2002 @@ -10,17 +10,4 @@ #ifndef LINUX_NFSD_INTERFACE_H #define LINUX_NFSD_INTERFACE_H -#include <linux/config.h> - -#ifndef CONFIG_NFSD -#ifdef CONFIG_MODULES - -extern struct nfsd_linkage { - long (*do_nfsservctl)(int cmd, void *argp, void *resp); - struct module *owner; -} * nfsd_linkage; - -#endif -#endif - #endif /* LINUX_NFSD_INTERFACE_H */ diff -urN C7-pre1-nfsd-fix/include/linux/nfsd/syscall.h C7-pre1-nfsd-fs/include/linux/nfsd/syscall.h --- C7-pre1-nfsd-fix/include/linux/nfsd/syscall.h Wed Mar 6 18:13:07 2002 +++ C7-pre1-nfsd-fs/include/linux/nfsd/syscall.h Wed Mar 13 02:16:27 2002 @@ -133,7 +133,7 @@ * Kernel syscall implementation. */ #if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE) -extern asmlinkage long sys_nfsservctl(int, void *, void *); +extern asmlinkage long sys_nfsservctl(int, struct nfsctl_arg *, void *); #else #define sys_nfsservctl sys_ni_syscall #endif - To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html