Fix a buffer overflow bug in the LFS_UBC case that manifested itself

either as a mysterious UVM error or as "panic: dirty bufs".  Verify
maximum size in lfs_malloc.

Teach lfs_updatemeta and lfs_shellsort about oversized cluster blocks from
lfs_gop_write.

When unwiring pages in lfs_gop_write, deactivate them, under the theory
that the pagedaemon wanted to free them last we knew.
This commit is contained in:
perseant 2003-02-23 00:22:33 +00:00
parent 6bce155b9e
commit 3ab94fed93
7 changed files with 125 additions and 100 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: TODO,v 1.6 2003/02/17 23:48:16 perseant Exp $
# $NetBSD: TODO,v 1.7 2003/02/23 00:22:33 perseant Exp $
- Lock audit. Need to check locking for multiprocessor case in particular.
@ -38,13 +38,13 @@
and possibly perform additional tasks:
- Backups. At a minimum, turn the cleaner off and on to allow
effective live backups. More aggressively, the cleaner itself could
be the backup agent, and dump_lfs would merely be a controller.
effective live backups. More aggressively, the cleaner itself could
be the backup agent, and dump_lfs would merely be a controller.
- Cleaning time policies. Be able to tweak the cleaner's thresholds
to allow more thorough cleaning during policy-determined idle
periods (regardless of actual idleness) or put off until later
during short, intensive write periods.
to allow more thorough cleaning during policy-determined idle
periods (regardless of actual idleness) or put off until later
during short, intensive write periods.
- File coalescing and placement. During periods we expect to be idle,
coalesce fragmented files into one place on disk for better read

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs.h,v 1.49 2003/02/20 04:27:23 perseant Exp $ */
/* $NetBSD: lfs.h,v 1.50 2003/02/23 00:22:33 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@ -130,6 +130,7 @@
typedef struct lfs_res_blk {
void *p;
LIST_ENTRY(lfs_res_blk) res;
int size;
char inuse;
} res_t;
@ -834,8 +835,8 @@ struct segment {
struct vnode *vp; /* vnode being gathered */
void *segsum; /* segment summary info */
u_int32_t ninodes; /* number of inodes in this segment */
u_int32_t seg_bytes_left; /* bytes left in segment */
u_int32_t sum_bytes_left; /* bytes left in summary block */
int32_t seg_bytes_left; /* bytes left in segment */
int32_t sum_bytes_left; /* bytes left in summary block */
u_int32_t seg_number; /* number of this segment */
/* XXX ondisk32 */
int32_t *start_lbp; /* beginning lbn for this set */

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_extern.h,v 1.41 2003/02/20 04:27:24 perseant Exp $ */
/* $NetBSD: lfs_extern.h,v 1.42 2003/02/23 00:22:34 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@ -162,7 +162,7 @@ void lfs_writefile(struct lfs *, struct segment *, struct vnode *);
int lfs_writeinode(struct lfs *, struct segment *, struct inode *);
int lfs_gatherblock(struct segment *, struct buf *, int *);
int lfs_gather(struct lfs *, struct segment *, struct vnode *, int (*match )(struct lfs *, struct buf *));
void lfs_update_single(struct lfs *, struct segment *, daddr_t, int32_t, int, int);
void lfs_update_single(struct lfs *, struct segment *, daddr_t, int32_t, int);
void lfs_updatemeta(struct segment *);
int lfs_initseg(struct lfs *);
void lfs_newseg(struct lfs *);
@ -175,7 +175,7 @@ int lfs_match_tindir(struct lfs *, struct buf *);
void lfs_callback(struct buf *);
void lfs_supercallback(struct buf *);
/* XXX ondisk32 */
void lfs_shellsort(struct buf **, int32_t *, int);
void lfs_shellsort(struct buf **, int32_t *, int, int);
int lfs_vref(struct vnode *);
void lfs_vunref(struct vnode *);
void lfs_vunref_head(struct vnode *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_segment.c,v 1.103 2003/02/20 04:27:24 perseant Exp $ */
/* $NetBSD: lfs_segment.c,v 1.104 2003/02/23 00:22:34 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@ -71,7 +71,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.103 2003/02/20 04:27:24 perseant Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.104 2003/02/23 00:22:34 perseant Exp $");
#define ivndebug(vp,str) printf("ino %d: %s\n",VTOI(vp)->i_number,(str))
@ -137,7 +137,7 @@ int lfs_match_indir(struct lfs *, struct buf *);
int lfs_match_tindir(struct lfs *, struct buf *);
void lfs_newseg(struct lfs *);
/* XXX ondisk32 */
void lfs_shellsort(struct buf **, int32_t *, int);
void lfs_shellsort(struct buf **, int32_t *, int, int);
void lfs_supercallback(struct buf *);
void lfs_updatemeta(struct segment *);
int lfs_vref(struct vnode *);
@ -1114,10 +1114,9 @@ lfs_gatherblock(struct segment *sp, struct buf *bp, int *sptr)
*sp->cbpp++ = bp;
for (j = 0; j < blksinblk; j++)
sp->fip->fi_blocks[sp->fip->fi_nblocks++] = bp->b_lblkno +
(j << fs->lfs_fbshift);
sp->fip->fi_blocks[sp->fip->fi_nblocks++] = bp->b_lblkno + j;
sp->sum_bytes_left -= sizeof(int32_t);
sp->sum_bytes_left -= sizeof(int32_t) * blksinblk;
sp->seg_bytes_left -= bp->b_bcount;
return (0);
}
@ -1218,7 +1217,7 @@ loop: for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
*/
void
lfs_update_single(struct lfs *fs, struct segment *sp, daddr_t lbn,
int32_t ndaddr, int size, int num)
int32_t ndaddr, int size)
{
SEGUSE *sup;
struct buf *bp;
@ -1226,7 +1225,7 @@ lfs_update_single(struct lfs *fs, struct segment *sp, daddr_t lbn,
struct inode *ip;
struct vnode *vp;
daddr_t daddr, ooff;
int error;
int num, error;
int bb, osize, obb;
vp = sp->vp;
@ -1347,6 +1346,21 @@ lfs_updatemeta(struct segment *sp)
KASSERT(nblocks >= 0);
if (vp == NULL || nblocks == 0)
return;
/*
* This count may be high due to oversize blocks from lfs_gop_write.
* Correct for this. (XXX we should be able to keep track of these.)
*/
fs = sp->fs;
for (i = 0; i < nblocks; i++) {
if (sp->start_bpp[i] == NULL) {
printf("nblocks = %d, not %d\n", i, nblocks);
nblocks = i;
break;
}
num = howmany(sp->start_bpp[i]->b_bcount, fs->lfs_bsize);
nblocks -= num - 1;
}
/*
* Sort the blocks.
@ -1356,7 +1370,7 @@ lfs_updatemeta(struct segment *sp)
* same inode...and if we don't sort, and there are fragments
* present, blocks may be written in the wrong place.
*/
lfs_shellsort(sp->start_bpp, sp->start_lbp, nblocks);
lfs_shellsort(sp->start_bpp, sp->start_lbp, nblocks, fs->lfs_bsize);
/*
* Record the length of the last block in case it's a fragment.
@ -1369,7 +1383,6 @@ lfs_updatemeta(struct segment *sp)
* XXX true until lfs_markv is fixed to do everything with
* XXX fake blocks (including fake inodes and fake indirect blocks).
*/
fs = sp->fs;
sp->fip->fi_lastlength = ((sp->start_bpp[nblocks - 1]->b_bcount - 1) &
fs->lfs_bmask) + 1;
@ -1379,7 +1392,8 @@ lfs_updatemeta(struct segment *sp)
*/
for (i = nblocks; i--; ++sp->start_bpp) {
sbp = *sp->start_bpp;
lbn = *sp->start_lbp++;
lbn = *sp->start_lbp;
sbp->b_blkno = fsbtodb(fs, fs->lfs_offset);
/*
@ -1401,10 +1415,9 @@ lfs_updatemeta(struct segment *sp)
bytesleft -= fs->lfs_bsize) {
size = MIN(bytesleft, fs->lfs_bsize);
bb = fragstofsb(fs, numfrags(fs, size));
lfs_update_single(fs, sp, lbn, fs->lfs_offset,
size, num);
lbn = *sp->start_lbp++;
lfs_update_single(fs, sp, lbn, fs->lfs_offset, size);
fs->lfs_offset += bb;
++lbn;
}
}
@ -1499,7 +1512,7 @@ lfs_initseg(struct lfs *fs)
sp->seg_bytes_left -= fs->lfs_sumsize;
sp->sum_bytes_left = fs->lfs_sumsize - SEGSUM_SIZE(fs);
#ifndef LFS_MALLOC_SUMMARY
LFS_LOCK_BUF(sbp);
brelse(sbp);
@ -1599,8 +1612,6 @@ extern LIST_HEAD(bufhashhdr, buf) invalhash;
#define binshash(bp, dp) LIST_INSERT_HEAD(dp, bp, b_hash)
#define bremhash(bp) LIST_REMOVE(bp, b_hash)
extern int maxbpp;
static struct buf *
lfs_newclusterbuf(struct lfs *fs, struct vnode *vp, daddr_t addr, int n)
{
@ -1993,6 +2004,13 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
cbp->b_data = lfs_malloc(fs, CHUNKSIZE, LFS_NB_CLUSTER);
}
#if defined(DEBUG) && defined(DIAGNOSTIC)
if (bpp - sp->bpp > (fs->lfs_sumsize - SEGSUM_SIZE(fs))
/ sizeof(int32_t)) {
panic("lfs_writeseg: real bpp overwrite");
}
if (bpp - sp->bpp > fs->lfs_ssize / fs->lfs_fsize) {
panic("lfs_writeseg: theoretical bpp overwrite");
}
if(dtosn(fs, dbtofsb(fs, (*bpp)->b_blkno + btodb((*bpp)->b_bcount - 1))) !=
dtosn(fs, dbtofsb(fs, cbp->b_blkno))) {
printf("block at %" PRId64 " (%" PRIu32 "), "
@ -2459,27 +2477,31 @@ lfs_supercallback(struct buf *bp)
*/
void
lfs_shellsort(struct buf **bp_array, int32_t *lb_array, int nmemb)
lfs_shellsort(struct buf **bp_array, int32_t *lb_array, int nmemb, int size)
{
static int __rsshell_increments[] = { 4, 1, 0 };
int incr, *incrp, t1, t2;
struct buf *bp_temp;
u_int32_t lbt, *lba;
lba = (u_int32_t *)lb_array;
for (incrp = __rsshell_increments; (incr = *incrp++) != 0;)
for (t1 = incr; t1 < nmemb; ++t1)
for (t2 = t1 - incr; t2 >= 0;)
if (lba[t2] > lba[t2 + incr]) {
lbt = lba[t2];
lba[t2] = lba[t2 + incr];
lba[t2 + incr] = lbt;
if ((u_int32_t)bp_array[t2]->b_lblkno >
(u_int32_t)bp_array[t2 + incr]->b_lblkno) {
bp_temp = bp_array[t2];
bp_array[t2] = bp_array[t2 + incr];
bp_array[t2 + incr] = bp_temp;
t2 -= incr;
} else
break;
/* Reform the list of logical blocks */
incr = 0;
for (t1 = 0; t1 < nmemb; t1++) {
for (t2 = 0; t2 * size < bp_array[t1]->b_bcount; t2++) {
lb_array[incr++] = bp_array[t1]->b_lblkno + t2;
}
}
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_subr.c,v 1.33 2003/02/20 04:27:24 perseant Exp $ */
/* $NetBSD: lfs_subr.c,v 1.34 2003/02/23 00:22:34 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@ -71,7 +71,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_subr.c,v 1.33 2003/02/20 04:27:24 perseant Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_subr.c,v 1.34 2003/02/23 00:22:34 perseant Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -162,28 +162,32 @@ lfs_setup_resblks(struct lfs *fs)
* so we can't use the pool subsystem for them.
*/
for (i = 0, j = 0; j < LFS_N_SUMMARIES; j++, i++)
fs->lfs_resblk[i].p = malloc(fs->lfs_sumsize, M_SEGMENT,
M_WAITOK);
fs->lfs_resblk[i].size = fs->lfs_sumsize;
for (j = 0; j < LFS_N_SBLOCKS; j++, i++)
fs->lfs_resblk[i].p = malloc(LFS_SBPAD, M_SEGMENT, M_WAITOK);
fs->lfs_resblk[i].size = LFS_SBPAD;
for (j = 0; j < LFS_N_IBLOCKS; j++, i++)
fs->lfs_resblk[i].p = malloc(fs->lfs_bsize, M_SEGMENT, M_WAITOK);
fs->lfs_resblk[i].size = fs->lfs_bsize;
for (j = 0; j < LFS_N_CLUSTERS; j++, i++)
fs->lfs_resblk[i].p = malloc(MAXPHYS, M_SEGMENT, M_WAITOK);
fs->lfs_resblk[i].size = MAXPHYS;
for (j = 0; j < LFS_N_CLEAN; j++, i++)
fs->lfs_resblk[i].p = malloc(MAXPHYS, M_SEGMENT, M_WAITOK);
fs->lfs_resblk[i].size = MAXPHYS;
for (i = 0; i < LFS_N_TOTAL; i++) {
fs->lfs_resblk[i].p = malloc(fs->lfs_resblk[i].size,
M_SEGMENT, M_WAITOK);
}
/*
* Initialize pools for small types (XXX is BPP small?)
*/
maxbpp = ((fs->lfs_sumsize - SEGSUM_SIZE(fs)) / sizeof(int32_t) + 2);
maxbpp = MIN(maxbpp, fs->lfs_ssize / fs->lfs_fsize + 2);
pool_init(&fs->lfs_bpppool, maxbpp * sizeof(struct buf *), 0, 0,
LFS_N_BPP, "lfsbpppl", &pool_allocator_nointr);
pool_init(&fs->lfs_clpool, sizeof(struct lfs_cluster), 0, 0,
LFS_N_CL, "lfsclpl", &pool_allocator_nointr);
pool_init(&fs->lfs_segpool, sizeof(struct segment), 0, 0,
LFS_N_SEG, "lfssegpool", &pool_allocator_nointr);
maxbpp = ((fs->lfs_sumsize - SEGSUM_SIZE(fs)) / sizeof(int32_t) + 2);
maxbpp = MIN(maxbpp, fs->lfs_ssize / fs->lfs_fsize + 2);
pool_init(&fs->lfs_bpppool, maxbpp * sizeof(struct buf *), 0, 0,
LFS_N_BPP, "lfsbpppl", &pool_allocator_nointr);
}
void
@ -222,13 +226,18 @@ lfs_malloc(struct lfs *fs, size_t size, int type)
int i, s, start;
unsigned int h;
r = NULL;
/* If no mem allocated for this type, it just waits */
if (lfs_res_qty[type] == 0)
return malloc(size, M_SEGMENT, M_WAITOK);
if (lfs_res_qty[type] == 0) {
r = malloc(size, M_SEGMENT, M_WAITOK);
return r;
}
/* Otherwise try a quick malloc, and if it works, great */
if ((r = malloc(size, M_SEGMENT, M_NOWAIT)) != NULL)
if ((r = malloc(size, M_SEGMENT, M_NOWAIT)) != NULL) {
return r;
}
/*
* If malloc returned NULL, we are forced to use one of our
@ -245,6 +254,7 @@ lfs_malloc(struct lfs *fs, size_t size, int type)
re = fs->lfs_resblk + start + i;
re->inuse = 1;
r = re->p;
KASSERT(re->size >= size);
h = lfs_mhash(r);
s = splbio();
LIST_INSERT_HEAD(&fs->lfs_reshash[h], re, res);
@ -289,7 +299,7 @@ lfs_free(struct lfs *fs, void *p, int type)
#ifdef DEBUG
for (i = 0; i < LFS_N_TOTAL; i++) {
if (fs->lfs_resblk[i].p == p)
panic("lfs_free: inconsist reserved block");
panic("lfs_free: inconsistent reserved block");
}
#endif
splx(s);

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_vfsops.c,v 1.96 2003/02/20 04:27:25 perseant Exp $ */
/* $NetBSD: lfs_vfsops.c,v 1.97 2003/02/23 00:22:34 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@ -71,7 +71,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.96 2003/02/20 04:27:25 perseant Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.97 2003/02/23 00:22:34 perseant Exp $");
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
@ -1800,14 +1800,17 @@ lfs_gop_write(struct vnode *vp, struct vm_page **pgs, int npages, int flags)
#endif
uvm_lock_pageq();
for (i = 0; i < npages; i++) {
if (pgs[i]->flags & PG_WANTED)
wakeup(pgs[i]);
if (pgs[i]->flags & PG_PAGEOUT)
pg = pgs[i];
if (pg->flags & PG_WANTED)
wakeup(pg);
if (pg->flags & PG_PAGEOUT)
uvmexp.paging--;
if (pgs[i]->flags & PG_DELWRI) {
uvm_pageunwire(pgs[i]);
if (pg->flags & PG_DELWRI) {
uvm_pageunwire(pg);
uvm_pagedeactivate(pg);
}
pgs[i]->flags &= ~(PG_BUSY|PG_CLEAN|PG_WANTED|PG_DELWRI|PG_PAGEOUT|PG_RELEASED);
pg->flags &= ~(PG_BUSY|PG_CLEAN|PG_WANTED|PG_DELWRI|PG_PAGEOUT|PG_RELEASED);
UVM_PAGE_OWN(pg, NULL);
}
uvm_page_unbusy(pgs, npages);
@ -1908,10 +1911,9 @@ lfs_gop_write(struct vnode *vp, struct vm_page **pgs, int npages, int flags)
/*
* Discover how much we can really pack into this buffer.
*/
#ifdef LFS_UBC_BIGBUFS
/* If no room in the current segment, finish it up */
if (sp->sum_bytes_left < sizeof(int32_t) ||
sp->seg_bytes_left < MIN(iobytes, (1 << fs->lfs_bshift))) {
sp->seg_bytes_left < (1 << fs->lfs_bshift)) {
int version;
lfs_updatemeta(sp);
@ -1925,16 +1927,11 @@ lfs_gop_write(struct vnode *vp, struct vm_page **pgs, int npages, int flags)
++((SEGSUM *)(sp->segsum))->ss_nfinfo;
sp->sum_bytes_left -= FINFOSIZE;
}
iobytes = MIN(iobytes, ((sp->seg_bytes_left >> fs_bshift) << fs_bshift));
#else
iobytes = MIN(iobytes, (1 << fs_bshift));
if (iobytes != blksize(fs, ip, lblkno(fs, offset))) {
printf("iobytes = %" PRId64 ", blk = %" PRId64 "\n",
(int64_t)iobytes,
(int64_t)blksize(fs, ip, lblkno(fs, offset)));
}
KASSERT(iobytes == blksize(fs, ip, lblkno(fs, offset)));
#endif
/* Check both for space in segment and space in segsum */
iobytes = MIN(iobytes, (sp->seg_bytes_left >> fs_bshift)
<< fs_bshift);
iobytes = MIN(iobytes, (sp->sum_bytes_left / sizeof(int32_t))
<< fs_bshift);
KASSERT(iobytes > 0);
/* if it's really one i/o, don't make a second buf */

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_vnops.c,v 1.87 2003/02/22 01:52:25 yamt Exp $ */
/* $NetBSD: lfs_vnops.c,v 1.88 2003/02/23 00:22:35 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@ -71,7 +71,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,v 1.87 2003/02/22 01:52:25 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,v 1.88 2003/02/23 00:22:35 perseant Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -1132,11 +1132,9 @@ check_dirty(struct lfs *fs, struct vnode *vp,
/*
* If any are dirty make all dirty; unbusy them,
* but if we were asked to clean, take them off
* of their queue so the pagedaemon doesn't bother
* us about them while they're on their way to disk.
*
* (XXXUBC the page is now on *no* page queue.)
* but if we were asked to clean, wire them so that
* the pagedaemon doesn't bother us about them while
* they're on their way to disk.
*/
for (i = 0; i == 0 || i < pages_per_block; i++) {
pg = pgs[i];
@ -1153,6 +1151,7 @@ check_dirty(struct lfs *fs, struct vnode *vp,
uvm_lock_pageq();
uvm_pagewire(pg);
uvm_unlock_pageq();
/* Suspended write flag */
pg->flags |= PG_DELWRI;
}
@ -1406,13 +1405,6 @@ lfs_putpages(void *v)
sp = fs->lfs_sp;
sp->vp = vp;
/*
* XXXUBC
* There is some danger here that we might run out of
* buffers if we flush too much at once. If the number
* of dirty buffers is too great, we should cut the range
* down and write in chunks.
*/
while ((error = genfs_putpages(v)) == EDEADLK) {
#ifdef DEBUG_LFS
printf("lfs_putpages: genfs_putpages returned EDEADLK"
@ -1420,6 +1412,12 @@ lfs_putpages(void *v)
ip->i_number, fs->lfs_offset,
dtosn(fs, fs->lfs_offset));
#endif
/* If nothing to write, short-circuit */
if (sp->cbpp - sp->bpp == 1) {
preempt(NULL);
simple_lock(&vp->v_interlock);
continue;
}
/* Write gathered pages */
lfs_updatemeta(sp);
(void) lfs_writeseg(fs, sp);
@ -1476,17 +1474,8 @@ lfs_putpages(void *v)
/*
* Loop through genfs_putpages until all pages are gathered.
* genfs_putpages() drops the interlock, so reacquire it if necessary.
*/
/*
* There is some danger here that we might run out of
* buffers if we flush too much at once. If the number
* of dirty buffers is too great, then, cut the range down
* and write in chunks.
*
* XXXUBC this assumes a uniform dirtying of the pages
* XXXUBC across the address space
* XXXXXX do this
*/
simple_lock(&vp->v_interlock);
while ((error = genfs_putpages(v)) == EDEADLK) {
#ifdef DEBUG_LFS
@ -1495,6 +1484,12 @@ lfs_putpages(void *v)
ip->i_number, fs->lfs_offset,
dtosn(fs, fs->lfs_offset));
#endif
/* If nothing to write, short-circuit */
if (sp->cbpp - sp->bpp == 1) {
preempt(NULL);
simple_lock(&vp->v_interlock);
continue;
}
/* Write gathered pages */
lfs_updatemeta(sp);
(void) lfs_writeseg(fs, sp);
@ -1522,11 +1517,9 @@ lfs_putpages(void *v)
*/
lfs_updatemeta(fs->lfs_sp);
fs->lfs_sp->vp = NULL;
lfs_writeseg(fs, fs->lfs_sp);
/*
* Clean up FIP.
* (This should duplicate cleanup at the end of lfs_writefile().)
* Clean up FIP, since we're done writing this file.
* This should duplicate cleanup at the end of lfs_writefile().
*/
if (sp->fip->fi_nblocks != 0) {
sp->fip = (FINFO*)((caddr_t)sp->fip + sizeof(struct finfo) +
@ -1536,6 +1529,8 @@ lfs_putpages(void *v)
sp->sum_bytes_left += sizeof(FINFO) - sizeof(int32_t);
--((SEGSUM *)(sp->segsum))->ss_nfinfo;
}
lfs_writeseg(fs, fs->lfs_sp);
/*
* XXX - with the malloc/copy writeseg, the pages are freed by now
* even if we don't wait (e.g. if we hold a nested lock). This