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:
parent
6bce155b9e
commit
3ab94fed93
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user