Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/fs/nfsclient/nfs_clrpcops.c
107609 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
/*
38
* Rpc op calls, generally called from the vnode op calls or through the
39
* buffer cache, for NFS v2, 3 and 4.
40
* These do not normally make any changes to vnode arguments or use
41
* structures that might change between the VFS variants. The returned
42
* arguments are all at the end, after the NFSPROC_T *p one.
43
*/
44
45
#include "opt_inet6.h"
46
47
#include <fs/nfs/nfsport.h>
48
#include <fs/nfsclient/nfs.h>
49
#include <sys/extattr.h>
50
#include <sys/sysctl.h>
51
#include <sys/taskqueue.h>
52
53
SYSCTL_DECL(_vfs_nfs);
54
55
static int nfsignore_eexist = 0;
56
SYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW,
57
&nfsignore_eexist, 0, "NFS ignore EEXIST replies for mkdir/symlink");
58
59
static int nfscl_dssameconn = 0;
60
SYSCTL_INT(_vfs_nfs, OID_AUTO, dssameconn, CTLFLAG_RW,
61
&nfscl_dssameconn, 0, "Use same TCP connection to multiple DSs");
62
63
static uint64_t nfs_maxcopyrange = SSIZE_MAX;
64
SYSCTL_U64(_vfs_nfs, OID_AUTO, maxcopyrange, CTLFLAG_RW,
65
&nfs_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable");
66
67
/*
68
* Global variables
69
*/
70
extern struct nfsstatsv1 nfsstatsv1;
71
extern int nfs_numnfscbd;
72
extern struct timeval nfsboottime;
73
extern u_int32_t newnfs_false, newnfs_true;
74
extern nfstype nfsv34_type[9];
75
extern int nfsrv_useacl;
76
extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
77
extern int nfscl_debuglevel;
78
extern int nfs_pnfsiothreads;
79
extern u_long sb_max_adj;
80
NFSCLSTATEMUTEX;
81
int nfstest_outofseq = 0;
82
int nfscl_assumeposixlocks = 1;
83
int nfscl_enablecallb = 0;
84
short nfsv4_cbport = NFSV4_CBPORT;
85
int nfstest_openallsetattr = 0;
86
87
#define DIRHDSIZ offsetof(struct dirent, d_name)
88
89
/*
90
* nfscl_getsameserver() can return one of three values:
91
* NFSDSP_USETHISSESSION - Use this session for the DS.
92
* NFSDSP_SEQTHISSESSION - Use the nfsclds_sequence field of this dsp for new
93
* session.
94
* NFSDSP_NOTFOUND - No matching server was found.
95
*/
96
enum nfsclds_state {
97
NFSDSP_USETHISSESSION = 0,
98
NFSDSP_SEQTHISSESSION = 1,
99
NFSDSP_NOTFOUND = 2,
100
};
101
102
/*
103
* Do a write RPC on a DS data file, using this structure for the arguments,
104
* so that this function can be executed by a separate kernel process.
105
*/
106
struct nfsclwritedsdorpc {
107
int done;
108
int inprog;
109
struct task tsk;
110
struct vnode *vp;
111
int iomode;
112
int must_commit;
113
nfsv4stateid_t *stateidp;
114
struct nfsclds *dsp;
115
uint64_t off;
116
int len;
117
#ifdef notyet
118
int advise;
119
#endif
120
struct nfsfh *fhp;
121
struct mbuf *m;
122
int vers;
123
int minorvers;
124
struct ucred *cred;
125
NFSPROC_T *p;
126
int err;
127
};
128
129
static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *,
130
struct ucred *, NFSPROC_T *, struct nfsvattr *, int *);
131
static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *,
132
nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *);
133
static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *,
134
struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *,
135
int);
136
static int nfsrpc_deallocaterpc(vnode_t, off_t, off_t, nfsv4stateid_t *,
137
struct nfsvattr *, int *, struct ucred *, NFSPROC_T *);
138
static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *,
139
nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *,
140
struct nfsvattr *, struct nfsfh **, int *, int *);
141
static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *,
142
nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *,
143
NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *,
144
int *, int *);
145
static bool nfscl_invalidfname(bool, char *, int);
146
static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *,
147
struct nfscllockowner *, u_int64_t, u_int64_t,
148
u_int32_t, struct ucred *, NFSPROC_T *, int);
149
static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *,
150
struct acl *, acl_type_t, nfsv4stateid_t *);
151
static int nfsrpc_layouterror(struct nfsmount *, uint8_t *, int, uint64_t,
152
uint64_t, nfsv4stateid_t *, struct ucred *, NFSPROC_T *, uint32_t,
153
uint32_t, char *);
154
static int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int,
155
uint32_t, uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **,
156
struct ucred *, NFSPROC_T *);
157
static int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_in *,
158
struct sockaddr_in6 *, sa_family_t, int, int, struct nfsclds **,
159
NFSPROC_T *);
160
static void nfscl_initsessionslots(struct nfsclsession *);
161
static int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *,
162
nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
163
struct nfsclflayout *, uint64_t, uint64_t, int, struct ucred *,
164
NFSPROC_T *);
165
static int nfscl_dofflayoutio(vnode_t, struct uio *, int *, int *, int *,
166
nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
167
struct nfsclflayout *, uint64_t, uint64_t, int, int, struct mbuf *,
168
struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *);
169
static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *,
170
struct nfsclds *, uint64_t, int, struct nfsfh *, int, int, int,
171
struct ucred *, NFSPROC_T *);
172
static int nfsrpc_writeds(vnode_t, struct uio *, int *, int *,
173
nfsv4stateid_t *, struct nfsclds *, uint64_t, int,
174
struct nfsfh *, int, int, int, int, struct ucred *, NFSPROC_T *);
175
static int nfsio_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *,
176
struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int,
177
struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *);
178
static int nfsrpc_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *,
179
struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int,
180
struct ucred *, NFSPROC_T *);
181
static enum nfsclds_state nfscl_getsameserver(struct nfsmount *,
182
struct nfsclds *, struct nfsclds **, uint32_t *);
183
static int nfsio_commitds(vnode_t, uint64_t, int, struct nfsclds *,
184
struct nfsfh *, int, int, struct nfsclwritedsdorpc *, struct ucred *,
185
NFSPROC_T *);
186
static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *,
187
struct nfsfh *, int, int, struct ucred *, NFSPROC_T *);
188
#ifdef notyet
189
static int nfsio_adviseds(vnode_t, uint64_t, int, int, struct nfsclds *,
190
struct nfsfh *, int, int, struct nfsclwritedsdorpc *, struct ucred *,
191
NFSPROC_T *);
192
static int nfsrpc_adviseds(vnode_t, uint64_t, int, int, struct nfsclds *,
193
struct nfsfh *, int, int, struct ucred *, NFSPROC_T *);
194
#endif
195
static int nfsrpc_allocaterpc(vnode_t, off_t, off_t, nfsv4stateid_t *,
196
struct nfsvattr *, int *, struct ucred *, NFSPROC_T *);
197
static void nfsrv_setuplayoutget(struct nfsrv_descript *, int, uint64_t,
198
uint64_t, uint64_t, nfsv4stateid_t *, int, int, int);
199
static int nfsrv_parseug(struct nfsrv_descript *, int, uid_t *, gid_t *,
200
NFSPROC_T *);
201
static int nfsrv_parselayoutget(struct nfsmount *, struct nfsrv_descript *,
202
nfsv4stateid_t *, int *, struct nfsclflayouthead *);
203
static int nfsrpc_getopenlayout(struct nfsmount *, vnode_t, u_int8_t *,
204
int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int,
205
struct nfscldeleg **, struct ucred *, NFSPROC_T *);
206
static int nfsrpc_getcreatelayout(vnode_t, char *, int, struct vattr *,
207
nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **,
208
struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
209
struct nfsfh **, int *, int *, int *);
210
static int nfsrpc_openlayoutrpc(struct nfsmount *, vnode_t, u_int8_t *,
211
int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int,
212
struct nfscldeleg **, nfsv4stateid_t *, int, int, int, int *,
213
struct nfsclflayouthead *, int *, struct ucred *, NFSPROC_T *);
214
static int nfsrpc_createlayout(vnode_t, char *, int, struct vattr *,
215
nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **,
216
struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
217
struct nfsfh **, int *, int *, int *, nfsv4stateid_t *,
218
int, int, int, int *, struct nfsclflayouthead *, int *);
219
static int nfsrpc_layoutget(struct nfsmount *, uint8_t *, int, int, uint64_t,
220
uint64_t, uint64_t, int, int, nfsv4stateid_t *, int *,
221
struct nfsclflayouthead *, struct ucred *, NFSPROC_T *);
222
static int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_t *,
223
int, nfsv4stateid_t *, int, uint32_t *, struct nfscllayout **,
224
struct nfsclflayouthead *, int, int, int *, struct ucred *, NFSPROC_T *);
225
static int nfsrpc_copyrpc(vnode_t, off_t, vnode_t, off_t, size_t *,
226
nfsv4stateid_t *, nfsv4stateid_t *, struct nfsvattr *, int *,
227
struct nfsvattr *, int *, bool, int *, struct ucred *, NFSPROC_T *);
228
static int nfsrpc_clonerpc(vnode_t, off_t, vnode_t, off_t, size_t *, bool,
229
nfsv4stateid_t *, nfsv4stateid_t *, struct nfsvattr *, int *,
230
struct nfsvattr *, int *, struct ucred *, NFSPROC_T *);
231
static int nfsrpc_seekrpc(vnode_t, off_t *, nfsv4stateid_t *, bool *,
232
int, struct nfsvattr *, int *, struct ucred *);
233
static struct mbuf *nfsm_split(struct mbuf *, uint64_t);
234
static void nfscl_statfs(struct vnode *, struct ucred *, NFSPROC_T *);
235
236
int nfs_pnfsio(task_fn_t *, void *);
237
238
/*
239
* nfs null call from vfs.
240
*/
241
int
242
nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p)
243
{
244
int error;
245
struct nfsrv_descript nfsd, *nd = &nfsd;
246
247
NFSCL_REQSTART(nd, NFSPROC_NULL, vp, NULL);
248
error = nfscl_request(nd, vp, p, cred);
249
if (nd->nd_repstat && !error)
250
error = nd->nd_repstat;
251
m_freem(nd->nd_mrep);
252
return (error);
253
}
254
255
/*
256
* nfs access rpc op.
257
* For nfs version 3 and 4, use the access rpc to check accessibility. If file
258
* modes are changed on the server, accesses might still fail later.
259
*/
260
int
261
nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred,
262
NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
263
{
264
int error;
265
u_int32_t mode, rmode;
266
267
if (acmode & VREAD)
268
mode = NFSACCESS_READ;
269
else
270
mode = 0;
271
if (vp->v_type == VDIR) {
272
if (acmode & VWRITE)
273
mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND |
274
NFSACCESS_DELETE);
275
if (acmode & VEXEC)
276
mode |= NFSACCESS_LOOKUP;
277
} else {
278
if (acmode & VWRITE)
279
mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND);
280
if (acmode & VEXEC)
281
mode |= NFSACCESS_EXECUTE;
282
}
283
284
/*
285
* Now, just call nfsrpc_accessrpc() to do the actual RPC.
286
*/
287
error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode);
288
289
/*
290
* The NFS V3 spec does not clarify whether or not
291
* the returned access bits can be a superset of
292
* the ones requested, so...
293
*/
294
if (!error && (rmode & mode) != mode)
295
error = EACCES;
296
return (error);
297
}
298
299
/*
300
* The actual rpc, separated out for Darwin.
301
*/
302
int
303
nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred,
304
NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep)
305
{
306
u_int32_t *tl;
307
u_int32_t supported, rmode;
308
int error;
309
struct nfsrv_descript nfsd, *nd = &nfsd;
310
nfsattrbit_t attrbits;
311
struct nfsmount *nmp;
312
struct nfsnode *np;
313
314
*attrflagp = 0;
315
supported = mode;
316
nmp = VFSTONFS(vp->v_mount);
317
np = VTONFS(vp);
318
if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
319
nmp->nm_fhsize == 0) {
320
/* Attempt to get the actual root file handle. */
321
error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), cred, p);
322
if (error != 0)
323
return (EACCES);
324
if (np->n_fhp->nfh_len == NFSX_FHMAX + 1)
325
nfscl_statfs(vp, cred, p);
326
}
327
NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp, cred);
328
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
329
*tl = txdr_unsigned(mode);
330
if (nd->nd_flag & ND_NFSV4) {
331
/*
332
* And do a Getattr op.
333
*/
334
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
335
*tl = txdr_unsigned(NFSV4OP_GETATTR);
336
NFSGETATTR_ATTRBIT(&attrbits);
337
(void) nfsrv_putattrbit(nd, &attrbits);
338
}
339
error = nfscl_request(nd, vp, p, cred);
340
if (error)
341
return (error);
342
if (nd->nd_flag & ND_NFSV3) {
343
error = nfscl_postop_attr(nd, nap, attrflagp);
344
if (error)
345
goto nfsmout;
346
}
347
if (!nd->nd_repstat) {
348
if (nd->nd_flag & ND_NFSV4) {
349
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
350
supported = fxdr_unsigned(u_int32_t, *tl++);
351
} else {
352
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
353
}
354
rmode = fxdr_unsigned(u_int32_t, *tl);
355
if (nd->nd_flag & ND_NFSV4)
356
error = nfscl_postop_attr(nd, nap, attrflagp);
357
358
/*
359
* It's not obvious what should be done about
360
* unsupported access modes. For now, be paranoid
361
* and clear the unsupported ones.
362
*/
363
rmode &= supported;
364
*rmodep = rmode;
365
} else
366
error = nd->nd_repstat;
367
nfsmout:
368
m_freem(nd->nd_mrep);
369
return (error);
370
}
371
372
/*
373
* nfs open rpc
374
*/
375
int
376
nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p)
377
{
378
struct nfsclopen *op;
379
struct nfscldeleg *dp;
380
struct nfsfh *nfhp;
381
struct nfsnode *np = VTONFS(vp);
382
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
383
u_int32_t mode, clidrev;
384
int ret, newone, error, expireret = 0, retrycnt;
385
386
/*
387
* For NFSv4, Open Ops are only done on Regular Files.
388
*/
389
if (vp->v_type != VREG)
390
return (0);
391
mode = 0;
392
if (amode & FREAD)
393
mode |= NFSV4OPEN_ACCESSREAD;
394
if (amode & FWRITE)
395
mode |= NFSV4OPEN_ACCESSWRITE;
396
if (NFSHASNFSV4N(nmp)) {
397
if (!NFSHASPNFS(nmp) && nfscl_enablecallb != 0 &&
398
nfs_numnfscbd > 0 &&
399
(vn_irflag_read(vp) & VIRF_NAMEDATTR) == 0) {
400
if ((mode & NFSV4OPEN_ACCESSWRITE) != 0)
401
mode |= NFSV4OPEN_WANTWRITEDELEG;
402
else
403
mode |= NFSV4OPEN_WANTANYDELEG;
404
} else
405
mode |= NFSV4OPEN_WANTNODELEG;
406
}
407
nfhp = np->n_fhp;
408
409
retrycnt = 0;
410
do {
411
dp = NULL;
412
error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len,
413
(mode & NFSV4OPEN_ACCESSBOTH), 1, cred, p, NULL,
414
&op, &newone, &ret, 1, true);
415
if (error) {
416
return (error);
417
}
418
if (nmp->nm_clp != NULL)
419
clidrev = nmp->nm_clp->nfsc_clientidrev;
420
else
421
clidrev = 0;
422
if (ret == NFSCLOPEN_DOOPEN) {
423
if (np->n_v4 != NULL) {
424
/*
425
* For the first attempt, try and get a layout, if
426
* pNFS is enabled for the mount.
427
*/
428
if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 ||
429
nfs_numnfscbd == 0 ||
430
(np->n_flag & NNOLAYOUT) != 0 || retrycnt > 0)
431
error = nfsrpc_openrpc(nmp, vp,
432
np->n_v4->n4_data,
433
np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
434
np->n_fhp->nfh_len, mode, op,
435
NFS4NODENAME(np->n_v4),
436
np->n_v4->n4_namelen,
437
&dp, 0, 0x0, cred, p, 0, 0);
438
else
439
error = nfsrpc_getopenlayout(nmp, vp,
440
np->n_v4->n4_data,
441
np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
442
np->n_fhp->nfh_len, mode, op,
443
NFS4NODENAME(np->n_v4),
444
np->n_v4->n4_namelen, &dp, cred, p);
445
if (dp != NULL) {
446
NFSLOCKNODE(np);
447
np->n_flag &= ~NDELEGMOD;
448
/*
449
* Invalidate the attribute cache, so that
450
* attributes that pre-date the issue of a
451
* delegation are not cached, since the
452
* cached attributes will remain valid while
453
* the delegation is held.
454
*/
455
NFSINVALATTRCACHE(np);
456
NFSUNLOCKNODE(np);
457
(void) nfscl_deleg(nmp->nm_mountp,
458
op->nfso_own->nfsow_clp,
459
nfhp->nfh_fh, nfhp->nfh_len, cred, p, dp);
460
}
461
} else if (NFSHASNFSV4N(nmp)) {
462
/*
463
* For the first attempt, try and get a layout, if
464
* pNFS is enabled for the mount.
465
*/
466
if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 ||
467
nfs_numnfscbd == 0 ||
468
(np->n_flag & NNOLAYOUT) != 0 || retrycnt > 0)
469
error = nfsrpc_openrpc(nmp, vp, nfhp->nfh_fh,
470
nfhp->nfh_len, nfhp->nfh_fh, nfhp->nfh_len,
471
mode, op, NULL, 0, &dp, 0, 0x0, cred, p, 0,
472
0);
473
else
474
error = nfsrpc_getopenlayout(nmp, vp,
475
nfhp->nfh_fh, nfhp->nfh_len, nfhp->nfh_fh,
476
nfhp->nfh_len, mode, op, NULL, 0, &dp,
477
cred, p);
478
if (dp != NULL) {
479
NFSLOCKNODE(np);
480
np->n_flag &= ~NDELEGMOD;
481
/*
482
* Invalidate the attribute cache, so that
483
* attributes that pre-date the issue of a
484
* delegation are not cached, since the
485
* cached attributes will remain valid while
486
* the delegation is held.
487
*/
488
NFSINVALATTRCACHE(np);
489
NFSUNLOCKNODE(np);
490
(void) nfscl_deleg(nmp->nm_mountp,
491
op->nfso_own->nfsow_clp,
492
nfhp->nfh_fh, nfhp->nfh_len, cred, p, dp);
493
}
494
} else {
495
error = EIO;
496
}
497
newnfs_copyincred(cred, &op->nfso_cred);
498
} else if (ret == NFSCLOPEN_SETCRED)
499
/*
500
* This is a new local open on a delegation. It needs
501
* to have credentials so that an open can be done
502
* against the server during recovery.
503
*/
504
newnfs_copyincred(cred, &op->nfso_cred);
505
506
/*
507
* nfso_opencnt is the count of how many VOP_OPEN()s have
508
* been done on this Open successfully and a VOP_CLOSE()
509
* is expected for each of these.
510
* If error is non-zero, don't increment it, since the Open
511
* hasn't succeeded yet.
512
*/
513
if (!error) {
514
op->nfso_opencnt++;
515
if (NFSHASNFSV4N(nmp) && NFSHASONEOPENOWN(nmp)) {
516
NFSLOCKNODE(np);
517
np->n_openstateid = op;
518
NFSUNLOCKNODE(np);
519
}
520
}
521
nfscl_openrelease(nmp, op, error, newone);
522
if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
523
error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
524
error == NFSERR_BADSESSION) {
525
(void) nfs_catnap(PZERO, error, "nfs_open");
526
} else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
527
&& clidrev != 0) {
528
expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
529
retrycnt++;
530
}
531
} while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
532
error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
533
error == NFSERR_BADSESSION ||
534
((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
535
expireret == 0 && clidrev != 0 && retrycnt < 4));
536
if (error && retrycnt >= 4)
537
error = EIO;
538
return (error);
539
}
540
541
/*
542
* the actual open rpc
543
*/
544
int
545
nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
546
u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op,
547
u_int8_t *name, int namelen, struct nfscldeleg **dpp,
548
int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p,
549
int syscred, int recursed)
550
{
551
u_int32_t *tl;
552
struct nfsrv_descript nfsd, *nd = &nfsd;
553
struct nfscldeleg *dp, *ndp = NULL;
554
struct nfsvattr nfsva;
555
u_int32_t rflags, deleg;
556
nfsattrbit_t attrbits;
557
int error, ret, acesize, limitby;
558
struct nfsclsession *tsep;
559
560
dp = *dpp;
561
*dpp = NULL;
562
nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL, NULL, 0, 0,
563
cred);
564
NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
565
*tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
566
*tl++ = txdr_unsigned(mode & (NFSV4OPEN_ACCESSBOTH |
567
NFSV4OPEN_WANTDELEGMASK));
568
*tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
569
tsep = nfsmnt_mdssession(nmp);
570
*tl++ = tsep->nfsess_clientid.lval[0];
571
*tl = tsep->nfsess_clientid.lval[1];
572
(void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
573
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
574
*tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
575
if (reclaim) {
576
*tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS);
577
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
578
*tl = txdr_unsigned(delegtype);
579
} else {
580
if (dp != NULL) {
581
if (NFSHASNFSV4N(nmp))
582
*tl = txdr_unsigned(
583
NFSV4OPEN_CLAIMDELEGATECURFH);
584
else
585
*tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR);
586
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
587
if (NFSHASNFSV4N(nmp))
588
*tl++ = 0;
589
else
590
*tl++ = dp->nfsdl_stateid.seqid;
591
*tl++ = dp->nfsdl_stateid.other[0];
592
*tl++ = dp->nfsdl_stateid.other[1];
593
*tl = dp->nfsdl_stateid.other[2];
594
if (!NFSHASNFSV4N(nmp))
595
(void)nfsm_strtom(nd, name, namelen);
596
} else if (NFSHASNFSV4N(nmp)) {
597
*tl = txdr_unsigned(NFSV4OPEN_CLAIMFH);
598
} else {
599
*tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
600
(void)nfsm_strtom(nd, name, namelen);
601
}
602
}
603
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
604
*tl = txdr_unsigned(NFSV4OP_GETATTR);
605
NFSZERO_ATTRBIT(&attrbits);
606
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
607
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
608
(void) nfsrv_putattrbit(nd, &attrbits);
609
if (syscred)
610
nd->nd_flag |= ND_USEGSSNAME;
611
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
612
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
613
if (error)
614
return (error);
615
NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
616
if (nd->nd_repstat == 0 || (nd->nd_repstat == NFSERR_DELAY &&
617
reclaim != 0 && (nd->nd_flag & ND_NOMOREDATA) == 0)) {
618
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
619
6 * NFSX_UNSIGNED);
620
op->nfso_stateid.seqid = *tl++;
621
op->nfso_stateid.other[0] = *tl++;
622
op->nfso_stateid.other[1] = *tl++;
623
op->nfso_stateid.other[2] = *tl;
624
rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
625
error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
626
if (error)
627
goto nfsmout;
628
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
629
deleg = fxdr_unsigned(u_int32_t, *tl);
630
if (deleg == NFSV4OPEN_DELEGATEREAD ||
631
deleg == NFSV4OPEN_DELEGATEWRITE) {
632
if (!(op->nfso_own->nfsow_clp->nfsc_flags &
633
NFSCLFLAGS_FIRSTDELEG))
634
op->nfso_own->nfsow_clp->nfsc_flags |=
635
(NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
636
ndp = malloc(
637
sizeof (struct nfscldeleg) + newfhlen,
638
M_NFSCLDELEG, M_WAITOK);
639
LIST_INIT(&ndp->nfsdl_owner);
640
LIST_INIT(&ndp->nfsdl_lock);
641
ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
642
ndp->nfsdl_fhlen = newfhlen;
643
NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
644
newnfs_copyincred(cred, &ndp->nfsdl_cred);
645
nfscl_lockinit(&ndp->nfsdl_rwlock);
646
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
647
NFSX_UNSIGNED);
648
ndp->nfsdl_stateid.seqid = *tl++;
649
ndp->nfsdl_stateid.other[0] = *tl++;
650
ndp->nfsdl_stateid.other[1] = *tl++;
651
ndp->nfsdl_stateid.other[2] = *tl++;
652
ret = fxdr_unsigned(int, *tl);
653
if (deleg == NFSV4OPEN_DELEGATEWRITE) {
654
ndp->nfsdl_flags = NFSCLDL_WRITE;
655
/*
656
* Indicates how much the file can grow.
657
*/
658
NFSM_DISSECT(tl, u_int32_t *,
659
3 * NFSX_UNSIGNED);
660
limitby = fxdr_unsigned(int, *tl++);
661
switch (limitby) {
662
case NFSV4OPEN_LIMITSIZE:
663
ndp->nfsdl_sizelimit = fxdr_hyper(tl);
664
break;
665
case NFSV4OPEN_LIMITBLOCKS:
666
ndp->nfsdl_sizelimit =
667
fxdr_unsigned(u_int64_t, *tl++);
668
ndp->nfsdl_sizelimit *=
669
fxdr_unsigned(u_int64_t, *tl);
670
break;
671
default:
672
error = NFSERR_BADXDR;
673
goto nfsmout;
674
}
675
} else {
676
ndp->nfsdl_flags = NFSCLDL_READ;
677
}
678
if (ret)
679
ndp->nfsdl_flags |= NFSCLDL_RECALL;
680
error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, false,
681
&ret, &acesize);
682
if (error)
683
goto nfsmout;
684
} else if (deleg == NFSV4OPEN_DELEGATENONEEXT &&
685
NFSHASNFSV4N(nmp)) {
686
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
687
deleg = fxdr_unsigned(uint32_t, *tl);
688
if (deleg == NFSV4OPEN_CONTENTION ||
689
deleg == NFSV4OPEN_RESOURCE)
690
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
691
} else if (deleg != NFSV4OPEN_DELEGATENONE) {
692
error = NFSERR_BADXDR;
693
goto nfsmout;
694
}
695
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
696
/* If the 2nd element == NFS_OK, the Getattr succeeded. */
697
if (*++tl == 0) {
698
KASSERT(nd->nd_repstat == 0,
699
("nfsrpc_openrpc: Getattr repstat"));
700
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
701
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
702
NULL, NULL, NULL, NULL, NULL, NULL, p, cred);
703
if (error)
704
goto nfsmout;
705
}
706
if (ndp != NULL) {
707
if (reclaim != 0 && dp != NULL) {
708
ndp->nfsdl_change = dp->nfsdl_change;
709
ndp->nfsdl_modtime = dp->nfsdl_modtime;
710
ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
711
} else if (nd->nd_repstat == 0) {
712
ndp->nfsdl_change = nfsva.na_filerev;
713
ndp->nfsdl_modtime = nfsva.na_mtime;
714
ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
715
} else
716
ndp->nfsdl_flags |= NFSCLDL_RECALL;
717
}
718
nd->nd_repstat = 0;
719
if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) {
720
do {
721
ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op,
722
cred, p);
723
if (ret == NFSERR_DELAY)
724
(void) nfs_catnap(PZERO, ret, "nfs_open");
725
} while (ret == NFSERR_DELAY);
726
error = ret;
727
}
728
if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) ||
729
nfscl_assumeposixlocks)
730
op->nfso_posixlock = 1;
731
else
732
op->nfso_posixlock = 0;
733
734
/*
735
* If the server is handing out delegations, but we didn't
736
* get one because an OpenConfirm was required, try the
737
* Open again, to get a delegation. This is a harmless no-op,
738
* from a server's point of view.
739
*/
740
if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) &&
741
(op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG)
742
&& !error && dp == NULL && ndp == NULL && !recursed) {
743
do {
744
ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp,
745
newfhlen, mode, op, name, namelen, &ndp, 0, 0x0,
746
cred, p, syscred, 1);
747
if (ret == NFSERR_DELAY)
748
(void) nfs_catnap(PZERO, ret, "nfs_open2");
749
} while (ret == NFSERR_DELAY);
750
if (ret) {
751
if (ndp != NULL) {
752
free(ndp, M_NFSCLDELEG);
753
ndp = NULL;
754
}
755
if (ret == NFSERR_STALECLIENTID ||
756
ret == NFSERR_STALEDONTRECOVER ||
757
ret == NFSERR_BADSESSION)
758
error = ret;
759
}
760
}
761
}
762
if (nd->nd_repstat != 0 && error == 0)
763
error = nd->nd_repstat;
764
if (error == NFSERR_STALECLIENTID)
765
nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
766
nfsmout:
767
if (!error)
768
*dpp = ndp;
769
else if (ndp != NULL)
770
free(ndp, M_NFSCLDELEG);
771
m_freem(nd->nd_mrep);
772
return (error);
773
}
774
775
/*
776
* open downgrade rpc
777
*/
778
int
779
nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op,
780
struct ucred *cred, NFSPROC_T *p)
781
{
782
u_int32_t *tl;
783
struct nfsrv_descript nfsd, *nd = &nfsd;
784
int error;
785
786
NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp, cred);
787
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
788
if (NFSHASNFSV4N(VFSTONFS(vp->v_mount)))
789
*tl++ = 0;
790
else
791
*tl++ = op->nfso_stateid.seqid;
792
*tl++ = op->nfso_stateid.other[0];
793
*tl++ = op->nfso_stateid.other[1];
794
*tl++ = op->nfso_stateid.other[2];
795
*tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
796
*tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
797
*tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
798
error = nfscl_request(nd, vp, p, cred);
799
if (error)
800
return (error);
801
NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
802
if (!nd->nd_repstat) {
803
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
804
op->nfso_stateid.seqid = *tl++;
805
op->nfso_stateid.other[0] = *tl++;
806
op->nfso_stateid.other[1] = *tl++;
807
op->nfso_stateid.other[2] = *tl;
808
}
809
if (nd->nd_repstat && error == 0)
810
error = nd->nd_repstat;
811
if (error == NFSERR_STALESTATEID)
812
nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
813
nfsmout:
814
m_freem(nd->nd_mrep);
815
return (error);
816
}
817
818
/*
819
* V4 Close operation.
820
*/
821
int
822
nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p)
823
{
824
struct nfsclclient *clp;
825
int error;
826
827
if (vp->v_type != VREG)
828
return (0);
829
if (doclose)
830
error = nfscl_doclose(vp, &clp, p);
831
else {
832
error = nfscl_getclose(vp, &clp);
833
if (error == 0)
834
nfscl_clientrelease(clp);
835
}
836
return (error);
837
}
838
839
/*
840
* Close the open.
841
*/
842
int
843
nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p,
844
bool loop_on_delayed, bool freeop)
845
{
846
struct nfsrv_descript nfsd, *nd = &nfsd;
847
struct nfscllockowner *lp, *nlp;
848
struct nfscllock *lop, *nlop;
849
struct ucred *tcred;
850
u_int64_t off = 0, len = 0;
851
u_int32_t type = NFSV4LOCKT_READ;
852
int error, do_unlock, trycnt;
853
bool own_not_null;
854
855
tcred = newnfs_getcred();
856
newnfs_copycred(&op->nfso_cred, tcred);
857
/*
858
* (Theoretically this could be done in the same
859
* compound as the close, but having multiple
860
* sequenced Ops in the same compound might be
861
* too scary for some servers.)
862
*/
863
if (op->nfso_posixlock) {
864
off = 0;
865
len = NFS64BITSSET;
866
type = NFSV4LOCKT_READ;
867
}
868
869
/*
870
* Since this function is only called from VOP_INACTIVE(), no
871
* other thread will be manipulating this Open. As such, the
872
* lock lists are not being changed by other threads, so it should
873
* be safe to do this without locking.
874
*/
875
LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
876
do_unlock = 1;
877
LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
878
if (op->nfso_posixlock == 0) {
879
off = lop->nfslo_first;
880
len = lop->nfslo_end - lop->nfslo_first;
881
if (lop->nfslo_type == F_WRLCK)
882
type = NFSV4LOCKT_WRITE;
883
else
884
type = NFSV4LOCKT_READ;
885
}
886
if (do_unlock) {
887
trycnt = 0;
888
do {
889
error = nfsrpc_locku(nd, nmp, lp, off,
890
len, type, tcred, p, 0);
891
if ((nd->nd_repstat == NFSERR_GRACE ||
892
nd->nd_repstat == NFSERR_DELAY) &&
893
error == 0)
894
(void) nfs_catnap(PZERO,
895
(int)nd->nd_repstat,
896
"nfs_close");
897
} while ((nd->nd_repstat == NFSERR_GRACE ||
898
nd->nd_repstat == NFSERR_DELAY) &&
899
error == 0 && trycnt++ < 5);
900
if (op->nfso_posixlock)
901
do_unlock = 0;
902
}
903
nfscl_freelock(lop, 0);
904
}
905
/*
906
* Do a ReleaseLockOwner.
907
* The lock owner name nfsl_owner may be used by other opens for
908
* other files but the lock_owner4 name that nfsrpc_rellockown()
909
* puts on the wire has the file handle for this file appended
910
* to it, so it can be done now.
911
*/
912
(void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh,
913
lp->nfsl_open->nfso_fhlen, tcred, p);
914
}
915
916
/*
917
* There could be other Opens for different files on the same
918
* OpenOwner, so locking is required.
919
*/
920
own_not_null = false;
921
if (op->nfso_own != NULL) {
922
own_not_null = true;
923
NFSLOCKCLSTATE();
924
nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
925
NFSUNLOCKCLSTATE();
926
}
927
do {
928
error = nfscl_tryclose(op, tcred, nmp, p, loop_on_delayed);
929
if (error == NFSERR_GRACE)
930
(void) nfs_catnap(PZERO, error, "nfs_close");
931
} while (error == NFSERR_GRACE);
932
if (own_not_null) {
933
NFSLOCKCLSTATE();
934
nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
935
}
936
937
LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp)
938
nfscl_freelockowner(lp, 0);
939
if (freeop && error != NFSERR_DELAY)
940
nfscl_freeopen(op, 0, true);
941
if (own_not_null)
942
NFSUNLOCKCLSTATE();
943
NFSFREECRED(tcred);
944
return (error);
945
}
946
947
/*
948
* The actual Close RPC.
949
*/
950
int
951
nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp,
952
struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p,
953
int syscred)
954
{
955
u_int32_t *tl;
956
int error;
957
958
nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh,
959
op->nfso_fhlen, NULL, NULL, 0, 0, cred);
960
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
961
if (NFSHASNFSV4N(nmp)) {
962
*tl++ = 0;
963
*tl++ = 0;
964
} else {
965
*tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
966
*tl++ = op->nfso_stateid.seqid;
967
}
968
*tl++ = op->nfso_stateid.other[0];
969
*tl++ = op->nfso_stateid.other[1];
970
*tl = op->nfso_stateid.other[2];
971
if (syscred)
972
nd->nd_flag |= ND_USEGSSNAME;
973
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
974
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
975
if (error)
976
return (error);
977
if (!NFSHASNFSV4N(nmp))
978
NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
979
if (nd->nd_repstat == 0)
980
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
981
error = nd->nd_repstat;
982
if (!NFSHASNFSV4N(nmp) && error == NFSERR_STALESTATEID)
983
nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
984
nfsmout:
985
m_freem(nd->nd_mrep);
986
return (error);
987
}
988
989
/*
990
* V4 Open Confirm RPC.
991
*/
992
int
993
nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen,
994
struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p)
995
{
996
u_int32_t *tl;
997
struct nfsrv_descript nfsd, *nd = &nfsd;
998
struct nfsmount *nmp;
999
int error;
1000
1001
nmp = VFSTONFS(vp->v_mount);
1002
if (NFSHASNFSV4N(nmp))
1003
return (0); /* No confirmation for NFSv4.1. */
1004
nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, nmp, nfhp, fhlen, NULL, NULL,
1005
0, 0, NULL);
1006
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
1007
*tl++ = op->nfso_stateid.seqid;
1008
*tl++ = op->nfso_stateid.other[0];
1009
*tl++ = op->nfso_stateid.other[1];
1010
*tl++ = op->nfso_stateid.other[2];
1011
*tl = txdr_unsigned(op->nfso_own->nfsow_seqid);
1012
error = nfscl_request(nd, vp, p, cred);
1013
if (error)
1014
return (error);
1015
NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
1016
if (!nd->nd_repstat) {
1017
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
1018
op->nfso_stateid.seqid = *tl++;
1019
op->nfso_stateid.other[0] = *tl++;
1020
op->nfso_stateid.other[1] = *tl++;
1021
op->nfso_stateid.other[2] = *tl;
1022
}
1023
error = nd->nd_repstat;
1024
if (error == NFSERR_STALESTATEID)
1025
nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
1026
nfsmout:
1027
m_freem(nd->nd_mrep);
1028
return (error);
1029
}
1030
1031
/*
1032
* Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs()
1033
* when a mount has just occurred and when the server replies NFSERR_EXPIRED.
1034
*/
1035
int
1036
nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim,
1037
bool *retokp, struct ucred *cred, NFSPROC_T *p)
1038
{
1039
u_int32_t *tl;
1040
struct nfsrv_descript nfsd;
1041
struct nfsrv_descript *nd = &nfsd;
1042
u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9];
1043
u_short port;
1044
int error, isinet6 = 0, callblen;
1045
nfsquad_t confirm;
1046
static u_int32_t rev = 0;
1047
struct nfsclds *dsp, *odsp;
1048
struct in6_addr a6;
1049
struct nfsclsession *tsep;
1050
struct rpc_reconupcall recon;
1051
struct nfscl_reconarg *rcp;
1052
1053
if (nfsboottime.tv_sec == 0)
1054
NFSSETBOOTTIME(nfsboottime);
1055
if (NFSHASNFSV4N(nmp)) {
1056
error = NFSERR_BADSESSION;
1057
odsp = dsp = NULL;
1058
if (retokp != NULL) {
1059
NFSLOCKMNT(nmp);
1060
odsp = TAILQ_FIRST(&nmp->nm_sess);
1061
NFSUNLOCKMNT(nmp);
1062
}
1063
if (odsp != NULL) {
1064
/*
1065
* When a session already exists, first try a
1066
* CreateSession with the extant ClientID.
1067
*/
1068
dsp = malloc(sizeof(struct nfsclds) +
1069
odsp->nfsclds_servownlen + 1, M_NFSCLDS,
1070
M_WAITOK | M_ZERO);
1071
dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew;
1072
dsp->nfsclds_servownlen = odsp->nfsclds_servownlen;
1073
dsp->nfsclds_sess.nfsess_clientid =
1074
odsp->nfsclds_sess.nfsess_clientid;
1075
dsp->nfsclds_sess.nfsess_sequenceid =
1076
odsp->nfsclds_sess.nfsess_sequenceid + 1;
1077
dsp->nfsclds_flags = odsp->nfsclds_flags;
1078
if (dsp->nfsclds_servownlen > 0)
1079
memcpy(dsp->nfsclds_serverown,
1080
odsp->nfsclds_serverown,
1081
dsp->nfsclds_servownlen + 1);
1082
mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
1083
mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
1084
NULL, MTX_DEF);
1085
nfscl_initsessionslots(&dsp->nfsclds_sess);
1086
error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
1087
&nmp->nm_sockreq, NULL,
1088
dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p);
1089
NFSCL_DEBUG(1, "create session for extant "
1090
"ClientID=%d\n", error);
1091
if (error != 0) {
1092
nfscl_freenfsclds(dsp);
1093
dsp = NULL;
1094
/*
1095
* If *retokp is true, return any error other
1096
* than NFSERR_STALECLIENTID,
1097
* NFSERR_BADSESSION or NFSERR_STALEDONTRECOVER
1098
* so that nfscl_recover() will not loop.
1099
*/
1100
if (*retokp)
1101
return (NFSERR_IO);
1102
} else
1103
*retokp = true;
1104
} else if (retokp != NULL && *retokp)
1105
return (NFSERR_IO);
1106
if (error != 0) {
1107
/*
1108
* Either there was no previous session or the
1109
* CreateSession attempt failed, so...
1110
* do an ExchangeID followed by the CreateSession.
1111
*/
1112
clp->nfsc_rev = rev++;
1113
error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq, 0,
1114
NFSV4EXCH_USEPNFSMDS | NFSV4EXCH_USENONPNFS, &dsp,
1115
cred, p);
1116
NFSCL_DEBUG(1, "aft exch=%d\n", error);
1117
if (error == 0)
1118
error = nfsrpc_createsession(nmp,
1119
&dsp->nfsclds_sess, &nmp->nm_sockreq, NULL,
1120
dsp->nfsclds_sess.nfsess_sequenceid, 1,
1121
cred, p);
1122
NFSCL_DEBUG(1, "aft createsess=%d\n", error);
1123
}
1124
if (error == 0) {
1125
/*
1126
* If the session supports a backchannel, set up
1127
* the BindConnectionToSession call in the krpc
1128
* so that it is done on a reconnection.
1129
*/
1130
if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0) {
1131
rcp = mem_alloc(sizeof(*rcp));
1132
rcp->minorvers = nmp->nm_minorvers;
1133
memcpy(rcp->sessionid,
1134
dsp->nfsclds_sess.nfsess_sessionid,
1135
NFSX_V4SESSIONID);
1136
recon.call = nfsrpc_bindconnsess;
1137
recon.arg = rcp;
1138
CLNT_CONTROL(nmp->nm_client, CLSET_RECONUPCALL,
1139
&recon);
1140
}
1141
1142
NFSLOCKMNT(nmp);
1143
/*
1144
* The old sessions cannot be safely free'd
1145
* here, since they may still be used by
1146
* in-progress RPCs.
1147
*/
1148
tsep = NULL;
1149
if (TAILQ_FIRST(&nmp->nm_sess) != NULL) {
1150
/*
1151
* Mark the old session defunct. Needed
1152
* when called from nfscl_hasexpired().
1153
*/
1154
tsep = NFSMNT_MDSSESSION(nmp);
1155
tsep->nfsess_defunct = 1;
1156
}
1157
TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp,
1158
nfsclds_list);
1159
/*
1160
* Wake up RPCs waiting for a slot on the
1161
* old session. These will then fail with
1162
* NFSERR_BADSESSION and be retried with the
1163
* new session by nfsv4_setsequence().
1164
* Also wakeup() processes waiting for the
1165
* new session.
1166
*/
1167
if (tsep != NULL)
1168
wakeup(&tsep->nfsess_slots);
1169
wakeup(&nmp->nm_sess);
1170
NFSUNLOCKMNT(nmp);
1171
} else if (dsp != NULL)
1172
nfscl_freenfsclds(dsp);
1173
if (error == 0 && reclaim == 0) {
1174
error = nfsrpc_reclaimcomplete(nmp, cred, p);
1175
NFSCL_DEBUG(1, "aft reclaimcomp=%d\n", error);
1176
if (error == NFSERR_COMPLETEALREADY ||
1177
error == NFSERR_NOTSUPP)
1178
/* Ignore this error. */
1179
error = 0;
1180
}
1181
return (error);
1182
} else if (retokp != NULL && *retokp)
1183
return (NFSERR_IO);
1184
clp->nfsc_rev = rev++;
1185
1186
/*
1187
* Allocate a single session structure for NFSv4.0, because some of
1188
* the fields are used by NFSv4.0 although it doesn't do a session.
1189
*/
1190
dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, M_WAITOK | M_ZERO);
1191
mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
1192
mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF);
1193
NFSLOCKMNT(nmp);
1194
TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, nfsclds_list);
1195
tsep = NFSMNT_MDSSESSION(nmp);
1196
NFSUNLOCKMNT(nmp);
1197
1198
nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL, NULL, 0, 0,
1199
NULL);
1200
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1201
*tl++ = txdr_unsigned(nfsboottime.tv_sec);
1202
*tl = txdr_unsigned(clp->nfsc_rev);
1203
(void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
1204
1205
/*
1206
* set up the callback address
1207
*/
1208
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1209
*tl = txdr_unsigned(NFS_CALLBCKPROG);
1210
callblen = strlen(nfsv4_callbackaddr);
1211
if (callblen == 0)
1212
cp = nfscl_getmyip(nmp, &a6, &isinet6);
1213
if (nfscl_enablecallb && nfs_numnfscbd > 0 &&
1214
(callblen > 0 || cp != NULL)) {
1215
port = htons(nfsv4_cbport);
1216
cp2 = (u_int8_t *)&port;
1217
#ifdef INET6
1218
if ((callblen > 0 &&
1219
strchr(nfsv4_callbackaddr, ':')) || isinet6) {
1220
char ip6buf[INET6_ADDRSTRLEN], *ip6add;
1221
1222
(void) nfsm_strtom(nd, "tcp6", 4);
1223
if (callblen == 0) {
1224
ip6_sprintf(ip6buf, (struct in6_addr *)cp);
1225
ip6add = ip6buf;
1226
} else {
1227
ip6add = nfsv4_callbackaddr;
1228
}
1229
snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d",
1230
ip6add, cp2[0], cp2[1]);
1231
} else
1232
#endif
1233
{
1234
(void) nfsm_strtom(nd, "tcp", 3);
1235
if (callblen == 0)
1236
snprintf(addr, INET6_ADDRSTRLEN + 9,
1237
"%d.%d.%d.%d.%d.%d", cp[0], cp[1],
1238
cp[2], cp[3], cp2[0], cp2[1]);
1239
else
1240
snprintf(addr, INET6_ADDRSTRLEN + 9,
1241
"%s.%d.%d", nfsv4_callbackaddr,
1242
cp2[0], cp2[1]);
1243
}
1244
(void) nfsm_strtom(nd, addr, strlen(addr));
1245
} else {
1246
(void) nfsm_strtom(nd, "tcp", 3);
1247
(void) nfsm_strtom(nd, "0.0.0.0.0.0", 11);
1248
}
1249
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1250
*tl = txdr_unsigned(clp->nfsc_cbident);
1251
nd->nd_flag |= ND_USEGSSNAME;
1252
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
1253
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
1254
if (error)
1255
return (error);
1256
if (nd->nd_repstat == 0) {
1257
NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1258
tsep->nfsess_clientid.lval[0] = *tl++;
1259
tsep->nfsess_clientid.lval[1] = *tl++;
1260
confirm.lval[0] = *tl++;
1261
confirm.lval[1] = *tl;
1262
m_freem(nd->nd_mrep);
1263
nd->nd_mrep = NULL;
1264
1265
/*
1266
* and confirm it.
1267
*/
1268
nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL,
1269
NULL, 0, 0, NULL);
1270
NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1271
*tl++ = tsep->nfsess_clientid.lval[0];
1272
*tl++ = tsep->nfsess_clientid.lval[1];
1273
*tl++ = confirm.lval[0];
1274
*tl = confirm.lval[1];
1275
nd->nd_flag |= ND_USEGSSNAME;
1276
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
1277
cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
1278
if (error)
1279
return (error);
1280
m_freem(nd->nd_mrep);
1281
nd->nd_mrep = NULL;
1282
}
1283
error = nd->nd_repstat;
1284
nfsmout:
1285
m_freem(nd->nd_mrep);
1286
return (error);
1287
}
1288
1289
/*
1290
* nfs getattr call.
1291
*/
1292
int
1293
nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
1294
struct nfsvattr *nap)
1295
{
1296
struct nfsrv_descript nfsd, *nd = &nfsd;
1297
int error;
1298
nfsattrbit_t attrbits;
1299
struct nfsnode *np;
1300
struct nfsmount *nmp;
1301
1302
nmp = VFSTONFS(vp->v_mount);
1303
np = VTONFS(vp);
1304
if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
1305
nmp->nm_fhsize == 0) {
1306
/* Attempt to get the actual root file handle. */
1307
error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), cred, p);
1308
if (error != 0)
1309
return (EACCES);
1310
if (np->n_fhp->nfh_len == NFSX_FHMAX + 1)
1311
nfscl_statfs(vp, cred, p);
1312
}
1313
NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred);
1314
if (nd->nd_flag & ND_NFSV4) {
1315
NFSGETATTR_ATTRBIT(&attrbits);
1316
(void) nfsrv_putattrbit(nd, &attrbits);
1317
}
1318
error = nfscl_request(nd, vp, p, cred);
1319
if (error)
1320
return (error);
1321
if (!nd->nd_repstat)
1322
error = nfsm_loadattr(nd, nap);
1323
else
1324
error = nd->nd_repstat;
1325
m_freem(nd->nd_mrep);
1326
return (error);
1327
}
1328
1329
/*
1330
* nfs getattr call with non-vnode arguments.
1331
*/
1332
int
1333
nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred,
1334
struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp,
1335
uint32_t *leasep)
1336
{
1337
struct nfsrv_descript nfsd, *nd = &nfsd;
1338
int error, vers = NFS_VER2;
1339
nfsattrbit_t attrbits;
1340
1341
nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL, NULL, 0, 0,
1342
cred);
1343
if (nd->nd_flag & ND_NFSV4) {
1344
vers = NFS_VER4;
1345
NFSGETATTR_ATTRBIT(&attrbits);
1346
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
1347
(void) nfsrv_putattrbit(nd, &attrbits);
1348
} else if (nd->nd_flag & ND_NFSV3) {
1349
vers = NFS_VER3;
1350
}
1351
if (syscred)
1352
nd->nd_flag |= ND_USEGSSNAME;
1353
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
1354
NFS_PROG, vers, NULL, 1, xidp, NULL);
1355
if (error)
1356
return (error);
1357
if (nd->nd_repstat == 0) {
1358
if ((nd->nd_flag & ND_NFSV4) != 0)
1359
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
1360
NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL,
1361
NULL, NULL, NULL, NULL, NULL);
1362
else
1363
error = nfsm_loadattr(nd, nap);
1364
} else
1365
error = nd->nd_repstat;
1366
m_freem(nd->nd_mrep);
1367
return (error);
1368
}
1369
1370
/*
1371
* Do an nfs setattr operation.
1372
*/
1373
int
1374
nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp, acl_type_t aclt,
1375
struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp)
1376
{
1377
int error, expireret = 0, openerr, retrycnt;
1378
u_int32_t clidrev = 0, mode;
1379
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1380
struct nfsfh *nfhp;
1381
nfsv4stateid_t stateid;
1382
void *lckp;
1383
1384
if (nmp->nm_clp != NULL)
1385
clidrev = nmp->nm_clp->nfsc_clientidrev;
1386
if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size))
1387
mode = NFSV4OPEN_ACCESSWRITE;
1388
else
1389
mode = NFSV4OPEN_ACCESSREAD;
1390
retrycnt = 0;
1391
do {
1392
lckp = NULL;
1393
openerr = 1;
1394
if (NFSHASNFSV4(nmp)) {
1395
nfhp = VTONFS(vp)->n_fhp;
1396
error = nfscl_getstateid(vp, nfhp->nfh_fh,
1397
nfhp->nfh_len, mode, 0, cred, p, &stateid, &lckp);
1398
if (error && vp->v_type == VREG &&
1399
(mode == NFSV4OPEN_ACCESSWRITE ||
1400
nfstest_openallsetattr)) {
1401
/*
1402
* No Open stateid, so try and open the file
1403
* now.
1404
*/
1405
if (mode == NFSV4OPEN_ACCESSWRITE)
1406
openerr = nfsrpc_open(vp, FWRITE, cred,
1407
p);
1408
else
1409
openerr = nfsrpc_open(vp, FREAD, cred,
1410
p);
1411
if (!openerr)
1412
(void) nfscl_getstateid(vp,
1413
nfhp->nfh_fh, nfhp->nfh_len,
1414
mode, 0, cred, p, &stateid, &lckp);
1415
}
1416
}
1417
if (vap != NULL)
1418
error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p,
1419
rnap, attrflagp);
1420
else
1421
error = nfsrpc_setaclrpc(vp, cred, p, aclp, aclt,
1422
&stateid);
1423
if (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD) {
1424
NFSLOCKMNT(nmp);
1425
nmp->nm_state |= NFSSTA_OPENMODE;
1426
NFSUNLOCKMNT(nmp);
1427
}
1428
if (error == NFSERR_STALESTATEID)
1429
nfscl_initiate_recovery(nmp->nm_clp);
1430
if (lckp != NULL)
1431
nfscl_lockderef(lckp);
1432
if (!openerr)
1433
(void) nfsrpc_close(vp, 0, p);
1434
if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1435
error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1436
error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1437
(void) nfs_catnap(PZERO, error, "nfs_setattr");
1438
} else if ((error == NFSERR_EXPIRED ||
1439
((!NFSHASINT(nmp) || !NFSHASNFSV4N(nmp)) &&
1440
error == NFSERR_BADSTATEID)) && clidrev != 0) {
1441
expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1442
} else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp) &&
1443
NFSHASNFSV4N(nmp)) {
1444
error = EIO;
1445
}
1446
retrycnt++;
1447
} while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1448
error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1449
error == NFSERR_BADSESSION ||
1450
(error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1451
((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1452
expireret == 0 && clidrev != 0 && retrycnt < 4) ||
1453
(error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD &&
1454
retrycnt < 4));
1455
if (error && retrycnt >= 4)
1456
error = EIO;
1457
return (error);
1458
}
1459
1460
static int
1461
nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap,
1462
nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
1463
struct nfsvattr *rnap, int *attrflagp)
1464
{
1465
u_int32_t *tl;
1466
struct nfsrv_descript nfsd, *nd = &nfsd;
1467
int error;
1468
nfsattrbit_t attrbits;
1469
1470
*attrflagp = 0;
1471
NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp, cred);
1472
if (nd->nd_flag & ND_NFSV4)
1473
nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1474
vap->va_type = vp->v_type;
1475
nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0);
1476
if (nd->nd_flag & ND_NFSV3) {
1477
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1478
*tl = newnfs_false;
1479
} else if (nd->nd_flag & ND_NFSV4) {
1480
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1481
*tl = txdr_unsigned(NFSV4OP_GETATTR);
1482
NFSGETATTR_ATTRBIT(&attrbits);
1483
(void) nfsrv_putattrbit(nd, &attrbits);
1484
}
1485
error = nfscl_request(nd, vp, p, cred);
1486
if (error)
1487
return (error);
1488
if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
1489
error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, NULL);
1490
if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && !error)
1491
error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1492
if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error)
1493
error = nfscl_postop_attr(nd, rnap, attrflagp);
1494
m_freem(nd->nd_mrep);
1495
if (nd->nd_repstat && !error)
1496
error = nd->nd_repstat;
1497
return (error);
1498
}
1499
1500
/*
1501
* nfs lookup rpc
1502
*/
1503
int
1504
nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred,
1505
NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap,
1506
struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, uint32_t openmode)
1507
{
1508
uint32_t deleg, rflags, *tl;
1509
struct nfsrv_descript nfsd, *nd = &nfsd;
1510
struct nfsmount *nmp;
1511
struct nfsnode *np;
1512
struct nfsfh *nfhp;
1513
nfsattrbit_t attrbits;
1514
int error = 0, lookupp = 0, newone, ret, retop;
1515
uint8_t own[NFSV4CL_LOCKNAMELEN];
1516
struct nfsclopen *op;
1517
struct nfscldeleg *ndp;
1518
nfsv4stateid_t stateid;
1519
1520
*attrflagp = 0;
1521
*dattrflagp = 0;
1522
if (dvp->v_type != VDIR)
1523
return (ENOTDIR);
1524
nmp = VFSTONFS(dvp->v_mount);
1525
if (len > NFS_MAXNAMLEN)
1526
return (ENAMETOOLONG);
1527
if (NFSHASNFSV4(nmp) && len == 1 &&
1528
name[0] == '.') {
1529
/*
1530
* Just return the current dir's fh.
1531
*/
1532
np = VTONFS(dvp);
1533
nfhp = malloc(sizeof (struct nfsfh) +
1534
np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
1535
nfhp->nfh_len = np->n_fhp->nfh_len;
1536
NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
1537
*nfhpp = nfhp;
1538
return (0);
1539
}
1540
if (NFSHASNFSV4(nmp) && len == 2 &&
1541
name[0] == '.' && name[1] == '.') {
1542
lookupp = 1;
1543
openmode = 0;
1544
NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp, cred);
1545
} else if (openmode != 0) {
1546
NFSCL_REQSTART(nd, NFSPROC_LOOKUPOPEN, dvp, cred);
1547
nfsm_strtom(nd, name, len);
1548
} else {
1549
NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp, cred);
1550
(void) nfsm_strtom(nd, name, len);
1551
}
1552
if (nd->nd_flag & ND_NFSV4) {
1553
NFSGETATTR_ATTRBIT(&attrbits);
1554
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1555
*tl++ = txdr_unsigned(NFSV4OP_GETFH);
1556
*tl = txdr_unsigned(NFSV4OP_GETATTR);
1557
(void) nfsrv_putattrbit(nd, &attrbits);
1558
if (openmode != 0) {
1559
/* Test for a VREG file. */
1560
NFSZERO_ATTRBIT(&attrbits);
1561
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE);
1562
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
1563
*tl = txdr_unsigned(NFSV4OP_VERIFY);
1564
nfsrv_putattrbit(nd, &attrbits);
1565
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
1566
*tl++ = txdr_unsigned(NFSX_UNSIGNED);
1567
*tl = vtonfsv34_type(VREG);
1568
1569
/* Attempt the Open for VREG. */
1570
nfscl_filllockowner(NULL, own, F_POSIX);
1571
NFSM_BUILD(tl, uint32_t *, 6 * NFSX_UNSIGNED);
1572
*tl++ = txdr_unsigned(NFSV4OP_OPEN);
1573
*tl++ = 0; /* seqid, ignored. */
1574
*tl++ = txdr_unsigned(openmode | NFSV4OPEN_WANTNODELEG);
1575
*tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
1576
*tl++ = 0; /* ClientID, ignored. */
1577
*tl = 0;
1578
nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN);
1579
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
1580
*tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
1581
*tl = txdr_unsigned(NFSV4OPEN_CLAIMFH);
1582
}
1583
}
1584
error = nfscl_request(nd, dvp, p, cred);
1585
if (error)
1586
return (error);
1587
ndp = NULL;
1588
if (nd->nd_repstat) {
1589
/*
1590
* When an NFSv4 Lookupp returns ENOENT, it means that
1591
* the lookup is at the root of an fs, so return this dir.
1592
*/
1593
if (nd->nd_repstat == NFSERR_NOENT && lookupp) {
1594
np = VTONFS(dvp);
1595
nfhp = malloc(sizeof (struct nfsfh) +
1596
np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
1597
nfhp->nfh_len = np->n_fhp->nfh_len;
1598
NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
1599
*nfhpp = nfhp;
1600
m_freem(nd->nd_mrep);
1601
return (0);
1602
}
1603
if (nd->nd_flag & ND_NFSV3)
1604
error = nfscl_postop_attr(nd, dnap, dattrflagp);
1605
else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
1606
ND_NFSV4) {
1607
/* Load the directory attributes. */
1608
error = nfsm_loadattr(nd, dnap);
1609
if (error != 0)
1610
goto nfsmout;
1611
*dattrflagp = 1;
1612
}
1613
/* Check Lookup operation reply status. */
1614
if (openmode != 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) {
1615
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
1616
if (*++tl != 0)
1617
goto nfsmout;
1618
}
1619
/* Look for GetFH reply. */
1620
if (openmode != 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) {
1621
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
1622
if (*++tl != 0)
1623
goto nfsmout;
1624
error = nfsm_getfh(nd, nfhpp);
1625
if (error)
1626
goto nfsmout;
1627
}
1628
/* Look for Getattr reply. */
1629
if (openmode != 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) {
1630
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
1631
if (*++tl != 0)
1632
goto nfsmout;
1633
error = nfsm_loadattr(nd, nap);
1634
if (error == 0) {
1635
/*
1636
* We have now successfully completed the
1637
* lookup, so set nd_repstat to 0.
1638
*/
1639
nd->nd_repstat = 0;
1640
*attrflagp = 1;
1641
}
1642
}
1643
goto nfsmout;
1644
}
1645
if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
1646
/* Load the directory attributes. */
1647
error = nfsm_loadattr(nd, dnap);
1648
if (error != 0)
1649
goto nfsmout;
1650
*dattrflagp = 1;
1651
/* Skip over the Lookup and GetFH operation status values. */
1652
NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1653
}
1654
error = nfsm_getfh(nd, nfhpp);
1655
if (error)
1656
goto nfsmout;
1657
1658
error = nfscl_postop_attr(nd, nap, attrflagp);
1659
if (openmode != 0 && error == 0) {
1660
NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID +
1661
10 * NFSX_UNSIGNED);
1662
tl += 4; /* Skip over Verify+Open status. */
1663
stateid.seqid = *tl++;
1664
stateid.other[0] = *tl++;
1665
stateid.other[1] = *tl++;
1666
stateid.other[2] = *tl;
1667
rflags = fxdr_unsigned(uint32_t, *(tl + 6));
1668
error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1669
if (error != 0)
1670
goto nfsmout;
1671
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
1672
deleg = fxdr_unsigned(uint32_t, *tl);
1673
if (deleg == NFSV4OPEN_DELEGATEREAD ||
1674
deleg == NFSV4OPEN_DELEGATEWRITE) {
1675
/*
1676
* Just need to fill in the fields used by
1677
* nfscl_trydelegreturn().
1678
* Mark the mount point as acquiring
1679
* delegations, so NFSPROC_LOOKUPOPEN will
1680
* no longer be done.
1681
*/
1682
NFSLOCKMNT(nmp);
1683
nmp->nm_privflag |= NFSMNTP_DELEGISSUED;
1684
NFSUNLOCKMNT(nmp);
1685
ndp = malloc(sizeof(struct nfscldeleg) +
1686
(*nfhpp)->nfh_len, M_NFSCLDELEG, M_WAITOK);
1687
ndp->nfsdl_fhlen = (*nfhpp)->nfh_len;
1688
NFSBCOPY((*nfhpp)->nfh_fh, ndp->nfsdl_fh,
1689
ndp->nfsdl_fhlen);
1690
newnfs_copyincred(cred, &ndp->nfsdl_cred);
1691
NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
1692
ndp->nfsdl_stateid.seqid = *tl++;
1693
ndp->nfsdl_stateid.other[0] = *tl++;
1694
ndp->nfsdl_stateid.other[1] = *tl++;
1695
ndp->nfsdl_stateid.other[2] = *tl++;
1696
} else if (deleg == NFSV4OPEN_DELEGATENONEEXT &&
1697
NFSHASNFSV4N(nmp)) {
1698
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
1699
deleg = fxdr_unsigned(uint32_t, *tl);
1700
if (deleg == NFSV4OPEN_CONTENTION ||
1701
deleg == NFSV4OPEN_RESOURCE)
1702
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
1703
} else if (deleg != NFSV4OPEN_DELEGATENONE) {
1704
error = NFSERR_BADXDR;
1705
goto nfsmout;
1706
}
1707
ret = nfscl_open(dvp, (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len,
1708
openmode, 0, cred, p, NULL, &op, &newone, &retop, 1, true);
1709
if (ret != 0)
1710
goto nfsmout;
1711
if (newone != 0) {
1712
op->nfso_stateid.seqid = stateid.seqid;
1713
op->nfso_stateid.other[0] = stateid.other[0];
1714
op->nfso_stateid.other[1] = stateid.other[1];
1715
op->nfso_stateid.other[2] = stateid.other[2];
1716
op->nfso_mode = openmode;
1717
} else {
1718
op->nfso_stateid.seqid = stateid.seqid;
1719
if (retop == NFSCLOPEN_DOOPEN)
1720
op->nfso_mode |= openmode;
1721
}
1722
if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 ||
1723
nfscl_assumeposixlocks)
1724
op->nfso_posixlock = 1;
1725
else
1726
op->nfso_posixlock = 0;
1727
nfscl_openrelease(nmp, op, 0, 0);
1728
if (ndp != NULL) {
1729
/*
1730
* Since we do not have the vnode, we
1731
* cannot invalidate cached attributes.
1732
* Just return the delegation.
1733
*/
1734
nfscl_trydelegreturn(ndp, cred, nmp, p);
1735
}
1736
}
1737
if ((nd->nd_flag & ND_NFSV3) && !error)
1738
error = nfscl_postop_attr(nd, dnap, dattrflagp);
1739
nfsmout:
1740
m_freem(nd->nd_mrep);
1741
if (!error && nd->nd_repstat)
1742
error = nd->nd_repstat;
1743
free(ndp, M_NFSCLDELEG);
1744
return (error);
1745
}
1746
1747
/*
1748
* Do a readlink rpc.
1749
*/
1750
int
1751
nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred,
1752
NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
1753
{
1754
u_int32_t *tl;
1755
struct nfsrv_descript nfsd, *nd = &nfsd;
1756
struct nfsnode *np = VTONFS(vp);
1757
nfsattrbit_t attrbits;
1758
int error, len, cangetattr = 1;
1759
1760
*attrflagp = 0;
1761
NFSCL_REQSTART(nd, NFSPROC_READLINK, vp, cred);
1762
if (nd->nd_flag & ND_NFSV4) {
1763
/*
1764
* And do a Getattr op.
1765
*/
1766
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1767
*tl = txdr_unsigned(NFSV4OP_GETATTR);
1768
NFSGETATTR_ATTRBIT(&attrbits);
1769
(void) nfsrv_putattrbit(nd, &attrbits);
1770
}
1771
error = nfscl_request(nd, vp, p, cred);
1772
if (error)
1773
return (error);
1774
if (nd->nd_flag & ND_NFSV3)
1775
error = nfscl_postop_attr(nd, nap, attrflagp);
1776
if (!nd->nd_repstat && !error) {
1777
NFSM_STRSIZ(len, NFS_MAXPATHLEN);
1778
/*
1779
* This seems weird to me, but must have been added to
1780
* FreeBSD for some reason. The only thing I can think of
1781
* is that there was/is some server that replies with
1782
* more link data than it should?
1783
*/
1784
if (len == NFS_MAXPATHLEN) {
1785
NFSLOCKNODE(np);
1786
if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) {
1787
len = np->n_size;
1788
cangetattr = 0;
1789
}
1790
NFSUNLOCKNODE(np);
1791
}
1792
error = nfsm_mbufuio(nd, uiop, len);
1793
if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr)
1794
error = nfscl_postop_attr(nd, nap, attrflagp);
1795
}
1796
if (nd->nd_repstat && !error)
1797
error = nd->nd_repstat;
1798
nfsmout:
1799
m_freem(nd->nd_mrep);
1800
return (error);
1801
}
1802
1803
/*
1804
* Read operation.
1805
*/
1806
int
1807
nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred,
1808
NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
1809
{
1810
int error, expireret = 0, retrycnt;
1811
u_int32_t clidrev = 0;
1812
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1813
struct nfsnode *np = VTONFS(vp);
1814
struct ucred *newcred;
1815
struct nfsfh *nfhp = NULL;
1816
nfsv4stateid_t stateid;
1817
void *lckp;
1818
1819
if (nmp->nm_clp != NULL)
1820
clidrev = nmp->nm_clp->nfsc_clientidrev;
1821
newcred = cred;
1822
if (NFSHASNFSV4(nmp)) {
1823
nfhp = np->n_fhp;
1824
newcred = NFSNEWCRED(cred);
1825
}
1826
retrycnt = 0;
1827
do {
1828
lckp = NULL;
1829
if (NFSHASNFSV4(nmp))
1830
(void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1831
NFSV4OPEN_ACCESSREAD, 0, newcred, p, &stateid,
1832
&lckp);
1833
error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap,
1834
attrflagp);
1835
if (error == NFSERR_OPENMODE) {
1836
NFSLOCKMNT(nmp);
1837
nmp->nm_state |= NFSSTA_OPENMODE;
1838
NFSUNLOCKMNT(nmp);
1839
}
1840
if (error == NFSERR_STALESTATEID)
1841
nfscl_initiate_recovery(nmp->nm_clp);
1842
if (lckp != NULL)
1843
nfscl_lockderef(lckp);
1844
if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1845
error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1846
error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
1847
(void) nfs_catnap(PZERO, error, "nfs_read");
1848
} else if ((error == NFSERR_EXPIRED ||
1849
((!NFSHASINT(nmp) || !NFSHASNFSV4N(nmp)) &&
1850
error == NFSERR_BADSTATEID)) && clidrev != 0) {
1851
expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
1852
} else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp) &&
1853
NFSHASNFSV4N(nmp)) {
1854
error = EIO;
1855
}
1856
retrycnt++;
1857
} while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
1858
error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
1859
error == NFSERR_BADSESSION ||
1860
(error == NFSERR_OLDSTATEID && retrycnt < 20) ||
1861
((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
1862
expireret == 0 && clidrev != 0 && retrycnt < 4) ||
1863
(error == NFSERR_OPENMODE && retrycnt < 4));
1864
if (error && retrycnt >= 4)
1865
error = EIO;
1866
if (NFSHASNFSV4(nmp))
1867
NFSFREECRED(newcred);
1868
return (error);
1869
}
1870
1871
/*
1872
* The actual read RPC.
1873
*/
1874
static int
1875
nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred,
1876
nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap,
1877
int *attrflagp)
1878
{
1879
u_int32_t *tl;
1880
int error = 0, len, retlen, tsiz, eof = 0;
1881
struct nfsrv_descript nfsd;
1882
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1883
struct nfsrv_descript *nd = &nfsd;
1884
int rsize;
1885
off_t tmp_off;
1886
1887
*attrflagp = 0;
1888
tsiz = uiop->uio_resid;
1889
tmp_off = uiop->uio_offset + tsiz;
1890
NFSLOCKMNT(nmp);
1891
if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
1892
NFSUNLOCKMNT(nmp);
1893
return (EFBIG);
1894
}
1895
rsize = nmp->nm_rsize;
1896
NFSUNLOCKMNT(nmp);
1897
nd->nd_mrep = NULL;
1898
while (tsiz > 0) {
1899
*attrflagp = 0;
1900
len = (tsiz > rsize) ? rsize : tsiz;
1901
NFSCL_REQSTART(nd, NFSPROC_READ, vp, cred);
1902
if (nd->nd_flag & ND_NFSV4)
1903
nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
1904
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3);
1905
if (nd->nd_flag & ND_NFSV2) {
1906
*tl++ = txdr_unsigned(uiop->uio_offset);
1907
*tl++ = txdr_unsigned(len);
1908
*tl = 0;
1909
} else {
1910
txdr_hyper(uiop->uio_offset, tl);
1911
*(tl + 2) = txdr_unsigned(len);
1912
}
1913
/*
1914
* Since I can't do a Getattr for NFSv4 for Write, there
1915
* doesn't seem any point in doing one here, either.
1916
* (See the comment in nfsrpc_writerpc() for more info.)
1917
*/
1918
error = nfscl_request(nd, vp, p, cred);
1919
if (error)
1920
return (error);
1921
if (nd->nd_flag & ND_NFSV3) {
1922
error = nfscl_postop_attr(nd, nap, attrflagp);
1923
} else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
1924
error = nfsm_loadattr(nd, nap);
1925
if (!error)
1926
*attrflagp = 1;
1927
}
1928
if (nd->nd_repstat || error) {
1929
if (!error)
1930
error = nd->nd_repstat;
1931
goto nfsmout;
1932
}
1933
if (nd->nd_flag & ND_NFSV3) {
1934
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1935
eof = fxdr_unsigned(int, *(tl + 1));
1936
} else if (nd->nd_flag & ND_NFSV4) {
1937
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1938
eof = fxdr_unsigned(int, *tl);
1939
}
1940
NFSM_STRSIZ(retlen, len);
1941
error = nfsm_mbufuio(nd, uiop, retlen);
1942
if (error)
1943
goto nfsmout;
1944
m_freem(nd->nd_mrep);
1945
nd->nd_mrep = NULL;
1946
tsiz -= retlen;
1947
if (!(nd->nd_flag & ND_NFSV2)) {
1948
if (eof || retlen == 0)
1949
tsiz = 0;
1950
} else if (retlen < len)
1951
tsiz = 0;
1952
}
1953
return (0);
1954
nfsmout:
1955
if (nd->nd_mrep != NULL)
1956
m_freem(nd->nd_mrep);
1957
return (error);
1958
}
1959
1960
/*
1961
* nfs write operation
1962
* When called_from_strategy != 0, it should return EIO for an error that
1963
* indicates recovery is in progress, so that the buffer will be left
1964
* dirty and be written back to the server later. If it loops around,
1965
* the recovery thread could get stuck waiting for the buffer and recovery
1966
* will then deadlock.
1967
*/
1968
int
1969
nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
1970
struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
1971
int called_from_strategy, int ioflag)
1972
{
1973
int error, expireret = 0, retrycnt, nostateid;
1974
u_int32_t clidrev = 0;
1975
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1976
struct nfsnode *np = VTONFS(vp);
1977
struct ucred *newcred;
1978
struct nfsfh *nfhp = NULL;
1979
nfsv4stateid_t stateid;
1980
void *lckp;
1981
1982
KASSERT(*must_commit >= 0 && *must_commit <= 2,
1983
("nfsrpc_write: must_commit out of range=%d", *must_commit));
1984
if (nmp->nm_clp != NULL)
1985
clidrev = nmp->nm_clp->nfsc_clientidrev;
1986
newcred = cred;
1987
if (NFSHASNFSV4(nmp)) {
1988
newcred = NFSNEWCRED(cred);
1989
nfhp = np->n_fhp;
1990
}
1991
retrycnt = 0;
1992
do {
1993
lckp = NULL;
1994
nostateid = 0;
1995
if (NFSHASNFSV4(nmp)) {
1996
(void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
1997
NFSV4OPEN_ACCESSWRITE, 0, newcred, p, &stateid,
1998
&lckp);
1999
if (stateid.other[0] == 0 && stateid.other[1] == 0 &&
2000
stateid.other[2] == 0) {
2001
nostateid = 1;
2002
NFSCL_DEBUG(1, "stateid0 in write\n");
2003
}
2004
}
2005
2006
/*
2007
* If there is no stateid for NFSv4, it means this is an
2008
* extraneous write after close. Basically a poorly
2009
* implemented buffer cache. Just don't do the write.
2010
*/
2011
if (nostateid)
2012
error = 0;
2013
else
2014
error = nfsrpc_writerpc(vp, uiop, iomode, must_commit,
2015
newcred, &stateid, p, nap, attrflagp, ioflag);
2016
if (error == NFSERR_STALESTATEID)
2017
nfscl_initiate_recovery(nmp->nm_clp);
2018
if (lckp != NULL)
2019
nfscl_lockderef(lckp);
2020
if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
2021
error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
2022
error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
2023
(void) nfs_catnap(PZERO, error, "nfs_write");
2024
} else if ((error == NFSERR_EXPIRED ||
2025
((!NFSHASINT(nmp) || !NFSHASNFSV4N(nmp)) &&
2026
error == NFSERR_BADSTATEID)) && clidrev != 0) {
2027
expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
2028
} else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp) &&
2029
NFSHASNFSV4N(nmp)) {
2030
error = EIO;
2031
}
2032
retrycnt++;
2033
} while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
2034
((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
2035
error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) ||
2036
(error == NFSERR_OLDSTATEID && retrycnt < 20) ||
2037
((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
2038
expireret == 0 && clidrev != 0 && retrycnt < 4));
2039
if (error != 0 && (retrycnt >= 4 ||
2040
((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
2041
error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0)))
2042
error = EIO;
2043
if (NFSHASNFSV4(nmp))
2044
NFSFREECRED(newcred);
2045
return (error);
2046
}
2047
2048
/*
2049
* The actual write RPC.
2050
*/
2051
static int
2052
nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
2053
int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp,
2054
NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, int ioflag)
2055
{
2056
u_int32_t *tl;
2057
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2058
struct nfsnode *np = VTONFS(vp);
2059
int error = 0, len, rlen, commit, committed = NFSWRITE_FILESYNC;
2060
int wccflag = 0;
2061
int32_t backup;
2062
struct nfsrv_descript *nd;
2063
nfsattrbit_t attrbits;
2064
uint64_t tmp_off;
2065
ssize_t tsiz, wsize;
2066
bool do_append;
2067
2068
KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
2069
*attrflagp = 0;
2070
tsiz = uiop->uio_resid;
2071
tmp_off = uiop->uio_offset + tsiz;
2072
NFSLOCKMNT(nmp);
2073
if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
2074
NFSUNLOCKMNT(nmp);
2075
return (EFBIG);
2076
}
2077
wsize = nmp->nm_wsize;
2078
do_append = false;
2079
if ((ioflag & IO_APPEND) != 0 && NFSHASNFSV4(nmp) && !NFSHASPNFS(nmp))
2080
do_append = true;
2081
NFSUNLOCKMNT(nmp);
2082
nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK);
2083
nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */
2084
nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */
2085
while (tsiz > 0) {
2086
*attrflagp = 0;
2087
len = (tsiz > wsize) ? wsize : tsiz;
2088
if (do_append)
2089
NFSCL_REQSTART(nd, NFSPROC_APPENDWRITE, vp, cred);
2090
else
2091
NFSCL_REQSTART(nd, NFSPROC_WRITE, vp, cred);
2092
if (nd->nd_flag & ND_NFSV4) {
2093
if (do_append) {
2094
NFSZERO_ATTRBIT(&attrbits);
2095
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
2096
nfsrv_putattrbit(nd, &attrbits);
2097
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED +
2098
NFSX_HYPER);
2099
*tl++ = txdr_unsigned(NFSX_HYPER);
2100
txdr_hyper(uiop->uio_offset, tl); tl += 2;
2101
*tl = txdr_unsigned(NFSV4OP_WRITE);
2102
}
2103
nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
2104
NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED);
2105
txdr_hyper(uiop->uio_offset, tl);
2106
tl += 2;
2107
*tl++ = txdr_unsigned(*iomode);
2108
*tl = txdr_unsigned(len);
2109
} else if (nd->nd_flag & ND_NFSV3) {
2110
NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED);
2111
txdr_hyper(uiop->uio_offset, tl);
2112
tl += 2;
2113
*tl++ = txdr_unsigned(len);
2114
*tl++ = txdr_unsigned(*iomode);
2115
*tl = txdr_unsigned(len);
2116
} else {
2117
u_int32_t x;
2118
2119
NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2120
/*
2121
* Not sure why someone changed this, since the
2122
* RFC clearly states that "beginoffset" and
2123
* "totalcount" are ignored, but it wouldn't
2124
* surprise me if there's a busted server out there.
2125
*/
2126
/* Set both "begin" and "current" to non-garbage. */
2127
x = txdr_unsigned((u_int32_t)uiop->uio_offset);
2128
*tl++ = x; /* "begin offset" */
2129
*tl++ = x; /* "current offset" */
2130
x = txdr_unsigned(len);
2131
*tl++ = x; /* total to this offset */
2132
*tl = x; /* size of this write */
2133
}
2134
error = nfsm_uiombuf(nd, uiop, len);
2135
if (error != 0) {
2136
m_freem(nd->nd_mreq);
2137
free(nd, M_TEMP);
2138
return (error);
2139
}
2140
/*
2141
* Although it is tempting to do a normal Getattr Op in the
2142
* NFSv4 compound, the result can be a nearly hung client
2143
* system if the Getattr asks for Owner and/or OwnerGroup.
2144
* It occurs when the client can't map either the Owner or
2145
* Owner_group name in the Getattr reply to a uid/gid. When
2146
* there is a cache miss, the kernel does an upcall to the
2147
* nfsuserd. Then, it can try and read the local /etc/passwd
2148
* or /etc/group file. It can then block in getnewbuf(),
2149
* waiting for dirty writes to be pushed to the NFS server.
2150
* The only reason this doesn't result in a complete
2151
* deadlock, is that the upcall times out and allows
2152
* the write to complete. However, progress is so slow
2153
* that it might just as well be deadlocked.
2154
* As such, we get the rest of the attributes, but not
2155
* Owner or Owner_group.
2156
* nb: nfscl_loadattrcache() needs to be told that these
2157
* partial attributes from a write rpc are being
2158
* passed in, via a argument flag.
2159
*/
2160
if (nd->nd_flag & ND_NFSV4) {
2161
NFSWRITEGETATTR_ATTRBIT(&attrbits);
2162
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2163
*tl = txdr_unsigned(NFSV4OP_GETATTR);
2164
(void) nfsrv_putattrbit(nd, &attrbits);
2165
}
2166
error = nfscl_request(nd, vp, p, cred);
2167
if (error) {
2168
free(nd, M_TEMP);
2169
return (error);
2170
}
2171
if (nd->nd_repstat) {
2172
/*
2173
* In case the rpc gets retried, roll
2174
* the uio fields changed by nfsm_uiombuf()
2175
* back.
2176
*/
2177
uiop->uio_offset -= len;
2178
uiop->uio_resid += len;
2179
uiop->uio_iov->iov_base =
2180
(char *)uiop->uio_iov->iov_base - len;
2181
uiop->uio_iov->iov_len += len;
2182
}
2183
if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2184
error = nfscl_wcc_data(nd, vp, nap, attrflagp,
2185
&wccflag, &tmp_off);
2186
if (error)
2187
goto nfsmout;
2188
}
2189
if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2190
(ND_NFSV4 | ND_NOMOREDATA) &&
2191
nd->nd_repstat == NFSERR_NOTSAME && do_append) {
2192
/*
2193
* Verify of the file's size failed, so redo the
2194
* write using the file's size as returned in
2195
* the wcc attributes.
2196
*/
2197
if (tmp_off + tsiz <= nmp->nm_maxfilesize) {
2198
do_append = false;
2199
uiop->uio_offset = tmp_off;
2200
m_freem(nd->nd_mrep);
2201
nd->nd_mrep = NULL;
2202
continue;
2203
} else
2204
nd->nd_repstat = EFBIG;
2205
}
2206
if (!nd->nd_repstat) {
2207
if (do_append) {
2208
/* Strip off the Write reply status. */
2209
do_append = false;
2210
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
2211
}
2212
if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2213
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED
2214
+ NFSX_VERF);
2215
rlen = fxdr_unsigned(int, *tl++);
2216
if (rlen <= 0 || rlen > len) {
2217
error = NFSERR_IO;
2218
goto nfsmout;
2219
} else if (rlen < len) {
2220
backup = len - rlen;
2221
uiop->uio_iov->iov_base =
2222
(char *)uiop->uio_iov->iov_base -
2223
backup;
2224
uiop->uio_iov->iov_len += backup;
2225
uiop->uio_offset -= backup;
2226
uiop->uio_resid += backup;
2227
len = rlen;
2228
}
2229
commit = fxdr_unsigned(int, *tl++);
2230
2231
/*
2232
* Return the lowest commitment level
2233
* obtained by any of the RPCs.
2234
*/
2235
if (committed == NFSWRITE_FILESYNC)
2236
committed = commit;
2237
else if (committed == NFSWRITE_DATASYNC &&
2238
commit == NFSWRITE_UNSTABLE)
2239
committed = commit;
2240
NFSLOCKMNT(nmp);
2241
if (!NFSHASWRITEVERF(nmp)) {
2242
NFSBCOPY((caddr_t)tl,
2243
(caddr_t)&nmp->nm_verf[0],
2244
NFSX_VERF);
2245
NFSSETWRITEVERF(nmp);
2246
} else if (NFSBCMP(tl, nmp->nm_verf,
2247
NFSX_VERF) && *must_commit != 2) {
2248
*must_commit = 1;
2249
NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
2250
}
2251
NFSUNLOCKMNT(nmp);
2252
}
2253
if (nd->nd_flag & ND_NFSV4)
2254
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2255
if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) {
2256
error = nfsm_loadattr(nd, nap);
2257
if (!error)
2258
*attrflagp = NFS_LATTR_NOSHRINK;
2259
}
2260
} else {
2261
error = nd->nd_repstat;
2262
}
2263
if (error)
2264
goto nfsmout;
2265
NFSWRITERPC_SETTIME(wccflag, np, nap, (nd->nd_flag & ND_NFSV4));
2266
m_freem(nd->nd_mrep);
2267
nd->nd_mrep = NULL;
2268
tsiz -= len;
2269
}
2270
nfsmout:
2271
if (nd->nd_mrep != NULL)
2272
m_freem(nd->nd_mrep);
2273
*iomode = committed;
2274
if (nd->nd_repstat && !error)
2275
error = nd->nd_repstat;
2276
free(nd, M_TEMP);
2277
return (error);
2278
}
2279
2280
/*
2281
* Do an nfs deallocate operation.
2282
*/
2283
int
2284
nfsrpc_deallocate(vnode_t vp, off_t offs, off_t len, struct nfsvattr *nap,
2285
int *attrflagp, struct ucred *cred, NFSPROC_T *p)
2286
{
2287
int error, expireret = 0, openerr, retrycnt;
2288
uint32_t clidrev = 0;
2289
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2290
struct nfsfh *nfhp;
2291
nfsv4stateid_t stateid;
2292
void *lckp;
2293
2294
if (nmp->nm_clp != NULL)
2295
clidrev = nmp->nm_clp->nfsc_clientidrev;
2296
retrycnt = 0;
2297
do {
2298
lckp = NULL;
2299
openerr = 1;
2300
nfhp = VTONFS(vp)->n_fhp;
2301
error = nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
2302
NFSV4OPEN_ACCESSWRITE, 0, cred, p, &stateid, &lckp);
2303
if (error != 0) {
2304
/*
2305
* No Open stateid, so try and open the file
2306
* now.
2307
*/
2308
openerr = nfsrpc_open(vp, FWRITE, cred, p);
2309
if (openerr == 0)
2310
nfscl_getstateid(vp, nfhp->nfh_fh,
2311
nfhp->nfh_len, NFSV4OPEN_ACCESSWRITE, 0,
2312
cred, p, &stateid, &lckp);
2313
}
2314
error = nfsrpc_deallocaterpc(vp, offs, len, &stateid, nap,
2315
attrflagp, cred, p);
2316
if (error == NFSERR_STALESTATEID)
2317
nfscl_initiate_recovery(nmp->nm_clp);
2318
if (lckp != NULL)
2319
nfscl_lockderef(lckp);
2320
if (openerr == 0)
2321
nfsrpc_close(vp, 0, p);
2322
if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
2323
error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
2324
error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
2325
(void) nfs_catnap(PZERO, error, "nfs_deallocate");
2326
} else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) &&
2327
error == NFSERR_BADSTATEID)) && clidrev != 0) {
2328
expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
2329
} else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) {
2330
error = EIO;
2331
}
2332
retrycnt++;
2333
} while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
2334
error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
2335
error == NFSERR_BADSESSION ||
2336
(error == NFSERR_OLDSTATEID && retrycnt < 20) ||
2337
((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
2338
expireret == 0 && clidrev != 0 && retrycnt < 4));
2339
if (error && retrycnt >= 4)
2340
error = EIO;
2341
return (error);
2342
}
2343
2344
/*
2345
* The actual deallocate RPC.
2346
*/
2347
static int
2348
nfsrpc_deallocaterpc(vnode_t vp, off_t offs, off_t len,
2349
nfsv4stateid_t *stateidp, struct nfsvattr *nap, int *attrflagp,
2350
struct ucred *cred, NFSPROC_T *p)
2351
{
2352
uint32_t *tl;
2353
struct nfsnode *np = VTONFS(vp);
2354
int error, wccflag;
2355
struct nfsrv_descript nfsd;
2356
struct nfsrv_descript *nd = &nfsd;
2357
nfsattrbit_t attrbits;
2358
2359
*attrflagp = 0;
2360
NFSCL_REQSTART(nd, NFSPROC_DEALLOCATE, vp, cred);
2361
nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
2362
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER);
2363
txdr_hyper(offs, tl);
2364
tl += 2;
2365
txdr_hyper(len, tl);
2366
NFSWRITEGETATTR_ATTRBIT(&attrbits);
2367
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
2368
*tl = txdr_unsigned(NFSV4OP_GETATTR);
2369
nfsrv_putattrbit(nd, &attrbits);
2370
error = nfscl_request(nd, vp, p, cred);
2371
if (error != 0)
2372
return (error);
2373
wccflag = 0;
2374
error = nfscl_wcc_data(nd, vp, nap, attrflagp, &wccflag, NULL);
2375
if (error != 0)
2376
goto nfsmout;
2377
if (nd->nd_repstat == 0) {
2378
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
2379
error = nfsm_loadattr(nd, nap);
2380
if (error != 0)
2381
goto nfsmout;
2382
*attrflagp = NFS_LATTR_NOSHRINK;
2383
}
2384
NFSWRITERPC_SETTIME(wccflag, np, nap, 1);
2385
nfsmout:
2386
m_freem(nd->nd_mrep);
2387
if (nd->nd_repstat != 0 && error == 0)
2388
error = nd->nd_repstat;
2389
return (error);
2390
}
2391
2392
/*
2393
* nfs mknod rpc
2394
* For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
2395
* mode set to specify the file type and the size field for rdev.
2396
*/
2397
int
2398
nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2399
u_int32_t rdev, __enum_uint8(vtype) vtyp, struct ucred *cred, NFSPROC_T *p,
2400
struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
2401
int *attrflagp, int *dattrflagp)
2402
{
2403
u_int32_t *tl;
2404
int error = 0;
2405
struct nfsrv_descript nfsd, *nd = &nfsd;
2406
nfsattrbit_t attrbits;
2407
2408
*nfhpp = NULL;
2409
*attrflagp = 0;
2410
*dattrflagp = 0;
2411
if (namelen > NFS_MAXNAMLEN)
2412
return (ENAMETOOLONG);
2413
NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp, cred);
2414
if (nd->nd_flag & ND_NFSV4) {
2415
if (vtyp == VBLK || vtyp == VCHR) {
2416
NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2417
*tl++ = vtonfsv34_type(vtyp);
2418
*tl++ = txdr_unsigned(NFSMAJOR(rdev));
2419
*tl = txdr_unsigned(NFSMINOR(rdev));
2420
} else {
2421
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2422
*tl = vtonfsv34_type(vtyp);
2423
}
2424
}
2425
(void) nfsm_strtom(nd, name, namelen);
2426
if (nd->nd_flag & ND_NFSV3) {
2427
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2428
*tl = vtonfsv34_type(vtyp);
2429
}
2430
if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
2431
nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0);
2432
if ((nd->nd_flag & ND_NFSV3) &&
2433
(vtyp == VCHR || vtyp == VBLK)) {
2434
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2435
*tl++ = txdr_unsigned(NFSMAJOR(rdev));
2436
*tl = txdr_unsigned(NFSMINOR(rdev));
2437
}
2438
if (nd->nd_flag & ND_NFSV4) {
2439
NFSGETATTR_ATTRBIT(&attrbits);
2440
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2441
*tl++ = txdr_unsigned(NFSV4OP_GETFH);
2442
*tl = txdr_unsigned(NFSV4OP_GETATTR);
2443
(void) nfsrv_putattrbit(nd, &attrbits);
2444
}
2445
if (nd->nd_flag & ND_NFSV2)
2446
nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev);
2447
error = nfscl_request(nd, dvp, p, cred);
2448
if (error)
2449
return (error);
2450
if (nd->nd_flag & ND_NFSV4)
2451
error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
2452
if (!nd->nd_repstat) {
2453
if (nd->nd_flag & ND_NFSV4) {
2454
NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2455
error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2456
if (error)
2457
goto nfsmout;
2458
}
2459
error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2460
if (error)
2461
goto nfsmout;
2462
}
2463
if (nd->nd_flag & ND_NFSV3)
2464
error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
2465
if (!error && nd->nd_repstat)
2466
error = nd->nd_repstat;
2467
nfsmout:
2468
m_freem(nd->nd_mrep);
2469
return (error);
2470
}
2471
2472
/*
2473
* nfs file create call
2474
* Mostly just call the approriate routine. (I separated out v4, so that
2475
* error recovery wouldn't be as difficult.)
2476
*/
2477
int
2478
nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2479
nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
2480
struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
2481
int *attrflagp, int *dattrflagp)
2482
{
2483
int error = 0, newone, expireret = 0, retrycnt, unlocked;
2484
struct nfsclowner *owp;
2485
struct nfscldeleg *dp;
2486
struct nfsmount *nmp = VFSTONFS(dvp->v_mount);
2487
u_int32_t clidrev;
2488
2489
if (NFSHASNFSV4(nmp)) {
2490
retrycnt = 0;
2491
do {
2492
dp = NULL;
2493
error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE |
2494
NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone,
2495
NULL, 1, true);
2496
if (error)
2497
return (error);
2498
if (nmp->nm_clp != NULL)
2499
clidrev = nmp->nm_clp->nfsc_clientidrev;
2500
else
2501
clidrev = 0;
2502
if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 ||
2503
nfs_numnfscbd == 0 || retrycnt > 0)
2504
error = nfsrpc_createv4(dvp, name, namelen, vap, cverf,
2505
fmode, owp, &dp, cred, p, dnap, nnap, nfhpp,
2506
attrflagp, dattrflagp, &unlocked);
2507
else
2508
error = nfsrpc_getcreatelayout(dvp, name, namelen, vap,
2509
cverf, fmode, owp, &dp, cred, p, dnap, nnap, nfhpp,
2510
attrflagp, dattrflagp, &unlocked);
2511
/*
2512
* There is no need to invalidate cached attributes here,
2513
* since new post-delegation issue attributes are always
2514
* returned by nfsrpc_createv4() and these will update the
2515
* attribute cache.
2516
*/
2517
if (dp != NULL)
2518
(void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp,
2519
(*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, dp);
2520
nfscl_ownerrelease(nmp, owp, error, newone, unlocked);
2521
if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
2522
error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
2523
error == NFSERR_BADSESSION) {
2524
(void) nfs_catnap(PZERO, error, "nfs_open");
2525
} else if ((error == NFSERR_EXPIRED ||
2526
error == NFSERR_BADSTATEID) && clidrev != 0) {
2527
expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
2528
retrycnt++;
2529
}
2530
} while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
2531
error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
2532
error == NFSERR_BADSESSION ||
2533
((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
2534
expireret == 0 && clidrev != 0 && retrycnt < 4));
2535
if (error && retrycnt >= 4)
2536
error = EIO;
2537
} else {
2538
error = nfsrpc_createv23(dvp, name, namelen, vap, cverf,
2539
fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp);
2540
}
2541
return (error);
2542
}
2543
2544
/*
2545
* The create rpc for v2 and 3.
2546
*/
2547
static int
2548
nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2549
nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
2550
struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
2551
int *attrflagp, int *dattrflagp)
2552
{
2553
u_int32_t *tl;
2554
int error = 0;
2555
struct nfsrv_descript nfsd, *nd = &nfsd;
2556
2557
*nfhpp = NULL;
2558
*attrflagp = 0;
2559
*dattrflagp = 0;
2560
if (namelen > NFS_MAXNAMLEN)
2561
return (ENAMETOOLONG);
2562
NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp, cred);
2563
(void) nfsm_strtom(nd, name, namelen);
2564
if (nd->nd_flag & ND_NFSV3) {
2565
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2566
if (fmode & O_EXCL) {
2567
*tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
2568
NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2569
*tl++ = cverf.lval[0];
2570
*tl = cverf.lval[1];
2571
} else {
2572
*tl = txdr_unsigned(NFSCREATE_UNCHECKED);
2573
nfscl_fillsattr(nd, vap, dvp, 0, 0);
2574
}
2575
} else {
2576
nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0);
2577
}
2578
error = nfscl_request(nd, dvp, p, cred);
2579
if (error)
2580
return (error);
2581
if (nd->nd_repstat == 0) {
2582
error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2583
if (error)
2584
goto nfsmout;
2585
}
2586
if (nd->nd_flag & ND_NFSV3)
2587
error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
2588
if (nd->nd_repstat != 0 && error == 0)
2589
error = nd->nd_repstat;
2590
nfsmout:
2591
m_freem(nd->nd_mrep);
2592
return (error);
2593
}
2594
2595
static int
2596
nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
2597
nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
2598
struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
2599
struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
2600
int *dattrflagp, int *unlockedp)
2601
{
2602
u_int32_t *tl;
2603
int error = 0, deleg, newone, ret, acesize, limitby;
2604
struct nfsrv_descript nfsd, *nd = &nfsd;
2605
struct nfsclopen *op;
2606
struct nfscldeleg *dp = NULL;
2607
struct nfsnode *np;
2608
struct nfsfh *nfhp;
2609
nfsattrbit_t attrbits;
2610
nfsv4stateid_t stateid;
2611
u_int32_t rflags;
2612
struct nfsmount *nmp;
2613
struct nfsclsession *tsep;
2614
2615
nmp = VFSTONFS(dvp->v_mount);
2616
np = VTONFS(dvp);
2617
*unlockedp = 0;
2618
*nfhpp = NULL;
2619
*dpp = NULL;
2620
*attrflagp = 0;
2621
*dattrflagp = 0;
2622
if (namelen > NFS_MAXNAMLEN)
2623
return (ENAMETOOLONG);
2624
NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp, cred);
2625
/*
2626
* For V4, this is actually an Open op.
2627
*/
2628
NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2629
*tl++ = txdr_unsigned(owp->nfsow_seqid);
2630
if (NFSHASNFSV4N(nmp)) {
2631
if (!NFSHASPNFS(nmp) && nfscl_enablecallb != 0 &&
2632
nfs_numnfscbd > 0)
2633
*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
2634
NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTWRITEDELEG);
2635
else
2636
*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
2637
NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTNODELEG);
2638
} else
2639
*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
2640
NFSV4OPEN_ACCESSREAD);
2641
*tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
2642
tsep = nfsmnt_mdssession(nmp);
2643
*tl++ = tsep->nfsess_clientid.lval[0];
2644
*tl = tsep->nfsess_clientid.lval[1];
2645
(void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
2646
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2647
*tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
2648
if (fmode & O_EXCL) {
2649
if (NFSHASNFSV4N(nmp)) {
2650
if (NFSHASSESSPERSIST(nmp)) {
2651
/* Use GUARDED for persistent sessions. */
2652
*tl = txdr_unsigned(NFSCREATE_GUARDED);
2653
nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE,
2654
0);
2655
} else {
2656
/* Otherwise, use EXCLUSIVE4_1. */
2657
*tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41);
2658
NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2659
*tl++ = cverf.lval[0];
2660
*tl = cverf.lval[1];
2661
nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE,
2662
0);
2663
}
2664
} else {
2665
/* NFSv4.0 */
2666
*tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
2667
NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2668
*tl++ = cverf.lval[0];
2669
*tl = cverf.lval[1];
2670
}
2671
} else {
2672
*tl = txdr_unsigned(NFSCREATE_UNCHECKED);
2673
nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0);
2674
}
2675
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2676
*tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
2677
(void) nfsm_strtom(nd, name, namelen);
2678
/* Get the new file's handle and attributes. */
2679
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2680
*tl++ = txdr_unsigned(NFSV4OP_GETFH);
2681
*tl = txdr_unsigned(NFSV4OP_GETATTR);
2682
NFSGETATTR_ATTRBIT(&attrbits);
2683
(void) nfsrv_putattrbit(nd, &attrbits);
2684
/* Get the directory's post-op attributes. */
2685
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2686
*tl = txdr_unsigned(NFSV4OP_PUTFH);
2687
(void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
2688
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2689
*tl = txdr_unsigned(NFSV4OP_GETATTR);
2690
(void) nfsrv_putattrbit(nd, &attrbits);
2691
error = nfscl_request(nd, dvp, p, cred);
2692
if (error)
2693
return (error);
2694
NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
2695
if (nd->nd_repstat == 0) {
2696
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
2697
6 * NFSX_UNSIGNED);
2698
stateid.seqid = *tl++;
2699
stateid.other[0] = *tl++;
2700
stateid.other[1] = *tl++;
2701
stateid.other[2] = *tl;
2702
rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
2703
error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
2704
if (error)
2705
goto nfsmout;
2706
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2707
deleg = fxdr_unsigned(int, *tl);
2708
if (deleg == NFSV4OPEN_DELEGATEREAD ||
2709
deleg == NFSV4OPEN_DELEGATEWRITE) {
2710
if (!(owp->nfsow_clp->nfsc_flags &
2711
NFSCLFLAGS_FIRSTDELEG))
2712
owp->nfsow_clp->nfsc_flags |=
2713
(NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
2714
dp = malloc(
2715
sizeof (struct nfscldeleg) + NFSX_V4FHMAX,
2716
M_NFSCLDELEG, M_WAITOK);
2717
LIST_INIT(&dp->nfsdl_owner);
2718
LIST_INIT(&dp->nfsdl_lock);
2719
dp->nfsdl_clp = owp->nfsow_clp;
2720
newnfs_copyincred(cred, &dp->nfsdl_cred);
2721
nfscl_lockinit(&dp->nfsdl_rwlock);
2722
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
2723
NFSX_UNSIGNED);
2724
dp->nfsdl_stateid.seqid = *tl++;
2725
dp->nfsdl_stateid.other[0] = *tl++;
2726
dp->nfsdl_stateid.other[1] = *tl++;
2727
dp->nfsdl_stateid.other[2] = *tl++;
2728
ret = fxdr_unsigned(int, *tl);
2729
if (deleg == NFSV4OPEN_DELEGATEWRITE) {
2730
dp->nfsdl_flags = NFSCLDL_WRITE;
2731
/*
2732
* Indicates how much the file can grow.
2733
*/
2734
NFSM_DISSECT(tl, u_int32_t *,
2735
3 * NFSX_UNSIGNED);
2736
limitby = fxdr_unsigned(int, *tl++);
2737
switch (limitby) {
2738
case NFSV4OPEN_LIMITSIZE:
2739
dp->nfsdl_sizelimit = fxdr_hyper(tl);
2740
break;
2741
case NFSV4OPEN_LIMITBLOCKS:
2742
dp->nfsdl_sizelimit =
2743
fxdr_unsigned(u_int64_t, *tl++);
2744
dp->nfsdl_sizelimit *=
2745
fxdr_unsigned(u_int64_t, *tl);
2746
break;
2747
default:
2748
error = NFSERR_BADXDR;
2749
goto nfsmout;
2750
}
2751
} else {
2752
dp->nfsdl_flags = NFSCLDL_READ;
2753
}
2754
if (ret)
2755
dp->nfsdl_flags |= NFSCLDL_RECALL;
2756
error = nfsrv_dissectace(nd, &dp->nfsdl_ace, false,
2757
&ret, &acesize);
2758
if (error)
2759
goto nfsmout;
2760
} else if (deleg == NFSV4OPEN_DELEGATENONEEXT &&
2761
NFSHASNFSV4N(nmp)) {
2762
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2763
deleg = fxdr_unsigned(uint32_t, *tl);
2764
if (deleg == NFSV4OPEN_CONTENTION ||
2765
deleg == NFSV4OPEN_RESOURCE)
2766
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2767
} else if (deleg != NFSV4OPEN_DELEGATENONE) {
2768
error = NFSERR_BADXDR;
2769
goto nfsmout;
2770
}
2771
error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
2772
if (error)
2773
goto nfsmout;
2774
/* Get rid of the PutFH and Getattr status values. */
2775
NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2776
/* Load the directory attributes. */
2777
error = nfsm_loadattr(nd, dnap);
2778
if (error)
2779
goto nfsmout;
2780
*dattrflagp = 1;
2781
if (dp != NULL && *attrflagp) {
2782
dp->nfsdl_change = nnap->na_filerev;
2783
dp->nfsdl_modtime = nnap->na_mtime;
2784
dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
2785
}
2786
/*
2787
* We can now complete the Open state.
2788
*/
2789
nfhp = *nfhpp;
2790
if (dp != NULL) {
2791
dp->nfsdl_fhlen = nfhp->nfh_len;
2792
NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len);
2793
}
2794
/*
2795
* Get an Open structure that will be
2796
* attached to the OpenOwner, acquired already.
2797
*/
2798
error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len,
2799
(NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
2800
cred, p, NULL, &op, &newone, NULL, 0, false);
2801
if (error)
2802
goto nfsmout;
2803
op->nfso_stateid = stateid;
2804
newnfs_copyincred(cred, &op->nfso_cred);
2805
if ((rflags & NFSV4OPEN_RESULTCONFIRM)) {
2806
do {
2807
ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh,
2808
nfhp->nfh_len, op, cred, p);
2809
if (ret == NFSERR_DELAY)
2810
(void) nfs_catnap(PZERO, ret, "nfs_create");
2811
} while (ret == NFSERR_DELAY);
2812
error = ret;
2813
}
2814
2815
/*
2816
* If the server is handing out delegations, but we didn't
2817
* get one because an OpenConfirm was required, try the
2818
* Open again, to get a delegation. This is a harmless no-op,
2819
* from a server's point of view.
2820
*/
2821
if ((rflags & NFSV4OPEN_RESULTCONFIRM) &&
2822
(owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) &&
2823
!error && dp == NULL) {
2824
KASSERT(!NFSHASNFSV4N(nmp),
2825
("nfsrpc_createv4: result confirm"));
2826
do {
2827
ret = nfsrpc_openrpc(VFSTONFS(dvp->v_mount), dvp,
2828
np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
2829
nfhp->nfh_fh, nfhp->nfh_len,
2830
(NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op,
2831
name, namelen, &dp, 0, 0x0, cred, p, 0, 1);
2832
if (ret == NFSERR_DELAY)
2833
(void) nfs_catnap(PZERO, ret, "nfs_crt2");
2834
} while (ret == NFSERR_DELAY);
2835
if (ret) {
2836
if (dp != NULL) {
2837
free(dp, M_NFSCLDELEG);
2838
dp = NULL;
2839
}
2840
if (ret == NFSERR_STALECLIENTID ||
2841
ret == NFSERR_STALEDONTRECOVER ||
2842
ret == NFSERR_BADSESSION)
2843
error = ret;
2844
}
2845
}
2846
nfscl_openrelease(nmp, op, error, newone);
2847
*unlockedp = 1;
2848
}
2849
if (nd->nd_repstat != 0 && error == 0)
2850
error = nd->nd_repstat;
2851
if (error == NFSERR_STALECLIENTID)
2852
nfscl_initiate_recovery(owp->nfsow_clp);
2853
nfsmout:
2854
if (!error)
2855
*dpp = dp;
2856
else if (dp != NULL)
2857
free(dp, M_NFSCLDELEG);
2858
m_freem(nd->nd_mrep);
2859
return (error);
2860
}
2861
2862
/*
2863
* Nfs remove rpc
2864
*/
2865
int
2866
nfsrpc_remove(struct vnode *dvp, char *name, int namelen, struct vnode *vp,
2867
struct nfsvattr *nap, int *attrflagp, nfsremove_status *file_status,
2868
struct nfsvattr *dnap, int *dattrflagp, struct ucred *cred, NFSPROC_T *p)
2869
{
2870
uint32_t *tl;
2871
struct nfsrv_descript nfsd, *nd = &nfsd;
2872
struct nfsnode *np;
2873
struct nfsmount *nmp;
2874
nfsv4stateid_t dstateid;
2875
nfsattrbit_t attrbits;
2876
int error, i, ret;
2877
2878
*dattrflagp = 0;
2879
*attrflagp = 0;
2880
*file_status = UNKNOWN;
2881
ret = 0;
2882
if (namelen > NFS_MAXNAMLEN)
2883
return (ENAMETOOLONG);
2884
nmp = VFSTONFS(dvp->v_mount);
2885
tryagain:
2886
if (NFSHASNFSV4(nmp) && ((nmp->nm_flag & NFSMNT_NOCTO) == 0 ||
2887
!NFSHASNFSV4N(nmp)) && ret == 0) {
2888
ret = nfscl_removedeleg(vp, p, &dstateid);
2889
if (ret == 1) {
2890
NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp, cred);
2891
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
2892
NFSX_UNSIGNED);
2893
if (NFSHASNFSV4N(nmp))
2894
*tl++ = 0;
2895
else
2896
*tl++ = dstateid.seqid;
2897
*tl++ = dstateid.other[0];
2898
*tl++ = dstateid.other[1];
2899
*tl++ = dstateid.other[2];
2900
*tl = txdr_unsigned(NFSV4OP_PUTFH);
2901
np = VTONFS(dvp);
2902
(void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh,
2903
np->n_fhp->nfh_len, 0);
2904
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2905
*tl = txdr_unsigned(NFSV4OP_REMOVE);
2906
}
2907
} else {
2908
ret = 0;
2909
}
2910
if (ret == 0)
2911
NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp, cred);
2912
(void)nfsm_strtom(nd, name, namelen);
2913
if (ret == 0 && (nd->nd_flag & ND_NFSV4) != 0) {
2914
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
2915
*tl = txdr_unsigned(NFSV4OP_PUTFH);
2916
np = VTONFS(vp);
2917
(void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
2918
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
2919
NFSGETATTR_ATTRBIT(&attrbits);
2920
*tl = txdr_unsigned(NFSV4OP_GETATTR);
2921
(void)nfsrv_putattrbit(nd, &attrbits);
2922
}
2923
error = nfscl_request(nd, dvp, p, cred);
2924
if (error != 0)
2925
return (error);
2926
if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
2927
/* For NFSv4, parse out any Delereturn replies. */
2928
if (ret > 0 && nd->nd_repstat != 0 &&
2929
(nd->nd_flag & ND_NOMOREDATA)) {
2930
/*
2931
* If the Delegreturn failed, try again without
2932
* it. The server will Recall, as required.
2933
*/
2934
m_freem(nd->nd_mrep);
2935
goto tryagain;
2936
}
2937
for (i = 0; i < (ret * 2); i++) {
2938
if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
2939
ND_NFSV4) {
2940
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2941
if (*(tl + 1))
2942
nd->nd_flag |= ND_NOMOREDATA;
2943
}
2944
}
2945
error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
2946
}
2947
if (ret == 0 && (nd->nd_flag & (ND_NFSV4 |
2948
ND_NOMOREDATA)) == ND_NFSV4) {
2949
/* Parse out the Remove reply for NFSPROC_REMOVE. */
2950
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED + 2 * NFSX_HYPER);
2951
/* No use for change info for now. */
2952
/* The Remove succeeded. */
2953
nd->nd_repstat = 0;
2954
}
2955
if (ret == 0 && (nd->nd_flag & (ND_NFSV4 |
2956
ND_NOMOREDATA)) == ND_NFSV4) {
2957
/* Parse out the PutFH, Getattr for NFSPROC_REMOVE. */
2958
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
2959
if (*(tl + 1) != 0) {
2960
i = fxdr_unsigned(int, *(tl + 1));
2961
if (i == NFSERR_STALE)
2962
*file_status = DELETED;
2963
} else {
2964
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
2965
if (*(tl + 1) != 0) {
2966
i = fxdr_unsigned(int, *(tl + 1));
2967
if (i == NFSERR_STALE)
2968
*file_status = DELETED;
2969
} else {
2970
error = nfsm_loadattr(nd, nap);
2971
if (error == 0) {
2972
*attrflagp = 1;
2973
if (nap->na_nlink == 0)
2974
*file_status = NLINK_ZERO;
2975
else
2976
*file_status = VALID;
2977
}
2978
}
2979
}
2980
}
2981
if (nd->nd_repstat != 0 && error == 0)
2982
error = nd->nd_repstat;
2983
nfsmout:
2984
m_freem(nd->nd_mrep);
2985
return (error);
2986
}
2987
2988
/*
2989
* Do an nfs rename rpc.
2990
*/
2991
int
2992
nfsrpc_rename(struct vnode *fdvp, struct vnode *fvp, char *fnameptr,
2993
int fnamelen, struct vnode *tdvp, struct vnode *tvp, char *tnameptr,
2994
int tnamelen, nfsremove_status *tvp_status, struct nfsvattr *fnap,
2995
struct nfsvattr *tnap, int *fattrflagp, int *tattrflagp,
2996
struct nfsvattr *tvpnap, int *tvpattrflagp, struct ucred *cred,
2997
NFSPROC_T *p)
2998
{
2999
uint32_t *tl;
3000
struct nfsrv_descript nfsd, *nd = &nfsd;
3001
struct nfsmount *nmp;
3002
struct nfsnode *np;
3003
nfsattrbit_t attrbits;
3004
nfsv4stateid_t fdstateid, tdstateid;
3005
int error = 0, ret = 0, gottd = 0, gotfd = 0, i;
3006
3007
*fattrflagp = 0;
3008
*tattrflagp = 0;
3009
*tvpattrflagp = 0;
3010
*tvp_status = UNKNOWN;
3011
nmp = VFSTONFS(fdvp->v_mount);
3012
if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN)
3013
return (ENAMETOOLONG);
3014
tryagain:
3015
if (NFSHASNFSV4(nmp) && ((nmp->nm_flag & NFSMNT_NOCTO) == 0 ||
3016
!NFSHASNFSV4N(nmp)) && ret == 0) {
3017
ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp,
3018
&tdstateid, &gottd, p);
3019
if (gotfd && gottd) {
3020
NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp, cred);
3021
} else if (gotfd) {
3022
NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp, cred);
3023
} else if (gottd) {
3024
NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp, cred);
3025
}
3026
if (gotfd) {
3027
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3028
if (NFSHASNFSV4N(nmp))
3029
*tl++ = 0;
3030
else
3031
*tl++ = fdstateid.seqid;
3032
*tl++ = fdstateid.other[0];
3033
*tl++ = fdstateid.other[1];
3034
*tl = fdstateid.other[2];
3035
if (gottd) {
3036
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3037
*tl = txdr_unsigned(NFSV4OP_PUTFH);
3038
np = VTONFS(tvp);
3039
(void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh,
3040
np->n_fhp->nfh_len, 0);
3041
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3042
*tl = txdr_unsigned(NFSV4OP_DELEGRETURN);
3043
}
3044
}
3045
if (gottd) {
3046
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3047
if (NFSHASNFSV4N(nmp))
3048
*tl++ = 0;
3049
else
3050
*tl++ = tdstateid.seqid;
3051
*tl++ = tdstateid.other[0];
3052
*tl++ = tdstateid.other[1];
3053
*tl = tdstateid.other[2];
3054
}
3055
if (ret > 0) {
3056
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3057
*tl = txdr_unsigned(NFSV4OP_PUTFH);
3058
np = VTONFS(fdvp);
3059
(void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh,
3060
np->n_fhp->nfh_len, 0);
3061
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3062
*tl = txdr_unsigned(NFSV4OP_SAVEFH);
3063
}
3064
} else {
3065
ret = 0;
3066
}
3067
if (ret == 0)
3068
NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp, cred);
3069
if ((nd->nd_flag & ND_NFSV4) != 0) {
3070
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3071
*tl = txdr_unsigned(NFSV4OP_GETATTR);
3072
NFSWCCATTR_ATTRBIT(&attrbits);
3073
(void)nfsrv_putattrbit(nd, &attrbits);
3074
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3075
*tl = txdr_unsigned(NFSV4OP_PUTFH);
3076
(void)nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh,
3077
VTONFS(tdvp)->n_fhp->nfh_len, 0);
3078
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3079
*tl = txdr_unsigned(NFSV4OP_GETATTR);
3080
(void)nfsrv_putattrbit(nd, &attrbits);
3081
nd->nd_flag |= ND_V4WCCATTR;
3082
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3083
*tl = txdr_unsigned(NFSV4OP_RENAME);
3084
}
3085
(void)nfsm_strtom(nd, fnameptr, fnamelen);
3086
if ((nd->nd_flag & ND_NFSV4) == 0)
3087
(void)nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh,
3088
VTONFS(tdvp)->n_fhp->nfh_len, 0);
3089
(void)nfsm_strtom(nd, tnameptr, tnamelen);
3090
if (ret == 0 && (nd->nd_flag & ND_NFSV4) != 0) {
3091
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3092
/* When tvp == NULL, it doesn't matter which dvp is used. */
3093
*tl = txdr_unsigned(NFSV4OP_PUTFH);
3094
if (tvp != NULL)
3095
(void)nfsm_fhtom(nmp, nd, VTONFS(tvp)->n_fhp->nfh_fh,
3096
VTONFS(tvp)->n_fhp->nfh_len, 0);
3097
else
3098
(void)nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh,
3099
VTONFS(tdvp)->n_fhp->nfh_len, 0);
3100
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3101
*tl = txdr_unsigned(NFSV4OP_GETATTR);
3102
NFSGETATTR_ATTRBIT(&attrbits);
3103
(void)nfsrv_putattrbit(nd, &attrbits);
3104
}
3105
error = nfscl_request(nd, fdvp, p, cred);
3106
if (error != 0)
3107
return (error);
3108
if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
3109
/* For NFSv4, parse out any Delereturn replies. */
3110
if (ret > 0 && nd->nd_repstat != 0 &&
3111
(nd->nd_flag & ND_NOMOREDATA)) {
3112
/*
3113
* If the Delegreturn failed, try again without
3114
* it. The server will Recall, as required.
3115
*/
3116
m_freem(nd->nd_mrep);
3117
goto tryagain;
3118
}
3119
for (i = 0; i < (ret * 2); i++) {
3120
if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
3121
ND_NFSV4) {
3122
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3123
if (*(tl + 1)) {
3124
if (i == 1 && ret > 1) {
3125
/*
3126
* If the Delegreturn failed, try again
3127
* without it. The server will Recall, as
3128
* required.
3129
* If ret > 1, the second iteration of this
3130
* loop is the second DelegReturn result.
3131
*/
3132
m_freem(nd->nd_mrep);
3133
goto tryagain;
3134
} else {
3135
nd->nd_flag |= ND_NOMOREDATA;
3136
}
3137
}
3138
}
3139
}
3140
/* Now, the first wcc attribute reply. */
3141
if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
3142
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3143
if (*(tl + 1))
3144
nd->nd_flag |= ND_NOMOREDATA;
3145
}
3146
error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL, NULL);
3147
/* and the second wcc attribute reply. */
3148
if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 &&
3149
error == 0) {
3150
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3151
if (*(tl + 1))
3152
nd->nd_flag |= ND_NOMOREDATA;
3153
}
3154
if (error == 0)
3155
error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp,
3156
NULL, NULL);
3157
}
3158
if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 &&
3159
ret == 0 && error == 0) {
3160
/* Parse out the rename successful reply. */
3161
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED +
3162
4 * NFSX_HYPER);
3163
nd->nd_repstat = 0; /* Rename succeeded. */
3164
/* Parse PutFH reply for tvp. */
3165
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3166
if (*(tl + 1) != 0) {
3167
if (tvp != NULL) {
3168
i = fxdr_unsigned(int, *(tl + 1));
3169
if (i == NFSERR_STALE)
3170
*tvp_status = DELETED;
3171
}
3172
} else {
3173
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3174
if (*(tl + 1) != 0) {
3175
if (tvp != NULL) {
3176
i = fxdr_unsigned(int, *(tl + 1));
3177
if (i == NFSERR_STALE)
3178
*tvp_status = DELETED;
3179
}
3180
} else {
3181
error = nfsm_loadattr(nd, tvpnap);
3182
if (error == 0 && tvp != NULL) {
3183
*tvpattrflagp = 1;
3184
if (tvpnap->na_nlink == 0)
3185
*tvp_status = NLINK_ZERO;
3186
else
3187
*tvp_status = VALID;
3188
}
3189
}
3190
}
3191
}
3192
if (nd->nd_repstat != 0 && error == 0)
3193
error = nd->nd_repstat;
3194
nfsmout:
3195
m_freem(nd->nd_mrep);
3196
return (error);
3197
}
3198
3199
/*
3200
* nfs hard link create rpc
3201
*/
3202
int
3203
nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen,
3204
struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
3205
struct nfsvattr *nap, int *attrflagp, int *dattrflagp)
3206
{
3207
u_int32_t *tl;
3208
struct nfsrv_descript nfsd, *nd = &nfsd;
3209
nfsattrbit_t attrbits;
3210
int error = 0;
3211
3212
*attrflagp = 0;
3213
*dattrflagp = 0;
3214
if (namelen > NFS_MAXNAMLEN)
3215
return (ENAMETOOLONG);
3216
NFSCL_REQSTART(nd, NFSPROC_LINK, vp, cred);
3217
if (nd->nd_flag & ND_NFSV4) {
3218
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3219
*tl = txdr_unsigned(NFSV4OP_PUTFH);
3220
}
3221
(void)nfsm_fhtom(VFSTONFS(dvp->v_mount), nd, VTONFS(dvp)->n_fhp->nfh_fh,
3222
VTONFS(dvp)->n_fhp->nfh_len, 0);
3223
if (nd->nd_flag & ND_NFSV4) {
3224
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3225
*tl = txdr_unsigned(NFSV4OP_LINK);
3226
}
3227
(void) nfsm_strtom(nd, name, namelen);
3228
if (nd->nd_flag & ND_NFSV4) {
3229
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3230
*tl = txdr_unsigned(NFSV4OP_GETATTR);
3231
NFSGETATTR_ATTRBIT(&attrbits);
3232
(void)nfsrv_putattrbit(nd, &attrbits);
3233
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3234
*tl++ = txdr_unsigned(NFSV4OP_RESTOREFH);
3235
*tl = txdr_unsigned(NFSV4OP_GETATTR);
3236
(void)nfsrv_putattrbit(nd, &attrbits);
3237
}
3238
error = nfscl_request(nd, vp, p, cred);
3239
if (error)
3240
return (error);
3241
if (nd->nd_flag & ND_NFSV3) {
3242
error = nfscl_postop_attr(nd, nap, attrflagp);
3243
if (!error)
3244
error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
3245
NULL, NULL);
3246
} else if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0) {
3247
/*
3248
* First and parse out the PutFH and Link results.
3249
*/
3250
NFSM_DISSECT(tl, uint32_t *, 5 * NFSX_UNSIGNED +
3251
2 * NFSX_HYPER);
3252
if (*(tl + 3))
3253
nd->nd_flag |= ND_NOMOREDATA;
3254
/*
3255
* Get the directory post-op attributes.
3256
*/
3257
if ((nd->nd_flag & ND_NOMOREDATA) == 0)
3258
error = nfscl_postop_attr(nd, dnap, dattrflagp);
3259
if (error == 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) {
3260
/* Get rid of the RestoreFH reply. */
3261
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3262
if (*(tl + 1))
3263
nd->nd_flag |= ND_NOMOREDATA;
3264
}
3265
/* Get the file's post-op attributes. */
3266
if (error == 0 && (nd->nd_flag & ND_NOMOREDATA) == 0)
3267
error = nfscl_postop_attr(nd, nap, attrflagp);
3268
}
3269
if (nd->nd_repstat && !error)
3270
error = nd->nd_repstat;
3271
nfsmout:
3272
m_freem(nd->nd_mrep);
3273
return (error);
3274
}
3275
3276
/*
3277
* nfs symbolic link create rpc
3278
*/
3279
int
3280
nfsrpc_symlink(vnode_t dvp, char *name, int namelen, const char *target,
3281
struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
3282
struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
3283
int *dattrflagp)
3284
{
3285
u_int32_t *tl;
3286
struct nfsrv_descript nfsd, *nd = &nfsd;
3287
struct nfsmount *nmp;
3288
int slen, error = 0;
3289
3290
*nfhpp = NULL;
3291
*attrflagp = 0;
3292
*dattrflagp = 0;
3293
nmp = VFSTONFS(dvp->v_mount);
3294
slen = strlen(target);
3295
if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN)
3296
return (ENAMETOOLONG);
3297
NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp, cred);
3298
if (nd->nd_flag & ND_NFSV4) {
3299
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3300
*tl = txdr_unsigned(NFLNK);
3301
(void) nfsm_strtom(nd, target, slen);
3302
}
3303
(void) nfsm_strtom(nd, name, namelen);
3304
if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
3305
nfscl_fillsattr(nd, vap, dvp, 0, 0);
3306
if (!(nd->nd_flag & ND_NFSV4))
3307
(void) nfsm_strtom(nd, target, slen);
3308
if (nd->nd_flag & ND_NFSV2)
3309
nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
3310
error = nfscl_request(nd, dvp, p, cred);
3311
if (error)
3312
return (error);
3313
if (nd->nd_flag & ND_NFSV4)
3314
error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
3315
if ((nd->nd_flag & ND_NFSV3) && !error) {
3316
if (!nd->nd_repstat)
3317
error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
3318
if (!error)
3319
error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
3320
NULL, NULL);
3321
}
3322
if (nd->nd_repstat && !error)
3323
error = nd->nd_repstat;
3324
m_freem(nd->nd_mrep);
3325
/*
3326
* Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
3327
* Only do this if vfs.nfs.ignore_eexist is set.
3328
* Never do this for NFSv4.1 or later minor versions, since sessions
3329
* should guarantee "exactly once" RPC semantics.
3330
*/
3331
if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
3332
nmp->nm_minorvers == 0))
3333
error = 0;
3334
return (error);
3335
}
3336
3337
/*
3338
* nfs make dir rpc
3339
*/
3340
int
3341
nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap,
3342
struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
3343
struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
3344
int *dattrflagp)
3345
{
3346
u_int32_t *tl;
3347
struct nfsrv_descript nfsd, *nd = &nfsd;
3348
nfsattrbit_t attrbits;
3349
int error = 0;
3350
struct nfsfh *fhp;
3351
struct nfsmount *nmp;
3352
3353
*nfhpp = NULL;
3354
*attrflagp = 0;
3355
*dattrflagp = 0;
3356
nmp = VFSTONFS(dvp->v_mount);
3357
fhp = VTONFS(dvp)->n_fhp;
3358
if (namelen > NFS_MAXNAMLEN)
3359
return (ENAMETOOLONG);
3360
NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp, cred);
3361
if (nd->nd_flag & ND_NFSV4) {
3362
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3363
*tl = txdr_unsigned(NFDIR);
3364
}
3365
(void) nfsm_strtom(nd, name, namelen);
3366
nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1 | NFSSATTR_NEWFILE, 0);
3367
if (nd->nd_flag & ND_NFSV4) {
3368
NFSGETATTR_ATTRBIT(&attrbits);
3369
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3370
*tl++ = txdr_unsigned(NFSV4OP_GETFH);
3371
*tl = txdr_unsigned(NFSV4OP_GETATTR);
3372
(void) nfsrv_putattrbit(nd, &attrbits);
3373
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3374
*tl = txdr_unsigned(NFSV4OP_PUTFH);
3375
(void)nfsm_fhtom(nmp, nd, fhp->nfh_fh, fhp->nfh_len, 0);
3376
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3377
*tl = txdr_unsigned(NFSV4OP_GETATTR);
3378
(void) nfsrv_putattrbit(nd, &attrbits);
3379
}
3380
error = nfscl_request(nd, dvp, p, cred);
3381
if (error)
3382
return (error);
3383
if (nd->nd_flag & ND_NFSV4)
3384
error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
3385
if (!nd->nd_repstat && !error) {
3386
if (nd->nd_flag & ND_NFSV4) {
3387
NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
3388
error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
3389
}
3390
if (!error)
3391
error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
3392
if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) {
3393
/* Get rid of the PutFH and Getattr status values. */
3394
NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
3395
/* Load the directory attributes. */
3396
error = nfsm_loadattr(nd, dnap);
3397
if (error == 0)
3398
*dattrflagp = 1;
3399
}
3400
}
3401
if ((nd->nd_flag & ND_NFSV3) && !error)
3402
error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
3403
if (nd->nd_repstat && !error)
3404
error = nd->nd_repstat;
3405
nfsmout:
3406
m_freem(nd->nd_mrep);
3407
/*
3408
* Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
3409
* Only do this if vfs.nfs.ignore_eexist is set.
3410
* Never do this for NFSv4.1 or later minor versions, since sessions
3411
* should guarantee "exactly once" RPC semantics.
3412
*/
3413
if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
3414
nmp->nm_minorvers == 0))
3415
error = 0;
3416
return (error);
3417
}
3418
3419
/*
3420
* nfs remove directory call
3421
*/
3422
int
3423
nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred,
3424
NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp)
3425
{
3426
struct nfsrv_descript nfsd, *nd = &nfsd;
3427
int error = 0;
3428
3429
*dattrflagp = 0;
3430
if (namelen > NFS_MAXNAMLEN)
3431
return (ENAMETOOLONG);
3432
NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp, cred);
3433
(void) nfsm_strtom(nd, name, namelen);
3434
error = nfscl_request(nd, dvp, p, cred);
3435
if (error)
3436
return (error);
3437
if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
3438
error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL);
3439
if (nd->nd_repstat && !error)
3440
error = nd->nd_repstat;
3441
m_freem(nd->nd_mrep);
3442
/*
3443
* Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
3444
*/
3445
if (error == ENOENT)
3446
error = 0;
3447
return (error);
3448
}
3449
3450
/*
3451
* Check to make sure the file name in a Readdir reply is valid.
3452
*/
3453
static bool
3454
nfscl_invalidfname(bool is_v4, char *name, int len)
3455
{
3456
int i;
3457
char *cp;
3458
3459
if (is_v4 && ((len == 1 && name[0] == '.') ||
3460
(len == 2 && name[0] == '.' && name[1] == '.'))) {
3461
printf("Readdir NFSv4 reply has dot or dotdot in it\n");
3462
return (true);
3463
}
3464
cp = name;
3465
for (i = 0; i < len; i++, cp++) {
3466
if (*cp == '/' || *cp == '\0') {
3467
printf("Readdir reply file name had imbedded / or nul"
3468
" byte\n");
3469
return (true);
3470
}
3471
}
3472
return (false);
3473
}
3474
3475
/*
3476
* Readdir rpc.
3477
* Always returns with either uio_resid unchanged, if you are at the
3478
* end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks
3479
* filled in.
3480
* I felt this would allow caching of directory blocks more easily
3481
* than returning a pertially filled block.
3482
* Directory offset cookies:
3483
* Oh my, what to do with them...
3484
* I can think of three ways to deal with them:
3485
* 1 - have the layer above these RPCs maintain a map between logical
3486
* directory byte offsets and the NFS directory offset cookies
3487
* 2 - pass the opaque directory offset cookies up into userland
3488
* and let the libc functions deal with them, via the system call
3489
* 3 - return them to userland in the "struct dirent", so future versions
3490
* of libc can use them and do whatever is necessary to make things work
3491
* above these rpc calls, in the meantime
3492
* For now, I do #3 by "hiding" the directory offset cookies after the
3493
* d_name field in struct dirent. This is space inside d_reclen that
3494
* will be ignored by anything that doesn't know about them.
3495
* The directory offset cookies are filled in as the last 8 bytes of
3496
* each directory entry, after d_name. Someday, the userland libc
3497
* functions may be able to use these. In the meantime, it satisfies
3498
* OpenBSD's requirements for cookies being returned.
3499
* If expects the directory offset cookie for the read to be in uio_offset
3500
* and returns the one for the next entry after this directory block in
3501
* there, as well.
3502
*/
3503
int
3504
nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
3505
struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3506
int *eofp)
3507
{
3508
int len, left;
3509
struct dirent *dp = NULL;
3510
u_int32_t *tl;
3511
nfsquad_t cookie, ncookie;
3512
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
3513
struct nfsnode *dnp = VTONFS(vp);
3514
struct nfsvattr nfsva;
3515
struct nfsrv_descript nfsd, *nd = &nfsd;
3516
int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
3517
int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0;
3518
u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX;
3519
char *cp;
3520
nfsattrbit_t attrbits, dattrbits;
3521
u_int32_t rderr, *tl2 = NULL;
3522
size_t tresid;
3523
bool validentry;
3524
3525
KASSERT(uiop->uio_iovcnt == 1 &&
3526
(uiop->uio_resid & (DIRBLKSIZ - 1)) == 0,
3527
("nfs readdirrpc bad uio"));
3528
KASSERT(uiop->uio_segflg == UIO_SYSSPACE,
3529
("nfsrpc_readdir: uio userspace"));
3530
ncookie.lval[0] = ncookie.lval[1] = 0;
3531
/*
3532
* There is no point in reading a lot more than uio_resid, however
3533
* adding one additional DIRBLKSIZ makes sense. Since uio_resid
3534
* and nm_readdirsize are both exact multiples of DIRBLKSIZ, this
3535
* will never make readsize > nm_readdirsize.
3536
*/
3537
readsize = nmp->nm_readdirsize;
3538
if (readsize > uiop->uio_resid)
3539
readsize = uiop->uio_resid + DIRBLKSIZ;
3540
3541
*attrflagp = 0;
3542
if (eofp)
3543
*eofp = 0;
3544
tresid = uiop->uio_resid;
3545
cookie.lval[0] = cookiep->nfsuquad[0];
3546
cookie.lval[1] = cookiep->nfsuquad[1];
3547
nd->nd_mrep = NULL;
3548
3549
/*
3550
* For NFSv4, first create the "." and ".." entries.
3551
*/
3552
if (NFSHASNFSV4(nmp)) {
3553
reqsize = 6 * NFSX_UNSIGNED;
3554
NFSGETATTR_ATTRBIT(&dattrbits);
3555
NFSZERO_ATTRBIT(&attrbits);
3556
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
3557
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE);
3558
if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
3559
NFSATTRBIT_MOUNTEDONFILEID)) {
3560
NFSSETBIT_ATTRBIT(&attrbits,
3561
NFSATTRBIT_MOUNTEDONFILEID);
3562
gotmnton = 1;
3563
} else {
3564
/*
3565
* Must fake it. Use the fileno, except when the
3566
* fsid is != to that of the directory. For that
3567
* case, generate a fake fileno that is not the same.
3568
*/
3569
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
3570
gotmnton = 0;
3571
}
3572
3573
/*
3574
* Joy, oh joy. For V4 we get to hand craft '.' and '..'.
3575
*/
3576
if (uiop->uio_offset == 0) {
3577
NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp, cred);
3578
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3579
*tl++ = txdr_unsigned(NFSV4OP_GETFH);
3580
*tl = txdr_unsigned(NFSV4OP_GETATTR);
3581
(void) nfsrv_putattrbit(nd, &attrbits);
3582
error = nfscl_request(nd, vp, p, cred);
3583
if (error)
3584
return (error);
3585
dotfileid = 0; /* Fake out the compiler. */
3586
if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
3587
error = nfsm_loadattr(nd, &nfsva);
3588
if (error != 0)
3589
goto nfsmout;
3590
dotfileid = nfsva.na_fileid;
3591
}
3592
if (nd->nd_repstat == 0) {
3593
NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
3594
len = fxdr_unsigned(int, *(tl + 4));
3595
if (len > 0 && len <= NFSX_V4FHMAX)
3596
error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3597
else
3598
error = EPERM;
3599
if (!error) {
3600
NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3601
nfsva.na_mntonfileno = UINT64_MAX;
3602
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3603
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3604
NULL, NULL, NULL, NULL, NULL, NULL,
3605
p, cred);
3606
if (error) {
3607
dotdotfileid = dotfileid;
3608
} else if (gotmnton) {
3609
if (nfsva.na_mntonfileno != UINT64_MAX)
3610
dotdotfileid = nfsva.na_mntonfileno;
3611
else
3612
dotdotfileid = nfsva.na_fileid;
3613
} else if (nfsva.na_filesid[0] ==
3614
dnp->n_vattr.na_filesid[0] &&
3615
nfsva.na_filesid[1] ==
3616
dnp->n_vattr.na_filesid[1]) {
3617
dotdotfileid = nfsva.na_fileid;
3618
} else {
3619
do {
3620
fakefileno--;
3621
} while (fakefileno ==
3622
nfsva.na_fileid);
3623
dotdotfileid = fakefileno;
3624
}
3625
}
3626
} else if (nd->nd_repstat == NFSERR_NOENT) {
3627
/*
3628
* Lookupp returns NFSERR_NOENT when we are
3629
* at the root, so just use the current dir.
3630
*/
3631
nd->nd_repstat = 0;
3632
dotdotfileid = dotfileid;
3633
} else {
3634
error = nd->nd_repstat;
3635
}
3636
m_freem(nd->nd_mrep);
3637
if (error)
3638
return (error);
3639
nd->nd_mrep = NULL;
3640
dp = (struct dirent *)uiop->uio_iov->iov_base;
3641
dp->d_pad0 = dp->d_pad1 = 0;
3642
dp->d_off = 0;
3643
dp->d_type = DT_DIR;
3644
dp->d_fileno = dotfileid;
3645
dp->d_namlen = 1;
3646
*((uint64_t *)dp->d_name) = 0; /* Zero pad it. */
3647
dp->d_name[0] = '.';
3648
dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
3649
/*
3650
* Just make these offset cookie 0.
3651
*/
3652
tl = (u_int32_t *)&dp->d_name[8];
3653
*tl++ = 0;
3654
*tl = 0;
3655
blksiz += dp->d_reclen;
3656
uiop->uio_resid -= dp->d_reclen;
3657
uiop->uio_offset += dp->d_reclen;
3658
uiop->uio_iov->iov_base =
3659
(char *)uiop->uio_iov->iov_base + dp->d_reclen;
3660
uiop->uio_iov->iov_len -= dp->d_reclen;
3661
dp = (struct dirent *)uiop->uio_iov->iov_base;
3662
dp->d_pad0 = dp->d_pad1 = 0;
3663
dp->d_off = 0;
3664
dp->d_type = DT_DIR;
3665
dp->d_fileno = dotdotfileid;
3666
dp->d_namlen = 2;
3667
*((uint64_t *)dp->d_name) = 0;
3668
dp->d_name[0] = '.';
3669
dp->d_name[1] = '.';
3670
dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
3671
/*
3672
* Just make these offset cookie 0.
3673
*/
3674
tl = (u_int32_t *)&dp->d_name[8];
3675
*tl++ = 0;
3676
*tl = 0;
3677
blksiz += dp->d_reclen;
3678
uiop->uio_resid -= dp->d_reclen;
3679
uiop->uio_offset += dp->d_reclen;
3680
uiop->uio_iov->iov_base =
3681
(char *)uiop->uio_iov->iov_base + dp->d_reclen;
3682
uiop->uio_iov->iov_len -= dp->d_reclen;
3683
}
3684
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR);
3685
} else {
3686
reqsize = 5 * NFSX_UNSIGNED;
3687
}
3688
3689
/*
3690
* Loop around doing readdir rpc's of size readsize.
3691
* The stopping criteria is EOF or buffer full.
3692
*/
3693
while (more_dirs && bigenough) {
3694
*attrflagp = 0;
3695
NFSCL_REQSTART(nd, NFSPROC_READDIR, vp, cred);
3696
if (nd->nd_flag & ND_NFSV2) {
3697
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3698
*tl++ = cookie.lval[1];
3699
*tl = txdr_unsigned(readsize);
3700
} else {
3701
NFSM_BUILD(tl, u_int32_t *, reqsize);
3702
*tl++ = cookie.lval[0];
3703
*tl++ = cookie.lval[1];
3704
if (cookie.qval == 0) {
3705
*tl++ = 0;
3706
*tl++ = 0;
3707
} else {
3708
NFSLOCKNODE(dnp);
3709
*tl++ = dnp->n_cookieverf.nfsuquad[0];
3710
*tl++ = dnp->n_cookieverf.nfsuquad[1];
3711
NFSUNLOCKNODE(dnp);
3712
}
3713
if (nd->nd_flag & ND_NFSV4) {
3714
*tl++ = txdr_unsigned(readsize);
3715
*tl = txdr_unsigned(readsize);
3716
(void) nfsrv_putattrbit(nd, &attrbits);
3717
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3718
*tl = txdr_unsigned(NFSV4OP_GETATTR);
3719
(void) nfsrv_putattrbit(nd, &dattrbits);
3720
} else {
3721
*tl = txdr_unsigned(readsize);
3722
}
3723
}
3724
error = nfscl_request(nd, vp, p, cred);
3725
if (error)
3726
return (error);
3727
if (!(nd->nd_flag & ND_NFSV2)) {
3728
if (nd->nd_flag & ND_NFSV3)
3729
error = nfscl_postop_attr(nd, nap, attrflagp);
3730
if (!nd->nd_repstat && !error) {
3731
NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3732
NFSLOCKNODE(dnp);
3733
dnp->n_cookieverf.nfsuquad[0] = *tl++;
3734
dnp->n_cookieverf.nfsuquad[1] = *tl;
3735
NFSUNLOCKNODE(dnp);
3736
}
3737
}
3738
if (nd->nd_repstat || error) {
3739
if (!error)
3740
error = nd->nd_repstat;
3741
goto nfsmout;
3742
}
3743
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3744
more_dirs = fxdr_unsigned(int, *tl);
3745
if (!more_dirs)
3746
tryformoredirs = 0;
3747
3748
/* loop through the dir entries, doctoring them to 4bsd form */
3749
while (more_dirs && bigenough) {
3750
validentry = true;
3751
if (nd->nd_flag & ND_NFSV4) {
3752
NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3753
ncookie.lval[0] = *tl++;
3754
ncookie.lval[1] = *tl++;
3755
len = fxdr_unsigned(int, *tl);
3756
} else if (nd->nd_flag & ND_NFSV3) {
3757
NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3758
nfsva.na_fileid = fxdr_hyper(tl);
3759
tl += 2;
3760
len = fxdr_unsigned(int, *tl);
3761
} else {
3762
NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3763
nfsva.na_fileid = fxdr_unsigned(uint64_t,
3764
*tl++);
3765
len = fxdr_unsigned(int, *tl);
3766
}
3767
if (len <= 0 || len > NFS_MAXNAMLEN) {
3768
error = EBADRPC;
3769
goto nfsmout;
3770
}
3771
tlen = roundup2(len, 8);
3772
if (tlen == len)
3773
tlen += 8; /* To ensure null termination. */
3774
left = DIRBLKSIZ - blksiz;
3775
if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) {
3776
NFSBZERO(uiop->uio_iov->iov_base, left);
3777
dp->d_reclen += left;
3778
uiop->uio_iov->iov_base =
3779
(char *)uiop->uio_iov->iov_base + left;
3780
uiop->uio_iov->iov_len -= left;
3781
uiop->uio_resid -= left;
3782
uiop->uio_offset += left;
3783
blksiz = 0;
3784
}
3785
if (_GENERIC_DIRLEN(len) + NFSX_HYPER >
3786
uiop->uio_resid)
3787
bigenough = 0;
3788
if (bigenough) {
3789
struct iovec saviov;
3790
off_t savoff;
3791
ssize_t savresid;
3792
int savblksiz;
3793
3794
saviov.iov_base = uiop->uio_iov->iov_base;
3795
saviov.iov_len = uiop->uio_iov->iov_len;
3796
savoff = uiop->uio_offset;
3797
savresid = uiop->uio_resid;
3798
savblksiz = blksiz;
3799
3800
dp = (struct dirent *)uiop->uio_iov->iov_base;
3801
dp->d_pad0 = dp->d_pad1 = 0;
3802
dp->d_off = 0;
3803
dp->d_namlen = len;
3804
dp->d_reclen = _GENERIC_DIRLEN(len) +
3805
NFSX_HYPER;
3806
dp->d_type = DT_UNKNOWN;
3807
blksiz += dp->d_reclen;
3808
if (blksiz == DIRBLKSIZ)
3809
blksiz = 0;
3810
uiop->uio_resid -= DIRHDSIZ;
3811
uiop->uio_offset += DIRHDSIZ;
3812
uiop->uio_iov->iov_base =
3813
(char *)uiop->uio_iov->iov_base + DIRHDSIZ;
3814
uiop->uio_iov->iov_len -= DIRHDSIZ;
3815
cp = uiop->uio_iov->iov_base;
3816
error = nfsm_mbufuio(nd, uiop, len);
3817
if (error)
3818
goto nfsmout;
3819
/* Check for an invalid file name. */
3820
if (nfscl_invalidfname(
3821
(nd->nd_flag & ND_NFSV4) != 0, cp, len)) {
3822
/* Skip over this entry. */
3823
uiop->uio_iov->iov_base =
3824
saviov.iov_base;
3825
uiop->uio_iov->iov_len =
3826
saviov.iov_len;
3827
uiop->uio_offset = savoff;
3828
uiop->uio_resid = savresid;
3829
blksiz = savblksiz;
3830
validentry = false;
3831
} else {
3832
cp = uiop->uio_iov->iov_base;
3833
tlen -= len;
3834
NFSBZERO(cp, tlen);
3835
cp += tlen; /* points to cookie store */
3836
tl2 = (u_int32_t *)cp;
3837
uiop->uio_iov->iov_base =
3838
(char *)uiop->uio_iov->iov_base +
3839
tlen + NFSX_HYPER;
3840
uiop->uio_iov->iov_len -= tlen +
3841
NFSX_HYPER;
3842
uiop->uio_resid -= tlen + NFSX_HYPER;
3843
uiop->uio_offset += (tlen + NFSX_HYPER);
3844
}
3845
} else {
3846
error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
3847
if (error)
3848
goto nfsmout;
3849
}
3850
if (nd->nd_flag & ND_NFSV4) {
3851
rderr = 0;
3852
nfsva.na_mntonfileno = UINT64_MAX;
3853
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
3854
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
3855
NULL, NULL, &rderr, NULL, NULL, NULL,
3856
p, cred);
3857
if (error)
3858
goto nfsmout;
3859
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3860
} else if (nd->nd_flag & ND_NFSV3) {
3861
NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
3862
ncookie.lval[0] = *tl++;
3863
ncookie.lval[1] = *tl++;
3864
} else {
3865
NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
3866
ncookie.lval[0] = 0;
3867
ncookie.lval[1] = *tl++;
3868
}
3869
if (bigenough && validentry) {
3870
if (nd->nd_flag & ND_NFSV4) {
3871
if (rderr) {
3872
dp->d_fileno = 0;
3873
} else {
3874
if (gotmnton) {
3875
if (nfsva.na_mntonfileno != UINT64_MAX)
3876
dp->d_fileno = nfsva.na_mntonfileno;
3877
else
3878
dp->d_fileno = nfsva.na_fileid;
3879
} else if (nfsva.na_filesid[0] ==
3880
dnp->n_vattr.na_filesid[0] &&
3881
nfsva.na_filesid[1] ==
3882
dnp->n_vattr.na_filesid[1]) {
3883
dp->d_fileno = nfsva.na_fileid;
3884
} else {
3885
do {
3886
fakefileno--;
3887
} while (fakefileno ==
3888
nfsva.na_fileid);
3889
dp->d_fileno = fakefileno;
3890
}
3891
dp->d_type = vtonfs_dtype(nfsva.na_type);
3892
}
3893
} else {
3894
dp->d_fileno = nfsva.na_fileid;
3895
}
3896
*tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
3897
ncookie.lval[0];
3898
*tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
3899
ncookie.lval[1];
3900
}
3901
more_dirs = fxdr_unsigned(int, *tl);
3902
}
3903
/*
3904
* If at end of rpc data, get the eof boolean
3905
*/
3906
if (!more_dirs) {
3907
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3908
eof = fxdr_unsigned(int, *tl);
3909
if (tryformoredirs)
3910
more_dirs = !eof;
3911
if (nd->nd_flag & ND_NFSV4) {
3912
error = nfscl_postop_attr(nd, nap, attrflagp);
3913
if (error)
3914
goto nfsmout;
3915
}
3916
}
3917
m_freem(nd->nd_mrep);
3918
nd->nd_mrep = NULL;
3919
}
3920
/*
3921
* Fill last record, iff any, out to a multiple of DIRBLKSIZ
3922
* by increasing d_reclen for the last record.
3923
*/
3924
if (blksiz > 0) {
3925
left = DIRBLKSIZ - blksiz;
3926
NFSBZERO(uiop->uio_iov->iov_base, left);
3927
dp->d_reclen += left;
3928
uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base +
3929
left;
3930
uiop->uio_iov->iov_len -= left;
3931
uiop->uio_resid -= left;
3932
uiop->uio_offset += left;
3933
}
3934
3935
/*
3936
* If returning no data, assume end of file.
3937
* If not bigenough, return not end of file, since you aren't
3938
* returning all the data
3939
* Otherwise, return the eof flag from the server.
3940
*/
3941
if (eofp) {
3942
if (tresid == ((size_t)(uiop->uio_resid)))
3943
*eofp = 1;
3944
else if (!bigenough)
3945
*eofp = 0;
3946
else
3947
*eofp = eof;
3948
}
3949
3950
/*
3951
* Add extra empty records to any remaining DIRBLKSIZ chunks.
3952
*/
3953
while (uiop->uio_resid > 0 && uiop->uio_resid != tresid) {
3954
dp = (struct dirent *)uiop->uio_iov->iov_base;
3955
NFSBZERO(dp, DIRBLKSIZ);
3956
dp->d_type = DT_UNKNOWN;
3957
tl = (u_int32_t *)&dp->d_name[4];
3958
*tl++ = cookie.lval[0];
3959
*tl = cookie.lval[1];
3960
dp->d_reclen = DIRBLKSIZ;
3961
uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base +
3962
DIRBLKSIZ;
3963
uiop->uio_iov->iov_len -= DIRBLKSIZ;
3964
uiop->uio_resid -= DIRBLKSIZ;
3965
uiop->uio_offset += DIRBLKSIZ;
3966
}
3967
3968
nfsmout:
3969
if (nd->nd_mrep != NULL)
3970
m_freem(nd->nd_mrep);
3971
return (error);
3972
}
3973
3974
/*
3975
* NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir().
3976
* (Also used for NFS V4 when mount flag set.)
3977
* (ditto above w.r.t. multiple of DIRBLKSIZ, etc.)
3978
*/
3979
int
3980
nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
3981
struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
3982
int *eofp)
3983
{
3984
int len, left;
3985
struct dirent *dp = NULL;
3986
u_int32_t *tl;
3987
vnode_t newvp = NULL;
3988
struct nfsrv_descript nfsd, *nd = &nfsd;
3989
struct nameidata nami, *ndp = &nami;
3990
struct componentname *cnp = &ndp->ni_cnd;
3991
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
3992
struct nfsnode *dnp = VTONFS(vp), *np;
3993
struct nfsvattr nfsva;
3994
struct nfsfh *nfhp;
3995
nfsquad_t cookie, ncookie;
3996
int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
3997
int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0;
3998
int isdotdot = 0, unlocknewvp = 0;
3999
u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX;
4000
u_int64_t fileno = 0;
4001
char *cp;
4002
nfsattrbit_t attrbits, dattrbits;
4003
size_t tresid;
4004
u_int32_t *tl2 = NULL, rderr;
4005
struct timespec dctime, ts;
4006
bool attr_ok, named_dir, validentry;
4007
4008
KASSERT(uiop->uio_iovcnt == 1 &&
4009
(uiop->uio_resid & (DIRBLKSIZ - 1)) == 0,
4010
("nfs readdirplusrpc bad uio"));
4011
KASSERT(uiop->uio_segflg == UIO_SYSSPACE,
4012
("nfsrpc_readdirplus: uio userspace"));
4013
named_dir = false;
4014
if ((vp->v_irflag & VIRF_NAMEDDIR) != 0)
4015
named_dir = true;
4016
ncookie.lval[0] = ncookie.lval[1] = 0;
4017
timespecclear(&dctime);
4018
*attrflagp = 0;
4019
if (eofp != NULL)
4020
*eofp = 0;
4021
ndp->ni_dvp = vp;
4022
nd->nd_mrep = NULL;
4023
cookie.lval[0] = cookiep->nfsuquad[0];
4024
cookie.lval[1] = cookiep->nfsuquad[1];
4025
tresid = uiop->uio_resid;
4026
4027
/*
4028
* For NFSv4, first create the "." and ".." entries.
4029
*/
4030
if (NFSHASNFSV4(nmp)) {
4031
NFSGETATTR_ATTRBIT(&dattrbits);
4032
NFSZERO_ATTRBIT(&attrbits);
4033
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
4034
if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
4035
NFSATTRBIT_MOUNTEDONFILEID)) {
4036
NFSSETBIT_ATTRBIT(&attrbits,
4037
NFSATTRBIT_MOUNTEDONFILEID);
4038
gotmnton = 1;
4039
} else {
4040
/*
4041
* Must fake it. Use the fileno, except when the
4042
* fsid is != to that of the directory. For that
4043
* case, generate a fake fileno that is not the same.
4044
*/
4045
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
4046
gotmnton = 0;
4047
}
4048
4049
/*
4050
* Joy, oh joy. For V4 we get to hand craft '.' and '..'.
4051
*/
4052
if (uiop->uio_offset == 0) {
4053
NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp, cred);
4054
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4055
*tl++ = txdr_unsigned(NFSV4OP_GETFH);
4056
*tl = txdr_unsigned(NFSV4OP_GETATTR);
4057
(void) nfsrv_putattrbit(nd, &attrbits);
4058
error = nfscl_request(nd, vp, p, cred);
4059
if (error)
4060
return (error);
4061
dotfileid = 0; /* Fake out the compiler. */
4062
if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
4063
error = nfsm_loadattr(nd, &nfsva);
4064
if (error != 0)
4065
goto nfsmout;
4066
dctime = nfsva.na_ctime;
4067
dotfileid = nfsva.na_fileid;
4068
}
4069
if (nd->nd_repstat == 0) {
4070
NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
4071
len = fxdr_unsigned(int, *(tl + 4));
4072
if (len > 0 && len <= NFSX_V4FHMAX)
4073
error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
4074
else
4075
error = EPERM;
4076
if (!error) {
4077
NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
4078
nfsva.na_mntonfileno = UINT64_MAX;
4079
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
4080
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
4081
NULL, NULL, NULL, NULL, NULL, NULL,
4082
p, cred);
4083
if (error) {
4084
dotdotfileid = dotfileid;
4085
} else if (gotmnton) {
4086
if (nfsva.na_mntonfileno != UINT64_MAX)
4087
dotdotfileid = nfsva.na_mntonfileno;
4088
else
4089
dotdotfileid = nfsva.na_fileid;
4090
} else if (nfsva.na_filesid[0] ==
4091
dnp->n_vattr.na_filesid[0] &&
4092
nfsva.na_filesid[1] ==
4093
dnp->n_vattr.na_filesid[1]) {
4094
dotdotfileid = nfsva.na_fileid;
4095
} else {
4096
do {
4097
fakefileno--;
4098
} while (fakefileno ==
4099
nfsva.na_fileid);
4100
dotdotfileid = fakefileno;
4101
}
4102
}
4103
} else if (nd->nd_repstat == NFSERR_NOENT) {
4104
/*
4105
* Lookupp returns NFSERR_NOENT when we are
4106
* at the root, so just use the current dir.
4107
*/
4108
nd->nd_repstat = 0;
4109
dotdotfileid = dotfileid;
4110
} else {
4111
error = nd->nd_repstat;
4112
}
4113
m_freem(nd->nd_mrep);
4114
if (error)
4115
return (error);
4116
nd->nd_mrep = NULL;
4117
dp = (struct dirent *)uiop->uio_iov->iov_base;
4118
dp->d_pad0 = dp->d_pad1 = 0;
4119
dp->d_off = 0;
4120
dp->d_type = DT_DIR;
4121
dp->d_fileno = dotfileid;
4122
dp->d_namlen = 1;
4123
*((uint64_t *)dp->d_name) = 0; /* Zero pad it. */
4124
dp->d_name[0] = '.';
4125
dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
4126
/*
4127
* Just make these offset cookie 0.
4128
*/
4129
tl = (u_int32_t *)&dp->d_name[8];
4130
*tl++ = 0;
4131
*tl = 0;
4132
blksiz += dp->d_reclen;
4133
uiop->uio_resid -= dp->d_reclen;
4134
uiop->uio_offset += dp->d_reclen;
4135
uiop->uio_iov->iov_base =
4136
(char *)uiop->uio_iov->iov_base + dp->d_reclen;
4137
uiop->uio_iov->iov_len -= dp->d_reclen;
4138
dp = (struct dirent *)uiop->uio_iov->iov_base;
4139
dp->d_pad0 = dp->d_pad1 = 0;
4140
dp->d_off = 0;
4141
dp->d_type = DT_DIR;
4142
dp->d_fileno = dotdotfileid;
4143
dp->d_namlen = 2;
4144
*((uint64_t *)dp->d_name) = 0;
4145
dp->d_name[0] = '.';
4146
dp->d_name[1] = '.';
4147
dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
4148
/*
4149
* Just make these offset cookie 0.
4150
*/
4151
tl = (u_int32_t *)&dp->d_name[8];
4152
*tl++ = 0;
4153
*tl = 0;
4154
blksiz += dp->d_reclen;
4155
uiop->uio_resid -= dp->d_reclen;
4156
uiop->uio_offset += dp->d_reclen;
4157
uiop->uio_iov->iov_base =
4158
(char *)uiop->uio_iov->iov_base + dp->d_reclen;
4159
uiop->uio_iov->iov_len -= dp->d_reclen;
4160
}
4161
NFSREADDIRPLUS_ATTRBIT(&attrbits);
4162
if (gotmnton)
4163
NFSSETBIT_ATTRBIT(&attrbits,
4164
NFSATTRBIT_MOUNTEDONFILEID);
4165
if (!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
4166
NFSATTRBIT_TIMECREATE))
4167
NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE);
4168
if (!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
4169
NFSATTRBIT_ARCHIVE) ||
4170
!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
4171
NFSATTRBIT_HIDDEN) ||
4172
!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
4173
NFSATTRBIT_SYSTEM)) {
4174
NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_ARCHIVE);
4175
NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN);
4176
NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM);
4177
}
4178
}
4179
4180
/*
4181
* Loop around doing readdir rpc's of size nm_readdirsize.
4182
* The stopping criteria is EOF or buffer full.
4183
*/
4184
while (more_dirs && bigenough) {
4185
*attrflagp = 0;
4186
NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp, cred);
4187
NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
4188
*tl++ = cookie.lval[0];
4189
*tl++ = cookie.lval[1];
4190
if (cookie.qval == 0) {
4191
*tl++ = 0;
4192
*tl++ = 0;
4193
} else {
4194
NFSLOCKNODE(dnp);
4195
*tl++ = dnp->n_cookieverf.nfsuquad[0];
4196
*tl++ = dnp->n_cookieverf.nfsuquad[1];
4197
NFSUNLOCKNODE(dnp);
4198
}
4199
*tl++ = txdr_unsigned(nmp->nm_readdirsize);
4200
*tl = txdr_unsigned(nmp->nm_readdirsize);
4201
if (nd->nd_flag & ND_NFSV4) {
4202
(void) nfsrv_putattrbit(nd, &attrbits);
4203
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4204
*tl = txdr_unsigned(NFSV4OP_GETATTR);
4205
(void) nfsrv_putattrbit(nd, &dattrbits);
4206
}
4207
nanouptime(&ts);
4208
error = nfscl_request(nd, vp, p, cred);
4209
if (error)
4210
return (error);
4211
if (nd->nd_flag & ND_NFSV3)
4212
error = nfscl_postop_attr(nd, nap, attrflagp);
4213
if (nd->nd_repstat || error) {
4214
if (!error)
4215
error = nd->nd_repstat;
4216
goto nfsmout;
4217
}
4218
if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0)
4219
dctime = nap->na_ctime;
4220
NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
4221
NFSLOCKNODE(dnp);
4222
dnp->n_cookieverf.nfsuquad[0] = *tl++;
4223
dnp->n_cookieverf.nfsuquad[1] = *tl++;
4224
NFSUNLOCKNODE(dnp);
4225
more_dirs = fxdr_unsigned(int, *tl);
4226
if (!more_dirs)
4227
tryformoredirs = 0;
4228
4229
/* loop through the dir entries, doctoring them to 4bsd form */
4230
while (more_dirs && bigenough) {
4231
validentry = true;
4232
NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
4233
if (nd->nd_flag & ND_NFSV4) {
4234
ncookie.lval[0] = *tl++;
4235
ncookie.lval[1] = *tl++;
4236
} else {
4237
fileno = fxdr_hyper(tl);
4238
tl += 2;
4239
}
4240
len = fxdr_unsigned(int, *tl);
4241
if (len <= 0 || len > NFS_MAXNAMLEN) {
4242
error = EBADRPC;
4243
goto nfsmout;
4244
}
4245
tlen = roundup2(len, 8);
4246
if (tlen == len)
4247
tlen += 8; /* To ensure null termination. */
4248
left = DIRBLKSIZ - blksiz;
4249
if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) {
4250
NFSBZERO(uiop->uio_iov->iov_base, left);
4251
dp->d_reclen += left;
4252
uiop->uio_iov->iov_base =
4253
(char *)uiop->uio_iov->iov_base + left;
4254
uiop->uio_iov->iov_len -= left;
4255
uiop->uio_resid -= left;
4256
uiop->uio_offset += left;
4257
blksiz = 0;
4258
}
4259
if (_GENERIC_DIRLEN(len) + NFSX_HYPER >
4260
uiop->uio_resid)
4261
bigenough = 0;
4262
if (bigenough) {
4263
struct iovec saviov;
4264
off_t savoff;
4265
ssize_t savresid;
4266
int savblksiz;
4267
4268
saviov.iov_base = uiop->uio_iov->iov_base;
4269
saviov.iov_len = uiop->uio_iov->iov_len;
4270
savoff = uiop->uio_offset;
4271
savresid = uiop->uio_resid;
4272
savblksiz = blksiz;
4273
4274
dp = (struct dirent *)uiop->uio_iov->iov_base;
4275
dp->d_pad0 = dp->d_pad1 = 0;
4276
dp->d_off = 0;
4277
dp->d_namlen = len;
4278
dp->d_reclen = _GENERIC_DIRLEN(len) +
4279
NFSX_HYPER;
4280
dp->d_type = DT_UNKNOWN;
4281
blksiz += dp->d_reclen;
4282
if (blksiz == DIRBLKSIZ)
4283
blksiz = 0;
4284
uiop->uio_resid -= DIRHDSIZ;
4285
uiop->uio_offset += DIRHDSIZ;
4286
uiop->uio_iov->iov_base =
4287
(char *)uiop->uio_iov->iov_base + DIRHDSIZ;
4288
uiop->uio_iov->iov_len -= DIRHDSIZ;
4289
cnp->cn_nameptr = uiop->uio_iov->iov_base;
4290
cnp->cn_namelen = len;
4291
NFSCNHASHZERO(cnp);
4292
cp = uiop->uio_iov->iov_base;
4293
error = nfsm_mbufuio(nd, uiop, len);
4294
if (error)
4295
goto nfsmout;
4296
/* Check for an invalid file name. */
4297
if (nfscl_invalidfname(
4298
(nd->nd_flag & ND_NFSV4) != 0, cp, len)) {
4299
/* Skip over this entry. */
4300
uiop->uio_iov->iov_base =
4301
saviov.iov_base;
4302
uiop->uio_iov->iov_len =
4303
saviov.iov_len;
4304
uiop->uio_offset = savoff;
4305
uiop->uio_resid = savresid;
4306
blksiz = savblksiz;
4307
validentry = false;
4308
} else {
4309
cp = uiop->uio_iov->iov_base;
4310
tlen -= len;
4311
NFSBZERO(cp, tlen);
4312
cp += tlen; /* points to cookie store */
4313
tl2 = (u_int32_t *)cp;
4314
if (len == 2 &&
4315
cnp->cn_nameptr[0] == '.' &&
4316
cnp->cn_nameptr[1] == '.')
4317
isdotdot = 1;
4318
else
4319
isdotdot = 0;
4320
uiop->uio_iov->iov_base =
4321
(char *)uiop->uio_iov->iov_base +
4322
tlen + NFSX_HYPER;
4323
uiop->uio_iov->iov_len -= tlen +
4324
NFSX_HYPER;
4325
uiop->uio_resid -= tlen + NFSX_HYPER;
4326
uiop->uio_offset += (tlen + NFSX_HYPER);
4327
}
4328
} else {
4329
error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
4330
if (error)
4331
goto nfsmout;
4332
}
4333
nfhp = NULL;
4334
if (nd->nd_flag & ND_NFSV3) {
4335
NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
4336
ncookie.lval[0] = *tl++;
4337
ncookie.lval[1] = *tl++;
4338
attrflag = fxdr_unsigned(int, *tl);
4339
if (attrflag) {
4340
error = nfsm_loadattr(nd, &nfsva);
4341
if (error)
4342
goto nfsmout;
4343
}
4344
NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED);
4345
if (*tl) {
4346
error = nfsm_getfh(nd, &nfhp);
4347
if (error)
4348
goto nfsmout;
4349
}
4350
if (!attrflag && nfhp != NULL) {
4351
free(nfhp, M_NFSFH);
4352
nfhp = NULL;
4353
}
4354
} else {
4355
rderr = 0;
4356
nfsva.na_mntonfileno = 0xffffffff;
4357
error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
4358
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
4359
NULL, NULL, &rderr, NULL, NULL, NULL,
4360
p, cred);
4361
if (error)
4362
goto nfsmout;
4363
}
4364
4365
if (bigenough && validentry) {
4366
if (nd->nd_flag & ND_NFSV4) {
4367
if (rderr) {
4368
dp->d_fileno = 0;
4369
} else if (gotmnton) {
4370
if (nfsva.na_mntonfileno != 0xffffffff)
4371
dp->d_fileno = nfsva.na_mntonfileno;
4372
else
4373
dp->d_fileno = nfsva.na_fileid;
4374
} else if (nfsva.na_filesid[0] ==
4375
dnp->n_vattr.na_filesid[0] &&
4376
nfsva.na_filesid[1] ==
4377
dnp->n_vattr.na_filesid[1]) {
4378
dp->d_fileno = nfsva.na_fileid;
4379
} else {
4380
do {
4381
fakefileno--;
4382
} while (fakefileno ==
4383
nfsva.na_fileid);
4384
dp->d_fileno = fakefileno;
4385
}
4386
} else {
4387
dp->d_fileno = fileno;
4388
}
4389
*tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
4390
ncookie.lval[0];
4391
*tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
4392
ncookie.lval[1];
4393
4394
if (nfhp != NULL) {
4395
attr_ok = true;
4396
if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len,
4397
dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) {
4398
vref(vp);
4399
newvp = vp;
4400
unlocknewvp = 0;
4401
free(nfhp, M_NFSFH);
4402
np = dnp;
4403
} else if (isdotdot != 0) {
4404
/*
4405
* Skip doing a nfscl_nget() call for "..".
4406
* There's a race between acquiring the nfs
4407
* node here and lookups that look for the
4408
* directory being read (in the parent).
4409
* It would try to get a lock on ".." here,
4410
* owning the lock on the directory being
4411
* read. Lookup will hold the lock on ".."
4412
* and try to acquire the lock on the
4413
* directory being read.
4414
* If the directory is unlocked/relocked,
4415
* then there is a LOR with the buflock
4416
* vp is relocked.
4417
*/
4418
free(nfhp, M_NFSFH);
4419
} else {
4420
error = nfscl_nget(vp->v_mount, vp,
4421
nfhp, cnp, p, &np, LK_EXCLUSIVE);
4422
if (!error) {
4423
newvp = NFSTOV(np);
4424
unlocknewvp = 1;
4425
/*
4426
* If n_localmodtime >= time before RPC,
4427
* then a file modification operation,
4428
* such as VOP_SETATTR() of size, has
4429
* occurred while the Lookup RPC and
4430
* acquisition of the vnode happened. As
4431
* such, the attributes might be stale,
4432
* with possibly an incorrect size.
4433
*/
4434
NFSLOCKNODE(np);
4435
if (timespecisset(
4436
&np->n_localmodtime) &&
4437
timespeccmp(&np->n_localmodtime,
4438
&ts, >=)) {
4439
NFSCL_DEBUG(4, "nfsrpc_readdirplus:"
4440
" localmod stale attributes\n");
4441
attr_ok = false;
4442
}
4443
NFSUNLOCKNODE(np);
4444
}
4445
}
4446
nfhp = NULL;
4447
if (newvp != NULL) {
4448
if (attr_ok)
4449
error = nfscl_loadattrcache(&newvp,
4450
&nfsva, NULL, 0, 0);
4451
if (error) {
4452
if (unlocknewvp)
4453
vput(newvp);
4454
else
4455
vrele(newvp);
4456
goto nfsmout;
4457
}
4458
dp->d_type =
4459
vtonfs_dtype(np->n_vattr.na_type);
4460
ndp->ni_vp = newvp;
4461
NFSCNHASH(cnp, HASHINIT);
4462
if (cnp->cn_namelen <= NCHNAMLEN &&
4463
ndp->ni_dvp != ndp->ni_vp &&
4464
(newvp->v_type != VDIR ||
4465
dctime.tv_sec != 0) &&
4466
!named_dir) {
4467
cache_enter_time_flags(ndp->ni_dvp,
4468
ndp->ni_vp, cnp,
4469
&nfsva.na_ctime,
4470
newvp->v_type != VDIR ? NULL :
4471
&dctime, VFS_CACHE_DROPOLD);
4472
}
4473
if (unlocknewvp)
4474
vput(newvp);
4475
else
4476
vrele(newvp);
4477
newvp = NULL;
4478
}
4479
}
4480
} else if (nfhp != NULL) {
4481
free(nfhp, M_NFSFH);
4482
}
4483
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4484
more_dirs = fxdr_unsigned(int, *tl);
4485
}
4486
/*
4487
* If at end of rpc data, get the eof boolean
4488
*/
4489
if (!more_dirs) {
4490
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4491
eof = fxdr_unsigned(int, *tl);
4492
if (tryformoredirs)
4493
more_dirs = !eof;
4494
if (nd->nd_flag & ND_NFSV4) {
4495
error = nfscl_postop_attr(nd, nap, attrflagp);
4496
if (error)
4497
goto nfsmout;
4498
}
4499
}
4500
m_freem(nd->nd_mrep);
4501
nd->nd_mrep = NULL;
4502
}
4503
/*
4504
* Fill last record, iff any, out to a multiple of DIRBLKSIZ
4505
* by increasing d_reclen for the last record.
4506
*/
4507
if (blksiz > 0) {
4508
left = DIRBLKSIZ - blksiz;
4509
NFSBZERO(uiop->uio_iov->iov_base, left);
4510
dp->d_reclen += left;
4511
uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base +
4512
left;
4513
uiop->uio_iov->iov_len -= left;
4514
uiop->uio_resid -= left;
4515
uiop->uio_offset += left;
4516
}
4517
4518
/*
4519
* If returning no data, assume end of file.
4520
* If not bigenough, return not end of file, since you aren't
4521
* returning all the data
4522
* Otherwise, return the eof flag from the server.
4523
*/
4524
if (eofp != NULL) {
4525
if (tresid == uiop->uio_resid)
4526
*eofp = 1;
4527
else if (!bigenough)
4528
*eofp = 0;
4529
else
4530
*eofp = eof;
4531
}
4532
4533
/*
4534
* Add extra empty records to any remaining DIRBLKSIZ chunks.
4535
*/
4536
while (uiop->uio_resid > 0 && uiop->uio_resid != tresid) {
4537
dp = (struct dirent *)uiop->uio_iov->iov_base;
4538
NFSBZERO(dp, DIRBLKSIZ);
4539
dp->d_type = DT_UNKNOWN;
4540
tl = (u_int32_t *)&dp->d_name[4];
4541
*tl++ = cookie.lval[0];
4542
*tl = cookie.lval[1];
4543
dp->d_reclen = DIRBLKSIZ;
4544
uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base +
4545
DIRBLKSIZ;
4546
uiop->uio_iov->iov_len -= DIRBLKSIZ;
4547
uiop->uio_resid -= DIRBLKSIZ;
4548
uiop->uio_offset += DIRBLKSIZ;
4549
}
4550
4551
nfsmout:
4552
if (nd->nd_mrep != NULL)
4553
m_freem(nd->nd_mrep);
4554
return (error);
4555
}
4556
4557
/*
4558
* Nfs commit rpc
4559
*/
4560
int
4561
nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred,
4562
NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
4563
{
4564
u_int32_t *tl;
4565
struct nfsrv_descript nfsd, *nd = &nfsd;
4566
nfsattrbit_t attrbits;
4567
int error;
4568
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
4569
4570
*attrflagp = 0;
4571
NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp, cred);
4572
NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
4573
txdr_hyper(offset, tl);
4574
tl += 2;
4575
*tl = txdr_unsigned(cnt);
4576
if (nd->nd_flag & ND_NFSV4) {
4577
/*
4578
* And do a Getattr op.
4579
*/
4580
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4581
*tl = txdr_unsigned(NFSV4OP_GETATTR);
4582
NFSGETATTR_ATTRBIT(&attrbits);
4583
(void) nfsrv_putattrbit(nd, &attrbits);
4584
}
4585
error = nfscl_request(nd, vp, p, cred);
4586
if (error)
4587
return (error);
4588
error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, NULL);
4589
if (!error && !nd->nd_repstat) {
4590
NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
4591
NFSLOCKMNT(nmp);
4592
if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) {
4593
NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
4594
nd->nd_repstat = NFSERR_STALEWRITEVERF;
4595
}
4596
NFSUNLOCKMNT(nmp);
4597
if (nd->nd_flag & ND_NFSV4)
4598
error = nfscl_postop_attr(nd, nap, attrflagp);
4599
}
4600
nfsmout:
4601
if (!error && nd->nd_repstat)
4602
error = nd->nd_repstat;
4603
m_freem(nd->nd_mrep);
4604
return (error);
4605
}
4606
4607
/*
4608
* NFS byte range lock rpc.
4609
* (Mostly just calls one of the three lower level RPC routines.)
4610
*/
4611
int
4612
nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
4613
int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
4614
{
4615
struct nfscllockowner *lp;
4616
struct nfsclclient *clp;
4617
struct nfsfh *nfhp;
4618
struct nfsrv_descript nfsd, *nd = &nfsd;
4619
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
4620
u_int64_t off, len;
4621
off_t start, end;
4622
u_int32_t clidrev = 0;
4623
int error = 0, newone = 0, expireret = 0, retrycnt, donelocally;
4624
int callcnt, dorpc;
4625
4626
/*
4627
* Convert the flock structure into a start and end and do POSIX
4628
* bounds checking.
4629
*/
4630
switch (fl->l_whence) {
4631
case SEEK_SET:
4632
case SEEK_CUR:
4633
/*
4634
* Caller is responsible for adding any necessary offset
4635
* when SEEK_CUR is used.
4636
*/
4637
start = fl->l_start;
4638
off = fl->l_start;
4639
break;
4640
case SEEK_END:
4641
start = size + fl->l_start;
4642
off = size + fl->l_start;
4643
break;
4644
default:
4645
return (EINVAL);
4646
}
4647
if (start < 0)
4648
return (EINVAL);
4649
if (fl->l_len != 0) {
4650
end = start + fl->l_len - 1;
4651
if (end < start)
4652
return (EINVAL);
4653
}
4654
4655
len = fl->l_len;
4656
if (len == 0)
4657
len = NFS64BITSSET;
4658
retrycnt = 0;
4659
do {
4660
nd->nd_repstat = 0;
4661
if (op == F_GETLK) {
4662
error = nfscl_getcl(vp->v_mount, cred, p, false, true, &clp);
4663
if (error)
4664
return (error);
4665
error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
4666
if (!error) {
4667
clidrev = clp->nfsc_clientidrev;
4668
error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
4669
p, id, flags);
4670
} else if (error == -1) {
4671
error = 0;
4672
}
4673
nfscl_clientrelease(clp);
4674
} else if (op == F_UNLCK && fl->l_type == F_UNLCK) {
4675
/*
4676
* We must loop around for all lockowner cases.
4677
*/
4678
callcnt = 0;
4679
error = nfscl_getcl(vp->v_mount, cred, p, false, true, &clp);
4680
if (error)
4681
return (error);
4682
do {
4683
error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
4684
clp, id, flags, &lp, &dorpc);
4685
/*
4686
* If it returns a NULL lp, we're done.
4687
*/
4688
if (lp == NULL) {
4689
if (callcnt == 0)
4690
nfscl_clientrelease(clp);
4691
else
4692
nfscl_releasealllocks(clp, vp, p, id, flags);
4693
return (error);
4694
}
4695
if (nmp->nm_clp != NULL)
4696
clidrev = nmp->nm_clp->nfsc_clientidrev;
4697
else
4698
clidrev = 0;
4699
/*
4700
* If the server doesn't support Posix lock semantics,
4701
* only allow locks on the entire file, since it won't
4702
* handle overlapping byte ranges.
4703
* There might still be a problem when a lock
4704
* upgrade/downgrade (read<->write) occurs, since the
4705
* server "might" expect an unlock first?
4706
*/
4707
if (dorpc && (lp->nfsl_open->nfso_posixlock ||
4708
(off == 0 && len == NFS64BITSSET))) {
4709
/*
4710
* Since the lock records will go away, we must
4711
* wait for grace and delay here.
4712
*/
4713
do {
4714
error = nfsrpc_locku(nd, nmp, lp, off, len,
4715
NFSV4LOCKT_READ, cred, p, 0);
4716
if ((nd->nd_repstat == NFSERR_GRACE ||
4717
nd->nd_repstat == NFSERR_DELAY) &&
4718
error == 0)
4719
(void) nfs_catnap(PZERO, (int)nd->nd_repstat,
4720
"nfs_advlock");
4721
} while ((nd->nd_repstat == NFSERR_GRACE ||
4722
nd->nd_repstat == NFSERR_DELAY) && error == 0);
4723
}
4724
callcnt++;
4725
} while (error == 0 && nd->nd_repstat == 0);
4726
nfscl_releasealllocks(clp, vp, p, id, flags);
4727
} else if (op == F_SETLK) {
4728
error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
4729
NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
4730
if (error || donelocally) {
4731
return (error);
4732
}
4733
if (nmp->nm_clp != NULL)
4734
clidrev = nmp->nm_clp->nfsc_clientidrev;
4735
else
4736
clidrev = 0;
4737
nfhp = VTONFS(vp)->n_fhp;
4738
if (!lp->nfsl_open->nfso_posixlock &&
4739
(off != 0 || len != NFS64BITSSET)) {
4740
error = EINVAL;
4741
} else {
4742
error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh,
4743
nfhp->nfh_len, lp, newone, reclaim, off,
4744
len, fl->l_type, cred, p, 0);
4745
}
4746
if (!error)
4747
error = nd->nd_repstat;
4748
nfscl_lockrelease(lp, error, newone);
4749
} else {
4750
error = EINVAL;
4751
}
4752
if (!error)
4753
error = nd->nd_repstat;
4754
if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
4755
error == NFSERR_STALEDONTRECOVER ||
4756
error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
4757
error == NFSERR_BADSESSION) {
4758
(void) nfs_catnap(PZERO, error, "nfs_advlock");
4759
} else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
4760
&& clidrev != 0) {
4761
expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
4762
retrycnt++;
4763
}
4764
} while (error == NFSERR_GRACE ||
4765
error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
4766
error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID ||
4767
error == NFSERR_BADSESSION ||
4768
((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
4769
expireret == 0 && clidrev != 0 && retrycnt < 4));
4770
if (error && retrycnt >= 4)
4771
error = EIO;
4772
return (error);
4773
}
4774
4775
/*
4776
* The lower level routine for the LockT case.
4777
*/
4778
int
4779
nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
4780
struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
4781
struct ucred *cred, NFSPROC_T *p, void *id, int flags)
4782
{
4783
u_int32_t *tl;
4784
int error, type, size;
4785
uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4786
struct nfsnode *np;
4787
struct nfsmount *nmp;
4788
struct nfsclsession *tsep;
4789
4790
nmp = VFSTONFS(vp->v_mount);
4791
NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp, cred);
4792
NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
4793
if (fl->l_type == F_RDLCK)
4794
*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
4795
else
4796
*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
4797
txdr_hyper(off, tl);
4798
tl += 2;
4799
txdr_hyper(len, tl);
4800
tl += 2;
4801
tsep = nfsmnt_mdssession(nmp);
4802
*tl++ = tsep->nfsess_clientid.lval[0];
4803
*tl = tsep->nfsess_clientid.lval[1];
4804
nfscl_filllockowner(id, own, flags);
4805
np = VTONFS(vp);
4806
NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN],
4807
np->n_fhp->nfh_len);
4808
(void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len);
4809
error = nfscl_request(nd, vp, p, cred);
4810
if (error)
4811
return (error);
4812
if (nd->nd_repstat == 0) {
4813
fl->l_type = F_UNLCK;
4814
} else if (nd->nd_repstat == NFSERR_DENIED) {
4815
nd->nd_repstat = 0;
4816
fl->l_whence = SEEK_SET;
4817
NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
4818
fl->l_start = fxdr_hyper(tl);
4819
tl += 2;
4820
len = fxdr_hyper(tl);
4821
tl += 2;
4822
if (len == NFS64BITSSET)
4823
fl->l_len = 0;
4824
else
4825
fl->l_len = len;
4826
type = fxdr_unsigned(int, *tl++);
4827
if (type == NFSV4LOCKT_WRITE)
4828
fl->l_type = F_WRLCK;
4829
else
4830
fl->l_type = F_RDLCK;
4831
/*
4832
* XXX For now, I have no idea what to do with the
4833
* conflicting lock_owner, so I'll just set the pid == 0
4834
* and skip over the lock_owner.
4835
*/
4836
fl->l_pid = (pid_t)0;
4837
tl += 2;
4838
size = fxdr_unsigned(int, *tl);
4839
if (size < 0 || size > NFSV4_OPAQUELIMIT)
4840
error = EBADRPC;
4841
if (!error)
4842
error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
4843
} else if (nd->nd_repstat == NFSERR_STALECLIENTID)
4844
nfscl_initiate_recovery(clp);
4845
nfsmout:
4846
m_freem(nd->nd_mrep);
4847
return (error);
4848
}
4849
4850
/*
4851
* Lower level function that performs the LockU RPC.
4852
*/
4853
static int
4854
nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp,
4855
struct nfscllockowner *lp, u_int64_t off, u_int64_t len,
4856
u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred)
4857
{
4858
u_int32_t *tl;
4859
int error;
4860
4861
nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh,
4862
lp->nfsl_open->nfso_fhlen, NULL, NULL, 0, 0, cred);
4863
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
4864
*tl++ = txdr_unsigned(type);
4865
*tl = txdr_unsigned(lp->nfsl_seqid);
4866
if (nfstest_outofseq &&
4867
(arc4random() % nfstest_outofseq) == 0)
4868
*tl = txdr_unsigned(lp->nfsl_seqid + 1);
4869
tl++;
4870
if (NFSHASNFSV4N(nmp))
4871
*tl++ = 0;
4872
else
4873
*tl++ = lp->nfsl_stateid.seqid;
4874
*tl++ = lp->nfsl_stateid.other[0];
4875
*tl++ = lp->nfsl_stateid.other[1];
4876
*tl++ = lp->nfsl_stateid.other[2];
4877
txdr_hyper(off, tl);
4878
tl += 2;
4879
txdr_hyper(len, tl);
4880
if (syscred)
4881
nd->nd_flag |= ND_USEGSSNAME;
4882
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
4883
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4884
NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
4885
if (error)
4886
return (error);
4887
if (nd->nd_repstat == 0) {
4888
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
4889
lp->nfsl_stateid.seqid = *tl++;
4890
lp->nfsl_stateid.other[0] = *tl++;
4891
lp->nfsl_stateid.other[1] = *tl++;
4892
lp->nfsl_stateid.other[2] = *tl;
4893
} else if (nd->nd_repstat == NFSERR_STALESTATEID)
4894
nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
4895
nfsmout:
4896
m_freem(nd->nd_mrep);
4897
return (error);
4898
}
4899
4900
/*
4901
* The actual Lock RPC.
4902
*/
4903
int
4904
nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp,
4905
u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone,
4906
int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred,
4907
NFSPROC_T *p, int syscred)
4908
{
4909
u_int32_t *tl;
4910
int error, size;
4911
uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
4912
struct nfsclsession *tsep;
4913
4914
nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL, 0, 0,
4915
cred);
4916
NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
4917
if (type == F_RDLCK)
4918
*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
4919
else
4920
*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
4921
*tl++ = txdr_unsigned(reclaim);
4922
txdr_hyper(off, tl);
4923
tl += 2;
4924
txdr_hyper(len, tl);
4925
tl += 2;
4926
if (newone) {
4927
*tl = newnfs_true;
4928
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
4929
2 * NFSX_UNSIGNED + NFSX_HYPER);
4930
*tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid);
4931
if (NFSHASNFSV4N(nmp))
4932
*tl++ = 0;
4933
else
4934
*tl++ = lp->nfsl_open->nfso_stateid.seqid;
4935
*tl++ = lp->nfsl_open->nfso_stateid.other[0];
4936
*tl++ = lp->nfsl_open->nfso_stateid.other[1];
4937
*tl++ = lp->nfsl_open->nfso_stateid.other[2];
4938
*tl++ = txdr_unsigned(lp->nfsl_seqid);
4939
tsep = nfsmnt_mdssession(nmp);
4940
*tl++ = tsep->nfsess_clientid.lval[0];
4941
*tl = tsep->nfsess_clientid.lval[1];
4942
NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
4943
NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen);
4944
(void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
4945
} else {
4946
*tl = newnfs_false;
4947
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
4948
if (NFSHASNFSV4N(nmp))
4949
*tl++ = 0;
4950
else
4951
*tl++ = lp->nfsl_stateid.seqid;
4952
*tl++ = lp->nfsl_stateid.other[0];
4953
*tl++ = lp->nfsl_stateid.other[1];
4954
*tl++ = lp->nfsl_stateid.other[2];
4955
*tl = txdr_unsigned(lp->nfsl_seqid);
4956
if (nfstest_outofseq &&
4957
(arc4random() % nfstest_outofseq) == 0)
4958
*tl = txdr_unsigned(lp->nfsl_seqid + 1);
4959
}
4960
if (syscred)
4961
nd->nd_flag |= ND_USEGSSNAME;
4962
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
4963
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
4964
if (error)
4965
return (error);
4966
if (newone)
4967
NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd);
4968
NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
4969
if (nd->nd_repstat == 0) {
4970
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
4971
lp->nfsl_stateid.seqid = *tl++;
4972
lp->nfsl_stateid.other[0] = *tl++;
4973
lp->nfsl_stateid.other[1] = *tl++;
4974
lp->nfsl_stateid.other[2] = *tl;
4975
} else if (nd->nd_repstat == NFSERR_DENIED) {
4976
NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
4977
size = fxdr_unsigned(int, *(tl + 7));
4978
if (size < 0 || size > NFSV4_OPAQUELIMIT)
4979
error = EBADRPC;
4980
if (!error)
4981
error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
4982
} else if (nd->nd_repstat == NFSERR_STALESTATEID)
4983
nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
4984
nfsmout:
4985
m_freem(nd->nd_mrep);
4986
return (error);
4987
}
4988
4989
/*
4990
* nfs statfs rpc
4991
* (always called with the vp for the mount point)
4992
*/
4993
int
4994
nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
4995
uint32_t *leasep, uint32_t *cloneblksizep, struct ucred *cred, NFSPROC_T *p,
4996
struct nfsvattr *nap, int *attrflagp)
4997
{
4998
struct nfsvattr na;
4999
struct nfsv3_pathconf pc;
5000
u_int32_t *tl = NULL;
5001
struct nfsrv_descript nfsd, *nd = &nfsd;
5002
struct nfsmount *nmp;
5003
nfsattrbit_t attrbits;
5004
int attrflag, error;
5005
5006
*attrflagp = 0;
5007
if (cloneblksizep != NULL)
5008
*cloneblksizep = 0;
5009
nmp = VFSTONFS(vp->v_mount);
5010
if (NFSHASNFSV4(nmp)) {
5011
/*
5012
* For V4, you actually do a getattr.
5013
*/
5014
NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred);
5015
if (leasep != NULL)
5016
NFSROOTFS_GETATTRBIT(&attrbits);
5017
else
5018
NFSSTATFS_GETATTRBIT(&attrbits);
5019
(void) nfsrv_putattrbit(nd, &attrbits);
5020
nd->nd_flag |= ND_USEGSSNAME;
5021
error = nfscl_request(nd, vp, p, cred);
5022
if (error)
5023
return (error);
5024
if (nd->nd_repstat == 0) {
5025
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
5026
NULL, NULL, sbp, fsp, NULL, 0, NULL, leasep, NULL,
5027
NULL, cloneblksizep, NULL, p, cred);
5028
if (!error) {
5029
nmp->nm_fsid[0] = nap->na_filesid[0];
5030
nmp->nm_fsid[1] = nap->na_filesid[1];
5031
NFSSETHASSETFSID(nmp);
5032
*attrflagp = 1;
5033
}
5034
} else {
5035
error = nd->nd_repstat;
5036
}
5037
if (error)
5038
goto nfsmout;
5039
} else {
5040
NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp, NULL);
5041
error = nfscl_request(nd, vp, p, cred);
5042
if (error)
5043
return (error);
5044
if (nd->nd_flag & ND_NFSV3) {
5045
error = nfscl_postop_attr(nd, nap, attrflagp);
5046
if (error)
5047
goto nfsmout;
5048
}
5049
if (nd->nd_repstat) {
5050
error = nd->nd_repstat;
5051
goto nfsmout;
5052
}
5053
NFSM_DISSECT(tl, u_int32_t *,
5054
NFSX_STATFS(nd->nd_flag & ND_NFSV3));
5055
}
5056
if (NFSHASNFSV3(nmp)) {
5057
sbp->sf_tbytes = fxdr_hyper(tl); tl += 2;
5058
sbp->sf_fbytes = fxdr_hyper(tl); tl += 2;
5059
sbp->sf_abytes = fxdr_hyper(tl); tl += 2;
5060
sbp->sf_tfiles = fxdr_hyper(tl); tl += 2;
5061
sbp->sf_ffiles = fxdr_hyper(tl); tl += 2;
5062
sbp->sf_afiles = fxdr_hyper(tl); tl += 2;
5063
sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl);
5064
} else if (NFSHASNFSV4(nmp) == 0) {
5065
sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++);
5066
sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++);
5067
sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++);
5068
sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++);
5069
sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl);
5070
}
5071
5072
/* Try and find out if the server fs is case-insensitive. */
5073
error = nfsrpc_pathconf(vp, &pc, NULL, NULL, cred, p, &na, &attrflag,
5074
NULL);
5075
if (error == 0 && pc.pc_caseinsensitive != 0) {
5076
NFSLOCKMNT(nmp);
5077
nmp->nm_state |= NFSSTA_CASEINSENSITIVE;
5078
NFSUNLOCKMNT(nmp);
5079
}
5080
error = 0;
5081
nfsmout:
5082
m_freem(nd->nd_mrep);
5083
return (error);
5084
}
5085
5086
/*
5087
* nfs pathconf rpc
5088
*/
5089
int
5090
nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, bool *has_namedattrp,
5091
uint32_t *clone_blksizep, struct ucred *cred, NFSPROC_T *p,
5092
struct nfsvattr *nap, int *attrflagp, uint32_t *trueformp)
5093
{
5094
struct nfsrv_descript nfsd, *nd = &nfsd;
5095
struct nfsmount *nmp;
5096
u_int32_t *tl;
5097
nfsattrbit_t attrbits;
5098
int error;
5099
struct nfsnode *np;
5100
5101
if (has_namedattrp != NULL)
5102
*has_namedattrp = false;
5103
*attrflagp = 0;
5104
if (clone_blksizep != NULL)
5105
*clone_blksizep = 0;
5106
nmp = VFSTONFS(vp->v_mount);
5107
if (NFSHASNFSV4(nmp)) {
5108
np = VTONFS(vp);
5109
if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
5110
nmp->nm_fhsize == 0) {
5111
/* Attempt to get the actual root file handle. */
5112
error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
5113
cred, p);
5114
if (error != 0)
5115
return (EACCES);
5116
if (np->n_fhp->nfh_len == NFSX_FHMAX + 1)
5117
nfscl_statfs(vp, cred, p);
5118
}
5119
/*
5120
* For V4, you actually do a getattr.
5121
*/
5122
NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred);
5123
NFSPATHCONF_GETATTRBIT(&attrbits);
5124
if (nmp->nm_minorvers >= NFSV42_MINORVERSION)
5125
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACLTRUEFORM);
5126
(void) nfsrv_putattrbit(nd, &attrbits);
5127
nd->nd_flag |= ND_USEGSSNAME;
5128
error = nfscl_request(nd, vp, p, cred);
5129
if (error)
5130
return (error);
5131
if (nd->nd_repstat == 0) {
5132
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
5133
pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL,
5134
has_namedattrp, clone_blksizep, trueformp, p, cred);
5135
if (!error)
5136
*attrflagp = 1;
5137
} else {
5138
error = nd->nd_repstat;
5139
}
5140
} else {
5141
NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp, NULL);
5142
error = nfscl_request(nd, vp, p, cred);
5143
if (error)
5144
return (error);
5145
error = nfscl_postop_attr(nd, nap, attrflagp);
5146
if (nd->nd_repstat && !error)
5147
error = nd->nd_repstat;
5148
if (!error) {
5149
NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF);
5150
pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++);
5151
pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++);
5152
pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++);
5153
pc->pc_chownrestricted =
5154
fxdr_unsigned(u_int32_t, *tl++);
5155
pc->pc_caseinsensitive =
5156
fxdr_unsigned(u_int32_t, *tl++);
5157
pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl);
5158
}
5159
}
5160
nfsmout:
5161
m_freem(nd->nd_mrep);
5162
return (error);
5163
}
5164
5165
/*
5166
* nfs version 3 fsinfo rpc call
5167
*/
5168
int
5169
nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred,
5170
NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
5171
{
5172
u_int32_t *tl;
5173
struct nfsrv_descript nfsd, *nd = &nfsd;
5174
int error;
5175
5176
*attrflagp = 0;
5177
NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp, NULL);
5178
error = nfscl_request(nd, vp, p, cred);
5179
if (error)
5180
return (error);
5181
error = nfscl_postop_attr(nd, nap, attrflagp);
5182
if (nd->nd_repstat && !error)
5183
error = nd->nd_repstat;
5184
if (!error) {
5185
NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO);
5186
fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++);
5187
fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++);
5188
fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++);
5189
fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++);
5190
fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++);
5191
fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++);
5192
fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++);
5193
fsp->fs_maxfilesize = fxdr_hyper(tl);
5194
tl += 2;
5195
fxdr_nfsv3time(tl, &fsp->fs_timedelta);
5196
tl += 2;
5197
fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl);
5198
}
5199
nfsmout:
5200
m_freem(nd->nd_mrep);
5201
return (error);
5202
}
5203
5204
/*
5205
* This function performs the Renew RPC.
5206
*/
5207
int
5208
nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred,
5209
NFSPROC_T *p)
5210
{
5211
u_int32_t *tl;
5212
struct nfsrv_descript nfsd;
5213
struct nfsrv_descript *nd = &nfsd;
5214
struct nfsmount *nmp;
5215
int error;
5216
struct nfssockreq *nrp;
5217
struct nfsclsession *tsep;
5218
5219
nmp = clp->nfsc_nmp;
5220
if (nmp == NULL)
5221
return (0);
5222
if (dsp == NULL)
5223
nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, NULL, 0,
5224
0, cred);
5225
else
5226
nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL,
5227
&dsp->nfsclds_sess, 0, 0, NULL);
5228
if (!NFSHASNFSV4N(nmp)) {
5229
/* NFSv4.1 just uses a Sequence Op and not a Renew. */
5230
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
5231
tsep = nfsmnt_mdssession(nmp);
5232
*tl++ = tsep->nfsess_clientid.lval[0];
5233
*tl = tsep->nfsess_clientid.lval[1];
5234
}
5235
nrp = NULL;
5236
if (dsp != NULL)
5237
nrp = dsp->nfsclds_sockp;
5238
if (nrp == NULL)
5239
/* If NULL, use the MDS socket. */
5240
nrp = &nmp->nm_sockreq;
5241
nd->nd_flag |= ND_USEGSSNAME;
5242
if (dsp == NULL)
5243
error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
5244
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5245
else {
5246
error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
5247
NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
5248
if (error == ENXIO)
5249
nfscl_cancelreqs(dsp);
5250
}
5251
if (error)
5252
return (error);
5253
error = nd->nd_repstat;
5254
m_freem(nd->nd_mrep);
5255
return (error);
5256
}
5257
5258
/*
5259
* This function performs the Releaselockowner RPC.
5260
*/
5261
int
5262
nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp,
5263
uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p)
5264
{
5265
struct nfsrv_descript nfsd, *nd = &nfsd;
5266
u_int32_t *tl;
5267
int error;
5268
uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
5269
struct nfsclsession *tsep;
5270
5271
if (NFSHASNFSV4N(nmp)) {
5272
/* For NFSv4.1, do a FreeStateID. */
5273
nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL,
5274
NULL, 0, 0, cred);
5275
nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID);
5276
} else {
5277
nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL,
5278
NULL, 0, 0, NULL);
5279
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
5280
tsep = nfsmnt_mdssession(nmp);
5281
*tl++ = tsep->nfsess_clientid.lval[0];
5282
*tl = tsep->nfsess_clientid.lval[1];
5283
NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
5284
NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen);
5285
(void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
5286
}
5287
nd->nd_flag |= ND_USEGSSNAME;
5288
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5289
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5290
if (error)
5291
return (error);
5292
error = nd->nd_repstat;
5293
m_freem(nd->nd_mrep);
5294
return (error);
5295
}
5296
5297
/*
5298
* This function performs the Compound to get the mount pt FH.
5299
*/
5300
int
5301
nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
5302
NFSPROC_T *p)
5303
{
5304
u_int32_t *tl;
5305
struct nfsrv_descript nfsd;
5306
struct nfsrv_descript *nd = &nfsd;
5307
u_char *cp, *cp2, *fhp;
5308
int error, cnt, i, len, setnil;
5309
u_int32_t *opcntp;
5310
5311
nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL, 0,
5312
0, NULL);
5313
cp = dirpath;
5314
cnt = 0;
5315
do {
5316
setnil = 0;
5317
while (*cp == '/')
5318
cp++;
5319
cp2 = cp;
5320
while (*cp2 != '\0' && *cp2 != '/')
5321
cp2++;
5322
if (*cp2 == '/') {
5323
setnil = 1;
5324
*cp2 = '\0';
5325
}
5326
if (cp2 != cp) {
5327
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
5328
*tl = txdr_unsigned(NFSV4OP_LOOKUP);
5329
nfsm_strtom(nd, cp, strlen(cp));
5330
cnt++;
5331
}
5332
if (setnil)
5333
*cp2++ = '/';
5334
cp = cp2;
5335
} while (*cp != '\0');
5336
if (NFSHASNFSV4N(nmp))
5337
/* Has a Sequence Op done by nfscl_reqstart(). */
5338
*opcntp = txdr_unsigned(3 + cnt);
5339
else
5340
*opcntp = txdr_unsigned(2 + cnt);
5341
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
5342
*tl = txdr_unsigned(NFSV4OP_GETFH);
5343
nd->nd_flag |= ND_USEGSSNAME;
5344
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5345
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5346
if (error)
5347
return (error);
5348
if (nd->nd_repstat == 0) {
5349
NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
5350
tl += 2;
5351
for (i = 0; i < cnt; i++) {
5352
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5353
tl++;
5354
}
5355
if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
5356
len > NFSX_FHMAX) {
5357
nd->nd_repstat = NFSERR_BADXDR;
5358
} else {
5359
fhp = malloc(len + 1, M_TEMP, M_WAITOK);
5360
nd->nd_repstat = nfsrv_mtostr(nd, fhp, len);
5361
if (nd->nd_repstat == 0) {
5362
NFSLOCKMNT(nmp);
5363
if (nmp->nm_fhsize == 0) {
5364
NFSBCOPY(fhp, nmp->nm_fh, len);
5365
nmp->nm_fhsize = len;
5366
}
5367
NFSUNLOCKMNT(nmp);
5368
}
5369
free(fhp, M_TEMP);
5370
}
5371
}
5372
error = nd->nd_repstat;
5373
nfsmout:
5374
m_freem(nd->nd_mrep);
5375
return (error);
5376
}
5377
5378
/*
5379
* This function performs the Delegreturn RPC.
5380
*/
5381
int
5382
nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred,
5383
struct nfsmount *nmp, NFSPROC_T *p, int syscred)
5384
{
5385
u_int32_t *tl;
5386
struct nfsrv_descript nfsd;
5387
struct nfsrv_descript *nd = &nfsd;
5388
int error;
5389
5390
nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh,
5391
dp->nfsdl_fhlen, NULL, NULL, 0, 0, cred);
5392
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
5393
if (NFSHASNFSV4N(nmp))
5394
*tl++ = 0;
5395
else
5396
*tl++ = dp->nfsdl_stateid.seqid;
5397
*tl++ = dp->nfsdl_stateid.other[0];
5398
*tl++ = dp->nfsdl_stateid.other[1];
5399
*tl = dp->nfsdl_stateid.other[2];
5400
if (syscred)
5401
nd->nd_flag |= ND_USEGSSNAME;
5402
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5403
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5404
if (error)
5405
return (error);
5406
error = nd->nd_repstat;
5407
m_freem(nd->nd_mrep);
5408
return (error);
5409
}
5410
5411
/*
5412
* nfs getacl call.
5413
*/
5414
int
5415
nfsrpc_getacl(struct vnode *vp, acl_type_t acltype, struct ucred *cred,
5416
NFSPROC_T *p, struct acl *aclp)
5417
{
5418
struct nfsrv_descript nfsd, *nd = &nfsd;
5419
int error;
5420
nfsattrbit_t attrbits;
5421
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
5422
struct nfsnode *np;
5423
5424
if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
5425
return (EOPNOTSUPP);
5426
np = VTONFS(vp);
5427
if (!NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, NFSATTRBIT_ACL) &&
5428
acltype == ACL_TYPE_NFS4)
5429
return (EOPNOTSUPP);
5430
if ((!NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
5431
NFSATTRBIT_POSIXACCESSACL) ||
5432
!NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
5433
NFSATTRBIT_POSIXDEFAULTACL)) &&
5434
(acltype == ACL_TYPE_ACCESS || acltype == ACL_TYPE_DEFAULT))
5435
return (EOPNOTSUPP);
5436
NFSCL_REQSTART(nd, NFSPROC_GETACL, vp, cred);
5437
NFSZERO_ATTRBIT(&attrbits);
5438
if (acltype == ACL_TYPE_NFS4)
5439
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
5440
else if (acltype == ACL_TYPE_ACCESS)
5441
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_POSIXACCESSACL);
5442
else
5443
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_POSIXDEFAULTACL);
5444
(void) nfsrv_putattrbit(nd, &attrbits);
5445
error = nfscl_request(nd, vp, p, cred);
5446
if (error)
5447
return (error);
5448
if (!nd->nd_repstat)
5449
error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL,
5450
NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, NULL, NULL,
5451
NULL, p, cred);
5452
else
5453
error = nd->nd_repstat;
5454
m_freem(nd->nd_mrep);
5455
return (error);
5456
}
5457
5458
/*
5459
* nfs setacl call.
5460
*/
5461
int
5462
nfsrpc_setacl(struct vnode *vp, acl_type_t acltype, struct ucred *cred,
5463
NFSPROC_T *p, struct acl *aclp)
5464
{
5465
int error;
5466
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
5467
struct nfsnode *np;
5468
5469
if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
5470
return (EOPNOTSUPP);
5471
np = VTONFS(vp);
5472
if (!NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, NFSATTRBIT_ACL) &&
5473
acltype == ACL_TYPE_NFS4)
5474
return (EOPNOTSUPP);
5475
if ((!NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
5476
NFSATTRBIT_POSIXACCESSACL) ||
5477
!NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
5478
NFSATTRBIT_POSIXDEFAULTACL)) &&
5479
(acltype == ACL_TYPE_ACCESS || acltype == ACL_TYPE_DEFAULT))
5480
return (EOPNOTSUPP);
5481
error = nfsrpc_setattr(vp, NULL, aclp, acltype, cred, p, NULL, NULL);
5482
return (error);
5483
}
5484
5485
/*
5486
* nfs setacl call.
5487
*/
5488
static int
5489
nfsrpc_setaclrpc(struct vnode *vp, struct ucred *cred, NFSPROC_T *p,
5490
struct acl *aclp, acl_type_t aclt, nfsv4stateid_t *stateidp)
5491
{
5492
struct nfsrv_descript nfsd, *nd = &nfsd;
5493
int error;
5494
nfsattrbit_t attrbits;
5495
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
5496
5497
if (!NFSHASNFSV4(nmp))
5498
return (EOPNOTSUPP);
5499
NFSCL_REQSTART(nd, NFSPROC_SETACL, vp, cred);
5500
nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
5501
NFSZERO_ATTRBIT(&attrbits);
5502
if (aclt == ACL_TYPE_NFS4)
5503
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
5504
else if (aclt == ACL_TYPE_ACCESS)
5505
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_POSIXACCESSACL);
5506
else
5507
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_POSIXDEFAULTACL);
5508
(void)nfsv4_fillattr(nd, vp->v_mount, vp, aclp, NULL, NULL, 0,
5509
&attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL, false,
5510
false, false, 0, NULL, false);
5511
error = nfscl_request(nd, vp, p, cred);
5512
if (error)
5513
return (error);
5514
/* Don't care about the pre/postop attributes */
5515
m_freem(nd->nd_mrep);
5516
return (nd->nd_repstat);
5517
}
5518
5519
/*
5520
* Do the NFSv4.1 Exchange ID.
5521
*/
5522
int
5523
nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp,
5524
struct nfssockreq *nrp, int minorvers, uint32_t exchflags,
5525
struct nfsclds **dspp, struct ucred *cred, NFSPROC_T *p)
5526
{
5527
uint32_t *tl, v41flags;
5528
struct nfsrv_descript nfsd;
5529
struct nfsrv_descript *nd = &nfsd;
5530
struct nfsclds *dsp;
5531
struct timespec verstime;
5532
int error, len;
5533
5534
*dspp = NULL;
5535
if (minorvers == 0)
5536
minorvers = nmp->nm_minorvers;
5537
nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL,
5538
NFS_VER4, minorvers, NULL);
5539
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5540
*tl++ = txdr_unsigned(nfsboottime.tv_sec); /* Client owner */
5541
*tl = txdr_unsigned(clp->nfsc_rev);
5542
(void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
5543
5544
NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
5545
*tl++ = txdr_unsigned(exchflags);
5546
*tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);
5547
5548
/* Set the implementation id4 */
5549
*tl = txdr_unsigned(1);
5550
(void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
5551
(void) nfsm_strtom(nd, version, strlen(version));
5552
NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
5553
verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
5554
verstime.tv_nsec = 0;
5555
txdr_nfsv4time(&verstime, tl);
5556
nd->nd_flag |= ND_USEGSSNAME;
5557
error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
5558
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5559
NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error,
5560
(int)nd->nd_repstat);
5561
if (error != 0)
5562
return (error);
5563
if (nd->nd_repstat == 0) {
5564
NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER);
5565
len = fxdr_unsigned(int, *(tl + 7));
5566
if (len < 0 || len > NFSV4_OPAQUELIMIT) {
5567
error = NFSERR_BADXDR;
5568
goto nfsmout;
5569
}
5570
dsp = malloc(sizeof(struct nfsclds) + len + 1, M_NFSCLDS,
5571
M_WAITOK | M_ZERO);
5572
dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew;
5573
dsp->nfsclds_servownlen = len;
5574
dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++;
5575
dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++;
5576
dsp->nfsclds_sess.nfsess_sequenceid =
5577
fxdr_unsigned(uint32_t, *tl++);
5578
v41flags = fxdr_unsigned(uint32_t, *tl);
5579
if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 &&
5580
NFSHASPNFSOPT(nmp)) {
5581
NFSCL_DEBUG(1, "set PNFS\n");
5582
NFSLOCKMNT(nmp);
5583
nmp->nm_state |= NFSSTA_PNFS;
5584
NFSUNLOCKMNT(nmp);
5585
dsp->nfsclds_flags |= NFSCLDS_MDS;
5586
}
5587
if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0)
5588
dsp->nfsclds_flags |= NFSCLDS_DS;
5589
if (minorvers == NFSV42_MINORVERSION)
5590
dsp->nfsclds_flags |= NFSCLDS_MINORV2;
5591
if (len > 0)
5592
nd->nd_repstat = nfsrv_mtostr(nd,
5593
dsp->nfsclds_serverown, len);
5594
if (nd->nd_repstat == 0) {
5595
mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
5596
mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
5597
NULL, MTX_DEF);
5598
nfscl_initsessionslots(&dsp->nfsclds_sess);
5599
*dspp = dsp;
5600
} else
5601
free(dsp, M_NFSCLDS);
5602
}
5603
error = nd->nd_repstat;
5604
nfsmout:
5605
m_freem(nd->nd_mrep);
5606
return (error);
5607
}
5608
5609
/*
5610
* Do the NFSv4.1 Create Session.
5611
*/
5612
int
5613
nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep,
5614
struct nfssockreq *nrp, struct nfsclds *dsp, uint32_t sequenceid, int mds,
5615
struct ucred *cred, NFSPROC_T *p)
5616
{
5617
uint32_t crflags, maxval, *tl;
5618
struct nfsrv_descript nfsd;
5619
struct nfsrv_descript *nd = &nfsd;
5620
int error, irdcnt, minorvers;
5621
5622
/* Make sure nm_rsize, nm_wsize is set. */
5623
if (nmp->nm_rsize > NFS_MAXBSIZE || nmp->nm_rsize == 0)
5624
nmp->nm_rsize = NFS_MAXBSIZE;
5625
if (nmp->nm_wsize > NFS_MAXBSIZE || nmp->nm_wsize == 0)
5626
nmp->nm_wsize = NFS_MAXBSIZE;
5627
if (dsp == NULL)
5628
minorvers = nmp->nm_minorvers;
5629
else if ((dsp->nfsclds_flags & NFSCLDS_MINORV2) != 0)
5630
minorvers = NFSV42_MINORVERSION;
5631
else
5632
minorvers = NFSV41_MINORVERSION;
5633
nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL,
5634
NFS_VER4, minorvers, NULL);
5635
NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
5636
*tl++ = sep->nfsess_clientid.lval[0];
5637
*tl++ = sep->nfsess_clientid.lval[1];
5638
*tl++ = txdr_unsigned(sequenceid);
5639
crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST);
5640
if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0 && mds != 0)
5641
crflags |= NFSV4CRSESS_CONNBACKCHAN;
5642
*tl = txdr_unsigned(crflags);
5643
5644
/* Fill in fore channel attributes. */
5645
NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
5646
*tl++ = 0; /* Header pad size */
5647
if ((nd->nd_flag & ND_NFSV42) != 0 && mds != 0 && sb_max_adj >=
5648
nmp->nm_wsize && sb_max_adj >= nmp->nm_rsize) {
5649
/*
5650
* NFSv4.2 Extended Attribute operations may want to do
5651
* requests/replies that are larger than nm_rsize/nm_wsize.
5652
*/
5653
*tl++ = txdr_unsigned(sb_max_adj - NFS_MAXXDR);
5654
*tl++ = txdr_unsigned(sb_max_adj - NFS_MAXXDR);
5655
} else {
5656
*tl++ = txdr_unsigned(nmp->nm_wsize + NFS_MAXXDR);
5657
*tl++ = txdr_unsigned(nmp->nm_rsize + NFS_MAXXDR);
5658
}
5659
*tl++ = txdr_unsigned(4096); /* Max response size cached */
5660
*tl++ = txdr_unsigned(20); /* Max operations */
5661
*tl++ = txdr_unsigned(NFSV4_SLOTS); /* Max slots */
5662
*tl = 0; /* No rdma ird */
5663
5664
/* Fill in back channel attributes. */
5665
NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
5666
*tl++ = 0; /* Header pad size */
5667
*tl++ = txdr_unsigned(10000); /* Max request size */
5668
*tl++ = txdr_unsigned(10000); /* Max response size */
5669
*tl++ = txdr_unsigned(4096); /* Max response size cached */
5670
*tl++ = txdr_unsigned(4); /* Max operations */
5671
*tl++ = txdr_unsigned(NFSV4_CBSLOTS); /* Max slots */
5672
*tl = 0; /* No rdma ird */
5673
5674
NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED);
5675
*tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */
5676
5677
/* Allow AUTH_SYS callbacks as uid, gid == 0. */
5678
*tl++ = txdr_unsigned(1); /* Auth_sys only */
5679
*tl++ = txdr_unsigned(AUTH_SYS); /* AUTH_SYS type */
5680
*tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */
5681
*tl++ = 0; /* Null machine name */
5682
*tl++ = 0; /* Uid == 0 */
5683
*tl++ = 0; /* Gid == 0 */
5684
*tl = 0; /* No additional gids */
5685
nd->nd_flag |= ND_USEGSSNAME;
5686
error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG,
5687
NFS_VER4, NULL, 1, NULL, NULL);
5688
if (error != 0)
5689
return (error);
5690
if (nd->nd_repstat == 0) {
5691
NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
5692
2 * NFSX_UNSIGNED);
5693
bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID);
5694
tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
5695
sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++);
5696
crflags = fxdr_unsigned(uint32_t, *tl);
5697
if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) {
5698
NFSLOCKMNT(nmp);
5699
nmp->nm_state |= NFSSTA_SESSPERSIST;
5700
NFSUNLOCKMNT(nmp);
5701
}
5702
5703
/* Get the fore channel slot count. */
5704
NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
5705
tl++; /* Skip the header pad size. */
5706
5707
/* Make sure nm_wsize is small enough. */
5708
maxval = fxdr_unsigned(uint32_t, *tl++);
5709
while (maxval < nmp->nm_wsize + NFS_MAXXDR) {
5710
if (nmp->nm_wsize > 8096)
5711
nmp->nm_wsize /= 2;
5712
else
5713
break;
5714
}
5715
sep->nfsess_maxreq = maxval;
5716
5717
/* Make sure nm_rsize is small enough. */
5718
maxval = fxdr_unsigned(uint32_t, *tl++);
5719
while (maxval < nmp->nm_rsize + NFS_MAXXDR) {
5720
if (nmp->nm_rsize > 8096)
5721
nmp->nm_rsize /= 2;
5722
else
5723
break;
5724
}
5725
sep->nfsess_maxresp = maxval;
5726
5727
sep->nfsess_maxcache = fxdr_unsigned(int, *tl++);
5728
tl++;
5729
sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++);
5730
if (sep->nfsess_foreslots == 0) {
5731
error = NFSERR_BADXDR;
5732
goto nfsmout;
5733
} else if (sep->nfsess_foreslots > NFSV4_SLOTS)
5734
sep->nfsess_foreslots = NFSV4_SLOTS;
5735
NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots);
5736
irdcnt = fxdr_unsigned(int, *tl);
5737
if (irdcnt < 0 || irdcnt > 1) {
5738
error = NFSERR_BADXDR;
5739
goto nfsmout;
5740
}
5741
if (irdcnt > 0)
5742
NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED);
5743
5744
/* and the back channel slot count. */
5745
NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
5746
tl += 5;
5747
sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl);
5748
if (sep->nfsess_backslots > NFSV4_CBSLOTS)
5749
sep->nfsess_backslots = NFSV4_CBSLOTS;
5750
NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots);
5751
}
5752
error = nd->nd_repstat;
5753
nfsmout:
5754
m_freem(nd->nd_mrep);
5755
return (error);
5756
}
5757
5758
/*
5759
* Do the NFSv4.1 Destroy Client.
5760
*/
5761
int
5762
nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp,
5763
struct ucred *cred, NFSPROC_T *p)
5764
{
5765
uint32_t *tl;
5766
struct nfsrv_descript nfsd;
5767
struct nfsrv_descript *nd = &nfsd;
5768
int error;
5769
struct nfsclsession *tsep;
5770
5771
nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL, 0,
5772
0, NULL);
5773
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5774
tsep = nfsmnt_mdssession(nmp);
5775
*tl++ = tsep->nfsess_clientid.lval[0];
5776
*tl = tsep->nfsess_clientid.lval[1];
5777
nd->nd_flag |= ND_USEGSSNAME;
5778
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5779
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5780
if (error != 0)
5781
return (error);
5782
error = nd->nd_repstat;
5783
m_freem(nd->nd_mrep);
5784
return (error);
5785
}
5786
5787
/*
5788
* Do the NFSv4.1 LayoutGet.
5789
*/
5790
static int
5791
nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode,
5792
uint64_t offset, uint64_t len, uint64_t minlen, int layouttype,
5793
int layoutlen, nfsv4stateid_t *stateidp, int *retonclosep,
5794
struct nfsclflayouthead *flhp, struct ucred *cred, NFSPROC_T *p)
5795
{
5796
struct nfsrv_descript nfsd, *nd = &nfsd;
5797
int error;
5798
5799
nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL, 0,
5800
0, cred);
5801
nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp,
5802
layouttype, layoutlen, 0);
5803
nd->nd_flag |= ND_USEGSSNAME;
5804
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5805
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5806
NFSCL_DEBUG(4, "layget err=%d st=%d\n", error, nd->nd_repstat);
5807
if (error != 0)
5808
return (error);
5809
if (nd->nd_repstat == 0)
5810
error = nfsrv_parselayoutget(nmp, nd, stateidp, retonclosep,
5811
flhp);
5812
if (error == 0 && nd->nd_repstat != 0)
5813
error = nd->nd_repstat;
5814
m_freem(nd->nd_mrep);
5815
return (error);
5816
}
5817
5818
/*
5819
* Do the NFSv4.1 Get Device Info.
5820
*/
5821
int
5822
nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype,
5823
uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred,
5824
NFSPROC_T *p)
5825
{
5826
uint32_t cnt, *tl, vers, minorvers;
5827
struct nfsrv_descript nfsd;
5828
struct nfsrv_descript *nd = &nfsd;
5829
struct sockaddr_in sin, ssin;
5830
struct sockaddr_in6 sin6, ssin6;
5831
struct nfsclds *dsp = NULL, **dspp, **gotdspp;
5832
struct nfscldevinfo *ndi;
5833
int addrcnt = 0, bitcnt, error, gotminor, gotvers, i, isudp, j;
5834
int stripecnt;
5835
uint8_t stripeindex;
5836
sa_family_t af, safilled;
5837
5838
ssin.sin_port = 0; /* To shut up compiler. */
5839
ssin.sin_addr.s_addr = 0; /* ditto */
5840
*ndip = NULL;
5841
ndi = NULL;
5842
gotdspp = NULL;
5843
nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL, 0,
5844
0, cred);
5845
NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED);
5846
NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID);
5847
tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5848
*tl++ = txdr_unsigned(layouttype);
5849
*tl++ = txdr_unsigned(100000);
5850
if (notifybitsp != NULL && *notifybitsp != 0) {
5851
*tl = txdr_unsigned(1); /* One word of bits. */
5852
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5853
*tl = txdr_unsigned(*notifybitsp);
5854
} else
5855
*tl = txdr_unsigned(0);
5856
nd->nd_flag |= ND_USEGSSNAME;
5857
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5858
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5859
if (error != 0)
5860
return (error);
5861
if (nd->nd_repstat == 0) {
5862
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5863
if (layouttype != fxdr_unsigned(int, *tl))
5864
printf("EEK! devinfo layout type not same!\n");
5865
if (layouttype == NFSLAYOUT_NFSV4_1_FILES) {
5866
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5867
stripecnt = fxdr_unsigned(int, *tl);
5868
NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt);
5869
if (stripecnt >= MHLEN / NFSX_UNSIGNED ||
5870
stripecnt < 1) {
5871
printf("pNFS File layout devinfo stripecnt %d:"
5872
" out of range\n", stripecnt);
5873
error = NFSERR_BADXDR;
5874
goto nfsmout;
5875
}
5876
NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) *
5877
NFSX_UNSIGNED);
5878
addrcnt = fxdr_unsigned(int, *(tl + stripecnt));
5879
NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt);
5880
if (addrcnt < 1 || addrcnt > 128) {
5881
printf("NFS devinfo addrcnt %d: out of range\n",
5882
addrcnt);
5883
error = NFSERR_BADXDR;
5884
goto nfsmout;
5885
}
5886
5887
/*
5888
* Now we know how many stripe indices and addresses, so
5889
* we can allocate the structure the correct size.
5890
*/
5891
i = (stripecnt * sizeof(uint8_t)) /
5892
sizeof(struct nfsclds *) + 1;
5893
NFSCL_DEBUG(4, "stripeindices=%d\n", i);
5894
ndi = malloc(sizeof(*ndi) + (addrcnt + i) *
5895
sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK |
5896
M_ZERO);
5897
NFSBCOPY(deviceid, ndi->nfsdi_deviceid,
5898
NFSX_V4DEVICEID);
5899
ndi->nfsdi_refcnt = 0;
5900
ndi->nfsdi_flags = NFSDI_FILELAYOUT;
5901
ndi->nfsdi_stripecnt = stripecnt;
5902
ndi->nfsdi_addrcnt = addrcnt;
5903
/* Fill in the stripe indices. */
5904
for (i = 0; i < stripecnt; i++) {
5905
stripeindex = fxdr_unsigned(uint8_t, *tl++);
5906
NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex);
5907
if (stripeindex >= addrcnt) {
5908
printf("pNFS File Layout devinfo"
5909
" stripeindex %d: too big\n",
5910
(int)stripeindex);
5911
error = NFSERR_BADXDR;
5912
goto nfsmout;
5913
}
5914
nfsfldi_setstripeindex(ndi, i, stripeindex);
5915
}
5916
} else if (layouttype == NFSLAYOUT_FLEXFILE) {
5917
/* For Flex File, we only get one address list. */
5918
ndi = malloc(sizeof(*ndi) + sizeof(struct nfsclds *),
5919
M_NFSDEVINFO, M_WAITOK | M_ZERO);
5920
NFSBCOPY(deviceid, ndi->nfsdi_deviceid,
5921
NFSX_V4DEVICEID);
5922
ndi->nfsdi_refcnt = 0;
5923
ndi->nfsdi_flags = NFSDI_FLEXFILE;
5924
addrcnt = ndi->nfsdi_addrcnt = 1;
5925
}
5926
5927
/* Now, dissect the server address(es). */
5928
safilled = AF_UNSPEC;
5929
for (i = 0; i < addrcnt; i++) {
5930
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5931
cnt = fxdr_unsigned(uint32_t, *tl);
5932
if (cnt == 0) {
5933
printf("NFS devinfo 0 len addrlist\n");
5934
error = NFSERR_BADXDR;
5935
goto nfsmout;
5936
}
5937
dspp = nfsfldi_addr(ndi, i);
5938
safilled = AF_UNSPEC;
5939
for (j = 0; j < cnt; j++) {
5940
error = nfsv4_getipaddr(nd, &sin, &sin6, &af,
5941
&isudp);
5942
if (error != 0 && error != EPERM) {
5943
error = NFSERR_BADXDR;
5944
goto nfsmout;
5945
}
5946
if (error == 0 && isudp == 0) {
5947
/*
5948
* The priority is:
5949
* - Same address family.
5950
* Save the address and dspp, so that
5951
* the connection can be done after
5952
* parsing is complete.
5953
*/
5954
if (safilled == AF_UNSPEC ||
5955
(af == nmp->nm_nam->sa_family &&
5956
safilled != nmp->nm_nam->sa_family)
5957
) {
5958
if (af == AF_INET)
5959
ssin = sin;
5960
else
5961
ssin6 = sin6;
5962
safilled = af;
5963
gotdspp = dspp;
5964
}
5965
}
5966
}
5967
}
5968
5969
gotvers = NFS_VER4; /* Default NFSv4.1 for File Layout. */
5970
gotminor = NFSV41_MINORVERSION;
5971
/* For Flex File, we will take one of the versions to use. */
5972
if (layouttype == NFSLAYOUT_FLEXFILE) {
5973
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5974
j = fxdr_unsigned(int, *tl);
5975
if (j < 1 || j > NFSDEV_MAXVERS) {
5976
printf("pNFS: too many versions\n");
5977
error = NFSERR_BADXDR;
5978
goto nfsmout;
5979
}
5980
gotvers = 0;
5981
gotminor = 0;
5982
for (i = 0; i < j; i++) {
5983
NFSM_DISSECT(tl, uint32_t *, 5 * NFSX_UNSIGNED);
5984
vers = fxdr_unsigned(uint32_t, *tl++);
5985
minorvers = fxdr_unsigned(uint32_t, *tl++);
5986
if (vers == NFS_VER3)
5987
minorvers = 0;
5988
if ((vers == NFS_VER4 && ((minorvers ==
5989
NFSV41_MINORVERSION && gotminor == 0) ||
5990
minorvers == NFSV42_MINORVERSION)) ||
5991
(vers == NFS_VER3 && gotvers == 0)) {
5992
gotvers = vers;
5993
gotminor = minorvers;
5994
/* We'll take this one. */
5995
ndi->nfsdi_versindex = i;
5996
ndi->nfsdi_vers = vers;
5997
ndi->nfsdi_minorvers = minorvers;
5998
ndi->nfsdi_rsize = fxdr_unsigned(
5999
uint32_t, *tl++);
6000
ndi->nfsdi_wsize = fxdr_unsigned(
6001
uint32_t, *tl++);
6002
if (*tl == newnfs_true)
6003
ndi->nfsdi_flags |=
6004
NFSDI_TIGHTCOUPLED;
6005
else
6006
ndi->nfsdi_flags &=
6007
~NFSDI_TIGHTCOUPLED;
6008
}
6009
}
6010
if (gotvers == 0) {
6011
printf("pNFS: no NFSv3, NFSv4.1 or NFSv4.2\n");
6012
error = NFSERR_BADXDR;
6013
goto nfsmout;
6014
}
6015
}
6016
6017
/* And the notify bits. */
6018
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6019
bitcnt = fxdr_unsigned(int, *tl);
6020
if (bitcnt > 0) {
6021
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6022
if (notifybitsp != NULL)
6023
*notifybitsp =
6024
fxdr_unsigned(uint32_t, *tl);
6025
}
6026
if (safilled != AF_UNSPEC) {
6027
KASSERT(ndi != NULL, ("ndi is NULL"));
6028
*ndip = ndi;
6029
} else
6030
error = EPERM;
6031
if (error == 0) {
6032
/*
6033
* Now we can do a TCP connection for the correct
6034
* NFS version and IP address.
6035
*/
6036
error = nfsrpc_fillsa(nmp, &ssin, &ssin6, safilled,
6037
gotvers, gotminor, &dsp, p);
6038
}
6039
if (error == 0) {
6040
KASSERT(gotdspp != NULL, ("gotdspp is NULL"));
6041
*gotdspp = dsp;
6042
}
6043
}
6044
if (nd->nd_repstat != 0 && error == 0)
6045
error = nd->nd_repstat;
6046
nfsmout:
6047
if (error != 0 && ndi != NULL)
6048
nfscl_freedevinfo(ndi);
6049
m_freem(nd->nd_mrep);
6050
return (error);
6051
}
6052
6053
/*
6054
* Do the NFSv4.1 LayoutCommit.
6055
*/
6056
int
6057
nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
6058
uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp,
6059
int layouttype, struct ucred *cred, NFSPROC_T *p)
6060
{
6061
uint32_t *tl;
6062
struct nfsrv_descript nfsd, *nd = &nfsd;
6063
int error;
6064
6065
nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL,
6066
0, 0, cred);
6067
NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
6068
NFSX_STATEID);
6069
txdr_hyper(off, tl);
6070
tl += 2;
6071
txdr_hyper(len, tl);
6072
tl += 2;
6073
if (reclaim != 0)
6074
*tl++ = newnfs_true;
6075
else
6076
*tl++ = newnfs_false;
6077
*tl++ = txdr_unsigned(stateidp->seqid);
6078
*tl++ = stateidp->other[0];
6079
*tl++ = stateidp->other[1];
6080
*tl++ = stateidp->other[2];
6081
*tl++ = newnfs_true;
6082
if (lastbyte < off)
6083
lastbyte = off;
6084
else if (lastbyte >= (off + len))
6085
lastbyte = off + len - 1;
6086
txdr_hyper(lastbyte, tl);
6087
tl += 2;
6088
*tl++ = newnfs_false;
6089
*tl++ = txdr_unsigned(layouttype);
6090
/* All supported layouts are 0 length. */
6091
*tl = txdr_unsigned(0);
6092
nd->nd_flag |= ND_USEGSSNAME;
6093
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
6094
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
6095
if (error != 0)
6096
return (error);
6097
error = nd->nd_repstat;
6098
m_freem(nd->nd_mrep);
6099
return (error);
6100
}
6101
6102
/*
6103
* Do the NFSv4.1 LayoutReturn.
6104
*/
6105
int
6106
nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
6107
int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset,
6108
uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
6109
uint32_t stat, uint32_t op, char *devid)
6110
{
6111
uint32_t *tl;
6112
struct nfsrv_descript nfsd, *nd = &nfsd;
6113
uint64_t tu64;
6114
int error;
6115
6116
nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL,
6117
0, 0, cred);
6118
NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
6119
if (reclaim != 0)
6120
*tl++ = newnfs_true;
6121
else
6122
*tl++ = newnfs_false;
6123
*tl++ = txdr_unsigned(layouttype);
6124
*tl++ = txdr_unsigned(iomode);
6125
*tl = txdr_unsigned(layoutreturn);
6126
if (layoutreturn == NFSLAYOUTRETURN_FILE) {
6127
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
6128
NFSX_UNSIGNED);
6129
txdr_hyper(offset, tl);
6130
tl += 2;
6131
txdr_hyper(len, tl);
6132
tl += 2;
6133
NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid);
6134
*tl++ = txdr_unsigned(stateidp->seqid);
6135
*tl++ = stateidp->other[0];
6136
*tl++ = stateidp->other[1];
6137
*tl++ = stateidp->other[2];
6138
if (layouttype == NFSLAYOUT_NFSV4_1_FILES)
6139
*tl = txdr_unsigned(0);
6140
else if (layouttype == NFSLAYOUT_FLEXFILE) {
6141
if (stat != 0) {
6142
*tl = txdr_unsigned(2 * NFSX_HYPER +
6143
NFSX_STATEID + NFSX_V4DEVICEID + 5 *
6144
NFSX_UNSIGNED);
6145
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER +
6146
NFSX_STATEID + NFSX_V4DEVICEID + 5 *
6147
NFSX_UNSIGNED);
6148
*tl++ = txdr_unsigned(1); /* One error. */
6149
tu64 = 0; /* Offset. */
6150
txdr_hyper(tu64, tl); tl += 2;
6151
tu64 = UINT64_MAX; /* Length. */
6152
txdr_hyper(tu64, tl); tl += 2;
6153
NFSBCOPY(stateidp, tl, NFSX_STATEID);
6154
tl += (NFSX_STATEID / NFSX_UNSIGNED);
6155
*tl++ = txdr_unsigned(1); /* One error. */
6156
NFSBCOPY(devid, tl, NFSX_V4DEVICEID);
6157
tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
6158
*tl++ = txdr_unsigned(stat);
6159
*tl++ = txdr_unsigned(op);
6160
} else {
6161
*tl = txdr_unsigned(2 * NFSX_UNSIGNED);
6162
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
6163
/* No ioerrs. */
6164
*tl++ = 0;
6165
}
6166
*tl = 0; /* No stats yet. */
6167
}
6168
}
6169
nd->nd_flag |= ND_USEGSSNAME;
6170
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
6171
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
6172
if (error != 0)
6173
return (error);
6174
if (nd->nd_repstat == 0) {
6175
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6176
if (*tl != 0) {
6177
NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
6178
stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
6179
stateidp->other[0] = *tl++;
6180
stateidp->other[1] = *tl++;
6181
stateidp->other[2] = *tl;
6182
}
6183
} else
6184
error = nd->nd_repstat;
6185
nfsmout:
6186
m_freem(nd->nd_mrep);
6187
return (error);
6188
}
6189
6190
/*
6191
* Do the NFSv4.2 LayoutError.
6192
*/
6193
static int
6194
nfsrpc_layouterror(struct nfsmount *nmp, uint8_t *fh, int fhlen, uint64_t offset,
6195
uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
6196
uint32_t stat, uint32_t op, char *devid)
6197
{
6198
uint32_t *tl;
6199
struct nfsrv_descript nfsd, *nd = &nfsd;
6200
int error;
6201
6202
nfscl_reqstart(nd, NFSPROC_LAYOUTERROR, nmp, fh, fhlen, NULL, NULL,
6203
0, 0, cred);
6204
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
6205
NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED);
6206
txdr_hyper(offset, tl); tl += 2;
6207
txdr_hyper(len, tl); tl += 2;
6208
*tl++ = txdr_unsigned(stateidp->seqid);
6209
*tl++ = stateidp->other[0];
6210
*tl++ = stateidp->other[1];
6211
*tl++ = stateidp->other[2];
6212
*tl++ = txdr_unsigned(1);
6213
NFSBCOPY(devid, tl, NFSX_V4DEVICEID);
6214
tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
6215
*tl++ = txdr_unsigned(stat);
6216
*tl = txdr_unsigned(op);
6217
nd->nd_flag |= ND_USEGSSNAME;
6218
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
6219
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
6220
if (error != 0)
6221
return (error);
6222
if (nd->nd_repstat != 0)
6223
error = nd->nd_repstat;
6224
m_freem(nd->nd_mrep);
6225
return (error);
6226
}
6227
6228
/*
6229
* Acquire a layout and devinfo, if possible. The caller must have acquired
6230
* a reference count on the nfsclclient structure before calling this.
6231
* Return the layout in lypp with a reference count on it, if successful.
6232
*/
6233
static int
6234
nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp,
6235
int iomode, uint32_t rw, uint32_t *notifybitsp, nfsv4stateid_t *stateidp,
6236
uint64_t off, struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p)
6237
{
6238
struct nfscllayout *lyp;
6239
struct nfsclflayout *flp;
6240
struct nfsclflayouthead flh;
6241
int error = 0, islocked, layoutlen, layouttype, recalled, retonclose;
6242
nfsv4stateid_t stateid;
6243
struct nfsclsession *tsep;
6244
6245
*lypp = NULL;
6246
if (NFSHASFLEXFILE(nmp))
6247
layouttype = NFSLAYOUT_FLEXFILE;
6248
else
6249
layouttype = NFSLAYOUT_NFSV4_1_FILES;
6250
/*
6251
* If lyp is returned non-NULL, there will be a refcnt (shared lock)
6252
* on it, iff flp != NULL or a lock (exclusive lock) on it iff
6253
* flp == NULL.
6254
*/
6255
lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len,
6256
off, rw, &flp, &recalled);
6257
islocked = 0;
6258
if (lyp == NULL || flp == NULL) {
6259
if (recalled != 0)
6260
return (EIO);
6261
LIST_INIT(&flh);
6262
tsep = nfsmnt_mdssession(nmp);
6263
layoutlen = tsep->nfsess_maxcache -
6264
(NFSX_STATEID + 3 * NFSX_UNSIGNED);
6265
if (lyp == NULL) {
6266
stateid.seqid = 0;
6267
stateid.other[0] = stateidp->other[0];
6268
stateid.other[1] = stateidp->other[1];
6269
stateid.other[2] = stateidp->other[2];
6270
error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
6271
nfhp->nfh_len, iomode, (uint64_t)0, UINT64_MAX,
6272
(uint64_t)0, layouttype, layoutlen, &stateid,
6273
&retonclose, &flh, cred, p);
6274
} else {
6275
islocked = 1;
6276
stateid.seqid = lyp->nfsly_stateid.seqid;
6277
stateid.other[0] = lyp->nfsly_stateid.other[0];
6278
stateid.other[1] = lyp->nfsly_stateid.other[1];
6279
stateid.other[2] = lyp->nfsly_stateid.other[2];
6280
error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
6281
nfhp->nfh_len, iomode, off, UINT64_MAX,
6282
(uint64_t)0, layouttype, layoutlen, &stateid,
6283
&retonclose, &flh, cred, p);
6284
}
6285
error = nfsrpc_layoutgetres(nmp, vp, nfhp->nfh_fh,
6286
nfhp->nfh_len, &stateid, retonclose, notifybitsp, &lyp,
6287
&flh, layouttype, error, NULL, cred, p);
6288
if (error == 0)
6289
*lypp = lyp;
6290
else if (islocked != 0)
6291
nfscl_rellayout(lyp, 1);
6292
} else
6293
*lypp = lyp;
6294
return (error);
6295
}
6296
6297
/*
6298
* Do a TCP connection plus exchange id and create session.
6299
* If successful, a "struct nfsclds" is linked into the list for the
6300
* mount point and a pointer to it is returned.
6301
*/
6302
static int
6303
nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_in *sin,
6304
struct sockaddr_in6 *sin6, sa_family_t af, int vers, int minorvers,
6305
struct nfsclds **dspp, NFSPROC_T *p)
6306
{
6307
struct sockaddr_in *msad, *sad;
6308
struct sockaddr_in6 *msad6, *sad6;
6309
struct nfsclclient *clp;
6310
struct nfssockreq *nrp;
6311
struct nfsclds *dsp, *tdsp;
6312
int error, firsttry;
6313
enum nfsclds_state retv;
6314
uint32_t sequenceid = 0;
6315
6316
KASSERT(nmp->nm_sockreq.nr_cred != NULL,
6317
("nfsrpc_fillsa: NULL nr_cred"));
6318
NFSLOCKCLSTATE();
6319
clp = nmp->nm_clp;
6320
NFSUNLOCKCLSTATE();
6321
if (clp == NULL)
6322
return (EPERM);
6323
if (af == AF_INET) {
6324
NFSLOCKMNT(nmp);
6325
/*
6326
* Check to see if we already have a session for this
6327
* address that is usable for a DS.
6328
* Note that the MDS's address is in a different place
6329
* than the sessions already acquired for DS's.
6330
*/
6331
msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam;
6332
tdsp = TAILQ_FIRST(&nmp->nm_sess);
6333
while (tdsp != NULL) {
6334
if (msad != NULL && msad->sin_family == AF_INET &&
6335
sin->sin_addr.s_addr == msad->sin_addr.s_addr &&
6336
sin->sin_port == msad->sin_port &&
6337
(tdsp->nfsclds_flags & NFSCLDS_DS) != 0 &&
6338
tdsp->nfsclds_sess.nfsess_defunct == 0) {
6339
*dspp = tdsp;
6340
NFSUNLOCKMNT(nmp);
6341
NFSCL_DEBUG(4, "fnd same addr\n");
6342
return (0);
6343
}
6344
tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
6345
if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
6346
msad = (struct sockaddr_in *)
6347
tdsp->nfsclds_sockp->nr_nam;
6348
else
6349
msad = NULL;
6350
}
6351
NFSUNLOCKMNT(nmp);
6352
6353
/* No IP address match, so look for new/trunked one. */
6354
sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO);
6355
sad->sin_len = sizeof(*sad);
6356
sad->sin_family = AF_INET;
6357
sad->sin_port = sin->sin_port;
6358
sad->sin_addr.s_addr = sin->sin_addr.s_addr;
6359
if (NFSHASPNFS(nmp) && NFSHASKERB(nmp)) {
6360
/* For pNFS, a separate server principal is needed. */
6361
nrp = malloc(sizeof(*nrp) + NI_MAXSERV + NI_MAXHOST,
6362
M_NFSSOCKREQ, M_WAITOK | M_ZERO);
6363
/*
6364
* Use the latter part of nr_srvprinc as a temporary
6365
* buffer for the IP address.
6366
*/
6367
inet_ntoa_r(sad->sin_addr,
6368
&nrp->nr_srvprinc[NI_MAXSERV]);
6369
NFSCL_DEBUG(1, "nfsrpc_fillsa: DS IP=%s\n",
6370
&nrp->nr_srvprinc[NI_MAXSERV]);
6371
if (!rpc_gss_ip_to_srv_principal_call(
6372
&nrp->nr_srvprinc[NI_MAXSERV], "nfs",
6373
nrp->nr_srvprinc))
6374
nrp->nr_srvprinc[0] = '\0';
6375
NFSCL_DEBUG(1, "nfsrpc_fillsa: srv principal=%s\n",
6376
nrp->nr_srvprinc);
6377
} else
6378
nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ,
6379
M_WAITOK | M_ZERO);
6380
nrp->nr_nam = (struct sockaddr *)sad;
6381
} else if (af == AF_INET6) {
6382
NFSLOCKMNT(nmp);
6383
/*
6384
* Check to see if we already have a session for this
6385
* address that is usable for a DS.
6386
* Note that the MDS's address is in a different place
6387
* than the sessions already acquired for DS's.
6388
*/
6389
msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam;
6390
tdsp = TAILQ_FIRST(&nmp->nm_sess);
6391
while (tdsp != NULL) {
6392
if (msad6 != NULL && msad6->sin6_family == AF_INET6 &&
6393
IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
6394
&msad6->sin6_addr) &&
6395
sin6->sin6_port == msad6->sin6_port &&
6396
(tdsp->nfsclds_flags & NFSCLDS_DS) != 0 &&
6397
tdsp->nfsclds_sess.nfsess_defunct == 0) {
6398
*dspp = tdsp;
6399
NFSUNLOCKMNT(nmp);
6400
return (0);
6401
}
6402
tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
6403
if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
6404
msad6 = (struct sockaddr_in6 *)
6405
tdsp->nfsclds_sockp->nr_nam;
6406
else
6407
msad6 = NULL;
6408
}
6409
NFSUNLOCKMNT(nmp);
6410
6411
/* No IP address match, so look for new/trunked one. */
6412
sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO);
6413
sad6->sin6_len = sizeof(*sad6);
6414
sad6->sin6_family = AF_INET6;
6415
sad6->sin6_port = sin6->sin6_port;
6416
NFSBCOPY(&sin6->sin6_addr, &sad6->sin6_addr,
6417
sizeof(struct in6_addr));
6418
if (NFSHASPNFS(nmp) && NFSHASKERB(nmp)) {
6419
/* For pNFS, a separate server principal is needed. */
6420
nrp = malloc(sizeof(*nrp) + NI_MAXSERV + NI_MAXHOST,
6421
M_NFSSOCKREQ, M_WAITOK | M_ZERO);
6422
/*
6423
* Use the latter part of nr_srvprinc as a temporary
6424
* buffer for the IP address.
6425
*/
6426
inet_ntop(AF_INET6, &sad6->sin6_addr,
6427
&nrp->nr_srvprinc[NI_MAXSERV], NI_MAXHOST);
6428
NFSCL_DEBUG(1, "nfsrpc_fillsa: DS IP=%s\n",
6429
&nrp->nr_srvprinc[NI_MAXSERV]);
6430
if (!rpc_gss_ip_to_srv_principal_call(
6431
&nrp->nr_srvprinc[NI_MAXSERV], "nfs",
6432
nrp->nr_srvprinc))
6433
nrp->nr_srvprinc[0] = '\0';
6434
NFSCL_DEBUG(1, "nfsrpc_fillsa: srv principal=%s\n",
6435
nrp->nr_srvprinc);
6436
} else
6437
nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ,
6438
M_WAITOK | M_ZERO);
6439
nrp->nr_nam = (struct sockaddr *)sad6;
6440
} else
6441
return (EPERM);
6442
6443
nrp->nr_sotype = SOCK_STREAM;
6444
mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF);
6445
nrp->nr_prog = NFS_PROG;
6446
nrp->nr_vers = vers;
6447
6448
/*
6449
* Use the credentials that were used for the mount, which are
6450
* in nmp->nm_sockreq.nr_cred for newnfs_connect() etc.
6451
* Ref. counting the credentials with crhold() is probably not
6452
* necessary, since nm_sockreq.nr_cred won't be crfree()'d until
6453
* unmount, but I did it anyhow.
6454
*/
6455
nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred);
6456
error = newnfs_connect(nmp, nrp, NULL, p, 0, false, &nrp->nr_client);
6457
NFSCL_DEBUG(3, "DS connect=%d\n", error);
6458
6459
dsp = NULL;
6460
/* Now, do the exchangeid and create session. */
6461
if (error == 0) {
6462
if (vers == NFS_VER4) {
6463
firsttry = 0;
6464
do {
6465
error = nfsrpc_exchangeid(nmp, clp, nrp,
6466
minorvers, NFSV4EXCH_USEPNFSDS, &dsp,
6467
nrp->nr_cred, p);
6468
NFSCL_DEBUG(3, "DS exchangeid=%d\n", error);
6469
if (error == NFSERR_MINORVERMISMATCH)
6470
minorvers = NFSV42_MINORVERSION;
6471
} while (error == NFSERR_MINORVERMISMATCH &&
6472
firsttry++ == 0);
6473
if (error != 0)
6474
newnfs_disconnect(NULL, nrp);
6475
} else {
6476
dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS,
6477
M_WAITOK | M_ZERO);
6478
dsp->nfsclds_flags |= NFSCLDS_DS;
6479
dsp->nfsclds_expire = INT32_MAX; /* No renews needed. */
6480
mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
6481
mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
6482
NULL, MTX_DEF);
6483
}
6484
}
6485
if (error == 0) {
6486
dsp->nfsclds_sockp = nrp;
6487
if (vers == NFS_VER4) {
6488
NFSLOCKMNT(nmp);
6489
retv = nfscl_getsameserver(nmp, dsp, &tdsp,
6490
&sequenceid);
6491
NFSCL_DEBUG(3, "getsame ret=%d\n", retv);
6492
if (retv == NFSDSP_USETHISSESSION &&
6493
nfscl_dssameconn != 0) {
6494
NFSLOCKDS(tdsp);
6495
tdsp->nfsclds_flags |= NFSCLDS_SAMECONN;
6496
NFSUNLOCKDS(tdsp);
6497
NFSUNLOCKMNT(nmp);
6498
/*
6499
* If there is already a session for this
6500
* server, use it.
6501
*/
6502
newnfs_disconnect(NULL, nrp);
6503
nfscl_freenfsclds(dsp);
6504
*dspp = tdsp;
6505
return (0);
6506
}
6507
if (retv == NFSDSP_NOTFOUND)
6508
sequenceid =
6509
dsp->nfsclds_sess.nfsess_sequenceid;
6510
NFSUNLOCKMNT(nmp);
6511
error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
6512
nrp, dsp, sequenceid, 0, nrp->nr_cred, p);
6513
NFSCL_DEBUG(3, "DS createsess=%d\n", error);
6514
}
6515
} else {
6516
NFSFREECRED(nrp->nr_cred);
6517
NFSFREEMUTEX(&nrp->nr_mtx);
6518
free(nrp->nr_nam, M_SONAME);
6519
free(nrp, M_NFSSOCKREQ);
6520
}
6521
if (error == 0) {
6522
NFSCL_DEBUG(3, "add DS session\n");
6523
/*
6524
* Put it at the end of the list. That way the list
6525
* is ordered by when the entry was added. This matters
6526
* since the one done first is the one that should be
6527
* used for sequencid'ing any subsequent create sessions.
6528
*/
6529
NFSLOCKMNT(nmp);
6530
TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list);
6531
NFSUNLOCKMNT(nmp);
6532
*dspp = dsp;
6533
} else if (dsp != NULL) {
6534
newnfs_disconnect(NULL, nrp);
6535
nfscl_freenfsclds(dsp);
6536
}
6537
return (error);
6538
}
6539
6540
/*
6541
* Do the NFSv4.1 Reclaim Complete.
6542
*/
6543
int
6544
nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p)
6545
{
6546
uint32_t *tl;
6547
struct nfsrv_descript nfsd;
6548
struct nfsrv_descript *nd = &nfsd;
6549
int error;
6550
6551
nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL, 0,
6552
0, cred);
6553
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6554
*tl = newnfs_false;
6555
nd->nd_flag |= ND_USEGSSNAME;
6556
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
6557
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
6558
if (error != 0)
6559
return (error);
6560
error = nd->nd_repstat;
6561
m_freem(nd->nd_mrep);
6562
return (error);
6563
}
6564
6565
/*
6566
* Initialize the slot tables for a session.
6567
*/
6568
static void
6569
nfscl_initsessionslots(struct nfsclsession *sep)
6570
{
6571
int i;
6572
6573
for (i = 0; i < NFSV4_CBSLOTS; i++) {
6574
if (sep->nfsess_cbslots[i].nfssl_reply != NULL)
6575
m_freem(sep->nfsess_cbslots[i].nfssl_reply);
6576
NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot));
6577
}
6578
for (i = 0; i < 64; i++)
6579
sep->nfsess_slotseq[i] = 0;
6580
sep->nfsess_slots = 0;
6581
sep->nfsess_badslots = 0;
6582
}
6583
6584
/*
6585
* Called to try and do an I/O operation via an NFSv4.1 Data Server (DS).
6586
*/
6587
int
6588
nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
6589
uint32_t rwaccess, int docommit, struct ucred *cred, NFSPROC_T *p)
6590
{
6591
struct nfsnode *np = VTONFS(vp);
6592
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
6593
struct nfscllayout *layp;
6594
struct nfscldevinfo *dip;
6595
struct nfsclflayout *rflp;
6596
struct mbuf *m, *m2;
6597
struct nfsclwritedsdorpc *drpc, *tdrpc;
6598
nfsv4stateid_t stateid;
6599
struct ucred *newcred;
6600
uint64_t lastbyte, len, off, oresid, xfer;
6601
int eof, error, firstmirror, i, iolaymode, mirrorcnt, recalled, timo;
6602
void *lckp;
6603
uint8_t *dev;
6604
void *iovbase = NULL;
6605
size_t iovlen = 0;
6606
off_t offs = 0;
6607
ssize_t resid = 0;
6608
uint32_t op;
6609
6610
if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 ||
6611
(np->n_flag & NNOLAYOUT) != 0)
6612
return (EIO);
6613
/* Now, get a reference cnt on the clientid for this mount. */
6614
if (nfscl_getref(nmp) == 0)
6615
return (EIO);
6616
6617
/* Find an appropriate stateid. */
6618
newcred = NFSNEWCRED(cred);
6619
error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
6620
rwaccess, 1, newcred, p, &stateid, &lckp);
6621
if (error != 0) {
6622
NFSFREECRED(newcred);
6623
nfscl_relref(nmp);
6624
return (error);
6625
}
6626
/* Search for a layout for this file. */
6627
off = uiop->uio_offset;
6628
layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh,
6629
np->n_fhp->nfh_len, off, rwaccess, &rflp, &recalled);
6630
if (layp == NULL || rflp == NULL) {
6631
if (recalled != 0) {
6632
NFSFREECRED(newcred);
6633
if (lckp != NULL)
6634
nfscl_lockderef(lckp);
6635
nfscl_relref(nmp);
6636
return (EIO);
6637
}
6638
if (layp != NULL) {
6639
nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0);
6640
layp = NULL;
6641
}
6642
/* Try and get a Layout, if it is supported. */
6643
if (rwaccess == NFSV4OPEN_ACCESSWRITE ||
6644
(np->n_flag & NWRITEOPENED) != 0)
6645
iolaymode = NFSLAYOUTIOMODE_RW;
6646
else
6647
iolaymode = NFSLAYOUTIOMODE_READ;
6648
error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode,
6649
rwaccess, NULL, &stateid, off, &layp, newcred, p);
6650
if (error != 0) {
6651
NFSLOCKNODE(np);
6652
np->n_flag |= NNOLAYOUT;
6653
NFSUNLOCKNODE(np);
6654
if (lckp != NULL)
6655
nfscl_lockderef(lckp);
6656
NFSFREECRED(newcred);
6657
if (layp != NULL)
6658
nfscl_rellayout(layp, 0);
6659
nfscl_relref(nmp);
6660
return (error);
6661
}
6662
}
6663
6664
/*
6665
* Loop around finding a layout that works for the first part of
6666
* this I/O operation, and then call the function that actually
6667
* does the RPC.
6668
*/
6669
eof = 0;
6670
len = (uint64_t)uiop->uio_resid;
6671
while (len > 0 && error == 0 && eof == 0) {
6672
off = uiop->uio_offset;
6673
error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp);
6674
if (error == 0) {
6675
oresid = xfer = (uint64_t)uiop->uio_resid;
6676
if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off))
6677
xfer = rflp->nfsfl_end - rflp->nfsfl_off;
6678
/*
6679
* For Flex File layout with mirrored DSs, select one
6680
* of them at random for reads. For writes and commits,
6681
* do all mirrors.
6682
*/
6683
m = NULL;
6684
tdrpc = drpc = NULL;
6685
firstmirror = 0;
6686
mirrorcnt = 1;
6687
if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0 &&
6688
(mirrorcnt = rflp->nfsfl_mirrorcnt) > 1) {
6689
if (rwaccess == NFSV4OPEN_ACCESSREAD) {
6690
firstmirror = arc4random() % mirrorcnt;
6691
mirrorcnt = firstmirror + 1;
6692
} else {
6693
if (docommit == 0) {
6694
/*
6695
* Save values, so uiop can be
6696
* rolled back upon a write
6697
* error.
6698
*/
6699
offs = uiop->uio_offset;
6700
resid = uiop->uio_resid;
6701
iovbase =
6702
uiop->uio_iov->iov_base;
6703
iovlen = uiop->uio_iov->iov_len;
6704
m = nfsm_uiombuflist(uiop, len,
6705
0);
6706
if (m == NULL) {
6707
error = EFAULT;
6708
break;
6709
}
6710
}
6711
tdrpc = drpc = malloc(sizeof(*drpc) *
6712
(mirrorcnt - 1), M_TEMP, M_WAITOK |
6713
M_ZERO);
6714
}
6715
}
6716
for (i = firstmirror; i < mirrorcnt && error == 0; i++){
6717
m2 = NULL;
6718
if (m != NULL && i < mirrorcnt - 1)
6719
m2 = m_copym(m, 0, M_COPYALL, M_WAITOK);
6720
else {
6721
m2 = m;
6722
m = NULL;
6723
}
6724
if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0) {
6725
dev = rflp->nfsfl_ffm[i].dev;
6726
dip = nfscl_getdevinfo(nmp->nm_clp, dev,
6727
rflp->nfsfl_ffm[i].devp);
6728
} else {
6729
dev = rflp->nfsfl_dev;
6730
dip = nfscl_getdevinfo(nmp->nm_clp, dev,
6731
rflp->nfsfl_devp);
6732
}
6733
if (dip != NULL) {
6734
if ((rflp->nfsfl_flags & NFSFL_FLEXFILE)
6735
!= 0)
6736
error = nfscl_dofflayoutio(vp,
6737
uiop, iomode, must_commit,
6738
&eof, &stateid, rwaccess,
6739
dip, layp, rflp, off, xfer,
6740
i, docommit, m2, tdrpc,
6741
newcred, p);
6742
else
6743
error = nfscl_doflayoutio(vp,
6744
uiop, iomode, must_commit,
6745
&eof, &stateid, rwaccess,
6746
dip, layp, rflp, off, xfer,
6747
docommit, newcred, p);
6748
nfscl_reldevinfo(dip);
6749
} else {
6750
if (m2 != NULL)
6751
m_freem(m2);
6752
error = EIO;
6753
}
6754
tdrpc++;
6755
}
6756
if (m != NULL)
6757
m_freem(m);
6758
tdrpc = drpc;
6759
timo = hz / 50; /* Wait for 20msec. */
6760
if (timo < 1)
6761
timo = 1;
6762
for (i = firstmirror; i < mirrorcnt - 1 &&
6763
tdrpc != NULL; i++, tdrpc++) {
6764
/*
6765
* For the unused drpc entries, both inprog and
6766
* err == 0, so this loop won't break.
6767
*/
6768
while (tdrpc->inprog != 0 && tdrpc->done == 0)
6769
tsleep(&tdrpc->tsk, PVFS, "clrpcio",
6770
timo);
6771
if (error == 0 && tdrpc->err != 0)
6772
error = tdrpc->err;
6773
if (rwaccess != NFSV4OPEN_ACCESSREAD &&
6774
docommit == 0 && *must_commit == 0 &&
6775
tdrpc->must_commit == 1)
6776
*must_commit = 1;
6777
}
6778
free(drpc, M_TEMP);
6779
if (error == 0) {
6780
if (mirrorcnt > 1 && rwaccess ==
6781
NFSV4OPEN_ACCESSWRITE && docommit == 0) {
6782
NFSLOCKCLSTATE();
6783
layp->nfsly_flags |= NFSLY_WRITTEN;
6784
NFSUNLOCKCLSTATE();
6785
}
6786
lastbyte = off + xfer - 1;
6787
NFSLOCKCLSTATE();
6788
if (lastbyte > layp->nfsly_lastbyte)
6789
layp->nfsly_lastbyte = lastbyte;
6790
NFSUNLOCKCLSTATE();
6791
} else if (error == NFSERR_OPENMODE &&
6792
rwaccess == NFSV4OPEN_ACCESSREAD) {
6793
NFSLOCKMNT(nmp);
6794
nmp->nm_state |= NFSSTA_OPENMODE;
6795
NFSUNLOCKMNT(nmp);
6796
} else if ((error == NFSERR_NOSPC ||
6797
error == NFSERR_IO || error == NFSERR_NXIO) &&
6798
nmp->nm_minorvers == NFSV42_MINORVERSION) {
6799
if (docommit != 0)
6800
op = NFSV4OP_COMMIT;
6801
else if (rwaccess == NFSV4OPEN_ACCESSREAD)
6802
op = NFSV4OP_READ;
6803
else
6804
op = NFSV4OP_WRITE;
6805
nfsrpc_layouterror(nmp, np->n_fhp->nfh_fh,
6806
np->n_fhp->nfh_len, off, xfer,
6807
&layp->nfsly_stateid, newcred, p, error, op,
6808
dip->nfsdi_deviceid);
6809
error = EIO;
6810
} else
6811
error = EIO;
6812
if (error == 0)
6813
len -= (oresid - (uint64_t)uiop->uio_resid);
6814
else if (mirrorcnt > 1 && rwaccess ==
6815
NFSV4OPEN_ACCESSWRITE && docommit == 0) {
6816
/*
6817
* In case the rpc gets retried, roll the
6818
* uio fields changed by nfsm_uiombuflist()
6819
* back.
6820
*/
6821
uiop->uio_offset = offs;
6822
uiop->uio_resid = resid;
6823
uiop->uio_iov->iov_base = iovbase;
6824
uiop->uio_iov->iov_len = iovlen;
6825
}
6826
}
6827
}
6828
if (lckp != NULL)
6829
nfscl_lockderef(lckp);
6830
NFSFREECRED(newcred);
6831
nfscl_rellayout(layp, 0);
6832
nfscl_relref(nmp);
6833
return (error);
6834
}
6835
6836
/*
6837
* Find a file layout that will handle the first bytes of the requested
6838
* range and return the information from it needed to the I/O operation.
6839
*/
6840
int
6841
nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess,
6842
struct nfsclflayout **retflpp)
6843
{
6844
struct nfsclflayout *flp, *nflp, *rflp;
6845
uint32_t rw;
6846
6847
rflp = NULL;
6848
rw = rwaccess;
6849
/* For reading, do the Read list first and then the Write list. */
6850
do {
6851
if (rw == NFSV4OPEN_ACCESSREAD)
6852
flp = LIST_FIRST(&lyp->nfsly_flayread);
6853
else
6854
flp = LIST_FIRST(&lyp->nfsly_flayrw);
6855
while (flp != NULL) {
6856
nflp = LIST_NEXT(flp, nfsfl_list);
6857
if (flp->nfsfl_off > off)
6858
break;
6859
if (flp->nfsfl_end > off &&
6860
(rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end))
6861
rflp = flp;
6862
flp = nflp;
6863
}
6864
if (rw == NFSV4OPEN_ACCESSREAD)
6865
rw = NFSV4OPEN_ACCESSWRITE;
6866
else
6867
rw = 0;
6868
} while (rw != 0);
6869
if (rflp != NULL) {
6870
/* This one covers the most bytes starting at off. */
6871
*retflpp = rflp;
6872
return (0);
6873
}
6874
return (EIO);
6875
}
6876
6877
/*
6878
* Do I/O using an NFSv4.1 or NFSv4.2 file layout.
6879
*/
6880
static int
6881
nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
6882
int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp,
6883
struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off,
6884
uint64_t len, int docommit, struct ucred *cred, NFSPROC_T *p)
6885
{
6886
uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer;
6887
int commit_thru_mds, error, stripe_index, stripe_pos, minorvers;
6888
struct nfsnode *np;
6889
struct nfsfh *fhp;
6890
struct nfsclds **dspp;
6891
6892
np = VTONFS(vp);
6893
rel_off = off - flp->nfsfl_patoff;
6894
stripe_unit_size = flp->nfsfl_util & NFSFLAYUTIL_STRIPE_MASK;
6895
stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) %
6896
dp->nfsdi_stripecnt;
6897
transfer = stripe_unit_size - (rel_off % stripe_unit_size);
6898
error = 0;
6899
6900
/* Loop around, doing I/O for each stripe unit. */
6901
while (len > 0 && error == 0) {
6902
stripe_index = nfsfldi_stripeindex(dp, stripe_pos);
6903
dspp = nfsfldi_addr(dp, stripe_index);
6904
if (((*dspp)->nfsclds_flags & NFSCLDS_MINORV2) != 0)
6905
minorvers = NFSV42_MINORVERSION;
6906
else
6907
minorvers = NFSV41_MINORVERSION;
6908
if (len > transfer && docommit == 0)
6909
xfer = transfer;
6910
else
6911
xfer = len;
6912
if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) {
6913
/* Dense layout. */
6914
if (stripe_pos >= flp->nfsfl_fhcnt)
6915
return (EIO);
6916
fhp = flp->nfsfl_fh[stripe_pos];
6917
io_off = (rel_off / (stripe_unit_size *
6918
dp->nfsdi_stripecnt)) * stripe_unit_size +
6919
rel_off % stripe_unit_size;
6920
} else {
6921
/* Sparse layout. */
6922
if (flp->nfsfl_fhcnt > 1) {
6923
if (stripe_index >= flp->nfsfl_fhcnt)
6924
return (EIO);
6925
fhp = flp->nfsfl_fh[stripe_index];
6926
} else if (flp->nfsfl_fhcnt == 1)
6927
fhp = flp->nfsfl_fh[0];
6928
else
6929
fhp = np->n_fhp;
6930
io_off = off;
6931
}
6932
if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0) {
6933
commit_thru_mds = 1;
6934
if (docommit != 0)
6935
error = EIO;
6936
} else {
6937
commit_thru_mds = 0;
6938
NFSLOCKNODE(np);
6939
np->n_flag |= NDSCOMMIT;
6940
NFSUNLOCKNODE(np);
6941
}
6942
if (docommit != 0) {
6943
if (error == 0)
6944
error = nfsrpc_commitds(vp, io_off, xfer,
6945
*dspp, fhp, NFS_VER4, minorvers, cred, p);
6946
if (error == 0) {
6947
/*
6948
* Set both eof and uio_resid = 0 to end any
6949
* loops.
6950
*/
6951
*eofp = 1;
6952
uiop->uio_resid = 0;
6953
} else {
6954
NFSLOCKNODE(np);
6955
np->n_flag &= ~NDSCOMMIT;
6956
NFSUNLOCKNODE(np);
6957
}
6958
} else if (rwflag == NFSV4OPEN_ACCESSREAD)
6959
error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
6960
io_off, xfer, fhp, 0, NFS_VER4, minorvers, cred, p);
6961
else {
6962
error = nfsrpc_writeds(vp, uiop, iomode, must_commit,
6963
stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds,
6964
0, NFS_VER4, minorvers, cred, p);
6965
if (error == 0) {
6966
NFSLOCKCLSTATE();
6967
lyp->nfsly_flags |= NFSLY_WRITTEN;
6968
NFSUNLOCKCLSTATE();
6969
}
6970
}
6971
if (error == 0) {
6972
transfer = stripe_unit_size;
6973
stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt;
6974
len -= xfer;
6975
off += xfer;
6976
}
6977
}
6978
return (error);
6979
}
6980
6981
/*
6982
* Do I/O using an NFSv4.1 flex file layout.
6983
*/
6984
static int
6985
nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
6986
int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp,
6987
struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off,
6988
uint64_t len, int mirror, int docommit, struct mbuf *mp,
6989
struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p)
6990
{
6991
uint64_t xfer;
6992
int error;
6993
struct nfsnode *np;
6994
struct nfsfh *fhp;
6995
struct nfsclds **dspp;
6996
struct ucred *tcred;
6997
struct mbuf *m, *m2;
6998
uint32_t copylen;
6999
7000
np = VTONFS(vp);
7001
error = 0;
7002
NFSCL_DEBUG(4, "nfscl_dofflayoutio: off=%ju len=%ju\n", (uintmax_t)off,
7003
(uintmax_t)len);
7004
/* Loop around, doing I/O for each stripe unit. */
7005
while (len > 0 && error == 0) {
7006
dspp = nfsfldi_addr(dp, 0);
7007
fhp = flp->nfsfl_ffm[mirror].fh[dp->nfsdi_versindex];
7008
stateidp = &flp->nfsfl_ffm[mirror].st;
7009
NFSCL_DEBUG(4, "mirror=%d vind=%d fhlen=%d st.seqid=0x%x\n",
7010
mirror, dp->nfsdi_versindex, fhp->nfh_len, stateidp->seqid);
7011
if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) {
7012
tcred = NFSNEWCRED(cred);
7013
tcred->cr_uid = flp->nfsfl_ffm[mirror].user;
7014
tcred->cr_gid = flp->nfsfl_ffm[mirror].group;
7015
tcred->cr_ngroups = 0;
7016
} else
7017
tcred = cred;
7018
if (rwflag == NFSV4OPEN_ACCESSREAD)
7019
copylen = dp->nfsdi_rsize;
7020
else {
7021
copylen = dp->nfsdi_wsize;
7022
if (len > copylen && mp != NULL) {
7023
/*
7024
* When a mirrored configuration needs to do
7025
* multiple writes to each mirror, all writes
7026
* except the last one must be a multiple of
7027
* 4 bytes. This is required so that the XDR
7028
* does not need padding.
7029
* If possible, clip the size to an exact
7030
* multiple of the mbuf length, so that the
7031
* split will be on an mbuf boundary.
7032
*/
7033
copylen &= 0xfffffffc;
7034
if (copylen > mp->m_len)
7035
copylen = copylen / mp->m_len *
7036
mp->m_len;
7037
}
7038
}
7039
NFSLOCKNODE(np);
7040
np->n_flag |= NDSCOMMIT;
7041
NFSUNLOCKNODE(np);
7042
if (len > copylen && docommit == 0)
7043
xfer = copylen;
7044
else
7045
xfer = len;
7046
if (docommit != 0) {
7047
if (error == 0) {
7048
/*
7049
* Do last mirrored DS commit with this thread.
7050
*/
7051
if (mirror < flp->nfsfl_mirrorcnt - 1)
7052
error = nfsio_commitds(vp, off, xfer,
7053
*dspp, fhp, dp->nfsdi_vers,
7054
dp->nfsdi_minorvers, drpc, tcred,
7055
p);
7056
else
7057
error = nfsrpc_commitds(vp, off, xfer,
7058
*dspp, fhp, dp->nfsdi_vers,
7059
dp->nfsdi_minorvers, tcred, p);
7060
NFSCL_DEBUG(4, "commitds=%d\n", error);
7061
if (error != 0 && error != EACCES && error !=
7062
ESTALE) {
7063
NFSCL_DEBUG(4,
7064
"DS layreterr for commit\n");
7065
nfscl_dserr(NFSV4OP_COMMIT, error, dp,
7066
lyp, *dspp);
7067
}
7068
}
7069
NFSCL_DEBUG(4, "aft nfsio_commitds=%d\n", error);
7070
if (error == 0) {
7071
/*
7072
* Set both eof and uio_resid = 0 to end any
7073
* loops.
7074
*/
7075
*eofp = 1;
7076
uiop->uio_resid = 0;
7077
} else {
7078
NFSLOCKNODE(np);
7079
np->n_flag &= ~NDSCOMMIT;
7080
NFSUNLOCKNODE(np);
7081
}
7082
} else if (rwflag == NFSV4OPEN_ACCESSREAD) {
7083
error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
7084
off, xfer, fhp, 1, dp->nfsdi_vers,
7085
dp->nfsdi_minorvers, tcred, p);
7086
NFSCL_DEBUG(4, "readds=%d\n", error);
7087
if (error != 0 && error != EACCES && error != ESTALE) {
7088
NFSCL_DEBUG(4, "DS layreterr for read\n");
7089
nfscl_dserr(NFSV4OP_READ, error, dp, lyp,
7090
*dspp);
7091
}
7092
} else {
7093
if (flp->nfsfl_mirrorcnt == 1) {
7094
error = nfsrpc_writeds(vp, uiop, iomode,
7095
must_commit, stateidp, *dspp, off, xfer,
7096
fhp, 0, 1, dp->nfsdi_vers,
7097
dp->nfsdi_minorvers, tcred, p);
7098
if (error == 0) {
7099
NFSLOCKCLSTATE();
7100
lyp->nfsly_flags |= NFSLY_WRITTEN;
7101
NFSUNLOCKCLSTATE();
7102
}
7103
} else {
7104
m = mp;
7105
if (xfer < len) {
7106
/* The mbuf list must be split. */
7107
m2 = nfsm_split(mp, xfer);
7108
if (m2 != NULL)
7109
mp = m2;
7110
else {
7111
m_freem(mp);
7112
error = EIO;
7113
}
7114
}
7115
NFSCL_DEBUG(4, "mcopy len=%jd xfer=%jd\n",
7116
(uintmax_t)len, (uintmax_t)xfer);
7117
/*
7118
* Do last write to a mirrored DS with this
7119
* thread.
7120
*/
7121
if (error == 0) {
7122
if (mirror < flp->nfsfl_mirrorcnt - 1)
7123
error = nfsio_writedsmir(vp,
7124
iomode, must_commit,
7125
stateidp, *dspp, off,
7126
xfer, fhp, m,
7127
dp->nfsdi_vers,
7128
dp->nfsdi_minorvers, drpc,
7129
tcred, p);
7130
else
7131
error = nfsrpc_writedsmir(vp,
7132
iomode, must_commit,
7133
stateidp, *dspp, off,
7134
xfer, fhp, m,
7135
dp->nfsdi_vers,
7136
dp->nfsdi_minorvers, tcred,
7137
p);
7138
}
7139
NFSCL_DEBUG(4, "nfsio_writedsmir=%d\n", error);
7140
if (error != 0 && error != EACCES && error !=
7141
ESTALE) {
7142
NFSCL_DEBUG(4,
7143
"DS layreterr for write\n");
7144
nfscl_dserr(NFSV4OP_WRITE, error, dp,
7145
lyp, *dspp);
7146
}
7147
}
7148
}
7149
NFSCL_DEBUG(4, "aft read/writeds=%d\n", error);
7150
if (error == 0) {
7151
len -= xfer;
7152
off += xfer;
7153
}
7154
if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0)
7155
NFSFREECRED(tcred);
7156
}
7157
NFSCL_DEBUG(4, "eo nfscl_dofflayoutio=%d\n", error);
7158
return (error);
7159
}
7160
7161
/*
7162
* The actual read RPC done to a DS.
7163
*/
7164
static int
7165
nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp,
7166
struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp, int flex,
7167
int vers, int minorvers, struct ucred *cred, NFSPROC_T *p)
7168
{
7169
uint32_t *tl;
7170
int attrflag, error, retlen;
7171
struct nfsrv_descript nfsd;
7172
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
7173
struct nfsrv_descript *nd = &nfsd;
7174
struct nfssockreq *nrp;
7175
struct nfsvattr na;
7176
7177
nd->nd_mrep = NULL;
7178
if (vers == 0 || vers == NFS_VER4) {
7179
nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh,
7180
fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers,
7181
NULL);
7182
vers = NFS_VER4;
7183
NFSCL_DEBUG(4, "nfsrpc_readds: vers4 minvers=%d\n", minorvers);
7184
if (flex != 0)
7185
nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
7186
else
7187
nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
7188
} else {
7189
nfscl_reqstart(nd, NFSPROC_READ, nmp, fhp->nfh_fh,
7190
fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers,
7191
NULL);
7192
NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_READ]);
7193
NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_READDS]);
7194
NFSCL_DEBUG(4, "nfsrpc_readds: vers3\n");
7195
}
7196
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3);
7197
txdr_hyper(io_off, tl);
7198
*(tl + 2) = txdr_unsigned(len);
7199
nrp = dsp->nfsclds_sockp;
7200
NFSCL_DEBUG(4, "nfsrpc_readds: nrp=%p\n", nrp);
7201
if (nrp == NULL)
7202
/* If NULL, use the MDS socket. */
7203
nrp = &nmp->nm_sockreq;
7204
error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
7205
NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
7206
NFSCL_DEBUG(4, "nfsrpc_readds: stat=%d err=%d\n", nd->nd_repstat,
7207
error);
7208
if (error != 0)
7209
return (error);
7210
if (vers == NFS_VER3) {
7211
error = nfscl_postop_attr(nd, &na, &attrflag);
7212
NFSCL_DEBUG(4, "nfsrpc_readds: postop=%d\n", error);
7213
if (error != 0)
7214
goto nfsmout;
7215
}
7216
if (nd->nd_repstat != 0) {
7217
error = nd->nd_repstat;
7218
goto nfsmout;
7219
}
7220
if (vers == NFS_VER3) {
7221
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
7222
*eofp = fxdr_unsigned(int, *(tl + 1));
7223
} else {
7224
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
7225
*eofp = fxdr_unsigned(int, *tl);
7226
}
7227
NFSM_STRSIZ(retlen, len);
7228
NFSCL_DEBUG(4, "nfsrpc_readds: retlen=%d eof=%d\n", retlen, *eofp);
7229
error = nfsm_mbufuio(nd, uiop, retlen);
7230
nfsmout:
7231
if (nd->nd_mrep != NULL)
7232
m_freem(nd->nd_mrep);
7233
return (error);
7234
}
7235
7236
/*
7237
* The actual write RPC done to a DS.
7238
*/
7239
static int
7240
nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
7241
nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len,
7242
struct nfsfh *fhp, int commit_thru_mds, int flex, int vers, int minorvers,
7243
struct ucred *cred, NFSPROC_T *p)
7244
{
7245
uint32_t *tl;
7246
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
7247
int attrflag, error, rlen, commit, committed = NFSWRITE_FILESYNC;
7248
int32_t backup;
7249
struct nfsrv_descript nfsd;
7250
struct nfsrv_descript *nd = &nfsd;
7251
struct nfssockreq *nrp;
7252
struct nfsvattr na;
7253
7254
KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
7255
nd->nd_mrep = NULL;
7256
if (vers == 0 || vers == NFS_VER4) {
7257
nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh,
7258
fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers,
7259
NULL);
7260
NFSCL_DEBUG(4, "nfsrpc_writeds: vers4 minvers=%d\n", minorvers);
7261
vers = NFS_VER4;
7262
if (flex != 0)
7263
nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
7264
else
7265
nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
7266
NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
7267
} else {
7268
nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh,
7269
fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers,
7270
NULL);
7271
NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITE]);
7272
NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITEDS]);
7273
NFSCL_DEBUG(4, "nfsrpc_writeds: vers3\n");
7274
NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
7275
}
7276
txdr_hyper(io_off, tl);
7277
tl += 2;
7278
if (vers == NFS_VER3)
7279
*tl++ = txdr_unsigned(len);
7280
*tl++ = txdr_unsigned(*iomode);
7281
*tl = txdr_unsigned(len);
7282
error = nfsm_uiombuf(nd, uiop, len);
7283
if (error != 0) {
7284
m_freem(nd->nd_mreq);
7285
return (error);
7286
}
7287
nrp = dsp->nfsclds_sockp;
7288
if (nrp == NULL)
7289
/* If NULL, use the MDS socket. */
7290
nrp = &nmp->nm_sockreq;
7291
error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
7292
NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
7293
NFSCL_DEBUG(4, "nfsrpc_writeds: err=%d stat=%d\n", error,
7294
nd->nd_repstat);
7295
if (error != 0)
7296
return (error);
7297
if (nd->nd_repstat != 0) {
7298
/*
7299
* In case the rpc gets retried, roll
7300
* the uio fields changed by nfsm_uiombuf()
7301
* back.
7302
*/
7303
uiop->uio_offset -= len;
7304
uiop->uio_resid += len;
7305
uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base - len;
7306
uiop->uio_iov->iov_len += len;
7307
error = nd->nd_repstat;
7308
} else {
7309
if (vers == NFS_VER3) {
7310
error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL,
7311
NULL);
7312
NFSCL_DEBUG(4, "nfsrpc_writeds: wcc_data=%d\n", error);
7313
if (error != 0)
7314
goto nfsmout;
7315
}
7316
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
7317
rlen = fxdr_unsigned(int, *tl++);
7318
NFSCL_DEBUG(4, "nfsrpc_writeds: len=%d rlen=%d\n", len, rlen);
7319
if (rlen <= 0 || rlen > len) {
7320
error = NFSERR_IO;
7321
goto nfsmout;
7322
} else if (rlen < len) {
7323
backup = len - rlen;
7324
uiop->uio_iov->iov_base =
7325
(char *)uiop->uio_iov->iov_base - backup;
7326
uiop->uio_iov->iov_len += backup;
7327
uiop->uio_offset -= backup;
7328
uiop->uio_resid += backup;
7329
len = rlen;
7330
}
7331
commit = fxdr_unsigned(int, *tl++);
7332
7333
/*
7334
* Return the lowest commitment level
7335
* obtained by any of the RPCs.
7336
*/
7337
if (committed == NFSWRITE_FILESYNC)
7338
committed = commit;
7339
else if (committed == NFSWRITE_DATASYNC &&
7340
commit == NFSWRITE_UNSTABLE)
7341
committed = commit;
7342
if (commit_thru_mds != 0) {
7343
NFSLOCKMNT(nmp);
7344
if (!NFSHASWRITEVERF(nmp)) {
7345
NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
7346
NFSSETWRITEVERF(nmp);
7347
} else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF) &&
7348
*must_commit != 2) {
7349
*must_commit = 1;
7350
NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
7351
}
7352
NFSUNLOCKMNT(nmp);
7353
} else {
7354
NFSLOCKDS(dsp);
7355
if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) {
7356
NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
7357
dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF;
7358
} else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF) &&
7359
*must_commit != 2) {
7360
*must_commit = 1;
7361
NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
7362
}
7363
NFSUNLOCKDS(dsp);
7364
}
7365
}
7366
nfsmout:
7367
if (nd->nd_mrep != NULL)
7368
m_freem(nd->nd_mrep);
7369
*iomode = committed;
7370
if (nd->nd_repstat != 0 && error == 0)
7371
error = nd->nd_repstat;
7372
return (error);
7373
}
7374
7375
/*
7376
* The actual write RPC done to a DS.
7377
* This variant is called from a separate kernel process for mirrors.
7378
* Any short write is considered an IO error.
7379
*/
7380
static int
7381
nfsrpc_writedsmir(vnode_t vp, int *iomode, int *must_commit,
7382
nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len,
7383
struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers,
7384
struct ucred *cred, NFSPROC_T *p)
7385
{
7386
uint32_t *tl;
7387
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
7388
int attrflag, error, commit, committed = NFSWRITE_FILESYNC, rlen;
7389
struct nfsrv_descript nfsd;
7390
struct nfsrv_descript *nd = &nfsd;
7391
struct nfssockreq *nrp;
7392
struct nfsvattr na;
7393
7394
nd->nd_mrep = NULL;
7395
if (vers == 0 || vers == NFS_VER4) {
7396
nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh,
7397
fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers,
7398
NULL);
7399
vers = NFS_VER4;
7400
NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers4 minvers=%d\n",
7401
minorvers);
7402
nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
7403
NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
7404
} else {
7405
nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh,
7406
fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers,
7407
NULL);
7408
NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITE]);
7409
NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITEDS]);
7410
NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers3\n");
7411
NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
7412
}
7413
txdr_hyper(io_off, tl);
7414
tl += 2;
7415
if (vers == NFS_VER3)
7416
*tl++ = txdr_unsigned(len);
7417
*tl++ = txdr_unsigned(*iomode);
7418
*tl = txdr_unsigned(len);
7419
if (len > 0) {
7420
/* Put data in mbuf chain. */
7421
nd->nd_mb->m_next = m;
7422
}
7423
nrp = dsp->nfsclds_sockp;
7424
if (nrp == NULL)
7425
/* If NULL, use the MDS socket. */
7426
nrp = &nmp->nm_sockreq;
7427
error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
7428
NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
7429
NFSCL_DEBUG(4, "nfsrpc_writedsmir: err=%d stat=%d\n", error,
7430
nd->nd_repstat);
7431
if (error != 0)
7432
return (error);
7433
if (nd->nd_repstat != 0)
7434
error = nd->nd_repstat;
7435
else {
7436
if (vers == NFS_VER3) {
7437
error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL,
7438
NULL);
7439
NFSCL_DEBUG(4, "nfsrpc_writedsmir: wcc_data=%d\n",
7440
error);
7441
if (error != 0)
7442
goto nfsmout;
7443
}
7444
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
7445
rlen = fxdr_unsigned(int, *tl++);
7446
NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", len,
7447
rlen);
7448
if (rlen != len) {
7449
error = NFSERR_IO;
7450
NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n",
7451
len, rlen);
7452
goto nfsmout;
7453
}
7454
commit = fxdr_unsigned(int, *tl++);
7455
7456
/*
7457
* Return the lowest commitment level
7458
* obtained by any of the RPCs.
7459
*/
7460
if (committed == NFSWRITE_FILESYNC)
7461
committed = commit;
7462
else if (committed == NFSWRITE_DATASYNC &&
7463
commit == NFSWRITE_UNSTABLE)
7464
committed = commit;
7465
NFSLOCKDS(dsp);
7466
if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) {
7467
NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
7468
dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF;
7469
} else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF) &&
7470
*must_commit != 2) {
7471
*must_commit = 1;
7472
NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
7473
}
7474
NFSUNLOCKDS(dsp);
7475
}
7476
nfsmout:
7477
if (nd->nd_mrep != NULL)
7478
m_freem(nd->nd_mrep);
7479
*iomode = committed;
7480
if (nd->nd_repstat != 0 && error == 0)
7481
error = nd->nd_repstat;
7482
return (error);
7483
}
7484
7485
/*
7486
* Start up the thread that will execute nfsrpc_writedsmir().
7487
*/
7488
static void
7489
start_writedsmir(void *arg, int pending)
7490
{
7491
struct nfsclwritedsdorpc *drpc;
7492
7493
drpc = (struct nfsclwritedsdorpc *)arg;
7494
drpc->err = nfsrpc_writedsmir(drpc->vp, &drpc->iomode,
7495
&drpc->must_commit, drpc->stateidp, drpc->dsp, drpc->off, drpc->len,
7496
drpc->fhp, drpc->m, drpc->vers, drpc->minorvers, drpc->cred,
7497
drpc->p);
7498
drpc->done = 1;
7499
crfree(drpc->cred);
7500
NFSCL_DEBUG(4, "start_writedsmir: err=%d\n", drpc->err);
7501
}
7502
7503
/*
7504
* Set up the write DS mirror call for the pNFS I/O thread.
7505
*/
7506
static int
7507
nfsio_writedsmir(vnode_t vp, int *iomode, int *must_commit,
7508
nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t off, int len,
7509
struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers,
7510
struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p)
7511
{
7512
int error, ret;
7513
7514
error = 0;
7515
drpc->done = 0;
7516
drpc->vp = vp;
7517
drpc->iomode = *iomode;
7518
drpc->must_commit = *must_commit;
7519
drpc->stateidp = stateidp;
7520
drpc->dsp = dsp;
7521
drpc->off = off;
7522
drpc->len = len;
7523
drpc->fhp = fhp;
7524
drpc->m = m;
7525
drpc->vers = vers;
7526
drpc->minorvers = minorvers;
7527
drpc->cred = crhold(cred);
7528
drpc->p = p;
7529
drpc->inprog = 0;
7530
ret = EIO;
7531
if (nfs_pnfsiothreads != 0) {
7532
ret = nfs_pnfsio(start_writedsmir, drpc);
7533
NFSCL_DEBUG(4, "nfsio_writedsmir: nfs_pnfsio=%d\n", ret);
7534
}
7535
if (ret != 0) {
7536
error = nfsrpc_writedsmir(vp, iomode, &drpc->must_commit,
7537
stateidp, dsp, off, len, fhp, m, vers, minorvers, cred, p);
7538
crfree(drpc->cred);
7539
}
7540
NFSCL_DEBUG(4, "nfsio_writedsmir: error=%d\n", error);
7541
return (error);
7542
}
7543
7544
/*
7545
* Free up the nfsclds structure.
7546
*/
7547
void
7548
nfscl_freenfsclds(struct nfsclds *dsp)
7549
{
7550
int i;
7551
7552
if (dsp == NULL)
7553
return;
7554
if (dsp->nfsclds_sockp != NULL) {
7555
NFSFREECRED(dsp->nfsclds_sockp->nr_cred);
7556
NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx);
7557
free(dsp->nfsclds_sockp->nr_nam, M_SONAME);
7558
free(dsp->nfsclds_sockp, M_NFSSOCKREQ);
7559
}
7560
NFSFREEMUTEX(&dsp->nfsclds_mtx);
7561
NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx);
7562
for (i = 0; i < NFSV4_CBSLOTS; i++) {
7563
if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL)
7564
m_freem(
7565
dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply);
7566
}
7567
free(dsp, M_NFSCLDS);
7568
}
7569
7570
static enum nfsclds_state
7571
nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp,
7572
struct nfsclds **retdspp, uint32_t *sequencep)
7573
{
7574
struct nfsclds *dsp;
7575
int fndseq;
7576
7577
/*
7578
* Search the list of nfsclds structures for one with the same
7579
* server.
7580
*/
7581
fndseq = 0;
7582
TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) {
7583
if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen &&
7584
dsp->nfsclds_servownlen != 0 &&
7585
!NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown,
7586
dsp->nfsclds_servownlen) &&
7587
dsp->nfsclds_sess.nfsess_defunct == 0) {
7588
NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n",
7589
TAILQ_FIRST(&nmp->nm_sess), dsp,
7590
dsp->nfsclds_flags);
7591
if (fndseq == 0) {
7592
/* Get sequenceid# from first entry. */
7593
*sequencep =
7594
dsp->nfsclds_sess.nfsess_sequenceid;
7595
fndseq = 1;
7596
}
7597
/* Server major id matches. */
7598
if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) {
7599
*retdspp = dsp;
7600
return (NFSDSP_USETHISSESSION);
7601
}
7602
}
7603
}
7604
if (fndseq != 0)
7605
return (NFSDSP_SEQTHISSESSION);
7606
return (NFSDSP_NOTFOUND);
7607
}
7608
7609
/*
7610
* NFS commit rpc to a NFSv4.1 DS.
7611
*/
7612
static int
7613
nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
7614
struct nfsfh *fhp, int vers, int minorvers, struct ucred *cred,
7615
NFSPROC_T *p)
7616
{
7617
uint32_t *tl;
7618
struct nfsrv_descript nfsd, *nd = &nfsd;
7619
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
7620
struct nfssockreq *nrp;
7621
struct nfsvattr na;
7622
int attrflag, error;
7623
7624
nd->nd_mrep = NULL;
7625
if (vers == 0 || vers == NFS_VER4) {
7626
nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh,
7627
fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers,
7628
NULL);
7629
vers = NFS_VER4;
7630
} else {
7631
nfscl_reqstart(nd, NFSPROC_COMMIT, nmp, fhp->nfh_fh,
7632
fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers,
7633
NULL);
7634
NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_COMMIT]);
7635
NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_COMMITDS]);
7636
}
7637
NFSCL_DEBUG(4, "nfsrpc_commitds: vers=%d minvers=%d\n", vers,
7638
minorvers);
7639
NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
7640
txdr_hyper(offset, tl);
7641
tl += 2;
7642
*tl = txdr_unsigned(cnt);
7643
nrp = dsp->nfsclds_sockp;
7644
if (nrp == NULL)
7645
/* If NULL, use the MDS socket. */
7646
nrp = &nmp->nm_sockreq;
7647
error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
7648
NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
7649
NFSCL_DEBUG(4, "nfsrpc_commitds: err=%d stat=%d\n", error,
7650
nd->nd_repstat);
7651
if (error != 0)
7652
return (error);
7653
if (nd->nd_repstat == 0) {
7654
if (vers == NFS_VER3) {
7655
error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL,
7656
NULL);
7657
NFSCL_DEBUG(4, "nfsrpc_commitds: wccdata=%d\n", error);
7658
if (error != 0)
7659
goto nfsmout;
7660
}
7661
NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
7662
NFSLOCKDS(dsp);
7663
if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
7664
NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
7665
error = NFSERR_STALEWRITEVERF;
7666
}
7667
NFSUNLOCKDS(dsp);
7668
}
7669
nfsmout:
7670
if (error == 0 && nd->nd_repstat != 0)
7671
error = nd->nd_repstat;
7672
m_freem(nd->nd_mrep);
7673
return (error);
7674
}
7675
7676
/*
7677
* Start up the thread that will execute nfsrpc_commitds().
7678
*/
7679
static void
7680
start_commitds(void *arg, int pending)
7681
{
7682
struct nfsclwritedsdorpc *drpc;
7683
7684
drpc = (struct nfsclwritedsdorpc *)arg;
7685
drpc->err = nfsrpc_commitds(drpc->vp, drpc->off, drpc->len,
7686
drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, drpc->cred,
7687
drpc->p);
7688
drpc->done = 1;
7689
crfree(drpc->cred);
7690
NFSCL_DEBUG(4, "start_commitds: err=%d\n", drpc->err);
7691
}
7692
7693
/*
7694
* Set up the commit DS mirror call for the pNFS I/O thread.
7695
*/
7696
static int
7697
nfsio_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
7698
struct nfsfh *fhp, int vers, int minorvers,
7699
struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p)
7700
{
7701
int error, ret;
7702
7703
error = 0;
7704
drpc->done = 0;
7705
drpc->vp = vp;
7706
drpc->off = offset;
7707
drpc->len = cnt;
7708
drpc->dsp = dsp;
7709
drpc->fhp = fhp;
7710
drpc->vers = vers;
7711
drpc->minorvers = minorvers;
7712
drpc->cred = crhold(cred);
7713
drpc->p = p;
7714
drpc->inprog = 0;
7715
ret = EIO;
7716
if (nfs_pnfsiothreads != 0) {
7717
ret = nfs_pnfsio(start_commitds, drpc);
7718
NFSCL_DEBUG(4, "nfsio_commitds: nfs_pnfsio=%d\n", ret);
7719
}
7720
if (ret != 0) {
7721
error = nfsrpc_commitds(vp, offset, cnt, dsp, fhp, vers,
7722
minorvers, cred, p);
7723
crfree(drpc->cred);
7724
}
7725
NFSCL_DEBUG(4, "nfsio_commitds: error=%d\n", error);
7726
return (error);
7727
}
7728
7729
/*
7730
* NFS Advise rpc
7731
*/
7732
int
7733
nfsrpc_advise(vnode_t vp, off_t offset, uint64_t cnt, int advise,
7734
struct ucred *cred, NFSPROC_T *p)
7735
{
7736
u_int32_t *tl;
7737
struct nfsrv_descript nfsd, *nd = &nfsd;
7738
nfsattrbit_t hints;
7739
int error;
7740
7741
NFSZERO_ATTRBIT(&hints);
7742
if (advise == POSIX_FADV_WILLNEED)
7743
NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
7744
else if (advise == POSIX_FADV_DONTNEED)
7745
NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
7746
else
7747
return (0);
7748
NFSCL_REQSTART(nd, NFSPROC_IOADVISE, vp, cred);
7749
nfsm_stateidtom(nd, NULL, NFSSTATEID_PUTALLZERO);
7750
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER);
7751
txdr_hyper(offset, tl);
7752
tl += 2;
7753
txdr_hyper(cnt, tl);
7754
nfsrv_putattrbit(nd, &hints);
7755
error = nfscl_request(nd, vp, p, cred);
7756
if (error != 0)
7757
return (error);
7758
if (nd->nd_repstat != 0)
7759
error = nd->nd_repstat;
7760
m_freem(nd->nd_mrep);
7761
return (error);
7762
}
7763
7764
#ifdef notyet
7765
/*
7766
* NFS advise rpc to a NFSv4.2 DS.
7767
*/
7768
static int
7769
nfsrpc_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise,
7770
struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers,
7771
struct ucred *cred, NFSPROC_T *p)
7772
{
7773
uint32_t *tl;
7774
struct nfsrv_descript nfsd, *nd = &nfsd;
7775
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
7776
struct nfssockreq *nrp;
7777
nfsattrbit_t hints;
7778
int error;
7779
7780
/* For NFS DSs prior to NFSv4.2, just return OK. */
7781
if (vers == NFS_VER3 || minorversion < NFSV42_MINORVERSION)
7782
return (0);
7783
NFSZERO_ATTRBIT(&hints);
7784
if (advise == POSIX_FADV_WILLNEED)
7785
NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
7786
else if (advise == POSIX_FADV_DONTNEED)
7787
NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
7788
else
7789
return (0);
7790
nd->nd_mrep = NULL;
7791
nfscl_reqstart(nd, NFSPROC_IOADVISEDS, nmp, fhp->nfh_fh,
7792
fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, NULL);
7793
vers = NFS_VER4;
7794
NFSCL_DEBUG(4, "nfsrpc_adviseds: vers=%d minvers=%d\n", vers,
7795
minorvers);
7796
nfsm_stateidtom(nd, NULL, NFSSTATEID_PUTALLZERO);
7797
NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
7798
txdr_hyper(offset, tl);
7799
tl += 2;
7800
*tl = txdr_unsigned(cnt);
7801
nfsrv_putattrbit(nd, &hints);
7802
nrp = dsp->nfsclds_sockp;
7803
if (nrp == NULL)
7804
/* If NULL, use the MDS socket. */
7805
nrp = &nmp->nm_sockreq;
7806
error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
7807
NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
7808
NFSCL_DEBUG(4, "nfsrpc_adviseds: err=%d stat=%d\n", error,
7809
nd->nd_repstat);
7810
if (error != 0)
7811
return (error);
7812
if (nd->nd_repstat != 0)
7813
error = nd->nd_repstat;
7814
m_freem(nd->nd_mrep);
7815
return (error);
7816
}
7817
7818
/*
7819
* Start up the thread that will execute nfsrpc_commitds().
7820
*/
7821
static void
7822
start_adviseds(void *arg, int pending)
7823
{
7824
struct nfsclwritedsdorpc *drpc;
7825
7826
drpc = (struct nfsclwritedsdorpc *)arg;
7827
drpc->err = nfsrpc_adviseds(drpc->vp, drpc->off, drpc->len,
7828
drpc->advise, drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers,
7829
drpc->cred, drpc->p);
7830
drpc->done = 1;
7831
crfree(drpc->cred);
7832
NFSCL_DEBUG(4, "start_adviseds: err=%d\n", drpc->err);
7833
}
7834
7835
/*
7836
* Set up the advise DS mirror call for the pNFS I/O thread.
7837
*/
7838
static int
7839
nfsio_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise,
7840
struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers,
7841
struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p)
7842
{
7843
int error, ret;
7844
7845
error = 0;
7846
drpc->done = 0;
7847
drpc->vp = vp;
7848
drpc->off = offset;
7849
drpc->len = cnt;
7850
drpc->advise = advise;
7851
drpc->dsp = dsp;
7852
drpc->fhp = fhp;
7853
drpc->vers = vers;
7854
drpc->minorvers = minorvers;
7855
drpc->cred = crhold(cred);
7856
drpc->p = p;
7857
drpc->inprog = 0;
7858
ret = EIO;
7859
if (nfs_pnfsiothreads != 0) {
7860
ret = nfs_pnfsio(start_adviseds, drpc);
7861
NFSCL_DEBUG(4, "nfsio_adviseds: nfs_pnfsio=%d\n", ret);
7862
}
7863
if (ret != 0) {
7864
error = nfsrpc_adviseds(vp, offset, cnt, advise, dsp, fhp, vers,
7865
minorvers, cred, p);
7866
crfree(drpc->cred);
7867
}
7868
NFSCL_DEBUG(4, "nfsio_adviseds: error=%d\n", error);
7869
return (error);
7870
}
7871
#endif /* notyet */
7872
7873
/*
7874
* Do the Allocate operation, retrying for recovery.
7875
*/
7876
int
7877
nfsrpc_allocate(vnode_t vp, off_t off, off_t len, struct nfsvattr *nap,
7878
int *attrflagp, struct ucred *cred, NFSPROC_T *p)
7879
{
7880
int error, expireret = 0, retrycnt, nostateid;
7881
uint32_t clidrev = 0;
7882
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
7883
struct nfsfh *nfhp = NULL;
7884
nfsv4stateid_t stateid;
7885
off_t tmp_off;
7886
void *lckp;
7887
7888
if (len < 0)
7889
return (EINVAL);
7890
if (len == 0)
7891
return (0);
7892
tmp_off = off + len;
7893
NFSLOCKMNT(nmp);
7894
if (tmp_off > nmp->nm_maxfilesize || tmp_off < off) {
7895
NFSUNLOCKMNT(nmp);
7896
return (EFBIG);
7897
}
7898
if (nmp->nm_clp != NULL)
7899
clidrev = nmp->nm_clp->nfsc_clientidrev;
7900
NFSUNLOCKMNT(nmp);
7901
nfhp = VTONFS(vp)->n_fhp;
7902
retrycnt = 0;
7903
do {
7904
lckp = NULL;
7905
nostateid = 0;
7906
nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
7907
NFSV4OPEN_ACCESSWRITE, 0, cred, p, &stateid, &lckp);
7908
if (stateid.other[0] == 0 && stateid.other[1] == 0 &&
7909
stateid.other[2] == 0) {
7910
nostateid = 1;
7911
NFSCL_DEBUG(1, "stateid0 in allocate\n");
7912
}
7913
7914
/*
7915
* Not finding a stateid should probably never happen,
7916
* but just return an error for this case.
7917
*/
7918
if (nostateid != 0)
7919
error = EIO;
7920
else
7921
error = nfsrpc_allocaterpc(vp, off, len, &stateid,
7922
nap, attrflagp, cred, p);
7923
if (error == NFSERR_STALESTATEID)
7924
nfscl_initiate_recovery(nmp->nm_clp);
7925
if (lckp != NULL)
7926
nfscl_lockderef(lckp);
7927
if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
7928
error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
7929
error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
7930
(void) nfs_catnap(PZERO, error, "nfs_allocate");
7931
} else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) &&
7932
error == NFSERR_BADSTATEID)) && clidrev != 0) {
7933
expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
7934
} else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) {
7935
error = EIO;
7936
}
7937
retrycnt++;
7938
} while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
7939
error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
7940
error == NFSERR_STALEDONTRECOVER ||
7941
(error == NFSERR_OLDSTATEID && retrycnt < 20) ||
7942
((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
7943
expireret == 0 && clidrev != 0 && retrycnt < 4));
7944
if (error != 0 && retrycnt >= 4)
7945
error = EIO;
7946
return (error);
7947
}
7948
7949
/*
7950
* The allocate RPC.
7951
*/
7952
static int
7953
nfsrpc_allocaterpc(vnode_t vp, off_t off, off_t len, nfsv4stateid_t *stateidp,
7954
struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p)
7955
{
7956
uint32_t *tl;
7957
int error;
7958
struct nfsrv_descript nfsd;
7959
struct nfsrv_descript *nd = &nfsd;
7960
nfsattrbit_t attrbits;
7961
7962
*attrflagp = 0;
7963
NFSCL_REQSTART(nd, NFSPROC_ALLOCATE, vp, cred);
7964
nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
7965
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
7966
txdr_hyper(off, tl); tl += 2;
7967
txdr_hyper(len, tl); tl += 2;
7968
*tl = txdr_unsigned(NFSV4OP_GETATTR);
7969
NFSGETATTR_ATTRBIT(&attrbits);
7970
nfsrv_putattrbit(nd, &attrbits);
7971
error = nfscl_request(nd, vp, p, cred);
7972
if (error != 0)
7973
return (error);
7974
if (nd->nd_repstat == 0) {
7975
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
7976
error = nfsm_loadattr(nd, nap);
7977
if (error == 0)
7978
*attrflagp = NFS_LATTR_NOSHRINK;
7979
} else
7980
error = nd->nd_repstat;
7981
nfsmout:
7982
m_freem(nd->nd_mrep);
7983
return (error);
7984
}
7985
7986
/*
7987
* Set up the XDR arguments for the LayoutGet operation.
7988
*/
7989
static void
7990
nfsrv_setuplayoutget(struct nfsrv_descript *nd, int iomode, uint64_t offset,
7991
uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layouttype,
7992
int layoutlen, int usecurstateid)
7993
{
7994
uint32_t *tl;
7995
7996
NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
7997
NFSX_STATEID);
7998
*tl++ = newnfs_false; /* Don't signal availability. */
7999
*tl++ = txdr_unsigned(layouttype);
8000
*tl++ = txdr_unsigned(iomode);
8001
txdr_hyper(offset, tl);
8002
tl += 2;
8003
txdr_hyper(len, tl);
8004
tl += 2;
8005
txdr_hyper(minlen, tl);
8006
tl += 2;
8007
if (usecurstateid != 0) {
8008
/* Special stateid for Current stateid. */
8009
*tl++ = txdr_unsigned(1);
8010
*tl++ = 0;
8011
*tl++ = 0;
8012
*tl++ = 0;
8013
} else {
8014
*tl++ = txdr_unsigned(stateidp->seqid);
8015
NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid);
8016
*tl++ = stateidp->other[0];
8017
*tl++ = stateidp->other[1];
8018
*tl++ = stateidp->other[2];
8019
}
8020
*tl = txdr_unsigned(layoutlen);
8021
}
8022
8023
/*
8024
* Parse the reply for a successful LayoutGet operation.
8025
*/
8026
static int
8027
nfsrv_parselayoutget(struct nfsmount *nmp, struct nfsrv_descript *nd,
8028
nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp)
8029
{
8030
uint32_t *tl;
8031
struct nfsclflayout *flp, *prevflp, *tflp;
8032
int cnt, error, fhcnt, gotiomode, i, iomode, j, k, l, laytype, nfhlen;
8033
int m, mirrorcnt;
8034
uint64_t retlen, off;
8035
struct nfsfh *nfhp;
8036
uint8_t *cp;
8037
uid_t user;
8038
gid_t grp;
8039
8040
NFSCL_DEBUG(4, "in nfsrv_parselayoutget\n");
8041
error = 0;
8042
flp = NULL;
8043
gotiomode = -1;
8044
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID);
8045
if (*tl++ != 0)
8046
*retonclosep = 1;
8047
else
8048
*retonclosep = 0;
8049
stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
8050
NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep,
8051
(int)stateidp->seqid);
8052
stateidp->other[0] = *tl++;
8053
stateidp->other[1] = *tl++;
8054
stateidp->other[2] = *tl++;
8055
cnt = fxdr_unsigned(int, *tl);
8056
NFSCL_DEBUG(4, "layg cnt=%d\n", cnt);
8057
if (cnt <= 0 || cnt > 10000) {
8058
/* Don't accept more than 10000 layouts in reply. */
8059
error = NFSERR_BADXDR;
8060
goto nfsmout;
8061
}
8062
for (i = 0; i < cnt; i++) {
8063
/* Dissect to the layout type. */
8064
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER +
8065
3 * NFSX_UNSIGNED);
8066
off = fxdr_hyper(tl); tl += 2;
8067
retlen = fxdr_hyper(tl); tl += 2;
8068
iomode = fxdr_unsigned(int, *tl++);
8069
laytype = fxdr_unsigned(int, *tl);
8070
NFSCL_DEBUG(4, "layt=%d off=%ju len=%ju iom=%d\n", laytype,
8071
(uintmax_t)off, (uintmax_t)retlen, iomode);
8072
/* Ignore length of layout body for now. */
8073
if (laytype == NFSLAYOUT_NFSV4_1_FILES) {
8074
/* Parse the File layout up to fhcnt. */
8075
NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED +
8076
NFSX_HYPER + NFSX_V4DEVICEID);
8077
fhcnt = fxdr_unsigned(int, *(tl + 4 +
8078
NFSX_V4DEVICEID / NFSX_UNSIGNED));
8079
NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt);
8080
if (fhcnt < 0 || fhcnt > 100) {
8081
/* Don't accept more than 100 file handles. */
8082
error = NFSERR_BADXDR;
8083
goto nfsmout;
8084
}
8085
if (fhcnt > 0)
8086
flp = malloc(sizeof(*flp) + fhcnt *
8087
sizeof(struct nfsfh *), M_NFSFLAYOUT,
8088
M_WAITOK);
8089
else
8090
flp = malloc(sizeof(*flp), M_NFSFLAYOUT,
8091
M_WAITOK);
8092
flp->nfsfl_flags = NFSFL_FILE;
8093
flp->nfsfl_fhcnt = 0;
8094
flp->nfsfl_devp = NULL;
8095
flp->nfsfl_off = off;
8096
if (flp->nfsfl_off + retlen < flp->nfsfl_off)
8097
flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off;
8098
else
8099
flp->nfsfl_end = flp->nfsfl_off + retlen;
8100
flp->nfsfl_iomode = iomode;
8101
if (gotiomode == -1)
8102
gotiomode = flp->nfsfl_iomode;
8103
/* Ignore layout body length for now. */
8104
NFSBCOPY(tl, flp->nfsfl_dev, NFSX_V4DEVICEID);
8105
tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
8106
flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++);
8107
NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util);
8108
mtx_lock(&nmp->nm_mtx);
8109
if (nmp->nm_minorvers > 1 && (flp->nfsfl_util &
8110
NFSFLAYUTIL_IOADVISE_THRU_MDS) != 0)
8111
nmp->nm_privflag |= NFSMNTP_IOADVISETHRUMDS;
8112
mtx_unlock(&nmp->nm_mtx);
8113
flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++);
8114
flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2;
8115
NFSCL_DEBUG(4, "stripe1=%u poff=%ju\n",
8116
flp->nfsfl_stripe1, (uintmax_t)flp->nfsfl_patoff);
8117
for (j = 0; j < fhcnt; j++) {
8118
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
8119
nfhlen = fxdr_unsigned(int, *tl);
8120
if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) {
8121
error = NFSERR_BADXDR;
8122
goto nfsmout;
8123
}
8124
nfhp = malloc(sizeof(*nfhp) + nfhlen - 1,
8125
M_NFSFH, M_WAITOK);
8126
flp->nfsfl_fh[j] = nfhp;
8127
flp->nfsfl_fhcnt++;
8128
nfhp->nfh_len = nfhlen;
8129
NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen));
8130
NFSBCOPY(cp, nfhp->nfh_fh, nfhlen);
8131
}
8132
} else if (laytype == NFSLAYOUT_FLEXFILE) {
8133
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED +
8134
NFSX_HYPER);
8135
mirrorcnt = fxdr_unsigned(int, *(tl + 2));
8136
NFSCL_DEBUG(4, "mirrorcnt=%d\n", mirrorcnt);
8137
if (mirrorcnt < 1 || mirrorcnt > NFSDEV_MAXMIRRORS) {
8138
error = NFSERR_BADXDR;
8139
goto nfsmout;
8140
}
8141
flp = malloc(sizeof(*flp) + mirrorcnt *
8142
sizeof(struct nfsffm), M_NFSFLAYOUT, M_WAITOK);
8143
flp->nfsfl_flags = NFSFL_FLEXFILE;
8144
flp->nfsfl_mirrorcnt = mirrorcnt;
8145
for (j = 0; j < mirrorcnt; j++)
8146
flp->nfsfl_ffm[j].devp = NULL;
8147
flp->nfsfl_off = off;
8148
if (flp->nfsfl_off + retlen < flp->nfsfl_off)
8149
flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off;
8150
else
8151
flp->nfsfl_end = flp->nfsfl_off + retlen;
8152
flp->nfsfl_iomode = iomode;
8153
if (gotiomode == -1)
8154
gotiomode = flp->nfsfl_iomode;
8155
flp->nfsfl_stripeunit = fxdr_hyper(tl);
8156
NFSCL_DEBUG(4, "stripeunit=%ju\n",
8157
(uintmax_t)flp->nfsfl_stripeunit);
8158
for (j = 0; j < mirrorcnt; j++) {
8159
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
8160
k = fxdr_unsigned(int, *tl);
8161
if (k < 1 || k > 128) {
8162
error = NFSERR_BADXDR;
8163
goto nfsmout;
8164
}
8165
NFSCL_DEBUG(4, "servercnt=%d\n", k);
8166
for (l = 0; l < k; l++) {
8167
NFSM_DISSECT(tl, uint32_t *,
8168
NFSX_V4DEVICEID + NFSX_STATEID +
8169
2 * NFSX_UNSIGNED);
8170
if (l == 0) {
8171
/* Just use the first server. */
8172
NFSBCOPY(tl,
8173
flp->nfsfl_ffm[j].dev,
8174
NFSX_V4DEVICEID);
8175
tl += (NFSX_V4DEVICEID /
8176
NFSX_UNSIGNED);
8177
tl++;
8178
flp->nfsfl_ffm[j].st.seqid =
8179
*tl++;
8180
flp->nfsfl_ffm[j].st.other[0] =
8181
*tl++;
8182
flp->nfsfl_ffm[j].st.other[1] =
8183
*tl++;
8184
flp->nfsfl_ffm[j].st.other[2] =
8185
*tl++;
8186
NFSCL_DEBUG(4, "st.seqid=%u "
8187
"st.o0=0x%x st.o1=0x%x "
8188
"st.o2=0x%x\n",
8189
flp->nfsfl_ffm[j].st.seqid,
8190
flp->nfsfl_ffm[j].st.other[0],
8191
flp->nfsfl_ffm[j].st.other[1],
8192
flp->nfsfl_ffm[j].st.other[2]);
8193
} else
8194
tl += ((NFSX_V4DEVICEID +
8195
NFSX_STATEID +
8196
NFSX_UNSIGNED) /
8197
NFSX_UNSIGNED);
8198
fhcnt = fxdr_unsigned(int, *tl);
8199
NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt);
8200
if (fhcnt < 1 ||
8201
fhcnt > NFSDEV_MAXVERS) {
8202
error = NFSERR_BADXDR;
8203
goto nfsmout;
8204
}
8205
for (m = 0; m < fhcnt; m++) {
8206
NFSM_DISSECT(tl, uint32_t *,
8207
NFSX_UNSIGNED);
8208
nfhlen = fxdr_unsigned(int,
8209
*tl);
8210
NFSCL_DEBUG(4, "nfhlen=%d\n",
8211
nfhlen);
8212
if (nfhlen <= 0 || nfhlen >
8213
NFSX_V4FHMAX) {
8214
error = NFSERR_BADXDR;
8215
goto nfsmout;
8216
}
8217
NFSM_DISSECT(cp, uint8_t *,
8218
NFSM_RNDUP(nfhlen));
8219
if (l == 0) {
8220
flp->nfsfl_ffm[j].fhcnt
8221
= fhcnt;
8222
nfhp = malloc(
8223
sizeof(*nfhp) +
8224
nfhlen - 1, M_NFSFH,
8225
M_WAITOK);
8226
flp->nfsfl_ffm[j].fh[m]
8227
= nfhp;
8228
nfhp->nfh_len = nfhlen;
8229
NFSBCOPY(cp,
8230
nfhp->nfh_fh,
8231
nfhlen);
8232
NFSCL_DEBUG(4,
8233
"got fh\n");
8234
}
8235
}
8236
/* Now, get the ffsd_user/ffds_group. */
8237
error = nfsrv_parseug(nd, 0, &user,
8238
&grp, curthread);
8239
NFSCL_DEBUG(4, "after parseu=%d\n",
8240
error);
8241
if (error == 0)
8242
error = nfsrv_parseug(nd, 1,
8243
&user, &grp, curthread);
8244
NFSCL_DEBUG(4, "aft parseg=%d\n",
8245
grp);
8246
if (error != 0)
8247
goto nfsmout;
8248
NFSCL_DEBUG(4, "user=%d group=%d\n",
8249
user, grp);
8250
if (l == 0) {
8251
flp->nfsfl_ffm[j].user = user;
8252
flp->nfsfl_ffm[j].group = grp;
8253
NFSCL_DEBUG(4,
8254
"usr=%d grp=%d\n", user,
8255
grp);
8256
}
8257
}
8258
}
8259
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8260
flp->nfsfl_fflags = fxdr_unsigned(uint32_t, *tl++);
8261
#ifdef notnow
8262
/*
8263
* At this time, there is no flag.
8264
* NFSFLEXFLAG_IOADVISE_THRU_MDS might need to be
8265
* added, or it may never exist?
8266
*/
8267
mtx_lock(&nmp->nm_mtx);
8268
if (nmp->nm_minorvers > 1 && (flp->nfsfl_fflags &
8269
NFSFLEXFLAG_IOADVISE_THRU_MDS) != 0)
8270
nmp->nm_privflag |= NFSMNTP_IOADVISETHRUMDS;
8271
mtx_unlock(&nmp->nm_mtx);
8272
#endif
8273
flp->nfsfl_statshint = fxdr_unsigned(uint32_t, *tl);
8274
NFSCL_DEBUG(4, "fflags=0x%x statshint=%d\n",
8275
flp->nfsfl_fflags, flp->nfsfl_statshint);
8276
} else {
8277
error = NFSERR_BADXDR;
8278
goto nfsmout;
8279
}
8280
if (flp->nfsfl_iomode == gotiomode) {
8281
/* Keep the list in increasing offset order. */
8282
tflp = LIST_FIRST(flhp);
8283
prevflp = NULL;
8284
while (tflp != NULL &&
8285
tflp->nfsfl_off < flp->nfsfl_off) {
8286
prevflp = tflp;
8287
tflp = LIST_NEXT(tflp, nfsfl_list);
8288
}
8289
if (prevflp == NULL)
8290
LIST_INSERT_HEAD(flhp, flp, nfsfl_list);
8291
else
8292
LIST_INSERT_AFTER(prevflp, flp,
8293
nfsfl_list);
8294
NFSCL_DEBUG(4, "flp inserted\n");
8295
} else {
8296
printf("nfscl_layoutget(): got wrong iomode\n");
8297
nfscl_freeflayout(flp);
8298
}
8299
flp = NULL;
8300
}
8301
nfsmout:
8302
NFSCL_DEBUG(4, "eo nfsrv_parselayoutget=%d\n", error);
8303
if (error != 0 && flp != NULL)
8304
nfscl_freeflayout(flp);
8305
return (error);
8306
}
8307
8308
/*
8309
* Parse a user/group digit string.
8310
*/
8311
static int
8312
nfsrv_parseug(struct nfsrv_descript *nd, int dogrp, uid_t *uidp, gid_t *gidp,
8313
NFSPROC_T *p)
8314
{
8315
uint32_t *tl;
8316
char *str, str0[NFSV4_SMALLSTR + 1];
8317
uint32_t len = 0;
8318
int error = 0;
8319
8320
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
8321
len = fxdr_unsigned(uint32_t, *tl);
8322
str = NULL;
8323
if (len > NFSV4_OPAQUELIMIT) {
8324
error = NFSERR_BADXDR;
8325
goto nfsmout;
8326
}
8327
NFSCL_DEBUG(4, "nfsrv_parseug: len=%d\n", len);
8328
if (len == 0) {
8329
if (dogrp != 0)
8330
*gidp = GID_NOGROUP;
8331
else
8332
*uidp = UID_NOBODY;
8333
return (0);
8334
}
8335
if (len > NFSV4_SMALLSTR)
8336
str = malloc(len + 1, M_TEMP, M_WAITOK);
8337
else
8338
str = str0;
8339
error = nfsrv_mtostr(nd, str, len);
8340
if (error != 0)
8341
goto nfsmout;
8342
NFSCL_DEBUG(4, "nfsrv_parseug: str=%s\n", str);
8343
if (dogrp != 0)
8344
error = nfsv4_strtogid(nd, str, len, gidp);
8345
else
8346
error = nfsv4_strtouid(nd, str, len, uidp);
8347
nfsmout:
8348
if (len > NFSV4_SMALLSTR)
8349
free(str, M_TEMP);
8350
NFSCL_DEBUG(4, "eo nfsrv_parseug=%d\n", error);
8351
return (error);
8352
}
8353
8354
/*
8355
* Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(),
8356
* so that it does both an Open and a Layoutget.
8357
*/
8358
static int
8359
nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
8360
int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode,
8361
struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp,
8362
struct ucred *cred, NFSPROC_T *p)
8363
{
8364
struct nfscllayout *lyp;
8365
struct nfsclflayout *flp;
8366
struct nfsclflayouthead flh;
8367
int error, islocked, layoutlen, recalled, retonclose, usecurstateid;
8368
int layouttype, laystat;
8369
nfsv4stateid_t stateid;
8370
struct nfsclsession *tsep;
8371
8372
error = 0;
8373
if (NFSHASFLEXFILE(nmp))
8374
layouttype = NFSLAYOUT_FLEXFILE;
8375
else
8376
layouttype = NFSLAYOUT_NFSV4_1_FILES;
8377
/*
8378
* If lyp is returned non-NULL, there will be a refcnt (shared lock)
8379
* on it, iff flp != NULL or a lock (exclusive lock) on it iff
8380
* flp == NULL.
8381
*/
8382
lyp = nfscl_getlayout(nmp->nm_clp, newfhp, newfhlen, 0, mode, &flp,
8383
&recalled);
8384
NFSCL_DEBUG(4, "nfsrpc_getopenlayout nfscl_getlayout lyp=%p\n", lyp);
8385
if (lyp == NULL)
8386
islocked = 0;
8387
else if (flp != NULL)
8388
islocked = 1;
8389
else
8390
islocked = 2;
8391
if ((lyp == NULL || flp == NULL) && recalled == 0) {
8392
LIST_INIT(&flh);
8393
tsep = nfsmnt_mdssession(nmp);
8394
layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID +
8395
3 * NFSX_UNSIGNED);
8396
if (lyp == NULL)
8397
usecurstateid = 1;
8398
else {
8399
usecurstateid = 0;
8400
stateid.seqid = lyp->nfsly_stateid.seqid;
8401
stateid.other[0] = lyp->nfsly_stateid.other[0];
8402
stateid.other[1] = lyp->nfsly_stateid.other[1];
8403
stateid.other[2] = lyp->nfsly_stateid.other[2];
8404
}
8405
error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen,
8406
newfhp, newfhlen, mode, op, name, namelen,
8407
dpp, &stateid, usecurstateid, layouttype, layoutlen,
8408
&retonclose, &flh, &laystat, cred, p);
8409
NFSCL_DEBUG(4, "aft nfsrpc_openlayoutrpc laystat=%d err=%d\n",
8410
laystat, error);
8411
laystat = nfsrpc_layoutgetres(nmp, vp, newfhp, newfhlen,
8412
&stateid, retonclose, NULL, &lyp, &flh, layouttype, laystat,
8413
&islocked, cred, p);
8414
} else
8415
error = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen,
8416
mode, op, name, namelen, dpp, 0, 0, cred, p, 0, 0);
8417
if (islocked == 2)
8418
nfscl_rellayout(lyp, 1);
8419
else if (islocked == 1)
8420
nfscl_rellayout(lyp, 0);
8421
return (error);
8422
}
8423
8424
/*
8425
* This function does an Open+LayoutGet for an NFSv4.1 mount with pNFS
8426
* enabled, only for the CLAIM_NULL case. All other NFSv4 Opens are
8427
* handled by nfsrpc_openrpc().
8428
* For the case where op == NULL, dvp is the directory. When op != NULL, it
8429
* can be NULL.
8430
*/
8431
static int
8432
nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
8433
int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode,
8434
struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp,
8435
nfsv4stateid_t *stateidp, int usecurstateid, int layouttype,
8436
int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp,
8437
int *laystatp, struct ucred *cred, NFSPROC_T *p)
8438
{
8439
uint32_t *tl;
8440
struct nfsrv_descript nfsd, *nd = &nfsd;
8441
struct nfscldeleg *ndp = NULL;
8442
struct nfsvattr nfsva;
8443
struct nfsclsession *tsep;
8444
uint32_t rflags, deleg;
8445
nfsattrbit_t attrbits;
8446
int error, ret, acesize, limitby, iomode;
8447
8448
*dpp = NULL;
8449
*laystatp = ENXIO;
8450
nfscl_reqstart(nd, NFSPROC_OPENLAYGET, nmp, nfhp, fhlen, NULL, NULL,
8451
0, 0, cred);
8452
NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
8453
*tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
8454
*tl++ = txdr_unsigned(mode & (NFSV4OPEN_ACCESSBOTH |
8455
NFSV4OPEN_WANTDELEGMASK));
8456
*tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
8457
tsep = nfsmnt_mdssession(nmp);
8458
*tl++ = tsep->nfsess_clientid.lval[0];
8459
*tl = tsep->nfsess_clientid.lval[1];
8460
nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
8461
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8462
*tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
8463
if (NFSHASNFSV4N(nmp)) {
8464
*tl = txdr_unsigned(NFSV4OPEN_CLAIMFH);
8465
} else {
8466
*tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
8467
nfsm_strtom(nd, name, namelen);
8468
}
8469
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8470
*tl = txdr_unsigned(NFSV4OP_GETATTR);
8471
NFSZERO_ATTRBIT(&attrbits);
8472
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
8473
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
8474
nfsrv_putattrbit(nd, &attrbits);
8475
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
8476
*tl = txdr_unsigned(NFSV4OP_LAYOUTGET);
8477
if ((mode & NFSV4OPEN_ACCESSWRITE) != 0)
8478
iomode = NFSLAYOUTIOMODE_RW;
8479
else
8480
iomode = NFSLAYOUTIOMODE_READ;
8481
nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp,
8482
layouttype, layoutlen, usecurstateid);
8483
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
8484
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
8485
if (error != 0)
8486
return (error);
8487
NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
8488
if (nd->nd_repstat != 0)
8489
*laystatp = nd->nd_repstat;
8490
if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
8491
/* ND_NOMOREDATA will be set if the Open operation failed. */
8492
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
8493
6 * NFSX_UNSIGNED);
8494
op->nfso_stateid.seqid = *tl++;
8495
op->nfso_stateid.other[0] = *tl++;
8496
op->nfso_stateid.other[1] = *tl++;
8497
op->nfso_stateid.other[2] = *tl;
8498
rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
8499
error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
8500
if (error != 0)
8501
goto nfsmout;
8502
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
8503
deleg = fxdr_unsigned(u_int32_t, *tl);
8504
if (deleg == NFSV4OPEN_DELEGATEREAD ||
8505
deleg == NFSV4OPEN_DELEGATEWRITE) {
8506
if (!(op->nfso_own->nfsow_clp->nfsc_flags &
8507
NFSCLFLAGS_FIRSTDELEG))
8508
op->nfso_own->nfsow_clp->nfsc_flags |=
8509
(NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
8510
ndp = malloc(sizeof(struct nfscldeleg) + newfhlen,
8511
M_NFSCLDELEG, M_WAITOK);
8512
LIST_INIT(&ndp->nfsdl_owner);
8513
LIST_INIT(&ndp->nfsdl_lock);
8514
ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
8515
ndp->nfsdl_fhlen = newfhlen;
8516
NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
8517
newnfs_copyincred(cred, &ndp->nfsdl_cred);
8518
nfscl_lockinit(&ndp->nfsdl_rwlock);
8519
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
8520
NFSX_UNSIGNED);
8521
ndp->nfsdl_stateid.seqid = *tl++;
8522
ndp->nfsdl_stateid.other[0] = *tl++;
8523
ndp->nfsdl_stateid.other[1] = *tl++;
8524
ndp->nfsdl_stateid.other[2] = *tl++;
8525
ret = fxdr_unsigned(int, *tl);
8526
if (deleg == NFSV4OPEN_DELEGATEWRITE) {
8527
ndp->nfsdl_flags = NFSCLDL_WRITE;
8528
/*
8529
* Indicates how much the file can grow.
8530
*/
8531
NFSM_DISSECT(tl, u_int32_t *,
8532
3 * NFSX_UNSIGNED);
8533
limitby = fxdr_unsigned(int, *tl++);
8534
switch (limitby) {
8535
case NFSV4OPEN_LIMITSIZE:
8536
ndp->nfsdl_sizelimit = fxdr_hyper(tl);
8537
break;
8538
case NFSV4OPEN_LIMITBLOCKS:
8539
ndp->nfsdl_sizelimit =
8540
fxdr_unsigned(u_int64_t, *tl++);
8541
ndp->nfsdl_sizelimit *=
8542
fxdr_unsigned(u_int64_t, *tl);
8543
break;
8544
default:
8545
error = NFSERR_BADXDR;
8546
goto nfsmout;
8547
};
8548
} else
8549
ndp->nfsdl_flags = NFSCLDL_READ;
8550
if (ret != 0)
8551
ndp->nfsdl_flags |= NFSCLDL_RECALL;
8552
error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, false,
8553
&ret, &acesize);
8554
if (error != 0)
8555
goto nfsmout;
8556
} else if (deleg == NFSV4OPEN_DELEGATENONEEXT &&
8557
NFSHASNFSV4N(nmp)) {
8558
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
8559
deleg = fxdr_unsigned(uint32_t, *tl);
8560
if (deleg == NFSV4OPEN_CONTENTION ||
8561
deleg == NFSV4OPEN_RESOURCE)
8562
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
8563
} else if (deleg != NFSV4OPEN_DELEGATENONE) {
8564
error = NFSERR_BADXDR;
8565
goto nfsmout;
8566
}
8567
if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 ||
8568
nfscl_assumeposixlocks)
8569
op->nfso_posixlock = 1;
8570
else
8571
op->nfso_posixlock = 0;
8572
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
8573
/* If the 2nd element == NFS_OK, the Getattr succeeded. */
8574
if (*++tl == 0) {
8575
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
8576
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
8577
NULL, NULL, NULL, NULL, NULL, NULL, p, cred);
8578
if (error != 0)
8579
goto nfsmout;
8580
if (ndp != NULL) {
8581
ndp->nfsdl_change = nfsva.na_filerev;
8582
ndp->nfsdl_modtime = nfsva.na_mtime;
8583
ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
8584
*dpp = ndp;
8585
ndp = NULL;
8586
}
8587
/*
8588
* At this point, the Open has succeeded, so set
8589
* nd_repstat = NFS_OK. If the Layoutget failed,
8590
* this function just won't return a layout.
8591
*/
8592
if (nd->nd_repstat == 0) {
8593
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8594
*laystatp = fxdr_unsigned(int, *++tl);
8595
if (*laystatp == 0) {
8596
error = nfsrv_parselayoutget(nmp, nd,
8597
stateidp, retonclosep, flhp);
8598
if (error != 0)
8599
*laystatp = error;
8600
}
8601
} else
8602
nd->nd_repstat = 0; /* Return 0 for Open. */
8603
}
8604
}
8605
if (nd->nd_repstat != 0 && error == 0)
8606
error = nd->nd_repstat;
8607
nfsmout:
8608
free(ndp, M_NFSCLDELEG);
8609
m_freem(nd->nd_mrep);
8610
return (error);
8611
}
8612
8613
/*
8614
* Similar nfsrpc_createv4(), but also does the LayoutGet operation.
8615
* Used only for mounts with pNFS enabled.
8616
*/
8617
static int
8618
nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
8619
nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
8620
struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
8621
struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
8622
int *dattrflagp, int *unlockedp, nfsv4stateid_t *stateidp,
8623
int usecurstateid, int layouttype, int layoutlen, int *retonclosep,
8624
struct nfsclflayouthead *flhp, int *laystatp)
8625
{
8626
uint32_t *tl;
8627
int error = 0, deleg, newone, ret, acesize, limitby;
8628
struct nfsrv_descript nfsd, *nd = &nfsd;
8629
struct nfsclopen *op;
8630
struct nfscldeleg *dp = NULL;
8631
struct nfsnode *np;
8632
struct nfsfh *nfhp;
8633
struct nfsclsession *tsep;
8634
nfsattrbit_t attrbits;
8635
nfsv4stateid_t stateid;
8636
struct nfsmount *nmp;
8637
8638
nmp = VFSTONFS(dvp->v_mount);
8639
np = VTONFS(dvp);
8640
*laystatp = ENXIO;
8641
*unlockedp = 0;
8642
*nfhpp = NULL;
8643
*dpp = NULL;
8644
*attrflagp = 0;
8645
*dattrflagp = 0;
8646
if (namelen > NFS_MAXNAMLEN)
8647
return (ENAMETOOLONG);
8648
NFSCL_REQSTART(nd, NFSPROC_CREATELAYGET, dvp, cred);
8649
/*
8650
* For V4, this is actually an Open op.
8651
*/
8652
NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
8653
*tl++ = txdr_unsigned(owp->nfsow_seqid);
8654
if (NFSHASNFSV4N(nmp)) {
8655
if (!NFSHASPNFS(nmp) && nfscl_enablecallb != 0 &&
8656
nfs_numnfscbd > 0)
8657
*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
8658
NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTWRITEDELEG);
8659
else
8660
*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
8661
NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTNODELEG);
8662
} else
8663
*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
8664
NFSV4OPEN_ACCESSREAD);
8665
*tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
8666
tsep = nfsmnt_mdssession(nmp);
8667
*tl++ = tsep->nfsess_clientid.lval[0];
8668
*tl = tsep->nfsess_clientid.lval[1];
8669
nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
8670
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
8671
*tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
8672
if ((fmode & O_EXCL) != 0) {
8673
if (NFSHASSESSPERSIST(nmp)) {
8674
/* Use GUARDED for persistent sessions. */
8675
*tl = txdr_unsigned(NFSCREATE_GUARDED);
8676
nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0);
8677
} else {
8678
/* Otherwise, use EXCLUSIVE4_1. */
8679
*tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41);
8680
NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
8681
*tl++ = cverf.lval[0];
8682
*tl = cverf.lval[1];
8683
nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0);
8684
}
8685
} else {
8686
*tl = txdr_unsigned(NFSCREATE_UNCHECKED);
8687
nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0);
8688
}
8689
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
8690
*tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
8691
nfsm_strtom(nd, name, namelen);
8692
/* Get the new file's handle and attributes, plus save the FH. */
8693
NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
8694
*tl++ = txdr_unsigned(NFSV4OP_SAVEFH);
8695
*tl++ = txdr_unsigned(NFSV4OP_GETFH);
8696
*tl = txdr_unsigned(NFSV4OP_GETATTR);
8697
NFSGETATTR_ATTRBIT(&attrbits);
8698
nfsrv_putattrbit(nd, &attrbits);
8699
/* Get the directory's post-op attributes. */
8700
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
8701
*tl = txdr_unsigned(NFSV4OP_PUTFH);
8702
(void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
8703
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
8704
*tl = txdr_unsigned(NFSV4OP_GETATTR);
8705
nfsrv_putattrbit(nd, &attrbits);
8706
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
8707
*tl++ = txdr_unsigned(NFSV4OP_RESTOREFH);
8708
*tl = txdr_unsigned(NFSV4OP_LAYOUTGET);
8709
nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp,
8710
layouttype, layoutlen, usecurstateid);
8711
error = nfscl_request(nd, dvp, p, cred);
8712
if (error != 0)
8713
return (error);
8714
NFSCL_DEBUG(4, "nfsrpc_createlayout stat=%d err=%d\n", nd->nd_repstat,
8715
error);
8716
if (nd->nd_repstat != 0)
8717
*laystatp = nd->nd_repstat;
8718
NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
8719
if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
8720
NFSCL_DEBUG(4, "nfsrpc_createlayout open succeeded\n");
8721
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
8722
6 * NFSX_UNSIGNED);
8723
stateid.seqid = *tl++;
8724
stateid.other[0] = *tl++;
8725
stateid.other[1] = *tl++;
8726
stateid.other[2] = *tl;
8727
error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
8728
if (error != 0)
8729
goto nfsmout;
8730
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
8731
deleg = fxdr_unsigned(int, *tl);
8732
if (deleg == NFSV4OPEN_DELEGATEREAD ||
8733
deleg == NFSV4OPEN_DELEGATEWRITE) {
8734
if (!(owp->nfsow_clp->nfsc_flags &
8735
NFSCLFLAGS_FIRSTDELEG))
8736
owp->nfsow_clp->nfsc_flags |=
8737
(NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
8738
dp = malloc(sizeof(struct nfscldeleg) + NFSX_V4FHMAX,
8739
M_NFSCLDELEG, M_WAITOK);
8740
LIST_INIT(&dp->nfsdl_owner);
8741
LIST_INIT(&dp->nfsdl_lock);
8742
dp->nfsdl_clp = owp->nfsow_clp;
8743
newnfs_copyincred(cred, &dp->nfsdl_cred);
8744
nfscl_lockinit(&dp->nfsdl_rwlock);
8745
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
8746
NFSX_UNSIGNED);
8747
dp->nfsdl_stateid.seqid = *tl++;
8748
dp->nfsdl_stateid.other[0] = *tl++;
8749
dp->nfsdl_stateid.other[1] = *tl++;
8750
dp->nfsdl_stateid.other[2] = *tl++;
8751
ret = fxdr_unsigned(int, *tl);
8752
if (deleg == NFSV4OPEN_DELEGATEWRITE) {
8753
dp->nfsdl_flags = NFSCLDL_WRITE;
8754
/*
8755
* Indicates how much the file can grow.
8756
*/
8757
NFSM_DISSECT(tl, u_int32_t *,
8758
3 * NFSX_UNSIGNED);
8759
limitby = fxdr_unsigned(int, *tl++);
8760
switch (limitby) {
8761
case NFSV4OPEN_LIMITSIZE:
8762
dp->nfsdl_sizelimit = fxdr_hyper(tl);
8763
break;
8764
case NFSV4OPEN_LIMITBLOCKS:
8765
dp->nfsdl_sizelimit =
8766
fxdr_unsigned(u_int64_t, *tl++);
8767
dp->nfsdl_sizelimit *=
8768
fxdr_unsigned(u_int64_t, *tl);
8769
break;
8770
default:
8771
error = NFSERR_BADXDR;
8772
goto nfsmout;
8773
};
8774
} else {
8775
dp->nfsdl_flags = NFSCLDL_READ;
8776
}
8777
if (ret != 0)
8778
dp->nfsdl_flags |= NFSCLDL_RECALL;
8779
error = nfsrv_dissectace(nd, &dp->nfsdl_ace, false,
8780
&ret, &acesize);
8781
if (error != 0)
8782
goto nfsmout;
8783
} else if (deleg == NFSV4OPEN_DELEGATENONEEXT &&
8784
NFSHASNFSV4N(nmp)) {
8785
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
8786
deleg = fxdr_unsigned(uint32_t, *tl);
8787
if (deleg == NFSV4OPEN_CONTENTION ||
8788
deleg == NFSV4OPEN_RESOURCE)
8789
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
8790
} else if (deleg != NFSV4OPEN_DELEGATENONE) {
8791
error = NFSERR_BADXDR;
8792
goto nfsmout;
8793
}
8794
8795
/* Now, we should have the status for the SaveFH. */
8796
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8797
if (*++tl == 0) {
8798
NFSCL_DEBUG(4, "nfsrpc_createlayout SaveFH ok\n");
8799
/*
8800
* Now, process the GetFH and Getattr for the newly
8801
* created file. nfscl_mtofh() will set
8802
* ND_NOMOREDATA if these weren't successful.
8803
*/
8804
error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
8805
NFSCL_DEBUG(4, "aft nfscl_mtofh err=%d\n", error);
8806
if (error != 0)
8807
goto nfsmout;
8808
} else
8809
nd->nd_flag |= ND_NOMOREDATA;
8810
/* Now we have the PutFH and Getattr for the directory. */
8811
if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
8812
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
8813
if (*++tl != 0)
8814
nd->nd_flag |= ND_NOMOREDATA;
8815
else {
8816
NFSM_DISSECT(tl, uint32_t *, 2 *
8817
NFSX_UNSIGNED);
8818
if (*++tl != 0)
8819
nd->nd_flag |= ND_NOMOREDATA;
8820
}
8821
}
8822
if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
8823
/* Load the directory attributes. */
8824
error = nfsm_loadattr(nd, dnap);
8825
NFSCL_DEBUG(4, "aft nfsm_loadattr err=%d\n", error);
8826
if (error != 0)
8827
goto nfsmout;
8828
*dattrflagp = 1;
8829
if (dp != NULL && *attrflagp != 0) {
8830
dp->nfsdl_change = nnap->na_filerev;
8831
dp->nfsdl_modtime = nnap->na_mtime;
8832
dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
8833
}
8834
/*
8835
* We can now complete the Open state.
8836
*/
8837
nfhp = *nfhpp;
8838
if (dp != NULL) {
8839
dp->nfsdl_fhlen = nfhp->nfh_len;
8840
NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh,
8841
nfhp->nfh_len);
8842
}
8843
/*
8844
* Get an Open structure that will be
8845
* attached to the OpenOwner, acquired already.
8846
*/
8847
error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len,
8848
(NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
8849
cred, p, NULL, &op, &newone, NULL, 0, false);
8850
if (error != 0)
8851
goto nfsmout;
8852
op->nfso_stateid = stateid;
8853
newnfs_copyincred(cred, &op->nfso_cred);
8854
8855
nfscl_openrelease(nmp, op, error, newone);
8856
*unlockedp = 1;
8857
8858
/* Now, handle the RestoreFH and LayoutGet. */
8859
if (nd->nd_repstat == 0) {
8860
NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
8861
*laystatp = fxdr_unsigned(int, *(tl + 3));
8862
if (*laystatp == 0) {
8863
error = nfsrv_parselayoutget(nmp, nd,
8864
stateidp, retonclosep, flhp);
8865
if (error != 0)
8866
*laystatp = error;
8867
}
8868
NFSCL_DEBUG(4, "aft nfsrv_parselayout err=%d\n",
8869
error);
8870
} else
8871
nd->nd_repstat = 0;
8872
}
8873
}
8874
if (nd->nd_repstat != 0 && error == 0)
8875
error = nd->nd_repstat;
8876
if (error == NFSERR_STALECLIENTID)
8877
nfscl_initiate_recovery(owp->nfsow_clp);
8878
nfsmout:
8879
NFSCL_DEBUG(4, "eo nfsrpc_createlayout err=%d\n", error);
8880
if (error == 0)
8881
*dpp = dp;
8882
else
8883
free(dp, M_NFSCLDELEG);
8884
m_freem(nd->nd_mrep);
8885
return (error);
8886
}
8887
8888
/*
8889
* Similar to nfsrpc_getopenlayout(), except that it used for the Create case.
8890
*/
8891
static int
8892
nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
8893
nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
8894
struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
8895
struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
8896
int *dattrflagp, int *unlockedp)
8897
{
8898
struct nfscllayout *lyp;
8899
struct nfsclflayouthead flh;
8900
struct nfsfh *nfhp;
8901
struct nfsclsession *tsep;
8902
struct nfsmount *nmp;
8903
nfsv4stateid_t stateid;
8904
int error, layoutlen, layouttype, retonclose, laystat;
8905
8906
error = 0;
8907
nmp = VFSTONFS(dvp->v_mount);
8908
if (NFSHASFLEXFILE(nmp))
8909
layouttype = NFSLAYOUT_FLEXFILE;
8910
else
8911
layouttype = NFSLAYOUT_NFSV4_1_FILES;
8912
LIST_INIT(&flh);
8913
tsep = nfsmnt_mdssession(nmp);
8914
layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED);
8915
error = nfsrpc_createlayout(dvp, name, namelen, vap, cverf, fmode,
8916
owp, dpp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
8917
unlockedp, &stateid, 1, layouttype, layoutlen, &retonclose,
8918
&flh, &laystat);
8919
NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n",
8920
laystat, error);
8921
lyp = NULL;
8922
if (laystat == 0) {
8923
nfhp = *nfhpp;
8924
laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh,
8925
nfhp->nfh_len, &stateid, retonclose, NULL, &lyp, &flh,
8926
layouttype, laystat, NULL, cred, p);
8927
} else
8928
laystat = nfsrpc_layoutgetres(nmp, dvp, NULL, 0, &stateid,
8929
retonclose, NULL, &lyp, &flh, layouttype, laystat, NULL,
8930
cred, p);
8931
if (laystat == 0)
8932
nfscl_rellayout(lyp, 0);
8933
return (error);
8934
}
8935
8936
/*
8937
* Process the results of a layoutget() operation.
8938
*/
8939
static int
8940
nfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp,
8941
int newfhlen, nfsv4stateid_t *stateidp, int retonclose, uint32_t *notifybit,
8942
struct nfscllayout **lypp, struct nfsclflayouthead *flhp, int layouttype,
8943
int laystat, int *islockedp, struct ucred *cred, NFSPROC_T *p)
8944
{
8945
struct nfsclflayout *tflp;
8946
struct nfscldevinfo *dip;
8947
uint8_t *dev;
8948
int i, mirrorcnt;
8949
8950
if (laystat == NFSERR_UNKNLAYOUTTYPE) {
8951
NFSLOCKMNT(nmp);
8952
if (!NFSHASFLEXFILE(nmp)) {
8953
/* Switch to using Flex File Layout. */
8954
nmp->nm_state |= NFSSTA_FLEXFILE;
8955
} else if (layouttype == NFSLAYOUT_FLEXFILE) {
8956
/* Disable pNFS. */
8957
NFSCL_DEBUG(1, "disable PNFS\n");
8958
nmp->nm_state &= ~(NFSSTA_PNFS | NFSSTA_FLEXFILE);
8959
}
8960
NFSUNLOCKMNT(nmp);
8961
}
8962
if (laystat == 0) {
8963
NFSCL_DEBUG(4, "nfsrpc_layoutgetres at FOREACH\n");
8964
LIST_FOREACH(tflp, flhp, nfsfl_list) {
8965
if (layouttype == NFSLAYOUT_FLEXFILE)
8966
mirrorcnt = tflp->nfsfl_mirrorcnt;
8967
else
8968
mirrorcnt = 1;
8969
for (i = 0; i < mirrorcnt; i++) {
8970
laystat = nfscl_adddevinfo(nmp, NULL, i, tflp);
8971
NFSCL_DEBUG(4, "aft adddev=%d\n", laystat);
8972
if (laystat != 0) {
8973
if (layouttype == NFSLAYOUT_FLEXFILE)
8974
dev = tflp->nfsfl_ffm[i].dev;
8975
else
8976
dev = tflp->nfsfl_dev;
8977
laystat = nfsrpc_getdeviceinfo(nmp, dev,
8978
layouttype, notifybit, &dip, cred,
8979
p);
8980
NFSCL_DEBUG(4, "aft nfsrpc_gdi=%d\n",
8981
laystat);
8982
if (laystat != 0)
8983
goto out;
8984
laystat = nfscl_adddevinfo(nmp, dip, i,
8985
tflp);
8986
if (laystat != 0)
8987
printf("nfsrpc_layoutgetresout"
8988
": cannot add\n");
8989
}
8990
}
8991
}
8992
}
8993
out:
8994
if (laystat == 0) {
8995
/*
8996
* nfscl_layout() always returns with the nfsly_lock
8997
* set to a refcnt (shared lock).
8998
* Passing in dvp is sufficient, since it is only used to
8999
* get the fsid for the file system.
9000
*/
9001
laystat = nfscl_layout(nmp, vp, newfhp, newfhlen, stateidp,
9002
layouttype, retonclose, flhp, lypp, cred, p);
9003
NFSCL_DEBUG(4, "nfsrpc_layoutgetres: aft nfscl_layout=%d\n",
9004
laystat);
9005
if (laystat == 0 && islockedp != NULL)
9006
*islockedp = 1;
9007
}
9008
return (laystat);
9009
}
9010
9011
/*
9012
* nfs copy_file_range operation.
9013
*/
9014
int
9015
nfsrpc_copy_file_range(vnode_t invp, off_t *inoffp, vnode_t outvp,
9016
off_t *outoffp, size_t *lenp, unsigned int flags, int *inattrflagp,
9017
struct nfsvattr *innap, int *outattrflagp, struct nfsvattr *outnap,
9018
struct ucred *cred, bool consecutive, bool *must_commitp)
9019
{
9020
int commit, error, expireret = 0, retrycnt;
9021
u_int32_t clidrev = 0;
9022
struct nfsmount *nmp = VFSTONFS(invp->v_mount);
9023
struct nfsfh *innfhp = NULL, *outnfhp = NULL;
9024
nfsv4stateid_t instateid, outstateid;
9025
void *inlckp, *outlckp;
9026
9027
if (nmp->nm_clp != NULL)
9028
clidrev = nmp->nm_clp->nfsc_clientidrev;
9029
innfhp = VTONFS(invp)->n_fhp;
9030
outnfhp = VTONFS(outvp)->n_fhp;
9031
retrycnt = 0;
9032
do {
9033
/* Get both stateids. */
9034
inlckp = NULL;
9035
nfscl_getstateid(invp, innfhp->nfh_fh, innfhp->nfh_len,
9036
NFSV4OPEN_ACCESSREAD, 0, NULL, curthread, &instateid,
9037
&inlckp);
9038
outlckp = NULL;
9039
nfscl_getstateid(outvp, outnfhp->nfh_fh, outnfhp->nfh_len,
9040
NFSV4OPEN_ACCESSWRITE, 0, NULL, curthread, &outstateid,
9041
&outlckp);
9042
9043
error = nfsrpc_copyrpc(invp, *inoffp, outvp, *outoffp, lenp,
9044
&instateid, &outstateid, innap, inattrflagp, outnap,
9045
outattrflagp, consecutive, &commit, cred, curthread);
9046
if (error == 0) {
9047
if (commit != NFSWRITE_FILESYNC)
9048
*must_commitp = true;
9049
*inoffp += *lenp;
9050
*outoffp += *lenp;
9051
} else if (error == NFSERR_STALESTATEID)
9052
nfscl_initiate_recovery(nmp->nm_clp);
9053
if (inlckp != NULL)
9054
nfscl_lockderef(inlckp);
9055
if (outlckp != NULL)
9056
nfscl_lockderef(outlckp);
9057
if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
9058
error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
9059
error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
9060
(void) nfs_catnap(PZERO, error, "nfs_cfr");
9061
} else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) &&
9062
error == NFSERR_BADSTATEID)) && clidrev != 0) {
9063
expireret = nfscl_hasexpired(nmp->nm_clp, clidrev,
9064
curthread);
9065
} else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) {
9066
error = EIO;
9067
}
9068
retrycnt++;
9069
} while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
9070
error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
9071
error == NFSERR_STALEDONTRECOVER ||
9072
(error == NFSERR_OLDSTATEID && retrycnt < 20) ||
9073
((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
9074
expireret == 0 && clidrev != 0 && retrycnt < 4));
9075
if (error != 0 && (retrycnt >= 4 ||
9076
error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
9077
error == NFSERR_STALEDONTRECOVER))
9078
error = EIO;
9079
return (error);
9080
}
9081
9082
/*
9083
* The copy RPC.
9084
*/
9085
static int
9086
nfsrpc_copyrpc(vnode_t invp, off_t inoff, vnode_t outvp, off_t outoff,
9087
size_t *lenp, nfsv4stateid_t *instateidp, nfsv4stateid_t *outstateidp,
9088
struct nfsvattr *innap, int *inattrflagp, struct nfsvattr *outnap,
9089
int *outattrflagp, bool consecutive, int *commitp, struct ucred *cred,
9090
NFSPROC_T *p)
9091
{
9092
uint32_t *tl, *opcntp;
9093
int error;
9094
struct nfsrv_descript nfsd;
9095
struct nfsrv_descript *nd = &nfsd;
9096
struct nfsmount *nmp;
9097
nfsattrbit_t attrbits;
9098
struct vattr va;
9099
uint64_t len;
9100
9101
nmp = VFSTONFS(invp->v_mount);
9102
*inattrflagp = *outattrflagp = 0;
9103
*commitp = NFSWRITE_UNSTABLE;
9104
len = *lenp;
9105
*lenp = 0;
9106
if (len > nfs_maxcopyrange)
9107
len = nfs_maxcopyrange;
9108
nfscl_reqstart(nd, NFSPROC_COPY, nmp, VTONFS(invp)->n_fhp->nfh_fh,
9109
VTONFS(invp)->n_fhp->nfh_len, &opcntp, NULL, 0, 0, cred);
9110
/*
9111
* First do a Setattr of atime to the server's clock
9112
* time. The FreeBSD "collective" was of the opinion
9113
* that setting atime was necessary for this syscall.
9114
* Do the Setattr before the Copy, so that it can be
9115
* handled well if the server replies NFSERR_DELAY to
9116
* the Setattr operation.
9117
*/
9118
if ((nmp->nm_mountp->mnt_flag & MNT_NOATIME) == 0) {
9119
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
9120
*tl = txdr_unsigned(NFSV4OP_SETATTR);
9121
nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID);
9122
VATTR_NULL(&va);
9123
va.va_atime.tv_sec = va.va_atime.tv_nsec = 0;
9124
va.va_vaflags = VA_UTIMES_NULL;
9125
nfscl_fillsattr(nd, &va, invp, 0, 0);
9126
/* Bump opcnt from 7 to 8. */
9127
*opcntp = txdr_unsigned(8);
9128
}
9129
9130
/* Now Getattr the invp attributes. */
9131
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
9132
*tl = txdr_unsigned(NFSV4OP_GETATTR);
9133
NFSGETATTR_ATTRBIT(&attrbits);
9134
nfsrv_putattrbit(nd, &attrbits);
9135
9136
/* Set outvp. */
9137
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
9138
*tl = txdr_unsigned(NFSV4OP_PUTFH);
9139
(void)nfsm_fhtom(nmp, nd, VTONFS(outvp)->n_fhp->nfh_fh,
9140
VTONFS(outvp)->n_fhp->nfh_len, 0);
9141
9142
/* Do the Copy. */
9143
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
9144
*tl = txdr_unsigned(NFSV4OP_COPY);
9145
nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID);
9146
nfsm_stateidtom(nd, outstateidp, NFSSTATEID_PUTSTATEID);
9147
NFSM_BUILD(tl, uint32_t *, 3 * NFSX_HYPER + 4 * NFSX_UNSIGNED);
9148
txdr_hyper(inoff, tl); tl += 2;
9149
txdr_hyper(outoff, tl); tl += 2;
9150
txdr_hyper(len, tl); tl += 2;
9151
if (consecutive)
9152
*tl++ = newnfs_true;
9153
else
9154
*tl++ = newnfs_false;
9155
*tl++ = newnfs_true;
9156
*tl++ = 0;
9157
9158
/* Get the outvp attributes. */
9159
*tl = txdr_unsigned(NFSV4OP_GETATTR);
9160
NFSWRITEGETATTR_ATTRBIT(&attrbits);
9161
nfsrv_putattrbit(nd, &attrbits);
9162
9163
error = nfscl_request(nd, invp, p, cred);
9164
if (error != 0)
9165
return (error);
9166
/* Skip over the Setattr reply. */
9167
if ((nd->nd_flag & ND_NOMOREDATA) == 0 &&
9168
(nmp->nm_mountp->mnt_flag & MNT_NOATIME) == 0) {
9169
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
9170
if (*(tl + 1) == 0) {
9171
error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
9172
if (error != 0)
9173
goto nfsmout;
9174
} else
9175
nd->nd_flag |= ND_NOMOREDATA;
9176
}
9177
if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
9178
/* Get the input file's attributes. */
9179
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
9180
if (*(tl + 1) == 0) {
9181
error = nfsm_loadattr(nd, innap);
9182
if (error != 0)
9183
goto nfsmout;
9184
*inattrflagp = 1;
9185
} else
9186
nd->nd_flag |= ND_NOMOREDATA;
9187
}
9188
/* Skip over return stat for PutFH. */
9189
if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
9190
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
9191
if (*++tl != 0)
9192
nd->nd_flag |= ND_NOMOREDATA;
9193
}
9194
/* Skip over return stat for Copy. */
9195
if ((nd->nd_flag & ND_NOMOREDATA) == 0)
9196
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
9197
if (nd->nd_repstat == 0) {
9198
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
9199
if (*tl != 0) {
9200
/* There should be no callback ids. */
9201
error = NFSERR_BADXDR;
9202
goto nfsmout;
9203
}
9204
NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED +
9205
NFSX_VERF);
9206
len = fxdr_hyper(tl); tl += 2;
9207
*commitp = fxdr_unsigned(int, *tl++);
9208
NFSLOCKMNT(nmp);
9209
if (!NFSHASWRITEVERF(nmp)) {
9210
NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
9211
NFSSETWRITEVERF(nmp);
9212
} else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) {
9213
NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
9214
nd->nd_repstat = NFSERR_STALEWRITEVERF;
9215
}
9216
NFSUNLOCKMNT(nmp);
9217
tl += (NFSX_VERF / NFSX_UNSIGNED);
9218
if (nd->nd_repstat == 0 && *++tl != newnfs_true)
9219
/* Must be a synchronous copy. */
9220
nd->nd_repstat = NFSERR_NOTSUPP;
9221
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
9222
error = nfsm_loadattr(nd, outnap);
9223
if (error == 0)
9224
*outattrflagp = NFS_LATTR_NOSHRINK;
9225
if (nd->nd_repstat == 0)
9226
*lenp = len;
9227
} else if (nd->nd_repstat == NFSERR_OFFLOADNOREQS) {
9228
/*
9229
* For the case where consecutive is not supported, but
9230
* synchronous is supported, we can try consecutive == false
9231
* by returning this error. Otherwise, return NFSERR_NOTSUPP,
9232
* since Copy cannot be done.
9233
*/
9234
if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
9235
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
9236
if (!consecutive || *++tl == newnfs_false)
9237
nd->nd_repstat = NFSERR_NOTSUPP;
9238
} else
9239
nd->nd_repstat = NFSERR_BADXDR;
9240
}
9241
if (error == 0)
9242
error = nd->nd_repstat;
9243
nfsmout:
9244
m_freem(nd->nd_mrep);
9245
return (error);
9246
}
9247
9248
/*
9249
* nfs clone operation.
9250
*/
9251
int
9252
nfsrpc_clone(vnode_t invp, off_t *inoffp, vnode_t outvp,
9253
off_t *outoffp, size_t *lenp, bool toeof, int *inattrflagp,
9254
struct nfsvattr *innap, int *outattrflagp, struct nfsvattr *outnap,
9255
struct ucred *cred)
9256
{
9257
int error, expireret = 0, retrycnt;
9258
uint32_t clidrev = 0;
9259
struct nfsmount *nmp = VFSTONFS(invp->v_mount);
9260
struct nfsfh *innfhp = NULL, *outnfhp = NULL;
9261
nfsv4stateid_t instateid, outstateid;
9262
void *inlckp, *outlckp;
9263
9264
if (nmp->nm_clp != NULL)
9265
clidrev = nmp->nm_clp->nfsc_clientidrev;
9266
innfhp = VTONFS(invp)->n_fhp;
9267
outnfhp = VTONFS(outvp)->n_fhp;
9268
retrycnt = 0;
9269
do {
9270
/* Get both stateids. */
9271
inlckp = NULL;
9272
nfscl_getstateid(invp, innfhp->nfh_fh, innfhp->nfh_len,
9273
NFSV4OPEN_ACCESSREAD, 0, NULL, curthread, &instateid,
9274
&inlckp);
9275
outlckp = NULL;
9276
nfscl_getstateid(outvp, outnfhp->nfh_fh, outnfhp->nfh_len,
9277
NFSV4OPEN_ACCESSWRITE, 0, NULL, curthread, &outstateid,
9278
&outlckp);
9279
9280
error = nfsrpc_clonerpc(invp, *inoffp, outvp, *outoffp, lenp,
9281
toeof, &instateid, &outstateid, innap, inattrflagp, outnap,
9282
outattrflagp, cred, curthread);
9283
if (error == 0) {
9284
*inoffp += *lenp;
9285
*outoffp += *lenp;
9286
} else if (error == NFSERR_STALESTATEID)
9287
nfscl_initiate_recovery(nmp->nm_clp);
9288
if (inlckp != NULL)
9289
nfscl_lockderef(inlckp);
9290
if (outlckp != NULL)
9291
nfscl_lockderef(outlckp);
9292
if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
9293
error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
9294
error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
9295
(void) nfs_catnap(PZERO, error, "nfs_cfr");
9296
} else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) &&
9297
error == NFSERR_BADSTATEID)) && clidrev != 0) {
9298
expireret = nfscl_hasexpired(nmp->nm_clp, clidrev,
9299
curthread);
9300
} else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) {
9301
error = EIO;
9302
}
9303
retrycnt++;
9304
} while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
9305
error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
9306
error == NFSERR_STALEDONTRECOVER ||
9307
(error == NFSERR_OLDSTATEID && retrycnt < 20) ||
9308
((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
9309
expireret == 0 && clidrev != 0 && retrycnt < 4));
9310
if (error != 0 && (retrycnt >= 4 ||
9311
error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
9312
error == NFSERR_STALEDONTRECOVER))
9313
error = EIO;
9314
return (error);
9315
}
9316
9317
/*
9318
* The clone RPC.
9319
*/
9320
static int
9321
nfsrpc_clonerpc(vnode_t invp, off_t inoff, vnode_t outvp, off_t outoff,
9322
size_t *lenp, bool toeof, nfsv4stateid_t *instateidp,
9323
nfsv4stateid_t *outstateidp, struct nfsvattr *innap, int *inattrflagp,
9324
struct nfsvattr *outnap, int *outattrflagp, struct ucred *cred,
9325
NFSPROC_T *p)
9326
{
9327
uint32_t *tl, *opcntp;
9328
int error;
9329
struct nfsrv_descript nfsd;
9330
struct nfsrv_descript *nd = &nfsd;
9331
struct nfsmount *nmp;
9332
nfsattrbit_t attrbits;
9333
struct vattr va;
9334
uint64_t len;
9335
9336
nmp = VFSTONFS(invp->v_mount);
9337
*inattrflagp = *outattrflagp = 0;
9338
len = *lenp;
9339
if (len == 0)
9340
return (0);
9341
if (toeof)
9342
len = 0;
9343
nfscl_reqstart(nd, NFSPROC_CLONE, nmp, VTONFS(invp)->n_fhp->nfh_fh,
9344
VTONFS(invp)->n_fhp->nfh_len, &opcntp, NULL, 0, 0, cred);
9345
/*
9346
* First do a Setattr of atime to the server's clock
9347
* time. The FreeBSD "collective" was of the opinion
9348
* that setting atime was necessary for this syscall.
9349
* Do the Setattr before the Clone, so that it can be
9350
* handled well if the server replies NFSERR_DELAY to
9351
* the Setattr operation.
9352
*/
9353
if ((nmp->nm_mountp->mnt_flag & MNT_NOATIME) == 0) {
9354
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
9355
*tl = txdr_unsigned(NFSV4OP_SETATTR);
9356
nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID);
9357
VATTR_NULL(&va);
9358
va.va_atime.tv_sec = va.va_atime.tv_nsec = 0;
9359
va.va_vaflags = VA_UTIMES_NULL;
9360
nfscl_fillsattr(nd, &va, invp, 0, 0);
9361
/* Bump opcnt from 7 to 8. */
9362
*opcntp = txdr_unsigned(8);
9363
}
9364
9365
/* Now Getattr the invp attributes. */
9366
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
9367
*tl = txdr_unsigned(NFSV4OP_GETATTR);
9368
NFSGETATTR_ATTRBIT(&attrbits);
9369
nfsrv_putattrbit(nd, &attrbits);
9370
9371
/* Set outvp. */
9372
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
9373
*tl = txdr_unsigned(NFSV4OP_PUTFH);
9374
(void)nfsm_fhtom(nmp, nd, VTONFS(outvp)->n_fhp->nfh_fh,
9375
VTONFS(outvp)->n_fhp->nfh_len, 0);
9376
9377
/* Do the Clone. */
9378
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
9379
*tl = txdr_unsigned(NFSV4OP_CLONE);
9380
nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID);
9381
nfsm_stateidtom(nd, outstateidp, NFSSTATEID_PUTSTATEID);
9382
NFSM_BUILD(tl, uint32_t *, 3 * NFSX_HYPER + NFSX_UNSIGNED);
9383
txdr_hyper(inoff, tl); tl += 2;
9384
txdr_hyper(outoff, tl); tl += 2;
9385
txdr_hyper(len, tl); tl += 2;
9386
9387
/* Get the outvp attributes. */
9388
*tl = txdr_unsigned(NFSV4OP_GETATTR);
9389
NFSWRITEGETATTR_ATTRBIT(&attrbits);
9390
nfsrv_putattrbit(nd, &attrbits);
9391
9392
error = nfscl_request(nd, invp, p, cred);
9393
if (error != 0)
9394
return (error);
9395
/* Skip over the Setattr reply. */
9396
if ((nd->nd_flag & ND_NOMOREDATA) == 0 &&
9397
(nmp->nm_mountp->mnt_flag & MNT_NOATIME) == 0) {
9398
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
9399
if (*(tl + 1) == 0) {
9400
error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
9401
if (error != 0)
9402
goto nfsmout;
9403
} else
9404
nd->nd_flag |= ND_NOMOREDATA;
9405
}
9406
if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
9407
/* Get the input file's attributes. */
9408
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
9409
if (*(tl + 1) == 0) {
9410
error = nfsm_loadattr(nd, innap);
9411
if (error != 0)
9412
goto nfsmout;
9413
*inattrflagp = 1;
9414
} else
9415
nd->nd_flag |= ND_NOMOREDATA;
9416
}
9417
/* Skip over return stat for PutFH. */
9418
if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
9419
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
9420
if (*++tl != 0)
9421
nd->nd_flag |= ND_NOMOREDATA;
9422
}
9423
/* Skip over return stat for Clone. */
9424
if ((nd->nd_flag & ND_NOMOREDATA) == 0)
9425
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
9426
if (nd->nd_repstat == 0) {
9427
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
9428
error = nfsm_loadattr(nd, outnap);
9429
if (error == 0)
9430
*outattrflagp = NFS_LATTR_NOSHRINK;
9431
} else {
9432
*lenp = 0;
9433
}
9434
if (error == 0)
9435
error = nd->nd_repstat;
9436
nfsmout:
9437
m_freem(nd->nd_mrep);
9438
return (error);
9439
}
9440
9441
/*
9442
* Seek operation.
9443
*/
9444
int
9445
nfsrpc_seek(vnode_t vp, off_t *offp, bool *eofp, int content,
9446
struct ucred *cred, struct nfsvattr *nap, int *attrflagp)
9447
{
9448
int error, expireret = 0, retrycnt;
9449
u_int32_t clidrev = 0;
9450
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
9451
struct nfsnode *np = VTONFS(vp);
9452
struct nfsfh *nfhp = NULL;
9453
nfsv4stateid_t stateid;
9454
void *lckp;
9455
9456
if (nmp->nm_clp != NULL)
9457
clidrev = nmp->nm_clp->nfsc_clientidrev;
9458
nfhp = np->n_fhp;
9459
retrycnt = 0;
9460
do {
9461
lckp = NULL;
9462
nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
9463
NFSV4OPEN_ACCESSREAD, 0, cred, curthread, &stateid, &lckp);
9464
error = nfsrpc_seekrpc(vp, offp, &stateid, eofp, content,
9465
nap, attrflagp, cred);
9466
if (error == NFSERR_STALESTATEID)
9467
nfscl_initiate_recovery(nmp->nm_clp);
9468
if (lckp != NULL)
9469
nfscl_lockderef(lckp);
9470
if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
9471
error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
9472
error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
9473
(void) nfs_catnap(PZERO, error, "nfs_seek");
9474
} else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) &&
9475
error == NFSERR_BADSTATEID)) && clidrev != 0) {
9476
expireret = nfscl_hasexpired(nmp->nm_clp, clidrev,
9477
curthread);
9478
} else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) {
9479
error = EIO;
9480
}
9481
retrycnt++;
9482
} while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
9483
error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
9484
error == NFSERR_BADSESSION ||
9485
(error == NFSERR_OLDSTATEID && retrycnt < 20) ||
9486
((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
9487
expireret == 0 && clidrev != 0 && retrycnt < 4) ||
9488
(error == NFSERR_OPENMODE && retrycnt < 4));
9489
if (error && retrycnt >= 4)
9490
error = EIO;
9491
return (error);
9492
}
9493
9494
/*
9495
* The seek RPC.
9496
*/
9497
static int
9498
nfsrpc_seekrpc(vnode_t vp, off_t *offp, nfsv4stateid_t *stateidp, bool *eofp,
9499
int content, struct nfsvattr *nap, int *attrflagp, struct ucred *cred)
9500
{
9501
uint32_t *tl;
9502
int error;
9503
struct nfsrv_descript nfsd;
9504
struct nfsrv_descript *nd = &nfsd;
9505
nfsattrbit_t attrbits;
9506
9507
*attrflagp = 0;
9508
NFSCL_REQSTART(nd, NFSPROC_SEEK, vp, cred);
9509
nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
9510
NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
9511
txdr_hyper(*offp, tl); tl += 2;
9512
*tl++ = txdr_unsigned(content);
9513
*tl = txdr_unsigned(NFSV4OP_GETATTR);
9514
NFSGETATTR_ATTRBIT(&attrbits);
9515
nfsrv_putattrbit(nd, &attrbits);
9516
error = nfscl_request(nd, vp, curthread, cred);
9517
if (error != 0)
9518
return (error);
9519
if (nd->nd_repstat == 0) {
9520
NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_HYPER);
9521
if (*tl++ == newnfs_true)
9522
*eofp = true;
9523
else
9524
*eofp = false;
9525
*offp = fxdr_hyper(tl);
9526
/* Just skip over Getattr op status. */
9527
error = nfsm_loadattr(nd, nap);
9528
if (error == 0)
9529
*attrflagp = 1;
9530
}
9531
error = nd->nd_repstat;
9532
nfsmout:
9533
m_freem(nd->nd_mrep);
9534
return (error);
9535
}
9536
9537
/*
9538
* The getextattr RPC.
9539
*/
9540
int
9541
nfsrpc_getextattr(vnode_t vp, const char *name, struct uio *uiop, ssize_t *lenp,
9542
struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p)
9543
{
9544
uint32_t *tl;
9545
int error;
9546
struct nfsrv_descript nfsd;
9547
struct nfsrv_descript *nd = &nfsd;
9548
nfsattrbit_t attrbits;
9549
uint32_t len, len2;
9550
9551
*attrflagp = 0;
9552
NFSCL_REQSTART(nd, NFSPROC_GETEXTATTR, vp, cred);
9553
nfsm_strtom(nd, name, strlen(name));
9554
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
9555
*tl = txdr_unsigned(NFSV4OP_GETATTR);
9556
NFSGETATTR_ATTRBIT(&attrbits);
9557
nfsrv_putattrbit(nd, &attrbits);
9558
error = nfscl_request(nd, vp, p, cred);
9559
if (error != 0)
9560
return (error);
9561
if (nd->nd_repstat == 0) {
9562
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
9563
len = fxdr_unsigned(uint32_t, *tl);
9564
/* Sanity check lengths. */
9565
if (uiop != NULL && len > 0 && len <= IOSIZE_MAX &&
9566
uiop->uio_resid <= UINT32_MAX) {
9567
len2 = uiop->uio_resid;
9568
if (len2 >= len)
9569
error = nfsm_mbufuio(nd, uiop, len);
9570
else {
9571
error = nfsm_mbufuio(nd, uiop, len2);
9572
if (error == 0) {
9573
/*
9574
* nfsm_mbufuio() advances to a multiple
9575
* of 4, so round up len2 as well. Then
9576
* we need to advance over the rest of
9577
* the data, rounding up the remaining
9578
* length.
9579
*/
9580
len2 = NFSM_RNDUP(len2);
9581
len2 = NFSM_RNDUP(len - len2);
9582
if (len2 > 0)
9583
error = nfsm_advance(nd, len2,
9584
-1);
9585
}
9586
}
9587
} else if (uiop == NULL && len > 0) {
9588
/* Just wants the length and not the data. */
9589
error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
9590
} else if (len > 0)
9591
error = ENOATTR;
9592
if (error != 0)
9593
goto nfsmout;
9594
*lenp = len;
9595
/* Just skip over Getattr op status. */
9596
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
9597
error = nfsm_loadattr(nd, nap);
9598
if (error == 0)
9599
*attrflagp = 1;
9600
}
9601
if (error == 0)
9602
error = nd->nd_repstat;
9603
nfsmout:
9604
m_freem(nd->nd_mrep);
9605
return (error);
9606
}
9607
9608
/*
9609
* The setextattr RPC.
9610
*/
9611
int
9612
nfsrpc_setextattr(vnode_t vp, const char *name, struct uio *uiop,
9613
struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p)
9614
{
9615
uint32_t *tl;
9616
int error;
9617
struct nfsrv_descript nfsd;
9618
struct nfsrv_descript *nd = &nfsd;
9619
nfsattrbit_t attrbits;
9620
9621
*attrflagp = 0;
9622
NFSCL_REQSTART(nd, NFSPROC_SETEXTATTR, vp, cred);
9623
if (uiop->uio_resid > nd->nd_maxreq) {
9624
/* nd_maxreq is set by NFSCL_REQSTART(). */
9625
m_freem(nd->nd_mreq);
9626
return (EINVAL);
9627
}
9628
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
9629
*tl = txdr_unsigned(NFSV4SXATTR_EITHER);
9630
nfsm_strtom(nd, name, strlen(name));
9631
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
9632
*tl = txdr_unsigned(uiop->uio_resid);
9633
error = nfsm_uiombuf(nd, uiop, uiop->uio_resid);
9634
if (error != 0) {
9635
m_freem(nd->nd_mreq);
9636
return (error);
9637
}
9638
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
9639
*tl = txdr_unsigned(NFSV4OP_GETATTR);
9640
NFSGETATTR_ATTRBIT(&attrbits);
9641
nfsrv_putattrbit(nd, &attrbits);
9642
error = nfscl_request(nd, vp, p, cred);
9643
if (error != 0)
9644
return (error);
9645
if (nd->nd_repstat == 0) {
9646
/* Just skip over the reply and Getattr op status. */
9647
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 3 *
9648
NFSX_UNSIGNED);
9649
error = nfsm_loadattr(nd, nap);
9650
if (error == 0)
9651
*attrflagp = 1;
9652
}
9653
if (error == 0)
9654
error = nd->nd_repstat;
9655
nfsmout:
9656
m_freem(nd->nd_mrep);
9657
return (error);
9658
}
9659
9660
/*
9661
* The removeextattr RPC.
9662
*/
9663
int
9664
nfsrpc_rmextattr(vnode_t vp, const char *name, struct nfsvattr *nap,
9665
int *attrflagp, struct ucred *cred, NFSPROC_T *p)
9666
{
9667
uint32_t *tl;
9668
int error;
9669
struct nfsrv_descript nfsd;
9670
struct nfsrv_descript *nd = &nfsd;
9671
nfsattrbit_t attrbits;
9672
9673
*attrflagp = 0;
9674
NFSCL_REQSTART(nd, NFSPROC_RMEXTATTR, vp, cred);
9675
nfsm_strtom(nd, name, strlen(name));
9676
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
9677
*tl = txdr_unsigned(NFSV4OP_GETATTR);
9678
NFSGETATTR_ATTRBIT(&attrbits);
9679
nfsrv_putattrbit(nd, &attrbits);
9680
error = nfscl_request(nd, vp, p, cred);
9681
if (error != 0)
9682
return (error);
9683
if (nd->nd_repstat == 0) {
9684
/* Just skip over the reply and Getattr op status. */
9685
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 3 *
9686
NFSX_UNSIGNED);
9687
error = nfsm_loadattr(nd, nap);
9688
if (error == 0)
9689
*attrflagp = 1;
9690
}
9691
if (error == 0)
9692
error = nd->nd_repstat;
9693
nfsmout:
9694
m_freem(nd->nd_mrep);
9695
return (error);
9696
}
9697
9698
/*
9699
* The listextattr RPC.
9700
*/
9701
int
9702
nfsrpc_listextattr(vnode_t vp, uint64_t *cookiep, struct uio *uiop,
9703
size_t *lenp, bool *eofp, struct nfsvattr *nap, int *attrflagp,
9704
struct ucred *cred, NFSPROC_T *p)
9705
{
9706
uint32_t *tl;
9707
int cnt, error, i, len;
9708
struct nfsrv_descript nfsd;
9709
struct nfsrv_descript *nd = &nfsd;
9710
nfsattrbit_t attrbits;
9711
u_char c;
9712
9713
*attrflagp = 0;
9714
NFSCL_REQSTART(nd, NFSPROC_LISTEXTATTR, vp, cred);
9715
NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
9716
txdr_hyper(*cookiep, tl); tl += 2;
9717
*tl++ = txdr_unsigned(*lenp);
9718
*tl = txdr_unsigned(NFSV4OP_GETATTR);
9719
NFSGETATTR_ATTRBIT(&attrbits);
9720
nfsrv_putattrbit(nd, &attrbits);
9721
error = nfscl_request(nd, vp, p, cred);
9722
if (error != 0)
9723
return (error);
9724
*eofp = true;
9725
*lenp = 0;
9726
if (nd->nd_repstat == 0) {
9727
NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
9728
*cookiep = fxdr_hyper(tl); tl += 2;
9729
cnt = fxdr_unsigned(int, *tl);
9730
if (cnt < 0) {
9731
error = EBADRPC;
9732
goto nfsmout;
9733
}
9734
for (i = 0; i < cnt; i++) {
9735
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
9736
len = fxdr_unsigned(int, *tl);
9737
if (len <= 0 || len > EXTATTR_MAXNAMELEN) {
9738
error = EBADRPC;
9739
goto nfsmout;
9740
}
9741
if (uiop == NULL)
9742
error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
9743
else if (uiop->uio_resid >= len + 1) {
9744
c = len;
9745
error = uiomove(&c, sizeof(c), uiop);
9746
if (error == 0)
9747
error = nfsm_mbufuio(nd, uiop, len);
9748
} else {
9749
error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
9750
*eofp = false;
9751
}
9752
if (error != 0)
9753
goto nfsmout;
9754
*lenp += (len + 1);
9755
}
9756
/* Get the eof and skip over the Getattr op status. */
9757
NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
9758
/*
9759
* *eofp is set false above, because it wasn't able to copy
9760
* all of the reply.
9761
*/
9762
if (*eofp && *tl == 0)
9763
*eofp = false;
9764
error = nfsm_loadattr(nd, nap);
9765
if (error == 0)
9766
*attrflagp = 1;
9767
}
9768
if (error == 0)
9769
error = nd->nd_repstat;
9770
nfsmout:
9771
m_freem(nd->nd_mrep);
9772
return (error);
9773
}
9774
9775
/*
9776
* Split an mbuf list. For non-M_EXTPG mbufs, just use m_split().
9777
*/
9778
static struct mbuf *
9779
nfsm_split(struct mbuf *mp, uint64_t xfer)
9780
{
9781
struct mbuf *m, *m2;
9782
vm_page_t pg;
9783
int i, j, left, pgno, plen, trim;
9784
char *cp, *cp2;
9785
9786
if ((mp->m_flags & M_EXTPG) == 0) {
9787
m = m_split(mp, xfer, M_WAITOK);
9788
return (m);
9789
}
9790
9791
/* Find the correct mbuf to split at. */
9792
for (m = mp; m != NULL && xfer > m->m_len; m = m->m_next)
9793
xfer -= m->m_len;
9794
if (m == NULL)
9795
return (NULL);
9796
9797
/* If xfer == m->m_len, we can just split the mbuf list. */
9798
if (xfer == m->m_len) {
9799
m2 = m->m_next;
9800
m->m_next = NULL;
9801
return (m2);
9802
}
9803
9804
/* Find the page to split at. */
9805
pgno = 0;
9806
left = xfer;
9807
do {
9808
if (pgno == 0)
9809
plen = m_epg_pagelen(m, 0, m->m_epg_1st_off);
9810
else
9811
plen = m_epg_pagelen(m, pgno, 0);
9812
if (left <= plen)
9813
break;
9814
left -= plen;
9815
pgno++;
9816
} while (pgno < m->m_epg_npgs);
9817
if (pgno == m->m_epg_npgs)
9818
panic("nfsm_split: erroneous ext_pgs mbuf");
9819
9820
m2 = mb_alloc_ext_pgs(M_WAITOK, mb_free_mext_pgs, 0);
9821
m2->m_epg_flags |= EPG_FLAG_ANON;
9822
9823
/*
9824
* If left < plen, allocate a new page for the new mbuf
9825
* and copy the data after left in the page to this new
9826
* page.
9827
*/
9828
if (left < plen) {
9829
pg = vm_page_alloc_noobj(VM_ALLOC_WAITOK | VM_ALLOC_NODUMP |
9830
VM_ALLOC_WIRED);
9831
m2->m_epg_pa[0] = VM_PAGE_TO_PHYS(pg);
9832
m2->m_epg_npgs = 1;
9833
9834
/* Copy the data after left to the new page. */
9835
trim = plen - left;
9836
cp = (char *)(void *)PHYS_TO_DMAP(m->m_epg_pa[pgno]);
9837
if (pgno == 0)
9838
cp += m->m_epg_1st_off;
9839
cp += left;
9840
cp2 = (char *)(void *)PHYS_TO_DMAP(m2->m_epg_pa[0]);
9841
if (pgno == m->m_epg_npgs - 1)
9842
m2->m_epg_last_len = trim;
9843
else {
9844
cp2 += PAGE_SIZE - trim;
9845
m2->m_epg_1st_off = PAGE_SIZE - trim;
9846
m2->m_epg_last_len = m->m_epg_last_len;
9847
}
9848
memcpy(cp2, cp, trim);
9849
m2->m_len = trim;
9850
} else {
9851
m2->m_len = 0;
9852
m2->m_epg_last_len = m->m_epg_last_len;
9853
}
9854
9855
/* Move the pages beyond pgno to the new mbuf. */
9856
for (i = pgno + 1, j = m2->m_epg_npgs; i < m->m_epg_npgs; i++, j++) {
9857
m2->m_epg_pa[j] = m->m_epg_pa[i];
9858
/* Never moves page 0. */
9859
m2->m_len += m_epg_pagelen(m, i, 0);
9860
}
9861
m2->m_epg_npgs = j;
9862
m->m_epg_npgs = pgno + 1;
9863
m->m_epg_last_len = left;
9864
m->m_len = xfer;
9865
9866
m2->m_next = m->m_next;
9867
m->m_next = NULL;
9868
return (m2);
9869
}
9870
9871
/*
9872
* Do the NFSv4.1 Bind Connection to Session.
9873
* Called from the reconnect layer of the krpc (sys/rpc/clnt_rc.c).
9874
*/
9875
void
9876
nfsrpc_bindconnsess(CLIENT *cl, void *arg, struct ucred *cr)
9877
{
9878
struct nfscl_reconarg *rcp = (struct nfscl_reconarg *)arg;
9879
uint32_t res, *tl;
9880
struct nfsrv_descript nfsd;
9881
struct nfsrv_descript *nd = &nfsd;
9882
struct rpc_callextra ext;
9883
struct timeval utimeout;
9884
enum clnt_stat stat;
9885
int error;
9886
9887
nfscl_reqstart(nd, NFSPROC_BINDCONNTOSESS, NULL, NULL, 0, NULL, NULL,
9888
NFS_VER4, rcp->minorvers, NULL);
9889
NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
9890
memcpy(tl, rcp->sessionid, NFSX_V4SESSIONID);
9891
tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
9892
*tl++ = txdr_unsigned(NFSCDFC4_FORE_OR_BOTH);
9893
*tl = newnfs_false;
9894
9895
memset(&ext, 0, sizeof(ext));
9896
utimeout.tv_sec = 30;
9897
utimeout.tv_usec = 0;
9898
ext.rc_auth = authunix_create(cr);
9899
nd->nd_mrep = NULL;
9900
stat = CLNT_CALL_MBUF(cl, &ext, NFSV4PROC_COMPOUND, nd->nd_mreq,
9901
&nd->nd_mrep, utimeout);
9902
AUTH_DESTROY(ext.rc_auth);
9903
if (stat != RPC_SUCCESS) {
9904
printf("nfsrpc_bindconnsess: call failed stat=%d\n", stat);
9905
return;
9906
}
9907
if (nd->nd_mrep == NULL) {
9908
printf("nfsrpc_bindconnsess: no reply args\n");
9909
return;
9910
}
9911
error = 0;
9912
newnfs_realign(&nd->nd_mrep, M_WAITOK);
9913
nd->nd_md = nd->nd_mrep;
9914
nd->nd_dpos = mtod(nd->nd_md, char *);
9915
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
9916
nd->nd_repstat = fxdr_unsigned(uint32_t, *tl++);
9917
if (nd->nd_repstat == NFSERR_OK) {
9918
res = fxdr_unsigned(uint32_t, *tl);
9919
if (res > 0 && (error = nfsm_advance(nd, NFSM_RNDUP(res),
9920
-1)) != 0)
9921
goto nfsmout;
9922
NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
9923
4 * NFSX_UNSIGNED);
9924
tl += 3;
9925
if (!NFSBCMP(tl, rcp->sessionid, NFSX_V4SESSIONID)) {
9926
tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
9927
res = fxdr_unsigned(uint32_t, *tl);
9928
if (res != NFSCDFS4_BOTH)
9929
printf("nfsrpc_bindconnsess: did not "
9930
"return FS4_BOTH\n");
9931
} else
9932
printf("nfsrpc_bindconnsess: not same "
9933
"sessionid\n");
9934
} else if (nd->nd_repstat != NFSERR_BADSESSION)
9935
printf("nfsrpc_bindconnsess: returned %d\n", nd->nd_repstat);
9936
nfsmout:
9937
if (error != 0)
9938
printf("nfsrpc_bindconnsess: reply bad xdr\n");
9939
m_freem(nd->nd_mrep);
9940
}
9941
9942
/*
9943
* nfs opeattr rpc
9944
*/
9945
int
9946
nfsrpc_openattr(struct nfsmount *nmp, struct vnode *vp, uint8_t *fhp, int fhlen,
9947
bool createit, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap,
9948
struct nfsfh **nfhpp, int *attrflagp)
9949
{
9950
uint32_t *tl;
9951
struct nfsrv_descript nfsd, *nd = &nfsd;
9952
nfsattrbit_t attrbits;
9953
int error = 0;
9954
9955
*attrflagp = 0;
9956
nfscl_reqstart(nd, NFSPROC_OPENATTR, nmp, fhp, fhlen, NULL, NULL, 0, 0,
9957
cred);
9958
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
9959
if (createit)
9960
*tl = newnfs_true;
9961
else
9962
*tl = newnfs_false;
9963
NFSGETATTR_ATTRBIT(&attrbits);
9964
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
9965
*tl++ = txdr_unsigned(NFSV4OP_GETFH);
9966
*tl = txdr_unsigned(NFSV4OP_GETATTR);
9967
(void)nfsrv_putattrbit(nd, &attrbits);
9968
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
9969
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
9970
if (error != 0)
9971
return (error);
9972
if (nd->nd_repstat == 0) {
9973
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
9974
error = nfsm_getfh(nd, nfhpp);
9975
if (error != 0)
9976
goto nfsmout;
9977
error = nfscl_postop_attr(nd, nap, attrflagp);
9978
}
9979
nfsmout:
9980
m_freem(nd->nd_mrep);
9981
if (error == 0 && nd->nd_repstat != 0)
9982
error = nd->nd_repstat;
9983
return (error);
9984
}
9985
9986
/*
9987
* Do roughly what nfs_statfs() does for NFSv4, but when called with a shared
9988
* locked vnode.
9989
*/
9990
static void
9991
nfscl_statfs(struct vnode *vp, struct ucred *cred, NFSPROC_T *td)
9992
{
9993
struct nfsvattr nfsva;
9994
struct nfsfsinfo fs;
9995
struct nfsstatfs sb;
9996
struct mount *mp;
9997
struct nfsmount *nmp;
9998
uint32_t clone_blksize, lease;
9999
int attrflag, error;
10000
10001
mp = vp->v_mount;
10002
nmp = VFSTONFS(mp);
10003
error = nfsrpc_statfs(vp, &sb, &fs, &lease, &clone_blksize, cred, td,
10004
&nfsva, &attrflag);
10005
if (attrflag != 0)
10006
(void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1);
10007
if (error == 0) {
10008
NFSLOCKCLSTATE();
10009
if (nmp->nm_clp != NULL)
10010
nmp->nm_clp->nfsc_renew = NFSCL_RENEW(lease);
10011
NFSUNLOCKCLSTATE();
10012
mtx_lock(&nmp->nm_mtx);
10013
nfscl_loadfsinfo(nmp, &fs, clone_blksize);
10014
nfscl_loadsbinfo(nmp, &sb, &mp->mnt_stat);
10015
mp->mnt_stat.f_iosize = newnfs_iosize(nmp);
10016
mtx_unlock(&nmp->nm_mtx);
10017
}
10018
}
10019
10020