1 /* $NetBSD: nfs_vfsops.c,v 1.60 1997/06/12 17:14:54 mrg Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993, 1995 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.12 (Berkeley) 5/20/95 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/device.h> 48 #include <sys/vnode.h> 49 #include <sys/kernel.h> 50 #include <sys/mount.h> 51 #include <sys/buf.h> 52 #include <sys/mbuf.h> 53 #include <sys/socket.h> 54 #include <sys/socketvar.h> 55 #include <sys/systm.h> 56 57 #include <net/if.h> 58 #include <net/route.h> 59 #include <netinet/in.h> 60 61 #include <nfs/rpcv2.h> 62 #include <nfs/nfsproto.h> 63 #include <nfs/nfsnode.h> 64 #include <nfs/nfs.h> 65 #include <nfs/nfsmount.h> 66 #include <nfs/xdr_subs.h> 67 #include <nfs/nfsm_subs.h> 68 #include <nfs/nfsdiskless.h> 69 #include <nfs/nqnfs.h> 70 #include <nfs/nfs_var.h> 71 72 extern struct nfsstats nfsstats; 73 extern int nfs_ticks; 74 75 #ifdef notyet 76 static int nfs_sysctl(int *, u_int, void *, size_t *, void *, size_t, 77 struct proc *); 78 #endif 79 80 /* 81 * nfs vfs operations. 82 */ 83 struct vfsops nfs_vfsops = { 84 MOUNT_NFS, 85 nfs_mount, 86 nfs_start, 87 nfs_unmount, 88 nfs_root, 89 nfs_quotactl, 90 nfs_statfs, 91 nfs_sync, 92 nfs_vget, 93 nfs_fhtovp, 94 nfs_vptofh, 95 nfs_vfs_init, 96 nfs_mountroot, 97 #ifdef notyet 98 nfs_sysctl 99 #endif 100 }; 101 102 extern u_int32_t nfs_procids[NFS_NPROCS]; 103 extern u_int32_t nfs_prog, nfs_vers; 104 105 static int 106 nfs_mount_diskless __P((struct nfs_dlmount *, const char *, 107 struct mount **, struct vnode **)); 108 109 #define TRUE 1 110 #define FALSE 0 111 112 /* 113 * nfs statfs call 114 */ 115 int 116 nfs_statfs(mp, sbp, p) 117 struct mount *mp; 118 register struct statfs *sbp; 119 struct proc *p; 120 { 121 register struct vnode *vp; 122 register struct nfs_statfs *sfp; 123 register caddr_t cp; 124 register u_int32_t *tl; 125 register int32_t t1, t2; 126 caddr_t bpos, dpos, cp2; 127 struct nfsmount *nmp = VFSTONFS(mp); 128 int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr; 129 struct mbuf *mreq, *mrep = NULL, *md, *mb, *mb2; 130 struct ucred *cred; 131 struct nfsnode *np; 132 u_quad_t tquad; 133 134 #ifndef nolint 135 sfp = (struct nfs_statfs *)0; 136 #endif 137 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np); 138 if (error) 139 return (error); 140 vp = NFSTOV(np); 141 cred = crget(); 142 cred->cr_ngroups = 0; 143 if (v3 && (nmp->nm_flag & NFSMNT_GOTFSINFO) == 0) 144 (void)nfs_fsinfo(nmp, vp, cred, p); 145 nfsstats.rpccnt[NFSPROC_FSSTAT]++; 146 nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3)); 147 nfsm_fhtom(vp, v3); 148 nfsm_request(vp, NFSPROC_FSSTAT, p, cred); 149 if (v3) 150 nfsm_postop_attr(vp, retattr); 151 if (error) { 152 if (mrep != NULL) 153 m_free(mrep); 154 goto nfsmout; 155 } 156 nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3)); 157 #ifdef COMPAT_09 158 sbp->f_type = 2; 159 #else 160 sbp->f_type = 0; 161 #endif 162 sbp->f_flags = nmp->nm_flag; 163 sbp->f_iosize = min(nmp->nm_rsize, nmp->nm_wsize); 164 if (v3) { 165 sbp->f_bsize = NFS_FABLKSIZE; 166 fxdr_hyper(&sfp->sf_tbytes, &tquad); 167 sbp->f_blocks = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE)); 168 fxdr_hyper(&sfp->sf_fbytes, &tquad); 169 sbp->f_bfree = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE)); 170 fxdr_hyper(&sfp->sf_abytes, &tquad); 171 sbp->f_bavail = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE)); 172 sbp->f_files = (fxdr_unsigned(int32_t, 173 sfp->sf_tfiles.nfsuquad[1]) & 0x7fffffff); 174 sbp->f_ffree = (fxdr_unsigned(int32_t, 175 sfp->sf_ffiles.nfsuquad[1]) & 0x7fffffff); 176 } else { 177 sbp->f_bsize = fxdr_unsigned(int32_t, sfp->sf_bsize); 178 sbp->f_blocks = fxdr_unsigned(int32_t, sfp->sf_blocks); 179 sbp->f_bfree = fxdr_unsigned(int32_t, sfp->sf_bfree); 180 sbp->f_bavail = fxdr_unsigned(int32_t, sfp->sf_bavail); 181 sbp->f_files = 0; 182 sbp->f_ffree = 0; 183 } 184 if (sbp != &mp->mnt_stat) { 185 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 186 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 187 } 188 strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN); 189 nfsm_reqdone; 190 vrele(vp); 191 crfree(cred); 192 return (error); 193 } 194 195 /* 196 * nfs version 3 fsinfo rpc call 197 */ 198 int 199 nfs_fsinfo(nmp, vp, cred, p) 200 register struct nfsmount *nmp; 201 register struct vnode *vp; 202 struct ucred *cred; 203 struct proc *p; 204 { 205 register struct nfsv3_fsinfo *fsp; 206 register caddr_t cp; 207 register int32_t t1, t2; 208 register u_int32_t *tl, pref, max; 209 caddr_t bpos, dpos, cp2; 210 int error = 0, retattr; 211 struct mbuf *mreq, *mrep, *md, *mb, *mb2; 212 213 nfsstats.rpccnt[NFSPROC_FSINFO]++; 214 nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1)); 215 nfsm_fhtom(vp, 1); 216 nfsm_request(vp, NFSPROC_FSINFO, p, cred); 217 nfsm_postop_attr(vp, retattr); 218 if (!error) { 219 nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO); 220 pref = fxdr_unsigned(u_int32_t, fsp->fs_wtpref); 221 if (pref < nmp->nm_wsize) 222 nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) & 223 ~(NFS_FABLKSIZE - 1); 224 max = fxdr_unsigned(u_int32_t, fsp->fs_wtmax); 225 if (max < nmp->nm_wsize) { 226 nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1); 227 if (nmp->nm_wsize == 0) 228 nmp->nm_wsize = max; 229 } 230 pref = fxdr_unsigned(u_int32_t, fsp->fs_rtpref); 231 if (pref < nmp->nm_rsize) 232 nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) & 233 ~(NFS_FABLKSIZE - 1); 234 max = fxdr_unsigned(u_int32_t, fsp->fs_rtmax); 235 if (max < nmp->nm_rsize) { 236 nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1); 237 if (nmp->nm_rsize == 0) 238 nmp->nm_rsize = max; 239 } 240 pref = fxdr_unsigned(u_int32_t, fsp->fs_dtpref); 241 if (pref < nmp->nm_readdirsize) 242 nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) & 243 ~(NFS_DIRBLKSIZ - 1); 244 if (max < nmp->nm_readdirsize) { 245 nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1); 246 if (nmp->nm_readdirsize == 0) 247 nmp->nm_readdirsize = max; 248 } 249 nmp->nm_flag |= NFSMNT_GOTFSINFO; 250 } 251 nfsm_reqdone; 252 return (error); 253 } 254 255 /* 256 * Mount a remote root fs via. NFS. It goes like this: 257 * - Call nfs_boot_init() to fill in the nfs_diskless struct 258 * - build the rootfs mount point and call mountnfs() to do the rest. 259 */ 260 int 261 nfs_mountroot() 262 { 263 struct nfs_diskless nd; 264 struct vattr attr; 265 struct mount *mp; 266 struct vnode *vp; 267 struct proc *procp; 268 long n; 269 int error; 270 271 procp = curproc; /* XXX */ 272 273 if (root_device->dv_class != DV_IFNET) 274 return (ENODEV); 275 276 /* 277 * XXX time must be non-zero when we init the interface or else 278 * the arp code will wedge. [Fixed now in if_ether.c] 279 * However, the NFS attribute cache gives false "hits" when 280 * time.tv_sec < NFS_ATTRTIMEO(np) so keep this in for now. 281 */ 282 if (time.tv_sec < NFS_MAXATTRTIMO) 283 time.tv_sec = NFS_MAXATTRTIMO; 284 285 /* 286 * Call nfs_boot_init() to fill in the nfs_diskless struct. 287 * Side effect: Finds and configures a network interface. 288 */ 289 bzero((caddr_t) &nd, sizeof(nd)); 290 error = nfs_boot_init(&nd, procp); 291 if (error) 292 return (error); 293 294 /* 295 * Create the root mount point. 296 */ 297 error = nfs_boot_getfh(&nd.nd_root); 298 if (error) 299 return (error); 300 error = nfs_mount_diskless(&nd.nd_root, "/", &mp, &vp); 301 if (error) 302 return (error); 303 printf("root on %s\n", nd.nd_root.ndm_host); 304 305 /* 306 * Link it into the mount list. 307 */ 308 #ifdef Lite2_integrated 309 simple_lock(&mountlist_slock); 310 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 311 simple_unlock(&mountlist_slock); 312 rootvp = vp; 313 vfs_unbusy(mp, procp); 314 #else 315 if (vfs_lock(mp)) 316 panic("nfs_mountroot: vfs_lock"); 317 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 318 mp->mnt_vnodecovered = NULLVP; 319 vfs_unlock(mp); 320 rootvp = vp; 321 #endif 322 323 /* Get root attributes (for the time). */ 324 error = VOP_GETATTR(vp, &attr, procp->p_ucred, procp); 325 if (error) 326 panic("nfs_mountroot: getattr for root"); 327 n = attr.va_mtime.tv_sec; 328 #ifdef DEBUG 329 printf("root time: 0x%lx\n", n); 330 #endif 331 inittodr(n); 332 333 #if 0 334 /* 335 * XXX splnet, so networks will receive... 336 * XXX What system needed this hack? 337 * XXX Should already be at spl0. 338 */ 339 splnet(); 340 #endif 341 342 #ifdef notyet 343 /* Set up swap credentials. */ 344 proc0.p_ucred->cr_uid = ntohl(nd.swap_ucred.cr_uid); 345 proc0.p_ucred->cr_gid = ntohl(nd.swap_ucred.cr_gid); 346 if ((proc0.p_ucred->cr_ngroups = ntohs(nd.swap_ucred.cr_ngroups)) > 347 NGROUPS) 348 proc0.p_ucred->cr_ngroups = NGROUPS; 349 for (i = 0; i < proc0.p_ucred->cr_ngroups; i++) 350 proc0.p_ucred->cr_groups[i] = ntohl(nd.swap_ucred.cr_groups[i]); 351 #endif 352 353 /* swap from outside now */ 354 #if 0 355 * "Mount" the swap device. 356 * 357 * On a "dataless" configuration (swap on disk) we will have: 358 * (swdevt[0].sw_dev != NODEV) identifying the swap device. 359 */ 360 if (bdevvp(swapdev, &swapdev_vp)) 361 panic("nfs_mountroot: can't setup swap vp"); 362 if (swdevt[0].sw_dev != NODEV) { 363 printf("swap on device 0x%x\n", swdevt[0].sw_dev); 364 return (0); 365 } 366 367 /* 368 * If swapping to an nfs node: (swdevt[0].sw_dev == NODEV) 369 * Create a fake mount point just for the swap vnode so that the 370 * swap file can be on a different server from the rootfs. 371 */ 372 if ((error = nfs_boot_getfh(&nd.nd_swap)) != 0) { 373 printf("nfs_boot: warning: getfh(swap), error=%d\n", error); 374 return (0); 375 } 376 error = nfs_mount_diskless(&nd.nd_swap, "/swap", &mp, &vp); 377 if (error) { 378 printf("nfs_boot: warning: mount(swap), error=%d\n", error); 379 return (0); 380 } 381 #ifdef Lite2_integrated 382 vfs_unbusy(mp, procp); 383 #endif 384 printf("swap on %s\n", nd.nd_swap.ndm_host); 385 386 /* 387 * Since the swap file is not the root dir of a file system, 388 * hack it to a regular file. 389 */ 390 vp->v_type = VREG; 391 vp->v_flag = 0; 392 swdevt[0].sw_vp = vp; 393 394 /* 395 * Find out how large the swap file is. 396 */ 397 error = VOP_GETATTR(vp, &attr, procp->p_ucred, procp); 398 if (error) 399 panic("nfs_mountroot: getattr for swap"); 400 n = (long) (attr.va_size >> DEV_BSHIFT); 401 #ifdef DEBUG 402 printf("swap size: 0x%lx (blocks)\n", n); 403 #endif 404 swdevt[0].sw_nblks = n; 405 #endif 406 407 return (0); 408 } 409 410 /* 411 * Internal version of mount system call for diskless setup. 412 */ 413 static int 414 nfs_mount_diskless(ndmntp, mntname, mpp, vpp) 415 struct nfs_dlmount *ndmntp; 416 const char *mntname; /* mount point name */ 417 struct mount **mpp; 418 struct vnode **vpp; 419 { 420 struct mount *mp; 421 struct mbuf *m; 422 int error; 423 424 #ifdef Lite2_integrated 425 vfs_rootmountalloc("nfs", mntname, &mp); 426 #else 427 /* Create the mount point. */ 428 mp = (struct mount *)malloc((u_long)sizeof(struct mount), 429 M_MOUNT, M_WAITOK); 430 bzero((char *)mp, (u_long)sizeof(struct mount)); 431 #endif 432 mp->mnt_op = &nfs_vfsops; 433 /* mp->mnt_flag = 0 */ 434 435 /* Get mbuf for server sockaddr. */ 436 m = m_get(M_WAIT, MT_SONAME); 437 if (m == NULL) 438 panic("nfs_mountroot: mget soname for %s", mntname); 439 bcopy((caddr_t)ndmntp->ndm_args.addr, mtod(m, caddr_t), 440 (m->m_len = ndmntp->ndm_args.addr->sa_len)); 441 442 error = mountnfs(&ndmntp->ndm_args, mp, m, mntname, 443 ndmntp->ndm_args.hostname, vpp); 444 if (error) { 445 printf("nfs_mountroot: mount %s failed: %d\n", 446 mntname, error); 447 free(mp, M_MOUNT); 448 } else 449 *mpp = mp; 450 451 return (error); 452 } 453 454 void 455 nfs_decode_args(nmp, argp) 456 struct nfsmount *nmp; 457 struct nfs_args *argp; 458 { 459 int s; 460 int adjsock; 461 int maxio; 462 463 s = splsoftnet(); 464 465 /* 466 * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes 467 * no sense in that context. 468 */ 469 if (argp->sotype == SOCK_STREAM) 470 argp->flags &= ~NFSMNT_NOCONN; 471 472 /* Re-bind if rsrvd port requested and wasn't on one */ 473 adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT) 474 && (argp->flags & NFSMNT_RESVPORT); 475 /* Also re-bind if we're switching to/from a connected UDP socket */ 476 adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) != 477 (argp->flags & NFSMNT_NOCONN)); 478 479 /* Update flags atomically. Don't change the lock bits. */ 480 nmp->nm_flag = 481 (argp->flags & ~NFSMNT_INTERNAL) | (nmp->nm_flag & NFSMNT_INTERNAL); 482 splx(s); 483 484 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 485 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 486 if (nmp->nm_timeo < NFS_MINTIMEO) 487 nmp->nm_timeo = NFS_MINTIMEO; 488 else if (nmp->nm_timeo > NFS_MAXTIMEO) 489 nmp->nm_timeo = NFS_MAXTIMEO; 490 } 491 492 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 493 nmp->nm_retry = argp->retrans; 494 if (nmp->nm_retry > NFS_MAXREXMIT) 495 nmp->nm_retry = NFS_MAXREXMIT; 496 } 497 498 if (argp->flags & NFSMNT_NFSV3) { 499 if (argp->sotype == SOCK_DGRAM) 500 maxio = NFS_MAXDGRAMDATA; 501 else 502 maxio = NFS_MAXDATA; 503 } else 504 maxio = NFS_V2MAXDATA; 505 506 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 507 int osize = nmp->nm_wsize; 508 nmp->nm_wsize = argp->wsize; 509 /* Round down to multiple of blocksize */ 510 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1); 511 if (nmp->nm_wsize <= 0) 512 nmp->nm_wsize = NFS_FABLKSIZE; 513 adjsock |= (nmp->nm_wsize != osize); 514 } 515 if (nmp->nm_wsize > maxio) 516 nmp->nm_wsize = maxio; 517 if (nmp->nm_wsize > MAXBSIZE) 518 nmp->nm_wsize = MAXBSIZE; 519 520 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 521 int osize = nmp->nm_rsize; 522 nmp->nm_rsize = argp->rsize; 523 /* Round down to multiple of blocksize */ 524 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1); 525 if (nmp->nm_rsize <= 0) 526 nmp->nm_rsize = NFS_FABLKSIZE; 527 adjsock |= (nmp->nm_rsize != osize); 528 } 529 if (nmp->nm_rsize > maxio) 530 nmp->nm_rsize = maxio; 531 if (nmp->nm_rsize > MAXBSIZE) 532 nmp->nm_rsize = MAXBSIZE; 533 534 if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { 535 nmp->nm_readdirsize = argp->readdirsize; 536 /* Round down to multiple of blocksize */ 537 nmp->nm_readdirsize &= ~(NFS_DIRBLKSIZ - 1); 538 if (nmp->nm_readdirsize < NFS_DIRBLKSIZ) 539 nmp->nm_readdirsize = NFS_DIRBLKSIZ; 540 } else if (argp->flags & NFSMNT_RSIZE) 541 nmp->nm_readdirsize = nmp->nm_rsize; 542 543 if (nmp->nm_readdirsize > maxio) 544 nmp->nm_readdirsize = maxio; 545 546 if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 && 547 argp->maxgrouplist <= NFS_MAXGRPS) 548 nmp->nm_numgrps = argp->maxgrouplist; 549 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 && 550 argp->readahead <= NFS_MAXRAHEAD) 551 nmp->nm_readahead = argp->readahead; 552 if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 && 553 argp->leaseterm <= NQ_MAXLEASE) 554 nmp->nm_leaseterm = argp->leaseterm; 555 if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 && 556 argp->deadthresh <= NQ_NEVERDEAD) 557 nmp->nm_deadthresh = argp->deadthresh; 558 559 adjsock |= ((nmp->nm_sotype != argp->sotype) || 560 (nmp->nm_soproto != argp->proto)); 561 nmp->nm_sotype = argp->sotype; 562 nmp->nm_soproto = argp->proto; 563 564 if (nmp->nm_so && adjsock) { 565 nfs_disconnect(nmp); 566 if (nmp->nm_sotype == SOCK_DGRAM) 567 while (nfs_connect(nmp, (struct nfsreq *)0)) { 568 printf("nfs_args: retrying connect\n"); 569 (void) tsleep((caddr_t)&lbolt, 570 PSOCK, "nfscon", 0); 571 } 572 } 573 } 574 575 /* 576 * VFS Operations. 577 * 578 * mount system call 579 * It seems a bit dumb to copyinstr() the host and path here and then 580 * bcopy() them in mountnfs(), but I wanted to detect errors before 581 * doing the sockargs() call because sockargs() allocates an mbuf and 582 * an error after that means that I have to release the mbuf. 583 */ 584 /* ARGSUSED */ 585 int 586 nfs_mount(mp, path, data, ndp, p) 587 struct mount *mp; 588 const char *path; 589 void *data; 590 struct nameidata *ndp; 591 struct proc *p; 592 { 593 int error; 594 struct nfs_args args; 595 struct mbuf *nam; 596 struct vnode *vp; 597 char pth[MNAMELEN], hst[MNAMELEN]; 598 size_t len; 599 u_char nfh[NFSX_V3FHMAX]; 600 601 error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)); 602 if (error) 603 return (error); 604 if (args.version != NFS_ARGSVERSION) 605 return (EPROGMISMATCH); 606 if (mp->mnt_flag & MNT_UPDATE) { 607 register struct nfsmount *nmp = VFSTONFS(mp); 608 609 if (nmp == NULL) 610 return (EIO); 611 /* 612 * When doing an update, we can't change from or to 613 * v3 and/or nqnfs. 614 */ 615 args.flags = (args.flags & ~(NFSMNT_NFSV3|NFSMNT_NQNFS)) | 616 (nmp->nm_flag & (NFSMNT_NFSV3|NFSMNT_NQNFS)); 617 nfs_decode_args(nmp, &args); 618 return (0); 619 } 620 error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize); 621 if (error) 622 return (error); 623 error = copyinstr(path, pth, MNAMELEN-1, &len); 624 if (error) 625 return (error); 626 bzero(&pth[len], MNAMELEN - len); 627 error = copyinstr(args.hostname, hst, MNAMELEN-1, &len); 628 if (error) 629 return (error); 630 bzero(&hst[len], MNAMELEN - len); 631 /* sockargs() call must be after above copyin() calls */ 632 error = sockargs(&nam, (caddr_t)args.addr, args.addrlen, MT_SONAME); 633 if (error) 634 return (error); 635 args.fh = nfh; 636 error = mountnfs(&args, mp, nam, pth, hst, &vp); 637 return (error); 638 } 639 640 /* 641 * Common code for mount and mountroot 642 */ 643 int 644 mountnfs(argp, mp, nam, pth, hst, vpp) 645 register struct nfs_args *argp; 646 register struct mount *mp; 647 struct mbuf *nam; 648 const char *pth, *hst; 649 struct vnode **vpp; 650 { 651 register struct nfsmount *nmp; 652 struct nfsnode *np; 653 int error; 654 struct vattr attrs; 655 656 if (mp->mnt_flag & MNT_UPDATE) { 657 nmp = VFSTONFS(mp); 658 /* update paths, file handles, etc, here XXX */ 659 m_freem(nam); 660 return (0); 661 } else { 662 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount), 663 M_NFSMNT, M_WAITOK); 664 bzero((caddr_t)nmp, sizeof (struct nfsmount)); 665 mp->mnt_data = (qaddr_t)nmp; 666 TAILQ_INIT(&nmp->nm_uidlruhead); 667 TAILQ_INIT(&nmp->nm_bufq); 668 } 669 #ifdef Lite2_integrated 670 vfs_getnewfsid(mp, makefstype(MOUNT_NFS)); 671 #else 672 getnewfsid(mp, makefstype(MOUNT_NFS)); 673 #endif 674 nmp->nm_mountp = mp; 675 if (argp->flags & NFSMNT_NQNFS) 676 /* 677 * We have to set mnt_maxsymlink to a non-zero value so 678 * that COMPAT_43 routines will know that we are setting 679 * the d_type field in directories (and can zero it for 680 * unsuspecting binaries). 681 */ 682 mp->mnt_maxsymlinklen = 1; 683 nmp->nm_timeo = NFS_TIMEO; 684 nmp->nm_retry = NFS_RETRANS; 685 nmp->nm_wsize = NFS_WSIZE; 686 nmp->nm_rsize = NFS_RSIZE; 687 nmp->nm_readdirsize = NFS_READDIRSIZE; 688 nmp->nm_numgrps = NFS_MAXGRPS; 689 nmp->nm_readahead = NFS_DEFRAHEAD; 690 nmp->nm_leaseterm = NQ_DEFLEASE; 691 nmp->nm_deadthresh = NQ_DEADTHRESH; 692 CIRCLEQ_INIT(&nmp->nm_timerhead); 693 nmp->nm_inprog = NULLVP; 694 nmp->nm_fhsize = argp->fhsize; 695 bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); 696 #ifdef COMPAT_09 697 mp->mnt_stat.f_type = 2; 698 #else 699 mp->mnt_stat.f_type = 0; 700 #endif 701 strncpy(&mp->mnt_stat.f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN); 702 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 703 bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); 704 nmp->nm_nam = nam; 705 706 /* Set up the sockets and per-host congestion */ 707 nmp->nm_sotype = argp->sotype; 708 nmp->nm_soproto = argp->proto; 709 710 nfs_decode_args(nmp, argp); 711 712 /* 713 * For Connection based sockets (TCP,...) defer the connect until 714 * the first request, in case the server is not responding. 715 */ 716 if (nmp->nm_sotype == SOCK_DGRAM && 717 (error = nfs_connect(nmp, (struct nfsreq *)0))) 718 goto bad; 719 720 /* 721 * This is silly, but it has to be set so that vinifod() works. 722 * We do not want to do an nfs_statfs() here since we can get 723 * stuck on a dead server and we are holding a lock on the mount 724 * point. 725 */ 726 mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA; 727 /* 728 * A reference count is needed on the nfsnode representing the 729 * remote root. If this object is not persistent, then backward 730 * traversals of the mount point (i.e. "..") will not work if 731 * the nfsnode gets flushed out of the cache. Ufs does not have 732 * this problem, because one can identify root inodes by their 733 * number == ROOTINO (2). 734 */ 735 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np); 736 if (error) 737 goto bad; 738 *vpp = NFSTOV(np); 739 VOP_GETATTR(*vpp, &attrs, curproc->p_ucred, curproc); /* XXX */ 740 741 return (0); 742 bad: 743 nfs_disconnect(nmp); 744 free((caddr_t)nmp, M_NFSMNT); 745 m_freem(nam); 746 return (error); 747 } 748 749 /* 750 * unmount system call 751 */ 752 int 753 nfs_unmount(mp, mntflags, p) 754 struct mount *mp; 755 int mntflags; 756 struct proc *p; 757 { 758 register struct nfsmount *nmp; 759 struct nfsnode *np; 760 struct vnode *vp; 761 int error, flags = 0; 762 763 if (mntflags & MNT_FORCE) 764 flags |= FORCECLOSE; 765 nmp = VFSTONFS(mp); 766 /* 767 * Goes something like this.. 768 * - Check for activity on the root vnode (other than ourselves). 769 * - Call vflush() to clear out vnodes for this file system, 770 * except for the root vnode. 771 * - Decrement reference on the vnode representing remote root. 772 * - Close the socket 773 * - Free up the data structures 774 */ 775 /* 776 * We need to decrement the ref. count on the nfsnode representing 777 * the remote root. See comment in mountnfs(). The VFS unmount() 778 * has done vput on this vnode, otherwise we would get deadlock! 779 */ 780 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np); 781 if (error) 782 return(error); 783 vp = NFSTOV(np); 784 if ((mntflags & MNT_FORCE) == 0 && vp->v_usecount > 2) { 785 vput(vp); 786 return (EBUSY); 787 } 788 789 /* 790 * Must handshake with nqnfs_clientd() if it is active. 791 */ 792 nmp->nm_flag |= NFSMNT_DISMINPROG; 793 while (nmp->nm_inprog != NULLVP) 794 (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0); 795 error = vflush(mp, vp, flags); 796 if (error) { 797 vput(vp); 798 nmp->nm_flag &= ~NFSMNT_DISMINPROG; 799 return (error); 800 } 801 802 /* 803 * We are now committed to the unmount. 804 * For NQNFS, let the server daemon free the nfsmount structure. 805 */ 806 if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) 807 nmp->nm_flag |= NFSMNT_DISMNT; 808 809 /* 810 * There are two reference counts to get rid of here. 811 */ 812 vrele(vp); 813 vrele(vp); 814 vgone(vp); 815 nfs_disconnect(nmp); 816 m_freem(nmp->nm_nam); 817 818 if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0) 819 free((caddr_t)nmp, M_NFSMNT); 820 return (0); 821 } 822 823 /* 824 * Return root of a filesystem 825 */ 826 int 827 nfs_root(mp, vpp) 828 struct mount *mp; 829 struct vnode **vpp; 830 { 831 register struct vnode *vp; 832 struct nfsmount *nmp; 833 struct nfsnode *np; 834 int error; 835 836 nmp = VFSTONFS(mp); 837 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np); 838 if (error) 839 return (error); 840 vp = NFSTOV(np); 841 if (vp->v_type == VNON) 842 vp->v_type = VDIR; 843 vp->v_flag = VROOT; 844 *vpp = vp; 845 return (0); 846 } 847 848 extern int syncprt; 849 850 /* 851 * Flush out the buffer cache 852 */ 853 /* ARGSUSED */ 854 int 855 nfs_sync(mp, waitfor, cred, p) 856 struct mount *mp; 857 int waitfor; 858 struct ucred *cred; 859 struct proc *p; 860 { 861 register struct vnode *vp; 862 int error, allerror = 0; 863 864 /* 865 * Force stale buffer cache information to be flushed. 866 */ 867 loop: 868 for (vp = mp->mnt_vnodelist.lh_first; 869 vp != NULL; 870 vp = vp->v_mntvnodes.le_next) { 871 /* 872 * If the vnode that we are about to sync is no longer 873 * associated with this mount point, start over. 874 */ 875 if (vp->v_mount != mp) 876 goto loop; 877 if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL) 878 continue; 879 #ifdef Lite2_integrated 880 if (vget(vp, LK_EXCLUSIVE, p)) 881 #else 882 if (vget(vp, 1)) 883 #endif 884 goto loop; 885 error = VOP_FSYNC(vp, cred, waitfor, p); 886 if (error) 887 allerror = error; 888 vput(vp); 889 } 890 return (allerror); 891 } 892 893 /* 894 * NFS flat namespace lookup. 895 * Currently unsupported. 896 */ 897 /* ARGSUSED */ 898 int 899 nfs_vget(mp, ino, vpp) 900 struct mount *mp; 901 ino_t ino; 902 struct vnode **vpp; 903 { 904 905 return (EOPNOTSUPP); 906 } 907 908 #ifdef notyet 909 /* 910 * Do that sysctl thang... 911 */ 912 static int 913 nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 914 size_t newlen, struct proc *p) 915 { 916 int rv; 917 918 /* 919 * All names at this level are terminal. 920 */ 921 if(namelen > 1) 922 return ENOTDIR; /* overloaded */ 923 924 switch(name[0]) { 925 case NFS_NFSSTATS: 926 if(!oldp) { 927 *oldlenp = sizeof nfsstats; 928 return 0; 929 } 930 931 if(*oldlenp < sizeof nfsstats) { 932 *oldlenp = sizeof nfsstats; 933 return ENOMEM; 934 } 935 936 rv = copyout(&nfsstats, oldp, sizeof nfsstats); 937 if(rv) return rv; 938 939 if(newp && newlen != sizeof nfsstats) 940 return EINVAL; 941 942 if(newp) { 943 return copyin(newp, &nfsstats, sizeof nfsstats); 944 } 945 return 0; 946 947 default: 948 return EOPNOTSUPP; 949 } 950 } 951 #endif 952 953 954 /* 955 * At this point, this should never happen 956 */ 957 /* ARGSUSED */ 958 int 959 nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 960 register struct mount *mp; 961 struct fid *fhp; 962 struct mbuf *nam; 963 struct vnode **vpp; 964 int *exflagsp; 965 struct ucred **credanonp; 966 { 967 968 return (EINVAL); 969 } 970 971 /* 972 * Vnode pointer to File handle, should never happen either 973 */ 974 /* ARGSUSED */ 975 int 976 nfs_vptofh(vp, fhp) 977 struct vnode *vp; 978 struct fid *fhp; 979 { 980 981 return (EINVAL); 982 } 983 984 /* 985 * Vfs start routine, a no-op. 986 */ 987 /* ARGSUSED */ 988 int 989 nfs_start(mp, flags, p) 990 struct mount *mp; 991 int flags; 992 struct proc *p; 993 { 994 995 return (0); 996 } 997 998 /* 999 * Do operations associated with quotas, not supported 1000 */ 1001 /* ARGSUSED */ 1002 int 1003 nfs_quotactl(mp, cmd, uid, arg, p) 1004 struct mount *mp; 1005 int cmd; 1006 uid_t uid; 1007 caddr_t arg; 1008 struct proc *p; 1009 { 1010 1011 return (EOPNOTSUPP); 1012 } 1013