unix_io.c revision 543547a52a20cb7e69d74921b2f691078fd55d83
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 * 7efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore 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% 13543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * This file may be redistributed under the terms of the GNU Library 14543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * General Public License, version 2. 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 347ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#ifdef HAVE_SYS_IOCTL_H 357ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#include <sys/ioctl.h> 367ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#endif 377ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#ifdef HAVE_SYS_MOUNT_H 387ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#include <sys/mount.h> 397ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#endif 401d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_STAT_H 413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/stat.h> 421d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif 431d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_TYPES_H 443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/types.h> 451d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif 46fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#if HAVE_SYS_RESOURCE_H 478880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o#include <sys/resource.h> 48fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif 493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 507ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE) 517ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#define BLKROGET _IO(0x12, 94) /* Get read-only status (0 = read_write). */ 527ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#endif 537ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen 54b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h" 557b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o#include "ext2fs.h" 563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 57f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o/* 58f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o * For checking structure magic numbers... 59f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o */ 60f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 61f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#define EXT2_CHECK_MAGIC(struct, code) \ 62f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if ((struct)->magic != (code)) return (code) 63adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 64adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostruct unix_cache { 65adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o char *buf; 66adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o unsigned long block; 67adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int access_time; 6883e692e88bf2d01edb089010bdfc07b7dcc78642Matthias Andree unsigned dirty:1; 6983e692e88bf2d01edb089010bdfc07b7dcc78642Matthias Andree unsigned in_use:1; 70adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}; 71adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 72adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#define CACHE_SIZE 8 7382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define WRITE_DIRECT_SIZE 4 /* Must be smaller than CACHE_SIZE */ 7482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define READ_DIRECT_SIZE 4 /* Should be smaller than CACHE_SIZE */ 75adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct unix_private_data { 77f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o int magic; 783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int dev; 793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int flags; 80adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int access_time; 812e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o ext2_loff_t offset; 82adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache cache[CACHE_SIZE]; 836d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o struct struct_io_stats io_stats; 843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel); 873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel); 883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize); 893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block, 903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, void *data); 913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block, 923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, const void *data); 933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel); 94c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset, 95c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o int size, const void *data); 96efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'ostatic errcode_t unix_set_option(io_channel channel, const char *option, 972e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o const char *arg); 986d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'ostatic errcode_t unix_get_stats(io_channel channel, io_stats *stats) 996d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o; 10023b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data, 10159ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos struct unix_cache *cache, unsigned long long block); 10259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk64(io_channel channel, unsigned long long block, 10359ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos int count, void *data); 10459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk64(io_channel channel, unsigned long long block, 10559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos int count, const void *data); 10623b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o 107289e0557c24c68290b6d9b73b09674447801fdacMatthias Andree/* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel 108289e0557c24c68290b6d9b73b09674447801fdacMatthias Andree * does not know buffered block devices - everything is raw. */ 109289e0557c24c68290b6d9b73b09674447801fdacMatthias Andree#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 110b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#define NEED_BOUNCE_BUFFER 111b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#else 112b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#undef NEED_BOUNCE_BUFFER 113b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#endif 114b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree 115f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = { 116f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_ET_MAGIC_IO_MANAGER, 1173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "Unix I/O Manager", 1183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_open, 1193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_close, 1203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_set_blksize, 1213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_read_blk, 1223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_write_blk, 123c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o unix_flush, 124b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#ifdef NEED_BOUNCE_BUFFER 1252e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o 0, 126fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#else 1272e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o unix_write_byte, 128fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif 1296d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o unix_set_option, 1306d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o unix_get_stats, 13159ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos unix_read_blk64, 13259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos unix_write_blk64, 1333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 1343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager; 1363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 1376d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'ostatic errcode_t unix_get_stats(io_channel channel, io_stats *stats) 1386d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o{ 1396d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o errcode_t retval = 0; 1406d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o 1416d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o struct unix_private_data *data; 1426d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o 1436d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 1446d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o data = (struct unix_private_data *) channel->private_data; 1456d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 1466d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o 1476d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o if (stats) 1486d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o *stats = &data->io_stats; 1496d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o 1506d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o return retval; 1516d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o} 1526d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o 153adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 154adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions 155adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 156b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#ifndef NEED_BOUNCE_BUFFER 157adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel, 158adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 15959ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos unsigned long long block, 160adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int count, void *buf) 161adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 162adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 163544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o ssize_t size; 164adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2_loff_t location; 165adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int actual = 0; 166adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 167adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = (count < 0) ? -count : count * channel->block_size; 1686d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o data->io_stats.bytes_read += size; 1692e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o location = ((ext2_loff_t) block * channel->block_size) + data->offset; 170adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 171adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 172adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 173adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 174adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = read(data->dev, buf, size); 175adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual != size) { 176adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual < 0) 177adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = 0; 178adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = EXT2_ET_SHORT_READ; 179adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 180adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 181adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 182efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 183adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out: 184adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o memset((char *) buf+actual, 0, size-actual); 185adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (channel->read_error) 186adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = (channel->read_error)(channel, block, count, buf, 187adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size, actual, retval); 188adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 189adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 190b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#else /* NEED_BOUNCE_BUFFER */ 191fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o/* 192b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree * Windows and FreeBSD block devices only allow sector alignment IO in offset and size 193fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o */ 194fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'ostatic errcode_t raw_read_blk(io_channel channel, 195fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o struct unix_private_data *data, 196fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o unsigned long block, 197fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o int count, void *buf) 198fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o{ 199fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o errcode_t retval; 200fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o size_t size, alignsize, fragment; 201fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o ext2_loff_t location; 202fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o int total = 0, actual; 203fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#define BLOCKALIGN 512 204fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o char sector[BLOCKALIGN]; 205fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o 206fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o size = (count < 0) ? -count : count * channel->block_size; 2076d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o data->io_stats.bytes_read += size; 2082e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o location = ((ext2_loff_t) block * channel->block_size) + data->offset; 209fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#ifdef DEBUG 210d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen printf("count=%d, size=%d, block=%lu, blk_size=%d, location=%llx\n", 211d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen count, size, block, channel->block_size, (long long)location); 212fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif 213fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 214fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 215fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o goto error_out; 216fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o } 217fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o fragment = size % BLOCKALIGN; 218fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o alignsize = size - fragment; 219fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o if (alignsize) { 220fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o actual = read(data->dev, buf, alignsize); 221fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o if (actual != alignsize) 222fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o goto short_read; 223fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o } 224fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o if (fragment) { 225fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o actual = read(data->dev, sector, BLOCKALIGN); 226fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o if (actual != BLOCKALIGN) 227fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o goto short_read; 228fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o memcpy(buf+alignsize, sector, fragment); 229fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o } 230fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o return 0; 231fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o 232fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'oshort_read: 233fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o if (actual>0) 234fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o total += actual; 235fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o retval = EXT2_ET_SHORT_READ; 236fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o 237fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'oerror_out: 238fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o memset((char *) buf+total, 0, size-actual); 239fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o if (channel->read_error) 240fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o retval = (channel->read_error)(channel, block, count, buf, 241fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o size, actual, retval); 242fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o return retval; 243fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o} 244fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif 245adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 246adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel, 247adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 24859ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos unsigned long long block, 249adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int count, const void *buf) 250adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 251544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o ssize_t size; 252adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2_loff_t location; 253adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int actual = 0; 254adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 255adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 256adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count == 1) 257adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = channel->block_size; 258adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else { 259adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count < 0) 260adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = -count; 261adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else 262adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = count * channel->block_size; 263adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 2646d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o data->io_stats.bytes_written += size; 265adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 2662e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o location = ((ext2_loff_t) block * channel->block_size) + data->offset; 267adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 268adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 269adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 270adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 271efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 272adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = write(data->dev, buf, size); 273adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual != size) { 274adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = EXT2_ET_SHORT_WRITE; 275adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 276adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 277adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 278efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 279adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out: 280adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (channel->write_error) 281adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = (channel->write_error)(channel, block, count, buf, 282adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size, actual, retval); 283adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 284adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 285adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 286adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 287adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 288adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions 289adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 290adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 291adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */ 292adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel, 293adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data) 294adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 295adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 296adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 297adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 298efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 299adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o data->access_time = 0; 300adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 301adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = 0; 302adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = 0; 303adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 304adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 305adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = ext2fs_get_mem(channel->block_size, 306c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o &cache->buf))) 307adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 308adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 309adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 310adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 311adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 312adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */ 313544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic void free_cache(struct unix_private_data *data) 314adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 315adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 316adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 317efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 318adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o data->access_time = 0; 319adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 320adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = 0; 321adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = 0; 322adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 323adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 324adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->buf) 325c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&cache->buf); 326adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->buf = 0; 327adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 328adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 329adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 330b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE 331adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 33282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Try to find a block in the cache. If the block is not found, and 33382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * eldest is a non-zero pointer, then fill in eldest with the cache 33482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * entry to that should be reused. 335adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 336544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic struct unix_cache *find_cached_block(struct unix_private_data *data, 33759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos unsigned long long block, 33882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o struct unix_cache **eldest) 339adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 34031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o struct unix_cache *cache, *unused_cache, *oldest_cache; 341adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 342efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 34331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o unused_cache = oldest_cache = 0; 344adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 345adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->in_use) { 34682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (!unused_cache) 34782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o unused_cache = cache; 348adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 349adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 350adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->block == block) { 351adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = ++data->access_time; 352adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return cache; 353adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 354adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!oldest_cache || 355adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o (cache->access_time < oldest_cache->access_time)) 356adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o oldest_cache = cache; 357adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 35882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (eldest) 35982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o *eldest = (unused_cache) ? unused_cache : oldest_cache; 36082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o return 0; 36182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o} 36282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o 36382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o/* 36482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Reuse a particular cache entry for another block. 36582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o */ 36623b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data, 36759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos struct unix_cache *cache, unsigned long long block) 36882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o{ 36982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (cache->dirty && cache->in_use) 37082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o raw_write_blk(channel, data, cache->block, 1, cache->buf); 37182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o 372adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 1; 3731d47dfb91ef010c506e9354dec102385d8494d8fTheodore Ts'o cache->dirty = 0; 374adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = block; 375adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = ++data->access_time; 376adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 377adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 378adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 379adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache 380adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 381adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel, 382adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 383adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int invalidate) 384adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 385adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 386adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 387adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval, retval2; 388adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 389efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 390adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval2 = 0; 391adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 392adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->in_use) 393adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 394efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 395adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (invalidate) 396adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 397efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 398adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->dirty) 399adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 400efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 401adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = raw_write_blk(channel, data, 402adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block, 1, cache->buf); 403adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (retval) 404adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval2 = retval; 405adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else 406adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 407adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 408adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval2; 409adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 410b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */ 411adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 4123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel) 4133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io_channel io = NULL; 4153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data = NULL; 4163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 417dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o int open_flags; 4188880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o struct stat st; 419f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__ 420f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o struct utsname ut; 421f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif 4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 42350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o if (name == 0) 42450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o return EXT2_ET_BAD_DEVICE_NAME; 425c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io); 4267b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 4277b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o return retval; 428f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o memset(io, 0, sizeof(struct struct_io_channel)); 429f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->magic = EXT2_ET_MAGIC_IO_CHANNEL; 430c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data); 4317b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 4323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 4337b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 4343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io->manager = unix_io_manager; 435c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o retval = ext2fs_get_mem(strlen(name)+1, &io->name); 4367b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 4373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 4387b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 4393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o strcpy(io->name, name); 4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io->private_data = data; 441f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->block_size = 1024; 442f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->read_error = 0; 443f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->write_error = 0; 444a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o io->refcount = 1; 4453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o memset(data, 0, sizeof(struct unix_private_data)); 447f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; 4486d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o data->io_stats.num_fields = 2; 4497b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 450adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = alloc_cache(io, data))) 451adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto cleanup; 4522e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o 453dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY; 454fa6c653ec3117dd689c8adb4ea2ebfc10f8cdd4aTheodore Ts'o if (flags & IO_FLAG_EXCLUSIVE) 455fa6c653ec3117dd689c8adb4ea2ebfc10f8cdd4aTheodore Ts'o open_flags |= O_EXCL; 456dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#ifdef HAVE_OPEN64 4572e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o data->dev = open64(io->name, open_flags); 458dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#else 4592e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o data->dev = open(io->name, open_flags); 460dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#endif 4613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (data->dev < 0) { 4623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = errno; 4633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 4643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 46564e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o 4667ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#ifdef BLKROGET 4677ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen if (flags & IO_FLAG_RW) { 4687ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen int error; 4697ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen int readonly = 0; 4707ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen 4717ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen /* Is the block device actually writable? */ 4727ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen error = ioctl(data->dev, BLKROGET, &readonly); 4737ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen if (!error && readonly) { 4747ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen close(data->dev); 4757ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen retval = EPERM; 4767ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen goto cleanup; 4777ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen } 4787ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen } 4797ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#endif 4807ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen 48164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#ifdef __linux__ 48264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#undef RLIM_INFINITY 48364e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4))) 48464e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY ((unsigned long)(~0UL>>1)) 48564e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#else 48664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY (~0UL) 48764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif 4888880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o /* 489f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * Work around a bug in 2.4.10-2.4.18 kernels where writes to 490f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * block devices are wrongly getting hit by the filesize 491f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * limit. This workaround isn't perfect, since it won't work 492f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * if glibc wasn't built against 2.2 header files. (Sigh.) 493efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * 4948880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o */ 495f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o if ((flags & IO_FLAG_RW) && 496f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (uname(&ut) == 0) && 497f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o ((ut.release[0] == '2') && (ut.release[1] == '.') && 498f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (ut.release[2] == '4') && (ut.release[3] == '.') && 499f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (ut.release[4] == '1') && (ut.release[5] >= '0') && 500f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (ut.release[5] < '8')) && 5018880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o (fstat(data->dev, &st) == 0) && 5028880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o (S_ISBLK(st.st_mode))) { 5038880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o struct rlimit rlim; 504efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 50564e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY; 5068880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o setrlimit(RLIMIT_FSIZE, &rlim); 5078880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o getrlimit(RLIMIT_FSIZE, &rlim); 508bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o if (((unsigned long) rlim.rlim_cur) < 509bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o ((unsigned long) rlim.rlim_max)) { 5108880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o rlim.rlim_cur = rlim.rlim_max; 5118880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o setrlimit(RLIMIT_FSIZE, &rlim); 5128880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o } 5138880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o } 51464e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif 5153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *channel = io; 5163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 5173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup: 5193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (data) { 520544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o free_cache(data); 521c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&data); 5223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 523adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (io) 524c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&io); 5253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 5263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel) 5293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 5303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 5313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval = 0; 5323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 533f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 5343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 535f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 536a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 537a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o if (--channel->refcount > 0) 538a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o return 0; 539adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 540b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE 541adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = flush_cached_blocks(channel, data, 0); 542b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif 543adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 5443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (close(data->dev) < 0) 5453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = errno; 546544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o free_cache(data); 547f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o 548c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&channel->private_data); 5493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (channel->name) 550c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&channel->name); 551c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o ext2fs_free_mem(&channel); 5523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 5533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize) 5563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 5573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 5587b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o errcode_t retval; 5593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 560f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 5613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 562f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 563f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 5643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (channel->block_size != blksize) { 565b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE 566adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 0))) 567adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 568b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif 569efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 5703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o channel->block_size = blksize; 571544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o free_cache(data); 572adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = alloc_cache(channel, data))) 5737b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o return retval; 5743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 5763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 57959ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk64(io_channel channel, unsigned long long block, 5803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, void *buf) 5813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 5823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 58382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o struct unix_cache *cache, *reuse[READ_DIRECT_SIZE]; 5843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 58531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o char *cp; 586adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i, j; 5873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 588f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 5893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 590f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 5913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 592b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE 593b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o return raw_read_blk(channel, data, block, count, buf); 594b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#else 5953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 59682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * If we're doing an odd-sized read or a very large read, 59782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * flush out the cache and then do a direct read. 5983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 59982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (count < 0 || count > WRITE_DIRECT_SIZE) { 600adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 0))) 601adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 602adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return raw_read_blk(channel, data, block, count, buf); 6033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 604adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 60531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp = buf; 606adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o while (count > 0) { 607adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* If it's in the cache, use it! */ 608544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o if ((cache = find_cached_block(data, block, &reuse[0]))) { 609adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG 610d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen printf("Using cached block %lu\n", block); 611f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif 61231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o memcpy(cp, cache->buf, channel->block_size); 613adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 614adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o block++; 61531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 616adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 617adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 618adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 619adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Find the number of uncached blocks so we can do a 620adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * single read request 621adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 622adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=1; i < count; i++) 623544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o if (find_cached_block(data, block+i, &reuse[i])) 624adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o break; 625adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG 626d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen printf("Reading %d blocks starting at %lu\n", i, block); 627adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif 62831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o if ((retval = raw_read_blk(channel, data, block, i, cp))) 629adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 630efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 631adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* Save the results in the cache */ 632adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (j=0; j < i; j++) { 633adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 63482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o cache = reuse[j]; 63582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o reuse_cache(channel, data, cache, block++); 63682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o memcpy(cache->buf, cp, channel->block_size); 63731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 638adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 6393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 6403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 641b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */ 6423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 6433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 64459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk(io_channel channel, unsigned long block, 64559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos int count, void *buf) 64659ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos{ 64759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos return unix_read_blk64(channel, block, count, buf); 64859ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos} 64959ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos 65059ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk64(io_channel channel, unsigned long long block, 6513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, const void *buf) 6523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 6533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 65482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o struct unix_cache *cache, *reuse; 65523b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o errcode_t retval = 0; 65631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o const char *cp; 65731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o int writethrough; 6583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 659f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 6603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 661f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 6623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 663b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE 664b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o return raw_write_blk(channel, data, block, count, buf); 665efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o#else 666adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 667adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * If we're doing an odd-sized write or a very large write, 668adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * flush out the cache completely and then do a direct write. 669adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 67082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (count < 0 || count > WRITE_DIRECT_SIZE) { 671adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 1))) 672adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 673adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return raw_write_blk(channel, data, block, count, buf); 6743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 6753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 676adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 677adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * For a moderate-sized multi-block write, first force a write 678adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * if we're in write-through cache mode, and then fill the 679adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * cache with the blocks. 680adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 681adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH; 682adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (writethrough) 683adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = raw_write_blk(channel, data, block, count, buf); 684efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 68531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp = buf; 686adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o while (count > 0) { 687544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o cache = find_cached_block(data, block, &reuse); 688adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache) { 68982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o cache = reuse; 69082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o reuse_cache(channel, data, cache, block); 691adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 69282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o memcpy(cache->buf, cp, channel->block_size); 69382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o cache->dirty = !writethrough; 694adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 695adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o block++; 69631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 697adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 6983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 699b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */ 7003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 7013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 70259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk(io_channel channel, unsigned long block, 70359ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos int count, const void *buf) 70459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos{ 70559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos return unix_write_blk64(channel, block, count, buf); 70659ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos} 70759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos 708c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset, 709c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o int size, const void *buf) 710c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{ 711c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o struct unix_private_data *data; 71231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o errcode_t retval = 0; 713544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o ssize_t actual; 714c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 715c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 716c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o data = (struct unix_private_data *) channel->private_data; 717c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 718c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 719b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE 720c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o /* 721c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o * Flush out the cache completely 722c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o */ 723c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 1))) 724c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return retval; 725b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif 726c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 7272e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0) 728c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return errno; 729efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 730c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o actual = write(data->dev, buf, size); 731c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if (actual != size) 732c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return EXT2_ET_SHORT_WRITE; 733c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 734c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return 0; 735c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o} 736c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 7373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 738efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * Flush data buffers to disk. 7393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 7403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel) 7413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 742f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o struct unix_private_data *data; 743adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval = 0; 744efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o 745f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 746f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o data = (struct unix_private_data *) channel->private_data; 747f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 748adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 749b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE 750adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = flush_cached_blocks(channel, data, 0); 751b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif 75236f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o fsync(data->dev); 753adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 7543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 7553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 756efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'ostatic errcode_t unix_set_option(io_channel channel, const char *option, 7572e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o const char *arg) 7582e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o{ 7592e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o struct unix_private_data *data; 7602aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o unsigned long long tmp; 7612e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o char *end; 7622e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o 7632e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 7642e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 7652e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 7662e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o 7672e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o if (!strcmp(option, "offset")) { 7682e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o if (!arg) 7692e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o return EXT2_ET_INVALID_ARGUMENT; 7702e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o 7712aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o tmp = strtoull(arg, &end, 0); 7722e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o if (*end) 7732e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o return EXT2_ET_INVALID_ARGUMENT; 7742e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o data->offset = tmp; 7752aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o if (data->offset < 0) 7762aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o return EXT2_ET_INVALID_ARGUMENT; 7772e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o return 0; 7782e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o } 7792e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o return EXT2_ET_INVALID_ARGUMENT; 7802e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o} 781