Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/fs/nfsclient/nfs_clvfsops.c
109329 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1989, 1993, 1995
5
* The Regents of the University of California. All rights reserved.
6
*
7
* This code is derived from software contributed to Berkeley by
8
* Rick Macklem at The University of Guelph.
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
* 3. Neither the name of the University nor the names of its contributors
19
* may be used to endorse or promote products derived from this software
20
* without specific prior written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
* SUCH DAMAGE.
33
*
34
* from nfs_vfsops.c 8.12 (Berkeley) 5/20/95
35
*/
36
37
#include <sys/cdefs.h>
38
#include "opt_bootp.h"
39
#include "opt_nfsroot.h"
40
#include "opt_kern_tls.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/mount.h>
54
#include <sys/proc.h>
55
#include <sys/socket.h>
56
#include <sys/socketvar.h>
57
#include <sys/sockio.h>
58
#include <sys/sysctl.h>
59
#include <sys/vnode.h>
60
#include <sys/signalvar.h>
61
62
#include <vm/vm.h>
63
#include <vm/vm_extern.h>
64
#include <vm/uma.h>
65
66
#include <net/if.h>
67
#include <net/route.h>
68
#include <net/route/route_ctl.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
77
#include <rpc/rpcsec_tls.h>
78
79
FEATURE(nfscl, "NFSv4 client");
80
81
extern int nfscl_ticks;
82
extern struct timeval nfsboottime;
83
extern int nfsrv_useacl;
84
extern int nfscl_debuglevel;
85
extern enum nfsiod_state ncl_iodwant[NFS_MAXASYNCDAEMON];
86
extern struct nfsmount *ncl_iodmount[NFS_MAXASYNCDAEMON];
87
extern struct mtx ncl_iod_mutex;
88
NFSCLSTATEMUTEX;
89
extern struct mtx nfsrv_dslock_mtx;
90
91
MALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "NFS request header");
92
MALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "NFS mount struct");
93
94
SYSCTL_DECL(_vfs_nfs);
95
static int nfs_ip_paranoia = 1;
96
SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW,
97
&nfs_ip_paranoia, 0, "");
98
static int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY;
99
SYSCTL_INT(_vfs_nfs, NFS_TPRINTF_INITIAL_DELAY,
100
downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, "");
101
/* how long between console messages "nfs server foo not responding" */
102
static int nfs_tprintf_delay = NFS_TPRINTF_DELAY;
103
SYSCTL_INT(_vfs_nfs, NFS_TPRINTF_DELAY,
104
downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, "");
105
#ifdef NFS_DEBUG
106
int nfs_debug;
107
SYSCTL_INT(_vfs_nfs, OID_AUTO, debug, CTLFLAG_RW, &nfs_debug, 0,
108
"Toggle debug flag");
109
#endif
110
111
static int nfs_mountroot(struct mount *);
112
static void nfs_sec_name(char *, int *);
113
static void nfs_decode_args(struct mount *mp, struct nfsmount *nmp,
114
struct nfs_args *argp, const char *, struct ucred *,
115
struct thread *);
116
static int mountnfs(struct nfs_args *, struct mount *,
117
struct sockaddr *, char *, u_char *, int, u_char *, int,
118
u_char *, int, struct vnode **, struct ucred *,
119
struct thread *, int, int, int, uint32_t, char *, int);
120
static void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *,
121
struct sockaddr_storage *, int *, off_t *,
122
struct timeval *);
123
static vfs_mount_t nfs_mount;
124
static vfs_cmount_t nfs_cmount;
125
static vfs_unmount_t nfs_unmount;
126
static vfs_root_t nfs_root;
127
static vfs_statfs_t nfs_statfs;
128
static vfs_sync_t nfs_sync;
129
static vfs_sysctl_t nfs_sysctl;
130
static vfs_purge_t nfs_purge;
131
132
/*
133
* nfs vfs operations.
134
*/
135
static struct vfsops nfs_vfsops = {
136
.vfs_init = ncl_init,
137
.vfs_mount = nfs_mount,
138
.vfs_cmount = nfs_cmount,
139
.vfs_root = vfs_cache_root,
140
.vfs_cachedroot = nfs_root,
141
.vfs_statfs = nfs_statfs,
142
.vfs_sync = nfs_sync,
143
.vfs_uninit = ncl_uninit,
144
.vfs_unmount = nfs_unmount,
145
.vfs_sysctl = nfs_sysctl,
146
.vfs_purge = nfs_purge,
147
};
148
/*
149
* This macro declares that the file system type is named "nfs".
150
* It also declares a module name of "nfs" and uses vfs_modevent()
151
* as the event handling function.
152
* The main module declaration is found in sys/fs/nfsclient/nfs_clport.c
153
* for "nfscl" and is needed so that a custom event handling
154
* function gets called. MODULE_DEPEND() macros are found there.
155
*/
156
VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK | VFCF_SBDRY);
157
158
MODULE_VERSION(nfs, 1);
159
160
/*
161
* This structure is now defined in sys/nfs/nfs_diskless.c so that it
162
* can be shared by both NFS clients. It is declared here so that it
163
* will be defined for kernels built without NFS_ROOT, although it
164
* isn't used in that case.
165
*/
166
#if !defined(NFS_ROOT)
167
struct nfs_diskless nfs_diskless = { { { 0 } } };
168
struct nfsv3_diskless nfsv3_diskless = { { { 0 } } };
169
int nfs_diskless_valid = 0;
170
#endif
171
172
SYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD,
173
&nfs_diskless_valid, 0,
174
"Has the diskless struct been filled correctly");
175
176
SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
177
nfsv3_diskless.root_hostnam, 0, "Path to nfs root");
178
179
SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
180
&nfsv3_diskless.root_saddr, sizeof(nfsv3_diskless.root_saddr),
181
"%Ssockaddr_in", "Diskless root nfs address");
182
183
void newnfsargs_ntoh(struct nfs_args *);
184
static int nfs_mountdiskless(char *,
185
struct sockaddr_in *, struct nfs_args *,
186
struct thread *, struct vnode **, struct mount *);
187
static void nfs_convert_diskless(void);
188
static void nfs_convert_oargs(struct nfs_args *args,
189
struct onfs_args *oargs);
190
191
int
192
newnfs_iosize(struct nfsmount *nmp)
193
{
194
int iosize, maxio;
195
196
/* First, set the upper limit for iosize */
197
if (nmp->nm_flag & NFSMNT_NFSV4) {
198
maxio = NFS_MAXBSIZE;
199
} else if (nmp->nm_flag & NFSMNT_NFSV3) {
200
if (nmp->nm_sotype == SOCK_DGRAM)
201
maxio = NFS_MAXDGRAMDATA;
202
else
203
maxio = NFS_MAXBSIZE;
204
} else {
205
maxio = NFS_V2MAXDATA;
206
}
207
if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0)
208
nmp->nm_rsize = maxio;
209
if (nmp->nm_rsize > NFS_MAXBSIZE)
210
nmp->nm_rsize = NFS_MAXBSIZE;
211
if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0)
212
nmp->nm_readdirsize = maxio;
213
if (nmp->nm_readdirsize > nmp->nm_rsize)
214
nmp->nm_readdirsize = nmp->nm_rsize;
215
if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0)
216
nmp->nm_wsize = maxio;
217
if (nmp->nm_wsize > NFS_MAXBSIZE)
218
nmp->nm_wsize = NFS_MAXBSIZE;
219
220
/*
221
* Calculate the size used for io buffers. Use the larger
222
* of the two sizes to minimise nfs requests but make sure
223
* that it is at least one VM page to avoid wasting buffer
224
* space. It must also be at least NFS_DIRBLKSIZ, since
225
* that is the buffer size used for directories.
226
*/
227
iosize = imax(nmp->nm_rsize, nmp->nm_wsize);
228
iosize = imax(iosize, PAGE_SIZE);
229
iosize = imax(iosize, NFS_DIRBLKSIZ);
230
nmp->nm_mountp->mnt_stat.f_iosize = iosize;
231
return (iosize);
232
}
233
234
static void
235
nfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs)
236
{
237
238
args->version = NFS_ARGSVERSION;
239
args->addr = oargs->addr;
240
args->addrlen = oargs->addrlen;
241
args->sotype = oargs->sotype;
242
args->proto = oargs->proto;
243
args->fh = oargs->fh;
244
args->fhsize = oargs->fhsize;
245
args->flags = oargs->flags;
246
args->wsize = oargs->wsize;
247
args->rsize = oargs->rsize;
248
args->readdirsize = oargs->readdirsize;
249
args->timeo = oargs->timeo;
250
args->retrans = oargs->retrans;
251
args->readahead = oargs->readahead;
252
args->hostname = oargs->hostname;
253
}
254
255
static void
256
nfs_convert_diskless(void)
257
{
258
259
bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
260
sizeof(struct ifaliasreq));
261
bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
262
sizeof(struct sockaddr_in));
263
nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args);
264
if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) {
265
nfsv3_diskless.root_fhsize = NFSX_MYFH;
266
bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_MYFH);
267
} else {
268
nfsv3_diskless.root_fhsize = NFSX_V2FH;
269
bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH);
270
}
271
bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
272
sizeof(struct sockaddr_in));
273
bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN);
274
nfsv3_diskless.root_time = nfs_diskless.root_time;
275
bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam,
276
MAXHOSTNAMELEN);
277
nfs_diskless_valid = 3;
278
}
279
280
/*
281
* nfs statfs call
282
*/
283
static int
284
nfs_statfs(struct mount *mp, struct statfs *sbp)
285
{
286
struct vnode *vp;
287
struct thread *td;
288
struct nfsmount *nmp = VFSTONFS(mp);
289
struct nfsvattr nfsva;
290
struct nfsfsinfo fs;
291
struct nfsstatfs sb;
292
int error = 0, attrflag, gotfsinfo = 0, ret;
293
struct nfsnode *np;
294
char *fakefh;
295
uint32_t clone_blksize;
296
297
td = curthread;
298
clone_blksize = 0;
299
300
error = vfs_busy(mp, MBF_NOWAIT);
301
if (error)
302
return (error);
303
if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0) {
304
if (nmp->nm_fhsize == 0) {
305
error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
306
td->td_ucred, td);
307
if (error != 0) {
308
/*
309
* We cannot do anything yet. Hopefully what
310
* is in mnt_stat is sufficient.
311
*/
312
if (sbp != &mp->mnt_stat)
313
*sbp = mp->mnt_stat;
314
strncpy(&sbp->f_fstypename[0],
315
mp->mnt_vfc->vfc_name, MFSNAMELEN);
316
vfs_unbusy(mp);
317
return (0);
318
}
319
}
320
fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK | M_ZERO);
321
error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np, LK_EXCLUSIVE);
322
free(fakefh, M_TEMP);
323
} else {
324
error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
325
LK_EXCLUSIVE);
326
}
327
if (error) {
328
vfs_unbusy(mp);
329
return (error);
330
}
331
vp = NFSTOV(np);
332
mtx_lock(&nmp->nm_mtx);
333
if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
334
mtx_unlock(&nmp->nm_mtx);
335
error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva,
336
&attrflag);
337
if (!error)
338
gotfsinfo = 1;
339
} else
340
mtx_unlock(&nmp->nm_mtx);
341
if (!error)
342
error = nfsrpc_statfs(vp, &sb, &fs, NULL, &clone_blksize,
343
td->td_ucred, td, &nfsva, &attrflag);
344
if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
345
error == NFSERR_WRONGSEC) {
346
/* Cannot get new stats, so return what is in mnt_stat. */
347
if (sbp != &mp->mnt_stat)
348
*sbp = mp->mnt_stat;
349
strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name,
350
MFSNAMELEN);
351
vput(vp);
352
vfs_unbusy(mp);
353
return (0);
354
}
355
if (error != 0)
356
NFSCL_DEBUG(2, "statfs=%d\n", error);
357
if (attrflag == 0) {
358
ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
359
td->td_ucred, td, &nfsva, NULL, NULL);
360
if (ret) {
361
/*
362
* Just set default values to get things going.
363
*/
364
NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
365
nfsva.na_vattr.va_type = VDIR;
366
nfsva.na_vattr.va_mode = 0777;
367
nfsva.na_vattr.va_nlink = 100;
368
nfsva.na_vattr.va_uid = (uid_t)0;
369
nfsva.na_vattr.va_gid = (gid_t)0;
370
nfsva.na_vattr.va_fileid = 2;
371
nfsva.na_vattr.va_gen = 1;
372
nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
373
nfsva.na_vattr.va_size = 512 * 1024;
374
}
375
}
376
(void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1);
377
if (!error) {
378
mtx_lock(&nmp->nm_mtx);
379
if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4))
380
nfscl_loadfsinfo(nmp, &fs, clone_blksize);
381
nfscl_loadsbinfo(nmp, &sb, sbp);
382
sbp->f_iosize = newnfs_iosize(nmp);
383
mtx_unlock(&nmp->nm_mtx);
384
if (sbp != &mp->mnt_stat) {
385
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
386
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
387
}
388
strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN);
389
} else if (NFS_ISV4(vp)) {
390
error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
391
}
392
vput(vp);
393
vfs_unbusy(mp);
394
return (error);
395
}
396
397
/*
398
* nfs version 3 fsinfo rpc call
399
*/
400
int
401
ncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred,
402
struct thread *td)
403
{
404
struct nfsfsinfo fs;
405
struct nfsvattr nfsva;
406
int error, attrflag;
407
408
error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag);
409
if (!error) {
410
if (attrflag)
411
(void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1);
412
mtx_lock(&nmp->nm_mtx);
413
nfscl_loadfsinfo(nmp, &fs, 0);
414
mtx_unlock(&nmp->nm_mtx);
415
}
416
return (error);
417
}
418
419
/*
420
* Mount a remote root fs via nfs. This depends on the info in the
421
* nfs_diskless structure that has been filled in properly by some primary
422
* bootstrap.
423
* It goes something like this:
424
* - do enough of "ifconfig" by calling ifioctl() so that the system
425
* can talk to the server
426
* - If nfs_diskless.mygateway is filled in, use that address as
427
* a default gateway.
428
* - build the rootfs mount point and call mountnfs() to do the rest.
429
*
430
* It is assumed to be safe to read, modify, and write the nfsv3_diskless
431
* structure, as well as other global NFS client variables here, as
432
* nfs_mountroot() will be called once in the boot before any other NFS
433
* client activity occurs.
434
*/
435
static int
436
nfs_mountroot(struct mount *mp)
437
{
438
struct thread *td = curthread;
439
struct nfsv3_diskless *nd = &nfsv3_diskless;
440
struct socket *so;
441
struct vnode *vp;
442
struct ifreq ir;
443
int error;
444
u_long l;
445
char buf[128];
446
char *cp;
447
448
#if defined(BOOTP_NFSROOT) && defined(BOOTP)
449
bootpc_init(); /* use bootp to get nfs_diskless filled in */
450
#elif defined(NFS_ROOT)
451
nfs_setup_diskless();
452
#endif
453
454
if (nfs_diskless_valid == 0)
455
return (-1);
456
if (nfs_diskless_valid == 1)
457
nfs_convert_diskless();
458
459
/*
460
* Do enough of ifconfig(8) so that the critical net interface can
461
* talk to the server.
462
*/
463
error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0,
464
td->td_ucred, td);
465
if (error)
466
panic("nfs_mountroot: socreate(%04x): %d",
467
nd->myif.ifra_addr.sa_family, error);
468
469
#if 0 /* XXX Bad idea */
470
/*
471
* We might not have been told the right interface, so we pass
472
* over the first ten interfaces of the same kind, until we get
473
* one of them configured.
474
*/
475
476
for (i = strlen(nd->myif.ifra_name) - 1;
477
nd->myif.ifra_name[i] >= '0' &&
478
nd->myif.ifra_name[i] <= '9';
479
nd->myif.ifra_name[i] ++) {
480
error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
481
if(!error)
482
break;
483
}
484
#endif
485
error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
486
if (error)
487
panic("nfs_mountroot: SIOCAIFADDR: %d", error);
488
if ((cp = kern_getenv("boot.netif.mtu")) != NULL) {
489
ir.ifr_mtu = strtol(cp, NULL, 10);
490
bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ);
491
freeenv(cp);
492
error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td);
493
if (error)
494
printf("nfs_mountroot: SIOCSIFMTU: %d", error);
495
}
496
soclose(so);
497
498
/*
499
* If the gateway field is filled in, set it as the default route.
500
* Note that pxeboot will set a default route of 0 if the route
501
* is not set by the DHCP server. Check also for a value of 0
502
* to avoid panicking inappropriately in that situation.
503
*/
504
if (nd->mygateway.sin_len != 0 &&
505
nd->mygateway.sin_addr.s_addr != 0) {
506
struct sockaddr_in mask, sin;
507
struct epoch_tracker et;
508
struct rt_addrinfo info;
509
struct rib_cmd_info rc;
510
511
bzero((caddr_t)&mask, sizeof(mask));
512
sin = mask;
513
sin.sin_family = AF_INET;
514
sin.sin_len = sizeof(sin);
515
/* XXX MRT use table 0 for this sort of thing */
516
NET_EPOCH_ENTER(et);
517
CURVNET_SET(TD_TO_VNET(td));
518
519
bzero((caddr_t)&info, sizeof(info));
520
info.rti_flags = RTF_UP | RTF_GATEWAY;
521
info.rti_info[RTAX_DST] = (struct sockaddr *)&sin;
522
info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&nd->mygateway;
523
info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask;
524
525
error = rib_action(RT_DEFAULT_FIB, RTM_ADD, &info, &rc);
526
CURVNET_RESTORE();
527
NET_EPOCH_EXIT(et);
528
if (error)
529
panic("nfs_mountroot: RTM_ADD: %d", error);
530
}
531
532
/*
533
* Create the rootfs mount point.
534
*/
535
nd->root_args.fh = nd->root_fh;
536
nd->root_args.fhsize = nd->root_fhsize;
537
l = ntohl(nd->root_saddr.sin_addr.s_addr);
538
snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s",
539
(l >> 24) & 0xff, (l >> 16) & 0xff,
540
(l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam);
541
printf("NFS ROOT: %s\n", buf);
542
nd->root_args.hostname = buf;
543
if ((error = nfs_mountdiskless(buf,
544
&nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) {
545
return (error);
546
}
547
548
/*
549
* This is not really an nfs issue, but it is much easier to
550
* set hostname here and then let the "/etc/rc.xxx" files
551
* mount the right /var based upon its preset value.
552
*/
553
mtx_lock(&prison0.pr_mtx);
554
strlcpy(prison0.pr_hostname, nd->my_hostnam,
555
sizeof(prison0.pr_hostname));
556
mtx_unlock(&prison0.pr_mtx);
557
inittodr(ntohl(nd->root_time));
558
return (0);
559
}
560
561
/*
562
* Internal version of mount system call for diskless setup.
563
*/
564
static int
565
nfs_mountdiskless(char *path,
566
struct sockaddr_in *sin, struct nfs_args *args, struct thread *td,
567
struct vnode **vpp, struct mount *mp)
568
{
569
struct sockaddr *nam;
570
int dirlen, error;
571
char *dirpath;
572
573
/*
574
* Find the directory path in "path", which also has the server's
575
* name/ip address in it.
576
*/
577
dirpath = strchr(path, ':');
578
if (dirpath != NULL)
579
dirlen = strlen(++dirpath);
580
else
581
dirlen = 0;
582
nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
583
if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen,
584
NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO,
585
NFS_DEFAULT_NEGNAMETIMEO, 0, 0, NULL, 0)) != 0) {
586
printf("nfs_mountroot: mount %s on /: %d\n", path, error);
587
return (error);
588
}
589
return (0);
590
}
591
592
static void
593
nfs_sec_name(char *sec, int *flagsp)
594
{
595
if (!strcmp(sec, "krb5"))
596
*flagsp |= NFSMNT_KERB;
597
else if (!strcmp(sec, "krb5i"))
598
*flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY);
599
else if (!strcmp(sec, "krb5p"))
600
*flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY);
601
}
602
603
static void
604
nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp,
605
const char *hostname, struct ucred *cred, struct thread *td)
606
{
607
int adjsock;
608
char *p;
609
610
/*
611
* Set read-only flag if requested; otherwise, clear it if this is
612
* an update. If this is not an update, then either the read-only
613
* flag is already clear, or this is a root mount and it was set
614
* intentionally at some previous point.
615
*/
616
if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) {
617
MNT_ILOCK(mp);
618
mp->mnt_flag |= MNT_RDONLY;
619
MNT_IUNLOCK(mp);
620
} else if (mp->mnt_flag & MNT_UPDATE) {
621
MNT_ILOCK(mp);
622
mp->mnt_flag &= ~MNT_RDONLY;
623
MNT_IUNLOCK(mp);
624
}
625
626
/*
627
* Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes
628
* no sense in that context. Also, set up appropriate retransmit
629
* and soft timeout behavior.
630
*/
631
if (argp->sotype == SOCK_STREAM) {
632
nmp->nm_flag &= ~NFSMNT_NOCONN;
633
nmp->nm_timeo = NFS_MAXTIMEO;
634
if ((argp->flags & NFSMNT_NFSV4) != 0)
635
nmp->nm_retry = INT_MAX;
636
else
637
nmp->nm_retry = NFS_RETRANS_TCP;
638
}
639
640
/* Also clear RDIRPLUS if NFSv2, it crashes some servers */
641
if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
642
argp->flags &= ~NFSMNT_RDIRPLUS;
643
nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
644
}
645
646
/* Clear ONEOPENOWN for NFSv2, 3 and 4.0. */
647
if (nmp->nm_minorvers == 0) {
648
argp->flags &= ~NFSMNT_ONEOPENOWN;
649
nmp->nm_flag &= ~NFSMNT_ONEOPENOWN;
650
}
651
652
/* Re-bind if rsrvd port requested and wasn't on one */
653
adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
654
&& (argp->flags & NFSMNT_RESVPORT);
655
/* Also re-bind if we're switching to/from a connected UDP socket */
656
adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) !=
657
(argp->flags & NFSMNT_NOCONN));
658
659
/* Update flags atomically. Don't change the lock bits. */
660
nmp->nm_flag = argp->flags | nmp->nm_flag;
661
662
if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
663
nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
664
if (nmp->nm_timeo < NFS_MINTIMEO)
665
nmp->nm_timeo = NFS_MINTIMEO;
666
else if (nmp->nm_timeo > NFS_MAXTIMEO)
667
nmp->nm_timeo = NFS_MAXTIMEO;
668
}
669
670
if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
671
nmp->nm_retry = argp->retrans;
672
if (nmp->nm_retry > NFS_MAXREXMIT)
673
nmp->nm_retry = NFS_MAXREXMIT;
674
}
675
676
if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
677
nmp->nm_wsize = argp->wsize;
678
/*
679
* Clip at the power of 2 below the size. There is an
680
* issue (not isolated) that causes intermittent page
681
* faults if this is not done.
682
*/
683
if (nmp->nm_wsize > NFS_FABLKSIZE)
684
nmp->nm_wsize = 1 << (fls(nmp->nm_wsize) - 1);
685
else
686
nmp->nm_wsize = NFS_FABLKSIZE;
687
}
688
689
if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
690
nmp->nm_rsize = argp->rsize;
691
/*
692
* Clip at the power of 2 below the size. There is an
693
* issue (not isolated) that causes intermittent page
694
* faults if this is not done.
695
*/
696
if (nmp->nm_rsize > NFS_FABLKSIZE)
697
nmp->nm_rsize = 1 << (fls(nmp->nm_rsize) - 1);
698
else
699
nmp->nm_rsize = NFS_FABLKSIZE;
700
}
701
702
if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
703
nmp->nm_readdirsize = argp->readdirsize;
704
}
705
706
if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0)
707
nmp->nm_acregmin = argp->acregmin;
708
else
709
nmp->nm_acregmin = NFS_MINATTRTIMO;
710
if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0)
711
nmp->nm_acregmax = argp->acregmax;
712
else
713
nmp->nm_acregmax = NFS_MAXATTRTIMO;
714
if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0)
715
nmp->nm_acdirmin = argp->acdirmin;
716
else
717
nmp->nm_acdirmin = NFS_MINDIRATTRTIMO;
718
if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0)
719
nmp->nm_acdirmax = argp->acdirmax;
720
else
721
nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO;
722
if (nmp->nm_acdirmin > nmp->nm_acdirmax)
723
nmp->nm_acdirmin = nmp->nm_acdirmax;
724
if (nmp->nm_acregmin > nmp->nm_acregmax)
725
nmp->nm_acregmin = nmp->nm_acregmax;
726
727
if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) {
728
if (argp->readahead <= NFS_MAXRAHEAD)
729
nmp->nm_readahead = argp->readahead;
730
else
731
nmp->nm_readahead = NFS_MAXRAHEAD;
732
}
733
if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) {
734
if (argp->wcommitsize < nmp->nm_wsize)
735
nmp->nm_wcommitsize = nmp->nm_wsize;
736
else
737
nmp->nm_wcommitsize = argp->wcommitsize;
738
}
739
740
adjsock |= ((nmp->nm_sotype != argp->sotype) ||
741
(nmp->nm_soproto != argp->proto));
742
743
if (nmp->nm_client != NULL && adjsock) {
744
int haslock = 0, error = 0;
745
746
if (nmp->nm_sotype == SOCK_STREAM) {
747
error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock);
748
if (!error)
749
haslock = 1;
750
}
751
if (!error) {
752
newnfs_disconnect(nmp, &nmp->nm_sockreq);
753
if (haslock)
754
newnfs_sndunlock(&nmp->nm_sockreq.nr_lock);
755
nmp->nm_sotype = argp->sotype;
756
nmp->nm_soproto = argp->proto;
757
if (nmp->nm_sotype == SOCK_DGRAM)
758
while (newnfs_connect(nmp, &nmp->nm_sockreq,
759
cred, td, 0, false, &nmp->nm_sockreq.nr_client)) {
760
printf("newnfs_args: retrying connect\n");
761
(void) nfs_catnap(PSOCK, 0, "nfscon");
762
}
763
}
764
} else {
765
nmp->nm_sotype = argp->sotype;
766
nmp->nm_soproto = argp->proto;
767
}
768
769
if (hostname != NULL) {
770
strlcpy(nmp->nm_hostname, hostname,
771
sizeof(nmp->nm_hostname));
772
p = strchr(nmp->nm_hostname, ':');
773
if (p != NULL)
774
*p = '\0';
775
}
776
}
777
778
static const char *nfs_opts[] = { "from", "nfs_args",
779
"noac", "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union",
780
"noclusterr", "noclusterw", "multilabel", "acls", "force", "update",
781
"async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus",
782
"readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize",
783
"retrans", "actimeo", "acregmin", "acregmax", "acdirmin", "acdirmax",
784
"resvport", "readahead", "hostname", "timeo", "timeout", "addr", "fh",
785
"nfsv3", "sec", "principal", "nfsv4", "gssname", "allgssname", "dirpath",
786
"minorversion", "nametimeo", "negnametimeo", "nocto", "noncontigwr",
787
"pnfs", "wcommitsize", "oneopenown", "tls", "tlscertname", "nconnect",
788
"syskrb5", NULL };
789
790
/*
791
* Parse the "from" mountarg, passed by the generic mount(8) program
792
* or the mountroot code. This is used when rerooting into NFS.
793
*
794
* Note that the "hostname" is actually a "hostname:/share/path" string.
795
*/
796
static int
797
nfs_mount_parse_from(struct vfsoptlist *opts, char **hostnamep,
798
struct sockaddr_in **sinp, char *dirpath, size_t dirpathsize, int *dirlenp)
799
{
800
char *nam, *delimp, *hostp, *spec;
801
int error, have_bracket = 0, offset, rv, speclen;
802
struct sockaddr_in *sin;
803
size_t len;
804
805
error = vfs_getopt(opts, "from", (void **)&spec, &speclen);
806
if (error != 0)
807
return (error);
808
nam = malloc(MNAMELEN + 1, M_TEMP, M_WAITOK);
809
810
/*
811
* This part comes from sbin/mount_nfs/mount_nfs.c:getnfsargs().
812
*/
813
if (*spec == '[' && (delimp = strchr(spec + 1, ']')) != NULL &&
814
*(delimp + 1) == ':') {
815
hostp = spec + 1;
816
spec = delimp + 2;
817
have_bracket = 1;
818
} else if ((delimp = strrchr(spec, ':')) != NULL) {
819
hostp = spec;
820
spec = delimp + 1;
821
} else if ((delimp = strrchr(spec, '@')) != NULL) {
822
printf("%s: path@server syntax is deprecated, "
823
"use server:path\n", __func__);
824
hostp = delimp + 1;
825
} else {
826
printf("%s: no <host>:<dirpath> nfs-name\n", __func__);
827
free(nam, M_TEMP);
828
return (EINVAL);
829
}
830
*delimp = '\0';
831
832
/*
833
* If there has been a trailing slash at mounttime it seems
834
* that some mountd implementations fail to remove the mount
835
* entries from their mountlist while unmounting.
836
*/
837
for (speclen = strlen(spec);
838
speclen > 1 && spec[speclen - 1] == '/';
839
speclen--)
840
spec[speclen - 1] = '\0';
841
if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) {
842
printf("%s: %s:%s: name too long", __func__, hostp, spec);
843
free(nam, M_TEMP);
844
return (EINVAL);
845
}
846
/* Make both '@' and ':' notations equal */
847
if (*hostp != '\0') {
848
len = strlen(hostp);
849
offset = 0;
850
if (have_bracket)
851
nam[offset++] = '[';
852
memmove(nam + offset, hostp, len);
853
if (have_bracket)
854
nam[len + offset++] = ']';
855
nam[len + offset++] = ':';
856
memmove(nam + len + offset, spec, speclen);
857
nam[len + speclen + offset] = '\0';
858
} else
859
nam[0] = '\0';
860
861
/*
862
* XXX: IPv6
863
*/
864
sin = malloc(sizeof(*sin), M_SONAME, M_WAITOK);
865
rv = inet_pton(AF_INET, hostp, &sin->sin_addr);
866
if (rv != 1) {
867
printf("%s: cannot parse '%s', inet_pton() returned %d\n",
868
__func__, hostp, rv);
869
free(nam, M_TEMP);
870
free(sin, M_SONAME);
871
return (EINVAL);
872
}
873
874
sin->sin_len = sizeof(*sin);
875
sin->sin_family = AF_INET;
876
/*
877
* XXX: hardcoded port number.
878
*/
879
sin->sin_port = htons(2049);
880
881
*hostnamep = strdup(nam, M_NEWNFSMNT);
882
*sinp = sin;
883
strlcpy(dirpath, spec, dirpathsize);
884
*dirlenp = strlen(dirpath);
885
886
free(nam, M_TEMP);
887
return (0);
888
}
889
890
/*
891
* VFS Operations.
892
*
893
* mount system call
894
* It seems a bit dumb to copyinstr() the host and path here and then
895
* bcopy() them in mountnfs(), but I wanted to detect errors before
896
* doing the getsockaddr() call because getsockaddr() allocates an mbuf and
897
* an error after that means that I have to release the mbuf.
898
*/
899
/* ARGSUSED */
900
static int
901
nfs_mount(struct mount *mp)
902
{
903
struct nfs_args args = {
904
.version = NFS_ARGSVERSION,
905
.addr = NULL,
906
.addrlen = sizeof (struct sockaddr_in),
907
.sotype = SOCK_STREAM,
908
.proto = 0,
909
.fh = NULL,
910
.fhsize = 0,
911
.flags = NFSMNT_RESVPORT,
912
.wsize = NFS_WSIZE,
913
.rsize = NFS_RSIZE,
914
.readdirsize = NFS_READDIRSIZE,
915
.timeo = 10,
916
.retrans = NFS_RETRANS,
917
.readahead = NFS_DEFRAHEAD,
918
.wcommitsize = 0, /* was: NQ_DEFLEASE */
919
.hostname = NULL,
920
.acregmin = NFS_MINATTRTIMO,
921
.acregmax = NFS_MAXATTRTIMO,
922
.acdirmin = NFS_MINDIRATTRTIMO,
923
.acdirmax = NFS_MAXDIRATTRTIMO,
924
};
925
int error = 0, ret, len;
926
struct sockaddr *nam = NULL;
927
struct vnode *vp;
928
struct thread *td;
929
char *hst;
930
u_char nfh[NFSX_FHMAX], krbname[100], *dirpath, srvkrbname[100];
931
char *cp, *opt, *name, *secname, *tlscertname;
932
int nametimeo = NFS_DEFAULT_NAMETIMEO;
933
int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
934
int minvers = -1;
935
int dirlen, has_nfs_args_opt, has_nfs_from_opt,
936
krbnamelen, srvkrbnamelen;
937
size_t hstlen;
938
uint32_t newflag;
939
int aconn = 0;
940
941
has_nfs_args_opt = 0;
942
has_nfs_from_opt = 0;
943
newflag = 0;
944
tlscertname = NULL;
945
hst = malloc(MNAMELEN, M_TEMP, M_WAITOK);
946
dirpath = malloc(MNAMELEN, M_TEMP, M_WAITOK);
947
if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
948
error = EINVAL;
949
goto out;
950
}
951
952
td = curthread;
953
if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS &&
954
nfs_diskless_valid != 0) {
955
error = nfs_mountroot(mp);
956
goto out;
957
}
958
959
nfscl_init();
960
961
/*
962
* The old mount_nfs program passed the struct nfs_args
963
* from userspace to kernel. The new mount_nfs program
964
* passes string options via nmount() from userspace to kernel
965
* and we populate the struct nfs_args in the kernel.
966
*/
967
if (vfs_getopt(mp->mnt_optnew, "nfs_args", NULL, NULL) == 0) {
968
error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args,
969
sizeof(args));
970
if (error != 0)
971
goto out;
972
973
if (args.version != NFS_ARGSVERSION) {
974
error = EPROGMISMATCH;
975
goto out;
976
}
977
has_nfs_args_opt = 1;
978
}
979
980
/* Handle the new style options. */
981
if (vfs_getopt(mp->mnt_optnew, "noac", NULL, NULL) == 0) {
982
args.acdirmin = args.acdirmax =
983
args.acregmin = args.acregmax = 0;
984
args.flags |= NFSMNT_ACDIRMIN | NFSMNT_ACDIRMAX |
985
NFSMNT_ACREGMIN | NFSMNT_ACREGMAX;
986
}
987
if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0)
988
args.flags |= NFSMNT_NOCONN;
989
if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0)
990
args.flags &= ~NFSMNT_NOCONN;
991
if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0)
992
args.flags |= NFSMNT_NOLOCKD;
993
if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0)
994
args.flags &= ~NFSMNT_NOLOCKD;
995
if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0)
996
args.flags |= NFSMNT_INT;
997
if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0)
998
args.flags |= NFSMNT_RDIRPLUS;
999
if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0)
1000
args.flags |= NFSMNT_RESVPORT;
1001
if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0)
1002
args.flags &= ~NFSMNT_RESVPORT;
1003
if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0)
1004
args.flags |= NFSMNT_SOFT;
1005
if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0)
1006
args.flags &= ~NFSMNT_SOFT;
1007
if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0)
1008
args.sotype = SOCK_DGRAM;
1009
if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0)
1010
args.sotype = SOCK_DGRAM;
1011
if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0)
1012
args.sotype = SOCK_STREAM;
1013
if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0)
1014
args.flags |= NFSMNT_NFSV3;
1015
if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) {
1016
args.flags |= NFSMNT_NFSV4;
1017
args.sotype = SOCK_STREAM;
1018
}
1019
if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0)
1020
args.flags |= NFSMNT_ALLGSSNAME;
1021
if (vfs_getopt(mp->mnt_optnew, "nocto", NULL, NULL) == 0)
1022
args.flags |= NFSMNT_NOCTO;
1023
if (vfs_getopt(mp->mnt_optnew, "noncontigwr", NULL, NULL) == 0)
1024
args.flags |= NFSMNT_NONCONTIGWR;
1025
if (vfs_getopt(mp->mnt_optnew, "pnfs", NULL, NULL) == 0)
1026
args.flags |= NFSMNT_PNFS;
1027
if (vfs_getopt(mp->mnt_optnew, "oneopenown", NULL, NULL) == 0)
1028
args.flags |= NFSMNT_ONEOPENOWN;
1029
if (vfs_getopt(mp->mnt_optnew, "tls", NULL, NULL) == 0)
1030
newflag |= NFSMNT_TLS;
1031
if (vfs_getopt(mp->mnt_optnew, "tlscertname", (void **)&opt, &len) ==
1032
0) {
1033
/*
1034
* tlscertname with "key.pem" appended to it forms a file
1035
* name. As such, the maximum allowable strlen(tlscertname) is
1036
* NAME_MAX - 7. However, "len" includes the nul termination
1037
* byte so it can be up to NAME_MAX - 6.
1038
*/
1039
if (opt == NULL || len <= 1 || len > NAME_MAX - 6) {
1040
vfs_mount_error(mp, "invalid tlscertname");
1041
error = EINVAL;
1042
goto out;
1043
}
1044
tlscertname = malloc(len, M_NEWNFSMNT, M_WAITOK);
1045
strlcpy(tlscertname, opt, len);
1046
}
1047
if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) {
1048
if (opt == NULL) {
1049
vfs_mount_error(mp, "illegal readdirsize");
1050
error = EINVAL;
1051
goto out;
1052
}
1053
ret = sscanf(opt, "%d", &args.readdirsize);
1054
if (ret != 1 || args.readdirsize <= 0) {
1055
vfs_mount_error(mp, "illegal readdirsize: %s",
1056
opt);
1057
error = EINVAL;
1058
goto out;
1059
}
1060
args.flags |= NFSMNT_READDIRSIZE;
1061
}
1062
if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) {
1063
if (opt == NULL) {
1064
vfs_mount_error(mp, "illegal readahead");
1065
error = EINVAL;
1066
goto out;
1067
}
1068
ret = sscanf(opt, "%d", &args.readahead);
1069
if (ret != 1 || args.readahead <= 0) {
1070
vfs_mount_error(mp, "illegal readahead: %s",
1071
opt);
1072
error = EINVAL;
1073
goto out;
1074
}
1075
args.flags |= NFSMNT_READAHEAD;
1076
}
1077
if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) {
1078
if (opt == NULL) {
1079
vfs_mount_error(mp, "illegal wsize");
1080
error = EINVAL;
1081
goto out;
1082
}
1083
ret = sscanf(opt, "%d", &args.wsize);
1084
if (ret != 1 || args.wsize <= 0) {
1085
vfs_mount_error(mp, "illegal wsize: %s",
1086
opt);
1087
error = EINVAL;
1088
goto out;
1089
}
1090
args.flags |= NFSMNT_WSIZE;
1091
}
1092
if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) {
1093
if (opt == NULL) {
1094
vfs_mount_error(mp, "illegal rsize");
1095
error = EINVAL;
1096
goto out;
1097
}
1098
ret = sscanf(opt, "%d", &args.rsize);
1099
if (ret != 1 || args.rsize <= 0) {
1100
vfs_mount_error(mp, "illegal wsize: %s",
1101
opt);
1102
error = EINVAL;
1103
goto out;
1104
}
1105
args.flags |= NFSMNT_RSIZE;
1106
}
1107
if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) {
1108
if (opt == NULL) {
1109
vfs_mount_error(mp, "illegal retrans");
1110
error = EINVAL;
1111
goto out;
1112
}
1113
ret = sscanf(opt, "%d", &args.retrans);
1114
if (ret != 1 || args.retrans <= 0) {
1115
vfs_mount_error(mp, "illegal retrans: %s",
1116
opt);
1117
error = EINVAL;
1118
goto out;
1119
}
1120
args.flags |= NFSMNT_RETRANS;
1121
}
1122
if (vfs_getopt(mp->mnt_optnew, "actimeo", (void **)&opt, NULL) == 0) {
1123
ret = sscanf(opt, "%d", &args.acregmin);
1124
if (ret != 1 || args.acregmin < 0) {
1125
vfs_mount_error(mp, "illegal actimeo: %s",
1126
opt);
1127
error = EINVAL;
1128
goto out;
1129
}
1130
args.acdirmin = args.acdirmax = args.acregmax = args.acregmin;
1131
args.flags |= NFSMNT_ACDIRMIN | NFSMNT_ACDIRMAX |
1132
NFSMNT_ACREGMIN | NFSMNT_ACREGMAX;
1133
}
1134
if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) {
1135
ret = sscanf(opt, "%d", &args.acregmin);
1136
if (ret != 1 || args.acregmin < 0) {
1137
vfs_mount_error(mp, "illegal acregmin: %s",
1138
opt);
1139
error = EINVAL;
1140
goto out;
1141
}
1142
args.flags |= NFSMNT_ACREGMIN;
1143
}
1144
if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) {
1145
ret = sscanf(opt, "%d", &args.acregmax);
1146
if (ret != 1 || args.acregmax < 0) {
1147
vfs_mount_error(mp, "illegal acregmax: %s",
1148
opt);
1149
error = EINVAL;
1150
goto out;
1151
}
1152
args.flags |= NFSMNT_ACREGMAX;
1153
}
1154
if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) {
1155
ret = sscanf(opt, "%d", &args.acdirmin);
1156
if (ret != 1 || args.acdirmin < 0) {
1157
vfs_mount_error(mp, "illegal acdirmin: %s",
1158
opt);
1159
error = EINVAL;
1160
goto out;
1161
}
1162
args.flags |= NFSMNT_ACDIRMIN;
1163
}
1164
if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) {
1165
ret = sscanf(opt, "%d", &args.acdirmax);
1166
if (ret != 1 || args.acdirmax < 0) {
1167
vfs_mount_error(mp, "illegal acdirmax: %s",
1168
opt);
1169
error = EINVAL;
1170
goto out;
1171
}
1172
args.flags |= NFSMNT_ACDIRMAX;
1173
}
1174
if (vfs_getopt(mp->mnt_optnew, "wcommitsize", (void **)&opt, NULL) == 0) {
1175
ret = sscanf(opt, "%d", &args.wcommitsize);
1176
if (ret != 1 || args.wcommitsize < 0) {
1177
vfs_mount_error(mp, "illegal wcommitsize: %s", opt);
1178
error = EINVAL;
1179
goto out;
1180
}
1181
args.flags |= NFSMNT_WCOMMITSIZE;
1182
}
1183
if (vfs_getopt(mp->mnt_optnew, "timeo", (void **)&opt, NULL) == 0) {
1184
ret = sscanf(opt, "%d", &args.timeo);
1185
if (ret != 1 || args.timeo <= 0) {
1186
vfs_mount_error(mp, "illegal timeo: %s",
1187
opt);
1188
error = EINVAL;
1189
goto out;
1190
}
1191
args.flags |= NFSMNT_TIMEO;
1192
}
1193
if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) {
1194
ret = sscanf(opt, "%d", &args.timeo);
1195
if (ret != 1 || args.timeo <= 0) {
1196
vfs_mount_error(mp, "illegal timeout: %s",
1197
opt);
1198
error = EINVAL;
1199
goto out;
1200
}
1201
args.flags |= NFSMNT_TIMEO;
1202
}
1203
if (vfs_getopt(mp->mnt_optnew, "nametimeo", (void **)&opt, NULL) == 0) {
1204
ret = sscanf(opt, "%d", &nametimeo);
1205
if (ret != 1 || nametimeo < 0) {
1206
vfs_mount_error(mp, "illegal nametimeo: %s", opt);
1207
error = EINVAL;
1208
goto out;
1209
}
1210
}
1211
if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
1212
== 0) {
1213
ret = sscanf(opt, "%d", &negnametimeo);
1214
if (ret != 1 || negnametimeo < 0) {
1215
vfs_mount_error(mp, "illegal negnametimeo: %s",
1216
opt);
1217
error = EINVAL;
1218
goto out;
1219
}
1220
}
1221
if (vfs_getopt(mp->mnt_optnew, "minorversion", (void **)&opt, NULL) ==
1222
0) {
1223
ret = sscanf(opt, "%d", &minvers);
1224
if (ret != 1 || minvers < 0 || minvers > 2 ||
1225
(args.flags & NFSMNT_NFSV4) == 0) {
1226
vfs_mount_error(mp, "illegal minorversion: %s", opt);
1227
error = EINVAL;
1228
goto out;
1229
}
1230
}
1231
if (vfs_getopt(mp->mnt_optnew, "nconnect", (void **)&opt, NULL) ==
1232
0) {
1233
ret = sscanf(opt, "%d", &aconn);
1234
if (ret != 1 || aconn < 1 || aconn > NFS_MAXNCONN) {
1235
vfs_mount_error(mp, "illegal nconnect: %s", opt);
1236
error = EINVAL;
1237
goto out;
1238
}
1239
/*
1240
* Setting nconnect=1 is a no-op, allowed so that
1241
* the option can be used in a Linux compatible way.
1242
*/
1243
aconn--;
1244
}
1245
if (vfs_getopt(mp->mnt_optnew, "syskrb5", NULL, NULL) == 0)
1246
newflag |= NFSMNT_SYSKRB5;
1247
if (vfs_getopt(mp->mnt_optnew, "sec",
1248
(void **) &secname, NULL) == 0)
1249
nfs_sec_name(secname, &args.flags);
1250
1251
if (mp->mnt_flag & MNT_UPDATE) {
1252
struct nfsmount *nmp = VFSTONFS(mp);
1253
1254
if (nmp == NULL) {
1255
error = EIO;
1256
goto out;
1257
}
1258
1259
/*
1260
* If a change from TCP->UDP is done and there are thread(s)
1261
* that have I/O RPC(s) in progress with a transfer size
1262
* greater than NFS_MAXDGRAMDATA, those thread(s) will be
1263
* hung, retrying the RPC(s) forever. Usually these threads
1264
* will be seen doing an uninterruptible sleep on wait channel
1265
* "nfsreq".
1266
*/
1267
if (args.sotype == SOCK_DGRAM && nmp->nm_sotype == SOCK_STREAM)
1268
tprintf(td->td_proc, LOG_WARNING,
1269
"Warning: mount -u that changes TCP->UDP can result in hung threads\n");
1270
1271
/*
1272
* When doing an update, we can't change version,
1273
* security, switch lockd strategies, change cookie
1274
* translation or switch oneopenown.
1275
*/
1276
args.flags = (args.flags &
1277
~(NFSMNT_NFSV3 |
1278
NFSMNT_NFSV4 |
1279
NFSMNT_KERB |
1280
NFSMNT_INTEGRITY |
1281
NFSMNT_PRIVACY |
1282
NFSMNT_ONEOPENOWN |
1283
NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) |
1284
(nmp->nm_flag &
1285
(NFSMNT_NFSV3 |
1286
NFSMNT_NFSV4 |
1287
NFSMNT_KERB |
1288
NFSMNT_INTEGRITY |
1289
NFSMNT_PRIVACY |
1290
NFSMNT_ONEOPENOWN |
1291
NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/));
1292
nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td);
1293
goto out;
1294
}
1295
1296
/*
1297
* Make the nfs_ip_paranoia sysctl serve as the default connection
1298
* or no-connection mode for those protocols that support
1299
* no-connection mode (the flag will be cleared later for protocols
1300
* that do not support no-connection mode). This will allow a client
1301
* to receive replies from a different IP then the request was
1302
* sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid),
1303
* not 0.
1304
*/
1305
if (nfs_ip_paranoia == 0)
1306
args.flags |= NFSMNT_NOCONN;
1307
1308
if (has_nfs_args_opt != 0) {
1309
/*
1310
* In the 'nfs_args' case, the pointers in the args
1311
* structure are in userland - we copy them in here.
1312
*/
1313
if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) {
1314
vfs_mount_error(mp, "Bad file handle");
1315
error = EINVAL;
1316
goto out;
1317
}
1318
error = copyin((caddr_t)args.fh, (caddr_t)nfh,
1319
args.fhsize);
1320
if (error != 0)
1321
goto out;
1322
error = copyinstr(args.hostname, hst, MNAMELEN - 1, &hstlen);
1323
if (error != 0)
1324
goto out;
1325
bzero(&hst[hstlen], MNAMELEN - hstlen);
1326
args.hostname = hst;
1327
/* getsockaddr() call must be after above copyin() calls */
1328
error = getsockaddr(&nam, args.addr, args.addrlen);
1329
if (error != 0)
1330
goto out;
1331
} else if (nfs_mount_parse_from(mp->mnt_optnew,
1332
&args.hostname, (struct sockaddr_in **)&nam, dirpath,
1333
MNAMELEN, &dirlen) == 0) {
1334
has_nfs_from_opt = 1;
1335
bcopy(args.hostname, hst, MNAMELEN);
1336
hst[MNAMELEN - 1] = '\0';
1337
1338
/*
1339
* This only works with NFSv4 for now.
1340
*/
1341
args.fhsize = 0;
1342
args.flags |= NFSMNT_NFSV4;
1343
args.sotype = SOCK_STREAM;
1344
} else {
1345
if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh,
1346
&args.fhsize) == 0) {
1347
if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) {
1348
vfs_mount_error(mp, "Bad file handle");
1349
error = EINVAL;
1350
goto out;
1351
}
1352
bcopy(args.fh, nfh, args.fhsize);
1353
} else {
1354
args.fhsize = 0;
1355
}
1356
(void) vfs_getopt(mp->mnt_optnew, "hostname",
1357
(void **)&args.hostname, &len);
1358
if (args.hostname == NULL) {
1359
vfs_mount_error(mp, "Invalid hostname");
1360
error = EINVAL;
1361
goto out;
1362
}
1363
if (len >= MNAMELEN) {
1364
vfs_mount_error(mp, "Hostname too long");
1365
error = EINVAL;
1366
goto out;
1367
}
1368
bcopy(args.hostname, hst, len);
1369
hst[len] = '\0';
1370
}
1371
1372
if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0)
1373
strlcpy(srvkrbname, name, sizeof (srvkrbname));
1374
else {
1375
snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst);
1376
cp = strchr(srvkrbname, ':');
1377
if (cp != NULL)
1378
*cp = '\0';
1379
}
1380
srvkrbnamelen = strlen(srvkrbname);
1381
1382
if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0)
1383
strlcpy(krbname, name, sizeof (krbname));
1384
else
1385
krbname[0] = '\0';
1386
krbnamelen = strlen(krbname);
1387
1388
if (has_nfs_from_opt == 0) {
1389
if (vfs_getopt(mp->mnt_optnew,
1390
"dirpath", (void **)&name, NULL) == 0)
1391
strlcpy(dirpath, name, MNAMELEN);
1392
else
1393
dirpath[0] = '\0';
1394
dirlen = strlen(dirpath);
1395
}
1396
1397
if (has_nfs_args_opt == 0 && has_nfs_from_opt == 0) {
1398
if (vfs_getopt(mp->mnt_optnew, "addr",
1399
(void **)&args.addr, &args.addrlen) == 0) {
1400
if (args.addrlen > SOCK_MAXADDRLEN) {
1401
error = ENAMETOOLONG;
1402
goto out;
1403
}
1404
nam = malloc(args.addrlen, M_SONAME, M_WAITOK);
1405
bcopy(args.addr, nam, args.addrlen);
1406
nam->sa_len = args.addrlen;
1407
} else {
1408
vfs_mount_error(mp, "No server address");
1409
error = EINVAL;
1410
goto out;
1411
}
1412
}
1413
1414
if (aconn > 0 && (args.sotype != SOCK_STREAM ||
1415
(args.flags & NFSMNT_NFSV4) == 0 || minvers == 0)) {
1416
/*
1417
* RFC 5661 requires that an NFSv4.1/4.2 server
1418
* send an RPC reply on the same TCP connection
1419
* as the one it received the request on.
1420
* This property in required for "nconnect" and
1421
* might not be the case for NFSv3 or NFSv4.0 servers.
1422
*/
1423
vfs_mount_error(mp, "nconnect should only be used "
1424
"for NFSv4.1/4.2 mounts");
1425
error = EINVAL;
1426
goto out;
1427
}
1428
1429
if ((newflag & NFSMNT_SYSKRB5) != 0 &&
1430
((args.flags & NFSMNT_NFSV4) == 0 || minvers == 0)) {
1431
/*
1432
* This option requires the use of SP4_NONE, which
1433
* is only in NFSv4.1/4.2.
1434
*/
1435
vfs_mount_error(mp, "syskrb5 should only be used "
1436
"for NFSv4.1/4.2 mounts");
1437
error = EINVAL;
1438
goto out;
1439
}
1440
1441
if ((newflag & NFSMNT_SYSKRB5) != 0 &&
1442
(args.flags & NFSMNT_KERB) == 0) {
1443
/*
1444
* This option modifies the behaviour of sec=krb5[ip].
1445
*/
1446
vfs_mount_error(mp, "syskrb5 should only be used "
1447
"for sec=krb5[ip] mounts");
1448
error = EINVAL;
1449
goto out;
1450
}
1451
1452
if ((newflag & NFSMNT_SYSKRB5) != 0 && krbname[0] != '\0') {
1453
/*
1454
* This option is used as an alternative to "gssname".
1455
*/
1456
vfs_mount_error(mp, "syskrb5 should not be used "
1457
"with the gssname option");
1458
error = EINVAL;
1459
goto out;
1460
}
1461
1462
args.fh = nfh;
1463
error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
1464
dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
1465
nametimeo, negnametimeo, minvers, newflag, tlscertname, aconn);
1466
out:
1467
if (!error) {
1468
MNT_ILOCK(mp);
1469
mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_NO_IOPF |
1470
MNTK_USES_BCACHE;
1471
if ((VFSTONFS(mp)->nm_flag & NFSMNT_NFSV4) != 0)
1472
mp->mnt_kern_flag |= MNTK_NULL_NOCACHE;
1473
MNT_IUNLOCK(mp);
1474
}
1475
free(hst, M_TEMP);
1476
free(dirpath, M_TEMP);
1477
return (error);
1478
}
1479
1480
/*
1481
* VFS Operations.
1482
*
1483
* mount system call
1484
* It seems a bit dumb to copyinstr() the host and path here and then
1485
* bcopy() them in mountnfs(), but I wanted to detect errors before
1486
* doing the getsockaddr() call because getsockaddr() allocates an mbuf and
1487
* an error after that means that I have to release the mbuf.
1488
*/
1489
/* ARGSUSED */
1490
static int
1491
nfs_cmount(struct mntarg *ma, void *data, uint64_t flags)
1492
{
1493
int error;
1494
struct nfs_args args;
1495
1496
error = copyin(data, &args, sizeof (struct nfs_args));
1497
if (error)
1498
return error;
1499
1500
ma = mount_arg(ma, "nfs_args", &args, sizeof args);
1501
1502
error = kernel_mount(ma, flags);
1503
return (error);
1504
}
1505
1506
/*
1507
* Common code for mount and mountroot
1508
*/
1509
static int
1510
mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
1511
char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen,
1512
u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp,
1513
struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo,
1514
int minvers, uint32_t newflag, char *tlscertname, int aconn)
1515
{
1516
struct nfsmount *nmp;
1517
struct nfsnode *np;
1518
int error, trycnt, ret;
1519
struct nfsvattr nfsva;
1520
struct nfsclclient *clp;
1521
struct nfsclds *dsp, *tdsp;
1522
uint32_t lease;
1523
bool tryminvers;
1524
char *fakefh;
1525
static u_int64_t clval = 0;
1526
#ifdef KERN_TLS
1527
u_int maxlen;
1528
#endif
1529
1530
NFSCL_DEBUG(3, "in mnt\n");
1531
CURVNET_SET(CRED_TO_VNET(cred));
1532
clp = NULL;
1533
if (mp->mnt_flag & MNT_UPDATE) {
1534
nmp = VFSTONFS(mp);
1535
printf("%s: MNT_UPDATE is no longer handled here\n", __func__);
1536
free(nam, M_SONAME);
1537
free(tlscertname, M_NEWNFSMNT);
1538
CURVNET_RESTORE();
1539
return (0);
1540
} else {
1541
/* NFS-over-TLS requires that rpctls be functioning. */
1542
if ((newflag & NFSMNT_TLS) != 0) {
1543
error = EINVAL;
1544
#ifdef KERN_TLS
1545
/* KERN_TLS is only supported for TCP. */
1546
if (argp->sotype == SOCK_STREAM &&
1547
rpctls_getinfo(&maxlen, true, false))
1548
error = 0;
1549
#endif
1550
if (error != 0) {
1551
free(nam, M_SONAME);
1552
free(tlscertname, M_NEWNFSMNT);
1553
CURVNET_RESTORE();
1554
return (error);
1555
}
1556
}
1557
nmp = malloc(sizeof (struct nfsmount) +
1558
krbnamelen + dirlen + srvkrbnamelen + 2,
1559
M_NEWNFSMNT, M_WAITOK | M_ZERO);
1560
nmp->nm_tlscertname = tlscertname;
1561
nmp->nm_newflag = newflag;
1562
TAILQ_INIT(&nmp->nm_bufq);
1563
TAILQ_INIT(&nmp->nm_sess);
1564
if (clval == 0)
1565
clval = (u_int64_t)nfsboottime.tv_sec;
1566
nmp->nm_clval = clval++;
1567
nmp->nm_krbnamelen = krbnamelen;
1568
nmp->nm_dirpathlen = dirlen;
1569
nmp->nm_srvkrbnamelen = srvkrbnamelen;
1570
if (td->td_ucred->cr_uid != (uid_t)0) {
1571
/*
1572
* nm_uid is used to get KerberosV credentials for
1573
* the nfsv4 state handling operations if there is
1574
* no host based principal set. Use the uid of
1575
* this user if not root, since they are doing the
1576
* mount. I don't think setting this for root will
1577
* work, since root normally does not have user
1578
* credentials in a credentials cache.
1579
*/
1580
nmp->nm_uid = td->td_ucred->cr_uid;
1581
} else {
1582
/*
1583
* Just set to -1, so it won't be used.
1584
*/
1585
nmp->nm_uid = (uid_t)-1;
1586
}
1587
1588
/* Copy and null terminate all the names */
1589
if (nmp->nm_krbnamelen > 0) {
1590
bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen);
1591
nmp->nm_name[nmp->nm_krbnamelen] = '\0';
1592
}
1593
if (nmp->nm_dirpathlen > 0) {
1594
bcopy(dirpath, NFSMNT_DIRPATH(nmp),
1595
nmp->nm_dirpathlen);
1596
nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
1597
+ 1] = '\0';
1598
}
1599
if (nmp->nm_srvkrbnamelen > 0) {
1600
bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp),
1601
nmp->nm_srvkrbnamelen);
1602
nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen
1603
+ nmp->nm_srvkrbnamelen + 2] = '\0';
1604
}
1605
nmp->nm_sockreq.nr_cred = crhold(cred);
1606
mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF);
1607
mp->mnt_data = nmp;
1608
nmp->nm_getinfo = nfs_getnlminfo;
1609
nmp->nm_vinvalbuf = ncl_vinvalbuf;
1610
}
1611
vfs_getnewfsid(mp);
1612
nmp->nm_mountp = mp;
1613
mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK);
1614
1615
/*
1616
* Since nfs_decode_args() might optionally set them, these
1617
* need to be set to defaults before the call, so that the
1618
* optional settings aren't overwritten.
1619
*/
1620
nmp->nm_nametimeo = nametimeo;
1621
nmp->nm_negnametimeo = negnametimeo;
1622
nmp->nm_timeo = NFS_TIMEO;
1623
nmp->nm_retry = NFS_RETRANS;
1624
nmp->nm_readahead = NFS_DEFRAHEAD;
1625
1626
/* This is empirical approximation of sqrt(hibufspace) * 256. */
1627
nmp->nm_wcommitsize = NFS_MAXBSIZE / 256;
1628
while ((long)nmp->nm_wcommitsize * nmp->nm_wcommitsize < hibufspace)
1629
nmp->nm_wcommitsize *= 2;
1630
nmp->nm_wcommitsize *= 256;
1631
1632
tryminvers = false;
1633
if ((argp->flags & NFSMNT_NFSV4) != 0) {
1634
if (minvers < 0) {
1635
tryminvers = true;
1636
minvers = NFSV42_MINORVERSION;
1637
}
1638
nmp->nm_minorvers = minvers;
1639
} else
1640
nmp->nm_minorvers = 0;
1641
1642
nfs_decode_args(mp, nmp, argp, hst, cred, td);
1643
1644
/*
1645
* V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too
1646
* high, depending on whether we end up with negative offsets in
1647
* the client or server somewhere. 2GB-1 may be safer.
1648
*
1649
* For V3, ncl_fsinfo will adjust this as necessary. Assume maximum
1650
* that we can handle until we find out otherwise.
1651
*/
1652
if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0)
1653
nmp->nm_maxfilesize = 0xffffffffLL;
1654
else
1655
nmp->nm_maxfilesize = OFF_MAX;
1656
1657
if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) {
1658
nmp->nm_wsize = NFS_WSIZE;
1659
nmp->nm_rsize = NFS_RSIZE;
1660
nmp->nm_readdirsize = NFS_READDIRSIZE;
1661
}
1662
nmp->nm_numgrps = NFS_MAXGRPS;
1663
nmp->nm_tprintf_delay = nfs_tprintf_delay;
1664
if (nmp->nm_tprintf_delay < 0)
1665
nmp->nm_tprintf_delay = 0;
1666
nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay;
1667
if (nmp->nm_tprintf_initial_delay < 0)
1668
nmp->nm_tprintf_initial_delay = 0;
1669
nmp->nm_fhsize = argp->fhsize;
1670
if (nmp->nm_fhsize > 0)
1671
bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
1672
strlcpy(mp->mnt_stat.f_mntfromname, hst, MNAMELEN);
1673
nmp->nm_nam = nam;
1674
/* Set up the sockets and per-host congestion */
1675
nmp->nm_sotype = argp->sotype;
1676
nmp->nm_soproto = argp->proto;
1677
nmp->nm_sockreq.nr_prog = NFS_PROG;
1678
if ((argp->flags & NFSMNT_NFSV4))
1679
nmp->nm_sockreq.nr_vers = NFS_VER4;
1680
else if ((argp->flags & NFSMNT_NFSV3))
1681
nmp->nm_sockreq.nr_vers = NFS_VER3;
1682
else
1683
nmp->nm_sockreq.nr_vers = NFS_VER2;
1684
1685
if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0, false,
1686
&nmp->nm_sockreq.nr_client)))
1687
goto bad;
1688
/* For NFSv4, get the clientid now. */
1689
if ((argp->flags & NFSMNT_NFSV4) != 0) {
1690
NFSCL_DEBUG(3, "at getcl\n");
1691
error = nfscl_getcl(mp, cred, td, tryminvers, true, &clp);
1692
NFSCL_DEBUG(3, "aft getcl=%d\n", error);
1693
if (error != 0)
1694
goto bad;
1695
if (aconn > 0 && nmp->nm_minorvers == 0) {
1696
vfs_mount_error(mp, "nconnect should only be used "
1697
"for NFSv4.1/4.2 mounts");
1698
error = EINVAL;
1699
goto bad;
1700
}
1701
if (NFSHASSYSKRB5(nmp) && nmp->nm_minorvers == 0) {
1702
vfs_mount_error(mp, "syskrb5 should only be used "
1703
"for NFSv4.1/4.2 mounts");
1704
error = EINVAL;
1705
goto bad;
1706
}
1707
}
1708
1709
if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) &&
1710
nmp->nm_dirpathlen > 0) {
1711
NFSCL_DEBUG(3, "in dirp\n");
1712
/*
1713
* If the fhsize on the mount point == 0 for V4, the mount
1714
* path needs to be looked up.
1715
*/
1716
trycnt = 3;
1717
do {
1718
error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
1719
cred, td);
1720
NFSCL_DEBUG(3, "aft dirp=%d\n", error);
1721
if (error != 0 && (!NFSHASSYSKRB5(nmp) ||
1722
error != NFSERR_WRONGSEC))
1723
(void) nfs_catnap(PZERO, error, "nfsgetdirp");
1724
} while (error != 0 && --trycnt > 0 &&
1725
(!NFSHASSYSKRB5(nmp) || error != NFSERR_WRONGSEC));
1726
if (error != 0 && (!NFSHASSYSKRB5(nmp) ||
1727
error != NFSERR_WRONGSEC))
1728
goto bad;
1729
}
1730
1731
/*
1732
* A reference count is needed on the nfsnode representing the
1733
* remote root. If this object is not persistent, then backward
1734
* traversals of the mount point (i.e. "..") will not work if
1735
* the nfsnode gets flushed out of the cache. Ufs does not have
1736
* this problem, because one can identify root inodes by their
1737
* number == UFS_ROOTINO (2).
1738
* For the "syskrb5" mount, the file handle might not have
1739
* been acquired. As such, use a "fake" file handle which
1740
* can never be returned by a server for the root vnode.
1741
*/
1742
if (nmp->nm_fhsize > 0 || NFSHASSYSKRB5(nmp)) {
1743
/*
1744
* Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set
1745
* non-zero for the root vnode. f_iosize will be set correctly
1746
* by nfs_statfs() before any I/O occurs.
1747
*/
1748
mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ;
1749
if (nmp->nm_fhsize == 0) {
1750
fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK |
1751
M_ZERO);
1752
error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np,
1753
LK_EXCLUSIVE);
1754
free(fakefh, M_TEMP);
1755
nmp->nm_privflag |= NFSMNTP_FAKEROOTFH;
1756
} else
1757
error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
1758
LK_EXCLUSIVE);
1759
if (error)
1760
goto bad;
1761
*vpp = NFSTOV(np);
1762
1763
/*
1764
* Get file attributes and transfer parameters for the
1765
* mountpoint. This has the side effect of filling in
1766
* (*vpp)->v_type with the correct value.
1767
*/
1768
ret = ENXIO;
1769
if (nmp->nm_fhsize > 0)
1770
ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh,
1771
nmp->nm_fhsize, 1, cred, td, &nfsva, NULL, &lease);
1772
if (ret) {
1773
/*
1774
* Just set default values to get things going.
1775
*/
1776
NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr));
1777
nfsva.na_vattr.va_type = VDIR;
1778
nfsva.na_vattr.va_mode = 0777;
1779
nfsva.na_vattr.va_nlink = 100;
1780
nfsva.na_vattr.va_uid = (uid_t)0;
1781
nfsva.na_vattr.va_gid = (gid_t)0;
1782
nfsva.na_vattr.va_fileid = 2;
1783
nfsva.na_vattr.va_gen = 1;
1784
nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
1785
nfsva.na_vattr.va_size = 512 * 1024;
1786
lease = 20;
1787
}
1788
(void) nfscl_loadattrcache(vpp, &nfsva, NULL, 0, 1);
1789
if ((argp->flags & NFSMNT_NFSV4) != 0) {
1790
NFSCL_DEBUG(3, "lease=%d\n", (int)lease);
1791
NFSLOCKCLSTATE();
1792
clp->nfsc_renew = NFSCL_RENEW(lease);
1793
clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
1794
clp->nfsc_clientidrev++;
1795
if (clp->nfsc_clientidrev == 0)
1796
clp->nfsc_clientidrev++;
1797
NFSUNLOCKCLSTATE();
1798
/*
1799
* Mount will succeed, so the renew thread can be
1800
* started now.
1801
*/
1802
nfscl_start_renewthread(clp);
1803
nfscl_clientrelease(clp);
1804
}
1805
if (argp->flags & NFSMNT_NFSV3)
1806
ncl_fsinfo(nmp, *vpp, cred, td);
1807
1808
/*
1809
* Mark if the mount point supports NFSv4 ACLs and
1810
* named attributes.
1811
*/
1812
if ((argp->flags & NFSMNT_NFSV4) != 0) {
1813
MNT_ILOCK(mp);
1814
if (ret == 0 && nfsrv_useacl != 0 &&
1815
NFSISSET_ATTRBIT(&nfsva.na_suppattr,
1816
NFSATTRBIT_ACL))
1817
mp->mnt_flag |= MNT_NFS4ACLS;
1818
if (nmp->nm_minorvers > 0)
1819
mp->mnt_flag |= MNT_NAMEDATTR;
1820
MNT_IUNLOCK(mp);
1821
}
1822
1823
/* Can now allow additional connections. */
1824
if (aconn > 0)
1825
nmp->nm_aconnect = aconn;
1826
1827
/*
1828
* Lose the lock but keep the ref.
1829
*/
1830
NFSVOPUNLOCK(*vpp);
1831
vfs_cache_root_set(mp, *vpp);
1832
CURVNET_RESTORE();
1833
return (0);
1834
}
1835
error = EIO;
1836
1837
bad:
1838
if (clp != NULL)
1839
nfscl_clientrelease(clp);
1840
newnfs_disconnect(NULL, &nmp->nm_sockreq);
1841
crfree(nmp->nm_sockreq.nr_cred);
1842
if (nmp->nm_sockreq.nr_auth != NULL)
1843
AUTH_DESTROY(nmp->nm_sockreq.nr_auth);
1844
mtx_destroy(&nmp->nm_sockreq.nr_mtx);
1845
mtx_destroy(&nmp->nm_mtx);
1846
if (nmp->nm_clp != NULL) {
1847
NFSLOCKCLSTATE();
1848
LIST_REMOVE(nmp->nm_clp, nfsc_list);
1849
NFSUNLOCKCLSTATE();
1850
free(nmp->nm_clp, M_NFSCLCLIENT);
1851
}
1852
TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) {
1853
if (dsp != TAILQ_FIRST(&nmp->nm_sess) &&
1854
dsp->nfsclds_sockp != NULL)
1855
newnfs_disconnect(NULL, dsp->nfsclds_sockp);
1856
nfscl_freenfsclds(dsp);
1857
}
1858
free(nmp->nm_tlscertname, M_NEWNFSMNT);
1859
free(nmp, M_NEWNFSMNT);
1860
free(nam, M_SONAME);
1861
CURVNET_RESTORE();
1862
return (error);
1863
}
1864
1865
/*
1866
* unmount system call
1867
*/
1868
static int
1869
nfs_unmount(struct mount *mp, int mntflags)
1870
{
1871
struct thread *td;
1872
struct nfsmount *nmp;
1873
int error, flags = 0, i, trycnt = 0;
1874
struct nfsclds *dsp, *tdsp;
1875
struct nfscldeleg *dp, *ndp;
1876
struct nfscldeleghead dh;
1877
1878
td = curthread;
1879
TAILQ_INIT(&dh);
1880
1881
if (mntflags & MNT_FORCE)
1882
flags |= FORCECLOSE;
1883
nmp = VFSTONFS(mp);
1884
error = 0;
1885
/*
1886
* Goes something like this..
1887
* - Call vflush() to clear out vnodes for this filesystem
1888
* - Close the socket
1889
* - Free up the data structures
1890
*/
1891
/* In the forced case, cancel any outstanding requests. */
1892
if (mntflags & MNT_FORCE) {
1893
NFSDDSLOCK();
1894
if (nfsv4_findmirror(nmp) != NULL)
1895
error = ENXIO;
1896
NFSDDSUNLOCK();
1897
if (error)
1898
goto out;
1899
error = newnfs_nmcancelreqs(nmp);
1900
if (error)
1901
goto out;
1902
/* For a forced close, get rid of the renew thread now */
1903
nfscl_umount(nmp, td, &dh);
1904
}
1905
/* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */
1906
do {
1907
error = vflush(mp, 1, flags, td);
1908
if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30)
1909
(void) nfs_catnap(PSOCK, error, "newndm");
1910
} while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30);
1911
if (error)
1912
goto out;
1913
1914
/*
1915
* We are now committed to the unmount.
1916
*/
1917
if ((mntflags & MNT_FORCE) == 0)
1918
nfscl_umount(nmp, td, NULL);
1919
else {
1920
mtx_lock(&nmp->nm_mtx);
1921
nmp->nm_privflag |= NFSMNTP_FORCEDISM;
1922
mtx_unlock(&nmp->nm_mtx);
1923
}
1924
/* Make sure no nfsiods are assigned to this mount. */
1925
NFSLOCKIOD();
1926
for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
1927
if (ncl_iodmount[i] == nmp) {
1928
ncl_iodwant[i] = NFSIOD_AVAILABLE;
1929
ncl_iodmount[i] = NULL;
1930
}
1931
NFSUNLOCKIOD();
1932
1933
/*
1934
* We can now set mnt_data to NULL and wait for
1935
* nfssvc(NFSSVC_FORCEDISM) to complete.
1936
*/
1937
mtx_lock(&mountlist_mtx);
1938
mtx_lock(&nmp->nm_mtx);
1939
mp->mnt_data = NULL;
1940
mtx_unlock(&mountlist_mtx);
1941
while ((nmp->nm_privflag & NFSMNTP_CANCELRPCS) != 0)
1942
msleep(nmp, &nmp->nm_mtx, PVFS, "nfsfdism", 0);
1943
mtx_unlock(&nmp->nm_mtx);
1944
1945
newnfs_disconnect(nmp, &nmp->nm_sockreq);
1946
crfree(nmp->nm_sockreq.nr_cred);
1947
free(nmp->nm_nam, M_SONAME);
1948
if (nmp->nm_sockreq.nr_auth != NULL)
1949
AUTH_DESTROY(nmp->nm_sockreq.nr_auth);
1950
mtx_destroy(&nmp->nm_sockreq.nr_mtx);
1951
mtx_destroy(&nmp->nm_mtx);
1952
TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) {
1953
if (dsp != TAILQ_FIRST(&nmp->nm_sess) &&
1954
dsp->nfsclds_sockp != NULL)
1955
newnfs_disconnect(NULL, dsp->nfsclds_sockp);
1956
nfscl_freenfsclds(dsp);
1957
}
1958
free(nmp->nm_tlscertname, M_NEWNFSMNT);
1959
free(nmp, M_NEWNFSMNT);
1960
1961
/* Free up the delegation structures for forced dismounts. */
1962
TAILQ_FOREACH_SAFE(dp, &dh, nfsdl_list, ndp) {
1963
TAILQ_REMOVE(&dh, dp, nfsdl_list);
1964
free(dp, M_NFSCLDELEG);
1965
}
1966
out:
1967
return (error);
1968
}
1969
1970
/*
1971
* Return root of a filesystem
1972
*/
1973
static int
1974
nfs_root(struct mount *mp, int flags, struct vnode **vpp)
1975
{
1976
struct vnode *vp;
1977
struct nfsmount *nmp;
1978
struct nfsnode *np;
1979
int error;
1980
char *fakefh;
1981
1982
nmp = VFSTONFS(mp);
1983
if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0) {
1984
/* Attempt to get the actual root file handle. */
1985
if (nmp->nm_fhsize == 0)
1986
error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
1987
curthread->td_ucred, curthread);
1988
fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK | M_ZERO);
1989
error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np, flags);
1990
free(fakefh, M_TEMP);
1991
} else {
1992
error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags);
1993
}
1994
if (error)
1995
return error;
1996
vp = NFSTOV(np);
1997
/*
1998
* Get transfer parameters and attributes for root vnode once.
1999
*/
2000
mtx_lock(&nmp->nm_mtx);
2001
if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) {
2002
mtx_unlock(&nmp->nm_mtx);
2003
ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread);
2004
} else
2005
mtx_unlock(&nmp->nm_mtx);
2006
if (vp->v_type == VNON)
2007
vp->v_type = VDIR;
2008
vp->v_vflag |= VV_ROOT;
2009
*vpp = vp;
2010
return (0);
2011
}
2012
2013
/*
2014
* Flush out the buffer cache
2015
*/
2016
/* ARGSUSED */
2017
static int
2018
nfs_sync(struct mount *mp, int waitfor)
2019
{
2020
struct vnode *vp, *mvp;
2021
struct thread *td;
2022
int error, allerror = 0;
2023
2024
td = curthread;
2025
2026
MNT_ILOCK(mp);
2027
/*
2028
* If a forced dismount is in progress, return from here so that
2029
* the umount(2) syscall doesn't get stuck in VFS_SYNC() before
2030
* calling VFS_UNMOUNT().
2031
*/
2032
if (NFSCL_FORCEDISM(mp)) {
2033
MNT_IUNLOCK(mp);
2034
return (EBADF);
2035
}
2036
MNT_IUNLOCK(mp);
2037
2038
if (waitfor == MNT_LAZY)
2039
return (0);
2040
2041
/*
2042
* Force stale buffer cache information to be flushed.
2043
*/
2044
loop:
2045
MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
2046
/* XXX Racy bv_cnt check. */
2047
if (NFSVOPISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0) {
2048
VI_UNLOCK(vp);
2049
continue;
2050
}
2051
if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK)) {
2052
MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
2053
goto loop;
2054
}
2055
error = VOP_FSYNC(vp, waitfor, td);
2056
if (error)
2057
allerror = error;
2058
NFSVOPUNLOCK(vp);
2059
vrele(vp);
2060
}
2061
return (allerror);
2062
}
2063
2064
static int
2065
nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req)
2066
{
2067
struct nfsmount *nmp = VFSTONFS(mp);
2068
struct vfsquery vq;
2069
int error;
2070
2071
bzero(&vq, sizeof(vq));
2072
switch (op) {
2073
#if 0
2074
case VFS_CTL_NOLOCKS:
2075
val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0;
2076
if (req->oldptr != NULL) {
2077
error = SYSCTL_OUT(req, &val, sizeof(val));
2078
if (error)
2079
return (error);
2080
}
2081
if (req->newptr != NULL) {
2082
error = SYSCTL_IN(req, &val, sizeof(val));
2083
if (error)
2084
return (error);
2085
if (val)
2086
nmp->nm_flag |= NFSMNT_NOLOCKS;
2087
else
2088
nmp->nm_flag &= ~NFSMNT_NOLOCKS;
2089
}
2090
break;
2091
#endif
2092
case VFS_CTL_QUERY:
2093
mtx_lock(&nmp->nm_mtx);
2094
if (nmp->nm_state & NFSSTA_TIMEO)
2095
vq.vq_flags |= VQ_NOTRESP;
2096
mtx_unlock(&nmp->nm_mtx);
2097
#if 0
2098
if (!(nmp->nm_flag & NFSMNT_NOLOCKS) &&
2099
(nmp->nm_state & NFSSTA_LOCKTIMEO))
2100
vq.vq_flags |= VQ_NOTRESPLOCK;
2101
#endif
2102
error = SYSCTL_OUT(req, &vq, sizeof(vq));
2103
break;
2104
case VFS_CTL_TIMEO:
2105
if (req->oldptr != NULL) {
2106
error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay,
2107
sizeof(nmp->nm_tprintf_initial_delay));
2108
if (error)
2109
return (error);
2110
}
2111
if (req->newptr != NULL) {
2112
error = vfs_suser(mp, req->td);
2113
if (error)
2114
return (error);
2115
error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay,
2116
sizeof(nmp->nm_tprintf_initial_delay));
2117
if (error)
2118
return (error);
2119
if (nmp->nm_tprintf_initial_delay < 0)
2120
nmp->nm_tprintf_initial_delay = 0;
2121
}
2122
break;
2123
default:
2124
return (ENOTSUP);
2125
}
2126
return (0);
2127
}
2128
2129
/*
2130
* Purge any RPCs in progress, so that they will all return errors.
2131
* This allows dounmount() to continue as far as VFS_UNMOUNT() for a
2132
* forced dismount.
2133
*/
2134
static void
2135
nfs_purge(struct mount *mp)
2136
{
2137
struct nfsmount *nmp = VFSTONFS(mp);
2138
2139
newnfs_nmcancelreqs(nmp);
2140
}
2141
2142
/*
2143
* Extract the information needed by the nlm from the nfs vnode.
2144
*/
2145
static void
2146
nfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp,
2147
struct sockaddr_storage *sp, int *is_v3p, off_t *sizep,
2148
struct timeval *timeop)
2149
{
2150
struct nfsmount *nmp;
2151
struct nfsnode *np = VTONFS(vp);
2152
2153
nmp = VFSTONFS(vp->v_mount);
2154
if (fhlenp != NULL)
2155
*fhlenp = (size_t)np->n_fhp->nfh_len;
2156
if (fhp != NULL)
2157
bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len);
2158
if (sp != NULL)
2159
bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp)));
2160
if (is_v3p != NULL)
2161
*is_v3p = NFS_ISV3(vp);
2162
if (sizep != NULL)
2163
*sizep = np->n_size;
2164
if (timeop != NULL) {
2165
timeop->tv_sec = nmp->nm_timeo / NFS_HZ;
2166
timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ);
2167
}
2168
}
2169
2170
/*
2171
* This function prints out an option name, based on the conditional
2172
* argument.
2173
*/
2174
static __inline void nfscl_printopt(struct nfsmount *nmp, int testval,
2175
char *opt, char **buf, size_t *blen)
2176
{
2177
int len;
2178
2179
if (testval != 0 && *blen > strlen(opt)) {
2180
len = snprintf(*buf, *blen, "%s", opt);
2181
if (len != strlen(opt))
2182
printf("EEK!!\n");
2183
*buf += len;
2184
*blen -= len;
2185
}
2186
}
2187
2188
/*
2189
* This function printf out an options integer value.
2190
*/
2191
static __inline void nfscl_printoptval(struct nfsmount *nmp, int optval,
2192
char *opt, char **buf, size_t *blen)
2193
{
2194
int len;
2195
2196
if (*blen > strlen(opt) + 1) {
2197
/* Could result in truncated output string. */
2198
len = snprintf(*buf, *blen, "%s=%d", opt, optval);
2199
if (len < *blen) {
2200
*buf += len;
2201
*blen -= len;
2202
}
2203
}
2204
}
2205
2206
/*
2207
* Load the option flags and values into the buffer.
2208
*/
2209
void nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen)
2210
{
2211
char *buf;
2212
size_t blen;
2213
2214
buf = buffer;
2215
blen = buflen;
2216
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV4) != 0, "nfsv4", &buf,
2217
&blen);
2218
if ((nmp->nm_flag & NFSMNT_NFSV4) != 0) {
2219
nfscl_printoptval(nmp, nmp->nm_minorvers, ",minorversion", &buf,
2220
&blen);
2221
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_PNFS) != 0, ",pnfs",
2222
&buf, &blen);
2223
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_ONEOPENOWN) != 0 &&
2224
nmp->nm_minorvers > 0, ",oneopenown", &buf, &blen);
2225
}
2226
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV3) != 0, "nfsv3", &buf,
2227
&blen);
2228
nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0,
2229
"nfsv2", &buf, &blen);
2230
nfscl_printopt(nmp, nmp->nm_sotype == SOCK_STREAM, ",tcp", &buf, &blen);
2231
nfscl_printopt(nmp, nmp->nm_sotype != SOCK_STREAM, ",udp", &buf, &blen);
2232
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RESVPORT) != 0, ",resvport",
2233
&buf, &blen);
2234
nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_TLS) != 0, ",tls", &buf,
2235
&blen);
2236
nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_SYSKRB5) != 0,
2237
",syskrb5", &buf, &blen);
2238
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn",
2239
&buf, &blen);
2240
nfscl_printoptval(nmp, nmp->nm_aconnect + 1, ",nconnect", &buf, &blen);
2241
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) == 0, ",hard", &buf,
2242
&blen);
2243
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) != 0, ",soft", &buf,
2244
&blen);
2245
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_INT) != 0, ",intr", &buf,
2246
&blen);
2247
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) == 0, ",cto", &buf,
2248
&blen);
2249
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) != 0, ",nocto", &buf,
2250
&blen);
2251
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NONCONTIGWR) != 0,
2252
",noncontigwr", &buf, &blen);
2253
nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) ==
2254
0, ",lockd", &buf, &blen);
2255
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOLOCKD) != 0, ",nolockd",
2256
&buf, &blen);
2257
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RDIRPLUS) != 0, ",rdirplus",
2258
&buf, &blen);
2259
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_KERB) == 0, ",sec=sys",
2260
&buf, &blen);
2261
nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
2262
NFSMNT_PRIVACY)) == NFSMNT_KERB, ",sec=krb5", &buf, &blen);
2263
nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
2264
NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_INTEGRITY), ",sec=krb5i",
2265
&buf, &blen);
2266
nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY |
2267
NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_PRIVACY), ",sec=krb5p",
2268
&buf, &blen);
2269
nfscl_printoptval(nmp, nmp->nm_acdirmin, ",acdirmin", &buf, &blen);
2270
nfscl_printoptval(nmp, nmp->nm_acdirmax, ",acdirmax", &buf, &blen);
2271
nfscl_printoptval(nmp, nmp->nm_acregmin, ",acregmin", &buf, &blen);
2272
nfscl_printoptval(nmp, nmp->nm_acregmax, ",acregmax", &buf, &blen);
2273
nfscl_printoptval(nmp, nmp->nm_nametimeo, ",nametimeo", &buf, &blen);
2274
nfscl_printoptval(nmp, nmp->nm_negnametimeo, ",negnametimeo", &buf,
2275
&blen);
2276
nfscl_printoptval(nmp, nmp->nm_rsize, ",rsize", &buf, &blen);
2277
nfscl_printoptval(nmp, nmp->nm_wsize, ",wsize", &buf, &blen);
2278
nfscl_printoptval(nmp, nmp->nm_readdirsize, ",readdirsize", &buf,
2279
&blen);
2280
nfscl_printoptval(nmp, nmp->nm_readahead, ",readahead", &buf, &blen);
2281
nfscl_printoptval(nmp, nmp->nm_wcommitsize, ",wcommitsize", &buf,
2282
&blen);
2283
nfscl_printoptval(nmp, nmp->nm_timeo, ",timeout", &buf, &blen);
2284
nfscl_printoptval(nmp, nmp->nm_retry, ",retrans", &buf, &blen);
2285
}
2286
2287