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