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.24 (Berkeley) 06/28/90 11 */ 12 13 #include "param.h" 14 #include "signal.h" 15 #include "user.h" 16 #include "proc.h" 17 #include "vnode.h" 18 #include "mount.h" 19 #include "errno.h" 20 #include "buf.h" 21 #include "mbuf.h" 22 #include "socket.h" 23 #include "systm.h" 24 #include "nfsv2.h" 25 #include "nfsnode.h" 26 #include "nfsmount.h" 27 #include "nfs.h" 28 #include "xdr_subs.h" 29 #include "nfsm_subs.h" 30 31 /* 32 * nfs vfs operations. 33 */ 34 int nfs_mount(); 35 int nfs_start(); 36 int nfs_unmount(); 37 int nfs_root(); 38 int nfs_quotactl(); 39 int nfs_statfs(); 40 int nfs_sync(); 41 int nfs_fhtovp(); 42 int nfs_vptofh(); 43 int nfs_init(); 44 45 struct vfsops nfs_vfsops = { 46 nfs_mount, 47 nfs_start, 48 nfs_unmount, 49 nfs_root, 50 nfs_quotactl, 51 nfs_statfs, 52 nfs_sync, 53 nfs_fhtovp, 54 nfs_vptofh, 55 nfs_init, 56 }; 57 58 static u_char nfs_mntid; 59 extern u_long nfs_procids[NFS_NPROCS]; 60 extern u_long nfs_prog, nfs_vers; 61 void nfs_disconnect(); 62 63 #define TRUE 1 64 #define FALSE 0 65 66 /* 67 * nfs statfs call 68 */ 69 nfs_statfs(mp, sbp) 70 struct mount *mp; 71 register struct statfs *sbp; 72 { 73 register struct vnode *vp; 74 register struct nfsv2_statfs *sfp; 75 register caddr_t cp; 76 register long t1; 77 caddr_t bpos, dpos, cp2; 78 u_long xid; 79 int error = 0; 80 struct mbuf *mreq, *mrep, *md, *mb, *mb2; 81 struct nfsmount *nmp; 82 struct ucred *cred; 83 struct nfsnode *np; 84 85 nmp = VFSTONFS(mp); 86 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 87 return (error); 88 vp = NFSTOV(np); 89 nfsstats.rpccnt[NFSPROC_STATFS]++; 90 cred = crget(); 91 cred->cr_ngroups = 1; 92 nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH); 93 nfsm_fhtom(vp); 94 nfsm_request(vp, NFSPROC_STATFS, u.u_procp, 0); 95 nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS); 96 sbp->f_type = MOUNT_NFS; 97 sbp->f_flags = nmp->nm_flag; 98 sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize); 99 sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize); 100 sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks); 101 sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree); 102 sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail); 103 sbp->f_files = 0; 104 sbp->f_ffree = 0; 105 if (sbp != &mp->mnt_stat) { 106 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 107 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 108 } 109 nfsm_reqdone; 110 nfs_nput(vp); 111 crfree(cred); 112 return (error); 113 } 114 115 /* 116 * Called by vfs_mountroot when nfs is going to be mounted as root 117 * Not Yet (By a LONG shot) 118 */ 119 nfs_mountroot() 120 { 121 return (ENODEV); 122 } 123 124 /* 125 * VFS Operations. 126 * 127 * mount system call 128 * It seems a bit dumb to copyinstr() the host and path here and then 129 * bcopy() them in mountnfs(), but I wanted to detect errors before 130 * doing the sockargs() call because sockargs() allocates an mbuf and 131 * an error after that means that I have to release the mbuf. 132 */ 133 /* ARGSUSED */ 134 nfs_mount(mp, path, data, ndp) 135 struct mount *mp; 136 char *path; 137 caddr_t data; 138 struct nameidata *ndp; 139 { 140 int error; 141 struct nfs_args args; 142 struct mbuf *nam; 143 char pth[MNAMELEN], hst[MNAMELEN]; 144 int len; 145 nfsv2fh_t nfh; 146 147 if (mp->mnt_flag & MNT_UPDATE) 148 return (0); 149 if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args))) 150 return (error); 151 if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t))) 152 return (error); 153 if (error = copyinstr(path, pth, MNAMELEN-1, &len)) 154 return (error); 155 bzero(&pth[len], MNAMELEN-len); 156 if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) 157 return (error); 158 bzero(&hst[len], MNAMELEN-len); 159 /* sockargs() call must be after above copyin() calls */ 160 if (error = sockargs(&nam, (caddr_t)args.addr, 161 sizeof (struct sockaddr), MT_SONAME)) 162 return (error); 163 args.fh = &nfh; 164 error = mountnfs(&args, mp, nam, pth, hst); 165 return (error); 166 } 167 168 /* 169 * Common code for mount and mountroot 170 */ 171 mountnfs(argp, mp, nam, pth, hst) 172 register struct nfs_args *argp; 173 register struct mount *mp; 174 struct mbuf *nam; 175 char *pth, *hst; 176 { 177 register struct nfsmount *nmp; 178 struct nfsnode *np; 179 int error; 180 fsid_t tfsid; 181 182 MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK); 183 bzero((caddr_t)nmp, sizeof *nmp); 184 mp->mnt_data = (qaddr_t)nmp; 185 /* 186 * Generate a unique nfs mount id. The problem is that a dev number 187 * is not unique across multiple systems. The techique is as follows: 188 * 1) Set to nblkdev,0 which will never be used otherwise 189 * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is 190 * NOT 0 191 * 3) Loop searching the mount list for another one with same id 192 * If a match, increment val[0] and try again 193 * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char } 194 * so that nfs is not limited to 255 mount points 195 * Incrementing the high order bits does no real harm, since it 196 * simply makes the major dev number tick up. The upper bound is 197 * set to major dev 127 to avoid any sign extention problems 198 */ 199 mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0); 200 mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS; 201 if (++nfs_mntid == 0) 202 ++nfs_mntid; 203 tfsid.val[0] = makedev(nblkdev, nfs_mntid); 204 tfsid.val[1] = MOUNT_NFS; 205 while (getvfs(&tfsid)) { 206 tfsid.val[0]++; 207 nfs_mntid++; 208 } 209 if (major(tfsid.val[0]) > 127) { 210 error = ENOENT; 211 goto bad; 212 } 213 mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; 214 nmp->nm_mountp = mp; 215 nmp->nm_flag = argp->flags; 216 nmp->nm_rto = NFS_TIMEO; 217 nmp->nm_rtt = -1; 218 nmp->nm_rttvar = nmp->nm_rto << 1; 219 nmp->nm_retry = NFS_RETRANS; 220 nmp->nm_wsize = NFS_WSIZE; 221 nmp->nm_rsize = NFS_RSIZE; 222 bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); 223 mp->mnt_stat.f_type = MOUNT_NFS; 224 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 225 bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN); 226 nmp->nm_nam = nam; 227 228 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 229 nmp->nm_rto = argp->timeo; 230 /* NFS timeouts are specified in 1/10 sec. */ 231 nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ; 232 if (nmp->nm_rto < NFS_MINTIMEO) 233 nmp->nm_rto = NFS_MINTIMEO; 234 else if (nmp->nm_rto > NFS_MAXTIMEO) 235 nmp->nm_rto = NFS_MAXTIMEO; 236 nmp->nm_rttvar = nmp->nm_rto << 1; 237 } 238 239 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 240 nmp->nm_retry = argp->retrans; 241 if (nmp->nm_retry > NFS_MAXREXMIT) 242 nmp->nm_retry = NFS_MAXREXMIT; 243 } 244 245 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 246 nmp->nm_wsize = argp->wsize; 247 /* Round down to multiple of blocksize */ 248 nmp->nm_wsize &= ~0x1ff; 249 if (nmp->nm_wsize <= 0) 250 nmp->nm_wsize = 512; 251 else if (nmp->nm_wsize > NFS_MAXDATA) 252 nmp->nm_wsize = NFS_MAXDATA; 253 } 254 if (nmp->nm_wsize > MAXBSIZE) 255 nmp->nm_wsize = MAXBSIZE; 256 257 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 258 nmp->nm_rsize = argp->rsize; 259 /* Round down to multiple of blocksize */ 260 nmp->nm_rsize &= ~0x1ff; 261 if (nmp->nm_rsize <= 0) 262 nmp->nm_rsize = 512; 263 else if (nmp->nm_rsize > NFS_MAXDATA) 264 nmp->nm_rsize = NFS_MAXDATA; 265 } 266 if (nmp->nm_rsize > MAXBSIZE) 267 nmp->nm_rsize = MAXBSIZE; 268 /* Set up the sockets and per-host congestion */ 269 nmp->nm_sotype = argp->sotype; 270 nmp->nm_soproto = argp->proto; 271 if (error = nfs_connect(nmp)) 272 goto bad; 273 274 if (error = nfs_statfs(mp, &mp->mnt_stat)) 275 goto bad; 276 /* 277 * A reference count is needed on the nfsnode representing the 278 * remote root. If this object is not persistent, then backward 279 * traversals of the mount point (i.e. "..") will not work if 280 * the nfsnode gets flushed out of the cache. Ufs does not have 281 * this problem, because one can identify root inodes by their 282 * number == ROOTINO (2). 283 */ 284 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 285 goto bad; 286 /* 287 * Unlock it, but keep the reference count. 288 */ 289 nfs_unlock(NFSTOV(np)); 290 291 return (0); 292 bad: 293 nfs_disconnect(nmp); 294 FREE(nmp, M_NFSMNT); 295 m_freem(nam); 296 return (error); 297 } 298 299 /* 300 * unmount system call 301 */ 302 nfs_unmount(mp, mntflags) 303 struct mount *mp; 304 int mntflags; 305 { 306 register struct nfsmount *nmp; 307 struct nfsnode *np; 308 struct vnode *vp; 309 int flags = 0; 310 int error; 311 312 if (mntflags & MNT_FORCE) 313 return (EINVAL); 314 if (mntflags & MNT_FORCE) 315 flags |= FORCECLOSE; 316 nmp = VFSTONFS(mp); 317 /* 318 * Clear out the buffer cache 319 */ 320 mntflushbuf(mp, 0); 321 if (mntinvalbuf(mp)) 322 return (EBUSY); 323 /* 324 * Goes something like this.. 325 * - Check for activity on the root vnode (other than ourselves). 326 * - Call vflush() to clear out vnodes for this file system, 327 * except for the root vnode. 328 * - Decrement reference on the vnode representing remote root. 329 * - Close the socket 330 * - Free up the data structures 331 */ 332 /* 333 * We need to decrement the ref. count on the nfsnode representing 334 * the remote root. See comment in mountnfs(). The VFS unmount() 335 * has done vput on this vnode, otherwise we would get deadlock! 336 */ 337 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 338 return(error); 339 vp = NFSTOV(np); 340 if (vp->v_usecount > 2) { 341 vput(vp); 342 return (EBUSY); 343 } 344 if (error = vflush(mp, vp, flags)) { 345 vput(vp); 346 return (error); 347 } 348 /* 349 * Get rid of two reference counts, and unlock it on the second. 350 */ 351 vrele(vp); 352 vput(vp); 353 nfs_disconnect(nmp); 354 m_freem(nmp->nm_nam); 355 free((caddr_t)nmp, M_NFSMNT); 356 return (0); 357 } 358 359 /* 360 * Return root of a filesystem 361 */ 362 nfs_root(mp, vpp) 363 struct mount *mp; 364 struct vnode **vpp; 365 { 366 register struct vnode *vp; 367 struct nfsmount *nmp; 368 struct nfsnode *np; 369 int error; 370 371 nmp = VFSTONFS(mp); 372 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 373 return (error); 374 vp = NFSTOV(np); 375 vp->v_type = VDIR; 376 vp->v_flag = VROOT; 377 *vpp = vp; 378 return (0); 379 } 380 381 extern int syncprt; 382 383 /* 384 * Flush out the buffer cache 385 */ 386 /* ARGSUSED */ 387 nfs_sync(mp, waitfor) 388 struct mount *mp; 389 int waitfor; 390 { 391 if (syncprt) 392 bufstats(); 393 /* 394 * Force stale buffer cache information to be flushed. 395 */ 396 mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0); 397 return (0); 398 } 399 400 /* 401 * At this point, this should never happen 402 */ 403 /* ARGSUSED */ 404 nfs_fhtovp(mp, fhp, vpp) 405 struct mount *mp; 406 struct fid *fhp; 407 struct vnode **vpp; 408 { 409 410 return (EINVAL); 411 } 412 413 /* 414 * Vnode pointer to File handle, should never happen either 415 */ 416 /* ARGSUSED */ 417 nfs_vptofh(mp, fhp, vpp) 418 struct mount *mp; 419 struct fid *fhp; 420 struct vnode **vpp; 421 { 422 423 return (EINVAL); 424 } 425 426 /* 427 * Vfs start routine, a no-op. 428 */ 429 /* ARGSUSED */ 430 nfs_start(mp, flags) 431 struct mount *mp; 432 int flags; 433 { 434 435 return (0); 436 } 437 438 /* 439 * Do operations associated with quotas, not supported 440 */ 441 nfs_quotactl(mp, cmd, uid, arg) 442 struct mount *mp; 443 int cmd; 444 uid_t uid; 445 caddr_t arg; 446 { 447 #ifdef lint 448 mp = mp; cmd = cmd; uid = uid; arg = arg; 449 #endif /* lint */ 450 return (EOPNOTSUPP); 451 } 452