Index: sys/fs/msdosfs/msdosfs_vfsops.c =================================================================== RCS file: /cvsroot/src/sys/fs/msdosfs/msdosfs_vfsops.c,v retrieving revision 1.107 diff -u -p -u -r1.107 msdosfs_vfsops.c --- sys/fs/msdosfs/msdosfs_vfsops.c 16 Apr 2014 18:55:18 -0000 1.107 +++ sys/fs/msdosfs/msdosfs_vfsops.c 23 May 2014 18:21:10 -0000 @@ -943,14 +943,34 @@ msdosfs_statvfs(struct mount *mp, struct return (0); } +struct msdosfs_sync_ctx { + int waitfor; +}; + +static bool +msdosfs_sync_selector(void *cl, struct vnode *vp) +{ + struct msdosfs_sync_ctx *c = cl; + struct denode *dep; + + dep = VTODE(vp); + if (c->waitfor == MNT_LAZY || vp->v_type == VNON || + dep == NULL || (((dep->de_flag & + (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0) && + (LIST_EMPTY(&vp->v_dirtyblkhd) && + UVM_OBJ_IS_CLEAN(&vp->v_uobj)))) + return false; + return true; +} + int msdosfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) { struct vnode *vp; struct vnode_iterator *marker; - struct denode *dep; struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); int error, allerror = 0; + struct msdosfs_sync_ctx ctx; /* * If we ever switch to not updating all of the FATs all the time, @@ -968,21 +988,15 @@ msdosfs_sync(struct mount *mp, int waitf * Write back each (modified) denode. */ vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { + ctx.waitfor = waitfor; + while ((vp = vfs_vnode_iterator_next(marker, msdosfs_sync_selector, + &ctx))) + { error = vn_lock(vp, LK_EXCLUSIVE); if (error) { vrele(vp); continue; } - dep = VTODE(vp); - if (waitfor == MNT_LAZY || vp->v_type == VNON || - dep == NULL || (((dep->de_flag & - (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0) && - (LIST_EMPTY(&vp->v_dirtyblkhd) && - UVM_OBJ_IS_CLEAN(&vp->v_uobj)))) { - vput(vp); - continue; - } if ((error = VOP_FSYNC(vp, cred, waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0)) != 0) allerror = error; Index: sys/fs/puffs/puffs_vfsops.c =================================================================== RCS file: /cvsroot/src/sys/fs/puffs/puffs_vfsops.c,v retrieving revision 1.110 diff -u -p -u -r1.110 puffs_vfsops.c --- sys/fs/puffs/puffs_vfsops.c 16 Apr 2014 18:55:18 -0000 1.110 +++ sys/fs/puffs/puffs_vfsops.c 23 May 2014 18:21:10 -0000 @@ -510,6 +510,18 @@ puffs_vfsop_statvfs(struct mount *mp, st return error; } +static bool +pageflush_selector(void *cl, struct vnode *vp) +{ + bool rv; + + mutex_enter(vp->v_interlock); + rv = vp->v_type == VREG && !UVM_OBJ_IS_CLEAN(&vp->v_uobj); + mutex_exit(vp->v_interlock); + + return rv; +} + static int pageflush(struct mount *mp, kauth_cred_t cred, int waitfor) { @@ -528,7 +540,9 @@ pageflush(struct mount *mp, kauth_cred_t * all the nodes it knows to exist. */ vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { + while ((vp = vfs_vnode_iterator_next(marker, pageflush_selector, + NULL))) + { /* * Here we try to get a reference to the vnode and to * lock it. This is mostly cargo-culted, but I will @@ -550,11 +564,6 @@ pageflush(struct mount *mp, kauth_cred_t continue; } pn = VPTOPP(vp); - if (vp->v_type != VREG || UVM_OBJ_IS_CLEAN(&vp->v_uobj)) { - vput(vp); - continue; - } - /* hmm.. is the FAF thing entirely sensible? */ if (waitfor == MNT_LAZY) { mutex_enter(vp->v_interlock); Index: sys/fs/smbfs/smbfs_vfsops.c =================================================================== RCS file: /cvsroot/src/sys/fs/smbfs/smbfs_vfsops.c,v retrieving revision 1.100 diff -u -p -u -r1.100 smbfs_vfsops.c --- sys/fs/smbfs/smbfs_vfsops.c 16 Apr 2014 18:55:18 -0000 1.100 +++ sys/fs/smbfs/smbfs_vfsops.c 23 May 2014 18:25:33 -0000 @@ -400,6 +400,23 @@ smbfs_statvfs(struct mount *mp, struct s return 0; } +static bool +smbfs_sync_selector(void *cl, struct vnode *vp) +{ + struct smbnode *np; + + np = VTOSMB(vp); + if (np == NULL) + return false; + + if ((vp->v_type == VNON || (np->n_flag & NMODIFIED) == 0) && + LIST_EMPTY(&vp->v_dirtyblkhd) && + vp->v_uobj.uo_npages == 0) + return false; + + return true; +} + /* * Flush out the buffer cache */ @@ -408,27 +425,17 @@ smbfs_sync(struct mount *mp, int waitfor { struct vnode *vp; struct vnode_iterator *marker; - struct smbnode *np; int error, allerror = 0; vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { + while ((vp = vfs_vnode_iterator_next(marker, smbfs_sync_selector, + NULL))) + { error = vn_lock(vp, LK_EXCLUSIVE); if (error) { vrele(vp); continue; } - np = VTOSMB(vp); - if (np == NULL) { - vput(vp); - continue; - } - if ((vp->v_type == VNON || (np->n_flag & NMODIFIED) == 0) && - LIST_EMPTY(&vp->v_dirtyblkhd) && - vp->v_uobj.uo_npages == 0) { - vput(vp); - continue; - } error = VOP_FSYNC(vp, cred, waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0); if (error) Index: sys/kern/vfs_mount.c =================================================================== RCS file: /cvsroot/src/sys/kern/vfs_mount.c,v retrieving revision 1.28 diff -u -p -u -r1.28 vfs_mount.c --- sys/kern/vfs_mount.c 18 Mar 2014 10:21:47 -0000 1.28 +++ sys/kern/vfs_mount.c 23 May 2014 18:21:10 -0000 @@ -371,8 +371,9 @@ vfs_vnode_iterator_destroy(struct vnode_ vnfree(mvp); } -bool -vfs_vnode_iterator_next(struct vnode_iterator *vi, struct vnode **vpp) +struct vnode * +vfs_vnode_iterator_next(struct vnode_iterator *vi, + bool (*f)(void *, struct vnode *), void *cl) { struct vnode *mvp = &vi->vi_vnode; struct mount *mp = mvp->v_mount; @@ -386,20 +387,24 @@ vfs_vnode_iterator_next(struct vnode_ite vp = TAILQ_NEXT(mvp, v_mntvnodes); TAILQ_REMOVE(&mp->mnt_vnodelist, mvp, v_mntvnodes); mvp->v_usecount = 0; +again: if (vp == NULL) { mutex_exit(&mntvnode_lock); - *vpp = NULL; - return false; + return NULL; } - mutex_enter(vp->v_interlock); + if (f && !(*f)(cl, vp)) { + mutex_exit(vp->v_interlock); + vp = TAILQ_NEXT(vp, v_mntvnodes); + goto again; + } + while ((vp->v_iflag & VI_MARKER) != 0) { mutex_exit(vp->v_interlock); vp = TAILQ_NEXT(vp, v_mntvnodes); if (vp == NULL) { mutex_exit(&mntvnode_lock); - *vpp = NULL; - return false; + return NULL; } mutex_enter(vp->v_interlock); } @@ -411,8 +416,7 @@ vfs_vnode_iterator_next(struct vnode_ite KASSERT(error == 0 || error == ENOENT); } while (error != 0); - *vpp = vp; - return true; + return vp; } /* @@ -465,59 +469,64 @@ int busyprt = 0; /* print out busy vnode struct ctldebug debug1 = { "busyprt", &busyprt }; #endif -static vnode_t * -vflushnext(struct vnode_iterator *marker, int *when) +struct vflush_ctx { + const struct vnode *skipvp; + int flags; +}; + +static bool +vflush_selector(void *cl, struct vnode *vp) { - struct vnode *vp; + struct vflush_ctx *c = cl; + /* + * Skip over a selected vnode. + */ + if (vp == c->skipvp) + return false; + /* + * Skip over a vnodes marked VSYSTEM. + */ + if ((c->flags & SKIPSYSTEM) && (vp->v_vflag & VV_SYSTEM)) + return false; + /* + * If WRITECLOSE is set, only flush out regular file + * vnodes open for writing. + */ + if ((c->flags & WRITECLOSE) && vp->v_type == VREG) { + if (vp->v_writecount == 0) + return false; + } + return true; +} + +static vnode_t * +vflushnext(struct vnode_iterator *marker, void *ctx, int *when) +{ if (hardclock_ticks > *when) { yield(); *when = hardclock_ticks + hz / 10; } - if (vfs_vnode_iterator_next(marker, &vp)) - return vp; - return NULL; + return vfs_vnode_iterator_next(marker, vflush_selector, ctx); } + int vflush(struct mount *mp, vnode_t *skipvp, int flags) { vnode_t *vp; struct vnode_iterator *marker; int busy = 0, when = 0; + struct vflush_ctx ctx; /* First, flush out any vnode references from vrele_list. */ vrele_flush(); vfs_vnode_iterator_init(mp, &marker); - while ((vp = vflushnext(marker, &when)) != NULL) { - /* - * Skip over a selected vnode. - */ - if (vp == skipvp) { - vrele(vp); - continue; - } - /* - * Skip over a vnodes marked VSYSTEM. - */ - if ((flags & SKIPSYSTEM) && (vp->v_vflag & VV_SYSTEM)) { - vrele(vp); - continue; - } - /* - * If WRITECLOSE is set, only flush out regular file - * vnodes open for writing. - */ - if ((flags & WRITECLOSE) && vp->v_type == VREG) { - mutex_enter(vp->v_interlock); - if (vp->v_writecount == 0) { - mutex_exit(vp->v_interlock); - vrele(vp); - continue; - } - mutex_exit(vp->v_interlock); - } + + ctx.skipvp = skipvp; + ctx.flags = flags; + while ((vp = vflushnext(marker, &ctx, &when)) != NULL) { /* * First try to recycle the vnode. */ Index: sys/kern/vfs_subr.c =================================================================== RCS file: /cvsroot/src/sys/kern/vfs_subr.c,v retrieving revision 1.443 diff -u -p -u -r1.443 vfs_subr.c --- sys/kern/vfs_subr.c 17 Mar 2014 09:28:37 -0000 1.443 +++ sys/kern/vfs_subr.c 23 May 2014 18:21:10 -0000 @@ -637,7 +637,7 @@ sysctl_kern_vnode(SYSCTLFN_ARGS) continue; } vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { + while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) { if (bp + VPTRSZ + VNODESZ > ewhere) { vrele(vp); vfs_vnode_iterator_destroy(marker); Index: sys/nfs/nfs_subs.c =================================================================== RCS file: /cvsroot/src/sys/nfs/nfs_subs.c,v retrieving revision 1.225 diff -u -p -u -r1.225 nfs_subs.c --- sys/nfs/nfs_subs.c 17 Mar 2014 09:35:24 -0000 1.225 +++ sys/nfs/nfs_subs.c 23 May 2014 18:21:24 -0000 @@ -1743,6 +1743,30 @@ netaddr_match(int family, union nethosta return (0); } +struct nfs_clearcommit_ctx { + struct mount *mp; +}; + +static bool +nfs_clearcommit_selector(void *cl, struct vnode *vp) +{ + struct nfs_clearcommit_ctx *c = cl; + struct nfsnode *np; + struct vm_page *pg; + + np = VTONFS(vp); + if (vp->v_type != VREG || vp->v_mount != c->mp || np == NULL) + return false; + np->n_pushlo = np->n_pushhi = np->n_pushedlo = + np->n_pushedhi = 0; + np->n_commitflags &= + ~(NFS_COMMIT_PUSH_VALID | NFS_COMMIT_PUSHED_VALID); + TAILQ_FOREACH(pg, &vp->v_uobj.memq, listq.queue) { + pg->flags &= ~PG_NEEDCOMMIT; + } + return false; +} + /* * The write verifier has changed (probably due to a server reboot), so all * PG_NEEDCOMMIT pages will have to be written again. Since they are marked @@ -1755,28 +1779,14 @@ nfs_clearcommit(struct mount *mp) { struct vnode *vp; struct vnode_iterator *marker; - struct nfsnode *np; - struct vm_page *pg; struct nfsmount *nmp = VFSTONFS(mp); + struct nfs_clearcommit_ctx ctx; rw_enter(&nmp->nm_writeverflock, RW_WRITER); vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { - mutex_enter(vp->v_interlock); - np = VTONFS(vp); - if (vp->v_type != VREG || vp->v_mount != mp || np == NULL) { - mutex_exit(vp->v_interlock); - vrele(vp); - continue; - } - np->n_pushlo = np->n_pushhi = np->n_pushedlo = - np->n_pushedhi = 0; - np->n_commitflags &= - ~(NFS_COMMIT_PUSH_VALID | NFS_COMMIT_PUSHED_VALID); - TAILQ_FOREACH(pg, &vp->v_uobj.memq, listq.queue) { - pg->flags &= ~PG_NEEDCOMMIT; - } - mutex_exit(vp->v_interlock); + ctx.mp = mp; + while ((vp = vfs_vnode_iterator_next(marker, nfs_clearcommit_selector, + &ctx))) { vrele(vp); } vfs_vnode_iterator_destroy(marker); Index: sys/nfs/nfs_vfsops.c =================================================================== RCS file: /cvsroot/src/sys/nfs/nfs_vfsops.c,v retrieving revision 1.227 diff -u -p -u -r1.227 nfs_vfsops.c --- sys/nfs/nfs_vfsops.c 16 Apr 2014 18:55:17 -0000 1.227 +++ sys/nfs/nfs_vfsops.c 23 May 2014 18:21:24 -0000 @@ -937,6 +937,13 @@ nfs_root(struct mount *mp, struct vnode extern int syncprt; +static bool +nfs_sync_selector(void *cl, struct vnode *vp) +{ + + return !LIST_EMPTY(&vp->v_dirtyblkhd) || !UVM_OBJ_IS_CLEAN(&vp->v_uobj); +} + /* * Flush out the buffer cache */ @@ -952,17 +959,14 @@ nfs_sync(struct mount *mp, int waitfor, * Force stale buffer cache information to be flushed. */ vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { + while ((vp = vfs_vnode_iterator_next(marker, nfs_sync_selector, + NULL))) + { error = vn_lock(vp, LK_EXCLUSIVE); if (error) { vrele(vp); continue; } - if (LIST_EMPTY(&vp->v_dirtyblkhd) && - UVM_OBJ_IS_CLEAN(&vp->v_uobj)) { - vput(vp); - continue; - } error = VOP_FSYNC(vp, cred, waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0); if (error) Index: sys/sys/mount.h =================================================================== RCS file: /cvsroot/src/sys/sys/mount.h,v retrieving revision 1.213 diff -u -p -u -r1.213 mount.h --- sys/sys/mount.h 8 May 2014 08:21:53 -0000 1.213 +++ sys/sys/mount.h 23 May 2014 18:21:27 -0000 @@ -442,7 +442,8 @@ int vfs_quotactl_quotaoff(struct mount * struct vnode_iterator; /* Opaque. */ void vfs_vnode_iterator_init(struct mount *, struct vnode_iterator **); void vfs_vnode_iterator_destroy(struct vnode_iterator *); -bool vfs_vnode_iterator_next(struct vnode_iterator *, struct vnode **); +struct vnode *vfs_vnode_iterator_next(struct vnode_iterator *, + bool (*)(void *, struct vnode *), void *); extern TAILQ_HEAD(mntlist, mount) mountlist; /* mounted filesystem list */ extern struct vfsops *vfssw[]; /* filesystem type table */ Index: sys/ufs/ext2fs/ext2fs_vfsops.c =================================================================== RCS file: /cvsroot/src/sys/ufs/ext2fs/ext2fs_vfsops.c,v retrieving revision 1.181 diff -u -p -u -r1.181 ext2fs_vfsops.c --- sys/ufs/ext2fs/ext2fs_vfsops.c 8 May 2014 08:21:53 -0000 1.181 +++ sys/ufs/ext2fs/ext2fs_vfsops.c 23 May 2014 18:21:27 -0000 @@ -588,7 +588,7 @@ ext2fs_reload(struct mount *mp, kauth_cr } vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { + while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) { /* * Step 4: invalidate all inactive vnodes. */ @@ -862,6 +862,26 @@ ext2fs_statvfs(struct mount *mp, struct return (0); } +static bool +ext2fs_sync_selector(void *cl, struct vnode *vp) +{ + struct inode *ip; + + ip = VTOI(vp); + /* + * Skip the vnode/inode if inaccessible. + */ + if (ip == NULL || vp->v_type == VNON) + return false; + + if (((ip->i_flag & + (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) == 0 && + LIST_EMPTY(&vp->v_dirtyblkhd) && + UVM_OBJ_IS_CLEAN(&vp->v_uobj))) + return false; + return true; +} + /* * Go through the disk queues to initiate sandbagged IO; * go through the inodes to write those that have been modified; @@ -873,7 +893,6 @@ int ext2fs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) { struct vnode *vp; - struct inode *ip; struct ufsmount *ump = VFSTOUFS(mp); struct m_ext2fs *fs; struct vnode_iterator *marker; @@ -889,28 +908,14 @@ ext2fs_sync(struct mount *mp, int waitfo * Write back each (modified) inode. */ vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { + while ((vp = vfs_vnode_iterator_next(marker, ext2fs_sync_selector, + NULL))) + { error = vn_lock(vp, LK_EXCLUSIVE); if (error) { vrele(vp); continue; } - ip = VTOI(vp); - /* - * Skip the vnode/inode if inaccessible. - */ - if (ip == NULL || vp->v_type == VNON) { - vput(vp); - continue; - } - - if (((ip->i_flag & - (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) == 0 && - LIST_EMPTY(&vp->v_dirtyblkhd) && - UVM_OBJ_IS_CLEAN(&vp->v_uobj))) { - vput(vp); - continue; - } if (vp->v_type == VREG && waitfor == MNT_LAZY) error = ext2fs_update(vp, NULL, NULL, 0); else Index: sys/ufs/ffs/ffs_snapshot.c =================================================================== RCS file: /cvsroot/src/sys/ufs/ffs/ffs_snapshot.c,v retrieving revision 1.133 diff -u -p -u -r1.133 ffs_snapshot.c --- sys/ufs/ffs/ffs_snapshot.c 17 Mar 2014 09:29:20 -0000 1.133 +++ sys/ufs/ffs/ffs_snapshot.c 23 May 2014 18:21:28 -0000 @@ -600,6 +600,42 @@ snapshot_copyfs(struct mount *mp, struct return 0; } +struct snapshot_expunge_ctx { + struct vnode *logvp; + struct lwp *l; + struct vnode *vp; + struct fs *copy_fs; +}; + +static bool +snapshot_expunge_selector(void *cl, struct vnode *xvp) +{ + struct vattr vat; + struct snapshot_expunge_ctx *c = cl; + struct inode *xp; + + xp = VTOI(xvp); + if (xvp->v_type == VNON || VTOI(xvp) == NULL || + (xp->i_flags & SF_SNAPSHOT)) + return false; +#ifdef DEBUG + if (snapdebug) + vprint("ffs_snapshot: busy vnode", xvp); +#endif + + if (xvp == c->logvp) + return true; + + if (VOP_GETATTR(xvp, &vat, c->l->l_cred) == 0 && + vat.va_nlink > 0) + return false; + + if (ffs_checkfreefile(c->copy_fs, c->vp, xp->i_number)) + return false; + + return true; +} + /* * We must check for active files that have been unlinked (e.g., with a zero * link count). We have to expunge all trace of these files from the snapshot @@ -616,9 +652,9 @@ snapshot_expunge(struct mount *mp, struc struct fs *fs = VFSTOUFS(mp)->um_fs; struct inode *xp; struct lwp *l = curlwp; - struct vattr vat; struct vnode *logvp = NULL, *xvp; struct vnode_iterator *marker; + struct snapshot_expunge_ctx ctx; *snaplist = NULL; /* @@ -638,31 +674,17 @@ snapshot_expunge(struct mount *mp, struc FSMAXSNAP + 1 /* superblock */ + 1 /* last block */ + 1 /* size */; vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &xvp)) { - if (xvp->v_type == VNON || VTOI(xvp) == NULL || - (VTOI(xvp)->i_flags & SF_SNAPSHOT)) { - vrele(xvp); - continue; - } -#ifdef DEBUG - if (snapdebug) - vprint("ffs_snapshot: busy vnode", xvp); -#endif - xp = VTOI(xvp); - if (xvp != logvp) { - if (VOP_GETATTR(xvp, &vat, l->l_cred) == 0 && - vat.va_nlink > 0) { - vrele(xvp); - continue; - } - if (ffs_checkfreefile(copy_fs, vp, xp->i_number)) { - vrele(xvp); - continue; - } - } + ctx.logvp = logvp; + ctx.l = l; + ctx.vp = vp; + ctx.copy_fs = copy_fs; + while ((xvp = vfs_vnode_iterator_next(marker, snapshot_expunge_selector, + &ctx))) + { /* * If there is a fragment, clear it here. */ + xp = VTOI(xvp); blkno = 0; loc = howmany(xp->i_size, fs->fs_bsize) - 1; if (loc < UFS_NDADDR) { Index: sys/ufs/ffs/ffs_vfsops.c =================================================================== RCS file: /cvsroot/src/sys/ufs/ffs/ffs_vfsops.c,v retrieving revision 1.298 diff -u -p -u -r1.298 ffs_vfsops.c --- sys/ufs/ffs/ffs_vfsops.c 8 May 2014 08:21:53 -0000 1.298 +++ sys/ufs/ffs/ffs_vfsops.c 23 May 2014 18:21:28 -0000 @@ -808,7 +808,7 @@ ffs_reload(struct mount *mp, kauth_cred_ } vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { + while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) { /* * Step 4: invalidate all inactive vnodes. */ @@ -1594,6 +1594,51 @@ ffs_statvfs(struct mount *mp, struct sta return (0); } +struct ffs_sync_ctx { + int waitfor; + bool is_suspending; +}; + +static bool +ffs_sync_selector(void *cl, struct vnode *vp) +{ + struct ffs_sync_ctx *c = cl; + struct inode *ip; + + ip = VTOI(vp); + /* + * Skip the vnode/inode if inaccessible. + */ + if (ip == NULL || vp->v_type == VNON) + return false; + + /* + * We deliberately update inode times here. This will + * prevent a massive queue of updates accumulating, only + * to be handled by a call to unmount. + * + * XXX It would be better to have the syncer trickle these + * out. Adjustment needed to allow registering vnodes for + * sync when the vnode is clean, but the inode dirty. Or + * have ufs itself trickle out inode updates. + * + * If doing a lazy sync, we don't care about metadata or + * data updates, because they are handled by each vnode's + * synclist entry. In this case we are only interested in + * writing back modified inodes. + */ + if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE | + IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) == 0 && + (c->waitfor == MNT_LAZY || (LIST_EMPTY(&vp->v_dirtyblkhd) && + UVM_OBJ_IS_CLEAN(&vp->v_uobj)))) + return false; + + if (vp->v_type == VBLK && c->is_suspending) + return false; + + return true; +} + /* * Go through the disk queues to initiate sandbagged IO; * go through the inodes to write those that have been modified; @@ -1605,12 +1650,12 @@ int ffs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) { struct vnode *vp; - struct inode *ip; struct ufsmount *ump = VFSTOUFS(mp); struct fs *fs; struct vnode_iterator *marker; int error, allerror = 0; bool is_suspending; + struct ffs_sync_ctx ctx; fs = ump->um_fs; if (fs->fs_fmod != 0 && fs->fs_ronly != 0) { /* XXX */ @@ -1624,47 +1669,16 @@ ffs_sync(struct mount *mp, int waitfor, * Write back each (modified) inode. */ vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { + + ctx.waitfor = waitfor; + ctx.is_suspending = is_suspending; + while ((vp = vfs_vnode_iterator_next(marker, ffs_sync_selector, &ctx))) + { error = vn_lock(vp, LK_EXCLUSIVE); if (error) { vrele(vp); continue; } - ip = VTOI(vp); - /* - * Skip the vnode/inode if inaccessible. - */ - if (ip == NULL || vp->v_type == VNON) { - vput(vp); - continue; - } - - /* - * We deliberately update inode times here. This will - * prevent a massive queue of updates accumulating, only - * to be handled by a call to unmount. - * - * XXX It would be better to have the syncer trickle these - * out. Adjustment needed to allow registering vnodes for - * sync when the vnode is clean, but the inode dirty. Or - * have ufs itself trickle out inode updates. - * - * If doing a lazy sync, we don't care about metadata or - * data updates, because they are handled by each vnode's - * synclist entry. In this case we are only interested in - * writing back modified inodes. - */ - if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE | - IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) == 0 && - (waitfor == MNT_LAZY || (LIST_EMPTY(&vp->v_dirtyblkhd) && - UVM_OBJ_IS_CLEAN(&vp->v_uobj)))) { - vput(vp); - continue; - } - if (vp->v_type == VBLK && is_suspending) { - vput(vp); - continue; - } if (waitfor == MNT_LAZY) { error = UFS_WAPBL_BEGIN(vp->v_mount); if (!error) { Index: sys/ufs/lfs/ulfs_quota1.c =================================================================== RCS file: /cvsroot/src/sys/ufs/lfs/ulfs_quota1.c,v retrieving revision 1.7 diff -u -p -u -r1.7 ulfs_quota1.c --- sys/ufs/lfs/ulfs_quota1.c 17 Mar 2014 09:34:16 -0000 1.7 +++ sys/ufs/lfs/ulfs_quota1.c 23 May 2014 18:21:28 -0000 @@ -370,7 +370,7 @@ lfsquota1_handle_cmd_quotaon(struct lwp * NB: only need to add dquot's for inodes being modified. */ vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { + while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) { error = vn_lock(vp, LK_EXCLUSIVE); if (error) { vrele(vp); @@ -434,7 +434,7 @@ lfsquota1_handle_cmd_quotaoff(struct lwp * deleting any references to quota file being closed. */ vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { + while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) { error = vn_lock(vp, LK_EXCLUSIVE); if (error) { vrele(vp); @@ -760,7 +760,7 @@ lfs_q1sync(struct mount *mp) * synchronizing any modified dquot structures. */ vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { + while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) { error = vn_lock(vp, LK_EXCLUSIVE); if (error) { vrele(vp); Index: sys/ufs/ufs/ufs_quota1.c =================================================================== RCS file: /cvsroot/src/sys/ufs/ufs/ufs_quota1.c,v retrieving revision 1.19 diff -u -p -u -r1.19 ufs_quota1.c --- sys/ufs/ufs/ufs_quota1.c 17 Mar 2014 09:31:35 -0000 1.19 +++ sys/ufs/ufs/ufs_quota1.c 23 May 2014 18:21:28 -0000 @@ -373,7 +373,7 @@ quota1_handle_cmd_quotaon(struct lwp *l, * NB: only need to add dquot's for inodes being modified. */ vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { + while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) { error = vn_lock(vp, LK_EXCLUSIVE); if (error) { vrele(vp); @@ -436,7 +436,7 @@ quota1_handle_cmd_quotaoff(struct lwp *l * deleting any references to quota file being closed. */ vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { + while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) { error = vn_lock(vp, LK_EXCLUSIVE); if (error) { vrele(vp); @@ -762,7 +762,7 @@ q1sync(struct mount *mp) * synchronizing any modified dquot structures. */ vfs_vnode_iterator_init(mp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { + while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) { error = vn_lock(vp, LK_EXCLUSIVE); if (error) { vrele(vp); Index: external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c =================================================================== RCS file: /cvsroot/src/external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c,v retrieving revision 1.12 diff -u -p -u -r1.12 zfs_vfsops.c --- external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c 16 Apr 2014 18:55:18 -0000 1.12 +++ external/cddl/osnet/dist/uts/common/fs/zfs/zfs_vfsops.c 23 May 2014 18:21:30 -0000 @@ -147,6 +147,20 @@ static mntopts_t zfs_mntopts = { mntopts }; +static bool +zfs_sync_selector(void *cl, struct vnode *vp) +{ + znode_t *zp; + + /* + * Skip the vnode/inode if inaccessible, or if the + * atime is clean. + */ + zp = VTOZ(vp); + return zp != NULL && vp->v_type != VNON && zp->z_atime_dirty != 0 + && !zp->z_unlinked; +} + /*ARGSUSED*/ int zfs_sync(vfs_t *vfsp, int flag, cred_t *cr) @@ -174,22 +188,14 @@ zfs_sync(vfs_t *vfsp, int flag, cred_t * * BSD VFS, so we do it in batch here. */ vfs_vnode_iterator_init(vfsp, &marker); - while (vfs_vnode_iterator_next(marker, &vp)) { + while ((vp = vfs_vnode_iterator_next(marker, zfs_sync_selector, NULL))) + { error = vn_lock(vp, LK_EXCLUSIVE); if (error) { vrele(vp); continue; } - /* - * Skip the vnode/inode if inaccessible, or if the - * atime is clean. - */ zp = VTOZ(vp); - if (zp == NULL || vp->v_type == VNON || - zp->z_atime_dirty == 0 || zp->z_unlinked) { - vput(vp); - continue; - } tx = dmu_tx_create(zfsvfs->z_os); dmu_tx_hold_bonus(tx, zp->z_id); error = dmu_tx_assign(tx, TXG_WAIT);