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