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.
@ -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

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.
@ -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))) {
/*

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.
@ -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);
}

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.
@ -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;

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.
@ -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;

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.
@ -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);

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
@ -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);
}