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

_______________________________________________
freebsd-stable@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-stable
To unsubscribe, send any mail to "freebsd-stable-unsubscr...@freebsd.org"

Reply via email to