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