Annotation of src/sys/ufs/ffs/ffs_vfsops.c, Revision 1.223.4.2
1.223.4.2! yamt 1: /* $NetBSD: ffs_vfsops.c,v 1.223.4.1 2008/05/16 02:26:00 yamt Exp $ */
! 2:
! 3: /*-
! 4: * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
! 5: * All rights reserved.
! 6: *
! 7: * This code is derived from software contributed to The NetBSD Foundation
! 8: * by Wasabi Systems, Inc, and by Andrew Doran.
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: *
! 19: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 21: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 22: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 23: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 24: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 25: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 26: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 27: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 28: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 29: * POSSIBILITY OF SUCH DAMAGE.
! 30: */
1.4 cgd 31:
1.1 mycroft 32: /*
33: * Copyright (c) 1989, 1991, 1993, 1994
34: * The Regents of the University of California. All rights reserved.
35: *
36: * Redistribution and use in source and binary forms, with or without
37: * modification, are permitted provided that the following conditions
38: * are met:
39: * 1. Redistributions of source code must retain the above copyright
40: * notice, this list of conditions and the following disclaimer.
41: * 2. Redistributions in binary form must reproduce the above copyright
42: * notice, this list of conditions and the following disclaimer in the
43: * documentation and/or other materials provided with the distribution.
1.119 agc 44: * 3. Neither the name of the University nor the names of its contributors
1.1 mycroft 45: * may be used to endorse or promote products derived from this software
46: * without specific prior written permission.
47: *
48: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58: * SUCH DAMAGE.
59: *
1.33 fvdl 60: * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95
1.1 mycroft 61: */
1.88 lukem 62:
63: #include <sys/cdefs.h>
1.223.4.2! yamt 64: __KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.223.4.1 2008/05/16 02:26:00 yamt Exp $");
1.36 scottr 65:
1.81 mrg 66: #if defined(_KERNEL_OPT)
1.45 thorpej 67: #include "opt_ffs.h"
1.36 scottr 68: #include "opt_quota.h"
1.223.4.2! yamt 69: #include "opt_wapbl.h"
1.37 scottr 70: #endif
1.1 mycroft 71:
72: #include <sys/param.h>
73: #include <sys/systm.h>
74: #include <sys/namei.h>
75: #include <sys/proc.h>
76: #include <sys/kernel.h>
77: #include <sys/vnode.h>
78: #include <sys/socket.h>
79: #include <sys/mount.h>
80: #include <sys/buf.h>
1.23 thorpej 81: #include <sys/device.h>
1.1 mycroft 82: #include <sys/mbuf.h>
83: #include <sys/file.h>
84: #include <sys/disklabel.h>
85: #include <sys/ioctl.h>
86: #include <sys/errno.h>
87: #include <sys/malloc.h>
1.43 thorpej 88: #include <sys/pool.h>
1.29 fvdl 89: #include <sys/lock.h>
1.33 fvdl 90: #include <sys/sysctl.h>
1.101 gehenna 91: #include <sys/conf.h>
1.181 elad 92: #include <sys/kauth.h>
1.223.4.2! yamt 93: #include <sys/wapbl.h>
1.193 hannken 94: #include <sys/fstrans.h>
1.223.4.1 yamt 95: #include <sys/module.h>
1.1 mycroft 96:
1.221 dholland 97: #include <miscfs/genfs/genfs.h>
1.1 mycroft 98: #include <miscfs/specfs/specdev.h>
99:
100: #include <ufs/ufs/quota.h>
101: #include <ufs/ufs/ufsmount.h>
102: #include <ufs/ufs/inode.h>
1.25 bouyer 103: #include <ufs/ufs/dir.h>
1.1 mycroft 104: #include <ufs/ufs/ufs_extern.h>
1.34 bouyer 105: #include <ufs/ufs/ufs_bswap.h>
1.223.4.2! yamt 106: #include <ufs/ufs/ufs_wapbl.h>
1.1 mycroft 107:
108: #include <ufs/ffs/fs.h>
109: #include <ufs/ffs/ffs_extern.h>
110:
1.223.4.1 yamt 111: MODULE(MODULE_CLASS_VFS, ffs, NULL);
112:
1.223.4.2! yamt 113: static int ffs_vfs_fsync(vnode_t *, int);
! 114:
! 115: static struct sysctllog *ffs_sysctl_log;
! 116:
1.59 jdolecek 117: /* how many times ffs_init() was called */
118: int ffs_initcount = 0;
119:
1.195 ad 120: extern kmutex_t ufs_hashlock;
1.29 fvdl 121:
1.105 matt 122: extern const struct vnodeopv_desc ffs_vnodeop_opv_desc;
123: extern const struct vnodeopv_desc ffs_specop_opv_desc;
124: extern const struct vnodeopv_desc ffs_fifoop_opv_desc;
1.32 thorpej 125:
1.79 jdolecek 126: const struct vnodeopv_desc * const ffs_vnodeopv_descs[] = {
1.32 thorpej 127: &ffs_vnodeop_opv_desc,
128: &ffs_specop_opv_desc,
129: &ffs_fifoop_opv_desc,
130: NULL,
131: };
132:
1.17 mycroft 133: struct vfsops ffs_vfsops = {
134: MOUNT_FFS,
1.204 dsl 135: sizeof (struct ufs_args),
1.1 mycroft 136: ffs_mount,
137: ufs_start,
138: ffs_unmount,
139: ufs_root,
140: ufs_quotactl,
1.143 christos 141: ffs_statvfs,
1.1 mycroft 142: ffs_sync,
143: ffs_vget,
144: ffs_fhtovp,
145: ffs_vptofh,
146: ffs_init,
1.86 chs 147: ffs_reinit,
1.59 jdolecek 148: ffs_done,
1.23 thorpej 149: ffs_mountroot,
1.149 hannken 150: ffs_snapshot,
1.170 thorpej 151: ffs_extattrctl,
1.193 hannken 152: ffs_suspendctl,
1.221 dholland 153: genfs_renamelock_enter,
154: genfs_renamelock_exit,
1.223.4.2! yamt 155: ffs_vfs_fsync,
1.32 thorpej 156: ffs_vnodeopv_descs,
1.185 christos 157: 0,
158: { NULL, NULL },
1.1 mycroft 159: };
160:
1.165 yamt 161: static const struct genfs_ops ffs_genfsops = {
162: .gop_size = ffs_gop_size,
163: .gop_alloc = ufs_gop_alloc,
164: .gop_write = genfs_gop_write,
1.167 yamt 165: .gop_markupdate = ufs_gop_markupdate,
1.87 chs 166: };
167:
1.175 yamt 168: static const struct ufs_ops ffs_ufsops = {
169: .uo_itimes = ffs_itimes,
1.176 yamt 170: .uo_update = ffs_update,
171: .uo_truncate = ffs_truncate,
172: .uo_valloc = ffs_valloc,
173: .uo_vfree = ffs_vfree,
174: .uo_balloc = ffs_balloc,
1.223.4.2! yamt 175: .uo_unmark_vnode = (void (*)(vnode_t *))nullop,
1.175 yamt 176: };
177:
1.223.4.1 yamt 178: static int
179: ffs_modcmd(modcmd_t cmd, void *arg)
180: {
1.223.4.2! yamt 181: int error;
! 182:
! 183: #if 0
! 184: extern int doasyncfree;
! 185: #endif
! 186: extern int ffs_log_changeopt;
1.223.4.1 yamt 187:
188: switch (cmd) {
189: case MODULE_CMD_INIT:
1.223.4.2! yamt 190: error = vfs_attach(&ffs_vfsops);
! 191: if (error != 0)
! 192: break;
! 193:
! 194: sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL,
! 195: CTLFLAG_PERMANENT,
! 196: CTLTYPE_NODE, "vfs", NULL,
! 197: NULL, 0, NULL, 0,
! 198: CTL_VFS, CTL_EOL);
! 199: sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL,
! 200: CTLFLAG_PERMANENT,
! 201: CTLTYPE_NODE, "ffs",
! 202: SYSCTL_DESCR("Berkeley Fast File System"),
! 203: NULL, 0, NULL, 0,
! 204: CTL_VFS, 1, CTL_EOL);
! 205:
! 206: /*
! 207: * @@@ should we even bother with these first three?
! 208: */
! 209: sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL,
! 210: CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
! 211: CTLTYPE_INT, "doclusterread", NULL,
! 212: sysctl_notavail, 0, NULL, 0,
! 213: CTL_VFS, 1, FFS_CLUSTERREAD, CTL_EOL);
! 214: sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL,
! 215: CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
! 216: CTLTYPE_INT, "doclusterwrite", NULL,
! 217: sysctl_notavail, 0, NULL, 0,
! 218: CTL_VFS, 1, FFS_CLUSTERWRITE, CTL_EOL);
! 219: sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL,
! 220: CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
! 221: CTLTYPE_INT, "doreallocblks", NULL,
! 222: sysctl_notavail, 0, NULL, 0,
! 223: CTL_VFS, 1, FFS_REALLOCBLKS, CTL_EOL);
! 224: #if 0
! 225: sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL,
! 226: CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
! 227: CTLTYPE_INT, "doasyncfree",
! 228: SYSCTL_DESCR("Release dirty blocks asynchronously"),
! 229: NULL, 0, &doasyncfree, 0,
! 230: CTL_VFS, 1, FFS_ASYNCFREE, CTL_EOL);
! 231: #endif
! 232: sysctl_createv(&ffs_sysctl_log, 0, NULL, NULL,
! 233: CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
! 234: CTLTYPE_INT, "log_changeopt",
! 235: SYSCTL_DESCR("Log changes in optimization strategy"),
! 236: NULL, 0, &ffs_log_changeopt, 0,
! 237: CTL_VFS, 1, FFS_LOG_CHANGEOPT, CTL_EOL);
! 238: break;
1.223.4.1 yamt 239: case MODULE_CMD_FINI:
1.223.4.2! yamt 240: error = vfs_detach(&ffs_vfsops);
! 241: if (error != 0)
! 242: break;
! 243: sysctl_teardown(&ffs_sysctl_log);
! 244: break;
1.223.4.1 yamt 245: default:
1.223.4.2! yamt 246: error = ENOTTY;
! 247: break;
1.223.4.1 yamt 248: }
1.223.4.2! yamt 249:
! 250: return (error);
1.223.4.1 yamt 251: }
252:
1.216 ad 253: pool_cache_t ffs_inode_cache;
254: pool_cache_t ffs_dinode1_cache;
255: pool_cache_t ffs_dinode2_cache;
1.110 fvdl 256:
1.146 simonb 257: static void ffs_oldfscompat_read(struct fs *, struct ufsmount *, daddr_t);
1.110 fvdl 258: static void ffs_oldfscompat_write(struct fs *, struct ufsmount *);
1.43 thorpej 259:
1.1 mycroft 260: /*
1.33 fvdl 261: * Called by main() when ffs is going to be mounted as root.
1.1 mycroft 262: */
263:
1.19 christos 264: int
1.166 thorpej 265: ffs_mountroot(void)
1.1 mycroft 266: {
1.33 fvdl 267: struct fs *fs;
268: struct mount *mp;
1.177 christos 269: struct lwp *l = curlwp; /* XXX */
1.1 mycroft 270: struct ufsmount *ump;
271: int error;
1.23 thorpej 272:
1.180 thorpej 273: if (device_class(root_device) != DV_DISK)
1.23 thorpej 274: return (ENODEV);
275:
1.51 wrstuden 276: if ((error = vfs_rootmountalloc(MOUNT_FFS, "root_device", &mp))) {
277: vrele(rootvp);
1.33 fvdl 278: return (error);
1.51 wrstuden 279: }
1.223.4.2! yamt 280:
! 281: /*
! 282: * We always need to be able to mount the root file system.
! 283: */
! 284: mp->mnt_flag |= MNT_FORCE;
1.177 christos 285: if ((error = ffs_mountfs(rootvp, mp, l)) != 0) {
1.223.4.1 yamt 286: vfs_unbusy(mp, false, NULL);
1.210 ad 287: vfs_destroy(mp);
1.1 mycroft 288: return (error);
289: }
1.223.4.2! yamt 290: mp->mnt_flag &= ~MNT_FORCE;
1.210 ad 291: mutex_enter(&mountlist_lock);
1.11 mycroft 292: CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
1.210 ad 293: mutex_exit(&mountlist_lock);
1.1 mycroft 294: ump = VFSTOUFS(mp);
295: fs = ump->um_fs;
1.42 perry 296: memset(fs->fs_fsmnt, 0, sizeof(fs->fs_fsmnt));
1.33 fvdl 297: (void)copystr(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN - 1, 0);
1.211 pooka 298: (void)ffs_statvfs(mp, &mp->mnt_stat);
1.223.4.1 yamt 299: vfs_unbusy(mp, false, NULL);
1.151 pk 300: setrootfstime((time_t)fs->fs_time);
1.1 mycroft 301: return (0);
302: }
303:
304: /*
305: * VFS Operations.
306: *
307: * mount system call
308: */
309: int
1.211 pooka 310: ffs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
1.1 mycroft 311: {
1.211 pooka 312: struct lwp *l = curlwp;
1.207 pooka 313: struct nameidata nd;
1.223.4.2! yamt 314: struct vnode *devvp = NULL;
1.204 dsl 315: struct ufs_args *args = data;
1.19 christos 316: struct ufsmount *ump = NULL;
1.61 augustss 317: struct fs *fs;
1.204 dsl 318: int error = 0, flags, update;
1.9 mycroft 319: mode_t accessmode;
1.1 mycroft 320:
1.204 dsl 321: if (*data_len < sizeof *args)
322: return EINVAL;
323:
1.102 christos 324: if (mp->mnt_flag & MNT_GETARGS) {
325: ump = VFSTOUFS(mp);
326: if (ump == NULL)
327: return EIO;
1.204 dsl 328: args->fspec = NULL;
329: *data_len = sizeof *args;
330: return 0;
1.102 christos 331: }
1.66 matt 332:
1.95 christos 333: update = mp->mnt_flag & MNT_UPDATE;
334:
335: /* Check arguments */
1.204 dsl 336: if (args->fspec != NULL) {
1.95 christos 337: /*
338: * Look up the name and verify that it's sane.
339: */
1.212 pooka 340: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, args->fspec);
1.207 pooka 341: if ((error = namei(&nd)) != 0)
1.95 christos 342: return (error);
1.207 pooka 343: devvp = nd.ni_vp;
1.95 christos 344:
345: if (!update) {
346: /*
347: * Be sure this is a valid block device
348: */
349: if (devvp->v_type != VBLK)
350: error = ENOTBLK;
1.101 gehenna 351: else if (bdevsw_lookup(devvp->v_rdev) == NULL)
1.95 christos 352: error = ENXIO;
353: } else {
354: /*
355: * Be sure we're still naming the same device
356: * used for our initial mount
357: */
1.160 mycroft 358: ump = VFSTOUFS(mp);
1.186 jld 359: if (devvp != ump->um_devvp) {
360: if (devvp->v_rdev != ump->um_devvp->v_rdev)
361: error = EINVAL;
362: else {
363: vrele(devvp);
364: devvp = ump->um_devvp;
365: vref(devvp);
366: }
367: }
1.95 christos 368: }
1.160 mycroft 369: } else {
370: if (!update) {
371: /* New mounts must have a filename for the device */
372: return (EINVAL);
373: } else {
374: /* Use the extant mount */
375: ump = VFSTOUFS(mp);
376: devvp = ump->um_devvp;
377: vref(devvp);
378: }
1.95 christos 379: }
1.218 ad 380:
381: /*
1.95 christos 382: * If mount by non-root, then verify that user has necessary
383: * permissions on the device.
1.223.4.2! yamt 384: *
! 385: * Permission to update a mount is checked higher, so here we presume
! 386: * updating the mount is okay (for example, as far as securelevel goes)
! 387: * which leaves us with the normal check.
! 388: */
! 389: accessmode = VREAD;
! 390: if (update ?
! 391: (mp->mnt_iflag & IMNT_WANTRDWR) != 0 :
! 392: (mp->mnt_flag & MNT_RDONLY) == 0)
! 393: accessmode |= VWRITE;
! 394: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
! 395: error = genfs_can_mount(devvp, accessmode, l->l_cred);
! 396: VOP_UNLOCK(devvp, 0);
1.95 christos 397:
398: if (error) {
399: vrele(devvp);
400: return (error);
401: }
402:
1.223.4.2! yamt 403: #ifdef WAPBL
! 404: /* WAPBL can only be enabled on a r/w mount. */
! 405: if ((mp->mnt_flag & MNT_RDONLY) && !(mp->mnt_iflag & IMNT_WANTRDWR)) {
! 406: mp->mnt_flag &= ~MNT_LOG;
! 407: }
! 408: #else /* !WAPBL */
! 409: mp->mnt_flag &= ~MNT_LOG;
! 410: #endif /* !WAPBL */
! 411:
1.95 christos 412: if (!update) {
1.164 christos 413: int xflags;
1.159 mycroft 414:
415: if (mp->mnt_flag & MNT_RDONLY)
1.164 christos 416: xflags = FREAD;
1.159 mycroft 417: else
1.223.4.2! yamt 418: xflags = FREAD | FWRITE;
1.211 pooka 419: error = VOP_OPEN(devvp, xflags, FSCRED);
1.159 mycroft 420: if (error)
421: goto fail;
1.177 christos 422: error = ffs_mountfs(devvp, mp, l);
1.95 christos 423: if (error) {
1.159 mycroft 424: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1.211 pooka 425: (void)VOP_CLOSE(devvp, xflags, NOCRED);
1.159 mycroft 426: VOP_UNLOCK(devvp, 0);
427: goto fail;
1.95 christos 428: }
429:
1.1 mycroft 430: ump = VFSTOUFS(mp);
431: fs = ump->um_fs;
1.95 christos 432: } else {
433: /*
1.96 christos 434: * Update the mount.
435: */
436:
437: /*
438: * The initial mount got a reference on this
439: * device, so drop the one obtained via
440: * namei(), above.
1.95 christos 441: */
1.96 christos 442: vrele(devvp);
443:
1.160 mycroft 444: ump = VFSTOUFS(mp);
1.95 christos 445: fs = ump->um_fs;
1.1 mycroft 446: if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
1.95 christos 447: /*
448: * Changing from r/w to r/o
449: */
1.1 mycroft 450: flags = WRITECLOSE;
451: if (mp->mnt_flag & MNT_FORCE)
452: flags |= FORCECLOSE;
1.223.4.2! yamt 453: error = ffs_flushfiles(mp, flags, l);
! 454: if (error == 0)
! 455: error = UFS_WAPBL_BEGIN(mp);
1.15 mycroft 456: if (error == 0 &&
457: ffs_cgupdate(ump, MNT_WAIT) == 0 &&
458: fs->fs_clean & FS_WASCLEAN) {
1.65 fvdl 459: if (mp->mnt_flag & MNT_SOFTDEP)
460: fs->fs_flags &= ~FS_DOSOFTDEP;
1.15 mycroft 461: fs->fs_clean = FS_ISCLEAN;
462: (void) ffs_sbupdate(ump, MNT_WAIT);
463: }
1.223.4.2! yamt 464: if (error == 0)
! 465: UFS_WAPBL_END(mp);
1.15 mycroft 466: if (error)
467: return (error);
1.1 mycroft 468: }
1.65 fvdl 469:
1.223.4.2! yamt 470: #ifdef WAPBL
! 471: if ((mp->mnt_flag & MNT_LOG) == 0) {
! 472: error = ffs_wapbl_stop(mp, mp->mnt_flag & MNT_FORCE);
! 473: if (error)
! 474: return error;
1.65 fvdl 475: }
1.223.4.2! yamt 476: #endif /* WAPBL */
1.65 fvdl 477:
1.223.4.2! yamt 478: if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
! 479: /*
! 480: * Finish change from r/w to r/o
! 481: */
! 482: fs->fs_ronly = 1;
! 483: fs->fs_fmod = 0;
1.65 fvdl 484: }
485:
1.15 mycroft 486: if (mp->mnt_flag & MNT_RELOAD) {
1.184 ad 487: error = ffs_reload(mp, l->l_cred, l);
1.15 mycroft 488: if (error)
489: return (error);
490: }
1.95 christos 491:
1.124 dbj 492: if (fs->fs_ronly && (mp->mnt_iflag & IMNT_WANTRDWR)) {
1.9 mycroft 493: /*
1.95 christos 494: * Changing from read-only to read/write
1.9 mycroft 495: */
1.1 mycroft 496: fs->fs_ronly = 0;
1.15 mycroft 497: fs->fs_clean <<= 1;
498: fs->fs_fmod = 1;
1.223.4.2! yamt 499: #ifdef WAPBL
! 500: if (fs->fs_flags & FS_DOWAPBL) {
! 501: printf("%s: replaying log to disk\n",
! 502: fs->fs_fsmnt);
! 503: KDASSERT(mp->mnt_wapbl_replay);
! 504: error = wapbl_replay_write(mp->mnt_wapbl_replay,
! 505: devvp);
! 506: if (error) {
! 507: return error;
! 508: }
! 509: wapbl_replay_stop(mp->mnt_wapbl_replay);
! 510: fs->fs_clean = FS_WASCLEAN;
1.65 fvdl 511: }
1.223.4.2! yamt 512: #endif /* WAPBL */
1.149 hannken 513: if (fs->fs_snapinum[0] != 0)
514: ffs_snapshot_mount(mp);
1.9 mycroft 515: }
1.223.4.2! yamt 516:
! 517: #ifdef WAPBL
! 518: error = ffs_wapbl_start(mp);
! 519: if (error)
! 520: return error;
! 521: #endif /* WAPBL */
! 522:
1.204 dsl 523: if (args->fspec == NULL)
1.174 jmmv 524: return EINVAL;
1.1 mycroft 525: }
526:
1.204 dsl 527: error = set_statvfs_info(path, UIO_USERSPACE, args->fspec,
1.205 pooka 528: UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l);
1.114 christos 529: if (error == 0)
530: (void)strncpy(fs->fs_fsmnt, mp->mnt_stat.f_mntonname,
531: sizeof(fs->fs_fsmnt));
1.223.4.2! yamt 532: fs->fs_flags &= ~FS_DOSOFTDEP;
1.15 mycroft 533: if (fs->fs_fmod != 0) { /* XXX */
1.223.4.2! yamt 534: int err;
! 535:
1.15 mycroft 536: fs->fs_fmod = 0;
537: if (fs->fs_clean & FS_WASCLEAN)
1.182 kardel 538: fs->fs_time = time_second;
1.89 fvdl 539: else {
1.223.4.2! yamt 540: printf("%s: file system not clean (fs_clean=%#x); "
! 541: "please fsck(8)\n", mp->mnt_stat.f_mntfromname,
! 542: fs->fs_clean);
1.110 fvdl 543: printf("%s: lost blocks %" PRId64 " files %d\n",
1.89 fvdl 544: mp->mnt_stat.f_mntfromname, fs->fs_pendingblocks,
545: fs->fs_pendinginodes);
546: }
1.223.4.2! yamt 547: err = UFS_WAPBL_BEGIN(mp);
! 548: if (err == 0) {
! 549: (void) ffs_cgupdate(ump, MNT_WAIT);
! 550: UFS_WAPBL_END(mp);
! 551: }
1.15 mycroft 552: }
1.223.4.2! yamt 553: if ((mp->mnt_flag & MNT_SOFTDEP) != 0) {
! 554: printf("%s: `-o softdep' is no longer supported, "
! 555: "consider `-o log'\n", mp->mnt_stat.f_mntfromname);
! 556: mp->mnt_flag &= ~MNT_SOFTDEP;
! 557: }
! 558:
1.159 mycroft 559: return (error);
560:
561: fail:
562: vrele(devvp);
563: return (error);
1.1 mycroft 564: }
565:
566: /*
567: * Reload all incore data for a filesystem (used after running fsck on
568: * the root filesystem and finding things to fix). The filesystem must
569: * be mounted read-only.
570: *
571: * Things to do to update the mount:
572: * 1) invalidate all cached meta-data.
573: * 2) re-read superblock from disk.
574: * 3) re-read summary information from disk.
575: * 4) invalidate all inactive vnodes.
576: * 5) invalidate all cached file data.
577: * 6) re-read inode data for all active vnodes.
578: */
1.19 christos 579: int
1.181 elad 580: ffs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l)
1.1 mycroft 581: {
1.214 ad 582: struct vnode *vp, *mvp, *devvp;
1.1 mycroft 583: struct inode *ip;
1.84 lukem 584: void *space;
1.1 mycroft 585: struct buf *bp;
1.18 cgd 586: struct fs *fs, *newfs;
1.1 mycroft 587: struct partinfo dpart;
588: int i, blks, size, error;
1.18 cgd 589: int32_t *lp;
1.111 fvdl 590: struct ufsmount *ump;
1.141 dbj 591: daddr_t sblockloc;
1.1 mycroft 592:
1.153 mycroft 593: if ((mp->mnt_flag & MNT_RDONLY) == 0)
1.1 mycroft 594: return (EINVAL);
1.111 fvdl 595:
1.153 mycroft 596: ump = VFSTOUFS(mp);
1.1 mycroft 597: /*
598: * Step 1: invalidate all cached meta-data.
599: */
1.111 fvdl 600: devvp = ump->um_devvp;
1.55 fvdl 601: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1.177 christos 602: error = vinvalbuf(devvp, 0, cred, l, 0, 0);
1.55 fvdl 603: VOP_UNLOCK(devvp, 0);
604: if (error)
1.1 mycroft 605: panic("ffs_reload: dirty1");
606: /*
607: * Step 2: re-read superblock from disk.
608: */
1.111 fvdl 609: fs = ump->um_fs;
1.211 pooka 610: if (VOP_IOCTL(devvp, DIOCGPART, &dpart, FREAD, NOCRED) != 0)
1.1 mycroft 611: size = DEV_BSIZE;
612: else
613: size = dpart.disklab->d_secsize;
1.141 dbj 614: /* XXX we don't handle possibility that superblock moved. */
1.110 fvdl 615: error = bread(devvp, fs->fs_sblockloc / size, fs->fs_sbsize,
1.223.4.2! yamt 616: NOCRED, 0, &bp);
1.47 bouyer 617: if (error) {
1.209 ad 618: brelse(bp, 0);
1.1 mycroft 619: return (error);
1.47 bouyer 620: }
1.34 bouyer 621: newfs = malloc(fs->fs_sbsize, M_UFSMNT, M_WAITOK);
1.42 perry 622: memcpy(newfs, bp->b_data, fs->fs_sbsize);
1.34 bouyer 623: #ifdef FFS_EI
1.111 fvdl 624: if (ump->um_flags & UFS_NEEDSWAP) {
1.83 lukem 625: ffs_sb_swap((struct fs*)bp->b_data, newfs);
1.55 fvdl 626: fs->fs_flags |= FS_SWAPPED;
1.121 bouyer 627: } else
1.34 bouyer 628: #endif
1.121 bouyer 629: fs->fs_flags &= ~FS_SWAPPED;
1.161 perry 630: if ((newfs->fs_magic != FS_UFS1_MAGIC &&
1.110 fvdl 631: newfs->fs_magic != FS_UFS2_MAGIC)||
632: newfs->fs_bsize > MAXBSIZE ||
633: newfs->fs_bsize < sizeof(struct fs)) {
1.209 ad 634: brelse(bp, 0);
1.34 bouyer 635: free(newfs, M_UFSMNT);
1.1 mycroft 636: return (EIO); /* XXX needs translation */
637: }
1.141 dbj 638: /* Store off old fs_sblockloc for fs_oldfscompat_read. */
639: sblockloc = fs->fs_sblockloc;
1.161 perry 640: /*
1.18 cgd 641: * Copy pointer fields back into superblock before copying in XXX
642: * new superblock. These should really be in the ufsmount. XXX
643: * Note that important parameters (eg fs_ncg) are unchanged.
644: */
1.84 lukem 645: newfs->fs_csp = fs->fs_csp;
1.18 cgd 646: newfs->fs_maxcluster = fs->fs_maxcluster;
1.85 lukem 647: newfs->fs_contigdirs = fs->fs_contigdirs;
1.76 mycroft 648: newfs->fs_ronly = fs->fs_ronly;
1.110 fvdl 649: newfs->fs_active = fs->fs_active;
1.42 perry 650: memcpy(fs, newfs, (u_int)fs->fs_sbsize);
1.209 ad 651: brelse(bp, 0);
1.34 bouyer 652: free(newfs, M_UFSMNT);
1.103 dbj 653:
654: /* Recheck for apple UFS filesystem */
1.153 mycroft 655: ump->um_flags &= ~UFS_ISAPPLEUFS;
1.103 dbj 656: /* First check to see if this is tagged as an Apple UFS filesystem
657: * in the disklabel
658: */
1.211 pooka 659: if ((VOP_IOCTL(devvp, DIOCGPART, &dpart, FREAD, cred) == 0) &&
1.103 dbj 660: (dpart.part->p_fstype == FS_APPLEUFS)) {
1.153 mycroft 661: ump->um_flags |= UFS_ISAPPLEUFS;
1.103 dbj 662: }
663: #ifdef APPLE_UFS
664: else {
665: /* Manually look for an apple ufs label, and if a valid one
666: * is found, then treat it like an Apple UFS filesystem anyway
667: */
1.106 fvdl 668: error = bread(devvp, (daddr_t)(APPLEUFS_LABEL_OFFSET / size),
1.223.4.2! yamt 669: APPLEUFS_LABEL_SIZE, cred, 0, &bp);
1.103 dbj 670: if (error) {
1.209 ad 671: brelse(bp, 0);
1.103 dbj 672: return (error);
673: }
674: error = ffs_appleufs_validate(fs->fs_fsmnt,
1.223.4.2! yamt 675: (struct appleufslabel *)bp->b_data, NULL);
1.153 mycroft 676: if (error == 0)
677: ump->um_flags |= UFS_ISAPPLEUFS;
1.209 ad 678: brelse(bp, 0);
1.103 dbj 679: bp = NULL;
680: }
681: #else
1.153 mycroft 682: if (ump->um_flags & UFS_ISAPPLEUFS)
1.103 dbj 683: return (EIO);
684: #endif
685:
1.153 mycroft 686: if (UFS_MPISAPPLEUFS(ump)) {
1.103 dbj 687: /* see comment about NeXT below */
1.153 mycroft 688: ump->um_maxsymlinklen = APPLEUFS_MAXSYMLINKLEN;
689: ump->um_dirblksiz = APPLEUFS_DIRBLKSIZ;
690: mp->mnt_iflag |= IMNT_DTYPE;
691: } else {
692: ump->um_maxsymlinklen = fs->fs_maxsymlinklen;
693: ump->um_dirblksiz = DIRBLKSIZ;
694: if (ump->um_maxsymlinklen > 0)
695: mp->mnt_iflag |= IMNT_DTYPE;
696: else
697: mp->mnt_iflag &= ~IMNT_DTYPE;
1.103 dbj 698: }
1.154 yamt 699: ffs_oldfscompat_read(fs, ump, sblockloc);
1.223.4.2! yamt 700:
1.209 ad 701: mutex_enter(&ump->um_lock);
1.153 mycroft 702: ump->um_maxfilesize = fs->fs_maxfilesize;
1.223.4.2! yamt 703: if (fs->fs_flags & ~(FS_KNOWN_FLAGS | FS_INTERNAL)) {
! 704: uprintf("%s: unknown ufs flags: 0x%08"PRIx32"%s\n",
! 705: mp->mnt_stat.f_mntonname, fs->fs_flags,
! 706: (mp->mnt_flag & MNT_FORCE) ? "" : ", not mounting");
! 707: if ((mp->mnt_flag & MNT_FORCE) == 0) {
! 708: mutex_exit(&ump->um_lock);
! 709: return (EINVAL);
! 710: }
! 711: }
1.89 fvdl 712: if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
713: fs->fs_pendingblocks = 0;
714: fs->fs_pendinginodes = 0;
715: }
1.209 ad 716: mutex_exit(&ump->um_lock);
1.85 lukem 717:
1.211 pooka 718: ffs_statvfs(mp, &mp->mnt_stat);
1.1 mycroft 719: /*
720: * Step 3: re-read summary information from disk.
721: */
722: blks = howmany(fs->fs_cssize, fs->fs_fsize);
1.84 lukem 723: space = fs->fs_csp;
1.1 mycroft 724: for (i = 0; i < blks; i += fs->fs_frag) {
725: size = fs->fs_bsize;
726: if (i + fs->fs_frag > blks)
727: size = (blks - i) * fs->fs_fsize;
1.19 christos 728: error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
1.223.4.2! yamt 729: NOCRED, 0, &bp);
1.47 bouyer 730: if (error) {
1.209 ad 731: brelse(bp, 0);
1.1 mycroft 732: return (error);
1.47 bouyer 733: }
1.34 bouyer 734: #ifdef FFS_EI
1.55 fvdl 735: if (UFS_FSNEEDSWAP(fs))
1.84 lukem 736: ffs_csum_swap((struct csum *)bp->b_data,
737: (struct csum *)space, size);
1.34 bouyer 738: else
739: #endif
1.84 lukem 740: memcpy(space, bp->b_data, (size_t)size);
741: space = (char *)space + size;
1.209 ad 742: brelse(bp, 0);
1.1 mycroft 743: }
1.149 hannken 744: if (fs->fs_snapinum[0] != 0)
1.153 mycroft 745: ffs_snapshot_mount(mp);
1.18 cgd 746: /*
747: * We no longer know anything about clusters per cylinder group.
748: */
749: if (fs->fs_contigsumsize > 0) {
750: lp = fs->fs_maxcluster;
751: for (i = 0; i < fs->fs_ncg; i++)
752: *lp++ = fs->fs_contigsumsize;
753: }
754:
1.214 ad 755: /* Allocate a marker vnode. */
1.215 pooka 756: if ((mvp = vnalloc(mp)) == NULL)
1.214 ad 757: return ENOMEM;
1.189 reinoud 758: /*
759: * NOTE: not using the TAILQ_FOREACH here since in this loop vgone()
760: * and vclean() can be called indirectly
761: */
1.214 ad 762: mutex_enter(&mntvnode_lock);
763: loop:
764: for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
765: vmark(mvp, vp);
766: if (vp->v_mount != mp || vismarker(vp))
767: continue;
1.1 mycroft 768: /*
769: * Step 4: invalidate all inactive vnodes.
770: */
1.214 ad 771: if (vrecycle(vp, &mntvnode_lock, l)) {
772: mutex_enter(&mntvnode_lock);
773: (void)vunmark(mvp);
1.33 fvdl 774: goto loop;
1.214 ad 775: }
1.1 mycroft 776: /*
777: * Step 5: invalidate all cached file data.
778: */
1.214 ad 779: mutex_enter(&vp->v_interlock);
780: mutex_exit(&mntvnode_lock);
781: if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK)) {
782: (void)vunmark(mvp);
1.1 mycroft 783: goto loop;
1.214 ad 784: }
1.177 christos 785: if (vinvalbuf(vp, 0, cred, l, 0, 0))
1.1 mycroft 786: panic("ffs_reload: dirty2");
787: /*
788: * Step 6: re-read inode data for all active vnodes.
789: */
790: ip = VTOI(vp);
1.19 christos 791: error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
1.223.4.2! yamt 792: (int)fs->fs_bsize, NOCRED, 0, &bp);
1.19 christos 793: if (error) {
1.209 ad 794: brelse(bp, 0);
1.1 mycroft 795: vput(vp);
1.214 ad 796: (void)vunmark(mvp);
797: break;
1.1 mycroft 798: }
1.110 fvdl 799: ffs_load_inode(bp, ip, fs, ip->i_number);
1.209 ad 800: brelse(bp, 0);
1.1 mycroft 801: vput(vp);
1.214 ad 802: mutex_enter(&mntvnode_lock);
1.1 mycroft 803: }
1.214 ad 804: mutex_exit(&mntvnode_lock);
1.215 pooka 805: vnfree(mvp);
1.214 ad 806: return (error);
1.1 mycroft 807: }
808:
809: /*
1.110 fvdl 810: * Possible superblock locations ordered from most to least likely.
811: */
1.135 jdolecek 812: static const int sblock_try[] = SBLOCKSEARCH;
1.110 fvdl 813:
814: /*
1.1 mycroft 815: * Common code for mount and mountroot
816: */
817: int
1.177 christos 818: ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
1.1 mycroft 819: {
1.34 bouyer 820: struct ufsmount *ump;
1.1 mycroft 821: struct buf *bp;
1.34 bouyer 822: struct fs *fs;
1.9 mycroft 823: dev_t dev;
1.1 mycroft 824: struct partinfo dpart;
1.84 lukem 825: void *space;
1.110 fvdl 826: daddr_t sblockloc, fsblockloc;
827: int blks, fstype;
1.209 ad 828: int error, i, size, ronly, bset = 0;
1.52 drochner 829: #ifdef FFS_EI
1.110 fvdl 830: int needswap = 0; /* keep gcc happy */
1.52 drochner 831: #endif
1.9 mycroft 832: int32_t *lp;
1.181 elad 833: kauth_cred_t cred;
1.110 fvdl 834: u_int32_t sbsize = 8192; /* keep gcc happy*/
1.1 mycroft 835:
1.9 mycroft 836: dev = devvp->v_rdev;
1.184 ad 837: cred = l ? l->l_cred : NOCRED;
1.159 mycroft 838:
839: /* Flush out any old buffers remaining from a previous use. */
1.55 fvdl 840: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1.177 christos 841: error = vinvalbuf(devvp, V_SAVE, cred, l, 0, 0);
1.55 fvdl 842: VOP_UNLOCK(devvp, 0);
843: if (error)
1.1 mycroft 844: return (error);
845:
846: ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
1.211 pooka 847: if (VOP_IOCTL(devvp, DIOCGPART, &dpart, FREAD, cred) != 0)
1.1 mycroft 848: size = DEV_BSIZE;
849: else
850: size = dpart.disklab->d_secsize;
851:
852: bp = NULL;
853: ump = NULL;
1.110 fvdl 854: fs = NULL;
1.138 dsl 855: sblockloc = 0;
1.110 fvdl 856: fstype = 0;
1.34 bouyer 857:
1.214 ad 858: error = fstrans_mount(mp);
859: if (error)
860: return error;
861:
1.223.4.2! yamt 862: ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
! 863: memset(ump, 0, sizeof *ump);
! 864: mutex_init(&ump->um_lock, MUTEX_DEFAULT, IPL_NONE);
! 865: error = ffs_snapshot_init(ump);
! 866: if (error)
! 867: goto out;
! 868: ump->um_ops = &ffs_ufsops;
! 869:
! 870: #ifdef WAPBL
! 871: sbagain:
! 872: #endif
1.110 fvdl 873: /*
1.192 isaki 874: * Try reading the superblock in each of its possible locations.
875: */
1.138 dsl 876: for (i = 0; ; i++) {
877: if (bp != NULL) {
1.209 ad 878: brelse(bp, BC_NOCACHE);
1.138 dsl 879: bp = NULL;
880: }
881: if (sblock_try[i] == -1) {
882: error = EINVAL;
883: fs = NULL;
884: goto out;
885: }
1.110 fvdl 886: error = bread(devvp, sblock_try[i] / size, SBLOCKSIZE, cred,
1.223.4.2! yamt 887: 0, &bp);
1.168 drochner 888: if (error) {
889: fs = NULL;
1.110 fvdl 890: goto out;
1.168 drochner 891: }
1.110 fvdl 892: fs = (struct fs*)bp->b_data;
893: fsblockloc = sblockloc = sblock_try[i];
894: if (fs->fs_magic == FS_UFS1_MAGIC) {
895: sbsize = fs->fs_sbsize;
896: fstype = UFS1;
1.34 bouyer 897: #ifdef FFS_EI
1.110 fvdl 898: needswap = 0;
899: } else if (fs->fs_magic == bswap32(FS_UFS1_MAGIC)) {
900: sbsize = bswap32(fs->fs_sbsize);
901: fstype = UFS1;
902: needswap = 1;
1.34 bouyer 903: #endif
1.110 fvdl 904: } else if (fs->fs_magic == FS_UFS2_MAGIC) {
905: sbsize = fs->fs_sbsize;
906: fstype = UFS2;
907: #ifdef FFS_EI
908: needswap = 0;
909: } else if (fs->fs_magic == bswap32(FS_UFS2_MAGIC)) {
910: sbsize = bswap32(fs->fs_sbsize);
911: fstype = UFS2;
912: needswap = 1;
913: #endif
1.112 fvdl 914: } else
1.138 dsl 915: continue;
916:
917:
918: /* fs->fs_sblockloc isn't defined for old filesystems */
1.140 dsl 919: if (fstype == UFS1 && !(fs->fs_old_flags & FS_FLAGS_UPDATED)) {
920: if (sblockloc == SBLOCK_UFS2)
1.138 dsl 921: /*
922: * This is likely to be the first alternate
923: * in a filesystem with 64k blocks.
924: * Don't use it.
925: */
926: continue;
927: fsblockloc = sblockloc;
928: } else {
929: fsblockloc = fs->fs_sblockloc;
930: #ifdef FFS_EI
931: if (needswap)
932: fsblockloc = bswap64(fsblockloc);
933: #endif
934: }
1.110 fvdl 935:
1.138 dsl 936: /* Check we haven't found an alternate superblock */
937: if (fsblockloc != sblockloc)
938: continue;
1.112 fvdl 939:
1.138 dsl 940: /* Validate size of superblock */
941: if (sbsize > MAXBSIZE || sbsize < sizeof(struct fs))
942: continue;
1.110 fvdl 943:
1.138 dsl 944: /* Ok seems to be a good superblock */
945: break;
1.34 bouyer 946: }
947:
948: fs = malloc((u_long)sbsize, M_UFSMNT, M_WAITOK);
1.42 perry 949: memcpy(fs, bp->b_data, sbsize);
1.111 fvdl 950: ump->um_fs = fs;
951:
1.34 bouyer 952: #ifdef FFS_EI
1.55 fvdl 953: if (needswap) {
1.83 lukem 954: ffs_sb_swap((struct fs*)bp->b_data, fs);
1.55 fvdl 955: fs->fs_flags |= FS_SWAPPED;
1.121 bouyer 956: } else
1.34 bouyer 957: #endif
1.121 bouyer 958: fs->fs_flags &= ~FS_SWAPPED;
1.56 drochner 959:
1.223.4.2! yamt 960: #ifdef WAPBL
! 961: if ((mp->mnt_wapbl_replay == 0) && (fs->fs_flags & FS_DOWAPBL)) {
! 962: error = ffs_wapbl_replay_start(mp, fs, devvp);
! 963: if (error)
! 964: goto out;
! 965:
! 966: if (!ronly) {
! 967: /* XXX fsmnt may be stale. */
! 968: printf("%s: replaying log to disk\n", fs->fs_fsmnt);
! 969: error = wapbl_replay_write(mp->mnt_wapbl_replay, devvp);
! 970: if (error)
! 971: goto out;
! 972: wapbl_replay_stop(mp->mnt_wapbl_replay);
! 973: fs->fs_clean = FS_WASCLEAN;
! 974: } else {
! 975: /* XXX fsmnt may be stale */
! 976: printf("%s: replaying log to memory\n", fs->fs_fsmnt);
! 977: }
! 978:
! 979: /* Force a re-read of the superblock */
! 980: brelse(bp, BC_INVAL);
! 981: bp = NULL;
! 982: free(fs, M_UFSMNT);
! 983: fs = NULL;
! 984: goto sbagain;
! 985: }
! 986: #else /* !WAPBL */
! 987: if ((fs->fs_flags & FS_DOWAPBL) && (mp->mnt_flag & MNT_FORCE) == 0) {
! 988: error = EPERM;
! 989: goto out;
! 990: }
! 991: #endif /* !WAPBL */
! 992:
1.154 yamt 993: ffs_oldfscompat_read(fs, ump, sblockloc);
1.153 mycroft 994: ump->um_maxfilesize = fs->fs_maxfilesize;
1.131 dbj 995:
1.223.4.2! yamt 996: if (fs->fs_flags & ~(FS_KNOWN_FLAGS | FS_INTERNAL)) {
! 997: uprintf("%s: unknown ufs flags: 0x%08"PRIx32"%s\n",
! 998: mp->mnt_stat.f_mntonname, fs->fs_flags,
! 999: (mp->mnt_flag & MNT_FORCE) ? "" : ", not mounting");
! 1000: if ((mp->mnt_flag & MNT_FORCE) == 0) {
! 1001: error = EINVAL;
! 1002: goto out;
! 1003: }
! 1004: }
! 1005:
1.89 fvdl 1006: if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
1007: fs->fs_pendingblocks = 0;
1008: fs->fs_pendinginodes = 0;
1009: }
1.56 drochner 1010:
1.110 fvdl 1011: ump->um_fstype = fstype;
1012: if (fs->fs_sbsize < SBLOCKSIZE)
1.209 ad 1013: brelse(bp, BC_INVAL);
1014: else
1015: brelse(bp, 0);
1.1 mycroft 1016: bp = NULL;
1.94 chs 1017:
1.103 dbj 1018: /* First check to see if this is tagged as an Apple UFS filesystem
1019: * in the disklabel
1020: */
1.211 pooka 1021: if ((VOP_IOCTL(devvp, DIOCGPART, &dpart, FREAD, cred) == 0) &&
1.103 dbj 1022: (dpart.part->p_fstype == FS_APPLEUFS)) {
1023: ump->um_flags |= UFS_ISAPPLEUFS;
1024: }
1025: #ifdef APPLE_UFS
1026: else {
1027: /* Manually look for an apple ufs label, and if a valid one
1028: * is found, then treat it like an Apple UFS filesystem anyway
1029: */
1.106 fvdl 1030: error = bread(devvp, (daddr_t)(APPLEUFS_LABEL_OFFSET / size),
1.223.4.2! yamt 1031: APPLEUFS_LABEL_SIZE, cred, 0, &bp);
1.103 dbj 1032: if (error)
1033: goto out;
1034: error = ffs_appleufs_validate(fs->fs_fsmnt,
1.223.4.2! yamt 1035: (struct appleufslabel *)bp->b_data, NULL);
1.103 dbj 1036: if (error == 0) {
1037: ump->um_flags |= UFS_ISAPPLEUFS;
1038: }
1.209 ad 1039: brelse(bp, 0);
1.103 dbj 1040: bp = NULL;
1041: }
1042: #else
1043: if (ump->um_flags & UFS_ISAPPLEUFS) {
1044: error = EINVAL;
1045: goto out;
1046: }
1047: #endif
1048:
1.223.4.2! yamt 1049: #if 0
! 1050: /*
! 1051: * XXX This code changes the behaviour of mounting dirty filesystems, to
! 1052: * XXX require "mount -f ..." to mount them. This doesn't match what
! 1053: * XXX mount(8) describes and is disabled for now.
! 1054: */
! 1055: /*
! 1056: * If the file system is not clean, don't allow it to be mounted
! 1057: * unless MNT_FORCE is specified. (Note: MNT_FORCE is always set
! 1058: * for the root file system.)
! 1059: */
! 1060: if (fs->fs_flags & FS_DOWAPBL) {
! 1061: /*
! 1062: * wapbl normally expects to be FS_WASCLEAN when the FS_DOWAPBL
! 1063: * bit is set, although there's a window in unmount where it
! 1064: * could be FS_ISCLEAN
! 1065: */
! 1066: if ((mp->mnt_flag & MNT_FORCE) == 0 &&
! 1067: (fs->fs_clean & (FS_WASCLEAN | FS_ISCLEAN)) == 0) {
! 1068: error = EPERM;
! 1069: goto out;
! 1070: }
! 1071: } else
! 1072: if ((fs->fs_clean & FS_ISCLEAN) == 0 &&
! 1073: (mp->mnt_flag & MNT_FORCE) == 0) {
! 1074: error = EPERM;
! 1075: goto out;
! 1076: }
! 1077: #endif
! 1078:
1.94 chs 1079: /*
1.99 chs 1080: * verify that we can access the last block in the fs
1081: * if we're mounting read/write.
1.94 chs 1082: */
1083:
1.99 chs 1084: if (!ronly) {
1085: error = bread(devvp, fsbtodb(fs, fs->fs_size - 1), fs->fs_fsize,
1.223.4.2! yamt 1086: cred, 0, &bp);
1.99 chs 1087: if (bp->b_bcount != fs->fs_fsize)
1088: error = EINVAL;
1.209 ad 1089: if (error) {
1090: bset = BC_INVAL;
1.99 chs 1091: goto out;
1.209 ad 1092: }
1093: brelse(bp, BC_INVAL);
1.99 chs 1094: bp = NULL;
1095: }
1.94 chs 1096:
1.1 mycroft 1097: fs->fs_ronly = ronly;
1.223.4.2! yamt 1098: /* Don't bump fs_clean if we're replaying journal */
! 1099: if (!((fs->fs_flags & FS_DOWAPBL) && (fs->fs_clean & FS_WASCLEAN)))
! 1100: if (ronly == 0) {
! 1101: fs->fs_clean <<= 1;
! 1102: fs->fs_fmod = 1;
! 1103: }
1.9 mycroft 1104: size = fs->fs_cssize;
1105: blks = howmany(size, fs->fs_fsize);
1106: if (fs->fs_contigsumsize > 0)
1107: size += fs->fs_ncg * sizeof(int32_t);
1.85 lukem 1108: size += fs->fs_ncg * sizeof(*fs->fs_contigdirs);
1.84 lukem 1109: space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
1110: fs->fs_csp = space;
1.1 mycroft 1111: for (i = 0; i < blks; i += fs->fs_frag) {
1112: size = fs->fs_bsize;
1113: if (i + fs->fs_frag > blks)
1114: size = (blks - i) * fs->fs_fsize;
1.19 christos 1115: error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
1.223.4.2! yamt 1116: cred, 0, &bp);
1.19 christos 1117: if (error) {
1.84 lukem 1118: free(fs->fs_csp, M_UFSMNT);
1.128 dbj 1119: goto out;
1.1 mycroft 1120: }
1.34 bouyer 1121: #ifdef FFS_EI
1122: if (needswap)
1.84 lukem 1123: ffs_csum_swap((struct csum *)bp->b_data,
1124: (struct csum *)space, size);
1.34 bouyer 1125: else
1126: #endif
1.42 perry 1127: memcpy(space, bp->b_data, (u_int)size);
1.161 perry 1128:
1.84 lukem 1129: space = (char *)space + size;
1.209 ad 1130: brelse(bp, 0);
1.1 mycroft 1131: bp = NULL;
1132: }
1.9 mycroft 1133: if (fs->fs_contigsumsize > 0) {
1.85 lukem 1134: fs->fs_maxcluster = lp = space;
1.9 mycroft 1135: for (i = 0; i < fs->fs_ncg; i++)
1136: *lp++ = fs->fs_contigsumsize;
1.85 lukem 1137: space = lp;
1.9 mycroft 1138: }
1.85 lukem 1139: size = fs->fs_ncg * sizeof(*fs->fs_contigdirs);
1140: fs->fs_contigdirs = space;
1141: space = (char *)space + size;
1142: memset(fs->fs_contigdirs, 0, size);
1143: /* Compatibility for old filesystems - XXX */
1144: if (fs->fs_avgfilesize <= 0)
1145: fs->fs_avgfilesize = AVFILESIZ;
1146: if (fs->fs_avgfpdir <= 0)
1147: fs->fs_avgfpdir = AFPDIR;
1.150 hannken 1148: fs->fs_active = NULL;
1.100 soren 1149: mp->mnt_data = ump;
1.143 christos 1150: mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev;
1151: mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_FFS);
1152: mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
1.169 christos 1153: mp->mnt_stat.f_namemax = FFS_MAXNAMLEN;
1.153 mycroft 1154: if (UFS_MPISAPPLEUFS(ump)) {
1.103 dbj 1155: /* NeXT used to keep short symlinks in the inode even
1156: * when using FS_42INODEFMT. In that case fs->fs_maxsymlinklen
1157: * is probably -1, but we still need to be able to identify
1158: * short symlinks.
1159: */
1.153 mycroft 1160: ump->um_maxsymlinklen = APPLEUFS_MAXSYMLINKLEN;
1161: ump->um_dirblksiz = APPLEUFS_DIRBLKSIZ;
1162: mp->mnt_iflag |= IMNT_DTYPE;
1163: } else {
1164: ump->um_maxsymlinklen = fs->fs_maxsymlinklen;
1165: ump->um_dirblksiz = DIRBLKSIZ;
1166: if (ump->um_maxsymlinklen > 0)
1167: mp->mnt_iflag |= IMNT_DTYPE;
1168: else
1169: mp->mnt_iflag &= ~IMNT_DTYPE;
1.103 dbj 1170: }
1.73 chs 1171: mp->mnt_fs_bshift = fs->fs_bshift;
1172: mp->mnt_dev_bshift = DEV_BSHIFT; /* XXX */
1.1 mycroft 1173: mp->mnt_flag |= MNT_LOCAL;
1.214 ad 1174: mp->mnt_iflag |= IMNT_MPSAFE;
1.34 bouyer 1175: #ifdef FFS_EI
1176: if (needswap)
1177: ump->um_flags |= UFS_NEEDSWAP;
1178: #endif
1.1 mycroft 1179: ump->um_mountp = mp;
1180: ump->um_dev = dev;
1181: ump->um_devvp = devvp;
1182: ump->um_nindir = fs->fs_nindir;
1.73 chs 1183: ump->um_lognindir = ffs(fs->fs_nindir) - 1;
1.1 mycroft 1184: ump->um_bptrtodb = fs->fs_fsbtodb;
1185: ump->um_seqinc = fs->fs_frag;
1186: for (i = 0; i < MAXQUOTAS; i++)
1187: ump->um_quotas[i] = NULLVP;
1.55 fvdl 1188: devvp->v_specmountpoint = mp;
1.223.4.2! yamt 1189: if (ronly == 0 && fs->fs_snapinum[0] != 0)
! 1190: ffs_snapshot_mount(mp);
! 1191:
! 1192: #ifdef WAPBL
! 1193: if (!ronly) {
! 1194: KDASSERT(fs->fs_ronly == 0);
! 1195: /*
! 1196: * ffs_wapbl_start() needs mp->mnt_stat initialised if it
! 1197: * needs to create a new log file in-filesystem.
! 1198: */
! 1199: ffs_statvfs(mp, &mp->mnt_stat);
! 1200:
! 1201: error = ffs_wapbl_start(mp);
1.55 fvdl 1202: if (error) {
1.84 lukem 1203: free(fs->fs_csp, M_UFSMNT);
1.55 fvdl 1204: goto out;
1205: }
1206: }
1.223.4.2! yamt 1207: #endif /* WAPBL */
1.170 thorpej 1208: #ifdef UFS_EXTATTR
1209: /*
1210: * Initialize file-backed extended attributes on UFS1 file
1211: * systems.
1212: */
1213: if (ump->um_fstype == UFS1) {
1214: ufs_extattr_uepm_init(&ump->um_extattr);
1215: #ifdef UFS_EXTATTR_AUTOSTART
1216: /*
1217: * XXX Just ignore errors. Not clear that we should
1218: * XXX fail the mount in this case.
1219: */
1.178 rpaulo 1220: (void) ufs_extattr_autostart(mp, l);
1.170 thorpej 1221: #endif
1222: }
1223: #endif /* UFS_EXTATTR */
1.1 mycroft 1224: return (0);
1225: out:
1.223.4.2! yamt 1226: #ifdef WAPBL
! 1227: if (mp->mnt_wapbl_replay) {
! 1228: wapbl_replay_stop(mp->mnt_wapbl_replay);
! 1229: wapbl_replay_free(mp->mnt_wapbl_replay);
! 1230: mp->mnt_wapbl_replay = 0;
! 1231: }
! 1232: #endif
! 1233:
1.214 ad 1234: fstrans_unmount(mp);
1.128 dbj 1235: if (fs)
1236: free(fs, M_UFSMNT);
1.55 fvdl 1237: devvp->v_specmountpoint = NULL;
1.1 mycroft 1238: if (bp)
1.209 ad 1239: brelse(bp, bset);
1.1 mycroft 1240: if (ump) {
1.131 dbj 1241: if (ump->um_oldfscompat)
1242: free(ump->um_oldfscompat, M_UFSMNT);
1.209 ad 1243: mutex_destroy(&ump->um_lock);
1.1 mycroft 1244: free(ump, M_UFSMNT);
1.100 soren 1245: mp->mnt_data = NULL;
1.1 mycroft 1246: }
1247: return (error);
1248: }
1249:
1250: /*
1.110 fvdl 1251: * Sanity checks for loading old filesystem superblocks.
1252: * See ffs_oldfscompat_write below for unwound actions.
1.1 mycroft 1253: *
1.110 fvdl 1254: * XXX - Parts get retired eventually.
1255: * Unfortunately new bits get added.
1.1 mycroft 1256: */
1.110 fvdl 1257: static void
1.166 thorpej 1258: ffs_oldfscompat_read(struct fs *fs, struct ufsmount *ump, daddr_t sblockloc)
1.110 fvdl 1259: {
1260: off_t maxfilesize;
1.131 dbj 1261: int32_t *extrasave;
1.110 fvdl 1262:
1.131 dbj 1263: if ((fs->fs_magic != FS_UFS1_MAGIC) ||
1264: (fs->fs_old_flags & FS_FLAGS_UPDATED))
1.111 fvdl 1265: return;
1266:
1.131 dbj 1267: if (!ump->um_oldfscompat)
1268: ump->um_oldfscompat = malloc(512 + 3*sizeof(int32_t),
1269: M_UFSMNT, M_WAITOK);
1270:
1271: memcpy(ump->um_oldfscompat, &fs->fs_old_postbl_start, 512);
1272: extrasave = ump->um_oldfscompat;
1273: extrasave += 512/sizeof(int32_t);
1274: extrasave[0] = fs->fs_old_npsect;
1275: extrasave[1] = fs->fs_old_interleave;
1276: extrasave[2] = fs->fs_old_trackskew;
1277:
1278: /* These fields will be overwritten by their
1279: * original values in fs_oldfscompat_write, so it is harmless
1280: * to modify them here.
1281: */
1282: fs->fs_cstotal.cs_ndir = fs->fs_old_cstotal.cs_ndir;
1283: fs->fs_cstotal.cs_nbfree = fs->fs_old_cstotal.cs_nbfree;
1284: fs->fs_cstotal.cs_nifree = fs->fs_old_cstotal.cs_nifree;
1285: fs->fs_cstotal.cs_nffree = fs->fs_old_cstotal.cs_nffree;
1286:
1287: fs->fs_maxbsize = fs->fs_bsize;
1288: fs->fs_time = fs->fs_old_time;
1289: fs->fs_size = fs->fs_old_size;
1290: fs->fs_dsize = fs->fs_old_dsize;
1291: fs->fs_csaddr = fs->fs_old_csaddr;
1292: fs->fs_sblockloc = sblockloc;
1293:
1.223.4.2! yamt 1294: fs->fs_flags = fs->fs_old_flags | (fs->fs_flags & FS_INTERNAL);
1.122 enami 1295:
1.131 dbj 1296: if (fs->fs_old_postblformat == FS_42POSTBLFMT) {
1297: fs->fs_old_nrpos = 8;
1298: fs->fs_old_npsect = fs->fs_old_nsect;
1299: fs->fs_old_interleave = 1;
1300: fs->fs_old_trackskew = 0;
1.111 fvdl 1301: }
1302:
1303: if (fs->fs_old_inodefmt < FS_44INODEFMT) {
1.201 tsutsui 1304: fs->fs_maxfilesize = (u_quad_t) 1LL << 39;
1.110 fvdl 1305: fs->fs_qbmask = ~fs->fs_bmask;
1306: fs->fs_qfmask = ~fs->fs_fmask;
1307: }
1.111 fvdl 1308:
1309: maxfilesize = (u_int64_t)0x80000000 * fs->fs_bsize - 1;
1.201 tsutsui 1310: if (fs->fs_maxfilesize > maxfilesize)
1311: fs->fs_maxfilesize = maxfilesize;
1.111 fvdl 1312:
1.110 fvdl 1313: /* Compatibility for old filesystems */
1314: if (fs->fs_avgfilesize <= 0)
1315: fs->fs_avgfilesize = AVFILESIZ;
1316: if (fs->fs_avgfpdir <= 0)
1317: fs->fs_avgfpdir = AFPDIR;
1.131 dbj 1318:
1.110 fvdl 1319: #if 0
1320: if (bigcgs) {
1321: fs->fs_save_cgsize = fs->fs_cgsize;
1322: fs->fs_cgsize = fs->fs_bsize;
1323: }
1324: #endif
1325: }
1326:
1327: /*
1328: * Unwinding superblock updates for old filesystems.
1329: * See ffs_oldfscompat_read above for details.
1330: *
1331: * XXX - Parts get retired eventually.
1332: * Unfortunately new bits get added.
1333: */
1334: static void
1.166 thorpej 1335: ffs_oldfscompat_write(struct fs *fs, struct ufsmount *ump)
1.1 mycroft 1336: {
1.131 dbj 1337: int32_t *extrasave;
1338:
1339: if ((fs->fs_magic != FS_UFS1_MAGIC) ||
1340: (fs->fs_old_flags & FS_FLAGS_UPDATED))
1.111 fvdl 1341: return;
1.115 fvdl 1342:
1.111 fvdl 1343: fs->fs_old_time = fs->fs_time;
1344: fs->fs_old_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir;
1345: fs->fs_old_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree;
1346: fs->fs_old_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree;
1347: fs->fs_old_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree;
1.131 dbj 1348: fs->fs_old_flags = fs->fs_flags;
1.111 fvdl 1349:
1.110 fvdl 1350: #if 0
1351: if (bigcgs) {
1352: fs->fs_cgsize = fs->fs_save_cgsize;
1353: }
1354: #endif
1.131 dbj 1355:
1356: memcpy(&fs->fs_old_postbl_start, ump->um_oldfscompat, 512);
1357: extrasave = ump->um_oldfscompat;
1358: extrasave += 512/sizeof(int32_t);
1359: fs->fs_old_npsect = extrasave[0];
1360: fs->fs_old_interleave = extrasave[1];
1361: fs->fs_old_trackskew = extrasave[2];
1362:
1.1 mycroft 1363: }
1364:
1365: /*
1366: * unmount system call
1367: */
1368: int
1.211 pooka 1369: ffs_unmount(struct mount *mp, int mntflags)
1.1 mycroft 1370: {
1.211 pooka 1371: struct lwp *l = curlwp;
1.170 thorpej 1372: struct ufsmount *ump = VFSTOUFS(mp);
1373: struct fs *fs = ump->um_fs;
1.223.4.2! yamt 1374: int error, flags;
! 1375: #ifdef WAPBL
! 1376: extern int doforce;
! 1377: #endif
1.1 mycroft 1378:
1379: flags = 0;
1.11 mycroft 1380: if (mntflags & MNT_FORCE)
1.1 mycroft 1381: flags |= FORCECLOSE;
1.170 thorpej 1382: #ifdef UFS_EXTATTR
1383: if (ump->um_fstype == UFS1) {
1.220 pooka 1384: ufs_extattr_stop(mp, l);
1385: ufs_extattr_uepm_destroy(&ump->um_extattr);
1.170 thorpej 1386: }
1387: #endif /* UFS_EXTATTR */
1.223.4.2! yamt 1388: if ((error = ffs_flushfiles(mp, flags, l)) != 0)
! 1389: return (error);
! 1390: error = UFS_WAPBL_BEGIN(mp);
! 1391: if (error == 0)
! 1392: if (fs->fs_ronly == 0 &&
! 1393: ffs_cgupdate(ump, MNT_WAIT) == 0 &&
! 1394: fs->fs_clean & FS_WASCLEAN) {
1.91 fvdl 1395: fs->fs_clean = FS_ISCLEAN;
1.223.4.2! yamt 1396: fs->fs_fmod = 0;
! 1397: (void) ffs_sbupdate(ump, MNT_WAIT);
1.91 fvdl 1398: }
1.223.4.2! yamt 1399: if (error == 0)
! 1400: UFS_WAPBL_END(mp);
! 1401: #ifdef WAPBL
! 1402: KASSERT(!(mp->mnt_wapbl_replay && mp->mnt_wapbl));
! 1403: if (mp->mnt_wapbl_replay) {
! 1404: KDASSERT(fs->fs_ronly);
! 1405: wapbl_replay_stop(mp->mnt_wapbl_replay);
! 1406: wapbl_replay_free(mp->mnt_wapbl_replay);
! 1407: mp->mnt_wapbl_replay = 0;
1.15 mycroft 1408: }
1.223.4.2! yamt 1409: error = ffs_wapbl_stop(mp, doforce && (mntflags & MNT_FORCE));
! 1410: if (error) {
! 1411: return error;
! 1412: }
! 1413: #endif /* WAPBL */
1.54 enami 1414: if (ump->um_devvp->v_type != VBAD)
1.55 fvdl 1415: ump->um_devvp->v_specmountpoint = NULL;
1.53 wrstuden 1416: vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
1.223.4.2! yamt 1417: (void)VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD | FWRITE,
1.211 pooka 1418: NOCRED);
1.53 wrstuden 1419: vput(ump->um_devvp);
1.84 lukem 1420: free(fs->fs_csp, M_UFSMNT);
1.1 mycroft 1421: free(fs, M_UFSMNT);
1.131 dbj 1422: if (ump->um_oldfscompat != NULL)
1423: free(ump->um_oldfscompat, M_UFSMNT);
1.209 ad 1424: mutex_destroy(&ump->um_lock);
1.223 hannken 1425: ffs_snapshot_fini(ump);
1.1 mycroft 1426: free(ump, M_UFSMNT);
1.100 soren 1427: mp->mnt_data = NULL;
1.1 mycroft 1428: mp->mnt_flag &= ~MNT_LOCAL;
1.214 ad 1429: fstrans_unmount(mp);
1.129 dbj 1430: return (0);
1.1 mycroft 1431: }
1432:
1433: /*
1434: * Flush out all the files in a filesystem.
1435: */
1.19 christos 1436: int
1.177 christos 1437: ffs_flushfiles(struct mount *mp, int flags, struct lwp *l)
1.1 mycroft 1438: {
1439: extern int doforce;
1.61 augustss 1440: struct ufsmount *ump;
1.19 christos 1441: int error;
1.1 mycroft 1442:
1443: if (!doforce)
1444: flags &= ~FORCECLOSE;
1445: ump = VFSTOUFS(mp);
1446: #ifdef QUOTA
1447: if (mp->mnt_flag & MNT_QUOTA) {
1.19 christos 1448: int i;
1.223.4.2! yamt 1449: if ((error = vflush(mp, NULLVP, SKIPSYSTEM | flags)) != 0)
1.1 mycroft 1450: return (error);
1451: for (i = 0; i < MAXQUOTAS; i++) {
1452: if (ump->um_quotas[i] == NULLVP)
1453: continue;
1.177 christos 1454: quotaoff(l, mp, i);
1.1 mycroft 1455: }
1456: /*
1457: * Here we fall through to vflush again to ensure
1458: * that we have gotten rid of all the system vnodes.
1459: */
1460: }
1461: #endif
1.149 hannken 1462: if ((error = vflush(mp, 0, SKIPSYSTEM | flags)) != 0)
1463: return (error);
1464: ffs_snapshot_unmount(mp);
1.55 fvdl 1465: /*
1466: * Flush all the files.
1467: */
1.1 mycroft 1468: error = vflush(mp, NULLVP, flags);
1.55 fvdl 1469: if (error)
1470: return (error);
1471: /*
1472: * Flush filesystem metadata.
1473: */
1474: vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
1.211 pooka 1475: error = VOP_FSYNC(ump->um_devvp, l->l_cred, FSYNC_WAIT, 0, 0);
1.55 fvdl 1476: VOP_UNLOCK(ump->um_devvp, 0);
1.223.4.2! yamt 1477: if (flags & FORCECLOSE) /* XXXDBJ */
! 1478: error = 0;
! 1479:
! 1480: #ifdef WAPBL
! 1481: if (error)
! 1482: return error;
! 1483: if (mp->mnt_wapbl) {
! 1484: error = wapbl_flush(mp->mnt_wapbl, 1);
! 1485: if (flags & FORCECLOSE)
! 1486: error = 0;
! 1487: }
! 1488: #endif
! 1489:
1.1 mycroft 1490: return (error);
1491: }
1492:
1493: /*
1494: * Get file system statistics.
1495: */
1496: int
1.211 pooka 1497: ffs_statvfs(struct mount *mp, struct statvfs *sbp)
1.1 mycroft 1498: {
1.61 augustss 1499: struct ufsmount *ump;
1500: struct fs *fs;
1.1 mycroft 1501:
1502: ump = VFSTOUFS(mp);
1503: fs = ump->um_fs;
1.209 ad 1504: mutex_enter(&ump->um_lock);
1.143 christos 1505: sbp->f_bsize = fs->fs_bsize;
1506: sbp->f_frsize = fs->fs_fsize;
1.1 mycroft 1507: sbp->f_iosize = fs->fs_bsize;
1508: sbp->f_blocks = fs->fs_dsize;
1.98 mycroft 1509: sbp->f_bfree = blkstofrags(fs, fs->fs_cstotal.cs_nbfree) +
1.223.4.2! yamt 1510: fs->fs_cstotal.cs_nffree + dbtofsb(fs, fs->fs_pendingblocks);
1.143 christos 1511: sbp->f_bresvd = ((u_int64_t) fs->fs_dsize * (u_int64_t)
1512: fs->fs_minfree) / (u_int64_t) 100;
1513: if (sbp->f_bfree > sbp->f_bresvd)
1514: sbp->f_bavail = sbp->f_bfree - sbp->f_bresvd;
1515: else
1516: sbp->f_bavail = 0;
1.1 mycroft 1517: sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO;
1.89 fvdl 1518: sbp->f_ffree = fs->fs_cstotal.cs_nifree + fs->fs_pendinginodes;
1.143 christos 1519: sbp->f_favail = sbp->f_ffree;
1520: sbp->f_fresvd = 0;
1.209 ad 1521: mutex_exit(&ump->um_lock);
1.143 christos 1522: copy_statvfs_info(sbp, mp);
1.209 ad 1523:
1.1 mycroft 1524: return (0);
1525: }
1526:
1527: /*
1528: * Go through the disk queues to initiate sandbagged IO;
1529: * go through the inodes to write those that have been modified;
1530: * initiate the writing of the super block if it has been modified.
1531: *
1532: * Note: we are always called with the filesystem marked `MPBUSY'.
1533: */
1534: int
1.211 pooka 1535: ffs_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
1.1 mycroft 1536: {
1.223.4.2! yamt 1537: struct vnode *vp, *mvp, *nvp;
1.33 fvdl 1538: struct inode *ip;
1539: struct ufsmount *ump = VFSTOUFS(mp);
1540: struct fs *fs;
1.223.4.2! yamt 1541: int error, allerror = 0;
1.1 mycroft 1542:
1543: fs = ump->um_fs;
1.33 fvdl 1544: if (fs->fs_fmod != 0 && fs->fs_ronly != 0) { /* XXX */
1545: printf("fs = %s\n", fs->fs_fsmnt);
1546: panic("update: rofs mod");
1.1 mycroft 1547: }
1.214 ad 1548:
1549: /* Allocate a marker vnode. */
1.215 pooka 1550: if ((mvp = vnalloc(mp)) == NULL)
1.214 ad 1551: return (ENOMEM);
1552:
1.199 hannken 1553: fstrans_start(mp, FSTRANS_SHARED);
1.1 mycroft 1554: /*
1555: * Write back each (modified) inode.
1556: */
1.214 ad 1557: mutex_enter(&mntvnode_lock);
1.1 mycroft 1558: loop:
1.189 reinoud 1559: /*
1560: * NOTE: not using the TAILQ_FOREACH here since in this loop vgone()
1561: * and vclean() can be called indirectly
1562: */
1.223.4.2! yamt 1563: for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = nvp) {
! 1564: nvp = TAILQ_NEXT(vp, v_mntvnodes);
1.1 mycroft 1565: /*
1566: * If the vnode that we are about to sync is no longer
1567: * associated with this mount point, start over.
1568: */
1.223.4.2! yamt 1569: if (vp->v_mount != mp)
! 1570: goto loop;
! 1571: /*
! 1572: * Don't interfere with concurrent scans of this FS.
! 1573: */
! 1574: if (vismarker(vp))
1.214 ad 1575: continue;
1576: mutex_enter(&vp->v_interlock);
1.1 mycroft 1577: ip = VTOI(vp);
1.223.4.2! yamt 1578:
! 1579: /*
! 1580: * Skip the vnode/inode if inaccessible.
! 1581: */
! 1582: if (ip == NULL || (vp->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0 ||
! 1583: vp->v_type == VNON) {
! 1584: mutex_exit(&vp->v_interlock);
! 1585: continue;
! 1586: }
! 1587:
! 1588: /*
! 1589: * We deliberately update inode times here. This will
! 1590: * prevent a massive queue of updates accumulating, only
! 1591: * to be handled by a call to unmount.
! 1592: *
! 1593: * XXX It would be better to have the syncer trickle these
! 1594: * out. Adjustment needed to allow registering vnodes for
! 1595: * sync when the vnode is clean, but the inode dirty. Or
! 1596: * have ufs itself trickle out inode updates.
! 1597: *
! 1598: * If doing a lazy sync, we don't care about metadata or
! 1599: * data updates, because they are handled by each vnode's
! 1600: * synclist entry. In this case we are only interested in
! 1601: * writing back modified inodes.
! 1602: */
! 1603: if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE |
! 1604: IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) == 0 &&
! 1605: (waitfor == MNT_LAZY || (LIST_EMPTY(&vp->v_dirtyblkhd) &&
! 1606: UVM_OBJ_IS_CLEAN(&vp->v_uobj)))) {
1.214 ad 1607: mutex_exit(&vp->v_interlock);
1.33 fvdl 1608: continue;
1609: }
1.193 hannken 1610: if (vp->v_type == VBLK &&
1.194 hannken 1611: fstrans_getstate(mp) == FSTRANS_SUSPENDING) {
1.214 ad 1612: mutex_exit(&vp->v_interlock);
1.193 hannken 1613: continue;
1614: }
1.223.4.2! yamt 1615: vmark(mvp, vp);
1.214 ad 1616: mutex_exit(&mntvnode_lock);
1.117 thorpej 1617: error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK);
1.33 fvdl 1618: if (error) {
1.214 ad 1619: mutex_enter(&mntvnode_lock);
1.223.4.2! yamt 1620: nvp = vunmark(mvp);
1.214 ad 1621: if (error == ENOENT) {
1.33 fvdl 1622: goto loop;
1.214 ad 1623: }
1.1 mycroft 1624: continue;
1.33 fvdl 1625: }
1.223.4.2! yamt 1626: if (waitfor == MNT_LAZY) {
! 1627: error = UFS_WAPBL_BEGIN(vp->v_mount);
! 1628: if (!error) {
! 1629: error = ffs_update(vp, NULL, NULL,
! 1630: UPDATE_CLOSE);
! 1631: UFS_WAPBL_END(vp->v_mount);
! 1632: }
! 1633: } else {
! 1634: error = VOP_FSYNC(vp, cred, FSYNC_NOLOG |
! 1635: (waitfor == MNT_WAIT ? FSYNC_WAIT : 0), 0, 0);
! 1636: }
1.152 mycroft 1637: if (error)
1.1 mycroft 1638: allerror = error;
1639: vput(vp);
1.214 ad 1640: mutex_enter(&mntvnode_lock);
1.223.4.2! yamt 1641: nvp = vunmark(mvp);
1.1 mycroft 1642: }
1.214 ad 1643: mutex_exit(&mntvnode_lock);
1.1 mycroft 1644: /*
1645: * Force stale file system control information to be flushed.
1646: */
1.132 hannken 1647: if (waitfor != MNT_LAZY && (ump->um_devvp->v_numoutput > 0 ||
1648: !LIST_EMPTY(&ump->um_devvp->v_dirtyblkhd))) {
1.55 fvdl 1649: vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
1650: if ((error = VOP_FSYNC(ump->um_devvp, cred,
1.223.4.2! yamt 1651: (waitfor == MNT_WAIT ? FSYNC_WAIT : 0) | FSYNC_NOLOG,
! 1652: 0, 0)) != 0)
1.55 fvdl 1653: allerror = error;
1654: VOP_UNLOCK(ump->um_devvp, 0);
1.223.4.2! yamt 1655: if (allerror == 0 && waitfor == MNT_WAIT && !mp->mnt_wapbl) {
1.214 ad 1656: mutex_enter(&mntvnode_lock);
1.132 hannken 1657: goto loop;
1658: }
1.55 fvdl 1659: }
1.1 mycroft 1660: #ifdef QUOTA
1.118 fvdl 1661: qsync(mp);
1.1 mycroft 1662: #endif
1.33 fvdl 1663: /*
1664: * Write back modified superblock.
1665: */
1666: if (fs->fs_fmod != 0) {
1667: fs->fs_fmod = 0;
1.182 kardel 1668: fs->fs_time = time_second;
1.223.4.2! yamt 1669: error = UFS_WAPBL_BEGIN(mp);
! 1670: if (error)
! 1671: allerror = error;
! 1672: else {
! 1673: if ((error = ffs_cgupdate(ump, waitfor)))
! 1674: allerror = error;
! 1675: UFS_WAPBL_END(mp);
! 1676: }
! 1677: }
! 1678:
! 1679: #ifdef WAPBL
! 1680: if (mp->mnt_wapbl) {
! 1681: error = wapbl_flush(mp->mnt_wapbl, 0);
! 1682: if (error)
1.64 mycroft 1683: allerror = error;
1.33 fvdl 1684: }
1.223.4.2! yamt 1685: #endif
! 1686:
1.193 hannken 1687: fstrans_done(mp);
1.215 pooka 1688: vnfree(mvp);
1.1 mycroft 1689: return (allerror);
1690: }
1691:
1692: /*
1693: * Look up a FFS dinode number to find its incore vnode, otherwise read it
1694: * in from disk. If it is in core, wait for the lock bit to clear, then
1695: * return the inode locked. Detection and handling of mount points must be
1696: * done by the calling routine.
1697: */
1698: int
1.166 thorpej 1699: ffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
1.1 mycroft 1700: {
1.33 fvdl 1701: struct fs *fs;
1702: struct inode *ip;
1.1 mycroft 1703: struct ufsmount *ump;
1704: struct buf *bp;
1705: struct vnode *vp;
1706: dev_t dev;
1.43 thorpej 1707: int error;
1.1 mycroft 1708:
1709: ump = VFSTOUFS(mp);
1710: dev = ump->um_dev;
1.68 fvdl 1711:
1.200 ad 1712: retry:
1.117 thorpej 1713: if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL)
1.68 fvdl 1714: return (0);
1.1 mycroft 1715:
1716: /* Allocate a new vnode/inode. */
1.19 christos 1717: if ((error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) != 0) {
1.1 mycroft 1718: *vpp = NULL;
1719: return (error);
1720: }
1.216 ad 1721: ip = pool_cache_get(ffs_inode_cache, PR_WAITOK);
1.68 fvdl 1722:
1723: /*
1.200 ad 1724: * If someone beat us to it, put back the freshly allocated
1725: * vnode/inode pair and retry.
1.68 fvdl 1726: */
1.195 ad 1727: mutex_enter(&ufs_hashlock);
1.200 ad 1728: if (ufs_ihashget(dev, ino, 0) != NULL) {
1.195 ad 1729: mutex_exit(&ufs_hashlock);
1730: ungetnewvnode(vp);
1.216 ad 1731: pool_cache_put(ffs_inode_cache, ip);
1.200 ad 1732: goto retry;
1.195 ad 1733: }
1.68 fvdl 1734:
1.210 ad 1735: vp->v_vflag |= VV_LOCKSWORK;
1.155 thorpej 1736:
1.43 thorpej 1737: /*
1738: * XXX MFS ends up here, too, to allocate an inode. Should we
1739: * XXX create another pool for MFS inodes?
1740: */
1.87 chs 1741:
1742: memset(ip, 0, sizeof(struct inode));
1.1 mycroft 1743: vp->v_data = ip;
1744: ip->i_vnode = vp;
1.110 fvdl 1745: ip->i_ump = ump;
1.1 mycroft 1746: ip->i_fs = fs = ump->um_fs;
1747: ip->i_dev = dev;
1748: ip->i_number = ino;
1749: #ifdef QUOTA
1.203 hannken 1750: ufsquota_init(ip);
1.1 mycroft 1751: #endif
1.86 chs 1752:
1.1 mycroft 1753: /*
1.213 dyoung 1754: * Initialize genfs node, we might proceed to destroy it in
1755: * error branches.
1756: */
1757: genfs_node_init(vp, &ffs_genfsops);
1758:
1759: /*
1.1 mycroft 1760: * Put it onto its hash chain and lock it so that other requests for
1761: * this inode will block if they arrive while we are sleeping waiting
1762: * for old data structures to be purged or for the contents of the
1763: * disk portion of this inode to be read.
1764: */
1.87 chs 1765:
1.1 mycroft 1766: ufs_ihashins(ip);
1.195 ad 1767: mutex_exit(&ufs_hashlock);
1.1 mycroft 1768:
1769: /* Read in the disk contents for the inode, copy into the inode. */
1.19 christos 1770: error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
1.223.4.2! yamt 1771: (int)fs->fs_bsize, NOCRED, 0, &bp);
1.19 christos 1772: if (error) {
1.87 chs 1773:
1.1 mycroft 1774: /*
1775: * The inode does not contain anything useful, so it would
1776: * be misleading to leave it on its hash chain. With mode
1777: * still zero, it will be unlinked and returned to the free
1778: * list by vput().
1779: */
1.87 chs 1780:
1.1 mycroft 1781: vput(vp);
1.209 ad 1782: brelse(bp, 0);
1.1 mycroft 1783: *vpp = NULL;
1784: return (error);
1785: }
1.110 fvdl 1786: if (ip->i_ump->um_fstype == UFS1)
1.216 ad 1787: ip->i_din.ffs1_din = pool_cache_get(ffs_dinode1_cache,
1788: PR_WAITOK);
1.110 fvdl 1789: else
1.216 ad 1790: ip->i_din.ffs2_din = pool_cache_get(ffs_dinode2_cache,
1791: PR_WAITOK);
1.110 fvdl 1792: ffs_load_inode(bp, ip, fs, ino);
1.209 ad 1793: brelse(bp, 0);
1.1 mycroft 1794:
1795: /*
1796: * Initialize the vnode from the inode, check for aliases.
1797: * Note that the underlying vnode may have changed.
1798: */
1.87 chs 1799:
1800: ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, &vp);
1801:
1.1 mycroft 1802: /*
1803: * Finish inode initialization now that aliasing has been resolved.
1804: */
1.87 chs 1805:
1.1 mycroft 1806: ip->i_devvp = ump->um_devvp;
1807: VREF(ip->i_devvp);
1.87 chs 1808:
1.1 mycroft 1809: /*
1810: * Ensure that uid and gid are correct. This is a temporary
1811: * fix until fsck has been changed to do the update.
1812: */
1.87 chs 1813:
1.110 fvdl 1814: if (fs->fs_old_inodefmt < FS_44INODEFMT) { /* XXX */
1815: ip->i_uid = ip->i_ffs1_ouid; /* XXX */
1816: ip->i_gid = ip->i_ffs1_ogid; /* XXX */
1.38 kleink 1817: } /* XXX */
1.110 fvdl 1818: uvm_vnp_setsize(vp, ip->i_size);
1.1 mycroft 1819: *vpp = vp;
1820: return (0);
1821: }
1822:
1823: /*
1824: * File handle to vnode
1825: *
1826: * Have to be really careful about stale file handles:
1827: * - check that the inode number is valid
1828: * - call ffs_vget() to get the locked inode
1829: * - check for an unallocated inode (i_mode == 0)
1830: * - check that the given client host has export rights and return
1831: * those rights via. exflagsp and credanonp
1832: */
1833: int
1.166 thorpej 1834: ffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
1.1 mycroft 1835: {
1.183 martin 1836: struct ufid ufh;
1.1 mycroft 1837: struct fs *fs;
1838:
1.183 martin 1839: if (fhp->fid_len != sizeof(struct ufid))
1840: return EINVAL;
1841:
1842: memcpy(&ufh, fhp, sizeof(ufh));
1.1 mycroft 1843: fs = VFSTOUFS(mp)->um_fs;
1.183 martin 1844: if (ufh.ufid_ino < ROOTINO ||
1845: ufh.ufid_ino >= fs->fs_ncg * fs->fs_ipg)
1.1 mycroft 1846: return (ESTALE);
1.183 martin 1847: return (ufs_fhtovp(mp, &ufh, vpp));
1.1 mycroft 1848: }
1849:
1850: /*
1851: * Vnode pointer to File handle
1852: */
1853: /* ARGSUSED */
1.19 christos 1854: int
1.183 martin 1855: ffs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
1.1 mycroft 1856: {
1.61 augustss 1857: struct inode *ip;
1.183 martin 1858: struct ufid ufh;
1.1 mycroft 1859:
1.183 martin 1860: if (*fh_size < sizeof(struct ufid)) {
1861: *fh_size = sizeof(struct ufid);
1862: return E2BIG;
1863: }
1.1 mycroft 1864: ip = VTOI(vp);
1.183 martin 1865: *fh_size = sizeof(struct ufid);
1866: memset(&ufh, 0, sizeof(ufh));
1867: ufh.ufid_len = sizeof(struct ufid);
1868: ufh.ufid_ino = ip->i_number;
1869: ufh.ufid_gen = ip->i_gen;
1870: memcpy(fhp, &ufh, sizeof(ufh));
1.1 mycroft 1871: return (0);
1.33 fvdl 1872: }
1873:
1874: void
1.166 thorpej 1875: ffs_init(void)
1.33 fvdl 1876: {
1.59 jdolecek 1877: if (ffs_initcount++ > 0)
1878: return;
1879:
1.216 ad 1880: ffs_inode_cache = pool_cache_init(sizeof(struct inode), 0, 0, 0,
1881: "ffsino", NULL, IPL_NONE, NULL, NULL, NULL);
1882: ffs_dinode1_cache = pool_cache_init(sizeof(struct ufs1_dinode), 0, 0, 0,
1883: "ffsdino1", NULL, IPL_NONE, NULL, NULL, NULL);
1884: ffs_dinode2_cache = pool_cache_init(sizeof(struct ufs2_dinode), 0, 0, 0,
1885: "ffsdino2", NULL, IPL_NONE, NULL, NULL, NULL);
1.33 fvdl 1886: ufs_init();
1.86 chs 1887: }
1888:
1889: void
1.166 thorpej 1890: ffs_reinit(void)
1.86 chs 1891: {
1.223.4.2! yamt 1892:
1.86 chs 1893: ufs_reinit();
1.59 jdolecek 1894: }
1895:
1896: void
1.166 thorpej 1897: ffs_done(void)
1.59 jdolecek 1898: {
1899: if (--ffs_initcount > 0)
1900: return;
1901:
1902: ufs_done();
1.216 ad 1903: pool_cache_destroy(ffs_dinode2_cache);
1904: pool_cache_destroy(ffs_dinode1_cache);
1905: pool_cache_destroy(ffs_inode_cache);
1.33 fvdl 1906: }
1907:
1.1 mycroft 1908: /*
1909: * Write a superblock and associated information back to disk.
1910: */
1911: int
1.166 thorpej 1912: ffs_sbupdate(struct ufsmount *mp, int waitfor)
1.1 mycroft 1913: {
1.61 augustss 1914: struct fs *fs = mp->um_fs;
1915: struct buf *bp;
1.110 fvdl 1916: int error = 0;
1917: u_int32_t saveflag;
1.34 bouyer 1918:
1.223.4.2! yamt 1919: error = ffs_getblk(mp->um_devvp,
! 1920: fs->fs_sblockloc >> (fs->fs_fshift - fs->fs_fsbtodb), FFS_NOBLK,
! 1921: fs->fs_sbsize, false, &bp);
! 1922: if (error)
! 1923: return error;
1.55 fvdl 1924: saveflag = fs->fs_flags & FS_INTERNAL;
1925: fs->fs_flags &= ~FS_INTERNAL;
1.161 perry 1926:
1.42 perry 1927: memcpy(bp->b_data, fs, fs->fs_sbsize);
1.110 fvdl 1928:
1929: ffs_oldfscompat_write((struct fs *)bp->b_data, mp);
1.34 bouyer 1930: #ifdef FFS_EI
1931: if (mp->um_flags & UFS_NEEDSWAP)
1.123 enami 1932: ffs_sb_swap((struct fs *)bp->b_data, (struct fs *)bp->b_data);
1.111 fvdl 1933: #endif
1.55 fvdl 1934: fs->fs_flags |= saveflag;
1.34 bouyer 1935:
1.1 mycroft 1936: if (waitfor == MNT_WAIT)
1937: error = bwrite(bp);
1938: else
1939: bawrite(bp);
1.15 mycroft 1940: return (error);
1941: }
1942:
1943: int
1.166 thorpej 1944: ffs_cgupdate(struct ufsmount *mp, int waitfor)
1.15 mycroft 1945: {
1.61 augustss 1946: struct fs *fs = mp->um_fs;
1947: struct buf *bp;
1.15 mycroft 1948: int blks;
1.84 lukem 1949: void *space;
1.15 mycroft 1950: int i, size, error = 0, allerror = 0;
1951:
1952: allerror = ffs_sbupdate(mp, waitfor);
1.1 mycroft 1953: blks = howmany(fs->fs_cssize, fs->fs_fsize);
1.84 lukem 1954: space = fs->fs_csp;
1.1 mycroft 1955: for (i = 0; i < blks; i += fs->fs_frag) {
1956: size = fs->fs_bsize;
1957: if (i + fs->fs_frag > blks)
1958: size = (blks - i) * fs->fs_fsize;
1.223.4.2! yamt 1959: error = ffs_getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
! 1960: FFS_NOBLK, size, false, &bp);
! 1961: if (error)
! 1962: break;
1.34 bouyer 1963: #ifdef FFS_EI
1964: if (mp->um_flags & UFS_NEEDSWAP)
1965: ffs_csum_swap((struct csum*)space,
1.38 kleink 1966: (struct csum*)bp->b_data, size);
1.34 bouyer 1967: else
1968: #endif
1.42 perry 1969: memcpy(bp->b_data, space, (u_int)size);
1.84 lukem 1970: space = (char *)space + size;
1.1 mycroft 1971: if (waitfor == MNT_WAIT)
1972: error = bwrite(bp);
1973: else
1974: bawrite(bp);
1975: }
1.15 mycroft 1976: if (!allerror && error)
1977: allerror = error;
1978: return (allerror);
1.1 mycroft 1979: }
1.170 thorpej 1980:
1981: int
1982: ffs_extattrctl(struct mount *mp, int cmd, struct vnode *vp,
1.211 pooka 1983: int attrnamespace, const char *attrname)
1.170 thorpej 1984: {
1985: #ifdef UFS_EXTATTR
1986: /*
1987: * File-backed extended attributes are only supported on UFS1.
1988: * UFS2 has native extended attributes.
1989: */
1990: if (VFSTOUFS(mp)->um_fstype == UFS1)
1.211 pooka 1991: return (ufs_extattrctl(mp, cmd, vp, attrnamespace, attrname));
1.170 thorpej 1992: #endif
1.211 pooka 1993: return (vfs_stdextattrctl(mp, cmd, vp, attrnamespace, attrname));
1.170 thorpej 1994: }
1.193 hannken 1995:
1996: int
1997: ffs_suspendctl(struct mount *mp, int cmd)
1998: {
1999: int error;
2000: struct lwp *l = curlwp;
2001:
2002: switch (cmd) {
2003: case SUSPEND_SUSPEND:
1.194 hannken 2004: if ((error = fstrans_setstate(mp, FSTRANS_SUSPENDING)) != 0)
1.193 hannken 2005: return error;
1.211 pooka 2006: error = ffs_sync(mp, MNT_WAIT, l->l_proc->p_cred);
1.193 hannken 2007: if (error == 0)
1.194 hannken 2008: error = fstrans_setstate(mp, FSTRANS_SUSPENDED);
1.223.4.2! yamt 2009: #ifdef WAPBL
! 2010: if (error == 0 && mp->mnt_wapbl)
! 2011: error = wapbl_flush(mp->mnt_wapbl, 1);
! 2012: #endif
1.193 hannken 2013: if (error != 0) {
1.194 hannken 2014: (void) fstrans_setstate(mp, FSTRANS_NORMAL);
1.193 hannken 2015: return error;
2016: }
2017: return 0;
2018:
2019: case SUSPEND_RESUME:
1.194 hannken 2020: return fstrans_setstate(mp, FSTRANS_NORMAL);
1.193 hannken 2021:
2022: default:
2023: return EINVAL;
2024: }
2025: }
1.223.4.2! yamt 2026:
! 2027: /*
! 2028: * Synch vnode for a mounted file system. This is called for foreign
! 2029: * vnodes, i.e. non-ffs.
! 2030: */
! 2031: static int
! 2032: ffs_vfs_fsync(vnode_t *vp, int flags)
! 2033: {
! 2034: int error, passes, skipmeta, i, pflags;
! 2035: buf_t *bp, *nbp;
! 2036: #ifdef WAPBL
! 2037: struct mount *mp;
! 2038: #endif
! 2039:
! 2040: KASSERT(vp->v_type == VBLK);
! 2041: KASSERT(vp->v_specmountpoint != NULL);
! 2042:
! 2043: /*
! 2044: * Flush all dirty data associated with the vnode.
! 2045: */
! 2046: pflags = PGO_ALLPAGES | PGO_CLEANIT;
! 2047: if ((flags & FSYNC_WAIT) != 0)
! 2048: pflags |= PGO_SYNCIO;
! 2049: mutex_enter(&vp->v_interlock);
! 2050: error = VOP_PUTPAGES(vp, 0, 0, pflags);
! 2051: if (error)
! 2052: return error;
! 2053:
! 2054: #ifdef WAPBL
! 2055: mp = vp->v_specmountpoint;
! 2056: if (mp && mp->mnt_wapbl) {
! 2057: /*
! 2058: * Don't bother writing out metadata if the syncer is
! 2059: * making the request. We will let the sync vnode
! 2060: * write it out in a single burst through a call to
! 2061: * VFS_SYNC().
! 2062: */
! 2063: if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY | FSYNC_NOLOG)) != 0)
! 2064: return 0;
! 2065:
! 2066: /*
! 2067: * Don't flush the log if the vnode being flushed
! 2068: * contains no dirty buffers that could be in the log.
! 2069: */
! 2070: if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
! 2071: error = wapbl_flush(mp->mnt_wapbl, 0);
! 2072: if (error)
! 2073: return error;
! 2074: }
! 2075:
! 2076: if ((flags & FSYNC_WAIT) != 0) {
! 2077: mutex_enter(&vp->v_interlock);
! 2078: while (vp->v_numoutput)
! 2079: cv_wait(&vp->v_cv, &vp->v_interlock);
! 2080: mutex_exit(&vp->v_interlock);
! 2081: }
! 2082:
! 2083: return 0;
! 2084: }
! 2085: #endif /* WAPBL */
! 2086:
! 2087: /*
! 2088: * Write out metadata for non-logging file systems. XXX This block
! 2089: * should be simplified now that softdep is gone.
! 2090: */
! 2091: passes = NIADDR + 1;
! 2092: skipmeta = 0;
! 2093: if (flags & FSYNC_WAIT)
! 2094: skipmeta = 1;
! 2095:
! 2096: loop:
! 2097: mutex_enter(&bufcache_lock);
! 2098: LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) {
! 2099: bp->b_cflags &= ~BC_SCANNED;
! 2100: }
! 2101: for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
! 2102: nbp = LIST_NEXT(bp, b_vnbufs);
! 2103: if (bp->b_cflags & (BC_BUSY | BC_SCANNED))
! 2104: continue;
! 2105: if ((bp->b_oflags & BO_DELWRI) == 0)
! 2106: panic("ffs_fsync: not dirty");
! 2107: if (skipmeta && bp->b_lblkno < 0)
! 2108: continue;
! 2109: bp->b_cflags |= BC_BUSY | BC_VFLUSH | BC_SCANNED;
! 2110: mutex_exit(&bufcache_lock);
! 2111: /*
! 2112: * On our final pass through, do all I/O synchronously
! 2113: * so that we can find out if our flush is failing
! 2114: * because of write errors.
! 2115: */
! 2116: if (passes > 0 || !(flags & FSYNC_WAIT))
! 2117: (void) bawrite(bp);
! 2118: else if ((error = bwrite(bp)) != 0)
! 2119: return (error);
! 2120: /*
! 2121: * Since we unlocked during the I/O, we need
! 2122: * to start from a known point.
! 2123: */
! 2124: mutex_enter(&bufcache_lock);
! 2125: nbp = LIST_FIRST(&vp->v_dirtyblkhd);
! 2126: }
! 2127: mutex_exit(&bufcache_lock);
! 2128: if (skipmeta) {
! 2129: skipmeta = 0;
! 2130: goto loop;
! 2131: }
! 2132:
! 2133: if ((flags & FSYNC_WAIT) != 0) {
! 2134: mutex_enter(&vp->v_interlock);
! 2135: while (vp->v_numoutput) {
! 2136: cv_wait(&vp->v_cv, &vp->v_interlock);
! 2137: }
! 2138: mutex_exit(&vp->v_interlock);
! 2139:
! 2140: if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
! 2141: /*
! 2142: * Block devices associated with filesystems may
! 2143: * have new I/O requests posted for them even if
! 2144: * the vnode is locked, so no amount of trying will
! 2145: * get them clean. Thus we give block devices a
! 2146: * good effort, then just give up. For all other file
! 2147: * types, go around and try again until it is clean.
! 2148: */
! 2149: if (passes > 0) {
! 2150: passes--;
! 2151: goto loop;
! 2152: }
! 2153: #ifdef DIAGNOSTIC
! 2154: if (vp->v_type != VBLK)
! 2155: vprint("ffs_fsync: dirty", vp);
! 2156: #endif
! 2157: }
! 2158: }
! 2159:
! 2160: if (error == 0 && (flags & FSYNC_CACHE) != 0) {
! 2161: (void)VOP_IOCTL(vp, DIOCCACHESYNC, &i, FWRITE,
! 2162: kauth_cred_get());
! 2163: }
! 2164:
! 2165: return error;
! 2166: }
CVSweb <webmaster@jp.NetBSD.org>