1 /* $NetBSD: ext2fs_vfsops.c,v 1.142 2009/03/01 15:59:57 christos 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.142 2009/03/01 15:59:57 christos 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(fs); 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(fs)); 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("ext2 sb size: %d\n", sizeof(struct ext2fs)); 694 #endif 695 error = bread(devvp, (SBOFF / size), SBSIZE, cred, 0, &bp); 696 if (error) 697 goto out; 698 fs = (struct ext2fs *)bp->b_data; 699 error = ext2fs_checksb(fs, ronly); 700 if (error) 701 goto out; 702 ump = malloc(sizeof(*ump), M_UFSMNT, M_WAITOK); 703 memset(ump, 0, sizeof(*ump)); 704 ump->um_fstype = UFS1; 705 ump->um_ops = &ext2fs_ufsops; 706 ump->um_e2fs = malloc(sizeof(struct m_ext2fs), M_UFSMNT, M_WAITOK); 707 memset(ump->um_e2fs, 0, sizeof(struct m_ext2fs)); 708 e2fs_sbload((struct ext2fs *)bp->b_data, &ump->um_e2fs->e2fs); 709 brelse(bp, 0); 710 bp = NULL; 711 m_fs = ump->um_e2fs; 712 m_fs->e2fs_ronly = ronly; 713 714 #ifdef DEBUG_EXT2 715 printf("ext2 ino size %d\n", EXT2_DINODE_SIZE(m_fs)); 716 #endif 717 if (ronly == 0) { 718 if (m_fs->e2fs.e2fs_state == E2FS_ISCLEAN) 719 m_fs->e2fs.e2fs_state = 0; 720 else 721 m_fs->e2fs.e2fs_state = E2FS_ERRORS; 722 m_fs->e2fs_fmod = 1; 723 } 724 725 /* compute dynamic sb infos */ 726 m_fs->e2fs_ncg = 727 howmany(m_fs->e2fs.e2fs_bcount - m_fs->e2fs.e2fs_first_dblock, 728 m_fs->e2fs.e2fs_bpg); 729 /* XXX assume hw bsize = 512 */ 730 m_fs->e2fs_fsbtodb = m_fs->e2fs.e2fs_log_bsize + 1; 731 m_fs->e2fs_bsize = MINBSIZE << m_fs->e2fs.e2fs_log_bsize; 732 m_fs->e2fs_bshift = LOG_MINBSIZE + m_fs->e2fs.e2fs_log_bsize; 733 m_fs->e2fs_qbmask = m_fs->e2fs_bsize - 1; 734 m_fs->e2fs_bmask = ~m_fs->e2fs_qbmask; 735 m_fs->e2fs_ngdb = 736 howmany(m_fs->e2fs_ncg, m_fs->e2fs_bsize / sizeof(struct ext2_gd)); 737 m_fs->e2fs_ipb = m_fs->e2fs_bsize / EXT2_DINODE_SIZE(m_fs); 738 m_fs->e2fs_itpg = m_fs->e2fs.e2fs_ipg / m_fs->e2fs_ipb; 739 740 m_fs->e2fs_gd = malloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize, 741 M_UFSMNT, M_WAITOK); 742 for (i = 0; i < m_fs->e2fs_ngdb; i++) { 743 error = bread(devvp , 744 fsbtodb(m_fs, m_fs->e2fs.e2fs_first_dblock + 745 1 /* superblock */ + i), 746 m_fs->e2fs_bsize, NOCRED, 0, &bp); 747 if (error) { 748 free(m_fs->e2fs_gd, M_UFSMNT); 749 goto out; 750 } 751 e2fs_cgload((struct ext2_gd *)bp->b_data, 752 &m_fs->e2fs_gd[ 753 i * m_fs->e2fs_bsize / sizeof(struct ext2_gd)], 754 m_fs->e2fs_bsize); 755 brelse(bp, 0); 756 bp = NULL; 757 } 758 759 mp->mnt_data = ump; 760 mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev; 761 mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_EXT2FS); 762 mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; 763 mp->mnt_stat.f_namemax = EXT2FS_MAXNAMLEN; 764 mp->mnt_flag |= MNT_LOCAL; 765 mp->mnt_dev_bshift = DEV_BSHIFT; /* XXX */ 766 mp->mnt_fs_bshift = m_fs->e2fs_bshift; 767 mp->mnt_iflag |= IMNT_DTYPE; 768 ump->um_flags = 0; 769 ump->um_mountp = mp; 770 ump->um_dev = dev; 771 ump->um_devvp = devvp; 772 ump->um_nindir = NINDIR(m_fs); 773 ump->um_lognindir = ffs(NINDIR(m_fs)) - 1; 774 ump->um_bptrtodb = m_fs->e2fs_fsbtodb; 775 ump->um_seqinc = 1; /* no frags */ 776 ump->um_maxsymlinklen = EXT2_MAXSYMLINKLEN; 777 ump->um_dirblksiz = m_fs->e2fs_bsize; 778 ump->um_maxfilesize = ((uint64_t)0x80000000 * m_fs->e2fs_bsize - 1); 779 devvp->v_specmountpoint = mp; 780 return (0); 781 782 out: 783 KASSERT(bp != NULL); 784 brelse(bp, 0); 785 if (ump) { 786 free(ump->um_e2fs, M_UFSMNT); 787 free(ump, M_UFSMNT); 788 mp->mnt_data = NULL; 789 } 790 return (error); 791 } 792 793 /* 794 * unmount system call 795 */ 796 int 797 ext2fs_unmount(struct mount *mp, int mntflags) 798 { 799 struct ufsmount *ump; 800 struct m_ext2fs *fs; 801 int error, flags; 802 803 flags = 0; 804 if (mntflags & MNT_FORCE) 805 flags |= FORCECLOSE; 806 if ((error = ext2fs_flushfiles(mp, flags)) != 0) 807 return (error); 808 ump = VFSTOUFS(mp); 809 fs = ump->um_e2fs; 810 if (fs->e2fs_ronly == 0 && 811 ext2fs_cgupdate(ump, MNT_WAIT) == 0 && 812 (fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) { 813 fs->e2fs.e2fs_state = E2FS_ISCLEAN; 814 (void) ext2fs_sbupdate(ump, MNT_WAIT); 815 } 816 if (ump->um_devvp->v_type != VBAD) 817 ump->um_devvp->v_specmountpoint = NULL; 818 vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); 819 error = VOP_CLOSE(ump->um_devvp, fs->e2fs_ronly ? FREAD : FREAD|FWRITE, 820 NOCRED); 821 vput(ump->um_devvp); 822 free(fs->e2fs_gd, M_UFSMNT); 823 free(fs, M_UFSMNT); 824 free(ump, M_UFSMNT); 825 mp->mnt_data = NULL; 826 mp->mnt_flag &= ~MNT_LOCAL; 827 return (error); 828 } 829 830 /* 831 * Flush out all the files in a filesystem. 832 */ 833 int 834 ext2fs_flushfiles(struct mount *mp, int flags) 835 { 836 extern int doforce; 837 int error; 838 839 if (!doforce) 840 flags &= ~FORCECLOSE; 841 error = vflush(mp, NULLVP, flags); 842 return (error); 843 } 844 845 /* 846 * Get file system statistics. 847 */ 848 int 849 ext2fs_statvfs(struct mount *mp, struct statvfs *sbp) 850 { 851 struct ufsmount *ump; 852 struct m_ext2fs *fs; 853 uint32_t overhead, overhead_per_group, ngdb; 854 int i, ngroups; 855 856 ump = VFSTOUFS(mp); 857 fs = ump->um_e2fs; 858 if (fs->e2fs.e2fs_magic != E2FS_MAGIC) 859 panic("ext2fs_statvfs"); 860 861 /* 862 * Compute the overhead (FS structures) 863 */ 864 overhead_per_group = 865 1 /* block bitmap */ + 866 1 /* inode bitmap */ + 867 fs->e2fs_itpg; 868 overhead = fs->e2fs.e2fs_first_dblock + 869 fs->e2fs_ncg * overhead_per_group; 870 if (fs->e2fs.e2fs_rev > E2FS_REV0 && 871 fs->e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_SPARSESUPER) { 872 for (i = 0, ngroups = 0; i < fs->e2fs_ncg; i++) { 873 if (cg_has_sb(i)) 874 ngroups++; 875 } 876 } else { 877 ngroups = fs->e2fs_ncg; 878 } 879 ngdb = fs->e2fs_ngdb; 880 if (fs->e2fs.e2fs_rev > E2FS_REV0 && 881 fs->e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) 882 ngdb += fs->e2fs.e2fs_reserved_ngdb; 883 overhead += ngroups * (1 /* superblock */ + ngdb); 884 885 sbp->f_bsize = fs->e2fs_bsize; 886 sbp->f_frsize = MINBSIZE << fs->e2fs.e2fs_fsize; 887 sbp->f_iosize = fs->e2fs_bsize; 888 sbp->f_blocks = fs->e2fs.e2fs_bcount - overhead; 889 sbp->f_bfree = fs->e2fs.e2fs_fbcount; 890 sbp->f_bresvd = fs->e2fs.e2fs_rbcount; 891 if (sbp->f_bfree > sbp->f_bresvd) 892 sbp->f_bavail = sbp->f_bfree - sbp->f_bresvd; 893 else 894 sbp->f_bavail = 0; 895 sbp->f_files = fs->e2fs.e2fs_icount; 896 sbp->f_ffree = fs->e2fs.e2fs_ficount; 897 sbp->f_favail = fs->e2fs.e2fs_ficount; 898 sbp->f_fresvd = 0; 899 copy_statvfs_info(sbp, mp); 900 return (0); 901 } 902 903 /* 904 * Go through the disk queues to initiate sandbagged IO; 905 * go through the inodes to write those that have been modified; 906 * initiate the writing of the super block if it has been modified. 907 * 908 * Note: we are always called with the filesystem marked `MPBUSY'. 909 */ 910 int 911 ext2fs_sync(struct mount *mp, int waitfor, kauth_cred_t cred) 912 { 913 struct vnode *vp, *mvp; 914 struct inode *ip; 915 struct ufsmount *ump = VFSTOUFS(mp); 916 struct m_ext2fs *fs; 917 int error, allerror = 0; 918 919 fs = ump->um_e2fs; 920 if (fs->e2fs_fmod != 0 && fs->e2fs_ronly != 0) { /* XXX */ 921 printf("fs = %s\n", fs->e2fs_fsmnt); 922 panic("update: rofs mod"); 923 } 924 925 /* Allocate a marker vnode. */ 926 if ((mvp = vnalloc(mp)) == NULL) 927 return (ENOMEM); 928 929 /* 930 * Write back each (modified) inode. 931 */ 932 mutex_enter(&mntvnode_lock); 933 loop: 934 /* 935 * NOTE: not using the TAILQ_FOREACH here since in this loop vgone() 936 * and vclean() can be called indirectly 937 */ 938 for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) { 939 vmark(mvp, vp); 940 if (vp->v_mount != mp || vismarker(vp)) 941 continue; 942 mutex_enter(&vp->v_interlock); 943 ip = VTOI(vp); 944 if (ip == NULL || (vp->v_iflag & (VI_XLOCK|VI_CLEAN)) != 0 || 945 vp->v_type == VNON || 946 ((ip->i_flag & 947 (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) == 0 && 948 LIST_EMPTY(&vp->v_dirtyblkhd) && 949 UVM_OBJ_IS_CLEAN(&vp->v_uobj))) 950 { 951 mutex_exit(&vp->v_interlock); 952 continue; 953 } 954 mutex_exit(&mntvnode_lock); 955 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK); 956 if (error) { 957 mutex_enter(&mntvnode_lock); 958 if (error == ENOENT) { 959 mutex_enter(&mntvnode_lock); 960 (void)vunmark(mvp); 961 goto loop; 962 } 963 continue; 964 } 965 if (vp->v_type == VREG && waitfor == MNT_LAZY) 966 error = ext2fs_update(vp, NULL, NULL, 0); 967 else 968 error = VOP_FSYNC(vp, cred, 969 waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0); 970 if (error) 971 allerror = error; 972 vput(vp); 973 mutex_enter(&mntvnode_lock); 974 } 975 mutex_exit(&mntvnode_lock); 976 vnfree(mvp); 977 /* 978 * Force stale file system control information to be flushed. 979 */ 980 if (waitfor != MNT_LAZY) { 981 vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); 982 if ((error = VOP_FSYNC(ump->um_devvp, cred, 983 waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0)) != 0) 984 allerror = error; 985 VOP_UNLOCK(ump->um_devvp, 0); 986 } 987 /* 988 * Write back modified superblock. 989 */ 990 if (fs->e2fs_fmod != 0) { 991 fs->e2fs_fmod = 0; 992 fs->e2fs.e2fs_wtime = time_second; 993 if ((error = ext2fs_cgupdate(ump, waitfor))) 994 allerror = error; 995 } 996 return (allerror); 997 } 998 999 /* 1000 * Look up a EXT2FS dinode number to find its incore vnode, otherwise read it 1001 * in from disk. If it is in core, wait for the lock bit to clear, then 1002 * return the inode locked. Detection and handling of mount points must be 1003 * done by the calling routine. 1004 */ 1005 int 1006 ext2fs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) 1007 { 1008 struct m_ext2fs *fs; 1009 struct inode *ip; 1010 struct ufsmount *ump; 1011 struct buf *bp; 1012 struct vnode *vp; 1013 dev_t dev; 1014 int error; 1015 void *cp; 1016 1017 ump = VFSTOUFS(mp); 1018 dev = ump->um_dev; 1019 retry: 1020 if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) 1021 return (0); 1022 1023 /* Allocate a new vnode/inode. */ 1024 if ((error = getnewvnode(VT_EXT2FS, mp, ext2fs_vnodeop_p, &vp)) != 0) { 1025 *vpp = NULL; 1026 return (error); 1027 } 1028 ip = pool_get(&ext2fs_inode_pool, PR_WAITOK); 1029 1030 mutex_enter(&ufs_hashlock); 1031 if ((*vpp = ufs_ihashget(dev, ino, 0)) != NULL) { 1032 mutex_exit(&ufs_hashlock); 1033 ungetnewvnode(vp); 1034 pool_put(&ext2fs_inode_pool, ip); 1035 goto retry; 1036 } 1037 1038 vp->v_vflag |= VV_LOCKSWORK; 1039 1040 memset(ip, 0, sizeof(struct inode)); 1041 vp->v_data = ip; 1042 ip->i_vnode = vp; 1043 ip->i_ump = ump; 1044 ip->i_e2fs = fs = ump->um_e2fs; 1045 ip->i_dev = dev; 1046 ip->i_number = ino; 1047 ip->i_e2fs_last_lblk = 0; 1048 ip->i_e2fs_last_blk = 0; 1049 genfs_node_init(vp, &ext2fs_genfsops); 1050 1051 /* 1052 * Put it onto its hash chain and lock it so that other requests for 1053 * this inode will block if they arrive while we are sleeping waiting 1054 * for old data structures to be purged or for the contents of the 1055 * disk portion of this inode to be read. 1056 */ 1057 1058 ufs_ihashins(ip); 1059 mutex_exit(&ufs_hashlock); 1060 1061 /* Read in the disk contents for the inode, copy into the inode. */ 1062 error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), 1063 (int)fs->e2fs_bsize, NOCRED, 0, &bp); 1064 if (error) { 1065 1066 /* 1067 * The inode does not contain anything useful, so it would 1068 * be misleading to leave it on its hash chain. With mode 1069 * still zero, it will be unlinked and returned to the free 1070 * list by vput(). 1071 */ 1072 1073 vput(vp); 1074 brelse(bp, 0); 1075 *vpp = NULL; 1076 return (error); 1077 } 1078 cp = (char *)bp->b_data + (ino_to_fsbo(fs, ino) * EXT2_DINODE_SIZE(fs)); 1079 ip->i_din.e2fs_din = pool_get(&ext2fs_dinode_pool, PR_WAITOK); 1080 e2fs_iload((struct ext2fs_dinode *)cp, ip->i_din.e2fs_din); 1081 ext2fs_set_inode_guid(ip); 1082 brelse(bp, 0); 1083 1084 /* If the inode was deleted, reset all fields */ 1085 if (ip->i_e2fs_dtime != 0) { 1086 ip->i_e2fs_mode = ip->i_e2fs_nblock = 0; 1087 (void)ext2fs_setsize(ip, 0); 1088 memset(ip->i_e2fs_blocks, 0, sizeof(ip->i_e2fs_blocks)); 1089 } 1090 1091 /* 1092 * Initialize the vnode from the inode, check for aliases. 1093 */ 1094 1095 error = ext2fs_vinit(mp, ext2fs_specop_p, ext2fs_fifoop_p, &vp); 1096 if (error) { 1097 vput(vp); 1098 *vpp = NULL; 1099 return (error); 1100 } 1101 /* 1102 * Finish inode initialization now that aliasing has been resolved. 1103 */ 1104 1105 ip->i_devvp = ump->um_devvp; 1106 VREF(ip->i_devvp); 1107 1108 /* 1109 * Set up a generation number for this inode if it does not 1110 * already have one. This should only happen on old filesystems. 1111 */ 1112 1113 if (ip->i_e2fs_gen == 0) { 1114 if (++ext2gennumber < (u_long)time_second) 1115 ext2gennumber = time_second; 1116 ip->i_e2fs_gen = ext2gennumber; 1117 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 1118 ip->i_flag |= IN_MODIFIED; 1119 } 1120 uvm_vnp_setsize(vp, ext2fs_size(ip)); 1121 *vpp = vp; 1122 return (0); 1123 } 1124 1125 /* 1126 * File handle to vnode 1127 * 1128 * Have to be really careful about stale file handles: 1129 * - check that the inode number is valid 1130 * - call ext2fs_vget() to get the locked inode 1131 * - check for an unallocated inode (i_mode == 0) 1132 */ 1133 int 1134 ext2fs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) 1135 { 1136 struct inode *ip; 1137 struct vnode *nvp; 1138 int error; 1139 struct ufid ufh; 1140 struct m_ext2fs *fs; 1141 1142 if (fhp->fid_len != sizeof(struct ufid)) 1143 return EINVAL; 1144 1145 memcpy(&ufh, fhp, sizeof(struct ufid)); 1146 fs = VFSTOUFS(mp)->um_e2fs; 1147 if ((ufh.ufid_ino < EXT2_FIRSTINO && ufh.ufid_ino != EXT2_ROOTINO) || 1148 ufh.ufid_ino >= fs->e2fs_ncg * fs->e2fs.e2fs_ipg) 1149 return (ESTALE); 1150 1151 if ((error = VFS_VGET(mp, ufh.ufid_ino, &nvp)) != 0) { 1152 *vpp = NULLVP; 1153 return (error); 1154 } 1155 ip = VTOI(nvp); 1156 if (ip->i_e2fs_mode == 0 || ip->i_e2fs_dtime != 0 || 1157 ip->i_e2fs_gen != ufh.ufid_gen) { 1158 vput(nvp); 1159 *vpp = NULLVP; 1160 return (ESTALE); 1161 } 1162 *vpp = nvp; 1163 return (0); 1164 } 1165 1166 /* 1167 * Vnode pointer to File handle 1168 */ 1169 /* ARGSUSED */ 1170 int 1171 ext2fs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size) 1172 { 1173 struct inode *ip; 1174 struct ufid ufh; 1175 1176 if (*fh_size < sizeof(struct ufid)) { 1177 *fh_size = sizeof(struct ufid); 1178 return E2BIG; 1179 } 1180 *fh_size = sizeof(struct ufid); 1181 1182 ip = VTOI(vp); 1183 memset(&ufh, 0, sizeof(ufh)); 1184 ufh.ufid_len = sizeof(struct ufid); 1185 ufh.ufid_ino = ip->i_number; 1186 ufh.ufid_gen = ip->i_e2fs_gen; 1187 memcpy(fhp, &ufh, sizeof(ufh)); 1188 return (0); 1189 } 1190 1191 /* 1192 * Write a superblock and associated information back to disk. 1193 */ 1194 int 1195 ext2fs_sbupdate(struct ufsmount *mp, int waitfor) 1196 { 1197 struct m_ext2fs *fs = mp->um_e2fs; 1198 struct buf *bp; 1199 int error = 0; 1200 1201 bp = getblk(mp->um_devvp, SBLOCK, SBSIZE, 0, 0); 1202 e2fs_sbsave(&fs->e2fs, (struct ext2fs*)bp->b_data); 1203 if (waitfor == MNT_WAIT) 1204 error = bwrite(bp); 1205 else 1206 bawrite(bp); 1207 return (error); 1208 } 1209 1210 int 1211 ext2fs_cgupdate(struct ufsmount *mp, int waitfor) 1212 { 1213 struct m_ext2fs *fs = mp->um_e2fs; 1214 struct buf *bp; 1215 int i, error = 0, allerror = 0; 1216 1217 allerror = ext2fs_sbupdate(mp, waitfor); 1218 for (i = 0; i < fs->e2fs_ngdb; i++) { 1219 bp = getblk(mp->um_devvp, fsbtodb(fs, 1220 fs->e2fs.e2fs_first_dblock + 1221 1 /* superblock */ + i), fs->e2fs_bsize, 0, 0); 1222 e2fs_cgsave(&fs->e2fs_gd[ 1223 i * fs->e2fs_bsize / sizeof(struct ext2_gd)], 1224 (struct ext2_gd *)bp->b_data, fs->e2fs_bsize); 1225 if (waitfor == MNT_WAIT) 1226 error = bwrite(bp); 1227 else 1228 bawrite(bp); 1229 } 1230 1231 if (!allerror && error) 1232 allerror = error; 1233 return (allerror); 1234 } 1235 1236 static int 1237 ext2fs_checksb(struct ext2fs *fs, int ronly) 1238 { 1239 1240 if (fs2h16(fs->e2fs_magic) != E2FS_MAGIC) { 1241 return (EINVAL); /* XXX needs translation */ 1242 } 1243 if (fs2h32(fs->e2fs_rev) > E2FS_REV1) { 1244 #ifdef DIAGNOSTIC 1245 printf("Ext2 fs: unsupported revision number: %x\n", 1246 fs2h32(fs->e2fs_rev)); 1247 #endif 1248 return (EINVAL); /* XXX needs translation */ 1249 } 1250 if (fs2h32(fs->e2fs_log_bsize) > 2) { /* block size = 1024|2048|4096 */ 1251 #ifdef DIAGNOSTIC 1252 printf("Ext2 fs: bad block size: %d " 1253 "(expected <= 2 for ext2 fs)\n", 1254 fs2h32(fs->e2fs_log_bsize)); 1255 #endif 1256 return (EINVAL); /* XXX needs translation */ 1257 } 1258 if (fs2h32(fs->e2fs_rev) > E2FS_REV0) { 1259 if (fs2h32(fs->e2fs_first_ino) != EXT2_FIRSTINO) { 1260 printf("Ext2 fs: unsupported first inode position\n"); 1261 return (EINVAL); /* XXX needs translation */ 1262 } 1263 if (fs2h32(fs->e2fs_features_incompat) & 1264 ~EXT2F_INCOMPAT_SUPP) { 1265 printf("Ext2 fs: unsupported optional feature\n"); 1266 return (EINVAL); /* XXX needs translation */ 1267 } 1268 if (!ronly && fs2h32(fs->e2fs_features_rocompat) & 1269 ~EXT2F_ROCOMPAT_SUPP) { 1270 return (EROFS); /* XXX needs translation */ 1271 } 1272 } 1273 return (0); 1274 } 1275