diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index c00d66a..4f68347 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -952,15 +952,17 @@ vn_start_write(vp, mpp, flags) /* * Check on status of suspension. */ - while ((mp->mnt_kern_flag & MNTK_SUSPEND) != 0) { - if (flags & V_NOWAIT) { - error = EWOULDBLOCK; - goto unlock; + if ((curthread->td_pflags & TDP_IGNSUSP) == 0) { + while ((mp->mnt_kern_flag & MNTK_SUSPEND) != 0) { + if (flags & V_NOWAIT) { + error = EWOULDBLOCK; + goto unlock; + } + error = msleep(&mp->mnt_flag, MNT_MTX(mp), + (PUSER - 1) | (flags & PCATCH), "suspfs", 0); + if (error) + goto unlock; } - error = msleep(&mp->mnt_flag, MNT_MTX(mp), - (PUSER - 1) | (flags & PCATCH), "suspfs", 0); - if (error) - goto unlock; } if (flags & V_XSLEEP) goto unlock; @@ -1055,7 +1057,8 @@ vn_start_secondary_write(vp, mpp, flags) MNT_ILOCK(mp); if (vp == NULL) MNT_REF(mp); - if ((mp->mnt_kern_flag & (MNTK_SUSPENDED | MNTK_SUSPEND2)) == 0) { + if ((curthread->td_pflags & TDP_IGNSUSP) != 0 || + (mp->mnt_kern_flag & (MNTK_SUSPENDED | MNTK_SUSPEND2)) == 0) { mp->mnt_secondary_writes++; mp->mnt_secondary_accwrites++; MNT_REL(mp); diff --git a/sys/sys/proc.h b/sys/sys/proc.h index fa10291..bcf083a 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -359,6 +359,7 @@ do { \ #define TDP_INBDFLUSH 0x00100000 /* Already in BO_BDFLUSH, do not recurse */ #define TDP_KTHREAD 0x00200000 /* This is an official kernel thread */ #define TDP_CALLCHAIN 0x00400000 /* Capture thread's callchain */ +#define TDP_IGNSUSP 0x00800000 /* Permission to ignore the MNTK_SUSPEND* */ /* * Reasons that the current thread can not be run yet. diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index 67986c1..a6485fa 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -80,6 +80,7 @@ void ffs_snapremove(struct vnode *vp); int ffs_snapshot(struct mount *mp, char *snapfile); void ffs_snapshot_mount(struct mount *mp); void ffs_snapshot_unmount(struct mount *mp); +void process_deferred_inactive(struct mount *mp); int ffs_syncvnode(struct vnode *vp, int waitfor); int ffs_truncate(struct vnode *, off_t, int, struct ucred *, struct thread *); int ffs_update(struct vnode *, int); diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index 27f40d2..7f51087 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -123,6 +123,11 @@ ffs_copyonwrite(devvp, bp) return (EINVAL); } +void +process_deferred_inactive(struct mount *mp) +{ +} + #else TAILQ_HEAD(snaphead, inode); @@ -167,7 +172,6 @@ static int snapacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, static int mapacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, struct fs *, ufs_lbn_t, int); static int readblock(struct vnode *vp, struct buf *, ufs2_daddr_t); -static void process_deferred_inactive(struct mount *); static void try_free_snapdata(struct vnode *devvp); static struct snapdata *ffs_snapdata_acquire(struct vnode *devvp); static int ffs_bp_snapblk(struct vnode *, struct buf *); @@ -2380,7 +2384,7 @@ readblock(vp, bp, lbn) * the file system being suspended. Transfer IN_LAZYACCESS into * IN_MODIFIED for vnodes that were accessed during suspension. */ -static void +void process_deferred_inactive(struct mount *mp) { struct vnode *vp, *mvp; diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 1b746f6..3874495 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -185,14 +185,36 @@ ffs_mount(struct mount *mp, struct thread *td) devvp = ump->um_devvp; if (fs->fs_ronly == 0 && vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { - if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0) - return (error); /* - * Flush any dirty data. + * Remove the MNT_RDONLY flag, it is set too + * early for suspension. */ - if ((error = ffs_sync(mp, MNT_WAIT, td)) != 0) { - vn_finished_write(mp); + MNT_ILOCK(mp); + mp->mnt_flag &= ~MNT_RDONLY; + MNT_IUNLOCK(mp); + /* + * Flush any dirty data and suspend filesystem. + */ + if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0) return (error); + for (;;) { + vn_finished_write(mp); + if ((error = vfs_write_suspend(mp)) != 0) + return (error); + MNT_ILOCK(mp); + if (mp->mnt_kern_flag & MNTK_SUSPENDED) { + /* + * Allow the secondary writes + * to proceed. + */ + mp->mnt_kern_flag &= ~MNTK_SUSPENDED; + wakeup(&mp->mnt_flag); + MNT_IUNLOCK(mp); + curthread->td_pflags |= TDP_IGNSUSP; + break; + } + MNT_IUNLOCK(mp); + vn_start_write(NULL, &mp, V_WAIT); } /* * Check for and optionally get rid of files open @@ -207,7 +229,9 @@ ffs_mount(struct mount *mp, struct thread *td) error = ffs_flushfiles(mp, flags, td); } if (error) { - vn_finished_write(mp); + vfs_write_resume(mp); + curthread->td_pflags &= ~TDP_IGNSUSP; + process_deferred_inactive(mp); return (error); } if (fs->fs_pendingblocks != 0 || @@ -224,10 +248,12 @@ ffs_mount(struct mount *mp, struct thread *td) if ((error = ffs_sbupdate(ump, MNT_WAIT, 0)) != 0) { fs->fs_ronly = 0; fs->fs_clean = 0; - vn_finished_write(mp); + vfs_write_resume(mp); + curthread->td_pflags &= ~TDP_IGNSUSP; + process_deferred_inactive(mp); return (error); } - vn_finished_write(mp); + curthread->td_pflags &= ~TDP_IGNSUSP; DROP_GIANT(); g_topology_lock(); g_access(ump->um_cp, 0, -1, 0); @@ -237,6 +263,12 @@ ffs_mount(struct mount *mp, struct thread *td) MNT_ILOCK(mp); mp->mnt_flag |= MNT_RDONLY; MNT_IUNLOCK(mp); + /* + * Allow the writers to note that filesystem + * is ro now. + */ + vfs_write_resume(mp); + process_deferred_inactive(mp); } if ((mp->mnt_flag & MNT_RELOAD) && (error = ffs_reload(mp, td)) != 0)