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
Re: [RFCv1 01/72] e2fsck: Fix unbalanced mutex unlock for BOUNCE_MTX
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 01/72] e2fsck: Fix unbalanced mutex unlock for BOUNCE_MTX
Quoted 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 01/72] e2fsck: Fix unbalanced mutex unlock for BOUNCE_MTX
Quoted 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
Theodore Ts'o
AppliedRe: [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]>
Applied, thanks.
- Ted
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
Re: [RFCv1 02/72] gen_bitmaps: Fix ext2fs_compare_generic_bmap/bitmap logic
lib/ext2fs/gen_bitmap.c errcode_t ext2fs_compare_generic_bitmap(errcode_t magic, errcode_t neq,
Quoted 17 lines · 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.Signed-off-by Ritesh Harjani (IBM) <[email protected]>---
lib/ext2fs/gen_bitmap.c| 9 ++++++---lib/ext2fs/gen_bitmap64.c| 10 +++++++---2 files changed, 13 insertions(+), 6 deletions(-)lib/ext2fs/gen_bitmap.c +0
-0@@ -385,10 +385,13 @@ errcode_t ext2fs_compare_generic_bitmap(errcode_t magic, errcode_t neq,
if ((bm1->start != bm2->start) ||
(bm1->end != bm2->end) ||
(memcmp(bm1->bitmap, bm2->bitmap,lib/ext2fs/gen_bitmap.c errcode_t ext2fs_compare_generic_bitmap(errcode_t magic, errcode_t neq, · line 388
Quoted 4 lines
lib/ext2fs/gen_bitmap.c +0
-1(size_t) (bm1->end - bm1->start)/8)))return neq; -for (i = bm1->end - ((bm1->end - bm1->start) %8 ); i <= bm1->end; i++)
On first review it appears that this is only comparing at most the last 7 bits before "end", which appears to be wrong. However, if you include the context earlier in the function (which I've added above), it is using memcmp() to compare the majority of the bitmaps in byte-wise order, so this is only needs to compare the remaining bits, and doing the full bitwise scan is much less efficient.
I was going to say that the "start" value needs to be added to the bitmap offset for the comparison, but I don't think that is correct either. Looking at the code (and thinking about it some more), it doesn't make sense to allocate space for bits before "start", so this must be a virtual offset, and the *actual* bits are always starting at "bitmap", so the above code is correct, AFAICS.
In summary, I don't think this patch will introduce a visible defect, but it makes the comparisons orders of magnitude less efficient when comparing each bit individually instead of using memcmp() that is likely hardware accelerated.
It may well be that the calling convention of this code is such that it is always called with end=byte-aligned value so this code is never used, but that doesn't mean it shouldn't be coded properly, in case that isn't true in the future.
lib/ext2fs/gen_bitmap.c errcode_t ext2fs_compare_generic_bitmap(errcode_t magic, errcode_t neq, · line 391
Quoted 6 lines
lib/ext2fs/gen_bitmap.c +4
-2-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);
Strictly speaking, the !! here is not needed, and ! is enough for comparing the inequality of the two values. However, this is only used for 0-7 bits and isn't performance critical since the memcmp() does the heavy lifting.
lib/ext2fs/gen_bitmap64.c errcode_t ext2fs_compare_generic_bmap(errcode_t neq, · line 629
Quoted 12 lines
lib/ext2fs/gen_bitmap.c +2
-0+if (ret1 != ret2)return neq; + }return 0 ; }lib/ext2fs/gen_bitmap64.c +0
-0@@ -629,10 +629,14 @@ errcode_t ext2fs_compare_generic_bmap(errcode_t neq, (bm1->end != bm2->end))
Conversely, *this* version of the function is *not* doing the memcmp() of the bulk of the bitmap contents, so it would appear to have a bug that the patch fixes, but in a very slow manner. It would be better to use memcmp().
lib/ext2fs/gen_bitmap64.c errcode_t ext2fs_compare_generic_bmap(errcode_t neq, · line 635
Quoted 9 lines
lib/ext2fs/gen_bitmap64.c +4
-3return 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);
Cheers, Andreas
Re: [RFCv1 02/72] gen_bitmaps: Fix ext2fs_compare_generic_bmap/bitmap logic
Quoted 10 lines · Andreas Dilger
Quoted 9 lines · 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.Signed-off-by Ritesh Harjani (IBM) <[email protected]>---
lib/ext2fs/gen_bitmap.c| 9 ++++++---
The gen_bitmap.c file supports only the original 32-bit bitmaps, so there is not rbtree bitmap. That's why using memcmp is safe, and as near as I can tell, no changes are needed for the lib/ext2fs/gen_bitmap.c
Quoted 10 lines
lib/ext2fs/gen_bitmap64.c errcode_t ext2fs_compare_generic_bmap(errcode_t neq, · line 629
Quoted 6 lines
lib/ext2fs/gen_bitmap64.c +0
-0@@ -629,10 +629,14 @@ errcode_t ext2fs_compare_generic_bmap(errcode_t neq, (bm1->end != bm2->end))Conversely, *this* version of the function is *not* doing the
memcmp()of the bulk of the bitmap contents, so it would appear to have a bug that the patch fixes, but in a very slow manner. It would be better to usememcmp().
This is where we have a problem, and the reason why we can't use memcmp is because in the case where the bitmap is really encoded using an rbtree, a memcmp isn't applicable.
We *could* extract the bitmap into a bitarray, but that would require allocating memory, and in the case of a very large file system/bitmap, especially when running on a 32-bit NAS box, we might not be able to *afford* to allocate that much memory (or it might not even be addressable :-).
So yes, we need a fix here, and yes, comparing bit by bit is very slow. Fortunately, from what I can tell, no one is actually calling this function, which is why no once noticed that the 64-bit compare bitmap fucntion was totally hosed.
So applying Ritesh's fix here makes sense, since it at least fixes the obvious problems. In the long term, we should probably add proper unit regression tests so can test whether or not this function is actually working correctly, and if we *want* a faster version of it, we could do something faster in the case where both bitmaps are the same type (e.g., both bitarrays or both rbtrees), and if they could do something where we look for "runs" where all of the bits are all set or not set, and then compare that against the other bitmap, etc. But given that we don't have anyusers of this function any more (we used to, but it disappeared when we optimzied e2fsck's pass5 implementation), that's probably not an urgent fix.
- Ted
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
Re: [RFCv1 03/72] blkmap64_ba: Add common helper for bits size calculation
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
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
Re: [RFCv1 04/72] badblocks: Remove unused badblocks_flags
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
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
Re: [RFCv1 05/72] badblocks: Add badblocks merge logic
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
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
Re: [RFCv1 06/72] dblist: add dblist merge logic
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
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
Re: [RFCv1 08/72] libext2fs: Add bitmaps merge ops
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
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
Re: [RFCv1 09/72] libext2fs: Add flush cleanup API
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
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
Re: [RFCv1 10/72] libext2fs: merge icounts after thread finishes
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
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
Re: [RFCv1 11/72] libext2fs: merge quota context after threads finish
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
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
Re: [RFCv1 12/72] libext2fs: dupfs: Add fs clone & merge api
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 12/72] libext2fs: dupfs: Add fs clone & merge api
Quoted 66 lines · Andreas Dilger
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?
Quoted 4 lines
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.
Ok, so there are two things here. Let's first discuss it from the e2fsck perspective. ext2fs_clone_fs() is called in the thread prepare for each thread sequentially. Also what we are really trying to do here is copy the ext2_filsys source fs and then all threads will work on their cloned "childfs".
So we don't require any locking, because even when threads will start running, they will only modify their childfs.
Now.. let's see it from the libext2fs API perspective. So will there be any need for locking for any other client which might use ext2fs_clone_fs()? Because the general pthread programming would be like :
start():
for (t = 0; t < num_threads; t++) {
clone_contexts() -> ext2fs_clone_fs()
pthread_run()
<..>
}finish():
for (t = 0; t < num_threads; t++) {
pthread_join()
merge_contexts() -> ext2fs_merge_fs()
}So why we don't require any locking here, right? Unless ofcourse start() phase can also be called in parallel. But that won't be true no.
Quoted 24 lines
Quoted 24 lines
lib/ext2fs/dupfs.c +23
-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; + } + +if ((flags &EXT2FS_CLONE_DBLIST ) && fs->dblist) { + retval =ext2fs_copy_dblist (fs->dblist, &childfs->dblist); +if (retval)
Quoted 8 lines
lib/ext2fs/dupfs.c errout: · line 178
Quoted 6 lines
lib/ext2fs/dupfs.c +6
-0+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.
ok.
Quoted 24 lines
Quoted 24 lines
lib/ext2fs/dupfs.c +23
-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; +ext2fs_block_bitmap block_map; +ext2_badblocks_list badblocks; +ext2_dblist dblist; +void *priv_data;
Quoted 8 lines
lib/ext2fs/dupfs.c errout: · line 207
Quoted 6 lines
lib/ext2fs/dupfs.c +6
-0+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.
Again same discussion as above. We don't need to have a lock here, because the ext2fs_merge_fs() will happen post pthread_join() for each thread.
-ritesh
Quoted 152 lines
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
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
Re: [RFCv1 13/72] tst_badblocks: Add unit test to verify badblocks list merge api
Quoted 5 lines · Ritesh Harjani (IBM)
Add unit test to verify badblocks list merge api i.e.
ext2fs_badblocks_merge()Signed-off-by Ritesh Harjani (IBM) <[email protected]>
Quoted 103 lines
---
lib/ext2fs/tst_badblocks.c| 61 ++++++++++++++++++++++++++++++++++++--1 file changed, 59 insertions(+), 2 deletions(-)lib/ext2fs/tst_badblocks.c +59
-3@@ -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; --
Quoted 2 lines
2.37.3
Cheers, Andreas
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
Re: [RFCv1 14/72] tst_bitmaps_standalone: Add copy and merge bitmaps test
Quoted 4 lines · Ritesh Harjani (IBM)
This adds a basic copy and merge api test for rbtree bitmap type.
Signed-off-by Ritesh Harjani (IBM) <[email protected]>
Thanks for adding this test. It looks like it is only testing the default rbtree bitmap type. It would be good to also add a test for regular bitmaps.
Quoted 276 lines
---
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.clib/ext2fs/Makefile.in +8
-2@@ -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)lib/ext2fs/Makefile.in +2
-1@@ -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_standaloneinstalldirs::
$(E) " MKDIR_P $(libdir) $(includedir)/ext2fs"lib/ext2fs/Makefile.in +0
-0@@ -581,7 +588,7 @@ install:: all $(HFILES) $(HFILES_IN) installdirs ext2fs.pcuninstall::
$(RM) -f $(DESTDIR)$(libdir)/libext2fs.a \ $(DESTDIR)$(pkgconfigdir)/ext2fs.pclib/ext2fs/Makefile.in +1
-1- $(RM) -rf $(DESTDIR)$(includedir)/ext2fs + $(RM) -rf $(DESTDIR)$(includedir)/ext2fsclean::
$(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* \lib/ext2fs/Makefile.in +8
-2@@ -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
-1@@ -0,0 +1,170 @@ +#include "config.h" +#include <stdio.h> +#include <string.h> +#include <assert.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <fcntl.h> +#include <time.h> +#include <sys/stat.h> +#include <sys/types.h> +#if HAVE_ERRNO_H +#include <errno.h> +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "bmap64.h" + +ext2_filsys test_fs; +ext2fs_block_bitmap block_map_1; +ext2fs_block_bitmap block_map_2; +ext2fs_block_bitmap block_map; + +static int test_fail =0 ; + +void dump_bitmap (ext2fs_generic_bitmap bmap,unsigned int start,unsigned num) +{ +unsigned char *buf; +errcode_t retval; +int i, len = (num - start +7 ) /8 ; + + buf =malloc (len); +if (!buf) { +com_err ("dump_bitmap" ,0 ,"couldn't allocate buffer" ); +return ; + } +memset (buf,0 , len); + retval =ext2fs_get_generic_bmap_range (bmap, (__u64 ) start, num, buf); +if (retval) { +com_err ("dump_bitmap" , retval, +"while calling ext2fs_generic_bmap_range" ); +free (buf); +return ; + } +for (i=len-1 ; i >=0 ; i--) +printf ("%02x " , buf[i]); +printf ("\n" ); +printf ("bits set: %u\n" ,ext2fs_bitcount (buf, len)); +free (buf); +} + +static void test_copy_run () +{ +int blocks[] = {1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,21 ,23 ,26 ,29 ,33 ,37 ,38 }; +errcode_t ret; +char *buf_map =NULL ; +char *buf_copy_map =NULL ; + +assert (ext2fs_allocate_block_bitmap (test_fs,"block bitmap" , &block_map_1) ==0 ); + +for (int i =0 ; i <sizeof (blocks)/sizeof (blocks[0 ]); i++) { +ext2fs_mark_block_bitmap2 (block_map_1, blocks[i]); + } + +assert (ext2fs_copy_bitmap (block_map_1, &block_map) ==0 ); + +if (ext2fs_compare_block_bitmap (block_map_1, block_map) !=0 ) { +printf ("block bitmap copy test failed\n" ); + test_fail++; + +dump_bitmap (block_map_1, test_fs->super->s_first_data_block, + test_fs->super->s_blocks_count); + +dump_bitmap (block_map, test_fs->super->s_first_data_block, + test_fs->super->s_blocks_count); + } + +ext2fs_free_block_bitmap (block_map_1); +ext2fs_free_block_bitmap (block_map); +} + +void test_merge_run () +{ +int blocks_odd[] = {1 ,3 ,5 ,7 ,9 ,21 ,23 ,29 ,33 ,37 }; +int blocks_even[] = {2 ,4 ,6 ,8 ,10 ,26 ,38 }; +ext2fs_generic_bitmap_64 tmp_map; + +assert (ext2fs_allocate_block_bitmap (test_fs,"block bitmap 1" , &block_map_1) ==0 ); +assert (ext2fs_allocate_block_bitmap (test_fs,"block bitmap 2" , &block_map_2) ==0 ); +assert (ext2fs_allocate_block_bitmap (test_fs,"block bitmap 2" , &block_map) ==0 ); + +for (int i =0 ; i <sizeof (blocks_odd) /sizeof (blocks_odd[0 ]); i++) { +ext2fs_mark_block_bitmap2 (block_map_1, blocks_odd[i]); +ext2fs_mark_block_bitmap2 (block_map, blocks_odd[i]); + } + +for (int i =0 ; i <sizeof (blocks_even) /sizeof (blocks_even[0 ]); i++) { +ext2fs_mark_block_bitmap2 (block_map_2, blocks_even[i]); +ext2fs_mark_block_bitmap2 (block_map, blocks_even[i]); + } + +assert (ext2fs_merge_bitmap (block_map_2, block_map_1,NULL ,NULL ) ==0 ); +if (ext2fs_compare_block_bitmap (block_map_1, block_map) !=0 ) { +printf ("block bitmap merge test failed\n" ); + test_fail++; + +dump_bitmap (block_map_1, test_fs->super->s_first_data_block, + test_fs->super->s_blocks_count); + +dump_bitmap (block_map, test_fs->super->s_first_data_block, + test_fs->super->s_blocks_count); + } + +ext2fs_free_block_bitmap (block_map_1); +ext2fs_free_block_bitmap (block_map_2); +ext2fs_free_block_bitmap (block_map); +} + +static void setup_filesystem (const char *name,unsigned int blocks, +unsigned int inodes,unsigned int type, +unsigned int flags) +{ +struct ext2_super_block param; +errcode_t ret; + +memset (¶m,0 ,sizeof (param)); +ext2fs_blocks_count_set (¶m, blocks); + param.s_inodes_count = inodes; + + ret =ext2fs_initialize (name, flags, ¶m, test_io_manager, + &test_fs); +if (ret) { +com_err (name, ret,"while initializing filesystem" ); +return ; + } + + test_fs->default_bitmap_type = type; + +ext2fs_free_block_bitmap (test_fs->block_map); +ext2fs_free_block_bitmap (test_fs->inode_map); + +return ; +errout: +ext2fs_close_free (&test_fs); +} + +int main (int argc,char **argv) +{ +unsigned int blocks =127 ; +unsigned int inodes =0 ; +unsigned int type =EXT2FS_BMAP64_RBTREE ; +unsigned int flags =EXT2_FLAG_64BITS ; +char *buf =NULL ; + +setup_filesystem (argv[0 ], blocks, inodes, type, flags); + +/* test for EXT2FS_BMAP64_RBTREE */ +test_copy_run (); +test_merge_run (); + +/* TODO: test for EXT2FS_BMAP64_BITARRAY */ + +if (test_fail) +printf ("%s: Test copy & merge bitmaps -- NOT OK\n" , argv[0 ]); +else +printf ("%s: Test copy & merge bitmaps -- OK\n" , argv[0 ]); + +return test_fail; +} --
Quoted 2 lines
2.37.3
Cheers, Andreas
Re: [RFCv1 14/72] tst_bitmaps_standalone: Add copy and merge bitmaps test
Quoted 8 lines · Andreas Dilger
Quoted 4 lines · Ritesh Harjani (IBM)
This adds a basic copy and merge api test for rbtree bitmap type.
Signed-off-by Ritesh Harjani (IBM) <[email protected]>Thanks for adding this test. It looks like it is only testing the default rbtree bitmap type. It would be good to also add a test for regular bitmaps.
sure, the test will also requires merge logic for regular bitmap. I had added some basic support earlier (non-aligned was remaining to be added). In the next iteration, I will keep a note about this.
Quoted 2 lines
Reviewed-by Andreas Dilger <[email protected]>
Thanks for the review!
Quoted 287 lines
Quoted 277 lines
---
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.clib/ext2fs/Makefile.in +8
-2@@ -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)lib/ext2fs/Makefile.in +2
-1@@ -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_standaloneinstalldirs::
$(E) " MKDIR_P $(libdir) $(includedir)/ext2fs"lib/ext2fs/Makefile.in +0
-0@@ -581,7 +588,7 @@ install:: all $(HFILES) $(HFILES_IN) installdirs ext2fs.pcuninstall::
$(RM) -f $(DESTDIR)$(libdir)/libext2fs.a \ $(DESTDIR)$(pkgconfigdir)/ext2fs.pclib/ext2fs/Makefile.in +1
-1- $(RM) -rf $(DESTDIR)$(includedir)/ext2fs + $(RM) -rf $(DESTDIR)$(includedir)/ext2fsclean::
$(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* \lib/ext2fs/Makefile.in +8
-2@@ -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
-1@@ -0,0 +1,170 @@ +#include "config.h" +#include <stdio.h> +#include <string.h> +#include <assert.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <fcntl.h> +#include <time.h> +#include <sys/stat.h> +#include <sys/types.h> +#if HAVE_ERRNO_H +#include <errno.h> +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "bmap64.h" + +ext2_filsys test_fs; +ext2fs_block_bitmap block_map_1; +ext2fs_block_bitmap block_map_2; +ext2fs_block_bitmap block_map; + +static int test_fail =0 ; + +void dump_bitmap (ext2fs_generic_bitmap bmap,unsigned int start,unsigned num) +{ +unsigned char *buf; +errcode_t retval; +int i, len = (num - start +7 ) /8 ; + + buf =malloc (len); +if (!buf) { +com_err ("dump_bitmap" ,0 ,"couldn't allocate buffer" ); +return ; + } +memset (buf,0 , len); + retval =ext2fs_get_generic_bmap_range (bmap, (__u64 ) start, num, buf); +if (retval) { +com_err ("dump_bitmap" , retval, +"while calling ext2fs_generic_bmap_range" ); +free (buf); +return ; + } +for (i=len-1 ; i >=0 ; i--) +printf ("%02x " , buf[i]); +printf ("\n" ); +printf ("bits set: %u\n" ,ext2fs_bitcount (buf, len)); +free (buf); +} + +static void test_copy_run () +{ +int blocks[] = {1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,21 ,23 ,26 ,29 ,33 ,37 ,38 }; +errcode_t ret; +char *buf_map =NULL ; +char *buf_copy_map =NULL ; + +assert (ext2fs_allocate_block_bitmap (test_fs,"block bitmap" , &block_map_1) ==0 ); + +for (int i =0 ; i <sizeof (blocks)/sizeof (blocks[0 ]); i++) { +ext2fs_mark_block_bitmap2 (block_map_1, blocks[i]); + } + +assert (ext2fs_copy_bitmap (block_map_1, &block_map) ==0 ); + +if (ext2fs_compare_block_bitmap (block_map_1, block_map) !=0 ) { +printf ("block bitmap copy test failed\n" ); + test_fail++; + +dump_bitmap (block_map_1, test_fs->super->s_first_data_block, + test_fs->super->s_blocks_count); + +dump_bitmap (block_map, test_fs->super->s_first_data_block, + test_fs->super->s_blocks_count); + } + +ext2fs_free_block_bitmap (block_map_1); +ext2fs_free_block_bitmap (block_map); +} + +void test_merge_run () +{ +int blocks_odd[] = {1 ,3 ,5 ,7 ,9 ,21 ,23 ,29 ,33 ,37 }; +int blocks_even[] = {2 ,4 ,6 ,8 ,10 ,26 ,38 }; +ext2fs_generic_bitmap_64 tmp_map; + +assert (ext2fs_allocate_block_bitmap (test_fs,"block bitmap 1" , &block_map_1) ==0 ); +assert (ext2fs_allocate_block_bitmap (test_fs,"block bitmap 2" , &block_map_2) ==0 ); +assert (ext2fs_allocate_block_bitmap (test_fs,"block bitmap 2" , &block_map) ==0 ); + +for (int i =0 ; i <sizeof (blocks_odd) /sizeof (blocks_odd[0 ]); i++) { +ext2fs_mark_block_bitmap2 (block_map_1, blocks_odd[i]); +ext2fs_mark_block_bitmap2 (block_map, blocks_odd[i]); + } + +for (int i =0 ; i <sizeof (blocks_even) /sizeof (blocks_even[0 ]); i++) { +ext2fs_mark_block_bitmap2 (block_map_2, blocks_even[i]); +ext2fs_mark_block_bitmap2 (block_map, blocks_even[i]); + } + +assert (ext2fs_merge_bitmap (block_map_2, block_map_1,NULL ,NULL ) ==0 ); +if (ext2fs_compare_block_bitmap (block_map_1, block_map) !=0 ) { +printf ("block bitmap merge test failed\n" ); + test_fail++; + +dump_bitmap (block_map_1, test_fs->super->s_first_data_block, + test_fs->super->s_blocks_count); + +dump_bitmap (block_map, test_fs->super->s_first_data_block, + test_fs->super->s_blocks_count); + } + +ext2fs_free_block_bitmap (block_map_1); +ext2fs_free_block_bitmap (block_map_2); +ext2fs_free_block_bitmap (block_map); +} + +static void setup_filesystem (const char *name,unsigned int blocks, +unsigned int inodes,unsigned int type, +unsigned int flags) +{ +struct ext2_super_block param; +errcode_t ret; + +memset (¶m,0 ,sizeof (param)); +ext2fs_blocks_count_set (¶m, blocks); + param.s_inodes_count = inodes; + + ret =ext2fs_initialize (name, flags, ¶m, test_io_manager, + &test_fs); +if (ret) { +com_err (name, ret,"while initializing filesystem" ); +return ; + } + + test_fs->default_bitmap_type = type; + +ext2fs_free_block_bitmap (test_fs->block_map); +ext2fs_free_block_bitmap (test_fs->inode_map); + +return ; +errout: +ext2fs_close_free (&test_fs); +} + +int main (int argc,char **argv) +{ +unsigned int blocks =127 ; +unsigned int inodes =0 ; +unsigned int type =EXT2FS_BMAP64_RBTREE ; +unsigned int flags =EXT2_FLAG_64BITS ; +char *buf =NULL ; + +setup_filesystem (argv[0 ], blocks, inodes, type, flags); + +/* test for EXT2FS_BMAP64_RBTREE */ +test_copy_run (); +test_merge_run (); + +/* TODO: test for EXT2FS_BMAP64_BITARRAY */ + +if (test_fail) +printf ("%s: Test copy & merge bitmaps -- NOT OK\n" , argv[0 ]); +else +printf ("%s: Test copy & merge bitmaps -- OK\n" , argv[0 ]); + +return test_fail; +} --Quoted 2 lines
2.37.3
Cheers, Andreas
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
Re: [RFCv1 15/72] tst_bitmaps_pthread: Add merge bitmaps test using pthreads
Quoted 5 lines · Ritesh Harjani (IBM)
This patch adds a test to verify the core bitmaps merge APIs for rbtree bitmap type.
Signed-off-by Ritesh Harjani (IBM) <[email protected]>
Quoted 5 lines
+/*
+ * Note we useEXT2FS_BMAP64_BITARRAYalways forused_bitmap, this is because
+ *EXT2FS_BMAP64_RBTREEdoes not support parallel scan due to rcursor
+ * optimization.
+ */
Is this going to be a problem in the future? I think for pass1/pass5 there are no rbtree bitmaps that are *source* bitmaps for multi-threaded operation, but I suspect that once we try to parallelize pass2 this could break.
Is there any check in the code that prevents multi-thread access to an rbtree bitmap? Making a copy for each thread, or ideally copying the rcursor for each thread, to allow at least multi-threaded reads. I don't think there is a high need for multi-threaded write
Cheers, Andreas
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
Re: [RFCv1 16/72] tst_libext2fs_pthread: Add libext2fs merge/clone unit tests
Quoted 9 lines · 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 addEXT2FS_CLONE_BADBLOCKSandEXT2FS_CLONE_DBLISTtest as well into it.Signed-off-by Ritesh Harjani (IBM) <[email protected]>
Quoted 391 lines
---
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.clib/ext2fs/Makefile.in +6
-0@@ -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)lib/ext2fs/Makefile.in +2
-1@@ -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_pthreadinstalldirs::
$(E) " MKDIR_P $(libdir) $(includedir)/ext2fs"lib/ext2fs/Makefile.in +7
-1@@ -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
-1@@ -0,0 +1,315 @@ +#include "config.h" +#include <stdio.h> +#include <string.h> +#include <assert.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <fcntl.h> +#include <time.h> +#include <sys/stat.h> +#include <sys/types.h> +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_PTHREAD +#include <pthread.h> +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +#ifdef HAVE_PTHREAD +int test_fail =0 ; +ext2_filsys testfs; +ext2fs_inode_bitmap inode_used_map; +ext2fs_block_bitmap block_used_map; +ext2_filsys childfs[2 ]; +pthread_t pthread_infos[2 ]; + +#define nr_bits 16384 +int nr_threads =2 ; + +int should_mark_bit () +{ +return rand () %2 ==0 ; +} + +void setupfs () +{ +errcode_t retval; +struct ext2_super_block param; + +initialize_ext2_error_table (); + +memset (¶m,0 ,sizeof (param)); +ext2fs_blocks_count_set (¶m, nr_bits); + retval =ext2fs_initialize ("test fs" ,EXT2_FLAG_64BITS , ¶m, + test_io_manager, &testfs); +if (retval) { +com_err ("setup" , retval,"while initializing filesystem" ); +exit (1 ); + } + + retval =ext2fs_allocate_tables (testfs); +if (retval) { +com_err ("setup" , retval,"while allocating tables for testfs" ); +exit (1 ); + } +} + +void setup_used_bitmaps () +{ +int saved_type = testfs->default_bitmap_type; +ext2_inode_scan scan; +struct ext2_inode inode; +ext2_ino_t ino; +errcode_t retval; +int i; + + testfs->default_bitmap_type =EXT2FS_BMAP64_BITARRAY ; + +/* allocate block and inode used bitmaps */ + retval =ext2fs_allocate_block_bitmap (testfs,"block used map" , &block_used_map); +if (retval) + goto out; + + retval =ext2fs_allocate_inode_bitmap (testfs,"inode used map" , &inode_used_map); +if (retval) + goto out; + +/* setup block and inode used bitmaps */ +for (i =1 ; i < nr_bits; i++) { +/* +* we check for testfs->block_map as well since there could be some +* blocks already set as part of the FS metadata. +*/ +if (should_mark_bit () ||ext2fs_test_block_bitmap2 (testfs->block_map, i)) { +ext2fs_mark_block_bitmap2 (block_used_map, i); + } + } + + retval =ext2fs_open_inode_scan (testfs,8 , &scan); +if (retval) { +com_err ("setup_inode_map" , retval,"while open inode scan" ); +exit (1 ); + } + + retval =ext2fs_get_next_inode (scan, &ino, &inode); +if (retval) { +com_err ("setup_inode_map" , retval,"while getting next inode" ); +exit (1 ); + } + +while (ino) { +if (should_mark_bit ()) +ext2fs_mark_inode_bitmap2 (inode_used_map, ino); + + retval =ext2fs_get_next_inode (scan, &ino, &inode); +if (retval) { +com_err ("setup_inode_map" , retval,"while getting next inode" ); +exit (1 ); + } + } +ext2fs_close_inode_scan (scan); + + testfs->default_bitmap_type = saved_type; +return ; +out: +com_err ("setup_used_bitmaps" , retval,"while setting up bitmaps\n" ); +exit (1 ); +} + +void setup_childfs () +{ +errcode_t retval; +int i; + +for (i =0 ; i < nr_threads; i++) { + retval =ext2fs_clone_fs (testfs, &childfs[i],EXT2FS_CLONE_INODE |EXT2FS_CLONE_BLOCK ); +if (retval) { +com_err ("setup_childfs" , retval,"while clone testfs for childfs" ); +exit (1 ); + } + + retval = childfs[i]->io->manager->open (childfs[i]->device_name, +IO_FLAG_THREADS |IO_FLAG_NOCACHE , &childfs[i]->io); +if (retval) { +com_err ("setup_pthread" , retval,"while opening childfs" ); +exit (1 ); + } +assert (childfs[i]->parent == testfs); + } +} + +static errcode_t scan_callback(ext2_filsys fs, + ext2_inode_scan scan EXT2FS_ATTR((unused)), + dgrp_t group, void *priv_data) +{ + pthread_t id = *((pthread_t *)priv_data); + +printf ("%s: Called for group %d via thread %d\n" , __func__, group, +pthread_equal (pthread_infos[1 ], id)); +if (pthread_equal (pthread_infos[0 ], id)) { +if (group >= fs->group_desc_count /2 -1 ) +return 1 ; + } +return 0 ; +} + +static void *run_pthread (void *arg) +{ +errcode_t retval =0 ; +int i =0 , start, end; +ext2fs_block_bitmap test_block_bitmap; +ext2fs_inode_bitmap test_inode_bitmap; +ext2_inode_scan scan; +struct ext2_inode inode; +ext2_ino_t ino; +pthread_t id =pthread_self (); + +if (pthread_equal (pthread_infos[0 ], id)) { + start =1 ; + end = nr_bits/2 ; + test_block_bitmap = childfs[0 ]->block_map; + test_inode_bitmap = childfs[0 ]->inode_map; + + retval =ext2fs_open_inode_scan (childfs[0 ],8 , &scan); +if (retval) { +com_err ("setup_inode_map" , retval,"while open inode scan" ); +exit (1 ); + } + + }else { + start = nr_bits /2 +1 ;; + end = nr_bits -1 ; + test_block_bitmap = childfs[1 ]->block_map; + test_inode_bitmap = childfs[1 ]->inode_map; + + retval =ext2fs_open_inode_scan (childfs[1 ],8 , &scan); +if (retval) { +com_err ("setup_inode_map" , retval,"while open inode scan" ); +exit (1 ); + } +ext2fs_inode_scan_goto_blockgroup (scan, testfs->group_desc_count/2 ); + } + +ext2fs_set_inode_callback (scan, scan_callback, &id); + +/* blocks scan */ +for (i = start; i <= end; i++) { +if (ext2fs_test_block_bitmap2 (block_used_map, i)) { +ext2fs_mark_block_bitmap2 (test_block_bitmap, i); + } + } + +/* inodes scan */ + retval =ext2fs_get_next_inode (scan, &ino, &inode); +if (retval) { +com_err ("setup_inode_map" , retval,"while getting next inode" ); +exit (1 ); + } + +while (ino) { +if (ext2fs_test_inode_bitmap2 (inode_used_map, ino)) { +ext2fs_mark_inode_bitmap2 (test_inode_bitmap, ino); + } + + retval =ext2fs_get_next_inode (scan, &ino, &inode); +if (retval) +break ; + } +ext2fs_close_inode_scan (scan); +return NULL ; +} + +void run_pthreads () +{ +errcode_t retval; +int i; + +for (i =0 ; i < nr_threads; i++) { +printf ("Starting thread (%d)\n" , i); + retval =pthread_create (&pthread_infos[i],NULL , &run_pthread,NULL ); +if (retval) { +com_err ("run_pthreads" , retval,"while pthread_create" ); +exit (1 ); + } + } + +for (i =0 ; i < nr_threads; i++) { +void *status; +int ret; + retval =pthread_join (pthread_infos[i], &status); +if (retval) { +com_err ("run_pthreads" , retval,"while joining pthreads" ); +exit (1 ); + + } + ret = status ==NULL ?0 : *(int *)status; +if (ret) { +com_err ("run_pthreads" , ret,"pthread returned error" ); + test_fail++; + } + +printf ("Closing thread (%d), ret(%d)\n" , i, ret); + } + +assert (ext2fs_merge_fs (&childfs[0 ]) ==0 ); +assert (ext2fs_merge_fs (&childfs[1 ]) ==0 ); +} + +void test_bitmaps () +{ +errcode_t retval; + retval =ext2fs_compare_block_bitmap (testfs->block_map, block_used_map); +if (retval) { +printf ("Block bitmap compare -- NOT OK!! (%ld)\n" , retval); + test_fail++; + } + +printf ("Block compare bitmap -- OK!!\n" ); + retval =ext2fs_compare_inode_bitmap (testfs->inode_map, inode_used_map); +if (retval) { +printf ("Inode bitmap compare -- NOT OK!! (%ld)\n" , retval); + test_fail++; + } +printf ("Inode compare bitmap -- OK!!\n" ); +} + +void free_used_bitmaps () +{ +ext2fs_free_block_bitmap (block_used_map); +ext2fs_free_inode_bitmap (inode_used_map); +} + +#endif + +int main (int argc,char *argv[]) +{ +int i; + +#ifndef HAVE_PTHREAD +printf ("No PTHREAD support, exiting...\n" ); +return 0 ; +#else + +srand (time (0 )); + +setupfs (); +setup_used_bitmaps (); + +setup_childfs (); +run_pthreads (); +test_bitmaps (i); + +if (test_fail) +printf ("%s: Test libext2fs clone/merge with pthreads NOT OK!!\n" , argv[0 ]); +else +printf ("%s: Test libext2fs clone/merge with pthreads OK!!\n" , argv[0 ]); +free_used_bitmaps (); +ext2fs_free (testfs); + +return test_fail; +#endif +} --
Quoted 2 lines
2.37.3
Cheers, Andreas
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
Re: [RFCv1 17/72] libext2fs: Add support for ext2fs_test_block_bitmap_range2_valid()
Quoted 7 lines · 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.
Quoted 6 lines
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 fromext2fs_test_block_bitmap_range2()Signed-off-by Wang Shilong <[email protected]>Signed-off-by Ritesh Harjani (IBM) <[email protected]>
I don't think this patch is correct?
Quoted 14 lines
---
lib/ext2fs/gen_bitmap64.c +5
-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;
lib/ext2fs/gen_bitmap64.c int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap gen_bmap, · line 748
Quoted 10 lines
lib/ext2fs/gen_bitmap64.c +10
-0+ +if (!bmap) +return 0 ; + +if (EXT2FS_IS_32_BITMAP (bmap)) { +if ((block & ~0xffffffffULL ) || + ((block+num-1 ) & ~0xffffffffULL )) { +return 0 ; + } + }
This is bailing out early if the requested bit is > 2^32, but that is before cluster conversion below. However, I think the bitmap is actually stored in clusters, so the 2^32 check seems premature?
Quoted 6 lines
lib/ext2fs/gen_bitmap64.c +6
-0+ +if (!EXT2FS_IS_64_BITMAP (bmap)) +return 0 ; + +/* convert to clusters if necessary */ + block >>= bmap->cluster_bits;
lib/ext2fs/gen_bitmap64.c int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap gen_bmap, · line 764
Quoted 10 lines
lib/ext2fs/gen_bitmap64.c +10
-0+ 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 ; +}
Cheers, Andreas
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
Re: [RFCv1 18/72] libext2fs: Add support to get average group count
Quoted 25 lines · 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_threadswill 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 setfs->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.Signed-off-by Wang Shilong <[email protected]>Signed-off-by Ritesh Harjani (IBM) <[email protected]>---
lib/ext2fs/ext2fs.h| 32 +++++++++++++++++++++++++++++++-1 file changed, 31 insertions(+), 1 deletion(-)lib/ext2fs/ext2fs.h +0
-0
lib/ext2fs/ext2fs.h struct struct_ext2_filsys { · line 282
Quoted 4 lines
lib/ext2fs/ext2fs.h +1
-0@@ -279,10 +279,11 @@ struct struct_ext2_filsys {int cluster_ratio_bits;__u16 default_bitmap_type;__u16 pad; +__u32 fs_num_threads;
From later cleanup patch, fs_num_threads should just use "__u16 pad" field.
Otherwise, looks OK.
Quoted 45 lines
lib/ext2fs/ext2fs.h +30
-2/* * 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 --
Quoted 2 lines
2.37.3
Cheers, Andreas
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
Re: [RFCv1 19/72] libext2fs: Misc fixes for struct_ext2_filsys
Quoted 5 lines · Ritesh Harjani (IBM)
From: Andreas Dilger <[email protected]>
Move
ext2_filsysfs_num_threadsto fit into the__u16"pad" field to avoid consuming one of the few remaining__u32reserved fields.
This should be merged into the previous patch.
Quoted 26 lines
Signed-off-by Andreas Dilger <[email protected]>Signed-off-by Ritesh Harjani (IBM) <[email protected]>---
lib/ext2fs/ext2fs.h| 5 ++---1 file changed, 2 insertions(+), 3 deletions(-)lib/ext2fs/ext2fs.h +2
-4@@ -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. --
Quoted 2 lines
2.37.3
Cheers, Andreas
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
Re: [RFCv1 20/72] libext2fs: avoid too much memory allocation in case fs_num_threads
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
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
Re: [RFCv1 21/72] e2fsck: add -m option for multithread
Quoted 10 lines · 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
(quoted diff) +0
-2-p/-y/-n options should be specified. And when -m is specified, -C shouldn't be specified and the completion progress report won'tbe triggered by sending SIGUSR1/SIGUSR2 signals. This simplifies the implementation of multi-thread fsck in the future.
Quoted 7 lines
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.
Signed-off-by Li Xi <[email protected]>Signed-off-by Wang Shilong <[email protected]>Signed-off-by Ritesh Harjani (IBM) <[email protected]>
Minor nit below, but looks OK otherwise:
e2fsck/unix.c static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) · line 859
Quoted 11 lines
e2fsck/unix.c +2
-1@@ -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 )
I find it easier to find/add options when these are sorted in alphabetical order, but that is not solely the fault of this patch. At least 'm' is added in order relative to most other lower-case options.
Cheers, Andreas
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