Print this page
NEX-15279 support NFS server in zone
NEX-15520 online NFS shares cause zoneadm halt to hang in nfs_export_zone_fini
Portions contributed by: Dan Kruchinin dan.kruchinin@nexenta.com
Portions contributed by: Stepan Zastupov stepan.zastupov@gmail.com
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-6778 NFS kstats leak and cause system to hang
Revert "NEX-4261 Per-client NFS server IOPS, bandwidth, and latency kstats"
This reverts commit 586c3ab1927647487f01c337ddc011c642575a52.
Revert "NEX-5354 Aggregated IOPS, bandwidth, and latency kstats for NFS server"
This reverts commit c91d7614da8618ef48018102b077f60ecbbac8c2.
Revert "NEX-5667 nfssrv_stats_flags does not work for aggregated kstats"
This reverts commit 3dcf42618be7dd5f408c327f429c81e07ca08e74.
Revert "NEX-5750 Time values for aggregated NFS server kstats should be normalized"
This reverts commit 1f4d4f901153b0191027969fa4a8064f9d3b9ee1.
Revert "NEX-5942 Panic in rfs4_minorvers_mismatch() with NFSv4.1 client"
This reverts commit 40766417094a162f5e4cc8786c0fa0a7e5871cd9.
Revert "NEX-5752 NFS server: namespace collision in kstats"
This reverts commit ae81e668db86050da8e483264acb0cce0444a132.
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-5942 Panic in rfs4_minorvers_mismatch() with NFSv4.1 client
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-4261 Per-client NFS server IOPS, bandwidth, and latency kstats
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-3097 IOPS, bandwidth, and latency kstats for NFS server
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/nfs/nfs4_dispatch.c
+++ new/usr/src/uts/common/fs/nfs/nfs4_dispatch.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
|
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 +/*
28 + * Copyright 2018 Nexenta Systems, Inc.
29 + */
30 +
27 31 #include <sys/systm.h>
28 32 #include <sys/sdt.h>
29 33 #include <rpc/types.h>
30 34 #include <rpc/auth.h>
31 35 #include <rpc/auth_unix.h>
32 36 #include <rpc/auth_des.h>
33 37 #include <rpc/svc.h>
34 38 #include <rpc/xdr.h>
35 39 #include <nfs/nfs4.h>
36 40 #include <nfs/nfs_dispatch.h>
37 41 #include <nfs/nfs4_drc.h>
38 42
39 43 #define NFS4_MAX_MINOR_VERSION 0
40 44
41 45 /*
42 - * This is the duplicate request cache for NFSv4
43 - */
44 -rfs4_drc_t *nfs4_drc = NULL;
45 -
46 -/*
47 46 * The default size of the duplicate request cache
48 47 */
49 48 uint32_t nfs4_drc_max = 8 * 1024;
50 49
51 50 /*
52 51 * The number of buckets we'd like to hash the
53 52 * replies into.. do not change this on the fly.
54 53 */
55 54 uint32_t nfs4_drc_hash = 541;
56 55
57 56 static void rfs4_resource_err(struct svc_req *req, COMPOUND4args *argsp);
58 57
58 +extern zone_key_t rfs4_zone_key;
59 +
59 60 /*
60 61 * Initialize a duplicate request cache.
61 62 */
62 63 rfs4_drc_t *
63 64 rfs4_init_drc(uint32_t drc_size, uint32_t drc_hash_size)
64 65 {
65 66 rfs4_drc_t *drc;
66 67 uint32_t bki;
67 68
68 69 ASSERT(drc_size);
69 70 ASSERT(drc_hash_size);
70 71
71 72 drc = kmem_alloc(sizeof (rfs4_drc_t), KM_SLEEP);
72 73
73 74 drc->max_size = drc_size;
74 75 drc->in_use = 0;
75 76
76 77 mutex_init(&drc->lock, NULL, MUTEX_DEFAULT, NULL);
77 78
78 79 drc->dr_hash = drc_hash_size;
79 80
80 81 drc->dr_buckets = kmem_alloc(sizeof (list_t)*drc_hash_size, KM_SLEEP);
81 82
82 83 for (bki = 0; bki < drc_hash_size; bki++) {
83 84 list_create(&drc->dr_buckets[bki], sizeof (rfs4_dupreq_t),
84 85 offsetof(rfs4_dupreq_t, dr_bkt_next));
85 86 }
86 87
|
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
87 88 list_create(&(drc->dr_cache), sizeof (rfs4_dupreq_t),
88 89 offsetof(rfs4_dupreq_t, dr_next));
89 90
90 91 return (drc);
91 92 }
92 93
93 94 /*
94 95 * Destroy a duplicate request cache.
95 96 */
96 97 void
97 -rfs4_fini_drc(rfs4_drc_t *drc)
98 +rfs4_fini_drc(void)
98 99 {
100 + nfs4_srv_t *nsrv4 = zone_getspecific(rfs4_zone_key, curzone);
101 + rfs4_drc_t *drc = nsrv4->nfs4_drc;
99 102 rfs4_dupreq_t *drp, *drp_next;
100 103
101 - ASSERT(drc);
102 -
103 104 /* iterate over the dr_cache and free the enties */
104 105 for (drp = list_head(&(drc->dr_cache)); drp != NULL; drp = drp_next) {
105 106
106 107 if (drp->dr_state == NFS4_DUP_REPLAY)
107 108 rfs4_compound_free(&(drp->dr_res));
108 109
109 110 if (drp->dr_addr.buf != NULL)
110 111 kmem_free(drp->dr_addr.buf, drp->dr_addr.maxlen);
111 112
112 113 drp_next = list_next(&(drc->dr_cache), drp);
113 114
114 115 kmem_free(drp, sizeof (rfs4_dupreq_t));
115 116 }
116 117
117 118 mutex_destroy(&drc->lock);
118 119 kmem_free(drc->dr_buckets,
119 120 sizeof (list_t)*drc->dr_hash);
120 121 kmem_free(drc, sizeof (rfs4_drc_t));
121 122 }
122 123
123 124 /*
124 125 * rfs4_dr_chstate:
125 126 *
126 127 * Change the state of a rfs4_dupreq. If it's not in transition
127 128 * to the FREE state, return. If we are moving to the FREE state
128 129 * then we need to clean up the compound results and move the entry
129 130 * to the end of the list.
130 131 */
131 132 void
132 133 rfs4_dr_chstate(rfs4_dupreq_t *drp, int new_state)
133 134 {
134 135 rfs4_drc_t *drc;
135 136
136 137 ASSERT(drp);
137 138 ASSERT(drp->drc);
138 139 ASSERT(drp->dr_bkt);
139 140 ASSERT(MUTEX_HELD(&drp->drc->lock));
140 141
141 142 drp->dr_state = new_state;
142 143
143 144 if (new_state != NFS4_DUP_FREE)
144 145 return;
145 146
146 147 drc = drp->drc;
147 148
148 149 /*
149 150 * Remove entry from the bucket and
150 151 * dr_cache list, free compound results.
151 152 */
152 153 list_remove(drp->dr_bkt, drp);
153 154 list_remove(&(drc->dr_cache), drp);
154 155 rfs4_compound_free(&(drp->dr_res));
155 156 }
156 157
157 158 /*
158 159 * rfs4_alloc_dr:
159 160 *
160 161 * Malloc a new one if we have not reached our maximum cache
161 162 * limit, otherwise pick an entry off the tail -- Use if it
162 163 * is marked as NFS4_DUP_FREE, or is an entry in the
163 164 * NFS4_DUP_REPLAY state.
164 165 */
165 166 rfs4_dupreq_t *
166 167 rfs4_alloc_dr(rfs4_drc_t *drc)
167 168 {
168 169 rfs4_dupreq_t *drp_tail, *drp = NULL;
169 170
170 171 ASSERT(drc);
171 172 ASSERT(MUTEX_HELD(&drc->lock));
172 173
173 174 /*
174 175 * Have we hit the cache limit yet ?
175 176 */
176 177 if (drc->in_use < drc->max_size) {
177 178 /*
178 179 * nope, so let's malloc a new one
179 180 */
180 181 drp = kmem_zalloc(sizeof (rfs4_dupreq_t), KM_SLEEP);
181 182 drp->drc = drc;
182 183 drc->in_use++;
183 184 DTRACE_PROBE1(nfss__i__drc_new, rfs4_dupreq_t *, drp);
184 185 return (drp);
185 186 }
186 187
187 188 /*
188 189 * Cache is all allocated now traverse the list
189 190 * backwards to find one we can reuse.
190 191 */
191 192 for (drp_tail = list_tail(&drc->dr_cache); drp_tail != NULL;
192 193 drp_tail = list_prev(&drc->dr_cache, drp_tail)) {
193 194
194 195 switch (drp_tail->dr_state) {
195 196
196 197 case NFS4_DUP_FREE:
197 198 list_remove(&(drc->dr_cache), drp_tail);
198 199 DTRACE_PROBE1(nfss__i__drc_freeclaim,
199 200 rfs4_dupreq_t *, drp_tail);
200 201 return (drp_tail);
201 202 /* NOTREACHED */
202 203
203 204 case NFS4_DUP_REPLAY:
204 205 /* grab it. */
205 206 rfs4_dr_chstate(drp_tail, NFS4_DUP_FREE);
206 207 DTRACE_PROBE1(nfss__i__drc_replayclaim,
207 208 rfs4_dupreq_t *, drp_tail);
208 209 return (drp_tail);
209 210 /* NOTREACHED */
210 211 }
211 212 }
212 213 DTRACE_PROBE1(nfss__i__drc_full, rfs4_drc_t *, drc);
213 214 return (NULL);
214 215 }
215 216
216 217 /*
217 218 * rfs4_find_dr:
218 219 *
219 220 * Search for an entry in the duplicate request cache by
220 221 * calculating the hash index based on the XID, and examining
221 222 * the entries in the hash bucket. If we find a match, return.
222 223 * Once we have searched the bucket we call rfs4_alloc_dr() to
223 224 * allocate a new entry, or reuse one that is available.
224 225 */
225 226 int
226 227 rfs4_find_dr(struct svc_req *req, rfs4_drc_t *drc, rfs4_dupreq_t **dup)
227 228 {
228 229
229 230 uint32_t the_xid;
230 231 list_t *dr_bkt;
231 232 rfs4_dupreq_t *drp;
232 233 int bktdex;
233 234
234 235 /*
235 236 * Get the XID, calculate the bucket and search to
236 237 * see if we need to replay from the cache.
237 238 */
238 239 the_xid = req->rq_xprt->xp_xid;
239 240 bktdex = the_xid % drc->dr_hash;
240 241
241 242 dr_bkt = (list_t *)
242 243 &(drc->dr_buckets[(the_xid % drc->dr_hash)]);
243 244
244 245 DTRACE_PROBE3(nfss__i__drc_bktdex,
245 246 int, bktdex,
246 247 uint32_t, the_xid,
247 248 list_t *, dr_bkt);
248 249
249 250 *dup = NULL;
250 251
251 252 mutex_enter(&drc->lock);
252 253 /*
253 254 * Search the bucket for a matching xid and address.
254 255 */
255 256 for (drp = list_head(dr_bkt); drp != NULL;
256 257 drp = list_next(dr_bkt, drp)) {
257 258
258 259 if (drp->dr_xid == the_xid &&
259 260 drp->dr_addr.len == req->rq_xprt->xp_rtaddr.len &&
260 261 bcmp((caddr_t)drp->dr_addr.buf,
261 262 (caddr_t)req->rq_xprt->xp_rtaddr.buf,
262 263 drp->dr_addr.len) == 0) {
263 264
264 265 /*
265 266 * Found a match so REPLAY the Reply
266 267 */
267 268 if (drp->dr_state == NFS4_DUP_REPLAY) {
268 269 rfs4_dr_chstate(drp, NFS4_DUP_INUSE);
269 270 mutex_exit(&drc->lock);
270 271 *dup = drp;
271 272 DTRACE_PROBE1(nfss__i__drc_replay,
272 273 rfs4_dupreq_t *, drp);
273 274 return (NFS4_DUP_REPLAY);
274 275 }
275 276
276 277 /*
277 278 * This entry must be in transition, so return
278 279 * the 'pending' status.
279 280 */
280 281 mutex_exit(&drc->lock);
281 282 return (NFS4_DUP_PENDING);
282 283 }
283 284 }
284 285
285 286 drp = rfs4_alloc_dr(drc);
286 287 mutex_exit(&drc->lock);
287 288
288 289 /*
289 290 * The DRC is full and all entries are in use. Upper function
290 291 * should error out this request and force the client to
291 292 * retransmit -- effectively this is a resource issue. NFSD
292 293 * threads tied up with native File System, or the cache size
293 294 * is too small for the server load.
294 295 */
295 296 if (drp == NULL)
296 297 return (NFS4_DUP_ERROR);
297 298
298 299 /*
299 300 * Init the state to NEW.
300 301 */
301 302 drp->dr_state = NFS4_DUP_NEW;
302 303
303 304 /*
304 305 * If needed, resize the address buffer
305 306 */
306 307 if (drp->dr_addr.maxlen < req->rq_xprt->xp_rtaddr.len) {
307 308 if (drp->dr_addr.buf != NULL)
308 309 kmem_free(drp->dr_addr.buf, drp->dr_addr.maxlen);
309 310 drp->dr_addr.maxlen = req->rq_xprt->xp_rtaddr.len;
310 311 drp->dr_addr.buf = kmem_alloc(drp->dr_addr.maxlen, KM_NOSLEEP);
311 312 if (drp->dr_addr.buf == NULL) {
312 313 /*
313 314 * If the malloc fails, mark the entry
314 315 * as free and put on the tail.
315 316 */
316 317 drp->dr_addr.maxlen = 0;
317 318 drp->dr_state = NFS4_DUP_FREE;
318 319 mutex_enter(&drc->lock);
319 320 list_insert_tail(&(drc->dr_cache), drp);
320 321 mutex_exit(&drc->lock);
321 322 return (NFS4_DUP_ERROR);
322 323 }
323 324 }
324 325
325 326
326 327 /*
327 328 * Copy the address.
328 329 */
329 330 drp->dr_addr.len = req->rq_xprt->xp_rtaddr.len;
330 331
331 332 bcopy((caddr_t)req->rq_xprt->xp_rtaddr.buf,
332 333 (caddr_t)drp->dr_addr.buf,
333 334 drp->dr_addr.len);
334 335
335 336 drp->dr_xid = the_xid;
336 337 drp->dr_bkt = dr_bkt;
337 338
338 339 /*
339 340 * Insert at the head of the bucket and
340 341 * the drc lists..
341 342 */
342 343 mutex_enter(&drc->lock);
343 344 list_insert_head(&drc->dr_cache, drp);
344 345 list_insert_head(dr_bkt, drp);
345 346 mutex_exit(&drc->lock);
346 347
347 348 *dup = drp;
348 349
349 350 return (NFS4_DUP_NEW);
350 351 }
351 352
352 353 /*
|
↓ open down ↓ |
240 lines elided |
↑ open up ↑ |
353 354 *
354 355 * This function handles the duplicate request cache,
355 356 * NULL_PROC and COMPOUND procedure calls for NFSv4;
356 357 *
357 358 * Passed into this function are:-
358 359 *
359 360 * disp A pointer to our dispatch table entry
360 361 * req The request to process
361 362 * xprt The server transport handle
362 363 * ap A pointer to the arguments
364 + * rlen A pointer to the reply length (output)
363 365 *
364 366 *
365 367 * When appropriate this function is responsible for inserting
366 368 * the reply into the duplicate cache or replaying an existing
367 369 * cached reply.
368 370 *
369 371 * dr_stat reflects the state of the duplicate request that
370 372 * has been inserted into or retrieved from the cache
371 373 *
372 374 * drp is the duplicate request entry
373 375 *
374 376 */
375 377 int
376 378 rfs4_dispatch(struct rpcdisp *disp, struct svc_req *req,
377 - SVCXPRT *xprt, char *ap)
379 + SVCXPRT *xprt, char *ap, size_t *rlen)
378 380 {
379 381
380 382 COMPOUND4res res_buf;
381 383 COMPOUND4res *rbp;
382 384 COMPOUND4args *cap;
383 385 cred_t *cr = NULL;
384 386 int error = 0;
385 387 int dis_flags = 0;
386 388 int dr_stat = NFS4_NOT_DUP;
387 389 rfs4_dupreq_t *drp = NULL;
388 390 int rv;
391 + nfs4_srv_t *nsrv4 = zone_getspecific(rfs4_zone_key, curzone);
392 + rfs4_drc_t *nfs4_drc = nsrv4->nfs4_drc;
389 393
390 394 ASSERT(disp);
391 395
392 396 /*
393 397 * Short circuit the RPC_NULL proc.
394 398 */
395 399 if (disp->dis_proc == rpc_null) {
396 400 DTRACE_NFSV4_1(null__start, struct svc_req *, req);
397 401 if (!svc_sendreply(xprt, xdr_void, NULL)) {
398 402 DTRACE_NFSV4_1(null__done, struct svc_req *, req);
399 403 svcerr_systemerr(xprt);
400 404 return (1);
401 405 }
402 406 DTRACE_NFSV4_1(null__done, struct svc_req *, req);
407 + *rlen = xdr_sizeof(xdr_void, NULL);
403 408 return (0);
404 409 }
405 410
406 411 /* Only NFSv4 Compounds from this point onward */
407 412
408 413 rbp = &res_buf;
409 414 cap = (COMPOUND4args *)ap;
410 415
411 416 /*
417 + * Update kstats
418 + */
419 + rfs4_compound_kstat_args(cap);
420 +
421 + /*
412 422 * Figure out the disposition of the whole COMPOUND
413 423 * and record it's IDEMPOTENTCY.
414 424 */
415 425 rfs4_compound_flagproc(cap, &dis_flags);
416 426
417 427 /*
418 428 * If NON-IDEMPOTENT then we need to figure out if this
419 429 * request can be replied from the duplicate cache.
420 430 *
421 431 * If this is a new request then we need to insert the
422 432 * reply into the duplicate cache.
423 433 */
424 434 if (!(dis_flags & RPC_IDEMPOTENT)) {
425 435 /* look for a replay from the cache or allocate */
426 436 dr_stat = rfs4_find_dr(req, nfs4_drc, &drp);
427 437
428 438 switch (dr_stat) {
429 439
430 440 case NFS4_DUP_ERROR:
431 441 rfs4_resource_err(req, cap);
432 442 return (1);
433 443 /* NOTREACHED */
434 444
435 445 case NFS4_DUP_PENDING:
436 446 /*
437 447 * reply has previously been inserted into the
438 448 * duplicate cache, however the reply has
439 449 * not yet been sent via svc_sendreply()
440 450 */
441 451 return (1);
442 452 /* NOTREACHED */
443 453
444 454 case NFS4_DUP_NEW:
445 455 curthread->t_flag |= T_DONTPEND;
446 456 /* NON-IDEMPOTENT proc call */
447 457 rfs4_compound(cap, rbp, NULL, req, cr, &rv);
448 458 curthread->t_flag &= ~T_DONTPEND;
449 459
450 460 if (rv) /* short ckt sendreply on error */
451 461 return (rv);
452 462
453 463 /*
454 464 * dr_res must be initialized before calling
455 465 * rfs4_dr_chstate (it frees the reply).
456 466 */
457 467 drp->dr_res = res_buf;
458 468 if (curthread->t_flag & T_WOULDBLOCK) {
459 469 curthread->t_flag &= ~T_WOULDBLOCK;
460 470 /*
461 471 * mark this entry as FREE and plop
462 472 * on the end of the cache list
463 473 */
464 474 mutex_enter(&drp->drc->lock);
465 475 rfs4_dr_chstate(drp, NFS4_DUP_FREE);
466 476 list_insert_tail(&(drp->drc->dr_cache), drp);
467 477 mutex_exit(&drp->drc->lock);
468 478 return (1);
469 479 }
470 480 break;
471 481
472 482 case NFS4_DUP_REPLAY:
473 483 /* replay from the cache */
474 484 rbp = &(drp->dr_res);
475 485 break;
476 486 }
477 487 } else {
478 488 curthread->t_flag |= T_DONTPEND;
479 489 /* IDEMPOTENT proc call */
480 490 rfs4_compound(cap, rbp, NULL, req, cr, &rv);
481 491 curthread->t_flag &= ~T_DONTPEND;
482 492
483 493 if (rv) /* short ckt sendreply on error */
484 494 return (rv);
|
↓ open down ↓ |
63 lines elided |
↑ open up ↑ |
485 495
486 496 if (curthread->t_flag & T_WOULDBLOCK) {
487 497 curthread->t_flag &= ~T_WOULDBLOCK;
488 498 return (1);
489 499 }
490 500 }
491 501
492 502 /*
493 503 * Send out the replayed reply or the 'real' one.
494 504 */
495 - if (!svc_sendreply(xprt, xdr_COMPOUND4res_srv, (char *)rbp)) {
505 + if (!svc_sendreply(xprt, xdr_COMPOUND4res_srv, (char *)rbp)) {
496 506 DTRACE_PROBE2(nfss__e__dispatch_sendfail,
497 507 struct svc_req *, xprt,
498 508 char *, rbp);
499 509 svcerr_systemerr(xprt);
500 510 error++;
511 + } else {
512 + /*
513 + * Update kstats
514 + */
515 + rfs4_compound_kstat_res(rbp);
516 + *rlen = xdr_sizeof(xdr_COMPOUND4res_srv, rbp);
501 517 }
502 518
503 519 /*
504 520 * If this reply was just inserted into the duplicate cache
505 521 * or it was replayed from the dup cache; (re)mark it as
506 522 * available for replay
507 523 *
508 524 * At first glance, this 'if' statement seems a little strange;
509 525 * testing for NFS4_DUP_REPLAY, and then calling...
510 526 *
511 527 * rfs4_dr_chatate(NFS4_DUP_REPLAY)
512 528 *
513 529 * ... but notice that we are checking dr_stat, and not the
514 530 * state of the entry itself, the entry will be NFS4_DUP_INUSE,
515 531 * we do that so that we know not to prematurely reap it whilst
516 532 * we resent it to the client.
517 533 *
518 534 */
519 535 if (dr_stat == NFS4_DUP_NEW || dr_stat == NFS4_DUP_REPLAY) {
520 536 mutex_enter(&drp->drc->lock);
521 537 rfs4_dr_chstate(drp, NFS4_DUP_REPLAY);
522 538 mutex_exit(&drp->drc->lock);
523 539 } else if (dr_stat == NFS4_NOT_DUP) {
524 540 rfs4_compound_free(rbp);
525 541 }
526 542
527 543 return (error);
528 544 }
529 545
530 546 bool_t
531 547 rfs4_minorvers_mismatch(struct svc_req *req, SVCXPRT *xprt, void *args)
532 548 {
533 549 COMPOUND4args *argsp;
534 550 COMPOUND4res res_buf, *resp;
535 551
536 552 if (req->rq_vers != 4)
537 553 return (FALSE);
538 554
539 555 argsp = (COMPOUND4args *)args;
540 556
541 557 if (argsp->minorversion <= NFS4_MAX_MINOR_VERSION)
542 558 return (FALSE);
543 559
544 560 resp = &res_buf;
545 561
546 562 /*
547 563 * Form a reply tag by copying over the reqeuest tag.
548 564 */
549 565 resp->tag.utf8string_val =
550 566 kmem_alloc(argsp->tag.utf8string_len, KM_SLEEP);
551 567 resp->tag.utf8string_len = argsp->tag.utf8string_len;
552 568 bcopy(argsp->tag.utf8string_val, resp->tag.utf8string_val,
553 569 resp->tag.utf8string_len);
554 570 resp->array_len = 0;
555 571 resp->array = NULL;
556 572 resp->status = NFS4ERR_MINOR_VERS_MISMATCH;
557 573 if (!svc_sendreply(xprt, xdr_COMPOUND4res_srv, (char *)resp)) {
558 574 DTRACE_PROBE2(nfss__e__minorvers_mismatch,
559 575 SVCXPRT *, xprt, char *, resp);
560 576 svcerr_systemerr(xprt);
561 577 }
562 578 rfs4_compound_free(resp);
563 579 return (TRUE);
564 580 }
565 581
566 582 void
567 583 rfs4_resource_err(struct svc_req *req, COMPOUND4args *argsp)
568 584 {
569 585 COMPOUND4res res_buf, *rbp;
570 586 nfs_resop4 *resop;
571 587 PUTFH4res *resp;
572 588
573 589 rbp = &res_buf;
574 590
575 591 /*
576 592 * Form a reply tag by copying over the request tag.
577 593 */
578 594 rbp->tag.utf8string_val =
579 595 kmem_alloc(argsp->tag.utf8string_len, KM_SLEEP);
580 596 rbp->tag.utf8string_len = argsp->tag.utf8string_len;
581 597 bcopy(argsp->tag.utf8string_val, rbp->tag.utf8string_val,
582 598 rbp->tag.utf8string_len);
583 599
584 600 rbp->array_len = 1;
585 601 rbp->array = kmem_zalloc(rbp->array_len * sizeof (nfs_resop4),
586 602 KM_SLEEP);
587 603 resop = &rbp->array[0];
588 604 resop->resop = argsp->array[0].argop; /* copy first op over */
589 605
590 606 /* Any op will do, just need to access status field */
591 607 resp = &resop->nfs_resop4_u.opputfh;
592 608
593 609 /*
594 610 * NFS4ERR_RESOURCE is allowed for all ops, except OP_ILLEGAL.
595 611 * Note that all op numbers in the compound array were already
596 612 * validated by the XDR decoder (xdr_COMPOUND4args_srv()).
597 613 */
598 614 resp->status = (resop->resop == OP_ILLEGAL ?
599 615 NFS4ERR_OP_ILLEGAL : NFS4ERR_RESOURCE);
600 616
601 617 /* compound status is same as first op status */
602 618 rbp->status = resp->status;
603 619
604 620 if (!svc_sendreply(req->rq_xprt, xdr_COMPOUND4res_srv, (char *)rbp)) {
605 621 DTRACE_PROBE2(nfss__rsrc_err__sendfail,
606 622 struct svc_req *, req->rq_xprt, char *, rbp);
607 623 svcerr_systemerr(req->rq_xprt);
608 624 }
609 625
610 626 UTF8STRING_FREE(rbp->tag);
611 627 kmem_free(rbp->array, rbp->array_len * sizeof (nfs_resop4));
612 628 }
|
↓ open down ↓ |
102 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX