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