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