unix_io.c revision 59ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 2fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o * unix_io.c --- This is the Unix (well, really POSIX) implementation 3fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o * of the I/O manager. 43839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 53839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Implements a one-block write-through cache. 63839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 7fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o * Includes support for Windows NT support under Cygwin. 8fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o * 964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 1064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o * 2002 by Theodore Ts'o. 1119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * 1219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header% 1319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * This file may be redistributed under the terms of the GNU Public 1419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * License. 1519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header% 163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 18dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE_SOURCE 19dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE64_SOURCE 20dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o 213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h> 223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h> 234cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H 243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h> 254cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif 26c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#if HAVE_ERRNO_H 27c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#include <errno.h> 28c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#endif 293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h> 303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <time.h> 31f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__ 32f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#include <sys/utsname.h> 33f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif 341d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_STAT_H 353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/stat.h> 361d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif 371d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_TYPES_H 383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/types.h> 391d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif 40fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#if HAVE_SYS_RESOURCE_H 418880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o#include <sys/resource.h> 42fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif 433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 44b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h" 457b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o#include "ext2fs.h" 463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 47f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o/* 48f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o * For checking structure magic numbers... 49f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o */ 50f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 51f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#define EXT2_CHECK_MAGIC(struct, code) \ 52f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if ((struct)->magic != (code)) return (code) 53adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 54adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostruct unix_cache { 55adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o char *buf; 56adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o unsigned long block; 57adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int access_time; 5883e692e88bf2d01edb089010bdfc07b7dcc78642Matthias Andree unsigned dirty:1; 5983e692e88bf2d01edb089010bdfc07b7dcc78642Matthias Andree unsigned in_use:1; 60adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}; 61adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 62adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#define CACHE_SIZE 8 6382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define WRITE_DIRECT_SIZE 4 /* Must be smaller than CACHE_SIZE */ 6482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define READ_DIRECT_SIZE 4 /* Should be smaller than CACHE_SIZE */ 65adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct unix_private_data { 67f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o int magic; 683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int dev; 693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int flags; 70adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int access_time; 712e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o ext2_loff_t offset; 72adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache cache[CACHE_SIZE]; 736d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o struct struct_io_stats io_stats; 743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel); 773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel); 783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize); 793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block, 803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, void *data); 813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block, 823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, const void *data); 833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel); 84c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset, 85c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o int size, const void *data); 862e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'ostatic errcode_t unix_set_option(io_channel channel, const char *option, 872e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o const char *arg); 886d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'ostatic errcode_t unix_get_stats(io_channel channel, io_stats *stats) 896d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o; 9023b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data, 9159ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos struct unix_cache *cache, unsigned long long block); 9259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk64(io_channel channel, unsigned long long block, 9359ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos int count, void *data); 9459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk64(io_channel channel, unsigned long long block, 9559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos int count, const void *data); 9623b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o 97289e0557c24c68290b6d9b73b09674447801fdacMatthias Andree/* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel 98289e0557c24c68290b6d9b73b09674447801fdacMatthias Andree * does not know buffered block devices - everything is raw. */ 99289e0557c24c68290b6d9b73b09674447801fdacMatthias Andree#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 100b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#define NEED_BOUNCE_BUFFER 101b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#else 102b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#undef NEED_BOUNCE_BUFFER 103b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#endif 104b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree 105f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = { 106f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_ET_MAGIC_IO_MANAGER, 1073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "Unix I/O Manager", 1083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_open, 1093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_close, 1103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_set_blksize, 1113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_read_blk, 1123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_write_blk, 113c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o unix_flush, 114b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#ifdef NEED_BOUNCE_BUFFER 1152e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o 0, 116fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#else 1172e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o unix_write_byte, 118fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif 1196d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o unix_set_option, 1206d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o unix_get_stats, 12159ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos unix_read_blk64, 12259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos unix_write_blk64, 1233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 1243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager; 1263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1276d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'ostatic errcode_t unix_get_stats(io_channel channel, io_stats *stats) 1286d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o{ 1296d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o errcode_t retval = 0; 1306d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o 1316d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o struct unix_private_data *data; 1326d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o 1336d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 1346d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o data = (struct unix_private_data *) channel->private_data; 1356d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 1366d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o 1376d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o if (stats) 1386d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o *stats = &data->io_stats; 1396d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o 1406d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o return retval; 1416d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o} 1426d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o 143adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 144adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions 145adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 146b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#ifndef NEED_BOUNCE_BUFFER 147adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel, 148adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 14959ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos unsigned long long block, 150adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int count, void *buf) 151adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 152adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 153544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o ssize_t size; 154adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2_loff_t location; 155adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int actual = 0; 156adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 157adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = (count < 0) ? -count : count * channel->block_size; 1586d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o data->io_stats.bytes_read += size; 1592e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o location = ((ext2_loff_t) block * channel->block_size) + data->offset; 160adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 161adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 162adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 163adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 164adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = read(data->dev, buf, size); 165adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual != size) { 166adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual < 0) 167adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = 0; 168adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = EXT2_ET_SHORT_READ; 169adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 170adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 171adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 172adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 173adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out: 174adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o memset((char *) buf+actual, 0, size-actual); 175adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (channel->read_error) 176adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = (channel->read_error)(channel, block, count, buf, 177adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size, actual, retval); 178adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 179adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 180b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#else /* NEED_BOUNCE_BUFFER */ 181fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o/* 182b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree * Windows and FreeBSD block devices only allow sector alignment IO in offset and size 183fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o */ 184fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'ostatic errcode_t raw_read_blk(io_channel channel, 185fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o struct unix_private_data *data, 186fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o unsigned long block, 187fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o int count, void *buf) 188fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o{ 189fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o errcode_t retval; 190fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o size_t size, alignsize, fragment; 191fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o ext2_loff_t location; 192fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o int total = 0, actual; 193fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#define BLOCKALIGN 512 194fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o char sector[BLOCKALIGN]; 195fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o 196fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o size = (count < 0) ? -count : count * channel->block_size; 1976d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o data->io_stats.bytes_read += size; 1982e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o location = ((ext2_loff_t) block * channel->block_size) + data->offset; 199fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#ifdef DEBUG 200d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen printf("count=%d, size=%d, block=%lu, blk_size=%d, location=%llx\n", 201d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen count, size, block, channel->block_size, (long long)location); 202fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif 203fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 204fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 205fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o goto error_out; 206fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o } 207fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o fragment = size % BLOCKALIGN; 208fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o alignsize = size - fragment; 209fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o if (alignsize) { 210fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o actual = read(data->dev, buf, alignsize); 211fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o if (actual != alignsize) 212fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o goto short_read; 213fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o } 214fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o if (fragment) { 215fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o actual = read(data->dev, sector, BLOCKALIGN); 216fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o if (actual != BLOCKALIGN) 217fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o goto short_read; 218fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o memcpy(buf+alignsize, sector, fragment); 219fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o } 220fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o return 0; 221fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o 222fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'oshort_read: 223fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o if (actual>0) 224fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o total += actual; 225fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o retval = EXT2_ET_SHORT_READ; 226fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o 227fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'oerror_out: 228fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o memset((char *) buf+total, 0, size-actual); 229fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o if (channel->read_error) 230fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o retval = (channel->read_error)(channel, block, count, buf, 231fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o size, actual, retval); 232fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o return retval; 233fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o} 234fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif 235adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 236adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel, 237adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 23859ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos unsigned long long block, 239adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int count, const void *buf) 240adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 241544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o ssize_t size; 242adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2_loff_t location; 243adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int actual = 0; 244adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 245adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 246adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count == 1) 247adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = channel->block_size; 248adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else { 249adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count < 0) 250adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = -count; 251adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else 252adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = count * channel->block_size; 253adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 2546d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o data->io_stats.bytes_written += size; 255adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 2562e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o location = ((ext2_loff_t) block * channel->block_size) + data->offset; 257adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 258adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 259adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 260adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 261adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 262adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = write(data->dev, buf, size); 263adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual != size) { 264adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = EXT2_ET_SHORT_WRITE; 265adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 266adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 267adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 268adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 269adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out: 270adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (channel->write_error) 271adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = (channel->write_error)(channel, block, count, buf, 272adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size, actual, retval); 273adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 274adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 275adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 276adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 277adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 278adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions 279adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 280adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 281adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */ 282adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel, 283adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data) 284adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 285adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 286adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 287adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 288adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 289adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o data->access_time = 0; 290adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 291adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = 0; 292adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = 0; 293adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 294adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 295adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = ext2fs_get_mem(channel->block_size, 296c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o &cache->buf))) 297adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 298adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 299adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 300adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 301adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 302adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */ 303544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic void free_cache(struct unix_private_data *data) 304adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 305adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 306adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 307adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 308adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o data->access_time = 0; 309adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 310adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = 0; 311adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = 0; 312adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 313adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 314adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->buf) 315c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&cache->buf); 316adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->buf = 0; 317adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 318adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 319adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 320b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE 321adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 32282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Try to find a block in the cache. If the block is not found, and 32382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * eldest is a non-zero pointer, then fill in eldest with the cache 32482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * entry to that should be reused. 325adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 326544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic struct unix_cache *find_cached_block(struct unix_private_data *data, 32759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos unsigned long long block, 32882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o struct unix_cache **eldest) 329adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 33031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o struct unix_cache *cache, *unused_cache, *oldest_cache; 331adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 332adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 33331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o unused_cache = oldest_cache = 0; 334adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 335adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->in_use) { 33682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (!unused_cache) 33782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o unused_cache = cache; 338adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 339adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 340adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->block == block) { 341adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = ++data->access_time; 342adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return cache; 343adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 344adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!oldest_cache || 345adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o (cache->access_time < oldest_cache->access_time)) 346adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o oldest_cache = cache; 347adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 34882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (eldest) 34982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o *eldest = (unused_cache) ? unused_cache : oldest_cache; 35082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o return 0; 35182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o} 35282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o 35382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o/* 35482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Reuse a particular cache entry for another block. 35582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o */ 35623b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data, 35759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos struct unix_cache *cache, unsigned long long block) 35882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o{ 35982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (cache->dirty && cache->in_use) 36082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o raw_write_blk(channel, data, cache->block, 1, cache->buf); 36182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o 362adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 1; 3631d47dfb91ef010c506e9354dec102385d8494d8fTheodore Ts'o cache->dirty = 0; 364adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = block; 365adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = ++data->access_time; 366adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 367adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 368adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 369adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache 370adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 371adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel, 372adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 373adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int invalidate) 374adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 375adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 376adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 377adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval, retval2; 378adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 379adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 380adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval2 = 0; 381adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 382adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->in_use) 383adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 384adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 385adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (invalidate) 386adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 387adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 388adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->dirty) 389adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 390adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 391adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = raw_write_blk(channel, data, 392adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block, 1, cache->buf); 393adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (retval) 394adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval2 = retval; 395adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else 396adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 397adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 398adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval2; 399adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 400b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */ 401adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 4023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel) 4033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io_channel io = NULL; 4053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data = NULL; 4063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 407dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o int open_flags; 4088880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o struct stat st; 409f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__ 410f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o struct utsname ut; 411f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif 4123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 41350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o if (name == 0) 41450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o return EXT2_ET_BAD_DEVICE_NAME; 415c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io); 4167b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 4177b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o return retval; 418f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o memset(io, 0, sizeof(struct struct_io_channel)); 419f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->magic = EXT2_ET_MAGIC_IO_CHANNEL; 420c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data); 4217b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 4237b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io->manager = unix_io_manager; 425c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o retval = ext2fs_get_mem(strlen(name)+1, &io->name); 4267b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 4273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 4287b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 4293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o strcpy(io->name, name); 4303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io->private_data = data; 431f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->block_size = 1024; 432f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->read_error = 0; 433f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->write_error = 0; 434a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o io->refcount = 1; 4353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o memset(data, 0, sizeof(struct unix_private_data)); 437f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; 4386d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o data->io_stats.num_fields = 2; 4397b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 440adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = alloc_cache(io, data))) 441adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto cleanup; 4422e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o 443dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY; 444fa6c653ec3117dd689c8adb4ea2ebfc10f8cdd4aTheodore Ts'o if (flags & IO_FLAG_EXCLUSIVE) 445fa6c653ec3117dd689c8adb4ea2ebfc10f8cdd4aTheodore Ts'o open_flags |= O_EXCL; 446dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#ifdef HAVE_OPEN64 4472e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o data->dev = open64(io->name, open_flags); 448dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#else 4492e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o data->dev = open(io->name, open_flags); 450dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#endif 4513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (data->dev < 0) { 4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = errno; 4533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 4543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 45564e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o 45664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#ifdef __linux__ 45764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#undef RLIM_INFINITY 45864e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4))) 45964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY ((unsigned long)(~0UL>>1)) 46064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#else 46164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY (~0UL) 46264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif 4638880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o /* 464f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * Work around a bug in 2.4.10-2.4.18 kernels where writes to 465f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * block devices are wrongly getting hit by the filesize 466f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * limit. This workaround isn't perfect, since it won't work 467f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * if glibc wasn't built against 2.2 header files. (Sigh.) 468f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * 4698880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o */ 470f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o if ((flags & IO_FLAG_RW) && 471f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (uname(&ut) == 0) && 472f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o ((ut.release[0] == '2') && (ut.release[1] == '.') && 473f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (ut.release[2] == '4') && (ut.release[3] == '.') && 474f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (ut.release[4] == '1') && (ut.release[5] >= '0') && 475f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (ut.release[5] < '8')) && 4768880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o (fstat(data->dev, &st) == 0) && 4778880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o (S_ISBLK(st.st_mode))) { 4788880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o struct rlimit rlim; 4798880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o 48064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY; 4818880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o setrlimit(RLIMIT_FSIZE, &rlim); 4828880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o getrlimit(RLIMIT_FSIZE, &rlim); 483bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o if (((unsigned long) rlim.rlim_cur) < 484bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o ((unsigned long) rlim.rlim_max)) { 4858880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o rlim.rlim_cur = rlim.rlim_max; 4868880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o setrlimit(RLIMIT_FSIZE, &rlim); 4878880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o } 4888880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o } 48964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif 4903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *channel = io; 4913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup: 4943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (data) { 495544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o free_cache(data); 496c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&data); 4973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 498adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (io) 499c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&io); 5003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 5013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel) 5043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 5053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 5063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval = 0; 5073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 508f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 5093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 510f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 511a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 512a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o if (--channel->refcount > 0) 513a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o return 0; 514adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 515b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE 516adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = flush_cached_blocks(channel, data, 0); 517b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif 518adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 5193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (close(data->dev) < 0) 5203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = errno; 521544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o free_cache(data); 522f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o 523c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&channel->private_data); 5243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (channel->name) 525c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&channel->name); 526c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&channel); 5273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 5283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize) 5313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 5323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 5337b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o errcode_t retval; 5343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 535f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 5363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 537f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 538f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 5393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (channel->block_size != blksize) { 540b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE 541adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 0))) 542adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 543b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif 544adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 5453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o channel->block_size = blksize; 546544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o free_cache(data); 547adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = alloc_cache(channel, data))) 5487b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o return retval; 5493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 5513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 55459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk64(io_channel channel, unsigned long long block, 5553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, void *buf) 5563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 5573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 55882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o struct unix_cache *cache, *reuse[READ_DIRECT_SIZE]; 5593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 56031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o char *cp; 561adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i, j; 5623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 563f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 5643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 565f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 5663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 567b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE 568b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o return raw_read_blk(channel, data, block, count, buf); 569b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#else 5703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 57182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * If we're doing an odd-sized read or a very large read, 57282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * flush out the cache and then do a direct read. 5733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 57482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (count < 0 || count > WRITE_DIRECT_SIZE) { 575adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 0))) 576adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 577adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return raw_read_blk(channel, data, block, count, buf); 5783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 579adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 58031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp = buf; 581adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o while (count > 0) { 582adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* If it's in the cache, use it! */ 583544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o if ((cache = find_cached_block(data, block, &reuse[0]))) { 584adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG 585d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen printf("Using cached block %lu\n", block); 586f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif 58731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o memcpy(cp, cache->buf, channel->block_size); 588adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 589adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o block++; 59031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 591adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 592adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 593adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 594adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Find the number of uncached blocks so we can do a 595adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * single read request 596adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 597adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=1; i < count; i++) 598544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o if (find_cached_block(data, block+i, &reuse[i])) 599adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o break; 600adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG 601d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen printf("Reading %d blocks starting at %lu\n", i, block); 602adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif 60331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o if ((retval = raw_read_blk(channel, data, block, i, cp))) 604adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 605adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 606adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* Save the results in the cache */ 607adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (j=0; j < i; j++) { 608adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 60982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o cache = reuse[j]; 61082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o reuse_cache(channel, data, cache, block++); 61182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o memcpy(cache->buf, cp, channel->block_size); 61231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 613adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 6143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 6153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 616b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */ 6173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 6183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 61959ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk(io_channel channel, unsigned long block, 62059ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos int count, void *buf) 62159ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos{ 62259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos return unix_read_blk64(channel, block, count, buf); 62359ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos} 62459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos 62559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk64(io_channel channel, unsigned long long block, 6263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, const void *buf) 6273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 6283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 62982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o struct unix_cache *cache, *reuse; 63023b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o errcode_t retval = 0; 63131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o const char *cp; 63231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o int writethrough; 6333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 634f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 6353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 636f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 6373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 638b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE 639b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o return raw_write_blk(channel, data, block, count, buf); 640b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#else 641adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 642adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * If we're doing an odd-sized write or a very large write, 643adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * flush out the cache completely and then do a direct write. 644adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 64582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (count < 0 || count > WRITE_DIRECT_SIZE) { 646adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 1))) 647adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 648adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return raw_write_blk(channel, data, block, count, buf); 6493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 6503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 651adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 652adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * For a moderate-sized multi-block write, first force a write 653adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * if we're in write-through cache mode, and then fill the 654adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * cache with the blocks. 655adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 656adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH; 657adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (writethrough) 658adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = raw_write_blk(channel, data, block, count, buf); 6593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 66031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp = buf; 661adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o while (count > 0) { 662544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o cache = find_cached_block(data, block, &reuse); 663adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache) { 66482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o cache = reuse; 66582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o reuse_cache(channel, data, cache, block); 666adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 66782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o memcpy(cache->buf, cp, channel->block_size); 66882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o cache->dirty = !writethrough; 669adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 670adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o block++; 67131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 672adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 6733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 674b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */ 6753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 6763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 67759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk(io_channel channel, unsigned long block, 67859ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos int count, const void *buf) 67959ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos{ 68059ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos return unix_write_blk64(channel, block, count, buf); 68159ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos} 68259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos 683c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset, 684c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o int size, const void *buf) 685c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{ 686c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o struct unix_private_data *data; 68731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o errcode_t retval = 0; 688544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o ssize_t actual; 689c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 690c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 691c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o data = (struct unix_private_data *) channel->private_data; 692c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 693c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 694b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE 695c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o /* 696c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o * Flush out the cache completely 697c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o */ 698c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 1))) 699c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return retval; 700b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif 701c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 7022e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0) 703c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return errno; 704c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 705c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o actual = write(data->dev, buf, size); 706c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if (actual != size) 707c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return EXT2_ET_SHORT_WRITE; 708c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 709c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return 0; 710c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o} 711c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 7123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 71336f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o * Flush data buffers to disk. 7143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 7153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel) 7163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 717f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o struct unix_private_data *data; 718adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval = 0; 719f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 720f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 721f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o data = (struct unix_private_data *) channel->private_data; 722f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 723adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 724b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE 725adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = flush_cached_blocks(channel, data, 0); 726b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif 72736f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o fsync(data->dev); 728adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 7293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 7303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 7312e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'ostatic errcode_t unix_set_option(io_channel channel, const char *option, 7322e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o const char *arg) 7332e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o{ 7342e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o struct unix_private_data *data; 7352aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o unsigned long long tmp; 7362e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o char *end; 7372e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o 7382e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 7392e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 7402e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 7412e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o 7422e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o if (!strcmp(option, "offset")) { 7432e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o if (!arg) 7442e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o return EXT2_ET_INVALID_ARGUMENT; 7452e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o 7462aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o tmp = strtoull(arg, &end, 0); 7472e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o if (*end) 7482e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o return EXT2_ET_INVALID_ARGUMENT; 7492e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o data->offset = tmp; 7502aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o if (data->offset < 0) 7512aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o return EXT2_ET_INVALID_ARGUMENT; 7522e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o return 0; 7532e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o } 7542e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o return EXT2_ET_INVALID_ARGUMENT; 7552e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o} 756