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.4 (Berkeley) 08/30/89 21 */ 22 23 #include "param.h" 24 #include "signal.h" 25 #include "user.h" 26 #include "proc.h" 27 #include "uio.h" 28 #include "ucred.h" 29 #include "../ufs/dir.h" 30 #include "namei.h" 31 #include "vnode.h" 32 #include "mount.h" 33 #include "errno.h" 34 #include "malloc.h" 35 #include "mbuf.h" 36 #undef m_data 37 #include "socket.h" 38 #include "socketvar.h" 39 #include "../netinet/in.h" 40 #include "nfsv2.h" 41 #include "nfsnode.h" 42 #include "nfsmount.h" 43 #include "nfs.h" 44 45 #ifndef shouldbe 46 #include "conf.h" 47 #endif 48 49 /* 50 * nfs vfs operations. 51 */ 52 int nfs_mount(); 53 int nfs_start(); 54 int nfs_unmount(); 55 int nfs_root(); 56 extern int nfs_statfs(); 57 int nfs_sync(); 58 int nfs_fhtovp(); 59 int nfs_vptofh(); 60 61 struct vfsops nfs_vfsops = { 62 nfs_mount, 63 nfs_start, 64 nfs_unmount, 65 nfs_root, 66 nfs_statfs, 67 nfs_sync, 68 nfs_fhtovp, 69 nfs_vptofh, 70 }; 71 72 extern struct nfsreq nfsreqh; 73 static long nfs_mntid; 74 75 /* 76 * Called by vfs_mountroot when nfs is going to be mounted as root 77 * Not Yet (By a LONG shot) 78 */ 79 nfs_mountroot() 80 { 81 return (ENODEV); 82 } 83 84 /* 85 * VFS Operations. 86 * 87 * mount system call 88 * It seems a bit dumb to copyinstr() the host and path here and then 89 * bcopy() them in mountnfs(), but I wanted to detect errors before 90 * doing the sockargs() call because sockargs() allocates an mbuf and 91 * an error after that means that I have to release the mbuf. 92 */ 93 nfs_mount(mp, path, data, ndp) 94 struct mount *mp; 95 char *path; 96 caddr_t data; 97 struct nameidata *ndp; 98 { 99 int error; 100 struct nfs_args args; 101 struct mbuf *saddr; 102 char pth[MNAMELEN], hst[MNAMELEN]; 103 int len; 104 nfsv2fh_t nfh; 105 106 if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args))) 107 return (error); 108 if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t))) 109 return (error); 110 if (error = copyinstr(path, pth, MNAMELEN-1, &len)) 111 return (error); 112 bzero(&pth[len], MNAMELEN-len); 113 if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len)) 114 return (error); 115 bzero(&hst[len], MNAMELEN-len); 116 /* sockargs() call must be after above copyin() calls */ 117 if (error = sockargs(&saddr, (caddr_t)args.addr, 118 sizeof (struct sockaddr_in), MT_SONAME)) 119 return (error); 120 args.fh = &nfh; 121 error = mountnfs(&args, mp, saddr, pth, hst); 122 return (error); 123 } 124 125 /* 126 * Common code for mount and mountroot 127 */ 128 mountnfs(argp, mp, saddr, pth, hst) 129 register struct nfs_args *argp; 130 register struct mount *mp; 131 register struct mbuf *saddr; 132 char *pth, *hst; 133 { 134 register struct nfsmount *nmp; 135 struct nfsnode *np; 136 #ifdef notdef 137 struct statfs statf, *sbp; 138 #endif 139 int error; 140 141 nmp = (struct nfsmount *)malloc(sizeof (struct nfsmount), M_NFSMNT, 142 M_WAITOK); 143 mp->m_data = (qaddr_t)nmp; 144 mp->m_fsid.val[0] = ++nfs_mntid; 145 mp->m_fsid.val[1] = MOUNT_NFS; 146 nmp->nm_mountp = mp; 147 nmp->nm_flag = argp->flags; 148 nmp->nm_sockaddr = saddr; 149 /* Set up the sockets */ 150 if (error = socreate(AF_INET, &nmp->nm_so, SOCK_DGRAM, 0)) 151 goto bad; 152 if (error = soconnect(nmp->nm_so, saddr)) 153 goto bad; 154 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo >= 1) 155 nmp->nm_timeo = argp->timeo; 156 else 157 nmp->nm_timeo = NFS_TIMEO; 158 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 0) 159 nmp->nm_retrans = argp->retrans; 160 else 161 nmp->nm_retrans = NFS_RETRANS; 162 if ((argp->flags & NFSMNT_WSIZE) && 163 argp->wsize <= NFS_MAXDATA && argp->wsize > 0 && 164 (argp->wsize & 0x1ff) == 0) 165 nmp->nm_wsize = argp->wsize; 166 else 167 nmp->nm_wsize = NFS_WSIZE; 168 if ((argp->flags & NFSMNT_RSIZE) && 169 argp->rsize <= NFS_MAXDATA && argp->rsize > 0 && 170 (argp->rsize & 0x1ff) == 0) 171 nmp->nm_rsize = argp->rsize; 172 else 173 nmp->nm_rsize = NFS_RSIZE; 174 bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t)); 175 bcopy(pth, nmp->nm_path, MNAMELEN); 176 bcopy(hst, nmp->nm_host, MNAMELEN); 177 #ifdef notdef 178 sbp = &statf; 179 /* 180 * Kludge City... 181 * To do an interruptable hard mount, turn it into a soft mount 182 * with a retry limit of one and then repeat it so long as it 183 * times out and there is no pending signal for the process. 184 * It is tempting to just let nfs_statfs() sleep at positive 185 * prio, but then you would long jump out without taking the 186 * mount structure back out of the list. 187 * NB: NFSMNT_INT must NEVER be set for nfs_mountroot(), since 188 * the process context is not yet built!! 189 */ 190 if ((argp->flags && NFSMNT_INT) && (argp->flags & NFSMNT_SOFT) == 0) { 191 int savretrans; 192 193 nmp->nm_flag |= NFSMNT_SOFT; 194 savretrans = nmp->nm_retrans; 195 nmp->nm_retrans = 1; 196 do { 197 error = nfs_statfs(mp, sbp); 198 } while (error == ETIMEDOUT && (u.u_procp->p_sig & 199 (sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM)| 200 sigmask(SIGKILL))) == 0); 201 nmp->nm_retrans = savretrans; 202 nmp->nm_flag &= ~NFSMNT_SOFT; 203 if (error) 204 goto bad; 205 } else if (error = nfs_statfs(mp, sbp)) 206 goto bad; 207 mp->m_fsize = sbp->f_fsize; 208 209 /* 210 * If the block size is not an exact multiple of CLBYTES 211 * use CLBYTES so that paging in ZMAGIC executables doesn't 212 * get sick. (It is used by vinitfod()) 213 */ 214 if (sbp->f_bsize >= CLBYTES && claligned(sbp->f_bsize)) 215 mp->m_bsize = sbp->f_bsize; 216 else 217 mp->m_bsize = CLBYTES; 218 #else 219 /* 220 * Set to CLBYTES so that vinifod() doesn't get confused. 221 * Actually any exact multiple of CLBYTES will do 222 */ 223 mp->m_bsize = mp->m_fsize = CLBYTES; 224 #endif 225 return (0); 226 bad: 227 m_freem(saddr); 228 free((caddr_t)nmp, M_NFSMNT); 229 return (error); 230 } 231 232 /* 233 * unmount system call 234 */ 235 nfs_unmount(mp, flags) 236 struct mount *mp; 237 int flags; 238 { 239 register struct nfsmount *nmp; 240 register struct nfsreq *rep; 241 struct nfsreq *rep2; 242 int error; 243 int s; 244 245 if (flags & MNT_FORCE) 246 return (EINVAL); 247 nmp = vfs_to_nfs(mp); 248 /* 249 * Clear out the buffer cache 250 */ 251 bflush(mp); 252 if (binval(mp)) 253 return (EBUSY); 254 /* 255 * Goes something like this.. 256 * - Call nfs_nflush() to clear out the nfsnode table 257 * - Flush out lookup cache 258 * - Close the socket 259 * - Free up the data structures 260 */ 261 if (error = nfs_nflush(mp)) { 262 return (error); 263 } 264 /* 265 * Scan the request list for any requests left hanging about 266 */ 267 s = splnet(); 268 rep = nfsreqh.r_next; 269 while (rep) { 270 if (rep->r_mntp == nmp) { 271 rep->r_prev->r_next = rep2 = rep->r_next; 272 if (rep->r_next != NULL) 273 rep->r_next->r_prev = rep->r_prev; 274 m_freem(rep->r_mreq); 275 if (rep->r_mrep != NULL) 276 m_freem(rep->r_mrep); 277 free((caddr_t)rep, M_NFSREQ); 278 rep = rep2; 279 } else 280 rep = rep->r_next; 281 } 282 splx(s); 283 soclose(nmp->nm_so); 284 m_freem(nmp->nm_sockaddr); 285 free((caddr_t)nmp, M_NFSMNT); 286 return (0); 287 } 288 289 /* 290 * Return root of a filesystem 291 */ 292 nfs_root(mp, vpp) 293 struct mount *mp; 294 struct vnode **vpp; 295 { 296 register struct vnode *vp; 297 struct nfsmount *nmp; 298 struct nfsnode *np; 299 int error; 300 301 nmp = vfs_to_nfs(mp); 302 if (error = nfs_nget(mp, &nmp->nm_fh, &np)) 303 return (error); 304 vp = NFSTOV(np); 305 vp->v_type = VDIR; 306 vp->v_flag = VROOT; 307 *vpp = vp; 308 return (0); 309 } 310 311 extern int syncprt; 312 313 /* 314 * Flush out the buffer cache 315 */ 316 nfs_sync(mp, waitfor) 317 struct mount *mp; 318 int waitfor; 319 { 320 if (syncprt) 321 bufstats(); 322 /* 323 * Force stale buffer cache information to be flushed. 324 */ 325 bflush(mp); 326 return (0); 327 } 328 329 /* 330 * At this point, this should never happen 331 */ 332 nfs_fhtovp(mp, fhp, vpp) 333 struct mount *mp; 334 struct fid *fhp; 335 struct vnode **vpp; 336 { 337 return (EINVAL); 338 } 339 340 /* 341 * Vnode pointer to File handle, should never happen either 342 */ 343 nfs_vptofh(mp, fhp, vpp) 344 struct mount *mp; 345 struct fid *fhp; 346 struct vnode **vpp; 347 { 348 return (EINVAL); 349 } 350 351 /* 352 * Vfs start routine, a no-op. 353 */ 354 nfs_start(mp, flags) 355 struct mount *mp; 356 int flags; 357 { 358 return (0); 359 } 360