diff options
author | Michael Shalayeff <mickey@cvs.openbsd.org> | 2006-09-26 09:26:37 +0000 |
---|---|---|
committer | Michael Shalayeff <mickey@cvs.openbsd.org> | 2006-09-26 09:26:37 +0000 |
commit | e63911418ab1bbafa6fcb95fa0b2b6113f45716f (patch) | |
tree | 7b565518c94d71ec243651dc495a0dae9a7f240a /sys | |
parent | ca8def7ca229cfdf5da1c0327826f26943e0ac04 (diff) |
fix races w/ getdirtybuf() usage that can violate normal
softdep processing and temporarily create inconsistant
on-disk ffs state and as well abuse kmem.
pedro@ deraadt@ ok; tested by many
Diffstat (limited to 'sys')
-rw-r--r-- | sys/ufs/ffs/ffs_softdep.c | 25 |
1 files changed, 13 insertions, 12 deletions
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index b5768d78171..c233d151795 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ffs_softdep.c,v 1.73 2006/07/27 11:34:13 mickey Exp $ */ +/* $OpenBSD: ffs_softdep.c,v 1.74 2006/09/26 09:26:36 mickey Exp $ */ /* * Copyright 1998, 2000 Marshall Kirk McKusick. All Rights Reserved. @@ -2014,8 +2014,9 @@ softdep_setup_freeblocks(ip, length) vp = ITOV(ip); ACQUIRE_LOCK(&lk); drain_output(vp, 1); - while (getdirtybuf(&LIST_FIRST(&vp->v_dirtyblkhd), MNT_WAIT)) { - bp = LIST_FIRST(&vp->v_dirtyblkhd); + while ((bp = LIST_FIRST(&vp->v_dirtyblkhd))) { + if (!getdirtybuf(&bp, MNT_WAIT)) + break; (void) inodedep_lookup(fs, ip->i_number, 0, &inodedep); deallocate_dependencies(bp, inodedep); bp->b_flags |= B_INVAL | B_NOCACHE; @@ -4485,10 +4486,10 @@ softdep_update_inodeblock(ip, bp, waitfor) FREE_LOCK(&lk); return; } - gotit = getdirtybuf(&inodedep->id_buf, MNT_WAIT); + bp = inodedep->id_buf; + gotit = getdirtybuf(&bp, MNT_WAIT); FREE_LOCK(&lk); - if (gotit && - (error = bwrite(inodedep->id_buf)) != 0) + if (gotit && (error = bwrite(bp)) != 0) softdep_error("softdep_update_inodeblock: bwrite", error); if ((inodedep->id_state & DEPCOMPLETE) == 0) panic("softdep_update_inodeblock: update failed"); @@ -4777,11 +4778,11 @@ top: * all potential buffers on the dirty list will be visible. */ drain_output(vp, 1); - if (getdirtybuf(&LIST_FIRST(&vp->v_dirtyblkhd), MNT_WAIT) == 0) { + bp = LIST_FIRST(&vp->v_dirtyblkhd); + if (getdirtybuf(&bp, MNT_WAIT) == 0) { FREE_LOCK(&lk); return (0); } - bp = LIST_FIRST(&vp->v_dirtyblkhd); loop: /* * As we hold the buffer locked, none of its dependencies @@ -4923,8 +4924,8 @@ loop: /* NOTREACHED */ } } - (void) getdirtybuf(&LIST_NEXT(bp, b_vnbufs), MNT_WAIT); nbp = LIST_NEXT(bp, b_vnbufs); + getdirtybuf(&nbp, MNT_WAIT); FREE_LOCK(&lk); bawrite(bp); ACQUIRE_LOCK(&lk); @@ -5160,10 +5161,10 @@ flush_pagedep_deps(pvp, mp, diraddhdp) * push them to disk. */ if ((inodedep->id_state & DEPCOMPLETE) == 0) { - gotit = getdirtybuf(&inodedep->id_buf, MNT_WAIT); + bp = inodedep->id_buf; + gotit = getdirtybuf(&bp, MNT_WAIT); FREE_LOCK(&lk); - if (gotit && - (error = bwrite(inodedep->id_buf)) != 0) + if (gotit && (error = bwrite(bp)) != 0) break; ACQUIRE_LOCK(&lk); if (dap != LIST_FIRST(diraddhdp)) |