Change the way LFS does block accounting, from trying to infer from the
buffer cache flags, to marking the inode and/or indirect blocks with a special disk address UNWRITTEN==-2 when a block is accounted for. (This address is never written to disk, but only used in-core. This is essentially the same method of block accounting as on the UBC branch, where the buffer headers don't exist.) Make sure that truncation is handled properly, especially in the case of holey files. Fixes PR#9994.
This commit is contained in:
parent
280a47cc0a
commit
737dec82d6
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs.h,v 1.20 2000/01/19 00:03:04 perseant Exp $ */
|
||||
/* $NetBSD: lfs.h,v 1.21 2000/05/05 20:59:21 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999 The NetBSD Foundation, Inc.
|
||||
|
@ -313,6 +313,7 @@ struct lfs {
|
|||
daddr_t lfs_sbactive; /* disk address of in-progress sb write */
|
||||
#endif
|
||||
struct vnode *lfs_flushvp; /* vnode being flushed */
|
||||
struct vnode *lfs_unlockvp; /* being inactivated in lfs_segunlock */
|
||||
u_int32_t lfs_diropwait; /* # procs waiting on dirop flush */
|
||||
struct lock lfs_freelock;
|
||||
};
|
||||
|
@ -333,8 +334,9 @@ struct lfs {
|
|||
#define D_INDIR(fs) (S_INDIR(fs) - NINDIR(fs) - 1)
|
||||
#define T_INDIR(fs) (D_INDIR(fs) - NINDIR(fs) * NINDIR(fs) - 1)
|
||||
|
||||
/* Unassigned disk address. */
|
||||
/* Unassigned disk addresses. */
|
||||
#define UNASSIGNED -1
|
||||
#define UNWRITTEN -2
|
||||
|
||||
/* Unused logical block number */
|
||||
#define LFS_UNUSED_LBN -1
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_balloc.c,v 1.15 2000/04/23 21:10:26 perseant Exp $ */
|
||||
/* $NetBSD: lfs_balloc.c,v 1.16 2000/05/05 20:59:21 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999 The NetBSD Foundation, Inc.
|
||||
|
@ -99,6 +99,19 @@
|
|||
|
||||
int lfs_fragextend __P((struct vnode *, int, int, ufs_daddr_t, struct buf **));
|
||||
|
||||
/*
|
||||
* Allocate a block, and to inode and filesystem block accounting for it
|
||||
* and for any indirect blocks the may need to be created in order for
|
||||
* this block to be created.
|
||||
*
|
||||
* Blocks which have never been accounted for (i.e., which "do not exist")
|
||||
* have disk address 0, which is translated by ufs_bmap to the special value
|
||||
* UNASSIGNED == -1, as in the historical UFS.
|
||||
*
|
||||
* Blocks which have been accounted for but which have not yet been written
|
||||
* to disk are given the new special disk address UNWRITTEN == -2, so that
|
||||
* they can be differentiated from completely new blocks.
|
||||
*/
|
||||
int
|
||||
lfs_balloc(v)
|
||||
void *v;
|
||||
|
@ -118,7 +131,7 @@ lfs_balloc(v)
|
|||
struct buf *ibp, *bp;
|
||||
struct inode *ip;
|
||||
struct lfs *fs;
|
||||
struct indir indirs[NIADDR+2];
|
||||
struct indir indirs[NIADDR+2], *idp;
|
||||
ufs_daddr_t daddr, lastblock;
|
||||
int bb; /* number of disk blocks in a block disk blocks */
|
||||
int error, frags, i, nsize, osize, num;
|
||||
|
@ -171,28 +184,45 @@ lfs_balloc(v)
|
|||
}
|
||||
|
||||
bb = VFSTOUFS(vp->v_mount)->um_seqinc;
|
||||
if (daddr == UNASSIGNED)
|
||||
if (daddr == UNASSIGNED) {
|
||||
if (num > 0 && ip->i_ffs_ib[indirs[0].in_off] == 0) {
|
||||
ip->i_ffs_ib[indirs[0].in_off] = UNWRITTEN;
|
||||
}
|
||||
/* May need to allocate indirect blocks */
|
||||
for (i = 1; i < num; ++i)
|
||||
for (i = 1; i < num; ++i) {
|
||||
ibp = getblk(vp, indirs[i].in_lbn, fs->lfs_bsize, 0,0);
|
||||
if (!indirs[i].in_exists) {
|
||||
ibp = getblk(vp, indirs[i].in_lbn, fs->lfs_bsize,
|
||||
0, 0);
|
||||
if ((ibp->b_flags & (B_DONE | B_DELWRI)))
|
||||
#ifdef DIAGNOSTIC
|
||||
if ((ibp->b_flags & (B_DONE | B_DELWRI)))
|
||||
panic ("Indirect block should not exist");
|
||||
#endif
|
||||
|
||||
if (!ISSPACE(fs, bb, curproc->p_ucred)){
|
||||
ibp->b_flags |= B_INVAL;
|
||||
brelse(ibp);
|
||||
/* XXX might leave some UNWRITTENs hanging, do this better */
|
||||
return(ENOSPC);
|
||||
} else {
|
||||
ip->i_ffs_blocks += bb;
|
||||
ip->i_lfs->lfs_bfree -= bb;
|
||||
clrbuf(ibp);
|
||||
if ((error = VOP_BWRITE(ibp)))
|
||||
return(error);
|
||||
((ufs_daddr_t *)ibp->b_data)[indirs[i].in_off] = UNWRITTEN;
|
||||
ibp->b_blkno = UNWRITTEN;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* This block exists, but the next one may not.
|
||||
* If that is the case mark it UNWRITTEN to
|
||||
* keep the accounting straight.
|
||||
*/
|
||||
if ( ((ufs_daddr_t *)ibp->b_data)[indirs[i].in_off] == 0) {
|
||||
((ufs_daddr_t *)ibp->b_data)[indirs[i].in_off] = UNWRITTEN;
|
||||
}
|
||||
}
|
||||
|
||||
if ((error = VOP_BWRITE(ibp)))
|
||||
return(error);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If the block we are writing is a direct block, it's the last
|
||||
* block in the file, and offset + iosize is less than a full
|
||||
|
@ -239,11 +269,10 @@ lfs_balloc(v)
|
|||
* for free space and update the inode number of blocks.
|
||||
*
|
||||
* We can tell a truly new block because (1) ufs_bmaparray
|
||||
* will say it is UNASSIGNED; and (2) it will not be marked
|
||||
* with B_DELWRI. (It might be marked B_DONE, if it was
|
||||
* read into the cache before it existed on disk.)
|
||||
* will say it is UNASSIGNED. Once we allocate it we will assign
|
||||
* it the disk address UNWRITTEN.
|
||||
*/
|
||||
if ((!(bp->b_flags & B_DELWRI)) && daddr == UNASSIGNED) {
|
||||
if (daddr == UNASSIGNED) {
|
||||
if (!ISSPACE(fs, bb, curproc->p_ucred)) {
|
||||
bp->b_flags |= B_INVAL;
|
||||
brelse(bp);
|
||||
|
@ -253,6 +282,27 @@ lfs_balloc(v)
|
|||
ip->i_lfs->lfs_bfree -= bb;
|
||||
if (iosize != fs->lfs_bsize)
|
||||
clrbuf(bp);
|
||||
|
||||
/* Note the new address */
|
||||
bp->b_blkno = UNWRITTEN;
|
||||
|
||||
switch (num) {
|
||||
case 0:
|
||||
ip->i_ffs_db[lbn] = UNWRITTEN;
|
||||
break;
|
||||
case 1:
|
||||
ip->i_ffs_ib[indirs[0].in_off] = UNWRITTEN;
|
||||
break;
|
||||
default:
|
||||
idp = &indirs[num - 1];
|
||||
if (bread(vp, idp->in_lbn, fs->lfs_bsize,
|
||||
NOCRED, &ibp))
|
||||
panic("lfs_balloc: bread bno %d",
|
||||
idp->in_lbn);
|
||||
((ufs_daddr_t *)ibp->b_data)[idp->in_off] =
|
||||
UNWRITTEN;
|
||||
VOP_BWRITE(ibp);
|
||||
}
|
||||
}
|
||||
} else if (!(bp->b_flags & (B_DONE|B_DELWRI))) {
|
||||
/*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_bio.c,v 1.17 2000/03/30 12:41:13 augustss Exp $ */
|
||||
/* $NetBSD: lfs_bio.c,v 1.18 2000/05/05 20:59:21 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999 The NetBSD Foundation, Inc.
|
||||
|
@ -393,6 +393,19 @@ lfs_check(vp, blkno, flags)
|
|||
#endif
|
||||
error = tsleep(&locked_queue_count, PCATCH | PUSER,
|
||||
"buffers", hz * LFS_BUFWAIT);
|
||||
/*
|
||||
* lfs_flush might not flush all the buffers, if some of the
|
||||
* inodes were locked. Try flushing again to keep us from
|
||||
* blocking indefinitely.
|
||||
*/
|
||||
if (locked_queue_count > LFS_MAX_BUFS
|
||||
|| locked_queue_bytes > LFS_MAX_BYTES)
|
||||
{
|
||||
++fs->lfs_writer;
|
||||
lfs_flush(fs, flags);
|
||||
if(--fs->lfs_writer==0)
|
||||
wakeup(&fs->lfs_dirops);
|
||||
}
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_inode.c,v 1.34 2000/04/24 19:07:16 perseant Exp $ */
|
||||
/* $NetBSD: lfs_inode.c,v 1.35 2000/05/05 20:59:21 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999 The NetBSD Foundation, Inc.
|
||||
|
@ -95,6 +95,8 @@
|
|||
#include <ufs/lfs/lfs_extern.h>
|
||||
|
||||
static int lfs_vinvalbuf __P((struct vnode *, struct ucred *, struct proc *, ufs_daddr_t));
|
||||
extern int locked_queue_count;
|
||||
extern long locked_queue_bytes;
|
||||
|
||||
/* Search a block for a specific dinode. */
|
||||
struct dinode *
|
||||
|
@ -184,7 +186,7 @@ lfs_update(v)
|
|||
}
|
||||
|
||||
/* Update segment usage information when removing a block. */
|
||||
#define UPDATE_SEGUSE \
|
||||
#define UPDATE_SEGUSE do { \
|
||||
if (lastseg != -1) { \
|
||||
LFS_SEGENTRY(sup, fs, lastseg, sup_bp); \
|
||||
if (num > sup->su_nbytes) { \
|
||||
|
@ -195,19 +197,22 @@ lfs_update(v)
|
|||
} else \
|
||||
sup->su_nbytes -= num; \
|
||||
e1 = VOP_BWRITE(sup_bp); \
|
||||
fragsreleased += numfrags(fs, num); \
|
||||
}
|
||||
} \
|
||||
fragsreleased += numfrags(fs, num); \
|
||||
} while(0)
|
||||
|
||||
#define SEGDEC(S) { \
|
||||
if (daddr != 0) { \
|
||||
#define SEGDEC(S) do { \
|
||||
if (daddr > 0) { \
|
||||
if (lastseg != (seg = datosn(fs, daddr))) { \
|
||||
UPDATE_SEGUSE; \
|
||||
num = (S); \
|
||||
lastseg = seg; \
|
||||
} else \
|
||||
num += (S); \
|
||||
} else if (daddr == UNWRITTEN) { \
|
||||
fragsreleased += numfrags(fs,(S)); \
|
||||
} \
|
||||
}
|
||||
} while(0)
|
||||
|
||||
/*
|
||||
* Truncate the inode ip to at most length size. Update segment usage
|
||||
|
@ -239,7 +244,7 @@ lfs_truncate(v)
|
|||
SEGUSE *sup;
|
||||
ufs_daddr_t daddr, lastblock, lbn, olastblock;
|
||||
ufs_daddr_t oldsize_lastblock, oldsize_newlast, newsize;
|
||||
long off, a_released, fragsreleased, i_released;
|
||||
long off, a_released, fragsreleased;
|
||||
int e1, e2, depth, lastseg, num, offset, seg, freesize, s;
|
||||
|
||||
if (length < 0)
|
||||
|
@ -288,15 +293,18 @@ lfs_truncate(v)
|
|||
uvm_vnp_setsize(vp, length);
|
||||
|
||||
/*
|
||||
* Make sure no writes happen while we're truncating.
|
||||
* Otherwise, blocks which are accounted for on the inode
|
||||
* *and* which have been created for cleaning can coexist,
|
||||
* and cause us to overcount, and panic below.
|
||||
* Make sure no writes to this inode can happen while we're
|
||||
* truncating. Otherwise, blocks which are accounted for on the
|
||||
* inode *and* which have been created for cleaning can coexist,
|
||||
* and cause an overcounting.
|
||||
*
|
||||
* XXX KS - too restrictive? Maybe only when cleaning?
|
||||
* (We don't need to *hold* the seglock, though, because we already
|
||||
* hold the inode lock; draining the seglock is sufficient.)
|
||||
*/
|
||||
while(fs->lfs_seglock && fs->lfs_lockpid != ap->a_p->p_pid) {
|
||||
tsleep(&fs->lfs_seglock, (PRIBIO+1), "lfs_truncate", 0);
|
||||
if (vp != fs->lfs_unlockvp) {
|
||||
while(fs->lfs_seglock) {
|
||||
tsleep(&fs->lfs_seglock, PRIBIO+1, "lfs_truncate", 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -339,12 +347,13 @@ lfs_truncate(v)
|
|||
bzero((char *)bp->b_data + offset, (u_int)(newsize - offset));
|
||||
#ifdef DEBUG
|
||||
if(bp->b_flags & B_CALL)
|
||||
panic("Can't allocbuf malloced buffer!");
|
||||
panic("Can't allocbuf malloced buffer!");
|
||||
else
|
||||
#endif
|
||||
allocbuf(bp, newsize);
|
||||
if(oldsize_newlast > newsize)
|
||||
if(bp->b_blkno != UNASSIGNED && oldsize_newlast > newsize) {
|
||||
ip->i_ffs_blocks -= btodb(oldsize_newlast - newsize);
|
||||
}
|
||||
if ((e1 = VOP_BWRITE(bp)) != 0) {
|
||||
printf("lfs_truncate: bwrite: %d\n",e1);
|
||||
return (e1);
|
||||
|
@ -393,15 +402,15 @@ lfs_truncate(v)
|
|||
panic("lfs_truncate: bread bno %d",
|
||||
inp->in_lbn);
|
||||
daddrp = (ufs_daddr_t *)bp->b_data + inp->in_off;
|
||||
for (i = inp->in_off;
|
||||
i++ <= a_end[depth].in_off;) {
|
||||
for (i = inp->in_off; i++ <= a_end[depth].in_off;) {
|
||||
daddr = *daddrp++;
|
||||
SEGDEC(freesize);
|
||||
}
|
||||
a_end[depth].in_off = NINDIR(fs) - 1;
|
||||
if (inp->in_off == 0)
|
||||
if (inp->in_off == 0) {
|
||||
bp->b_flags |= B_INVAL;
|
||||
brelse (bp);
|
||||
else {
|
||||
} else {
|
||||
bzero((ufs_daddr_t *)bp->b_data +
|
||||
inp->in_off, fs->lfs_bsize -
|
||||
inp->in_off * sizeof(ufs_daddr_t));
|
||||
|
@ -436,9 +445,11 @@ lfs_truncate(v)
|
|||
}
|
||||
#ifdef DIAGNOSTIC
|
||||
if (ip->i_ffs_blocks < fragstodb(fs, fragsreleased)) {
|
||||
panic("lfs_truncate: frag count < 0 (%d<%ld), ino %d\n",
|
||||
printf("lfs_truncate: frag count < 0 (%d<%ld), ino %d\n",
|
||||
ip->i_ffs_blocks, fragstodb(fs, fragsreleased),
|
||||
ip->i_number);
|
||||
if (length > 0)
|
||||
panic("lfs_truncate: frag count < 0");
|
||||
fragsreleased = dbtofrags(fs, ip->i_ffs_blocks);
|
||||
}
|
||||
#endif
|
||||
|
@ -451,59 +462,49 @@ lfs_truncate(v)
|
|||
* field can be updated.
|
||||
*/
|
||||
a_released = 0;
|
||||
i_released = 0;
|
||||
|
||||
s = splbio();
|
||||
for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = bp->b_vnbufs.le_next) {
|
||||
|
||||
/* XXX KS - Don't miscount if we're not truncating to zero. */
|
||||
if(length>0 && !(bp->b_lblkno >= 0 && bp->b_lblkno > lastblock)
|
||||
&& !(bp->b_lblkno < 0 && bp->b_lblkno < -lastblock-NIADDR))
|
||||
continue;
|
||||
|
||||
if (bp->b_flags & B_LOCKED) {
|
||||
if (bp->b_flags & B_LOCKED)
|
||||
a_released += numfrags(fs, bp->b_bcount);
|
||||
/*
|
||||
* XXX
|
||||
* When buffers are created in the cache, their block
|
||||
* number is set equal to their logical block number.
|
||||
* If that is still true, we are assuming that the
|
||||
* blocks are new (not yet on disk) and weren't
|
||||
* counted above. However, there is a slight chance
|
||||
* that a block's disk address is equal to its logical
|
||||
* block number in which case, we'll get an overcounting
|
||||
* here.
|
||||
*/
|
||||
if (bp->b_blkno == bp->b_lblkno) {
|
||||
i_released += numfrags(fs, bp->b_bcount);
|
||||
}
|
||||
}
|
||||
}
|
||||
splx(s);
|
||||
fragsreleased = i_released;
|
||||
#ifdef DIAGNOSTIC
|
||||
if (fragsreleased > dbtofrags(fs, ip->i_ffs_blocks)) {
|
||||
printf("lfs_inode: %ld frags released > %d in inode %d\n",
|
||||
fragsreleased, dbtofrags(fs, ip->i_ffs_blocks),
|
||||
ip->i_number);
|
||||
fragsreleased = dbtofrags(fs, ip->i_ffs_blocks);
|
||||
}
|
||||
#endif
|
||||
fs->lfs_bfree += fragstodb(fs, fragsreleased);
|
||||
ip->i_ffs_blocks -= fragstodb(fs, fragsreleased);
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (length == 0 && ip->i_ffs_blocks != 0) {
|
||||
printf("lfs_inode: trunc to zero, but %d blocks left on inode %d\n",
|
||||
ip->i_ffs_blocks, ip->i_number);
|
||||
panic("lfs_inode\n");
|
||||
panic("lfs_inode: trunc to zero\n");
|
||||
}
|
||||
#endif
|
||||
fs->lfs_avail += fragstodb(fs, a_released);
|
||||
if(length>0)
|
||||
e1 = lfs_vinvalbuf(vp, ap->a_cred, ap->a_p, lastblock-1);
|
||||
else
|
||||
else {
|
||||
e1 = vinvalbuf(vp, 0, ap->a_cred, ap->a_p, 0, 0);
|
||||
lfs_countlocked(&locked_queue_count,&locked_queue_bytes);
|
||||
}
|
||||
wakeup(&locked_queue_count);
|
||||
|
||||
if (length > 0) {
|
||||
/*
|
||||
* Allocate the new last block to ensure that any previously
|
||||
* existing indirect blocks invalidated above are valid.
|
||||
* (Adding the block is not really necessary.)
|
||||
*/
|
||||
error = VOP_BALLOC(vp, length - 1, 1, ap->a_cred, 0, &bp);
|
||||
if (error)
|
||||
return (error);
|
||||
VOP_BWRITE(bp);
|
||||
}
|
||||
|
||||
e2 = VOP_UPDATE(vp, NULL, NULL, 0);
|
||||
|
||||
if(e1)
|
||||
printf("lfs_truncate: vinvalbuf: %d\n",e1);
|
||||
if(e2)
|
||||
|
@ -540,6 +541,8 @@ lfs_vinvalbuf(vp, cred, p, maxblk)
|
|||
nbp = bp->b_vnbufs.le_next;
|
||||
|
||||
if (bp->b_flags & B_GATHERED) {
|
||||
printf("lfs_vinvalbuf: gathered block ino %d lbn %d\n",
|
||||
VTOI(vp)->i_number, bp->b_lblkno);
|
||||
error = tsleep(vp, PRIBIO+1, "lfs_vin2", 0);
|
||||
splx(s);
|
||||
if(error)
|
||||
|
@ -550,10 +553,9 @@ lfs_vinvalbuf(vp, cred, p, maxblk)
|
|||
bp->b_flags |= B_WANTED;
|
||||
error = tsleep((caddr_t)bp,
|
||||
(PRIBIO + 1), "lfs_vinval", 0);
|
||||
if (error) {
|
||||
splx(s);
|
||||
splx(s);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
goto top;
|
||||
}
|
||||
|
||||
|
@ -561,10 +563,14 @@ lfs_vinvalbuf(vp, cred, p, maxblk)
|
|||
if((bp->b_lblkno >= 0 && bp->b_lblkno > maxblk)
|
||||
|| (bp->b_lblkno < 0 && bp->b_lblkno < -maxblk-(NIADDR-1)))
|
||||
{
|
||||
bp->b_flags |= B_INVAL | B_VFLUSH;
|
||||
if(bp->b_flags & B_LOCKED) {
|
||||
--locked_queue_count;
|
||||
locked_queue_bytes -= bp->b_bufsize;
|
||||
}
|
||||
if(bp->b_flags & B_CALL) {
|
||||
lfs_freebuf(bp);
|
||||
} else {
|
||||
bp->b_flags |= B_INVAL | B_VFLUSH;
|
||||
brelse(bp);
|
||||
}
|
||||
++dirty;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_segment.c,v 1.42 2000/03/30 12:41:13 augustss Exp $ */
|
||||
/* $NetBSD: lfs_segment.c,v 1.43 2000/05/05 20:59:21 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999 The NetBSD Foundation, Inc.
|
||||
|
@ -343,6 +343,7 @@ lfs_writevnodes(fs, mp, sp, op)
|
|||
struct inode *ip;
|
||||
struct vnode *vp;
|
||||
int inodes_written=0, only_cleaning;
|
||||
int needs_unlock;
|
||||
|
||||
#ifndef LFS_NO_BACKVP_HACK
|
||||
/* BEGIN HACK */
|
||||
|
@ -405,6 +406,23 @@ lfs_writevnodes(fs, mp, sp, op)
|
|||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
needs_unlock = 0;
|
||||
if(VOP_ISLOCKED(vp)) {
|
||||
if (vp != fs->lfs_ivnode &&
|
||||
vp->v_lock.lk_lockholder != curproc->p_pid) {
|
||||
#ifdef DEBUG_LFS
|
||||
printf("lfs_writevnodes: not writing ino %d, locked by pid %d\n",
|
||||
VTOI(vp)->i_number,
|
||||
vp->v_lock.lk_lockholder);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
|
||||
needs_unlock = 1;
|
||||
}
|
||||
|
||||
only_cleaning = 0;
|
||||
/*
|
||||
* Write the inode/file if dirty and it's not the
|
||||
|
@ -438,6 +456,9 @@ lfs_writevnodes(fs, mp, sp, op)
|
|||
inodes_written++;
|
||||
}
|
||||
|
||||
if(needs_unlock)
|
||||
VOP_UNLOCK(vp,0);
|
||||
|
||||
if(lfs_clean_vnhead && only_cleaning)
|
||||
lfs_vunref_head(vp);
|
||||
else
|
||||
|
@ -907,6 +928,11 @@ loop: for (bp = vp->v_dirtyblkhd.lh_first; bp && bp->b_vnbufs.le_next != NULL;
|
|||
bwrite(bp);
|
||||
} else {
|
||||
#ifdef DIAGNOSTIC
|
||||
if ((bp->b_flags & (B_CALL|B_INVAL))==B_INVAL) {
|
||||
printf("lfs_gather: lbn %d is B_INVAL\n",
|
||||
bp->b_lblkno);
|
||||
VOP_PRINT(bp->b_vp);
|
||||
}
|
||||
if (!(bp->b_flags & B_DELWRI))
|
||||
panic("lfs_gather: bp not B_DELWRI");
|
||||
if (!(bp->b_flags & B_LOCKED)) {
|
||||
|
@ -940,12 +966,13 @@ lfs_updatemeta(sp)
|
|||
struct segment *sp;
|
||||
{
|
||||
SEGUSE *sup;
|
||||
struct buf *bp;
|
||||
struct buf *bp, *ibp;
|
||||
struct lfs *fs;
|
||||
struct vnode *vp;
|
||||
struct indir a[NIADDR + 2], *ap;
|
||||
struct inode *ip;
|
||||
ufs_daddr_t daddr, lbn, off;
|
||||
daddr_t ooff;
|
||||
int error, i, nblocks, num;
|
||||
|
||||
vp = sp->vp;
|
||||
|
@ -993,10 +1020,26 @@ lfs_updatemeta(sp)
|
|||
ip = VTOI(vp);
|
||||
switch (num) {
|
||||
case 0:
|
||||
ip->i_ffs_db[lbn] = off;
|
||||
ooff = ip->i_ffs_db[lbn];
|
||||
if(vp != fs->lfs_ivnode && (ooff == 0 || ooff == UNASSIGNED)) {
|
||||
#ifdef DEBUG_LFS
|
||||
printf("lfs_updatemeta[1]: warning: writing ino %d lbn %d at 0x%x, was 0x%x\n", ip->i_number, lbn, off, ooff);
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
} else
|
||||
ip->i_ffs_db[lbn] = off;
|
||||
break;
|
||||
case 1:
|
||||
ip->i_ffs_ib[a[0].in_off] = off;
|
||||
ooff = ip->i_ffs_ib[a[0].in_off];
|
||||
if(vp != fs->lfs_ivnode && (ooff == 0 || ooff == UNASSIGNED)) {
|
||||
#ifdef DEBUG_LFS
|
||||
printf("lfs_updatemeta[2]: warning: writing ino %d lbn %d at 0x%x, was 0x%x\n", ip->i_number, lbn, off, ooff);
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
} else
|
||||
ip->i_ffs_ib[a[0].in_off] = off;
|
||||
break;
|
||||
default:
|
||||
ap = &a[num - 1];
|
||||
|
@ -1006,17 +1049,49 @@ lfs_updatemeta(sp)
|
|||
/*
|
||||
* Bread may create a new (indirect) block which needs
|
||||
* to get counted for the inode.
|
||||
*
|
||||
* XXX - why would it ever do this (except possibly
|
||||
* for the Ifile)? lfs_balloc is supposed to take
|
||||
* care of this.
|
||||
*/
|
||||
if (/* bp->b_blkno == -1 && */
|
||||
!(bp->b_flags & (B_DELWRI|B_DONE))) {
|
||||
if (bp->b_blkno == UNASSIGNED) {
|
||||
ip->i_ffs_blocks += fsbtodb(fs, 1);
|
||||
fs->lfs_bfree -= fragstodb(fs, fs->lfs_frag);
|
||||
|
||||
/* Note the new address */
|
||||
bp->b_blkno = UNWRITTEN;
|
||||
|
||||
if(num == 2) {
|
||||
ip->i_ffs_ib[a[0].in_off] = UNWRITTEN;
|
||||
} else {
|
||||
ap = &a[num - 2];
|
||||
if (bread(vp, ap->in_lbn,
|
||||
fs->lfs_bsize, NOCRED, &ibp))
|
||||
panic("lfs_updatemeta: bread bno %d",
|
||||
ap->in_lbn);
|
||||
((ufs_daddr_t *)ibp->b_data)[ap->in_off] = UNWRITTEN;
|
||||
VOP_BWRITE(ibp);
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else if(!(bp->b_flags & (B_DONE|B_DELWRI)))
|
||||
printf("lfs_updatemeta: unaccounted indirect block ino %d block %d\n", ip->i_number, ap->in_lbn);
|
||||
#endif
|
||||
ooff = ((ufs_daddr_t *)bp->b_data)[ap->in_off];
|
||||
if(vp != fs->lfs_ivnode && (ooff == 0 || ooff == UNASSIGNED)) {
|
||||
#ifdef DEBUG_LFS
|
||||
printf("lfs_updatemeta[3]: warning: writing ino %d lbn %d at 0x%x, was 0x%x\n", ip->i_number, lbn, off, ooff);
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
brelse(bp);
|
||||
} else {
|
||||
((ufs_daddr_t *)bp->b_data)[ap->in_off] = off;
|
||||
VOP_BWRITE(bp);
|
||||
}
|
||||
((ufs_daddr_t *)bp->b_data)[ap->in_off] = off;
|
||||
VOP_BWRITE(bp);
|
||||
}
|
||||
/* Update segment usage information. */
|
||||
if (daddr != UNASSIGNED && !(daddr >= fs->lfs_lastpseg && daddr <= off)) {
|
||||
if (daddr > 0 && !(daddr >= fs->lfs_lastpseg && daddr <= off)) {
|
||||
LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp);
|
||||
#ifdef DIAGNOSTIC
|
||||
if (sup->su_nbytes < (*sp->start_bpp)->b_bcount) {
|
||||
|
@ -1195,9 +1270,6 @@ lfs_writeseg(fs, sp)
|
|||
if ((nblocks = sp->cbpp - sp->bpp) == 1)
|
||||
return (0);
|
||||
|
||||
#ifdef DEBUG_LFS
|
||||
lfs_check_bpp(fs,sp,__FILE__,__LINE__);
|
||||
#endif
|
||||
i_dev = VTOI(fs->lfs_ivnode)->i_dev;
|
||||
devvp = VTOI(fs->lfs_ivnode)->i_devvp;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_subr.c,v 1.13 2000/03/30 12:41:13 augustss Exp $ */
|
||||
/* $NetBSD: lfs_subr.c,v 1.14 2000/05/05 20:59:22 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999 The NetBSD Foundation, Inc.
|
||||
|
@ -218,7 +218,9 @@ lfs_segunlock(fs)
|
|||
wakeup(&lfs_dirvcount);
|
||||
if(vp->v_usecount == 1) {
|
||||
/* vrele may call VOP_INACTIVE */
|
||||
fs->lfs_unlockvp = vp;
|
||||
vrele(vp);
|
||||
fs->lfs_unlockvp = NULL;
|
||||
} else
|
||||
lfs_vunref(vp);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ufs_vnops.c,v 1.64 2000/03/30 12:41:15 augustss Exp $ */
|
||||
/* $NetBSD: ufs_vnops.c,v 1.65 2000/05/05 20:59:20 perseant Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1982, 1986, 1989, 1993, 1995
|
||||
|
@ -1639,10 +1639,10 @@ ufs_strategy(v)
|
|||
biodone(bp);
|
||||
return (error);
|
||||
}
|
||||
if ((long)bp->b_blkno == -1)
|
||||
if ((long)bp->b_blkno == -1) /* no valid data */
|
||||
clrbuf(bp);
|
||||
}
|
||||
if ((long)bp->b_blkno == -1) {
|
||||
if ((long)bp->b_blkno < 0) { /* block is not on disk */
|
||||
biodone(bp);
|
||||
return (0);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue