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:
perseant 2000-05-05 20:59:20 +00:00
parent 280a47cc0a
commit 737dec82d6
7 changed files with 235 additions and 90 deletions

View File

@ -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. * Copyright (c) 1999 The NetBSD Foundation, Inc.
@ -313,6 +313,7 @@ struct lfs {
daddr_t lfs_sbactive; /* disk address of in-progress sb write */ daddr_t lfs_sbactive; /* disk address of in-progress sb write */
#endif #endif
struct vnode *lfs_flushvp; /* vnode being flushed */ 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 */ u_int32_t lfs_diropwait; /* # procs waiting on dirop flush */
struct lock lfs_freelock; struct lock lfs_freelock;
}; };
@ -333,8 +334,9 @@ struct lfs {
#define D_INDIR(fs) (S_INDIR(fs) - NINDIR(fs) - 1) #define D_INDIR(fs) (S_INDIR(fs) - NINDIR(fs) - 1)
#define T_INDIR(fs) (D_INDIR(fs) - NINDIR(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 UNASSIGNED -1
#define UNWRITTEN -2
/* Unused logical block number */ /* Unused logical block number */
#define LFS_UNUSED_LBN -1 #define LFS_UNUSED_LBN -1

View File

@ -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. * Copyright (c) 1999 The NetBSD Foundation, Inc.
@ -99,6 +99,19 @@
int lfs_fragextend __P((struct vnode *, int, int, ufs_daddr_t, struct buf **)); 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 int
lfs_balloc(v) lfs_balloc(v)
void *v; void *v;
@ -118,7 +131,7 @@ lfs_balloc(v)
struct buf *ibp, *bp; struct buf *ibp, *bp;
struct inode *ip; struct inode *ip;
struct lfs *fs; struct lfs *fs;
struct indir indirs[NIADDR+2]; struct indir indirs[NIADDR+2], *idp;
ufs_daddr_t daddr, lastblock; ufs_daddr_t daddr, lastblock;
int bb; /* number of disk blocks in a block disk blocks */ int bb; /* number of disk blocks in a block disk blocks */
int error, frags, i, nsize, osize, num; int error, frags, i, nsize, osize, num;
@ -171,28 +184,45 @@ lfs_balloc(v)
} }
bb = VFSTOUFS(vp->v_mount)->um_seqinc; 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 */ /* 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) { if (!indirs[i].in_exists) {
ibp = getblk(vp, indirs[i].in_lbn, fs->lfs_bsize, #ifdef DIAGNOSTIC
0, 0); if ((ibp->b_flags & (B_DONE | B_DELWRI)))
if ((ibp->b_flags & (B_DONE | B_DELWRI)))
panic ("Indirect block should not exist"); panic ("Indirect block should not exist");
#endif
if (!ISSPACE(fs, bb, curproc->p_ucred)){ if (!ISSPACE(fs, bb, curproc->p_ucred)){
ibp->b_flags |= B_INVAL; ibp->b_flags |= B_INVAL;
brelse(ibp); brelse(ibp);
/* XXX might leave some UNWRITTENs hanging, do this better */
return(ENOSPC); return(ENOSPC);
} else { } else {
ip->i_ffs_blocks += bb; ip->i_ffs_blocks += bb;
ip->i_lfs->lfs_bfree -= bb; ip->i_lfs->lfs_bfree -= bb;
clrbuf(ibp); clrbuf(ibp);
if ((error = VOP_BWRITE(ibp))) ((ufs_daddr_t *)ibp->b_data)[indirs[i].in_off] = UNWRITTEN;
return(error); 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 * 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 * 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. * for free space and update the inode number of blocks.
* *
* We can tell a truly new block because (1) ufs_bmaparray * We can tell a truly new block because (1) ufs_bmaparray
* will say it is UNASSIGNED; and (2) it will not be marked * will say it is UNASSIGNED. Once we allocate it we will assign
* with B_DELWRI. (It might be marked B_DONE, if it was * it the disk address UNWRITTEN.
* read into the cache before it existed on disk.)
*/ */
if ((!(bp->b_flags & B_DELWRI)) && daddr == UNASSIGNED) { if (daddr == UNASSIGNED) {
if (!ISSPACE(fs, bb, curproc->p_ucred)) { if (!ISSPACE(fs, bb, curproc->p_ucred)) {
bp->b_flags |= B_INVAL; bp->b_flags |= B_INVAL;
brelse(bp); brelse(bp);
@ -253,6 +282,27 @@ lfs_balloc(v)
ip->i_lfs->lfs_bfree -= bb; ip->i_lfs->lfs_bfree -= bb;
if (iosize != fs->lfs_bsize) if (iosize != fs->lfs_bsize)
clrbuf(bp); 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))) { } else if (!(bp->b_flags & (B_DONE|B_DELWRI))) {
/* /*

View File

@ -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. * Copyright (c) 1999 The NetBSD Foundation, Inc.
@ -393,6 +393,19 @@ lfs_check(vp, blkno, flags)
#endif #endif
error = tsleep(&locked_queue_count, PCATCH | PUSER, error = tsleep(&locked_queue_count, PCATCH | PUSER,
"buffers", hz * LFS_BUFWAIT); "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); return (error);
} }

View File

@ -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. * Copyright (c) 1999 The NetBSD Foundation, Inc.
@ -95,6 +95,8 @@
#include <ufs/lfs/lfs_extern.h> #include <ufs/lfs/lfs_extern.h>
static int lfs_vinvalbuf __P((struct vnode *, struct ucred *, struct proc *, ufs_daddr_t)); 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. */ /* Search a block for a specific dinode. */
struct dinode * struct dinode *
@ -184,7 +186,7 @@ lfs_update(v)
} }
/* Update segment usage information when removing a block. */ /* Update segment usage information when removing a block. */
#define UPDATE_SEGUSE \ #define UPDATE_SEGUSE do { \
if (lastseg != -1) { \ if (lastseg != -1) { \
LFS_SEGENTRY(sup, fs, lastseg, sup_bp); \ LFS_SEGENTRY(sup, fs, lastseg, sup_bp); \
if (num > sup->su_nbytes) { \ if (num > sup->su_nbytes) { \
@ -195,19 +197,22 @@ lfs_update(v)
} else \ } else \
sup->su_nbytes -= num; \ sup->su_nbytes -= num; \
e1 = VOP_BWRITE(sup_bp); \ e1 = VOP_BWRITE(sup_bp); \
fragsreleased += numfrags(fs, num); \ } \
} fragsreleased += numfrags(fs, num); \
} while(0)
#define SEGDEC(S) { \ #define SEGDEC(S) do { \
if (daddr != 0) { \ if (daddr > 0) { \
if (lastseg != (seg = datosn(fs, daddr))) { \ if (lastseg != (seg = datosn(fs, daddr))) { \
UPDATE_SEGUSE; \ UPDATE_SEGUSE; \
num = (S); \ num = (S); \
lastseg = seg; \ lastseg = seg; \
} else \ } else \
num += (S); \ num += (S); \
} else if (daddr == UNWRITTEN) { \
fragsreleased += numfrags(fs,(S)); \
} \ } \
} } while(0)
/* /*
* Truncate the inode ip to at most length size. Update segment usage * Truncate the inode ip to at most length size. Update segment usage
@ -239,7 +244,7 @@ lfs_truncate(v)
SEGUSE *sup; SEGUSE *sup;
ufs_daddr_t daddr, lastblock, lbn, olastblock; ufs_daddr_t daddr, lastblock, lbn, olastblock;
ufs_daddr_t oldsize_lastblock, oldsize_newlast, newsize; 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; int e1, e2, depth, lastseg, num, offset, seg, freesize, s;
if (length < 0) if (length < 0)
@ -288,15 +293,18 @@ lfs_truncate(v)
uvm_vnp_setsize(vp, length); uvm_vnp_setsize(vp, length);
/* /*
* Make sure no writes happen while we're truncating. * Make sure no writes to this inode can happen while we're
* Otherwise, blocks which are accounted for on the inode * truncating. Otherwise, blocks which are accounted for on the
* *and* which have been created for cleaning can coexist, * inode *and* which have been created for cleaning can coexist,
* and cause us to overcount, and panic below. * 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) { if (vp != fs->lfs_unlockvp) {
tsleep(&fs->lfs_seglock, (PRIBIO+1), "lfs_truncate", 0); 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)); bzero((char *)bp->b_data + offset, (u_int)(newsize - offset));
#ifdef DEBUG #ifdef DEBUG
if(bp->b_flags & B_CALL) if(bp->b_flags & B_CALL)
panic("Can't allocbuf malloced buffer!"); panic("Can't allocbuf malloced buffer!");
else else
#endif #endif
allocbuf(bp, newsize); allocbuf(bp, newsize);
if(oldsize_newlast > newsize) if(bp->b_blkno != UNASSIGNED && oldsize_newlast > newsize) {
ip->i_ffs_blocks -= btodb(oldsize_newlast - newsize); ip->i_ffs_blocks -= btodb(oldsize_newlast - newsize);
}
if ((e1 = VOP_BWRITE(bp)) != 0) { if ((e1 = VOP_BWRITE(bp)) != 0) {
printf("lfs_truncate: bwrite: %d\n",e1); printf("lfs_truncate: bwrite: %d\n",e1);
return (e1); return (e1);
@ -393,15 +402,15 @@ lfs_truncate(v)
panic("lfs_truncate: bread bno %d", panic("lfs_truncate: bread bno %d",
inp->in_lbn); inp->in_lbn);
daddrp = (ufs_daddr_t *)bp->b_data + inp->in_off; daddrp = (ufs_daddr_t *)bp->b_data + inp->in_off;
for (i = inp->in_off; for (i = inp->in_off; i++ <= a_end[depth].in_off;) {
i++ <= a_end[depth].in_off;) {
daddr = *daddrp++; daddr = *daddrp++;
SEGDEC(freesize); SEGDEC(freesize);
} }
a_end[depth].in_off = NINDIR(fs) - 1; 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); brelse (bp);
else { } else {
bzero((ufs_daddr_t *)bp->b_data + bzero((ufs_daddr_t *)bp->b_data +
inp->in_off, fs->lfs_bsize - inp->in_off, fs->lfs_bsize -
inp->in_off * sizeof(ufs_daddr_t)); inp->in_off * sizeof(ufs_daddr_t));
@ -436,9 +445,11 @@ lfs_truncate(v)
} }
#ifdef DIAGNOSTIC #ifdef DIAGNOSTIC
if (ip->i_ffs_blocks < fragstodb(fs, fragsreleased)) { 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_ffs_blocks, fragstodb(fs, fragsreleased),
ip->i_number); ip->i_number);
if (length > 0)
panic("lfs_truncate: frag count < 0");
fragsreleased = dbtofrags(fs, ip->i_ffs_blocks); fragsreleased = dbtofrags(fs, ip->i_ffs_blocks);
} }
#endif #endif
@ -451,59 +462,49 @@ lfs_truncate(v)
* field can be updated. * field can be updated.
*/ */
a_released = 0; a_released = 0;
i_released = 0;
s = splbio(); s = splbio();
for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = bp->b_vnbufs.le_next) { 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. */ /* XXX KS - Don't miscount if we're not truncating to zero. */
if(length>0 && !(bp->b_lblkno >= 0 && bp->b_lblkno > lastblock) if(length>0 && !(bp->b_lblkno >= 0 && bp->b_lblkno > lastblock)
&& !(bp->b_lblkno < 0 && bp->b_lblkno < -lastblock-NIADDR)) && !(bp->b_lblkno < 0 && bp->b_lblkno < -lastblock-NIADDR))
continue; continue;
if (bp->b_flags & B_LOCKED) { if (bp->b_flags & B_LOCKED)
a_released += numfrags(fs, bp->b_bcount); 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); 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 #ifdef DIAGNOSTIC
if (length == 0 && ip->i_ffs_blocks != 0) { if (length == 0 && ip->i_ffs_blocks != 0) {
printf("lfs_inode: trunc to zero, but %d blocks left on inode %d\n", printf("lfs_inode: trunc to zero, but %d blocks left on inode %d\n",
ip->i_ffs_blocks, ip->i_number); ip->i_ffs_blocks, ip->i_number);
panic("lfs_inode\n"); panic("lfs_inode: trunc to zero\n");
} }
#endif #endif
fs->lfs_avail += fragstodb(fs, a_released); fs->lfs_avail += fragstodb(fs, a_released);
if(length>0) if(length>0)
e1 = lfs_vinvalbuf(vp, ap->a_cred, ap->a_p, lastblock-1); 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); 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); e2 = VOP_UPDATE(vp, NULL, NULL, 0);
if(e1) if(e1)
printf("lfs_truncate: vinvalbuf: %d\n",e1); printf("lfs_truncate: vinvalbuf: %d\n",e1);
if(e2) if(e2)
@ -540,6 +541,8 @@ lfs_vinvalbuf(vp, cred, p, maxblk)
nbp = bp->b_vnbufs.le_next; nbp = bp->b_vnbufs.le_next;
if (bp->b_flags & B_GATHERED) { 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); error = tsleep(vp, PRIBIO+1, "lfs_vin2", 0);
splx(s); splx(s);
if(error) if(error)
@ -550,10 +553,9 @@ lfs_vinvalbuf(vp, cred, p, maxblk)
bp->b_flags |= B_WANTED; bp->b_flags |= B_WANTED;
error = tsleep((caddr_t)bp, error = tsleep((caddr_t)bp,
(PRIBIO + 1), "lfs_vinval", 0); (PRIBIO + 1), "lfs_vinval", 0);
if (error) { splx(s);
splx(s); if (error)
return (error); return (error);
}
goto top; goto top;
} }
@ -561,10 +563,14 @@ lfs_vinvalbuf(vp, cred, p, maxblk)
if((bp->b_lblkno >= 0 && bp->b_lblkno > maxblk) if((bp->b_lblkno >= 0 && bp->b_lblkno > maxblk)
|| (bp->b_lblkno < 0 && bp->b_lblkno < -maxblk-(NIADDR-1))) || (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) { if(bp->b_flags & B_CALL) {
lfs_freebuf(bp); lfs_freebuf(bp);
} else { } else {
bp->b_flags |= B_INVAL | B_VFLUSH;
brelse(bp); brelse(bp);
} }
++dirty; ++dirty;

View File

@ -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. * Copyright (c) 1999 The NetBSD Foundation, Inc.
@ -343,6 +343,7 @@ lfs_writevnodes(fs, mp, sp, op)
struct inode *ip; struct inode *ip;
struct vnode *vp; struct vnode *vp;
int inodes_written=0, only_cleaning; int inodes_written=0, only_cleaning;
int needs_unlock;
#ifndef LFS_NO_BACKVP_HACK #ifndef LFS_NO_BACKVP_HACK
/* BEGIN HACK */ /* BEGIN HACK */
@ -405,6 +406,23 @@ lfs_writevnodes(fs, mp, sp, op)
continue; continue;
} }
#endif #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; only_cleaning = 0;
/* /*
* Write the inode/file if dirty and it's not the * Write the inode/file if dirty and it's not the
@ -438,6 +456,9 @@ lfs_writevnodes(fs, mp, sp, op)
inodes_written++; inodes_written++;
} }
if(needs_unlock)
VOP_UNLOCK(vp,0);
if(lfs_clean_vnhead && only_cleaning) if(lfs_clean_vnhead && only_cleaning)
lfs_vunref_head(vp); lfs_vunref_head(vp);
else else
@ -907,6 +928,11 @@ loop: for (bp = vp->v_dirtyblkhd.lh_first; bp && bp->b_vnbufs.le_next != NULL;
bwrite(bp); bwrite(bp);
} else { } else {
#ifdef DIAGNOSTIC #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)) if (!(bp->b_flags & B_DELWRI))
panic("lfs_gather: bp not B_DELWRI"); panic("lfs_gather: bp not B_DELWRI");
if (!(bp->b_flags & B_LOCKED)) { if (!(bp->b_flags & B_LOCKED)) {
@ -940,12 +966,13 @@ lfs_updatemeta(sp)
struct segment *sp; struct segment *sp;
{ {
SEGUSE *sup; SEGUSE *sup;
struct buf *bp; struct buf *bp, *ibp;
struct lfs *fs; struct lfs *fs;
struct vnode *vp; struct vnode *vp;
struct indir a[NIADDR + 2], *ap; struct indir a[NIADDR + 2], *ap;
struct inode *ip; struct inode *ip;
ufs_daddr_t daddr, lbn, off; ufs_daddr_t daddr, lbn, off;
daddr_t ooff;
int error, i, nblocks, num; int error, i, nblocks, num;
vp = sp->vp; vp = sp->vp;
@ -993,10 +1020,26 @@ lfs_updatemeta(sp)
ip = VTOI(vp); ip = VTOI(vp);
switch (num) { switch (num) {
case 0: 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; break;
case 1: 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; break;
default: default:
ap = &a[num - 1]; ap = &a[num - 1];
@ -1006,17 +1049,49 @@ lfs_updatemeta(sp)
/* /*
* Bread may create a new (indirect) block which needs * Bread may create a new (indirect) block which needs
* to get counted for the inode. * 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 && */ if (bp->b_blkno == UNASSIGNED) {
!(bp->b_flags & (B_DELWRI|B_DONE))) {
ip->i_ffs_blocks += fsbtodb(fs, 1); ip->i_ffs_blocks += fsbtodb(fs, 1);
fs->lfs_bfree -= fragstodb(fs, fs->lfs_frag); 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. */ /* 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); LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp);
#ifdef DIAGNOSTIC #ifdef DIAGNOSTIC
if (sup->su_nbytes < (*sp->start_bpp)->b_bcount) { if (sup->su_nbytes < (*sp->start_bpp)->b_bcount) {
@ -1195,9 +1270,6 @@ lfs_writeseg(fs, sp)
if ((nblocks = sp->cbpp - sp->bpp) == 1) if ((nblocks = sp->cbpp - sp->bpp) == 1)
return (0); return (0);
#ifdef DEBUG_LFS
lfs_check_bpp(fs,sp,__FILE__,__LINE__);
#endif
i_dev = VTOI(fs->lfs_ivnode)->i_dev; i_dev = VTOI(fs->lfs_ivnode)->i_dev;
devvp = VTOI(fs->lfs_ivnode)->i_devvp; devvp = VTOI(fs->lfs_ivnode)->i_devvp;

View File

@ -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. * Copyright (c) 1999 The NetBSD Foundation, Inc.
@ -218,7 +218,9 @@ lfs_segunlock(fs)
wakeup(&lfs_dirvcount); wakeup(&lfs_dirvcount);
if(vp->v_usecount == 1) { if(vp->v_usecount == 1) {
/* vrele may call VOP_INACTIVE */ /* vrele may call VOP_INACTIVE */
fs->lfs_unlockvp = vp;
vrele(vp); vrele(vp);
fs->lfs_unlockvp = NULL;
} else } else
lfs_vunref(vp); lfs_vunref(vp);

View File

@ -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 * Copyright (c) 1982, 1986, 1989, 1993, 1995
@ -1639,10 +1639,10 @@ ufs_strategy(v)
biodone(bp); biodone(bp);
return (error); return (error);
} }
if ((long)bp->b_blkno == -1) if ((long)bp->b_blkno == -1) /* no valid data */
clrbuf(bp); clrbuf(bp);
} }
if ((long)bp->b_blkno == -1) { if ((long)bp->b_blkno < 0) { /* block is not on disk */
biodone(bp); biodone(bp);
return (0); return (0);
} }