Annotation of sys/ufs/ffs/ffs_vfsops.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ffs_vfsops.c,v 1.109 2007/08/04 03:33:31 art Exp $ */
! 2: /* $NetBSD: ffs_vfsops.c,v 1.19 1996/02/09 22:22:26 christos Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1989, 1991, 1993, 1994
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the University nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: *
! 32: * @(#)ffs_vfsops.c 8.14 (Berkeley) 11/28/94
! 33: */
! 34:
! 35: #include <sys/param.h>
! 36: #include <sys/systm.h>
! 37: #include <sys/namei.h>
! 38: #include <sys/proc.h>
! 39: #include <sys/kernel.h>
! 40: #include <sys/vnode.h>
! 41: #include <sys/socket.h>
! 42: #include <sys/mount.h>
! 43: #include <sys/buf.h>
! 44: #include <sys/mbuf.h>
! 45: #include <sys/file.h>
! 46: #include <sys/disklabel.h>
! 47: #include <sys/ioctl.h>
! 48: #include <sys/errno.h>
! 49: #include <sys/malloc.h>
! 50: #include <sys/sysctl.h>
! 51: #include <sys/pool.h>
! 52:
! 53: #include <dev/rndvar.h>
! 54:
! 55: #include <miscfs/specfs/specdev.h>
! 56:
! 57: #include <ufs/ufs/quota.h>
! 58: #include <ufs/ufs/ufsmount.h>
! 59: #include <ufs/ufs/inode.h>
! 60: #include <ufs/ufs/dir.h>
! 61: #include <ufs/ufs/ufs_extern.h>
! 62: #include <ufs/ufs/dirhash.h>
! 63:
! 64: #include <ufs/ffs/fs.h>
! 65: #include <ufs/ffs/ffs_extern.h>
! 66:
! 67: int ffs_sbupdate(struct ufsmount *, int);
! 68: int ffs_reload_vnode(struct vnode *, void *);
! 69: int ffs_sync_vnode(struct vnode *, void *);
! 70: int ffs_validate(struct fs *);
! 71:
! 72: void ffs1_compat_read(struct fs *, struct ufsmount *, daddr64_t);
! 73: void ffs1_compat_write(struct fs *, struct ufsmount *);
! 74:
! 75: const struct vfsops ffs_vfsops = {
! 76: ffs_mount,
! 77: ufs_start,
! 78: ffs_unmount,
! 79: ufs_root,
! 80: ufs_quotactl,
! 81: ffs_statfs,
! 82: ffs_sync,
! 83: ffs_vget,
! 84: ffs_fhtovp,
! 85: ffs_vptofh,
! 86: ffs_init,
! 87: ffs_sysctl,
! 88: ufs_check_export
! 89: };
! 90:
! 91: struct inode_vtbl ffs_vtbl = {
! 92: ffs_truncate,
! 93: ffs_update,
! 94: ffs_inode_alloc,
! 95: ffs_inode_free,
! 96: ffs_balloc,
! 97: ffs_bufatoff
! 98: };
! 99:
! 100:
! 101: /*
! 102: * Called by main() when ufs is going to be mounted as root.
! 103: */
! 104:
! 105: struct pool ffs_ino_pool;
! 106: struct pool ffs_dinode1_pool;
! 107: #ifdef FFS2
! 108: struct pool ffs_dinode2_pool;
! 109: #endif
! 110:
! 111: int
! 112: ffs_mountroot(void)
! 113: {
! 114: struct fs *fs;
! 115: struct mount *mp;
! 116: struct proc *p = curproc; /* XXX */
! 117: struct ufsmount *ump;
! 118: int error;
! 119:
! 120: /*
! 121: * Get vnodes for swapdev and rootdev.
! 122: */
! 123: swapdev_vp = NULL;
! 124: if ((error = bdevvp(swapdev, &swapdev_vp)) ||
! 125: (error = bdevvp(rootdev, &rootvp))) {
! 126: printf("ffs_mountroot: can't setup bdevvp's\n");
! 127: if (swapdev_vp)
! 128: vrele(swapdev_vp);
! 129: return (error);
! 130: }
! 131:
! 132: if ((error = vfs_rootmountalloc("ffs", "root_device", &mp)) != 0) {
! 133: vrele(swapdev_vp);
! 134: vrele(rootvp);
! 135: return (error);
! 136: }
! 137:
! 138: if ((error = ffs_mountfs(rootvp, mp, p)) != 0) {
! 139: mp->mnt_vfc->vfc_refcount--;
! 140: vfs_unbusy(mp);
! 141: free(mp, M_MOUNT);
! 142: vrele(swapdev_vp);
! 143: vrele(rootvp);
! 144: return (error);
! 145: }
! 146:
! 147: CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
! 148: ump = VFSTOUFS(mp);
! 149: fs = ump->um_fs;
! 150: (void) copystr(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN - 1, 0);
! 151: (void)ffs_statfs(mp, &mp->mnt_stat, p);
! 152: vfs_unbusy(mp);
! 153: inittodr(fs->fs_time);
! 154:
! 155: return (0);
! 156: }
! 157:
! 158: /*
! 159: * VFS Operations.
! 160: *
! 161: * mount system call
! 162: */
! 163: int
! 164: ffs_mount(struct mount *mp, const char *path, void *data,
! 165: struct nameidata *ndp, struct proc *p)
! 166: {
! 167: struct vnode *devvp;
! 168: struct ufs_args args;
! 169: struct ufsmount *ump = NULL;
! 170: struct fs *fs;
! 171: int error = 0, flags;
! 172: int ronly;
! 173: mode_t accessmode;
! 174: size_t size;
! 175:
! 176: error = copyin(data, &args, sizeof (struct ufs_args));
! 177: if (error)
! 178: return (error);
! 179:
! 180: #ifndef FFS_SOFTUPDATES
! 181: if (mp->mnt_flag & MNT_SOFTDEP) {
! 182: printf("WARNING: soft updates isn't compiled in\n");
! 183: mp->mnt_flag &= ~MNT_SOFTDEP;
! 184: }
! 185: #endif
! 186:
! 187: /*
! 188: * Soft updates is incompatible with "async",
! 189: * so if we are doing softupdates stop the user
! 190: * from setting the async flag.
! 191: */
! 192: if ((mp->mnt_flag & (MNT_SOFTDEP | MNT_ASYNC)) ==
! 193: (MNT_SOFTDEP | MNT_ASYNC)) {
! 194: return (EINVAL);
! 195: }
! 196: /*
! 197: * If updating, check whether changing from read-only to
! 198: * read/write; if there is no device name, that's all we do.
! 199: */
! 200: if (mp->mnt_flag & MNT_UPDATE) {
! 201: ump = VFSTOUFS(mp);
! 202: fs = ump->um_fs;
! 203: devvp = ump->um_devvp;
! 204: error = 0;
! 205: ronly = fs->fs_ronly;
! 206:
! 207: if (ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
! 208: /* Flush any dirty data */
! 209: mp->mnt_flag &= ~MNT_RDONLY;
! 210: VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p);
! 211: mp->mnt_flag |= MNT_RDONLY;
! 212:
! 213: /*
! 214: * Get rid of files open for writing.
! 215: */
! 216: flags = WRITECLOSE;
! 217: if (mp->mnt_flag & MNT_FORCE)
! 218: flags |= FORCECLOSE;
! 219: if (fs->fs_flags & FS_DOSOFTDEP) {
! 220: error = softdep_flushfiles(mp, flags, p);
! 221: mp->mnt_flag &= ~MNT_SOFTDEP;
! 222: } else
! 223: error = ffs_flushfiles(mp, flags, p);
! 224: ronly = 1;
! 225: }
! 226:
! 227: /*
! 228: * Flush soft dependencies if disabling it via an update
! 229: * mount. This may leave some items to be processed,
! 230: * so don't do this yet XXX.
! 231: */
! 232: if ((fs->fs_flags & FS_DOSOFTDEP) &&
! 233: !(mp->mnt_flag & MNT_SOFTDEP) &&
! 234: !(mp->mnt_flag & MNT_RDONLY) && fs->fs_ronly == 0) {
! 235: #if 0
! 236: flags = WRITECLOSE;
! 237: if (mp->mnt_flag & MNT_FORCE)
! 238: flags |= FORCECLOSE;
! 239: error = softdep_flushfiles(mp, flags, p);
! 240: #elif FFS_SOFTUPDATES
! 241: mp->mnt_flag |= MNT_SOFTDEP;
! 242: #endif
! 243: }
! 244: /*
! 245: * When upgrading to a softdep mount, we must first flush
! 246: * all vnodes. (not done yet -- see above)
! 247: */
! 248: if (!(fs->fs_flags & FS_DOSOFTDEP) &&
! 249: (mp->mnt_flag & MNT_SOFTDEP) && fs->fs_ronly == 0) {
! 250: #if 0
! 251: flags = WRITECLOSE;
! 252: if (mp->mnt_flag & MNT_FORCE)
! 253: flags |= FORCECLOSE;
! 254: error = ffs_flushfiles(mp, flags, p);
! 255: #else
! 256: mp->mnt_flag &= ~MNT_SOFTDEP;
! 257: #endif
! 258: }
! 259:
! 260: if (!error && (mp->mnt_flag & MNT_RELOAD))
! 261: error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p);
! 262: if (error)
! 263: goto error_1;
! 264:
! 265: if (ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
! 266: /*
! 267: * If upgrade to read-write by non-root, then verify
! 268: * that user has necessary permissions on the device.
! 269: */
! 270: if (suser(p, 0)) {
! 271: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
! 272: error = VOP_ACCESS(devvp, VREAD | VWRITE,
! 273: p->p_ucred, p);
! 274: VOP_UNLOCK(devvp, 0, p);
! 275: if (error)
! 276: goto error_1;
! 277: }
! 278:
! 279: if (fs->fs_clean == 0) {
! 280: #if 0
! 281: /*
! 282: * It is safe mount unclean file system
! 283: * if it was previously mounted with softdep
! 284: * but we may loss space and must
! 285: * sometimes run fsck manually.
! 286: */
! 287: if (fs->fs_flags & FS_DOSOFTDEP)
! 288: printf(
! 289: "WARNING: %s was not properly unmounted\n",
! 290: fs->fs_fsmnt);
! 291: else
! 292: #endif
! 293: if (mp->mnt_flag & MNT_FORCE) {
! 294: printf(
! 295: "WARNING: %s was not properly unmounted\n",
! 296: fs->fs_fsmnt);
! 297: } else {
! 298: printf(
! 299: "WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n",
! 300: fs->fs_fsmnt);
! 301: error = EROFS;
! 302: goto error_1;
! 303: }
! 304: }
! 305:
! 306: if ((fs->fs_flags & FS_DOSOFTDEP)) {
! 307: error = softdep_mount(devvp, mp, fs,
! 308: p->p_ucred);
! 309: if (error)
! 310: goto error_1;
! 311: }
! 312: fs->fs_contigdirs=(u_int8_t*)malloc((u_long)fs->fs_ncg,
! 313: M_UFSMNT, M_WAITOK);
! 314: bzero(fs->fs_contigdirs, fs->fs_ncg);
! 315:
! 316: ronly = 0;
! 317: }
! 318: if (args.fspec == 0) {
! 319: /*
! 320: * Process export requests.
! 321: */
! 322: error = vfs_export(mp, &ump->um_export,
! 323: &args.export_info);
! 324: if (error)
! 325: goto error_1;
! 326: else
! 327: goto success;
! 328: }
! 329: }
! 330: /*
! 331: * Not an update, or updating the name: look up the name
! 332: * and verify that it refers to a sensible block device.
! 333: */
! 334: NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
! 335: if ((error = namei(ndp)) != 0)
! 336: goto error_1;
! 337:
! 338: devvp = ndp->ni_vp;
! 339:
! 340: if (devvp->v_type != VBLK) {
! 341: error = ENOTBLK;
! 342: goto error_2;
! 343: }
! 344:
! 345: if (major(devvp->v_rdev) >= nblkdev) {
! 346: error = ENXIO;
! 347: goto error_2;
! 348: }
! 349:
! 350: /*
! 351: * If mount by non-root, then verify that user has necessary
! 352: * permissions on the device.
! 353: */
! 354: if (suser(p, 0)) {
! 355: accessmode = VREAD;
! 356: if ((mp->mnt_flag & MNT_RDONLY) == 0)
! 357: accessmode |= VWRITE;
! 358: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
! 359: error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p);
! 360: VOP_UNLOCK(devvp, 0, p);
! 361: if (error)
! 362: goto error_2;
! 363: }
! 364:
! 365: if (mp->mnt_flag & MNT_UPDATE) {
! 366: /*
! 367: * UPDATE
! 368: * If it's not the same vnode, or at least the same device
! 369: * then it's not correct.
! 370: */
! 371:
! 372: if (devvp != ump->um_devvp) {
! 373: if (devvp->v_rdev == ump->um_devvp->v_rdev) {
! 374: vrele(devvp);
! 375: } else {
! 376: error = EINVAL; /* needs translation */
! 377: }
! 378: } else
! 379: vrele(devvp);
! 380: /*
! 381: * Update device name only on success
! 382: */
! 383: if (!error) {
! 384: /*
! 385: * Save "mounted from" info for mount point (NULL pad)
! 386: */
! 387: copyinstr(args.fspec,
! 388: mp->mnt_stat.f_mntfromname,
! 389: MNAMELEN - 1,
! 390: &size);
! 391: bzero(mp->mnt_stat.f_mntfromname + size,
! 392: MNAMELEN - size);
! 393: }
! 394: } else {
! 395: /*
! 396: * Since this is a new mount, we want the names for
! 397: * the device and the mount point copied in. If an
! 398: * error occurs, the mountpoint is discarded by the
! 399: * upper level code.
! 400: */
! 401: /* Save "last mounted on" info for mount point (NULL pad)*/
! 402: copyinstr(path, /* mount point*/
! 403: mp->mnt_stat.f_mntonname, /* save area*/
! 404: MNAMELEN - 1, /* max size*/
! 405: &size); /* real size*/
! 406: bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
! 407:
! 408: /* Save "mounted from" info for mount point (NULL pad)*/
! 409: copyinstr(args.fspec, /* device name*/
! 410: mp->mnt_stat.f_mntfromname, /* save area*/
! 411: MNAMELEN - 1, /* max size*/
! 412: &size); /* real size*/
! 413: bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
! 414:
! 415: error = ffs_mountfs(devvp, mp, p);
! 416: }
! 417:
! 418: if (error)
! 419: goto error_2;
! 420:
! 421: /*
! 422: * Initialize FS stat information in mount struct; uses both
! 423: * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
! 424: *
! 425: * This code is common to root and non-root mounts
! 426: */
! 427: bcopy(&args, &mp->mnt_stat.mount_info.ufs_args, sizeof(args));
! 428: (void)VFS_STATFS(mp, &mp->mnt_stat, p);
! 429:
! 430: success:
! 431: if (path && (mp->mnt_flag & MNT_UPDATE)) {
! 432: /* Update clean flag after changing read-onlyness. */
! 433: fs = ump->um_fs;
! 434: if (ronly != fs->fs_ronly) {
! 435: fs->fs_ronly = ronly;
! 436: fs->fs_clean = ronly &&
! 437: (fs->fs_flags & FS_UNCLEAN) == 0 ? 1 : 0;
! 438: if (ronly)
! 439: free(fs->fs_contigdirs, M_UFSMNT);
! 440: }
! 441: if (!ronly) {
! 442: if (mp->mnt_flag & MNT_SOFTDEP)
! 443: fs->fs_flags |= FS_DOSOFTDEP;
! 444: else
! 445: fs->fs_flags &= ~FS_DOSOFTDEP;
! 446: }
! 447: ffs_sbupdate(ump, MNT_WAIT);
! 448: }
! 449: return (0);
! 450:
! 451: error_2: /* error with devvp held */
! 452: vrele (devvp);
! 453: error_1: /* no state to back out */
! 454: return (error);
! 455: }
! 456:
! 457: struct ffs_reload_args {
! 458: struct fs *fs;
! 459: struct proc *p;
! 460: struct ucred *cred;
! 461: struct vnode *devvp;
! 462: };
! 463:
! 464: int
! 465: ffs_reload_vnode(struct vnode *vp, void *args)
! 466: {
! 467: struct ffs_reload_args *fra = args;
! 468: struct inode *ip;
! 469: struct buf *bp;
! 470: int error;
! 471:
! 472: /*
! 473: * Step 4: invalidate all inactive vnodes.
! 474: */
! 475: if (vp->v_usecount == 0) {
! 476: vgonel(vp, fra->p);
! 477: return (0);
! 478: }
! 479:
! 480: /*
! 481: * Step 5: invalidate all cached file data.
! 482: */
! 483: if (vget(vp, LK_EXCLUSIVE, fra->p))
! 484: return (0);
! 485:
! 486: if (vinvalbuf(vp, 0, fra->cred, fra->p, 0, 0))
! 487: panic("ffs_reload: dirty2");
! 488:
! 489: /*
! 490: * Step 6: re-read inode data for all active vnodes.
! 491: */
! 492: ip = VTOI(vp);
! 493:
! 494: error = bread(fra->devvp,
! 495: fsbtodb(fra->fs, ino_to_fsba(fra->fs, ip->i_number)),
! 496: (int)fra->fs->fs_bsize, NOCRED, &bp);
! 497: if (error) {
! 498: brelse(bp);
! 499: vput(vp);
! 500: return (error);
! 501: }
! 502:
! 503: *ip->i_din1 = *((struct ufs1_dinode *)bp->b_data +
! 504: ino_to_fsbo(fra->fs, ip->i_number));
! 505: ip->i_effnlink = DIP(ip, nlink);
! 506: brelse(bp);
! 507: vput(vp);
! 508: return (0);
! 509: }
! 510:
! 511: /*
! 512: * Reload all incore data for a filesystem (used after running fsck on
! 513: * the root filesystem and finding things to fix). The filesystem must
! 514: * be mounted read-only.
! 515: *
! 516: * Things to do to update the mount:
! 517: * 1) invalidate all cached meta-data.
! 518: * 2) re-read superblock from disk.
! 519: * 3) re-read summary information from disk.
! 520: * 4) invalidate all inactive vnodes.
! 521: * 5) invalidate all cached file data.
! 522: * 6) re-read inode data for all active vnodes.
! 523: */
! 524: int
! 525: ffs_reload(struct mount *mountp, struct ucred *cred, struct proc *p)
! 526: {
! 527: struct vnode *devvp;
! 528: caddr_t space;
! 529: struct fs *fs, *newfs;
! 530: struct partinfo dpart;
! 531: int i, blks, size, error;
! 532: int32_t *lp;
! 533: struct buf *bp = NULL;
! 534: struct ffs_reload_args fra;
! 535:
! 536: if ((mountp->mnt_flag & MNT_RDONLY) == 0)
! 537: return (EINVAL);
! 538: /*
! 539: * Step 1: invalidate all cached meta-data.
! 540: */
! 541: devvp = VFSTOUFS(mountp)->um_devvp;
! 542: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
! 543: error = vinvalbuf(devvp, 0, cred, p, 0, 0);
! 544: VOP_UNLOCK(devvp, 0, p);
! 545: if (error)
! 546: panic("ffs_reload: dirty1");
! 547:
! 548: /*
! 549: * Step 2: re-read superblock from disk.
! 550: */
! 551: if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
! 552: size = DEV_BSIZE;
! 553: else
! 554: size = dpart.disklab->d_secsize;
! 555:
! 556: fs = VFSTOUFS(mountp)->um_fs;
! 557:
! 558: error = bread(devvp, (daddr_t)(fs->fs_sblockloc / size), SBSIZE,
! 559: NOCRED, &bp);
! 560: if (error) {
! 561: brelse(bp);
! 562: return (error);
! 563: }
! 564:
! 565: newfs = (struct fs *)bp->b_data;
! 566: if (ffs_validate(newfs) == 0) {
! 567: brelse(bp);
! 568: return (EINVAL);
! 569: }
! 570:
! 571: /*
! 572: * Copy pointer fields back into superblock before copying in XXX
! 573: * new superblock. These should really be in the ufsmount. XXX
! 574: * Note that important parameters (eg fs_ncg) are unchanged.
! 575: */
! 576: newfs->fs_csp = fs->fs_csp;
! 577: newfs->fs_maxcluster = fs->fs_maxcluster;
! 578: newfs->fs_ronly = fs->fs_ronly;
! 579: bcopy(newfs, fs, (u_int)fs->fs_sbsize);
! 580: if (fs->fs_sbsize < SBSIZE)
! 581: bp->b_flags |= B_INVAL;
! 582: brelse(bp);
! 583: mountp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
! 584: ffs1_compat_read(fs, VFSTOUFS(mountp), fs->fs_sblockloc);
! 585: ffs_oldfscompat(fs);
! 586: (void)ffs_statfs(mountp, &mountp->mnt_stat, p);
! 587: /*
! 588: * Step 3: re-read summary information from disk.
! 589: */
! 590: blks = howmany(fs->fs_cssize, fs->fs_fsize);
! 591: space = (caddr_t)fs->fs_csp;
! 592: for (i = 0; i < blks; i += fs->fs_frag) {
! 593: size = fs->fs_bsize;
! 594: if (i + fs->fs_frag > blks)
! 595: size = (blks - i) * fs->fs_fsize;
! 596: error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
! 597: NOCRED, &bp);
! 598: if (error) {
! 599: brelse(bp);
! 600: return (error);
! 601: }
! 602: bcopy(bp->b_data, space, (u_int)size);
! 603: space += size;
! 604: brelse(bp);
! 605: }
! 606: if ((fs->fs_flags & FS_DOSOFTDEP))
! 607: (void) softdep_mount(devvp, mountp, fs, cred);
! 608: /*
! 609: * We no longer know anything about clusters per cylinder group.
! 610: */
! 611: if (fs->fs_contigsumsize > 0) {
! 612: lp = fs->fs_maxcluster;
! 613: for (i = 0; i < fs->fs_ncg; i++)
! 614: *lp++ = fs->fs_contigsumsize;
! 615: }
! 616:
! 617: fra.p = p;
! 618: fra.cred = cred;
! 619: fra.fs = fs;
! 620: fra.devvp = devvp;
! 621:
! 622: error = vfs_mount_foreach_vnode(mountp, ffs_reload_vnode, &fra);
! 623:
! 624: return (error);
! 625: }
! 626:
! 627: /*
! 628: * Checks if a super block is sane enough to be mounted.
! 629: */
! 630: int
! 631: ffs_validate(struct fs *fsp)
! 632: {
! 633: #ifdef FFS2
! 634: if (fsp->fs_magic != FS_UFS2_MAGIC && fsp->fs_magic != FS_UFS1_MAGIC)
! 635: return (0); /* Invalid magic */
! 636: #else
! 637: if (fsp->fs_magic != FS_UFS1_MAGIC)
! 638: return (0); /* Invalid magic */
! 639: #endif /* FFS2 */
! 640:
! 641: if ((u_int)fsp->fs_bsize > MAXBSIZE)
! 642: return (0); /* Invalid block size */
! 643:
! 644: if ((u_int)fsp->fs_bsize < sizeof(struct fs))
! 645: return (0); /* Invalid block size */
! 646:
! 647: if ((u_int)fsp->fs_sbsize > SBSIZE)
! 648: return (0); /* Invalid super block size */
! 649:
! 650: if ((u_int)fsp->fs_frag > MAXFRAG || fragtbl[fsp->fs_frag] == NULL)
! 651: return (0); /* Invalid number of fragments */
! 652:
! 653: return (1); /* Super block is okay */
! 654: }
! 655:
! 656: /*
! 657: * Possible locations for the super-block.
! 658: */
! 659: const int sbtry[] = SBLOCKSEARCH;
! 660:
! 661: /*
! 662: * Common code for mount and mountroot
! 663: */
! 664: int
! 665: ffs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p)
! 666: {
! 667: struct ufsmount *ump;
! 668: struct buf *bp;
! 669: struct fs *fs;
! 670: dev_t dev;
! 671: struct partinfo dpart;
! 672: caddr_t space;
! 673: daddr64_t sbloc;
! 674: int error, i, blks, size, ronly;
! 675: int32_t *lp;
! 676: size_t strsize;
! 677: struct ucred *cred;
! 678: u_int64_t maxfilesize; /* XXX */
! 679:
! 680: dev = devvp->v_rdev;
! 681: cred = p ? p->p_ucred : NOCRED;
! 682: /*
! 683: * Disallow multiple mounts of the same device.
! 684: * Disallow mounting of a device that is currently in use
! 685: * (except for root, which might share swap device for miniroot).
! 686: * Flush out any old buffers remaining from a previous use.
! 687: */
! 688: if ((error = vfs_mountedon(devvp)) != 0)
! 689: return (error);
! 690: if (vcount(devvp) > 1 && devvp != rootvp)
! 691: return (EBUSY);
! 692: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
! 693: error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0);
! 694: VOP_UNLOCK(devvp, 0, p);
! 695: if (error)
! 696: return (error);
! 697:
! 698: ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
! 699: error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
! 700: if (error)
! 701: return (error);
! 702: if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
! 703: size = DEV_BSIZE;
! 704: else
! 705: size = dpart.disklab->d_secsize;
! 706:
! 707: bp = NULL;
! 708: ump = NULL;
! 709:
! 710: /*
! 711: * Try reading the super-block in each of its possible locations.
! 712: */
! 713: for (i = 0; sbtry[i] != -1; i++) {
! 714: if (bp != NULL) {
! 715: bp->b_flags |= B_NOCACHE;
! 716: brelse(bp);
! 717: bp = NULL;
! 718: }
! 719:
! 720: error = bread(devvp, sbtry[i] / size, SBSIZE, cred, &bp);
! 721: if (error)
! 722: goto out;
! 723:
! 724: fs = (struct fs *) bp->b_data;
! 725: sbloc = sbtry[i];
! 726:
! 727: #if 0
! 728: if (fs->fs_magic == FS_UFS2_MAGIC) {
! 729: printf("ffs_mountfs(): Sorry, no UFS2 support (yet)\n");
! 730: error = EFTYPE;
! 731: goto out;
! 732: }
! 733: #endif
! 734:
! 735: /*
! 736: * Do not look for an FFS1 file system at SBLOCK_UFS2. Doing so
! 737: * will find the wrong super-block for file systems with 64k
! 738: * block size.
! 739: */
! 740: if (fs->fs_magic == FS_UFS1_MAGIC && sbloc == SBLOCK_UFS2)
! 741: continue;
! 742:
! 743: if (ffs_validate(fs))
! 744: break; /* Super block validated */
! 745: }
! 746:
! 747: if (sbtry[i] == -1) {
! 748: error = EINVAL;
! 749: goto out;
! 750: }
! 751:
! 752: fs->fs_fmod = 0;
! 753: fs->fs_flags &= ~FS_UNCLEAN;
! 754: if (fs->fs_clean == 0) {
! 755: #if 0
! 756: /*
! 757: * It is safe mount unclean file system
! 758: * if it was previously mounted with softdep
! 759: * but we may loss space and must
! 760: * sometimes run fsck manually.
! 761: */
! 762: if (fs->fs_flags & FS_DOSOFTDEP)
! 763: printf(
! 764: "WARNING: %s was not properly unmounted\n",
! 765: fs->fs_fsmnt);
! 766: else
! 767: #endif
! 768: if (ronly || (mp->mnt_flag & MNT_FORCE)) {
! 769: printf(
! 770: "WARNING: %s was not properly unmounted\n",
! 771: fs->fs_fsmnt);
! 772: } else {
! 773: printf(
! 774: "WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n",
! 775: fs->fs_fsmnt);
! 776: error = EROFS;
! 777: goto out;
! 778: }
! 779: }
! 780:
! 781: if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) {
! 782: #ifndef SMALL_KERNEL
! 783: printf("ffs_mountfs(): obsolete rotational table format, "
! 784: "please use fsck_ffs(8) -c 1\n");
! 785: #endif
! 786: error = EFTYPE;
! 787: goto out;
! 788: }
! 789:
! 790: ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
! 791: bzero(ump, sizeof *ump);
! 792: ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
! 793: M_WAITOK);
! 794:
! 795: if (fs->fs_magic == FS_UFS1_MAGIC)
! 796: ump->um_fstype = UM_UFS1;
! 797: #ifdef FFS2
! 798: else
! 799: ump->um_fstype = UM_UFS2;
! 800: #endif
! 801:
! 802: bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
! 803: if (fs->fs_sbsize < SBSIZE)
! 804: bp->b_flags |= B_INVAL;
! 805: brelse(bp);
! 806: bp = NULL;
! 807: fs = ump->um_fs;
! 808:
! 809: ffs1_compat_read(fs, ump, sbloc);
! 810:
! 811: if (fs->fs_clean == 0)
! 812: fs->fs_flags |= FS_UNCLEAN;
! 813: fs->fs_ronly = ronly;
! 814: size = fs->fs_cssize;
! 815: blks = howmany(size, fs->fs_fsize);
! 816: if (fs->fs_contigsumsize > 0)
! 817: size += fs->fs_ncg * sizeof(int32_t);
! 818: space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
! 819: fs->fs_csp = (struct csum *)space;
! 820: for (i = 0; i < blks; i += fs->fs_frag) {
! 821: size = fs->fs_bsize;
! 822: if (i + fs->fs_frag > blks)
! 823: size = (blks - i) * fs->fs_fsize;
! 824: error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
! 825: cred, &bp);
! 826: if (error) {
! 827: free(fs->fs_csp, M_UFSMNT);
! 828: goto out;
! 829: }
! 830: bcopy(bp->b_data, space, (u_int)size);
! 831: space += size;
! 832: brelse(bp);
! 833: bp = NULL;
! 834: }
! 835: if (fs->fs_contigsumsize > 0) {
! 836: fs->fs_maxcluster = lp = (int32_t *)space;
! 837: for (i = 0; i < fs->fs_ncg; i++)
! 838: *lp++ = fs->fs_contigsumsize;
! 839: }
! 840: mp->mnt_data = (qaddr_t)ump;
! 841: mp->mnt_stat.f_fsid.val[0] = (long)dev;
! 842: /* Use on-disk fsid if it exists, else fake it */
! 843: if (fs->fs_id[0] != 0 && fs->fs_id[1] != 0)
! 844: mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1];
! 845: else
! 846: mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
! 847: mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
! 848: mp->mnt_flag |= MNT_LOCAL;
! 849: ump->um_mountp = mp;
! 850: ump->um_dev = dev;
! 851: ump->um_devvp = devvp;
! 852: ump->um_nindir = fs->fs_nindir;
! 853: ump->um_bptrtodb = fs->fs_fsbtodb;
! 854: ump->um_seqinc = fs->fs_frag;
! 855: for (i = 0; i < MAXQUOTAS; i++)
! 856: ump->um_quotas[i] = NULLVP;
! 857:
! 858: devvp->v_specmountpoint = mp;
! 859: ffs_oldfscompat(fs);
! 860:
! 861: if (ronly)
! 862: fs->fs_contigdirs = NULL;
! 863: else {
! 864: fs->fs_contigdirs = (u_int8_t*)malloc((u_long)fs->fs_ncg,
! 865: M_UFSMNT, M_WAITOK);
! 866: bzero(fs->fs_contigdirs, fs->fs_ncg);
! 867: }
! 868:
! 869: /*
! 870: * Set FS local "last mounted on" information (NULL pad)
! 871: */
! 872: copystr(mp->mnt_stat.f_mntonname, /* mount point*/
! 873: fs->fs_fsmnt, /* copy area*/
! 874: sizeof(fs->fs_fsmnt) - 1, /* max size*/
! 875: &strsize); /* real size*/
! 876: bzero(fs->fs_fsmnt + strsize, sizeof(fs->fs_fsmnt) - strsize);
! 877:
! 878: #if 0
! 879: if( mp->mnt_flag & MNT_ROOTFS) {
! 880: /*
! 881: * Root mount; update timestamp in mount structure.
! 882: * this will be used by the common root mount code
! 883: * to update the system clock.
! 884: */
! 885: mp->mnt_time = fs->fs_time;
! 886: }
! 887: #endif
! 888:
! 889: /*
! 890: * XXX
! 891: * Limit max file size. Even though ffs can handle files up to 16TB,
! 892: * we do limit the max file to 2^31 pages to prevent overflow of
! 893: * a 32-bit unsigned int. The buffer cache has its own checks but
! 894: * a little added paranoia never hurts.
! 895: */
! 896: ump->um_savedmaxfilesize = fs->fs_maxfilesize; /* XXX */
! 897: maxfilesize = (u_int64_t)0x80000000 * MIN(PAGE_SIZE, fs->fs_bsize) - 1;
! 898: if (fs->fs_maxfilesize > maxfilesize) /* XXX */
! 899: fs->fs_maxfilesize = maxfilesize; /* XXX */
! 900: if (ronly == 0) {
! 901: if ((fs->fs_flags & FS_DOSOFTDEP) &&
! 902: (error = softdep_mount(devvp, mp, fs, cred)) != 0) {
! 903: free(fs->fs_csp, M_UFSMNT);
! 904: free(fs->fs_contigdirs, M_UFSMNT);
! 905: goto out;
! 906: }
! 907: fs->fs_fmod = 1;
! 908: fs->fs_clean = 0;
! 909: if (mp->mnt_flag & MNT_SOFTDEP)
! 910: fs->fs_flags |= FS_DOSOFTDEP;
! 911: else
! 912: fs->fs_flags &= ~FS_DOSOFTDEP;
! 913: (void) ffs_sbupdate(ump, MNT_WAIT);
! 914: }
! 915: return (0);
! 916: out:
! 917: devvp->v_specmountpoint = NULL;
! 918: if (bp)
! 919: brelse(bp);
! 920: (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
! 921: if (ump) {
! 922: free(ump->um_fs, M_UFSMNT);
! 923: free(ump, M_UFSMNT);
! 924: mp->mnt_data = (qaddr_t)0;
! 925: }
! 926: return (error);
! 927: }
! 928:
! 929: /*
! 930: * Sanity checks for old file systems.
! 931: */
! 932: int
! 933: ffs_oldfscompat(struct fs *fs)
! 934: {
! 935: int i;
! 936:
! 937: fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */
! 938: fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */
! 939: if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
! 940: fs->fs_nrpos = 8; /* XXX */
! 941: if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
! 942: u_int64_t sizepb = fs->fs_bsize; /* XXX */
! 943: /* XXX */
! 944: fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */
! 945: for (i = 0; i < NIADDR; i++) { /* XXX */
! 946: sizepb *= NINDIR(fs); /* XXX */
! 947: fs->fs_maxfilesize += sizepb; /* XXX */
! 948: } /* XXX */
! 949: fs->fs_qbmask = ~fs->fs_bmask; /* XXX */
! 950: fs->fs_qfmask = ~fs->fs_fmask; /* XXX */
! 951: } /* XXX */
! 952: if (fs->fs_avgfilesize <= 0) /* XXX */
! 953: fs->fs_avgfilesize = AVFILESIZ; /* XXX */
! 954: if (fs->fs_avgfpdir <= 0) /* XXX */
! 955: fs->fs_avgfpdir = AFPDIR; /* XXX */
! 956: return (0);
! 957: }
! 958:
! 959: /*
! 960: * Auxiliary function for reading FFS1 super blocks.
! 961: */
! 962: void
! 963: ffs1_compat_read(struct fs *fs, struct ufsmount *ump, daddr64_t sbloc)
! 964: {
! 965: if (fs->fs_magic == FS_UFS2_MAGIC)
! 966: return; /* UFS2 */
! 967: #if 0
! 968: if (fs->fs_ffs1_flags & FS_FLAGS_UPDATED)
! 969: return; /* Already updated */
! 970: #endif
! 971: fs->fs_flags = fs->fs_ffs1_flags;
! 972: fs->fs_sblockloc = sbloc;
! 973: fs->fs_maxbsize = fs->fs_bsize;
! 974: fs->fs_time = fs->fs_ffs1_time;
! 975: fs->fs_size = fs->fs_ffs1_size;
! 976: fs->fs_dsize = fs->fs_ffs1_dsize;
! 977: fs->fs_csaddr = fs->fs_ffs1_csaddr;
! 978: fs->fs_cstotal.cs_ndir = fs->fs_ffs1_cstotal.cs_ndir;
! 979: fs->fs_cstotal.cs_nbfree = fs->fs_ffs1_cstotal.cs_nbfree;
! 980: fs->fs_cstotal.cs_nifree = fs->fs_ffs1_cstotal.cs_nifree;
! 981: fs->fs_cstotal.cs_nffree = fs->fs_ffs1_cstotal.cs_nffree;
! 982: fs->fs_ffs1_flags |= FS_FLAGS_UPDATED;
! 983: }
! 984:
! 985: /*
! 986: * Auxiliary function for writing FFS1 super blocks.
! 987: */
! 988: void
! 989: ffs1_compat_write(struct fs *fs, struct ufsmount *ump)
! 990: {
! 991: if (fs->fs_magic != FS_UFS1_MAGIC)
! 992: return; /* UFS2 */
! 993:
! 994: fs->fs_ffs1_time = fs->fs_time;
! 995: fs->fs_ffs1_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir;
! 996: fs->fs_ffs1_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree;
! 997: fs->fs_ffs1_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree;
! 998: fs->fs_ffs1_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree;
! 999: }
! 1000:
! 1001: /*
! 1002: * unmount system call
! 1003: */
! 1004: int
! 1005: ffs_unmount(struct mount *mp, int mntflags, struct proc *p)
! 1006: {
! 1007: struct ufsmount *ump;
! 1008: struct fs *fs;
! 1009: int error, flags;
! 1010:
! 1011: flags = 0;
! 1012: if (mntflags & MNT_FORCE)
! 1013: flags |= FORCECLOSE;
! 1014:
! 1015: ump = VFSTOUFS(mp);
! 1016: fs = ump->um_fs;
! 1017: if (mp->mnt_flag & MNT_SOFTDEP)
! 1018: error = softdep_flushfiles(mp, flags, p);
! 1019: else
! 1020: error = ffs_flushfiles(mp, flags, p);
! 1021: if (error != 0)
! 1022: return (error);
! 1023:
! 1024: if (fs->fs_ronly == 0) {
! 1025: fs->fs_clean = (fs->fs_flags & FS_UNCLEAN) ? 0 : 1;
! 1026: error = ffs_sbupdate(ump, MNT_WAIT);
! 1027: /* ignore write errors if mounted RW on read-only device */
! 1028: if (error && error != EROFS) {
! 1029: fs->fs_clean = 0;
! 1030: return (error);
! 1031: }
! 1032: free(fs->fs_contigdirs, M_UFSMNT);
! 1033: }
! 1034: ump->um_devvp->v_specmountpoint = NULL;
! 1035:
! 1036: vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, p, 0, 0);
! 1037: error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
! 1038: NOCRED, p);
! 1039: vrele(ump->um_devvp);
! 1040: free(fs->fs_csp, M_UFSMNT);
! 1041: free(fs, M_UFSMNT);
! 1042: free(ump, M_UFSMNT);
! 1043: mp->mnt_data = (qaddr_t)0;
! 1044: mp->mnt_flag &= ~MNT_LOCAL;
! 1045: return (error);
! 1046: }
! 1047:
! 1048: /*
! 1049: * Flush out all the files in a filesystem.
! 1050: */
! 1051: int
! 1052: ffs_flushfiles(struct mount *mp, int flags, struct proc *p)
! 1053: {
! 1054: struct ufsmount *ump;
! 1055: int error;
! 1056:
! 1057: ump = VFSTOUFS(mp);
! 1058: if (mp->mnt_flag & MNT_QUOTA) {
! 1059: int i;
! 1060: if ((error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) != 0)
! 1061: return (error);
! 1062: for (i = 0; i < MAXQUOTAS; i++) {
! 1063: if (ump->um_quotas[i] == NULLVP)
! 1064: continue;
! 1065: quotaoff(p, mp, i);
! 1066: }
! 1067: /*
! 1068: * Here we fall through to vflush again to ensure
! 1069: * that we have gotten rid of all the system vnodes.
! 1070: */
! 1071: }
! 1072:
! 1073: /*
! 1074: * Flush all the files.
! 1075: */
! 1076: if ((error = vflush(mp, NULL, flags)) != 0)
! 1077: return (error);
! 1078: /*
! 1079: * Flush filesystem metadata.
! 1080: */
! 1081: vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p);
! 1082: error = VOP_FSYNC(ump->um_devvp, p->p_ucred, MNT_WAIT, p);
! 1083: VOP_UNLOCK(ump->um_devvp, 0, p);
! 1084: return (error);
! 1085: }
! 1086:
! 1087: /*
! 1088: * Get file system statistics.
! 1089: */
! 1090: int
! 1091: ffs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
! 1092: {
! 1093: struct ufsmount *ump;
! 1094: struct fs *fs;
! 1095:
! 1096: ump = VFSTOUFS(mp);
! 1097: fs = ump->um_fs;
! 1098:
! 1099: #ifdef FFS2
! 1100: if (fs->fs_magic != FS_MAGIC && fs->fs_magic != FS_UFS2_MAGIC)
! 1101: panic("ffs_statfs");
! 1102: #else
! 1103: if (fs->fs_magic != FS_MAGIC)
! 1104: panic("ffs_statfs");
! 1105: #endif /* FFS2 */
! 1106:
! 1107: sbp->f_bsize = fs->fs_fsize;
! 1108: sbp->f_iosize = fs->fs_bsize;
! 1109: sbp->f_blocks = fs->fs_dsize;
! 1110: sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
! 1111: fs->fs_cstotal.cs_nffree;
! 1112: sbp->f_bavail = sbp->f_bfree - ((int64_t)fs->fs_dsize * fs->fs_minfree / 100);
! 1113: sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO;
! 1114: sbp->f_ffree = fs->fs_cstotal.cs_nifree;
! 1115: if (sbp != &mp->mnt_stat) {
! 1116: bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
! 1117: bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
! 1118: bcopy(&mp->mnt_stat.mount_info.ufs_args,
! 1119: &sbp->mount_info.ufs_args, sizeof(struct ufs_args));
! 1120: }
! 1121: strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
! 1122:
! 1123: return (0);
! 1124: }
! 1125:
! 1126: struct ffs_sync_args {
! 1127: int allerror;
! 1128: struct proc *p;
! 1129: int waitfor;
! 1130: struct ucred *cred;
! 1131: };
! 1132:
! 1133: int
! 1134: ffs_sync_vnode(struct vnode *vp, void *arg) {
! 1135: struct ffs_sync_args *fsa = arg;
! 1136: struct inode *ip;
! 1137: int error;
! 1138:
! 1139: ip = VTOI(vp);
! 1140: if (vp->v_type == VNON ||
! 1141: ((ip->i_flag &
! 1142: (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
! 1143: LIST_EMPTY(&vp->v_dirtyblkhd)) ) {
! 1144: return (0);
! 1145: }
! 1146:
! 1147: if (vget(vp, LK_EXCLUSIVE | LK_NOWAIT, fsa->p))
! 1148: return (0);
! 1149:
! 1150: if ((error = VOP_FSYNC(vp, fsa->cred, fsa->waitfor, fsa->p)))
! 1151: fsa->allerror = error;
! 1152: VOP_UNLOCK(vp, 0, fsa->p);
! 1153: vrele(vp);
! 1154:
! 1155: return (0);
! 1156: }
! 1157:
! 1158: /*
! 1159: * Go through the disk queues to initiate sandbagged IO;
! 1160: * go through the inodes to write those that have been modified;
! 1161: * initiate the writing of the super block if it has been modified.
! 1162: *
! 1163: * Should always be called with the mount point locked.
! 1164: */
! 1165: int
! 1166: ffs_sync(struct mount *mp, int waitfor, struct ucred *cred, struct proc *p)
! 1167: {
! 1168: struct ufsmount *ump = VFSTOUFS(mp);
! 1169: struct fs *fs;
! 1170: int error, allerror = 0, count;
! 1171: struct ffs_sync_args fsa;
! 1172:
! 1173: fs = ump->um_fs;
! 1174: /*
! 1175: * Write back modified superblock.
! 1176: * Consistency check that the superblock
! 1177: * is still in the buffer cache.
! 1178: */
! 1179: if (fs->fs_fmod != 0 && fs->fs_ronly != 0) {
! 1180: printf("fs = %s\n", fs->fs_fsmnt);
! 1181: panic("update: rofs mod");
! 1182: }
! 1183: loop:
! 1184: /*
! 1185: * Write back each (modified) inode.
! 1186: */
! 1187: fsa.allerror = 0;
! 1188: fsa.p = p;
! 1189: fsa.cred = cred;
! 1190: fsa.waitfor = waitfor;
! 1191:
! 1192: /*
! 1193: * Don't traverse the vnode list if we want to skip all of them.
! 1194: */
! 1195: if (waitfor != MNT_LAZY) {
! 1196: vfs_mount_foreach_vnode(mp, ffs_sync_vnode, &fsa);
! 1197: allerror = fsa.allerror;
! 1198: }
! 1199:
! 1200: /*
! 1201: * Force stale file system control information to be flushed.
! 1202: */
! 1203: if ((ump->um_mountp->mnt_flag & MNT_SOFTDEP) && waitfor == MNT_WAIT) {
! 1204: if ((error = softdep_flushworklist(ump->um_mountp, &count, p)))
! 1205: allerror = error;
! 1206: /* Flushed work items may create new vnodes to clean */
! 1207: if (count)
! 1208: goto loop;
! 1209: }
! 1210: if (waitfor != MNT_LAZY) {
! 1211: vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p);
! 1212: if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) != 0)
! 1213: allerror = error;
! 1214: VOP_UNLOCK(ump->um_devvp, 0, p);
! 1215: }
! 1216: qsync(mp);
! 1217: /*
! 1218: * Write back modified superblock.
! 1219: */
! 1220:
! 1221: if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0)
! 1222: allerror = error;
! 1223:
! 1224: return (allerror);
! 1225: }
! 1226:
! 1227: /*
! 1228: * Look up a FFS dinode number to find its incore vnode, otherwise read it
! 1229: * in from disk. If it is in core, wait for the lock bit to clear, then
! 1230: * return the inode locked. Detection and handling of mount points must be
! 1231: * done by the calling routine.
! 1232: */
! 1233: int
! 1234: ffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
! 1235: {
! 1236: struct fs *fs;
! 1237: struct inode *ip;
! 1238: struct ufs1_dinode *dp1;
! 1239: #ifdef FFS2
! 1240: struct ufs2_dinode *dp2;
! 1241: #endif
! 1242: struct ufsmount *ump;
! 1243: struct buf *bp;
! 1244: struct vnode *vp;
! 1245: dev_t dev;
! 1246: int error;
! 1247:
! 1248: ump = VFSTOUFS(mp);
! 1249: dev = ump->um_dev;
! 1250: retry:
! 1251: if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
! 1252: return (0);
! 1253:
! 1254: /* Allocate a new vnode/inode. */
! 1255: if ((error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) != 0) {
! 1256: *vpp = NULL;
! 1257: return (error);
! 1258: }
! 1259: #ifdef VFSDEBUG
! 1260: vp->v_flag |= VLOCKSWORK;
! 1261: #endif
! 1262: /* XXX - we use the same pool for ffs and mfs */
! 1263: ip = pool_get(&ffs_ino_pool, PR_WAITOK);
! 1264: bzero((caddr_t)ip, sizeof(struct inode));
! 1265: lockinit(&ip->i_lock, PINOD, "inode", 0, 0);
! 1266: ip->i_ump = ump;
! 1267: VREF(ip->i_devvp);
! 1268: vp->v_data = ip;
! 1269: ip->i_vnode = vp;
! 1270: ip->i_fs = fs = ump->um_fs;
! 1271: ip->i_dev = dev;
! 1272: ip->i_number = ino;
! 1273: ip->i_vtbl = &ffs_vtbl;
! 1274:
! 1275: /*
! 1276: * Put it onto its hash chain and lock it so that other requests for
! 1277: * this inode will block if they arrive while we are sleeping waiting
! 1278: * for old data structures to be purged or for the contents of the
! 1279: * disk portion of this inode to be read.
! 1280: */
! 1281: error = ufs_ihashins(ip);
! 1282:
! 1283: if (error) {
! 1284: /*
! 1285: * VOP_INACTIVE will treat this as a stale file
! 1286: * and recycle it quickly
! 1287: */
! 1288: vrele(vp);
! 1289:
! 1290: if (error == EEXIST)
! 1291: goto retry;
! 1292:
! 1293: return (error);
! 1294: }
! 1295:
! 1296:
! 1297: /* Read in the disk contents for the inode, copy into the inode. */
! 1298: error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
! 1299: (int)fs->fs_bsize, NOCRED, &bp);
! 1300: if (error) {
! 1301: /*
! 1302: * The inode does not contain anything useful, so it would
! 1303: * be misleading to leave it on its hash chain. With mode
! 1304: * still zero, it will be unlinked and returned to the free
! 1305: * list by vput().
! 1306: */
! 1307: vput(vp);
! 1308: brelse(bp);
! 1309: *vpp = NULL;
! 1310: return (error);
! 1311: }
! 1312:
! 1313: #ifdef FFS2
! 1314: if (ip->i_ump->um_fstype == UM_UFS2) {
! 1315: ip->i_din2 = pool_get(&ffs_dinode2_pool, PR_WAITOK);
! 1316: dp2 = (struct ufs2_dinode *) bp->b_data + ino_to_fsbo(fs, ino);
! 1317: *ip->i_din2 = *dp2;
! 1318: } else
! 1319: #endif
! 1320: {
! 1321: ip->i_din1 = pool_get(&ffs_dinode1_pool, PR_WAITOK);
! 1322: dp1 = (struct ufs1_dinode *) bp->b_data + ino_to_fsbo(fs, ino);
! 1323: *ip->i_din1 = *dp1;
! 1324: }
! 1325:
! 1326: brelse(bp);
! 1327:
! 1328: if (DOINGSOFTDEP(vp))
! 1329: softdep_load_inodeblock(ip);
! 1330: else
! 1331: ip->i_effnlink = DIP(ip, nlink);
! 1332:
! 1333: /*
! 1334: * Initialize the vnode from the inode, check for aliases.
! 1335: * Note that the underlying vnode may have changed.
! 1336: */
! 1337: error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp);
! 1338: if (error) {
! 1339: vput(vp);
! 1340: *vpp = NULL;
! 1341: return (error);
! 1342: }
! 1343:
! 1344: /*
! 1345: * Set up a generation number for this inode if it does not
! 1346: * already have one. This should only happen on old filesystems.
! 1347: */
! 1348: if (DIP(ip, gen) == 0) {
! 1349: DIP_ASSIGN(ip, gen, arc4random() & INT_MAX);
! 1350: if (DIP(ip, gen) == 0 || DIP(ip, gen) == -1)
! 1351: DIP_ASSIGN(ip, gen, 1); /* Shouldn't happen */
! 1352: if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
! 1353: ip->i_flag |= IN_MODIFIED;
! 1354: }
! 1355:
! 1356: /*
! 1357: * Ensure that uid and gid are correct. This is a temporary
! 1358: * fix until fsck has been changed to do the update.
! 1359: */
! 1360: if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_inodefmt < FS_44INODEFMT) {
! 1361: ip->i_ffs1_uid = ip->i_din1->di_ouid;
! 1362: ip->i_ffs1_gid = ip->i_din1->di_ogid;
! 1363: }
! 1364:
! 1365: *vpp = vp;
! 1366:
! 1367: return (0);
! 1368: }
! 1369:
! 1370: /*
! 1371: * File handle to vnode
! 1372: *
! 1373: * Have to be really careful about stale file handles:
! 1374: * - check that the inode number is valid
! 1375: * - call ffs_vget() to get the locked inode
! 1376: * - check for an unallocated inode (i_mode == 0)
! 1377: */
! 1378: int
! 1379: ffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
! 1380: {
! 1381: struct ufid *ufhp;
! 1382: struct fs *fs;
! 1383:
! 1384: ufhp = (struct ufid *)fhp;
! 1385: fs = VFSTOUFS(mp)->um_fs;
! 1386: if (ufhp->ufid_ino < ROOTINO ||
! 1387: ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
! 1388: return (ESTALE);
! 1389: return (ufs_fhtovp(mp, ufhp, vpp));
! 1390: }
! 1391:
! 1392: /*
! 1393: * Vnode pointer to File handle
! 1394: */
! 1395: /* ARGSUSED */
! 1396: int
! 1397: ffs_vptofh(struct vnode *vp, struct fid *fhp)
! 1398: {
! 1399: struct inode *ip;
! 1400: struct ufid *ufhp;
! 1401:
! 1402: ip = VTOI(vp);
! 1403: ufhp = (struct ufid *)fhp;
! 1404: ufhp->ufid_len = sizeof(struct ufid);
! 1405: ufhp->ufid_ino = ip->i_number;
! 1406: ufhp->ufid_gen = DIP(ip, gen);
! 1407:
! 1408: return (0);
! 1409: }
! 1410:
! 1411: /*
! 1412: * Write a superblock and associated information back to disk.
! 1413: */
! 1414: int
! 1415: ffs_sbupdate(struct ufsmount *mp, int waitfor)
! 1416: {
! 1417: struct fs *dfs, *fs = mp->um_fs;
! 1418: struct buf *bp;
! 1419: int blks;
! 1420: caddr_t space;
! 1421: int i, size, error, allerror = 0;
! 1422:
! 1423: /*
! 1424: * First write back the summary information.
! 1425: */
! 1426: blks = howmany(fs->fs_cssize, fs->fs_fsize);
! 1427: space = (caddr_t)fs->fs_csp;
! 1428: for (i = 0; i < blks; i += fs->fs_frag) {
! 1429: size = fs->fs_bsize;
! 1430: if (i + fs->fs_frag > blks)
! 1431: size = (blks - i) * fs->fs_fsize;
! 1432: bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
! 1433: size, 0, 0);
! 1434: bcopy(space, bp->b_data, (u_int)size);
! 1435: space += size;
! 1436: if (waitfor != MNT_WAIT)
! 1437: bawrite(bp);
! 1438: else if ((error = bwrite(bp)))
! 1439: allerror = error;
! 1440: }
! 1441:
! 1442: /*
! 1443: * Now write back the superblock itself. If any errors occurred
! 1444: * up to this point, then fail so that the superblock avoids
! 1445: * being written out as clean.
! 1446: */
! 1447: if (allerror) {
! 1448: return (allerror);
! 1449: }
! 1450:
! 1451: bp = getblk(mp->um_devvp,
! 1452: fs->fs_sblockloc >> (fs->fs_fshift - fs->fs_fsbtodb),
! 1453: (int)fs->fs_sbsize, 0, 0);
! 1454: fs->fs_fmod = 0;
! 1455: fs->fs_time = time_second;
! 1456: bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
! 1457: /* Restore compatibility to old file systems. XXX */
! 1458: dfs = (struct fs *)bp->b_data; /* XXX */
! 1459: if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
! 1460: dfs->fs_nrpos = -1; /* XXX */
! 1461: if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
! 1462: int32_t *lp, tmp; /* XXX */
! 1463: /* XXX */
! 1464: lp = (int32_t *)&dfs->fs_qbmask; /* XXX */
! 1465: tmp = lp[4]; /* XXX */
! 1466: for (i = 4; i > 0; i--) /* XXX */
! 1467: lp[i] = lp[i-1]; /* XXX */
! 1468: lp[0] = tmp; /* XXX */
! 1469: } /* XXX */
! 1470: dfs->fs_maxfilesize = mp->um_savedmaxfilesize; /* XXX */
! 1471:
! 1472: ffs1_compat_write(dfs, mp);
! 1473:
! 1474: if (waitfor != MNT_WAIT)
! 1475: bawrite(bp);
! 1476: else if ((error = bwrite(bp)))
! 1477: allerror = error;
! 1478:
! 1479: return (allerror);
! 1480: }
! 1481:
! 1482: int
! 1483: ffs_init(struct vfsconf *vfsp)
! 1484: {
! 1485: static int done;
! 1486:
! 1487: if (done)
! 1488: return (0);
! 1489:
! 1490: done = 1;
! 1491:
! 1492: pool_init(&ffs_ino_pool, sizeof(struct inode), 0, 0, 0, "ffsino",
! 1493: &pool_allocator_nointr);
! 1494: pool_init(&ffs_dinode1_pool, sizeof(struct ufs1_dinode), 0, 0, 0,
! 1495: "dino1pl", &pool_allocator_nointr);
! 1496: #ifdef FFS2
! 1497: pool_init(&ffs_dinode2_pool, sizeof(struct ufs2_dinode), 0, 0, 0,
! 1498: "dino2pl", &pool_allocator_nointr);
! 1499: #endif
! 1500:
! 1501: softdep_initialize();
! 1502:
! 1503: return (ufs_init(vfsp));
! 1504: }
! 1505:
! 1506: /*
! 1507: * fast filesystem related variables.
! 1508: */
! 1509: int
! 1510: ffs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
! 1511: size_t newlen, struct proc *p)
! 1512: {
! 1513: extern int doclusterread, doclusterwrite, doreallocblks, doasyncfree;
! 1514: #ifdef FFS_SOFTUPDATES
! 1515: extern int max_softdeps, tickdelay, stat_worklist_push;
! 1516: extern int stat_blk_limit_push, stat_ino_limit_push, stat_blk_limit_hit;
! 1517: extern int stat_ino_limit_hit, stat_sync_limit_hit, stat_indir_blk_ptrs;
! 1518: extern int stat_inode_bitmap, stat_direct_blk_ptrs, stat_dir_entry;
! 1519: #endif
! 1520:
! 1521: /* all sysctl names at this level are terminal */
! 1522: if (namelen != 1)
! 1523: return (ENOTDIR); /* overloaded */
! 1524:
! 1525: switch (name[0]) {
! 1526: case FFS_CLUSTERREAD:
! 1527: return (sysctl_int(oldp, oldlenp, newp, newlen,
! 1528: &doclusterread));
! 1529: case FFS_CLUSTERWRITE:
! 1530: return (sysctl_int(oldp, oldlenp, newp, newlen,
! 1531: &doclusterwrite));
! 1532: case FFS_REALLOCBLKS:
! 1533: return (sysctl_int(oldp, oldlenp, newp, newlen,
! 1534: &doreallocblks));
! 1535: case FFS_ASYNCFREE:
! 1536: return (sysctl_int(oldp, oldlenp, newp, newlen, &doasyncfree));
! 1537: #ifdef FFS_SOFTUPDATES
! 1538: case FFS_MAX_SOFTDEPS:
! 1539: return (sysctl_int(oldp, oldlenp, newp, newlen, &max_softdeps));
! 1540: case FFS_SD_TICKDELAY:
! 1541: return (sysctl_int(oldp, oldlenp, newp, newlen, &tickdelay));
! 1542: case FFS_SD_WORKLIST_PUSH:
! 1543: return (sysctl_rdint(oldp, oldlenp, newp, stat_worklist_push));
! 1544: case FFS_SD_BLK_LIMIT_PUSH:
! 1545: return (sysctl_rdint(oldp, oldlenp, newp, stat_blk_limit_push));
! 1546: case FFS_SD_INO_LIMIT_PUSH:
! 1547: return (sysctl_rdint(oldp, oldlenp, newp, stat_ino_limit_push));
! 1548: case FFS_SD_BLK_LIMIT_HIT:
! 1549: return (sysctl_rdint(oldp, oldlenp, newp, stat_blk_limit_hit));
! 1550: case FFS_SD_INO_LIMIT_HIT:
! 1551: return (sysctl_rdint(oldp, oldlenp, newp, stat_ino_limit_hit));
! 1552: case FFS_SD_SYNC_LIMIT_HIT:
! 1553: return (sysctl_rdint(oldp, oldlenp, newp, stat_sync_limit_hit));
! 1554: case FFS_SD_INDIR_BLK_PTRS:
! 1555: return (sysctl_rdint(oldp, oldlenp, newp, stat_indir_blk_ptrs));
! 1556: case FFS_SD_INODE_BITMAP:
! 1557: return (sysctl_rdint(oldp, oldlenp, newp, stat_inode_bitmap));
! 1558: case FFS_SD_DIRECT_BLK_PTRS:
! 1559: return (sysctl_rdint(oldp, oldlenp, newp, stat_direct_blk_ptrs));
! 1560: case FFS_SD_DIR_ENTRY:
! 1561: return (sysctl_rdint(oldp, oldlenp, newp, stat_dir_entry));
! 1562: #endif
! 1563: #ifdef UFS_DIRHASH
! 1564: case FFS_DIRHASH_DIRSIZE:
! 1565: return (sysctl_int(oldp, oldlenp, newp, newlen,
! 1566: &ufs_mindirhashsize));
! 1567: case FFS_DIRHASH_MAXMEM:
! 1568: return (sysctl_int(oldp, oldlenp, newp, newlen,
! 1569: &ufs_dirhashmaxmem));
! 1570: case FFS_DIRHASH_MEM:
! 1571: return (sysctl_rdint(oldp, oldlenp, newp, ufs_dirhashmem));
! 1572: #endif
! 1573:
! 1574: default:
! 1575: return (EOPNOTSUPP);
! 1576: }
! 1577: /* NOTREACHED */
! 1578: }
CVSweb