Module Name: src Committed By: hannken Date: Tue Apr 11 07:46:38 UTC 2017
Modified Files: src/sys/kern: vfs_mount.c src/sys/sys: mount.h Log Message: Add an iterator over the currently mounted file systems. Ride 7.99.68 To generate a diff of this commit: cvs rdiff -u -r1.51 -r1.52 src/sys/kern/vfs_mount.c cvs rdiff -u -r1.221 -r1.222 src/sys/sys/mount.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/vfs_mount.c diff -u src/sys/kern/vfs_mount.c:1.51 src/sys/kern/vfs_mount.c:1.52 --- src/sys/kern/vfs_mount.c:1.51 Thu Mar 30 09:13:01 2017 +++ src/sys/kern/vfs_mount.c Tue Apr 11 07:46:37 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_mount.c,v 1.51 2017/03/30 09:13:01 hannken Exp $ */ +/* $NetBSD: vfs_mount.c,v 1.52 2017/04/11 07:46:37 hannken Exp $ */ /*- * Copyright (c) 1997-2011 The NetBSD Foundation, Inc. @@ -67,7 +67,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vfs_mount.c,v 1.51 2017/03/30 09:13:01 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_mount.c,v 1.52 2017/04/11 07:46:37 hannken Exp $"); #include <sys/param.h> #include <sys/kernel.h> @@ -94,6 +94,22 @@ __KERNEL_RCSID(0, "$NetBSD: vfs_mount.c, #include <miscfs/genfs/genfs.h> #include <miscfs/specfs/specdev.h> +enum mountlist_type { + ME_MOUNT, + ME_MARKER +}; +struct mountlist_entry { + TAILQ_ENTRY(mountlist_entry) me_list; /* Mount list. */ + struct mount *me_mount; /* Actual mount if ME_MOUNT, + current mount else. */ + enum mountlist_type me_type; /* Mount or marker. */ +}; +struct mount_iterator { + struct mountlist_entry mi_entry; +}; + +static TAILQ_HEAD(mountlist, mountlist_entry) mount_list; + static struct vnode *vfs_vnode_iterator_next1(struct vnode_iterator *, bool (*)(void *, struct vnode *), void *, bool); @@ -119,6 +135,7 @@ void vfs_mount_sysinit(void) { + TAILQ_INIT(&mount_list); TAILQ_INIT(&mountlist); mutex_init(&mountlist_lock, MUTEX_DEFAULT, IPL_NONE); mutex_init(&mntvnode_lock, MUTEX_DEFAULT, IPL_NONE); @@ -769,9 +786,7 @@ mount_domount(struct lwp *l, vnode_t **v cache_purge(vp); mp->mnt_iflag &= ~IMNT_WANTRDWR; - mutex_enter(&mountlist_lock); - TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); - mutex_exit(&mountlist_lock); + mountlist_append(mp); if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) vfs_syncer_add_to_worklist(mp); vp->v_mountedhere = mp; @@ -931,9 +946,7 @@ dounmount(struct mount *mp, int flags, s coveredvp->v_mountedhere = NULL; VOP_UNLOCK(coveredvp); } - mutex_enter(&mountlist_lock); - TAILQ_REMOVE(&mountlist, mp, mnt_list); - mutex_exit(&mountlist_lock); + mountlist_remove(mp); if (TAILQ_FIRST(&mp->mnt_vnodelist) != NULL) panic("unmount: dangling vnode"); if (used_syncer) @@ -1439,10 +1452,156 @@ makefstype(const char *type) return rv; } +static struct mountlist_entry * +mountlist_alloc(enum mountlist_type type, struct mount *mp) +{ + struct mountlist_entry *me; + + me = kmem_zalloc(sizeof(*me), KM_SLEEP); + me->me_mount = mp; + me->me_type = type; + + return me; +} + +static void +mountlist_free(struct mountlist_entry *me) +{ + + kmem_free(me, sizeof(*me)); +} + +void +mountlist_iterator_init(mount_iterator_t **mip) +{ + struct mountlist_entry *me; + + me = mountlist_alloc(ME_MARKER, NULL); + mutex_enter(&mountlist_lock); + TAILQ_INSERT_HEAD(&mount_list, me, me_list); + mutex_exit(&mountlist_lock); + *mip = (mount_iterator_t *)me; +} + +void +mountlist_iterator_destroy(mount_iterator_t *mi) +{ + struct mountlist_entry *marker = &mi->mi_entry; + + if (marker->me_mount != NULL) + vfs_unbusy(marker->me_mount, false, NULL); + + mutex_enter(&mountlist_lock); + TAILQ_REMOVE(&mount_list, marker, me_list); + mutex_exit(&mountlist_lock); + + mountlist_free(marker); + +} + +/* + * Return the next mount or NULL for this iterator. + * Mark it busy on success. + */ +struct mount * +mountlist_iterator_next(mount_iterator_t *mi) +{ + struct mountlist_entry *me, *marker = &mi->mi_entry; + struct mount *mp; + + if (marker->me_mount != NULL) { + vfs_unbusy(marker->me_mount, false, NULL); + marker->me_mount = NULL; + } + + mutex_enter(&mountlist_lock); + for (;;) { + KASSERT(marker->me_type == ME_MARKER); + + me = TAILQ_NEXT(marker, me_list); + if (me == NULL) { + /* End of list: keep marker and return. */ + mutex_exit(&mountlist_lock); + return NULL; + } + TAILQ_REMOVE(&mount_list, marker, me_list); + TAILQ_INSERT_AFTER(&mount_list, me, marker, me_list); + + /* Skip other markers. */ + if (me->me_type != ME_MOUNT) + continue; + + /* Take an initial reference for vfs_busy() below. */ + mp = me->me_mount; + KASSERT(mp != NULL); + atomic_inc_uint(&mp->mnt_refcnt); + mutex_exit(&mountlist_lock); + + /* Try to mark this mount busy and return on success. */ + if (vfs_busy(mp, NULL) == 0) { + vfs_destroy(mp); + marker->me_mount = mp; + return mp; + } + vfs_destroy(mp); + mutex_enter(&mountlist_lock); + } +} + +/* + * Attach new mount to the end of the mount list. + */ void mountlist_append(struct mount *mp) { + struct mountlist_entry *me; + + me = mountlist_alloc(ME_MOUNT, mp); mutex_enter(&mountlist_lock); + TAILQ_INSERT_TAIL(&mount_list, me, me_list); TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); mutex_exit(&mountlist_lock); } + +/* + * Remove mount from mount list. + */void +mountlist_remove(struct mount *mp) +{ + struct mountlist_entry *me; + + mutex_enter(&mountlist_lock); + TAILQ_FOREACH(me, &mount_list, me_list) + if (me->me_type == ME_MOUNT && me->me_mount == mp) + break; + KASSERT(me != NULL); + TAILQ_REMOVE(&mount_list, me, me_list); + TAILQ_REMOVE(&mountlist, mp, mnt_list); + mutex_exit(&mountlist_lock); + mountlist_free(me); +} + +/* + * Unlocked variant to traverse the mountlist. + * To be used from DDB only. + */ +struct mount * +_mountlist_next(struct mount *mp) +{ + struct mountlist_entry *me; + + if (mp == NULL) { + me = TAILQ_FIRST(&mount_list); + } else { + TAILQ_FOREACH(me, &mount_list, me_list) + if (me->me_type == ME_MOUNT && me->me_mount == mp) + break; + if (me != NULL) + me = TAILQ_NEXT(me, me_list); + } + + while (me != NULL && me->me_type != ME_MOUNT) + me = TAILQ_NEXT(me, me_list); + + return (me ? me->me_mount : NULL); +} Index: src/sys/sys/mount.h diff -u src/sys/sys/mount.h:1.221 src/sys/sys/mount.h:1.222 --- src/sys/sys/mount.h:1.221 Mon Mar 6 10:10:07 2017 +++ src/sys/sys/mount.h Tue Apr 11 07:46:37 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: mount.h,v 1.221 2017/03/06 10:10:07 hannken Exp $ */ +/* $NetBSD: mount.h,v 1.222 2017/04/11 07:46:37 hannken Exp $ */ /* * Copyright (c) 1989, 1991, 1993 @@ -494,7 +494,14 @@ void * mount_getspecific(struct mount *, void mount_setspecific(struct mount *, specificdata_key_t, void *); int usermount_common_policy(struct mount *, u_long); + +typedef struct mount_iterator mount_iterator_t; /* Opaque. */ +void mountlist_iterator_init(mount_iterator_t **); +void mountlist_iterator_destroy(mount_iterator_t *); +struct mount *mountlist_iterator_next(mount_iterator_t *); +struct mount *_mountlist_next(struct mount *); void mountlist_append(struct mount *); +void mountlist_remove(struct mount *); LIST_HEAD(vfs_list_head, vfsops); extern struct vfs_list_head vfs_list;