Deleted Added
full compact
nfs_vfsops.c (34572) nfs_vfsops.c (34961)
1/*
2 * Copyright (c) 1989, 1993, 1995
3 * The Regents of the University of California. 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, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95
1/*
2 * Copyright (c) 1989, 1993, 1995
3 * The Regents of the University of California. 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, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95
37 * $Id: nfs_vfsops.c,v 1.55 1998/03/01 22:46:30 msmith Exp $
37 * $Id: nfs_vfsops.c,v 1.56 1998/03/14 03:25:18 tegge Exp $
38 */
39
40#include <sys/param.h>
41#include <sys/sockio.h>
42#include <sys/proc.h>
43#include <sys/vnode.h>
44#include <sys/kernel.h>
45#include <sys/sysctl.h>
46#include <sys/malloc.h>
47#include <sys/mount.h>
48#include <sys/mbuf.h>
49#include <sys/socket.h>
50#include <sys/socketvar.h>
51#include <sys/systm.h>
52
53#include <vm/vm.h>
54#include <vm/vm_extern.h>
55
56#include <net/if.h>
57#include <net/route.h>
58#include <netinet/in.h>
59
60#include <nfs/rpcv2.h>
61#include <nfs/nfsproto.h>
62#include <nfs/nfs.h>
63#include <nfs/nfsnode.h>
64#include <nfs/nfsmount.h>
65#include <nfs/xdr_subs.h>
66#include <nfs/nfsm_subs.h>
67#include <nfs/nfsdiskless.h>
68#include <nfs/nqnfs.h>
69
70extern int nfs_mountroot __P((struct mount *mp));
71
72extern int nfs_ticks;
73
74MALLOC_DEFINE(M_NFSREQ, "NFS req", "NFS request header");
75MALLOC_DEFINE(M_NFSMNT, "NFS mount", "NFS mount structure");
76MALLOC_DEFINE(M_NFSBIGFH, "NFSV3 bigfh", "NFS version 3 file handle");
77MALLOC_DEFINE(M_NFSD, "NFS daemon", "Nfs server daemon structure");
78MALLOC_DEFINE(M_NFSDIROFF, "NFSV3 diroff", "NFS directory offset data");
79MALLOC_DEFINE(M_NFSRVDESC, "NFSV3 srvdesc", "NFS server socket descriptor");
80MALLOC_DEFINE(M_NFSUID, "NFS uid", "Nfs uid mapping structure");
81MALLOC_DEFINE(M_NQLEASE, "NQNFS Lease", "Nqnfs lease");
82
83struct nfsstats nfsstats;
84SYSCTL_NODE(_vfs, MOUNT_NFS, nfs, CTLFLAG_RW, 0, "NFS filesystem");
85SYSCTL_STRUCT(_vfs_nfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RD,
86 &nfsstats, nfsstats, "");
87#ifdef NFS_DEBUG
88int nfs_debug;
89SYSCTL_INT(_vfs_nfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0, "");
90#endif
91
92static int nfs_iosize __P((struct nfsmount *nmp));
93static int mountnfs __P((struct nfs_args *,struct mount *,
94 struct sockaddr *,char *,char *,struct vnode **));
95static int nfs_mount __P(( struct mount *mp, char *path, caddr_t data,
96 struct nameidata *ndp, struct proc *p));
97static int nfs_start __P(( struct mount *mp, int flags,
98 struct proc *p));
99static int nfs_unmount __P(( struct mount *mp, int mntflags,
100 struct proc *p));
101static int nfs_root __P(( struct mount *mp, struct vnode **vpp));
102static int nfs_quotactl __P(( struct mount *mp, int cmds, uid_t uid,
103 caddr_t arg, struct proc *p));
104static int nfs_statfs __P(( struct mount *mp, struct statfs *sbp,
105 struct proc *p));
106static int nfs_sync __P(( struct mount *mp, int waitfor,
107 struct ucred *cred, struct proc *p));
108static int nfs_vptofh __P(( struct vnode *vp, struct fid *fhp));
109static int nfs_fhtovp __P((struct mount *mp, struct fid *fhp,
110 struct sockaddr *nam, struct vnode **vpp,
111 int *exflagsp, struct ucred **credanonp));
112static int nfs_vget __P((struct mount *, ino_t, struct vnode **));
113
114
115/*
116 * nfs vfs operations.
117 */
118static struct vfsops nfs_vfsops = {
119 nfs_mount,
120 nfs_start,
121 nfs_unmount,
122 nfs_root,
123 nfs_quotactl,
124 nfs_statfs,
125 nfs_sync,
126 nfs_vget,
127 vfs_vrele,
128 nfs_fhtovp,
129 nfs_vptofh,
130 nfs_init
131};
132VFS_SET(nfs_vfsops, nfs, MOUNT_NFS, VFCF_NETWORK);
133
134/*
135 * This structure must be filled in by a primary bootstrap or bootstrap
136 * server for a diskless/dataless machine. It is initialized below just
137 * to ensure that it is allocated to initialized data (.data not .bss).
138 */
139struct nfs_diskless nfs_diskless = { 0 };
140struct nfsv3_diskless nfsv3_diskless = { 0 };
141int nfs_diskless_valid = 0;
142
143SYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
144 &nfs_diskless_valid, 0, "");
145
146SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
147 nfsv3_diskless.root_hostnam, 0, "");
148
149SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
150 &nfsv3_diskless.root_saddr, sizeof nfsv3_diskless.root_saddr,
151 "%Ssockaddr_in", "");
152
153SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_swappath, CTLFLAG_RD,
154 nfsv3_diskless.swap_hostnam, 0, "");
155
156SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_swapaddr, CTLFLAG_RD,
157 &nfsv3_diskless.swap_saddr, sizeof nfsv3_diskless.swap_saddr,
158 "%Ssockaddr_in","");
159
160
161void nfsargs_ntoh __P((struct nfs_args *));
162static int nfs_mountdiskless __P((char *, char *, int,
163 struct sockaddr_in *, struct nfs_args *,
164 struct proc *, struct vnode **,
165 struct mount **));
166static void nfs_convert_diskless __P((void));
167static void nfs_convert_oargs __P((struct nfs_args *args,
168 struct onfs_args *oargs));
169
170static int nfs_iosize(nmp)
171 struct nfsmount* nmp;
172{
173 int iosize;
174
175 /*
176 * Calculate the size used for io buffers. Use the larger
177 * of the two sizes to minimise nfs requests but make sure
178 * that it is at least one VM page to avoid wasting buffer
179 * space.
180 */
181 iosize = max(nmp->nm_rsize, nmp->nm_wsize);
182 if (iosize < PAGE_SIZE) iosize = PAGE_SIZE;
183 return iosize;
184}
185
186static void nfs_convert_oargs(args,oargs)
187 struct nfs_args *args;
188 struct onfs_args *oargs;
189{
190 args->version = NFS_ARGSVERSION;
191 args->addr = oargs->addr;
192 args->addrlen = oargs->addrlen;
193 args->sotype = oargs->sotype;
194 args->proto = oargs->proto;
195 args->fh = oargs->fh;
196 args->fhsize = oargs->fhsize;
197 args->flags = oargs->flags;
198 args->wsize = oargs->wsize;
199 args->rsize = oargs->rsize;
200 args->readdirsize = oargs->readdirsize;
201 args->timeo = oargs->timeo;
202 args->retrans = oargs->retrans;
203 args->maxgrouplist = oargs->maxgrouplist;
204 args->readahead = oargs->readahead;
205 args->leaseterm = oargs->leaseterm;
206 args->deadthresh = oargs->deadthresh;
207 args->hostname = oargs->hostname;
208}
209
210static void
211nfs_convert_diskless()
212{
213 bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
214 sizeof(struct ifaliasreq));
215 bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
216 sizeof(struct sockaddr_in));
217 nfs_convert_oargs(&nfsv3_diskless.swap_args,&nfs_diskless.swap_args);
218 nfsv3_diskless.swap_fhsize = NFSX_V2FH;
219 bcopy(nfs_diskless.swap_fh,nfsv3_diskless.swap_fh,NFSX_V2FH);
220 bcopy(&nfs_diskless.swap_saddr,&nfsv3_diskless.swap_saddr,
221 sizeof(struct sockaddr_in));
222 bcopy(nfs_diskless.swap_hostnam,nfsv3_diskless.swap_hostnam,
223 MNAMELEN);
224 nfsv3_diskless.swap_nblks = nfs_diskless.swap_nblks;
225 bcopy(&nfs_diskless.swap_ucred, &nfsv3_diskless.swap_ucred,
226 sizeof(struct ucred));
227 nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args);
228 nfsv3_diskless.root_fhsize = NFSX_V2FH;
229 bcopy(nfs_diskless.root_fh,nfsv3_diskless.root_fh,NFSX_V2FH);
230 bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
231 sizeof(struct sockaddr_in));
232 bcopy(nfs_diskless.root_hostnam,nfsv3_diskless.root_hostnam,
233 MNAMELEN);
234 nfsv3_diskless.root_time = nfs_diskless.root_time;
235 bcopy(nfs_diskless.my_hostnam,nfsv3_diskless.my_hostnam,
236 MAXHOSTNAMELEN);
237 nfs_diskless_valid = 3;
238}
239
240/*
241 * nfs statfs call
242 */
243int
244nfs_statfs(mp, sbp, p)
245 struct mount *mp;
246 register struct statfs *sbp;
247 struct proc *p;
248{
249 register struct vnode *vp;
250 register struct nfs_statfs *sfp;
251 register caddr_t cp;
252 register u_long *tl;
253 register long t1, t2;
254 caddr_t bpos, dpos, cp2;
255 struct nfsmount *nmp = VFSTONFS(mp);
256 int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr;
257 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
258 struct ucred *cred;
259 struct nfsnode *np;
260 u_quad_t tquad;
261
262#ifndef nolint
263 sfp = (struct nfs_statfs *)0;
264#endif
265 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
266 if (error)
267 return (error);
268 vp = NFSTOV(np);
269 cred = crget();
270 cred->cr_ngroups = 1;
271 if (v3 && (nmp->nm_flag & NFSMNT_GOTFSINFO) == 0)
272 (void)nfs_fsinfo(nmp, vp, cred, p);
273 nfsstats.rpccnt[NFSPROC_FSSTAT]++;
274 nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3));
275 nfsm_fhtom(vp, v3);
276 nfsm_request(vp, NFSPROC_FSSTAT, p, cred);
277 if (v3)
278 nfsm_postop_attr(vp, retattr);
279 if (!error) {
280 nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
281 } else
282 goto nfsmout;
283
284 sbp->f_type = MOUNT_NFS;
285 sbp->f_flags = nmp->nm_flag;
286 sbp->f_iosize = nfs_iosize(nmp);
287 if (v3) {
288 sbp->f_bsize = NFS_FABLKSIZE;
289 fxdr_hyper(&sfp->sf_tbytes, &tquad);
290 sbp->f_blocks = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
291 fxdr_hyper(&sfp->sf_fbytes, &tquad);
292 sbp->f_bfree = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
293 fxdr_hyper(&sfp->sf_abytes, &tquad);
294 sbp->f_bavail = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
295 sbp->f_files = (fxdr_unsigned(long, sfp->sf_tfiles.nfsuquad[1])
296 & 0x7fffffff);
297 sbp->f_ffree = (fxdr_unsigned(long, sfp->sf_ffiles.nfsuquad[1])
298 & 0x7fffffff);
299 } else {
300 sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
301 sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
302 sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
303 sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
304 sbp->f_files = 0;
305 sbp->f_ffree = 0;
306 }
307 if (sbp != &mp->mnt_stat) {
308 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
309 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
310 }
311 nfsm_reqdone;
312 vput(vp);
313 crfree(cred);
314 return (error);
315}
316
317/*
318 * nfs version 3 fsinfo rpc call
319 */
320int
321nfs_fsinfo(nmp, vp, cred, p)
322 register struct nfsmount *nmp;
323 register struct vnode *vp;
324 struct ucred *cred;
325 struct proc *p;
326{
327 register struct nfsv3_fsinfo *fsp;
328 register caddr_t cp;
329 register long t1, t2;
330 register u_long *tl, pref, max;
331 caddr_t bpos, dpos, cp2;
332 int error = 0, retattr;
333 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
334
335 nfsstats.rpccnt[NFSPROC_FSINFO]++;
336 nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1));
337 nfsm_fhtom(vp, 1);
338 nfsm_request(vp, NFSPROC_FSINFO, p, cred);
339 nfsm_postop_attr(vp, retattr);
340 if (!error) {
341 nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
342 pref = fxdr_unsigned(u_long, fsp->fs_wtpref);
343 if (pref < nmp->nm_wsize)
344 nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
345 ~(NFS_FABLKSIZE - 1);
346 max = fxdr_unsigned(u_long, fsp->fs_wtmax);
347 if (max < nmp->nm_wsize) {
348 nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
349 if (nmp->nm_wsize == 0)
350 nmp->nm_wsize = max;
351 }
352 pref = fxdr_unsigned(u_long, fsp->fs_rtpref);
353 if (pref < nmp->nm_rsize)
354 nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
355 ~(NFS_FABLKSIZE - 1);
356 max = fxdr_unsigned(u_long, fsp->fs_rtmax);
357 if (max < nmp->nm_rsize) {
358 nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
359 if (nmp->nm_rsize == 0)
360 nmp->nm_rsize = max;
361 }
362 pref = fxdr_unsigned(u_long, fsp->fs_dtpref);
363 if (pref < nmp->nm_readdirsize)
364 nmp->nm_readdirsize = pref;
365 if (max < nmp->nm_readdirsize) {
366 nmp->nm_readdirsize = max;
367 }
368 nmp->nm_flag |= NFSMNT_GOTFSINFO;
369 }
370 nfsm_reqdone;
371 return (error);
372}
373
374/*
375 * Mount a remote root fs via. nfs. This depends on the info in the
376 * nfs_diskless structure that has been filled in properly by some primary
377 * bootstrap.
378 * It goes something like this:
379 * - do enough of "ifconfig" by calling ifioctl() so that the system
380 * can talk to the server
381 * - If nfs_diskless.mygateway is filled in, use that address as
382 * a default gateway.
383 * - build the rootfs mount point and call mountnfs() to do the rest.
384 */
385int
386nfs_mountroot(mp)
387 struct mount *mp;
388{
389 struct mount *swap_mp;
390 struct nfsv3_diskless *nd = &nfsv3_diskless;
391 struct socket *so;
392 struct vnode *vp;
393 struct proc *p = curproc; /* XXX */
394 int error, i;
395 u_long l;
396 char buf[128];
397
398 /*
399 * XXX time must be non-zero when we init the interface or else
400 * the arp code will wedge...
401 */
38 */
39
40#include <sys/param.h>
41#include <sys/sockio.h>
42#include <sys/proc.h>
43#include <sys/vnode.h>
44#include <sys/kernel.h>
45#include <sys/sysctl.h>
46#include <sys/malloc.h>
47#include <sys/mount.h>
48#include <sys/mbuf.h>
49#include <sys/socket.h>
50#include <sys/socketvar.h>
51#include <sys/systm.h>
52
53#include <vm/vm.h>
54#include <vm/vm_extern.h>
55
56#include <net/if.h>
57#include <net/route.h>
58#include <netinet/in.h>
59
60#include <nfs/rpcv2.h>
61#include <nfs/nfsproto.h>
62#include <nfs/nfs.h>
63#include <nfs/nfsnode.h>
64#include <nfs/nfsmount.h>
65#include <nfs/xdr_subs.h>
66#include <nfs/nfsm_subs.h>
67#include <nfs/nfsdiskless.h>
68#include <nfs/nqnfs.h>
69
70extern int nfs_mountroot __P((struct mount *mp));
71
72extern int nfs_ticks;
73
74MALLOC_DEFINE(M_NFSREQ, "NFS req", "NFS request header");
75MALLOC_DEFINE(M_NFSMNT, "NFS mount", "NFS mount structure");
76MALLOC_DEFINE(M_NFSBIGFH, "NFSV3 bigfh", "NFS version 3 file handle");
77MALLOC_DEFINE(M_NFSD, "NFS daemon", "Nfs server daemon structure");
78MALLOC_DEFINE(M_NFSDIROFF, "NFSV3 diroff", "NFS directory offset data");
79MALLOC_DEFINE(M_NFSRVDESC, "NFSV3 srvdesc", "NFS server socket descriptor");
80MALLOC_DEFINE(M_NFSUID, "NFS uid", "Nfs uid mapping structure");
81MALLOC_DEFINE(M_NQLEASE, "NQNFS Lease", "Nqnfs lease");
82
83struct nfsstats nfsstats;
84SYSCTL_NODE(_vfs, MOUNT_NFS, nfs, CTLFLAG_RW, 0, "NFS filesystem");
85SYSCTL_STRUCT(_vfs_nfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RD,
86 &nfsstats, nfsstats, "");
87#ifdef NFS_DEBUG
88int nfs_debug;
89SYSCTL_INT(_vfs_nfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0, "");
90#endif
91
92static int nfs_iosize __P((struct nfsmount *nmp));
93static int mountnfs __P((struct nfs_args *,struct mount *,
94 struct sockaddr *,char *,char *,struct vnode **));
95static int nfs_mount __P(( struct mount *mp, char *path, caddr_t data,
96 struct nameidata *ndp, struct proc *p));
97static int nfs_start __P(( struct mount *mp, int flags,
98 struct proc *p));
99static int nfs_unmount __P(( struct mount *mp, int mntflags,
100 struct proc *p));
101static int nfs_root __P(( struct mount *mp, struct vnode **vpp));
102static int nfs_quotactl __P(( struct mount *mp, int cmds, uid_t uid,
103 caddr_t arg, struct proc *p));
104static int nfs_statfs __P(( struct mount *mp, struct statfs *sbp,
105 struct proc *p));
106static int nfs_sync __P(( struct mount *mp, int waitfor,
107 struct ucred *cred, struct proc *p));
108static int nfs_vptofh __P(( struct vnode *vp, struct fid *fhp));
109static int nfs_fhtovp __P((struct mount *mp, struct fid *fhp,
110 struct sockaddr *nam, struct vnode **vpp,
111 int *exflagsp, struct ucred **credanonp));
112static int nfs_vget __P((struct mount *, ino_t, struct vnode **));
113
114
115/*
116 * nfs vfs operations.
117 */
118static struct vfsops nfs_vfsops = {
119 nfs_mount,
120 nfs_start,
121 nfs_unmount,
122 nfs_root,
123 nfs_quotactl,
124 nfs_statfs,
125 nfs_sync,
126 nfs_vget,
127 vfs_vrele,
128 nfs_fhtovp,
129 nfs_vptofh,
130 nfs_init
131};
132VFS_SET(nfs_vfsops, nfs, MOUNT_NFS, VFCF_NETWORK);
133
134/*
135 * This structure must be filled in by a primary bootstrap or bootstrap
136 * server for a diskless/dataless machine. It is initialized below just
137 * to ensure that it is allocated to initialized data (.data not .bss).
138 */
139struct nfs_diskless nfs_diskless = { 0 };
140struct nfsv3_diskless nfsv3_diskless = { 0 };
141int nfs_diskless_valid = 0;
142
143SYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
144 &nfs_diskless_valid, 0, "");
145
146SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
147 nfsv3_diskless.root_hostnam, 0, "");
148
149SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
150 &nfsv3_diskless.root_saddr, sizeof nfsv3_diskless.root_saddr,
151 "%Ssockaddr_in", "");
152
153SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_swappath, CTLFLAG_RD,
154 nfsv3_diskless.swap_hostnam, 0, "");
155
156SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_swapaddr, CTLFLAG_RD,
157 &nfsv3_diskless.swap_saddr, sizeof nfsv3_diskless.swap_saddr,
158 "%Ssockaddr_in","");
159
160
161void nfsargs_ntoh __P((struct nfs_args *));
162static int nfs_mountdiskless __P((char *, char *, int,
163 struct sockaddr_in *, struct nfs_args *,
164 struct proc *, struct vnode **,
165 struct mount **));
166static void nfs_convert_diskless __P((void));
167static void nfs_convert_oargs __P((struct nfs_args *args,
168 struct onfs_args *oargs));
169
170static int nfs_iosize(nmp)
171 struct nfsmount* nmp;
172{
173 int iosize;
174
175 /*
176 * Calculate the size used for io buffers. Use the larger
177 * of the two sizes to minimise nfs requests but make sure
178 * that it is at least one VM page to avoid wasting buffer
179 * space.
180 */
181 iosize = max(nmp->nm_rsize, nmp->nm_wsize);
182 if (iosize < PAGE_SIZE) iosize = PAGE_SIZE;
183 return iosize;
184}
185
186static void nfs_convert_oargs(args,oargs)
187 struct nfs_args *args;
188 struct onfs_args *oargs;
189{
190 args->version = NFS_ARGSVERSION;
191 args->addr = oargs->addr;
192 args->addrlen = oargs->addrlen;
193 args->sotype = oargs->sotype;
194 args->proto = oargs->proto;
195 args->fh = oargs->fh;
196 args->fhsize = oargs->fhsize;
197 args->flags = oargs->flags;
198 args->wsize = oargs->wsize;
199 args->rsize = oargs->rsize;
200 args->readdirsize = oargs->readdirsize;
201 args->timeo = oargs->timeo;
202 args->retrans = oargs->retrans;
203 args->maxgrouplist = oargs->maxgrouplist;
204 args->readahead = oargs->readahead;
205 args->leaseterm = oargs->leaseterm;
206 args->deadthresh = oargs->deadthresh;
207 args->hostname = oargs->hostname;
208}
209
210static void
211nfs_convert_diskless()
212{
213 bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
214 sizeof(struct ifaliasreq));
215 bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
216 sizeof(struct sockaddr_in));
217 nfs_convert_oargs(&nfsv3_diskless.swap_args,&nfs_diskless.swap_args);
218 nfsv3_diskless.swap_fhsize = NFSX_V2FH;
219 bcopy(nfs_diskless.swap_fh,nfsv3_diskless.swap_fh,NFSX_V2FH);
220 bcopy(&nfs_diskless.swap_saddr,&nfsv3_diskless.swap_saddr,
221 sizeof(struct sockaddr_in));
222 bcopy(nfs_diskless.swap_hostnam,nfsv3_diskless.swap_hostnam,
223 MNAMELEN);
224 nfsv3_diskless.swap_nblks = nfs_diskless.swap_nblks;
225 bcopy(&nfs_diskless.swap_ucred, &nfsv3_diskless.swap_ucred,
226 sizeof(struct ucred));
227 nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args);
228 nfsv3_diskless.root_fhsize = NFSX_V2FH;
229 bcopy(nfs_diskless.root_fh,nfsv3_diskless.root_fh,NFSX_V2FH);
230 bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
231 sizeof(struct sockaddr_in));
232 bcopy(nfs_diskless.root_hostnam,nfsv3_diskless.root_hostnam,
233 MNAMELEN);
234 nfsv3_diskless.root_time = nfs_diskless.root_time;
235 bcopy(nfs_diskless.my_hostnam,nfsv3_diskless.my_hostnam,
236 MAXHOSTNAMELEN);
237 nfs_diskless_valid = 3;
238}
239
240/*
241 * nfs statfs call
242 */
243int
244nfs_statfs(mp, sbp, p)
245 struct mount *mp;
246 register struct statfs *sbp;
247 struct proc *p;
248{
249 register struct vnode *vp;
250 register struct nfs_statfs *sfp;
251 register caddr_t cp;
252 register u_long *tl;
253 register long t1, t2;
254 caddr_t bpos, dpos, cp2;
255 struct nfsmount *nmp = VFSTONFS(mp);
256 int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr;
257 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
258 struct ucred *cred;
259 struct nfsnode *np;
260 u_quad_t tquad;
261
262#ifndef nolint
263 sfp = (struct nfs_statfs *)0;
264#endif
265 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
266 if (error)
267 return (error);
268 vp = NFSTOV(np);
269 cred = crget();
270 cred->cr_ngroups = 1;
271 if (v3 && (nmp->nm_flag & NFSMNT_GOTFSINFO) == 0)
272 (void)nfs_fsinfo(nmp, vp, cred, p);
273 nfsstats.rpccnt[NFSPROC_FSSTAT]++;
274 nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3));
275 nfsm_fhtom(vp, v3);
276 nfsm_request(vp, NFSPROC_FSSTAT, p, cred);
277 if (v3)
278 nfsm_postop_attr(vp, retattr);
279 if (!error) {
280 nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
281 } else
282 goto nfsmout;
283
284 sbp->f_type = MOUNT_NFS;
285 sbp->f_flags = nmp->nm_flag;
286 sbp->f_iosize = nfs_iosize(nmp);
287 if (v3) {
288 sbp->f_bsize = NFS_FABLKSIZE;
289 fxdr_hyper(&sfp->sf_tbytes, &tquad);
290 sbp->f_blocks = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
291 fxdr_hyper(&sfp->sf_fbytes, &tquad);
292 sbp->f_bfree = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
293 fxdr_hyper(&sfp->sf_abytes, &tquad);
294 sbp->f_bavail = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
295 sbp->f_files = (fxdr_unsigned(long, sfp->sf_tfiles.nfsuquad[1])
296 & 0x7fffffff);
297 sbp->f_ffree = (fxdr_unsigned(long, sfp->sf_ffiles.nfsuquad[1])
298 & 0x7fffffff);
299 } else {
300 sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
301 sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
302 sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
303 sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
304 sbp->f_files = 0;
305 sbp->f_ffree = 0;
306 }
307 if (sbp != &mp->mnt_stat) {
308 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
309 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
310 }
311 nfsm_reqdone;
312 vput(vp);
313 crfree(cred);
314 return (error);
315}
316
317/*
318 * nfs version 3 fsinfo rpc call
319 */
320int
321nfs_fsinfo(nmp, vp, cred, p)
322 register struct nfsmount *nmp;
323 register struct vnode *vp;
324 struct ucred *cred;
325 struct proc *p;
326{
327 register struct nfsv3_fsinfo *fsp;
328 register caddr_t cp;
329 register long t1, t2;
330 register u_long *tl, pref, max;
331 caddr_t bpos, dpos, cp2;
332 int error = 0, retattr;
333 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
334
335 nfsstats.rpccnt[NFSPROC_FSINFO]++;
336 nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1));
337 nfsm_fhtom(vp, 1);
338 nfsm_request(vp, NFSPROC_FSINFO, p, cred);
339 nfsm_postop_attr(vp, retattr);
340 if (!error) {
341 nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
342 pref = fxdr_unsigned(u_long, fsp->fs_wtpref);
343 if (pref < nmp->nm_wsize)
344 nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
345 ~(NFS_FABLKSIZE - 1);
346 max = fxdr_unsigned(u_long, fsp->fs_wtmax);
347 if (max < nmp->nm_wsize) {
348 nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
349 if (nmp->nm_wsize == 0)
350 nmp->nm_wsize = max;
351 }
352 pref = fxdr_unsigned(u_long, fsp->fs_rtpref);
353 if (pref < nmp->nm_rsize)
354 nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
355 ~(NFS_FABLKSIZE - 1);
356 max = fxdr_unsigned(u_long, fsp->fs_rtmax);
357 if (max < nmp->nm_rsize) {
358 nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
359 if (nmp->nm_rsize == 0)
360 nmp->nm_rsize = max;
361 }
362 pref = fxdr_unsigned(u_long, fsp->fs_dtpref);
363 if (pref < nmp->nm_readdirsize)
364 nmp->nm_readdirsize = pref;
365 if (max < nmp->nm_readdirsize) {
366 nmp->nm_readdirsize = max;
367 }
368 nmp->nm_flag |= NFSMNT_GOTFSINFO;
369 }
370 nfsm_reqdone;
371 return (error);
372}
373
374/*
375 * Mount a remote root fs via. nfs. This depends on the info in the
376 * nfs_diskless structure that has been filled in properly by some primary
377 * bootstrap.
378 * It goes something like this:
379 * - do enough of "ifconfig" by calling ifioctl() so that the system
380 * can talk to the server
381 * - If nfs_diskless.mygateway is filled in, use that address as
382 * a default gateway.
383 * - build the rootfs mount point and call mountnfs() to do the rest.
384 */
385int
386nfs_mountroot(mp)
387 struct mount *mp;
388{
389 struct mount *swap_mp;
390 struct nfsv3_diskless *nd = &nfsv3_diskless;
391 struct socket *so;
392 struct vnode *vp;
393 struct proc *p = curproc; /* XXX */
394 int error, i;
395 u_long l;
396 char buf[128];
397
398 /*
399 * XXX time must be non-zero when we init the interface or else
400 * the arp code will wedge...
401 */
402 while (time.tv_sec == 0)
403 tsleep(&time, PZERO+8, "arpkludge", 10);
402 while (time_second == 0)
403 tsleep(&time_second, PZERO+8, "arpkludge", 10);
404
405 if (nfs_diskless_valid==1)
406 nfs_convert_diskless();
407
408 /*
409 * XXX splnet, so networks will receive...
410 */
411 splnet();
412
413#ifdef notyet
414 /* Set up swap credentials. */
415 proc0.p_ucred->cr_uid = ntohl(nd->swap_ucred.cr_uid);
416 proc0.p_ucred->cr_gid = ntohl(nd->swap_ucred.cr_gid);
417 if ((proc0.p_ucred->cr_ngroups = ntohs(nd->swap_ucred.cr_ngroups)) >
418 NGROUPS)
419 proc0.p_ucred->cr_ngroups = NGROUPS;
420 for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
421 proc0.p_ucred->cr_groups[i] = ntohl(nd->swap_ucred.cr_groups[i]);
422#endif
423
424 /*
425 * Do enough of ifconfig(8) so that the critical net interface can
426 * talk to the server.
427 */
428 error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0, p);
429 if (error)
430 panic("nfs_mountroot: socreate(%04x): %d",
431 nd->myif.ifra_addr.sa_family, error);
432
433 /*
434 * We might not have been told the right interface, so we pass
435 * over the first ten interfaces of the same kind, until we get
436 * one of them configured.
437 */
438
439 for (i = strlen(nd->myif.ifra_name) - 1;
440 nd->myif.ifra_name[i] >= '0' &&
441 nd->myif.ifra_name[i] <= '9';
442 nd->myif.ifra_name[i] ++) {
443 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, p);
444 if(!error)
445 break;
446 }
447 if (error)
448 panic("nfs_mountroot: SIOCAIFADDR: %d", error);
449 soclose(so);
450
451 /*
452 * If the gateway field is filled in, set it as the default route.
453 */
454 if (nd->mygateway.sin_len != 0) {
455 struct sockaddr_in mask, sin;
456
457 bzero((caddr_t)&mask, sizeof(mask));
458 sin = mask;
459 sin.sin_family = AF_INET;
460 sin.sin_len = sizeof(sin);
461 error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
462 (struct sockaddr *)&nd->mygateway,
463 (struct sockaddr *)&mask,
464 RTF_UP | RTF_GATEWAY, (struct rtentry **)0);
465 if (error)
466 panic("nfs_mountroot: RTM_ADD: %d", error);
467 }
468
469 /*
470 * Create the rootfs mount point.
471 */
472 nd->root_args.fh = nd->root_fh;
473 nd->root_args.fhsize = nd->root_fhsize;
474 l = ntohl(nd->root_saddr.sin_addr.s_addr);
475 sprintf(buf,"%ld.%ld.%ld.%ld:%s",
476 (l >> 24) & 0xff, (l >> 16) & 0xff,
477 (l >> 8) & 0xff, (l >> 0) & 0xff,nd->root_hostnam);
478 printf("NFS ROOT: %s\n",buf);
479 if (error = nfs_mountdiskless(buf, "/", MNT_RDONLY,
480 &nd->root_saddr, &nd->root_args, p, &vp, &mp)) {
481 if (swap_mp) {
482 mp->mnt_vfc->vfc_refcount--;
483 free(swap_mp, M_MOUNT);
484 }
485 return (error);
486 }
487
488 swap_mp = NULL;
489 if (nd->swap_nblks) {
490
491 /* Convert to DEV_BSIZE instead of Kilobyte */
492 nd->swap_nblks *= 2;
493
494 /*
495 * Create a fake mount point just for the swap vnode so that the
496 * swap file can be on a different server from the rootfs.
497 */
498 nd->swap_args.fh = nd->swap_fh;
499 nd->swap_args.fhsize = nd->swap_fhsize;
500 l = ntohl(nd->swap_saddr.sin_addr.s_addr);
501 sprintf(buf,"%ld.%ld.%ld.%ld:%s",
502 (l >> 24) & 0xff, (l >> 16) & 0xff,
503 (l >> 8) & 0xff, (l >> 0) & 0xff,nd->swap_hostnam);
504 printf("NFS SWAP: %s\n",buf);
505 if (error = nfs_mountdiskless(buf, "/swap", 0,
506 &nd->swap_saddr, &nd->swap_args, p, &vp, &swap_mp))
507 return (error);
508 vfs_unbusy(swap_mp, p);
509
510 VTONFS(vp)->n_size = VTONFS(vp)->n_vattr.va_size =
511 nd->swap_nblks * DEV_BSIZE ;
512
513 /*
514 * Since the swap file is not the root dir of a file system,
515 * hack it to a regular file.
516 */
517 vp->v_type = VREG;
518 vp->v_flag = 0;
519 VREF(vp);
520 swaponvp(p, vp, NODEV, nd->swap_nblks);
521 }
522
523 mp->mnt_flag |= MNT_ROOTFS;
524 mp->mnt_vnodecovered = NULLVP;
525 rootvp = vp;
526 vfs_unbusy(mp, p);
527
528 /*
529 * This is not really an nfs issue, but it is much easier to
530 * set hostname here and then let the "/etc/rc.xxx" files
531 * mount the right /var based upon its preset value.
532 */
533 bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN);
534 hostname[MAXHOSTNAMELEN - 1] = '\0';
535 for (i = 0; i < MAXHOSTNAMELEN; i++)
536 if (hostname[i] == '\0')
537 break;
538 inittodr(ntohl(nd->root_time));
539 return (0);
540}
541
542/*
543 * Internal version of mount system call for diskless setup.
544 */
545static int
546nfs_mountdiskless(path, which, mountflag, sin, args, p, vpp, mpp)
547 char *path;
548 char *which;
549 int mountflag;
550 struct sockaddr_in *sin;
551 struct nfs_args *args;
552 struct proc *p;
553 struct vnode **vpp;
554 struct mount **mpp;
555{
556 struct mount *mp;
557 struct sockaddr *nam;
558 int error;
559
560 mp = *mpp;
561
562 if (!mp && (error = vfs_rootmountalloc("nfs", path, &mp))) {
563 printf("nfs_mountroot: NFS not configured");
564 return (error);
565 }
566
567 mp->mnt_kern_flag = 0;
568 mp->mnt_flag = mountflag;
569 nam = dup_sockaddr((struct sockaddr *)sin, 1);
570 if (error = mountnfs(args, mp, nam, which, path, vpp)) {
571 printf("nfs_mountroot: mount %s on %s: %d", path, which, error);
572 mp->mnt_vfc->vfc_refcount--;
573 vfs_unbusy(mp, p);
574 free(mp, M_MOUNT);
575 FREE(nam, M_SONAME);
576 return (error);
577 }
578 (void) copystr(which, mp->mnt_stat.f_mntonname, MNAMELEN - 1, 0);
579 *mpp = mp;
580 return (0);
581}
582
583/*
584 * VFS Operations.
585 *
586 * mount system call
587 * It seems a bit dumb to copyinstr() the host and path here and then
588 * bcopy() them in mountnfs(), but I wanted to detect errors before
589 * doing the sockargs() call because sockargs() allocates an mbuf and
590 * an error after that means that I have to release the mbuf.
591 */
592/* ARGSUSED */
593static int
594nfs_mount(mp, path, data, ndp, p)
595 struct mount *mp;
596 char *path;
597 caddr_t data;
598 struct nameidata *ndp;
599 struct proc *p;
600{
601 int error;
602 struct nfs_args args;
603 struct sockaddr *nam;
604 struct vnode *vp;
605 char pth[MNAMELEN], hst[MNAMELEN];
606 u_int len;
607 u_char nfh[NFSX_V3FHMAX];
608
609 if (path == NULL) {
610 nfs_mountroot(mp);
611 return (0);
612 }
613 error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args));
614 if (error)
615 return (error);
616 if (args.version != NFS_ARGSVERSION) {
617#ifndef NO_COMPAT_PRELITE2
618 /*
619 * If the argument version is unknown, then assume the
620 * caller is a pre-lite2 4.4BSD client and convert its
621 * arguments.
622 */
623 struct onfs_args oargs;
624 error = copyin(data, (caddr_t)&oargs, sizeof (struct onfs_args));
625 if (error)
626 return (error);
627 nfs_convert_oargs(&args,&oargs);
628#else /* NO_COMPAT_PRELITE2 */
629 return (EPROGMISMATCH);
630#endif /* !NO_COMPAT_PRELITE2 */
631 }
632 error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize);
633 if (error)
634 return (error);
635 error = copyinstr(path, pth, MNAMELEN-1, &len);
636 if (error)
637 return (error);
638 bzero(&pth[len], MNAMELEN - len);
639 error = copyinstr(args.hostname, hst, MNAMELEN-1, &len);
640 if (error)
641 return (error);
642 bzero(&hst[len], MNAMELEN - len);
643 /* sockargs() call must be after above copyin() calls */
644 error = getsockaddr(&nam, (caddr_t)args.addr, args.addrlen);
645 if (error)
646 return (error);
647 args.fh = nfh;
648 error = mountnfs(&args, mp, nam, pth, hst, &vp);
649 return (error);
650}
651
652/*
653 * Common code for mount and mountroot
654 */
655static int
656mountnfs(argp, mp, nam, pth, hst, vpp)
657 register struct nfs_args *argp;
658 register struct mount *mp;
659 struct sockaddr *nam;
660 char *pth, *hst;
661 struct vnode **vpp;
662{
663 register struct nfsmount *nmp;
664 struct nfsnode *np;
665 int error, maxio;
666 struct vattr attrs;
667
668 if (mp->mnt_flag & MNT_UPDATE) {
669 nmp = VFSTONFS(mp);
670 /* update paths, file handles, etc, here XXX */
671 FREE(nam, M_SONAME);
672 return (0);
673 } else {
674 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount),
675 M_NFSMNT, M_WAITOK);
676 bzero((caddr_t)nmp, sizeof (struct nfsmount));
677 TAILQ_INIT(&nmp->nm_uidlruhead);
678 TAILQ_INIT(&nmp->nm_bufq);
679 mp->mnt_data = (qaddr_t)nmp;
680 }
681 vfs_getnewfsid(mp);
682 nmp->nm_mountp = mp;
683 nmp->nm_flag = argp->flags;
684 if (nmp->nm_flag & NFSMNT_NQNFS)
685 /*
686 * We have to set mnt_maxsymlink to a non-zero value so
687 * that COMPAT_43 routines will know that we are setting
688 * the d_type field in directories (and can zero it for
689 * unsuspecting binaries).
690 */
691 mp->mnt_maxsymlinklen = 1;
692 nmp->nm_timeo = NFS_TIMEO;
693 nmp->nm_retry = NFS_RETRANS;
694 nmp->nm_wsize = NFS_WSIZE;
695 nmp->nm_rsize = NFS_RSIZE;
696 nmp->nm_readdirsize = NFS_READDIRSIZE;
697 nmp->nm_numgrps = NFS_MAXGRPS;
698 nmp->nm_readahead = NFS_DEFRAHEAD;
699 nmp->nm_leaseterm = NQ_DEFLEASE;
700 nmp->nm_deadthresh = NQ_DEADTHRESH;
701 CIRCLEQ_INIT(&nmp->nm_timerhead);
702 nmp->nm_inprog = NULLVP;
703 nmp->nm_fhsize = argp->fhsize;
704 bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
705 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
706 bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
707 nmp->nm_nam = nam;
708
709 /*
710 * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
711 * no sense in that context.
712 */
713 if (argp->sotype == SOCK_STREAM)
714 argp->flags &= ~NFSMNT_NOCONN;
715
716 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
717 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
718 if (nmp->nm_timeo < NFS_MINTIMEO)
719 nmp->nm_timeo = NFS_MINTIMEO;
720 else if (nmp->nm_timeo > NFS_MAXTIMEO)
721 nmp->nm_timeo = NFS_MAXTIMEO;
722 }
723
724 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
725 nmp->nm_retry = argp->retrans;
726 if (nmp->nm_retry > NFS_MAXREXMIT)
727 nmp->nm_retry = NFS_MAXREXMIT;
728 }
729
730 if (argp->flags & NFSMNT_NFSV3) {
731 if (argp->sotype == SOCK_DGRAM)
732 maxio = NFS_MAXDGRAMDATA;
733 else
734 maxio = NFS_MAXDATA;
735 } else
736 maxio = NFS_V2MAXDATA;
737
738 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
739 nmp->nm_wsize = argp->wsize;
740 /* Round down to multiple of blocksize */
741 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
742 if (nmp->nm_wsize <= 0)
743 nmp->nm_wsize = NFS_FABLKSIZE;
744 }
745 if (nmp->nm_wsize > maxio)
746 nmp->nm_wsize = maxio;
747 if (nmp->nm_wsize > MAXBSIZE)
748 nmp->nm_wsize = MAXBSIZE;
749
750 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
751 nmp->nm_rsize = argp->rsize;
752 /* Round down to multiple of blocksize */
753 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
754 if (nmp->nm_rsize <= 0)
755 nmp->nm_rsize = NFS_FABLKSIZE;
756 }
757 if (nmp->nm_rsize > maxio)
758 nmp->nm_rsize = maxio;
759 if (nmp->nm_rsize > MAXBSIZE)
760 nmp->nm_rsize = MAXBSIZE;
761
762 if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
763 nmp->nm_readdirsize = argp->readdirsize;
764 }
765 if (nmp->nm_readdirsize > maxio)
766 nmp->nm_readdirsize = maxio;
767 if (nmp->nm_readdirsize > nmp->nm_rsize)
768 nmp->nm_readdirsize = nmp->nm_rsize;
769
770 if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
771 argp->maxgrouplist <= NFS_MAXGRPS)
772 nmp->nm_numgrps = argp->maxgrouplist;
773 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
774 argp->readahead <= NFS_MAXRAHEAD)
775 nmp->nm_readahead = argp->readahead;
776 if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
777 argp->leaseterm <= NQ_MAXLEASE)
778 nmp->nm_leaseterm = argp->leaseterm;
779 if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
780 argp->deadthresh <= NQ_NEVERDEAD)
781 nmp->nm_deadthresh = argp->deadthresh;
782 /* Set up the sockets and per-host congestion */
783 nmp->nm_sotype = argp->sotype;
784 nmp->nm_soproto = argp->proto;
785
786 /*
787 * For Connection based sockets (TCP,...) defer the connect until
788 * the first request, in case the server is not responding.
789 */
790 if (nmp->nm_sotype == SOCK_DGRAM &&
791 (error = nfs_connect(nmp, (struct nfsreq *)0)))
792 goto bad;
793
794 /*
795 * This is silly, but it has to be set so that vinifod() works.
796 * We do not want to do an nfs_statfs() here since we can get
797 * stuck on a dead server and we are holding a lock on the mount
798 * point.
799 */
800 mp->mnt_stat.f_iosize = nfs_iosize(nmp);
801 /*
802 * A reference count is needed on the nfsnode representing the
803 * remote root. If this object is not persistent, then backward
804 * traversals of the mount point (i.e. "..") will not work if
805 * the nfsnode gets flushed out of the cache. Ufs does not have
806 * this problem, because one can identify root inodes by their
807 * number == ROOTINO (2).
808 */
809 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
810 if (error)
811 goto bad;
812 *vpp = NFSTOV(np);
813
814 /*
815 * Get file attributes for the mountpoint. This has the side
816 * effect of filling in (*vpp)->v_type with the correct value.
817 */
818 VOP_GETATTR(*vpp, &attrs, curproc->p_ucred, curproc);
819
820 /*
821 * Lose the lock but keep the ref.
822 */
823 VOP_UNLOCK(*vpp, 0, curproc);
824
825 return (0);
826bad:
827 nfs_disconnect(nmp);
828 free((caddr_t)nmp, M_NFSMNT);
829 FREE(nam, M_SONAME);
830 return (error);
831}
832
833/*
834 * unmount system call
835 */
836static int
837nfs_unmount(mp, mntflags, p)
838 struct mount *mp;
839 int mntflags;
840 struct proc *p;
841{
842 register struct nfsmount *nmp;
843 struct nfsnode *np;
844 struct vnode *vp;
845 int error, flags = 0;
846
847 if (mntflags & MNT_FORCE)
848 flags |= FORCECLOSE;
849 nmp = VFSTONFS(mp);
850 /*
851 * Goes something like this..
852 * - Check for activity on the root vnode (other than ourselves).
853 * - Call vflush() to clear out vnodes for this file system,
854 * except for the root vnode.
855 * - Decrement reference on the vnode representing remote root.
856 * - Close the socket
857 * - Free up the data structures
858 */
859 /*
860 * We need to decrement the ref. count on the nfsnode representing
861 * the remote root. See comment in mountnfs(). The VFS unmount()
862 * has done vput on this vnode, otherwise we would get deadlock!
863 */
864 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
865 if (error)
866 return(error);
867 vp = NFSTOV(np);
868 if (vp->v_usecount > 2) {
869 vput(vp);
870 return (EBUSY);
871 }
872
873 /*
874 * Must handshake with nqnfs_clientd() if it is active.
875 */
876 nmp->nm_flag |= NFSMNT_DISMINPROG;
877 while (nmp->nm_inprog != NULLVP)
878 (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
879 error = vflush(mp, vp, flags);
880 if (error) {
881 vput(vp);
882 nmp->nm_flag &= ~NFSMNT_DISMINPROG;
883 return (error);
884 }
885
886 /*
887 * We are now committed to the unmount.
888 * For NQNFS, let the server daemon free the nfsmount structure.
889 */
890 if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
891 nmp->nm_flag |= NFSMNT_DISMNT;
892
893 /*
894 * There are two reference counts and one lock to get rid of here.
895 */
896 vput(vp);
897 vrele(vp);
898 vgone(vp);
899 nfs_disconnect(nmp);
900 FREE(nmp->nm_nam, M_SONAME);
901
902 if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
903 free((caddr_t)nmp, M_NFSMNT);
904 return (0);
905}
906
907/*
908 * Return root of a filesystem
909 */
910static int
911nfs_root(mp, vpp)
912 struct mount *mp;
913 struct vnode **vpp;
914{
915 register struct vnode *vp;
916 struct nfsmount *nmp;
917 struct nfsnode *np;
918 int error;
919
920 nmp = VFSTONFS(mp);
921 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
922 if (error)
923 return (error);
924 vp = NFSTOV(np);
925 if (vp->v_type == VNON)
926 vp->v_type = VDIR;
927 vp->v_flag = VROOT;
928 *vpp = vp;
929 return (0);
930}
931
932extern int syncprt;
933
934/*
935 * Flush out the buffer cache
936 */
937/* ARGSUSED */
938static int
939nfs_sync(mp, waitfor, cred, p)
940 struct mount *mp;
941 int waitfor;
942 struct ucred *cred;
943 struct proc *p;
944{
945 register struct vnode *vp;
946 int error, allerror = 0;
947
948 /*
949 * Force stale buffer cache information to be flushed.
950 */
951loop:
952 for (vp = mp->mnt_vnodelist.lh_first;
953 vp != NULL;
954 vp = vp->v_mntvnodes.le_next) {
955 /*
956 * If the vnode that we are about to sync is no longer
957 * associated with this mount point, start over.
958 */
959 if (vp->v_mount != mp)
960 goto loop;
961 if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL ||
962 waitfor == MNT_LAZY)
963 continue;
964 if (vget(vp, LK_EXCLUSIVE, p))
965 goto loop;
966 error = VOP_FSYNC(vp, cred, waitfor, p);
967 if (error)
968 allerror = error;
969 vput(vp);
970 }
971 return (allerror);
972}
973
974/*
975 * NFS flat namespace lookup.
976 * Currently unsupported.
977 */
978/* ARGSUSED */
979static int
980nfs_vget(mp, ino, vpp)
981 struct mount *mp;
982 ino_t ino;
983 struct vnode **vpp;
984{
985
986 return (EOPNOTSUPP);
987}
988
989/*
990 * At this point, this should never happen
991 */
992/* ARGSUSED */
993static int
994nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
995 register struct mount *mp;
996 struct fid *fhp;
997 struct sockaddr *nam;
998 struct vnode **vpp;
999 int *exflagsp;
1000 struct ucred **credanonp;
1001{
1002
1003 return (EINVAL);
1004}
1005
1006/*
1007 * Vnode pointer to File handle, should never happen either
1008 */
1009/* ARGSUSED */
1010static int
1011nfs_vptofh(vp, fhp)
1012 struct vnode *vp;
1013 struct fid *fhp;
1014{
1015
1016 return (EINVAL);
1017}
1018
1019/*
1020 * Vfs start routine, a no-op.
1021 */
1022/* ARGSUSED */
1023static int
1024nfs_start(mp, flags, p)
1025 struct mount *mp;
1026 int flags;
1027 struct proc *p;
1028{
1029
1030 return (0);
1031}
1032
1033/*
1034 * Do operations associated with quotas, not supported
1035 */
1036/* ARGSUSED */
1037static int
1038nfs_quotactl(mp, cmd, uid, arg, p)
1039 struct mount *mp;
1040 int cmd;
1041 uid_t uid;
1042 caddr_t arg;
1043 struct proc *p;
1044{
1045
1046 return (EOPNOTSUPP);
1047}
404
405 if (nfs_diskless_valid==1)
406 nfs_convert_diskless();
407
408 /*
409 * XXX splnet, so networks will receive...
410 */
411 splnet();
412
413#ifdef notyet
414 /* Set up swap credentials. */
415 proc0.p_ucred->cr_uid = ntohl(nd->swap_ucred.cr_uid);
416 proc0.p_ucred->cr_gid = ntohl(nd->swap_ucred.cr_gid);
417 if ((proc0.p_ucred->cr_ngroups = ntohs(nd->swap_ucred.cr_ngroups)) >
418 NGROUPS)
419 proc0.p_ucred->cr_ngroups = NGROUPS;
420 for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
421 proc0.p_ucred->cr_groups[i] = ntohl(nd->swap_ucred.cr_groups[i]);
422#endif
423
424 /*
425 * Do enough of ifconfig(8) so that the critical net interface can
426 * talk to the server.
427 */
428 error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0, p);
429 if (error)
430 panic("nfs_mountroot: socreate(%04x): %d",
431 nd->myif.ifra_addr.sa_family, error);
432
433 /*
434 * We might not have been told the right interface, so we pass
435 * over the first ten interfaces of the same kind, until we get
436 * one of them configured.
437 */
438
439 for (i = strlen(nd->myif.ifra_name) - 1;
440 nd->myif.ifra_name[i] >= '0' &&
441 nd->myif.ifra_name[i] <= '9';
442 nd->myif.ifra_name[i] ++) {
443 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, p);
444 if(!error)
445 break;
446 }
447 if (error)
448 panic("nfs_mountroot: SIOCAIFADDR: %d", error);
449 soclose(so);
450
451 /*
452 * If the gateway field is filled in, set it as the default route.
453 */
454 if (nd->mygateway.sin_len != 0) {
455 struct sockaddr_in mask, sin;
456
457 bzero((caddr_t)&mask, sizeof(mask));
458 sin = mask;
459 sin.sin_family = AF_INET;
460 sin.sin_len = sizeof(sin);
461 error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
462 (struct sockaddr *)&nd->mygateway,
463 (struct sockaddr *)&mask,
464 RTF_UP | RTF_GATEWAY, (struct rtentry **)0);
465 if (error)
466 panic("nfs_mountroot: RTM_ADD: %d", error);
467 }
468
469 /*
470 * Create the rootfs mount point.
471 */
472 nd->root_args.fh = nd->root_fh;
473 nd->root_args.fhsize = nd->root_fhsize;
474 l = ntohl(nd->root_saddr.sin_addr.s_addr);
475 sprintf(buf,"%ld.%ld.%ld.%ld:%s",
476 (l >> 24) & 0xff, (l >> 16) & 0xff,
477 (l >> 8) & 0xff, (l >> 0) & 0xff,nd->root_hostnam);
478 printf("NFS ROOT: %s\n",buf);
479 if (error = nfs_mountdiskless(buf, "/", MNT_RDONLY,
480 &nd->root_saddr, &nd->root_args, p, &vp, &mp)) {
481 if (swap_mp) {
482 mp->mnt_vfc->vfc_refcount--;
483 free(swap_mp, M_MOUNT);
484 }
485 return (error);
486 }
487
488 swap_mp = NULL;
489 if (nd->swap_nblks) {
490
491 /* Convert to DEV_BSIZE instead of Kilobyte */
492 nd->swap_nblks *= 2;
493
494 /*
495 * Create a fake mount point just for the swap vnode so that the
496 * swap file can be on a different server from the rootfs.
497 */
498 nd->swap_args.fh = nd->swap_fh;
499 nd->swap_args.fhsize = nd->swap_fhsize;
500 l = ntohl(nd->swap_saddr.sin_addr.s_addr);
501 sprintf(buf,"%ld.%ld.%ld.%ld:%s",
502 (l >> 24) & 0xff, (l >> 16) & 0xff,
503 (l >> 8) & 0xff, (l >> 0) & 0xff,nd->swap_hostnam);
504 printf("NFS SWAP: %s\n",buf);
505 if (error = nfs_mountdiskless(buf, "/swap", 0,
506 &nd->swap_saddr, &nd->swap_args, p, &vp, &swap_mp))
507 return (error);
508 vfs_unbusy(swap_mp, p);
509
510 VTONFS(vp)->n_size = VTONFS(vp)->n_vattr.va_size =
511 nd->swap_nblks * DEV_BSIZE ;
512
513 /*
514 * Since the swap file is not the root dir of a file system,
515 * hack it to a regular file.
516 */
517 vp->v_type = VREG;
518 vp->v_flag = 0;
519 VREF(vp);
520 swaponvp(p, vp, NODEV, nd->swap_nblks);
521 }
522
523 mp->mnt_flag |= MNT_ROOTFS;
524 mp->mnt_vnodecovered = NULLVP;
525 rootvp = vp;
526 vfs_unbusy(mp, p);
527
528 /*
529 * This is not really an nfs issue, but it is much easier to
530 * set hostname here and then let the "/etc/rc.xxx" files
531 * mount the right /var based upon its preset value.
532 */
533 bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN);
534 hostname[MAXHOSTNAMELEN - 1] = '\0';
535 for (i = 0; i < MAXHOSTNAMELEN; i++)
536 if (hostname[i] == '\0')
537 break;
538 inittodr(ntohl(nd->root_time));
539 return (0);
540}
541
542/*
543 * Internal version of mount system call for diskless setup.
544 */
545static int
546nfs_mountdiskless(path, which, mountflag, sin, args, p, vpp, mpp)
547 char *path;
548 char *which;
549 int mountflag;
550 struct sockaddr_in *sin;
551 struct nfs_args *args;
552 struct proc *p;
553 struct vnode **vpp;
554 struct mount **mpp;
555{
556 struct mount *mp;
557 struct sockaddr *nam;
558 int error;
559
560 mp = *mpp;
561
562 if (!mp && (error = vfs_rootmountalloc("nfs", path, &mp))) {
563 printf("nfs_mountroot: NFS not configured");
564 return (error);
565 }
566
567 mp->mnt_kern_flag = 0;
568 mp->mnt_flag = mountflag;
569 nam = dup_sockaddr((struct sockaddr *)sin, 1);
570 if (error = mountnfs(args, mp, nam, which, path, vpp)) {
571 printf("nfs_mountroot: mount %s on %s: %d", path, which, error);
572 mp->mnt_vfc->vfc_refcount--;
573 vfs_unbusy(mp, p);
574 free(mp, M_MOUNT);
575 FREE(nam, M_SONAME);
576 return (error);
577 }
578 (void) copystr(which, mp->mnt_stat.f_mntonname, MNAMELEN - 1, 0);
579 *mpp = mp;
580 return (0);
581}
582
583/*
584 * VFS Operations.
585 *
586 * mount system call
587 * It seems a bit dumb to copyinstr() the host and path here and then
588 * bcopy() them in mountnfs(), but I wanted to detect errors before
589 * doing the sockargs() call because sockargs() allocates an mbuf and
590 * an error after that means that I have to release the mbuf.
591 */
592/* ARGSUSED */
593static int
594nfs_mount(mp, path, data, ndp, p)
595 struct mount *mp;
596 char *path;
597 caddr_t data;
598 struct nameidata *ndp;
599 struct proc *p;
600{
601 int error;
602 struct nfs_args args;
603 struct sockaddr *nam;
604 struct vnode *vp;
605 char pth[MNAMELEN], hst[MNAMELEN];
606 u_int len;
607 u_char nfh[NFSX_V3FHMAX];
608
609 if (path == NULL) {
610 nfs_mountroot(mp);
611 return (0);
612 }
613 error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args));
614 if (error)
615 return (error);
616 if (args.version != NFS_ARGSVERSION) {
617#ifndef NO_COMPAT_PRELITE2
618 /*
619 * If the argument version is unknown, then assume the
620 * caller is a pre-lite2 4.4BSD client and convert its
621 * arguments.
622 */
623 struct onfs_args oargs;
624 error = copyin(data, (caddr_t)&oargs, sizeof (struct onfs_args));
625 if (error)
626 return (error);
627 nfs_convert_oargs(&args,&oargs);
628#else /* NO_COMPAT_PRELITE2 */
629 return (EPROGMISMATCH);
630#endif /* !NO_COMPAT_PRELITE2 */
631 }
632 error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize);
633 if (error)
634 return (error);
635 error = copyinstr(path, pth, MNAMELEN-1, &len);
636 if (error)
637 return (error);
638 bzero(&pth[len], MNAMELEN - len);
639 error = copyinstr(args.hostname, hst, MNAMELEN-1, &len);
640 if (error)
641 return (error);
642 bzero(&hst[len], MNAMELEN - len);
643 /* sockargs() call must be after above copyin() calls */
644 error = getsockaddr(&nam, (caddr_t)args.addr, args.addrlen);
645 if (error)
646 return (error);
647 args.fh = nfh;
648 error = mountnfs(&args, mp, nam, pth, hst, &vp);
649 return (error);
650}
651
652/*
653 * Common code for mount and mountroot
654 */
655static int
656mountnfs(argp, mp, nam, pth, hst, vpp)
657 register struct nfs_args *argp;
658 register struct mount *mp;
659 struct sockaddr *nam;
660 char *pth, *hst;
661 struct vnode **vpp;
662{
663 register struct nfsmount *nmp;
664 struct nfsnode *np;
665 int error, maxio;
666 struct vattr attrs;
667
668 if (mp->mnt_flag & MNT_UPDATE) {
669 nmp = VFSTONFS(mp);
670 /* update paths, file handles, etc, here XXX */
671 FREE(nam, M_SONAME);
672 return (0);
673 } else {
674 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount),
675 M_NFSMNT, M_WAITOK);
676 bzero((caddr_t)nmp, sizeof (struct nfsmount));
677 TAILQ_INIT(&nmp->nm_uidlruhead);
678 TAILQ_INIT(&nmp->nm_bufq);
679 mp->mnt_data = (qaddr_t)nmp;
680 }
681 vfs_getnewfsid(mp);
682 nmp->nm_mountp = mp;
683 nmp->nm_flag = argp->flags;
684 if (nmp->nm_flag & NFSMNT_NQNFS)
685 /*
686 * We have to set mnt_maxsymlink to a non-zero value so
687 * that COMPAT_43 routines will know that we are setting
688 * the d_type field in directories (and can zero it for
689 * unsuspecting binaries).
690 */
691 mp->mnt_maxsymlinklen = 1;
692 nmp->nm_timeo = NFS_TIMEO;
693 nmp->nm_retry = NFS_RETRANS;
694 nmp->nm_wsize = NFS_WSIZE;
695 nmp->nm_rsize = NFS_RSIZE;
696 nmp->nm_readdirsize = NFS_READDIRSIZE;
697 nmp->nm_numgrps = NFS_MAXGRPS;
698 nmp->nm_readahead = NFS_DEFRAHEAD;
699 nmp->nm_leaseterm = NQ_DEFLEASE;
700 nmp->nm_deadthresh = NQ_DEADTHRESH;
701 CIRCLEQ_INIT(&nmp->nm_timerhead);
702 nmp->nm_inprog = NULLVP;
703 nmp->nm_fhsize = argp->fhsize;
704 bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
705 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
706 bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
707 nmp->nm_nam = nam;
708
709 /*
710 * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
711 * no sense in that context.
712 */
713 if (argp->sotype == SOCK_STREAM)
714 argp->flags &= ~NFSMNT_NOCONN;
715
716 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
717 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
718 if (nmp->nm_timeo < NFS_MINTIMEO)
719 nmp->nm_timeo = NFS_MINTIMEO;
720 else if (nmp->nm_timeo > NFS_MAXTIMEO)
721 nmp->nm_timeo = NFS_MAXTIMEO;
722 }
723
724 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
725 nmp->nm_retry = argp->retrans;
726 if (nmp->nm_retry > NFS_MAXREXMIT)
727 nmp->nm_retry = NFS_MAXREXMIT;
728 }
729
730 if (argp->flags & NFSMNT_NFSV3) {
731 if (argp->sotype == SOCK_DGRAM)
732 maxio = NFS_MAXDGRAMDATA;
733 else
734 maxio = NFS_MAXDATA;
735 } else
736 maxio = NFS_V2MAXDATA;
737
738 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
739 nmp->nm_wsize = argp->wsize;
740 /* Round down to multiple of blocksize */
741 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
742 if (nmp->nm_wsize <= 0)
743 nmp->nm_wsize = NFS_FABLKSIZE;
744 }
745 if (nmp->nm_wsize > maxio)
746 nmp->nm_wsize = maxio;
747 if (nmp->nm_wsize > MAXBSIZE)
748 nmp->nm_wsize = MAXBSIZE;
749
750 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
751 nmp->nm_rsize = argp->rsize;
752 /* Round down to multiple of blocksize */
753 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
754 if (nmp->nm_rsize <= 0)
755 nmp->nm_rsize = NFS_FABLKSIZE;
756 }
757 if (nmp->nm_rsize > maxio)
758 nmp->nm_rsize = maxio;
759 if (nmp->nm_rsize > MAXBSIZE)
760 nmp->nm_rsize = MAXBSIZE;
761
762 if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
763 nmp->nm_readdirsize = argp->readdirsize;
764 }
765 if (nmp->nm_readdirsize > maxio)
766 nmp->nm_readdirsize = maxio;
767 if (nmp->nm_readdirsize > nmp->nm_rsize)
768 nmp->nm_readdirsize = nmp->nm_rsize;
769
770 if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
771 argp->maxgrouplist <= NFS_MAXGRPS)
772 nmp->nm_numgrps = argp->maxgrouplist;
773 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
774 argp->readahead <= NFS_MAXRAHEAD)
775 nmp->nm_readahead = argp->readahead;
776 if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
777 argp->leaseterm <= NQ_MAXLEASE)
778 nmp->nm_leaseterm = argp->leaseterm;
779 if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
780 argp->deadthresh <= NQ_NEVERDEAD)
781 nmp->nm_deadthresh = argp->deadthresh;
782 /* Set up the sockets and per-host congestion */
783 nmp->nm_sotype = argp->sotype;
784 nmp->nm_soproto = argp->proto;
785
786 /*
787 * For Connection based sockets (TCP,...) defer the connect until
788 * the first request, in case the server is not responding.
789 */
790 if (nmp->nm_sotype == SOCK_DGRAM &&
791 (error = nfs_connect(nmp, (struct nfsreq *)0)))
792 goto bad;
793
794 /*
795 * This is silly, but it has to be set so that vinifod() works.
796 * We do not want to do an nfs_statfs() here since we can get
797 * stuck on a dead server and we are holding a lock on the mount
798 * point.
799 */
800 mp->mnt_stat.f_iosize = nfs_iosize(nmp);
801 /*
802 * A reference count is needed on the nfsnode representing the
803 * remote root. If this object is not persistent, then backward
804 * traversals of the mount point (i.e. "..") will not work if
805 * the nfsnode gets flushed out of the cache. Ufs does not have
806 * this problem, because one can identify root inodes by their
807 * number == ROOTINO (2).
808 */
809 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
810 if (error)
811 goto bad;
812 *vpp = NFSTOV(np);
813
814 /*
815 * Get file attributes for the mountpoint. This has the side
816 * effect of filling in (*vpp)->v_type with the correct value.
817 */
818 VOP_GETATTR(*vpp, &attrs, curproc->p_ucred, curproc);
819
820 /*
821 * Lose the lock but keep the ref.
822 */
823 VOP_UNLOCK(*vpp, 0, curproc);
824
825 return (0);
826bad:
827 nfs_disconnect(nmp);
828 free((caddr_t)nmp, M_NFSMNT);
829 FREE(nam, M_SONAME);
830 return (error);
831}
832
833/*
834 * unmount system call
835 */
836static int
837nfs_unmount(mp, mntflags, p)
838 struct mount *mp;
839 int mntflags;
840 struct proc *p;
841{
842 register struct nfsmount *nmp;
843 struct nfsnode *np;
844 struct vnode *vp;
845 int error, flags = 0;
846
847 if (mntflags & MNT_FORCE)
848 flags |= FORCECLOSE;
849 nmp = VFSTONFS(mp);
850 /*
851 * Goes something like this..
852 * - Check for activity on the root vnode (other than ourselves).
853 * - Call vflush() to clear out vnodes for this file system,
854 * except for the root vnode.
855 * - Decrement reference on the vnode representing remote root.
856 * - Close the socket
857 * - Free up the data structures
858 */
859 /*
860 * We need to decrement the ref. count on the nfsnode representing
861 * the remote root. See comment in mountnfs(). The VFS unmount()
862 * has done vput on this vnode, otherwise we would get deadlock!
863 */
864 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
865 if (error)
866 return(error);
867 vp = NFSTOV(np);
868 if (vp->v_usecount > 2) {
869 vput(vp);
870 return (EBUSY);
871 }
872
873 /*
874 * Must handshake with nqnfs_clientd() if it is active.
875 */
876 nmp->nm_flag |= NFSMNT_DISMINPROG;
877 while (nmp->nm_inprog != NULLVP)
878 (void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
879 error = vflush(mp, vp, flags);
880 if (error) {
881 vput(vp);
882 nmp->nm_flag &= ~NFSMNT_DISMINPROG;
883 return (error);
884 }
885
886 /*
887 * We are now committed to the unmount.
888 * For NQNFS, let the server daemon free the nfsmount structure.
889 */
890 if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
891 nmp->nm_flag |= NFSMNT_DISMNT;
892
893 /*
894 * There are two reference counts and one lock to get rid of here.
895 */
896 vput(vp);
897 vrele(vp);
898 vgone(vp);
899 nfs_disconnect(nmp);
900 FREE(nmp->nm_nam, M_SONAME);
901
902 if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
903 free((caddr_t)nmp, M_NFSMNT);
904 return (0);
905}
906
907/*
908 * Return root of a filesystem
909 */
910static int
911nfs_root(mp, vpp)
912 struct mount *mp;
913 struct vnode **vpp;
914{
915 register struct vnode *vp;
916 struct nfsmount *nmp;
917 struct nfsnode *np;
918 int error;
919
920 nmp = VFSTONFS(mp);
921 error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
922 if (error)
923 return (error);
924 vp = NFSTOV(np);
925 if (vp->v_type == VNON)
926 vp->v_type = VDIR;
927 vp->v_flag = VROOT;
928 *vpp = vp;
929 return (0);
930}
931
932extern int syncprt;
933
934/*
935 * Flush out the buffer cache
936 */
937/* ARGSUSED */
938static int
939nfs_sync(mp, waitfor, cred, p)
940 struct mount *mp;
941 int waitfor;
942 struct ucred *cred;
943 struct proc *p;
944{
945 register struct vnode *vp;
946 int error, allerror = 0;
947
948 /*
949 * Force stale buffer cache information to be flushed.
950 */
951loop:
952 for (vp = mp->mnt_vnodelist.lh_first;
953 vp != NULL;
954 vp = vp->v_mntvnodes.le_next) {
955 /*
956 * If the vnode that we are about to sync is no longer
957 * associated with this mount point, start over.
958 */
959 if (vp->v_mount != mp)
960 goto loop;
961 if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL ||
962 waitfor == MNT_LAZY)
963 continue;
964 if (vget(vp, LK_EXCLUSIVE, p))
965 goto loop;
966 error = VOP_FSYNC(vp, cred, waitfor, p);
967 if (error)
968 allerror = error;
969 vput(vp);
970 }
971 return (allerror);
972}
973
974/*
975 * NFS flat namespace lookup.
976 * Currently unsupported.
977 */
978/* ARGSUSED */
979static int
980nfs_vget(mp, ino, vpp)
981 struct mount *mp;
982 ino_t ino;
983 struct vnode **vpp;
984{
985
986 return (EOPNOTSUPP);
987}
988
989/*
990 * At this point, this should never happen
991 */
992/* ARGSUSED */
993static int
994nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
995 register struct mount *mp;
996 struct fid *fhp;
997 struct sockaddr *nam;
998 struct vnode **vpp;
999 int *exflagsp;
1000 struct ucred **credanonp;
1001{
1002
1003 return (EINVAL);
1004}
1005
1006/*
1007 * Vnode pointer to File handle, should never happen either
1008 */
1009/* ARGSUSED */
1010static int
1011nfs_vptofh(vp, fhp)
1012 struct vnode *vp;
1013 struct fid *fhp;
1014{
1015
1016 return (EINVAL);
1017}
1018
1019/*
1020 * Vfs start routine, a no-op.
1021 */
1022/* ARGSUSED */
1023static int
1024nfs_start(mp, flags, p)
1025 struct mount *mp;
1026 int flags;
1027 struct proc *p;
1028{
1029
1030 return (0);
1031}
1032
1033/*
1034 * Do operations associated with quotas, not supported
1035 */
1036/* ARGSUSED */
1037static int
1038nfs_quotactl(mp, cmd, uid, arg, p)
1039 struct mount *mp;
1040 int cmd;
1041 uid_t uid;
1042 caddr_t arg;
1043 struct proc *p;
1044{
1045
1046 return (EOPNOTSUPP);
1047}