unix_io.c revision f154d2f687e922f8444ef3050dc83f5d8e0e2178
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 58adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#define WRITE_VIA_CACHE_SIZE 4 /* Must be smaller than CACHE_SIZE */ 59adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct unix_private_data { 61f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o int magic; 623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int dev; 633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int flags; 64adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int access_time; 65adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache cache[CACHE_SIZE]; 663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel); 693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel); 703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize); 713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block, 723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, void *data); 733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block, 743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, const void *data); 753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel); 76c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset, 77c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o int size, const void *data); 783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 79f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = { 80f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_ET_MAGIC_IO_MANAGER, 813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o "Unix I/O Manager", 823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_open, 833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_close, 843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_set_blksize, 853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_read_blk, 863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o unix_write_blk, 87c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o unix_flush, 88c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o unix_write_byte 893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}; 903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager; 923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 93adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 94adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions 95adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 96adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel, 97adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 98adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o unsigned long block, 99adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int count, void *buf) 100adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 101adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 102adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size_t size; 103adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2_loff_t location; 104adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int actual = 0; 105adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 106adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = (count < 0) ? -count : count * channel->block_size; 107adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o location = (ext2_loff_t) block * channel->block_size; 108adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 109adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 110adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 111adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 112adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = read(data->dev, buf, size); 113adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual != size) { 114adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual < 0) 115adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = 0; 116adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = EXT2_ET_SHORT_READ; 117adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 118adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 119adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 120adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 121adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out: 122adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o memset((char *) buf+actual, 0, size-actual); 123adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (channel->read_error) 124adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = (channel->read_error)(channel, block, count, buf, 125adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size, actual, retval); 126adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 127adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 128adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 129adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel, 130adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 131adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o unsigned long block, 132adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int count, const void *buf) 133adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 134adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size_t size; 135adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2_loff_t location; 136adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int actual = 0; 137adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 138adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 139adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count == 1) 140adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = channel->block_size; 141adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else { 142adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count < 0) 143adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = -count; 144adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else 145adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size = count * channel->block_size; 146adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 147adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 148adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o location = (ext2_loff_t) block * channel->block_size; 149adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { 150adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; 151adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 152adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 153adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 154adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o actual = write(data->dev, buf, size); 155adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (actual != size) { 156adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = EXT2_ET_SHORT_WRITE; 157adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto error_out; 158adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 159adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 160adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 161adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out: 162adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (channel->write_error) 163adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = (channel->write_error)(channel, block, count, buf, 164adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o size, actual, retval); 165adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 166adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 167adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 168adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 169adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 170adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions 171adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 172adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 173adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */ 174adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel, 175adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data) 176adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 177adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval; 178adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 179adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 180adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 181adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o data->access_time = 0; 182adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 183adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = 0; 184adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = 0; 185adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 186adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 187adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = ext2fs_get_mem(channel->block_size, 188adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o (void **) &cache->buf))) 189adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 190adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 191adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 192adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 193adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 194adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */ 195adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic void free_cache(io_channel channel, 196adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data) 197adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 198adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 199adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 200adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 201adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o data->access_time = 0; 202adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 203adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = 0; 204adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = 0; 205adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 206adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 207adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->buf) 208adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2fs_free_mem((void **) &cache->buf); 209adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->buf = 0; 210adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 211adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 212adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 213adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 214adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Try to find a block in the cache. If get_cache is non-zero, then 215adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * if the block isn't in the cache, evict the oldest block in the 216adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * cache and create a new cache entry for the requested block. 217adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 21831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'ostatic struct unix_cache *find_cached_block(io_channel channel, 21931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o struct unix_private_data *data, 22031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o unsigned long block, 22131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o int get_cache) 222adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 22331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o struct unix_cache *cache, *unused_cache, *oldest_cache; 224adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 225adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 22631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o unused_cache = oldest_cache = 0; 227adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 228adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->in_use) { 22931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o unused_cache = cache; 230adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 231adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 232adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->block == block) { 233adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = ++data->access_time; 234adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return cache; 235adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 236adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!oldest_cache || 237adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o (cache->access_time < oldest_cache->access_time)) 238adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o oldest_cache = cache; 239adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 240adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!get_cache) 241adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return 0; 242adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 243adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 244adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Try to allocate cache slot. 245adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 24631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o if (unused_cache) 24731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cache = unused_cache; 248adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else { 249adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache = oldest_cache; 250adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache->dirty) 251adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o raw_write_blk(channel, data, 252adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block, 1, cache->buf); 253adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 254adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 1; 255adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block = block; 256adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->access_time = ++data->access_time; 257adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return cache; 258adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 259adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 260adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* 261adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache 262adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 263adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel, 264adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_private_data *data, 265adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int invalidate) 266adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 267adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{ 268adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 269adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval, retval2; 270adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i; 271adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 272adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval2 = 0; 273adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) { 274adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->in_use) 275adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 276adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 277adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (invalidate) 278adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->in_use = 0; 279adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 280adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache->dirty) 281adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 282adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 283adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = raw_write_blk(channel, data, 284adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->block, 1, cache->buf); 285adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (retval) 286adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval2 = retval; 287adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o else 288adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = 0; 289adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 290adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval2; 291adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o} 292adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 293adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 294adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 2953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel) 2963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 2973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io_channel io = NULL; 2983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data = NULL; 2993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 300dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o int open_flags; 3018880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o struct stat st; 302f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__ 303f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o struct utsname ut; 304f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif 3053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 30650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o if (name == 0) 30750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o return EXT2_ET_BAD_DEVICE_NAME; 3087b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o retval = ext2fs_get_mem(sizeof(struct struct_io_channel), 3097b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o (void **) &io); 3107b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 3117b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o return retval; 312f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o memset(io, 0, sizeof(struct struct_io_channel)); 313f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->magic = EXT2_ET_MAGIC_IO_CHANNEL; 3147b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o retval = ext2fs_get_mem(sizeof(struct unix_private_data), 3157b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o (void **) &data); 3167b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 3173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 3187b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 3193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io->manager = unix_io_manager; 3207b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o retval = ext2fs_get_mem(strlen(name)+1, (void **) &io->name); 3217b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o if (retval) 3223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 3237b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 3243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o strcpy(io->name, name); 3253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o io->private_data = data; 326f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->block_size = 1024; 327f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->read_error = 0; 328f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o io->write_error = 0; 329a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o io->refcount = 1; 3303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o memset(data, 0, sizeof(struct unix_private_data)); 332f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; 3337b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o 334adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = alloc_cache(io, data))) 335adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o goto cleanup; 336adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 337dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY; 338dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#ifdef HAVE_OPEN64 339dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o data->dev = open64(name, open_flags); 340dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#else 341dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o data->dev = open(name, open_flags); 342dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#endif 3433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (data->dev < 0) { 3443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = errno; 3453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o goto cleanup; 3463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 34764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o 34864e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#ifdef __linux__ 34964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#undef RLIM_INFINITY 35064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4))) 35164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY ((unsigned long)(~0UL>>1)) 35264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#else 35364e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY (~0UL) 35464e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif 3558880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o /* 356f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * Work around a bug in 2.4.10-2.4.18 kernels where writes to 357f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * block devices are wrongly getting hit by the filesize 358f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * limit. This workaround isn't perfect, since it won't work 359f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * if glibc wasn't built against 2.2 header files. (Sigh.) 360f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o * 3618880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o */ 362f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o if ((flags & IO_FLAG_RW) && 363f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (uname(&ut) == 0) && 364f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o ((ut.release[0] == '2') && (ut.release[1] == '.') && 365f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (ut.release[2] == '4') && (ut.release[3] == '.') && 366f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (ut.release[4] == '1') && (ut.release[5] >= '0') && 367f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o (ut.release[5] < '8')) && 3688880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o (fstat(data->dev, &st) == 0) && 3698880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o (S_ISBLK(st.st_mode))) { 3708880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o struct rlimit rlim; 3718880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o 37264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY; 3738880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o setrlimit(RLIMIT_FSIZE, &rlim); 3748880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o getrlimit(RLIMIT_FSIZE, &rlim); 375bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o if (((unsigned long) rlim.rlim_cur) < 376bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o ((unsigned long) rlim.rlim_max)) { 3778880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o rlim.rlim_cur = rlim.rlim_max; 3788880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o setrlimit(RLIMIT_FSIZE, &rlim); 3798880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o } 3808880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o } 38164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif 3823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *channel = io; 3833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 3843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup: 3863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (data) { 387adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o free_cache(io, data); 3887b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &data); 3893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 390adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (io) 391adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o ext2fs_free_mem((void **) &io); 3923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 3933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 3943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 3953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel) 3963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 3973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 3983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval = 0; 3993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 400f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 4013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 402f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 403a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 404a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o if (--channel->refcount > 0) 405a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o return 0; 406adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 407adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = flush_cached_blocks(channel, data, 0); 408adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 4093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (close(data->dev) < 0) 4103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o retval = errno; 411adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o free_cache(channel, data); 412f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o 413f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o ext2fs_free_mem((void **) &channel->private_data); 4143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (channel->name) 4157b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &channel->name); 4167b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o ext2fs_free_mem((void **) &channel); 4173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 4183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 4193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize) 4213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 4237b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o errcode_t retval; 4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 425f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 4263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 427f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 428f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 4293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (channel->block_size != blksize) { 430adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 0))) 431adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 432adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 4333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o channel->block_size = blksize; 434adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o free_cache(channel, data); 435adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = alloc_cache(channel, data))) 4367b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o return retval; 4373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 4383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 4393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block, 4433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, void *buf) 4443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 4453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 446adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 4473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o errcode_t retval; 44831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o char *cp; 449adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o int i, j; 4503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 451f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 453f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 4543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 4553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o /* 456adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * If we're doing an odd-sized read, flush out the cache and 457adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * then do a direct read. 4583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 459adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count < 0) { 460adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 0))) 461adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 462adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return raw_read_blk(channel, data, block, count, buf); 4633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 464adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 46531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp = buf; 466adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o while (count > 0) { 467adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* If it's in the cache, use it! */ 468adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((cache = find_cached_block(channel, data, block, 0))) { 469adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG 470adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o printf("Using cached block %d\n", block); 471f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif 47231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o memcpy(cp, cache->buf, channel->block_size); 473adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 474adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o block++; 47531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 476adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o continue; 477adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 478adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 479adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Find the number of uncached blocks so we can do a 480adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * single read request 481adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 482adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (i=1; i < count; i++) 483adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (find_cached_block(channel, data, block+i, 0)) 484adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o break; 485adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG 486adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o printf("Reading %d blocks starting at %d\n", i, block); 487adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif 48831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o if ((retval = raw_read_blk(channel, data, block, i, cp))) 489adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 490adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 491adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* Save the results in the cache */ 492adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o for (j=0; j < i; j++) { 493adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 494adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache = find_cached_block(channel, data, block++, 1); 495adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (cache) 49631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o memcpy(cache->buf, cp, channel->block_size); 49731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 498adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 4993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return 0; 5013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 5033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block, 5043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o int count, const void *buf) 5053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 5063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o struct unix_private_data *data; 507adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o struct unix_cache *cache; 508adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval = 0, retval2; 50931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o const char *cp; 51031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o int writethrough; 5113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 512f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 5133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o data = (struct unix_private_data *) channel->private_data; 514f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 5153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 516adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 517adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * If we're doing an odd-sized write or a very large write, 518adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * flush out the cache completely and then do a direct write. 519adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 520adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (count < 0 || count > WRITE_VIA_CACHE_SIZE) { 521adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 1))) 522adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 523adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return raw_write_blk(channel, data, block, count, buf); 5243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } 5253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 526adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 527adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * For a moderate-sized multi-block write, first force a write 528adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * if we're in write-through cache mode, and then fill the 529adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * cache with the blocks. 530adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 531adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH; 532adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (writethrough) 533adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = raw_write_blk(channel, data, block, count, buf); 5343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 53531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp = buf; 536adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o while (count > 0) { 537adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache = find_cached_block(channel, data, block, 1); 538adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if (!cache) { 539adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o /* 540adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Oh shit, we couldn't get cache descriptor. 541adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Force the write directly. 542adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */ 543adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o if ((retval2 = raw_write_blk(channel, data, block, 54431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o 1, cp))) 545adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = retval2; 546adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } else { 54731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o memcpy(cache->buf, cp, channel->block_size); 548adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o cache->dirty = !writethrough; 549adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 550adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o count--; 551adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o block++; 55231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o cp += channel->block_size; 553adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o } 5543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o return retval; 5553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 5563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 557c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset, 558c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o int size, const void *buf) 559c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{ 560c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o struct unix_private_data *data; 56131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o errcode_t retval = 0; 562c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o size_t actual; 563c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 564c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 565c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o data = (struct unix_private_data *) channel->private_data; 566c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 567c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 568c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o /* 569c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o * Flush out the cache completely 570c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o */ 571c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if ((retval = flush_cached_blocks(channel, data, 1))) 572c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return retval; 573c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 574c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if (lseek(data->dev, offset, SEEK_SET) < 0) 575c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return errno; 576c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 577c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o actual = write(data->dev, buf, size); 578c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o if (actual != size) 579c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return EXT2_ET_SHORT_WRITE; 580c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 581c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o return 0; 582c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o} 583c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o 5843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* 58536f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o * Flush data buffers to disk. 5863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 5873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel) 5883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 589f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o struct unix_private_data *data; 590adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o errcode_t retval = 0; 591f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 592f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); 593f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o data = (struct unix_private_data *) channel->private_data; 594f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); 595adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o 596adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o retval = flush_cached_blocks(channel, data, 0); 59736f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o fsync(data->dev); 598adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o return retval; 5993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o} 6003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 601