2001-01-22 15:17:35 +03:00
|
|
|
/* $NetBSD: lfs_vnops.c,v 1.50 2001/01/22 12:17:43 jdolecek Exp $ */
|
1994-06-29 10:39:25 +04:00
|
|
|
|
1999-03-10 03:20:00 +03:00
|
|
|
/*-
|
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
|
|
|
* Copyright (c) 1999, 2000 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:
|
|
|
|
* This product includes software developed by the NetBSD
|
|
|
|
* Foundation, Inc. and its contributors.
|
|
|
|
* 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
|
|
|
/*
|
1998-03-01 05:20:01 +03:00
|
|
|
* Copyright (c) 1986, 1989, 1991, 1993, 1995
|
1994-06-08 15:41:58 +04:00
|
|
|
* 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.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by the University of
|
|
|
|
* California, Berkeley and its contributors.
|
|
|
|
* 4. Neither the name of the University 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 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_vnops.c 8.13 (Berkeley) 6/10/95
|
1994-06-08 15:41:58 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/namei.h>
|
|
|
|
#include <sys/resourcevar.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/buf.h>
|
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/conf.h>
|
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <sys/vnode.h>
|
|
|
|
#include <sys/malloc.h>
|
1998-09-01 07:26:05 +04:00
|
|
|
#include <sys/pool.h>
|
1996-02-10 01:28:45 +03:00
|
|
|
#include <sys/signalvar.h>
|
1994-06-08 15:41:58 +04:00
|
|
|
|
|
|
|
#include <miscfs/fifofs/fifo.h>
|
1996-09-02 03:47:48 +04:00
|
|
|
#include <miscfs/genfs/genfs.h>
|
|
|
|
#include <miscfs/specfs/specdev.h>
|
1994-06-08 15:41:58 +04:00
|
|
|
|
|
|
|
#include <ufs/ufs/quota.h>
|
|
|
|
#include <ufs/ufs/inode.h>
|
|
|
|
#include <ufs/ufs/dir.h>
|
|
|
|
#include <ufs/ufs/ufsmount.h>
|
|
|
|
#include <ufs/ufs/ufs_extern.h>
|
|
|
|
|
|
|
|
#include <ufs/lfs/lfs.h>
|
|
|
|
#include <ufs/lfs/lfs_extern.h>
|
|
|
|
|
|
|
|
/* Global vfs data structures for lfs. */
|
1996-02-10 01:28:45 +03:00
|
|
|
int (**lfs_vnodeop_p) __P((void *));
|
2001-01-22 15:17:35 +03:00
|
|
|
const struct vnodeopv_entry_desc lfs_vnodeop_entries[] = {
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &vop_default_desc, vn_default_error },
|
|
|
|
{ &vop_lookup_desc, ufs_lookup }, /* lookup */
|
1999-03-10 03:20:00 +03:00
|
|
|
{ &vop_create_desc, lfs_create }, /* create */
|
|
|
|
{ &vop_whiteout_desc, lfs_whiteout }, /* whiteout */
|
|
|
|
{ &vop_mknod_desc, lfs_mknod }, /* mknod */
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &vop_open_desc, ufs_open }, /* open */
|
|
|
|
{ &vop_close_desc, lfs_close }, /* close */
|
|
|
|
{ &vop_access_desc, ufs_access }, /* access */
|
|
|
|
{ &vop_getattr_desc, lfs_getattr }, /* getattr */
|
|
|
|
{ &vop_setattr_desc, ufs_setattr }, /* setattr */
|
|
|
|
{ &vop_read_desc, lfs_read }, /* read */
|
|
|
|
{ &vop_write_desc, lfs_write }, /* write */
|
1994-12-13 23:14:30 +03:00
|
|
|
{ &vop_lease_desc, ufs_lease_check }, /* lease */
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &vop_ioctl_desc, ufs_ioctl }, /* ioctl */
|
1999-08-04 00:19:16 +04:00
|
|
|
{ &vop_fcntl_desc, ufs_fcntl }, /* fcntl */
|
1996-09-07 16:40:22 +04:00
|
|
|
{ &vop_poll_desc, ufs_poll }, /* poll */
|
1998-03-01 05:20:01 +03:00
|
|
|
{ &vop_revoke_desc, ufs_revoke }, /* revoke */
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &vop_mmap_desc, ufs_mmap }, /* mmap */
|
|
|
|
{ &vop_fsync_desc, lfs_fsync }, /* fsync */
|
|
|
|
{ &vop_seek_desc, ufs_seek }, /* seek */
|
1999-03-10 03:20:00 +03:00
|
|
|
{ &vop_remove_desc, lfs_remove }, /* remove */
|
|
|
|
{ &vop_link_desc, lfs_link }, /* link */
|
|
|
|
{ &vop_rename_desc, lfs_rename }, /* rename */
|
|
|
|
{ &vop_mkdir_desc, lfs_mkdir }, /* mkdir */
|
|
|
|
{ &vop_rmdir_desc, lfs_rmdir }, /* rmdir */
|
|
|
|
{ &vop_symlink_desc, lfs_symlink }, /* symlink */
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &vop_readdir_desc, ufs_readdir }, /* readdir */
|
|
|
|
{ &vop_readlink_desc, ufs_readlink }, /* readlink */
|
|
|
|
{ &vop_abortop_desc, ufs_abortop }, /* abortop */
|
2000-06-28 00:57:11 +04:00
|
|
|
{ &vop_inactive_desc, lfs_inactive }, /* inactive */
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &vop_reclaim_desc, lfs_reclaim }, /* reclaim */
|
|
|
|
{ &vop_lock_desc, ufs_lock }, /* lock */
|
|
|
|
{ &vop_unlock_desc, ufs_unlock }, /* unlock */
|
|
|
|
{ &vop_bmap_desc, ufs_bmap }, /* bmap */
|
|
|
|
{ &vop_strategy_desc, ufs_strategy }, /* strategy */
|
|
|
|
{ &vop_print_desc, ufs_print }, /* print */
|
|
|
|
{ &vop_islocked_desc, ufs_islocked }, /* islocked */
|
|
|
|
{ &vop_pathconf_desc, ufs_pathconf }, /* pathconf */
|
|
|
|
{ &vop_advlock_desc, ufs_advlock }, /* advlock */
|
|
|
|
{ &vop_blkatoff_desc, lfs_blkatoff }, /* blkatoff */
|
|
|
|
{ &vop_valloc_desc, lfs_valloc }, /* valloc */
|
1999-11-15 21:49:07 +03:00
|
|
|
{ &vop_balloc_desc, lfs_balloc }, /* balloc */
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &vop_vfree_desc, lfs_vfree }, /* vfree */
|
|
|
|
{ &vop_truncate_desc, lfs_truncate }, /* truncate */
|
|
|
|
{ &vop_update_desc, lfs_update }, /* update */
|
|
|
|
{ &vop_bwrite_desc, lfs_bwrite }, /* bwrite */
|
1996-02-10 01:28:45 +03:00
|
|
|
{ (struct vnodeop_desc*)NULL, (int(*) __P((void *)))NULL }
|
1994-06-08 15:41:58 +04:00
|
|
|
};
|
2001-01-22 15:17:35 +03:00
|
|
|
const struct vnodeopv_desc lfs_vnodeop_opv_desc =
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &lfs_vnodeop_p, lfs_vnodeop_entries };
|
|
|
|
|
1996-02-10 01:28:45 +03:00
|
|
|
int (**lfs_specop_p) __P((void *));
|
2001-01-22 15:17:35 +03:00
|
|
|
const struct vnodeopv_entry_desc lfs_specop_entries[] = {
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &vop_default_desc, vn_default_error },
|
|
|
|
{ &vop_lookup_desc, spec_lookup }, /* lookup */
|
|
|
|
{ &vop_create_desc, spec_create }, /* create */
|
|
|
|
{ &vop_mknod_desc, spec_mknod }, /* mknod */
|
|
|
|
{ &vop_open_desc, spec_open }, /* open */
|
|
|
|
{ &vop_close_desc, ufsspec_close }, /* close */
|
|
|
|
{ &vop_access_desc, ufs_access }, /* access */
|
|
|
|
{ &vop_getattr_desc, lfs_getattr }, /* getattr */
|
|
|
|
{ &vop_setattr_desc, ufs_setattr }, /* setattr */
|
|
|
|
{ &vop_read_desc, ufsspec_read }, /* read */
|
|
|
|
{ &vop_write_desc, ufsspec_write }, /* write */
|
1994-12-13 23:14:30 +03:00
|
|
|
{ &vop_lease_desc, spec_lease_check }, /* lease */
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &vop_ioctl_desc, spec_ioctl }, /* ioctl */
|
1999-08-04 00:19:16 +04:00
|
|
|
{ &vop_fcntl_desc, ufs_fcntl }, /* fcntl */
|
1996-09-07 16:40:22 +04:00
|
|
|
{ &vop_poll_desc, spec_poll }, /* poll */
|
1998-03-01 05:20:01 +03:00
|
|
|
{ &vop_revoke_desc, spec_revoke }, /* revoke */
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &vop_mmap_desc, spec_mmap }, /* mmap */
|
|
|
|
{ &vop_fsync_desc, spec_fsync }, /* fsync */
|
|
|
|
{ &vop_seek_desc, spec_seek }, /* seek */
|
|
|
|
{ &vop_remove_desc, spec_remove }, /* remove */
|
|
|
|
{ &vop_link_desc, spec_link }, /* link */
|
|
|
|
{ &vop_rename_desc, spec_rename }, /* rename */
|
|
|
|
{ &vop_mkdir_desc, spec_mkdir }, /* mkdir */
|
|
|
|
{ &vop_rmdir_desc, spec_rmdir }, /* rmdir */
|
|
|
|
{ &vop_symlink_desc, spec_symlink }, /* symlink */
|
|
|
|
{ &vop_readdir_desc, spec_readdir }, /* readdir */
|
|
|
|
{ &vop_readlink_desc, spec_readlink }, /* readlink */
|
|
|
|
{ &vop_abortop_desc, spec_abortop }, /* abortop */
|
2000-06-28 00:57:11 +04:00
|
|
|
{ &vop_inactive_desc, lfs_inactive }, /* inactive */
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &vop_reclaim_desc, lfs_reclaim }, /* reclaim */
|
|
|
|
{ &vop_lock_desc, ufs_lock }, /* lock */
|
|
|
|
{ &vop_unlock_desc, ufs_unlock }, /* unlock */
|
|
|
|
{ &vop_bmap_desc, spec_bmap }, /* bmap */
|
|
|
|
{ &vop_strategy_desc, spec_strategy }, /* strategy */
|
|
|
|
{ &vop_print_desc, ufs_print }, /* print */
|
|
|
|
{ &vop_islocked_desc, ufs_islocked }, /* islocked */
|
|
|
|
{ &vop_pathconf_desc, spec_pathconf }, /* pathconf */
|
|
|
|
{ &vop_advlock_desc, spec_advlock }, /* advlock */
|
|
|
|
{ &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */
|
|
|
|
{ &vop_valloc_desc, spec_valloc }, /* valloc */
|
|
|
|
{ &vop_vfree_desc, lfs_vfree }, /* vfree */
|
|
|
|
{ &vop_truncate_desc, spec_truncate }, /* truncate */
|
|
|
|
{ &vop_update_desc, lfs_update }, /* update */
|
1999-09-04 02:48:51 +04:00
|
|
|
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */
|
1996-02-10 01:28:45 +03:00
|
|
|
{ (struct vnodeop_desc*)NULL, (int(*) __P((void *)))NULL }
|
1994-06-08 15:41:58 +04:00
|
|
|
};
|
2001-01-22 15:17:35 +03:00
|
|
|
const struct vnodeopv_desc lfs_specop_opv_desc =
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &lfs_specop_p, lfs_specop_entries };
|
|
|
|
|
1996-02-10 01:28:45 +03:00
|
|
|
int (**lfs_fifoop_p) __P((void *));
|
2001-01-22 15:17:35 +03:00
|
|
|
const struct vnodeopv_entry_desc lfs_fifoop_entries[] = {
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &vop_default_desc, vn_default_error },
|
|
|
|
{ &vop_lookup_desc, fifo_lookup }, /* lookup */
|
|
|
|
{ &vop_create_desc, fifo_create }, /* create */
|
|
|
|
{ &vop_mknod_desc, fifo_mknod }, /* mknod */
|
|
|
|
{ &vop_open_desc, fifo_open }, /* open */
|
|
|
|
{ &vop_close_desc, ufsfifo_close }, /* close */
|
|
|
|
{ &vop_access_desc, ufs_access }, /* access */
|
|
|
|
{ &vop_getattr_desc, lfs_getattr }, /* getattr */
|
|
|
|
{ &vop_setattr_desc, ufs_setattr }, /* setattr */
|
|
|
|
{ &vop_read_desc, ufsfifo_read }, /* read */
|
|
|
|
{ &vop_write_desc, ufsfifo_write }, /* write */
|
1994-12-13 23:14:30 +03:00
|
|
|
{ &vop_lease_desc, fifo_lease_check }, /* lease */
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
|
1999-08-04 00:19:16 +04:00
|
|
|
{ &vop_fcntl_desc, ufs_fcntl }, /* fcntl */
|
1996-09-07 16:40:22 +04:00
|
|
|
{ &vop_poll_desc, fifo_poll }, /* poll */
|
1998-03-01 05:20:01 +03:00
|
|
|
{ &vop_revoke_desc, fifo_revoke }, /* revoke */
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &vop_mmap_desc, fifo_mmap }, /* mmap */
|
|
|
|
{ &vop_fsync_desc, fifo_fsync }, /* fsync */
|
|
|
|
{ &vop_seek_desc, fifo_seek }, /* seek */
|
|
|
|
{ &vop_remove_desc, fifo_remove }, /* remove */
|
|
|
|
{ &vop_link_desc, fifo_link }, /* link */
|
|
|
|
{ &vop_rename_desc, fifo_rename }, /* rename */
|
|
|
|
{ &vop_mkdir_desc, fifo_mkdir }, /* mkdir */
|
|
|
|
{ &vop_rmdir_desc, fifo_rmdir }, /* rmdir */
|
|
|
|
{ &vop_symlink_desc, fifo_symlink }, /* symlink */
|
|
|
|
{ &vop_readdir_desc, fifo_readdir }, /* readdir */
|
|
|
|
{ &vop_readlink_desc, fifo_readlink }, /* readlink */
|
|
|
|
{ &vop_abortop_desc, fifo_abortop }, /* abortop */
|
2000-06-28 00:57:11 +04:00
|
|
|
{ &vop_inactive_desc, lfs_inactive }, /* inactive */
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &vop_reclaim_desc, lfs_reclaim }, /* reclaim */
|
|
|
|
{ &vop_lock_desc, ufs_lock }, /* lock */
|
|
|
|
{ &vop_unlock_desc, ufs_unlock }, /* unlock */
|
|
|
|
{ &vop_bmap_desc, fifo_bmap }, /* bmap */
|
|
|
|
{ &vop_strategy_desc, fifo_strategy }, /* strategy */
|
|
|
|
{ &vop_print_desc, ufs_print }, /* print */
|
|
|
|
{ &vop_islocked_desc, ufs_islocked }, /* islocked */
|
|
|
|
{ &vop_pathconf_desc, fifo_pathconf }, /* pathconf */
|
|
|
|
{ &vop_advlock_desc, fifo_advlock }, /* advlock */
|
|
|
|
{ &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */
|
|
|
|
{ &vop_valloc_desc, fifo_valloc }, /* valloc */
|
|
|
|
{ &vop_vfree_desc, lfs_vfree }, /* vfree */
|
|
|
|
{ &vop_truncate_desc, fifo_truncate }, /* truncate */
|
|
|
|
{ &vop_update_desc, lfs_update }, /* update */
|
|
|
|
{ &vop_bwrite_desc, lfs_bwrite }, /* bwrite */
|
1996-02-10 01:28:45 +03:00
|
|
|
{ (struct vnodeop_desc*)NULL, (int(*) __P((void *)))NULL }
|
1994-06-08 15:41:58 +04:00
|
|
|
};
|
2001-01-22 15:17:35 +03:00
|
|
|
const struct vnodeopv_desc lfs_fifoop_opv_desc =
|
1994-06-08 15:41:58 +04:00
|
|
|
{ &lfs_fifoop_p, lfs_fifoop_entries };
|
|
|
|
|
2000-07-06 02:25:43 +04:00
|
|
|
/*
|
|
|
|
* A function version of LFS_ITIMES, for the UFS functions which call ITIMES
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
lfs_itimes(ip, acc, mod, cre)
|
|
|
|
struct inode *ip;
|
|
|
|
struct timespec *acc, *mod, *cre;
|
|
|
|
{
|
|
|
|
LFS_ITIMES(ip, acc, mod, cre);
|
|
|
|
}
|
|
|
|
|
1994-06-08 15:41:58 +04:00
|
|
|
#define LFS_READWRITE
|
|
|
|
#include <ufs/ufs/ufs_readwrite.c>
|
|
|
|
#undef LFS_READWRITE
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Synch an open file.
|
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
1996-02-10 01:28:45 +03:00
|
|
|
int
|
|
|
|
lfs_fsync(v)
|
|
|
|
void *v;
|
|
|
|
{
|
1994-06-08 15:41:58 +04:00
|
|
|
struct vop_fsync_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
struct ucred *a_cred;
|
1999-03-10 03:20:00 +03:00
|
|
|
int a_flags;
|
2000-11-18 05:11:23 +03:00
|
|
|
off_t offlo;
|
|
|
|
off_t offhi;
|
1994-06-08 15:41:58 +04:00
|
|
|
struct proc *a_p;
|
1996-02-10 01:28:45 +03:00
|
|
|
} */ *ap = v;
|
1999-03-10 03:20:00 +03:00
|
|
|
|
2000-11-12 10:58:36 +03:00
|
|
|
/* Ignore the trickle syncer */
|
|
|
|
if (ap->a_flags & FSYNC_LAZY)
|
|
|
|
return 0;
|
|
|
|
|
1999-03-06 00:09:48 +03:00
|
|
|
return (VOP_UPDATE(ap->a_vp, NULL, NULL,
|
2000-05-27 04:19:52 +04:00
|
|
|
(ap->a_flags & FSYNC_WAIT) != 0 ? UPDATE_WAIT : 0));
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
/*
|
|
|
|
* Take IN_ADIROP off, then call ufs_inactive.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
lfs_inactive(v)
|
|
|
|
void *v;
|
|
|
|
{
|
|
|
|
struct vop_inactive_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
struct proc *a_p;
|
|
|
|
} */ *ap = v;
|
|
|
|
struct inode *ip = VTOI(ap->a_vp);
|
|
|
|
|
|
|
|
if (ip->i_flag & IN_ADIROP)
|
|
|
|
--ip->i_lfs->lfs_nadirop;
|
|
|
|
ip->i_flag &= ~IN_ADIROP;
|
|
|
|
return ufs_inactive(v);
|
|
|
|
}
|
|
|
|
|
1994-06-08 15:41:58 +04:00
|
|
|
/*
|
|
|
|
* These macros are used to bracket UFS directory ops, so that we can
|
|
|
|
* identify all the pages touched during directory ops which need to
|
|
|
|
* be ordered and flushed atomically, so that they may be recovered.
|
|
|
|
*/
|
1999-03-10 03:20:00 +03:00
|
|
|
/*
|
|
|
|
* XXX KS - Because we have to mark nodes VDIROP in order to prevent
|
|
|
|
* the cache from reclaiming them while a dirop is in progress, we must
|
|
|
|
* also manage the number of nodes so marked (otherwise we can run out).
|
|
|
|
* We do this by setting lfs_dirvcount to the number of marked vnodes; it
|
|
|
|
* is decremented during segment write, when VDIROP is taken off.
|
|
|
|
*/
|
2000-06-28 00:57:11 +04:00
|
|
|
#define SET_DIROP(vp) lfs_set_dirop(vp)
|
|
|
|
static int lfs_set_dirop __P((struct vnode *));
|
1999-11-06 23:33:05 +03:00
|
|
|
extern int lfs_dirvcount;
|
1999-03-26 01:33:03 +03:00
|
|
|
|
2000-10-15 03:22:14 +04:00
|
|
|
static int
|
|
|
|
lfs_set_dirop(vp)
|
2000-06-28 00:57:11 +04:00
|
|
|
struct vnode *vp;
|
1999-03-26 01:33:03 +03:00
|
|
|
{
|
2000-06-28 00:57:11 +04:00
|
|
|
struct lfs *fs;
|
1999-03-26 01:33:03 +03:00
|
|
|
int error;
|
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
fs = VTOI(vp)->i_lfs;
|
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
|
|
|
/*
|
|
|
|
* We might need one directory block plus supporting indirect blocks,
|
|
|
|
* plus an inode block and ifile page for the new vnode.
|
|
|
|
*/
|
|
|
|
if ((error = lfs_reserve(fs, vp, fsbtodb(fs, NIADDR + 3))) != 0)
|
|
|
|
return (error);
|
2000-06-28 00:57:11 +04:00
|
|
|
if (fs->lfs_dirops == 0)
|
|
|
|
lfs_check(vp, LFS_UNUSED_LBN, 0);
|
|
|
|
while (fs->lfs_writer || lfs_dirvcount > LFS_MAXDIROP) {
|
1999-03-26 01:33:03 +03:00
|
|
|
if(fs->lfs_writer)
|
|
|
|
tsleep(&fs->lfs_dirops, PRIBIO + 1, "lfs_dirop", 0);
|
1999-12-04 00:47:44 +03:00
|
|
|
if(lfs_dirvcount > LFS_MAXDIROP && fs->lfs_dirops==0) {
|
|
|
|
++fs->lfs_writer;
|
|
|
|
lfs_flush(fs, 0);
|
|
|
|
if(--fs->lfs_writer==0)
|
|
|
|
wakeup(&fs->lfs_dirops);
|
|
|
|
}
|
|
|
|
|
1999-11-06 23:33:05 +03:00
|
|
|
if(lfs_dirvcount > LFS_MAXDIROP) {
|
1999-03-26 01:33:03 +03:00
|
|
|
#ifdef DEBUG_LFS
|
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
|
|
|
printf("lfs_set_dirop: sleeping with dirops=%d, "
|
|
|
|
"dirvcount=%d\n", fs->lfs_dirops,
|
|
|
|
lfs_dirvcount);
|
1999-03-26 01:33:03 +03:00
|
|
|
#endif
|
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 = tsleep(&lfs_dirvcount, PCATCH|PUSER,
|
|
|
|
"lfs_maxdirop", 0)) !=0) {
|
|
|
|
lfs_reserve(fs, vp, -fsbtodb(fs, NIADDR + 3));
|
1999-03-26 01:33:03 +03:00
|
|
|
return error;
|
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
|
|
|
}
|
1999-03-26 01:33:03 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
++fs->lfs_dirops;
|
|
|
|
fs->lfs_doifile = 1;
|
|
|
|
|
2000-10-15 03:22:14 +04:00
|
|
|
/* Hold a reference so SET_ENDOP will be happy */
|
|
|
|
lfs_vref(vp);
|
|
|
|
|
1999-03-26 01:33:03 +03:00
|
|
|
return 0;
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
|
|
|
|
1999-04-12 04:36:47 +04:00
|
|
|
#define SET_ENDOP(fs,vp,str) { \
|
1994-06-08 15:41:58 +04:00
|
|
|
--(fs)->lfs_dirops; \
|
1999-03-10 03:20:00 +03:00
|
|
|
if (!(fs)->lfs_dirops) { \
|
2000-06-28 00:57:11 +04:00
|
|
|
if ((fs)->lfs_nadirop) { \
|
|
|
|
panic("SET_ENDOP: %s: no dirops but nadirop=%d\n", \
|
|
|
|
(str), (fs)->lfs_nadirop); \
|
|
|
|
} \
|
1994-06-08 15:41:58 +04:00
|
|
|
wakeup(&(fs)->lfs_writer); \
|
1999-04-12 04:36:47 +04:00
|
|
|
lfs_check((vp),LFS_UNUSED_LBN,0); \
|
1999-03-10 03:20:00 +03:00
|
|
|
} \
|
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
|
|
|
lfs_reserve(fs, vp, -fsbtodb(fs, NIADDR + 3)); /* XXX */ \
|
2000-10-15 03:22:14 +04:00
|
|
|
lfs_vunref(vp); \
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
|
|
|
|
1999-03-10 03:20:00 +03:00
|
|
|
#define MARK_VNODE(dvp) do { \
|
2000-05-27 04:19:52 +04:00
|
|
|
if (!((dvp)->v_flag & VDIROP)) { \
|
2000-06-22 22:11:45 +04:00
|
|
|
(void)lfs_vref(dvp); \
|
1999-11-06 23:33:05 +03:00
|
|
|
++lfs_dirvcount; \
|
1999-03-10 03:20:00 +03:00
|
|
|
} \
|
|
|
|
(dvp)->v_flag |= VDIROP; \
|
2000-05-27 04:19:52 +04:00
|
|
|
if (!(VTOI(dvp)->i_flag & IN_ADIROP)) { \
|
|
|
|
++VTOI(dvp)->i_lfs->lfs_nadirop; \
|
|
|
|
} \
|
|
|
|
VTOI(dvp)->i_flag |= IN_ADIROP; \
|
|
|
|
} while(0)
|
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
#define UNMARK_VNODE(vp) lfs_unmark_vnode(vp)
|
|
|
|
|
|
|
|
void lfs_unmark_vnode(vp)
|
|
|
|
struct vnode *vp;
|
|
|
|
{
|
|
|
|
struct inode *ip;
|
|
|
|
|
|
|
|
ip = VTOI(vp);
|
|
|
|
|
|
|
|
if (ip->i_flag & IN_ADIROP)
|
|
|
|
--ip->i_lfs->lfs_nadirop;
|
|
|
|
ip->i_flag &= ~IN_ADIROP;
|
|
|
|
}
|
1998-03-01 05:20:01 +03:00
|
|
|
|
1994-06-08 15:41:58 +04:00
|
|
|
int
|
1996-02-10 01:28:45 +03:00
|
|
|
lfs_symlink(v)
|
|
|
|
void *v;
|
|
|
|
{
|
1994-06-08 15:41:58 +04:00
|
|
|
struct vop_symlink_args /* {
|
|
|
|
struct vnode *a_dvp;
|
|
|
|
struct vnode **a_vpp;
|
|
|
|
struct componentname *a_cnp;
|
|
|
|
struct vattr *a_vap;
|
|
|
|
char *a_target;
|
1996-02-10 01:28:45 +03:00
|
|
|
} */ *ap = v;
|
2000-05-27 04:19:52 +04:00
|
|
|
int error;
|
1994-06-08 15:41:58 +04:00
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
if ((error = SET_DIROP(ap->a_dvp)) != 0) {
|
1999-12-15 10:19:07 +03:00
|
|
|
vput(ap->a_dvp);
|
2000-05-27 04:19:52 +04:00
|
|
|
return error;
|
1999-12-15 10:19:07 +03:00
|
|
|
}
|
1994-06-08 15:41:58 +04:00
|
|
|
MARK_VNODE(ap->a_dvp);
|
2000-05-27 04:19:52 +04:00
|
|
|
error = ufs_symlink(ap);
|
|
|
|
UNMARK_VNODE(ap->a_dvp);
|
2000-06-28 00:57:11 +04:00
|
|
|
if (*(ap->a_vpp))
|
2000-05-27 04:19:52 +04:00
|
|
|
UNMARK_VNODE(*(ap->a_vpp));
|
|
|
|
SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"symlink");
|
|
|
|
return (error);
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
1996-02-10 01:28:45 +03:00
|
|
|
lfs_mknod(v)
|
|
|
|
void *v;
|
|
|
|
{
|
1999-03-10 03:20:00 +03:00
|
|
|
struct vop_mknod_args /* {
|
1994-06-08 15:41:58 +04:00
|
|
|
struct vnode *a_dvp;
|
|
|
|
struct vnode **a_vpp;
|
|
|
|
struct componentname *a_cnp;
|
|
|
|
struct vattr *a_vap;
|
1999-03-10 03:20:00 +03:00
|
|
|
} */ *ap = v;
|
1999-09-04 02:48:51 +04:00
|
|
|
struct vattr *vap = ap->a_vap;
|
|
|
|
struct vnode **vpp = ap->a_vpp;
|
|
|
|
struct inode *ip;
|
|
|
|
int error;
|
1994-06-08 15:41:58 +04:00
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
if ((error = SET_DIROP(ap->a_dvp)) != 0) {
|
1999-12-15 10:19:07 +03:00
|
|
|
vput(ap->a_dvp);
|
1999-09-04 02:48:51 +04:00
|
|
|
return error;
|
1999-12-15 10:19:07 +03:00
|
|
|
}
|
1994-06-08 15:41:58 +04:00
|
|
|
MARK_VNODE(ap->a_dvp);
|
1999-09-04 02:48:51 +04:00
|
|
|
error = ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
|
|
|
|
ap->a_dvp, vpp, ap->a_cnp);
|
2000-05-27 04:19:52 +04:00
|
|
|
UNMARK_VNODE(ap->a_dvp);
|
2000-06-28 00:57:11 +04:00
|
|
|
if (*(ap->a_vpp))
|
2000-05-27 04:19:52 +04:00
|
|
|
UNMARK_VNODE(*(ap->a_vpp));
|
1999-09-04 02:48:51 +04:00
|
|
|
|
|
|
|
/* Either way we're done with the dirop at this point */
|
1999-04-12 04:36:47 +04:00
|
|
|
SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"mknod");
|
1999-09-04 02:48:51 +04:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
ip = VTOI(*vpp);
|
|
|
|
ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
|
|
|
|
if (vap->va_rdev != VNOVAL) {
|
|
|
|
/*
|
|
|
|
* Want to be able to use this to make badblock
|
|
|
|
* inodes, so don't truncate the dev number.
|
|
|
|
*/
|
|
|
|
#if 0
|
|
|
|
ip->i_ffs_rdev = ufs_rw32(vap->va_rdev,
|
|
|
|
UFS_MPNEEDSWAP((*vpp)->v_mount));
|
|
|
|
#else
|
|
|
|
ip->i_ffs_rdev = vap->va_rdev;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Call fsync to write the vnode so that we don't have to deal with
|
|
|
|
* flushing it when it's marked VDIROP|VXLOCK.
|
|
|
|
*
|
|
|
|
* XXX KS - If we can't flush we also can't call vgone(), so must
|
|
|
|
* return. But, that leaves this vnode in limbo, also not good.
|
|
|
|
* Can this ever happen (barring hardware failure)?
|
|
|
|
*/
|
2000-11-18 05:11:23 +03:00
|
|
|
if ((error = VOP_FSYNC(*vpp, NOCRED, FSYNC_WAIT, 0, 0, curproc)) != 0) {
|
2000-06-28 00:57:11 +04:00
|
|
|
printf("Couldn't fsync in mknod (ino %d)---what do I do?\n",
|
|
|
|
VTOI(*vpp)->i_number);
|
1999-09-04 02:48:51 +04:00
|
|
|
return (error);
|
2000-06-28 00:57:11 +04:00
|
|
|
}
|
1999-09-04 02:48:51 +04:00
|
|
|
/*
|
2000-06-28 00:57:11 +04:00
|
|
|
* Remove vnode so that it will be reloaded by VFS_VGET and
|
1999-09-04 02:48:51 +04:00
|
|
|
* checked to see if it is an alias of an existing entry in
|
|
|
|
* the inode cache.
|
|
|
|
*/
|
|
|
|
/* Used to be vput, but that causes us to call VOP_INACTIVE twice. */
|
2000-06-28 00:57:11 +04:00
|
|
|
VOP_UNLOCK(*vpp, 0);
|
1999-09-04 02:48:51 +04:00
|
|
|
lfs_vunref(*vpp);
|
|
|
|
(*vpp)->v_type = VNON;
|
|
|
|
vgone(*vpp);
|
|
|
|
*vpp = 0;
|
|
|
|
return (0);
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
1996-02-10 01:28:45 +03:00
|
|
|
lfs_create(v)
|
|
|
|
void *v;
|
|
|
|
{
|
1999-03-10 03:20:00 +03:00
|
|
|
struct vop_create_args /* {
|
1994-06-08 15:41:58 +04:00
|
|
|
struct vnode *a_dvp;
|
|
|
|
struct vnode **a_vpp;
|
|
|
|
struct componentname *a_cnp;
|
|
|
|
struct vattr *a_vap;
|
1996-02-10 01:28:45 +03:00
|
|
|
} */ *ap = v;
|
2000-05-27 04:19:52 +04:00
|
|
|
int error;
|
1994-06-08 15:41:58 +04:00
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
if((error = SET_DIROP(ap->a_dvp)) != 0) {
|
1999-12-15 10:19:07 +03:00
|
|
|
vput(ap->a_dvp);
|
2000-05-27 04:19:52 +04:00
|
|
|
return error;
|
1999-12-15 10:19:07 +03:00
|
|
|
}
|
1994-06-08 15:41:58 +04:00
|
|
|
MARK_VNODE(ap->a_dvp);
|
2000-05-27 04:19:52 +04:00
|
|
|
error = ufs_create(ap);
|
|
|
|
UNMARK_VNODE(ap->a_dvp);
|
2000-06-28 00:57:11 +04:00
|
|
|
if (*(ap->a_vpp))
|
2000-05-27 04:19:52 +04:00
|
|
|
UNMARK_VNODE(*(ap->a_vpp));
|
1999-04-12 04:36:47 +04:00
|
|
|
SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"create");
|
2000-05-27 04:19:52 +04:00
|
|
|
return (error);
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
|
|
|
|
1999-03-10 03:20:00 +03:00
|
|
|
int
|
|
|
|
lfs_whiteout(v)
|
|
|
|
void *v;
|
|
|
|
{
|
|
|
|
struct vop_whiteout_args /* {
|
|
|
|
struct vnode *a_dvp;
|
|
|
|
struct componentname *a_cnp;
|
|
|
|
int a_flags;
|
|
|
|
} */ *ap = v;
|
2000-05-27 04:19:52 +04:00
|
|
|
int error;
|
1999-03-10 03:20:00 +03:00
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
if ((error = SET_DIROP(ap->a_dvp)) != 0)
|
1999-12-15 10:19:07 +03:00
|
|
|
/* XXX no unlock here? */
|
2000-05-27 04:19:52 +04:00
|
|
|
return error;
|
1999-03-10 03:20:00 +03:00
|
|
|
MARK_VNODE(ap->a_dvp);
|
2000-05-27 04:19:52 +04:00
|
|
|
error = ufs_whiteout(ap);
|
|
|
|
UNMARK_VNODE(ap->a_dvp);
|
1999-04-12 04:36:47 +04:00
|
|
|
SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"whiteout");
|
2000-05-27 04:19:52 +04:00
|
|
|
return (error);
|
1999-03-10 03:20:00 +03:00
|
|
|
}
|
|
|
|
|
1994-06-08 15:41:58 +04:00
|
|
|
int
|
1996-02-10 01:28:45 +03:00
|
|
|
lfs_mkdir(v)
|
|
|
|
void *v;
|
|
|
|
{
|
1999-03-10 03:20:00 +03:00
|
|
|
struct vop_mkdir_args /* {
|
1994-06-08 15:41:58 +04:00
|
|
|
struct vnode *a_dvp;
|
|
|
|
struct vnode **a_vpp;
|
|
|
|
struct componentname *a_cnp;
|
|
|
|
struct vattr *a_vap;
|
1996-02-10 01:28:45 +03:00
|
|
|
} */ *ap = v;
|
2000-05-27 04:19:52 +04:00
|
|
|
int error;
|
1994-06-08 15:41:58 +04:00
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
if((error = SET_DIROP(ap->a_dvp)) != 0) {
|
1999-12-15 10:19:07 +03:00
|
|
|
vput(ap->a_dvp);
|
2000-05-27 04:19:52 +04:00
|
|
|
return error;
|
1999-12-15 10:19:07 +03:00
|
|
|
}
|
1994-06-08 15:41:58 +04:00
|
|
|
MARK_VNODE(ap->a_dvp);
|
2000-05-27 04:19:52 +04:00
|
|
|
error = ufs_mkdir(ap);
|
|
|
|
UNMARK_VNODE(ap->a_dvp);
|
2000-06-28 00:57:11 +04:00
|
|
|
if (*(ap->a_vpp))
|
2000-05-27 04:19:52 +04:00
|
|
|
UNMARK_VNODE(*(ap->a_vpp));
|
1999-04-12 04:36:47 +04:00
|
|
|
SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"mkdir");
|
2000-05-27 04:19:52 +04:00
|
|
|
return (error);
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
1996-02-10 01:28:45 +03:00
|
|
|
lfs_remove(v)
|
|
|
|
void *v;
|
|
|
|
{
|
1999-03-10 03:20:00 +03:00
|
|
|
struct vop_remove_args /* {
|
1994-06-08 15:41:58 +04:00
|
|
|
struct vnode *a_dvp;
|
|
|
|
struct vnode *a_vp;
|
|
|
|
struct componentname *a_cnp;
|
1996-02-10 01:28:45 +03:00
|
|
|
} */ *ap = v;
|
1999-12-15 10:19:07 +03:00
|
|
|
struct vnode *dvp, *vp;
|
2000-05-27 04:19:52 +04:00
|
|
|
int error;
|
1999-12-15 10:19:07 +03:00
|
|
|
|
|
|
|
dvp = ap->a_dvp;
|
|
|
|
vp = ap->a_vp;
|
2000-06-28 00:57:11 +04:00
|
|
|
if ((error = SET_DIROP(dvp)) != 0) {
|
1999-12-15 10:19:07 +03:00
|
|
|
if (dvp == vp)
|
|
|
|
vrele(vp);
|
|
|
|
else
|
|
|
|
vput(vp);
|
|
|
|
vput(dvp);
|
2000-05-27 04:19:52 +04:00
|
|
|
return error;
|
1999-12-15 10:19:07 +03:00
|
|
|
}
|
|
|
|
MARK_VNODE(dvp);
|
|
|
|
MARK_VNODE(vp);
|
2000-05-27 04:19:52 +04:00
|
|
|
error = ufs_remove(ap);
|
|
|
|
UNMARK_VNODE(dvp);
|
|
|
|
UNMARK_VNODE(vp);
|
2000-06-28 00:57:11 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If ufs_remove failed, vp doesn't need to be VDIROP any more.
|
|
|
|
* If it succeeded, we can go ahead and wipe out vp, since
|
|
|
|
* its loss won't appear on disk until checkpoint, and by then
|
|
|
|
* dvp will have been written, completing the dirop.
|
|
|
|
*/
|
|
|
|
--lfs_dirvcount;
|
|
|
|
vp->v_flag &= ~VDIROP;
|
|
|
|
wakeup(&lfs_dirvcount);
|
|
|
|
vrele(vp);
|
|
|
|
|
2000-07-01 23:03:57 +04:00
|
|
|
SET_ENDOP(VTOI(dvp)->i_lfs,dvp,"remove");
|
2000-05-27 04:19:52 +04:00
|
|
|
return (error);
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
1996-02-10 01:28:45 +03:00
|
|
|
lfs_rmdir(v)
|
|
|
|
void *v;
|
|
|
|
{
|
1999-03-10 03:20:00 +03:00
|
|
|
struct vop_rmdir_args /* {
|
1994-06-08 15:41:58 +04:00
|
|
|
struct vnodeop_desc *a_desc;
|
|
|
|
struct vnode *a_dvp;
|
|
|
|
struct vnode *a_vp;
|
|
|
|
struct componentname *a_cnp;
|
1996-02-10 01:28:45 +03:00
|
|
|
} */ *ap = v;
|
2000-05-27 04:19:52 +04:00
|
|
|
int error;
|
1994-06-08 15:41:58 +04:00
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
if ((error = SET_DIROP(ap->a_dvp)) != 0) {
|
1999-12-15 10:19:07 +03:00
|
|
|
vrele(ap->a_dvp);
|
|
|
|
if (ap->a_vp->v_mountedhere != NULL)
|
|
|
|
VOP_UNLOCK(ap->a_dvp, 0);
|
|
|
|
vput(ap->a_vp);
|
2000-05-27 04:19:52 +04:00
|
|
|
return error;
|
1999-12-15 10:19:07 +03:00
|
|
|
}
|
1994-06-08 15:41:58 +04:00
|
|
|
MARK_VNODE(ap->a_dvp);
|
|
|
|
MARK_VNODE(ap->a_vp);
|
2000-05-27 04:19:52 +04:00
|
|
|
error = ufs_rmdir(ap);
|
|
|
|
UNMARK_VNODE(ap->a_dvp);
|
|
|
|
UNMARK_VNODE(ap->a_vp);
|
2000-06-28 00:57:11 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If ufs_rmdir failed, vp doesn't need to be VDIROP any more.
|
|
|
|
* If it succeeded, we can go ahead and wipe out vp, since
|
|
|
|
* its loss won't appear on disk until checkpoint, and by then
|
|
|
|
* dvp will have been written, completing the dirop.
|
|
|
|
*/
|
|
|
|
--lfs_dirvcount;
|
|
|
|
ap->a_vp->v_flag &= ~VDIROP;
|
|
|
|
wakeup(&lfs_dirvcount);
|
|
|
|
vrele(ap->a_vp);
|
|
|
|
|
2000-07-01 23:03:57 +04:00
|
|
|
SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"rmdir");
|
2000-05-27 04:19:52 +04:00
|
|
|
return (error);
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
1996-02-10 01:28:45 +03:00
|
|
|
lfs_link(v)
|
|
|
|
void *v;
|
|
|
|
{
|
1999-03-10 03:20:00 +03:00
|
|
|
struct vop_link_args /* {
|
1996-02-09 17:45:36 +03:00
|
|
|
struct vnode *a_dvp;
|
1994-06-08 15:41:58 +04:00
|
|
|
struct vnode *a_vp;
|
|
|
|
struct componentname *a_cnp;
|
1996-02-10 01:28:45 +03:00
|
|
|
} */ *ap = v;
|
2000-05-27 04:19:52 +04:00
|
|
|
int error;
|
1994-06-08 15:41:58 +04:00
|
|
|
|
2000-06-28 00:57:11 +04:00
|
|
|
if ((error = SET_DIROP(ap->a_dvp)) != 0) {
|
1999-12-15 10:19:07 +03:00
|
|
|
vput(ap->a_dvp);
|
2000-05-27 04:19:52 +04:00
|
|
|
return error;
|
1999-12-15 10:19:07 +03:00
|
|
|
}
|
1996-02-09 17:45:36 +03:00
|
|
|
MARK_VNODE(ap->a_dvp);
|
2000-05-27 04:19:52 +04:00
|
|
|
error = ufs_link(ap);
|
|
|
|
UNMARK_VNODE(ap->a_dvp);
|
1999-04-12 04:36:47 +04:00
|
|
|
SET_ENDOP(VTOI(ap->a_dvp)->i_lfs,ap->a_dvp,"link");
|
2000-05-27 04:19:52 +04:00
|
|
|
return (error);
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
1999-03-10 03:20:00 +03:00
|
|
|
|
1994-06-08 15:41:58 +04:00
|
|
|
int
|
1996-02-10 01:28:45 +03:00
|
|
|
lfs_rename(v)
|
|
|
|
void *v;
|
|
|
|
{
|
1999-03-10 03:20:00 +03:00
|
|
|
struct vop_rename_args /* {
|
1994-06-08 15:41:58 +04:00
|
|
|
struct vnode *a_fdvp;
|
|
|
|
struct vnode *a_fvp;
|
|
|
|
struct componentname *a_fcnp;
|
|
|
|
struct vnode *a_tdvp;
|
|
|
|
struct vnode *a_tvp;
|
|
|
|
struct componentname *a_tcnp;
|
1996-02-10 01:28:45 +03:00
|
|
|
} */ *ap = v;
|
1999-11-05 23:14:56 +03:00
|
|
|
struct vnode *tvp, *fvp, *tdvp, *fdvp;
|
|
|
|
int error;
|
1999-11-01 21:29:33 +03:00
|
|
|
struct lfs *fs;
|
|
|
|
|
|
|
|
fs = VTOI(ap->a_fdvp)->i_lfs;
|
1999-11-05 23:14:56 +03:00
|
|
|
tvp = ap->a_tvp;
|
|
|
|
tdvp = ap->a_tdvp;
|
|
|
|
fvp = ap->a_fvp;
|
|
|
|
fdvp = ap->a_fdvp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for cross-device rename.
|
|
|
|
* If it is, we don't want to set dirops, just error out.
|
|
|
|
* (In particular note that MARK_VNODE(tdvp) will DTWT on
|
|
|
|
* a cross-device rename.)
|
|
|
|
*
|
|
|
|
* Copied from ufs_rename.
|
|
|
|
*/
|
|
|
|
if ((fvp->v_mount != tdvp->v_mount) ||
|
|
|
|
(tvp && (fvp->v_mount != tvp->v_mount))) {
|
|
|
|
error = EXDEV;
|
1999-12-15 10:19:07 +03:00
|
|
|
goto errout;
|
1999-11-05 23:14:56 +03:00
|
|
|
}
|
2000-06-28 00:57:11 +04:00
|
|
|
if ((error = SET_DIROP(fdvp))!=0)
|
1999-12-15 10:19:07 +03:00
|
|
|
goto errout;
|
1999-11-05 23:14:56 +03:00
|
|
|
MARK_VNODE(fdvp);
|
|
|
|
MARK_VNODE(tdvp);
|
|
|
|
error = ufs_rename(ap);
|
2000-05-27 04:19:52 +04:00
|
|
|
UNMARK_VNODE(fdvp);
|
|
|
|
UNMARK_VNODE(tdvp);
|
1999-11-05 23:14:56 +03:00
|
|
|
SET_ENDOP(fs,fdvp,"rename");
|
|
|
|
return (error);
|
1999-12-15 10:19:07 +03:00
|
|
|
|
|
|
|
errout:
|
|
|
|
VOP_ABORTOP(tdvp, ap->a_tcnp); /* XXX, why not in NFS? */
|
|
|
|
if (tdvp == tvp)
|
|
|
|
vrele(tdvp);
|
|
|
|
else
|
|
|
|
vput(tdvp);
|
|
|
|
if (tvp)
|
|
|
|
vput(tvp);
|
|
|
|
VOP_ABORTOP(fdvp, ap->a_fcnp); /* XXX, why not in NFS? */
|
|
|
|
vrele(fdvp);
|
|
|
|
vrele(fvp);
|
|
|
|
return (error);
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
1999-03-10 03:20:00 +03:00
|
|
|
|
1994-06-08 15:41:58 +04:00
|
|
|
/* XXX hack to avoid calling ITIMES in getattr */
|
|
|
|
int
|
1996-02-10 01:28:45 +03:00
|
|
|
lfs_getattr(v)
|
|
|
|
void *v;
|
|
|
|
{
|
1994-06-08 15:41:58 +04:00
|
|
|
struct vop_getattr_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
struct vattr *a_vap;
|
|
|
|
struct ucred *a_cred;
|
|
|
|
struct proc *a_p;
|
1996-02-10 01:28:45 +03:00
|
|
|
} */ *ap = v;
|
2000-03-30 16:41:09 +04:00
|
|
|
struct vnode *vp = ap->a_vp;
|
|
|
|
struct inode *ip = VTOI(vp);
|
|
|
|
struct vattr *vap = ap->a_vap;
|
1994-06-08 15:41:58 +04:00
|
|
|
/*
|
|
|
|
* Copy from inode table
|
|
|
|
*/
|
|
|
|
vap->va_fsid = ip->i_dev;
|
|
|
|
vap->va_fileid = ip->i_number;
|
1997-06-11 14:09:37 +04:00
|
|
|
vap->va_mode = ip->i_ffs_mode & ~IFMT;
|
|
|
|
vap->va_nlink = ip->i_ffs_nlink;
|
|
|
|
vap->va_uid = ip->i_ffs_uid;
|
|
|
|
vap->va_gid = ip->i_ffs_gid;
|
|
|
|
vap->va_rdev = (dev_t)ip->i_ffs_rdev;
|
|
|
|
vap->va_size = ip->i_ffs_size;
|
|
|
|
vap->va_atime.tv_sec = ip->i_ffs_atime;
|
|
|
|
vap->va_atime.tv_nsec = ip->i_ffs_atimensec;
|
|
|
|
vap->va_mtime.tv_sec = ip->i_ffs_mtime;
|
|
|
|
vap->va_mtime.tv_nsec = ip->i_ffs_mtimensec;
|
|
|
|
vap->va_ctime.tv_sec = ip->i_ffs_ctime;
|
|
|
|
vap->va_ctime.tv_nsec = ip->i_ffs_ctimensec;
|
|
|
|
vap->va_flags = ip->i_ffs_flags;
|
|
|
|
vap->va_gen = ip->i_ffs_gen;
|
1994-06-08 15:41:58 +04:00
|
|
|
/* this doesn't belong here */
|
|
|
|
if (vp->v_type == VBLK)
|
|
|
|
vap->va_blocksize = BLKDEV_IOSIZE;
|
|
|
|
else if (vp->v_type == VCHR)
|
|
|
|
vap->va_blocksize = MAXBSIZE;
|
|
|
|
else
|
|
|
|
vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
|
1998-11-07 02:02:12 +03:00
|
|
|
vap->va_bytes = dbtob((u_quad_t)ip->i_ffs_blocks);
|
1994-06-08 15:41:58 +04:00
|
|
|
vap->va_type = vp->v_type;
|
|
|
|
vap->va_filerev = ip->i_modrev;
|
|
|
|
return (0);
|
|
|
|
}
|
1999-03-10 03:20:00 +03:00
|
|
|
|
1994-06-08 15:41:58 +04:00
|
|
|
/*
|
|
|
|
* Close called
|
|
|
|
*
|
|
|
|
* XXX -- we were using ufs_close, but since it updates the
|
|
|
|
* times on the inode, we might need to bump the uinodes
|
|
|
|
* count.
|
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
1996-02-10 01:28:45 +03:00
|
|
|
lfs_close(v)
|
|
|
|
void *v;
|
|
|
|
{
|
1994-06-08 15:41:58 +04:00
|
|
|
struct vop_close_args /* {
|
|
|
|
struct vnode *a_vp;
|
|
|
|
int a_fflag;
|
|
|
|
struct ucred *a_cred;
|
|
|
|
struct proc *a_p;
|
1996-02-10 01:28:45 +03:00
|
|
|
} */ *ap = v;
|
2000-03-30 16:41:09 +04:00
|
|
|
struct vnode *vp = ap->a_vp;
|
|
|
|
struct inode *ip = VTOI(vp);
|
1996-09-02 03:47:48 +04:00
|
|
|
struct timespec ts;
|
1994-06-08 15:41:58 +04:00
|
|
|
|
1998-03-01 05:20:01 +03:00
|
|
|
simple_lock(&vp->v_interlock);
|
|
|
|
if (vp->v_usecount > 1) {
|
1996-09-02 03:47:48 +04:00
|
|
|
TIMEVAL_TO_TIMESPEC(&time, &ts);
|
1999-03-10 03:20:00 +03:00
|
|
|
LFS_ITIMES(ip, &ts, &ts, &ts);
|
1994-06-08 15:41:58 +04:00
|
|
|
}
|
1998-03-01 05:20:01 +03:00
|
|
|
simple_unlock(&vp->v_interlock);
|
1994-06-08 15:41:58 +04:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1998-03-01 05:20:01 +03:00
|
|
|
* Reclaim an inode so that it can be used for other purposes.
|
1994-06-08 15:41:58 +04:00
|
|
|
*/
|
|
|
|
int lfs_no_inactive = 0;
|
|
|
|
|
|
|
|
int
|
1996-02-10 01:28:45 +03:00
|
|
|
lfs_reclaim(v)
|
|
|
|
void *v;
|
|
|
|
{
|
1994-06-08 15:41:58 +04:00
|
|
|
struct vop_reclaim_args /* {
|
|
|
|
struct vnode *a_vp;
|
1998-03-01 05:20:01 +03:00
|
|
|
struct proc *a_p;
|
1996-02-10 01:28:45 +03:00
|
|
|
} */ *ap = v;
|
1998-03-01 05:20:01 +03:00
|
|
|
struct vnode *vp = ap->a_vp;
|
1994-06-08 15:41:58 +04:00
|
|
|
int error;
|
|
|
|
|
2000-07-06 02:25:43 +04:00
|
|
|
LFS_CLR_UINO(VTOI(vp), IN_ALLMOD);
|
1998-03-01 05:20:01 +03:00
|
|
|
if ((error = ufs_reclaim(vp, ap->a_p)))
|
1994-06-08 15:41:58 +04:00
|
|
|
return (error);
|
1998-09-01 07:26:05 +04:00
|
|
|
pool_put(&lfs_inode_pool, vp->v_data);
|
1994-06-08 15:41:58 +04:00
|
|
|
vp->v_data = NULL;
|
|
|
|
return (0);
|
|
|
|
}
|