version 1.223.4.1, 2008/05/16 02:26:00 |
version 1.223.4.2, 2009/05/04 08:14:37 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
|
|
|
/*- |
|
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. |
|
* All rights reserved. |
|
* |
|
* This code is derived from software contributed to The NetBSD Foundation |
|
* by Wasabi Systems, Inc, and by Andrew Doran. |
|
* |
|
* 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. |
|
* |
|
* 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. |
|
*/ |
|
|
/* |
/* |
* Copyright (c) 1989, 1991, 1993, 1994 |
* Copyright (c) 1989, 1991, 1993, 1994 |
* The Regents of the University of California. All rights reserved. |
* The Regents of the University of California. All rights reserved. |
Line 37 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 66 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#if defined(_KERNEL_OPT) |
#if defined(_KERNEL_OPT) |
#include "opt_ffs.h" |
#include "opt_ffs.h" |
#include "opt_quota.h" |
#include "opt_quota.h" |
#include "opt_softdep.h" |
#include "opt_wapbl.h" |
#endif |
#endif |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
Line 61 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 90 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/sysctl.h> |
#include <sys/sysctl.h> |
#include <sys/conf.h> |
#include <sys/conf.h> |
#include <sys/kauth.h> |
#include <sys/kauth.h> |
|
#include <sys/wapbl.h> |
#include <sys/fstrans.h> |
#include <sys/fstrans.h> |
#include <sys/module.h> |
#include <sys/module.h> |
|
|
Line 73 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 103 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <ufs/ufs/dir.h> |
#include <ufs/ufs/dir.h> |
#include <ufs/ufs/ufs_extern.h> |
#include <ufs/ufs/ufs_extern.h> |
#include <ufs/ufs/ufs_bswap.h> |
#include <ufs/ufs/ufs_bswap.h> |
|
#include <ufs/ufs/ufs_wapbl.h> |
|
|
#include <ufs/ffs/fs.h> |
#include <ufs/ffs/fs.h> |
#include <ufs/ffs/ffs_extern.h> |
#include <ufs/ffs/ffs_extern.h> |
|
|
MODULE(MODULE_CLASS_VFS, ffs, NULL); |
MODULE(MODULE_CLASS_VFS, ffs, NULL); |
|
|
|
static int ffs_vfs_fsync(vnode_t *, int); |
|
|
|
static struct sysctllog *ffs_sysctl_log; |
|
|
/* how many times ffs_init() was called */ |
/* how many times ffs_init() was called */ |
int ffs_initcount = 0; |
int ffs_initcount = 0; |
|
|
Line 117 struct vfsops ffs_vfsops = { |
|
Line 152 struct vfsops ffs_vfsops = { |
|
ffs_suspendctl, |
ffs_suspendctl, |
genfs_renamelock_enter, |
genfs_renamelock_enter, |
genfs_renamelock_exit, |
genfs_renamelock_exit, |
ffs_full_fsync, |
ffs_vfs_fsync, |
ffs_vnodeopv_descs, |
ffs_vnodeopv_descs, |
0, |
0, |
{ NULL, NULL }, |
{ NULL, NULL }, |
Line 137 static const struct ufs_ops ffs_ufsops = |
|
Line 172 static const struct ufs_ops ffs_ufsops = |
|
.uo_valloc = ffs_valloc, |
.uo_valloc = ffs_valloc, |
.uo_vfree = ffs_vfree, |
.uo_vfree = ffs_vfree, |
.uo_balloc = ffs_balloc, |
.uo_balloc = ffs_balloc, |
|
.uo_unmark_vnode = (void (*)(vnode_t *))nullop, |
}; |
}; |
|
|
static int |
static int |
ffs_modcmd(modcmd_t cmd, void *arg) |
ffs_modcmd(modcmd_t cmd, void *arg) |
{ |
{ |
|
int error; |
|
|
|
#if 0 |
|
extern int doasyncfree; |
|
#endif |
|
extern int ffs_log_changeopt; |
|
|
switch (cmd) { |
switch (cmd) { |
case MODULE_CMD_INIT: |
case MODULE_CMD_INIT: |
return vfs_attach(&ffs_vfsops); |
error = vfs_attach(&ffs_vfsops); |
|
if (error != 0) |
|
break; |
|
|
|
sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT, |
|
CTLTYPE_NODE, "vfs", NULL, |
|
NULL, 0, NULL, 0, |
|
CTL_VFS, CTL_EOL); |
|
sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT, |
|
CTLTYPE_NODE, "ffs", |
|
SYSCTL_DESCR("Berkeley Fast File System"), |
|
NULL, 0, NULL, 0, |
|
CTL_VFS, 1, CTL_EOL); |
|
|
|
/* |
|
* @@@ should we even bother with these first three? |
|
*/ |
|
sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
|
CTLTYPE_INT, "doclusterread", NULL, |
|
sysctl_notavail, 0, NULL, 0, |
|
CTL_VFS, 1, FFS_CLUSTERREAD, CTL_EOL); |
|
sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
|
CTLTYPE_INT, "doclusterwrite", NULL, |
|
sysctl_notavail, 0, NULL, 0, |
|
CTL_VFS, 1, FFS_CLUSTERWRITE, CTL_EOL); |
|
sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
|
CTLTYPE_INT, "doreallocblks", NULL, |
|
sysctl_notavail, 0, NULL, 0, |
|
CTL_VFS, 1, FFS_REALLOCBLKS, CTL_EOL); |
|
#if 0 |
|
sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
|
CTLTYPE_INT, "doasyncfree", |
|
SYSCTL_DESCR("Release dirty blocks asynchronously"), |
|
NULL, 0, &doasyncfree, 0, |
|
CTL_VFS, 1, FFS_ASYNCFREE, CTL_EOL); |
|
#endif |
|
sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
|
CTLTYPE_INT, "log_changeopt", |
|
SYSCTL_DESCR("Log changes in optimization strategy"), |
|
NULL, 0, &ffs_log_changeopt, 0, |
|
CTL_VFS, 1, FFS_LOG_CHANGEOPT, CTL_EOL); |
|
break; |
case MODULE_CMD_FINI: |
case MODULE_CMD_FINI: |
return vfs_detach(&ffs_vfsops); |
error = vfs_detach(&ffs_vfsops); |
|
if (error != 0) |
|
break; |
|
sysctl_teardown(&ffs_sysctl_log); |
|
break; |
default: |
default: |
return ENOTTY; |
error = ENOTTY; |
|
break; |
} |
} |
|
|
|
return (error); |
} |
} |
|
|
pool_cache_t ffs_inode_cache; |
pool_cache_t ffs_inode_cache; |
Line 180 ffs_mountroot(void) |
|
Line 277 ffs_mountroot(void) |
|
vrele(rootvp); |
vrele(rootvp); |
return (error); |
return (error); |
} |
} |
|
|
|
/* |
|
* We always need to be able to mount the root file system. |
|
*/ |
|
mp->mnt_flag |= MNT_FORCE; |
if ((error = ffs_mountfs(rootvp, mp, l)) != 0) { |
if ((error = ffs_mountfs(rootvp, mp, l)) != 0) { |
vfs_unbusy(mp, false, NULL); |
vfs_unbusy(mp, false, NULL); |
vfs_destroy(mp); |
vfs_destroy(mp); |
return (error); |
return (error); |
} |
} |
|
mp->mnt_flag &= ~MNT_FORCE; |
mutex_enter(&mountlist_lock); |
mutex_enter(&mountlist_lock); |
CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); |
CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); |
mutex_exit(&mountlist_lock); |
mutex_exit(&mountlist_lock); |
Line 208 ffs_mount(struct mount *mp, const char * |
|
Line 311 ffs_mount(struct mount *mp, const char * |
|
{ |
{ |
struct lwp *l = curlwp; |
struct lwp *l = curlwp; |
struct nameidata nd; |
struct nameidata nd; |
struct vnode *vp, *devvp = NULL; |
struct vnode *devvp = NULL; |
struct ufs_args *args = data; |
struct ufs_args *args = data; |
struct ufsmount *ump = NULL; |
struct ufsmount *ump = NULL; |
struct fs *fs; |
struct fs *fs; |
Line 227 ffs_mount(struct mount *mp, const char * |
|
Line 330 ffs_mount(struct mount *mp, const char * |
|
return 0; |
return 0; |
} |
} |
|
|
#if !defined(SOFTDEP) |
|
mp->mnt_flag &= ~MNT_SOFTDEP; |
|
#endif |
|
|
|
update = mp->mnt_flag & MNT_UPDATE; |
update = mp->mnt_flag & MNT_UPDATE; |
|
|
/* Check arguments */ |
/* Check arguments */ |
Line 280 ffs_mount(struct mount *mp, const char * |
|
Line 379 ffs_mount(struct mount *mp, const char * |
|
} |
} |
|
|
/* |
/* |
* Mark the device and any existing vnodes as involved in |
|
* softdep processing. |
|
*/ |
|
if ((mp->mnt_flag & MNT_SOFTDEP) != 0) { |
|
devvp->v_uflag |= VU_SOFTDEP; |
|
mutex_enter(&mntvnode_lock); |
|
TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) { |
|
if (vp->v_mount != mp || vismarker(vp)) |
|
continue; |
|
vp->v_uflag |= VU_SOFTDEP; |
|
} |
|
mutex_exit(&mntvnode_lock); |
|
} |
|
|
|
/* |
|
* If mount by non-root, then verify that user has necessary |
* If mount by non-root, then verify that user has necessary |
* permissions on the device. |
* permissions on the device. |
*/ |
* |
if (error == 0 && kauth_authorize_generic(l->l_cred, |
* Permission to update a mount is checked higher, so here we presume |
KAUTH_GENERIC_ISSUSER, NULL) != 0) { |
* updating the mount is okay (for example, as far as securelevel goes) |
accessmode = VREAD; |
* which leaves us with the normal check. |
if (update ? |
*/ |
(mp->mnt_iflag & IMNT_WANTRDWR) != 0 : |
accessmode = VREAD; |
(mp->mnt_flag & MNT_RDONLY) == 0) |
if (update ? |
accessmode |= VWRITE; |
(mp->mnt_iflag & IMNT_WANTRDWR) != 0 : |
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); |
(mp->mnt_flag & MNT_RDONLY) == 0) |
error = VOP_ACCESS(devvp, accessmode, l->l_cred); |
accessmode |= VWRITE; |
VOP_UNLOCK(devvp, 0); |
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); |
} |
error = genfs_can_mount(devvp, accessmode, l->l_cred); |
|
VOP_UNLOCK(devvp, 0); |
|
|
if (error) { |
if (error) { |
vrele(devvp); |
vrele(devvp); |
return (error); |
return (error); |
} |
} |
|
|
|
#ifdef WAPBL |
|
/* WAPBL can only be enabled on a r/w mount. */ |
|
if ((mp->mnt_flag & MNT_RDONLY) && !(mp->mnt_iflag & IMNT_WANTRDWR)) { |
|
mp->mnt_flag &= ~MNT_LOG; |
|
} |
|
#else /* !WAPBL */ |
|
mp->mnt_flag &= ~MNT_LOG; |
|
#endif /* !WAPBL */ |
|
|
if (!update) { |
if (!update) { |
int xflags; |
int xflags; |
|
|
if (mp->mnt_flag & MNT_RDONLY) |
if (mp->mnt_flag & MNT_RDONLY) |
xflags = FREAD; |
xflags = FREAD; |
else |
else |
xflags = FREAD|FWRITE; |
xflags = FREAD | FWRITE; |
error = VOP_OPEN(devvp, xflags, FSCRED); |
error = VOP_OPEN(devvp, xflags, FSCRED); |
if (error) |
if (error) |
goto fail; |
goto fail; |
Line 335 ffs_mount(struct mount *mp, const char * |
|
Line 429 ffs_mount(struct mount *mp, const char * |
|
|
|
ump = VFSTOUFS(mp); |
ump = VFSTOUFS(mp); |
fs = ump->um_fs; |
fs = ump->um_fs; |
if ((mp->mnt_flag & (MNT_SOFTDEP | MNT_ASYNC)) == |
|
(MNT_SOFTDEP | MNT_ASYNC)) { |
|
printf("%s fs uses soft updates, " |
|
"ignoring async mode\n", |
|
fs->fs_fsmnt); |
|
mp->mnt_flag &= ~MNT_ASYNC; |
|
} |
|
} else { |
} else { |
/* |
/* |
* Update the mount. |
* Update the mount. |
Line 363 ffs_mount(struct mount *mp, const char * |
|
Line 450 ffs_mount(struct mount *mp, const char * |
|
flags = WRITECLOSE; |
flags = WRITECLOSE; |
if (mp->mnt_flag & MNT_FORCE) |
if (mp->mnt_flag & MNT_FORCE) |
flags |= FORCECLOSE; |
flags |= FORCECLOSE; |
if (mp->mnt_flag & MNT_SOFTDEP) |
error = ffs_flushfiles(mp, flags, l); |
error = softdep_flushfiles(mp, flags, l); |
if (error == 0) |
else |
error = UFS_WAPBL_BEGIN(mp); |
error = ffs_flushfiles(mp, flags, l); |
|
if (fs->fs_pendingblocks != 0 || |
|
fs->fs_pendinginodes != 0) { |
|
printf("%s: update error: blocks %" PRId64 |
|
" files %d\n", |
|
fs->fs_fsmnt, fs->fs_pendingblocks, |
|
fs->fs_pendinginodes); |
|
fs->fs_pendingblocks = 0; |
|
fs->fs_pendinginodes = 0; |
|
} |
|
if (error == 0 && |
if (error == 0 && |
ffs_cgupdate(ump, MNT_WAIT) == 0 && |
ffs_cgupdate(ump, MNT_WAIT) == 0 && |
fs->fs_clean & FS_WASCLEAN) { |
fs->fs_clean & FS_WASCLEAN) { |
Line 384 ffs_mount(struct mount *mp, const char * |
|
Line 461 ffs_mount(struct mount *mp, const char * |
|
fs->fs_clean = FS_ISCLEAN; |
fs->fs_clean = FS_ISCLEAN; |
(void) ffs_sbupdate(ump, MNT_WAIT); |
(void) ffs_sbupdate(ump, MNT_WAIT); |
} |
} |
|
if (error == 0) |
|
UFS_WAPBL_END(mp); |
if (error) |
if (error) |
return (error); |
return (error); |
fs->fs_ronly = 1; |
|
fs->fs_fmod = 0; |
|
} |
} |
|
|
/* |
#ifdef WAPBL |
* Flush soft dependencies if disabling it via an update |
if ((mp->mnt_flag & MNT_LOG) == 0) { |
* mount. This may leave some items to be processed, |
error = ffs_wapbl_stop(mp, mp->mnt_flag & MNT_FORCE); |
* so don't do this yet XXX. |
if (error) |
*/ |
return error; |
if ((fs->fs_flags & FS_DOSOFTDEP) && |
|
!(mp->mnt_flag & MNT_SOFTDEP) && fs->fs_ronly == 0) { |
|
#ifdef notyet |
|
flags = WRITECLOSE; |
|
if (mp->mnt_flag & MNT_FORCE) |
|
flags |= FORCECLOSE; |
|
error = softdep_flushfiles(mp, flags, l); |
|
if (error == 0 && ffs_cgupdate(ump, MNT_WAIT) == 0) |
|
fs->fs_flags &= ~FS_DOSOFTDEP; |
|
(void) ffs_sbupdate(ump, MNT_WAIT); |
|
#elif defined(SOFTDEP) |
|
mp->mnt_flag |= MNT_SOFTDEP; |
|
#endif |
|
} |
} |
|
#endif /* WAPBL */ |
|
|
/* |
if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { |
* When upgrading to a softdep mount, we must first flush |
/* |
* all vnodes. (not done yet -- see above) |
* Finish change from r/w to r/o |
*/ |
*/ |
if (!(fs->fs_flags & FS_DOSOFTDEP) && |
fs->fs_ronly = 1; |
(mp->mnt_flag & MNT_SOFTDEP) && fs->fs_ronly == 0) { |
fs->fs_fmod = 0; |
#ifdef notyet |
|
flags = WRITECLOSE; |
|
if (mp->mnt_flag & MNT_FORCE) |
|
flags |= FORCECLOSE; |
|
error = ffs_flushfiles(mp, flags, l); |
|
#else |
|
mp->mnt_flag &= ~MNT_SOFTDEP; |
|
#endif |
|
} |
} |
|
|
if (mp->mnt_flag & MNT_RELOAD) { |
if (mp->mnt_flag & MNT_RELOAD) { |
Line 439 ffs_mount(struct mount *mp, const char * |
|
Line 496 ffs_mount(struct mount *mp, const char * |
|
fs->fs_ronly = 0; |
fs->fs_ronly = 0; |
fs->fs_clean <<= 1; |
fs->fs_clean <<= 1; |
fs->fs_fmod = 1; |
fs->fs_fmod = 1; |
if ((fs->fs_flags & FS_DOSOFTDEP)) { |
#ifdef WAPBL |
error = softdep_mount(devvp, mp, fs, |
if (fs->fs_flags & FS_DOWAPBL) { |
l->l_cred); |
printf("%s: replaying log to disk\n", |
if (error) |
fs->fs_fsmnt); |
return (error); |
KDASSERT(mp->mnt_wapbl_replay); |
|
error = wapbl_replay_write(mp->mnt_wapbl_replay, |
|
devvp); |
|
if (error) { |
|
return error; |
|
} |
|
wapbl_replay_stop(mp->mnt_wapbl_replay); |
|
fs->fs_clean = FS_WASCLEAN; |
} |
} |
|
#endif /* WAPBL */ |
if (fs->fs_snapinum[0] != 0) |
if (fs->fs_snapinum[0] != 0) |
ffs_snapshot_mount(mp); |
ffs_snapshot_mount(mp); |
} |
} |
|
|
|
#ifdef WAPBL |
|
error = ffs_wapbl_start(mp); |
|
if (error) |
|
return error; |
|
#endif /* WAPBL */ |
|
|
if (args->fspec == NULL) |
if (args->fspec == NULL) |
return EINVAL; |
return EINVAL; |
if ((mp->mnt_flag & (MNT_SOFTDEP | MNT_ASYNC)) == |
|
(MNT_SOFTDEP | MNT_ASYNC)) { |
|
printf("%s fs uses soft updates, ignoring async mode\n", |
|
fs->fs_fsmnt); |
|
mp->mnt_flag &= ~MNT_ASYNC; |
|
} |
|
} |
} |
|
|
error = set_statvfs_info(path, UIO_USERSPACE, args->fspec, |
error = set_statvfs_info(path, UIO_USERSPACE, args->fspec, |
Line 463 ffs_mount(struct mount *mp, const char * |
|
Line 529 ffs_mount(struct mount *mp, const char * |
|
if (error == 0) |
if (error == 0) |
(void)strncpy(fs->fs_fsmnt, mp->mnt_stat.f_mntonname, |
(void)strncpy(fs->fs_fsmnt, mp->mnt_stat.f_mntonname, |
sizeof(fs->fs_fsmnt)); |
sizeof(fs->fs_fsmnt)); |
if (mp->mnt_flag & MNT_SOFTDEP) |
fs->fs_flags &= ~FS_DOSOFTDEP; |
fs->fs_flags |= FS_DOSOFTDEP; |
|
else |
|
fs->fs_flags &= ~FS_DOSOFTDEP; |
|
if (fs->fs_fmod != 0) { /* XXX */ |
if (fs->fs_fmod != 0) { /* XXX */ |
|
int err; |
|
|
fs->fs_fmod = 0; |
fs->fs_fmod = 0; |
if (fs->fs_clean & FS_WASCLEAN) |
if (fs->fs_clean & FS_WASCLEAN) |
fs->fs_time = time_second; |
fs->fs_time = time_second; |
else { |
else { |
printf("%s: file system not clean (fs_clean=%x); please fsck(8)\n", |
printf("%s: file system not clean (fs_clean=%#x); " |
mp->mnt_stat.f_mntfromname, fs->fs_clean); |
"please fsck(8)\n", mp->mnt_stat.f_mntfromname, |
|
fs->fs_clean); |
printf("%s: lost blocks %" PRId64 " files %d\n", |
printf("%s: lost blocks %" PRId64 " files %d\n", |
mp->mnt_stat.f_mntfromname, fs->fs_pendingblocks, |
mp->mnt_stat.f_mntfromname, fs->fs_pendingblocks, |
fs->fs_pendinginodes); |
fs->fs_pendinginodes); |
} |
} |
(void) ffs_cgupdate(ump, MNT_WAIT); |
err = UFS_WAPBL_BEGIN(mp); |
|
if (err == 0) { |
|
(void) ffs_cgupdate(ump, MNT_WAIT); |
|
UFS_WAPBL_END(mp); |
|
} |
} |
} |
|
if ((mp->mnt_flag & MNT_SOFTDEP) != 0) { |
|
printf("%s: `-o softdep' is no longer supported, " |
|
"consider `-o log'\n", mp->mnt_stat.f_mntfromname); |
|
mp->mnt_flag &= ~MNT_SOFTDEP; |
|
} |
|
|
return (error); |
return (error); |
|
|
fail: |
fail: |
Line 537 ffs_reload(struct mount *mp, kauth_cred_ |
|
Line 613 ffs_reload(struct mount *mp, kauth_cred_ |
|
size = dpart.disklab->d_secsize; |
size = dpart.disklab->d_secsize; |
/* XXX we don't handle possibility that superblock moved. */ |
/* XXX we don't handle possibility that superblock moved. */ |
error = bread(devvp, fs->fs_sblockloc / size, fs->fs_sbsize, |
error = bread(devvp, fs->fs_sblockloc / size, fs->fs_sbsize, |
NOCRED, &bp); |
NOCRED, 0, &bp); |
if (error) { |
if (error) { |
brelse(bp, 0); |
brelse(bp, 0); |
return (error); |
return (error); |
Line 590 ffs_reload(struct mount *mp, kauth_cred_ |
|
Line 666 ffs_reload(struct mount *mp, kauth_cred_ |
|
* is found, then treat it like an Apple UFS filesystem anyway |
* is found, then treat it like an Apple UFS filesystem anyway |
*/ |
*/ |
error = bread(devvp, (daddr_t)(APPLEUFS_LABEL_OFFSET / size), |
error = bread(devvp, (daddr_t)(APPLEUFS_LABEL_OFFSET / size), |
APPLEUFS_LABEL_SIZE, cred, &bp); |
APPLEUFS_LABEL_SIZE, cred, 0, &bp); |
if (error) { |
if (error) { |
brelse(bp, 0); |
brelse(bp, 0); |
return (error); |
return (error); |
} |
} |
error = ffs_appleufs_validate(fs->fs_fsmnt, |
error = ffs_appleufs_validate(fs->fs_fsmnt, |
(struct appleufslabel *)bp->b_data,NULL); |
(struct appleufslabel *)bp->b_data, NULL); |
if (error == 0) |
if (error == 0) |
ump->um_flags |= UFS_ISAPPLEUFS; |
ump->um_flags |= UFS_ISAPPLEUFS; |
brelse(bp, 0); |
brelse(bp, 0); |
Line 621 ffs_reload(struct mount *mp, kauth_cred_ |
|
Line 697 ffs_reload(struct mount *mp, kauth_cred_ |
|
mp->mnt_iflag &= ~IMNT_DTYPE; |
mp->mnt_iflag &= ~IMNT_DTYPE; |
} |
} |
ffs_oldfscompat_read(fs, ump, sblockloc); |
ffs_oldfscompat_read(fs, ump, sblockloc); |
|
|
mutex_enter(&ump->um_lock); |
mutex_enter(&ump->um_lock); |
ump->um_maxfilesize = fs->fs_maxfilesize; |
ump->um_maxfilesize = fs->fs_maxfilesize; |
|
if (fs->fs_flags & ~(FS_KNOWN_FLAGS | FS_INTERNAL)) { |
|
uprintf("%s: unknown ufs flags: 0x%08"PRIx32"%s\n", |
|
mp->mnt_stat.f_mntonname, fs->fs_flags, |
|
(mp->mnt_flag & MNT_FORCE) ? "" : ", not mounting"); |
|
if ((mp->mnt_flag & MNT_FORCE) == 0) { |
|
mutex_exit(&ump->um_lock); |
|
return (EINVAL); |
|
} |
|
} |
if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) { |
if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) { |
fs->fs_pendingblocks = 0; |
fs->fs_pendingblocks = 0; |
fs->fs_pendinginodes = 0; |
fs->fs_pendinginodes = 0; |
Line 640 ffs_reload(struct mount *mp, kauth_cred_ |
|
Line 726 ffs_reload(struct mount *mp, kauth_cred_ |
|
if (i + fs->fs_frag > blks) |
if (i + fs->fs_frag > blks) |
size = (blks - i) * fs->fs_fsize; |
size = (blks - i) * fs->fs_fsize; |
error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, |
error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, |
NOCRED, &bp); |
NOCRED, 0, &bp); |
if (error) { |
if (error) { |
brelse(bp, 0); |
brelse(bp, 0); |
return (error); |
return (error); |
Line 655 ffs_reload(struct mount *mp, kauth_cred_ |
|
Line 741 ffs_reload(struct mount *mp, kauth_cred_ |
|
space = (char *)space + size; |
space = (char *)space + size; |
brelse(bp, 0); |
brelse(bp, 0); |
} |
} |
if ((fs->fs_flags & FS_DOSOFTDEP)) |
|
softdep_mount(devvp, mp, fs, cred); |
|
if (fs->fs_snapinum[0] != 0) |
if (fs->fs_snapinum[0] != 0) |
ffs_snapshot_mount(mp); |
ffs_snapshot_mount(mp); |
/* |
/* |
Line 705 ffs_reload(struct mount *mp, kauth_cred_ |
|
Line 789 ffs_reload(struct mount *mp, kauth_cred_ |
|
*/ |
*/ |
ip = VTOI(vp); |
ip = VTOI(vp); |
error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), |
error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), |
(int)fs->fs_bsize, NOCRED, &bp); |
(int)fs->fs_bsize, NOCRED, 0, &bp); |
if (error) { |
if (error) { |
brelse(bp, 0); |
brelse(bp, 0); |
vput(vp); |
vput(vp); |
Line 713 ffs_reload(struct mount *mp, kauth_cred_ |
|
Line 797 ffs_reload(struct mount *mp, kauth_cred_ |
|
break; |
break; |
} |
} |
ffs_load_inode(bp, ip, fs, ip->i_number); |
ffs_load_inode(bp, ip, fs, ip->i_number); |
ip->i_ffs_effnlink = ip->i_nlink; |
|
brelse(bp, 0); |
brelse(bp, 0); |
vput(vp); |
vput(vp); |
mutex_enter(&mntvnode_lock); |
mutex_enter(&mntvnode_lock); |
Line 776 ffs_mountfs(struct vnode *devvp, struct |
|
Line 859 ffs_mountfs(struct vnode *devvp, struct |
|
if (error) |
if (error) |
return error; |
return error; |
|
|
|
ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); |
|
memset(ump, 0, sizeof *ump); |
|
mutex_init(&ump->um_lock, MUTEX_DEFAULT, IPL_NONE); |
|
error = ffs_snapshot_init(ump); |
|
if (error) |
|
goto out; |
|
ump->um_ops = &ffs_ufsops; |
|
|
|
#ifdef WAPBL |
|
sbagain: |
|
#endif |
/* |
/* |
* Try reading the superblock in each of its possible locations. |
* Try reading the superblock in each of its possible locations. |
*/ |
*/ |
Line 790 ffs_mountfs(struct vnode *devvp, struct |
|
Line 884 ffs_mountfs(struct vnode *devvp, struct |
|
goto out; |
goto out; |
} |
} |
error = bread(devvp, sblock_try[i] / size, SBLOCKSIZE, cred, |
error = bread(devvp, sblock_try[i] / size, SBLOCKSIZE, cred, |
&bp); |
0, &bp); |
if (error) { |
if (error) { |
fs = NULL; |
fs = NULL; |
goto out; |
goto out; |
Line 853 ffs_mountfs(struct vnode *devvp, struct |
|
Line 947 ffs_mountfs(struct vnode *devvp, struct |
|
|
|
fs = malloc((u_long)sbsize, M_UFSMNT, M_WAITOK); |
fs = malloc((u_long)sbsize, M_UFSMNT, M_WAITOK); |
memcpy(fs, bp->b_data, sbsize); |
memcpy(fs, bp->b_data, sbsize); |
|
|
ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); |
|
memset(ump, 0, sizeof *ump); |
|
mutex_init(&ump->um_lock, MUTEX_DEFAULT, IPL_NONE); |
|
error = ffs_snapshot_init(ump); |
|
if (error) |
|
goto out; |
|
ump->um_fs = fs; |
ump->um_fs = fs; |
ump->um_ops = &ffs_ufsops; |
|
|
|
#ifdef FFS_EI |
#ifdef FFS_EI |
if (needswap) { |
if (needswap) { |
Line 871 ffs_mountfs(struct vnode *devvp, struct |
|
Line 957 ffs_mountfs(struct vnode *devvp, struct |
|
#endif |
#endif |
fs->fs_flags &= ~FS_SWAPPED; |
fs->fs_flags &= ~FS_SWAPPED; |
|
|
|
#ifdef WAPBL |
|
if ((mp->mnt_wapbl_replay == 0) && (fs->fs_flags & FS_DOWAPBL)) { |
|
error = ffs_wapbl_replay_start(mp, fs, devvp); |
|
if (error) |
|
goto out; |
|
|
|
if (!ronly) { |
|
/* XXX fsmnt may be stale. */ |
|
printf("%s: replaying log to disk\n", fs->fs_fsmnt); |
|
error = wapbl_replay_write(mp->mnt_wapbl_replay, devvp); |
|
if (error) |
|
goto out; |
|
wapbl_replay_stop(mp->mnt_wapbl_replay); |
|
fs->fs_clean = FS_WASCLEAN; |
|
} else { |
|
/* XXX fsmnt may be stale */ |
|
printf("%s: replaying log to memory\n", fs->fs_fsmnt); |
|
} |
|
|
|
/* Force a re-read of the superblock */ |
|
brelse(bp, BC_INVAL); |
|
bp = NULL; |
|
free(fs, M_UFSMNT); |
|
fs = NULL; |
|
goto sbagain; |
|
} |
|
#else /* !WAPBL */ |
|
if ((fs->fs_flags & FS_DOWAPBL) && (mp->mnt_flag & MNT_FORCE) == 0) { |
|
error = EPERM; |
|
goto out; |
|
} |
|
#endif /* !WAPBL */ |
|
|
ffs_oldfscompat_read(fs, ump, sblockloc); |
ffs_oldfscompat_read(fs, ump, sblockloc); |
ump->um_maxfilesize = fs->fs_maxfilesize; |
ump->um_maxfilesize = fs->fs_maxfilesize; |
|
|
|
if (fs->fs_flags & ~(FS_KNOWN_FLAGS | FS_INTERNAL)) { |
|
uprintf("%s: unknown ufs flags: 0x%08"PRIx32"%s\n", |
|
mp->mnt_stat.f_mntonname, fs->fs_flags, |
|
(mp->mnt_flag & MNT_FORCE) ? "" : ", not mounting"); |
|
if ((mp->mnt_flag & MNT_FORCE) == 0) { |
|
error = EINVAL; |
|
goto out; |
|
} |
|
} |
|
|
if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) { |
if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) { |
fs->fs_pendingblocks = 0; |
fs->fs_pendingblocks = 0; |
fs->fs_pendinginodes = 0; |
fs->fs_pendinginodes = 0; |
Line 899 ffs_mountfs(struct vnode *devvp, struct |
|
Line 1028 ffs_mountfs(struct vnode *devvp, struct |
|
* is found, then treat it like an Apple UFS filesystem anyway |
* is found, then treat it like an Apple UFS filesystem anyway |
*/ |
*/ |
error = bread(devvp, (daddr_t)(APPLEUFS_LABEL_OFFSET / size), |
error = bread(devvp, (daddr_t)(APPLEUFS_LABEL_OFFSET / size), |
APPLEUFS_LABEL_SIZE, cred, &bp); |
APPLEUFS_LABEL_SIZE, cred, 0, &bp); |
if (error) |
if (error) |
goto out; |
goto out; |
error = ffs_appleufs_validate(fs->fs_fsmnt, |
error = ffs_appleufs_validate(fs->fs_fsmnt, |
(struct appleufslabel *)bp->b_data,NULL); |
(struct appleufslabel *)bp->b_data, NULL); |
if (error == 0) { |
if (error == 0) { |
ump->um_flags |= UFS_ISAPPLEUFS; |
ump->um_flags |= UFS_ISAPPLEUFS; |
} |
} |
Line 917 ffs_mountfs(struct vnode *devvp, struct |
|
Line 1046 ffs_mountfs(struct vnode *devvp, struct |
|
} |
} |
#endif |
#endif |
|
|
|
#if 0 |
|
/* |
|
* XXX This code changes the behaviour of mounting dirty filesystems, to |
|
* XXX require "mount -f ..." to mount them. This doesn't match what |
|
* XXX mount(8) describes and is disabled for now. |
|
*/ |
|
/* |
|
* If the file system is not clean, don't allow it to be mounted |
|
* unless MNT_FORCE is specified. (Note: MNT_FORCE is always set |
|
* for the root file system.) |
|
*/ |
|
if (fs->fs_flags & FS_DOWAPBL) { |
|
/* |
|
* wapbl normally expects to be FS_WASCLEAN when the FS_DOWAPBL |
|
* bit is set, although there's a window in unmount where it |
|
* could be FS_ISCLEAN |
|
*/ |
|
if ((mp->mnt_flag & MNT_FORCE) == 0 && |
|
(fs->fs_clean & (FS_WASCLEAN | FS_ISCLEAN)) == 0) { |
|
error = EPERM; |
|
goto out; |
|
} |
|
} else |
|
if ((fs->fs_clean & FS_ISCLEAN) == 0 && |
|
(mp->mnt_flag & MNT_FORCE) == 0) { |
|
error = EPERM; |
|
goto out; |
|
} |
|
#endif |
|
|
/* |
/* |
* verify that we can access the last block in the fs |
* verify that we can access the last block in the fs |
* if we're mounting read/write. |
* if we're mounting read/write. |
Line 924 ffs_mountfs(struct vnode *devvp, struct |
|
Line 1083 ffs_mountfs(struct vnode *devvp, struct |
|
|
|
if (!ronly) { |
if (!ronly) { |
error = bread(devvp, fsbtodb(fs, fs->fs_size - 1), fs->fs_fsize, |
error = bread(devvp, fsbtodb(fs, fs->fs_size - 1), fs->fs_fsize, |
cred, &bp); |
cred, 0, &bp); |
if (bp->b_bcount != fs->fs_fsize) |
if (bp->b_bcount != fs->fs_fsize) |
error = EINVAL; |
error = EINVAL; |
if (error) { |
if (error) { |
Line 936 ffs_mountfs(struct vnode *devvp, struct |
|
Line 1095 ffs_mountfs(struct vnode *devvp, struct |
|
} |
} |
|
|
fs->fs_ronly = ronly; |
fs->fs_ronly = ronly; |
if (ronly == 0) { |
/* Don't bump fs_clean if we're replaying journal */ |
fs->fs_clean <<= 1; |
if (!((fs->fs_flags & FS_DOWAPBL) && (fs->fs_clean & FS_WASCLEAN))) |
fs->fs_fmod = 1; |
if (ronly == 0) { |
} |
fs->fs_clean <<= 1; |
|
fs->fs_fmod = 1; |
|
} |
size = fs->fs_cssize; |
size = fs->fs_cssize; |
blks = howmany(size, fs->fs_fsize); |
blks = howmany(size, fs->fs_fsize); |
if (fs->fs_contigsumsize > 0) |
if (fs->fs_contigsumsize > 0) |
Line 952 ffs_mountfs(struct vnode *devvp, struct |
|
Line 1113 ffs_mountfs(struct vnode *devvp, struct |
|
if (i + fs->fs_frag > blks) |
if (i + fs->fs_frag > blks) |
size = (blks - i) * fs->fs_fsize; |
size = (blks - i) * fs->fs_fsize; |
error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, |
error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, |
cred, &bp); |
cred, 0, &bp); |
if (error) { |
if (error) { |
free(fs->fs_csp, M_UFSMNT); |
free(fs->fs_csp, M_UFSMNT); |
goto out; |
goto out; |
Line 1025 ffs_mountfs(struct vnode *devvp, struct |
|
Line 1186 ffs_mountfs(struct vnode *devvp, struct |
|
for (i = 0; i < MAXQUOTAS; i++) |
for (i = 0; i < MAXQUOTAS; i++) |
ump->um_quotas[i] = NULLVP; |
ump->um_quotas[i] = NULLVP; |
devvp->v_specmountpoint = mp; |
devvp->v_specmountpoint = mp; |
if (ronly == 0 && (fs->fs_flags & FS_DOSOFTDEP)) { |
if (ronly == 0 && fs->fs_snapinum[0] != 0) |
error = softdep_mount(devvp, mp, fs, cred); |
ffs_snapshot_mount(mp); |
|
|
|
#ifdef WAPBL |
|
if (!ronly) { |
|
KDASSERT(fs->fs_ronly == 0); |
|
/* |
|
* ffs_wapbl_start() needs mp->mnt_stat initialised if it |
|
* needs to create a new log file in-filesystem. |
|
*/ |
|
ffs_statvfs(mp, &mp->mnt_stat); |
|
|
|
error = ffs_wapbl_start(mp); |
if (error) { |
if (error) { |
free(fs->fs_csp, M_UFSMNT); |
free(fs->fs_csp, M_UFSMNT); |
goto out; |
goto out; |
} |
} |
} |
} |
if (ronly == 0 && fs->fs_snapinum[0] != 0) |
#endif /* WAPBL */ |
ffs_snapshot_mount(mp); |
|
#ifdef UFS_EXTATTR |
#ifdef UFS_EXTATTR |
/* |
/* |
* Initialize file-backed extended attributes on UFS1 file |
* Initialize file-backed extended attributes on UFS1 file |
Line 1052 ffs_mountfs(struct vnode *devvp, struct |
|
Line 1223 ffs_mountfs(struct vnode *devvp, struct |
|
#endif /* UFS_EXTATTR */ |
#endif /* UFS_EXTATTR */ |
return (0); |
return (0); |
out: |
out: |
|
#ifdef WAPBL |
|
if (mp->mnt_wapbl_replay) { |
|
wapbl_replay_stop(mp->mnt_wapbl_replay); |
|
wapbl_replay_free(mp->mnt_wapbl_replay); |
|
mp->mnt_wapbl_replay = 0; |
|
} |
|
#endif |
|
|
fstrans_unmount(mp); |
fstrans_unmount(mp); |
if (fs) |
if (fs) |
free(fs, M_UFSMNT); |
free(fs, M_UFSMNT); |
Line 1112 ffs_oldfscompat_read(struct fs *fs, stru |
|
Line 1291 ffs_oldfscompat_read(struct fs *fs, stru |
|
fs->fs_csaddr = fs->fs_old_csaddr; |
fs->fs_csaddr = fs->fs_old_csaddr; |
fs->fs_sblockloc = sblockloc; |
fs->fs_sblockloc = sblockloc; |
|
|
fs->fs_flags = fs->fs_old_flags | (fs->fs_flags & FS_INTERNAL); |
fs->fs_flags = fs->fs_old_flags | (fs->fs_flags & FS_INTERNAL); |
|
|
if (fs->fs_old_postblformat == FS_42POSTBLFMT) { |
if (fs->fs_old_postblformat == FS_42POSTBLFMT) { |
fs->fs_old_nrpos = 8; |
fs->fs_old_nrpos = 8; |
Line 1192 ffs_unmount(struct mount *mp, int mntfla |
|
Line 1371 ffs_unmount(struct mount *mp, int mntfla |
|
struct lwp *l = curlwp; |
struct lwp *l = curlwp; |
struct ufsmount *ump = VFSTOUFS(mp); |
struct ufsmount *ump = VFSTOUFS(mp); |
struct fs *fs = ump->um_fs; |
struct fs *fs = ump->um_fs; |
int error, flags, penderr; |
int error, flags; |
|
#ifdef WAPBL |
|
extern int doforce; |
|
#endif |
|
|
penderr = 0; |
|
flags = 0; |
flags = 0; |
if (mntflags & MNT_FORCE) |
if (mntflags & MNT_FORCE) |
flags |= FORCECLOSE; |
flags |= FORCECLOSE; |
Line 1204 ffs_unmount(struct mount *mp, int mntfla |
|
Line 1385 ffs_unmount(struct mount *mp, int mntfla |
|
ufs_extattr_uepm_destroy(&ump->um_extattr); |
ufs_extattr_uepm_destroy(&ump->um_extattr); |
} |
} |
#endif /* UFS_EXTATTR */ |
#endif /* UFS_EXTATTR */ |
if (mp->mnt_flag & MNT_SOFTDEP) { |
if ((error = ffs_flushfiles(mp, flags, l)) != 0) |
if ((error = softdep_flushfiles(mp, flags, l)) != 0) |
return (error); |
return (error); |
error = UFS_WAPBL_BEGIN(mp); |
} else { |
if (error == 0) |
if ((error = ffs_flushfiles(mp, flags, l)) != 0) |
if (fs->fs_ronly == 0 && |
return (error); |
ffs_cgupdate(ump, MNT_WAIT) == 0 && |
} |
fs->fs_clean & FS_WASCLEAN) { |
mutex_enter(&ump->um_lock); |
|
if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) { |
|
printf("%s: unmount pending error: blocks %" PRId64 |
|
" files %d\n", |
|
fs->fs_fsmnt, fs->fs_pendingblocks, fs->fs_pendinginodes); |
|
fs->fs_pendingblocks = 0; |
|
fs->fs_pendinginodes = 0; |
|
penderr = 1; |
|
} |
|
mutex_exit(&ump->um_lock); |
|
if (fs->fs_ronly == 0 && |
|
ffs_cgupdate(ump, MNT_WAIT) == 0 && |
|
fs->fs_clean & FS_WASCLEAN) { |
|
/* |
|
* XXXX don't mark fs clean in the case of softdep |
|
* pending block errors, until they are fixed. |
|
*/ |
|
if (penderr == 0) { |
|
if (mp->mnt_flag & MNT_SOFTDEP) |
|
fs->fs_flags &= ~FS_DOSOFTDEP; |
|
fs->fs_clean = FS_ISCLEAN; |
fs->fs_clean = FS_ISCLEAN; |
|
fs->fs_fmod = 0; |
|
(void) ffs_sbupdate(ump, MNT_WAIT); |
} |
} |
fs->fs_fmod = 0; |
if (error == 0) |
(void) ffs_sbupdate(ump, MNT_WAIT); |
UFS_WAPBL_END(mp); |
|
#ifdef WAPBL |
|
KASSERT(!(mp->mnt_wapbl_replay && mp->mnt_wapbl)); |
|
if (mp->mnt_wapbl_replay) { |
|
KDASSERT(fs->fs_ronly); |
|
wapbl_replay_stop(mp->mnt_wapbl_replay); |
|
wapbl_replay_free(mp->mnt_wapbl_replay); |
|
mp->mnt_wapbl_replay = 0; |
} |
} |
|
error = ffs_wapbl_stop(mp, doforce && (mntflags & MNT_FORCE)); |
|
if (error) { |
|
return error; |
|
} |
|
#endif /* WAPBL */ |
if (ump->um_devvp->v_type != VBAD) |
if (ump->um_devvp->v_type != VBAD) |
ump->um_devvp->v_specmountpoint = NULL; |
ump->um_devvp->v_specmountpoint = NULL; |
vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); |
vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); |
(void)VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE, |
(void)VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD | FWRITE, |
NOCRED); |
NOCRED); |
vput(ump->um_devvp); |
vput(ump->um_devvp); |
free(fs->fs_csp, M_UFSMNT); |
free(fs->fs_csp, M_UFSMNT); |
free(fs, M_UFSMNT); |
free(fs, M_UFSMNT); |
if (ump->um_oldfscompat != NULL) |
if (ump->um_oldfscompat != NULL) |
free(ump->um_oldfscompat, M_UFSMNT); |
free(ump->um_oldfscompat, M_UFSMNT); |
softdep_unmount(mp); |
|
mutex_destroy(&ump->um_lock); |
mutex_destroy(&ump->um_lock); |
ffs_snapshot_fini(ump); |
ffs_snapshot_fini(ump); |
free(ump, M_UFSMNT); |
free(ump, M_UFSMNT); |
Line 1272 ffs_flushfiles(struct mount *mp, int fla |
|
Line 1446 ffs_flushfiles(struct mount *mp, int fla |
|
#ifdef QUOTA |
#ifdef QUOTA |
if (mp->mnt_flag & MNT_QUOTA) { |
if (mp->mnt_flag & MNT_QUOTA) { |
int i; |
int i; |
if ((error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) != 0) |
if ((error = vflush(mp, NULLVP, SKIPSYSTEM | flags)) != 0) |
return (error); |
return (error); |
for (i = 0; i < MAXQUOTAS; i++) { |
for (i = 0; i < MAXQUOTAS; i++) { |
if (ump->um_quotas[i] == NULLVP) |
if (ump->um_quotas[i] == NULLVP) |
Line 1300 ffs_flushfiles(struct mount *mp, int fla |
|
Line 1474 ffs_flushfiles(struct mount *mp, int fla |
|
vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); |
vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); |
error = VOP_FSYNC(ump->um_devvp, l->l_cred, FSYNC_WAIT, 0, 0); |
error = VOP_FSYNC(ump->um_devvp, l->l_cred, FSYNC_WAIT, 0, 0); |
VOP_UNLOCK(ump->um_devvp, 0); |
VOP_UNLOCK(ump->um_devvp, 0); |
|
if (flags & FORCECLOSE) /* XXXDBJ */ |
|
error = 0; |
|
|
|
#ifdef WAPBL |
|
if (error) |
|
return error; |
|
if (mp->mnt_wapbl) { |
|
error = wapbl_flush(mp->mnt_wapbl, 1); |
|
if (flags & FORCECLOSE) |
|
error = 0; |
|
} |
|
#endif |
|
|
return (error); |
return (error); |
} |
} |
|
|
Line 1320 ffs_statvfs(struct mount *mp, struct sta |
|
Line 1507 ffs_statvfs(struct mount *mp, struct sta |
|
sbp->f_iosize = fs->fs_bsize; |
sbp->f_iosize = fs->fs_bsize; |
sbp->f_blocks = fs->fs_dsize; |
sbp->f_blocks = fs->fs_dsize; |
sbp->f_bfree = blkstofrags(fs, fs->fs_cstotal.cs_nbfree) + |
sbp->f_bfree = blkstofrags(fs, fs->fs_cstotal.cs_nbfree) + |
fs->fs_cstotal.cs_nffree + dbtofsb(fs, fs->fs_pendingblocks); |
fs->fs_cstotal.cs_nffree + dbtofsb(fs, fs->fs_pendingblocks); |
sbp->f_bresvd = ((u_int64_t) fs->fs_dsize * (u_int64_t) |
sbp->f_bresvd = ((u_int64_t) fs->fs_dsize * (u_int64_t) |
fs->fs_minfree) / (u_int64_t) 100; |
fs->fs_minfree) / (u_int64_t) 100; |
if (sbp->f_bfree > sbp->f_bresvd) |
if (sbp->f_bfree > sbp->f_bresvd) |
Line 1347 ffs_statvfs(struct mount *mp, struct sta |
|
Line 1534 ffs_statvfs(struct mount *mp, struct sta |
|
int |
int |
ffs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) |
ffs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) |
{ |
{ |
struct lwp *l = curlwp; |
struct vnode *vp, *mvp, *nvp; |
struct vnode *vp, *mvp; |
|
struct inode *ip; |
struct inode *ip; |
struct ufsmount *ump = VFSTOUFS(mp); |
struct ufsmount *ump = VFSTOUFS(mp); |
struct fs *fs; |
struct fs *fs; |
int error, count, allerror = 0; |
int error, allerror = 0; |
|
|
fs = ump->um_fs; |
fs = ump->um_fs; |
if (fs->fs_fmod != 0 && fs->fs_ronly != 0) { /* XXX */ |
if (fs->fs_fmod != 0 && fs->fs_ronly != 0) { /* XXX */ |
|
|
* NOTE: not using the TAILQ_FOREACH here since in this loop vgone() |
* NOTE: not using the TAILQ_FOREACH here since in this loop vgone() |
* and vclean() can be called indirectly |
* and vclean() can be called indirectly |
*/ |
*/ |
for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) { |
for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = nvp) { |
vmark(mvp, vp); |
nvp = TAILQ_NEXT(vp, v_mntvnodes); |
/* |
/* |
* If the vnode that we are about to sync is no longer |
* If the vnode that we are about to sync is no longer |
* associated with this mount point, start over. |
* associated with this mount point, start over. |
*/ |
*/ |
if (vp->v_mount != mp || vismarker(vp)) |
if (vp->v_mount != mp) |
|
goto loop; |
|
/* |
|
* Don't interfere with concurrent scans of this FS. |
|
*/ |
|
if (vismarker(vp)) |
continue; |
continue; |
mutex_enter(&vp->v_interlock); |
mutex_enter(&vp->v_interlock); |
ip = VTOI(vp); |
ip = VTOI(vp); |
if (ip == NULL || (vp->v_iflag & (VI_XLOCK|VI_CLEAN)) != 0 || |
|
vp->v_type == VNON || ((ip->i_flag & |
/* |
(IN_CHANGE | IN_UPDATE | IN_MODIFIED)) == 0 && |
* Skip the vnode/inode if inaccessible. |
LIST_EMPTY(&vp->v_dirtyblkhd) && |
*/ |
UVM_OBJ_IS_CLEAN(&vp->v_uobj))) |
if (ip == NULL || (vp->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0 || |
{ |
vp->v_type == VNON) { |
|
mutex_exit(&vp->v_interlock); |
|
continue; |
|
} |
|
|
|
/* |
|
* We deliberately update inode times here. This will |
|
* prevent a massive queue of updates accumulating, only |
|
* to be handled by a call to unmount. |
|
* |
|
* XXX It would be better to have the syncer trickle these |
|
* out. Adjustment needed to allow registering vnodes for |
|
* sync when the vnode is clean, but the inode dirty. Or |
|
* have ufs itself trickle out inode updates. |
|
* |
|
* If doing a lazy sync, we don't care about metadata or |
|
* data updates, because they are handled by each vnode's |
|
* synclist entry. In this case we are only interested in |
|
* writing back modified inodes. |
|
*/ |
|
if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE | |
|
IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) == 0 && |
|
(waitfor == MNT_LAZY || (LIST_EMPTY(&vp->v_dirtyblkhd) && |
|
UVM_OBJ_IS_CLEAN(&vp->v_uobj)))) { |
mutex_exit(&vp->v_interlock); |
mutex_exit(&vp->v_interlock); |
continue; |
continue; |
} |
} |
|
|
mutex_exit(&vp->v_interlock); |
mutex_exit(&vp->v_interlock); |
continue; |
continue; |
} |
} |
|
vmark(mvp, vp); |
mutex_exit(&mntvnode_lock); |
mutex_exit(&mntvnode_lock); |
error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK); |
error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK); |
if (error) { |
if (error) { |
mutex_enter(&mntvnode_lock); |
mutex_enter(&mntvnode_lock); |
|
nvp = vunmark(mvp); |
if (error == ENOENT) { |
if (error == ENOENT) { |
(void)vunmark(mvp); |
|
goto loop; |
goto loop; |
} |
} |
continue; |
continue; |
} |
} |
if (vp->v_type == VREG && waitfor == MNT_LAZY) |
if (waitfor == MNT_LAZY) { |
error = ffs_update(vp, NULL, NULL, 0); |
error = UFS_WAPBL_BEGIN(vp->v_mount); |
else |
if (!error) { |
error = VOP_FSYNC(vp, cred, |
error = ffs_update(vp, NULL, NULL, |
waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0); |
UPDATE_CLOSE); |
|
UFS_WAPBL_END(vp->v_mount); |
|
} |
|
} else { |
|
error = VOP_FSYNC(vp, cred, FSYNC_NOLOG | |
|
(waitfor == MNT_WAIT ? FSYNC_WAIT : 0), 0, 0); |
|
} |
if (error) |
if (error) |
allerror = error; |
allerror = error; |
vput(vp); |
vput(vp); |
mutex_enter(&mntvnode_lock); |
mutex_enter(&mntvnode_lock); |
|
nvp = vunmark(mvp); |
} |
} |
mutex_exit(&mntvnode_lock); |
mutex_exit(&mntvnode_lock); |
/* |
/* |
* Force stale file system control information to be flushed. |
* Force stale file system control information to be flushed. |
*/ |
*/ |
if (waitfor == MNT_WAIT && (ump->um_mountp->mnt_flag & MNT_SOFTDEP)) { |
|
if ((error = softdep_flushworklist(ump->um_mountp, &count, l))) |
|
allerror = error; |
|
/* Flushed work items may create new vnodes to clean */ |
|
if (allerror == 0 && count) { |
|
mutex_enter(&mntvnode_lock); |
|
goto loop; |
|
} |
|
} |
|
if (waitfor != MNT_LAZY && (ump->um_devvp->v_numoutput > 0 || |
if (waitfor != MNT_LAZY && (ump->um_devvp->v_numoutput > 0 || |
!LIST_EMPTY(&ump->um_devvp->v_dirtyblkhd))) { |
!LIST_EMPTY(&ump->um_devvp->v_dirtyblkhd))) { |
vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); |
vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); |
if ((error = VOP_FSYNC(ump->um_devvp, cred, |
if ((error = VOP_FSYNC(ump->um_devvp, cred, |
waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0)) != 0) |
(waitfor == MNT_WAIT ? FSYNC_WAIT : 0) | FSYNC_NOLOG, |
|
0, 0)) != 0) |
allerror = error; |
allerror = error; |
VOP_UNLOCK(ump->um_devvp, 0); |
VOP_UNLOCK(ump->um_devvp, 0); |
if (allerror == 0 && waitfor == MNT_WAIT) { |
if (allerror == 0 && waitfor == MNT_WAIT && !mp->mnt_wapbl) { |
mutex_enter(&mntvnode_lock); |
mutex_enter(&mntvnode_lock); |
goto loop; |
goto loop; |
} |
} |
|
|
if (fs->fs_fmod != 0) { |
if (fs->fs_fmod != 0) { |
fs->fs_fmod = 0; |
fs->fs_fmod = 0; |
fs->fs_time = time_second; |
fs->fs_time = time_second; |
if ((error = ffs_cgupdate(ump, waitfor))) |
error = UFS_WAPBL_BEGIN(mp); |
|
if (error) |
|
allerror = error; |
|
else { |
|
if ((error = ffs_cgupdate(ump, waitfor))) |
|
allerror = error; |
|
UFS_WAPBL_END(mp); |
|
} |
|
} |
|
|
|
#ifdef WAPBL |
|
if (mp->mnt_wapbl) { |
|
error = wapbl_flush(mp->mnt_wapbl, 0); |
|
if (error) |
allerror = error; |
allerror = error; |
} |
} |
|
#endif |
|
|
fstrans_done(mp); |
fstrans_done(mp); |
vnfree(mvp); |
vnfree(mvp); |
return (allerror); |
return (allerror); |
Line 1504 ffs_vget(struct mount *mp, ino_t ino, st |
|
Line 1733 ffs_vget(struct mount *mp, ino_t ino, st |
|
} |
} |
|
|
vp->v_vflag |= VV_LOCKSWORK; |
vp->v_vflag |= VV_LOCKSWORK; |
if ((mp->mnt_flag & MNT_SOFTDEP) != 0) |
|
vp->v_uflag |= VU_SOFTDEP; |
|
|
|
/* |
/* |
* XXX MFS ends up here, too, to allocate an inode. Should we |
* XXX MFS ends up here, too, to allocate an inode. Should we |
Line 1519 ffs_vget(struct mount *mp, ino_t ino, st |
|
Line 1746 ffs_vget(struct mount *mp, ino_t ino, st |
|
ip->i_fs = fs = ump->um_fs; |
ip->i_fs = fs = ump->um_fs; |
ip->i_dev = dev; |
ip->i_dev = dev; |
ip->i_number = ino; |
ip->i_number = ino; |
LIST_INIT(&ip->i_pcbufhd); |
|
#ifdef QUOTA |
#ifdef QUOTA |
ufsquota_init(ip); |
ufsquota_init(ip); |
#endif |
#endif |
Line 1542 ffs_vget(struct mount *mp, ino_t ino, st |
|
Line 1768 ffs_vget(struct mount *mp, ino_t ino, st |
|
|
|
/* Read in the disk contents for the inode, copy into the inode. */ |
/* Read in the disk contents for the inode, copy into the inode. */ |
error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), |
error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), |
(int)fs->fs_bsize, NOCRED, &bp); |
(int)fs->fs_bsize, NOCRED, 0, &bp); |
if (error) { |
if (error) { |
|
|
/* |
/* |
Line 1564 ffs_vget(struct mount *mp, ino_t ino, st |
|
Line 1790 ffs_vget(struct mount *mp, ino_t ino, st |
|
ip->i_din.ffs2_din = pool_cache_get(ffs_dinode2_cache, |
ip->i_din.ffs2_din = pool_cache_get(ffs_dinode2_cache, |
PR_WAITOK); |
PR_WAITOK); |
ffs_load_inode(bp, ip, fs, ino); |
ffs_load_inode(bp, ip, fs, ino); |
if (DOINGSOFTDEP(vp)) |
|
softdep_load_inodeblock(ip); |
|
else |
|
ip->i_ffs_effnlink = ip->i_nlink; |
|
brelse(bp, 0); |
brelse(bp, 0); |
|
|
/* |
/* |
|
|
"ffsdino1", NULL, IPL_NONE, NULL, NULL, NULL); |
"ffsdino1", NULL, IPL_NONE, NULL, NULL, NULL); |
ffs_dinode2_cache = pool_cache_init(sizeof(struct ufs2_dinode), 0, 0, 0, |
ffs_dinode2_cache = pool_cache_init(sizeof(struct ufs2_dinode), 0, 0, 0, |
"ffsdino2", NULL, IPL_NONE, NULL, NULL, NULL); |
"ffsdino2", NULL, IPL_NONE, NULL, NULL, NULL); |
softdep_initialize(); |
|
ufs_init(); |
ufs_init(); |
} |
} |
|
|
void |
void |
ffs_reinit(void) |
ffs_reinit(void) |
{ |
{ |
softdep_reinitialize(); |
|
ufs_reinit(); |
ufs_reinit(); |
} |
} |
|
|
|
|
if (--ffs_initcount > 0) |
if (--ffs_initcount > 0) |
return; |
return; |
|
|
/* XXX softdep cleanup ? */ |
|
ufs_done(); |
ufs_done(); |
pool_cache_destroy(ffs_dinode2_cache); |
pool_cache_destroy(ffs_dinode2_cache); |
pool_cache_destroy(ffs_dinode1_cache); |
pool_cache_destroy(ffs_dinode1_cache); |
pool_cache_destroy(ffs_inode_cache); |
pool_cache_destroy(ffs_inode_cache); |
} |
} |
|
|
SYSCTL_SETUP(sysctl_vfs_ffs_setup, "sysctl vfs.ffs subtree setup") |
|
{ |
|
#if 0 |
|
extern int doasyncfree; |
|
#endif |
|
extern int ffs_log_changeopt; |
|
|
|
sysctl_createv(clog, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT, |
|
CTLTYPE_NODE, "vfs", NULL, |
|
NULL, 0, NULL, 0, |
|
CTL_VFS, CTL_EOL); |
|
sysctl_createv(clog, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT, |
|
CTLTYPE_NODE, "ffs", |
|
SYSCTL_DESCR("Berkeley Fast File System"), |
|
NULL, 0, NULL, 0, |
|
CTL_VFS, 1, CTL_EOL); |
|
|
|
/* |
|
* @@@ should we even bother with these first three? |
|
*/ |
|
sysctl_createv(clog, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
|
CTLTYPE_INT, "doclusterread", NULL, |
|
sysctl_notavail, 0, NULL, 0, |
|
CTL_VFS, 1, FFS_CLUSTERREAD, CTL_EOL); |
|
sysctl_createv(clog, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
|
CTLTYPE_INT, "doclusterwrite", NULL, |
|
sysctl_notavail, 0, NULL, 0, |
|
CTL_VFS, 1, FFS_CLUSTERWRITE, CTL_EOL); |
|
sysctl_createv(clog, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
|
CTLTYPE_INT, "doreallocblks", NULL, |
|
sysctl_notavail, 0, NULL, 0, |
|
CTL_VFS, 1, FFS_REALLOCBLKS, CTL_EOL); |
|
#if 0 |
|
sysctl_createv(clog, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
|
CTLTYPE_INT, "doasyncfree", |
|
SYSCTL_DESCR("Release dirty blocks asynchronously"), |
|
NULL, 0, &doasyncfree, 0, |
|
CTL_VFS, 1, FFS_ASYNCFREE, CTL_EOL); |
|
#endif |
|
sysctl_createv(clog, 0, NULL, NULL, |
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
|
CTLTYPE_INT, "log_changeopt", |
|
SYSCTL_DESCR("Log changes in optimization strategy"), |
|
NULL, 0, &ffs_log_changeopt, 0, |
|
CTL_VFS, 1, FFS_LOG_CHANGEOPT, CTL_EOL); |
|
} |
|
|
|
/* |
/* |
* Write a superblock and associated information back to disk. |
* Write a superblock and associated information back to disk. |
*/ |
*/ |
Line 1749 ffs_sbupdate(struct ufsmount *mp, int wa |
|
Line 1916 ffs_sbupdate(struct ufsmount *mp, int wa |
|
int error = 0; |
int error = 0; |
u_int32_t saveflag; |
u_int32_t saveflag; |
|
|
bp = getblk(mp->um_devvp, |
error = ffs_getblk(mp->um_devvp, |
fs->fs_sblockloc >> (fs->fs_fshift - fs->fs_fsbtodb), |
fs->fs_sblockloc >> (fs->fs_fshift - fs->fs_fsbtodb), FFS_NOBLK, |
(int)fs->fs_sbsize, 0, 0); |
fs->fs_sbsize, false, &bp); |
|
if (error) |
|
return error; |
saveflag = fs->fs_flags & FS_INTERNAL; |
saveflag = fs->fs_flags & FS_INTERNAL; |
fs->fs_flags &= ~FS_INTERNAL; |
fs->fs_flags &= ~FS_INTERNAL; |
|
|
Line 1787 ffs_cgupdate(struct ufsmount *mp, int wa |
|
Line 1956 ffs_cgupdate(struct ufsmount *mp, int wa |
|
size = fs->fs_bsize; |
size = fs->fs_bsize; |
if (i + fs->fs_frag > blks) |
if (i + fs->fs_frag > blks) |
size = (blks - i) * fs->fs_fsize; |
size = (blks - i) * fs->fs_fsize; |
bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), |
error = ffs_getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), |
size, 0, 0); |
FFS_NOBLK, size, false, &bp); |
|
if (error) |
|
break; |
#ifdef FFS_EI |
#ifdef FFS_EI |
if (mp->um_flags & UFS_NEEDSWAP) |
if (mp->um_flags & UFS_NEEDSWAP) |
ffs_csum_swap((struct csum*)space, |
ffs_csum_swap((struct csum*)space, |
Line 1835 ffs_suspendctl(struct mount *mp, int cmd |
|
Line 2006 ffs_suspendctl(struct mount *mp, int cmd |
|
error = ffs_sync(mp, MNT_WAIT, l->l_proc->p_cred); |
error = ffs_sync(mp, MNT_WAIT, l->l_proc->p_cred); |
if (error == 0) |
if (error == 0) |
error = fstrans_setstate(mp, FSTRANS_SUSPENDED); |
error = fstrans_setstate(mp, FSTRANS_SUSPENDED); |
|
#ifdef WAPBL |
|
if (error == 0 && mp->mnt_wapbl) |
|
error = wapbl_flush(mp->mnt_wapbl, 1); |
|
#endif |
if (error != 0) { |
if (error != 0) { |
(void) fstrans_setstate(mp, FSTRANS_NORMAL); |
(void) fstrans_setstate(mp, FSTRANS_NORMAL); |
return error; |
return error; |
Line 1848 ffs_suspendctl(struct mount *mp, int cmd |
|
Line 2023 ffs_suspendctl(struct mount *mp, int cmd |
|
return EINVAL; |
return EINVAL; |
} |
} |
} |
} |
|
|
|
/* |
|
* Synch vnode for a mounted file system. This is called for foreign |
|
* vnodes, i.e. non-ffs. |
|
*/ |
|
static int |
|
ffs_vfs_fsync(vnode_t *vp, int flags) |
|
{ |
|
int error, passes, skipmeta, i, pflags; |
|
buf_t *bp, *nbp; |
|
#ifdef WAPBL |
|
struct mount *mp; |
|
#endif |
|
|
|
KASSERT(vp->v_type == VBLK); |
|
KASSERT(vp->v_specmountpoint != NULL); |
|
|
|
/* |
|
* Flush all dirty data associated with the vnode. |
|
*/ |
|
pflags = PGO_ALLPAGES | PGO_CLEANIT; |
|
if ((flags & FSYNC_WAIT) != 0) |
|
pflags |= PGO_SYNCIO; |
|
mutex_enter(&vp->v_interlock); |
|
error = VOP_PUTPAGES(vp, 0, 0, pflags); |
|
if (error) |
|
return error; |
|
|
|
#ifdef WAPBL |
|
mp = vp->v_specmountpoint; |
|
if (mp && mp->mnt_wapbl) { |
|
/* |
|
* Don't bother writing out metadata if the syncer is |
|
* making the request. We will let the sync vnode |
|
* write it out in a single burst through a call to |
|
* VFS_SYNC(). |
|
*/ |
|
if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY | FSYNC_NOLOG)) != 0) |
|
return 0; |
|
|
|
/* |
|
* Don't flush the log if the vnode being flushed |
|
* contains no dirty buffers that could be in the log. |
|
*/ |
|
if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { |
|
error = wapbl_flush(mp->mnt_wapbl, 0); |
|
if (error) |
|
return error; |
|
} |
|
|
|
if ((flags & FSYNC_WAIT) != 0) { |
|
mutex_enter(&vp->v_interlock); |
|
while (vp->v_numoutput) |
|
cv_wait(&vp->v_cv, &vp->v_interlock); |
|
mutex_exit(&vp->v_interlock); |
|
} |
|
|
|
return 0; |
|
} |
|
#endif /* WAPBL */ |
|
|
|
/* |
|
* Write out metadata for non-logging file systems. XXX This block |
|
* should be simplified now that softdep is gone. |
|
*/ |
|
passes = NIADDR + 1; |
|
skipmeta = 0; |
|
if (flags & FSYNC_WAIT) |
|
skipmeta = 1; |
|
|
|
loop: |
|
mutex_enter(&bufcache_lock); |
|
LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) { |
|
bp->b_cflags &= ~BC_SCANNED; |
|
} |
|
for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { |
|
nbp = LIST_NEXT(bp, b_vnbufs); |
|
if (bp->b_cflags & (BC_BUSY | BC_SCANNED)) |
|
continue; |
|
if ((bp->b_oflags & BO_DELWRI) == 0) |
|
panic("ffs_fsync: not dirty"); |
|
if (skipmeta && bp->b_lblkno < 0) |
|
continue; |
|
bp->b_cflags |= BC_BUSY | BC_VFLUSH | BC_SCANNED; |
|
mutex_exit(&bufcache_lock); |
|
/* |
|
* On our final pass through, do all I/O synchronously |
|
* so that we can find out if our flush is failing |
|
* because of write errors. |
|
*/ |
|
if (passes > 0 || !(flags & FSYNC_WAIT)) |
|
(void) bawrite(bp); |
|
else if ((error = bwrite(bp)) != 0) |
|
return (error); |
|
/* |
|
* Since we unlocked during the I/O, we need |
|
* to start from a known point. |
|
*/ |
|
mutex_enter(&bufcache_lock); |
|
nbp = LIST_FIRST(&vp->v_dirtyblkhd); |
|
} |
|
mutex_exit(&bufcache_lock); |
|
if (skipmeta) { |
|
skipmeta = 0; |
|
goto loop; |
|
} |
|
|
|
if ((flags & FSYNC_WAIT) != 0) { |
|
mutex_enter(&vp->v_interlock); |
|
while (vp->v_numoutput) { |
|
cv_wait(&vp->v_cv, &vp->v_interlock); |
|
} |
|
mutex_exit(&vp->v_interlock); |
|
|
|
if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { |
|
/* |
|
* Block devices associated with filesystems may |
|
* have new I/O requests posted for them even if |
|
* the vnode is locked, so no amount of trying will |
|
* get them clean. Thus we give block devices a |
|
* good effort, then just give up. For all other file |
|
* types, go around and try again until it is clean. |
|
*/ |
|
if (passes > 0) { |
|
passes--; |
|
goto loop; |
|
} |
|
#ifdef DIAGNOSTIC |
|
if (vp->v_type != VBLK) |
|
vprint("ffs_fsync: dirty", vp); |
|
#endif |
|
} |
|
} |
|
|
|
if (error == 0 && (flags & FSYNC_CACHE) != 0) { |
|
(void)VOP_IOCTL(vp, DIOCCACHESYNC, &i, FWRITE, |
|
kauth_cred_get()); |
|
} |
|
|
|
return error; |
|
} |