Coverage Report

Created: 2026-07-30 06:16

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
667
{
83
667
  int r = 32;
84
85
667
  if (!x)
86
0
    return 0;
87
667
  if (!(x & 0xffff0000u)) {
88
667
    x = (x & 0xffffu) << 16;
89
667
    r -= 16;
90
667
  }
91
667
  if (!(x & 0xff000000u)) {
92
667
    x = (x & 0xffffffu) << 8;
93
667
    r -= 8;
94
667
  }
95
667
  if (!(x & 0xf0000000u)) {
96
667
    x = (x & 0xfffffffu) << 4;
97
667
    r -= 4;
98
667
  }
99
667
  if (!(x & 0xc0000000u)) {
100
0
    x = (x & 0x3fffffffu) << 2;
101
0
    r -= 2;
102
0
  }
103
667
  if (!(x & 0x80000000u)) {
104
0
    r -= 1;
105
0
  }
106
667
  return r;
107
667
}
108
109
/* Get high bit set out of 32-bit argument, -1 if none set */
110
static inline int highbit32(uint32_t v)
111
667
{
112
667
  return find_last_bit_set(v) - 1;
113
667
}
114
115
/*
116
 * For checking structure magic numbers...
117
 */
118
119
#define EXT2_CHECK_MAGIC(struct, code) \
120
11.7M
    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
34.2k
#define DEFAULT_CACHE_SIZE 8
132
27.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
76.5k
{
166
76.5k
  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
76.5k
  return NULL;
177
76.5k
}
178
#endif
179
180
static inline void mutex_lock(struct unix_private_data *data, kind_t kind)
181
38.2k
{
182
38.2k
#ifdef HAVE_PTHREAD
183
38.2k
  pthread_mutex_t *mtx = get_mutex(data,kind);
184
185
38.2k
  if (mtx)
186
0
    pthread_mutex_lock(mtx);
187
38.2k
#endif
188
38.2k
}
189
190
static inline void mutex_unlock(struct unix_private_data *data, kind_t kind)
191
38.2k
{
192
38.2k
#ifdef HAVE_PTHREAD
193
38.2k
  pthread_mutex_t *mtx = get_mutex(data,kind);
194
195
38.2k
  if (mtx)
196
0
    pthread_mutex_unlock(mtx);
197
38.2k
#endif
198
38.2k
}
199
200
static errcode_t unix_get_stats(io_channel channel, io_stats *stats)
201
468
{
202
468
  errcode_t retval = 0;
203
204
468
  struct unix_private_data *data;
205
206
468
  EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
207
468
  data = (struct unix_private_data *) channel->private_data;
208
468
  EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
209
210
468
  if (stats) {
211
468
    mutex_lock(data, STATS_MTX);
212
468
    *stats = &data->io_stats;
213
468
    mutex_unlock(data, STATS_MTX);
214
468
  }
215
216
468
  return retval;
217
468
}
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
5.93k
{
227
5.93k
  errcode_t retval;
228
5.93k
  ssize_t   size;
229
5.93k
  ext2_loff_t location;
230
5.93k
  int   actual = 0;
231
5.93k
  unsigned char *buf = bufv;
232
5.93k
  ssize_t   really_read = 0;
233
5.93k
  unsigned long long aligned_blk;
234
5.93k
  int   align_size, offset;
235
236
5.93k
  size = (count < 0) ? -count : (ext2_loff_t) count * channel->block_size;
237
5.93k
  mutex_lock(data, STATS_MTX);
238
5.93k
  data->io_stats.bytes_read += size;
239
5.93k
  mutex_unlock(data, STATS_MTX);
240
5.93k
  location = ((ext2_loff_t) block * channel->block_size) + data->offset;
241
242
5.93k
  if (data->flags & IO_FLAG_FORCE_BOUNCE)
243
0
    goto bounce_read;
244
245
5.93k
#ifdef HAVE_PREAD64
246
  /* Try an aligned pread */
247
5.93k
  if ((channel->align == 0) ||
248
0
      (IS_ALIGNED(buf, channel->align) &&
249
0
       IS_ALIGNED(location, channel->align) &&
250
5.93k
       IS_ALIGNED(size, channel->align))) {
251
5.93k
    actual = pread64(data->dev, buf, size, location);
252
5.93k
    if (actual == size)
253
5.75k
      return 0;
254
180
    actual = 0;
255
180
  }
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
180
  if ((channel->align == 0) ||
271
0
      (IS_ALIGNED(buf, channel->align) &&
272
0
       IS_ALIGNED(location, channel->align) &&
273
180
       IS_ALIGNED(size, channel->align))) {
274
180
    mutex_lock(data, BOUNCE_MTX);
275
180
    if (ext2fs_llseek(data->dev, location, SEEK_SET) < 0) {
276
7
      retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
277
7
      goto error_unlock;
278
7
    }
279
173
    actual = read(data->dev, buf, size);
280
173
    if (actual != size) {
281
173
    short_read:
282
173
      if (actual < 0) {
283
0
        retval = errno;
284
0
        actual = 0;
285
0
      } else
286
173
        retval = EXT2_ET_SHORT_READ;
287
173
      goto error_unlock;
288
173
    }
289
0
    goto success_unlock;
290
173
  }
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
180
error_unlock:
342
180
  mutex_unlock(data, BOUNCE_MTX);
343
180
  if (actual >= 0 && actual < size)
344
180
    memset((char *) buf+actual, 0, size-actual);
345
180
  if (channel->read_error)
346
0
    retval = (channel->read_error)(channel, block, count, buf,
347
0
                 size, actual, retval);
348
180
  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
718
{
520
718
  errcode_t   retval;
521
718
  struct unix_cache *cache;
522
718
  unsigned int    i;
523
524
718
  data->access_time = 0;
525
6.46k
  for (i=0, cache = data->cache; i < data->cache_size; i++, cache++) {
526
5.74k
    cache->block = 0;
527
5.74k
    cache->access_time = 0;
528
5.74k
    cache->dirty = 0;
529
5.74k
    cache->in_use = 0;
530
5.74k
    if (cache->buf)
531
0
      ext2fs_free_mem(&cache->buf);
532
5.74k
    retval = io_channel_alloc_buf(channel, 0, &cache->buf);
533
5.74k
    if (retval)
534
0
      return retval;
535
5.74k
  }
536
718
  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
718
  return retval;
542
718
}
543
544
/* Free the cache buffers */
545
static void free_cache(struct unix_private_data *data)
546
718
{
547
718
  struct unix_cache *cache;
548
718
  unsigned int    i;
549
550
718
  data->access_time = 0;
551
6.46k
  for (i=0, cache = data->cache; i < data->cache_size; i++, cache++) {
552
5.74k
    cache->block = 0;
553
5.74k
    cache->access_time = 0;
554
5.74k
    cache->dirty = 0;
555
5.74k
    cache->in_use = 0;
556
5.74k
    if (cache->buf)
557
5.74k
      ext2fs_free_mem(&cache->buf);
558
5.74k
  }
559
718
  if (data->bounce)
560
0
    ext2fs_free_mem(&data->bounce);
561
718
}
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
32.9k
{
576
32.9k
  uint64_t  hashval = blkno;
577
32.9k
  uint64_t  tmp;
578
579
  /* the default cache size is small, just do a linear scan */
580
32.9k
  if (data->cache_size <= DEFAULT_CACHE_SIZE)
581
32.9k
    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
32.9k
}
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
32.9k
{
597
32.9k
  struct unix_cache *cache, *unused_cache, *oldest_cache;
598
32.9k
  unsigned int    hash = cache_hash(data, block);
599
32.9k
  unsigned int    i;
600
601
32.9k
  unused_cache = oldest_cache = 0;
602
  /* walk [hash..] cache elements */
603
32.9k
  for (i = hash, cache = data->cache + hash;
604
147k
       i < data->cache_size;
605
137k
       i++, cache++) {
606
137k
    if (!cache->in_use) {
607
22.0k
      if (!unused_cache)
608
3.58k
        unused_cache = cache;
609
22.0k
      continue;
610
22.0k
    }
611
115k
    if (cache->block == block) {
612
23.6k
      cache->access_time = ++data->access_time;
613
23.6k
      data->io_stats.cache_hits++;
614
23.6k
      return cache;
615
23.6k
    }
616
92.2k
    if (!oldest_cache ||
617
66.5k
        (cache->access_time < oldest_cache->access_time))
618
40.5k
      oldest_cache = cache;
619
92.2k
  }
620
  /* walk [..hash] since we didnt find a good slot yet */
621
9.33k
  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
9.33k
  if (eldest)
637
4.58k
    *eldest = (unused_cache) ? unused_cache : oldest_cache;
638
9.33k
  data->io_stats.cache_misses++;
639
9.33k
  return 0;
640
9.33k
}
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
4.58k
{
649
4.58k
  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
4.58k
  cache->in_use = 1;
661
4.58k
  cache->dirty = 0;
662
4.58k
  cache->write_err = 0;
663
4.58k
  cache->block = block;
664
4.58k
  cache->access_time = ++data->access_time;
665
4.58k
  return 0;
666
4.58k
}
667
668
5.91k
#define FLUSH_INVALIDATE  0x01
669
6.61k
#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
3.28k
{
678
3.28k
  struct unix_cache *cache;
679
3.28k
  errcode_t   retval, retval2 = 0;
680
3.28k
  unsigned int    i;
681
3.28k
  int     errors_found = 0;
682
683
3.28k
  if ((flags & FLUSH_NOLOCK) == 0)
684
3.23k
    mutex_lock(data, CACHE_MTX);
685
29.5k
  for (i=0, cache = data->cache; i < data->cache_size; i++, cache++) {
686
26.2k
    if (!cache->in_use)
687
20.3k
      continue;
688
5.91k
    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
5.91k
    } else if (flags & FLUSH_INVALIDATE) {
708
0
      cache->in_use = 0;
709
0
    }
710
5.91k
  }
711
3.28k
  if ((flags & FLUSH_NOLOCK) == 0)
712
3.23k
    mutex_unlock(data, CACHE_MTX);
713
3.28k
retry:
714
3.28k
  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
3.28k
  return retval2;
750
3.28k
}
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
667
{
852
667
  if (mode)
853
0
#if defined(HAVE_OPEN64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
854
0
    return open64(pathname, flags, mode);
855
667
  else
856
667
    return open64(pathname, flags);
857
#else
858
    return open(pathname, flags, mode);
859
  else
860
    return open(pathname, flags);
861
#endif
862
667
}
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
667
{
875
667
#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
876
667
  return fstat64(fd, buf);
877
#else
878
  return fstat(fd, buf);
879
#endif
880
667
}
881
882
#ifdef HAVE_SYS_FILE_H
883
static errcode_t unix_funlock(io_channel channel)
884
667
{
885
667
  struct unix_private_data *data;
886
667
  int ret;
887
888
667
  EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
889
667
  data = (struct unix_private_data *) channel->private_data;
890
667
  EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
891
892
667
  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
667
  return 0;
901
667
}
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
667
{
949
667
  io_channel  io = NULL;
950
667
  struct unix_private_data *data = NULL;
951
667
  errcode_t retval;
952
667
  ext2fs_struct_stat st;
953
667
#ifdef __linux__
954
667
  struct    utsname ut;
955
667
#endif
956
957
667
  if (ext2fs_safe_getenv("UNIX_IO_FORCE_BOUNCE"))
958
0
    flags |= IO_FLAG_FORCE_BOUNCE;
959
960
667
#ifdef __linux__
961
  /*
962
   * We need to make sure any previous errors in the block
963
   * device are thrown away, sigh.
964
   */
965
667
  (void) fsync(fd);
966
667
#endif
967
968
667
  retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
969
667
  if (retval)
970
0
    goto cleanup;
971
667
  memset(io, 0, sizeof(struct struct_io_channel));
972
667
  io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
973
667
  retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
974
667
  if (retval)
975
0
    goto cleanup;
976
977
667
  io->manager = io_mgr;
978
667
  retval = ext2fs_get_mem(strlen(name)+1, &io->name);
979
667
  if (retval)
980
0
    goto cleanup;
981
982
667
  strcpy(io->name, name);
983
667
  io->private_data = data;
984
667
  io->block_size = 1024;
985
667
  io->read_error = 0;
986
667
  io->write_error = 0;
987
667
  io->refcount = 1;
988
667
  io->flags = 0;
989
990
667
  if (ext2fs_safe_getenv("UNIX_IO_NOZEROOUT"))
991
0
    io->flags |= CHANNEL_FLAGS_NOZEROOUT;
992
993
667
  memset(data, 0, sizeof(struct unix_private_data));
994
667
  data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
995
667
  data->io_stats.num_fields = 4;
996
667
  data->flags = flags;
997
667
  data->dev = fd;
998
999
667
  data->cache_size = DEFAULT_CACHE_SIZE;
1000
667
  data->cache_hash_shift = highbit32(data->cache_size);
1001
667
  data->cache = calloc(DEFAULT_CACHE_SIZE, sizeof(struct unix_cache));
1002
667
  if (!data->cache) {
1003
0
    retval = EXT2_ET_NO_MEMORY;
1004
0
    goto cleanup;
1005
0
  }
1006
1007
667
#if defined(O_DIRECT)
1008
667
  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
667
  if (ext2fs_fstat(data->dev, &st) == 0) {
1023
667
    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
667
    } else {
1033
667
      io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES;
1034
667
    }
1035
667
  }
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
667
  if ((retval = alloc_cache(io, data)))
1056
0
    goto cleanup;
1057
1058
667
#ifdef BLKROGET
1059
667
  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
667
#endif
1071
1072
667
#ifdef __linux__
1073
667
#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
667
#define RLIM_INFINITY  (~0UL)
1078
667
#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
667
  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
667
#endif
1106
667
#ifdef HAVE_PTHREAD
1107
667
  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
667
#endif
1125
667
  *channel = io;
1126
667
  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
667
}
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
667
{
1176
667
  int fd = -1;
1177
667
  int open_flags;
1178
1179
667
  if (name == 0)
1180
0
    return EXT2_ET_BAD_DEVICE_NAME;
1181
1182
667
  open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
1183
667
  if (flags & IO_FLAG_EXCLUSIVE)
1184
0
    open_flags |= O_EXCL;
1185
667
#if defined(O_DIRECT)
1186
667
  if (flags & IO_FLAG_DIRECT_IO)
1187
0
    open_flags |= O_DIRECT;
1188
667
#endif
1189
667
  fd = ext2fs_open_file(name, open_flags, 0);
1190
667
  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
667
  return unix_open_channel(name, fd, flags, channel, unix_io_manager);
1199
667
}
1200
1201
static errcode_t unix_close(io_channel channel)
1202
667
{
1203
667
  struct unix_private_data *data;
1204
667
  errcode_t retval = 0;
1205
1206
667
  EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1207
667
  data = (struct unix_private_data *) channel->private_data;
1208
667
  EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1209
1210
667
  if (--channel->refcount > 0)
1211
0
    return 0;
1212
1213
667
#ifndef NO_IO_CACHE
1214
667
  retval = flush_cached_blocks(channel, data, 0);
1215
667
#endif
1216
1217
667
  unix_funlock(channel);
1218
1219
667
  if (channel->manager != unixfd_io_manager && close(data->dev) < 0)
1220
0
    retval = errno;
1221
667
  free_cache(data);
1222
667
  free(data->cache);
1223
667
#ifdef HAVE_PTHREAD
1224
667
  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
667
#endif
1230
1231
667
  ext2fs_free_mem(&channel->private_data);
1232
667
  if (channel->name)
1233
667
    ext2fs_free_mem(&channel->name);
1234
667
  ext2fs_free_mem(&channel);
1235
667
  return retval;
1236
667
}
1237
1238
static errcode_t unix_set_blksize(io_channel channel, int blksize)
1239
1.29k
{
1240
1.29k
  struct unix_private_data *data;
1241
1.29k
  errcode_t   retval = 0;
1242
1243
1.29k
  EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1244
1.29k
  data = (struct unix_private_data *) channel->private_data;
1245
1.29k
  EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1246
1247
1.29k
  if (channel->block_size != blksize) {
1248
51
    mutex_lock(data, CACHE_MTX);
1249
51
    mutex_lock(data, BOUNCE_MTX);
1250
51
#ifndef NO_IO_CACHE
1251
51
    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
51
#endif
1257
1258
51
    channel->block_size = blksize;
1259
51
    free_cache(data);
1260
51
    retval = alloc_cache(channel, data);
1261
51
    mutex_unlock(data, BOUNCE_MTX);
1262
51
    mutex_unlock(data, CACHE_MTX);
1263
51
  }
1264
1.29k
  return retval;
1265
1.29k
}
1266
1267
static errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
1268
             int count, void *buf)
1269
27.7k
{
1270
27.7k
  struct unix_private_data *data;
1271
27.7k
  struct unix_cache *cache;
1272
27.7k
  errcode_t retval;
1273
27.7k
  char    *cp;
1274
27.7k
  int   i, j;
1275
1276
27.7k
  EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1277
27.7k
  data = (struct unix_private_data *) channel->private_data;
1278
27.7k
  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
27.7k
  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
27.7k
  if (count < 0 || count > WRITE_DIRECT_SIZE) {
1290
2.56k
    if ((retval = flush_cached_blocks(channel, data, 0)))
1291
0
      return retval;
1292
2.56k
    return raw_read_blk(channel, data, block, count, buf);
1293
2.56k
  }
1294
1295
25.1k
  cp = buf;
1296
25.1k
  mutex_lock(data, CACHE_MTX);
1297
51.7k
  while (count > 0) {
1298
    /* If it's in the cache, use it! */
1299
26.7k
    if ((cache = find_cached_block(data, block, NULL))) {
1300
#ifdef DEBUG
1301
      printf("Using cached block %lu\n", block);
1302
#endif
1303
23.4k
      memcpy(cp, cache->buf, channel->block_size);
1304
23.4k
      count--;
1305
23.4k
      block++;
1306
23.4k
      cp += channel->block_size;
1307
23.4k
      continue;
1308
23.4k
    }
1309
1310
    /*
1311
     * Find the number of uncached blocks so we can do a
1312
     * single read request
1313
     */
1314
4.75k
    for (i=1; i < count; i++)
1315
1.59k
      if (find_cached_block(data, block+i, NULL))
1316
214
        break;
1317
#ifdef DEBUG
1318
    printf("Reading %d blocks starting at %lu\n", i, block);
1319
#endif
1320
3.37k
    mutex_unlock(data, CACHE_MTX);
1321
3.37k
    if ((retval = raw_read_blk(channel, data, block, i, cp)))
1322
145
      return retval;
1323
3.22k
    mutex_lock(data, CACHE_MTX);
1324
1325
    /* Save the results in the cache */
1326
7.81k
    for (j=0; j < i; j++) {
1327
4.58k
      if (!find_cached_block(data, block, &cache)) {
1328
4.58k
        retval = reuse_cache(channel, data,
1329
4.58k
                 cache, block);
1330
4.58k
        if (retval)
1331
0
          goto call_write_handler;
1332
4.58k
        memcpy(cache->buf, cp, channel->block_size);
1333
4.58k
      }
1334
4.58k
      count--;
1335
4.58k
      block++;
1336
4.58k
      cp += channel->block_size;
1337
4.58k
    }
1338
3.22k
  }
1339
25.0k
  mutex_unlock(data, CACHE_MTX);
1340
25.0k
  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
25.1k
#endif /* NO_IO_CACHE */
1364
25.1k
}
1365
1366
static errcode_t unix_read_blk(io_channel channel, unsigned long block,
1367
             int count, void *buf)
1368
1.19k
{
1369
1.19k
  return unix_read_blk64(channel, block, count, buf);
1370
1.19k
}
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
11.6M
{
1460
11.6M
#ifdef POSIX_FADV_WILLNEED
1461
11.6M
  struct unix_private_data *data;
1462
1463
11.6M
  data = (struct unix_private_data *)channel->private_data;
1464
11.6M
  EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1465
11.6M
  return posix_fadvise(data->dev,
1466
11.6M
           (ext2_loff_t)block * channel->block_size + data->offset,
1467
11.6M
           (ext2_loff_t)count * channel->block_size,
1468
11.6M
           POSIX_FADV_WILLNEED);
1469
#else
1470
  return EXT2_ET_OP_NOT_SUPPORTED;
1471
#endif
1472
11.6M
}
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;