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