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