unix_io.c revision c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4e
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
2fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o * unix_io.c --- This is the Unix (well, really POSIX) implementation
3fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o * 	of the I/O manager.
43839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
53839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Implements a one-block write-through cache.
63839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
7fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o * Includes support for Windows NT support under Cygwin.
8fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o *
964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
1064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o * 	2002 by Theodore Ts'o.
1119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
1219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header%
1319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
1419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * License.
1519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header%
163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
18dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE_SOURCE
19dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE64_SOURCE
20dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o
213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
234cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H
243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
254cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif
26c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#if HAVE_ERRNO_H
27c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#include <errno.h>
28c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#endif
293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h>
303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <time.h>
31f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__
32f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#include <sys/utsname.h>
33f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif
341d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_STAT_H
353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/stat.h>
361d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
371d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_TYPES_H
383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/types.h>
391d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
40fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#if HAVE_SYS_RESOURCE_H
418880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o#include <sys/resource.h>
42fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
44b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
457b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o#include "ext2fs.h"
463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
47f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o/*
48f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o * For checking structure magic numbers...
49f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o */
50f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
51f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#define EXT2_CHECK_MAGIC(struct, code) \
52f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	  if ((struct)->magic != (code)) return (code)
53adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
54adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostruct unix_cache {
55adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	char		*buf;
56adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	unsigned long	block;
57adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		access_time;
58adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		dirty:1;
59adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		in_use:1;
60adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o};
61adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
62adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#define CACHE_SIZE 8
6382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define WRITE_DIRECT_SIZE 4	/* Must be smaller than CACHE_SIZE */
6482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define READ_DIRECT_SIZE 4	/* Should be smaller than CACHE_SIZE */
65adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct unix_private_data {
67f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	int	magic;
683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	dev;
693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	flags;
70adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int	access_time;
71adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache cache[CACHE_SIZE];
723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel);
753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel);
763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize);
773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *data);
793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *data);
813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel);
82c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
83c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				int size, const void *data);
843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
8523b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data,
8623b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o		 struct unix_cache *cache, unsigned long block);
8723b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o
88f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = {
89f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_ET_MAGIC_IO_MANAGER,
903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	"Unix I/O Manager",
913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_open,
923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_close,
933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_set_blksize,
943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_read_blk,
953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_write_blk,
96c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	unix_flush,
97a85e81a2ff4fb1afc05ff74d5da573031c3495e0Theodore Ts'o#ifdef __CYGWIN__
98fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	0
99fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#else
100c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	unix_write_byte
101fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
1023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
1033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager;
1053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
106adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
107adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions
108adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
109a85e81a2ff4fb1afc05ff74d5da573031c3495e0Theodore Ts'o#ifndef __CYGWIN__
110adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel,
111adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      struct unix_private_data *data,
112adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      unsigned long block,
113adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      int count, void *buf)
114adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
115adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
116adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size_t		size;
117adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
118adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
119adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
120adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size = (count < 0) ? -count : count * channel->block_size;
121adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	location = (ext2_loff_t) block * channel->block_size;
122adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
123adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
124adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
125adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
126adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	actual = read(data->dev, buf, size);
127adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (actual != size) {
128adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (actual < 0)
129adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			actual = 0;
130adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = EXT2_ET_SHORT_READ;
131adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
132adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
133adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
134adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
135adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
136adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	memset((char *) buf+actual, 0, size-actual);
137adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->read_error)
138adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->read_error)(channel, block, count, buf,
139adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o					       size, actual, retval);
140adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
141adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
142a85e81a2ff4fb1afc05ff74d5da573031c3495e0Theodore Ts'o#else /* __CYGWIN__ */
143fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o/*
144fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o * Windows block devices only allow sector alignment IO in offset and size
145fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o */
146fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'ostatic errcode_t raw_read_blk(io_channel channel,
147fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			      struct unix_private_data *data,
148fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			      unsigned long block,
149fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			      int count, void *buf)
150fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o{
151fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	errcode_t	retval;
152fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	size_t		size, alignsize, fragment;
153fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	ext2_loff_t	location;
154fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	int		total = 0, actual;
155fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#define BLOCKALIGN 512
156fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	char		sector[BLOCKALIGN];
157fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
158fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	size = (count < 0) ? -count : count * channel->block_size;
159fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	location = (ext2_loff_t) block * channel->block_size;
160fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#ifdef DEBUG
161fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	printf("count=%d, size=%d, block=%d, blk_size=%d, location=%lx\n",
162fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	 		count, size, block, channel->block_size, location);
163fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
164fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
165fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
166fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		goto error_out;
167fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
168fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	fragment = size % BLOCKALIGN;
169fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	alignsize = size - fragment;
170fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (alignsize) {
171fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		actual = read(data->dev, buf, alignsize);
172fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		if (actual != alignsize)
173fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			goto short_read;
174fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
175fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (fragment) {
176fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		actual = read(data->dev, sector, BLOCKALIGN);
177fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		if (actual != BLOCKALIGN)
178fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			goto short_read;
179fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		memcpy(buf+alignsize, sector, fragment);
180fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
181fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	return 0;
182fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
183fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'oshort_read:
184fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (actual>0)
185fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		total += actual;
186fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	retval = EXT2_ET_SHORT_READ;
187fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
188fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'oerror_out:
189fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	memset((char *) buf+total, 0, size-actual);
190fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (channel->read_error)
191fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		retval = (channel->read_error)(channel, block, count, buf,
192fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o					       size, actual, retval);
193fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	return retval;
194fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o}
195fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
196adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
197adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel,
198adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       struct unix_private_data *data,
199adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       unsigned long block,
200adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       int count, const void *buf)
201adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
202adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size_t		size;
203adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
204adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
205adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
206adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
207adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (count == 1)
208adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		size = channel->block_size;
209adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	else {
210adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (count < 0)
211adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = -count;
212adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
213adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = count * channel->block_size;
214adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
215adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
216adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	location = (ext2_loff_t) block * channel->block_size;
217adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
218adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
219adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
220adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
221adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
222adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	actual = write(data->dev, buf, size);
223adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (actual != size) {
224adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = EXT2_ET_SHORT_WRITE;
225adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
226adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
227adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
228adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
229adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
230adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->write_error)
231adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->write_error)(channel, block, count, buf,
232adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o						size, actual, retval);
233adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
234adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
235adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
236adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
237adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
238adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions
239adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
240adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
241adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */
242adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel,
243adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			     struct unix_private_data *data)
244adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
245adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval;
246adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
247adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
248adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
249adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
250adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
251adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
252adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
253adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
254adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
255adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = ext2fs_get_mem(channel->block_size,
256c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o					     &cache->buf)))
257adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
258adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
259adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
260adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
261adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
262adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */
263adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic void free_cache(io_channel channel,
264adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		       struct unix_private_data *data)
265adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
266adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
267adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
268adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
269adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
270adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
271adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
272adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
273adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
274adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
275adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->buf)
276c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o			ext2fs_free_mem(&cache->buf);
277adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->buf = 0;
278adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
279adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
280adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
281b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
282adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
28382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Try to find a block in the cache.  If the block is not found, and
28482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * eldest is a non-zero pointer, then fill in eldest with the cache
28582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * entry to that should be reused.
286adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
28731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'ostatic struct unix_cache *find_cached_block(io_channel channel,
28831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o					    struct unix_private_data *data,
28931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o					    unsigned long block,
29082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o					    struct unix_cache **eldest)
291adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
29231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	struct unix_cache	*cache, *unused_cache, *oldest_cache;
293adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
294adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
29531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	unused_cache = oldest_cache = 0;
296adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
297adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use) {
29882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			if (!unused_cache)
29982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o				unused_cache = cache;
300adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
301adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
302adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->block == block) {
303adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->access_time = ++data->access_time;
304adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return cache;
305adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
306adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!oldest_cache ||
307adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		    (cache->access_time < oldest_cache->access_time))
308adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			oldest_cache = cache;
309adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
31082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (eldest)
31182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		*eldest = (unused_cache) ? unused_cache : oldest_cache;
31282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	return 0;
31382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o}
31482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
31582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o/*
31682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Reuse a particular cache entry for another block.
31782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o */
31823b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data,
31982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		 struct unix_cache *cache, unsigned long block)
32082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o{
32182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (cache->dirty && cache->in_use)
32282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		raw_write_blk(channel, data, cache->block, 1, cache->buf);
32382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
324adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->in_use = 1;
3251d47dfb91ef010c506e9354dec102385d8494d8fTheodore Ts'o	cache->dirty = 0;
326adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->block = block;
327adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->access_time = ++data->access_time;
328adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
329adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
330adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
331adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache
332adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
333adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel,
334adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     struct unix_private_data *data,
335adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     int invalidate)
336adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
337adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
338adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
339adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval, retval2;
340adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
341adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
342adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval2 = 0;
343adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
344adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use)
345adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
346adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
347adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (invalidate)
348adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->in_use = 0;
349adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
350adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->dirty)
351adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
352adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
353adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data,
354adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				       cache->block, 1, cache->buf);
355adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (retval)
356adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			retval2 = retval;
357adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
358adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->dirty = 0;
359adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
360adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval2;
361adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
362b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
363adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
3643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel)
3653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io_channel	io = NULL;
3673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data = NULL;
3683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
369dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	int		open_flags;
3708880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	struct stat	st;
371f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__
372f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	struct 		utsname ut;
373f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif
3743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
37550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (name == 0)
37650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return EXT2_ET_BAD_DEVICE_NAME;
377c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
3787b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3797b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		return retval;
380f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	memset(io, 0, sizeof(struct struct_io_channel));
381f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
382c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
3837b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3857b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
3863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->manager = unix_io_manager;
387c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(strlen(name)+1, &io->name);
3887b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3907b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
3913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	strcpy(io->name, name);
3923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->private_data = data;
393f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->block_size = 1024;
394f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->read_error = 0;
395f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->write_error = 0;
396a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	io->refcount = 1;
3973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(data, 0, sizeof(struct unix_private_data));
399f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
4007b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
401adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if ((retval = alloc_cache(io, data)))
402adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto cleanup;
403adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
404dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
405dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#ifdef HAVE_OPEN64
406dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	data->dev = open64(name, open_flags);
407dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#else
408dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	data->dev = open(name, open_flags);
409dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#endif
4103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data->dev < 0) {
4113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
4123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
4133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
41464e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o
41564e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#ifdef __linux__
41664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#undef RLIM_INFINITY
41764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
41864e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY	((unsigned long)(~0UL>>1))
41964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#else
42064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY  (~0UL)
42164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
4228880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	/*
423f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * Work around a bug in 2.4.10-2.4.18 kernels where writes to
424f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * block devices are wrongly getting hit by the filesize
425f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * limit.  This workaround isn't perfect, since it won't work
426f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * if glibc wasn't built against 2.2 header files.  (Sigh.)
427f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 *
4288880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	 */
429f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	if ((flags & IO_FLAG_RW) &&
430f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    (uname(&ut) == 0) &&
431f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    ((ut.release[0] == '2') && (ut.release[1] == '.') &&
432f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[2] == '4') && (ut.release[3] == '.') &&
433f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[4] == '1') && (ut.release[5] >= '0') &&
434f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[5] < '8')) &&
4358880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (fstat(data->dev, &st) == 0) &&
4368880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (S_ISBLK(st.st_mode))) {
4378880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		struct rlimit	rlim;
4388880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o
43964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o		rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
4408880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		setrlimit(RLIMIT_FSIZE, &rlim);
4418880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		getrlimit(RLIMIT_FSIZE, &rlim);
442bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		if (((unsigned long) rlim.rlim_cur) <
443bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		    ((unsigned long) rlim.rlim_max)) {
4448880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			rlim.rlim_cur = rlim.rlim_max;
4458880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			setrlimit(RLIMIT_FSIZE, &rlim);
4468880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		}
4478880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	}
44864e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
4493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*channel = io;
4503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
4513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup:
4533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data) {
454adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		free_cache(io, data);
455c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&data);
4563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
457adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (io)
458c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&io);
4593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
4603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel)
4633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
4653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval = 0;
4663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
467f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
469f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
470a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
471a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	if (--channel->refcount > 0)
472a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o		return 0;
473adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
474b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
475adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
476b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
477adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
4783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (close(data->dev) < 0)
4793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
480adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	free_cache(channel, data);
481f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o
482c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&channel->private_data);
4833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->name)
484c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&channel->name);
485c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&channel);
4863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
4873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize)
4903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
4927b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	errcode_t		retval;
4933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
494f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
496f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
497f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
4983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->block_size != blksize) {
499b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
500adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
501adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
502b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
503adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
5043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		channel->block_size = blksize;
505adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		free_cache(channel, data);
506adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = alloc_cache(channel, data)))
5077b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			return retval;
5083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
5103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
5143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *buf)
5153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
51782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
5183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
51931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	char		*cp;
520adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		i, j;
5213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
522f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
524f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
5253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
526b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE
527b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o	return raw_read_blk(channel, data, block, count, buf);
528b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#else
5293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
53082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * If we're doing an odd-sized read or a very large read,
53182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * flush out the cache and then do a direct read.
5323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
53382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
534adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
535adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
536adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_read_blk(channel, data, block, count, buf);
5373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
538adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
53931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
540adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
541adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* If it's in the cache, use it! */
54282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		if ((cache = find_cached_block(channel, data, block,
54382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o					       &reuse[0]))) {
544adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
545adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			printf("Using cached block %d\n", block);
546f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif
54731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			memcpy(cp, cache->buf, channel->block_size);
548adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
549adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			block++;
55031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
551adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
552adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
553adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/*
554adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * Find the number of uncached blocks so we can do a
555adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * single read request
556adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 */
557adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (i=1; i < count; i++)
55882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			if (find_cached_block(channel, data, block+i,
55982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o					      &reuse[i]))
560adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				break;
561adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
562adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		printf("Reading %d blocks starting at %d\n", i, block);
563adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif
56431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		if ((retval = raw_read_blk(channel, data, block, i, cp)))
565adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
566adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
567adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* Save the results in the cache */
568adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (j=0; j < i; j++) {
569adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
57082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse[j];
57182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block++);
57282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			memcpy(cache->buf, cp, channel->block_size);
57331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
574adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
5753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
577b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
5783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
5813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *buf)
5823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
58482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse;
58523b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o	errcode_t	retval = 0;
58631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	const char	*cp;
58731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	int		writethrough;
5883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
589f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
591f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
5923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
593b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE
594b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o	return raw_write_blk(channel, data, block, count, buf);
595b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#else
596adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
597adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * If we're doing an odd-sized write or a very large write,
598adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * flush out the cache completely and then do a direct write.
599adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
60082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
601adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 1)))
602adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
603adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_write_blk(channel, data, block, count, buf);
6043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
606adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
607adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * For a moderate-sized multi-block write, first force a write
608adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * if we're in write-through cache mode, and then fill the
609adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * cache with the blocks.
610adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
611adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
612adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (writethrough)
613adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data, block, count, buf);
6143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
61531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
616adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
61782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		cache = find_cached_block(channel, data, block, &reuse);
618adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache) {
61982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse;
62082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block);
621adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
62282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		memcpy(cache->buf, cp, channel->block_size);
62382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		cache->dirty = !writethrough;
624adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		count--;
625adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		block++;
62631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		cp += channel->block_size;
627adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
6283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
629b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
6303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
632c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
633c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				 int size, const void *buf)
634c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{
635c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	struct unix_private_data *data;
63631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	errcode_t	retval = 0;
637c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	size_t		actual;
638c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
639c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
640c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
641c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
642c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
643b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
644c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	/*
645c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 * Flush out the cache completely
646c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 */
647c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if ((retval = flush_cached_blocks(channel, data, 1)))
648c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return retval;
649b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
650c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
651c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (lseek(data->dev, offset, SEEK_SET) < 0)
652c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return errno;
653c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
654c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	actual = write(data->dev, buf, size);
655c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (actual != size)
656c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return EXT2_ET_SHORT_WRITE;
657c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
658c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	return 0;
659c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o}
660c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
6613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
66236f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o * Flush data buffers to disk.
6633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
6643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel)
6653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
666f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	struct unix_private_data *data;
667adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t retval = 0;
668f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
669f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
670f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
671f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
672adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
673b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
674adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
675b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
67636f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o	fsync(data->dev);
677adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
6783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
680