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