1 /* $OpenBSD: nfs_vfsops.c,v 1.37 2001/07/27 05:43:17 csapuntz Exp $ */ 2 /* $NetBSD: nfs_vfsops.c,v 1.46.4.1 1996/05/25 22:40:35 fvdl Exp $ */ 3 4 /* 5 * Copyright (c) 1989, 1993, 1995 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Rick Macklem at The University of Guelph. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95 40 */ 41 42 #include <sys/param.h> 43 #include <sys/conf.h> 44 #include <sys/ioctl.h> 45 #include <sys/signal.h> 46 #include <sys/proc.h> 47 #include <sys/namei.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 #include <sys/sysctl.h> 57 58 #include <net/if.h> 59 #include <net/route.h> 60 #include <netinet/in.h> 61 62 #include <nfs/rpcv2.h> 63 #include <nfs/nfsproto.h> 64 #include <nfs/nfsnode.h> 65 #include <nfs/nfs.h> 66 #include <nfs/nfsmount.h> 67 #include <nfs/xdr_subs.h> 68 #include <nfs/nfsm_subs.h> 69 #include <nfs/nfsdiskless.h> 70 #include <nfs/nfs_var.h> 71 72 #define NQ_DEADTHRESH NQ_NEVERDEAD /* Default nm_deadthresh */ 73 #define NQ_NEVERDEAD 9 /* Greater than max. nm_timeouts */ 74 75 extern struct nfsstats nfsstats; 76 extern int nfs_ticks; 77 78 int nfs_sysctl 79 __P((int *, u_int, void *, size_t *, void *, size_t, struct proc *)); 80 int nfs_checkexp 81 __P((struct mount *mp, struct mbuf *nam, 82 int *extflagsp, struct ucred **credanonp)); 83 84 /* 85 * nfs vfs operations. 86 */ 87 struct vfsops nfs_vfsops = { 88 nfs_mount, 89 nfs_start, 90 nfs_unmount, 91 nfs_root, 92 nfs_quotactl, 93 nfs_statfs, 94 nfs_sync, 95 nfs_vget, 96 nfs_fhtovp, 97 nfs_vptofh, 98 nfs_vfs_init, 99 nfs_sysctl, 100 nfs_checkexp 101 }; 102 103 extern u_int32_t nfs_procids[NFS_NPROCS]; 104 extern u_int32_t nfs_prog, nfs_vers; 105 106 struct mount *nfs_mount_diskless 107 __P((struct nfs_dlmount *, char *, int)); 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 = NULL; 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 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np); 135 if (error) 136 return (error); 137 vp = NFSTOV(np); 138 cred = crget(); 139 cred->cr_ngroups = 0; 140 if (v3 && (nmp->nm_flag & NFSMNT_GOTFSINFO) == 0) 141 (void)nfs_fsinfo(nmp, vp, cred, p); 142 nfsstats.rpccnt[NFSPROC_FSSTAT]++; 143 nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3)); 144 nfsm_fhtom(vp, v3); 145 nfsm_request(vp, NFSPROC_FSSTAT, p, cred); 146 if (v3) 147 nfsm_postop_attr(vp, retattr); 148 if (error) { 149 if (mrep != NULL) 150 m_free(mrep); 151 goto nfsmout; 152 } 153 nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3)); 154 sbp->f_flags = nmp->nm_flag; 155 sbp->f_iosize = min(nmp->nm_rsize, nmp->nm_wsize); 156 if (v3) { 157 sbp->f_bsize = NFS_FABLKSIZE; 158 tquad = fxdr_hyper(&sfp->sf_tbytes); 159 sbp->f_blocks = (u_int32_t)(tquad / (u_quad_t)NFS_FABLKSIZE); 160 tquad = fxdr_hyper(&sfp->sf_fbytes); 161 sbp->f_bfree = (u_int32_t)(tquad / (u_quad_t)NFS_FABLKSIZE); 162 tquad = fxdr_hyper(&sfp->sf_abytes); 163 sbp->f_bavail = (int32_t)((quad_t)tquad / (quad_t)NFS_FABLKSIZE); 164 sbp->f_files = (fxdr_unsigned(int32_t, 165 sfp->sf_tfiles.nfsuquad[1]) & 0x7fffffff); 166 sbp->f_ffree = (fxdr_unsigned(int32_t, 167 sfp->sf_ffiles.nfsuquad[1]) & 0x7fffffff); 168 } else { 169 sbp->f_bsize = fxdr_unsigned(int32_t, sfp->sf_bsize); 170 sbp->f_blocks = fxdr_unsigned(int32_t, sfp->sf_blocks); 171 sbp->f_bfree = fxdr_unsigned(int32_t, sfp->sf_bfree); 172 sbp->f_bavail = fxdr_unsigned(int32_t, sfp->sf_bavail); 173 sbp->f_files = 0; 174 sbp->f_ffree = 0; 175 } 176 if (sbp != &mp->mnt_stat) { 177 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 178 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 179 bcopy(&mp->mnt_stat.mount_info.nfs_args, 180 &sbp->mount_info.nfs_args, sizeof(struct nfs_args)); 181 } 182 strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN); 183 nfsm_reqdone; 184 vrele(vp); 185 crfree(cred); 186 return (error); 187 } 188 189 /* 190 * nfs version 3 fsinfo rpc call 191 */ 192 int 193 nfs_fsinfo(nmp, vp, cred, p) 194 register struct nfsmount *nmp; 195 register struct vnode *vp; 196 struct ucred *cred; 197 struct proc *p; 198 { 199 register struct nfsv3_fsinfo *fsp; 200 register caddr_t cp; 201 register int32_t t1, t2; 202 register u_int32_t *tl, pref, max; 203 caddr_t bpos, dpos, cp2; 204 int error = 0, retattr; 205 struct mbuf *mreq, *mrep, *md, *mb, *mb2; 206 207 nfsstats.rpccnt[NFSPROC_FSINFO]++; 208 nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1)); 209 nfsm_fhtom(vp, 1); 210 nfsm_request(vp, NFSPROC_FSINFO, p, cred); 211 nfsm_postop_attr(vp, retattr); 212 if (!error) { 213 nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO); 214 pref = fxdr_unsigned(u_int32_t, fsp->fs_wtpref); 215 if (pref < nmp->nm_wsize) 216 nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) & 217 ~(NFS_FABLKSIZE - 1); 218 max = fxdr_unsigned(u_int32_t, fsp->fs_wtmax); 219 if (max < nmp->nm_wsize) { 220 nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1); 221 if (nmp->nm_wsize == 0) 222 nmp->nm_wsize = max; 223 } 224 pref = fxdr_unsigned(u_int32_t, fsp->fs_rtpref); 225 if (pref < nmp->nm_rsize) 226 nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) & 227 ~(NFS_FABLKSIZE - 1); 228 max = fxdr_unsigned(u_int32_t, fsp->fs_rtmax); 229 if (max < nmp->nm_rsize) { 230 nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1); 231 if (nmp->nm_rsize == 0) 232 nmp->nm_rsize = max; 233 } 234 pref = fxdr_unsigned(u_int32_t, fsp->fs_dtpref); 235 if (pref < nmp->nm_readdirsize) 236 nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) & 237 ~(NFS_DIRBLKSIZ - 1); 238 if (max < nmp->nm_readdirsize) { 239 nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1); 240 if (nmp->nm_readdirsize == 0) 241 nmp->nm_readdirsize = max; 242 } 243 nmp->nm_flag |= NFSMNT_GOTFSINFO; 244 } 245 nfsm_reqdone; 246 return (error); 247 } 248 249 /* 250 * Mount a remote root fs via. NFS. It goes like this: 251 * - Call nfs_boot_init() to fill in the nfs_diskless struct 252 * (using RARP, bootparam RPC, mountd RPC) 253 * - hand craft the swap nfs vnode hanging off a fake mount point 254 * if swdevt[0].sw_dev == NODEV 255 * - build the rootfs mount point and call mountnfs() to do the rest. 256 */ 257 int 258 nfs_mountroot() 259 { 260 struct nfs_diskless nd; 261 struct vattr attr; 262 struct mount *mp; 263 struct vnode *vp; 264 struct proc *procp; 265 long n; 266 int error; 267 268 procp = curproc; /* XXX */ 269 270 /* 271 * XXX time must be non-zero when we init the interface or else 272 * the arp code will wedge. [Fixed now in if_ether.c] 273 * However, the NFS attribute cache gives false "hits" when 274 * time.tv_sec < NFS_ATTRTIMEO(np) so keep this in for now. 275 */ 276 if (time.tv_sec < NFS_MAXATTRTIMO) 277 time.tv_sec = NFS_MAXATTRTIMO; 278 279 /* 280 * Call nfs_boot_init() to fill in the nfs_diskless struct. 281 * Side effect: Finds and configures a network interface. 282 */ 283 bzero((caddr_t) &nd, sizeof(nd)); 284 nfs_boot_init(&nd, procp); 285 286 /* 287 * Create the root mount point. 288 */ 289 nfs_boot_getfh(&nd.nd_boot, "root", &nd.nd_root); 290 mp = nfs_mount_diskless(&nd.nd_root, "/", 0); 291 nfs_root(mp, &rootvp); 292 printf("root on %s\n", nd.nd_root.ndm_host); 293 294 /* 295 * Link it into the mount list. 296 */ 297 simple_lock(&mountlist_slock); 298 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 299 simple_unlock(&mountlist_slock); 300 vfs_unbusy(mp, procp); 301 302 /* Get root attributes (for the time). */ 303 error = VOP_GETATTR(rootvp, &attr, procp->p_ucred, procp); 304 if (error) panic("nfs_mountroot: getattr for root"); 305 n = attr.va_mtime.tv_sec; 306 #ifdef DEBUG 307 printf("root time: 0x%lx\n", n); 308 #endif 309 inittodr(n); 310 311 /* 312 * XXX splnet, so networks will receive... 313 */ 314 splnet(); 315 316 #ifdef notyet 317 /* Set up swap credentials. */ 318 proc0.p_ucred->cr_uid = ntohl(nd.swap_ucred.cr_uid); 319 proc0.p_ucred->cr_gid = ntohl(nd.swap_ucred.cr_gid); 320 if ((proc0.p_ucred->cr_ngroups = ntohs(nd.swap_ucred.cr_ngroups)) > 321 NGROUPS) 322 proc0.p_ucred->cr_ngroups = NGROUPS; 323 for (i = 0; i < proc0.p_ucred->cr_ngroups; i++) 324 proc0.p_ucred->cr_groups[i] = ntohl(nd.swap_ucred.cr_groups[i]); 325 #endif 326 327 /* 328 * "Mount" the swap device. 329 * 330 * On a "dataless" configuration (swap on disk) we will have: 331 * (swdevt[0].sw_dev != NODEV) identifying the swap device. 332 */ 333 if (bdevvp(swapdev, &swapdev_vp)) 334 panic("nfs_mountroot: can't setup swap vp"); 335 if (swdevt[0].sw_dev != NODEV) { 336 printf("swap on device 0x%x\n", swdevt[0].sw_dev); 337 return (0); 338 } 339 340 /* 341 * If swapping to an nfs node: (swdevt[0].sw_dev == NODEV) 342 * Create a fake mount point just for the swap vnode so that the 343 * swap file can be on a different server from the rootfs. 344 */ 345 nfs_boot_getfh(&nd.nd_boot, "swap", &nd.nd_swap); 346 mp = nfs_mount_diskless(&nd.nd_swap, "/swap", 0); 347 nfs_root(mp, &vp); 348 vfs_unbusy(mp, procp); 349 printf("swap on %s\n", nd.nd_swap.ndm_host); 350 351 /* 352 * Since the swap file is not the root dir of a file system, 353 * hack it to a regular file. 354 */ 355 vp->v_type = VREG; 356 vp->v_flag = 0; 357 /* 358 * Next line is a hack to make swapmount() work on NFS swap files. 359 * XXX-smurph 360 */ 361 swdevt[0].sw_dev = NETDEV; 362 /* end hack */ 363 swdevt[0].sw_vp = vp; 364 365 /* 366 * Find out how large the swap file is. 367 */ 368 error = VOP_GETATTR(vp, &attr, procp->p_ucred, procp); 369 if (error) 370 panic("nfs_mountroot: getattr for swap"); 371 n = (long) (attr.va_size >> DEV_BSHIFT); 372 #ifdef DEBUG 373 printf("swap size: 0x%lx (blocks)\n", n); 374 #endif 375 swdevt[0].sw_nblks = n; 376 377 return (0); 378 } 379 380 /* 381 * Internal version of mount system call for diskless setup. 382 */ 383 struct mount * 384 nfs_mount_diskless(ndmntp, mntname, mntflag) 385 struct nfs_dlmount *ndmntp; 386 char *mntname; 387 int mntflag; 388 { 389 struct nfs_args args; 390 struct mount *mp; 391 struct mbuf *m; 392 int error; 393 394 if (vfs_rootmountalloc("nfs", mntname, &mp)) 395 panic("nfs_mount_diskless: vfs_rootmountalloc failed"); 396 mp->mnt_flag |= mntflag; 397 398 /* Initialize mount args. */ 399 bzero((caddr_t) &args, sizeof(args)); 400 args.addr = (struct sockaddr *)&ndmntp->ndm_saddr; 401 args.addrlen = args.addr->sa_len; 402 args.sotype = SOCK_DGRAM; 403 args.fh = ndmntp->ndm_fh; 404 args.fhsize = NFSX_V2FH; 405 args.hostname = ndmntp->ndm_host; 406 407 #ifdef NFS_BOOT_OPTIONS 408 args.flags |= NFS_BOOT_OPTIONS; 409 #endif 410 #ifdef NFS_BOOT_RWSIZE 411 /* 412 * Reduce rsize,wsize for interfaces that consistently 413 * drop fragments of long UDP messages. (i.e. wd8003). 414 * You can always change these later via remount. 415 */ 416 args.flags |= NFSMNT_WSIZE | NFSMNT_RSIZE; 417 args.wsize = NFS_BOOT_RWSIZE; 418 args.rsize = NFS_BOOT_RWSIZE; 419 #endif 420 421 /* Get mbuf for server sockaddr. */ 422 m = m_get(M_WAIT, MT_SONAME); 423 bcopy((caddr_t)args.addr, mtod(m, caddr_t), 424 (m->m_len = args.addr->sa_len)); 425 426 error = mountnfs(&args, mp, m, mntname, args.hostname); 427 if (error) 428 panic("nfs_mountroot: mount %s failed: %d", mntname, error); 429 430 return (mp); 431 } 432 433 void 434 nfs_decode_args(nmp, argp, nargp) 435 struct nfsmount *nmp; 436 struct nfs_args *argp; 437 struct nfs_args *nargp; 438 { 439 int s; 440 int adjsock = 0; 441 int maxio; 442 443 s = splsoftnet(); 444 445 #if 0 446 /* Re-bind if rsrvd port requested and wasn't on one */ 447 adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT) 448 && (argp->flags & NFSMNT_RESVPORT); 449 #endif 450 /* Also re-bind if we're switching to/from a connected UDP socket */ 451 adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) != 452 (argp->flags & NFSMNT_NOCONN)); 453 454 /* Update flags atomically. Don't change the lock bits. */ 455 nmp->nm_flag = 456 (argp->flags & ~NFSMNT_INTERNAL) | (nmp->nm_flag & NFSMNT_INTERNAL); 457 splx(s); 458 459 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 460 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 461 if (nmp->nm_timeo < NFS_MINTIMEO) 462 nmp->nm_timeo = NFS_MINTIMEO; 463 else if (nmp->nm_timeo > NFS_MAXTIMEO) 464 nmp->nm_timeo = NFS_MAXTIMEO; 465 } 466 467 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 468 nmp->nm_retry = argp->retrans; 469 if (nmp->nm_retry > NFS_MAXREXMIT) 470 nmp->nm_retry = NFS_MAXREXMIT; 471 } 472 473 if (argp->flags & NFSMNT_NFSV3) { 474 if (argp->sotype == SOCK_DGRAM) 475 maxio = NFS_MAXDGRAMDATA; 476 else 477 maxio = NFS_MAXDATA; 478 } else 479 maxio = NFS_V2MAXDATA; 480 481 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 482 int osize = nmp->nm_wsize; 483 nmp->nm_wsize = argp->wsize; 484 /* Round down to multiple of blocksize */ 485 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1); 486 if (nmp->nm_wsize <= 0) 487 nmp->nm_wsize = NFS_FABLKSIZE; 488 adjsock |= (nmp->nm_wsize != osize); 489 } 490 if (nmp->nm_wsize > maxio) 491 nmp->nm_wsize = maxio; 492 if (nmp->nm_wsize > MAXBSIZE) 493 nmp->nm_wsize = MAXBSIZE; 494 495 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 496 int osize = nmp->nm_rsize; 497 nmp->nm_rsize = argp->rsize; 498 /* Round down to multiple of blocksize */ 499 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1); 500 if (nmp->nm_rsize <= 0) 501 nmp->nm_rsize = NFS_FABLKSIZE; 502 adjsock |= (nmp->nm_rsize != osize); 503 } 504 if (nmp->nm_rsize > maxio) 505 nmp->nm_rsize = maxio; 506 if (nmp->nm_rsize > MAXBSIZE) 507 nmp->nm_rsize = MAXBSIZE; 508 509 if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { 510 nmp->nm_readdirsize = argp->readdirsize; 511 /* Round down to multiple of blocksize */ 512 nmp->nm_readdirsize &= ~(NFS_DIRBLKSIZ - 1); 513 if (nmp->nm_readdirsize < NFS_DIRBLKSIZ) 514 nmp->nm_readdirsize = NFS_DIRBLKSIZ; 515 } else if (argp->flags & NFSMNT_RSIZE) 516 nmp->nm_readdirsize = nmp->nm_rsize; 517 518 if (nmp->nm_readdirsize > maxio) 519 nmp->nm_readdirsize = maxio; 520 521 if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 && 522 argp->maxgrouplist <= NFS_MAXGRPS) 523 nmp->nm_numgrps = argp->maxgrouplist; 524 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 && 525 argp->readahead <= NFS_MAXRAHEAD) 526 nmp->nm_readahead = argp->readahead; 527 if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 && 528 argp->deadthresh <= NQ_NEVERDEAD) 529 nmp->nm_deadthresh = argp->deadthresh; 530 if (argp->flags & NFSMNT_ACREGMIN && argp->acregmin >= 0) { 531 if (argp->acregmin > 0xffff) 532 nmp->nm_acregmin = 0xffff; 533 else 534 nmp->nm_acregmin = argp->acregmin; 535 } 536 if (argp->flags & NFSMNT_ACREGMAX && argp->acregmax >= 0) { 537 if (argp->acregmax > 0xffff) 538 nmp->nm_acregmax = 0xffff; 539 else 540 nmp->nm_acregmax = argp->acregmax; 541 } 542 if (nmp->nm_acregmin > nmp->nm_acregmax) 543 nmp->nm_acregmin = nmp->nm_acregmax; 544 545 if (argp->flags & NFSMNT_ACDIRMIN && argp->acdirmin >= 0) { 546 if (argp->acdirmin > 0xffff) 547 nmp->nm_acdirmin = 0xffff; 548 else 549 nmp->nm_acdirmin = argp->acdirmin; 550 } 551 if (argp->flags & NFSMNT_ACDIRMAX && argp->acdirmax >= 0) { 552 if (argp->acdirmax > 0xffff) 553 nmp->nm_acdirmax = 0xffff; 554 else 555 nmp->nm_acdirmax = argp->acdirmax; 556 } 557 if (nmp->nm_acdirmin > nmp->nm_acdirmax) 558 nmp->nm_acdirmin = nmp->nm_acdirmax; 559 560 if (nmp->nm_so && adjsock) { 561 nfs_disconnect(nmp); 562 if (nmp->nm_sotype == SOCK_DGRAM) 563 while (nfs_connect(nmp, (struct nfsreq *)0)) { 564 printf("nfs_args: retrying connect\n"); 565 (void) tsleep((caddr_t)&lbolt, 566 PSOCK, "nfscon", 0); 567 } 568 } 569 570 /* Update nargp based on nmp */ 571 nargp->wsize = nmp->nm_wsize; 572 nargp->rsize = nmp->nm_rsize; 573 nargp->readdirsize = nmp->nm_readdirsize; 574 nargp->timeo = nmp->nm_timeo; 575 nargp->retrans = nmp->nm_retry; 576 nargp->maxgrouplist = nmp->nm_numgrps; 577 nargp->readahead = nmp->nm_readahead; 578 nargp->deadthresh = nmp->nm_deadthresh; 579 nargp->acregmin = nmp->nm_acregmin; 580 nargp->acregmax = nmp->nm_acregmax; 581 nargp->acdirmin = nmp->nm_acdirmin; 582 nargp->acdirmax = nmp->nm_acdirmax; 583 } 584 585 /* 586 * VFS Operations. 587 * 588 * mount system call 589 * It seems a bit dumb to copyinstr() the host and path here and then 590 * bcopy() them in mountnfs(), but I wanted to detect errors before 591 * doing the sockargs() call because sockargs() allocates an mbuf and 592 * an error after that means that I have to release the mbuf. 593 */ 594 /* ARGSUSED */ 595 int 596 nfs_mount(mp, path, data, ndp, p) 597 struct mount *mp; 598 const char *path; 599 void *data; 600 struct nameidata *ndp; 601 struct proc *p; 602 { 603 int error; 604 struct nfs_args args; 605 struct mbuf *nam; 606 char pth[MNAMELEN], hst[MNAMELEN]; 607 size_t len; 608 u_char nfh[NFSX_V3FHMAX]; 609 610 error = copyin (data, &args, sizeof (args.version)); 611 if (error) 612 return (error); 613 if (args.version == 3) { 614 error = copyin (data, (caddr_t)&args, 615 sizeof (struct nfs_args3)); 616 args.flags &= ~(NFSMNT_INTERNAL|NFSMNT_NOAC); 617 } 618 else if (args.version == NFS_ARGSVERSION) { 619 error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)); 620 args.flags &= ~NFSMNT_NOAC; /* XXX - compatibility */ 621 } 622 else 623 return (EPROGMISMATCH); 624 if (error) 625 return (error); 626 627 if (nfs_niothreads < 0) { 628 nfs_niothreads = 4; 629 nfs_getset_niothreads(TRUE); 630 } 631 632 if (mp->mnt_flag & MNT_UPDATE) { 633 register struct nfsmount *nmp = VFSTONFS(mp); 634 635 if (nmp == NULL) 636 return (EIO); 637 /* 638 * When doing an update, we can't change from or to 639 * v3. 640 */ 641 args.flags = (args.flags & ~(NFSMNT_NFSV3)) | 642 (nmp->nm_flag & (NFSMNT_NFSV3)); 643 nfs_decode_args(nmp, &args, &mp->mnt_stat.mount_info.nfs_args); 644 return (0); 645 } 646 if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) 647 return (EINVAL); 648 error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize); 649 if (error) 650 return (error); 651 error = copyinstr(path, pth, MNAMELEN-1, &len); 652 if (error) 653 return (error); 654 bzero(&pth[len], MNAMELEN - len); 655 error = copyinstr(args.hostname, hst, MNAMELEN-1, &len); 656 if (error) 657 return (error); 658 bzero(&hst[len], MNAMELEN - len); 659 /* sockargs() call must be after above copyin() calls */ 660 error = sockargs(&nam, (caddr_t)args.addr, args.addrlen, MT_SONAME); 661 if (error) 662 return (error); 663 args.fh = nfh; 664 error = mountnfs(&args, mp, nam, pth, hst); 665 return (error); 666 } 667 668 /* 669 * Common code for mount and mountroot 670 */ 671 int 672 mountnfs(argp, mp, nam, pth, hst) 673 register struct nfs_args *argp; 674 register struct mount *mp; 675 struct mbuf *nam; 676 char *pth, *hst; 677 { 678 register struct nfsmount *nmp; 679 int error; 680 681 if (mp->mnt_flag & MNT_UPDATE) { 682 nmp = VFSTONFS(mp); 683 /* update paths, file handles, etc, here XXX */ 684 m_freem(nam); 685 return (0); 686 } else { 687 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount), 688 M_NFSMNT, M_WAITOK); 689 bzero((caddr_t)nmp, sizeof (struct nfsmount)); 690 mp->mnt_data = (qaddr_t)nmp; 691 TAILQ_INIT(&nmp->nm_uidlruhead); 692 } 693 694 vfs_getnewfsid(mp); 695 nmp->nm_mountp = mp; 696 nmp->nm_timeo = NFS_TIMEO; 697 nmp->nm_retry = NFS_RETRANS; 698 nmp->nm_wsize = NFS_WSIZE; 699 nmp->nm_rsize = NFS_RSIZE; 700 nmp->nm_readdirsize = NFS_READDIRSIZE; 701 nmp->nm_numgrps = NFS_MAXGRPS; 702 nmp->nm_readahead = NFS_DEFRAHEAD; 703 nmp->nm_deadthresh = NQ_DEADTHRESH; 704 CIRCLEQ_INIT(&nmp->nm_timerhead); 705 nmp->nm_inprog = NULLVP; 706 nmp->nm_fhsize = argp->fhsize; 707 nmp->nm_acregmin = NFS_MINATTRTIMO; 708 nmp->nm_acregmax = NFS_MAXATTRTIMO; 709 nmp->nm_acdirmin = NFS_MINATTRTIMO; 710 nmp->nm_acdirmax = NFS_MAXATTRTIMO; 711 bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); 712 strncpy(&mp->mnt_stat.f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN); 713 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 714 bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); 715 bcopy(argp, &mp->mnt_stat.mount_info.nfs_args, sizeof(*argp)); 716 nmp->nm_nam = nam; 717 nfs_decode_args(nmp, argp, &mp->mnt_stat.mount_info.nfs_args); 718 719 /* Set up the sockets and per-host congestion */ 720 nmp->nm_sotype = argp->sotype; 721 nmp->nm_soproto = argp->proto; 722 723 /* 724 * For Connection based sockets (TCP,...) defer the connect until 725 * the first request, in case the server is not responding. 726 */ 727 if (nmp->nm_sotype == SOCK_DGRAM && 728 (error = nfs_connect(nmp, (struct nfsreq *)0))) 729 goto bad; 730 731 /* 732 * This is silly, but it has to be set so that vinifod() works. 733 * We do not want to do an nfs_statfs() here since we can get 734 * stuck on a dead server and we are holding a lock on the mount 735 * point. 736 */ 737 mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA; 738 739 return (0); 740 bad: 741 nfs_disconnect(nmp); 742 free((caddr_t)nmp, M_NFSMNT); 743 m_freem(nam); 744 return (error); 745 } 746 747 /* 748 * unmount system call 749 */ 750 int 751 nfs_unmount(mp, mntflags, p) 752 struct mount *mp; 753 int mntflags; 754 struct proc *p; 755 { 756 register struct nfsmount *nmp; 757 int error, flags = 0; 758 759 if (mntflags & MNT_FORCE) 760 flags |= FORCECLOSE; 761 nmp = VFSTONFS(mp); 762 /* 763 * Goes something like this.. 764 * - Call vflush() to clear out vnodes for this file system, 765 * except for the root vnode. 766 * - Close the socket 767 * - Free up the data structures 768 */ 769 770 /* 771 * Must handshake with nqnfs_clientd() if it is active. 772 */ 773 nmp->nm_flag |= NFSMNT_DISMINPROG; 774 while (nmp->nm_inprog != NULLVP) 775 (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0); 776 error = vflush(mp, NULL, flags); 777 if (error) { 778 nmp->nm_flag &= ~NFSMNT_DISMINPROG; 779 return (error); 780 } 781 782 /* 783 * We are now committed to the unmount. 784 * For NQNFS, let the server daemon free the nfsmount structure. 785 */ 786 if (nmp->nm_flag & NFSMNT_KERB) 787 nmp->nm_flag |= NFSMNT_DISMNT; 788 789 nfs_disconnect(nmp); 790 m_freem(nmp->nm_nam); 791 792 if ((nmp->nm_flag & NFSMNT_KERB) == 0) 793 free((caddr_t)nmp, M_NFSMNT); 794 return (0); 795 } 796 797 /* 798 * Return root of a filesystem 799 */ 800 int 801 nfs_root(mp, vpp) 802 struct mount *mp; 803 struct vnode **vpp; 804 { 805 struct nfsmount *nmp; 806 struct nfsnode *np; 807 int error; 808 809 nmp = VFSTONFS(mp); 810 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np); 811 if (error) 812 return (error); 813 *vpp = NFSTOV(np); 814 return (0); 815 } 816 817 extern int syncprt; 818 819 /* 820 * Flush out the buffer cache 821 */ 822 /* ARGSUSED */ 823 int 824 nfs_sync(mp, waitfor, cred, p) 825 struct mount *mp; 826 int waitfor; 827 struct ucred *cred; 828 struct proc *p; 829 { 830 register struct vnode *vp; 831 int error, allerror = 0; 832 833 /* 834 * Force stale buffer cache information to be flushed. 835 */ 836 loop: 837 for (vp = mp->mnt_vnodelist.lh_first; 838 vp != NULL; 839 vp = vp->v_mntvnodes.le_next) { 840 /* 841 * If the vnode that we are about to sync is no longer 842 * associated with this mount point, start over. 843 */ 844 if (vp->v_mount != mp) 845 goto loop; 846 if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL || 847 waitfor == MNT_LAZY) 848 continue; 849 if (vget(vp, LK_EXCLUSIVE, p)) 850 goto loop; 851 error = VOP_FSYNC(vp, cred, waitfor, p); 852 if (error) 853 allerror = error; 854 vput(vp); 855 } 856 return (allerror); 857 } 858 859 /* 860 * NFS flat namespace lookup. 861 * Currently unsupported. 862 */ 863 /* ARGSUSED */ 864 int 865 nfs_vget(mp, ino, vpp) 866 struct mount *mp; 867 ino_t ino; 868 struct vnode **vpp; 869 { 870 871 return (EOPNOTSUPP); 872 } 873 874 /* 875 * Do that sysctl thang... 876 */ 877 int 878 nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 879 size_t newlen, struct proc *p) 880 { 881 int rv; 882 883 /* 884 * All names at this level are terminal. 885 */ 886 if(namelen > 1) 887 return ENOTDIR; /* overloaded */ 888 889 switch(name[0]) { 890 case NFS_NFSSTATS: 891 if(!oldp) { 892 *oldlenp = sizeof nfsstats; 893 return 0; 894 } 895 896 if(*oldlenp < sizeof nfsstats) { 897 *oldlenp = sizeof nfsstats; 898 return ENOMEM; 899 } 900 901 rv = copyout(&nfsstats, oldp, sizeof nfsstats); 902 if(rv) return rv; 903 904 if(newp && newlen != sizeof nfsstats) 905 return EINVAL; 906 907 if(newp) { 908 return copyin(newp, &nfsstats, sizeof nfsstats); 909 } 910 return 0; 911 912 case NFS_NIOTHREADS: 913 nfs_getset_niothreads(0); 914 915 rv = sysctl_int(oldp, oldlenp, newp, newlen, &nfs_niothreads); 916 if (newp) 917 nfs_getset_niothreads(1); 918 919 return rv; 920 921 default: 922 return EOPNOTSUPP; 923 } 924 } 925 926 927 /* 928 * At this point, this should never happen 929 */ 930 /* ARGSUSED */ 931 int 932 nfs_fhtovp(mp, fhp, vpp) 933 register struct mount *mp; 934 struct fid *fhp; 935 struct vnode **vpp; 936 { 937 938 return (EINVAL); 939 } 940 941 /* 942 * Vnode pointer to File handle, should never happen either 943 */ 944 /* ARGSUSED */ 945 int 946 nfs_vptofh(vp, fhp) 947 struct vnode *vp; 948 struct fid *fhp; 949 { 950 951 return (EINVAL); 952 } 953 954 /* 955 * Vfs start routine, a no-op. 956 */ 957 /* ARGSUSED */ 958 int 959 nfs_start(mp, flags, p) 960 struct mount *mp; 961 int flags; 962 struct proc *p; 963 { 964 965 return (0); 966 } 967 968 /* 969 * Do operations associated with quotas, not supported 970 */ 971 /* ARGSUSED */ 972 int 973 nfs_quotactl(mp, cmd, uid, arg, p) 974 struct mount *mp; 975 int cmd; 976 uid_t uid; 977 caddr_t arg; 978 struct proc *p; 979 { 980 981 return (EOPNOTSUPP); 982 } 983 984 /* 985 * check export permission, not supported 986 */ 987 /* ARGUSED */ 988 int 989 nfs_checkexp(mp, nam, exflagsp, credanonp) 990 register struct mount *mp; 991 struct mbuf *nam; 992 int *exflagsp; 993 struct ucred **credanonp; 994 { 995 return (EOPNOTSUPP); 996 } 997 998