Refactor filesystem types list and fix bug.
authorMichael Neumann <mneumann@ntecs.de>
Wed, 17 Dec 2008 15:44:42 +0000 (15:44 +0000)
committerMichael Neumann <mneumann@ntecs.de>
Wed, 17 Dec 2008 15:44:42 +0000 (15:44 +0000)
Refactor the management of the filesystem types list (vfsconf) by
introducing some management functions. Reduce inter-module coupling.

This actually fixes a potential "bug" in vfs_register() which does not
compare the new VFS to register with the last entry from the list, i.e.
two (or more) sequential vfs_register() calls with the same argument
would succeed.

sys/kern/vfs_init.c
sys/kern/vfs_mount.c
sys/kern/vfs_subr.c
sys/kern/vfs_syscalls.c
sys/sys/mount.h

index c85aea6..0f8e6fd 100644 (file)
@@ -92,16 +92,10 @@ static MALLOC_DEFINE(M_NAMEI, "nameibufs", "namei path buffers");
  */
 struct objcache *namei_oc;
 
-/*
- * vfs_init() will set maxvfsconf
- * to the highest defined type number.
- */
-int maxvfsconf;
-struct vfsconf *vfsconf;
-
 static TAILQ_HEAD(, vnodeopv_node) vnodeopv_list;
 static void vfs_calc_vnodeops(struct vop_ops *ops);
 
+
 /*
  * Add a vnode operations (vnops) vector to the global list.
  */
@@ -233,10 +227,90 @@ vfsinit(void *dummy)
         * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF).
         */
        vattr_null(&va_null);
-       maxvfsconf = VFS_GENERIC + 1;
 }
 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
 
+/*
+ * vfsconf related functions/data.
+ */
+
+/* highest defined filesystem type */
+static int vfsconf_maxtypenum = VFS_GENERIC + 1; 
+
+/* head of list of filesystem types */
+static STAILQ_HEAD(, vfsconf) vfsconf_list = 
+       STAILQ_HEAD_INITIALIZER(vfsconf_list);
+
+struct vfsconf *
+vfsconf_find_by_name(const char *name) 
+{
+       struct vfsconf *vfsp;
+
+       STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) {
+               if (strcmp(name, vfsp->vfc_name) == 0)
+                       break;
+       }
+       return vfsp;
+}
+
+struct vfsconf *
+vfsconf_find_by_typenum(int typenum) 
+{
+       struct vfsconf *vfsp;
+
+       STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) {
+               if (typenum == vfsp->vfc_typenum)
+                       break;
+       }
+       return vfsp;
+}
+
+static void
+vfsconf_add(struct vfsconf *vfc)
+{
+       vfc->vfc_typenum = vfsconf_maxtypenum++;
+       STAILQ_INSERT_TAIL(&vfsconf_list, vfc, vfc_next);
+}
+
+static void
+vfsconf_remove(struct vfsconf *vfc)
+{
+       int maxtypenum;
+
+       STAILQ_REMOVE(&vfsconf_list, vfc, vfsconf, vfc_next); 
+
+       maxtypenum = VFS_GENERIC;
+       STAILQ_FOREACH(vfc, &vfsconf_list, vfc_next) {
+               if (maxtypenum < vfc->vfc_typenum)
+                       maxtypenum = vfc->vfc_typenum;
+       }
+       vfsconf_maxtypenum = maxtypenum + 1;
+}
+
+int
+vfsconf_get_maxtypenum()
+{
+       return vfsconf_maxtypenum;
+}
+
+/*
+ * Iterate over all vfsconf entries. Break out of the iterator
+ * by returning != 0.
+ */
+int
+vfsconf_each(int (*iter)(struct vfsconf *element, void *data), void *data)
+{
+       int error;
+       struct vfsconf *vfsp;
+
+       STAILQ_FOREACH(vfsp, &vfsconf_list, vfc_next) {
+               error = iter(vfsp, data);
+               if (error)
+                       return (error);
+       }
+       return (0);
+}
+
 /*
  * Register a VFS.
  *
@@ -248,21 +322,12 @@ int
 vfs_register(struct vfsconf *vfc)
 {
        struct sysctl_oid *oidp;
-       struct vfsconf *vfsp;
        struct vfsops *vfsops = NULL;
 
-       vfsp = NULL;
-       if (vfsconf)
-               for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next)
-                       if (strcmp(vfc->vfc_name, vfsp->vfc_name) == 0)
-                               return EEXIST;
+       if (vfsconf_find_by_name(vfc->vfc_name) != NULL)
+               return EEXIST;
 
-       vfc->vfc_typenum = maxvfsconf++;
-       if (vfsp)
-               vfsp->vfc_next = vfc;
-       else
-               vfsconf = vfc;
-       vfc->vfc_next = NULL;
+       vfsconf_add(vfc);
 
        /*
         * If this filesystem has a sysctl node under vfs
@@ -376,35 +441,24 @@ vfs_register(struct vfsconf *vfc)
 int
 vfs_unregister(struct vfsconf *vfc)
 {
-       struct vfsconf *vfsp, *prev_vfsp;
-       int error, i, maxtypenum;
+       struct vfsconf *vfsp;
+       int error;
 
-       i = vfc->vfc_typenum;
+       vfsp = vfsconf_find_by_name(vfc->vfc_name);
 
-       prev_vfsp = NULL;
-       for (vfsp = vfsconf; vfsp;
-                       prev_vfsp = vfsp, vfsp = vfsp->vfc_next) {
-               if (!strcmp(vfc->vfc_name, vfsp->vfc_name))
-                       break;
-       }
        if (vfsp == NULL)
                return EINVAL;
-       if (vfsp->vfc_refcount)
+
+       if (vfsp->vfc_refcount != 0)
                return EBUSY;
+
        if (vfc->vfc_vfsops->vfs_uninit != NULL) {
                error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
                if (error)
                        return (error);
        }
-       if (prev_vfsp)
-               prev_vfsp->vfc_next = vfsp->vfc_next;
-       else
-               vfsconf = vfsp->vfc_next;
-       maxtypenum = VFS_GENERIC;
-       for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next)
-               if (maxtypenum < vfsp->vfc_typenum)
-                       maxtypenum = vfsp->vfc_typenum;
-       maxvfsconf = maxtypenum + 1;
+
+       vfsconf_remove(vfsp);
        return 0;
 }
 
index 8648959..2a9976c 100644 (file)
@@ -281,10 +281,8 @@ vfs_rootmountalloc(char *fstypename, char *devname, struct mount **mpp)
 
        if (fstypename == NULL)
                return (ENODEV);
-       for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
-               if (!strcmp(vfsp->vfc_name, fstypename))
-                       break;
-       }
+
+       vfsp = vfsconf_find_by_name(fstypename);
        if (vfsp == NULL)
                return (ENODEV);
        mp = kmalloc(sizeof(struct mount), M_MOUNT, M_WAITOK | M_ZERO);
index 9b055c4..902ff24 100644 (file)
@@ -1510,6 +1510,7 @@ vfs_sysctl(SYSCTL_HANDLER_ARGS)
        int *name = (int *)arg1 - 1;    /* XXX */
        u_int namelen = arg2 + 1;       /* XXX */
        struct vfsconf *vfsp;
+       int maxtypenum;
 
 #if 1 || defined(COMPAT_PRELITE2)
        /* Resolve ambiguity between VFS_VFSCONF and VFS_GENERIC. */
@@ -1522,9 +1523,7 @@ vfs_sysctl(SYSCTL_HANDLER_ARGS)
        if (namelen < 2)
                return (ENOTDIR);               /* overloaded */
        if (name[0] != VFS_GENERIC) {
-               for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
-                       if (vfsp->vfc_typenum == name[0])
-                               break;
+               vfsp = vfsconf_find_by_typenum(name[0]);
                if (vfsp == NULL)
                        return (EOPNOTSUPP);
                return ((*vfsp->vfc_vfsops->vfs_sysctl)(&name[1], namelen - 1,
@@ -1535,13 +1534,12 @@ vfs_sysctl(SYSCTL_HANDLER_ARGS)
        case VFS_MAXTYPENUM:
                if (namelen != 2)
                        return (ENOTDIR);
-               return (SYSCTL_OUT(req, &maxvfsconf, sizeof(int)));
+               maxtypenum = vfsconf_get_maxtypenum();
+               return (SYSCTL_OUT(req, &maxtypenum, sizeof(maxtypenum)));
        case VFS_CONF:
                if (namelen != 3)
                        return (ENOTDIR);       /* overloaded */
-               for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
-                       if (vfsp->vfc_typenum == name[2])
-                               break;
+               vfsp = vfsconf_find_by_typenum(name[2]);
                if (vfsp == NULL)
                        return (EOPNOTSUPP);
                return (SYSCTL_OUT(req, vfsp, sizeof *vfsp));
@@ -1555,24 +1553,29 @@ SYSCTL_NODE(_vfs, VFS_GENERIC, generic, CTLFLAG_RD, vfs_sysctl,
 #if 1 || defined(COMPAT_PRELITE2)
 
 static int
-sysctl_ovfs_conf(SYSCTL_HANDLER_ARGS)
+sysctl_ovfs_conf_iter(struct vfsconf *vfsp, void *data)
 {
        int error;
-       struct vfsconf *vfsp;
        struct ovfsconf ovfs;
+       struct sysctl_req *req = (struct sysctl_req*) data;
+
+       bzero(&ovfs, sizeof(ovfs));
+       ovfs.vfc_vfsops = vfsp->vfc_vfsops;     /* XXX used as flag */
+       strcpy(ovfs.vfc_name, vfsp->vfc_name);
+       ovfs.vfc_index = vfsp->vfc_typenum;
+       ovfs.vfc_refcount = vfsp->vfc_refcount;
+       ovfs.vfc_flags = vfsp->vfc_flags;
+       error = SYSCTL_OUT(req, &ovfs, sizeof ovfs);
+       if (error)
+               return error; /* abort iteration with error code */
+       else
+               return 0; /* continue iterating with next element */
+}
 
-       for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
-               bzero(&ovfs, sizeof(ovfs));
-               ovfs.vfc_vfsops = vfsp->vfc_vfsops;     /* XXX used as flag */
-               strcpy(ovfs.vfc_name, vfsp->vfc_name);
-               ovfs.vfc_index = vfsp->vfc_typenum;
-               ovfs.vfc_refcount = vfsp->vfc_refcount;
-               ovfs.vfc_flags = vfsp->vfc_flags;
-               error = SYSCTL_OUT(req, &ovfs, sizeof ovfs);
-               if (error)
-                       return error;
-       }
-       return 0;
+static int
+sysctl_ovfs_conf(SYSCTL_HANDLER_ARGS)
+{
+       return vfsconf_each(sysctl_ovfs_conf_iter, (void*)req);
 }
 
 #endif /* 1 || COMPAT_PRELITE2 */
index 04b5a21..b1fc4c6 100644 (file)
@@ -260,10 +260,7 @@ sys_mount(struct mount_args *uap)
                vput(vp);
                return (error);
        }
-       for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
-               if (!strcmp(vfsp->vfc_name, fstypename))
-                       break;
-       }
+       vfsp = vfsconf_find_by_name(fstypename);
        if (vfsp == NULL) {
                linker_file_t lf;
 
@@ -283,10 +280,7 @@ sys_mount(struct mount_args *uap)
                }
                lf->userrefs++;
                /* lookup again, see if the VFS was loaded */
-               for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
-                       if (!strcmp(vfsp->vfc_name, fstypename))
-                               break;
-               }
+               vfsp = vfsconf_find_by_name(fstypename);
                if (vfsp == NULL) {
                        lf->userrefs--;
                        linker_file_unload(lf);
index 90f0f13..518dd89 100644 (file)
@@ -365,7 +365,7 @@ struct vfsconf {
        int     vfc_typenum;            /* historic filesystem type number */
        int     vfc_refcount;           /* number mounted of this type */
        int     vfc_flags;              /* permanent flags */
-       struct  vfsconf *vfc_next;      /* next in list */
+       STAILQ_ENTRY(vfsconf) vfc_next; /* next in list */
 };
 
 struct ovfsconf {
@@ -392,9 +392,12 @@ struct ovfsconf {
 #ifdef MALLOC_DECLARE
 MALLOC_DECLARE(M_MOUNT);
 #endif
-extern int maxvfsconf;         /* highest defined filesystem type */
 extern int nfs_mount_type;     /* vfc_typenum for nfs, or -1 */
-extern struct vfsconf *vfsconf;        /* head of list of filesystem types */
+
+struct vfsconf *vfsconf_find_by_name(const char *);
+struct vfsconf *vfsconf_find_by_typenum(int);
+int vfsconf_get_maxtypenum(void);
+int vfsconf_each(int (*)(struct vfsconf *, void *), void *);
 
 #endif