unix_io.c revision 534a4c3db58064caee4fc3e9e294251240d9d28a
1/* 2 * unix_io.c --- This is the Unix (well, really POSIX) implementation 3 * of the I/O manager. 4 * 5 * Implements a one-block write-through cache. 6 * 7 * Includes support for Windows NT support under Cygwin. 8 * 9 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 10 * 2002 by Theodore Ts'o. 11 * 12 * %Begin-Header% 13 * This file may be redistributed under the terms of the GNU Library 14 * General Public License, version 2. 15 * %End-Header% 16 */ 17 18#define _LARGEFILE_SOURCE 19#define _LARGEFILE64_SOURCE 20#ifndef _GNU_SOURCE 21#define _GNU_SOURCE 22#endif 23 24#include <stdio.h> 25#include <string.h> 26#if HAVE_UNISTD_H 27#include <unistd.h> 28#endif 29#if HAVE_ERRNO_H 30#include <errno.h> 31#endif 32#include <fcntl.h> 33#include <time.h> 34#ifdef __linux__ 35#include <sys/utsname.h> 36#endif 37#ifdef HAVE_SYS_IOCTL_H 38#include <sys/ioctl.h> 39#endif 40#ifdef HAVE_SYS_MOUNT_H 41#include <sys/mount.h> 42#endif 43#if HAVE_SYS_STAT_H 44#include <sys/stat.h> 45#endif 46#if HAVE_SYS_TYPES_H 47#include <sys/types.h> 48#endif 49#if HAVE_SYS_RESOURCE_H 50#include <sys/resource.h> 51#endif 52 53#if defined(__linux__) && defined(_IO) && !defined(BLKROGET) 54#define BLKROGET _IO(0x12, 94) /* Get read-only status (0 = read_write). */ 55#endif 56 57#if defined(__linux__) && defined(_IO) && !defined(BLKSSZGET) 58#define BLKSSZGET _IO(0x12,104)/* get block device sector size */ 59#endif 60 61#undef ALIGN_DEBUG 62 63#include "ext2_fs.h" 64#include "ext2fs.h" 65 66/* 67 * For checking structure magic numbers... 68 */ 69 70#define EXT2_CHECK_MAGIC(struct, code) \ 71 if ((struct)->magic != (code)) return (code) 72 73struct unix_cache { 74 char *buf; 75 unsigned long block; 76 int access_time; 77 unsigned dirty:1; 78 unsigned in_use:1; 79}; 80 81#define CACHE_SIZE 8 82#define WRITE_DIRECT_SIZE 4 /* Must be smaller than CACHE_SIZE */ 83#define READ_DIRECT_SIZE 4 /* Should be smaller than CACHE_SIZE */ 84 85struct unix_private_data { 86 int magic; 87 int dev; 88 int flags; 89 int align; 90 int access_time; 91 ext2_loff_t offset; 92 struct unix_cache cache[CACHE_SIZE]; 93 void *bounce; 94 struct struct_io_stats io_stats; 95}; 96 97#define IS_ALIGNED(n, align) ((((unsigned long) n) & \ 98 ((unsigned long) ((align)-1))) == 0) 99 100static errcode_t unix_open(const char *name, int flags, io_channel *channel); 101static errcode_t unix_close(io_channel channel); 102static errcode_t unix_set_blksize(io_channel channel, int blksize); 103static errcode_t unix_read_blk(io_channel channel, unsigned long block, 104 int count, void *data); 105static errcode_t unix_write_blk(io_channel channel, unsigned long block, 106 int count, const void *data); 107static errcode_t unix_flush(io_channel channel); 108static errcode_t unix_write_byte(io_channel channel, unsigned long offset, 109 int size, const void *data); 110static errcode_t unix_set_option(io_channel channel, const char *option, 111 const char *arg); 112static errcode_t unix_get_stats(io_channel channel, io_stats *stats) 113; 114static void reuse_cache(io_channel channel, struct unix_private_data *data, 115 struct unix_cache *cache, unsigned long long block); 116static errcode_t unix_read_blk64(io_channel channel, unsigned long long block, 117 int count, void *data); 118static errcode_t unix_write_blk64(io_channel channel, unsigned long long block, 119 int count, const void *data); 120static errcode_t unix_discard(io_channel channel, unsigned long long block, 121 unsigned long long count); 122 123static struct struct_io_manager struct_unix_manager = { 124 EXT2_ET_MAGIC_IO_MANAGER, 125 "Unix I/O Manager", 126 unix_open, 127 unix_close, 128 unix_set_blksize, 129 unix_read_blk, 130 unix_write_blk, 131 unix_flush, 132 unix_write_byte, 133 unix_set_option, 134 unix_get_stats, 135 unix_read_blk64, 136 unix_write_blk64, 137 unix_discard, 138}; 139 140io_manager unix_io_manager = &struct_unix_manager; 141 142static errcode_t unix_get_stats(io_channel channel, io_stats *stats) 143{ 144 errcode_t retval = 0; 145 146 struct unix_private_data *data; 147 148 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 149 data = (struct unix_private_data *) channel->private_data; 150 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 151 152 if (stats) 153 *stats = &data->io_stats; 154 155 return retval; 156} 157 158/* 159 * Here are the raw I/O functions 160 */ 161static errcode_t raw_read_blk(io_channel channel, 162 struct unix_private_data *data, 163 unsigned long long block, 164 int count, void *buf) 165{ 166 errcode_t retval; 167 ssize_t size; 168 ext2_loff_t location; 169 int actual = 0; 170 171 size = (count < 0) ? -count : count * channel->block_size; 172 data->io_stats.bytes_read += size; 173 location = ((ext2_loff_t) block * channel->block_size) + data->offset; 174 if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 175 retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 176 goto error_out; 177 } 178 if ((data->align == 0) || 179 ((IS_ALIGNED(buf, data->align)) && IS_ALIGNED(size, data->align))) { 180 actual = read(data->dev, buf, size); 181 if (actual != size) { 182 short_read: 183 if (actual < 0) 184 actual = 0; 185 retval = EXT2_ET_SHORT_READ; 186 goto error_out; 187 } 188 return 0; 189 } 190 191#ifdef ALIGN_DEBUG 192 printf("raw_read_blk: O_DIRECT fallback: %p %lu\n", buf, 193 (unsigned long) size); 194#endif 195 196 /* 197 * The buffer or size which we're trying to read isn't aligned 198 * to the O_DIRECT rules, so we need to do this the hard way... 199 */ 200 while (size > 0) { 201 actual = read(data->dev, data->bounce, channel->block_size); 202 if (actual != channel->block_size) 203 goto short_read; 204 actual = size; 205 if (size > channel->block_size) 206 actual = channel->block_size; 207 memcpy(buf, data->bounce, actual); 208 size -= actual; 209 buf += actual; 210 } 211 return 0; 212 213error_out: 214 memset((char *) buf+actual, 0, size-actual); 215 if (channel->read_error) 216 retval = (channel->read_error)(channel, block, count, buf, 217 size, actual, retval); 218 return retval; 219} 220 221static errcode_t raw_write_blk(io_channel channel, 222 struct unix_private_data *data, 223 unsigned long long block, 224 int count, const void *buf) 225{ 226 ssize_t size; 227 ext2_loff_t location; 228 int actual = 0; 229 errcode_t retval; 230 231 if (count == 1) 232 size = channel->block_size; 233 else { 234 if (count < 0) 235 size = -count; 236 else 237 size = count * channel->block_size; 238 } 239 data->io_stats.bytes_written += size; 240 241 location = ((ext2_loff_t) block * channel->block_size) + data->offset; 242 if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 243 retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 244 goto error_out; 245 } 246 247 if ((data->align == 0) || 248 ((IS_ALIGNED(buf, data->align)) && IS_ALIGNED(size, data->align))) { 249 actual = write(data->dev, buf, size); 250 if (actual != size) { 251 short_write: 252 retval = EXT2_ET_SHORT_WRITE; 253 goto error_out; 254 } 255 return 0; 256 } 257 258#ifdef ALIGN_DEBUG 259 printf("raw_write_blk: O_DIRECT fallback: %p %lu\n", buf, 260 (unsigned long) size); 261#endif 262 /* 263 * The buffer or size which we're trying to write isn't aligned 264 * to the O_DIRECT rules, so we need to do this the hard way... 265 */ 266 while (size > 0) { 267 if (size < channel->block_size) { 268 actual = read(data->dev, data->bounce, 269 channel->block_size); 270 if (actual != channel->block_size) { 271 retval = EXT2_ET_SHORT_READ; 272 goto error_out; 273 } 274 } 275 actual = size; 276 if (size > channel->block_size) 277 actual = channel->block_size; 278 memcpy(data->bounce, buf, actual); 279 actual = write(data->dev, data->bounce, channel->block_size); 280 if (actual != channel->block_size) 281 goto short_write; 282 size -= actual; 283 buf += actual; 284 } 285 return 0; 286 287error_out: 288 if (channel->write_error) 289 retval = (channel->write_error)(channel, block, count, buf, 290 size, actual, retval); 291 return retval; 292} 293 294 295/* 296 * Here we implement the cache functions 297 */ 298 299/* Allocate the cache buffers */ 300static errcode_t alloc_cache(io_channel channel, 301 struct unix_private_data *data) 302{ 303 errcode_t retval; 304 struct unix_cache *cache; 305 int i; 306 307 data->access_time = 0; 308 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 309 cache->block = 0; 310 cache->access_time = 0; 311 cache->dirty = 0; 312 cache->in_use = 0; 313 if (cache->buf) 314 ext2fs_free_mem(&cache->buf); 315 retval = ext2fs_get_memalign(channel->block_size, 316 data->align, &cache->buf); 317 if (retval) 318 return retval; 319 } 320 if (data->align) { 321 if (data->bounce) 322 ext2fs_free_mem(&data->bounce); 323 retval = ext2fs_get_memalign(channel->block_size, data->align, 324 &data->bounce); 325 } 326 return retval; 327} 328 329/* Free the cache buffers */ 330static void free_cache(struct unix_private_data *data) 331{ 332 struct unix_cache *cache; 333 int i; 334 335 data->access_time = 0; 336 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 337 cache->block = 0; 338 cache->access_time = 0; 339 cache->dirty = 0; 340 cache->in_use = 0; 341 if (cache->buf) 342 ext2fs_free_mem(&cache->buf); 343 } 344 if (data->bounce) 345 ext2fs_free_mem(&data->bounce); 346} 347 348#ifndef NO_IO_CACHE 349/* 350 * Try to find a block in the cache. If the block is not found, and 351 * eldest is a non-zero pointer, then fill in eldest with the cache 352 * entry to that should be reused. 353 */ 354static struct unix_cache *find_cached_block(struct unix_private_data *data, 355 unsigned long long block, 356 struct unix_cache **eldest) 357{ 358 struct unix_cache *cache, *unused_cache, *oldest_cache; 359 int i; 360 361 unused_cache = oldest_cache = 0; 362 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 363 if (!cache->in_use) { 364 if (!unused_cache) 365 unused_cache = cache; 366 continue; 367 } 368 if (cache->block == block) { 369 cache->access_time = ++data->access_time; 370 return cache; 371 } 372 if (!oldest_cache || 373 (cache->access_time < oldest_cache->access_time)) 374 oldest_cache = cache; 375 } 376 if (eldest) 377 *eldest = (unused_cache) ? unused_cache : oldest_cache; 378 return 0; 379} 380 381/* 382 * Reuse a particular cache entry for another block. 383 */ 384static void reuse_cache(io_channel channel, struct unix_private_data *data, 385 struct unix_cache *cache, unsigned long long block) 386{ 387 if (cache->dirty && cache->in_use) 388 raw_write_blk(channel, data, cache->block, 1, cache->buf); 389 390 cache->in_use = 1; 391 cache->dirty = 0; 392 cache->block = block; 393 cache->access_time = ++data->access_time; 394} 395 396/* 397 * Flush all of the blocks in the cache 398 */ 399static errcode_t flush_cached_blocks(io_channel channel, 400 struct unix_private_data *data, 401 int invalidate) 402 403{ 404 struct unix_cache *cache; 405 errcode_t retval, retval2; 406 int i; 407 408 retval2 = 0; 409 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 410 if (!cache->in_use) 411 continue; 412 413 if (invalidate) 414 cache->in_use = 0; 415 416 if (!cache->dirty) 417 continue; 418 419 retval = raw_write_blk(channel, data, 420 cache->block, 1, cache->buf); 421 if (retval) 422 retval2 = retval; 423 else 424 cache->dirty = 0; 425 } 426 return retval2; 427} 428#endif /* NO_IO_CACHE */ 429 430#ifdef __linux__ 431#ifndef BLKDISCARDZEROES 432#define BLKDISCARDZEROES _IO(0x12,124) 433#endif 434#endif 435 436static errcode_t unix_open(const char *name, int flags, io_channel *channel) 437{ 438 io_channel io = NULL; 439 struct unix_private_data *data = NULL; 440 errcode_t retval; 441 int open_flags, zeroes = 0; 442 struct stat st; 443#ifdef __linux__ 444 struct utsname ut; 445#endif 446 447 if (name == 0) 448 return EXT2_ET_BAD_DEVICE_NAME; 449 retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io); 450 if (retval) 451 return retval; 452 memset(io, 0, sizeof(struct struct_io_channel)); 453 io->magic = EXT2_ET_MAGIC_IO_CHANNEL; 454 retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data); 455 if (retval) 456 goto cleanup; 457 458 io->manager = unix_io_manager; 459 retval = ext2fs_get_mem(strlen(name)+1, &io->name); 460 if (retval) 461 goto cleanup; 462 463 strcpy(io->name, name); 464 io->private_data = data; 465 io->block_size = 1024; 466 io->read_error = 0; 467 io->write_error = 0; 468 io->refcount = 1; 469 470 memset(data, 0, sizeof(struct unix_private_data)); 471 data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; 472 data->io_stats.num_fields = 2; 473 474 open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY; 475 if (flags & IO_FLAG_EXCLUSIVE) 476 open_flags |= O_EXCL; 477#ifdef O_DIRECT 478 if (flags & IO_FLAG_DIRECT_IO) 479 open_flags |= O_DIRECT; 480#endif 481 data->flags = flags; 482 483#ifdef HAVE_OPEN64 484 data->dev = open64(io->name, open_flags); 485#else 486 data->dev = open(io->name, open_flags); 487#endif 488 if (data->dev < 0) { 489 retval = errno; 490 goto cleanup; 491 } 492 493#ifdef BLKSSZGET 494 if (flags & IO_FLAG_DIRECT_IO) { 495 if (ioctl(data->dev, BLKSSZGET, &data->align) != 0) 496 data->align = io->block_size; 497 } 498#endif 499 500#ifdef BLKDISCARDZEROES 501 ioctl(data->dev, BLKDISCARDZEROES, &zeroes); 502 if (zeroes) 503 io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES; 504#endif 505 506#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 507 /* 508 * Some operating systems require that the buffers be aligned, 509 * regardless of O_DIRECT 510 */ 511 data->align = 512; 512#endif 513 514 515 if ((retval = alloc_cache(io, data))) 516 goto cleanup; 517 518#ifdef BLKROGET 519 if (flags & IO_FLAG_RW) { 520 int error; 521 int readonly = 0; 522 523 /* Is the block device actually writable? */ 524 error = ioctl(data->dev, BLKROGET, &readonly); 525 if (!error && readonly) { 526 close(data->dev); 527 retval = EPERM; 528 goto cleanup; 529 } 530 } 531#endif 532 533#ifdef __linux__ 534#undef RLIM_INFINITY 535#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4))) 536#define RLIM_INFINITY ((unsigned long)(~0UL>>1)) 537#else 538#define RLIM_INFINITY (~0UL) 539#endif 540 /* 541 * Work around a bug in 2.4.10-2.4.18 kernels where writes to 542 * block devices are wrongly getting hit by the filesize 543 * limit. This workaround isn't perfect, since it won't work 544 * if glibc wasn't built against 2.2 header files. (Sigh.) 545 * 546 */ 547 if ((flags & IO_FLAG_RW) && 548 (uname(&ut) == 0) && 549 ((ut.release[0] == '2') && (ut.release[1] == '.') && 550 (ut.release[2] == '4') && (ut.release[3] == '.') && 551 (ut.release[4] == '1') && (ut.release[5] >= '0') && 552 (ut.release[5] < '8')) && 553 (fstat(data->dev, &st) == 0) && 554 (S_ISBLK(st.st_mode))) { 555 struct rlimit rlim; 556 557 rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY; 558 setrlimit(RLIMIT_FSIZE, &rlim); 559 getrlimit(RLIMIT_FSIZE, &rlim); 560 if (((unsigned long) rlim.rlim_cur) < 561 ((unsigned long) rlim.rlim_max)) { 562 rlim.rlim_cur = rlim.rlim_max; 563 setrlimit(RLIMIT_FSIZE, &rlim); 564 } 565 } 566#endif 567 *channel = io; 568 return 0; 569 570cleanup: 571 if (data) { 572 free_cache(data); 573 ext2fs_free_mem(&data); 574 } 575 if (io) 576 ext2fs_free_mem(&io); 577 return retval; 578} 579 580static errcode_t unix_close(io_channel channel) 581{ 582 struct unix_private_data *data; 583 errcode_t retval = 0; 584 585 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 586 data = (struct unix_private_data *) channel->private_data; 587 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 588 589 if (--channel->refcount > 0) 590 return 0; 591 592#ifndef NO_IO_CACHE 593 retval = flush_cached_blocks(channel, data, 0); 594#endif 595 596 if (close(data->dev) < 0) 597 retval = errno; 598 free_cache(data); 599 600 ext2fs_free_mem(&channel->private_data); 601 if (channel->name) 602 ext2fs_free_mem(&channel->name); 603 ext2fs_free_mem(&channel); 604 return retval; 605} 606 607static errcode_t unix_set_blksize(io_channel channel, int blksize) 608{ 609 struct unix_private_data *data; 610 errcode_t retval; 611 612 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 613 data = (struct unix_private_data *) channel->private_data; 614 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 615 616 if (channel->block_size != blksize) { 617#ifndef NO_IO_CACHE 618 if ((retval = flush_cached_blocks(channel, data, 0))) 619 return retval; 620#endif 621 622 channel->block_size = blksize; 623 free_cache(data); 624 if ((retval = alloc_cache(channel, data))) 625 return retval; 626 } 627 return 0; 628} 629 630 631static errcode_t unix_read_blk64(io_channel channel, unsigned long long block, 632 int count, void *buf) 633{ 634 struct unix_private_data *data; 635 struct unix_cache *cache, *reuse[READ_DIRECT_SIZE]; 636 errcode_t retval; 637 char *cp; 638 int i, j; 639 640 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 641 data = (struct unix_private_data *) channel->private_data; 642 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 643 644#ifdef NO_IO_CACHE 645 return raw_read_blk(channel, data, block, count, buf); 646#else 647 /* 648 * If we're doing an odd-sized read or a very large read, 649 * flush out the cache and then do a direct read. 650 */ 651 if (count < 0 || count > WRITE_DIRECT_SIZE) { 652 if ((retval = flush_cached_blocks(channel, data, 0))) 653 return retval; 654 return raw_read_blk(channel, data, block, count, buf); 655 } 656 657 cp = buf; 658 while (count > 0) { 659 /* If it's in the cache, use it! */ 660 if ((cache = find_cached_block(data, block, &reuse[0]))) { 661#ifdef DEBUG 662 printf("Using cached block %lu\n", block); 663#endif 664 memcpy(cp, cache->buf, channel->block_size); 665 count--; 666 block++; 667 cp += channel->block_size; 668 continue; 669 } 670 if (count == 1) { 671 /* 672 * Special case where we read directly into the 673 * cache buffer; important in the O_DIRECT case 674 */ 675 cache = reuse[0]; 676 reuse_cache(channel, data, cache, block); 677 if ((retval = raw_read_blk(channel, data, block, 1, 678 cache->buf))) { 679 cache->in_use = 0; 680 return retval; 681 } 682 memcpy(cp, cache->buf, channel->block_size); 683 return 0; 684 } 685 686 /* 687 * Find the number of uncached blocks so we can do a 688 * single read request 689 */ 690 for (i=1; i < count; i++) 691 if (find_cached_block(data, block+i, &reuse[i])) 692 break; 693#ifdef DEBUG 694 printf("Reading %d blocks starting at %lu\n", i, block); 695#endif 696 if ((retval = raw_read_blk(channel, data, block, i, cp))) 697 return retval; 698 699 /* Save the results in the cache */ 700 for (j=0; j < i; j++) { 701 count--; 702 cache = reuse[j]; 703 reuse_cache(channel, data, cache, block++); 704 memcpy(cache->buf, cp, channel->block_size); 705 cp += channel->block_size; 706 } 707 } 708 return 0; 709#endif /* NO_IO_CACHE */ 710} 711 712static errcode_t unix_read_blk(io_channel channel, unsigned long block, 713 int count, void *buf) 714{ 715 return unix_read_blk64(channel, block, count, buf); 716} 717 718static errcode_t unix_write_blk64(io_channel channel, unsigned long long block, 719 int count, const void *buf) 720{ 721 struct unix_private_data *data; 722 struct unix_cache *cache, *reuse; 723 errcode_t retval = 0; 724 const char *cp; 725 int writethrough; 726 727 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 728 data = (struct unix_private_data *) channel->private_data; 729 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 730 731#ifdef NO_IO_CACHE 732 return raw_write_blk(channel, data, block, count, buf); 733#else 734 /* 735 * If we're doing an odd-sized write or a very large write, 736 * flush out the cache completely and then do a direct write. 737 */ 738 if (count < 0 || count > WRITE_DIRECT_SIZE) { 739 if ((retval = flush_cached_blocks(channel, data, 1))) 740 return retval; 741 return raw_write_blk(channel, data, block, count, buf); 742 } 743 744 /* 745 * For a moderate-sized multi-block write, first force a write 746 * if we're in write-through cache mode, and then fill the 747 * cache with the blocks. 748 */ 749 writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH; 750 if (writethrough) 751 retval = raw_write_blk(channel, data, block, count, buf); 752 753 cp = buf; 754 while (count > 0) { 755 cache = find_cached_block(data, block, &reuse); 756 if (!cache) { 757 cache = reuse; 758 reuse_cache(channel, data, cache, block); 759 } 760 memcpy(cache->buf, cp, channel->block_size); 761 cache->dirty = !writethrough; 762 count--; 763 block++; 764 cp += channel->block_size; 765 } 766 return retval; 767#endif /* NO_IO_CACHE */ 768} 769 770static errcode_t unix_write_blk(io_channel channel, unsigned long block, 771 int count, const void *buf) 772{ 773 return unix_write_blk64(channel, block, count, buf); 774} 775 776static errcode_t unix_write_byte(io_channel channel, unsigned long offset, 777 int size, const void *buf) 778{ 779 struct unix_private_data *data; 780 errcode_t retval = 0; 781 ssize_t actual; 782 783 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 784 data = (struct unix_private_data *) channel->private_data; 785 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 786 787 if (data->align != 0) { 788#ifdef ALIGN_DEBUG 789 printf("unix_write_byte: O_DIRECT fallback\n"); 790#endif 791 return EXT2_ET_UNIMPLEMENTED; 792 } 793 794#ifndef NO_IO_CACHE 795 /* 796 * Flush out the cache completely 797 */ 798 if ((retval = flush_cached_blocks(channel, data, 1))) 799 return retval; 800#endif 801 802 if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0) 803 return errno; 804 805 actual = write(data->dev, buf, size); 806 if (actual != size) 807 return EXT2_ET_SHORT_WRITE; 808 809 return 0; 810} 811 812/* 813 * Flush data buffers to disk. 814 */ 815static errcode_t unix_flush(io_channel channel) 816{ 817 struct unix_private_data *data; 818 errcode_t retval = 0; 819 820 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 821 data = (struct unix_private_data *) channel->private_data; 822 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 823 824#ifndef NO_IO_CACHE 825 retval = flush_cached_blocks(channel, data, 0); 826#endif 827 fsync(data->dev); 828 return retval; 829} 830 831static errcode_t unix_set_option(io_channel channel, const char *option, 832 const char *arg) 833{ 834 struct unix_private_data *data; 835 unsigned long long tmp; 836 char *end; 837 838 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 839 data = (struct unix_private_data *) channel->private_data; 840 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 841 842 if (!strcmp(option, "offset")) { 843 if (!arg) 844 return EXT2_ET_INVALID_ARGUMENT; 845 846 tmp = strtoull(arg, &end, 0); 847 if (*end) 848 return EXT2_ET_INVALID_ARGUMENT; 849 data->offset = tmp; 850 if (data->offset < 0) 851 return EXT2_ET_INVALID_ARGUMENT; 852 return 0; 853 } 854 return EXT2_ET_INVALID_ARGUMENT; 855} 856 857#if defined(__linux__) && !defined(BLKDISCARD) 858#define BLKDISCARD _IO(0x12,119) 859#endif 860 861static errcode_t unix_discard(io_channel channel, unsigned long long block, 862 unsigned long long count) 863{ 864#ifdef BLKDISCARD 865 struct unix_private_data *data; 866 __uint64_t range[2]; 867 int ret; 868 869 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 870 data = (struct unix_private_data *) channel->private_data; 871 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 872 873 range[0] = (__uint64_t)(block) * channel->block_size; 874 range[1] = (__uint64_t)(count) * channel->block_size; 875 876 ret = ioctl(data->dev, BLKDISCARD, &range); 877 if (ret < 0) 878 return errno; 879 return 0; 880#else 881 return EXT2_ET_UNIMPLEMENTED; 882#endif 883} 884