For synchronous writes, keep separate i/o counters for each write, so

processes don't have to wait for one another to finish (e.g., nfsd seems
to be a little happier now, though I haven't measured the difference).
Synchronous checkpoints, however, must always wait for all i/o to finish.

Take the contents of the callback functions and have them run in thread
context instead (aiodoned thread).  lfs_iocount no longer has to be
protected in splbio(), and quite a bit less of the segment construction
loop needs to be in splbio() as well.

If lfs_markv is handed a block that is not the correct size according to
the inode, refuse to process it.  (Formerly it was extended to the "correct"
size.)  This is possibly more prone to deadlock, but less prone to corruption.

lfs_segclean now outright refuses to clean segments that appear to have live
bytes in them.  Again this may be more prone to deadlock but avoids
corruption.

Replace ufsspec_close and ufsfifo_close with LFS equivalents; this means
that no UFS functions need to know about LFS_ITIMES any more.  Remove
the reference from ufs/inode.h.

Tested on i386, test-compiled on alpha.
This commit is contained in:
perseant 2002-06-16 00:13:15 +00:00
parent 9ed8a29685
commit ddfb1dbb92
9 changed files with 222 additions and 124 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs.h,v 1.39 2002/05/14 20:03:53 perseant Exp $ */ /* $NetBSD: lfs.h,v 1.40 2002/06/16 00:13:15 perseant Exp $ */
/*- /*-
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@ -765,6 +765,7 @@ struct segment {
#define SEGM_SYNC 0x04 /* wait for segment */ #define SEGM_SYNC 0x04 /* wait for segment */
#define SEGM_PROT 0x08 /* don't inactivate at segunlock */ #define SEGM_PROT 0x08 /* don't inactivate at segunlock */
u_int16_t seg_flags; /* run-time flags for this segment */ u_int16_t seg_flags; /* run-time flags for this segment */
u_int32_t seg_iocount; /* number of ios pending */
}; };
struct lfs_cluster { struct lfs_cluster {
@ -773,8 +774,10 @@ struct lfs_cluster {
size_t bufsize; /* Size of kept data */ size_t bufsize; /* Size of kept data */
#define LFS_CL_MALLOC 0x00000001 #define LFS_CL_MALLOC 0x00000001
#define LFS_CL_SHIFT 0x00000002 #define LFS_CL_SHIFT 0x00000002
#define LFS_CL_SYNC 0x00000004
u_int32_t flags; /* Flags */ u_int32_t flags; /* Flags */
struct lfs *fs; /* LFS that this belongs to */ struct lfs *fs; /* LFS that this belongs to */
struct segment *seg; /* Segment structure, for LFS_CL_SYNC */
void *saveaddr; /* Original contents of saveaddr */ void *saveaddr; /* Original contents of saveaddr */
char *olddata; /* Original b_data, if LFS_CL_MALLOC */ char *olddata; /* Original b_data, if LFS_CL_MALLOC */
}; };

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_cksum.c,v 1.19 2001/11/15 09:48:29 lukem Exp $ */ /* $NetBSD: lfs_cksum.c,v 1.20 2002/06/16 00:13:15 perseant Exp $ */
/*- /*-
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@ -71,7 +71,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_cksum.c,v 1.19 2001/11/15 09:48:29 lukem Exp $"); __KERNEL_RCSID(0, "$NetBSD: lfs_cksum.c,v 1.20 2002/06/16 00:13:15 perseant Exp $");
#include <sys/param.h> #include <sys/param.h>
#ifdef _KERNEL #ifdef _KERNEL
@ -83,6 +83,7 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_cksum.c,v 1.19 2001/11/15 09:48:29 lukem Exp $")
#include <sys/mount.h> #include <sys/mount.h>
#include <ufs/ufs/inode.h> #include <ufs/ufs/inode.h>
#include <ufs/lfs/lfs.h> #include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
/* /*
* Simple, general purpose, fast checksum. Data must be short-aligned. * Simple, general purpose, fast checksum. Data must be short-aligned.

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_extern.h,v 1.30 2002/05/14 20:03:53 perseant Exp $ */ /* $NetBSD: lfs_extern.h,v 1.31 2002/06/16 00:13:15 perseant Exp $ */
/*- /*-
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@ -204,32 +204,34 @@ void lfs_unmark_vnode(struct vnode *);
void lfs_itimes(struct inode *, struct timespec *, struct timespec *, void lfs_itimes(struct inode *, struct timespec *, struct timespec *,
struct timespec *); struct timespec *);
int lfs_balloc (void *); int lfs_balloc (void *);
int lfs_valloc (void *); int lfs_valloc (void *);
int lfs_vfree (void *); int lfs_vfree (void *);
int lfs_bwrite (void *); int lfs_bwrite (void *);
int lfs_update (void *); int lfs_update (void *);
int lfs_truncate(void *); int lfs_truncate (void *);
int lfs_blkatoff(void *); int lfs_blkatoff (void *);
int lfs_fsync (void *); int lfs_fsync (void *);
int lfs_symlink (void *); int lfs_symlink (void *);
int lfs_mknod (void *); int lfs_mknod (void *);
int lfs_create (void *); int lfs_create (void *);
int lfs_mkdir (void *); int lfs_mkdir (void *);
int lfs_read (void *); int lfs_read (void *);
int lfs_remove (void *); int lfs_remove (void *);
int lfs_rmdir (void *); int lfs_rmdir (void *);
int lfs_link (void *); int lfs_link (void *);
int lfs_rename (void *); int lfs_rename (void *);
int lfs_getattr (void *); int lfs_getattr (void *);
int lfs_setattr (void *); int lfs_setattr (void *);
int lfs_close (void *); int lfs_close (void *);
int lfs_inactive(void *); int lfsspec_close(void *);
int lfs_reclaim (void *); int lfsfifo_close(void *);
int lfs_write (void *); int lfs_inactive (void *);
int lfs_whiteout(void *); int lfs_reclaim (void *);
int lfs_getpages(void *); int lfs_write (void *);
int lfs_putpages(void *); int lfs_whiteout (void *);
int lfs_getpages (void *);
int lfs_putpages (void *);
__END_DECLS __END_DECLS
extern int lfs_mount_type; extern int lfs_mount_type;

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_segment.c,v 1.78 2002/05/24 22:13:57 perseant Exp $ */ /* $NetBSD: lfs_segment.c,v 1.79 2002/06/16 00:13:15 perseant Exp $ */
/*- /*-
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@ -71,7 +71,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.78 2002/05/24 22:13:57 perseant Exp $"); __KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.79 2002/06/16 00:13:15 perseant Exp $");
#define ivndebug(vp,str) printf("ino %d: %s\n",VTOI(vp)->i_number,(str)) #define ivndebug(vp,str) printf("ino %d: %s\n",VTOI(vp)->i_number,(str))
@ -104,11 +104,15 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.78 2002/05/24 22:13:57 perseant Ex
#include <ufs/lfs/lfs.h> #include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h> #include <ufs/lfs/lfs_extern.h>
#include <uvm/uvm.h>
#include <uvm/uvm_extern.h> #include <uvm/uvm_extern.h>
extern int count_lock_queue(void); extern int count_lock_queue(void);
extern struct simplelock vnode_free_list_slock; /* XXX */ extern struct simplelock vnode_free_list_slock; /* XXX */
static void lfs_generic_callback(struct buf *, void (*)(struct buf *));
static void lfs_super_aiodone(struct buf *);
static void lfs_cluster_aiodone(struct buf *);
static void lfs_cluster_callback(struct buf *); static void lfs_cluster_callback(struct buf *);
static struct buf **lookahead_pagemove(struct buf **, int, size_t *); static struct buf **lookahead_pagemove(struct buf **, int, size_t *);
@ -290,8 +294,9 @@ lfs_vflush(struct vnode *vp)
} }
SET_FLUSHING(fs,vp); SET_FLUSHING(fs,vp);
if (fs->lfs_nactive > LFS_MAX_ACTIVE) { if (fs->lfs_nactive > LFS_MAX_ACTIVE ||
error = lfs_segwrite(vp->v_mount, SEGM_SYNC|SEGM_CKP); (fs->lfs_sp->seg_flags & SEGM_CKP)) {
error = lfs_segwrite(vp->v_mount, SEGM_CKP | SEGM_SYNC);
CLR_FLUSHING(fs,vp); CLR_FLUSHING(fs,vp);
lfs_segunlock(fs); lfs_segunlock(fs);
return error; return error;
@ -351,11 +356,9 @@ lfs_vflush(struct vnode *vp)
* artificially incremented by lfs_seglock(). * artificially incremented by lfs_seglock().
*/ */
if (fs->lfs_seglock > 1) { if (fs->lfs_seglock > 1) {
s = splbio();
while (fs->lfs_iocount > 1) while (fs->lfs_iocount > 1)
(void)tsleep(&fs->lfs_iocount, PRIBIO + 1, (void)tsleep(&fs->lfs_iocount, PRIBIO + 1,
"lfs_vflush", 0); "lfs_vflush", 0);
splx(s);
} }
lfs_segunlock(fs); lfs_segunlock(fs);
@ -692,8 +695,8 @@ lfs_segwrite(struct mount *mp, int flags)
* Take the flags off of the segment so that lfs_segunlock * Take the flags off of the segment so that lfs_segunlock
* doesn't have to write the superblock either. * doesn't have to write the superblock either.
*/ */
if (did_ckp == 0) { if (do_ckp && !did_ckp) {
sp->seg_flags &= ~(SEGM_SYNC|SEGM_CKP); sp->seg_flags &= ~SEGM_CKP;
/* if (do_ckp) printf("lfs_segwrite: no checkpoint\n"); */ /* if (do_ckp) printf("lfs_segwrite: no checkpoint\n"); */
} }
@ -1443,12 +1446,20 @@ lfs_newclusterbuf(struct lfs *fs, struct vnode *vp, daddr_t addr, int n)
cl = (struct lfs_cluster *)malloc(sizeof(*cl), M_SEGMENT, M_WAITOK); cl = (struct lfs_cluster *)malloc(sizeof(*cl), M_SEGMENT, M_WAITOK);
bpp = (struct buf **)malloc(n*sizeof(*bpp), M_SEGMENT, M_WAITOK); bpp = (struct buf **)malloc(n*sizeof(*bpp), M_SEGMENT, M_WAITOK);
memset(cl,0,sizeof(*cl)); memset(cl, 0, sizeof(*cl));
cl->fs = fs; cl->fs = fs;
cl->bpp = bpp; cl->bpp = bpp;
cl->bufcount = 0; cl->bufcount = 0;
cl->bufsize = 0; cl->bufsize = 0;
/* If this segment is being written synchronously, note that */
if (fs->lfs_sp->seg_flags & SEGM_SYNC) {
cl->flags |= LFS_CL_SYNC;
cl->seg = fs->lfs_sp;
++cl->seg->seg_iocount;
/* printf("+ %x => %d\n", cl->seg, cl->seg->seg_iocount); */
}
/* Get an empty buffer header, or maybe one with something on it */ /* Get an empty buffer header, or maybe one with something on it */
s = splbio(); s = splbio();
if((bp = bufqueues[BQ_EMPTY].tqh_first) != NULL) { if((bp = bufqueues[BQ_EMPTY].tqh_first) != NULL) {
@ -1791,7 +1802,6 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
/* /*
* Construct the cluster. * Construct the cluster.
*/ */
s = splbio();
while (fs->lfs_iocount >= LFS_THROTTLE) { while (fs->lfs_iocount >= LFS_THROTTLE) {
#ifdef DEBUG_LFS #ifdef DEBUG_LFS
printf("[%d]", fs->lfs_iocount); printf("[%d]", fs->lfs_iocount);
@ -1841,7 +1851,9 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
bp->b_flags &= ~(B_ERROR | B_READ | B_DELWRI | B_DONE); bp->b_flags &= ~(B_ERROR | B_READ | B_DELWRI | B_DONE);
cl->bpp[cl->bufcount++] = bp; cl->bpp[cl->bufcount++] = bp;
vp = bp->b_vp; vp = bp->b_vp;
s = splbio();
++vp->v_numoutput; ++vp->v_numoutput;
splx(s);
/* /*
* Although it cannot be freed for reuse before the * Although it cannot be freed for reuse before the
@ -1875,6 +1887,7 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
* XXX KS - Shouldn't we set *both* if both types * XXX KS - Shouldn't we set *both* if both types
* of blocks are present (traverse the dirty list?) * of blocks are present (traverse the dirty list?)
*/ */
s = splbio();
if ((i == 1 || if ((i == 1 ||
(i > 1 && vp && *bpp && (*bpp)->b_vp != vp)) && (i > 1 && vp && *bpp && (*bpp)->b_vp != vp)) &&
(bp = LIST_FIRST(&vp->v_dirtyblkhd)) != NULL && (bp = LIST_FIRST(&vp->v_dirtyblkhd)) != NULL &&
@ -1890,8 +1903,10 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
else else
LFS_SET_UINO(ip, IN_MODIFIED); LFS_SET_UINO(ip, IN_MODIFIED);
} }
splx(s);
wakeup(vp); wakeup(vp);
} }
s = splbio();
++cbp->b_vp->v_numoutput; ++cbp->b_vp->v_numoutput;
splx(s); splx(s);
/* /*
@ -1967,8 +1982,8 @@ lfs_writesuper(struct lfs *fs, daddr_t daddr)
vop_strategy_a.a_bp = bp; vop_strategy_a.a_bp = bp;
s = splbio(); s = splbio();
++bp->b_vp->v_numoutput; ++bp->b_vp->v_numoutput;
++fs->lfs_iocount;
splx(s); splx(s);
++fs->lfs_iocount;
(strategy)(&vop_strategy_a); (strategy)(&vop_strategy_a);
} }
@ -2030,8 +2045,8 @@ lfs_callback(struct buf *bp)
lfs_freebuf(bp); lfs_freebuf(bp);
} }
void static void
lfs_supercallback(struct buf *bp) lfs_super_aiodone(struct buf *bp)
{ {
struct lfs *fs; struct lfs *fs;
@ -2044,13 +2059,13 @@ lfs_supercallback(struct buf *bp)
} }
static void static void
lfs_cluster_callback(struct buf *bp) lfs_cluster_aiodone(struct buf *bp)
{ {
struct lfs_cluster *cl; struct lfs_cluster *cl;
struct lfs *fs; struct lfs *fs;
struct buf *tbp; struct buf *tbp;
struct vnode *vp; struct vnode *vp;
int error=0; int s, error=0;
char *cp; char *cp;
extern int locked_queue_count; extern int locked_queue_count;
extern long locked_queue_bytes; extern long locked_queue_bytes;
@ -2101,8 +2116,10 @@ lfs_cluster_callback(struct buf *bp)
tbp->b_flags |= B_INVAL; tbp->b_flags |= B_INVAL;
if(!(tbp->b_flags & B_CALL)) { if(!(tbp->b_flags & B_CALL)) {
bremfree(tbp); bremfree(tbp);
s = splbio();
if(vp) if(vp)
reassignbuf(tbp, vp); reassignbuf(tbp, vp);
splx(s);
tbp->b_flags |= B_ASYNC; /* for biodone */ tbp->b_flags |= B_ASYNC; /* for biodone */
} }
#ifdef DIAGNOSTIC #ifdef DIAGNOSTIC
@ -2112,27 +2129,7 @@ lfs_cluster_callback(struct buf *bp)
} }
#endif #endif
if (tbp->b_flags & (B_BUSY | B_CALL)) { if (tbp->b_flags & (B_BUSY | B_CALL)) {
/*
* Prevent vp from being moved between hold list
* and free list by giving it an extra hold,
* and then inline HOLDRELE, minus the TAILQ
* manipulation.
*
* lfs_vunref() will put the vnode back on the
* appropriate free list the next time it is
* called (in thread context).
*/
if (vp)
VHOLD(vp);
biodone(tbp); biodone(tbp);
if (vp) {
simple_lock(&vp->v_interlock);
if (vp->v_holdcnt <= 0)
panic("lfs_cluster_callback: "
"holdcnt vp %p", vp);
vp->v_holdcnt--;
simple_unlock(&vp->v_interlock);
}
} }
} }
@ -2151,23 +2148,26 @@ lfs_cluster_callback(struct buf *bp)
bp->b_iodone = NULL; bp->b_iodone = NULL;
bp->b_flags &= ~B_DELWRI; bp->b_flags &= ~B_DELWRI;
bp->b_flags |= B_DONE; bp->b_flags |= B_DONE;
s = splbio();
reassignbuf(bp, bp->b_vp); reassignbuf(bp, bp->b_vp);
splx(s);
brelse(bp); brelse(bp);
free(cl->bpp, M_SEGMENT); /* Note i/o done */
free(cl, M_SEGMENT); if (cl->flags & LFS_CL_SYNC) {
if (--cl->seg->seg_iocount == 0)
wakeup(&cl->seg->seg_iocount);
/* printf("- %x => %d\n", cl->seg, cl->seg->seg_iocount); */
}
#ifdef DIAGNOSTIC #ifdef DIAGNOSTIC
if (fs->lfs_iocount == 0) if (fs->lfs_iocount == 0)
panic("lfs_callback: zero iocount\n"); panic("lfs_cluster_aiodone: zero iocount\n");
#endif #endif
if (--fs->lfs_iocount < LFS_THROTTLE) if (--fs->lfs_iocount < LFS_THROTTLE)
wakeup(&fs->lfs_iocount); wakeup(&fs->lfs_iocount);
#if 0 #if 0
if (fs->lfs_iocount == 0) { if (fs->lfs_iocount == 0) {
/* /*
* XXX - do we really want to do this in a callback?
*
* Vinvalbuf can move locked buffers off the locked queue * Vinvalbuf can move locked buffers off the locked queue
* and we have no way of knowing about this. So, after * and we have no way of knowing about this. So, after
* doing a big write, we recalculate how many buffers are * doing a big write, we recalculate how many buffers are
@ -2177,6 +2177,33 @@ lfs_cluster_callback(struct buf *bp)
wakeup(&locked_queue_count); wakeup(&locked_queue_count);
} }
#endif #endif
free(cl->bpp, M_SEGMENT);
free(cl, M_SEGMENT);
}
static void
lfs_generic_callback(struct buf *bp, void (*aiodone)(struct buf *))
{
/* reset b_iodone for when this is a single-buf i/o. */
bp->b_iodone = aiodone;
simple_lock(&uvm.aiodoned_lock); /* locks uvm.aio_done */
TAILQ_INSERT_TAIL(&uvm.aio_done, bp, b_freelist);
wakeup(&uvm.aiodoned);
simple_unlock(&uvm.aiodoned_lock);
}
static void
lfs_cluster_callback(struct buf *bp)
{
lfs_generic_callback(bp, lfs_cluster_aiodone);
}
void
lfs_supercallback(struct buf *bp)
{
lfs_generic_callback(bp, lfs_super_aiodone);
} }
/* /*

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_subr.c,v 1.25 2002/05/24 22:13:57 perseant Exp $ */ /* $NetBSD: lfs_subr.c,v 1.26 2002/06/16 00:13:15 perseant Exp $ */
/*- /*-
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@ -71,7 +71,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_subr.c,v 1.25 2002/05/24 22:13:57 perseant Exp $"); __KERNEL_RCSID(0, "$NetBSD: lfs_subr.c,v 1.26 2002/06/16 00:13:15 perseant Exp $");
#include <sys/param.h> #include <sys/param.h>
#include <sys/systm.h> #include <sys/systm.h>
@ -131,7 +131,6 @@ void
lfs_seglock(struct lfs *fs, unsigned long flags) lfs_seglock(struct lfs *fs, unsigned long flags)
{ {
struct segment *sp; struct segment *sp;
int s;
if (fs->lfs_seglock) { if (fs->lfs_seglock) {
if (fs->lfs_lockpid == curproc->p_pid) { if (fs->lfs_lockpid == curproc->p_pid) {
@ -152,6 +151,7 @@ lfs_seglock(struct lfs *fs, unsigned long flags)
M_SEGMENT, M_WAITOK); M_SEGMENT, M_WAITOK);
sp->seg_flags = flags; sp->seg_flags = flags;
sp->vp = NULL; sp->vp = NULL;
sp->seg_iocount = 0;
(void) lfs_initseg(fs); (void) lfs_initseg(fs);
/* /*
@ -160,9 +160,7 @@ lfs_seglock(struct lfs *fs, unsigned long flags)
* so we artificially increment it by one until we've scheduled all of * so we artificially increment it by one until we've scheduled all of
* the writes we intend to do. * the writes we intend to do.
*/ */
s = splbio();
++fs->lfs_iocount; ++fs->lfs_iocount;
splx(s);
} }
/* /*
@ -174,7 +172,6 @@ lfs_segunlock(struct lfs *fs)
{ {
struct segment *sp; struct segment *sp;
unsigned long sync, ckp; unsigned long sync, ckp;
int s;
struct buf *bp; struct buf *bp;
struct vnode *vp, *nvp; struct vnode *vp, *nvp;
struct mount *mp; struct mount *mp;
@ -265,7 +262,9 @@ lfs_segunlock(struct lfs *fs)
free(sp->bpp, M_SEGMENT); free(sp->bpp, M_SEGMENT);
sp->bpp = NULL; sp->bpp = NULL;
free(sp, M_SEGMENT); /* The sync case holds a reference in `sp' to be freed below */
if (!sync)
free(sp, M_SEGMENT);
fs->lfs_sp = NULL; fs->lfs_sp = NULL;
/* /*
@ -273,7 +272,6 @@ lfs_segunlock(struct lfs *fs)
* At the moment, the user's process hangs around so we can * At the moment, the user's process hangs around so we can
* sleep. * sleep.
*/ */
s = splbio();
if (--fs->lfs_iocount < LFS_THROTTLE) if (--fs->lfs_iocount < LFS_THROTTLE)
wakeup(&fs->lfs_iocount); wakeup(&fs->lfs_iocount);
if(fs->lfs_iocount == 0) { if(fs->lfs_iocount == 0) {
@ -282,6 +280,16 @@ lfs_segunlock(struct lfs *fs)
wakeup(&locked_queue_count); wakeup(&locked_queue_count);
wakeup(&fs->lfs_iocount); wakeup(&fs->lfs_iocount);
} }
/*
* If we're not checkpointing, we don't have to block
* other processes to wait for a synchronous write
* to complete.
*/
if (!ckp) {
--fs->lfs_seglock;
fs->lfs_lockpid = 0;
wakeup(&fs->lfs_seglock);
}
/* /*
* We let checkpoints happen asynchronously. That means * We let checkpoints happen asynchronously. That means
* that during recovery, we have to roll forward between * that during recovery, we have to roll forward between
@ -289,10 +297,16 @@ lfs_segunlock(struct lfs *fs)
* superblocks to make sure that the checkpoint described * superblocks to make sure that the checkpoint described
* by a superblock completed. * by a superblock completed.
*/ */
while (sync && fs->lfs_iocount) while (ckp && sync && fs->lfs_iocount)
(void)tsleep(&fs->lfs_iocount, PRIBIO + 1, (void)tsleep(&fs->lfs_iocount, PRIBIO + 1,
"lfs vflush", 0); "lfs_iocount", 0);
splx(s); while (sync && sp->seg_iocount) {
(void)tsleep(&sp->seg_iocount, PRIBIO + 1,
"seg_iocount", 0);
/* printf("sleeping on iocount %x == %d\n", sp, sp->seg_iocount); */
}
if (sync)
free(sp, M_SEGMENT);
if (ckp) { if (ckp) {
fs->lfs_nactive = 0; fs->lfs_nactive = 0;
/* If we *know* everything's on disk, write both sbs */ /* If we *know* everything's on disk, write both sbs */
@ -300,10 +314,11 @@ lfs_segunlock(struct lfs *fs)
lfs_writesuper(fs,fs->lfs_sboffs[fs->lfs_activesb]); lfs_writesuper(fs,fs->lfs_sboffs[fs->lfs_activesb]);
fs->lfs_activesb = 1 - fs->lfs_activesb; fs->lfs_activesb = 1 - fs->lfs_activesb;
lfs_writesuper(fs,fs->lfs_sboffs[fs->lfs_activesb]); lfs_writesuper(fs,fs->lfs_sboffs[fs->lfs_activesb]);
--fs->lfs_seglock;
fs->lfs_lockpid = 0;
wakeup(&fs->lfs_seglock);
} }
--fs->lfs_seglock;
fs->lfs_lockpid = 0;
wakeup(&fs->lfs_seglock);
} else if (fs->lfs_seglock == 0) { } else if (fs->lfs_seglock == 0) {
panic ("Seglock not held"); panic ("Seglock not held");
} else { } else {

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_syscalls.c,v 1.66 2002/06/06 00:46:24 perseant Exp $ */ /* $NetBSD: lfs_syscalls.c,v 1.67 2002/06/16 00:13:16 perseant Exp $ */
/*- /*-
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@ -71,7 +71,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_syscalls.c,v 1.66 2002/06/06 00:46:24 perseant Exp $"); __KERNEL_RCSID(0, "$NetBSD: lfs_syscalls.c,v 1.67 2002/06/16 00:13:16 perseant Exp $");
#define LFS /* for prototypes in syscallargs.h */ #define LFS /* for prototypes in syscallargs.h */
@ -282,7 +282,7 @@ lfs_markv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov, int blkcnt)
* any Ifile blocks that we might be asked to clean will never get * any Ifile blocks that we might be asked to clean will never get
* to the disk. * to the disk.
*/ */
lfs_seglock(fs, SEGM_SYNC|SEGM_CLEAN|SEGM_CKP); lfs_seglock(fs, SEGM_CLEAN | SEGM_CKP | SEGM_SYNC);
/* Mark blocks/inodes dirty. */ /* Mark blocks/inodes dirty. */
error = 0; error = 0;
@ -444,6 +444,7 @@ lfs_markv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov, int blkcnt)
printf("lfs_markv: wrong da same seg: %x vs %x\n", printf("lfs_markv: wrong da same seg: %x vs %x\n",
blkp->bi_daddr, dbtofsb(fs, b_daddr)); blkp->bi_daddr, dbtofsb(fs, b_daddr));
} }
do_again++;
continue; continue;
} }
} }
@ -465,9 +466,13 @@ lfs_markv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov, int blkcnt)
s = splbio(); s = splbio();
bp = incore(vp, blkp->bi_lbn); bp = incore(vp, blkp->bi_lbn);
if (bp && bp->b_bcount > blkp->bi_size) { if (bp && bp->b_bcount > blkp->bi_size) {
printf("lfs_markv: %ld > %d (fixed)\n", splx(s);
bp->b_bcount, blkp->bi_size); printf("lfs_markv: ino %d lbn %d fragment size changed (%ld > %d), try again\n",
blkp->bi_size = bp->b_bcount; blkp->bi_inode, blkp->bi_lbn,
bp->b_bcount, blkp->bi_size);
do_again++;
continue;
/* blkp->bi_size = bp->b_bcount; */
} }
splx(s); splx(s);
} }
@ -524,7 +529,7 @@ lfs_markv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov, int blkcnt)
* over the newly cleaned data contained in a checkpoint, and then * over the newly cleaned data contained in a checkpoint, and then
* we'd be unhappy at recovery time. * we'd be unhappy at recovery time.
*/ */
lfs_segwrite(mntp, SEGM_SYNC|SEGM_CLEAN|SEGM_CKP); lfs_segwrite(mntp, SEGM_CLEAN | SEGM_CKP | SEGM_SYNC);
lfs_segunlock(fs); lfs_segunlock(fs);
@ -884,6 +889,7 @@ sys_lfs_segclean(struct proc *p, void *v, register_t *retval)
struct lfs *fs; struct lfs *fs;
fsid_t fsid; fsid_t fsid;
int error; int error;
unsigned long segnum;
if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
return (error); return (error);
@ -894,8 +900,9 @@ sys_lfs_segclean(struct proc *p, void *v, register_t *retval)
return (ENOENT); return (ENOENT);
fs = VFSTOUFS(mntp)->um_lfs; fs = VFSTOUFS(mntp)->um_lfs;
segnum = SCARG(uap, segment);
if (dtosn(fs, fs->lfs_curseg) == SCARG(uap, segment)) if (dtosn(fs, fs->lfs_curseg) == segnum)
return (EBUSY); return (EBUSY);
if ((error = vfs_busy(mntp, LK_NOWAIT, NULL)) != 0) if ((error = vfs_busy(mntp, LK_NOWAIT, NULL)) != 0)
@ -903,7 +910,17 @@ sys_lfs_segclean(struct proc *p, void *v, register_t *retval)
#ifdef LFS_AGGRESSIVE_SEGLOCK #ifdef LFS_AGGRESSIVE_SEGLOCK
lfs_seglock(fs, SEGM_PROT); lfs_seglock(fs, SEGM_PROT);
#endif #endif
LFS_SEGENTRY(sup, fs, SCARG(uap, segment), bp); LFS_SEGENTRY(sup, fs, segnum, bp);
if (sup->su_nbytes) {
printf("lfs_segclean: not cleaning segment %lu: %d live bytes\n",
segnum, sup->su_nbytes);
brelse(bp);
#ifdef LFS_AGGRESSIVE_SEGLOCK
lfs_segunlock(fs);
#endif
vfs_unbusy(mntp);
return (EBUSY);
}
if (sup->su_flags & SEGUSE_ACTIVE) { if (sup->su_flags & SEGUSE_ACTIVE) {
brelse(bp); brelse(bp);
#ifdef LFS_AGGRESSIVE_SEGLOCK #ifdef LFS_AGGRESSIVE_SEGLOCK
@ -924,7 +941,7 @@ sys_lfs_segclean(struct proc *p, void *v, register_t *retval)
fs->lfs_avail += segtod(fs, 1); fs->lfs_avail += segtod(fs, 1);
if (sup->su_flags & SEGUSE_SUPERBLOCK) if (sup->su_flags & SEGUSE_SUPERBLOCK)
fs->lfs_avail -= btofsb(fs, LFS_SBPAD); fs->lfs_avail -= btofsb(fs, LFS_SBPAD);
if (fs->lfs_version > 1 && SCARG(uap, segment) == 0 && if (fs->lfs_version > 1 && segnum == 0 &&
fs->lfs_start < btofsb(fs, LFS_LABELPAD)) fs->lfs_start < btofsb(fs, LFS_LABELPAD))
fs->lfs_avail -= btofsb(fs, LFS_LABELPAD) - fs->lfs_start; fs->lfs_avail -= btofsb(fs, LFS_LABELPAD) - fs->lfs_start;
fs->lfs_bfree += sup->su_nsums * btofsb(fs, fs->lfs_sumsize) + fs->lfs_bfree += sup->su_nsums * btofsb(fs, fs->lfs_sumsize) +
@ -1240,9 +1257,7 @@ lfs_fakebuf(struct lfs *fs, struct vnode *vp, int lbn, size_t size, caddr_t uadd
#endif #endif
#if 0 #if 0
bp->b_saveaddr = (caddr_t)fs; bp->b_saveaddr = (caddr_t)fs;
s = splbio();
++fs->lfs_iocount; ++fs->lfs_iocount;
splx(s);
#endif #endif
bp->b_bufsize = size; bp->b_bufsize = size;
bp->b_bcount = size; bp->b_bcount = size;

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_vfsops.c,v 1.76 2002/05/17 21:42:38 perseant Exp $ */ /* $NetBSD: lfs_vfsops.c,v 1.77 2002/06/16 00:13:16 perseant Exp $ */
/*- /*-
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@ -71,7 +71,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.76 2002/05/17 21:42:38 perseant Exp $"); __KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.77 2002/06/16 00:13:16 perseant Exp $");
#if defined(_KERNEL_OPT) #if defined(_KERNEL_OPT)
#include "opt_quota.h" #include "opt_quota.h"
@ -1174,7 +1174,7 @@ lfs_unmount(struct mount *mp, int mntflags, struct proc *p)
{ {
struct ufsmount *ump; struct ufsmount *ump;
struct lfs *fs; struct lfs *fs;
int error, flags, ronly, s; int error, flags, ronly;
flags = 0; flags = 0;
if (mntflags & MNT_FORCE) if (mntflags & MNT_FORCE)
@ -1231,10 +1231,8 @@ lfs_unmount(struct mount *mp, int mntflags, struct proc *p)
vgone(fs->lfs_ivnode); vgone(fs->lfs_ivnode);
/* Wait for superblock writes to complete */ /* Wait for superblock writes to complete */
s = splbio();
while (fs->lfs_iocount) while (fs->lfs_iocount)
tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs_umount", 0); tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs_umount", 0);
splx(s);
ronly = !fs->lfs_ronly; ronly = !fs->lfs_ronly;
if (ump->um_devvp->v_type != VBAD) if (ump->um_devvp->v_type != VBAD)

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_vnops.c,v 1.64 2002/05/17 21:42:38 perseant Exp $ */ /* $NetBSD: lfs_vnops.c,v 1.65 2002/06/16 00:13:16 perseant Exp $ */
/*- /*-
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@ -71,7 +71,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,v 1.64 2002/05/17 21:42:38 perseant Exp $"); __KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,v 1.65 2002/06/16 00:13:16 perseant Exp $");
#include <sys/param.h> #include <sys/param.h>
#include <sys/systm.h> #include <sys/systm.h>
@ -164,7 +164,7 @@ const struct vnodeopv_entry_desc lfs_specop_entries[] = {
{ &vop_create_desc, spec_create }, /* create */ { &vop_create_desc, spec_create }, /* create */
{ &vop_mknod_desc, spec_mknod }, /* mknod */ { &vop_mknod_desc, spec_mknod }, /* mknod */
{ &vop_open_desc, spec_open }, /* open */ { &vop_open_desc, spec_open }, /* open */
{ &vop_close_desc, ufsspec_close }, /* close */ { &vop_close_desc, lfsspec_close }, /* close */
{ &vop_access_desc, ufs_access }, /* access */ { &vop_access_desc, ufs_access }, /* access */
{ &vop_getattr_desc, lfs_getattr }, /* getattr */ { &vop_getattr_desc, lfs_getattr }, /* getattr */
{ &vop_setattr_desc, lfs_setattr }, /* setattr */ { &vop_setattr_desc, lfs_setattr }, /* setattr */
@ -217,7 +217,7 @@ const struct vnodeopv_entry_desc lfs_fifoop_entries[] = {
{ &vop_create_desc, fifo_create }, /* create */ { &vop_create_desc, fifo_create }, /* create */
{ &vop_mknod_desc, fifo_mknod }, /* mknod */ { &vop_mknod_desc, fifo_mknod }, /* mknod */
{ &vop_open_desc, fifo_open }, /* open */ { &vop_open_desc, fifo_open }, /* open */
{ &vop_close_desc, ufsfifo_close }, /* close */ { &vop_close_desc, lfsfifo_close }, /* close */
{ &vop_access_desc, ufs_access }, /* access */ { &vop_access_desc, ufs_access }, /* access */
{ &vop_getattr_desc, lfs_getattr }, /* getattr */ { &vop_getattr_desc, lfs_getattr }, /* getattr */
{ &vop_setattr_desc, lfs_setattr }, /* setattr */ { &vop_setattr_desc, lfs_setattr }, /* setattr */
@ -864,15 +864,67 @@ lfs_close(void *v)
struct inode *ip = VTOI(vp); struct inode *ip = VTOI(vp);
struct timespec ts; struct timespec ts;
simple_lock(&vp->v_interlock);
if (vp->v_usecount > 1) { if (vp->v_usecount > 1) {
TIMEVAL_TO_TIMESPEC(&time, &ts); TIMEVAL_TO_TIMESPEC(&time, &ts);
LFS_ITIMES(ip, &ts, &ts, &ts); LFS_ITIMES(ip, &ts, &ts, &ts);
} }
simple_unlock(&vp->v_interlock);
return (0); return (0);
} }
/*
* Close wrapper for special devices.
*
* Update the times on the inode then do device close.
*/
int
lfsspec_close(void *v)
{
struct vop_close_args /* {
struct vnode *a_vp;
int a_fflag;
struct ucred *a_cred;
struct proc *a_p;
} */ *ap = v;
struct vnode *vp;
struct inode *ip;
struct timespec ts;
vp = ap->a_vp;
ip = VTOI(vp);
if (vp->v_usecount > 1) {
TIMEVAL_TO_TIMESPEC(&time, &ts);
LFS_ITIMES(ip, &ts, &ts, &ts);
}
return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap));
}
/*
* Close wrapper for fifo's.
*
* Update the times on the inode then do device close.
*/
int
lfsfifo_close(void *v)
{
struct vop_close_args /* {
struct vnode *a_vp;
int a_fflag;
struct ucred *a_cred;
struct proc *a_p;
} */ *ap = v;
struct vnode *vp;
struct inode *ip;
struct timespec ts;
vp = ap->a_vp;
ip = VTOI(vp);
if (ap->a_vp->v_usecount > 1) {
TIMEVAL_TO_TIMESPEC(&time, &ts);
LFS_ITIMES(ip, &ts, &ts, &ts);
}
return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap));
}
/* /*
* Reclaim an inode so that it can be used for other purposes. * Reclaim an inode so that it can be used for other purposes.
*/ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: inode.h,v 1.27 2001/12/18 10:57:23 fvdl Exp $ */ /* $NetBSD: inode.h,v 1.28 2002/06/16 00:13:17 perseant Exp $ */
/* /*
* Copyright (c) 1982, 1989, 1993 * Copyright (c) 1982, 1989, 1993
@ -45,7 +45,6 @@
#include <ufs/ufs/dir.h> #include <ufs/ufs/dir.h>
#include <ufs/ufs/quota.h> #include <ufs/ufs/quota.h>
#include <ufs/ext2fs/ext2fs_dinode.h> #include <ufs/ext2fs/ext2fs_dinode.h>
#include <ufs/lfs/lfs_extern.h>
#include <miscfs/genfs/genfs_node.h> #include <miscfs/genfs/genfs_node.h>
/* /*
@ -176,9 +175,6 @@ struct inode {
#define IN_SPACECOUNTED 0x0400 /* Blocks to be freed in free count. */ #define IN_SPACECOUNTED 0x0400 /* Blocks to be freed in free count. */
#if defined(_KERNEL) #if defined(_KERNEL)
#if defined(_KERNEL_OPT)
#include "fs_lfs.h" /* for ITIMES */
#endif /* _KERNEL_OPT */
/* /*
* Structure used to pass around logical block paths generated by * Structure used to pass around logical block paths generated by
* ufs_getlbns and used by truncate and bmap code. * ufs_getlbns and used by truncate and bmap code.
@ -234,23 +230,12 @@ struct indir {
} \ } \
} }
#ifdef LFS
#define ITIMES(ip, acc, mod, cre) { \
if (IS_EXT2_VNODE((ip)->i_vnode)) \
EXT2FS_ITIMES(ip, acc, mod, cre) \
else if(IS_LFS_VNODE((ip)->i_vnode)) \
lfs_itimes(ip, acc, mod, cre); \
else \
FFS_ITIMES(ip, acc, mod, cre) \
}
#else /* ! LFS */
#define ITIMES(ip, acc, mod, cre) { \ #define ITIMES(ip, acc, mod, cre) { \
if (IS_EXT2_VNODE((ip)->i_vnode)) \ if (IS_EXT2_VNODE((ip)->i_vnode)) \
EXT2FS_ITIMES(ip, acc, mod, cre) \ EXT2FS_ITIMES(ip, acc, mod, cre) \
else \ else \
FFS_ITIMES(ip, acc, mod, cre) \ FFS_ITIMES(ip, acc, mod, cre) \
} }
#endif /* ! LFS */
/* Determine if soft dependencies are being done */ /* Determine if soft dependencies are being done */
#define DOINGSOFTDEP(vp) ((vp)->v_mount->mnt_flag & MNT_SOFTDEP) #define DOINGSOFTDEP(vp) ((vp)->v_mount->mnt_flag & MNT_SOFTDEP)