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.13 (Berkeley) 05/09/89 18 */ 19 20 21 #include "param.h" 22 #include "systm.h" 23 #include "time.h" 24 #include "kernel.h" 25 #include "namei.h" 26 #include "vnode.h" 27 #include "mount.h" 28 #include "buf.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, 174 (struct ucred *)0); 175 if (error) { 176 ump->um_fs = NULL; 177 return (error); 178 } 179 needclose = 1; 180 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, 181 (struct ucred *)0) != 0) 182 size = DEV_BSIZE; 183 else { 184 havepart = 1; 185 size = dpart.disklab->d_secsize; 186 } 187 if (error = bread(devvp, SBLOCK, SBSIZE, &bp)) { 188 ump->um_fs = NULL; 189 goto out; 190 } 191 fs = bp->b_un.b_fs; 192 if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 193 fs->fs_bsize < sizeof(struct fs)) { 194 ump->um_fs = NULL; 195 error = EINVAL; /* XXX also needs translation */ 196 goto out; 197 } 198 ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK, 199 M_WAITOK); 200 bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs, 201 (u_int)fs->fs_sbsize); 202 brelse(bp); 203 bp = NULL; 204 fs = ump->um_fs; 205 fs->fs_ronly = ronly; 206 if (ronly == 0) 207 fs->fs_fmod = 1; 208 if (havepart) { 209 dpart.part->p_fstype = FS_BSDFFS; 210 dpart.part->p_fsize = fs->fs_fsize; 211 dpart.part->p_frag = fs->fs_frag; 212 dpart.part->p_cpg = fs->fs_cpg; 213 } 214 blks = howmany(fs->fs_cssize, fs->fs_fsize); 215 base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK, 216 M_WAITOK); 217 for (i = 0; i < blks; i += fs->fs_frag) { 218 size = fs->fs_bsize; 219 if (i + fs->fs_frag > blks) 220 size = (blks - i) * fs->fs_fsize; 221 error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, &bp); 222 if (error) { 223 free((caddr_t)base, M_SUPERBLK); 224 goto out; 225 } 226 bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size); 227 fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 228 space += size; 229 brelse(bp); 230 bp = NULL; 231 } 232 mp->m_data = (qaddr_t)ump; 233 mp->m_bsize = fs->fs_bsize; 234 mp->m_fsize = fs->fs_fsize; 235 mp->m_fsid.val[0] = (long)dev; 236 mp->m_fsid.val[1] = MOUNT_UFS; 237 ump->um_mountp = mp; 238 ump->um_dev = dev; 239 ump->um_devvp = devvp; 240 ump->um_qinod = NULL; 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, 251 (struct ucred *)0); 252 if (ump->um_fs) { 253 free((caddr_t)ump->um_fs, M_SUPERBLK); 254 ump->um_fs = NULL; 255 } 256 if (bp) 257 brelse(bp); 258 return (error); 259 } 260 261 262 /* 263 * unmount system call 264 */ 265 ufs_unmount(mp, flags) 266 struct mount *mp; 267 int flags; 268 { 269 register struct ufsmount *ump; 270 register struct fs *fs; 271 dev_t dev; 272 int error, ronly; 273 274 if (flags & MNT_FORCE) 275 return (EINVAL); 276 ump = VFSTOUFS(mp); 277 dev = ump->um_dev; 278 #ifdef QUOTA 279 if (error = iflush(dev, ump->um_qinod)) 280 #else 281 if (error = iflush(dev)) 282 #endif 283 return (error); 284 #ifdef QUOTA 285 (void)closedq(ump); 286 /* 287 * Here we have to iflush again to get rid of the quota inode. 288 * A drag, but it would be ugly to cheat, & this doesn't happen often 289 */ 290 (void)iflush(dev, (struct inode *)NULL); 291 #endif 292 fs = ump->um_fs; 293 ronly = !fs->fs_ronly; 294 free((caddr_t)fs->fs_csp[0], M_SUPERBLK); 295 free((caddr_t)fs, M_SUPERBLK); 296 ump->um_fs = NULL; 297 ump->um_dev = NODEV; 298 error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, 299 (struct ucred *)0); 300 vrele(ump->um_devvp); 301 ump->um_devvp = (struct vnode *)0; 302 return (error); 303 } 304 305 /* 306 * Return root of a filesystem 307 */ 308 ufs_root(mp, vpp) 309 struct mount *mp; 310 struct vnode **vpp; 311 { 312 struct inode tip, *ip; 313 int error; 314 315 tip.i_dev = VFSTOUFS(mp)->um_dev; 316 tip.i_vnode.v_mount = mp; 317 error = iget(&tip, (ino_t)ROOTINO, &ip); 318 if (error) 319 return (error); 320 *vpp = ITOV(ip); 321 return (0); 322 } 323 324 /* 325 * Get file system statistics. 326 */ 327 ufs_statfs(mp, sbp) 328 struct mount *mp; 329 register struct statfs *sbp; 330 { 331 register struct ufsmount *ump; 332 register struct fs *fs; 333 334 ump = VFSTOUFS(mp); 335 fs = ump->um_fs; 336 if (fs->fs_magic != FS_MAGIC) 337 panic("ufs_statfs"); 338 sbp->f_type = MOUNT_UFS; 339 sbp->f_flags = mp->m_flag &~ (M_MLOCK|M_MWAIT); 340 sbp->f_fsize = fs->fs_fsize; 341 sbp->f_bsize = fs->fs_bsize; 342 sbp->f_blocks = fs->fs_dsize; 343 sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 344 fs->fs_cstotal.cs_nffree; 345 sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - 346 (fs->fs_dsize - sbp->f_bfree); 347 if (sbp->f_bavail < 0) 348 sbp->f_bavail = 0; 349 sbp->f_files = fs->fs_ncg * fs->fs_ipg; 350 sbp->f_ffree = fs->fs_cstotal.cs_nifree; 351 sbp->f_fsid = mp->m_fsid; 352 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 353 bcopy((caddr_t)ump->um_mntname, (caddr_t)&sbp->f_mntfromname[0], 354 MNAMELEN); 355 return (0); 356 } 357 358 int syncprt = 0; 359 360 /* 361 * Go through the disk queues to initiate sandbagged IO; 362 * go through the inodes to write those that have been modified; 363 * initiate the writing of the super block if it has been modified. 364 */ 365 ufs_sync(mp, waitfor) 366 struct mount *mp; 367 int waitfor; 368 { 369 register struct inode *ip; 370 register struct ufsmount *ump = VFSTOUFS(mp); 371 register struct fs *fs; 372 int error = 0; 373 static int updlock = 0; 374 375 if (syncprt) 376 bufstats(); 377 if (updlock) 378 return (EBUSY); 379 fs = ump->um_fs; 380 if (fs == (struct fs *)1) 381 return (0); 382 updlock++; 383 /* 384 * Write back modified superblock. 385 * Consistency check that the superblock 386 * is still in the buffer cache. 387 */ 388 if (fs->fs_fmod != 0) { 389 if (fs->fs_ronly != 0) { /* XXX */ 390 printf("fs = %s\n", fs->fs_fsmnt); 391 panic("update: rofs mod"); 392 } 393 fs->fs_fmod = 0; 394 fs->fs_time = time.tv_sec; 395 error = sbupdate(ump, waitfor); 396 } 397 /* 398 * Write back each (modified) inode. 399 */ 400 for (ip = inode; ip < inodeNINODE; ip++) { 401 if (ip->i_devvp != ump->um_devvp || 402 (ip->i_flag & ILOCKED) != 0 || ITOV(ip)->v_count == 0 || 403 (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0) 404 continue; 405 ip->i_flag |= ILOCKED; 406 ITOV(ip)->v_count++; 407 error = iupdat(ip, &time, &time, waitfor == MNT_WAIT); 408 iput(ip); 409 } 410 updlock = 0; 411 /* 412 * Force stale buffer cache information to be flushed. 413 */ 414 bflush(ump->um_devvp->v_rdev); 415 return (error); 416 } 417 418 /* 419 * Write a superblock and associated information back to disk. 420 */ 421 sbupdate(mp, waitfor) 422 struct ufsmount *mp; 423 int waitfor; 424 { 425 register struct fs *fs = mp->um_fs; 426 register struct buf *bp; 427 int blks; 428 caddr_t space; 429 int i, size, error = 0; 430 431 bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize); 432 bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 433 /* Restore compatibility to old file systems. XXX */ 434 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 435 bp->b_un.b_fs->fs_nrpos = -1; /* XXX */ 436 if (waitfor == MNT_WAIT) 437 error = bwrite(bp); 438 else 439 bawrite(bp); 440 blks = howmany(fs->fs_cssize, fs->fs_fsize); 441 space = (caddr_t)fs->fs_csp[0]; 442 for (i = 0; i < blks; i += fs->fs_frag) { 443 size = fs->fs_bsize; 444 if (i + fs->fs_frag > blks) 445 size = (blks - i) * fs->fs_fsize; 446 bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size); 447 bcopy(space, bp->b_un.b_addr, (u_int)size); 448 space += size; 449 if (waitfor == MNT_WAIT) 450 error = bwrite(bp); 451 else 452 bawrite(bp); 453 } 454 return (error); 455 } 456 457 /* 458 * Print out statistics on the current allocation of the buffer pool. 459 * Can be enabled to print out on every ``sync'' by setting "syncprt" 460 * above. 461 */ 462 bufstats() 463 { 464 int s, i, j, count; 465 register struct buf *bp, *dp; 466 int counts[MAXBSIZE/CLBYTES+1]; 467 static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; 468 469 for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { 470 count = 0; 471 for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 472 counts[j] = 0; 473 s = splbio(); 474 for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { 475 counts[dp->b_bufsize/CLBYTES]++; 476 count++; 477 } 478 splx(s); 479 printf("%s: total-%d", bname[i], count); 480 for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 481 if (counts[j] != 0) 482 printf(", %d-%d", j * CLBYTES, counts[j]); 483 printf("\n"); 484 } 485 } 486 487 /* 488 * File handle to vnode 489 */ 490 ufs_fhtovp(mp, fhp, vpp) 491 struct mount *mp; 492 struct fid *fhp; 493 struct vnode **vpp; 494 { 495 register struct ufid *ufhp; 496 struct inode tip, *ip; 497 int error; 498 499 ufhp = (struct ufid *)fhp; 500 tip.i_dev = VFSTOUFS(mp)->um_dev; 501 tip.i_vnode.v_mount = mp; 502 if (error = iget(&tip, ufhp->ufid_ino, &ip)) { 503 *vpp = NULL; 504 return (error); 505 } 506 if (ip->i_gen != ufhp->ufid_gen) { 507 iput(ip); 508 *vpp = NULL; 509 return (EINVAL); 510 } 511 *vpp = ITOV(ip); 512 return (0); 513 } 514 515 /* 516 * Vnode pointer to File handle, should never happen. 517 */ 518 /* ARGSUSED */ 519 ufs_vptofh(mp, fhp, vpp) 520 struct mount *mp; 521 struct fid *fhp; 522 struct vnode **vpp; 523 { 524 525 return (EINVAL); 526 } 527 528 /* 529 * Common code for mount and quota. 530 * Check that the user's argument is a reasonable 531 * thing on which to mount, and return the device number if so. 532 */ 533 getmdev(devvpp, fname, ndp) 534 struct vnode **devvpp; 535 caddr_t fname; 536 register struct nameidata *ndp; 537 { 538 register struct vnode *vp; 539 int error; 540 541 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 542 ndp->ni_segflg = UIO_USERSPACE; 543 ndp->ni_dirp = fname; 544 if (error = namei(ndp)) { 545 if (error == ENOENT) 546 return (ENODEV); /* needs translation */ 547 return (error); 548 } 549 vp = ndp->ni_vp; 550 if (vp->v_type != VBLK) { 551 vput(vp); 552 return (ENOTBLK); 553 } 554 if (major(vp->v_rdev) >= nblkdev) 555 return (ENXIO); 556 iunlock(VTOI(vp)); 557 *devvpp = vp; 558 return (0); 559 } 560