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