1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)nfs_vfsops.c 7.44 (Berkeley) 07/12/92 11 */ 12 13 #include "param.h" 14 #include "conf.h" 15 #include "ioctl.h" 16 #include "signal.h" 17 #include "proc.h" 18 #include "namei.h" 19 #include "vnode.h" 20 #include "kernel.h" 21 #include "mount.h" 22 #include "buf.h" 23 #include "mbuf.h" 24 #include "socket.h" 25 #include "systm.h" 26 27 #include "net/if.h" 28 #include "net/route.h" 29 #include "netinet/in.h" 30 31 #include "rpcv2.h" 32 #include "nfsv2.h" 33 #include "nfsnode.h" 34 #include "nfsmount.h" 35 #include "nfs.h" 36 #include "xdr_subs.h" 37 #include "nfsm_subs.h" 38 #include "nfsdiskless.h" 39 #include "nqnfs.h" 40 41 /* 42 * nfs vfs operations. 43 */ 44 struct vfsops nfs_vfsops = { 45 nfs_mount, 46 nfs_start, 47 nfs_unmount, 48 nfs_root, 49 nfs_quotactl, 50 nfs_statfs, 51 nfs_sync, 52 nfs_vget, 53 nfs_fhtovp, 54 nfs_vptofh, 55 nfs_init, 56 }; 57 58 /* 59 * This structure must be filled in by a primary bootstrap or bootstrap 60 * server for a diskless/dataless machine. It is initialized below just 61 * to ensure that it is allocated to initialized data (.data not .bss). 62 */ 63 struct nfs_diskless nfs_diskless = { 0 }; 64 65 static u_char nfs_mntid; 66 extern u_long nfs_procids[NFS_NPROCS]; 67 extern u_long nfs_prog, nfs_vers; 68 void nfs_disconnect __P((struct nfsmount *)); 69 void nfsargs_ntoh __P((struct nfs_args *)); 70 static struct mount *nfs_mountdiskless __P((char *, char *, int, 71 struct sockaddr_in *, struct nfs_args *, register struct vnode **)); 72 73 #define TRUE 1 74 #define FALSE 0 75 76 /* 77 * nfs statfs call 78 */ 79 int 80 nfs_statfs(mp, sbp, p) 81 struct mount *mp; 82 register struct statfs *sbp; 83 struct proc *p; 84 { 85 register struct vnode *vp; 86 register struct nfsv2_statfs *sfp; 87 register caddr_t cp; 88 register long t1; 89 caddr_t bpos, dpos, cp2; 90 int error = 0; 91 struct mbuf *mreq, *mrep, *md, *mb, *mb2; 92 struct nfsmount *nmp; 93 struct ucred *cred; 94 struct nfsnode *np; 95 96 nmp = VFSTONFS(mp); 97 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 98 return (error); 99 vp = NFSTOV(np); 100 nfsstats.rpccnt[NFSPROC_STATFS]++; 101 cred = crget(); 102 cred->cr_ngroups = 1; 103 nfsm_reqhead(vp, NFSPROC_STATFS, NFSX_FH); 104 nfsm_fhtom(vp); 105 nfsm_request(vp, NFSPROC_STATFS, p, cred); 106 nfsm_dissect(sfp, struct nfsv2_statfs *, NFSX_STATFS); 107 sbp->f_type = MOUNT_NFS; 108 sbp->f_flags = nmp->nm_flag; 109 sbp->f_iosize = NFS_MAXDGRAMDATA; 110 sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize); 111 sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks); 112 sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree); 113 sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail); 114 sbp->f_files = 0; 115 sbp->f_ffree = 0; 116 if (sbp != &mp->mnt_stat) { 117 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 118 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 119 } 120 nfsm_reqdone; 121 vrele(vp); 122 crfree(cred); 123 return (error); 124 } 125 126 /* 127 * Mount a remote root fs via. nfs. This depends on the info in the 128 * nfs_diskless structure that has been filled in properly by some primary 129 * bootstrap. 130 * It goes something like this: 131 * - do enough of "ifconfig" by calling ifioctl() so that the system 132 * can talk to the server 133 * - If nfs_diskless.mygateway is filled in, use that address as 134 * a default gateway. 135 * - hand craft the swap nfs vnode hanging off a fake mount point 136 * if swdevt[0].sw_dev == NODEV 137 * - build the rootfs mount point and call mountnfs() to do the rest. 138 */ 139 int 140 nfs_mountroot() 141 { 142 register struct mount *mp; 143 register struct nfs_diskless *nd = &nfs_diskless; 144 struct socket *so; 145 struct vnode *vp; 146 struct proc *p = curproc; /* XXX */ 147 int error, i; 148 149 /* 150 * XXX time must be non-zero when we init the interface or else 151 * the arp code will wedge... 152 */ 153 if (time.tv_sec == 0) 154 time.tv_sec = 1; 155 156 #ifdef notyet 157 /* Set up swap credentials. */ 158 *proc0.p_ucred = nfs_diskless.swap_ucred; 159 #endif 160 161 /* 162 * Do enough of ifconfig(8) so that the critical net interface can 163 * talk to the server. 164 */ 165 if (error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0)) 166 panic("nfs_mountroot: socreate: %d", error); 167 if (error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, p)) 168 panic("nfs_mountroot: SIOCAIFADDR: %d", error); 169 soclose(so); 170 171 /* 172 * If the gateway field is filled in, set it as the default route. 173 */ 174 if (nd->mygateway.sin_len != 0) { 175 struct sockaddr_in sin; 176 extern struct sockaddr_in icmpmask; 177 178 sin.sin_len = sizeof (struct sockaddr_in); 179 sin.sin_family = AF_INET; 180 sin.sin_addr.s_addr = 0; /* default */ 181 in_sockmaskof(sin.sin_addr, &icmpmask); 182 if (error = rtrequest(RTM_ADD, (struct sockaddr *)&sin, 183 (struct sockaddr *)&nd->mygateway, 184 (struct sockaddr *)&icmpmask, 185 RTF_UP | RTF_GATEWAY, (struct rtentry **)0)) 186 panic("nfs_mountroot: RTM_ADD: %d", error); 187 } 188 189 /* 190 * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV): 191 * Create a fake mount point just for the swap vnode so that the 192 * swap file can be on a different server from the rootfs. 193 */ 194 if (swdevt[0].sw_dev == NODEV) { 195 nd->swap_args.fh = (nfsv2fh_t *)nd->swap_fh; 196 (void) nfs_mountdiskless(nd->swap_hostnam, "/swap", 0, 197 &nd->swap_saddr, &nd->swap_args, &vp); 198 199 /* 200 * Since the swap file is not the root dir of a file system, 201 * hack it to a regular file. 202 */ 203 vp->v_type = VREG; 204 vp->v_flag = 0; 205 swapdev_vp = vp; 206 VREF(vp); 207 swdevt[0].sw_vp = vp; 208 swdevt[0].sw_nblks = ntohl(nd->swap_nblks); 209 } 210 211 /* 212 * Create the rootfs mount point. 213 */ 214 nd->root_args.fh = (nfsv2fh_t *)nd->root_fh; 215 mp = nfs_mountdiskless(nd->root_hostnam, "/", MNT_RDONLY, 216 &nd->root_saddr, &nd->root_args, &vp); 217 218 if (vfs_lock(mp)) 219 panic("nfs_mountroot: vfs_lock"); 220 rootfs = mp; 221 mp->mnt_next = mp; 222 mp->mnt_prev = mp; 223 mp->mnt_vnodecovered = NULLVP; 224 vfs_unlock(mp); 225 rootvp = vp; 226 227 /* 228 * This is not really an nfs issue, but it is much easier to 229 * set hostname here and then let the "/etc/rc.xxx" files 230 * mount the right /var based upon its preset value. 231 */ 232 bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN); 233 hostname[MAXHOSTNAMELEN - 1] = '\0'; 234 for (i = 0; i < MAXHOSTNAMELEN; i++) 235 if (hostname[i] == '\0') 236 break; 237 hostnamelen = i; 238 inittodr(nfs_diskless.root_time); 239 return (0); 240 } 241 242 /* 243 * Internal version of mount system call for diskless setup. 244 */ 245 static struct mount * 246 nfs_mountdiskless(path, which, mountflag, sin, args, vpp) 247 char *path; 248 char *which; 249 int mountflag; 250 struct sockaddr_in *sin; 251 struct nfs_args *args; 252 register struct vnode **vpp; 253 { 254 register struct mount *mp; 255 register struct mbuf *m; 256 register int error; 257 258 mp = (struct mount *)malloc((u_long)sizeof(struct mount), 259 M_MOUNT, M_NOWAIT); 260 if (mp == NULL) 261 panic("nfs_mountroot: %s mount malloc", which); 262 mp->mnt_op = &nfs_vfsops; 263 mp->mnt_flag = mountflag; 264 mp->mnt_mounth = NULLVP; 265 266 MGET(m, MT_SONAME, M_DONTWAIT); 267 if (m == NULL) 268 panic("nfs_mountroot: %s mount mbuf", which); 269 bcopy((caddr_t)sin, mtod(m, caddr_t), sin->sin_len); 270 m->m_len = sin->sin_len; 271 nfsargs_ntoh(args); 272 if (error = mountnfs(args, mp, m, which, path, vpp)) 273 panic("nfs_mountroot: mount %s on %s: %d", path, which, error); 274 275 return (mp); 276 } 277 278 /* 279 * Convert the integer fields of the nfs_args structure from net byte order 280 * to host byte order. Called by nfs_mountroot() above. 281 */ 282 void 283 nfsargs_ntoh(nfsp) 284 register struct nfs_args *nfsp; 285 { 286 287 NTOHL(nfsp->sotype); 288 NTOHL(nfsp->proto); 289 NTOHL(nfsp->flags); 290 NTOHL(nfsp->wsize); 291 NTOHL(nfsp->rsize); 292 NTOHL(nfsp->timeo); 293 NTOHL(nfsp->retrans); 294 NTOHL(nfsp->maxgrouplist); 295 NTOHL(nfsp->readahead); 296 NTOHL(nfsp->leaseterm); 297 NTOHL(nfsp->deadthresh); 298 } 299 300 /* 301 * VFS Operations. 302 * 303 * mount system call 304 * It seems a bit dumb to copyinstr() the host and path here and then 305 * bcopy() them in mountnfs(), but I wanted to detect errors before 306 * doing the sockargs() call because sockargs() allocates an mbuf and 307 * an error after that means that I have to release the mbuf. 308 */ 309 /* ARGSUSED */ 310 int 311 nfs_mount(mp, path, data, ndp, p) 312 struct mount *mp; 313 char *path; 314 caddr_t data; 315 struct nameidata *ndp; 316 struct proc *p; 317 { 318 int error; 319 struct nfs_args args; 320 struct mbuf *nam; 321 struct vnode *vp; 322 char pth[MNAMELEN], hst[MNAMELEN]; 323 u_int len; 324 nfsv2fh_t nfh; 325 326 if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args))) 327 return (error); 328 if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t))) 329 return (error); 330 if (error = copyinstr(path, pth, MNAMELEN-1, &len)) 331 return (error); 332 bzero(&pth[len], MNAMELEN - len); 333 if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) 334 return (error); 335 bzero(&hst[len], MNAMELEN - len); 336 /* sockargs() call must be after above copyin() calls */ 337 if (error = sockargs(&nam, (caddr_t)args.addr, 338 args.addrlen, MT_SONAME)) 339 return (error); 340 args.fh = &nfh; 341 error = mountnfs(&args, mp, nam, pth, hst, &vp); 342 return (error); 343 } 344 345 /* 346 * Common code for mount and mountroot 347 */ 348 int 349 mountnfs(argp, mp, nam, pth, hst, vpp) 350 register struct nfs_args *argp; 351 register struct mount *mp; 352 struct mbuf *nam; 353 char *pth, *hst; 354 struct vnode **vpp; 355 { 356 register struct nfsmount *nmp; 357 struct nfsnode *np; 358 int error; 359 fsid_t tfsid; 360 361 if (mp->mnt_flag & MNT_UPDATE) { 362 nmp = VFSTONFS(mp); 363 /* update paths, file handles, etc, here XXX */ 364 m_freem(nam); 365 return (0); 366 } else { 367 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount), 368 M_NFSMNT, M_WAITOK); 369 bzero((caddr_t)nmp, sizeof (struct nfsmount)); 370 mp->mnt_data = (qaddr_t)nmp; 371 } 372 getnewfsid(mp, MOUNT_NFS); 373 nmp->nm_mountp = mp; 374 nmp->nm_flag = argp->flags; 375 if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) == 376 (NFSMNT_NQNFS | NFSMNT_MYWRITE)) { 377 error = EPERM; 378 goto bad; 379 } 380 if (nmp->nm_flag & (NFSMNT_RDIRALOOK | NFSMNT_LEASETERM)) { 381 if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) { 382 error = EPERM; 383 goto bad; 384 } 385 /* 386 * We have to set mnt_maxsymlink to a non-zero value so 387 * that COMPAT_43 routines will know that we are setting 388 * the d_type field in directories (and can zero it for 389 * unsuspecting binaries). 390 */ 391 mp->mnt_maxsymlinklen = 1; 392 } 393 nmp->nm_timeo = NFS_TIMEO; 394 nmp->nm_retry = NFS_RETRANS; 395 nmp->nm_wsize = NFS_WSIZE; 396 nmp->nm_rsize = NFS_RSIZE; 397 nmp->nm_numgrps = NFS_MAXGRPS; 398 nmp->nm_readahead = NFS_DEFRAHEAD; 399 nmp->nm_leaseterm = NQ_DEFLEASE; 400 nmp->nm_deadthresh = NQ_DEADTHRESH; 401 nmp->nm_tnext = (struct nfsnode *)nmp; 402 nmp->nm_tprev = (struct nfsnode *)nmp; 403 nmp->nm_inprog = NULLVP; 404 bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); 405 mp->mnt_stat.f_type = MOUNT_NFS; 406 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 407 bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); 408 nmp->nm_nam = nam; 409 410 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 411 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 412 if (nmp->nm_timeo < NFS_MINTIMEO) 413 nmp->nm_timeo = NFS_MINTIMEO; 414 else if (nmp->nm_timeo > NFS_MAXTIMEO) 415 nmp->nm_timeo = NFS_MAXTIMEO; 416 } 417 418 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 419 nmp->nm_retry = argp->retrans; 420 if (nmp->nm_retry > NFS_MAXREXMIT) 421 nmp->nm_retry = NFS_MAXREXMIT; 422 } 423 424 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 425 nmp->nm_wsize = argp->wsize; 426 /* Round down to multiple of blocksize */ 427 nmp->nm_wsize &= ~0x1ff; 428 if (nmp->nm_wsize <= 0) 429 nmp->nm_wsize = 512; 430 else if (nmp->nm_wsize > NFS_MAXDATA) 431 nmp->nm_wsize = NFS_MAXDATA; 432 } 433 if (nmp->nm_wsize > MAXBSIZE) 434 nmp->nm_wsize = MAXBSIZE; 435 436 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 437 nmp->nm_rsize = argp->rsize; 438 /* Round down to multiple of blocksize */ 439 nmp->nm_rsize &= ~0x1ff; 440 if (nmp->nm_rsize <= 0) 441 nmp->nm_rsize = 512; 442 else if (nmp->nm_rsize > NFS_MAXDATA) 443 nmp->nm_rsize = NFS_MAXDATA; 444 } 445 if (nmp->nm_rsize > MAXBSIZE) 446 nmp->nm_rsize = MAXBSIZE; 447 if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 && 448 argp->maxgrouplist <= NFS_MAXGRPS) 449 nmp->nm_numgrps = argp->maxgrouplist; 450 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 && 451 argp->readahead <= NFS_MAXRAHEAD) 452 nmp->nm_readahead = argp->readahead; 453 if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 && 454 argp->leaseterm <= NQ_MAXLEASE) 455 nmp->nm_leaseterm = argp->leaseterm; 456 if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 && 457 argp->deadthresh <= NQ_NEVERDEAD) 458 nmp->nm_deadthresh = argp->deadthresh; 459 /* Set up the sockets and per-host congestion */ 460 nmp->nm_sotype = argp->sotype; 461 nmp->nm_soproto = argp->proto; 462 463 /* 464 * For Connection based sockets (TCP,...) defer the connect until 465 * the first request, in case the server is not responding. 466 */ 467 if (nmp->nm_sotype == SOCK_DGRAM && 468 (error = nfs_connect(nmp, (struct nfsreq *)0))) 469 goto bad; 470 471 /* 472 * This is silly, but it has to be set so that vinifod() works. 473 * We do not want to do an nfs_statfs() here since we can get 474 * stuck on a dead server and we are holding a lock on the mount 475 * point. 476 */ 477 mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA; 478 /* 479 * A reference count is needed on the nfsnode representing the 480 * remote root. If this object is not persistent, then backward 481 * traversals of the mount point (i.e. "..") will not work if 482 * the nfsnode gets flushed out of the cache. Ufs does not have 483 * this problem, because one can identify root inodes by their 484 * number == ROOTINO (2). 485 */ 486 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 487 goto bad; 488 *vpp = NFSTOV(np); 489 490 return (0); 491 bad: 492 nfs_disconnect(nmp); 493 free((caddr_t)nmp, M_NFSMNT); 494 m_freem(nam); 495 return (error); 496 } 497 498 /* 499 * unmount system call 500 */ 501 int 502 nfs_unmount(mp, mntflags, p) 503 struct mount *mp; 504 int mntflags; 505 struct proc *p; 506 { 507 register struct nfsmount *nmp; 508 struct nfsnode *np; 509 struct vnode *vp; 510 int error, flags = 0; 511 extern int doforce; 512 513 if (mntflags & MNT_FORCE) { 514 if (!doforce || mp == rootfs) 515 return (EINVAL); 516 flags |= FORCECLOSE; 517 } 518 nmp = VFSTONFS(mp); 519 /* 520 * Goes something like this.. 521 * - Check for activity on the root vnode (other than ourselves). 522 * - Call vflush() to clear out vnodes for this file system, 523 * except for the root vnode. 524 * - Decrement reference on the vnode representing remote root. 525 * - Close the socket 526 * - Free up the data structures 527 */ 528 /* 529 * We need to decrement the ref. count on the nfsnode representing 530 * the remote root. See comment in mountnfs(). The VFS unmount() 531 * has done vput on this vnode, otherwise we would get deadlock! 532 */ 533 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 534 return(error); 535 vp = NFSTOV(np); 536 if (vp->v_usecount > 2) { 537 vput(vp); 538 return (EBUSY); 539 } 540 541 /* 542 * Must handshake with nqnfs_clientd() if it is active. 543 */ 544 nmp->nm_flag |= NFSMNT_DISMINPROG; 545 while (nmp->nm_inprog != NULLVP) 546 (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0); 547 if (error = vflush(mp, vp, flags)) { 548 vput(vp); 549 nmp->nm_flag &= ~NFSMNT_DISMINPROG; 550 return (error); 551 } 552 553 /* 554 * We are now committed to the unmount. 555 * For NQNFS, let the server daemon free the nfsmount structure. 556 */ 557 if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) 558 nmp->nm_flag |= NFSMNT_DISMNT; 559 560 /* 561 * There are two reference counts to get rid of here. 562 */ 563 vrele(vp); 564 vrele(vp); 565 vgone(vp); 566 nfs_disconnect(nmp); 567 m_freem(nmp->nm_nam); 568 569 if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0) 570 free((caddr_t)nmp, M_NFSMNT); 571 return (0); 572 } 573 574 /* 575 * Return root of a filesystem 576 */ 577 int 578 nfs_root(mp, vpp) 579 struct mount *mp; 580 struct vnode **vpp; 581 { 582 register struct vnode *vp; 583 struct nfsmount *nmp; 584 struct nfsnode *np; 585 int error; 586 587 nmp = VFSTONFS(mp); 588 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 589 return (error); 590 vp = NFSTOV(np); 591 vp->v_type = VDIR; 592 vp->v_flag = VROOT; 593 *vpp = vp; 594 return (0); 595 } 596 597 extern int syncprt; 598 599 /* 600 * Flush out the buffer cache 601 */ 602 /* ARGSUSED */ 603 int 604 nfs_sync(mp, waitfor, cred, p) 605 struct mount *mp; 606 int waitfor; 607 struct ucred *cred; 608 struct proc *p; 609 { 610 register struct vnode *vp; 611 int error, allerror = 0; 612 613 /* 614 * Force stale buffer cache information to be flushed. 615 */ 616 loop: 617 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 618 /* 619 * If the vnode that we are about to sync is no longer 620 * associated with this mount point, start over. 621 */ 622 if (vp->v_mount != mp) 623 goto loop; 624 if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd == NULL) 625 continue; 626 if (vget(vp)) 627 goto loop; 628 if (error = VOP_FSYNC(vp, cred, waitfor, p)) 629 allerror = error; 630 vput(vp); 631 } 632 return (allerror); 633 } 634 635 /* 636 * NFS flat namespace lookup. 637 * Currently unsupported. 638 */ 639 /* ARGSUSED */ 640 int 641 nfs_vget(mp, ino, vpp) 642 struct mount *mp; 643 ino_t ino; 644 struct vnode **vpp; 645 { 646 647 return (EOPNOTSUPP); 648 } 649 650 /* 651 * At this point, this should never happen 652 */ 653 /* ARGSUSED */ 654 int 655 nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 656 register struct mount *mp; 657 struct fid *fhp; 658 struct mbuf *nam; 659 struct vnode **vpp; 660 int *exflagsp; 661 struct ucred **credanonp; 662 { 663 664 return (EINVAL); 665 } 666 667 /* 668 * Vnode pointer to File handle, should never happen either 669 */ 670 /* ARGSUSED */ 671 int 672 nfs_vptofh(vp, fhp) 673 struct vnode *vp; 674 struct fid *fhp; 675 { 676 677 return (EINVAL); 678 } 679 680 /* 681 * Vfs start routine, a no-op. 682 */ 683 /* ARGSUSED */ 684 int 685 nfs_start(mp, flags, p) 686 struct mount *mp; 687 int flags; 688 struct proc *p; 689 { 690 691 return (0); 692 } 693 694 /* 695 * Do operations associated with quotas, not supported 696 */ 697 /* ARGSUSED */ 698 int 699 nfs_quotactl(mp, cmd, uid, arg, p) 700 struct mount *mp; 701 int cmd; 702 uid_t uid; 703 caddr_t arg; 704 struct proc *p; 705 { 706 707 return (EOPNOTSUPP); 708 } 709