1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)lfs_vfsops.c 7.19 (Berkeley) 08/26/89 18 */ 19 20 #include "param.h" 21 #include "systm.h" 22 #include "time.h" 23 #include "kernel.h" 24 #include "namei.h" 25 #include "vnode.h" 26 #include "mount.h" 27 #include "buf.h" 28 #include "ucred.h" 29 #include "file.h" 30 #include "disklabel.h" 31 #include "ioctl.h" 32 #include "errno.h" 33 #include "malloc.h" 34 #include "../ufs/fs.h" 35 #include "../ufs/ufsmount.h" 36 #include "../ufs/inode.h" 37 38 /* 39 * ufs vfs operations. 40 */ 41 int ufs_mount(); 42 int ufs_unmount(); 43 int ufs_root(); 44 int ufs_statfs(); 45 int ufs_sync(); 46 int ufs_fhtovp(); 47 int ufs_vptofh(); 48 49 struct vfsops ufs_vfsops = { 50 ufs_mount, 51 ufs_unmount, 52 ufs_root, 53 ufs_statfs, 54 ufs_sync, 55 ufs_fhtovp, 56 ufs_vptofh 57 }; 58 59 /* 60 * ufs mount table. 61 */ 62 struct ufsmount mounttab[NMOUNT]; 63 64 /* 65 * Called by vfs_mountroot when ufs is going to be mounted as root 66 * 67 * XXX - Need to have a way of figuring the name of the root device 68 */ 69 #define ROOTNAME "root device" 70 71 ufs_mountroot() 72 { 73 register struct mount *mp; 74 extern struct vnode *rootvp; 75 struct ufsmount *ump; 76 register struct fs *fs; 77 u_int size; 78 int error; 79 80 mp = (struct mount *)malloc((u_long)sizeof(struct mount), 81 M_MOUNT, M_WAITOK); 82 mp->m_op = &ufs_vfsops; 83 mp->m_flag = 0; 84 mp->m_exroot = 0; 85 error = mountfs(rootvp, mp); 86 if (error) { 87 free((caddr_t)mp, M_MOUNT); 88 return (error); 89 } 90 error = vfs_add((struct vnode *)0, mp, 0); 91 if (error) { 92 (void)ufs_unmount(mp, 0); 93 free((caddr_t)mp, M_MOUNT); 94 return (error); 95 } 96 ump = VFSTOUFS(mp); 97 fs = ump->um_fs; 98 fs->fs_fsmnt[0] = '/'; 99 bzero(fs->fs_fsmnt + 1, sizeof(fs->fs_fsmnt) - 1); 100 (void) copystr(ROOTNAME, ump->um_mntname, MNAMELEN - 1, &size); 101 bzero(ump->um_mntname + size, MNAMELEN - size); 102 vfs_unlock(mp); 103 inittodr(fs->fs_time); 104 return (0); 105 } 106 107 /* 108 * VFS Operations. 109 * 110 * mount system call 111 */ 112 ufs_mount(mp, path, data, ndp) 113 struct mount *mp; 114 char *path; 115 caddr_t data; 116 struct nameidata *ndp; 117 { 118 struct vnode *devvp; 119 struct ufs_args args; 120 struct ufsmount *ump; 121 register struct fs *fs; 122 u_int size; 123 int error; 124 125 if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) 126 return (error); 127 if ((error = getmdev(&devvp, args.fspec, ndp)) != 0) 128 return (error); 129 error = mountfs(devvp, mp); 130 if (error) { 131 vrele(devvp); 132 return (error); 133 } 134 ump = VFSTOUFS(mp); 135 fs = ump->um_fs; 136 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 137 bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 138 (void) copyinstr(args.fspec, ump->um_mntname, MNAMELEN - 1, &size); 139 bzero(ump->um_mntname + size, MNAMELEN - size); 140 return (0); 141 } 142 143 /* 144 * Common code for mount and mountroot 145 */ 146 mountfs(devvp, mp) 147 struct vnode *devvp; 148 struct mount *mp; 149 { 150 register struct ufsmount *ump; 151 struct ufsmount *fmp = NULL; 152 struct buf *bp = NULL; 153 register struct fs *fs; 154 dev_t dev = devvp->v_rdev; 155 struct partinfo dpart; 156 caddr_t base, space; 157 int havepart = 0, blks; 158 int error, i, size; 159 int needclose = 0; 160 int ronly = (mp->m_flag & M_RDONLY) != 0; 161 162 for (ump = &mounttab[0]; ump < &mounttab[NMOUNT]; ump++) { 163 if (ump->um_fs == NULL) { 164 if (fmp == NULL) 165 fmp = ump; 166 } else if (dev == ump->um_dev) { 167 return (EBUSY); /* needs translation */ 168 } 169 } 170 if ((ump = fmp) == NULL) 171 return (EMFILE); /* needs translation */ 172 ump->um_fs = (struct fs *)1; /* just to reserve this slot */ 173 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); 174 if (error) { 175 ump->um_fs = NULL; 176 return (error); 177 } 178 needclose = 1; 179 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED) != 0) 180 size = DEV_BSIZE; 181 else { 182 havepart = 1; 183 size = dpart.disklab->d_secsize; 184 } 185 if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) { 186 ump->um_fs = NULL; 187 goto out; 188 } 189 fs = bp->b_un.b_fs; 190 if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 191 fs->fs_bsize < sizeof(struct fs)) { 192 ump->um_fs = NULL; 193 error = EINVAL; /* XXX also needs translation */ 194 goto out; 195 } 196 ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK, 197 M_WAITOK); 198 bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs, 199 (u_int)fs->fs_sbsize); 200 brelse(bp); 201 bp = NULL; 202 fs = ump->um_fs; 203 fs->fs_ronly = ronly; 204 if (ronly == 0) 205 fs->fs_fmod = 1; 206 if (havepart) { 207 dpart.part->p_fstype = FS_BSDFFS; 208 dpart.part->p_fsize = fs->fs_fsize; 209 dpart.part->p_frag = fs->fs_frag; 210 dpart.part->p_cpg = fs->fs_cpg; 211 } 212 blks = howmany(fs->fs_cssize, fs->fs_fsize); 213 base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK, 214 M_WAITOK); 215 for (i = 0; i < blks; i += fs->fs_frag) { 216 size = fs->fs_bsize; 217 if (i + fs->fs_frag > blks) 218 size = (blks - i) * fs->fs_fsize; 219 error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 220 NOCRED, &bp); 221 if (error) { 222 free((caddr_t)base, M_SUPERBLK); 223 goto out; 224 } 225 bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size); 226 fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 227 space += size; 228 brelse(bp); 229 bp = NULL; 230 } 231 mp->m_data = (qaddr_t)ump; 232 mp->m_bsize = fs->fs_bsize; 233 mp->m_fsize = fs->fs_fsize; 234 mp->m_fsid.val[0] = (long)dev; 235 mp->m_fsid.val[1] = MOUNT_UFS; 236 ump->um_mountp = mp; 237 ump->um_dev = dev; 238 ump->um_devvp = devvp; 239 ump->um_qinod = NULL; 240 devvp->v_mount = mp; 241 242 /* Sanity checks for old file systems. XXX */ 243 fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */ 244 fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ 245 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 246 fs->fs_nrpos = 8; /* XXX */ 247 return (0); 248 out: 249 if (needclose) 250 (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); 251 if (ump->um_fs) { 252 free((caddr_t)ump->um_fs, M_SUPERBLK); 253 ump->um_fs = NULL; 254 } 255 if (bp) 256 brelse(bp); 257 return (error); 258 } 259 260 261 /* 262 * unmount system call 263 */ 264 ufs_unmount(mp, flags) 265 struct mount *mp; 266 int flags; 267 { 268 register struct ufsmount *ump; 269 register struct fs *fs; 270 dev_t dev; 271 int error, ronly; 272 273 if (flags & MNT_FORCE) 274 return (EINVAL); 275 ump = VFSTOUFS(mp); 276 dev = ump->um_dev; 277 #ifdef QUOTA 278 if (error = iflush(dev, ump->um_qinod)) 279 #else 280 if (error = iflush(dev)) 281 #endif 282 return (error); 283 #ifdef QUOTA 284 (void)closedq(ump); 285 /* 286 * Here we have to iflush again to get rid of the quota inode. 287 * A drag, but it would be ugly to cheat, & this doesn't happen often 288 */ 289 (void)iflush(dev, (struct inode *)NULL); 290 #endif 291 fs = ump->um_fs; 292 ronly = !fs->fs_ronly; 293 free((caddr_t)fs->fs_csp[0], M_SUPERBLK); 294 free((caddr_t)fs, M_SUPERBLK); 295 ump->um_fs = NULL; 296 ump->um_dev = NODEV; 297 error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); 298 ump->um_devvp->v_mount = (struct mount *)0; 299 vrele(ump->um_devvp); 300 ump->um_devvp = (struct vnode *)0; 301 return (error); 302 } 303 304 /* 305 * Return root of a filesystem 306 */ 307 ufs_root(mp, vpp) 308 struct mount *mp; 309 struct vnode **vpp; 310 { 311 struct inode tip, *ip; 312 int error; 313 314 tip.i_dev = VFSTOUFS(mp)->um_dev; 315 tip.i_vnode.v_mount = mp; 316 error = iget(&tip, (ino_t)ROOTINO, &ip); 317 if (error) 318 return (error); 319 *vpp = ITOV(ip); 320 return (0); 321 } 322 323 /* 324 * Get file system statistics. 325 */ 326 ufs_statfs(mp, sbp) 327 struct mount *mp; 328 register struct statfs *sbp; 329 { 330 register struct ufsmount *ump; 331 register struct fs *fs; 332 333 ump = VFSTOUFS(mp); 334 fs = ump->um_fs; 335 if (fs->fs_magic != FS_MAGIC) 336 panic("ufs_statfs"); 337 sbp->f_type = MOUNT_UFS; 338 sbp->f_flags = mp->m_flag &~ (M_MLOCK|M_MWAIT); 339 sbp->f_fsize = fs->fs_fsize; 340 sbp->f_bsize = fs->fs_bsize; 341 sbp->f_blocks = fs->fs_dsize; 342 sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 343 fs->fs_cstotal.cs_nffree; 344 sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - 345 (fs->fs_dsize - sbp->f_bfree); 346 if (sbp->f_bavail < 0) 347 sbp->f_bavail = 0; 348 sbp->f_files = fs->fs_ncg * fs->fs_ipg; 349 sbp->f_ffree = fs->fs_cstotal.cs_nifree; 350 sbp->f_fsid = mp->m_fsid; 351 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 352 bcopy((caddr_t)ump->um_mntname, (caddr_t)&sbp->f_mntfromname[0], 353 MNAMELEN); 354 return (0); 355 } 356 357 int syncprt = 0; 358 359 /* 360 * Go through the disk queues to initiate sandbagged IO; 361 * go through the inodes to write those that have been modified; 362 * initiate the writing of the super block if it has been modified. 363 */ 364 ufs_sync(mp, waitfor) 365 struct mount *mp; 366 int waitfor; 367 { 368 register struct inode *ip; 369 register struct ufsmount *ump = VFSTOUFS(mp); 370 register struct fs *fs; 371 int error = 0; 372 static int updlock = 0; 373 374 if (syncprt) 375 bufstats(); 376 if (updlock) 377 return (EBUSY); 378 fs = ump->um_fs; 379 if (fs == (struct fs *)1) 380 return (0); 381 updlock++; 382 /* 383 * Write back modified superblock. 384 * Consistency check that the superblock 385 * is still in the buffer cache. 386 */ 387 if (fs->fs_fmod != 0) { 388 if (fs->fs_ronly != 0) { /* XXX */ 389 printf("fs = %s\n", fs->fs_fsmnt); 390 panic("update: rofs mod"); 391 } 392 fs->fs_fmod = 0; 393 fs->fs_time = time.tv_sec; 394 error = sbupdate(ump, waitfor); 395 } 396 /* 397 * Write back each (modified) inode. 398 */ 399 for (ip = inode; ip < inodeNINODE; ip++) { 400 if (ip->i_devvp != ump->um_devvp || 401 (ip->i_flag & ILOCKED) != 0 || ITOV(ip)->v_count == 0 || 402 (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0) 403 continue; 404 ILOCK(ip); 405 VREF(ITOV(ip)); 406 error = iupdat(ip, &time, &time, waitfor == MNT_WAIT); 407 iput(ip); 408 } 409 updlock = 0; 410 /* 411 * Force stale buffer cache information to be flushed. 412 */ 413 bflush(ump->um_devvp->v_mount); 414 return (error); 415 } 416 417 /* 418 * Write a superblock and associated information back to disk. 419 */ 420 sbupdate(mp, waitfor) 421 struct ufsmount *mp; 422 int waitfor; 423 { 424 register struct fs *fs = mp->um_fs; 425 register struct buf *bp; 426 int blks; 427 caddr_t space; 428 int i, size, error = 0; 429 430 bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize); 431 bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 432 /* Restore compatibility to old file systems. XXX */ 433 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 434 bp->b_un.b_fs->fs_nrpos = -1; /* XXX */ 435 if (waitfor == MNT_WAIT) 436 error = bwrite(bp); 437 else 438 bawrite(bp); 439 blks = howmany(fs->fs_cssize, fs->fs_fsize); 440 space = (caddr_t)fs->fs_csp[0]; 441 for (i = 0; i < blks; i += fs->fs_frag) { 442 size = fs->fs_bsize; 443 if (i + fs->fs_frag > blks) 444 size = (blks - i) * fs->fs_fsize; 445 bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size); 446 bcopy(space, bp->b_un.b_addr, (u_int)size); 447 space += size; 448 if (waitfor == MNT_WAIT) 449 error = bwrite(bp); 450 else 451 bawrite(bp); 452 } 453 return (error); 454 } 455 456 /* 457 * Print out statistics on the current allocation of the buffer pool. 458 * Can be enabled to print out on every ``sync'' by setting "syncprt" 459 * above. 460 */ 461 bufstats() 462 { 463 int s, i, j, count; 464 register struct buf *bp, *dp; 465 int counts[MAXBSIZE/CLBYTES+1]; 466 static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; 467 468 for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { 469 count = 0; 470 for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 471 counts[j] = 0; 472 s = splbio(); 473 for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { 474 counts[dp->b_bufsize/CLBYTES]++; 475 count++; 476 } 477 splx(s); 478 printf("%s: total-%d", bname[i], count); 479 for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 480 if (counts[j] != 0) 481 printf(", %d-%d", j * CLBYTES, counts[j]); 482 printf("\n"); 483 } 484 } 485 486 /* 487 * File handle to vnode 488 * 489 * Have to be really careful about stale file handles: 490 * - check that the inode number is in range 491 * - call iget() to get the locked inode 492 * - check for an unallocated inode (i_mode == 0) 493 * - check that the generation number matches 494 */ 495 ufs_fhtovp(mp, fhp, vpp) 496 register struct mount *mp; 497 struct fid *fhp; 498 struct vnode **vpp; 499 { 500 register struct ufid *ufhp; 501 register struct fs *fs; 502 struct inode tip, *ip; 503 int error; 504 505 ufhp = (struct ufid *)fhp; 506 fs = VFSTOUFS(mp)->um_fs; 507 if (ufhp->ufid_ino < ROOTINO || 508 ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) { 509 *vpp = (struct vnode *)0; 510 return (EINVAL); 511 } 512 tip.i_dev = VFSTOUFS(mp)->um_dev; 513 tip.i_vnode.v_mount = mp; 514 if (error = iget(&tip, ufhp->ufid_ino, &ip)) { 515 *vpp = (struct vnode *)0; 516 return (error); 517 } 518 if (ip->i_mode == 0) { 519 iput(ip); 520 *vpp = (struct vnode *)0; 521 return (EINVAL); 522 } 523 if (ip->i_gen != ufhp->ufid_gen) { 524 iput(ip); 525 *vpp = (struct vnode *)0; 526 return (EINVAL); 527 } 528 *vpp = ITOV(ip); 529 return (0); 530 } 531 532 /* 533 * Vnode pointer to File handle 534 */ 535 /* ARGSUSED */ 536 ufs_vptofh(vp, fhp) 537 struct vnode *vp; 538 struct fid *fhp; 539 { 540 register struct inode *ip = VTOI(vp); 541 register struct ufid *ufhp; 542 543 ufhp = (struct ufid *)fhp; 544 ufhp->ufid_len = sizeof(struct ufid); 545 ufhp->ufid_ino = ip->i_number; 546 ufhp->ufid_gen = ip->i_gen; 547 return (0); 548 } 549 550 /* 551 * Common code for mount and quota. 552 * Check that the user's argument is a reasonable 553 * thing on which to mount, and return the device number if so. 554 */ 555 getmdev(devvpp, fname, ndp) 556 struct vnode **devvpp; 557 caddr_t fname; 558 register struct nameidata *ndp; 559 { 560 register struct vnode *vp; 561 int error; 562 563 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 564 ndp->ni_segflg = UIO_USERSPACE; 565 ndp->ni_dirp = fname; 566 if (error = namei(ndp)) { 567 if (error == ENOENT) 568 return (ENODEV); /* needs translation */ 569 return (error); 570 } 571 vp = ndp->ni_vp; 572 if (vp->v_type != VBLK) { 573 vput(vp); 574 return (ENOTBLK); 575 } 576 if (major(vp->v_rdev) >= nblkdev) 577 return (ENXIO); 578 iunlock(VTOI(vp)); 579 *devvpp = vp; 580 return (0); 581 } 582