ffs_vfsops.c revision 55029
1290650Shselasky/* 2321992Shselasky * Copyright (c) 1989, 1991, 1993, 1994 3290650Shselasky * The Regents of the University of California. All rights reserved. 4290650Shselasky * 5290650Shselasky * Redistribution and use in source and binary forms, with or without 6290650Shselasky * modification, are permitted provided that the following conditions 7290650Shselasky * are met: 8290650Shselasky * 1. Redistributions of source code must retain the above copyright 9290650Shselasky * notice, this list of conditions and the following disclaimer. 10290650Shselasky * 2. Redistributions in binary form must reproduce the above copyright 11290650Shselasky * notice, this list of conditions and the following disclaimer in the 12290650Shselasky * documentation and/or other materials provided with the distribution. 13290650Shselasky * 3. All advertising materials mentioning features or use of this software 14290650Shselasky * must display the following acknowledgement: 15290650Shselasky * This product includes software developed by the University of 16290650Shselasky * California, Berkeley and its contributors. 17290650Shselasky * 4. Neither the name of the University nor the names of its contributors 18290650Shselasky * may be used to endorse or promote products derived from this software 19290650Shselasky * without specific prior written permission. 20290650Shselasky * 21290650Shselasky * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22290650Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23290650Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24290650Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25290650Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26321992Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27290650Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28290650Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29290650Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30290650Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31290650Shselasky * SUCH DAMAGE. 32290650Shselasky * 33290650Shselasky * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95 34290650Shselasky * $FreeBSD: head/sys/ufs/ffs/ffs_vfsops.c 55029 1999-12-23 15:42:14Z bde $ 35290650Shselasky */ 36290650Shselasky 37290650Shselasky#include "opt_quota.h" 38290650Shselasky 39290650Shselasky#include <sys/param.h> 40290650Shselasky#include <sys/systm.h> 41290650Shselasky#include <sys/namei.h> 42290650Shselasky#include <sys/proc.h> 43290650Shselasky#include <sys/kernel.h> 44290650Shselasky#include <sys/vnode.h> 45290650Shselasky#include <sys/mount.h> 46290650Shselasky#include <sys/buf.h> 47290650Shselasky#include <sys/conf.h> 48290650Shselasky#include <sys/fcntl.h> 49290650Shselasky#include <sys/disklabel.h> 50290650Shselasky#include <sys/malloc.h> 51306233Shselasky 52290650Shselasky#include <ufs/ufs/quota.h> 53306233Shselasky#include <ufs/ufs/ufsmount.h> 54321992Shselasky#include <ufs/ufs/inode.h> 55321992Shselasky#include <ufs/ufs/ufs_extern.h> 56290650Shselasky 57290650Shselasky#include <ufs/ffs/fs.h> 58290650Shselasky#include <ufs/ffs/ffs_extern.h> 59290650Shselasky 60290650Shselasky#include <vm/vm.h> 61290650Shselasky#include <vm/vm_page.h> 62290650Shselasky#include <vm/vm_zone.h> 63290650Shselasky 64290650Shselaskystatic MALLOC_DEFINE(M_FFSNODE, "FFS node", "FFS vnode private part"); 65306233Shselasky 66306233Shselaskystatic int ffs_sbupdate __P((struct ufsmount *, int)); 67306233Shselaskystatic int ffs_reload __P((struct mount *,struct ucred *,struct proc *)); 68306233Shselaskystatic int ffs_oldfscompat __P((struct fs *)); 69306233Shselaskystatic int ffs_mount __P((struct mount *, char *, caddr_t, 70290650Shselasky struct nameidata *, struct proc *)); 71290650Shselaskystatic int ffs_init __P((struct vfsconf *)); 72290650Shselasky 73290650Shselaskystatic struct vfsops ufs_vfsops = { 74290650Shselasky ffs_mount, 75290650Shselasky ufs_start, 76290650Shselasky ffs_unmount, 77290650Shselasky ufs_root, 78290650Shselasky ufs_quotactl, 79290650Shselasky ffs_statfs, 80290650Shselasky ffs_sync, 81290650Shselasky ffs_vget, 82290650Shselasky ffs_fhtovp, 83290650Shselasky ufs_check_export, 84290650Shselasky ffs_vptofh, 85290650Shselasky ffs_init, 86290650Shselasky vfs_stduninit, 87290650Shselasky vfs_stdextattrctl, 88290650Shselasky}; 89321992Shselasky 90321992ShselaskyVFS_SET(ufs_vfsops, ufs, 0); 91290650Shselasky 92290650Shselasky/* 93290650Shselasky * ffs_mount 94290650Shselasky * 95290650Shselasky * Called when mounting local physical media 96290650Shselasky * 97290650Shselasky * PARAMETERS: 98290650Shselasky * mountroot 99290650Shselasky * mp mount point structure 100290650Shselasky * path NULL (flag for root mount!!!) 101290650Shselasky * data <unused> 102290650Shselasky * ndp <unused> 103290650Shselasky * p process (user credentials check [statfs]) 104290650Shselasky * 105290650Shselasky * mount 106290650Shselasky * mp mount point structure 107290650Shselasky * path path to mount point 108290650Shselasky * data pointer to argument struct in user space 109290650Shselasky * ndp mount point namei() return (used for 110290650Shselasky * credentials on reload), reused to look 111290650Shselasky * up block device. 112290650Shselasky * p process (user credentials check) 113290650Shselasky * 114290650Shselasky * RETURNS: 0 Success 115290650Shselasky * !0 error number (errno.h) 116290650Shselasky * 117290650Shselasky * LOCK STATE: 118290650Shselasky * 119290650Shselasky * ENTRY 120290650Shselasky * mount point is locked 121290650Shselasky * EXIT 122290650Shselasky * mount point is locked 123290650Shselasky * 124290650Shselasky * NOTES: 125290650Shselasky * A NULL path can be used for a flag since the mount 126290650Shselasky * system call will fail with EFAULT in copyinstr in 127290650Shselasky * namei() if it is a genuine NULL from the user. 128290650Shselasky */ 129290650Shselaskystatic int 130290650Shselaskyffs_mount( mp, path, data, ndp, p) 131290650Shselasky struct mount *mp; /* mount struct pointer*/ 132290650Shselasky char *path; /* path to mount point*/ 133290650Shselasky caddr_t data; /* arguments to FS specific mount*/ 134290650Shselasky struct nameidata *ndp; /* mount point credentials*/ 135290650Shselasky struct proc *p; /* process requesting mount*/ 136290650Shselasky{ 137290650Shselasky size_t size; 138290650Shselasky int err = 0; 139290650Shselasky struct vnode *devvp; 140290650Shselasky 141290650Shselasky struct ufs_args args; 142290650Shselasky struct ufsmount *ump = 0; 143290650Shselasky register struct fs *fs; 144290650Shselasky int error, flags, ronly = 0; 145290650Shselasky mode_t accessmode; 146290650Shselasky 147290650Shselasky /* 148290650Shselasky * Use NULL path to flag a root mount 149306233Shselasky */ 150306233Shselasky if( path == NULL) { 151308678Shselasky /* 152308678Shselasky *** 153308678Shselasky * Mounting root file system 154308678Shselasky *** 155308678Shselasky */ 156308678Shselasky 157290650Shselasky if ((err = bdevvp(rootdev, &rootvp))) { 158290650Shselasky printf("ffs_mountroot: can't find rootvp\n"); 159290650Shselasky return (err); 160290650Shselasky } 161290650Shselasky 162290650Shselasky if( ( err = ffs_mountfs(rootvp, mp, p, M_FFSNODE)) != 0) { 163290650Shselasky /* fs specific cleanup (if any)*/ 164290650Shselasky goto error_1; 165290650Shselasky } 166290650Shselasky 167290650Shselasky goto dostatfs; /* success*/ 168290650Shselasky 169290650Shselasky } 170290650Shselasky 171290650Shselasky /* 172290650Shselasky *** 173290650Shselasky * Mounting non-root file system or updating a file system 174290650Shselasky *** 175290650Shselasky */ 176290650Shselasky 177290650Shselasky /* copy in user arguments*/ 178306233Shselasky err = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)); 179306233Shselasky if (err) 180290650Shselasky goto error_1; /* can't get arguments*/ 181290650Shselasky 182290650Shselasky /* 183290650Shselasky * If updating, check whether changing from read-only to 184290650Shselasky * read/write; if there is no device name, that's all we do. 185290650Shselasky */ 186290650Shselasky if (mp->mnt_flag & MNT_UPDATE) { 187290650Shselasky ump = VFSTOUFS(mp); 188290650Shselasky fs = ump->um_fs; 189290650Shselasky devvp = ump->um_devvp; 190290650Shselasky err = 0; 191290650Shselasky ronly = fs->fs_ronly; /* MNT_RELOAD might change this */ 192321992Shselasky if (ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 193321992Shselasky flags = WRITECLOSE; 194321992Shselasky if (mp->mnt_flag & MNT_FORCE) 195321992Shselasky flags |= FORCECLOSE; 196321992Shselasky if (mp->mnt_flag & MNT_SOFTDEP) { 197321992Shselasky err = softdep_flushfiles(mp, flags, p); 198290650Shselasky } else { 199290650Shselasky err = ffs_flushfiles(mp, flags, p); 200290650Shselasky } 201290650Shselasky ronly = 1; 202290650Shselasky } 203290650Shselasky if (!err && (mp->mnt_flag & MNT_RELOAD)) 204290650Shselasky err = ffs_reload(mp, ndp->ni_cnd.cn_cred, p); 205290650Shselasky if (err) { 206290650Shselasky goto error_1; 207290650Shselasky } 208290650Shselasky if (ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { 209290650Shselasky /* 210290650Shselasky * If upgrade to read-write by non-root, then verify 211290650Shselasky * that user has necessary permissions on the device. 212290650Shselasky */ 213290650Shselasky if (p->p_ucred->cr_uid != 0) { 214321992Shselasky vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 215321992Shselasky if ((error = VOP_ACCESS(devvp, VREAD | VWRITE, 216290650Shselasky p->p_ucred, p)) != 0) { 217290650Shselasky VOP_UNLOCK(devvp, 0, p); 218290650Shselasky return (error); 219290650Shselasky } 220290650Shselasky VOP_UNLOCK(devvp, 0, p); 221290650Shselasky } 222290650Shselasky 223290650Shselasky fs->fs_flags &= ~FS_UNCLEAN; 224290650Shselasky if (fs->fs_clean == 0) { 225290650Shselasky fs->fs_flags |= FS_UNCLEAN; 226290650Shselasky if (mp->mnt_flag & MNT_FORCE) { 227290650Shselasky printf( 228290650Shselasky"WARNING: %s was not properly dismounted\n", 229290650Shselasky fs->fs_fsmnt); 230290650Shselasky } else { 231290650Shselasky printf( 232290650Shselasky"WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n", 233290650Shselasky fs->fs_fsmnt); 234290650Shselasky err = EPERM; 235290650Shselasky goto error_1; 236321992Shselasky } 237321992Shselasky } 238321992Shselasky 239321992Shselasky /* check to see if we need to start softdep */ 240290650Shselasky if (fs->fs_flags & FS_DOSOFTDEP) { 241290650Shselasky err = softdep_mount(devvp, mp, fs, p->p_ucred); 242290650Shselasky if (err) 243290650Shselasky goto error_1; 244290650Shselasky } 245290650Shselasky 246290650Shselasky ronly = 0; 247290650Shselasky } 248290650Shselasky /* 249290650Shselasky * Soft updates is incompatible with "async", 250290650Shselasky * so if we are doing softupdates stop the user 251290650Shselasky * from setting the async flag in an update. 252290650Shselasky * Softdep_mount() clears it in an initial mount 253290650Shselasky * or ro->rw remount. 254290650Shselasky */ 255290650Shselasky if (mp->mnt_flag & MNT_SOFTDEP) { 256290650Shselasky mp->mnt_flag &= ~MNT_ASYNC; 257290650Shselasky } 258290650Shselasky /* if not updating name...*/ 259290650Shselasky if (args.fspec == 0) { 260290650Shselasky /* 261290650Shselasky * Process export requests. Jumping to "success" 262290650Shselasky * will return the vfs_export() error code. 263290650Shselasky */ 264290650Shselasky err = vfs_export(mp, &ump->um_export, &args.export); 265290650Shselasky goto success; 266290650Shselasky } 267290650Shselasky } 268290650Shselasky 269290650Shselasky /* 270290650Shselasky * Not an update, or updating the name: look up the name 271290650Shselasky * and verify that it refers to a sensible block device. 272290650Shselasky */ 273290650Shselasky NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 274290650Shselasky err = namei(ndp); 275290650Shselasky if (err) { 276290650Shselasky /* can't get devvp!*/ 277290650Shselasky goto error_1; 278290650Shselasky } 279290650Shselasky 280290650Shselasky NDFREE(ndp, NDF_ONLY_PNBUF); 281290650Shselasky devvp = ndp->ni_vp; 282290650Shselasky 283290650Shselasky if (!vn_isdisk(devvp)) { 284321992Shselasky err = ENOTBLK; 285321992Shselasky goto error_2; 286321992Shselasky } 287321992Shselasky 288321992Shselasky /* 289290650Shselasky * If mount by non-root, then verify that user has necessary 290290650Shselasky * permissions on the device. 291290650Shselasky */ 292290650Shselasky if (p->p_ucred->cr_uid != 0) { 293290650Shselasky accessmode = VREAD; 294290650Shselasky if ((mp->mnt_flag & MNT_RDONLY) == 0) 295290650Shselasky accessmode |= VWRITE; 296290650Shselasky vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 297290650Shselasky if ((error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p)) != 0) { 298290650Shselasky vput(devvp); 299290650Shselasky return (error); 300290650Shselasky } 301290650Shselasky VOP_UNLOCK(devvp, 0, p); 302290650Shselasky } 303290650Shselasky 304290650Shselasky if (mp->mnt_flag & MNT_UPDATE) { 305290650Shselasky /* 306290650Shselasky ******************** 307290650Shselasky * UPDATE 308290650Shselasky * If it's not the same vnode, or at least the same device 309290650Shselasky * then it's not correct. 310290650Shselasky ******************** 311290650Shselasky */ 312290650Shselasky 313290650Shselasky if (devvp != ump->um_devvp) { 314290650Shselasky if ( devvp->v_rdev == ump->um_devvp->v_rdev) { 315290650Shselasky vrele(devvp); 316321992Shselasky } else { 317321992Shselasky err = EINVAL; /* needs translation */ 318321992Shselasky } 319290650Shselasky } else 320290650Shselasky vrele(devvp); 321321992Shselasky /* 322290650Shselasky * Update device name only on success 323290650Shselasky */ 324308678Shselasky if( !err) { 325308678Shselasky /* Save "mounted from" info for mount point (NULL pad)*/ 326308678Shselasky copyinstr( args.fspec, 327308678Shselasky mp->mnt_stat.f_mntfromname, 328308678Shselasky MNAMELEN - 1, 329308678Shselasky &size); 330308678Shselasky bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 331308678Shselasky } 332308678Shselasky } else { 333308678Shselasky /* 334308678Shselasky ******************** 335308678Shselasky * NEW MOUNT 336308678Shselasky ******************** 337308678Shselasky */ 338308678Shselasky 339308678Shselasky /* 340308678Shselasky * Since this is a new mount, we want the names for 341308678Shselasky * the device and the mount point copied in. If an 342308678Shselasky * error occurs, the mountpoint is discarded by the 343308678Shselasky * upper level code. 344308678Shselasky */ 345308678Shselasky /* Save "last mounted on" info for mount point (NULL pad)*/ 346308678Shselasky copyinstr( path, /* mount point*/ 347308678Shselasky mp->mnt_stat.f_mntonname, /* save area*/ 348308678Shselasky MNAMELEN - 1, /* max size*/ 349308678Shselasky &size); /* real size*/ 350308678Shselasky bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 351308678Shselasky 352308678Shselasky /* Save "mounted from" info for mount point (NULL pad)*/ 353308678Shselasky copyinstr( args.fspec, /* device name*/ 354308678Shselasky mp->mnt_stat.f_mntfromname, /* save area*/ 355308678Shselasky MNAMELEN - 1, /* max size*/ 356308678Shselasky &size); /* real size*/ 357308678Shselasky bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 358308678Shselasky 359308678Shselasky err = ffs_mountfs(devvp, mp, p, M_FFSNODE); 360308678Shselasky } 361308678Shselasky if (err) { 362308678Shselasky goto error_2; 363308678Shselasky } 364308678Shselasky 365308678Shselaskydostatfs: 366308678Shselasky /* 367308678Shselasky * Initialize FS stat information in mount struct; uses both 368308678Shselasky * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname 369308678Shselasky * 370308678Shselasky * This code is common to root and non-root mounts 371308678Shselasky */ 372308678Shselasky (void)VFS_STATFS(mp, &mp->mnt_stat, p); 373308678Shselasky 374308678Shselasky goto success; 375321992Shselasky 376321992Shselasky 377321992Shselaskyerror_2: /* error with devvp held*/ 378321992Shselasky 379321992Shselasky /* release devvp before failing*/ 380308678Shselasky vrele(devvp); 381290650Shselasky 382290650Shselaskyerror_1: /* no state to back out*/ 383290650Shselasky 384290650Shselaskysuccess: 385290650Shselasky if (!err && path && (mp->mnt_flag & MNT_UPDATE)) { 386290650Shselasky /* Update clean flag after changing read-onlyness. */ 387329200Shselasky fs = ump->um_fs; 388329200Shselasky if (ronly != fs->fs_ronly) { 389329200Shselasky fs->fs_ronly = ronly; 390329200Shselasky fs->fs_clean = ronly && 391329200Shselasky (fs->fs_flags & FS_UNCLEAN) == 0 ? 1 : 0; 392329200Shselasky ffs_sbupdate(ump, MNT_WAIT); 393290650Shselasky } 394329200Shselasky } 395290650Shselasky return (err); 396329200Shselasky} 397290650Shselasky 398290650Shselasky/* 399329200Shselasky * Reload all incore data for a filesystem (used after running fsck on 400290650Shselasky * the root filesystem and finding things to fix). The filesystem must 401329200Shselasky * be mounted read-only. 402290650Shselasky * 403290650Shselasky * Things to do to update the mount: 404329200Shselasky * 1) invalidate all cached meta-data. 405290650Shselasky * 2) re-read superblock from disk. 406290650Shselasky * 3) re-read summary information from disk. 407290650Shselasky * 4) invalidate all inactive vnodes. 408329200Shselasky * 5) invalidate all cached file data. 409290650Shselasky * 6) re-read inode data for all active vnodes. 410290650Shselasky */ 411329200Shselaskystatic int 412290650Shselaskyffs_reload(mp, cred, p) 413290650Shselasky register struct mount *mp; 414290650Shselasky struct ucred *cred; 415290650Shselasky struct proc *p; 416290650Shselasky{ 417290650Shselasky register struct vnode *vp, *nvp, *devvp; 418290650Shselasky struct inode *ip; 419290650Shselasky struct csum *space; 420290650Shselasky struct buf *bp; 421290650Shselasky struct fs *fs, *newfs; 422290650Shselasky struct partinfo dpart; 423290650Shselasky dev_t dev; 424290650Shselasky int i, blks, size, error; 425290650Shselasky int32_t *lp; 426290650Shselasky 427290650Shselasky if ((mp->mnt_flag & MNT_RDONLY) == 0) 428290650Shselasky return (EINVAL); 429290650Shselasky /* 430290650Shselasky * Step 1: invalidate all cached meta-data. 431290650Shselasky */ 432290650Shselasky devvp = VFSTOUFS(mp)->um_devvp; 433290650Shselasky vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 434290650Shselasky error = vinvalbuf(devvp, 0, cred, p, 0, 0); 435290650Shselasky VOP_UNLOCK(devvp, 0, p); 436290650Shselasky if (error) 437290650Shselasky panic("ffs_reload: dirty1"); 438290650Shselasky 439321992Shselasky dev = devvp->v_rdev; 440290650Shselasky 441290650Shselasky /* 442290650Shselasky * Only VMIO the backing device if the backing device is a real 443290650Shselasky * block device. See ffs_mountmfs() for more details. 444290650Shselasky */ 445290650Shselasky if (devvp->v_tag != VT_MFS && vn_isdisk(devvp)) { 446290650Shselasky vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 447290650Shselasky vfs_object_create(devvp, p, p->p_ucred); 448290650Shselasky simple_lock(&devvp->v_interlock); 449329200Shselasky VOP_UNLOCK(devvp, LK_INTERLOCK, p); 450329200Shselasky } 451329200Shselasky 452329200Shselasky /* 453329200Shselasky * Step 2: re-read superblock from disk. 454329200Shselasky */ 455329200Shselasky if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) 456329200Shselasky size = DEV_BSIZE; 457329200Shselasky else 458329200Shselasky size = dpart.disklab->d_secsize; 459329200Shselasky if ((error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, NOCRED,&bp)) != 0) 460329200Shselasky return (error); 461329200Shselasky newfs = (struct fs *)bp->b_data; 462329200Shselasky if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE || 463329200Shselasky newfs->fs_bsize < sizeof(struct fs)) { 464329200Shselasky brelse(bp); 465290650Shselasky return (EIO); /* XXX needs translation */ 466290650Shselasky } 467290650Shselasky fs = VFSTOUFS(mp)->um_fs; 468290650Shselasky /* 469290650Shselasky * Copy pointer fields back into superblock before copying in XXX 470290650Shselasky * new superblock. These should really be in the ufsmount. XXX 471290650Shselasky * Note that important parameters (eg fs_ncg) are unchanged. 472290650Shselasky */ 473290650Shselasky bcopy(&fs->fs_csp[0], &newfs->fs_csp[0], sizeof(fs->fs_csp)); 474290650Shselasky newfs->fs_maxcluster = fs->fs_maxcluster; 475290650Shselasky bcopy(newfs, fs, (u_int)fs->fs_sbsize); 476290650Shselasky if (fs->fs_sbsize < SBSIZE) 477290650Shselasky bp->b_flags |= B_INVAL; 478290650Shselasky brelse(bp); 479290650Shselasky mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; 480290650Shselasky ffs_oldfscompat(fs); 481306233Shselasky 482306233Shselasky /* 483290650Shselasky * Step 3: re-read summary information from disk. 484290650Shselasky */ 485290650Shselasky blks = howmany(fs->fs_cssize, fs->fs_fsize); 486290650Shselasky space = fs->fs_csp[0]; 487290650Shselasky for (i = 0; i < blks; i += fs->fs_frag) { 488290650Shselasky size = fs->fs_bsize; 489290650Shselasky if (i + fs->fs_frag > blks) 490290650Shselasky size = (blks - i) * fs->fs_fsize; 491290650Shselasky error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 492290650Shselasky NOCRED, &bp); 493290650Shselasky if (error) 494290650Shselasky return (error); 495329200Shselasky bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size); 496290650Shselasky brelse(bp); 497329200Shselasky } 498290650Shselasky /* 499290650Shselasky * We no longer know anything about clusters per cylinder group. 500290650Shselasky */ 501290650Shselasky if (fs->fs_contigsumsize > 0) { 502290650Shselasky lp = fs->fs_maxcluster; 503290650Shselasky for (i = 0; i < fs->fs_ncg; i++) 504290650Shselasky *lp++ = fs->fs_contigsumsize; 505290650Shselasky } 506290650Shselasky 507290650Shselaskyloop: 508290650Shselasky simple_lock(&mntvnode_slock); 509290650Shselasky for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { 510290650Shselasky if (vp->v_mount != mp) { 511290650Shselasky simple_unlock(&mntvnode_slock); 512290650Shselasky goto loop; 513290650Shselasky } 514290650Shselasky nvp = vp->v_mntvnodes.le_next; 515290650Shselasky /* 516290650Shselasky * Step 4: invalidate all inactive vnodes. 517290650Shselasky */ 518290650Shselasky if (vrecycle(vp, &mntvnode_slock, p)) 519290650Shselasky goto loop; 520290650Shselasky /* 521290650Shselasky * Step 5: invalidate all cached file data. 522290650Shselasky */ 523290650Shselasky simple_lock(&vp->v_interlock); 524290650Shselasky simple_unlock(&mntvnode_slock); 525308678Shselasky if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) { 526308678Shselasky goto loop; 527308678Shselasky } 528290650Shselasky if (vinvalbuf(vp, 0, cred, p, 0, 0)) 529290650Shselasky panic("ffs_reload: dirty2"); 530290650Shselasky /* 531290650Shselasky * Step 6: re-read inode data for all active vnodes. 532290650Shselasky */ 533290650Shselasky ip = VTOI(vp); 534290650Shselasky error = 535321992Shselasky bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 536321992Shselasky (int)fs->fs_bsize, NOCRED, &bp); 537308678Shselasky if (error) { 538321992Shselasky vput(vp); 539321992Shselasky return (error); 540321992Shselasky } 541321992Shselasky ip->i_din = *((struct dinode *)bp->b_data + 542321992Shselasky ino_to_fsbo(fs, ip->i_number)); 543290650Shselasky ip->i_effnlink = ip->i_nlink; 544290650Shselasky brelse(bp); 545290650Shselasky vput(vp); 546290650Shselasky simple_lock(&mntvnode_slock); 547290650Shselasky } 548290650Shselasky simple_unlock(&mntvnode_slock); 549290650Shselasky return (0); 550290650Shselasky} 551290650Shselasky 552290650Shselasky/* 553290650Shselasky * Common code for mount and mountroot 554290650Shselasky */ 555290650Shselaskyint 556290650Shselaskyffs_mountfs(devvp, mp, p, malloctype) 557290650Shselasky register struct vnode *devvp; 558306233Shselasky struct mount *mp; 559306233Shselasky struct proc *p; 560306233Shselasky struct malloc_type *malloctype; 561306233Shselasky{ 562306233Shselasky register struct ufsmount *ump; 563306233Shselasky struct buf *bp; 564306233Shselasky register struct fs *fs; 565306233Shselasky dev_t dev; 566290650Shselasky struct partinfo dpart; 567290650Shselasky caddr_t base, space; 568290650Shselasky int error, i, blks, size, ronly; 569290650Shselasky int32_t *lp; 570290650Shselasky struct ucred *cred; 571290650Shselasky u_int64_t maxfilesize; /* XXX */ 572290650Shselasky size_t strsize; 573290650Shselasky int ncount; 574290650Shselasky 575290650Shselasky dev = devvp->v_rdev; 576290650Shselasky cred = p ? p->p_ucred : NOCRED; 577290650Shselasky /* 578290650Shselasky * Disallow multiple mounts of the same device. 579290650Shselasky * Disallow mounting of a device that is currently in use 580290650Shselasky * (except for root, which might share swap device for miniroot). 581290650Shselasky * Flush out any old buffers remaining from a previous use. 582290650Shselasky */ 583290650Shselasky error = vfs_mountedon(devvp); 584290650Shselasky if (error) 585290650Shselasky return (error); 586290650Shselasky ncount = vcount(devvp); 587290650Shselasky 588290650Shselasky if (ncount > 1 && devvp != rootvp) 589290650Shselasky return (EBUSY); 590290650Shselasky vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 591290650Shselasky error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0); 592290650Shselasky VOP_UNLOCK(devvp, 0, p); 593290650Shselasky if (error) 594290650Shselasky return (error); 595290650Shselasky 596290650Shselasky /* 597290650Shselasky * Only VMIO the backing device if the backing device is a real 598290650Shselasky * block device. This excludes the original MFS implementation. 599290650Shselasky * Note that it is optional that the backing device be VMIOed. This 600290650Shselasky * increases the opportunity for metadata caching. 601290650Shselasky */ 602290650Shselasky if (devvp->v_tag != VT_MFS && vn_isdisk(devvp)) { 603290650Shselasky vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 604290650Shselasky vfs_object_create(devvp, p, p->p_ucred); 605290650Shselasky simple_lock(&devvp->v_interlock); 606290650Shselasky VOP_UNLOCK(devvp, LK_INTERLOCK, p); 607290650Shselasky } 608290650Shselasky 609290650Shselasky ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 610290650Shselasky vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 611290650Shselasky error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); 612290650Shselasky VOP_UNLOCK(devvp, 0, p); 613290650Shselasky if (error) 614290650Shselasky return (error); 615290650Shselasky if (devvp->v_rdev->si_iosize_max > mp->mnt_iosize_max) 616290650Shselasky mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; 617290650Shselasky if (mp->mnt_iosize_max > MAXPHYS) 618290650Shselasky mp->mnt_iosize_max = MAXPHYS; 619290650Shselasky 620290650Shselasky if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0) 621290650Shselasky size = DEV_BSIZE; 622290650Shselasky else 623290650Shselasky size = dpart.disklab->d_secsize; 624290650Shselasky 625290650Shselasky bp = NULL; 626290650Shselasky ump = NULL; 627306233Shselasky if ((error = bread(devvp, SBLOCK, SBSIZE, cred, &bp)) != 0) 628306233Shselasky goto out; 629306233Shselasky fs = (struct fs *)bp->b_data; 630306233Shselasky if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 631306233Shselasky fs->fs_bsize < sizeof(struct fs)) { 632306233Shselasky error = EINVAL; /* XXX needs translation */ 633306233Shselasky goto out; 634306233Shselasky } 635306233Shselasky fs->fs_fmod = 0; 636306233Shselasky fs->fs_flags &= ~FS_UNCLEAN; 637306233Shselasky if (fs->fs_clean == 0) { 638306233Shselasky fs->fs_flags |= FS_UNCLEAN; 639306233Shselasky if (ronly || (mp->mnt_flag & MNT_FORCE)) { 640306233Shselasky printf( 641306233Shselasky"WARNING: %s was not properly dismounted\n", 642306233Shselasky fs->fs_fsmnt); 643306233Shselasky } else { 644306233Shselasky printf( 645306233Shselasky"WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n", 646306233Shselasky fs->fs_fsmnt); 647306233Shselasky error = EPERM; 648308678Shselasky goto out; 649308678Shselasky } 650308678Shselasky } 651308678Shselasky /* XXX updating 4.2 FFS superblocks trashes rotational layout tables */ 652308678Shselasky if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) { 653308678Shselasky error = EROFS; /* needs translation */ 654308678Shselasky goto out; 655308678Shselasky } 656308678Shselasky ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 657308678Shselasky bzero((caddr_t)ump, sizeof *ump); 658308678Shselasky ump->um_malloctype = malloctype; 659308678Shselasky ump->um_i_effnlink_valid = 1; 660308678Shselasky ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, 661308678Shselasky M_WAITOK); 662308678Shselasky ump->um_blkatoff = ffs_blkatoff; 663308678Shselasky ump->um_truncate = ffs_truncate; 664308678Shselasky ump->um_update = ffs_update; 665308678Shselasky ump->um_valloc = ffs_valloc; 666308678Shselasky ump->um_vfree = ffs_vfree; 667308678Shselasky bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize); 668308678Shselasky if (fs->fs_sbsize < SBSIZE) 669308678Shselasky bp->b_flags |= B_INVAL; 670308678Shselasky brelse(bp); 671308678Shselasky bp = NULL; 672308678Shselasky fs = ump->um_fs; 673308678Shselasky fs->fs_ronly = ronly; 674308678Shselasky if (ronly == 0) { 675308678Shselasky fs->fs_fmod = 1; 676308678Shselasky fs->fs_clean = 0; 677306233Shselasky } 678306233Shselasky size = fs->fs_cssize; 679306233Shselasky blks = howmany(size, fs->fs_fsize); 680306233Shselasky if (fs->fs_contigsumsize > 0) 681306233Shselasky size += fs->fs_ncg * sizeof(int32_t); 682306233Shselasky base = space = malloc((u_long)size, M_UFSMNT, M_WAITOK); 683306233Shselasky for (i = 0; i < blks; i += fs->fs_frag) { 684306233Shselasky size = fs->fs_bsize; 685306233Shselasky if (i + fs->fs_frag > blks) 686306233Shselasky size = (blks - i) * fs->fs_fsize; 687306233Shselasky if ((error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 688306233Shselasky cred, &bp)) != 0) { 689306233Shselasky free(base, M_UFSMNT); 690306233Shselasky goto out; 691306233Shselasky } 692306233Shselasky bcopy(bp->b_data, space, (u_int)size); 693306233Shselasky fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 694306233Shselasky space += size; 695306233Shselasky brelse(bp); 696290650Shselasky bp = NULL; 697290650Shselasky } 698290650Shselasky if (fs->fs_contigsumsize > 0) { 699290650Shselasky fs->fs_maxcluster = lp = (int32_t *)space; 700290650Shselasky for (i = 0; i < fs->fs_ncg; i++) 701290650Shselasky *lp++ = fs->fs_contigsumsize; 702290650Shselasky } 703306233Shselasky mp->mnt_data = (qaddr_t)ump; 704306233Shselasky mp->mnt_stat.f_fsid.val[0] = fs->fs_id[0]; 705306233Shselasky mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1]; 706306233Shselasky if (fs->fs_id[0] == 0 || fs->fs_id[1] == 0 || 707306233Shselasky vfs_getvfs(&mp->mnt_stat.f_fsid)) 708290650Shselasky vfs_getnewfsid(mp); 709290650Shselasky mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; 710290650Shselasky mp->mnt_flag |= MNT_LOCAL; 711290650Shselasky ump->um_mountp = mp; 712290650Shselasky ump->um_dev = dev; 713290650Shselasky ump->um_devvp = devvp; 714290650Shselasky ump->um_nindir = fs->fs_nindir; 715290650Shselasky ump->um_bptrtodb = fs->fs_fsbtodb; 716290650Shselasky ump->um_seqinc = fs->fs_frag; 717290650Shselasky for (i = 0; i < MAXQUOTAS; i++) 718290650Shselasky ump->um_quotas[i] = NULLVP; 719290650Shselasky devvp->v_specmountpoint = mp; 720290650Shselasky ffs_oldfscompat(fs); 721290650Shselasky 722290650Shselasky /* 723290650Shselasky * Set FS local "last mounted on" information (NULL pad) 724329200Shselasky */ 725329200Shselasky copystr( mp->mnt_stat.f_mntonname, /* mount point*/ 726329200Shselasky fs->fs_fsmnt, /* copy area*/ 727329200Shselasky sizeof(fs->fs_fsmnt) - 1, /* max size*/ 728290650Shselasky &strsize); /* real size*/ 729290650Shselasky bzero( fs->fs_fsmnt + strsize, sizeof(fs->fs_fsmnt) - strsize); 730290650Shselasky 731290650Shselasky if( mp->mnt_flag & MNT_ROOTFS) { 732290650Shselasky /* 733290650Shselasky * Root mount; update timestamp in mount structure. 734290650Shselasky * this will be used by the common root mount code 735290650Shselasky * to update the system clock. 736290650Shselasky */ 737290650Shselasky mp->mnt_time = fs->fs_time; 738290650Shselasky } 739290650Shselasky 740290650Shselasky ump->um_savedmaxfilesize = fs->fs_maxfilesize; /* XXX */ 741290650Shselasky maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1; /* XXX */ 742290650Shselasky if (fs->fs_maxfilesize > maxfilesize) /* XXX */ 743290650Shselasky fs->fs_maxfilesize = maxfilesize; /* XXX */ 744290650Shselasky if (ronly == 0) { 745290650Shselasky if ((fs->fs_flags & FS_DOSOFTDEP) && 746290650Shselasky (error = softdep_mount(devvp, mp, fs, cred)) != 0) { 747290650Shselasky free(base, M_UFSMNT); 748290650Shselasky goto out; 749290650Shselasky } 750290650Shselasky fs->fs_clean = 0; 751321992Shselasky (void) ffs_sbupdate(ump, MNT_WAIT); 752321992Shselasky } 753290650Shselasky return (0); 754290650Shselaskyout: 755290650Shselasky devvp->v_specmountpoint = NULL; 756290650Shselasky if (bp) 757290650Shselasky brelse(bp); 758290650Shselasky (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); 759329204Shselasky if (ump) { 760329204Shselasky free(ump->um_fs, M_UFSMNT); 761290650Shselasky free(ump, M_UFSMNT); 762290650Shselasky mp->mnt_data = (qaddr_t)0; 763290650Shselasky } 764290650Shselasky return (error); 765290650Shselasky} 766290650Shselasky 767308678Shselasky/* 768308678Shselasky * Sanity checks for old file systems. 769308678Shselasky * 770321992Shselasky * XXX - goes away some day. 771321992Shselasky */ 772308678Shselaskystatic int 773290650Shselaskyffs_oldfscompat(fs) 774290650Shselasky struct fs *fs; 775290650Shselasky{ 776290650Shselasky 777290650Shselasky fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ 778290650Shselasky fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ 779290650Shselasky if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 780290650Shselasky fs->fs_nrpos = 8; /* XXX */ 781290650Shselasky if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 782290650Shselasky#if 0 783290650Shselasky int i; /* XXX */ 784290650Shselasky u_int64_t sizepb = fs->fs_bsize; /* XXX */ 785290650Shselasky /* XXX */ 786290650Shselasky fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ 787290650Shselasky for (i = 0; i < NIADDR; i++) { /* XXX */ 788290650Shselasky sizepb *= NINDIR(fs); /* XXX */ 789290650Shselasky fs->fs_maxfilesize += sizepb; /* XXX */ 790290650Shselasky } /* XXX */ 791290650Shselasky#endif 792306233Shselasky fs->fs_maxfilesize = (u_quad_t) 1LL << 39; 793306233Shselasky fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ 794306233Shselasky fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ 795290650Shselasky } /* XXX */ 796306233Shselasky return (0); 797306233Shselasky} 798290650Shselasky 799290650Shselasky/* 800290650Shselasky * unmount system call 801290650Shselasky */ 802290650Shselaskyint 803290650Shselaskyffs_unmount(mp, mntflags, p) 804290650Shselasky struct mount *mp; 805290650Shselasky int mntflags; 806290650Shselasky struct proc *p; 807290650Shselasky{ 808290650Shselasky register struct ufsmount *ump; 809290650Shselasky register struct fs *fs; 810290650Shselasky int error, flags; 811290650Shselasky 812290650Shselasky flags = 0; 813290650Shselasky if (mntflags & MNT_FORCE) { 814290650Shselasky flags |= FORCECLOSE; 815290650Shselasky } 816290650Shselasky if (mp->mnt_flag & MNT_SOFTDEP) { 817290650Shselasky if ((error = softdep_flushfiles(mp, flags, p)) != 0) 818290650Shselasky return (error); 819290650Shselasky } else { 820290650Shselasky if ((error = ffs_flushfiles(mp, flags, p)) != 0) 821290650Shselasky return (error); 822290650Shselasky } 823290650Shselasky ump = VFSTOUFS(mp); 824290650Shselasky fs = ump->um_fs; 825290650Shselasky if (fs->fs_ronly == 0) { 826290650Shselasky fs->fs_clean = fs->fs_flags & FS_UNCLEAN ? 0 : 1; 827290650Shselasky error = ffs_sbupdate(ump, MNT_WAIT); 828290650Shselasky if (error) { 829290650Shselasky fs->fs_clean = 0; 830290650Shselasky return (error); 831290650Shselasky } 832290650Shselasky } 833290650Shselasky ump->um_devvp->v_specmountpoint = NULL; 834290650Shselasky 835290650Shselasky vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, p, 0, 0); 836290650Shselasky error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE, 837290650Shselasky NOCRED, p); 838290650Shselasky 839290650Shselasky vrele(ump->um_devvp); 840290650Shselasky 841290650Shselasky free(fs->fs_csp[0], M_UFSMNT); 842290650Shselasky free(fs, M_UFSMNT); 843290650Shselasky free(ump, M_UFSMNT); 844306233Shselasky mp->mnt_data = (qaddr_t)0; 845306233Shselasky mp->mnt_flag &= ~MNT_LOCAL; 846306233Shselasky return (error); 847290650Shselasky} 848306233Shselasky 849290650Shselasky/* 850306233Shselasky * Flush out all the files in a filesystem. 851306233Shselasky */ 852306233Shselaskyint 853290650Shselaskyffs_flushfiles(mp, flags, p) 854290650Shselasky register struct mount *mp; 855306233Shselasky int flags; 856290650Shselasky struct proc *p; 857290650Shselasky{ 858306233Shselasky register struct ufsmount *ump; 859290650Shselasky int error; 860290650Shselasky 861306233Shselasky ump = VFSTOUFS(mp); 862290650Shselasky#ifdef QUOTA 863290650Shselasky if (mp->mnt_flag & MNT_QUOTA) { 864290650Shselasky int i; 865290650Shselasky error = vflush(mp, NULLVP, SKIPSYSTEM|flags); 866290650Shselasky if (error) 867290650Shselasky return (error); 868290650Shselasky for (i = 0; i < MAXQUOTAS; i++) { 869290650Shselasky if (ump->um_quotas[i] == NULLVP) 870290650Shselasky continue; 871290650Shselasky quotaoff(p, mp, i); 872290650Shselasky } 873290650Shselasky /* 874290650Shselasky * Here we fall through to vflush again to ensure 875290650Shselasky * that we have gotten rid of all the system vnodes. 876290650Shselasky */ 877290650Shselasky } 878290650Shselasky#endif 879290650Shselasky /* 880290650Shselasky * Flush all the files. 881290650Shselasky */ 882290650Shselasky if ((error = vflush(mp, NULL, flags)) != 0) 883290650Shselasky return (error); 884290650Shselasky /* 885290650Shselasky * Flush filesystem metadata. 886290650Shselasky */ 887290650Shselasky vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p); 888290650Shselasky error = VOP_FSYNC(ump->um_devvp, p->p_ucred, MNT_WAIT, p); 889290650Shselasky VOP_UNLOCK(ump->um_devvp, 0, p); 890290650Shselasky return (error); 891290650Shselasky} 892290650Shselasky 893290650Shselasky/* 894290650Shselasky * Get file system statistics. 895290650Shselasky */ 896290650Shselaskyint 897290650Shselaskyffs_statfs(mp, sbp, p) 898290650Shselasky struct mount *mp; 899290650Shselasky register struct statfs *sbp; 900290650Shselasky struct proc *p; 901290650Shselasky{ 902290650Shselasky register struct ufsmount *ump; 903290650Shselasky register struct fs *fs; 904290650Shselasky 905290650Shselasky ump = VFSTOUFS(mp); 906290650Shselasky fs = ump->um_fs; 907290650Shselasky if (fs->fs_magic != FS_MAGIC) 908290650Shselasky panic("ffs_statfs"); 909290650Shselasky sbp->f_bsize = fs->fs_fsize; 910290650Shselasky sbp->f_iosize = fs->fs_bsize; 911290650Shselasky sbp->f_blocks = fs->fs_dsize; 912290650Shselasky sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 913290650Shselasky fs->fs_cstotal.cs_nffree; 914290650Shselasky sbp->f_bavail = freespace(fs, fs->fs_minfree); 915290650Shselasky sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; 916290650Shselasky sbp->f_ffree = fs->fs_cstotal.cs_nifree; 917290650Shselasky if (sbp != &mp->mnt_stat) { 918290650Shselasky sbp->f_type = mp->mnt_vfc->vfc_typenum; 919290650Shselasky bcopy((caddr_t)mp->mnt_stat.f_mntonname, 920290650Shselasky (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 921290650Shselasky bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 922290650Shselasky (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 923290650Shselasky } 924290650Shselasky return (0); 925290650Shselasky} 926290650Shselasky 927290650Shselasky/* 928290650Shselasky * Go through the disk queues to initiate sandbagged IO; 929290650Shselasky * go through the inodes to write those that have been modified; 930290650Shselasky * initiate the writing of the super block if it has been modified. 931290650Shselasky * 932290650Shselasky * Note: we are always called with the filesystem marked `MPBUSY'. 933290650Shselasky */ 934290650Shselaskyint 935290650Shselaskyffs_sync(mp, waitfor, cred, p) 936290650Shselasky struct mount *mp; 937290650Shselasky int waitfor; 938290650Shselasky struct ucred *cred; 939290650Shselasky struct proc *p; 940290650Shselasky{ 941290650Shselasky struct vnode *nvp, *vp; 942290650Shselasky struct inode *ip; 943290650Shselasky struct ufsmount *ump = VFSTOUFS(mp); 944290650Shselasky struct fs *fs; 945290650Shselasky int error, allerror = 0; 946290650Shselasky 947290650Shselasky fs = ump->um_fs; 948290650Shselasky if (fs->fs_fmod != 0 && fs->fs_ronly != 0) { /* XXX */ 949290650Shselasky printf("fs = %s\n", fs->fs_fsmnt); 950290650Shselasky panic("ffs_sync: rofs mod"); 951290650Shselasky } 952290650Shselasky /* 953290650Shselasky * Write back each (modified) inode. 954290650Shselasky */ 955290650Shselasky simple_lock(&mntvnode_slock); 956290650Shselaskyloop: 957306233Shselasky for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { 958306233Shselasky /* 959306233Shselasky * If the vnode that we are about to sync is no longer 960290650Shselasky * associated with this mount point, start over. 961290650Shselasky */ 962290650Shselasky if (vp->v_mount != mp) 963290650Shselasky goto loop; 964306233Shselasky simple_lock(&vp->v_interlock); 965306233Shselasky nvp = vp->v_mntvnodes.le_next; 966321992Shselasky ip = VTOI(vp); 967321992Shselasky if ((vp->v_type == VNON) || (((ip->i_flag & 968290650Shselasky (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) && 969290650Shselasky (TAILQ_EMPTY(&vp->v_dirtyblkhd) || (waitfor == MNT_LAZY)))) { 970290650Shselasky simple_unlock(&vp->v_interlock); 971290650Shselasky continue; 972290650Shselasky } 973290650Shselasky if (vp->v_type != VCHR) { 974290650Shselasky simple_unlock(&mntvnode_slock); 975290650Shselasky error = 976290650Shselasky vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); 977290650Shselasky if (error) { 978290650Shselasky simple_lock(&mntvnode_slock); 979290650Shselasky if (error == ENOENT) 980290650Shselasky goto loop; 981290650Shselasky continue; 982290650Shselasky } 983290650Shselasky if ((error = VOP_FSYNC(vp, cred, waitfor, p)) != 0) 984290650Shselasky allerror = error; 985290650Shselasky VOP_UNLOCK(vp, 0, p); 986290650Shselasky vrele(vp); 987290650Shselasky simple_lock(&mntvnode_slock); 988290650Shselasky } else { 989290650Shselasky simple_unlock(&mntvnode_slock); 990290650Shselasky simple_unlock(&vp->v_interlock); 991306233Shselasky /* UFS_UPDATE(vp, waitfor == MNT_WAIT); */ 992306233Shselasky UFS_UPDATE(vp, 0); 993306233Shselasky simple_lock(&mntvnode_slock); 994290650Shselasky } 995290650Shselasky } 996290650Shselasky simple_unlock(&mntvnode_slock); 997290650Shselasky /* 998290650Shselasky * Force stale file system control information to be flushed. 999290650Shselasky */ 1000290650Shselasky if (waitfor != MNT_LAZY) { 1001290650Shselasky if (ump->um_mountp->mnt_flag & MNT_SOFTDEP) 1002290650Shselasky waitfor = MNT_NOWAIT; 1003290650Shselasky vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p); 1004290650Shselasky if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) != 0) 1005290650Shselasky allerror = error; 1006290650Shselasky VOP_UNLOCK(ump->um_devvp, 0, p); 1007290650Shselasky } 1008290650Shselasky#ifdef QUOTA 1009290650Shselasky qsync(mp); 1010290650Shselasky#endif 1011306233Shselasky /* 1012306233Shselasky * Write back modified superblock. 1013306233Shselasky */ 1014306233Shselasky if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0) 1015306233Shselasky allerror = error; 1016290650Shselasky return (allerror); 1017290650Shselasky} 1018290650Shselasky 1019290650Shselasky/* 1020306233Shselasky * Look up a FFS dinode number to find its incore vnode, otherwise read it 1021290650Shselasky * in from disk. If it is in core, wait for the lock bit to clear, then 1022290650Shselasky * return the inode locked. Detection and handling of mount points must be 1023306233Shselasky * done by the calling routine. 1024290650Shselasky */ 1025290650Shselaskystatic int ffs_inode_hash_lock; 1026290650Shselasky 1027290650Shselaskyint 1028306233Shselaskyffs_vget(mp, ino, vpp) 1029290650Shselasky struct mount *mp; 1030290650Shselasky ino_t ino; 1031290650Shselasky struct vnode **vpp; 1032306233Shselasky{ 1033290650Shselasky struct fs *fs; 1034290650Shselasky struct inode *ip; 1035290650Shselasky struct ufsmount *ump; 1036290650Shselasky struct buf *bp; 1037321992Shselasky struct vnode *vp; 1038321992Shselasky dev_t dev; 1039321992Shselasky int error; 1040290650Shselasky 1041290650Shselasky ump = VFSTOUFS(mp); 1042290650Shselasky dev = ump->um_dev; 1043290650Shselaskyrestart: 1044290650Shselasky if ((*vpp = ufs_ihashget(dev, ino)) != NULL) { 1045290650Shselasky return (0); 1046290650Shselasky } 1047290650Shselasky 1048290650Shselasky /* 1049329204Shselasky * Lock out the creation of new entries in the FFS hash table in 1050329204Shselasky * case getnewvnode() or MALLOC() blocks, otherwise a duplicate 1051290650Shselasky * may occur! 1052290650Shselasky */ 1053329204Shselasky if (ffs_inode_hash_lock) { 1054329204Shselasky while (ffs_inode_hash_lock) { 1055290650Shselasky ffs_inode_hash_lock = -1; 1056290650Shselasky tsleep(&ffs_inode_hash_lock, PVM, "ffsvgt", 0); 1057290650Shselasky } 1058290650Shselasky goto restart; 1059290650Shselasky } 1060306233Shselasky ffs_inode_hash_lock = 1; 1061290650Shselasky 1062306233Shselasky /* 1063290650Shselasky * If this MALLOC() is performed after the getnewvnode() 1064290650Shselasky * it might block, leaving a vnode with a NULL v_data to be 1065290650Shselasky * found by ffs_sync() if a sync happens to fire right then, 1066290650Shselasky * which will cause a panic because ffs_sync() blindly 1067290650Shselasky * dereferences vp->v_data (as well it should). 1068306233Shselasky */ 1069290650Shselasky MALLOC(ip, struct inode *, sizeof(struct inode), 1070306233Shselasky ump->um_malloctype, M_WAITOK); 1071290650Shselasky 1072306233Shselasky /* Allocate a new vnode/inode. */ 1073290650Shselasky error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp); 1074290650Shselasky if (error) { 1075290650Shselasky if (ffs_inode_hash_lock < 0) 1076290650Shselasky wakeup(&ffs_inode_hash_lock); 1077290650Shselasky ffs_inode_hash_lock = 0; 1078290650Shselasky *vpp = NULL; 1079290650Shselasky FREE(ip, ump->um_malloctype); 1080290650Shselasky return (error); 1081290650Shselasky } 1082290650Shselasky bzero((caddr_t)ip, sizeof(struct inode)); 1083290650Shselasky lockinit(&ip->i_lock, PINOD, "inode", 0, 0); 1084290650Shselasky vp->v_data = ip; 1085290650Shselasky ip->i_vnode = vp; 1086290650Shselasky ip->i_fs = fs = ump->um_fs; 1087290650Shselasky ip->i_dev = dev; 1088290650Shselasky ip->i_number = ino; 1089290650Shselasky#ifdef QUOTA 1090290650Shselasky { 1091290650Shselasky int i; 1092290650Shselasky for (i = 0; i < MAXQUOTAS; i++) 1093290650Shselasky ip->i_dquot[i] = NODQUOT; 1094290650Shselasky } 1095290650Shselasky#endif 1096290650Shselasky /* 1097290650Shselasky * Put it onto its hash chain and lock it so that other requests for 1098290650Shselasky * this inode will block if they arrive while we are sleeping waiting 1099290650Shselasky * for old data structures to be purged or for the contents of the 1100290650Shselasky * disk portion of this inode to be read. 1101290650Shselasky */ 1102290650Shselasky ufs_ihashins(ip); 1103290650Shselasky 1104290650Shselasky if (ffs_inode_hash_lock < 0) 1105290650Shselasky wakeup(&ffs_inode_hash_lock); 1106290650Shselasky ffs_inode_hash_lock = 0; 1107290650Shselasky 1108290650Shselasky /* Read in the disk contents for the inode, copy into the inode. */ 1109290650Shselasky error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), 1110290650Shselasky (int)fs->fs_bsize, NOCRED, &bp); 1111290650Shselasky if (error) { 1112290650Shselasky /* 1113290650Shselasky * The inode does not contain anything useful, so it would 1114290650Shselasky * be misleading to leave it on its hash chain. With mode 1115290650Shselasky * still zero, it will be unlinked and returned to the free 1116290650Shselasky * list by vput(). 1117290650Shselasky */ 1118290650Shselasky brelse(bp); 1119290650Shselasky vput(vp); 1120290650Shselasky *vpp = NULL; 1121290650Shselasky return (error); 1122290650Shselasky } 1123290650Shselasky ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino)); 1124290650Shselasky if (DOINGSOFTDEP(vp)) 1125290650Shselasky softdep_load_inodeblock(ip); 1126290650Shselasky else 1127290650Shselasky ip->i_effnlink = ip->i_nlink; 1128290650Shselasky bqrelse(bp); 1129321992Shselasky 1130321992Shselasky /* 1131290650Shselasky * Initialize the vnode from the inode, check for aliases. 1132290650Shselasky * Note that the underlying vnode may have changed. 1133290650Shselasky */ 1134290650Shselasky error = ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, &vp); 1135290650Shselasky if (error) { 1136290650Shselasky vput(vp); 1137290650Shselasky *vpp = NULL; 1138290650Shselasky return (error); 1139290650Shselasky } 1140290650Shselasky /* 1141290650Shselasky * Finish inode initialization now that aliasing has been resolved. 1142290650Shselasky */ 1143290650Shselasky ip->i_devvp = ump->um_devvp; 1144290650Shselasky VREF(ip->i_devvp); 1145290650Shselasky /* 1146306233Shselasky * Set up a generation number for this inode if it does not 1147290650Shselasky * already have one. This should only happen on old filesystems. 1148306233Shselasky */ 1149290650Shselasky if (ip->i_gen == 0) { 1150306233Shselasky ip->i_gen = random() / 2 + 1; 1151306233Shselasky if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 1152290650Shselasky ip->i_flag |= IN_MODIFIED; 1153290650Shselasky } 1154290650Shselasky /* 1155290650Shselasky * Ensure that uid and gid are correct. This is a temporary 1156290650Shselasky * fix until fsck has been changed to do the update. 1157290650Shselasky */ 1158290650Shselasky if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 1159290650Shselasky ip->i_uid = ip->i_din.di_ouid; /* XXX */ 1160290650Shselasky ip->i_gid = ip->i_din.di_ogid; /* XXX */ 1161290650Shselasky } /* XXX */ 1162290650Shselasky 1163290650Shselasky *vpp = vp; 1164290650Shselasky return (0); 1165306233Shselasky} 1166306233Shselasky 1167306233Shselasky/* 1168306233Shselasky * File handle to vnode 1169306233Shselasky * 1170306233Shselasky * Have to be really careful about stale file handles: 1171290650Shselasky * - check that the inode number is valid 1172290650Shselasky * - call ffs_vget() to get the locked inode 1173290650Shselasky * - check for an unallocated inode (i_mode == 0) 1174290650Shselasky * - check that the given client host has export rights and return 1175290650Shselasky * those rights via. exflagsp and credanonp 1176290650Shselasky */ 1177290650Shselaskyint 1178290650Shselaskyffs_fhtovp(mp, fhp, vpp) 1179290650Shselasky register struct mount *mp; 1180290650Shselasky struct fid *fhp; 1181290650Shselasky struct vnode **vpp; 1182290650Shselasky{ 1183290650Shselasky register struct ufid *ufhp; 1184290650Shselasky struct fs *fs; 1185290650Shselasky 1186290650Shselasky ufhp = (struct ufid *)fhp; 1187290650Shselasky fs = VFSTOUFS(mp)->um_fs; 1188290650Shselasky if (ufhp->ufid_ino < ROOTINO || 1189290650Shselasky ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) 1190290650Shselasky return (ESTALE); 1191290650Shselasky return (ufs_fhtovp(mp, ufhp, vpp)); 1192290650Shselasky} 1193290650Shselasky 1194290650Shselasky/* 1195290650Shselasky * Vnode pointer to File handle 1196290650Shselasky */ 1197290650Shselasky/* ARGSUSED */ 1198290650Shselaskyint 1199290650Shselaskyffs_vptofh(vp, fhp) 1200290650Shselasky struct vnode *vp; 1201290650Shselasky struct fid *fhp; 1202290650Shselasky{ 1203290650Shselasky register struct inode *ip; 1204290650Shselasky register struct ufid *ufhp; 1205290650Shselasky 1206290650Shselasky ip = VTOI(vp); 1207290650Shselasky ufhp = (struct ufid *)fhp; 1208306233Shselasky ufhp->ufid_len = sizeof(struct ufid); 1209306233Shselasky ufhp->ufid_ino = ip->i_number; 1210306233Shselasky ufhp->ufid_gen = ip->i_gen; 1211306233Shselasky return (0); 1212306233Shselasky} 1213290650Shselasky 1214290650Shselasky/* 1215290650Shselasky * Initialize the filesystem; just use ufs_init. 1216290650Shselasky */ 1217290650Shselaskystatic int 1218290650Shselaskyffs_init(vfsp) 1219290650Shselasky struct vfsconf *vfsp; 1220290650Shselasky{ 1221290650Shselasky 1222290650Shselasky softdep_initialize(); 1223290650Shselasky return (ufs_init(vfsp)); 1224290650Shselasky} 1225290650Shselasky 1226290650Shselasky/* 1227290650Shselasky * Write a superblock and associated information back to disk. 1228290650Shselasky */ 1229290650Shselaskystatic int 1230290650Shselaskyffs_sbupdate(mp, waitfor) 1231290650Shselasky struct ufsmount *mp; 1232290650Shselasky int waitfor; 1233290650Shselasky{ 1234290650Shselasky register struct fs *dfs, *fs = mp->um_fs; 1235290650Shselasky register struct buf *bp; 1236290650Shselasky int blks; 1237290650Shselasky caddr_t space; 1238290650Shselasky int i, size, error, allerror = 0; 1239290650Shselasky 1240290650Shselasky /* 1241290650Shselasky * First write back the summary information. 1242290650Shselasky */ 1243290650Shselasky blks = howmany(fs->fs_cssize, fs->fs_fsize); 1244290650Shselasky space = (caddr_t)fs->fs_csp[0]; 1245290650Shselasky for (i = 0; i < blks; i += fs->fs_frag) { 1246290650Shselasky size = fs->fs_bsize; 1247290650Shselasky if (i + fs->fs_frag > blks) 1248290650Shselasky size = (blks - i) * fs->fs_fsize; 1249290650Shselasky bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), 1250290650Shselasky size, 0, 0); 1251290650Shselasky bcopy(space, bp->b_data, (u_int)size); 1252290650Shselasky space += size; 1253290650Shselasky if (waitfor != MNT_WAIT) 1254290650Shselasky bawrite(bp); 1255290650Shselasky else if ((error = bwrite(bp)) != 0) 1256290650Shselasky allerror = error; 1257290650Shselasky } 1258290650Shselasky /* 1259290650Shselasky * Now write back the superblock itself. If any errors occurred 1260290650Shselasky * up to this point, then fail so that the superblock avoids 1261290650Shselasky * being written out as clean. 1262290650Shselasky */ 1263290650Shselasky if (allerror) 1264290650Shselasky return (allerror); 1265290650Shselasky bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); 1266290650Shselasky fs->fs_fmod = 0; 1267290650Shselasky fs->fs_time = time_second; 1268290650Shselasky bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); 1269290650Shselasky /* Restore compatibility to old file systems. XXX */ 1270290650Shselasky dfs = (struct fs *)bp->b_data; /* XXX */ 1271290650Shselasky if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 1272290650Shselasky dfs->fs_nrpos = -1; /* XXX */ 1273290650Shselasky if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 1274290650Shselasky int32_t *lp, tmp; /* XXX */ 1275290650Shselasky /* XXX */ 1276290650Shselasky lp = (int32_t *)&dfs->fs_qbmask; /* XXX */ 1277290650Shselasky tmp = lp[4]; /* XXX */ 1278290650Shselasky for (i = 4; i > 0; i--) /* XXX */ 1279290650Shselasky lp[i] = lp[i-1]; /* XXX */ 1280290650Shselasky lp[0] = tmp; /* XXX */ 1281290650Shselasky } /* XXX */ 1282290650Shselasky dfs->fs_maxfilesize = mp->um_savedmaxfilesize; /* XXX */ 1283290650Shselasky if (waitfor != MNT_WAIT) 1284290650Shselasky bawrite(bp); 1285290650Shselasky else if ((error = bwrite(bp)) != 0) 1286290650Shselasky allerror = error; 1287290650Shselasky return (allerror); 1288290650Shselasky} 1289290650Shselasky