1 /* $NetBSD: nfs_vfsops.c,v 1.35 1995/03/18 05:54:10 gwr 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, "/", 0, &vp); 201 printf("root on %s\n", &nd.nd_root.ndm_host); 202 203 /* 204 * Link it into the mount list. 205 */ 206 if (vfs_lock(mp)) 207 panic("nfs_mountroot: vfs_lock"); 208 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 209 mp->mnt_vnodecovered = NULLVP; 210 vfs_unlock(mp); 211 rootvp = vp; 212 213 /* Get root attributes (for the time). */ 214 error = VOP_GETATTR(vp, &attr, procp->p_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 (bdevvp(swapdev, &swapdev_vp)) 240 panic("nfs_mountroot: can't setup swap vp"); 241 if (swdevt[0].sw_dev != NODEV) { 242 printf("swap on device 0x%x\n", 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 printf("swap on %s\n", &nd.nd_swap.ndm_host); 253 254 /* 255 * Since the swap file is not the root dir of a file system, 256 * hack it to a regular file. 257 */ 258 vp->v_type = VREG; 259 vp->v_flag = 0; 260 swdevt[0].sw_vp = vp; 261 262 /* 263 * Find out how large the swap file is. 264 */ 265 error = VOP_GETATTR(vp, &attr, procp->p_ucred, procp); 266 if (error) 267 panic("nfs_mountroot: getattr for swap"); 268 n = (long) (attr.va_size >> DEV_BSHIFT); 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 args.flags = NFSMNT_RESVPORT; 309 310 #ifdef NFS_BOOT_OPTIONS 311 args.flags |= NFS_BOOT_OPTIONS; 312 #endif 313 #ifdef NFS_BOOT_RWSIZE 314 /* 315 * Reduce rsize,wsize for interfaces that consistently 316 * drop fragments of long UDP messages. (i.e. wd8003). 317 * You can always change these later via remount. 318 */ 319 args.flags |= NFSMNT_WSIZE | NFSMNT_RSIZE; 320 args.wsize = NFS_BOOT_RWSIZE; 321 args.rsize = NFS_BOOT_RWSIZE; 322 #endif 323 324 /* Get mbuf for server sockaddr. */ 325 m = m_get(M_WAIT, MT_SONAME); 326 if (m == NULL) 327 panic("nfs_mountroot: mget soname for %s", mntname); 328 bcopy((caddr_t)args.addr, mtod(m, caddr_t), 329 (m->m_len = args.addr->sa_len)); 330 331 if (error = mountnfs(&args, mp, m, mntname, args.hostname, vpp)) 332 panic("nfs_mountroot: mount %s failed: %d", mntname); 333 334 return (mp); 335 } 336 337 void 338 nfs_decode_args(nmp, argp) 339 struct nfsmount *nmp; 340 struct nfs_args *argp; 341 { 342 int s; 343 int adjsock; 344 345 s = splnet(); 346 347 /* Re-bind if rsrvd port requested and wasn't on one */ 348 adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT) 349 && (argp->flags & NFSMNT_RESVPORT); 350 351 /* Update flags atomically. Don't change the lock bits. */ 352 nmp->nm_flag = 353 (argp->flags & ~NFSMNT_INTERNAL) | (nmp->nm_flag & NFSMNT_INTERNAL); 354 splx(s); 355 356 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 357 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 358 if (nmp->nm_timeo < NFS_MINTIMEO) 359 nmp->nm_timeo = NFS_MINTIMEO; 360 else if (nmp->nm_timeo > NFS_MAXTIMEO) 361 nmp->nm_timeo = NFS_MAXTIMEO; 362 } 363 364 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 365 nmp->nm_retry = argp->retrans; 366 if (nmp->nm_retry > NFS_MAXREXMIT) 367 nmp->nm_retry = NFS_MAXREXMIT; 368 } 369 370 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 371 int osize = nmp->nm_wsize; 372 nmp->nm_wsize = argp->wsize; 373 /* Round down to multiple of blocksize */ 374 nmp->nm_wsize &= ~0x1ff; 375 if (nmp->nm_wsize <= 0) 376 nmp->nm_wsize = 512; 377 else if (nmp->nm_wsize > NFS_MAXDATA) 378 nmp->nm_wsize = NFS_MAXDATA; 379 adjsock |= (nmp->nm_wsize != osize); 380 } 381 if (nmp->nm_wsize > MAXBSIZE) 382 nmp->nm_wsize = MAXBSIZE; 383 384 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 385 int osize = nmp->nm_rsize; 386 nmp->nm_rsize = argp->rsize; 387 /* Round down to multiple of blocksize */ 388 nmp->nm_rsize &= ~0x1ff; 389 if (nmp->nm_rsize <= 0) 390 nmp->nm_rsize = 512; 391 else if (nmp->nm_rsize > NFS_MAXDATA) 392 nmp->nm_rsize = NFS_MAXDATA; 393 adjsock |= (nmp->nm_rsize != osize); 394 } 395 if (nmp->nm_rsize > MAXBSIZE) 396 nmp->nm_rsize = MAXBSIZE; 397 398 if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 && 399 argp->maxgrouplist <= NFS_MAXGRPS) 400 nmp->nm_numgrps = argp->maxgrouplist; 401 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 && 402 argp->readahead <= NFS_MAXRAHEAD) 403 nmp->nm_readahead = argp->readahead; 404 if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 && 405 argp->leaseterm <= NQ_MAXLEASE) 406 nmp->nm_leaseterm = argp->leaseterm; 407 if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 && 408 argp->deadthresh <= NQ_NEVERDEAD) 409 nmp->nm_deadthresh = argp->deadthresh; 410 411 if (nmp->nm_so && adjsock) { 412 nfs_disconnect(nmp); 413 if (nmp->nm_sotype == SOCK_DGRAM) 414 while (nfs_connect(nmp, (struct nfsreq *)0)) { 415 printf("nfs_args: retrying connect\n"); 416 (void) tsleep((caddr_t)&lbolt, 417 PSOCK, "nfscon", 0); 418 } 419 } 420 } 421 422 /* 423 * VFS Operations. 424 * 425 * mount system call 426 * It seems a bit dumb to copyinstr() the host and path here and then 427 * bcopy() them in mountnfs(), but I wanted to detect errors before 428 * doing the sockargs() call because sockargs() allocates an mbuf and 429 * an error after that means that I have to release the mbuf. 430 */ 431 /* ARGSUSED */ 432 int 433 nfs_mount(mp, path, data, ndp, p) 434 struct mount *mp; 435 char *path; 436 caddr_t data; 437 struct nameidata *ndp; 438 struct proc *p; 439 { 440 int error; 441 struct nfs_args args; 442 struct mbuf *nam; 443 struct vnode *vp; 444 char pth[MNAMELEN], hst[MNAMELEN]; 445 size_t len; 446 nfsv2fh_t nfh; 447 448 if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args))) 449 return (error); 450 if (mp->mnt_flag & MNT_UPDATE) { 451 register struct nfsmount *nmp = VFSTONFS(mp); 452 453 if (nmp == NULL) 454 return (EIO); 455 nfs_decode_args(nmp, &args); 456 return (0); 457 } 458 if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t))) 459 return (error); 460 if (error = copyinstr(path, pth, MNAMELEN-1, &len)) 461 return (error); 462 bzero(&pth[len], MNAMELEN - len); 463 if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) 464 return (error); 465 bzero(&hst[len], MNAMELEN - len); 466 /* sockargs() call must be after above copyin() calls */ 467 if (error = sockargs(&nam, (caddr_t)args.addr, 468 args.addrlen, MT_SONAME)) 469 return (error); 470 args.fh = &nfh; 471 error = mountnfs(&args, mp, nam, pth, hst, &vp); 472 return (error); 473 } 474 475 /* 476 * Common code for mount and mountroot 477 */ 478 int 479 mountnfs(argp, mp, nam, pth, hst, vpp) 480 register struct nfs_args *argp; 481 register struct mount *mp; 482 struct mbuf *nam; 483 char *pth, *hst; 484 struct vnode **vpp; 485 { 486 register struct nfsmount *nmp; 487 struct nfsnode *np; 488 int error; 489 490 if (mp->mnt_flag & MNT_UPDATE) { 491 nmp = VFSTONFS(mp); 492 /* update paths, file handles, etc, here XXX */ 493 m_freem(nam); 494 return (0); 495 } else { 496 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount), 497 M_NFSMNT, M_WAITOK); 498 bzero((caddr_t)nmp, sizeof (struct nfsmount)); 499 mp->mnt_data = (qaddr_t)nmp; 500 } 501 getnewfsid(mp, makefstype(MOUNT_NFS)); 502 nmp->nm_mountp = mp; 503 if ((argp->flags & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) == 504 (NFSMNT_NQNFS | NFSMNT_MYWRITE)) { 505 error = EPERM; 506 goto bad; 507 } 508 if (argp->flags & NFSMNT_NQNFS) 509 /* 510 * We have to set mnt_maxsymlink to a non-zero value so 511 * that COMPAT_43 routines will know that we are setting 512 * the d_type field in directories (and can zero it for 513 * unsuspecting binaries). 514 */ 515 mp->mnt_maxsymlinklen = 1; 516 nmp->nm_timeo = NFS_TIMEO; 517 nmp->nm_retry = NFS_RETRANS; 518 nmp->nm_wsize = NFS_WSIZE; 519 nmp->nm_rsize = NFS_RSIZE; 520 nmp->nm_numgrps = NFS_MAXGRPS; 521 nmp->nm_readahead = NFS_DEFRAHEAD; 522 nmp->nm_leaseterm = NQ_DEFLEASE; 523 nmp->nm_deadthresh = NQ_DEADTHRESH; 524 CIRCLEQ_INIT(&nmp->nm_timerhead); 525 nmp->nm_inprog = NULLVP; 526 bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); 527 #ifdef COMPAT_09 528 mp->mnt_stat.f_type = 2; 529 #else 530 mp->mnt_stat.f_type = 0; 531 #endif 532 strncpy(&mp->mnt_stat.f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN); 533 mp->mnt_stat.f_fstypename[MFSNAMELEN] = '\0'; 534 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 535 bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); 536 nmp->nm_nam = nam; 537 nfs_decode_args(nmp, argp); 538 539 /* Set up the sockets and per-host congestion */ 540 nmp->nm_sotype = argp->sotype; 541 nmp->nm_soproto = argp->proto; 542 543 /* 544 * For Connection based sockets (TCP,...) defer the connect until 545 * the first request, in case the server is not responding. 546 */ 547 if (nmp->nm_sotype == SOCK_DGRAM && 548 (error = nfs_connect(nmp, (struct nfsreq *)0))) 549 goto bad; 550 551 /* 552 * This is silly, but it has to be set so that vinifod() works. 553 * We do not want to do an nfs_statfs() here since we can get 554 * stuck on a dead server and we are holding a lock on the mount 555 * point. 556 */ 557 mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA; 558 /* 559 * A reference count is needed on the nfsnode representing the 560 * remote root. If this object is not persistent, then backward 561 * traversals of the mount point (i.e. "..") will not work if 562 * the nfsnode gets flushed out of the cache. Ufs does not have 563 * this problem, because one can identify root inodes by their 564 * number == ROOTINO (2). 565 */ 566 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 567 goto bad; 568 *vpp = NFSTOV(np); 569 570 return (0); 571 bad: 572 nfs_disconnect(nmp); 573 free((caddr_t)nmp, M_NFSMNT); 574 m_freem(nam); 575 return (error); 576 } 577 578 /* 579 * unmount system call 580 */ 581 int 582 nfs_unmount(mp, mntflags, p) 583 struct mount *mp; 584 int mntflags; 585 struct proc *p; 586 { 587 register struct nfsmount *nmp; 588 struct nfsnode *np; 589 struct vnode *vp; 590 int error, flags = 0; 591 extern int doforce; 592 593 if (mntflags & MNT_FORCE) 594 flags |= FORCECLOSE; 595 nmp = VFSTONFS(mp); 596 /* 597 * Goes something like this.. 598 * - Check for activity on the root vnode (other than ourselves). 599 * - Call vflush() to clear out vnodes for this file system, 600 * except for the root vnode. 601 * - Decrement reference on the vnode representing remote root. 602 * - Close the socket 603 * - Free up the data structures 604 */ 605 /* 606 * We need to decrement the ref. count on the nfsnode representing 607 * the remote root. See comment in mountnfs(). The VFS unmount() 608 * has done vput on this vnode, otherwise we would get deadlock! 609 */ 610 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 611 return(error); 612 vp = NFSTOV(np); 613 if (vp->v_usecount > 2) { 614 vput(vp); 615 return (EBUSY); 616 } 617 618 /* 619 * Must handshake with nqnfs_clientd() if it is active. 620 */ 621 nmp->nm_flag |= NFSMNT_DISMINPROG; 622 while (nmp->nm_inprog != NULLVP) 623 (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0); 624 if (error = vflush(mp, vp, flags)) { 625 vput(vp); 626 nmp->nm_flag &= ~NFSMNT_DISMINPROG; 627 return (error); 628 } 629 630 /* 631 * We are now committed to the unmount. 632 * For NQNFS, let the server daemon free the nfsmount structure. 633 */ 634 if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) 635 nmp->nm_flag |= NFSMNT_DISMNT; 636 637 /* 638 * There are two reference counts to get rid of here. 639 */ 640 vrele(vp); 641 vrele(vp); 642 vgone(vp); 643 nfs_disconnect(nmp); 644 m_freem(nmp->nm_nam); 645 646 if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0) 647 free((caddr_t)nmp, M_NFSMNT); 648 return (0); 649 } 650 651 /* 652 * Return root of a filesystem 653 */ 654 int 655 nfs_root(mp, vpp) 656 struct mount *mp; 657 struct vnode **vpp; 658 { 659 register struct vnode *vp; 660 struct nfsmount *nmp; 661 struct nfsnode *np; 662 int error; 663 664 nmp = VFSTONFS(mp); 665 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 666 return (error); 667 vp = NFSTOV(np); 668 vp->v_type = VDIR; 669 vp->v_flag = VROOT; 670 *vpp = vp; 671 return (0); 672 } 673 674 extern int syncprt; 675 676 /* 677 * Flush out the buffer cache 678 */ 679 /* ARGSUSED */ 680 int 681 nfs_sync(mp, waitfor, cred, p) 682 struct mount *mp; 683 int waitfor; 684 struct ucred *cred; 685 struct proc *p; 686 { 687 register struct vnode *vp; 688 int error, allerror = 0; 689 690 /* 691 * Force stale buffer cache information to be flushed. 692 */ 693 loop: 694 for (vp = mp->mnt_vnodelist.lh_first; 695 vp != NULL; 696 vp = vp->v_mntvnodes.le_next) { 697 /* 698 * If the vnode that we are about to sync is no longer 699 * associated with this mount point, start over. 700 */ 701 if (vp->v_mount != mp) 702 goto loop; 703 if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL) 704 continue; 705 if (vget(vp, 1)) 706 goto loop; 707 if (error = VOP_FSYNC(vp, cred, waitfor, p)) 708 allerror = error; 709 vput(vp); 710 } 711 return (allerror); 712 } 713 714 /* 715 * NFS flat namespace lookup. 716 * Currently unsupported. 717 */ 718 /* ARGSUSED */ 719 int 720 nfs_vget(mp, ino, vpp) 721 struct mount *mp; 722 ino_t ino; 723 struct vnode **vpp; 724 { 725 726 return (EOPNOTSUPP); 727 } 728 729 /* 730 * At this point, this should never happen 731 */ 732 /* ARGSUSED */ 733 int 734 nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 735 register struct mount *mp; 736 struct fid *fhp; 737 struct mbuf *nam; 738 struct vnode **vpp; 739 int *exflagsp; 740 struct ucred **credanonp; 741 { 742 743 return (EINVAL); 744 } 745 746 /* 747 * Vnode pointer to File handle, should never happen either 748 */ 749 /* ARGSUSED */ 750 int 751 nfs_vptofh(vp, fhp) 752 struct vnode *vp; 753 struct fid *fhp; 754 { 755 756 return (EINVAL); 757 } 758 759 /* 760 * Vfs start routine, a no-op. 761 */ 762 /* ARGSUSED */ 763 int 764 nfs_start(mp, flags, p) 765 struct mount *mp; 766 int flags; 767 struct proc *p; 768 { 769 770 return (0); 771 } 772 773 /* 774 * Do operations associated with quotas, not supported 775 */ 776 /* ARGSUSED */ 777 int 778 nfs_quotactl(mp, cmd, uid, arg, p) 779 struct mount *mp; 780 int cmd; 781 uid_t uid; 782 caddr_t arg; 783 struct proc *p; 784 { 785 786 return (EOPNOTSUPP); 787 } 788