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