Coverage Report

Created: 2026-03-20 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/e2fsprogs/lib/ext2fs/rw_bitmaps.c
Line
Count
Source
1
/*
2
 * rw_bitmaps.c --- routines to read and write the  inode and block bitmaps.
3
 *
4
 * Copyright (C) 1993, 1994, 1994, 1996 Theodore Ts'o.
5
 *
6
 * %Begin-Header%
7
 * This file may be redistributed under the terms of the GNU Library
8
 * General Public License, version 2.
9
 * %End-Header%
10
 */
11
12
#include "config.h"
13
#include <stdio.h>
14
#include <string.h>
15
#if HAVE_UNISTD_H
16
#include <unistd.h>
17
#endif
18
#include <fcntl.h>
19
#include <time.h>
20
#ifdef HAVE_SYS_STAT_H
21
#include <sys/stat.h>
22
#endif
23
#ifdef HAVE_SYS_TYPES_H
24
#include <sys/types.h>
25
#endif
26
#ifdef HAVE_PTHREAD_H
27
#include <pthread.h>
28
#endif
29
30
#include "ext2_fs.h"
31
#include "ext2fs.h"
32
#include "e2image.h"
33
34
#ifdef HAVE_PTHREAD
35
typedef pthread_mutex_t mutex_t;
36
37
static void unix_pthread_mutex_lock(mutex_t *mutex)
38
205k
{
39
205k
  if (mutex)
40
0
    pthread_mutex_lock(mutex);
41
205k
}
42
static void unix_pthread_mutex_unlock(mutex_t *mutex)
43
205k
{
44
205k
  if (mutex)
45
0
    pthread_mutex_unlock(mutex);
46
205k
}
47
#else
48
typedef int mutex_t;
49
#define unix_pthread_mutex_lock(mutex_t) do {} while (0)
50
#define unix_pthread_mutex_unlock(mutex_t) do {} while (0)
51
#endif
52
53
static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
54
0
{
55
0
  dgrp_t    i;
56
0
  unsigned int  j;
57
0
  int   block_nbytes, inode_nbytes;
58
0
  unsigned int  nbits;
59
0
  errcode_t retval;
60
0
  char    *block_buf = NULL, *inode_buf = NULL;
61
0
  int   csum_flag;
62
0
  blk64_t   blk;
63
0
  blk64_t   blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block);
64
0
  ext2_ino_t  ino_itr = 1;
65
66
0
  EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
67
68
0
  if (!(fs->flags & EXT2_FLAG_RW))
69
0
    return EXT2_ET_RO_FILSYS;
70
71
0
  csum_flag = ext2fs_has_group_desc_csum(fs);
72
73
0
  inode_nbytes = block_nbytes = 0;
74
0
  if (do_block) {
75
0
    block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
76
0
    retval = io_channel_alloc_buf(fs->io, 0, &block_buf);
77
0
    if (retval)
78
0
      goto errout;
79
0
    memset(block_buf, 0xff, fs->blocksize);
80
0
  }
81
0
  if (do_inode) {
82
0
    inode_nbytes = (size_t)
83
0
      ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
84
0
    retval = io_channel_alloc_buf(fs->io, 0, &inode_buf);
85
0
    if (retval)
86
0
      goto errout;
87
0
    memset(inode_buf, 0xff, fs->blocksize);
88
0
  }
89
90
0
  for (i = 0; i < fs->group_desc_count; i++) {
91
0
    if (!do_block)
92
0
      goto skip_block_bitmap;
93
94
0
    if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT)
95
0
        )
96
0
      goto skip_this_block_bitmap;
97
98
0
    retval = ext2fs_get_block_bitmap_range2(fs->block_map,
99
0
        blk_itr, block_nbytes << 3, block_buf);
100
0
    if (retval)
101
0
      goto errout;
102
103
0
    if (i == fs->group_desc_count - 1) {
104
      /* Force bitmap padding for the last group */
105
0
      nbits = EXT2FS_NUM_B2C(fs,
106
0
        ((ext2fs_blocks_count(fs->super)
107
0
          - (__u64) fs->super->s_first_data_block)
108
0
         % (__u64) EXT2_BLOCKS_PER_GROUP(fs->super)));
109
0
      if (nbits)
110
0
        for (j = nbits; j < fs->blocksize * 8; j++)
111
0
          ext2fs_set_bit(j, block_buf);
112
0
    }
113
114
0
    retval = ext2fs_block_bitmap_csum_set(fs, i, block_buf,
115
0
                  block_nbytes);
116
0
    if (retval)
117
0
      return retval;
118
0
    ext2fs_group_desc_csum_set(fs, i);
119
0
    fs->flags |= EXT2_FLAG_DIRTY;
120
121
0
    blk = ext2fs_block_bitmap_loc(fs, i);
122
0
    if (blk && blk < ext2fs_blocks_count(fs->super)) {
123
0
      retval = io_channel_write_blk64(fs->io, blk, 1,
124
0
              block_buf);
125
0
      if (retval) {
126
0
        retval = EXT2_ET_BLOCK_BITMAP_WRITE;
127
0
        goto errout;
128
0
      }
129
0
    }
130
0
  skip_this_block_bitmap:
131
0
    blk_itr += block_nbytes << 3;
132
0
  skip_block_bitmap:
133
134
0
    if (!do_inode)
135
0
      continue;
136
137
0
    if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT)
138
0
        )
139
0
      goto skip_this_inode_bitmap;
140
141
0
    retval = ext2fs_get_inode_bitmap_range2(fs->inode_map,
142
0
        ino_itr, inode_nbytes << 3, inode_buf);
143
0
    if (retval)
144
0
      goto errout;
145
146
0
    retval = ext2fs_inode_bitmap_csum_set(fs, i, inode_buf,
147
0
                  inode_nbytes);
148
0
    if (retval)
149
0
      goto errout;
150
0
    ext2fs_group_desc_csum_set(fs, i);
151
0
    fs->flags |= EXT2_FLAG_DIRTY;
152
153
0
    blk = ext2fs_inode_bitmap_loc(fs, i);
154
0
    if (blk && blk < ext2fs_blocks_count(fs->super)) {
155
0
      retval = io_channel_write_blk64(fs->io, blk, 1,
156
0
                  inode_buf);
157
0
      if (retval) {
158
0
        retval = EXT2_ET_INODE_BITMAP_WRITE;
159
0
        goto errout;
160
0
      }
161
0
    }
162
0
  skip_this_inode_bitmap:
163
0
    ino_itr += inode_nbytes << 3;
164
165
0
  }
166
0
  if (do_block) {
167
0
    fs->flags &= ~EXT2_FLAG_BB_DIRTY;
168
0
    ext2fs_free_mem(&block_buf);
169
0
  }
170
0
  if (do_inode) {
171
0
    fs->flags &= ~EXT2_FLAG_IB_DIRTY;
172
0
    ext2fs_free_mem(&inode_buf);
173
0
  }
174
0
  return 0;
175
0
errout:
176
0
  if (inode_buf)
177
0
    ext2fs_free_mem(&inode_buf);
178
0
  if (block_buf)
179
0
    ext2fs_free_mem(&block_buf);
180
0
  return retval;
181
0
}
182
183
static errcode_t mark_uninit_bg_group_blocks(ext2_filsys fs)
184
160
{
185
160
  dgrp_t      i;
186
160
  blk64_t     blk;
187
160
  ext2fs_block_bitmap bmap = fs->block_map;
188
189
100k
  for (i = 0; i < fs->group_desc_count; i++) {
190
100k
    if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT))
191
16.6k
      continue;
192
193
83.5k
    ext2fs_reserve_super_and_bgd(fs, i, bmap);
194
195
    /*
196
     * Mark the blocks used for the inode table
197
     */
198
83.5k
    blk = ext2fs_inode_table_loc(fs, i);
199
83.5k
    if (blk)
200
81.7k
      ext2fs_mark_block_bitmap_range2(bmap, blk,
201
81.7k
            fs->inode_blocks_per_group);
202
203
    /*
204
     * Mark block used for the block bitmap
205
     */
206
83.5k
    blk = ext2fs_block_bitmap_loc(fs, i);
207
83.5k
    if (blk && blk < ext2fs_blocks_count(fs->super))
208
3.68k
      ext2fs_mark_block_bitmap2(bmap, blk);
209
210
    /*
211
     * Mark block used for the inode bitmap
212
     */
213
83.5k
    blk = ext2fs_inode_bitmap_loc(fs, i);
214
83.5k
    if (blk && blk < ext2fs_blocks_count(fs->super))
215
2.16k
      ext2fs_mark_block_bitmap2(bmap, blk);
216
83.5k
  }
217
160
  return 0;
218
160
}
219
220
static int bitmap_tail_verify(unsigned char *bitmap, int first, int last)
221
8.46k
{
222
8.46k
  int i;
223
224
14.2k
  for (i = first; i <= last; i++)
225
12.6k
    if (bitmap[i] != 0xff)
226
6.90k
      return 0;
227
1.55k
  return 1;
228
8.46k
}
229
230
static errcode_t read_bitmaps_range_prepare(ext2_filsys fs, int flags)
231
199
{
232
199
  errcode_t retval;
233
199
  int block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
234
199
  int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
235
199
  char *buf;
236
237
199
  EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
238
239
199
  if ((block_nbytes > (int) fs->blocksize) ||
240
198
      (inode_nbytes > (int) fs->blocksize))
241
3
    return EXT2_ET_CORRUPT_SUPERBLOCK;
242
243
196
  fs->write_bitmaps = ext2fs_write_bitmaps;
244
245
196
  retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
246
196
  if (retval)
247
0
    return retval;
248
249
196
  if (flags & EXT2FS_BITMAPS_BLOCK) {
250
191
    if (fs->block_map)
251
0
      ext2fs_free_block_bitmap(fs->block_map);
252
191
    strcpy(buf, "block bitmap for ");
253
191
    strcat(buf, fs->device_name);
254
191
    retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
255
191
    if (retval)
256
0
      goto cleanup;
257
191
  }
258
259
196
  if (flags & EXT2FS_BITMAPS_INODE) {
260
5
    if (fs->inode_map)
261
0
      ext2fs_free_inode_bitmap(fs->inode_map);
262
5
    strcpy(buf, "inode bitmap for ");
263
5
    strcat(buf, fs->device_name);
264
5
    retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
265
5
    if (retval)
266
0
      goto cleanup;
267
5
  }
268
196
  ext2fs_free_mem(&buf);
269
196
  return retval;
270
271
0
cleanup:
272
0
  if (flags & EXT2FS_BITMAPS_BLOCK) {
273
0
    ext2fs_free_block_bitmap(fs->block_map);
274
0
    fs->block_map = 0;
275
0
  }
276
0
  if (flags & EXT2FS_BITMAPS_INODE) {
277
0
    ext2fs_free_inode_bitmap(fs->inode_map);
278
0
    fs->inode_map = 0;
279
0
  }
280
0
  ext2fs_free_mem(&buf);
281
0
  return retval;
282
196
}
283
284
static errcode_t read_bitmaps_range_start(ext2_filsys fs, int flags,
285
            dgrp_t start, dgrp_t end,
286
            mutex_t *mutex,
287
            int *tail_flags)
288
196
{
289
196
  dgrp_t i;
290
196
  char *block_bitmap = 0, *inode_bitmap = 0;
291
196
  errcode_t retval = 0;
292
196
  int block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
293
196
  int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
294
196
  int csum_flag;
295
196
  unsigned int  cnt;
296
196
  blk64_t blk;
297
196
  blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block);
298
196
  blk64_t   blk_cnt;
299
196
  ext2_ino_t ino_itr = 1;
300
196
  ext2_ino_t ino_cnt;
301
302
196
  csum_flag = ext2fs_has_group_desc_csum(fs);
303
304
196
  if (flags & EXT2FS_BITMAPS_BLOCK) {
305
191
    retval = io_channel_alloc_buf(fs->io, 0, &block_bitmap);
306
191
    if (retval)
307
0
      goto cleanup;
308
191
  } else {
309
5
    block_nbytes = 0;
310
5
  }
311
312
196
  if (flags & EXT2FS_BITMAPS_INODE) {
313
5
    retval = io_channel_alloc_buf(fs->io, 0, &inode_bitmap);
314
5
    if (retval)
315
0
      goto cleanup;
316
191
  } else {
317
191
    inode_nbytes = 0;
318
191
  }
319
320
  /* io should be null */
321
196
  if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
322
0
    blk = (ext2fs_le32_to_cpu(fs->image_header->offset_inodemap) / fs->blocksize);
323
0
    ino_cnt = fs->super->s_inodes_count;
324
0
    while (inode_bitmap && ino_cnt > 0) {
325
0
      retval = io_channel_read_blk64(fs->image_io, blk++,
326
0
                 1, inode_bitmap);
327
0
      if (retval)
328
0
        goto cleanup;
329
0
      cnt = fs->blocksize << 3;
330
0
      if (cnt > ino_cnt)
331
0
        cnt = ino_cnt;
332
0
      retval = ext2fs_set_inode_bitmap_range2(fs->inode_map,
333
0
                 ino_itr, cnt, inode_bitmap);
334
0
      if (retval)
335
0
        goto cleanup;
336
0
      ino_itr += cnt;
337
0
      ino_cnt -= cnt;
338
0
    }
339
0
    blk = (ext2fs_le32_to_cpu(fs->image_header->offset_blockmap) /
340
0
           fs->blocksize);
341
0
    blk_cnt = EXT2_GROUPS_TO_CLUSTERS(fs->super,
342
0
              fs->group_desc_count);
343
0
    while (block_bitmap && blk_cnt > 0) {
344
0
      retval = io_channel_read_blk64(fs->image_io, blk++,
345
0
                 1, block_bitmap);
346
0
      if (retval)
347
0
        goto cleanup;
348
0
      cnt = fs->blocksize << 3;
349
0
      if (cnt > blk_cnt)
350
0
        cnt = blk_cnt;
351
0
      retval = ext2fs_set_block_bitmap_range2(fs->block_map,
352
0
               blk_itr, cnt, block_bitmap);
353
0
      if (retval)
354
0
        goto cleanup;
355
0
      blk_itr += cnt;
356
0
      blk_cnt -= cnt;
357
0
    }
358
0
    goto cleanup;
359
0
  }
360
361
196
  blk_itr += ((blk64_t)start * (block_nbytes << 3));
362
196
  ino_itr += ((blk64_t)start * (inode_nbytes << 3));
363
205k
  for (i = start; i <= end; i++) {
364
205k
    if (block_bitmap) {
365
195k
      blk = ext2fs_block_bitmap_loc(fs, i);
366
195k
      if ((csum_flag &&
367
83.1k
           ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) &&
368
79.0k
           ext2fs_group_desc_csum_verify(fs, i)) ||
369
195k
          (blk >= ext2fs_blocks_count(fs->super)))
370
173k
        blk = 0;
371
195k
      if (blk) {
372
8.49k
        retval = io_channel_read_blk64(fs->io, blk,
373
8.49k
                     1, block_bitmap);
374
8.49k
        if (retval) {
375
31
          retval = EXT2_ET_BLOCK_BITMAP_READ;
376
31
          goto cleanup;
377
31
        }
378
        /* verify block bitmap checksum */
379
8.46k
        if (!(fs->flags &
380
8.46k
              EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
381
0
            !ext2fs_block_bitmap_csum_verify(fs, i,
382
0
            block_bitmap, block_nbytes)) {
383
0
          retval =
384
0
          EXT2_ET_BLOCK_BITMAP_CSUM_INVALID;
385
0
          goto cleanup;
386
0
        }
387
8.46k
        if (!bitmap_tail_verify((unsigned char *) block_bitmap,
388
8.46k
              block_nbytes, fs->blocksize - 1))
389
6.90k
          *tail_flags |= EXT2_FLAG_BBITMAP_TAIL_PROBLEM;
390
8.46k
      } else
391
186k
        memset(block_bitmap, 0, block_nbytes);
392
195k
      cnt = block_nbytes << 3;
393
195k
      unix_pthread_mutex_lock(mutex);
394
195k
      retval = ext2fs_set_block_bitmap_range2(fs->block_map,
395
195k
                 blk_itr, cnt, block_bitmap);
396
195k
      unix_pthread_mutex_unlock(mutex);
397
195k
      if (retval)
398
0
        goto cleanup;
399
195k
      blk_itr += block_nbytes << 3;
400
195k
    }
401
205k
    if (inode_bitmap) {
402
10.3k
      blk = ext2fs_inode_bitmap_loc(fs, i);
403
10.3k
      if ((csum_flag &&
404
7.48k
           ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) &&
405
7.46k
           ext2fs_group_desc_csum_verify(fs, i)) ||
406
10.3k
          (blk >= ext2fs_blocks_count(fs->super)))
407
10.3k
        blk = 0;
408
10.3k
      if (blk) {
409
8
        retval = io_channel_read_blk64(fs->io, blk,
410
8
                     1, inode_bitmap);
411
8
        if (retval) {
412
5
          retval = EXT2_ET_INODE_BITMAP_READ;
413
5
          goto cleanup;
414
5
        }
415
416
        /* verify inode bitmap checksum */
417
3
        if (!(fs->flags &
418
3
              EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
419
0
            !ext2fs_inode_bitmap_csum_verify(fs, i,
420
0
            inode_bitmap, inode_nbytes)) {
421
0
          retval =
422
0
          EXT2_ET_INODE_BITMAP_CSUM_INVALID;
423
0
          goto cleanup;
424
0
        }
425
3
        if (!bitmap_tail_verify((unsigned char *) inode_bitmap,
426
3
              inode_nbytes, fs->blocksize - 1))
427
3
          *tail_flags |= EXT2_FLAG_IBITMAP_TAIL_PROBLEM;
428
3
      } else
429
10.3k
        memset(inode_bitmap, 0, inode_nbytes);
430
10.3k
      cnt = inode_nbytes << 3;
431
10.3k
      unix_pthread_mutex_lock(mutex);
432
10.3k
      retval = ext2fs_set_inode_bitmap_range2(fs->inode_map,
433
10.3k
                 ino_itr, cnt, inode_bitmap);
434
10.3k
      unix_pthread_mutex_unlock(mutex);
435
10.3k
      if (retval)
436
0
        goto cleanup;
437
10.3k
      ino_itr += inode_nbytes << 3;
438
10.3k
    }
439
205k
  }
440
441
196
cleanup:
442
196
  if (inode_bitmap)
443
5
    ext2fs_free_mem(&inode_bitmap);
444
196
  if (block_bitmap)
445
191
    ext2fs_free_mem(&block_bitmap);
446
196
  return retval;
447
196
}
448
449
static errcode_t read_bitmaps_range_end(ext2_filsys fs, int flags,
450
          int tail_flags)
451
160
{
452
160
  errcode_t retval;
453
454
  /* Mark group blocks for any BLOCK_UNINIT groups */
455
160
  if (flags & EXT2FS_BITMAPS_BLOCK) {
456
160
    retval = mark_uninit_bg_group_blocks(fs);
457
160
    if (retval)
458
0
      return retval;
459
160
    fs->flags &= ~EXT2_FLAG_BBITMAP_TAIL_PROBLEM;
460
160
  }
461
160
  if (flags & EXT2FS_BITMAPS_INODE)
462
0
    fs->flags &= ~EXT2_FLAG_IBITMAP_TAIL_PROBLEM;
463
160
  fs->flags |= tail_flags;
464
465
160
  return 0;
466
160
}
467
468
static void read_bitmaps_cleanup_on_error(ext2_filsys fs, int flags)
469
36
{
470
36
  if (flags & EXT2FS_BITMAPS_BLOCK) {
471
31
    ext2fs_free_block_bitmap(fs->block_map);
472
31
    fs->block_map = 0;
473
31
  }
474
36
  if (flags & EXT2FS_BITMAPS_INODE) {
475
5
    ext2fs_free_inode_bitmap(fs->inode_map);
476
5
    fs->inode_map = 0;
477
5
  }
478
36
}
479
480
static errcode_t read_bitmaps_range(ext2_filsys fs, int flags,
481
            dgrp_t start, dgrp_t end)
482
199
{
483
199
  errcode_t retval;
484
199
  int tail_flags = 0;
485
486
199
  retval = read_bitmaps_range_prepare(fs, flags);
487
199
  if (retval)
488
3
    return retval;
489
490
196
  retval = read_bitmaps_range_start(fs, flags, start, end,
491
196
            NULL, &tail_flags);
492
196
  if (retval == 0)
493
160
    retval = read_bitmaps_range_end(fs, flags, tail_flags);
494
196
  if (retval)
495
36
    read_bitmaps_cleanup_on_error(fs, flags);
496
196
  return retval;
497
199
}
498
499
#ifdef HAVE_PTHREAD
500
struct read_bitmaps_thread_info {
501
  ext2_filsys rbt_fs;
502
  int   rbt_flags;
503
  dgrp_t    rbt_grp_start;
504
  dgrp_t    rbt_grp_end;
505
  errcode_t rbt_retval;
506
  pthread_mutex_t *rbt_mutex;
507
  int   rbt_tail_flags;
508
};
509
510
static void *read_bitmaps_thread(void *data)
511
0
{
512
0
  struct read_bitmaps_thread_info *rbt = data;
513
514
0
  rbt->rbt_retval = read_bitmaps_range_start(rbt->rbt_fs, rbt->rbt_flags,
515
0
        rbt->rbt_grp_start, rbt->rbt_grp_end,
516
0
        rbt->rbt_mutex, &rbt->rbt_tail_flags);
517
0
  return NULL;
518
0
}
519
#endif
520
521
errcode_t ext2fs_rw_bitmaps(ext2_filsys fs, int flags, int num_threads)
522
199
{
523
199
#ifdef HAVE_PTHREAD
524
199
  pthread_attr_t  attr;
525
199
  pthread_t *thread_ids = NULL;
526
199
  struct read_bitmaps_thread_info *thread_infos = NULL;
527
199
  pthread_mutex_t rbt_mutex = PTHREAD_MUTEX_INITIALIZER;
528
199
  errcode_t retval;
529
199
  errcode_t rc;
530
199
  unsigned flexbg_size = 1U << fs->super->s_log_groups_per_flex;
531
199
  dgrp_t average_group;
532
199
  int i, tail_flags = 0;
533
199
#endif
534
535
199
  if (flags & ~EXT2FS_BITMAPS_VALID_FLAGS)
536
0
    return EXT2_ET_INVALID_ARGUMENT;
537
538
199
  if (ext2fs_has_feature_journal_dev(fs->super))
539
0
    return EXT2_ET_EXTERNAL_JOURNAL_NOSUPP;
540
541
199
  if (flags & EXT2FS_BITMAPS_WRITE)
542
0
    return write_bitmaps(fs, flags & EXT2FS_BITMAPS_INODE,
543
0
             flags & EXT2FS_BITMAPS_BLOCK);
544
545
199
#ifdef HAVE_PTHREAD
546
199
  if (((fs->io->flags & CHANNEL_FLAGS_THREADS) == 0) ||
547
0
      (num_threads == 1) || (fs->flags & EXT2_FLAG_IMAGE_FILE))
548
199
    goto fallback;
549
550
0
#if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF)
551
0
  if (num_threads < 0)
552
0
    num_threads = sysconf(_SC_NPROCESSORS_CONF);
553
0
#endif
554
  /*
555
   * Guess for now; eventually we should probably define
556
   * ext2fs_get_num_cpus() and teach it how to get this info on
557
   * MacOS, FreeBSD, etc.
558
   * ref: https://stackoverflow.com/questions/150355
559
   */
560
0
  if (num_threads <= 0)
561
0
    num_threads = 4;
562
563
0
  if ((unsigned) num_threads > fs->group_desc_count)
564
0
    num_threads = fs->group_desc_count;
565
0
  average_group = fs->group_desc_count / num_threads;
566
0
  if (ext2fs_has_feature_flex_bg(fs->super)) {
567
0
    average_group = (average_group / flexbg_size) * flexbg_size;
568
0
  }
569
0
  if ((num_threads <= 1) || (average_group == 0))
570
0
    goto fallback;
571
572
0
  io_channel_set_options(fs->io, "cache=off");
573
0
  retval = pthread_attr_init(&attr);
574
0
  if (retval)
575
0
    return retval;
576
577
0
  thread_ids = calloc(sizeof(pthread_t), num_threads);
578
0
  if (!thread_ids)
579
0
    return ENOMEM;
580
581
0
  thread_infos = calloc(sizeof(struct read_bitmaps_thread_info),
582
0
        num_threads);
583
0
  if (!thread_infos)
584
0
    goto out;
585
586
0
  retval = read_bitmaps_range_prepare(fs, flags);
587
0
  if (retval)
588
0
    goto out;
589
590
//  fprintf(stdout, "Multiple threads triggered to read bitmaps\n");
591
0
  for (i = 0; i < num_threads; i++) {
592
0
    thread_infos[i].rbt_fs = fs;
593
0
    thread_infos[i].rbt_flags = flags;
594
0
    thread_infos[i].rbt_mutex = &rbt_mutex;
595
0
    thread_infos[i].rbt_tail_flags = 0;
596
0
    if (i == 0)
597
0
      thread_infos[i].rbt_grp_start = 0;
598
0
    else
599
0
      thread_infos[i].rbt_grp_start = average_group * i + 1;
600
601
0
    if (i == num_threads - 1)
602
0
      thread_infos[i].rbt_grp_end = fs->group_desc_count - 1;
603
0
    else
604
0
      thread_infos[i].rbt_grp_end = average_group * (i + 1);
605
0
    retval = pthread_create(&thread_ids[i], &attr,
606
0
          &read_bitmaps_thread, &thread_infos[i]);
607
0
    if (retval)
608
0
      break;
609
0
  }
610
0
  for (i = 0; i < num_threads; i++) {
611
0
    if (!thread_ids[i])
612
0
      break;
613
0
    rc = pthread_join(thread_ids[i], NULL);
614
0
    if (rc && !retval)
615
0
      retval = rc;
616
0
    rc = thread_infos[i].rbt_retval;
617
0
    if (rc && !retval)
618
0
      retval = rc;
619
0
    tail_flags |= thread_infos[i].rbt_tail_flags;
620
0
  }
621
0
out:
622
0
  rc = pthread_attr_destroy(&attr);
623
0
  if (rc && !retval)
624
0
    retval = rc;
625
0
  free(thread_infos);
626
0
  free(thread_ids);
627
628
0
  if (retval == 0)
629
0
    retval = read_bitmaps_range_end(fs, flags, tail_flags);
630
0
  if (retval)
631
0
    read_bitmaps_cleanup_on_error(fs, flags);
632
  /* XXX should save and restore cache setting */
633
0
  io_channel_set_options(fs->io, "cache=on");
634
0
  return retval;
635
199
fallback:
636
199
#endif /* HAVE_PTHREAD */
637
199
  return read_bitmaps_range(fs, flags, 0, fs->group_desc_count - 1);
638
0
}
639
640
errcode_t ext2fs_read_inode_bitmap(ext2_filsys fs)
641
5
{
642
5
  return ext2fs_rw_bitmaps(fs, EXT2FS_BITMAPS_INODE, -1);
643
5
}
644
645
errcode_t ext2fs_read_block_bitmap(ext2_filsys fs)
646
194
{
647
194
  return ext2fs_rw_bitmaps(fs, EXT2FS_BITMAPS_BLOCK, -1);
648
194
}
649
650
errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs)
651
0
{
652
0
  return write_bitmaps(fs, 1, 0);
653
0
}
654
655
errcode_t ext2fs_write_block_bitmap (ext2_filsys fs)
656
0
{
657
0
  return write_bitmaps(fs, 0, 1);
658
0
}
659
660
errcode_t ext2fs_read_bitmaps(ext2_filsys fs)
661
0
{
662
0
  int flags = 0;
663
664
0
  if (!fs->inode_map)
665
0
    flags |= EXT2FS_BITMAPS_INODE;
666
0
  if (!fs->block_map)
667
0
    flags |= EXT2FS_BITMAPS_BLOCK;
668
0
  if (flags == 0)
669
0
    return 0;
670
0
  return ext2fs_rw_bitmaps(fs, flags, -1);
671
0
}
672
673
errcode_t ext2fs_write_bitmaps(ext2_filsys fs)
674
196
{
675
196
  int do_inode = fs->inode_map && ext2fs_test_ib_dirty(fs);
676
196
  int do_block = fs->block_map && ext2fs_test_bb_dirty(fs);
677
678
196
  if (!do_inode && !do_block)
679
196
    return 0;
680
681
0
  return write_bitmaps(fs, do_inode, do_block);
682
196
}