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