ml_iterator_api Add an iterator over the currently mounted file systems. diff -r 7eb89c9de7ec -r 48be60e6e615 sys/kern/vfs_mount.c --- sys/kern/vfs_mount.c +++ sys/kern/vfs_mount.c @@ -94,6 +94,14 @@ #include #include +struct mountlist_entry { + TAILQ_ENTRY(mountlist_entry) me_list; /* Mount list. */ + struct mount *me_mount; /* Actual mount or + NULL for marker. */ +}; + +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 +127,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 +778,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 +938,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 +1444,126 @@ makefstype(const char *type) return rv; } +static struct mountlist_entry * +mountlist_alloc(struct mount *mp) +{ + struct mountlist_entry *me; + + me = kmem_zalloc(sizeof(*me), KM_SLEEP); + me->me_mount = mp; + + return me; +} + +static void +mountlist_free(struct mountlist_entry *me) +{ + + kmem_free(me, sizeof(*me)); +} + +int +mountlist_iterate(int (*cb)(struct mount *, void *), void *arg) +{ + int error; + struct mount *mp; + struct mountlist_entry marker, *me; + + error = 0; + marker.me_mount = NULL; + + mutex_enter(&mountlist_lock); + + TAILQ_INSERT_HEAD(&mount_list, &marker, me_list); + + while (error == 0) { + me = TAILQ_NEXT(&marker, me_list); + if (me == NULL) { + /* End of list: keep marker and break. */ + break; + } + TAILQ_REMOVE(&mount_list, &marker, me_list); + TAILQ_INSERT_AFTER(&mount_list, me, &marker, me_list); + + /* Skip other markers. */ + if (me->me_mount == NULL) + 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 call back on success. */ + if (vfs_busy(mp, NULL) == 0) { + error = cb(mp, arg); + vfs_unbusy(mp, false, NULL); + } + vfs_destroy(mp); + mutex_enter(&mountlist_lock); + } + + TAILQ_REMOVE(&mount_list, &marker, me_list); + mutex_exit(&mountlist_lock); + + return error; +} + +/* + * Attach new mount to the end of the mount list. + */ void mountlist_append(struct mount *mp) { + struct mountlist_entry *me; + + me = mountlist_alloc(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_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_mount == mp) + break; + if (me != NULL) + me = TAILQ_NEXT(me, me_list); + } + + while (me != NULL && me->me_mount == NULL) + me = TAILQ_NEXT(me, me_list); + + return (me ? me->me_mount : NULL); +} diff -r 7eb89c9de7ec -r 48be60e6e615 sys/sys/mount.h --- sys/sys/mount.h +++ sys/sys/mount.h @@ -494,7 +494,11 @@ void * mount_getspecific(struct mount *, void mount_setspecific(struct mount *, specificdata_key_t, void *); int usermount_common_policy(struct mount *, u_long); + +int mountlist_iterate(int (*)(struct mount *, void *), void *); +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;