From: Michael Neumann Date: Wed, 17 Dec 2008 15:44:42 +0000 (+0000) Subject: Refactor filesystem types list and fix bug. X-Git-Url: https://gitweb.dragonflybsd.org/~lentferj/dragonfly.git/commitdiff_plain/2613053d50ad6f22186e88eca8b2944adb48ae69 Refactor filesystem types list and fix bug. 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. --- diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c index c85aea63b4..0f8e6fd901 100644 --- a/sys/kern/vfs_init.c +++ b/sys/kern/vfs_init.c @@ -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; } diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 86489591c1..2a9976c6d5 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -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); diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 9b055c45e1..902ff24ae2 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -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 */ diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 04b5a210dd..b1fc4c610b 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -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); diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 90f0f13966..518dd895a0 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -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