This commit was generated by cvs2svn to compensate for changes in r36206,

which included commits to RCS files with non-trunk default branches.
This commit is contained in:
Julian Elischer 1998-05-19 20:03:29 +00:00
commit a697eb98d4
4 changed files with 472 additions and 264 deletions

View File

@ -1,12 +1,14 @@
/*
* Copyright 1997 Marshall Kirk McKusick. All Rights Reserved.
* Copyright 1998 Marshall Kirk McKusick. All Rights Reserved.
*
* The soft dependency code is derived from work done by Greg Ganger
* at the University of Michigan.
* The soft updates code is derived from the appendix of a University
* of Michigan technical report (Gregory R. Ganger and Yale N. Patt,
* "Soft Updates: A Solution to the Metadata Update Problem in File
* Systems", CSE-TR-254-95, August 1995).
*
* The following are the copyrights and redistribution conditions that
* apply to this copy of the soft dependency software. For a license
* to use, redistribute or sell the soft dependency software under
* apply to this copy of the soft update software. For a license
* to use, redistribute or sell the soft update software under
* conditions other than those described here, please contact the
* author at one of the following addresses:
*
@ -24,12 +26,12 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. None of the names of McKusick, Ganger, or the University of Michigan
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. None of the names of McKusick, Ganger, Patt, or the University of
* Michigan may be used to endorse or promote products derived from
* this software without specific prior written permission.
* 4. Redistributions in any form must be accompanied by information on
* how to obtain complete source code for any accompanying software
* that uses the this software. This source code must either be included
* that uses this software. This source code must either be included
* in the distribution or be available for no more than the cost of
* distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete
@ -50,17 +52,30 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_softdep.c 9.1 (McKusick) 7/9/97
*
* from: @(#)ffs_softdep.c 9.14 (McKusick) 1/15/98
*/
/*
* For now we want the safety net that the DIAGNOSTIC and DEBUG flags provide.
*/
#ifndef DIAGNOSTIC
#define DIAGNOSTIC
#endif
#ifndef DEBUG
#define DEBUG
#endif
#include <sys/param.h>
#include <sys/buf.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/syslog.h>
#include <sys/systm.h>
#include <sys/vnode.h>
#include <machine/pcpu.h>
#include <miscfs/specfs/specdev.h>
#include <ufs/ufs/dir.h>
#include <ufs/ufs/quota.h>
@ -76,7 +91,8 @@
*/
static void softdep_error __P((char *, int));
static int getdirtybuf __P((struct buf **, int));
static int flush_pagedep_deps __P((struct vnode *, struct pagedep *));
static int flush_pagedep_deps __P((struct vnode *, struct mount *,
struct diraddhd *));
static int flush_inodedep_deps __P((struct fs *, ino_t));
static int handle_written_filepage __P((struct pagedep *, struct buf *));
static int handle_written_inodeblock __P((struct inodedep *, struct buf *));
@ -147,14 +163,15 @@ extern char *memname[];
* the spl, there is nothing that really needs to be done.
*/
#ifndef /* NOT */ DEBUG
static int lk;
#define ACQUIRE_LOCK(lk) *lk = splbio()
#define FREE_LOCK(lk) splx(*lk)
static struct lockit {
int lkt_spl;
} lk = { 0 };
#define ACQUIRE_LOCK(lk) (lk)->lkt_spl = splbio()
#define FREE_LOCK(lk) splx((lk)->lkt_spl)
#define ACQUIRE_LOCK_INTERLOCKED(lk)
#define FREE_LOCK_INTERLOCKED(lk)
#else /* DEBUG */
#include <sys/proc.h>
static struct lockit {
int lkt_spl;
pid_t lkt_held;
@ -293,11 +310,11 @@ sema_release(semap)
*/
#ifndef /* NOT */ DEBUG
#define WORKLIST_INSERT(head, item) do { \
item->wk_state |= ONWORKLIST; \
(item)->wk_state |= ONWORKLIST; \
LIST_INSERT_HEAD(head, item, wk_list); \
} while (0)
#define WORKLIST_REMOVE(item) do { \
item->wk_state &= ~ONWORKLIST; \
(item)->wk_state &= ~ONWORKLIST; \
LIST_REMOVE(item, wk_list); \
} while (0)
#define WORKITEM_FREE(item, type) FREE(item, type)
@ -507,8 +524,16 @@ softdep_flushfiles(oldmnt, flags, p)
break;
}
softdep_worklist_busy = 0;
if (loopcnt == 0)
panic("softdep_flushfiles: looping");
/*
* If we are unmounting then it is an error to fail. If we
* are simply trying to downgrade to read-only, then filesystem
* activity can keep us busy forever, so we just fail with EBUSY.
*/
if (loopcnt == 0) {
if (oldmnt->mnt_flag & MNT_UNMOUNT)
panic("softdep_flushfiles: looping");
error = EBUSY;
}
return (error);
}
@ -542,7 +567,8 @@ softdep_flushfiles(oldmnt, flags, p)
LIST_HEAD(pagedep_hashhead, pagedep) *pagedep_hashtbl;
u_long pagedep_hash; /* size of hash table - 1 */
#define PAGEDEP_HASH(mp, inum, lbn) \
(&pagedep_hashtbl[((((int)(mp)) >> 13) + (inum) + (lbn)) & pagedep_hash])
(&pagedep_hashtbl[((((register_t)(mp)) >> 13) + (inum) + (lbn)) & \
pagedep_hash])
static struct sema pagedep_in_progress;
/*
@ -612,7 +638,7 @@ pagedep_lookup(ip, lbn, flags, pagedeppp)
LIST_HEAD(inodedep_hashhead, inodedep) *inodedep_hashtbl;
u_long inodedep_hash; /* size of hash table - 1 */
#define INODEDEP_HASH(fs, inum) \
(&inodedep_hashtbl[((((int)(fs)) >> 13) + (inum)) & inodedep_hash])
(&inodedep_hashtbl[((((register_t)(fs)) >> 13) + (inum)) & inodedep_hash])
static struct sema inodedep_in_progress;
/*
@ -680,7 +706,7 @@ inodedep_lookup(fs, inum, flags, inodedeppp)
LIST_HEAD(newblk_hashhead, newblk) *newblk_hashtbl;
u_long newblk_hash; /* size of hash table - 1 */
#define NEWBLK_HASH(fs, inum) \
(&newblk_hashtbl[((((int)(fs)) >> 13) + (inum)) & newblk_hash])
(&newblk_hashtbl[((((register_t)(fs)) >> 13) + (inum)) & newblk_hash])
static struct sema newblk_in_progress;
/*
@ -735,11 +761,13 @@ softdep_initialize()
LIST_INIT(&mkdirlisthd);
LIST_INIT(&softdep_workitem_pending);
pagedep_hashtbl = hashinit(desiredvnodes * 2, M_PAGEDEP, &pagedep_hash);
pagedep_hashtbl = hashinit(desiredvnodes / 10, M_PAGEDEP,
&pagedep_hash);
sema_init(&pagedep_in_progress, "pagedep", PRIBIO, 0);
inodedep_hashtbl = hashinit(desiredvnodes, M_INODEDEP, &inodedep_hash);
inodedep_hashtbl = hashinit(desiredvnodes / 2, M_INODEDEP,
&inodedep_hash);
sema_init(&inodedep_in_progress, "inodedep", PRIBIO, 0);
newblk_hashtbl = hashinit(desiredvnodes / 10, M_NEWBLK, &newblk_hash);
newblk_hashtbl = hashinit(64, M_NEWBLK, &newblk_hash);
sema_init(&newblk_in_progress, "newblk", PRIBIO, 0);
}
@ -1683,12 +1711,12 @@ free_inodedep(inodedep)
{
if ((inodedep->id_state & ONWORKLIST) != 0 ||
(inodedep->id_state & ALLCOMPLETE) != ALLCOMPLETE ||
LIST_FIRST(&inodedep->id_pendinghd) != NULL ||
LIST_FIRST(&inodedep->id_inowait) != NULL ||
TAILQ_FIRST(&inodedep->id_inoupdt) != NULL ||
TAILQ_FIRST(&inodedep->id_newinoupdt) != NULL ||
inodedep->id_nlinkdelta != 0 || inodedep->id_buf != NULL ||
inodedep->id_savedino != NULL)
inodedep->id_nlinkdelta != 0 || inodedep->id_savedino != NULL)
return (0);
LIST_REMOVE(inodedep, id_hash);
WORKITEM_FREE(inodedep, M_INODEDEP);
@ -2001,17 +2029,18 @@ softdep_change_directoryentry_offset(dp, base, oldloc, newloc, entrysize)
caddr_t newloc; /* address of new directory location */
int entrysize; /* size of directory entry */
{
int oldoffset, newoffset;
int offset, oldoffset, newoffset;
struct pagedep *pagedep;
struct diradd *dap;
ufs_lbn_t lbn;
ACQUIRE_LOCK(&lk);
lbn = lblkno(dp->i_fs, dp->i_offset);
offset = blkoff(dp->i_fs, dp->i_offset);
if (pagedep_lookup(dp, lbn, 0, &pagedep) == 0)
goto done;
oldoffset = dp->i_offset + (oldloc - base);
newoffset = dp->i_offset + (newloc - base);
oldoffset = offset + (oldloc - base);
newoffset = offset + (newloc - base);
for (dap = LIST_FIRST(&pagedep->pd_diraddhd[DIRADDHASH(oldoffset)]);
dap; dap = LIST_NEXT(dap, da_pdlist)) {
if (dap->da_offset != oldoffset)
@ -2053,7 +2082,7 @@ free_diradd(dap)
} else {
dirrem = dap->da_previous;
pagedep = dirrem->dm_pagedep;
LIST_INSERT_HEAD(&pagedep->pd_dirremhd, dirrem, dm_next);
add_to_worklist(&dirrem->dm_list);
}
if (inodedep_lookup(VFSTOUFS(pagedep->pd_mnt)->um_fs, dap->da_newinum,
0, &inodedep) != 0)
@ -2125,6 +2154,7 @@ newdirrem(bp, dp, ip, isrmdir)
struct inode *ip; /* inode for directory entry being removed */
int isrmdir; /* indicates if doing RMDIR */
{
int offset;
ufs_lbn_t lbn;
struct diradd *dap;
struct dirrem *dirrem;
@ -2145,17 +2175,18 @@ newdirrem(bp, dp, ip, isrmdir)
ACQUIRE_LOCK(&lk);
lbn = lblkno(dp->i_fs, dp->i_offset);
offset = blkoff(dp->i_fs, dp->i_offset);
if (pagedep_lookup(dp, lbn, DEPALLOC, &pagedep) == 0)
WORKLIST_INSERT(&bp->b_dep, &pagedep->pd_list);
dirrem->dm_pagedep = pagedep;
for (dap = LIST_FIRST(&pagedep->pd_diraddhd[DIRADDHASH(dp->i_offset)]);
for (dap = LIST_FIRST(&pagedep->pd_diraddhd[DIRADDHASH(offset)]);
dap; dap = LIST_NEXT(dap, da_pdlist)) {
/*
* Check for a diradd dependency for the same directory entry.
* If present, then both dependencies become obsolete and can
* be de-allocated.
*/
if (dap->da_offset != dp->i_offset)
if (dap->da_offset != offset)
continue;
/*
* Must be ATTACHED at this point, so just delete it.
@ -2291,8 +2322,12 @@ handle_workitem_remove(dirrem)
*/
if ((dirrem->dm_state & RMDIR) == 0) {
ip->i_nlink--;
if (ip->i_nlink < ip->i_effnlink)
panic("handle_workitem_remove: bad file delta");
if (ip->i_nlink < ip->i_effnlink) {
#ifdef DIAGNOSTIC
vprint("handle_workitem_remove: bad file delta", vp);
#endif
ip->i_effnlink = ip->i_nlink;
}
ip->i_flag |= IN_CHANGE;
vput(vp);
WORKITEM_FREE(dirrem, M_DIRREM);
@ -2820,10 +2855,6 @@ handle_allocdirect_partdone(adp)
return;
free_allocdirect(&inodedep->id_inoupdt, adp, 1);
}
/*
* Try freeing the inodedep in case that was the last dependency.
*/
(void) free_inodedep(inodedep);
}
/*
@ -3110,8 +3141,7 @@ handle_written_filepage(pagedep, bp)
* Otherwise it will remain to update the page before it
* is written back to disk.
*/
if (LIST_FIRST(&pagedep->pd_dirremhd) == 0 &&
LIST_FIRST(&pagedep->pd_pendinghd) == 0) {
if (LIST_FIRST(&pagedep->pd_pendinghd) == 0) {
for (i = 0; i < DAHASHSZ; i++)
if (LIST_FIRST(&pagedep->pd_diraddhd[i]) != NULL)
break;
@ -3314,7 +3344,7 @@ softdep_fsync(vp)
if ((wk = LIST_FIRST(&inodedep->id_pendinghd)) == NULL)
break;
if (wk->wk_type != M_DIRADD)
panic("softdep_fsync: Unexpcted type %s",
panic("softdep_fsync: Unexpected type %s",
TYPENAME(wk->wk_type));
dap = WK_DIRADD(wk);
/*
@ -3401,11 +3431,12 @@ softdep_sync_metadata(ap)
} */ *ap;
{
struct vnode *vp = ap->a_vp;
struct pagedep *pagedep;
struct allocdirect *adp;
struct allocindir *aip;
struct buf *bp, *nbp;
struct worklist *wk;
int error, waitfor;
int i, error, waitfor;
/*
* Check whether this vnode is involved in a filesystem
@ -3494,22 +3525,21 @@ softdep_sync_metadata(ap)
break;
case M_INDIRDEP:
restart:
for (aip = LIST_FIRST(&WK_INDIRDEP(wk)->ir_deplisthd);
aip; aip = LIST_NEXT(aip, ai_next)) {
if (aip->ai_state & DEPCOMPLETE)
continue;
nbp = aip->ai_buf;
if (getdirtybuf(&nbp, waitfor) == 0)
break;
if (getdirtybuf(&nbp, MNT_WAIT) == 0)
goto restart;
FREE_LOCK(&lk);
if (waitfor == MNT_NOWAIT) {
bawrite(nbp);
} else if ((error = VOP_BWRITE(nbp)) != 0) {
if ((error = VOP_BWRITE(nbp)) != 0) {
bawrite(bp);
return (error);
}
ACQUIRE_LOCK(&lk);
continue;
goto restart;
}
break;
@ -3530,10 +3560,16 @@ softdep_sync_metadata(ap)
* recently allocated files. We walk its diradd
* lists pushing out the associated inode.
*/
if (error = flush_pagedep_deps(vp, WK_PAGEDEP(wk))) {
FREE_LOCK(&lk);
bawrite(bp);
return (error);
pagedep = WK_PAGEDEP(wk);
for (i = 0; i < DAHASHSZ; i++) {
if (LIST_FIRST(&pagedep->pd_diraddhd[i]) == 0)
continue;
if (error = flush_pagedep_deps(vp,
pagedep->pd_mnt, &pagedep->pd_diraddhd[i])) {
FREE_LOCK(&lk);
bawrite(bp);
return (error);
}
}
break;
@ -3690,83 +3726,123 @@ flush_inodedep_deps(fs, ino)
* Called with splbio blocked.
*/
static int
flush_pagedep_deps(pvp, pagedep)
flush_pagedep_deps(pvp, mp, diraddhdp)
struct vnode *pvp;
struct pagedep *pagedep;
struct mount *mp;
struct diraddhd *diraddhdp;
{
struct proc *p = curproc; /* XXX */
struct inodedep *inodedep;
struct ufsmount *ump;
struct diradd *dap;
struct timeval tv;
struct vnode *vp;
int i, error;
int gotit, error;
struct buf *bp;
ino_t inum;
for (i = 0, error = 0; i < DAHASHSZ && error == 0; i++) {
while ((dap = LIST_FIRST(&pagedep->pd_diraddhd[i])) != NULL) {
/*
* Flush ourselves if this directory entry
* has a MKDIR_PARENT dependency.
*/
if (dap->da_state & MKDIR_PARENT) {
tv = time;
FREE_LOCK(&lk);
if (error = VOP_UPDATE(pvp, &tv, &tv, MNT_WAIT))
break;
ACQUIRE_LOCK(&lk);
/*
* If that cleared dependencies, go on to next.
*/
if (dap != LIST_FIRST(&pagedep->pd_diraddhd[i]))
continue;
if (dap->da_state & MKDIR_PARENT)
panic("flush_pagedep_deps: MKDIR");
}
/*
* Flush the file on which the directory entry depends.
*/
inum = dap->da_newinum;
FREE_LOCK(&lk);
if ((error = VFS_VGET(pagedep->pd_mnt, inum, &vp)) != 0)
break;
if (vp->v_type == VDIR) {
/*
* A newly allocated directory must have its
* "." and ".." entries written out before its
* name can be committed in its parent. We do
* not want or need the full semantics of a
* synchronous VOP_FSYNC as that may end up
* here again, once for each directory level in
* the filesystem. Instead, we push the blocks
* and wait for them to clear.
*/
if (error =
VOP_FSYNC(vp, p->p_cred, MNT_NOWAIT, p)) {
vput(vp);
break;
}
ACQUIRE_LOCK(&lk);
while (vp->v_numoutput) {
vp->v_flag |= VBWAIT;
FREE_LOCK_INTERLOCKED(&lk);
sleep((caddr_t)&vp->v_numoutput,
PRIBIO + 1);
ACQUIRE_LOCK_INTERLOCKED(&lk);
}
FREE_LOCK(&lk);
}
ump = VFSTOUFS(mp);
while ((dap = LIST_FIRST(diraddhdp)) != NULL) {
/*
* Flush ourselves if this directory entry
* has a MKDIR_PARENT dependency.
*/
if (dap->da_state & MKDIR_PARENT) {
tv = time;
error = VOP_UPDATE(vp, &tv, &tv, MNT_WAIT);
vput(vp);
if (error)
FREE_LOCK(&lk);
if (error = VOP_UPDATE(pvp, &tv, &tv, MNT_WAIT))
break;
/*
* If we have failed to get rid of all the dependencies
* then something is seriously wrong.
*/
if (dap == LIST_FIRST(&pagedep->pd_diraddhd[i]))
panic("flush_pagedep_deps: flush failed");
ACQUIRE_LOCK(&lk);
/*
* If that cleared dependencies, go on to next.
*/
if (dap != LIST_FIRST(diraddhdp))
continue;
if (dap->da_state & MKDIR_PARENT)
panic("flush_pagedep_deps: MKDIR");
}
/*
* Flush the file on which the directory entry depends.
* If the inode has already been pushed out of the cache,
* then all the block dependencies will have been flushed
* leaving only inode dependencies (e.g., bitmaps). Thus,
* we do a ufs_ihashget to check for the vnode in the cache.
* If it is there, we do a full flush. If it is no longer
* there we need only dispose of any remaining bitmap
* dependencies and write the inode to disk.
*/
inum = dap->da_newinum;
FREE_LOCK(&lk);
if ((vp = ufs_ihashget(ump->um_dev, inum)) == NULL) {
ACQUIRE_LOCK(&lk);
if (inodedep_lookup(ump->um_fs, inum, 0, &inodedep) == 0
&& dap == LIST_FIRST(diraddhdp))
panic("flush_pagedep_deps: flush 1 failed");
/*
* If the inode still has bitmap dependencies,
* push them to disk.
*/
if ((inodedep->id_state & DEPCOMPLETE) == 0) {
gotit = getdirtybuf(&inodedep->id_buf,MNT_WAIT);
FREE_LOCK(&lk);
if (gotit &&
(error = VOP_BWRITE(inodedep->id_buf)) != 0)
break;
ACQUIRE_LOCK(&lk);
}
if (dap != LIST_FIRST(diraddhdp))
continue;
/*
* If the inode is still sitting in a buffer waiting
* to be written, push it to disk.
*/
FREE_LOCK(&lk);
if ((error = bread(ump->um_devvp,
fsbtodb(ump->um_fs, ino_to_fsba(ump->um_fs, inum)),
(int)ump->um_fs->fs_bsize, NOCRED, &bp)) != 0)
break;
if ((error = VOP_BWRITE(bp)) != 0)
break;
ACQUIRE_LOCK(&lk);
if (dap == LIST_FIRST(diraddhdp))
panic("flush_pagedep_deps: flush 2 failed");
continue;
}
if (vp->v_type == VDIR) {
/*
* A newly allocated directory must have its "." and
* ".." entries written out before its name can be
* committed in its parent. We do not want or need
* the full semantics of a synchronous VOP_FSYNC as
* that may end up here again, once for each directory
* level in the filesystem. Instead, we push the blocks
* and wait for them to clear.
*/
if (error = VOP_FSYNC(vp, p->p_cred, MNT_NOWAIT, p)) {
vput(vp);
break;
}
ACQUIRE_LOCK(&lk);
while (vp->v_numoutput) {
vp->v_flag |= VBWAIT;
FREE_LOCK_INTERLOCKED(&lk);
sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
ACQUIRE_LOCK_INTERLOCKED(&lk);
}
FREE_LOCK(&lk);
}
tv = time;
error = VOP_UPDATE(vp, &tv, &tv, MNT_WAIT);
vput(vp);
if (error)
break;
/*
* If we have failed to get rid of all the dependencies
* then something is seriously wrong.
*/
if (dap == LIST_FIRST(diraddhdp))
panic("flush_pagedep_deps: flush 3 failed");
ACQUIRE_LOCK(&lk);
}
if (error)
ACQUIRE_LOCK(&lk);
@ -3818,22 +3894,38 @@ softdep_deallocate_dependencies(bp)
if ((bp->b_flags & B_ERROR) == 0)
panic("softdep_deallocate_dependencies: dangling deps");
softdep_error(bp->b_vp->v_mount->mnt_stat.f_mntonname, bp->b_error);
ACQUIRE_LOCK(&lk);
while ((wk = LIST_FIRST(&bp->b_dep)) != NULL) {
WORKLIST_REMOVE(wk);
FREE_LOCK(&lk);
switch (wk->wk_type) {
/*
* XXX - should really clean up, but for now we will
* just leak memory and not worry about it.
* just leak memory and not worry about it. Also should
* mark the filesystem permanently dirty so that it will
* force fsck to be run (though this would best be done
* in the mainline code).
*/
case M_PAGEDEP: case M_INDIRDEP: case M_INODEDEP:
case M_PAGEDEP:
case M_INODEDEP:
case M_BMSAFEMAP:
case M_ALLOCDIRECT:
case M_INDIRDEP:
case M_ALLOCINDIR:
case M_MKDIR:
#ifdef DEBUG
printf("Lost %s\n", TYPENAME(wk->wk_type));
printf("Lost type %s\n", TYPENAME(wk->wk_type));
#endif
break;
default:
panic("softdep_deallocate_dependencies: bad type");
panic("%s: Unexpected type %s",
"softdep_deallocate_dependencies",
TYPENAME(wk->wk_type));
/* NOTREACHED */
}
ACQUIRE_LOCK(&lk);
}
FREE_LOCK(&lk);
}
/*

View File

@ -1,12 +1,14 @@
/*
* Copyright 1997 Marshall Kirk McKusick. All Rights Reserved.
* Copyright 1998 Marshall Kirk McKusick. All Rights Reserved.
*
* The soft dependency code is derived from work done by Greg Ganger
* at the University of Michigan.
* The soft updates code is derived from the appendix of a University
* of Michigan technical report (Gregory R. Ganger and Yale N. Patt,
* "Soft Updates: A Solution to the Metadata Update Problem in File
* Systems", CSE-TR-254-95, August 1995).
*
* The following are the copyrights and redistribution conditions that
* apply to this copy of the soft dependency software. For a license
* to use, redistribute or sell the soft dependency software under
* apply to this copy of the soft update software. For a license
* to use, redistribute or sell the soft update software under
* conditions other than those described here, please contact the
* author at one of the following addresses:
*
@ -24,12 +26,12 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. None of the names of McKusick, Ganger, or the University of Michigan
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. None of the names of McKusick, Ganger, Patt, or the University of
* Michigan may be used to endorse or promote products derived from
* this software without specific prior written permission.
* 4. Redistributions in any form must be accompanied by information on
* how to obtain complete source code for any accompanying software
* that uses the this software. This source code must either be included
* that uses this software. This source code must either be included
* in the distribution or be available for no more than the cost of
* distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete
@ -50,7 +52,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)softdep.h 9.1 (McKusick) 7/9/97
*
* from: @(#)softdep.h 9.4 (McKusick) 1/15/98
*/
#include <sys/queue.h>
@ -220,6 +223,15 @@ struct pagedep {
* The entries on the id_inoupdt and id_newinoupdt lists must be kept
* sorted by logical block number to speed the calculation of the size
* of the rolled back inode (see explanation in initiate_write_inodeblock).
* When a directory entry is created, it is represented by a diradd.
* The diradd is added to the id_inowait list and is not permitted to be
* written to disk until the inode that it represents is written. After
* the inode is written, the id_inowait list is processed and the diradd
* entries are moved to the id_pendinghd list where they remain until
* the directory block containing the name has been written to disk.
* The purpose of keeping the entries on the id_pendinghd list is so that
* the softdep_fsync function can find and push the inode's directory
* name(s) as part of the fsync operation for that file.
*/
struct inodedep {
struct worklist id_list; /* buffer holding inode block */

View File

@ -1,12 +1,14 @@
/*
* Copyright 1997 Marshall Kirk McKusick. All Rights Reserved.
* Copyright 1998 Marshall Kirk McKusick. All Rights Reserved.
*
* The soft dependency code is derived from work done by Greg Ganger
* at the University of Michigan.
* The soft updates code is derived from the appendix of a University
* of Michigan technical report (Gregory R. Ganger and Yale N. Patt,
* "Soft Updates: A Solution to the Metadata Update Problem in File
* Systems", CSE-TR-254-95, August 1995).
*
* The following are the copyrights and redistribution conditions that
* apply to this copy of the soft dependency software. For a license
* to use, redistribute or sell the soft dependency software under
* apply to this copy of the soft update software. For a license
* to use, redistribute or sell the soft update software under
* conditions other than those described here, please contact the
* author at one of the following addresses:
*
@ -24,12 +26,12 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. None of the names of McKusick, Ganger, or the University of Michigan
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. None of the names of McKusick, Ganger, Patt, or the University of
* Michigan may be used to endorse or promote products derived from
* this software without specific prior written permission.
* 4. Redistributions in any form must be accompanied by information on
* how to obtain complete source code for any accompanying software
* that uses the this software. This source code must either be included
* that uses this software. This source code must either be included
* in the distribution or be available for no more than the cost of
* distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete
@ -50,17 +52,30 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ffs_softdep.c 9.1 (McKusick) 7/9/97
*
* from: @(#)ffs_softdep.c 9.14 (McKusick) 1/15/98
*/
/*
* For now we want the safety net that the DIAGNOSTIC and DEBUG flags provide.
*/
#ifndef DIAGNOSTIC
#define DIAGNOSTIC
#endif
#ifndef DEBUG
#define DEBUG
#endif
#include <sys/param.h>
#include <sys/buf.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/syslog.h>
#include <sys/systm.h>
#include <sys/vnode.h>
#include <machine/pcpu.h>
#include <miscfs/specfs/specdev.h>
#include <ufs/ufs/dir.h>
#include <ufs/ufs/quota.h>
@ -76,7 +91,8 @@
*/
static void softdep_error __P((char *, int));
static int getdirtybuf __P((struct buf **, int));
static int flush_pagedep_deps __P((struct vnode *, struct pagedep *));
static int flush_pagedep_deps __P((struct vnode *, struct mount *,
struct diraddhd *));
static int flush_inodedep_deps __P((struct fs *, ino_t));
static int handle_written_filepage __P((struct pagedep *, struct buf *));
static int handle_written_inodeblock __P((struct inodedep *, struct buf *));
@ -147,14 +163,15 @@ extern char *memname[];
* the spl, there is nothing that really needs to be done.
*/
#ifndef /* NOT */ DEBUG
static int lk;
#define ACQUIRE_LOCK(lk) *lk = splbio()
#define FREE_LOCK(lk) splx(*lk)
static struct lockit {
int lkt_spl;
} lk = { 0 };
#define ACQUIRE_LOCK(lk) (lk)->lkt_spl = splbio()
#define FREE_LOCK(lk) splx((lk)->lkt_spl)
#define ACQUIRE_LOCK_INTERLOCKED(lk)
#define FREE_LOCK_INTERLOCKED(lk)
#else /* DEBUG */
#include <sys/proc.h>
static struct lockit {
int lkt_spl;
pid_t lkt_held;
@ -293,11 +310,11 @@ sema_release(semap)
*/
#ifndef /* NOT */ DEBUG
#define WORKLIST_INSERT(head, item) do { \
item->wk_state |= ONWORKLIST; \
(item)->wk_state |= ONWORKLIST; \
LIST_INSERT_HEAD(head, item, wk_list); \
} while (0)
#define WORKLIST_REMOVE(item) do { \
item->wk_state &= ~ONWORKLIST; \
(item)->wk_state &= ~ONWORKLIST; \
LIST_REMOVE(item, wk_list); \
} while (0)
#define WORKITEM_FREE(item, type) FREE(item, type)
@ -507,8 +524,16 @@ softdep_flushfiles(oldmnt, flags, p)
break;
}
softdep_worklist_busy = 0;
if (loopcnt == 0)
panic("softdep_flushfiles: looping");
/*
* If we are unmounting then it is an error to fail. If we
* are simply trying to downgrade to read-only, then filesystem
* activity can keep us busy forever, so we just fail with EBUSY.
*/
if (loopcnt == 0) {
if (oldmnt->mnt_flag & MNT_UNMOUNT)
panic("softdep_flushfiles: looping");
error = EBUSY;
}
return (error);
}
@ -542,7 +567,8 @@ softdep_flushfiles(oldmnt, flags, p)
LIST_HEAD(pagedep_hashhead, pagedep) *pagedep_hashtbl;
u_long pagedep_hash; /* size of hash table - 1 */
#define PAGEDEP_HASH(mp, inum, lbn) \
(&pagedep_hashtbl[((((int)(mp)) >> 13) + (inum) + (lbn)) & pagedep_hash])
(&pagedep_hashtbl[((((register_t)(mp)) >> 13) + (inum) + (lbn)) & \
pagedep_hash])
static struct sema pagedep_in_progress;
/*
@ -612,7 +638,7 @@ pagedep_lookup(ip, lbn, flags, pagedeppp)
LIST_HEAD(inodedep_hashhead, inodedep) *inodedep_hashtbl;
u_long inodedep_hash; /* size of hash table - 1 */
#define INODEDEP_HASH(fs, inum) \
(&inodedep_hashtbl[((((int)(fs)) >> 13) + (inum)) & inodedep_hash])
(&inodedep_hashtbl[((((register_t)(fs)) >> 13) + (inum)) & inodedep_hash])
static struct sema inodedep_in_progress;
/*
@ -680,7 +706,7 @@ inodedep_lookup(fs, inum, flags, inodedeppp)
LIST_HEAD(newblk_hashhead, newblk) *newblk_hashtbl;
u_long newblk_hash; /* size of hash table - 1 */
#define NEWBLK_HASH(fs, inum) \
(&newblk_hashtbl[((((int)(fs)) >> 13) + (inum)) & newblk_hash])
(&newblk_hashtbl[((((register_t)(fs)) >> 13) + (inum)) & newblk_hash])
static struct sema newblk_in_progress;
/*
@ -735,11 +761,13 @@ softdep_initialize()
LIST_INIT(&mkdirlisthd);
LIST_INIT(&softdep_workitem_pending);
pagedep_hashtbl = hashinit(desiredvnodes * 2, M_PAGEDEP, &pagedep_hash);
pagedep_hashtbl = hashinit(desiredvnodes / 10, M_PAGEDEP,
&pagedep_hash);
sema_init(&pagedep_in_progress, "pagedep", PRIBIO, 0);
inodedep_hashtbl = hashinit(desiredvnodes, M_INODEDEP, &inodedep_hash);
inodedep_hashtbl = hashinit(desiredvnodes / 2, M_INODEDEP,
&inodedep_hash);
sema_init(&inodedep_in_progress, "inodedep", PRIBIO, 0);
newblk_hashtbl = hashinit(desiredvnodes / 10, M_NEWBLK, &newblk_hash);
newblk_hashtbl = hashinit(64, M_NEWBLK, &newblk_hash);
sema_init(&newblk_in_progress, "newblk", PRIBIO, 0);
}
@ -1683,12 +1711,12 @@ free_inodedep(inodedep)
{
if ((inodedep->id_state & ONWORKLIST) != 0 ||
(inodedep->id_state & ALLCOMPLETE) != ALLCOMPLETE ||
LIST_FIRST(&inodedep->id_pendinghd) != NULL ||
LIST_FIRST(&inodedep->id_inowait) != NULL ||
TAILQ_FIRST(&inodedep->id_inoupdt) != NULL ||
TAILQ_FIRST(&inodedep->id_newinoupdt) != NULL ||
inodedep->id_nlinkdelta != 0 || inodedep->id_buf != NULL ||
inodedep->id_savedino != NULL)
inodedep->id_nlinkdelta != 0 || inodedep->id_savedino != NULL)
return (0);
LIST_REMOVE(inodedep, id_hash);
WORKITEM_FREE(inodedep, M_INODEDEP);
@ -2001,17 +2029,18 @@ softdep_change_directoryentry_offset(dp, base, oldloc, newloc, entrysize)
caddr_t newloc; /* address of new directory location */
int entrysize; /* size of directory entry */
{
int oldoffset, newoffset;
int offset, oldoffset, newoffset;
struct pagedep *pagedep;
struct diradd *dap;
ufs_lbn_t lbn;
ACQUIRE_LOCK(&lk);
lbn = lblkno(dp->i_fs, dp->i_offset);
offset = blkoff(dp->i_fs, dp->i_offset);
if (pagedep_lookup(dp, lbn, 0, &pagedep) == 0)
goto done;
oldoffset = dp->i_offset + (oldloc - base);
newoffset = dp->i_offset + (newloc - base);
oldoffset = offset + (oldloc - base);
newoffset = offset + (newloc - base);
for (dap = LIST_FIRST(&pagedep->pd_diraddhd[DIRADDHASH(oldoffset)]);
dap; dap = LIST_NEXT(dap, da_pdlist)) {
if (dap->da_offset != oldoffset)
@ -2053,7 +2082,7 @@ free_diradd(dap)
} else {
dirrem = dap->da_previous;
pagedep = dirrem->dm_pagedep;
LIST_INSERT_HEAD(&pagedep->pd_dirremhd, dirrem, dm_next);
add_to_worklist(&dirrem->dm_list);
}
if (inodedep_lookup(VFSTOUFS(pagedep->pd_mnt)->um_fs, dap->da_newinum,
0, &inodedep) != 0)
@ -2125,6 +2154,7 @@ newdirrem(bp, dp, ip, isrmdir)
struct inode *ip; /* inode for directory entry being removed */
int isrmdir; /* indicates if doing RMDIR */
{
int offset;
ufs_lbn_t lbn;
struct diradd *dap;
struct dirrem *dirrem;
@ -2145,17 +2175,18 @@ newdirrem(bp, dp, ip, isrmdir)
ACQUIRE_LOCK(&lk);
lbn = lblkno(dp->i_fs, dp->i_offset);
offset = blkoff(dp->i_fs, dp->i_offset);
if (pagedep_lookup(dp, lbn, DEPALLOC, &pagedep) == 0)
WORKLIST_INSERT(&bp->b_dep, &pagedep->pd_list);
dirrem->dm_pagedep = pagedep;
for (dap = LIST_FIRST(&pagedep->pd_diraddhd[DIRADDHASH(dp->i_offset)]);
for (dap = LIST_FIRST(&pagedep->pd_diraddhd[DIRADDHASH(offset)]);
dap; dap = LIST_NEXT(dap, da_pdlist)) {
/*
* Check for a diradd dependency for the same directory entry.
* If present, then both dependencies become obsolete and can
* be de-allocated.
*/
if (dap->da_offset != dp->i_offset)
if (dap->da_offset != offset)
continue;
/*
* Must be ATTACHED at this point, so just delete it.
@ -2291,8 +2322,12 @@ handle_workitem_remove(dirrem)
*/
if ((dirrem->dm_state & RMDIR) == 0) {
ip->i_nlink--;
if (ip->i_nlink < ip->i_effnlink)
panic("handle_workitem_remove: bad file delta");
if (ip->i_nlink < ip->i_effnlink) {
#ifdef DIAGNOSTIC
vprint("handle_workitem_remove: bad file delta", vp);
#endif
ip->i_effnlink = ip->i_nlink;
}
ip->i_flag |= IN_CHANGE;
vput(vp);
WORKITEM_FREE(dirrem, M_DIRREM);
@ -2820,10 +2855,6 @@ handle_allocdirect_partdone(adp)
return;
free_allocdirect(&inodedep->id_inoupdt, adp, 1);
}
/*
* Try freeing the inodedep in case that was the last dependency.
*/
(void) free_inodedep(inodedep);
}
/*
@ -3110,8 +3141,7 @@ handle_written_filepage(pagedep, bp)
* Otherwise it will remain to update the page before it
* is written back to disk.
*/
if (LIST_FIRST(&pagedep->pd_dirremhd) == 0 &&
LIST_FIRST(&pagedep->pd_pendinghd) == 0) {
if (LIST_FIRST(&pagedep->pd_pendinghd) == 0) {
for (i = 0; i < DAHASHSZ; i++)
if (LIST_FIRST(&pagedep->pd_diraddhd[i]) != NULL)
break;
@ -3314,7 +3344,7 @@ softdep_fsync(vp)
if ((wk = LIST_FIRST(&inodedep->id_pendinghd)) == NULL)
break;
if (wk->wk_type != M_DIRADD)
panic("softdep_fsync: Unexpcted type %s",
panic("softdep_fsync: Unexpected type %s",
TYPENAME(wk->wk_type));
dap = WK_DIRADD(wk);
/*
@ -3401,11 +3431,12 @@ softdep_sync_metadata(ap)
} */ *ap;
{
struct vnode *vp = ap->a_vp;
struct pagedep *pagedep;
struct allocdirect *adp;
struct allocindir *aip;
struct buf *bp, *nbp;
struct worklist *wk;
int error, waitfor;
int i, error, waitfor;
/*
* Check whether this vnode is involved in a filesystem
@ -3494,22 +3525,21 @@ softdep_sync_metadata(ap)
break;
case M_INDIRDEP:
restart:
for (aip = LIST_FIRST(&WK_INDIRDEP(wk)->ir_deplisthd);
aip; aip = LIST_NEXT(aip, ai_next)) {
if (aip->ai_state & DEPCOMPLETE)
continue;
nbp = aip->ai_buf;
if (getdirtybuf(&nbp, waitfor) == 0)
break;
if (getdirtybuf(&nbp, MNT_WAIT) == 0)
goto restart;
FREE_LOCK(&lk);
if (waitfor == MNT_NOWAIT) {
bawrite(nbp);
} else if ((error = VOP_BWRITE(nbp)) != 0) {
if ((error = VOP_BWRITE(nbp)) != 0) {
bawrite(bp);
return (error);
}
ACQUIRE_LOCK(&lk);
continue;
goto restart;
}
break;
@ -3530,10 +3560,16 @@ softdep_sync_metadata(ap)
* recently allocated files. We walk its diradd
* lists pushing out the associated inode.
*/
if (error = flush_pagedep_deps(vp, WK_PAGEDEP(wk))) {
FREE_LOCK(&lk);
bawrite(bp);
return (error);
pagedep = WK_PAGEDEP(wk);
for (i = 0; i < DAHASHSZ; i++) {
if (LIST_FIRST(&pagedep->pd_diraddhd[i]) == 0)
continue;
if (error = flush_pagedep_deps(vp,
pagedep->pd_mnt, &pagedep->pd_diraddhd[i])) {
FREE_LOCK(&lk);
bawrite(bp);
return (error);
}
}
break;
@ -3690,83 +3726,123 @@ flush_inodedep_deps(fs, ino)
* Called with splbio blocked.
*/
static int
flush_pagedep_deps(pvp, pagedep)
flush_pagedep_deps(pvp, mp, diraddhdp)
struct vnode *pvp;
struct pagedep *pagedep;
struct mount *mp;
struct diraddhd *diraddhdp;
{
struct proc *p = curproc; /* XXX */
struct inodedep *inodedep;
struct ufsmount *ump;
struct diradd *dap;
struct timeval tv;
struct vnode *vp;
int i, error;
int gotit, error;
struct buf *bp;
ino_t inum;
for (i = 0, error = 0; i < DAHASHSZ && error == 0; i++) {
while ((dap = LIST_FIRST(&pagedep->pd_diraddhd[i])) != NULL) {
/*
* Flush ourselves if this directory entry
* has a MKDIR_PARENT dependency.
*/
if (dap->da_state & MKDIR_PARENT) {
tv = time;
FREE_LOCK(&lk);
if (error = VOP_UPDATE(pvp, &tv, &tv, MNT_WAIT))
break;
ACQUIRE_LOCK(&lk);
/*
* If that cleared dependencies, go on to next.
*/
if (dap != LIST_FIRST(&pagedep->pd_diraddhd[i]))
continue;
if (dap->da_state & MKDIR_PARENT)
panic("flush_pagedep_deps: MKDIR");
}
/*
* Flush the file on which the directory entry depends.
*/
inum = dap->da_newinum;
FREE_LOCK(&lk);
if ((error = VFS_VGET(pagedep->pd_mnt, inum, &vp)) != 0)
break;
if (vp->v_type == VDIR) {
/*
* A newly allocated directory must have its
* "." and ".." entries written out before its
* name can be committed in its parent. We do
* not want or need the full semantics of a
* synchronous VOP_FSYNC as that may end up
* here again, once for each directory level in
* the filesystem. Instead, we push the blocks
* and wait for them to clear.
*/
if (error =
VOP_FSYNC(vp, p->p_cred, MNT_NOWAIT, p)) {
vput(vp);
break;
}
ACQUIRE_LOCK(&lk);
while (vp->v_numoutput) {
vp->v_flag |= VBWAIT;
FREE_LOCK_INTERLOCKED(&lk);
sleep((caddr_t)&vp->v_numoutput,
PRIBIO + 1);
ACQUIRE_LOCK_INTERLOCKED(&lk);
}
FREE_LOCK(&lk);
}
ump = VFSTOUFS(mp);
while ((dap = LIST_FIRST(diraddhdp)) != NULL) {
/*
* Flush ourselves if this directory entry
* has a MKDIR_PARENT dependency.
*/
if (dap->da_state & MKDIR_PARENT) {
tv = time;
error = VOP_UPDATE(vp, &tv, &tv, MNT_WAIT);
vput(vp);
if (error)
FREE_LOCK(&lk);
if (error = VOP_UPDATE(pvp, &tv, &tv, MNT_WAIT))
break;
/*
* If we have failed to get rid of all the dependencies
* then something is seriously wrong.
*/
if (dap == LIST_FIRST(&pagedep->pd_diraddhd[i]))
panic("flush_pagedep_deps: flush failed");
ACQUIRE_LOCK(&lk);
/*
* If that cleared dependencies, go on to next.
*/
if (dap != LIST_FIRST(diraddhdp))
continue;
if (dap->da_state & MKDIR_PARENT)
panic("flush_pagedep_deps: MKDIR");
}
/*
* Flush the file on which the directory entry depends.
* If the inode has already been pushed out of the cache,
* then all the block dependencies will have been flushed
* leaving only inode dependencies (e.g., bitmaps). Thus,
* we do a ufs_ihashget to check for the vnode in the cache.
* If it is there, we do a full flush. If it is no longer
* there we need only dispose of any remaining bitmap
* dependencies and write the inode to disk.
*/
inum = dap->da_newinum;
FREE_LOCK(&lk);
if ((vp = ufs_ihashget(ump->um_dev, inum)) == NULL) {
ACQUIRE_LOCK(&lk);
if (inodedep_lookup(ump->um_fs, inum, 0, &inodedep) == 0
&& dap == LIST_FIRST(diraddhdp))
panic("flush_pagedep_deps: flush 1 failed");
/*
* If the inode still has bitmap dependencies,
* push them to disk.
*/
if ((inodedep->id_state & DEPCOMPLETE) == 0) {
gotit = getdirtybuf(&inodedep->id_buf,MNT_WAIT);
FREE_LOCK(&lk);
if (gotit &&
(error = VOP_BWRITE(inodedep->id_buf)) != 0)
break;
ACQUIRE_LOCK(&lk);
}
if (dap != LIST_FIRST(diraddhdp))
continue;
/*
* If the inode is still sitting in a buffer waiting
* to be written, push it to disk.
*/
FREE_LOCK(&lk);
if ((error = bread(ump->um_devvp,
fsbtodb(ump->um_fs, ino_to_fsba(ump->um_fs, inum)),
(int)ump->um_fs->fs_bsize, NOCRED, &bp)) != 0)
break;
if ((error = VOP_BWRITE(bp)) != 0)
break;
ACQUIRE_LOCK(&lk);
if (dap == LIST_FIRST(diraddhdp))
panic("flush_pagedep_deps: flush 2 failed");
continue;
}
if (vp->v_type == VDIR) {
/*
* A newly allocated directory must have its "." and
* ".." entries written out before its name can be
* committed in its parent. We do not want or need
* the full semantics of a synchronous VOP_FSYNC as
* that may end up here again, once for each directory
* level in the filesystem. Instead, we push the blocks
* and wait for them to clear.
*/
if (error = VOP_FSYNC(vp, p->p_cred, MNT_NOWAIT, p)) {
vput(vp);
break;
}
ACQUIRE_LOCK(&lk);
while (vp->v_numoutput) {
vp->v_flag |= VBWAIT;
FREE_LOCK_INTERLOCKED(&lk);
sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
ACQUIRE_LOCK_INTERLOCKED(&lk);
}
FREE_LOCK(&lk);
}
tv = time;
error = VOP_UPDATE(vp, &tv, &tv, MNT_WAIT);
vput(vp);
if (error)
break;
/*
* If we have failed to get rid of all the dependencies
* then something is seriously wrong.
*/
if (dap == LIST_FIRST(diraddhdp))
panic("flush_pagedep_deps: flush 3 failed");
ACQUIRE_LOCK(&lk);
}
if (error)
ACQUIRE_LOCK(&lk);
@ -3818,22 +3894,38 @@ softdep_deallocate_dependencies(bp)
if ((bp->b_flags & B_ERROR) == 0)
panic("softdep_deallocate_dependencies: dangling deps");
softdep_error(bp->b_vp->v_mount->mnt_stat.f_mntonname, bp->b_error);
ACQUIRE_LOCK(&lk);
while ((wk = LIST_FIRST(&bp->b_dep)) != NULL) {
WORKLIST_REMOVE(wk);
FREE_LOCK(&lk);
switch (wk->wk_type) {
/*
* XXX - should really clean up, but for now we will
* just leak memory and not worry about it.
* just leak memory and not worry about it. Also should
* mark the filesystem permanently dirty so that it will
* force fsck to be run (though this would best be done
* in the mainline code).
*/
case M_PAGEDEP: case M_INDIRDEP: case M_INODEDEP:
case M_PAGEDEP:
case M_INODEDEP:
case M_BMSAFEMAP:
case M_ALLOCDIRECT:
case M_INDIRDEP:
case M_ALLOCINDIR:
case M_MKDIR:
#ifdef DEBUG
printf("Lost %s\n", TYPENAME(wk->wk_type));
printf("Lost type %s\n", TYPENAME(wk->wk_type));
#endif
break;
default:
panic("softdep_deallocate_dependencies: bad type");
panic("%s: Unexpected type %s",
"softdep_deallocate_dependencies",
TYPENAME(wk->wk_type));
/* NOTREACHED */
}
ACQUIRE_LOCK(&lk);
}
FREE_LOCK(&lk);
}
/*

View File

@ -1,12 +1,14 @@
/*
* Copyright 1997 Marshall Kirk McKusick. All Rights Reserved.
* Copyright 1998 Marshall Kirk McKusick. All Rights Reserved.
*
* The soft dependency code is derived from work done by Greg Ganger
* at the University of Michigan.
* The soft updates code is derived from the appendix of a University
* of Michigan technical report (Gregory R. Ganger and Yale N. Patt,
* "Soft Updates: A Solution to the Metadata Update Problem in File
* Systems", CSE-TR-254-95, August 1995).
*
* The following are the copyrights and redistribution conditions that
* apply to this copy of the soft dependency software. For a license
* to use, redistribute or sell the soft dependency software under
* apply to this copy of the soft update software. For a license
* to use, redistribute or sell the soft update software under
* conditions other than those described here, please contact the
* author at one of the following addresses:
*
@ -24,12 +26,12 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. None of the names of McKusick, Ganger, or the University of Michigan
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* 3. None of the names of McKusick, Ganger, Patt, or the University of
* Michigan may be used to endorse or promote products derived from
* this software without specific prior written permission.
* 4. Redistributions in any form must be accompanied by information on
* how to obtain complete source code for any accompanying software
* that uses the this software. This source code must either be included
* that uses this software. This source code must either be included
* in the distribution or be available for no more than the cost of
* distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete
@ -50,7 +52,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)softdep.h 9.1 (McKusick) 7/9/97
*
* from: @(#)softdep.h 9.4 (McKusick) 1/15/98
*/
#include <sys/queue.h>
@ -220,6 +223,15 @@ struct pagedep {
* The entries on the id_inoupdt and id_newinoupdt lists must be kept
* sorted by logical block number to speed the calculation of the size
* of the rolled back inode (see explanation in initiate_write_inodeblock).
* When a directory entry is created, it is represented by a diradd.
* The diradd is added to the id_inowait list and is not permitted to be
* written to disk until the inode that it represents is written. After
* the inode is written, the id_inowait list is processed and the diradd
* entries are moved to the id_pendinghd list where they remain until
* the directory block containing the name has been written to disk.
* The purpose of keeping the entries on the id_pendinghd list is so that
* the softdep_fsync function can find and push the inode's directory
* name(s) as part of the fsync operation for that file.
*/
struct inodedep {
struct worklist id_list; /* buffer holding inode block */