/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 | } |