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