Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/ufs/lfs Correct accounting of lfs_avail, locked_queue_co...
details: https://anonhg.NetBSD.org/src/rev/eb3582a8e9cf
branches: trunk
changeset: 499343:eb3582a8e9cf
user: perseant <perseant%NetBSD.org@localhost>
date: Fri Nov 17 19:14:41 2000 +0000
description:
Correct accounting of lfs_avail, locked_queue_count, and locked_queue_bytes.
(PR #11468). In the case of fragment allocation, check to see if enough
space is available before extending a fragment already scheduled for writing.
The locked_queue_* variables indicate the number of buffer headers and bytes,
respectively, that are unavailable to getnewbuf() because they are locked up
waiting for LFS to flush them; make sure that that is actually what we're
counting, i.e., never count malloced buffers, and always use b_bufsize instead
of b_bcount.
If DEBUG is defined, the periodic calls to lfs_countlocked will now complain
if either counter is incorrect. (In the future lfs_countlocked will not need
to be called at all if DEBUG is not defined.)
diffstat:
sys/ufs/lfs/TODO | 13 +-----
sys/ufs/lfs/lfs.h | 32 +++++++++++++++-
sys/ufs/lfs/lfs_balloc.c | 36 +++++++++++++++--
sys/ufs/lfs/lfs_bio.c | 95 +++++++++++++++++++++++----------------------
sys/ufs/lfs/lfs_extern.h | 4 +-
sys/ufs/lfs/lfs_inode.c | 14 +-----
sys/ufs/lfs/lfs_segment.c | 42 +++++++++++++-------
sys/ufs/lfs/lfs_syscalls.c | 3 +-
sys/ufs/lfs/lfs_vnops.c | 6 +-
9 files changed, 149 insertions(+), 96 deletions(-)
diffs (truncated from 562 to 300 lines):
diff -r 627f537bc58c -r eb3582a8e9cf sys/ufs/lfs/TODO
--- a/sys/ufs/lfs/TODO Fri Nov 17 19:08:00 2000 +0000
+++ b/sys/ufs/lfs/TODO Fri Nov 17 19:14:41 2000 +0000
@@ -1,10 +1,10 @@
-# $NetBSD: TODO,v 1.3 1999/03/15 00:46:47 perseant Exp $
+# $NetBSD: TODO,v 1.4 2000/11/17 19:14:41 perseant Exp $
- If we put an LFS onto a striped disk, we want to be able to specify
the segment size to be equal to the stripe size, regardless of whether
this is a power of two; also, the first segment should just eat the
label pad, like the segments eat the superblocks. Then, we could
- neatly lay out the segments along stripe boundaries.
+ neatly lay out the segments along stripe boundaries. [v2]
- Working fsck_lfs. (Have something that will verify, need something
that will fix too. Really, need a general-purpose external
@@ -14,10 +14,6 @@
checkpoint (easy) but also to create a valid checkpoint for
post-checkpoint writes (requires an external partial-segment writer).
-- Blocks created in the cache are currently not marked in any way,
- except that b_blkno == b_lblkno, which can happen naturally too. LFS
- needs to know for accounting.
-
- Inode blocks are currently the same size as the fs block size; but all
the ones I've seen are mostly empty, and this will be especially true
if atime information is kept in the ifile instead of the inode. Could
@@ -67,11 +63,6 @@
perhaps keep the name, replace the function. Could it count referenced
vnodes as well, if it was in vfs_subr.c instead?
-- If we clean a DIROP vnode, and we toss a fake buffer in favor of a
- pending held real buffer, we risk writing part of the dirop during a
- synchronous checkpoint. This is bad. Now that we're doing `stingy'
- cleaning, is there a good reason to favor real blocks over fake ones?
-
- Why not delete the lfs_bmapv call, just mark everything dirty that
isn't deleted/truncated? Get some numbers about what percentage of
the stuff that the cleaner thinks might be live is live. If it's
diff -r 627f537bc58c -r eb3582a8e9cf sys/ufs/lfs/lfs.h
--- a/sys/ufs/lfs/lfs.h Fri Nov 17 19:08:00 2000 +0000
+++ b/sys/ufs/lfs/lfs.h Fri Nov 17 19:14:41 2000 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: lfs.h,v 1.34 2000/11/13 00:24:30 perseant Exp $ */
+/* $NetBSD: lfs.h,v 1.35 2000/11/17 19:14:41 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@@ -89,6 +89,36 @@
#define LFS_MAX_ACTIVE 10
#define LFS_MAXDIROP (desiredvnodes>>2)
+/*
+ * #define WRITE_THRESHHOLD ((nbuf >> 1) - 10)
+ * #define WAIT_THRESHHOLD (nbuf - (nbuf >> 2) - 10)
+ */
+#define LFS_MAX_BUFS ((nbuf >> 2) - 10)
+#define LFS_WAIT_BUFS ((nbuf >> 1) - (nbuf >> 3) - 10)
+/* These are new ... is LFS taking up too much memory in its buffers? */
+#define LFS_MAX_BYTES (((bufpages >> 2) - 10) * NBPG)
+#define LFS_WAIT_BYTES (((bufpages >> 1) - (bufpages >> 3) - 10) * NBPG)
+#define LFS_BUFWAIT 2
+
+#define LFS_LOCK_BUF(bp) do { \
+ if (((bp)->b_flags & (B_LOCKED | B_CALL)) == 0) { \
+ ++locked_queue_count; \
+ locked_queue_bytes += bp->b_bufsize; \
+ } \
+ (bp)->b_flags |= B_LOCKED; \
+} while(0)
+
+#define LFS_UNLOCK_BUF(bp) do { \
+ if (((bp)->b_flags & (B_LOCKED | B_CALL)) == B_LOCKED) { \
+ --locked_queue_count; \
+ locked_queue_bytes -= bp->b_bufsize; \
+ if (locked_queue_count < LFS_WAIT_BUFS && \
+ locked_queue_bytes < LFS_WAIT_BYTES) \
+ wakeup(&locked_queue_count); \
+ } \
+ (bp)->b_flags &= ~B_LOCKED; \
+} while(0)
+
/* For convenience */
#define IN_ALLMOD (IN_MODIFIED|IN_ACCESS|IN_CHANGE|IN_UPDATE|IN_ACCESSED|IN_CLEANING)
#define LFS_SET_UINO(ip, flags) do { \
diff -r 627f537bc58c -r eb3582a8e9cf sys/ufs/lfs/lfs_balloc.c
--- a/sys/ufs/lfs/lfs_balloc.c Fri Nov 17 19:08:00 2000 +0000
+++ b/sys/ufs/lfs/lfs_balloc.c Fri Nov 17 19:14:41 2000 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: lfs_balloc.c,v 1.25 2000/09/09 04:49:54 perseant Exp $ */
+/* $NetBSD: lfs_balloc.c,v 1.26 2000/11/17 19:14:41 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@@ -344,6 +344,7 @@
int error;
extern long locked_queue_bytes;
struct buf *ibp;
+ size_t obufsize;
SEGUSE *sup;
ip = VTOI(vp);
@@ -355,6 +356,7 @@
* Get the seglock so we don't enlarge blocks or change the segment
* accounting information while a segment is being written.
*/
+ top:
lfs_seglock(fs, SEGM_PROT);
if (!ISSPACE(fs, bb, curproc->p_ucred)) {
@@ -372,23 +374,47 @@
}
#endif
/*
+ * Adjust accounting for lfs_avail. If there's not enough room,
+ * we will have to wait for the cleaner, which we can't do while
+ * holding a block busy or while holding the seglock. In that case,
+ * release both and start over after waiting.
+ */
+ if ((*bpp)->b_flags & B_DELWRI) {
+ if (!lfs_fits(fs, bb)) {
+ brelse(*bpp);
+#ifdef QUOTA
+ chkdq(ip, -bb, curproc->p_ucred, 0);
+#endif
+ lfs_segunlock(fs);
+ lfs_availwait(fs, bb);
+ goto top;
+ }
+ fs->lfs_avail -= bb;
+ }
+
+ /*
* Fix the allocation for this fragment so that it looks like the
* source segment contained a block of the new size. This overcounts;
* but the overcount only lasts until the block in question
* is written, so the on-disk live bytes count is always correct.
*/
if ((*bpp)->b_blkno > 0) {
- LFS_SEGENTRY(sup, fs, datosn(fs,(*bpp)->b_blkno), ibp);
- sup->su_nbytes += (nsize-osize);
+ LFS_SEGENTRY(sup, fs, datosn(fs, (*bpp)->b_blkno), ibp);
+ sup->su_nbytes += (nsize - osize);
VOP_BWRITE(ibp);
ip->i_ffs_blocks += bb;
}
fs->lfs_bfree -= bb;
ip->i_lfs_effnblks += bb;
ip->i_flag |= IN_CHANGE | IN_UPDATE;
- if((*bpp)->b_flags & B_LOCKED)
- locked_queue_bytes += (nsize - osize);
+
+ obufsize = (*bpp)->b_bufsize;
allocbuf(*bpp, nsize);
+
+ /* Adjust locked-list accounting */
+ if (((*bpp)->b_flags & (B_LOCKED | B_CALL)) == B_LOCKED)
+ locked_queue_bytes += btodb((*bpp)->b_bufsize - obufsize);
+
bzero((char *)((*bpp)->b_data) + osize, (u_int)(nsize - osize));
out:
diff -r 627f537bc58c -r eb3582a8e9cf sys/ufs/lfs/lfs_bio.c
--- a/sys/ufs/lfs/lfs_bio.c Fri Nov 17 19:08:00 2000 +0000
+++ b/sys/ufs/lfs/lfs_bio.c Fri Nov 17 19:14:41 2000 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: lfs_bio.c,v 1.31 2000/11/12 07:58:36 perseant Exp $ */
+/* $NetBSD: lfs_bio.c,v 1.32 2000/11/17 19:14:41 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@@ -107,20 +107,6 @@
because of buffer space */
extern int lfs_dostats;
-
-/*
- * #define WRITE_THRESHHOLD ((nbuf >> 1) - 10)
- * #define WAIT_THRESHHOLD (nbuf - (nbuf >> 2) - 10)
- */
-#define LFS_MAX_BUFS ((nbuf >> 2) - 10)
-#define LFS_WAIT_BUFS ((nbuf >> 1) - (nbuf >> 3) - 10)
-/* These are new ... is LFS taking up too much memory in its buffers? */
-#define LFS_MAX_BYTES (((bufpages >> 2) - 10) * NBPG)
-#define LFS_WAIT_BYTES (((bufpages >> 1) - (bufpages >> 3) - 10) * NBPG)
-#define LFS_BUFWAIT 2
-
-inline static int lfs_fits(struct lfs *, int);
-
/*
* Try to reserve some blocks, prior to performing a sensitive operation that
* requires the vnode lock to be honored. If there is not enough space, give
@@ -208,7 +194,7 @@
* inode blocks, a summary block, plus potentially the ifile inode and
* the segment usage table, plus an ifile page.
*/
-inline static int
+int
lfs_fits(struct lfs *fs, int db)
{
int needed;
@@ -229,6 +215,41 @@
}
int
+lfs_availwait(fs, db)
+ struct lfs *fs;
+ int db;
+{
+ int error;
+ CLEANERINFO *cip;
+ struct buf *cbp;
+
+ while (!lfs_fits(fs, db)) {
+ /*
+ * Out of space, need cleaner to run.
+ * Update the cleaner info, then wake it up.
+ * Note the cleanerinfo block is on the ifile
+ * so it CANT_WAIT.
+ */
+ LFS_CLEANERINFO(cip, fs, cbp);
+ LFS_SYNC_CLEANERINFO(cip, fs, cbp, 0);
+
+ printf("lfs_availwait: out of available space, "
+ "waiting on cleaner\n");
+
+ wakeup(&lfs_allclean_wakeup);
+ wakeup(&fs->lfs_nextseg);
+#ifdef DIAGNOSTIC
+ if (fs->lfs_seglock && fs->lfs_lockpid == curproc->p_pid)
+ panic("lfs_availwait: deadlock");
+#endif
+ error = tsleep(&fs->lfs_avail, PCATCH | PUSER, "cleaner", 0);
+ if (error)
+ return (error);
+ }
+ return 0;
+}
+
+int
lfs_bwrite_ext(bp, flags)
struct buf *bp;
int flags;
@@ -236,15 +257,14 @@
struct lfs *fs;
struct inode *ip;
int db, error, s;
- struct buf *cbp;
- CLEANERINFO *cip;
/*
* Don't write *any* blocks if we're mounted read-only.
* In particular the cleaner can't write blocks either.
*/
if(VTOI(bp->b_vp)->i_lfs->lfs_ronly) {
- bp->b_flags &= ~(B_DELWRI|B_LOCKED|B_READ|B_ERROR);
+ bp->b_flags &= ~(B_DELWRI | B_READ | B_ERROR);
+ LFS_UNLOCK_BUF(bp);
if(bp->b_flags & B_CALL)
bp->b_flags &= ~B_BUSY;
else
@@ -269,27 +289,10 @@
if (!(bp->b_flags & B_LOCKED)) {
fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs;
db = fragstodb(fs, numfrags(fs, bp->b_bcount));
- while (!lfs_fits(fs, db) && !CANT_WAIT(bp,flags)) {
- /*
- * Out of space, need cleaner to run.
- * Update the cleaner info, then wake it up.
- * Note the cleanerinfo block is on the ifile
- * so it CANT_WAIT.
- */
- LFS_CLEANERINFO(cip, fs, cbp);
- LFS_SYNC_CLEANERINFO(cip, fs, cbp, 0);
-
- printf("lfs_bwrite: out of available space, "
- "waiting on cleaner\n");
-
- wakeup(&lfs_allclean_wakeup);
- wakeup(&fs->lfs_nextseg);
- error = tsleep(&fs->lfs_avail, PCATCH | PUSER,
- "cleaner", 0);
- if (error) {
- /* printf("lfs_bwrite: error in tsleep"); */
+ if (!CANT_WAIT(bp, flags)) {
+ if ((error = lfs_availwait(fs, db)) != 0) {
brelse(bp);
- return (error);
+ return error;
}
}
@@ -300,11 +303,11 @@
LFS_SET_UINO(ip, IN_CHANGE | IN_MODIFIED | IN_UPDATE);
}
fs->lfs_avail -= db;
- ++locked_queue_count;
- locked_queue_bytes += bp->b_bufsize;
+ bp->b_flags |= B_DELWRI;
+
Home |
Main Index |
Thread Index |
Old Index