ffs_vfsops.c revision 7145
1/* 2 * Copyright (c) 1989, 1991, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)ffs_vfsops.c 8.8 (Berkeley) 4/18/94 34 * $Id: ffs_vfsops.c,v 1.13 1995/03/16 18:16:41 bde Exp $ 35 */ 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/namei.h> 40#include <sys/proc.h> 41#include <sys/kernel.h> 42#include <sys/vnode.h> 43#include <sys/socket.h> 44#include <sys/mount.h> 45#include <sys/buf.h> 46#include <sys/mbuf.h> 47#include <sys/file.h> 48#include <sys/disklabel.h> 49#include <sys/ioctl.h> 50#include <sys/errno.h> 51#include <sys/malloc.h> 52 53#include <miscfs/specfs/specdev.h> 54 55#include <ufs/ufs/quota.h> 56#include <ufs/ufs/ufsmount.h> 57#include <ufs/ufs/inode.h> 58#include <ufs/ufs/ufs_extern.h> 59 60#include <ufs/ffs/fs.h> 61#include <ufs/ffs/ffs_extern.h> 62 63int ffs_sbupdate __P((struct ufsmount *, int)); 64int ffs_flushfiles __P((struct mount *, int, struct proc *)); 65int ffs_reload __P((struct mount *,struct ucred *,struct proc *)); 66int ffs_oldfscompat __P((struct fs *)); 67 68struct vfsops ufs_vfsops = { 69 ffs_mount, 70 ufs_start, 71 ffs_unmount, 72 ufs_root, 73 ufs_quotactl, 74 ffs_statfs, 75 ffs_sync, 76 ffs_vget, 77 ffs_fhtovp, 78 ffs_vptofh, 79 ffs_init, 80}; 81 82VFS_SET(ufs_vfsops, ufs, MOUNT_UFS, 0); 83 84extern u_long nextgennumber; 85 86/* 87 * Called by main() when ufs is going to be mounted as root. 88 * 89 * Name is updated by mount(8) after booting. 90 */ 91#define ROOTNAME "root_device" 92 93int 94ffs_mountroot() 95{ 96 register struct fs *fs; 97 register struct mount *mp; 98 struct proc *p = curproc; /* XXX */ 99 struct ufsmount *ump; 100 u_int size; 101 int error; 102 103 /* 104 * Get vnodes for swapdev and rootdev. 105 */ 106 if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp)) 107 panic("ffs_mountroot: can't setup bdevvp's"); 108 109 mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); 110 bzero((char *)mp, (u_long)sizeof(struct mount)); 111 mp->mnt_op = &ufs_vfsops; 112 mp->mnt_flag = MNT_RDONLY; 113 error = ffs_mountfs(rootvp, mp, p); 114 if (error) { 115 free(mp, M_MOUNT); 116 return (error); 117 } 118 error = vfs_lock(mp); 119 if (error) { 120 (void)ffs_unmount(mp, 0, p); 121 free(mp, M_MOUNT); 122 return (error); 123 } 124 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 125 mp->mnt_flag |= MNT_ROOTFS; 126 mp->mnt_vnodecovered = NULLVP; 127 ump = VFSTOUFS(mp); 128 fs = ump->um_fs; 129 bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); 130 fs->fs_fsmnt[0] = '/'; 131 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 132 MNAMELEN); 133 (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 134 &size); 135 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 136 (void)ffs_statfs(mp, &mp->mnt_stat, p); 137 vfs_unlock(mp); 138 inittodr(fs->fs_time); 139 return (0); 140} 141 142/* 143 * VFS Operations. 144 * 145 * mount system call 146 */ 147int 148ffs_mount(mp, path, data, ndp, p) 149 register struct mount *mp; 150 char *path; 151 caddr_t data; 152 struct nameidata *ndp; 153 struct proc *p; 154{ 155 struct vnode *devvp; 156 struct ufs_args args; 157 struct ufsmount *ump = 0; 158 register struct fs *fs; 159 u_int size; 160 int error, flags; 161 162 error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)); 163 if (error) 164 return (error); 165 /* 166 * If updating, check whether changing from read-only to 167 * read/write; if there is no device name, that's all we do. 168 */ 169 if (mp->mnt_flag & MNT_UPDATE) { 170 ump = VFSTOUFS(mp); 171 fs = ump->um_fs; 172 error = 0; 173 if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 174 flags = WRITECLOSE; 175 if (mp->mnt_flag & MNT_FORCE) 176 flags |= FORCECLOSE; 177 if (vfs_busy(mp)) 178 return (EBUSY); 179 error = ffs_flushfiles(mp, flags, p); 180 vfs_unbusy(mp); 181 } 182 if (!error && (mp->mnt_flag & MNT_RELOAD)) 183 error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p); 184 if (error) 185 return (error); 186 if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) 187 fs->fs_ronly = 0; 188 if (fs->fs_ronly == 0) { 189 fs->fs_clean = 0; 190 ffs_sbupdate(ump, MNT_WAIT); 191 } 192 if (args.fspec == 0) { 193 /* 194 * Process export requests. 195 */ 196 return (vfs_export(mp, &ump->um_export, &args.export)); 197 } 198 } 199 /* 200 * Not an update, or updating the name: look up the name 201 * and verify that it refers to a sensible block device. 202 */ 203 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 204 error = namei(ndp); 205 if (error) 206 return (error); 207 devvp = ndp->ni_vp; 208 209 if (devvp->v_type != VBLK) { 210 vrele(devvp); 211 return (ENOTBLK); 212 } 213 if (major(devvp->v_rdev) >= nblkdev) { 214 vrele(devvp); 215 return (ENXIO); 216 } 217 if ((mp->mnt_flag & MNT_UPDATE) == 0) 218 error = ffs_mountfs(devvp, mp, p); 219 else { 220 if (devvp != ump->um_devvp) 221 error = EINVAL; /* needs translation */ 222 else 223 vrele(devvp); 224 } 225 if (error) { 226 vrele(devvp); 227 return (error); 228 } 229 ump = VFSTOUFS(mp); 230 fs = ump->um_fs; 231 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 232 bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 233 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 234 MNAMELEN); 235 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 236 &size); 237 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 238 (void)ffs_statfs(mp, &mp->mnt_stat, p); 239 return (0); 240} 241 242/* 243 * Reload all incore data for a filesystem (used after running fsck on 244 * the root filesystem and finding things to fix). The filesystem must 245 * be mounted read-only. 246 * 247 * Things to do to update the mount: 248 * 1) invalidate all cached meta-data. 249 * 2) re-read superblock from disk. 250 * 3) re-read summary information from disk. 251 * 4) invalidate all inactive vnodes. 252 * 5) invalidate all cached file data. 253 * 6) re-read inode data for all active vnodes. 254 */ 255int 256ffs_reload(mountp, cred, p) 257 register struct mount *mountp; 258 struct ucred *cred; 259 struct proc *p; 260{ 261 register struct vnode *vp, *nvp, *devvp; 262 struct inode *ip; 263 struct csum *space; 264 struct buf *bp; 265 struct fs *fs; 266 int i, blks, size, error; 267 268 if ((mountp->mnt_flag & MNT_RDONLY) == 0) 269 return (EINVAL); 270 /* 271 * Step 1: invalidate all cached meta-data. 272 */ 273 devvp = VFSTOUFS(mountp)->um_devvp; 274 if (vinvalbuf(devvp, 0, cred, p, 0, 0)) 275 panic("ffs_reload: dirty1"); 276 /* 277 * Step 2: re-read superblock from disk. 278 */ 279 error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp); 280 if (error) 281 return (error); 282 fs = (struct fs *)bp->b_data; 283 if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 284 fs->fs_bsize < sizeof(struct fs)) { 285 brelse(bp); 286 return (EIO); /* XXX needs translation */ 287 } 288 fs = VFSTOUFS(mountp)->um_fs; 289 bcopy(&fs->fs_csp[0], &((struct fs *)bp->b_data)->fs_csp[0], 290 sizeof(fs->fs_csp)); 291 bcopy(bp->b_data, fs, (u_int)fs->fs_sbsize); 292 if (fs->fs_sbsize < SBSIZE) 293 bp->b_flags |= B_INVAL; 294 brelse(bp); 295 ffs_oldfscompat(fs); 296 /* 297 * Step 3: re-read summary information from disk. 298 */ 299 blks = howmany(fs->fs_cssize, fs->fs_fsize); 300 space = fs->fs_csp[0]; 301 for (i = 0; i < blks; i += fs->fs_frag) { 302 size = fs->fs_bsize; 303 if (i + fs->fs_frag > blks) 304 size = (blks - i) * fs->fs_fsize; 305 error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 306 NOCRED, &bp); 307 if (error) 308 return (error); 309 bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size); 310 brelse(bp); 311 } 312loop: 313 for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { 314 nvp = vp->v_mntvnodes.le_next; 315 /* 316 * Step 4: invalidate all inactive vnodes. 317 */ 318 if (vp->v_usecount == 0) { 319 vgone(vp); 320 continue; 321 } 322 /* 323 * Step 5: invalidate all cached file data. 324 */ 325 if (vget(vp, 1)) 326 goto loop; 327 if (vinvalbuf(vp, 0, cred, p, 0, 0)) 328 panic("ffs_reload: dirty2"); 329 /* 330 * Step 6: re-read inode data for all active vnodes. 331 */ 332 ip = VTOI(vp); 333 error = 334 bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 335 (int)fs->fs_bsize, NOCRED, &bp); 336 if (error) { 337 vput(vp); 338 return (error); 339 } 340 ip->i_din = *((struct dinode *)bp->b_data + 341 ino_to_fsbo(fs, ip->i_number)); 342 brelse(bp); 343 vput(vp); 344 if (vp->v_mount != mountp) 345 goto loop; 346 } 347 return (0); 348} 349 350/* 351 * Common code for mount and mountroot 352 */ 353int 354ffs_mountfs(devvp, mp, p) 355 register struct vnode *devvp; 356 struct mount *mp; 357 struct proc *p; 358{ 359 register struct ufsmount *ump; 360 struct buf *bp; 361 register struct fs *fs; 362 dev_t dev = devvp->v_rdev; 363 struct partinfo dpart; 364 caddr_t base, space; 365 int havepart = 0, blks; 366 int error, i, size; 367 int ronly; 368 369 /* 370 * Disallow multiple mounts of the same device. 371 * Disallow mounting of a device that is currently in use 372 * (except for root, which might share swap device for miniroot). 373 * Flush out any old buffers remaining from a previous use. 374 */ 375 error = vfs_mountedon(devvp); 376 if (error) 377 return (error); 378 if (vcount(devvp) > 1 && devvp != rootvp) 379 return (EBUSY); 380 error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 381 if (error) 382 return (error); 383 384 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 385 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); 386 if (error) 387 return (error); 388 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) 389 size = DEV_BSIZE; 390 else { 391 havepart = 1; 392 size = dpart.disklab->d_secsize; 393 } 394 395 bp = NULL; 396 ump = NULL; 397 error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp); 398 if (error) 399 goto out; 400 fs = (struct fs *)bp->b_data; 401 if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 402 fs->fs_bsize < sizeof(struct fs)) { 403 error = EINVAL; /* XXX needs translation */ 404 goto out; 405 } 406 ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 407 bzero((caddr_t)ump, sizeof *ump); 408 ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, 409 M_WAITOK); 410 bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize); 411 if (fs->fs_sbsize < SBSIZE) 412 bp->b_flags |= B_INVAL; 413 brelse(bp); 414 bp = NULL; 415 fs = ump->um_fs; 416 fs->fs_ronly = ronly; 417 if (!fs->fs_clean) { 418 printf("WARNING: %s was not properly dismounted\n",fs->fs_fsmnt); 419 } 420 if (ronly == 0) { 421 fs->fs_fmod = 1; 422 fs->fs_clean = 0; 423 } 424 blks = howmany(fs->fs_cssize, fs->fs_fsize); 425 base = space = malloc((u_long)fs->fs_cssize, M_UFSMNT, 426 M_WAITOK); 427 for (i = 0; i < blks; i += fs->fs_frag) { 428 size = fs->fs_bsize; 429 if (i + fs->fs_frag > blks) 430 size = (blks - i) * fs->fs_fsize; 431 error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 432 NOCRED, &bp); 433 if (error) { 434 free(base, M_UFSMNT); 435 goto out; 436 } 437 bcopy(bp->b_data, space, (u_int)size); 438 fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 439 space += size; 440 brelse(bp); 441 bp = NULL; 442 } 443 mp->mnt_data = (qaddr_t)ump; 444 mp->mnt_stat.f_fsid.val[0] = (long)dev; 445 mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS; 446 mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; 447 mp->mnt_flag |= MNT_LOCAL; 448 ump->um_mountp = mp; 449 ump->um_dev = dev; 450 ump->um_devvp = devvp; 451 ump->um_nindir = fs->fs_nindir; 452 ump->um_bptrtodb = fs->fs_fsbtodb; 453 ump->um_seqinc = fs->fs_frag; 454 for (i = 0; i < MAXQUOTAS; i++) 455 ump->um_quotas[i] = NULLVP; 456 devvp->v_specflags |= SI_MOUNTEDON; 457 ffs_oldfscompat(fs); 458 if (ronly == 0) 459 ffs_sbupdate(ump, MNT_WAIT); 460 return (0); 461out: 462 if (bp) 463 brelse(bp); 464 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); 465 if (ump) { 466 free(ump->um_fs, M_UFSMNT); 467 free(ump, M_UFSMNT); 468 mp->mnt_data = (qaddr_t)0; 469 } 470 return (error); 471} 472 473/* 474 * Sanity checks for old file systems. 475 * 476 * XXX - goes away some day. 477 */ 478int 479ffs_oldfscompat(fs) 480 struct fs *fs; 481{ 482 int i; 483 484 fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ 485 fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ 486 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 487 fs->fs_nrpos = 8; /* XXX */ 488 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 489 quad_t sizepb = fs->fs_bsize; /* XXX */ 490 /* XXX */ 491#if 0 492 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ 493 for (i = 0; i < NIADDR; i++) { /* XXX */ 494 sizepb *= NINDIR(fs); /* XXX */ 495 fs->fs_maxfilesize += sizepb; /* XXX */ 496 } /* XXX */ 497#endif 498 fs->fs_maxfilesize = (u_quad_t) 1 << 39; 499 fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ 500 fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ 501 } /* XXX */ 502 return (0); 503} 504 505/* 506 * unmount system call 507 */ 508int 509ffs_unmount(mp, mntflags, p) 510 struct mount *mp; 511 int mntflags; 512 struct proc *p; 513{ 514 register struct ufsmount *ump; 515 register struct fs *fs; 516 int error, flags, ronly; 517 518 flags = 0; 519 if (mntflags & MNT_FORCE) { 520 flags |= FORCECLOSE; 521 } 522 error = ffs_flushfiles(mp, flags, p); 523 if (error) 524 return (error); 525 ump = VFSTOUFS(mp); 526 fs = ump->um_fs; 527 ronly = fs->fs_ronly; 528 if (!ronly) { 529 fs->fs_clean = 1; 530 ffs_sbupdate(ump, MNT_WAIT); 531 } 532 ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 533 error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, 534 NOCRED, p); 535 vrele(ump->um_devvp); 536 free(fs->fs_csp[0], M_UFSMNT); 537 free(fs, M_UFSMNT); 538 free(ump, M_UFSMNT); 539 mp->mnt_data = (qaddr_t)0; 540 mp->mnt_flag &= ~MNT_LOCAL; 541 return (error); 542} 543 544/* 545 * Flush out all the files in a filesystem. 546 */ 547int 548ffs_flushfiles(mp, flags, p) 549 register struct mount *mp; 550 int flags; 551 struct proc *p; 552{ 553 register struct ufsmount *ump; 554 int error; 555 556 if (!doforce) 557 flags &= ~FORCECLOSE; 558 ump = VFSTOUFS(mp); 559#ifdef QUOTA 560 if (mp->mnt_flag & MNT_QUOTA) { 561 int i; 562 error = vflush(mp, NULLVP, SKIPSYSTEM|flags); 563 if (error) 564 return (error); 565 for (i = 0; i < MAXQUOTAS; i++) { 566 if (ump->um_quotas[i] == NULLVP) 567 continue; 568 quotaoff(p, mp, i); 569 } 570 /* 571 * Here we fall through to vflush again to ensure 572 * that we have gotten rid of all the system vnodes. 573 */ 574 } 575#endif 576 error = vflush(mp, NULLVP, flags); 577 return (error); 578} 579 580/* 581 * Get file system statistics. 582 */ 583int 584ffs_statfs(mp, sbp, p) 585 struct mount *mp; 586 register struct statfs *sbp; 587 struct proc *p; 588{ 589 register struct ufsmount *ump; 590 register struct fs *fs; 591 592 ump = VFSTOUFS(mp); 593 fs = ump->um_fs; 594 if (fs->fs_magic != FS_MAGIC) 595 panic("ffs_statfs"); 596 sbp->f_type = MOUNT_UFS; 597 sbp->f_bsize = fs->fs_fsize; 598 sbp->f_iosize = fs->fs_bsize; 599 sbp->f_blocks = fs->fs_dsize; 600 sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 601 fs->fs_cstotal.cs_nffree; 602 sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - 603 (fs->fs_dsize - sbp->f_bfree); 604 sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; 605 sbp->f_ffree = fs->fs_cstotal.cs_nifree; 606 if (sbp != &mp->mnt_stat) { 607 bcopy((caddr_t)mp->mnt_stat.f_mntonname, 608 (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 609 bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 610 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 611 } 612 return (0); 613} 614 615/* 616 * Go through the disk queues to initiate sandbagged IO; 617 * go through the inodes to write those that have been modified; 618 * initiate the writing of the super block if it has been modified. 619 * 620 * Note: we are always called with the filesystem marked `MPBUSY'. 621 */ 622int 623ffs_sync(mp, waitfor, cred, p) 624 struct mount *mp; 625 int waitfor; 626 struct ucred *cred; 627 struct proc *p; 628{ 629 register struct vnode *vp; 630 register struct inode *ip; 631 register struct ufsmount *ump = VFSTOUFS(mp); 632 register struct fs *fs; 633 int error, allerror = 0; 634 635 fs = ump->um_fs; 636 /* 637 * Write back modified superblock. 638 * Consistency check that the superblock 639 * is still in the buffer cache. 640 */ 641 if (fs->fs_fmod != 0) { 642 if (fs->fs_ronly != 0) { /* XXX */ 643 printf("fs = %s\n", fs->fs_fsmnt); 644 panic("update: rofs mod"); 645 } 646 fs->fs_fmod = 0; 647 fs->fs_time = time.tv_sec; 648 allerror = ffs_sbupdate(ump, waitfor); 649 } 650 /* 651 * Write back each (modified) inode. 652 */ 653loop: 654 for (vp = mp->mnt_vnodelist.lh_first; 655 vp != NULL; 656 vp = vp->v_mntvnodes.le_next) { 657 /* 658 * If the vnode that we are about to sync is no longer 659 * associated with this mount point, start over. 660 */ 661 if (vp->v_mount != mp) 662 goto loop; 663 if (VOP_ISLOCKED(vp)) 664 continue; 665 ip = VTOI(vp); 666 if (((vp->v_type == VCHR) || ((ip->i_flag & 667 (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0)) && 668 vp->v_dirtyblkhd.lh_first == NULL) 669 continue; 670 if (vget(vp, 1)) 671 goto loop; 672 error = VOP_FSYNC(vp, cred, waitfor, p); 673 if (error) 674 allerror = error; 675 vput(vp); 676 } 677 /* 678 * Force stale file system control information to be flushed. 679 */ 680 error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p); 681 if (error) 682 allerror = error; 683#ifdef QUOTA 684 qsync(mp); 685#endif 686 return (allerror); 687} 688 689/* 690 * Look up a FFS dinode number to find its incore vnode, otherwise read it 691 * in from disk. If it is in core, wait for the lock bit to clear, then 692 * return the inode locked. Detection and handling of mount points must be 693 * done by the calling routine. 694 */ 695int 696ffs_vget(mp, ino, vpp) 697 struct mount *mp; 698 ino_t ino; 699 struct vnode **vpp; 700{ 701 register struct fs *fs; 702 register struct inode *ip; 703 struct ufsmount *ump; 704 struct buf *bp; 705 struct vnode *vp; 706 dev_t dev; 707 int type, error; 708 709 ump = VFSTOUFS(mp); 710 dev = ump->um_dev; 711 if ((*vpp = ufs_ihashget(dev, ino)) != NULL) 712 return (0); 713 714 /* Allocate a new vnode/inode. */ 715 error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp); 716 if (error) { 717 *vpp = NULL; 718 return (error); 719 } 720 type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */ 721 MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK); 722 bzero((caddr_t)ip, sizeof(struct inode)); 723 vp->v_data = ip; 724 ip->i_vnode = vp; 725 ip->i_fs = fs = ump->um_fs; 726 ip->i_dev = dev; 727 ip->i_number = ino; 728#ifdef QUOTA 729 { 730 int i; 731 for (i = 0; i < MAXQUOTAS; i++) 732 ip->i_dquot[i] = NODQUOT; 733 } 734#endif 735 /* 736 * Put it onto its hash chain and lock it so that other requests for 737 * this inode will block if they arrive while we are sleeping waiting 738 * for old data structures to be purged or for the contents of the 739 * disk portion of this inode to be read. 740 */ 741 ufs_ihashins(ip); 742 743 /* Read in the disk contents for the inode, copy into the inode. */ 744 error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), 745 (int)fs->fs_bsize, NOCRED, &bp); 746 if (error) { 747 /* 748 * The inode does not contain anything useful, so it would 749 * be misleading to leave it on its hash chain. With mode 750 * still zero, it will be unlinked and returned to the free 751 * list by vput(). 752 */ 753 vput(vp); 754 brelse(bp); 755 *vpp = NULL; 756 return (error); 757 } 758 ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino)); 759 brelse(bp); 760 761 /* 762 * Initialize the vnode from the inode, check for aliases. 763 * Note that the underlying vnode may have changed. 764 */ 765 error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp); 766 if (error) { 767 vput(vp); 768 *vpp = NULL; 769 return (error); 770 } 771 /* 772 * Finish inode initialization now that aliasing has been resolved. 773 */ 774 ip->i_devvp = ump->um_devvp; 775 VREF(ip->i_devvp); 776 /* 777 * Set up a generation number for this inode if it does not 778 * already have one. This should only happen on old filesystems. 779 */ 780 if (ip->i_gen == 0) { 781 if (++nextgennumber < (u_long)time.tv_sec) 782 nextgennumber = time.tv_sec; 783 ip->i_gen = nextgennumber; 784 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 785 ip->i_flag |= IN_MODIFIED; 786 } 787 /* 788 * Ensure that uid and gid are correct. This is a temporary 789 * fix until fsck has been changed to do the update. 790 */ 791 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 792 ip->i_uid = ip->i_din.di_ouid; /* XXX */ 793 ip->i_gid = ip->i_din.di_ogid; /* XXX */ 794 } /* XXX */ 795 796 *vpp = vp; 797 return (0); 798} 799 800/* 801 * File handle to vnode 802 * 803 * Have to be really careful about stale file handles: 804 * - check that the inode number is valid 805 * - call ffs_vget() to get the locked inode 806 * - check for an unallocated inode (i_mode == 0) 807 * - check that the given client host has export rights and return 808 * those rights via. exflagsp and credanonp 809 */ 810int 811ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 812 register struct mount *mp; 813 struct fid *fhp; 814 struct mbuf *nam; 815 struct vnode **vpp; 816 int *exflagsp; 817 struct ucred **credanonp; 818{ 819 register struct ufid *ufhp; 820 struct fs *fs; 821 822 ufhp = (struct ufid *)fhp; 823 fs = VFSTOUFS(mp)->um_fs; 824 if (ufhp->ufid_ino < ROOTINO || 825 ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) 826 return (ESTALE); 827 return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)); 828} 829 830/* 831 * Vnode pointer to File handle 832 */ 833/* ARGSUSED */ 834int 835ffs_vptofh(vp, fhp) 836 struct vnode *vp; 837 struct fid *fhp; 838{ 839 register struct inode *ip; 840 register struct ufid *ufhp; 841 842 ip = VTOI(vp); 843 ufhp = (struct ufid *)fhp; 844 ufhp->ufid_len = sizeof(struct ufid); 845 ufhp->ufid_ino = ip->i_number; 846 ufhp->ufid_gen = ip->i_gen; 847 return (0); 848} 849 850/* 851 * Write a superblock and associated information back to disk. 852 */ 853int 854ffs_sbupdate(mp, waitfor) 855 struct ufsmount *mp; 856 int waitfor; 857{ 858 register struct fs *fs = mp->um_fs; 859 register struct buf *bp; 860 int blks; 861 caddr_t space; 862 int i, size, error = 0; 863 864 bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); 865 bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); 866 /* Restore compatibility to old file systems. XXX */ 867 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 868 ((struct fs *)bp->b_data)->fs_nrpos = -1; /* XXX */ 869 if (waitfor == MNT_WAIT) 870 error = bwrite(bp); 871 else 872 bawrite(bp); 873 blks = howmany(fs->fs_cssize, fs->fs_fsize); 874 space = (caddr_t)fs->fs_csp[0]; 875 for (i = 0; i < blks; i += fs->fs_frag) { 876 size = fs->fs_bsize; 877 if (i + fs->fs_frag > blks) 878 size = (blks - i) * fs->fs_fsize; 879 bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), 880 size, 0, 0); 881 bcopy(space, bp->b_data, (u_int)size); 882 space += size; 883 if (waitfor == MNT_WAIT) 884 error = bwrite(bp); 885 else 886 bawrite(bp); 887 } 888 return (error); 889} 890