1 /* $NetBSD: ext2fs_vfsops.c,v 1.2 1997/06/12 17:14:56 mrg 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/param.h> 41 #include <sys/systm.h> 42 #include <sys/namei.h> 43 #include <sys/proc.h> 44 #include <sys/kernel.h> 45 #include <sys/vnode.h> 46 #include <sys/socket.h> 47 #include <sys/mount.h> 48 #include <sys/buf.h> 49 #include <sys/device.h> 50 #include <sys/mbuf.h> 51 #include <sys/file.h> 52 #include <sys/disklabel.h> 53 #include <sys/ioctl.h> 54 #include <sys/errno.h> 55 #include <sys/malloc.h> 56 57 #include <miscfs/specfs/specdev.h> 58 59 #include <ufs/ufs/quota.h> 60 #include <ufs/ufs/ufsmount.h> 61 #include <ufs/ufs/inode.h> 62 #include <ufs/ufs/dir.h> 63 #include <ufs/ufs/ufs_extern.h> 64 65 #include <ufs/ext2fs/ext2fs.h> 66 #include <ufs/ext2fs/ext2fs_extern.h> 67 68 int ext2fs_sbupdate __P((struct ufsmount *, int)); 69 int ext2fs_check_export __P((struct mount *, struct ufid *, struct mbuf *, 70 struct vnode **, int *, struct ucred **)); 71 72 struct vfsops ext2fs_vfsops = { 73 MOUNT_EXT2FS, 74 ext2fs_mount, 75 ufs_start, 76 ext2fs_unmount, 77 ufs_root, 78 ufs_quotactl, 79 ext2fs_statfs, 80 ext2fs_sync, 81 ext2fs_vget, 82 ext2fs_fhtovp, 83 ext2fs_vptofh, 84 ext2fs_init, 85 ext2fs_mountroot, 86 }; 87 88 extern u_long ext2gennumber; 89 90 /* 91 * This is the generic part of fhtovp called after the underlying 92 * filesystem has validated the file handle. 93 * 94 * Verify that a host should have access to a filesystem, and if so 95 * return a vnode for the presented file handle. 96 */ 97 int 98 ext2fs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp) 99 register struct mount *mp; 100 struct ufid *ufhp; 101 struct mbuf *nam; 102 struct vnode **vpp; 103 int *exflagsp; 104 struct ucred **credanonp; 105 { 106 register struct inode *ip; 107 register struct netcred *np; 108 register struct ufsmount *ump = VFSTOUFS(mp); 109 struct vnode *nvp; 110 int error; 111 112 /* 113 * Get the export permission structure for this <mp, client> tuple. 114 */ 115 np = vfs_export_lookup(mp, &ump->um_export, nam); 116 if (np == NULL) 117 return (EACCES); 118 119 if ((error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) != 0) { 120 *vpp = NULLVP; 121 return (error); 122 } 123 ip = VTOI(nvp); 124 if (ip->i_e2fs_mode == 0 || ip->i_e2fs_dtime != 0 || 125 ip->i_e2fs_gen != ufhp->ufid_gen) { 126 vput(nvp); 127 *vpp = NULLVP; 128 return (ESTALE); 129 } 130 *vpp = nvp; 131 *exflagsp = np->netc_exflags; 132 *credanonp = &np->netc_anon; 133 return (0); 134 } 135 136 137 /* 138 * Called by main() when ext2fs is going to be mounted as root. 139 * 140 * Name is updated by mount(8) after booting. 141 */ 142 #define ROOTNAME "root_device" 143 144 int 145 ext2fs_mountroot() 146 { 147 extern struct vnode *rootvp; 148 register struct m_ext2fs *fs; 149 register struct mount *mp; 150 struct proc *p = curproc; /* XXX */ 151 struct ufsmount *ump; 152 size_t size; 153 int error; 154 155 if (root_device->dv_class != DV_DISK) 156 return (ENODEV); 157 158 /* 159 * Get vnodes for rootdev. 160 */ 161 if (bdevvp(rootdev, &rootvp)) 162 panic("ext2fs_mountroot: can't setup bdevvp's"); 163 164 mp = malloc(sizeof(struct mount), M_MOUNT, M_WAITOK); 165 bzero((char *)mp, sizeof(struct mount)); 166 mp->mnt_op = &ext2fs_vfsops; 167 mp->mnt_flag = MNT_RDONLY; 168 if ((error = ext2fs_mountfs(rootvp, mp, p)) != 0) { 169 free(mp, M_MOUNT); 170 return (error); 171 } 172 if ((error = vfs_lock(mp)) != 0) { 173 (void)ext2fs_unmount(mp, 0, p); 174 free(mp, M_MOUNT); 175 return (error); 176 } 177 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 178 mp->mnt_vnodecovered = NULLVP; 179 ump = VFSTOUFS(mp); 180 fs = ump->um_e2fs; 181 bzero(fs->e2fs_fsmnt, sizeof(fs->e2fs_fsmnt)); 182 fs->e2fs_fsmnt[0] = '/'; 183 bcopy(fs->e2fs_fsmnt, mp->mnt_stat.f_mntonname, MNAMELEN); 184 (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 185 &size); 186 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 187 (void)ext2fs_statfs(mp, &mp->mnt_stat, p); 188 vfs_unlock(mp); 189 inittodr(fs->e2fs.e2fs_wtime); 190 return (0); 191 } 192 193 /* 194 * VFS Operations. 195 * 196 * mount system call 197 */ 198 int 199 ext2fs_mount(mp, path, data, ndp, p) 200 register struct mount *mp; 201 const char *path; 202 void * data; 203 struct nameidata *ndp; 204 struct proc *p; 205 { 206 struct vnode *devvp; 207 struct ufs_args args; 208 struct ufsmount *ump = NULL; 209 register struct m_ext2fs *fs; 210 size_t size; 211 int error, flags; 212 mode_t accessmode; 213 214 error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)); 215 if (error) 216 return (error); 217 /* 218 * If updating, check whether changing from read-only to 219 * read/write; if there is no device name, that's all we do. 220 */ 221 if (mp->mnt_flag & MNT_UPDATE) { 222 ump = VFSTOUFS(mp); 223 fs = ump->um_e2fs; 224 if (fs->e2fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 225 flags = WRITECLOSE; 226 if (mp->mnt_flag & MNT_FORCE) 227 flags |= FORCECLOSE; 228 if (vfs_busy(mp)) 229 return (EBUSY); 230 error = ext2fs_flushfiles(mp, flags, p); 231 if (error == 0 && 232 ext2fs_cgupdate(ump, MNT_WAIT) == 0 && 233 (fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) { 234 fs->e2fs.e2fs_state = E2FS_ISCLEAN; 235 (void) ext2fs_sbupdate(ump, MNT_WAIT); 236 } 237 vfs_unbusy(mp); 238 if (error) 239 return (error); 240 fs->e2fs_ronly = 1; 241 } 242 if (mp->mnt_flag & MNT_RELOAD) { 243 error = ext2fs_reload(mp, ndp->ni_cnd.cn_cred, p); 244 if (error) 245 return (error); 246 } 247 if (fs->e2fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) { 248 /* 249 * If upgrade to read-write by non-root, then verify 250 * that user has necessary permissions on the device. 251 */ 252 if (p->p_ucred->cr_uid != 0) { 253 devvp = ump->um_devvp; 254 VOP_LOCK(devvp); 255 error = VOP_ACCESS(devvp, VREAD | VWRITE, 256 p->p_ucred, p); 257 if (error) { 258 VOP_UNLOCK(devvp); 259 return (error); 260 } 261 VOP_UNLOCK(devvp); 262 } 263 fs->e2fs_ronly = 0; 264 if (fs->e2fs.e2fs_state == E2FS_ISCLEAN) 265 fs->e2fs.e2fs_state = 0; 266 else 267 fs->e2fs.e2fs_state = E2FS_ERRORS; 268 fs->e2fs_fmod = 1; 269 } 270 if (args.fspec == 0) { 271 /* 272 * Process export requests. 273 */ 274 return (vfs_export(mp, &ump->um_export, &args.export)); 275 } 276 } 277 /* 278 * Not an update, or updating the name: look up the name 279 * and verify that it refers to a sensible block device. 280 */ 281 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 282 if ((error = namei(ndp)) != 0) 283 return (error); 284 devvp = ndp->ni_vp; 285 286 if (devvp->v_type != VBLK) { 287 vrele(devvp); 288 return (ENOTBLK); 289 } 290 if (major(devvp->v_rdev) >= nblkdev) { 291 vrele(devvp); 292 return (ENXIO); 293 } 294 /* 295 * If mount by non-root, then verify that user has necessary 296 * permissions on the device. 297 */ 298 if (p->p_ucred->cr_uid != 0) { 299 accessmode = VREAD; 300 if ((mp->mnt_flag & MNT_RDONLY) == 0) 301 accessmode |= VWRITE; 302 VOP_LOCK(devvp); 303 error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p); 304 if (error) { 305 vput(devvp); 306 return (error); 307 } 308 VOP_UNLOCK(devvp); 309 } 310 if ((mp->mnt_flag & MNT_UPDATE) == 0) 311 error = ext2fs_mountfs(devvp, mp, p); 312 else { 313 if (devvp != ump->um_devvp) 314 error = EINVAL; /* needs translation */ 315 else 316 vrele(devvp); 317 } 318 if (error) { 319 vrele(devvp); 320 return (error); 321 } 322 ump = VFSTOUFS(mp); 323 fs = ump->um_e2fs; 324 (void) copyinstr(path, fs->e2fs_fsmnt, sizeof(fs->e2fs_fsmnt) - 1, &size); 325 bzero(fs->e2fs_fsmnt + size, sizeof(fs->e2fs_fsmnt) - size); 326 bcopy(fs->e2fs_fsmnt, mp->mnt_stat.f_mntonname, MNAMELEN); 327 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 328 &size); 329 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 330 if (fs->e2fs_fmod != 0) { /* XXX */ 331 fs->e2fs_fmod = 0; 332 if (fs->e2fs.e2fs_state == 0) 333 fs->e2fs.e2fs_wtime = time.tv_sec; 334 else 335 printf("%s: file system not clean; please fsck(8)\n", 336 mp->mnt_stat.f_mntfromname); 337 (void) ext2fs_cgupdate(ump, MNT_WAIT); 338 } 339 return (0); 340 } 341 342 /* 343 * Reload all incore data for a filesystem (used after running fsck on 344 * the root filesystem and finding things to fix). The filesystem must 345 * be mounted read-only. 346 * 347 * Things to do to update the mount: 348 * 1) invalidate all cached meta-data. 349 * 2) re-read superblock from disk. 350 * 3) re-read summary information from disk. 351 * 4) invalidate all inactive vnodes. 352 * 5) invalidate all cached file data. 353 * 6) re-read inode data for all active vnodes. 354 */ 355 int 356 ext2fs_reload(mountp, cred, p) 357 register struct mount *mountp; 358 struct ucred *cred; 359 struct proc *p; 360 { 361 register struct vnode *vp, *nvp, *devvp; 362 struct inode *ip; 363 struct buf *bp; 364 struct m_ext2fs *fs; 365 struct ext2fs *newfs; 366 struct partinfo dpart; 367 int i, size, error; 368 369 if ((mountp->mnt_flag & MNT_RDONLY) == 0) 370 return (EINVAL); 371 /* 372 * Step 1: invalidate all cached meta-data. 373 */ 374 devvp = VFSTOUFS(mountp)->um_devvp; 375 if (vinvalbuf(devvp, 0, cred, p, 0, 0)) 376 panic("ext2fs_reload: dirty1"); 377 /* 378 * Step 2: re-read superblock from disk. 379 */ 380 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) 381 size = DEV_BSIZE; 382 else 383 size = dpart.disklab->d_secsize; 384 error = bread(devvp, (daddr_t)(SBOFF / size), SBSIZE, NOCRED, &bp); 385 if (error) 386 return (error); 387 newfs = (struct ext2fs *)bp->b_data; 388 if (newfs->e2fs_magic != E2FS_MAGIC || newfs->e2fs_rev != E2FS_REV) { 389 #ifdef DIAGNOSTIC 390 printf("Wrong magic number: %x (expected %x for ext2 fs)", 391 newfs->e2fs_magic, E2FS_MAGIC); 392 printf("or wrong revision number: %x (expected %x for ext2 fs)", 393 newfs->e2fs_rev, E2FS_REV); 394 #endif 395 brelse(bp); 396 return (EIO); /* XXX needs translation */ 397 } 398 if (newfs->e2fs_log_bsize > 2) { /* block size = 1024|2048|4096 */ 399 #ifdef DIAGNOSTIC 400 printf("wrong block size: %d (expected <=2 for ext2 fs)\n", 401 newfs->e2fs_log_bsize); 402 #endif 403 brelse(bp); 404 return (EIO); /* XXX needs translation */ 405 } 406 407 408 fs = VFSTOUFS(mountp)->um_e2fs; 409 /* 410 * copy in new superblock, and compute in-memory values 411 */ 412 bcopy(newfs, &fs->e2fs, SBSIZE); 413 fs->e2fs_ncg = howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock, 414 fs->e2fs.e2fs_bpg); 415 /* XXX assume hw bsize = 512 */ 416 fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1; 417 fs->e2fs_bsize = 1024 << fs->e2fs.e2fs_log_bsize; 418 fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize; 419 fs->e2fs_qbmask = fs->e2fs_bsize - 1; 420 fs->e2fs_bmask = ~fs->e2fs_qbmask; 421 fs->e2fs_ngdb = howmany(fs->e2fs_ncg, 422 fs->e2fs_bsize / sizeof(struct ext2_gd)); 423 fs->e2fs_ipb = fs->e2fs_bsize / sizeof(struct ext2fs_dinode); 424 fs->e2fs_itpg = fs->e2fs.e2fs_ipg/fs->e2fs_ipb; 425 426 /* 427 * Step 3: re-read summary information from disk. 428 */ 429 430 for (i=0; i < fs->e2fs_ngdb; i++) { 431 error = bread(devvp , fsbtodb(fs, ((fs->e2fs_bsize>1024)?0:1)+i+1), 432 fs->e2fs_bsize, NOCRED, &bp); 433 if (error) 434 return (error); 435 bcopy(bp->b_data, 436 &fs->e2fs_gd[i* fs->e2fs_bsize / sizeof(struct ext2_gd)], 437 fs->e2fs_bsize); 438 brelse(bp); 439 } 440 441 loop: 442 for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { 443 nvp = vp->v_mntvnodes.le_next; 444 /* 445 * Step 4: invalidate all inactive vnodes. 446 */ 447 if (vp->v_usecount == 0) { 448 vgone(vp); 449 continue; 450 } 451 /* 452 * Step 5: invalidate all cached file data. 453 */ 454 if (vget(vp, 1)) 455 goto loop; 456 if (vinvalbuf(vp, 0, cred, p, 0, 0)) 457 panic("ext2fs_reload: dirty2"); 458 /* 459 * Step 6: re-read inode data for all active vnodes. 460 */ 461 ip = VTOI(vp); 462 error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 463 (int)fs->e2fs_bsize, NOCRED, &bp); 464 if (error) { 465 vput(vp); 466 return (error); 467 } 468 bcopy((struct ext2fs_dinode *)bp->b_data + 469 ino_to_fsbo(fs, ip->i_number), 470 &ip->i_din.e2fs_din, sizeof(struct ext2fs_dinode)); 471 brelse(bp); 472 vput(vp); 473 if (vp->v_mount != mountp) 474 goto loop; 475 } 476 return (0); 477 } 478 479 /* 480 * Common code for mount and mountroot 481 */ 482 int 483 ext2fs_mountfs(devvp, mp, p) 484 register struct vnode *devvp; 485 struct mount *mp; 486 struct proc *p; 487 { 488 register struct ufsmount *ump; 489 struct buf *bp; 490 register struct ext2fs *fs; 491 register struct m_ext2fs *m_fs; 492 dev_t dev; 493 struct partinfo dpart; 494 int error, i, size, ronly; 495 struct ucred *cred; 496 extern struct vnode *rootvp; 497 498 dev = devvp->v_rdev; 499 cred = p ? p->p_ucred : NOCRED; 500 /* 501 * Disallow multiple mounts of the same device. 502 * Disallow mounting of a device that is currently in use 503 * (except for root, which might share swap device for miniroot). 504 * Flush out any old buffers remaining from a previous use. 505 */ 506 if ((error = vfs_mountedon(devvp)) != 0) 507 return (error); 508 if (vcount(devvp) > 1 && devvp != rootvp) 509 return (EBUSY); 510 if ((error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) != 0) 511 return (error); 512 513 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 514 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); 515 if (error) 516 return (error); 517 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0) 518 size = DEV_BSIZE; 519 else 520 size = dpart.disklab->d_secsize; 521 522 bp = NULL; 523 ump = NULL; 524 525 #ifdef DEBUG_EXT2 526 printf("sb size: %d ino size %d\n", sizeof(struct ext2fs), 527 sizeof(struct ext2fs_dinode)); 528 #endif 529 error = bread(devvp, (SBOFF / DEV_BSIZE), SBSIZE, cred, &bp); 530 if (error) 531 goto out; 532 fs = (struct ext2fs *)bp->b_data; 533 if (fs->e2fs_magic != E2FS_MAGIC || fs->e2fs_rev != E2FS_REV) { 534 #ifdef DIAGNOSTIC 535 printf("Wrong magic number: %x (expected %x for ext2 fs)", 536 fs->e2fs_magic, E2FS_MAGIC); 537 printf(" or wrong revision number: %x (expected %x for ext2 fs)\n", 538 fs->e2fs_rev, E2FS_REV); 539 #endif 540 error = EINVAL; /* XXX needs translation */ 541 goto out; 542 } 543 544 if (fs->e2fs_log_bsize > 2) { /* block size = 1024|2048|4096 */ 545 #ifdef DIAGNOSTIC 546 printf("wrong block size: %d (expected <2 for ext2 fs)\n", 547 fs->e2fs_log_bsize); 548 #endif 549 error = EINVAL; /* XXX needs translation */ 550 goto out; 551 } 552 553 ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 554 bzero((caddr_t)ump, sizeof *ump); 555 ump->um_e2fs = malloc(sizeof(struct m_ext2fs), M_UFSMNT, M_WAITOK); 556 bcopy(bp->b_data, ump->um_e2fs, SBSIZE); 557 brelse(bp); 558 bp = NULL; 559 m_fs = ump->um_e2fs; 560 m_fs->e2fs_ronly = ronly; 561 if (ronly == 0) { 562 if (m_fs->e2fs.e2fs_state == E2FS_ISCLEAN) 563 m_fs->e2fs.e2fs_state = 0; 564 else 565 m_fs->e2fs.e2fs_state = E2FS_ERRORS; 566 m_fs->e2fs_fmod = 1; 567 } 568 569 /* compute dynamic sb infos */ 570 m_fs->e2fs_ncg = 571 howmany(m_fs->e2fs.e2fs_bcount - m_fs->e2fs.e2fs_first_dblock, 572 m_fs->e2fs.e2fs_bpg); 573 /* XXX assume hw bsize = 512 */ 574 m_fs->e2fs_fsbtodb = m_fs->e2fs.e2fs_log_bsize + 1; 575 m_fs->e2fs_bsize = 1024 << m_fs->e2fs.e2fs_log_bsize; 576 m_fs->e2fs_bshift = LOG_MINBSIZE + m_fs->e2fs.e2fs_log_bsize; 577 m_fs->e2fs_qbmask = m_fs->e2fs_bsize - 1; 578 m_fs->e2fs_bmask = ~m_fs->e2fs_qbmask; 579 m_fs->e2fs_ngdb = howmany(m_fs->e2fs_ncg, 580 m_fs->e2fs_bsize / sizeof(struct ext2_gd)); 581 m_fs->e2fs_ipb = m_fs->e2fs_bsize / sizeof(struct ext2fs_dinode); 582 m_fs->e2fs_itpg = m_fs->e2fs.e2fs_ipg/m_fs->e2fs_ipb; 583 584 m_fs->e2fs_gd = malloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize, 585 M_UFSMNT, M_WAITOK); 586 for (i=0; i < m_fs->e2fs_ngdb; i++) { 587 error = bread(devvp , fsbtodb(m_fs, ((m_fs->e2fs_bsize>1024)?0:1)+i+1), 588 m_fs->e2fs_bsize, NOCRED, &bp); 589 if (error) { 590 free(m_fs->e2fs_gd, M_UFSMNT); 591 goto out; 592 } 593 bcopy(bp->b_data, 594 &m_fs->e2fs_gd[i* m_fs->e2fs_bsize / sizeof(struct ext2_gd)], 595 m_fs->e2fs_bsize); 596 brelse(bp); 597 bp = NULL; 598 } 599 600 mp->mnt_data = (qaddr_t)ump; 601 mp->mnt_stat.f_fsid.val[0] = (long)dev; 602 mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_EXT2FS); 603 mp->mnt_maxsymlinklen = EXT2_MAXSYMLINKLEN; 604 mp->mnt_flag |= MNT_LOCAL; 605 ump->um_mountp = mp; 606 ump->um_dev = dev; 607 ump->um_devvp = devvp; 608 ump->um_nindir = NINDIR(m_fs); 609 ump->um_bptrtodb = m_fs->e2fs_fsbtodb; 610 ump->um_seqinc = 1; /* no frags */ 611 devvp->v_specflags |= SI_MOUNTEDON; 612 return (0); 613 out: 614 if (bp) 615 brelse(bp); 616 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); 617 if (ump) { 618 free(ump->um_e2fs, M_UFSMNT); 619 free(ump, M_UFSMNT); 620 mp->mnt_data = (qaddr_t)0; 621 } 622 return (error); 623 } 624 625 /* 626 * unmount system call 627 */ 628 int 629 ext2fs_unmount(mp, mntflags, p) 630 struct mount *mp; 631 int mntflags; 632 struct proc *p; 633 { 634 register struct ufsmount *ump; 635 register struct m_ext2fs *fs; 636 int error, flags; 637 638 flags = 0; 639 if (mntflags & MNT_FORCE) 640 flags |= FORCECLOSE; 641 if ((error = ext2fs_flushfiles(mp, flags, p)) != 0) 642 return (error); 643 ump = VFSTOUFS(mp); 644 fs = ump->um_e2fs; 645 if (fs->e2fs_ronly == 0 && 646 ext2fs_cgupdate(ump, MNT_WAIT) == 0 && 647 (fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) { 648 fs->e2fs.e2fs_state = E2FS_ISCLEAN; 649 (void) ext2fs_sbupdate(ump, MNT_WAIT); 650 } 651 ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 652 error = VOP_CLOSE(ump->um_devvp, fs->e2fs_ronly ? FREAD : FREAD|FWRITE, 653 NOCRED, p); 654 vrele(ump->um_devvp); 655 free(fs->e2fs_gd, M_UFSMNT); 656 free(fs, M_UFSMNT); 657 free(ump, M_UFSMNT); 658 mp->mnt_data = (qaddr_t)0; 659 mp->mnt_flag &= ~MNT_LOCAL; 660 return (error); 661 } 662 663 /* 664 * Flush out all the files in a filesystem. 665 */ 666 int 667 ext2fs_flushfiles(mp, flags, p) 668 register struct mount *mp; 669 int flags; 670 struct proc *p; 671 { 672 extern int doforce; 673 register struct ufsmount *ump; 674 int error; 675 676 if (!doforce) 677 flags &= ~FORCECLOSE; 678 ump = VFSTOUFS(mp); 679 error = vflush(mp, NULLVP, flags); 680 return (error); 681 } 682 683 /* 684 * Get file system statistics. 685 */ 686 int 687 ext2fs_statfs(mp, sbp, p) 688 struct mount *mp; 689 register struct statfs *sbp; 690 struct proc *p; 691 { 692 register struct ufsmount *ump; 693 register struct m_ext2fs *fs; 694 u_int32_t overhead, overhead_per_group; 695 696 ump = VFSTOUFS(mp); 697 fs = ump->um_e2fs; 698 if (fs->e2fs.e2fs_magic != E2FS_MAGIC) 699 panic("ext2fs_statfs"); 700 #ifdef COMPAT_09 701 sbp->f_type = 1; 702 #else 703 sbp->f_type = 0; 704 #endif 705 706 /* 707 * Compute the overhead (FS structures) 708 */ 709 overhead_per_group = 1 /* super block */ + 710 fs->e2fs_ngdb + 711 1 /* block bitmap */ + 712 1 /* inode bitmap */ + 713 fs->e2fs_itpg; 714 overhead = fs->e2fs.e2fs_first_dblock + 715 fs->e2fs_ncg * overhead_per_group; 716 717 718 sbp->f_bsize = fs->e2fs_bsize; 719 sbp->f_iosize = fs->e2fs_bsize; 720 sbp->f_blocks = fs->e2fs.e2fs_bcount - overhead; 721 sbp->f_bfree = fs->e2fs.e2fs_fbcount; 722 sbp->f_bavail = sbp->f_bfree - fs->e2fs.e2fs_rbcount; 723 sbp->f_files = fs->e2fs.e2fs_icount; 724 sbp->f_ffree = fs->e2fs.e2fs_ficount; 725 if (sbp != &mp->mnt_stat) { 726 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 727 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 728 } 729 strncpy(sbp->f_fstypename, mp->mnt_op->vfs_name, MFSNAMELEN); 730 return (0); 731 } 732 733 /* 734 * Go through the disk queues to initiate sandbagged IO; 735 * go through the inodes to write those that have been modified; 736 * initiate the writing of the super block if it has been modified. 737 * 738 * Note: we are always called with the filesystem marked `MPBUSY'. 739 */ 740 int 741 ext2fs_sync(mp, waitfor, cred, p) 742 struct mount *mp; 743 int waitfor; 744 struct ucred *cred; 745 struct proc *p; 746 { 747 register struct vnode *vp; 748 register struct inode *ip; 749 register struct ufsmount *ump = VFSTOUFS(mp); 750 register struct m_ext2fs *fs; 751 int error, allerror = 0; 752 753 fs = ump->um_e2fs; 754 /* 755 * Write back modified superblock. 756 * Consistency check that the superblock 757 * is still in the buffer cache. 758 */ 759 if (fs->e2fs_fmod != 0) { 760 if (fs->e2fs_ronly != 0) { /* XXX */ 761 printf("fs = %s\n", fs->e2fs_fsmnt); 762 panic("update: rofs mod"); 763 } 764 fs->e2fs_fmod = 0; 765 fs->e2fs.e2fs_wtime = time.tv_sec; 766 allerror = ext2fs_cgupdate(ump, waitfor); 767 } 768 /* 769 * Write back each (modified) inode. 770 */ 771 loop: 772 for (vp = mp->mnt_vnodelist.lh_first; 773 vp != NULL; 774 vp = vp->v_mntvnodes.le_next) { 775 /* 776 * If the vnode that we are about to sync is no longer 777 * associated with this mount point, start over. 778 */ 779 if (vp->v_mount != mp) 780 goto loop; 781 if (VOP_ISLOCKED(vp)) 782 continue; 783 ip = VTOI(vp); 784 if ((ip->i_flag & 785 (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && 786 vp->v_dirtyblkhd.lh_first == NULL) 787 continue; 788 if (vget(vp, 1)) 789 goto loop; 790 if ((error = VOP_FSYNC(vp, cred, waitfor, p)) != 0) 791 allerror = error; 792 vput(vp); 793 } 794 /* 795 * Force stale file system control information to be flushed. 796 */ 797 if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) != 0) 798 allerror = error; 799 return (allerror); 800 } 801 802 /* 803 * Look up a EXT2FS dinode number to find its incore vnode, otherwise read it 804 * in from disk. If it is in core, wait for the lock bit to clear, then 805 * return the inode locked. Detection and handling of mount points must be 806 * done by the calling routine. 807 */ 808 int 809 ext2fs_vget(mp, ino, vpp) 810 struct mount *mp; 811 ino_t ino; 812 struct vnode **vpp; 813 { 814 register struct m_ext2fs *fs; 815 register struct inode *ip; 816 struct ufsmount *ump; 817 struct buf *bp; 818 struct vnode *vp; 819 dev_t dev; 820 int error; 821 822 ump = VFSTOUFS(mp); 823 dev = ump->um_dev; 824 if ((*vpp = ufs_ihashget(dev, ino)) != NULL) 825 return (0); 826 827 /* Allocate a new vnode/inode. */ 828 if ((error = getnewvnode(VT_EXT2FS, mp, ext2fs_vnodeop_p, &vp)) != 0) { 829 *vpp = NULL; 830 return (error); 831 } 832 MALLOC(ip, struct inode *, sizeof(struct inode), M_EXT2FSNODE, M_WAITOK); 833 bzero((caddr_t)ip, sizeof(struct inode)); 834 vp->v_data = ip; 835 ip->i_vnode = vp; 836 ip->i_e2fs = fs = ump->um_e2fs; 837 ip->i_dev = dev; 838 ip->i_number = ino; 839 ip->i_e2fs_last_lblk = 0; 840 ip->i_e2fs_last_blk = 0; 841 842 /* 843 * Put it onto its hash chain and lock it so that other requests for 844 * this inode will block if they arrive while we are sleeping waiting 845 * for old data structures to be purged or for the contents of the 846 * disk portion of this inode to be read. 847 */ 848 ufs_ihashins(ip); 849 850 /* Read in the disk contents for the inode, copy into the inode. */ 851 error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), 852 (int)fs->e2fs_bsize, NOCRED, &bp); 853 if (error) { 854 /* 855 * The inode does not contain anything useful, so it would 856 * be misleading to leave it on its hash chain. With mode 857 * still zero, it will be unlinked and returned to the free 858 * list by vput(). 859 */ 860 vput(vp); 861 brelse(bp); 862 *vpp = NULL; 863 return (error); 864 } 865 bcopy(((struct ext2fs_dinode*)bp->b_data + ino_to_fsbo(fs, ino)), 866 &ip->i_din, sizeof(struct ext2fs_dinode)); 867 868 brelse(bp); 869 870 /* 871 * Initialize the vnode from the inode, check for aliases. 872 * Note that the underlying vnode may have changed. 873 */ 874 error = ufs_vinit(mp, ext2fs_specop_p, EXT2FS_FIFOOPS, &vp); 875 if (error) { 876 vput(vp); 877 *vpp = NULL; 878 return (error); 879 } 880 /* 881 * Finish inode initialization now that aliasing has been resolved. 882 */ 883 ip->i_devvp = ump->um_devvp; 884 VREF(ip->i_devvp); 885 /* 886 * Set up a generation number for this inode if it does not 887 * already have one. This should only happen on old filesystems. 888 */ 889 if (ip->i_e2fs_gen == 0) { 890 if (++ext2gennumber < (u_long)time.tv_sec) 891 ext2gennumber = time.tv_sec; 892 ip->i_e2fs_gen = ext2gennumber; 893 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 894 ip->i_flag |= IN_MODIFIED; 895 } 896 897 *vpp = vp; 898 return (0); 899 } 900 901 /* 902 * File handle to vnode 903 * 904 * Have to be really careful about stale file handles: 905 * - check that the inode number is valid 906 * - call ext2fs_vget() to get the locked inode 907 * - check for an unallocated inode (i_mode == 0) 908 * - check that the given client host has export rights and return 909 * those rights via. exflagsp and credanonp 910 */ 911 int 912 ext2fs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 913 register struct mount *mp; 914 struct fid *fhp; 915 struct mbuf *nam; 916 struct vnode **vpp; 917 int *exflagsp; 918 struct ucred **credanonp; 919 { 920 register struct ufid *ufhp; 921 struct m_ext2fs *fs; 922 923 ufhp = (struct ufid *)fhp; 924 fs = VFSTOUFS(mp)->um_e2fs; 925 if ((ufhp->ufid_ino < EXT2_FIRSTINO && ufhp->ufid_ino != EXT2_ROOTINO) || 926 ufhp->ufid_ino >= fs->e2fs_ncg * fs->e2fs.e2fs_ipg) 927 return (ESTALE); 928 return (ext2fs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)); 929 } 930 931 /* 932 * Vnode pointer to File handle 933 */ 934 /* ARGSUSED */ 935 int 936 ext2fs_vptofh(vp, fhp) 937 struct vnode *vp; 938 struct fid *fhp; 939 { 940 register struct inode *ip; 941 register struct ufid *ufhp; 942 943 ip = VTOI(vp); 944 ufhp = (struct ufid *)fhp; 945 ufhp->ufid_len = sizeof(struct ufid); 946 ufhp->ufid_ino = ip->i_number; 947 ufhp->ufid_gen = ip->i_e2fs_gen; 948 return (0); 949 } 950 951 /* 952 * Write a superblock and associated information back to disk. 953 */ 954 int 955 ext2fs_sbupdate(mp, waitfor) 956 struct ufsmount *mp; 957 int waitfor; 958 { 959 register struct m_ext2fs *fs = mp->um_e2fs; 960 register struct buf *bp; 961 int error = 0; 962 963 bp = getblk(mp->um_devvp, SBLOCK, SBSIZE, 0, 0); 964 bcopy((caddr_t)(&fs->e2fs), bp->b_data, SBSIZE); 965 if (waitfor == MNT_WAIT) 966 error = bwrite(bp); 967 else 968 bawrite(bp); 969 return (error); 970 } 971 972 int 973 ext2fs_cgupdate(mp, waitfor) 974 struct ufsmount *mp; 975 int waitfor; 976 { 977 register struct m_ext2fs *fs = mp->um_e2fs; 978 register struct buf *bp; 979 int i, error = 0, allerror = 0; 980 981 allerror = ext2fs_sbupdate(mp, waitfor); 982 for (i = 0; i < fs->e2fs_ngdb; i++) { 983 bp = getblk(mp->um_devvp, fsbtodb(fs, ((fs->e2fs_bsize>1024)?0:1)+i+1), 984 fs->e2fs_bsize, 0, 0); 985 bcopy(&fs->e2fs_gd[i* fs->e2fs_bsize / sizeof(struct ext2_gd)], 986 bp->b_data, fs->e2fs_bsize); 987 if (waitfor == MNT_WAIT) 988 error = bwrite(bp); 989 else 990 bawrite(bp); 991 } 992 993 if (!allerror && error) 994 allerror = error; 995 return (allerror); 996 } 997