Print this page
5513 KM_NORMALPRI should be documented in kmem_alloc(9f) and kmem_cache_create(9f) man pages
14465 Present KM_NOSLEEP_LAZY as documented interface
Change-Id: I002ec28ddf390650f1fcba1ca94f6abfdb241439
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c
+++ new/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 13 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
14 14 */
15 15
16 16 /*
17 17 * Support functions for smb2_ioctl/fsctl codes:
18 18 * FSCTL_SRV_OFFLOAD_READ
19 19 * FSCTL_SRV_OFFLOAD_WRITE
20 20 * (and related)
21 21 */
22 22
23 23 #include <smbsrv/smb2_kproto.h>
24 24 #include <smbsrv/smb_fsops.h>
25 25 #include <smb/winioctl.h>
26 26
27 27 /*
28 28 * Summary of how offload data transfer works:
29 29 *
30 30 * The client drives a server-side copy. Outline:
31 31 * 1: open src_file
32 32 * 2: create dst_file and set its size
33 33 * 3: while src_file not all copied {
34 34 * offload_read(src_file, &token);
35 35 * while token not all copied {
36 36 * offload_write(dst_file, token);
37 37 * }
38 38 * }
39 39 *
40 40 * Each "offload read" request returns a "token" representing some
41 41 * portion of the source file. The server decides what kind of
42 42 * token to use, and how much of the source file it should cover.
43 43 * The length represented may be less then the client requested.
44 44 * No data are copied during offload_read (just meta-data).
45 45 *
46 46 * Each "offload write" request copies some portion of the data
47 47 * represented by the "token" into the output file. The amount
48 48 * of data copied may be less than the client requested, and the
49 49 * client keeps sending offload write requests until they have
50 50 * copied all the data represented by the current token.
51 51 */
52 52
53 53 /* [MS-FSA] OFFLOAD_READ_FLAG_ALL_ZERO_BEYOND_CURRENT_RANGE */
54 54 #define OFFLOAD_READ_FLAG_ALL_ZERO_BEYOND 1
55 55
56 56 /*
57 57 * [MS-FSCC] 2.3.79 STORAGE_OFFLOAD_TOKEN
58 58 * Note reserved: 0xFFFF0002 – 0xFFFFFFFF
59 59 *
60 60 * ...TOKEN_TYPE_ZERO_DATA: A well-known Token that indicates ...
61 61 * (offload write should just zero to the destination)
62 62 * The payload (tok_other) is ignored with this type.
63 63 */
64 64 #define STORAGE_OFFLOAD_TOKEN_TYPE_ZERO_DATA 0xFFFF0001
65 65
66 66 /* Our vendor-specific token type: struct tok_native1 */
67 67 #define STORAGE_OFFLOAD_TOKEN_TYPE_NATIVE1 0x10001
68 68
69 69 #define TOKEN_TOTAL_SIZE 512
70 70 #define TOKEN_MAX_PAYLOAD 504 /* 512 - 8 */
71 71
72 72 /* This mask is for sanity checking offsets etc. */
73 73 #define OFFMASK ((uint64_t)DEV_BSIZE-1)
74 74
75 75 typedef struct smb_odx_token {
76 76 uint32_t tok_type; /* big-endian on the wire */
77 77 uint16_t tok_reserved; /* zero */
78 78 uint16_t tok_len; /* big-endian on the wire */
79 79 union {
80 80 uint8_t u_tok_other[TOKEN_MAX_PAYLOAD];
81 81 struct tok_native1 {
82 82 smb2fid_t tn1_fid;
83 83 uint64_t tn1_off;
84 84 uint64_t tn1_eof;
85 85 } u_tok_native1;
86 86 } tok_u;
87 87 } smb_odx_token_t;
88 88
89 89 typedef struct odx_write_args {
90 90 uint32_t in_struct_size;
91 91 uint32_t in_flags;
92 92 uint64_t in_dstoff;
93 93 uint64_t in_xlen;
94 94 uint64_t in_xoff;
95 95 uint32_t out_struct_size;
96 96 uint32_t out_flags;
97 97 uint64_t out_xlen;
98 98 uint64_t wa_eof;
99 99 } odx_write_args_t;
100 100
101 101 static int smb_odx_get_token(mbuf_chain_t *, smb_odx_token_t *);
102 102 static int smb_odx_get_token_native1(mbuf_chain_t *, struct tok_native1 *);
103 103 static int smb_odx_put_token(mbuf_chain_t *, smb_odx_token_t *);
104 104 static int smb_odx_put_token_native1(mbuf_chain_t *, struct tok_native1 *);
105 105
106 106 static uint32_t smb2_fsctl_odx_write_zeros(smb_request_t *, odx_write_args_t *);
107 107 static uint32_t smb2_fsctl_odx_write_native1(smb_request_t *,
108 108 odx_write_args_t *, smb_odx_token_t *);
109 109
110 110
111 111 /* We can disable this feature for testing etc. */
112 112 int smb2_odx_enable = 1;
113 113
114 114 /*
115 115 * These two variables determine the intervals of offload_read and
116 116 * offload_write calls (respectively) during an offload copy.
117 117 *
118 118 * For the offload read token we could offer a token representing
119 119 * the whole file, but we'll have the client come back for a new
120 120 * "token" after each 256M so we have a chance to look for "holes".
121 121 * This lets us use the special "zero" token while we're in any
122 122 * un-allocated parts of the file, so offload_write can use the
123 123 * (more efficient) smb_fsop_freesp instead of copying.
124 124 *
125 125 * We limit the size of offload_write to 16M per request so we
126 126 * don't end up taking so long with I/O that the client might
127 127 * time out the request. Keep: write_max <= read_max
128 128 */
129 129 uint32_t smb2_odx_read_max = (1<<28); /* 256M */
130 130 uint32_t smb2_odx_write_max = (1<<24); /* 16M */
131 131
132 132 /*
133 133 * This buffer size determines the I/O size for the copy during
134 134 * offoad write, where it will read/write using this buffer.
135 135 * Note: We kmem_alloc this, so don't make it HUGE. It only
136 136 * needs to be large enough to allow the copy to proceed with
137 137 * reasonable efficiency. 1M is currently the largest possible
138 138 * block size with ZFS, so that's what we'll use here.
139 139 */
140 140 uint32_t smb2_odx_buf_size = (1<<20); /* 1M */
141 141
142 142
143 143 /*
144 144 * FSCTL_OFFLOAD_READ
145 145 * [MS-FSCC] 2.3.77
146 146 *
147 147 * Similar (in concept) to FSCTL_SRV_REQUEST_RESUME_KEY
148 148 *
149 149 * The returned data is an (opaque to the client) 512-byte "token"
150 150 * that represents the specified range (offset, length) of the
151 151 * source file. The "token" we return here comes back to us in an
152 152 * FSCTL_OFFLOAD_READ. We must stash whatever we'll need then in
153 153 * the token we return here.
154 154 *
155 155 * We want server-side copy to be able to copy "holes" efficiently,
156 156 * but would rather avoid the complexity of encoding a list of all
157 157 * allocated ranges into our returned token, so this compromise:
158 158 *
159 159 * When the current range is entirely within a "hole", we'll return
160 160 * the special "zeros" token, and the offload write using that token
161 161 * will use the simple and very efficient smb_fsop_freesp. In this
162 162 * scenario, we'll have a copy stride of smb2_odx_read_max (256M).
163 163 *
164 164 * When there's any data in the range to copy, we'll return our
165 165 * "native" token, and the subsequent offload_write will walk the
166 166 * allocated ranges copying and/or zeroing as needed. In this
167 167 * scenario, we'll have a copy stride of smb2_odx_write_max (16M).
168 168 *
169 169 * One additional optimization allowed by the protocol is that when
170 170 * we discover that there's no more data after the current range,
171 171 * we can set the flag ..._ALL_ZERO_BEYOND which tells that client
172 172 * they can stop copying here if they like.
173 173 */
174 174 uint32_t
175 175 smb2_fsctl_odx_read(smb_request_t *sr, smb_fsctl_t *fsctl)
176 176 {
177 177 smb_attr_t src_attr;
178 178 smb_odx_token_t *tok = NULL;
179 179 struct tok_native1 *tn1;
180 180 smb_ofile_t *ofile = sr->fid_ofile;
181 181 uint64_t src_size, src_rnd_size;
182 182 off64_t data, hole;
183 183 uint32_t in_struct_size;
184 184 uint32_t in_flags;
185 185 uint32_t in_ttl;
186 186 uint64_t in_file_off;
187 187 uint64_t in_copy_len;
188 188 uint64_t out_xlen;
189 189 uint32_t out_struct_size = TOKEN_TOTAL_SIZE + 16;
190 190 uint32_t out_flags = 0;
191 191 uint32_t status;
192 192 uint32_t tok_type;
193 193 int rc;
194 194
195 195 if (smb2_odx_enable == 0)
196 196 return (NT_STATUS_NOT_SUPPORTED);
197 197
198 198 /*
199 199 * Make sure the (src) ofile granted access allows read.
200 200 * [MS-FSA] didn't mention this, so it's not clear where
201 201 * this should happen relative to other checks. Usually
202 202 * access checks happen early.
203 203 */
204 204 status = smb_ofile_access(ofile, ofile->f_cr, FILE_READ_DATA);
205 205 if (status != NT_STATUS_SUCCESS)
206 206 return (status);
207 207
208 208 /*
209 209 * Decode FSCTL_OFFLOAD_READ_INPUT struct,
210 210 * and do in/out size checks.
211 211 */
212 212 rc = smb_mbc_decodef(
213 213 fsctl->in_mbc, "lll4.qq",
214 214 &in_struct_size, /* l */
215 215 &in_flags, /* l */
216 216 &in_ttl, /* l */
217 217 /* reserved 4. */
218 218 &in_file_off, /* q */
219 219 &in_copy_len); /* q */
220 220 if (rc != 0)
221 221 return (NT_STATUS_BUFFER_TOO_SMALL);
222 222 if (fsctl->MaxOutputResp < out_struct_size)
223 223 return (NT_STATUS_BUFFER_TOO_SMALL);
224 224
225 225 /*
226 226 * More arg checking per MS-FSA
227 227 */
228 228 if ((in_file_off & OFFMASK) != 0 ||
229 229 (in_copy_len & OFFMASK) != 0)
230 230 return (NT_STATUS_INVALID_PARAMETER);
231 231 if (in_struct_size != 32)
232 232 return (NT_STATUS_INVALID_PARAMETER);
233 233 if (in_file_off > INT64_MAX ||
234 234 (in_file_off + in_copy_len) < in_file_off)
235 235 return (NT_STATUS_INVALID_PARAMETER);
236 236
237 237 /*
238 238 * [MS-FSA] (summarizing)
239 239 * If not data stream, or if sparse, encrypted, compressed...
240 240 * return STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED.
241 241 *
242 242 * We'll ignore most of those except to require:
243 243 * Plain file, not a stream.
244 244 */
245 245 if (!smb_node_is_file(ofile->f_node))
246 246 return (NT_STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED);
247 247 if (SMB_IS_STREAM(ofile->f_node))
248 248 return (NT_STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED);
249 249
250 250 /*
251 251 * [MS-FSA] If Open.Stream.IsDeleted ...
252 252 * We don't really have this.
253 253 */
254 254
255 255 /*
256 256 * If CopyLength == 0, "return immediately success".
257 257 */
258 258 if (in_copy_len == 0) {
259 259 out_xlen = 0;
260 260 tok_type = STORAGE_OFFLOAD_TOKEN_TYPE_ZERO_DATA;
261 261 goto done;
262 262 }
263 263
264 264 /*
265 265 * Check for lock conflicting with the read.
266 266 */
267 267 status = smb_lock_range_access(sr, ofile->f_node,
268 268 in_file_off, in_copy_len, B_FALSE);
269 269 if (status != 0)
270 270 return (status); /* == FILE_LOCK_CONFLICT */
271 271
272 272 /*
273 273 * Get the file size (rounded to a full block)
274 274 * and check the requested offset.
275 275 */
276 276 bzero(&src_attr, sizeof (src_attr));
277 277 src_attr.sa_mask = SMB_AT_SIZE;
278 278 status = smb2_ofile_getattr(sr, ofile, &src_attr);
279 279 if (status != NT_STATUS_SUCCESS)
280 280 return (status);
281 281 src_size = src_attr.sa_vattr.va_size;
282 282 if (in_file_off >= src_size)
283 283 return (NT_STATUS_END_OF_FILE);
284 284
285 285 /*
286 286 * Limit the transfer length based on (rounded) EOF.
287 287 * Clients expect ranges of whole disk blocks.
288 288 * If we get a read in this rounded-up range,
289 289 * we'll supply zeros.
290 290 */
291 291 src_rnd_size = (src_size + OFFMASK) & ~OFFMASK;
292 292 out_xlen = in_copy_len;
293 293 if ((in_file_off + out_xlen) > src_rnd_size)
294 294 out_xlen = src_rnd_size - in_file_off;
295 295
296 296 /*
297 297 * Also, have the client come back for a new token after every
298 298 * smb2_odx_read_max bytes, so we'll have opportunities to
299 299 * recognize "holes" in the source file.
300 300 */
301 301 if (out_xlen > smb2_odx_read_max)
302 302 out_xlen = smb2_odx_read_max;
303 303
304 304 /*
305 305 * Ask the filesystem if there are any allocated regions in
306 306 * the requested range, and return either the "zeros" token
307 307 * or our "native" token as appropriate (details above).
308 308 */
309 309 data = in_file_off;
310 310 tok_type = STORAGE_OFFLOAD_TOKEN_TYPE_NATIVE1;
311 311 rc = smb_fsop_next_alloc_range(ofile->f_cr, ofile->f_node,
312 312 &data, &hole);
313 313 switch (rc) {
314 314 case 0:
315 315 /* Found some data. Is it beyond this range? */
316 316 if (data >= (in_file_off + out_xlen))
317 317 tok_type = STORAGE_OFFLOAD_TOKEN_TYPE_ZERO_DATA;
318 318 break;
319 319 case ENXIO:
320 320 /* No data here or following. */
321 321 tok_type = STORAGE_OFFLOAD_TOKEN_TYPE_ZERO_DATA;
322 322 out_flags |= OFFLOAD_READ_FLAG_ALL_ZERO_BEYOND;
323 323 break;
324 324 case ENOSYS: /* FS does not support VOP_IOCTL... */
325 325 case ENOTTY: /* ... or _FIO_SEEK_DATA, _HOLE */
326 326 break;
327 327 default:
328 328 cmn_err(CE_NOTE, "smb_fsop_next_alloc_range: rc=%d", rc);
329 329 break;
330 330 }
331 331
332 332 done:
333 333 /* Already checked MaxOutputResp */
334 334 (void) smb_mbc_encodef(
335 335 fsctl->out_mbc, "llq",
336 336 out_struct_size, /* l */
337 337 out_flags, /* l */
338 338 out_xlen); /* q */
339 339
340 340 /*
341 341 * Build the ODX token to return
342 342 */
343 343 tok = smb_srm_zalloc(sr, sizeof (*tok));
344 344 tok->tok_type = tok_type;
345 345 tok->tok_reserved = 0;
346 346 if (tok_type == STORAGE_OFFLOAD_TOKEN_TYPE_NATIVE1) {
347 347 tok->tok_len = sizeof (*tn1);
348 348 tn1 = &tok->tok_u.u_tok_native1;
349 349 tn1->tn1_fid.persistent = ofile->f_persistid;
350 350 tn1->tn1_fid.temporal = ofile->f_fid;
351 351 tn1->tn1_off = in_file_off;
352 352 tn1->tn1_eof = src_size;
353 353 }
354 354
355 355 rc = smb_odx_put_token(fsctl->out_mbc, tok);
356 356 if (rc != 0)
357 357 return (NT_STATUS_BUFFER_TOO_SMALL);
358 358
359 359 return (NT_STATUS_SUCCESS);
360 360 }
361 361
362 362 /*
363 363 * FSCTL_SRV_OFFLOAD_WRITE
364 364 * [MS-FSCC] 2.3.80
365 365 *
366 366 * Similar (in concept) to FSCTL_COPYCHUNK_WRITE
367 367 *
368 368 * Copies from a source file identified by a "token"
369 369 * (previously returned by FSCTL_OFFLOAD_READ)
370 370 * to the file on which the ioctl is issued.
371 371 */
372 372 uint32_t
373 373 smb2_fsctl_odx_write(smb_request_t *sr, smb_fsctl_t *fsctl)
374 374 {
375 375 smb_attr_t dst_attr;
376 376 odx_write_args_t args;
377 377 smb_odx_token_t *tok = NULL;
378 378 smb_ofile_t *ofile = sr->fid_ofile;
379 379 uint64_t dst_rnd_size;
380 380 uint32_t status = NT_STATUS_INVALID_PARAMETER;
381 381 int rc;
382 382
383 383 bzero(&args, sizeof (args));
384 384 args.out_struct_size = 16;
385 385
386 386 if (smb2_odx_enable == 0)
387 387 return (NT_STATUS_NOT_SUPPORTED);
388 388
389 389 /*
390 390 * Make sure the (dst) ofile granted_access allows write.
391 391 * [MS-FSA] didn't mention this, so it's not clear where
392 392 * this should happen relative to other checks. Usually
393 393 * access checks happen early.
394 394 */
395 395 status = smb_ofile_access(ofile, ofile->f_cr, FILE_WRITE_DATA);
396 396 if (status != NT_STATUS_SUCCESS)
397 397 return (status);
398 398
399 399 /*
400 400 * Decode FSCTL_OFFLOAD_WRITE_INPUT struct,
401 401 * and do in/out size checks.
402 402 */
403 403 rc = smb_mbc_decodef(
404 404 fsctl->in_mbc, "llqqq",
405 405 &args.in_struct_size, /* l */
406 406 &args.in_flags, /* l */
407 407 &args.in_dstoff, /* q */
408 408 &args.in_xlen, /* q */
409 409 &args.in_xoff); /* q */
410 410 if (rc != 0)
411 411 return (NT_STATUS_BUFFER_TOO_SMALL);
412 412 tok = smb_srm_zalloc(sr, sizeof (*tok));
413 413 rc = smb_odx_get_token(fsctl->in_mbc, tok);
414 414 if (rc != 0)
415 415 return (NT_STATUS_BUFFER_TOO_SMALL);
416 416 if (fsctl->MaxOutputResp < args.out_struct_size)
417 417 return (NT_STATUS_BUFFER_TOO_SMALL);
418 418
419 419 /*
420 420 * More arg checking per MS-FSA
421 421 */
422 422 if ((args.in_dstoff & OFFMASK) != 0 ||
423 423 (args.in_xoff & OFFMASK) != 0 ||
424 424 (args.in_xlen & OFFMASK) != 0)
425 425 return (NT_STATUS_INVALID_PARAMETER);
426 426 if (args.in_struct_size != (TOKEN_TOTAL_SIZE + 32))
427 427 return (NT_STATUS_INVALID_PARAMETER);
428 428 if (args.in_dstoff > INT64_MAX ||
429 429 (args.in_dstoff + args.in_xlen) < args.in_dstoff)
430 430 return (NT_STATUS_INVALID_PARAMETER);
431 431
432 432 /*
433 433 * If CopyLength == 0, "return immediately success".
434 434 */
435 435 if (args.in_xlen == 0) {
436 436 status = 0;
437 437 goto done;
438 438 }
439 439
440 440 /*
441 441 * [MS-FSA] (summarizing)
442 442 * If not data stream, or if sparse, encrypted, compressed...
443 443 * return STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED.
444 444 *
445 445 * We'll ignore most of those except to require:
446 446 * Plain file, not a stream.
447 447 */
448 448 if (!smb_node_is_file(ofile->f_node))
449 449 return (NT_STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED);
450 450 if (SMB_IS_STREAM(ofile->f_node))
451 451 return (NT_STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED);
452 452
453 453 /*
454 454 * [MS-FSA] If Open.Stream.IsDeleted ...
455 455 * We don't really have such a thing.
456 456 * Also skip Volume.MaxFileSize check.
457 457 */
458 458
459 459 /*
460 460 * Check for lock conflicting with the write.
461 461 */
462 462 status = smb_lock_range_access(sr, ofile->f_node,
463 463 args.in_dstoff, args.in_xlen, B_TRUE);
464 464 if (status != 0)
465 465 return (status); /* == FILE_LOCK_CONFLICT */
466 466
467 467 /*
468 468 * Need the file size
469 469 */
470 470 bzero(&dst_attr, sizeof (dst_attr));
471 471 dst_attr.sa_mask = SMB_AT_SIZE;
472 472 status = smb2_ofile_getattr(sr, ofile, &dst_attr);
473 473 if (status != NT_STATUS_SUCCESS)
474 474 return (status);
475 475 args.wa_eof = dst_attr.sa_vattr.va_size;
476 476 dst_rnd_size = (args.wa_eof + OFFMASK) & ~OFFMASK;
477 477
478 478 /*
479 479 * Destination offset vs. EOF
480 480 */
481 481 if (args.in_dstoff >= args.wa_eof)
482 482 return (NT_STATUS_END_OF_FILE);
483 483
484 484 /*
485 485 * Destination offset+len vs. EOF
486 486 *
487 487 * The spec. is silent about copying when the file length is
488 488 * not block aligned, but clients appear to ask us to copy a
489 489 * range that's rounded up to a block size. We'll limit the
490 490 * transfer size to the rounded up file size, but the actual
491 491 * copy will stop at EOF (args.wa_eof).
492 492 */
493 493 if ((args.in_dstoff + args.in_xlen) > dst_rnd_size)
494 494 args.in_xlen = dst_rnd_size - args.in_dstoff;
495 495
496 496 /*
497 497 * Finally, run the I/O
498 498 */
499 499 switch (tok->tok_type) {
500 500 case STORAGE_OFFLOAD_TOKEN_TYPE_ZERO_DATA:
501 501 status = smb2_fsctl_odx_write_zeros(sr, &args);
502 502 break;
503 503 case STORAGE_OFFLOAD_TOKEN_TYPE_NATIVE1:
504 504 status = smb2_fsctl_odx_write_native1(sr, &args, tok);
505 505 break;
506 506 default:
507 507 status = NT_STATUS_INVALID_TOKEN;
508 508 break;
509 509 }
510 510
511 511 done:
512 512 /*
513 513 * Checked MaxOutputResp above, so we can ignore errors
514 514 * from mbc_encodef here.
515 515 */
516 516 if (status == NT_STATUS_SUCCESS) {
517 517 (void) smb_mbc_encodef(
518 518 fsctl->out_mbc, "llq",
519 519 args.out_struct_size,
520 520 args.out_flags,
521 521 args.out_xlen);
522 522 }
523 523
524 524 return (status);
525 525 }
526 526
527 527 /*
528 528 * Handle FSCTL_OFFLOAD_WRITE with token type
529 529 * STORAGE_OFFLOAD_TOKEN_TYPE_ZERO_DATA
530 530 *
531 531 * In this handler, the "token" represents a source of zeros.
532 532 */
533 533 static uint32_t
534 534 smb2_fsctl_odx_write_zeros(smb_request_t *sr, odx_write_args_t *args)
535 535 {
536 536 smb_ofile_t *dst_ofile = sr->fid_ofile;
537 537 uint64_t xlen = args->in_xlen;
538 538 uint32_t status = 0;
539 539 int rc;
540 540
541 541 ASSERT(args->in_xlen > 0);
542 542
543 543 /*
544 544 * Limit the I/O size. In here we're just doing freesp,
545 545 * which is assumed to require only meta-data I/O, so
546 546 * we'll allow up to smb2_odx_read_max (256M) per call.
547 547 * This is essentially just a double-check of the range
548 548 * we gave the client at the offload_read call, making
549 549 * sure they can't use a zero token for longer ranges
550 550 * than offload_read would allow.
551 551 */
552 552 if (xlen > smb2_odx_read_max)
553 553 xlen = smb2_odx_read_max;
554 554
555 555 /*
556 556 * Also limit to the actual file size, which may be
557 557 * smaller than the (block-aligned) transfer size.
558 558 * Report the rounded up size to the caller at EOF.
559 559 */
560 560 args->out_xlen = xlen;
561 561 if ((args->in_dstoff + xlen) > args->wa_eof)
562 562 xlen = args->wa_eof - args->in_dstoff;
563 563
564 564 /*
565 565 * Arrange for zeros to appear in the range:
566 566 * in_dstoff, (in_dstoff + in_xlen)
567 567 *
568 568 * Just "free" the range and let it allocate as needed
569 569 * when someone later writes in this range.
570 570 */
571 571 rc = smb_fsop_freesp(sr, dst_ofile->f_cr, dst_ofile,
572 572 args->in_dstoff, xlen);
573 573 if (rc != 0) {
574 574 status = smb_errno2status(rc);
575 575 if (status == NT_STATUS_INVALID_PARAMETER ||
576 576 status == NT_STATUS_NOT_SUPPORTED)
577 577 status = NT_STATUS_INVALID_DEVICE_REQUEST;
578 578 args->out_xlen = 0;
579 579 } else {
580 580 status = 0;
581 581 }
582 582
583 583 return (status);
584 584 }
585 585
586 586 /*
587 587 * Handle FSCTL_OFFLOAD_WRITE with token type
588 588 * STORAGE_OFFLOAD_TOKEN_TYPE_NATIVE1
589 589 */
590 590 static uint32_t
591 591 smb2_fsctl_odx_write_native1(smb_request_t *sr,
592 592 odx_write_args_t *args, smb_odx_token_t *tok)
593 593 {
594 594 struct tok_native1 *tn1;
595 595 smb_ofile_t *dst_ofile = sr->fid_ofile;
596 596 smb_ofile_t *src_ofile = NULL;
597 597 void *buffer = NULL;
598 598 size_t bufsize = smb2_odx_buf_size;
599 599 uint64_t src_offset;
600 600 uint32_t resid;
601 601 uint32_t xlen;
602 602 uint32_t status;
603 603
604 604 /*
605 605 * Lookup the source ofile using the resume key,
606 606 * which smb2_fsctl_offload_read encoded as an
607 607 * smb2fid_t. Similar to smb2sr_lookup_fid(),
608 608 * but different error code.
609 609 */
610 610 tn1 = &tok->tok_u.u_tok_native1;
611 611 src_ofile = smb_ofile_lookup_by_fid(sr,
612 612 (uint16_t)tn1->tn1_fid.temporal);
613 613 if (src_ofile == NULL ||
614 614 src_ofile->f_persistid != tn1->tn1_fid.persistent) {
615 615 status = NT_STATUS_INVALID_TOKEN;
616 616 goto out;
617 617 }
618 618
619 619 /*
620 620 * Make sure src_ofile is open on a regular file, and
621 621 * granted access includes READ_DATA
622 622 */
623 623 if (!smb_node_is_file(src_ofile->f_node)) {
624 624 status = NT_STATUS_ACCESS_DENIED;
625 625 goto out;
626 626 }
627 627 status = smb_ofile_access(src_ofile, src_ofile->f_cr, FILE_READ_DATA);
628 628 if (status != NT_STATUS_SUCCESS)
629 629 goto out;
630 630
631 631 /*
632 632 * Limit the I/O size. In here we're actually copying,
633 633 * so limit to smb2_odx_write_max (16M) per call.
634 634 * Note that xlen is a 32-bit value here.
635 635 */
636 636 if (args->in_xlen > smb2_odx_write_max)
637 637 xlen = smb2_odx_write_max;
638 638 else
639 639 xlen = (uint32_t)args->in_xlen;
640 640
641 641 /*
642 642 * Also limit to the actual file size, which may be
643 643 * smaller than the (block-aligned) transfer size.
644 644 * Report the rounded up size to the caller at EOF.
645 645 */
646 646 args->out_xlen = xlen;
647 647 if ((args->in_dstoff + xlen) > args->wa_eof)
648 648 xlen = (uint32_t)(args->wa_eof - args->in_dstoff);
649 649
650 650 /*
651 651 * Note: in_xoff is relative to the beginning of the "token"
652 652 * (a range of the source file tn1_off, tn1_eof). Make sure
653 653 * in_xoff is within the range represented by this token.
654 654 */
655 655 src_offset = tn1->tn1_off + args->in_xoff;
656 656 if (src_offset >= tn1->tn1_eof ||
657 657 src_offset < tn1->tn1_off) {
658 658 status = NT_STATUS_INVALID_PARAMETER;
659 659 goto out;
|
↓ open down ↓ |
659 lines elided |
↑ open up ↑ |
660 660 }
661 661
662 662 /*
663 663 * Get a buffer used for copying, always
664 664 * smb2_odx_buf_size (1M)
665 665 *
666 666 * Rather than sleep for this relatively large allocation,
667 667 * allow the allocation to fail and return an error.
668 668 * The client should then fall back to normal copy.
669 669 */
670 - buffer = kmem_alloc(bufsize, KM_NOSLEEP | KM_NORMALPRI);
670 + buffer = kmem_alloc(bufsize, KM_NOSLEEP_LAZY);
671 671 if (buffer == NULL) {
672 672 status = NT_STATUS_INSUFF_SERVER_RESOURCES;
673 673 goto out;
674 674 }
675 675
676 676 /*
677 677 * Copy src to dst for xlen
678 678 */
679 679 resid = xlen;
680 680 status = smb2_sparse_copy(sr, src_ofile, dst_ofile,
681 681 src_offset, args->in_dstoff, &resid, buffer, bufsize);
682 682
683 683 /*
684 684 * If the result was a partial copy, round down the
685 685 * reported transfer size to a block boundary.
686 686 */
687 687 if (resid != 0) {
688 688 xlen -= resid;
689 689 xlen &= ~OFFMASK;
690 690 args->out_xlen = xlen;
691 691 }
692 692
693 693 /*
694 694 * If we did any I/O, ignore the error that stopped us.
695 695 * We'll report this error during the next call.
696 696 */
697 697 if (args->out_xlen > 0)
698 698 status = 0;
699 699
700 700 out:
701 701 if (src_ofile != NULL)
702 702 smb_ofile_release(src_ofile);
703 703
704 704 if (buffer != NULL)
705 705 kmem_free(buffer, bufsize);
706 706
707 707 return (status);
708 708 }
709 709
710 710 /*
711 711 * Get an smb_odx_token_t from the (input) mbuf chain.
712 712 * Consumes exactly TOKEN_TOTAL_SIZE bytes.
713 713 */
714 714 static int
715 715 smb_odx_get_token(mbuf_chain_t *mbc, smb_odx_token_t *tok)
716 716 {
717 717 mbuf_chain_t tok_mbc;
718 718 int start_pos = mbc->chain_offset;
719 719 int rc;
720 720
721 721 if (MBC_ROOM_FOR(mbc, TOKEN_TOTAL_SIZE) == 0)
722 722 return (-1);
723 723
724 724 /*
725 725 * No big-endian support in smb_mbc_encodef, so swap
726 726 * the big-endian fields: tok_type (32-bits),
727 727 * (reserved is 16-bit zero, so no swap),
728 728 * and tok_len (16-bits)
729 729 */
730 730 rc = smb_mbc_decodef(
731 731 mbc, "l..w",
732 732 &tok->tok_type,
733 733 /* tok_reserved */
734 734 &tok->tok_len);
735 735 if (rc != 0)
736 736 return (rc);
737 737 tok->tok_type = BSWAP_32(tok->tok_type);
738 738 tok->tok_len = BSWAP_16(tok->tok_len);
739 739
740 740 if (tok->tok_len > TOKEN_MAX_PAYLOAD)
741 741 return (-1);
742 742 rc = MBC_SHADOW_CHAIN(&tok_mbc, mbc,
743 743 mbc->chain_offset, tok->tok_len);
744 744 if (rc != 0)
745 745 return (rc);
746 746
747 747 switch (tok->tok_type) {
748 748 case STORAGE_OFFLOAD_TOKEN_TYPE_ZERO_DATA:
749 749 /* no payload */
750 750 break;
751 751 case STORAGE_OFFLOAD_TOKEN_TYPE_NATIVE1:
752 752 rc = smb_odx_get_token_native1(&tok_mbc,
753 753 &tok->tok_u.u_tok_native1);
754 754 break;
755 755 default:
756 756 /* caller will error out */
757 757 break;
758 758 }
759 759
760 760 if (rc == 0) {
761 761 /* Advance past what we shadowed. */
762 762 mbc->chain_offset = start_pos + TOKEN_TOTAL_SIZE;
763 763 }
764 764
765 765 return (rc);
766 766 }
767 767
768 768 static int
769 769 smb_odx_get_token_native1(mbuf_chain_t *mbc, struct tok_native1 *tn1)
770 770 {
771 771 int rc;
772 772
773 773 rc = smb_mbc_decodef(
774 774 mbc, "qqqq",
775 775 &tn1->tn1_fid.persistent,
776 776 &tn1->tn1_fid.temporal,
777 777 &tn1->tn1_off,
778 778 &tn1->tn1_eof);
779 779
780 780 return (rc);
781 781 }
782 782
783 783 /*
784 784 * Put an smb_odx_token_t into the (output) mbuf chain,
785 785 * padded to TOKEN_TOTAL_SIZE bytes.
786 786 */
787 787 static int
788 788 smb_odx_put_token(mbuf_chain_t *mbc, smb_odx_token_t *tok)
789 789 {
790 790 int rc, padlen;
791 791 int start_pos = mbc->chain_offset;
792 792 int end_pos = start_pos + TOKEN_TOTAL_SIZE;
793 793
794 794 if (tok->tok_len > TOKEN_MAX_PAYLOAD)
795 795 return (-1);
796 796
797 797 /*
798 798 * No big-endian support in smb_mbc_encodef, so swap
799 799 * the big-endian fields: tok_type (32-bits),
800 800 * (reserved is 16-bit zero, so no swap),
801 801 * and tok_len (16-bits)
802 802 */
803 803 rc = smb_mbc_encodef(
804 804 mbc, "lww",
805 805 BSWAP_32(tok->tok_type),
806 806 0, /* tok_reserved */
807 807 BSWAP_16(tok->tok_len));
808 808 if (rc != 0)
809 809 return (rc);
810 810
811 811 switch (tok->tok_type) {
812 812 case STORAGE_OFFLOAD_TOKEN_TYPE_ZERO_DATA:
813 813 /* no payload */
814 814 break;
815 815 case STORAGE_OFFLOAD_TOKEN_TYPE_NATIVE1:
816 816 rc = smb_odx_put_token_native1(mbc,
817 817 &tok->tok_u.u_tok_native1);
818 818 break;
819 819 default:
820 820 ASSERT(0);
821 821 return (-1);
822 822 }
823 823
824 824 /* Pad out to TOKEN_TOTAL_SIZE bytes. */
825 825 if (mbc->chain_offset < end_pos) {
826 826 padlen = end_pos - mbc->chain_offset;
827 827 (void) smb_mbc_encodef(mbc, "#.", padlen);
828 828 }
829 829 ASSERT(mbc->chain_offset == end_pos);
830 830
831 831 return (rc);
832 832 }
833 833
834 834 static int
835 835 smb_odx_put_token_native1(mbuf_chain_t *mbc, struct tok_native1 *tn1)
836 836 {
837 837 int rc;
838 838
839 839 rc = smb_mbc_encodef(
840 840 mbc, "qqqq",
841 841 tn1->tn1_fid.persistent,
842 842 tn1->tn1_fid.temporal,
843 843 tn1->tn1_off,
844 844 tn1->tn1_eof);
845 845
846 846 return (rc);
847 847 }
|
↓ open down ↓ |
167 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX