Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/ufs/lfs Fix a buffer overflow bug in the LFS_UBC case th...
details: https://anonhg.NetBSD.org/src/rev/12325cae9bb4
branches: trunk
changeset: 543311:12325cae9bb4
user: perseant <perseant%NetBSD.org@localhost>
date: Sun Feb 23 00:22:33 2003 +0000
description:
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.
diffstat:
sys/ufs/lfs/TODO | 12 ++++----
sys/ufs/lfs/lfs.h | 7 ++--
sys/ufs/lfs/lfs_extern.h | 6 ++--
sys/ufs/lfs/lfs_segment.c | 70 ++++++++++++++++++++++++++++++----------------
sys/ufs/lfs/lfs_subr.c | 42 +++++++++++++++++----------
sys/ufs/lfs/lfs_vfsops.c | 37 +++++++++++-------------
sys/ufs/lfs/lfs_vnops.c | 51 +++++++++++++++------------------
7 files changed, 125 insertions(+), 100 deletions(-)
diffs (truncated from 573 to 300 lines):
diff -r 3efbd539618d -r 12325cae9bb4 sys/ufs/lfs/TODO
--- a/sys/ufs/lfs/TODO Sat Feb 22 23:46:46 2003 +0000
+++ b/sys/ufs/lfs/TODO Sun Feb 23 00:22:33 2003 +0000
@@ -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
diff -r 3efbd539618d -r 12325cae9bb4 sys/ufs/lfs/lfs.h
--- a/sys/ufs/lfs/lfs.h Sat Feb 22 23:46:46 2003 +0000
+++ b/sys/ufs/lfs/lfs.h Sun Feb 23 00:22:33 2003 +0000
@@ -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 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 */
diff -r 3efbd539618d -r 12325cae9bb4 sys/ufs/lfs/lfs_extern.h
--- a/sys/ufs/lfs/lfs_extern.h Sat Feb 22 23:46:46 2003 +0000
+++ b/sys/ufs/lfs/lfs_extern.h Sun Feb 23 00:22:33 2003 +0000
@@ -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 @@
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 @@
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 *);
diff -r 3efbd539618d -r 12325cae9bb4 sys/ufs/lfs/lfs_segment.c
--- a/sys/ufs/lfs/lfs_segment.c Sat Feb 22 23:46:46 2003 +0000
+++ b/sys/ufs/lfs/lfs_segment.c Sun Feb 23 00:22:33 2003 +0000
@@ -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_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 @@
*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 @@
*/
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 @@
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 @@
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 @@
* 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 @@
* 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 @@
*/
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 @@
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 @@
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 @@
#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 @@
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 @@
*/
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;
+ }
+ }
}
/*
diff -r 3efbd539618d -r 12325cae9bb4 sys/ufs/lfs/lfs_subr.c
--- a/sys/ufs/lfs/lfs_subr.c Sat Feb 22 23:46:46 2003 +0000
+++ b/sys/ufs/lfs/lfs_subr.c Sun Feb 23 00:22:33 2003 +0000
@@ -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 @@
* 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++)
Home |
Main Index |
Thread Index |
Old Index