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.3 (Berkeley) 01/04/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 nmp->nm_tnext = (struct nfsnode *)nmp; 406 nmp->nm_tprev = (struct nfsnode *)nmp; 407 nmp->nm_inprog = NULLVP; 408 bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); 409 mp->mnt_stat.f_type = MOUNT_NFS; 410 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 411 bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); 412 nmp->nm_nam = nam; 413 414 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 415 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 416 if (nmp->nm_timeo < NFS_MINTIMEO) 417 nmp->nm_timeo = NFS_MINTIMEO; 418 else if (nmp->nm_timeo > NFS_MAXTIMEO) 419 nmp->nm_timeo = NFS_MAXTIMEO; 420 } 421 422 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 423 nmp->nm_retry = argp->retrans; 424 if (nmp->nm_retry > NFS_MAXREXMIT) 425 nmp->nm_retry = NFS_MAXREXMIT; 426 } 427 428 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 429 nmp->nm_wsize = argp->wsize; 430 /* Round down to multiple of blocksize */ 431 nmp->nm_wsize &= ~0x1ff; 432 if (nmp->nm_wsize <= 0) 433 nmp->nm_wsize = 512; 434 else if (nmp->nm_wsize > NFS_MAXDATA) 435 nmp->nm_wsize = NFS_MAXDATA; 436 } 437 if (nmp->nm_wsize > MAXBSIZE) 438 nmp->nm_wsize = MAXBSIZE; 439 440 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 441 nmp->nm_rsize = argp->rsize; 442 /* Round down to multiple of blocksize */ 443 nmp->nm_rsize &= ~0x1ff; 444 if (nmp->nm_rsize <= 0) 445 nmp->nm_rsize = 512; 446 else if (nmp->nm_rsize > NFS_MAXDATA) 447 nmp->nm_rsize = NFS_MAXDATA; 448 } 449 if (nmp->nm_rsize > MAXBSIZE) 450 nmp->nm_rsize = MAXBSIZE; 451 if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 && 452 argp->maxgrouplist <= NFS_MAXGRPS) 453 nmp->nm_numgrps = argp->maxgrouplist; 454 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 && 455 argp->readahead <= NFS_MAXRAHEAD) 456 nmp->nm_readahead = argp->readahead; 457 if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 && 458 argp->leaseterm <= NQ_MAXLEASE) 459 nmp->nm_leaseterm = argp->leaseterm; 460 if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 && 461 argp->deadthresh <= NQ_NEVERDEAD) 462 nmp->nm_deadthresh = argp->deadthresh; 463 /* Set up the sockets and per-host congestion */ 464 nmp->nm_sotype = argp->sotype; 465 nmp->nm_soproto = argp->proto; 466 467 /* 468 * For Connection based sockets (TCP,...) defer the connect until 469 * the first request, in case the server is not responding. 470 */ 471 if (nmp->nm_sotype == SOCK_DGRAM && 472 (error = nfs_connect(nmp, (struct nfsreq *)0))) 473 goto bad; 474 475 /* 476 * This is silly, but it has to be set so that vinifod() works. 477 * We do not want to do an nfs_statfs() here since we can get 478 * stuck on a dead server and we are holding a lock on the mount 479 * point. 480 */ 481 mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA; 482 /* 483 * A reference count is needed on the nfsnode representing the 484 * remote root. If this object is not persistent, then backward 485 * traversals of the mount point (i.e. "..") will not work if 486 * the nfsnode gets flushed out of the cache. Ufs does not have 487 * this problem, because one can identify root inodes by their 488 * number == ROOTINO (2). 489 */ 490 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 491 goto bad; 492 *vpp = NFSTOV(np); 493 494 return (0); 495 bad: 496 nfs_disconnect(nmp); 497 free((caddr_t)nmp, M_NFSMNT); 498 m_freem(nam); 499 return (error); 500 } 501 502 /* 503 * unmount system call 504 */ 505 int 506 nfs_unmount(mp, mntflags, p) 507 struct mount *mp; 508 int mntflags; 509 struct proc *p; 510 { 511 register struct nfsmount *nmp; 512 struct nfsnode *np; 513 struct vnode *vp; 514 int error, flags = 0; 515 extern int doforce; 516 517 if (mntflags & MNT_FORCE) { 518 if (!doforce || (mp->mnt_flag & MNT_ROOTFS)) 519 return (EINVAL); 520 flags |= FORCECLOSE; 521 } 522 nmp = VFSTONFS(mp); 523 /* 524 * Goes something like this.. 525 * - Check for activity on the root vnode (other than ourselves). 526 * - Call vflush() to clear out vnodes for this file system, 527 * except for the root vnode. 528 * - Decrement reference on the vnode representing remote root. 529 * - Close the socket 530 * - Free up the data structures 531 */ 532 /* 533 * We need to decrement the ref. count on the nfsnode representing 534 * the remote root. See comment in mountnfs(). The VFS unmount() 535 * has done vput on this vnode, otherwise we would get deadlock! 536 */ 537 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 538 return(error); 539 vp = NFSTOV(np); 540 if (vp->v_usecount > 2) { 541 vput(vp); 542 return (EBUSY); 543 } 544 545 /* 546 * Must handshake with nqnfs_clientd() if it is active. 547 */ 548 nmp->nm_flag |= NFSMNT_DISMINPROG; 549 while (nmp->nm_inprog != NULLVP) 550 (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0); 551 if (error = vflush(mp, vp, flags)) { 552 vput(vp); 553 nmp->nm_flag &= ~NFSMNT_DISMINPROG; 554 return (error); 555 } 556 557 /* 558 * We are now committed to the unmount. 559 * For NQNFS, let the server daemon free the nfsmount structure. 560 */ 561 if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) 562 nmp->nm_flag |= NFSMNT_DISMNT; 563 564 /* 565 * There are two reference counts to get rid of here. 566 */ 567 vrele(vp); 568 vrele(vp); 569 vgone(vp); 570 nfs_disconnect(nmp); 571 m_freem(nmp->nm_nam); 572 573 if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0) 574 free((caddr_t)nmp, M_NFSMNT); 575 return (0); 576 } 577 578 /* 579 * Return root of a filesystem 580 */ 581 int 582 nfs_root(mp, vpp) 583 struct mount *mp; 584 struct vnode **vpp; 585 { 586 register struct vnode *vp; 587 struct nfsmount *nmp; 588 struct nfsnode *np; 589 int error; 590 591 nmp = VFSTONFS(mp); 592 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 593 return (error); 594 vp = NFSTOV(np); 595 vp->v_type = VDIR; 596 vp->v_flag = VROOT; 597 *vpp = vp; 598 return (0); 599 } 600 601 extern int syncprt; 602 603 /* 604 * Flush out the buffer cache 605 */ 606 /* ARGSUSED */ 607 int 608 nfs_sync(mp, waitfor, cred, p) 609 struct mount *mp; 610 int waitfor; 611 struct ucred *cred; 612 struct proc *p; 613 { 614 register struct vnode *vp; 615 int error, allerror = 0; 616 617 /* 618 * Force stale buffer cache information to be flushed. 619 */ 620 loop: 621 for (vp = mp->mnt_vnodelist.lh_first; 622 vp != NULL; 623 vp = vp->v_mntvnodes.le_next) { 624 /* 625 * If the vnode that we are about to sync is no longer 626 * associated with this mount point, start over. 627 */ 628 if (vp->v_mount != mp) 629 goto loop; 630 if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL) 631 continue; 632 if (vget(vp, 1)) 633 goto loop; 634 if (error = VOP_FSYNC(vp, cred, waitfor, p)) 635 allerror = error; 636 vput(vp); 637 } 638 return (allerror); 639 } 640 641 /* 642 * NFS flat namespace lookup. 643 * Currently unsupported. 644 */ 645 /* ARGSUSED */ 646 int 647 nfs_vget(mp, ino, vpp) 648 struct mount *mp; 649 ino_t ino; 650 struct vnode **vpp; 651 { 652 653 return (EOPNOTSUPP); 654 } 655 656 /* 657 * At this point, this should never happen 658 */ 659 /* ARGSUSED */ 660 int 661 nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 662 register struct mount *mp; 663 struct fid *fhp; 664 struct mbuf *nam; 665 struct vnode **vpp; 666 int *exflagsp; 667 struct ucred **credanonp; 668 { 669 670 return (EINVAL); 671 } 672 673 /* 674 * Vnode pointer to File handle, should never happen either 675 */ 676 /* ARGSUSED */ 677 int 678 nfs_vptofh(vp, fhp) 679 struct vnode *vp; 680 struct fid *fhp; 681 { 682 683 return (EINVAL); 684 } 685 686 /* 687 * Vfs start routine, a no-op. 688 */ 689 /* ARGSUSED */ 690 int 691 nfs_start(mp, flags, p) 692 struct mount *mp; 693 int flags; 694 struct proc *p; 695 { 696 697 return (0); 698 } 699 700 /* 701 * Do operations associated with quotas, not supported 702 */ 703 /* ARGSUSED */ 704 int 705 nfs_quotactl(mp, cmd, uid, arg, p) 706 struct mount *mp; 707 int cmd; 708 uid_t uid; 709 caddr_t arg; 710 struct proc *p; 711 { 712 713 return (EOPNOTSUPP); 714 } 715