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