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