1 /* $NetBSD: ext2fs_vfsops.c,v 1.141 2008/12/08 11:34:30 pooka Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1991, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)ffs_vfsops.c 8.14 (Berkeley) 11/28/94 32 * Modified for ext2fs by Manuel Bouyer. 33 */ 34 35 /* 36 * Copyright (c) 1997 Manuel Bouyer. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 3. All advertising materials mentioning features or use of this software 47 * must display the following acknowledgement: 48 * This product includes software developed by Manuel Bouyer. 49 * 4. The name of the author may not be used to endorse or promote products 50 * derived from this software without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 53 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 54 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 55 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 56 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 57 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 58 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 59 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 60 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 61 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 * 63 * @(#)ffs_vfsops.c 8.14 (Berkeley) 11/28/94 64 * Modified for ext2fs by Manuel Bouyer. 65 */ 66 67 #include <sys/cdefs.h> 68 __KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsops.c,v 1.141 2008/12/08 11:34:30 pooka Exp $"); 69 70 #if defined(_KERNEL_OPT) 71 #include "opt_compat_netbsd.h" 72 #endif 73 74 #include <sys/param.h> 75 #include <sys/systm.h> 76 #include <sys/sysctl.h> 77 #include <sys/namei.h> 78 #include <sys/proc.h> 79 #include <sys/kernel.h> 80 #include <sys/vnode.h> 81 #include <sys/socket.h> 82 #include <sys/mount.h> 83 #include <sys/buf.h> 84 #include <sys/device.h> 85 #include <sys/mbuf.h> 86 #include <sys/file.h> 87 #include <sys/disklabel.h> 88 #include <sys/ioctl.h> 89 #include <sys/errno.h> 90 #include <sys/malloc.h> 91 #include <sys/pool.h> 92 #include <sys/lock.h> 93 #include <sys/conf.h> 94 #include <sys/kauth.h> 95 #include <sys/module.h> 96 97 #include <miscfs/genfs/genfs.h> 98 #include <miscfs/specfs/specdev.h> 99 100 #include <ufs/ufs/quota.h> 101 #include <ufs/ufs/ufsmount.h> 102 #include <ufs/ufs/inode.h> 103 #include <ufs/ufs/dir.h> 104 #include <ufs/ufs/ufs_extern.h> 105 106 #include <ufs/ext2fs/ext2fs.h> 107 #include <ufs/ext2fs/ext2fs_dir.h> 108 #include <ufs/ext2fs/ext2fs_extern.h> 109 110 MODULE(MODULE_CLASS_VFS, ext2fs, "ffs"); 111 112 extern kmutex_t ufs_hashlock; 113 114 int ext2fs_sbupdate(struct ufsmount *, int); 115 static int ext2fs_checksb(struct ext2fs *, int); 116 static void ext2fs_set_inode_guid(struct inode *); 117 118 static struct sysctllog *ext2fs_sysctl_log; 119 120 extern const struct vnodeopv_desc ext2fs_vnodeop_opv_desc; 121 extern const struct vnodeopv_desc ext2fs_specop_opv_desc; 122 extern const struct vnodeopv_desc ext2fs_fifoop_opv_desc; 123 124 const struct vnodeopv_desc * const ext2fs_vnodeopv_descs[] = { 125 &ext2fs_vnodeop_opv_desc, 126 &ext2fs_specop_opv_desc, 127 &ext2fs_fifoop_opv_desc, 128 NULL, 129 }; 130 131 struct vfsops ext2fs_vfsops = { 132 MOUNT_EXT2FS, 133 sizeof (struct ufs_args), 134 ext2fs_mount, 135 ufs_start, 136 ext2fs_unmount, 137 ufs_root, 138 ufs_quotactl, 139 ext2fs_statvfs, 140 ext2fs_sync, 141 ext2fs_vget, 142 ext2fs_fhtovp, 143 ext2fs_vptofh, 144 ext2fs_init, 145 ext2fs_reinit, 146 ext2fs_done, 147 ext2fs_mountroot, 148 (int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp, 149 vfs_stdextattrctl, 150 (void *)eopnotsupp, /* vfs_suspendctl */ 151 genfs_renamelock_enter, 152 genfs_renamelock_exit, 153 (void *)eopnotsupp, 154 ext2fs_vnodeopv_descs, 155 0, 156 { NULL, NULL }, 157 }; 158 159 static const struct genfs_ops ext2fs_genfsops = { 160 .gop_size = genfs_size, 161 .gop_alloc = ext2fs_gop_alloc, 162 .gop_write = genfs_gop_write, 163 .gop_markupdate = ufs_gop_markupdate, 164 }; 165 166 static const struct ufs_ops ext2fs_ufsops = { 167 .uo_itimes = ext2fs_itimes, 168 .uo_update = ext2fs_update, 169 .uo_vfree = ext2fs_vfree, 170 .uo_unmark_vnode = (void (*)(vnode_t *))nullop, 171 }; 172 173 /* Fill in the inode uid/gid from ext2 halves. */ 174 static void 175 ext2fs_set_inode_guid(struct inode *ip) 176 { 177 178 ip->i_gid = ip->i_e2fs_gid; 179 ip->i_uid = ip->i_e2fs_uid; 180 if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0) { 181 ip->i_gid |= ip->i_e2fs_gid_high << 16; 182 ip->i_uid |= ip->i_e2fs_uid_high << 16; 183 } 184 } 185 186 static int 187 ext2fs_modcmd(modcmd_t cmd, void *arg) 188 { 189 int error; 190 191 switch (cmd) { 192 case MODULE_CMD_INIT: 193 error = vfs_attach(&ext2fs_vfsops); 194 if (error != 0) 195 break; 196 sysctl_createv(&ext2fs_sysctl_log, 0, NULL, NULL, 197 CTLFLAG_PERMANENT, 198 CTLTYPE_NODE, "vfs", NULL, 199 NULL, 0, NULL, 0, 200 CTL_VFS, CTL_EOL); 201 sysctl_createv(&ext2fs_sysctl_log, 0, NULL, NULL, 202 CTLFLAG_PERMANENT, 203 CTLTYPE_NODE, "ext2fs", 204 SYSCTL_DESCR("Linux EXT2FS file system"), 205 NULL, 0, NULL, 0, 206 CTL_VFS, 17, CTL_EOL); 207 /* 208 * XXX the "17" above could be dynamic, thereby eliminating 209 * one more instance of the "number to vfs" mapping problem, 210 * but "17" is the order as taken from sys/mount.h 211 */ 212 break; 213 case MODULE_CMD_FINI: 214 error = vfs_detach(&ext2fs_vfsops); 215 if (error != 0) 216 break; 217 sysctl_teardown(&ext2fs_sysctl_log); 218 break; 219 default: 220 error = ENOTTY; 221 break; 222 } 223 224 return (error); 225 } 226 227 /* 228 * XXX Same structure as FFS inodes? Should we share a common pool? 229 */ 230 struct pool ext2fs_inode_pool; 231 struct pool ext2fs_dinode_pool; 232 233 extern u_long ext2gennumber; 234 235 void 236 ext2fs_init(void) 237 { 238 239 pool_init(&ext2fs_inode_pool, sizeof(struct inode), 0, 0, 0, 240 "ext2fsinopl", &pool_allocator_nointr, IPL_NONE); 241 pool_init(&ext2fs_dinode_pool, sizeof(struct ext2fs_dinode), 0, 0, 0, 242 "ext2dinopl", &pool_allocator_nointr, IPL_NONE); 243 ufs_init(); 244 } 245 246 void 247 ext2fs_reinit(void) 248 { 249 ufs_reinit(); 250 } 251 252 void 253 ext2fs_done(void) 254 { 255 256 ufs_done(); 257 pool_destroy(&ext2fs_inode_pool); 258 pool_destroy(&ext2fs_dinode_pool); 259 } 260 261 /* 262 * Called by main() when ext2fs is going to be mounted as root. 263 * 264 * Name is updated by mount(8) after booting. 265 */ 266 #define ROOTNAME "root_device" 267 268 int 269 ext2fs_mountroot(void) 270 { 271 extern struct vnode *rootvp; 272 struct m_ext2fs *fs; 273 struct mount *mp; 274 struct ufsmount *ump; 275 int error; 276 277 if (device_class(root_device) != DV_DISK) 278 return (ENODEV); 279 280 if ((error = vfs_rootmountalloc(MOUNT_EXT2FS, "root_device", &mp))) { 281 vrele(rootvp); 282 return (error); 283 } 284 285 if ((error = ext2fs_mountfs(rootvp, mp)) != 0) { 286 vfs_unbusy(mp, false, NULL); 287 vfs_destroy(mp); 288 return (error); 289 } 290 mutex_enter(&mountlist_lock); 291 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 292 mutex_exit(&mountlist_lock); 293 ump = VFSTOUFS(mp); 294 fs = ump->um_e2fs; 295 memset(fs->e2fs_fsmnt, 0, sizeof(fs->e2fs_fsmnt)); 296 (void) copystr(mp->mnt_stat.f_mntonname, fs->e2fs_fsmnt, 297 sizeof(fs->e2fs_fsmnt) - 1, 0); 298 if (fs->e2fs.e2fs_rev > E2FS_REV0) { 299 memset(fs->e2fs.e2fs_fsmnt, 0, sizeof(fs->e2fs.e2fs_fsmnt)); 300 (void) copystr(mp->mnt_stat.f_mntonname, fs->e2fs.e2fs_fsmnt, 301 sizeof(fs->e2fs.e2fs_fsmnt) - 1, 0); 302 } 303 (void)ext2fs_statvfs(mp, &mp->mnt_stat); 304 vfs_unbusy(mp, false, NULL); 305 setrootfstime((time_t)fs->e2fs.e2fs_wtime); 306 return (0); 307 } 308 309 /* 310 * VFS Operations. 311 * 312 * mount system call 313 */ 314 int 315 ext2fs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) 316 { 317 struct lwp *l = curlwp; 318 struct nameidata nd; 319 struct vnode *devvp; 320 struct ufs_args *args = data; 321 struct ufsmount *ump = NULL; 322 struct m_ext2fs *fs; 323 size_t size; 324 int error = 0, flags, update; 325 mode_t accessmode; 326 327 if (*data_len < sizeof *args) 328 return EINVAL; 329 330 if (mp->mnt_flag & MNT_GETARGS) { 331 ump = VFSTOUFS(mp); 332 if (ump == NULL) 333 return EIO; 334 memset(args, 0, sizeof *args); 335 args->fspec = NULL; 336 *data_len = sizeof *args; 337 return 0; 338 } 339 340 update = mp->mnt_flag & MNT_UPDATE; 341 342 /* Check arguments */ 343 if (args->fspec != NULL) { 344 /* 345 * Look up the name and verify that it's sane. 346 */ 347 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, args->fspec); 348 if ((error = namei(&nd)) != 0) 349 return (error); 350 devvp = nd.ni_vp; 351 352 if (!update) { 353 /* 354 * Be sure this is a valid block device 355 */ 356 if (devvp->v_type != VBLK) 357 error = ENOTBLK; 358 else if (bdevsw_lookup(devvp->v_rdev) == NULL) 359 error = ENXIO; 360 } else { 361 /* 362 * Be sure we're still naming the same device 363 * used for our initial mount 364 */ 365 ump = VFSTOUFS(mp); 366 if (devvp != ump->um_devvp) 367 error = EINVAL; 368 } 369 } else { 370 if (!update) { 371 /* New mounts must have a filename for the device */ 372 return (EINVAL); 373 } else { 374 ump = VFSTOUFS(mp); 375 devvp = ump->um_devvp; 376 vref(devvp); 377 } 378 } 379 380 /* 381 * If mount by non-root, then verify that user has necessary 382 * permissions on the device. 383 */ 384 if (error == 0 && kauth_authorize_generic(l->l_cred, 385 KAUTH_GENERIC_ISSUSER, NULL) != 0) { 386 accessmode = VREAD; 387 if (update ? 388 (mp->mnt_iflag & IMNT_WANTRDWR) != 0 : 389 (mp->mnt_flag & MNT_RDONLY) == 0) 390 accessmode |= VWRITE; 391 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 392 error = VOP_ACCESS(devvp, accessmode, l->l_cred); 393 VOP_UNLOCK(devvp, 0); 394 } 395 396 if (error) { 397 vrele(devvp); 398 return (error); 399 } 400 401 if (!update) { 402 int xflags; 403 404 if (mp->mnt_flag & MNT_RDONLY) 405 xflags = FREAD; 406 else 407 xflags = FREAD|FWRITE; 408 error = VOP_OPEN(devvp, xflags, FSCRED); 409 if (error) 410 goto fail; 411 error = ext2fs_mountfs(devvp, mp); 412 if (error) { 413 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 414 (void)VOP_CLOSE(devvp, xflags, NOCRED); 415 VOP_UNLOCK(devvp, 0); 416 goto fail; 417 } 418 419 ump = VFSTOUFS(mp); 420 fs = ump->um_e2fs; 421 } else { 422 /* 423 * Update the mount. 424 */ 425 426 /* 427 * The initial mount got a reference on this 428 * device, so drop the one obtained via 429 * namei(), above. 430 */ 431 vrele(devvp); 432 433 ump = VFSTOUFS(mp); 434 fs = ump->um_e2fs; 435 if (fs->e2fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 436 /* 437 * Changing from r/w to r/o 438 */ 439 flags = WRITECLOSE; 440 if (mp->mnt_flag & MNT_FORCE) 441 flags |= FORCECLOSE; 442 error = ext2fs_flushfiles(mp, flags); 443 if (error == 0 && 444 ext2fs_cgupdate(ump, MNT_WAIT) == 0 && 445 (fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) { 446 fs->e2fs.e2fs_state = E2FS_ISCLEAN; 447 (void) ext2fs_sbupdate(ump, MNT_WAIT); 448 } 449 if (error) 450 return (error); 451 fs->e2fs_ronly = 1; 452 } 453 454 if (mp->mnt_flag & MNT_RELOAD) { 455 error = ext2fs_reload(mp, l->l_cred); 456 if (error) 457 return (error); 458 } 459 460 if (fs->e2fs_ronly && (mp->mnt_iflag & IMNT_WANTRDWR)) { 461 /* 462 * Changing from read-only to read/write 463 */ 464 fs->e2fs_ronly = 0; 465 if (fs->e2fs.e2fs_state == E2FS_ISCLEAN) 466 fs->e2fs.e2fs_state = 0; 467 else 468 fs->e2fs.e2fs_state = E2FS_ERRORS; 469 fs->e2fs_fmod = 1; 470 } 471 if (args->fspec == NULL) 472 return EINVAL; 473 } 474 475 error = set_statvfs_info(path, UIO_USERSPACE, args->fspec, 476 UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l); 477 (void) copystr(mp->mnt_stat.f_mntonname, fs->e2fs_fsmnt, 478 sizeof(fs->e2fs_fsmnt) - 1, &size); 479 memset(fs->e2fs_fsmnt + size, 0, sizeof(fs->e2fs_fsmnt) - size); 480 if (fs->e2fs.e2fs_rev > E2FS_REV0) { 481 (void) copystr(mp->mnt_stat.f_mntonname, fs->e2fs.e2fs_fsmnt, 482 sizeof(fs->e2fs.e2fs_fsmnt) - 1, &size); 483 memset(fs->e2fs.e2fs_fsmnt, 0, 484 sizeof(fs->e2fs.e2fs_fsmnt) - size); 485 } 486 if (fs->e2fs_fmod != 0) { /* XXX */ 487 fs->e2fs_fmod = 0; 488 if (fs->e2fs.e2fs_state == 0) 489 fs->e2fs.e2fs_wtime = time_second; 490 else 491 printf("%s: file system not clean; please fsck(8)\n", 492 mp->mnt_stat.f_mntfromname); 493 (void) ext2fs_cgupdate(ump, MNT_WAIT); 494 } 495 return (error); 496 497 fail: 498 vrele(devvp); 499 return (error); 500 } 501 502 /* 503 * Reload all incore data for a filesystem (used after running fsck on 504 * the root filesystem and finding things to fix). The filesystem must 505 * be mounted read-only. 506 * 507 * Things to do to update the mount: 508 * 1) invalidate all cached meta-data. 509 * 2) re-read superblock from disk. 510 * 3) re-read summary information from disk. 511 * 4) invalidate all inactive vnodes. 512 * 5) invalidate all cached file data. 513 * 6) re-read inode data for all active vnodes. 514 */ 515 int 516 ext2fs_reload(struct mount *mountp, kauth_cred_t cred) 517 { 518 struct lwp *l = curlwp; 519 struct vnode *vp, *mvp, *devvp; 520 struct inode *ip; 521 struct buf *bp; 522 struct m_ext2fs *fs; 523 struct ext2fs *newfs; 524 struct partinfo dpart; 525 int i, size, error; 526 void *cp; 527 528 if ((mountp->mnt_flag & MNT_RDONLY) == 0) 529 return (EINVAL); 530 531 /* 532 * Step 1: invalidate all cached meta-data. 533 */ 534 devvp = VFSTOUFS(mountp)->um_devvp; 535 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 536 error = vinvalbuf(devvp, 0, cred, l, 0, 0); 537 VOP_UNLOCK(devvp, 0); 538 if (error) 539 panic("ext2fs_reload: dirty1"); 540 /* 541 * Step 2: re-read superblock from disk. 542 */ 543 if (VOP_IOCTL(devvp, DIOCGPART, &dpart, FREAD, NOCRED) != 0) 544 size = DEV_BSIZE; 545 else 546 size = dpart.disklab->d_secsize; 547 error = bread(devvp, (daddr_t)(SBOFF / size), SBSIZE, NOCRED, 0, &bp); 548 if (error) { 549 brelse(bp, 0); 550 return (error); 551 } 552 newfs = (struct ext2fs *)bp->b_data; 553 error = ext2fs_checksb(newfs, (mountp->mnt_flag & MNT_RDONLY) != 0); 554 if (error) { 555 brelse(bp, 0); 556 return (error); 557 } 558 559 fs = VFSTOUFS(mountp)->um_e2fs; 560 /* 561 * copy in new superblock, and compute in-memory values 562 */ 563 e2fs_sbload(newfs, &fs->e2fs); 564 fs->e2fs_ncg = 565 howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock, 566 fs->e2fs.e2fs_bpg); 567 /* XXX assume hw bsize = 512 */ 568 fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1; 569 fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize; 570 fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize; 571 fs->e2fs_qbmask = fs->e2fs_bsize - 1; 572 fs->e2fs_bmask = ~fs->e2fs_qbmask; 573 fs->e2fs_ngdb = 574 howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd)); 575 fs->e2fs_ipb = fs->e2fs_bsize / EXT2_DINODE_SIZE; 576 fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb; 577 578 /* 579 * Step 3: re-read summary information from disk. 580 */ 581 582 for (i = 0; i < fs->e2fs_ngdb; i++) { 583 error = bread(devvp , 584 fsbtodb(fs, fs->e2fs.e2fs_first_dblock + 585 1 /* superblock */ + i), 586 fs->e2fs_bsize, NOCRED, 0, &bp); 587 if (error) { 588 brelse(bp, 0); 589 return (error); 590 } 591 e2fs_cgload((struct ext2_gd *)bp->b_data, 592 &fs->e2fs_gd[i * fs->e2fs_bsize / sizeof(struct ext2_gd)], 593 fs->e2fs_bsize); 594 brelse(bp, 0); 595 } 596 597 /* Allocate a marker vnode. */ 598 if ((mvp = vnalloc(mountp)) == NULL) 599 return (ENOMEM); 600 /* 601 * NOTE: not using the TAILQ_FOREACH here since in this loop vgone() 602 * and vclean() can be called indirectly 603 */ 604 mutex_enter(&mntvnode_lock); 605 loop: 606 for (vp = TAILQ_FIRST(&mountp->mnt_vnodelist); vp; vp = vunmark(mvp)) { 607 vmark(mvp, vp); 608 if (vp->v_mount != mountp || vismarker(vp)) 609 continue; 610 /* 611 * Step 4: invalidate all inactive vnodes. 612 */ 613 if (vrecycle(vp, &mntvnode_lock, l)) { 614 mutex_enter(&mntvnode_lock); 615 (void)vunmark(mvp); 616 goto loop; 617 } 618 /* 619 * Step 5: invalidate all cached file data. 620 */ 621 mutex_enter(&vp->v_interlock); 622 mutex_exit(&mntvnode_lock); 623 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK)) { 624 mutex_enter(&mntvnode_lock); 625 (void)vunmark(mvp); 626 goto loop; 627 } 628 if (vinvalbuf(vp, 0, cred, l, 0, 0)) 629 panic("ext2fs_reload: dirty2"); 630 /* 631 * Step 6: re-read inode data for all active vnodes. 632 */ 633 ip = VTOI(vp); 634 error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 635 (int)fs->e2fs_bsize, NOCRED, 0, &bp); 636 if (error) { 637 vput(vp); 638 mutex_enter(&mntvnode_lock); 639 (void)vunmark(mvp); 640 break; 641 } 642 cp = (char *)bp->b_data + 643 (ino_to_fsbo(fs, ip->i_number) * EXT2_DINODE_SIZE); 644 e2fs_iload((struct ext2fs_dinode *)cp, ip->i_din.e2fs_din); 645 ext2fs_set_inode_guid(ip); 646 brelse(bp, 0); 647 vput(vp); 648 mutex_enter(&mntvnode_lock); 649 } 650 mutex_exit(&mntvnode_lock); 651 vnfree(mvp); 652 return (error); 653 } 654 655 /* 656 * Common code for mount and mountroot 657 */ 658 int 659 ext2fs_mountfs(struct vnode *devvp, struct mount *mp) 660 { 661 struct lwp *l = curlwp; 662 struct ufsmount *ump; 663 struct buf *bp; 664 struct ext2fs *fs; 665 struct m_ext2fs *m_fs; 666 dev_t dev; 667 struct partinfo dpart; 668 int error, i, size, ronly; 669 kauth_cred_t cred; 670 struct proc *p; 671 672 dev = devvp->v_rdev; 673 p = l ? l->l_proc : NULL; 674 cred = l ? l->l_cred : NOCRED; 675 676 /* Flush out any old buffers remaining from a previous use. */ 677 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 678 error = vinvalbuf(devvp, V_SAVE, cred, l, 0, 0); 679 VOP_UNLOCK(devvp, 0); 680 if (error) 681 return (error); 682 683 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 684 if (VOP_IOCTL(devvp, DIOCGPART, &dpart, FREAD, cred) != 0) 685 size = DEV_BSIZE; 686 else 687 size = dpart.disklab->d_secsize; 688 689 bp = NULL; 690 ump = NULL; 691 692 #ifdef DEBUG_EXT2 693 printf("sb size: %d ino size %d\n", sizeof(struct ext2fs), 694 EXT2_DINODE_SIZE); 695 #endif 696 error = bread(devvp, (SBOFF / size), SBSIZE, cred, 0, &bp); 697 if (error) 698 goto out; 699 fs = (struct ext2fs *)bp->b_data; 700 error = ext2fs_checksb(fs, ronly); 701 if (error) 702 goto out; 703 ump = malloc(sizeof(*ump), M_UFSMNT, M_WAITOK); 704 memset(ump, 0, sizeof(*ump)); 705 ump->um_fstype = UFS1; 706 ump->um_ops = &ext2fs_ufsops; 707 ump->um_e2fs = malloc(sizeof(struct m_ext2fs), M_UFSMNT, M_WAITOK); 708 memset(ump->um_e2fs, 0, sizeof(struct m_ext2fs)); 709 e2fs_sbload((struct ext2fs *)bp->b_data, &ump->um_e2fs->e2fs); 710 brelse(bp, 0); 711 bp = NULL; 712 m_fs = ump->um_e2fs; 713 m_fs->e2fs_ronly = ronly; 714 if (ronly == 0) { 715 if (m_fs->e2fs.e2fs_state == E2FS_ISCLEAN) 716 m_fs->e2fs.e2fs_state = 0; 717 else 718 m_fs->e2fs.e2fs_state = E2FS_ERRORS; 719 m_fs->e2fs_fmod = 1; 720 } 721 722 /* compute dynamic sb infos */ 723 m_fs->e2fs_ncg = 724 howmany(m_fs->e2fs.e2fs_bcount - m_fs->e2fs.e2fs_first_dblock, 725 m_fs->e2fs.e2fs_bpg); 726 /* XXX assume hw bsize = 512 */ 727 m_fs->e2fs_fsbtodb = m_fs->e2fs.e2fs_log_bsize + 1; 728 m_fs->e2fs_bsize = MINBSIZE << m_fs->e2fs.e2fs_log_bsize; 729 m_fs->e2fs_bshift = LOG_MINBSIZE + m_fs->e2fs.e2fs_log_bsize; 730 m_fs->e2fs_qbmask = m_fs->e2fs_bsize - 1; 731 m_fs->e2fs_bmask = ~m_fs->e2fs_qbmask; 732 m_fs->e2fs_ngdb = 733 howmany(m_fs->e2fs_ncg, m_fs->e2fs_bsize / sizeof(struct ext2_gd)); 734 m_fs->e2fs_ipb = m_fs->e2fs_bsize / EXT2_DINODE_SIZE; 735 m_fs->e2fs_itpg = m_fs->e2fs.e2fs_ipg / m_fs->e2fs_ipb; 736 737 m_fs->e2fs_gd = malloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize, 738 M_UFSMNT, M_WAITOK); 739 for (i = 0; i < m_fs->e2fs_ngdb; i++) { 740 error = bread(devvp , 741 fsbtodb(m_fs, m_fs->e2fs.e2fs_first_dblock + 742 1 /* superblock */ + i), 743 m_fs->e2fs_bsize, NOCRED, 0, &bp); 744 if (error) { 745 free(m_fs->e2fs_gd, M_UFSMNT); 746 goto out; 747 } 748 e2fs_cgload((struct ext2_gd *)bp->b_data, 749 &m_fs->e2fs_gd[ 750 i * m_fs->e2fs_bsize / sizeof(struct ext2_gd)], 751 m_fs->e2fs_bsize); 752 brelse(bp, 0); 753 bp = NULL; 754 } 755 756 mp->mnt_data = ump; 757 mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev; 758 mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_EXT2FS); 759 mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; 760 mp->mnt_stat.f_namemax = EXT2FS_MAXNAMLEN; 761 mp->mnt_flag |= MNT_LOCAL; 762 mp->mnt_dev_bshift = DEV_BSHIFT; /* XXX */ 763 mp->mnt_fs_bshift = m_fs->e2fs_bshift; 764 mp->mnt_iflag |= IMNT_DTYPE; 765 ump->um_flags = 0; 766 ump->um_mountp = mp; 767 ump->um_dev = dev; 768 ump->um_devvp = devvp; 769 ump->um_nindir = NINDIR(m_fs); 770 ump->um_lognindir = ffs(NINDIR(m_fs)) - 1; 771 ump->um_bptrtodb = m_fs->e2fs_fsbtodb; 772 ump->um_seqinc = 1; /* no frags */ 773 ump->um_maxsymlinklen = EXT2_MAXSYMLINKLEN; 774 ump->um_dirblksiz = m_fs->e2fs_bsize; 775 ump->um_maxfilesize = ((uint64_t)0x80000000 * m_fs->e2fs_bsize - 1); 776 devvp->v_specmountpoint = mp; 777 return (0); 778 779 out: 780 KASSERT(bp != NULL); 781 brelse(bp, 0); 782 if (ump) { 783 free(ump->um_e2fs, M_UFSMNT); 784 free(ump, M_UFSMNT); 785 mp->mnt_data = NULL; 786 } 787 return (error); 788 } 789 790 /* 791 * unmount system call 792 */ 793 int 794 ext2fs_unmount(struct mount *mp, int mntflags) 795 { 796 struct ufsmount *ump; 797 struct m_ext2fs *fs; 798 int error, flags; 799 800 flags = 0; 801 if (mntflags & MNT_FORCE) 802 flags |= FORCECLOSE; 803 if ((error = ext2fs_flushfiles(mp, flags)) != 0) 804 return (error); 805 ump = VFSTOUFS(mp); 806 fs = ump->um_e2fs; 807 if (fs->e2fs_ronly == 0 && 808 ext2fs_cgupdate(ump, MNT_WAIT) == 0 && 809 (fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) { 810 fs->e2fs.e2fs_state = E2FS_ISCLEAN; 811 (void) ext2fs_sbupdate(ump, MNT_WAIT); 812 } 813 if (ump->um_devvp->v_type != VBAD) 814 ump->um_devvp->v_specmountpoint = NULL; 815 vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); 816 error = VOP_CLOSE(ump->um_devvp, fs->e2fs_ronly ? FREAD : FREAD|FWRITE, 817 NOCRED); 818 vput(ump->um_devvp); 819 free(fs->e2fs_gd, M_UFSMNT); 820 free(fs, M_UFSMNT); 821 free(ump, M_UFSMNT); 822 mp->mnt_data = NULL; 823 mp->mnt_flag &= ~MNT_LOCAL; 824 return (error); 825 } 826 827 /* 828 * Flush out all the files in a filesystem. 829 */ 830 int 831 ext2fs_flushfiles(struct mount *mp, int flags) 832 { 833 extern int doforce; 834 int error; 835 836 if (!doforce) 837 flags &= ~FORCECLOSE; 838 error = vflush(mp, NULLVP, flags); 839 return (error); 840 } 841 842 /* 843 * Get file system statistics. 844 */ 845 int 846 ext2fs_statvfs(struct mount *mp, struct statvfs *sbp) 847 { 848 struct ufsmount *ump; 849 struct m_ext2fs *fs; 850 uint32_t overhead, overhead_per_group, ngdb; 851 int i, ngroups; 852 853 ump = VFSTOUFS(mp); 854 fs = ump->um_e2fs; 855 if (fs->e2fs.e2fs_magic != E2FS_MAGIC) 856 panic("ext2fs_statvfs"); 857 858 /* 859 * Compute the overhead (FS structures) 860 */ 861 overhead_per_group = 862 1 /* block bitmap */ + 863 1 /* inode bitmap */ + 864 fs->e2fs_itpg; 865 overhead = fs->e2fs.e2fs_first_dblock + 866 fs->e2fs_ncg * overhead_per_group; 867 if (fs->e2fs.e2fs_rev > E2FS_REV0 && 868 fs->e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_SPARSESUPER) { 869 for (i = 0, ngroups = 0; i < fs->e2fs_ncg; i++) { 870 if (cg_has_sb(i)) 871 ngroups++; 872 } 873 } else { 874 ngroups = fs->e2fs_ncg; 875 } 876 ngdb = fs->e2fs_ngdb; 877 if (fs->e2fs.e2fs_rev > E2FS_REV0 && 878 fs->e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) 879 ngdb += fs->e2fs.e2fs_reserved_ngdb; 880 overhead += ngroups * (1 /* superblock */ + ngdb); 881 882 sbp->f_bsize = fs->e2fs_bsize; 883 sbp->f_frsize = MINBSIZE << fs->e2fs.e2fs_fsize; 884 sbp->f_iosize = fs->e2fs_bsize; 885 sbp->f_blocks = fs->e2fs.e2fs_bcount - overhead; 886 sbp->f_bfree = fs->e2fs.e2fs_fbcount; 887 sbp->f_bresvd = fs->e2fs.e2fs_rbcount; 888 if (sbp->f_bfree > sbp->f_bresvd) 889 sbp->f_bavail = sbp->f_bfree - sbp->f_bresvd; 890 else 891 sbp->f_bavail = 0; 892 sbp->f_files = fs->e2fs.e2fs_icount; 893 sbp->f_ffree = fs->e2fs.e2fs_ficount; 894 sbp->f_favail = fs->e2fs.e2fs_ficount; 895 sbp->f_fresvd = 0; 896 copy_statvfs_info(sbp, mp); 897 return (0); 898 } 899 900 /* 901 * Go through the disk queues to initiate sandbagged IO; 902 * go through the inodes to write those that have been modified; 903 * initiate the writing of the super block if it has been modified. 904 * 905 * Note: we are always called with the filesystem marked `MPBUSY'. 906 */ 907 int 908 ext2fs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) 909 { 910 struct vnode *vp, *mvp; 911 struct inode *ip; 912 struct ufsmount *ump = VFSTOUFS(mp); 913 struct m_ext2fs *fs; 914 int error, allerror = 0; 915 916 fs = ump->um_e2fs; 917 if (fs->e2fs_fmod != 0 && fs->e2fs_ronly != 0) { /* XXX */ 918 printf("fs = %s\n", fs->e2fs_fsmnt); 919 panic("update: rofs mod"); 920 } 921 922 /* Allocate a marker vnode. */ 923 if ((mvp = vnalloc(mp)) == NULL) 924 return (ENOMEM); 925 926 /* 927 * Write back each (modified) inode. 928 */ 929 mutex_enter(&mntvnode_lock); 930 loop: 931 /* 932 * NOTE: not using the TAILQ_FOREACH here since in this loop vgone() 933 * and vclean() can be called indirectly 934 */ 935 for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) { 936 vmark(mvp, vp); 937 if (vp->v_mount != mp || vismarker(vp)) 938 continue; 939 mutex_enter(&vp->v_interlock); 940 ip = VTOI(vp); 941 if (ip == NULL || (vp->v_iflag & (VI_XLOCK|VI_CLEAN)) != 0 || 942 vp->v_type == VNON || 943 ((ip->i_flag & 944 (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) == 0 && 945 LIST_EMPTY(&vp->v_dirtyblkhd) && 946 UVM_OBJ_IS_CLEAN(&vp->v_uobj))) 947 { 948 mutex_exit(&vp->v_interlock); 949 continue; 950 } 951 mutex_exit(&mntvnode_lock); 952 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK); 953 if (error) { 954 mutex_enter(&mntvnode_lock); 955 if (error == ENOENT) { 956 mutex_enter(&mntvnode_lock); 957 (void)vunmark(mvp); 958 goto loop; 959 } 960 continue; 961 } 962 if (vp->v_type == VREG && waitfor == MNT_LAZY) 963 error = ext2fs_update(vp, NULL, NULL, 0); 964 else 965 error = VOP_FSYNC(vp, cred, 966 waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0); 967 if (error) 968 allerror = error; 969 vput(vp); 970 mutex_enter(&mntvnode_lock); 971 } 972 mutex_exit(&mntvnode_lock); 973 vnfree(mvp); 974 /* 975 * Force stale file system control information to be flushed. 976 */ 977 if (waitfor != MNT_LAZY) { 978 vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); 979 if ((error = VOP_FSYNC(ump->um_devvp, cred, 980 waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0)) != 0) 981 allerror = error; 982 VOP_UNLOCK(ump->um_devvp, 0); 983 } 984 /* 985 * Write back modified superblock. 986 */ 987 if (fs->e2fs_fmod != 0) { 988 fs->e2fs_fmod = 0; 989 fs->e2fs.e2fs_wtime = time_second; 990 if ((error = ext2fs_cgupdate(ump, waitfor))) 991 allerror = error; 992 } 993 return (allerror); 994 } 995 996 /* 997 * Look up a EXT2FS dinode number to find its incore vnode, otherwise read it 998 * in from disk. If it is in core, wait for the lock bit to clear, then 999 * return the inode locked. Detection and handling of mount points must be 1000 * done by the calling routine. 1001 */ 1002 int 1003 ext2fs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) 1004 { 1005 struct m_ext2fs *fs; 1006 struct inode *ip; 1007 struct ufsmount *ump; 1008 struct buf *bp; 1009 struct vnode *vp; 1010 dev_t dev; 1011 int error; 1012 void *cp; 1013 1014 ump = VFSTOUFS(mp); 1015 dev = ump->um_dev; 1016 retry: 1017 if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) 1018 return (0); 1019 1020 /* Allocate a new vnode/inode. */ 1021 if ((error = getnewvnode(VT_EXT2FS, mp, ext2fs_vnodeop_p, &vp)) != 0) { 1022 *vpp = NULL; 1023 return (error); 1024 } 1025 ip = pool_get(&ext2fs_inode_pool, PR_WAITOK); 1026 1027 mutex_enter(&ufs_hashlock); 1028 if ((*vpp = ufs_ihashget(dev, ino, 0)) != NULL) { 1029 mutex_exit(&ufs_hashlock); 1030 ungetnewvnode(vp); 1031 pool_put(&ext2fs_inode_pool, ip); 1032 goto retry; 1033 } 1034 1035 vp->v_vflag |= VV_LOCKSWORK; 1036 1037 memset(ip, 0, sizeof(struct inode)); 1038 vp->v_data = ip; 1039 ip->i_vnode = vp; 1040 ip->i_ump = ump; 1041 ip->i_e2fs = fs = ump->um_e2fs; 1042 ip->i_dev = dev; 1043 ip->i_number = ino; 1044 ip->i_e2fs_last_lblk = 0; 1045 ip->i_e2fs_last_blk = 0; 1046 genfs_node_init(vp, &ext2fs_genfsops); 1047 1048 /* 1049 * Put it onto its hash chain and lock it so that other requests for 1050 * this inode will block if they arrive while we are sleeping waiting 1051 * for old data structures to be purged or for the contents of the 1052 * disk portion of this inode to be read. 1053 */ 1054 1055 ufs_ihashins(ip); 1056 mutex_exit(&ufs_hashlock); 1057 1058 /* Read in the disk contents for the inode, copy into the inode. */ 1059 error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), 1060 (int)fs->e2fs_bsize, NOCRED, 0, &bp); 1061 if (error) { 1062 1063 /* 1064 * The inode does not contain anything useful, so it would 1065 * be misleading to leave it on its hash chain. With mode 1066 * still zero, it will be unlinked and returned to the free 1067 * list by vput(). 1068 */ 1069 1070 vput(vp); 1071 brelse(bp, 0); 1072 *vpp = NULL; 1073 return (error); 1074 } 1075 cp = (char *)bp->b_data + (ino_to_fsbo(fs, ino) * EXT2_DINODE_SIZE); 1076 ip->i_din.e2fs_din = pool_get(&ext2fs_dinode_pool, PR_WAITOK); 1077 e2fs_iload((struct ext2fs_dinode *)cp, ip->i_din.e2fs_din); 1078 ext2fs_set_inode_guid(ip); 1079 brelse(bp, 0); 1080 1081 /* If the inode was deleted, reset all fields */ 1082 if (ip->i_e2fs_dtime != 0) { 1083 ip->i_e2fs_mode = ip->i_e2fs_nblock = 0; 1084 (void)ext2fs_setsize(ip, 0); 1085 memset(ip->i_e2fs_blocks, 0, sizeof(ip->i_e2fs_blocks)); 1086 } 1087 1088 /* 1089 * Initialize the vnode from the inode, check for aliases. 1090 */ 1091 1092 error = ext2fs_vinit(mp, ext2fs_specop_p, ext2fs_fifoop_p, &vp); 1093 if (error) { 1094 vput(vp); 1095 *vpp = NULL; 1096 return (error); 1097 } 1098 /* 1099 * Finish inode initialization now that aliasing has been resolved. 1100 */ 1101 1102 ip->i_devvp = ump->um_devvp; 1103 VREF(ip->i_devvp); 1104 1105 /* 1106 * Set up a generation number for this inode if it does not 1107 * already have one. This should only happen on old filesystems. 1108 */ 1109 1110 if (ip->i_e2fs_gen == 0) { 1111 if (++ext2gennumber < (u_long)time_second) 1112 ext2gennumber = time_second; 1113 ip->i_e2fs_gen = ext2gennumber; 1114 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 1115 ip->i_flag |= IN_MODIFIED; 1116 } 1117 uvm_vnp_setsize(vp, ext2fs_size(ip)); 1118 *vpp = vp; 1119 return (0); 1120 } 1121 1122 /* 1123 * File handle to vnode 1124 * 1125 * Have to be really careful about stale file handles: 1126 * - check that the inode number is valid 1127 * - call ext2fs_vget() to get the locked inode 1128 * - check for an unallocated inode (i_mode == 0) 1129 */ 1130 int 1131 ext2fs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) 1132 { 1133 struct inode *ip; 1134 struct vnode *nvp; 1135 int error; 1136 struct ufid ufh; 1137 struct m_ext2fs *fs; 1138 1139 if (fhp->fid_len != sizeof(struct ufid)) 1140 return EINVAL; 1141 1142 memcpy(&ufh, fhp, sizeof(struct ufid)); 1143 fs = VFSTOUFS(mp)->um_e2fs; 1144 if ((ufh.ufid_ino < EXT2_FIRSTINO && ufh.ufid_ino != EXT2_ROOTINO) || 1145 ufh.ufid_ino >= fs->e2fs_ncg * fs->e2fs.e2fs_ipg) 1146 return (ESTALE); 1147 1148 if ((error = VFS_VGET(mp, ufh.ufid_ino, &nvp)) != 0) { 1149 *vpp = NULLVP; 1150 return (error); 1151 } 1152 ip = VTOI(nvp); 1153 if (ip->i_e2fs_mode == 0 || ip->i_e2fs_dtime != 0 || 1154 ip->i_e2fs_gen != ufh.ufid_gen) { 1155 vput(nvp); 1156 *vpp = NULLVP; 1157 return (ESTALE); 1158 } 1159 *vpp = nvp; 1160 return (0); 1161 } 1162 1163 /* 1164 * Vnode pointer to File handle 1165 */ 1166 /* ARGSUSED */ 1167 int 1168 ext2fs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size) 1169 { 1170 struct inode *ip; 1171 struct ufid ufh; 1172 1173 if (*fh_size < sizeof(struct ufid)) { 1174 *fh_size = sizeof(struct ufid); 1175 return E2BIG; 1176 } 1177 *fh_size = sizeof(struct ufid); 1178 1179 ip = VTOI(vp); 1180 memset(&ufh, 0, sizeof(ufh)); 1181 ufh.ufid_len = sizeof(struct ufid); 1182 ufh.ufid_ino = ip->i_number; 1183 ufh.ufid_gen = ip->i_e2fs_gen; 1184 memcpy(fhp, &ufh, sizeof(ufh)); 1185 return (0); 1186 } 1187 1188 /* 1189 * Write a superblock and associated information back to disk. 1190 */ 1191 int 1192 ext2fs_sbupdate(struct ufsmount *mp, int waitfor) 1193 { 1194 struct m_ext2fs *fs = mp->um_e2fs; 1195 struct buf *bp; 1196 int error = 0; 1197 1198 bp = getblk(mp->um_devvp, SBLOCK, SBSIZE, 0, 0); 1199 e2fs_sbsave(&fs->e2fs, (struct ext2fs*)bp->b_data); 1200 if (waitfor == MNT_WAIT) 1201 error = bwrite(bp); 1202 else 1203 bawrite(bp); 1204 return (error); 1205 } 1206 1207 int 1208 ext2fs_cgupdate(struct ufsmount *mp, int waitfor) 1209 { 1210 struct m_ext2fs *fs = mp->um_e2fs; 1211 struct buf *bp; 1212 int i, error = 0, allerror = 0; 1213 1214 allerror = ext2fs_sbupdate(mp, waitfor); 1215 for (i = 0; i < fs->e2fs_ngdb; i++) { 1216 bp = getblk(mp->um_devvp, fsbtodb(fs, 1217 fs->e2fs.e2fs_first_dblock + 1218 1 /* superblock */ + i), fs->e2fs_bsize, 0, 0); 1219 e2fs_cgsave(&fs->e2fs_gd[ 1220 i * fs->e2fs_bsize / sizeof(struct ext2_gd)], 1221 (struct ext2_gd *)bp->b_data, fs->e2fs_bsize); 1222 if (waitfor == MNT_WAIT) 1223 error = bwrite(bp); 1224 else 1225 bawrite(bp); 1226 } 1227 1228 if (!allerror && error) 1229 allerror = error; 1230 return (allerror); 1231 } 1232 1233 static int 1234 ext2fs_checksb(struct ext2fs *fs, int ronly) 1235 { 1236 1237 if (fs2h16(fs->e2fs_magic) != E2FS_MAGIC) { 1238 return (EINVAL); /* XXX needs translation */ 1239 } 1240 if (fs2h32(fs->e2fs_rev) > E2FS_REV1) { 1241 #ifdef DIAGNOSTIC 1242 printf("Ext2 fs: unsupported revision number: %x\n", 1243 fs2h32(fs->e2fs_rev)); 1244 #endif 1245 return (EINVAL); /* XXX needs translation */ 1246 } 1247 if (fs2h32(fs->e2fs_log_bsize) > 2) { /* block size = 1024|2048|4096 */ 1248 #ifdef DIAGNOSTIC 1249 printf("Ext2 fs: bad block size: %d " 1250 "(expected <= 2 for ext2 fs)\n", 1251 fs2h32(fs->e2fs_log_bsize)); 1252 #endif 1253 return (EINVAL); /* XXX needs translation */ 1254 } 1255 if (fs2h32(fs->e2fs_rev) > E2FS_REV0) { 1256 if (fs2h32(fs->e2fs_first_ino) != EXT2_FIRSTINO || 1257 fs2h16(fs->e2fs_inode_size) != EXT2_DINODE_SIZE) { 1258 printf("Ext2 fs: unsupported inode size\n"); 1259 return (EINVAL); /* XXX needs translation */ 1260 } 1261 if (fs2h32(fs->e2fs_features_incompat) & 1262 ~EXT2F_INCOMPAT_SUPP) { 1263 printf("Ext2 fs: unsupported optional feature\n"); 1264 return (EINVAL); /* XXX needs translation */ 1265 } 1266 if (!ronly && fs2h32(fs->e2fs_features_rocompat) & 1267 ~EXT2F_ROCOMPAT_SUPP) { 1268 return (EROFS); /* XXX needs translation */ 1269 } 1270 } 1271 return (0); 1272 } 1273