]> git.hungrycats.org Git - linux/commitdiff
[PATCH] nfsd as filesystem
authorAlexander Viro <viro@math.psu.edu>
Fri, 15 Mar 2002 07:06:06 +0000 (23:06 -0800)
committerLinus Torvalds <torvalds@home.transmeta.com>
Fri, 15 Mar 2002 07:06:06 +0000 (23:06 -0800)
* 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.

fs/Makefile
fs/dcache.c
fs/filesystems.c
fs/nfsctl.c [new file with mode: 0644]
fs/nfsd/nfsctl.c
include/linux/nfsd/interface.h
include/linux/nfsd/syscall.h

index bf19068fe008a034525c87de87c76e842b4e4294..331ec687a6a4a7200b19c11112af9e2fec7f6607 100644 (file)
@@ -22,6 +22,12 @@ else
 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
index fab5e57765f7896a621eef020a7b4a6829f54186..f4b4056b05ff58e79366915ce28a7ec96f060175 100644 (file)
@@ -1252,6 +1252,7 @@ kmem_cache_t *dquot_cachep;
 /* 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);
index a465ff2dc0bfb78a5e834a04c5fe7af987570bd7..76eda773d051da2a528f34a97f9ba96713dffdba 100644 (file)
@@ -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 --git a/fs/nfsctl.c b/fs/nfsctl.c
new file mode 100644 (file)
index 0000000..6da2299
--- /dev/null
@@ -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;
+}
index 5a7aec7d5a1a261ceb9db4d32e84f81d6883892e..df4ffc0a978e0b3ccce48eff225ac6b303536db7 100644 (file)
@@ -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>
 #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 @@ static struct file_operations exports_operations = {
        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;
-
-       if (data->gd_addr.sa_family != AF_INET)
+       struct nfsctl_fdparm data;
+       struct sockaddr_in *sin;
+       struct svc_client *clp;
+       int err = 0;
+       struct knfsd_fh fh;
+       char *res;
+
+       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;
+       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;
        }
-       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;
+       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;
 
-       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;
-       }
-
-       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)
index 80c65165778dce279e73d0afe85f01c144083b5d..af0979704afb0a40bfe0da0d564f2b2c017d25e4 100644 (file)
 #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 */
index e98c9fa8ae21db7fd5f09c9311eeb2110b182ba8..b68a0d63f9017b3c0c2a2a35cc69a2529116a28f 100644 (file)
@@ -133,7 +133,7 @@ union nfsctl_res {
  * 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