Deleted Added
full compact
nfs_clvfsops.c (221066) nfs_clvfsops.c (221124)
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 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * from nfs_vfsops.c 8.12 (Berkeley) 5/20/95
33 */
34
35#include <sys/cdefs.h>
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 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * from nfs_vfsops.c 8.12 (Berkeley) 5/20/95
33 */
34
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD: head/sys/fs/nfsclient/nfs_clvfsops.c 221066 2011-04-26 13:50:11Z rmacklem $");
36__FBSDID("$FreeBSD: head/sys/fs/nfsclient/nfs_clvfsops.c 221124 2011-04-27 17:51:51Z rmacklem $");
37
38
39#include "opt_bootp.h"
40#include "opt_nfsroot.h"
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/kernel.h>
45#include <sys/bio.h>
46#include <sys/buf.h>
47#include <sys/clock.h>
48#include <sys/jail.h>
49#include <sys/limits.h>
50#include <sys/lock.h>
51#include <sys/malloc.h>
52#include <sys/mbuf.h>
53#include <sys/module.h>
54#include <sys/mount.h>
55#include <sys/proc.h>
56#include <sys/socket.h>
57#include <sys/socketvar.h>
58#include <sys/sockio.h>
59#include <sys/sysctl.h>
60#include <sys/vnode.h>
61#include <sys/signalvar.h>
62
63#include <vm/vm.h>
64#include <vm/vm_extern.h>
65#include <vm/uma.h>
66
67#include <net/if.h>
68#include <net/route.h>
69#include <netinet/in.h>
70
71#include <fs/nfs/nfsport.h>
72#include <fs/nfsclient/nfsnode.h>
73#include <fs/nfsclient/nfsmount.h>
74#include <fs/nfsclient/nfs.h>
75#include <nfs/nfsdiskless.h>
76
77FEATURE(nfscl, "NFSv4 client");
78
79extern int nfscl_ticks;
80extern struct timeval nfsboottime;
81extern struct nfsstats newnfsstats;
82
83MALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header");
84MALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct");
85
86SYSCTL_DECL(_vfs_newnfs);
87SYSCTL_STRUCT(_vfs_newnfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RW,
88 &newnfsstats, nfsstats, "S,nfsstats");
89static int nfs_ip_paranoia = 1;
90SYSCTL_INT(_vfs_newnfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW,
91 &nfs_ip_paranoia, 0, "");
92static int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY;
93SYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_INITIAL_DELAY,
94 downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, "");
95/* how long between console messages "nfs server foo not responding" */
96static int nfs_tprintf_delay = NFS_TPRINTF_DELAY;
97SYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_DELAY,
98 downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, "");
99
100static int nfs_mountroot(struct mount *);
101static void nfs_sec_name(char *, int *);
102static void nfs_decode_args(struct mount *mp, struct nfsmount *nmp,
103 struct nfs_args *argp, const char *, struct ucred *,
104 struct thread *);
105static int mountnfs(struct nfs_args *, struct mount *,
106 struct sockaddr *, char *, u_char *, int, u_char *, int,
107 u_char *, int, struct vnode **, struct ucred *,
108 struct thread *, int);
109static void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *,
110 struct sockaddr_storage *, int *, off_t *,
111 struct timeval *);
112static vfs_mount_t nfs_mount;
113static vfs_cmount_t nfs_cmount;
114static vfs_unmount_t nfs_unmount;
115static vfs_root_t nfs_root;
116static vfs_statfs_t nfs_statfs;
117static vfs_sync_t nfs_sync;
118static vfs_sysctl_t nfs_sysctl;
119
120/*
121 * nfs vfs operations.
122 */
123static struct vfsops nfs_vfsops = {
124 .vfs_init = ncl_init,
125 .vfs_mount = nfs_mount,
126 .vfs_cmount = nfs_cmount,
127 .vfs_root = nfs_root,
128 .vfs_statfs = nfs_statfs,
129 .vfs_sync = nfs_sync,
130 .vfs_uninit = ncl_uninit,
131 .vfs_unmount = nfs_unmount,
132 .vfs_sysctl = nfs_sysctl,
133};
37
38
39#include "opt_bootp.h"
40#include "opt_nfsroot.h"
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/kernel.h>
45#include <sys/bio.h>
46#include <sys/buf.h>
47#include <sys/clock.h>
48#include <sys/jail.h>
49#include <sys/limits.h>
50#include <sys/lock.h>
51#include <sys/malloc.h>
52#include <sys/mbuf.h>
53#include <sys/module.h>
54#include <sys/mount.h>
55#include <sys/proc.h>
56#include <sys/socket.h>
57#include <sys/socketvar.h>
58#include <sys/sockio.h>
59#include <sys/sysctl.h>
60#include <sys/vnode.h>
61#include <sys/signalvar.h>
62
63#include <vm/vm.h>
64#include <vm/vm_extern.h>
65#include <vm/uma.h>
66
67#include <net/if.h>
68#include <net/route.h>
69#include <netinet/in.h>
70
71#include <fs/nfs/nfsport.h>
72#include <fs/nfsclient/nfsnode.h>
73#include <fs/nfsclient/nfsmount.h>
74#include <fs/nfsclient/nfs.h>
75#include <nfs/nfsdiskless.h>
76
77FEATURE(nfscl, "NFSv4 client");
78
79extern int nfscl_ticks;
80extern struct timeval nfsboottime;
81extern struct nfsstats newnfsstats;
82
83MALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header");
84MALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct");
85
86SYSCTL_DECL(_vfs_newnfs);
87SYSCTL_STRUCT(_vfs_newnfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RW,
88 &newnfsstats, nfsstats, "S,nfsstats");
89static int nfs_ip_paranoia = 1;
90SYSCTL_INT(_vfs_newnfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW,
91 &nfs_ip_paranoia, 0, "");
92static int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY;
93SYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_INITIAL_DELAY,
94 downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, "");
95/* how long between console messages "nfs server foo not responding" */
96static int nfs_tprintf_delay = NFS_TPRINTF_DELAY;
97SYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_DELAY,
98 downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, "");
99
100static int nfs_mountroot(struct mount *);
101static void nfs_sec_name(char *, int *);
102static void nfs_decode_args(struct mount *mp, struct nfsmount *nmp,
103 struct nfs_args *argp, const char *, struct ucred *,
104 struct thread *);
105static int mountnfs(struct nfs_args *, struct mount *,
106 struct sockaddr *, char *, u_char *, int, u_char *, int,
107 u_char *, int, struct vnode **, struct ucred *,
108 struct thread *, int);
109static void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *,
110 struct sockaddr_storage *, int *, off_t *,
111 struct timeval *);
112static vfs_mount_t nfs_mount;
113static vfs_cmount_t nfs_cmount;
114static vfs_unmount_t nfs_unmount;
115static vfs_root_t nfs_root;
116static vfs_statfs_t nfs_statfs;
117static vfs_sync_t nfs_sync;
118static vfs_sysctl_t nfs_sysctl;
119
120/*
121 * nfs vfs operations.
122 */
123static struct vfsops nfs_vfsops = {
124 .vfs_init = ncl_init,
125 .vfs_mount = nfs_mount,
126 .vfs_cmount = nfs_cmount,
127 .vfs_root = nfs_root,
128 .vfs_statfs = nfs_statfs,
129 .vfs_sync = nfs_sync,
130 .vfs_uninit = ncl_uninit,
131 .vfs_unmount = nfs_unmount,
132 .vfs_sysctl = nfs_sysctl,
133};
134VFS_SET(nfs_vfsops, newnfs, VFCF_NETWORK);
134VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK);
135
136/* So that loader and kldload(2) can find us, wherever we are.. */
137MODULE_VERSION(newnfs, 1);
138
139/*
140 * This structure is now defined in sys/nfs/nfs_diskless.c so that it
141 * can be shared by both NFS clients. It is declared here so that it
142 * will be defined for kernels built without NFS_ROOT, although it
143 * isn't used in that case.
144 */
145#if !defined(NFS_ROOT) && !defined(NFSCLIENT)
146struct nfs_diskless nfs_diskless = { { { 0 } } };
147struct nfsv3_diskless nfsv3_diskless = { { { 0 } } };
148int nfs_diskless_valid = 0;
149#endif
150
151SYSCTL_INT(_vfs_newnfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
152 &nfs_diskless_valid, 0,
153 "Has the diskless struct been filled correctly");
154
155SYSCTL_STRING(_vfs_newnfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
156 nfsv3_diskless.root_hostnam, 0, "Path to nfs root");
157
158SYSCTL_OPAQUE(_vfs_newnfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
159 &nfsv3_diskless.root_saddr, sizeof(nfsv3_diskless.root_saddr),
160 "%Ssockaddr_in", "Diskless root nfs address");
161
162
163void newnfsargs_ntoh(struct nfs_args *);
164static int nfs_mountdiskless(char *,
165 struct sockaddr_in *, struct nfs_args *,
166 struct thread *, struct vnode **, struct mount *);
167static void nfs_convert_diskless(void);
168static void nfs_convert_oargs(struct nfs_args *args,
169 struct onfs_args *oargs);
170
171int
172newnfs_iosize(struct nfsmount *nmp)
173{
174 int iosize, maxio;
175
176 /* First, set the upper limit for iosize */
177 if (nmp->nm_flag & NFSMNT_NFSV4) {
178 maxio = NFS_MAXBSIZE;
179 } else if (nmp->nm_flag & NFSMNT_NFSV3) {
180 if (nmp->nm_sotype == SOCK_DGRAM)
181 maxio = NFS_MAXDGRAMDATA;
182 else
183 maxio = NFS_MAXBSIZE;
184 } else {
185 maxio = NFS_V2MAXDATA;
186 }
187 if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0)
188 nmp->nm_rsize = maxio;
189 if (nmp->nm_rsize > MAXBSIZE)
190 nmp->nm_rsize = MAXBSIZE;
191 if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0)
192 nmp->nm_readdirsize = maxio;
193 if (nmp->nm_readdirsize > nmp->nm_rsize)
194 nmp->nm_readdirsize = nmp->nm_rsize;
195 if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0)
196 nmp->nm_wsize = maxio;
197 if (nmp->nm_wsize > MAXBSIZE)
198 nmp->nm_wsize = MAXBSIZE;
199
200 /*
201 * Calculate the size used for io buffers. Use the larger
202 * of the two sizes to minimise nfs requests but make sure
203 * that it is at least one VM page to avoid wasting buffer
204 * space.
205 */
206 iosize = imax(nmp->nm_rsize, nmp->nm_wsize);
207 iosize = imax(iosize, PAGE_SIZE);
208 nmp->nm_mountp->mnt_stat.f_iosize = iosize;
209 return (iosize);
210}
211
212static void
213nfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs)
214{
215
216 args->version = NFS_ARGSVERSION;
217 args->addr = oargs->addr;
218 args->addrlen = oargs->addrlen;
219 args->sotype = oargs->sotype;
220 args->proto = oargs->proto;
221 args->fh = oargs->fh;
222 args->fhsize = oargs->fhsize;
223 args->flags = oargs->flags;
224 args->wsize = oargs->wsize;
225 args->rsize = oargs->rsize;
226 args->readdirsize = oargs->readdirsize;
227 args->timeo = oargs->timeo;
228 args->retrans = oargs->retrans;
229 args->readahead = oargs->readahead;
230 args->hostname = oargs->hostname;
231}
232
233static void
234nfs_convert_diskless(void)
235{
236
237 bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
238 sizeof(struct ifaliasreq));
239 bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
240 sizeof(struct sockaddr_in));
241 nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args);
242 if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) {
243 nfsv3_diskless.root_fhsize = NFSX_MYFH;
244 bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_MYFH);
245 } else {
246 nfsv3_diskless.root_fhsize = NFSX_V2FH;
247 bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH);
248 }
249 bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
250 sizeof(struct sockaddr_in));
251 bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN);
252 nfsv3_diskless.root_time = nfs_diskless.root_time;
253 bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam,
254 MAXHOSTNAMELEN);
255 nfs_diskless_valid = 3;
256}
257
258/*
259 * nfs statfs call
260 */
261static int
262nfs_statfs(struct mount *mp, struct statfs *sbp)
263{
264 struct vnode *vp;
265 struct thread *td;
266 struct nfsmount *nmp = VFSTONFS(mp);
267 struct nfsvattr nfsva;
268 struct nfsfsinfo fs;
269 struct nfsstatfs sb;
270 int error = 0, attrflag, gotfsinfo = 0, ret;
271 struct nfsnode *np;
272
273 td = curthread;
274
275 error = vfs_busy(mp, MBF_NOWAIT);
276 if (error)
277 return (error);
278 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE);
279 if (error) {
280 vfs_unbusy(mp);
281 return (error);
282 }
283 vp = NFSTOV(np);
284 mtx_lock(&nmp->nm_mtx);
285 if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
286 mtx_unlock(&nmp->nm_mtx);
287 error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva,
288 &attrflag, NULL);
289 if (!error)
290 gotfsinfo = 1;
291 } else
292 mtx_unlock(&nmp->nm_mtx);
293 if (!error)
294 error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva,
295 &attrflag, NULL);
296 if (attrflag == 0) {
297 ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
298 td->td_ucred, td, &nfsva, NULL);
299 if (ret) {
300 /*
301 * Just set default values to get things going.
302 */
303 NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
304 nfsva.na_vattr.va_type = VDIR;
305 nfsva.na_vattr.va_mode = 0777;
306 nfsva.na_vattr.va_nlink = 100;
307 nfsva.na_vattr.va_uid = (uid_t)0;
308 nfsva.na_vattr.va_gid = (gid_t)0;
309 nfsva.na_vattr.va_fileid = 2;
310 nfsva.na_vattr.va_gen = 1;
311 nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
312 nfsva.na_vattr.va_size = 512 * 1024;
313 }
314 }
315 (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1);
316 if (!error) {
317 mtx_lock(&nmp->nm_mtx);
318 if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4))
319 nfscl_loadfsinfo(nmp, &fs);
320 nfscl_loadsbinfo(nmp, &sb, sbp);
321 sbp->f_iosize = newnfs_iosize(nmp);
322 mtx_unlock(&nmp->nm_mtx);
323 if (sbp != &mp->mnt_stat) {
324 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
325 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
326 }
327 strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN);
328 } else if (NFS_ISV4(vp)) {
329 error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
330 }
331 vput(vp);
332 vfs_unbusy(mp);
333 return (error);
334}
335
336/*
337 * nfs version 3 fsinfo rpc call
338 */
339int
340ncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred,
341 struct thread *td)
342{
343 struct nfsfsinfo fs;
344 struct nfsvattr nfsva;
345 int error, attrflag;
346
347 error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL);
348 if (!error) {
349 if (attrflag)
350 (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0,
351 1);
352 mtx_lock(&nmp->nm_mtx);
353 nfscl_loadfsinfo(nmp, &fs);
354 mtx_unlock(&nmp->nm_mtx);
355 }
356 return (error);
357}
358
359/*
360 * Mount a remote root fs via. nfs. This depends on the info in the
361 * nfs_diskless structure that has been filled in properly by some primary
362 * bootstrap.
363 * It goes something like this:
364 * - do enough of "ifconfig" by calling ifioctl() so that the system
365 * can talk to the server
366 * - If nfs_diskless.mygateway is filled in, use that address as
367 * a default gateway.
368 * - build the rootfs mount point and call mountnfs() to do the rest.
369 *
370 * It is assumed to be safe to read, modify, and write the nfsv3_diskless
371 * structure, as well as other global NFS client variables here, as
372 * nfs_mountroot() will be called once in the boot before any other NFS
373 * client activity occurs.
374 */
375static int
376nfs_mountroot(struct mount *mp)
377{
378 struct thread *td = curthread;
379 struct nfsv3_diskless *nd = &nfsv3_diskless;
380 struct socket *so;
381 struct vnode *vp;
382 struct ifreq ir;
383 int error;
384 u_long l;
385 char buf[128];
386 char *cp;
387
388#if defined(BOOTP_NFSROOT) && defined(BOOTP)
389 bootpc_init(); /* use bootp to get nfs_diskless filled in */
390#elif defined(NFS_ROOT)
391 nfs_setup_diskless();
392#endif
393
394 if (nfs_diskless_valid == 0)
395 return (-1);
396 if (nfs_diskless_valid == 1)
397 nfs_convert_diskless();
398
399 /*
400 * XXX splnet, so networks will receive...
401 */
402 splnet();
403
404 /*
405 * Do enough of ifconfig(8) so that the critical net interface can
406 * talk to the server.
407 */
408 error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0,
409 td->td_ucred, td);
410 if (error)
411 panic("nfs_mountroot: socreate(%04x): %d",
412 nd->myif.ifra_addr.sa_family, error);
413
414#if 0 /* XXX Bad idea */
415 /*
416 * We might not have been told the right interface, so we pass
417 * over the first ten interfaces of the same kind, until we get
418 * one of them configured.
419 */
420
421 for (i = strlen(nd->myif.ifra_name) - 1;
422 nd->myif.ifra_name[i] >= '0' &&
423 nd->myif.ifra_name[i] <= '9';
424 nd->myif.ifra_name[i] ++) {
425 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
426 if(!error)
427 break;
428 }
429#endif
430 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
431 if (error)
432 panic("nfs_mountroot: SIOCAIFADDR: %d", error);
433 if ((cp = getenv("boot.netif.mtu")) != NULL) {
434 ir.ifr_mtu = strtol(cp, NULL, 10);
435 bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ);
436 freeenv(cp);
437 error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td);
438 if (error)
439 printf("nfs_mountroot: SIOCSIFMTU: %d", error);
440 }
441 soclose(so);
442
443 /*
444 * If the gateway field is filled in, set it as the default route.
445 * Note that pxeboot will set a default route of 0 if the route
446 * is not set by the DHCP server. Check also for a value of 0
447 * to avoid panicking inappropriately in that situation.
448 */
449 if (nd->mygateway.sin_len != 0 &&
450 nd->mygateway.sin_addr.s_addr != 0) {
451 struct sockaddr_in mask, sin;
452
453 bzero((caddr_t)&mask, sizeof(mask));
454 sin = mask;
455 sin.sin_family = AF_INET;
456 sin.sin_len = sizeof(sin);
457 /* XXX MRT use table 0 for this sort of thing */
458 CURVNET_SET(TD_TO_VNET(td));
459 error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
460 (struct sockaddr *)&nd->mygateway,
461 (struct sockaddr *)&mask,
462 RTF_UP | RTF_GATEWAY, NULL);
463 CURVNET_RESTORE();
464 if (error)
465 panic("nfs_mountroot: RTM_ADD: %d", error);
466 }
467
468 /*
469 * Create the rootfs mount point.
470 */
471 nd->root_args.fh = nd->root_fh;
472 nd->root_args.fhsize = nd->root_fhsize;
473 l = ntohl(nd->root_saddr.sin_addr.s_addr);
474 snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s",
475 (l >> 24) & 0xff, (l >> 16) & 0xff,
476 (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam);
477 printf("NFS ROOT: %s\n", buf);
478 nd->root_args.hostname = buf;
479 if ((error = nfs_mountdiskless(buf,
480 &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) {
481 return (error);
482 }
483
484 /*
485 * This is not really an nfs issue, but it is much easier to
486 * set hostname here and then let the "/etc/rc.xxx" files
487 * mount the right /var based upon its preset value.
488 */
489 mtx_lock(&prison0.pr_mtx);
490 strlcpy(prison0.pr_hostname, nd->my_hostnam,
491 sizeof(prison0.pr_hostname));
492 mtx_unlock(&prison0.pr_mtx);
493 inittodr(ntohl(nd->root_time));
494 return (0);
495}
496
497/*
498 * Internal version of mount system call for diskless setup.
499 */
500static int
501nfs_mountdiskless(char *path,
502 struct sockaddr_in *sin, struct nfs_args *args, struct thread *td,
503 struct vnode **vpp, struct mount *mp)
504{
505 struct sockaddr *nam;
506 int dirlen, error;
507 char *dirpath;
508
509 /*
510 * Find the directory path in "path", which also has the server's
511 * name/ip address in it.
512 */
513 dirpath = strchr(path, ':');
514 if (dirpath != NULL)
515 dirlen = strlen(++dirpath);
516 else
517 dirlen = 0;
518 nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
519 if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen,
520 NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NEGNAMETIMEO)) != 0) {
521 printf("nfs_mountroot: mount %s on /: %d\n", path, error);
522 return (error);
523 }
524 return (0);
525}
526
527static void
528nfs_sec_name(char *sec, int *flagsp)
529{
530 if (!strcmp(sec, "krb5"))
531 *flagsp |= NFSMNT_KERB;
532 else if (!strcmp(sec, "krb5i"))
533 *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY);
534 else if (!strcmp(sec, "krb5p"))
535 *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY);
536}
537
538static void
539nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp,
540 const char *hostname, struct ucred *cred, struct thread *td)
541{
542 int s;
543 int adjsock;
544 char *p;
545
546 s = splnet();
547
548 /*
549 * Set read-only flag if requested; otherwise, clear it if this is
550 * an update. If this is not an update, then either the read-only
551 * flag is already clear, or this is a root mount and it was set
552 * intentionally at some previous point.
553 */
554 if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) {
555 MNT_ILOCK(mp);
556 mp->mnt_flag |= MNT_RDONLY;
557 MNT_IUNLOCK(mp);
558 } else if (mp->mnt_flag & MNT_UPDATE) {
559 MNT_ILOCK(mp);
560 mp->mnt_flag &= ~MNT_RDONLY;
561 MNT_IUNLOCK(mp);
562 }
563
564 /*
565 * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
566 * no sense in that context. Also, set up appropriate retransmit
567 * and soft timeout behavior.
568 */
569 if (argp->sotype == SOCK_STREAM) {
570 nmp->nm_flag &= ~NFSMNT_NOCONN;
571 nmp->nm_timeo = NFS_MAXTIMEO;
572 if ((argp->flags & NFSMNT_NFSV4) != 0)
573 nmp->nm_retry = INT_MAX;
574 else
575 nmp->nm_retry = NFS_RETRANS_TCP;
576 }
577
578 /* Also clear RDIRPLUS if NFSv2, it crashes some servers */
579 if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
580 argp->flags &= ~NFSMNT_RDIRPLUS;
581 nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
582 }
583
584 /* Clear NFSMNT_RESVPORT for NFSv4, since it is not required. */
585 if ((argp->flags & NFSMNT_NFSV4) != 0) {
586 argp->flags &= ~NFSMNT_RESVPORT;
587 nmp->nm_flag &= ~NFSMNT_RESVPORT;
588 }
589
590 /* Re-bind if rsrvd port requested and wasn't on one */
591 adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
592 && (argp->flags & NFSMNT_RESVPORT);
593 /* Also re-bind if we're switching to/from a connected UDP socket */
594 adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
595 (argp->flags & NFSMNT_NOCONN));
596
597 /* Update flags atomically. Don't change the lock bits. */
598 nmp->nm_flag = argp->flags | nmp->nm_flag;
599 splx(s);
600
601 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
602 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
603 if (nmp->nm_timeo < NFS_MINTIMEO)
604 nmp->nm_timeo = NFS_MINTIMEO;
605 else if (nmp->nm_timeo > NFS_MAXTIMEO)
606 nmp->nm_timeo = NFS_MAXTIMEO;
607 }
608
609 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
610 nmp->nm_retry = argp->retrans;
611 if (nmp->nm_retry > NFS_MAXREXMIT)
612 nmp->nm_retry = NFS_MAXREXMIT;
613 }
614
615 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
616 nmp->nm_wsize = argp->wsize;
617 /* Round down to multiple of blocksize */
618 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
619 if (nmp->nm_wsize <= 0)
620 nmp->nm_wsize = NFS_FABLKSIZE;
621 }
622
623 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
624 nmp->nm_rsize = argp->rsize;
625 /* Round down to multiple of blocksize */
626 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
627 if (nmp->nm_rsize <= 0)
628 nmp->nm_rsize = NFS_FABLKSIZE;
629 }
630
631 if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
632 nmp->nm_readdirsize = argp->readdirsize;
633 }
634
635 if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0)
636 nmp->nm_acregmin = argp->acregmin;
637 else
638 nmp->nm_acregmin = NFS_MINATTRTIMO;
639 if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0)
640 nmp->nm_acregmax = argp->acregmax;
641 else
642 nmp->nm_acregmax = NFS_MAXATTRTIMO;
643 if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0)
644 nmp->nm_acdirmin = argp->acdirmin;
645 else
646 nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
647 if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0)
648 nmp->nm_acdirmax = argp->acdirmax;
649 else
650 nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO;
651 if (nmp->nm_acdirmin > nmp->nm_acdirmax)
652 nmp->nm_acdirmin = nmp->nm_acdirmax;
653 if (nmp->nm_acregmin > nmp->nm_acregmax)
654 nmp->nm_acregmin = nmp->nm_acregmax;
655
656 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) {
657 if (argp->readahead <= NFS_MAXRAHEAD)
658 nmp->nm_readahead = argp->readahead;
659 else
660 nmp->nm_readahead = NFS_MAXRAHEAD;
661 }
662 if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) {
663 if (argp->wcommitsize < nmp->nm_wsize)
664 nmp->nm_wcommitsize = nmp->nm_wsize;
665 else
666 nmp->nm_wcommitsize = argp->wcommitsize;
667 }
668
669 adjsock |= ((nmp->nm_sotype != argp->sotype) ||
670 (nmp->nm_soproto != argp->proto));
671
672 if (nmp->nm_client != NULL && adjsock) {
673 int haslock = 0, error = 0;
674
675 if (nmp->nm_sotype == SOCK_STREAM) {
676 error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock);
677 if (!error)
678 haslock = 1;
679 }
680 if (!error) {
681 newnfs_disconnect(&nmp->nm_sockreq);
682 if (haslock)
683 newnfs_sndunlock(&nmp->nm_sockreq.nr_lock);
684 nmp->nm_sotype = argp->sotype;
685 nmp->nm_soproto = argp->proto;
686 if (nmp->nm_sotype == SOCK_DGRAM)
687 while (newnfs_connect(nmp, &nmp->nm_sockreq,
688 cred, td, 0)) {
689 printf("newnfs_args: retrying connect\n");
690 (void) nfs_catnap(PSOCK, 0, "newnfscon");
691 }
692 }
693 } else {
694 nmp->nm_sotype = argp->sotype;
695 nmp->nm_soproto = argp->proto;
696 }
697
698 if (hostname != NULL) {
699 strlcpy(nmp->nm_hostname, hostname,
700 sizeof(nmp->nm_hostname));
701 p = strchr(nmp->nm_hostname, ':');
702 if (p != NULL)
703 *p = '\0';
704 }
705}
706
707static const char *nfs_opts[] = { "from",
708 "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union",
709 "noclusterr", "noclusterw", "multilabel", "acls", "force", "update",
710 "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus",
711 "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize",
712 "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport",
713 "readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec",
714 "principal", "nfsv4", "gssname", "allgssname", "dirpath",
715 "negnametimeo",
716 NULL };
717
718/*
719 * VFS Operations.
720 *
721 * mount system call
722 * It seems a bit dumb to copyinstr() the host and path here and then
723 * bcopy() them in mountnfs(), but I wanted to detect errors before
724 * doing the sockargs() call because sockargs() allocates an mbuf and
725 * an error after that means that I have to release the mbuf.
726 */
727/* ARGSUSED */
728static int
729nfs_mount(struct mount *mp)
730{
731 struct nfs_args args = {
732 .version = NFS_ARGSVERSION,
733 .addr = NULL,
734 .addrlen = sizeof (struct sockaddr_in),
735 .sotype = SOCK_STREAM,
736 .proto = 0,
737 .fh = NULL,
738 .fhsize = 0,
739 .flags = NFSMNT_RESVPORT,
740 .wsize = NFS_WSIZE,
741 .rsize = NFS_RSIZE,
742 .readdirsize = NFS_READDIRSIZE,
743 .timeo = 10,
744 .retrans = NFS_RETRANS,
745 .readahead = NFS_DEFRAHEAD,
746 .wcommitsize = 0, /* was: NQ_DEFLEASE */
747 .hostname = NULL,
748 .acregmin = NFS_MINATTRTIMO,
749 .acregmax = NFS_MAXATTRTIMO,
750 .acdirmin = NFS_MINDIRATTRTIMO,
751 .acdirmax = NFS_MAXDIRATTRTIMO,
752 };
753 int error = 0, ret, len;
754 struct sockaddr *nam = NULL;
755 struct vnode *vp;
756 struct thread *td;
757 char hst[MNAMELEN];
758 u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100];
759 char *opt, *name, *secname;
760 int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
761 int dirlen, krbnamelen, srvkrbnamelen;
762
763 if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
764 error = EINVAL;
765 goto out;
766 }
767
768 td = curthread;
769 if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) {
770 error = nfs_mountroot(mp);
771 goto out;
772 }
773
774 nfscl_init();
775
776 /* Handle the new style options. */
777 if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0)
778 args.flags |= NFSMNT_NOCONN;
779 if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0)
780 args.flags |= NFSMNT_NOCONN;
781 if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0)
782 args.flags |= NFSMNT_NOLOCKD;
783 if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0)
784 args.flags &= ~NFSMNT_NOLOCKD;
785 if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0)
786 args.flags |= NFSMNT_INT;
787 if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0)
788 args.flags |= NFSMNT_RDIRPLUS;
789 if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0)
790 args.flags |= NFSMNT_RESVPORT;
791 if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0)
792 args.flags &= ~NFSMNT_RESVPORT;
793 if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0)
794 args.flags |= NFSMNT_SOFT;
795 if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0)
796 args.flags &= ~NFSMNT_SOFT;
797 if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0)
798 args.sotype = SOCK_DGRAM;
799 if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0)
800 args.sotype = SOCK_DGRAM;
801 if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0)
802 args.sotype = SOCK_STREAM;
803 if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0)
804 args.flags |= NFSMNT_NFSV3;
805 if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) {
806 args.flags |= NFSMNT_NFSV4;
807 args.sotype = SOCK_STREAM;
808 }
809 if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0)
810 args.flags |= NFSMNT_ALLGSSNAME;
811 if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) {
812 if (opt == NULL) {
813 vfs_mount_error(mp, "illegal readdirsize");
814 error = EINVAL;
815 goto out;
816 }
817 ret = sscanf(opt, "%d", &args.readdirsize);
818 if (ret != 1 || args.readdirsize <= 0) {
819 vfs_mount_error(mp, "illegal readdirsize: %s",
820 opt);
821 error = EINVAL;
822 goto out;
823 }
824 args.flags |= NFSMNT_READDIRSIZE;
825 }
826 if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) {
827 if (opt == NULL) {
828 vfs_mount_error(mp, "illegal readahead");
829 error = EINVAL;
830 goto out;
831 }
832 ret = sscanf(opt, "%d", &args.readahead);
833 if (ret != 1 || args.readahead <= 0) {
834 vfs_mount_error(mp, "illegal readahead: %s",
835 opt);
836 error = EINVAL;
837 goto out;
838 }
839 args.flags |= NFSMNT_READAHEAD;
840 }
841 if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) {
842 if (opt == NULL) {
843 vfs_mount_error(mp, "illegal wsize");
844 error = EINVAL;
845 goto out;
846 }
847 ret = sscanf(opt, "%d", &args.wsize);
848 if (ret != 1 || args.wsize <= 0) {
849 vfs_mount_error(mp, "illegal wsize: %s",
850 opt);
851 error = EINVAL;
852 goto out;
853 }
854 args.flags |= NFSMNT_WSIZE;
855 }
856 if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) {
857 if (opt == NULL) {
858 vfs_mount_error(mp, "illegal rsize");
859 error = EINVAL;
860 goto out;
861 }
862 ret = sscanf(opt, "%d", &args.rsize);
863 if (ret != 1 || args.rsize <= 0) {
864 vfs_mount_error(mp, "illegal wsize: %s",
865 opt);
866 error = EINVAL;
867 goto out;
868 }
869 args.flags |= NFSMNT_RSIZE;
870 }
871 if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) {
872 if (opt == NULL) {
873 vfs_mount_error(mp, "illegal retrans");
874 error = EINVAL;
875 goto out;
876 }
877 ret = sscanf(opt, "%d", &args.retrans);
878 if (ret != 1 || args.retrans <= 0) {
879 vfs_mount_error(mp, "illegal retrans: %s",
880 opt);
881 error = EINVAL;
882 goto out;
883 }
884 args.flags |= NFSMNT_RETRANS;
885 }
886 if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) {
887 ret = sscanf(opt, "%d", &args.acregmin);
888 if (ret != 1 || args.acregmin < 0) {
889 vfs_mount_error(mp, "illegal acregmin: %s",
890 opt);
891 error = EINVAL;
892 goto out;
893 }
894 args.flags |= NFSMNT_ACREGMIN;
895 }
896 if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) {
897 ret = sscanf(opt, "%d", &args.acregmax);
898 if (ret != 1 || args.acregmax < 0) {
899 vfs_mount_error(mp, "illegal acregmax: %s",
900 opt);
901 error = EINVAL;
902 goto out;
903 }
904 args.flags |= NFSMNT_ACREGMAX;
905 }
906 if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) {
907 ret = sscanf(opt, "%d", &args.acdirmin);
908 if (ret != 1 || args.acdirmin < 0) {
909 vfs_mount_error(mp, "illegal acdirmin: %s",
910 opt);
911 error = EINVAL;
912 goto out;
913 }
914 args.flags |= NFSMNT_ACDIRMIN;
915 }
916 if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) {
917 ret = sscanf(opt, "%d", &args.acdirmax);
918 if (ret != 1 || args.acdirmax < 0) {
919 vfs_mount_error(mp, "illegal acdirmax: %s",
920 opt);
921 error = EINVAL;
922 goto out;
923 }
924 args.flags |= NFSMNT_ACDIRMAX;
925 }
926 if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) {
927 ret = sscanf(opt, "%d", &args.timeo);
928 if (ret != 1 || args.timeo <= 0) {
929 vfs_mount_error(mp, "illegal timeout: %s",
930 opt);
931 error = EINVAL;
932 goto out;
933 }
934 args.flags |= NFSMNT_TIMEO;
935 }
936 if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
937 == 0) {
938 ret = sscanf(opt, "%d", &negnametimeo);
939 if (ret != 1 || negnametimeo < 0) {
940 vfs_mount_error(mp, "illegal negnametimeo: %s",
941 opt);
942 error = EINVAL;
943 goto out;
944 }
945 }
946 if (vfs_getopt(mp->mnt_optnew, "sec",
947 (void **) &secname, NULL) == 0)
948 nfs_sec_name(secname, &args.flags);
949
950 if (mp->mnt_flag & MNT_UPDATE) {
951 struct nfsmount *nmp = VFSTONFS(mp);
952
953 if (nmp == NULL) {
954 error = EIO;
955 goto out;
956 }
957 /*
958 * When doing an update, we can't change version,
959 * security, switch lockd strategies or change cookie
960 * translation
961 */
962 args.flags = (args.flags &
963 ~(NFSMNT_NFSV3 |
964 NFSMNT_NFSV4 |
965 NFSMNT_KERB |
966 NFSMNT_INTEGRITY |
967 NFSMNT_PRIVACY |
968 NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) |
969 (nmp->nm_flag &
970 (NFSMNT_NFSV3 |
971 NFSMNT_NFSV4 |
972 NFSMNT_KERB |
973 NFSMNT_INTEGRITY |
974 NFSMNT_PRIVACY |
975 NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/));
976 nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td);
977 goto out;
978 }
979
980 /*
981 * Make the nfs_ip_paranoia sysctl serve as the default connection
982 * or no-connection mode for those protocols that support
983 * no-connection mode (the flag will be cleared later for protocols
984 * that do not support no-connection mode). This will allow a client
985 * to receive replies from a different IP then the request was
986 * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid),
987 * not 0.
988 */
989 if (nfs_ip_paranoia == 0)
990 args.flags |= NFSMNT_NOCONN;
991
992 if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh,
993 &args.fhsize) == 0) {
994 if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) {
995 vfs_mount_error(mp, "Bad file handle");
996 error = EINVAL;
997 goto out;
998 }
999 bcopy(args.fh, nfh, args.fhsize);
1000 } else {
1001 args.fhsize = 0;
1002 }
1003
1004 (void) vfs_getopt(mp->mnt_optnew, "hostname", (void **)&args.hostname,
1005 &len);
1006 if (args.hostname == NULL) {
1007 vfs_mount_error(mp, "Invalid hostname");
1008 error = EINVAL;
1009 goto out;
1010 }
1011 bcopy(args.hostname, hst, MNAMELEN);
1012 hst[MNAMELEN - 1] = '\0';
1013
1014 if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0)
1015 strlcpy(srvkrbname, name, sizeof (srvkrbname));
1016 else
1017 snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst);
1018 srvkrbnamelen = strlen(srvkrbname);
1019
1020 if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0)
1021 strlcpy(krbname, name, sizeof (krbname));
1022 else
1023 krbname[0] = '\0';
1024 krbnamelen = strlen(krbname);
1025
1026 if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0)
1027 strlcpy(dirpath, name, sizeof (dirpath));
1028 else
1029 dirpath[0] = '\0';
1030 dirlen = strlen(dirpath);
1031
1032 if (vfs_getopt(mp->mnt_optnew, "addr", (void **)&args.addr,
1033 &args.addrlen) == 0) {
1034 if (args.addrlen > SOCK_MAXADDRLEN) {
1035 error = ENAMETOOLONG;
1036 goto out;
1037 }
1038 nam = malloc(args.addrlen, M_SONAME, M_WAITOK);
1039 bcopy(args.addr, nam, args.addrlen);
1040 nam->sa_len = args.addrlen;
1041 }
1042
1043 args.fh = nfh;
1044 error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
1045 dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
1046 negnametimeo);
1047out:
1048 if (!error) {
1049 MNT_ILOCK(mp);
1050 mp->mnt_kern_flag |= (MNTK_MPSAFE|MNTK_LOOKUP_SHARED);
1051 MNT_IUNLOCK(mp);
1052 }
1053 return (error);
1054}
1055
1056
1057/*
1058 * VFS Operations.
1059 *
1060 * mount system call
1061 * It seems a bit dumb to copyinstr() the host and path here and then
1062 * bcopy() them in mountnfs(), but I wanted to detect errors before
1063 * doing the sockargs() call because sockargs() allocates an mbuf and
1064 * an error after that means that I have to release the mbuf.
1065 */
1066/* ARGSUSED */
1067static int
1068nfs_cmount(struct mntarg *ma, void *data, int flags)
1069{
1070 int error;
1071 struct nfs_args args;
1072
1073 error = copyin(data, &args, sizeof (struct nfs_args));
1074 if (error)
1075 return error;
1076
1077 ma = mount_arg(ma, "nfs_args", &args, sizeof args);
1078
1079 error = kernel_mount(ma, flags);
1080 return (error);
1081}
1082
1083/*
1084 * Common code for mount and mountroot
1085 */
1086static int
1087mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
1088 char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen,
1089 u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp,
1090 struct ucred *cred, struct thread *td, int negnametimeo)
1091{
1092 struct nfsmount *nmp;
1093 struct nfsnode *np;
1094 int error, trycnt, ret;
1095 struct nfsvattr nfsva;
1096 static u_int64_t clval = 0;
1097
1098 if (mp->mnt_flag & MNT_UPDATE) {
1099 nmp = VFSTONFS(mp);
1100 printf("%s: MNT_UPDATE is no longer handled here\n", __func__);
1101 FREE(nam, M_SONAME);
1102 return (0);
1103 } else {
1104 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) +
1105 krbnamelen + dirlen + srvkrbnamelen + 2,
1106 M_NEWNFSMNT, M_WAITOK | M_ZERO);
1107 TAILQ_INIT(&nmp->nm_bufq);
1108 if (clval == 0)
1109 clval = (u_int64_t)nfsboottime.tv_sec;
1110 nmp->nm_clval = clval++;
1111 nmp->nm_krbnamelen = krbnamelen;
1112 nmp->nm_dirpathlen = dirlen;
1113 nmp->nm_srvkrbnamelen = srvkrbnamelen;
1114 if (td->td_ucred->cr_uid != (uid_t)0) {
1115 /*
1116 * nm_uid is used to get KerberosV credentials for
1117 * the nfsv4 state handling operations if there is
1118 * no host based principal set. Use the uid of
1119 * this user if not root, since they are doing the
1120 * mount. I don't think setting this for root will
1121 * work, since root normally does not have user
1122 * credentials in a credentials cache.
1123 */
1124 nmp->nm_uid = td->td_ucred->cr_uid;
1125 } else {
1126 /*
1127 * Just set to -1, so it won't be used.
1128 */
1129 nmp->nm_uid = (uid_t)-1;
1130 }
1131
1132 /* Copy and null terminate all the names */
1133 if (nmp->nm_krbnamelen > 0) {
1134 bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen);
1135 nmp->nm_name[nmp->nm_krbnamelen] = '\0';
1136 }
1137 if (nmp->nm_dirpathlen > 0) {
1138 bcopy(dirpath, NFSMNT_DIRPATH(nmp),
1139 nmp->nm_dirpathlen);
1140 nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
1141 + 1] = '\0';
1142 }
1143 if (nmp->nm_srvkrbnamelen > 0) {
1144 bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp),
1145 nmp->nm_srvkrbnamelen);
1146 nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
1147 + nmp->nm_srvkrbnamelen + 2] = '\0';
1148 }
1149 nmp->nm_sockreq.nr_cred = crhold(cred);
1150 mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF);
1151 mp->mnt_data = nmp;
1152 nmp->nm_getinfo = nfs_getnlminfo;
1153 nmp->nm_vinvalbuf = ncl_vinvalbuf;
1154 }
1155 vfs_getnewfsid(mp);
1156 nmp->nm_mountp = mp;
1157 mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK);
1158 nmp->nm_negnametimeo = negnametimeo;
1159
1160 nfs_decode_args(mp, nmp, argp, hst, cred, td);
1161
1162 /*
1163 * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too
1164 * high, depending on whether we end up with negative offsets in
1165 * the client or server somewhere. 2GB-1 may be safer.
1166 *
1167 * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum
1168 * that we can handle until we find out otherwise.
1169 * XXX Our "safe" limit on the client is what we can store in our
1170 * buffer cache using signed(!) block numbers.
1171 */
1172 if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0)
1173 nmp->nm_maxfilesize = 0xffffffffLL;
1174 else
1175 nmp->nm_maxfilesize = (u_int64_t)0x80000000 * DEV_BSIZE - 1;
1176
1177 nmp->nm_timeo = NFS_TIMEO;
1178 nmp->nm_retry = NFS_RETRANS;
1179 if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
1180 nmp->nm_wsize = NFS_WSIZE;
1181 nmp->nm_rsize = NFS_RSIZE;
1182 nmp->nm_readdirsize = NFS_READDIRSIZE;
1183 }
1184 nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000);
1185 nmp->nm_numgrps = NFS_MAXGRPS;
1186 nmp->nm_readahead = NFS_DEFRAHEAD;
1187 nmp->nm_tprintf_delay = nfs_tprintf_delay;
1188 if (nmp->nm_tprintf_delay < 0)
1189 nmp->nm_tprintf_delay = 0;
1190 nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay;
1191 if (nmp->nm_tprintf_initial_delay < 0)
1192 nmp->nm_tprintf_initial_delay = 0;
1193 nmp->nm_fhsize = argp->fhsize;
1194 if (nmp->nm_fhsize > 0)
1195 bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
1196 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
1197 nmp->nm_nam = nam;
1198 /* Set up the sockets and per-host congestion */
1199 nmp->nm_sotype = argp->sotype;
1200 nmp->nm_soproto = argp->proto;
1201 nmp->nm_sockreq.nr_prog = NFS_PROG;
1202 if ((argp->flags & NFSMNT_NFSV4))
1203 nmp->nm_sockreq.nr_vers = NFS_VER4;
1204 else if ((argp->flags & NFSMNT_NFSV3))
1205 nmp->nm_sockreq.nr_vers = NFS_VER3;
1206 else
1207 nmp->nm_sockreq.nr_vers = NFS_VER2;
1208
1209
1210 if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0)))
1211 goto bad;
1212
1213 /*
1214 * A reference count is needed on the nfsnode representing the
1215 * remote root. If this object is not persistent, then backward
1216 * traversals of the mount point (i.e. "..") will not work if
1217 * the nfsnode gets flushed out of the cache. Ufs does not have
1218 * this problem, because one can identify root inodes by their
1219 * number == ROOTINO (2).
1220 */
1221 if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) &&
1222 nmp->nm_dirpathlen > 0) {
1223 /*
1224 * If the fhsize on the mount point == 0 for V4, the mount
1225 * path needs to be looked up.
1226 */
1227 trycnt = 3;
1228 do {
1229 error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
1230 cred, td);
1231 if (error)
1232 (void) nfs_catnap(PZERO, error, "nfsgetdirp");
1233 } while (error && --trycnt > 0);
1234 if (error) {
1235 error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
1236 goto bad;
1237 }
1238 }
1239 if (nmp->nm_fhsize > 0) {
1240 /*
1241 * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set
1242 * non-zero for the root vnode. f_iosize will be set correctly
1243 * by nfs_statfs() before any I/O occurs.
1244 */
1245 mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ;
1246 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
1247 LK_EXCLUSIVE);
1248 if (error)
1249 goto bad;
1250 *vpp = NFSTOV(np);
1251
1252 /*
1253 * Get file attributes and transfer parameters for the
1254 * mountpoint. This has the side effect of filling in
1255 * (*vpp)->v_type with the correct value.
1256 */
1257 ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
1258 cred, td, &nfsva, NULL);
1259 if (ret) {
1260 /*
1261 * Just set default values to get things going.
1262 */
1263 NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
1264 nfsva.na_vattr.va_type = VDIR;
1265 nfsva.na_vattr.va_mode = 0777;
1266 nfsva.na_vattr.va_nlink = 100;
1267 nfsva.na_vattr.va_uid = (uid_t)0;
1268 nfsva.na_vattr.va_gid = (gid_t)0;
1269 nfsva.na_vattr.va_fileid = 2;
1270 nfsva.na_vattr.va_gen = 1;
1271 nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
1272 nfsva.na_vattr.va_size = 512 * 1024;
1273 }
1274 (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1);
1275 if (argp->flags & NFSMNT_NFSV3)
1276 ncl_fsinfo(nmp, *vpp, cred, td);
1277
1278 /*
1279 * Lose the lock but keep the ref.
1280 */
1281 VOP_UNLOCK(*vpp, 0);
1282 return (0);
1283 }
1284 error = EIO;
1285
1286bad:
1287 newnfs_disconnect(&nmp->nm_sockreq);
1288 crfree(nmp->nm_sockreq.nr_cred);
1289 mtx_destroy(&nmp->nm_sockreq.nr_mtx);
1290 mtx_destroy(&nmp->nm_mtx);
1291 FREE(nmp, M_NEWNFSMNT);
1292 FREE(nam, M_SONAME);
1293 return (error);
1294}
1295
1296/*
1297 * unmount system call
1298 */
1299static int
1300nfs_unmount(struct mount *mp, int mntflags)
1301{
1302 struct thread *td;
1303 struct nfsmount *nmp;
1304 int error, flags = 0, trycnt = 0;
1305
1306 td = curthread;
1307
1308 if (mntflags & MNT_FORCE)
1309 flags |= FORCECLOSE;
1310 nmp = VFSTONFS(mp);
1311 /*
1312 * Goes something like this..
1313 * - Call vflush() to clear out vnodes for this filesystem
1314 * - Close the socket
1315 * - Free up the data structures
1316 */
1317 /* In the forced case, cancel any outstanding requests. */
1318 if (mntflags & MNT_FORCE) {
1319 error = newnfs_nmcancelreqs(nmp);
1320 if (error)
1321 goto out;
1322 /* For a forced close, get rid of the renew thread now */
1323 nfscl_umount(nmp, td);
1324 }
1325 /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
1326 do {
1327 error = vflush(mp, 1, flags, td);
1328 if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30)
1329 (void) nfs_catnap(PSOCK, error, "newndm");
1330 } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30);
1331 if (error)
1332 goto out;
1333
1334 /*
1335 * We are now committed to the unmount.
1336 */
1337 if ((mntflags & MNT_FORCE) == 0)
1338 nfscl_umount(nmp, td);
1339 newnfs_disconnect(&nmp->nm_sockreq);
1340 crfree(nmp->nm_sockreq.nr_cred);
1341 FREE(nmp->nm_nam, M_SONAME);
1342
1343 mtx_destroy(&nmp->nm_sockreq.nr_mtx);
1344 mtx_destroy(&nmp->nm_mtx);
1345 FREE(nmp, M_NEWNFSMNT);
1346out:
1347 return (error);
1348}
1349
1350/*
1351 * Return root of a filesystem
1352 */
1353static int
1354nfs_root(struct mount *mp, int flags, struct vnode **vpp)
1355{
1356 struct vnode *vp;
1357 struct nfsmount *nmp;
1358 struct nfsnode *np;
1359 int error;
1360
1361 nmp = VFSTONFS(mp);
1362 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags);
1363 if (error)
1364 return error;
1365 vp = NFSTOV(np);
1366 /*
1367 * Get transfer parameters and attributes for root vnode once.
1368 */
1369 mtx_lock(&nmp->nm_mtx);
1370 if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
1371 mtx_unlock(&nmp->nm_mtx);
1372 ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread);
1373 } else
1374 mtx_unlock(&nmp->nm_mtx);
1375 if (vp->v_type == VNON)
1376 vp->v_type = VDIR;
1377 vp->v_vflag |= VV_ROOT;
1378 *vpp = vp;
1379 return (0);
1380}
1381
1382/*
1383 * Flush out the buffer cache
1384 */
1385/* ARGSUSED */
1386static int
1387nfs_sync(struct mount *mp, int waitfor)
1388{
1389 struct vnode *vp, *mvp;
1390 struct thread *td;
1391 int error, allerror = 0;
1392
1393 td = curthread;
1394
1395 /*
1396 * Force stale buffer cache information to be flushed.
1397 */
1398 MNT_ILOCK(mp);
1399loop:
1400 MNT_VNODE_FOREACH(vp, mp, mvp) {
1401 VI_LOCK(vp);
1402 MNT_IUNLOCK(mp);
1403 /* XXX Racy bv_cnt check. */
1404 if (VOP_ISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 ||
1405 waitfor == MNT_LAZY) {
1406 VI_UNLOCK(vp);
1407 MNT_ILOCK(mp);
1408 continue;
1409 }
1410 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
1411 MNT_ILOCK(mp);
1412 MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp);
1413 goto loop;
1414 }
1415 error = VOP_FSYNC(vp, waitfor, td);
1416 if (error)
1417 allerror = error;
1418 VOP_UNLOCK(vp, 0);
1419 vrele(vp);
1420
1421 MNT_ILOCK(mp);
1422 }
1423 MNT_IUNLOCK(mp);
1424 return (allerror);
1425}
1426
1427static int
1428nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req)
1429{
1430 struct nfsmount *nmp = VFSTONFS(mp);
1431 struct vfsquery vq;
1432 int error;
1433
1434 bzero(&vq, sizeof(vq));
1435 switch (op) {
1436#if 0
1437 case VFS_CTL_NOLOCKS:
1438 val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0;
1439 if (req->oldptr != NULL) {
1440 error = SYSCTL_OUT(req, &val, sizeof(val));
1441 if (error)
1442 return (error);
1443 }
1444 if (req->newptr != NULL) {
1445 error = SYSCTL_IN(req, &val, sizeof(val));
1446 if (error)
1447 return (error);
1448 if (val)
1449 nmp->nm_flag |= NFSMNT_NOLOCKS;
1450 else
1451 nmp->nm_flag &= ~NFSMNT_NOLOCKS;
1452 }
1453 break;
1454#endif
1455 case VFS_CTL_QUERY:
1456 mtx_lock(&nmp->nm_mtx);
1457 if (nmp->nm_state & NFSSTA_TIMEO)
1458 vq.vq_flags |= VQ_NOTRESP;
1459 mtx_unlock(&nmp->nm_mtx);
1460#if 0
1461 if (!(nmp->nm_flag & NFSMNT_NOLOCKS) &&
1462 (nmp->nm_state & NFSSTA_LOCKTIMEO))
1463 vq.vq_flags |= VQ_NOTRESPLOCK;
1464#endif
1465 error = SYSCTL_OUT(req, &vq, sizeof(vq));
1466 break;
1467 case VFS_CTL_TIMEO:
1468 if (req->oldptr != NULL) {
1469 error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay,
1470 sizeof(nmp->nm_tprintf_initial_delay));
1471 if (error)
1472 return (error);
1473 }
1474 if (req->newptr != NULL) {
1475 error = vfs_suser(mp, req->td);
1476 if (error)
1477 return (error);
1478 error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay,
1479 sizeof(nmp->nm_tprintf_initial_delay));
1480 if (error)
1481 return (error);
1482 if (nmp->nm_tprintf_initial_delay < 0)
1483 nmp->nm_tprintf_initial_delay = 0;
1484 }
1485 break;
1486 default:
1487 return (ENOTSUP);
1488 }
1489 return (0);
1490}
1491
1492/*
1493 * Extract the information needed by the nlm from the nfs vnode.
1494 */
1495static void
1496nfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp,
1497 struct sockaddr_storage *sp, int *is_v3p, off_t *sizep,
1498 struct timeval *timeop)
1499{
1500 struct nfsmount *nmp;
1501 struct nfsnode *np = VTONFS(vp);
1502
1503 nmp = VFSTONFS(vp->v_mount);
1504 if (fhlenp != NULL)
1505 *fhlenp = (size_t)np->n_fhp->nfh_len;
1506 if (fhp != NULL)
1507 bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len);
1508 if (sp != NULL)
1509 bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp)));
1510 if (is_v3p != NULL)
1511 *is_v3p = NFS_ISV3(vp);
1512 if (sizep != NULL)
1513 *sizep = np->n_size;
1514 if (timeop != NULL) {
1515 timeop->tv_sec = nmp->nm_timeo / NFS_HZ;
1516 timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ);
1517 }
1518}
1519
135
136/* So that loader and kldload(2) can find us, wherever we are.. */
137MODULE_VERSION(newnfs, 1);
138
139/*
140 * This structure is now defined in sys/nfs/nfs_diskless.c so that it
141 * can be shared by both NFS clients. It is declared here so that it
142 * will be defined for kernels built without NFS_ROOT, although it
143 * isn't used in that case.
144 */
145#if !defined(NFS_ROOT) && !defined(NFSCLIENT)
146struct nfs_diskless nfs_diskless = { { { 0 } } };
147struct nfsv3_diskless nfsv3_diskless = { { { 0 } } };
148int nfs_diskless_valid = 0;
149#endif
150
151SYSCTL_INT(_vfs_newnfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
152 &nfs_diskless_valid, 0,
153 "Has the diskless struct been filled correctly");
154
155SYSCTL_STRING(_vfs_newnfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
156 nfsv3_diskless.root_hostnam, 0, "Path to nfs root");
157
158SYSCTL_OPAQUE(_vfs_newnfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
159 &nfsv3_diskless.root_saddr, sizeof(nfsv3_diskless.root_saddr),
160 "%Ssockaddr_in", "Diskless root nfs address");
161
162
163void newnfsargs_ntoh(struct nfs_args *);
164static int nfs_mountdiskless(char *,
165 struct sockaddr_in *, struct nfs_args *,
166 struct thread *, struct vnode **, struct mount *);
167static void nfs_convert_diskless(void);
168static void nfs_convert_oargs(struct nfs_args *args,
169 struct onfs_args *oargs);
170
171int
172newnfs_iosize(struct nfsmount *nmp)
173{
174 int iosize, maxio;
175
176 /* First, set the upper limit for iosize */
177 if (nmp->nm_flag & NFSMNT_NFSV4) {
178 maxio = NFS_MAXBSIZE;
179 } else if (nmp->nm_flag & NFSMNT_NFSV3) {
180 if (nmp->nm_sotype == SOCK_DGRAM)
181 maxio = NFS_MAXDGRAMDATA;
182 else
183 maxio = NFS_MAXBSIZE;
184 } else {
185 maxio = NFS_V2MAXDATA;
186 }
187 if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0)
188 nmp->nm_rsize = maxio;
189 if (nmp->nm_rsize > MAXBSIZE)
190 nmp->nm_rsize = MAXBSIZE;
191 if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0)
192 nmp->nm_readdirsize = maxio;
193 if (nmp->nm_readdirsize > nmp->nm_rsize)
194 nmp->nm_readdirsize = nmp->nm_rsize;
195 if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0)
196 nmp->nm_wsize = maxio;
197 if (nmp->nm_wsize > MAXBSIZE)
198 nmp->nm_wsize = MAXBSIZE;
199
200 /*
201 * Calculate the size used for io buffers. Use the larger
202 * of the two sizes to minimise nfs requests but make sure
203 * that it is at least one VM page to avoid wasting buffer
204 * space.
205 */
206 iosize = imax(nmp->nm_rsize, nmp->nm_wsize);
207 iosize = imax(iosize, PAGE_SIZE);
208 nmp->nm_mountp->mnt_stat.f_iosize = iosize;
209 return (iosize);
210}
211
212static void
213nfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs)
214{
215
216 args->version = NFS_ARGSVERSION;
217 args->addr = oargs->addr;
218 args->addrlen = oargs->addrlen;
219 args->sotype = oargs->sotype;
220 args->proto = oargs->proto;
221 args->fh = oargs->fh;
222 args->fhsize = oargs->fhsize;
223 args->flags = oargs->flags;
224 args->wsize = oargs->wsize;
225 args->rsize = oargs->rsize;
226 args->readdirsize = oargs->readdirsize;
227 args->timeo = oargs->timeo;
228 args->retrans = oargs->retrans;
229 args->readahead = oargs->readahead;
230 args->hostname = oargs->hostname;
231}
232
233static void
234nfs_convert_diskless(void)
235{
236
237 bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
238 sizeof(struct ifaliasreq));
239 bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
240 sizeof(struct sockaddr_in));
241 nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args);
242 if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) {
243 nfsv3_diskless.root_fhsize = NFSX_MYFH;
244 bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_MYFH);
245 } else {
246 nfsv3_diskless.root_fhsize = NFSX_V2FH;
247 bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH);
248 }
249 bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
250 sizeof(struct sockaddr_in));
251 bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN);
252 nfsv3_diskless.root_time = nfs_diskless.root_time;
253 bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam,
254 MAXHOSTNAMELEN);
255 nfs_diskless_valid = 3;
256}
257
258/*
259 * nfs statfs call
260 */
261static int
262nfs_statfs(struct mount *mp, struct statfs *sbp)
263{
264 struct vnode *vp;
265 struct thread *td;
266 struct nfsmount *nmp = VFSTONFS(mp);
267 struct nfsvattr nfsva;
268 struct nfsfsinfo fs;
269 struct nfsstatfs sb;
270 int error = 0, attrflag, gotfsinfo = 0, ret;
271 struct nfsnode *np;
272
273 td = curthread;
274
275 error = vfs_busy(mp, MBF_NOWAIT);
276 if (error)
277 return (error);
278 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE);
279 if (error) {
280 vfs_unbusy(mp);
281 return (error);
282 }
283 vp = NFSTOV(np);
284 mtx_lock(&nmp->nm_mtx);
285 if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
286 mtx_unlock(&nmp->nm_mtx);
287 error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva,
288 &attrflag, NULL);
289 if (!error)
290 gotfsinfo = 1;
291 } else
292 mtx_unlock(&nmp->nm_mtx);
293 if (!error)
294 error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva,
295 &attrflag, NULL);
296 if (attrflag == 0) {
297 ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
298 td->td_ucred, td, &nfsva, NULL);
299 if (ret) {
300 /*
301 * Just set default values to get things going.
302 */
303 NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
304 nfsva.na_vattr.va_type = VDIR;
305 nfsva.na_vattr.va_mode = 0777;
306 nfsva.na_vattr.va_nlink = 100;
307 nfsva.na_vattr.va_uid = (uid_t)0;
308 nfsva.na_vattr.va_gid = (gid_t)0;
309 nfsva.na_vattr.va_fileid = 2;
310 nfsva.na_vattr.va_gen = 1;
311 nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
312 nfsva.na_vattr.va_size = 512 * 1024;
313 }
314 }
315 (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1);
316 if (!error) {
317 mtx_lock(&nmp->nm_mtx);
318 if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4))
319 nfscl_loadfsinfo(nmp, &fs);
320 nfscl_loadsbinfo(nmp, &sb, sbp);
321 sbp->f_iosize = newnfs_iosize(nmp);
322 mtx_unlock(&nmp->nm_mtx);
323 if (sbp != &mp->mnt_stat) {
324 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
325 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
326 }
327 strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN);
328 } else if (NFS_ISV4(vp)) {
329 error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
330 }
331 vput(vp);
332 vfs_unbusy(mp);
333 return (error);
334}
335
336/*
337 * nfs version 3 fsinfo rpc call
338 */
339int
340ncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred,
341 struct thread *td)
342{
343 struct nfsfsinfo fs;
344 struct nfsvattr nfsva;
345 int error, attrflag;
346
347 error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL);
348 if (!error) {
349 if (attrflag)
350 (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0,
351 1);
352 mtx_lock(&nmp->nm_mtx);
353 nfscl_loadfsinfo(nmp, &fs);
354 mtx_unlock(&nmp->nm_mtx);
355 }
356 return (error);
357}
358
359/*
360 * Mount a remote root fs via. nfs. This depends on the info in the
361 * nfs_diskless structure that has been filled in properly by some primary
362 * bootstrap.
363 * It goes something like this:
364 * - do enough of "ifconfig" by calling ifioctl() so that the system
365 * can talk to the server
366 * - If nfs_diskless.mygateway is filled in, use that address as
367 * a default gateway.
368 * - build the rootfs mount point and call mountnfs() to do the rest.
369 *
370 * It is assumed to be safe to read, modify, and write the nfsv3_diskless
371 * structure, as well as other global NFS client variables here, as
372 * nfs_mountroot() will be called once in the boot before any other NFS
373 * client activity occurs.
374 */
375static int
376nfs_mountroot(struct mount *mp)
377{
378 struct thread *td = curthread;
379 struct nfsv3_diskless *nd = &nfsv3_diskless;
380 struct socket *so;
381 struct vnode *vp;
382 struct ifreq ir;
383 int error;
384 u_long l;
385 char buf[128];
386 char *cp;
387
388#if defined(BOOTP_NFSROOT) && defined(BOOTP)
389 bootpc_init(); /* use bootp to get nfs_diskless filled in */
390#elif defined(NFS_ROOT)
391 nfs_setup_diskless();
392#endif
393
394 if (nfs_diskless_valid == 0)
395 return (-1);
396 if (nfs_diskless_valid == 1)
397 nfs_convert_diskless();
398
399 /*
400 * XXX splnet, so networks will receive...
401 */
402 splnet();
403
404 /*
405 * Do enough of ifconfig(8) so that the critical net interface can
406 * talk to the server.
407 */
408 error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0,
409 td->td_ucred, td);
410 if (error)
411 panic("nfs_mountroot: socreate(%04x): %d",
412 nd->myif.ifra_addr.sa_family, error);
413
414#if 0 /* XXX Bad idea */
415 /*
416 * We might not have been told the right interface, so we pass
417 * over the first ten interfaces of the same kind, until we get
418 * one of them configured.
419 */
420
421 for (i = strlen(nd->myif.ifra_name) - 1;
422 nd->myif.ifra_name[i] >= '0' &&
423 nd->myif.ifra_name[i] <= '9';
424 nd->myif.ifra_name[i] ++) {
425 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
426 if(!error)
427 break;
428 }
429#endif
430 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
431 if (error)
432 panic("nfs_mountroot: SIOCAIFADDR: %d", error);
433 if ((cp = getenv("boot.netif.mtu")) != NULL) {
434 ir.ifr_mtu = strtol(cp, NULL, 10);
435 bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ);
436 freeenv(cp);
437 error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td);
438 if (error)
439 printf("nfs_mountroot: SIOCSIFMTU: %d", error);
440 }
441 soclose(so);
442
443 /*
444 * If the gateway field is filled in, set it as the default route.
445 * Note that pxeboot will set a default route of 0 if the route
446 * is not set by the DHCP server. Check also for a value of 0
447 * to avoid panicking inappropriately in that situation.
448 */
449 if (nd->mygateway.sin_len != 0 &&
450 nd->mygateway.sin_addr.s_addr != 0) {
451 struct sockaddr_in mask, sin;
452
453 bzero((caddr_t)&mask, sizeof(mask));
454 sin = mask;
455 sin.sin_family = AF_INET;
456 sin.sin_len = sizeof(sin);
457 /* XXX MRT use table 0 for this sort of thing */
458 CURVNET_SET(TD_TO_VNET(td));
459 error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
460 (struct sockaddr *)&nd->mygateway,
461 (struct sockaddr *)&mask,
462 RTF_UP | RTF_GATEWAY, NULL);
463 CURVNET_RESTORE();
464 if (error)
465 panic("nfs_mountroot: RTM_ADD: %d", error);
466 }
467
468 /*
469 * Create the rootfs mount point.
470 */
471 nd->root_args.fh = nd->root_fh;
472 nd->root_args.fhsize = nd->root_fhsize;
473 l = ntohl(nd->root_saddr.sin_addr.s_addr);
474 snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s",
475 (l >> 24) & 0xff, (l >> 16) & 0xff,
476 (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam);
477 printf("NFS ROOT: %s\n", buf);
478 nd->root_args.hostname = buf;
479 if ((error = nfs_mountdiskless(buf,
480 &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) {
481 return (error);
482 }
483
484 /*
485 * This is not really an nfs issue, but it is much easier to
486 * set hostname here and then let the "/etc/rc.xxx" files
487 * mount the right /var based upon its preset value.
488 */
489 mtx_lock(&prison0.pr_mtx);
490 strlcpy(prison0.pr_hostname, nd->my_hostnam,
491 sizeof(prison0.pr_hostname));
492 mtx_unlock(&prison0.pr_mtx);
493 inittodr(ntohl(nd->root_time));
494 return (0);
495}
496
497/*
498 * Internal version of mount system call for diskless setup.
499 */
500static int
501nfs_mountdiskless(char *path,
502 struct sockaddr_in *sin, struct nfs_args *args, struct thread *td,
503 struct vnode **vpp, struct mount *mp)
504{
505 struct sockaddr *nam;
506 int dirlen, error;
507 char *dirpath;
508
509 /*
510 * Find the directory path in "path", which also has the server's
511 * name/ip address in it.
512 */
513 dirpath = strchr(path, ':');
514 if (dirpath != NULL)
515 dirlen = strlen(++dirpath);
516 else
517 dirlen = 0;
518 nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
519 if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen,
520 NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NEGNAMETIMEO)) != 0) {
521 printf("nfs_mountroot: mount %s on /: %d\n", path, error);
522 return (error);
523 }
524 return (0);
525}
526
527static void
528nfs_sec_name(char *sec, int *flagsp)
529{
530 if (!strcmp(sec, "krb5"))
531 *flagsp |= NFSMNT_KERB;
532 else if (!strcmp(sec, "krb5i"))
533 *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY);
534 else if (!strcmp(sec, "krb5p"))
535 *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY);
536}
537
538static void
539nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp,
540 const char *hostname, struct ucred *cred, struct thread *td)
541{
542 int s;
543 int adjsock;
544 char *p;
545
546 s = splnet();
547
548 /*
549 * Set read-only flag if requested; otherwise, clear it if this is
550 * an update. If this is not an update, then either the read-only
551 * flag is already clear, or this is a root mount and it was set
552 * intentionally at some previous point.
553 */
554 if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) {
555 MNT_ILOCK(mp);
556 mp->mnt_flag |= MNT_RDONLY;
557 MNT_IUNLOCK(mp);
558 } else if (mp->mnt_flag & MNT_UPDATE) {
559 MNT_ILOCK(mp);
560 mp->mnt_flag &= ~MNT_RDONLY;
561 MNT_IUNLOCK(mp);
562 }
563
564 /*
565 * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
566 * no sense in that context. Also, set up appropriate retransmit
567 * and soft timeout behavior.
568 */
569 if (argp->sotype == SOCK_STREAM) {
570 nmp->nm_flag &= ~NFSMNT_NOCONN;
571 nmp->nm_timeo = NFS_MAXTIMEO;
572 if ((argp->flags & NFSMNT_NFSV4) != 0)
573 nmp->nm_retry = INT_MAX;
574 else
575 nmp->nm_retry = NFS_RETRANS_TCP;
576 }
577
578 /* Also clear RDIRPLUS if NFSv2, it crashes some servers */
579 if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
580 argp->flags &= ~NFSMNT_RDIRPLUS;
581 nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
582 }
583
584 /* Clear NFSMNT_RESVPORT for NFSv4, since it is not required. */
585 if ((argp->flags & NFSMNT_NFSV4) != 0) {
586 argp->flags &= ~NFSMNT_RESVPORT;
587 nmp->nm_flag &= ~NFSMNT_RESVPORT;
588 }
589
590 /* Re-bind if rsrvd port requested and wasn't on one */
591 adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
592 && (argp->flags & NFSMNT_RESVPORT);
593 /* Also re-bind if we're switching to/from a connected UDP socket */
594 adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
595 (argp->flags & NFSMNT_NOCONN));
596
597 /* Update flags atomically. Don't change the lock bits. */
598 nmp->nm_flag = argp->flags | nmp->nm_flag;
599 splx(s);
600
601 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
602 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
603 if (nmp->nm_timeo < NFS_MINTIMEO)
604 nmp->nm_timeo = NFS_MINTIMEO;
605 else if (nmp->nm_timeo > NFS_MAXTIMEO)
606 nmp->nm_timeo = NFS_MAXTIMEO;
607 }
608
609 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
610 nmp->nm_retry = argp->retrans;
611 if (nmp->nm_retry > NFS_MAXREXMIT)
612 nmp->nm_retry = NFS_MAXREXMIT;
613 }
614
615 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
616 nmp->nm_wsize = argp->wsize;
617 /* Round down to multiple of blocksize */
618 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
619 if (nmp->nm_wsize <= 0)
620 nmp->nm_wsize = NFS_FABLKSIZE;
621 }
622
623 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
624 nmp->nm_rsize = argp->rsize;
625 /* Round down to multiple of blocksize */
626 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
627 if (nmp->nm_rsize <= 0)
628 nmp->nm_rsize = NFS_FABLKSIZE;
629 }
630
631 if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
632 nmp->nm_readdirsize = argp->readdirsize;
633 }
634
635 if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0)
636 nmp->nm_acregmin = argp->acregmin;
637 else
638 nmp->nm_acregmin = NFS_MINATTRTIMO;
639 if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0)
640 nmp->nm_acregmax = argp->acregmax;
641 else
642 nmp->nm_acregmax = NFS_MAXATTRTIMO;
643 if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0)
644 nmp->nm_acdirmin = argp->acdirmin;
645 else
646 nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
647 if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0)
648 nmp->nm_acdirmax = argp->acdirmax;
649 else
650 nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO;
651 if (nmp->nm_acdirmin > nmp->nm_acdirmax)
652 nmp->nm_acdirmin = nmp->nm_acdirmax;
653 if (nmp->nm_acregmin > nmp->nm_acregmax)
654 nmp->nm_acregmin = nmp->nm_acregmax;
655
656 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) {
657 if (argp->readahead <= NFS_MAXRAHEAD)
658 nmp->nm_readahead = argp->readahead;
659 else
660 nmp->nm_readahead = NFS_MAXRAHEAD;
661 }
662 if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) {
663 if (argp->wcommitsize < nmp->nm_wsize)
664 nmp->nm_wcommitsize = nmp->nm_wsize;
665 else
666 nmp->nm_wcommitsize = argp->wcommitsize;
667 }
668
669 adjsock |= ((nmp->nm_sotype != argp->sotype) ||
670 (nmp->nm_soproto != argp->proto));
671
672 if (nmp->nm_client != NULL && adjsock) {
673 int haslock = 0, error = 0;
674
675 if (nmp->nm_sotype == SOCK_STREAM) {
676 error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock);
677 if (!error)
678 haslock = 1;
679 }
680 if (!error) {
681 newnfs_disconnect(&nmp->nm_sockreq);
682 if (haslock)
683 newnfs_sndunlock(&nmp->nm_sockreq.nr_lock);
684 nmp->nm_sotype = argp->sotype;
685 nmp->nm_soproto = argp->proto;
686 if (nmp->nm_sotype == SOCK_DGRAM)
687 while (newnfs_connect(nmp, &nmp->nm_sockreq,
688 cred, td, 0)) {
689 printf("newnfs_args: retrying connect\n");
690 (void) nfs_catnap(PSOCK, 0, "newnfscon");
691 }
692 }
693 } else {
694 nmp->nm_sotype = argp->sotype;
695 nmp->nm_soproto = argp->proto;
696 }
697
698 if (hostname != NULL) {
699 strlcpy(nmp->nm_hostname, hostname,
700 sizeof(nmp->nm_hostname));
701 p = strchr(nmp->nm_hostname, ':');
702 if (p != NULL)
703 *p = '\0';
704 }
705}
706
707static const char *nfs_opts[] = { "from",
708 "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union",
709 "noclusterr", "noclusterw", "multilabel", "acls", "force", "update",
710 "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus",
711 "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize",
712 "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport",
713 "readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec",
714 "principal", "nfsv4", "gssname", "allgssname", "dirpath",
715 "negnametimeo",
716 NULL };
717
718/*
719 * VFS Operations.
720 *
721 * mount system call
722 * It seems a bit dumb to copyinstr() the host and path here and then
723 * bcopy() them in mountnfs(), but I wanted to detect errors before
724 * doing the sockargs() call because sockargs() allocates an mbuf and
725 * an error after that means that I have to release the mbuf.
726 */
727/* ARGSUSED */
728static int
729nfs_mount(struct mount *mp)
730{
731 struct nfs_args args = {
732 .version = NFS_ARGSVERSION,
733 .addr = NULL,
734 .addrlen = sizeof (struct sockaddr_in),
735 .sotype = SOCK_STREAM,
736 .proto = 0,
737 .fh = NULL,
738 .fhsize = 0,
739 .flags = NFSMNT_RESVPORT,
740 .wsize = NFS_WSIZE,
741 .rsize = NFS_RSIZE,
742 .readdirsize = NFS_READDIRSIZE,
743 .timeo = 10,
744 .retrans = NFS_RETRANS,
745 .readahead = NFS_DEFRAHEAD,
746 .wcommitsize = 0, /* was: NQ_DEFLEASE */
747 .hostname = NULL,
748 .acregmin = NFS_MINATTRTIMO,
749 .acregmax = NFS_MAXATTRTIMO,
750 .acdirmin = NFS_MINDIRATTRTIMO,
751 .acdirmax = NFS_MAXDIRATTRTIMO,
752 };
753 int error = 0, ret, len;
754 struct sockaddr *nam = NULL;
755 struct vnode *vp;
756 struct thread *td;
757 char hst[MNAMELEN];
758 u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100];
759 char *opt, *name, *secname;
760 int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
761 int dirlen, krbnamelen, srvkrbnamelen;
762
763 if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
764 error = EINVAL;
765 goto out;
766 }
767
768 td = curthread;
769 if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) {
770 error = nfs_mountroot(mp);
771 goto out;
772 }
773
774 nfscl_init();
775
776 /* Handle the new style options. */
777 if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0)
778 args.flags |= NFSMNT_NOCONN;
779 if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0)
780 args.flags |= NFSMNT_NOCONN;
781 if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0)
782 args.flags |= NFSMNT_NOLOCKD;
783 if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0)
784 args.flags &= ~NFSMNT_NOLOCKD;
785 if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0)
786 args.flags |= NFSMNT_INT;
787 if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0)
788 args.flags |= NFSMNT_RDIRPLUS;
789 if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0)
790 args.flags |= NFSMNT_RESVPORT;
791 if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0)
792 args.flags &= ~NFSMNT_RESVPORT;
793 if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0)
794 args.flags |= NFSMNT_SOFT;
795 if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0)
796 args.flags &= ~NFSMNT_SOFT;
797 if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0)
798 args.sotype = SOCK_DGRAM;
799 if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0)
800 args.sotype = SOCK_DGRAM;
801 if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0)
802 args.sotype = SOCK_STREAM;
803 if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0)
804 args.flags |= NFSMNT_NFSV3;
805 if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) {
806 args.flags |= NFSMNT_NFSV4;
807 args.sotype = SOCK_STREAM;
808 }
809 if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0)
810 args.flags |= NFSMNT_ALLGSSNAME;
811 if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) {
812 if (opt == NULL) {
813 vfs_mount_error(mp, "illegal readdirsize");
814 error = EINVAL;
815 goto out;
816 }
817 ret = sscanf(opt, "%d", &args.readdirsize);
818 if (ret != 1 || args.readdirsize <= 0) {
819 vfs_mount_error(mp, "illegal readdirsize: %s",
820 opt);
821 error = EINVAL;
822 goto out;
823 }
824 args.flags |= NFSMNT_READDIRSIZE;
825 }
826 if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) {
827 if (opt == NULL) {
828 vfs_mount_error(mp, "illegal readahead");
829 error = EINVAL;
830 goto out;
831 }
832 ret = sscanf(opt, "%d", &args.readahead);
833 if (ret != 1 || args.readahead <= 0) {
834 vfs_mount_error(mp, "illegal readahead: %s",
835 opt);
836 error = EINVAL;
837 goto out;
838 }
839 args.flags |= NFSMNT_READAHEAD;
840 }
841 if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) {
842 if (opt == NULL) {
843 vfs_mount_error(mp, "illegal wsize");
844 error = EINVAL;
845 goto out;
846 }
847 ret = sscanf(opt, "%d", &args.wsize);
848 if (ret != 1 || args.wsize <= 0) {
849 vfs_mount_error(mp, "illegal wsize: %s",
850 opt);
851 error = EINVAL;
852 goto out;
853 }
854 args.flags |= NFSMNT_WSIZE;
855 }
856 if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) {
857 if (opt == NULL) {
858 vfs_mount_error(mp, "illegal rsize");
859 error = EINVAL;
860 goto out;
861 }
862 ret = sscanf(opt, "%d", &args.rsize);
863 if (ret != 1 || args.rsize <= 0) {
864 vfs_mount_error(mp, "illegal wsize: %s",
865 opt);
866 error = EINVAL;
867 goto out;
868 }
869 args.flags |= NFSMNT_RSIZE;
870 }
871 if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) {
872 if (opt == NULL) {
873 vfs_mount_error(mp, "illegal retrans");
874 error = EINVAL;
875 goto out;
876 }
877 ret = sscanf(opt, "%d", &args.retrans);
878 if (ret != 1 || args.retrans <= 0) {
879 vfs_mount_error(mp, "illegal retrans: %s",
880 opt);
881 error = EINVAL;
882 goto out;
883 }
884 args.flags |= NFSMNT_RETRANS;
885 }
886 if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) {
887 ret = sscanf(opt, "%d", &args.acregmin);
888 if (ret != 1 || args.acregmin < 0) {
889 vfs_mount_error(mp, "illegal acregmin: %s",
890 opt);
891 error = EINVAL;
892 goto out;
893 }
894 args.flags |= NFSMNT_ACREGMIN;
895 }
896 if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) {
897 ret = sscanf(opt, "%d", &args.acregmax);
898 if (ret != 1 || args.acregmax < 0) {
899 vfs_mount_error(mp, "illegal acregmax: %s",
900 opt);
901 error = EINVAL;
902 goto out;
903 }
904 args.flags |= NFSMNT_ACREGMAX;
905 }
906 if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) {
907 ret = sscanf(opt, "%d", &args.acdirmin);
908 if (ret != 1 || args.acdirmin < 0) {
909 vfs_mount_error(mp, "illegal acdirmin: %s",
910 opt);
911 error = EINVAL;
912 goto out;
913 }
914 args.flags |= NFSMNT_ACDIRMIN;
915 }
916 if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) {
917 ret = sscanf(opt, "%d", &args.acdirmax);
918 if (ret != 1 || args.acdirmax < 0) {
919 vfs_mount_error(mp, "illegal acdirmax: %s",
920 opt);
921 error = EINVAL;
922 goto out;
923 }
924 args.flags |= NFSMNT_ACDIRMAX;
925 }
926 if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) {
927 ret = sscanf(opt, "%d", &args.timeo);
928 if (ret != 1 || args.timeo <= 0) {
929 vfs_mount_error(mp, "illegal timeout: %s",
930 opt);
931 error = EINVAL;
932 goto out;
933 }
934 args.flags |= NFSMNT_TIMEO;
935 }
936 if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
937 == 0) {
938 ret = sscanf(opt, "%d", &negnametimeo);
939 if (ret != 1 || negnametimeo < 0) {
940 vfs_mount_error(mp, "illegal negnametimeo: %s",
941 opt);
942 error = EINVAL;
943 goto out;
944 }
945 }
946 if (vfs_getopt(mp->mnt_optnew, "sec",
947 (void **) &secname, NULL) == 0)
948 nfs_sec_name(secname, &args.flags);
949
950 if (mp->mnt_flag & MNT_UPDATE) {
951 struct nfsmount *nmp = VFSTONFS(mp);
952
953 if (nmp == NULL) {
954 error = EIO;
955 goto out;
956 }
957 /*
958 * When doing an update, we can't change version,
959 * security, switch lockd strategies or change cookie
960 * translation
961 */
962 args.flags = (args.flags &
963 ~(NFSMNT_NFSV3 |
964 NFSMNT_NFSV4 |
965 NFSMNT_KERB |
966 NFSMNT_INTEGRITY |
967 NFSMNT_PRIVACY |
968 NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) |
969 (nmp->nm_flag &
970 (NFSMNT_NFSV3 |
971 NFSMNT_NFSV4 |
972 NFSMNT_KERB |
973 NFSMNT_INTEGRITY |
974 NFSMNT_PRIVACY |
975 NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/));
976 nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td);
977 goto out;
978 }
979
980 /*
981 * Make the nfs_ip_paranoia sysctl serve as the default connection
982 * or no-connection mode for those protocols that support
983 * no-connection mode (the flag will be cleared later for protocols
984 * that do not support no-connection mode). This will allow a client
985 * to receive replies from a different IP then the request was
986 * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid),
987 * not 0.
988 */
989 if (nfs_ip_paranoia == 0)
990 args.flags |= NFSMNT_NOCONN;
991
992 if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh,
993 &args.fhsize) == 0) {
994 if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) {
995 vfs_mount_error(mp, "Bad file handle");
996 error = EINVAL;
997 goto out;
998 }
999 bcopy(args.fh, nfh, args.fhsize);
1000 } else {
1001 args.fhsize = 0;
1002 }
1003
1004 (void) vfs_getopt(mp->mnt_optnew, "hostname", (void **)&args.hostname,
1005 &len);
1006 if (args.hostname == NULL) {
1007 vfs_mount_error(mp, "Invalid hostname");
1008 error = EINVAL;
1009 goto out;
1010 }
1011 bcopy(args.hostname, hst, MNAMELEN);
1012 hst[MNAMELEN - 1] = '\0';
1013
1014 if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0)
1015 strlcpy(srvkrbname, name, sizeof (srvkrbname));
1016 else
1017 snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst);
1018 srvkrbnamelen = strlen(srvkrbname);
1019
1020 if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0)
1021 strlcpy(krbname, name, sizeof (krbname));
1022 else
1023 krbname[0] = '\0';
1024 krbnamelen = strlen(krbname);
1025
1026 if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0)
1027 strlcpy(dirpath, name, sizeof (dirpath));
1028 else
1029 dirpath[0] = '\0';
1030 dirlen = strlen(dirpath);
1031
1032 if (vfs_getopt(mp->mnt_optnew, "addr", (void **)&args.addr,
1033 &args.addrlen) == 0) {
1034 if (args.addrlen > SOCK_MAXADDRLEN) {
1035 error = ENAMETOOLONG;
1036 goto out;
1037 }
1038 nam = malloc(args.addrlen, M_SONAME, M_WAITOK);
1039 bcopy(args.addr, nam, args.addrlen);
1040 nam->sa_len = args.addrlen;
1041 }
1042
1043 args.fh = nfh;
1044 error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
1045 dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
1046 negnametimeo);
1047out:
1048 if (!error) {
1049 MNT_ILOCK(mp);
1050 mp->mnt_kern_flag |= (MNTK_MPSAFE|MNTK_LOOKUP_SHARED);
1051 MNT_IUNLOCK(mp);
1052 }
1053 return (error);
1054}
1055
1056
1057/*
1058 * VFS Operations.
1059 *
1060 * mount system call
1061 * It seems a bit dumb to copyinstr() the host and path here and then
1062 * bcopy() them in mountnfs(), but I wanted to detect errors before
1063 * doing the sockargs() call because sockargs() allocates an mbuf and
1064 * an error after that means that I have to release the mbuf.
1065 */
1066/* ARGSUSED */
1067static int
1068nfs_cmount(struct mntarg *ma, void *data, int flags)
1069{
1070 int error;
1071 struct nfs_args args;
1072
1073 error = copyin(data, &args, sizeof (struct nfs_args));
1074 if (error)
1075 return error;
1076
1077 ma = mount_arg(ma, "nfs_args", &args, sizeof args);
1078
1079 error = kernel_mount(ma, flags);
1080 return (error);
1081}
1082
1083/*
1084 * Common code for mount and mountroot
1085 */
1086static int
1087mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
1088 char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen,
1089 u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp,
1090 struct ucred *cred, struct thread *td, int negnametimeo)
1091{
1092 struct nfsmount *nmp;
1093 struct nfsnode *np;
1094 int error, trycnt, ret;
1095 struct nfsvattr nfsva;
1096 static u_int64_t clval = 0;
1097
1098 if (mp->mnt_flag & MNT_UPDATE) {
1099 nmp = VFSTONFS(mp);
1100 printf("%s: MNT_UPDATE is no longer handled here\n", __func__);
1101 FREE(nam, M_SONAME);
1102 return (0);
1103 } else {
1104 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) +
1105 krbnamelen + dirlen + srvkrbnamelen + 2,
1106 M_NEWNFSMNT, M_WAITOK | M_ZERO);
1107 TAILQ_INIT(&nmp->nm_bufq);
1108 if (clval == 0)
1109 clval = (u_int64_t)nfsboottime.tv_sec;
1110 nmp->nm_clval = clval++;
1111 nmp->nm_krbnamelen = krbnamelen;
1112 nmp->nm_dirpathlen = dirlen;
1113 nmp->nm_srvkrbnamelen = srvkrbnamelen;
1114 if (td->td_ucred->cr_uid != (uid_t)0) {
1115 /*
1116 * nm_uid is used to get KerberosV credentials for
1117 * the nfsv4 state handling operations if there is
1118 * no host based principal set. Use the uid of
1119 * this user if not root, since they are doing the
1120 * mount. I don't think setting this for root will
1121 * work, since root normally does not have user
1122 * credentials in a credentials cache.
1123 */
1124 nmp->nm_uid = td->td_ucred->cr_uid;
1125 } else {
1126 /*
1127 * Just set to -1, so it won't be used.
1128 */
1129 nmp->nm_uid = (uid_t)-1;
1130 }
1131
1132 /* Copy and null terminate all the names */
1133 if (nmp->nm_krbnamelen > 0) {
1134 bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen);
1135 nmp->nm_name[nmp->nm_krbnamelen] = '\0';
1136 }
1137 if (nmp->nm_dirpathlen > 0) {
1138 bcopy(dirpath, NFSMNT_DIRPATH(nmp),
1139 nmp->nm_dirpathlen);
1140 nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
1141 + 1] = '\0';
1142 }
1143 if (nmp->nm_srvkrbnamelen > 0) {
1144 bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp),
1145 nmp->nm_srvkrbnamelen);
1146 nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
1147 + nmp->nm_srvkrbnamelen + 2] = '\0';
1148 }
1149 nmp->nm_sockreq.nr_cred = crhold(cred);
1150 mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF);
1151 mp->mnt_data = nmp;
1152 nmp->nm_getinfo = nfs_getnlminfo;
1153 nmp->nm_vinvalbuf = ncl_vinvalbuf;
1154 }
1155 vfs_getnewfsid(mp);
1156 nmp->nm_mountp = mp;
1157 mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK);
1158 nmp->nm_negnametimeo = negnametimeo;
1159
1160 nfs_decode_args(mp, nmp, argp, hst, cred, td);
1161
1162 /*
1163 * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too
1164 * high, depending on whether we end up with negative offsets in
1165 * the client or server somewhere. 2GB-1 may be safer.
1166 *
1167 * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum
1168 * that we can handle until we find out otherwise.
1169 * XXX Our "safe" limit on the client is what we can store in our
1170 * buffer cache using signed(!) block numbers.
1171 */
1172 if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0)
1173 nmp->nm_maxfilesize = 0xffffffffLL;
1174 else
1175 nmp->nm_maxfilesize = (u_int64_t)0x80000000 * DEV_BSIZE - 1;
1176
1177 nmp->nm_timeo = NFS_TIMEO;
1178 nmp->nm_retry = NFS_RETRANS;
1179 if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
1180 nmp->nm_wsize = NFS_WSIZE;
1181 nmp->nm_rsize = NFS_RSIZE;
1182 nmp->nm_readdirsize = NFS_READDIRSIZE;
1183 }
1184 nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000);
1185 nmp->nm_numgrps = NFS_MAXGRPS;
1186 nmp->nm_readahead = NFS_DEFRAHEAD;
1187 nmp->nm_tprintf_delay = nfs_tprintf_delay;
1188 if (nmp->nm_tprintf_delay < 0)
1189 nmp->nm_tprintf_delay = 0;
1190 nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay;
1191 if (nmp->nm_tprintf_initial_delay < 0)
1192 nmp->nm_tprintf_initial_delay = 0;
1193 nmp->nm_fhsize = argp->fhsize;
1194 if (nmp->nm_fhsize > 0)
1195 bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
1196 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
1197 nmp->nm_nam = nam;
1198 /* Set up the sockets and per-host congestion */
1199 nmp->nm_sotype = argp->sotype;
1200 nmp->nm_soproto = argp->proto;
1201 nmp->nm_sockreq.nr_prog = NFS_PROG;
1202 if ((argp->flags & NFSMNT_NFSV4))
1203 nmp->nm_sockreq.nr_vers = NFS_VER4;
1204 else if ((argp->flags & NFSMNT_NFSV3))
1205 nmp->nm_sockreq.nr_vers = NFS_VER3;
1206 else
1207 nmp->nm_sockreq.nr_vers = NFS_VER2;
1208
1209
1210 if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0)))
1211 goto bad;
1212
1213 /*
1214 * A reference count is needed on the nfsnode representing the
1215 * remote root. If this object is not persistent, then backward
1216 * traversals of the mount point (i.e. "..") will not work if
1217 * the nfsnode gets flushed out of the cache. Ufs does not have
1218 * this problem, because one can identify root inodes by their
1219 * number == ROOTINO (2).
1220 */
1221 if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) &&
1222 nmp->nm_dirpathlen > 0) {
1223 /*
1224 * If the fhsize on the mount point == 0 for V4, the mount
1225 * path needs to be looked up.
1226 */
1227 trycnt = 3;
1228 do {
1229 error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
1230 cred, td);
1231 if (error)
1232 (void) nfs_catnap(PZERO, error, "nfsgetdirp");
1233 } while (error && --trycnt > 0);
1234 if (error) {
1235 error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
1236 goto bad;
1237 }
1238 }
1239 if (nmp->nm_fhsize > 0) {
1240 /*
1241 * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set
1242 * non-zero for the root vnode. f_iosize will be set correctly
1243 * by nfs_statfs() before any I/O occurs.
1244 */
1245 mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ;
1246 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
1247 LK_EXCLUSIVE);
1248 if (error)
1249 goto bad;
1250 *vpp = NFSTOV(np);
1251
1252 /*
1253 * Get file attributes and transfer parameters for the
1254 * mountpoint. This has the side effect of filling in
1255 * (*vpp)->v_type with the correct value.
1256 */
1257 ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
1258 cred, td, &nfsva, NULL);
1259 if (ret) {
1260 /*
1261 * Just set default values to get things going.
1262 */
1263 NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
1264 nfsva.na_vattr.va_type = VDIR;
1265 nfsva.na_vattr.va_mode = 0777;
1266 nfsva.na_vattr.va_nlink = 100;
1267 nfsva.na_vattr.va_uid = (uid_t)0;
1268 nfsva.na_vattr.va_gid = (gid_t)0;
1269 nfsva.na_vattr.va_fileid = 2;
1270 nfsva.na_vattr.va_gen = 1;
1271 nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
1272 nfsva.na_vattr.va_size = 512 * 1024;
1273 }
1274 (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1);
1275 if (argp->flags & NFSMNT_NFSV3)
1276 ncl_fsinfo(nmp, *vpp, cred, td);
1277
1278 /*
1279 * Lose the lock but keep the ref.
1280 */
1281 VOP_UNLOCK(*vpp, 0);
1282 return (0);
1283 }
1284 error = EIO;
1285
1286bad:
1287 newnfs_disconnect(&nmp->nm_sockreq);
1288 crfree(nmp->nm_sockreq.nr_cred);
1289 mtx_destroy(&nmp->nm_sockreq.nr_mtx);
1290 mtx_destroy(&nmp->nm_mtx);
1291 FREE(nmp, M_NEWNFSMNT);
1292 FREE(nam, M_SONAME);
1293 return (error);
1294}
1295
1296/*
1297 * unmount system call
1298 */
1299static int
1300nfs_unmount(struct mount *mp, int mntflags)
1301{
1302 struct thread *td;
1303 struct nfsmount *nmp;
1304 int error, flags = 0, trycnt = 0;
1305
1306 td = curthread;
1307
1308 if (mntflags & MNT_FORCE)
1309 flags |= FORCECLOSE;
1310 nmp = VFSTONFS(mp);
1311 /*
1312 * Goes something like this..
1313 * - Call vflush() to clear out vnodes for this filesystem
1314 * - Close the socket
1315 * - Free up the data structures
1316 */
1317 /* In the forced case, cancel any outstanding requests. */
1318 if (mntflags & MNT_FORCE) {
1319 error = newnfs_nmcancelreqs(nmp);
1320 if (error)
1321 goto out;
1322 /* For a forced close, get rid of the renew thread now */
1323 nfscl_umount(nmp, td);
1324 }
1325 /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
1326 do {
1327 error = vflush(mp, 1, flags, td);
1328 if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30)
1329 (void) nfs_catnap(PSOCK, error, "newndm");
1330 } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30);
1331 if (error)
1332 goto out;
1333
1334 /*
1335 * We are now committed to the unmount.
1336 */
1337 if ((mntflags & MNT_FORCE) == 0)
1338 nfscl_umount(nmp, td);
1339 newnfs_disconnect(&nmp->nm_sockreq);
1340 crfree(nmp->nm_sockreq.nr_cred);
1341 FREE(nmp->nm_nam, M_SONAME);
1342
1343 mtx_destroy(&nmp->nm_sockreq.nr_mtx);
1344 mtx_destroy(&nmp->nm_mtx);
1345 FREE(nmp, M_NEWNFSMNT);
1346out:
1347 return (error);
1348}
1349
1350/*
1351 * Return root of a filesystem
1352 */
1353static int
1354nfs_root(struct mount *mp, int flags, struct vnode **vpp)
1355{
1356 struct vnode *vp;
1357 struct nfsmount *nmp;
1358 struct nfsnode *np;
1359 int error;
1360
1361 nmp = VFSTONFS(mp);
1362 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags);
1363 if (error)
1364 return error;
1365 vp = NFSTOV(np);
1366 /*
1367 * Get transfer parameters and attributes for root vnode once.
1368 */
1369 mtx_lock(&nmp->nm_mtx);
1370 if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
1371 mtx_unlock(&nmp->nm_mtx);
1372 ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread);
1373 } else
1374 mtx_unlock(&nmp->nm_mtx);
1375 if (vp->v_type == VNON)
1376 vp->v_type = VDIR;
1377 vp->v_vflag |= VV_ROOT;
1378 *vpp = vp;
1379 return (0);
1380}
1381
1382/*
1383 * Flush out the buffer cache
1384 */
1385/* ARGSUSED */
1386static int
1387nfs_sync(struct mount *mp, int waitfor)
1388{
1389 struct vnode *vp, *mvp;
1390 struct thread *td;
1391 int error, allerror = 0;
1392
1393 td = curthread;
1394
1395 /*
1396 * Force stale buffer cache information to be flushed.
1397 */
1398 MNT_ILOCK(mp);
1399loop:
1400 MNT_VNODE_FOREACH(vp, mp, mvp) {
1401 VI_LOCK(vp);
1402 MNT_IUNLOCK(mp);
1403 /* XXX Racy bv_cnt check. */
1404 if (VOP_ISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 ||
1405 waitfor == MNT_LAZY) {
1406 VI_UNLOCK(vp);
1407 MNT_ILOCK(mp);
1408 continue;
1409 }
1410 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
1411 MNT_ILOCK(mp);
1412 MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp);
1413 goto loop;
1414 }
1415 error = VOP_FSYNC(vp, waitfor, td);
1416 if (error)
1417 allerror = error;
1418 VOP_UNLOCK(vp, 0);
1419 vrele(vp);
1420
1421 MNT_ILOCK(mp);
1422 }
1423 MNT_IUNLOCK(mp);
1424 return (allerror);
1425}
1426
1427static int
1428nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req)
1429{
1430 struct nfsmount *nmp = VFSTONFS(mp);
1431 struct vfsquery vq;
1432 int error;
1433
1434 bzero(&vq, sizeof(vq));
1435 switch (op) {
1436#if 0
1437 case VFS_CTL_NOLOCKS:
1438 val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0;
1439 if (req->oldptr != NULL) {
1440 error = SYSCTL_OUT(req, &val, sizeof(val));
1441 if (error)
1442 return (error);
1443 }
1444 if (req->newptr != NULL) {
1445 error = SYSCTL_IN(req, &val, sizeof(val));
1446 if (error)
1447 return (error);
1448 if (val)
1449 nmp->nm_flag |= NFSMNT_NOLOCKS;
1450 else
1451 nmp->nm_flag &= ~NFSMNT_NOLOCKS;
1452 }
1453 break;
1454#endif
1455 case VFS_CTL_QUERY:
1456 mtx_lock(&nmp->nm_mtx);
1457 if (nmp->nm_state & NFSSTA_TIMEO)
1458 vq.vq_flags |= VQ_NOTRESP;
1459 mtx_unlock(&nmp->nm_mtx);
1460#if 0
1461 if (!(nmp->nm_flag & NFSMNT_NOLOCKS) &&
1462 (nmp->nm_state & NFSSTA_LOCKTIMEO))
1463 vq.vq_flags |= VQ_NOTRESPLOCK;
1464#endif
1465 error = SYSCTL_OUT(req, &vq, sizeof(vq));
1466 break;
1467 case VFS_CTL_TIMEO:
1468 if (req->oldptr != NULL) {
1469 error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay,
1470 sizeof(nmp->nm_tprintf_initial_delay));
1471 if (error)
1472 return (error);
1473 }
1474 if (req->newptr != NULL) {
1475 error = vfs_suser(mp, req->td);
1476 if (error)
1477 return (error);
1478 error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay,
1479 sizeof(nmp->nm_tprintf_initial_delay));
1480 if (error)
1481 return (error);
1482 if (nmp->nm_tprintf_initial_delay < 0)
1483 nmp->nm_tprintf_initial_delay = 0;
1484 }
1485 break;
1486 default:
1487 return (ENOTSUP);
1488 }
1489 return (0);
1490}
1491
1492/*
1493 * Extract the information needed by the nlm from the nfs vnode.
1494 */
1495static void
1496nfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp,
1497 struct sockaddr_storage *sp, int *is_v3p, off_t *sizep,
1498 struct timeval *timeop)
1499{
1500 struct nfsmount *nmp;
1501 struct nfsnode *np = VTONFS(vp);
1502
1503 nmp = VFSTONFS(vp->v_mount);
1504 if (fhlenp != NULL)
1505 *fhlenp = (size_t)np->n_fhp->nfh_len;
1506 if (fhp != NULL)
1507 bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len);
1508 if (sp != NULL)
1509 bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp)));
1510 if (is_v3p != NULL)
1511 *is_v3p = NFS_ISV3(vp);
1512 if (sizep != NULL)
1513 *sizep = np->n_size;
1514 if (timeop != NULL) {
1515 timeop->tv_sec = nmp->nm_timeo / NFS_HZ;
1516 timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ);
1517 }
1518}
1519