From 6035a76dedba0e741aff7b14e85e7b88e0a31444 Mon Sep 17 00:00:00 2001 From: RoyHuang Date: Tue, 20 May 2025 12:48:49 +0800 Subject: [PATCH] Reclaim extent block when removing non-root dir When removing a directory, the extent block was not reclaimed properly. This fix ensures that extent blocks for non-root directories are reclaimed during removal. The root directory is excluded from this process, as it serves as the mount point and cannot be removed. The reclaim mechanism is designed to run when a directory is actually removed, not just when it becomes empty. close #65 --- inode.c | 3 --- script/test.sh | 44 ++++++++++++++++++++++----------------- script/test_large_file.sh | 20 ++++++++++++++++++ 3 files changed, 45 insertions(+), 22 deletions(-) create mode 100755 script/test_large_file.sh diff --git a/inode.c b/inode.c index e869ef3..17ab21d 100644 --- a/inode.c +++ b/inode.c @@ -603,8 +603,6 @@ static int simplefs_unlink(struct inode *dir, struct dentry *dentry) if (!bh) goto clean_inode; file_block = (struct simplefs_file_ei_block *) bh->b_data; - if (S_ISDIR(inode->i_mode)) - goto scrub; for (ei = 0; ei < SIMPLEFS_MAX_EXTENTS; ei++) { char *block; @@ -627,7 +625,6 @@ static int simplefs_unlink(struct inode *dir, struct dentry *dentry) } } -scrub: /* Scrub index block */ memset(file_block, 0, SIMPLEFS_BLOCK_SIZE); mark_buffer_dirty(bh); diff --git a/script/test.sh b/script/test.sh index 3803bf0..b479593 100755 --- a/script/test.sh +++ b/script/test.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +. script/test_large_file.sh + SIMPLEFS_MOD=simplefs.ko IMAGE=$1 IMAGESIZE=$2 @@ -47,13 +49,6 @@ dd if=/dev/zero of=$IMAGE bs=1M count=$IMAGESIZE status=none && \ sudo mount -t simplefs -o loop $IMAGE test && \ pushd test >/dev/null -# mkdir -test_op 'mkdir dir' -test_op 'mkdir dir' # expected to fail - -# create file -test_op 'touch file' - # create 40920 files for ((i=0; i<=$MAXFILES; i++)) do @@ -98,6 +93,21 @@ do fi done find . -name 'file_[0-9]*.txt' | xargs sudo rm || { echo "Failed to delete files"; exit 1; } +sync + +popd >/dev/null || { echo "popd failed"; exit 1; } +ls test -laR +rm test/* -rf +nr_free_blk=$(($(dd if=$IMAGE bs=1 skip=28 count=4 2>/dev/null | hexdump -v -e '1/4 "0x%08x\n"'))) +echo "$nr_free_blk" +pushd test >/dev/null || { echo "pushd failed"; exit 1; } + +# mkdir +test_op 'mkdir dir' +test_op 'mkdir dir' # expected to fail + +# create file +test_op 'touch file' # hard link test_op 'ln file hdlink' @@ -119,21 +129,11 @@ test_op 'echo abc > file' test $(cat file) = "abc" || echo "Failed to write" # file too large -test_op 'dd if=/dev/zero of=file bs=1M count=12 status=none' -filesize=$(sudo ls -lR | grep -e "$F_MOD 2".*file | awk '{print $5}') -test $filesize -le $MAXFILESIZE || echo "Failed, file size over the limit" +test_too_large_file # Write the file size larger than BLOCK_SIZE # test serial to write -test_op 'printf \"%.0s123456789\" {1..1600} > file.txt' -count=$(awk '{count += gsub(/123456789/, "")} END {print count}' "file.txt") -echo "test $count" -test "$count" -eq 1600 || echo "Failed, file size not matching" -# test block to write -test_op 'cat file.txt > checkfile.txt' -count=$(awk '{count += gsub(/123456789/, "")} END {print count}' "checkfile.txt") -echo "test $count" -test "$count" -eq 1600 || echo "Failed, file size not matching" +test_file_size_larger_than_block_size # test remove symbolic link test_op 'ln -s file symlink_fake' @@ -152,7 +152,13 @@ check_exist $S_MOD 1 symlink check_exist $F_MOD 1 symlink_fake check_exist $F_MOD 1 symlink_hard_fake +# clean all files and directories +test_op 'rm -rf ./*' + sleep 1 popd >/dev/null sudo umount test sudo rmmod simplefs + +af_nr_free_blk=$(($(dd if=$IMAGE bs=1 skip=28 count=4 2>/dev/null | hexdump -v -e '1/4 "0x%08x\n"'))) +test $nr_free_blk -eq $af_nr_free_blk || echo "Failed, some blocks are not be reclaimed" diff --git a/script/test_large_file.sh b/script/test_large_file.sh new file mode 100755 index 0000000..7241c4d --- /dev/null +++ b/script/test_large_file.sh @@ -0,0 +1,20 @@ +# file too large +test_too_large_file() { + test_op 'dd if=/dev/zero of=file bs=1M count=12 status=none' + filesize=$(sudo ls -lR | grep -e "$F_MOD 2".*file | awk '{print $5}') + test $filesize -le $MAXFILESIZE || echo "Failed, file size over the limit" +} + +# Write the file size larger than BLOCK_SIZE +# test serial to write +test_file_size_larger_than_block_size() { + test_op 'yes 123456789 | head -n 1600 | tr -d "\n" > file.txt' + count=$(awk '{count += gsub(/123456789/, "")} END {print count}' "file.txt") + echo "test $count" + test "$count" -eq 1600 || echo "Failed, file size not matching" + # test block to write + test_op 'cat file.txt > checkfile.txt' + count=$(awk '{count += gsub(/123456789/, "")} END {print count}' "checkfile.txt") + echo "test $count" + test "$count" -eq 1600 || echo "Failed, file size not matching" +}