unix_io.c revision 23b7c8b88673248b1f93abc717943867ad037bb4
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 8023b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data, 8123b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o struct unix_cache *cache, unsigned long block); 8223b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o 83f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = { 84f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_ET_MAGIC_IO_MANAGER, 853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "Unix I/O Manager", 863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_open, 873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_close, 883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_set_blksize, 893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_read_blk, 903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_write_blk, 91c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o unix_flush, 92c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o unix_write_byte 933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager; 963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 97adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 98adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions 99adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 100adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel, 101adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 102adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o unsigned long block, 103adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int count, void *buf) 104adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 105adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 106adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size_t size; 107adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2_loff_t location; 108adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int actual = 0; 109adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 110adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = (count < 0) ? -count : count * channel->block_size; 111adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o location = (ext2_loff_t) block * channel->block_size; 112adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 113adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 114adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 115adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 116adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = read(data->dev, buf, size); 117adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual != size) { 118adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual < 0) 119adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = 0; 120adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = EXT2_ET_SHORT_READ; 121adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 122adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 123adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 124adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 125adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out: 126adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o memset((char *) buf+actual, 0, size-actual); 127adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (channel->read_error) 128adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = (channel->read_error)(channel, block, count, buf, 129adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size, actual, retval); 130adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 131adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 132adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 133adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel, 134adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 135adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o unsigned long block, 136adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int count, const void *buf) 137adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 138adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size_t size; 139adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2_loff_t location; 140adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int actual = 0; 141adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 142adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 143adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count == 1) 144adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = channel->block_size; 145adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else { 146adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count < 0) 147adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = -count; 148adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else 149adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = count * channel->block_size; 150adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 151adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 152adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o location = (ext2_loff_t) block * channel->block_size; 153adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 154adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 155adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 156adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 157adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 158adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = write(data->dev, buf, size); 159adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual != size) { 160adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = EXT2_ET_SHORT_WRITE; 161adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 162adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 163adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 164adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 165adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out: 166adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (channel->write_error) 167adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = (channel->write_error)(channel, block, count, buf, 168adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size, actual, retval); 169adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 170adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 171adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 172adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 173adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 174adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions 175adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 176adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 177adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */ 178adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel, 179adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data) 180adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 181adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 182adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 183adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 184adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 185adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o data->access_time = 0; 186adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 187adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = 0; 188adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = 0; 189adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 190adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 191adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = ext2fs_get_mem(channel->block_size, 192adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o (void **) &cache->buf))) 193adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 194adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 195adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 196adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 197adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 198adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */ 199adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic void free_cache(io_channel channel, 200adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data) 201adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 202adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 203adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 204adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 205adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o data->access_time = 0; 206adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 207adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = 0; 208adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = 0; 209adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 210adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 211adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->buf) 212adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2fs_free_mem((void **) &cache->buf); 213adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->buf = 0; 214adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 215adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 216adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 217adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 21882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Try to find a block in the cache. If the block is not found, and 21982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * eldest is a non-zero pointer, then fill in eldest with the cache 22082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * entry to that should be reused. 221adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 22231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'ostatic struct unix_cache *find_cached_block(io_channel channel, 22331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o struct unix_private_data *data, 22431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o unsigned long block, 22582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o struct unix_cache **eldest) 226adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 22731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o struct unix_cache *cache, *unused_cache, *oldest_cache; 228adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 229adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 23031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o unused_cache = oldest_cache = 0; 231adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 232adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->in_use) { 23382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (!unused_cache) 23482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o unused_cache = cache; 235adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 236adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 237adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->block == block) { 238adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = ++data->access_time; 239adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return cache; 240adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 241adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!oldest_cache || 242adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o (cache->access_time < oldest_cache->access_time)) 243adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o oldest_cache = cache; 244adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 24582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (eldest) 24682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o *eldest = (unused_cache) ? unused_cache : oldest_cache; 24782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o return 0; 24882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o} 24982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o 25082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o/* 25182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Reuse a particular cache entry for another block. 25282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o */ 25323b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data, 25482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o struct unix_cache *cache, unsigned long block) 25582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o{ 25682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (cache->dirty && cache->in_use) 25782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o raw_write_blk(channel, data, cache->block, 1, cache->buf); 25882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o 259adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 1; 2601d47dfb91ef010c506e9354dec102385d8494d8fTheodore Ts'o cache->dirty = 0; 261adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = block; 262adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = ++data->access_time; 263adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 264adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 265adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 266adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache 267adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 268adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel, 269adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 270adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int invalidate) 271adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 272adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 273adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 274adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval, retval2; 275adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 276adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 277adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval2 = 0; 278adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 279adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->in_use) 280adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 281adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 282adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (invalidate) 283adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 284adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 285adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->dirty) 286adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 287adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 288adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = raw_write_blk(channel, data, 289adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block, 1, cache->buf); 290adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (retval) 291adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval2 = retval; 292adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else 293adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 294adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 295adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval2; 296adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 297adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 298adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 299adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 3003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel) 3013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 3023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io_channel io = NULL; 3033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data = NULL; 3043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 305dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o int open_flags; 3068880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o struct stat st; 307f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__ 308f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o struct utsname ut; 309f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif 3103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 31150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o if (name == 0) 31250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o return EXT2_ET_BAD_DEVICE_NAME; 3137b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o retval = ext2fs_get_mem(sizeof(struct struct_io_channel), 3147b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o (void **) &io); 3157b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 3167b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o return retval; 317f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o memset(io, 0, sizeof(struct struct_io_channel)); 318f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->magic = EXT2_ET_MAGIC_IO_CHANNEL; 3197b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o retval = ext2fs_get_mem(sizeof(struct unix_private_data), 3207b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o (void **) &data); 3217b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 3223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 3237b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 3243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io->manager = unix_io_manager; 3257b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o retval = ext2fs_get_mem(strlen(name)+1, (void **) &io->name); 3267b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 3273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 3287b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 3293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o strcpy(io->name, name); 3303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io->private_data = data; 331f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->block_size = 1024; 332f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->read_error = 0; 333f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->write_error = 0; 334a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o io->refcount = 1; 3353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o memset(data, 0, sizeof(struct unix_private_data)); 337f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; 3387b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 339adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = alloc_cache(io, data))) 340adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto cleanup; 341adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 342dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY; 343dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#ifdef HAVE_OPEN64 344dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o data->dev = open64(name, open_flags); 345dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#else 346dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o data->dev = open(name, open_flags); 347dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#endif 3483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (data->dev < 0) { 3493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = errno; 3503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 3513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 35264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o 35364e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#ifdef __linux__ 35464e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#undef RLIM_INFINITY 35564e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4))) 35664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY ((unsigned long)(~0UL>>1)) 35764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#else 35864e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY (~0UL) 35964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif 3608880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o /* 361f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * Work around a bug in 2.4.10-2.4.18 kernels where writes to 362f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * block devices are wrongly getting hit by the filesize 363f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * limit. This workaround isn't perfect, since it won't work 364f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * if glibc wasn't built against 2.2 header files. (Sigh.) 365f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * 3668880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o */ 367f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o if ((flags & IO_FLAG_RW) && 368f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (uname(&ut) == 0) && 369f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o ((ut.release[0] == '2') && (ut.release[1] == '.') && 370f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (ut.release[2] == '4') && (ut.release[3] == '.') && 371f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (ut.release[4] == '1') && (ut.release[5] >= '0') && 372f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (ut.release[5] < '8')) && 3738880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o (fstat(data->dev, &st) == 0) && 3748880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o (S_ISBLK(st.st_mode))) { 3758880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o struct rlimit rlim; 3768880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o 37764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY; 3788880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o setrlimit(RLIMIT_FSIZE, &rlim); 3798880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o getrlimit(RLIMIT_FSIZE, &rlim); 380bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o if (((unsigned long) rlim.rlim_cur) < 381bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o ((unsigned long) rlim.rlim_max)) { 3828880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o rlim.rlim_cur = rlim.rlim_max; 3838880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o setrlimit(RLIMIT_FSIZE, &rlim); 3848880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o } 3858880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o } 38664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif 3873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *channel = io; 3883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 3893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup: 3913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (data) { 392adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o free_cache(io, data); 3937b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &data); 3943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 395adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (io) 396adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2fs_free_mem((void **) &io); 3973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 3983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 3993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel) 4013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 4033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval = 0; 4043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 405f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 4063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 407f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 408a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 409a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o if (--channel->refcount > 0) 410a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o return 0; 411adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 412adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = flush_cached_blocks(channel, data, 0); 413adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 4143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (close(data->dev) < 0) 4153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = errno; 416adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o free_cache(channel, data); 417f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o 418f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o ext2fs_free_mem((void **) &channel->private_data); 4193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (channel->name) 4207b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &channel->name); 4217b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &channel); 4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 4233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize) 4263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 4287b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o errcode_t retval; 4293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 430f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 4313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 432f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 433f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 4343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (channel->block_size != blksize) { 435adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 0))) 436adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 437adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 4383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o channel->block_size = blksize; 439adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o free_cache(channel, data); 440adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = alloc_cache(channel, data))) 4417b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o return retval; 4423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 4453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block, 4483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, void *buf) 4493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 45182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o struct unix_cache *cache, *reuse[READ_DIRECT_SIZE]; 4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 45331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o char *cp; 454adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i, j; 4553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 456f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 4573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 458f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 4593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 46182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * If we're doing an odd-sized read or a very large read, 46282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * flush out the cache and then do a direct read. 4633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 46482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (count < 0 || count > WRITE_DIRECT_SIZE) { 465adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 0))) 466adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 467adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return raw_read_blk(channel, data, block, count, buf); 4683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 469adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 47031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp = buf; 471adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o while (count > 0) { 472adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* If it's in the cache, use it! */ 47382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if ((cache = find_cached_block(channel, data, block, 47482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o &reuse[0]))) { 475adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG 476adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o printf("Using cached block %d\n", block); 477f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif 47831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o memcpy(cp, cache->buf, channel->block_size); 479adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 480adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o block++; 48131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 482adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 483adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 484adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 485adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Find the number of uncached blocks so we can do a 486adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * single read request 487adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 488adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=1; i < count; i++) 48982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (find_cached_block(channel, data, block+i, 49082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o &reuse[i])) 491adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o break; 492adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG 493adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o printf("Reading %d blocks starting at %d\n", i, block); 494adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif 49531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o if ((retval = raw_read_blk(channel, data, block, i, cp))) 496adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 497adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 498adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* Save the results in the cache */ 499adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (j=0; j < i; j++) { 500adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 50182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o cache = reuse[j]; 50282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o reuse_cache(channel, data, cache, block++); 50382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o memcpy(cache->buf, cp, channel->block_size); 50431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 505adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 5063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 5083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block, 5113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, const void *buf) 5123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 5133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 51482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o struct unix_cache *cache, *reuse; 51523b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o errcode_t retval = 0; 51631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o const char *cp; 51731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o int writethrough; 5183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 519f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 5203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 521f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 5223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 523adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 524adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * If we're doing an odd-sized write or a very large write, 525adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * flush out the cache completely and then do a direct write. 526adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 52782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o if (count < 0 || count > WRITE_DIRECT_SIZE) { 528adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 1))) 529adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 530adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return raw_write_blk(channel, data, block, count, buf); 5313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 533adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 534adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * For a moderate-sized multi-block write, first force a write 535adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * if we're in write-through cache mode, and then fill the 536adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * cache with the blocks. 537adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 538adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH; 539adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (writethrough) 540adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = raw_write_blk(channel, data, block, count, buf); 5413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 54231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp = buf; 543adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o while (count > 0) { 54482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o cache = find_cached_block(channel, data, block, &reuse); 545adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache) { 54682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o cache = reuse; 54782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o reuse_cache(channel, data, cache, block); 548adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 54982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o memcpy(cache->buf, cp, channel->block_size); 55082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o cache->dirty = !writethrough; 551adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 552adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o block++; 55331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 554adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 5553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 5563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 558c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset, 559c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o int size, const void *buf) 560c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{ 561c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o struct unix_private_data *data; 56231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o errcode_t retval = 0; 563c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o size_t actual; 564c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 565c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 566c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o data = (struct unix_private_data *) channel->private_data; 567c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 568c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 569c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o /* 570c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o * Flush out the cache completely 571c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o */ 572c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 1))) 573c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return retval; 574c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 575c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if (lseek(data->dev, offset, SEEK_SET) < 0) 576c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return errno; 577c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 578c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o actual = write(data->dev, buf, size); 579c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if (actual != size) 580c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return EXT2_ET_SHORT_WRITE; 581c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 582c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return 0; 583c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o} 584c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 5853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 58636f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o * Flush data buffers to disk. 5873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 5883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel) 5893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 590f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o struct unix_private_data *data; 591adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval = 0; 592f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 593f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 594f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o data = (struct unix_private_data *) channel->private_data; 595f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 596adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 597adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = flush_cached_blocks(channel, data, 0); 59836f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o fsync(data->dev); 599adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 6003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 6013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 602