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