summaryrefslogtreecommitdiffstats
path: root/sys/ufs/ffs
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2006-10-10 09:20:54 +0000
committerkib <kib@FreeBSD.org>2006-10-10 09:20:54 +0000
commitdc1147adb06ee01012984702aebef6c27b92c7e0 (patch)
treeb21ac1bbb7acef29dace7ac99cf8f176bcc4b0fc /sys/ufs/ffs
parentc23de2fec88f3af5873cf8856e1e480b353f63cd (diff)
downloadFreeBSD-src-dc1147adb06ee01012984702aebef6c27b92c7e0.zip
FreeBSD-src-dc1147adb06ee01012984702aebef6c27b92c7e0.tar.gz
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
Diffstat (limited to 'sys/ufs/ffs')
-rw-r--r--sys/ufs/ffs/ffs_inode.c12
-rw-r--r--sys/ufs/ffs/ffs_snapshot.c24
-rw-r--r--sys/ufs/ffs/ffs_vnops.c10
3 files changed, 33 insertions, 13 deletions
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);
}
OpenPOWER on IntegriCloud