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 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: @(#)nfs_vfsops.c 8.3 (Berkeley) 1/4/94 37 * $Id: nfs_vfsops.c,v 1.23 1994/06/14 03:29:12 gwr Exp $ 38 */ 39 40 #include <sys/param.h> 41 #include <sys/conf.h> 42 #include <sys/ioctl.h> 43 #include <sys/signal.h> 44 #include <sys/proc.h> 45 #include <sys/namei.h> 46 #include <sys/vnode.h> 47 #include <sys/kernel.h> 48 #include <sys/mount.h> 49 #include <sys/buf.h> 50 #include <sys/mbuf.h> 51 #include <sys/socket.h> 52 #include <sys/systm.h> 53 54 #include <net/if.h> 55 #include <net/route.h> 56 #include <netinet/in.h> 57 58 #include <nfs/rpcv2.h> 59 #include <nfs/nfsv2.h> 60 #include <nfs/nfsnode.h> 61 #include <nfs/nfsmount.h> 62 #include <nfs/nfs.h> 63 #include <nfs/xdr_subs.h> 64 #include <nfs/nfsm_subs.h> 65 #include <nfs/nfsdiskless.h> 66 #include <nfs/nqnfs.h> 67 68 /* 69 * nfs vfs operations. 70 */ 71 struct vfsops nfs_vfsops = { 72 MOUNT_NFS, 73 nfs_mount, 74 nfs_start, 75 nfs_unmount, 76 nfs_root, 77 nfs_quotactl, 78 nfs_statfs, 79 nfs_sync, 80 nfs_vget, 81 nfs_fhtovp, 82 nfs_vptofh, 83 nfs_init, 84 }; 85 86 extern u_long nfs_procids[NFS_NPROCS]; 87 extern u_long nfs_prog, nfs_vers; 88 void nfs_disconnect __P((struct nfsmount *)); 89 90 static struct mount * 91 nfs_mount_diskless __P((struct nfs_dlmount *, char *, int, struct vnode **)); 92 93 #define TRUE 1 94 #define FALSE 0 95 96 /* 97 * nfs statfs call 98 */ 99 int 100 nfs_statfs(mp, sbp, p) 101 struct mount *mp; 102 register struct statfs *sbp; 103 struct proc *p; 104 { 105 register struct vnode *vp; 106 register struct nfsv2_statfs *sfp; 107 register caddr_t cp; 108 register long t1; 109 caddr_t bpos, dpos, cp2; 110 int error = 0, isnq; 111 struct mbuf *mreq, *mrep, *md, *mb, *mb2; 112 struct nfsmount *nmp; 113 struct ucred *cred; 114 struct nfsnode *np; 115 116 nmp = VFSTONFS(mp); 117 isnq = (nmp->nm_flag & NFSMNT_NQNFS); 118 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 119 return (error); 120 vp = NFSTOV(np); 121 nfsstats.rpccnt[NFSPROC_STATFS]++; 122 cred = crget(); 123 cred->cr_ngroups = 1; 124 nfsm_reqhead(vp, NFSPROC_STATFS, NFSX_FH); 125 nfsm_fhtom(vp); 126 nfsm_request(vp, NFSPROC_STATFS, p, cred); 127 nfsm_dissect(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq)); 128 #ifdef COMPAT_09 129 sbp->f_type = 2; 130 #else 131 sbp->f_type = 0; 132 #endif 133 sbp->f_flags = nmp->nm_flag; 134 sbp->f_iosize = NFS_MAXDGRAMDATA; 135 sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize); 136 sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks); 137 sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree); 138 sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail); 139 if (isnq) { 140 sbp->f_files = fxdr_unsigned(long, sfp->sf_files); 141 sbp->f_ffree = fxdr_unsigned(long, sfp->sf_ffree); 142 } else { 143 sbp->f_files = 0; 144 sbp->f_ffree = 0; 145 } 146 if (sbp != &mp->mnt_stat) { 147 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 148 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 149 } 150 strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN); 151 sbp->f_fstypename[MFSNAMELEN] = '\0'; 152 nfsm_reqdone; 153 vrele(vp); 154 crfree(cred); 155 return (error); 156 } 157 158 /* 159 * Mount a remote root fs via. NFS. It goes like this: 160 * - Call nfs_boot_init() to fill in the nfs_diskless struct 161 * (using RARP, bootparam RPC, mountd RPC) 162 * - hand craft the swap nfs vnode hanging off a fake mount point 163 * if swdevt[0].sw_dev == NODEV 164 * - build the rootfs mount point and call mountnfs() to do the rest. 165 */ 166 int 167 nfs_mountroot() 168 { 169 struct nfs_diskless nd; 170 struct vattr attr; 171 struct mount *mp; 172 struct vnode *vp; 173 struct proc *procp; 174 struct ucred *cred; 175 long n; 176 int error; 177 178 procp = curproc; /* XXX */ 179 180 /* 181 * XXX time must be non-zero when we init the interface or else 182 * the arp code will wedge. [Fixed now in if_ether.c] 183 * However, the NFS attribute cache gives false "hits" when 184 * time.tv_sec < NFS_ATTRTIMEO(np) so keep this in for now. 185 */ 186 if (time.tv_sec < NFS_MAXATTRTIMO) 187 time.tv_sec = NFS_MAXATTRTIMO; 188 189 /* 190 * Call nfs_boot_init() to fill in the nfs_diskless struct. 191 * Side effect: Finds and configures a network interface. 192 */ 193 bzero((caddr_t) &nd, sizeof(nd)); 194 nfs_boot_init(&nd, procp); 195 196 /* 197 * Create the root mount point. 198 */ 199 mp = nfs_mount_diskless(&nd.nd_root, "/", MNT_RDONLY, &vp); 200 201 /* 202 * Link it into the mount list. 203 */ 204 if (vfs_lock(mp)) 205 panic("nfs_mountroot: vfs_lock"); 206 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 207 mp->mnt_flag |= MNT_ROOTFS; 208 mp->mnt_vnodecovered = NULLVP; 209 vfs_unlock(mp); 210 rootvp = vp; 211 212 213 /* Get root attributes (for the time). */ 214 error = VOP_GETATTR(vp, &attr, procp->p_cred->pc_ucred, procp); 215 if (error) panic("nfs_mountroot: getattr for root"); 216 n = attr.va_mtime.ts_sec; 217 #ifdef DEBUG 218 printf(" root time: 0x%x\n", n); 219 #endif 220 inittodr(n); 221 222 #ifdef notyet 223 /* Set up swap credentials. */ 224 proc0.p_ucred->cr_uid = ntohl(nd.swap_ucred.cr_uid); 225 proc0.p_ucred->cr_gid = ntohl(nd.swap_ucred.cr_gid); 226 if ((proc0.p_ucred->cr_ngroups = ntohs(nd.swap_ucred.cr_ngroups)) > 227 NGROUPS) 228 proc0.p_ucred->cr_ngroups = NGROUPS; 229 for (i = 0; i < proc0.p_ucred->cr_ngroups; i++) 230 proc0.p_ucred->cr_groups[i] = ntohl(nd.swap_ucred.cr_groups[i]); 231 #endif 232 233 /* 234 * "Mount" the swap device. 235 * 236 * On a "dataless" configuration (swap on disk) we will have: 237 * (swdevt[0].sw_dev != NODEV) identifying the swap device. 238 */ 239 if (swdevt[0].sw_dev != NODEV) { 240 if (bdevvp(swapdev, &swapdev_vp)) 241 panic("nfs_mountroot: can't get swap vp for dev %d,%d", 242 major(swdevt[0].sw_dev), minor(swdevt[0].sw_dev)); 243 return (0); 244 } 245 246 /* 247 * If swapping to an nfs node: (swdevt[0].sw_dev == NODEV) 248 * Create a fake mount point just for the swap vnode so that the 249 * swap file can be on a different server from the rootfs. 250 */ 251 mp = nfs_mount_diskless(&nd.nd_swap, "/swap", 0, &vp); 252 253 /* 254 * Since the swap file is not the root dir of a file system, 255 * hack it to a regular file. 256 */ 257 vp->v_type = VREG; 258 vp->v_flag = 0; 259 swapdev_vp = vp; 260 VREF(vp); 261 swdevt[0].sw_vp = vp; 262 263 /* 264 * Find out how large the swap file is. 265 */ 266 error = VOP_GETATTR(vp, &attr, procp->p_cred->pc_ucred, procp); 267 if (error) panic("nfs_mountroot: getattr for swap"); 268 n = (long) (attr.va_size / DEV_BSIZE); 269 #ifdef DEBUG 270 printf(" swap size: 0x%x (blocks)\n", n); 271 #endif 272 swdevt[0].sw_nblks = n; 273 274 return (0); 275 } 276 277 /* 278 * Internal version of mount system call for diskless setup. 279 */ 280 static struct mount * 281 nfs_mount_diskless(ndmntp, mntname, mntflag, vpp) 282 struct nfs_dlmount *ndmntp; 283 char *mntname; 284 int mntflag; 285 struct vnode **vpp; 286 { 287 struct nfs_args args; 288 struct mount *mp; 289 struct mbuf *m; 290 int error; 291 292 /* Create the mount point. */ 293 mp = (struct mount *)malloc((u_long)sizeof(struct mount), 294 M_MOUNT, M_NOWAIT); 295 if (mp == NULL) 296 panic("nfs_mountroot: malloc mount for %s", mntname); 297 bzero((char *)mp, (u_long)sizeof(struct mount)); 298 mp->mnt_op = &nfs_vfsops; 299 mp->mnt_flag = mntflag; 300 301 /* Initialize mount args. */ 302 bzero((caddr_t) &args, sizeof(args)); 303 args.addr = (struct sockaddr *)&ndmntp->ndm_saddr; 304 args.addrlen = args.addr->sa_len; 305 args.sotype = SOCK_DGRAM; 306 args.fh = (nfsv2fh_t *)ndmntp->ndm_fh; 307 args.hostname = ndmntp->ndm_host; 308 309 /* Get mbuf for server sockaddr. */ 310 MGET(m, MT_SONAME, M_DONTWAIT); 311 if (m == NULL) 312 panic("nfs_mountroot: mget soname for %s", mntname); 313 bcopy((caddr_t)args.addr, mtod(m, caddr_t), 314 (m->m_len = args.addr->sa_len)); 315 316 if (error = mountnfs(&args, mp, m, mntname, args.hostname, vpp)) 317 panic("nfs_mountroot: mount %s failed: %d", mntname); 318 319 return (mp); 320 } 321 322 void 323 nfs_decode_args(nmp, argp) 324 struct nfsmount *nmp; 325 struct nfs_args *argp; 326 { 327 int s; 328 329 s = splnet(); 330 /* Update flags atomically. Don't change the lock bits. */ 331 nmp->nm_flag = 332 (argp->flags & ~NFSMNT_INTERNAL) | (nmp->nm_flag & NFSMNT_INTERNAL); 333 splx(s); 334 335 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 336 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 337 if (nmp->nm_timeo < NFS_MINTIMEO) 338 nmp->nm_timeo = NFS_MINTIMEO; 339 else if (nmp->nm_timeo > NFS_MAXTIMEO) 340 nmp->nm_timeo = NFS_MAXTIMEO; 341 } 342 343 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 344 nmp->nm_retry = argp->retrans; 345 if (nmp->nm_retry > NFS_MAXREXMIT) 346 nmp->nm_retry = NFS_MAXREXMIT; 347 } 348 349 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 350 nmp->nm_wsize = argp->wsize; 351 /* Round down to multiple of blocksize */ 352 nmp->nm_wsize &= ~0x1ff; 353 if (nmp->nm_wsize <= 0) 354 nmp->nm_wsize = 512; 355 else if (nmp->nm_wsize > NFS_MAXDATA) 356 nmp->nm_wsize = NFS_MAXDATA; 357 } 358 if (nmp->nm_wsize > MAXBSIZE) 359 nmp->nm_wsize = MAXBSIZE; 360 361 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 362 nmp->nm_rsize = argp->rsize; 363 /* Round down to multiple of blocksize */ 364 nmp->nm_rsize &= ~0x1ff; 365 if (nmp->nm_rsize <= 0) 366 nmp->nm_rsize = 512; 367 else if (nmp->nm_rsize > NFS_MAXDATA) 368 nmp->nm_rsize = NFS_MAXDATA; 369 } 370 if (nmp->nm_rsize > MAXBSIZE) 371 nmp->nm_rsize = MAXBSIZE; 372 373 if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 && 374 argp->maxgrouplist <= NFS_MAXGRPS) 375 nmp->nm_numgrps = argp->maxgrouplist; 376 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 && 377 argp->readahead <= NFS_MAXRAHEAD) 378 nmp->nm_readahead = argp->readahead; 379 if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 && 380 argp->leaseterm <= NQ_MAXLEASE) 381 nmp->nm_leaseterm = argp->leaseterm; 382 if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 && 383 argp->deadthresh <= NQ_NEVERDEAD) 384 nmp->nm_deadthresh = argp->deadthresh; 385 } 386 387 /* 388 * VFS Operations. 389 * 390 * mount system call 391 * It seems a bit dumb to copyinstr() the host and path here and then 392 * bcopy() them in mountnfs(), but I wanted to detect errors before 393 * doing the sockargs() call because sockargs() allocates an mbuf and 394 * an error after that means that I have to release the mbuf. 395 */ 396 /* ARGSUSED */ 397 int 398 nfs_mount(mp, path, data, ndp, p) 399 struct mount *mp; 400 char *path; 401 caddr_t data; 402 struct nameidata *ndp; 403 struct proc *p; 404 { 405 int error; 406 struct nfs_args args; 407 struct mbuf *nam; 408 struct vnode *vp; 409 char pth[MNAMELEN], hst[MNAMELEN]; 410 u_int len; 411 nfsv2fh_t nfh; 412 413 if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args))) 414 return (error); 415 if (mp->mnt_flag & MNT_UPDATE) { 416 register struct nfsmount *nmp = VFSTONFS(mp); 417 418 if (nmp == NULL) 419 return (EIO); 420 nfs_decode_args(nmp, &args); 421 return (0); 422 } 423 if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t))) 424 return (error); 425 if (error = copyinstr(path, pth, MNAMELEN-1, &len)) 426 return (error); 427 bzero(&pth[len], MNAMELEN - len); 428 if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) 429 return (error); 430 bzero(&hst[len], MNAMELEN - len); 431 /* sockargs() call must be after above copyin() calls */ 432 if (error = sockargs(&nam, (caddr_t)args.addr, 433 args.addrlen, MT_SONAME)) 434 return (error); 435 args.fh = &nfh; 436 error = mountnfs(&args, mp, nam, pth, hst, &vp); 437 return (error); 438 } 439 440 /* 441 * Common code for mount and mountroot 442 */ 443 int 444 mountnfs(argp, mp, nam, pth, hst, vpp) 445 register struct nfs_args *argp; 446 register struct mount *mp; 447 struct mbuf *nam; 448 char *pth, *hst; 449 struct vnode **vpp; 450 { 451 register struct nfsmount *nmp; 452 struct nfsnode *np; 453 int error; 454 455 if (mp->mnt_flag & MNT_UPDATE) { 456 nmp = VFSTONFS(mp); 457 /* update paths, file handles, etc, here XXX */ 458 m_freem(nam); 459 return (0); 460 } else { 461 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount), 462 M_NFSMNT, M_WAITOK); 463 bzero((caddr_t)nmp, sizeof (struct nfsmount)); 464 mp->mnt_data = (qaddr_t)nmp; 465 } 466 getnewfsid(mp, makefstype(MOUNT_NFS)); 467 nmp->nm_mountp = mp; 468 if ((argp->flags & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) == 469 (NFSMNT_NQNFS | NFSMNT_MYWRITE)) { 470 error = EPERM; 471 goto bad; 472 } 473 if (argp->flags & NFSMNT_NQNFS) 474 /* 475 * We have to set mnt_maxsymlink to a non-zero value so 476 * that COMPAT_43 routines will know that we are setting 477 * the d_type field in directories (and can zero it for 478 * unsuspecting binaries). 479 */ 480 mp->mnt_maxsymlinklen = 1; 481 nmp->nm_timeo = NFS_TIMEO; 482 nmp->nm_retry = NFS_RETRANS; 483 nmp->nm_wsize = NFS_WSIZE; 484 nmp->nm_rsize = NFS_RSIZE; 485 nmp->nm_numgrps = NFS_MAXGRPS; 486 nmp->nm_readahead = NFS_DEFRAHEAD; 487 nmp->nm_leaseterm = NQ_DEFLEASE; 488 nmp->nm_deadthresh = NQ_DEADTHRESH; 489 nmp->nm_tnext = (struct nfsnode *)nmp; 490 nmp->nm_tprev = (struct nfsnode *)nmp; 491 nmp->nm_inprog = NULLVP; 492 bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); 493 #ifdef COMPAT_09 494 mp->mnt_stat.f_type = 2; 495 #else 496 mp->mnt_stat.f_type = 0; 497 #endif 498 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 499 bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); 500 nmp->nm_nam = nam; 501 nfs_decode_args(nmp, argp); 502 503 /* Set up the sockets and per-host congestion */ 504 nmp->nm_sotype = argp->sotype; 505 nmp->nm_soproto = argp->proto; 506 507 /* 508 * For Connection based sockets (TCP,...) defer the connect until 509 * the first request, in case the server is not responding. 510 */ 511 if (nmp->nm_sotype == SOCK_DGRAM && 512 (error = nfs_connect(nmp, (struct nfsreq *)0))) 513 goto bad; 514 515 /* 516 * This is silly, but it has to be set so that vinifod() works. 517 * We do not want to do an nfs_statfs() here since we can get 518 * stuck on a dead server and we are holding a lock on the mount 519 * point. 520 */ 521 mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA; 522 /* 523 * A reference count is needed on the nfsnode representing the 524 * remote root. If this object is not persistent, then backward 525 * traversals of the mount point (i.e. "..") will not work if 526 * the nfsnode gets flushed out of the cache. Ufs does not have 527 * this problem, because one can identify root inodes by their 528 * number == ROOTINO (2). 529 */ 530 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 531 goto bad; 532 *vpp = NFSTOV(np); 533 534 return (0); 535 bad: 536 nfs_disconnect(nmp); 537 free((caddr_t)nmp, M_NFSMNT); 538 m_freem(nam); 539 return (error); 540 } 541 542 /* 543 * unmount system call 544 */ 545 int 546 nfs_unmount(mp, mntflags, p) 547 struct mount *mp; 548 int mntflags; 549 struct proc *p; 550 { 551 register struct nfsmount *nmp; 552 struct nfsnode *np; 553 struct vnode *vp; 554 int error, flags = 0; 555 extern int doforce; 556 557 if (mntflags & MNT_FORCE) { 558 if (!doforce || (mp->mnt_flag & MNT_ROOTFS)) 559 return (EINVAL); 560 flags |= FORCECLOSE; 561 } 562 nmp = VFSTONFS(mp); 563 /* 564 * Goes something like this.. 565 * - Check for activity on the root vnode (other than ourselves). 566 * - Call vflush() to clear out vnodes for this file system, 567 * except for the root vnode. 568 * - Decrement reference on the vnode representing remote root. 569 * - Close the socket 570 * - Free up the data structures 571 */ 572 /* 573 * We need to decrement the ref. count on the nfsnode representing 574 * the remote root. See comment in mountnfs(). The VFS unmount() 575 * has done vput on this vnode, otherwise we would get deadlock! 576 */ 577 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 578 return(error); 579 vp = NFSTOV(np); 580 if (vp->v_usecount > 2) { 581 vput(vp); 582 return (EBUSY); 583 } 584 585 /* 586 * Must handshake with nqnfs_clientd() if it is active. 587 */ 588 nmp->nm_flag |= NFSMNT_DISMINPROG; 589 while (nmp->nm_inprog != NULLVP) 590 (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0); 591 if (error = vflush(mp, vp, flags)) { 592 vput(vp); 593 nmp->nm_flag &= ~NFSMNT_DISMINPROG; 594 return (error); 595 } 596 597 /* 598 * We are now committed to the unmount. 599 * For NQNFS, let the server daemon free the nfsmount structure. 600 */ 601 if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) 602 nmp->nm_flag |= NFSMNT_DISMNT; 603 604 /* 605 * There are two reference counts to get rid of here. 606 */ 607 vrele(vp); 608 vrele(vp); 609 vgone(vp); 610 nfs_disconnect(nmp); 611 m_freem(nmp->nm_nam); 612 613 if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0) 614 free((caddr_t)nmp, M_NFSMNT); 615 return (0); 616 } 617 618 /* 619 * Return root of a filesystem 620 */ 621 int 622 nfs_root(mp, vpp) 623 struct mount *mp; 624 struct vnode **vpp; 625 { 626 register struct vnode *vp; 627 struct nfsmount *nmp; 628 struct nfsnode *np; 629 int error; 630 631 nmp = VFSTONFS(mp); 632 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 633 return (error); 634 vp = NFSTOV(np); 635 vp->v_type = VDIR; 636 vp->v_flag = VROOT; 637 *vpp = vp; 638 return (0); 639 } 640 641 extern int syncprt; 642 643 /* 644 * Flush out the buffer cache 645 */ 646 /* ARGSUSED */ 647 int 648 nfs_sync(mp, waitfor, cred, p) 649 struct mount *mp; 650 int waitfor; 651 struct ucred *cred; 652 struct proc *p; 653 { 654 register struct vnode *vp; 655 int error, allerror = 0; 656 657 /* 658 * Force stale buffer cache information to be flushed. 659 */ 660 loop: 661 for (vp = mp->mnt_vnodelist.lh_first; 662 vp != NULL; 663 vp = vp->v_mntvnodes.le_next) { 664 /* 665 * If the vnode that we are about to sync is no longer 666 * associated with this mount point, start over. 667 */ 668 if (vp->v_mount != mp) 669 goto loop; 670 if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL) 671 continue; 672 if (vget(vp, 1)) 673 goto loop; 674 if (error = VOP_FSYNC(vp, cred, waitfor, p)) 675 allerror = error; 676 vput(vp); 677 } 678 return (allerror); 679 } 680 681 /* 682 * NFS flat namespace lookup. 683 * Currently unsupported. 684 */ 685 /* ARGSUSED */ 686 int 687 nfs_vget(mp, ino, vpp) 688 struct mount *mp; 689 ino_t ino; 690 struct vnode **vpp; 691 { 692 693 return (EOPNOTSUPP); 694 } 695 696 /* 697 * At this point, this should never happen 698 */ 699 /* ARGSUSED */ 700 int 701 nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 702 register struct mount *mp; 703 struct fid *fhp; 704 struct mbuf *nam; 705 struct vnode **vpp; 706 int *exflagsp; 707 struct ucred **credanonp; 708 { 709 710 return (EINVAL); 711 } 712 713 /* 714 * Vnode pointer to File handle, should never happen either 715 */ 716 /* ARGSUSED */ 717 int 718 nfs_vptofh(vp, fhp) 719 struct vnode *vp; 720 struct fid *fhp; 721 { 722 723 return (EINVAL); 724 } 725 726 /* 727 * Vfs start routine, a no-op. 728 */ 729 /* ARGSUSED */ 730 int 731 nfs_start(mp, flags, p) 732 struct mount *mp; 733 int flags; 734 struct proc *p; 735 { 736 737 return (0); 738 } 739 740 /* 741 * Do operations associated with quotas, not supported 742 */ 743 /* ARGSUSED */ 744 int 745 nfs_quotactl(mp, cmd, uid, arg, p) 746 struct mount *mp; 747 int cmd; 748 uid_t uid; 749 caddr_t arg; 750 struct proc *p; 751 { 752 753 return (EOPNOTSUPP); 754 } 755