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.51 (Berkeley) 03/19/91 8 */ 9 10 #include "param.h" 11 #include "systm.h" 12 #include "namei.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 25 #include "quota.h" 26 #include "fs.h" 27 #include "ufsmount.h" 28 #include "inode.h" 29 30 /* 31 * ufs vfs operations. 32 */ 33 int ufs_mount(); 34 int ufs_start(); 35 int ufs_unmount(); 36 int ufs_root(); 37 int ufs_quotactl(); 38 int ufs_statfs(); 39 int ufs_sync(); 40 int ufs_fhtovp(); 41 int ufs_vptofh(); 42 int ufs_init(); 43 44 struct vfsops ufs_vfsops = { 45 ufs_mount, 46 ufs_start, 47 ufs_unmount, 48 ufs_root, 49 ufs_quotactl, 50 ufs_statfs, 51 ufs_sync, 52 ufs_fhtovp, 53 ufs_vptofh, 54 ufs_init 55 }; 56 57 /* 58 * Called by vfs_mountroot when ufs is going to be mounted as root. 59 * 60 * Name is updated by mount(8) after booting. 61 */ 62 #define ROOTNAME "root_device" 63 64 ufs_mountroot() 65 { 66 register struct mount *mp; 67 extern struct vnode *rootvp; 68 struct ufsmount *ump; 69 register struct fs *fs; 70 u_int size; 71 int error; 72 73 mp = (struct mount *)malloc((u_long)sizeof(struct mount), 74 M_MOUNT, M_WAITOK); 75 mp->mnt_op = &ufs_vfsops; 76 mp->mnt_flag = MNT_RDONLY; 77 mp->mnt_exroot = 0; 78 mp->mnt_mounth = NULLVP; 79 error = mountfs(rootvp, mp); 80 if (error) { 81 free((caddr_t)mp, M_MOUNT); 82 return (error); 83 } 84 if (error = vfs_lock(mp)) { 85 (void)ufs_unmount(mp, 0); 86 free((caddr_t)mp, M_MOUNT); 87 return (error); 88 } 89 rootfs = mp; 90 mp->mnt_next = mp; 91 mp->mnt_prev = mp; 92 mp->mnt_vnodecovered = NULLVP; 93 ump = VFSTOUFS(mp); 94 fs = ump->um_fs; 95 bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); 96 fs->fs_fsmnt[0] = '/'; 97 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 98 MNAMELEN); 99 (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 100 &size); 101 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 102 (void) ufs_statfs(mp, &mp->mnt_stat); 103 vfs_unlock(mp); 104 inittodr(fs->fs_time); 105 return (0); 106 } 107 108 /* 109 * VFS Operations. 110 * 111 * mount system call 112 */ 113 ufs_mount(mp, path, data, ndp) 114 register struct mount *mp; 115 char *path; 116 caddr_t data; 117 struct nameidata *ndp; 118 { 119 struct vnode *devvp; 120 struct ufs_args args; 121 struct ufsmount *ump; 122 register struct fs *fs; 123 u_int size; 124 int error; 125 126 if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) 127 return (error); 128 /* 129 * Process export requests. 130 */ 131 if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) { 132 if (args.exflags & MNT_EXPORTED) 133 mp->mnt_flag |= MNT_EXPORTED; 134 else 135 mp->mnt_flag &= ~MNT_EXPORTED; 136 if (args.exflags & MNT_EXRDONLY) 137 mp->mnt_flag |= MNT_EXRDONLY; 138 else 139 mp->mnt_flag &= ~MNT_EXRDONLY; 140 mp->mnt_exroot = args.exroot; 141 } 142 if ((mp->mnt_flag & MNT_UPDATE) == 0) { 143 if ((error = getmdev(&devvp, args.fspec, ndp)) != 0) 144 return (error); 145 error = mountfs(devvp, mp); 146 } else { 147 ump = VFSTOUFS(mp); 148 fs = ump->um_fs; 149 if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 150 fs->fs_ronly = 0; 151 /* 152 * Verify that the specified device is the one that 153 * is really being used for the root file system. 154 */ 155 if (args.fspec == 0) 156 return (0); 157 if ((error = getmdev(&devvp, args.fspec, ndp)) != 0) 158 return (error); 159 if (devvp != ump->um_devvp) 160 error = EINVAL; /* needs translation */ 161 else 162 vrele(devvp); 163 } 164 if (error) { 165 vrele(devvp); 166 return (error); 167 } 168 ump = VFSTOUFS(mp); 169 fs = ump->um_fs; 170 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 171 bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 172 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 173 MNAMELEN); 174 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 175 &size); 176 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 177 (void) ufs_statfs(mp, &mp->mnt_stat); 178 return (0); 179 } 180 181 /* 182 * Common code for mount and mountroot 183 */ 184 mountfs(devvp, mp) 185 register struct vnode *devvp; 186 struct mount *mp; 187 { 188 register struct ufsmount *ump = (struct ufsmount *)0; 189 struct buf *bp = NULL; 190 register struct fs *fs; 191 dev_t dev = devvp->v_rdev; 192 struct partinfo dpart; 193 caddr_t base, space; 194 int havepart = 0, blks; 195 int error, i, size; 196 int needclose = 0; 197 int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 198 extern struct vnode *rootvp; 199 200 /* 201 * Disallow multiple mounts of the same device. 202 * Disallow mounting of a device that is currently in use 203 * (except for root, which might share swap device for miniroot). 204 * Flush out any old buffers remaining from a previous use. 205 */ 206 if (error = mountedon(devvp)) 207 return (error); 208 if (vcount(devvp) > 1 && devvp != rootvp) 209 return (EBUSY); 210 vinvalbuf(devvp, 1); 211 if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED)) 212 return (error); 213 needclose = 1; 214 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED) != 0) { 215 size = DEV_BSIZE; 216 } else { 217 havepart = 1; 218 size = dpart.disklab->d_secsize; 219 } 220 if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) 221 goto out; 222 fs = bp->b_un.b_fs; 223 if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 224 fs->fs_bsize < sizeof(struct fs)) { 225 error = EINVAL; /* XXX needs translation */ 226 goto out; 227 } 228 ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 229 ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK, 230 M_WAITOK); 231 bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs, 232 (u_int)fs->fs_sbsize); 233 if (fs->fs_sbsize < SBSIZE) 234 bp->b_flags |= B_INVAL; 235 brelse(bp); 236 bp = NULL; 237 fs = ump->um_fs; 238 fs->fs_ronly = ronly; 239 if (ronly == 0) 240 fs->fs_fmod = 1; 241 if (havepart) { 242 dpart.part->p_fstype = FS_BSDFFS; 243 dpart.part->p_fsize = fs->fs_fsize; 244 dpart.part->p_frag = fs->fs_frag; 245 dpart.part->p_cpg = fs->fs_cpg; 246 } 247 blks = howmany(fs->fs_cssize, fs->fs_fsize); 248 base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK, 249 M_WAITOK); 250 for (i = 0; i < blks; i += fs->fs_frag) { 251 size = fs->fs_bsize; 252 if (i + fs->fs_frag > blks) 253 size = (blks - i) * fs->fs_fsize; 254 error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 255 NOCRED, &bp); 256 if (error) { 257 free((caddr_t)base, M_SUPERBLK); 258 goto out; 259 } 260 bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size); 261 fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 262 space += size; 263 brelse(bp); 264 bp = NULL; 265 } 266 mp->mnt_data = (qaddr_t)ump; 267 mp->mnt_stat.f_fsid.val[0] = (long)dev; 268 mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS; 269 mp->mnt_flag |= MNT_LOCAL; 270 ump->um_mountp = mp; 271 ump->um_dev = dev; 272 ump->um_devvp = devvp; 273 for (i = 0; i < MAXQUOTAS; i++) 274 ump->um_quotas[i] = NULLVP; 275 devvp->v_specflags |= SI_MOUNTEDON; 276 277 /* Sanity checks for old file systems. XXX */ 278 fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */ 279 fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ 280 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 281 fs->fs_nrpos = 8; /* XXX */ 282 return (0); 283 out: 284 if (bp) 285 brelse(bp); 286 if (needclose) 287 (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); 288 if (ump) { 289 free((caddr_t)ump->um_fs, M_SUPERBLK); 290 free((caddr_t)ump, M_UFSMNT); 291 mp->mnt_data = (qaddr_t)0; 292 } 293 return (error); 294 } 295 296 /* 297 * Make a filesystem operational. 298 * Nothing to do at the moment. 299 */ 300 /* ARGSUSED */ 301 ufs_start(mp, flags) 302 struct mount *mp; 303 int flags; 304 { 305 306 return (0); 307 } 308 309 /* 310 * unmount system call 311 */ 312 ufs_unmount(mp, mntflags) 313 struct mount *mp; 314 int mntflags; 315 { 316 register struct ufsmount *ump; 317 register struct fs *fs; 318 int i, error, ronly, flags = 0; 319 320 if (mntflags & MNT_FORCE) 321 return (EINVAL); 322 if (mntflags & MNT_FORCE) 323 flags |= FORCECLOSE; 324 mntflushbuf(mp, 0); 325 if (mntinvalbuf(mp)) 326 return (EBUSY); 327 ump = VFSTOUFS(mp); 328 #ifdef QUOTA 329 if (mp->mnt_flag & MNT_QUOTA) { 330 if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) 331 return (error); 332 for (i = 0; i < MAXQUOTAS; i++) { 333 if (ump->um_quotas[i] == NULLVP) 334 continue; 335 quotaoff(mp, i); 336 } 337 /* 338 * Here we fall through to vflush again to ensure 339 * that we have gotten rid of all the system vnodes. 340 */ 341 } 342 #endif 343 if (error = vflush(mp, NULLVP, flags)) 344 return (error); 345 fs = ump->um_fs; 346 ronly = !fs->fs_ronly; 347 ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 348 error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); 349 vrele(ump->um_devvp); 350 free((caddr_t)fs->fs_csp[0], M_SUPERBLK); 351 free((caddr_t)fs, M_SUPERBLK); 352 free((caddr_t)ump, M_UFSMNT); 353 mp->mnt_data = (qaddr_t)0; 354 mp->mnt_flag &= ~MNT_LOCAL; 355 return (error); 356 } 357 358 /* 359 * Check to see if a filesystem is mounted on a block device. 360 */ 361 mountedon(vp) 362 register struct vnode *vp; 363 { 364 register struct vnode *vq; 365 366 if (vp->v_specflags & SI_MOUNTEDON) 367 return (EBUSY); 368 if (vp->v_flag & VALIASED) { 369 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 370 if (vq->v_rdev != vp->v_rdev || 371 vq->v_type != vp->v_type) 372 continue; 373 if (vq->v_specflags & SI_MOUNTEDON) 374 return (EBUSY); 375 } 376 } 377 return (0); 378 } 379 380 /* 381 * Return root of a filesystem 382 */ 383 ufs_root(mp, vpp) 384 struct mount *mp; 385 struct vnode **vpp; 386 { 387 register struct inode *ip; 388 struct inode *nip; 389 struct vnode tvp; 390 int error; 391 392 tvp.v_mount = mp; 393 ip = VTOI(&tvp); 394 ip->i_vnode = &tvp; 395 ip->i_dev = VFSTOUFS(mp)->um_dev; 396 error = iget(ip, (ino_t)ROOTINO, &nip); 397 if (error) 398 return (error); 399 *vpp = ITOV(nip); 400 return (0); 401 } 402 403 /* 404 * Do operations associated with quotas 405 */ 406 ufs_quotactl(mp, cmds, uid, arg) 407 struct mount *mp; 408 int cmds; 409 uid_t uid; 410 caddr_t arg; 411 { 412 struct ufsmount *ump = VFSTOUFS(mp); 413 struct proc *p = curproc; /* XXX */ 414 int cmd, type, error; 415 416 #ifndef QUOTA 417 return (EOPNOTSUPP); 418 #else 419 if (uid == -1) 420 uid = p->p_cred->p_ruid; 421 cmd = cmds >> SUBCMDSHIFT; 422 423 switch (cmd) { 424 case Q_GETQUOTA: 425 case Q_SYNC: 426 if (uid == p->p_cred->p_ruid) 427 break; 428 /* fall through */ 429 default: 430 if (error = suser(p->p_ucred, &p->p_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(p, 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, curproc)) /* XXX */ 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