82 83struct nfsstats nfsstats; 84SYSCTL_NODE(_vfs, OID_AUTO, nfs, CTLFLAG_RW, 0, "NFS filesystem"); 85SYSCTL_STRUCT(_vfs_nfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RD, 86 &nfsstats, nfsstats, "S,nfsstats"); 87#ifdef NFS_DEBUG 88int nfs_debug; 89SYSCTL_INT(_vfs_nfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0, ""); 90#endif 91 92static int nfs_iosize(struct nfsmount *nmp); 93static void nfs_decode_args(struct nfsmount *nmp, struct nfs_args *argp); 94static int mountnfs(struct nfs_args *, struct mount *, 95 struct sockaddr *, char *, char *, struct vnode **, 96 struct ucred *cred); 97static int nfs_mount(struct mount *mp, char *path, caddr_t data, 98 struct nameidata *ndp, struct thread *td); 99static int nfs_unmount(struct mount *mp, int mntflags, struct thread *td); 100static int nfs_root(struct mount *mp, struct vnode **vpp); 101static int nfs_statfs(struct mount *mp, struct statfs *sbp, 102 struct thread *td); 103static int nfs_sync(struct mount *mp, int waitfor, struct ucred *cred, 104 struct thread *td); 105 106/* 107 * nfs vfs operations. 108 */ 109static struct vfsops nfs_vfsops = { 110 nfs_mount, 111 vfs_stdstart, 112 nfs_unmount, 113 nfs_root, 114 vfs_stdquotactl, 115 nfs_statfs, 116 nfs_sync, 117 vfs_stdvget, 118 vfs_stdfhtovp, /* shouldn't happen */ 119 vfs_stdcheckexp, 120 vfs_stdvptofh, /* shouldn't happen */ 121 nfs_init, 122 nfs_uninit, 123 vfs_stdextattrctl, 124}; 125VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK); 126 127/* So that loader and kldload(2) can find us, wherever we are.. */ 128MODULE_VERSION(nfs, 1); 129 130/* 131 * This structure must be filled in by a primary bootstrap or bootstrap 132 * server for a diskless/dataless machine. It is initialized below just 133 * to ensure that it is allocated to initialized data (.data not .bss). 134 */ 135struct nfs_diskless nfs_diskless = { { { 0 } } }; 136struct nfsv3_diskless nfsv3_diskless = { { { 0 } } }; 137int nfs_diskless_valid = 0; 138 139SYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD, 140 &nfs_diskless_valid, 0, ""); 141 142SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD, 143 nfsv3_diskless.root_hostnam, 0, ""); 144 145SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD, 146 &nfsv3_diskless.root_saddr, sizeof nfsv3_diskless.root_saddr, 147 "%Ssockaddr_in", ""); 148 149SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_swappath, CTLFLAG_RD, 150 nfsv3_diskless.swap_hostnam, 0, ""); 151 152SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_swapaddr, CTLFLAG_RD, 153 &nfsv3_diskless.swap_saddr, sizeof nfsv3_diskless.swap_saddr, 154 "%Ssockaddr_in",""); 155 156 157void nfsargs_ntoh(struct nfs_args *); 158static int nfs_mountdiskless(char *, char *, int, 159 struct sockaddr_in *, struct nfs_args *, 160 struct thread *, struct vnode **, struct mount **); 161static void nfs_convert_diskless(void); 162static void nfs_convert_oargs(struct nfs_args *args, 163 struct onfs_args *oargs); 164 165static int 166nfs_iosize(struct nfsmount *nmp) 167{ 168 int iosize; 169 170 /* 171 * Calculate the size used for io buffers. Use the larger 172 * of the two sizes to minimise nfs requests but make sure 173 * that it is at least one VM page to avoid wasting buffer 174 * space. 175 */ 176 iosize = max(nmp->nm_rsize, nmp->nm_wsize); 177 if (iosize < PAGE_SIZE) iosize = PAGE_SIZE; 178 return iosize; 179} 180 181static void 182nfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs) 183{ 184 185 args->version = NFS_ARGSVERSION; 186 args->addr = oargs->addr; 187 args->addrlen = oargs->addrlen; 188 args->sotype = oargs->sotype; 189 args->proto = oargs->proto; 190 args->fh = oargs->fh; 191 args->fhsize = oargs->fhsize; 192 args->flags = oargs->flags; 193 args->wsize = oargs->wsize; 194 args->rsize = oargs->rsize; 195 args->readdirsize = oargs->readdirsize; 196 args->timeo = oargs->timeo; 197 args->retrans = oargs->retrans; 198 args->maxgrouplist = oargs->maxgrouplist; 199 args->readahead = oargs->readahead; 200 args->deadthresh = oargs->deadthresh; 201 args->hostname = oargs->hostname; 202} 203 204static void 205nfs_convert_diskless(void) 206{ 207 208 bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif, 209 sizeof(struct ifaliasreq)); 210 bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway, 211 sizeof(struct sockaddr_in)); 212 nfs_convert_oargs(&nfsv3_diskless.swap_args,&nfs_diskless.swap_args); 213 nfsv3_diskless.swap_fhsize = NFSX_V2FH; 214 bcopy(nfs_diskless.swap_fh, nfsv3_diskless.swap_fh, NFSX_V2FH); 215 bcopy(&nfs_diskless.swap_saddr,&nfsv3_diskless.swap_saddr, 216 sizeof(struct sockaddr_in)); 217 bcopy(nfs_diskless.swap_hostnam, nfsv3_diskless.swap_hostnam, MNAMELEN); 218 nfsv3_diskless.swap_nblks = nfs_diskless.swap_nblks; 219 bcopy(&nfs_diskless.swap_ucred, &nfsv3_diskless.swap_ucred, 220 sizeof(struct ucred)); 221 nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args); 222 nfsv3_diskless.root_fhsize = NFSX_V2FH; 223 bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH); 224 bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr, 225 sizeof(struct sockaddr_in)); 226 bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN); 227 nfsv3_diskless.root_time = nfs_diskless.root_time; 228 bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam, 229 MAXHOSTNAMELEN); 230 nfs_diskless_valid = 3; 231} 232 233/* 234 * nfs statfs call 235 */ 236int 237nfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td) 238{ 239 struct vnode *vp; 240 struct nfs_statfs *sfp; 241 caddr_t bpos, dpos; 242 struct nfsmount *nmp = VFSTONFS(mp); 243 int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr; 244 struct mbuf *mreq, *mrep, *md, *mb; 245 struct nfsnode *np; 246 u_quad_t tquad; 247 248#ifndef nolint 249 sfp = (struct nfs_statfs *)0; 250#endif 251 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np); 252 if (error) 253 return (error); 254 vp = NFSTOV(np); 255 if (v3 && (nmp->nm_state & NFSSTA_GOTFSINFO) == 0) 256 (void)nfs_fsinfo(nmp, vp, td->td_ucred, td); 257 nfsstats.rpccnt[NFSPROC_FSSTAT]++; 258 mreq = nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3)); 259 mb = mreq; 260 bpos = mtod(mb, caddr_t); 261 nfsm_fhtom(vp, v3); 262 nfsm_request(vp, NFSPROC_FSSTAT, td, td->td_ucred); 263 if (v3) 264 nfsm_postop_attr(vp, retattr); 265 if (error) { 266 if (mrep != NULL) 267 m_freem(mrep); 268 goto nfsmout; 269 } 270 sfp = nfsm_dissect(struct nfs_statfs *, NFSX_STATFS(v3)); 271 sbp->f_flags = nmp->nm_flag; 272 sbp->f_iosize = nfs_iosize(nmp); 273 if (v3) { 274 sbp->f_bsize = NFS_FABLKSIZE; 275 tquad = fxdr_hyper(&sfp->sf_tbytes); 276 sbp->f_blocks = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE)); 277 tquad = fxdr_hyper(&sfp->sf_fbytes); 278 sbp->f_bfree = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE)); 279 tquad = fxdr_hyper(&sfp->sf_abytes); 280 sbp->f_bavail = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE)); 281 sbp->f_files = (fxdr_unsigned(int32_t, 282 sfp->sf_tfiles.nfsuquad[1]) & 0x7fffffff); 283 sbp->f_ffree = (fxdr_unsigned(int32_t, 284 sfp->sf_ffiles.nfsuquad[1]) & 0x7fffffff); 285 } else { 286 sbp->f_bsize = fxdr_unsigned(int32_t, sfp->sf_bsize); 287 sbp->f_blocks = fxdr_unsigned(int32_t, sfp->sf_blocks); 288 sbp->f_bfree = fxdr_unsigned(int32_t, sfp->sf_bfree); 289 sbp->f_bavail = fxdr_unsigned(int32_t, sfp->sf_bavail); 290 sbp->f_files = 0; 291 sbp->f_ffree = 0; 292 } 293 if (sbp != &mp->mnt_stat) { 294 sbp->f_type = mp->mnt_vfc->vfc_typenum; 295 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 296 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 297 } 298 m_freem(mrep); 299nfsmout: 300 vput(vp); 301 return (error); 302} 303 304/* 305 * nfs version 3 fsinfo rpc call 306 */ 307int 308nfs_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred, 309 struct thread *td) 310{ 311 struct nfsv3_fsinfo *fsp; 312 u_int32_t pref, max; 313 caddr_t bpos, dpos; 314 int error = 0, retattr; 315 struct mbuf *mreq, *mrep, *md, *mb; 316 u_int64_t maxfsize; 317 318 nfsstats.rpccnt[NFSPROC_FSINFO]++; 319 mreq = nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1)); 320 mb = mreq; 321 bpos = mtod(mb, caddr_t); 322 nfsm_fhtom(vp, 1); 323 nfsm_request(vp, NFSPROC_FSINFO, td, cred); 324 nfsm_postop_attr(vp, retattr); 325 if (!error) { 326 fsp = nfsm_dissect(struct nfsv3_fsinfo *, NFSX_V3FSINFO); 327 pref = fxdr_unsigned(u_int32_t, fsp->fs_wtpref); 328 if (pref < nmp->nm_wsize && pref >= NFS_FABLKSIZE) 329 nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) & 330 ~(NFS_FABLKSIZE - 1); 331 max = fxdr_unsigned(u_int32_t, fsp->fs_wtmax); 332 if (max < nmp->nm_wsize && max > 0) { 333 nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1); 334 if (nmp->nm_wsize == 0) 335 nmp->nm_wsize = max; 336 } 337 pref = fxdr_unsigned(u_int32_t, fsp->fs_rtpref); 338 if (pref < nmp->nm_rsize && pref >= NFS_FABLKSIZE) 339 nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) & 340 ~(NFS_FABLKSIZE - 1); 341 max = fxdr_unsigned(u_int32_t, fsp->fs_rtmax); 342 if (max < nmp->nm_rsize && max > 0) { 343 nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1); 344 if (nmp->nm_rsize == 0) 345 nmp->nm_rsize = max; 346 } 347 pref = fxdr_unsigned(u_int32_t, fsp->fs_dtpref); 348 if (pref < nmp->nm_readdirsize && pref >= NFS_DIRBLKSIZ) 349 nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) & 350 ~(NFS_DIRBLKSIZ - 1); 351 if (max < nmp->nm_readdirsize && max > 0) { 352 nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1); 353 if (nmp->nm_readdirsize == 0) 354 nmp->nm_readdirsize = max; 355 } 356 maxfsize = fxdr_hyper(&fsp->fs_maxfilesize); 357 if (maxfsize > 0 && maxfsize < nmp->nm_maxfilesize) 358 nmp->nm_maxfilesize = maxfsize; 359 nmp->nm_state |= NFSSTA_GOTFSINFO; 360 } 361 m_freem(mrep); 362nfsmout: 363 return (error); 364} 365 366/* 367 * Mount a remote root fs via. nfs. This depends on the info in the 368 * nfs_diskless structure that has been filled in properly by some primary 369 * bootstrap. 370 * It goes something like this: 371 * - do enough of "ifconfig" by calling ifioctl() so that the system 372 * can talk to the server 373 * - If nfs_diskless.mygateway is filled in, use that address as 374 * a default gateway. 375 * - build the rootfs mount point and call mountnfs() to do the rest. 376 */ 377int 378nfs_mountroot(struct mount *mp, struct thread *td) 379{ 380 struct mount *swap_mp; 381 struct nfsv3_diskless *nd = &nfsv3_diskless; 382 struct socket *so; 383 struct vnode *vp; 384 int error, i; 385 u_long l; 386 char buf[128]; 387 388#if defined(BOOTP_NFSROOT) && defined(BOOTP) 389 bootpc_init(); /* use bootp to get nfs_diskless filled in */ 390#endif 391 392 /* 393 * XXX time must be non-zero when we init the interface or else 394 * the arp code will wedge... 395 */ 396 while (time_second == 0) 397 tsleep(&time_second, PZERO+8, "arpkludge", 10); 398 399 if (nfs_diskless_valid==1) 400 nfs_convert_diskless(); 401 402 /* 403 * XXX splnet, so networks will receive... 404 */ 405 splnet(); 406 407#ifdef notyet 408 /* Set up swap credentials. */ 409 proc0.p_ucred->cr_uid = ntohl(nd->swap_ucred.cr_uid); 410 proc0.p_ucred->cr_gid = ntohl(nd->swap_ucred.cr_gid); 411 if ((proc0.p_ucred->cr_ngroups = ntohs(nd->swap_ucred.cr_ngroups)) > 412 NGROUPS) 413 proc0.p_ucred->cr_ngroups = NGROUPS; 414 for (i = 0; i < proc0.p_ucred->cr_ngroups; i++) 415 proc0.p_ucred->cr_groups[i] = ntohl(nd->swap_ucred.cr_groups[i]); 416#endif 417 418 /* 419 * Do enough of ifconfig(8) so that the critical net interface can 420 * talk to the server. 421 */ 422 error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0, 423 td->td_ucred, td); 424 if (error) 425 panic("nfs_mountroot: socreate(%04x): %d", 426 nd->myif.ifra_addr.sa_family, error); 427 428#if 0 /* XXX Bad idea */ 429 /* 430 * We might not have been told the right interface, so we pass 431 * over the first ten interfaces of the same kind, until we get 432 * one of them configured. 433 */ 434 435 for (i = strlen(nd->myif.ifra_name) - 1; 436 nd->myif.ifra_name[i] >= '0' && 437 nd->myif.ifra_name[i] <= '9'; 438 nd->myif.ifra_name[i] ++) { 439 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 440 if(!error) 441 break; 442 } 443#endif 444 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 445 if (error) 446 panic("nfs_mountroot: SIOCAIFADDR: %d", error); 447 soclose(so); 448 449 /* 450 * If the gateway field is filled in, set it as the default route. 451 */ 452 if (nd->mygateway.sin_len != 0) { 453 struct sockaddr_in mask, sin; 454 455 bzero((caddr_t)&mask, sizeof(mask)); 456 sin = mask; 457 sin.sin_family = AF_INET; 458 sin.sin_len = sizeof(sin); 459 error = rtrequest(RTM_ADD, (struct sockaddr *)&sin, 460 (struct sockaddr *)&nd->mygateway, 461 (struct sockaddr *)&mask, 462 RTF_UP | RTF_GATEWAY, (struct rtentry **)0); 463 if (error) 464 panic("nfs_mountroot: RTM_ADD: %d", error); 465 } 466 467 /* 468 * Create the rootfs mount point. 469 */ 470 nd->root_args.fh = nd->root_fh; 471 nd->root_args.fhsize = nd->root_fhsize; 472 l = ntohl(nd->root_saddr.sin_addr.s_addr); 473 snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", 474 (l >> 24) & 0xff, (l >> 16) & 0xff, 475 (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam); 476 printf("NFS ROOT: %s\n", buf); 477 if ((error = nfs_mountdiskless(buf, "/", MNT_RDONLY, 478 &nd->root_saddr, &nd->root_args, td, &vp, &mp)) != 0) { 479 if (swap_mp) { 480 mp->mnt_vfc->vfc_refcount--; 481 free(swap_mp, M_MOUNT); 482 } 483 return (error); 484 } 485 486 swap_mp = NULL; 487 if (nd->swap_nblks) { 488 489 /* Convert to DEV_BSIZE instead of Kilobyte */ 490 nd->swap_nblks *= 2; 491 492 /* 493 * Create a fake mount point just for the swap vnode so that the 494 * swap file can be on a different server from the rootfs. 495 */ 496 nd->swap_args.fh = nd->swap_fh; 497 nd->swap_args.fhsize = nd->swap_fhsize; 498 l = ntohl(nd->swap_saddr.sin_addr.s_addr); 499 snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", 500 (l >> 24) & 0xff, (l >> 16) & 0xff, 501 (l >> 8) & 0xff, (l >> 0) & 0xff, nd->swap_hostnam); 502 printf("NFS SWAP: %s\n", buf); 503 if ((error = nfs_mountdiskless(buf, "/swap", 0, 504 &nd->swap_saddr, &nd->swap_args, td, &vp, &swap_mp)) != 0) 505 return (error); 506 vfs_unbusy(swap_mp, td); 507 508 VTONFS(vp)->n_size = VTONFS(vp)->n_vattr.va_size = 509 nd->swap_nblks * DEV_BSIZE ; 510 /* 511 * Since the swap file is not the root dir of a file system, 512 * hack it to a regular file. 513 */ 514 vp->v_type = VREG; 515 vp->v_flag = 0; 516 VREF(vp); 517 swaponvp(td, vp, NODEV, nd->swap_nblks); 518 } 519 520 mp->mnt_flag |= MNT_ROOTFS; 521 mp->mnt_vnodecovered = NULLVP; 522 rootvp = vp; 523 vfs_unbusy(mp, td); 524 525 /* 526 * This is not really an nfs issue, but it is much easier to 527 * set hostname here and then let the "/etc/rc.xxx" files 528 * mount the right /var based upon its preset value. 529 */ 530 bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN); 531 hostname[MAXHOSTNAMELEN - 1] = '\0'; 532 for (i = 0; i < MAXHOSTNAMELEN; i++) 533 if (hostname[i] == '\0') 534 break; 535 inittodr(ntohl(nd->root_time)); 536 return (0); 537} 538 539/* 540 * Internal version of mount system call for diskless setup. 541 */ 542static int 543nfs_mountdiskless(char *path, char *which, int mountflag, 544 struct sockaddr_in *sin, struct nfs_args *args, struct thread *td, 545 struct vnode **vpp, struct mount **mpp) 546{ 547 struct mount *mp; 548 struct sockaddr *nam; 549 int error; 550 551 mp = *mpp; 552 553 if (!mp && (error = vfs_rootmountalloc("nfs", path, &mp))) { 554 printf("nfs_mountroot: NFS not configured"); 555 return (error); 556 } 557 558 mp->mnt_kern_flag = 0; 559 mp->mnt_flag = mountflag; 560 nam = dup_sockaddr((struct sockaddr *)sin, 1); 561 if ((error = mountnfs(args, mp, nam, which, path, vpp, 562 td->td_ucred)) != 0) { 563 printf("nfs_mountroot: mount %s on %s: %d", path, which, error); 564 mp->mnt_vfc->vfc_refcount--; 565 vfs_unbusy(mp, td); 566 free(mp, M_MOUNT); 567 FREE(nam, M_SONAME); 568 return (error); 569 } 570 (void) copystr(which, mp->mnt_stat.f_mntonname, MNAMELEN - 1, 0); 571 *mpp = mp; 572 return (0); 573} 574 575static void 576nfs_decode_args(struct nfsmount *nmp, struct nfs_args *argp) 577{ 578 int s; 579 int adjsock; 580 int maxio; 581 582 s = splnet(); 583 /* 584 * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes 585 * no sense in that context. 586 */ 587 if (argp->sotype == SOCK_STREAM) 588 nmp->nm_flag &= ~NFSMNT_NOCONN; 589 590 /* Also clear RDIRPLUS if not NFSv3, it crashes some servers */ 591 if ((argp->flags & NFSMNT_NFSV3) == 0) 592 nmp->nm_flag &= ~NFSMNT_RDIRPLUS; 593 594 /* Re-bind if rsrvd port requested and wasn't on one */ 595 adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT) 596 && (argp->flags & NFSMNT_RESVPORT); 597 /* Also re-bind if we're switching to/from a connected UDP socket */ 598 adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) != 599 (argp->flags & NFSMNT_NOCONN)); 600 601 /* Update flags atomically. Don't change the lock bits. */ 602 nmp->nm_flag = argp->flags | nmp->nm_flag; 603 splx(s); 604 605 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 606 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 607 if (nmp->nm_timeo < NFS_MINTIMEO) 608 nmp->nm_timeo = NFS_MINTIMEO; 609 else if (nmp->nm_timeo > NFS_MAXTIMEO) 610 nmp->nm_timeo = NFS_MAXTIMEO; 611 } 612 613 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 614 nmp->nm_retry = argp->retrans; 615 if (nmp->nm_retry > NFS_MAXREXMIT) 616 nmp->nm_retry = NFS_MAXREXMIT; 617 } 618 619 if (argp->flags & NFSMNT_NFSV3) { 620 if (argp->sotype == SOCK_DGRAM) 621 maxio = NFS_MAXDGRAMDATA; 622 else 623 maxio = NFS_MAXDATA; 624 } else 625 maxio = NFS_V2MAXDATA; 626 627 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 628 nmp->nm_wsize = argp->wsize; 629 /* Round down to multiple of blocksize */ 630 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1); 631 if (nmp->nm_wsize <= 0) 632 nmp->nm_wsize = NFS_FABLKSIZE; 633 } 634 if (nmp->nm_wsize > maxio) 635 nmp->nm_wsize = maxio; 636 if (nmp->nm_wsize > MAXBSIZE) 637 nmp->nm_wsize = MAXBSIZE; 638 639 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 640 nmp->nm_rsize = argp->rsize; 641 /* Round down to multiple of blocksize */ 642 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1); 643 if (nmp->nm_rsize <= 0) 644 nmp->nm_rsize = NFS_FABLKSIZE; 645 } 646 if (nmp->nm_rsize > maxio) 647 nmp->nm_rsize = maxio; 648 if (nmp->nm_rsize > MAXBSIZE) 649 nmp->nm_rsize = MAXBSIZE; 650 651 if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { 652 nmp->nm_readdirsize = argp->readdirsize; 653 } 654 if (nmp->nm_readdirsize > maxio) 655 nmp->nm_readdirsize = maxio; 656 if (nmp->nm_readdirsize > nmp->nm_rsize) 657 nmp->nm_readdirsize = nmp->nm_rsize; 658 659 if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0) 660 nmp->nm_acregmin = argp->acregmin; 661 else 662 nmp->nm_acregmin = NFS_MINATTRTIMO; 663 if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0) 664 nmp->nm_acregmax = argp->acregmax; 665 else 666 nmp->nm_acregmax = NFS_MAXATTRTIMO; 667 if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0) 668 nmp->nm_acdirmin = argp->acdirmin; 669 else 670 nmp->nm_acdirmin = NFS_MINDIRATTRTIMO; 671 if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0) 672 nmp->nm_acdirmax = argp->acdirmax; 673 else 674 nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO; 675 if (nmp->nm_acdirmin > nmp->nm_acdirmax) 676 nmp->nm_acdirmin = nmp->nm_acdirmax; 677 if (nmp->nm_acregmin > nmp->nm_acregmax) 678 nmp->nm_acregmin = nmp->nm_acregmax; 679 680 if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0) { 681 if (argp->maxgrouplist <= NFS_MAXGRPS) 682 nmp->nm_numgrps = argp->maxgrouplist; 683 else 684 nmp->nm_numgrps = NFS_MAXGRPS; 685 } 686 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) { 687 if (argp->readahead <= NFS_MAXRAHEAD) 688 nmp->nm_readahead = argp->readahead; 689 else 690 nmp->nm_readahead = NFS_MAXRAHEAD; 691 } 692 if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 0) { 693 if (argp->deadthresh <= NFS_MAXDEADTHRESH) 694 nmp->nm_deadthresh = argp->deadthresh; 695 else 696 nmp->nm_deadthresh = NFS_MAXDEADTHRESH; 697 } 698 699 adjsock |= ((nmp->nm_sotype != argp->sotype) || 700 (nmp->nm_soproto != argp->proto)); 701 nmp->nm_sotype = argp->sotype; 702 nmp->nm_soproto = argp->proto; 703 704 if (nmp->nm_so && adjsock) { 705 nfs_safedisconnect(nmp); 706 if (nmp->nm_sotype == SOCK_DGRAM) 707 while (nfs_connect(nmp, (struct nfsreq *)0)) { 708 printf("nfs_args: retrying connect\n"); 709 (void) tsleep((caddr_t)&lbolt, 710 PSOCK, "nfscon", 0); 711 } 712 } 713} 714 715/* 716 * VFS Operations. 717 * 718 * mount system call 719 * It seems a bit dumb to copyinstr() the host and path here and then 720 * bcopy() them in mountnfs(), but I wanted to detect errors before 721 * doing the sockargs() call because sockargs() allocates an mbuf and 722 * an error after that means that I have to release the mbuf. 723 */ 724/* ARGSUSED */ 725static int 726nfs_mount(struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, 727 struct thread *td) 728{ 729 int error; 730 struct nfs_args args; 731 struct sockaddr *nam; 732 struct vnode *vp; 733 char hst[MNAMELEN]; 734 size_t len; 735 u_char nfh[NFSX_V3FHMAX]; 736 737 if (path == NULL) { 738 nfs_mountroot(mp, td); 739 return (0); 740 } 741 error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)); 742 if (error) 743 return (error); 744 if (args.version != NFS_ARGSVERSION) { 745#ifdef COMPAT_PRELITE2 746 /* 747 * If the argument version is unknown, then assume the 748 * caller is a pre-lite2 4.4BSD client and convert its 749 * arguments. 750 */ 751 struct onfs_args oargs; 752 error = copyin(data, (caddr_t)&oargs, sizeof (struct onfs_args)); 753 if (error) 754 return (error); 755 nfs_convert_oargs(&args,&oargs); 756#else /* !COMPAT_PRELITE2 */ 757 return (EPROGMISMATCH); 758#endif /* COMPAT_PRELITE2 */ 759 } 760 if (mp->mnt_flag & MNT_UPDATE) { 761 struct nfsmount *nmp = VFSTONFS(mp); 762 763 if (nmp == NULL) 764 return (EIO); 765 /* 766 * When doing an update, we can't change from or to 767 * v3, switch lockd strategies or change cookie translation 768 */ 769 args.flags = (args.flags & 770 ~(NFSMNT_NFSV3 | NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) | 771 (nmp->nm_flag & 772 (NFSMNT_NFSV3 | NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)); 773 nfs_decode_args(nmp, &args); 774 return (0); 775 } 776 if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) 777 return (EINVAL); 778 error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize); 779 if (error) 780 return (error); 781 error = copyinstr(args.hostname, hst, MNAMELEN-1, &len); 782 if (error) 783 return (error); 784 bzero(&hst[len], MNAMELEN - len); 785 /* sockargs() call must be after above copyin() calls */ 786 error = getsockaddr(&nam, (caddr_t)args.addr, args.addrlen); 787 if (error) 788 return (error); 789 args.fh = nfh; 790 error = mountnfs(&args, mp, nam, path, hst, &vp, td->td_ucred); 791 return (error); 792} 793 794/* 795 * Common code for mount and mountroot 796 */ 797static int 798mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, 799 char *pth, char *hst, struct vnode **vpp, struct ucred *cred) 800{ 801 struct nfsmount *nmp; 802 struct nfsnode *np; 803 int error; 804 struct vattr attrs; 805 806 if (mp->mnt_flag & MNT_UPDATE) { 807 nmp = VFSTONFS(mp); 808 /* update paths, file handles, etc, here XXX */ 809 FREE(nam, M_SONAME); 810 return (0); 811 } else {
|