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