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