1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker * unix_io.c --- This is the Unix (well, really POSIX) implementation
3*6a54128fSAndroid Build Coastguard Worker * of the I/O manager.
4*6a54128fSAndroid Build Coastguard Worker *
5*6a54128fSAndroid Build Coastguard Worker * Implements a one-block write-through cache.
6*6a54128fSAndroid Build Coastguard Worker *
7*6a54128fSAndroid Build Coastguard Worker * Includes support for Windows NT support under Cygwin.
8*6a54128fSAndroid Build Coastguard Worker *
9*6a54128fSAndroid Build Coastguard Worker * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
10*6a54128fSAndroid Build Coastguard Worker * 2002 by Theodore Ts'o.
11*6a54128fSAndroid Build Coastguard Worker *
12*6a54128fSAndroid Build Coastguard Worker * %Begin-Header%
13*6a54128fSAndroid Build Coastguard Worker * This file may be redistributed under the terms of the GNU Library
14*6a54128fSAndroid Build Coastguard Worker * General Public License, version 2.
15*6a54128fSAndroid Build Coastguard Worker * %End-Header%
16*6a54128fSAndroid Build Coastguard Worker */
17*6a54128fSAndroid Build Coastguard Worker
18*6a54128fSAndroid Build Coastguard Worker #if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
19*6a54128fSAndroid Build Coastguard Worker #define _XOPEN_SOURCE 600
20*6a54128fSAndroid Build Coastguard Worker #define _DARWIN_C_SOURCE
21*6a54128fSAndroid Build Coastguard Worker #define _FILE_OFFSET_BITS 64
22*6a54128fSAndroid Build Coastguard Worker #ifndef _LARGEFILE_SOURCE
23*6a54128fSAndroid Build Coastguard Worker #define _LARGEFILE_SOURCE
24*6a54128fSAndroid Build Coastguard Worker #endif
25*6a54128fSAndroid Build Coastguard Worker #ifndef _LARGEFILE64_SOURCE
26*6a54128fSAndroid Build Coastguard Worker #define _LARGEFILE64_SOURCE
27*6a54128fSAndroid Build Coastguard Worker #endif
28*6a54128fSAndroid Build Coastguard Worker #ifndef _GNU_SOURCE
29*6a54128fSAndroid Build Coastguard Worker #define _GNU_SOURCE
30*6a54128fSAndroid Build Coastguard Worker #endif
31*6a54128fSAndroid Build Coastguard Worker #endif
32*6a54128fSAndroid Build Coastguard Worker
33*6a54128fSAndroid Build Coastguard Worker #include "config.h"
34*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
35*6a54128fSAndroid Build Coastguard Worker #include <string.h>
36*6a54128fSAndroid Build Coastguard Worker #if HAVE_UNISTD_H
37*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
38*6a54128fSAndroid Build Coastguard Worker #endif
39*6a54128fSAndroid Build Coastguard Worker #if HAVE_ERRNO_H
40*6a54128fSAndroid Build Coastguard Worker #include <errno.h>
41*6a54128fSAndroid Build Coastguard Worker #endif
42*6a54128fSAndroid Build Coastguard Worker #include <fcntl.h>
43*6a54128fSAndroid Build Coastguard Worker #include <time.h>
44*6a54128fSAndroid Build Coastguard Worker #ifdef __linux__
45*6a54128fSAndroid Build Coastguard Worker #include <sys/utsname.h>
46*6a54128fSAndroid Build Coastguard Worker #endif
47*6a54128fSAndroid Build Coastguard Worker #if HAVE_SYS_TYPES_H
48*6a54128fSAndroid Build Coastguard Worker #include <sys/types.h>
49*6a54128fSAndroid Build Coastguard Worker #endif
50*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_SYS_IOCTL_H
51*6a54128fSAndroid Build Coastguard Worker #include <sys/ioctl.h>
52*6a54128fSAndroid Build Coastguard Worker #endif
53*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_SYS_MOUNT_H
54*6a54128fSAndroid Build Coastguard Worker #include <sys/mount.h>
55*6a54128fSAndroid Build Coastguard Worker #endif
56*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_SYS_PRCTL_H
57*6a54128fSAndroid Build Coastguard Worker #include <sys/prctl.h>
58*6a54128fSAndroid Build Coastguard Worker #else
59*6a54128fSAndroid Build Coastguard Worker #define PR_GET_DUMPABLE 3
60*6a54128fSAndroid Build Coastguard Worker #endif
61*6a54128fSAndroid Build Coastguard Worker #if HAVE_SYS_STAT_H
62*6a54128fSAndroid Build Coastguard Worker #include <sys/stat.h>
63*6a54128fSAndroid Build Coastguard Worker #endif
64*6a54128fSAndroid Build Coastguard Worker #if HAVE_SYS_RESOURCE_H
65*6a54128fSAndroid Build Coastguard Worker #include <sys/resource.h>
66*6a54128fSAndroid Build Coastguard Worker #endif
67*6a54128fSAndroid Build Coastguard Worker #if HAVE_LINUX_FALLOC_H
68*6a54128fSAndroid Build Coastguard Worker #include <linux/falloc.h>
69*6a54128fSAndroid Build Coastguard Worker #endif
70*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_PTHREAD
71*6a54128fSAndroid Build Coastguard Worker #include <pthread.h>
72*6a54128fSAndroid Build Coastguard Worker #endif
73*6a54128fSAndroid Build Coastguard Worker
74*6a54128fSAndroid Build Coastguard Worker #if defined(__linux__) && defined(_IO) && !defined(BLKROGET)
75*6a54128fSAndroid Build Coastguard Worker #define BLKROGET _IO(0x12, 94) /* Get read-only status (0 = read_write). */
76*6a54128fSAndroid Build Coastguard Worker #endif
77*6a54128fSAndroid Build Coastguard Worker
78*6a54128fSAndroid Build Coastguard Worker #undef ALIGN_DEBUG
79*6a54128fSAndroid Build Coastguard Worker
80*6a54128fSAndroid Build Coastguard Worker #include "ext2_fs.h"
81*6a54128fSAndroid Build Coastguard Worker #include "ext2fs.h"
82*6a54128fSAndroid Build Coastguard Worker #include "ext2fsP.h"
83*6a54128fSAndroid Build Coastguard Worker
84*6a54128fSAndroid Build Coastguard Worker /*
85*6a54128fSAndroid Build Coastguard Worker * For checking structure magic numbers...
86*6a54128fSAndroid Build Coastguard Worker */
87*6a54128fSAndroid Build Coastguard Worker
88*6a54128fSAndroid Build Coastguard Worker #define EXT2_CHECK_MAGIC(struct, code) \
89*6a54128fSAndroid Build Coastguard Worker if ((struct)->magic != (code)) return (code)
90*6a54128fSAndroid Build Coastguard Worker
91*6a54128fSAndroid Build Coastguard Worker struct unix_cache {
92*6a54128fSAndroid Build Coastguard Worker char *buf;
93*6a54128fSAndroid Build Coastguard Worker unsigned long long block;
94*6a54128fSAndroid Build Coastguard Worker int access_time;
95*6a54128fSAndroid Build Coastguard Worker unsigned dirty:1;
96*6a54128fSAndroid Build Coastguard Worker unsigned in_use:1;
97*6a54128fSAndroid Build Coastguard Worker unsigned write_err:1;
98*6a54128fSAndroid Build Coastguard Worker };
99*6a54128fSAndroid Build Coastguard Worker
100*6a54128fSAndroid Build Coastguard Worker #define CACHE_SIZE 8
101*6a54128fSAndroid Build Coastguard Worker #define WRITE_DIRECT_SIZE 4 /* Must be smaller than CACHE_SIZE */
102*6a54128fSAndroid Build Coastguard Worker #define READ_DIRECT_SIZE 4 /* Should be smaller than CACHE_SIZE */
103*6a54128fSAndroid Build Coastguard Worker
104*6a54128fSAndroid Build Coastguard Worker struct unix_private_data {
105*6a54128fSAndroid Build Coastguard Worker int magic;
106*6a54128fSAndroid Build Coastguard Worker int dev;
107*6a54128fSAndroid Build Coastguard Worker int flags;
108*6a54128fSAndroid Build Coastguard Worker int align;
109*6a54128fSAndroid Build Coastguard Worker int access_time;
110*6a54128fSAndroid Build Coastguard Worker ext2_loff_t offset;
111*6a54128fSAndroid Build Coastguard Worker struct unix_cache cache[CACHE_SIZE];
112*6a54128fSAndroid Build Coastguard Worker void *bounce;
113*6a54128fSAndroid Build Coastguard Worker struct struct_io_stats io_stats;
114*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_PTHREAD
115*6a54128fSAndroid Build Coastguard Worker pthread_mutex_t cache_mutex;
116*6a54128fSAndroid Build Coastguard Worker pthread_mutex_t bounce_mutex;
117*6a54128fSAndroid Build Coastguard Worker pthread_mutex_t stats_mutex;
118*6a54128fSAndroid Build Coastguard Worker #endif
119*6a54128fSAndroid Build Coastguard Worker };
120*6a54128fSAndroid Build Coastguard Worker
121*6a54128fSAndroid Build Coastguard Worker #define IS_ALIGNED(n, align) ((((uintptr_t) n) & \
122*6a54128fSAndroid Build Coastguard Worker ((uintptr_t) ((align)-1))) == 0)
123*6a54128fSAndroid Build Coastguard Worker
124*6a54128fSAndroid Build Coastguard Worker typedef enum lock_kind {
125*6a54128fSAndroid Build Coastguard Worker CACHE_MTX, BOUNCE_MTX, STATS_MTX
126*6a54128fSAndroid Build Coastguard Worker } kind_t;
127*6a54128fSAndroid Build Coastguard Worker
128*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_PTHREAD
get_mutex(struct unix_private_data * data,kind_t kind)129*6a54128fSAndroid Build Coastguard Worker static inline pthread_mutex_t *get_mutex(struct unix_private_data *data,
130*6a54128fSAndroid Build Coastguard Worker kind_t kind)
131*6a54128fSAndroid Build Coastguard Worker {
132*6a54128fSAndroid Build Coastguard Worker if (data->flags & IO_FLAG_THREADS) {
133*6a54128fSAndroid Build Coastguard Worker switch (kind) {
134*6a54128fSAndroid Build Coastguard Worker case CACHE_MTX:
135*6a54128fSAndroid Build Coastguard Worker return &data->cache_mutex;
136*6a54128fSAndroid Build Coastguard Worker case BOUNCE_MTX:
137*6a54128fSAndroid Build Coastguard Worker return &data->bounce_mutex;
138*6a54128fSAndroid Build Coastguard Worker case STATS_MTX:
139*6a54128fSAndroid Build Coastguard Worker return &data->stats_mutex;
140*6a54128fSAndroid Build Coastguard Worker }
141*6a54128fSAndroid Build Coastguard Worker }
142*6a54128fSAndroid Build Coastguard Worker return NULL;
143*6a54128fSAndroid Build Coastguard Worker }
144*6a54128fSAndroid Build Coastguard Worker #endif
145*6a54128fSAndroid Build Coastguard Worker
mutex_lock(struct unix_private_data * data,kind_t kind)146*6a54128fSAndroid Build Coastguard Worker static inline void mutex_lock(struct unix_private_data *data, kind_t kind)
147*6a54128fSAndroid Build Coastguard Worker {
148*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_PTHREAD
149*6a54128fSAndroid Build Coastguard Worker pthread_mutex_t *mtx = get_mutex(data,kind);
150*6a54128fSAndroid Build Coastguard Worker
151*6a54128fSAndroid Build Coastguard Worker if (mtx)
152*6a54128fSAndroid Build Coastguard Worker pthread_mutex_lock(mtx);
153*6a54128fSAndroid Build Coastguard Worker #endif
154*6a54128fSAndroid Build Coastguard Worker }
155*6a54128fSAndroid Build Coastguard Worker
mutex_unlock(struct unix_private_data * data,kind_t kind)156*6a54128fSAndroid Build Coastguard Worker static inline void mutex_unlock(struct unix_private_data *data, kind_t kind)
157*6a54128fSAndroid Build Coastguard Worker {
158*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_PTHREAD
159*6a54128fSAndroid Build Coastguard Worker pthread_mutex_t *mtx = get_mutex(data,kind);
160*6a54128fSAndroid Build Coastguard Worker
161*6a54128fSAndroid Build Coastguard Worker if (mtx)
162*6a54128fSAndroid Build Coastguard Worker pthread_mutex_unlock(mtx);
163*6a54128fSAndroid Build Coastguard Worker #endif
164*6a54128fSAndroid Build Coastguard Worker }
165*6a54128fSAndroid Build Coastguard Worker
unix_get_stats(io_channel channel,io_stats * stats)166*6a54128fSAndroid Build Coastguard Worker static errcode_t unix_get_stats(io_channel channel, io_stats *stats)
167*6a54128fSAndroid Build Coastguard Worker {
168*6a54128fSAndroid Build Coastguard Worker errcode_t retval = 0;
169*6a54128fSAndroid Build Coastguard Worker
170*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data;
171*6a54128fSAndroid Build Coastguard Worker
172*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
173*6a54128fSAndroid Build Coastguard Worker data = (struct unix_private_data *) channel->private_data;
174*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
175*6a54128fSAndroid Build Coastguard Worker
176*6a54128fSAndroid Build Coastguard Worker if (stats) {
177*6a54128fSAndroid Build Coastguard Worker mutex_lock(data, STATS_MTX);
178*6a54128fSAndroid Build Coastguard Worker *stats = &data->io_stats;
179*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, STATS_MTX);
180*6a54128fSAndroid Build Coastguard Worker }
181*6a54128fSAndroid Build Coastguard Worker
182*6a54128fSAndroid Build Coastguard Worker return retval;
183*6a54128fSAndroid Build Coastguard Worker }
184*6a54128fSAndroid Build Coastguard Worker
safe_getenv(const char * arg)185*6a54128fSAndroid Build Coastguard Worker static char *safe_getenv(const char *arg)
186*6a54128fSAndroid Build Coastguard Worker {
187*6a54128fSAndroid Build Coastguard Worker if ((getuid() != geteuid()) || (getgid() != getegid()))
188*6a54128fSAndroid Build Coastguard Worker return NULL;
189*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_PRCTL
190*6a54128fSAndroid Build Coastguard Worker if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
191*6a54128fSAndroid Build Coastguard Worker return NULL;
192*6a54128fSAndroid Build Coastguard Worker #else
193*6a54128fSAndroid Build Coastguard Worker #if (defined(linux) && defined(SYS_prctl))
194*6a54128fSAndroid Build Coastguard Worker if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
195*6a54128fSAndroid Build Coastguard Worker return NULL;
196*6a54128fSAndroid Build Coastguard Worker #endif
197*6a54128fSAndroid Build Coastguard Worker #endif
198*6a54128fSAndroid Build Coastguard Worker
199*6a54128fSAndroid Build Coastguard Worker #if defined(HAVE_SECURE_GETENV)
200*6a54128fSAndroid Build Coastguard Worker return secure_getenv(arg);
201*6a54128fSAndroid Build Coastguard Worker #elif defined(HAVE___SECURE_GETENV)
202*6a54128fSAndroid Build Coastguard Worker return __secure_getenv(arg);
203*6a54128fSAndroid Build Coastguard Worker #else
204*6a54128fSAndroid Build Coastguard Worker return getenv(arg);
205*6a54128fSAndroid Build Coastguard Worker #endif
206*6a54128fSAndroid Build Coastguard Worker }
207*6a54128fSAndroid Build Coastguard Worker
208*6a54128fSAndroid Build Coastguard Worker /*
209*6a54128fSAndroid Build Coastguard Worker * Here are the raw I/O functions
210*6a54128fSAndroid Build Coastguard Worker */
raw_read_blk(io_channel channel,struct unix_private_data * data,unsigned long long block,int count,void * bufv)211*6a54128fSAndroid Build Coastguard Worker static errcode_t raw_read_blk(io_channel channel,
212*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data,
213*6a54128fSAndroid Build Coastguard Worker unsigned long long block,
214*6a54128fSAndroid Build Coastguard Worker int count, void *bufv)
215*6a54128fSAndroid Build Coastguard Worker {
216*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
217*6a54128fSAndroid Build Coastguard Worker ssize_t size;
218*6a54128fSAndroid Build Coastguard Worker ext2_loff_t location;
219*6a54128fSAndroid Build Coastguard Worker int actual = 0;
220*6a54128fSAndroid Build Coastguard Worker unsigned char *buf = bufv;
221*6a54128fSAndroid Build Coastguard Worker ssize_t really_read = 0;
222*6a54128fSAndroid Build Coastguard Worker unsigned long long aligned_blk;
223*6a54128fSAndroid Build Coastguard Worker int align_size, offset;
224*6a54128fSAndroid Build Coastguard Worker
225*6a54128fSAndroid Build Coastguard Worker size = (count < 0) ? -count : (ext2_loff_t) count * channel->block_size;
226*6a54128fSAndroid Build Coastguard Worker mutex_lock(data, STATS_MTX);
227*6a54128fSAndroid Build Coastguard Worker data->io_stats.bytes_read += size;
228*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, STATS_MTX);
229*6a54128fSAndroid Build Coastguard Worker location = ((ext2_loff_t) block * channel->block_size) + data->offset;
230*6a54128fSAndroid Build Coastguard Worker
231*6a54128fSAndroid Build Coastguard Worker if (data->flags & IO_FLAG_FORCE_BOUNCE)
232*6a54128fSAndroid Build Coastguard Worker goto bounce_read;
233*6a54128fSAndroid Build Coastguard Worker
234*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_PREAD64
235*6a54128fSAndroid Build Coastguard Worker /* Try an aligned pread */
236*6a54128fSAndroid Build Coastguard Worker if ((channel->align == 0) ||
237*6a54128fSAndroid Build Coastguard Worker (IS_ALIGNED(buf, channel->align) &&
238*6a54128fSAndroid Build Coastguard Worker IS_ALIGNED(location, channel->align) &&
239*6a54128fSAndroid Build Coastguard Worker IS_ALIGNED(size, channel->align))) {
240*6a54128fSAndroid Build Coastguard Worker actual = pread64(data->dev, buf, size, location);
241*6a54128fSAndroid Build Coastguard Worker if (actual == size)
242*6a54128fSAndroid Build Coastguard Worker return 0;
243*6a54128fSAndroid Build Coastguard Worker actual = 0;
244*6a54128fSAndroid Build Coastguard Worker }
245*6a54128fSAndroid Build Coastguard Worker #elif HAVE_PREAD
246*6a54128fSAndroid Build Coastguard Worker /* Try an aligned pread */
247*6a54128fSAndroid Build Coastguard Worker if ((sizeof(off_t) >= sizeof(ext2_loff_t)) &&
248*6a54128fSAndroid Build Coastguard Worker ((channel->align == 0) ||
249*6a54128fSAndroid Build Coastguard Worker (IS_ALIGNED(buf, channel->align) &&
250*6a54128fSAndroid Build Coastguard Worker IS_ALIGNED(location, channel->align) &&
251*6a54128fSAndroid Build Coastguard Worker IS_ALIGNED(size, channel->align)))) {
252*6a54128fSAndroid Build Coastguard Worker actual = pread(data->dev, buf, size, location);
253*6a54128fSAndroid Build Coastguard Worker if (actual == size)
254*6a54128fSAndroid Build Coastguard Worker return 0;
255*6a54128fSAndroid Build Coastguard Worker actual = 0;
256*6a54128fSAndroid Build Coastguard Worker }
257*6a54128fSAndroid Build Coastguard Worker #endif /* HAVE_PREAD */
258*6a54128fSAndroid Build Coastguard Worker
259*6a54128fSAndroid Build Coastguard Worker if ((channel->align == 0) ||
260*6a54128fSAndroid Build Coastguard Worker (IS_ALIGNED(buf, channel->align) &&
261*6a54128fSAndroid Build Coastguard Worker IS_ALIGNED(location, channel->align) &&
262*6a54128fSAndroid Build Coastguard Worker IS_ALIGNED(size, channel->align))) {
263*6a54128fSAndroid Build Coastguard Worker mutex_lock(data, BOUNCE_MTX);
264*6a54128fSAndroid Build Coastguard Worker if (ext2fs_llseek(data->dev, location, SEEK_SET) < 0) {
265*6a54128fSAndroid Build Coastguard Worker retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
266*6a54128fSAndroid Build Coastguard Worker goto error_unlock;
267*6a54128fSAndroid Build Coastguard Worker }
268*6a54128fSAndroid Build Coastguard Worker actual = read(data->dev, buf, size);
269*6a54128fSAndroid Build Coastguard Worker if (actual != size) {
270*6a54128fSAndroid Build Coastguard Worker short_read:
271*6a54128fSAndroid Build Coastguard Worker if (actual < 0) {
272*6a54128fSAndroid Build Coastguard Worker retval = errno;
273*6a54128fSAndroid Build Coastguard Worker actual = 0;
274*6a54128fSAndroid Build Coastguard Worker } else
275*6a54128fSAndroid Build Coastguard Worker retval = EXT2_ET_SHORT_READ;
276*6a54128fSAndroid Build Coastguard Worker goto error_unlock;
277*6a54128fSAndroid Build Coastguard Worker }
278*6a54128fSAndroid Build Coastguard Worker goto success_unlock;
279*6a54128fSAndroid Build Coastguard Worker }
280*6a54128fSAndroid Build Coastguard Worker
281*6a54128fSAndroid Build Coastguard Worker #ifdef ALIGN_DEBUG
282*6a54128fSAndroid Build Coastguard Worker printf("raw_read_blk: O_DIRECT fallback: %p %lu\n", buf,
283*6a54128fSAndroid Build Coastguard Worker (unsigned long) size);
284*6a54128fSAndroid Build Coastguard Worker #endif
285*6a54128fSAndroid Build Coastguard Worker
286*6a54128fSAndroid Build Coastguard Worker /*
287*6a54128fSAndroid Build Coastguard Worker * The buffer or size which we're trying to read isn't aligned
288*6a54128fSAndroid Build Coastguard Worker * to the O_DIRECT rules, so we need to do this the hard way...
289*6a54128fSAndroid Build Coastguard Worker */
290*6a54128fSAndroid Build Coastguard Worker bounce_read:
291*6a54128fSAndroid Build Coastguard Worker if (channel->align == 0)
292*6a54128fSAndroid Build Coastguard Worker channel->align = 1;
293*6a54128fSAndroid Build Coastguard Worker if ((channel->block_size > channel->align) &&
294*6a54128fSAndroid Build Coastguard Worker (channel->block_size % channel->align) == 0)
295*6a54128fSAndroid Build Coastguard Worker align_size = channel->block_size;
296*6a54128fSAndroid Build Coastguard Worker else
297*6a54128fSAndroid Build Coastguard Worker align_size = channel->align;
298*6a54128fSAndroid Build Coastguard Worker aligned_blk = location / align_size;
299*6a54128fSAndroid Build Coastguard Worker offset = location % align_size;
300*6a54128fSAndroid Build Coastguard Worker
301*6a54128fSAndroid Build Coastguard Worker mutex_lock(data, BOUNCE_MTX);
302*6a54128fSAndroid Build Coastguard Worker if (ext2fs_llseek(data->dev, aligned_blk * align_size, SEEK_SET) < 0) {
303*6a54128fSAndroid Build Coastguard Worker retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
304*6a54128fSAndroid Build Coastguard Worker goto error_unlock;
305*6a54128fSAndroid Build Coastguard Worker }
306*6a54128fSAndroid Build Coastguard Worker while (size > 0) {
307*6a54128fSAndroid Build Coastguard Worker actual = read(data->dev, data->bounce, align_size);
308*6a54128fSAndroid Build Coastguard Worker if (actual != align_size) {
309*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, BOUNCE_MTX);
310*6a54128fSAndroid Build Coastguard Worker actual = really_read;
311*6a54128fSAndroid Build Coastguard Worker buf -= really_read;
312*6a54128fSAndroid Build Coastguard Worker size += really_read;
313*6a54128fSAndroid Build Coastguard Worker goto short_read;
314*6a54128fSAndroid Build Coastguard Worker }
315*6a54128fSAndroid Build Coastguard Worker if ((actual + offset) > align_size)
316*6a54128fSAndroid Build Coastguard Worker actual = align_size - offset;
317*6a54128fSAndroid Build Coastguard Worker if (actual > size)
318*6a54128fSAndroid Build Coastguard Worker actual = size;
319*6a54128fSAndroid Build Coastguard Worker memcpy(buf, (char *)data->bounce + offset, actual);
320*6a54128fSAndroid Build Coastguard Worker
321*6a54128fSAndroid Build Coastguard Worker really_read += actual;
322*6a54128fSAndroid Build Coastguard Worker size -= actual;
323*6a54128fSAndroid Build Coastguard Worker buf += actual;
324*6a54128fSAndroid Build Coastguard Worker offset = 0;
325*6a54128fSAndroid Build Coastguard Worker aligned_blk++;
326*6a54128fSAndroid Build Coastguard Worker }
327*6a54128fSAndroid Build Coastguard Worker success_unlock:
328*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, BOUNCE_MTX);
329*6a54128fSAndroid Build Coastguard Worker return 0;
330*6a54128fSAndroid Build Coastguard Worker
331*6a54128fSAndroid Build Coastguard Worker error_unlock:
332*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, BOUNCE_MTX);
333*6a54128fSAndroid Build Coastguard Worker if (actual >= 0 && actual < size)
334*6a54128fSAndroid Build Coastguard Worker memset((char *) buf+actual, 0, size-actual);
335*6a54128fSAndroid Build Coastguard Worker if (channel->read_error)
336*6a54128fSAndroid Build Coastguard Worker retval = (channel->read_error)(channel, block, count, buf,
337*6a54128fSAndroid Build Coastguard Worker size, actual, retval);
338*6a54128fSAndroid Build Coastguard Worker return retval;
339*6a54128fSAndroid Build Coastguard Worker }
340*6a54128fSAndroid Build Coastguard Worker
341*6a54128fSAndroid Build Coastguard Worker #define RAW_WRITE_NO_HANDLER 1
342*6a54128fSAndroid Build Coastguard Worker
raw_write_blk(io_channel channel,struct unix_private_data * data,unsigned long long block,int count,const void * bufv,int flags)343*6a54128fSAndroid Build Coastguard Worker static errcode_t raw_write_blk(io_channel channel,
344*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data,
345*6a54128fSAndroid Build Coastguard Worker unsigned long long block,
346*6a54128fSAndroid Build Coastguard Worker int count, const void *bufv,
347*6a54128fSAndroid Build Coastguard Worker int flags)
348*6a54128fSAndroid Build Coastguard Worker {
349*6a54128fSAndroid Build Coastguard Worker ssize_t size;
350*6a54128fSAndroid Build Coastguard Worker ext2_loff_t location;
351*6a54128fSAndroid Build Coastguard Worker int actual = 0;
352*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
353*6a54128fSAndroid Build Coastguard Worker const unsigned char *buf = bufv;
354*6a54128fSAndroid Build Coastguard Worker unsigned long long aligned_blk;
355*6a54128fSAndroid Build Coastguard Worker int align_size, offset;
356*6a54128fSAndroid Build Coastguard Worker
357*6a54128fSAndroid Build Coastguard Worker if (count == 1)
358*6a54128fSAndroid Build Coastguard Worker size = channel->block_size;
359*6a54128fSAndroid Build Coastguard Worker else {
360*6a54128fSAndroid Build Coastguard Worker if (count < 0)
361*6a54128fSAndroid Build Coastguard Worker size = -count;
362*6a54128fSAndroid Build Coastguard Worker else
363*6a54128fSAndroid Build Coastguard Worker size = (ext2_loff_t) count * channel->block_size;
364*6a54128fSAndroid Build Coastguard Worker }
365*6a54128fSAndroid Build Coastguard Worker mutex_lock(data, STATS_MTX);
366*6a54128fSAndroid Build Coastguard Worker data->io_stats.bytes_written += size;
367*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, STATS_MTX);
368*6a54128fSAndroid Build Coastguard Worker
369*6a54128fSAndroid Build Coastguard Worker location = ((ext2_loff_t) block * channel->block_size) + data->offset;
370*6a54128fSAndroid Build Coastguard Worker
371*6a54128fSAndroid Build Coastguard Worker if (data->flags & IO_FLAG_FORCE_BOUNCE)
372*6a54128fSAndroid Build Coastguard Worker goto bounce_write;
373*6a54128fSAndroid Build Coastguard Worker
374*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_PWRITE64
375*6a54128fSAndroid Build Coastguard Worker /* Try an aligned pwrite */
376*6a54128fSAndroid Build Coastguard Worker if ((channel->align == 0) ||
377*6a54128fSAndroid Build Coastguard Worker (IS_ALIGNED(buf, channel->align) &&
378*6a54128fSAndroid Build Coastguard Worker IS_ALIGNED(location, channel->align) &&
379*6a54128fSAndroid Build Coastguard Worker IS_ALIGNED(size, channel->align))) {
380*6a54128fSAndroid Build Coastguard Worker actual = pwrite64(data->dev, buf, size, location);
381*6a54128fSAndroid Build Coastguard Worker if (actual == size)
382*6a54128fSAndroid Build Coastguard Worker return 0;
383*6a54128fSAndroid Build Coastguard Worker }
384*6a54128fSAndroid Build Coastguard Worker #elif HAVE_PWRITE
385*6a54128fSAndroid Build Coastguard Worker /* Try an aligned pwrite */
386*6a54128fSAndroid Build Coastguard Worker if ((sizeof(off_t) >= sizeof(ext2_loff_t)) &&
387*6a54128fSAndroid Build Coastguard Worker ((channel->align == 0) ||
388*6a54128fSAndroid Build Coastguard Worker (IS_ALIGNED(buf, channel->align) &&
389*6a54128fSAndroid Build Coastguard Worker IS_ALIGNED(location, channel->align) &&
390*6a54128fSAndroid Build Coastguard Worker IS_ALIGNED(size, channel->align)))) {
391*6a54128fSAndroid Build Coastguard Worker actual = pwrite(data->dev, buf, size, location);
392*6a54128fSAndroid Build Coastguard Worker if (actual == size)
393*6a54128fSAndroid Build Coastguard Worker return 0;
394*6a54128fSAndroid Build Coastguard Worker }
395*6a54128fSAndroid Build Coastguard Worker #endif /* HAVE_PWRITE */
396*6a54128fSAndroid Build Coastguard Worker
397*6a54128fSAndroid Build Coastguard Worker if ((channel->align == 0) ||
398*6a54128fSAndroid Build Coastguard Worker (IS_ALIGNED(buf, channel->align) &&
399*6a54128fSAndroid Build Coastguard Worker IS_ALIGNED(location, channel->align) &&
400*6a54128fSAndroid Build Coastguard Worker IS_ALIGNED(size, channel->align))) {
401*6a54128fSAndroid Build Coastguard Worker mutex_lock(data, BOUNCE_MTX);
402*6a54128fSAndroid Build Coastguard Worker if (ext2fs_llseek(data->dev, location, SEEK_SET) < 0) {
403*6a54128fSAndroid Build Coastguard Worker retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
404*6a54128fSAndroid Build Coastguard Worker goto error_unlock;
405*6a54128fSAndroid Build Coastguard Worker }
406*6a54128fSAndroid Build Coastguard Worker actual = write(data->dev, buf, size);
407*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, BOUNCE_MTX);
408*6a54128fSAndroid Build Coastguard Worker if (actual < 0) {
409*6a54128fSAndroid Build Coastguard Worker retval = errno;
410*6a54128fSAndroid Build Coastguard Worker goto error_out;
411*6a54128fSAndroid Build Coastguard Worker }
412*6a54128fSAndroid Build Coastguard Worker if (actual != size) {
413*6a54128fSAndroid Build Coastguard Worker short_write:
414*6a54128fSAndroid Build Coastguard Worker retval = EXT2_ET_SHORT_WRITE;
415*6a54128fSAndroid Build Coastguard Worker goto error_out;
416*6a54128fSAndroid Build Coastguard Worker }
417*6a54128fSAndroid Build Coastguard Worker return 0;
418*6a54128fSAndroid Build Coastguard Worker }
419*6a54128fSAndroid Build Coastguard Worker
420*6a54128fSAndroid Build Coastguard Worker #ifdef ALIGN_DEBUG
421*6a54128fSAndroid Build Coastguard Worker printf("raw_write_blk: O_DIRECT fallback: %p %lu\n", buf,
422*6a54128fSAndroid Build Coastguard Worker (unsigned long) size);
423*6a54128fSAndroid Build Coastguard Worker #endif
424*6a54128fSAndroid Build Coastguard Worker /*
425*6a54128fSAndroid Build Coastguard Worker * The buffer or size which we're trying to write isn't aligned
426*6a54128fSAndroid Build Coastguard Worker * to the O_DIRECT rules, so we need to do this the hard way...
427*6a54128fSAndroid Build Coastguard Worker */
428*6a54128fSAndroid Build Coastguard Worker bounce_write:
429*6a54128fSAndroid Build Coastguard Worker if (channel->align == 0)
430*6a54128fSAndroid Build Coastguard Worker channel->align = 1;
431*6a54128fSAndroid Build Coastguard Worker if ((channel->block_size > channel->align) &&
432*6a54128fSAndroid Build Coastguard Worker (channel->block_size % channel->align) == 0)
433*6a54128fSAndroid Build Coastguard Worker align_size = channel->block_size;
434*6a54128fSAndroid Build Coastguard Worker else
435*6a54128fSAndroid Build Coastguard Worker align_size = channel->align;
436*6a54128fSAndroid Build Coastguard Worker aligned_blk = location / align_size;
437*6a54128fSAndroid Build Coastguard Worker offset = location % align_size;
438*6a54128fSAndroid Build Coastguard Worker
439*6a54128fSAndroid Build Coastguard Worker while (size > 0) {
440*6a54128fSAndroid Build Coastguard Worker int actual_w;
441*6a54128fSAndroid Build Coastguard Worker
442*6a54128fSAndroid Build Coastguard Worker mutex_lock(data, BOUNCE_MTX);
443*6a54128fSAndroid Build Coastguard Worker if (size < align_size || offset) {
444*6a54128fSAndroid Build Coastguard Worker if (ext2fs_llseek(data->dev, aligned_blk * align_size,
445*6a54128fSAndroid Build Coastguard Worker SEEK_SET) < 0) {
446*6a54128fSAndroid Build Coastguard Worker retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
447*6a54128fSAndroid Build Coastguard Worker goto error_unlock;
448*6a54128fSAndroid Build Coastguard Worker }
449*6a54128fSAndroid Build Coastguard Worker actual = read(data->dev, data->bounce,
450*6a54128fSAndroid Build Coastguard Worker align_size);
451*6a54128fSAndroid Build Coastguard Worker if (actual != align_size) {
452*6a54128fSAndroid Build Coastguard Worker if (actual < 0) {
453*6a54128fSAndroid Build Coastguard Worker retval = errno;
454*6a54128fSAndroid Build Coastguard Worker goto error_unlock;
455*6a54128fSAndroid Build Coastguard Worker }
456*6a54128fSAndroid Build Coastguard Worker memset((char *) data->bounce + actual, 0,
457*6a54128fSAndroid Build Coastguard Worker align_size - actual);
458*6a54128fSAndroid Build Coastguard Worker }
459*6a54128fSAndroid Build Coastguard Worker }
460*6a54128fSAndroid Build Coastguard Worker actual = size;
461*6a54128fSAndroid Build Coastguard Worker if ((actual + offset) > align_size)
462*6a54128fSAndroid Build Coastguard Worker actual = align_size - offset;
463*6a54128fSAndroid Build Coastguard Worker if (actual > size)
464*6a54128fSAndroid Build Coastguard Worker actual = size;
465*6a54128fSAndroid Build Coastguard Worker memcpy(((char *)data->bounce) + offset, buf, actual);
466*6a54128fSAndroid Build Coastguard Worker if (ext2fs_llseek(data->dev, aligned_blk * align_size, SEEK_SET) < 0) {
467*6a54128fSAndroid Build Coastguard Worker retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
468*6a54128fSAndroid Build Coastguard Worker goto error_unlock;
469*6a54128fSAndroid Build Coastguard Worker }
470*6a54128fSAndroid Build Coastguard Worker actual_w = write(data->dev, data->bounce, align_size);
471*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, BOUNCE_MTX);
472*6a54128fSAndroid Build Coastguard Worker if (actual_w < 0) {
473*6a54128fSAndroid Build Coastguard Worker retval = errno;
474*6a54128fSAndroid Build Coastguard Worker goto error_out;
475*6a54128fSAndroid Build Coastguard Worker }
476*6a54128fSAndroid Build Coastguard Worker if (actual_w != align_size)
477*6a54128fSAndroid Build Coastguard Worker goto short_write;
478*6a54128fSAndroid Build Coastguard Worker size -= actual;
479*6a54128fSAndroid Build Coastguard Worker buf += actual;
480*6a54128fSAndroid Build Coastguard Worker location += actual;
481*6a54128fSAndroid Build Coastguard Worker aligned_blk++;
482*6a54128fSAndroid Build Coastguard Worker offset = 0;
483*6a54128fSAndroid Build Coastguard Worker }
484*6a54128fSAndroid Build Coastguard Worker return 0;
485*6a54128fSAndroid Build Coastguard Worker
486*6a54128fSAndroid Build Coastguard Worker error_unlock:
487*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, BOUNCE_MTX);
488*6a54128fSAndroid Build Coastguard Worker error_out:
489*6a54128fSAndroid Build Coastguard Worker if (((flags & RAW_WRITE_NO_HANDLER) == 0) && channel->write_error)
490*6a54128fSAndroid Build Coastguard Worker retval = (channel->write_error)(channel, block, count, buf,
491*6a54128fSAndroid Build Coastguard Worker size, actual, retval);
492*6a54128fSAndroid Build Coastguard Worker return retval;
493*6a54128fSAndroid Build Coastguard Worker }
494*6a54128fSAndroid Build Coastguard Worker
495*6a54128fSAndroid Build Coastguard Worker
496*6a54128fSAndroid Build Coastguard Worker /*
497*6a54128fSAndroid Build Coastguard Worker * Here we implement the cache functions
498*6a54128fSAndroid Build Coastguard Worker */
499*6a54128fSAndroid Build Coastguard Worker
500*6a54128fSAndroid Build Coastguard Worker /* Allocate the cache buffers */
alloc_cache(io_channel channel,struct unix_private_data * data)501*6a54128fSAndroid Build Coastguard Worker static errcode_t alloc_cache(io_channel channel,
502*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data)
503*6a54128fSAndroid Build Coastguard Worker {
504*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
505*6a54128fSAndroid Build Coastguard Worker struct unix_cache *cache;
506*6a54128fSAndroid Build Coastguard Worker int i;
507*6a54128fSAndroid Build Coastguard Worker
508*6a54128fSAndroid Build Coastguard Worker data->access_time = 0;
509*6a54128fSAndroid Build Coastguard Worker for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
510*6a54128fSAndroid Build Coastguard Worker cache->block = 0;
511*6a54128fSAndroid Build Coastguard Worker cache->access_time = 0;
512*6a54128fSAndroid Build Coastguard Worker cache->dirty = 0;
513*6a54128fSAndroid Build Coastguard Worker cache->in_use = 0;
514*6a54128fSAndroid Build Coastguard Worker if (cache->buf)
515*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&cache->buf);
516*6a54128fSAndroid Build Coastguard Worker retval = io_channel_alloc_buf(channel, 0, &cache->buf);
517*6a54128fSAndroid Build Coastguard Worker if (retval)
518*6a54128fSAndroid Build Coastguard Worker return retval;
519*6a54128fSAndroid Build Coastguard Worker }
520*6a54128fSAndroid Build Coastguard Worker if (channel->align || data->flags & IO_FLAG_FORCE_BOUNCE) {
521*6a54128fSAndroid Build Coastguard Worker if (data->bounce)
522*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&data->bounce);
523*6a54128fSAndroid Build Coastguard Worker retval = io_channel_alloc_buf(channel, 0, &data->bounce);
524*6a54128fSAndroid Build Coastguard Worker }
525*6a54128fSAndroid Build Coastguard Worker return retval;
526*6a54128fSAndroid Build Coastguard Worker }
527*6a54128fSAndroid Build Coastguard Worker
528*6a54128fSAndroid Build Coastguard Worker /* Free the cache buffers */
free_cache(struct unix_private_data * data)529*6a54128fSAndroid Build Coastguard Worker static void free_cache(struct unix_private_data *data)
530*6a54128fSAndroid Build Coastguard Worker {
531*6a54128fSAndroid Build Coastguard Worker struct unix_cache *cache;
532*6a54128fSAndroid Build Coastguard Worker int i;
533*6a54128fSAndroid Build Coastguard Worker
534*6a54128fSAndroid Build Coastguard Worker data->access_time = 0;
535*6a54128fSAndroid Build Coastguard Worker for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
536*6a54128fSAndroid Build Coastguard Worker cache->block = 0;
537*6a54128fSAndroid Build Coastguard Worker cache->access_time = 0;
538*6a54128fSAndroid Build Coastguard Worker cache->dirty = 0;
539*6a54128fSAndroid Build Coastguard Worker cache->in_use = 0;
540*6a54128fSAndroid Build Coastguard Worker if (cache->buf)
541*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&cache->buf);
542*6a54128fSAndroid Build Coastguard Worker }
543*6a54128fSAndroid Build Coastguard Worker if (data->bounce)
544*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&data->bounce);
545*6a54128fSAndroid Build Coastguard Worker }
546*6a54128fSAndroid Build Coastguard Worker
547*6a54128fSAndroid Build Coastguard Worker #ifndef NO_IO_CACHE
548*6a54128fSAndroid Build Coastguard Worker /*
549*6a54128fSAndroid Build Coastguard Worker * Try to find a block in the cache. If the block is not found, and
550*6a54128fSAndroid Build Coastguard Worker * eldest is a non-zero pointer, then fill in eldest with the cache
551*6a54128fSAndroid Build Coastguard Worker * entry to that should be reused.
552*6a54128fSAndroid Build Coastguard Worker */
find_cached_block(struct unix_private_data * data,unsigned long long block,struct unix_cache ** eldest)553*6a54128fSAndroid Build Coastguard Worker static struct unix_cache *find_cached_block(struct unix_private_data *data,
554*6a54128fSAndroid Build Coastguard Worker unsigned long long block,
555*6a54128fSAndroid Build Coastguard Worker struct unix_cache **eldest)
556*6a54128fSAndroid Build Coastguard Worker {
557*6a54128fSAndroid Build Coastguard Worker struct unix_cache *cache, *unused_cache, *oldest_cache;
558*6a54128fSAndroid Build Coastguard Worker int i;
559*6a54128fSAndroid Build Coastguard Worker
560*6a54128fSAndroid Build Coastguard Worker unused_cache = oldest_cache = 0;
561*6a54128fSAndroid Build Coastguard Worker for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
562*6a54128fSAndroid Build Coastguard Worker if (!cache->in_use) {
563*6a54128fSAndroid Build Coastguard Worker if (!unused_cache)
564*6a54128fSAndroid Build Coastguard Worker unused_cache = cache;
565*6a54128fSAndroid Build Coastguard Worker continue;
566*6a54128fSAndroid Build Coastguard Worker }
567*6a54128fSAndroid Build Coastguard Worker if (cache->block == block) {
568*6a54128fSAndroid Build Coastguard Worker cache->access_time = ++data->access_time;
569*6a54128fSAndroid Build Coastguard Worker return cache;
570*6a54128fSAndroid Build Coastguard Worker }
571*6a54128fSAndroid Build Coastguard Worker if (!oldest_cache ||
572*6a54128fSAndroid Build Coastguard Worker (cache->access_time < oldest_cache->access_time))
573*6a54128fSAndroid Build Coastguard Worker oldest_cache = cache;
574*6a54128fSAndroid Build Coastguard Worker }
575*6a54128fSAndroid Build Coastguard Worker if (eldest)
576*6a54128fSAndroid Build Coastguard Worker *eldest = (unused_cache) ? unused_cache : oldest_cache;
577*6a54128fSAndroid Build Coastguard Worker return 0;
578*6a54128fSAndroid Build Coastguard Worker }
579*6a54128fSAndroid Build Coastguard Worker
580*6a54128fSAndroid Build Coastguard Worker /*
581*6a54128fSAndroid Build Coastguard Worker * Reuse a particular cache entry for another block.
582*6a54128fSAndroid Build Coastguard Worker */
reuse_cache(io_channel channel,struct unix_private_data * data,struct unix_cache * cache,unsigned long long block)583*6a54128fSAndroid Build Coastguard Worker static errcode_t reuse_cache(io_channel channel,
584*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data, struct unix_cache *cache,
585*6a54128fSAndroid Build Coastguard Worker unsigned long long block)
586*6a54128fSAndroid Build Coastguard Worker {
587*6a54128fSAndroid Build Coastguard Worker if (cache->dirty && cache->in_use) {
588*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
589*6a54128fSAndroid Build Coastguard Worker
590*6a54128fSAndroid Build Coastguard Worker retval = raw_write_blk(channel, data, cache->block, 1,
591*6a54128fSAndroid Build Coastguard Worker cache->buf, RAW_WRITE_NO_HANDLER);
592*6a54128fSAndroid Build Coastguard Worker if (retval) {
593*6a54128fSAndroid Build Coastguard Worker cache->write_err = 1;
594*6a54128fSAndroid Build Coastguard Worker return retval;
595*6a54128fSAndroid Build Coastguard Worker }
596*6a54128fSAndroid Build Coastguard Worker }
597*6a54128fSAndroid Build Coastguard Worker
598*6a54128fSAndroid Build Coastguard Worker cache->in_use = 1;
599*6a54128fSAndroid Build Coastguard Worker cache->dirty = 0;
600*6a54128fSAndroid Build Coastguard Worker cache->write_err = 0;
601*6a54128fSAndroid Build Coastguard Worker cache->block = block;
602*6a54128fSAndroid Build Coastguard Worker cache->access_time = ++data->access_time;
603*6a54128fSAndroid Build Coastguard Worker return 0;
604*6a54128fSAndroid Build Coastguard Worker }
605*6a54128fSAndroid Build Coastguard Worker
606*6a54128fSAndroid Build Coastguard Worker #define FLUSH_INVALIDATE 0x01
607*6a54128fSAndroid Build Coastguard Worker #define FLUSH_NOLOCK 0x02
608*6a54128fSAndroid Build Coastguard Worker
609*6a54128fSAndroid Build Coastguard Worker /*
610*6a54128fSAndroid Build Coastguard Worker * Flush all of the blocks in the cache
611*6a54128fSAndroid Build Coastguard Worker */
flush_cached_blocks(io_channel channel,struct unix_private_data * data,int flags)612*6a54128fSAndroid Build Coastguard Worker static errcode_t flush_cached_blocks(io_channel channel,
613*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data,
614*6a54128fSAndroid Build Coastguard Worker int flags)
615*6a54128fSAndroid Build Coastguard Worker {
616*6a54128fSAndroid Build Coastguard Worker struct unix_cache *cache;
617*6a54128fSAndroid Build Coastguard Worker errcode_t retval, retval2 = 0;
618*6a54128fSAndroid Build Coastguard Worker int i;
619*6a54128fSAndroid Build Coastguard Worker int errors_found = 0;
620*6a54128fSAndroid Build Coastguard Worker
621*6a54128fSAndroid Build Coastguard Worker if ((flags & FLUSH_NOLOCK) == 0)
622*6a54128fSAndroid Build Coastguard Worker mutex_lock(data, CACHE_MTX);
623*6a54128fSAndroid Build Coastguard Worker for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
624*6a54128fSAndroid Build Coastguard Worker if (!cache->in_use || !cache->dirty)
625*6a54128fSAndroid Build Coastguard Worker continue;
626*6a54128fSAndroid Build Coastguard Worker retval = raw_write_blk(channel, data,
627*6a54128fSAndroid Build Coastguard Worker cache->block, 1, cache->buf,
628*6a54128fSAndroid Build Coastguard Worker RAW_WRITE_NO_HANDLER);
629*6a54128fSAndroid Build Coastguard Worker if (retval) {
630*6a54128fSAndroid Build Coastguard Worker cache->write_err = 1;
631*6a54128fSAndroid Build Coastguard Worker errors_found = 1;
632*6a54128fSAndroid Build Coastguard Worker retval2 = retval;
633*6a54128fSAndroid Build Coastguard Worker } else {
634*6a54128fSAndroid Build Coastguard Worker cache->dirty = 0;
635*6a54128fSAndroid Build Coastguard Worker cache->write_err = 0;
636*6a54128fSAndroid Build Coastguard Worker if (flags & FLUSH_INVALIDATE)
637*6a54128fSAndroid Build Coastguard Worker cache->in_use = 0;
638*6a54128fSAndroid Build Coastguard Worker }
639*6a54128fSAndroid Build Coastguard Worker }
640*6a54128fSAndroid Build Coastguard Worker if ((flags & FLUSH_NOLOCK) == 0)
641*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, CACHE_MTX);
642*6a54128fSAndroid Build Coastguard Worker retry:
643*6a54128fSAndroid Build Coastguard Worker while (errors_found) {
644*6a54128fSAndroid Build Coastguard Worker if ((flags & FLUSH_NOLOCK) == 0)
645*6a54128fSAndroid Build Coastguard Worker mutex_lock(data, CACHE_MTX);
646*6a54128fSAndroid Build Coastguard Worker errors_found = 0;
647*6a54128fSAndroid Build Coastguard Worker for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
648*6a54128fSAndroid Build Coastguard Worker if (!cache->in_use || !cache->write_err)
649*6a54128fSAndroid Build Coastguard Worker continue;
650*6a54128fSAndroid Build Coastguard Worker errors_found = 1;
651*6a54128fSAndroid Build Coastguard Worker if (cache->write_err && channel->write_error) {
652*6a54128fSAndroid Build Coastguard Worker char *err_buf = NULL;
653*6a54128fSAndroid Build Coastguard Worker unsigned long long err_block = cache->block;
654*6a54128fSAndroid Build Coastguard Worker
655*6a54128fSAndroid Build Coastguard Worker cache->dirty = 0;
656*6a54128fSAndroid Build Coastguard Worker cache->in_use = 0;
657*6a54128fSAndroid Build Coastguard Worker cache->write_err = 0;
658*6a54128fSAndroid Build Coastguard Worker if (io_channel_alloc_buf(channel, 0,
659*6a54128fSAndroid Build Coastguard Worker &err_buf))
660*6a54128fSAndroid Build Coastguard Worker err_buf = NULL;
661*6a54128fSAndroid Build Coastguard Worker else
662*6a54128fSAndroid Build Coastguard Worker memcpy(err_buf, cache->buf,
663*6a54128fSAndroid Build Coastguard Worker channel->block_size);
664*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, CACHE_MTX);
665*6a54128fSAndroid Build Coastguard Worker (channel->write_error)(channel, err_block,
666*6a54128fSAndroid Build Coastguard Worker 1, err_buf, channel->block_size, -1,
667*6a54128fSAndroid Build Coastguard Worker retval2);
668*6a54128fSAndroid Build Coastguard Worker if (err_buf)
669*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&err_buf);
670*6a54128fSAndroid Build Coastguard Worker goto retry;
671*6a54128fSAndroid Build Coastguard Worker } else
672*6a54128fSAndroid Build Coastguard Worker cache->write_err = 0;
673*6a54128fSAndroid Build Coastguard Worker }
674*6a54128fSAndroid Build Coastguard Worker if ((flags & FLUSH_NOLOCK) == 0)
675*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, CACHE_MTX);
676*6a54128fSAndroid Build Coastguard Worker }
677*6a54128fSAndroid Build Coastguard Worker return retval2;
678*6a54128fSAndroid Build Coastguard Worker }
679*6a54128fSAndroid Build Coastguard Worker #endif /* NO_IO_CACHE */
680*6a54128fSAndroid Build Coastguard Worker
681*6a54128fSAndroid Build Coastguard Worker #ifdef __linux__
682*6a54128fSAndroid Build Coastguard Worker #ifndef BLKDISCARDZEROES
683*6a54128fSAndroid Build Coastguard Worker #define BLKDISCARDZEROES _IO(0x12,124)
684*6a54128fSAndroid Build Coastguard Worker #endif
685*6a54128fSAndroid Build Coastguard Worker #endif
686*6a54128fSAndroid Build Coastguard Worker
ext2fs_open_file(const char * pathname,int flags,mode_t mode)687*6a54128fSAndroid Build Coastguard Worker int ext2fs_open_file(const char *pathname, int flags, mode_t mode)
688*6a54128fSAndroid Build Coastguard Worker {
689*6a54128fSAndroid Build Coastguard Worker if (mode)
690*6a54128fSAndroid Build Coastguard Worker #if defined(HAVE_OPEN64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
691*6a54128fSAndroid Build Coastguard Worker return open64(pathname, flags, mode);
692*6a54128fSAndroid Build Coastguard Worker else
693*6a54128fSAndroid Build Coastguard Worker return open64(pathname, flags);
694*6a54128fSAndroid Build Coastguard Worker #else
695*6a54128fSAndroid Build Coastguard Worker return open(pathname, flags, mode);
696*6a54128fSAndroid Build Coastguard Worker else
697*6a54128fSAndroid Build Coastguard Worker return open(pathname, flags);
698*6a54128fSAndroid Build Coastguard Worker #endif
699*6a54128fSAndroid Build Coastguard Worker }
700*6a54128fSAndroid Build Coastguard Worker
ext2fs_stat(const char * path,ext2fs_struct_stat * buf)701*6a54128fSAndroid Build Coastguard Worker int ext2fs_stat(const char *path, ext2fs_struct_stat *buf)
702*6a54128fSAndroid Build Coastguard Worker {
703*6a54128fSAndroid Build Coastguard Worker #if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
704*6a54128fSAndroid Build Coastguard Worker return stat64(path, buf);
705*6a54128fSAndroid Build Coastguard Worker #else
706*6a54128fSAndroid Build Coastguard Worker return stat(path, buf);
707*6a54128fSAndroid Build Coastguard Worker #endif
708*6a54128fSAndroid Build Coastguard Worker }
709*6a54128fSAndroid Build Coastguard Worker
ext2fs_fstat(int fd,ext2fs_struct_stat * buf)710*6a54128fSAndroid Build Coastguard Worker int ext2fs_fstat(int fd, ext2fs_struct_stat *buf)
711*6a54128fSAndroid Build Coastguard Worker {
712*6a54128fSAndroid Build Coastguard Worker #if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
713*6a54128fSAndroid Build Coastguard Worker return fstat64(fd, buf);
714*6a54128fSAndroid Build Coastguard Worker #else
715*6a54128fSAndroid Build Coastguard Worker return fstat(fd, buf);
716*6a54128fSAndroid Build Coastguard Worker #endif
717*6a54128fSAndroid Build Coastguard Worker }
718*6a54128fSAndroid Build Coastguard Worker
719*6a54128fSAndroid Build Coastguard Worker
unix_open_channel(const char * name,int fd,int flags,io_channel * channel,io_manager io_mgr)720*6a54128fSAndroid Build Coastguard Worker static errcode_t unix_open_channel(const char *name, int fd,
721*6a54128fSAndroid Build Coastguard Worker int flags, io_channel *channel,
722*6a54128fSAndroid Build Coastguard Worker io_manager io_mgr)
723*6a54128fSAndroid Build Coastguard Worker {
724*6a54128fSAndroid Build Coastguard Worker io_channel io = NULL;
725*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data = NULL;
726*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
727*6a54128fSAndroid Build Coastguard Worker ext2fs_struct_stat st;
728*6a54128fSAndroid Build Coastguard Worker #ifdef __linux__
729*6a54128fSAndroid Build Coastguard Worker struct utsname ut;
730*6a54128fSAndroid Build Coastguard Worker #endif
731*6a54128fSAndroid Build Coastguard Worker
732*6a54128fSAndroid Build Coastguard Worker if (safe_getenv("UNIX_IO_FORCE_BOUNCE"))
733*6a54128fSAndroid Build Coastguard Worker flags |= IO_FLAG_FORCE_BOUNCE;
734*6a54128fSAndroid Build Coastguard Worker
735*6a54128fSAndroid Build Coastguard Worker #ifdef __linux__
736*6a54128fSAndroid Build Coastguard Worker /*
737*6a54128fSAndroid Build Coastguard Worker * We need to make sure any previous errors in the block
738*6a54128fSAndroid Build Coastguard Worker * device are thrown away, sigh.
739*6a54128fSAndroid Build Coastguard Worker */
740*6a54128fSAndroid Build Coastguard Worker (void) fsync(fd);
741*6a54128fSAndroid Build Coastguard Worker #endif
742*6a54128fSAndroid Build Coastguard Worker
743*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
744*6a54128fSAndroid Build Coastguard Worker if (retval)
745*6a54128fSAndroid Build Coastguard Worker goto cleanup;
746*6a54128fSAndroid Build Coastguard Worker memset(io, 0, sizeof(struct struct_io_channel));
747*6a54128fSAndroid Build Coastguard Worker io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
748*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
749*6a54128fSAndroid Build Coastguard Worker if (retval)
750*6a54128fSAndroid Build Coastguard Worker goto cleanup;
751*6a54128fSAndroid Build Coastguard Worker
752*6a54128fSAndroid Build Coastguard Worker io->manager = io_mgr;
753*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_get_mem(strlen(name)+1, &io->name);
754*6a54128fSAndroid Build Coastguard Worker if (retval)
755*6a54128fSAndroid Build Coastguard Worker goto cleanup;
756*6a54128fSAndroid Build Coastguard Worker
757*6a54128fSAndroid Build Coastguard Worker strcpy(io->name, name);
758*6a54128fSAndroid Build Coastguard Worker io->private_data = data;
759*6a54128fSAndroid Build Coastguard Worker io->block_size = 1024;
760*6a54128fSAndroid Build Coastguard Worker io->read_error = 0;
761*6a54128fSAndroid Build Coastguard Worker io->write_error = 0;
762*6a54128fSAndroid Build Coastguard Worker io->refcount = 1;
763*6a54128fSAndroid Build Coastguard Worker io->flags = 0;
764*6a54128fSAndroid Build Coastguard Worker
765*6a54128fSAndroid Build Coastguard Worker memset(data, 0, sizeof(struct unix_private_data));
766*6a54128fSAndroid Build Coastguard Worker data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
767*6a54128fSAndroid Build Coastguard Worker data->io_stats.num_fields = 2;
768*6a54128fSAndroid Build Coastguard Worker data->flags = flags;
769*6a54128fSAndroid Build Coastguard Worker data->dev = fd;
770*6a54128fSAndroid Build Coastguard Worker
771*6a54128fSAndroid Build Coastguard Worker #if defined(O_DIRECT)
772*6a54128fSAndroid Build Coastguard Worker if (flags & IO_FLAG_DIRECT_IO)
773*6a54128fSAndroid Build Coastguard Worker io->align = ext2fs_get_dio_alignment(data->dev);
774*6a54128fSAndroid Build Coastguard Worker #elif defined(F_NOCACHE)
775*6a54128fSAndroid Build Coastguard Worker if (flags & IO_FLAG_DIRECT_IO)
776*6a54128fSAndroid Build Coastguard Worker io->align = 4096;
777*6a54128fSAndroid Build Coastguard Worker #endif
778*6a54128fSAndroid Build Coastguard Worker
779*6a54128fSAndroid Build Coastguard Worker /*
780*6a54128fSAndroid Build Coastguard Worker * If the device is really a block device, then set the
781*6a54128fSAndroid Build Coastguard Worker * appropriate flag, otherwise we can set DISCARD_ZEROES flag
782*6a54128fSAndroid Build Coastguard Worker * because we are going to use punch hole instead of discard
783*6a54128fSAndroid Build Coastguard Worker * and if it succeed, subsequent read from sparse area returns
784*6a54128fSAndroid Build Coastguard Worker * zero.
785*6a54128fSAndroid Build Coastguard Worker */
786*6a54128fSAndroid Build Coastguard Worker if (ext2fs_fstat(data->dev, &st) == 0) {
787*6a54128fSAndroid Build Coastguard Worker if (ext2fsP_is_disk_device(st.st_mode))
788*6a54128fSAndroid Build Coastguard Worker io->flags |= CHANNEL_FLAGS_BLOCK_DEVICE;
789*6a54128fSAndroid Build Coastguard Worker else
790*6a54128fSAndroid Build Coastguard Worker io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES;
791*6a54128fSAndroid Build Coastguard Worker }
792*6a54128fSAndroid Build Coastguard Worker
793*6a54128fSAndroid Build Coastguard Worker #ifdef BLKDISCARDZEROES
794*6a54128fSAndroid Build Coastguard Worker {
795*6a54128fSAndroid Build Coastguard Worker int zeroes = 0;
796*6a54128fSAndroid Build Coastguard Worker if (ioctl(data->dev, BLKDISCARDZEROES, &zeroes) == 0 &&
797*6a54128fSAndroid Build Coastguard Worker zeroes)
798*6a54128fSAndroid Build Coastguard Worker io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES;
799*6a54128fSAndroid Build Coastguard Worker }
800*6a54128fSAndroid Build Coastguard Worker #endif
801*6a54128fSAndroid Build Coastguard Worker
802*6a54128fSAndroid Build Coastguard Worker #if defined(__CYGWIN__)
803*6a54128fSAndroid Build Coastguard Worker /*
804*6a54128fSAndroid Build Coastguard Worker * Some operating systems require that the buffers be aligned,
805*6a54128fSAndroid Build Coastguard Worker * regardless of O_DIRECT
806*6a54128fSAndroid Build Coastguard Worker */
807*6a54128fSAndroid Build Coastguard Worker if (!io->align)
808*6a54128fSAndroid Build Coastguard Worker io->align = 512;
809*6a54128fSAndroid Build Coastguard Worker #endif
810*6a54128fSAndroid Build Coastguard Worker
811*6a54128fSAndroid Build Coastguard Worker #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
812*6a54128fSAndroid Build Coastguard Worker if (io->flags & CHANNEL_FLAGS_BLOCK_DEVICE) {
813*6a54128fSAndroid Build Coastguard Worker int dio_align = ext2fs_get_dio_alignment(fd);
814*6a54128fSAndroid Build Coastguard Worker
815*6a54128fSAndroid Build Coastguard Worker if (io->align < dio_align)
816*6a54128fSAndroid Build Coastguard Worker io->align = dio_align;
817*6a54128fSAndroid Build Coastguard Worker }
818*6a54128fSAndroid Build Coastguard Worker #endif
819*6a54128fSAndroid Build Coastguard Worker
820*6a54128fSAndroid Build Coastguard Worker if ((retval = alloc_cache(io, data)))
821*6a54128fSAndroid Build Coastguard Worker goto cleanup;
822*6a54128fSAndroid Build Coastguard Worker
823*6a54128fSAndroid Build Coastguard Worker #ifdef BLKROGET
824*6a54128fSAndroid Build Coastguard Worker if (flags & IO_FLAG_RW) {
825*6a54128fSAndroid Build Coastguard Worker int error;
826*6a54128fSAndroid Build Coastguard Worker int readonly = 0;
827*6a54128fSAndroid Build Coastguard Worker
828*6a54128fSAndroid Build Coastguard Worker /* Is the block device actually writable? */
829*6a54128fSAndroid Build Coastguard Worker error = ioctl(data->dev, BLKROGET, &readonly);
830*6a54128fSAndroid Build Coastguard Worker if (!error && readonly) {
831*6a54128fSAndroid Build Coastguard Worker retval = EPERM;
832*6a54128fSAndroid Build Coastguard Worker goto cleanup;
833*6a54128fSAndroid Build Coastguard Worker }
834*6a54128fSAndroid Build Coastguard Worker }
835*6a54128fSAndroid Build Coastguard Worker #endif
836*6a54128fSAndroid Build Coastguard Worker
837*6a54128fSAndroid Build Coastguard Worker #ifdef __linux__
838*6a54128fSAndroid Build Coastguard Worker #undef RLIM_INFINITY
839*6a54128fSAndroid Build Coastguard Worker #if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
840*6a54128fSAndroid Build Coastguard Worker #define RLIM_INFINITY ((unsigned long)(~0UL>>1))
841*6a54128fSAndroid Build Coastguard Worker #else
842*6a54128fSAndroid Build Coastguard Worker #define RLIM_INFINITY (~0UL)
843*6a54128fSAndroid Build Coastguard Worker #endif
844*6a54128fSAndroid Build Coastguard Worker /*
845*6a54128fSAndroid Build Coastguard Worker * Work around a bug in 2.4.10-2.4.18 kernels where writes to
846*6a54128fSAndroid Build Coastguard Worker * block devices are wrongly getting hit by the filesize
847*6a54128fSAndroid Build Coastguard Worker * limit. This workaround isn't perfect, since it won't work
848*6a54128fSAndroid Build Coastguard Worker * if glibc wasn't built against 2.2 header files. (Sigh.)
849*6a54128fSAndroid Build Coastguard Worker *
850*6a54128fSAndroid Build Coastguard Worker */
851*6a54128fSAndroid Build Coastguard Worker if ((flags & IO_FLAG_RW) &&
852*6a54128fSAndroid Build Coastguard Worker (uname(&ut) == 0) &&
853*6a54128fSAndroid Build Coastguard Worker ((ut.release[0] == '2') && (ut.release[1] == '.') &&
854*6a54128fSAndroid Build Coastguard Worker (ut.release[2] == '4') && (ut.release[3] == '.') &&
855*6a54128fSAndroid Build Coastguard Worker (ut.release[4] == '1') && (ut.release[5] >= '0') &&
856*6a54128fSAndroid Build Coastguard Worker (ut.release[5] < '8')) &&
857*6a54128fSAndroid Build Coastguard Worker (ext2fs_fstat(data->dev, &st) == 0) &&
858*6a54128fSAndroid Build Coastguard Worker (ext2fsP_is_disk_device(st.st_mode))) {
859*6a54128fSAndroid Build Coastguard Worker struct rlimit rlim;
860*6a54128fSAndroid Build Coastguard Worker
861*6a54128fSAndroid Build Coastguard Worker rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
862*6a54128fSAndroid Build Coastguard Worker setrlimit(RLIMIT_FSIZE, &rlim);
863*6a54128fSAndroid Build Coastguard Worker getrlimit(RLIMIT_FSIZE, &rlim);
864*6a54128fSAndroid Build Coastguard Worker if (((unsigned long) rlim.rlim_cur) <
865*6a54128fSAndroid Build Coastguard Worker ((unsigned long) rlim.rlim_max)) {
866*6a54128fSAndroid Build Coastguard Worker rlim.rlim_cur = rlim.rlim_max;
867*6a54128fSAndroid Build Coastguard Worker setrlimit(RLIMIT_FSIZE, &rlim);
868*6a54128fSAndroid Build Coastguard Worker }
869*6a54128fSAndroid Build Coastguard Worker }
870*6a54128fSAndroid Build Coastguard Worker #endif
871*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_PTHREAD
872*6a54128fSAndroid Build Coastguard Worker if (flags & IO_FLAG_THREADS) {
873*6a54128fSAndroid Build Coastguard Worker io->flags |= CHANNEL_FLAGS_THREADS;
874*6a54128fSAndroid Build Coastguard Worker retval = pthread_mutex_init(&data->cache_mutex, NULL);
875*6a54128fSAndroid Build Coastguard Worker if (retval)
876*6a54128fSAndroid Build Coastguard Worker goto cleanup;
877*6a54128fSAndroid Build Coastguard Worker retval = pthread_mutex_init(&data->bounce_mutex, NULL);
878*6a54128fSAndroid Build Coastguard Worker if (retval) {
879*6a54128fSAndroid Build Coastguard Worker pthread_mutex_destroy(&data->cache_mutex);
880*6a54128fSAndroid Build Coastguard Worker goto cleanup;
881*6a54128fSAndroid Build Coastguard Worker }
882*6a54128fSAndroid Build Coastguard Worker retval = pthread_mutex_init(&data->stats_mutex, NULL);
883*6a54128fSAndroid Build Coastguard Worker if (retval) {
884*6a54128fSAndroid Build Coastguard Worker pthread_mutex_destroy(&data->cache_mutex);
885*6a54128fSAndroid Build Coastguard Worker pthread_mutex_destroy(&data->bounce_mutex);
886*6a54128fSAndroid Build Coastguard Worker goto cleanup;
887*6a54128fSAndroid Build Coastguard Worker }
888*6a54128fSAndroid Build Coastguard Worker }
889*6a54128fSAndroid Build Coastguard Worker #endif
890*6a54128fSAndroid Build Coastguard Worker *channel = io;
891*6a54128fSAndroid Build Coastguard Worker return 0;
892*6a54128fSAndroid Build Coastguard Worker
893*6a54128fSAndroid Build Coastguard Worker cleanup:
894*6a54128fSAndroid Build Coastguard Worker if (data) {
895*6a54128fSAndroid Build Coastguard Worker if (data->dev >= 0)
896*6a54128fSAndroid Build Coastguard Worker close(data->dev);
897*6a54128fSAndroid Build Coastguard Worker free_cache(data);
898*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&data);
899*6a54128fSAndroid Build Coastguard Worker }
900*6a54128fSAndroid Build Coastguard Worker if (io) {
901*6a54128fSAndroid Build Coastguard Worker if (io->name) {
902*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&io->name);
903*6a54128fSAndroid Build Coastguard Worker }
904*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&io);
905*6a54128fSAndroid Build Coastguard Worker }
906*6a54128fSAndroid Build Coastguard Worker return retval;
907*6a54128fSAndroid Build Coastguard Worker }
908*6a54128fSAndroid Build Coastguard Worker
unixfd_open(const char * str_fd,int flags,io_channel * channel)909*6a54128fSAndroid Build Coastguard Worker static errcode_t unixfd_open(const char *str_fd, int flags,
910*6a54128fSAndroid Build Coastguard Worker io_channel *channel)
911*6a54128fSAndroid Build Coastguard Worker {
912*6a54128fSAndroid Build Coastguard Worker int fd;
913*6a54128fSAndroid Build Coastguard Worker int fd_flags;
914*6a54128fSAndroid Build Coastguard Worker
915*6a54128fSAndroid Build Coastguard Worker fd = atoi(str_fd);
916*6a54128fSAndroid Build Coastguard Worker #if defined(HAVE_FCNTL)
917*6a54128fSAndroid Build Coastguard Worker fd_flags = fcntl(fd, F_GETFD);
918*6a54128fSAndroid Build Coastguard Worker if (fd_flags == -1)
919*6a54128fSAndroid Build Coastguard Worker return EBADF;
920*6a54128fSAndroid Build Coastguard Worker
921*6a54128fSAndroid Build Coastguard Worker flags = 0;
922*6a54128fSAndroid Build Coastguard Worker if (fd_flags & O_RDWR)
923*6a54128fSAndroid Build Coastguard Worker flags |= IO_FLAG_RW;
924*6a54128fSAndroid Build Coastguard Worker if (fd_flags & O_EXCL)
925*6a54128fSAndroid Build Coastguard Worker flags |= IO_FLAG_EXCLUSIVE;
926*6a54128fSAndroid Build Coastguard Worker #if defined(O_DIRECT)
927*6a54128fSAndroid Build Coastguard Worker if (fd_flags & O_DIRECT)
928*6a54128fSAndroid Build Coastguard Worker flags |= IO_FLAG_DIRECT_IO;
929*6a54128fSAndroid Build Coastguard Worker #endif
930*6a54128fSAndroid Build Coastguard Worker #endif /* HAVE_FCNTL */
931*6a54128fSAndroid Build Coastguard Worker
932*6a54128fSAndroid Build Coastguard Worker return unix_open_channel(str_fd, fd, flags, channel, unixfd_io_manager);
933*6a54128fSAndroid Build Coastguard Worker }
934*6a54128fSAndroid Build Coastguard Worker
unix_open(const char * name,int flags,io_channel * channel)935*6a54128fSAndroid Build Coastguard Worker static errcode_t unix_open(const char *name, int flags,
936*6a54128fSAndroid Build Coastguard Worker io_channel *channel)
937*6a54128fSAndroid Build Coastguard Worker {
938*6a54128fSAndroid Build Coastguard Worker int fd = -1;
939*6a54128fSAndroid Build Coastguard Worker int open_flags;
940*6a54128fSAndroid Build Coastguard Worker
941*6a54128fSAndroid Build Coastguard Worker if (name == 0)
942*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_BAD_DEVICE_NAME;
943*6a54128fSAndroid Build Coastguard Worker
944*6a54128fSAndroid Build Coastguard Worker open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
945*6a54128fSAndroid Build Coastguard Worker if (flags & IO_FLAG_EXCLUSIVE)
946*6a54128fSAndroid Build Coastguard Worker open_flags |= O_EXCL;
947*6a54128fSAndroid Build Coastguard Worker #if defined(O_DIRECT)
948*6a54128fSAndroid Build Coastguard Worker if (flags & IO_FLAG_DIRECT_IO)
949*6a54128fSAndroid Build Coastguard Worker open_flags |= O_DIRECT;
950*6a54128fSAndroid Build Coastguard Worker #endif
951*6a54128fSAndroid Build Coastguard Worker fd = ext2fs_open_file(name, open_flags, 0);
952*6a54128fSAndroid Build Coastguard Worker if (fd < 0)
953*6a54128fSAndroid Build Coastguard Worker return errno;
954*6a54128fSAndroid Build Coastguard Worker #if defined(F_NOCACHE) && !defined(IO_DIRECT)
955*6a54128fSAndroid Build Coastguard Worker if (flags & IO_FLAG_DIRECT_IO) {
956*6a54128fSAndroid Build Coastguard Worker if (fcntl(fd, F_NOCACHE, 1) < 0)
957*6a54128fSAndroid Build Coastguard Worker return errno;
958*6a54128fSAndroid Build Coastguard Worker }
959*6a54128fSAndroid Build Coastguard Worker #endif
960*6a54128fSAndroid Build Coastguard Worker return unix_open_channel(name, fd, flags, channel, unix_io_manager);
961*6a54128fSAndroid Build Coastguard Worker }
962*6a54128fSAndroid Build Coastguard Worker
unix_close(io_channel channel)963*6a54128fSAndroid Build Coastguard Worker static errcode_t unix_close(io_channel channel)
964*6a54128fSAndroid Build Coastguard Worker {
965*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data;
966*6a54128fSAndroid Build Coastguard Worker errcode_t retval = 0;
967*6a54128fSAndroid Build Coastguard Worker
968*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
969*6a54128fSAndroid Build Coastguard Worker data = (struct unix_private_data *) channel->private_data;
970*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
971*6a54128fSAndroid Build Coastguard Worker
972*6a54128fSAndroid Build Coastguard Worker if (--channel->refcount > 0)
973*6a54128fSAndroid Build Coastguard Worker return 0;
974*6a54128fSAndroid Build Coastguard Worker
975*6a54128fSAndroid Build Coastguard Worker #ifndef NO_IO_CACHE
976*6a54128fSAndroid Build Coastguard Worker retval = flush_cached_blocks(channel, data, 0);
977*6a54128fSAndroid Build Coastguard Worker #endif
978*6a54128fSAndroid Build Coastguard Worker
979*6a54128fSAndroid Build Coastguard Worker if (close(data->dev) < 0)
980*6a54128fSAndroid Build Coastguard Worker retval = errno;
981*6a54128fSAndroid Build Coastguard Worker free_cache(data);
982*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_PTHREAD
983*6a54128fSAndroid Build Coastguard Worker if (data->flags & IO_FLAG_THREADS) {
984*6a54128fSAndroid Build Coastguard Worker pthread_mutex_destroy(&data->cache_mutex);
985*6a54128fSAndroid Build Coastguard Worker pthread_mutex_destroy(&data->bounce_mutex);
986*6a54128fSAndroid Build Coastguard Worker pthread_mutex_destroy(&data->stats_mutex);
987*6a54128fSAndroid Build Coastguard Worker }
988*6a54128fSAndroid Build Coastguard Worker #endif
989*6a54128fSAndroid Build Coastguard Worker
990*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&channel->private_data);
991*6a54128fSAndroid Build Coastguard Worker if (channel->name)
992*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&channel->name);
993*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&channel);
994*6a54128fSAndroid Build Coastguard Worker return retval;
995*6a54128fSAndroid Build Coastguard Worker }
996*6a54128fSAndroid Build Coastguard Worker
unix_set_blksize(io_channel channel,int blksize)997*6a54128fSAndroid Build Coastguard Worker static errcode_t unix_set_blksize(io_channel channel, int blksize)
998*6a54128fSAndroid Build Coastguard Worker {
999*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data;
1000*6a54128fSAndroid Build Coastguard Worker errcode_t retval = 0;
1001*6a54128fSAndroid Build Coastguard Worker
1002*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1003*6a54128fSAndroid Build Coastguard Worker data = (struct unix_private_data *) channel->private_data;
1004*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1005*6a54128fSAndroid Build Coastguard Worker
1006*6a54128fSAndroid Build Coastguard Worker if (channel->block_size != blksize) {
1007*6a54128fSAndroid Build Coastguard Worker mutex_lock(data, CACHE_MTX);
1008*6a54128fSAndroid Build Coastguard Worker mutex_lock(data, BOUNCE_MTX);
1009*6a54128fSAndroid Build Coastguard Worker #ifndef NO_IO_CACHE
1010*6a54128fSAndroid Build Coastguard Worker if ((retval = flush_cached_blocks(channel, data, FLUSH_NOLOCK))){
1011*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, BOUNCE_MTX);
1012*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, CACHE_MTX);
1013*6a54128fSAndroid Build Coastguard Worker return retval;
1014*6a54128fSAndroid Build Coastguard Worker }
1015*6a54128fSAndroid Build Coastguard Worker #endif
1016*6a54128fSAndroid Build Coastguard Worker
1017*6a54128fSAndroid Build Coastguard Worker channel->block_size = blksize;
1018*6a54128fSAndroid Build Coastguard Worker free_cache(data);
1019*6a54128fSAndroid Build Coastguard Worker retval = alloc_cache(channel, data);
1020*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, BOUNCE_MTX);
1021*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, CACHE_MTX);
1022*6a54128fSAndroid Build Coastguard Worker }
1023*6a54128fSAndroid Build Coastguard Worker return retval;
1024*6a54128fSAndroid Build Coastguard Worker }
1025*6a54128fSAndroid Build Coastguard Worker
unix_read_blk64(io_channel channel,unsigned long long block,int count,void * buf)1026*6a54128fSAndroid Build Coastguard Worker static errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
1027*6a54128fSAndroid Build Coastguard Worker int count, void *buf)
1028*6a54128fSAndroid Build Coastguard Worker {
1029*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data;
1030*6a54128fSAndroid Build Coastguard Worker struct unix_cache *cache;
1031*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
1032*6a54128fSAndroid Build Coastguard Worker char *cp;
1033*6a54128fSAndroid Build Coastguard Worker int i, j;
1034*6a54128fSAndroid Build Coastguard Worker
1035*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1036*6a54128fSAndroid Build Coastguard Worker data = (struct unix_private_data *) channel->private_data;
1037*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1038*6a54128fSAndroid Build Coastguard Worker
1039*6a54128fSAndroid Build Coastguard Worker #ifdef NO_IO_CACHE
1040*6a54128fSAndroid Build Coastguard Worker return raw_read_blk(channel, data, block, count, buf);
1041*6a54128fSAndroid Build Coastguard Worker #else
1042*6a54128fSAndroid Build Coastguard Worker if (data->flags & IO_FLAG_NOCACHE)
1043*6a54128fSAndroid Build Coastguard Worker return raw_read_blk(channel, data, block, count, buf);
1044*6a54128fSAndroid Build Coastguard Worker /*
1045*6a54128fSAndroid Build Coastguard Worker * If we're doing an odd-sized read or a very large read,
1046*6a54128fSAndroid Build Coastguard Worker * flush out the cache and then do a direct read.
1047*6a54128fSAndroid Build Coastguard Worker */
1048*6a54128fSAndroid Build Coastguard Worker if (count < 0 || count > WRITE_DIRECT_SIZE) {
1049*6a54128fSAndroid Build Coastguard Worker if ((retval = flush_cached_blocks(channel, data, 0)))
1050*6a54128fSAndroid Build Coastguard Worker return retval;
1051*6a54128fSAndroid Build Coastguard Worker return raw_read_blk(channel, data, block, count, buf);
1052*6a54128fSAndroid Build Coastguard Worker }
1053*6a54128fSAndroid Build Coastguard Worker
1054*6a54128fSAndroid Build Coastguard Worker cp = buf;
1055*6a54128fSAndroid Build Coastguard Worker mutex_lock(data, CACHE_MTX);
1056*6a54128fSAndroid Build Coastguard Worker while (count > 0) {
1057*6a54128fSAndroid Build Coastguard Worker /* If it's in the cache, use it! */
1058*6a54128fSAndroid Build Coastguard Worker if ((cache = find_cached_block(data, block, NULL))) {
1059*6a54128fSAndroid Build Coastguard Worker #ifdef DEBUG
1060*6a54128fSAndroid Build Coastguard Worker printf("Using cached block %lu\n", block);
1061*6a54128fSAndroid Build Coastguard Worker #endif
1062*6a54128fSAndroid Build Coastguard Worker memcpy(cp, cache->buf, channel->block_size);
1063*6a54128fSAndroid Build Coastguard Worker count--;
1064*6a54128fSAndroid Build Coastguard Worker block++;
1065*6a54128fSAndroid Build Coastguard Worker cp += channel->block_size;
1066*6a54128fSAndroid Build Coastguard Worker continue;
1067*6a54128fSAndroid Build Coastguard Worker }
1068*6a54128fSAndroid Build Coastguard Worker
1069*6a54128fSAndroid Build Coastguard Worker /*
1070*6a54128fSAndroid Build Coastguard Worker * Find the number of uncached blocks so we can do a
1071*6a54128fSAndroid Build Coastguard Worker * single read request
1072*6a54128fSAndroid Build Coastguard Worker */
1073*6a54128fSAndroid Build Coastguard Worker for (i=1; i < count; i++)
1074*6a54128fSAndroid Build Coastguard Worker if (find_cached_block(data, block+i, NULL))
1075*6a54128fSAndroid Build Coastguard Worker break;
1076*6a54128fSAndroid Build Coastguard Worker #ifdef DEBUG
1077*6a54128fSAndroid Build Coastguard Worker printf("Reading %d blocks starting at %lu\n", i, block);
1078*6a54128fSAndroid Build Coastguard Worker #endif
1079*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, CACHE_MTX);
1080*6a54128fSAndroid Build Coastguard Worker if ((retval = raw_read_blk(channel, data, block, i, cp)))
1081*6a54128fSAndroid Build Coastguard Worker return retval;
1082*6a54128fSAndroid Build Coastguard Worker mutex_lock(data, CACHE_MTX);
1083*6a54128fSAndroid Build Coastguard Worker
1084*6a54128fSAndroid Build Coastguard Worker /* Save the results in the cache */
1085*6a54128fSAndroid Build Coastguard Worker for (j=0; j < i; j++) {
1086*6a54128fSAndroid Build Coastguard Worker if (!find_cached_block(data, block, &cache)) {
1087*6a54128fSAndroid Build Coastguard Worker retval = reuse_cache(channel, data,
1088*6a54128fSAndroid Build Coastguard Worker cache, block);
1089*6a54128fSAndroid Build Coastguard Worker if (retval)
1090*6a54128fSAndroid Build Coastguard Worker goto call_write_handler;
1091*6a54128fSAndroid Build Coastguard Worker memcpy(cache->buf, cp, channel->block_size);
1092*6a54128fSAndroid Build Coastguard Worker }
1093*6a54128fSAndroid Build Coastguard Worker count--;
1094*6a54128fSAndroid Build Coastguard Worker block++;
1095*6a54128fSAndroid Build Coastguard Worker cp += channel->block_size;
1096*6a54128fSAndroid Build Coastguard Worker }
1097*6a54128fSAndroid Build Coastguard Worker }
1098*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, CACHE_MTX);
1099*6a54128fSAndroid Build Coastguard Worker return 0;
1100*6a54128fSAndroid Build Coastguard Worker
1101*6a54128fSAndroid Build Coastguard Worker call_write_handler:
1102*6a54128fSAndroid Build Coastguard Worker if (cache->write_err && channel->write_error) {
1103*6a54128fSAndroid Build Coastguard Worker char *err_buf = NULL;
1104*6a54128fSAndroid Build Coastguard Worker unsigned long long err_block = cache->block;
1105*6a54128fSAndroid Build Coastguard Worker
1106*6a54128fSAndroid Build Coastguard Worker cache->dirty = 0;
1107*6a54128fSAndroid Build Coastguard Worker cache->in_use = 0;
1108*6a54128fSAndroid Build Coastguard Worker cache->write_err = 0;
1109*6a54128fSAndroid Build Coastguard Worker if (io_channel_alloc_buf(channel, 0, &err_buf))
1110*6a54128fSAndroid Build Coastguard Worker err_buf = NULL;
1111*6a54128fSAndroid Build Coastguard Worker else
1112*6a54128fSAndroid Build Coastguard Worker memcpy(err_buf, cache->buf, channel->block_size);
1113*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, CACHE_MTX);
1114*6a54128fSAndroid Build Coastguard Worker (channel->write_error)(channel, err_block, 1, err_buf,
1115*6a54128fSAndroid Build Coastguard Worker channel->block_size, -1,
1116*6a54128fSAndroid Build Coastguard Worker retval);
1117*6a54128fSAndroid Build Coastguard Worker if (err_buf)
1118*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&err_buf);
1119*6a54128fSAndroid Build Coastguard Worker } else
1120*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, CACHE_MTX);
1121*6a54128fSAndroid Build Coastguard Worker return retval;
1122*6a54128fSAndroid Build Coastguard Worker #endif /* NO_IO_CACHE */
1123*6a54128fSAndroid Build Coastguard Worker }
1124*6a54128fSAndroid Build Coastguard Worker
unix_read_blk(io_channel channel,unsigned long block,int count,void * buf)1125*6a54128fSAndroid Build Coastguard Worker static errcode_t unix_read_blk(io_channel channel, unsigned long block,
1126*6a54128fSAndroid Build Coastguard Worker int count, void *buf)
1127*6a54128fSAndroid Build Coastguard Worker {
1128*6a54128fSAndroid Build Coastguard Worker return unix_read_blk64(channel, block, count, buf);
1129*6a54128fSAndroid Build Coastguard Worker }
1130*6a54128fSAndroid Build Coastguard Worker
unix_write_blk64(io_channel channel,unsigned long long block,int count,const void * buf)1131*6a54128fSAndroid Build Coastguard Worker static errcode_t unix_write_blk64(io_channel channel, unsigned long long block,
1132*6a54128fSAndroid Build Coastguard Worker int count, const void *buf)
1133*6a54128fSAndroid Build Coastguard Worker {
1134*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data;
1135*6a54128fSAndroid Build Coastguard Worker struct unix_cache *cache, *reuse;
1136*6a54128fSAndroid Build Coastguard Worker errcode_t retval = 0;
1137*6a54128fSAndroid Build Coastguard Worker const char *cp;
1138*6a54128fSAndroid Build Coastguard Worker int writethrough;
1139*6a54128fSAndroid Build Coastguard Worker
1140*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1141*6a54128fSAndroid Build Coastguard Worker data = (struct unix_private_data *) channel->private_data;
1142*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1143*6a54128fSAndroid Build Coastguard Worker
1144*6a54128fSAndroid Build Coastguard Worker #ifdef NO_IO_CACHE
1145*6a54128fSAndroid Build Coastguard Worker return raw_write_blk(channel, data, block, count, buf, 0);
1146*6a54128fSAndroid Build Coastguard Worker #else
1147*6a54128fSAndroid Build Coastguard Worker if (data->flags & IO_FLAG_NOCACHE)
1148*6a54128fSAndroid Build Coastguard Worker return raw_write_blk(channel, data, block, count, buf, 0);
1149*6a54128fSAndroid Build Coastguard Worker /*
1150*6a54128fSAndroid Build Coastguard Worker * If we're doing an odd-sized write or a very large write,
1151*6a54128fSAndroid Build Coastguard Worker * flush out the cache completely and then do a direct write.
1152*6a54128fSAndroid Build Coastguard Worker */
1153*6a54128fSAndroid Build Coastguard Worker if (count < 0 || count > WRITE_DIRECT_SIZE) {
1154*6a54128fSAndroid Build Coastguard Worker if ((retval = flush_cached_blocks(channel, data,
1155*6a54128fSAndroid Build Coastguard Worker FLUSH_INVALIDATE)))
1156*6a54128fSAndroid Build Coastguard Worker return retval;
1157*6a54128fSAndroid Build Coastguard Worker return raw_write_blk(channel, data, block, count, buf, 0);
1158*6a54128fSAndroid Build Coastguard Worker }
1159*6a54128fSAndroid Build Coastguard Worker
1160*6a54128fSAndroid Build Coastguard Worker /*
1161*6a54128fSAndroid Build Coastguard Worker * For a moderate-sized multi-block write, first force a write
1162*6a54128fSAndroid Build Coastguard Worker * if we're in write-through cache mode, and then fill the
1163*6a54128fSAndroid Build Coastguard Worker * cache with the blocks.
1164*6a54128fSAndroid Build Coastguard Worker */
1165*6a54128fSAndroid Build Coastguard Worker writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
1166*6a54128fSAndroid Build Coastguard Worker if (writethrough)
1167*6a54128fSAndroid Build Coastguard Worker retval = raw_write_blk(channel, data, block, count, buf, 0);
1168*6a54128fSAndroid Build Coastguard Worker
1169*6a54128fSAndroid Build Coastguard Worker cp = buf;
1170*6a54128fSAndroid Build Coastguard Worker mutex_lock(data, CACHE_MTX);
1171*6a54128fSAndroid Build Coastguard Worker while (count > 0) {
1172*6a54128fSAndroid Build Coastguard Worker cache = find_cached_block(data, block, &reuse);
1173*6a54128fSAndroid Build Coastguard Worker if (!cache) {
1174*6a54128fSAndroid Build Coastguard Worker errcode_t err;
1175*6a54128fSAndroid Build Coastguard Worker
1176*6a54128fSAndroid Build Coastguard Worker cache = reuse;
1177*6a54128fSAndroid Build Coastguard Worker err = reuse_cache(channel, data, cache, block);
1178*6a54128fSAndroid Build Coastguard Worker if (err)
1179*6a54128fSAndroid Build Coastguard Worker goto call_write_handler;
1180*6a54128fSAndroid Build Coastguard Worker }
1181*6a54128fSAndroid Build Coastguard Worker if (cache->buf != cp)
1182*6a54128fSAndroid Build Coastguard Worker memcpy(cache->buf, cp, channel->block_size);
1183*6a54128fSAndroid Build Coastguard Worker cache->dirty = !writethrough;
1184*6a54128fSAndroid Build Coastguard Worker count--;
1185*6a54128fSAndroid Build Coastguard Worker block++;
1186*6a54128fSAndroid Build Coastguard Worker cp += channel->block_size;
1187*6a54128fSAndroid Build Coastguard Worker }
1188*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, CACHE_MTX);
1189*6a54128fSAndroid Build Coastguard Worker return retval;
1190*6a54128fSAndroid Build Coastguard Worker
1191*6a54128fSAndroid Build Coastguard Worker call_write_handler:
1192*6a54128fSAndroid Build Coastguard Worker if (cache->write_err && channel->write_error) {
1193*6a54128fSAndroid Build Coastguard Worker char *err_buf = NULL;
1194*6a54128fSAndroid Build Coastguard Worker unsigned long long err_block = cache->block;
1195*6a54128fSAndroid Build Coastguard Worker
1196*6a54128fSAndroid Build Coastguard Worker cache->dirty = 0;
1197*6a54128fSAndroid Build Coastguard Worker cache->in_use = 0;
1198*6a54128fSAndroid Build Coastguard Worker cache->write_err = 0;
1199*6a54128fSAndroid Build Coastguard Worker if (io_channel_alloc_buf(channel, 0, &err_buf))
1200*6a54128fSAndroid Build Coastguard Worker err_buf = NULL;
1201*6a54128fSAndroid Build Coastguard Worker else
1202*6a54128fSAndroid Build Coastguard Worker memcpy(err_buf, cache->buf, channel->block_size);
1203*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, CACHE_MTX);
1204*6a54128fSAndroid Build Coastguard Worker (channel->write_error)(channel, err_block, 1, err_buf,
1205*6a54128fSAndroid Build Coastguard Worker channel->block_size, -1,
1206*6a54128fSAndroid Build Coastguard Worker retval);
1207*6a54128fSAndroid Build Coastguard Worker if (err_buf)
1208*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&err_buf);
1209*6a54128fSAndroid Build Coastguard Worker } else
1210*6a54128fSAndroid Build Coastguard Worker mutex_unlock(data, CACHE_MTX);
1211*6a54128fSAndroid Build Coastguard Worker return retval;
1212*6a54128fSAndroid Build Coastguard Worker #endif /* NO_IO_CACHE */
1213*6a54128fSAndroid Build Coastguard Worker }
1214*6a54128fSAndroid Build Coastguard Worker
unix_cache_readahead(io_channel channel,unsigned long long block,unsigned long long count)1215*6a54128fSAndroid Build Coastguard Worker static errcode_t unix_cache_readahead(io_channel channel,
1216*6a54128fSAndroid Build Coastguard Worker unsigned long long block,
1217*6a54128fSAndroid Build Coastguard Worker unsigned long long count)
1218*6a54128fSAndroid Build Coastguard Worker {
1219*6a54128fSAndroid Build Coastguard Worker #ifdef POSIX_FADV_WILLNEED
1220*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data;
1221*6a54128fSAndroid Build Coastguard Worker
1222*6a54128fSAndroid Build Coastguard Worker data = (struct unix_private_data *)channel->private_data;
1223*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1224*6a54128fSAndroid Build Coastguard Worker return posix_fadvise(data->dev,
1225*6a54128fSAndroid Build Coastguard Worker (ext2_loff_t)block * channel->block_size + data->offset,
1226*6a54128fSAndroid Build Coastguard Worker (ext2_loff_t)count * channel->block_size,
1227*6a54128fSAndroid Build Coastguard Worker POSIX_FADV_WILLNEED);
1228*6a54128fSAndroid Build Coastguard Worker #else
1229*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_OP_NOT_SUPPORTED;
1230*6a54128fSAndroid Build Coastguard Worker #endif
1231*6a54128fSAndroid Build Coastguard Worker }
1232*6a54128fSAndroid Build Coastguard Worker
unix_write_blk(io_channel channel,unsigned long block,int count,const void * buf)1233*6a54128fSAndroid Build Coastguard Worker static errcode_t unix_write_blk(io_channel channel, unsigned long block,
1234*6a54128fSAndroid Build Coastguard Worker int count, const void *buf)
1235*6a54128fSAndroid Build Coastguard Worker {
1236*6a54128fSAndroid Build Coastguard Worker return unix_write_blk64(channel, block, count, buf);
1237*6a54128fSAndroid Build Coastguard Worker }
1238*6a54128fSAndroid Build Coastguard Worker
unix_write_byte(io_channel channel,unsigned long offset,int size,const void * buf)1239*6a54128fSAndroid Build Coastguard Worker static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
1240*6a54128fSAndroid Build Coastguard Worker int size, const void *buf)
1241*6a54128fSAndroid Build Coastguard Worker {
1242*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data;
1243*6a54128fSAndroid Build Coastguard Worker errcode_t retval = 0;
1244*6a54128fSAndroid Build Coastguard Worker ssize_t actual;
1245*6a54128fSAndroid Build Coastguard Worker
1246*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1247*6a54128fSAndroid Build Coastguard Worker data = (struct unix_private_data *) channel->private_data;
1248*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1249*6a54128fSAndroid Build Coastguard Worker
1250*6a54128fSAndroid Build Coastguard Worker if (channel->align != 0) {
1251*6a54128fSAndroid Build Coastguard Worker #ifdef ALIGN_DEBUG
1252*6a54128fSAndroid Build Coastguard Worker printf("unix_write_byte: O_DIRECT fallback\n");
1253*6a54128fSAndroid Build Coastguard Worker #endif
1254*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_UNIMPLEMENTED;
1255*6a54128fSAndroid Build Coastguard Worker }
1256*6a54128fSAndroid Build Coastguard Worker
1257*6a54128fSAndroid Build Coastguard Worker #ifndef NO_IO_CACHE
1258*6a54128fSAndroid Build Coastguard Worker /*
1259*6a54128fSAndroid Build Coastguard Worker * Flush out the cache completely
1260*6a54128fSAndroid Build Coastguard Worker */
1261*6a54128fSAndroid Build Coastguard Worker if ((retval = flush_cached_blocks(channel, data, FLUSH_INVALIDATE)))
1262*6a54128fSAndroid Build Coastguard Worker return retval;
1263*6a54128fSAndroid Build Coastguard Worker #endif
1264*6a54128fSAndroid Build Coastguard Worker
1265*6a54128fSAndroid Build Coastguard Worker if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0)
1266*6a54128fSAndroid Build Coastguard Worker return errno;
1267*6a54128fSAndroid Build Coastguard Worker
1268*6a54128fSAndroid Build Coastguard Worker actual = write(data->dev, buf, size);
1269*6a54128fSAndroid Build Coastguard Worker if (actual < 0)
1270*6a54128fSAndroid Build Coastguard Worker return errno;
1271*6a54128fSAndroid Build Coastguard Worker if (actual != size)
1272*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_SHORT_WRITE;
1273*6a54128fSAndroid Build Coastguard Worker
1274*6a54128fSAndroid Build Coastguard Worker return 0;
1275*6a54128fSAndroid Build Coastguard Worker }
1276*6a54128fSAndroid Build Coastguard Worker
1277*6a54128fSAndroid Build Coastguard Worker /*
1278*6a54128fSAndroid Build Coastguard Worker * Flush data buffers to disk.
1279*6a54128fSAndroid Build Coastguard Worker */
unix_flush(io_channel channel)1280*6a54128fSAndroid Build Coastguard Worker static errcode_t unix_flush(io_channel channel)
1281*6a54128fSAndroid Build Coastguard Worker {
1282*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data;
1283*6a54128fSAndroid Build Coastguard Worker errcode_t retval = 0;
1284*6a54128fSAndroid Build Coastguard Worker
1285*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1286*6a54128fSAndroid Build Coastguard Worker data = (struct unix_private_data *) channel->private_data;
1287*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1288*6a54128fSAndroid Build Coastguard Worker
1289*6a54128fSAndroid Build Coastguard Worker #ifndef NO_IO_CACHE
1290*6a54128fSAndroid Build Coastguard Worker retval = flush_cached_blocks(channel, data, 0);
1291*6a54128fSAndroid Build Coastguard Worker #endif
1292*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_FSYNC
1293*6a54128fSAndroid Build Coastguard Worker if (!retval && fsync(data->dev) != 0)
1294*6a54128fSAndroid Build Coastguard Worker return errno;
1295*6a54128fSAndroid Build Coastguard Worker #endif
1296*6a54128fSAndroid Build Coastguard Worker return retval;
1297*6a54128fSAndroid Build Coastguard Worker }
1298*6a54128fSAndroid Build Coastguard Worker
unix_set_option(io_channel channel,const char * option,const char * arg)1299*6a54128fSAndroid Build Coastguard Worker static errcode_t unix_set_option(io_channel channel, const char *option,
1300*6a54128fSAndroid Build Coastguard Worker const char *arg)
1301*6a54128fSAndroid Build Coastguard Worker {
1302*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data;
1303*6a54128fSAndroid Build Coastguard Worker unsigned long long tmp;
1304*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
1305*6a54128fSAndroid Build Coastguard Worker char *end;
1306*6a54128fSAndroid Build Coastguard Worker
1307*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1308*6a54128fSAndroid Build Coastguard Worker data = (struct unix_private_data *) channel->private_data;
1309*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1310*6a54128fSAndroid Build Coastguard Worker
1311*6a54128fSAndroid Build Coastguard Worker if (!strcmp(option, "offset")) {
1312*6a54128fSAndroid Build Coastguard Worker if (!arg)
1313*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_INVALID_ARGUMENT;
1314*6a54128fSAndroid Build Coastguard Worker
1315*6a54128fSAndroid Build Coastguard Worker tmp = strtoull(arg, &end, 0);
1316*6a54128fSAndroid Build Coastguard Worker if (*end)
1317*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_INVALID_ARGUMENT;
1318*6a54128fSAndroid Build Coastguard Worker data->offset = tmp;
1319*6a54128fSAndroid Build Coastguard Worker if (data->offset < 0)
1320*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_INVALID_ARGUMENT;
1321*6a54128fSAndroid Build Coastguard Worker return 0;
1322*6a54128fSAndroid Build Coastguard Worker }
1323*6a54128fSAndroid Build Coastguard Worker if (!strcmp(option, "cache")) {
1324*6a54128fSAndroid Build Coastguard Worker if (!arg)
1325*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_INVALID_ARGUMENT;
1326*6a54128fSAndroid Build Coastguard Worker if (!strcmp(arg, "on")) {
1327*6a54128fSAndroid Build Coastguard Worker data->flags &= ~IO_FLAG_NOCACHE;
1328*6a54128fSAndroid Build Coastguard Worker return 0;
1329*6a54128fSAndroid Build Coastguard Worker }
1330*6a54128fSAndroid Build Coastguard Worker if (!strcmp(arg, "off")) {
1331*6a54128fSAndroid Build Coastguard Worker retval = flush_cached_blocks(channel, data, 0);
1332*6a54128fSAndroid Build Coastguard Worker data->flags |= IO_FLAG_NOCACHE;
1333*6a54128fSAndroid Build Coastguard Worker return retval;
1334*6a54128fSAndroid Build Coastguard Worker }
1335*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_INVALID_ARGUMENT;
1336*6a54128fSAndroid Build Coastguard Worker }
1337*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_INVALID_ARGUMENT;
1338*6a54128fSAndroid Build Coastguard Worker }
1339*6a54128fSAndroid Build Coastguard Worker
1340*6a54128fSAndroid Build Coastguard Worker #if defined(__linux__) && !defined(BLKDISCARD)
1341*6a54128fSAndroid Build Coastguard Worker #define BLKDISCARD _IO(0x12,119)
1342*6a54128fSAndroid Build Coastguard Worker #endif
1343*6a54128fSAndroid Build Coastguard Worker
unix_discard(io_channel channel,unsigned long long block,unsigned long long count)1344*6a54128fSAndroid Build Coastguard Worker static errcode_t unix_discard(io_channel channel, unsigned long long block,
1345*6a54128fSAndroid Build Coastguard Worker unsigned long long count)
1346*6a54128fSAndroid Build Coastguard Worker {
1347*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data;
1348*6a54128fSAndroid Build Coastguard Worker int ret;
1349*6a54128fSAndroid Build Coastguard Worker
1350*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1351*6a54128fSAndroid Build Coastguard Worker data = (struct unix_private_data *) channel->private_data;
1352*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1353*6a54128fSAndroid Build Coastguard Worker
1354*6a54128fSAndroid Build Coastguard Worker if (channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE) {
1355*6a54128fSAndroid Build Coastguard Worker #ifdef BLKDISCARD
1356*6a54128fSAndroid Build Coastguard Worker __u64 range[2];
1357*6a54128fSAndroid Build Coastguard Worker
1358*6a54128fSAndroid Build Coastguard Worker range[0] = (__u64)(block) * channel->block_size + data->offset;
1359*6a54128fSAndroid Build Coastguard Worker range[1] = (__u64)(count) * channel->block_size;
1360*6a54128fSAndroid Build Coastguard Worker
1361*6a54128fSAndroid Build Coastguard Worker ret = ioctl(data->dev, BLKDISCARD, &range);
1362*6a54128fSAndroid Build Coastguard Worker #else
1363*6a54128fSAndroid Build Coastguard Worker goto unimplemented;
1364*6a54128fSAndroid Build Coastguard Worker #endif
1365*6a54128fSAndroid Build Coastguard Worker } else {
1366*6a54128fSAndroid Build Coastguard Worker #if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE)
1367*6a54128fSAndroid Build Coastguard Worker /*
1368*6a54128fSAndroid Build Coastguard Worker * If we are not on block device, try to use punch hole
1369*6a54128fSAndroid Build Coastguard Worker * to reclaim free space.
1370*6a54128fSAndroid Build Coastguard Worker */
1371*6a54128fSAndroid Build Coastguard Worker ret = fallocate(data->dev,
1372*6a54128fSAndroid Build Coastguard Worker FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
1373*6a54128fSAndroid Build Coastguard Worker (off_t)(block) * channel->block_size + data->offset,
1374*6a54128fSAndroid Build Coastguard Worker (off_t)(count) * channel->block_size);
1375*6a54128fSAndroid Build Coastguard Worker #else
1376*6a54128fSAndroid Build Coastguard Worker goto unimplemented;
1377*6a54128fSAndroid Build Coastguard Worker #endif
1378*6a54128fSAndroid Build Coastguard Worker }
1379*6a54128fSAndroid Build Coastguard Worker if (ret < 0) {
1380*6a54128fSAndroid Build Coastguard Worker if (errno == EOPNOTSUPP)
1381*6a54128fSAndroid Build Coastguard Worker goto unimplemented;
1382*6a54128fSAndroid Build Coastguard Worker return errno;
1383*6a54128fSAndroid Build Coastguard Worker }
1384*6a54128fSAndroid Build Coastguard Worker return 0;
1385*6a54128fSAndroid Build Coastguard Worker unimplemented:
1386*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_UNIMPLEMENTED;
1387*6a54128fSAndroid Build Coastguard Worker }
1388*6a54128fSAndroid Build Coastguard Worker
1389*6a54128fSAndroid Build Coastguard Worker /*
1390*6a54128fSAndroid Build Coastguard Worker * If we know about ZERO_RANGE, try that before we try PUNCH_HOLE because
1391*6a54128fSAndroid Build Coastguard Worker * ZERO_RANGE doesn't unmap preallocated blocks. We prefer fallocate because
1392*6a54128fSAndroid Build Coastguard Worker * it always invalidates page cache, and libext2fs requires that reads after
1393*6a54128fSAndroid Build Coastguard Worker * ZERO_RANGE return zeroes.
1394*6a54128fSAndroid Build Coastguard Worker */
__unix_zeroout(int fd,off_t offset,off_t len)1395*6a54128fSAndroid Build Coastguard Worker static int __unix_zeroout(int fd, off_t offset, off_t len)
1396*6a54128fSAndroid Build Coastguard Worker {
1397*6a54128fSAndroid Build Coastguard Worker int ret = -1;
1398*6a54128fSAndroid Build Coastguard Worker
1399*6a54128fSAndroid Build Coastguard Worker #if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_ZERO_RANGE)
1400*6a54128fSAndroid Build Coastguard Worker ret = fallocate(fd, FALLOC_FL_ZERO_RANGE, offset, len);
1401*6a54128fSAndroid Build Coastguard Worker if (ret == 0)
1402*6a54128fSAndroid Build Coastguard Worker return 0;
1403*6a54128fSAndroid Build Coastguard Worker #endif
1404*6a54128fSAndroid Build Coastguard Worker #if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE)
1405*6a54128fSAndroid Build Coastguard Worker ret = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
1406*6a54128fSAndroid Build Coastguard Worker offset, len);
1407*6a54128fSAndroid Build Coastguard Worker if (ret == 0)
1408*6a54128fSAndroid Build Coastguard Worker return 0;
1409*6a54128fSAndroid Build Coastguard Worker #endif
1410*6a54128fSAndroid Build Coastguard Worker errno = EOPNOTSUPP;
1411*6a54128fSAndroid Build Coastguard Worker return ret;
1412*6a54128fSAndroid Build Coastguard Worker }
1413*6a54128fSAndroid Build Coastguard Worker
1414*6a54128fSAndroid Build Coastguard Worker /* parameters might not be used if OS doesn't support zeroout */
1415*6a54128fSAndroid Build Coastguard Worker #if __GNUC_PREREQ (4, 6)
1416*6a54128fSAndroid Build Coastguard Worker #pragma GCC diagnostic push
1417*6a54128fSAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wunused-parameter"
1418*6a54128fSAndroid Build Coastguard Worker #endif
unix_zeroout(io_channel channel,unsigned long long block,unsigned long long count)1419*6a54128fSAndroid Build Coastguard Worker static errcode_t unix_zeroout(io_channel channel, unsigned long long block,
1420*6a54128fSAndroid Build Coastguard Worker unsigned long long count)
1421*6a54128fSAndroid Build Coastguard Worker {
1422*6a54128fSAndroid Build Coastguard Worker struct unix_private_data *data;
1423*6a54128fSAndroid Build Coastguard Worker int ret;
1424*6a54128fSAndroid Build Coastguard Worker
1425*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1426*6a54128fSAndroid Build Coastguard Worker data = (struct unix_private_data *) channel->private_data;
1427*6a54128fSAndroid Build Coastguard Worker EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1428*6a54128fSAndroid Build Coastguard Worker
1429*6a54128fSAndroid Build Coastguard Worker if (safe_getenv("UNIX_IO_NOZEROOUT"))
1430*6a54128fSAndroid Build Coastguard Worker goto unimplemented;
1431*6a54128fSAndroid Build Coastguard Worker
1432*6a54128fSAndroid Build Coastguard Worker if (!(channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE)) {
1433*6a54128fSAndroid Build Coastguard Worker /* Regular file, try to use truncate/punch/zero. */
1434*6a54128fSAndroid Build Coastguard Worker struct stat statbuf;
1435*6a54128fSAndroid Build Coastguard Worker
1436*6a54128fSAndroid Build Coastguard Worker if (count == 0)
1437*6a54128fSAndroid Build Coastguard Worker return 0;
1438*6a54128fSAndroid Build Coastguard Worker /*
1439*6a54128fSAndroid Build Coastguard Worker * If we're trying to zero a range past the end of the file,
1440*6a54128fSAndroid Build Coastguard Worker * extend the file size, then truncate everything.
1441*6a54128fSAndroid Build Coastguard Worker */
1442*6a54128fSAndroid Build Coastguard Worker ret = fstat(data->dev, &statbuf);
1443*6a54128fSAndroid Build Coastguard Worker if (ret)
1444*6a54128fSAndroid Build Coastguard Worker goto err;
1445*6a54128fSAndroid Build Coastguard Worker if ((unsigned long long) statbuf.st_size <
1446*6a54128fSAndroid Build Coastguard Worker (block + count) * channel->block_size + data->offset) {
1447*6a54128fSAndroid Build Coastguard Worker ret = ftruncate(data->dev,
1448*6a54128fSAndroid Build Coastguard Worker (block + count) * channel->block_size + data->offset);
1449*6a54128fSAndroid Build Coastguard Worker if (ret)
1450*6a54128fSAndroid Build Coastguard Worker goto err;
1451*6a54128fSAndroid Build Coastguard Worker }
1452*6a54128fSAndroid Build Coastguard Worker }
1453*6a54128fSAndroid Build Coastguard Worker
1454*6a54128fSAndroid Build Coastguard Worker ret = __unix_zeroout(data->dev,
1455*6a54128fSAndroid Build Coastguard Worker (off_t)(block) * channel->block_size + data->offset,
1456*6a54128fSAndroid Build Coastguard Worker (off_t)(count) * channel->block_size);
1457*6a54128fSAndroid Build Coastguard Worker err:
1458*6a54128fSAndroid Build Coastguard Worker if (ret < 0) {
1459*6a54128fSAndroid Build Coastguard Worker if (errno == EOPNOTSUPP)
1460*6a54128fSAndroid Build Coastguard Worker goto unimplemented;
1461*6a54128fSAndroid Build Coastguard Worker return errno;
1462*6a54128fSAndroid Build Coastguard Worker }
1463*6a54128fSAndroid Build Coastguard Worker return 0;
1464*6a54128fSAndroid Build Coastguard Worker unimplemented:
1465*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_UNIMPLEMENTED;
1466*6a54128fSAndroid Build Coastguard Worker }
1467*6a54128fSAndroid Build Coastguard Worker #if __GNUC_PREREQ (4, 6)
1468*6a54128fSAndroid Build Coastguard Worker #pragma GCC diagnostic pop
1469*6a54128fSAndroid Build Coastguard Worker #endif
1470*6a54128fSAndroid Build Coastguard Worker
1471*6a54128fSAndroid Build Coastguard Worker static struct struct_io_manager struct_unix_manager = {
1472*6a54128fSAndroid Build Coastguard Worker .magic = EXT2_ET_MAGIC_IO_MANAGER,
1473*6a54128fSAndroid Build Coastguard Worker .name = "Unix I/O Manager",
1474*6a54128fSAndroid Build Coastguard Worker .open = unix_open,
1475*6a54128fSAndroid Build Coastguard Worker .close = unix_close,
1476*6a54128fSAndroid Build Coastguard Worker .set_blksize = unix_set_blksize,
1477*6a54128fSAndroid Build Coastguard Worker .read_blk = unix_read_blk,
1478*6a54128fSAndroid Build Coastguard Worker .write_blk = unix_write_blk,
1479*6a54128fSAndroid Build Coastguard Worker .flush = unix_flush,
1480*6a54128fSAndroid Build Coastguard Worker .write_byte = unix_write_byte,
1481*6a54128fSAndroid Build Coastguard Worker .set_option = unix_set_option,
1482*6a54128fSAndroid Build Coastguard Worker .get_stats = unix_get_stats,
1483*6a54128fSAndroid Build Coastguard Worker .read_blk64 = unix_read_blk64,
1484*6a54128fSAndroid Build Coastguard Worker .write_blk64 = unix_write_blk64,
1485*6a54128fSAndroid Build Coastguard Worker .discard = unix_discard,
1486*6a54128fSAndroid Build Coastguard Worker .cache_readahead = unix_cache_readahead,
1487*6a54128fSAndroid Build Coastguard Worker .zeroout = unix_zeroout,
1488*6a54128fSAndroid Build Coastguard Worker };
1489*6a54128fSAndroid Build Coastguard Worker
1490*6a54128fSAndroid Build Coastguard Worker io_manager unix_io_manager = &struct_unix_manager;
1491*6a54128fSAndroid Build Coastguard Worker
1492*6a54128fSAndroid Build Coastguard Worker static struct struct_io_manager struct_unixfd_manager = {
1493*6a54128fSAndroid Build Coastguard Worker .magic = EXT2_ET_MAGIC_IO_MANAGER,
1494*6a54128fSAndroid Build Coastguard Worker .name = "Unix fd I/O Manager",
1495*6a54128fSAndroid Build Coastguard Worker .open = unixfd_open,
1496*6a54128fSAndroid Build Coastguard Worker .close = unix_close,
1497*6a54128fSAndroid Build Coastguard Worker .set_blksize = unix_set_blksize,
1498*6a54128fSAndroid Build Coastguard Worker .read_blk = unix_read_blk,
1499*6a54128fSAndroid Build Coastguard Worker .write_blk = unix_write_blk,
1500*6a54128fSAndroid Build Coastguard Worker .flush = unix_flush,
1501*6a54128fSAndroid Build Coastguard Worker .write_byte = unix_write_byte,
1502*6a54128fSAndroid Build Coastguard Worker .set_option = unix_set_option,
1503*6a54128fSAndroid Build Coastguard Worker .get_stats = unix_get_stats,
1504*6a54128fSAndroid Build Coastguard Worker .read_blk64 = unix_read_blk64,
1505*6a54128fSAndroid Build Coastguard Worker .write_blk64 = unix_write_blk64,
1506*6a54128fSAndroid Build Coastguard Worker .discard = unix_discard,
1507*6a54128fSAndroid Build Coastguard Worker .cache_readahead = unix_cache_readahead,
1508*6a54128fSAndroid Build Coastguard Worker .zeroout = unix_zeroout,
1509*6a54128fSAndroid Build Coastguard Worker };
1510*6a54128fSAndroid Build Coastguard Worker
1511*6a54128fSAndroid Build Coastguard Worker io_manager unixfd_io_manager = &struct_unixfd_manager;
1512