e2fsprogs: Parallel fsck support
cover e2fsprogs: Parallel fsck support
Hello,
This is a RFC patch series which has the list of all pfsck related changes which should also address the problem statements mentioned by Ted and Harshad here [1]
Below points will provide more details on how this patch series is laid out:-
1. This series is rebased on the latest e2fsprogs master branch.
2. Patch series is broken down into logical patches for easier review. The series contains libext2fs changes first, followed by e2fsck changes which utilizes libext2fs apis to add pfsck support to pass1.
3. Changes [0005] to [0012] addresses the problem statement laid out by Ted and Harshad [1] i.e. we now have a libext2fs API for clone and merge of ext2_filsys struct. (ext2fs_clone_fs() & ext2fs_merge_fs())
4. These two changes [0016] & [0026] uses above clone/merge api for test and for use in e2fsck.
5. For a lot of libext2fs changes (for e.g. bitmap merging logic or clone/merge apis), there are some unit tests added for it's functionality verification.
Performance results:
=====================
1. On nvme with 22M 0-byte inodes: 7sec v/s 19sec
2. On nvme with 22M 4KB-32KB inodes: 17sec v/s 30sec
3. On nvme with 11M 32KB inodes: 9sec v/s 15sec
4. On RAID HDD setups: (will get back with perf results for this. Although, I had shared some numbers earlier, but I wanted to run pfsck with different FS layout and collect the numbers once again)
For review: Since these are large number of changes. So if the overall series looks good, then we can start reviewing changes in batches. For e.g. if we could review initial changes in libext2fs (from [001] - [0020]), that would be a good start.
Patch-0073 adds support to all tests/* with "-m 2" mode to test pfsck as well. If pthread support is present, make check then test with "-m 2" fsck mode option as well (for tests which utilizes run_e2fsck script).
This was mainly done for verifying that all existing tests passes with pfsck. In this only few tests are kept disabled by passing SKIP_MT=true (Note: Last min. I have decided to drop this patch from sending. Although this can still be found in the github branch [2] for any testing)
On Threadsan: I had tested this patch series against threadsan as well. It does lists few race conditions when running multi-threading (these doesn't looks to be any major problem). I have fixed a few [0070] and rest might either need some minor fixing or marking it false positive.
Here is the github link with all these commits (pfsck-RFCv1 branch) [2].
[1]: https://lore.kernel.org/linux-ext4/YMN10sXgoTR%[email protected]/
[2]: https://github.com/riteshharjani/e2fsprogs/commits/pfsck-RFCv1
Andreas Dilger (2):
libext2fs: Misc fixes for struct_ext2_filsys
e2fsck: misc cleanups for pfsck
Li Xi (16):
dblist: add dblist merge logic
libext2fs: Add flush cleanup API
libext2fs: merge icounts after thread finishes
e2fsck: add -m option for multithread
e2fsck: copy context when using multi-thread fsck
e2fsck: create logs for multi-threads
e2fsck: configure one pfsck thread
e2fsck: Add asserts in open_channel_fs
e2fsck: add start/end group for thread
e2fsck: split groups to different threads
e2fsck: print thread log properly
e2fsck: do not change global variables
e2fsck: optimize the inserting of dir_info_db
e2fsck: merge dir_info after thread finishes
e2fsck: merge icounts after thread finishes
e2fsck: add debug codes for multiple threads
Ritesh Harjani (IBM) (15):
e2fsck: Fix unbalanced mutex unlock for BOUNCE_MTX
gen_bitmaps: Fix ext2fs_compare_generic_bmap/bitmap logic
blkmap64_ba: Add common helper for bits size calculation
badblocks: Remove unused badblocks_flags
tst_badblocks: Add unit test to verify badblocks list merge api
tst_bitmaps_standalone: Add copy and merge bitmaps test
tst_bitmaps_pthread: Add merge bitmaps test using pthreads
tst_libext2fs_pthread: Add libext2fs merge/clone unit tests
e2fsck: Add e2fsck_pass1_thread_join return value
e2fsck: Use merge/clone apis of libext2fs
e2fsck: Fix io->align assert check
e2fsck: Fix double free of inodes_to_process
e2fsck: Fix and simplify update_mmp in case of pfsck
e2fsck: Make threads call log_out after pthread_join tests/f_multithread: Fix f_multithread related tests
Saranya Muruganandam (3):
libext2fs: dupfs: Add fs clone & merge api
e2fsck: propagate number of threads
e2fsck: Annotating fields in e2fsck_struct
Sebastien Buisson (1):
sec: support encrypted files handling in pfsck mode
Wang Shilong (35):
badblocks: Add badblocks merge logic
libext2fs: Add rbtree bitmap merge logic
libext2fs: Add bitmaps merge ops
libext2fs: merge quota context after threads finish
libext2fs: Add support for ext2fs_test_block_bitmap_range2_valid()
libext2fs: Add support to get average group count
libext2fs: avoid too much memory allocation in case fs_num_threads
e2fsck: Add e2fsck_pass1_merge_bitmap() api
e2fsck: rbtree bitmap for dir
e2fsck: merge counts after threads finish
e2fsck: merge dx_dir_info after threads finish
e2fsck: merge dirs_to_hash when threads finish
e2fsck: merge context flags properly
e2fsck: merge quota context after threads finish
e2fsck: serialize fix operations
e2fsck: move some fixes out of parallel pthreads
e2fsck: split and merge invalid bitmaps
e2fsck: merge EA blocks properly
e2fsck: kickoff mutex lock for block found map
e2fsck: allow admin specify number of threads
e2fsck: adjust number of threads
e2fsck: fix readahead for pfsck of pass1
e2fsck: merge options after threads finish
e2fsck: reset lost_and_found after threads finish
e2fsck: merge extent depth count after threads finish
e2fsck: simplify e2fsck context merging codes
e2fsck: set E2F_FLAG_ALLOC_OK after threads
e2fsck: wait fix thread finish before checking
e2fsck: cleanup e2fsck_pass1_thread_join()
e2fsck: make default smallest RA size to 1M
e2fsck: update mmp block in one thread
e2fsck: reset @inodes_to_rebuild if restart
tests: add pfsck test
e2fsck: fix memory leaks with pfsck enabled
e2fsck: merge casefolded dir lists after thread finish
e2fsck/dirinfo.c | 238 ++- e2fsck/dx_dirinfo.c | 64 + e2fsck/e2fsck.8.in | 8 +- e2fsck/e2fsck.c | 11 + e2fsck/e2fsck.h | 103 +- e2fsck/encrypted_files.c | 139 ++ e2fsck/logfile.c | 13 +- e2fsck/pass1.c | 1894 +++++++++++++++++++---- e2fsck/problem.c | 11 + e2fsck/problem.h | 3 + e2fsck/readahead.c | 4 + e2fsck/unix.c | 58 +- e2fsck/util.c | 193 ++- lib/ext2fs/Makefile.in | 53 +- lib/ext2fs/badblocks.c | 81 +- lib/ext2fs/bitmaps.c | 10 + lib/ext2fs/bitops.h | 2 + lib/ext2fs/blkmap64_ba.c | 20 +- lib/ext2fs/blkmap64_rb.c | 65 + lib/ext2fs/bmap64.h | 4 + lib/ext2fs/dblist.c | 38 + lib/ext2fs/dupfs.c | 183 +++ lib/ext2fs/ext2_err.et.in | 3 + lib/ext2fs/ext2_io.h | 2 + lib/ext2fs/ext2fs.h | 66 +- lib/ext2fs/ext2fsP.h | 1 - lib/ext2fs/gen_bitmap.c | 9 +- lib/ext2fs/gen_bitmap64.c | 72 +- lib/ext2fs/icount.c | 107 ++ lib/ext2fs/tst_badblocks.c | 61 +- lib/ext2fs/tst_bitmaps_pthread.c | 247 +++ lib/ext2fs/tst_bitmaps_standalone.c | 170 ++ lib/ext2fs/tst_libext2fs_pthread.c | 315 ++++ lib/ext2fs/undo_io.c | 19 + lib/ext2fs/unix_io.c | 25 +- lib/support/mkquota.c | 39 + lib/support/quotaio.h | 3 + tests/f_itable_collision/expect.1 | 3 - tests/f_multithread/expect.1 | 25 + tests/f_multithread/expect.2 | 7 + tests/f_multithread/image.gz | 1 + tests/f_multithread/name | 1 + tests/f_multithread/script | 4 + tests/f_multithread_completion/expect.1 | 2 + tests/f_multithread_completion/expect.2 | 23 + tests/f_multithread_completion/image.gz | 1 + tests/f_multithread_completion/name | 1 + tests/f_multithread_completion/script | 4 + tests/f_multithread_logfile/expect.1 | 25 + tests/f_multithread_logfile/image.gz | 1 + tests/f_multithread_logfile/name | 1 + tests/f_multithread_logfile/script | 32 + tests/f_multithread_no/expect.1 | 26 + tests/f_multithread_no/expect.2 | 23 + tests/f_multithread_no/image.gz | 1 + tests/f_multithread_no/name | 1 + tests/f_multithread_no/script | 4 + tests/f_multithread_ok/expect.1 | 15 + tests/f_multithread_ok/image.gz | Bin 0 -> 796311 bytes tests/f_multithread_ok/name | 1 + tests/f_multithread_ok/script | 4 + tests/f_multithread_preen/expect.1 | 11 + tests/f_multithread_preen/expect.2 | 23 + tests/f_multithread_preen/image.gz | 1 + tests/f_multithread_preen/name | 1 + tests/f_multithread_preen/script | 4 + tests/f_multithread_yes/expect.1 | 2 + tests/f_multithread_yes/expect.2 | 23 + tests/f_multithread_yes/image.gz | 1 + tests/f_multithread_yes/name | 1 + tests/f_multithread_yes/script | 4 + tests/test_one.in | 8 + 72 files changed, 4186 insertions(+), 433 deletions(-) create mode 100644 lib/ext2fs/tst_bitmaps_pthread.c create mode 100644 lib/ext2fs/tst_bitmaps_standalone.c create mode 100644 lib/ext2fs/tst_libext2fs_pthread.c create mode 100644 tests/f_multithread/expect.1 create mode 100644 tests/f_multithread/expect.2 create mode 120000 tests/f_multithread/image.gz create mode 100644 tests/f_multithread/name create mode 100644 tests/f_multithread/script create mode 100644 tests/f_multithread_completion/expect.1 create mode 100644 tests/f_multithread_completion/expect.2 create mode 120000 tests/f_multithread_completion/image.gz create mode 100644 tests/f_multithread_completion/name create mode 100644 tests/f_multithread_completion/script create mode 100644 tests/f_multithread_logfile/expect.1 create mode 120000 tests/f_multithread_logfile/image.gz create mode 100644 tests/f_multithread_logfile/name create mode 100644 tests/f_multithread_logfile/script create mode 100644 tests/f_multithread_no/expect.1 create mode 100644 tests/f_multithread_no/expect.2 create mode 120000 tests/f_multithread_no/image.gz create mode 100644 tests/f_multithread_no/name create mode 100644 tests/f_multithread_no/script create mode 100644 tests/f_multithread_ok/expect.1 create mode 100644 tests/f_multithread_ok/image.gz create mode 100644 tests/f_multithread_ok/name create mode 100644 tests/f_multithread_ok/script create mode 100644 tests/f_multithread_preen/expect.1 create mode 100644 tests/f_multithread_preen/expect.2 create mode 120000 tests/f_multithread_preen/image.gz create mode 100644 tests/f_multithread_preen/name create mode 100644 tests/f_multithread_preen/script create mode 100644 tests/f_multithread_yes/expect.1 create mode 100644 tests/f_multithread_yes/expect.2 create mode 120000 tests/f_multithread_yes/image.gz create mode 100644 tests/f_multithread_yes/name create mode 100644 tests/f_multithread_yes/script
Signature · 1 line
2.37.3
RFC 1/72 e2fsck: Fix unbalanced mutex unlock for BOUNCE_MTX
f_crashdisk test failed with UNIX_IO_FORCE_BOUNCE=yes due to unbalanced mutex unlock in below path.
This patch fixes it.
--- lib/ext2fs/unix_io.c | 1 - 1 file changed, 1 deletion(-)
lib/ext2fs/unix_io.c +0 -1
@@ -305,7 +305,6 @@ bounce_read:while (size >0 ) { actual =read (data->dev, data->bounce, align_size);if (actual != align_size) { -mutex_unlock (data,BOUNCE_MTX ); actual = really_read; buf -= really_read; size += really_read;
Signature · 1 line
2.37.3
RFC 2/72 gen_bitmaps: Fix ext2fs_compare_generic_bmap/bitmap logic
In reply to Ritesh Harjani (IBM)Currently this function was not correctly comparing against the right length of the bitmap. Also when we compare bitarray v/s rbtree bitmap the value returned by ext2fs_test_generic_bmap() could be different in these two implementations. Hence only check against boolean value.
--- lib/ext2fs/gen_bitmap.c | 9 ++++++--- lib/ext2fs/gen_bitmap64.c | 10 +++++++--- 2 files changed, 13 insertions(+), 6 deletions(-)
lib/ext2fs/gen_bitmap.c +6 -3
@@ -385,10 +385,13 @@ errcode_t ext2fs_compare_generic_bitmap(errcode_t magic, errcode_t neq, (size_t) (bm1->end - bm1->start)/8)))return neq; -for (i = bm1->end - ((bm1->end - bm1->start) %8 ); i <= bm1->end; i++) -if (ext2fs_fast_test_block_bitmap (gen_bm1, i) != -ext2fs_fast_test_block_bitmap (gen_bm2, i)) +for (i = bm1->start; i <= bm1->end; i++) { +int ret1, ret2; + ret1 = !!ext2fs_fast_test_block_bitmap (gen_bm1, i); + ret2 = !!ext2fs_fast_test_block_bitmap (gen_bm2, i); +if (ret1 != ret2)return neq; + }return 0 ; }
lib/ext2fs/gen_bitmap64.c +7 -3
@@ -629,10 +629,14 @@ errcode_t ext2fs_compare_generic_bmap(errcode_t neq, (bm1->end != bm2->end))return neq; -for (i = bm1->end - ((bm1->end - bm1->start) %8 ); i <= bm1->end; i++) -if (ext2fs_test_generic_bmap (gen_bm1, i) != -ext2fs_test_generic_bmap (gen_bm2, i)) +for (i = bm1->start; i < bm1->end; i++) { +int ret1, ret2; + ret1 = !!ext2fs_test_generic_bmap (gen_bm1, i); + ret2 = !!ext2fs_test_generic_bmap (gen_bm2, i); +if (ret1 != ret2) {return neq; + } + }return 0 ; }
Signature · 1 line
2.37.3
RFC 3/72 blkmap64_ba: Add common helper for bits size calculation
In reply to Ritesh Harjani (IBM)Just a quick common helper for bits size calculation.
--- lib/ext2fs/blkmap64_ba.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
lib/ext2fs/blkmap64_ba.c +13 -7
@@ -40,6 +40,13 @@ struct ext2fs_ba_private_struct {typedef struct ext2fs_ba_private_struct *ext2fs_ba_private ; +#define ba_bits_size (start, end) ((((end) - (start)) / 8 + 1)) + +static size_t ba_bitmap_size (ext2fs_generic_bitmap_64 bitmap) +{ +return (size_t )ba_bits_size (bitmap->start, bitmap->real_end); +} +static errcode_t ba_alloc_private_data (ext2fs_generic_bitmap_64 bitmap) {ext2fs_ba_private bp;
@@ -56,7 +63,7 @@ static errcode_t ba_alloc_private_data (ext2fs_generic_bitmap_64 bitmap)if (retval)return retval; - size = (size_t ) (((bitmap->real_end - bitmap->start) /8 ) +1 ); + size =ba_bitmap_size (bitmap); retval =ext2fs_get_mem (size, &bp->bitarray);if (retval) {
@@ -80,7 +87,7 @@ static errcode_t ba_new_bmap(ext2_filsys fs EXT2FS_ATTR((unused)),return retval; bp = (ext2fs_ba_private ) bitmap->private; - size = (size_t ) (((bitmap->real_end - bitmap->start) /8 ) +1 ); + size =ba_bitmap_size (bitmap);memset (bp->bitarray,0 , size);return 0 ;
@@ -115,7 +122,7 @@ static errcode_t ba_copy_bmap(ext2fs_generic_bitmap_64 src, dest_bp = (ext2fs_ba_private ) dest->private; - size = (size_t ) (((src->real_end - src->start) /8 ) +1 ); + size =ba_bitmap_size (src);memcpy (dest_bp->bitarray, src_bp->bitarray, size);return 0 ;
@@ -145,8 +152,8 @@ static errcode_t ba_resize_bmap(ext2fs_generic_bitmap_64 bmap,return 0 ; } - size = ((bmap->real_end - bmap->start) /8 ) +1 ; - new_size = ((new_real_end - bmap->start) /8 ) +1 ; + size =ba_bitmap_size (bmap); + new_size =ba_bits_size (new_real_end, bmap->start);if (size != new_size) { retval =ext2fs_resize_mem (size, new_size, &bp->bitarray);
@@ -306,8 +313,7 @@ static void ba_clear_bmap(ext2fs_generic_bitmap_64 bitmap) {ext2fs_ba_private bp = (ext2fs_ba_private ) bitmap->private; -memset (bp->bitarray,0 , - (size_t ) (((bitmap->real_end - bitmap->start) /8 ) +1 )); +memset (bp->bitarray,0 ,ba_bitmap_size (bitmap)); }#ifdef ENABLE_BMAP_STATS
Signature · 1 line
2.37.3
RFC 4/72 badblocks: Remove unused badblocks_flags
In reply to Ritesh Harjani (IBM)badblocks_flags is not used anywhere. So just remove it.
--- lib/ext2fs/badblocks.c | 6 +----- lib/ext2fs/ext2fsP.h | 1 - 2 files changed, 1 insertion(+), 6 deletions(-)
lib/ext2fs/badblocks.c +1 -5
@@ -81,11 +81,7 @@ errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest) {errcode_t retval; - retval =make_u32_list (src->size, src->num, src->list, dest); -if (retval) -return retval; - (*dest)->badblocks_flags = src->badblocks_flags; -return 0 ; +return make_u32_list (src->size, src->num, src->list, dest); } errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
lib/ext2fs/ext2fsP.h +0 -1
@@ -34,7 +34,6 @@ struct ext2_struct_u32_list {int num;int size;__u32 *list; -int badblocks_flags; };struct ext2_struct_u32_iterate {
Signature · 1 line
2.37.3
RFC 5/72 badblocks: Add badblocks merge logic
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
Add badblocks merge logic
--- lib/ext2fs/badblocks.c | 75 ++++++++++++++++++++++++++++++++++++++++++ lib/ext2fs/ext2fs.h | 2 ++ 2 files changed, 77 insertions(+)
lib/ext2fs/badblocks.c +75 -0
@@ -56,6 +56,74 @@ static errcode_t make_u32_list(int size, int num, __u32 *list,return 0 ; } +static inline int insert_ok (blk_t *array,int cnt,blk_t new) +{ +return (cnt ==0 || array[cnt -1 ] != new); +} + +/* +* Merge list from src to dest +*/ +static errcode_t merge_u32_list (ext2_u32_list src,ext2_u32_list dest) +{ +errcode_t retval; +int src_count = src->num; +int dest_count = dest->num; +int size = src_count + dest_count; +int size_entry =sizeof (blk_t); +blk_t *array; +blk_t *src_array = src->list; +blk_t *dest_array = dest->list; +int src_index =0 ; +int dest_index =0 ; +int uniq_cnt =0 ; + +if (src->num ==0 ) +return 0 ; + + retval =ext2fs_get_array (size, size_entry, &array); +if (retval) +return retval; + +/* +* It is possible that src list and dest list could be +* duplicated when merging badblocks. +*/ +while (src_index < src_count || dest_index < dest_count) { +if (src_index >= src_count) { +for (; dest_index < dest_count; dest_index++) +if (insert_ok (array, uniq_cnt, dest_array[dest_index])) + array[uniq_cnt++] = dest_array[dest_index]; +break ; + } +if (dest_index >= dest_count) { +for (; src_index < src_count; src_index++) +if (insert_ok (array, uniq_cnt, src_array[src_index])) + array[uniq_cnt++] = src_array[src_index]; +break ; + } +if (src_array[src_index] < dest_array[dest_index]) { +if (insert_ok (array, uniq_cnt, src_array[src_index])) + array[uniq_cnt++] = src_array[src_index]; + src_index++; + }else if (src_array[src_index] > dest_array[dest_index]) { +if (insert_ok (array, uniq_cnt, dest_array[dest_index])) + array[uniq_cnt++] = dest_array[dest_index]; + dest_index++; + }else { +if (insert_ok (array, uniq_cnt, dest_array[dest_index])) + array[uniq_cnt++] = dest_array[dest_index]; + src_index++; + dest_index++; + } + } + +ext2fs_free_mem (&dest->list); + dest->list = array; + dest->num = uniq_cnt; + dest->size = size; +return 0 ; +}/* * This procedure creates an empty u32 list.
@@ -91,6 +159,13 @@ errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src, (ext2_u32_list *) dest); } +errcode_t ext2fs_badblocks_merge (ext2_badblocks_list src, +ext2_badblocks_list dest) +{ +return merge_u32_list ((ext2_u32_list ) src, + (ext2_u32_list ) dest); +} +/* * This procedure frees a badblocks list. *
lib/ext2fs/ext2fs.h +2 -0
@@ -845,6 +845,8 @@ extern int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter,extern void ext2fs_badblocks_list_iterate_end (ext2_badblocks_iterate iter);extern errcode_t ext2fs_badblocks_copy (ext2_badblocks_list src,ext2_badblocks_list *dest); +extern errcode_t ext2fs_badblocks_merge (ext2_badblocks_list src, +ext2_badblocks_list dest);extern int ext2fs_badblocks_equal (ext2_badblocks_list bb1,ext2_badblocks_list bb2);extern int ext2fs_u32_list_count (ext2_u32_list bb);
Signature · 1 line
2.37.3
RFC 6/72 dblist: add dblist merge logic
In reply to Ritesh Harjani (IBM)From: Li Xi <[email protected]>
This adds dblist merge logic.
TODO: Add a unit test for core operations of dblist. Currently there is no such test for this.
--- lib/ext2fs/dblist.c | 36 ++++++++++++++++++++++++++++++++++++ lib/ext2fs/ext2fs.h | 1 + 2 files changed, 37 insertions(+)
lib/ext2fs/dblist.c +36 -0
@@ -119,6 +119,42 @@ errcode_t ext2fs_copy_dblist(ext2_dblist src, ext2_dblist *dest)return 0 ; } +/* +* Merge a directory block list @src to @dest +*/ +errcode_t ext2fs_merge_dblist (ext2_dblist src,ext2_dblist dest) +{ +unsigned long long src_count = src->count; +unsigned long long dest_count = dest->count; +unsigned long long size = src_count + dest_count; +size_t size_entry =sizeof (struct ext2_db_entry2 ); +struct ext2_db_entry2 *array, *array2; +errcode_t retval; + +if (src_count ==0 ) +return 0 ; + +if (src->sorted || (dest->sorted && dest_count !=0 )) +return EINVAL ; + + retval =ext2fs_get_array (size, size_entry, &array); +if (retval) +return retval; + + array2 = array; +memcpy (array, src->list, src_count * size_entry); + array += src_count; +memcpy (array, dest->list, dest_count * size_entry); +ext2fs_free_mem (&dest->list); + + dest->list = array2; + dest->count = src_count + dest_count; + dest->size = size; + dest->sorted =0 ; + +return 0 ; +} +/* * Close a directory block list *
lib/ext2fs/ext2fs.h +1 -0
@@ -1143,6 +1143,7 @@ extern errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk, int blockcnt);extern errcode_t ext2fs_add_dir_block2 (ext2_dblist dblist,ext2_ino_t ino,blk64_t blk,e2_blkcnt_t blockcnt); +extern errcode_t ext2fs_merge_dblist (ext2_dblist src,ext2_dblist dest);extern void ext2fs_dblist_sort (ext2_dblist dblist,EXT2_QSORT_TYPE (*sortfunc)(const void *,const void *));
Signature · 1 line
2.37.3
RFC 7/72 libext2fs: Add rbtree bitmap merge logic
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
This adds rbtree bitmap merge logic.
--- lib/ext2fs/blkmap64_rb.c | 65 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+)
lib/ext2fs/blkmap64_rb.c +65 -0
@@ -977,11 +977,76 @@ static void rb_print_stats(ext2fs_generic_bitmap_64 bitmap EXT2FS_ATTR((unused)) }#endif +static errcode_t rb_merge_bmap (ext2fs_generic_bitmap_64 src, +ext2fs_generic_bitmap_64 dest, +ext2fs_generic_bitmap_64 dup, +ext2fs_generic_bitmap_64 dup_allowed) +{ +struct ext2fs_rb_private *src_bp, *dest_bp, *dup_bp =NULL ; +struct bmap_rb_extent *src_ext; +struct rb_node *src_node; +errcode_t retval =0 ; +int dup_found =0 ; +__u64 i; + + src_bp = (struct ext2fs_rb_private *) src->private; + dest_bp = (struct ext2fs_rb_private *) dest->private; +if (dup) + dup_bp = (struct ext2fs_rb_private *)dup->private; + src_bp->rcursor =NULL ; + dest_bp->rcursor =NULL ; + + src_node =ext2fs_rb_first (&src_bp->root); +while (src_node) { + src_ext =node_to_extent (src_node); + retval =rb_test_clear_bmap_extent (dest, + src_ext->start + src->start, + src_ext->count); +if (retval) { +rb_insert_extent (src_ext->start, src_ext->count, + dest_bp); + goto next; + } + +/* unlikely case, do it one by one block */ +for (i = src_ext->start; + i < src_ext->start + src_ext->count; i++) { + retval =rb_test_clear_bmap_extent (dest, i + src->start,1 ); +if (retval) { +rb_insert_extent (i,1 , dest_bp); +continue ; + } +if (dup_allowed) { + retval =rb_test_clear_bmap_extent (dup_allowed, + i + src->start,1 ); +/* not existed in dup_allowed */ +if (retval) { + dup_found =1 ; +if (dup_bp) +rb_insert_extent (i,1 , dup_bp); + }/* else we conside it not duplicated */ + }else { +if (dup_bp) +rb_insert_extent (i,1 , dup_bp); + dup_found =1 ; + } + } +next: + src_node =ext2fs_rb_next (src_node); + } + +if (dup_found && dup) +return EEXIST ; + +return 0 ; +} +struct ext2_bitmap_ops ext2fs_blkmap64_rbtree = { .type =EXT2FS_BMAP64_RBTREE , .new_bmap = rb_new_bmap, .free_bmap = rb_free_bmap, .copy_bmap = rb_copy_bmap, + .merge_bmap = rb_merge_bmap, .resize_bmap = rb_resize_bmap, .mark_bmap = rb_mark_bmap, .unmark_bmap = rb_unmark_bmap,
Signature · 1 line
2.37.3
RFC 8/72 libext2fs: Add bitmaps merge ops
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
[Note: splitted rb merge tree logic patch such that we seperate out libext2fs changes from e2fsck specific changes]
--- lib/ext2fs/bitmaps.c | 10 ++++++++++ lib/ext2fs/bmap64.h | 4 ++++ lib/ext2fs/ext2fs.h | 8 ++++++++ lib/ext2fs/gen_bitmap64.c | 29 +++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+)
lib/ext2fs/bitmaps.c +10 -0
@@ -45,6 +45,16 @@ errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src, {return (ext2fs_copy_generic_bmap (src, dest)); } + +errcode_t ext2fs_merge_bitmap (ext2fs_generic_bitmap src, +ext2fs_generic_bitmap dest, +ext2fs_generic_bitmap dup, +ext2fs_generic_bitmap dup_allowed) +{ +return ext2fs_merge_generic_bmap (src, dest, dup, + dup_allowed); +} +void ext2fs_set_bitmap_padding (ext2fs_generic_bitmap map) {ext2fs_set_generic_bmap_padding (map);
lib/ext2fs/bmap64.h +4 -0
@@ -72,6 +72,10 @@ struct ext2_bitmap_ops {void (*free_bmap)(ext2fs_generic_bitmap_64 bitmap);errcode_t (*copy_bmap)(ext2fs_generic_bitmap_64 src,ext2fs_generic_bitmap_64 dest); +errcode_t (*merge_bmap)(ext2fs_generic_bitmap_64 src, +ext2fs_generic_bitmap_64 dest, +ext2fs_generic_bitmap_64 dup, +ext2fs_generic_bitmap_64 dup_allowed);errcode_t (*resize_bmap)(ext2fs_generic_bitmap_64 bitmap,__u64 new_end,__u64 new_real_end);
lib/ext2fs/ext2fs.h +8 -0
@@ -870,6 +870,10 @@ extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap);extern void ext2fs_free_inode_bitmap (ext2fs_inode_bitmap bitmap);extern errcode_t ext2fs_copy_bitmap (ext2fs_generic_bitmap src,ext2fs_generic_bitmap *dest); +extern errcode_t ext2fs_merge_bitmap (ext2fs_generic_bitmap src, +ext2fs_generic_bitmap dest, +ext2fs_generic_bitmap dup, +ext2fs_generic_bitmap dup_allowed);extern errcode_t ext2fs_allocate_block_bitmap (ext2_filsys fs,const char *descr,ext2fs_block_bitmap *ret);
@@ -1467,6 +1471,10 @@ void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap);errcode_t ext2fs_resize_generic_bmap (ext2fs_generic_bitmap bmap,__u64 new_end,__u64 new_real_end); +errcode_t ext2fs_merge_generic_bmap (ext2fs_generic_bitmap gen_src, +ext2fs_generic_bitmap gen_dest, +ext2fs_generic_bitmap gen_dup, +ext2fs_generic_bitmap dup_allowed);errcode_t ext2fs_compare_generic_bmap (errcode_t neq,ext2fs_generic_bitmap bm1,ext2fs_generic_bitmap bm2);
lib/ext2fs/gen_bitmap64.c +29 -0
@@ -346,6 +346,35 @@ errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap gen_src,return 0 ; } +errcode_t ext2fs_merge_generic_bmap (ext2fs_generic_bitmap gen_src, +ext2fs_generic_bitmap gen_dest, +ext2fs_generic_bitmap gen_dup, +ext2fs_generic_bitmap gen_dup_allowed) +{ +ext2fs_generic_bitmap_64 src = (ext2fs_generic_bitmap_64 )gen_src; +ext2fs_generic_bitmap_64 dest = (ext2fs_generic_bitmap_64 )gen_dest; +ext2fs_generic_bitmap_64 dup = (ext2fs_generic_bitmap_64 )gen_dup; +ext2fs_generic_bitmap_64 dup_allowed = (ext2fs_generic_bitmap_64 )gen_dup_allowed; + +if (!src || !dest) +return EINVAL ; + +if (!EXT2FS_IS_64_BITMAP (src) || !EXT2FS_IS_64_BITMAP (dest) || + (dup && !EXT2FS_IS_64_BITMAP (dup)) || + (dup_allowed && !EXT2FS_IS_64_BITMAP (dup_allowed))) +return EINVAL ; + +if (src->bitmap_ops != dest->bitmap_ops || + (dup && src->bitmap_ops != dup->bitmap_ops) || + (dup_allowed && src->bitmap_ops != dup_allowed->bitmap_ops)) +return EINVAL ; + +if (src->bitmap_ops->merge_bmap ==NULL ) +return EOPNOTSUPP ; + +return src->bitmap_ops->merge_bmap (src, dest, dup, dup_allowed); +} +errcode_t ext2fs_resize_generic_bmap (ext2fs_generic_bitmap gen_bmap,__u64 new_end,__u64 new_real_end)
Signature · 1 line
2.37.3
RFC 9/72 libext2fs: Add flush cleanup API
In reply to Ritesh Harjani (IBM)From: Li Xi <[email protected]>
--- lib/ext2fs/ext2_io.h | 2 ++ lib/ext2fs/undo_io.c | 19 +++++++++++++++++++ lib/ext2fs/unix_io.c | 24 +++++++++++++++++++++--- 3 files changed, 42 insertions(+), 3 deletions(-)
lib/ext2fs/ext2_io.h +2 -0
@@ -82,6 +82,7 @@ struct struct_io_manager {errcode_t (*write_blk)(io_channel channel,unsigned long block,int count,const void *data);errcode_t (*flush)(io_channel channel); +errcode_t (*flush_cleanup)(io_channel channel);errcode_t (*write_byte)(io_channel channel,unsigned long offset,int count,const void *data); errcode_t (*set_option)(io_channel channel, const char *option,
@@ -116,6 +117,7 @@ struct struct_io_manager {#define io_channel_read_blk (c,b,n,d) ((c)->manager->read_blk((c),b,n,d))#define io_channel_write_blk (c,b,n,d) ((c)->manager->write_blk((c),b,n,d))#define io_channel_flush (c) ((c)->manager->flush((c))) +#define io_channel_flush_cleanup (c) ((c)->manager->flush_cleanup((c)))#define io_channel_bumpcount (c) ((c)->refcount++)/* io_manager.c */
lib/ext2fs/undo_io.c +19 -0
@@ -1024,6 +1024,24 @@ static errcode_t undo_flush(io_channel channel)return retval; } +/* +* Flush data buffers to disk and cleanup the cache. +*/ +static errcode_t undo_flush_cleanup (io_channel channel) +{ +errcode_t retval =0 ; +struct undo_private_data *data; + +EXT2_CHECK_MAGIC (channel,EXT2_ET_MAGIC_IO_CHANNEL ); + data = (struct undo_private_data *) channel->private_data; +EXT2_CHECK_MAGIC (data,EXT2_ET_MAGIC_UNIX_IO_CHANNEL ); + +if (data->real) + retval =io_channel_flush_cleanup (data->real); + +return retval; +} +static errcode_t undo_set_option (io_channel channel,const char *option,const char *arg) {
@@ -1095,6 +1113,7 @@ static struct struct_io_manager struct_undo_manager = { .read_blk = undo_read_blk, .write_blk = undo_write_blk, .flush = undo_flush, + .flush_cleanup = undo_flush_cleanup, .write_byte = undo_write_byte, .set_option = undo_set_option, .get_stats = undo_get_stats,
lib/ext2fs/unix_io.c +21 -3
@@ -1173,9 +1173,9 @@ static errcode_t unix_write_byte(io_channel channel, unsigned long offset, }/* -* Flush data buffers to disk. +* Flush data buffers to disk and invalidate cache if needed */ -static errcode_t unix_flush (io_channel channel) +static errcode_t _unix_flush (io_channel channel,int invalidate) {struct unix_private_data *data;errcode_t retval =0 ;
@@ -1185,7 +1185,7 @@ static errcode_t unix_flush(io_channel channel)EXT2_CHECK_MAGIC (data,EXT2_ET_MAGIC_UNIX_IO_CHANNEL );#ifndef NO_IO_CACHE - retval =flush_cached_blocks (channel, data,0 ); + retval =flush_cached_blocks (channel, data, invalidate);#endif #ifdef HAVE_FSYNC if (!retval &&fsync (data->dev) !=0 )
@@ -1194,6 +1194,22 @@ static errcode_t unix_flush(io_channel channel)return retval; } +/* +* Flush data buffers to disk. +*/ +static errcode_t unix_flush (io_channel channel) +{ +return _unix_flush (channel,0 ); +} + +/* +* Flush data buffers to disk and invalidate cache. +*/ +static errcode_t unix_flush_cleanup (io_channel channel) +{ +return _unix_flush (channel,1 ); +} +static errcode_t unix_set_option (io_channel channel,const char *option,const char *arg) {
@@ -1383,6 +1399,7 @@ static struct struct_io_manager struct_unix_manager = { .discard = unix_discard, .cache_readahead = unix_cache_readahead, .zeroout = unix_zeroout, + .flush_cleanup = unix_flush_cleanup, };io_manager unix_io_manager = &struct_unix_manager;
@@ -1404,6 +1421,7 @@ static struct struct_io_manager struct_unixfd_manager = { .discard = unix_discard, .cache_readahead = unix_cache_readahead, .zeroout = unix_zeroout, + .flush_cleanup = unix_flush_cleanup, };io_manager unixfd_io_manager = &struct_unixfd_manager;
Signature · 1 line
2.37.3
RFC 10/72 libext2fs: merge icounts after thread finishes
In reply to Ritesh Harjani (IBM)From: Li Xi <[email protected]>
Merge inode_count and inode_link_info properly after threads finish.
--- lib/ext2fs/ext2fs.h | 1 + lib/ext2fs/icount.c | 103 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+)
lib/ext2fs/ext2fs.h +1 -0
@@ -1546,6 +1546,7 @@ extern errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret);extern errcode_t ext2fs_icount_store (ext2_icount_t icount,ext2_ino_t ino,__u16 count); +extern errcode_t ext2fs_icount_merge (ext2_icount_t src,ext2_icount_t dest);extern ext2_ino_t ext2fs_get_icount_size (ext2_icount_t icount);errcode_t ext2fs_icount_validate (ext2_icount_t icount,FILE *);
lib/ext2fs/icount.c +103 -0
115 lines not on this page · raw message
Signature · 1 line
2.37.3
RFC 11/72 libext2fs: merge quota context after threads finish
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
Every threads calculate its own quota accounting,
merge them after threads finish.
--- lib/support/mkquota.c | 39 +++++++++++++++++++++++++++++++++++++++ lib/support/quotaio.h | 3 +++ 2 files changed, 42 insertions(+)
lib/support/mkquota.c +39 -0
@@ -618,6 +618,45 @@ out:return err; } +static errcode_t merge_usage (dict_t *dest,dict_t *src) +{ +dnode_t *n; +struct dquot *src_dq, *dest_dq; + +for (n =dict_first (src); n; n =dict_next (src, n)) { + src_dq =dnode_get (n); +if (!src_dq) +continue ; + dest_dq =get_dq (dest, src_dq->dq_id); +if (dest_dq ==NULL ) +return -ENOMEM ; + dest_dq->dq_dqb.dqb_curspace += src_dq->dq_dqb.dqb_curspace; + dest_dq->dq_dqb.dqb_curinodes += src_dq->dq_dqb.dqb_curinodes; + } + +return 0 ; +} + + +errcode_t quota_merge_and_update_usage (quota_ctx_t dest_qctx, +quota_ctx_t src_qctx) +{ +dict_t *dict; +enum quota_type qtype; +errcode_t retval =0 ; + +for (qtype =0 ; qtype <MAXQUOTAS ; qtype++) { + dict = src_qctx->quota_dict[qtype]; +if (!dict) +continue ; + retval =merge_usage (dest_qctx->quota_dict[qtype], dict); +if (retval) +break ; + } + +return retval; +} +/* * Compares the measured quota in qctx->quota_dict with that in the quota inode * on disk and updates the limits in qctx->quota_dict. 'usage_inconsistent' is
lib/support/quotaio.h +3 -0
@@ -40,6 +40,7 @@#include "ext2fs/ext2_fs.h" #include "ext2fs/ext2fs.h" #include "dqblk_v2.h" +#include "support/dict.h" typedef int64_t qsize_t ;/* Type in which we store size limitations */
@@ -236,6 +237,8 @@ int quota_file_exists(ext2_filsys fs, enum quota_type qtype);void quota_set_sb_inum (ext2_filsys fs,ext2_ino_t ino,enum quota_type qtype);errcode_t quota_compare_and_update (quota_ctx_t qctx,enum quota_type qtype,int *usage_inconsistent); +errcode_t quota_merge_and_update_usage (quota_ctx_t dest_qctx, +quota_ctx_t src_qctx);int parse_quota_opts (const char *opts,int (*func)(char *));/* parse_qtype.c */
Signature · 1 line
2.37.3
RFC 12/72 libext2fs: dupfs: Add fs clone & merge api
In reply to Ritesh Harjani (IBM)From: Saranya Muruganandam <[email protected]>
This patch mainly adds "parent" & "clone_flags" member in ext2_filsys struct for enabling multi-threading. Based on what CLONE flags will be passed from the client of libext2fs down to ext2fs_clone_fs(), those structures/bitmaps will be cloned (thread-aware child copy) and rest will be shared with the parent fs.
The same flags will also help to merge those cloned bitmap structures back into the parent bitmaps when ext2fs_merge_fs() will be called with childfs struct.
--- lib/ext2fs/dupfs.c | 183 ++++++++++++++++++++++++++++++++++++++++++++ lib/ext2fs/ext2fs.h | 23 ++++++ 2 files changed, 206 insertions(+)
lib/ext2fs/dupfs.c +183 -0
@@ -14,8 +14,12 @@#if HAVE_UNISTD_H #include <unistd.h> #endif +#if HAVE_PTHREAD_H +#include <pthread.h> +#endif #include <time.h> #include <string.h> +#include <assert.h> #include "ext2_fs.h" #include "ext2fsP.h"
@@ -120,3 +124,182 @@ errout: } +#ifdef HAVE_PTHREAD +errcode_t ext2fs_clone_fs (ext2_filsys fs,ext2_filsys *dest,unsigned int flags) +{ +errcode_t retval; +ext2_filsys childfs; + +EXT2_CHECK_MAGIC (fs,EXT2_ET_MAGIC_EXT2FS_FILSYS ); + + retval =ext2fs_get_mem (sizeof (struct struct_ext2_filsys ), &childfs); +if (retval) +return retval; + +/* make an exact copy implying lists and memory structures are shared */ +memcpy (childfs, fs,sizeof (struct struct_ext2_filsys )); + childfs->inode_map =NULL ; + childfs->block_map =NULL ; + childfs->badblocks =NULL ; + childfs->dblist =NULL ; + +pthread_mutex_lock (&fs->refcount_mutex); + fs->refcount++; +pthread_mutex_unlock (&fs->refcount_mutex); + +if ((flags &EXT2FS_CLONE_INODE ) && fs->inode_map) { + retval =ext2fs_copy_bitmap (fs->inode_map, &childfs->inode_map); +if (retval) +return retval; + childfs->inode_map->fs = childfs; + } + +if ((flags &EXT2FS_CLONE_BLOCK ) && fs->block_map) { + retval =ext2fs_copy_bitmap (fs->block_map, &childfs->block_map); +if (retval) +return retval; + childfs->block_map->fs = childfs; + } + +if ((flags &EXT2FS_CLONE_BADBLOCKS ) && fs->badblocks) { + retval =ext2fs_badblocks_copy (fs->badblocks, &childfs->badblocks); +if (retval) +return retval; + } + +if ((flags &EXT2FS_CLONE_DBLIST ) && fs->dblist) { + retval =ext2fs_copy_dblist (fs->dblist, &childfs->dblist); +if (retval) +return retval; + childfs->dblist->fs = childfs; + } + +/* icache when NULL will be rebuilt if needed */ + childfs->icache =NULL ; + + childfs->clone_flags = flags; + childfs->parent = fs; + *dest = childfs; + +return 0 ; +} + +errcode_t ext2fs_merge_fs (ext2_filsys *thread_fs) +{ +ext2_filsys fs = *thread_fs; +errcode_t retval =0 ; +ext2_filsys dest = fs->parent; +ext2_filsys src = fs; +unsigned int flags = fs->clone_flags; +struct ext2_inode_cache *icache; +io_channel dest_io; +io_channel dest_image_io; +ext2fs_inode_bitmap inode_map; +ext2fs_block_bitmap block_map; +ext2_badblocks_list badblocks; +ext2_dblist dblist; +void *priv_data; +int fsflags; + +pthread_mutex_lock (&fs->refcount_mutex); + fs->refcount--; +assert (fs->refcount >=0 ); +pthread_mutex_unlock (&fs->refcount_mutex); + + icache = dest->icache; + dest_io = dest->io; + dest_image_io = dest->image_io; + inode_map = dest->inode_map; + block_map = dest->block_map; + badblocks = dest->badblocks; + dblist = dest->dblist; + priv_data = dest->priv_data; + fsflags = dest->flags; + +memcpy (dest, src,sizeof (struct struct_ext2_filsys )); + + dest->io = dest_io; + dest->image_io = dest_image_io; + dest->icache = icache; + dest->inode_map = inode_map; + dest->block_map = block_map; + dest->badblocks = badblocks; + dest->dblist = dblist; + dest->priv_data = priv_data; +if (dest->dblist) + dest->dblist->fs = dest; + dest->flags = src->flags | fsflags; +if (!(src->flags &EXT2_FLAG_VALID ) || !(dest->flags &EXT2_FLAG_VALID )) +ext2fs_unmark_valid (dest); + +if ((flags &EXT2FS_CLONE_INODE ) && src->inode_map) { +if (dest->inode_map ==NULL ) { + dest->inode_map = src->inode_map; + src->inode_map =NULL ; + }else { + retval =ext2fs_merge_bitmap (src->inode_map, dest->inode_map,NULL ,NULL ); +if (retval) + goto out; + } + dest->inode_map->fs = dest; + } + +if ((flags &EXT2FS_CLONE_BLOCK ) && src->block_map) { +if (dest->block_map ==NULL ) { + dest->block_map = src->block_map; + src->block_map =NULL ; + }else { + retval =ext2fs_merge_bitmap (src->block_map, dest->block_map,NULL ,NULL ); +if (retval) + goto out; + } + dest->block_map->fs = dest; + } + +if ((flags &EXT2FS_CLONE_BADBLOCKS ) && src->badblocks) { +if (dest->badblocks ==NULL ) + retval =ext2fs_badblocks_copy (src->badblocks, &dest->badblocks); +else + retval =ext2fs_badblocks_merge (src->badblocks, dest->badblocks); +if (retval) + goto out; + } + +if ((flags &EXT2FS_CLONE_DBLIST ) && src->dblist) { +if (dest->dblist ==NULL ) { + dest->dblist = src->dblist; + src->dblist =NULL ; + }else { + retval =ext2fs_merge_dblist (src->dblist, dest->dblist); +if (retval) + goto out; + } + dest->dblist->fs = dest; + } + +if (src->icache) { +ext2fs_free_inode_cache (src->icache); + src->icache =NULL ; + } + +out: +if (src->io) +io_channel_close (src->io); + +if ((flags &EXT2FS_CLONE_INODE ) && src->inode_map) +ext2fs_free_generic_bmap (src->inode_map); +if ((flags &EXT2FS_CLONE_BLOCK ) && src->block_map) +ext2fs_free_generic_bmap (src->block_map); +if ((flags &EXT2FS_CLONE_BADBLOCKS ) && src->badblocks) +ext2fs_badblocks_list_free (src->badblocks); +if ((flags &EXT2FS_CLONE_DBLIST ) && src->dblist) { +ext2fs_free_dblist (src->dblist); + src->dblist =NULL ; + } + +ext2fs_free_mem (&src); + *thread_fs =NULL ; + +return retval; +} +#endif
lib/ext2fs/ext2fs.h +23 -0
@@ -12,6 +12,10 @@#ifndef _EXT2FS_EXT2FS_H#define _EXT2FS_EXT2FS_H +#ifdef HAVE_PTHREAD_H +#include <pthread.h> +#endif +#ifdef __GNUC__#define EXT2FS_ATTR (x) __attribute__(x)#else
@@ -331,6 +335,13 @@ struct struct_ext2_filsys {struct ext2fs_hashmap * block_sha_map;const struct ext2fs_nls_table *encoding; + +#ifdef HAVE_PTHREAD +struct struct_ext2_filsys *parent; +size_t refcount; +pthread_mutex_t refcount_mutex; +unsigned int clone_flags; +#endif };#if EXT2_FLAT_INCLUDES
@@ -1057,6 +1068,18 @@ extern errcode_t ext2fs_move_blocks(ext2_filsys fs,/* check_desc.c */ extern errcode_t ext2fs_check_desc (ext2_filsys fs); +#ifdef HAVE_PTHREAD +/* flags for ext2fs_clone_fs */ +#define EXT2FS_CLONE_BLOCK 0x0001 +#define EXT2FS_CLONE_INODE 0x0002 +#define EXT2FS_CLONE_BADBLOCKS 0x0004 +#define EXT2FS_CLONE_DBLIST 0x0008 + +extern errcode_t ext2fs_clone_fs (ext2_filsys fs,ext2_filsys *dest, +unsigned int flags); +extern errcode_t ext2fs_merge_fs (ext2_filsys *fs); +#endif +/* closefs.c */ extern errcode_t ext2fs_close (ext2_filsys fs);extern errcode_t ext2fs_close2 (ext2_filsys fs,int flags);
Signature · 1 line
2.37.3
RFC 13/72 tst_badblocks: Add unit test to verify badblocks list merge api
In reply to Ritesh Harjani (IBM)Add unit test to verify badblocks list merge api i.e. ext2fs_badblocks_merge()
--- lib/ext2fs/tst_badblocks.c | 61 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-)
lib/ext2fs/tst_badblocks.c +59 -2
@@ -119,6 +119,40 @@ static void print_list(badblocks_list bb, int verify) } } +static void do_list_merge_verify (badblocks_list bb,badblocks_list bbm,int verify) +{ +errcode_t retval; +badblocks_iterate iter; +blk_t blk; +int i, ok; + + retval =ext2fs_badblocks_merge (bb, bbm); +if (retval) { +com_err ("do_list_merge_verify" , retval,"while doing list merge" ); +return ; + } + +if (!verify) +return ; + + retval =ext2fs_badblocks_list_iterate_begin (bb, &iter); +if (retval) { +com_err ("do_list_merge_verify" , retval,"while setting up iterator" ); +return ; + } + +while (ext2fs_badblocks_list_iterate (iter, &blk)) { + retval =ext2fs_badblocks_list_test (bbm, blk); +if (retval ==0 ) { +printf (" --- NOT OK\n" ); + test_fail++; +return ; + } + } +ext2fs_badblocks_list_iterate_end (iter); +printf (" --- OK\n" ); +} +static void validate_test_seq (badblocks_list bb,blk_t *vec) {int i, match, ok;
@@ -275,13 +309,13 @@ out:int main (int argc,char **argv) { -badblocks_list bb1, bb2, bb3, bb4, bb5; +badblocks_list bb1, bb2, bb3, bb4, bb5, bbm;int equal;errcode_t retval;add_error_table (&et_ext2_error_table); - bb1 = bb2 = bb3 = bb4 = bb5 =0 ; + bb1 = bb2 = bb3 = bb4 = bb5 = bbm =0 ;printf ("test1: " ); retval =create_test_list (test1, &bb1);
@@ -346,6 +380,27 @@ int main(int argc, char **argv)printf ("\n" ); } +printf ("Create merge bb list\n" ); + retval =ext2fs_badblocks_list_create (&bbm,5 ); +if (retval) { +com_err ("ext2fs_badblocks_list_create" , retval,"while creating list" ); + test_fail++; + } + +printf ("Merge & Verify all bb{1..5} into bbm\n" ); +if (bb1 && bb2 && bb3 && bb4 && bb5 && bbm) { +printf ("Merge bb1 into bbm" ); +do_list_merge_verify (bb1, bbm,1 ); +printf ("Merge bb2 into bbm" ); +do_list_merge_verify (bb2, bbm,1 ); +printf ("Merge bb3 into bbm" ); +do_list_merge_verify (bb3, bbm,1 ); +printf ("Merge bb4 into bbm" ); +do_list_merge_verify (bb4, bbm,1 ); +printf ("Merge bb5 into bbm" ); +do_list_merge_verify (bb5, bbm,1 ); + } +file_test (bb4);file_test_invalid (bb4);
@@ -363,6 +418,8 @@ int main(int argc, char **argv)ext2fs_badblocks_list_free (bb4);if (bb5)ext2fs_badblocks_list_free (bb5); +if (bbm) +ext2fs_badblocks_list_free (bbm);return test_fail;
Signature · 1 line
2.37.3
RFC 14/72 tst_bitmaps_standalone: Add copy and merge bitmaps test
In reply to Ritesh Harjani (IBM)This adds a basic copy and merge api test for rbtree bitmap type.
--- lib/ext2fs/Makefile.in | 25 +++- lib/ext2fs/tst_bitmaps_standalone.c | 170 ++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+), 6 deletions(-) create mode 100644 lib/ext2fs/tst_bitmaps_standalone.c
lib/ext2fs/Makefile.in +19 -6
@@ -227,6 +227,7 @@ SRCS= ext2_err.c \ $(srcdir)/write_bb_file.c \ $(srcdir)/rbtree.c \ $(srcdir)/tst_libext2fs.c \ + $(srcdir)/tst_bitmaps_standalone.c \ $(DEBUG_SRCS) HFILES= bitops.h ext2fs.h ext2_io.h ext2_fs.h ext2_ext_attr.h ext3_extents.h \
@@ -328,9 +329,9 @@ tst_getsectsize: tst_getsectsize.o getsectsize.o $(STATIC_LIBEXT2FS) \ $(ALL_LDFLAGS) $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) \ $(SYSLIBS) -tst_types.o: $(srcdir)/tst_types.c ext2_types.h +tst_types.o: $(srcdir)/tst_types.c ext2_types.h -tst_types: tst_types.o ext2_types.h +tst_types: tst_types.o ext2_types.h $(E) " LD $@" $(Q) $(CC) -o tst_types tst_types.o $(ALL_LDFLAGS) $(SYSLIBS)
@@ -362,6 +363,11 @@ tst_sha512: $(srcdir)/sha512.c $(srcdir)/ext2_fs.h $(Q) $(CC) $(ALL_LDFLAGS) $(ALL_CFLAGS) -o tst_sha512 \ $(srcdir)/sha512.c -DUNITTEST $(SYSLIBS) +tst_bitmaps_standalone: tst_bitmaps_standalone.o $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) + $(E) " LD $@" + $(Q) $(CC) -o tst_bitmaps_standalone tst_bitmaps_standalone.o $(ALL_LDFLAGS) \ + $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(SYSLIBS) + ext2_tdbtool: tdbtool.o $(E) " LD $@" $(Q) $(CC) -o ext2_tdbtool tdbtool.o tdb.o $(ALL_LDFLAGS) $(SYSLIBS)
@@ -533,7 +539,7 @@ mkjournal: mkjournal.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR) fullcheck check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \ tst_super_size tst_types tst_inode_size tst_csum tst_crc32c tst_bitmaps \ tst_inline tst_inline_data tst_libext2fs tst_sha256 tst_sha512 \ - tst_digest_encode tst_getsize tst_getsectsize + tst_digest_encode tst_getsize tst_getsectsize tst_bitmaps_standalone $(TESTENV) ./tst_bitops $(TESTENV) ./tst_badblocks $(TESTENV) ./tst_iscan
@@ -556,6 +562,7 @@ fullcheck check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \ $(TESTENV) ./tst_bitmaps -l -f $(srcdir)/tst_bitmaps_cmds > tst_bitmaps_out diff $(srcdir)/tst_bitmaps_exp tst_bitmaps_out $(TESTENV) ./tst_digest_encode + $(TESTENV) ./tst_bitmaps_standalone installdirs:: $(E) " MKDIR_P $(libdir) $(includedir)/ext2fs"
@@ -581,7 +588,7 @@ install:: all $(HFILES) $(HFILES_IN) installdirs ext2fs.pc uninstall:: $(RM) -f $(DESTDIR)$(libdir)/libext2fs.a \ $(DESTDIR)$(pkgconfigdir)/ext2fs.pc - $(RM) -rf $(DESTDIR)$(includedir)/ext2fs + $(RM) -rf $(DESTDIR)$(includedir)/ext2fs clean:: $(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* \
@@ -590,7 +597,7 @@ clean:: tst_bitops tst_types tst_icount tst_super_size tst_csum \ tst_bitmaps tst_bitmaps_out tst_extents tst_inline \ tst_inline_data tst_inode_size tst_bitmaps_cmd.c \ - tst_digest_encode tst_sha256 tst_sha512 \ + tst_digest_encode tst_sha256 tst_sha512 tst_bitmaps_standalone \ ext2_tdbtool mkjournal debug_cmds.c tst_cmds.c extent_cmds.c \ ../libext2fs.a ../libext2fs_p.a ../libext2fs_chk.a \ crc32c_table.h gen_crc32ctable tst_crc32c tst_libext2fs \
@@ -646,7 +653,7 @@ windows_io.o: $(srcdir)/windows_io.c $(top_builddir)/lib/config.h \ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h $(srcdir)/ext2fsP.h # +++ Dependency line eater +++ -# +# # Makefile dependencies follow. This must be the last section in # the Makefile.in file #
@@ -1156,6 +1163,12 @@ tst_iscan.o: $(srcdir)/tst_iscan.c $(top_builddir)/lib/config.h \ $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ $(srcdir)/ext2_ext_attr.h $(srcdir)/hashmap.h $(srcdir)/bitops.h +tst_bitmaps_standalone.o: $(srcdir)/tst_bitmaps_standalone.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \ + $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \ + $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \ + $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ + $(srcdir)/ext2_ext_attr.h $(srcdir)/hashmap.h $(srcdir)/bitops.h undo_io.o: $(srcdir)/undo_io.c $(top_builddir)/lib/config.h \ $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
lib/ext2fs/tst_bitmaps_standalone.c new file +170 -0
170 lines not on this page · raw message
Signature · 1 line
2.37.3
RFC 15/72 tst_bitmaps_pthread: Add merge bitmaps test using pthreads
In reply to Ritesh Harjani (IBM)This patch adds a test to verify the core bitmaps merge APIs for rbtree bitmap type.
--- lib/ext2fs/Makefile.in | 17 ++- lib/ext2fs/tst_bitmaps_pthread.c | 247 +++++++++++++++++++++++++++++++ 2 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 lib/ext2fs/tst_bitmaps_pthread.c
lib/ext2fs/Makefile.in +16 -1
@@ -228,6 +228,7 @@ SRCS= ext2_err.c \ $(srcdir)/rbtree.c \ $(srcdir)/tst_libext2fs.c \ $(srcdir)/tst_bitmaps_standalone.c \ + $(srcdir)/tst_bitmaps_pthread.c \ $(DEBUG_SRCS) HFILES= bitops.h ext2fs.h ext2_io.h ext2_fs.h ext2_ext_attr.h ext3_extents.h \
@@ -368,6 +369,11 @@ tst_bitmaps_standalone: tst_bitmaps_standalone.o $(STATIC_LIBEXT2FS) $(DEPSTATIC $(Q) $(CC) -o tst_bitmaps_standalone tst_bitmaps_standalone.o $(ALL_LDFLAGS) \ $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(SYSLIBS) +tst_bitmaps_pthread: tst_bitmaps_pthread.o $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) + $(E) " LD $@" + $(Q) $(CC) -o tst_bitmaps_pthread tst_bitmaps_pthread.o $(ALL_LDFLAGS) \ + $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(SYSLIBS) + ext2_tdbtool: tdbtool.o $(E) " LD $@" $(Q) $(CC) -o ext2_tdbtool tdbtool.o tdb.o $(ALL_LDFLAGS) $(SYSLIBS)
@@ -539,7 +545,8 @@ mkjournal: mkjournal.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR) fullcheck check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \ tst_super_size tst_types tst_inode_size tst_csum tst_crc32c tst_bitmaps \ tst_inline tst_inline_data tst_libext2fs tst_sha256 tst_sha512 \ - tst_digest_encode tst_getsize tst_getsectsize tst_bitmaps_standalone + tst_digest_encode tst_getsize tst_getsectsize tst_bitmaps_standalone \ + tst_bitmaps_pthread $(TESTENV) ./tst_bitops $(TESTENV) ./tst_badblocks $(TESTENV) ./tst_iscan
@@ -563,6 +570,7 @@ fullcheck check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \ diff $(srcdir)/tst_bitmaps_exp tst_bitmaps_out $(TESTENV) ./tst_digest_encode $(TESTENV) ./tst_bitmaps_standalone + $(TESTENV) ./tst_bitmaps_pthread installdirs:: $(E) " MKDIR_P $(libdir) $(includedir)/ext2fs"
@@ -598,6 +606,7 @@ clean:: tst_bitmaps tst_bitmaps_out tst_extents tst_inline \ tst_inline_data tst_inode_size tst_bitmaps_cmd.c \ tst_digest_encode tst_sha256 tst_sha512 tst_bitmaps_standalone \ + tst_bitmaps_pthread \ ext2_tdbtool mkjournal debug_cmds.c tst_cmds.c extent_cmds.c \ ../libext2fs.a ../libext2fs_p.a ../libext2fs_chk.a \ crc32c_table.h gen_crc32ctable tst_crc32c tst_libext2fs \
@@ -1169,6 +1178,12 @@ tst_bitmaps_standalone.o: $(srcdir)/tst_bitmaps_standalone.c $(top_builddir)/lib $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ $(srcdir)/ext2_ext_attr.h $(srcdir)/hashmap.h $(srcdir)/bitops.h +tst_bitmaps_pthread.o: $(srcdir)/tst_bitmaps_pthread.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \ + $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \ + $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \ + $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ + $(srcdir)/ext2_ext_attr.h $(srcdir)/hashmap.h $(srcdir)/bitops.h undo_io.o: $(srcdir)/undo_io.c $(top_builddir)/lib/config.h \ $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
lib/ext2fs/tst_bitmaps_pthread.c new file +247 -0
247 lines not on this page · raw message
Signature · 1 line
2.37.3
RFC 16/72 tst_libext2fs_pthread: Add libext2fs merge/clone unit tests
In reply to Ritesh Harjani (IBM)This adds a unit tests for libext2fs merge/clone apis and uses pthreads to test the functionality correctly.
TODO:
We can also add EXT2FS_CLONE_BADBLOCKS and EXT2FS_CLONE_DBLIST test as well into it.
--- lib/ext2fs/Makefile.in | 17 +- lib/ext2fs/tst_libext2fs_pthread.c | 315 +++++++++++++++++++++++++++++ 2 files changed, 330 insertions(+), 2 deletions(-) create mode 100644 lib/ext2fs/tst_libext2fs_pthread.c
lib/ext2fs/Makefile.in +15 -2
@@ -229,6 +229,7 @@ SRCS= ext2_err.c \ $(srcdir)/tst_libext2fs.c \ $(srcdir)/tst_bitmaps_standalone.c \ $(srcdir)/tst_bitmaps_pthread.c \ + $(srcdir)/tst_libext2fs_pthread.c \ $(DEBUG_SRCS) HFILES= bitops.h ext2fs.h ext2_io.h ext2_fs.h ext2_ext_attr.h ext3_extents.h \
@@ -374,6 +375,11 @@ tst_bitmaps_pthread: tst_bitmaps_pthread.o $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCO $(Q) $(CC) -o tst_bitmaps_pthread tst_bitmaps_pthread.o $(ALL_LDFLAGS) \ $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(SYSLIBS) +tst_libext2fs_pthread: tst_libext2fs_pthread.o $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) + $(E) " LD $@" + $(Q) $(CC) -o tst_libext2fs_pthread tst_libext2fs_pthread.o $(ALL_LDFLAGS) \ + $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(SYSLIBS) + ext2_tdbtool: tdbtool.o $(E) " LD $@" $(Q) $(CC) -o ext2_tdbtool tdbtool.o tdb.o $(ALL_LDFLAGS) $(SYSLIBS)
@@ -546,7 +552,7 @@ fullcheck check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \ tst_super_size tst_types tst_inode_size tst_csum tst_crc32c tst_bitmaps \ tst_inline tst_inline_data tst_libext2fs tst_sha256 tst_sha512 \ tst_digest_encode tst_getsize tst_getsectsize tst_bitmaps_standalone \ - tst_bitmaps_pthread + tst_bitmaps_pthread tst_libext2fs_pthread $(TESTENV) ./tst_bitops $(TESTENV) ./tst_badblocks $(TESTENV) ./tst_iscan
@@ -571,6 +577,7 @@ fullcheck check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \ $(TESTENV) ./tst_digest_encode $(TESTENV) ./tst_bitmaps_standalone $(TESTENV) ./tst_bitmaps_pthread + $(TESTENV) ./tst_libext2fs_pthread installdirs:: $(E) " MKDIR_P $(libdir) $(includedir)/ext2fs"
@@ -606,7 +613,7 @@ clean:: tst_bitmaps tst_bitmaps_out tst_extents tst_inline \ tst_inline_data tst_inode_size tst_bitmaps_cmd.c \ tst_digest_encode tst_sha256 tst_sha512 tst_bitmaps_standalone \ - tst_bitmaps_pthread \ + tst_bitmaps_pthread tst_libext2fs_pthread \ ext2_tdbtool mkjournal debug_cmds.c tst_cmds.c extent_cmds.c \ ../libext2fs.a ../libext2fs_p.a ../libext2fs_chk.a \ crc32c_table.h gen_crc32ctable tst_crc32c tst_libext2fs \
@@ -1184,6 +1191,12 @@ tst_bitmaps_pthread.o: $(srcdir)/tst_bitmaps_pthread.c $(top_builddir)/lib/confi $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ $(srcdir)/ext2_ext_attr.h $(srcdir)/hashmap.h $(srcdir)/bitops.h +tst_libext2fs_pthread.o: $(srcdir)/tst_libext2fs_pthread.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \ + $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \ + $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \ + $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ + $(srcdir)/ext2_ext_attr.h $(srcdir)/hashmap.h $(srcdir)/bitops.h undo_io.o: $(srcdir)/undo_io.c $(top_builddir)/lib/config.h \ $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
lib/ext2fs/tst_libext2fs_pthread.c new file +315 -0
315 lines not on this page · raw message
Signature · 1 line
2.37.3
RFC 17/72 libext2fs: Add support for ext2fs_test_block_bitmap_range2_valid()
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
This adds the support in libext2fs to query whether the block range is valid or not (within range) given the block bitmap.
Also to avoid duplicate warning messages in case of invalid blocks.
This will be later used in pass1 of e2fsck is_blocks_used() function to check whether the given block range is valid or not to avoid duplicate warning resulting from ext2fs_test_block_bitmap_range2()
--- lib/ext2fs/bitops.h | 2 ++ lib/ext2fs/gen_bitmap64.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+)
lib/ext2fs/bitops.h +2 -0
@@ -120,6 +120,8 @@ extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,extern void ext2fs_set_bitmap_padding (ext2fs_generic_bitmap map);extern __u32 ext2fs_get_generic_bitmap_start (ext2fs_generic_bitmap bitmap);extern __u32 ext2fs_get_generic_bitmap_end (ext2fs_generic_bitmap bitmap); +extern int ext2fs_test_block_bitmap_range2_valid (ext2fs_block_bitmap bitmap, +blk64_t block,unsigned int num);/* 64-bit versions */
lib/ext2fs/gen_bitmap64.c +33 -0
@@ -731,6 +731,39 @@ int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,return bmap->bitmap_ops->test_clear_bmap_extent (bmap, block, num); } +int ext2fs_test_block_bitmap_range2_valid (ext2fs_block_bitmap bitmap, +blk64_t block,unsigned int num) +{ +ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64 )bitmap; +__u64 end = block + num; + +if (!bmap) +return 0 ; + +if (EXT2FS_IS_32_BITMAP (bmap)) { +if ((block & ~0xffffffffULL ) || + ((block+num-1 ) & ~0xffffffffULL )) { +return 0 ; + } + } + +if (!EXT2FS_IS_64_BITMAP (bmap)) +return 0 ; + +/* convert to clusters if necessary */ + block >>= bmap->cluster_bits; + end += (1 << bmap->cluster_bits) -1 ; + end >>= bmap->cluster_bits; + num = end - block; + +if ((block < bmap->start) || (block > bmap->end) || + (block+num-1 > bmap->end)) +return 0 ; + +return 1 ; +} + +void ext2fs_mark_block_bitmap_range2 (ext2fs_block_bitmap gen_bmap,blk64_t block,unsigned int num) {
Signature · 1 line
2.37.3
RFC 18/72 libext2fs: Add support to get average group count
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
number of threads in pfsck should not exceed flex bg numbers. This patch adds the support in libext2fs to calculate ext2fs_get_avg_group() which returns an average group count which each thread has to scan.
fs->fs_num_threads will be set by the client, in this case e2fsck. No. of threads will be passed along with -m option while running e2fsck. That will also set fs->fs_num_threads, which will help in controlling the amount of memory consumed to maintain in memory data structures (per thread) in case of multiple parallel threads (pfsck) to avoid oom.
--- lib/ext2fs/ext2fs.h | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-)
lib/ext2fs/ext2fs.h +31 -1
@@ -279,10 +279,11 @@ struct struct_ext2_filsys {int cluster_ratio_bits;__u16 default_bitmap_type;__u16 pad; +__u32 fs_num_threads;/* * Reserved for future expansion */ -__u32 reserved[5 ]; +__u32 reserved[4 ];/* * Reserved for the use of the calling application.
@@ -2231,6 +2232,35 @@ ext2fs_orphan_block_tail(ext2_filsys fs, char *buf) sizeof(struct ext4_orphan_block_tail)); } +static dgrp_t ext2fs_get_avg_group (ext2_filsys fs) +{ +#ifdef HAVE_PTHREAD +dgrp_t average_group; +unsigned flexbg_size; + +if (fs->fs_num_threads <=1 ) +return fs->group_desc_count; + + average_group = fs->group_desc_count / fs->fs_num_threads; +if (average_group <=1 ) +return 1 ; + +if (ext2fs_has_feature_flex_bg (fs->super)) { +int times =1 ; + + flexbg_size =1 << fs->super->s_log_groups_per_flex; +if (average_group % flexbg_size) { + times = average_group / flexbg_size; + average_group = times * flexbg_size; + } + } + +return average_group; +#else +return fs->group_desc_count; +#endif +} +#undef _INLINE_#endif
Signature · 1 line
2.37.3
RFC 19/72 libext2fs: Misc fixes for struct_ext2_filsys
In reply to Ritesh Harjani (IBM)From: Andreas Dilger <[email protected]>
Move ext2_filsys fs_num_threads to fit into the __u16 "pad" field to avoid consuming one of the few remaining __u32 reserved fields.
--- lib/ext2fs/ext2fs.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
lib/ext2fs/ext2fs.h +2 -3
@@ -278,12 +278,11 @@ struct struct_ext2_filsys {time_t now;int cluster_ratio_bits;__u16 default_bitmap_type; -__u16 pad; -__u32 fs_num_threads; +__u16 fs_num_threads;/* * Reserved for future expansion */ -__u32 reserved[4 ]; +__u32 reserved[5 ];/* * Reserved for the use of the calling application.
Signature · 1 line
2.37.3
RFC 20/72 libext2fs: avoid too much memory allocation in case fs_num_threads
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
e2fsck init memory according to filesystem inodes/dir numbers recorded in the superblock, this should be aware of filesystem number of threads, otherwise, oom can happen.
So in case of fs->fs_num_threads, this patch controls the amount of memory consumed for running multiple threads in e2fsck.
--- lib/ext2fs/dblist.c | 2 ++ lib/ext2fs/icount.c | 4 ++++ 2 files changed, 6 insertions(+)
lib/ext2fs/dblist.c +2 -0
@@ -58,6 +58,8 @@ static errcode_t make_dblist(ext2_filsys fs, ext2_ino_t size,if (retval) goto cleanup; dblist->size = (num_dirs *2 ) +12 ; +if (fs->fs_num_threads) + dblist->size /= fs->fs_num_threads; } len = (size_t )sizeof (struct ext2_db_entry2 ) * dblist->size; dblist->count = count;
lib/ext2fs/icount.c +4 -0
@@ -237,6 +237,8 @@ errcode_t ext2fs_create_icount_tdb(ext2_filsys fs EXT2FS_NO_TDB_UNUSED,* value. */ num_inodes = fs->super->s_inodes_count - fs->super->s_free_inodes_count; +if (fs->fs_num_threads) + num_inodes /= fs->fs_num_threads; icount->tdb =tdb_open (fn, num_inodes,TDB_NOLOCK |TDB_NOSYNC ,O_RDWR |O_CREAT |O_TRUNC ,0600 );
@@ -288,6 +290,8 @@ errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size,if (retval) goto errout; icount->size += fs->super->s_inodes_count /50 ; +if (fs->fs_num_threads) + icount->size /= fs->fs_num_threads; } bytes = (size_t ) (icount->size *sizeof (struct ext2_icount_el ));
Signature · 1 line
2.37.3
RFC 21/72 e2fsck: add -m option for multithread
In reply to Ritesh Harjani (IBM)From: Li Xi <[email protected]>
-m option is added but no actual functionality is added. This patch only adds the logic that when -m is specified, one of -p/-y/-n options should be specified. And when -m is specified, -C shouldn't be specified and the completion progress report won't be triggered by sending SIGUSR1/SIGUSR2 signals. This simplifies the implementation of multi-thread fsck in the future.
Completion progress support with multi-thread fsck will be added back after multi-thread fsck implementation is finished. Right now, disable it to simplify the implementation of multi-thread fsck.
--- e2fsck/e2fsck.h | 1 + e2fsck/unix.c | 31 ++++++++++++++++++++----- tests/f_multithread/expect.1 | 23 ++++++++++++++++++ tests/f_multithread/expect.2 | 7 ++++++ tests/f_multithread/image.gz | 1 + tests/f_multithread/name | 1 + tests/f_multithread/script | 4 ++++ tests/f_multithread_completion/expect.1 | 2 ++ tests/f_multithread_completion/expect.2 | 23 ++++++++++++++++++ tests/f_multithread_completion/image.gz | 1 + tests/f_multithread_completion/name | 1 + tests/f_multithread_completion/script | 4 ++++ tests/f_multithread_no/expect.1 | 24 +++++++++++++++++++ tests/f_multithread_no/expect.2 | 23 ++++++++++++++++++ tests/f_multithread_no/image.gz | 1 + tests/f_multithread_no/name | 1 + tests/f_multithread_no/script | 4 ++++ tests/f_multithread_preen/expect.1 | 11 +++++++++ tests/f_multithread_preen/expect.2 | 23 ++++++++++++++++++ tests/f_multithread_preen/image.gz | 1 + tests/f_multithread_preen/name | 1 + tests/f_multithread_preen/script | 4 ++++ tests/f_multithread_yes/expect.1 | 2 ++ tests/f_multithread_yes/expect.2 | 23 ++++++++++++++++++ tests/f_multithread_yes/image.gz | 1 + tests/f_multithread_yes/name | 1 + tests/f_multithread_yes/script | 4 ++++ 27 files changed, 217 insertions(+), 6 deletions(-) create mode 100644 tests/f_multithread/expect.1 create mode 100644 tests/f_multithread/expect.2 create mode 120000 tests/f_multithread/image.gz create mode 100644 tests/f_multithread/name create mode 100644 tests/f_multithread/script create mode 100644 tests/f_multithread_completion/expect.1 create mode 100644 tests/f_multithread_completion/expect.2 create mode 120000 tests/f_multithread_completion/image.gz create mode 100644 tests/f_multithread_completion/name create mode 100644 tests/f_multithread_completion/script create mode 100644 tests/f_multithread_no/expect.1 create mode 100644 tests/f_multithread_no/expect.2 create mode 120000 tests/f_multithread_no/image.gz create mode 100644 tests/f_multithread_no/name create mode 100644 tests/f_multithread_no/script create mode 100644 tests/f_multithread_preen/expect.1 create mode 100644 tests/f_multithread_preen/expect.2 create mode 120000 tests/f_multithread_preen/image.gz create mode 100644 tests/f_multithread_preen/name create mode 100644 tests/f_multithread_preen/script create mode 100644 tests/f_multithread_yes/expect.1 create mode 100644 tests/f_multithread_yes/expect.2 create mode 120000 tests/f_multithread_yes/image.gz create mode 100644 tests/f_multithread_yes/name create mode 100644 tests/f_multithread_yes/script
e2fsck/e2fsck.h +1 -0
@@ -186,6 +186,7 @@ struct resource_track {#define E2F_OPT_UNSHARE_BLOCKS 0x40000#define E2F_OPT_CLEAR_UNINIT 0x80000/* Hack to clear the uninit bit */ #define E2F_OPT_CHECK_ENCODING 0x100000/* Force verification of encoded filenames */ +#define E2F_OPT_MULTITHREAD 0x200000/* Use multiple threads to speedup */ /* * E2fsck flags
e2fsck/unix.c +25 -6
@@ -76,13 +76,14 @@ int journal_enable_debug = -1;static void usage (e2fsck_t ctx) {fprintf (stderr, -_ ("Usage: %s [-panyrcdfktvDFV] [-b superblock] [-B blocksize]\n" +_ ("Usage: %s [-pamnyrcdfktvDFV] [-b superblock] [-B blocksize]\n" "\t\t[-l|-L bad_blocks_file] [-C fd] [-j external_journal]\n" "\t\t[-E extended-options] [-z undo_file] device\n" ), ctx->program_name ? ctx->program_name :"e2fsck" ); fprintf(stderr, "%s", _("\nEmergency help:\n" " -p Automatic repair (no questions)\n" + " -m multiple threads to speedup fsck\n" " -n Make no changes to the filesystem\n" " -y Assume \"yes\" to all questions\n" " -c Check for bad blocks and add them to the badblock list\n"
@@ -854,7 +855,8 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) phys_mem_kb =get_memory_size () /1024 ; ctx->readahead_kb = ~0ULL ; -while ((c =getopt (argc, argv,"panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkz:" )) !=EOF ) + +while ((c =getopt (argc, argv,"pamnyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkz:" )) !=EOF )switch (c) {case 'C' : ctx->progress = e2fsck_update_progress;
@@ -895,6 +897,9 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) } ctx->options |=E2F_OPT_PREEN ;break ; +case 'm' : + ctx->options |=E2F_OPT_MULTITHREAD ; +break ;case 'n' :if (ctx->options & (E2F_OPT_YES |E2F_OPT_PREEN )) goto conflict_opt;
@@ -1014,6 +1019,18 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) _("The -n and -l/-L options are incompatible."));fatal_error (ctx,0 ); } +if (ctx->options &E2F_OPT_MULTITHREAD ) { +if ((ctx->options & (E2F_OPT_YES |E2F_OPT_NO |E2F_OPT_PREEN )) ==0 ) { +com_err (ctx->program_name,0 ,"%s" , +_ ("The -m option should be used together with one of -p/-y/-n options." )); +fatal_error (ctx,0 ); + } +if (ctx->progress) { +com_err (ctx->program_name,0 ,"%s" , +_ ("Only one of the options -C or -m may be specified." )); +fatal_error (ctx,0 ); + } + }if (ctx->options &E2F_OPT_NO ) ctx->options |=E2F_OPT_READONLY ;
@@ -1120,10 +1137,12 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)#ifdef SA_RESTART sa.sa_flags =SA_RESTART ;#endif - sa.sa_handler = signal_progress_on; -sigaction (SIGUSR1 , &sa,0 ); - sa.sa_handler = signal_progress_off; -sigaction (SIGUSR2 , &sa,0 ); +if ((ctx->options &E2F_OPT_MULTITHREAD ) ==0 ) { + sa.sa_handler = signal_progress_on; +sigaction (SIGUSR1 , &sa,0 ); + sa.sa_handler = signal_progress_off; +sigaction (SIGUSR2 , &sa,0 ); + }#endif /* Update our PATH to include /sbin if we need to run badblocks */
tests/f_multithread/expect.1 new file +23 -0
@@ -0,0 +1,23 @@ +ext2fs_open2: Bad magic number in super-block +../e2fsck/e2fsck: Superblock invalid, trying backup blocks... +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +Free blocks count wrong for group #0 (7987, counted=7982). +Fix? yes + +Free blocks count wrong (11602, counted=11597). +Fix? yes + +Free inodes count wrong for group #0 (1493, counted=1488). +Fix? yes + +Free inodes count wrong (2997, counted=2992). +Fix? yes + + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 16/3008 files (0.0% non-contiguous), 403/12000 blocks +Exit status is 1
tests/f_multithread/expect.2 new file +7 -0
@@ -0,0 +1,7 @@ +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +test_filesys: 16/3008 files (0.0% non-contiguous), 403/12000 blocks +Exit status is 0
tests/f_multithread/image.gz new file +1 -0
@@ -0,0 +1 @@ +../f_zero_super/image.gz
tests/f_multithread/name new file +1 -0
@@ -0,0 +1 @@ +test "e2fsck -m" option
tests/f_multithread/script new file +4 -0
@@ -0,0 +1,4 @@ +FSCK_OPT="-fy -m" +SECOND_FSCK_OPT=-yf + +. $cmd_dir/run_e2fsck
tests/f_multithread_completion/expect.1 new file +2 -0
@@ -0,0 +1,2 @@ +../e2fsck/e2fsck: Only one of the options -C or -m may be specified. +Exit status is 8
tests/f_multithread_completion/expect.2 new file +23 -0
@@ -0,0 +1,23 @@ +ext2fs_open2: Bad magic number in super-block +../e2fsck/e2fsck: Superblock invalid, trying backup blocks... +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +Free blocks count wrong for group #0 (7987, counted=7982). +Fix? yes + +Free blocks count wrong (11602, counted=11597). +Fix? yes + +Free inodes count wrong for group #0 (1493, counted=1488). +Fix? yes + +Free inodes count wrong (2997, counted=2992). +Fix? yes + + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 16/3008 files (0.0% non-contiguous), 403/12000 blocks +Exit status is 1
tests/f_multithread_completion/image.gz new file +1 -0
@@ -0,0 +1 @@ +../f_zero_super/image.gz
tests/f_multithread_completion/name new file +1 -0
@@ -0,0 +1 @@ +test "e2fsck -m" option conflicts with "-C"
tests/f_multithread_completion/script new file +4 -0
@@ -0,0 +1,4 @@ +FSCK_OPT="-fy -m -C 1" +SECOND_FSCK_OPT=-yf + +. $cmd_dir/run_e2fsck
tests/f_multithread_no/expect.1 new file +24 -0
@@ -0,0 +1,24 @@ +ext2fs_open2: Bad magic number in super-block +../e2fsck/e2fsck: Superblock invalid, trying backup blocks... +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +Free blocks count wrong for group #0 (7987, counted=7982). +Fix? no + +Free blocks count wrong (11602, counted=11597). +Fix? no + +Free inodes count wrong for group #0 (1493, counted=1488). +Fix? no + +Free inodes count wrong (2997, counted=2992). +Fix? no + + +test_filesys: ********** WARNING: Filesystem still has errors ********** + +test_filesys: 11/3008 files (0.0% non-contiguous), 398/12000 blocks +Exit status is 4
tests/f_multithread_no/expect.2 new file +23 -0
@@ -0,0 +1,23 @@ +ext2fs_open2: Bad magic number in super-block +../e2fsck/e2fsck: Superblock invalid, trying backup blocks... +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +Free blocks count wrong for group #0 (7987, counted=7982). +Fix? yes + +Free blocks count wrong (11602, counted=11597). +Fix? yes + +Free inodes count wrong for group #0 (1493, counted=1488). +Fix? yes + +Free inodes count wrong (2997, counted=2992). +Fix? yes + + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 16/3008 files (0.0% non-contiguous), 403/12000 blocks +Exit status is 1
tests/f_multithread_no/image.gz new file +1 -0
@@ -0,0 +1 @@ +../f_zero_super/image.gz
tests/f_multithread_no/name new file +1 -0
@@ -0,0 +1 @@ +test "e2fsck -m" option works with "-n"
tests/f_multithread_no/script new file +4 -0
@@ -0,0 +1,4 @@ +FSCK_OPT="-fn -m" +SECOND_FSCK_OPT=-yf + +. $cmd_dir/run_e2fsck
tests/f_multithread_preen/expect.1 new file +11 -0
@@ -0,0 +1,11 @@ +../e2fsck/e2fsck: Bad magic number in super-block while trying to open test.img +test_filesys: +The superblock could not be read or does not describe a valid ext2/ext3/ext4 +filesystem. If the device is valid and it really contains an ext2/ext3/ext4 +filesystem (and not swap or ufs or something else), then the superblock +is corrupt, and you might try running e2fsck with an alternate superblock: + e2fsck -b 8193 <device> + or + e2fsck -b 32768 <device> + +Exit status is 8
tests/f_multithread_preen/expect.2 new file +23 -0
@@ -0,0 +1,23 @@ +ext2fs_open2: Bad magic number in super-block +../e2fsck/e2fsck: Superblock invalid, trying backup blocks... +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +Free blocks count wrong for group #0 (7987, counted=7982). +Fix? yes + +Free blocks count wrong (11602, counted=11597). +Fix? yes + +Free inodes count wrong for group #0 (1493, counted=1488). +Fix? yes + +Free inodes count wrong (2997, counted=2992). +Fix? yes + + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 16/3008 files (0.0% non-contiguous), 403/12000 blocks +Exit status is 1
tests/f_multithread_preen/image.gz new file +1 -0
@@ -0,0 +1 @@ +../f_zero_super/image.gz
tests/f_multithread_preen/name new file +1 -0
@@ -0,0 +1 @@ +test "e2fsck -m" option works with "-p"
tests/f_multithread_preen/script new file +4 -0
@@ -0,0 +1,4 @@ +FSCK_OPT="-fp -m" +SECOND_FSCK_OPT=-yf + +. $cmd_dir/run_e2fsck
tests/f_multithread_yes/expect.1 new file +2 -0
@@ -0,0 +1,2 @@ +../e2fsck/e2fsck: The -m option should be used together with one of -p/-y/-n options. +Exit status is 8
tests/f_multithread_yes/expect.2 new file +23 -0
@@ -0,0 +1,23 @@ +ext2fs_open2: Bad magic number in super-block +../e2fsck/e2fsck: Superblock invalid, trying backup blocks... +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +Free blocks count wrong for group #0 (7987, counted=7982). +Fix? yes + +Free blocks count wrong (11602, counted=11597). +Fix? yes + +Free inodes count wrong for group #0 (1493, counted=1488). +Fix? yes + +Free inodes count wrong (2997, counted=2992). +Fix? yes + + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 16/3008 files (0.0% non-contiguous), 403/12000 blocks +Exit status is 1
tests/f_multithread_yes/image.gz new file +1 -0
@@ -0,0 +1 @@ +../f_zero_super/image.gz
tests/f_multithread_yes/name new file +1 -0
@@ -0,0 +1 @@ +test "e2fsck -m" option works with "-y"
tests/f_multithread_yes/script new file +4 -0
@@ -0,0 +1,4 @@ +FSCK_OPT="-f -m" +SECOND_FSCK_OPT=-yf + +. $cmd_dir/run_e2fsck
Signature · 1 line
2.37.3
RFC 22/72 e2fsck: copy context when using multi-thread fsck
In reply to Ritesh Harjani (IBM)From: Li Xi <[email protected]>
This patch only copy the context to a new one when -m is enabled. It doesn't actually start any thread. When pass1 test finishes, the new context is copied back to the original context.
Since the signal handler only changes the original context, so add global_ctx in "struct e2fsck_struct" and use that to check whether there is any signal of canceling.
This patch handles the long jump properly so that all the existing tests can be passed even the context has been copied. Otherwise, test f_expisize_ea_del would fail when aborting.
--- e2fsck/e2fsck.h | 2 + e2fsck/pass1.c | 117 ++++++++++++++++++++++++++++++++++++++++++++---- e2fsck/unix.c | 1 + 3 files changed, 112 insertions(+), 8 deletions(-)
e2fsck/e2fsck.h +2 -0
@@ -262,6 +262,8 @@ struct e2fsck_fc_replay_state { };struct e2fsck_struct { +/* Global context to get the cancel flag */ +e2fsck_t global_ctx;ext2_filsys fs;const char *program_name;char *filesystem_name;
e2fsck/pass1.c +109 -8
171 lines not on this page · raw message
e2fsck/unix.c +1 -0
@@ -1461,6 +1461,7 @@ int main (int argc, char *argv[]) }reserve_stdio_fds (); + ctx->global_ctx =NULL ;set_up_logging (ctx);if (ctx->logf) {int i;
Signature · 1 line
2.37.3
RFC 23/72 e2fsck: create logs for multi-threads
In reply to Ritesh Harjani (IBM)From: Li Xi <[email protected]>
When multi-threads are used, different logs should be created for different threads. Each thread has log files with suffix of ".$THREAD_INDEX".
And this patch adds f_multithread_logfile test case.
--- e2fsck/e2fsck.h | 6 ++++-- e2fsck/logfile.c | 10 ++++++++- e2fsck/pass1.c | 12 +++++++++++ tests/f_multithread_logfile/expect.1 | 23 ++++++++++++++++++++ tests/f_multithread_logfile/image.gz | 1 + tests/f_multithread_logfile/name | 1 + tests/f_multithread_logfile/script | 32 ++++++++++++++++++++++++++++ 7 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 tests/f_multithread_logfile/expect.1 create mode 120000 tests/f_multithread_logfile/image.gz create mode 100644 tests/f_multithread_logfile/name create mode 100644 tests/f_multithread_logfile/script
e2fsck/e2fsck.h +4 -2
@@ -342,8 +342,10 @@ struct e2fsck_struct {/* * For pass1_check_directory and pass1_get_blocks */ -ext2_ino_t stashed_ino; -struct ext2_inode *stashed_inode; +ext2_ino_t stashed_ino; +struct ext2_inode *stashed_inode; +/* Thread index, if global_ctx is null, this field is unused */ +int thread_index;/* * Location of the lost and found directory
e2fsck/logfile.c +9 -1
@@ -16,6 +16,7 @@#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <assert.h> #include "e2fsck.h" #include <pwd.h>
@@ -294,6 +295,8 @@ static FILE *set_up_log_file(e2fsck_t ctx, const char *key, const char *fn)struct string s, s1, s2;char *s0 =0 , *log_dir =0 , *log_fn =0 ;int log_dir_wait =0 ; +int string_size; +char string_index[10 ]; s.s = s1.s = s2.s =0 ;
@@ -310,6 +313,12 @@ static FILE *set_up_log_file(e2fsck_t ctx, const char *key, const char *fn) goto out;expand_logfn (ctx, log_fn, &s); +if (ctx->global_ctx) { +sprintf (string_index,"%d" , ctx->thread_index); +append_string (&s,"." ,1 ); +append_string (&s, string_index,0 ); + } +if ((log_fn[0 ] =='/' ) || !log_dir || !log_dir[0 ]) s0 = s.s;
@@ -328,7 +337,6 @@ static FILE *set_up_log_file(e2fsck_t ctx, const char *key, const char *fn)append_string (&s2, log_dir,0 );append_string (&s2,"/" ,1 );append_string (&s2, s.s,0 ); -printf ("%s\n" , s2.s); }if (s0)
e2fsck/pass1.c +12 -0
@@ -2164,6 +2164,8 @@ static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *thre thread_context->fs->priv_data = thread_context; thread_context->global_ctx = global_ctx; + thread_context->thread_index =0 ; +set_up_logging (thread_context); *thread_ctx = thread_context;return 0 ; }
@@ -2171,6 +2173,8 @@ static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *threstatic int e2fsck_pass1_thread_join (e2fsck_t global_ctx,e2fsck_t thread_ctx) {int flags = global_ctx->flags; +FILE *global_logf = global_ctx->logf; +FILE *global_problem_logf = global_ctx->problem_logf;#ifdef HAVE_SETJMP_H jmp_buf old_jmp;
@@ -2185,6 +2189,14 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx) (global_ctx->flags &E2F_FLAG_SIGNAL_MASK ); global_ctx->fs->priv_data = global_ctx; + global_ctx->logf = global_logf; + global_ctx->problem_logf = global_problem_logf; +if (thread_ctx->logf) +fclose (thread_ctx->logf); +if (thread_ctx->problem_logf) { +fputs ("</problem_log>\n" , thread_ctx->problem_logf); +fclose (thread_ctx->problem_logf); + }ext2fs_free_mem (&thread_ctx);return 0 ; }
tests/f_multithread_logfile/expect.1 new file +23 -0
@@ -0,0 +1,23 @@ +ext2fs_open2: Bad magic number in super-block +../e2fsck/e2fsck: Superblock invalid, trying backup blocks... +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +Free blocks count wrong for group #0 (7987, counted=7982). +Fix? yes + +Free blocks count wrong (11602, counted=11597). +Fix? yes + +Free inodes count wrong for group #0 (1493, counted=1488). +Fix? yes + +Free inodes count wrong (2997, counted=2992). +Fix? yes + + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 16/3008 files (0.0% non-contiguous), 403/12000 blocks +Exit status is 1
tests/f_multithread_logfile/image.gz new file +1 -0
@@ -0,0 +1 @@ +../f_zero_super/image.gz
tests/f_multithread_logfile/name new file +1 -0
@@ -0,0 +1 @@ +test "e2fsck -m" option works with "-E log_filename="
tests/f_multithread_logfile/script new file +32 -0
@@ -0,0 +1,32 @@ +LOG_FNAME="f_multithread_logfile_xxx" +FSCK_OPT="-fy -m -y -E log_filename=$LOG_FNAME" +SKIP_VERIFY="true" +ONE_PASS_ONLY="true" +SKIP_CLEANUP="true" + +rm -f $LOG_FNAME.* $LOG_FNAME + +. $cmd_dir/run_e2fsck + +rm -f $test_name.ok $test_name.failed +cmp -s $OUT1 $EXP1 +status1=$? + +if [ "$status1" -eq 0 ]; then + if [ ! -f $LOG_FNAME -o ! -f $LOG_FNAME.0 ]; then + echo "$LOG_FNAME or $LOG_FNAME.0 is not created" > $test_name.failed + echo "$test_name: $test_description: failed" + else + echo "$test_name: $test_description: ok" + touch $test_name.ok + fi +else + diff $DIFF_OPTS $test_dir/expect.1 \ + $test_name.1.log >> $test_name.failed + echo "$test_name: $test_description: failed" +fi + +unset IMAGE FSCK_OPT SECOND_FSCK_OPT OUT1 OUT2 EXP1 EXP2 +unset SKIP_VERIFY SKIP_CLEANUP SKIP_GUNZIP ONE_PASS_ONLY PREP_CMD +unset DESCRIPTION SKIP_UNLINK AFTER_CMD PASS_ZERO +unset LOG_FINAME
Signature · 1 line
2.37.3
RFC 24/72 e2fsck: configure one pfsck thread
In reply to Ritesh Harjani (IBM)From: Li Xi <[email protected]>
This patch creates only one thread to do pass1 check if pthreads are enabled. The same codes can be used to create multiple threads, but other functions need to be modified to get ready for that.
--- e2fsck/e2fsck.h | 13 ++++ e2fsck/logfile.c | 2 + e2fsck/pass1.c | 152 ++++++++++++++++++++++++++++++++++++++++------ e2fsck/unix.c | 10 +++ tests/test_one.in | 8 +++ 5 files changed, 166 insertions(+), 19 deletions(-)
e2fsck/e2fsck.h +13 -0
@@ -465,6 +465,19 @@ struct e2fsck_struct {struct e2fsck_fc_replay_state fc_replay_state; }; +#ifdef HAVE_PTHREAD +struct e2fsck_thread_info { +/* ID returned by pthread_create() */ +pthread_t eti_thread_id; +/* Application-defined thread index */ +int eti_thread_index; +/* Thread has been started */ +int eti_started; +/* Context used for this thread */ +e2fsck_t eti_thread_ctx; +}; +#endif +/* Data structures to evaluate whether an extent tree needs rebuilding. */ struct extent_tree_level {unsigned int num_extents;
e2fsck/logfile.c +2 -0
@@ -313,11 +313,13 @@ static FILE *set_up_log_file(e2fsck_t ctx, const char *key, const char *fn) goto out;expand_logfn (ctx, log_fn, &s); +#ifdef HAVE_PTHREAD if (ctx->global_ctx) {sprintf (string_index,"%d" , ctx->thread_index);append_string (&s,"." ,1 );append_string (&s, string_index,0 ); } +#endif if ((log_fn[0 ] =='/' ) || !log_dir || !log_dir[0 ]) s0 = s.s;
e2fsck/pass1.c +133 -19
198 lines not on this page · raw message
e2fsck/unix.c +10 -0
@@ -83,7 +83,9 @@ static void usage(e2fsck_t ctx) fprintf(stderr, "%s", _("\nEmergency help:\n" " -p Automatic repair (no questions)\n" +#ifdef HAVE_PTHREAD " -m multiple threads to speedup fsck\n" +#endif " -n Make no changes to the filesystem\n" " -y Assume \"yes\" to all questions\n" " -c Check for bad blocks and add them to the badblock list\n"
@@ -856,7 +858,11 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) phys_mem_kb =get_memory_size () /1024 ; ctx->readahead_kb = ~0ULL ; +#ifdef HAVE_PTHREAD while ((c =getopt (argc, argv,"pamnyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkz:" )) !=EOF ) +#else + while ((c = getopt(argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkz:")) != EOF) +#endif switch (c) {case 'C' : ctx->progress = e2fsck_update_progress;
@@ -897,9 +903,11 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) } ctx->options |=E2F_OPT_PREEN ;break ; +#ifdef HAVE_PTHREAD case 'm' : ctx->options |=E2F_OPT_MULTITHREAD ;break ; +#endif case 'n' :if (ctx->options & (E2F_OPT_YES |E2F_OPT_PREEN )) goto conflict_opt;
@@ -1019,6 +1027,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) _("The -n and -l/-L options are incompatible."));fatal_error (ctx,0 ); } +#ifdef HAVE_PTHREAD if (ctx->options &E2F_OPT_MULTITHREAD ) {if ((ctx->options & (E2F_OPT_YES |E2F_OPT_NO |E2F_OPT_PREEN )) ==0 ) { com_err(ctx->program_name, 0, "%s",
@@ -1031,6 +1040,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) fatal_error(ctx, 0); } } +#endif if (ctx->options &E2F_OPT_NO ) ctx->options |=E2F_OPT_READONLY ;
tests/test_one.in +8 -0
@@ -27,6 +27,7 @@ esac test_dir=$1 cmd_dir=$SRCDIR +pfsck_enabled="no" if test "$TEST_CONFIG"x = x; then TEST_CONFIG=$SRCDIR/test_config
@@ -52,6 +53,13 @@ else test_description= fi +$FSCK --help 2>&1 | grep -q -w -- -m && pfsck_enabled=yes +if [ "$pfsck_enabled" != "yes" ] ; then + echo "$test_dir" | grep -q multithread && + echo "$test_name: $test_description: skipped (pfsck disabled)" && + exit 0 +fi + if [ -n "$SKIP_SLOW_TESTS" -a -f $test_dir/is_slow_test ]; then echo "$test_name: $test_description: skipped (slow test)" exit 0
Signature · 1 line
2.37.3
RFC 25/72 e2fsck: Add e2fsck_pass1_thread_join return value
In reply to Ritesh Harjani (IBM)This adds the return value to e2fsck_pass1_thread_join() to check for any error in pass1 threads join operation.
--- e2fsck/pass1.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-)
e2fsck/pass1.c +18 -3
@@ -2174,8 +2174,9 @@ static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *threreturn 0 ; } -static int e2fsck_pass1_thread_join (e2fsck_t global_ctx,e2fsck_t thread_ctx) +static int e2fsck_pass1_thread_join_one (e2fsck_t global_ctx,e2fsck_t thread_ctx) { +errcode_t retval =0 ;int flags = global_ctx->flags;FILE *global_logf = global_ctx->logf;FILE *global_problem_logf = global_ctx->problem_logf;
@@ -2195,6 +2196,14 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx) global_ctx->fs->priv_data = global_ctx; global_ctx->logf = global_logf; global_ctx->problem_logf = global_problem_logf; +return retval; +} + +static int e2fsck_pass1_thread_join (e2fsck_t global_ctx,e2fsck_t thread_ctx) +{ +errcode_t retval; + + retval =e2fsck_pass1_thread_join_one (global_ctx, thread_ctx);if (thread_ctx->logf)fclose (thread_ctx->logf);if (thread_ctx->problem_logf) {
@@ -2202,7 +2211,7 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx)fclose (thread_ctx->problem_logf); }ext2fs_free_mem (&thread_ctx); -return 0 ; +return retval; } static int e2fsck_pass1_threads_join(struct e2fsck_thread_info *infos,
@@ -2226,7 +2235,13 @@ static int e2fsck_pass1_threads_join(struct e2fsck_thread_info *infos,if (ret ==0 ) ret = rc; } -e2fsck_pass1_thread_join (global_ctx, infos[i].eti_thread_ctx); + rc =e2fsck_pass1_thread_join (global_ctx, infos[i].eti_thread_ctx); +if (rc) { +com_err (global_ctx->program_name, rc, +_ ("while joining pass1 thread\n" )); +if (ret ==0 ) + ret = rc; + } }free (infos);
Signature · 1 line
2.37.3
RFC 26/72 e2fsck: Use merge/clone apis of libext2fs
In reply to Ritesh Harjani (IBM)This patch makes use of libext2fs merge/clone apis in e2fsck to first clone the global_fs based on the passed CLONE_FLAGS. Then once the parallel e2fsck operation finishes, it calls for merge fs api which merges it into parent fs.
--- e2fsck/pass1.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-)
e2fsck/pass1.c +55 -3
@@ -2154,10 +2154,36 @@ endit: }#ifdef HAVE_PTHREAD +static errcode_t e2fsck_open_channel_fs (ext2_filsys dest,e2fsck_t dest_context,ext2_filsys src) +{ +errcode_t retval; + +io_channel_flush_cleanup (src->io); + retval = dest->io->manager->open (dest->device_name, +IO_FLAG_RW |IO_FLAG_THREADS , &dest->io); +if (retval) +return retval; + dest->image_io = dest->io; + dest->io->app_data = dest; +/* Block size might not be default */ +io_channel_set_blksize (dest->io, src->io->block_size); +ehandler_init (dest->io); + + dest->priv_data = dest_context; + dest_context->fs = dest; +/* The data should be written to disk immediately */ + dest->io->flags |=CHANNEL_FLAGS_WRITETHROUGH ; +/* icache will be rebuilt if needed, so do not copy from @src */ + src->icache =NULL ; +return 0 ; +} +static errcode_t e2fsck_pass1_thread_prepare (e2fsck_t global_ctx,e2fsck_t *thread_ctx) {errcode_t retval;e2fsck_t thread_context; +ext2_filsys thread_fs; +ext2_filsys global_fs = global_ctx->fs; retval =ext2fs_get_mem (sizeof (struct e2fsck_struct ), &thread_context);if (retval) {
@@ -2165,13 +2191,30 @@ static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *threreturn retval; }memcpy (thread_context, global_ctx,sizeof (struct e2fsck_struct )); - thread_context->fs->priv_data = thread_context; thread_context->global_ctx = global_ctx; + retval =ext2fs_clone_fs (global_fs, &thread_fs, +EXT2FS_CLONE_BLOCK |EXT2FS_CLONE_INODE | +EXT2FS_CLONE_BADBLOCKS |EXT2FS_CLONE_DBLIST ); +if (retval) { +com_err (global_ctx->program_name, retval,"while allocating memory" ); + goto out_context; + } + + retval =e2fsck_open_channel_fs (thread_fs, thread_context, global_fs); +if (retval) { +com_err (global_ctx->program_name, retval,"while copying fs" ); + goto out_fs; + } thread_context->thread_index =0 ;set_up_logging (thread_context); *thread_ctx = thread_context;return 0 ; +out_fs: +ext2fs_merge_fs (&thread_fs); +out_context: +ext2fs_free_mem (&thread_context); +return retval; }static int e2fsck_pass1_thread_join_one (e2fsck_t global_ctx,e2fsck_t thread_ctx)
@@ -2180,6 +2223,8 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctxint flags = global_ctx->flags;FILE *global_logf = global_ctx->logf;FILE *global_problem_logf = global_ctx->problem_logf; +ext2_filsys thread_fs = thread_ctx->fs; +ext2_filsys global_fs = global_ctx->fs;#ifdef HAVE_SETJMP_H jmp_buf old_jmp;
@@ -2192,10 +2237,17 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx/* Keep the global singal flags*/ global_ctx->flags |= (flags &E2F_FLAG_SIGNAL_MASK ) | (global_ctx->flags &E2F_FLAG_SIGNAL_MASK ); - - global_ctx->fs->priv_data = global_ctx; global_ctx->logf = global_logf; global_ctx->problem_logf = global_problem_logf; + + global_fs->priv_data = global_ctx; + global_ctx->fs = global_fs; + + retval =ext2fs_merge_fs (&(thread_ctx->fs)); +if (retval) { +com_err (global_ctx->program_name,0 ,_ ("while merging fs\n" )); +return retval; + }return retval; }
Signature · 1 line
2.37.3
RFC 27/72 e2fsck: Add e2fsck_pass1_merge_bitmap() api
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
This adds e2fsck_pass1_merge_bitmap() which uses libext2fs merge api (ext2fs_merge_bitmap()) to merge all the bitmaps after threads finishes.
--- e2fsck/pass1.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+)
e2fsck/pass1.c +128 -0
@@ -50,6 +50,7 @@#ifdef HAVE_PTHREAD #include <pthread.h> #endif +#include <assert.h> #include "e2fsck.h" #include <ext2fs/ext2_ext_attr.h>
@@ -2154,6 +2155,26 @@ endit: }#ifdef HAVE_PTHREAD +static errcode_t e2fsck_pass1_merge_bitmap (ext2_filsys fs,ext2fs_generic_bitmap *src, +ext2fs_generic_bitmap *dest) +{ +errcode_t ret =0 ; + +if (*src) { +if (*dest ==NULL ) { + *dest = *src; + *src =NULL ; + }else { + ret =ext2fs_merge_bitmap (*src, *dest,NULL ,NULL ); +if (ret) +return ret; + } + (*dest)->fs = fs; + } + +return 0 ; +} +static errcode_t e2fsck_open_channel_fs (ext2_filsys dest,e2fsck_t dest_context,ext2_filsys src) {errcode_t retval;
@@ -2185,6 +2206,19 @@ static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *threext2_filsys thread_fs;ext2_filsys global_fs = global_ctx->fs; +assert (global_ctx->inode_used_map ==NULL ); +assert (global_ctx->inode_dir_map ==NULL ); +assert (global_ctx->inode_bb_map ==NULL ); +assert (global_ctx->inode_imagic_map ==NULL ); +assert (global_ctx->inode_reg_map ==NULL ); +assert (global_ctx->inodes_to_rebuild ==NULL ); + +assert (global_ctx->block_found_map ==NULL ); +assert (global_ctx->block_dup_map ==NULL ); +assert (global_ctx->block_ea_map ==NULL ); +assert (global_ctx->block_metadata_map ==NULL ); +assert (global_ctx->fs->dblist ==NULL ); + retval =ext2fs_get_mem (sizeof (struct e2fsck_struct ), &thread_context);if (retval) {com_err (global_ctx->program_name, retval,"while allocating memory" );
@@ -2225,6 +2259,18 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctxFILE *global_problem_logf = global_ctx->problem_logf;ext2_filsys thread_fs = thread_ctx->fs;ext2_filsys global_fs = global_ctx->fs; +ext2fs_inode_bitmap inode_bad_map = global_ctx->inode_bad_map; +ext2fs_inode_bitmap inode_used_map = global_ctx->inode_used_map; +ext2fs_inode_bitmap inode_dir_map = global_ctx->inode_dir_map; +ext2fs_inode_bitmap inode_bb_map = global_ctx->inode_bb_map; +ext2fs_inode_bitmap inode_imagic_map = global_ctx->inode_imagic_map; +ext2fs_inode_bitmap inode_reg_map = global_ctx->inode_reg_map; +ext2fs_block_bitmap block_found_map = global_ctx->block_found_map; +ext2fs_block_bitmap block_dup_map = global_ctx->block_dup_map; +ext2fs_block_bitmap block_ea_map = global_ctx->block_ea_map; +ext2fs_block_bitmap block_metadata_map = global_ctx->block_metadata_map; +ext2fs_block_bitmap inodes_to_rebuild = global_ctx->inodes_to_rebuild; +#ifdef HAVE_SETJMP_H jmp_buf old_jmp;
@@ -2234,6 +2280,19 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx#ifdef HAVE_SETJMP_H memcpy (global_ctx->abort_loc, old_jmp,sizeof (jmp_buf));#endif + + global_ctx->inode_used_map = inode_used_map; + global_ctx->inode_bad_map = inode_bad_map; + global_ctx->inode_dir_map = inode_dir_map; + global_ctx->inode_bb_map = inode_bb_map; + global_ctx->inode_imagic_map = inode_imagic_map; + global_ctx->inodes_to_rebuild = inodes_to_rebuild; + global_ctx->inode_reg_map = inode_reg_map; + global_ctx->block_found_map = block_found_map; + global_ctx->block_dup_map = block_dup_map; + global_ctx->block_ea_map = block_ea_map; + global_ctx->block_metadata_map = block_metadata_map; +/* Keep the global singal flags*/ global_ctx->flags |= (flags &E2F_FLAG_SIGNAL_MASK ) | (global_ctx->flags &E2F_FLAG_SIGNAL_MASK );
@@ -2248,6 +2307,63 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctxcom_err (global_ctx->program_name,0 ,_ ("while merging fs\n" ));return retval; } + retval =e2fsck_pass1_merge_bitmap (global_fs, + &thread_ctx->inode_used_map, + &global_ctx->inode_used_map); +if (retval) +return retval; + + retval =e2fsck_pass1_merge_bitmap (global_fs, + &thread_ctx->inode_bad_map, + &global_ctx->inode_bad_map); +if (retval) +return retval; + retval =e2fsck_pass1_merge_bitmap (global_fs, + &thread_ctx->inode_dir_map, + &global_ctx->inode_dir_map); +if (retval) +return retval; + retval =e2fsck_pass1_merge_bitmap (global_fs, + &thread_ctx->inode_bb_map, + &global_ctx->inode_bb_map); +if (retval) +return retval; + retval =e2fsck_pass1_merge_bitmap (global_fs, + &thread_ctx->inode_imagic_map, + &global_ctx->inode_imagic_map); +if (retval) +return retval; + retval =e2fsck_pass1_merge_bitmap (global_fs, + &thread_ctx->inode_reg_map, + &global_ctx->inode_reg_map); +if (retval) +return retval; + retval =e2fsck_pass1_merge_bitmap (global_fs, + &thread_ctx->inodes_to_rebuild, + &global_ctx->inodes_to_rebuild); +if (retval) +return retval; + retval =e2fsck_pass1_merge_bitmap (global_fs, + &thread_ctx->block_found_map, + &global_ctx->block_found_map); +if (retval) +return retval; + retval =e2fsck_pass1_merge_bitmap (global_fs, + &thread_ctx->block_dup_map, + &global_ctx->block_dup_map); +if (retval) +return retval; + retval =e2fsck_pass1_merge_bitmap (global_fs, + &thread_ctx->block_ea_map, + &global_ctx->block_ea_map); +if (retval) +return retval; + retval =e2fsck_pass1_merge_bitmap (global_fs, + &thread_ctx->block_metadata_map, + &global_ctx->block_metadata_map); +if (retval) +return retval; +return retval; }
@@ -2256,6 +2372,18 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx)errcode_t retval; retval =e2fsck_pass1_thread_join_one (global_ctx, thread_ctx); +e2fsck_pass1_free_bitmap (&thread_ctx->inode_used_map); +e2fsck_pass1_free_bitmap (&thread_ctx->inode_bad_map); +e2fsck_pass1_free_bitmap (&thread_ctx->inode_dir_map); +e2fsck_pass1_free_bitmap (&thread_ctx->inode_bb_map); +e2fsck_pass1_free_bitmap (&thread_ctx->inode_imagic_map); +e2fsck_pass1_free_bitmap (&thread_ctx->inode_reg_map); +e2fsck_pass1_free_bitmap (&thread_ctx->inodes_to_rebuild); +e2fsck_pass1_free_bitmap (&thread_ctx->block_found_map); +e2fsck_pass1_free_bitmap (&thread_ctx->block_dup_map); +e2fsck_pass1_free_bitmap (&thread_ctx->block_ea_map); +e2fsck_pass1_free_bitmap (&thread_ctx->block_metadata_map); +if (thread_ctx->logf)fclose (thread_ctx->logf);if (thread_ctx->problem_logf) {
Signature · 1 line
2.37.3
RFC 28/72 e2fsck: Add asserts in open_channel_fs
In reply to Ritesh Harjani (IBM)From: Li Xi <[email protected]>
--- e2fsck/pass1.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
e2fsck/pass1.c +12 -0
@@ -2190,6 +2190,18 @@ static errcode_t e2fsck_open_channel_fs(ext2_filsys dest, e2fsck_t dest_context,io_channel_set_blksize (dest->io, src->io->block_size);ehandler_init (dest->io); +assert (dest->io->magic == src->io->magic); +assert (dest->io->manager == src->io->manager); +assert (strcmp (dest->io->name, src->io->name) ==0 ); +assert (dest->io->block_size == src->io->block_size); +assert (dest->io->read_error == src->io->read_error); +assert (dest->io->write_error == src->io->write_error); +assert (dest->io->refcount == src->io->refcount); +assert (dest->io->flags == src->io->flags); +assert (dest->io->app_data == dest); +assert (src->io->app_data == src); +assert (dest->io->align == src->io->align); + dest->priv_data = dest_context; dest_context->fs = dest;/* The data should be written to disk immediately */
Signature · 1 line
2.37.3
RFC 29/72 e2fsck: add start/end group for thread
In reply to Ritesh Harjani (IBM)From: Li Xi <[email protected]>
When multi-threads are used for check, each thread needs to jump to different group in pass1 check. This patch adds the group jumping support. But still, only one thread is used to check.
--- e2fsck/e2fsck.h | 23 ++++++++++++++++++-- e2fsck/logfile.c | 3 ++- e2fsck/pass1.c | 44 ++++++++++++++++++++++++++++++++++++--- e2fsck/problem.c | 5 +++++ e2fsck/problem.h | 3 +++ lib/ext2fs/ext2_err.et.in | 3 +++ 6 files changed, 75 insertions(+), 6 deletions(-)
e2fsck/e2fsck.h +21 -2
@@ -261,6 +261,22 @@ struct e2fsck_fc_replay_state {__u16 fc_super_state; }; +#ifdef HAVE_PTHREAD +/* +* Fields that used for multi-thread +*/ +struct e2fsck_thread { +/* Thread index */ +int et_thread_index; +/* The start group number for this thread */ +dgrp_t et_group_start; +/* The end (not included) group number for this thread*/ +dgrp_t et_group_end; +/* The next group number to check */ +dgrp_t et_group_next; +}; +#endif +struct e2fsck_struct {/* Global context to get the cancel flag */ e2fsck_t global_ctx;
@@ -344,8 +360,11 @@ struct e2fsck_struct {*/ ext2_ino_t stashed_ino;struct ext2_inode *stashed_inode; -/* Thread index, if global_ctx is null, this field is unused */ -int thread_index; + +/* if @global_ctx is null, this field is unused */ +#ifdef HAVE_PTHREAD +struct e2fsck_thread thread_info; +#endif /* * Location of the lost and found directory
e2fsck/logfile.c +2 -1
@@ -315,7 +315,8 @@ static FILE *set_up_log_file(e2fsck_t ctx, const char *key, const char *fn)expand_logfn (ctx, log_fn, &s);#ifdef HAVE_PTHREAD if (ctx->global_ctx) { -sprintf (string_index,"%d" , ctx->thread_index); +sprintf (string_index,"%d" , + ctx->thread_info.et_thread_index);append_string (&s,"." ,1 );append_string (&s, string_index,0 ); }
e2fsck/pass1.c +41 -3
92 lines not on this page · raw message
e2fsck/problem.c +5 -0
@@ -1309,6 +1309,11 @@ static struct e2fsck_problem problem_table[] = {N_ ("Orphan file @i %i is not in use, but contains data. " ), PROMPT_CLEAR, PR_PREEN_OK }, +/* Failed to goto block group */ + { PR_1_SCAN_GOTO, +N_ ("failed to goto block group" ), + PROMPT_NONE, PR_FATAL, 0, 0, 0 }, +/* Pass 1b errors */ /* Pass 1B: Rescan for duplicate/bad blocks */
e2fsck/problem.h +3 -0
@@ -734,6 +734,9 @@ struct problem_context {/* Orphan file inode is not in use, but contains data */ #define PR_1_ORPHAN_FILE_NOT_CLEAR 0x010090 +/* Failed to goto block group */ +#define PR_1_SCAN_GOTO 0x0100A0 +/* * Pass 1b errors */
lib/ext2fs/ext2_err.et.in +3 -0
@@ -557,4 +557,7 @@ ec EXT2_ET_EXTENT_CYCLE, ec EXT2_ET_EXTERNAL_JOURNAL_NOSUPP, "Operation not supported on an external journal" +ec EXT2_ET_SCAN_FINISHED, + "Scanning finished" + end
Signature · 1 line
2.37.3
RFC 30/72 e2fsck: split groups to different threads
In reply to Ritesh Harjani (IBM)From: Li Xi <[email protected]>
The start/end groups of a thread is calculated according to the thread number. But still, only one thread is used to check.
--- e2fsck/pass1.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-)
e2fsck/pass1.c +17 -6
@@ -2231,13 +2231,14 @@ static errcode_t e2fsck_open_channel_fs(ext2_filsys dest, e2fsck_t dest_context, }static errcode_t e2fsck_pass1_thread_prepare (e2fsck_t global_ctx,e2fsck_t *thread_ctx, -int thread_index) +int thread_index,int num_threads) {errcode_t retval;e2fsck_t thread_context;ext2_filsys thread_fs;ext2_filsys global_fs = global_ctx->fs;struct e2fsck_thread *tinfo; +dgrp_t average_group;assert (global_ctx->inode_used_map ==NULL );assert (global_ctx->inode_dir_map ==NULL );
@@ -2276,11 +2277,20 @@ static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *thre thread_context->thread_info.et_thread_index = thread_index;set_up_logging (thread_context); -assert (thread_index ==0 ); +/* +* Distribute work to multiple threads: +* Each thread work on fs->group_desc_count / nthread groups. +*/ tinfo = &thread_context->thread_info; - tinfo->et_group_start =0 ; - tinfo->et_group_next =0 ; - tinfo->et_group_end = thread_fs->group_desc_count; + average_group = thread_fs->group_desc_count / num_threads; +if (average_group ==0 ) + average_group =1 ; + tinfo->et_group_start = average_group * thread_index; +if (thread_index == num_threads -1 ) + tinfo->et_group_end = thread_fs->group_desc_count; +else + tinfo->et_group_end = average_group * (thread_index +1 ); + tinfo->et_group_next = tinfo->et_group_start; *thread_ctx = thread_context;return 0 ;
@@ -2523,7 +2533,8 @@ static int e2fsck_pass1_threads_start(struct e2fsck_thread_info **pinfo,for (i =0 ; i < num_threads; i++) { tmp_pinfo = &infos[i]; tmp_pinfo->eti_thread_index = i; - retval =e2fsck_pass1_thread_prepare (global_ctx, &thread_ctx, i); + retval =e2fsck_pass1_thread_prepare (global_ctx, &thread_ctx, + i, num_threads);if (retval) {com_err (global_ctx->program_name, retval,_ ("while preparing pass1 thread\n" ));
Signature · 1 line
2.37.3
RFC 31/72 e2fsck: print thread log properly
In reply to Ritesh Harjani (IBM)From: Li Xi <[email protected]>
When multi-thread fsck is enabled, logs printed from multiple threads could overlap with each other. The overlap sometimes makes the logs unreadable because log_out() is used multiple times for a single line.
This patch adds leading [Thread XXX] to each logs if multi-thread is enabed by -m option.
This patch also adds message to show the group ranges and inode numbers for each thread, which is useful for debuging multi-thread check.
--- e2fsck/e2fsck.h | 4 ++ e2fsck/pass1.c | 21 ++++++++++ e2fsck/problem.c | 6 +++ e2fsck/util.c | 61 ++++++++++++++++++++++++++-- tests/f_multithread/expect.1 | 4 +- tests/f_multithread_logfile/expect.1 | 4 +- tests/f_multithread_no/expect.1 | 4 +- 7 files changed, 98 insertions(+), 6 deletions(-)
e2fsck/e2fsck.h +4 -0
@@ -274,6 +274,10 @@ struct e2fsck_thread {dgrp_t et_group_end;/* The next group number to check */ dgrp_t et_group_next; +/* Scanned inode number */ +ext2_ino_t et_inode_number; +char et_log_buf[2048 ]; + char et_log_length; };#endif
e2fsck/pass1.c +21 -0
@@ -1460,6 +1460,10 @@ void e2fsck_pass1_run(e2fsck_t ctx) }if (!ino)break ; +#ifdef HAVE_PTHREAD +if (ctx->global_ctx) + ctx->thread_info.et_inode_number++; +#endif pctx.ino = ino; pctx.inode = inode; ctx->stashed_ino = ino;
@@ -2292,6 +2296,12 @@ static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *thre tinfo->et_group_end = average_group * (thread_index +1 ); tinfo->et_group_next = tinfo->et_group_start; + tinfo->et_inode_number =0 ; + tinfo->et_log_buf[0 ] ='\0' ; + tinfo->et_log_length =0 ; +if (thread_context->options &E2F_OPT_MULTITHREAD ) +log_out (thread_context,_ ("Scan group range [%d, %d)\n" ), + tinfo->et_group_start, tinfo->et_group_end); *thread_ctx = thread_context;return 0 ; out_fs:
@@ -2348,6 +2358,7 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx (global_ctx->flags &E2F_FLAG_SIGNAL_MASK ); global_ctx->logf = global_logf; global_ctx->problem_logf = global_problem_logf; + global_ctx->global_ctx =NULL ; global_fs->priv_data = global_ctx; global_ctx->fs = global_fs;
@@ -2500,6 +2511,12 @@ static void *e2fsck_pass1_thread(void *arg)e2fsck_pass1_run (thread_ctx); out: +if (thread_ctx->options &E2F_OPT_MULTITHREAD ) +log_out (thread_ctx, +_ ("Scanned group range [%lu, %lu), inodes %lu\n" ), + thread_ctx->thread_info.et_group_start, + thread_ctx->thread_info.et_group_end, + thread_ctx->thread_info.et_inode_number);return NULL ; }
@@ -2635,6 +2652,10 @@ static errcode_t scan_callback(ext2_filsys fs,if (ctx->global_ctx) { tinfo = &ctx->thread_info; tinfo->et_group_next++; +if (ctx->options &E2F_OPT_DEBUG && + ctx->options &E2F_OPT_MULTITHREAD ) +log_out (ctx,_ ("group %d finished\n" ), + tinfo->et_group_next);if (tinfo->et_group_next >= tinfo->et_group_end)return EXT2_ET_SCAN_FINISHED ; }
e2fsck/problem.c +6 -0
@@ -2594,6 +2594,12 @@ int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)if (*message) message =_ (message);if (!suppress) { +#ifdef HAVE_PTHREAD +if ((ctx->options &E2F_OPT_MULTITHREAD ) && ctx->global_ctx) +printf ("[Thread %d] " , + ctx->thread_info.et_thread_index); +#endif +if ((ctx->options &E2F_OPT_PREEN ) && !(ptr->flags &PR_PREEN_NOHDR )) { printf("%s: ", ctx->device_name ?
e2fsck/util.c +58 -3
77 lines not on this page · raw message
tests/f_multithread/expect.1 +3 -1
@@ -1,6 +1,8 @@ ext2fs_open2: Bad magic number in super-block ../e2fsck/e2fsck: Superblock invalid, trying backup blocks... -Pass 1: Checking inodes, blocks, and sizes +[Thread 0] Scan group range [0, 2) +[Thread 0] Pass 1: Checking inodes, blocks, and sizes +[Thread 0] Scanned group range [0, 2), inodes 3008 Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts
tests/f_multithread_logfile/expect.1 +3 -1
@@ -1,6 +1,8 @@ ext2fs_open2: Bad magic number in super-block ../e2fsck/e2fsck: Superblock invalid, trying backup blocks... -Pass 1: Checking inodes, blocks, and sizes +[Thread 0] Scan group range [0, 2) +[Thread 0] Pass 1: Checking inodes, blocks, and sizes +[Thread 0] Scanned group range [0, 2), inodes 3008 Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts
tests/f_multithread_no/expect.1 +3 -1
@@ -1,6 +1,8 @@ ext2fs_open2: Bad magic number in super-block ../e2fsck/e2fsck: Superblock invalid, trying backup blocks... -Pass 1: Checking inodes, blocks, and sizes +[Thread 0] Scan group range [0, 2) +[Thread 0] Pass 1: Checking inodes, blocks, and sizes +[Thread 0] Scanned group range [0, 2), inodes 3008 Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts
Signature · 1 line
2.37.3
RFC 32/72 e2fsck: do not change global variables
In reply to Ritesh Harjani (IBM)From: Li Xi <[email protected]>
Global variables used in pass1 check are changed to local variables in this patch. This will avoid conflict between threads.
--- e2fsck/pass1.c | 75 +++++++++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 28 deletions(-)
e2fsck/pass1.c +47 -28
@@ -86,7 +86,6 @@ static void alloc_imagic_map(e2fsck_t ctx);static void mark_inode_bad (e2fsck_t ctx,ext2_ino_t ino);static void add_casefolded_dir (e2fsck_t ctx,ext2_ino_t ino);static void handle_fs_bad_blocks (e2fsck_t ctx); -static void process_inodes (e2fsck_t ctx,char *block_buf);static EXT2_QSORT_TYPE process_inode_cmp (const void *a,const void *b);static errcode_t scan_callback (ext2_filsys fs,ext2_inode_scan scan,dgrp_t group,void * priv_data);
@@ -121,15 +120,15 @@ struct process_inode_block { };struct scan_callback_struct { -e2fsck_t ctx; -char *block_buf; +e2fsck_t ctx; +char *block_buf; +struct process_inode_block *inodes_to_process; +int *process_inode_count; }; -/* -* For the inodes to process list. -*/ -static struct process_inode_block *inodes_to_process; -static int process_inode_count; +static void process_inodes (e2fsck_t ctx,char *block_buf, +struct process_inode_block *inodes_to_process, +int *process_inode_count);static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE -EXT2_MIN_BLOCK_LOG_SIZE +1 ];
@@ -1173,7 +1172,6 @@ static int e2fsck_should_abort(e2fsck_t ctx)void e2fsck_pass1_run (e2fsck_t ctx) {int i; -__u64 max_sizes;ext2_filsys fs = ctx->fs;ext2_ino_t ino =0 ;struct ext2_inode *inode =NULL ;
@@ -1196,6 +1194,8 @@ void e2fsck_pass1_run(e2fsck_t ctx)ext2_ino_t ino_threshold =0 ;dgrp_t ra_group =0 ;struct ea_quota ea_ibody_quota; +struct process_inode_block *inodes_to_process; +int process_inode_count;init_resource_track (&rtrack, ctx->fs->io);clear_problem_context (&pctx);
@@ -1220,17 +1220,6 @@ void e2fsck_pass1_run(e2fsck_t ctx)mtrace_print ("Pass 1" );#endif -#define EXT2_BPP (bits) (1ULL << ((bits) - 2)) - -for (i =EXT2_MIN_BLOCK_LOG_SIZE ; i <=EXT2_MAX_BLOCK_LOG_SIZE ; i++) { - max_sizes =EXT2_NDIR_BLOCKS +EXT2_BPP (i); - max_sizes = max_sizes +EXT2_BPP (i) *EXT2_BPP (i); - max_sizes = max_sizes +EXT2_BPP (i) *EXT2_BPP (i) *EXT2_BPP (i); - max_sizes = (max_sizes * (1UL << i)); - ext2_max_sizes[i -EXT2_MIN_BLOCK_LOG_SIZE ] = max_sizes; - } -#undef EXT2_BPP - imagic_fs =ext2fs_has_feature_imagic_inodes (sb); extent_fs =ext2fs_has_feature_extents (sb); inlinedata_fs =ext2fs_has_feature_inline_data (sb);
@@ -1368,6 +1357,8 @@ void e2fsck_pass1_run(e2fsck_t ctx) ctx->stashed_inode = inode; scan_struct.ctx = ctx; scan_struct.block_buf = block_buf; + scan_struct.inodes_to_process = inodes_to_process; + scan_struct.process_inode_count = &process_inode_count;ext2fs_set_inode_callback (scan, scan_callback, &scan_struct);if (ctx->progress && ((ctx->progress)(ctx,1 ,0 , ctx->fs->group_desc_count)))
@@ -2048,13 +2039,15 @@ void e2fsck_pass1_run(e2fsck_t ctx) goto endit;if (process_inode_count >= ctx->process_inode_size) { -process_inodes (ctx, block_buf); +process_inodes (ctx, block_buf, inodes_to_process, + &process_inode_count);if (e2fsck_should_abort (ctx)) goto endit; } } -process_inodes (ctx, block_buf); +process_inodes (ctx, block_buf, inodes_to_process, + &process_inode_count);ext2fs_close_inode_scan (scan); scan =NULL ;
@@ -2177,6 +2170,27 @@ endit: ctx->invalid_bitmaps++; } +static void init_ext2_max_sizes () +{ +int i; +__u64 max_sizes; + +/* +* Init ext2_max_sizes which will be immutable and shared between +* threads +*/ +#define EXT2_BPP (bits) (1ULL << ((bits) - 2)) + +for (i =EXT2_MIN_BLOCK_LOG_SIZE ; i <=EXT2_MAX_BLOCK_LOG_SIZE ; i++) { + max_sizes =EXT2_NDIR_BLOCKS +EXT2_BPP (i); + max_sizes = max_sizes +EXT2_BPP (i) *EXT2_BPP (i); + max_sizes = max_sizes +EXT2_BPP (i) *EXT2_BPP (i) *EXT2_BPP (i); + max_sizes = (max_sizes * (1UL << i)); + ext2_max_sizes[i -EXT2_MIN_BLOCK_LOG_SIZE ] = max_sizes; + } +#undef EXT2_BPP +} +#ifdef HAVE_PTHREAD static errcode_t e2fsck_pass1_merge_bitmap (ext2_filsys fs,ext2fs_generic_bitmap *src,ext2fs_generic_bitmap *dest)
@@ -2616,6 +2630,7 @@ out_abort:void e2fsck_pass1 (e2fsck_t ctx) { +init_ext2_max_sizes ();#ifdef HAVE_PTHREAD if (ctx->options &E2F_OPT_MULTITHREAD )e2fsck_pass1_multithread (ctx);
@@ -2641,7 +2656,9 @@ static errcode_t scan_callback(ext2_filsys fs, scan_struct = (struct scan_callback_struct *) priv_data; ctx = scan_struct->ctx; -process_inodes ((e2fsck_t ) fs->priv_data, scan_struct->block_buf); +process_inodes ((e2fsck_t ) fs->priv_data, scan_struct->block_buf, + scan_struct->inodes_to_process, + scan_struct->process_inode_count);if (ctx->progress) if ((ctx->progress)(ctx, 1, group+1,
@@ -2667,7 +2684,9 @@ static errcode_t scan_callback(ext2_filsys fs,/* * Process the inodes in the "inodes to process" list. */ -static void process_inodes (e2fsck_t ctx,char *block_buf) +static void process_inodes (e2fsck_t ctx,char *block_buf, +struct process_inode_block *inodes_to_process, +int *process_inode_count) {int i;struct ext2_inode *old_stashed_inode;
@@ -2679,15 +2698,15 @@ static void process_inodes(e2fsck_t ctx, char *block_buf)#if 0 printf ("begin process_inodes: " );#endif -if (process_inode_count ==0 ) +if (*process_inode_count ==0 )return ; old_operation =ehandler_operation (0 ); old_stashed_inode = ctx->stashed_inode; old_stashed_ino = ctx->stashed_ino; -qsort (inodes_to_process, process_inode_count, +qsort (inodes_to_process, *process_inode_count,sizeof (struct process_inode_block ), process_inode_cmp);clear_problem_context (&pctx); -for (i=0 ; i < process_inode_count; i++) { +for (i=0 ; i < *process_inode_count; i++) { pctx.inode = ctx->stashed_inode = (struct ext2_inode *) &inodes_to_process[i].inode; pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
@@ -2705,7 +2724,7 @@ static void process_inodes(e2fsck_t ctx, char *block_buf) } ctx->stashed_inode = old_stashed_inode; ctx->stashed_ino = old_stashed_ino; - process_inode_count =0 ; + *process_inode_count =0 ;#if 0 printf ("end process inodes\n" );#endif
Signature · 1 line
2.37.3
RFC 33/72 e2fsck: optimize the inserting of dir_info_db
In reply to Ritesh Harjani (IBM)From: Li Xi <[email protected]>
Binary search is now used when inserting an dir info to the array. Memmove is now used when moving array. Both of them improves the performance of inserting.
This patch is also a prepartion for the merging of two dir db arrays.
--- e2fsck/dirinfo.c | 172 ++++++++++++++++++++++++++++++----------------- 1 file changed, 112 insertions(+), 60 deletions(-)
e2fsck/dirinfo.c +112 -60
@@ -7,6 +7,7 @@#undef DIRINFO_DEBUG +#include <assert.h> #include "config.h" #include "e2fsck.h" #include <sys/stat.h>
@@ -122,6 +123,104 @@ static void setup_db(e2fsck_t ctx) "directory map"); } +/* +* Return the min index that has ino larger or equal to @ino +* If not found, return -ENOENT +*/ +static int +e2fsck_dir_info_min_larger_equal (struct dir_info_db *dir_info, +ext2_ino_t ino,ext2_ino_t *index) +{ +ext2_ino_t low =0 ; +ext2_ino_t mid, high; +ext2_ino_t tmp_ino; +int found =0 ; + +if (dir_info->count ==0 ) +return -ENOENT ; + + high = dir_info->count -1 ; +while (low <= high) { +/* sum may overflow, but result will fit into mid again */ + mid = (unsigned long long )(low + high) /2 ; + tmp_ino = dir_info->array[mid].ino; +if (ino == tmp_ino) { + *index = mid; + found =1 ; +return 0 ; + }else if (ino < tmp_ino) { +/* +* The mid ino is larger than @ino, remember the index +* here so we won't miss this ino +*/ + *index = mid; + found =1 ; +if (mid ==0 ) +break ; + high = mid -1 ; + }else { + low = mid +1 ; + } + } + +if (found) +return 0 ; + +return -ENOENT ; +} + +/* +* +* Insert an inode into the sorted array. The array should have at least one +* free slot. +* +* Normally, add_dir_info is called with each inode in +* sequential order; but once in a while (like when pass 3 +* needs to recreate the root directory or lost+found +* directory) it is called out of order. In those cases, we +* need to move the dir_info entries down to make room, since +* the dir_info array needs to be sorted by inode number for +* get_dir_info()'s sake. +*/ +static void e2fsck_insert_dir_info (struct dir_info_db *dir_info,ext2_ino_t ino,ext2_ino_t parent) +{ +ext2_ino_t index; +struct dir_info *dir; +size_t dir_size =sizeof (*dir); +struct dir_info *array = dir_info->array; +ext2_ino_t array_count = dir_info->count; +int err; + +/* +* Removing this check won't break anything. But since seqential ino +* inserting happens a lot, this check avoids binary search. +*/ +if (array_count ==0 || array[array_count -1 ].ino < ino) { + dir = &array[array_count]; + dir_info->count++; + goto out; + } + + err =e2fsck_dir_info_min_larger_equal (dir_info, ino, &index); +if (err >=0 && array[index].ino == ino) { + dir = &array[index]; + goto out; + } +if (err <0 ) { + dir = &array[array_count]; + dir_info->count++; + goto out; + } + + dir = &array[index]; +memmove ((char *)dir + dir_size, dir, dir_size * (array_count - index)); + dir_info->count++; +out: + dir->ino = ino; + dir->dotdot = parent; + dir->parent = parent; +} +/* * This subroutine is called during pass1 to create a directory info * entry. During pass1, the passed-in parent is 0; it will get filled
@@ -171,30 +270,7 @@ void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent) }#endif -/* -* Normally, add_dir_info is called with each inode in -* sequential order; but once in a while (like when pass 3 -* needs to recreate the root directory or lost+found -* directory) it is called out of order. In those cases, we -* need to move the dir_info entries down to make room, since -* the dir_info array needs to be sorted by inode number for -* get_dir_info()'s sake. -*/ -if (ctx->dir_info->count && - ctx->dir_info->array[ctx->dir_info->count-1 ].ino >= ino) { -for (i = ctx->dir_info->count-1 ; i >0 ; i--) -if (ctx->dir_info->array[i-1 ].ino < ino) -break ; - dir = &ctx->dir_info->array[i]; -if (dir->ino != ino) -for (j = ctx->dir_info->count++; j > i; j--) - ctx->dir_info->array[j] = ctx->dir_info->array[j-1 ]; - }else - dir = &ctx->dir_info->array[ctx->dir_info->count++]; - - dir->ino = ino; - dir->dotdot = parent; - dir->parent = parent; +e2fsck_insert_dir_info (ctx->dir_info, ino, parent); }/*
@@ -204,7 +280,8 @@ void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)static struct dir_info *e2fsck_get_dir_info (e2fsck_t ctx,ext2_ino_t ino) {struct dir_info_db *db = ctx->dir_info; -ext2_ino_t low, high, mid; +ext2_ino_t index; +int err;if (!db)return 0 ;
@@ -245,44 +322,19 @@ static struct dir_info *e2fsck_get_dir_info(e2fsck_t ctx, ext2_ino_t ino)if (db->last_lookup && db->last_lookup->ino == ino)return db->last_lookup; - low =0 ; - high = ctx->dir_info->count -1 ; -if (ino == ctx->dir_info->array[low].ino) { + err =e2fsck_dir_info_min_larger_equal (ctx->dir_info, ino, &index); +if (err <0 ) +return NULL ; +assert (ino <= ctx->dir_info->array[index].ino); +if (ino == ctx->dir_info->array[index].ino) {#ifdef DIRINFO_DEBUG -printf ("(%u,%u,%u)\n" , ino, - ctx->dir_info->array[low].dotdot, - ctx->dir_info->array[low].parent); +printf ("(%d,%d,%d)\n" , ino, + ctx->dir_info->array[index].dotdot, + ctx->dir_info->array[index].parent);#endif -return &ctx->dir_info->array[low]; +return &ctx->dir_info->array[index]; } -if (ino == ctx->dir_info->array[high].ino) { -#ifdef DIRINFO_DEBUG -printf ("(%u,%u,%u)\n" , ino, - ctx->dir_info->array[high].dotdot, - ctx->dir_info->array[high].parent); -#endif -return &ctx->dir_info->array[high]; - } - -while (low < high) { -/* sum may overflow, but result will fit into mid again */ - mid = (unsigned long long )(low + high) /2 ; -if (mid == low || mid == high) -break ; -if (ino == ctx->dir_info->array[mid].ino) { -#ifdef DIRINFO_DEBUG -printf ("(%u,%u,%u)\n" , ino, - ctx->dir_info->array[mid].dotdot, - ctx->dir_info->array[mid].parent); -#endif -return &ctx->dir_info->array[mid]; - } -if (ino < ctx->dir_info->array[mid].ino) - high = mid; -else - low = mid; - } -return 0 ; +return NULL ; } static void e2fsck_put_dir_info(e2fsck_t ctx EXT2FS_NO_TDB_UNUSED,
Signature · 1 line
2.37.3
RFC 34/72 e2fsck: merge dir_info after thread finishes
In reply to Ritesh Harjani (IBM)From: Li Xi <[email protected]>
dir_info need be merged after thread finish.
--- e2fsck/dirinfo.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ e2fsck/e2fsck.h | 2 ++ e2fsck/pass1.c | 53 +++++++++++++++++++++++++++++++++++++- 3 files changed, 120 insertions(+), 1 deletion(-)
e2fsck/dirinfo.c +66 -0
@@ -169,6 +169,72 @@ e2fsck_dir_info_min_larger_equal(struct dir_info_db *dir_info,return -ENOENT ; } +/* +* Merge two sorted dir info to @dest +*/ +void e2fsck_merge_dir_info (e2fsck_t ctx,struct dir_info_db *src, +struct dir_info_db *dest) +{ +size_t size_dir_info =sizeof (struct dir_info ); +ext2_ino_t size = dest->size; +struct dir_info *src_array = src->array; +struct dir_info *dest_array = dest->array; +ext2_ino_t src_count = src->count; +ext2_ino_t dest_count = dest->count; +ext2_ino_t total_count = src_count + dest_count; +struct dir_info *tmp_array; +struct dir_info *array_ptr; +ext2_ino_t src_index =0 ; +ext2_ino_t dest_index =0 ; + +if (src->count ==0 ) +return ; + +if (size < total_count) + size = total_count; + +if (size < src->size) + size = src->size; + + tmp_array =e2fsck_allocate_memory (ctx, size * size_dir_info, +"directory map" ); + array_ptr = tmp_array; +/* +* This can be improved by binary search and memcpy, but codes +* would be more complex. And if the groups distributed to each +* thread are strided, this implementation won't be too bad +* comparing to the optimiztion. +*/ +while (src_index < src_count || dest_index < dest_count) { +if (src_index >= src_count) { +memcpy (array_ptr, &dest_array[dest_index], + (dest_count - dest_index) * size_dir_info); +break ; + } +if (dest_index >= dest_count) { +memcpy (array_ptr, &src_array[src_index], + (src_count - src_index) * size_dir_info); +break ; + } +if (src_array[src_index].ino < dest_array[dest_index].ino) { + *array_ptr = src_array[src_index]; + src_index++; + }else { +assert (src_array[src_index].ino > + dest_array[dest_index].ino); + *array_ptr = dest_array[dest_index]; + dest_index++; + } + array_ptr++; + } + +if (dest->array) +ext2fs_free_mem (&dest->array); + dest->array = tmp_array; + dest->size = size; + dest->count = total_count; +} +/* * * Insert an inode into the sorted array. The array should have at least one
e2fsck/e2fsck.h +2 -0
@@ -546,6 +546,8 @@ extern void read_bad_blocks_file(e2fsck_t ctx, const char *bad_blocks_file,/* dirinfo.c */ extern void e2fsck_add_dir_info (e2fsck_t ctx,ext2_ino_t ino,ext2_ino_t parent); +void e2fsck_merge_dir_info (e2fsck_t ctx,struct dir_info_db *src, +struct dir_info_db *dest);extern void e2fsck_free_dir_info (e2fsck_t ctx);extern int e2fsck_get_num_dirinfo (e2fsck_t ctx);extern struct dir_info_iter *e2fsck_dir_info_iter_begin (e2fsck_t ctx);
e2fsck/pass1.c +52 -1
87 lines not on this page · raw message
Signature · 1 line
2.37.3
RFC 35/72 e2fsck: rbtree bitmap for dir
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
Only rbtree support merge operation now, use it for bitmaps.
--- e2fsck/pass1.c | 1 + 1 file changed, 1 insertion(+)
e2fsck/pass1.c +1 -0
@@ -1240,6 +1240,7 @@ void e2fsck_pass1_run(e2fsck_t ctx) } pctx.errcode =e2fsck_allocate_inode_bitmap (fs,_ ("directory inode map" ), + ctx->global_ctx ?EXT2FS_BMAP64_RBTREE :EXT2FS_BMAP64_AUTODIR ,"inode_dir_map" , &ctx->inode_dir_map);if (pctx.errcode) {
Signature · 1 line
2.37.3
RFC 36/72 e2fsck: merge icounts after thread finishes
In reply to Ritesh Harjani (IBM)From: Li Xi <[email protected]>
Merge inode_count and inode_link_info properly after threads finish.
--- e2fsck/pass1.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+)
e2fsck/pass1.c +48 -0
@@ -2341,6 +2341,41 @@ static void e2fsck_pass1_merge_dir_info(e2fsck_t global_ctx, e2fsck_t thread_ctx global_ctx->dir_info); } +static inline errcode_t +e2fsck_pass1_merge_icount (ext2_icount_t *dest_icount, +ext2_icount_t *src_icount) +{ +if (*src_icount) { +if (*dest_icount ==NULL ) { + *dest_icount = *src_icount; + *src_icount =NULL ; + }else { +errcode_t ret; + + ret =ext2fs_icount_merge (*src_icount, + *dest_icount); +if (ret) +return ret; + } + } + +return 0 ; +} + +static errcode_t e2fsck_pass1_merge_icounts (e2fsck_t global_ctx,e2fsck_t thread_ctx) +{ +errcode_t ret; + + ret =e2fsck_pass1_merge_icount (&global_ctx->inode_count, + &thread_ctx->inode_count); +if (ret) +return ret; + ret =e2fsck_pass1_merge_icount (&global_ctx->inode_link_info, + &thread_ctx->inode_link_info); + +return ret; +} +static int e2fsck_pass1_thread_join_one (e2fsck_t global_ctx,e2fsck_t thread_ctx) {errcode_t retval =0 ;
@@ -2361,6 +2396,8 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctxext2fs_block_bitmap block_ea_map = global_ctx->block_ea_map;ext2fs_block_bitmap block_metadata_map = global_ctx->block_metadata_map;ext2fs_block_bitmap inodes_to_rebuild = global_ctx->inodes_to_rebuild; +ext2_icount_t inode_count = global_ctx->inode_count; +ext2_icount_t inode_link_info = global_ctx->inode_link_info;#ifdef HAVE_SETJMP_H jmp_buf old_jmp;
@@ -2385,6 +2422,8 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx global_ctx->block_metadata_map = block_metadata_map; global_ctx->dir_info = dir_info;e2fsck_pass1_merge_dir_info (global_ctx, thread_ctx); + global_ctx->inode_count = inode_count; + global_ctx->inode_link_info = inode_link_info;/* Keep the global singal flags*/ global_ctx->flags |= (flags & E2F_FLAG_SIGNAL_MASK) |
@@ -2396,6 +2435,13 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx global_fs->priv_data = global_ctx; global_ctx->fs = global_fs; + retval =e2fsck_pass1_merge_icounts (global_ctx, thread_ctx); +if (retval) { +com_err (global_ctx->program_name,0 , +_ ("while merging icounts\n" )); +return retval; + } + retval =ext2fs_merge_fs (&(thread_ctx->fs));if (retval) {com_err (global_ctx->program_name,0 ,_ ("while merging fs\n" ));
@@ -2478,6 +2524,8 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx)e2fsck_pass1_free_bitmap (&thread_ctx->block_ea_map);e2fsck_pass1_free_bitmap (&thread_ctx->block_metadata_map);e2fsck_free_dir_info (thread_ctx); +ext2fs_free_icount (thread_ctx->inode_count); +ext2fs_free_icount (thread_ctx->inode_link_info);if (thread_ctx->logf)fclose (thread_ctx->logf);
Signature · 1 line
2.37.3
RFC 37/72 e2fsck: add debug codes for multiple threads
In reply to Ritesh Harjani (IBM)From: Li Xi <[email protected]>
These debug codes are added to run the multiple pass1 check thread one by one in order. If all the codes are correct, fsck of multiple threads should have exactly the same outcome with single thread.
--- e2fsck/e2fsck.h | 16 ++++++++++++++++ e2fsck/pass1.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+)
e2fsck/e2fsck.h +16 -0
@@ -489,6 +489,18 @@ struct e2fsck_struct { }; #ifdef HAVE_PTHREAD +#ifdef DEBUG_THREADS +/* + * Enabling DEBUG_THREADS would cause the parallel + * fsck threads run sequentially. + */ +struct e2fsck_thread_debug { + pthread_mutex_t etd_mutex; + pthread_cond_t etd_cond; + int etd_finished_threads; +}; +#endif + struct e2fsck_thread_info { /* ID returned by pthread_create() */ pthread_t eti_thread_id;
@@ -498,7 +510,11 @@ struct e2fsck_thread_info {int eti_started;/* Context used for this thread */ e2fsck_t eti_thread_ctx; +#ifdef DEBUG_THREADS +struct e2fsck_thread_debug *eti_debug; +#endif }; +#endif /* Data structures to evaluate whether an extent tree needs rebuilding. */
e2fsck/pass1.c +29 -0
@@ -2575,6 +2575,18 @@ static void *e2fsck_pass1_thread(void *arg) {struct e2fsck_thread_info *info = arg;e2fsck_t thread_ctx = info->eti_thread_ctx; +#ifdef DEBUG_THREADS +struct e2fsck_thread_debug *thread_debug = info->eti_debug; +#endif + +#ifdef DEBUG_THREADS +pthread_mutex_lock (&thread_debug->etd_mutex); +while (info->eti_thread_index > thread_debug->etd_finished_threads) { +pthread_cond_wait (&thread_debug->etd_cond, + &thread_debug->etd_mutex); + } +pthread_mutex_unlock (&thread_debug->etd_mutex); +#endif #ifdef HAVE_SETJMP_H /*
@@ -2599,6 +2611,14 @@ out: thread_ctx->thread_info.et_group_start, thread_ctx->thread_info.et_group_end, thread_ctx->thread_info.et_inode_number); + +#ifdef DEBUG_THREADS +pthread_mutex_lock (&thread_debug->etd_mutex); + thread_debug->etd_finished_threads++; +pthread_cond_broadcast (&thread_debug->etd_cond); +pthread_mutex_unlock (&thread_debug->etd_mutex); +#endif +return NULL ; }
@@ -2612,6 +2632,12 @@ static int e2fsck_pass1_threads_start(struct e2fsck_thread_info **pinfo,struct e2fsck_thread_info *tmp_pinfo;int i;e2fsck_t thread_ctx; +#ifdef DEBUG_THREADS +struct e2fsck_thread_debug thread_debug = + {PTHREAD_MUTEX_INITIALIZER ,PTHREAD_COND_INITIALIZER ,0 }; + + thread_debug.etd_finished_threads =0 ; +#endif retval =pthread_attr_init (&attr);if (retval) {
@@ -2632,6 +2658,9 @@ static int e2fsck_pass1_threads_start(struct e2fsck_thread_info **pinfo,for (i =0 ; i < num_threads; i++) { tmp_pinfo = &infos[i]; tmp_pinfo->eti_thread_index = i; +#ifdef DEBUG_THREADS + tmp_pinfo->eti_debug = &thread_debug; +#endif retval =e2fsck_pass1_thread_prepare (global_ctx, &thread_ctx, i, num_threads);if (retval) {
Signature · 1 line
2.37.3
RFC 38/72 e2fsck: merge counts after threads finish
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
Merge counts properly.
--- e2fsck/pass1.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)
e2fsck/pass1.c +34 -0
@@ -2398,6 +2398,23 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctxext2fs_block_bitmap inodes_to_rebuild = global_ctx->inodes_to_rebuild;ext2_icount_t inode_count = global_ctx->inode_count;ext2_icount_t inode_link_info = global_ctx->inode_link_info; +__u32 fs_directory_count = global_ctx->fs_directory_count; +__u32 fs_regular_count = global_ctx->fs_regular_count; +__u32 fs_blockdev_count = global_ctx->fs_blockdev_count; +__u32 fs_chardev_count = global_ctx->fs_chardev_count; +__u32 fs_links_count = global_ctx->fs_links_count; +__u32 fs_symlinks_count = global_ctx->fs_symlinks_count; +__u32 fs_fast_symlinks_count = global_ctx->fs_fast_symlinks_count; +__u32 fs_fifo_count = global_ctx->fs_fifo_count; +__u32 fs_total_count = global_ctx->fs_total_count; +__u32 fs_badblocks_count = global_ctx->fs_badblocks_count; +__u32 fs_sockets_count = global_ctx->fs_sockets_count; +__u32 fs_ind_count = global_ctx->fs_ind_count; +__u32 fs_dind_count = global_ctx->fs_dind_count; +__u32 fs_tind_count = global_ctx->fs_tind_count; +__u32 fs_fragmented = global_ctx->fs_fragmented; +__u32 fs_fragmented_dir = global_ctx->fs_fragmented_dir; +__u32 large_files = global_ctx->large_files;#ifdef HAVE_SETJMP_H jmp_buf old_jmp;
@@ -2424,6 +2441,23 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctxe2fsck_pass1_merge_dir_info (global_ctx, thread_ctx); global_ctx->inode_count = inode_count; global_ctx->inode_link_info = inode_link_info; + global_ctx->fs_directory_count += fs_directory_count; + global_ctx->fs_regular_count += fs_regular_count; + global_ctx->fs_blockdev_count += fs_blockdev_count; + global_ctx->fs_chardev_count += fs_chardev_count; + global_ctx->fs_links_count += fs_links_count; + global_ctx->fs_symlinks_count += fs_symlinks_count; + global_ctx->fs_fast_symlinks_count += fs_fast_symlinks_count; + global_ctx->fs_fifo_count += fs_fifo_count; + global_ctx->fs_total_count += fs_total_count; + global_ctx->fs_badblocks_count += fs_badblocks_count; + global_ctx->fs_sockets_count += fs_sockets_count; + global_ctx->fs_ind_count += fs_ind_count; + global_ctx->fs_dind_count += fs_dind_count; + global_ctx->fs_tind_count += fs_tind_count; + global_ctx->fs_fragmented += fs_fragmented; + global_ctx->fs_fragmented_dir += fs_fragmented_dir; + global_ctx->large_files += large_files;/* Keep the global singal flags*/ global_ctx->flags |= (flags & E2F_FLAG_SIGNAL_MASK) |
Signature · 1 line
2.37.3
RFC 39/72 e2fsck: merge dx_dir_info after threads finish
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
Merge properly.
--- e2fsck/dx_dirinfo.c | 64 +++++++++++++++++++++++++++++++++++++++++++++ e2fsck/e2fsck.h | 1 + e2fsck/pass1.c | 23 ++++++++++++++++ 3 files changed, 88 insertions(+)
e2fsck/dx_dirinfo.c +64 -0
@@ -5,6 +5,7 @@* under the terms of the GNU Public License. */ +#include <assert.h> #include "config.h" #include "e2fsck.h"
@@ -79,6 +80,69 @@ void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, struct ext2_inode *inode, "dx_block info array"); } +/* +* Merge two sorted dir info to @dest +*/ +void e2fsck_merge_dx_dir (e2fsck_t global_ctx,e2fsck_t thread_ctx) +{ +struct dx_dir_info *src_array = thread_ctx->dx_dir_info; +struct dx_dir_info *dest_array = global_ctx->dx_dir_info; +size_t size_dx_info =sizeof (struct dx_dir_info ); +ext2_ino_t size = global_ctx->dx_dir_info_size; +ext2_ino_t src_count = thread_ctx->dx_dir_info_count; +ext2_ino_t dest_count = global_ctx->dx_dir_info_count; +ext2_ino_t total_count = src_count + dest_count; +struct dx_dir_info *array; +struct dx_dir_info *array_ptr; +ext2_ino_t src_index =0 , dest_index =0 ; + +if (thread_ctx->dx_dir_info_count ==0 ) +return ; + +if (size < total_count) + size = total_count; + + array =e2fsck_allocate_memory (global_ctx, size * size_dx_info, +"directory map" ); + array_ptr = array; +/* +* This can be improved by binary search and memcpy, but codes +* would be more complex. And if the groups distributed to each +* thread are strided, this implementation won't be too bad +* comparing to the optimiztion. +*/ +while (src_index < src_count || dest_index < dest_count) { +if (src_index >= src_count) { +memcpy (array_ptr, &dest_array[dest_index], + (dest_count - dest_index) * size_dx_info); +break ; + } +if (dest_index >= dest_count) { +memcpy (array_ptr, &src_array[src_index], + (src_count - src_index) * size_dx_info); +break ; + } +if (src_array[src_index].ino < dest_array[dest_index].ino) { + *array_ptr = src_array[src_index]; + src_index++; + }else { +assert (src_array[src_index].ino > + dest_array[dest_index].ino); + *array_ptr = dest_array[dest_index]; + dest_index++; + } + array_ptr++; + } + +if (global_ctx->dx_dir_info) +ext2fs_free_mem (&global_ctx->dx_dir_info); +if (thread_ctx->dx_dir_info) +ext2fs_free_mem (&thread_ctx->dx_dir_info); + global_ctx->dx_dir_info = array; + global_ctx->dx_dir_info_size = size; + global_ctx->dx_dir_info_count = total_count; +} +/* * get_dx_dir_info() --- given an inode number, try to find the directory * information entry for it.
e2fsck/e2fsck.h +1 -0
@@ -578,6 +578,7 @@ extern int e2fsck_dir_info_get_parent(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t *parent);extern int e2fsck_dir_info_get_dotdot (e2fsck_t ctx,ext2_ino_t ino,ext2_ino_t *dotdot); +extern void e2fsck_merge_dx_dir (e2fsck_t global_ctx,e2fsck_t thread_ctx);/* dx_dirinfo.c */ extern void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino,
e2fsck/pass1.c +23 -0
@@ -2341,6 +2341,22 @@ static void e2fsck_pass1_merge_dir_info(e2fsck_t global_ctx, e2fsck_t thread_ctx global_ctx->dir_info); } +static void e2fsck_pass1_merge_dx_dir (e2fsck_t global_ctx,e2fsck_t thread_ctx) +{ +if (thread_ctx->dx_dir_info ==NULL ) +return ; + +if (global_ctx->dx_dir_info ==NULL ) { + global_ctx->dx_dir_info = thread_ctx->dx_dir_info; + global_ctx->dx_dir_info_size = thread_ctx->dx_dir_info_size; + global_ctx->dx_dir_info_count = thread_ctx->dx_dir_info_count; + thread_ctx->dx_dir_info =NULL ; +return ; + } + +e2fsck_merge_dx_dir (global_ctx, thread_ctx); +} +static inline errcode_t e2fsck_pass1_merge_icount (ext2_icount_t *dest_icount,ext2_icount_t *src_icount)
@@ -2386,6 +2402,7 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctxext2_filsys global_fs = global_ctx->fs;ext2fs_inode_bitmap inode_bad_map = global_ctx->inode_bad_map;struct dir_info_db *dir_info = global_ctx->dir_info; +struct dx_dir_info *dx_dir_info = global_ctx->dx_dir_info;ext2fs_inode_bitmap inode_used_map = global_ctx->inode_used_map;ext2fs_inode_bitmap inode_dir_map = global_ctx->inode_dir_map;ext2fs_inode_bitmap inode_bb_map = global_ctx->inode_bb_map;
@@ -2415,6 +2432,8 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx__u32 fs_fragmented = global_ctx->fs_fragmented;__u32 fs_fragmented_dir = global_ctx->fs_fragmented_dir;__u32 large_files = global_ctx->large_files; +ext2_ino_t dx_dir_info_size = global_ctx->dx_dir_info_size; +ext2_ino_t dx_dir_info_count = global_ctx->dx_dir_info_count;#ifdef HAVE_SETJMP_H jmp_buf old_jmp;
@@ -2439,6 +2458,10 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx global_ctx->block_metadata_map = block_metadata_map; global_ctx->dir_info = dir_info;e2fsck_pass1_merge_dir_info (global_ctx, thread_ctx); + global_ctx->dx_dir_info = dx_dir_info; + global_ctx->dx_dir_info_count = dx_dir_info_count; + global_ctx->dx_dir_info_size = dx_dir_info_size; +e2fsck_pass1_merge_dx_dir (global_ctx, thread_ctx); global_ctx->inode_count = inode_count; global_ctx->inode_link_info = inode_link_info; global_ctx->fs_directory_count += fs_directory_count;
Signature · 1 line
2.37.3
RFC 40/72 e2fsck: merge dirs_to_hash when threads finish
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
@dirs_to_hash list need be merged after threads finish, test covered by t_dangerous.
--- e2fsck/pass1.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
e2fsck/pass1.c +30 -0
@@ -2392,6 +2392,25 @@ static errcode_t e2fsck_pass1_merge_icounts(e2fsck_t global_ctx, e2fsck_t threadreturn ret; } +static errcode_t e2fsck_pass1_merge_dirs_to_hash (e2fsck_t global_ctx, +e2fsck_t thread_ctx) +{ +errcode_t retval =0 ; + +if (!thread_ctx->dirs_to_hash) +return 0 ; + +if (!global_ctx->dirs_to_hash) + retval =ext2fs_badblocks_copy (thread_ctx->dirs_to_hash, + &global_ctx->dirs_to_hash); +else + retval =ext2fs_badblocks_merge (thread_ctx->dirs_to_hash, + global_ctx->dirs_to_hash); + +return retval; +} + +static int e2fsck_pass1_thread_join_one (e2fsck_t global_ctx,e2fsck_t thread_ctx) {errcode_t retval =0 ;
@@ -2434,6 +2453,7 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx__u32 large_files = global_ctx->large_files;ext2_ino_t dx_dir_info_size = global_ctx->dx_dir_info_size;ext2_ino_t dx_dir_info_count = global_ctx->dx_dir_info_count; +ext2_u32_list dirs_to_hash = global_ctx->dirs_to_hash;#ifdef HAVE_SETJMP_H jmp_buf old_jmp;
@@ -2504,6 +2524,14 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctxcom_err (global_ctx->program_name,0 ,_ ("while merging fs\n" ));return retval; } + global_ctx->dirs_to_hash = dirs_to_hash; + retval =e2fsck_pass1_merge_dirs_to_hash (global_ctx, thread_ctx); +if (retval) { +com_err (global_ctx->program_name,0 , +_ ("while merging dirs to hash\n" )); +return retval; + } + retval =e2fsck_pass1_merge_bitmap (global_fs, &thread_ctx->inode_used_map, &global_ctx->inode_used_map);
@@ -2583,6 +2611,8 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx)e2fsck_free_dir_info (thread_ctx);ext2fs_free_icount (thread_ctx->inode_count);ext2fs_free_icount (thread_ctx->inode_link_info); +if (thread_ctx->dirs_to_hash) +ext2fs_badblocks_list_free (thread_ctx->dirs_to_hash);if (thread_ctx->logf)fclose (thread_ctx->logf);
Signature · 1 line
2.37.3
RFC 41/72 e2fsck: merge context flags properly
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
e2fsck might restart after pass1, so we should keep flags if possible, this patch try to fix f_illitable_flexbg failure
--- e2fsck/pass1.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
e2fsck/pass1.c +1 -3
@@ -2502,9 +2502,7 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx global_ctx->fs_fragmented_dir += fs_fragmented_dir; global_ctx->large_files += large_files; -/* Keep the global singal flags*/ - global_ctx->flags |= (flags &E2F_FLAG_SIGNAL_MASK ) | - (global_ctx->flags &E2F_FLAG_SIGNAL_MASK ); + global_ctx->flags |= flags; global_ctx->logf = global_logf; global_ctx->problem_logf = global_problem_logf; global_ctx->global_ctx =NULL ;
Signature · 1 line
2.37.3
RFC 42/72 e2fsck: merge quota context after threads finish
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
Every threads calculate its own quota accounting,
merge them after threads finish.
--- e2fsck/pass1.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
e2fsck/pass1.c +14 -0
@@ -2317,6 +2317,12 @@ static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *threif (thread_context->options &E2F_OPT_MULTITHREAD )log_out (thread_context,_ ("Scan group range [%d, %d)\n" ), tinfo->et_group_start, tinfo->et_group_end); + retval =quota_init_context (&thread_context->qctx, thread_fs,0 ); +if (retval) { +com_err (global_ctx->program_name, retval, +"while init quota context" ); + goto out_fs; + } *thread_ctx = thread_context;return 0 ; out_fs:
@@ -2454,6 +2460,7 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctxext2_ino_t dx_dir_info_size = global_ctx->dx_dir_info_size;ext2_ino_t dx_dir_info_count = global_ctx->dx_dir_info_count;ext2_u32_list dirs_to_hash = global_ctx->dirs_to_hash; +quota_ctx_t qctx = global_ctx->qctx;#ifdef HAVE_SETJMP_H jmp_buf old_jmp;
@@ -2530,6 +2537,12 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctxreturn retval; } + global_ctx->qctx = qctx; + retval =quota_merge_and_update_usage (global_ctx->qctx, + thread_ctx->qctx); +if (retval) +return retval; + retval =e2fsck_pass1_merge_bitmap (global_fs, &thread_ctx->inode_used_map, &global_ctx->inode_used_map);
@@ -2611,6 +2624,7 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx)ext2fs_free_icount (thread_ctx->inode_link_info);if (thread_ctx->dirs_to_hash)ext2fs_badblocks_list_free (thread_ctx->dirs_to_hash); +quota_release_context (&thread_ctx->qctx);if (thread_ctx->logf)fclose (thread_ctx->logf);
Signature · 1 line
2.37.3
RFC 43/72 e2fsck: serialize fix operations
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
Allow different threads to fix at the same time could be dangerous and error-prone now, and most of time parallel scanning and checking is important.
So this patch adds a mutex to serialize
fix operations during pass1.
And the good benefit of this, we don't need block allocations and free, superblock updates protection any more, since only fix operations during pass1 could touch them.
--- e2fsck/e2fsck.h | 6 +++++ e2fsck/pass1.c | 63 +++++++++++++++++++++++++++++++++++++++++++------ e2fsck/util.c | 38 +++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 7 deletions(-)
e2fsck/e2fsck.h +6 -0
@@ -484,6 +484,10 @@ struct e2fsck_struct {/* Undo file */ char *undo_file; +#ifdef HAVE_PTHREAD +/* serialize fix operation for multiple threads */ +pthread_mutex_t fs_fix_mutex; +#endif /* Fast commit replay state */ struct e2fsck_fc_replay_state fc_replay_state; };
@@ -787,6 +791,8 @@ extern errcode_t e2fsck_allocate_subcluster_bitmap(ext2_filsys fs,const char *profile_name, ext2fs_block_bitmap *ret);unsigned long long get_memory_size (void ); +extern void e2fsck_pass1_fix_lock (e2fsck_t ctx); +extern void e2fsck_pass1_fix_unlock (e2fsck_t ctx);/* unix.c */ extern void e2fsck_clear_progbar (e2fsck_t ctx);
e2fsck/pass1.c +56 -7
217 lines not on this page · raw message
e2fsck/util.c +38 -0
@@ -38,6 +38,10 @@#include <errno.h> #endif +#ifdef HAVE_PTHREAD +#include <pthread.h> +#endif +#include "e2fsck.h" extern e2fsck_t e2fsck_global_ctx;/* Try your very best not to use this! */
@@ -570,13 +574,45 @@ void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino, } } +#ifdef HAVE_PTHREAD +void e2fsck_pass1_fix_lock (e2fsck_t ctx) +{ +e2fsck_t global_ctx = ctx->global_ctx; +if (!global_ctx) + global_ctx = ctx; + +pthread_mutex_lock (&global_ctx->fs_fix_mutex); +} + +void e2fsck_pass1_fix_unlock (e2fsck_t ctx) +{ +e2fsck_t global_ctx = ctx->global_ctx; +if (!global_ctx) + global_ctx = ctx; + +pthread_mutex_unlock (&global_ctx->fs_fix_mutex); +} +#else +void e2fsck_pass1_fix_lock (e2fsck_t ctx) +{ + +} + +void e2fsck_pass1_fix_unlock (e2fsck_t ctx) +{ + +} +#endif +void e2fsck_write_inode_full (e2fsck_t ctx,unsigned long ino,struct ext2_inode * inode,int bufsize,const char *proc) {errcode_t retval; +e2fsck_pass1_fix_lock (ctx); retval =ext2fs_write_inode_full (ctx->fs, ino, inode, bufsize); +e2fsck_pass1_fix_unlock (ctx);if (retval) {com_err ("ext2fs_write_inode" , retval,_ ("while writing inode %lu in %s" ), ino, proc);
@@ -589,7 +625,9 @@ void e2fsck_write_inode(e2fsck_t ctx, unsigned long ino, {errcode_t retval; +e2fsck_pass1_fix_lock (ctx); retval =ext2fs_write_inode (ctx->fs, ino, inode); +e2fsck_pass1_fix_unlock (ctx);if (retval) {com_err ("ext2fs_write_inode" , retval,_ ("while writing inode %lu in %s" ), ino, proc);
Signature · 1 line
2.37.3
RFC 44/72 e2fsck: move some fixes out of parallel pthreads
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
We could only use @found_map_block to find free blocks after we have collectd all used blocks, so something like handle_fs_bad_blocks(), ext2fs_create_resize_inode(), e2fsck_pass1_dupblocks() really should be handled after all threads has been finished.
--- e2fsck/e2fsck.h | 4 + e2fsck/pass1.c | 296 ++++++++++++++++----------- e2fsck/util.c | 36 +++- tests/f_multithread/expect.1 | 2 +- tests/f_multithread_logfile/expect.1 | 2 +- tests/f_multithread_no/expect.1 | 2 +- 6 files changed, 210 insertions(+), 132 deletions(-)
e2fsck/e2fsck.h +4 -0
@@ -487,6 +487,8 @@ struct e2fsck_struct {#ifdef HAVE_PTHREAD /* serialize fix operation for multiple threads */ pthread_mutex_t fs_fix_mutex; +/* protect block_found_map, block_dup_map */ +pthread_mutex_t fs_block_map_mutex;#endif /* Fast commit replay state */ struct e2fsck_fc_replay_state fc_replay_state;
@@ -793,6 +795,8 @@ extern errcode_t e2fsck_allocate_subcluster_bitmap(ext2_filsys fs,unsigned long long get_memory_size (void );extern void e2fsck_pass1_fix_lock (e2fsck_t ctx);extern void e2fsck_pass1_fix_unlock (e2fsck_t ctx); +extern void e2fsck_pass1_block_map_lock (e2fsck_t ctx); +extern void e2fsck_pass1_block_map_unlock (e2fsck_t ctx);/* unix.c */ extern void e2fsck_clear_progbar (e2fsck_t ctx);
e2fsck/pass1.c +175 -121
533 lines not on this page · raw message
e2fsck/util.c +28 -8
@@ -575,23 +575,34 @@ void e2fsck_read_inode_full(e2fsck_t ctx, unsigned long ino, }#ifdef HAVE_PTHREAD +#define e2fsck_get_lock_context (ctx) \ + e2fsck_t global_ctx = ctx->global_ctx; \ + if (!global_ctx) \ + global_ctx = ctx; \ +void e2fsck_pass1_fix_lock (e2fsck_t ctx) { -e2fsck_t global_ctx = ctx->global_ctx; -if (!global_ctx) - global_ctx = ctx; - +e2fsck_get_lock_context (ctx);pthread_mutex_lock (&global_ctx->fs_fix_mutex); }void e2fsck_pass1_fix_unlock (e2fsck_t ctx) { -e2fsck_t global_ctx = ctx->global_ctx; -if (!global_ctx) - global_ctx = ctx; - +e2fsck_get_lock_context (ctx);pthread_mutex_unlock (&global_ctx->fs_fix_mutex); } + +void e2fsck_pass1_block_map_lock (e2fsck_t ctx) +{ +e2fsck_get_lock_context (ctx); +pthread_mutex_lock (&global_ctx->fs_block_map_mutex); +} + +void e2fsck_pass1_block_map_unlock (e2fsck_t ctx) +{ +e2fsck_get_lock_context (ctx); +pthread_mutex_unlock (&global_ctx->fs_block_map_mutex); +}#else void e2fsck_pass1_fix_lock (e2fsck_t ctx) {
@@ -601,6 +612,15 @@ void e2fsck_pass1_fix_lock(e2fsck_t ctx)void e2fsck_pass1_fix_unlock (e2fsck_t ctx) { +} + +void e2fsck_pass1_block_map_lock (e2fsck_t ctx) +{ + +} + +void e2fsck_pass1_block_map_unlock (e2fsck_t ctx) +{ }#endif
tests/f_multithread/expect.1 +1 -1
@@ -1,7 +1,7 @@ ext2fs_open2: Bad magic number in super-block ../e2fsck/e2fsck: Superblock invalid, trying backup blocks... +Pass 1: Checking inodes, blocks, and sizes [Thread 0] Scan group range [0, 2) -[Thread 0] Pass 1: Checking inodes, blocks, and sizes [Thread 0] Scanned group range [0, 2), inodes 3008 Pass 2: Checking directory structure Pass 3: Checking directory connectivity
tests/f_multithread_logfile/expect.1 +1 -1
@@ -1,7 +1,7 @@ ext2fs_open2: Bad magic number in super-block ../e2fsck/e2fsck: Superblock invalid, trying backup blocks... +Pass 1: Checking inodes, blocks, and sizes [Thread 0] Scan group range [0, 2) -[Thread 0] Pass 1: Checking inodes, blocks, and sizes [Thread 0] Scanned group range [0, 2), inodes 3008 Pass 2: Checking directory structure Pass 3: Checking directory connectivity
tests/f_multithread_no/expect.1 +1 -1
@@ -1,7 +1,7 @@ ext2fs_open2: Bad magic number in super-block ../e2fsck/e2fsck: Superblock invalid, trying backup blocks... +Pass 1: Checking inodes, blocks, and sizes [Thread 0] Scan group range [0, 2) -[Thread 0] Pass 1: Checking inodes, blocks, and sizes [Thread 0] Scanned group range [0, 2), inodes 3008 Pass 2: Checking directory structure Pass 3: Checking directory connectivity
Signature · 1 line
2.37.3
RFC 45/72 e2fsck: split and merge invalid bitmaps
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
Invalid bitmaps are splitted per thread, and we
should merge them after thread finish.
--- e2fsck/pass1.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+)
e2fsck/pass1.c +71 -0
@@ -2309,6 +2309,62 @@ static errcode_t e2fsck_open_channel_fs(ext2_filsys dest, e2fsck_t dest_context,return 0 ; } +static void e2fsck_pass1_copy_invalid_bitmaps (e2fsck_t global_ctx, +e2fsck_t thread_ctx) +{ +dgrp_t i, j; +dgrp_t grp_start = thread_ctx->thread_info.et_group_start; +dgrp_t grp_end = thread_ctx->thread_info.et_group_end; +dgrp_t total = grp_end - grp_start; + + thread_ctx->invalid_inode_bitmap_flag = +e2fsck_allocate_memory (global_ctx,sizeof (int ) * total, +"invalid_inode_bitmap" ); + thread_ctx->invalid_block_bitmap_flag = +e2fsck_allocate_memory (global_ctx,sizeof (int ) * total, +"invalid_block_bitmap" ); + thread_ctx->invalid_inode_table_flag = +e2fsck_allocate_memory (global_ctx,sizeof (int ) * total, +"invalid_inode_table" ); + +memcpy (thread_ctx->invalid_block_bitmap_flag, + &global_ctx->invalid_block_bitmap_flag[grp_start], + total *sizeof (int )); +memcpy (thread_ctx->invalid_inode_bitmap_flag, + &global_ctx->invalid_inode_bitmap_flag[grp_start], + total *sizeof (int )); +memcpy (thread_ctx->invalid_inode_table_flag, + &global_ctx->invalid_inode_table_flag[grp_start], + total *sizeof (int )); + + thread_ctx->invalid_bitmaps =0 ; +for (i = grp_start, j =0 ; i < grp_end; i++, j++) { +if (thread_ctx->invalid_block_bitmap_flag[j]) + thread_ctx->invalid_bitmaps++; +if (thread_ctx->invalid_inode_bitmap_flag[j]) + thread_ctx->invalid_bitmaps++; +if (thread_ctx->invalid_inode_table_flag[j]) + thread_ctx->invalid_bitmaps++; + } +} + +static void e2fsck_pass1_merge_invalid_bitmaps (e2fsck_t global_ctx, +e2fsck_t thread_ctx) +{ +dgrp_t i, j; +dgrp_t grp_start = thread_ctx->thread_info.et_group_start; +dgrp_t grp_end = thread_ctx->thread_info.et_group_end; +dgrp_t total = grp_end - grp_start; + +memcpy (&global_ctx->invalid_block_bitmap_flag[grp_start], + thread_ctx->invalid_block_bitmap_flag, total *sizeof (int )); +memcpy (&global_ctx->invalid_inode_bitmap_flag[grp_start], + thread_ctx->invalid_inode_bitmap_flag, total *sizeof (int )); +memcpy (&global_ctx->invalid_inode_table_flag[grp_start], + thread_ctx->invalid_inode_table_flag, total *sizeof (int )); + global_ctx->invalid_bitmaps += thread_ctx->invalid_bitmaps; +} +static errcode_t e2fsck_pass1_thread_prepare (e2fsck_t global_ctx,e2fsck_t *thread_ctx,int thread_index,int num_threads) {
@@ -2384,6 +2440,7 @@ static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *thre goto out_fs; } *thread_ctx = thread_context; +e2fsck_pass1_copy_invalid_bitmaps (global_ctx, thread_context);return 0 ; out_fs:ext2fs_merge_fs (&thread_fs);
@@ -2519,6 +2576,10 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctxext2_ino_t dx_dir_info_count = global_ctx->dx_dir_info_count;ext2_u32_list dirs_to_hash = global_ctx->dirs_to_hash;quota_ctx_t qctx = global_ctx->qctx; +int *invalid_block_bitmap_flag = global_ctx->invalid_block_bitmap_flag; +int *invalid_inode_bitmap_flag = global_ctx->invalid_inode_bitmap_flag; +int *invalid_inode_table_flag = global_ctx->invalid_inode_table_flag; +int invalid_bitmaps = global_ctx->invalid_bitmaps;#ifdef HAVE_SETJMP_H jmp_buf old_jmp;
@@ -2598,6 +2659,11 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx thread_ctx->qctx);if (retval)return retval; + global_ctx->invalid_block_bitmap_flag = invalid_block_bitmap_flag; + global_ctx->invalid_inode_bitmap_flag = invalid_inode_bitmap_flag; + global_ctx->invalid_inode_table_flag = invalid_inode_table_flag; + global_ctx->invalid_bitmaps = invalid_bitmaps; +e2fsck_pass1_merge_invalid_bitmaps (global_ctx, thread_ctx); retval = e2fsck_pass1_merge_bitmap(global_fs, &thread_ctx->inode_used_map,
@@ -2663,6 +2729,9 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx)if (thread_ctx->dirs_to_hash)ext2fs_badblocks_list_free (thread_ctx->dirs_to_hash);quota_release_context (&thread_ctx->qctx); +ext2fs_free_mem (&thread_ctx->invalid_block_bitmap_flag); +ext2fs_free_mem (&thread_ctx->invalid_inode_bitmap_flag); +ext2fs_free_mem (&thread_ctx->invalid_inode_table_flag);if (thread_ctx->logf)fclose (thread_ctx->logf);
@@ -2682,6 +2751,8 @@ static int e2fsck_pass1_threads_join(struct e2fsck_thread_info *infos,int i;struct e2fsck_thread_info *pinfo; +/* merge invalid bitmaps will recalculate it */ + global_ctx->invalid_bitmaps =0 ;for (i =0 ; i < num_threads; i++) { pinfo = &infos[i];
Signature · 1 line
2.37.3
RFC 46/72 e2fsck: merge EA blocks properly
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
EA blocks might be shared, merge them carefully.
--- e2fsck/e2fsck.h | 1 + e2fsck/pass1.c | 244 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 212 insertions(+), 33 deletions(-)
e2fsck/e2fsck.h +1 -0
@@ -333,6 +333,7 @@ struct e2fsck_struct {ext2_refcount_t refcount;ext2_refcount_t refcount_extra; +ext2_refcount_t refcount_orig;/* * Quota blocks and inodes to be charged for each ea block.
e2fsck/pass1.c +211 -33
341 lines not on this page · raw message
Signature · 1 line
2.37.3
RFC 47/72 e2fsck: kickoff mutex lock for block found map
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
Now @block_found_map is no longer shared by multiple threads, and @block_dup_map need be checked again after threads finish.
--- e2fsck/e2fsck.h | 9 +- e2fsck/pass1.c | 171 ++++++++++++++++++------------ e2fsck/util.c | 34 ++++-- tests/f_itable_collision/expect.1 | 3 - 4 files changed, 137 insertions(+), 80 deletions(-)
e2fsck/e2fsck.h +6 -3
@@ -211,6 +211,7 @@ struct resource_track {#define E2F_FLAG_TIME_INSANE 0x2000/* Time is insane */ #define E2F_FLAG_PROBLEMS_FIXED 0x4000/* At least one problem was fixed */ #define E2F_FLAG_ALLOC_OK 0x8000/* Can we allocate blocks? */ +#define E2F_FLAG_DUP_BLOCK 0x20000/* dup block found during pass1 */ #define E2F_RESET_FLAGS (E2F_FLAG_TIME_INSANE | E2F_FLAG_PROBLEMS_FIXED)
@@ -489,7 +490,7 @@ struct e2fsck_struct {/* serialize fix operation for multiple threads */ pthread_mutex_t fs_fix_mutex;/* protect block_found_map, block_dup_map */ -pthread_mutex_t fs_block_map_mutex; +pthread_rwlock_t fs_block_map_rwlock;#endif /* Fast commit replay state */ struct e2fsck_fc_replay_state fc_replay_state;
@@ -796,8 +797,10 @@ extern errcode_t e2fsck_allocate_subcluster_bitmap(ext2_filsys fs,unsigned long long get_memory_size (void );extern void e2fsck_pass1_fix_lock (e2fsck_t ctx);extern void e2fsck_pass1_fix_unlock (e2fsck_t ctx); -extern void e2fsck_pass1_block_map_lock (e2fsck_t ctx); -extern void e2fsck_pass1_block_map_unlock (e2fsck_t ctx); +extern void e2fsck_pass1_block_map_w_lock (e2fsck_t ctx); +extern void e2fsck_pass1_block_map_w_unlock (e2fsck_t ctx); +extern void e2fsck_pass1_block_map_r_lock (e2fsck_t ctx); +extern void e2fsck_pass1_block_map_r_unlock (e2fsck_t ctx);/* unix.c */ extern void e2fsck_clear_progbar (e2fsck_t ctx);
e2fsck/pass1.c +103 -68
350 lines not on this page · raw message
e2fsck/util.c +28 -6
@@ -592,17 +592,29 @@ void e2fsck_pass1_fix_unlock(e2fsck_t ctx) pthread_mutex_unlock(&global_ctx->fs_fix_mutex); } -void e2fsck_pass1_block_map_lock (e2fsck_t ctx) +void e2fsck_pass1_block_map_w_lock (e2fsck_t ctx) {e2fsck_get_lock_context (ctx); -pthread_mutex_lock (&global_ctx->fs_block_map_mutex); +pthread_rwlock_wrlock (&global_ctx->fs_block_map_rwlock); } -void e2fsck_pass1_block_map_unlock (e2fsck_t ctx) +void e2fsck_pass1_block_map_w_unlock (e2fsck_t ctx) {e2fsck_get_lock_context (ctx); -pthread_mutex_unlock (&global_ctx->fs_block_map_mutex); +pthread_rwlock_unlock (&global_ctx->fs_block_map_rwlock); } + +void e2fsck_pass1_block_map_r_lock (e2fsck_t ctx) +{ +e2fsck_get_lock_context (ctx); +pthread_rwlock_rdlock (&global_ctx->fs_block_map_rwlock); +} + +void e2fsck_pass1_block_map_r_unlock (e2fsck_t ctx) +{ +e2fsck_get_lock_context (ctx); +pthread_rwlock_unlock (&global_ctx->fs_block_map_rwlock); + }#else void e2fsck_pass1_fix_lock (e2fsck_t ctx) {
@@ -613,14 +625,24 @@ void e2fsck_pass1_fix_unlock(e2fsck_t ctx) { } +void e2fsck_pass1_block_map_w_lock (e2fsck_t ctx) +{ -void e2fsck_pass1_block_map_lock (e2fsck_t ctx) +} + +void e2fsck_pass1_block_map_w_unlock (e2fsck_t ctx) { } -void e2fsck_pass1_block_map_unlock (e2fsck_t ctx) +void e2fsck_pass1_block_map_r_lock (e2fsck_t ctx) { + +} + +void e2fsck_pass1_block_map_r_unlock (e2fsck_t ctx) +{ + }#endif
tests/f_itable_collision/expect.1 +0 -3
@@ -1,6 +1,5 @@ Pass 1: Checking inodes, blocks, and sizes Inode 12 block 37 conflicts with critical metadata, skipping block checks. -Illegal block number passed to ext2fs_test_block_bitmap #268435455 for in-use block map Illegal block number passed to ext2fs_mark_block_bitmap #268435455 for in-use block map Inode 12, i_blocks is 48, should be 56. Fix? yes
@@ -27,9 +26,7 @@ Clear inode? yes Restarting e2fsck from the beginning... Pass 1: Checking inodes, blocks, and sizes Inode 12 block 37 conflicts with critical metadata, skipping block checks. -Illegal block number passed to ext2fs_test_block_bitmap #4294967294 for in-use block map Illegal block number passed to ext2fs_mark_block_bitmap #4294967294 for in-use block map -Illegal block number passed to ext2fs_test_block_bitmap #268435455 for in-use block map Illegal block number passed to ext2fs_mark_block_bitmap #268435455 for in-use block map Running additional passes to resolve blocks claimed by more than one inode...
Signature · 1 line
2.37.3
RFC 48/72 e2fsck: allow admin specify number of threads
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
-m option is introduced to specify number of threads for pfsck.
--- e2fsck/e2fsck.h | 2 + e2fsck/pass1.c | 154 ++++++++++++++++---------- e2fsck/unix.c | 17 ++- tests/f_multithread/script | 2 +- tests/f_multithread_completion/script | 2 +- tests/f_multithread_logfile/script | 2 +- tests/f_multithread_no/script | 2 +- tests/f_multithread_preen/script | 2 +- tests/f_multithread_yes/script | 2 +- 9 files changed, 122 insertions(+), 63 deletions(-)
e2fsck/e2fsck.h +2 -0
@@ -487,6 +487,7 @@ struct e2fsck_struct {char *undo_file;#ifdef HAVE_PTHREAD +__u32 fs_num_threads;/* serialize fix operation for multiple threads */ pthread_mutex_t fs_fix_mutex;/* protect block_found_map, block_dup_map */
@@ -727,6 +728,7 @@ void check_resize_inode(e2fsck_t ctx);int check_init_orphan_file (e2fsck_t ctx);/* util.c */ +#define E2FSCK_MAX_THREADS (65536)extern void *e2fsck_allocate_memory (e2fsck_t ctx,unsigned long size,const char *description);extern int ask (e2fsck_t ctx,const char * string,int def);
e2fsck/pass1.c +98 -56
192 lines not on this page · raw message
e2fsck/unix.c +16 -1
@@ -826,6 +826,10 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)int res;/* result of sscanf */ #ifdef CONFIG_JBD_DEBUG char *jbd_debug; +#endif +#ifdef HAVE_PTHREAD +char *pm; +unsigned long thread_num;#endif unsigned long long phys_mem_kb, blk;
@@ -859,7 +863,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) ctx->readahead_kb = ~0ULL ;#ifdef HAVE_PTHREAD -while ((c =getopt (argc, argv,"pamnyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkz:" )) !=EOF ) +while ((c =getopt (argc, argv,"pam:nyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkz:" )) !=EOF ) #else while ((c = getopt(argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkz:")) != EOF)#endif
@@ -905,7 +909,18 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)break ;#ifdef HAVE_PTHREAD case 'm' : + thread_num =strtoul (optarg, &pm,0 ); +if (*pm) +fatal_error (ctx, +_ ("Invalid multiple thread num.\n" )); +if (thread_num >E2FSCK_MAX_THREADS ) { +fprintf (stderr, +_ ("threads %lu too large (max %lu)\n" ), + thread_num,E2FSCK_MAX_THREADS ); +fatal_error (ctx,0 ); + } ctx->options |=E2F_OPT_MULTITHREAD ; + ctx->fs_num_threads = thread_num;break ;#endif case 'n' :
tests/f_multithread/script +1 -1
@@ -1,4 +1,4 @@ -FSCK_OPT="-fy -m" +FSCK_OPT="-fy -m1" SECOND_FSCK_OPT=-yf . $cmd_dir/run_e2fsck
tests/f_multithread_completion/script +1 -1
@@ -1,4 +1,4 @@ -FSCK_OPT="-fy -m -C 1" +FSCK_OPT="-fy -m1 -C 1" SECOND_FSCK_OPT=-yf . $cmd_dir/run_e2fsck
tests/f_multithread_logfile/script +1 -1
@@ -1,5 +1,5 @@ LOG_FNAME="f_multithread_logfile_xxx" -FSCK_OPT="-fy -m -y -E log_filename=$LOG_FNAME" +FSCK_OPT="-fy -m1 -y -E log_filename=$LOG_FNAME" SKIP_VERIFY="true" ONE_PASS_ONLY="true" SKIP_CLEANUP="true"
tests/f_multithread_no/script +1 -1
@@ -1,4 +1,4 @@ -FSCK_OPT="-fn -m" +FSCK_OPT="-fn -m1" SECOND_FSCK_OPT=-yf . $cmd_dir/run_e2fsck
tests/f_multithread_preen/script +1 -1
@@ -1,4 +1,4 @@ -FSCK_OPT="-fp -m" +FSCK_OPT="-fp -m1" SECOND_FSCK_OPT=-yf . $cmd_dir/run_e2fsck
tests/f_multithread_yes/script +1 -1
@@ -1,4 +1,4 @@ -FSCK_OPT="-f -m" +FSCK_OPT="-f -m1" SECOND_FSCK_OPT=-yf . $cmd_dir/run_e2fsck
Signature · 1 line
2.37.3
RFC 49/72 e2fsck: adjust number of threads
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
number of threads should not exceed flex bg numbers, and output messages if we adjust threads number.
--- e2fsck/pass1.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-)
e2fsck/pass1.c +15 -17
@@ -1287,6 +1287,7 @@ static void e2fsck_pass1_set_thread_num(e2fsck_t ctx) } out: ctx->fs_num_threads = num_threads; + ctx->fs->fs_num_threads = num_threads; }#endif
@@ -2481,14 +2482,14 @@ static void e2fsck_pass1_merge_invalid_bitmaps(e2fsck_t global_ctx, }static errcode_t e2fsck_pass1_thread_prepare (e2fsck_t global_ctx,e2fsck_t *thread_ctx, -int thread_index,int num_threads) +int thread_index,int num_threads, +dgrp_t average_group) {errcode_t retval;e2fsck_t thread_context;ext2_filsys thread_fs;ext2_filsys global_fs = global_ctx->fs;struct e2fsck_thread *tinfo; -dgrp_t average_group;assert (global_ctx->inode_used_map ==NULL );assert (global_ctx->inode_dir_map ==NULL );
@@ -2535,16 +2536,9 @@ static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *thre thread_context->thread_info.et_thread_index = thread_index;set_up_logging (thread_context); -/* -* Distribute work to multiple threads: -* Each thread work on fs->group_desc_count / nthread groups. -*/ tinfo = &thread_context->thread_info; - average_group = thread_fs->group_desc_count / num_threads; -if (average_group ==0 ) - average_group =1 ; tinfo->et_group_start = average_group * thread_index; -if (thread_index == num_threads -1 ) +if (thread_index == global_fs->fs_num_threads -1 ) tinfo->et_group_end = thread_fs->group_desc_count;else tinfo->et_group_end = average_group * (thread_index +1 );
@@ -3060,12 +3054,13 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx) }static int e2fsck_pass1_threads_join (struct e2fsck_thread_info *infos, -int num_threads,e2fsck_t global_ctx) +e2fsck_t global_ctx) {errcode_t rc;errcode_t ret =0 ;int i;struct e2fsck_thread_info *pinfo; +int num_threads = global_ctx->fs_num_threads;/* merge invalid bitmaps will recalculate it */ global_ctx->invalid_bitmaps =0 ;
@@ -3147,7 +3142,7 @@ out: }static int e2fsck_pass1_threads_start (struct e2fsck_thread_info **pinfo, -int num_threads,e2fsck_t global_ctx) +e2fsck_t global_ctx) {struct e2fsck_thread_info *infos;pthread_attr_t attr;
@@ -3156,6 +3151,8 @@ static int e2fsck_pass1_threads_start(struct e2fsck_thread_info **pinfo,struct e2fsck_thread_info *tmp_pinfo;int i;e2fsck_t thread_ctx; +dgrp_t average_group; +int num_threads = global_ctx->fs_num_threads;#ifdef DEBUG_THREADS struct e2fsck_thread_debug thread_debug = {PTHREAD_MUTEX_INITIALIZER ,PTHREAD_COND_INITIALIZER ,0 };
@@ -3179,6 +3176,7 @@ static int e2fsck_pass1_threads_start(struct e2fsck_thread_info **pinfo,return retval; } + average_group =ext2fs_get_avg_group (global_ctx->fs);for (i =0 ; i < num_threads; i++) { tmp_pinfo = &infos[i]; tmp_pinfo->eti_thread_index = i;
@@ -3186,7 +3184,8 @@ static int e2fsck_pass1_threads_start(struct e2fsck_thread_info **pinfo, tmp_pinfo->eti_debug = &thread_debug;#endif retval =e2fsck_pass1_thread_prepare (global_ctx, &thread_ctx, - i, num_threads); + i, num_threads, + average_group);if (retval) {com_err (global_ctx->program_name, retval,_ ("while preparing pass1 thread\n" ));
@@ -3216,7 +3215,7 @@ static int e2fsck_pass1_threads_start(struct e2fsck_thread_info **pinfo, }if (retval) { -e2fsck_pass1_threads_join (infos, num_threads, global_ctx); +e2fsck_pass1_threads_join (infos, global_ctx);return retval; } *pinfo = infos;
@@ -3226,17 +3225,16 @@ static int e2fsck_pass1_threads_start(struct e2fsck_thread_info **pinfo,static void e2fsck_pass1_multithread (e2fsck_t global_ctx) {struct e2fsck_thread_info *infos =NULL ; -int num_threads = global_ctx->fs_num_threads;errcode_t retval; - retval =e2fsck_pass1_threads_start (&infos, num_threads, global_ctx); + retval =e2fsck_pass1_threads_start (&infos, global_ctx);if (retval) {com_err (global_ctx->program_name, retval,_ ("while starting pass1 threads\n" )); goto out_abort; } - retval =e2fsck_pass1_threads_join (infos, num_threads, global_ctx); + retval =e2fsck_pass1_threads_join (infos, global_ctx);if (retval) {com_err (global_ctx->program_name, retval,_ ("while joining pass1 threads\n" ));
Signature · 1 line
2.37.3
RFC 50/72 e2fsck: fix readahead for pfsck of pass1
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
Several improvments for this patch:
1) move readahead_kb detection to preparing phase.
2) inode readahead should be aware of thread block group boundary.
3) make readahead_kb aware of multiple threads.
--- e2fsck/pass1.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-)
e2fsck/pass1.c +20 -9
@@ -1098,16 +1098,20 @@ out:static void pass1_readahead (e2fsck_t ctx,dgrp_t *group,ext2_ino_t *next_ino) {ext2_ino_t inodes_in_group =0 , inodes_per_block, inodes_per_buffer; -dgrp_t start = *group, grp; +dgrp_t start = *group, grp, grp_end = ctx->fs->group_desc_count;blk64_t blocks_to_read =0 ;errcode_t err =EXT2_ET_INVALID_ARGUMENT ; +#ifdef HAVE_PTHREAD +if (ctx->fs->fs_num_threads >1 ) + grp_end = ctx->thread_info.et_group_end; +#endif if (ctx->readahead_kb ==0 ) goto out;/* Keep iterating groups until we have enough to readahead */ inodes_per_block =EXT2_INODES_PER_BLOCK (ctx->fs->super); -for (grp = start; grp < ctx->fs->group_desc_count; grp++) { +for (grp = start; grp < grp_end; grp++) {if (ext2fs_bg_flags_test (ctx->fs, grp,EXT2_BG_INODE_UNINIT ))continue ; inodes_in_group = ctx->fs->super->s_inodes_per_group -
@@ -1300,12 +1304,25 @@ static errcode_t e2fsck_pass1_prepare(e2fsck_t ctx) {struct problem_context pctx;ext2_filsys fs = ctx->fs; +unsigned long long readahead_kb;init_ext2_max_sizes (); -#ifdef HAVE_PTHREAD +#ifdef HAVE_PTHREAD e2fsck_pass1_set_thread_num (ctx);#endif +/* If we can do readahead, figure out how many groups to pull in. */ +if (!e2fsck_can_readahead (ctx->fs)) + ctx->readahead_kb =0 ; +else if (ctx->readahead_kb == ~0ULL ) + ctx->readahead_kb =e2fsck_guess_readahead (ctx->fs); +#ifdef HAVE_PTHREAD +/* don't use more than 1/10 of memory for threads checking */ + readahead_kb =get_memory_size () / (10 * ctx->fs_num_threads); +/* maybe better disable RA if this is too small? */ +if (ctx->readahead_kb > readahead_kb) + ctx->readahead_kb = readahead_kb; +#endif clear_problem_context (&pctx);if (!(ctx->options &E2F_OPT_PREEN ))fix_problem (ctx,PR_1_PASS_HEADER , &pctx);
@@ -1482,13 +1499,7 @@ void e2fsck_pass1_run(e2fsck_t ctx)init_resource_track (&rtrack, ctx->fs->io);clear_problem_context (&pctx); -/* If we can do readahead, figure out how many groups to pull in. */ -if (!e2fsck_can_readahead (ctx->fs)) - ctx->readahead_kb =0 ; -else if (ctx->readahead_kb == ~0ULL ) - ctx->readahead_kb =e2fsck_guess_readahead (ctx->fs);pass1_readahead (ctx, &ra_group, &ino_threshold); -if (ext2fs_has_feature_dir_index (fs->super) && !(ctx->options &E2F_OPT_NO )) {if (ext2fs_u32_list_create (&ctx->dirs_to_hash,50 ))
Signature · 1 line
2.37.3
RFC 51/72 e2fsck: merge options after threads finish
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
It will be possible that threads might append E2F_OPT_YES, so we need merge options to global, test f_yesall cover this.
--- e2fsck/pass1.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
e2fsck/pass1.c +4 -1
@@ -2866,6 +2866,7 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctxext2_refcount_t ea_inode_refs = global_ctx->ea_inode_refs;ext2fs_block_bitmap block_found_map = global_ctx->block_found_map;ext2fs_block_bitmap block_dup_map = global_ctx->block_dup_map; +int options = global_ctx->options;#ifdef HAVE_SETJMP_H jmp_buf old_jmp;
@@ -2918,7 +2919,8 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx global_ctx->fs_fragmented += fs_fragmented; global_ctx->fs_fragmented_dir += fs_fragmented_dir; global_ctx->large_files += large_files; - +/* threads might enable E2F_OPT_YES */ + global_ctx->options |= options; global_ctx->flags |= flags; global_ctx->logf = global_logf; global_ctx->problem_logf = global_problem_logf;
@@ -2954,6 +2956,7 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx thread_ctx->qctx);if (retval)return retval; + global_ctx->invalid_block_bitmap_flag = invalid_block_bitmap_flag; global_ctx->invalid_inode_bitmap_flag = invalid_inode_bitmap_flag; global_ctx->invalid_inode_table_flag = invalid_inode_table_flag;
Signature · 1 line
2.37.3
RFC 52/72 e2fsck: reset lost_and_found after threads finish
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
This should not be kept, the reaons is similar to what e2fsck_pass1 has done before.
--- e2fsck/pass1.c | 5 +++++ 1 file changed, 5 insertions(+)
e2fsck/pass1.c +5 -0
@@ -2925,6 +2925,11 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx global_ctx->logf = global_logf; global_ctx->problem_logf = global_problem_logf; global_ctx->global_ctx =NULL ; +/* +* The l+f inode may have been cleared, so zap it now and +* later passes will recalculate it if necessary +*/ + global_ctx->lost_and_found =0 ; global_fs->priv_data = global_ctx; global_ctx->fs = global_fs;
Signature · 1 line
2.37.3
RFC 53/72 e2fsck: merge extent depth count after threads finish
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
tests covered by f_extent_htree.
--- e2fsck/pass1.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
e2fsck/pass1.c +10 -1
@@ -2866,8 +2866,11 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctxext2_refcount_t ea_inode_refs = global_ctx->ea_inode_refs;ext2fs_block_bitmap block_found_map = global_ctx->block_found_map;ext2fs_block_bitmap block_dup_map = global_ctx->block_dup_map; -int options = global_ctx->options; +int options = global_ctx->options, i; +__u32 extent_depth_count[MAX_EXTENT_DEPTH_COUNT ]; +memcpy (extent_depth_count, global_ctx->extent_depth_count, +sizeof (extent_depth_count));#ifdef HAVE_SETJMP_H jmp_buf old_jmp;
@@ -2930,6 +2933,12 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx* later passes will recalculate it if necessary */ global_ctx->lost_and_found =0 ; +memcpy (global_ctx->extent_depth_count, extent_depth_count, +sizeof (extent_depth_count)); +/* merge extent depth count */ +for (i =0 ; i <MAX_EXTENT_DEPTH_COUNT ; i++) + global_ctx->extent_depth_count[i] += + thread_ctx->extent_depth_count[i]; global_fs->priv_data = global_ctx; global_ctx->fs = global_fs;
Signature · 1 line
2.37.3
RFC 54/72 e2fsck: simplify e2fsck context merging codes
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
We tried to copy thread context to global context directly and then copy back some saved variables before merging.
Since we have finished almost all necessary variables in the e2fsck context, we could simplify codes, and this could help us understand what is missing rather than hide problems.
--- e2fsck/pass1.c | 158 ++++++++++--------------------------------------- 1 file changed, 31 insertions(+), 127 deletions(-)
e2fsck/pass1.c +31 -127
@@ -2813,136 +2813,51 @@ static errcode_t e2fsck_pass1_merge_ea_refcount(e2fsck_t global_ctx,return retval; } -static int e2fsck_pass1_thread_join_one (e2fsck_t global_ctx,e2fsck_t thread_ctx) +static errcode_t e2fsck_pass1_merge_context (e2fsck_t global_ctx, +e2fsck_t thread_ctx) { -errcode_t retval =0 ; -int flags = global_ctx->flags; -FILE *global_logf = global_ctx->logf; -FILE *global_problem_logf = global_ctx->problem_logf; -ext2_filsys thread_fs = thread_ctx->fs;ext2_filsys global_fs = global_ctx->fs; -ext2fs_inode_bitmap inode_bad_map = global_ctx->inode_bad_map; -struct dir_info_db *dir_info = global_ctx->dir_info; -struct dx_dir_info *dx_dir_info = global_ctx->dx_dir_info; -ext2fs_inode_bitmap inode_used_map = global_ctx->inode_used_map; -ext2fs_inode_bitmap inode_dir_map = global_ctx->inode_dir_map; -ext2fs_inode_bitmap inode_bb_map = global_ctx->inode_bb_map; -ext2fs_inode_bitmap inode_imagic_map = global_ctx->inode_imagic_map; -ext2fs_inode_bitmap inode_reg_map = global_ctx->inode_reg_map; -ext2fs_block_bitmap inodes_to_rebuild = global_ctx->inodes_to_rebuild; -ext2_icount_t inode_count = global_ctx->inode_count; -ext2_icount_t inode_link_info = global_ctx->inode_link_info; -__u32 fs_directory_count = global_ctx->fs_directory_count; -__u32 fs_regular_count = global_ctx->fs_regular_count; -__u32 fs_blockdev_count = global_ctx->fs_blockdev_count; -__u32 fs_chardev_count = global_ctx->fs_chardev_count; -__u32 fs_links_count = global_ctx->fs_links_count; -__u32 fs_symlinks_count = global_ctx->fs_symlinks_count; -__u32 fs_fast_symlinks_count = global_ctx->fs_fast_symlinks_count; -__u32 fs_fifo_count = global_ctx->fs_fifo_count; -__u32 fs_total_count = global_ctx->fs_total_count; -__u32 fs_badblocks_count = global_ctx->fs_badblocks_count; -__u32 fs_sockets_count = global_ctx->fs_sockets_count; -__u32 fs_ind_count = global_ctx->fs_ind_count; -__u32 fs_dind_count = global_ctx->fs_dind_count; -__u32 fs_tind_count = global_ctx->fs_tind_count; -__u32 fs_fragmented = global_ctx->fs_fragmented; -__u32 fs_fragmented_dir = global_ctx->fs_fragmented_dir; -__u32 large_files = global_ctx->large_files; -ext2_ino_t dx_dir_info_size = global_ctx->dx_dir_info_size; -ext2_ino_t dx_dir_info_count = global_ctx->dx_dir_info_count; -ext2_u32_list dirs_to_hash = global_ctx->dirs_to_hash; -quota_ctx_t qctx = global_ctx->qctx; -int *invalid_block_bitmap_flag = global_ctx->invalid_block_bitmap_flag; -int *invalid_inode_bitmap_flag = global_ctx->invalid_inode_bitmap_flag; -int *invalid_inode_table_flag = global_ctx->invalid_inode_table_flag; -int invalid_bitmaps = global_ctx->invalid_bitmaps; -ext2_refcount_t refcount = global_ctx->refcount; -ext2_refcount_t refcount_extra = global_ctx->refcount_extra; -ext2_refcount_t refcount_orig = global_ctx->refcount_orig; -ext2_refcount_t ea_block_quota_blocks = global_ctx->ea_block_quota_blocks; -ext2_refcount_t ea_block_quota_inodes = global_ctx->ea_block_quota_inodes; -ext2fs_block_bitmap block_ea_map = global_ctx->block_ea_map; -ext2_refcount_t ea_inode_refs = global_ctx->ea_inode_refs; -ext2fs_block_bitmap block_found_map = global_ctx->block_found_map; -ext2fs_block_bitmap block_dup_map = global_ctx->block_dup_map; -int options = global_ctx->options, i; -__u32 extent_depth_count[MAX_EXTENT_DEPTH_COUNT ]; - -memcpy (extent_depth_count, global_ctx->extent_depth_count, -sizeof (extent_depth_count)); -#ifdef HAVE_SETJMP_H -jmp_buf old_jmp; - -memcpy (old_jmp, global_ctx->abort_loc,sizeof (jmp_buf)); -#endif -memcpy (global_ctx, thread_ctx,sizeof (struct e2fsck_struct )); -#ifdef HAVE_SETJMP_H -memcpy (global_ctx->abort_loc, old_jmp,sizeof (jmp_buf)); -#endif +errcode_t retval =0 ; +int i; - global_ctx->inode_used_map = inode_used_map; - global_ctx->inode_bad_map = inode_bad_map; - global_ctx->inode_dir_map = inode_dir_map; - global_ctx->inode_bb_map = inode_bb_map; - global_ctx->inode_imagic_map = inode_imagic_map; - global_ctx->inodes_to_rebuild = inodes_to_rebuild; - global_ctx->inode_reg_map = inode_reg_map; - global_ctx->block_dup_map = block_dup_map; - global_ctx->block_found_map = block_found_map; - global_ctx->dir_info = dir_info; -e2fsck_pass1_merge_dir_info (global_ctx, thread_ctx); - global_ctx->dx_dir_info = dx_dir_info; - global_ctx->dx_dir_info_count = dx_dir_info_count; - global_ctx->dx_dir_info_size = dx_dir_info_size; -e2fsck_pass1_merge_dx_dir (global_ctx, thread_ctx); - global_ctx->inode_count = inode_count; - global_ctx->inode_link_info = inode_link_info; - global_ctx->refcount = refcount; - global_ctx->refcount_extra = refcount_extra; - global_ctx->refcount_orig = refcount_orig; - global_ctx->ea_block_quota_blocks = ea_block_quota_blocks; - global_ctx->ea_block_quota_inodes = ea_block_quota_inodes; - global_ctx->block_ea_map = block_ea_map; - global_ctx->ea_inode_refs = ea_inode_refs; - global_ctx->fs_directory_count += fs_directory_count; - global_ctx->fs_regular_count += fs_regular_count; - global_ctx->fs_blockdev_count += fs_blockdev_count; - global_ctx->fs_chardev_count += fs_chardev_count; - global_ctx->fs_links_count += fs_links_count; - global_ctx->fs_symlinks_count += fs_symlinks_count; - global_ctx->fs_fast_symlinks_count += fs_fast_symlinks_count; - global_ctx->fs_fifo_count += fs_fifo_count; - global_ctx->fs_total_count += fs_total_count; - global_ctx->fs_badblocks_count += fs_badblocks_count; - global_ctx->fs_sockets_count += fs_sockets_count; - global_ctx->fs_ind_count += fs_ind_count; - global_ctx->fs_dind_count += fs_dind_count; - global_ctx->fs_tind_count += fs_tind_count; - global_ctx->fs_fragmented += fs_fragmented; - global_ctx->fs_fragmented_dir += fs_fragmented_dir; - global_ctx->large_files += large_files; + global_ctx->fs_directory_count += thread_ctx->fs_directory_count; + global_ctx->fs_regular_count += thread_ctx->fs_regular_count; + global_ctx->fs_blockdev_count += thread_ctx->fs_blockdev_count; + global_ctx->fs_chardev_count += thread_ctx->fs_chardev_count; + global_ctx->fs_links_count += thread_ctx->fs_links_count; + global_ctx->fs_symlinks_count += thread_ctx->fs_symlinks_count; + global_ctx->fs_fast_symlinks_count += thread_ctx->fs_fast_symlinks_count; + global_ctx->fs_fifo_count += thread_ctx->fs_fifo_count; + global_ctx->fs_total_count += thread_ctx->fs_total_count; + global_ctx->fs_badblocks_count += thread_ctx->fs_badblocks_count; + global_ctx->fs_sockets_count += thread_ctx->fs_sockets_count; + global_ctx->fs_ind_count += thread_ctx->fs_ind_count; + global_ctx->fs_dind_count += thread_ctx->fs_dind_count; + global_ctx->fs_tind_count += thread_ctx->fs_tind_count; + global_ctx->fs_fragmented += thread_ctx->fs_fragmented; + global_ctx->fs_fragmented_dir += thread_ctx->fs_fragmented_dir; + global_ctx->large_files += thread_ctx->large_files;/* threads might enable E2F_OPT_YES */ - global_ctx->options |= options; - global_ctx->flags |= flags; - global_ctx->logf = global_logf; - global_ctx->problem_logf = global_problem_logf; - global_ctx->global_ctx =NULL ; + global_ctx->options |= thread_ctx->options; + global_ctx->flags |= thread_ctx->flags;/* * The l+f inode may have been cleared, so zap it now and * later passes will recalculate it if necessary */ global_ctx->lost_and_found =0 ; -memcpy (global_ctx->extent_depth_count, extent_depth_count, -sizeof (extent_depth_count));/* merge extent depth count */ for (i =0 ; i <MAX_EXTENT_DEPTH_COUNT ; i++) global_ctx->extent_depth_count[i] += thread_ctx->extent_depth_count[i]; - global_fs->priv_data = global_ctx; - global_ctx->fs = global_fs; +e2fsck_pass1_merge_dir_info (global_ctx, thread_ctx); +e2fsck_pass1_merge_dx_dir (global_ctx, thread_ctx); + retval =ext2fs_merge_fs (&(thread_ctx->fs)); +if (retval) { +com_err (global_ctx->program_name,0 ,_ ("while merging fs\n" )); +return retval; + } retval =e2fsck_pass1_merge_icounts (global_ctx, thread_ctx);if (retval) { com_err(global_ctx->program_name, 0,
@@ -2950,12 +2865,6 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctxreturn retval; } - retval =ext2fs_merge_fs (&(thread_ctx->fs)); -if (retval) { -com_err (global_ctx->program_name,0 ,_ ("while merging fs\n" )); -return retval; - } - global_ctx->dirs_to_hash = dirs_to_hash; retval =e2fsck_pass1_merge_dirs_to_hash (global_ctx, thread_ctx);if (retval) { com_err(global_ctx->program_name, 0,
@@ -2965,16 +2874,11 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctxe2fsck_pass1_merge_ea_inode_refs (global_ctx, thread_ctx);e2fsck_pass1_merge_ea_refcount (global_ctx, thread_ctx); - global_ctx->qctx = qctx; retval =quota_merge_and_update_usage (global_ctx->qctx, thread_ctx->qctx);if (retval)return retval; - global_ctx->invalid_block_bitmap_flag = invalid_block_bitmap_flag; - global_ctx->invalid_inode_bitmap_flag = invalid_inode_bitmap_flag; - global_ctx->invalid_inode_table_flag = invalid_inode_table_flag; - global_ctx->invalid_bitmaps = invalid_bitmaps;e2fsck_pass1_merge_invalid_bitmaps (global_ctx, thread_ctx); retval = e2fsck_pass1_merge_bitmap(global_fs,
@@ -3043,7 +2947,7 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx) {errcode_t retval; - retval =e2fsck_pass1_thread_join_one (global_ctx, thread_ctx); + retval =e2fsck_pass1_merge_context (global_ctx, thread_ctx);e2fsck_pass1_free_bitmap (&thread_ctx->inode_used_map);e2fsck_pass1_free_bitmap (&thread_ctx->inode_bad_map);e2fsck_pass1_free_bitmap (&thread_ctx->inode_dir_map);
Signature · 1 line
2.37.3
RFC 55/72 e2fsck: set E2F_FLAG_ALLOC_OK after threads
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
Only flag ALLOC OK after all threads finished without problem.
--- e2fsck/pass1.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
e2fsck/pass1.c +8 -2
@@ -1385,9 +1385,12 @@ static void e2fsck_pass1_post(e2fsck_t ctx) {struct problem_context pctx;ext2_filsys fs = ctx->fs; +char *block_buf; -char *block_buf = - (char *)e2fsck_allocate_memory (ctx, ctx->fs->blocksize *3 , +if (e2fsck_should_abort (ctx)) +return ; + + block_buf = (char *)e2fsck_allocate_memory (ctx, ctx->fs->blocksize *3 ,"block interate buffer" );reserve_block_for_root_repair (ctx);reserve_block_for_lnf_repair (ctx);
@@ -1465,6 +1468,8 @@ static void e2fsck_pass1_post(e2fsck_t ctx)ext2fs_free_mem (&block_buf); ctx->flags &= ~E2F_FLAG_DUP_BLOCK ; } + + ctx->flags |=E2F_FLAG_ALLOC_OK ; }
@@ -2355,6 +2360,7 @@ void e2fsck_pass1_run(e2fsck_t ctx) } ctx->flags |=E2F_FLAG_ALLOC_OK ; +ext2fs_free_mem (&inodes_to_process); endit:e2fsck_use_inode_shortcuts (ctx,0 );ext2fs_free_mem (&inodes_to_process);
Signature · 1 line
2.37.3
RFC 56/72 e2fsck: wait fix thread finish before checking
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
Before proceeding next inodes, waitting existed
fixing finished.
--- e2fsck/e2fsck.c | 3 +++ e2fsck/e2fsck.h | 5 +++- e2fsck/pass1.c | 70 +++++++++++++++++++++++++++++++++++++++++++------ e2fsck/util.c | 56 ++++++++++++++++++++++++++++++++++++--- 4 files changed, 122 insertions(+), 12 deletions(-)
e2fsck/e2fsck.c +3 -0
@@ -187,6 +187,9 @@ errcode_t e2fsck_reset_context(e2fsck_t ctx) ctx->fs_fragmented_dir =0 ; ctx->large_files =0 ; ctx->large_dirs =0 ; +#ifdef HAVE_PTHREAD + ctx->fs_need_locking =0 ; +#endif for (i=0 ; i <MAX_EXTENT_DEPTH_COUNT ; i++) ctx->extent_depth_count[i] =0 ;
e2fsck/e2fsck.h +4 -1
@@ -488,8 +488,9 @@ struct e2fsck_struct {#ifdef HAVE_PTHREAD __u32 fs_num_threads; +int fs_need_locking;/* serialize fix operation for multiple threads */ -pthread_mutex_t fs_fix_mutex; +pthread_rwlock_t fs_fix_rwlock;/* protect block_found_map, block_dup_map */ pthread_rwlock_t fs_block_map_rwlock;#endif
@@ -553,6 +554,8 @@ extern int e2fsck_strnlen(const char * s, int count);extern void e2fsck_pass1 (e2fsck_t ctx);extern void e2fsck_pass1_dupblocks (e2fsck_t ctx,char *block_buf); +extern void e2fsck_pass1_check_lock (e2fsck_t ctx); +extern void e2fsck_pass1_check_unlock (e2fsck_t ctx);extern void e2fsck_pass2 (e2fsck_t ctx);extern void e2fsck_pass3 (e2fsck_t ctx);extern void e2fsck_pass4 (e2fsck_t ctx);
e2fsck/pass1.c +62 -8
246 lines not on this page · raw message
e2fsck/util.c +53 -3
104 lines not on this page · raw message
Signature · 1 line
2.37.3
RFC 57/72 e2fsck: cleanup e2fsck_pass1_thread_join()
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
Use e2fsck_reset_context() to free memory to simpify codes.
--- e2fsck/pass1.c | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-)
e2fsck/pass1.c +7 -26
@@ -3008,39 +3008,20 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx)errcode_t retval; retval =e2fsck_pass1_merge_context (global_ctx, thread_ctx); -e2fsck_pass1_free_bitmap (&thread_ctx->inode_used_map); -e2fsck_pass1_free_bitmap (&thread_ctx->inode_bad_map); -e2fsck_pass1_free_bitmap (&thread_ctx->inode_dir_map); -e2fsck_pass1_free_bitmap (&thread_ctx->inode_bb_map); -e2fsck_pass1_free_bitmap (&thread_ctx->inode_imagic_map); -e2fsck_pass1_free_bitmap (&thread_ctx->inode_reg_map); -e2fsck_pass1_free_bitmap (&thread_ctx->inodes_to_rebuild); -e2fsck_pass1_free_bitmap (&thread_ctx->block_found_map); -e2fsck_pass1_free_bitmap (&thread_ctx->block_ea_map); -if (thread_ctx->refcount) -ea_refcount_free (thread_ctx->refcount); -if (thread_ctx->refcount_extra) -ea_refcount_free (thread_ctx->refcount_extra); -if (thread_ctx->ea_inode_refs) -ea_refcount_free (thread_ctx->ea_inode_refs); -if (thread_ctx->refcount_orig) -ea_refcount_free (thread_ctx->refcount_orig); -e2fsck_free_dir_info (thread_ctx); -ext2fs_free_icount (thread_ctx->inode_count); -ext2fs_free_icount (thread_ctx->inode_link_info); -if (thread_ctx->dirs_to_hash) -ext2fs_badblocks_list_free (thread_ctx->dirs_to_hash); -quota_release_context (&thread_ctx->qctx); -ext2fs_free_mem (&thread_ctx->invalid_block_bitmap_flag); -ext2fs_free_mem (&thread_ctx->invalid_inode_bitmap_flag); -ext2fs_free_mem (&thread_ctx->invalid_inode_table_flag); +/* +* @block_metadata_map and @block_dup_map are +* shared, so we don't free them. +*/ + thread_ctx->block_metadata_map =NULL ; + thread_ctx->block_dup_map =NULL ;if (thread_ctx->logf)fclose (thread_ctx->logf);if (thread_ctx->problem_logf) {fputs ("</problem_log>\n" , thread_ctx->problem_logf);fclose (thread_ctx->problem_logf); } +e2fsck_reset_context (thread_ctx);ext2fs_free_mem (&thread_ctx);return retval; }
Signature · 1 line
2.37.3
RFC 58/72 e2fsck: make default smallest RA size to 1M
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
If we have a smaller inodes per group, default ra size could be very small(etc 128KiB), this hurts performances.
Tune above 128K to 1M, i see pass1 time drop down from 677.12 seconds to 246 secons with 32 threads.
--- e2fsck/readahead.c | 4 ++++ 1 file changed, 4 insertions(+)
e2fsck/readahead.c +4 -0
@@ -234,6 +234,8 @@ int e2fsck_can_readahead(ext2_filsys fs)return err !=EXT2_ET_OP_NOT_SUPPORTED ; } +#define MIN_DEFAULT_RA (1024 * 1024) +unsigned long long e2fsck_guess_readahead (ext2_filsys fs) {unsigned long long guess;
@@ -245,6 +247,8 @@ unsigned long long e2fsck_guess_readahead(ext2_filsys fs)* in e2fsck runtime. */ guess =2ULL * fs->blocksize * fs->inode_blocks_per_group; +if (guess <MIN_DEFAULT_RA ) + guess =MIN_DEFAULT_RA ;/* Disable RA if it'd use more 1/50th of RAM. */ if (get_memory_size () > (guess *50 ))
Signature · 1 line
2.37.3
RFC 59/72 e2fsck: update mmp block in one thread
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
For multiple threads, different threads will try to update mmp block at the same time, only allow one thread to update it.
--- e2fsck/e2fsck.h | 1 + e2fsck/pass1.c | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-)
e2fsck/e2fsck.h +1 -0
@@ -488,6 +488,7 @@ struct e2fsck_struct {#ifdef HAVE_PTHREAD __u32 fs_num_threads; +__u32 mmp_update_thread;int fs_need_locking;/* serialize fix operation for multiple threads */ pthread_rwlock_t fs_fix_rwlock;
e2fsck/pass1.c +32 -2
@@ -1509,7 +1509,8 @@ void e2fsck_pass1_run(e2fsck_t ctx)dgrp_t ra_group =0 ;struct ea_quota ea_ibody_quota;struct process_inode_block *inodes_to_process; -int process_inode_count; +int process_inode_count, check_mmp; +e2fsck_t global_ctx = ctx->global_ctx ? ctx->global_ctx : ctx;init_resource_track (&rtrack, ctx->fs->io);clear_problem_context (&pctx);
@@ -1672,8 +1673,30 @@ void e2fsck_pass1_run(e2fsck_t ctx)#endif while (1 ) { + check_mmp =0 ;e2fsck_pass1_check_lock (ctx); -if (ino % (fs->super->s_inodes_per_group *4 ) ==1 ) { +#ifdef HAVE_PTHREAD +if (!global_ctx->mmp_update_thread) { +e2fsck_pass1_block_map_w_lock (ctx); +if (!global_ctx->mmp_update_thread) { + global_ctx->mmp_update_thread = + ctx->thread_info.et_thread_index +1 ; + check_mmp =1 ; + } +e2fsck_pass1_block_map_w_unlock (ctx); + } + +/* only one active thread could update mmp block. */ +e2fsck_pass1_block_map_r_lock (ctx); +if (global_ctx->mmp_update_thread == + ctx->thread_info.et_thread_index +1 ) + check_mmp =1 ; +e2fsck_pass1_block_map_r_unlock (ctx); +#else + check_mmp =1 ; +#endif + +if (check_mmp && (ino % (fs->super->s_inodes_per_group *4 ) ==1 )) {if (e2fsck_mmp_update (fs))fatal_error (ctx,0 ); }
@@ -2437,6 +2460,13 @@ endit:print_resource_track (ctx,_ ("Pass 1" ), &rtrack, ctx->fs->io); else ctx->invalid_bitmaps++; +#ifdef HAVE_PTHREAD +/* reset update_thread after this thread exit */ +e2fsck_pass1_block_map_w_lock (ctx); +if (check_mmp) + global_ctx->mmp_update_thread =0 ; +e2fsck_pass1_block_map_w_unlock (ctx); +#endif }#ifdef HAVE_PTHREAD
Signature · 1 line
2.37.3
RFC 60/72 e2fsck: reset @inodes_to_rebuild if restart
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
Verify multiple thread on a corrupted images hit following bug:
pass1.c:2902: e2fsck_pass1_thread_prepare:
Assertion `global_ctx->inodes_to_rebuild == NULL' failed. Signal (6) SIGABRT si_code=SI_TKILL ./e2fsck/e2fsck[0x43829e] /lib64/libpthread.so.0(+0x14b20)[0x7f3b45135b20] /lib64/libc.so.6(gsignal+0x145)[0x7f3b44f2c625] /lib64/libc.so.6(abort+0x12b)[0x7f3b44f158d9] /lib64/libc.so.6(+0x257a9)[0x7f3b44f157a9] /lib64/libc.so.6(+0x34a66)[0x7f3b44f24a66] ./e2fsck/e2fsck(e2fsck_pass1+0x1662)[0x423572] ./e2fsck/e2fsck(e2fsck_run+0x5a)[0x41611a] ./e2fsck/e2fsck(main+0x1608)[0x4121b8] /lib64/libc.so.6(__libc_start_main+0xf3)[0x7f3b44f171a3] ./e2fsck/e2fsck(_start+0x2e)[0x413dde]
@inodes_to_rebuild could be not NULL after we restart pass1
--- e2fsck/e2fsck.c | 4 ++++ 1 file changed, 4 insertions(+)
e2fsck/e2fsck.c +4 -0
@@ -79,6 +79,10 @@ errcode_t e2fsck_reset_context(e2fsck_t ctx)ext2fs_free_block_bitmap (ctx->inode_casefold_map); ctx->inode_casefold_map =0 ; } +if (ctx->inodes_to_rebuild) { +ext2fs_free_inode_bitmap (ctx->inodes_to_rebuild); + ctx->inodes_to_rebuild =0 ; + }if (ctx->inode_link_info) {ext2fs_free_icount (ctx->inode_link_info); ctx->inode_link_info =0 ;
Signature · 1 line
2.37.3
RFC 61/72 tests: add pfsck test
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
pfsck run on a clean fs should not return any errors.
Generate an image with possible features enabled,
especially EA shared blocks etc.
--- tests/f_multithread_ok/expect.1 | 7 +++++++ tests/f_multithread_ok/image.gz | Bin 0 -> 796311 bytes tests/f_multithread_ok/name | 1 + tests/f_multithread_ok/script | 21 +++++++++++++++++++++ 4 files changed, 29 insertions(+) create mode 100644 tests/f_multithread_ok/expect.1 create mode 100644 tests/f_multithread_ok/image.gz create mode 100644 tests/f_multithread_ok/name create mode 100644 tests/f_multithread_ok/script
tests/f_multithread_ok/expect.1 new file +7 -0
@@ -0,0 +1,7 @@ +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +test_filesys: 10251/32768 files (0.0% non-contiguous), 2218/131072 blocks +Exit status is 0
tests/f_multithread_ok/image.gz new file binary +0 -0
tests/f_multithread_ok/name new file +1 -0
@@ -0,0 +1 @@ +multiple threads checking on clean fs
tests/f_multithread_ok/script new file +21 -0
@@ -0,0 +1,21 @@ +FSCK_OPT="-fym4" +SKIP_VERIFY="true" +ONE_PASS_ONLY="true" +SKIP_CLEANUP="true" + +. $cmd_dir/run_e2fsck + +grep -v Thread $OUT1 > $OUT1.tmp +cmp -s $EXP1 $OUT1.tmp +status1=$? +if [ "$status1" -eq 0 ]; then + echo "$test_name: $test_description: ok" + touch $test_name.ok +else + echo "$test_name: $test_description: failed" + diff $DIFF_OPTS $EXP1 $OUT1.tmp > $test_name.failed +fi + +unset IMAGE FSCK_OPT SECOND_FSCK_OPT OUT1 OUT2 EXP1 EXP2 +unset SKIP_VERIFY SKIP_CLEANUP SKIP_GUNZIP ONE_PASS_ONLY PREP_CMD +unset DESCRIPTION SKIP_UNLINK AFTER_CMD PASS_ZERO
Signature · 1 line
2.37.3
RFC 62/72 e2fsck: fix memory leaks with pfsck enabled
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
valgrind detected two memory leaks:
1) quota context is not released after merging.
2) @refcount_orig should be released
--- e2fsck/e2fsck.c | 4 ++++ e2fsck/pass1.c | 1 + 2 files changed, 5 insertions(+)
e2fsck/e2fsck.c +4 -0
@@ -106,6 +106,10 @@ errcode_t e2fsck_reset_context(e2fsck_t ctx)ea_refcount_free (ctx->refcount_extra); ctx->refcount_extra =0 ; } +if (ctx->refcount_orig) { +ea_refcount_free (ctx->refcount_orig); + ctx->refcount_orig =0 ; + }if (ctx->ea_block_quota_blocks) {ea_refcount_free (ctx->ea_block_quota_blocks); ctx->ea_block_quota_blocks =0 ;
e2fsck/pass1.c +1 -0
@@ -3039,6 +3039,7 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx) retval =e2fsck_pass1_merge_context (global_ctx, thread_ctx); +quota_release_context (&thread_ctx->qctx);/* * @block_metadata_map and @block_dup_map are * shared, so we don't free them.
Signature · 1 line
2.37.3
RFC 63/72 e2fsck: misc cleanups for pfsck
In reply to Ritesh Harjani (IBM)From: Andreas Dilger <[email protected]>
Add -m option description to e2fsck.8 man page.
Rename e2fsck_struct fs_num_threads to pfs_num_threads to avoid confusion with the ext2_filsys fs_num_threads field, and move thread_info to be together with the other HAVE_PTHREAD fields.
Move ext2_filsys fs_num_threads to fit into the __u16 "pad" field to avoid consuming one of the few remaining __u32 reserved fields.
Fix a few print format warnings.
--- e2fsck/e2fsck.8.in | 8 +++++++- e2fsck/e2fsck.h | 13 +++++-------- e2fsck/pass1.c | 20 +++++++++++--------- e2fsck/unix.c | 4 ++-- 4 files changed, 25 insertions(+), 20 deletions(-)
e2fsck/e2fsck.8.in +7 -1
@@ -8,7 +8,7 @@ e2fsck \- check a Linux ext2/ext3/ext4 file system .SH SYNOPSIS .B e2fsck [ -.B \-pacnyrdfkvtDFV +.B \-pacnyrdfkmvtDFV ] [ .B \-b
@@ -333,6 +333,12 @@ Set the bad blocks list to be the list of blocks specified by option, except the bad blocks list is cleared before the blocks listed in the file are added to the bad blocks list.) .TP +.B \-m " threads" +Run e2fsck with up to the specified number of +.IR threads . +The actual number of threads may be lower, if the filesystem does not +have enough block groups to effectively parallelize the workload. +.TP .B \-n Open the file system read-only, and assume an answer of `no' to all questions. Allows
e2fsck/e2fsck.h +5 -8
@@ -277,8 +277,8 @@ struct e2fsck_thread {dgrp_t et_group_next;/* Scanned inode number */ ext2_ino_t et_inode_number; -char et_log_buf[2048 ];char et_log_length; + char et_log_buf[2048]; };#endif
@@ -367,11 +367,6 @@ struct e2fsck_struct {ext2_ino_t stashed_ino;struct ext2_inode *stashed_inode; -/* if @global_ctx is null, this field is unused */ -#ifdef HAVE_PTHREAD -struct e2fsck_thread thread_info; -#endif -/* * Location of the lost and found directory */
@@ -487,7 +482,9 @@ struct e2fsck_struct {char *undo_file;#ifdef HAVE_PTHREAD -__u32 fs_num_threads; +/* if @global_ctx is null, this field is unused */ +struct e2fsck_thread thread_info; +__u32 pfs_num_threads;__u32 mmp_update_thread;int fs_need_locking;/* serialize fix operation for multiple threads */
@@ -732,7 +729,7 @@ void check_resize_inode(e2fsck_t ctx);int check_init_orphan_file (e2fsck_t ctx);/* util.c */ -#define E2FSCK_MAX_THREADS (65536) +#define E2FSCK_MAX_THREADS (65535)extern void *e2fsck_allocate_memory (e2fsck_t ctx,unsigned long size,const char *description);extern int ask (e2fsck_t ctx,const char * string,int def);
e2fsck/pass1.c +11 -9
@@ -1265,7 +1265,7 @@ static void e2fsck_pass1_set_thread_num(e2fsck_t ctx) {unsigned flexbg_size =1 ;ext2_filsys fs = ctx->fs; -int num_threads = ctx->fs_num_threads; +int num_threads = ctx->pfs_num_threads;int max_threads;if (num_threads <1 ) {
@@ -1285,6 +1285,8 @@ static void e2fsck_pass1_set_thread_num(e2fsck_t ctx) max_threads = fs->group_desc_count / flexbg_size;if (max_threads ==0 ) max_threads =1 ; +if (max_threads >E2FSCK_MAX_THREADS ) + max_threads =E2FSCK_MAX_THREADS ;if (num_threads > max_threads) { fprintf(stderr, "Use max possible thread num: %d instead\n",
@@ -1292,7 +1294,7 @@ static void e2fsck_pass1_set_thread_num(e2fsck_t ctx) num_threads = max_threads; } out: - ctx->fs_num_threads = num_threads; + ctx->pfs_num_threads = num_threads; ctx->fs->fs_num_threads = num_threads; }#endif
@@ -1320,7 +1322,7 @@ static errcode_t e2fsck_pass1_prepare(e2fsck_t ctx)#ifdef HAVE_PTHREAD /* don't use more than 1/10 of memory for threads checking */ - readahead_kb =get_memory_size () / (10 * ctx->fs_num_threads); + readahead_kb =get_memory_size () / (10 * ctx->pfs_num_threads);/* maybe better disable RA if this is too small? */ if (ctx->readahead_kb > readahead_kb) ctx->readahead_kb = readahead_kb;
@@ -1378,7 +1380,7 @@ static errcode_t e2fsck_pass1_prepare(e2fsck_t ctx)#ifdef HAVE_PTHREAD pthread_rwlock_init (&ctx->fs_fix_rwlock,NULL );pthread_rwlock_init (&ctx->fs_block_map_rwlock,NULL ); -if (ctx->fs_num_threads >1 ) +if (ctx->pfs_num_threads >1 ) ctx->fs_need_locking =1 ;else ctx->fs_need_locking =0 ;
@@ -1659,7 +1661,7 @@ void e2fsck_pass1_run(e2fsck_t ctx)if (ctx->global_ctx) {if (ctx->options &E2F_OPT_DEBUG && ctx->options &E2F_OPT_MULTITHREAD ) -fprintf (stderr,"thread %d jumping to group %d\n" , +fprintf (stderr,"thread %d jumping to group %u\n" , ctx->thread_info.et_thread_index, ctx->thread_info.et_group_start); pctx.errcode = ext2fs_inode_scan_goto_blockgroup(scan,
@@ -3064,7 +3066,7 @@ static int e2fsck_pass1_threads_join(struct e2fsck_thread_info *infos,errcode_t ret =0 ;int i;struct e2fsck_thread_info *pinfo; -int num_threads = global_ctx->fs_num_threads; +int num_threads = global_ctx->pfs_num_threads;/* merge invalid bitmaps will recalculate it */ global_ctx->invalid_bitmaps =0 ;
@@ -3130,7 +3132,7 @@ static void *e2fsck_pass1_thread(void *arg) out:if (thread_ctx->options &E2F_OPT_MULTITHREAD )log_out (thread_ctx, -_ ("Scanned group range [%lu, %lu), inodes %lu\n" ), +_ ("Scanned group range [%u, %u), inodes %u\n" ), thread_ctx->thread_info.et_group_start, thread_ctx->thread_info.et_group_end, thread_ctx->thread_info.et_inode_number);
@@ -3156,7 +3158,7 @@ static int e2fsck_pass1_threads_start(struct e2fsck_thread_info **pinfo,int i;e2fsck_t thread_ctx;dgrp_t average_group; -int num_threads = global_ctx->fs_num_threads; +int num_threads = global_ctx->pfs_num_threads;#ifdef DEBUG_THREADS struct e2fsck_thread_debug thread_debug = {PTHREAD_MUTEX_INITIALIZER ,PTHREAD_COND_INITIALIZER ,0 };
@@ -3259,7 +3261,7 @@ void e2fsck_pass1(e2fsck_t ctx)if (retval)return ;#ifdef HAVE_PTHREAD -if (ctx->options &E2F_OPT_MULTITHREAD || ctx->fs_num_threads >1 ) +if (ctx->options &E2F_OPT_MULTITHREAD || ctx->pfs_num_threads >1 )e2fsck_pass1_multithread (ctx); else#endif
e2fsck/unix.c +2 -2
@@ -915,12 +915,12 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) _("Invalid multiple thread num.\n"));if (thread_num >E2FSCK_MAX_THREADS ) {fprintf (stderr, -_ ("threads %lu too large (max %lu)\n" ), +_ ("threads %lu too large (max %u)\n" ), thread_num,E2FSCK_MAX_THREADS );fatal_error (ctx,0 ); } ctx->options |=E2F_OPT_MULTITHREAD ; - ctx->fs_num_threads = thread_num; + ctx->pfs_num_threads = thread_num;break ;#endif case 'n' :
Signature · 1 line
2.37.3
RFC 64/72 e2fsck: propagate number of threads
In reply to Ritesh Harjani (IBM)From: Saranya Muruganandam <[email protected]>
Sometimes, such as in orphan_inode case, e2fsck_pass1 is called after reading the block bitmaps. This results in reading the block bitmap sequentially and multithreading only gets kicked in later. Fix the thread count earlier while setting up the file system.
--- e2fsck/unix.c | 3 +++ 1 file changed, 3 insertions(+)
e2fsck/unix.c +3 -0
@@ -1745,6 +1745,9 @@ failure: ctx->fs = fs; fs->now = ctx->now; +#ifdef HAVE_PTHREAD + fs->fs_num_threads = ctx->pfs_num_threads; +#endif sb = fs->super;if (sb->s_rev_level >E2FSCK_CURRENT_REV ) {
Signature · 1 line
2.37.3
RFC 65/72 e2fsck: Annotating fields in e2fsck_struct
In reply to Ritesh Harjani (IBM)From: Saranya Muruganandam <[email protected]>
Adding information on fields in e2fsck_struct
on how they are used when running parallel fsck.
--- e2fsck/e2fsck.h | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-)
e2fsck/e2fsck.h +14 -6
@@ -285,7 +285,7 @@ struct e2fsck_thread {struct e2fsck_struct {/* Global context to get the cancel flag */ e2fsck_t global_ctx; -ext2_filsys fs; +ext2_filsys fs;/* [fs_fix_rwlock] */ const char *program_name;char *filesystem_name;char *device_name;
@@ -294,7 +294,9 @@ struct e2fsck_struct {char *log_fn;FILE *problem_logf;char *problem_log_fn; -int flags;/* E2fsck internal flags */ +/* E2fsck internal flags. +* shared by different threads for pass1 [fs_fix_rwlock] */ +int flags;int options;unsigned blocksize;/* blocksize */ blk64_t use_superblock;/* sb requested by user */
@@ -314,6 +316,7 @@ struct e2fsck_struct {int (*progress)(e2fsck_t ctx,int pass,unsigned long cur,unsigned long max); +/* The following inode bitmaps are separately used in thread_ctx Pass1*/ ext2fs_inode_bitmap inode_used_map;/* Inodes which are in use */ ext2fs_inode_bitmap inode_bad_map;/* Inodes which are bad somehow */ ext2fs_inode_bitmap inode_dir_map;/* Inodes which are directories */
@@ -322,12 +325,14 @@ struct e2fsck_struct {ext2fs_inode_bitmap inode_reg_map;/* Inodes which are regular files*/ ext2fs_inode_bitmap inode_casefold_map;/* Inodes which are casefolded */ +/* Following 3 protected by [fs_block_map_rwlock] */ ext2fs_block_bitmap block_found_map;/* Blocks which are in use */ ext2fs_block_bitmap block_dup_map;/* Blks referenced more than once */ ext2fs_block_bitmap block_ea_map;/* Blocks which are used by EA's */ /* -* Inode count arrays +* Inode count arrays. +* Separately used in thread_ctx, pass1 */ ext2_icount_t inode_count;ext2_icount_t inode_link_info;
@@ -349,7 +354,8 @@ struct e2fsck_struct {/* * Array of flags indicating whether an inode bitmap, block -* bitmap, or inode table is invalid +* bitmap, or inode table is invalid. +* Separately used in thread_ctx, pass1 */ int *invalid_inode_bitmap_flag;int *invalid_block_bitmap_flag;
@@ -362,7 +368,8 @@ struct e2fsck_struct {char *block_buf;/* -* For pass1_check_directory and pass1_get_blocks +* For pass1_check_directory and pass1_get_blocks. +* Separately used in thread_ctx in pass1 */ ext2_ino_t stashed_ino;struct ext2_inode *stashed_inode;
@@ -421,6 +428,7 @@ struct e2fsck_struct {/* * How we display the progress update (for unix) +* shared by different threads for pass1 [fs_fix_rwlock] */ int progress_fd;int progress_pos;
@@ -429,7 +437,7 @@ struct e2fsck_struct {int interactive;/* Are we connected directly to a tty? */ char start_meta[2 ], stop_meta[2 ]; -/* File counts */ +/* File counts. Separately used in thread_ctx, pass1 */ __u32 fs_directory_count;__u32 fs_regular_count;__u32 fs_blockdev_count;
Signature · 1 line
2.37.3
RFC 66/72 e2fsck: merge casefolded dir lists after thread finish
In reply to Ritesh Harjani (IBM)From: Wang Shilong <[email protected]>
This is missed and should be done after threads finish.
Original commit:18538b27 ("LU-8465 e2fsck: merge encrypted dir lists after thread finish") Upstream is now using e2fsck_struct->casefolded_dirs instead of encrypted_dirs.
Only for the correctness of pfsck, we won't use casefolded feature on ldiskfs.
--- e2fsck/pass1.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
e2fsck/pass1.c +26 -0
@@ -2614,6 +2614,7 @@ static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *thre }memcpy (thread_context, global_ctx,sizeof (struct e2fsck_struct )); thread_context->block_dup_map =NULL ; + thread_context->casefolded_dirs =NULL ; retval = e2fsck_allocate_block_bitmap(global_ctx->fs, _("in-use block map"), EXT2FS_BMAP64_RBTREE,
@@ -2905,6 +2906,24 @@ static errcode_t e2fsck_pass1_merge_ea_refcount(e2fsck_t global_ctx,return retval; } +static errcode_t e2fsck_pass1_merge_casefolded_dirs (e2fsck_t global_ctx, +e2fsck_t thread_ctx) +{ +errcode_t retval =0 ; + +if (!thread_ctx->casefolded_dirs) +return 0 ; + +if (!global_ctx->casefolded_dirs) + retval =ext2fs_badblocks_copy (thread_ctx->casefolded_dirs, + &global_ctx->casefolded_dirs); +else + retval =ext2fs_badblocks_merge (thread_ctx->casefolded_dirs, + global_ctx->casefolded_dirs); + +return retval; +} +static errcode_t e2fsck_pass1_merge_context (e2fsck_t global_ctx,e2fsck_t thread_ctx) {
@@ -2971,6 +2990,13 @@ static errcode_t e2fsck_pass1_merge_context(e2fsck_t global_ctx,if (retval)return retval; + retval =e2fsck_pass1_merge_casefolded_dirs (global_ctx, thread_ctx); +if (retval) { +com_err (global_ctx->program_name,0 , +_ ("while merging casefolded dirs\n" )); +return retval; + } +e2fsck_pass1_merge_invalid_bitmaps (global_ctx, thread_ctx); retval = e2fsck_pass1_merge_bitmap(global_fs,
Signature · 1 line
2.37.3
RFC 69/72 e2fsck: Fix double free of inodes_to_process
In reply to Ritesh Harjani (IBM)Found during code review, this fixes the double free of inodes_to_process in e2fsck_pass1_run.
--- e2fsck/pass1.c | 1 - 1 file changed, 1 deletion(-)
e2fsck/pass1.c +0 -1
@@ -2436,7 +2436,6 @@ void e2fsck_pass1_run(e2fsck_t ctx) } ctx->flags |=E2F_FLAG_ALLOC_OK ; -ext2fs_free_mem (&inodes_to_process); endit:e2fsck_use_inode_shortcuts (ctx,0 );ext2fs_free_mem (&inodes_to_process);
Signature · 1 line
2.37.3
RFC 68/72 e2fsck: Fix io->align assert check
In reply to Ritesh Harjani (IBM)dest->io->align might still get set later in case of non-aligned read done by any thread in raw_read_blk(). Hence remove this assert check.
--- e2fsck/pass1.c | 1 - 1 file changed, 1 deletion(-)
e2fsck/pass1.c +0 -1
@@ -2514,7 +2514,6 @@ static errcode_t e2fsck_open_channel_fs(ext2_filsys dest, e2fsck_t dest_context,assert (dest->io->flags == src->io->flags);assert (dest->io->app_data == dest);assert (src->io->app_data == src); -assert (dest->io->align == src->io->align); dest->priv_data = dest_context; dest_context->fs = dest;
Signature · 1 line
2.37.3
RFC 70/72 e2fsck: Fix and simplify update_mmp in case of pfsck
In reply to Ritesh Harjani (IBM)This adds pass1_update_mmp_enter() & pass1_update_mmp_exit() routines to update mmp block. This also fixes a data race reported by threadsan because of reading and writing to mmp_update_thread variable.
--- e2fsck/pass1.c | 97 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 34 deletions(-)
e2fsck/pass1.c +63 -34
@@ -1097,6 +1097,66 @@ out:return 0 ; } +static void pass1_update_mmp_enter (e2fsck_t ctx,ext2_ino_t ino) +{ +ext2_filsys fs = ctx->fs; +e2fsck_t global_ctx = ctx->global_ctx ? ctx->global_ctx : ctx; +int check_mmp =0 ; +int set_mmp =0 ; + +#ifdef HAVE_PTHREAD +/* only one active thread could update mmp block. */ +e2fsck_pass1_block_map_r_lock (ctx); +if (!global_ctx->mmp_update_thread) + set_mmp =1 ; +if (global_ctx->mmp_update_thread == ctx->thread_info.et_thread_index +1 ) + check_mmp =1 ; +e2fsck_pass1_block_map_r_unlock (ctx); + +if (!check_mmp && !set_mmp) +return ; + +if (set_mmp) { +e2fsck_pass1_block_map_w_lock (ctx); +if (!global_ctx->mmp_update_thread) { + global_ctx->mmp_update_thread = + ctx->thread_info.et_thread_index +1 ; + check_mmp =1 ; + } +e2fsck_pass1_block_map_w_unlock (ctx); + } +#else + check_mmp =1 ; +#endif + +if (check_mmp && (ino % (fs->super->s_inodes_per_group *4 ) ==1 )) { +if (e2fsck_mmp_update (fs)) +fatal_error (ctx,0 ); + } +} + +static void pass1_update_mmp_exit (e2fsck_t ctx) +{ +ext2_filsys fs = ctx->fs; +e2fsck_t global_ctx = ctx->global_ctx ? ctx->global_ctx : ctx; +int set_mmp =0 ; + +#ifdef HAVE_PTHREAD +e2fsck_pass1_block_map_r_lock (ctx); +if (global_ctx->mmp_update_thread == ctx->thread_info.et_thread_index +1 ) + set_mmp =1 ; +e2fsck_pass1_block_map_r_unlock (ctx); + +if (!set_mmp) +return ; + +/* reset update_thread after this thread exit */ +e2fsck_pass1_block_map_w_lock (ctx); + global_ctx->mmp_update_thread =0 ; +e2fsck_pass1_block_map_w_unlock (ctx); +#endif +} +static void pass1_readahead (e2fsck_t ctx,dgrp_t *group,ext2_ino_t *next_ino) {ext2_ino_t inodes_in_group =0 , inodes_per_block, inodes_per_buffer;
@@ -1511,7 +1571,7 @@ void e2fsck_pass1_run(e2fsck_t ctx)dgrp_t ra_group =0 ;struct ea_quota ea_ibody_quota;struct process_inode_block *inodes_to_process; -int process_inode_count, check_mmp; +int process_inode_count;e2fsck_t global_ctx = ctx->global_ctx ? ctx->global_ctx : ctx;init_resource_track (&rtrack, ctx->fs->io);
@@ -1675,33 +1735,8 @@ void e2fsck_pass1_run(e2fsck_t ctx)#endif while (1 ) { - check_mmp =0 ;e2fsck_pass1_check_lock (ctx); -#ifdef HAVE_PTHREAD -if (!global_ctx->mmp_update_thread) { -e2fsck_pass1_block_map_w_lock (ctx); -if (!global_ctx->mmp_update_thread) { - global_ctx->mmp_update_thread = - ctx->thread_info.et_thread_index +1 ; - check_mmp =1 ; - } -e2fsck_pass1_block_map_w_unlock (ctx); - } - -/* only one active thread could update mmp block. */ -e2fsck_pass1_block_map_r_lock (ctx); -if (global_ctx->mmp_update_thread == - ctx->thread_info.et_thread_index +1 ) - check_mmp =1 ; -e2fsck_pass1_block_map_r_unlock (ctx); -#else - check_mmp =1 ; -#endif - -if (check_mmp && (ino % (fs->super->s_inodes_per_group *4 ) ==1 )) { -if (e2fsck_mmp_update (fs)) -fatal_error (ctx,0 ); - } +pass1_update_mmp_enter (ctx, ino); old_op =ehandler_operation (eop_next_inode); pctx.errcode =ext2fs_get_next_inode_full (scan, &ino, inode, inode_size);
@@ -2458,13 +2493,7 @@ endit:print_resource_track (ctx,_ ("Pass 1" ), &rtrack, ctx->fs->io); else ctx->invalid_bitmaps++; -#ifdef HAVE_PTHREAD -/* reset update_thread after this thread exit */ -e2fsck_pass1_block_map_w_lock (ctx); -if (check_mmp) - global_ctx->mmp_update_thread =0 ; -e2fsck_pass1_block_map_w_unlock (ctx); -#endif +pass1_update_mmp_exit (ctx); }#ifdef HAVE_PTHREAD
Signature · 1 line
2.37.3
RFC 67/72 sec: support encrypted files handling in pfsck mode
In reply to Ritesh Harjani (IBM)From: Sebastien Buisson <[email protected]>
e2fsck needs to be improved in order to support encrypted files handling in parallel fsck mode. The e2fsck_merge_encrypted_info() function is added to merge encrypted inodes info collected from different threads in pass1, so that it can be used in pass2.
--- e2fsck/e2fsck.h | 2 + e2fsck/encrypted_files.c | 139 +++++++++++++++++++++++++++++++++++++++ e2fsck/pass1.c | 26 +++++++- 3 files changed, 164 insertions(+), 3 deletions(-)
e2fsck/e2fsck.h +2 -0
@@ -642,6 +642,8 @@ __u32 find_encryption_policy(e2fsck_t ctx, ext2_ino_t ino);void destroy_encryption_policy_map (e2fsck_t ctx);void destroy_encrypted_file_info (e2fsck_t ctx); +int e2fsck_merge_encrypted_info (e2fsck_t ctx,struct encrypted_file_info *src, +struct encrypted_file_info *dest);/* extents.c */ errcode_t e2fsck_rebuild_extents_later (e2fsck_t ctx,ext2_ino_t ino);
e2fsck/encrypted_files.c +139 -0
142 lines not on this page · raw message
e2fsck/pass1.c +23 -3
@@ -2411,9 +2411,6 @@ void e2fsck_pass1_run(e2fsck_t ctx) ctx->ea_block_quota_inodes =0 ; } -/* We don't need the encryption policy => ID map any more */ -destroy_encryption_policy_map (ctx); -if (ctx->flags &E2F_FLAG_RESTART ) {/* * Only the master copy of the superblock and block
@@ -2703,6 +2700,23 @@ static void e2fsck_pass1_merge_dx_dir(e2fsck_t global_ctx, e2fsck_t thread_ctx)e2fsck_merge_dx_dir (global_ctx, thread_ctx); } +static int e2fsck_pass1_merge_encrypted_info (e2fsck_t global_ctx, +e2fsck_t thread_ctx) +{ +if (thread_ctx->encrypted_files ==NULL ) +return 0 ; + +if (global_ctx->encrypted_files ==NULL ) { + global_ctx->encrypted_files = thread_ctx->encrypted_files; + thread_ctx->encrypted_files =NULL ; +return 0 ; + } + +return e2fsck_merge_encrypted_info (global_ctx, + thread_ctx->encrypted_files, + global_ctx->encrypted_files); +} +static inline errcode_t e2fsck_pass1_merge_icount (ext2_icount_t *dest_icount,ext2_icount_t *src_icount)
@@ -2963,6 +2977,12 @@ static errcode_t e2fsck_pass1_merge_context(e2fsck_t global_ctx,e2fsck_pass1_merge_dir_info (global_ctx, thread_ctx);e2fsck_pass1_merge_dx_dir (global_ctx, thread_ctx); + retval =e2fsck_pass1_merge_encrypted_info (global_ctx, thread_ctx); +if (retval) { +com_err (global_ctx->program_name,0 , +_ ("while merging encrypted info\n" )); +return retval; + } retval =ext2fs_merge_fs (&(thread_ctx->fs));if (retval) {
Signature · 1 line
2.37.3
RFC 71/72 e2fsck: Make threads call log_out after pthread_join
In reply to Ritesh Harjani (IBM)All fsck threads will call for log_out prints after the pass1 their respective pass1 scanning is completed. This patch moves the log_out print from to after the pthread_join operation.
This makes the threads always print the info in order.
--- e2fsck/pass1.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
e2fsck/pass1.c +6 -7
@@ -3112,6 +3112,12 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx) {errcode_t retval; +log_out (thread_ctx, +_ ("Scanned group range [%u, %u), inodes %u\n" ), + thread_ctx->thread_info.et_group_start, + thread_ctx->thread_info.et_group_end, + thread_ctx->thread_info.et_inode_number); + retval =e2fsck_pass1_merge_context (global_ctx, thread_ctx);quota_release_context (&thread_ctx->qctx);
@@ -3203,13 +3209,6 @@ static void *e2fsck_pass1_thread(void *arg)e2fsck_pass1_run (thread_ctx); out: -if (thread_ctx->options &E2F_OPT_MULTITHREAD ) -log_out (thread_ctx, -_ ("Scanned group range [%u, %u), inodes %u\n" ), - thread_ctx->thread_info.et_group_start, - thread_ctx->thread_info.et_group_end, - thread_ctx->thread_info.et_inode_number); -#ifdef DEBUG_THREADS pthread_mutex_lock (&thread_debug->etd_mutex); thread_debug->etd_finished_threads++;
Signature · 1 line
2.37.3
RFC 72/72 tests/f_multithread: Fix f_multithread related tests
In reply to Ritesh Harjani (IBM)With log_out() function now changed to print the message after the pthread join operation, it is safe to also add "Scan group range" related messages in expect files to compare against the pfsck output.
--- tests/f_multithread_ok/expect.1 | 8 ++++++++ tests/f_multithread_ok/script | 17 ----------------- 2 files changed, 8 insertions(+), 17 deletions(-)
tests/f_multithread_ok/expect.1 +8 -0
@@ -1,4 +1,12 @@ Pass 1: Checking inodes, blocks, and sizes +[Thread 0] Scan group range [0, 1) +[Thread 1] Scan group range [1, 2) +[Thread 2] Scan group range [2, 3) +[Thread 3] Scan group range [3, 4) +[Thread 0] Scanned group range [0, 1), inodes 8192 +[Thread 1] Scanned group range [1, 2), inodes 8192 +[Thread 2] Scanned group range [2, 3), inodes 8192 +[Thread 3] Scanned group range [3, 4), inodes 8192 Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts
tests/f_multithread_ok/script +0 -17
@@ -1,21 +1,4 @@ FSCK_OPT="-fym4" -SKIP_VERIFY="true" ONE_PASS_ONLY="true" -SKIP_CLEANUP="true" . $cmd_dir/run_e2fsck - -grep -v Thread $OUT1 > $OUT1.tmp -cmp -s $EXP1 $OUT1.tmp -status1=$? -if [ "$status1" -eq 0 ]; then - echo "$test_name: $test_description: ok" - touch $test_name.ok -else - echo "$test_name: $test_description: failed" - diff $DIFF_OPTS $EXP1 $OUT1.tmp > $test_name.failed -fi - -unset IMAGE FSCK_OPT SECOND_FSCK_OPT OUT1 OUT2 EXP1 EXP2 -unset SKIP_VERIFY SKIP_CLEANUP SKIP_GUNZIP ONE_PASS_ONLY PREP_CMD -unset DESCRIPTION SKIP_UNLINK AFTER_CMD PASS_ZERO
Signature · 1 line
2.37.3
Re: [RFCv1 67/72] sec: support encrypted files handling in pfsck mode
In reply to Ritesh Harjani (IBM)Quoted 2 lines · Ritesh Harjani (IBM)
sec: support encrypted files handling in pfsck mode
"sec:" => "e2fsck:".
Quoted 22 lines
e2fsck/encrypted_files.c +22
-0+/** +* Search policy matching @policy in @info->policies +* @ctx: e2fsck context +* @info: encrypted_file_info to look into +* @policy: the policy we are looking for +* @parent: (out) last known parent, useful to insert a new leaf +* in @info->policies +* +* Return: id of found policy on success, -1 if no matching policy found. +*/ +static inline int search_policy (e2fsck_t ctx,struct encrypted_file_info *info, +union fscrypt_policy policy, +struct rb_node **parent) +{ +struct rb_node *n = info->policies.rb_node; +struct policy_map_entry *entry; + +while (n) { +int res; + + *parent = n; + entry = ext2fs_rb_entry(n, struct policy_map_entry, node);
e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 491
Quoted 10 lines
e2fsck/encrypted_files.c +10
-0+ res =cmp_fscrypt_policies (ctx, &policy, &entry->policy); +if (res <0 ) + n = n->rb_left; +else if (res >0 ) + n = n->rb_right; +else +return entry->policy_id; + } +return -1 ; +}
Can this rbtree search code be reused by get_encryption_policy_id()?
Also, please use the existing constant NO_ENCRYPTION_POLICY instead of -1.
e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 504
Quoted 12 lines
e2fsck/encrypted_files.c +12
-0+/* +* Merge @src encrypted info into @dest +*/ +int e2fsck_merge_encrypted_info (e2fsck_t ctx,struct encrypted_file_info *src, +struct encrypted_file_info *dest) +{ +struct rb_root *src_policies = &src->policies; +__u32 *policy_trans; +int i, rc =0 ; + +if (dest->file_ranges[src->file_ranges_count -1 ].last_ino > + src->file_ranges[0 ].first_ino) {
There is an off-by-one error here. How about writing it like the following so that it looks like the check in append_ino_and_policy_id():
if (src->file_ranges[0].first_ino <=
dest->file_ranges[src->file_ranges_count - 1].last_ino) {e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 514
Quoted 1 line
e2fsck/encrypted_files.c +1
-0+/* First, deal with the encryption policy => ID map.
My understanding is that e2fsprogs follows the kernel coding style, where block comments are formatted like the following:
/* * text */
e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 516
Quoted 2 lines
e2fsck/encrypted_files.c +2
-0+* Compare encryption policies in src with policies already recorded +* in dest. It can be similar policies, but recorded with a different
"similar" => "the same"
e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 531
Quoted 10 lines
e2fsck/encrypted_files.c +10
-0+while (!ext2fs_rb_empty_root (src_policies)) { +struct policy_map_entry *entry, *newentry; +struct rb_node *new, *parent =NULL ; +int existing_polid; + + entry =ext2fs_rb_entry (src_policies->rb_node, + struct policy_map_entry, node); + existing_polid =search_policy (ctx, dest, + entry->policy, &parent); +if (existing_polid >=0 ) {
existing_polid != NO_ENCRYPTION_POLICY
e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 543
Quoted 12 lines
e2fsck/encrypted_files.c +12
-0+/* The policy in src is already recorded in dest, +* so just update its id. +*/ + policy_trans[entry->policy_id] = existing_polid; + }else { +/* The policy in src is new to dest, so insert it +* with the next available id (its original id could +* be already used in dest). +*/ + rc =ext2fs_get_mem (sizeof (*newentry), &newentry); +if (rc) + goto out_merge;
Use handle_nomem() for memory allocation failures?
e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 549
Quoted 6 lines
e2fsck/encrypted_files.c +6
-0+ newentry->policy_id = dest->next_policy_id++; + newentry->policy = entry->policy; +ext2fs_rb_link_node (&newentry->node, parent, &new); +ext2fs_rb_insert_color (&newentry->node, + &dest->policies); + policy_trans[entry->policy_id] = newentry->policy_id;
This code also appears in get_encryption_policy_id(). Should it be refactored into a helper function?
Quoted 20 lines
e2fsck/encrypted_files.c +20
-0+/* Second, deal with the inode number => encryption policy ID map. */ +if (dest->file_ranges_capacity < + dest->file_ranges_count + src->file_ranges_count) { +/* dest->file_ranges is too short, increase its capacity. */ +size_t new_capacity = dest->file_ranges_count + + src->file_ranges_count; + +/* Make sure we at least double the capacity. */ +if (new_capacity < (dest->file_ranges_capacity *2 )) + new_capacity = dest->file_ranges_capacity *2 ; + +/* We won't need more than the filesystem's inode count. */ +if (new_capacity > ctx->fs->super->s_inodes_count) + new_capacity = ctx->fs->super->s_inodes_count; + + rc =ext2fs_resize_mem (dest->file_ranges_capacity * +sizeof (struct encrypted_file_range ), + new_capacity * +sizeof (struct encrypted_file_range ), + &dest->file_ranges);
e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 584
Quoted 10 lines
e2fsck/encrypted_files.c +10
-0+if (rc) { +fix_problem (ctx,PR_1_ALLOCATE_ENCRYPTED_INODE_LIST , +NULL ); +/* Should never get here */ + ctx->flags |=E2F_FLAG_ABORT ; + goto out_merge; + } + + dest->file_ranges_capacity = new_capacity; + }
The exact allocation size that is needed is 'dest->file_ranges_count + src->file_ranges_count', so much of the above logic is unnecessary. Just reallocate that exact amount.
Also, handle_nomem() should be used.
e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 592
Quoted 8 lines
e2fsck/encrypted_files.c +8
-0+/* Copy file ranges from src to dest. */ +for (i =0 ; i < src->file_ranges_count; i++) { +/* Make sure to convert policy ids in src. */ + src->file_ranges[i].policy_id = + policy_trans[src->file_ranges[i].policy_id]; + dest->file_ranges[dest->file_ranges_count++] = + src->file_ranges[i]; + }
This needs to handle UNRECOGNIZED_ENCRYPTION_POLICY as a special case.
Also, shouldn't src->file_ranges be freed after this?
Review
Quoted 2 lines
(quoted diff) +2
-0+ +out_merge:
I guess the "_merge" in "out_merge:" comes from the name of the containing function? It's a bit confusing. Maybe just use "out:".
e2fsck/pass1.c void e2fsck_pass1_run(e2fsck_t ctx) · line 2415
Quoted 10 lines
e2fsck/pass1.c +0
-2@@ -2411,9 +2411,6 @@ void e2fsck_pass1_run(e2fsck_t ctx) ctx->ea_block_quota_inodes =0 ; } -/* We don't need the encryption policy => ID map any more */ -destroy_encryption_policy_map (ctx);
With this change, there are no callers of destroy_encryption_policy_map() outside encrypted_files.c. So absent any other changes, destroy_encryption_policy_map() should be made into a static function and the 'if (info)' check inside it removed.
But, isn't there still some point where pass 1 is fully done and the encryption policy ID map can be destroyed? Maybe e2fsck_pass1_merge_encrypted_info() should be calling destroy_encryption_policy_map() on the global_ctx after doing the merge?
- Eric
Re: [RFCv1 01/72] e2fsck: Fix unbalanced mutex unlock for BOUNCE_MTX
In reply to Ritesh Harjani (IBM)Quoted 6 lines · Ritesh Harjani (IBM)
f_crashdisktest failed with UNIX_IO_FORCE_BOUNCE=yes due to unbalanced mutex unlock in below path.This patch fixes it.
Signed-off-by Ritesh Harjani (IBM) <[email protected]>
This has been fixed in upstream (for a while, actually); what commit is your patches based upon?
- Ted
Re: [RFCv1 01/72] e2fsck: Fix unbalanced mutex unlock for BOUNCE_MTX
Quoted 9 lines · Theodore Ts'o
Quoted 6 lines · Ritesh Harjani (IBM)
f_crashdisktest failed with UNIX_IO_FORCE_BOUNCE=yes due to unbalanced mutex unlock in below path.This patch fixes it.
Signed-off-by Ritesh Harjani (IBM) <[email protected]>This has been fixed in upstream (for a while, actually);
Hello Ted,
I think you are speaking about this patch here [1], which prevents the race of using the fd by multiple threads at a time, by using BOUNCE_MTX lock.
The current patch on the other hand fixes the unbalanced mutex_unlock(), which can be reproduced with f_crashdisk test with UNIX_IO_FORCE_BOUNCE=yes. (when tested with --enable-threadsan)
Below is the threadsan warning that I see.
WARNING: ThreadSanitizer: unlock of an unlocked mutex (or by a wrong thread) (pid=135059)
#0 pthread_mutex_unlock <null> (libtsan.so.0+0x3b64a)
#1 mutex_unlock ../../../lib/ext2fs/unix_io.c:161 (e2fsck+0x5b392b)
#2 raw_read_blk ../../../lib/ext2fs/unix_io.c:331 (e2fsck+0x5b392b)
#3 unix_read_blk64 ../../../lib/ext2fs/unix_io.c:1001 (e2fsck+0x5b4981)
#4 unix_read_blk ../../../lib/ext2fs/unix_io.c:1053 (e2fsck+0x5b5171)
#5 ext2fs_open2 ../../../lib/ext2fs/openfs.c:228 (e2fsck+0x579e5c)
#6 try_open_fs ../../e2fsck/unix.c:1242 (e2fsck+0x424e63)
#7 main ../../e2fsck/unix.c:1604 (e2fsck+0x41a1d2) Location is heap block of size 376 at 0x7b4800000000 allocated by main thread:
#0 malloc <null> (libtsan.so.0+0x32919)
#1 ext2fs_get_mem ../../../lib/ext2fs/ext2fs.h:1944 (e2fsck+0x5aec30)
#2 unix_open_channel ../../../lib/ext2fs/unix_io.c:698 (e2fsck+0x5aec30)
#3 unix_open ../../../lib/ext2fs/unix_io.c:910 (e2fsck+0x5afd67)
#4 ext2fs_open2 ../../../lib/ext2fs/openfs.c:175 (e2fsck+0x579918)
#5 try_open_fs ../../e2fsck/unix.c:1242 (e2fsck+0x424e63)
#6 main ../../e2fsck/unix.c:1604 (e2fsck+0x41a1d2) Mutex M22 (0x7b4800000128) created at:
#0 pthread_mutex_init <null> (libtsan.so.0+0x49603)
#1 unix_open_channel ../../../lib/ext2fs/unix_io.c:827 (e2fsck+0x5af5ef)
#2 unix_open ../../../lib/ext2fs/unix_io.c:910 (e2fsck+0x5afd67)
#3 ext2fs_open2 ../../../lib/ext2fs/openfs.c:175 (e2fsck+0x579918)
#4 try_open_fs ../../e2fsck/unix.c:1242 (e2fsck+0x424e63)
#5 main ../../e2fsck/unix.c:1604 (e2fsck+0x41a1d2)SUMMARY: ThreadSanitizer: unlock of an unlocked mutex (or by a wrong thread) (/lib64/libtsan.so.0+0x3b64a) in pthread_mutex_unlock
Quoted 1 line
what commit is your patches based upon?
1. This series is rebased on the latest e2fsprogs master branch.
https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/log/
Cover letter might provide some more details on how the patch series is broken into. The github link of the series can be found at
https://github.com/riteshharjani/e2fsprogs/commits/pfsck-RFCv1
Note: I have provided some details in the cover letter about Patch-073 i.e. ("tests: Add multi-thread tests framework"). But putting it once again here... You can ignore this ^^^ last patch in the github link.
This was added to tests all existing e2fsck test with pfsck mode. But later I realized that it will require more work then how it is in the current form. Since I didn't want to hold the patch series any longer and I wanted this series to go through the initial round of review, before it becomes any bigger and difficult to review, hence I decided to drop the last patch from sending it to mailing list.
Please let me know if you have any queries on any patch/series.
-ritesh
Re: [RFCv1 01/72] e2fsck: Fix unbalanced mutex unlock for BOUNCE_MTX
In reply to Ritesh Harjani (IBM)Quoted 16 lines · Ritesh Harjani (IBM)
f_crashdisk test failed with UNIX_IO_FORCE_BOUNCE=yes due to unbalanced mutex unlock in below path.
This patch fixes it.
Signed-off-by Ritesh Harjani (IBM) <[email protected]>---
lib/ext2fs/unix_io.c| 1 -1 file changed, 1 deletion(-)lib/ext2fs/unix_io.c +0
-0
lib/ext2fs/unix_io.c bounce_read: · line 308
Quoted 4 lines
lib/ext2fs/unix_io.c +0
-1@@ -305,7 +305,6 @@ bounce_read:while (size >0 ) { actual =read (data->dev, data->bounce, align_size);if (actual != align_size) { -mutex_unlock (data,BOUNCE_MTX );
This patch doesn't show enough context, but AFAIK this is jumping before mutex_down() is called, so this *should* be correct as is?
Cheers, Andreas
Quoted 6 lines
lib/ext2fs/unix_io.c +0
-0actual = really_read; buf -= really_read; size += really_read;Signature · 1 line
2.37.3
Re: [RFCv1 03/72] blkmap64_ba: Add common helper for bits size calculation
In reply to Ritesh Harjani (IBM)Quoted 4 lines · Ritesh Harjani (IBM)
Just a quick common helper for bits size calculation.
Signed-off-by Ritesh Harjani (IBM) <[email protected]>
Quoted 72 lines
---
lib/ext2fs/blkmap64_ba.c| 20 +++++++++++++-------1 file changed, 13 insertions(+), 7 deletions(-)lib/ext2fs/blkmap64_ba.c +13
-7@@ -40,6 +40,13 @@ struct ext2fs_ba_private_struct {typedef struct ext2fs_ba_private_struct *ext2fs_ba_private ; +#define ba_bits_size (start, end) ((((end) - (start)) / 8 + 1)) + +static size_t ba_bitmap_size (ext2fs_generic_bitmap_64 bitmap) +{ +return (size_t )ba_bits_size (bitmap->start, bitmap->real_end); +} +static errcode_t ba_alloc_private_data (ext2fs_generic_bitmap_64 bitmap) {ext2fs_ba_private bp;@@ -56,7 +63,7 @@ static errcode_t ba_alloc_private_data (ext2fs_generic_bitmap_64 bitmap)if (retval)return retval; - size = (size_t ) (((bitmap->real_end - bitmap->start) /8 ) +1 ); + size =ba_bitmap_size (bitmap); retval =ext2fs_get_mem (size, &bp->bitarray);if (retval) {@@ -80,7 +87,7 @@ static errcode_t ba_new_bmap(ext2_filsys fs EXT2FS_ATTR((unused)),return retval; bp = (ext2fs_ba_private ) bitmap->private; - size = (size_t ) (((bitmap->real_end - bitmap->start) /8 ) +1 ); + size =ba_bitmap_size (bitmap);memset (bp->bitarray,0 , size);return 0 ;@@ -115,7 +122,7 @@ static errcode_t ba_copy_bmap(ext2fs_generic_bitmap_64 src, dest_bp = (ext2fs_ba_private ) dest->private; - size = (size_t ) (((src->real_end - src->start) /8 ) +1 ); + size =ba_bitmap_size (src);memcpy (dest_bp->bitarray, src_bp->bitarray, size);return 0 ;@@ -145,8 +152,8 @@ static errcode_t ba_resize_bmap(ext2fs_generic_bitmap_64 bmap,return 0 ; } - size = ((bmap->real_end - bmap->start) /8 ) +1 ; - new_size = ((new_real_end - bmap->start) /8 ) +1 ; + size =ba_bitmap_size (bmap); + new_size =ba_bits_size (new_real_end, bmap->start);if (size != new_size) { retval =ext2fs_resize_mem (size, new_size, &bp->bitarray);@@ -306,8 +313,7 @@ static void ba_clear_bmap(ext2fs_generic_bitmap_64 bitmap) {ext2fs_ba_private bp = (ext2fs_ba_private ) bitmap->private; -memset (bp->bitarray,0 , - (size_t ) (((bitmap->real_end - bitmap->start) /8 ) +1 )); +memset (bp->bitarray,0 ,ba_bitmap_size (bitmap)); }#ifdef ENABLE_BMAP_STATS Signature · 1 line
2.37.3
Re: [RFCv1 01/72] e2fsck: Fix unbalanced mutex unlock for BOUNCE_MTX
In reply to Andreas DilgerQuoted 12 lines · Andreas Dilger
Quoted 11 lines · Ritesh Harjani (IBM)
f_crashdisktest failed with UNIX_IO_FORCE_BOUNCE=yes due to unbalanced mutex unlock in below path.This patch fixes it.
Signed-off-by Ritesh Harjani (IBM) <[email protected]>---
lib/ext2fs/unix_io.c| 1 -1 file changed, 1 deletion(-)
Quoted 12 lines
lib/ext2fs/unix_io.c bounce_read: · line 308
Quoted 9 lines
lib/ext2fs/unix_io.c +0
-1@@ -305,7 +305,6 @@ bounce_read:while (size >0 ) { actual =read (data->dev, data->bounce, align_size);if (actual != align_size) { -mutex_unlock (data,BOUNCE_MTX );This patch doesn't show enough context, but AFAIK this is jumping before
mutex_down()is called, so this *should* be correct as is?
Thanks for the review, Andreas.
Yeah, the patch diff above is not sufficient since it doesn't share enuf context.
But essentially when "actual" is not equal to "align_size", then in this if condition it goes to label "short_read:", which always goto error_unlock, where we anyways call mutex_unlock()
Looking at a lot of labels in this function, this definitely looks like something which can be cleaned up ("raw_read_blk()").
I will add that to my list of todos.
I have also shared the threadsan warning which detects the unbalanced mutex unlock here [1]
[1]: https://lore.kernel.org/linux-ext4/[email protected]/T/#md75b3ccb146e4433653bc2d7dd01329a9757ea26
-ritesh
Re: [RFCv1 01/72] e2fsck: Fix unbalanced mutex unlock for BOUNCE_MTX
Quoted 35 lines · Ritesh Harjani (IBM)
Quoted 12 lines · Andreas Dilger
Quoted 12 lines · Ritesh Harjani (IBM)
f_crashdisktest failed with UNIX_IO_FORCE_BOUNCE=yes due to unbalanced mutex unlock in below path.This patch fixes it.
Signed-off-by Ritesh Harjani (IBM) <[email protected]>---
lib/ext2fs/unix_io.c| 1 -1 file changed, 1 deletion(-)Quoted 12 lines
lib/ext2fs/unix_io.c bounce_read: · line 308
Quoted 9 lines
lib/ext2fs/unix_io.c +0
-1@@ -305,7 +305,6 @@ bounce_read:while (size >0 ) { actual =read (data->dev, data->bounce, align_size);if (actual != align_size) { -mutex_unlock (data,BOUNCE_MTX );This patch doesn't show enough context, but AFAIK this is jumping before
mutex_down()is called, so this *should* be correct as is?Thanks for the review, Andreas.
Yeah, the patch diff above is not sufficient since it doesn't share enuf context.
But essentially when "actual" is not equal to "align_size", then in this if condition it goes to label "short_read:", which always gotoerror_unlock, where we anyways callmutex_unlock()
Quoted 3 lines
Looking at a lot of labels in this function, this definitely looks like something which can be cleaned up ("
raw_read_blk()").
I will add that to my list of todos.
You are correct, and it means this code is just not very clear to the reader. I think it would make more sense to move the "short_read:" label to the end of the code:
actual = read(...);
if (actual != size)
goto error_short_read;
goto success_unlock;
:
actual = read(...);
if (actual != align_size) {
actual = really_read;
buf -= really_read;
size += really_read;
goto error_short_read;
}
:
success_unlock:
mutex_unlock(...);
return 0;error_short_read:
if (actual < 0) {
retval = errno;
actual = 0;
} else {
retval = EXT2_ET_SHORT_READ;
}
error_unlock:
mutex_unlock(...);That way the code follows the normal error handling convention and is less likely to be surprising to the reader.
Cheers, Andreas
Re: [RFCv1 04/72] badblocks: Remove unused badblocks_flags
In reply to Ritesh Harjani (IBM)Quoted 4 lines · Ritesh Harjani (IBM)
badblocks_flags is not used anywhere. So just remove it.
Signed-off-by Ritesh Harjani (IBM) <[email protected]>
Quoted 37 lines
---
lib/ext2fs/badblocks.c| 6 +-----lib/ext2fs/ext2fsP.h| 1 -2 files changed, 1 insertion(+), 6 deletions(-)lib/ext2fs/badblocks.c +1
-5@@ -81,11 +81,7 @@ errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest) {errcode_t retval; - retval =make_u32_list (src->size, src->num, src->list, dest); -if (retval) -return retval; - (*dest)->badblocks_flags = src->badblocks_flags; -return 0 ; +return make_u32_list (src->size, src->num, src->list, dest); } errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,lib/ext2fs/ext2fsP.h +0
-1@@ -34,7 +34,6 @@ struct ext2_struct_u32_list {int num;int size;__u32 *list; -int badblocks_flags; };struct ext2_struct_u32_iterate {Signature · 1 line
2.37.3
Re: [RFCv1 05/72] badblocks: Add badblocks merge logic
In reply to Ritesh Harjani (IBM)Quoted 7 lines · Ritesh Harjani (IBM)
From: Wang Shilong <[email protected]>
Add badblocks merge logic
Signed-off-by Wang Shilong <[email protected]>Signed-off-by Ritesh Harjani (IBM) <[email protected]>
Quoted 114 lines
---
lib/ext2fs/badblocks.c| 75 ++++++++++++++++++++++++++++++++++++++++++lib/ext2fs/ext2fs.h| 2 ++2 files changed, 77 insertions(+)lib/ext2fs/badblocks.c +75
-0@@ -56,6 +56,74 @@ static errcode_t make_u32_list(int size, int num, __u32 *list,return 0 ; } +static inline int insert_ok (blk_t *array,int cnt,blk_t new) +{ +return (cnt ==0 || array[cnt -1 ] != new); +} + +/* +* Merge list from src to dest +*/ +static errcode_t merge_u32_list (ext2_u32_list src,ext2_u32_list dest) +{ +errcode_t retval; +int src_count = src->num; +int dest_count = dest->num; +int size = src_count + dest_count; +int size_entry =sizeof (blk_t); +blk_t *array; +blk_t *src_array = src->list; +blk_t *dest_array = dest->list; +int src_index =0 ; +int dest_index =0 ; +int uniq_cnt =0 ; + +if (src->num ==0 ) +return 0 ; + + retval =ext2fs_get_array (size, size_entry, &array); +if (retval) +return retval; + +/* +* It is possible that src list and dest list could be +* duplicated when merging badblocks. +*/ +while (src_index < src_count || dest_index < dest_count) { +if (src_index >= src_count) { +for (; dest_index < dest_count; dest_index++) +if (insert_ok (array, uniq_cnt, dest_array[dest_index])) + array[uniq_cnt++] = dest_array[dest_index]; +break ; + } +if (dest_index >= dest_count) { +for (; src_index < src_count; src_index++) +if (insert_ok (array, uniq_cnt, src_array[src_index])) + array[uniq_cnt++] = src_array[src_index]; +break ; + } +if (src_array[src_index] < dest_array[dest_index]) { +if (insert_ok (array, uniq_cnt, src_array[src_index])) + array[uniq_cnt++] = src_array[src_index]; + src_index++; + }else if (src_array[src_index] > dest_array[dest_index]) { +if (insert_ok (array, uniq_cnt, dest_array[dest_index])) + array[uniq_cnt++] = dest_array[dest_index]; + dest_index++; + }else { +if (insert_ok (array, uniq_cnt, dest_array[dest_index])) + array[uniq_cnt++] = dest_array[dest_index]; + src_index++; + dest_index++; + } + } + +ext2fs_free_mem (&dest->list); + dest->list = array; + dest->num = uniq_cnt; + dest->size = size; +return 0 ; +}/* * This procedure creates an empty u32 list. @@ -91,6 +159,13 @@ errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src, (ext2_u32_list *) dest); } +errcode_t ext2fs_badblocks_merge (ext2_badblocks_list src, +ext2_badblocks_list dest) +{ +return merge_u32_list ((ext2_u32_list ) src, + (ext2_u32_list ) dest); +} +/* * This procedure frees a badblocks list. * lib/ext2fs/ext2fs.h +2
-0@@ -845,6 +845,8 @@ extern int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter,extern void ext2fs_badblocks_list_iterate_end (ext2_badblocks_iterate iter);extern errcode_t ext2fs_badblocks_copy (ext2_badblocks_list src,ext2_badblocks_list *dest); +extern errcode_t ext2fs_badblocks_merge (ext2_badblocks_list src, +ext2_badblocks_list dest);extern int ext2fs_badblocks_equal (ext2_badblocks_list bb1,ext2_badblocks_list bb2);extern int ext2fs_u32_list_count (ext2_u32_list bb);Signature · 1 line
2.37.3
Re: [RFCv1 06/72] dblist: add dblist merge logic
In reply to Ritesh Harjani (IBM)Quoted 10 lines · Ritesh Harjani (IBM)
From: Li Xi <[email protected]>
This adds dblist merge logic.
TODO: Add a unit test for core operations of dblist. Currently there is no such test for this.
Signed-off-by Li Xi <[email protected]>Signed-off-by Ritesh Harjani (IBM) <[email protected]>
Quoted 67 lines
---
lib/ext2fs/dblist.c| 36 ++++++++++++++++++++++++++++++++++++lib/ext2fs/ext2fs.h| 1 +2 files changed, 37 insertions(+)lib/ext2fs/dblist.c +36
-0@@ -119,6 +119,42 @@ errcode_t ext2fs_copy_dblist(ext2_dblist src, ext2_dblist *dest)return 0 ; } +/* +* Merge a directory block list @src to @dest +*/ +errcode_t ext2fs_merge_dblist (ext2_dblist src,ext2_dblist dest) +{ +unsigned long long src_count = src->count; +unsigned long long dest_count = dest->count; +unsigned long long size = src_count + dest_count; +size_t size_entry =sizeof (struct ext2_db_entry2 ); +struct ext2_db_entry2 *array, *array2; +errcode_t retval; + +if (src_count ==0 ) +return 0 ; + +if (src->sorted || (dest->sorted && dest_count !=0 )) +return EINVAL ; + + retval =ext2fs_get_array (size, size_entry, &array); +if (retval) +return retval; + + array2 = array; +memcpy (array, src->list, src_count * size_entry); + array += src_count; +memcpy (array, dest->list, dest_count * size_entry); +ext2fs_free_mem (&dest->list); + + dest->list = array2; + dest->count = src_count + dest_count; + dest->size = size; + dest->sorted =0 ; + +return 0 ; +} +/* * Close a directory block list * lib/ext2fs/ext2fs.h +1
-0@@ -1143,6 +1143,7 @@ extern errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk, int blockcnt);extern errcode_t ext2fs_add_dir_block2 (ext2_dblist dblist,ext2_ino_t ino,blk64_t blk,e2_blkcnt_t blockcnt); +extern errcode_t ext2fs_merge_dblist (ext2_dblist src,ext2_dblist dest);extern void ext2fs_dblist_sort (ext2_dblist dblist,EXT2_QSORT_TYPE (*sortfunc)(const void *,const void *));Signature · 1 line
2.37.3
Re: [RFCv1 08/72] libext2fs: Add bitmaps merge ops
In reply to Ritesh Harjani (IBM)Quoted 8 lines · Ritesh Harjani (IBM)
From: Wang Shilong <[email protected]>
Signed-off-by Li Xi <[email protected]>Signed-off-by Wang Shilong <[email protected]>[Note: splitted rb merge tree logic patch such that we seperate out libext2fs changes from e2fsck specific changes]
Signed-off-by Ritesh Harjani (IBM) <[email protected]>
Quoted 112 lines
---
lib/ext2fs/bitmaps.c | 10 ++++++++++ lib/ext2fs/bmap64.h | 4 ++++ lib/ext2fs/ext2fs.h | 8 ++++++++ lib/ext2fs/gen_bitmap64.c | 29 +++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+)lib/ext2fs/bitmaps.c +10
-0@@ -45,6 +45,16 @@ errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src, {return (ext2fs_copy_generic_bmap (src, dest)); } + +errcode_t ext2fs_merge_bitmap (ext2fs_generic_bitmap src, +ext2fs_generic_bitmap dest, +ext2fs_generic_bitmap dup, +ext2fs_generic_bitmap dup_allowed) +{ +return ext2fs_merge_generic_bmap (src, dest, dup, + dup_allowed); +} +void ext2fs_set_bitmap_padding (ext2fs_generic_bitmap map) {ext2fs_set_generic_bmap_padding (map);lib/ext2fs/bmap64.h +4
-0@@ -72,6 +72,10 @@ struct ext2_bitmap_ops {void (*free_bmap)(ext2fs_generic_bitmap_64 bitmap);errcode_t (*copy_bmap)(ext2fs_generic_bitmap_64 src,ext2fs_generic_bitmap_64 dest); +errcode_t (*merge_bmap)(ext2fs_generic_bitmap_64 src, +ext2fs_generic_bitmap_64 dest, +ext2fs_generic_bitmap_64 dup, +ext2fs_generic_bitmap_64 dup_allowed);errcode_t (*resize_bmap)(ext2fs_generic_bitmap_64 bitmap,__u64 new_end,__u64 new_real_end);lib/ext2fs/ext2fs.h +8
-0@@ -870,6 +870,10 @@ extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap);extern void ext2fs_free_inode_bitmap (ext2fs_inode_bitmap bitmap);extern errcode_t ext2fs_copy_bitmap (ext2fs_generic_bitmap src,ext2fs_generic_bitmap *dest); +extern errcode_t ext2fs_merge_bitmap (ext2fs_generic_bitmap src, +ext2fs_generic_bitmap dest, +ext2fs_generic_bitmap dup, +ext2fs_generic_bitmap dup_allowed);extern errcode_t ext2fs_allocate_block_bitmap (ext2_filsys fs,const char *descr,ext2fs_block_bitmap *ret);@@ -1467,6 +1471,10 @@ void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap);errcode_t ext2fs_resize_generic_bmap (ext2fs_generic_bitmap bmap,__u64 new_end,__u64 new_real_end); +errcode_t ext2fs_merge_generic_bmap (ext2fs_generic_bitmap gen_src, +ext2fs_generic_bitmap gen_dest, +ext2fs_generic_bitmap gen_dup, +ext2fs_generic_bitmap dup_allowed);errcode_t ext2fs_compare_generic_bmap (errcode_t neq,ext2fs_generic_bitmap bm1,ext2fs_generic_bitmap bm2);lib/ext2fs/gen_bitmap64.c +29
-0@@ -346,6 +346,35 @@ errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap gen_src,return 0 ; } +errcode_t ext2fs_merge_generic_bmap (ext2fs_generic_bitmap gen_src, +ext2fs_generic_bitmap gen_dest, +ext2fs_generic_bitmap gen_dup, +ext2fs_generic_bitmap gen_dup_allowed) +{ +ext2fs_generic_bitmap_64 src = (ext2fs_generic_bitmap_64 )gen_src; +ext2fs_generic_bitmap_64 dest = (ext2fs_generic_bitmap_64 )gen_dest; +ext2fs_generic_bitmap_64 dup = (ext2fs_generic_bitmap_64 )gen_dup; +ext2fs_generic_bitmap_64 dup_allowed = (ext2fs_generic_bitmap_64 )gen_dup_allowed; + +if (!src || !dest) +return EINVAL ; + +if (!EXT2FS_IS_64_BITMAP (src) || !EXT2FS_IS_64_BITMAP (dest) || + (dup && !EXT2FS_IS_64_BITMAP (dup)) || + (dup_allowed && !EXT2FS_IS_64_BITMAP (dup_allowed))) +return EINVAL ; + +if (src->bitmap_ops != dest->bitmap_ops || + (dup && src->bitmap_ops != dup->bitmap_ops) || + (dup_allowed && src->bitmap_ops != dup_allowed->bitmap_ops)) +return EINVAL ; + +if (src->bitmap_ops->merge_bmap ==NULL ) +return EOPNOTSUPP ; + +return src->bitmap_ops->merge_bmap (src, dest, dup, dup_allowed); +} +errcode_t ext2fs_resize_generic_bmap (ext2fs_generic_bitmap gen_bmap,__u64 new_end,__u64 new_real_end)Signature · 1 line
2.37.3
Re: [RFCv1 20/72] libext2fs: avoid too much memory allocation in case fs_num_threads
In reply to Ritesh Harjani (IBM)Quoted 7 lines · Ritesh Harjani (IBM)
From: Wang Shilong <[email protected]>
e2fsck init memory according to filesystem inodes/dir numbers recorded in the superblock, this should be aware of filesystem number of threads, otherwise, oom can happen.
Quoted 5 lines
So in case of
fs->fs_num_threads, this patch controls the amount of memory consumed for running multiple threads in e2fsck.Signed-off-by Wang Shilong <[email protected]>Signed-off-by Ritesh Harjani (IBM) <[email protected]>
Quoted 43 lines
---
lib/ext2fs/dblist.c| 2 ++lib/ext2fs/icount.c| 4 ++++2 files changed, 6 insertions(+)lib/ext2fs/dblist.c +2
-0@@ -58,6 +58,8 @@ static errcode_t make_dblist(ext2_filsys fs, ext2_ino_t size,if (retval) goto cleanup; dblist->size = (num_dirs *2 ) +12 ; +if (fs->fs_num_threads) + dblist->size /= fs->fs_num_threads; } len = (size_t )sizeof (struct ext2_db_entry2 ) * dblist->size; dblist->count = count;lib/ext2fs/icount.c +4
-0@@ -237,6 +237,8 @@ errcode_t ext2fs_create_icount_tdb(ext2_filsys fs EXT2FS_NO_TDB_UNUSED,* value. */ num_inodes = fs->super->s_inodes_count - fs->super->s_free_inodes_count; +if (fs->fs_num_threads) + num_inodes /= fs->fs_num_threads; icount->tdb =tdb_open (fn, num_inodes,TDB_NOLOCK |TDB_NOSYNC ,O_RDWR |O_CREAT |O_TRUNC ,0600 );@@ -288,6 +290,8 @@ errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size,if (retval) goto errout; icount->size += fs->super->s_inodes_count /50 ; +if (fs->fs_num_threads) + icount->size /= fs->fs_num_threads; } bytes = (size_t ) (icount->size *sizeof (struct ext2_icount_el ));Signature · 1 line
2.37.3
Re: [RFCv1 09/72] libext2fs: Add flush cleanup API
In reply to Ritesh Harjani (IBM)Quoted 6 lines · Ritesh Harjani (IBM)
From: Li Xi <[email protected]>
Signed-off-by Li Xi <[email protected]>Signed-off-by Wang Shilong <[email protected]>Signed-off-by Ritesh Harjani (IBM) <[email protected]>
Quoted 130 lines
---
lib/ext2fs/ext2_io.h | 2 ++ lib/ext2fs/undo_io.c | 19 +++++++++++++++++++ lib/ext2fs/unix_io.c | 24 +++++++++++++++++++++--- 3 files changed, 42 insertions(+), 3 deletions(-)lib/ext2fs/ext2_io.h +2
-0@@ -82,6 +82,7 @@ struct struct_io_manager {errcode_t (*write_blk)(io_channel channel,unsigned long block,int count,const void *data);errcode_t (*flush)(io_channel channel); +errcode_t (*flush_cleanup)(io_channel channel);errcode_t (*write_byte)(io_channel channel,unsigned long offset,int count,const void *data); errcode_t (*set_option)(io_channel channel, const char *option,@@ -116,6 +117,7 @@ struct struct_io_manager {#define io_channel_read_blk (c,b,n,d) ((c)->manager->read_blk((c),b,n,d))#define io_channel_write_blk (c,b,n,d) ((c)->manager->write_blk((c),b,n,d))#define io_channel_flush (c) ((c)->manager->flush((c))) +#define io_channel_flush_cleanup (c) ((c)->manager->flush_cleanup((c)))#define io_channel_bumpcount (c) ((c)->refcount++)/* io_manager.c */ lib/ext2fs/undo_io.c +19
-0@@ -1024,6 +1024,24 @@ static errcode_t undo_flush(io_channel channel)return retval; } +/* +* Flush data buffers to disk and cleanup the cache. +*/ +static errcode_t undo_flush_cleanup (io_channel channel) +{ +errcode_t retval =0 ; +struct undo_private_data *data; + +EXT2_CHECK_MAGIC (channel,EXT2_ET_MAGIC_IO_CHANNEL ); + data = (struct undo_private_data *) channel->private_data; +EXT2_CHECK_MAGIC (data,EXT2_ET_MAGIC_UNIX_IO_CHANNEL ); + +if (data->real) + retval =io_channel_flush_cleanup (data->real); + +return retval; +} +static errcode_t undo_set_option (io_channel channel,const char *option,const char *arg) {@@ -1095,6 +1113,7 @@ static struct struct_io_manager struct_undo_manager = { .read_blk = undo_read_blk, .write_blk = undo_write_blk, .flush = undo_flush, + .flush_cleanup = undo_flush_cleanup, .write_byte = undo_write_byte, .set_option = undo_set_option, .get_stats = undo_get_stats,lib/ext2fs/unix_io.c +21
-3@@ -1173,9 +1173,9 @@ static errcode_t unix_write_byte(io_channel channel, unsigned long offset, }/* -* Flush data buffers to disk. +* Flush data buffers to disk and invalidate cache if needed */ -static errcode_t unix_flush (io_channel channel) +static errcode_t _unix_flush (io_channel channel,int invalidate) {struct unix_private_data *data;errcode_t retval =0 ;@@ -1185,7 +1185,7 @@ static errcode_t unix_flush(io_channel channel)EXT2_CHECK_MAGIC (data,EXT2_ET_MAGIC_UNIX_IO_CHANNEL );#ifndef NO_IO_CACHE - retval =flush_cached_blocks (channel, data,0 ); + retval =flush_cached_blocks (channel, data, invalidate);#endif #ifdef HAVE_FSYNC if (!retval &&fsync (data->dev) !=0 )@@ -1194,6 +1194,22 @@ static errcode_t unix_flush(io_channel channel)return retval; } +/* +* Flush data buffers to disk. +*/ +static errcode_t unix_flush (io_channel channel) +{ +return _unix_flush (channel,0 ); +} + +/* +* Flush data buffers to disk and invalidate cache. +*/ +static errcode_t unix_flush_cleanup (io_channel channel) +{ +return _unix_flush (channel,1 ); +} +static errcode_t unix_set_option (io_channel channel,const char *option,const char *arg) {@@ -1383,6 +1399,7 @@ static struct struct_io_manager struct_unix_manager = { .discard = unix_discard, .cache_readahead = unix_cache_readahead, .zeroout = unix_zeroout, + .flush_cleanup = unix_flush_cleanup, };io_manager unix_io_manager = &struct_unix_manager;@@ -1404,6 +1421,7 @@ static struct struct_io_manager struct_unixfd_manager = { .discard = unix_discard, .cache_readahead = unix_cache_readahead, .zeroout = unix_zeroout, + .flush_cleanup = unix_flush_cleanup, };io_manager unixfd_io_manager = &struct_unixfd_manager;Signature · 1 line
2.37.3
Re: [RFCv1 10/72] libext2fs: merge icounts after thread finishes
In reply to Ritesh Harjani (IBM)Quoted 10 lines · Ritesh Harjani (IBM)
From: Li Xi <[email protected]>
Merge
inode_countandinode_link_infoproperly after threads finish.Signed-off-by Li Xi <[email protected]>Signed-off-by Wang Shilong <[email protected]>[Note: splitted the patch to seperate libext2fs changes from e2fsck]Signed-off-by Ritesh Harjani (IBM) <[email protected]>
Quoted 141 lines
---
lib/ext2fs/ext2fs.h| 1 +lib/ext2fs/icount.c| 103 ++++++++++++++++++++++++++++++++++++++++++++2 files changed, 104 insertions(+)lib/ext2fs/ext2fs.h +1
-0@@ -1546,6 +1546,7 @@ extern errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret);extern errcode_t ext2fs_icount_store (ext2_icount_t icount,ext2_ino_t ino,__u16 count); +extern errcode_t ext2fs_icount_merge (ext2_icount_t src,ext2_icount_t dest);extern ext2_ino_t ext2fs_get_icount_size (ext2_icount_t icount);errcode_t ext2fs_icount_validate (ext2_icount_t icount,FILE *);lib/ext2fs/icount.c +103
-0@@ -13,6 +13,7 @@#if HAVE_UNISTD_H #include <unistd.h> #endif +#include <assert.h> #include <string.h> #include <stdio.h> #include <sys/stat.h> @@ -701,6 +702,108 @@ errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,return 0 ; } +errcode_t ext2fs_icount_merge_full_map (ext2_icount_t src,ext2_icount_t dest) +{ +/* TODO: add the support for full map */ +return EOPNOTSUPP ; +} + +errcode_t ext2fs_icount_merge_el (ext2_icount_t src,ext2_icount_t dest) +{ +int src_count = src->count; +int dest_count = dest->count; +int size = src_count + dest_count; +int size_entry =sizeof (struct ext2_icount_el ); +struct ext2_icount_el *array; +struct ext2_icount_el *array_ptr; +struct ext2_icount_el *src_array = src->list; +struct ext2_icount_el *dest_array = dest->list; +int src_index =0 ; +int dest_index =0 ; +errcode_t retval; + +if (src_count ==0 ) +return 0 ; + + retval =ext2fs_get_array (size, size_entry, &array); +if (retval) +return retval; + + array_ptr = array; +/* +* This can be improved by binary search and memcpy, but codes +* would be more complex. And if number of bad blocks is small, +* the optimization won't improve performance a lot. +*/ +while (src_index < src_count || dest_index < dest_count) { +if (src_index >= src_count) { +memcpy (array_ptr, &dest_array[dest_index], + (dest_count - dest_index) * size_entry); +break ; + } +if (dest_index >= dest_count) { +memcpy (array_ptr, &src_array[src_index], + (src_count - src_index) * size_entry); +break ; + } +if (src_array[src_index].ino < dest_array[dest_index].ino) { + *array_ptr = src_array[src_index]; + src_index++; + }else { +assert (src_array[src_index].ino > + dest_array[dest_index].ino); + *array_ptr = dest_array[dest_index]; + dest_index++; + } + array_ptr++; + } + +ext2fs_free_mem (&dest->list); + dest->list = array; + dest->count = src_count + dest_count; + dest->size = size; + dest->last_lookup =NULL ; +return 0 ; +} + +errcode_t ext2fs_icount_merge (ext2_icount_t src,ext2_icount_t dest) +{ +errcode_t retval; + +if (src->fullmap && !dest->fullmap) +return EINVAL ; + +if (!src->fullmap && dest->fullmap) +return EINVAL ; + +if (src->multiple && !dest->multiple) +return EINVAL ; + +if (!src->multiple && dest->multiple) +return EINVAL ; + +if (src->fullmap) +return ext2fs_icount_merge_full_map (src, dest); + + retval =ext2fs_merge_bitmap (src->single, dest->single,NULL , +NULL ); +if (retval) +return retval; + +if (src->multiple) { + retval =ext2fs_merge_bitmap (src->multiple, dest->multiple, +NULL ,NULL ); +if (retval) +return retval; + } + + retval =ext2fs_icount_merge_el (src, dest); +if (retval) +return retval; + +return 0 ; +} +ext2_ino_t ext2fs_get_icount_size (ext2_icount_t icount) {if (!icount || icount->magic !=EXT2_ET_MAGIC_ICOUNT )Signature · 1 line
2.37.3
Re: [RFCv1 11/72] libext2fs: merge quota context after threads finish
In reply to Ritesh Harjani (IBM)Quoted 9 lines · Ritesh Harjani (IBM)
From: Wang Shilong <[email protected]>
Every threads calculate its own quota accounting,
merge them after threads finish.Signed-off-by Wang Shilong <[email protected]>[Note: splitted the patch to seperate libext2fs changes from e2fsck]Signed-off-by Ritesh Harjani (IBM) <[email protected]>
Quoted 79 lines
---
lib/support/mkquota.c| 39 +++++++++++++++++++++++++++++++++++++++lib/support/quotaio.h| 3 +++2 files changed, 42 insertions(+)lib/support/mkquota.c +39
-0@@ -618,6 +618,45 @@ out:return err; } +static errcode_t merge_usage (dict_t *dest,dict_t *src) +{ +dnode_t *n; +struct dquot *src_dq, *dest_dq; + +for (n =dict_first (src); n; n =dict_next (src, n)) { + src_dq =dnode_get (n); +if (!src_dq) +continue ; + dest_dq =get_dq (dest, src_dq->dq_id); +if (dest_dq ==NULL ) +return -ENOMEM ; + dest_dq->dq_dqb.dqb_curspace += src_dq->dq_dqb.dqb_curspace; + dest_dq->dq_dqb.dqb_curinodes += src_dq->dq_dqb.dqb_curinodes; + } + +return 0 ; +} + + +errcode_t quota_merge_and_update_usage (quota_ctx_t dest_qctx, +quota_ctx_t src_qctx) +{ +dict_t *dict; +enum quota_type qtype; +errcode_t retval =0 ; + +for (qtype =0 ; qtype <MAXQUOTAS ; qtype++) { + dict = src_qctx->quota_dict[qtype]; +if (!dict) +continue ; + retval =merge_usage (dest_qctx->quota_dict[qtype], dict); +if (retval) +break ; + } + +return retval; +} +/* * Compares the measured quota in qctx->quota_dict with that in the quota inode * on disk and updates the limits in qctx->quota_dict. 'usage_inconsistent' is lib/support/quotaio.h +1
-0@@ -40,6 +40,7 @@#include "ext2fs/ext2_fs.h" #include "ext2fs/ext2fs.h" #include "dqblk_v2.h" +#include "support/dict.h" typedef
int64_tqsize_t; /* Type in which we store size limitations */lib/support/quotaio.h +2
-0@@ -236,6 +237,8 @@ int quota_file_exists(ext2_filsys fs, enum quota_type qtype);void quota_set_sb_inum (ext2_filsys fs,ext2_ino_t ino,enum quota_type qtype);errcode_t quota_compare_and_update (quota_ctx_t qctx,enum quota_type qtype,int *usage_inconsistent); +errcode_t quota_merge_and_update_usage (quota_ctx_t dest_qctx, +quota_ctx_t src_qctx);int parse_quota_opts (const char *opts,int (*func)(char *));/* parse_qtype.c */ Signature · 1 line
2.37.3
Re: [RFCv1 12/72] libext2fs: dupfs: Add fs clone & merge api
In reply to Ritesh Harjani (IBM)Quoted 51 lines · Ritesh Harjani (IBM)
From: Saranya Muruganandam <[email protected]>
This patch mainly adds "parent" & "
clone_flags" member inext2_filsysstruct for enabling multi-threading. Based on what CLONE flags will be passed from the client of libext2fs down toext2fs_clone_fs(), those structures/bitmaps will be cloned (thread-aware child copy) and rest will be shared with the parent fs.The same flags will also help to merge those cloned bitmap structures back into the parent bitmaps when
ext2fs_merge_fs()will be called with childfs struct.Signed-off-by Saranya Muruganandam <[email protected]>Signed-off-by Ritesh Harjani (IBM) <[email protected]>---
lib/ext2fs/dupfs.c| 183 ++++++++++++++++++++++++++++++++++++++++++++lib/ext2fs/ext2fs.h| 23 ++++++2 files changed, 206 insertions(+)lib/ext2fs/dupfs.c +16
-0@@ -14,8 +14,12 @@#if HAVE_UNISTD_H #include <unistd.h> #endif +#if HAVE_PTHREAD_H +#include <pthread.h> +#endif #include <time.h> #include <string.h> +#include <assert.h> #include "ext2_fs.h" #include "ext2fsP.h" @@ -120,3 +124,182 @@ errout: } +#ifdef HAVE_PTHREAD +errcode_t ext2fs_clone_fs (ext2_filsys fs,ext2_filsys *dest,unsigned int flags) +{ +errcode_t retval; +ext2_filsys childfs; + +EXT2_CHECK_MAGIC (fs,EXT2_ET_MAGIC_EXT2FS_FILSYS ); + + retval =ext2fs_get_mem (sizeof (struct struct_ext2_filsys ), &childfs); +if (retval) +return retval; +
lib/ext2fs/dupfs.c errout: · line 148
Quoted 10 lines
lib/ext2fs/dupfs.c +10
-0+/* make an exact copy implying lists and memory structures are shared */ +memcpy (childfs, fs,sizeof (struct struct_ext2_filsys )); + childfs->inode_map =NULL ; + childfs->block_map =NULL ; + childfs->badblocks =NULL ; + childfs->dblist =NULL ; + +pthread_mutex_lock (&fs->refcount_mutex); + fs->refcount++; +pthread_mutex_unlock (&fs->refcount_mutex);
The locking her doesn't make sense. Why is the mutex only protecting the "refcount", and not the rest of the fields in fs?
It would make more sense to hold the mutex over the whole copy process, from up before the memcpy(), until down after the last structure is cloned. Otherwise, once fs has been cloned once and given to another thread it would be possible for them to change these structures.
Quoted 19 lines
lib/ext2fs/dupfs.c +19
-0+if ((flags &EXT2FS_CLONE_INODE ) && fs->inode_map) { + retval =ext2fs_copy_bitmap (fs->inode_map, &childfs->inode_map); +if (retval) +return retval; + childfs->inode_map->fs = childfs; + } + +if ((flags &EXT2FS_CLONE_BLOCK ) && fs->block_map) { + retval =ext2fs_copy_bitmap (fs->block_map, &childfs->block_map); +if (retval) +return retval; + childfs->block_map->fs = childfs; + } + +if ((flags &EXT2FS_CLONE_BADBLOCKS ) && fs->badblocks) { + retval =ext2fs_badblocks_copy (fs->badblocks, &childfs->badblocks); +if (retval) +return retval; + }
lib/ext2fs/dupfs.c errout: · line 178
Quoted 10 lines
lib/ext2fs/dupfs.c +10
-0+ +if ((flags &EXT2FS_CLONE_DBLIST ) && fs->dblist) { + retval =ext2fs_copy_dblist (fs->dblist, &childfs->dblist); +if (retval) +return retval; + childfs->dblist->fs = childfs; + } + +/* icache when NULL will be rebuilt if needed */ + childfs->icache =NULL ;
This should be up where the other NULL values are set.
Quoted 19 lines
lib/ext2fs/dupfs.c +19
-0+ + childfs->clone_flags = flags; + childfs->parent = fs; + *dest = childfs; + +return 0 ; +} + +errcode_t ext2fs_merge_fs (ext2_filsys *thread_fs) +{ +ext2_filsys fs = *thread_fs; +errcode_t retval =0 ; +ext2_filsys dest = fs->parent; +ext2_filsys src = fs; +unsigned int flags = fs->clone_flags; +struct ext2_inode_cache *icache; +io_channel dest_io; +io_channel dest_image_io; +ext2fs_inode_bitmap inode_map;
lib/ext2fs/dupfs.c errout: · line 207
Quoted 10 lines
lib/ext2fs/dupfs.c +10
-0+ext2fs_block_bitmap block_map; +ext2_badblocks_list badblocks; +ext2_dblist dblist; +void *priv_data; +int fsflags; + +pthread_mutex_lock (&fs->refcount_mutex); + fs->refcount--; +assert (fs->refcount >=0 ); +pthread_mutex_unlock (&fs->refcount_mutex);
Same here. The mutex should be held over the whole copy process.
Cheers, Andreas
Quoted 148 lines
lib/ext2fs/dupfs.c +97
-0+ icache = dest->icache; + dest_io = dest->io; + dest_image_io = dest->image_io; + inode_map = dest->inode_map; + block_map = dest->block_map; + badblocks = dest->badblocks; + dblist = dest->dblist; + priv_data = dest->priv_data; + fsflags = dest->flags; + +memcpy (dest, src,sizeof (struct struct_ext2_filsys )); + + dest->io = dest_io; + dest->image_io = dest_image_io; + dest->icache = icache; + dest->inode_map = inode_map; + dest->block_map = block_map; + dest->badblocks = badblocks; + dest->dblist = dblist; + dest->priv_data = priv_data; +if (dest->dblist) + dest->dblist->fs = dest; + dest->flags = src->flags | fsflags; +if (!(src->flags &EXT2_FLAG_VALID ) || !(dest->flags &EXT2_FLAG_VALID )) +ext2fs_unmark_valid (dest); + +if ((flags &EXT2FS_CLONE_INODE ) && src->inode_map) { +if (dest->inode_map ==NULL ) { + dest->inode_map = src->inode_map; + src->inode_map =NULL ; + }else { + retval =ext2fs_merge_bitmap (src->inode_map, dest->inode_map,NULL ,NULL ); +if (retval) + goto out; + } + dest->inode_map->fs = dest; + } + +if ((flags &EXT2FS_CLONE_BLOCK ) && src->block_map) { +if (dest->block_map ==NULL ) { + dest->block_map = src->block_map; + src->block_map =NULL ; + }else { + retval =ext2fs_merge_bitmap (src->block_map, dest->block_map,NULL ,NULL ); +if (retval) + goto out; + } + dest->block_map->fs = dest; + } + +if ((flags &EXT2FS_CLONE_BADBLOCKS ) && src->badblocks) { +if (dest->badblocks ==NULL ) + retval =ext2fs_badblocks_copy (src->badblocks, &dest->badblocks); +else + retval =ext2fs_badblocks_merge (src->badblocks, dest->badblocks); +if (retval) + goto out; + } + +if ((flags &EXT2FS_CLONE_DBLIST ) && src->dblist) { +if (dest->dblist ==NULL ) { + dest->dblist = src->dblist; + src->dblist =NULL ; + }else { + retval =ext2fs_merge_dblist (src->dblist, dest->dblist); +if (retval) + goto out; + } + dest->dblist->fs = dest; + } + +if (src->icache) { +ext2fs_free_inode_cache (src->icache); + src->icache =NULL ; + } + +out: +if (src->io) +io_channel_close (src->io); + +if ((flags &EXT2FS_CLONE_INODE ) && src->inode_map) +ext2fs_free_generic_bmap (src->inode_map); +if ((flags &EXT2FS_CLONE_BLOCK ) && src->block_map) +ext2fs_free_generic_bmap (src->block_map); +if ((flags &EXT2FS_CLONE_BADBLOCKS ) && src->badblocks) +ext2fs_badblocks_list_free (src->badblocks); +if ((flags &EXT2FS_CLONE_DBLIST ) && src->dblist) { +ext2fs_free_dblist (src->dblist); + src->dblist =NULL ; + } + +ext2fs_free_mem (&src); + *thread_fs =NULL ; + + return retval; +} +#endif lib/ext2fs/ext2fs.h +23
-0@@ -12,6 +12,10 @@#ifndef _EXT2FS_EXT2FS_H#define _EXT2FS_EXT2FS_H +#ifdef HAVE_PTHREAD_H +#include <pthread.h> +#endif +#ifdef __GNUC__#define EXT2FS_ATTR (x) __attribute__(x)#else @@ -331,6 +335,13 @@ struct struct_ext2_filsys {struct ext2fs_hashmap * block_sha_map;const struct ext2fs_nls_table *encoding; + +#ifdef HAVE_PTHREAD +struct struct_ext2_filsys *parent; +size_t refcount; +pthread_mutex_t refcount_mutex; +unsigned int clone_flags; +#endif };#if EXT2_FLAT_INCLUDES @@ -1057,6 +1068,18 @@ extern errcode_t ext2fs_move_blocks(ext2_filsys fs,/* check_desc.c */ extern errcode_t ext2fs_check_desc (ext2_filsys fs); +#ifdef HAVE_PTHREAD +/* flags for ext2fs_clone_fs */ +#define EXT2FS_CLONE_BLOCK 0x0001 +#define EXT2FS_CLONE_INODE 0x0002 +#define EXT2FS_CLONE_BADBLOCKS 0x0004 +#define EXT2FS_CLONE_DBLIST 0x0008 + +extern errcode_t ext2fs_clone_fs (ext2_filsys fs,ext2_filsys *dest, +unsigned int flags); +extern errcode_t ext2fs_merge_fs (ext2_filsys *fs); +#endif +/* closefs.c */ extern errcode_t ext2fs_close (ext2_filsys fs);extern errcode_t ext2fs_close2 (ext2_filsys fs,int flags);Signature · 1 line
2.37.3
Re: [RFCv1 01/72] e2fsck: Fix unbalanced mutex unlock for BOUNCE_MTX
In reply to Andreas DilgerQuoted 70 lines · Andreas Dilger
Quoted 35 lines · Ritesh Harjani (IBM)
Quoted 12 lines · Andreas Dilger
Quoted 12 lines · Ritesh Harjani (IBM)
f_crashdisktest failed with UNIX_IO_FORCE_BOUNCE=yes due to unbalanced mutex unlock in below path.This patch fixes it.
Signed-off-by Ritesh Harjani (IBM) <[email protected]>---
lib/ext2fs/unix_io.c| 1 -1 file changed, 1 deletion(-)Quoted 12 lines
lib/ext2fs/unix_io.c bounce_read: · line 308
Quoted 9 lines
lib/ext2fs/unix_io.c +0
-1@@ -305,7 +305,6 @@ bounce_read:while (size >0 ) { actual =read (data->dev, data->bounce, align_size);if (actual != align_size) { -mutex_unlock (data,BOUNCE_MTX );This patch doesn't show enough context, but AFAIK this is jumping before
mutex_down()is called, so this *should* be correct as is?Thanks for the review, Andreas.
Yeah, the patch diff above is not sufficient since it doesn't share enuf context.
But essentially when "actual" is not equal to "align_size", then in this if condition it goes to label "short_read:", which always gotoerror_unlock, where we anyways callmutex_unlock()Quoted 3 lines
Looking at a lot of labels in this function, this definitely looks like something which can be cleaned up ("
raw_read_blk()").
I will add that to my list of todos.You are correct, and it means this code is just not very clear to the reader. I think it would make more sense to move the "
short_read:" label to the end of the code:actual = read(...); if (actual != size) goto error_short_read; goto success_unlock; : actual = read(...); if (actual != align_size) { actual = really_read; buf -= really_read; size += really_read; goto error_short_read; } : success_unlock: mutex_unlock(...); return 0;
error_short_read:if (actual < 0) { retval = errno; actual = 0; } else { retval = EXT2_ET_SHORT_READ; } error_unlock: mutex_unlock(...);
Quoted 2 lines
That way the code follows the normal error handling convention and is less likely to be surprising to the reader.
Yes, you are right. I will do the change in the next rev.
-ritesh