1/* 2 Unix SMB/Netbios implementation. 3 Version 1.9. 4 read/write to a files_struct 5 Copyright (C) Andrew Tridgell 1992-1998 6 Copyright (C) Jeremy Allison 2000-2002. - write cache. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22#include "includes.h" 23#include "smbd/globals.h" 24 25static bool setup_write_cache(files_struct *, SMB_OFF_T); 26 27/**************************************************************************** 28 Read from write cache if we can. 29****************************************************************************/ 30 31static bool read_from_write_cache(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) 32{ 33 write_cache *wcp = fsp->wcp; 34 35 if(!wcp) { 36 return False; 37 } 38 39 if( n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size) { 40 return False; 41 } 42 43 memcpy(data, wcp->data + (pos - wcp->offset), n); 44 45 DO_PROFILE_INC(writecache_read_hits); 46 47 return True; 48} 49 50/**************************************************************************** 51 Read from a file. 52****************************************************************************/ 53 54ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) 55{ 56 ssize_t ret=0,readret; 57 58 /* you can't read from print files */ 59 if (fsp->print_file) { 60 errno = EBADF; 61 return -1; 62 } 63 64 /* 65 * Serve from write cache if we can. 66 */ 67 68 if(read_from_write_cache(fsp, data, pos, n)) { 69 fsp->fh->pos = pos + n; 70 fsp->fh->position_information = fsp->fh->pos; 71 return n; 72 } 73 74 flush_write_cache(fsp, READ_FLUSH); 75 76 fsp->fh->pos = pos; 77 78 if (n > 0) { 79#ifdef DMF_FIX 80 int numretries = 3; 81tryagain: 82 readret = SMB_VFS_PREAD(fsp,data,n,pos); 83 84 if (readret == -1) { 85 if ((errno == EAGAIN) && numretries) { 86 DEBUG(3,("read_file EAGAIN retry in 10 seconds\n")); 87 (void)sleep(10); 88 --numretries; 89 goto tryagain; 90 } 91 return -1; 92 } 93#else /* NO DMF fix. */ 94 readret = SMB_VFS_PREAD(fsp,data,n,pos); 95 96 if (readret == -1) { 97 return -1; 98 } 99#endif 100 if (readret > 0) { 101 ret += readret; 102 } 103 } 104 105 DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n", 106 fsp_str_dbg(fsp), (double)pos, (unsigned long)n, (long)ret)); 107 108 fsp->fh->pos += ret; 109 fsp->fh->position_information = fsp->fh->pos; 110 111 return(ret); 112} 113 114/**************************************************************************** 115 *Really* write to a file. 116****************************************************************************/ 117 118static ssize_t real_write_file(struct smb_request *req, 119 files_struct *fsp, 120 const char *data, 121 SMB_OFF_T pos, 122 size_t n) 123{ 124 ssize_t ret; 125 126 if (pos == -1) { 127 ret = vfs_write_data(req, fsp, data, n); 128 } else { 129 fsp->fh->pos = pos; 130 if (pos && lp_strict_allocate(SNUM(fsp->conn))) { 131 if (vfs_fill_sparse(fsp, pos) == -1) { 132 return -1; 133 } 134 } 135 ret = vfs_pwrite_data(req, fsp, data, n, pos); 136 } 137 138 DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n", 139 fsp_str_dbg(fsp), (double)pos, (unsigned long)n, (long)ret)); 140 141 if (ret != -1) { 142 fsp->fh->pos += ret; 143 144/* Yes - this is correct - writes don't update this. JRA. */ 145/* Found by Samba4 tests. */ 146#if 0 147 fsp->position_information = fsp->pos; 148#endif 149 } 150 151 return ret; 152} 153 154/**************************************************************************** 155 File size cache change. 156 Updates size on disk but doesn't flush the cache. 157****************************************************************************/ 158 159static int wcp_file_size_change(files_struct *fsp) 160{ 161 int ret; 162 write_cache *wcp = fsp->wcp; 163 164 wcp->file_size = wcp->offset + wcp->data_size; 165 ret = SMB_VFS_FTRUNCATE(fsp, wcp->file_size); 166 if (ret == -1) { 167 DEBUG(0,("wcp_file_size_change (%s): ftruncate of size %.0f " 168 "error %s\n", fsp_str_dbg(fsp), 169 (double)wcp->file_size, strerror(errno))); 170 } 171 return ret; 172} 173 174void update_write_time_handler(struct event_context *ctx, 175 struct timed_event *te, 176 struct timeval now, 177 void *private_data) 178{ 179 files_struct *fsp = (files_struct *)private_data; 180 181 DEBUG(5, ("Update write time on %s\n", fsp_str_dbg(fsp))); 182 183 /* change the write time in the open file db. */ 184 (void)set_write_time(fsp->file_id, timespec_current()); 185 186 /* And notify. */ 187 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED, 188 FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name->base_name); 189 190 /* Remove the timed event handler. */ 191 TALLOC_FREE(fsp->update_write_time_event); 192} 193 194/********************************************************* 195 Schedule a write time update for WRITE_TIME_UPDATE_USEC_DELAY 196 in the future. 197*********************************************************/ 198 199void trigger_write_time_update(struct files_struct *fsp) 200{ 201 int delay; 202 203 if (fsp->posix_open) { 204 /* Don't use delayed writes on POSIX files. */ 205 return; 206 } 207 208 if (fsp->write_time_forced) { 209 /* No point - "sticky" write times 210 * in effect. 211 */ 212 return; 213 } 214 215 /* We need to remember someone did a write 216 * and update to current time on close. */ 217 218 fsp->update_write_time_on_close = true; 219 220 if (fsp->update_write_time_triggered) { 221 /* 222 * We only update the write time after 2 seconds 223 * on the first normal write. After that 224 * no other writes affect this until close. 225 */ 226 return; 227 } 228 fsp->update_write_time_triggered = true; 229 230 delay = lp_parm_int(SNUM(fsp->conn), 231 "smbd", "writetimeupdatedelay", 232 WRITE_TIME_UPDATE_USEC_DELAY); 233 234 DEBUG(5, ("Update write time %d usec later on %s\n", 235 delay, fsp_str_dbg(fsp))); 236 237 /* trigger the update 2 seconds later */ 238 fsp->update_write_time_event = 239 event_add_timed(smbd_event_context(), NULL, 240 timeval_current_ofs(0, delay), 241 update_write_time_handler, fsp); 242} 243 244void trigger_write_time_update_immediate(struct files_struct *fsp) 245{ 246 struct smb_file_time ft; 247 248 if (fsp->posix_open) { 249 /* Don't use delayed writes on POSIX files. */ 250 return; 251 } 252 253 if (fsp->write_time_forced) { 254 /* 255 * No point - "sticky" write times 256 * in effect. 257 */ 258 return; 259 } 260 261 TALLOC_FREE(fsp->update_write_time_event); 262 DEBUG(5, ("Update write time immediate on %s\n", 263 fsp_str_dbg(fsp))); 264 265 /* After an immediate update, reset the trigger. */ 266 fsp->update_write_time_triggered = true; 267 fsp->update_write_time_on_close = false; 268 269 ZERO_STRUCT(ft); 270 ft.mtime = timespec_current(); 271 272 /* Update the time in the open file db. */ 273 (void)set_write_time(fsp->file_id, ft.mtime); 274 275 /* Now set on disk - takes care of notify. */ 276 (void)smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, false); 277} 278 279/**************************************************************************** 280 Write to a file. 281****************************************************************************/ 282 283ssize_t write_file(struct smb_request *req, 284 files_struct *fsp, 285 const char *data, 286 SMB_OFF_T pos, 287 size_t n) 288{ 289 write_cache *wcp = fsp->wcp; 290 ssize_t total_written = 0; 291 int write_path = -1; 292 293 if (fsp->print_file) { 294 uint32 jobid; 295 296 if (!rap_to_pjobid(fsp->rap_print_jobid, NULL, &jobid)) { 297 DEBUG(3,("write_file: Unable to map RAP jobid %u to jobid.\n", 298 (unsigned int)fsp->rap_print_jobid )); 299 errno = EBADF; 300 return -1; 301 } 302 303 return print_job_write(SNUM(fsp->conn), jobid, data, pos, n); 304 } 305 306 if (!fsp->can_write) { 307 errno = EPERM; 308 return -1; 309 } 310 311 if (!fsp->modified) { 312 fsp->modified = True; 313 314 if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) == 0) { 315 trigger_write_time_update(fsp); 316 if (!fsp->posix_open && 317 (lp_store_dos_attributes(SNUM(fsp->conn)) || 318 MAP_ARCHIVE(fsp->conn))) { 319 int dosmode = dos_mode(fsp->conn, fsp->fsp_name); 320 if (!IS_DOS_ARCHIVE(dosmode)) { 321 file_set_dosmode(fsp->conn, fsp->fsp_name, 322 dosmode | aARCH, NULL, false); 323 } 324 } 325 326 /* 327 * If this is the first write and we have an exclusive oplock then setup 328 * the write cache. 329 */ 330 331 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) { 332 setup_write_cache(fsp, 333 fsp->fsp_name->st.st_ex_size); 334 wcp = fsp->wcp; 335 } 336 } 337 } 338 339#ifdef WITH_PROFILE 340 DO_PROFILE_INC(writecache_total_writes); 341 if (!fsp->oplock_type) { 342 DO_PROFILE_INC(writecache_non_oplock_writes); 343 } 344#endif 345 346 /* 347 * If this file is level II oplocked then we need 348 * to grab the shared memory lock and inform all 349 * other files with a level II lock that they need 350 * to flush their read caches. We keep the lock over 351 * the shared memory area whilst doing this. 352 */ 353 354 /* This should actually be improved to span the write. */ 355 contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE); 356 contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE); 357 358#ifdef WITH_PROFILE 359 if (profile_p && profile_p->writecache_total_writes % 500 == 0) { 360 DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \ 361nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", 362 profile_p->writecache_init_writes, 363 profile_p->writecache_abutted_writes, 364 profile_p->writecache_total_writes, 365 profile_p->writecache_non_oplock_writes, 366 profile_p->writecache_allocated_write_caches, 367 profile_p->writecache_num_write_caches, 368 profile_p->writecache_direct_writes, 369 profile_p->writecache_num_perfect_writes, 370 profile_p->writecache_read_hits )); 371 372 DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n", 373 profile_p->writecache_flushed_writes[SEEK_FLUSH], 374 profile_p->writecache_flushed_writes[READ_FLUSH], 375 profile_p->writecache_flushed_writes[WRITE_FLUSH], 376 profile_p->writecache_flushed_writes[READRAW_FLUSH], 377 profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH], 378 profile_p->writecache_flushed_writes[CLOSE_FLUSH], 379 profile_p->writecache_flushed_writes[SYNC_FLUSH] )); 380 } 381#endif 382 383 if (wcp && req->unread_bytes) { 384 /* If we're using receivefile don't 385 * deal with a write cache. 386 */ 387 flush_write_cache(fsp, WRITE_FLUSH); 388 delete_write_cache(fsp); 389 wcp = NULL; 390 } 391 392 if(!wcp) { 393 DO_PROFILE_INC(writecache_direct_writes); 394 total_written = real_write_file(req, fsp, data, pos, n); 395 return total_written; 396 } 397 398 DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f " 399 "wcp->data_size=%u\n", fsp_str_dbg(fsp), fsp->fh->fd, 400 (double)pos, (unsigned int)n, (double)wcp->offset, 401 (unsigned int)wcp->data_size)); 402 403 fsp->fh->pos = pos + n; 404 405 /* 406 * If we have active cache and it isn't contiguous then we flush. 407 * NOTE: There is a small problem with running out of disk .... 408 */ 409 410 if (wcp->data_size) { 411 bool cache_flush_needed = False; 412 413 if ((pos >= wcp->offset) && (pos <= wcp->offset + wcp->data_size)) { 414 415 /* ASCII art.... JRA. 416 417 +--------------+----- 418 | Cached data | Rest of allocated cache buffer.... 419 +--------------+----- 420 421 +-------------------+ 422 | Data to write | 423 +-------------------+ 424 425 */ 426 427 /* 428 * Start of write overlaps or abutts the existing data. 429 */ 430 431 size_t data_used = MIN((wcp->alloc_size - (pos - wcp->offset)), n); 432 433 memcpy(wcp->data + (pos - wcp->offset), data, data_used); 434 435 /* 436 * Update the current buffer size with the new data. 437 */ 438 439 if(pos + data_used > wcp->offset + wcp->data_size) { 440 wcp->data_size = pos + data_used - wcp->offset; 441 } 442 443 /* 444 * Update the file size if changed. 445 */ 446 447 if (wcp->offset + wcp->data_size > wcp->file_size) { 448 if (wcp_file_size_change(fsp) == -1) { 449 return -1; 450 } 451 } 452 453 /* 454 * If we used all the data then 455 * return here. 456 */ 457 458 if(n == data_used) { 459 return n; 460 } else { 461 cache_flush_needed = True; 462 } 463 /* 464 * Move the start of data forward by the amount used, 465 * cut down the amount left by the same amount. 466 */ 467 468 data += data_used; 469 pos += data_used; 470 n -= data_used; 471 472 DO_PROFILE_INC(writecache_abutted_writes); 473 total_written = data_used; 474 475 write_path = 1; 476 477 } else if ((pos < wcp->offset) && (pos + n > wcp->offset) && 478 (pos + n <= wcp->offset + wcp->alloc_size)) { 479 480 /* ASCII art.... JRA. 481 482 +---------------+ 483 | Cache buffer | 484 +---------------+ 485 486 +-------------------+ 487 | Data to write | 488 +-------------------+ 489 490 */ 491 492 /* 493 * End of write overlaps the existing data. 494 */ 495 496 size_t data_used = pos + n - wcp->offset; 497 498 memcpy(wcp->data, data + n - data_used, data_used); 499 500 /* 501 * Update the current buffer size with the new data. 502 */ 503 504 if(pos + n > wcp->offset + wcp->data_size) { 505 wcp->data_size = pos + n - wcp->offset; 506 } 507 508 /* 509 * Update the file size if changed. 510 */ 511 512 if (wcp->offset + wcp->data_size > wcp->file_size) { 513 if (wcp_file_size_change(fsp) == -1) { 514 return -1; 515 } 516 } 517 518 /* 519 * We don't need to move the start of data, but we 520 * cut down the amount left by the amount used. 521 */ 522 523 n -= data_used; 524 525 /* 526 * We cannot have used all the data here. 527 */ 528 529 cache_flush_needed = True; 530 531 DO_PROFILE_INC(writecache_abutted_writes); 532 total_written = data_used; 533 534 write_path = 2; 535 536 } else if ( (pos >= wcp->file_size) && 537 (wcp->offset + wcp->data_size == wcp->file_size) && 538 (pos > wcp->offset + wcp->data_size) && 539 (pos < wcp->offset + wcp->alloc_size) ) { 540 541 /* ASCII art.... JRA. 542 543 End of file ---->| 544 545 +---------------+---------------+ 546 | Cached data | Cache buffer | 547 +---------------+---------------+ 548 549 +-------------------+ 550 | Data to write | 551 +-------------------+ 552 553 */ 554 555 /* 556 * Non-contiguous write part of which fits within 557 * the cache buffer and is extending the file 558 * and the cache contents reflect the current 559 * data up to the current end of the file. 560 */ 561 562 size_t data_used; 563 564 if(pos + n <= wcp->offset + wcp->alloc_size) { 565 data_used = n; 566 } else { 567 data_used = wcp->offset + wcp->alloc_size - pos; 568 } 569 570 /* 571 * Fill in the non-continuous area with zeros. 572 */ 573 574 memset(wcp->data + wcp->data_size, '\0', 575 pos - (wcp->offset + wcp->data_size) ); 576 577 memcpy(wcp->data + (pos - wcp->offset), data, data_used); 578 579 /* 580 * Update the current buffer size with the new data. 581 */ 582 583 if(pos + data_used > wcp->offset + wcp->data_size) { 584 wcp->data_size = pos + data_used - wcp->offset; 585 } 586 587 /* 588 * Update the file size if changed. 589 */ 590 591 if (wcp->offset + wcp->data_size > wcp->file_size) { 592 if (wcp_file_size_change(fsp) == -1) { 593 return -1; 594 } 595 } 596 597 /* 598 * If we used all the data then 599 * return here. 600 */ 601 602 if(n == data_used) { 603 return n; 604 } else { 605 cache_flush_needed = True; 606 } 607 608 /* 609 * Move the start of data forward by the amount used, 610 * cut down the amount left by the same amount. 611 */ 612 613 data += data_used; 614 pos += data_used; 615 n -= data_used; 616 617 DO_PROFILE_INC(writecache_abutted_writes); 618 total_written = data_used; 619 620 write_path = 3; 621 622 } else if ( (pos >= wcp->file_size) && 623 (n == 1) && 624 (wcp->file_size == wcp->offset + wcp->data_size) && 625 (pos < wcp->file_size + wcp->alloc_size)) { 626 627 /* 628 629 End of file ---->| 630 631 +---------------+---------------+ 632 | Cached data | Cache buffer | 633 +---------------+---------------+ 634 635 |<------- allocated size ---------------->| 636 637 +--------+ 638 | 1 Byte | 639 +--------+ 640 641 MS-Office seems to do this a lot to determine if there's enough 642 space on the filesystem to write a new file. 643 644 Change to : 645 646 End of file ---->| 647 +-----------------------+--------+ 648 | Zeroed Cached data | 1 Byte | 649 +-----------------------+--------+ 650 */ 651 652 flush_write_cache(fsp, WRITE_FLUSH); 653 wcp->offset = wcp->file_size; 654 wcp->data_size = pos - wcp->file_size + 1; 655 memset(wcp->data, '\0', wcp->data_size); 656 memcpy(wcp->data + wcp->data_size-1, data, 1); 657 658 /* 659 * Update the file size if changed. 660 */ 661 662 if (wcp->offset + wcp->data_size > wcp->file_size) { 663 if (wcp_file_size_change(fsp) == -1) { 664 return -1; 665 } 666 } 667 668 return n; 669 670 } else { 671 672 /* ASCII art..... JRA. 673 674 Case 1). 675 676 +---------------+---------------+ 677 | Cached data | Cache buffer | 678 +---------------+---------------+ 679 680 +-------------------+ 681 | Data to write | 682 +-------------------+ 683 684 Case 2). 685 686 +---------------+---------------+ 687 | Cached data | Cache buffer | 688 +---------------+---------------+ 689 690 +-------------------+ 691 | Data to write | 692 +-------------------+ 693 694 Case 3). 695 696 +---------------+---------------+ 697 | Cached data | Cache buffer | 698 +---------------+---------------+ 699 700 +-----------------------------------------------------+ 701 | Data to write | 702 +-----------------------------------------------------+ 703 704 */ 705 706 /* 707 * Write is bigger than buffer, or there is no overlap on the 708 * low or high ends. 709 */ 710 711 DEBUG(9,("write_file: non cacheable write : fd = %d, pos = %.0f, len = %u, current cache pos = %.0f \ 712len = %u\n",fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size )); 713 714 /* 715 * If write would fit in the cache, and is larger than 716 * the data already in the cache, flush the cache and 717 * preferentially copy the data new data into it. Otherwise 718 * just write the data directly. 719 */ 720 721 if ( n <= wcp->alloc_size && n > wcp->data_size) { 722 cache_flush_needed = True; 723 } else { 724 ssize_t ret = real_write_file(NULL,fsp, data, pos, n); 725 726 /* 727 * If the write overlaps the entire cache, then 728 * discard the current contents of the cache. 729 * Fix from Rasmus Borup Hansen rbh@math.ku.dk. 730 */ 731 732 if ((pos <= wcp->offset) && 733 (pos + n >= wcp->offset + wcp->data_size) ) { 734 DEBUG(9,("write_file: discarding overwritten write \ 735cache: fd = %d, off=%.0f, size=%u\n", fsp->fh->fd, (double)wcp->offset, (unsigned int)wcp->data_size )); 736 wcp->data_size = 0; 737 } 738 739 DO_PROFILE_INC(writecache_direct_writes); 740 if (ret == -1) { 741 return ret; 742 } 743 744 if (pos + ret > wcp->file_size) { 745 wcp->file_size = pos + ret; 746 } 747 748 return ret; 749 } 750 751 write_path = 4; 752 753 } 754 755 if (cache_flush_needed) { 756 DEBUG(3,("WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \ 757n = %u, wcp->offset=%.0f, wcp->data_size=%u\n", 758 write_path, fsp->fh->fd, (double)wcp->file_size, (double)pos, (unsigned int)n, 759 (double)wcp->offset, (unsigned int)wcp->data_size )); 760 761 flush_write_cache(fsp, WRITE_FLUSH); 762 } 763 } 764 765 /* 766 * If the write request is bigger than the cache 767 * size, write it all out. 768 */ 769 770 if (n > wcp->alloc_size ) { 771 ssize_t ret = real_write_file(NULL,fsp, data, pos, n); 772 if (ret == -1) { 773 return -1; 774 } 775 776 if (pos + ret > wcp->file_size) { 777 wcp->file_size = pos + n; 778 } 779 780 DO_PROFILE_INC(writecache_direct_writes); 781 return total_written + n; 782 } 783 784 /* 785 * If there's any data left, cache it. 786 */ 787 788 if (n) { 789#ifdef WITH_PROFILE 790 if (wcp->data_size) { 791 DO_PROFILE_INC(writecache_abutted_writes); 792 } else { 793 DO_PROFILE_INC(writecache_init_writes); 794 } 795#endif 796 memcpy(wcp->data+wcp->data_size, data, n); 797 if (wcp->data_size == 0) { 798 wcp->offset = pos; 799 DO_PROFILE_INC(writecache_num_write_caches); 800 } 801 wcp->data_size += n; 802 803 /* 804 * Update the file size if changed. 805 */ 806 807 if (wcp->offset + wcp->data_size > wcp->file_size) { 808 if (wcp_file_size_change(fsp) == -1) { 809 return -1; 810 } 811 } 812 DEBUG(9,("wcp->offset = %.0f wcp->data_size = %u cache return %u\n", 813 (double)wcp->offset, (unsigned int)wcp->data_size, (unsigned int)n)); 814 815 total_written += n; 816 return total_written; /* .... that's a write :) */ 817 } 818 819 return total_written; 820} 821 822/**************************************************************************** 823 Delete the write cache structure. 824****************************************************************************/ 825 826void delete_write_cache(files_struct *fsp) 827{ 828 write_cache *wcp; 829 830 if(!fsp) { 831 return; 832 } 833 834 if(!(wcp = fsp->wcp)) { 835 return; 836 } 837 838 DO_PROFILE_DEC(writecache_allocated_write_caches); 839 allocated_write_caches--; 840 841 SMB_ASSERT(wcp->data_size == 0); 842 843 SAFE_FREE(wcp->data); 844 SAFE_FREE(fsp->wcp); 845 846 DEBUG(10,("delete_write_cache: File %s deleted write cache\n", 847 fsp_str_dbg(fsp))); 848} 849 850/**************************************************************************** 851 Setup the write cache structure. 852****************************************************************************/ 853 854static bool setup_write_cache(files_struct *fsp, SMB_OFF_T file_size) 855{ 856 ssize_t alloc_size = lp_write_cache_size(SNUM(fsp->conn)); 857 write_cache *wcp; 858 859 if (allocated_write_caches >= MAX_WRITE_CACHES) { 860 return False; 861 } 862 863 if(alloc_size == 0 || fsp->wcp) { 864 return False; 865 } 866 867 if((wcp = SMB_MALLOC_P(write_cache)) == NULL) { 868 DEBUG(0,("setup_write_cache: malloc fail.\n")); 869 return False; 870 } 871 872 wcp->file_size = file_size; 873 wcp->offset = 0; 874 wcp->alloc_size = alloc_size; 875 wcp->data_size = 0; 876 if((wcp->data = (char *)SMB_MALLOC(wcp->alloc_size)) == NULL) { 877 DEBUG(0,("setup_write_cache: malloc fail for buffer size %u.\n", 878 (unsigned int)wcp->alloc_size )); 879 SAFE_FREE(wcp); 880 return False; 881 } 882 883 memset(wcp->data, '\0', wcp->alloc_size ); 884 885 fsp->wcp = wcp; 886 DO_PROFILE_INC(writecache_allocated_write_caches); 887 allocated_write_caches++; 888 889 DEBUG(10,("setup_write_cache: File %s allocated write cache size %lu\n", 890 fsp_str_dbg(fsp), (unsigned long)wcp->alloc_size)); 891 892 return True; 893} 894 895/**************************************************************************** 896 Cope with a size change. 897****************************************************************************/ 898 899void set_filelen_write_cache(files_struct *fsp, SMB_OFF_T file_size) 900{ 901 if(fsp->wcp) { 902 /* The cache *must* have been flushed before we do this. */ 903 if (fsp->wcp->data_size != 0) { 904 char *msg; 905 if (asprintf(&msg, "set_filelen_write_cache: size change " 906 "on file %s with write cache size = %lu\n", 907 fsp->fsp_name->base_name, 908 (unsigned long)fsp->wcp->data_size) != -1) { 909 smb_panic(msg); 910 } else { 911 smb_panic("set_filelen_write_cache"); 912 } 913 } 914 fsp->wcp->file_size = file_size; 915 } 916} 917 918/******************************************************************* 919 Flush a write cache struct to disk. 920********************************************************************/ 921 922ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason) 923{ 924 write_cache *wcp = fsp->wcp; 925 size_t data_size; 926 ssize_t ret; 927 928 if(!wcp || !wcp->data_size) { 929 return 0; 930 } 931 932 data_size = wcp->data_size; 933 wcp->data_size = 0; 934 935 DO_PROFILE_DEC_INC(writecache_num_write_caches,writecache_flushed_writes[reason]); 936 937 DEBUG(9,("flushing write cache: fd = %d, off=%.0f, size=%u\n", 938 fsp->fh->fd, (double)wcp->offset, (unsigned int)data_size)); 939 940#ifdef WITH_PROFILE 941 if(data_size == wcp->alloc_size) { 942 DO_PROFILE_INC(writecache_num_perfect_writes); 943 } 944#endif 945 946 ret = real_write_file(NULL, fsp, wcp->data, wcp->offset, data_size); 947 948 /* 949 * Ensure file size if kept up to date if write extends file. 950 */ 951 952 if ((ret != -1) && (wcp->offset + ret > wcp->file_size)) { 953 wcp->file_size = wcp->offset + ret; 954 } 955 956 return ret; 957} 958 959/******************************************************************* 960sync a file 961********************************************************************/ 962 963NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, bool write_through) 964{ 965 if (fsp->fh->fd == -1) 966 return NT_STATUS_INVALID_HANDLE; 967 968 if (lp_strict_sync(SNUM(conn)) && 969 (lp_syncalways(SNUM(conn)) || write_through)) { 970 int ret = flush_write_cache(fsp, SYNC_FLUSH); 971 if (ret == -1) { 972 return map_nt_error_from_unix(errno); 973 } 974 ret = SMB_VFS_FSYNC(fsp); 975 if (ret == -1) { 976 return map_nt_error_from_unix(errno); 977 } 978 } 979 return NT_STATUS_OK; 980} 981 982/************************************************************ 983 Perform a stat whether a valid fd or not. 984************************************************************/ 985 986int fsp_stat(files_struct *fsp) 987{ 988 if (fsp->fh->fd == -1) { 989 if (fsp->posix_open) { 990 return SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name); 991 } else { 992 return SMB_VFS_STAT(fsp->conn, fsp->fsp_name); 993 } 994 } else { 995 return SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st); 996 } 997} 998