unix_io.c revision 31dbecd482405e0d3a67eb58e1a1c8cb9f2ad83e
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 * 619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * Copyright (C) 1993, 1994, 1995 Theodore Ts'o. 719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * 819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header% 919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * This file may be redistributed under the terms of the GNU Public 1019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * License. 1119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header% 123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 14dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE_SOURCE 15dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE64_SOURCE 16dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o 173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h> 183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h> 194cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H 203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h> 214cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif 22c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#if HAVE_ERRNO_H 23c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#include <errno.h> 24c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#endif 253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h> 263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <time.h> 271d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_STAT_H 283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/stat.h> 291d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif 301d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_TYPES_H 313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/types.h> 321d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif 333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 34b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#if EXT2_FLAT_INCLUDES 35b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h" 36b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#else 377b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o#include <linux/ext2_fs.h> 38b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#endif 397b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 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 58adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#define WRITE_VIA_CACHE_SIZE 4 /* Must be smaller than CACHE_SIZE */ 59adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct unix_private_data { 61f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o int magic; 623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int dev; 633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int flags; 64adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int access_time; 65adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache cache[CACHE_SIZE]; 663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel); 693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel); 703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize); 713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block, 723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, void *data); 733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block, 743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, const void *data); 753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel); 76c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset, 77c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o int size, const void *data); 783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 79f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = { 80f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_ET_MAGIC_IO_MANAGER, 813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "Unix I/O Manager", 823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_open, 833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_close, 843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_set_blksize, 853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_read_blk, 863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_write_blk, 87c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o unix_flush, 88c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o unix_write_byte 893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager; 923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 93adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 94adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions 95adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 96adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel, 97adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 98adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o unsigned long block, 99adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int count, void *buf) 100adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 101adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 102adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size_t size; 103adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2_loff_t location; 104adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int actual = 0; 105adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 106adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = (count < 0) ? -count : count * channel->block_size; 107adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o location = (ext2_loff_t) block * channel->block_size; 108adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 109adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 110adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 111adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 112adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = read(data->dev, buf, size); 113adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual != size) { 114adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual < 0) 115adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = 0; 116adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = EXT2_ET_SHORT_READ; 117adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 118adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 119adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 120adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 121adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out: 122adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o memset((char *) buf+actual, 0, size-actual); 123adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (channel->read_error) 124adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = (channel->read_error)(channel, block, count, buf, 125adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size, actual, retval); 126adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 127adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 128adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 129adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel, 130adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 131adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o unsigned long block, 132adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int count, const void *buf) 133adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 134adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size_t size; 135adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2_loff_t location; 136adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int actual = 0; 137adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 138adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 139adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count == 1) 140adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = channel->block_size; 141adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else { 142adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count < 0) 143adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = -count; 144adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else 145adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = count * channel->block_size; 146adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 147adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 148adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o location = (ext2_loff_t) block * channel->block_size; 149adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 150adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 151adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 152adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 153adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 154adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = write(data->dev, buf, size); 155adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual != size) { 156adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = EXT2_ET_SHORT_WRITE; 157adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 158adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 159adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 160adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 161adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out: 162adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (channel->write_error) 163adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = (channel->write_error)(channel, block, count, buf, 164adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size, actual, retval); 165adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 166adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 167adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 168adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 169adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 170adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions 171adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 172adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 173adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */ 174adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel, 175adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data) 176adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 177adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 178adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 179adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 180adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 181adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o data->access_time = 0; 182adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 183adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = 0; 184adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = 0; 185adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 186adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 187adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = ext2fs_get_mem(channel->block_size, 188adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o (void **) &cache->buf))) 189adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 190adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 191adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 192adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 193adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 194adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */ 195adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic void free_cache(io_channel channel, 196adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data) 197adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 198adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 199adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 200adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 201adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o data->access_time = 0; 202adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 203adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = 0; 204adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = 0; 205adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 206adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 207adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->buf) 208adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2fs_free_mem((void **) &cache->buf); 209adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->buf = 0; 210adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 211adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 212adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 213adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 214adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Try to find a block in the cache. If get_cache is non-zero, then 215adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * if the block isn't in the cache, evict the oldest block in the 216adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * cache and create a new cache entry for the requested block. 217adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 21831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'ostatic struct unix_cache *find_cached_block(io_channel channel, 21931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o struct unix_private_data *data, 22031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o unsigned long block, 22131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o int get_cache) 222adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 22331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o struct unix_cache *cache, *unused_cache, *oldest_cache; 224adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 225adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 22631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o unused_cache = oldest_cache = 0; 227adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 228adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->in_use) { 22931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o unused_cache = cache; 230adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 231adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 232adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->block == block) { 233adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = ++data->access_time; 234adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return cache; 235adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 236adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!oldest_cache || 237adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o (cache->access_time < oldest_cache->access_time)) 238adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o oldest_cache = cache; 239adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 240adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!get_cache) 241adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 242adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 243adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 244adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Try to allocate cache slot. 245adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 24631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o if (unused_cache) 24731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cache = unused_cache; 248adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else { 249adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache = oldest_cache; 250adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->dirty) 251adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o raw_write_blk(channel, data, 252adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block, 1, cache->buf); 253adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 254adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 1; 255adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = block; 256adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = ++data->access_time; 257adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return cache; 258adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 259adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 260adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 261adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache 262adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 263adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel, 264adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 265adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int invalidate) 266adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 267adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 268adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 269adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval, retval2; 270adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 271adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 272adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval2 = 0; 273adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 274adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->in_use) 275adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 276adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 277adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (invalidate) 278adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 279adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 280adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->dirty) 281adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 282adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 283adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = raw_write_blk(channel, data, 284adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block, 1, cache->buf); 285adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (retval) 286adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval2 = retval; 287adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else 288adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 289adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 290adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval2; 291adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 292adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 293adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 294adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 2953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel) 2963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 2973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io_channel io = NULL; 2983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data = NULL; 2993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 300dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o int open_flags; 3013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 30250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o if (name == 0) 30350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o return EXT2_ET_BAD_DEVICE_NAME; 3047b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o retval = ext2fs_get_mem(sizeof(struct struct_io_channel), 3057b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o (void **) &io); 3067b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 3077b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o return retval; 308f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o memset(io, 0, sizeof(struct struct_io_channel)); 309f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->magic = EXT2_ET_MAGIC_IO_CHANNEL; 3107b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o retval = ext2fs_get_mem(sizeof(struct unix_private_data), 3117b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o (void **) &data); 3127b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 3133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 3147b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 3153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io->manager = unix_io_manager; 3167b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o retval = ext2fs_get_mem(strlen(name)+1, (void **) &io->name); 3177b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 3183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 3197b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 3203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o strcpy(io->name, name); 3213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io->private_data = data; 322f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->block_size = 1024; 323f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->read_error = 0; 324f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->write_error = 0; 325a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o io->refcount = 1; 3263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o memset(data, 0, sizeof(struct unix_private_data)); 328f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; 3297b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 330adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = alloc_cache(io, data))) 331adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto cleanup; 332adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 333dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY; 334dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#ifdef HAVE_OPEN64 335dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o data->dev = open64(name, open_flags); 336dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#else 337dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o data->dev = open(name, open_flags); 338dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#endif 3393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (data->dev < 0) { 3403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = errno; 3413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 3423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 3433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *channel = io; 3443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 3453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup: 3473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (data) { 348adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o free_cache(io, data); 3497b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &data); 3503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 351adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (io) 352adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2fs_free_mem((void **) &io); 3533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 3543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 3553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel) 3573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 3583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 3593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval = 0; 3603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 361f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 3623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 363f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 364a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 365a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o if (--channel->refcount > 0) 366a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o return 0; 367adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 368adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = flush_cached_blocks(channel, data, 0); 369adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 3703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (close(data->dev) < 0) 3713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = errno; 372adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o free_cache(channel, data); 3733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (channel->private_data) 3747b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &channel->private_data); 3753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (channel->name) 3767b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &channel->name); 3777b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &channel); 3783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 3793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 3803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize) 3823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 3833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 3847b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o errcode_t retval; 3853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 386f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 3873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 388f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 389f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 3903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (channel->block_size != blksize) { 391adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 0))) 392adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 393adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 3943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o channel->block_size = blksize; 395adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o free_cache(channel, data); 396adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = alloc_cache(channel, data))) 3977b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o return retval; 3983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 3993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 4013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block, 4043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, void *buf) 4053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 407adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 4083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 40931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o char *cp; 410adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i, j; 4113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 412f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 4133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 414f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 4153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 417adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * If we're doing an odd-sized read, flush out the cache and 418adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * then do a direct read. 4193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 420adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count < 0) { 421adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 0))) 422adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 423adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return raw_read_blk(channel, data, block, count, buf); 4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 425adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 42631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp = buf; 427adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o while (count > 0) { 428adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* If it's in the cache, use it! */ 429adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((cache = find_cached_block(channel, data, block, 0))) { 430adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG 431adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o printf("Using cached block %d\n", block); 432f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif 43331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o memcpy(cp, cache->buf, channel->block_size); 434adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 435adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o block++; 43631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 437adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 438adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 439adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 440adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Find the number of uncached blocks so we can do a 441adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * single read request 442adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 443adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=1; i < count; i++) 444adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (find_cached_block(channel, data, block+i, 0)) 445adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o break; 446adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG 447adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o printf("Reading %d blocks starting at %d\n", i, block); 448adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif 44931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o if ((retval = raw_read_blk(channel, data, block, i, cp))) 450adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 451adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 452adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* Save the results in the cache */ 453adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (j=0; j < i; j++) { 454adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 455adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache = find_cached_block(channel, data, block++, 1); 456adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache) 45731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o memcpy(cache->buf, cp, channel->block_size); 45831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 459adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 4603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 4633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block, 4653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, const void *buf) 4663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 468adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 469adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval = 0, retval2; 47031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o const char *cp; 47131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o int writethrough; 4723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 473f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 4743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 475f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 4763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 477adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 478adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * If we're doing an odd-sized write or a very large write, 479adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * flush out the cache completely and then do a direct write. 480adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 481adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count < 0 || count > WRITE_VIA_CACHE_SIZE) { 482adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 1))) 483adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 484adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return raw_write_blk(channel, data, block, count, buf); 4853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 487adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 488adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * For a moderate-sized multi-block write, first force a write 489adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * if we're in write-through cache mode, and then fill the 490adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * cache with the blocks. 491adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 492adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH; 493adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (writethrough) 494adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = raw_write_blk(channel, data, block, count, buf); 4953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 49631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp = buf; 497adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o while (count > 0) { 498adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache = find_cached_block(channel, data, block, 1); 499adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache) { 500adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 501adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Oh shit, we couldn't get cache descriptor. 502adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Force the write directly. 503adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 504adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval2 = raw_write_blk(channel, data, block, 50531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o 1, cp))) 506adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = retval2; 507adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } else { 50831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o memcpy(cache->buf, cp, channel->block_size); 509adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = !writethrough; 510adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 511adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 512adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o block++; 51331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 514adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 5153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 5163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 518c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset, 519c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o int size, const void *buf) 520c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{ 521c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o struct unix_private_data *data; 52231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o errcode_t retval = 0; 523c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o size_t actual; 524c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 525c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 526c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o data = (struct unix_private_data *) channel->private_data; 527c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 528c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 529c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o /* 530c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o * Flush out the cache completely 531c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o */ 532c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 1))) 533c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return retval; 534c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 535c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if (lseek(data->dev, offset, SEEK_SET) < 0) 536c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return errno; 537c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 538c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o actual = write(data->dev, buf, size); 539c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if (actual != size) 540c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return EXT2_ET_SHORT_WRITE; 541c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 542c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return 0; 543c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o} 544c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 5453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 54636f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o * Flush data buffers to disk. 5473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 5483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel) 5493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 550f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o struct unix_private_data *data; 551adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval = 0; 552f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 553f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 554f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o data = (struct unix_private_data *) channel->private_data; 555f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 556adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 557adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = flush_cached_blocks(channel, data, 0); 55836f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o fsync(data->dev); 559adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 5603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 562