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