2
* unix_io.c --- This is the Unix I/O interface to the I/O manager.
4
* Implements a one-block write-through cache.
6
* Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
7
* 2002 by Theodore Ts'o.
10
* This file may be redistributed under the terms of the GNU Public
15
#define _LARGEFILE_SOURCE
16
#define _LARGEFILE64_SOURCE
32
#include <sys/types.h>
34
#include <sys/resource.h>
40
* For checking structure magic numbers...
43
#define EXT2_CHECK_MAGIC(struct, code) \
44
if ((struct)->magic != (code)) return (code)
55
#define WRITE_VIA_CACHE_SIZE 4 /* Must be smaller than CACHE_SIZE */
57
struct unix_private_data {
62
struct unix_cache cache[CACHE_SIZE];
65
static errcode_t unix_open(const char *name, int flags, io_channel *channel);
66
static errcode_t unix_close(io_channel channel);
67
static errcode_t unix_set_blksize(io_channel channel, int blksize);
68
static errcode_t unix_read_blk(io_channel channel, unsigned long block,
69
int count, void *data);
70
static errcode_t unix_write_blk(io_channel channel, unsigned long block,
71
int count, const void *data);
72
static errcode_t unix_flush(io_channel channel);
73
static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
74
int size, const void *data);
76
static struct struct_io_manager struct_unix_manager = {
77
EXT2_ET_MAGIC_IO_MANAGER,
88
io_manager unix_io_manager = &struct_unix_manager;
91
* Here are the raw I/O functions
93
static errcode_t raw_read_blk(io_channel channel,
94
struct unix_private_data *data,
100
ext2_loff_t location;
103
size = (count < 0) ? -count : count * channel->block_size;
104
location = (ext2_loff_t) block * channel->block_size;
105
if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
106
retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
109
actual = read(data->dev, buf, size);
110
if (actual != size) {
113
retval = EXT2_ET_SHORT_READ;
119
memset((char *) buf+actual, 0, size-actual);
120
if (channel->read_error)
121
retval = (channel->read_error)(channel, block, count, buf,
122
size, actual, retval);
126
static errcode_t raw_write_blk(io_channel channel,
127
struct unix_private_data *data,
129
int count, const void *buf)
132
ext2_loff_t location;
137
size = channel->block_size;
142
size = count * channel->block_size;
145
location = (ext2_loff_t) block * channel->block_size;
146
if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
147
retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
151
actual = write(data->dev, buf, size);
152
if (actual != size) {
153
retval = EXT2_ET_SHORT_WRITE;
159
if (channel->write_error)
160
retval = (channel->write_error)(channel, block, count, buf,
161
size, actual, retval);
167
* Here we implement the cache functions
170
/* Allocate the cache buffers */
171
static errcode_t alloc_cache(io_channel channel,
172
struct unix_private_data *data)
175
struct unix_cache *cache;
178
data->access_time = 0;
179
for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
181
cache->access_time = 0;
184
if ((retval = ext2fs_get_mem(channel->block_size,
185
(void **) &cache->buf)))
191
/* Free the cache buffers */
192
static void free_cache(io_channel channel,
193
struct unix_private_data *data)
195
struct unix_cache *cache;
198
data->access_time = 0;
199
for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
201
cache->access_time = 0;
205
ext2fs_free_mem((void **) &cache->buf);
211
* Try to find a block in the cache. If get_cache is non-zero, then
212
* if the block isn't in the cache, evict the oldest block in the
213
* cache and create a new cache entry for the requested block.
215
static struct unix_cache *find_cached_block(io_channel channel,
216
struct unix_private_data *data,
220
struct unix_cache *cache, *unused_cache, *oldest_cache;
223
unused_cache = oldest_cache = 0;
224
for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
225
if (!cache->in_use) {
226
unused_cache = cache;
229
if (cache->block == block) {
230
cache->access_time = ++data->access_time;
234
(cache->access_time < oldest_cache->access_time))
235
oldest_cache = cache;
241
* Try to allocate cache slot.
244
cache = unused_cache;
246
cache = oldest_cache;
248
raw_write_blk(channel, data,
249
cache->block, 1, cache->buf);
252
cache->block = block;
253
cache->access_time = ++data->access_time;
258
* Flush all of the blocks in the cache
260
static errcode_t flush_cached_blocks(io_channel channel,
261
struct unix_private_data *data,
265
struct unix_cache *cache;
266
errcode_t retval, retval2;
270
for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
280
retval = raw_write_blk(channel, data,
281
cache->block, 1, cache->buf);
292
static errcode_t unix_open(const char *name, int flags, io_channel *channel)
294
io_channel io = NULL;
295
struct unix_private_data *data = NULL;
301
return EXT2_ET_BAD_DEVICE_NAME;
302
retval = ext2fs_get_mem(sizeof(struct struct_io_channel),
306
memset(io, 0, sizeof(struct struct_io_channel));
307
io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
308
retval = ext2fs_get_mem(sizeof(struct unix_private_data),
313
io->manager = unix_io_manager;
314
retval = ext2fs_get_mem(strlen(name)+1, (void **) &io->name);
318
strcpy(io->name, name);
319
io->private_data = data;
320
io->block_size = 1024;
325
memset(data, 0, sizeof(struct unix_private_data));
326
data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
328
if ((retval = alloc_cache(io, data)))
331
open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
333
data->dev = open64(name, open_flags);
335
data->dev = open(name, open_flags);
344
#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
345
#define RLIM_INFINITY ((unsigned long)(~0UL>>1))
347
#define RLIM_INFINITY (~0UL)
350
* Work around a bug in 2.4.10+ kernels where writes to block
351
* devices are wrongly getting hit by the filesize limit.
353
if ((flags & IO_FLAG_RW) &&
354
(fstat(data->dev, &st) == 0) &&
355
(S_ISBLK(st.st_mode))) {
358
rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
359
setrlimit(RLIMIT_FSIZE, &rlim);
360
getrlimit(RLIMIT_FSIZE, &rlim);
361
if (((unsigned long) rlim.rlim_cur) <
362
((unsigned long) rlim.rlim_max)) {
363
rlim.rlim_cur = rlim.rlim_max;
364
setrlimit(RLIMIT_FSIZE, &rlim);
373
free_cache(io, data);
374
ext2fs_free_mem((void **) &data);
377
ext2fs_free_mem((void **) &io);
381
static errcode_t unix_close(io_channel channel)
383
struct unix_private_data *data;
384
errcode_t retval = 0;
386
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
387
data = (struct unix_private_data *) channel->private_data;
388
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
390
if (--channel->refcount > 0)
393
retval = flush_cached_blocks(channel, data, 0);
395
if (close(data->dev) < 0)
397
free_cache(channel, data);
399
ext2fs_free_mem((void **) &channel->private_data);
401
ext2fs_free_mem((void **) &channel->name);
402
ext2fs_free_mem((void **) &channel);
406
static errcode_t unix_set_blksize(io_channel channel, int blksize)
408
struct unix_private_data *data;
411
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
412
data = (struct unix_private_data *) channel->private_data;
413
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
415
if (channel->block_size != blksize) {
416
if ((retval = flush_cached_blocks(channel, data, 0)))
419
channel->block_size = blksize;
420
free_cache(channel, data);
421
if ((retval = alloc_cache(channel, data)))
428
static errcode_t unix_read_blk(io_channel channel, unsigned long block,
429
int count, void *buf)
431
struct unix_private_data *data;
432
struct unix_cache *cache;
437
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
438
data = (struct unix_private_data *) channel->private_data;
439
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
442
* If we're doing an odd-sized read, flush out the cache and
443
* then do a direct read.
446
if ((retval = flush_cached_blocks(channel, data, 0)))
448
return raw_read_blk(channel, data, block, count, buf);
453
/* If it's in the cache, use it! */
454
if ((cache = find_cached_block(channel, data, block, 0))) {
456
printf("Using cached block %d\n", block);
458
memcpy(cp, cache->buf, channel->block_size);
461
cp += channel->block_size;
465
* Find the number of uncached blocks so we can do a
466
* single read request
468
for (i=1; i < count; i++)
469
if (find_cached_block(channel, data, block+i, 0))
472
printf("Reading %d blocks starting at %d\n", i, block);
474
if ((retval = raw_read_blk(channel, data, block, i, cp)))
477
/* Save the results in the cache */
478
for (j=0; j < i; j++) {
480
cache = find_cached_block(channel, data, block++, 1);
482
memcpy(cache->buf, cp, channel->block_size);
483
cp += channel->block_size;
489
static errcode_t unix_write_blk(io_channel channel, unsigned long block,
490
int count, const void *buf)
492
struct unix_private_data *data;
493
struct unix_cache *cache;
494
errcode_t retval = 0, retval2;
498
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
499
data = (struct unix_private_data *) channel->private_data;
500
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
503
* If we're doing an odd-sized write or a very large write,
504
* flush out the cache completely and then do a direct write.
506
if (count < 0 || count > WRITE_VIA_CACHE_SIZE) {
507
if ((retval = flush_cached_blocks(channel, data, 1)))
509
return raw_write_blk(channel, data, block, count, buf);
513
* For a moderate-sized multi-block write, first force a write
514
* if we're in write-through cache mode, and then fill the
515
* cache with the blocks.
517
writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
519
retval = raw_write_blk(channel, data, block, count, buf);
523
cache = find_cached_block(channel, data, block, 1);
526
* Oh shit, we couldn't get cache descriptor.
527
* Force the write directly.
529
if ((retval2 = raw_write_blk(channel, data, block,
533
memcpy(cache->buf, cp, channel->block_size);
534
cache->dirty = !writethrough;
538
cp += channel->block_size;
543
static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
544
int size, const void *buf)
546
struct unix_private_data *data;
547
errcode_t retval = 0;
550
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
551
data = (struct unix_private_data *) channel->private_data;
552
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
555
* Flush out the cache completely
557
if ((retval = flush_cached_blocks(channel, data, 1)))
560
if (lseek(data->dev, offset, SEEK_SET) < 0)
563
actual = write(data->dev, buf, size);
565
return EXT2_ET_SHORT_WRITE;
571
* Flush data buffers to disk.
573
static errcode_t unix_flush(io_channel channel)
575
struct unix_private_data *data;
576
errcode_t retval = 0;
578
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
579
data = (struct unix_private_data *) channel->private_data;
580
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
582
retval = flush_cached_blocks(channel, data, 0);