Introduce another per-filesystem parameter, lfs_resvseg, to separate the

notion of "how many segments are reserved for the cleaner" from that of
"how many segments are not counted in lfs_bfree".  The default value
used for existing filesystems is the same as the previous implicit value
of (lfs_minfreeseg / 2 + 1), modulo some sanity checking.

Count pending dirops on a per-filesystem basis, since once we start
writing them we can't stop until we're done.  This seems to help stave off
the "no clean segments" panic in the case of filling the filesystem with
directories and small files (e.g. simultaneously unpacking more copies of
pkgsrc than will fit).
This commit is contained in:
perseant 2006-05-04 04:22:55 +00:00
parent 5754da5b7f
commit ce053245eb
6 changed files with 40 additions and 15 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs.h,v 1.104 2006/04/30 21:19:42 perseant Exp $ */
/* $NetBSD: lfs.h,v 1.105 2006/05/04 04:22:55 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@ -96,7 +96,8 @@
#define LFS_MAXNAMLEN 255 /* maximum name length in a dir */
/* Adjustable filesystem parameters */
#define MIN_FREE_SEGS 2
#define MIN_FREE_SEGS 20
#define MIN_RESV_SEGS 15
#ifndef LFS_ATIME_IFILE
# define LFS_ATIME_IFILE 0 /* Store atime info in ifile (optional in LFSv1) */
#endif
@ -114,6 +115,11 @@
#define LFS_INVERSE_MAX_BYTES(n) (((n) + 10 * PAGE_SIZE) << 2)
#define LFS_WAIT_BYTES ((bufmem_lowater >> 1) - (bufmem_lowater >> 3) - 10 * PAGE_SIZE)
#define LFS_MAX_DIROP ((desiredvnodes >> 2) + (desiredvnodes >> 3))
#define SIZEOF_DIROP(fs) ((fs)->lfs_fsize + 2 * DINODE1_SIZE)
#define LFS_MAX_FSDIROP(fs) \
((fs)->lfs_nclean <= (fs)->lfs_resvseg ? 0 : \
(((fs)->lfs_nclean - (fs)->lfs_resvseg) * (fs)->lfs_ssize) / \
(2 * SIZEOF_DIROP(fs)))
#define LFS_MAX_PAGES \
(((uvmexp.active + uvmexp.inactive + uvmexp.free) * uvmexp.filemin) >> 8)
#define LFS_WAIT_PAGES \
@ -121,7 +127,7 @@
#define LFS_BUFWAIT 2 /* How long to wait if over *_WAIT_* */
/* How starved can we be before we start holding back page writes */
#define LFS_STARVED_FOR_SEGS(fs) ((fs)->lfs_nclean < (fs)->lfs_minfreeseg / 2 + 1)
#define LFS_STARVED_FOR_SEGS(fs) ((fs)->lfs_nclean < (fs)->lfs_resvseg)
/*
* Reserved blocks for lfs_malloc
@ -680,7 +686,7 @@ struct dlfs {
#define LFS_PF_CLEAN 0x1
u_int16_t dlfs_pflags; /* 322: file system persistent flags */
int32_t dlfs_dmeta; /* 324: total number of dirty summaries */
u_int32_t dlfs_minfreeseg; /* 328: segs reserved for cleaner */
u_int32_t dlfs_minfreeseg; /* 328: segments not counted in bfree */
u_int32_t dlfs_sumsize; /* 332: size of summary blocks */
u_int64_t dlfs_serial; /* 336: serial number */
u_int32_t dlfs_ibsize; /* 344: size of inode blocks */
@ -692,7 +698,8 @@ struct dlfs {
u_int32_t dlfs_interleave; /* 364: segment interleave */
u_int32_t dlfs_ident; /* 368: per-fs identifier */
u_int32_t dlfs_fsbtodb; /* 372: fsbtodb abd dbtodsb shift constant */
int8_t dlfs_pad[132]; /* 376: round to 512 bytes */
u_int32_t dlfs_resvseg; /* 376: segments reserved for the cleaner */
int8_t dlfs_pad[128]; /* 380: round to 512 bytes */
/* Checksum -- last valid disk field. */
u_int32_t dlfs_cksum; /* 508: checksum for superblock checking */
};
@ -775,6 +782,7 @@ struct lfs {
#define lfs_inodefmt lfs_dlfs.dlfs_inodefmt
#define lfs_interleave lfs_dlfs.dlfs_interleave
#define lfs_ident lfs_dlfs.dlfs_ident
#define lfs_resvseg lfs_dlfs.dlfs_resvseg
/* These fields are set at mount time and are meaningless on disk. */
struct segment *lfs_sp; /* current segment being written */
@ -785,6 +793,7 @@ struct lfs {
u_int32_t lfs_iocount; /* number of ios pending */
u_int32_t lfs_writer; /* don't allow any dirops to start */
u_int32_t lfs_dirops; /* count of active directory ops */
u_int32_t lfs_dirvcount; /* count of VDIROP nodes in this fs */
u_int32_t lfs_doifile; /* Write ifile blocks on next write */
u_int32_t lfs_nactive; /* Number of segments since last ckp */
int8_t lfs_fmod; /* super block modified flag */

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_alloc.c,v 1.91 2006/04/30 21:59:58 perseant Exp $ */
/* $NetBSD: lfs_alloc.c,v 1.92 2006/05/04 04:22:55 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_alloc.c,v 1.91 2006/04/30 21:59:58 perseant Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_alloc.c,v 1.92 2006/05/04 04:22:55 perseant Exp $");
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
@ -227,7 +227,10 @@ lfs_rf_valloc(struct lfs *fs, ino_t ino, int vers, struct lwp *l,
simple_lock(&lfs_subsys_lock);
--lfs_dirvcount;
simple_unlock(&lfs_subsys_lock);
--fs->lfs_dirvcount;
TAILQ_REMOVE(&fs->lfs_dchainhd, ip, i_lfs_dchain);
wakeup(&lfs_dirvcount);
wakeup(&fs->lfs_dirvcount);
simple_unlock(&fs->lfs_interlock);
}
*vpp = vp;
@ -585,8 +588,10 @@ lfs_vfree(struct vnode *vp, ino_t ino, int mode)
simple_lock(&lfs_subsys_lock);
--lfs_dirvcount;
simple_unlock(&lfs_subsys_lock);
--fs->lfs_dirvcount;
TAILQ_REMOVE(&fs->lfs_dchainhd, ip, i_lfs_dchain);
simple_unlock(&fs->lfs_interlock);
wakeup(&fs->lfs_dirvcount);
wakeup(&lfs_dirvcount);
lfs_vunref(vp);

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_bio.c,v 1.91 2006/04/13 23:46:28 perseant Exp $ */
/* $NetBSD: lfs_bio.c,v 1.92 2006/05/04 04:22:55 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_bio.c,v 1.91 2006/04/13 23:46:28 perseant Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_bio.c,v 1.92 2006/05/04 04:22:55 perseant Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -651,6 +651,7 @@ lfs_check(struct vnode *vp, daddr_t blkno, int flags)
(locked_queue_count + INOCOUNT(fs) > LFS_MAX_BUFS ||
locked_queue_bytes + INOBYTES(fs) > LFS_MAX_BYTES ||
lfs_subsys_pages > LFS_MAX_PAGES ||
fs->lfs_dirvcount > LFS_MAX_FSDIROP(fs) ||
lfs_dirvcount > LFS_MAX_DIROP || fs->lfs_diropwait > 0))
{
simple_unlock(&lfs_subsys_lock);
@ -677,6 +678,9 @@ lfs_check(struct vnode *vp, daddr_t blkno, int flags)
if (lfs_dirvcount > LFS_MAX_DIROP)
DLOG((DLOG_FLUSH, "lfs_check: ldvc = %d, max %d\n",
lfs_dirvcount, LFS_MAX_DIROP));
if (fs->lfs_dirvcount > LFS_MAX_FSDIROP(fs))
DLOG((DLOG_FLUSH, "lfs_check: lfdvc = %d, max %d\n",
fs->lfs_dirvcount, LFS_MAX_FSDIROP(fs)));
if (fs->lfs_diropwait > 0)
DLOG((DLOG_FLUSH, "lfs_check: ldvw = %d\n",
fs->lfs_diropwait));
@ -685,6 +689,7 @@ lfs_check(struct vnode *vp, daddr_t blkno, int flags)
if (locked_queue_count + INOCOUNT(fs) > LFS_MAX_BUFS ||
locked_queue_bytes + INOBYTES(fs) > LFS_MAX_BYTES ||
lfs_subsys_pages > LFS_MAX_PAGES ||
fs->lfs_dirvcount > LFS_MAX_FSDIROP(fs) ||
lfs_dirvcount > LFS_MAX_DIROP || fs->lfs_diropwait > 0) {
simple_unlock(&fs->lfs_interlock);
lfs_flush(fs, flags, 0);
@ -702,6 +707,7 @@ lfs_check(struct vnode *vp, daddr_t blkno, int flags)
while (locked_queue_count + INOCOUNT(fs) > LFS_WAIT_BUFS ||
locked_queue_bytes + INOBYTES(fs) > LFS_WAIT_BYTES ||
lfs_subsys_pages > LFS_WAIT_PAGES ||
fs->lfs_dirvcount > LFS_MAX_FSDIROP(fs) ||
lfs_dirvcount > LFS_MAX_DIROP) {
if (lfs_dostats)

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_subr.c,v 1.58 2006/04/07 23:44:14 perseant Exp $ */
/* $NetBSD: lfs_subr.c,v 1.59 2006/05/04 04:22:57 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_subr.c,v 1.58 2006/04/07 23:44:14 perseant Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_subr.c,v 1.59 2006/05/04 04:22:57 perseant Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -381,6 +381,7 @@ lfs_unmark_dirop(struct lfs *fs)
simple_lock(&lfs_subsys_lock);
--lfs_dirvcount;
simple_unlock(&lfs_subsys_lock);
--fs->lfs_dirvcount;
vp->v_flag &= ~VDIROP;
TAILQ_REMOVE(&fs->lfs_dchainhd, ip, i_lfs_dchain);
simple_unlock(&fs->lfs_interlock);

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_vfsops.c,v 1.206 2006/04/30 21:19:42 perseant Exp $ */
/* $NetBSD: lfs_vfsops.c,v 1.207 2006/05/04 04:22:57 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.206 2006/04/30 21:19:42 perseant Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.207 2006/05/04 04:22:57 perseant Exp $");
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
@ -1053,6 +1053,9 @@ lfs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
fs->lfs_tstamp = fs->lfs_otstamp;
fs->lfs_fsbtodb = 0;
}
if (fs->lfs_resvseg == 0)
fs->lfs_resvseg = MIN(fs->lfs_minfreeseg - 1, \
MAX(MIN_RESV_SEGS, fs->lfs_minfreeseg / 2 + 1));
/*
* If we aren't going to be able to write meaningfully to this

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_vnops.c,v 1.172 2006/05/02 00:52:26 perseant Exp $ */
/* $NetBSD: lfs_vnops.c,v 1.173 2006/05/04 04:22:57 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,v 1.172 2006/05/02 00:52:26 perseant Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,v 1.173 2006/05/04 04:22:57 perseant Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -512,6 +512,7 @@ lfs_mark_vnode(struct vnode *vp)
(void)lfs_vref(vp);
simple_lock(&lfs_subsys_lock);
++lfs_dirvcount;
++fs->lfs_dirvcount;
simple_unlock(&lfs_subsys_lock);
TAILQ_INSERT_TAIL(&fs->lfs_dchainhd, ip, i_lfs_dchain);
vp->v_flag |= VDIROP;