Date: Fri, 28 Dec 2012 22:36:58 +0100 From: Andreas Longwitz <longwitz@incore.de> To: Konstantin Belousov <kostikbel@gmail.com> Cc: pho@freebsd.org, freebsd-stable@freebsd.org, fs@freebsd.org Subject: Re: FS hang with suspfs when creating snapshot on a UFS + GJOURNAL setup Message-ID: <50DE10FA.30102@incore.de> In-Reply-To: <20121228112724.GR82219@kib.kiev.ua> References: <50DC30F6.1050904@incore.de> <20121227133355.GI82219@kib.kiev.ua> <50DC8999.8000708@incore.de> <20121227194145.GM82219@kib.kiev.ua> <50DD6423.5090305@incore.de> <20121228112724.GR82219@kib.kiev.ua>
next in thread | previous in thread | raw e-mail | index | archive | help
Konstantin Belousov wrote: > > Please try the following patch. It is against HEAD, might need some > adjustments for 8. I do the resume and write accounting atomically, > not allowing other suspension to intervent between. > > diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c > index 3f65b05..cf49ecb 100644 > --- a/sys/kern/vfs_vnops.c > +++ b/sys/kern/vfs_vnops.c > @@ -1434,6 +1434,40 @@ vn_closefile(fp, td) > * proceed. If a suspend request is in progress, we wait until the > * suspension is over, and then proceed. > */ > +static int > +vn_start_write_locked(struct mount *mp, int flags) > +{ > + int error; > + > + mtx_assert(MNT_MTX(mp), MA_OWNED); > + error = 0; > + > + /* > + * Check on status of suspension. > + */ > + if ((curthread->td_pflags & TDP_IGNSUSP) == 0 || > + mp->mnt_susp_owner != curthread) { > + 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; > + } > + } > + if (flags & V_XSLEEP) > + goto unlock; > + mp->mnt_writeopcount++; > +unlock: > + if (error != 0 || (flags & V_XSLEEP) != 0) > + MNT_REL(mp); > + MNT_IUNLOCK(mp); > + return (error); > +} > + > int > vn_start_write(vp, mpp, flags) > struct vnode *vp; > @@ -1470,30 +1504,7 @@ vn_start_write(vp, mpp, flags) > if (vp == NULL) > MNT_REF(mp); > > - /* > - * Check on status of suspension. > - */ > - if ((curthread->td_pflags & TDP_IGNSUSP) == 0 || > - mp->mnt_susp_owner != curthread) { > - 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; > - } > - } > - if (flags & V_XSLEEP) > - goto unlock; > - mp->mnt_writeopcount++; > -unlock: > - if (error != 0 || (flags & V_XSLEEP) != 0) > - MNT_REL(mp); > - MNT_IUNLOCK(mp); > - return (error); > + return (vn_start_write_locked(mp, flags)); > } > > /* > @@ -1639,8 +1650,7 @@ vfs_write_suspend(mp) > * Request a filesystem to resume write operations. > */ > void > -vfs_write_resume(mp) > - struct mount *mp; > +vfs_write_resume_flags(struct mount *mp, int flags) > { > > MNT_ILOCK(mp); > @@ -1652,10 +1662,25 @@ vfs_write_resume(mp) > wakeup(&mp->mnt_writeopcount); > wakeup(&mp->mnt_flag); > curthread->td_pflags &= ~TDP_IGNSUSP; > + if ((flags & VR_START_WRITE) != 0) { > + MNT_REF(mp); > + mp->mnt_writeopcount++; > + } > MNT_IUNLOCK(mp); > VFS_SUSP_CLEAN(mp); > - } else > + } else if ((flags & VR_START_WRITE) != 0) { > + MNT_REF(mp); > + vn_start_write_locked(mp, 0); > + } else { > MNT_IUNLOCK(mp); > + } > +} > + > +void > +vfs_write_resume(struct mount *mp) > +{ > + > + vfs_write_resume_flags(mp, 0); > } > > /* > diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h > index 42f9e5f..4371b40 100644 > --- a/sys/sys/vnode.h > +++ b/sys/sys/vnode.h > @@ -392,6 +392,8 @@ extern int vttoif_tab[]; > #define V_NOWAIT 0x0002 /* vn_start_write: don't sleep for suspend */ > #define V_XSLEEP 0x0004 /* vn_start_write: just return after sleep */ > > +#define VR_START_WRITE 0x0001 /* vfs_write_resume: start write atomically */ > + > #define VREF(vp) vref(vp) > > #ifdef DIAGNOSTIC > @@ -701,6 +703,7 @@ int vn_io_fault_uiomove(char *data, int xfersize, struct uio *uio); > int vfs_cache_lookup(struct vop_lookup_args *ap); > void vfs_timestamp(struct timespec *); > void vfs_write_resume(struct mount *mp); > +void vfs_write_resume_flags(struct mount *mp, int flags); > int vfs_write_suspend(struct mount *mp); > int vop_stdbmap(struct vop_bmap_args *); > int vop_stdfsync(struct vop_fsync_args *); > diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c > index e528509..25ad79c 100644 > --- a/sys/ufs/ffs/ffs_snapshot.c > +++ b/sys/ufs/ffs/ffs_snapshot.c > @@ -687,8 +687,7 @@ out1: > /* > * Resume operation on filesystem. > */ > - vfs_write_resume(vp->v_mount); > - vn_start_write(NULL, &wrtmp, V_WAIT); > + vfs_write_resume_flags(vp->v_mount, VR_START_WRITE); > if (collectsnapstats && starttime.tv_sec > 0) { > nanotime(&endtime); > timespecsub(&endtime, &starttime); Your patch adjusted to FreeBSD Stable 8 works fine. Creating a snapshot every minute runs without errors for more than 6 hours now, without the patch my test machine hangs not later than one hour. -- Andreas Longwitz
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?50DE10FA.30102>