From 159d64f4626c08ec8283c8837943f979c8dcf537 Mon Sep 17 00:00:00 2001 From: RoyHuang Date: Mon, 21 Jul 2025 00:36:02 +0800 Subject: [PATCH 1/2] Adjust unit tests --- script/config | 10 +++++ script/test.sh | 92 ++++++++------------------------------- script/test_func.sh | 16 +++++++ script/test_large_file.sh | 13 +++--- script/test_remount.sh | 52 ++++++++++++++++++++++ 5 files changed, 103 insertions(+), 80 deletions(-) create mode 100644 script/config create mode 100644 script/test_func.sh create mode 100644 script/test_remount.sh diff --git a/script/config b/script/config new file mode 100644 index 0000000..eee67b3 --- /dev/null +++ b/script/config @@ -0,0 +1,10 @@ +D_MOD="drwxr-xr-x" +F_MOD="-rw-r--r--" +S_MOD="lrwxrwxrwx" +SIMPLEFS_MAX_BLOCKS_PER_EXTENT=8 +SIMPLEFS_BLOCK_SIZE=4096 +SIMPLEFS_MAX_EXTENTS=$(( ($SIMPLEFS_BLOCK_SIZE - 4) / 16 )) +MAXFILESIZE=$(( $SIMPLEFS_MAX_EXTENTS * $SIMPLEFS_MAX_BLOCKS_PER_EXTENT * $SIMPLEFS_BLOCK_SIZE )) +# MAXFILES=1173 # max files per dir +MAXFILES=30600 # max files per dir +MOUNT_TEST=100 diff --git a/script/test.sh b/script/test.sh index b479593..df695a8 100755 --- a/script/test.sh +++ b/script/test.sh @@ -1,36 +1,15 @@ #!/usr/bin/env bash +. script/test_func.sh . script/test_large_file.sh +. script/test_remount.sh +. script/config SIMPLEFS_MOD=simplefs.ko IMAGE=$1 IMAGESIZE=$2 MKFS=$3 -D_MOD="drwxr-xr-x" -F_MOD="-rw-r--r--" -S_MOD="lrwxrwxrwx" -MAXFILESIZE=11173888 # SIMPLEFS_MAX_EXTENTS * SIMPLEFS_MAX_BLOCKS_PER_EXTENT * SIMPLEFS_BLOCK_SIZE -MAXFILES=40920 # max files per dir -MOUNT_TEST=100 - -test_op() { - local op=$1 - echo - echo -n "Testing cmd: $op..." - sudo sh -c "$op" >/dev/null && echo "Success" -} - -check_exist() { - local mode=$1 - local nlink=$2 - local name=$3 - echo - echo -n "Check if exist: $mode $nlink $name..." - sudo ls -lR | grep -e "$mode $nlink".*$name >/dev/null && echo "Success" || \ - echo "Failed" -} - if [ "$EUID" -eq 0 ] then echo "Don't run this script as root" exit @@ -46,62 +25,32 @@ echo && \ sudo insmod $SIMPLEFS_MOD && \ dd if=/dev/zero of=$IMAGE bs=1M count=$IMAGESIZE status=none && \ ./$MKFS $IMAGE && \ + sudo mount -t simplefs -o loop $IMAGE test && \ pushd test >/dev/null -# create 40920 files -for ((i=0; i<=$MAXFILES; i++)) -do - test_op "touch $i.txt" # expected to fail with more than 40920 files -done -filecnts=$(ls | wc -w) -test $filecnts -eq $MAXFILES || echo "Failed, it should be $MAXFILES files" -find . -name '[0-9]*.txt' | xargs -n 2000 sudo rm -sync - -# create 100 files with filenames inside -for ((i=1; i<=$MOUNT_TEST; i++)) -do - echo file_$i | sudo tee file_$i.txt >/dev/null && echo "file_$i.txt created." -done -sync +# test serial to write +test_create_max_nr_files +# test remount file exist or not +test_remount_file_exist -# unmount and remount the filesystem -echo "Unmounting filesystem..." popd >/dev/null || { echo "popd failed"; exit 1; } -sudo umount test || { echo "umount failed"; exit 1; } -sleep 1 -echo "Remounting filesystem..." -sudo mount -t simplefs -o loop $IMAGE test || { echo "mount failed"; exit 1; } -echo "Remount succeeds." -pushd test >/dev/null || { echo "pushd failed"; exit 1; } -# check if files exist and content is correct after remounting -for ((i=1; i<=$MOUNT_TEST; i++)) -do - if [[ -f "file_$i.txt" ]]; then - content=$(cat "file_$i.txt" | tr -d '\000') - if [[ "$content" == "file_$i" ]]; then - echo "Success: file_$i.txt content is correct." - else - echo "Failed: file_$i.txt content is incorrect." - exit 1 - fi - else - echo "Failed: file_$i.txt does not exist." - exit 1 - fi -done -find . -name 'file_[0-9]*.txt' | xargs sudo rm || { echo "Failed to delete files"; exit 1; } +# Get ready to count free block +sudo touch test/test.txt +sudo rm test/* -rf 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; } +# write a file larger than max size +test_too_large_file + +# Write the a file larger than BLOCK_SIZE +test_file_size_larger_than_block_size + # mkdir test_op 'mkdir dir' test_op 'mkdir dir' # expected to fail @@ -128,13 +77,6 @@ test_op 'ln -s dir len_of_name_of_the_link_is_29' test_op 'echo abc > file' test $(cat file) = "abc" || echo "Failed to write" -# file too large -test_too_large_file - -# Write the file size larger than BLOCK_SIZE -# test serial to write -test_file_size_larger_than_block_size - # test remove symbolic link test_op 'ln -s file symlink_fake' test_op 'rm -f symlink_fake' diff --git a/script/test_func.sh b/script/test_func.sh new file mode 100644 index 0000000..f1b7a4e --- /dev/null +++ b/script/test_func.sh @@ -0,0 +1,16 @@ +test_op() { + local op=$1 + echo + echo -n "Testing cmd: $op..." + sudo sh -c "$op" >/dev/null && echo "Success" +} + +check_exist() { + local mode=$1 + local nlink=$2 + local name=$3 + echo + echo -n "Check if exist: $mode $nlink $name..." + sudo ls -lR | grep -e "$mode $nlink".*$name >/dev/null && echo "Success" || \ + echo "Failed" +} diff --git a/script/test_large_file.sh b/script/test_large_file.sh index 7241c4d..bd1b364 100755 --- a/script/test_large_file.sh +++ b/script/test_large_file.sh @@ -1,20 +1,23 @@ # 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}') + TESTLG_FILE_SZ=$(( $MAXFILESIZE / 1024 / 1024 + 1 )) + test_op "dd if=/dev/zero of=exceed_max_sz_file bs=1M count=$TESTLG_FILE_SZ status=none" + filesize=$(sudo ls -lR | grep -e "$F_MOD 1".*file | awk '{print $5}') test $filesize -le $MAXFILESIZE || echo "Failed, file size over the limit" + test_op 'rm exceed_max_sz_file' } # 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") + test_op 'yes 123456789 | head -n 1600 | tr -d "\n" > exceed_blk.txt' + count=$(awk '{count += gsub(/123456789/, "")} END {print count}' "exceed_blk.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' + test_op 'cat exceed_blk.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_op 'rm exceed_blk.txt checkfile.txt' } diff --git a/script/test_remount.sh b/script/test_remount.sh new file mode 100644 index 0000000..d3f2ce4 --- /dev/null +++ b/script/test_remount.sh @@ -0,0 +1,52 @@ +# test create max nr files +test_create_max_nr_files() { + echo "max size $MAXFILESIZE" + # create 40920 files + for ((i=0; i<=$MAXFILES; i++)) + do + test_op "touch $i.txt" # expected to fail with more than 40920 files + done + sync + filecnts=$(ls | wc -w) + test $filecnts -eq $MAXFILES || echo "Failed($filecnts), it should be $MAXFILES files" + find . -name '[0-9]*.txt' | xargs -n 2000 sudo rm + sync +} + +# create 100 files with filenames inside +test_remount_file_exist() { + for ((i=1; i<=$MOUNT_TEST; i++)) + do + echo file_$i | sudo tee file_$i.txt >/dev/null && echo "file_$i.txt created." + done + sync + + # unmount and remount the filesystem + echo "Unmounting filesystem..." + popd >/dev/null || { echo "popd failed"; exit 1; } + sudo umount test || { echo "umount failed"; exit 1; } + sleep 1 + echo "Remounting filesystem..." + sudo mount -t simplefs -o loop $IMAGE test || { echo "mount failed"; exit 1; } + echo "Remount succeeds." + pushd test >/dev/null || { echo "pushd failed"; exit 1; } + + # check if files exist and content is correct after remounting + for ((i=1; i<=$MOUNT_TEST; i++)) + do + if [[ -f "file_$i.txt" ]]; then + content=$(cat "file_$i.txt" | tr -d '\000') + if [[ "$content" == "file_$i" ]]; then + echo "Success: file_$i.txt content is correct." + else + echo "Failed: file_$i.txt content is incorrect." + exit 1 + fi + else + echo "Failed: file_$i.txt does not exist." + exit 1 + fi + done + find . -name 'file_[0-9]*.txt' | xargs sudo rm || { echo "Failed to delete files"; exit 1; } + sync +} From 0c50fb52b0f8209e4aa43d5dd9b21b48acac2ce5 Mon Sep 17 00:00:00 2001 From: RoyHuang Date: Sun, 27 Jul 2025 21:16:04 +0800 Subject: [PATCH 2/2] Use nr_blk to record the cont. blks in ext Add nr_blk in struct simiplefs_file to record the number of contiguous blocks a file occupies, similar to ext4's rec_len. This speeds up finding free blocks and optimizes file removal by merging freed space with the previous entry. --- README.md | 69 +++--- bitmap.h | 3 +- dir.c | 59 ++++-- file.c | 8 +- inode.c | 392 ++++++++++++++++++++++------------- script/config | 6 +- script/rand_rm_and_create.sh | 46 ++++ script/test.sh | 12 +- script/test_func.sh | 20 +- script/test_large_file.sh | 5 + script/test_remount.sh | 15 -- simplefs.h | 3 + super.c | 2 + 13 files changed, 416 insertions(+), 224 deletions(-) create mode 100755 script/rand_rm_and_create.sh diff --git a/README.md b/README.md index 9a67f7b..441ba0b 100644 --- a/README.md +++ b/README.md @@ -101,22 +101,27 @@ on the type of file: ``` inode +-----------------------+ - | i_mode = IFDIR | 0755 | block 123 - | ei_block = 123 ----|--------> +----------------+ - | i_size = 4 KiB | 0 | ee_block = 0 | - | i_blocks = 1 | | ee_len = 8 | block 84 - +-----------------------+ | ee_start = 84 |---> +-----------+ - |----------------| 0 | 24 (foo) | - 1 | ee_block = 8 | |-----------| - | ee_len = 8 | 1 | 45 (bar) | - | ee_start = 16 | |-----------| - |----------------| | ... | - | ... | |-----------| - |----------------| 14 | 0 | - 341 | ee_block = 0 | +-----------+ - | ee_len = 0 | - | ee_start = 0 | - +----------------+ + | i_mode = IFDIR | 0755 | block 123 (simplefs_file_ei_block) + | ei_block = 123 ----|---> +----------------+ + | i_size = 4 KiB | | nr_files = 7 | + | i_blocks = 1 | |----------------| + +-----------------------+ 0 | ee_block = 0 | + | ee_len = 8 | block 84(simplefs_dir_block) + | ee_start = 84 |---> +-------------+ + | nr_file = 2 | |nr_files = 2 | + |----------------| |-------------| + 1 | ee_block = 8 | 0 | inode = 24 | + | ee_len = 8 | | nr_blk = 1 | + | ee_start = 16 | | (foo) | + | nr_file = 5 | |-------------| + |----------------| 1 | inode = 45 | + | ... | | nr_blk = 14 | + |----------------| | (bar) | + 341 | ee_block = 0 | |-------------| + | ee_len = 0 | | ... | + | ee_start = 0 | |-------------| + | nr_file = 12 | 14 | 0 | + +----------------+ +-------------+ ``` - For a file, it lists the extents that hold the actual data of the file. @@ -124,25 +129,25 @@ on the type of file: bytes, a single block can accommodate up to 341 links. This limitation restricts the maximum size of a file to approximately 10.65 MiB (10,912 KiB). ``` - inode - +-----------------------+ - | i_mode = IFDIR | 0644 | block 93 - | ei_block = 93 ----|------> +----------------+ - | i_size = 10 KiB | 0 | ee_block = 0 | - | i_blocks = 25 | | ee_len = 8 | extent 94 + inode + +-----------------------+ + | i_mode = IFDIR | 0644 | block 93 + | ei_block = 93 ----|------> +----------------+ + | i_size = 10 KiB | 0 | ee_block = 0 | + | i_blocks = 25 | | ee_len = 8 | extent 94 +-----------------------+ | ee_start = 94 |---> +--------+ - |----------------| | | + |----------------| | | 1 | ee_block = 8 | +--------+ | ee_len = 8 | extent 99 - | ee_start = 99 |---> +--------+ + | ee_start = 99 |---> +--------+ |----------------| | | 2 | ee_block = 16 | +--------+ - | ee_len = 8 | extent 66 + | ee_len = 8 | extent 66 | ee_start = 66 |---> +--------+ |----------------| | | | ... | +--------+ - |----------------| - 341 | ee_block = 0 | + |----------------| + 341 | ee_block = 0 | | ee_len = 0 | | ee_start = 0 | +----------------+ @@ -158,8 +163,8 @@ comprises three members: ``` struct simplefs_extent - +----------------+ - | ee_block = 0 | + +----------------+ + | ee_block = 0 | | ee_len = 200| extent | ee_start = 12 |-----------> +---------+ +----------------+ block 12 | | @@ -181,7 +186,7 @@ The journaling support in simplefs is implemented using the jbd2 subsystem, whic For a detailed introduction to journaling, please refer to these two websites: [Journal(jbd2) document](https://www.kernel.org/doc/html/latest/filesystems/ext4/journal.html) -[Journal(jbd2) api](https://docs.kernel.org/filesystems/journalling.html) +[Journal(jbd2) api](https://docs.kernel.org/filesystems/journalling.html) External journal device disk layout: @@ -193,12 +198,12 @@ Hint: Each transaction starts with a descriptor block, followed by several metadata blocks or data blocks, and ends with a commit block. Every modified metadata (such as inode, bitmap, etc.) occupies its own block. Currently, simplefs primarily records "extent" metadata. -How to Enable Journaling in simplefs: +How to Enable Journaling in simplefs: Step 1: Create the Journal Disk Image To create an 8MB disk image for the journal, use the following make command: -Note: +Note: Assuming an 8 MB size for the external journal device, which is an arbitrary choice for now, I will set the journal block length to a fixed 2048, calculated by dividing the device size by the block size (4096 bytes). ```shell diff --git a/bitmap.h b/bitmap.h index e0368f3..8a317d1 100644 --- a/bitmap.h +++ b/bitmap.h @@ -52,8 +52,9 @@ static inline uint32_t get_free_blocks(struct super_block *sb, uint32_t len) return 0; sbi->nr_free_blocks -= len; + struct buffer_head *bh; for (i = 0; i < len; i++) { - struct buffer_head *bh = sb_bread(sb, ret + i); + bh = sb_bread(sb, ret + i); if (!bh) { pr_err("get_free_blocks: sb_bread failed for block %d\n", ret + i); sbi->nr_free_blocks += len; diff --git a/dir.c b/dir.c index b9d4e24..e96484f 100644 --- a/dir.c +++ b/dir.c @@ -19,7 +19,6 @@ static int simplefs_iterate(struct file *dir, struct dir_context *ctx) struct buffer_head *bh = NULL, *bh2 = NULL; struct simplefs_file_ei_block *eblock = NULL; struct simplefs_dir_block *dblock = NULL; - struct simplefs_file *f = NULL; int ei = 0, bi = 0, fi = 0; int ret = 0; @@ -43,36 +42,62 @@ static int simplefs_iterate(struct file *dir, struct dir_context *ctx) return -EIO; eblock = (struct simplefs_file_ei_block *) bh->b_data; - ei = (ctx->pos - 2) / SIMPLEFS_FILES_PER_EXT; - bi = (ctx->pos - 2) % SIMPLEFS_FILES_PER_EXT / SIMPLEFS_FILES_PER_BLOCK; - fi = (ctx->pos - 2) % SIMPLEFS_FILES_PER_BLOCK; + if (ctx->pos - 2 == eblock->nr_files) + goto release_bh; - /* Iterate over the index block and commit subfiles */ - for (; ei < SIMPLEFS_MAX_EXTENTS; ei++) { + int remained_nr_files = eblock->nr_files - (ctx->pos - 2); + + int offset = ctx->pos - 2; + for (ei = 0; ei < SIMPLEFS_MAX_EXTENTS; ei++) { if (eblock->extents[ei].ee_start == 0) + continue; + if (offset > eblock->extents[ei].nr_files) { + offset -= eblock->extents[ei].nr_files; + } else { break; + } + } + + /* Iterate over the index block and commit subfiles */ + for (; remained_nr_files && ei < SIMPLEFS_MAX_EXTENTS; ei++) { + if (eblock->extents[ei].ee_start == 0) + continue; /* Iterate over blocks in one extent */ - for (; bi < eblock->extents[ei].ee_len; bi++) { + for (bi = 0; bi < eblock->extents[ei].ee_len && remained_nr_files; + bi++) { bh2 = sb_bread(sb, eblock->extents[ei].ee_start + bi); if (!bh2) { ret = -EIO; goto release_bh; } dblock = (struct simplefs_dir_block *) bh2->b_data; - if (dblock->files[0].inode == 0) { + + if (offset > dblock->nr_files) { + offset -= dblock->nr_files; brelse(bh2); bh2 = NULL; - break; + continue; } - /* Iterate every file in one block */ - for (; fi < SIMPLEFS_FILES_PER_BLOCK; fi++) { - f = &dblock->files[fi]; - if (f->inode && - !dir_emit(ctx, f->filename, SIMPLEFS_FILENAME_LEN, f->inode, - DT_UNKNOWN)) - break; - ctx->pos++; + + for (fi = 0; fi < SIMPLEFS_FILES_PER_BLOCK;) { + if (dblock->files[fi].inode != 0) { + if (offset) { + offset--; + } else { + remained_nr_files--; + if (!dir_emit(ctx, dblock->files[fi].filename, + SIMPLEFS_FILENAME_LEN, + dblock->files[fi].inode, DT_UNKNOWN)) { + brelse(bh2); + bh2 = NULL; + goto release_bh; + } + + ctx->pos++; + } + } + fi += dblock->files[fi].nr_blk; } brelse(bh2); bh2 = NULL; diff --git a/file.c b/file.c index f6868c0..96c8e84 100644 --- a/file.c +++ b/file.c @@ -51,14 +51,14 @@ static int simplefs_file_get_block(struct inode *inode, ret = 0; goto brelse_index; } - bno = get_free_blocks(sb, 8); + bno = get_free_blocks(sb, SIMPLEFS_MAX_BLOCKS_PER_EXTENT); if (!bno) { ret = -ENOSPC; goto brelse_index; } index->extents[extent].ee_start = bno; - index->extents[extent].ee_len = 8; + index->extents[extent].ee_len = SIMPLEFS_MAX_BLOCKS_PER_EXTENT; index->extents[extent].ee_block = extent ? index->extents[extent - 1].ee_block + index->extents[extent - 1].ee_len @@ -386,13 +386,13 @@ static ssize_t simplefs_write(struct file *file, while (len > 0) { /* check if block is allocated */ if (ei_block->extents[ei_index].ee_start == 0) { - int bno = get_free_blocks(sb, 8); + int bno = get_free_blocks(sb, SIMPLEFS_MAX_BLOCKS_PER_EXTENT); if (!bno) { bytes_write = -ENOSPC; break; } ei_block->extents[ei_index].ee_start = bno; - ei_block->extents[ei_index].ee_len = 8; + ei_block->extents[ei_index].ee_len = SIMPLEFS_MAX_BLOCKS_PER_EXTENT; ei_block->extents[ei_index].ee_block = ei_index ? ei_block->extents[ei_index - 1].ee_block + ei_block->extents[ei_index - 1].ee_len diff --git a/inode.c b/inode.c index 17ab21d..4ba8b73 100644 --- a/inode.c +++ b/inode.c @@ -153,7 +153,7 @@ static struct dentry *simplefs_lookup(struct inode *dir, dblock = (struct simplefs_dir_block *) bh2->b_data; /* Search file in ei_block */ - for (fi = 0; fi < SIMPLEFS_FILES_PER_BLOCK; fi++) { + for (fi = 0; fi < dblock->nr_files;) { f = &dblock->files[fi]; if (!f->inode) { brelse(bh2); @@ -165,6 +165,7 @@ static struct dentry *simplefs_lookup(struct inode *dir, brelse(bh2); goto search_end; } + fi += dblock->files[fi].nr_blk; } brelse(bh2); bh2 = NULL; @@ -173,7 +174,7 @@ static struct dentry *simplefs_lookup(struct inode *dir, search_end: brelse(bh); - + bh = NULL; /* Update directory access time */ #if SIMPLEFS_AT_LEAST(6, 7, 0) inode_set_atime_to_ts(dir, current_time(dir)); @@ -312,6 +313,88 @@ static struct inode *simplefs_new_inode(struct inode *dir, mode_t mode) return ERR_PTR(ret); } +static uint32_t simplefs_get_available_ext_idx( + int *dir_nr_files, + struct simplefs_file_ei_block *eblock) +{ + int ei = 0; + uint32_t first_empty_blk = -1; + for (ei = 0; ei < SIMPLEFS_MAX_EXTENTS; ei++) { + if (eblock->extents[ei].ee_start && + eblock->extents[ei].nr_files != SIMPLEFS_FILES_PER_EXT) { + first_empty_blk = ei; + break; + } else if (!eblock->extents[ei].ee_start) { + if (first_empty_blk == -1) + first_empty_blk = ei; + } else { + *dir_nr_files -= eblock->extents[ei].nr_files; + if (first_empty_blk == -1 && !*dir_nr_files) + first_empty_blk = ei + 1; + } + if (!*dir_nr_files) + break; + } + return first_empty_blk; +} + +static int simplefs_put_new_ext(struct super_block *sb, + uint32_t ei, + struct simplefs_file_ei_block *eblock) +{ + int bno, bi; + struct buffer_head *bh; + struct simplefs_dir_block *dblock; + bno = get_free_blocks(sb, SIMPLEFS_MAX_BLOCKS_PER_EXTENT); + if (!bno) + return -ENOSPC; + + eblock->extents[ei].ee_start = bno; + eblock->extents[ei].ee_len = SIMPLEFS_MAX_BLOCKS_PER_EXTENT; + eblock->extents[ei].ee_block = + ei ? eblock->extents[ei - 1].ee_block + eblock->extents[ei - 1].ee_len + : 0; + eblock->extents[ei].nr_files = 0; + + /* clear the ext block*/ + /* TODO: fix from 8 to dynamic value */ + for (bi = 0; bi < eblock->extents[ei].ee_len; bi++) { + bh = sb_bread(sb, eblock->extents[ei].ee_start + bi); + if (!bh) + return -EIO; + + dblock = (struct simplefs_dir_block *) bh->b_data; + memset(dblock, 0, sizeof(struct simplefs_dir_block)); + dblock->files[0].nr_blk = SIMPLEFS_FILES_PER_BLOCK; + brelse(bh); + } + return 0; +} + +static void simplefs_set_file_into_dir(struct simplefs_dir_block *dblock, + uint32_t inode_no, + const char *name) +{ + int fi; + if (dblock->nr_files != 0 && dblock->files[0].inode != 0) { + for (fi = 0; fi < SIMPLEFS_FILES_PER_BLOCK - 1; fi++) { + if (dblock->files[fi].nr_blk != 1) + break; + } + dblock->files[fi + 1].inode = inode_no; + dblock->files[fi + 1].nr_blk = dblock->files[fi].nr_blk - 1; + strncpy(dblock->files[fi + 1].filename, name, SIMPLEFS_FILENAME_LEN); + dblock->files[fi].nr_blk = 1; + } else if (dblock->nr_files == 0) { + dblock->files[fi].inode = inode_no; + strncpy(dblock->files[fi].filename, name, SIMPLEFS_FILENAME_LEN); + } else { + dblock->files[0].inode = inode_no; + strncpy(dblock->files[fi].filename, name, SIMPLEFS_FILENAME_LEN); + } + dblock->nr_files++; +} + /* Create a file or directory in this way: * - check filename length and if the parent directory is not full * - create the new inode (allocate inode and blocks) @@ -344,12 +427,12 @@ static int simplefs_create(struct inode *dir, struct simplefs_dir_block *dblock; char *fblock; struct buffer_head *bh, *bh2; - + uint32_t dir_nr_files = 0, avail; #if SIMPLEFS_AT_LEAST(6, 6, 0) && SIMPLEFS_LESS_EQUAL(6, 7, 0) struct timespec64 cur_time; #endif - int ret = 0, alloc = false, bno = 0; - int ei = 0, bi = 0, fi = 0; + int ret = 0, alloc = false; + int bi = 0; /* Check filename length */ if (strlen(dentry->d_name.name) > SIMPLEFS_FILENAME_LEN) @@ -389,35 +472,42 @@ static int simplefs_create(struct inode *dir, mark_buffer_dirty(bh2); brelse(bh2); - /* Find first free slot in parent index and register new inode */ - ei = eblock->nr_files / SIMPLEFS_FILES_PER_EXT; - bi = eblock->nr_files % SIMPLEFS_FILES_PER_EXT / SIMPLEFS_FILES_PER_BLOCK; - fi = eblock->nr_files % SIMPLEFS_FILES_PER_BLOCK; + dir_nr_files = eblock->nr_files; + avail = simplefs_get_available_ext_idx(&dir_nr_files, eblock); - if (!eblock->extents[ei].ee_start) { - bno = get_free_blocks(sb, 8); - if (!bno) { + /* if there is not any empty space, alloc new one */ + if (!dir_nr_files && !eblock->extents[avail].ee_start) { + ret = simplefs_put_new_ext(sb, avail, eblock); + switch (ret) { + case -ENOSPC: ret = -ENOSPC; goto iput; + case -EIO: + ret = -EIO; + goto put_block; } - eblock->extents[ei].ee_start = bno; - eblock->extents[ei].ee_len = 8; - eblock->extents[ei].ee_block = ei ? eblock->extents[ei - 1].ee_block + - eblock->extents[ei - 1].ee_len - : 0; alloc = true; } - bh2 = sb_bread(sb, eblock->extents[ei].ee_start + bi); - if (!bh2) { - ret = -EIO; - goto put_block; + + /* TODO: fix from 8 to dynamic value */ + /* Find which simplefs_dir_block has free space */ + for (bi = 0; bi < eblock->extents[avail].ee_len; bi++) { + bh2 = sb_bread(sb, eblock->extents[avail].ee_start + bi); + if (!bh2) { + ret = -EIO; + goto put_block; + } + dblock = (struct simplefs_dir_block *) bh2->b_data; + if (dblock->nr_files != SIMPLEFS_FILES_PER_BLOCK) + break; + else + brelse(bh2); } - dblock = (struct simplefs_dir_block *) bh2->b_data; - dblock->files[fi].inode = inode->i_ino; - strncpy(dblock->files[fi].filename, dentry->d_name.name, - SIMPLEFS_FILENAME_LEN); + /* write the file info into simplefs_dir_block */ + simplefs_set_file_into_dir(dblock, inode->i_ino, dentry->d_name.name); + eblock->extents[avail].nr_files++; eblock->nr_files++; mark_buffer_dirty(bh2); mark_buffer_dirty(bh); @@ -447,10 +537,10 @@ static int simplefs_create(struct inode *dir, return 0; put_block: - if (alloc && eblock->extents[ei].ee_start) { - put_blocks(SIMPLEFS_SB(sb), eblock->extents[ei].ee_start, - eblock->extents[ei].ee_len); - memset(&eblock->extents[ei], 0, sizeof(struct simplefs_extent)); + if (alloc && eblock->extents[avail].ee_start) { + put_blocks(SIMPLEFS_SB(sb), eblock->extents[avail].ee_start, + eblock->extents[avail].ee_len); + memset(&eblock->extents[avail], 0, sizeof(struct simplefs_extent)); } iput: put_blocks(SIMPLEFS_SB(sb), SIMPLEFS_INODE(inode)->ei_block, 1); @@ -465,9 +555,9 @@ static int simplefs_remove_from_dir(struct inode *dir, struct dentry *dentry) { struct super_block *sb = dir->i_sb; struct inode *inode = d_inode(dentry); - struct buffer_head *bh = NULL, *bh2 = NULL, *bh_prev = NULL; + struct buffer_head *bh = NULL, *bh2 = NULL; struct simplefs_file_ei_block *eblock = NULL; - struct simplefs_dir_block *dblock = NULL, *dblock_prev = NULL; + struct simplefs_dir_block *dirblk = NULL; int ei = 0, bi = 0, fi = 0; int ret = 0, found = false; @@ -477,62 +567,52 @@ static int simplefs_remove_from_dir(struct inode *dir, struct dentry *dentry) return -EIO; eblock = (struct simplefs_file_ei_block *) bh->b_data; - for (ei = 0; ei < SIMPLEFS_MAX_EXTENTS; ei++) { - if (!eblock->extents[ei].ee_start) - break; - - for (bi = 0; bi < eblock->extents[ei].ee_len; bi++) { - bh2 = sb_bread(sb, eblock->extents[ei].ee_start + bi); - if (!bh2) { - ret = -EIO; - goto release_bh; - } - dblock = (struct simplefs_dir_block *) bh2->b_data; - if (!dblock->files[0].inode) - break; - - if (found) { - memmove(dblock_prev->files + SIMPLEFS_FILES_PER_BLOCK - 1, - dblock->files, sizeof(struct simplefs_file)); - brelse(bh_prev); - memmove(dblock->files, dblock->files + 1, - (SIMPLEFS_FILES_PER_BLOCK - 1) * - sizeof(struct simplefs_file)); - memset(dblock->files + SIMPLEFS_FILES_PER_BLOCK - 1, 0, - sizeof(struct simplefs_file)); - mark_buffer_dirty(bh2); - - bh_prev = bh2; - dblock_prev = dblock; - continue; - } - /* Remove file from parent directory */ - for (fi = 0; fi < SIMPLEFS_FILES_PER_BLOCK; fi++) { - if (dblock->files[fi].inode == inode->i_ino && - !strcmp(dblock->files[fi].filename, dentry->d_name.name)) { - found = true; - if (fi != SIMPLEFS_FILES_PER_BLOCK - 1) { - memmove(dblock->files + fi, dblock->files + fi + 1, - (SIMPLEFS_FILES_PER_BLOCK - fi - 1) * - sizeof(struct simplefs_file)); + int dir_nr_files = eblock->nr_files; + for (ei = 0; dir_nr_files; ei++) { + if (eblock->extents[ei].ee_start) { + dir_nr_files -= eblock->extents[ei].nr_files; + for (bi = 0; bi < eblock->extents[ei].ee_len; bi++) { + bh2 = sb_bread(sb, eblock->extents[ei].ee_start + bi); + if (!bh2) { + ret = -EIO; + goto release_bh; + } + dirblk = (struct simplefs_dir_block *) bh2->b_data; + int blk_nr_files = dirblk->nr_files; + for (fi = 0; blk_nr_files && fi < SIMPLEFS_FILES_PER_BLOCK;) { + if (dirblk->files[fi].inode) { + if (dirblk->files[fi].inode == inode->i_ino && + !strcmp(dirblk->files[fi].filename, + dentry->d_name.name)) { + found = true; + dirblk->files[fi].inode = 0; + /* merge the empty data */ + for (int i = fi - 1; i >= 0; i--) { + if (dirblk->files[i].inode != 0 || i == 0) { + dirblk->files[i].nr_blk += + dirblk->files[fi].nr_blk; + break; + } + } + dirblk->nr_files--; + eblock->extents[ei].nr_files--; + eblock->nr_files--; + mark_buffer_dirty(bh2); + brelse(bh2); + found = true; + goto found_data; + } + blk_nr_files--; } - memset(dblock->files + SIMPLEFS_FILES_PER_BLOCK - 1, 0, - sizeof(struct simplefs_file)); - mark_buffer_dirty(bh2); - bh_prev = bh2; - dblock_prev = dblock; - break; + fi += dirblk->files[fi].nr_blk; } - } - if (!found) brelse(bh2); + } } } +found_data: if (found) { - if (bh_prev) - brelse(bh_prev); - eblock->nr_files--; mark_buffer_dirty(bh); } release_bh: @@ -554,6 +634,7 @@ static int simplefs_unlink(struct inode *dir, struct dentry *dentry) struct inode *inode = d_inode(dentry); struct buffer_head *bh = NULL, *bh2 = NULL; struct simplefs_file_ei_block *file_block = NULL; + char *block; #if SIMPLEFS_AT_LEAST(6, 6, 0) && SIMPLEFS_LESS_EQUAL(6, 7, 0) struct timespec64 cur_time; #endif @@ -605,8 +686,6 @@ static int simplefs_unlink(struct inode *dir, struct dentry *dentry) file_block = (struct simplefs_file_ei_block *) bh->b_data; for (ei = 0; ei < SIMPLEFS_MAX_EXTENTS; ei++) { - char *block; - if (!file_block->extents[ei].ee_start) break; @@ -722,9 +801,12 @@ static int simplefs_rename(struct inode *old_dir, } dblock = (struct simplefs_dir_block *) bh2->b_data; - for (fi = 0; fi < SIMPLEFS_FILES_PER_BLOCK; fi++) { + int blk_nr_files = dblock->nr_files; + for (fi = 0; blk_nr_files;) { + /* src and target are the same dir (inode is same) */ if (new_dir == old_dir) { - if (!strncmp(dblock->files[fi].filename, + if (dblock->files[fi].inode && + !strncmp(dblock->files[fi].filename, old_dentry->d_name.name, SIMPLEFS_FILENAME_LEN)) { strncpy(dblock->files[fi].filename, @@ -733,19 +815,26 @@ static int simplefs_rename(struct inode *old_dir, brelse(bh2); goto release_new; } + } else { + /* src and target are different, then check if the + same name in the target directory */ + if (dblock->files[fi].inode && + !strncmp(dblock->files[fi].filename, + new_dentry->d_name.name, + SIMPLEFS_FILENAME_LEN)) { + brelse(bh2); + ret = -EEXIST; + goto release_new; + } + /* find the empty index in target directory */ + if (new_pos < 0 && dblock->files[fi].nr_blk != 1) { + new_pos = fi + 1; + break; + } } - if (!strncmp(dblock->files[fi].filename, - new_dentry->d_name.name, SIMPLEFS_FILENAME_LEN)) { - brelse(bh2); - ret = -EEXIST; - goto release_new; - } - if (new_pos < 0 && !dblock->files[fi].inode) { - new_pos = fi; - break; - } + blk_nr_files--; + fi += dblock->files[fi].nr_blk; } - brelse(bh2); } } @@ -759,13 +848,13 @@ static int simplefs_rename(struct inode *old_dir, /* insert in new parent directory */ /* Get new freeblocks for extent if needed*/ if (new_pos < 0) { - bno = get_free_blocks(sb, 8); + bno = get_free_blocks(sb, SIMPLEFS_MAX_BLOCKS_PER_EXTENT); if (!bno) { ret = -ENOSPC; goto release_new; } eblock_new->extents[ei].ee_start = bno; - eblock_new->extents[ei].ee_len = 8; + eblock_new->extents[ei].ee_len = SIMPLEFS_MAX_BLOCKS_PER_EXTENT; eblock_new->extents[ei].ee_block = ei ? eblock_new->extents[ei - 1].ee_block + eblock_new->extents[ei - 1].ee_len @@ -890,14 +979,15 @@ static int simplefs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { - struct inode *inode = d_inode(old_dentry); - struct super_block *sb = inode->i_sb; + struct inode *old_inode = d_inode(old_dentry); + struct super_block *sb = old_inode->i_sb; struct simplefs_inode_info *ci_dir = SIMPLEFS_INODE(dir); struct simplefs_file_ei_block *eblock = NULL; struct simplefs_dir_block *dblock; struct buffer_head *bh = NULL, *bh2 = NULL; - int ret = 0, alloc = false, bno = 0; - int ei = 0, bi = 0, fi = 0; + int ret = 0, alloc = false; + int ei = 0, bi = 0; + uint32_t avail; bh = sb_bread(sb, ci_dir->ei_block); if (!bh) @@ -910,33 +1000,40 @@ static int simplefs_link(struct dentry *old_dentry, goto end; } - ei = eblock->nr_files / SIMPLEFS_FILES_PER_EXT; - bi = eblock->nr_files % SIMPLEFS_FILES_PER_EXT / SIMPLEFS_FILES_PER_BLOCK; - fi = eblock->nr_files % SIMPLEFS_FILES_PER_BLOCK; + int dir_nr_files = eblock->nr_files; + avail = simplefs_get_available_ext_idx(&dir_nr_files, eblock); - if (eblock->extents[ei].ee_start == 0) { - bno = get_free_blocks(sb, 8); - if (!bno) { + /* if there is not any empty space, alloc new one */ + if (!dir_nr_files && !eblock->extents[avail].ee_start) { + ret = simplefs_put_new_ext(sb, avail, eblock); + switch (ret) { + case -ENOSPC: ret = -ENOSPC; goto end; + case -EIO: + ret = -EIO; + goto put_block; } - eblock->extents[ei].ee_start = bno; - eblock->extents[ei].ee_len = 8; - eblock->extents[ei].ee_block = ei ? eblock->extents[ei - 1].ee_block + - eblock->extents[ei - 1].ee_len - : 0; alloc = true; } - bh2 = sb_bread(sb, eblock->extents[ei].ee_start + bi); - if (!bh2) { - ret = -EIO; - goto put_block; + + /* TODO: fix from 8 to dynamic value */ + /* Find which simplefs_dir_block has free space */ + for (bi = 0; bi < eblock->extents[avail].ee_len; bi++) { + bh2 = sb_bread(sb, eblock->extents[avail].ee_start + bi); + if (!bh2) { + ret = -EIO; + goto put_block; + } + dblock = (struct simplefs_dir_block *) bh2->b_data; + if (dblock->nr_files != SIMPLEFS_FILES_PER_BLOCK) + break; + else + brelse(bh2); } - dblock = (struct simplefs_dir_block *) bh2->b_data; - dblock->files[fi].inode = inode->i_ino; - strncpy(dblock->files[fi].filename, dentry->d_name.name, - SIMPLEFS_FILENAME_LEN); + /* write the file info into simplefs_dir_block */ + simplefs_set_file_into_dir(dblock, old_inode->i_ino, dentry->d_name.name); eblock->nr_files++; mark_buffer_dirty(bh2); @@ -944,9 +1041,9 @@ static int simplefs_link(struct dentry *old_dentry, brelse(bh2); brelse(bh); - inode_inc_link_count(inode); - ihold(inode); - d_instantiate(dentry, inode); + inode_inc_link_count(old_inode); + ihold(old_inode); + d_instantiate(dentry, old_inode); return ret; put_block: @@ -984,8 +1081,9 @@ static int simplefs_symlink(struct inode *dir, struct simplefs_file_ei_block *eblock = NULL; struct simplefs_dir_block *dblock = NULL; struct buffer_head *bh = NULL, *bh2 = NULL; - int ret = 0, alloc = false, bno = 0; - int ei = 0, bi = 0, fi = 0; + int ret = 0, alloc = false; + int ei = 0, bi = 0; + uint32_t avail; /* Check if symlink content is not too long */ if (l > sizeof(ci->i_data)) @@ -1003,34 +1101,40 @@ static int simplefs_symlink(struct inode *dir, goto end; } - ei = eblock->nr_files / SIMPLEFS_FILES_PER_EXT; - bi = eblock->nr_files % SIMPLEFS_FILES_PER_EXT / SIMPLEFS_FILES_PER_BLOCK; - fi = eblock->nr_files % SIMPLEFS_FILES_PER_BLOCK; + int dir_nr_files = eblock->nr_files; + avail = simplefs_get_available_ext_idx(&dir_nr_files, eblock); - if (eblock->extents[ei].ee_start == 0) { - bno = get_free_blocks(sb, 8); - if (!bno) { + /* if there is not any empty space, alloc new one */ + if (!dir_nr_files && !eblock->extents[avail].ee_start) { + ret = simplefs_put_new_ext(sb, avail, eblock); + switch (ret) { + case -ENOSPC: ret = -ENOSPC; goto end; + case -EIO: + ret = -EIO; + goto put_block; } - eblock->extents[ei].ee_start = bno; - eblock->extents[ei].ee_len = 8; - eblock->extents[ei].ee_block = ei ? eblock->extents[ei - 1].ee_block + - eblock->extents[ei - 1].ee_len - : 0; alloc = true; } - bh2 = sb_bread(sb, eblock->extents[ei].ee_start + bi); - if (!bh2) { - ret = -EIO; - goto put_block; + /* TODO: fix from 8 to dynamic value */ + /* Find which simplefs_dir_block has free space */ + for (bi = 0; bi < eblock->extents[avail].ee_len; bi++) { + bh2 = sb_bread(sb, eblock->extents[avail].ee_start + bi); + if (!bh2) { + ret = -EIO; + goto put_block; + } + dblock = (struct simplefs_dir_block *) bh2->b_data; + if (dblock->nr_files != SIMPLEFS_FILES_PER_BLOCK) + break; + else + brelse(bh2); } - dblock = (struct simplefs_dir_block *) bh2->b_data; - dblock->files[fi].inode = inode->i_ino; - strncpy(dblock->files[fi].filename, dentry->d_name.name, - SIMPLEFS_FILENAME_LEN); + /* write the file info into simplefs_dir_block */ + simplefs_set_file_into_dir(dblock, inode->i_ino, dentry->d_name.name); eblock->nr_files++; mark_buffer_dirty(bh2); diff --git a/script/config b/script/config index eee67b3..2062ef0 100644 --- a/script/config +++ b/script/config @@ -3,8 +3,8 @@ F_MOD="-rw-r--r--" S_MOD="lrwxrwxrwx" SIMPLEFS_MAX_BLOCKS_PER_EXTENT=8 SIMPLEFS_BLOCK_SIZE=4096 -SIMPLEFS_MAX_EXTENTS=$(( ($SIMPLEFS_BLOCK_SIZE - 4) / 16 )) +SIMPLEFS_FILES_PER_BLOCK=15 +SIMPLEFS_MAX_EXTENTS=255 # $(( ($SIMPLEFS_BLOCK_SIZE - 4) / 16 )) MAXFILESIZE=$(( $SIMPLEFS_MAX_EXTENTS * $SIMPLEFS_MAX_BLOCKS_PER_EXTENT * $SIMPLEFS_BLOCK_SIZE )) -# MAXFILES=1173 # max files per dir -MAXFILES=30600 # max files per dir +MAXFILES=$(( $SIMPLEFS_MAX_EXTENTS * $SIMPLEFS_MAX_BLOCKS_PER_EXTENT * $SIMPLEFS_FILES_PER_BLOCK )) # 36000 MOUNT_TEST=100 diff --git a/script/rand_rm_and_create.sh b/script/rand_rm_and_create.sh new file mode 100755 index 0000000..f6774b4 --- /dev/null +++ b/script/rand_rm_and_create.sh @@ -0,0 +1,46 @@ +# test create max nr files +test_create_max_nr_files() { + echo + echo "max size $MAXFILES" + for ((i=0; i<=$MAXFILES; i++)) + do + test_op "touch $i.txt" Failed # expected to fail with more than $MAXFILES files + done + sync + filecnts=$(ls | wc -w) + test $filecnts -eq $MAXFILES || echo "Failed($filecnts), it should be $MAXFILES files" +} + +test_rm_all_files() { + echo + echo "remove all files" + find . -name '[0-9]*.txt' | xargs -n 2000 sudo rm + sync +} + +test_rand_access_files() { + STARTNR=$1 + INTERVAL=$2 + echo + echo "remove from $STARTNR, interval: $INTERVAL, Max: $MAXFILES" + for ((i=$STARTNR; i<$MAXFILES; i+=$INTERVAL)) + do + test_op "rm $i.txt" Failed + done + echo "create from $STARTNR, interval: $INTERVAL, Max: $MAXFILES" + for ((i=$STARTNR; i<$MAXFILES; i+=$INTERVAL)) + do + test_op "touch $i"_1".txt" Failed + done + echo +} + +test_rand_access_files_exist() { + echo + echo "quick check files" + for ((i=0; i<$MAXFILES; i++)) + do + quick_check_exist $i"_1".txt + done + echo +} diff --git a/script/test.sh b/script/test.sh index df695a8..80b1c50 100755 --- a/script/test.sh +++ b/script/test.sh @@ -1,9 +1,10 @@ #!/usr/bin/env bash +. script/config . script/test_func.sh . script/test_large_file.sh . script/test_remount.sh -. script/config +. script/rand_rm_and_create.sh SIMPLEFS_MOD=simplefs.ko IMAGE=$1 @@ -31,6 +32,15 @@ pushd test >/dev/null # test serial to write test_create_max_nr_files + +test_rand_access_files 0 2 +sync +test_rand_access_files 1 2 +sync +test_rand_access_files_exist +sync +test_rm_all_files + # test remount file exist or not test_remount_file_exist diff --git a/script/test_func.sh b/script/test_func.sh index f1b7a4e..2a483dc 100644 --- a/script/test_func.sh +++ b/script/test_func.sh @@ -1,16 +1,22 @@ test_op() { local op=$1 - echo - echo -n "Testing cmd: $op..." - sudo sh -c "$op" >/dev/null && echo "Success" + local option=${2:-Success} + + if [ "$option" = "Success" ]; then + sudo sh -c "$op" >/dev/null && echo "Testing cmd: $op... Success" + elif [ "$option" = "Failed" ]; then + sudo sh -c "$op" >/dev/null || echo "Testing cmd: $op... Failed" + fi } check_exist() { local mode=$1 local nlink=$2 local name=$3 - echo - echo -n "Check if exist: $mode $nlink $name..." - sudo ls -lR | grep -e "$mode $nlink".*$name >/dev/null && echo "Success" || \ - echo "Failed" + sudo ls -lR | grep -e "$mode $nlink".*$name >/dev/null || echo "Failed" +} + +quick_check_exist() { + local name=$1 + [ ! -f $name ] && echo "Not found: $name" } diff --git a/script/test_large_file.sh b/script/test_large_file.sh index bd1b364..dc8f810 100755 --- a/script/test_large_file.sh +++ b/script/test_large_file.sh @@ -2,22 +2,27 @@ test_too_large_file() { TESTLG_FILE_SZ=$(( $MAXFILESIZE / 1024 / 1024 + 1 )) test_op "dd if=/dev/zero of=exceed_max_sz_file bs=1M count=$TESTLG_FILE_SZ status=none" + echo filesize=$(sudo ls -lR | grep -e "$F_MOD 1".*file | awk '{print $5}') test $filesize -le $MAXFILESIZE || echo "Failed, file size over the limit" test_op 'rm exceed_max_sz_file' + echo } # 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" > exceed_blk.txt' + echo count=$(awk '{count += gsub(/123456789/, "")} END {print count}' "exceed_blk.txt") echo "test $count" test "$count" -eq 1600 || echo "Failed, file size not matching" # test block to write test_op 'cat exceed_blk.txt > checkfile.txt' + echo count=$(awk '{count += gsub(/123456789/, "")} END {print count}' "checkfile.txt") echo "test $count" test "$count" -eq 1600 || echo "Failed, file size not matching" test_op 'rm exceed_blk.txt checkfile.txt' + echo } diff --git a/script/test_remount.sh b/script/test_remount.sh index d3f2ce4..f7e6b57 100644 --- a/script/test_remount.sh +++ b/script/test_remount.sh @@ -1,18 +1,3 @@ -# test create max nr files -test_create_max_nr_files() { - echo "max size $MAXFILESIZE" - # create 40920 files - for ((i=0; i<=$MAXFILES; i++)) - do - test_op "touch $i.txt" # expected to fail with more than 40920 files - done - sync - filecnts=$(ls | wc -w) - test $filecnts -eq $MAXFILES || echo "Failed($filecnts), it should be $MAXFILES files" - find . -name '[0-9]*.txt' | xargs -n 2000 sudo rm - sync -} - # create 100 files with filenames inside test_remount_file_exist() { for ((i=1; i<=$MOUNT_TEST; i++)) diff --git a/simplefs.h b/simplefs.h index e365a82..f99353f 100644 --- a/simplefs.h +++ b/simplefs.h @@ -81,6 +81,7 @@ struct simplefs_extent { uint32_t ee_block; /* first logical block extent covers */ uint32_t ee_len; /* number of blocks covered by extent */ uint32_t ee_start; /* first physical block extent covers */ + uint32_t nr_files; /* Number of files in this extent */ }; struct simplefs_file_ei_block { @@ -90,10 +91,12 @@ struct simplefs_file_ei_block { struct simplefs_file { uint32_t inode; + uint32_t nr_blk; char filename[SIMPLEFS_FILENAME_LEN]; }; struct simplefs_dir_block { + uint32_t nr_files; struct simplefs_file files[SIMPLEFS_FILES_PER_BLOCK]; }; diff --git a/super.c b/super.c index 2e4924f..019944e 100644 --- a/super.c +++ b/super.c @@ -597,6 +597,7 @@ int simplefs_fill_super(struct super_block *sb, void *data, int silent) brelse(bh); } + bh = NULL; /* Allocate and copy bfree_bitmap */ sbi->bfree_bitmap = @@ -621,6 +622,7 @@ int simplefs_fill_super(struct super_block *sb, void *data, int silent) brelse(bh); } + bh = NULL; /* Create root inode */ root_inode = simplefs_iget(sb, 1); if (IS_ERR(root_inode)) {