1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1989, 1991, 1993, 1994 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33996c772fSJohn Dyson * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95 34c3aac50fSPeter Wemm * $FreeBSD$ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37a64ed089SRobert Watson #include "opt_ffs.h" 3801733a9bSGarrett Wollman #include "opt_quota.h" 3901733a9bSGarrett Wollman 40df8bae1dSRodney W. Grimes #include <sys/param.h> 41df8bae1dSRodney W. Grimes #include <sys/systm.h> 42df8bae1dSRodney W. Grimes #include <sys/namei.h> 43df8bae1dSRodney W. Grimes #include <sys/proc.h> 44df8bae1dSRodney W. Grimes #include <sys/kernel.h> 45df8bae1dSRodney W. Grimes #include <sys/vnode.h> 46df8bae1dSRodney W. Grimes #include <sys/mount.h> 479626b608SPoul-Henning Kamp #include <sys/bio.h> 48df8bae1dSRodney W. Grimes #include <sys/buf.h> 4981bca6ddSKATO Takenori #include <sys/conf.h> 503ac4d1efSBruce Evans #include <sys/fcntl.h> 51df8bae1dSRodney W. Grimes #include <sys/disklabel.h> 52df8bae1dSRodney W. Grimes #include <sys/malloc.h> 53df8bae1dSRodney W. Grimes 54a64ed089SRobert Watson #include <ufs/ufs/extattr.h> 55df8bae1dSRodney W. Grimes #include <ufs/ufs/quota.h> 56df8bae1dSRodney W. Grimes #include <ufs/ufs/ufsmount.h> 57df8bae1dSRodney W. Grimes #include <ufs/ufs/inode.h> 58df8bae1dSRodney W. Grimes #include <ufs/ufs/ufs_extern.h> 59df8bae1dSRodney W. Grimes 60df8bae1dSRodney W. Grimes #include <ufs/ffs/fs.h> 61df8bae1dSRodney W. Grimes #include <ufs/ffs/ffs_extern.h> 62df8bae1dSRodney W. Grimes 63f6b04d2bSDavid Greenman #include <vm/vm.h> 64f6b04d2bSDavid Greenman #include <vm/vm_page.h> 65f6b04d2bSDavid Greenman 66a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_FFSNODE, "FFS node", "FFS vnode private part"); 6755166637SPoul-Henning Kamp 68b8dce649SPoul-Henning Kamp static int ffs_sbupdate __P((struct ufsmount *, int)); 69b8dce649SPoul-Henning Kamp static int ffs_reload __P((struct mount *,struct ucred *,struct proc *)); 70b8dce649SPoul-Henning Kamp static int ffs_oldfscompat __P((struct fs *)); 71996c772fSJohn Dyson static int ffs_mount __P((struct mount *, char *, caddr_t, 72996c772fSJohn Dyson struct nameidata *, struct proc *)); 73996c772fSJohn Dyson static int ffs_init __P((struct vfsconf *)); 74df8bae1dSRodney W. Grimes 75303b270bSEivind Eklund static struct vfsops ufs_vfsops = { 76df8bae1dSRodney W. Grimes ffs_mount, 77df8bae1dSRodney W. Grimes ufs_start, 78df8bae1dSRodney W. Grimes ffs_unmount, 79df8bae1dSRodney W. Grimes ufs_root, 80df8bae1dSRodney W. Grimes ufs_quotactl, 81df8bae1dSRodney W. Grimes ffs_statfs, 82df8bae1dSRodney W. Grimes ffs_sync, 83df8bae1dSRodney W. Grimes ffs_vget, 84df8bae1dSRodney W. Grimes ffs_fhtovp, 85c24fda81SAlfred Perlstein ufs_check_export, 86df8bae1dSRodney W. Grimes ffs_vptofh, 87df8bae1dSRodney W. Grimes ffs_init, 8891f37dcbSRobert Watson vfs_stduninit, 89a64ed089SRobert Watson #ifdef FFS_EXTATTR 90a64ed089SRobert Watson ufs_extattrctl, 91a64ed089SRobert Watson #else 9291f37dcbSRobert Watson vfs_stdextattrctl, 93a64ed089SRobert Watson #endif 94df8bae1dSRodney W. Grimes }; 95df8bae1dSRodney W. Grimes 968994ca3cSBruce Evans VFS_SET(ufs_vfsops, ufs, 0); 97c901836cSGarrett Wollman 98df8bae1dSRodney W. Grimes /* 992b14f991SJulian Elischer * ffs_mount 100df8bae1dSRodney W. Grimes * 1012b14f991SJulian Elischer * Called when mounting local physical media 102df8bae1dSRodney W. Grimes * 1032b14f991SJulian Elischer * PARAMETERS: 1042b14f991SJulian Elischer * mountroot 1052b14f991SJulian Elischer * mp mount point structure 1062b14f991SJulian Elischer * path NULL (flag for root mount!!!) 1072b14f991SJulian Elischer * data <unused> 1082b14f991SJulian Elischer * ndp <unused> 1092b14f991SJulian Elischer * p process (user credentials check [statfs]) 1102b14f991SJulian Elischer * 1112b14f991SJulian Elischer * mount 1122b14f991SJulian Elischer * mp mount point structure 1132b14f991SJulian Elischer * path path to mount point 1142b14f991SJulian Elischer * data pointer to argument struct in user space 1152b14f991SJulian Elischer * ndp mount point namei() return (used for 1162b14f991SJulian Elischer * credentials on reload), reused to look 1172b14f991SJulian Elischer * up block device. 1182b14f991SJulian Elischer * p process (user credentials check) 1192b14f991SJulian Elischer * 1202b14f991SJulian Elischer * RETURNS: 0 Success 1212b14f991SJulian Elischer * !0 error number (errno.h) 1222b14f991SJulian Elischer * 1232b14f991SJulian Elischer * LOCK STATE: 1242b14f991SJulian Elischer * 1252b14f991SJulian Elischer * ENTRY 1262b14f991SJulian Elischer * mount point is locked 1272b14f991SJulian Elischer * EXIT 1282b14f991SJulian Elischer * mount point is locked 1292b14f991SJulian Elischer * 1302b14f991SJulian Elischer * NOTES: 1312b14f991SJulian Elischer * A NULL path can be used for a flag since the mount 1322b14f991SJulian Elischer * system call will fail with EFAULT in copyinstr in 1332b14f991SJulian Elischer * namei() if it is a genuine NULL from the user. 134df8bae1dSRodney W. Grimes */ 135b8dce649SPoul-Henning Kamp static int 136df8bae1dSRodney W. Grimes ffs_mount(mp, path, data, ndp, p) 137996c772fSJohn Dyson struct mount *mp; /* mount struct pointer*/ 1382b14f991SJulian Elischer char *path; /* path to mount point*/ 1392b14f991SJulian Elischer caddr_t data; /* arguments to FS specific mount*/ 1402b14f991SJulian Elischer struct nameidata *ndp; /* mount point credentials*/ 1412b14f991SJulian Elischer struct proc *p; /* process requesting mount*/ 142df8bae1dSRodney W. Grimes { 1438435e0aeSDoug Rabson size_t size; 144df8bae1dSRodney W. Grimes struct vnode *devvp; 145df8bae1dSRodney W. Grimes struct ufs_args args; 14626f9a767SRodney W. Grimes struct ufsmount *ump = 0; 147df8bae1dSRodney W. Grimes register struct fs *fs; 148f2a2857bSKirk McKusick int error, flags; 149c9b99213SBruce Evans mode_t accessmode; 150df8bae1dSRodney W. Grimes 1512b14f991SJulian Elischer /* 152f2a2857bSKirk McKusick * Use NULL path to indicate we are mounting the root file system. 1532b14f991SJulian Elischer */ 1542b14f991SJulian Elischer if (path == NULL) { 155f2a2857bSKirk McKusick if ((error = bdevvp(rootdev, &rootvp))) { 1566d147828SMike Smith printf("ffs_mountroot: can't find rootvp\n"); 157f2a2857bSKirk McKusick return (error); 158996c772fSJohn Dyson } 1592b14f991SJulian Elischer 160f2a2857bSKirk McKusick if ((error = ffs_mountfs(rootvp, mp, p, M_FFSNODE)) != 0) 161f2a2857bSKirk McKusick return (error); 1622b14f991SJulian Elischer 163f2a2857bSKirk McKusick (void)VFS_STATFS(mp, &mp->mnt_stat, p); 164f2a2857bSKirk McKusick return (0); 1652b14f991SJulian Elischer } 1662b14f991SJulian Elischer 1672b14f991SJulian Elischer /* 1682b14f991SJulian Elischer * Mounting non-root file system or updating a file system 1692b14f991SJulian Elischer */ 170f2a2857bSKirk McKusick if ((error = copyin(data, (caddr_t)&args, sizeof(struct ufs_args)))!= 0) 171f2a2857bSKirk McKusick return (error); 1722b14f991SJulian Elischer 173df8bae1dSRodney W. Grimes /* 174df8bae1dSRodney W. Grimes * If updating, check whether changing from read-only to 175df8bae1dSRodney W. Grimes * read/write; if there is no device name, that's all we do. 176df8bae1dSRodney W. Grimes */ 177df8bae1dSRodney W. Grimes if (mp->mnt_flag & MNT_UPDATE) { 178df8bae1dSRodney W. Grimes ump = VFSTOUFS(mp); 179df8bae1dSRodney W. Grimes fs = ump->um_fs; 18026cf9c3bSPeter Wemm devvp = ump->um_devvp; 181f2a2857bSKirk McKusick if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 182f2a2857bSKirk McKusick if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0) 183f2a2857bSKirk McKusick return (error); 184df8bae1dSRodney W. Grimes flags = WRITECLOSE; 185df8bae1dSRodney W. Grimes if (mp->mnt_flag & MNT_FORCE) 186df8bae1dSRodney W. Grimes flags |= FORCECLOSE; 187b1897c19SJulian Elischer if (mp->mnt_flag & MNT_SOFTDEP) { 188f2a2857bSKirk McKusick error = softdep_flushfiles(mp, flags, p); 189b1897c19SJulian Elischer } else { 190f2a2857bSKirk McKusick error = ffs_flushfiles(mp, flags, p); 191df8bae1dSRodney W. Grimes } 192f2a2857bSKirk McKusick if (error) { 193f2a2857bSKirk McKusick vn_finished_write(mp); 194f2a2857bSKirk McKusick return (error); 195b1897c19SJulian Elischer } 196f2a2857bSKirk McKusick fs->fs_ronly = 1; 197f2a2857bSKirk McKusick if ((fs->fs_flags & FS_UNCLEAN) == 0) 198f2a2857bSKirk McKusick fs->fs_clean = 1; 199f2a2857bSKirk McKusick if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) { 200f2a2857bSKirk McKusick fs->fs_ronly = 0; 201f2a2857bSKirk McKusick fs->fs_clean = 0; 202f2a2857bSKirk McKusick vn_finished_write(mp); 203f2a2857bSKirk McKusick return (error); 2042b14f991SJulian Elischer } 205f2a2857bSKirk McKusick vn_finished_write(mp); 206f2a2857bSKirk McKusick } 207f2a2857bSKirk McKusick if ((mp->mnt_flag & MNT_RELOAD) && 208f2a2857bSKirk McKusick (error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p)) != 0) 209f2a2857bSKirk McKusick return (error); 210f2a2857bSKirk McKusick if (fs->fs_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { 211c9b99213SBruce Evans /* 212c9b99213SBruce Evans * If upgrade to read-write by non-root, then verify 213c9b99213SBruce Evans * that user has necessary permissions on the device. 214c9b99213SBruce Evans */ 215c9b99213SBruce Evans if (p->p_ucred->cr_uid != 0) { 216c9b99213SBruce Evans vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 2178aef1712SMatthew Dillon if ((error = VOP_ACCESS(devvp, VREAD | VWRITE, 2188aef1712SMatthew Dillon p->p_ucred, p)) != 0) { 219c9b99213SBruce Evans VOP_UNLOCK(devvp, 0, p); 220c9b99213SBruce Evans return (error); 221c9b99213SBruce Evans } 222c9b99213SBruce Evans VOP_UNLOCK(devvp, 0, p); 223c9b99213SBruce Evans } 2247e58bfacSBruce Evans fs->fs_flags &= ~FS_UNCLEAN; 2250922cce6SBruce Evans if (fs->fs_clean == 0) { 2267e58bfacSBruce Evans fs->fs_flags |= FS_UNCLEAN; 2270922cce6SBruce Evans if (mp->mnt_flag & MNT_FORCE) { 228f2a2857bSKirk McKusick printf("WARNING: %s was not %s\n", 229f2a2857bSKirk McKusick fs->fs_fsmnt, "properly dismounted"); 2300922cce6SBruce Evans } else { 2310922cce6SBruce Evans printf( 2320922cce6SBruce Evans "WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n", 2330922cce6SBruce Evans fs->fs_fsmnt); 234f2a2857bSKirk McKusick return (EPERM); 2350922cce6SBruce Evans } 2360922cce6SBruce Evans } 237f2a2857bSKirk McKusick if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0) 238f2a2857bSKirk McKusick return (error); 239f2a2857bSKirk McKusick fs->fs_ronly = 0; 240f2a2857bSKirk McKusick fs->fs_clean = 0; 241f2a2857bSKirk McKusick if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) { 242f2a2857bSKirk McKusick vn_finished_write(mp); 243f2a2857bSKirk McKusick return (error); 244f2a2857bSKirk McKusick } 24526cf9c3bSPeter Wemm /* check to see if we need to start softdep */ 246f2a2857bSKirk McKusick if ((fs->fs_flags & FS_DOSOFTDEP) && 247f2a2857bSKirk McKusick (error = softdep_mount(devvp, mp, fs, p->p_ucred))){ 248f2a2857bSKirk McKusick vn_finished_write(mp); 249f2a2857bSKirk McKusick return (error); 25026cf9c3bSPeter Wemm } 251f2a2857bSKirk McKusick if (fs->fs_snapinum[0] != 0) 252f2a2857bSKirk McKusick ffs_snapshot_mount(mp); 253f2a2857bSKirk McKusick vn_finished_write(mp); 2541469eec8SDavid Greenman } 255c11d2981SJulian Elischer /* 256c11d2981SJulian Elischer * Soft updates is incompatible with "async", 257c11d2981SJulian Elischer * so if we are doing softupdates stop the user 258c11d2981SJulian Elischer * from setting the async flag in an update. 259c11d2981SJulian Elischer * Softdep_mount() clears it in an initial mount 260c11d2981SJulian Elischer * or ro->rw remount. 261c11d2981SJulian Elischer */ 262f2a2857bSKirk McKusick if (mp->mnt_flag & MNT_SOFTDEP) 263c11d2981SJulian Elischer mp->mnt_flag &= ~MNT_ASYNC; 264df8bae1dSRodney W. Grimes /* 265f2a2857bSKirk McKusick * If not updating name, process export requests. 266df8bae1dSRodney W. Grimes */ 267f2a2857bSKirk McKusick if (args.fspec == 0) 268f2a2857bSKirk McKusick return (vfs_export(mp, &ump->um_export, &args.export)); 269f2a2857bSKirk McKusick /* 270f2a2857bSKirk McKusick * If this is a snapshot request, take the snapshot. 271f2a2857bSKirk McKusick */ 272f2a2857bSKirk McKusick if (mp->mnt_flag & MNT_SNAPSHOT) 273f2a2857bSKirk McKusick return (ffs_snapshot(mp, args.fspec)); 274df8bae1dSRodney W. Grimes } 2752b14f991SJulian Elischer 276df8bae1dSRodney W. Grimes /* 277df8bae1dSRodney W. Grimes * Not an update, or updating the name: look up the name 278df8bae1dSRodney W. Grimes * and verify that it refers to a sensible block device. 279df8bae1dSRodney W. Grimes */ 280df8bae1dSRodney W. Grimes NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 281f2a2857bSKirk McKusick if ((error = namei(ndp)) != 0) 282f2a2857bSKirk McKusick return (error); 283762e6b85SEivind Eklund NDFREE(ndp, NDF_ONLY_PNBUF); 284df8bae1dSRodney W. Grimes devvp = ndp->ni_vp; 285f2a2857bSKirk McKusick if (!vn_isdisk(devvp, &error)) { 286f2a2857bSKirk McKusick vrele(devvp); 287f2a2857bSKirk McKusick return (error); 288f2a2857bSKirk McKusick } 289c9b99213SBruce Evans 290c9b99213SBruce Evans /* 291c9b99213SBruce Evans * If mount by non-root, then verify that user has necessary 292c9b99213SBruce Evans * permissions on the device. 293c9b99213SBruce Evans */ 294c9b99213SBruce Evans if (p->p_ucred->cr_uid != 0) { 295c9b99213SBruce Evans accessmode = VREAD; 296c9b99213SBruce Evans if ((mp->mnt_flag & MNT_RDONLY) == 0) 297c9b99213SBruce Evans accessmode |= VWRITE; 298c9b99213SBruce Evans vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 2998aef1712SMatthew Dillon if ((error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p))!= 0){ 300c9b99213SBruce Evans vput(devvp); 301c9b99213SBruce Evans return (error); 302c9b99213SBruce Evans } 303c9b99213SBruce Evans VOP_UNLOCK(devvp, 0, p); 304c9b99213SBruce Evans } 305c9b99213SBruce Evans 3062b14f991SJulian Elischer if (mp->mnt_flag & MNT_UPDATE) { 3072b14f991SJulian Elischer /* 308f2a2857bSKirk McKusick * Update only 309f2a2857bSKirk McKusick * 3103e425b96SJulian Elischer * If it's not the same vnode, or at least the same device 3113e425b96SJulian Elischer * then it's not correct. 3122b14f991SJulian Elischer */ 3132b14f991SJulian Elischer 314f2a2857bSKirk McKusick if (devvp != ump->um_devvp && 315f2a2857bSKirk McKusick devvp->v_rdev != ump->um_devvp->v_rdev) 316f2a2857bSKirk McKusick error = EINVAL; /* needs translation */ 3173e425b96SJulian Elischer vrele(devvp); 318f2a2857bSKirk McKusick if (error) 319f2a2857bSKirk McKusick return (error); 3202b14f991SJulian Elischer } else { 3212b14f991SJulian Elischer /* 322f2a2857bSKirk McKusick * New mount 3232b14f991SJulian Elischer * 324f2a2857bSKirk McKusick * We need the name for the mount point (also used for 325f2a2857bSKirk McKusick * "last mounted on") copied in. If an error occurs, 326f2a2857bSKirk McKusick * the mount point is discarded by the upper level code. 327f2a2857bSKirk McKusick */ 328f2a2857bSKirk McKusick copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 329f2a2857bSKirk McKusick bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 330f2a2857bSKirk McKusick if ((error = ffs_mountfs(devvp, mp, p, M_FFSNODE)) != 0) { 331f2a2857bSKirk McKusick vrele(devvp); 332f2a2857bSKirk McKusick return (error); 333f2a2857bSKirk McKusick } 334f2a2857bSKirk McKusick } 335f2a2857bSKirk McKusick /* 336f2a2857bSKirk McKusick * Save "mounted from" device name info for mount point (NULL pad). 337f2a2857bSKirk McKusick */ 338f2a2857bSKirk McKusick copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); 339f2a2857bSKirk McKusick bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 340f2a2857bSKirk McKusick /* 341f2a2857bSKirk McKusick * Initialize filesystem stat information in mount struct. 3422b14f991SJulian Elischer */ 3432b14f991SJulian Elischer (void)VFS_STATFS(mp, &mp->mnt_stat, p); 344f2a2857bSKirk McKusick return (0); 3452b14f991SJulian Elischer } 3462b14f991SJulian Elischer 347df8bae1dSRodney W. Grimes /* 348df8bae1dSRodney W. Grimes * Reload all incore data for a filesystem (used after running fsck on 349df8bae1dSRodney W. Grimes * the root filesystem and finding things to fix). The filesystem must 350df8bae1dSRodney W. Grimes * be mounted read-only. 351df8bae1dSRodney W. Grimes * 352df8bae1dSRodney W. Grimes * Things to do to update the mount: 353df8bae1dSRodney W. Grimes * 1) invalidate all cached meta-data. 354df8bae1dSRodney W. Grimes * 2) re-read superblock from disk. 355df8bae1dSRodney W. Grimes * 3) re-read summary information from disk. 356df8bae1dSRodney W. Grimes * 4) invalidate all inactive vnodes. 357df8bae1dSRodney W. Grimes * 5) invalidate all cached file data. 358df8bae1dSRodney W. Grimes * 6) re-read inode data for all active vnodes. 359df8bae1dSRodney W. Grimes */ 360b8dce649SPoul-Henning Kamp static int 3612b14f991SJulian Elischer ffs_reload(mp, cred, p) 3622b14f991SJulian Elischer register struct mount *mp; 363df8bae1dSRodney W. Grimes struct ucred *cred; 364df8bae1dSRodney W. Grimes struct proc *p; 365df8bae1dSRodney W. Grimes { 366df8bae1dSRodney W. Grimes register struct vnode *vp, *nvp, *devvp; 367df8bae1dSRodney W. Grimes struct inode *ip; 368df8bae1dSRodney W. Grimes struct csum *space; 369df8bae1dSRodney W. Grimes struct buf *bp; 370996c772fSJohn Dyson struct fs *fs, *newfs; 371996c772fSJohn Dyson struct partinfo dpart; 37295e5e988SJohn Dyson dev_t dev; 373df8bae1dSRodney W. Grimes int i, blks, size, error; 374996c772fSJohn Dyson int32_t *lp; 375df8bae1dSRodney W. Grimes 3762b14f991SJulian Elischer if ((mp->mnt_flag & MNT_RDONLY) == 0) 377df8bae1dSRodney W. Grimes return (EINVAL); 378df8bae1dSRodney W. Grimes /* 379df8bae1dSRodney W. Grimes * Step 1: invalidate all cached meta-data. 380df8bae1dSRodney W. Grimes */ 3812b14f991SJulian Elischer devvp = VFSTOUFS(mp)->um_devvp; 382b1897c19SJulian Elischer vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 383b1897c19SJulian Elischer error = vinvalbuf(devvp, 0, cred, p, 0, 0); 384b1897c19SJulian Elischer VOP_UNLOCK(devvp, 0, p); 385b1897c19SJulian Elischer if (error) 386df8bae1dSRodney W. Grimes panic("ffs_reload: dirty1"); 38795e5e988SJohn Dyson 38895e5e988SJohn Dyson dev = devvp->v_rdev; 389b5ee1640SBruce Evans 39095e5e988SJohn Dyson /* 39195e5e988SJohn Dyson * Only VMIO the backing device if the backing device is a real 392b5ee1640SBruce Evans * block device. See ffs_mountmfs() for more details. 39395e5e988SJohn Dyson */ 394ba4ad1fcSPoul-Henning Kamp if (devvp->v_tag != VT_MFS && vn_isdisk(devvp, NULL)) { 395a777e820SEivind Eklund vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 396fb116777SEivind Eklund vfs_object_create(devvp, p, p->p_ucred); 3972d8acc0fSJohn Dyson simple_lock(&devvp->v_interlock); 398a777e820SEivind Eklund VOP_UNLOCK(devvp, LK_INTERLOCK, p); 39995e5e988SJohn Dyson } 40095e5e988SJohn Dyson 401df8bae1dSRodney W. Grimes /* 402df8bae1dSRodney W. Grimes * Step 2: re-read superblock from disk. 403df8bae1dSRodney W. Grimes */ 404996c772fSJohn Dyson if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) 405996c772fSJohn Dyson size = DEV_BSIZE; 406996c772fSJohn Dyson else 407996c772fSJohn Dyson size = dpart.disklab->d_secsize; 4088aef1712SMatthew Dillon if ((error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, NOCRED,&bp)) != 0) 409df8bae1dSRodney W. Grimes return (error); 410996c772fSJohn Dyson newfs = (struct fs *)bp->b_data; 411996c772fSJohn Dyson if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE || 412996c772fSJohn Dyson newfs->fs_bsize < sizeof(struct fs)) { 413df8bae1dSRodney W. Grimes brelse(bp); 414df8bae1dSRodney W. Grimes return (EIO); /* XXX needs translation */ 415df8bae1dSRodney W. Grimes } 4162b14f991SJulian Elischer fs = VFSTOUFS(mp)->um_fs; 417996c772fSJohn Dyson /* 418996c772fSJohn Dyson * Copy pointer fields back into superblock before copying in XXX 419996c772fSJohn Dyson * new superblock. These should really be in the ufsmount. XXX 420996c772fSJohn Dyson * Note that important parameters (eg fs_ncg) are unchanged. 421996c772fSJohn Dyson */ 422996c772fSJohn Dyson bcopy(&fs->fs_csp[0], &newfs->fs_csp[0], sizeof(fs->fs_csp)); 423996c772fSJohn Dyson newfs->fs_maxcluster = fs->fs_maxcluster; 424996c772fSJohn Dyson bcopy(newfs, fs, (u_int)fs->fs_sbsize); 425df8bae1dSRodney W. Grimes if (fs->fs_sbsize < SBSIZE) 426f2a2857bSKirk McKusick bp->b_flags |= B_INVAL | B_NOCACHE; 427df8bae1dSRodney W. Grimes brelse(bp); 428996c772fSJohn Dyson mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; 429df8bae1dSRodney W. Grimes ffs_oldfscompat(fs); 430996c772fSJohn Dyson 431df8bae1dSRodney W. Grimes /* 432df8bae1dSRodney W. Grimes * Step 3: re-read summary information from disk. 433df8bae1dSRodney W. Grimes */ 434df8bae1dSRodney W. Grimes blks = howmany(fs->fs_cssize, fs->fs_fsize); 435df8bae1dSRodney W. Grimes space = fs->fs_csp[0]; 436df8bae1dSRodney W. Grimes for (i = 0; i < blks; i += fs->fs_frag) { 437df8bae1dSRodney W. Grimes size = fs->fs_bsize; 438df8bae1dSRodney W. Grimes if (i + fs->fs_frag > blks) 439df8bae1dSRodney W. Grimes size = (blks - i) * fs->fs_fsize; 440c9671602SPoul-Henning Kamp error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 441c9671602SPoul-Henning Kamp NOCRED, &bp); 442c9671602SPoul-Henning Kamp if (error) 443df8bae1dSRodney W. Grimes return (error); 444df8bae1dSRodney W. Grimes bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size); 445df8bae1dSRodney W. Grimes brelse(bp); 446df8bae1dSRodney W. Grimes } 447996c772fSJohn Dyson /* 448996c772fSJohn Dyson * We no longer know anything about clusters per cylinder group. 449996c772fSJohn Dyson */ 450996c772fSJohn Dyson if (fs->fs_contigsumsize > 0) { 451996c772fSJohn Dyson lp = fs->fs_maxcluster; 452996c772fSJohn Dyson for (i = 0; i < fs->fs_ncg; i++) 453996c772fSJohn Dyson *lp++ = fs->fs_contigsumsize; 454996c772fSJohn Dyson } 455996c772fSJohn Dyson 456df8bae1dSRodney W. Grimes loop: 457996c772fSJohn Dyson simple_lock(&mntvnode_slock); 4582b14f991SJulian Elischer for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { 459996c772fSJohn Dyson if (vp->v_mount != mp) { 460996c772fSJohn Dyson simple_unlock(&mntvnode_slock); 461996c772fSJohn Dyson goto loop; 462996c772fSJohn Dyson } 463df8bae1dSRodney W. Grimes nvp = vp->v_mntvnodes.le_next; 464df8bae1dSRodney W. Grimes /* 465df8bae1dSRodney W. Grimes * Step 4: invalidate all inactive vnodes. 466df8bae1dSRodney W. Grimes */ 467996c772fSJohn Dyson if (vrecycle(vp, &mntvnode_slock, p)) 468996c772fSJohn Dyson goto loop; 469df8bae1dSRodney W. Grimes /* 470df8bae1dSRodney W. Grimes * Step 5: invalidate all cached file data. 471df8bae1dSRodney W. Grimes */ 472996c772fSJohn Dyson simple_lock(&vp->v_interlock); 473996c772fSJohn Dyson simple_unlock(&mntvnode_slock); 474996c772fSJohn Dyson if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) { 475df8bae1dSRodney W. Grimes goto loop; 476996c772fSJohn Dyson } 477df8bae1dSRodney W. Grimes if (vinvalbuf(vp, 0, cred, p, 0, 0)) 478df8bae1dSRodney W. Grimes panic("ffs_reload: dirty2"); 479df8bae1dSRodney W. Grimes /* 480df8bae1dSRodney W. Grimes * Step 6: re-read inode data for all active vnodes. 481df8bae1dSRodney W. Grimes */ 482df8bae1dSRodney W. Grimes ip = VTOI(vp); 483c9671602SPoul-Henning Kamp error = 484df8bae1dSRodney W. Grimes bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 485c9671602SPoul-Henning Kamp (int)fs->fs_bsize, NOCRED, &bp); 486c9671602SPoul-Henning Kamp if (error) { 487df8bae1dSRodney W. Grimes vput(vp); 488df8bae1dSRodney W. Grimes return (error); 489df8bae1dSRodney W. Grimes } 490df8bae1dSRodney W. Grimes ip->i_din = *((struct dinode *)bp->b_data + 491df8bae1dSRodney W. Grimes ino_to_fsbo(fs, ip->i_number)); 492b1897c19SJulian Elischer ip->i_effnlink = ip->i_nlink; 493df8bae1dSRodney W. Grimes brelse(bp); 494df8bae1dSRodney W. Grimes vput(vp); 495996c772fSJohn Dyson simple_lock(&mntvnode_slock); 496df8bae1dSRodney W. Grimes } 497996c772fSJohn Dyson simple_unlock(&mntvnode_slock); 498df8bae1dSRodney W. Grimes return (0); 499df8bae1dSRodney W. Grimes } 500df8bae1dSRodney W. Grimes 501df8bae1dSRodney W. Grimes /* 502df8bae1dSRodney W. Grimes * Common code for mount and mountroot 503df8bae1dSRodney W. Grimes */ 504df8bae1dSRodney W. Grimes int 5050be6b890SPoul-Henning Kamp ffs_mountfs(devvp, mp, p, malloctype) 506df8bae1dSRodney W. Grimes register struct vnode *devvp; 507df8bae1dSRodney W. Grimes struct mount *mp; 508df8bae1dSRodney W. Grimes struct proc *p; 5090be6b890SPoul-Henning Kamp struct malloc_type *malloctype; 510df8bae1dSRodney W. Grimes { 511df8bae1dSRodney W. Grimes register struct ufsmount *ump; 512df8bae1dSRodney W. Grimes struct buf *bp; 513df8bae1dSRodney W. Grimes register struct fs *fs; 514996c772fSJohn Dyson dev_t dev; 515df8bae1dSRodney W. Grimes struct partinfo dpart; 516df8bae1dSRodney W. Grimes caddr_t base, space; 517f5ef029eSPoul-Henning Kamp int error, i, blks, size, ronly; 518996c772fSJohn Dyson int32_t *lp; 519996c772fSJohn Dyson struct ucred *cred; 520996c772fSJohn Dyson u_int64_t maxfilesize; /* XXX */ 5218435e0aeSDoug Rabson size_t strsize; 5226476c0d2SJohn Dyson int ncount; 523df8bae1dSRodney W. Grimes 524996c772fSJohn Dyson dev = devvp->v_rdev; 525996c772fSJohn Dyson cred = p ? p->p_ucred : NOCRED; 526df8bae1dSRodney W. Grimes /* 527df8bae1dSRodney W. Grimes * Disallow multiple mounts of the same device. 528df8bae1dSRodney W. Grimes * Disallow mounting of a device that is currently in use 529df8bae1dSRodney W. Grimes * (except for root, which might share swap device for miniroot). 530df8bae1dSRodney W. Grimes * Flush out any old buffers remaining from a previous use. 531df8bae1dSRodney W. Grimes */ 532c9671602SPoul-Henning Kamp error = vfs_mountedon(devvp); 533c9671602SPoul-Henning Kamp if (error) 534df8bae1dSRodney W. Grimes return (error); 5356476c0d2SJohn Dyson ncount = vcount(devvp); 5368f9110f6SJohn Dyson 5376476c0d2SJohn Dyson if (ncount > 1 && devvp != rootvp) 538df8bae1dSRodney W. Grimes return (EBUSY); 539b1897c19SJulian Elischer vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 540b1897c19SJulian Elischer error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0); 541b1897c19SJulian Elischer VOP_UNLOCK(devvp, 0, p); 542b1897c19SJulian Elischer if (error) 543df8bae1dSRodney W. Grimes return (error); 544df8bae1dSRodney W. Grimes 54595e5e988SJohn Dyson /* 54695e5e988SJohn Dyson * Only VMIO the backing device if the backing device is a real 54795e5e988SJohn Dyson * block device. This excludes the original MFS implementation. 54895e5e988SJohn Dyson * Note that it is optional that the backing device be VMIOed. This 54995e5e988SJohn Dyson * increases the opportunity for metadata caching. 55095e5e988SJohn Dyson */ 551ba4ad1fcSPoul-Henning Kamp if (devvp->v_tag != VT_MFS && vn_isdisk(devvp, NULL)) { 552a777e820SEivind Eklund vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 5533fbd9742SBoris Popov vfs_object_create(devvp, p, cred); 55416337c2eSBruce Evans simple_lock(&devvp->v_interlock); 555a777e820SEivind Eklund VOP_UNLOCK(devvp, LK_INTERLOCK, p); 55695e5e988SJohn Dyson } 55795e5e988SJohn Dyson 558df8bae1dSRodney W. Grimes ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 559698f9cf8SPoul-Henning Kamp vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 560c9671602SPoul-Henning Kamp error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); 561698f9cf8SPoul-Henning Kamp VOP_UNLOCK(devvp, 0, p); 562c9671602SPoul-Henning Kamp if (error) 563df8bae1dSRodney W. Grimes return (error); 5641b5464efSPoul-Henning Kamp if (devvp->v_rdev->si_iosize_max > mp->mnt_iosize_max) 5651b5464efSPoul-Henning Kamp mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; 5661b5464efSPoul-Henning Kamp if (mp->mnt_iosize_max > MAXPHYS) 5671b5464efSPoul-Henning Kamp mp->mnt_iosize_max = MAXPHYS; 56895e5e988SJohn Dyson 569996c772fSJohn Dyson if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0) 570df8bae1dSRodney W. Grimes size = DEV_BSIZE; 571996c772fSJohn Dyson else 572df8bae1dSRodney W. Grimes size = dpart.disklab->d_secsize; 573df8bae1dSRodney W. Grimes 574df8bae1dSRodney W. Grimes bp = NULL; 575df8bae1dSRodney W. Grimes ump = NULL; 5768aef1712SMatthew Dillon if ((error = bread(devvp, SBLOCK, SBSIZE, cred, &bp)) != 0) 577df8bae1dSRodney W. Grimes goto out; 578df8bae1dSRodney W. Grimes fs = (struct fs *)bp->b_data; 579df8bae1dSRodney W. Grimes if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 580df8bae1dSRodney W. Grimes fs->fs_bsize < sizeof(struct fs)) { 581df8bae1dSRodney W. Grimes error = EINVAL; /* XXX needs translation */ 582df8bae1dSRodney W. Grimes goto out; 583df8bae1dSRodney W. Grimes } 5843f6f17eeSJulian Elischer fs->fs_fmod = 0; 5850922cce6SBruce Evans fs->fs_flags &= ~FS_UNCLEAN; 5860922cce6SBruce Evans if (fs->fs_clean == 0) { 5870922cce6SBruce Evans fs->fs_flags |= FS_UNCLEAN; 5881469eec8SDavid Greenman if (ronly || (mp->mnt_flag & MNT_FORCE)) { 5890922cce6SBruce Evans printf( 5900922cce6SBruce Evans "WARNING: %s was not properly dismounted\n", 5910922cce6SBruce Evans fs->fs_fsmnt); 5921469eec8SDavid Greenman } else { 5930922cce6SBruce Evans printf( 5940922cce6SBruce Evans "WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n", 5950922cce6SBruce Evans fs->fs_fsmnt); 5961469eec8SDavid Greenman error = EPERM; 5971469eec8SDavid Greenman goto out; 5981469eec8SDavid Greenman } 5991469eec8SDavid Greenman } 600996c772fSJohn Dyson /* XXX updating 4.2 FFS superblocks trashes rotational layout tables */ 601996c772fSJohn Dyson if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) { 602996c772fSJohn Dyson error = EROFS; /* needs translation */ 603996c772fSJohn Dyson goto out; 604996c772fSJohn Dyson } 605df8bae1dSRodney W. Grimes ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 606df8bae1dSRodney W. Grimes bzero((caddr_t)ump, sizeof *ump); 6070be6b890SPoul-Henning Kamp ump->um_malloctype = malloctype; 6085bd5c8b9SBruce Evans ump->um_i_effnlink_valid = 1; 609df8bae1dSRodney W. Grimes ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, 610df8bae1dSRodney W. Grimes M_WAITOK); 611cec0f20cSPoul-Henning Kamp ump->um_blkatoff = ffs_blkatoff; 612cec0f20cSPoul-Henning Kamp ump->um_truncate = ffs_truncate; 613987f5696SPoul-Henning Kamp ump->um_update = ffs_update; 614cec0f20cSPoul-Henning Kamp ump->um_valloc = ffs_valloc; 615cec0f20cSPoul-Henning Kamp ump->um_vfree = ffs_vfree; 616df8bae1dSRodney W. Grimes bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize); 617df8bae1dSRodney W. Grimes if (fs->fs_sbsize < SBSIZE) 618f2a2857bSKirk McKusick bp->b_flags |= B_INVAL | B_NOCACHE; 619df8bae1dSRodney W. Grimes brelse(bp); 620df8bae1dSRodney W. Grimes bp = NULL; 621df8bae1dSRodney W. Grimes fs = ump->um_fs; 622df8bae1dSRodney W. Grimes fs->fs_ronly = ronly; 623996c772fSJohn Dyson size = fs->fs_cssize; 624996c772fSJohn Dyson blks = howmany(size, fs->fs_fsize); 625996c772fSJohn Dyson if (fs->fs_contigsumsize > 0) 626996c772fSJohn Dyson size += fs->fs_ncg * sizeof(int32_t); 627996c772fSJohn Dyson base = space = malloc((u_long)size, M_UFSMNT, M_WAITOK); 628df8bae1dSRodney W. Grimes for (i = 0; i < blks; i += fs->fs_frag) { 629df8bae1dSRodney W. Grimes size = fs->fs_bsize; 630df8bae1dSRodney W. Grimes if (i + fs->fs_frag > blks) 631df8bae1dSRodney W. Grimes size = (blks - i) * fs->fs_fsize; 6328aef1712SMatthew Dillon if ((error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 6338aef1712SMatthew Dillon cred, &bp)) != 0) { 634df8bae1dSRodney W. Grimes free(base, M_UFSMNT); 635df8bae1dSRodney W. Grimes goto out; 636df8bae1dSRodney W. Grimes } 637df8bae1dSRodney W. Grimes bcopy(bp->b_data, space, (u_int)size); 638df8bae1dSRodney W. Grimes fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 639df8bae1dSRodney W. Grimes space += size; 640df8bae1dSRodney W. Grimes brelse(bp); 641df8bae1dSRodney W. Grimes bp = NULL; 642df8bae1dSRodney W. Grimes } 643996c772fSJohn Dyson if (fs->fs_contigsumsize > 0) { 644996c772fSJohn Dyson fs->fs_maxcluster = lp = (int32_t *)space; 645996c772fSJohn Dyson for (i = 0; i < fs->fs_ncg; i++) 646996c772fSJohn Dyson *lp++ = fs->fs_contigsumsize; 647996c772fSJohn Dyson } 648df8bae1dSRodney W. Grimes mp->mnt_data = (qaddr_t)ump; 64968de329eSPoul-Henning Kamp mp->mnt_stat.f_fsid.val[0] = fs->fs_id[0]; 6508f89943eSGuido van Rooij mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1]; 65168de329eSPoul-Henning Kamp if (fs->fs_id[0] == 0 || fs->fs_id[1] == 0 || 65268de329eSPoul-Henning Kamp vfs_getvfs(&mp->mnt_stat.f_fsid)) 65368de329eSPoul-Henning Kamp vfs_getnewfsid(mp); 654df8bae1dSRodney W. Grimes mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; 655cc9d8990SPeter Wemm mp->mnt_flag |= MNT_LOCAL; 656df8bae1dSRodney W. Grimes ump->um_mountp = mp; 657df8bae1dSRodney W. Grimes ump->um_dev = dev; 658df8bae1dSRodney W. Grimes ump->um_devvp = devvp; 659df8bae1dSRodney W. Grimes ump->um_nindir = fs->fs_nindir; 660df8bae1dSRodney W. Grimes ump->um_bptrtodb = fs->fs_fsbtodb; 661df8bae1dSRodney W. Grimes ump->um_seqinc = fs->fs_frag; 662df8bae1dSRodney W. Grimes for (i = 0; i < MAXQUOTAS; i++) 663df8bae1dSRodney W. Grimes ump->um_quotas[i] = NULLVP; 664a64ed089SRobert Watson #ifdef FFS_EXTATTR 665a64ed089SRobert Watson ufs_extattr_uepm_init(&ump->um_extattr); 666a64ed089SRobert Watson #endif 667b1897c19SJulian Elischer devvp->v_specmountpoint = mp; 668df8bae1dSRodney W. Grimes ffs_oldfscompat(fs); 6692b14f991SJulian Elischer 6702b14f991SJulian Elischer /* 6712b14f991SJulian Elischer * Set FS local "last mounted on" information (NULL pad) 6722b14f991SJulian Elischer */ 6732b14f991SJulian Elischer copystr( mp->mnt_stat.f_mntonname, /* mount point*/ 6742b14f991SJulian Elischer fs->fs_fsmnt, /* copy area*/ 6752b14f991SJulian Elischer sizeof(fs->fs_fsmnt) - 1, /* max size*/ 6762b14f991SJulian Elischer &strsize); /* real size*/ 6772b14f991SJulian Elischer bzero( fs->fs_fsmnt + strsize, sizeof(fs->fs_fsmnt) - strsize); 6782b14f991SJulian Elischer 6792b14f991SJulian Elischer if( mp->mnt_flag & MNT_ROOTFS) { 6802b14f991SJulian Elischer /* 6812b14f991SJulian Elischer * Root mount; update timestamp in mount structure. 6822b14f991SJulian Elischer * this will be used by the common root mount code 6832b14f991SJulian Elischer * to update the system clock. 6842b14f991SJulian Elischer */ 6852b14f991SJulian Elischer mp->mnt_time = fs->fs_time; 6862b14f991SJulian Elischer } 687996c772fSJohn Dyson 688996c772fSJohn Dyson ump->um_savedmaxfilesize = fs->fs_maxfilesize; /* XXX */ 689996c772fSJohn Dyson maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1; /* XXX */ 690996c772fSJohn Dyson if (fs->fs_maxfilesize > maxfilesize) /* XXX */ 691996c772fSJohn Dyson fs->fs_maxfilesize = maxfilesize; /* XXX */ 692996c772fSJohn Dyson if (ronly == 0) { 693b1897c19SJulian Elischer if ((fs->fs_flags & FS_DOSOFTDEP) && 694b1897c19SJulian Elischer (error = softdep_mount(devvp, mp, fs, cred)) != 0) { 695b1897c19SJulian Elischer free(base, M_UFSMNT); 696b1897c19SJulian Elischer goto out; 697b1897c19SJulian Elischer } 698f2a2857bSKirk McKusick if (fs->fs_snapinum[0] != 0) 699f2a2857bSKirk McKusick ffs_snapshot_mount(mp); 700cf60e8e4SKirk McKusick fs->fs_fmod = 1; 701996c772fSJohn Dyson fs->fs_clean = 0; 702996c772fSJohn Dyson (void) ffs_sbupdate(ump, MNT_WAIT); 703996c772fSJohn Dyson } 704df8bae1dSRodney W. Grimes return (0); 705df8bae1dSRodney W. Grimes out: 706b1897c19SJulian Elischer devvp->v_specmountpoint = NULL; 707df8bae1dSRodney W. Grimes if (bp) 708df8bae1dSRodney W. Grimes brelse(bp); 709996c772fSJohn Dyson (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); 710df8bae1dSRodney W. Grimes if (ump) { 711df8bae1dSRodney W. Grimes free(ump->um_fs, M_UFSMNT); 712df8bae1dSRodney W. Grimes free(ump, M_UFSMNT); 713df8bae1dSRodney W. Grimes mp->mnt_data = (qaddr_t)0; 714df8bae1dSRodney W. Grimes } 715df8bae1dSRodney W. Grimes return (error); 716df8bae1dSRodney W. Grimes } 717df8bae1dSRodney W. Grimes 718df8bae1dSRodney W. Grimes /* 719df8bae1dSRodney W. Grimes * Sanity checks for old file systems. 720df8bae1dSRodney W. Grimes * 721df8bae1dSRodney W. Grimes * XXX - goes away some day. 722df8bae1dSRodney W. Grimes */ 723b8dce649SPoul-Henning Kamp static int 724df8bae1dSRodney W. Grimes ffs_oldfscompat(fs) 725df8bae1dSRodney W. Grimes struct fs *fs; 726df8bae1dSRodney W. Grimes { 727df8bae1dSRodney W. Grimes 728df8bae1dSRodney W. Grimes fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ 729df8bae1dSRodney W. Grimes fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ 730df8bae1dSRodney W. Grimes if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 731df8bae1dSRodney W. Grimes fs->fs_nrpos = 8; /* XXX */ 732df8bae1dSRodney W. Grimes if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 733c03020b2SPoul-Henning Kamp #if 0 734c03020b2SPoul-Henning Kamp int i; /* XXX */ 735996c772fSJohn Dyson u_int64_t sizepb = fs->fs_bsize; /* XXX */ 736996c772fSJohn Dyson /* XXX */ 737df8bae1dSRodney W. Grimes fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ 738df8bae1dSRodney W. Grimes for (i = 0; i < NIADDR; i++) { /* XXX */ 739df8bae1dSRodney W. Grimes sizepb *= NINDIR(fs); /* XXX */ 740df8bae1dSRodney W. Grimes fs->fs_maxfilesize += sizepb; /* XXX */ 741df8bae1dSRodney W. Grimes } /* XXX */ 742901ba606SDavid Greenman #endif 743a316d390SJohn Dyson fs->fs_maxfilesize = (u_quad_t) 1LL << 39; 744df8bae1dSRodney W. Grimes fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ 745df8bae1dSRodney W. Grimes fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ 746df8bae1dSRodney W. Grimes } /* XXX */ 747df8bae1dSRodney W. Grimes return (0); 748df8bae1dSRodney W. Grimes } 749df8bae1dSRodney W. Grimes 750df8bae1dSRodney W. Grimes /* 751df8bae1dSRodney W. Grimes * unmount system call 752df8bae1dSRodney W. Grimes */ 753df8bae1dSRodney W. Grimes int 754df8bae1dSRodney W. Grimes ffs_unmount(mp, mntflags, p) 755df8bae1dSRodney W. Grimes struct mount *mp; 756df8bae1dSRodney W. Grimes int mntflags; 757df8bae1dSRodney W. Grimes struct proc *p; 758df8bae1dSRodney W. Grimes { 759df8bae1dSRodney W. Grimes register struct ufsmount *ump; 760df8bae1dSRodney W. Grimes register struct fs *fs; 761996c772fSJohn Dyson int error, flags; 762df8bae1dSRodney W. Grimes 763df8bae1dSRodney W. Grimes flags = 0; 764df8bae1dSRodney W. Grimes if (mntflags & MNT_FORCE) { 765df8bae1dSRodney W. Grimes flags |= FORCECLOSE; 766df8bae1dSRodney W. Grimes } 767a64ed089SRobert Watson #ifdef FFS_EXTATTR 768b2b0497aSRobert Watson if ((error = ufs_extattr_stop(mp, p))) 769b2b0497aSRobert Watson if (error != EOPNOTSUPP) 770b2b0497aSRobert Watson printf("ffs_unmount: ufs_extattr_stop returned %d\n", 771b2b0497aSRobert Watson error); 772a64ed089SRobert Watson #endif 773b1897c19SJulian Elischer if (mp->mnt_flag & MNT_SOFTDEP) { 774b1897c19SJulian Elischer if ((error = softdep_flushfiles(mp, flags, p)) != 0) 775df8bae1dSRodney W. Grimes return (error); 776b1897c19SJulian Elischer } else { 777b1897c19SJulian Elischer if ((error = ffs_flushfiles(mp, flags, p)) != 0) 778b1897c19SJulian Elischer return (error); 779b1897c19SJulian Elischer } 780df8bae1dSRodney W. Grimes ump = VFSTOUFS(mp); 781df8bae1dSRodney W. Grimes fs = ump->um_fs; 782996c772fSJohn Dyson if (fs->fs_ronly == 0) { 7830922cce6SBruce Evans fs->fs_clean = fs->fs_flags & FS_UNCLEAN ? 0 : 1; 784996c772fSJohn Dyson error = ffs_sbupdate(ump, MNT_WAIT); 785996c772fSJohn Dyson if (error) { 786996c772fSJohn Dyson fs->fs_clean = 0; 787996c772fSJohn Dyson return (error); 788996c772fSJohn Dyson } 789e0e9c421SDavid Greenman } 790b1897c19SJulian Elischer ump->um_devvp->v_specmountpoint = NULL; 7916476c0d2SJohn Dyson 79295e5e988SJohn Dyson vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, p, 0, 0); 793996c772fSJohn Dyson error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE, 794df8bae1dSRodney W. Grimes NOCRED, p); 7956476c0d2SJohn Dyson 7966476c0d2SJohn Dyson vrele(ump->um_devvp); 7976476c0d2SJohn Dyson 798df8bae1dSRodney W. Grimes free(fs->fs_csp[0], M_UFSMNT); 799df8bae1dSRodney W. Grimes free(fs, M_UFSMNT); 800df8bae1dSRodney W. Grimes free(ump, M_UFSMNT); 801df8bae1dSRodney W. Grimes mp->mnt_data = (qaddr_t)0; 802cc9d8990SPeter Wemm mp->mnt_flag &= ~MNT_LOCAL; 803df8bae1dSRodney W. Grimes return (error); 804df8bae1dSRodney W. Grimes } 805df8bae1dSRodney W. Grimes 806df8bae1dSRodney W. Grimes /* 807df8bae1dSRodney W. Grimes * Flush out all the files in a filesystem. 808df8bae1dSRodney W. Grimes */ 80926f9a767SRodney W. Grimes int 810df8bae1dSRodney W. Grimes ffs_flushfiles(mp, flags, p) 811df8bae1dSRodney W. Grimes register struct mount *mp; 812df8bae1dSRodney W. Grimes int flags; 813df8bae1dSRodney W. Grimes struct proc *p; 814df8bae1dSRodney W. Grimes { 815df8bae1dSRodney W. Grimes register struct ufsmount *ump; 816c9671602SPoul-Henning Kamp int error; 817df8bae1dSRodney W. Grimes 818df8bae1dSRodney W. Grimes ump = VFSTOUFS(mp); 819df8bae1dSRodney W. Grimes #ifdef QUOTA 820df8bae1dSRodney W. Grimes if (mp->mnt_flag & MNT_QUOTA) { 821c1d9efcbSPoul-Henning Kamp int i; 822c1d9efcbSPoul-Henning Kamp error = vflush(mp, NULLVP, SKIPSYSTEM|flags); 823c1d9efcbSPoul-Henning Kamp if (error) 824df8bae1dSRodney W. Grimes return (error); 825df8bae1dSRodney W. Grimes for (i = 0; i < MAXQUOTAS; i++) { 826df8bae1dSRodney W. Grimes if (ump->um_quotas[i] == NULLVP) 827df8bae1dSRodney W. Grimes continue; 828df8bae1dSRodney W. Grimes quotaoff(p, mp, i); 829df8bae1dSRodney W. Grimes } 830df8bae1dSRodney W. Grimes /* 831df8bae1dSRodney W. Grimes * Here we fall through to vflush again to ensure 832df8bae1dSRodney W. Grimes * that we have gotten rid of all the system vnodes. 833df8bae1dSRodney W. Grimes */ 834df8bae1dSRodney W. Grimes } 835df8bae1dSRodney W. Grimes #endif 836f2a2857bSKirk McKusick if (ump->um_devvp->v_flag & VCOPYONWRITE) { 837f2a2857bSKirk McKusick if ((error = vflush(mp, NULL, SKIPSYSTEM | flags)) != 0) 838f2a2857bSKirk McKusick return (error); 839f2a2857bSKirk McKusick ffs_snapshot_unmount(mp); 840f2a2857bSKirk McKusick /* 841f2a2857bSKirk McKusick * Here we fall through to vflush again to ensure 842f2a2857bSKirk McKusick * that we have gotten rid of all the system vnodes. 843f2a2857bSKirk McKusick */ 844f2a2857bSKirk McKusick } 845b1897c19SJulian Elischer /* 846b1897c19SJulian Elischer * Flush all the files. 847b1897c19SJulian Elischer */ 848b1897c19SJulian Elischer if ((error = vflush(mp, NULL, flags)) != 0) 849b1897c19SJulian Elischer return (error); 850b1897c19SJulian Elischer /* 851b1897c19SJulian Elischer * Flush filesystem metadata. 852b1897c19SJulian Elischer */ 853b1897c19SJulian Elischer vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p); 854b1897c19SJulian Elischer error = VOP_FSYNC(ump->um_devvp, p->p_ucred, MNT_WAIT, p); 855b1897c19SJulian Elischer VOP_UNLOCK(ump->um_devvp, 0, p); 856df8bae1dSRodney W. Grimes return (error); 857df8bae1dSRodney W. Grimes } 858df8bae1dSRodney W. Grimes 859df8bae1dSRodney W. Grimes /* 860df8bae1dSRodney W. Grimes * Get file system statistics. 861df8bae1dSRodney W. Grimes */ 862df8bae1dSRodney W. Grimes int 863df8bae1dSRodney W. Grimes ffs_statfs(mp, sbp, p) 864df8bae1dSRodney W. Grimes struct mount *mp; 865df8bae1dSRodney W. Grimes register struct statfs *sbp; 866df8bae1dSRodney W. Grimes struct proc *p; 867df8bae1dSRodney W. Grimes { 868df8bae1dSRodney W. Grimes register struct ufsmount *ump; 869df8bae1dSRodney W. Grimes register struct fs *fs; 870df8bae1dSRodney W. Grimes 871df8bae1dSRodney W. Grimes ump = VFSTOUFS(mp); 872df8bae1dSRodney W. Grimes fs = ump->um_fs; 873df8bae1dSRodney W. Grimes if (fs->fs_magic != FS_MAGIC) 874df8bae1dSRodney W. Grimes panic("ffs_statfs"); 875df8bae1dSRodney W. Grimes sbp->f_bsize = fs->fs_fsize; 876df8bae1dSRodney W. Grimes sbp->f_iosize = fs->fs_bsize; 877df8bae1dSRodney W. Grimes sbp->f_blocks = fs->fs_dsize; 878df8bae1dSRodney W. Grimes sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 879df8bae1dSRodney W. Grimes fs->fs_cstotal.cs_nffree; 88051ea8b57SBruce Evans sbp->f_bavail = freespace(fs, fs->fs_minfree); 881df8bae1dSRodney W. Grimes sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; 882df8bae1dSRodney W. Grimes sbp->f_ffree = fs->fs_cstotal.cs_nifree; 883df8bae1dSRodney W. Grimes if (sbp != &mp->mnt_stat) { 884996c772fSJohn Dyson sbp->f_type = mp->mnt_vfc->vfc_typenum; 885df8bae1dSRodney W. Grimes bcopy((caddr_t)mp->mnt_stat.f_mntonname, 886df8bae1dSRodney W. Grimes (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 887df8bae1dSRodney W. Grimes bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 888df8bae1dSRodney W. Grimes (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 889df8bae1dSRodney W. Grimes } 890df8bae1dSRodney W. Grimes return (0); 891df8bae1dSRodney W. Grimes } 892df8bae1dSRodney W. Grimes 893df8bae1dSRodney W. Grimes /* 894df8bae1dSRodney W. Grimes * Go through the disk queues to initiate sandbagged IO; 895df8bae1dSRodney W. Grimes * go through the inodes to write those that have been modified; 896df8bae1dSRodney W. Grimes * initiate the writing of the super block if it has been modified. 897df8bae1dSRodney W. Grimes * 898df8bae1dSRodney W. Grimes * Note: we are always called with the filesystem marked `MPBUSY'. 899df8bae1dSRodney W. Grimes */ 900df8bae1dSRodney W. Grimes int 901df8bae1dSRodney W. Grimes ffs_sync(mp, waitfor, cred, p) 902df8bae1dSRodney W. Grimes struct mount *mp; 903df8bae1dSRodney W. Grimes int waitfor; 904df8bae1dSRodney W. Grimes struct ucred *cred; 905df8bae1dSRodney W. Grimes struct proc *p; 906df8bae1dSRodney W. Grimes { 907996c772fSJohn Dyson struct vnode *nvp, *vp; 908996c772fSJohn Dyson struct inode *ip; 909996c772fSJohn Dyson struct ufsmount *ump = VFSTOUFS(mp); 910996c772fSJohn Dyson struct fs *fs; 9119b971133SKirk McKusick int error, count, wait, lockreq, allerror = 0; 912df8bae1dSRodney W. Grimes 913df8bae1dSRodney W. Grimes fs = ump->um_fs; 914996c772fSJohn Dyson if (fs->fs_fmod != 0 && fs->fs_ronly != 0) { /* XXX */ 915df8bae1dSRodney W. Grimes printf("fs = %s\n", fs->fs_fsmnt); 9165ace3b26SMike Pritchard panic("ffs_sync: rofs mod"); 917df8bae1dSRodney W. Grimes } 918df8bae1dSRodney W. Grimes /* 919df8bae1dSRodney W. Grimes * Write back each (modified) inode. 920df8bae1dSRodney W. Grimes */ 9219b971133SKirk McKusick wait = 0; 9229b971133SKirk McKusick lockreq = LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK; 9239b971133SKirk McKusick if (waitfor == MNT_WAIT) { 9249b971133SKirk McKusick wait = 1; 9259b971133SKirk McKusick lockreq = LK_EXCLUSIVE | LK_INTERLOCK; 9269b971133SKirk McKusick } 927996c772fSJohn Dyson simple_lock(&mntvnode_slock); 928df8bae1dSRodney W. Grimes loop: 929a316d390SJohn Dyson for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { 930df8bae1dSRodney W. Grimes /* 931df8bae1dSRodney W. Grimes * If the vnode that we are about to sync is no longer 932df8bae1dSRodney W. Grimes * associated with this mount point, start over. 933df8bae1dSRodney W. Grimes */ 934df8bae1dSRodney W. Grimes if (vp->v_mount != mp) 935df8bae1dSRodney W. Grimes goto loop; 936996c772fSJohn Dyson simple_lock(&vp->v_interlock); 937a316d390SJohn Dyson nvp = vp->v_mntvnodes.le_next; 938df8bae1dSRodney W. Grimes ip = VTOI(vp); 939cf60e8e4SKirk McKusick if (vp->v_type == VNON || ((ip->i_flag & 940cf60e8e4SKirk McKusick (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && 941cf60e8e4SKirk McKusick TAILQ_EMPTY(&vp->v_dirtyblkhd))) { 942996c772fSJohn Dyson simple_unlock(&vp->v_interlock); 943df8bae1dSRodney W. Grimes continue; 944996c772fSJohn Dyson } 94581c6e3e5SDavid Greenman if (vp->v_type != VCHR) { 946996c772fSJohn Dyson simple_unlock(&mntvnode_slock); 9479b971133SKirk McKusick if ((error = vget(vp, lockreq, p)) != 0) { 948996c772fSJohn Dyson simple_lock(&mntvnode_slock); 949996c772fSJohn Dyson if (error == ENOENT) 950df8bae1dSRodney W. Grimes goto loop; 951996c772fSJohn Dyson continue; 952996c772fSJohn Dyson } 9538aef1712SMatthew Dillon if ((error = VOP_FSYNC(vp, cred, waitfor, p)) != 0) 954df8bae1dSRodney W. Grimes allerror = error; 9559b971133SKirk McKusick vput(vp); 956996c772fSJohn Dyson simple_lock(&mntvnode_slock); 95781c6e3e5SDavid Greenman } else { 958996c772fSJohn Dyson simple_unlock(&mntvnode_slock); 959996c772fSJohn Dyson simple_unlock(&vp->v_interlock); 9609b971133SKirk McKusick UFS_UPDATE(vp, wait); 961996c772fSJohn Dyson simple_lock(&mntvnode_slock); 96281c6e3e5SDavid Greenman } 963df8bae1dSRodney W. Grimes } 964996c772fSJohn Dyson simple_unlock(&mntvnode_slock); 965df8bae1dSRodney W. Grimes /* 966df8bae1dSRodney W. Grimes * Force stale file system control information to be flushed. 967df8bae1dSRodney W. Grimes */ 9689b971133SKirk McKusick if (waitfor == MNT_WAIT) { 9699b971133SKirk McKusick if ((error = softdep_flushworklist(ump->um_mountp, &count, p))) 9709b971133SKirk McKusick allerror = error; 9719b971133SKirk McKusick /* Flushed work items may create new vnodes to clean */ 9729b971133SKirk McKusick if (count) { 9739b971133SKirk McKusick simple_lock(&mntvnode_slock); 9749b971133SKirk McKusick goto loop; 9759b971133SKirk McKusick } 9769b971133SKirk McKusick } 9779b971133SKirk McKusick if (waitfor == MNT_NOWAIT) { 978b1897c19SJulian Elischer vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p); 979b1897c19SJulian Elischer if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) != 0) 980df8bae1dSRodney W. Grimes allerror = error; 981b1897c19SJulian Elischer VOP_UNLOCK(ump->um_devvp, 0, p); 982b1897c19SJulian Elischer } 983df8bae1dSRodney W. Grimes #ifdef QUOTA 984df8bae1dSRodney W. Grimes qsync(mp); 985df8bae1dSRodney W. Grimes #endif 986996c772fSJohn Dyson /* 987996c772fSJohn Dyson * Write back modified superblock. 988996c772fSJohn Dyson */ 989b1897c19SJulian Elischer if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0) 990996c772fSJohn Dyson allerror = error; 991df8bae1dSRodney W. Grimes return (allerror); 992df8bae1dSRodney W. Grimes } 993df8bae1dSRodney W. Grimes 994df8bae1dSRodney W. Grimes /* 995df8bae1dSRodney W. Grimes * Look up a FFS dinode number to find its incore vnode, otherwise read it 996df8bae1dSRodney W. Grimes * in from disk. If it is in core, wait for the lock bit to clear, then 997df8bae1dSRodney W. Grimes * return the inode locked. Detection and handling of mount points must be 998df8bae1dSRodney W. Grimes * done by the calling routine. 999df8bae1dSRodney W. Grimes */ 1000b8dce649SPoul-Henning Kamp static int ffs_inode_hash_lock; 10012094ddb6SDavid Greenman 1002df8bae1dSRodney W. Grimes int 1003df8bae1dSRodney W. Grimes ffs_vget(mp, ino, vpp) 1004df8bae1dSRodney W. Grimes struct mount *mp; 1005df8bae1dSRodney W. Grimes ino_t ino; 1006df8bae1dSRodney W. Grimes struct vnode **vpp; 1007df8bae1dSRodney W. Grimes { 1008996c772fSJohn Dyson struct fs *fs; 1009996c772fSJohn Dyson struct inode *ip; 1010df8bae1dSRodney W. Grimes struct ufsmount *ump; 1011df8bae1dSRodney W. Grimes struct buf *bp; 1012df8bae1dSRodney W. Grimes struct vnode *vp; 1013df8bae1dSRodney W. Grimes dev_t dev; 10140be6b890SPoul-Henning Kamp int error; 1015df8bae1dSRodney W. Grimes 1016df8bae1dSRodney W. Grimes ump = VFSTOUFS(mp); 1017df8bae1dSRodney W. Grimes dev = ump->um_dev; 10188997d94fSDavid Greenman restart: 10198f9110f6SJohn Dyson if ((*vpp = ufs_ihashget(dev, ino)) != NULL) { 1020df8bae1dSRodney W. Grimes return (0); 10218f9110f6SJohn Dyson } 1022df8bae1dSRodney W. Grimes 10232094ddb6SDavid Greenman /* 10248997d94fSDavid Greenman * Lock out the creation of new entries in the FFS hash table in 10258997d94fSDavid Greenman * case getnewvnode() or MALLOC() blocks, otherwise a duplicate 10262094ddb6SDavid Greenman * may occur! 10272094ddb6SDavid Greenman */ 10282094ddb6SDavid Greenman if (ffs_inode_hash_lock) { 10292094ddb6SDavid Greenman while (ffs_inode_hash_lock) { 10302094ddb6SDavid Greenman ffs_inode_hash_lock = -1; 10312094ddb6SDavid Greenman tsleep(&ffs_inode_hash_lock, PVM, "ffsvgt", 0); 10322094ddb6SDavid Greenman } 10338997d94fSDavid Greenman goto restart; 10342094ddb6SDavid Greenman } 10352094ddb6SDavid Greenman ffs_inode_hash_lock = 1; 10362094ddb6SDavid Greenman 10372f9bae59SDavid Greenman /* 10382f9bae59SDavid Greenman * If this MALLOC() is performed after the getnewvnode() 10392f9bae59SDavid Greenman * it might block, leaving a vnode with a NULL v_data to be 10402f9bae59SDavid Greenman * found by ffs_sync() if a sync happens to fire right then, 10412f9bae59SDavid Greenman * which will cause a panic because ffs_sync() blindly 10422f9bae59SDavid Greenman * dereferences vp->v_data (as well it should). 10432f9bae59SDavid Greenman */ 10440be6b890SPoul-Henning Kamp MALLOC(ip, struct inode *, sizeof(struct inode), 10450be6b890SPoul-Henning Kamp ump->um_malloctype, M_WAITOK); 10462f9bae59SDavid Greenman 1047df8bae1dSRodney W. Grimes /* Allocate a new vnode/inode. */ 1048c9671602SPoul-Henning Kamp error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp); 1049c9671602SPoul-Henning Kamp if (error) { 10508997d94fSDavid Greenman if (ffs_inode_hash_lock < 0) 10512094ddb6SDavid Greenman wakeup(&ffs_inode_hash_lock); 10522094ddb6SDavid Greenman ffs_inode_hash_lock = 0; 1053df8bae1dSRodney W. Grimes *vpp = NULL; 10540be6b890SPoul-Henning Kamp FREE(ip, ump->um_malloctype); 1055df8bae1dSRodney W. Grimes return (error); 1056df8bae1dSRodney W. Grimes } 1057df8bae1dSRodney W. Grimes bzero((caddr_t)ip, sizeof(struct inode)); 1058cf60e8e4SKirk McKusick lockinit(&ip->i_lock, PINOD, "inode", 0, LK_CANRECURSE); 1059df8bae1dSRodney W. Grimes vp->v_data = ip; 1060df8bae1dSRodney W. Grimes ip->i_vnode = vp; 1061df8bae1dSRodney W. Grimes ip->i_fs = fs = ump->um_fs; 1062df8bae1dSRodney W. Grimes ip->i_dev = dev; 1063df8bae1dSRodney W. Grimes ip->i_number = ino; 1064df8bae1dSRodney W. Grimes #ifdef QUOTA 1065c1d9efcbSPoul-Henning Kamp { 1066c1d9efcbSPoul-Henning Kamp int i; 1067df8bae1dSRodney W. Grimes for (i = 0; i < MAXQUOTAS; i++) 1068df8bae1dSRodney W. Grimes ip->i_dquot[i] = NODQUOT; 1069c1d9efcbSPoul-Henning Kamp } 1070df8bae1dSRodney W. Grimes #endif 1071df8bae1dSRodney W. Grimes /* 1072df8bae1dSRodney W. Grimes * Put it onto its hash chain and lock it so that other requests for 1073df8bae1dSRodney W. Grimes * this inode will block if they arrive while we are sleeping waiting 1074df8bae1dSRodney W. Grimes * for old data structures to be purged or for the contents of the 1075df8bae1dSRodney W. Grimes * disk portion of this inode to be read. 1076df8bae1dSRodney W. Grimes */ 1077df8bae1dSRodney W. Grimes ufs_ihashins(ip); 1078df8bae1dSRodney W. Grimes 10798997d94fSDavid Greenman if (ffs_inode_hash_lock < 0) 10802094ddb6SDavid Greenman wakeup(&ffs_inode_hash_lock); 10812094ddb6SDavid Greenman ffs_inode_hash_lock = 0; 10822094ddb6SDavid Greenman 1083df8bae1dSRodney W. Grimes /* Read in the disk contents for the inode, copy into the inode. */ 1084c9671602SPoul-Henning Kamp error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), 1085c9671602SPoul-Henning Kamp (int)fs->fs_bsize, NOCRED, &bp); 1086c9671602SPoul-Henning Kamp if (error) { 1087df8bae1dSRodney W. Grimes /* 1088df8bae1dSRodney W. Grimes * The inode does not contain anything useful, so it would 1089df8bae1dSRodney W. Grimes * be misleading to leave it on its hash chain. With mode 1090df8bae1dSRodney W. Grimes * still zero, it will be unlinked and returned to the free 1091df8bae1dSRodney W. Grimes * list by vput(). 1092df8bae1dSRodney W. Grimes */ 1093df8bae1dSRodney W. Grimes brelse(bp); 1094bd7e5f99SJohn Dyson vput(vp); 1095df8bae1dSRodney W. Grimes *vpp = NULL; 1096df8bae1dSRodney W. Grimes return (error); 1097df8bae1dSRodney W. Grimes } 1098df8bae1dSRodney W. Grimes ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino)); 1099b1897c19SJulian Elischer if (DOINGSOFTDEP(vp)) 1100b1897c19SJulian Elischer softdep_load_inodeblock(ip); 1101b1897c19SJulian Elischer else 1102b1897c19SJulian Elischer ip->i_effnlink = ip->i_nlink; 1103bd7e5f99SJohn Dyson bqrelse(bp); 1104df8bae1dSRodney W. Grimes 1105df8bae1dSRodney W. Grimes /* 1106df8bae1dSRodney W. Grimes * Initialize the vnode from the inode, check for aliases. 1107df8bae1dSRodney W. Grimes * Note that the underlying vnode may have changed. 1108df8bae1dSRodney W. Grimes */ 1109e6302eabSBruce Evans error = ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, &vp); 1110c9671602SPoul-Henning Kamp if (error) { 1111df8bae1dSRodney W. Grimes vput(vp); 1112df8bae1dSRodney W. Grimes *vpp = NULL; 1113df8bae1dSRodney W. Grimes return (error); 1114df8bae1dSRodney W. Grimes } 1115df8bae1dSRodney W. Grimes /* 1116df8bae1dSRodney W. Grimes * Finish inode initialization now that aliasing has been resolved. 1117df8bae1dSRodney W. Grimes */ 1118df8bae1dSRodney W. Grimes ip->i_devvp = ump->um_devvp; 1119df8bae1dSRodney W. Grimes VREF(ip->i_devvp); 1120df8bae1dSRodney W. Grimes /* 1121df8bae1dSRodney W. Grimes * Set up a generation number for this inode if it does not 1122df8bae1dSRodney W. Grimes * already have one. This should only happen on old filesystems. 1123df8bae1dSRodney W. Grimes */ 1124df8bae1dSRodney W. Grimes if (ip->i_gen == 0) { 11258f89943eSGuido van Rooij ip->i_gen = random() / 2 + 1; 1126df8bae1dSRodney W. Grimes if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 1127df8bae1dSRodney W. Grimes ip->i_flag |= IN_MODIFIED; 1128df8bae1dSRodney W. Grimes } 1129df8bae1dSRodney W. Grimes /* 1130df8bae1dSRodney W. Grimes * Ensure that uid and gid are correct. This is a temporary 1131df8bae1dSRodney W. Grimes * fix until fsck has been changed to do the update. 1132df8bae1dSRodney W. Grimes */ 1133df8bae1dSRodney W. Grimes if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 1134df8bae1dSRodney W. Grimes ip->i_uid = ip->i_din.di_ouid; /* XXX */ 1135df8bae1dSRodney W. Grimes ip->i_gid = ip->i_din.di_ogid; /* XXX */ 1136df8bae1dSRodney W. Grimes } /* XXX */ 1137df8bae1dSRodney W. Grimes 1138df8bae1dSRodney W. Grimes *vpp = vp; 1139df8bae1dSRodney W. Grimes return (0); 1140df8bae1dSRodney W. Grimes } 1141df8bae1dSRodney W. Grimes 1142df8bae1dSRodney W. Grimes /* 1143df8bae1dSRodney W. Grimes * File handle to vnode 1144df8bae1dSRodney W. Grimes * 1145df8bae1dSRodney W. Grimes * Have to be really careful about stale file handles: 1146df8bae1dSRodney W. Grimes * - check that the inode number is valid 1147df8bae1dSRodney W. Grimes * - call ffs_vget() to get the locked inode 1148df8bae1dSRodney W. Grimes * - check for an unallocated inode (i_mode == 0) 1149df8bae1dSRodney W. Grimes * - check that the given client host has export rights and return 1150df8bae1dSRodney W. Grimes * those rights via. exflagsp and credanonp 1151df8bae1dSRodney W. Grimes */ 1152df8bae1dSRodney W. Grimes int 1153c24fda81SAlfred Perlstein ffs_fhtovp(mp, fhp, vpp) 1154df8bae1dSRodney W. Grimes register struct mount *mp; 1155df8bae1dSRodney W. Grimes struct fid *fhp; 1156df8bae1dSRodney W. Grimes struct vnode **vpp; 1157df8bae1dSRodney W. Grimes { 1158df8bae1dSRodney W. Grimes register struct ufid *ufhp; 1159df8bae1dSRodney W. Grimes struct fs *fs; 1160df8bae1dSRodney W. Grimes 1161df8bae1dSRodney W. Grimes ufhp = (struct ufid *)fhp; 1162df8bae1dSRodney W. Grimes fs = VFSTOUFS(mp)->um_fs; 1163df8bae1dSRodney W. Grimes if (ufhp->ufid_ino < ROOTINO || 1164df8bae1dSRodney W. Grimes ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) 1165df8bae1dSRodney W. Grimes return (ESTALE); 1166c24fda81SAlfred Perlstein return (ufs_fhtovp(mp, ufhp, vpp)); 1167df8bae1dSRodney W. Grimes } 1168df8bae1dSRodney W. Grimes 1169df8bae1dSRodney W. Grimes /* 1170df8bae1dSRodney W. Grimes * Vnode pointer to File handle 1171df8bae1dSRodney W. Grimes */ 1172df8bae1dSRodney W. Grimes /* ARGSUSED */ 117326f9a767SRodney W. Grimes int 1174df8bae1dSRodney W. Grimes ffs_vptofh(vp, fhp) 1175df8bae1dSRodney W. Grimes struct vnode *vp; 1176df8bae1dSRodney W. Grimes struct fid *fhp; 1177df8bae1dSRodney W. Grimes { 1178df8bae1dSRodney W. Grimes register struct inode *ip; 1179df8bae1dSRodney W. Grimes register struct ufid *ufhp; 1180df8bae1dSRodney W. Grimes 1181df8bae1dSRodney W. Grimes ip = VTOI(vp); 1182df8bae1dSRodney W. Grimes ufhp = (struct ufid *)fhp; 1183df8bae1dSRodney W. Grimes ufhp->ufid_len = sizeof(struct ufid); 1184df8bae1dSRodney W. Grimes ufhp->ufid_ino = ip->i_number; 1185df8bae1dSRodney W. Grimes ufhp->ufid_gen = ip->i_gen; 1186df8bae1dSRodney W. Grimes return (0); 1187df8bae1dSRodney W. Grimes } 1188df8bae1dSRodney W. Grimes 1189df8bae1dSRodney W. Grimes /* 1190996c772fSJohn Dyson * Initialize the filesystem; just use ufs_init. 1191996c772fSJohn Dyson */ 1192996c772fSJohn Dyson static int 1193996c772fSJohn Dyson ffs_init(vfsp) 1194996c772fSJohn Dyson struct vfsconf *vfsp; 1195996c772fSJohn Dyson { 1196996c772fSJohn Dyson 1197b1897c19SJulian Elischer softdep_initialize(); 1198996c772fSJohn Dyson return (ufs_init(vfsp)); 1199996c772fSJohn Dyson } 1200996c772fSJohn Dyson 1201996c772fSJohn Dyson /* 1202df8bae1dSRodney W. Grimes * Write a superblock and associated information back to disk. 1203df8bae1dSRodney W. Grimes */ 1204b8dce649SPoul-Henning Kamp static int 1205df8bae1dSRodney W. Grimes ffs_sbupdate(mp, waitfor) 1206df8bae1dSRodney W. Grimes struct ufsmount *mp; 1207df8bae1dSRodney W. Grimes int waitfor; 1208df8bae1dSRodney W. Grimes { 1209996c772fSJohn Dyson register struct fs *dfs, *fs = mp->um_fs; 1210df8bae1dSRodney W. Grimes register struct buf *bp; 1211df8bae1dSRodney W. Grimes int blks; 1212df8bae1dSRodney W. Grimes caddr_t space; 1213996c772fSJohn Dyson int i, size, error, allerror = 0; 1214df8bae1dSRodney W. Grimes 1215996c772fSJohn Dyson /* 1216996c772fSJohn Dyson * First write back the summary information. 1217996c772fSJohn Dyson */ 1218df8bae1dSRodney W. Grimes blks = howmany(fs->fs_cssize, fs->fs_fsize); 1219df8bae1dSRodney W. Grimes space = (caddr_t)fs->fs_csp[0]; 1220df8bae1dSRodney W. Grimes for (i = 0; i < blks; i += fs->fs_frag) { 1221df8bae1dSRodney W. Grimes size = fs->fs_bsize; 1222df8bae1dSRodney W. Grimes if (i + fs->fs_frag > blks) 1223df8bae1dSRodney W. Grimes size = (blks - i) * fs->fs_fsize; 1224df8bae1dSRodney W. Grimes bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), 1225df8bae1dSRodney W. Grimes size, 0, 0); 1226df8bae1dSRodney W. Grimes bcopy(space, bp->b_data, (u_int)size); 1227df8bae1dSRodney W. Grimes space += size; 1228996c772fSJohn Dyson if (waitfor != MNT_WAIT) 1229df8bae1dSRodney W. Grimes bawrite(bp); 12308aef1712SMatthew Dillon else if ((error = bwrite(bp)) != 0) 1231996c772fSJohn Dyson allerror = error; 1232df8bae1dSRodney W. Grimes } 1233996c772fSJohn Dyson /* 1234996c772fSJohn Dyson * Now write back the superblock itself. If any errors occurred 1235996c772fSJohn Dyson * up to this point, then fail so that the superblock avoids 1236996c772fSJohn Dyson * being written out as clean. 1237996c772fSJohn Dyson */ 1238996c772fSJohn Dyson if (allerror) 1239996c772fSJohn Dyson return (allerror); 1240996c772fSJohn Dyson bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); 1241b1897c19SJulian Elischer fs->fs_fmod = 0; 1242227ee8a1SPoul-Henning Kamp fs->fs_time = time_second; 1243996c772fSJohn Dyson bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); 1244996c772fSJohn Dyson /* Restore compatibility to old file systems. XXX */ 1245996c772fSJohn Dyson dfs = (struct fs *)bp->b_data; /* XXX */ 1246996c772fSJohn Dyson if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 1247996c772fSJohn Dyson dfs->fs_nrpos = -1; /* XXX */ 1248996c772fSJohn Dyson if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 1249996c772fSJohn Dyson int32_t *lp, tmp; /* XXX */ 1250996c772fSJohn Dyson /* XXX */ 1251996c772fSJohn Dyson lp = (int32_t *)&dfs->fs_qbmask; /* XXX */ 1252996c772fSJohn Dyson tmp = lp[4]; /* XXX */ 1253996c772fSJohn Dyson for (i = 4; i > 0; i--) /* XXX */ 1254996c772fSJohn Dyson lp[i] = lp[i-1]; /* XXX */ 1255996c772fSJohn Dyson lp[0] = tmp; /* XXX */ 1256996c772fSJohn Dyson } /* XXX */ 1257996c772fSJohn Dyson dfs->fs_maxfilesize = mp->um_savedmaxfilesize; /* XXX */ 1258996c772fSJohn Dyson if (waitfor != MNT_WAIT) 1259996c772fSJohn Dyson bawrite(bp); 12608aef1712SMatthew Dillon else if ((error = bwrite(bp)) != 0) 1261996c772fSJohn Dyson allerror = error; 1262996c772fSJohn Dyson return (allerror); 1263df8bae1dSRodney W. Grimes } 1264