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