2005-12-11 15:16:03 +03:00
|
|
|
/* $NetBSD: lfs_inode.c,v 1.100 2005/12/11 12:25:26 christos Exp $ */
|
1994-06-29 10:39:25 +04:00
|
|
|
|
1999-03-10 03:20:00 +03:00
|
|
|
/*-
|
Add code to UBCify LFS. This is still behind "#ifdef LFS_UBC" for now
(there are still some details to work out) but expect that to go
away soon. To support these basic changes (creation of lfs_putpages,
lfs_gop_write, mods to lfs_balloc) several other changes were made, to
wit:
* Create a writer daemon kernel thread whose purpose is to handle page
writes for the pagedaemon, but which also takes over some of the
functions of lfs_check(). This thread is started the first time an
LFS is mounted.
* Add a "flags" parameter to GOP_SIZE. Current values are
GOP_SIZE_READ, meaning that the call should return the size of the
in-core version of the file, and GOP_SIZE_WRITE, meaning that it
should return the on-disk size. One of GOP_SIZE_READ or
GOP_SIZE_WRITE must be specified.
* Instead of using malloc(...M_WAITOK) for everything, reserve enough
resources to get by and use malloc(...M_NOWAIT), using the reserves if
necessary. Use the pool subsystem for structures small enough that
this is feasible. This also obsoletes LFS_THROTTLE.
And a few that are not strictly necessary:
* Moves the LFS inode extensions off onto a separately allocated
structure; getting closer to LFS as an LKM. "Welcome to 1.6O."
* Unified GOP_ALLOC between FFS and LFS.
* Update LFS copyright headers to correct values.
* Actually cast to unsigned in lfs_shellsort, like the comment says.
* Keep track of which segments were empty before the previous
checkpoint; any segments that pass two checkpoints both dirty and
empty can be summarily cleaned. Do this. Right now lfs_segclean
still works, but this should be turned into an effectless
compatibility syscall.
2003-02-18 02:48:08 +03:00
|
|
|
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
|
1999-03-10 03:20:00 +03:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
|
|
* by Konrad E. Schroder <perseant@hhhh.org>.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
2003-02-20 07:27:23 +03:00
|
|
|
* This product includes software developed by the NetBSD
|
|
|
|
* Foundation, Inc. and its contributors.
|
1999-03-10 03:20:00 +03:00
|
|
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
1994-06-08 15:41:58 +04:00
|
|
|
/*
|
|
|
|
* Copyright (c) 1986, 1989, 1991, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2003-08-07 20:26:28 +04:00
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
1994-06-08 15:41:58 +04:00
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
1998-03-01 05:20:01 +03:00
|
|
|
* @(#)lfs_inode.c 8.9 (Berkeley) 5/8/95
|
1994-06-08 15:41:58 +04:00
|
|
|
*/
|
|
|
|
|
2001-11-08 05:39:06 +03:00
|
|
|
#include <sys/cdefs.h>
|
2005-12-11 15:16:03 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: lfs_inode.c,v 1.100 2005/12/11 12:25:26 christos Exp $");
|
2001-11-08 05:39:06 +03:00
|
|
|
|
2001-05-30 15:57:16 +04:00
|
|
|
#if defined(_KERNEL_OPT)
|
1998-06-08 08:27:50 +04:00
|
|
|
#include "opt_quota.h"
|
1998-06-09 11:46:31 +04:00
|
|
|
#endif
|
1998-06-08 08:27:50 +04:00
|
|
|
|
1994-06-08 15:41:58 +04:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/buf.h>
|
|
|
|
#include <sys/vnode.h>
|
|
|
|
#include <sys/kernel.h>
|
2000-06-28 00:57:11 +04:00
|
|
|
#include <sys/trace.h>
|
|
|
|
#include <sys/resourcevar.h>
|
1994-06-08 15:41:58 +04:00
|
|
|
|
|
|
|
#include <ufs/ufs/quota.h>
|
|
|
|
#include <ufs/ufs/inode.h>
|
|
|
|
#include <ufs/ufs/ufsmount.h>
|
|
|
|
#include <ufs/ufs/ufs_extern.h>
|
|
|
|
|
|
|
|
#include <ufs/lfs/lfs.h>
|
|
|
|
#include <ufs/lfs/lfs_extern.h>
|
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
static int lfs_update_seguse(struct lfs *, long, size_t);
|
2003-01-25 00:55:02 +03:00
|
|
|
static int lfs_indirtrunc (struct inode *, daddr_t, daddr_t,
|
|
|
|
daddr_t, int, long *, long *, long *, size_t *,
|
2005-12-11 15:16:03 +03:00
|
|
|
struct lwp *);
|
2000-06-28 00:57:11 +04:00
|
|
|
static int lfs_blkfree (struct lfs *, daddr_t, size_t, long *, size_t *);
|
|
|
|
static int lfs_vtruncbuf(struct vnode *, daddr_t, int, int);
|
|
|
|
|
1994-06-08 15:41:58 +04:00
|
|
|
/* Search a block for a specific dinode. */
|
2003-04-02 14:39:19 +04:00
|
|
|
struct ufs1_dinode *
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
lfs_ifind(struct lfs *fs, ino_t ino, struct buf *bp)
|
1994-06-08 15:41:58 +04:00
|
|
|
{
|
2003-04-02 14:39:19 +04:00
|
|
|
struct ufs1_dinode *dip = (struct ufs1_dinode *)bp->b_data;
|
|
|
|
struct ufs1_dinode *ldip, *fin;
|
2005-02-27 01:31:44 +03:00
|
|
|
|
2005-04-02 01:59:46 +04:00
|
|
|
ASSERT_NO_SEGLOCK(fs);
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
/*
|
2002-07-06 05:30:11 +04:00
|
|
|
* Read the inode block backwards, since later versions of the
|
|
|
|
* inode will supercede earlier ones. Though it is unlikely, it is
|
|
|
|
* possible that the same inode will appear in the same inode block.
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
*/
|
2005-03-08 03:18:19 +03:00
|
|
|
fin = dip + INOPB(fs);
|
2002-07-06 05:30:11 +04:00
|
|
|
for (ldip = fin - 1; ldip >= dip; --ldip)
|
1994-06-08 15:41:58 +04:00
|
|
|
if (ldip->di_inumber == ino)
|
|
|
|
return (ldip);
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
|
|
|
|
printf("searched %d entries\n", (int)(fin - dip));
|
2000-07-03 05:45:46 +04:00
|
|
|
printf("offset is 0x%x (seg %d)\n", fs->lfs_offset,
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
dtosn(fs, fs->lfs_offset));
|
2003-01-25 00:55:02 +03:00
|
|
|
printf("block is 0x%llx (seg %lld)\n",
|
|
|
|
(unsigned long long)dbtofsb(fs, bp->b_blkno),
|
|
|
|
(long long)dtosn(fs, dbtofsb(fs, bp->b_blkno)));
|
2002-05-15 00:03:53 +04:00
|
|
|
|
|
|
|
return NULL;
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2005-11-02 15:38:58 +03:00
|
|
|
lfs_update(struct vnode *vp, const struct timespec *acc,
|
|
|
|
const struct timespec *mod, int updflags)
|
1996-02-10 01:28:45 +03:00
|
|
|
{
|
1994-06-08 15:41:58 +04:00
|
|
|
struct inode *ip;
|
1999-06-01 07:00:40 +04:00
|
|
|
struct lfs *fs = VFSTOUFS(vp->v_mount)->um_lfs;
|
2002-05-15 00:03:53 +04:00
|
|
|
int s;
|
2004-08-14 05:08:02 +04:00
|
|
|
int flags;
|
2005-02-27 01:31:44 +03:00
|
|
|
|
2005-04-02 01:59:46 +04:00
|
|
|
ASSERT_NO_SEGLOCK(fs);
|
1998-03-01 05:20:01 +03:00
|
|
|
if (vp->v_mount->mnt_flag & MNT_RDONLY)
|
1994-06-08 15:41:58 +04:00
|
|
|
return (0);
|
1998-03-01 05:20:01 +03:00
|
|
|
ip = VTOI(vp);
|
1999-03-10 03:20:00 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we are called from vinvalbuf, and the file's blocks have
|
|
|
|
* already been scheduled for writing, but the writes have not
|
|
|
|
* yet completed, lfs_vflush will not be called, and vinvalbuf
|
2003-02-20 07:27:23 +03:00
|
|
|
* will cause a panic. So, we must wait until any pending write
|
2000-05-14 03:43:06 +04:00
|
|
|
* for our inode completes, if we are called with UPDATE_WAIT set.
|
1999-03-10 03:20:00 +03:00
|
|
|
*/
|
2002-05-15 00:03:53 +04:00
|
|
|
s = splbio();
|
2005-04-02 01:59:46 +04:00
|
|
|
simple_lock(&vp->v_interlock);
|
2005-11-02 15:38:58 +03:00
|
|
|
while ((updflags & (UPDATE_WAIT|UPDATE_DIROP)) == UPDATE_WAIT &&
|
2000-05-14 03:43:06 +04:00
|
|
|
WRITEINPROG(vp)) {
|
2005-03-08 03:18:19 +03:00
|
|
|
DLOG((DLOG_SEG, "lfs_update: sleeping on ino %d"
|
|
|
|
" (in progress)\n", ip->i_number));
|
2005-04-02 01:59:46 +04:00
|
|
|
ltsleep(vp, (PRIBIO+1), "lfs_update", 0, &vp->v_interlock);
|
1999-03-10 03:20:00 +03:00
|
|
|
}
|
2005-04-02 01:59:46 +04:00
|
|
|
simple_unlock(&vp->v_interlock);
|
2002-05-15 00:03:53 +04:00
|
|
|
splx(s);
|
2005-11-02 15:38:58 +03:00
|
|
|
LFS_ITIMES(ip, acc, mod, NULL);
|
|
|
|
if (updflags & UPDATE_CLOSE)
|
2004-08-14 05:08:02 +04:00
|
|
|
flags = ip->i_flag & (IN_MODIFIED | IN_ACCESSED | IN_CLEANING);
|
|
|
|
else
|
|
|
|
flags = ip->i_flag & (IN_MODIFIED | IN_CLEANING);
|
|
|
|
if (flags == 0)
|
1994-06-08 15:41:58 +04:00
|
|
|
return (0);
|
2005-02-27 01:31:44 +03:00
|
|
|
|
1994-06-08 15:41:58 +04:00
|
|
|
/* If sync, push back the vnode and any dirty blocks it may have. */
|
2005-11-02 15:38:58 +03:00
|
|
|
if ((updflags & (UPDATE_WAIT|UPDATE_DIROP)) == UPDATE_WAIT) {
|
1999-06-01 07:00:40 +04:00
|
|
|
/* Avoid flushing VDIROP. */
|
2005-04-02 01:59:46 +04:00
|
|
|
simple_lock(&fs->lfs_interlock);
|
1999-06-01 07:00:40 +04:00
|
|
|
++fs->lfs_diropwait;
|
2001-11-24 00:44:25 +03:00
|
|
|
while (vp->v_flag & VDIROP) {
|
2005-03-08 03:18:19 +03:00
|
|
|
DLOG((DLOG_DIROP, "lfs_update: sleeping on inode %d"
|
|
|
|
" (dirops)\n", ip->i_number));
|
|
|
|
DLOG((DLOG_DIROP, "lfs_update: vflags 0x%x, iflags"
|
|
|
|
" 0x%x\n", vp->v_flag, ip->i_flag));
|
2001-11-24 00:44:25 +03:00
|
|
|
if (fs->lfs_dirops == 0)
|
2000-06-28 00:57:11 +04:00
|
|
|
lfs_flush_fs(fs, SEGM_SYNC);
|
1999-06-01 07:00:40 +04:00
|
|
|
else
|
2005-04-02 01:59:46 +04:00
|
|
|
ltsleep(&fs->lfs_writer, PRIBIO+1, "lfs_fsync",
|
|
|
|
0, &fs->lfs_interlock);
|
1999-06-01 07:00:40 +04:00
|
|
|
/* XXX KS - by falling out here, are we writing the vn
|
|
|
|
twice? */
|
|
|
|
}
|
|
|
|
--fs->lfs_diropwait;
|
2005-04-02 01:59:46 +04:00
|
|
|
simple_unlock(&fs->lfs_interlock);
|
1999-06-01 07:00:40 +04:00
|
|
|
return lfs_vflush(vp);
|
2003-02-20 07:27:23 +03:00
|
|
|
}
|
1999-06-01 07:00:40 +04:00
|
|
|
return 0;
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
#define SINGLE 0 /* index of single indirect block */
|
|
|
|
#define DOUBLE 1 /* index of double indirect block */
|
|
|
|
#define TRIPLE 2 /* index of triple indirect block */
|
1994-06-08 15:41:58 +04:00
|
|
|
/*
|
2000-06-28 00:57:11 +04:00
|
|
|
* Truncate the inode oip to at most length size, freeing the
|
|
|
|
* disk blocks.
|
1994-06-08 15:41:58 +04:00
|
|
|
*/
|
2005-11-02 15:38:58 +03:00
|
|
|
/* VOP_BWRITE 1 + NIADDR + lfs_balloc == 2 + 2*NIADDR times */
|
2002-07-06 05:30:11 +04:00
|
|
|
|
1994-06-08 15:41:58 +04:00
|
|
|
int
|
2005-11-02 15:38:58 +03:00
|
|
|
lfs_truncate(struct vnode *ovp, off_t length, int ioflag,
|
2005-12-11 15:16:03 +03:00
|
|
|
struct ucred *cred, struct lwp *l)
|
1996-02-10 01:28:45 +03:00
|
|
|
{
|
Add code to UBCify LFS. This is still behind "#ifdef LFS_UBC" for now
(there are still some details to work out) but expect that to go
away soon. To support these basic changes (creation of lfs_putpages,
lfs_gop_write, mods to lfs_balloc) several other changes were made, to
wit:
* Create a writer daemon kernel thread whose purpose is to handle page
writes for the pagedaemon, but which also takes over some of the
functions of lfs_check(). This thread is started the first time an
LFS is mounted.
* Add a "flags" parameter to GOP_SIZE. Current values are
GOP_SIZE_READ, meaning that the call should return the size of the
in-core version of the file, and GOP_SIZE_WRITE, meaning that it
should return the on-disk size. One of GOP_SIZE_READ or
GOP_SIZE_WRITE must be specified.
* Instead of using malloc(...M_WAITOK) for everything, reserve enough
resources to get by and use malloc(...M_NOWAIT), using the reserves if
necessary. Use the pool subsystem for structures small enough that
this is feasible. This also obsoletes LFS_THROTTLE.
And a few that are not strictly necessary:
* Moves the LFS inode extensions off onto a separately allocated
structure; getting closer to LFS as an LKM. "Welcome to 1.6O."
* Unified GOP_ALLOC between FFS and LFS.
* Update LFS copyright headers to correct values.
* Actually cast to unsigned in lfs_shellsort, like the comment says.
* Keep track of which segments were empty before the previous
checkpoint; any segments that pass two checkpoints both dirty and
empty can be summarily cleaned. Do this. Right now lfs_segclean
still works, but this should be turned into an effectless
compatibility syscall.
2003-02-18 02:48:08 +03:00
|
|
|
struct genfs_node *gp = VTOG(ovp);
|
2003-01-25 00:55:02 +03:00
|
|
|
daddr_t lastblock;
|
Fixing age old cruft:
* Rather than using mnt_maxsymlinklen to indicate that a file systems returns
d_type fields(!), add a new internal flag, IMNT_DTYPE.
Add 3 new elements to ufsmount:
* um_maxsymlinklen, replaces mnt_maxsymlinklen (which never should have existed
in the first place).
* um_dirblksiz, which tracks the current directory block size, eliminating the
FS-specific checks littered throughout the code. This may be used later to
make the block size variable.
* um_maxfilesize, which is the maximum file size, possibly adjusted lower due
to implementation issues.
Sync some bug fixes from FFS into ext2fs, particularly:
* ffs_lookup.c 1.21, 1.28, 1.33, 1.48
* ffs_inode.c 1.43, 1.44, 1.45, 1.66, 1.67
* ffs_vnops.c 1.84, 1.85, 1.86
Clean up some crappy pointer frobnication.
2004-08-15 11:19:54 +04:00
|
|
|
struct inode *oip = VTOI(ovp);
|
2003-01-25 00:55:02 +03:00
|
|
|
daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR];
|
2003-01-25 19:40:28 +03:00
|
|
|
/* XXX ondisk32 */
|
|
|
|
int32_t newblks[NDADDR + NIADDR];
|
1994-06-08 15:41:58 +04:00
|
|
|
struct lfs *fs;
|
2000-06-28 00:57:11 +04:00
|
|
|
struct buf *bp;
|
|
|
|
int offset, size, level;
|
2004-08-15 23:01:16 +04:00
|
|
|
long count, rcount, blocksreleased = 0, real_released = 0;
|
2005-11-02 15:38:58 +03:00
|
|
|
int i, nblocks;
|
2000-06-28 00:57:11 +04:00
|
|
|
int aflags, error, allerror = 0;
|
|
|
|
off_t osize;
|
|
|
|
long lastseg;
|
|
|
|
size_t bc;
|
2000-11-21 03:00:31 +03:00
|
|
|
int obufsize, odb;
|
2003-03-20 09:47:38 +03:00
|
|
|
int usepc;
|
Fixing age old cruft:
* Rather than using mnt_maxsymlinklen to indicate that a file systems returns
d_type fields(!), add a new internal flag, IMNT_DTYPE.
Add 3 new elements to ufsmount:
* um_maxsymlinklen, replaces mnt_maxsymlinklen (which never should have existed
in the first place).
* um_dirblksiz, which tracks the current directory block size, eliminating the
FS-specific checks littered throughout the code. This may be used later to
make the block size variable.
* um_maxfilesize, which is the maximum file size, possibly adjusted lower due
to implementation issues.
Sync some bug fixes from FFS into ext2fs, particularly:
* ffs_lookup.c 1.21, 1.28, 1.33, 1.48
* ffs_inode.c 1.43, 1.44, 1.45, 1.66, 1.67
* ffs_vnops.c 1.84, 1.85, 1.86
Clean up some crappy pointer frobnication.
2004-08-15 11:19:54 +04:00
|
|
|
struct ufsmount *ump = oip->i_ump;
|
2000-06-28 00:57:11 +04:00
|
|
|
|
2005-11-11 18:50:57 +03:00
|
|
|
if (ovp->v_type == VCHR || ovp->v_type == VBLK ||
|
|
|
|
ovp->v_type == VFIFO || ovp->v_type == VSOCK) {
|
|
|
|
KASSERT(oip->i_size == 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-04-24 01:10:26 +04:00
|
|
|
if (length < 0)
|
|
|
|
return (EINVAL);
|
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
/*
|
|
|
|
* Just return and not update modification times.
|
|
|
|
*/
|
2003-04-02 14:39:19 +04:00
|
|
|
if (oip->i_size == length)
|
2000-06-28 00:57:11 +04:00
|
|
|
return (0);
|
1999-03-10 03:20:00 +03:00
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
if (ovp->v_type == VLNK &&
|
Fixing age old cruft:
* Rather than using mnt_maxsymlinklen to indicate that a file systems returns
d_type fields(!), add a new internal flag, IMNT_DTYPE.
Add 3 new elements to ufsmount:
* um_maxsymlinklen, replaces mnt_maxsymlinklen (which never should have existed
in the first place).
* um_dirblksiz, which tracks the current directory block size, eliminating the
FS-specific checks littered throughout the code. This may be used later to
make the block size variable.
* um_maxfilesize, which is the maximum file size, possibly adjusted lower due
to implementation issues.
Sync some bug fixes from FFS into ext2fs, particularly:
* ffs_lookup.c 1.21, 1.28, 1.33, 1.48
* ffs_inode.c 1.43, 1.44, 1.45, 1.66, 1.67
* ffs_vnops.c 1.84, 1.85, 1.86
Clean up some crappy pointer frobnication.
2004-08-15 11:19:54 +04:00
|
|
|
(oip->i_size < ump->um_maxsymlinklen ||
|
|
|
|
(ump->um_maxsymlinklen == 0 &&
|
2003-04-02 14:39:19 +04:00
|
|
|
oip->i_ffs1_blocks == 0))) {
|
1994-06-08 15:41:58 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (length != 0)
|
|
|
|
panic("lfs_truncate: partial truncate of symlink");
|
|
|
|
#endif
|
2003-04-02 14:39:19 +04:00
|
|
|
memset((char *)SHORTLINK(oip), 0, (u_int)oip->i_size);
|
|
|
|
oip->i_size = oip->i_ffs1_size = 0;
|
2000-06-28 00:57:11 +04:00
|
|
|
oip->i_flag |= IN_CHANGE | IN_UPDATE;
|
2005-11-02 15:38:58 +03:00
|
|
|
return (lfs_update(ovp, NULL, NULL, 0));
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
2003-04-02 14:39:19 +04:00
|
|
|
if (oip->i_size == length) {
|
2000-06-28 00:57:11 +04:00
|
|
|
oip->i_flag |= IN_CHANGE | IN_UPDATE;
|
2005-11-02 15:38:58 +03:00
|
|
|
return (lfs_update(ovp, NULL, NULL, 0));
|
2000-06-28 00:57:11 +04:00
|
|
|
}
|
|
|
|
#ifdef QUOTA
|
|
|
|
if ((error = getinoquota(oip)) != 0)
|
|
|
|
return (error);
|
|
|
|
#endif
|
|
|
|
fs = oip->i_lfs;
|
1999-03-10 03:20:00 +03:00
|
|
|
lfs_imtime(fs);
|
2003-04-02 14:39:19 +04:00
|
|
|
osize = oip->i_size;
|
2003-02-28 10:37:56 +03:00
|
|
|
usepc = (ovp->v_type == VREG && ovp != fs->lfs_ivnode);
|
2000-06-28 00:57:11 +04:00
|
|
|
|
2005-04-02 01:59:46 +04:00
|
|
|
ASSERT_NO_SEGLOCK(fs);
|
2000-06-28 00:57:11 +04:00
|
|
|
/*
|
|
|
|
* Lengthen the size of the file. We must ensure that the
|
|
|
|
* last byte of the file is allocated. Since the smallest
|
|
|
|
* value of osize is 0, length will be at least 1.
|
|
|
|
*/
|
|
|
|
if (osize < length) {
|
Fixing age old cruft:
* Rather than using mnt_maxsymlinklen to indicate that a file systems returns
d_type fields(!), add a new internal flag, IMNT_DTYPE.
Add 3 new elements to ufsmount:
* um_maxsymlinklen, replaces mnt_maxsymlinklen (which never should have existed
in the first place).
* um_dirblksiz, which tracks the current directory block size, eliminating the
FS-specific checks littered throughout the code. This may be used later to
make the block size variable.
* um_maxfilesize, which is the maximum file size, possibly adjusted lower due
to implementation issues.
Sync some bug fixes from FFS into ext2fs, particularly:
* ffs_lookup.c 1.21, 1.28, 1.33, 1.48
* ffs_inode.c 1.43, 1.44, 1.45, 1.66, 1.67
* ffs_vnops.c 1.84, 1.85, 1.86
Clean up some crappy pointer frobnication.
2004-08-15 11:19:54 +04:00
|
|
|
if (length > ump->um_maxfilesize)
|
2000-04-24 01:10:26 +04:00
|
|
|
return (EFBIG);
|
2000-06-28 00:57:11 +04:00
|
|
|
aflags = B_CLRBUF;
|
2004-08-15 23:01:16 +04:00
|
|
|
if (ioflag & IO_SYNC)
|
2000-06-28 00:57:11 +04:00
|
|
|
aflags |= B_SYNC;
|
2003-02-28 10:37:56 +03:00
|
|
|
if (usepc) {
|
|
|
|
if (lblkno(fs, osize) < NDADDR &&
|
|
|
|
lblkno(fs, osize) != lblkno(fs, length) &&
|
|
|
|
blkroundup(fs, osize) != osize) {
|
2004-08-15 20:17:37 +04:00
|
|
|
off_t eob;
|
|
|
|
|
|
|
|
eob = blkroundup(fs, osize);
|
2003-02-28 10:37:56 +03:00
|
|
|
error = ufs_balloc_range(ovp, osize,
|
2005-11-02 15:38:58 +03:00
|
|
|
eob - osize, cred, aflags);
|
2004-08-15 20:17:37 +04:00
|
|
|
if (error)
|
2003-02-28 10:37:56 +03:00
|
|
|
return error;
|
2004-08-15 23:01:16 +04:00
|
|
|
if (ioflag & IO_SYNC) {
|
2004-08-15 20:17:37 +04:00
|
|
|
ovp->v_size = eob;
|
2003-02-28 10:37:56 +03:00
|
|
|
simple_lock(&ovp->v_interlock);
|
|
|
|
VOP_PUTPAGES(ovp,
|
|
|
|
trunc_page(osize & fs->lfs_bmask),
|
2004-08-15 20:17:37 +04:00
|
|
|
round_page(eob),
|
2003-02-28 10:37:56 +03:00
|
|
|
PGO_CLEANIT | PGO_SYNCIO);
|
|
|
|
}
|
|
|
|
}
|
2005-11-02 15:38:58 +03:00
|
|
|
error = ufs_balloc_range(ovp, length - 1, 1, cred,
|
2003-02-28 10:37:56 +03:00
|
|
|
aflags);
|
|
|
|
if (error) {
|
2005-11-02 15:38:58 +03:00
|
|
|
(void) lfs_truncate(ovp, osize,
|
2005-12-11 15:16:03 +03:00
|
|
|
ioflag & IO_SYNC, cred, l);
|
2003-02-28 10:37:56 +03:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
uvm_vnp_setsize(ovp, length);
|
|
|
|
oip->i_flag |= IN_CHANGE | IN_UPDATE;
|
2003-04-02 14:39:19 +04:00
|
|
|
KASSERT(ovp->v_size == oip->i_size);
|
2005-04-14 04:02:46 +04:00
|
|
|
oip->i_lfs_hiblk = lblkno(fs, oip->i_size + fs->lfs_bsize - 1) - 1;
|
2005-11-02 15:38:58 +03:00
|
|
|
return (lfs_update(ovp, NULL, NULL, 0));
|
2003-02-28 10:37:56 +03:00
|
|
|
} else {
|
|
|
|
error = lfs_reserve(fs, ovp, NULL,
|
|
|
|
btofsb(fs, (NIADDR + 2) << fs->lfs_bshift));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
2005-11-02 15:38:58 +03:00
|
|
|
error = lfs_balloc(ovp, length - 1, 1, cred,
|
2003-02-28 10:37:56 +03:00
|
|
|
aflags, &bp);
|
|
|
|
lfs_reserve(fs, ovp, NULL,
|
|
|
|
-btofsb(fs, (NIADDR + 2) << fs->lfs_bshift));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
2003-04-02 14:39:19 +04:00
|
|
|
oip->i_ffs1_size = oip->i_size = length;
|
2003-02-28 10:37:56 +03:00
|
|
|
uvm_vnp_setsize(ovp, length);
|
|
|
|
(void) VOP_BWRITE(bp);
|
|
|
|
oip->i_flag |= IN_CHANGE | IN_UPDATE;
|
2005-04-14 04:02:46 +04:00
|
|
|
oip->i_lfs_hiblk = lblkno(fs, oip->i_size + fs->lfs_bsize - 1) - 1;
|
2005-11-02 15:38:58 +03:00
|
|
|
return (lfs_update(ovp, NULL, NULL, 0));
|
2003-02-28 10:37:56 +03:00
|
|
|
}
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
|
|
|
|
2002-12-28 17:39:08 +03:00
|
|
|
if ((error = lfs_reserve(fs, ovp, NULL,
|
|
|
|
btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift))) != 0)
|
Various bug-fixes to LFS, to wit:
Kernel:
* Add runtime quantity lfs_ravail, the number of disk-blocks reserved
for writing. Writes to the filesystem first reserve a maximum amount
of blocks before their write is allowed to proceed; after the blocks
are allocated the reserved total is reduced by a corresponding amount.
If the lfs_reserve function cannot immediately reserve the requested
number of blocks, the inode is unlocked, and the thread sleeps until
the cleaner has made enough space available for the blocks to be
reserved. In this way large files can be written to the filesystem
(or, smaller files can be written to a nearly-full but thoroughly
clean filesystem) and the cleaner can still function properly.
* Remove explicit switching on dlfs_minfreeseg from the kernel code; it
is now merely a fs-creation parameter used to compute dlfs_avail and
dlfs_bfree (and used by fsck_lfs(8) to check their accuracy). Its
former role is better assumed by a properly computed dlfs_avail.
* Bounds-check inode numbers submitted through lfs_bmapv and lfs_markv.
This prevents a panic, but, if the cleaner is feeding the filesystem
the wrong data, you are still in a world of hurt.
* Cleanup: remove explicit references of DEV_BSIZE in favor of
btodb()/dbtob().
lfs_cleanerd:
* Make -n mean "send N segments' blocks through a single call to
lfs_markv". Previously it had meant "clean N segments though N calls
to lfs_markv, before looking again to see if more need to be cleaned".
The new behavior gives better packing of direct data on disk with as
little metadata as possible, largely alleviating the problem that the
cleaner can consume more disk through inefficient use of metadata than
it frees by moving dirty data away from clean "holes" to produce
entirely clean segments.
* Make -b mean "read as many segments as necessary to write N segments
of dirty data back to disk", rather than its former meaning of "read
as many segments as necessary to free N segments worth of space". The
new meaning, combined with the new -n behavior described above,
further aids in cleaning storage efficiency as entire segments can be
written at once, using as few blocks as possible for segment summaries
and inode blocks.
* Make the cleaner take note of segments which could not be cleaned due
to error, and not attempt to clean them until they are entirely free
of dirty blocks. This prevents the case in which a cleanerd running
with -n 1 and without -b (formerly the default) would spin trying
repeatedly to clean a corrupt segment, while the remaining space
filled and deadlocked the filesystem.
* Update the lfs_cleanerd manual page to describe all the options,
including the changes mentioned here (in particular, the -b and -n
flags were previously undocumented).
fsck_lfs:
* Check, and optionally fix, lfs_avail (to an exact figure) and
lfs_bfree (within a margin of error) in pass 5.
newfs_lfs:
* Reduce the default dlfs_minfreeseg to 1/20 of the total segments.
* Add a warning if the sgs disklabel field is 16 (the default for FFS'
cpg, but not usually desirable for LFS' sgs: 5--8 is a better range).
* Change the calculation of lfs_avail and lfs_bfree, corresponding to
the kernel changes mentioned above.
mount_lfs:
* Add -N and -b options to pass corresponding -n and -b options to
lfs_cleanerd.
* Default to calling lfs_cleanerd with "-b -n 4".
[All of these changes were largely tested in the 1.5 branch, with the
idea that they (along with previous un-pulled-up work) could be applied
to the branch while it was still in ALPHA2; however my test system has
experienced corruption on another filesystem (/dev/console has gone
missing :^), and, while I believe this unrelated to the LFS changes, I
cannot with good conscience request that the changes be pulled up.]
2000-09-09 08:49:54 +04:00
|
|
|
return (error);
|
Add code to UBCify LFS. This is still behind "#ifdef LFS_UBC" for now
(there are still some details to work out) but expect that to go
away soon. To support these basic changes (creation of lfs_putpages,
lfs_gop_write, mods to lfs_balloc) several other changes were made, to
wit:
* Create a writer daemon kernel thread whose purpose is to handle page
writes for the pagedaemon, but which also takes over some of the
functions of lfs_check(). This thread is started the first time an
LFS is mounted.
* Add a "flags" parameter to GOP_SIZE. Current values are
GOP_SIZE_READ, meaning that the call should return the size of the
in-core version of the file, and GOP_SIZE_WRITE, meaning that it
should return the on-disk size. One of GOP_SIZE_READ or
GOP_SIZE_WRITE must be specified.
* Instead of using malloc(...M_WAITOK) for everything, reserve enough
resources to get by and use malloc(...M_NOWAIT), using the reserves if
necessary. Use the pool subsystem for structures small enough that
this is feasible. This also obsoletes LFS_THROTTLE.
And a few that are not strictly necessary:
* Moves the LFS inode extensions off onto a separately allocated
structure; getting closer to LFS as an LKM. "Welcome to 1.6O."
* Unified GOP_ALLOC between FFS and LFS.
* Update LFS copyright headers to correct values.
* Actually cast to unsigned in lfs_shellsort, like the comment says.
* Keep track of which segments were empty before the previous
checkpoint; any segments that pass two checkpoints both dirty and
empty can be summarily cleaned. Do this. Right now lfs_segclean
still works, but this should be turned into an effectless
compatibility syscall.
2003-02-18 02:48:08 +03:00
|
|
|
|
1994-06-08 15:41:58 +04:00
|
|
|
/*
|
2000-06-28 00:57:11 +04:00
|
|
|
* Shorten the size of the file. If the file is not being
|
|
|
|
* truncated to a block boundary, the contents of the
|
|
|
|
* partial block following the end of the file must be
|
|
|
|
* zero'ed in case it ever becomes accessible again because
|
|
|
|
* of subsequent file growth. Directories however are not
|
|
|
|
* zero'ed as they should grow back initialized to empty.
|
1994-06-08 15:41:58 +04:00
|
|
|
*/
|
2000-06-28 00:57:11 +04:00
|
|
|
offset = blkoff(fs, length);
|
|
|
|
lastseg = -1;
|
|
|
|
bc = 0;
|
2003-03-20 09:47:38 +03:00
|
|
|
|
2005-04-23 23:47:51 +04:00
|
|
|
if (ovp != fs->lfs_ivnode)
|
|
|
|
lfs_seglock(fs, SEGM_PROT);
|
2000-06-28 00:57:11 +04:00
|
|
|
if (offset == 0) {
|
2003-04-02 14:39:19 +04:00
|
|
|
oip->i_size = oip->i_ffs1_size = length;
|
2003-03-09 00:46:04 +03:00
|
|
|
} else if (!usepc) {
|
2000-06-28 00:57:11 +04:00
|
|
|
lbn = lblkno(fs, length);
|
|
|
|
aflags = B_CLRBUF;
|
2004-08-15 23:01:16 +04:00
|
|
|
if (ioflag & IO_SYNC)
|
2000-06-28 00:57:11 +04:00
|
|
|
aflags |= B_SYNC;
|
2005-11-02 15:38:58 +03:00
|
|
|
error = lfs_balloc(ovp, length - 1, 1, cred, aflags, &bp);
|
Various bug-fixes to LFS, to wit:
Kernel:
* Add runtime quantity lfs_ravail, the number of disk-blocks reserved
for writing. Writes to the filesystem first reserve a maximum amount
of blocks before their write is allowed to proceed; after the blocks
are allocated the reserved total is reduced by a corresponding amount.
If the lfs_reserve function cannot immediately reserve the requested
number of blocks, the inode is unlocked, and the thread sleeps until
the cleaner has made enough space available for the blocks to be
reserved. In this way large files can be written to the filesystem
(or, smaller files can be written to a nearly-full but thoroughly
clean filesystem) and the cleaner can still function properly.
* Remove explicit switching on dlfs_minfreeseg from the kernel code; it
is now merely a fs-creation parameter used to compute dlfs_avail and
dlfs_bfree (and used by fsck_lfs(8) to check their accuracy). Its
former role is better assumed by a properly computed dlfs_avail.
* Bounds-check inode numbers submitted through lfs_bmapv and lfs_markv.
This prevents a panic, but, if the cleaner is feeding the filesystem
the wrong data, you are still in a world of hurt.
* Cleanup: remove explicit references of DEV_BSIZE in favor of
btodb()/dbtob().
lfs_cleanerd:
* Make -n mean "send N segments' blocks through a single call to
lfs_markv". Previously it had meant "clean N segments though N calls
to lfs_markv, before looking again to see if more need to be cleaned".
The new behavior gives better packing of direct data on disk with as
little metadata as possible, largely alleviating the problem that the
cleaner can consume more disk through inefficient use of metadata than
it frees by moving dirty data away from clean "holes" to produce
entirely clean segments.
* Make -b mean "read as many segments as necessary to write N segments
of dirty data back to disk", rather than its former meaning of "read
as many segments as necessary to free N segments worth of space". The
new meaning, combined with the new -n behavior described above,
further aids in cleaning storage efficiency as entire segments can be
written at once, using as few blocks as possible for segment summaries
and inode blocks.
* Make the cleaner take note of segments which could not be cleaned due
to error, and not attempt to clean them until they are entirely free
of dirty blocks. This prevents the case in which a cleanerd running
with -n 1 and without -b (formerly the default) would spin trying
repeatedly to clean a corrupt segment, while the remaining space
filled and deadlocked the filesystem.
* Update the lfs_cleanerd manual page to describe all the options,
including the changes mentioned here (in particular, the -b and -n
flags were previously undocumented).
fsck_lfs:
* Check, and optionally fix, lfs_avail (to an exact figure) and
lfs_bfree (within a margin of error) in pass 5.
newfs_lfs:
* Reduce the default dlfs_minfreeseg to 1/20 of the total segments.
* Add a warning if the sgs disklabel field is 16 (the default for FFS'
cpg, but not usually desirable for LFS' sgs: 5--8 is a better range).
* Change the calculation of lfs_avail and lfs_bfree, corresponding to
the kernel changes mentioned above.
mount_lfs:
* Add -N and -b options to pass corresponding -n and -b options to
lfs_cleanerd.
* Default to calling lfs_cleanerd with "-b -n 4".
[All of these changes were largely tested in the 1.5 branch, with the
idea that they (along with previous un-pulled-up work) could be applied
to the branch while it was still in ALPHA2; however my test system has
experienced corruption on another filesystem (/dev/console has gone
missing :^), and, while I believe this unrelated to the LFS changes, I
cannot with good conscience request that the changes be pulled up.]
2000-09-09 08:49:54 +04:00
|
|
|
if (error) {
|
2002-12-28 17:39:08 +03:00
|
|
|
lfs_reserve(fs, ovp, NULL,
|
|
|
|
-btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift));
|
2003-03-20 09:47:38 +03:00
|
|
|
goto errout;
|
Various bug-fixes to LFS, to wit:
Kernel:
* Add runtime quantity lfs_ravail, the number of disk-blocks reserved
for writing. Writes to the filesystem first reserve a maximum amount
of blocks before their write is allowed to proceed; after the blocks
are allocated the reserved total is reduced by a corresponding amount.
If the lfs_reserve function cannot immediately reserve the requested
number of blocks, the inode is unlocked, and the thread sleeps until
the cleaner has made enough space available for the blocks to be
reserved. In this way large files can be written to the filesystem
(or, smaller files can be written to a nearly-full but thoroughly
clean filesystem) and the cleaner can still function properly.
* Remove explicit switching on dlfs_minfreeseg from the kernel code; it
is now merely a fs-creation parameter used to compute dlfs_avail and
dlfs_bfree (and used by fsck_lfs(8) to check their accuracy). Its
former role is better assumed by a properly computed dlfs_avail.
* Bounds-check inode numbers submitted through lfs_bmapv and lfs_markv.
This prevents a panic, but, if the cleaner is feeding the filesystem
the wrong data, you are still in a world of hurt.
* Cleanup: remove explicit references of DEV_BSIZE in favor of
btodb()/dbtob().
lfs_cleanerd:
* Make -n mean "send N segments' blocks through a single call to
lfs_markv". Previously it had meant "clean N segments though N calls
to lfs_markv, before looking again to see if more need to be cleaned".
The new behavior gives better packing of direct data on disk with as
little metadata as possible, largely alleviating the problem that the
cleaner can consume more disk through inefficient use of metadata than
it frees by moving dirty data away from clean "holes" to produce
entirely clean segments.
* Make -b mean "read as many segments as necessary to write N segments
of dirty data back to disk", rather than its former meaning of "read
as many segments as necessary to free N segments worth of space". The
new meaning, combined with the new -n behavior described above,
further aids in cleaning storage efficiency as entire segments can be
written at once, using as few blocks as possible for segment summaries
and inode blocks.
* Make the cleaner take note of segments which could not be cleaned due
to error, and not attempt to clean them until they are entirely free
of dirty blocks. This prevents the case in which a cleanerd running
with -n 1 and without -b (formerly the default) would spin trying
repeatedly to clean a corrupt segment, while the remaining space
filled and deadlocked the filesystem.
* Update the lfs_cleanerd manual page to describe all the options,
including the changes mentioned here (in particular, the -b and -n
flags were previously undocumented).
fsck_lfs:
* Check, and optionally fix, lfs_avail (to an exact figure) and
lfs_bfree (within a margin of error) in pass 5.
newfs_lfs:
* Reduce the default dlfs_minfreeseg to 1/20 of the total segments.
* Add a warning if the sgs disklabel field is 16 (the default for FFS'
cpg, but not usually desirable for LFS' sgs: 5--8 is a better range).
* Change the calculation of lfs_avail and lfs_bfree, corresponding to
the kernel changes mentioned above.
mount_lfs:
* Add -N and -b options to pass corresponding -n and -b options to
lfs_cleanerd.
* Default to calling lfs_cleanerd with "-b -n 4".
[All of these changes were largely tested in the 1.5 branch, with the
idea that they (along with previous un-pulled-up work) could be applied
to the branch while it was still in ALPHA2; however my test system has
experienced corruption on another filesystem (/dev/console has gone
missing :^), and, while I believe this unrelated to the LFS changes, I
cannot with good conscience request that the changes be pulled up.]
2000-09-09 08:49:54 +04:00
|
|
|
}
|
2000-11-21 03:00:31 +03:00
|
|
|
obufsize = bp->b_bufsize;
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
odb = btofsb(fs, bp->b_bcount);
|
2003-04-02 14:39:19 +04:00
|
|
|
oip->i_size = oip->i_ffs1_size = length;
|
2000-06-28 00:57:11 +04:00
|
|
|
size = blksize(fs, oip, lbn);
|
|
|
|
if (ovp->v_type != VDIR)
|
|
|
|
memset((char *)bp->b_data + offset, 0,
|
|
|
|
(u_int)(size - offset));
|
2003-12-30 15:33:13 +03:00
|
|
|
allocbuf(bp, size, 1);
|
2005-04-02 01:59:46 +04:00
|
|
|
if ((bp->b_flags & (B_LOCKED | B_CALL)) == B_LOCKED) {
|
|
|
|
simple_lock(&lfs_subsys_lock);
|
2002-05-15 00:03:53 +04:00
|
|
|
locked_queue_bytes -= obufsize - bp->b_bufsize;
|
2005-04-02 01:59:46 +04:00
|
|
|
simple_unlock(&lfs_subsys_lock);
|
|
|
|
}
|
2002-05-15 00:03:53 +04:00
|
|
|
if (bp->b_flags & B_DELWRI)
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
fs->lfs_avail += odb - btofsb(fs, size);
|
Various bug-fixes to LFS, to wit:
Kernel:
* Add runtime quantity lfs_ravail, the number of disk-blocks reserved
for writing. Writes to the filesystem first reserve a maximum amount
of blocks before their write is allowed to proceed; after the blocks
are allocated the reserved total is reduced by a corresponding amount.
If the lfs_reserve function cannot immediately reserve the requested
number of blocks, the inode is unlocked, and the thread sleeps until
the cleaner has made enough space available for the blocks to be
reserved. In this way large files can be written to the filesystem
(or, smaller files can be written to a nearly-full but thoroughly
clean filesystem) and the cleaner can still function properly.
* Remove explicit switching on dlfs_minfreeseg from the kernel code; it
is now merely a fs-creation parameter used to compute dlfs_avail and
dlfs_bfree (and used by fsck_lfs(8) to check their accuracy). Its
former role is better assumed by a properly computed dlfs_avail.
* Bounds-check inode numbers submitted through lfs_bmapv and lfs_markv.
This prevents a panic, but, if the cleaner is feeding the filesystem
the wrong data, you are still in a world of hurt.
* Cleanup: remove explicit references of DEV_BSIZE in favor of
btodb()/dbtob().
lfs_cleanerd:
* Make -n mean "send N segments' blocks through a single call to
lfs_markv". Previously it had meant "clean N segments though N calls
to lfs_markv, before looking again to see if more need to be cleaned".
The new behavior gives better packing of direct data on disk with as
little metadata as possible, largely alleviating the problem that the
cleaner can consume more disk through inefficient use of metadata than
it frees by moving dirty data away from clean "holes" to produce
entirely clean segments.
* Make -b mean "read as many segments as necessary to write N segments
of dirty data back to disk", rather than its former meaning of "read
as many segments as necessary to free N segments worth of space". The
new meaning, combined with the new -n behavior described above,
further aids in cleaning storage efficiency as entire segments can be
written at once, using as few blocks as possible for segment summaries
and inode blocks.
* Make the cleaner take note of segments which could not be cleaned due
to error, and not attempt to clean them until they are entirely free
of dirty blocks. This prevents the case in which a cleanerd running
with -n 1 and without -b (formerly the default) would spin trying
repeatedly to clean a corrupt segment, while the remaining space
filled and deadlocked the filesystem.
* Update the lfs_cleanerd manual page to describe all the options,
including the changes mentioned here (in particular, the -b and -n
flags were previously undocumented).
fsck_lfs:
* Check, and optionally fix, lfs_avail (to an exact figure) and
lfs_bfree (within a margin of error) in pass 5.
newfs_lfs:
* Reduce the default dlfs_minfreeseg to 1/20 of the total segments.
* Add a warning if the sgs disklabel field is 16 (the default for FFS'
cpg, but not usually desirable for LFS' sgs: 5--8 is a better range).
* Change the calculation of lfs_avail and lfs_bfree, corresponding to
the kernel changes mentioned above.
mount_lfs:
* Add -N and -b options to pass corresponding -n and -b options to
lfs_cleanerd.
* Default to calling lfs_cleanerd with "-b -n 4".
[All of these changes were largely tested in the 1.5 branch, with the
idea that they (along with previous un-pulled-up work) could be applied
to the branch while it was still in ALPHA2; however my test system has
experienced corruption on another filesystem (/dev/console has gone
missing :^), and, while I believe this unrelated to the LFS changes, I
cannot with good conscience request that the changes be pulled up.]
2000-09-09 08:49:54 +04:00
|
|
|
(void) VOP_BWRITE(bp);
|
2003-03-09 00:46:04 +03:00
|
|
|
} else { /* vp->v_type == VREG && length < osize && offset != 0 */
|
|
|
|
/*
|
|
|
|
* When truncating a regular file down to a non-block-aligned
|
|
|
|
* size, we must zero the part of last block which is past
|
|
|
|
* the new EOF. We must synchronously flush the zeroed pages
|
|
|
|
* to disk since the new pages will be invalidated as soon
|
|
|
|
* as we inform the VM system of the new, smaller size.
|
|
|
|
* We must do this before acquiring the GLOCK, since fetching
|
|
|
|
* the pages will acquire the GLOCK internally.
|
|
|
|
* So there is a window where another thread could see a whole
|
|
|
|
* zeroed page past EOF, but that's life.
|
|
|
|
*/
|
2005-05-30 01:25:24 +04:00
|
|
|
daddr_t xlbn;
|
2004-08-15 21:37:07 +04:00
|
|
|
voff_t eoz;
|
|
|
|
|
2004-08-15 23:01:16 +04:00
|
|
|
aflags = ioflag & IO_SYNC ? B_SYNC : 0;
|
2005-11-02 15:38:58 +03:00
|
|
|
error = ufs_balloc_range(ovp, length - 1, 1, cred, aflags);
|
2003-02-20 07:27:23 +03:00
|
|
|
if (error) {
|
2004-03-30 18:50:46 +04:00
|
|
|
lfs_reserve(fs, ovp, NULL,
|
|
|
|
-btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift));
|
2003-03-20 09:47:38 +03:00
|
|
|
goto errout;
|
2003-02-20 07:27:23 +03:00
|
|
|
}
|
2005-05-30 01:25:24 +04:00
|
|
|
xlbn = lblkno(fs, length);
|
|
|
|
size = blksize(fs, oip, xlbn);
|
|
|
|
eoz = MIN(lblktosize(fs, xlbn) + size, osize);
|
2003-02-20 07:27:23 +03:00
|
|
|
uvm_vnp_zerorange(ovp, length, eoz - length);
|
2004-08-15 21:37:07 +04:00
|
|
|
if (round_page(eoz) > round_page(length)) {
|
|
|
|
simple_lock(&ovp->v_interlock);
|
|
|
|
error = VOP_PUTPAGES(ovp, round_page(length),
|
|
|
|
round_page(eoz),
|
2004-08-15 23:01:16 +04:00
|
|
|
PGO_CLEANIT | PGO_DEACTIVATE |
|
|
|
|
((ioflag & IO_SYNC) ? PGO_SYNCIO : 0));
|
2004-08-15 21:37:07 +04:00
|
|
|
if (error) {
|
|
|
|
lfs_reserve(fs, ovp, NULL,
|
|
|
|
-btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift));
|
|
|
|
goto errout;
|
|
|
|
}
|
2003-02-20 07:27:23 +03:00
|
|
|
}
|
|
|
|
}
|
Add code to UBCify LFS. This is still behind "#ifdef LFS_UBC" for now
(there are still some details to work out) but expect that to go
away soon. To support these basic changes (creation of lfs_putpages,
lfs_gop_write, mods to lfs_balloc) several other changes were made, to
wit:
* Create a writer daemon kernel thread whose purpose is to handle page
writes for the pagedaemon, but which also takes over some of the
functions of lfs_check(). This thread is started the first time an
LFS is mounted.
* Add a "flags" parameter to GOP_SIZE. Current values are
GOP_SIZE_READ, meaning that the call should return the size of the
in-core version of the file, and GOP_SIZE_WRITE, meaning that it
should return the on-disk size. One of GOP_SIZE_READ or
GOP_SIZE_WRITE must be specified.
* Instead of using malloc(...M_WAITOK) for everything, reserve enough
resources to get by and use malloc(...M_NOWAIT), using the reserves if
necessary. Use the pool subsystem for structures small enough that
this is feasible. This also obsoletes LFS_THROTTLE.
And a few that are not strictly necessary:
* Moves the LFS inode extensions off onto a separately allocated
structure; getting closer to LFS as an LKM. "Welcome to 1.6O."
* Unified GOP_ALLOC between FFS and LFS.
* Update LFS copyright headers to correct values.
* Actually cast to unsigned in lfs_shellsort, like the comment says.
* Keep track of which segments were empty before the previous
checkpoint; any segments that pass two checkpoints both dirty and
empty can be summarily cleaned. Do this. Right now lfs_segclean
still works, but this should be turned into an effectless
compatibility syscall.
2003-02-18 02:48:08 +03:00
|
|
|
|
2003-02-20 07:27:23 +03:00
|
|
|
lockmgr(&gp->g_glock, LK_EXCLUSIVE, NULL);
|
Add code to UBCify LFS. This is still behind "#ifdef LFS_UBC" for now
(there are still some details to work out) but expect that to go
away soon. To support these basic changes (creation of lfs_putpages,
lfs_gop_write, mods to lfs_balloc) several other changes were made, to
wit:
* Create a writer daemon kernel thread whose purpose is to handle page
writes for the pagedaemon, but which also takes over some of the
functions of lfs_check(). This thread is started the first time an
LFS is mounted.
* Add a "flags" parameter to GOP_SIZE. Current values are
GOP_SIZE_READ, meaning that the call should return the size of the
in-core version of the file, and GOP_SIZE_WRITE, meaning that it
should return the on-disk size. One of GOP_SIZE_READ or
GOP_SIZE_WRITE must be specified.
* Instead of using malloc(...M_WAITOK) for everything, reserve enough
resources to get by and use malloc(...M_NOWAIT), using the reserves if
necessary. Use the pool subsystem for structures small enough that
this is feasible. This also obsoletes LFS_THROTTLE.
And a few that are not strictly necessary:
* Moves the LFS inode extensions off onto a separately allocated
structure; getting closer to LFS as an LKM. "Welcome to 1.6O."
* Unified GOP_ALLOC between FFS and LFS.
* Update LFS copyright headers to correct values.
* Actually cast to unsigned in lfs_shellsort, like the comment says.
* Keep track of which segments were empty before the previous
checkpoint; any segments that pass two checkpoints both dirty and
empty can be summarily cleaned. Do this. Right now lfs_segclean
still works, but this should be turned into an effectless
compatibility syscall.
2003-02-18 02:48:08 +03:00
|
|
|
|
2003-04-02 14:39:19 +04:00
|
|
|
oip->i_size = oip->i_ffs1_size = length;
|
2000-06-28 00:57:11 +04:00
|
|
|
uvm_vnp_setsize(ovp, length);
|
1994-06-08 15:41:58 +04:00
|
|
|
/*
|
2000-06-28 00:57:11 +04:00
|
|
|
* Calculate index into inode's block list of
|
|
|
|
* last direct and indirect blocks (if any)
|
|
|
|
* which we want to keep. Lastblock is -1 when
|
|
|
|
* the file is truncated to 0.
|
1994-06-08 15:41:58 +04:00
|
|
|
*/
|
2000-06-28 00:57:11 +04:00
|
|
|
lastblock = lblkno(fs, length + fs->lfs_bsize - 1) - 1;
|
|
|
|
lastiblock[SINGLE] = lastblock - NDADDR;
|
|
|
|
lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
|
|
|
|
lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
nblocks = btofsb(fs, fs->lfs_bsize);
|
2000-06-28 00:57:11 +04:00
|
|
|
/*
|
|
|
|
* Record changed file and block pointers before we start
|
|
|
|
* freeing blocks. lastiblock values are also normalized to -1
|
|
|
|
* for calls to lfs_indirtrunc below.
|
|
|
|
*/
|
2003-04-02 14:39:19 +04:00
|
|
|
memcpy((caddr_t)newblks, (caddr_t)&oip->i_ffs1_db[0], sizeof newblks);
|
2000-06-28 00:57:11 +04:00
|
|
|
for (level = TRIPLE; level >= SINGLE; level--)
|
|
|
|
if (lastiblock[level] < 0) {
|
|
|
|
newblks[NDADDR+level] = 0;
|
|
|
|
lastiblock[level] = -1;
|
2000-05-06 00:59:20 +04:00
|
|
|
}
|
2000-06-28 00:57:11 +04:00
|
|
|
for (i = NDADDR - 1; i > lastblock; i--)
|
|
|
|
newblks[i] = 0;
|
|
|
|
|
2003-04-02 14:39:19 +04:00
|
|
|
oip->i_size = oip->i_ffs1_size = osize;
|
2000-06-28 00:57:11 +04:00
|
|
|
error = lfs_vtruncbuf(ovp, lastblock + 1, 0, 0);
|
|
|
|
if (error && !allerror)
|
|
|
|
allerror = error;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Indirect blocks first.
|
|
|
|
*/
|
|
|
|
indir_lbn[SINGLE] = -NDADDR;
|
|
|
|
indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1;
|
|
|
|
indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
|
|
|
|
for (level = TRIPLE; level >= SINGLE; level--) {
|
2003-04-02 14:39:19 +04:00
|
|
|
bn = oip->i_ffs1_ib[level];
|
2000-06-28 00:57:11 +04:00
|
|
|
if (bn != 0) {
|
|
|
|
error = lfs_indirtrunc(oip, indir_lbn[level],
|
2000-07-03 05:45:46 +04:00
|
|
|
bn, lastiblock[level],
|
|
|
|
level, &count, &rcount,
|
2005-12-11 15:16:03 +03:00
|
|
|
&lastseg, &bc, l);
|
2000-06-28 00:57:11 +04:00
|
|
|
if (error)
|
|
|
|
allerror = error;
|
2000-07-03 05:45:46 +04:00
|
|
|
real_released += rcount;
|
2000-06-28 00:57:11 +04:00
|
|
|
blocksreleased += count;
|
|
|
|
if (lastiblock[level] < 0) {
|
2003-04-02 14:39:19 +04:00
|
|
|
if (oip->i_ffs1_ib[level] > 0)
|
2000-07-03 05:45:46 +04:00
|
|
|
real_released += nblocks;
|
|
|
|
blocksreleased += nblocks;
|
2003-04-02 14:39:19 +04:00
|
|
|
oip->i_ffs1_ib[level] = 0;
|
2000-06-28 00:57:11 +04:00
|
|
|
lfs_blkfree(fs, bn, fs->lfs_bsize, &lastseg, &bc);
|
2005-04-16 21:35:58 +04:00
|
|
|
lfs_deregister_block(ovp, bn);
|
2000-06-28 00:57:11 +04:00
|
|
|
}
|
1999-03-10 03:20:00 +03:00
|
|
|
}
|
2000-06-28 00:57:11 +04:00
|
|
|
if (lastiblock[level] >= 0)
|
|
|
|
goto done;
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
2000-06-28 00:57:11 +04:00
|
|
|
|
1994-06-08 15:41:58 +04:00
|
|
|
/*
|
2000-06-28 00:57:11 +04:00
|
|
|
* All whole direct blocks or frags.
|
1994-06-08 15:41:58 +04:00
|
|
|
*/
|
2000-06-28 00:57:11 +04:00
|
|
|
for (i = NDADDR - 1; i > lastblock; i--) {
|
2002-07-06 05:30:11 +04:00
|
|
|
long bsize, obsize;
|
1994-06-08 15:41:58 +04:00
|
|
|
|
2003-04-02 14:39:19 +04:00
|
|
|
bn = oip->i_ffs1_db[i];
|
2000-06-28 00:57:11 +04:00
|
|
|
if (bn == 0)
|
|
|
|
continue;
|
|
|
|
bsize = blksize(fs, oip, i);
|
2003-04-02 14:39:19 +04:00
|
|
|
if (oip->i_ffs1_db[i] > 0) {
|
2002-07-06 05:30:11 +04:00
|
|
|
/* Check for fragment size changes */
|
|
|
|
obsize = oip->i_lfs_fragsize[i];
|
|
|
|
real_released += btofsb(fs, obsize);
|
|
|
|
oip->i_lfs_fragsize[i] = 0;
|
|
|
|
} else
|
|
|
|
obsize = 0;
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
blocksreleased += btofsb(fs, bsize);
|
2003-04-02 14:39:19 +04:00
|
|
|
oip->i_ffs1_db[i] = 0;
|
2002-07-06 05:30:11 +04:00
|
|
|
lfs_blkfree(fs, bn, obsize, &lastseg, &bc);
|
2005-04-16 21:35:58 +04:00
|
|
|
lfs_deregister_block(ovp, bn);
|
2000-06-28 00:57:11 +04:00
|
|
|
}
|
|
|
|
if (lastblock < 0)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Finally, look for a change in size of the
|
|
|
|
* last direct block; release any frags.
|
|
|
|
*/
|
2003-04-02 14:39:19 +04:00
|
|
|
bn = oip->i_ffs1_db[lastblock];
|
2000-06-28 00:57:11 +04:00
|
|
|
if (bn != 0) {
|
2003-04-10 08:15:38 +04:00
|
|
|
long oldspace, newspace;
|
|
|
|
#if 0
|
|
|
|
long olddspace;
|
|
|
|
#endif
|
2000-06-28 00:57:11 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate amount of space we're giving
|
|
|
|
* back as old block size minus new block size.
|
|
|
|
*/
|
|
|
|
oldspace = blksize(fs, oip, lastblock);
|
2003-04-10 08:15:38 +04:00
|
|
|
#if 0
|
2002-07-06 05:30:11 +04:00
|
|
|
olddspace = oip->i_lfs_fragsize[lastblock];
|
2003-04-10 08:15:38 +04:00
|
|
|
#endif
|
2002-07-06 05:30:11 +04:00
|
|
|
|
2003-04-02 14:39:19 +04:00
|
|
|
oip->i_size = oip->i_ffs1_size = length;
|
2000-06-28 00:57:11 +04:00
|
|
|
newspace = blksize(fs, oip, lastblock);
|
|
|
|
if (newspace == 0)
|
|
|
|
panic("itrunc: newspace");
|
|
|
|
if (oldspace - newspace > 0) {
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
blocksreleased += btofsb(fs, oldspace - newspace);
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
2002-07-06 05:30:11 +04:00
|
|
|
#if 0
|
|
|
|
if (bn > 0 && olddspace - newspace > 0) {
|
|
|
|
/* No segment accounting here, just vnode */
|
|
|
|
real_released += btofsb(fs, olddspace - newspace);
|
|
|
|
}
|
|
|
|
#endif
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
2000-06-28 00:57:11 +04:00
|
|
|
|
|
|
|
done:
|
|
|
|
/* Finish segment accounting corrections */
|
|
|
|
lfs_update_seguse(fs, lastseg, bc);
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
for (level = SINGLE; level <= TRIPLE; level++)
|
2003-02-28 07:37:07 +03:00
|
|
|
if ((newblks[NDADDR + level] == 0) !=
|
2003-04-02 14:39:19 +04:00
|
|
|
(oip->i_ffs1_ib[level]) == 0) {
|
2000-06-28 00:57:11 +04:00
|
|
|
panic("lfs itrunc1");
|
2003-02-28 07:37:07 +03:00
|
|
|
}
|
2000-06-28 00:57:11 +04:00
|
|
|
for (i = 0; i < NDADDR; i++)
|
2003-04-02 14:39:19 +04:00
|
|
|
if ((newblks[i] == 0) != (oip->i_ffs1_db[i] == 0)) {
|
2000-06-28 00:57:11 +04:00
|
|
|
panic("lfs itrunc2");
|
2003-02-28 07:37:07 +03:00
|
|
|
}
|
2000-06-28 00:57:11 +04:00
|
|
|
if (length == 0 &&
|
|
|
|
(!LIST_EMPTY(&ovp->v_cleanblkhd) || !LIST_EMPTY(&ovp->v_dirtyblkhd)))
|
|
|
|
panic("lfs itrunc3");
|
|
|
|
#endif /* DIAGNOSTIC */
|
|
|
|
/*
|
|
|
|
* Put back the real size.
|
|
|
|
*/
|
2003-04-02 14:39:19 +04:00
|
|
|
oip->i_size = oip->i_ffs1_size = length;
|
2000-07-03 05:45:46 +04:00
|
|
|
oip->i_lfs_effnblks -= blocksreleased;
|
2003-04-02 14:39:19 +04:00
|
|
|
oip->i_ffs1_blocks -= real_released;
|
2005-04-02 01:59:46 +04:00
|
|
|
simple_lock(&fs->lfs_interlock);
|
2000-06-28 00:57:11 +04:00
|
|
|
fs->lfs_bfree += blocksreleased;
|
2005-04-02 01:59:46 +04:00
|
|
|
simple_unlock(&fs->lfs_interlock);
|
2000-06-28 00:57:11 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
2003-11-07 17:48:28 +03:00
|
|
|
if (oip->i_size == 0 &&
|
|
|
|
(oip->i_ffs1_blocks != 0 || oip->i_lfs_effnblks != 0)) {
|
|
|
|
printf("lfs_truncate: truncate to 0 but %d blks/%d effblks\n",
|
|
|
|
oip->i_ffs1_blocks, oip->i_lfs_effnblks);
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("lfs_truncate: persistent blocks");
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
2000-06-28 00:57:11 +04:00
|
|
|
#endif
|
|
|
|
oip->i_flag |= IN_CHANGE;
|
|
|
|
#ifdef QUOTA
|
|
|
|
(void) chkdq(oip, -blocksreleased, NOCRED, 0);
|
1994-06-08 15:41:58 +04:00
|
|
|
#endif
|
2002-12-28 17:39:08 +03:00
|
|
|
lfs_reserve(fs, ovp, NULL,
|
|
|
|
-btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift));
|
Add code to UBCify LFS. This is still behind "#ifdef LFS_UBC" for now
(there are still some details to work out) but expect that to go
away soon. To support these basic changes (creation of lfs_putpages,
lfs_gop_write, mods to lfs_balloc) several other changes were made, to
wit:
* Create a writer daemon kernel thread whose purpose is to handle page
writes for the pagedaemon, but which also takes over some of the
functions of lfs_check(). This thread is started the first time an
LFS is mounted.
* Add a "flags" parameter to GOP_SIZE. Current values are
GOP_SIZE_READ, meaning that the call should return the size of the
in-core version of the file, and GOP_SIZE_WRITE, meaning that it
should return the on-disk size. One of GOP_SIZE_READ or
GOP_SIZE_WRITE must be specified.
* Instead of using malloc(...M_WAITOK) for everything, reserve enough
resources to get by and use malloc(...M_NOWAIT), using the reserves if
necessary. Use the pool subsystem for structures small enough that
this is feasible. This also obsoletes LFS_THROTTLE.
And a few that are not strictly necessary:
* Moves the LFS inode extensions off onto a separately allocated
structure; getting closer to LFS as an LKM. "Welcome to 1.6O."
* Unified GOP_ALLOC between FFS and LFS.
* Update LFS copyright headers to correct values.
* Actually cast to unsigned in lfs_shellsort, like the comment says.
* Keep track of which segments were empty before the previous
checkpoint; any segments that pass two checkpoints both dirty and
empty can be summarily cleaned. Do this. Right now lfs_segclean
still works, but this should be turned into an effectless
compatibility syscall.
2003-02-18 02:48:08 +03:00
|
|
|
lockmgr(&gp->g_glock, LK_RELEASE, NULL);
|
2003-03-20 09:47:38 +03:00
|
|
|
errout:
|
2005-04-14 04:02:46 +04:00
|
|
|
oip->i_lfs_hiblk = lblkno(fs, oip->i_size + fs->lfs_bsize - 1) - 1;
|
2005-04-23 23:47:51 +04:00
|
|
|
if (ovp != fs->lfs_ivnode)
|
|
|
|
lfs_segunlock(fs);
|
2003-03-20 09:47:38 +03:00
|
|
|
return (allerror ? allerror : error);
|
2000-06-28 00:57:11 +04:00
|
|
|
}
|
1999-11-24 02:52:40 +03:00
|
|
|
|
2005-04-16 21:35:58 +04:00
|
|
|
/* Update segment and avail usage information when removing a block. */
|
2000-06-28 00:57:11 +04:00
|
|
|
static int
|
|
|
|
lfs_blkfree(struct lfs *fs, daddr_t daddr, size_t bsize, long *lastseg,
|
|
|
|
size_t *num)
|
|
|
|
{
|
|
|
|
long seg;
|
|
|
|
int error = 0;
|
1999-04-12 04:30:08 +04:00
|
|
|
|
2005-04-02 01:59:46 +04:00
|
|
|
ASSERT_SEGLOCK(fs);
|
2000-06-28 00:57:11 +04:00
|
|
|
bsize = fragroundup(fs, bsize);
|
|
|
|
if (daddr > 0) {
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
if (*lastseg != (seg = dtosn(fs, daddr))) {
|
2000-06-28 00:57:11 +04:00
|
|
|
error = lfs_update_seguse(fs, *lastseg, *num);
|
|
|
|
*num = bsize;
|
|
|
|
*lastseg = seg;
|
|
|
|
} else
|
|
|
|
*num += bsize;
|
1999-03-10 03:20:00 +03:00
|
|
|
}
|
2005-04-16 21:35:58 +04:00
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
return error;
|
|
|
|
}
|
2000-05-06 00:59:20 +04:00
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
/* Finish the accounting updates for a segment. */
|
|
|
|
static int
|
|
|
|
lfs_update_seguse(struct lfs *fs, long lastseg, size_t num)
|
|
|
|
{
|
|
|
|
SEGUSE *sup;
|
|
|
|
struct buf *bp;
|
|
|
|
|
2005-04-02 01:59:46 +04:00
|
|
|
ASSERT_SEGLOCK(fs);
|
2000-06-28 00:57:11 +04:00
|
|
|
if (lastseg < 0 || num == 0)
|
|
|
|
return 0;
|
2005-02-27 01:31:44 +03:00
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
LFS_SEGENTRY(sup, fs, lastseg, bp);
|
|
|
|
if (num > sup->su_nbytes) {
|
|
|
|
printf("lfs_truncate: segment %ld short by %ld\n",
|
|
|
|
lastseg, (long)num - sup->su_nbytes);
|
|
|
|
panic("lfs_truncate: negative bytes");
|
|
|
|
sup->su_nbytes = num;
|
1998-03-01 05:20:01 +03:00
|
|
|
}
|
2000-06-28 00:57:11 +04:00
|
|
|
sup->su_nbytes -= num;
|
Add code to UBCify LFS. This is still behind "#ifdef LFS_UBC" for now
(there are still some details to work out) but expect that to go
away soon. To support these basic changes (creation of lfs_putpages,
lfs_gop_write, mods to lfs_balloc) several other changes were made, to
wit:
* Create a writer daemon kernel thread whose purpose is to handle page
writes for the pagedaemon, but which also takes over some of the
functions of lfs_check(). This thread is started the first time an
LFS is mounted.
* Add a "flags" parameter to GOP_SIZE. Current values are
GOP_SIZE_READ, meaning that the call should return the size of the
in-core version of the file, and GOP_SIZE_WRITE, meaning that it
should return the on-disk size. One of GOP_SIZE_READ or
GOP_SIZE_WRITE must be specified.
* Instead of using malloc(...M_WAITOK) for everything, reserve enough
resources to get by and use malloc(...M_NOWAIT), using the reserves if
necessary. Use the pool subsystem for structures small enough that
this is feasible. This also obsoletes LFS_THROTTLE.
And a few that are not strictly necessary:
* Moves the LFS inode extensions off onto a separately allocated
structure; getting closer to LFS as an LKM. "Welcome to 1.6O."
* Unified GOP_ALLOC between FFS and LFS.
* Update LFS copyright headers to correct values.
* Actually cast to unsigned in lfs_shellsort, like the comment says.
* Keep track of which segments were empty before the previous
checkpoint; any segments that pass two checkpoints both dirty and
empty can be summarily cleaned. Do this. Right now lfs_segclean
still works, but this should be turned into an effectless
compatibility syscall.
2003-02-18 02:48:08 +03:00
|
|
|
LFS_WRITESEGENTRY(sup, fs, lastseg, bp);
|
|
|
|
|
|
|
|
return 0;
|
2000-06-28 00:57:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Release blocks associated with the inode ip and stored in the indirect
|
|
|
|
* block bn. Blocks are free'd in LIFO order up to (but not including)
|
|
|
|
* lastbn. If level is greater than SINGLE, the block is an indirect block
|
|
|
|
* and recursive calls to indirtrunc must be used to cleanse other indirect
|
|
|
|
* blocks.
|
|
|
|
*
|
|
|
|
* NB: triple indirect blocks are untested.
|
|
|
|
*/
|
|
|
|
static int
|
2003-01-25 00:55:02 +03:00
|
|
|
lfs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn,
|
|
|
|
daddr_t lastbn, int level, long *countp,
|
2005-12-11 15:16:03 +03:00
|
|
|
long *rcountp, long *lastsegp, size_t *bcp, struct lwp *l)
|
2000-06-28 00:57:11 +04:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct buf *bp;
|
|
|
|
struct lfs *fs = ip->i_lfs;
|
2003-01-25 00:55:02 +03:00
|
|
|
int32_t *bap; /* XXX ondisk32 */
|
2000-06-28 00:57:11 +04:00
|
|
|
struct vnode *vp;
|
2003-01-25 00:55:02 +03:00
|
|
|
daddr_t nb, nlbn, last;
|
|
|
|
int32_t *copy = NULL; /* XXX ondisk32 */
|
2000-07-03 05:45:46 +04:00
|
|
|
long blkcount, rblkcount, factor;
|
|
|
|
int nblocks, blocksreleased = 0, real_released = 0;
|
2000-06-28 00:57:11 +04:00
|
|
|
int error = 0, allerror = 0;
|
|
|
|
|
2005-04-02 01:59:46 +04:00
|
|
|
ASSERT_SEGLOCK(fs);
|
2000-06-28 00:57:11 +04:00
|
|
|
/*
|
|
|
|
* Calculate index in current block of last
|
|
|
|
* block to be kept. -1 indicates the entire
|
|
|
|
* block so we need not calculate the index.
|
|
|
|
*/
|
|
|
|
factor = 1;
|
|
|
|
for (i = SINGLE; i < level; i++)
|
|
|
|
factor *= NINDIR(fs);
|
|
|
|
last = lastbn;
|
|
|
|
if (lastbn > 0)
|
|
|
|
last /= factor;
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
nblocks = btofsb(fs, fs->lfs_bsize);
|
2000-06-28 00:57:11 +04:00
|
|
|
/*
|
|
|
|
* Get buffer of block pointers, zero those entries corresponding
|
|
|
|
* to blocks to be free'd, and update on disk copy first. Since
|
|
|
|
* double(triple) indirect before single(double) indirect, calls
|
|
|
|
* to bmap on these blocks will fail. However, we already have
|
|
|
|
* the on disk address, so we have to set the b_blkno field
|
|
|
|
* explicitly instead of letting bread do everything for us.
|
|
|
|
*/
|
|
|
|
vp = ITOV(ip);
|
|
|
|
bp = getblk(vp, lbn, (int)fs->lfs_bsize, 0, 0);
|
|
|
|
if (bp->b_flags & (B_DONE | B_DELWRI)) {
|
|
|
|
/* Braces must be here in case trace evaluates to nothing. */
|
|
|
|
trace(TR_BREADHIT, pack(vp, fs->lfs_bsize), lbn);
|
|
|
|
} else {
|
|
|
|
trace(TR_BREADMISS, pack(vp, fs->lfs_bsize), lbn);
|
2005-12-11 15:16:03 +03:00
|
|
|
l->l_proc->p_stats->p_ru.ru_inblock++; /* pay for read */
|
2000-06-28 00:57:11 +04:00
|
|
|
bp->b_flags |= B_READ;
|
|
|
|
if (bp->b_bcount > bp->b_bufsize)
|
|
|
|
panic("lfs_indirtrunc: bad buffer size");
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
bp->b_blkno = fsbtodb(fs, dbn);
|
2004-01-25 21:06:48 +03:00
|
|
|
VOP_STRATEGY(vp, bp);
|
2000-06-28 00:57:11 +04:00
|
|
|
error = biowait(bp);
|
|
|
|
}
|
|
|
|
if (error) {
|
|
|
|
brelse(bp);
|
2000-07-03 05:45:46 +04:00
|
|
|
*countp = *rcountp = 0;
|
2000-06-28 00:57:11 +04:00
|
|
|
return (error);
|
2000-05-06 00:59:20 +04:00
|
|
|
}
|
|
|
|
|
2003-01-25 00:55:02 +03:00
|
|
|
bap = (int32_t *)bp->b_data; /* XXX ondisk32 */
|
2000-06-28 00:57:11 +04:00
|
|
|
if (lastbn >= 0) {
|
2005-04-16 21:28:37 +04:00
|
|
|
copy = (int32_t *)lfs_malloc(fs, fs->lfs_bsize, LFS_NB_IBLOCK);
|
2000-06-28 00:57:11 +04:00
|
|
|
memcpy((caddr_t)copy, (caddr_t)bap, (u_int)fs->lfs_bsize);
|
|
|
|
memset((caddr_t)&bap[last + 1], 0,
|
2003-01-25 00:55:02 +03:00
|
|
|
/* XXX ondisk32 */
|
|
|
|
(u_int)(NINDIR(fs) - (last + 1)) * sizeof (int32_t));
|
2000-06-28 00:57:11 +04:00
|
|
|
error = VOP_BWRITE(bp);
|
2000-05-06 00:59:20 +04:00
|
|
|
if (error)
|
2000-06-28 00:57:11 +04:00
|
|
|
allerror = error;
|
|
|
|
bap = copy;
|
2000-05-06 00:59:20 +04:00
|
|
|
}
|
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
/*
|
|
|
|
* Recursively free totally unused blocks.
|
|
|
|
*/
|
|
|
|
for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last;
|
|
|
|
i--, nlbn += factor) {
|
|
|
|
nb = bap[i];
|
|
|
|
if (nb == 0)
|
|
|
|
continue;
|
|
|
|
if (level > SINGLE) {
|
|
|
|
error = lfs_indirtrunc(ip, nlbn, nb,
|
2003-01-25 00:55:02 +03:00
|
|
|
(daddr_t)-1, level - 1,
|
2000-07-03 05:45:46 +04:00
|
|
|
&blkcount, &rblkcount,
|
2005-12-11 15:16:03 +03:00
|
|
|
lastsegp, bcp, l);
|
2000-06-28 00:57:11 +04:00
|
|
|
if (error)
|
|
|
|
allerror = error;
|
|
|
|
blocksreleased += blkcount;
|
2000-07-03 05:45:46 +04:00
|
|
|
real_released += rblkcount;
|
2000-06-28 00:57:11 +04:00
|
|
|
}
|
|
|
|
lfs_blkfree(fs, nb, fs->lfs_bsize, lastsegp, bcp);
|
2000-07-03 05:45:46 +04:00
|
|
|
if (bap[i] > 0)
|
|
|
|
real_released += nblocks;
|
2000-06-28 00:57:11 +04:00
|
|
|
blocksreleased += nblocks;
|
|
|
|
}
|
2000-05-06 00:59:20 +04:00
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
/*
|
|
|
|
* Recursively free last partial block.
|
|
|
|
*/
|
|
|
|
if (level > SINGLE && lastbn >= 0) {
|
|
|
|
last = lastbn % factor;
|
|
|
|
nb = bap[i];
|
|
|
|
if (nb != 0) {
|
|
|
|
error = lfs_indirtrunc(ip, nlbn, nb,
|
|
|
|
last, level - 1, &blkcount,
|
2005-12-11 15:16:03 +03:00
|
|
|
&rblkcount, lastsegp, bcp, l);
|
2000-06-28 00:57:11 +04:00
|
|
|
if (error)
|
|
|
|
allerror = error;
|
2000-07-03 05:45:46 +04:00
|
|
|
real_released += rblkcount;
|
2000-06-28 00:57:11 +04:00
|
|
|
blocksreleased += blkcount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (copy != NULL) {
|
2005-04-16 21:28:37 +04:00
|
|
|
lfs_free(fs, copy, LFS_NB_IBLOCK);
|
2000-06-28 00:57:11 +04:00
|
|
|
} else {
|
2000-11-21 03:00:31 +03:00
|
|
|
if (bp->b_flags & B_DELWRI) {
|
|
|
|
LFS_UNLOCK_BUF(bp);
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
fs->lfs_avail += btofsb(fs, bp->b_bcount);
|
2000-11-21 03:00:31 +03:00
|
|
|
wakeup(&fs->lfs_avail);
|
|
|
|
}
|
2000-06-28 00:57:11 +04:00
|
|
|
bp->b_flags |= B_INVAL;
|
|
|
|
brelse(bp);
|
|
|
|
}
|
1999-03-10 03:20:00 +03:00
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
*countp = blocksreleased;
|
2000-07-03 05:45:46 +04:00
|
|
|
*rcountp = real_released;
|
2000-06-28 00:57:11 +04:00
|
|
|
return (allerror);
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
1999-03-30 01:51:38 +04:00
|
|
|
|
|
|
|
/*
|
2000-06-28 00:57:11 +04:00
|
|
|
* Destroy any in core blocks past the truncation length.
|
|
|
|
* Inlined from vtruncbuf, so that lfs_avail could be updated.
|
2003-03-20 09:47:38 +03:00
|
|
|
* We take the seglock to prevent cleaning from occurring while we are
|
Add code to UBCify LFS. This is still behind "#ifdef LFS_UBC" for now
(there are still some details to work out) but expect that to go
away soon. To support these basic changes (creation of lfs_putpages,
lfs_gop_write, mods to lfs_balloc) several other changes were made, to
wit:
* Create a writer daemon kernel thread whose purpose is to handle page
writes for the pagedaemon, but which also takes over some of the
functions of lfs_check(). This thread is started the first time an
LFS is mounted.
* Add a "flags" parameter to GOP_SIZE. Current values are
GOP_SIZE_READ, meaning that the call should return the size of the
in-core version of the file, and GOP_SIZE_WRITE, meaning that it
should return the on-disk size. One of GOP_SIZE_READ or
GOP_SIZE_WRITE must be specified.
* Instead of using malloc(...M_WAITOK) for everything, reserve enough
resources to get by and use malloc(...M_NOWAIT), using the reserves if
necessary. Use the pool subsystem for structures small enough that
this is feasible. This also obsoletes LFS_THROTTLE.
And a few that are not strictly necessary:
* Moves the LFS inode extensions off onto a separately allocated
structure; getting closer to LFS as an LKM. "Welcome to 1.6O."
* Unified GOP_ALLOC between FFS and LFS.
* Update LFS copyright headers to correct values.
* Actually cast to unsigned in lfs_shellsort, like the comment says.
* Keep track of which segments were empty before the previous
checkpoint; any segments that pass two checkpoints both dirty and
empty can be summarily cleaned. Do this. Right now lfs_segclean
still works, but this should be turned into an effectless
compatibility syscall.
2003-02-18 02:48:08 +03:00
|
|
|
* invalidating blocks.
|
1999-03-30 01:51:38 +04:00
|
|
|
*/
|
2000-06-28 00:57:11 +04:00
|
|
|
static int
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
lfs_vtruncbuf(struct vnode *vp, daddr_t lbn, int slpflag, int slptimeo)
|
1999-03-30 01:51:38 +04:00
|
|
|
{
|
2000-06-28 00:57:11 +04:00
|
|
|
struct buf *bp, *nbp;
|
|
|
|
int s, error;
|
|
|
|
struct lfs *fs;
|
Add code to UBCify LFS. This is still behind "#ifdef LFS_UBC" for now
(there are still some details to work out) but expect that to go
away soon. To support these basic changes (creation of lfs_putpages,
lfs_gop_write, mods to lfs_balloc) several other changes were made, to
wit:
* Create a writer daemon kernel thread whose purpose is to handle page
writes for the pagedaemon, but which also takes over some of the
functions of lfs_check(). This thread is started the first time an
LFS is mounted.
* Add a "flags" parameter to GOP_SIZE. Current values are
GOP_SIZE_READ, meaning that the call should return the size of the
in-core version of the file, and GOP_SIZE_WRITE, meaning that it
should return the on-disk size. One of GOP_SIZE_READ or
GOP_SIZE_WRITE must be specified.
* Instead of using malloc(...M_WAITOK) for everything, reserve enough
resources to get by and use malloc(...M_NOWAIT), using the reserves if
necessary. Use the pool subsystem for structures small enough that
this is feasible. This also obsoletes LFS_THROTTLE.
And a few that are not strictly necessary:
* Moves the LFS inode extensions off onto a separately allocated
structure; getting closer to LFS as an LKM. "Welcome to 1.6O."
* Unified GOP_ALLOC between FFS and LFS.
* Update LFS copyright headers to correct values.
* Actually cast to unsigned in lfs_shellsort, like the comment says.
* Keep track of which segments were empty before the previous
checkpoint; any segments that pass two checkpoints both dirty and
empty can be summarily cleaned. Do this. Right now lfs_segclean
still works, but this should be turned into an effectless
compatibility syscall.
2003-02-18 02:48:08 +03:00
|
|
|
voff_t off;
|
|
|
|
|
|
|
|
off = round_page((voff_t)lbn << vp->v_mount->mnt_fs_bshift);
|
|
|
|
simple_lock(&vp->v_interlock);
|
|
|
|
error = VOP_PUTPAGES(vp, off, 0, PGO_FREE | PGO_SYNCIO);
|
2004-08-15 20:17:37 +04:00
|
|
|
if (error)
|
Add code to UBCify LFS. This is still behind "#ifdef LFS_UBC" for now
(there are still some details to work out) but expect that to go
away soon. To support these basic changes (creation of lfs_putpages,
lfs_gop_write, mods to lfs_balloc) several other changes were made, to
wit:
* Create a writer daemon kernel thread whose purpose is to handle page
writes for the pagedaemon, but which also takes over some of the
functions of lfs_check(). This thread is started the first time an
LFS is mounted.
* Add a "flags" parameter to GOP_SIZE. Current values are
GOP_SIZE_READ, meaning that the call should return the size of the
in-core version of the file, and GOP_SIZE_WRITE, meaning that it
should return the on-disk size. One of GOP_SIZE_READ or
GOP_SIZE_WRITE must be specified.
* Instead of using malloc(...M_WAITOK) for everything, reserve enough
resources to get by and use malloc(...M_NOWAIT), using the reserves if
necessary. Use the pool subsystem for structures small enough that
this is feasible. This also obsoletes LFS_THROTTLE.
And a few that are not strictly necessary:
* Moves the LFS inode extensions off onto a separately allocated
structure; getting closer to LFS as an LKM. "Welcome to 1.6O."
* Unified GOP_ALLOC between FFS and LFS.
* Update LFS copyright headers to correct values.
* Actually cast to unsigned in lfs_shellsort, like the comment says.
* Keep track of which segments were empty before the previous
checkpoint; any segments that pass two checkpoints both dirty and
empty can be summarily cleaned. Do this. Right now lfs_segclean
still works, but this should be turned into an effectless
compatibility syscall.
2003-02-18 02:48:08 +03:00
|
|
|
return error;
|
2000-06-28 00:57:11 +04:00
|
|
|
|
|
|
|
fs = VTOI(vp)->i_lfs;
|
|
|
|
s = splbio();
|
|
|
|
|
2005-04-02 01:59:46 +04:00
|
|
|
ASSERT_SEGLOCK(fs);
|
2000-06-28 00:57:11 +04:00
|
|
|
restart:
|
|
|
|
for (bp = LIST_FIRST(&vp->v_cleanblkhd); bp; bp = nbp) {
|
|
|
|
nbp = LIST_NEXT(bp, b_vnbufs);
|
|
|
|
if (bp->b_lblkno < lbn)
|
|
|
|
continue;
|
2003-04-23 11:20:37 +04:00
|
|
|
simple_lock(&bp->b_interlock);
|
2000-06-28 00:57:11 +04:00
|
|
|
if (bp->b_flags & B_BUSY) {
|
|
|
|
bp->b_flags |= B_WANTED;
|
2003-04-27 10:46:38 +04:00
|
|
|
error = ltsleep(bp, slpflag | (PRIBIO + 1) | PNORELOCK,
|
2003-04-23 11:20:37 +04:00
|
|
|
"lfs_vtruncbuf", slptimeo, &bp->b_interlock);
|
2000-06-28 00:57:11 +04:00
|
|
|
if (error) {
|
2000-05-06 00:59:20 +04:00
|
|
|
splx(s);
|
2000-06-28 00:57:11 +04:00
|
|
|
return (error);
|
1999-03-30 01:51:38 +04:00
|
|
|
}
|
2000-06-28 00:57:11 +04:00
|
|
|
goto restart;
|
|
|
|
}
|
|
|
|
bp->b_flags |= B_BUSY | B_INVAL | B_VFLUSH;
|
2000-09-09 07:47:05 +04:00
|
|
|
if (bp->b_flags & B_DELWRI) {
|
|
|
|
bp->b_flags &= ~B_DELWRI;
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
fs->lfs_avail += btofsb(fs, bp->b_bcount);
|
2000-11-21 03:00:31 +03:00
|
|
|
wakeup(&fs->lfs_avail);
|
2000-09-09 07:47:05 +04:00
|
|
|
}
|
2000-11-17 22:14:41 +03:00
|
|
|
LFS_UNLOCK_BUF(bp);
|
2003-04-23 11:20:37 +04:00
|
|
|
simple_unlock(&bp->b_interlock);
|
2000-06-28 00:57:11 +04:00
|
|
|
brelse(bp);
|
|
|
|
}
|
1999-04-02 03:28:09 +04:00
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
|
|
|
|
nbp = LIST_NEXT(bp, b_vnbufs);
|
|
|
|
if (bp->b_lblkno < lbn)
|
|
|
|
continue;
|
2003-04-23 11:20:37 +04:00
|
|
|
simple_lock(&bp->b_interlock);
|
2000-06-28 00:57:11 +04:00
|
|
|
if (bp->b_flags & B_BUSY) {
|
|
|
|
bp->b_flags |= B_WANTED;
|
2003-04-27 10:46:38 +04:00
|
|
|
error = ltsleep(bp, slpflag | (PRIBIO + 1) | PNORELOCK,
|
2003-04-23 11:20:37 +04:00
|
|
|
"lfs_vtruncbuf", slptimeo, &bp->b_interlock);
|
2000-06-28 00:57:11 +04:00
|
|
|
if (error) {
|
|
|
|
splx(s);
|
|
|
|
return (error);
|
1999-04-02 03:28:09 +04:00
|
|
|
}
|
2000-06-28 00:57:11 +04:00
|
|
|
goto restart;
|
|
|
|
}
|
|
|
|
bp->b_flags |= B_BUSY | B_INVAL | B_VFLUSH;
|
2000-09-09 07:47:05 +04:00
|
|
|
if (bp->b_flags & B_DELWRI) {
|
|
|
|
bp->b_flags &= ~B_DELWRI;
|
Merge the short-lived perseant-lfsv2 branch into the trunk.
Kernels and tools understand both v1 and v2 filesystems; newfs_lfs
generates v2 by default. Changes for the v2 layout include:
- Segments of non-PO2 size and arbitrary block offset, so these can be
matched to convenient physical characteristics of the partition (e.g.,
stripe or track size and offset).
- Address by fragment instead of by disk sector, paving the way for
non-512-byte-sector devices. In theory fragments can be as large
as you like, though in reality they must be smaller than MAXBSIZE in size.
- Use serial number and filesystem identifier to ensure that roll-forward
doesn't get old data and think it's new. Roll-forward is enabled for
v2 filesystems, though not for v1 filesystems by default.
- The inode free list is now a tailq, paving the way for undelete (undelete
is not yet implemented, but can be without further non-backwards-compatible
changes to disk structures).
- Inode atime information is kept in the Ifile, instead of on the inode;
that is, the inode is never written *just* because atime was changed.
Because of this the inodes remain near the file data on the disk, rather
than wandering all over as the disk is read repeatedly. This speeds up
repeated reads by a small but noticeable amount.
Other changes of note include:
- The ifile written by newfs_lfs can now be of arbitrary length, it is no
longer restricted to a single indirect block.
- Fixed an old bug where ctime was changed every time a vnode was created.
I need to look more closely to make sure that the times are only updated
during write(2) and friends, not after-the-fact during a segment write,
and certainly not by the cleaner.
2001-07-14 00:30:18 +04:00
|
|
|
fs->lfs_avail += btofsb(fs, bp->b_bcount);
|
2000-11-21 03:00:31 +03:00
|
|
|
wakeup(&fs->lfs_avail);
|
2000-09-09 07:47:05 +04:00
|
|
|
}
|
2000-11-17 22:14:41 +03:00
|
|
|
LFS_UNLOCK_BUF(bp);
|
2003-04-23 11:20:37 +04:00
|
|
|
simple_unlock(&bp->b_interlock);
|
2000-06-28 00:57:11 +04:00
|
|
|
brelse(bp);
|
1999-03-30 01:51:38 +04:00
|
|
|
}
|
2000-06-28 00:57:11 +04:00
|
|
|
|
|
|
|
splx(s);
|
|
|
|
|
1999-03-30 01:51:38 +04:00
|
|
|
return (0);
|
|
|
|
}
|
2000-06-28 00:57:11 +04:00
|
|
|
|