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