1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)ffs_vfsops.c 7.50 (Berkeley) 11/28/90 8 */ 9 10 #include "param.h" 11 #include "systm.h" 12 #include "user.h" 13 #include "proc.h" 14 #include "kernel.h" 15 #include "vnode.h" 16 #include "specdev.h" 17 #include "mount.h" 18 #include "buf.h" 19 #include "file.h" 20 #include "disklabel.h" 21 #include "ioctl.h" 22 #include "errno.h" 23 #include "malloc.h" 24 #include "../ufs/quota.h" 25 #include "../ufs/fs.h" 26 #include "../ufs/ufsmount.h" 27 #include "../ufs/inode.h" 28 29 /* 30 * ufs vfs operations. 31 */ 32 int ufs_mount(); 33 int ufs_start(); 34 int ufs_unmount(); 35 int ufs_root(); 36 int ufs_quotactl(); 37 int ufs_statfs(); 38 int ufs_sync(); 39 int ufs_fhtovp(); 40 int ufs_vptofh(); 41 int ufs_init(); 42 43 struct vfsops ufs_vfsops = { 44 ufs_mount, 45 ufs_start, 46 ufs_unmount, 47 ufs_root, 48 ufs_quotactl, 49 ufs_statfs, 50 ufs_sync, 51 ufs_fhtovp, 52 ufs_vptofh, 53 ufs_init 54 }; 55 56 /* 57 * Called by vfs_mountroot when ufs is going to be mounted as root. 58 * 59 * Name is updated by mount(8) after booting. 60 */ 61 #define ROOTNAME "root_device" 62 63 ufs_mountroot() 64 { 65 register struct mount *mp; 66 extern struct vnode *rootvp; 67 struct ufsmount *ump; 68 register struct fs *fs; 69 u_int size; 70 int error; 71 72 mp = (struct mount *)malloc((u_long)sizeof(struct mount), 73 M_MOUNT, M_WAITOK); 74 mp->mnt_op = &ufs_vfsops; 75 mp->mnt_flag = MNT_RDONLY; 76 mp->mnt_exroot = 0; 77 mp->mnt_mounth = NULLVP; 78 error = mountfs(rootvp, mp); 79 if (error) { 80 free((caddr_t)mp, M_MOUNT); 81 return (error); 82 } 83 if (error = vfs_lock(mp)) { 84 (void)ufs_unmount(mp, 0); 85 free((caddr_t)mp, M_MOUNT); 86 return (error); 87 } 88 rootfs = mp; 89 mp->mnt_next = mp; 90 mp->mnt_prev = mp; 91 mp->mnt_vnodecovered = NULLVP; 92 ump = VFSTOUFS(mp); 93 fs = ump->um_fs; 94 bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); 95 fs->fs_fsmnt[0] = '/'; 96 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 97 MNAMELEN); 98 (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 99 &size); 100 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 101 (void) ufs_statfs(mp, &mp->mnt_stat); 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 register 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 /* 128 * Process export requests. 129 */ 130 if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) { 131 if (args.exflags & MNT_EXPORTED) 132 mp->mnt_flag |= MNT_EXPORTED; 133 else 134 mp->mnt_flag &= ~MNT_EXPORTED; 135 if (args.exflags & MNT_EXRDONLY) 136 mp->mnt_flag |= MNT_EXRDONLY; 137 else 138 mp->mnt_flag &= ~MNT_EXRDONLY; 139 mp->mnt_exroot = args.exroot; 140 } 141 if ((mp->mnt_flag & MNT_UPDATE) == 0) { 142 if ((error = getmdev(&devvp, args.fspec, ndp)) != 0) 143 return (error); 144 error = mountfs(devvp, mp); 145 } else { 146 ump = VFSTOUFS(mp); 147 fs = ump->um_fs; 148 if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 149 fs->fs_ronly = 0; 150 /* 151 * Verify that the specified device is the one that 152 * is really being used for the root file system. 153 */ 154 if (args.fspec == 0) 155 return (0); 156 if ((error = getmdev(&devvp, args.fspec, ndp)) != 0) 157 return (error); 158 if (devvp != ump->um_devvp) 159 error = EINVAL; /* needs translation */ 160 else 161 vrele(devvp); 162 } 163 if (error) { 164 vrele(devvp); 165 return (error); 166 } 167 ump = VFSTOUFS(mp); 168 fs = ump->um_fs; 169 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 170 bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 171 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 172 MNAMELEN); 173 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 174 &size); 175 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 176 (void) ufs_statfs(mp, &mp->mnt_stat); 177 return (0); 178 } 179 180 /* 181 * Common code for mount and mountroot 182 */ 183 mountfs(devvp, mp) 184 register struct vnode *devvp; 185 struct mount *mp; 186 { 187 register struct ufsmount *ump = (struct ufsmount *)0; 188 struct buf *bp = NULL; 189 register struct fs *fs; 190 dev_t dev = devvp->v_rdev; 191 struct partinfo dpart; 192 caddr_t base, space; 193 int havepart = 0, blks; 194 int error, i, size; 195 int needclose = 0; 196 int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 197 extern struct vnode *rootvp; 198 199 /* 200 * Disallow multiple mounts of the same device. 201 * Disallow mounting of a device that is currently in use 202 * (except for root, which might share swap device for miniroot). 203 * Flush out any old buffers remaining from a previous use. 204 */ 205 if (error = mountedon(devvp)) 206 return (error); 207 if (vcount(devvp) > 1 && devvp != rootvp) 208 return (EBUSY); 209 vinvalbuf(devvp, 1); 210 if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED)) 211 return (error); 212 needclose = 1; 213 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED) != 0) { 214 size = DEV_BSIZE; 215 } else { 216 havepart = 1; 217 size = dpart.disklab->d_secsize; 218 } 219 if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) 220 goto out; 221 fs = bp->b_un.b_fs; 222 if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 223 fs->fs_bsize < sizeof(struct fs)) { 224 error = EINVAL; /* XXX needs translation */ 225 goto out; 226 } 227 ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 228 ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK, 229 M_WAITOK); 230 bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs, 231 (u_int)fs->fs_sbsize); 232 if (fs->fs_sbsize < SBSIZE) 233 bp->b_flags |= B_INVAL; 234 brelse(bp); 235 bp = NULL; 236 fs = ump->um_fs; 237 fs->fs_ronly = ronly; 238 if (ronly == 0) 239 fs->fs_fmod = 1; 240 if (havepart) { 241 dpart.part->p_fstype = FS_BSDFFS; 242 dpart.part->p_fsize = fs->fs_fsize; 243 dpart.part->p_frag = fs->fs_frag; 244 dpart.part->p_cpg = fs->fs_cpg; 245 } 246 blks = howmany(fs->fs_cssize, fs->fs_fsize); 247 base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK, 248 M_WAITOK); 249 for (i = 0; i < blks; i += fs->fs_frag) { 250 size = fs->fs_bsize; 251 if (i + fs->fs_frag > blks) 252 size = (blks - i) * fs->fs_fsize; 253 error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 254 NOCRED, &bp); 255 if (error) { 256 free((caddr_t)base, M_SUPERBLK); 257 goto out; 258 } 259 bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size); 260 fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 261 space += size; 262 brelse(bp); 263 bp = NULL; 264 } 265 mp->mnt_data = (qaddr_t)ump; 266 mp->mnt_stat.f_fsid.val[0] = (long)dev; 267 mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS; 268 mp->mnt_flag |= MNT_LOCAL; 269 ump->um_mountp = mp; 270 ump->um_dev = dev; 271 ump->um_devvp = devvp; 272 for (i = 0; i < MAXQUOTAS; i++) 273 ump->um_quotas[i] = NULLVP; 274 devvp->v_specflags |= SI_MOUNTEDON; 275 276 /* Sanity checks for old file systems. XXX */ 277 fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */ 278 fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ 279 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 280 fs->fs_nrpos = 8; /* XXX */ 281 return (0); 282 out: 283 if (bp) 284 brelse(bp); 285 if (needclose) 286 (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); 287 if (ump) { 288 free((caddr_t)ump->um_fs, M_SUPERBLK); 289 free((caddr_t)ump, M_UFSMNT); 290 mp->mnt_data = (qaddr_t)0; 291 } 292 return (error); 293 } 294 295 /* 296 * Make a filesystem operational. 297 * Nothing to do at the moment. 298 */ 299 /* ARGSUSED */ 300 ufs_start(mp, flags) 301 struct mount *mp; 302 int flags; 303 { 304 305 return (0); 306 } 307 308 /* 309 * unmount system call 310 */ 311 ufs_unmount(mp, mntflags) 312 struct mount *mp; 313 int mntflags; 314 { 315 register struct ufsmount *ump; 316 register struct fs *fs; 317 int i, error, ronly, flags = 0; 318 319 if (mntflags & MNT_FORCE) 320 return (EINVAL); 321 if (mntflags & MNT_FORCE) 322 flags |= FORCECLOSE; 323 mntflushbuf(mp, 0); 324 if (mntinvalbuf(mp)) 325 return (EBUSY); 326 ump = VFSTOUFS(mp); 327 #ifdef QUOTA 328 if (mp->mnt_flag & MNT_QUOTA) { 329 if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) 330 return (error); 331 for (i = 0; i < MAXQUOTAS; i++) { 332 if (ump->um_quotas[i] == NULLVP) 333 continue; 334 quotaoff(mp, i); 335 } 336 /* 337 * Here we fall through to vflush again to ensure 338 * that we have gotten rid of all the system vnodes. 339 */ 340 } 341 #endif 342 if (error = vflush(mp, NULLVP, flags)) 343 return (error); 344 fs = ump->um_fs; 345 ronly = !fs->fs_ronly; 346 ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 347 error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); 348 vrele(ump->um_devvp); 349 free((caddr_t)fs->fs_csp[0], M_SUPERBLK); 350 free((caddr_t)fs, M_SUPERBLK); 351 free((caddr_t)ump, M_UFSMNT); 352 mp->mnt_data = (qaddr_t)0; 353 mp->mnt_flag &= ~MNT_LOCAL; 354 return (error); 355 } 356 357 /* 358 * Check to see if a filesystem is mounted on a block device. 359 */ 360 mountedon(vp) 361 register struct vnode *vp; 362 { 363 register struct vnode *vq; 364 365 if (vp->v_specflags & SI_MOUNTEDON) 366 return (EBUSY); 367 if (vp->v_flag & VALIASED) { 368 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 369 if (vq->v_rdev != vp->v_rdev || 370 vq->v_type != vp->v_type) 371 continue; 372 if (vq->v_specflags & SI_MOUNTEDON) 373 return (EBUSY); 374 } 375 } 376 return (0); 377 } 378 379 /* 380 * Return root of a filesystem 381 */ 382 ufs_root(mp, vpp) 383 struct mount *mp; 384 struct vnode **vpp; 385 { 386 register struct inode *ip; 387 struct inode *nip; 388 struct vnode tvp; 389 int error; 390 391 tvp.v_mount = mp; 392 ip = VTOI(&tvp); 393 ip->i_vnode = &tvp; 394 ip->i_dev = VFSTOUFS(mp)->um_dev; 395 error = iget(ip, (ino_t)ROOTINO, &nip); 396 if (error) 397 return (error); 398 *vpp = ITOV(nip); 399 return (0); 400 } 401 402 /* 403 * Do operations associated with quotas 404 */ 405 ufs_quotactl(mp, cmds, uid, arg) 406 struct mount *mp; 407 int cmds; 408 uid_t uid; 409 caddr_t arg; 410 { 411 register struct nameidata *ndp = &u.u_nd; 412 struct ufsmount *ump = VFSTOUFS(mp); 413 struct proc *p = u.u_procp; /* XXX */ 414 int cmd, type, error; 415 416 #ifndef QUOTA 417 return (EOPNOTSUPP); 418 #else 419 if (uid == -1) 420 uid = p->p_ruid; 421 cmd = cmds >> SUBCMDSHIFT; 422 423 switch (cmd) { 424 case Q_GETQUOTA: 425 case Q_SYNC: 426 if (uid == p->p_ruid) 427 break; 428 /* fall through */ 429 default: 430 if (error = suser(ndp->ni_cred, &u.u_acflag)) 431 return (error); 432 } 433 434 type = cmd & SUBCMDMASK; 435 if ((u_int)type >= MAXQUOTAS) 436 return (EINVAL); 437 438 switch (cmd) { 439 440 case Q_QUOTAON: 441 return (quotaon(ndp, mp, type, arg)); 442 443 case Q_QUOTAOFF: 444 if (vfs_busy(mp)) 445 return (0); 446 error = quotaoff(mp, type); 447 vfs_unbusy(mp); 448 return (error); 449 450 case Q_SETQUOTA: 451 return (setquota(mp, uid, type, arg)); 452 453 case Q_SETUSE: 454 return (setuse(mp, uid, type, arg)); 455 456 case Q_GETQUOTA: 457 return (getquota(mp, uid, type, arg)); 458 459 case Q_SYNC: 460 if (vfs_busy(mp)) 461 return (0); 462 error = qsync(mp); 463 vfs_unbusy(mp); 464 return (error); 465 466 default: 467 return (EINVAL); 468 } 469 /* NOTREACHED */ 470 #endif 471 } 472 473 /* 474 * Get file system statistics. 475 */ 476 ufs_statfs(mp, sbp) 477 struct mount *mp; 478 register struct statfs *sbp; 479 { 480 register struct ufsmount *ump; 481 register struct fs *fs; 482 483 ump = VFSTOUFS(mp); 484 fs = ump->um_fs; 485 if (fs->fs_magic != FS_MAGIC) 486 panic("ufs_statfs"); 487 sbp->f_type = MOUNT_UFS; 488 sbp->f_fsize = fs->fs_fsize; 489 sbp->f_bsize = fs->fs_bsize; 490 sbp->f_blocks = fs->fs_dsize; 491 sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 492 fs->fs_cstotal.cs_nffree; 493 sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - 494 (fs->fs_dsize - sbp->f_bfree); 495 sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; 496 sbp->f_ffree = fs->fs_cstotal.cs_nifree; 497 if (sbp != &mp->mnt_stat) { 498 bcopy((caddr_t)mp->mnt_stat.f_mntonname, 499 (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 500 bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 501 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 502 } 503 return (0); 504 } 505 506 int syncprt = 0; 507 508 /* 509 * Go through the disk queues to initiate sandbagged IO; 510 * go through the inodes to write those that have been modified; 511 * initiate the writing of the super block if it has been modified. 512 * 513 * Note: we are always called with the filesystem marked `MPBUSY'. 514 */ 515 ufs_sync(mp, waitfor) 516 struct mount *mp; 517 int waitfor; 518 { 519 register struct vnode *vp; 520 register struct inode *ip; 521 register struct ufsmount *ump = VFSTOUFS(mp); 522 register struct fs *fs; 523 int error, allerror = 0; 524 525 if (syncprt) 526 bufstats(); 527 fs = ump->um_fs; 528 /* 529 * Write back modified superblock. 530 * Consistency check that the superblock 531 * is still in the buffer cache. 532 */ 533 if (fs->fs_fmod != 0) { 534 if (fs->fs_ronly != 0) { /* XXX */ 535 printf("fs = %s\n", fs->fs_fsmnt); 536 panic("update: rofs mod"); 537 } 538 fs->fs_fmod = 0; 539 fs->fs_time = time.tv_sec; 540 allerror = sbupdate(ump, waitfor); 541 } 542 /* 543 * Write back each (modified) inode. 544 */ 545 loop: 546 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 547 /* 548 * If the vnode that we are about to sync is no longer 549 * associated with this mount point, start over. 550 */ 551 if (vp->v_mount != mp) 552 goto loop; 553 ip = VTOI(vp); 554 if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 && 555 vp->v_dirtyblkhd == NULL) 556 continue; 557 if (vget(vp)) 558 goto loop; 559 if (vp->v_dirtyblkhd) 560 vflushbuf(vp, 0); 561 if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) && 562 (error = iupdat(ip, &time, &time, 0))) 563 allerror = error; 564 vput(vp); 565 } 566 /* 567 * Force stale file system control information to be flushed. 568 */ 569 vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0); 570 #ifdef QUOTA 571 qsync(mp); 572 #endif 573 return (allerror); 574 } 575 576 /* 577 * Write a superblock and associated information back to disk. 578 */ 579 sbupdate(mp, waitfor) 580 struct ufsmount *mp; 581 int waitfor; 582 { 583 register struct fs *fs = mp->um_fs; 584 register struct buf *bp; 585 int blks; 586 caddr_t space; 587 int i, size, error = 0; 588 589 bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize); 590 bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 591 /* Restore compatibility to old file systems. XXX */ 592 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 593 bp->b_un.b_fs->fs_nrpos = -1; /* XXX */ 594 if (waitfor == MNT_WAIT) 595 error = bwrite(bp); 596 else 597 bawrite(bp); 598 blks = howmany(fs->fs_cssize, fs->fs_fsize); 599 space = (caddr_t)fs->fs_csp[0]; 600 for (i = 0; i < blks; i += fs->fs_frag) { 601 size = fs->fs_bsize; 602 if (i + fs->fs_frag > blks) 603 size = (blks - i) * fs->fs_fsize; 604 bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size); 605 bcopy(space, bp->b_un.b_addr, (u_int)size); 606 space += size; 607 if (waitfor == MNT_WAIT) 608 error = bwrite(bp); 609 else 610 bawrite(bp); 611 } 612 return (error); 613 } 614 615 /* 616 * Print out statistics on the current allocation of the buffer pool. 617 * Can be enabled to print out on every ``sync'' by setting "syncprt" 618 * above. 619 */ 620 bufstats() 621 { 622 int s, i, j, count; 623 register struct buf *bp, *dp; 624 int counts[MAXBSIZE/CLBYTES+1]; 625 static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; 626 627 for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { 628 count = 0; 629 for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 630 counts[j] = 0; 631 s = splbio(); 632 for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { 633 counts[dp->b_bufsize/CLBYTES]++; 634 count++; 635 } 636 splx(s); 637 printf("%s: total-%d", bname[i], count); 638 for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 639 if (counts[j] != 0) 640 printf(", %d-%d", j * CLBYTES, counts[j]); 641 printf("\n"); 642 } 643 } 644 645 /* 646 * File handle to vnode 647 * 648 * Have to be really careful about stale file handles: 649 * - check that the inode number is in range 650 * - call iget() to get the locked inode 651 * - check for an unallocated inode (i_mode == 0) 652 * - check that the generation number matches 653 */ 654 ufs_fhtovp(mp, fhp, vpp) 655 register struct mount *mp; 656 struct fid *fhp; 657 struct vnode **vpp; 658 { 659 register struct ufid *ufhp; 660 register struct fs *fs; 661 register struct inode *ip; 662 struct inode *nip; 663 struct vnode tvp; 664 int error; 665 666 ufhp = (struct ufid *)fhp; 667 fs = VFSTOUFS(mp)->um_fs; 668 if (ufhp->ufid_ino < ROOTINO || 669 ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) { 670 *vpp = NULLVP; 671 return (EINVAL); 672 } 673 tvp.v_mount = mp; 674 ip = VTOI(&tvp); 675 ip->i_vnode = &tvp; 676 ip->i_dev = VFSTOUFS(mp)->um_dev; 677 if (error = iget(ip, ufhp->ufid_ino, &nip)) { 678 *vpp = NULLVP; 679 return (error); 680 } 681 ip = nip; 682 if (ip->i_mode == 0) { 683 iput(ip); 684 *vpp = NULLVP; 685 return (EINVAL); 686 } 687 if (ip->i_gen != ufhp->ufid_gen) { 688 iput(ip); 689 *vpp = NULLVP; 690 return (EINVAL); 691 } 692 *vpp = ITOV(ip); 693 return (0); 694 } 695 696 /* 697 * Vnode pointer to File handle 698 */ 699 /* ARGSUSED */ 700 ufs_vptofh(vp, fhp) 701 struct vnode *vp; 702 struct fid *fhp; 703 { 704 register struct inode *ip = VTOI(vp); 705 register struct ufid *ufhp; 706 707 ufhp = (struct ufid *)fhp; 708 ufhp->ufid_len = sizeof(struct ufid); 709 ufhp->ufid_ino = ip->i_number; 710 ufhp->ufid_gen = ip->i_gen; 711 return (0); 712 } 713 714 /* 715 * Check that the user's argument is a reasonable 716 * thing on which to mount, and return the device number if so. 717 */ 718 getmdev(devvpp, fname, ndp) 719 struct vnode **devvpp; 720 caddr_t fname; 721 register struct nameidata *ndp; 722 { 723 register struct vnode *vp; 724 int error; 725 726 ndp->ni_nameiop = LOOKUP | FOLLOW; 727 ndp->ni_segflg = UIO_USERSPACE; 728 ndp->ni_dirp = fname; 729 if (error = namei(ndp)) 730 return (error); 731 vp = ndp->ni_vp; 732 if (vp->v_type != VBLK) { 733 vrele(vp); 734 return (ENOTBLK); 735 } 736 if (major(vp->v_rdev) >= nblkdev) { 737 vrele(vp); 738 return (ENXIO); 739 } 740 *devvpp = vp; 741 return (0); 742 } 743