Various minor LFS improvements:
* Note when lfs_putpages(9) thinks it is not going to be writing any pages before calling genfs_putpages(9). This prevents a situation in which blocks can be queued for writing without a segment header. * Correct computation of NRESERVE(), though it is still a gross overestimate in most cases. Note that if NRESERVE() is too high, it may be impossible to create files on the filesystem. We catch this case on filesystem mount and refuse to mount r/w. * Allow filesystems to be mounted whose block size is == MAXBSIZE. * Somewhere along the line, ufs_bmaparray(9) started mangling UNWRITTEN entries in indirect blocks again, triggering a failed assertion "daddr <= LFS_MAX_DADDR". Explicitly convert to and from int32_t to correct this. * Add a high-water mark for the number of dirty pages any given LFS can hold before triggering a flush. This is settable by sysctl, but off (zero) by default. * Be more careful about the MAX_BYTES and MAX_BUFS computations so we shouldn't see "please increase to at least zero" messages. * Note that VBLK and VCHR vnodes can have nonzero values in di_db[0] even though their v_size == 0. Don't panic when we see this. * Change lfs_bfree to a signed quantity. The manner in which it is processed before being passed to the cleaner means that sometimes it may drop below zero, and the cleaner must be aware of this. * Never report bfree < 0 (or higher than lfs_dsize) through lfs_statvfs(9). This prevents df(1) from ever telling us that our full filesystems have 16TB free. * Account space allocated through lfs_balloc(9) that does not have associated buffer headers, so that the pagedaemon doesn't run us out of segments. * Return ENOSPC from lfs_balloc(9) when bfree drops to zero. * Address a deadlock in lfs_bmapv/lfs_markv when the filesystem is being unmounted. Because vfs_busy() is a shared lock, and lfs_bmapv/lfs_markv mark the filesystem vfs_busy(), the cleaner can be holding the lock that umount() is blocking on, then try to vfs_busy() again in getnewvnode().
This commit is contained in:
parent
0a40f744b4
commit
25f49c3c91
|
@ -1,11 +1,7 @@
|
|||
# $NetBSD: TODO,v 1.7 2003/02/23 00:22:33 perseant Exp $
|
||||
# $NetBSD: TODO,v 1.8 2005/02/26 05:40:42 perseant Exp $
|
||||
|
||||
- Lock audit. Need to check locking for multiprocessor case in particular.
|
||||
|
||||
- Get rid of the syscalls: make them into ioctl calls instead. This would
|
||||
allow LFS to be loaded as a module. We would then ideally have an
|
||||
in-kernel cleaner that runs if no userland cleaner has asserted itself.
|
||||
|
||||
- Get rid of lfs_segclean(); the kernel should clean a dirty segment IFF it
|
||||
has passed two checkpoints containing zero live bytes.
|
||||
|
||||
|
@ -23,9 +19,6 @@
|
|||
locking problem in lfs_{bmapv,markv} goes away and lfs_reserve can go,
|
||||
too.
|
||||
|
||||
- Fully working fsck_lfs. (Really, need a general-purpose external
|
||||
partial-segment writer.)
|
||||
|
||||
- Get rid of DEV_BSIZE, pay attention to the media block size at mount time.
|
||||
|
||||
- More fs ops need to call lfs_imtime. Which ones? (Blackwell et al., 1995)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs.h,v 1.74 2004/08/14 14:32:04 mycroft Exp $ */
|
||||
/* $NetBSD: lfs.h,v 1.75 2005/02/26 05:40:42 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
|
||||
|
@ -77,6 +77,7 @@
|
|||
#define LFS_DEBUG_RFW /* print roll-forward debugging info */
|
||||
#define LFS_LOGLENGTH 1024 /* size of debugging log */
|
||||
#define LFS_MAX_ACTIVE 10 /* Dirty segments before ckp forced */
|
||||
#define LFS_PD /* pagedaemon codaemon */
|
||||
|
||||
/* #define DEBUG_LFS */ /* Intensive debugging of LFS subsystem */
|
||||
|
||||
|
@ -111,9 +112,11 @@
|
|||
/* Resource limits */
|
||||
#define LFS_MAX_BUFS ((nbuf >> 2) - 10)
|
||||
#define LFS_WAIT_BUFS ((nbuf >> 1) - (nbuf >> 3) - 10)
|
||||
extern u_long bufmem; /* XXX */
|
||||
#define LFS_MAX_BYTES ((bufmem >> 2) - 10 * PAGE_SIZE)
|
||||
#define LFS_WAIT_BYTES ((bufmem >> 1) - (bufmem >> 3) - 10 * PAGE_SIZE)
|
||||
#define LFS_INVERSE_MAX_BUFS(n) (((n) + 10) << 2)
|
||||
extern u_long bufmem_lowater, bufmem_hiwater; /* XXX */
|
||||
#define LFS_MAX_BYTES ((bufmem_lowater >> 2) - 10 * PAGE_SIZE)
|
||||
#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 LFS_MAX_PAGES \
|
||||
(((uvmexp.active + uvmexp.inactive + uvmexp.free) * uvmexp.filemin) >> 8)
|
||||
|
@ -121,7 +124,6 @@ extern u_long bufmem; /* XXX */
|
|||
(((uvmexp.active + uvmexp.inactive + uvmexp.free) * uvmexp.filemax) >> 8)
|
||||
#define LFS_BUFWAIT 2 /* How long to wait if over *_WAIT_* */
|
||||
|
||||
|
||||
/*
|
||||
* Reserved blocks for lfs_malloc
|
||||
*/
|
||||
|
@ -466,7 +468,7 @@ struct ifile_v1 {
|
|||
typedef struct _cleanerinfo {
|
||||
u_int32_t clean; /* number of clean segments */
|
||||
u_int32_t dirty; /* number of dirty segments */
|
||||
u_int32_t bfree; /* disk blocks free */
|
||||
int32_t bfree; /* disk blocks free */
|
||||
int32_t avail; /* disk blocks available */
|
||||
u_int32_t free_head; /* head of the inode free list */
|
||||
u_int32_t free_tail; /* tail of the inode free list */
|
||||
|
@ -487,9 +489,11 @@ typedef struct _cleanerinfo {
|
|||
/* Synchronize the Ifile cleaner info with current avail and bfree */
|
||||
#define LFS_SYNC_CLEANERINFO(cip, fs, bp, w) do { \
|
||||
if ((w) || (cip)->bfree != (fs)->lfs_bfree || \
|
||||
(cip)->avail != (fs)->lfs_avail - (fs)->lfs_ravail) { \
|
||||
(cip)->avail != (fs)->lfs_avail - (fs)->lfs_ravail - \
|
||||
(fs)->lfs_favail) { \
|
||||
(cip)->bfree = (fs)->lfs_bfree; \
|
||||
(cip)->avail = (fs)->lfs_avail - (fs)->lfs_ravail; \
|
||||
(cip)->avail = (fs)->lfs_avail - (fs)->lfs_ravail - \
|
||||
(fs)->lfs_favail; \
|
||||
if (((bp)->b_flags & B_GATHERED) == 0) \
|
||||
(fs)->lfs_flags |= LFS_IFDIRTY; \
|
||||
(void) LFS_BWRITE_LOG(bp); /* Ifile */ \
|
||||
|
@ -590,7 +594,7 @@ struct dlfs {
|
|||
|
||||
/* Checkpoint region. */
|
||||
u_int32_t dlfs_freehd; /* 32: start of the free list */
|
||||
u_int32_t dlfs_bfree; /* 36: number of free disk blocks */
|
||||
int32_t dlfs_bfree; /* 36: number of free disk blocks */
|
||||
u_int32_t dlfs_nfiles; /* 40: number of allocated inodes */
|
||||
int32_t dlfs_avail; /* 44: blocks available for writing */
|
||||
int32_t dlfs_uinodes; /* 48: inodes in cache not yet on disk */
|
||||
|
@ -750,6 +754,7 @@ struct lfs {
|
|||
pid_t lfs_rfpid; /* Process ID of roll-forward agent */
|
||||
int lfs_nadirop; /* number of active dirop nodes */
|
||||
long lfs_ravail; /* blocks pre-reserved for writing */
|
||||
long lfs_favail; /* blocks pre-reserved for writing */
|
||||
res_t *lfs_resblk; /* Reserved memory for pageout */
|
||||
TAILQ_HEAD(, inode) lfs_dchainhd; /* dirop vnodes */
|
||||
TAILQ_HEAD(, inode) lfs_pchainhd; /* paging vnodes */
|
||||
|
@ -767,6 +772,7 @@ struct lfs {
|
|||
int lfs_cleanind; /* Index into intervals */
|
||||
struct simplelock lfs_interlock; /* lock for lfs_seglock */
|
||||
int lfs_sleepers; /* # procs sleeping this fs */
|
||||
int lfs_pages; /* dirty pages blaming this fs */
|
||||
};
|
||||
|
||||
/* NINDIR is the number of indirects in a file system block. */
|
||||
|
@ -899,20 +905,34 @@ struct lfs_cluster {
|
|||
#endif /* _KERNEL */
|
||||
|
||||
/*
|
||||
* LFS inode extensions; moved from <ufs/ufs/inode.h> so that file didn't
|
||||
* have to change every time LFS changed.
|
||||
* List containing block numbers allocated through lfs_balloc.
|
||||
*/
|
||||
struct lbnentry {
|
||||
LIST_ENTRY(lbnentry) entry;
|
||||
daddr_t lbn;
|
||||
};
|
||||
|
||||
/*
|
||||
* LFS inode extensions.
|
||||
*/
|
||||
struct lfs_inode_ext {
|
||||
off_t lfs_osize; /* size of file on disk */
|
||||
u_int32_t lfs_effnblocks; /* number of blocks when i/o completes */
|
||||
size_t lfs_fragsize[NDADDR]; /* size of on-disk direct blocks */
|
||||
TAILQ_ENTRY(inode) lfs_dchain; /* Dirop chain. */
|
||||
TAILQ_ENTRY(inode) lfs_pchain; /* Paging chain. */
|
||||
TAILQ_ENTRY(inode) lfs_dchain; /* Dirop chain. */
|
||||
TAILQ_ENTRY(inode) lfs_pchain; /* Paging chain. */
|
||||
/* Blocks allocated for write */
|
||||
#define LFS_BLIST_HASH_WIDTH 17
|
||||
LIST_HEAD(, lbnentry) lfs_blist[LFS_BLIST_HASH_WIDTH];
|
||||
#define LFSI_NO_GOP_WRITE 0x01
|
||||
u_int32_t lfs_iflags; /* Inode flags */
|
||||
};
|
||||
#define i_lfs_osize inode_ext.lfs->lfs_osize
|
||||
#define i_lfs_effnblks inode_ext.lfs->lfs_effnblocks
|
||||
#define i_lfs_fragsize inode_ext.lfs->lfs_fragsize
|
||||
#define i_lfs_dchain inode_ext.lfs->lfs_dchain
|
||||
#define i_lfs_blist inode_ext.lfs->lfs_blist
|
||||
#define i_lfs_iflags inode_ext.lfs->lfs_iflags
|
||||
|
||||
/*
|
||||
* Macros for determining free space on the disk, with the variable metadata
|
||||
|
@ -927,7 +947,7 @@ struct lfs_inode_ext {
|
|||
#define LFS_EST_NONMETA(F) ((F)->lfs_dsize - (F)->lfs_dmeta - LFS_EST_CMETA(F))
|
||||
|
||||
/* Estimate number of blocks actually available for writing */
|
||||
#define LFS_EST_BFREE(F) ((F)->lfs_bfree - LFS_EST_CMETA(F) - (F)->lfs_dmeta)
|
||||
#define LFS_EST_BFREE(F) ((F)->lfs_bfree > LFS_EST_CMETA(F) + (F)->lfs_dmeta ? (F)->lfs_bfree - LFS_EST_CMETA(F) - (F)->lfs_dmeta : 0)
|
||||
|
||||
/* Amount of non-meta space not available to mortal man */
|
||||
#define LFS_EST_RSVD(F) (int32_t)((LFS_EST_NONMETA(F) * \
|
||||
|
@ -944,6 +964,13 @@ struct lfs_inode_ext {
|
|||
#define IS_FREESPACE(F, BB) \
|
||||
(LFS_EST_BFREE(F) >= (BB) + LFS_EST_RSVD(F))
|
||||
|
||||
/*
|
||||
* The minimum number of blocks to create a new inode. This is:
|
||||
* directory direct block (1) + NIADDR indirect blocks + inode block (1) +
|
||||
* ifile direct block (1) + NIADDR indirect blocks = 3 + 2 * NIADDR blocks.
|
||||
*/
|
||||
#define LFS_NRESERVE(F) (btofsb((F), (2 * NIADDR + 3) << (F)->lfs_bshift))
|
||||
|
||||
/* Statistics Counters */
|
||||
struct lfs_stats {
|
||||
u_int segsused;
|
||||
|
@ -970,11 +997,15 @@ struct lfs_fcntl_markv {
|
|||
int blkcnt; /* number of blocks */
|
||||
};
|
||||
|
||||
#define LFCNSEGWAITALL _FCNW_FSPRIV('L', 0, struct timeval)
|
||||
#define LFCNSEGWAIT _FCNW_FSPRIV('L', 1, struct timeval)
|
||||
#define LFCNSEGWAITALL _FCNR_FSPRIV('L', 0, struct timeval)
|
||||
#define LFCNSEGWAIT _FCNR_FSPRIV('L', 1, struct timeval)
|
||||
#define LFCNBMAPV _FCNRW_FSPRIV('L', 2, struct lfs_fcntl_markv)
|
||||
#define LFCNMARKV _FCNRW_FSPRIV('L', 3, struct lfs_fcntl_markv)
|
||||
#define LFCNRECLAIM _FCNO_FSPRIV('L', 4)
|
||||
#define LFCNIFILEFH _FCNW_FSPRIV('L', 5, struct fhandle)
|
||||
/* Compat for NetBSD 2.x error */
|
||||
#define LFCNSEGWAITALL_COMPAT _FCNW_FSPRIV('L', 0, struct timeval)
|
||||
#define LFCNSEGWAIT_COMPAT _FCNW_FSPRIV('L', 1, struct timeval)
|
||||
|
||||
#ifdef _KERNEL
|
||||
/* XXX MP */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_alloc.c,v 1.73 2004/08/14 01:08:03 mycroft Exp $ */
|
||||
/* $NetBSD: lfs_alloc.c,v 1.74 2005/02/26 05:40:42 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.73 2004/08/14 01:08:03 mycroft Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_alloc.c,v 1.74 2005/02/26 05:40:42 perseant Exp $");
|
||||
|
||||
#if defined(_KERNEL_OPT)
|
||||
#include "opt_quota.h"
|
||||
|
@ -422,9 +422,7 @@ lfs_vcreate(struct mount *mp, ino_t ino, struct vnode *vp)
|
|||
struct inode *ip;
|
||||
struct ufs1_dinode *dp;
|
||||
struct ufsmount *ump;
|
||||
#ifdef QUOTA
|
||||
int i;
|
||||
#endif
|
||||
|
||||
/* Get a pointer to the private mount structure. */
|
||||
ump = VFSTOUFS(mp);
|
||||
|
@ -435,6 +433,9 @@ lfs_vcreate(struct mount *mp, ino_t ino, struct vnode *vp)
|
|||
dp = pool_get(&lfs_dinode_pool, PR_WAITOK);
|
||||
memset(dp, 0, sizeof(*dp));
|
||||
ip->inode_ext.lfs = pool_get(&lfs_inoext_pool, PR_WAITOK);
|
||||
memset(ip->inode_ext.lfs, 0, sizeof(*ip->inode_ext.lfs));
|
||||
for (i = 0; i < LFS_BLIST_HASH_WIDTH; i++)
|
||||
LIST_INIT(&(ip->i_lfs_blist[i]));
|
||||
vp->v_data = ip;
|
||||
ip->i_din.ffs1_din = dp;
|
||||
ip->i_ump = ump;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_balloc.c,v 1.48 2004/01/25 18:06:49 hannken Exp $ */
|
||||
/* $NetBSD: lfs_balloc.c,v 1.49 2005/02/26 05:40:42 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_balloc.c,v 1.48 2004/01/25 18:06:49 hannken Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_balloc.c,v 1.49 2005/02/26 05:40:42 perseant Exp $");
|
||||
|
||||
#if defined(_KERNEL_OPT)
|
||||
#include "opt_quota.h"
|
||||
|
@ -81,6 +81,7 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_balloc.c,v 1.48 2004/01/25 18:06:49 hannken Exp
|
|||
#include <sys/mount.h>
|
||||
#include <sys/resourcevar.h>
|
||||
#include <sys/trace.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <miscfs/specfs/specdev.h>
|
||||
|
||||
|
@ -96,6 +97,8 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_balloc.c,v 1.48 2004/01/25 18:06:49 hannken Exp
|
|||
|
||||
int lfs_fragextend(struct vnode *, int, int, daddr_t, struct buf **, struct ucred *);
|
||||
|
||||
u_int64_t locked_fakequeue_count;
|
||||
|
||||
/*
|
||||
* Allocate a block, and to inode and filesystem block accounting for it
|
||||
* and for any indirect blocks the may need to be created in order for
|
||||
|
@ -162,6 +165,10 @@ lfs_balloc(void *v)
|
|||
if (bpp)
|
||||
*bpp = NULL;
|
||||
|
||||
/* Bomb out immediately if there's no space left */
|
||||
if (fs->lfs_bfree <= 0)
|
||||
return ENOSPC;
|
||||
|
||||
/* Check for block beyond end of file and fragment extension needed. */
|
||||
lastblock = lblkno(fs, ip->i_size);
|
||||
if (lastblock < NDADDR && lastblock < lbn) {
|
||||
|
@ -227,6 +234,10 @@ lfs_balloc(void *v)
|
|||
error = ufs_bmaparray(vp, lbn, &daddr, &indirs[0], &num, NULL, NULL);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
daddr = (daddr_t)((int32_t)daddr); /* XXX ondisk32 */
|
||||
KASSERT(daddr <= LFS_MAX_DADDR);
|
||||
|
||||
/*
|
||||
* Do byte accounting all at once, so we can gracefully fail *before*
|
||||
* we start assigning blocks.
|
||||
|
@ -295,6 +306,12 @@ lfs_balloc(void *v)
|
|||
if (bpp)
|
||||
*bpp = bp = getblk(vp, lbn, blksize(fs, ip, lbn), 0, 0);
|
||||
|
||||
/*
|
||||
* Do accounting on blocks that represent pages.
|
||||
*/
|
||||
if (!bpp)
|
||||
lfs_register_block(vp, lbn);
|
||||
|
||||
/*
|
||||
* The block we are writing may be a brand new block
|
||||
* in which case we need to do accounting.
|
||||
|
@ -444,3 +461,91 @@ lfs_fragextend(struct vnode *vp, int osize, int nsize, daddr_t lbn, struct buf *
|
|||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Record this lbn as being "write pending". We used to have this information
|
||||
* on the buffer headers, but since pages don't have buffer headers we
|
||||
* record it here instead.
|
||||
*/
|
||||
|
||||
void
|
||||
lfs_register_block(struct vnode *vp, daddr_t lbn)
|
||||
{
|
||||
struct lfs *fs;
|
||||
struct inode *ip;
|
||||
struct lbnentry *lbp;
|
||||
int hash;
|
||||
|
||||
/* Don't count metadata */
|
||||
if (lbn < 0 || vp->v_type != VREG || VTOI(vp)->i_number == LFS_IFILE_INUM)
|
||||
return;
|
||||
|
||||
ip = VTOI(vp);
|
||||
fs = ip->i_lfs;
|
||||
|
||||
/* If no space, wait for the cleaner */
|
||||
lfs_availwait(fs, btofsb(fs, 1 << fs->lfs_bshift));
|
||||
|
||||
hash = lbn % LFS_BLIST_HASH_WIDTH;
|
||||
LIST_FOREACH(lbp, &(ip->i_lfs_blist[hash]), entry) {
|
||||
if (lbp->lbn == lbn)
|
||||
return;
|
||||
}
|
||||
|
||||
lbp = (struct lbnentry *)pool_get(&lfs_lbnentry_pool, PR_WAITOK);
|
||||
lbp->lbn = lbn;
|
||||
LIST_INSERT_HEAD(&(ip->i_lfs_blist[hash]), lbp, entry);
|
||||
fs->lfs_favail += btofsb(fs, (1 << fs->lfs_bshift));
|
||||
++locked_fakequeue_count;
|
||||
}
|
||||
|
||||
static void
|
||||
lfs_do_deregister(struct lfs *fs, struct lbnentry *lbp)
|
||||
{
|
||||
LIST_REMOVE(lbp, entry);
|
||||
pool_put(&lfs_lbnentry_pool, lbp);
|
||||
if (fs->lfs_favail > btofsb(fs, (1 << fs->lfs_bshift)))
|
||||
fs->lfs_favail -= btofsb(fs, (1 << fs->lfs_bshift));
|
||||
if (locked_fakequeue_count > 0)
|
||||
--locked_fakequeue_count;
|
||||
}
|
||||
|
||||
void
|
||||
lfs_deregister_block(struct vnode *vp, daddr_t lbn)
|
||||
{
|
||||
struct lfs *fs;
|
||||
struct inode *ip;
|
||||
struct lbnentry *lbp;
|
||||
int hash;
|
||||
|
||||
/* Don't count metadata */
|
||||
if (lbn < 0 || vp->v_type != VREG || VTOI(vp)->i_number == LFS_IFILE_INUM)
|
||||
return;
|
||||
|
||||
ip = VTOI(vp);
|
||||
fs = ip->i_lfs;
|
||||
hash = lbn % LFS_BLIST_HASH_WIDTH;
|
||||
LIST_FOREACH(lbp, &(ip->i_lfs_blist[hash]), entry) {
|
||||
if (lbp->lbn == lbn)
|
||||
break;
|
||||
}
|
||||
if (lbp == NULL)
|
||||
return;
|
||||
|
||||
lfs_do_deregister(fs, lbp);
|
||||
}
|
||||
|
||||
void
|
||||
lfs_deregister_all(struct vnode *vp)
|
||||
{
|
||||
struct lbnentry *lbp;
|
||||
struct lfs *fs;
|
||||
struct inode *ip;
|
||||
int i;
|
||||
|
||||
ip = VTOI(vp);
|
||||
fs = ip->i_lfs;
|
||||
for (i = 0; i < LFS_BLIST_HASH_WIDTH; i++)
|
||||
while((lbp = LIST_FIRST(&(ip->i_lfs_blist[i]))) != NULL)
|
||||
lfs_do_deregister(fs, lbp);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_bio.c,v 1.77 2004/01/28 10:54:23 yamt Exp $ */
|
||||
/* $NetBSD: lfs_bio.c,v 1.78 2005/02/26 05:40:42 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.77 2004/01/28 10:54:23 yamt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_bio.c,v 1.78 2005/02/26 05:40:42 perseant Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -104,6 +104,7 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_bio.c,v 1.77 2004/01/28 10:54:23 yamt Exp $");
|
|||
int locked_queue_count = 0; /* Count of locked-down buffers. */
|
||||
long locked_queue_bytes = 0L; /* Total size of locked buffers. */
|
||||
int lfs_subsys_pages = 0L; /* Total number LFS-written pages */
|
||||
int lfs_fs_pagetrip = 0; /* # of pages to trip per-fs write */
|
||||
int lfs_writing = 0; /* Set if already kicked off a writer
|
||||
because of buffer space */
|
||||
/* Lock for aboves */
|
||||
|
@ -162,7 +163,7 @@ lfs_reservebuf(struct lfs *fs, struct vnode *vp, struct vnode *vp2,
|
|||
while (n > 0 && !lfs_fits_buf(fs, n, bytes)) {
|
||||
int error;
|
||||
|
||||
lfs_flush(fs, 0);
|
||||
lfs_flush(fs, 0, 0);
|
||||
|
||||
error = ltsleep(&locked_queue_count, PCATCH | PUSER,
|
||||
"lfsresbuf", hz * LFS_BUFWAIT, &lfs_subsys_lock);
|
||||
|
@ -207,7 +208,7 @@ lfs_reserveavail(struct lfs *fs, struct vnode *vp, struct vnode *vp2, int fsb)
|
|||
int error, slept;
|
||||
|
||||
slept = 0;
|
||||
while (fsb > 0 && !lfs_fits(fs, fsb + fs->lfs_ravail)) {
|
||||
while (fsb > 0 && !lfs_fits(fs, fsb + fs->lfs_ravail + fs->lfs_favail)) {
|
||||
#if 0
|
||||
/*
|
||||
* XXX ideally, we should unlock vnodes here
|
||||
|
@ -226,10 +227,10 @@ lfs_reserveavail(struct lfs *fs, struct vnode *vp, struct vnode *vp2, int fsb)
|
|||
#endif
|
||||
|
||||
if (!slept) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_LFS
|
||||
printf("lfs_reserve: waiting for %ld (bfree = %d,"
|
||||
" est_bfree = %d)\n",
|
||||
fsb + fs->lfs_ravail, fs->lfs_bfree,
|
||||
fsb + fs->lfs_ravail + fs->lfs_favail, fs->lfs_bfree,
|
||||
LFS_EST_BFREE(fs));
|
||||
#endif
|
||||
}
|
||||
|
@ -250,7 +251,7 @@ lfs_reserveavail(struct lfs *fs, struct vnode *vp, struct vnode *vp2, int fsb)
|
|||
if (error)
|
||||
return error;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_LFS
|
||||
if (slept)
|
||||
printf("lfs_reserve: woke up\n");
|
||||
#endif
|
||||
|
@ -360,10 +361,11 @@ lfs_fits(struct lfs *fs, int fsb)
|
|||
1) << (fs->lfs_blktodb - fs->lfs_fsbtodb));
|
||||
|
||||
if (needed >= fs->lfs_avail) {
|
||||
#ifdef DEBUG
|
||||
printf("lfs_fits: no fit: fsb = %d, uinodes = %d, "
|
||||
"needed = %d, avail = %d\n",
|
||||
fsb, fs->lfs_uinodes, needed, fs->lfs_avail);
|
||||
#ifdef DEBUG_LFS
|
||||
printf("lfs_fits: no fit: fsb = %ld, uinodes = %ld, "
|
||||
"needed = %ld, avail = %ld\n",
|
||||
(long)fsb, (long)fs->lfs_uinodes, (long)needed,
|
||||
(long)fs->lfs_avail);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -397,8 +399,10 @@ lfs_availwait(struct lfs *fs, int fsb)
|
|||
LFS_CLEANERINFO(cip, fs, cbp);
|
||||
LFS_SYNC_CLEANERINFO(cip, fs, cbp, 0);
|
||||
|
||||
#ifdef DEBUG_LFS
|
||||
printf("lfs_availwait: out of available space, "
|
||||
"waiting on cleaner\n");
|
||||
#endif
|
||||
|
||||
wakeup(&lfs_allclean_wakeup);
|
||||
wakeup(&fs->lfs_nextseg);
|
||||
|
@ -487,11 +491,17 @@ lfs_flush_fs(struct lfs *fs, int flags)
|
|||
if (fs->lfs_ronly)
|
||||
return;
|
||||
|
||||
lfs_subsys_pages -= fs->lfs_pages; /* XXXUBC */
|
||||
if (lfs_subsys_pages < 0) /* XXXUBC */
|
||||
lfs_subsys_pages = 0; /* XXXUBC */
|
||||
fs->lfs_pages = 0; /* XXXUBC need a better way to count this */
|
||||
|
||||
lfs_writer_enter(fs, "fldirop");
|
||||
|
||||
if (lfs_dostats)
|
||||
++lfs_stats.flush_invoked;
|
||||
lfs_segwrite(fs->lfs_ivnode->v_mount, flags);
|
||||
fs->lfs_favail = 0; /* XXX */
|
||||
|
||||
lfs_writer_leave(fs);
|
||||
}
|
||||
|
@ -507,8 +517,9 @@ lfs_flush_fs(struct lfs *fs, int flags)
|
|||
* called and return with lfs_subsys_lock held.
|
||||
*/
|
||||
void
|
||||
lfs_flush(struct lfs *fs, int flags)
|
||||
lfs_flush(struct lfs *fs, int flags, int only_onefs)
|
||||
{
|
||||
extern u_int64_t locked_fakequeue_count;
|
||||
struct mount *mp, *nmp;
|
||||
|
||||
LOCK_ASSERT(simple_lock_held(&lfs_subsys_lock));
|
||||
|
@ -527,27 +538,38 @@ lfs_flush(struct lfs *fs, int flags)
|
|||
&lfs_subsys_lock);
|
||||
lfs_writing = 1;
|
||||
|
||||
lfs_subsys_pages = 0; /* XXXUBC need a better way to count this */
|
||||
simple_unlock(&lfs_subsys_lock);
|
||||
|
||||
if (only_onefs) {
|
||||
if (vfs_busy(fs->lfs_ivnode->v_mount, LK_NOWAIT, &mountlist_slock))
|
||||
goto errout;
|
||||
lfs_flush_fs(fs, flags);
|
||||
vfs_unbusy(fs->lfs_ivnode->v_mount);
|
||||
} else {
|
||||
locked_fakequeue_count = 0;
|
||||
simple_lock(&mountlist_slock);
|
||||
for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
|
||||
mp = nmp) {
|
||||
if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {
|
||||
#ifdef DEBUG_LFS
|
||||
printf("lfs_flush: fs is vfs_busy\n");
|
||||
#endif
|
||||
nmp = CIRCLEQ_NEXT(mp, mnt_list);
|
||||
continue;
|
||||
}
|
||||
if (strncmp(&mp->mnt_stat.f_fstypename[0], MOUNT_LFS,
|
||||
MFSNAMELEN) == 0)
|
||||
lfs_flush_fs(VFSTOUFS(mp)->um_lfs, flags);
|
||||
simple_lock(&mountlist_slock);
|
||||
nmp = CIRCLEQ_NEXT(mp, mnt_list);
|
||||
vfs_unbusy(mp);
|
||||
}
|
||||
simple_unlock(&mountlist_slock);
|
||||
}
|
||||
LFS_DEBUG_COUNTLOCKED("flush");
|
||||
wakeup(&lfs_subsys_pages);
|
||||
|
||||
simple_lock(&mountlist_slock);
|
||||
for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
|
||||
mp = nmp) {
|
||||
if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {
|
||||
nmp = CIRCLEQ_NEXT(mp, mnt_list);
|
||||
continue;
|
||||
}
|
||||
if (strncmp(&mp->mnt_stat.f_fstypename[0], MOUNT_LFS,
|
||||
MFSNAMELEN) == 0)
|
||||
lfs_flush_fs(VFSTOUFS(mp)->um_lfs, flags);
|
||||
simple_lock(&mountlist_slock);
|
||||
nmp = CIRCLEQ_NEXT(mp, mnt_list);
|
||||
vfs_unbusy(mp);
|
||||
}
|
||||
simple_unlock(&mountlist_slock);
|
||||
LFS_DEBUG_COUNTLOCKED("flush");
|
||||
|
||||
errout:
|
||||
simple_lock(&lfs_subsys_lock);
|
||||
KASSERT(lfs_writing);
|
||||
lfs_writing = 0;
|
||||
|
@ -567,6 +589,7 @@ lfs_check(struct vnode *vp, daddr_t blkno, int flags)
|
|||
int error;
|
||||
struct lfs *fs;
|
||||
struct inode *ip;
|
||||
extern pid_t lfs_writer_daemon;
|
||||
|
||||
error = 0;
|
||||
ip = VTOI(vp);
|
||||
|
@ -607,6 +630,8 @@ lfs_check(struct vnode *vp, daddr_t blkno, int flags)
|
|||
locked_queue_bytes + INOBYTES(fs), LFS_MAX_BYTES);
|
||||
if (lfs_subsys_pages > LFS_MAX_PAGES)
|
||||
printf("lssp = %d, max %d\n", lfs_subsys_pages, LFS_MAX_PAGES);
|
||||
if (lfs_fs_pagetrip && fs->lfs_pages > lfs_fs_pagetrip)
|
||||
printf("fssp = %d, trip at %d\n", fs->lfs_pages, lfs_fs_pagetrip);
|
||||
if (lfs_dirvcount > LFS_MAX_DIROP)
|
||||
printf("ldvc = %d, max %d\n", lfs_dirvcount, LFS_MAX_DIROP);
|
||||
if (fs->lfs_diropwait > 0)
|
||||
|
@ -617,7 +642,20 @@ lfs_check(struct vnode *vp, daddr_t blkno, int flags)
|
|||
locked_queue_bytes + INOBYTES(fs) > LFS_MAX_BYTES ||
|
||||
lfs_subsys_pages > LFS_MAX_PAGES ||
|
||||
lfs_dirvcount > LFS_MAX_DIROP || fs->lfs_diropwait > 0) {
|
||||
lfs_flush(fs, flags);
|
||||
lfs_flush(fs, flags, 0);
|
||||
}
|
||||
/*
|
||||
* If we didn't flush the whole thing, we might want to flush
|
||||
* one filesystem anyway.
|
||||
*/
|
||||
else if (lfs_fs_pagetrip && fs->lfs_pages > lfs_fs_pagetrip)
|
||||
{
|
||||
#ifdef LFS_PD
|
||||
++fs->lfs_pdflush;
|
||||
wakeup(&lfs_writer_daemon);
|
||||
#else
|
||||
lfs_flush(fs, flags, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
while (locked_queue_count + INOCOUNT(fs) > LFS_WAIT_BUFS ||
|
||||
|
@ -646,7 +684,7 @@ lfs_check(struct vnode *vp, daddr_t blkno, int flags)
|
|||
simple_lock(&lfs_subsys_lock);
|
||||
if (locked_queue_count + INOCOUNT(fs) > LFS_MAX_BUFS ||
|
||||
locked_queue_bytes + INOBYTES(fs) > LFS_MAX_BYTES) {
|
||||
lfs_flush(fs, flags | SEGM_CKP);
|
||||
lfs_flush(fs, flags | SEGM_CKP, 0);
|
||||
}
|
||||
}
|
||||
simple_unlock(&lfs_subsys_lock);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_extern.h,v 1.61 2004/05/20 06:34:33 atatat Exp $ */
|
||||
/* $NetBSD: lfs_extern.h,v 1.62 2005/02/26 05:40:42 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
|
||||
|
@ -85,7 +85,8 @@ MALLOC_DECLARE(M_SEGMENT);
|
|||
#define LFS_CLEAN_VNHEAD 2 /* put prev unrefed cleaned vnodes on head of free list */
|
||||
#define LFS_DOSTATS 3
|
||||
#define LFS_MAXPAGES 4
|
||||
#define LFS_MAXID 5
|
||||
#define LFS_FS_PAGETRIP 5
|
||||
#define LFS_MAXID 6
|
||||
|
||||
#define LFS_NAMES { \
|
||||
{ 0, 0 }, \
|
||||
|
@ -117,6 +118,7 @@ extern int lfs_allclean_wakeup;
|
|||
extern struct pool lfs_inode_pool; /* memory pool for inodes */
|
||||
extern struct pool lfs_dinode_pool; /* memory pool for dinodes */
|
||||
extern struct pool lfs_inoext_pool; /* memory pool for inode extension */
|
||||
extern struct pool lfs_lbnentry_pool; /* memory pool for balloc accounting */
|
||||
|
||||
extern int locked_queue_count;
|
||||
extern long locked_queue_bytes;
|
||||
|
@ -128,12 +130,18 @@ __BEGIN_DECLS
|
|||
/* lfs_alloc.c */
|
||||
int lfs_rf_valloc(struct lfs *, ino_t, int, struct proc *, struct vnode **);
|
||||
void lfs_vcreate(struct mount *, ino_t, struct vnode *);
|
||||
|
||||
/* lfs_balloc.c */
|
||||
void lfs_register_block(struct vnode *, daddr_t);
|
||||
void lfs_deregister_block(struct vnode *, daddr_t);
|
||||
void lfs_deregister_all(struct vnode *);
|
||||
|
||||
/* lfs_bio.c */
|
||||
int lfs_availwait(struct lfs *, int);
|
||||
int lfs_bwrite_ext(struct buf *, int);
|
||||
int lfs_fits(struct lfs *, int);
|
||||
void lfs_flush_fs(struct lfs *, int);
|
||||
void lfs_flush(struct lfs *, int);
|
||||
void lfs_flush(struct lfs *, int, int);
|
||||
int lfs_check(struct vnode *, daddr_t, int);
|
||||
void lfs_freebuf(struct lfs *, struct buf *);
|
||||
struct buf *lfs_newbuf(struct lfs *, struct vnode *, daddr_t, size_t, int);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_segment.c,v 1.155 2004/09/18 16:40:11 yamt Exp $ */
|
||||
/* $NetBSD: lfs_segment.c,v 1.156 2005/02/26 05:40:42 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_segment.c,v 1.155 2004/09/18 16:40:11 yamt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.156 2005/02/26 05:40:42 perseant Exp $");
|
||||
|
||||
#define ivndebug(vp,str) printf("ino %d: %s\n",VTOI(vp)->i_number,(str))
|
||||
|
||||
|
@ -1073,6 +1073,9 @@ lfs_gatherblock(struct segment *sp, struct buf *bp, int *sptr)
|
|||
/* Insert into the buffer list, update the FINFO block. */
|
||||
bp->b_flags |= B_GATHERED;
|
||||
|
||||
/* This block's accounting moves from lfs_favail to lfs_avail */
|
||||
lfs_deregister_block(sp->vp, bp->b_lblkno);
|
||||
|
||||
*sp->cbpp++ = bp;
|
||||
for (j = 0; j < blksinblk; j++)
|
||||
sp->fip->fi_blocks[sp->fip->fi_nblocks++] = bp->b_lblkno + j;
|
||||
|
@ -1216,6 +1219,7 @@ lfs_update_single(struct lfs *fs, struct segment *sp, struct vnode *vp,
|
|||
if (error)
|
||||
panic("lfs_updatemeta: ufs_bmaparray returned %d", error);
|
||||
|
||||
daddr = (daddr_t)((int32_t)daddr); /* XXX ondisk32 */
|
||||
KASSERT(daddr <= LFS_MAX_DADDR);
|
||||
if (daddr > 0)
|
||||
daddr = dbtofsb(fs, daddr);
|
||||
|
@ -1879,11 +1883,7 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
|
|||
ssp->ss_datasum = lfs_cksum_fold(sum);
|
||||
ssp->ss_sumsum = cksum(&ssp->ss_datasum,
|
||||
fs->lfs_sumsize - sizeof(ssp->ss_sumsum));
|
||||
#ifdef DIAGNOSTIC
|
||||
if (fs->lfs_bfree <
|
||||
btofsb(fs, ninos * fs->lfs_ibsize) + btofsb(fs, fs->lfs_sumsize))
|
||||
panic("lfs_writeseg: No diskspace for summary");
|
||||
#endif
|
||||
|
||||
fs->lfs_bfree -= (btofsb(fs, ninos * fs->lfs_ibsize) +
|
||||
btofsb(fs, fs->lfs_sumsize));
|
||||
|
||||
|
@ -2020,6 +2020,9 @@ lfs_writesuper(struct lfs *fs, daddr_t daddr)
|
|||
int s;
|
||||
struct vnode *devvp = VTOI(fs->lfs_ivnode)->i_devvp;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
KASSERT(fs->lfs_magic == LFS_MAGIC);
|
||||
#endif
|
||||
/*
|
||||
* If we can write one superblock while another is in
|
||||
* progress, we risk not having a complete checkpoint if we crash.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_subr.c,v 1.47 2004/03/09 06:43:18 yamt Exp $ */
|
||||
/* $NetBSD: lfs_subr.c,v 1.48 2005/02/26 05:40:42 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.47 2004/03/09 06:43:18 yamt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_subr.c,v 1.48 2005/02/26 05:40:42 perseant Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -399,7 +399,7 @@ lfs_unmark_dirop(struct lfs *fs)
|
|||
static void
|
||||
lfs_auto_segclean(struct lfs *fs)
|
||||
{
|
||||
int i, error;
|
||||
int i, error, s, waited;
|
||||
|
||||
/*
|
||||
* Now that we've swapped lfs_activesb, but while we still
|
||||
|
@ -407,6 +407,7 @@ lfs_auto_segclean(struct lfs *fs)
|
|||
* the empty ones clean.
|
||||
* XXX - do we really need to do them all at once?
|
||||
*/
|
||||
waited = 0;
|
||||
for (i = 0; i < fs->lfs_nseg; i++) {
|
||||
if ((fs->lfs_suflags[0][i] &
|
||||
(SEGUSE_ACTIVE | SEGUSE_DIRTY | SEGUSE_EMPTY)) ==
|
||||
|
@ -415,6 +416,14 @@ lfs_auto_segclean(struct lfs *fs)
|
|||
(SEGUSE_ACTIVE | SEGUSE_DIRTY | SEGUSE_EMPTY)) ==
|
||||
(SEGUSE_DIRTY | SEGUSE_EMPTY)) {
|
||||
|
||||
/* Make sure the sb is written before we clean */
|
||||
s = splbio();
|
||||
while (waited == 0 && fs->lfs_sbactive)
|
||||
tsleep(&fs->lfs_sbactive, PRIBIO+1, "lfs asb",
|
||||
0);
|
||||
splx(s);
|
||||
waited = 1;
|
||||
|
||||
if ((error = lfs_do_segclean(fs, i)) != 0) {
|
||||
#ifdef DEBUG
|
||||
printf("lfs_auto_segclean: lfs_do_segclean returned %d for seg %d\n", error, i);
|
||||
|
@ -514,8 +523,12 @@ lfs_segunlock(struct lfs *fs)
|
|||
if (sync)
|
||||
lfs_writesuper(fs, fs->lfs_sboffs[fs->lfs_activesb]);
|
||||
lfs_writesuper(fs, fs->lfs_sboffs[1 - fs->lfs_activesb]);
|
||||
if (!(fs->lfs_ivnode->v_mount->mnt_iflag & IMNT_UNMOUNT))
|
||||
if (!(fs->lfs_ivnode->v_mount->mnt_iflag & IMNT_UNMOUNT)) {
|
||||
lfs_auto_segclean(fs);
|
||||
/* If sync, we can clean the remainder too */
|
||||
if (sync)
|
||||
lfs_auto_segclean(fs);
|
||||
}
|
||||
fs->lfs_activesb = 1 - fs->lfs_activesb;
|
||||
simple_lock(&fs->lfs_interlock);
|
||||
--fs->lfs_seglock;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_syscalls.c,v 1.100 2003/12/04 14:57:47 yamt Exp $ */
|
||||
/* $NetBSD: lfs_syscalls.c,v 1.101 2005/02/26 05:40:42 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_syscalls.c,v 1.100 2003/12/04 14:57:47 yamt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_syscalls.c,v 1.101 2005/02/26 05:40:42 perseant Exp $");
|
||||
|
||||
#ifndef LFS
|
||||
# define LFS /* for prototypes in syscallargs.h */
|
||||
|
@ -756,6 +756,14 @@ lfs_bmapv(struct proc *p, fsid_t *fsidp, BLOCK_INFO *blkiov, int blkcnt)
|
|||
}
|
||||
numrefed++;
|
||||
} else {
|
||||
/*
|
||||
* Don't VFS_VGET if we're being unmounted,
|
||||
* since we hold vfs_busy().
|
||||
*/
|
||||
if (mntp->mnt_iflag & IMNT_UNMOUNT) {
|
||||
v_daddr = LFS_UNUSED_DADDR;
|
||||
continue;
|
||||
}
|
||||
error = VFS_VGET(mntp, blkp->bi_inode, &vp);
|
||||
if (error) {
|
||||
#ifdef DEBUG_LFS
|
||||
|
@ -927,7 +935,7 @@ lfs_do_segclean(struct lfs *fs, unsigned long segnum)
|
|||
--cip->dirty;
|
||||
fs->lfs_nclean = cip->clean;
|
||||
cip->bfree = fs->lfs_bfree;
|
||||
cip->avail = fs->lfs_avail - fs->lfs_ravail;
|
||||
cip->avail = fs->lfs_avail - fs->lfs_ravail - fs->lfs_favail;
|
||||
(void) LFS_BWRITE_LOG(bp);
|
||||
wakeup(&fs->lfs_avail);
|
||||
|
||||
|
@ -1074,6 +1082,16 @@ lfs_fastvget(struct mount *mp, ino_t ino, daddr_t daddr, struct vnode **vpp, str
|
|||
if (error != 0 || *vpp != NULL)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* getnewvnode(9) will call vfs_busy, which will block if the
|
||||
* filesystem is being unmounted; but umount(9) is waiting for
|
||||
* us because we're already holding the fs busy.
|
||||
* XXXMP
|
||||
*/
|
||||
if (mp->mnt_iflag & IMNT_UNMOUNT) {
|
||||
*vpp = NULL;
|
||||
return EDEADLK;
|
||||
}
|
||||
if ((error = getnewvnode(VT_LFS, mp, lfs_vnodeop_p, &vp)) != 0) {
|
||||
*vpp = NULL;
|
||||
return (error);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_vfsops.c,v 1.162 2005/01/11 00:19:36 mycroft Exp $ */
|
||||
/* $NetBSD: lfs_vfsops.c,v 1.163 2005/02/26 05:40:42 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.162 2005/01/11 00:19:36 mycroft Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.163 2005/02/26 05:40:42 perseant Exp $");
|
||||
|
||||
#if defined(_KERNEL_OPT)
|
||||
#include "opt_quota.h"
|
||||
|
@ -173,6 +173,8 @@ POOL_INIT(lfs_dinode_pool, sizeof(struct ufs1_dinode), 0, 0, 0, "lfsdinopl",
|
|||
&pool_allocator_nointr);
|
||||
POOL_INIT(lfs_inoext_pool, sizeof(struct lfs_inode_ext), 8, 0, 0, "lfsinoextpl",
|
||||
&pool_allocator_nointr);
|
||||
POOL_INIT(lfs_lbnentry_pool, sizeof(struct lbnentry), 0, 0, 0, "lfslbnpool",
|
||||
&pool_allocator_nointr);
|
||||
|
||||
/*
|
||||
* The writer daemon. UVM keeps track of how many dirty pages we are holding
|
||||
|
@ -211,6 +213,9 @@ lfs_writerd(void *arg)
|
|||
fs = VFSTOUFS(mp)->um_lfs;
|
||||
if (fs->lfs_pdflush ||
|
||||
!TAILQ_EMPTY(&fs->lfs_pchainhd)) {
|
||||
#ifdef DEBUG_LFS_FLUSH
|
||||
printf("daemon: pdflush set\n");
|
||||
#endif
|
||||
fs->lfs_pdflush = 0;
|
||||
lfs_flush_fs(fs, 0);
|
||||
}
|
||||
|
@ -244,7 +249,7 @@ lfs_writerd(void *arg)
|
|||
printf("daemon: lssp = %d, max %d\n",
|
||||
lfs_subsys_pages, LFS_MAX_PAGES);
|
||||
#endif /* DEBUG_LFS_FLUSH */
|
||||
lfs_flush(NULL, SEGM_WRITERD);
|
||||
lfs_flush(NULL, SEGM_WRITERD, 0);
|
||||
lfs_do_flush = 0;
|
||||
}
|
||||
}
|
||||
|
@ -265,6 +270,8 @@ lfs_init()
|
|||
"lfsdinopl", &pool_allocator_nointr);
|
||||
pool_init(&lfs_inoext_pool, sizeof(struct lfs_inode_ext), 8, 0, 0,
|
||||
"lfsinoextpl", &pool_allocator_nointr);
|
||||
pool_init(&lfs_lbnentry_pool, sizeof(struct lbnentry), 0, 0, 0,
|
||||
"lfslbnpool", &pool_allocator_nointr);
|
||||
#endif
|
||||
ufs_init();
|
||||
|
||||
|
@ -875,7 +882,7 @@ check_segsum(struct lfs *fs, daddr_t offset, u_int64_t nextserial,
|
|||
simple_lock(&lfs_subsys_lock);
|
||||
if (locked_queue_count > LFS_MAX_BUFS ||
|
||||
locked_queue_bytes > LFS_MAX_BYTES) {
|
||||
lfs_flush(fs, SEGM_CKP);
|
||||
lfs_flush(fs, SEGM_CKP, 0);
|
||||
}
|
||||
simple_unlock(&lfs_subsys_lock);
|
||||
}
|
||||
|
@ -946,7 +953,7 @@ lfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p)
|
|||
dfs = (struct dlfs *)bp->b_data;
|
||||
|
||||
/* Check the basics. */
|
||||
if (dfs->dlfs_magic != LFS_MAGIC || dfs->dlfs_bsize >= MAXBSIZE ||
|
||||
if (dfs->dlfs_magic != LFS_MAGIC || dfs->dlfs_bsize > MAXBSIZE ||
|
||||
dfs->dlfs_version > LFS_VERSION ||
|
||||
dfs->dlfs_bsize < sizeof(struct dlfs)) {
|
||||
#ifdef DEBUG_LFS
|
||||
|
@ -1047,6 +1054,21 @@ lfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p)
|
|||
fs->lfs_fsbtodb = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we aren't going to be able to write meaningfully to this
|
||||
* filesystem, and were not mounted readonly, bomb out now.
|
||||
*/
|
||||
if (fsbtob(fs, LFS_NRESERVE(fs)) > LFS_MAX_BYTES && !ronly) {
|
||||
printf("lfs_mount: to mount this filesystem read/write,"
|
||||
" we need BUFPAGES >= %lld\n",
|
||||
(long long)((bufmem_hiwater / bufmem_lowater) *
|
||||
LFS_INVERSE_MAX_BYTES(
|
||||
fsbtob(fs, LFS_NRESERVE(fs))) >> PAGE_SHIFT));
|
||||
free(fs, M_UFSMNT);
|
||||
error = EFBIG; /* XXX needs translation */
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Before rolling forward, lock so vget will sleep for other procs */
|
||||
fs->lfs_flags = LFS_NOTYET;
|
||||
fs->lfs_rfpid = p->p_pid;
|
||||
|
@ -1070,6 +1092,7 @@ lfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p)
|
|||
fs->lfs_activesb = 0;
|
||||
fs->lfs_uinodes = 0;
|
||||
fs->lfs_ravail = 0;
|
||||
fs->lfs_favail = 0;
|
||||
fs->lfs_sbactive = 0;
|
||||
|
||||
/* Set up the ifile and lock aflags */
|
||||
|
@ -1080,6 +1103,7 @@ lfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p)
|
|||
fs->lfs_seglock = 0;
|
||||
fs->lfs_pdflush = 0;
|
||||
fs->lfs_sleepers = 0;
|
||||
fs->lfs_pages = 0;
|
||||
simple_lock_init(&fs->lfs_interlock);
|
||||
lockinit(&fs->lfs_fraglock, PINOD, "lfs_fraglock", 0, 0);
|
||||
|
||||
|
@ -1325,14 +1349,19 @@ lfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p)
|
|||
if (fs->lfs_ivnode->v_size / fs->lfs_bsize > LFS_MAX_BUFS) {
|
||||
fs->lfs_flags |= LFS_WARNED;
|
||||
printf("lfs_mountfs: please consider increasing NBUF to at least %lld\n",
|
||||
(long long)(fs->lfs_ivnode->v_size / fs->lfs_bsize) * (nbuf / LFS_MAX_BUFS));
|
||||
(long long)LFS_INVERSE_MAX_BUFS((fs->lfs_ivnode->v_size / fs->lfs_bsize) - fs->lfs_segtabsz));
|
||||
}
|
||||
if (fs->lfs_ivnode->v_size > LFS_MAX_BYTES) {
|
||||
fs->lfs_flags |= LFS_WARNED;
|
||||
printf("lfs_mountfs: please consider increasing BUFPAGES to at least %lld\n",
|
||||
(long long)(fs->lfs_ivnode->v_size * bufpages / LFS_MAX_BYTES));
|
||||
(long long)LFS_INVERSE_MAX_BYTES((fs->lfs_ivnode->v_size - fs->lfs_segtabsz * fs->lfs_bsize) >> PAGE_SHIFT));
|
||||
}
|
||||
|
||||
/* Start the pagedaemon-anticipating daemon */
|
||||
if (lfs_writer_daemon == 0 &&
|
||||
kthread_create1(lfs_writerd, NULL, NULL, "lfs_writer") != 0)
|
||||
panic("fork lfs_writer");
|
||||
|
||||
return (0);
|
||||
|
||||
out:
|
||||
|
@ -1346,11 +1375,6 @@ out:
|
|||
mp->mnt_data = NULL;
|
||||
}
|
||||
|
||||
/* Start the pagedaemon-anticipating daemon */
|
||||
if (lfs_writer_daemon == 0 &&
|
||||
kthread_create1(lfs_writerd, NULL, NULL, "lfs_writer") != 0)
|
||||
panic("fork lfs_writer");
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -1472,7 +1496,12 @@ lfs_statvfs(struct mount *mp, struct statvfs *sbp, struct proc *p)
|
|||
sbp->f_frsize = fs->lfs_fsize;
|
||||
sbp->f_iosize = fs->lfs_bsize;
|
||||
sbp->f_blocks = fsbtofrags(fs, LFS_EST_NONMETA(fs));
|
||||
|
||||
sbp->f_bfree = fsbtofrags(fs, LFS_EST_BFREE(fs));
|
||||
KASSERT(sbp->f_bfree <= fs->lfs_dsize);
|
||||
if (sbp->f_bfree < 0)
|
||||
sbp->f_bfree = 0;
|
||||
|
||||
sbp->f_bresvd = fsbtofrags(fs, LFS_EST_RSVD(fs));
|
||||
if (sbp->f_bfree > sbp->f_bresvd)
|
||||
sbp->f_bavail = sbp->f_bfree - sbp->f_bresvd;
|
||||
|
@ -1751,7 +1780,8 @@ sysctl_lfs_dostats(SYSCTLFN_ARGS)
|
|||
|
||||
SYSCTL_SETUP(sysctl_vfs_lfs_setup, "sysctl vfs.lfs subtree setup")
|
||||
{
|
||||
extern int lfs_writeindir, lfs_dostats, lfs_clean_vnhead;
|
||||
extern int lfs_writeindir, lfs_dostats, lfs_clean_vnhead,
|
||||
lfs_fs_pagetrip;
|
||||
|
||||
sysctl_createv(clog, 0, NULL, NULL,
|
||||
CTLFLAG_PERMANENT,
|
||||
|
@ -1786,6 +1816,12 @@ SYSCTL_SETUP(sysctl_vfs_lfs_setup, "sysctl vfs.lfs subtree setup")
|
|||
SYSCTL_DESCR("Maintain statistics on LFS operations"),
|
||||
sysctl_lfs_dostats, 0, &lfs_dostats, 0,
|
||||
CTL_VFS, 5, LFS_DOSTATS, CTL_EOL);
|
||||
sysctl_createv(clog, 0, NULL, NULL,
|
||||
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
||||
CTLTYPE_INT, "pagetrip",
|
||||
SYSCTL_DESCR("How many dirty segments of pages in fs trips write"),
|
||||
sysctl_lfs_dostats, 0, &lfs_fs_pagetrip, 0,
|
||||
CTL_VFS, 5, LFS_FS_PAGETRIP, CTL_EOL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1798,6 +1834,8 @@ static boolean_t
|
|||
lfs_issequential_hole(const struct ufsmount *ump,
|
||||
daddr_t daddr0, daddr_t daddr1)
|
||||
{
|
||||
daddr0 = (daddr_t)((int32_t)daddr0); /* XXX ondisk32 */
|
||||
daddr1 = (daddr_t)((int32_t)daddr1); /* XXX ondisk32 */
|
||||
|
||||
KASSERT(daddr0 == UNWRITTEN ||
|
||||
(0 <= daddr0 && daddr0 <= LFS_MAX_DADDR));
|
||||
|
@ -1859,42 +1897,21 @@ lfs_gop_write(struct vnode *vp, struct vm_page **pgs, int npages, int flags)
|
|||
* and the pagedaemon tries to write pages---problem is
|
||||
* that the pagedaemon never acquires the segment lock.
|
||||
*
|
||||
* Alternatively, pages that were clean when we called
|
||||
* genfs_putpages may have become dirty in the meantime. In this
|
||||
* case the segment header is not properly set up for blocks
|
||||
* to be added to it.
|
||||
*
|
||||
* Unbusy and unclean the pages, and put them on the ACTIVE
|
||||
* queue under the hypothesis that they couldn't have got here
|
||||
* unless they were modified *quite* recently.
|
||||
*
|
||||
* XXXUBC that last statement is an oversimplification of course.
|
||||
*/
|
||||
if (!(fs->lfs_seglock) || fs->lfs_lockpid != curproc->p_pid) {
|
||||
simple_lock(&vp->v_interlock);
|
||||
#ifdef DEBUG
|
||||
printf("lfs_gop_write: seglock not held\n");
|
||||
#endif
|
||||
uvm_lock_pageq();
|
||||
for (i = 0; i < npages; i++) {
|
||||
pg = pgs[i];
|
||||
|
||||
if (pg->flags & PG_PAGEOUT)
|
||||
uvmexp.paging--;
|
||||
if (pg->flags & PG_DELWRI) {
|
||||
uvm_pageunwire(pg);
|
||||
}
|
||||
uvm_pageactivate(pg);
|
||||
pg->flags &= ~(PG_CLEAN|PG_DELWRI|PG_PAGEOUT|PG_RELEASED);
|
||||
#ifdef DEBUG_LFS
|
||||
printf("pg[%d]->flags = %x\n", i, pg->flags);
|
||||
printf("pg[%d]->pqflags = %x\n", i, pg->pqflags);
|
||||
printf("pg[%d]->uanon = %p\n", i, pg->uanon);
|
||||
printf("pg[%d]->uobject = %p\n", i, pg->uobject);
|
||||
printf("pg[%d]->wire_count = %d\n", i, pg->wire_count);
|
||||
printf("pg[%d]->loan_count = %d\n", i, pg->loan_count);
|
||||
#endif
|
||||
}
|
||||
/* uvm_pageunbusy takes care of PG_BUSY, PG_WANTED */
|
||||
uvm_page_unbusy(pgs, npages);
|
||||
uvm_unlock_pageq();
|
||||
simple_unlock(&vp->v_interlock);
|
||||
return EAGAIN;
|
||||
if (!(fs->lfs_seglock) || fs->lfs_lockpid != curproc->p_pid ||
|
||||
(ip->i_lfs_iflags & LFSI_NO_GOP_WRITE) ||
|
||||
(pgs[0]->offset & fs->lfs_bmask) != 0) {
|
||||
goto tryagain;
|
||||
}
|
||||
|
||||
UVMHIST_LOG(ubchist, "vp %p pgs %p npages %d flags 0x%x",
|
||||
|
@ -1944,6 +1961,9 @@ lfs_gop_write(struct vnode *vp, struct vm_page **pgs, int npages, int flags)
|
|||
panic("lfs_gop_write: non-integer blocks");
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX We can deadlock here on pager_map with UVMPAGER_MAPIN_WAITOK.
|
||||
*/
|
||||
kva = uvm_pagermapin(pgs, npages,
|
||||
UVMPAGER_MAPIN_WRITE | UVMPAGER_MAPIN_WAITOK);
|
||||
|
||||
|
@ -2070,6 +2090,46 @@ lfs_gop_write(struct vnode *vp, struct vm_page **pgs, int npages, int flags)
|
|||
}
|
||||
UVMHIST_LOG(ubchist, "returning 0", 0,0,0,0);
|
||||
return (0);
|
||||
|
||||
tryagain:
|
||||
/*
|
||||
* We can't write the pages, for whatever reason.
|
||||
* Clean up after ourselves, and make the caller try again.
|
||||
*/
|
||||
simple_lock(&vp->v_interlock);
|
||||
#ifdef DEBUG
|
||||
if (ip->i_lfs_iflags & LFSI_NO_GOP_WRITE)
|
||||
printf("lfs_gop_write: clean pages dirtied\n");
|
||||
else if ((pgs[0]->offset & fs->lfs_bmask) != 0)
|
||||
printf("lfs_gop_write: start not on block boundary\n");
|
||||
else
|
||||
printf("lfs_gop_write: seglock not held\n");
|
||||
#endif
|
||||
uvm_lock_pageq();
|
||||
for (i = 0; i < npages; i++) {
|
||||
pg = pgs[i];
|
||||
|
||||
if (pg->flags & PG_PAGEOUT)
|
||||
uvmexp.paging--;
|
||||
if (pg->flags & PG_DELWRI) {
|
||||
uvm_pageunwire(pg);
|
||||
}
|
||||
uvm_pageactivate(pg);
|
||||
pg->flags &= ~(PG_CLEAN|PG_DELWRI|PG_PAGEOUT|PG_RELEASED);
|
||||
#ifdef DEBUG_LFS
|
||||
printf("pg[%d]->flags = %x\n", i, pg->flags);
|
||||
printf("pg[%d]->pqflags = %x\n", i, pg->pqflags);
|
||||
printf("pg[%d]->uanon = %p\n", i, pg->uanon);
|
||||
printf("pg[%d]->uobject = %p\n", i, pg->uobject);
|
||||
printf("pg[%d]->wire_count = %d\n", i, pg->wire_count);
|
||||
printf("pg[%d]->loan_count = %d\n", i, pg->loan_count);
|
||||
#endif
|
||||
}
|
||||
/* uvm_pageunbusy takes care of PG_BUSY, PG_WANTED */
|
||||
uvm_page_unbusy(pgs, npages);
|
||||
uvm_unlock_pageq();
|
||||
simple_unlock(&vp->v_interlock);
|
||||
return EAGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2099,6 +2159,7 @@ lfs_vinit(struct mount *mp, struct vnode **vpp)
|
|||
* cases re-init ip, the underlying vnode/inode may have changed.
|
||||
*/
|
||||
ufs_vinit(mp, lfs_specop_p, lfs_fifoop_p, &vp);
|
||||
ip = VTOI(vp);
|
||||
|
||||
memset(ip->i_lfs_fragsize, 0, NDADDR * sizeof(*ip->i_lfs_fragsize));
|
||||
if (vp->v_type != VLNK || ip->i_size >= ip->i_ump->um_maxsymlinklen) {
|
||||
|
@ -2106,6 +2167,9 @@ lfs_vinit(struct mount *mp, struct vnode **vpp)
|
|||
#ifdef DEBUG
|
||||
for (i = (ip->i_size + fs->lfs_bsize - 1) >> fs->lfs_bshift;
|
||||
i < NDADDR; i++) {
|
||||
if ((vp->v_type == VBLK || vp->v_type == VCHR) &&
|
||||
i == 0)
|
||||
continue;
|
||||
if (ip->i_ffs1_db[i] != 0) {
|
||||
inconsistent:
|
||||
lfs_dump_dinode(ip->i_din.ffs1_din);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_vnops.c,v 1.133 2005/01/25 23:55:21 wrstuden Exp $ */
|
||||
/* $NetBSD: lfs_vnops.c,v 1.134 2005/02/26 05:40:42 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.133 2005/01/25 23:55:21 wrstuden Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,v 1.134 2005/02/26 05:40:42 perseant Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -267,6 +267,8 @@ const struct vnodeopv_entry_desc lfs_fifoop_entries[] = {
|
|||
const struct vnodeopv_desc lfs_fifoop_opv_desc =
|
||||
{ &lfs_fifoop_p, lfs_fifoop_entries };
|
||||
|
||||
static int check_dirty(struct lfs *, struct vnode *, off_t, off_t, off_t, int, int);
|
||||
|
||||
/*
|
||||
* A function version of LFS_ITIMES, for the UFS functions which call ITIMES
|
||||
*/
|
||||
|
@ -372,8 +374,6 @@ lfs_inactive(void *v)
|
|||
#define SET_DIROP2(vp, vp2) lfs_set_dirop((vp), (vp2))
|
||||
static int lfs_set_dirop(struct vnode *, struct vnode *);
|
||||
|
||||
#define NRESERVE(fs) (btofsb(fs, (NIADDR + 3 + (2 * NIADDR + 3)) << fs->lfs_bshift))
|
||||
|
||||
static int
|
||||
lfs_set_dirop(struct vnode *vp, struct vnode *vp2)
|
||||
{
|
||||
|
@ -385,10 +385,10 @@ lfs_set_dirop(struct vnode *vp, struct vnode *vp2)
|
|||
|
||||
fs = VTOI(vp)->i_lfs;
|
||||
/*
|
||||
* We might need one directory block plus supporting indirect blocks,
|
||||
* plus an inode block and ifile page for the new vnode.
|
||||
* LFS_NRESERVE calculates direct and indirect blocks as well
|
||||
* as an inode block; an overestimate in most cases.
|
||||
*/
|
||||
if ((error = lfs_reserve(fs, vp, vp2, NRESERVE(fs))) != 0)
|
||||
if ((error = lfs_reserve(fs, vp, vp2, LFS_NRESERVE(fs))) != 0)
|
||||
return (error);
|
||||
|
||||
if (fs->lfs_dirops == 0)
|
||||
|
@ -436,7 +436,7 @@ restart:
|
|||
return 0;
|
||||
|
||||
unreserve:
|
||||
lfs_reserve(fs, vp, vp2, -NRESERVE(fs));
|
||||
lfs_reserve(fs, vp, vp2, -LFS_NRESERVE(fs));
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -451,7 +451,7 @@ unreserve:
|
|||
wakeup(&(fs)->lfs_writer); \
|
||||
lfs_check((vp),LFS_UNUSED_LBN,0); \
|
||||
} \
|
||||
lfs_reserve((fs), vp, vp2, -NRESERVE(fs)); /* XXX */ \
|
||||
lfs_reserve((fs), vp, vp2, -LFS_NRESERVE(fs)); /* XXX */ \
|
||||
vrele(vp); \
|
||||
if (vp2) \
|
||||
vrele(vp2); \
|
||||
|
@ -565,6 +565,7 @@ lfs_mknod(void *v)
|
|||
ip->i_ffs1_rdev = vap->va_rdev;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Call fsync to write the vnode so that we don't have to deal with
|
||||
* flushing it when it's marked VDIROP|VXLOCK.
|
||||
|
@ -585,11 +586,13 @@ lfs_mknod(void *v)
|
|||
* the inode cache.
|
||||
*/
|
||||
/* Used to be vput, but that causes us to call VOP_INACTIVE twice. */
|
||||
|
||||
VOP_UNLOCK(*vpp, 0);
|
||||
lfs_vunref(*vpp);
|
||||
(*vpp)->v_type = VNON;
|
||||
vgone(*vpp);
|
||||
error = VFS_VGET(mp, ino, vpp);
|
||||
|
||||
if (error != 0) {
|
||||
*vpp = NULL;
|
||||
return (error);
|
||||
|
@ -1006,6 +1009,7 @@ lfs_reclaim(void *v)
|
|||
LFS_CLR_UINO(ip, IN_ALLMOD);
|
||||
if ((error = ufs_reclaim(vp, ap->a_p)))
|
||||
return (error);
|
||||
lfs_deregister_all(vp);
|
||||
pool_put(&lfs_dinode_pool, VTOI(vp)->i_din.ffs1_din);
|
||||
pool_put(&lfs_inoext_pool, ip->inode_ext.lfs);
|
||||
ip->inode_ext.lfs = NULL;
|
||||
|
@ -1217,6 +1221,7 @@ lfs_fcntl(void *v)
|
|||
fsid_t *fsidp;
|
||||
struct lfs *fs;
|
||||
struct buf *bp;
|
||||
fhandle_t *fhp;
|
||||
daddr_t off;
|
||||
|
||||
/* Only respect LFS fcntls on fs root or Ifile */
|
||||
|
@ -1235,9 +1240,11 @@ lfs_fcntl(void *v)
|
|||
|
||||
switch (ap->a_command) {
|
||||
case LFCNSEGWAITALL:
|
||||
case LFCNSEGWAITALL_COMPAT:
|
||||
fsidp = NULL;
|
||||
/* FALLSTHROUGH */
|
||||
case LFCNSEGWAIT:
|
||||
case LFCNSEGWAIT_COMPAT:
|
||||
tvp = (struct timeval *)ap->a_data;
|
||||
simple_lock(&fs->lfs_interlock);
|
||||
++fs->lfs_sleepers;
|
||||
|
@ -1316,6 +1323,14 @@ lfs_fcntl(void *v)
|
|||
|
||||
return 0;
|
||||
|
||||
case LFCNIFILEFH:
|
||||
/* Return the filehandle of the Ifile */
|
||||
if ((error = suser(ap->a_p->p_ucred, &ap->a_p->p_acflag)) != 0)
|
||||
return (error);
|
||||
fhp = (struct fhandle *)ap->a_data;
|
||||
fhp->fh_fsid = *fsidp;
|
||||
return lfs_vptofh(fs->lfs_ivnode, &(fhp->fh_fid));
|
||||
|
||||
default:
|
||||
return ufs_fcntl(v);
|
||||
}
|
||||
|
@ -1672,7 +1687,16 @@ lfs_putpages(void *v)
|
|||
ap->a_flags, 1) != 0)
|
||||
break;
|
||||
|
||||
if ((r = genfs_putpages(v)) != EDEADLK)
|
||||
/*
|
||||
* Sometimes pages are dirtied between the time that
|
||||
* we check and the time we try to clean them.
|
||||
* Instruct lfs_gop_write to return EDEADLK in this case
|
||||
* so we can write them properly.
|
||||
*/
|
||||
ip->i_lfs_iflags |= LFSI_NO_GOP_WRITE;
|
||||
r = genfs_putpages(v);
|
||||
ip->i_lfs_iflags &= ~LFSI_NO_GOP_WRITE;
|
||||
if (r != EDEADLK)
|
||||
return r;
|
||||
|
||||
/* Start over. */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: ufs_readwrite.c,v 1.60 2005/01/09 16:42:44 chs Exp $ */
|
||||
/* $NetBSD: ufs_readwrite.c,v 1.61 2005/02/26 05:40:42 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1993
|
||||
|
@ -32,7 +32,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(1, "$NetBSD: ufs_readwrite.c,v 1.60 2005/01/09 16:42:44 chs Exp $");
|
||||
__KERNEL_RCSID(1, "$NetBSD: ufs_readwrite.c,v 1.61 2005/02/26 05:40:42 perseant Exp $");
|
||||
|
||||
#ifdef LFS_READWRITE
|
||||
#define BLKSIZE(a, b, c) blksize(a, b, c)
|
||||
|
@ -285,6 +285,7 @@ WRITE(void *v)
|
|||
if (usepc) {
|
||||
simple_lock(&lfs_subsys_lock);
|
||||
lfs_subsys_pages += round_page(uio->uio_resid) >> PAGE_SHIFT;
|
||||
fs->lfs_pages += round_page(uio->uio_resid) >> PAGE_SHIFT;
|
||||
simple_unlock(&lfs_subsys_lock);
|
||||
}
|
||||
lfs_check(vp, LFS_UNUSED_LBN, 0);
|
||||
|
|
Loading…
Reference in New Issue