Coverage Report

Created: 2026-10-17 07:17

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