unix_io.c revision 1d6fd6d0c3766a8165e69284c75812574a29c804
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 *
7efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore 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%
13543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * This file may be redistributed under the terms of the GNU Library
14543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * General Public License, version 2.
1519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header%
163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
18dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE_SOURCE
19dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE64_SOURCE
20cf5301d7f2c3bbed3d26600335102414cbf0c4baAndreas Dilger#ifndef _GNU_SOURCE
217f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#define _GNU_SOURCE
22cf5301d7f2c3bbed3d26600335102414cbf0c4baAndreas Dilger#endif
23dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o
24d1154eb460efe588eaed3d439c1caaca149fa362Theodore Ts'o#include "config.h"
253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
274cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H
283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
294cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif
30c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#if HAVE_ERRNO_H
31c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#include <errno.h>
32c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#endif
333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h>
343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <time.h>
35f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__
36f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#include <sys/utsname.h>
37f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif
387ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#ifdef HAVE_SYS_IOCTL_H
397ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#include <sys/ioctl.h>
407ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#endif
417ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#ifdef HAVE_SYS_MOUNT_H
427ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#include <sys/mount.h>
437ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#endif
441d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_STAT_H
453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/stat.h>
461d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
471d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_TYPES_H
483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/types.h>
491d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
50fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#if HAVE_SYS_RESOURCE_H
518880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o#include <sys/resource.h>
52fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
53d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner#if HAVE_LINUX_FALLOC_H
54d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner#include <linux/falloc.h>
55d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner#endif
563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
577f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#if defined(__linux__) && defined(_IO) && !defined(BLKROGET)
587ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#define BLKROGET   _IO(0x12, 94) /* Get read-only status (0 = read_write).  */
597ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#endif
607ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen
617f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#undef ALIGN_DEBUG
627f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
63b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
647b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o#include "ext2fs.h"
653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
66f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o/*
67f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o * For checking structure magic numbers...
68f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o */
69f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
70f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#define EXT2_CHECK_MAGIC(struct, code) \
71f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	  if ((struct)->magic != (code)) return (code)
72adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
73adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostruct unix_cache {
7440024fdbafdf3875a0950e8fee5dd8bf69ea6b6cTheodore Ts'o	char			*buf;
7540024fdbafdf3875a0950e8fee5dd8bf69ea6b6cTheodore Ts'o	unsigned long long	block;
7640024fdbafdf3875a0950e8fee5dd8bf69ea6b6cTheodore Ts'o	int			access_time;
7740024fdbafdf3875a0950e8fee5dd8bf69ea6b6cTheodore Ts'o	unsigned		dirty:1;
7840024fdbafdf3875a0950e8fee5dd8bf69ea6b6cTheodore Ts'o	unsigned		in_use:1;
79adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o};
80adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
81adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#define CACHE_SIZE 8
8282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define WRITE_DIRECT_SIZE 4	/* Must be smaller than CACHE_SIZE */
8382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define READ_DIRECT_SIZE 4	/* Should be smaller than CACHE_SIZE */
84adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct unix_private_data {
86f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	int	magic;
873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	dev;
883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	flags;
897f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	int	align;
90adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int	access_time;
912e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	ext2_loff_t offset;
92adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache cache[CACHE_SIZE];
937f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	void	*bounce;
946d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	struct struct_io_stats io_stats;
953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
977f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#define IS_ALIGNED(n, align) ((((unsigned long) n) & \
987f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			       ((unsigned long) ((align)-1))) == 0)
997f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
1003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel);
1013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel);
1023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize);
1033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
1043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *data);
1053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
1063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *data);
1073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel);
108c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
109c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				int size, const void *data);
110efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'ostatic errcode_t unix_set_option(io_channel channel, const char *option,
1112e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o				 const char *arg);
1126d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'ostatic errcode_t unix_get_stats(io_channel channel, io_stats *stats)
1136d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o;
11423b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data,
11559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos		 struct unix_cache *cache, unsigned long long block);
11659ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
11759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos			       int count, void *data);
11859ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk64(io_channel channel, unsigned long long block,
11959ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos				int count, const void *data);
120e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czernerstatic errcode_t unix_discard(io_channel channel, unsigned long long block,
121e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner			      unsigned long long count);
12223b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o
123f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = {
124f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_ET_MAGIC_IO_MANAGER,
1253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	"Unix I/O Manager",
1263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_open,
1273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_close,
1283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_set_blksize,
1293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_read_blk,
1303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_write_blk,
131c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	unix_flush,
1322e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	unix_write_byte,
1336d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	unix_set_option,
1346d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	unix_get_stats,
13559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos	unix_read_blk64,
13659ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos	unix_write_blk64,
137e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner	unix_discard,
1383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
1393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager;
1413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1426d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'ostatic errcode_t unix_get_stats(io_channel channel, io_stats *stats)
1436d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o{
1446d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	errcode_t 	retval = 0;
1456d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
1466d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	struct unix_private_data *data;
1476d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
1486d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1496d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
1506d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1516d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
1526d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	if (stats)
1536d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o		*stats = &data->io_stats;
1546d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
1556d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	return retval;
1566d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o}
1576d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
158adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
159adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions
160adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
161adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel,
162adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      struct unix_private_data *data,
16359ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos			      unsigned long long block,
164d32c915abfb224f6f6659e9cada7e9f759b7e3d2Theodore Ts'o			      int count, void *bufv)
165adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
166adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
167544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		size;
168adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
169adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
170d32c915abfb224f6f6659e9cada7e9f759b7e3d2Theodore Ts'o	unsigned char	*buf = bufv;
171adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
172adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size = (count < 0) ? -count : count * channel->block_size;
1736d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data->io_stats.bytes_read += size;
1742e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
175adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
176adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
177adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
178adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
1790a05b90330d8b505469c72143964b954776be232Theodore Ts'o	if ((channel->align == 0) ||
1800a05b90330d8b505469c72143964b954776be232Theodore Ts'o	    (IS_ALIGNED(buf, channel->align) &&
1810a05b90330d8b505469c72143964b954776be232Theodore Ts'o	     IS_ALIGNED(size, channel->align))) {
1827f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		actual = read(data->dev, buf, size);
1837f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (actual != size) {
1847f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		short_read:
1857f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			if (actual < 0)
1867f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o				actual = 0;
1877f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			retval = EXT2_ET_SHORT_READ;
1887f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			goto error_out;
1897f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		}
1907f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		return 0;
191adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
192fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
1937f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#ifdef ALIGN_DEBUG
1947f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	printf("raw_read_blk: O_DIRECT fallback: %p %lu\n", buf,
1957f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	       (unsigned long) size);
196fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
1977f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
1987f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	/*
1997f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 * The buffer or size which we're trying to read isn't aligned
2007f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 * to the O_DIRECT rules, so we need to do this the hard way...
2017f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 */
2027f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	while (size > 0) {
2037f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		actual = read(data->dev, data->bounce, channel->block_size);
2047f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (actual != channel->block_size)
205fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			goto short_read;
2067f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		actual = size;
2077f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (size > channel->block_size)
2087f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			actual = channel->block_size;
2097f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		memcpy(buf, data->bounce, actual);
2107f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		size -= actual;
2117f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		buf += actual;
212fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
213fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	return 0;
214fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
215fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'oerror_out:
2167f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	memset((char *) buf+actual, 0, size-actual);
217fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (channel->read_error)
218fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		retval = (channel->read_error)(channel, block, count, buf,
219fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o					       size, actual, retval);
220fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	return retval;
221fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o}
222adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
223adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel,
224adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       struct unix_private_data *data,
22559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos			       unsigned long long block,
226d32c915abfb224f6f6659e9cada7e9f759b7e3d2Theodore Ts'o			       int count, const void *bufv)
227adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
228544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		size;
229adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
230adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
231adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
232d32c915abfb224f6f6659e9cada7e9f759b7e3d2Theodore Ts'o	const unsigned char *buf = bufv;
233adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
234adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (count == 1)
235adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		size = channel->block_size;
236adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	else {
237adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (count < 0)
238adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = -count;
239adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
240adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = count * channel->block_size;
241adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
2426d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data->io_stats.bytes_written += size;
243adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
2442e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
245adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
246adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
247adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
248adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
249efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
2500a05b90330d8b505469c72143964b954776be232Theodore Ts'o	if ((channel->align == 0) ||
2510a05b90330d8b505469c72143964b954776be232Theodore Ts'o	    (IS_ALIGNED(buf, channel->align) &&
2520a05b90330d8b505469c72143964b954776be232Theodore Ts'o	     IS_ALIGNED(size, channel->align))) {
2537f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		actual = write(data->dev, buf, size);
2547f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (actual != size) {
2557f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		short_write:
2567f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			retval = EXT2_ET_SHORT_WRITE;
2577f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			goto error_out;
2587f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		}
2597f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		return 0;
2607f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	}
2617f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
2627f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#ifdef ALIGN_DEBUG
2637f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	printf("raw_write_blk: O_DIRECT fallback: %p %lu\n", buf,
2647f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	       (unsigned long) size);
2657f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#endif
2667f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	/*
2677f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 * The buffer or size which we're trying to write isn't aligned
2687f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 * to the O_DIRECT rules, so we need to do this the hard way...
2697f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 */
2707f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	while (size > 0) {
2717f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (size < channel->block_size) {
2727f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			actual = read(data->dev, data->bounce,
2737f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o				      channel->block_size);
2747f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			if (actual != channel->block_size) {
2757f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o				retval = EXT2_ET_SHORT_READ;
2767f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o				goto error_out;
2777f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			}
2787f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		}
2797f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		actual = size;
2807f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (size > channel->block_size)
2817f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			actual = channel->block_size;
2827f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		memcpy(data->bounce, buf, actual);
2837f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		actual = write(data->dev, data->bounce, channel->block_size);
2847f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (actual != channel->block_size)
2857f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			goto short_write;
2867f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		size -= actual;
2877f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		buf += actual;
288adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
289adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
290efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
291adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
292adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->write_error)
293adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->write_error)(channel, block, count, buf,
294adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o						size, actual, retval);
295adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
296adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
297adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
298adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
299adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
300adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions
301adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
302adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
303adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */
304adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel,
305adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			     struct unix_private_data *data)
306adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
307adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval;
308adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
309adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
310efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
311adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
312adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
313adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
314adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
315adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
316adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
317faafdb765b4ed2bb33070d998426bec0cf774344Theodore Ts'o		if (cache->buf)
318faafdb765b4ed2bb33070d998426bec0cf774344Theodore Ts'o			ext2fs_free_mem(&cache->buf);
319fd1c5a0622a9578b86f695d2f60df7d4f8b21875Theodore Ts'o		retval = io_channel_alloc_buf(channel, 0, &cache->buf);
3207f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (retval)
321adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
322adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
3230a05b90330d8b505469c72143964b954776be232Theodore Ts'o	if (channel->align) {
3247f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (data->bounce)
3257f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			ext2fs_free_mem(&data->bounce);
326fd1c5a0622a9578b86f695d2f60df7d4f8b21875Theodore Ts'o		retval = io_channel_alloc_buf(channel, 0, &data->bounce);
3277f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	}
3287f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	return retval;
329adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
330adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
331adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */
332544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic void free_cache(struct unix_private_data *data)
333adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
334adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
335adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
336efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
337adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
338adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
339adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
340adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
341adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
342adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
343adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->buf)
344c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o			ext2fs_free_mem(&cache->buf);
345adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
3467f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	if (data->bounce)
3477f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		ext2fs_free_mem(&data->bounce);
348adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
349adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
350b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
351adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
35282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Try to find a block in the cache.  If the block is not found, and
35382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * eldest is a non-zero pointer, then fill in eldest with the cache
35482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * entry to that should be reused.
355adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
356544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic struct unix_cache *find_cached_block(struct unix_private_data *data,
35759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos					    unsigned long long block,
35882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o					    struct unix_cache **eldest)
359adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
36031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	struct unix_cache	*cache, *unused_cache, *oldest_cache;
361adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
362efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
36331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	unused_cache = oldest_cache = 0;
364adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
365adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use) {
36682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			if (!unused_cache)
36782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o				unused_cache = cache;
368adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
369adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
370adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->block == block) {
371adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->access_time = ++data->access_time;
372adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return cache;
373adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
374adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!oldest_cache ||
375adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		    (cache->access_time < oldest_cache->access_time))
376adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			oldest_cache = cache;
377adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
37882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (eldest)
37982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		*eldest = (unused_cache) ? unused_cache : oldest_cache;
38082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	return 0;
38182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o}
38282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
38382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o/*
38482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Reuse a particular cache entry for another block.
38582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o */
38623b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data,
38759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos		 struct unix_cache *cache, unsigned long long block)
38882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o{
38982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (cache->dirty && cache->in_use)
39082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		raw_write_blk(channel, data, cache->block, 1, cache->buf);
39182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
392adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->in_use = 1;
3931d47dfb91ef010c506e9354dec102385d8494d8fTheodore Ts'o	cache->dirty = 0;
394adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->block = block;
395adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->access_time = ++data->access_time;
396adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
397adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
398adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
399adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache
400adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
401adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel,
402adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     struct unix_private_data *data,
403adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     int invalidate)
404adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
405adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
406adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
407adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval, retval2;
408adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
409efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
410adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval2 = 0;
411adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
412adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use)
413adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
414efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
415adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (invalidate)
416adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->in_use = 0;
417efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
418adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->dirty)
419adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
420efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
421adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data,
422adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				       cache->block, 1, cache->buf);
423adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (retval)
424adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			retval2 = retval;
425adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
426adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->dirty = 0;
427adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
428adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval2;
429adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
430b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
431adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
432d866599ab4955858b1541f0891b1b165ba66493aLukas Czerner#ifdef __linux__
433d866599ab4955858b1541f0891b1b165ba66493aLukas Czerner#ifndef BLKDISCARDZEROES
434d866599ab4955858b1541f0891b1b165ba66493aLukas Czerner#define BLKDISCARDZEROES _IO(0x12,124)
435d866599ab4955858b1541f0891b1b165ba66493aLukas Czerner#endif
436d866599ab4955858b1541f0891b1b165ba66493aLukas Czerner#endif
437d866599ab4955858b1541f0891b1b165ba66493aLukas Czerner
438182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilgerint ext2fs_open_file(const char *pathname, int flags, mode_t mode)
439182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger{
440182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger	if (mode)
441182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger#if defined(HAVE_OPEN64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
442182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger		return open64(pathname, flags, mode);
443182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger	else
444182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger		return open64(pathname, flags);
445182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger#else
446182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger		return open(pathname, flags, mode);
447182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger	else
448182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger		return open(pathname, flags);
449182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger#endif
450182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger}
451182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger
452182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilgerint ext2fs_stat(const char *path, ext2fs_struct_stat *buf)
453182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger{
454182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
455182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger	return stat64(path, buf);
456182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger#else
457182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger	return stat(path, buf);
458182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger#endif
459182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger}
460182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger
461182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilgerint ext2fs_fstat(int fd, ext2fs_struct_stat *buf)
462182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger{
463182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
464182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger	return fstat64(fd, buf);
465182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger#else
466182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger	return fstat(fd, buf);
467182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger#endif
468182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger}
469182acd17bef0cf8dcb66568448a528abb1dfcd71Andreas Dilger
4703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel)
4713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io_channel	io = NULL;
4733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data = NULL;
4743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
4751d6fd6d0c3766a8165e69284c75812574a29c804Andreas Dilger	int		open_flags;
476d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o	int		f_nocache = 0;
477c859cb1de0d624caa0779fb17d1a53766143136eLukas Czerner	ext2fs_struct_stat st;
478f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__
479f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	struct 		utsname ut;
480f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif
4813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
48250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (name == 0)
48350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return EXT2_ET_BAD_DEVICE_NAME;
484c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
4857b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
486624e8ebe3058bad9af6e719b7f9e7afab7d3fe30Eric Sandeen		goto cleanup;
487f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	memset(io, 0, sizeof(struct struct_io_channel));
488f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
489c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
4907b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
4913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
4927b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
4933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->manager = unix_io_manager;
494c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(strlen(name)+1, &io->name);
4957b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
4963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
4977b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
4983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	strcpy(io->name, name);
4993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->private_data = data;
500f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->block_size = 1024;
501f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->read_error = 0;
502f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->write_error = 0;
503a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	io->refcount = 1;
5043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(data, 0, sizeof(struct unix_private_data));
506f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
5076d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data->io_stats.num_fields = 2;
5084e0bb5eb745009decac4c5836671ff4bef21ce2aTheodore Ts'o	data->dev = -1;
5097b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
510dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
511fa6c653ec3117dd689c8adb4ea2ebfc10f8cdd4aTheodore Ts'o	if (flags & IO_FLAG_EXCLUSIVE)
512fa6c653ec3117dd689c8adb4ea2ebfc10f8cdd4aTheodore Ts'o		open_flags |= O_EXCL;
513d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o#if defined(O_DIRECT)
514dd0a2679ddd0a9bf53e32efc0f67a7e7a5ea5f00Theodore Ts'o	if (flags & IO_FLAG_DIRECT_IO) {
5157f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		open_flags |= O_DIRECT;
516dd0a2679ddd0a9bf53e32efc0f67a7e7a5ea5f00Theodore Ts'o		io->align = ext2fs_get_dio_alignment(data->dev);
517dd0a2679ddd0a9bf53e32efc0f67a7e7a5ea5f00Theodore Ts'o	}
518d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o#elif defined(F_NOCACHE)
519dd0a2679ddd0a9bf53e32efc0f67a7e7a5ea5f00Theodore Ts'o	if (flags & IO_FLAG_DIRECT_IO) {
520d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o		f_nocache = F_NOCACHE;
521dd0a2679ddd0a9bf53e32efc0f67a7e7a5ea5f00Theodore Ts'o		io->align = 4096;
522dd0a2679ddd0a9bf53e32efc0f67a7e7a5ea5f00Theodore Ts'o	}
523534a4c3db58064caee4fc3e9e294251240d9d28aAndreas Dilger#endif
5247f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	data->flags = flags;
5257f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
526c4012e5a7ace2e1f382c4d46f56e5749758c9a1aTheodore Ts'o	data->dev = ext2fs_open_file(io->name, open_flags, 0);
5273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data->dev < 0) {
5283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
5293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
5303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
531d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o	if (f_nocache) {
532d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o		if (fcntl(data->dev, f_nocache, 1) < 0) {
533d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o			retval = errno;
534d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o			goto cleanup;
535d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o		}
536d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o	}
53764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o
538d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner	/*
539d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner	 * If the device is really a block device, then set the
540d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner	 * appropriate flag, otherwise we can set DISCARD_ZEROES flag
541d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner	 * because we are going to use punch hole instead of discard
542d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner	 * and if it succeed, subsequent read from sparse area returns
543d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner	 * zero.
544d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner	 */
545d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner	if (ext2fs_stat(io->name, &st) == 0) {
546d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner		if (S_ISBLK(st.st_mode))
547d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner			io->flags |= CHANNEL_FLAGS_BLOCK_DEVICE;
548d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner		else
549d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner			io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES;
550d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner	}
551d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner
552d866599ab4955858b1541f0891b1b165ba66493aLukas Czerner#ifdef BLKDISCARDZEROES
5531d6fd6d0c3766a8165e69284c75812574a29c804Andreas Dilger	{
5541d6fd6d0c3766a8165e69284c75812574a29c804Andreas Dilger		int zeroes = 0;
5551d6fd6d0c3766a8165e69284c75812574a29c804Andreas Dilger		if (ioctl(data->dev, BLKDISCARDZEROES, &zeroes) == 0 &&
5561d6fd6d0c3766a8165e69284c75812574a29c804Andreas Dilger		    zeroes)
5571d6fd6d0c3766a8165e69284c75812574a29c804Andreas Dilger			io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES;
5581d6fd6d0c3766a8165e69284c75812574a29c804Andreas Dilger	}
559d866599ab4955858b1541f0891b1b165ba66493aLukas Czerner#endif
560d866599ab4955858b1541f0891b1b165ba66493aLukas Czerner
5617f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
5627f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	/*
5637f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 * Some operating systems require that the buffers be aligned,
5647f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 * regardless of O_DIRECT
5657f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 */
566dd0a2679ddd0a9bf53e32efc0f67a7e7a5ea5f00Theodore Ts'o	if (!io->align)
567dd0a2679ddd0a9bf53e32efc0f67a7e7a5ea5f00Theodore Ts'o		io->align = 512;
5687f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#endif
5697f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
5707f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
5717f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	if ((retval = alloc_cache(io, data)))
5727f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		goto cleanup;
5737f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
5747ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#ifdef BLKROGET
5757ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen	if (flags & IO_FLAG_RW) {
5767ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		int error;
5777ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		int readonly = 0;
5787ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen
5797ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		/* Is the block device actually writable? */
5807ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		error = ioctl(data->dev, BLKROGET, &readonly);
5817ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		if (!error && readonly) {
5827ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen			retval = EPERM;
5837ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen			goto cleanup;
5847ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		}
5857ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen	}
5867ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#endif
5877ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen
58864e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#ifdef __linux__
58964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#undef RLIM_INFINITY
59064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
59164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY	((unsigned long)(~0UL>>1))
59264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#else
59364e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY  (~0UL)
59464e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
5958880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	/*
596f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * Work around a bug in 2.4.10-2.4.18 kernels where writes to
597f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * block devices are wrongly getting hit by the filesize
598f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * limit.  This workaround isn't perfect, since it won't work
599f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * if glibc wasn't built against 2.2 header files.  (Sigh.)
600efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	 *
6018880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	 */
602f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	if ((flags & IO_FLAG_RW) &&
603f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    (uname(&ut) == 0) &&
604f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    ((ut.release[0] == '2') && (ut.release[1] == '.') &&
605f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[2] == '4') && (ut.release[3] == '.') &&
606f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[4] == '1') && (ut.release[5] >= '0') &&
607f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[5] < '8')) &&
608c859cb1de0d624caa0779fb17d1a53766143136eLukas Czerner	    (ext2fs_stat(io->name, &st) == 0) &&
6098880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (S_ISBLK(st.st_mode))) {
6108880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		struct rlimit	rlim;
611efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
61264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o		rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
6138880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		setrlimit(RLIMIT_FSIZE, &rlim);
6148880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		getrlimit(RLIMIT_FSIZE, &rlim);
615bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		if (((unsigned long) rlim.rlim_cur) <
616bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		    ((unsigned long) rlim.rlim_max)) {
6178880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			rlim.rlim_cur = rlim.rlim_max;
6188880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			setrlimit(RLIMIT_FSIZE, &rlim);
6198880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		}
6208880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	}
62164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
6223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*channel = io;
6233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
6243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup:
6263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data) {
6274e0bb5eb745009decac4c5836671ff4bef21ce2aTheodore Ts'o		if (data->dev >= 0)
6284e0bb5eb745009decac4c5836671ff4bef21ce2aTheodore Ts'o			close(data->dev);
629544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		free_cache(data);
630c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&data);
6313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6324e0bb5eb745009decac4c5836671ff4bef21ce2aTheodore Ts'o	if (io) {
6334e0bb5eb745009decac4c5836671ff4bef21ce2aTheodore Ts'o		if (io->name) {
6344e0bb5eb745009decac4c5836671ff4bef21ce2aTheodore Ts'o			ext2fs_free_mem(&io->name);
6354e0bb5eb745009decac4c5836671ff4bef21ce2aTheodore Ts'o		}
636c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&io);
6374e0bb5eb745009decac4c5836671ff4bef21ce2aTheodore Ts'o	}
6383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
6393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel)
6423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
6433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
6443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval = 0;
6453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
646f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
6473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
648f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
649a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
650a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	if (--channel->refcount > 0)
651a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o		return 0;
652adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
653b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
654adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
655b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
656adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
6573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (close(data->dev) < 0)
6583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
659544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	free_cache(data);
660f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o
661c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&channel->private_data);
6623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->name)
663c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&channel->name);
664c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&channel);
6653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
6663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize)
6693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
6703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
6717b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	errcode_t		retval;
6723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
673f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
6743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
675f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
676f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
6773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->block_size != blksize) {
678b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
679adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
680adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
681b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
682efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
6833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		channel->block_size = blksize;
684544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		free_cache(data);
685adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = alloc_cache(channel, data)))
6867b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			return retval;
6873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
6893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
69259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
6933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *buf)
6943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
6953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
69682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
6973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
69831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	char		*cp;
699adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		i, j;
7003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
701f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
7023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
703f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
7043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
705b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE
706b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o	return raw_read_blk(channel, data, block, count, buf);
707b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#else
7083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
70982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * If we're doing an odd-sized read or a very large read,
71082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * flush out the cache and then do a direct read.
7113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
71282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
713adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
714adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
715adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_read_blk(channel, data, block, count, buf);
7163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
717adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
71831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
719adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
720adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* If it's in the cache, use it! */
721544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		if ((cache = find_cached_block(data, block, &reuse[0]))) {
722adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
723d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen			printf("Using cached block %lu\n", block);
724f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif
72531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			memcpy(cp, cache->buf, channel->block_size);
726adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
727adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			block++;
72831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
729adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
730adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
7317f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (count == 1) {
7327f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			/*
7337f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			 * Special case where we read directly into the
7347f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			 * cache buffer; important in the O_DIRECT case
7357f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			 */
7367f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			cache = reuse[0];
7377f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			reuse_cache(channel, data, cache, block);
7387f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			if ((retval = raw_read_blk(channel, data, block, 1,
7397f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o						   cache->buf))) {
7407f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o				cache->in_use = 0;
7417f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o				return retval;
7427f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			}
7437f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			memcpy(cp, cache->buf, channel->block_size);
7447f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			return 0;
7457f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		}
7467f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
747adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/*
748adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * Find the number of uncached blocks so we can do a
749adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * single read request
750adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 */
751adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (i=1; i < count; i++)
752544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			if (find_cached_block(data, block+i, &reuse[i]))
753adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				break;
754adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
755d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen		printf("Reading %d blocks starting at %lu\n", i, block);
756adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif
75731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		if ((retval = raw_read_blk(channel, data, block, i, cp)))
758adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
759efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
760adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* Save the results in the cache */
761adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (j=0; j < i; j++) {
762adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
76382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse[j];
76482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block++);
76582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			memcpy(cache->buf, cp, channel->block_size);
76631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
767adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
7683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
7693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
770b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
7713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
7723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
77359ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
77459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos			       int count, void *buf)
77559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos{
77659ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos	return unix_read_blk64(channel, block, count, buf);
77759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos}
77859ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos
77959ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk64(io_channel channel, unsigned long long block,
7803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *buf)
7813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
7823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
78382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse;
78423b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o	errcode_t	retval = 0;
78531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	const char	*cp;
78631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	int		writethrough;
7873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
788f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
7893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
790f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
7913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
792b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE
793b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o	return raw_write_blk(channel, data, block, count, buf);
794efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o#else
795adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
796adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * If we're doing an odd-sized write or a very large write,
797adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * flush out the cache completely and then do a direct write.
798adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
79982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
800adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 1)))
801adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
802adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_write_blk(channel, data, block, count, buf);
8033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
8043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
805adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
806adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * For a moderate-sized multi-block write, first force a write
807adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * if we're in write-through cache mode, and then fill the
808adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * cache with the blocks.
809adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
810adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
811adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (writethrough)
812adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data, block, count, buf);
813efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
81431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
815adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
816544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		cache = find_cached_block(data, block, &reuse);
817adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache) {
81882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse;
81982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block);
820adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
82182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		memcpy(cache->buf, cp, channel->block_size);
82282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		cache->dirty = !writethrough;
823adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		count--;
824adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		block++;
82531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		cp += channel->block_size;
826adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
8273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
828b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
8293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
8303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
83159ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
83259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos				int count, const void *buf)
83359ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos{
83459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos	return unix_write_blk64(channel, block, count, buf);
83559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos}
83659ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos
837c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
838c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				 int size, const void *buf)
839c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{
840c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	struct unix_private_data *data;
84131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	errcode_t	retval = 0;
842544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		actual;
843c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
844c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
845c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
846c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
847c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
8480a05b90330d8b505469c72143964b954776be232Theodore Ts'o	if (channel->align != 0) {
8497f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#ifdef ALIGN_DEBUG
8507f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		printf("unix_write_byte: O_DIRECT fallback\n");
8517f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#endif
8527f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		return EXT2_ET_UNIMPLEMENTED;
8537f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	}
8547f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
855b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
856c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	/*
857c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 * Flush out the cache completely
858c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 */
859c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if ((retval = flush_cached_blocks(channel, data, 1)))
860c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return retval;
861b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
862c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
8632e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0)
864c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return errno;
865efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
866c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	actual = write(data->dev, buf, size);
867c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (actual != size)
868c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return EXT2_ET_SHORT_WRITE;
869c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
870c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	return 0;
871c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o}
872c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
8733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
874efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * Flush data buffers to disk.
8753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
8763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel)
8773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
878f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	struct unix_private_data *data;
879adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t retval = 0;
880efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
881f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
882f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
883f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
884adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
885b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
886adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
887b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
88836f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o	fsync(data->dev);
889adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
8903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
8913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
892efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'ostatic errcode_t unix_set_option(io_channel channel, const char *option,
8932e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o				 const char *arg)
8942e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o{
8952e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	struct unix_private_data *data;
8962aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o	unsigned long long tmp;
8972e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	char *end;
8982e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
8992e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
9002e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
9012e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
9022e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
9032e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	if (!strcmp(option, "offset")) {
9042e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		if (!arg)
9052e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o			return EXT2_ET_INVALID_ARGUMENT;
9062e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
9072aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o		tmp = strtoull(arg, &end, 0);
9082e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		if (*end)
9092e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o			return EXT2_ET_INVALID_ARGUMENT;
9102e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		data->offset = tmp;
9112aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o		if (data->offset < 0)
9122aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o			return EXT2_ET_INVALID_ARGUMENT;
9132e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		return 0;
9142e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	}
9152e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	return EXT2_ET_INVALID_ARGUMENT;
9162e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o}
917e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner
918e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner#if defined(__linux__) && !defined(BLKDISCARD)
919d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner#define BLKDISCARD		_IO(0x12,119)
920e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner#endif
921e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner
922e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czernerstatic errcode_t unix_discard(io_channel channel, unsigned long long block,
923e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner			      unsigned long long count)
924e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner{
925e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner	struct unix_private_data *data;
926e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner	int		ret;
927e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner
928e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
929e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner	data = (struct unix_private_data *) channel->private_data;
930e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
931e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner
932d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner	if (channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE) {
933d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner#ifdef BLKDISCARD
9341d6fd6d0c3766a8165e69284c75812574a29c804Andreas Dilger		__uint64_t range[2];
9351d6fd6d0c3766a8165e69284c75812574a29c804Andreas Dilger
936d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner		range[0] = (__uint64_t)(block) * channel->block_size;
937d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner		range[1] = (__uint64_t)(count) * channel->block_size;
938e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner
939d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner		ret = ioctl(data->dev, BLKDISCARD, &range);
940d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner#else
941d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner		goto unimplemented;
942d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner#endif
943d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner	} else {
944800766ee4a2bcdc0a32442d093d20da6ea3815abMike Frysinger#if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE)
945d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner		/*
946d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner		 * If we are not on block device, try to use punch hole
947d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner		 * to reclaim free space.
948d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner		 */
949d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner		ret = fallocate(data->dev,
950d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner				FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
951d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner				(off_t)(block) * channel->block_size,
952d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner				(off_t)(count) * channel->block_size);
953d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner#else
954d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner		goto unimplemented;
955d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner#endif
956d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner	}
957d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner	if (ret < 0) {
958d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner		if (errno == EOPNOTSUPP)
959d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner			goto unimplemented;
960e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner		return errno;
961d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czerner	}
962e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner	return 0;
963d2bfdc7ff15ce7b6b40c087021528ce190ef43c3Lukas Czernerunimplemented:
964e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner	return EXT2_ET_UNIMPLEMENTED;
965e90a59ed434d6c5e38dd148aa4ba5b22b8f7eb24Lukas Czerner}
966