unix_io.c revision 82c4660c756fba5eae289e6fbf03fab55393e3e2
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * unix_io.c --- This is the Unix I/O interface to the I/O manager. 33839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 43839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Implements a one-block write-through cache. 53839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o * 2002 by Theodore Ts'o. 819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * 919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header% 1019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * This file may be redistributed under the terms of the GNU Public 1119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * License. 1219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header% 133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 15dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE_SOURCE 16dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE64_SOURCE 17dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o 183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h> 193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h> 204cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H 213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h> 224cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif 23c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#if HAVE_ERRNO_H 24c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#include <errno.h> 25c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#endif 263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h> 273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <time.h> 28f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__ 29f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#include <sys/utsname.h> 30f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif 311d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_STAT_H 323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/stat.h> 331d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif 341d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_TYPES_H 353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/types.h> 361d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif 378880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o#include <sys/resource.h> 383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 39b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h" 407b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o#include "ext2fs.h" 413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 42f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o/* 43f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o * For checking structure magic numbers... 44f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o */ 45f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 46f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#define EXT2_CHECK_MAGIC(struct, code) \ 47f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if ((struct)->magic != (code)) return (code) 48adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 49adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostruct unix_cache { 50adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o char *buf; 51adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o unsigned long block; 52adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int access_time; 53adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int dirty:1; 54adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int in_use:1; 55adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}; 56adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 57adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#define CACHE_SIZE 8 5882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define WRITE_DIRECT_SIZE 4 /* Must be smaller than CACHE_SIZE */ 5982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define READ_DIRECT_SIZE 4 /* Should be smaller than CACHE_SIZE */ 60adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct unix_private_data { 62f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o int magic; 633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int dev; 643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int flags; 65adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int access_time; 66adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache cache[CACHE_SIZE]; 673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel); 703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel); 713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize); 723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block, 733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, void *data); 743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block, 753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, const void *data); 763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel); 77c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset, 78c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o int size, const void *data); 793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 80f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = { 81f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_ET_MAGIC_IO_MANAGER, 823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "Unix I/O Manager", 833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_open, 843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_close, 853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_set_blksize, 863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_read_blk, 873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_write_blk, 88c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o unix_flush, 89c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o unix_write_byte 903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager; 933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 94adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 95adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions 96adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 97adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel, 98adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 99adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o unsigned long block, 100adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int count, void *buf) 101adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 102adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 103adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size_t size; 104adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2_loff_t location; 105adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int actual = 0; 106adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 107adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = (count < 0) ? -count : count * channel->block_size; 108adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o location = (ext2_loff_t) block * channel->block_size; 109adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 110adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 111adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 112adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 113adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = read(data->dev, buf, size); 114adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual != size) { 115adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual < 0) 116adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = 0; 117adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = EXT2_ET_SHORT_READ; 118adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 119adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 120adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 121adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 122adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out: 123adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o memset((char *) buf+actual, 0, size-actual); 124adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (channel->read_error) 125adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = (channel->read_error)(channel, block, count, buf, 126adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size, actual, retval); 127adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 128adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 129adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 130adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel, 131adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 132adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o unsigned long block, 133adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int count, const void *buf) 134adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 135adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size_t size; 136adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2_loff_t location; 137adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int actual = 0; 138adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 139adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 140adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count == 1) 141adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = channel->block_size; 142adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else { 143adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count < 0) 144adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = -count; 145adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else 146adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = count * channel->block_size; 147adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 148adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 149adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o location = (ext2_loff_t) block * channel->block_size; 150adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 151adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 152adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 153adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 154adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 155adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = write(data->dev, buf, size); 156adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual != size) { 157adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = EXT2_ET_SHORT_WRITE; 158adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 159adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 160adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 161adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 162adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out: 163adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (channel->write_error) 164adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = (channel->write_error)(channel, block, count, buf, 165adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size, actual, retval); 166adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 167adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 168adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 169adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 170adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 171adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions 172adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 173adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 174adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */ 175adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel, 176adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data) 177adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 178adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 179adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 180adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 181adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 182adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o data->access_time = 0; 183adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 184adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = 0; 185adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = 0; 186adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 187adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 188adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = ext2fs_get_mem(channel->block_size, 189adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o (void **) &cache->buf))) 190adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 191adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 192adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 193adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 194adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 195adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */ 196adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic void free_cache(io_channel channel, 197adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data) 198adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 199adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 200adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 201adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 202adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o data->access_time = 0; 203adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 204adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = 0; 205adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = 0; 206adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 207adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 208adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->buf) 209adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2fs_free_mem((void **) &cache->buf); 210adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->buf = 0; 211adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 212adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 213adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 214adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 21582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Try to find a block in the cache. If the block is not found, and 21682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * eldest is a non-zero pointer, then fill in eldest with the cache 21782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * entry to that should be reused. 218adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 21931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'ostatic struct unix_cache *find_cached_block(io_channel channel, 22031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o struct unix_private_data *data, 22131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o unsigned long block, 22282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o struct unix_cache **eldest) 223adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 22431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o struct unix_cache *cache, *unused_cache, *oldest_cache; 225adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 226adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 22731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o unused_cache = oldest_cache = 0; 228adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 229adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->in_use) { 23082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (!unused_cache) 23182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o unused_cache = cache; 232adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 233adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 234adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->block == block) { 235adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = ++data->access_time; 236adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return cache; 237adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 238adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!oldest_cache || 239adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o (cache->access_time < oldest_cache->access_time)) 240adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o oldest_cache = cache; 241adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 24282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (eldest) 24382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o *eldest = (unused_cache) ? unused_cache : oldest_cache; 24482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o return 0; 24582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o} 24682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o 24782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o/* 24882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Reuse a particular cache entry for another block. 24982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o */ 25082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'ovoid reuse_cache(io_channel channel, struct unix_private_data *data, 25182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o struct unix_cache *cache, unsigned long block) 25282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o{ 25382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (cache->dirty && cache->in_use) 25482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o raw_write_blk(channel, data, cache->block, 1, cache->buf); 25582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o 256adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 1; 2571d47dfb91ef010c506e9354dec102385d8494d8fTheodore Ts'o cache->dirty = 0; 258adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = block; 259adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = ++data->access_time; 260adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 261adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 262adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 263adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache 264adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 265adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel, 266adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 267adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int invalidate) 268adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 269adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 270adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 271adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval, retval2; 272adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 273adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 274adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval2 = 0; 275adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 276adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->in_use) 277adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 278adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 279adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (invalidate) 280adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 281adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 282adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->dirty) 283adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 284adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 285adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = raw_write_blk(channel, data, 286adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block, 1, cache->buf); 287adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (retval) 288adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval2 = retval; 289adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else 290adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 291adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 292adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval2; 293adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 294adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 295adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 296adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 2973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel) 2983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 2993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io_channel io = NULL; 3003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data = NULL; 3013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 302dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o int open_flags; 3038880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o struct stat st; 304f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__ 305f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o struct utsname ut; 306f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif 3073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 30850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o if (name == 0) 30950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o return EXT2_ET_BAD_DEVICE_NAME; 3107b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o retval = ext2fs_get_mem(sizeof(struct struct_io_channel), 3117b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o (void **) &io); 3127b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 3137b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o return retval; 314f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o memset(io, 0, sizeof(struct struct_io_channel)); 315f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->magic = EXT2_ET_MAGIC_IO_CHANNEL; 3167b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o retval = ext2fs_get_mem(sizeof(struct unix_private_data), 3177b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o (void **) &data); 3187b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 3193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 3207b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 3213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io->manager = unix_io_manager; 3227b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o retval = ext2fs_get_mem(strlen(name)+1, (void **) &io->name); 3237b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 3243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 3257b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 3263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o strcpy(io->name, name); 3273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io->private_data = data; 328f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->block_size = 1024; 329f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->read_error = 0; 330f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->write_error = 0; 331a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o io->refcount = 1; 3323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o memset(data, 0, sizeof(struct unix_private_data)); 334f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; 3357b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 336adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = alloc_cache(io, data))) 337adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto cleanup; 338adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 339dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY; 340dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#ifdef HAVE_OPEN64 341dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o data->dev = open64(name, open_flags); 342dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#else 343dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o data->dev = open(name, open_flags); 344dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#endif 3453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (data->dev < 0) { 3463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = errno; 3473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 3483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 34964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o 35064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#ifdef __linux__ 35164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#undef RLIM_INFINITY 35264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4))) 35364e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY ((unsigned long)(~0UL>>1)) 35464e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#else 35564e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY (~0UL) 35664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif 3578880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o /* 358f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * Work around a bug in 2.4.10-2.4.18 kernels where writes to 359f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * block devices are wrongly getting hit by the filesize 360f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * limit. This workaround isn't perfect, since it won't work 361f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * if glibc wasn't built against 2.2 header files. (Sigh.) 362f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * 3638880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o */ 364f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o if ((flags & IO_FLAG_RW) && 365f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (uname(&ut) == 0) && 366f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o ((ut.release[0] == '2') && (ut.release[1] == '.') && 367f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (ut.release[2] == '4') && (ut.release[3] == '.') && 368f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (ut.release[4] == '1') && (ut.release[5] >= '0') && 369f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (ut.release[5] < '8')) && 3708880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o (fstat(data->dev, &st) == 0) && 3718880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o (S_ISBLK(st.st_mode))) { 3728880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o struct rlimit rlim; 3738880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o 37464e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY; 3758880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o setrlimit(RLIMIT_FSIZE, &rlim); 3768880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o getrlimit(RLIMIT_FSIZE, &rlim); 377bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o if (((unsigned long) rlim.rlim_cur) < 378bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o ((unsigned long) rlim.rlim_max)) { 3798880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o rlim.rlim_cur = rlim.rlim_max; 3808880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o setrlimit(RLIMIT_FSIZE, &rlim); 3818880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o } 3828880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o } 38364e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif 3843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *channel = io; 3853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 3863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup: 3883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (data) { 389adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o free_cache(io, data); 3907b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &data); 3913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 392adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (io) 393adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2fs_free_mem((void **) &io); 3943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 3953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 3963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel) 3983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 3993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 4003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval = 0; 4013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 402f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 4033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 404f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 405a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 406a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o if (--channel->refcount > 0) 407a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o return 0; 408adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 409adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = flush_cached_blocks(channel, data, 0); 410adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 4113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (close(data->dev) < 0) 4123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = errno; 413adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o free_cache(channel, data); 414f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o 415f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o ext2fs_free_mem((void **) &channel->private_data); 4163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (channel->name) 4177b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &channel->name); 4187b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &channel); 4193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 4203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 4213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize) 4233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 4257b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o errcode_t retval; 4263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 427f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 4283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 429f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 430f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 4313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (channel->block_size != blksize) { 432adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 0))) 433adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 434adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 4353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o channel->block_size = blksize; 436adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o free_cache(channel, data); 437adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = alloc_cache(channel, data))) 4387b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o return retval; 4393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 4423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block, 4453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, void *buf) 4463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 44882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o struct unix_cache *cache, *reuse[READ_DIRECT_SIZE]; 4493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 45031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o char *cp; 451adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i, j; 4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 453f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 4543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 455f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 4563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 45882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * If we're doing an odd-sized read or a very large read, 45982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * flush out the cache and then do a direct read. 4603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 46182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (count < 0 || count > WRITE_DIRECT_SIZE) { 462adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 0))) 463adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 464adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return raw_read_blk(channel, data, block, count, buf); 4653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 466adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 46731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp = buf; 468adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o while (count > 0) { 469adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* If it's in the cache, use it! */ 47082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if ((cache = find_cached_block(channel, data, block, 47182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o &reuse[0]))) { 472adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG 473adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o printf("Using cached block %d\n", block); 474f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif 47531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o memcpy(cp, cache->buf, channel->block_size); 476adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 477adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o block++; 47831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 479adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 480adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 481adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 482adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Find the number of uncached blocks so we can do a 483adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * single read request 484adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 485adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=1; i < count; i++) 48682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (find_cached_block(channel, data, block+i, 48782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o &reuse[i])) 488adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o break; 489adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG 490adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o printf("Reading %d blocks starting at %d\n", i, block); 491adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif 49231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o if ((retval = raw_read_blk(channel, data, block, i, cp))) 493adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 494adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 495adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* Save the results in the cache */ 496adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (j=0; j < i; j++) { 497adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 49882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o cache = reuse[j]; 49982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o reuse_cache(channel, data, cache, block++); 50082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o memcpy(cache->buf, cp, channel->block_size); 50131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 502adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 5033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 5053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block, 5083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, const void *buf) 5093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 5103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 51182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o struct unix_cache *cache, *reuse; 512adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval = 0, retval2; 51331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o const char *cp; 51431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o int writethrough; 5153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 516f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 5173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 518f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 5193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 520adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 521adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * If we're doing an odd-sized write or a very large write, 522adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * flush out the cache completely and then do a direct write. 523adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 52482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (count < 0 || count > WRITE_DIRECT_SIZE) { 525adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 1))) 526adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 527adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return raw_write_blk(channel, data, block, count, buf); 5283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 530adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 531adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * For a moderate-sized multi-block write, first force a write 532adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * if we're in write-through cache mode, and then fill the 533adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * cache with the blocks. 534adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 535adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH; 536adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (writethrough) 537adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = raw_write_blk(channel, data, block, count, buf); 5383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 53931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp = buf; 540adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o while (count > 0) { 54182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o cache = find_cached_block(channel, data, block, &reuse); 542adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache) { 54382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o cache = reuse; 54482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o reuse_cache(channel, data, cache, block); 545adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 54682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o memcpy(cache->buf, cp, channel->block_size); 54782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o cache->dirty = !writethrough; 548adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 549adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o block++; 55031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 551adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 5523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 5533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 555c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset, 556c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o int size, const void *buf) 557c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{ 558c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o struct unix_private_data *data; 55931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o errcode_t retval = 0; 560c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o size_t actual; 561c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 562c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 563c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o data = (struct unix_private_data *) channel->private_data; 564c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 565c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 566c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o /* 567c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o * Flush out the cache completely 568c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o */ 569c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 1))) 570c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return retval; 571c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 572c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if (lseek(data->dev, offset, SEEK_SET) < 0) 573c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return errno; 574c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 575c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o actual = write(data->dev, buf, size); 576c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if (actual != size) 577c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return EXT2_ET_SHORT_WRITE; 578c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 579c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return 0; 580c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o} 581c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 5823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 58336f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o * Flush data buffers to disk. 5843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 5853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel) 5863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 587f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o struct unix_private_data *data; 588adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval = 0; 589f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 590f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 591f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o data = (struct unix_private_data *) channel->private_data; 592f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 593adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 594adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = flush_cached_blocks(channel, data, 0); 59536f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o fsync(data->dev); 596adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 5973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 599