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