diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2018-02-10 05:24:24 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2018-02-10 05:24:24 +0000 |
commit | 46a5fdccdbec824aec3e3e383277baed4c200dee (patch) | |
tree | d5edda8fa947c8eeb74eb1c49f6b40b68b93b101 /sys/ufs/ext2fs | |
parent | d02979485b47a573dd086a214bbd30bce63e5708 (diff) |
Syncronize filesystems to disk when suspending. Each mountpoint's vnodes
are pushed to disk. Dangling vnodes (unlinked files still in use) and
vnodes undergoing change by long-running syscalls are identified -- and
such filesystems are marked dirty on-disk while we are suspended (in case
power is lost, a fsck will be required). Filesystems without dangling or
busy vnodes are marked clean, resulting in faster boots following
"battery died" circumstances.
Tested by numerous developers, thanks for the feedback.
Diffstat (limited to 'sys/ufs/ext2fs')
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_extern.h | 4 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_vfsops.c | 58 |
2 files changed, 49 insertions, 13 deletions
diff --git a/sys/ufs/ext2fs/ext2fs_extern.h b/sys/ufs/ext2fs/ext2fs_extern.h index a0253a1470e..68c71ca1e9e 100644 --- a/sys/ufs/ext2fs/ext2fs_extern.h +++ b/sys/ufs/ext2fs/ext2fs_extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_extern.h,v 1.36 2016/08/10 07:53:02 natano Exp $ */ +/* $OpenBSD: ext2fs_extern.h,v 1.37 2018/02/10 05:24:23 deraadt Exp $ */ /* $NetBSD: ext2fs_extern.h,v 1.1 1997/06/11 09:33:55 bouyer Exp $ */ /*- @@ -105,7 +105,7 @@ int ext2fs_mountfs(struct vnode *, struct mount *, struct proc *); int ext2fs_unmount(struct mount *, int, struct proc *); int ext2fs_flushfiles(struct mount *, int, struct proc *); int ext2fs_statfs(struct mount *, struct statfs *, struct proc *); -int ext2fs_sync(struct mount *, int, struct ucred *, struct proc *); +int ext2fs_sync(struct mount *, int, int, struct ucred *, struct proc *); int ext2fs_vget(struct mount *, ino_t, struct vnode **); int ext2fs_fhtovp(struct mount *, struct fid *, struct vnode **); int ext2fs_vptofh(struct vnode *, struct fid *); diff --git a/sys/ufs/ext2fs/ext2fs_vfsops.c b/sys/ufs/ext2fs/ext2fs_vfsops.c index 114285d423c..55cfacddb2e 100644 --- a/sys/ufs/ext2fs/ext2fs_vfsops.c +++ b/sys/ufs/ext2fs/ext2fs_vfsops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_vfsops.c,v 1.101 2017/12/30 23:08:29 guenther Exp $ */ +/* $OpenBSD: ext2fs_vfsops.c,v 1.102 2018/02/10 05:24:23 deraadt Exp $ */ /* $NetBSD: ext2fs_vfsops.c,v 1.1 1997/06/11 09:34:07 bouyer Exp $ */ /* @@ -696,6 +696,8 @@ int ext2fs_sync_vnode(struct vnode *vp, void *); struct ext2fs_sync_args { int allerror; int waitfor; + int nlink0; + int inflight; struct proc *p; struct ucred *cred; }; @@ -705,22 +707,34 @@ ext2fs_sync_vnode(struct vnode *vp, void *args) { struct ext2fs_sync_args *esa = args; struct inode *ip; - int error; + int error, nlink0 = 0; - ip = VTOI(vp); - if (vp->v_type == VNON || - ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && - LIST_EMPTY(&vp->v_dirtyblkhd)) || - esa->waitfor == MNT_LAZY) { + if (vp->v_type == VNON) return (0); + + if (vp->v_inflight) + esa->inflight = MIN(esa->inflight+1, 65536); + + ip = VTOI(vp); + + if (ip->i_e2fs_nlink == 0) + nlink0 = 1; + + if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && + LIST_EMPTY(&vp->v_dirtyblkhd)) { + goto end; } - if (vget(vp, LK_EXCLUSIVE | LK_NOWAIT, esa->p)) - return (0); + if (vget(vp, LK_EXCLUSIVE | LK_NOWAIT, esa->p)) { + nlink0 = 1; /* potentially */ + goto end; + } if ((error = VOP_FSYNC(vp, esa->cred, esa->waitfor, esa->p)) != 0) esa->allerror = error; vput(vp); +end: + esa->nlink0 = MIN(esa->nlink0 + nlink0, 65536); return (0); } /* @@ -731,11 +745,12 @@ ext2fs_sync_vnode(struct vnode *vp, void *args) * Should always be called with the mount point locked. */ int -ext2fs_sync(struct mount *mp, int waitfor, struct ucred *cred, struct proc *p) +ext2fs_sync(struct mount *mp, int waitfor, int stall, + struct ucred *cred, struct proc *p) { struct ufsmount *ump = VFSTOUFS(mp); struct m_ext2fs *fs; - int error, allerror = 0; + int error, allerror = 0, state, fmod; struct ext2fs_sync_args esa; fs = ump->um_e2fs; @@ -751,6 +766,8 @@ ext2fs_sync(struct mount *mp, int waitfor, struct ucred *cred, struct proc *p) esa.cred = cred; esa.allerror = 0; esa.waitfor = waitfor; + esa.nlink0 = 0; + esa.inflight = 0; vfs_mount_foreach_vnode(mp, ext2fs_sync_vnode, &esa); if (esa.allerror != 0) @@ -768,12 +785,31 @@ ext2fs_sync(struct mount *mp, int waitfor, struct ucred *cred, struct proc *p) /* * Write back modified superblock. */ + state = fs->e2fs.e2fs_state; + fmod = fs->e2fs_fmod; + if (stall && fs->e2fs_ronly == 0) { + fs->e2fs_fmod = 1; + if (allerror == 0 && esa.nlink0 == 0 && esa.inflight == 0) { + if ((fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) + fs->e2fs.e2fs_state = E2FS_ISCLEAN; +#if 0 + printf("%s force clean (dangling %d inflight %d)\n", + mp->mnt_stat.f_mntonname, esa.nlink0, esa.inflight); +#endif + } else { + fs->e2fs.e2fs_state = 0; + printf("%s force dirty (dangling %d inflight %d)\n", + mp->mnt_stat.f_mntonname, esa.nlink0, esa.inflight); + } + } if (fs->e2fs_fmod != 0) { fs->e2fs_fmod = 0; fs->e2fs.e2fs_wtime = time_second; if ((error = ext2fs_cgupdate(ump, waitfor))) allerror = error; } + fs->e2fs.e2fs_state = state; + fs->e2fs_fmod = fmod; return (allerror); } |