add islocked function to vnode switch
[unix-history] / usr / src / sys / nfs / nfs_vfsops.c
CommitLineData
a2907882
KM
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 *
e8540f59 20 * @(#)nfs_vfsops.c 7.11 (Berkeley) %G%
a2907882
KM
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"
e8540f59 29#include "systm.h"
36c3043b 30#include "../ufs/dir.h"
a2907882
KM
31#include "namei.h"
32#include "vnode.h"
33#include "mount.h"
34#include "errno.h"
35#include "malloc.h"
36#include "mbuf.h"
37#undef m_data
38#include "socket.h"
39#include "socketvar.h"
40#include "../netinet/in.h"
41#include "nfsv2.h"
42#include "nfsnode.h"
43#include "nfsmount.h"
44#include "nfs.h"
45
46#ifndef shouldbe
47#include "conf.h"
48#endif
49
50/*
51 * nfs vfs operations.
52 */
53int nfs_mount();
b3226026 54int nfs_start();
a2907882
KM
55int nfs_unmount();
56int nfs_root();
363ac00e 57int nfs_statfs();
a2907882
KM
58int nfs_sync();
59int nfs_fhtovp();
60int nfs_vptofh();
363ac00e 61int nfs_init();
a2907882
KM
62
63struct vfsops nfs_vfsops = {
64 nfs_mount,
b3226026 65 nfs_start,
a2907882
KM
66 nfs_unmount,
67 nfs_root,
68 nfs_statfs,
69 nfs_sync,
70 nfs_fhtovp,
71 nfs_vptofh,
363ac00e 72 nfs_init,
a2907882
KM
73};
74
75extern struct nfsreq nfsreqh;
e8540f59 76static u_char nfs_mntid;
a2907882
KM
77
78/*
79 * Called by vfs_mountroot when nfs is going to be mounted as root
80 * Not Yet (By a LONG shot)
81 */
82nfs_mountroot()
83{
84 return (ENODEV);
85}
86
87/*
88 * VFS Operations.
89 *
90 * mount system call
91 * It seems a bit dumb to copyinstr() the host and path here and then
92 * bcopy() them in mountnfs(), but I wanted to detect errors before
93 * doing the sockargs() call because sockargs() allocates an mbuf and
94 * an error after that means that I have to release the mbuf.
95 */
0bd503ad 96/* ARGSUSED */
a2907882
KM
97nfs_mount(mp, path, data, ndp)
98 struct mount *mp;
99 char *path;
100 caddr_t data;
101 struct nameidata *ndp;
102{
103 int error;
104 struct nfs_args args;
105 struct mbuf *saddr;
106 char pth[MNAMELEN], hst[MNAMELEN];
107 int len;
108 nfsv2fh_t nfh;
109
c2e44d7a
KM
110 if (mp->m_flag & M_UPDATE)
111 return (0);
a2907882
KM
112 if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
113 return (error);
114 if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
115 return (error);
116 if (error = copyinstr(path, pth, MNAMELEN-1, &len))
117 return (error);
118 bzero(&pth[len], MNAMELEN-len);
119 if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
120 return (error);
121 bzero(&hst[len], MNAMELEN-len);
122 /* sockargs() call must be after above copyin() calls */
123 if (error = sockargs(&saddr, (caddr_t)args.addr,
124 sizeof (struct sockaddr_in), MT_SONAME))
125 return (error);
126 args.fh = &nfh;
127 error = mountnfs(&args, mp, saddr, pth, hst);
128 return (error);
129}
130
131/*
132 * Common code for mount and mountroot
133 */
134mountnfs(argp, mp, saddr, pth, hst)
135 register struct nfs_args *argp;
136 register struct mount *mp;
137 register struct mbuf *saddr;
138 char *pth, *hst;
139{
140 register struct nfsmount *nmp;
e8540f59 141 fsid_t tfsid;
a2907882
KM
142 int error;
143
144 nmp = (struct nfsmount *)malloc(sizeof (struct nfsmount), M_NFSMNT,
145 M_WAITOK);
146 mp->m_data = (qaddr_t)nmp;
e8540f59
KM
147 /*
148 * Generate a unique nfs mount id. The problem is that a dev number
149 * is not unique across multiple systems. The techique is as follows:
150 * 1) Set to nblkdev,0 which will never be used otherwise
151 * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is
152 * NOT 0
153 * 3) Loop searching the mount list for another one with same id
154 * If a match, increment val[0] and try again
155 * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char }
156 * so that nfs is not limited to 255 mount points
157 * Incrementing the high order bits does no real harm, since it
158 * simply makes the major dev number tick up. The upper bound is
159 * set to major dev 127 to avoid any sign extention problems
160 */
161 mp->m_fsid.val[0] = makedev(nblkdev, 0);
a2907882 162 mp->m_fsid.val[1] = MOUNT_NFS;
e8540f59
KM
163 if (++nfs_mntid == 0)
164 ++nfs_mntid;
165 tfsid.val[0] = makedev(nblkdev, nfs_mntid);
166 tfsid.val[1] = MOUNT_NFS;
167 while (getvfs(&tfsid)) {
168 tfsid.val[0]++;
169 nfs_mntid++;
170 }
171 if (major(tfsid.val[0]) > 127) {
172 error = ENOENT;
173 goto bad;
174 }
175 mp->m_fsid.val[0] = tfsid.val[0];
a2907882
KM
176 nmp->nm_mountp = mp;
177 nmp->nm_flag = argp->flags;
178 nmp->nm_sockaddr = saddr;
179 /* Set up the sockets */
180 if (error = socreate(AF_INET, &nmp->nm_so, SOCK_DGRAM, 0))
181 goto bad;
182 if (error = soconnect(nmp->nm_so, saddr))
183 goto bad;
184 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo >= 1)
185 nmp->nm_timeo = argp->timeo;
186 else
187 nmp->nm_timeo = NFS_TIMEO;
188 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 0)
189 nmp->nm_retrans = argp->retrans;
190 else
191 nmp->nm_retrans = NFS_RETRANS;
192 if ((argp->flags & NFSMNT_WSIZE) &&
193 argp->wsize <= NFS_MAXDATA && argp->wsize > 0 &&
194 (argp->wsize & 0x1ff) == 0)
195 nmp->nm_wsize = argp->wsize;
196 else
197 nmp->nm_wsize = NFS_WSIZE;
198 if ((argp->flags & NFSMNT_RSIZE) &&
199 argp->rsize <= NFS_MAXDATA && argp->rsize > 0 &&
200 (argp->rsize & 0x1ff) == 0)
201 nmp->nm_rsize = argp->rsize;
202 else
203 nmp->nm_rsize = NFS_RSIZE;
204 bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
205 bcopy(pth, nmp->nm_path, MNAMELEN);
206 bcopy(hst, nmp->nm_host, MNAMELEN);
36c3043b
KM
207 /*
208 * Set to CLBYTES so that vinifod() doesn't get confused.
209 * Actually any exact multiple of CLBYTES will do
210 */
211 mp->m_bsize = mp->m_fsize = CLBYTES;
a2907882
KM
212 return (0);
213bad:
214 m_freem(saddr);
215 free((caddr_t)nmp, M_NFSMNT);
216 return (error);
217}
218
219/*
220 * unmount system call
221 */
222nfs_unmount(mp, flags)
223 struct mount *mp;
224 int flags;
225{
226 register struct nfsmount *nmp;
227 register struct nfsreq *rep;
228 struct nfsreq *rep2;
229 int error;
230 int s;
231
232 if (flags & MNT_FORCE)
233 return (EINVAL);
234 nmp = vfs_to_nfs(mp);
9238aa59
RM
235 /*
236 * Clear out the buffer cache
237 */
45836215
KM
238 mntflushbuf(mp, 0);
239 if (mntinvalbuf(mp))
9238aa59 240 return (EBUSY);
a2907882
KM
241 /*
242 * Goes something like this..
dee32656 243 * - Call vflush() to clear out vnodes for this file system
a2907882
KM
244 * - Flush out lookup cache
245 * - Close the socket
246 * - Free up the data structures
247 */
dee32656 248 if (error = vflush(mp, (struct vnode *)0, flags))
a2907882 249 return (error);
a2907882
KM
250 /*
251 * Scan the request list for any requests left hanging about
252 */
253 s = splnet();
254 rep = nfsreqh.r_next;
ffe6f482 255 while (rep && rep != &nfsreqh) {
a2907882
KM
256 if (rep->r_mntp == nmp) {
257 rep->r_prev->r_next = rep2 = rep->r_next;
ffe6f482 258 rep->r_next->r_prev = rep->r_prev;
a2907882
KM
259 m_freem(rep->r_mreq);
260 if (rep->r_mrep != NULL)
261 m_freem(rep->r_mrep);
262 free((caddr_t)rep, M_NFSREQ);
263 rep = rep2;
264 } else
265 rep = rep->r_next;
266 }
267 splx(s);
268 soclose(nmp->nm_so);
269 m_freem(nmp->nm_sockaddr);
270 free((caddr_t)nmp, M_NFSMNT);
271 return (0);
272}
273
274/*
275 * Return root of a filesystem
276 */
277nfs_root(mp, vpp)
278 struct mount *mp;
279 struct vnode **vpp;
280{
281 register struct vnode *vp;
282 struct nfsmount *nmp;
283 struct nfsnode *np;
284 int error;
285
286 nmp = vfs_to_nfs(mp);
287 if (error = nfs_nget(mp, &nmp->nm_fh, &np))
288 return (error);
289 vp = NFSTOV(np);
290 vp->v_type = VDIR;
291 vp->v_flag = VROOT;
292 *vpp = vp;
293 return (0);
294}
295
9238aa59
RM
296extern int syncprt;
297
a2907882 298/*
9238aa59 299 * Flush out the buffer cache
a2907882 300 */
0bd503ad 301/* ARGSUSED */
a2907882
KM
302nfs_sync(mp, waitfor)
303 struct mount *mp;
304 int waitfor;
305{
9238aa59
RM
306 if (syncprt)
307 bufstats();
308 /*
309 * Force stale buffer cache information to be flushed.
310 */
45836215 311 mntflushbuf(mp);
a2907882
KM
312 return (0);
313}
314
315/*
316 * At this point, this should never happen
317 */
0bd503ad 318/* ARGSUSED */
a2907882
KM
319nfs_fhtovp(mp, fhp, vpp)
320 struct mount *mp;
321 struct fid *fhp;
322 struct vnode **vpp;
323{
0bd503ad 324
a2907882
KM
325 return (EINVAL);
326}
327
328/*
329 * Vnode pointer to File handle, should never happen either
330 */
0bd503ad 331/* ARGSUSED */
a2907882
KM
332nfs_vptofh(mp, fhp, vpp)
333 struct mount *mp;
334 struct fid *fhp;
335 struct vnode **vpp;
336{
0bd503ad 337
a2907882
KM
338 return (EINVAL);
339}
9238aa59
RM
340
341/*
342 * Vfs start routine, a no-op.
343 */
0bd503ad 344/* ARGSUSED */
9238aa59
RM
345nfs_start(mp, flags)
346 struct mount *mp;
347 int flags;
348{
0bd503ad 349
9238aa59
RM
350 return (0);
351}