1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)nfs_vfsops.c 7.26 (Berkeley) 03/19/91 11 */ 12 13 #include "param.h" 14 #include "conf.h" 15 #include "ioctl.h" 16 #include "signal.h" 17 #include "proc.h" 18 #include "vnode.h" 19 #include "mount.h" 20 #include "buf.h" 21 #include "mbuf.h" 22 #include "socket.h" 23 #include "systm.h" 24 25 #include "../net/if.h" 26 #include "../net/route.h" 27 #include "../netinet/in.h" 28 29 #include "nfsv2.h" 30 #include "nfsnode.h" 31 #include "nfsmount.h" 32 #include "nfs.h" 33 #include "xdr_subs.h" 34 #include "nfsm_subs.h" 35 #include "nfsdiskless.h" 36 37 /* 38 * nfs vfs operations. 39 */ 40 int nfs_mount(); 41 int nfs_start(); 42 int nfs_unmount(); 43 int nfs_root(); 44 int nfs_quotactl(); 45 int nfs_statfs(); 46 int nfs_sync(); 47 int nfs_fhtovp(); 48 int nfs_vptofh(); 49 int nfs_init(); 50 51 struct vfsops nfs_vfsops = { 52 nfs_mount, 53 nfs_start, 54 nfs_unmount, 55 nfs_root, 56 nfs_quotactl, 57 nfs_statfs, 58 nfs_sync, 59 nfs_fhtovp, 60 nfs_vptofh, 61 nfs_init, 62 }; 63 64 static u_char nfs_mntid; 65 extern u_long nfs_procids[NFS_NPROCS]; 66 extern u_long nfs_prog, nfs_vers; 67 struct nfs_diskless nfs_diskless; 68 void nfs_disconnect(); 69 70 #define TRUE 1 71 #define FALSE 0 72 73 /* 74 * nfs statfs call 75 */ 76 nfs_statfs(mp, sbp) 77 struct mount *mp; 78 register struct statfs *sbp; 79 { 80 register struct vnode *vp; 81 register struct nfsv2_statfs *sfp; 82 register caddr_t cp; 83 register long t1; 84 caddr_t bpos, dpos, cp2; 85 u_long xid; 86 int error = 0; 87 struct mbuf *mreq, *mrep, *md, *mb, *mb2; 88 struct nfsmount *nmp; 89 struct ucred *cred; 90 struct nfsnode *np; 91 92 nmp = VFSTONFS(mp); 93 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 94 return (error); 95 vp = NFSTOV(np); 96 nfsstats.rpccnt[NFSPROC_STATFS]++; 97 cred = crget(); 98 cred->cr_ngroups = 1; 99 nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH); 100 nfsm_fhtom(vp); 101 nfsm_request(vp, NFSPROC_STATFS, curproc, 0); 102 nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS); 103 sbp->f_type = MOUNT_NFS; 104 sbp->f_flags = nmp->nm_flag; 105 sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize); 106 sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize); 107 sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks); 108 sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree); 109 sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail); 110 sbp->f_files = 0; 111 sbp->f_ffree = 0; 112 if (sbp != &mp->mnt_stat) { 113 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 114 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 115 } 116 nfsm_reqdone; 117 nfs_nput(vp); 118 crfree(cred); 119 return (error); 120 } 121 122 /* 123 * Mount a remote root fs via. nfs. This depends on the info in the 124 * nfs_diskless structure that has been filled in properly by some primary 125 * bootstrap. 126 * It goes something like this: 127 * - do enough of "ifconfig" by calling ifioctl() so that the system 128 * can talk to the server 129 * - If nfs_diskless.mygateway is filled in, use that address as 130 * a default gateway. 131 * (This is done the 4.3 way with rtioctl() and should be changed) 132 * - hand craft the swap nfs vnode hanging off a fake mount point 133 * - build the rootfs mount point and call mountnfs() to do the rest. 134 */ 135 nfs_mountroot() 136 { 137 register struct mount *mp; 138 register struct mbuf *m; 139 struct socket *so; 140 struct vnode *vp; 141 int error; 142 143 /* 144 * Do enough of ifconfig(8) so that critical net interface can 145 * talk to the server. 146 */ 147 if (socreate(nfs_diskless.myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0)) 148 panic("nfs ifconf"); 149 if (ifioctl(so, SIOCAIFADDR, &nfs_diskless.myif)) 150 panic("nfs ifconf2"); 151 soclose(so); 152 153 /* 154 * If the gateway field is filled in, set it as the default route. 155 */ 156 #ifdef COMPAT_43 157 if (nfs_diskless.mygateway.sa_family == AF_INET) { 158 struct ortentry rt; 159 struct sockaddr_in *sin; 160 161 sin = (struct sockaddr_in *) &rt.rt_dst; 162 sin->sin_len = sizeof (struct sockaddr_in); 163 sin->sin_family = AF_INET; 164 sin->sin_addr.s_addr = 0; /* default */ 165 bcopy((caddr_t)&nfs_diskless.mygateway, (caddr_t)&rt.rt_gateway, 166 sizeof (struct sockaddr_in)); 167 rt.rt_flags = (RTF_UP | RTF_GATEWAY); 168 if (rtioctl(SIOCADDRT, (caddr_t)&rt)) 169 panic("nfs root route"); 170 } 171 #endif /* COMPAT_43 */ 172 173 /* 174 * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV): 175 * Create a fake mount point just for the swap vnode so that the 176 * swap file can be on a different server from the rootfs. 177 */ 178 if (swdevt[0].sw_dev == NODEV) { 179 mp = (struct mount *)malloc((u_long)sizeof(struct mount), 180 M_MOUNT, M_NOWAIT); 181 if (mp == NULL) 182 panic("nfs root mount"); 183 mp->mnt_op = &nfs_vfsops; 184 mp->mnt_flag = 0; 185 mp->mnt_exroot = 0; 186 mp->mnt_mounth = NULLVP; 187 188 /* 189 * Set up the diskless nfs_args for the swap mount point 190 * and then call mountnfs() to mount it. 191 * Since the swap file is not the root dir of a file system, 192 * hack it to a regular file. 193 */ 194 nfs_diskless.swap_args.fh = (nfsv2fh_t *)nfs_diskless.swap_fh; 195 MGET(m, MT_SONAME, M_DONTWAIT); 196 if (m == NULL) 197 panic("nfs root mbuf"); 198 bcopy((caddr_t)&nfs_diskless.swap_saddr, mtod(m, caddr_t), 199 nfs_diskless.swap_saddr.sa_len); 200 m->m_len = nfs_diskless.swap_saddr.sa_len; 201 if (mountnfs(&nfs_diskless.swap_args, mp, m, "/swap", 202 nfs_diskless.swap_hostnam, &vp)) 203 panic("nfs swap"); 204 vp->v_type = VREG; 205 vp->v_flag = 0; 206 swapdev_vp = vp; 207 VREF(vp); 208 swdevt[0].sw_vp = vp; 209 VREF(vp); 210 argdev_vp = vp; 211 } 212 213 /* 214 * Create the rootfs mount point. 215 */ 216 mp = (struct mount *)malloc((u_long)sizeof(struct mount), 217 M_MOUNT, M_NOWAIT); 218 if (mp == NULL) 219 panic("nfs root mount2"); 220 mp->mnt_op = &nfs_vfsops; 221 mp->mnt_flag = MNT_RDONLY; 222 mp->mnt_exroot = 0; 223 mp->mnt_mounth = NULLVP; 224 225 /* 226 * Set up the root fs args and call mountnfs() to do the rest. 227 */ 228 nfs_diskless.root_args.fh = (nfsv2fh_t *)nfs_diskless.root_fh; 229 MGET(m, MT_SONAME, M_DONTWAIT); 230 if (m == NULL) 231 panic("nfs root mbuf2"); 232 bcopy((caddr_t)&nfs_diskless.root_saddr, mtod(m, caddr_t), 233 nfs_diskless.root_saddr.sa_len); 234 m->m_len = nfs_diskless.root_saddr.sa_len; 235 if (mountnfs(&nfs_diskless.root_args, mp, m, "/", 236 nfs_diskless.root_hostnam, &vp)) 237 panic("nfs root"); 238 if (vfs_lock(mp)) 239 panic("nfs root2"); 240 rootfs = mp; 241 mp->mnt_next = mp; 242 mp->mnt_prev = mp; 243 mp->mnt_vnodecovered = NULLVP; 244 vfs_unlock(mp); 245 rootvp = vp; 246 inittodr((time_t)0); /* There is no time in the nfs fsstat so ?? */ 247 return (0); 248 } 249 250 /* 251 * VFS Operations. 252 * 253 * mount system call 254 * It seems a bit dumb to copyinstr() the host and path here and then 255 * bcopy() them in mountnfs(), but I wanted to detect errors before 256 * doing the sockargs() call because sockargs() allocates an mbuf and 257 * an error after that means that I have to release the mbuf. 258 */ 259 /* ARGSUSED */ 260 nfs_mount(mp, path, data, ndp) 261 struct mount *mp; 262 char *path; 263 caddr_t data; 264 struct nameidata *ndp; 265 { 266 int error; 267 struct nfs_args args; 268 struct mbuf *nam; 269 struct vnode *vp; 270 char pth[MNAMELEN], hst[MNAMELEN]; 271 int len; 272 nfsv2fh_t nfh; 273 274 if (mp->mnt_flag & MNT_UPDATE) 275 return (0); 276 if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args))) 277 return (error); 278 if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t))) 279 return (error); 280 if (error = copyinstr(path, pth, MNAMELEN-1, &len)) 281 return (error); 282 bzero(&pth[len], MNAMELEN-len); 283 if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) 284 return (error); 285 bzero(&hst[len], MNAMELEN-len); 286 /* sockargs() call must be after above copyin() calls */ 287 if (error = sockargs(&nam, (caddr_t)args.addr, 288 sizeof (struct sockaddr), MT_SONAME)) 289 return (error); 290 args.fh = &nfh; 291 error = mountnfs(&args, mp, nam, pth, hst, &vp); 292 return (error); 293 } 294 295 /* 296 * Common code for mount and mountroot 297 */ 298 mountnfs(argp, mp, nam, pth, hst, vpp) 299 register struct nfs_args *argp; 300 register struct mount *mp; 301 struct mbuf *nam; 302 char *pth, *hst; 303 struct vnode **vpp; 304 { 305 register struct nfsmount *nmp; 306 struct nfsnode *np; 307 int error; 308 fsid_t tfsid; 309 310 MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK); 311 bzero((caddr_t)nmp, sizeof *nmp); 312 mp->mnt_data = (qaddr_t)nmp; 313 /* 314 * Generate a unique nfs mount id. The problem is that a dev number 315 * is not unique across multiple systems. The techique is as follows: 316 * 1) Set to nblkdev,0 which will never be used otherwise 317 * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is 318 * NOT 0 319 * 3) Loop searching the mount list for another one with same id 320 * If a match, increment val[0] and try again 321 * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char } 322 * so that nfs is not limited to 255 mount points 323 * Incrementing the high order bits does no real harm, since it 324 * simply makes the major dev number tick up. The upper bound is 325 * set to major dev 127 to avoid any sign extention problems 326 */ 327 mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0); 328 mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS; 329 if (++nfs_mntid == 0) 330 ++nfs_mntid; 331 tfsid.val[0] = makedev(nblkdev, nfs_mntid); 332 tfsid.val[1] = MOUNT_NFS; 333 while (rootfs && getvfs(&tfsid)) { 334 tfsid.val[0]++; 335 nfs_mntid++; 336 } 337 if (major(tfsid.val[0]) > 127) { 338 error = ENOENT; 339 goto bad; 340 } 341 mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 342 nmp->nm_mountp = mp; 343 nmp->nm_flag = argp->flags; 344 nmp->nm_rto = NFS_TIMEO; 345 nmp->nm_rtt = -1; 346 nmp->nm_rttvar = nmp->nm_rto << 1; 347 nmp->nm_retry = NFS_RETRANS; 348 nmp->nm_wsize = NFS_WSIZE; 349 nmp->nm_rsize = NFS_RSIZE; 350 bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); 351 mp->mnt_stat.f_type = MOUNT_NFS; 352 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 353 bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); 354 nmp->nm_nam = nam; 355 356 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 357 nmp->nm_rto = argp->timeo; 358 /* NFS timeouts are specified in 1/10 sec. */ 359 nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ; 360 if (nmp->nm_rto < NFS_MINTIMEO) 361 nmp->nm_rto = NFS_MINTIMEO; 362 else if (nmp->nm_rto > NFS_MAXTIMEO) 363 nmp->nm_rto = NFS_MAXTIMEO; 364 nmp->nm_rttvar = nmp->nm_rto << 1; 365 } 366 367 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 368 nmp->nm_retry = argp->retrans; 369 if (nmp->nm_retry > NFS_MAXREXMIT) 370 nmp->nm_retry = NFS_MAXREXMIT; 371 } 372 373 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 374 nmp->nm_wsize = argp->wsize; 375 /* Round down to multiple of blocksize */ 376 nmp->nm_wsize &= ~0x1ff; 377 if (nmp->nm_wsize <= 0) 378 nmp->nm_wsize = 512; 379 else if (nmp->nm_wsize > NFS_MAXDATA) 380 nmp->nm_wsize = NFS_MAXDATA; 381 } 382 if (nmp->nm_wsize > MAXBSIZE) 383 nmp->nm_wsize = MAXBSIZE; 384 385 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 386 nmp->nm_rsize = argp->rsize; 387 /* Round down to multiple of blocksize */ 388 nmp->nm_rsize &= ~0x1ff; 389 if (nmp->nm_rsize <= 0) 390 nmp->nm_rsize = 512; 391 else if (nmp->nm_rsize > NFS_MAXDATA) 392 nmp->nm_rsize = NFS_MAXDATA; 393 } 394 if (nmp->nm_rsize > MAXBSIZE) 395 nmp->nm_rsize = MAXBSIZE; 396 /* Set up the sockets and per-host congestion */ 397 nmp->nm_sotype = argp->sotype; 398 nmp->nm_soproto = argp->proto; 399 if (error = nfs_connect(nmp)) 400 goto bad; 401 402 if (error = nfs_statfs(mp, &mp->mnt_stat)) 403 goto bad; 404 /* 405 * A reference count is needed on the nfsnode representing the 406 * remote root. If this object is not persistent, then backward 407 * traversals of the mount point (i.e. "..") will not work if 408 * the nfsnode gets flushed out of the cache. Ufs does not have 409 * this problem, because one can identify root inodes by their 410 * number == ROOTINO (2). 411 */ 412 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 413 goto bad; 414 /* 415 * Unlock it, but keep the reference count. 416 */ 417 nfs_unlock(NFSTOV(np)); 418 *vpp = NFSTOV(np); 419 420 return (0); 421 bad: 422 nfs_disconnect(nmp); 423 FREE(nmp, M_NFSMNT); 424 m_freem(nam); 425 return (error); 426 } 427 428 /* 429 * unmount system call 430 */ 431 nfs_unmount(mp, mntflags) 432 struct mount *mp; 433 int mntflags; 434 { 435 register struct nfsmount *nmp; 436 struct nfsnode *np; 437 struct vnode *vp; 438 int flags = 0; 439 int error; 440 441 if (mntflags & MNT_FORCE) 442 return (EINVAL); 443 if (mntflags & MNT_FORCE) 444 flags |= FORCECLOSE; 445 nmp = VFSTONFS(mp); 446 /* 447 * Clear out the buffer cache 448 */ 449 mntflushbuf(mp, 0); 450 if (mntinvalbuf(mp)) 451 return (EBUSY); 452 /* 453 * Goes something like this.. 454 * - Check for activity on the root vnode (other than ourselves). 455 * - Call vflush() to clear out vnodes for this file system, 456 * except for the root vnode. 457 * - Decrement reference on the vnode representing remote root. 458 * - Close the socket 459 * - Free up the data structures 460 */ 461 /* 462 * We need to decrement the ref. count on the nfsnode representing 463 * the remote root. See comment in mountnfs(). The VFS unmount() 464 * has done vput on this vnode, otherwise we would get deadlock! 465 */ 466 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 467 return(error); 468 vp = NFSTOV(np); 469 if (vp->v_usecount > 2) { 470 vput(vp); 471 return (EBUSY); 472 } 473 if (error = vflush(mp, vp, flags)) { 474 vput(vp); 475 return (error); 476 } 477 /* 478 * Get rid of two reference counts, and unlock it on the second. 479 */ 480 vrele(vp); 481 vput(vp); 482 nfs_disconnect(nmp); 483 m_freem(nmp->nm_nam); 484 free((caddr_t)nmp, M_NFSMNT); 485 return (0); 486 } 487 488 /* 489 * Return root of a filesystem 490 */ 491 nfs_root(mp, vpp) 492 struct mount *mp; 493 struct vnode **vpp; 494 { 495 register struct vnode *vp; 496 struct nfsmount *nmp; 497 struct nfsnode *np; 498 int error; 499 500 nmp = VFSTONFS(mp); 501 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 502 return (error); 503 vp = NFSTOV(np); 504 vp->v_type = VDIR; 505 vp->v_flag = VROOT; 506 *vpp = vp; 507 return (0); 508 } 509 510 extern int syncprt; 511 512 /* 513 * Flush out the buffer cache 514 */ 515 /* ARGSUSED */ 516 nfs_sync(mp, waitfor) 517 struct mount *mp; 518 int waitfor; 519 { 520 if (syncprt) 521 bufstats(); 522 /* 523 * Force stale buffer cache information to be flushed. 524 */ 525 mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0); 526 return (0); 527 } 528 529 /* 530 * At this point, this should never happen 531 */ 532 /* ARGSUSED */ 533 nfs_fhtovp(mp, fhp, vpp) 534 struct mount *mp; 535 struct fid *fhp; 536 struct vnode **vpp; 537 { 538 539 return (EINVAL); 540 } 541 542 /* 543 * Vnode pointer to File handle, should never happen either 544 */ 545 /* ARGSUSED */ 546 nfs_vptofh(mp, fhp, vpp) 547 struct mount *mp; 548 struct fid *fhp; 549 struct vnode **vpp; 550 { 551 552 return (EINVAL); 553 } 554 555 /* 556 * Vfs start routine, a no-op. 557 */ 558 /* ARGSUSED */ 559 nfs_start(mp, flags) 560 struct mount *mp; 561 int flags; 562 { 563 564 return (0); 565 } 566 567 /* 568 * Do operations associated with quotas, not supported 569 */ 570 nfs_quotactl(mp, cmd, uid, arg) 571 struct mount *mp; 572 int cmd; 573 uid_t uid; 574 caddr_t arg; 575 { 576 #ifdef lint 577 mp = mp; cmd = cmd; uid = uid; arg = arg; 578 #endif /* lint */ 579 return (EOPNOTSUPP); 580 } 581