Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/fs/nfsclient/nfs_clport.c
39483 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1989, 1993
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
*/
35
36
#include <sys/cdefs.h>
37
#include "opt_inet.h"
38
#include "opt_inet6.h"
39
40
#include <sys/capsicum.h>
41
42
/*
43
* generally, I don't like #includes inside .h files, but it seems to
44
* be the easiest way to handle the port.
45
*/
46
#include <sys/fail.h>
47
#include <sys/hash.h>
48
#include <sys/sysctl.h>
49
#include <fs/nfs/nfsport.h>
50
#include <netinet/in_fib.h>
51
#include <netinet/if_ether.h>
52
#include <netinet6/ip6_var.h>
53
#include <net/if_types.h>
54
#include <net/route/nhop.h>
55
56
#include <fs/nfsclient/nfs_kdtrace.h>
57
58
#ifdef KDTRACE_HOOKS
59
dtrace_nfsclient_attrcache_flush_probe_func_t
60
dtrace_nfscl_attrcache_flush_done_probe;
61
uint32_t nfscl_attrcache_flush_done_id;
62
63
dtrace_nfsclient_attrcache_get_hit_probe_func_t
64
dtrace_nfscl_attrcache_get_hit_probe;
65
uint32_t nfscl_attrcache_get_hit_id;
66
67
dtrace_nfsclient_attrcache_get_miss_probe_func_t
68
dtrace_nfscl_attrcache_get_miss_probe;
69
uint32_t nfscl_attrcache_get_miss_id;
70
71
dtrace_nfsclient_attrcache_load_probe_func_t
72
dtrace_nfscl_attrcache_load_done_probe;
73
uint32_t nfscl_attrcache_load_done_id;
74
#endif /* !KDTRACE_HOOKS */
75
76
extern u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
77
extern struct vop_vector newnfs_vnodeops;
78
extern struct vop_vector newnfs_fifoops;
79
extern uma_zone_t newnfsnode_zone;
80
extern uma_zone_t ncl_pbuf_zone;
81
extern short nfsv4_cbport;
82
extern int nfscl_enablecallb;
83
extern int nfs_numnfscbd;
84
extern int nfscl_inited;
85
struct mtx ncl_iod_mutex;
86
NFSDLOCKMUTEX;
87
extern struct mtx nfsrv_dslock_mtx;
88
89
extern void (*ncl_call_invalcaches)(struct vnode *);
90
91
SYSCTL_DECL(_vfs_nfs);
92
static int ncl_fileid_maxwarnings = 10;
93
SYSCTL_INT(_vfs_nfs, OID_AUTO, fileid_maxwarnings, CTLFLAG_RWTUN,
94
&ncl_fileid_maxwarnings, 0,
95
"Limit fileid corruption warnings; 0 is off; -1 is unlimited");
96
static volatile int ncl_fileid_nwarnings;
97
98
static void nfscl_warn_fileid(struct nfsmount *, struct nfsvattr *,
99
struct nfsvattr *);
100
101
/*
102
* Comparison function for vfs_hash functions.
103
*/
104
int
105
newnfs_vncmpf(struct vnode *vp, void *arg)
106
{
107
struct nfsfh *nfhp = (struct nfsfh *)arg;
108
struct nfsnode *np = VTONFS(vp);
109
110
if (np->n_fhp->nfh_len != nfhp->nfh_len ||
111
NFSBCMP(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len))
112
return (1);
113
return (0);
114
}
115
116
/*
117
* Look up a vnode/nfsnode by file handle.
118
* Callers must check for mount points!!
119
* In all cases, a pointer to a
120
* nfsnode structure is returned.
121
* This variant takes a "struct nfsfh *" as second argument and uses
122
* that structure up, either by hanging off the nfsnode or FREEing it.
123
*/
124
int
125
nfscl_nget(struct mount *mntp, struct vnode *dvp, struct nfsfh *nfhp,
126
struct componentname *cnp, struct thread *td, struct nfsnode **npp,
127
int lkflags)
128
{
129
struct nfsnode *np, *dnp;
130
struct vnode *vp, *nvp;
131
struct nfsv4node *newd, *oldd;
132
int error;
133
u_int hash;
134
struct nfsmount *nmp;
135
136
nmp = VFSTONFS(mntp);
137
dnp = VTONFS(dvp);
138
*npp = NULL;
139
140
/*
141
* If this is the mount point fh and NFSMNTP_FAKEROOT is set, replace
142
* it with the fake fh.
143
*/
144
if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
145
nmp->nm_fhsize > 0 && nmp->nm_fhsize == nfhp->nfh_len &&
146
!NFSBCMP(nmp->nm_fh, nfhp->nfh_fh, nmp->nm_fhsize)) {
147
free(nfhp, M_NFSFH);
148
nfhp = malloc(sizeof(struct nfsfh) + NFSX_FHMAX + 1,
149
M_NFSFH, M_WAITOK | M_ZERO);
150
nfhp->nfh_len = NFSX_FHMAX + 1;
151
}
152
153
hash = fnv_32_buf(nfhp->nfh_fh, nfhp->nfh_len, FNV1_32_INIT);
154
155
error = vfs_hash_get(mntp, hash, lkflags,
156
td, &nvp, newnfs_vncmpf, nfhp);
157
if (error == 0 && nvp != NULL) {
158
/*
159
* I believe there is a slight chance that vgonel() could
160
* get called on this vnode between when NFSVOPLOCK() drops
161
* the VI_LOCK() and vget() acquires it again, so that it
162
* hasn't yet had v_usecount incremented. If this were to
163
* happen, the VIRF_DOOMED flag would be set, so check for
164
* that here. Since we now have the v_usecount incremented,
165
* we should be ok until we vrele() it, if the VIRF_DOOMED
166
* flag isn't set now.
167
*/
168
VI_LOCK(nvp);
169
if (VN_IS_DOOMED(nvp)) {
170
VI_UNLOCK(nvp);
171
vrele(nvp);
172
error = ENOENT;
173
} else {
174
VI_UNLOCK(nvp);
175
}
176
}
177
if (error) {
178
free(nfhp, M_NFSFH);
179
return (error);
180
}
181
if (nvp != NULL) {
182
np = VTONFS(nvp);
183
/*
184
* For NFSv4, check to see if it is the same name and
185
* replace the name, if it is different.
186
*/
187
oldd = newd = NULL;
188
if ((nmp->nm_flag & NFSMNT_NFSV4) && np->n_v4 != NULL &&
189
nvp->v_type == VREG &&
190
(np->n_v4->n4_namelen != cnp->cn_namelen ||
191
NFSBCMP(cnp->cn_nameptr, NFS4NODENAME(np->n_v4),
192
cnp->cn_namelen) ||
193
dnp->n_fhp->nfh_len != np->n_v4->n4_fhlen ||
194
NFSBCMP(dnp->n_fhp->nfh_fh, np->n_v4->n4_data,
195
dnp->n_fhp->nfh_len))) {
196
newd = malloc(
197
sizeof (struct nfsv4node) + dnp->n_fhp->nfh_len +
198
+ cnp->cn_namelen - 1, M_NFSV4NODE, M_WAITOK);
199
NFSLOCKNODE(np);
200
if (newd != NULL && np->n_v4 != NULL && nvp->v_type == VREG
201
&& (np->n_v4->n4_namelen != cnp->cn_namelen ||
202
NFSBCMP(cnp->cn_nameptr, NFS4NODENAME(np->n_v4),
203
cnp->cn_namelen) ||
204
dnp->n_fhp->nfh_len != np->n_v4->n4_fhlen ||
205
NFSBCMP(dnp->n_fhp->nfh_fh, np->n_v4->n4_data,
206
dnp->n_fhp->nfh_len))) {
207
oldd = np->n_v4;
208
np->n_v4 = newd;
209
newd = NULL;
210
np->n_v4->n4_fhlen = dnp->n_fhp->nfh_len;
211
np->n_v4->n4_namelen = cnp->cn_namelen;
212
NFSBCOPY(dnp->n_fhp->nfh_fh, np->n_v4->n4_data,
213
dnp->n_fhp->nfh_len);
214
NFSBCOPY(cnp->cn_nameptr, NFS4NODENAME(np->n_v4),
215
cnp->cn_namelen);
216
}
217
NFSUNLOCKNODE(np);
218
}
219
if (newd != NULL)
220
free(newd, M_NFSV4NODE);
221
if (oldd != NULL)
222
free(oldd, M_NFSV4NODE);
223
*npp = np;
224
free(nfhp, M_NFSFH);
225
return (0);
226
}
227
np = uma_zalloc(newnfsnode_zone, M_WAITOK | M_ZERO);
228
229
error = getnewvnode(nfs_vnode_tag, mntp, &newnfs_vnodeops, &nvp);
230
if (error) {
231
uma_zfree(newnfsnode_zone, np);
232
free(nfhp, M_NFSFH);
233
return (error);
234
}
235
vp = nvp;
236
KASSERT(vp->v_bufobj.bo_bsize != 0, ("nfscl_nget: bo_bsize == 0"));
237
vp->v_data = np;
238
np->n_vnode = vp;
239
/*
240
* Initialize the mutex even if the vnode is going to be a loser.
241
* This simplifies the logic in reclaim, which can then unconditionally
242
* destroy the mutex (in the case of the loser, or if hash_insert
243
* happened to return an error no special casing is needed).
244
*/
245
mtx_init(&np->n_mtx, "NEWNFSnode lock", NULL, MTX_DEF | MTX_DUPOK);
246
lockinit(&np->n_excl, PVFS, "nfsupg", VLKTIMEOUT, LK_NOSHARE |
247
LK_CANRECURSE);
248
249
/*
250
* Are we getting the root? If so, make sure the vnode flags
251
* are correct
252
*/
253
if (nfhp->nfh_len == NFSX_FHMAX + 1 ||
254
(nfhp->nfh_len == nmp->nm_fhsize &&
255
!bcmp(nfhp->nfh_fh, nmp->nm_fh, nfhp->nfh_len))) {
256
if (vp->v_type == VNON)
257
vp->v_type = VDIR;
258
vp->v_vflag |= VV_ROOT;
259
}
260
261
vp->v_vflag |= VV_VMSIZEVNLOCK;
262
263
np->n_fhp = nfhp;
264
/*
265
* For NFSv4.0, we have to attach the directory file handle and
266
* file name, so that Open Ops can be done later.
267
*/
268
if (NFSHASNFSV4(nmp) && !NFSHASNFSV4N(nmp)) {
269
np->n_v4 = malloc(sizeof (struct nfsv4node)
270
+ dnp->n_fhp->nfh_len + cnp->cn_namelen - 1, M_NFSV4NODE,
271
M_WAITOK);
272
np->n_v4->n4_fhlen = dnp->n_fhp->nfh_len;
273
np->n_v4->n4_namelen = cnp->cn_namelen;
274
NFSBCOPY(dnp->n_fhp->nfh_fh, np->n_v4->n4_data,
275
dnp->n_fhp->nfh_len);
276
NFSBCOPY(cnp->cn_nameptr, NFS4NODENAME(np->n_v4),
277
cnp->cn_namelen);
278
} else {
279
np->n_v4 = NULL;
280
}
281
282
/*
283
* NFS supports recursive and shared locking.
284
*/
285
lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL);
286
VN_LOCK_AREC(vp);
287
VN_LOCK_ASHARE(vp);
288
error = insmntque(vp, mntp);
289
if (error != 0) {
290
*npp = NULL;
291
mtx_destroy(&np->n_mtx);
292
lockdestroy(&np->n_excl);
293
free(nfhp, M_NFSFH);
294
if (np->n_v4 != NULL)
295
free(np->n_v4, M_NFSV4NODE);
296
uma_zfree(newnfsnode_zone, np);
297
return (error);
298
}
299
vn_set_state(vp, VSTATE_CONSTRUCTED);
300
error = vfs_hash_insert(vp, hash, lkflags,
301
td, &nvp, newnfs_vncmpf, nfhp);
302
if (error)
303
return (error);
304
if (nvp != NULL) {
305
*npp = VTONFS(nvp);
306
/* vfs_hash_insert() vput()'s the losing vnode */
307
return (0);
308
}
309
*npp = np;
310
311
return (0);
312
}
313
314
/*
315
* Another variant of nfs_nget(). This one is only used by reopen. It
316
* takes almost the same args as nfs_nget(), but only succeeds if an entry
317
* exists in the cache. (Since files should already be "open" with a
318
* vnode ref cnt on the node when reopen calls this, it should always
319
* succeed.)
320
* Also, don't get a vnode lock, since it may already be locked by some
321
* other process that is handling it. This is ok, since all other threads
322
* on the client are blocked by the nfsc_lock being exclusively held by the
323
* caller of this function.
324
*/
325
int
326
nfscl_ngetreopen(struct mount *mntp, u_int8_t *fhp, int fhsize,
327
struct thread *td, struct nfsnode **npp)
328
{
329
struct vnode *nvp;
330
u_int hash;
331
struct nfsfh *nfhp;
332
int error;
333
334
*npp = NULL;
335
/* For forced dismounts, just return error. */
336
if (NFSCL_FORCEDISM(mntp))
337
return (EINTR);
338
nfhp = malloc(sizeof (struct nfsfh) + fhsize,
339
M_NFSFH, M_WAITOK);
340
bcopy(fhp, &nfhp->nfh_fh[0], fhsize);
341
nfhp->nfh_len = fhsize;
342
343
hash = fnv_32_buf(fhp, fhsize, FNV1_32_INIT);
344
345
/*
346
* First, try to get the vnode locked, but don't block for the lock.
347
*/
348
error = vfs_hash_get(mntp, hash, (LK_EXCLUSIVE | LK_NOWAIT), td, &nvp,
349
newnfs_vncmpf, nfhp);
350
if (error == 0 && nvp != NULL) {
351
NFSVOPUNLOCK(nvp);
352
} else if (error == EBUSY) {
353
/*
354
* It is safe so long as a vflush() with
355
* FORCECLOSE has not been done. Since the Renew thread is
356
* stopped and the MNTK_UNMOUNTF flag is set before doing
357
* a vflush() with FORCECLOSE, we should be ok here.
358
*/
359
if (NFSCL_FORCEDISM(mntp))
360
error = EINTR;
361
else {
362
vfs_hash_ref(mntp, hash, td, &nvp, newnfs_vncmpf, nfhp);
363
if (nvp == NULL) {
364
error = ENOENT;
365
} else if (VN_IS_DOOMED(nvp)) {
366
error = ENOENT;
367
vrele(nvp);
368
} else {
369
error = 0;
370
}
371
}
372
}
373
free(nfhp, M_NFSFH);
374
if (error)
375
return (error);
376
if (nvp != NULL) {
377
*npp = VTONFS(nvp);
378
return (0);
379
}
380
return (EINVAL);
381
}
382
383
static void
384
nfscl_warn_fileid(struct nfsmount *nmp, struct nfsvattr *oldnap,
385
struct nfsvattr *newnap)
386
{
387
int off;
388
389
if (ncl_fileid_maxwarnings >= 0 &&
390
ncl_fileid_nwarnings >= ncl_fileid_maxwarnings)
391
return;
392
off = 0;
393
if (ncl_fileid_maxwarnings >= 0) {
394
if (++ncl_fileid_nwarnings >= ncl_fileid_maxwarnings)
395
off = 1;
396
}
397
398
printf("newnfs: server '%s' error: fileid changed. "
399
"fsid %jx:%jx: expected fileid %#jx, got %#jx. "
400
"(BROKEN NFS SERVER OR MIDDLEWARE)\n",
401
nmp->nm_com.nmcom_hostname,
402
(uintmax_t)nmp->nm_fsid[0],
403
(uintmax_t)nmp->nm_fsid[1],
404
(uintmax_t)oldnap->na_fileid,
405
(uintmax_t)newnap->na_fileid);
406
407
if (off)
408
printf("newnfs: Logged %d times about fileid corruption; "
409
"going quiet to avoid spamming logs excessively. (Limit "
410
"is: %d).\n", ncl_fileid_nwarnings,
411
ncl_fileid_maxwarnings);
412
}
413
414
void
415
ncl_copy_vattr(struct vnode *vp, struct vattr *dst, struct vattr *src)
416
{
417
dst->va_type = src->va_type;
418
dst->va_mode = src->va_mode;
419
dst->va_nlink = src->va_nlink;
420
dst->va_uid = src->va_uid;
421
dst->va_gid = src->va_gid;
422
dst->va_fsid = src->va_fsid;
423
dst->va_fileid = src->va_fileid;
424
dst->va_size = src->va_size;
425
dst->va_blocksize = src->va_blocksize;
426
dst->va_atime = src->va_atime;
427
dst->va_mtime = src->va_mtime;
428
dst->va_ctime = src->va_ctime;
429
dst->va_birthtime = src->va_birthtime;
430
dst->va_gen = src->va_gen;
431
dst->va_flags = src->va_flags;
432
dst->va_rdev = VN_ISDEV(vp) ? src->va_rdev : NODEV;
433
dst->va_bytes = src->va_bytes;
434
dst->va_filerev = src->va_filerev;
435
}
436
437
/*
438
* Load the attribute cache (that lives in the nfsnode entry) with
439
* the attributes of the second argument and
440
* Iff vaper not NULL
441
* copy the attributes to *vaper
442
* Similar to nfs_loadattrcache(), except the attributes are passed in
443
* instead of being parsed out of the mbuf list.
444
*/
445
int
446
nfscl_loadattrcache(struct vnode **vpp, struct nfsvattr *nap, void *nvaper,
447
int writeattr, int dontshrink)
448
{
449
struct vnode *vp = *vpp;
450
struct vattr *vap, *nvap = &nap->na_vattr, *vaper = nvaper;
451
struct nfsnode *np;
452
struct nfsmount *nmp;
453
struct timespec mtime_save;
454
int error, force_fid_err;
455
dev_t topfsid;
456
457
error = 0;
458
459
/*
460
* If v_type == VNON it is a new node, so fill in the v_type,
461
* n_mtime fields. Check to see if it represents a special
462
* device, and if so, check for a possible alias. Once the
463
* correct vnode has been obtained, fill in the rest of the
464
* information.
465
*/
466
np = VTONFS(vp);
467
NFSLOCKNODE(np);
468
if (vp->v_type != nvap->va_type) {
469
vp->v_type = nvap->va_type;
470
if (vp->v_type == VFIFO)
471
vp->v_op = &newnfs_fifoops;
472
np->n_mtime = nvap->va_mtime;
473
}
474
nmp = VFSTONFS(vp->v_mount);
475
vap = &np->n_vattr.na_vattr;
476
mtime_save = vap->va_mtime;
477
if (writeattr) {
478
np->n_vattr.na_filerev = nap->na_filerev;
479
np->n_vattr.na_size = nap->na_size;
480
np->n_vattr.na_mtime = nap->na_mtime;
481
np->n_vattr.na_ctime = nap->na_ctime;
482
np->n_vattr.na_btime = nap->na_btime;
483
np->n_vattr.na_fsid = nap->na_fsid;
484
np->n_vattr.na_mode = nap->na_mode;
485
} else {
486
force_fid_err = 0;
487
KFAIL_POINT_ERROR(DEBUG_FP, nfscl_force_fileid_warning,
488
force_fid_err);
489
/*
490
* BROKEN NFS SERVER OR MIDDLEWARE
491
*
492
* Certain NFS servers (certain old proprietary filers ca.
493
* 2006) or broken middleboxes (e.g. WAN accelerator products)
494
* will respond to GETATTR requests with results for a
495
* different fileid.
496
*
497
* The WAN accelerator we've observed not only serves stale
498
* cache results for a given file, it also occasionally serves
499
* results for wholly different files. This causes surprising
500
* problems; for example the cached size attribute of a file
501
* may truncate down and then back up, resulting in zero
502
* regions in file contents read by applications. We observed
503
* this reliably with Clang and .c files during parallel build.
504
* A pcap revealed packet fragmentation and GETATTR RPC
505
* responses with wholly wrong fileids.
506
* For the case where the file handle is a fake one
507
* generated via the "syskrb5" mount option and
508
* the old fileid is 2, ignore the test, since this might
509
* be replacing the fake attributes with correct ones.
510
*/
511
if ((np->n_vattr.na_fileid != 0 &&
512
np->n_vattr.na_fileid != nap->na_fileid &&
513
(np->n_vattr.na_fileid != 2 || !NFSHASSYSKRB5(nmp) ||
514
np->n_fhp->nfh_len != NFSX_FHMAX + 1)) ||
515
force_fid_err) {
516
nfscl_warn_fileid(nmp, &np->n_vattr, nap);
517
error = EIDRM;
518
goto out;
519
}
520
NFSBCOPY((caddr_t)nap, (caddr_t)&np->n_vattr,
521
sizeof (struct nfsvattr));
522
}
523
524
/*
525
* For NFSv4, the server's export may be a tree of file systems
526
* where a fileno is a unique value within each file system.
527
* na_filesid[0,1] uniquely identify the server file system
528
* and nm_fsid[0,1] is the value for the root file system mounted.
529
* As such, the value of va_fsid generated by vn_fsid() represents
530
* the root file system on the server and a different value for
531
* va_fsid is needed for the other server file systems. This
532
* va_fsid is ideally unique for all of the server file systems,
533
* so a 64bit hash on na_filesid[0,1] is calculated.
534
* Although highly unlikely that the fnv_64_hash() will be
535
* the same as the root, test for this case and recalculate the hash.
536
*/
537
vn_fsid(vp, vap);
538
if (NFSHASNFSV4(nmp) && NFSHASHASSETFSID(nmp) &&
539
(nmp->nm_fsid[0] != np->n_vattr.na_filesid[0] ||
540
nmp->nm_fsid[1] != np->n_vattr.na_filesid[1])) {
541
topfsid = vap->va_fsid;
542
vap->va_fsid = FNV1_64_INIT;
543
do {
544
vap->va_fsid = fnv_64_buf(np->n_vattr.na_filesid,
545
sizeof(np->n_vattr.na_filesid), vap->va_fsid);
546
} while (vap->va_fsid == topfsid);
547
}
548
549
np->n_attrstamp = time_second;
550
if (vap->va_size != np->n_size) {
551
if (vap->va_type == VREG) {
552
if (dontshrink && vap->va_size < np->n_size) {
553
/*
554
* We've been told not to shrink the file;
555
* zero np->n_attrstamp to indicate that
556
* the attributes are stale.
557
*/
558
vap->va_size = np->n_size;
559
np->n_attrstamp = 0;
560
KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
561
} else if (np->n_flag & NMODIFIED) {
562
/*
563
* We've modified the file: Use the larger
564
* of our size, and the server's size.
565
*/
566
if (vap->va_size < np->n_size) {
567
vap->va_size = np->n_size;
568
} else {
569
np->n_size = vap->va_size;
570
np->n_flag |= NSIZECHANGED;
571
}
572
} else {
573
np->n_size = vap->va_size;
574
np->n_flag |= NSIZECHANGED;
575
}
576
} else {
577
np->n_size = vap->va_size;
578
}
579
}
580
/*
581
* The following checks are added to prevent a race between (say)
582
* a READDIR+ and a WRITE.
583
* READDIR+, WRITE requests sent out.
584
* READDIR+ resp, WRITE resp received on client.
585
* However, the WRITE resp was handled before the READDIR+ resp
586
* causing the post op attrs from the write to be loaded first
587
* and the attrs from the READDIR+ to be loaded later. If this
588
* happens, we have stale attrs loaded into the attrcache.
589
* We detect this by for the mtime moving back. We invalidate the
590
* attrcache when this happens.
591
*/
592
if (timespeccmp(&mtime_save, &vap->va_mtime, >)) {
593
/* Size changed or mtime went backwards */
594
np->n_attrstamp = 0;
595
KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
596
}
597
if (vaper != NULL) {
598
ncl_copy_vattr(vp, vaper, vap);
599
if (np->n_flag & NCHG) {
600
if (np->n_flag & NACC)
601
vaper->va_atime = np->n_atim;
602
if (np->n_flag & NUPD)
603
vaper->va_mtime = np->n_mtim;
604
}
605
}
606
607
out:
608
#ifdef KDTRACE_HOOKS
609
if (np->n_attrstamp != 0)
610
KDTRACE_NFS_ATTRCACHE_LOAD_DONE(vp, vap, error);
611
#endif
612
(void)ncl_pager_setsize(vp, NULL);
613
return (error);
614
}
615
616
/*
617
* Call vnode_pager_setsize() if the size of the node changed, as
618
* recorded in nfsnode vs. v_object, or delay the call if notifying
619
* the pager is not possible at the moment.
620
*
621
* If nsizep is non-NULL, the call is delayed and the new node size is
622
* provided. Caller should itself call vnode_pager_setsize() if
623
* function returned true. If nsizep is NULL, function tries to call
624
* vnode_pager_setsize() itself if needed and possible, and the nfs
625
* node is unlocked unconditionally, the return value is not useful.
626
*/
627
bool
628
ncl_pager_setsize(struct vnode *vp, u_quad_t *nsizep)
629
{
630
struct nfsnode *np;
631
vm_object_t object;
632
struct vattr *vap;
633
u_quad_t nsize;
634
bool setnsize;
635
636
np = VTONFS(vp);
637
NFSASSERTNODE(np);
638
639
vap = &np->n_vattr.na_vattr;
640
nsize = vap->va_size;
641
object = vp->v_object;
642
setnsize = false;
643
644
if (object != NULL && nsize != object->un_pager.vnp.vnp_size) {
645
if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE &&
646
(curthread->td_pflags2 & TDP2_SBPAGES) == 0)
647
setnsize = true;
648
else
649
np->n_flag |= NVNSETSZSKIP;
650
}
651
if (nsizep == NULL) {
652
NFSUNLOCKNODE(np);
653
if (setnsize)
654
vnode_pager_setsize(vp, nsize);
655
setnsize = false;
656
} else {
657
*nsizep = nsize;
658
}
659
return (setnsize);
660
}
661
662
/*
663
* Fill in the client id name. For these bytes:
664
* 1 - they must be unique
665
* 2 - they should be persistent across client reboots
666
* 1 is more critical than 2
667
* Use the mount point's unique id plus either the uuid or, if that
668
* isn't set, random junk.
669
*/
670
void
671
nfscl_fillclid(u_int64_t clval, char *uuid, u_int8_t *cp, u_int16_t idlen)
672
{
673
int uuidlen;
674
675
/*
676
* First, put in the 64bit mount point identifier.
677
*/
678
if (idlen >= sizeof (u_int64_t)) {
679
NFSBCOPY((caddr_t)&clval, cp, sizeof (u_int64_t));
680
cp += sizeof (u_int64_t);
681
idlen -= sizeof (u_int64_t);
682
}
683
684
/*
685
* If uuid is non-zero length, use it.
686
*/
687
uuidlen = strlen(uuid);
688
if (uuidlen > 0 && idlen >= uuidlen) {
689
NFSBCOPY(uuid, cp, uuidlen);
690
cp += uuidlen;
691
idlen -= uuidlen;
692
}
693
694
/*
695
* This only normally happens if the uuid isn't set.
696
*/
697
while (idlen > 0) {
698
*cp++ = (u_int8_t)(arc4random() % 256);
699
idlen--;
700
}
701
}
702
703
/*
704
* Fill in a lock owner name. For now, pid + the process's creation time.
705
*/
706
void
707
nfscl_filllockowner(void *id, u_int8_t *cp, int flags)
708
{
709
union {
710
u_int32_t lval;
711
u_int8_t cval[4];
712
} tl;
713
struct proc *p;
714
715
if (id == NULL) {
716
/* Return the single open_owner of all 0 bytes. */
717
bzero(cp, NFSV4CL_LOCKNAMELEN);
718
return;
719
}
720
if ((flags & F_POSIX) != 0) {
721
p = (struct proc *)id;
722
tl.lval = p->p_pid;
723
*cp++ = tl.cval[0];
724
*cp++ = tl.cval[1];
725
*cp++ = tl.cval[2];
726
*cp++ = tl.cval[3];
727
tl.lval = p->p_stats->p_start.tv_sec;
728
*cp++ = tl.cval[0];
729
*cp++ = tl.cval[1];
730
*cp++ = tl.cval[2];
731
*cp++ = tl.cval[3];
732
tl.lval = p->p_stats->p_start.tv_usec;
733
*cp++ = tl.cval[0];
734
*cp++ = tl.cval[1];
735
*cp++ = tl.cval[2];
736
*cp = tl.cval[3];
737
} else if ((flags & F_FLOCK) != 0) {
738
bcopy(&id, cp, sizeof(id));
739
bzero(&cp[sizeof(id)], NFSV4CL_LOCKNAMELEN - sizeof(id));
740
} else {
741
printf("nfscl_filllockowner: not F_POSIX or F_FLOCK\n");
742
bzero(cp, NFSV4CL_LOCKNAMELEN);
743
}
744
}
745
746
/*
747
* Find the parent process for the thread passed in as an argument.
748
* If none exists, return NULL, otherwise return a thread for the parent.
749
* (Can be any of the threads, since it is only used for td->td_proc.)
750
*/
751
NFSPROC_T *
752
nfscl_getparent(struct thread *td)
753
{
754
struct proc *p;
755
struct thread *ptd;
756
757
if (td == NULL)
758
return (NULL);
759
p = td->td_proc;
760
if (p->p_pid == 0)
761
return (NULL);
762
p = p->p_pptr;
763
if (p == NULL)
764
return (NULL);
765
ptd = TAILQ_FIRST(&p->p_threads);
766
return (ptd);
767
}
768
769
/*
770
* Start up the renew kernel thread.
771
*/
772
static void
773
start_nfscl(void *arg)
774
{
775
struct nfsclclient *clp;
776
struct thread *td;
777
778
clp = (struct nfsclclient *)arg;
779
td = TAILQ_FIRST(&clp->nfsc_renewthread->p_threads);
780
nfscl_renewthread(clp, td);
781
kproc_exit(0);
782
}
783
784
void
785
nfscl_start_renewthread(struct nfsclclient *clp)
786
{
787
788
kproc_create(start_nfscl, (void *)clp, &clp->nfsc_renewthread, 0, 0,
789
"nfscl");
790
}
791
792
/*
793
* Handle wcc_data.
794
* For NFSv4, it assumes that nfsv4_wccattr() was used to set up the getattr
795
* as the first Op after PutFH.
796
* (For NFSv4, the postop attributes are after the Op, so they can't be
797
* parsed here. A separate call to nfscl_postop_attr() is required.)
798
*/
799
int
800
nfscl_wcc_data(struct nfsrv_descript *nd, struct vnode *vp,
801
struct nfsvattr *nap, int *flagp, int *wccflagp, uint64_t *repsizep)
802
{
803
u_int32_t *tl;
804
struct nfsnode *np = VTONFS(vp);
805
struct nfsvattr nfsva;
806
int error = 0;
807
808
if (wccflagp != NULL)
809
*wccflagp = 0;
810
if (nd->nd_flag & ND_NFSV3) {
811
*flagp = 0;
812
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
813
if (*tl == newnfs_true) {
814
NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
815
if (wccflagp != NULL) {
816
NFSLOCKNODE(np);
817
*wccflagp = (np->n_mtime.tv_sec ==
818
fxdr_unsigned(u_int32_t, *(tl + 2)) &&
819
np->n_mtime.tv_nsec ==
820
fxdr_unsigned(u_int32_t, *(tl + 3)));
821
NFSUNLOCKNODE(np);
822
}
823
}
824
error = nfscl_postop_attr(nd, nap, flagp);
825
if (wccflagp != NULL && *flagp == 0)
826
*wccflagp = 0;
827
} else if ((nd->nd_flag & (ND_NOMOREDATA | ND_NFSV4 | ND_V4WCCATTR))
828
== (ND_NFSV4 | ND_V4WCCATTR)) {
829
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
830
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
831
NULL, NULL, NULL, NULL, NULL, NULL, NULL);
832
if (error)
833
return (error);
834
/*
835
* Get rid of Op# and status for next op.
836
*/
837
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
838
if (*++tl)
839
nd->nd_flag |= ND_NOMOREDATA;
840
if (repsizep != NULL)
841
*repsizep = nfsva.na_size;
842
if (wccflagp != NULL &&
843
nfsva.na_vattr.va_mtime.tv_sec != 0) {
844
NFSLOCKNODE(np);
845
*wccflagp = (np->n_mtime.tv_sec ==
846
nfsva.na_vattr.va_mtime.tv_sec &&
847
np->n_mtime.tv_nsec ==
848
nfsva.na_vattr.va_mtime.tv_sec);
849
NFSUNLOCKNODE(np);
850
}
851
}
852
nfsmout:
853
return (error);
854
}
855
856
/*
857
* Get postop attributes.
858
*/
859
int
860
nfscl_postop_attr(struct nfsrv_descript *nd, struct nfsvattr *nap, int *retp)
861
{
862
u_int32_t *tl;
863
int error = 0;
864
865
*retp = 0;
866
if (nd->nd_flag & ND_NOMOREDATA)
867
return (error);
868
if (nd->nd_flag & ND_NFSV3) {
869
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
870
*retp = fxdr_unsigned(int, *tl);
871
} else if (nd->nd_flag & ND_NFSV4) {
872
/*
873
* For NFSv4, the postop attr are at the end, so no point
874
* in looking if nd_repstat != 0.
875
*/
876
if (!nd->nd_repstat) {
877
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
878
if (*(tl + 1))
879
/* should never happen since nd_repstat != 0 */
880
nd->nd_flag |= ND_NOMOREDATA;
881
else
882
*retp = 1;
883
}
884
} else if (!nd->nd_repstat) {
885
/* For NFSv2, the attributes are here iff nd_repstat == 0 */
886
*retp = 1;
887
}
888
if (*retp) {
889
error = nfsm_loadattr(nd, nap);
890
if (error)
891
*retp = 0;
892
}
893
nfsmout:
894
return (error);
895
}
896
897
/*
898
* nfscl_request() - mostly a wrapper for newnfs_request().
899
*/
900
int
901
nfscl_request(struct nfsrv_descript *nd, struct vnode *vp, NFSPROC_T *p,
902
struct ucred *cred)
903
{
904
int ret, vers;
905
struct nfsmount *nmp;
906
907
nmp = VFSTONFS(vp->v_mount);
908
if (nd->nd_flag & ND_NFSV4)
909
vers = NFS_VER4;
910
else if (nd->nd_flag & ND_NFSV3)
911
vers = NFS_VER3;
912
else
913
vers = NFS_VER2;
914
ret = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
915
NFS_PROG, vers, NULL, 1, NULL, NULL);
916
return (ret);
917
}
918
919
/*
920
* fill in this bsden's variant of statfs using nfsstatfs.
921
*/
922
void
923
nfscl_loadsbinfo(struct nfsmount *nmp, struct nfsstatfs *sfp, void *statfs)
924
{
925
struct statfs *sbp = (struct statfs *)statfs;
926
927
if (nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) {
928
sbp->f_bsize = NFS_FABLKSIZE;
929
sbp->f_blocks = sfp->sf_tbytes / NFS_FABLKSIZE;
930
sbp->f_bfree = sfp->sf_fbytes / NFS_FABLKSIZE;
931
/*
932
* Although sf_abytes is uint64_t and f_bavail is int64_t,
933
* the value after dividing by NFS_FABLKSIZE is small
934
* enough that it will fit in 63bits, so it is ok to
935
* assign it to f_bavail without fear that it will become
936
* negative.
937
*/
938
sbp->f_bavail = sfp->sf_abytes / NFS_FABLKSIZE;
939
sbp->f_files = sfp->sf_tfiles;
940
/* Since f_ffree is int64_t, clip it to 63bits. */
941
if (sfp->sf_ffiles > INT64_MAX)
942
sbp->f_ffree = INT64_MAX;
943
else
944
sbp->f_ffree = sfp->sf_ffiles;
945
} else if ((nmp->nm_flag & NFSMNT_NFSV4) == 0) {
946
/*
947
* The type casts to (int32_t) ensure that this code is
948
* compatible with the old NFS client, in that it will
949
* propagate bit31 to the high order bits. This may or may
950
* not be correct for NFSv2, but since it is a legacy
951
* environment, I'd rather retain backwards compatibility.
952
*/
953
sbp->f_bsize = (int32_t)sfp->sf_bsize;
954
sbp->f_blocks = (int32_t)sfp->sf_blocks;
955
sbp->f_bfree = (int32_t)sfp->sf_bfree;
956
sbp->f_bavail = (int32_t)sfp->sf_bavail;
957
sbp->f_files = 0;
958
sbp->f_ffree = 0;
959
}
960
}
961
962
/*
963
* Use the fsinfo stuff to update the mount point.
964
*/
965
void
966
nfscl_loadfsinfo(struct nfsmount *nmp, struct nfsfsinfo *fsp,
967
uint32_t clone_blksize)
968
{
969
970
if ((nmp->nm_wsize == 0 || fsp->fs_wtpref < nmp->nm_wsize) &&
971
fsp->fs_wtpref >= NFS_FABLKSIZE)
972
nmp->nm_wsize = (fsp->fs_wtpref + NFS_FABLKSIZE - 1) &
973
~(NFS_FABLKSIZE - 1);
974
if (fsp->fs_wtmax < nmp->nm_wsize && fsp->fs_wtmax > 0) {
975
nmp->nm_wsize = fsp->fs_wtmax & ~(NFS_FABLKSIZE - 1);
976
if (nmp->nm_wsize == 0)
977
nmp->nm_wsize = fsp->fs_wtmax;
978
}
979
if (nmp->nm_wsize < NFS_FABLKSIZE)
980
nmp->nm_wsize = NFS_FABLKSIZE;
981
if ((nmp->nm_rsize == 0 || fsp->fs_rtpref < nmp->nm_rsize) &&
982
fsp->fs_rtpref >= NFS_FABLKSIZE)
983
nmp->nm_rsize = (fsp->fs_rtpref + NFS_FABLKSIZE - 1) &
984
~(NFS_FABLKSIZE - 1);
985
if (fsp->fs_rtmax < nmp->nm_rsize && fsp->fs_rtmax > 0) {
986
nmp->nm_rsize = fsp->fs_rtmax & ~(NFS_FABLKSIZE - 1);
987
if (nmp->nm_rsize == 0)
988
nmp->nm_rsize = fsp->fs_rtmax;
989
}
990
if (nmp->nm_rsize < NFS_FABLKSIZE)
991
nmp->nm_rsize = NFS_FABLKSIZE;
992
if ((nmp->nm_readdirsize == 0 || fsp->fs_dtpref < nmp->nm_readdirsize)
993
&& fsp->fs_dtpref >= NFS_DIRBLKSIZ)
994
nmp->nm_readdirsize = (fsp->fs_dtpref + NFS_DIRBLKSIZ - 1) &
995
~(NFS_DIRBLKSIZ - 1);
996
if (fsp->fs_rtmax < nmp->nm_readdirsize && fsp->fs_rtmax > 0) {
997
nmp->nm_readdirsize = fsp->fs_rtmax & ~(NFS_DIRBLKSIZ - 1);
998
if (nmp->nm_readdirsize == 0)
999
nmp->nm_readdirsize = fsp->fs_rtmax;
1000
}
1001
if (nmp->nm_readdirsize < NFS_DIRBLKSIZ)
1002
nmp->nm_readdirsize = NFS_DIRBLKSIZ;
1003
if (fsp->fs_maxfilesize > 0 &&
1004
fsp->fs_maxfilesize < nmp->nm_maxfilesize)
1005
nmp->nm_maxfilesize = fsp->fs_maxfilesize;
1006
nmp->nm_mountp->mnt_stat.f_iosize = newnfs_iosize(nmp);
1007
1008
/*
1009
* Although ZFS reports a clone_blksize of 16Mbytes,
1010
* 128Kbytes usually works, so set it to that.
1011
*/
1012
if (clone_blksize > 128 * 1024)
1013
clone_blksize = 128 * 1024;
1014
nmp->nm_cloneblksize = clone_blksize;
1015
nmp->nm_state |= NFSSTA_GOTFSINFO;
1016
}
1017
1018
/*
1019
* Lookups source address which should be used to communicate with
1020
* @nmp and stores it inside @pdst.
1021
*
1022
* Returns 0 on success.
1023
*/
1024
u_int8_t *
1025
nfscl_getmyip(struct nfsmount *nmp, struct in6_addr *paddr, int *isinet6p)
1026
{
1027
#if defined(INET6) || defined(INET)
1028
int fibnum;
1029
1030
fibnum = curthread->td_proc->p_fibnum;
1031
#endif
1032
#ifdef INET
1033
if (nmp->nm_nam->sa_family == AF_INET) {
1034
struct epoch_tracker et;
1035
struct nhop_object *nh;
1036
struct sockaddr_in *sin;
1037
struct in_addr addr = {};
1038
1039
sin = (struct sockaddr_in *)nmp->nm_nam;
1040
NET_EPOCH_ENTER(et);
1041
CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred));
1042
nh = fib4_lookup(fibnum, sin->sin_addr, 0, NHR_NONE, 0);
1043
if (nh != NULL) {
1044
addr = IA_SIN(ifatoia(nh->nh_ifa))->sin_addr;
1045
if (IN_LOOPBACK(ntohl(addr.s_addr))) {
1046
/* Ignore loopback addresses */
1047
nh = NULL;
1048
}
1049
}
1050
CURVNET_RESTORE();
1051
NET_EPOCH_EXIT(et);
1052
1053
if (nh == NULL)
1054
return (NULL);
1055
*isinet6p = 0;
1056
*((struct in_addr *)paddr) = addr;
1057
1058
return (u_int8_t *)paddr;
1059
}
1060
#endif
1061
#ifdef INET6
1062
if (nmp->nm_nam->sa_family == AF_INET6) {
1063
struct epoch_tracker et;
1064
struct sockaddr_in6 *sin6;
1065
int error;
1066
1067
sin6 = (struct sockaddr_in6 *)nmp->nm_nam;
1068
1069
NET_EPOCH_ENTER(et);
1070
CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred));
1071
error = in6_selectsrc_addr(fibnum, &sin6->sin6_addr,
1072
sin6->sin6_scope_id, NULL, paddr, NULL);
1073
CURVNET_RESTORE();
1074
NET_EPOCH_EXIT(et);
1075
if (error != 0)
1076
return (NULL);
1077
1078
if (IN6_IS_ADDR_LOOPBACK(paddr))
1079
return (NULL);
1080
1081
/* Scope is embedded in */
1082
*isinet6p = 1;
1083
1084
return (u_int8_t *)paddr;
1085
}
1086
#endif
1087
return (NULL);
1088
}
1089
1090
/*
1091
* Copy NFS uid, gids from the cred structure.
1092
*/
1093
void
1094
newnfs_copyincred(struct ucred *cr, struct nfscred *nfscr)
1095
{
1096
int i;
1097
1098
KASSERT(cr->cr_ngroups >= 0,
1099
("newnfs_copyincred: negative cr_ngroups"));
1100
nfscr->nfsc_uid = cr->cr_uid;
1101
nfscr->nfsc_ngroups = MIN(cr->cr_ngroups + 1, NFS_MAXGRPS + 1);
1102
nfscr->nfsc_groups[0] = cr->cr_gid;
1103
for (i = 1; i < nfscr->nfsc_ngroups; i++)
1104
nfscr->nfsc_groups[i] = cr->cr_groups[i - 1];
1105
}
1106
1107
/*
1108
* Do any client specific initialization.
1109
*/
1110
void
1111
nfscl_init(void)
1112
{
1113
static int inited = 0;
1114
1115
if (inited)
1116
return;
1117
inited = 1;
1118
nfscl_inited = 1;
1119
ncl_pbuf_zone = pbuf_zsecond_create("nfspbuf", nswbuf / 2);
1120
}
1121
1122
/*
1123
* Check each of the attributes to be set, to ensure they aren't already
1124
* the correct value. Disable setting ones already correct.
1125
*/
1126
int
1127
nfscl_checksattr(struct vattr *vap, struct nfsvattr *nvap)
1128
{
1129
1130
if (vap->va_mode != (mode_t)VNOVAL) {
1131
if (vap->va_mode == nvap->na_mode)
1132
vap->va_mode = (mode_t)VNOVAL;
1133
}
1134
if (vap->va_uid != (uid_t)VNOVAL) {
1135
if (vap->va_uid == nvap->na_uid)
1136
vap->va_uid = (uid_t)VNOVAL;
1137
}
1138
if (vap->va_gid != (gid_t)VNOVAL) {
1139
if (vap->va_gid == nvap->na_gid)
1140
vap->va_gid = (gid_t)VNOVAL;
1141
}
1142
if (vap->va_size != VNOVAL) {
1143
if (vap->va_size == nvap->na_size)
1144
vap->va_size = VNOVAL;
1145
}
1146
1147
/*
1148
* We are normally called with only a partially initialized
1149
* VAP. Since the NFSv3 spec says that server may use the
1150
* file attributes to store the verifier, the spec requires
1151
* us to do a SETATTR RPC. FreeBSD servers store the verifier
1152
* in atime, but we can't really assume that all servers will
1153
* so we ensure that our SETATTR sets both atime and mtime.
1154
* Set the VA_UTIMES_NULL flag for this case, so that
1155
* the server's time will be used. This is needed to
1156
* work around a bug in some Solaris servers, where
1157
* setting the time TOCLIENT causes the Setattr RPC
1158
* to return NFS_OK, but not set va_mode.
1159
*/
1160
if (vap->va_mtime.tv_sec == VNOVAL) {
1161
vfs_timestamp(&vap->va_mtime);
1162
vap->va_vaflags |= VA_UTIMES_NULL;
1163
}
1164
if (vap->va_atime.tv_sec == VNOVAL)
1165
vap->va_atime = vap->va_mtime;
1166
return (1);
1167
}
1168
1169
/*
1170
* Map nfsv4 errors to errno.h errors.
1171
* The uid and gid arguments are only used for NFSERR_BADOWNER and that
1172
* error should only be returned for the Open, Create and Setattr Ops.
1173
* As such, most calls can just pass in 0 for those arguments.
1174
*/
1175
int
1176
nfscl_maperr(struct thread *td, int error, uid_t uid, gid_t gid)
1177
{
1178
struct proc *p;
1179
1180
if (error < 10000 || error >= NFSERR_STALEWRITEVERF)
1181
return (error);
1182
if (td != NULL)
1183
p = td->td_proc;
1184
else
1185
p = NULL;
1186
switch (error) {
1187
case NFSERR_BADOWNER:
1188
tprintf(p, LOG_INFO,
1189
"No name and/or group mapping for uid,gid:(%d,%d)\n",
1190
uid, gid);
1191
return (EPERM);
1192
case NFSERR_BADNAME:
1193
case NFSERR_BADCHAR:
1194
printf("nfsv4 char/name not handled by server\n");
1195
return (ENOENT);
1196
case NFSERR_STALECLIENTID:
1197
case NFSERR_STALESTATEID:
1198
case NFSERR_EXPIRED:
1199
case NFSERR_BADSTATEID:
1200
case NFSERR_BADSESSION:
1201
printf("nfsv4 recover err returned %d\n", error);
1202
return (EIO);
1203
case NFSERR_BADHANDLE:
1204
case NFSERR_SERVERFAULT:
1205
case NFSERR_BADTYPE:
1206
case NFSERR_FHEXPIRED:
1207
case NFSERR_RESOURCE:
1208
case NFSERR_MOVED:
1209
case NFSERR_MINORVERMISMATCH:
1210
case NFSERR_OLDSTATEID:
1211
case NFSERR_BADSEQID:
1212
case NFSERR_LEASEMOVED:
1213
case NFSERR_RECLAIMBAD:
1214
case NFSERR_BADXDR:
1215
case NFSERR_OPILLEGAL:
1216
printf("nfsv4 client/server protocol prob err=%d\n",
1217
error);
1218
return (EIO);
1219
case NFSERR_NOFILEHANDLE:
1220
printf("nfsv4 no file handle: usually means the file "
1221
"system is not exported on the NFSv4 server\n");
1222
return (EIO);
1223
case NFSERR_WRONGSEC:
1224
tprintf(p, LOG_INFO, "NFSv4 error WrongSec: You probably need a"
1225
" Kerberos TGT\n");
1226
return (EIO);
1227
default:
1228
tprintf(p, LOG_INFO, "nfsv4 err=%d\n", error);
1229
return (EIO);
1230
};
1231
}
1232
1233
/*
1234
* Check to see if the process for this owner exists. Return 1 if it doesn't
1235
* and 0 otherwise.
1236
*/
1237
int
1238
nfscl_procdoesntexist(u_int8_t *own)
1239
{
1240
union {
1241
u_int32_t lval;
1242
u_int8_t cval[4];
1243
} tl;
1244
struct proc *p;
1245
pid_t pid;
1246
int i, ret = 0;
1247
1248
/* For the single open_owner of all 0 bytes, just return 0. */
1249
for (i = 0; i < NFSV4CL_LOCKNAMELEN; i++)
1250
if (own[i] != 0)
1251
break;
1252
if (i == NFSV4CL_LOCKNAMELEN)
1253
return (0);
1254
1255
tl.cval[0] = *own++;
1256
tl.cval[1] = *own++;
1257
tl.cval[2] = *own++;
1258
tl.cval[3] = *own++;
1259
pid = tl.lval;
1260
p = pfind_any_locked(pid);
1261
if (p == NULL)
1262
return (1);
1263
if (p->p_stats == NULL) {
1264
PROC_UNLOCK(p);
1265
return (0);
1266
}
1267
tl.cval[0] = *own++;
1268
tl.cval[1] = *own++;
1269
tl.cval[2] = *own++;
1270
tl.cval[3] = *own++;
1271
if (tl.lval != p->p_stats->p_start.tv_sec) {
1272
ret = 1;
1273
} else {
1274
tl.cval[0] = *own++;
1275
tl.cval[1] = *own++;
1276
tl.cval[2] = *own++;
1277
tl.cval[3] = *own;
1278
if (tl.lval != p->p_stats->p_start.tv_usec)
1279
ret = 1;
1280
}
1281
PROC_UNLOCK(p);
1282
return (ret);
1283
}
1284
1285
/*
1286
* - nfs pseudo system call for the client
1287
*/
1288
/*
1289
* MPSAFE
1290
*/
1291
static int
1292
nfssvc_nfscl(struct thread *td, struct nfssvc_args *uap)
1293
{
1294
struct file *fp;
1295
struct nfscbd_args nfscbdarg;
1296
struct nfsd_nfscbd_args nfscbdarg2;
1297
struct nameidata nd;
1298
struct nfscl_dumpmntopts dumpmntopts;
1299
cap_rights_t rights;
1300
char *buf;
1301
int error;
1302
struct mount *mp;
1303
struct nfsmount *nmp;
1304
1305
NFSD_CURVNET_SET(NFSD_TD_TO_VNET(td));
1306
if (uap->flag & NFSSVC_CBADDSOCK) {
1307
error = copyin(uap->argp, (caddr_t)&nfscbdarg, sizeof(nfscbdarg));
1308
if (error)
1309
goto out;
1310
/*
1311
* Since we don't know what rights might be required,
1312
* pretend that we need them all. It is better to be too
1313
* careful than too reckless.
1314
*/
1315
error = fget(td, nfscbdarg.sock,
1316
cap_rights_init_one(&rights, CAP_SOCK_CLIENT), &fp);
1317
if (error)
1318
goto out;
1319
if (fp->f_type != DTYPE_SOCKET) {
1320
fdrop(fp, td);
1321
error = EPERM;
1322
goto out;
1323
}
1324
error = nfscbd_addsock(fp);
1325
fdrop(fp, td);
1326
if (!error && nfscl_enablecallb == 0) {
1327
nfsv4_cbport = nfscbdarg.port;
1328
nfscl_enablecallb = 1;
1329
}
1330
} else if (uap->flag & NFSSVC_NFSCBD) {
1331
if (uap->argp == NULL) {
1332
error = EINVAL;
1333
goto out;
1334
}
1335
error = copyin(uap->argp, (caddr_t)&nfscbdarg2,
1336
sizeof(nfscbdarg2));
1337
if (error)
1338
goto out;
1339
error = nfscbd_nfsd(td, &nfscbdarg2);
1340
} else if (uap->flag & NFSSVC_DUMPMNTOPTS) {
1341
error = copyin(uap->argp, &dumpmntopts, sizeof(dumpmntopts));
1342
if (error == 0 && (dumpmntopts.ndmnt_blen < 256 ||
1343
dumpmntopts.ndmnt_blen > 1024))
1344
error = EINVAL;
1345
if (error == 0)
1346
error = nfsrv_lookupfilename(&nd,
1347
dumpmntopts.ndmnt_fname, td);
1348
if (error == 0 && strcmp(nd.ni_vp->v_mount->mnt_vfc->vfc_name,
1349
"nfs") != 0) {
1350
vput(nd.ni_vp);
1351
error = EINVAL;
1352
}
1353
if (error == 0) {
1354
buf = malloc(dumpmntopts.ndmnt_blen, M_TEMP, M_WAITOK |
1355
M_ZERO);
1356
nfscl_retopts(VFSTONFS(nd.ni_vp->v_mount), buf,
1357
dumpmntopts.ndmnt_blen);
1358
vput(nd.ni_vp);
1359
error = copyout(buf, dumpmntopts.ndmnt_buf,
1360
dumpmntopts.ndmnt_blen);
1361
free(buf, M_TEMP);
1362
}
1363
} else if (uap->flag & NFSSVC_FORCEDISM) {
1364
buf = malloc(MNAMELEN + 1, M_TEMP, M_WAITOK);
1365
error = copyinstr(uap->argp, buf, MNAMELEN + 1, NULL);
1366
if (error == 0) {
1367
nmp = NULL;
1368
mtx_lock(&mountlist_mtx);
1369
TAILQ_FOREACH(mp, &mountlist, mnt_list) {
1370
if (strcmp(mp->mnt_stat.f_mntonname, buf) ==
1371
0 && strcmp(mp->mnt_stat.f_fstypename,
1372
"nfs") == 0 && mp->mnt_data != NULL) {
1373
nmp = VFSTONFS(mp);
1374
NFSDDSLOCK();
1375
if (nfsv4_findmirror(nmp) != NULL) {
1376
NFSDDSUNLOCK();
1377
error = ENXIO;
1378
nmp = NULL;
1379
break;
1380
}
1381
mtx_lock(&nmp->nm_mtx);
1382
if ((nmp->nm_privflag &
1383
NFSMNTP_FORCEDISM) == 0) {
1384
nmp->nm_privflag |=
1385
(NFSMNTP_FORCEDISM |
1386
NFSMNTP_CANCELRPCS);
1387
mtx_unlock(&nmp->nm_mtx);
1388
} else {
1389
mtx_unlock(&nmp->nm_mtx);
1390
nmp = NULL;
1391
}
1392
NFSDDSUNLOCK();
1393
break;
1394
}
1395
}
1396
mtx_unlock(&mountlist_mtx);
1397
1398
if (nmp != NULL) {
1399
/*
1400
* Call newnfs_nmcancelreqs() to cause
1401
* any RPCs in progress on the mount point to
1402
* fail.
1403
* This will cause any process waiting for an
1404
* RPC to complete while holding a vnode lock
1405
* on the mounted-on vnode (such as "df" or
1406
* a non-forced "umount") to fail.
1407
* This will unlock the mounted-on vnode so
1408
* a forced dismount can succeed.
1409
* Then clear NFSMNTP_CANCELRPCS and wakeup(),
1410
* so that nfs_unmount() can complete.
1411
*/
1412
newnfs_nmcancelreqs(nmp);
1413
mtx_lock(&nmp->nm_mtx);
1414
nmp->nm_privflag &= ~NFSMNTP_CANCELRPCS;
1415
wakeup(nmp);
1416
mtx_unlock(&nmp->nm_mtx);
1417
} else if (error == 0)
1418
error = EINVAL;
1419
}
1420
free(buf, M_TEMP);
1421
} else {
1422
error = EINVAL;
1423
}
1424
out:
1425
NFSD_CURVNET_RESTORE();
1426
return (error);
1427
}
1428
1429
extern int (*nfsd_call_nfscl)(struct thread *, struct nfssvc_args *);
1430
1431
/*
1432
* Called once to initialize data structures...
1433
*/
1434
static int
1435
nfscl_modevent(module_t mod, int type, void *data)
1436
{
1437
int error = 0;
1438
static int loaded = 0;
1439
1440
switch (type) {
1441
case MOD_LOAD:
1442
if (loaded)
1443
return (0);
1444
newnfs_portinit();
1445
mtx_init(&ncl_iod_mutex, "ncl_iod_mutex", NULL, MTX_DEF);
1446
nfscl_init();
1447
NFSD_LOCK();
1448
nfsrvd_cbinit(0);
1449
NFSD_UNLOCK();
1450
ncl_call_invalcaches = ncl_invalcaches;
1451
nfsd_call_nfscl = nfssvc_nfscl;
1452
loaded = 1;
1453
break;
1454
1455
case MOD_UNLOAD:
1456
if (nfs_numnfscbd != 0) {
1457
error = EBUSY;
1458
break;
1459
}
1460
1461
/*
1462
* XXX: Unloading of nfscl module is unsupported.
1463
*/
1464
#if 0
1465
ncl_call_invalcaches = NULL;
1466
nfsd_call_nfscl = NULL;
1467
uma_zdestroy(ncl_pbuf_zone);
1468
/* and get rid of the mutexes */
1469
mtx_destroy(&ncl_iod_mutex);
1470
loaded = 0;
1471
break;
1472
#else
1473
/* FALLTHROUGH */
1474
#endif
1475
default:
1476
error = EOPNOTSUPP;
1477
break;
1478
}
1479
return error;
1480
}
1481
static moduledata_t nfscl_mod = {
1482
"nfscl",
1483
nfscl_modevent,
1484
NULL,
1485
};
1486
/*
1487
* This is the main module declaration for the NFS client. The
1488
* nfscl_modevent() function is needed to ensure that the module
1489
* cannot be unloaded, among other things.
1490
* There is also a module declaration in sys/fs/nfsclient/nfs_clvfsops.c
1491
* for the name "nfs" within the VFS_SET() macro that defines the "nfs"
1492
* file system type.
1493
*/
1494
DECLARE_MODULE(nfscl, nfscl_mod, SI_SUB_VFS, SI_ORDER_FIRST);
1495
1496
/* So that loader and kldload(2) can find us, wherever we are.. */
1497
MODULE_VERSION(nfscl, 1);
1498
MODULE_DEPEND(nfscl, nfscommon, 1, 1, 1);
1499
MODULE_DEPEND(nfscl, krpc, 1, 1, 1);
1500
MODULE_DEPEND(nfscl, nfssvc, 1, 1, 1);
1501
MODULE_DEPEND(nfscl, xdr, 1, 1, 1);
1502
MODULE_DEPEND(nfscl, acl_nfs4, 1, 1, 1);
1503
1504