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
20e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#ifndef _GNU_SOURCE
217f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#define _GNU_SOURCE
22e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
23dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o
243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
264cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H
273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
284cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif
29c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#if HAVE_ERRNO_H
30c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#include <errno.h>
31c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#endif
323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h>
333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <time.h>
34f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__
35f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#include <sys/utsname.h>
36f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif
377ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#ifdef HAVE_SYS_IOCTL_H
387ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#include <sys/ioctl.h>
397ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#endif
407ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#ifdef HAVE_SYS_MOUNT_H
417ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#include <sys/mount.h>
427ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#endif
431d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_STAT_H
443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/stat.h>
451d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
461d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_TYPES_H
473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/types.h>
481d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
49fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#if HAVE_SYS_RESOURCE_H
508880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o#include <sys/resource.h>
51fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
52e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#if HAVE_LINUX_FALLOC_H
53e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <linux/falloc.h>
54e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
567f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#if defined(__linux__) && defined(_IO) && !defined(BLKROGET)
577ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#define BLKROGET   _IO(0x12, 94) /* Get read-only status (0 = read_write).  */
587ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#endif
597ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen
607f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#undef ALIGN_DEBUG
617f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
62b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
637b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o#include "ext2fs.h"
643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
65f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o/*
66f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o * For checking structure magic numbers...
67f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o */
68f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
69f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#define EXT2_CHECK_MAGIC(struct, code) \
70f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	  if ((struct)->magic != (code)) return (code)
71adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
72adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostruct unix_cache {
73e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	char			*buf;
74e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	unsigned long long	block;
75e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int			access_time;
76e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	unsigned		dirty:1;
77e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	unsigned		in_use:1;
78adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o};
79adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
80adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#define CACHE_SIZE 8
8182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define WRITE_DIRECT_SIZE 4	/* Must be smaller than CACHE_SIZE */
8282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define READ_DIRECT_SIZE 4	/* Should be smaller than CACHE_SIZE */
83adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct unix_private_data {
85f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	int	magic;
863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	dev;
873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	flags;
887f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	int	align;
89adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int	access_time;
902e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	ext2_loff_t offset;
91adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache cache[CACHE_SIZE];
927f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	void	*bounce;
936d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	struct struct_io_stats io_stats;
943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
967f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#define IS_ALIGNED(n, align) ((((unsigned long) n) & \
977f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			       ((unsigned long) ((align)-1))) == 0)
987f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel);
1003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel);
1013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize);
1023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
1033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *data);
1043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
1053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *data);
1063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel);
107c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
108c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				int size, const void *data);
109efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'ostatic errcode_t unix_set_option(io_channel channel, const char *option,
1102e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o				 const char *arg);
1116d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'ostatic errcode_t unix_get_stats(io_channel channel, io_stats *stats)
1126d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o;
11323b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data,
11459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos		 struct unix_cache *cache, unsigned long long block);
11559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
11659ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos			       int count, void *data);
11759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk64(io_channel channel, unsigned long long block,
11859ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos				int count, const void *data);
119e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic errcode_t unix_discard(io_channel channel, unsigned long long block,
120e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			      unsigned long long count);
12123b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o
122f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = {
123f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_ET_MAGIC_IO_MANAGER,
1243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	"Unix I/O Manager",
1253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_open,
1263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_close,
1273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_set_blksize,
1283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_read_blk,
1293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_write_blk,
130c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	unix_flush,
1312e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	unix_write_byte,
1326d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	unix_set_option,
1336d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	unix_get_stats,
13459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos	unix_read_blk64,
13559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos	unix_write_blk64,
136e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	unix_discard,
1373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
1383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager;
1403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1416d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'ostatic errcode_t unix_get_stats(io_channel channel, io_stats *stats)
1426d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o{
1436d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	errcode_t 	retval = 0;
1446d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
1456d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	struct unix_private_data *data;
1466d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
1476d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1486d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
1496d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1506d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
1516d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	if (stats)
1526d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o		*stats = &data->io_stats;
1536d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
1546d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	return retval;
1556d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o}
1566d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
157adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
158adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions
159adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
160adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel,
161adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      struct unix_private_data *data,
16259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos			      unsigned long long block,
163e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			      int count, void *bufv)
164adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
165adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
166544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		size;
167adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
168adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
169e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	unsigned char	*buf = bufv;
170adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
171adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size = (count < 0) ? -count : count * channel->block_size;
1726d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data->io_stats.bytes_read += size;
1732e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
174adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
175adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
176adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
177adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
178e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if ((channel->align == 0) ||
179e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	    (IS_ALIGNED(buf, channel->align) &&
180e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	     IS_ALIGNED(size, channel->align))) {
1817f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		actual = read(data->dev, buf, size);
1827f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (actual != size) {
1837f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		short_read:
1847f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			if (actual < 0)
1857f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o				actual = 0;
1867f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			retval = EXT2_ET_SHORT_READ;
1877f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			goto error_out;
1887f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		}
1897f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		return 0;
190adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
191fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
1927f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#ifdef ALIGN_DEBUG
1937f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	printf("raw_read_blk: O_DIRECT fallback: %p %lu\n", buf,
1947f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	       (unsigned long) size);
195fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
1967f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
1977f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	/*
1987f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 * The buffer or size which we're trying to read isn't aligned
1997f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 * to the O_DIRECT rules, so we need to do this the hard way...
2007f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 */
2017f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	while (size > 0) {
2027f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		actual = read(data->dev, data->bounce, channel->block_size);
2037f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (actual != channel->block_size)
204fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			goto short_read;
2057f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		actual = size;
2067f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (size > channel->block_size)
2077f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			actual = channel->block_size;
2087f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		memcpy(buf, data->bounce, actual);
2097f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		size -= actual;
2107f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		buf += actual;
211fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
212fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	return 0;
213fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
214fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'oerror_out:
2157f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	memset((char *) buf+actual, 0, size-actual);
216fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (channel->read_error)
217fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		retval = (channel->read_error)(channel, block, count, buf,
218fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o					       size, actual, retval);
219fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	return retval;
220fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o}
221adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
222adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel,
223adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       struct unix_private_data *data,
22459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos			       unsigned long long block,
225e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			       int count, const void *bufv)
226adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
227544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		size;
228adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
229adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
230adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
231e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	const unsigned char *buf = bufv;
232adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
233adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (count == 1)
234adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		size = channel->block_size;
235adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	else {
236adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (count < 0)
237adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = -count;
238adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
239adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = count * channel->block_size;
240adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
2416d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data->io_stats.bytes_written += size;
242adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
2432e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
244adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
245adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
246adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
247adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
248efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
249e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if ((channel->align == 0) ||
250e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	    (IS_ALIGNED(buf, channel->align) &&
251e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	     IS_ALIGNED(size, channel->align))) {
2527f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		actual = write(data->dev, buf, size);
2537f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (actual != size) {
2547f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		short_write:
2557f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			retval = EXT2_ET_SHORT_WRITE;
2567f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			goto error_out;
2577f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		}
2587f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		return 0;
2597f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	}
2607f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
2617f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#ifdef ALIGN_DEBUG
2627f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	printf("raw_write_blk: O_DIRECT fallback: %p %lu\n", buf,
2637f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	       (unsigned long) size);
2647f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#endif
2657f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	/*
2667f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 * The buffer or size which we're trying to write isn't aligned
2677f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 * to the O_DIRECT rules, so we need to do this the hard way...
2687f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 */
2697f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	while (size > 0) {
2707f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (size < channel->block_size) {
2717f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			actual = read(data->dev, data->bounce,
2727f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o				      channel->block_size);
2737f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			if (actual != channel->block_size) {
2747f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o				retval = EXT2_ET_SHORT_READ;
2757f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o				goto error_out;
2767f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			}
2777f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		}
2787f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		actual = size;
2797f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (size > channel->block_size)
2807f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			actual = channel->block_size;
2817f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		memcpy(data->bounce, buf, actual);
2827f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		actual = write(data->dev, data->bounce, channel->block_size);
2837f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (actual != channel->block_size)
2847f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			goto short_write;
2857f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		size -= actual;
2867f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		buf += actual;
287adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
288adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
289efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
290adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
291adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->write_error)
292adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->write_error)(channel, block, count, buf,
293adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o						size, actual, retval);
294adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
295adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
296adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
297adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
298adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
299adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions
300adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
301adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
302adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */
303adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel,
304adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			     struct unix_private_data *data)
305adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
306adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval;
307adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
308adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
309efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
310adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
311adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
312adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
313adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
314adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
315adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
316faafdb765b4ed2bb33070d998426bec0cf774344Theodore Ts'o		if (cache->buf)
317faafdb765b4ed2bb33070d998426bec0cf774344Theodore Ts'o			ext2fs_free_mem(&cache->buf);
318e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = io_channel_alloc_buf(channel, 0, &cache->buf);
3197f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (retval)
320adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
321adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
322e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (channel->align) {
3237f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (data->bounce)
3247f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			ext2fs_free_mem(&data->bounce);
325e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = io_channel_alloc_buf(channel, 0, &data->bounce);
3267f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	}
3277f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	return retval;
328adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
329adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
330adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */
331544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic void free_cache(struct unix_private_data *data)
332adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
333adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
334adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
335efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
336adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
337adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
338adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
339adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
340adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
341adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
342adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->buf)
343c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o			ext2fs_free_mem(&cache->buf);
344adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
3457f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	if (data->bounce)
3467f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		ext2fs_free_mem(&data->bounce);
347adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
348adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
349b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
350adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
35182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Try to find a block in the cache.  If the block is not found, and
35282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * eldest is a non-zero pointer, then fill in eldest with the cache
35382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * entry to that should be reused.
354adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
355544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic struct unix_cache *find_cached_block(struct unix_private_data *data,
35659ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos					    unsigned long long block,
35782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o					    struct unix_cache **eldest)
358adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
35931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	struct unix_cache	*cache, *unused_cache, *oldest_cache;
360adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
361efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
36231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	unused_cache = oldest_cache = 0;
363adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
364adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use) {
36582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			if (!unused_cache)
36682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o				unused_cache = cache;
367adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
368adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
369adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->block == block) {
370adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->access_time = ++data->access_time;
371adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return cache;
372adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
373adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!oldest_cache ||
374adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		    (cache->access_time < oldest_cache->access_time))
375adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			oldest_cache = cache;
376adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
37782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (eldest)
37882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		*eldest = (unused_cache) ? unused_cache : oldest_cache;
37982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	return 0;
38082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o}
38182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
38282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o/*
38382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Reuse a particular cache entry for another block.
38482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o */
38523b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data,
38659ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos		 struct unix_cache *cache, unsigned long long block)
38782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o{
38882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (cache->dirty && cache->in_use)
38982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		raw_write_blk(channel, data, cache->block, 1, cache->buf);
39082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
391adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->in_use = 1;
3921d47dfb91ef010c506e9354dec102385d8494d8fTheodore Ts'o	cache->dirty = 0;
393adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->block = block;
394adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->access_time = ++data->access_time;
395adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
396adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
397adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
398adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache
399adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
400adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel,
401adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     struct unix_private_data *data,
402adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     int invalidate)
403adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
404adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
405adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
406adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval, retval2;
407adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
408efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
409adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval2 = 0;
410adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
411adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use)
412adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
413efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
414adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (invalidate)
415adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->in_use = 0;
416efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
417adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->dirty)
418adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
419efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
420adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data,
421adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				       cache->block, 1, cache->buf);
422adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (retval)
423adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			retval2 = retval;
424adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
425adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->dirty = 0;
426adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
427adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval2;
428adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
429b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
430adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
431e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#ifdef __linux__
432e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#ifndef BLKDISCARDZEROES
433e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#define BLKDISCARDZEROES _IO(0x12,124)
434e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
435e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
436e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
437e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallint ext2fs_open_file(const char *pathname, int flags, mode_t mode)
438e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
439e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (mode)
440e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#if defined(HAVE_OPEN64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
441e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return open64(pathname, flags, mode);
442e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	else
443e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return open64(pathname, flags);
444e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#else
445e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return open(pathname, flags, mode);
446e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	else
447e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return open(pathname, flags);
448e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
449e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
450e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
451e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallint ext2fs_stat(const char *path, ext2fs_struct_stat *buf)
452e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
453e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
454e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return stat64(path, buf);
455e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#else
456e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return stat(path, buf);
457e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
458e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
459e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
460e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallint ext2fs_fstat(int fd, ext2fs_struct_stat *buf)
461e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
462e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
463e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return fstat64(fd, buf);
464e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#else
465e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return fstat(fd, buf);
466e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
467e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
468e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
4693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel)
4703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io_channel	io = NULL;
4723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data = NULL;
4733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
4741d6fd6d0c3766a8165e69284c75812574a29c804Andreas Dilger	int		open_flags;
475d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o	int		f_nocache = 0;
476e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_struct_stat st;
477f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__
478f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	struct 		utsname ut;
479f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif
4803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
48150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (name == 0)
48250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return EXT2_ET_BAD_DEVICE_NAME;
483c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
4847b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
485e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		goto cleanup;
486f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	memset(io, 0, sizeof(struct struct_io_channel));
487f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
488c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
4897b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
4903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
4917b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
4923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->manager = unix_io_manager;
493c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(strlen(name)+1, &io->name);
4947b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
4953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
4967b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
4973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	strcpy(io->name, name);
4983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->private_data = data;
499f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->block_size = 1024;
500f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->read_error = 0;
501f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->write_error = 0;
502a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	io->refcount = 1;
5033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(data, 0, sizeof(struct unix_private_data));
505f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
5066d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data->io_stats.num_fields = 2;
507e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	data->dev = -1;
5087b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
509dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
510fa6c653ec3117dd689c8adb4ea2ebfc10f8cdd4aTheodore Ts'o	if (flags & IO_FLAG_EXCLUSIVE)
511fa6c653ec3117dd689c8adb4ea2ebfc10f8cdd4aTheodore Ts'o		open_flags |= O_EXCL;
512e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#if defined(O_DIRECT)
513e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (flags & IO_FLAG_DIRECT_IO) {
51465f0aab98b20b5994a726ab90d355248bcddfffdJP Abgrall		open_flags |= O_DIRECT;
515e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		io->align = ext2fs_get_dio_alignment(data->dev);
516e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
517e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#elif defined(F_NOCACHE)
518e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (flags & IO_FLAG_DIRECT_IO) {
519e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		f_nocache = F_NOCACHE;
520e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		io->align = 4096;
521e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
522534a4c3db58064caee4fc3e9e294251240d9d28aAndreas Dilger#endif
5237f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	data->flags = flags;
5247f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
525e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	data->dev = ext2fs_open_file(io->name, open_flags, 0);
5263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data->dev < 0) {
5273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
5283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
5293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
530d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o	if (f_nocache) {
531d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o		if (fcntl(data->dev, f_nocache, 1) < 0) {
532d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o			retval = errno;
533d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o			goto cleanup;
534d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o		}
535d9a5d37535794842358e1cfe4faa4a89804ed209Theodore Ts'o	}
53664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o
537e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	/*
538e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * If the device is really a block device, then set the
539e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * appropriate flag, otherwise we can set DISCARD_ZEROES flag
540e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * because we are going to use punch hole instead of discard
541e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * and if it succeed, subsequent read from sparse area returns
542e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * zero.
543e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 */
544e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ext2fs_stat(io->name, &st) == 0) {
545e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (S_ISBLK(st.st_mode))
546e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			io->flags |= CHANNEL_FLAGS_BLOCK_DEVICE;
547e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		else
548e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES;
549e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
550e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
551e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#ifdef BLKDISCARDZEROES
552e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	{
553e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		int zeroes = 0;
554e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (ioctl(data->dev, BLKDISCARDZEROES, &zeroes) == 0 &&
555e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		    zeroes)
556e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES;
5571d6fd6d0c3766a8165e69284c75812574a29c804Andreas Dilger	}
558d866599ab4955858b1541f0891b1b165ba66493aLukas Czerner#endif
559d866599ab4955858b1541f0891b1b165ba66493aLukas Czerner
5607f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
5617f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	/*
5627f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 * Some operating systems require that the buffers be aligned,
5637f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 * regardless of O_DIRECT
5647f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	 */
565e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (!io->align)
566e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		io->align = 512;
5677f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#endif
5687f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
5697f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
5707f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	if ((retval = alloc_cache(io, data)))
5717f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		goto cleanup;
5727f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
5737ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#ifdef BLKROGET
5747ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen	if (flags & IO_FLAG_RW) {
5757ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		int error;
5767ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		int readonly = 0;
5777ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen
5787ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		/* Is the block device actually writable? */
5797ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		error = ioctl(data->dev, BLKROGET, &readonly);
5807ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		if (!error && readonly) {
5817ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen			retval = EPERM;
5827ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen			goto cleanup;
5837ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		}
5847ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen	}
5857ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#endif
5867ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen
58764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#ifdef __linux__
58864e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#undef RLIM_INFINITY
58964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
59064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY	((unsigned long)(~0UL>>1))
59164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#else
59264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY  (~0UL)
59364e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
5948880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	/*
595f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * Work around a bug in 2.4.10-2.4.18 kernels where writes to
596f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * block devices are wrongly getting hit by the filesize
597f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * limit.  This workaround isn't perfect, since it won't work
598f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * if glibc wasn't built against 2.2 header files.  (Sigh.)
599efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	 *
6008880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	 */
601f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	if ((flags & IO_FLAG_RW) &&
602f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    (uname(&ut) == 0) &&
603f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    ((ut.release[0] == '2') && (ut.release[1] == '.') &&
604f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[2] == '4') && (ut.release[3] == '.') &&
605f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[4] == '1') && (ut.release[5] >= '0') &&
606f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[5] < '8')) &&
607e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	    (ext2fs_stat(io->name, &st) == 0) &&
6088880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (S_ISBLK(st.st_mode))) {
6098880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		struct rlimit	rlim;
610efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
61164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o		rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
6128880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		setrlimit(RLIMIT_FSIZE, &rlim);
6138880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		getrlimit(RLIMIT_FSIZE, &rlim);
614bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		if (((unsigned long) rlim.rlim_cur) <
615bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		    ((unsigned long) rlim.rlim_max)) {
6168880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			rlim.rlim_cur = rlim.rlim_max;
6178880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			setrlimit(RLIMIT_FSIZE, &rlim);
6188880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		}
6198880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	}
62064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
6213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*channel = io;
6223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
6233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup:
6253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data) {
626e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (data->dev >= 0)
627e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			close(data->dev);
628544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		free_cache(data);
629c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&data);
6303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
631e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (io) {
632e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (io->name) {
633e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			ext2fs_free_mem(&io->name);
634e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		}
635c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&io);
636e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
6373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
6383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel)
6413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
6423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
6433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval = 0;
6443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
645f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
6463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
647f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
648a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
649a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	if (--channel->refcount > 0)
650a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o		return 0;
651adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
652b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
653adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
654b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
655adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
6563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (close(data->dev) < 0)
6573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
658544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	free_cache(data);
659f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o
660c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&channel->private_data);
6613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->name)
662c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&channel->name);
663c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&channel);
6643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
6653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize)
6683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
6693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
6707b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	errcode_t		retval;
6713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
672f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
6733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
674f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
675f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
6763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->block_size != blksize) {
677b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
678adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
679adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
680b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
681efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
6823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		channel->block_size = blksize;
683544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		free_cache(data);
684adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = alloc_cache(channel, data)))
6857b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			return retval;
6863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
6883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
6903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
69159ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
6923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *buf)
6933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
6943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
69582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
6963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
69731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	char		*cp;
698adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		i, j;
6993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
700f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
7013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
702f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
7033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
704b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE
705b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o	return raw_read_blk(channel, data, block, count, buf);
706b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#else
7073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
70882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * If we're doing an odd-sized read or a very large read,
70982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * flush out the cache and then do a direct read.
7103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
71182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
712adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
713adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
714adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_read_blk(channel, data, block, count, buf);
7153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
716adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
71731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
718adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
719adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* If it's in the cache, use it! */
720544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		if ((cache = find_cached_block(data, block, &reuse[0]))) {
721adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
722d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen			printf("Using cached block %lu\n", block);
723f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif
72431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			memcpy(cp, cache->buf, channel->block_size);
725adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
726adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			block++;
72731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
728adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
729adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
7307f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		if (count == 1) {
7317f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			/*
7327f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			 * Special case where we read directly into the
7337f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			 * cache buffer; important in the O_DIRECT case
7347f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			 */
7357f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			cache = reuse[0];
7367f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			reuse_cache(channel, data, cache, block);
7377f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			if ((retval = raw_read_blk(channel, data, block, 1,
7387f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o						   cache->buf))) {
7397f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o				cache->in_use = 0;
7407f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o				return retval;
7417f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			}
7427f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			memcpy(cp, cache->buf, channel->block_size);
7437f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o			return 0;
7447f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		}
7457f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
746adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/*
747adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * Find the number of uncached blocks so we can do a
748adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * single read request
749adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 */
750adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (i=1; i < count; i++)
751544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			if (find_cached_block(data, block+i, &reuse[i]))
752adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				break;
753adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
754d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen		printf("Reading %d blocks starting at %lu\n", i, block);
755adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif
75631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		if ((retval = raw_read_blk(channel, data, block, i, cp)))
757adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
758efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
759adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* Save the results in the cache */
760adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (j=0; j < i; j++) {
761adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
76282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse[j];
76382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block++);
76482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			memcpy(cache->buf, cp, channel->block_size);
76531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
766adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
7673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
7683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
769b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
7703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
7713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
77259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
77359ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos			       int count, void *buf)
77459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos{
77559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos	return unix_read_blk64(channel, block, count, buf);
77659ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos}
77759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos
77859ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk64(io_channel channel, unsigned long long block,
7793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *buf)
7803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
7813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
78282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse;
78323b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o	errcode_t	retval = 0;
78431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	const char	*cp;
78531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	int		writethrough;
7863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
787f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
7883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
789f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
7903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
791b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE
792b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o	return raw_write_blk(channel, data, block, count, buf);
793efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o#else
794adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
795adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * If we're doing an odd-sized write or a very large write,
796adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * flush out the cache completely and then do a direct write.
797adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
79882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
799adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 1)))
800adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
801adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_write_blk(channel, data, block, count, buf);
8023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
8033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
804adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
805adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * For a moderate-sized multi-block write, first force a write
806adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * if we're in write-through cache mode, and then fill the
807adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * cache with the blocks.
808adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
809adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
810adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (writethrough)
811adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data, block, count, buf);
812efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
81331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
814adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
815544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		cache = find_cached_block(data, block, &reuse);
816adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache) {
81782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse;
81882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block);
819adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
82082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		memcpy(cache->buf, cp, channel->block_size);
82182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		cache->dirty = !writethrough;
822adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		count--;
823adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		block++;
82431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		cp += channel->block_size;
825adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
8263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
827b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
8283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
8293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
83059ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
83159ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos				int count, const void *buf)
83259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos{
83359ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos	return unix_write_blk64(channel, block, count, buf);
83459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos}
83559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos
836c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
837c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				 int size, const void *buf)
838c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{
839c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	struct unix_private_data *data;
84031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	errcode_t	retval = 0;
841544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		actual;
842c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
843c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
844c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
845c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
846c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
847e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (channel->align != 0) {
8487f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#ifdef ALIGN_DEBUG
8497f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		printf("unix_write_byte: O_DIRECT fallback\n");
8507f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o#endif
8517f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o		return EXT2_ET_UNIMPLEMENTED;
8527f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o	}
8537f1a1fbf850f6b73b5c9c82365f01029fb250a1cTheodore Ts'o
854b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
855c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	/*
856c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 * Flush out the cache completely
857c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 */
858c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if ((retval = flush_cached_blocks(channel, data, 1)))
859c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return retval;
860b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
861c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
8622e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0)
863c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return errno;
864efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
865c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	actual = write(data->dev, buf, size);
866c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (actual != size)
867c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return EXT2_ET_SHORT_WRITE;
868c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
869c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	return 0;
870c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o}
871c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
8723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
873efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * Flush data buffers to disk.
8743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
8753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel)
8763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
877f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	struct unix_private_data *data;
878adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t retval = 0;
879efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
880f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
881f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
882f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
883adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
884b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
885adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
886b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
88736f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o	fsync(data->dev);
888adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
8893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
8903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
891efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'ostatic errcode_t unix_set_option(io_channel channel, const char *option,
8922e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o				 const char *arg)
8932e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o{
8942e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	struct unix_private_data *data;
8952aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o	unsigned long long tmp;
8962e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	char *end;
8972e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
8982e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
8992e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
9002e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
9012e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
9022e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	if (!strcmp(option, "offset")) {
9032e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		if (!arg)
9042e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o			return EXT2_ET_INVALID_ARGUMENT;
9052e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
9062aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o		tmp = strtoull(arg, &end, 0);
9072e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		if (*end)
9082e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o			return EXT2_ET_INVALID_ARGUMENT;
9092e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		data->offset = tmp;
9102aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o		if (data->offset < 0)
9112aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o			return EXT2_ET_INVALID_ARGUMENT;
9122e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		return 0;
9132e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	}
9142e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	return EXT2_ET_INVALID_ARGUMENT;
9152e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o}
916e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
917e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#if defined(__linux__) && !defined(BLKDISCARD)
918e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#define BLKDISCARD		_IO(0x12,119)
919e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
920e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
921e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic errcode_t unix_discard(io_channel channel, unsigned long long block,
922e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			      unsigned long long count)
923e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
924e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	struct unix_private_data *data;
925e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int		ret;
926e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
927e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
928e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	data = (struct unix_private_data *) channel->private_data;
929e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
930e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
931e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE) {
932e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#ifdef BLKDISCARD
933e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		__uint64_t range[2];
934e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
935e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		range[0] = (__uint64_t)(block) * channel->block_size;
936e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		range[1] = (__uint64_t)(count) * channel->block_size;
937e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
938e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ret = ioctl(data->dev, BLKDISCARD, &range);
939e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#else
940e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		goto unimplemented;
941e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
942e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	} else {
943e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE)
944e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		/*
945e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		 * If we are not on block device, try to use punch hole
946e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		 * to reclaim free space.
947e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		 */
948e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ret = fallocate(data->dev,
949e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
950e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				(off_t)(block) * channel->block_size,
951e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				(off_t)(count) * channel->block_size);
952e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#else
953e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		goto unimplemented;
954e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
955e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
956e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (ret < 0) {
957e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (errno == EOPNOTSUPP)
958e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			goto unimplemented;
959e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return errno;
960e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
961e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return 0;
962e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallunimplemented:
963e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return EXT2_ET_UNIMPLEMENTED;
964e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
965