ml_iterator_apply Switch from direct mountlist traversal to mountlist iterator. diff -r 48be60e6e615 -r 6c8b24cc81b0 sys/compat/ndis/subr_ndis.c --- sys/compat/ndis/subr_ndis.c +++ sys/compat/ndis/subr_ndis.c @@ -3028,6 +3028,13 @@ ndis_find_sym(linker_file_t lf, char *fi return(0); } +static int +NdisOpenFile_cb(struct mount *mp, void *arg) +{ + + return EEXIST; +} + /* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */ __stdcall static void NdisOpenFile(ndis_status *status, ndis_handle *filehandle, uint32_t *filelength, ndis_unicode_string *filename, ndis_physaddr highestaddr) @@ -3094,7 +3101,7 @@ NdisOpenFile(ndis_status *status, ndis_h return; } - if (TAILQ_EMPTY(&mountlist)) { + if (mountlist_iterate(NdisOpenFile_cb, NULL) != EEXIST) { ExFreePool(fh); *status = NDIS_STATUS_FILE_NOT_FOUND; printf("NDIS: could not find file %s in linker list\n", diff -r 48be60e6e615 -r 6c8b24cc81b0 sys/kern/kern_veriexec.c --- sys/kern/kern_veriexec.c +++ sys/kern/kern_veriexec.c @@ -1360,48 +1360,52 @@ veriexec_file_dump(struct veriexec_file_ prop_array_add(entries, entry); } +static int +veriexec_dump_cb(struct mount *mp, void *arg) +{ + prop_array_t rarray = arg; + + fileassoc_table_run(mp, veriexec_hook, + (fileassoc_cb_t)veriexec_file_dump, rarray); + + return 0; +} + int veriexec_dump(struct lwp *l, prop_array_t rarray) { - struct mount *mp, *nmp; - mutex_enter(&mountlist_lock); - for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { - /* If it fails, the file-system is [being] unmounted. */ - if (vfs_busy(mp, &nmp) != 0) - continue; - - fileassoc_table_run(mp, veriexec_hook, - (fileassoc_cb_t)veriexec_file_dump, rarray); - - vfs_unbusy(mp, false, &nmp); - } - mutex_exit(&mountlist_lock); + mountlist_iterate(veriexec_dump_cb, rarray); return (0); } +struct veriexec_flush_arg { + int error; + struct lwp *l; +}; + +static int +veriexec_flush_cb(struct mount *mp, void *arg) +{ + struct veriexec_flush_arg *ctx = arg; + int error; + + error = veriexec_table_delete(ctx->l, mp); + if (error && error != ENOENT) + ctx->error = error; + + return 0; +} + int veriexec_flush(struct lwp *l) { - struct mount *mp, *nmp; - int error = 0; + struct veriexec_flush_arg ctx; - mutex_enter(&mountlist_lock); - for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { - int lerror; + ctx.error = 0; + ctx.l = l; + mountlist_iterate(veriexec_flush_cb, &ctx); - /* If it fails, the file-system is [being] unmounted. */ - if (vfs_busy(mp, &nmp) != 0) - continue; - - lerror = veriexec_table_delete(l, mp); - if (lerror && lerror != ENOENT) - error = lerror; - - vfs_unbusy(mp, false, &nmp); - } - mutex_exit(&mountlist_lock); - - return (error); + return ctx.error; } diff -r 48be60e6e615 -r 6c8b24cc81b0 sys/kern/vfs_mount.c --- sys/kern/vfs_mount.c +++ sys/kern/vfs_mount.c @@ -226,11 +226,9 @@ vfs_getnewfsid(struct mount *mp) ++xxxfs_mntid; tfsid.__fsid_val[0] = makedev(mtype & 0xff, xxxfs_mntid); tfsid.__fsid_val[1] = mtype; - if (!TAILQ_EMPTY(&mountlist)) { - while (vfs_getvfs(&tfsid)) { - tfsid.__fsid_val[0]++; - xxxfs_mntid++; - } + while (vfs_getvfs(&tfsid)) { + tfsid.__fsid_val[0]++; + xxxfs_mntid++; } mp->mnt_stat.f_fsidx.__fsid_val[0] = tfsid.__fsid_val[0]; mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; @@ -242,21 +240,34 @@ vfs_getnewfsid(struct mount *mp) * * XXX Needs to add a reference to the mount point. */ +struct vfs_getvfs_arg { + fsid_t *fsid; + struct mount *mp; +}; + +static int +vfs_getvfs_cb(struct mount *mp, void *arg) +{ + struct vfs_getvfs_arg *ctx = arg; + + if (mp->mnt_stat.f_fsidx.__fsid_val[0] == ctx->fsid->__fsid_val[0] && + mp->mnt_stat.f_fsidx.__fsid_val[1] == ctx->fsid->__fsid_val[1] && + ctx->mp == NULL) + ctx->mp = mp; + + return 0; +} + struct mount * vfs_getvfs(fsid_t *fsid) { - struct mount *mp; + struct vfs_getvfs_arg ctx; - mutex_enter(&mountlist_lock); - TAILQ_FOREACH(mp, &mountlist, mnt_list) { - if (mp->mnt_stat.f_fsidx.__fsid_val[0] == fsid->__fsid_val[0] && - mp->mnt_stat.f_fsidx.__fsid_val[1] == fsid->__fsid_val[1]) { - mutex_exit(&mountlist_lock); - return (mp); - } - } - mutex_exit(&mountlist_lock); - return NULL; + ctx.fsid = fsid; + ctx.mp = NULL; + mountlist_iterate(vfs_getvfs_cb, &ctx); + + return ctx.mp; } /* @@ -821,10 +832,17 @@ err_unmounted: * * => Caller hold reference to the mount, explicitly for dounmount(). */ +static int +dounmount_cb(struct mount *mp, void *arg) +{ + struct mount *cmp = arg; + + return (mp->mnt_lower == cmp ? EBUSY : 0); +} + int dounmount(struct mount *mp, int flags, struct lwp *l) { - struct mount *cmp; vnode_t *coveredvp; int error, async, used_syncer, used_extattr; @@ -837,14 +855,9 @@ dounmount(struct mount *mp, int flags, s /* * No unmount below layered mounts. */ - mutex_enter(&mountlist_lock); - TAILQ_FOREACH(cmp, &mountlist, mnt_list) { - if (cmp->mnt_lower == mp) { - mutex_exit(&mountlist_lock); - return EBUSY; - } - } - mutex_exit(&mountlist_lock); + error = mountlist_iterate(dounmount_cb, mp); + if (error) + return error; /* * XXX Freeze syncer. Must do this before locking the @@ -975,38 +988,55 @@ vfs_unmount_print(struct mount *mp, cons mp->mnt_stat.f_fstypename); } +struct vfs_unmount_arg { + uint64_t gen; + struct mount *mp; +}; + +static int +vfs_unmount_cb(struct mount *mp, void *arg) +{ + struct vfs_unmount_arg *ctx = arg; + + if ((ctx->mp == NULL || mp->mnt_gen > ctx->mp->mnt_gen) + && mp->mnt_gen < ctx->gen) { + if (ctx->mp) + vfs_destroy(ctx->mp); + ctx->mp = mp; + atomic_inc_uint(&ctx->mp->mnt_refcnt); + } + + return 0; +} + bool vfs_unmount_forceone(struct lwp *l) { - struct mount *mp, *nmp; + struct vfs_unmount_arg ctx; int error; - nmp = NULL; + ctx.gen = mountgen; + ctx.mp = NULL; - TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) { - if (nmp == NULL || mp->mnt_gen > nmp->mnt_gen) { - nmp = mp; - } - } - if (nmp == NULL) { + mountlist_iterate(vfs_unmount_cb, &ctx); + if (ctx.mp == NULL) { return false; } #ifdef DEBUG printf("forcefully unmounting %s (%s)...\n", - nmp->mnt_stat.f_mntonname, nmp->mnt_stat.f_mntfromname); + ctx.mp->mnt_stat.f_mntonname, ctx.mp->mnt_stat.f_mntfromname); #endif - atomic_inc_uint(&nmp->mnt_refcnt); - if ((error = dounmount(nmp, MNT_FORCE, l)) == 0) { - vfs_unmount_print(nmp, "forcefully "); + if ((error = dounmount(ctx.mp, MNT_FORCE, l)) == 0) { + vfs_unmount_print(ctx.mp, "forcefully "); return true; } else { - vfs_destroy(nmp); + vfs_destroy(ctx.mp); } #ifdef DEBUG printf("forceful unmount of %s failed with error %d\n", - nmp->mnt_stat.f_mntonname, error); + ctx.mp->mnt_stat.f_mntonname, error); #endif return false; @@ -1015,25 +1045,33 @@ vfs_unmount_forceone(struct lwp *l) bool vfs_unmountall1(struct lwp *l, bool force, bool verbose) { - struct mount *mp, *nmp; + struct vfs_unmount_arg ctx; bool any_error = false, progress = false; int error; - TAILQ_FOREACH_REVERSE_SAFE(mp, &mountlist, mntlist, mnt_list, nmp) { + ctx.gen = mountgen; + + for (;;) { + ctx.mp = NULL; + mountlist_iterate(vfs_unmount_cb, &ctx); + if (ctx.mp == NULL) + break; + ctx.gen = ctx.mp->mnt_gen; + #ifdef DEBUG printf("unmounting %p %s (%s)...\n", - (void *)mp, mp->mnt_stat.f_mntonname, - mp->mnt_stat.f_mntfromname); + (void *)ctx.mp, ctx.mp->mnt_stat.f_mntonname, + ctx.mp->mnt_stat.f_mntfromname); #endif - atomic_inc_uint(&mp->mnt_refcnt); - if ((error = dounmount(mp, force ? MNT_FORCE : 0, l)) == 0) { - vfs_unmount_print(mp, ""); + error = dounmount(ctx.mp, force ? MNT_FORCE : 0, l); + if (error == 0) { + vfs_unmount_print(ctx.mp, ""); progress = true; } else { - vfs_destroy(mp); + vfs_destroy(ctx.mp); if (verbose) { printf("unmount of %s failed with error %d\n", - mp->mnt_stat.f_mntonname, error); + ctx.mp->mnt_stat.f_mntonname, error); } any_error = true; } @@ -1127,6 +1165,16 @@ vfs_print_fstypes(void) * file system to use, try all possible file systems until one * succeeds. */ +static int +vfs_mountroot_cb(struct mount *mp, void *arg) +{ + struct mount **mpp = arg; + + *mpp = mp; + + return EEXIST; +} + int vfs_mountroot(void) { @@ -1224,7 +1272,10 @@ done: struct mount *mp; extern struct cwdinfo cwdi0; - mp = TAILQ_FIRST(&mountlist); + mp = NULL; + mountlist_iterate(vfs_mountroot_cb, &mp); + KASSERT(mp != NULL); + mp->mnt_flag |= MNT_ROOTFS; mp->mnt_op->vfs_refcount++; error = fstrans_mount(mp); diff -r 48be60e6e615 -r 6c8b24cc81b0 sys/kern/vfs_subr.c --- sys/kern/vfs_subr.c +++ sys/kern/vfs_subr.c @@ -756,12 +756,26 @@ lazy_sync_vnode(struct vnode *vp) /* * System filesystem synchronizer daemon. */ +static int +sched_sync_cb(struct mount *mp, void *arg) +{ + + if ((mp->mnt_iflag & IMNT_ONWORKLIST) == 0 || + mp->mnt_synclist_slot != syncer_delayno) + return 0; + mp->mnt_synclist_slot = sync_delay_slot(sync_delay(mp)); + if (fstrans_start_nowait(mp, FSTRANS_SHARED) == 0) { + VFS_SYNC(mp, MNT_LAZY, curlwp->l_cred); + fstrans_done(mp); + } + return 0; +} + void sched_sync(void *arg) { synclist_t *slp; struct vnode *vp; - struct mount *mp, *nmp; time_t starttime; bool synced; @@ -773,23 +787,7 @@ sched_sync(void *arg) /* * Sync mounts whose dirty time has expired. */ - mutex_enter(&mountlist_lock); - for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { - if ((mp->mnt_iflag & IMNT_ONWORKLIST) == 0 || - mp->mnt_synclist_slot != syncer_delayno) { - nmp = TAILQ_NEXT(mp, mnt_list); - continue; - } - mp->mnt_synclist_slot = sync_delay_slot(sync_delay(mp)); - if (vfs_busy(mp, &nmp)) - continue; - if (fstrans_start_nowait(mp, FSTRANS_SHARED) == 0) { - VFS_SYNC(mp, MNT_LAZY, curlwp->l_cred); - fstrans_done(mp); - } - vfs_unbusy(mp, false, &nmp); - } - mutex_exit(&mountlist_lock); + mountlist_iterate(sched_sync_cb, NULL); mutex_enter(&syncer_data_lock); @@ -962,16 +960,50 @@ int kinfo_vgetfailed; * Dump vnode list (via sysctl). * Copyout address of vnode followed by vnode. */ +#define VPTRSZ sizeof(vnode_t *) +#define VNODESZ sizeof(vnode_t) + +struct sysctl_kern_vnode_arg { + char *bp; + char *ewhere; +}; + +static int +sysctl_kern_vnode_cb(struct mount *mp, void *arg) +{ + int error; + vnode_t *vp, vbuf; + struct vnode_iterator *marker; + struct sysctl_kern_vnode_arg *ctx = arg; + + vfs_vnode_iterator_init(mp, &marker); + while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) { + if (ctx->bp + VPTRSZ + VNODESZ > ctx->ewhere) { + vrele(vp); + vfs_vnode_iterator_destroy(marker); + return ENOMEM; + } + memcpy(&vbuf, vp, VNODESZ); + if ((error = copyout(&vp, ctx->bp, VPTRSZ)) || + (error = copyout(&vbuf, ctx->bp + VPTRSZ, VNODESZ))) { + vrele(vp); + vfs_vnode_iterator_destroy(marker); + return error; + } + vrele(vp); + ctx->bp += VPTRSZ + VNODESZ; + } + vfs_vnode_iterator_destroy(marker); + + return 0; +} + int sysctl_kern_vnode(SYSCTLFN_ARGS) { char *where = oldp; size_t *sizep = oldlenp; - struct mount *mp, *nmp; - vnode_t *vp, vbuf; - struct vnode_iterator *marker; - char *bp = where; - char *ewhere; + struct sysctl_kern_vnode_arg ctx; int error; if (namelen != 0) @@ -979,51 +1011,22 @@ sysctl_kern_vnode(SYSCTLFN_ARGS) if (newp != NULL) return (EPERM); -#define VPTRSZ sizeof(vnode_t *) -#define VNODESZ sizeof(vnode_t) if (where == NULL) { *sizep = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); return (0); } - ewhere = where + *sizep; + ctx.bp = where; + ctx.ewhere = where + *sizep; sysctl_unlock(); - mutex_enter(&mountlist_lock); - for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { - if (vfs_busy(mp, &nmp)) { - continue; - } - vfs_vnode_iterator_init(mp, &marker); - while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) { - if (bp + VPTRSZ + VNODESZ > ewhere) { - vrele(vp); - vfs_vnode_iterator_destroy(marker); - vfs_unbusy(mp, false, NULL); - sysctl_relock(); - *sizep = bp - where; - return (ENOMEM); - } - memcpy(&vbuf, vp, VNODESZ); - if ((error = copyout(&vp, bp, VPTRSZ)) || - (error = copyout(&vbuf, bp + VPTRSZ, VNODESZ))) { - vrele(vp); - vfs_vnode_iterator_destroy(marker); - vfs_unbusy(mp, false, NULL); - sysctl_relock(); - return (error); - } - vrele(vp); - bp += VPTRSZ + VNODESZ; - } - vfs_vnode_iterator_destroy(marker); - vfs_unbusy(mp, false, &nmp); - } - mutex_exit(&mountlist_lock); + error = mountlist_iterate(sysctl_kern_vnode_cb, &ctx); sysctl_relock(); - *sizep = bp - where; - return (0); + *sizep = ctx.bp - where; + return error; } +#undef VPTRSZ +#undef VNODESZ /* * Set vnode attributes to VNOVAL @@ -1549,7 +1552,7 @@ vfs_vnode_lock_print(void *vlock, int fu struct mount *mp; vnode_impl_t *vip; - TAILQ_FOREACH(mp, &mountlist, mnt_list) { + for (mp = _mountlist_next(NULL); mp; mp = _mountlist_next(mp)) { TAILQ_FOREACH(vip, &mp->mnt_vnodelist, vi_mntvnodes) { if (&vip->vi_lock != vlock) continue; @@ -1656,25 +1659,18 @@ void printlockedvnodes(void); void printlockedvnodes(void) { - struct mount *mp, *nmp; + struct mount *mp; vnode_t *vp; vnode_impl_t *vip; printf("Locked vnodes\n"); - mutex_enter(&mountlist_lock); - for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { - if (vfs_busy(mp, &nmp)) { - continue; - } + for (mp = _mountlist_next(NULL); mp; mp = _mountlist_next(mp)) { TAILQ_FOREACH(vip, &mp->mnt_vnodelist, vi_mntvnodes) { vp = VIMPL_TO_VNODE(vip); if (VOP_ISLOCKED(vp)) vprint(NULL, vp); } - mutex_enter(&mountlist_lock); - vfs_unbusy(mp, false, &nmp); } - mutex_exit(&mountlist_lock); } #endif /* DDB || DEBUGPRINT */ diff -r 48be60e6e615 -r 6c8b24cc81b0 sys/kern/vfs_syscalls.c --- sys/kern/vfs_syscalls.c +++ sys/kern/vfs_syscalls.c @@ -638,31 +638,32 @@ int syncprt = 0; struct ctldebug debug0 = { "syncprt", &syncprt }; #endif +static int +do_sys_sync_cb(struct mount *mp, void *arg) +{ + struct lwp *l = arg; + int asyncflag; + + fstrans_start(mp, FSTRANS_SHARED); + mutex_enter(&mp->mnt_updating); + if ((mp->mnt_flag & MNT_RDONLY) == 0) { + asyncflag = mp->mnt_flag & MNT_ASYNC; + mp->mnt_flag &= ~MNT_ASYNC; + VFS_SYNC(mp, MNT_NOWAIT, l->l_cred); + if (asyncflag) + mp->mnt_flag |= MNT_ASYNC; + } + mutex_exit(&mp->mnt_updating); + fstrans_done(mp); + + return 0; +} + void do_sys_sync(struct lwp *l) { - struct mount *mp, *nmp; - int asyncflag; - - mutex_enter(&mountlist_lock); - for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { - if (vfs_busy(mp, &nmp)) { - continue; - } - fstrans_start(mp, FSTRANS_SHARED); - mutex_enter(&mp->mnt_updating); - if ((mp->mnt_flag & MNT_RDONLY) == 0) { - asyncflag = mp->mnt_flag & MNT_ASYNC; - mp->mnt_flag &= ~MNT_ASYNC; - VFS_SYNC(mp, MNT_NOWAIT, l->l_cred); - if (asyncflag) - mp->mnt_flag |= MNT_ASYNC; - } - mutex_exit(&mp->mnt_updating); - fstrans_done(mp); - vfs_unbusy(mp, false, &nmp); - } - mutex_exit(&mountlist_lock); + + mountlist_iterate(do_sys_sync_cb, l); #ifdef DEBUG if (syncprt) vfs_bufstats(); @@ -1245,67 +1246,84 @@ sys_fstatvfs1(struct lwp *l, const struc /* * Get statistics on all filesystems. */ +struct do_sys_getvfsstat_arg { + struct lwp *l; + void *sfsp; + int (*copyfn)(const void *, void *, size_t); + size_t entry_sz; + int flags; + int root; + struct statvfs *sb; + size_t count; + size_t maxcount; +}; + +static int +do_sys_getvfsstat_cb(struct mount *mp, void *arg) +{ + struct do_sys_getvfsstat_arg *ctx = arg; + int error; + + if (ctx->sfsp && ctx->count < ctx->maxcount) { + error = dostatvfs(mp, ctx->sb, ctx->l, ctx->flags, 0); + if (error) { + return 0; + } + error = ctx->copyfn(ctx->sb, ctx->sfsp, ctx->entry_sz); + if (error) { + return error; + } + ctx->sfsp = (char *)ctx->sfsp + ctx->entry_sz; + ctx->root |= strcmp(ctx->sb->f_mntonname, "/") == 0; + } + ctx->count++; + + return 0; +} + int do_sys_getvfsstat(struct lwp *l, void *sfsp, size_t bufsize, int flags, int (*copyfn)(const void *, void *, size_t), size_t entry_sz, register_t *retval) { - int root = 0; - struct proc *p = l->l_proc; - struct mount *mp, *nmp; - struct statvfs *sb; - size_t count, maxcount; - int error = 0; - - sb = STATVFSBUF_GET(); - maxcount = bufsize / entry_sz; - mutex_enter(&mountlist_lock); - count = 0; - for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { - if (vfs_busy(mp, &nmp)) { - continue; - } - if (sfsp && count < maxcount) { - error = dostatvfs(mp, sb, l, flags, 0); - if (error) { - vfs_unbusy(mp, false, &nmp); - error = 0; - continue; - } - error = copyfn(sb, sfsp, entry_sz); - if (error) { - vfs_unbusy(mp, false, NULL); - goto out; - } - sfsp = (char *)sfsp + entry_sz; - root |= strcmp(sb->f_mntonname, "/") == 0; - } - count++; - vfs_unbusy(mp, false, &nmp); - } - mutex_exit(&mountlist_lock); - - if (root == 0 && p->p_cwdi->cwdi_rdir) { + struct do_sys_getvfsstat_arg ctx; + int error; + + ctx.l = l; + ctx.sfsp = sfsp; + ctx.copyfn = copyfn; + ctx.entry_sz = entry_sz; + ctx.flags = flags; + ctx.root = 0; + ctx.sb = STATVFSBUF_GET(); + ctx.count = 0; + ctx.maxcount = bufsize / entry_sz; + + error = mountlist_iterate(do_sys_getvfsstat_cb, &ctx); + if (error) + goto out; + + if (ctx.root == 0 && l->l_proc->p_cwdi->cwdi_rdir) { /* * fake a root entry */ - error = dostatvfs(p->p_cwdi->cwdi_rdir->v_mount, - sb, l, flags, 1); + error = dostatvfs(l->l_proc->p_cwdi->cwdi_rdir->v_mount, + ctx.sb, l, flags, 1); if (error != 0) goto out; if (sfsp) { - error = copyfn(sb, sfsp, entry_sz); + error = copyfn(ctx.sb, sfsp, entry_sz); if (error != 0) goto out; } - count++; + ctx.count++; } - if (sfsp && count > maxcount) - *retval = maxcount; + if (sfsp && ctx.count > ctx.maxcount) + *retval = ctx.maxcount; else - *retval = count; + *retval = ctx.count; out: - STATVFSBUF_PUT(sb); + STATVFSBUF_PUT(ctx.sb); return error; } diff -r 48be60e6e615 -r 6c8b24cc81b0 sys/kern/vfs_trans.c --- sys/kern/vfs_trans.c +++ sys/kern/vfs_trans.c @@ -871,7 +871,7 @@ fstrans_dump(int full) fstrans_print_lwp(p, l, full == 1); printf("Fstrans state by mount:\n"); - TAILQ_FOREACH(mp, &mountlist, mnt_list) + for (mp = _mountlist_next(NULL); mp; mp = _mountlist_next(mp)) fstrans_print_mount(mp, full == 1); } #endif /* defined(DDB) */ diff -r 48be60e6e615 -r 6c8b24cc81b0 sys/ufs/lfs/lfs_bio.c --- sys/ufs/lfs/lfs_bio.c +++ sys/ufs/lfs/lfs_bio.c @@ -510,12 +510,27 @@ lfs_flush_fs(struct lfs *fs, int flags) * Called and return with lfs_lock held. * If fs != NULL, we hold the segment lock for fs. */ +static int +lfs_flush_cb(struct mount *mp, void *arg) +{ + int *flags = arg; + struct lfs *tfs; + + if (strncmp(&mp->mnt_stat.f_fstypename[0], MOUNT_LFS, + sizeof(mp->mnt_stat.f_fstypename)) == 0) { + tfs = VFSTOULFS(mp)->um_lfs; + mutex_enter(&lfs_lock); + lfs_flush_fs(tfs, *flags); + mutex_exit(&lfs_lock); + } + + return 0; +} + void lfs_flush(struct lfs *fs, int flags, int only_onefs) { extern u_int64_t locked_fakequeue_count; - struct mount *mp, *nmp; - struct lfs *tfs; KASSERT(mutex_owned(&lfs_lock)); KDASSERT(fs == NULL || !LFS_SEGLOCK_HELD(fs)); @@ -543,22 +558,7 @@ lfs_flush(struct lfs *fs, int flags, int vfs_unbusy(fs->lfs_ivnode->v_mount, false, NULL); } else { locked_fakequeue_count = 0; - mutex_enter(&mountlist_lock); - for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { - if (vfs_busy(mp, &nmp)) { - DLOG((DLOG_FLUSH, "lfs_flush: fs vfs_busy\n")); - continue; - } - if (strncmp(&mp->mnt_stat.f_fstypename[0], MOUNT_LFS, - sizeof(mp->mnt_stat.f_fstypename)) == 0) { - tfs = VFSTOULFS(mp)->um_lfs; - mutex_enter(&lfs_lock); - lfs_flush_fs(tfs, flags); - mutex_exit(&lfs_lock); - } - vfs_unbusy(mp, false, &nmp); - } - mutex_exit(&mountlist_lock); + mountlist_iterate(lfs_flush_cb, &flags); } LFS_DEBUG_COUNTLOCKED("flush"); wakeup(&lfs_subsys_pages); diff -r 48be60e6e615 -r 6c8b24cc81b0 sys/ufs/lfs/lfs_vfsops.c --- sys/ufs/lfs/lfs_vfsops.c +++ sys/ufs/lfs/lfs_vfsops.c @@ -384,16 +384,75 @@ struct pool lfs_lbnentry_pool; * in lfs_subsys_pages; the daemon flushes the filesystem when this value * crosses the (user-defined) threshhold LFS_MAX_PAGES. */ +struct lfs_writerd_arg { + int lfsc; + int wrote_something; +}; + +static int +lfs_writerd_cb(struct mount *mp, void *arg) +{ + struct lfs_writerd_arg *ctx = arg; + struct lfs *fs; + int fsflags; + daddr_t ooffset; + + KASSERT(!mutex_owned(&lfs_lock)); + if (strncmp(mp->mnt_stat.f_fstypename, MOUNT_LFS, + sizeof(mp->mnt_stat.f_fstypename)) != 0) + return 0; + + ++ctx->lfsc; + fs = VFSTOULFS(mp)->um_lfs; + ooffset = 0; + fsflags = SEGM_SINGLE; + + mutex_enter(&lfs_lock); + ooffset = lfs_sb_getoffset(fs); + + if (lfs_sb_getnextseg(fs) < lfs_sb_getcurseg(fs) && fs->lfs_nowrap) { + /* Don't try to write if we're suspended */ + mutex_exit(&lfs_lock); + return 0; + } + if (LFS_STARVED_FOR_SEGS(fs)) { + mutex_exit(&lfs_lock); + + DLOG((DLOG_FLUSH, + "lfs_writerd: need cleaning before writing possible\n")); + lfs_wakeup_cleaner(fs); + return 0; + } + + if ((fs->lfs_dirvcount > LFS_MAX_FSDIROP(fs) || + lfs_dirvcount > LFS_MAX_DIROP) && fs->lfs_dirops == 0) { + fsflags &= ~SEGM_SINGLE; + fsflags |= SEGM_CKP; + DLOG((DLOG_FLUSH, "lfs_writerd: checkpoint\n")); + lfs_flush_fs(fs, fsflags); + } else if (fs->lfs_pdflush) { + DLOG((DLOG_FLUSH, "lfs_writerd: pdflush set\n")); + lfs_flush_fs(fs, fsflags); + } else if (!TAILQ_EMPTY(&fs->lfs_pchainhd)) { + DLOG((DLOG_FLUSH, "lfs_writerd: pchain non-empty\n")); + mutex_exit(&lfs_lock); + lfs_writer_enter(fs, "wrdirop"); + lfs_flush_pchain(fs); + lfs_writer_leave(fs); + mutex_enter(&lfs_lock); + } + if (lfs_sb_getoffset(fs) != ooffset) + ++ctx->wrote_something; + mutex_exit(&lfs_lock); + + return 0; +} + static void lfs_writerd(void *arg) { - struct mount *mp, *nmp; - struct lfs *fs; + struct lfs_writerd_arg ctx; struct vfsops *vfs = NULL; - int fsflags; - int skipc; - int lfsc; - int wrote_something = 0; mutex_enter(&lfs_lock); KASSERTMSG(lfs_writer_daemon == NULL, "more than one LFS writer daemon"); @@ -406,10 +465,10 @@ lfs_writerd(void *arg) mutex_enter(&lfs_lock); for (;;) { KASSERT(mutex_owned(&lfs_lock)); - if (wrote_something == 0) + if (ctx.wrote_something == 0) cv_timedwait(&lfs_writerd_cv, &lfs_lock, hz/10 + 1); KASSERT(mutex_owned(&lfs_lock)); - wrote_something = 0; + ctx.wrote_something = 0; /* * If global state wants a flush, flush everything. @@ -446,78 +505,18 @@ lfs_writerd(void *arg) * Look through the list of LFSs to see if any of them * have requested pageouts. */ - mutex_enter(&mountlist_lock); - lfsc = 0; - skipc = 0; - for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { - if (vfs_busy(mp, &nmp)) { - ++skipc; - continue; - } - KASSERT(!mutex_owned(&lfs_lock)); - if (strncmp(mp->mnt_stat.f_fstypename, MOUNT_LFS, - sizeof(mp->mnt_stat.f_fstypename)) == 0) { - ++lfsc; - fs = VFSTOULFS(mp)->um_lfs; - daddr_t ooffset = 0; - fsflags = SEGM_SINGLE; - - mutex_enter(&lfs_lock); - ooffset = lfs_sb_getoffset(fs); - - if (lfs_sb_getnextseg(fs) < lfs_sb_getcurseg(fs) && fs->lfs_nowrap) { - /* Don't try to write if we're suspended */ - mutex_exit(&lfs_lock); - vfs_unbusy(mp, false, &nmp); - continue; - } - if (LFS_STARVED_FOR_SEGS(fs)) { - mutex_exit(&lfs_lock); - - DLOG((DLOG_FLUSH, "lfs_writerd: need cleaning before writing possible\n")); - lfs_wakeup_cleaner(fs); - vfs_unbusy(mp, false, &nmp); - continue; - } - - if ((fs->lfs_dirvcount > LFS_MAX_FSDIROP(fs) || - lfs_dirvcount > LFS_MAX_DIROP) && - fs->lfs_dirops == 0) { - fsflags &= ~SEGM_SINGLE; - fsflags |= SEGM_CKP; - DLOG((DLOG_FLUSH, "lfs_writerd: checkpoint\n")); - lfs_flush_fs(fs, fsflags); - } else if (fs->lfs_pdflush) { - DLOG((DLOG_FLUSH, "lfs_writerd: pdflush set\n")); - lfs_flush_fs(fs, fsflags); - } else if (!TAILQ_EMPTY(&fs->lfs_pchainhd)) { - DLOG((DLOG_FLUSH, "lfs_writerd: pchain non-empty\n")); - mutex_exit(&lfs_lock); - lfs_writer_enter(fs, "wrdirop"); - lfs_flush_pchain(fs); - lfs_writer_leave(fs); - mutex_enter(&lfs_lock); - } - if (lfs_sb_getoffset(fs) != ooffset) - ++wrote_something; - mutex_exit(&lfs_lock); - } - KASSERT(!mutex_owned(&lfs_lock)); - vfs_unbusy(mp, false, &nmp); - } - if (lfsc + skipc == 0) { + ctx.lfsc = 0; + mountlist_iterate(lfs_writerd_cb, &ctx); + if (ctx.lfsc == 0) { mutex_enter(&lfs_lock); lfs_writer_daemon = NULL; mutex_exit(&lfs_lock); - mutex_exit(&mountlist_lock); break; } - mutex_exit(&mountlist_lock); mutex_enter(&lfs_lock); } KASSERT(!mutex_owned(&lfs_lock)); - KASSERT(!mutex_owned(&mountlist_lock)); /* Give up our extra reference so the module can be unloaded. */ mutex_enter(&vfs_list_lock);