From dc1147adb06ee01012984702aebef6c27b92c7e0 Mon Sep 17 00:00:00 2001 From: kib Date: Tue, 10 Oct 2006 09:20:54 +0000 Subject: Do not translate the IN_ACCESS inode flag into the IN_MODIFIED while filesystem is suspending/suspended. Doing so may result in deadlock. Instead, set the (new) IN_LAZYACCESS flag, that becomes IN_MODIFIED when suspend is lifted. Change the locking protocol in order to set the IN_ACCESS and timestamps without upgrading shared vnode lock to exclusive (see comments in the inode.h). Before that, inode was modified while holding only shared lock. Tested by: Peter Holm Reviewed by: tegge, bde Approved by: pjd (mentor) MFC after: 3 weeks --- sys/ufs/ffs/ffs_inode.c | 12 +++++++----- sys/ufs/ffs/ffs_snapshot.c | 24 ++++++++++++++++++------ sys/ufs/ffs/ffs_vnops.c | 10 ++++++++-- 3 files changed, 33 insertions(+), 13 deletions(-) (limited to 'sys/ufs/ffs') diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c index 33b65bf..ad6bff9 100644 --- a/sys/ufs/ffs/ffs_inode.c +++ b/sys/ufs/ffs/ffs_inode.c @@ -66,9 +66,11 @@ static int ffs_indirtrunc(struct inode *, ufs2_daddr_t, ufs2_daddr_t, * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively. Write the inode * to disk if the IN_MODIFIED flag is set (it may be set initially, or by * the timestamp update). The IN_LAZYMOD flag is set to force a write - * later if not now. If we write now, then clear both IN_MODIFIED and - * IN_LAZYMOD to reflect the presumably successful write, and if waitfor is - * set, then wait for the write to complete. + * later if not now. The IN_LAZYACCESS is set instead of IN_MODIFIED if the fs + * is currently being suspended (or is suspended) and vnode has been accessed. + * If we write now, then clear IN_MODIFIED, IN_LAZYACCESS and IN_LAZYMOD to + * reflect the presumably successful write, and if waitfor is set, then wait + * for the write to complete. */ int ffs_update(vp, waitfor) @@ -80,12 +82,12 @@ ffs_update(vp, waitfor) struct inode *ip; int error; - ASSERT_VOP_LOCKED(vp, "ffs_update"); + ASSERT_VOP_ELOCKED(vp, "ffs_update"); ufs_itimes(vp); ip = VTOI(vp); if ((ip->i_flag & IN_MODIFIED) == 0 && waitfor == 0) return (0); - ip->i_flag &= ~(IN_LAZYMOD | IN_MODIFIED); + ip->i_flag &= ~(IN_LAZYACCESS | IN_LAZYMOD | IN_MODIFIED); fs = ip->i_fs; if (fs->fs_ronly) return (0); diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index 473dbfd..6ab9af2 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -2309,15 +2309,16 @@ readblock(vp, bp, lbn) return (bp->b_error); } - /* * Process file deletes that were deferred by ufs_inactive() due to - * the file system being suspended. + * the file system being suspended. Transfer IN_LAZYACCESS into + * IN_MODIFIED for vnodes that were accessed during suspension. */ static void process_deferred_inactive(struct mount *mp) { struct vnode *vp, *mvp; + struct inode *ip; struct thread *td; int error; @@ -2327,9 +2328,15 @@ process_deferred_inactive(struct mount *mp) loop: MNT_VNODE_FOREACH(vp, mp, mvp) { VI_LOCK(vp); - if ((vp->v_iflag & (VI_DOOMED | VI_OWEINACT)) != VI_OWEINACT || - vp->v_usecount > 0 || - vp->v_type == VNON) { + /* + * IN_LAZYACCESS is checked here without holding any + * vnode lock, but this flag is set only while holding + * vnode interlock. + */ + if (vp->v_type == VNON || (vp->v_iflag & VI_DOOMED) != 0 || + ((VTOI(vp)->i_flag & IN_LAZYACCESS) == 0 && + ((vp->v_iflag & VI_OWEINACT) == 0 || + vp->v_usecount > 0))) { VI_UNLOCK(vp); continue; } @@ -2344,8 +2351,13 @@ process_deferred_inactive(struct mount *mp) MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp); goto loop; } + ip = VTOI(vp); + if ((ip->i_flag & IN_LAZYACCESS) != 0) { + ip->i_flag &= ~IN_LAZYACCESS; + ip->i_flag |= IN_MODIFIED; + } VI_LOCK(vp); - if ((vp->v_iflag & VI_OWEINACT) == 0) { + if ((vp->v_iflag & VI_OWEINACT) == 0 || vp->v_usecount > 0) { VI_UNLOCK(vp); VOP_UNLOCK(vp, 0, td); vdrop(vp); diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index 91d2c01..4d8d9ef 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -593,8 +593,11 @@ ffs_read(ap) } if ((error == 0 || uio->uio_resid != orig_resid) && - (vp->v_mount->mnt_flag & MNT_NOATIME) == 0) + (vp->v_mount->mnt_flag & MNT_NOATIME) == 0) { + VI_LOCK(vp); ip->i_flag |= IN_ACCESS; + VI_UNLOCK(vp); + } return (error); } @@ -989,8 +992,11 @@ ffs_extread(struct vnode *vp, struct uio *uio, int ioflag) } if ((error == 0 || uio->uio_resid != orig_resid) && - (vp->v_mount->mnt_flag & MNT_NOATIME) == 0) + (vp->v_mount->mnt_flag & MNT_NOATIME) == 0) { + VI_LOCK(vp); ip->i_flag |= IN_ACCESS; + VI_UNLOCK(vp); + } return (error); } -- cgit v1.1