unix_io.c revision 8880e7599ced6d047626dd45665b765d0f5eded5
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 338880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o#include <sys/resource.h> 343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 35b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h" 367b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o#include "ext2fs.h" 373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 38f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o/* 39f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o * For checking structure magic numbers... 40f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o */ 41f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 42f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#define EXT2_CHECK_MAGIC(struct, code) \ 43f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if ((struct)->magic != (code)) return (code) 44adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 45adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostruct unix_cache { 46adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o char *buf; 47adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o unsigned long block; 48adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int access_time; 49adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int dirty:1; 50adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int in_use:1; 51adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}; 52adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 53adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#define CACHE_SIZE 8 54adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#define WRITE_VIA_CACHE_SIZE 4 /* Must be smaller than CACHE_SIZE */ 55adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct unix_private_data { 57f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o int magic; 583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int dev; 593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int flags; 60adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int access_time; 61adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache cache[CACHE_SIZE]; 623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel); 653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel); 663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize); 673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block, 683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, void *data); 693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block, 703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, const void *data); 713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel); 72c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset, 73c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o int size, const void *data); 743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 75f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = { 76f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_ET_MAGIC_IO_MANAGER, 773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "Unix I/O Manager", 783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_open, 793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_close, 803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_set_blksize, 813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_read_blk, 823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_write_blk, 83c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o unix_flush, 84c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o unix_write_byte 853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager; 883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 89adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 90adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions 91adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 92adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel, 93adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 94adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o unsigned long block, 95adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int count, void *buf) 96adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 97adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 98adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size_t size; 99adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2_loff_t location; 100adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int actual = 0; 101adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 102adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = (count < 0) ? -count : count * channel->block_size; 103adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o location = (ext2_loff_t) block * channel->block_size; 104adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 105adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 106adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 107adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 108adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = read(data->dev, buf, size); 109adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual != size) { 110adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual < 0) 111adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = 0; 112adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = EXT2_ET_SHORT_READ; 113adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 114adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 115adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 116adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 117adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out: 118adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o memset((char *) buf+actual, 0, size-actual); 119adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (channel->read_error) 120adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = (channel->read_error)(channel, block, count, buf, 121adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size, actual, retval); 122adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 123adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 124adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 125adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel, 126adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 127adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o unsigned long block, 128adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int count, const void *buf) 129adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 130adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size_t size; 131adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2_loff_t location; 132adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int actual = 0; 133adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 134adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 135adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count == 1) 136adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = channel->block_size; 137adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else { 138adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count < 0) 139adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = -count; 140adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else 141adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = count * channel->block_size; 142adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 143adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 144adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o location = (ext2_loff_t) block * channel->block_size; 145adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 146adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 147adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 148adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 149adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 150adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = write(data->dev, buf, size); 151adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual != size) { 152adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = EXT2_ET_SHORT_WRITE; 153adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 154adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 155adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 156adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 157adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out: 158adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (channel->write_error) 159adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = (channel->write_error)(channel, block, count, buf, 160adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size, actual, retval); 161adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 162adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 163adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 164adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 165adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 166adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions 167adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 168adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 169adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */ 170adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel, 171adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data) 172adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 173adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 174adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 175adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 176adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 177adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o data->access_time = 0; 178adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 179adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = 0; 180adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = 0; 181adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 182adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 183adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = ext2fs_get_mem(channel->block_size, 184adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o (void **) &cache->buf))) 185adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 186adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 187adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 188adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 189adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 190adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */ 191adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic void free_cache(io_channel channel, 192adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data) 193adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 194adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 195adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 196adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 197adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o data->access_time = 0; 198adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 199adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = 0; 200adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = 0; 201adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 202adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 203adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->buf) 204adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2fs_free_mem((void **) &cache->buf); 205adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->buf = 0; 206adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 207adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 208adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 209adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 210adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Try to find a block in the cache. If get_cache is non-zero, then 211adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * if the block isn't in the cache, evict the oldest block in the 212adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * cache and create a new cache entry for the requested block. 213adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 21431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'ostatic struct unix_cache *find_cached_block(io_channel channel, 21531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o struct unix_private_data *data, 21631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o unsigned long block, 21731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o int get_cache) 218adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 21931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o struct unix_cache *cache, *unused_cache, *oldest_cache; 220adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 221adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 22231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o unused_cache = oldest_cache = 0; 223adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 224adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->in_use) { 22531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o unused_cache = cache; 226adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 227adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 228adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->block == block) { 229adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = ++data->access_time; 230adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return cache; 231adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 232adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!oldest_cache || 233adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o (cache->access_time < oldest_cache->access_time)) 234adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o oldest_cache = cache; 235adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 236adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!get_cache) 237adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 238adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 239adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 240adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Try to allocate cache slot. 241adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 24231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o if (unused_cache) 24331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cache = unused_cache; 244adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else { 245adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache = oldest_cache; 246adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->dirty) 247adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o raw_write_blk(channel, data, 248adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block, 1, cache->buf); 249adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 250adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 1; 251adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = block; 252adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = ++data->access_time; 253adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return cache; 254adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 255adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 256adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 257adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache 258adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 259adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel, 260adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 261adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int invalidate) 262adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 263adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 264adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 265adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval, retval2; 266adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 267adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 268adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval2 = 0; 269adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 270adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->in_use) 271adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 272adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 273adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (invalidate) 274adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 275adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 276adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->dirty) 277adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 278adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 279adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = raw_write_blk(channel, data, 280adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block, 1, cache->buf); 281adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (retval) 282adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval2 = retval; 283adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else 284adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 285adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 286adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval2; 287adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 288adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 289adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 290adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 2913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel) 2923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 2933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io_channel io = NULL; 2943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data = NULL; 2953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 296dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o int open_flags; 2978880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o struct stat st; 2983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 29950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o if (name == 0) 30050e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o return EXT2_ET_BAD_DEVICE_NAME; 3017b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o retval = ext2fs_get_mem(sizeof(struct struct_io_channel), 3027b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o (void **) &io); 3037b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 3047b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o return retval; 305f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o memset(io, 0, sizeof(struct struct_io_channel)); 306f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->magic = EXT2_ET_MAGIC_IO_CHANNEL; 3077b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o retval = ext2fs_get_mem(sizeof(struct unix_private_data), 3087b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o (void **) &data); 3097b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 3103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 3117b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 3123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io->manager = unix_io_manager; 3137b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o retval = ext2fs_get_mem(strlen(name)+1, (void **) &io->name); 3147b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 3153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 3167b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 3173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o strcpy(io->name, name); 3183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io->private_data = data; 319f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->block_size = 1024; 320f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->read_error = 0; 321f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->write_error = 0; 322a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o io->refcount = 1; 3233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o memset(data, 0, sizeof(struct unix_private_data)); 325f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; 3267b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 327adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = alloc_cache(io, data))) 328adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto cleanup; 329adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 330dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY; 331dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#ifdef HAVE_OPEN64 332dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o data->dev = open64(name, open_flags); 333dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#else 334dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o data->dev = open(name, open_flags); 335dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#endif 3363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (data->dev < 0) { 3373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = errno; 3383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 3393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 3408880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o /* 3418880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o * Work around a bug in 2.4.10+ kernels where writes to block 3428880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o * devices are wrongly getting hit by the filesize limit. 3438880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o */ 3448880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o if ((flags & IO_FLAG_RW) && 3458880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o (fstat(data->dev, &st) == 0) && 3468880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o (S_ISBLK(st.st_mode))) { 3478880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o struct rlimit rlim; 3488880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o 3498880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o rlim.rlim_cur = RLIM_INFINITY; 3508880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o rlim.rlim_max = RLIM_INFINITY; 3518880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o setrlimit(RLIMIT_FSIZE, &rlim); 3528880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o getrlimit(RLIMIT_FSIZE, &rlim); 3538880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o if (rlim.rlim_cur != rlim.rlim_max) { 3548880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o rlim.rlim_cur = rlim.rlim_max; 3558880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o setrlimit(RLIMIT_FSIZE, &rlim); 3568880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o } 3578880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o } 3583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *channel = io; 3593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 3603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup: 3623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (data) { 363adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o free_cache(io, data); 3647b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &data); 3653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 366adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (io) 367adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2fs_free_mem((void **) &io); 3683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 3693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 3703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel) 3723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 3733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 3743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval = 0; 3753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 376f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 3773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 378f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 379a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 380a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o if (--channel->refcount > 0) 381a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o return 0; 382adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 383adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = flush_cached_blocks(channel, data, 0); 384adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 3853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (close(data->dev) < 0) 3863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = errno; 387adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o free_cache(channel, data); 3883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (channel->private_data) 3897b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &channel->private_data); 3903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (channel->name) 3917b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &channel->name); 3927b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &channel); 3933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 3943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 3953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize) 3973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 3983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 3997b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o errcode_t retval; 4003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 401f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 4023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 403f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 404f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 4053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (channel->block_size != blksize) { 406adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 0))) 407adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 408adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 4093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o channel->block_size = blksize; 410adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o free_cache(channel, data); 411adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = alloc_cache(channel, data))) 4127b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o return retval; 4133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 4163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block, 4193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, void *buf) 4203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 422adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 4233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 42431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o char *cp; 425adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i, j; 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); 4303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 432adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * If we're doing an odd-sized read, flush out the cache and 433adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * then do a direct read. 4343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 435adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count < 0) { 436adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 0))) 437adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 438adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return raw_read_blk(channel, data, block, count, buf); 4393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 440adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 44131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp = buf; 442adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o while (count > 0) { 443adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* If it's in the cache, use it! */ 444adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((cache = find_cached_block(channel, data, block, 0))) { 445adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG 446adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o printf("Using cached block %d\n", block); 447f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif 44831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o memcpy(cp, cache->buf, channel->block_size); 449adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 450adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o block++; 45131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 452adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 453adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 454adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 455adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Find the number of uncached blocks so we can do a 456adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * single read request 457adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 458adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=1; i < count; i++) 459adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (find_cached_block(channel, data, block+i, 0)) 460adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o break; 461adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG 462adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o printf("Reading %d blocks starting at %d\n", i, block); 463adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif 46431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o if ((retval = raw_read_blk(channel, data, block, i, cp))) 465adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 466adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 467adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* Save the results in the cache */ 468adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (j=0; j < i; j++) { 469adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 470adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache = find_cached_block(channel, data, block++, 1); 471adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache) 47231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o memcpy(cache->buf, cp, channel->block_size); 47331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 474adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 4753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 4783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block, 4803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, const void *buf) 4813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 483adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 484adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval = 0, retval2; 48531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o const char *cp; 48631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o int writethrough; 4873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 488f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 4893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 490f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 4913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 492adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 493adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * If we're doing an odd-sized write or a very large write, 494adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * flush out the cache completely and then do a direct write. 495adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 496adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count < 0 || count > WRITE_VIA_CACHE_SIZE) { 497adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 1))) 498adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 499adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return raw_write_blk(channel, data, block, count, buf); 5003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 502adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 503adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * For a moderate-sized multi-block write, first force a write 504adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * if we're in write-through cache mode, and then fill the 505adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * cache with the blocks. 506adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 507adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH; 508adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (writethrough) 509adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = raw_write_blk(channel, data, block, count, buf); 5103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 51131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp = buf; 512adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o while (count > 0) { 513adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache = find_cached_block(channel, data, block, 1); 514adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache) { 515adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 516adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Oh shit, we couldn't get cache descriptor. 517adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Force the write directly. 518adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 519adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval2 = raw_write_blk(channel, data, block, 52031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o 1, cp))) 521adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = retval2; 522adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } else { 52331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o memcpy(cache->buf, cp, channel->block_size); 524adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = !writethrough; 525adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 526adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 527adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o block++; 52831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 529adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 5303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 5313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 533c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset, 534c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o int size, const void *buf) 535c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{ 536c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o struct unix_private_data *data; 53731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o errcode_t retval = 0; 538c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o size_t actual; 539c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 540c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 541c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o data = (struct unix_private_data *) channel->private_data; 542c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 543c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 544c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o /* 545c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o * Flush out the cache completely 546c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o */ 547c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 1))) 548c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return retval; 549c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 550c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if (lseek(data->dev, offset, SEEK_SET) < 0) 551c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return errno; 552c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 553c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o actual = write(data->dev, buf, size); 554c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if (actual != size) 555c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return EXT2_ET_SHORT_WRITE; 556c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 557c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return 0; 558c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o} 559c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 5603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 56136f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o * Flush data buffers to disk. 5623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 5633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel) 5643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 565f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o struct unix_private_data *data; 566adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval = 0; 567f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 568f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 569f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o data = (struct unix_private_data *) channel->private_data; 570f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 571adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 572adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = flush_cached_blocks(channel, data, 0); 57336f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o fsync(data->dev); 574adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 5753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 577