nfs_clrpcops.c 269 KB
Newer Older
1
/*-
2
3
 * SPDX-License-Identifier: BSD-3-Clause
 *
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 * Copyright (c) 1989, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Rick Macklem at The University of Guelph.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
Warner Losh's avatar
Warner Losh committed
18
 * 3. Neither the name of the University nor the names of its contributors
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

/*
 * Rpc op calls, generally called from the vnode op calls or through the
 * buffer cache, for NFS v2, 3 and 4.
 * These do not normally make any changes to vnode arguments or use
 * structures that might change between the VFS variants. The returned
 * arguments are all at the end, after the NFSPROC_T *p one.
 */

47
48
#include "opt_inet6.h"

49
#include <fs/nfs/nfsport.h>
50
51
#include <fs/nfsclient/nfs.h>
#include <sys/extattr.h>
52
#include <sys/sysctl.h>
53
#include <sys/taskqueue.h>
54
55
56
57
58
59

SYSCTL_DECL(_vfs_nfs);

static int	nfsignore_eexist = 0;
SYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW,
    &nfsignore_eexist, 0, "NFS ignore EEXIST replies for mkdir/symlink");
60

61
62
63
64
static int	nfscl_dssameconn = 0;
SYSCTL_INT(_vfs_nfs, OID_AUTO, dssameconn, CTLFLAG_RW,
    &nfscl_dssameconn, 0, "Use same TCP connection to multiple DSs");

65
66
67
68
static uint64_t nfs_maxcopyrange = SSIZE_MAX;
SYSCTL_U64(_vfs_nfs, OID_AUTO, maxcopyrange, CTLFLAG_RW,
    &nfs_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable");

69
70
71
/*
 * Global variables
 */
72
extern struct nfsstatsv1 nfsstatsv1;
73
74
75
76
77
78
extern int nfs_numnfscbd;
extern struct timeval nfsboottime;
extern u_int32_t newnfs_false, newnfs_true;
extern nfstype nfsv34_type[9];
extern int nfsrv_useacl;
extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
79
extern int nfscl_debuglevel;
80
extern int nfs_pnfsiothreads;
81
extern u_long sb_max_adj;
82
83
84
85
86
87
88
NFSCLSTATEMUTEX;
int nfstest_outofseq = 0;
int nfscl_assumeposixlocks = 1;
int nfscl_enablecallb = 0;
short nfsv4_cbport = NFSV4_CBPORT;
int nfstest_openallsetattr = 0;

89
#define	DIRHDSIZ	offsetof(struct dirent, d_name)
90

91
92
93
94
95
96
97
98
99
100
101
102
103
/*
 * nfscl_getsameserver() can return one of three values:
 * NFSDSP_USETHISSESSION - Use this session for the DS.
 * NFSDSP_SEQTHISSESSION - Use the nfsclds_sequence field of this dsp for new
 *     session.
 * NFSDSP_NOTFOUND - No matching server was found.
 */
enum nfsclds_state {
	NFSDSP_USETHISSESSION = 0,
	NFSDSP_SEQTHISSESSION = 1,
	NFSDSP_NOTFOUND = 2,
};

104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*
 * Do a write RPC on a DS data file, using this structure for the arguments,
 * so that this function can be executed by a separate kernel process.
 */
struct nfsclwritedsdorpc {
	int			done;
	int			inprog;
	struct task		tsk;
	struct vnode		*vp;
	int			iomode;
	int			must_commit;
	nfsv4stateid_t		*stateidp;
	struct nfsclds		*dsp;
	uint64_t		off;
	int			len;
119
120
121
#ifdef notyet
	int			advise;
#endif
122
123
124
125
126
127
128
129
130
	struct nfsfh		*fhp;
	struct mbuf		*m;
	int			vers;
	int			minorvers;
	struct ucred		*cred;
	NFSPROC_T		*p;
	int			err;
};

131
static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *,
132
    struct ucred *, NFSPROC_T *, struct nfsvattr *, int *);
133
static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *,
134
    nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *);
135
static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *,
136
    struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *,
137
    int);
138
static int nfsrpc_deallocaterpc(vnode_t, off_t, off_t, nfsv4stateid_t *,
139
    struct nfsvattr *, int *, struct ucred *, NFSPROC_T *);
140
141
static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *,
    nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *,
142
    struct nfsvattr *, struct nfsfh **, int *, int *);
143
144
145
static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *,
    nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *,
    NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *,
146
    int *, int *);
147
148
149
150
static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *,
    struct nfscllockowner *, u_int64_t, u_int64_t,
    u_int32_t, struct ucred *, NFSPROC_T *, int);
static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *,
151
    struct acl *, nfsv4stateid_t *);
152
153
154
static int nfsrpc_layouterror(struct nfsmount *, uint8_t *, int, uint64_t,
    uint64_t, nfsv4stateid_t *, struct ucred *, NFSPROC_T *, uint32_t,
    uint32_t, char *);
155
static int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int,
156
    uint32_t, uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **,
157
    struct ucred *, NFSPROC_T *);
158
static int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_in *,
159
160
    struct sockaddr_in6 *, sa_family_t, int, int, struct nfsclds **,
    NFSPROC_T *);
161
162
163
static void nfscl_initsessionslots(struct nfsclsession *);
static int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *,
    nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
164
165
    struct nfsclflayout *, uint64_t, uint64_t, int, struct ucred *,
    NFSPROC_T *);
166
167
168
static int nfscl_dofflayoutio(vnode_t, struct uio *, int *, int *, int *,
    nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
    struct nfsclflayout *, uint64_t, uint64_t, int, int, struct mbuf *,
169
    struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *);
170
static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *,
171
172
    struct nfsclds *, uint64_t, int, struct nfsfh *, int, int, int,
    struct ucred *, NFSPROC_T *);
173
174
static int nfsrpc_writeds(vnode_t, struct uio *, int *, int *,
    nfsv4stateid_t *, struct nfsclds *, uint64_t, int,
175
    struct nfsfh *, int, int, int, int, struct ucred *, NFSPROC_T *);
176
177
178
static int nfsio_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *,
    struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int,
    struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *);
179
180
181
static int nfsrpc_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *,
    struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int,
    struct ucred *, NFSPROC_T *);
182
static enum nfsclds_state nfscl_getsameserver(struct nfsmount *,
183
    struct nfsclds *, struct nfsclds **, uint32_t *);
184
185
186
static int nfsio_commitds(vnode_t, uint64_t, int, struct nfsclds *,
    struct nfsfh *, int, int, struct nfsclwritedsdorpc *, struct ucred *,
    NFSPROC_T *);
187
static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *,
188
    struct nfsfh *, int, int, struct ucred *, NFSPROC_T *);
189
190
191
192
193
194
195
196
#ifdef notyet
static int nfsio_adviseds(vnode_t, uint64_t, int, int, struct nfsclds *,
    struct nfsfh *, int, int, struct nfsclwritedsdorpc *, struct ucred *,
    NFSPROC_T *);
static int nfsrpc_adviseds(vnode_t, uint64_t, int, int, struct nfsclds *,
    struct nfsfh *, int, int, struct ucred *, NFSPROC_T *);
#endif
static int nfsrpc_allocaterpc(vnode_t, off_t, off_t, nfsv4stateid_t *,
197
    struct nfsvattr *, int *, struct ucred *, NFSPROC_T *);
198
static void nfsrv_setuplayoutget(struct nfsrv_descript *, int, uint64_t,
199
200
201
    uint64_t, uint64_t, nfsv4stateid_t *, int, int, int);
static int nfsrv_parseug(struct nfsrv_descript *, int, uid_t *, gid_t *,
    NFSPROC_T *);
202
203
static int nfsrv_parselayoutget(struct nfsmount *, struct nfsrv_descript *,
    nfsv4stateid_t *, int *, struct nfsclflayouthead *);
204
205
206
207
208
209
static int nfsrpc_getopenlayout(struct nfsmount *, vnode_t, u_int8_t *,
    int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int,
    struct nfscldeleg **, struct ucred *, NFSPROC_T *);
static int nfsrpc_getcreatelayout(vnode_t, char *, int, struct vattr *,
    nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **,
    struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
210
    struct nfsfh **, int *, int *, int *);
211
212
static int nfsrpc_openlayoutrpc(struct nfsmount *, vnode_t, u_int8_t *,
    int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int,
213
    struct nfscldeleg **, nfsv4stateid_t *, int, int, int, int *,
214
215
216
217
    struct nfsclflayouthead *, int *, struct ucred *, NFSPROC_T *);
static int nfsrpc_createlayout(vnode_t, char *, int, struct vattr *,
    nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **,
    struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
218
    struct nfsfh **, int *, int *, int *, nfsv4stateid_t *,
219
    int, int, int, int *, struct nfsclflayouthead *, int *);
220
static int nfsrpc_layoutget(struct nfsmount *, uint8_t *, int, int, uint64_t,
221
    uint64_t, uint64_t, int, int, nfsv4stateid_t *, int *,
222
    struct nfsclflayouthead *, struct ucred *, NFSPROC_T *);
223
224
static int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_t *,
    int, nfsv4stateid_t *, int, uint32_t *, struct nfscllayout **,
225
    struct nfsclflayouthead *, int, int, int *, struct ucred *, NFSPROC_T *);
226
227
228
229
230
static int nfsrpc_copyrpc(vnode_t, off_t, vnode_t, off_t, size_t *,
    nfsv4stateid_t *, nfsv4stateid_t *, struct nfsvattr *, int *,
    struct nfsvattr *, int *, bool, int *, struct ucred *, NFSPROC_T *);
static int nfsrpc_seekrpc(vnode_t, off_t *, nfsv4stateid_t *, bool *,
    int, struct nfsvattr *, int *, struct ucred *);
231
static struct mbuf *nfsm_split(struct mbuf *, uint64_t);
232

233
234
int nfs_pnfsio(task_fn_t *, void *);

235
236
237
/*
 * nfs null call from vfs.
 */
Ryan Moeller's avatar
Ryan Moeller committed
238
int
239
240
241
242
nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p)
{
	int error;
	struct nfsrv_descript nfsd, *nd = &nfsd;
243

244
	NFSCL_REQSTART(nd, NFSPROC_NULL, vp);
245
	error = nfscl_request(nd, vp, p, cred);
246
247
	if (nd->nd_repstat && !error)
		error = nd->nd_repstat;
248
	m_freem(nd->nd_mrep);
249
250
251
252
253
254
255
256
	return (error);
}

/*
 * nfs access rpc op.
 * For nfs version 3 and 4, use the access rpc to check accessibility. If file
 * modes are changed on the server, accesses might still fail later.
 */
Ryan Moeller's avatar
Ryan Moeller committed
257
int
258
259
260
261
262
263
264
265
266
267
nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred,
    NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
{
	int error;
	u_int32_t mode, rmode;

	if (acmode & VREAD)
		mode = NFSACCESS_READ;
	else
		mode = 0;
268
	if (vp->v_type == VDIR) {
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
		if (acmode & VWRITE)
			mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND |
				 NFSACCESS_DELETE);
		if (acmode & VEXEC)
			mode |= NFSACCESS_LOOKUP;
	} else {
		if (acmode & VWRITE)
			mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND);
		if (acmode & VEXEC)
			mode |= NFSACCESS_EXECUTE;
	}

	/*
	 * Now, just call nfsrpc_accessrpc() to do the actual RPC.
	 */
284
	error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode);
285
286
287
288
289
290
291
292
293
294
295
296
297
298

	/*
	 * The NFS V3 spec does not clarify whether or not
	 * the returned access bits can be a superset of
	 * the ones requested, so...
	 */
	if (!error && (rmode & mode) != mode)
		error = EACCES;
	return (error);
}

/*
 * The actual rpc, separated out for Darwin.
 */
Ryan Moeller's avatar
Ryan Moeller committed
299
int
300
nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred,
301
    NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep)
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
{
	u_int32_t *tl;
	u_int32_t supported, rmode;
	int error;
	struct nfsrv_descript nfsd, *nd = &nfsd;
	nfsattrbit_t attrbits;

	*attrflagp = 0;
	supported = mode;
	NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp);
	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
	*tl = txdr_unsigned(mode);
	if (nd->nd_flag & ND_NFSV4) {
		/*
		 * And do a Getattr op.
		 */
		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
		*tl = txdr_unsigned(NFSV4OP_GETATTR);
		NFSGETATTR_ATTRBIT(&attrbits);
		(void) nfsrv_putattrbit(nd, &attrbits);
	}
323
	error = nfscl_request(nd, vp, p, cred);
324
325
326
	if (error)
		return (error);
	if (nd->nd_flag & ND_NFSV3) {
327
		error = nfscl_postop_attr(nd, nap, attrflagp);
328
329
330
331
332
333
334
335
336
337
338
339
		if (error)
			goto nfsmout;
	}
	if (!nd->nd_repstat) {
		if (nd->nd_flag & ND_NFSV4) {
			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
			supported = fxdr_unsigned(u_int32_t, *tl++);
		} else {
			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
		}
		rmode = fxdr_unsigned(u_int32_t, *tl);
		if (nd->nd_flag & ND_NFSV4)
340
			error = nfscl_postop_attr(nd, nap, attrflagp);
341
342
343
344
345
346
347
348
349
350
351

		/*
		 * It's not obvious what should be done about
		 * unsupported access modes. For now, be paranoid
		 * and clear the unsupported ones.
		 */
		rmode &= supported;
		*rmodep = rmode;
	} else
		error = nd->nd_repstat;
nfsmout:
352
	m_freem(nd->nd_mrep);
353
354
355
356
357
358
	return (error);
}

/*
 * nfs open rpc
 */
Ryan Moeller's avatar
Ryan Moeller committed
359
int
360
361
362
363
364
365
nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p)
{
	struct nfsclopen *op;
	struct nfscldeleg *dp;
	struct nfsfh *nfhp;
	struct nfsnode *np = VTONFS(vp);
366
	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
367
368
369
370
371
372
	u_int32_t mode, clidrev;
	int ret, newone, error, expireret = 0, retrycnt;

	/*
	 * For NFSv4, Open Ops are only done on Regular Files.
	 */
373
	if (vp->v_type != VREG)
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
		return (0);
	mode = 0;
	if (amode & FREAD)
		mode |= NFSV4OPEN_ACCESSREAD;
	if (amode & FWRITE)
		mode |= NFSV4OPEN_ACCESSWRITE;
	nfhp = np->n_fhp;

	retrycnt = 0;
#ifdef notdef
{ char name[100]; int namel;
namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99;
bcopy(NFS4NODENAME(np->n_v4), name, namel);
name[namel] = '\0';
printf("rpcopen p=0x%x name=%s",p->p_pid,name);
if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]);
else printf(" fhl=0\n");
}
#endif
	do {
	    dp = NULL;
	    error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1,
396
		cred, p, NULL, &op, &newone, &ret, 1, true);
397
398
399
400
401
402
403
404
405
	    if (error) {
		return (error);
	    }
	    if (nmp->nm_clp != NULL)
		clidrev = nmp->nm_clp->nfsc_clientidrev;
	    else
		clidrev = 0;
	    if (ret == NFSCLOPEN_DOOPEN) {
		if (np->n_v4 != NULL) {
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
			/*
			 * For the first attempt, try and get a layout, if
			 * pNFS is enabled for the mount.
			 */
			if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 ||
			    nfs_numnfscbd == 0 ||
			    (np->n_flag & NNOLAYOUT) != 0 || retrycnt > 0)
				error = nfsrpc_openrpc(nmp, vp,
				    np->n_v4->n4_data,
				    np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
				    np->n_fhp->nfh_len, mode, op,
				    NFS4NODENAME(np->n_v4),
				    np->n_v4->n4_namelen,
				    &dp, 0, 0x0, cred, p, 0, 0);
			else
				error = nfsrpc_getopenlayout(nmp, vp,
				    np->n_v4->n4_data,
				    np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
				    np->n_fhp->nfh_len, mode, op,
				    NFS4NODENAME(np->n_v4),
				    np->n_v4->n4_namelen, &dp, cred, p);
427
428
429
			if (dp != NULL) {
				NFSLOCKNODE(np);
				np->n_flag &= ~NDELEGMOD;
430
431
432
433
434
435
436
437
				/*
				 * Invalidate the attribute cache, so that
				 * attributes that pre-date the issue of a
				 * delegation are not cached, since the
				 * cached attributes will remain valid while
				 * the delegation is held.
				 */
				NFSINVALATTRCACHE(np);
438
439
440
441
442
443
444
445
446
				NFSUNLOCKNODE(np);
				(void) nfscl_deleg(nmp->nm_mountp,
				    op->nfso_own->nfsow_clp,
				    nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp);
			}
		} else {
			error = EIO;
		}
		newnfs_copyincred(cred, &op->nfso_cred);
447
448
449
450
451
452
453
	    } else if (ret == NFSCLOPEN_SETCRED)
		/*
		 * This is a new local open on a delegation. It needs
		 * to have credentials so that an open can be done
		 * against the server during recovery.
		 */
		newnfs_copyincred(cred, &op->nfso_cred);
454
455
456
457
458
459
460
461

	    /*
	     * nfso_opencnt is the count of how many VOP_OPEN()s have
	     * been done on this Open successfully and a VOP_CLOSE()
	     * is expected for each of these.
	     * If error is non-zero, don't increment it, since the Open
	     * hasn't succeeded yet.
	     */
462
	    if (!error) {
463
		op->nfso_opencnt++;
464
465
466
467
468
469
		if (NFSHASNFSV4N(nmp) && NFSHASONEOPENOWN(nmp)) {
		    NFSLOCKNODE(np);
		    np->n_openstateid = op;
		    NFSUNLOCKNODE(np);
		}
	    }
470
	    nfscl_openrelease(nmp, op, error, newone);
471
	    if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
472
473
		error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
		error == NFSERR_BADSESSION) {
474
		(void) nfs_catnap(PZERO, error, "nfs_open");
475
476
477
478
479
480
481
	    } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
		&& clidrev != 0) {
		expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
		retrycnt++;
	    }
	} while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
	    error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
482
	    error == NFSERR_BADSESSION ||
483
484
485
486
487
488
489
490
491
492
	    ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
	     expireret == 0 && clidrev != 0 && retrycnt < 4));
	if (error && retrycnt >= 4)
		error = EIO;
	return (error);
}

/*
 * the actual open rpc
 */
Ryan Moeller's avatar
Ryan Moeller committed
493
int
494
495
496
497
498
499
500
501
502
503
504
505
506
nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
    u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op,
    u_int8_t *name, int namelen, struct nfscldeleg **dpp,
    int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p,
    int syscred, int recursed)
{
	u_int32_t *tl;
	struct nfsrv_descript nfsd, *nd = &nfsd;
	struct nfscldeleg *dp, *ndp = NULL;
	struct nfsvattr nfsva;
	u_int32_t rflags, deleg;
	nfsattrbit_t attrbits;
	int error, ret, acesize, limitby;
507
	struct nfsclsession *tsep;
508
509
510

	dp = *dpp;
	*dpp = NULL;
511
	nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL, NULL, 0, 0);
512
513
514
515
	NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
	*tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
	*tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
	*tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
516
517
518
	tsep = nfsmnt_mdssession(nmp);
	*tl++ = tsep->nfsess_clientid.lval[0];
	*tl = tsep->nfsess_clientid.lval[1];
519
520
521
522
523
524
525
526
527
528
529
	(void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
	NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
	*tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
	if (reclaim) {
		*tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS);
		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
		*tl = txdr_unsigned(delegtype);
	} else {
		if (dp != NULL) {
			*tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR);
			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
530
531
532
533
			if (NFSHASNFSV4N(nmp))
				*tl++ = 0;
			else
				*tl++ = dp->nfsdl_stateid.seqid;
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
			*tl++ = dp->nfsdl_stateid.other[0];
			*tl++ = dp->nfsdl_stateid.other[1];
			*tl = dp->nfsdl_stateid.other[2];
		} else {
			*tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
		}
		(void) nfsm_strtom(nd, name, namelen);
	}
	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
	*tl = txdr_unsigned(NFSV4OP_GETATTR);
	NFSZERO_ATTRBIT(&attrbits);
	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
	(void) nfsrv_putattrbit(nd, &attrbits);
	if (syscred)
		nd->nd_flag |= ND_USEGSSNAME;
	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
551
	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
	if (error)
		return (error);
	NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
	if (!nd->nd_repstat) {
		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
		    6 * NFSX_UNSIGNED);
		op->nfso_stateid.seqid = *tl++;
		op->nfso_stateid.other[0] = *tl++;
		op->nfso_stateid.other[1] = *tl++;
		op->nfso_stateid.other[2] = *tl;
		rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
		if (error)
			goto nfsmout;
		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
		deleg = fxdr_unsigned(u_int32_t, *tl);
		if (deleg == NFSV4OPEN_DELEGATEREAD ||
		    deleg == NFSV4OPEN_DELEGATEWRITE) {
			if (!(op->nfso_own->nfsow_clp->nfsc_flags &
			      NFSCLFLAGS_FIRSTDELEG))
				op->nfso_own->nfsow_clp->nfsc_flags |=
				  (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
574
			ndp = malloc(
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
			    sizeof (struct nfscldeleg) + newfhlen,
			    M_NFSCLDELEG, M_WAITOK);
			LIST_INIT(&ndp->nfsdl_owner);
			LIST_INIT(&ndp->nfsdl_lock);
			ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
			ndp->nfsdl_fhlen = newfhlen;
			NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
			newnfs_copyincred(cred, &ndp->nfsdl_cred);
			nfscl_lockinit(&ndp->nfsdl_rwlock);
			NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
			    NFSX_UNSIGNED);
			ndp->nfsdl_stateid.seqid = *tl++;
			ndp->nfsdl_stateid.other[0] = *tl++;
			ndp->nfsdl_stateid.other[1] = *tl++;
			ndp->nfsdl_stateid.other[2] = *tl++;
			ret = fxdr_unsigned(int, *tl);
			if (deleg == NFSV4OPEN_DELEGATEWRITE) {
				ndp->nfsdl_flags = NFSCLDL_WRITE;
				/*
				 * Indicates how much the file can grow.
				 */
				NFSM_DISSECT(tl, u_int32_t *,
				    3 * NFSX_UNSIGNED);
				limitby = fxdr_unsigned(int, *tl++);
				switch (limitby) {
				case NFSV4OPEN_LIMITSIZE:
					ndp->nfsdl_sizelimit = fxdr_hyper(tl);
					break;
				case NFSV4OPEN_LIMITBLOCKS:
					ndp->nfsdl_sizelimit =
					    fxdr_unsigned(u_int64_t, *tl++);
					ndp->nfsdl_sizelimit *=
					    fxdr_unsigned(u_int64_t, *tl);
					break;
				default:
					error = NFSERR_BADXDR;
					goto nfsmout;
612
				}
613
614
615
616
617
			} else {
				ndp->nfsdl_flags = NFSCLDL_READ;
			}
			if (ret)
				ndp->nfsdl_flags |= NFSCLDL_RECALL;
618
619
			error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, false,
			    &ret, &acesize, p);
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
			if (error)
				goto nfsmout;
		} else if (deleg != NFSV4OPEN_DELEGATENONE) {
			error = NFSERR_BADXDR;
			goto nfsmout;
		}
		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
		error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
		    NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
		    NULL, NULL, NULL, p, cred);
		if (error)
			goto nfsmout;
		if (ndp != NULL) {
			ndp->nfsdl_change = nfsva.na_filerev;
			ndp->nfsdl_modtime = nfsva.na_mtime;
			ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
		}
		if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) {
		    do {
			ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op,
			    cred, p);
			if (ret == NFSERR_DELAY)
642
			    (void) nfs_catnap(PZERO, ret, "nfs_open");
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
		    } while (ret == NFSERR_DELAY);
		    error = ret;
		}
		if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) ||
		    nfscl_assumeposixlocks)
		    op->nfso_posixlock = 1;
		else
		    op->nfso_posixlock = 0;

		/*
		 * If the server is handing out delegations, but we didn't
		 * get one because an OpenConfirm was required, try the
		 * Open again, to get a delegation. This is a harmless no-op,
		 * from a server's point of view.
		 */
		if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) &&
		    (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG)
		    && !error && dp == NULL && ndp == NULL && !recursed) {
		    do {
			ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp,
			    newfhlen, mode, op, name, namelen, &ndp, 0, 0x0,
			    cred, p, syscred, 1);
			if (ret == NFSERR_DELAY)
666
			    (void) nfs_catnap(PZERO, ret, "nfs_open2");
667
668
		    } while (ret == NFSERR_DELAY);
		    if (ret) {
Pedro F. Giffuni's avatar
Pedro F. Giffuni committed
669
			if (ndp != NULL) {
670
				free(ndp, M_NFSCLDELEG);
Pedro F. Giffuni's avatar
Pedro F. Giffuni committed
671
672
				ndp = NULL;
			}
673
			if (ret == NFSERR_STALECLIENTID ||
674
675
			    ret == NFSERR_STALEDONTRECOVER ||
			    ret == NFSERR_BADSESSION)
676
677
678
679
680
681
				error = ret;
		    }
		}
	}
	if (nd->nd_repstat != 0 && error == 0)
		error = nd->nd_repstat;
682
	if (error == NFSERR_STALECLIENTID)
683
684
685
686
687
		nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
nfsmout:
	if (!error)
		*dpp = ndp;
	else if (ndp != NULL)
688
		free(ndp, M_NFSCLDELEG);
689
	m_freem(nd->nd_mrep);
690
691
692
693
694
695
	return (error);
}

/*
 * open downgrade rpc
 */
Ryan Moeller's avatar
Ryan Moeller committed
696
int
697
698
699
700
701
702
703
704
705
nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op,
    struct ucred *cred, NFSPROC_T *p)
{
	u_int32_t *tl;
	struct nfsrv_descript nfsd, *nd = &nfsd;
	int error;

	NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp);
	NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
706
	if (NFSHASNFSV4N(VFSTONFS(vp->v_mount)))
707
708
709
		*tl++ = 0;
	else
		*tl++ = op->nfso_stateid.seqid;
710
711
712
713
714
715
	*tl++ = op->nfso_stateid.other[0];
	*tl++ = op->nfso_stateid.other[1];
	*tl++ = op->nfso_stateid.other[2];
	*tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
	*tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
	*tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
716
	error = nfscl_request(nd, vp, p, cred);
717
718
719
720
721
722
723
724
725
726
727
728
	if (error)
		return (error);
	NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
	if (!nd->nd_repstat) {
		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
		op->nfso_stateid.seqid = *tl++;
		op->nfso_stateid.other[0] = *tl++;
		op->nfso_stateid.other[1] = *tl++;
		op->nfso_stateid.other[2] = *tl;
	}
	if (nd->nd_repstat && error == 0)
		error = nd->nd_repstat;
729
	if (error == NFSERR_STALESTATEID)
730
731
		nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
nfsmout:
732
	m_freem(nd->nd_mrep);
733
734
735
736
737
738
	return (error);
}

/*
 * V4 Close operation.
 */
Ryan Moeller's avatar
Ryan Moeller committed
739
int
740
nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p)
741
742
743
744
{
	struct nfsclclient *clp;
	int error;

745
	if (vp->v_type != VREG)
746
		return (0);
747
	if (doclose)
748
		error = nfscl_doclose(vp, &clp, p);
749
	else {
750
		error = nfscl_getclose(vp, &clp);
751
752
753
754
		if (error == 0)
			nfscl_clientrelease(clp);
	}
	return (error);
755
756
757
}

/*
758
 * Close the open.
759
 */
760
761
762
int
nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p,
    bool loop_on_delayed, bool freeop)
763
764
{
	struct nfsrv_descript nfsd, *nd = &nfsd;
765
	struct nfscllockowner *lp, *nlp;
766
767
768
769
	struct nfscllock *lop, *nlop;
	struct ucred *tcred;
	u_int64_t off = 0, len = 0;
	u_int32_t type = NFSV4LOCKT_READ;
770
	int error, do_unlock, trycnt;
771
772

	tcred = newnfs_getcred();
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
	newnfs_copycred(&op->nfso_cred, tcred);
	/*
	 * (Theoretically this could be done in the same
	 *  compound as the close, but having multiple
	 *  sequenced Ops in the same compound might be
	 *  too scary for some servers.)
	 */
	if (op->nfso_posixlock) {
		off = 0;
		len = NFS64BITSSET;
		type = NFSV4LOCKT_READ;
	}

	/*
	 * Since this function is only called from VOP_INACTIVE(), no
	 * other thread will be manipulating this Open. As such, the
	 * lock lists are not being changed by other threads, so it should
	 * be safe to do this without locking.
	 */
	LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
		do_unlock = 1;
		LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
795
			if (op->nfso_posixlock == 0) {
796
797
798
799
800
801
				off = lop->nfslo_first;
				len = lop->nfslo_end - lop->nfslo_first;
				if (lop->nfslo_type == F_WRLCK)
					type = NFSV4LOCKT_WRITE;
				else
					type = NFSV4LOCKT_READ;
802
			}
803
804
805
806
807
808
809
810
811
			if (do_unlock) {
				trycnt = 0;
				do {
					error = nfsrpc_locku(nd, nmp, lp, off,
					    len, type, tcred, p, 0);
					if ((nd->nd_repstat == NFSERR_GRACE ||
					    nd->nd_repstat == NFSERR_DELAY) &&
					    error == 0)
						(void) nfs_catnap(PZERO,
812
						    (int)nd->nd_repstat,
813
814
815
816
817
818
						    "nfs_close");
				} while ((nd->nd_repstat == NFSERR_GRACE ||
				    nd->nd_repstat == NFSERR_DELAY) &&
				    error == 0 && trycnt++ < 5);
				if (op->nfso_posixlock)
					do_unlock = 0;
819
820
821
			}
			nfscl_freelock(lop, 0);
		}
822
823
824
825
826
827
828
		/*
		 * Do a ReleaseLockOwner.
		 * The lock owner name nfsl_owner may be used by other opens for
		 * other files but the lock_owner4 name that nfsrpc_rellockown()
		 * puts on the wire has the file handle for this file appended
		 * to it, so it can be done now.
		 */
829
830
		(void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh,
		    lp->nfsl_open->nfso_fhlen, tcred, p);
831
	}
832

833
834
835
836
837
838
839
840
	/*
	 * There could be other Opens for different files on the same
	 * OpenOwner, so locking is required.
	 */
	NFSLOCKCLSTATE();
	nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
	NFSUNLOCKCLSTATE();
	do {
841
		error = nfscl_tryclose(op, tcred, nmp, p, loop_on_delayed);
842
		if (error == NFSERR_GRACE)
843
			(void) nfs_catnap(PZERO, error, "nfs_close");
844
845
846
847
	} while (error == NFSERR_GRACE);
	NFSLOCKCLSTATE();
	nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);

848
849
	LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp)
		nfscl_freelockowner(lp, 0);
850
851
	if (freeop && error != NFSERR_DELAY)
		nfscl_freeopen(op, 0, true);
852
	NFSUNLOCKCLSTATE();
853
	NFSFREECRED(tcred);
854
	return (error);
855
856
857
858
859
}

/*
 * The actual Close RPC.
 */
Ryan Moeller's avatar
Ryan Moeller committed
860
int
861
862
863
864
865
866
867
868
nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp,
    struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p,
    int syscred)
{
	u_int32_t *tl;
	int error;

	nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh,
869
	    op->nfso_fhlen, NULL, NULL, 0, 0);
870
	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
871
	if (NFSHASNFSV4N(nmp)) {
872
		*tl++ = 0;
873
874
875
		*tl++ = 0;
	} else {
		*tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
876
		*tl++ = op->nfso_stateid.seqid;
877
	}
878
879
880
881
882
883
	*tl++ = op->nfso_stateid.other[0];
	*tl++ = op->nfso_stateid.other[1];
	*tl = op->nfso_stateid.other[2];
	if (syscred)
		nd->nd_flag |= ND_USEGSSNAME;
	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
884
	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
885
886
	if (error)
		return (error);
887
888
	if (!NFSHASNFSV4N(nmp))
		NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
889
890
891
	if (nd->nd_repstat == 0)
		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
	error = nd->nd_repstat;
892
	if (!NFSHASNFSV4N(nmp) && error == NFSERR_STALESTATEID)
893
894
		nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
nfsmout:
895
	m_freem(nd->nd_mrep);
896
897
898
899
900
901
	return (error);
}

/*
 * V4 Open Confirm RPC.
 */
Ryan Moeller's avatar
Ryan Moeller committed
902
int
903
904
905
906
907
nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen,
    struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p)
{
	u_int32_t *tl;
	struct nfsrv_descript nfsd, *nd = &nfsd;
908
	struct nfsmount *nmp;
909
910
	int error;

911
	nmp = VFSTONFS(vp->v_mount);
912
913
	if (NFSHASNFSV4N(nmp))
		return (0);		/* No confirmation for NFSv4.1. */
914
	nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, nmp, nfhp, fhlen, NULL, NULL,
915
	    0, 0);
916
917
918
919
920
921
	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
	*tl++ = op->nfso_stateid.seqid;
	*tl++ = op->nfso_stateid.other[0];
	*tl++ = op->nfso_stateid.other[1];
	*tl++ = op->nfso_stateid.other[2];
	*tl = txdr_unsigned(op->nfso_own->nfsow_seqid);
922
	error = nfscl_request(nd, vp, p, cred);
923
924
925
926
927
928
929
930
931
932
933
	if (error)
		return (error);
	NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
	if (!nd->nd_repstat) {
		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
		op->nfso_stateid.seqid = *tl++;
		op->nfso_stateid.other[0] = *tl++;
		op->nfso_stateid.other[1] = *tl++;
		op->nfso_stateid.other[2] = *tl;
	}
	error = nd->nd_repstat;
934
	if (error == NFSERR_STALESTATEID)
935
936
		nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
nfsmout:
937
	m_freem(nd->nd_mrep);
938
939
940
941
942
943
944
	return (error);
}

/*
 * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs()
 * when a mount has just occurred and when the server replies NFSERR_EXPIRED.
 */
Ryan Moeller's avatar
Ryan Moeller committed
945
int
946
nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim,
947
    bool *retokp, struct ucred *cred, NFSPROC_T *p)
948
949
950
951
952
953
{
	u_int32_t *tl;
	struct nfsrv_descript nfsd;
	struct nfsrv_descript *nd = &nfsd;
	u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9];
	u_short port;
954
	int error, isinet6 = 0, callblen;
955
956
	nfsquad_t confirm;
	static u_int32_t rev = 0;
957
	struct nfsclds *dsp, *odsp;
958
	struct in6_addr a6;
959
	struct nfsclsession *tsep;
960
961
	struct rpc_reconupcall recon;
	struct nfscl_reconarg *rcp;
962
963
964

	if (nfsboottime.tv_sec == 0)
		NFSSETBOOTTIME(nfsboottime);
965
	if (NFSHASNFSV4N(nmp)) {
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
		error = NFSERR_BADSESSION;
		odsp = dsp = NULL;
		if (retokp != NULL) {
			NFSLOCKMNT(nmp);
			odsp = TAILQ_FIRST(&nmp->nm_sess);
			NFSUNLOCKMNT(nmp);
		}
		if (odsp != NULL) {
			/*
			 * When a session already exists, first try a
			 * CreateSession with the extant ClientID.
			 */
			dsp = malloc(sizeof(struct nfsclds) +
			    odsp->nfsclds_servownlen + 1, M_NFSCLDS,
			    M_WAITOK | M_ZERO);
			dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew;
			dsp->nfsclds_servownlen = odsp->nfsclds_servownlen;
			dsp->nfsclds_sess.nfsess_clientid =
			    odsp->nfsclds_sess.nfsess_clientid;
			dsp->nfsclds_sess.nfsess_sequenceid =
			    odsp->nfsclds_sess.nfsess_sequenceid;
			dsp->nfsclds_flags = odsp->nfsclds_flags;
			if (dsp->nfsclds_servownlen > 0)
				memcpy(dsp->nfsclds_serverown,
				    odsp->nfsclds_serverown,
				    dsp->nfsclds_servownlen + 1);
			mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
			mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
			    NULL, MTX_DEF);
			nfscl_initsessionslots(&dsp->nfsclds_sess);
996
			error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
997
			    &nmp->nm_sockreq, NULL,
998
			    dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p);
999
1000
			NFSCL_DEBUG(1, "create session for extant "
			    "ClientID=%d\n", error);
For faster browsing, not all history is shown. View entire blame