From 8cf581b7856095308ddbaa41ddec48a2ade5f344 Mon Sep 17 00:00:00 2001 From: roy Date: Tue, 11 Nov 2025 04:54:58 +0800 Subject: [PATCH 1/7] Optimize the file iteration Each `simplefs_extent` structure contains a counter that records the total number of files within that extent. When the counter matches the expected file number, it indicates there are no more files after this index, allowing the iterator to skip directly to the next extension block. This reduces unnecessary scanning and improves traversal efficiency. --- dir.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dir.c b/dir.c index e96484f..a326d98 100644 --- a/dir.c +++ b/dir.c @@ -62,9 +62,10 @@ static int simplefs_iterate(struct file *dir, struct dir_context *ctx) for (; remained_nr_files && ei < SIMPLEFS_MAX_EXTENTS; ei++) { if (eblock->extents[ei].ee_start == 0) continue; - + int ei_nr = eblock->extents[ei].nr_files; /* Iterate over blocks in one extent */ - for (bi = 0; bi < eblock->extents[ei].ee_len && remained_nr_files; + for (bi = 0; + bi < eblock->extents[ei].ee_len && remained_nr_files && ei_nr; bi++) { bh2 = sb_bread(sb, eblock->extents[ei].ee_start + bi); if (!bh2) { @@ -86,6 +87,7 @@ static int simplefs_iterate(struct file *dir, struct dir_context *ctx) offset--; } else { remained_nr_files--; + ei_nr--; if (!dir_emit(ctx, dblock->files[fi].filename, SIMPLEFS_FILENAME_LEN, dblock->files[fi].inode, DT_UNKNOWN)) { From 94e38bbb6860ea00637c365c999505cbd9add0b7 Mon Sep 17 00:00:00 2001 From: roy Date: Tue, 11 Nov 2025 13:57:34 +0800 Subject: [PATCH 2/7] Rename variables for better readability --- inode.c | 116 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/inode.c b/inode.c index 634a935..663dcf2 100644 --- a/inode.c +++ b/inode.c @@ -753,31 +753,31 @@ static int simplefs_unlink(struct inode *dir, struct dentry *dentry) #if SIMPLEFS_AT_LEAST(6, 3, 0) static int simplefs_rename(struct mnt_idmap *id, - struct inode *old_dir, - struct dentry *old_dentry, - struct inode *new_dir, - struct dentry *new_dentry, + struct inode *src_dir, + struct dentry *src_dentry, + struct inode *dest_dir, + struct dentry *dest_dentry, unsigned int flags) #elif SIMPLEFS_AT_LEAST(5, 12, 0) static int simplefs_rename(struct user_namespace *ns, - struct inode *old_dir, - struct dentry *old_dentry, - struct inode *new_dir, - struct dentry *new_dentry, + struct inode *src_dir, + struct dentry *src_dentry, + struct inode *dest_dir, + struct dentry *dest_dentry, unsigned int flags) #else -static int simplefs_rename(struct inode *old_dir, - struct dentry *old_dentry, - struct inode *new_dir, - struct dentry *new_dentry, +static int simplefs_rename(struct inode *src_dir, + struct dentry *src_dentry, + struct inode *dest_dir, + struct dentry *dest_dentry, unsigned int flags) #endif { - struct super_block *sb = old_dir->i_sb; - struct simplefs_inode_info *ci_new = SIMPLEFS_INODE(new_dir); - struct inode *src = d_inode(old_dentry); + struct super_block *sb = src_dir->i_sb; + struct simplefs_inode_info *ci_dest = SIMPLEFS_INODE(dest_dir); + struct inode *src = d_inode(src_dentry); struct buffer_head *bh_new = NULL, *bh2 = NULL; - struct simplefs_file_ei_block *eblock_new = NULL; + struct simplefs_file_ei_block *eblk_dest = NULL; struct simplefs_dir_block *dblock = NULL; #if SIMPLEFS_AT_LEAST(6, 6, 0) && SIMPLEFS_LESS_EQUAL(6, 7, 0) @@ -792,21 +792,21 @@ static int simplefs_rename(struct inode *old_dir, return -EINVAL; /* Check if filename is not too long */ - if (strlen(new_dentry->d_name.name) > SIMPLEFS_FILENAME_LEN) + if (strlen(dest_dentry->d_name.name) > SIMPLEFS_FILENAME_LEN) return -ENAMETOOLONG; - /* Fail if new_dentry exists or if new_dir is full */ - bh_new = sb_bread(sb, ci_new->ei_block); + /* Fail if dest_dentry exists or if dest_dir is full */ + bh_new = sb_bread(sb, ci_dest->ei_block); if (!bh_new) return -EIO; - eblock_new = (struct simplefs_file_ei_block *) bh_new->b_data; + eblk_dest = (struct simplefs_file_ei_block *) bh_new->b_data; for (ei = 0; new_pos < 0 && ei < SIMPLEFS_MAX_EXTENTS; ei++) { - if (!eblock_new->extents[ei].ee_start) + if (!eblk_dest->extents[ei].ee_start) break; - for (bi = 0; new_pos < 0 && bi < eblock_new->extents[ei].ee_len; bi++) { - bh2 = sb_bread(sb, eblock_new->extents[ei].ee_start + bi); + for (bi = 0; new_pos < 0 && bi < eblk_dest->extents[ei].ee_len; bi++) { + bh2 = sb_bread(sb, eblk_dest->extents[ei].ee_start + bi); if (!bh2) { ret = -EIO; goto release_new; @@ -816,13 +816,13 @@ static int simplefs_rename(struct inode *old_dir, 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 (dest_dir == src_dir) { if (dblock->files[fi].inode && !strncmp(dblock->files[fi].filename, - old_dentry->d_name.name, + src_dentry->d_name.name, SIMPLEFS_FILENAME_LEN)) { strncpy(dblock->files[fi].filename, - new_dentry->d_name.name, SIMPLEFS_FILENAME_LEN); + dest_dentry->d_name.name, SIMPLEFS_FILENAME_LEN); mark_buffer_dirty(bh2); brelse(bh2); goto release_new; @@ -832,7 +832,7 @@ static int simplefs_rename(struct inode *old_dir, same name in the target directory */ if (dblock->files[fi].inode && !strncmp(dblock->files[fi].filename, - new_dentry->d_name.name, + dest_dentry->d_name.name, SIMPLEFS_FILENAME_LEN)) { brelse(bh2); ret = -EEXIST; @@ -852,7 +852,7 @@ static int simplefs_rename(struct inode *old_dir, } /* If new directory is full, fail */ - if (new_pos < 0 && eblock_new->nr_files == SIMPLEFS_FILES_PER_EXT) { + if (new_pos < 0 && eblk_dest->nr_files == SIMPLEFS_FILES_PER_EXT) { ret = -EMLINK; goto release_new; } @@ -865,13 +865,13 @@ static int simplefs_rename(struct inode *old_dir, ret = -ENOSPC; goto release_new; } - eblock_new->extents[ei].ee_start = bno; - 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 + eblk_dest->extents[ei].ee_start = bno; + eblk_dest->extents[ei].ee_len = SIMPLEFS_MAX_BLOCKS_PER_EXTENT; + eblk_dest->extents[ei].ee_block = + ei ? eblk_dest->extents[ei - 1].ee_block + + eblk_dest->extents[ei - 1].ee_len : 0; - bh2 = sb_bread(sb, eblock_new->extents[ei].ee_start + 0); + bh2 = sb_bread(sb, eblk_dest->extents[ei].ee_start + 0); if (!bh2) { ret = -EIO; goto put_block; @@ -881,55 +881,55 @@ static int simplefs_rename(struct inode *old_dir, new_pos = 0; } dblock->files[new_pos].inode = src->i_ino; - strncpy(dblock->files[new_pos].filename, new_dentry->d_name.name, + strncpy(dblock->files[new_pos].filename, dest_dentry->d_name.name, SIMPLEFS_FILENAME_LEN); mark_buffer_dirty(bh2); brelse(bh2); /* Update new parent inode metadata */ #if SIMPLEFS_AT_LEAST(6, 7, 0) - simple_inode_init_ts(new_dir); + simple_inode_init_ts(dest_dir); #elif SIMPLEFS_AT_LEAST(6, 6, 0) - cur_time = current_time(new_dir); - new_dir->i_atime = new_dir->i_mtime = cur_time; - inode_set_ctime_to_ts(new_dir, cur_time); + cur_time = current_time(dest_dir); + dest_dir->i_atime = dest_dir->i_mtime = cur_time; + inode_set_ctime_to_ts(dest_dir, cur_time); #else - new_dir->i_atime = new_dir->i_ctime = new_dir->i_mtime = - current_time(new_dir); + dest_dir->i_atime = dest_dir->i_ctime = dest_dir->i_mtime = + current_time(dest_dir); #endif if (S_ISDIR(src->i_mode)) - inc_nlink(new_dir); - mark_inode_dirty(new_dir); + inc_nlink(dest_dir); + mark_inode_dirty(dest_dir); /* remove target from old parent directory */ - ret = simplefs_remove_from_dir(old_dir, old_dentry); + ret = simplefs_remove_from_dir(src_dir, src_dentry); if (ret != 0) goto release_new; /* Update old parent inode metadata */ #if SIMPLEFS_AT_LEAST(6, 7, 0) - simple_inode_init_ts(old_dir); + simple_inode_init_ts(src_dir); #elif SIMPLEFS_AT_LEAST(6, 6, 0) - cur_time = current_time(old_dir); - old_dir->i_atime = old_dir->i_mtime = cur_time; - inode_set_ctime_to_ts(old_dir, cur_time); + cur_time = current_time(src_dir); + src_dir->i_atime = src_dir->i_mtime = cur_time; + inode_set_ctime_to_ts(src_dir, cur_time); #else - old_dir->i_atime = old_dir->i_ctime = old_dir->i_mtime = - current_time(old_dir); + src_dir->i_atime = src_dir->i_ctime = src_dir->i_mtime = + current_time(src_dir); #endif if (S_ISDIR(src->i_mode)) - drop_nlink(old_dir); - mark_inode_dirty(old_dir); + drop_nlink(src_dir); + mark_inode_dirty(src_dir); return ret; put_block: - if (eblock_new->extents[ei].ee_start) { - put_blocks(SIMPLEFS_SB(sb), eblock_new->extents[ei].ee_start, - eblock_new->extents[ei].ee_len); - memset(&eblock_new->extents[ei], 0, sizeof(struct simplefs_extent)); + if (eblk_dest->extents[ei].ee_start) { + put_blocks(SIMPLEFS_SB(sb), eblk_dest->extents[ei].ee_start, + eblk_dest->extents[ei].ee_len); + memset(&eblk_dest->extents[ei], 0, sizeof(struct simplefs_extent)); } release_new: brelse(bh_new); @@ -996,11 +996,11 @@ static int simplefs_rmdir(struct inode *dir, struct dentry *dentry) return simplefs_unlink(dir, dentry); } -static int simplefs_link(struct dentry *old_dentry, +static int simplefs_link(struct dentry *src_dentry, struct inode *dir, struct dentry *dentry) { - struct inode *old_inode = d_inode(old_dentry); + struct inode *old_inode = d_inode(src_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; From 7d6d3a7da02c13dcb406f65979c65d49b5d65399 Mon Sep 17 00:00:00 2001 From: hsule Date: Mon, 19 Jan 2026 16:40:56 +0800 Subject: [PATCH 3/7] Add macOS support for mkfs.simplefs mkfs.simplefs depended on Linux-only headers and ioctl calls, so the rv32emu CI could not run simplefs tests on macOS runners. Add macOS-specific endian helpers and detect block device size via DKIOCGETBLOCKCOUNT/DKIOCGETBLOCKSIZE while keeping the Linux path (BLKGETSIZE64) unchanged. Fixes: #78 Signed-off-by: hsule --- mkfs.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/mkfs.c b/mkfs.c index 59dd967..b50a009 100644 --- a/mkfs.c +++ b/mkfs.c @@ -1,5 +1,19 @@ +#if !defined(__linux__) && !defined(__APPLE__) +#error \ + "Do not manage to build this file unless your platform is Linux or macOS." +#endif + #include -#include +#if defined(__linux__) +#include /* BLKGETSIZE64 */ +#elif defined(__APPLE__) +#include +#include /* DKIOCGETBLOCKCOUNT and DKIOCGETBLOCKSIZE */ +#define htole32(x) OSSwapHostToLittleInt32(x) +#define le32toh(x) OSSwapLittleToHostInt32(x) +#define htole64(x) OSSwapHostToLittleInt64(x) +#define le64toh(x) OSSwapLittleToHostInt64(x) +#endif #include #include #include @@ -278,12 +292,31 @@ int main(int argc, char **argv) /* Get block device size */ if ((stat_buf.st_mode & S_IFMT) == S_IFBLK) { long int blk_size = 0; +#if defined(__linux__) ret = ioctl(fd, BLKGETSIZE64, &blk_size); if (ret != 0) { perror("BLKGETSIZE64:"); ret = EXIT_FAILURE; goto fclose; } +#elif defined(__APPLE__) + uint64_t block_count = 0; + uint32_t sector_size = 0; + + ret = ioctl(fd, DKIOCGETBLOCKCOUNT, &block_count); + if (ret) { + perror("DKIOCGETBLOCKCOUNT"); + ret = EXIT_FAILURE; + goto fclose; + } + ret = ioctl(fd, DKIOCGETBLOCKSIZE, §or_size); + if (ret) { + perror("DKIOCGETBLOCKSIZE"); + ret = EXIT_FAILURE; + goto fclose; + } + blk_size = block_count * sector_size; +#endif stat_buf.st_size = blk_size; } From dddf333b6fefcae9425cd3b9e88cf832a7288c84 Mon Sep 17 00:00:00 2001 From: hsule Date: Tue, 20 Jan 2026 01:25:11 +0800 Subject: [PATCH 4/7] CI: add macOS job to verify mkfs.simplefs Add a CI script to build mkfs.simplefs and format a test image on macOS runners. Signed-off-by: hsule --- .ci/test-mkfs-macos.sh | 21 +++++++++++++++++++++ .github/workflows/main.yaml | 10 ++++++++++ 2 files changed, 31 insertions(+) create mode 100755 .ci/test-mkfs-macos.sh diff --git a/.ci/test-mkfs-macos.sh b/.ci/test-mkfs-macos.sh new file mode 100755 index 0000000..cc90850 --- /dev/null +++ b/.ci/test-mkfs-macos.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +set -e + +IMAGE=test.img +IMAGESIZE=50 +MKFS=mkfs.simplefs + +function build_mkfs() +{ + make $MKFS +} + +function test_mkfs() +{ + dd if=/dev/zero of=$IMAGE bs=1M count=$IMAGESIZE 2>/dev/null + ./$MKFS $IMAGE +} + +build_mkfs +test_mkfs diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 8edb577..33687c8 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -26,3 +26,13 @@ jobs: .ci/check-newline.sh .ci/check-format.sh shell: bash + + mkfs_macos: + runs-on: macos-latest + steps: + - name: checkout code + uses: actions/checkout@v4 + - name: test mkfs.simplefs on macOS + run: | + .ci/test-mkfs-macos.sh + shell: bash From f14139f8bd6dff0452ad7a61cef76089119e9972 Mon Sep 17 00:00:00 2001 From: ibat10clw Date: Mon, 30 Mar 2026 15:12:28 +0800 Subject: [PATCH 5/7] Fix missing entries in simplefs_lookup simplefs_lookup must scan all entries in a directory before it can determine whether a file exists. The current implementation stops early when it encounters a hole in the directory, which can cause later files to be missed. In addition, fi is used as the index into dblock, so the loop should be bounded by SIMPLEFS_FILES_PER_BLOCK rather than dblock->nr_files. If a file is located near the end of the directory block, the loop may terminate early when fi >= dblock->nr_files, resulting in an incomplete scan. Fix this by skipping holes during filename comparison and continuing to advance fi until all live directory entries have been examined. --- inode.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/inode.c b/inode.c index 663dcf2..48c87fa 100644 --- a/inode.c +++ b/inode.c @@ -153,21 +153,21 @@ static struct dentry *simplefs_lookup(struct inode *dir, } dblock = (struct simplefs_dir_block *) bh2->b_data; - + int nr_files = dblock->nr_files; /* Search file in ei_block */ - for (fi = 0; fi < dblock->nr_files;) { + for (fi = 0; nr_files && fi < SIMPLEFS_FILES_PER_BLOCK;) { f = &dblock->files[fi]; - if (!f->inode) { - brelse(bh2); - goto search_end; - } - if (!strncmp(f->filename, dentry->d_name.name, - SIMPLEFS_FILENAME_LEN)) { - inode = simplefs_iget(sb, f->inode); - brelse(bh2); - goto search_end; + + if (f->inode) { + nr_files--; + if (!strncmp(f->filename, dentry->d_name.name, + SIMPLEFS_FILENAME_LEN)) { + inode = simplefs_iget(sb, f->inode); + brelse(bh2); + goto search_end; + } } - fi += dblock->files[fi].nr_blk; + fi += f->nr_blk; } brelse(bh2); bh2 = NULL; From 226cd48f013699170d3876fa73dc89f9cb1a3a15 Mon Sep 17 00:00:00 2001 From: RoyHuang Date: Fri, 3 Apr 2026 18:54:01 +0800 Subject: [PATCH 6/7] Use hash func to boost file creation and lookup Introduce a hash-based mechanism to speed up file creation and lookup operations. The hash function enables faster access to extent and logical block extent index, improving overall filesystem performance. hash_code = file_hash(file_name); extent index = hash_code / SIMPLEFS_MAX_BLOCKS_PER_EXTENT block index = hash_code % SIMPLEFS_MAX_BLOCKS_PER_EXTENT; Use perf to measure: 1. File Creation (random) Legacy: 259.842753513 seconds time elapsed 23.000247000 seconds user 150.380145000 seconds sys full_name_hash: 222.274028604 seconds time elapsed 20.794966000 seconds user 151.941876000 seconds sys 2. File Listing (random) Legacy: min time: 0.00171 s max time: 0.03799 s avg time: 0.00423332 s tot time: 129.539510 s full_name_hash: min time: 0.00171 s max time: 0.03588 s avg time: 0.00305601 s tot time: 93.514040 s 3. files Removal (Random) Legacy: 106.921706288 seconds time elapsed 16.987883000 seconds user 91.268661000 seconds sys full_name_hash: 86.132655220 seconds time elapsed 19.180209000 seconds user 68.476075000 seconds sys --- Makefile | 2 +- README.md | 2 +- dir.c | 2 +- hash.c | 15 ++ inode.c | 581 +++++++++++++++++++++++++++++++++++------------------ simplefs.h | 3 + 6 files changed, 403 insertions(+), 202 deletions(-) create mode 100644 hash.c diff --git a/Makefile b/Makefile index 8d10f24..067be34 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ obj-m += simplefs.o -simplefs-objs := fs.o super.o inode.o file.o dir.o extent.o +simplefs-objs := fs.o super.o inode.o file.o dir.o extent.o hash.o KDIR ?= /lib/modules/$(shell uname -r)/build diff --git a/README.md b/README.md index 441ba0b..a40ff67 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ named `ei_block`. This field, `ei_block`, serves different purposes depending on the type of file: - For a directory, it contains the list of files within that directory. A directory can hold a maximum of 40,920 files, with filenames restricted - to a maximum of 255 characters to ensure they fit within a single block. + to a maximum of 254 characters to ensure they fit within a single block. ``` inode +-----------------------+ diff --git a/dir.c b/dir.c index a326d98..95fb7ba 100644 --- a/dir.c +++ b/dir.c @@ -81,7 +81,7 @@ static int simplefs_iterate(struct file *dir, struct dir_context *ctx) continue; } - for (fi = 0; fi < SIMPLEFS_FILES_PER_BLOCK;) { + for (fi = 0; fi < SIMPLEFS_FILES_PER_BLOCK && dblock->nr_files;) { if (dblock->files[fi].inode != 0) { if (offset) { offset--; diff --git a/hash.c b/hash.c new file mode 100644 index 0000000..0926539 --- /dev/null +++ b/hash.c @@ -0,0 +1,15 @@ +#include +#include +#include "simplefs.h" + +uint32_t simplefs_hash(struct dentry *dentry) +{ + const char *str = dentry->d_name.name; + uint64_t h = 0xcbf29ce484222325ULL; + while (*str) { + h ^= (unsigned char) (*str++); + h *= 0x100000001b3ULL; + } + /* Fold high 32 bits into low 32 bits to mix the full 64-bit result */ + return (uint32_t) (h ^ (h >> 32)); +} diff --git a/inode.c b/inode.c index 48c87fa..294e5ee 100644 --- a/inode.c +++ b/inode.c @@ -11,6 +11,11 @@ static const struct inode_operations simplefs_inode_ops; static const struct inode_operations symlink_inode_ops; +#define CHECK_AND_SET_RING_INDEX(idx, len) \ + do { \ + if (unlikely(idx >= len)) \ + idx -= len; \ + } while (0) /* Either return the inode that corresponds to a given inode number (ino), if * it is already in the cache, or create a new inode object if it is not in the * cache. @@ -110,6 +115,76 @@ struct inode *simplefs_iget(struct super_block *sb, unsigned long ino) return ERR_PTR(ret); } +static int __file_lookup(struct inode *dir, + struct dentry *dentry, + int *ei, + int *bi, + int *fi) +{ + struct super_block *sb = dir->i_sb; + struct simplefs_inode_info *ci_dir = SIMPLEFS_INODE(dir); + 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, _bi, _fi, ret = -ENOENT; + int idx_ei, idx_bi; + uint32_t hash_code; + + /* Read the directory block on disk */ + bh = sb_bread(sb, ci_dir->ei_block); + if (!bh) + return -EIO; + eblock = (struct simplefs_file_ei_block *) bh->b_data; + hash_code = simplefs_hash(dentry) % + (SIMPLEFS_MAX_EXTENTS * SIMPLEFS_MAX_BLOCKS_PER_EXTENT); + _ei = hash_code / SIMPLEFS_MAX_BLOCKS_PER_EXTENT; + _bi = hash_code % SIMPLEFS_MAX_BLOCKS_PER_EXTENT; + int nr_ei_files = eblock->nr_files; + for (idx_ei = 0; nr_ei_files; _ei++, idx_ei++) { + CHECK_AND_SET_RING_INDEX(_ei, SIMPLEFS_MAX_EXTENTS); + + if (!eblock->extents[_ei].ee_start) + continue; + + nr_ei_files -= eblock->extents[_ei].nr_files; + /* Iterate blocks in extent */ + int nr_bi_files = eblock->extents[_ei].nr_files; + for (idx_bi = 0; nr_bi_files; _bi++, idx_bi++) { + CHECK_AND_SET_RING_INDEX(_bi, eblock->extents[_ei].ee_len); + + bh2 = sb_bread(sb, eblock->extents[_ei].ee_start + _bi); + if (!bh2) { + ret = -EIO; + goto file_search_end; + } + + dblock = (struct simplefs_dir_block *) bh2->b_data; + /* Search file in ei_block */ + nr_bi_files -= dblock->nr_files; + for (_fi = 0; _fi < SIMPLEFS_FILES_PER_BLOCK;) { + f = &dblock->files[_fi]; + if (f->inode && !strncmp(f->filename, dentry->d_name.name, + SIMPLEFS_FILENAME_LEN - 1)) { + *ei = _ei; + *bi = _bi; + *fi = _fi; + + brelse(bh); + brelse(bh2); + return 0; + } + _fi += dblock->files[_fi].nr_blk; + } + brelse(bh2); + } + _bi = 0; + } +file_search_end: + brelse(bh); + return ret; +} + /* Search for a dentry in dir. * Fills dentry with NULL if not found in dir, or with the corresponding inode * if found. @@ -126,18 +201,31 @@ static struct dentry *simplefs_lookup(struct inode *dir, 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, bi, fi; + int ei, bi, fi, chk; - /* Check filename length */ - if (dentry->d_name.len > SIMPLEFS_FILENAME_LEN) + /* Check filename length less than SIMPLEFS_FILENAME_LEN - 1, the last + * character is for null terminator */ + if (dentry->d_name.len >= SIMPLEFS_FILENAME_LEN) return ERR_PTR(-ENAMETOOLONG); /* Read the directory block on disk */ + + chk = __file_lookup(dir, dentry, &ei, &bi, &fi); + if (chk == -ENOENT) + goto search_end; /* Not found, return NULL dentry */ + if (chk < 0) + return ERR_PTR(chk); /* I/O error */ + bh = sb_bread(sb, ci_dir->ei_block); if (!bh) return ERR_PTR(-EIO); + eblock = (struct simplefs_file_ei_block *) bh->b_data; + bh2 = sb_bread(sb, eblock->extents[ei].ee_start + bi); + if (!bh2) { + brelse(bh); + return ERR_PTR(-EIO); + } /* Search for the file in directory */ for (ei = 0; ei < SIMPLEFS_MAX_EXTENTS; ei++) { @@ -316,31 +404,30 @@ static struct inode *simplefs_new_inode(struct inode *dir, mode_t mode) } static uint32_t simplefs_get_available_ext_idx( - int *dir_nr_files, - struct simplefs_file_ei_block *eblock) + struct simplefs_file_ei_block *eblock, + uint32_t hash_code) { - int ei = 0; + int ei = 0, idx; 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) { + + ei = hash_code / SIMPLEFS_MAX_BLOCKS_PER_EXTENT; + + for (idx = 0; idx < SIMPLEFS_MAX_EXTENTS; ei++, idx++) { + CHECK_AND_SET_RING_INDEX(ei, SIMPLEFS_MAX_EXTENTS); + + if (!eblock->extents[ei].ee_start) { 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) + } else if (eblock->extents[ei].ee_start && + eblock->extents[ei].nr_files != SIMPLEFS_FILES_PER_EXT) { + first_empty_blk = ei; break; + } } return first_empty_blk; } -static int simplefs_put_new_ext(struct super_block *sb, +static int simplefs_get_new_ext(struct super_block *sb, uint32_t ei, struct simplefs_file_ei_block *eblock) { @@ -353,9 +440,9 @@ static int simplefs_put_new_ext(struct super_block *sb, 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; + /* ee_block is only used for file extent search, not for directory extents. + * Set to 0 as directory operations rely solely on ee_start and ee_len. */ + eblock->extents[ei].ee_block = 0; eblock->extents[ei].nr_files = 0; /* clear the ext block*/ @@ -401,6 +488,39 @@ static void simplefs_set_file_into_dir(struct simplefs_dir_block *dblock, dblock->nr_files++; } +static bool simplefs_try_remove_entry(struct simplefs_dir_block *dblock, + struct simplefs_file_ei_block *eblock, + int ei, + ino_t ino, + const char *name) +{ + int fi, i; + int blk_nr_files = dblock->nr_files; + + for (fi = 0; blk_nr_files && fi < SIMPLEFS_FILES_PER_BLOCK;) { + if (dblock->files[fi].inode) { + if (dblock->files[fi].inode == ino && + !strcmp(dblock->files[fi].filename, name)) { + dblock->files[fi].inode = 0; + /* Merge the empty data */ + for (i = fi - 1; i >= 0; i--) { + if (dblock->files[i].inode != 0 || i == 0) { + dblock->files[i].nr_blk += dblock->files[fi].nr_blk; + break; + } + } + dblock->nr_files--; + eblock->extents[ei].nr_files--; + eblock->nr_files--; + return true; + } + blk_nr_files--; + } + fi += dblock->files[fi].nr_blk; + } + return false; +} + /* 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) @@ -433,15 +553,17 @@ 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; + uint32_t avail; #if SIMPLEFS_AT_LEAST(6, 6, 0) && SIMPLEFS_LESS_EQUAL(6, 7, 0) struct timespec64 cur_time; #endif int ret = 0, alloc = false; - int bi = 0; + uint32_t hash_code; + int bi = 0, idx_bi; - /* Check filename length */ - if (strlen(dentry->d_name.name) > SIMPLEFS_FILENAME_LEN) + /* Check filename length less than SIMPLEFS_FILENAME_LEN - 1, the last + * character is for null terminator */ + if (strlen(dentry->d_name.name) >= SIMPLEFS_FILENAME_LEN) return -ENAMETOOLONG; /* Read parent directory index */ @@ -478,8 +600,9 @@ static int simplefs_create(struct inode *dir, mark_buffer_dirty(bh2); brelse(bh2); - dir_nr_files = eblock->nr_files; - avail = simplefs_get_available_ext_idx(&dir_nr_files, eblock); + hash_code = simplefs_hash(dentry) % + (SIMPLEFS_MAX_EXTENTS * SIMPLEFS_MAX_BLOCKS_PER_EXTENT); + avail = simplefs_get_available_ext_idx(eblock, hash_code); /* Validate avail index is within bounds */ if (avail >= SIMPLEFS_MAX_EXTENTS) { @@ -488,8 +611,8 @@ static int simplefs_create(struct inode *dir, } /* 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); + if (!eblock->extents[avail].ee_start) { + ret = simplefs_get_new_ext(sb, avail, eblock); switch (ret) { case -ENOSPC: ret = -ENOSPC; @@ -503,7 +626,10 @@ static int simplefs_create(struct inode *dir, /* 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++) { + bi = hash_code % eblock->extents[avail].ee_len; + for (idx_bi = 0; idx_bi < eblock->extents[avail].ee_len; bi++, idx_bi++) { + CHECK_AND_SET_RING_INDEX(bi, eblock->extents[avail].ee_len); + bh2 = sb_bread(sb, eblock->extents[avail].ee_start + bi); if (!bh2) { ret = -EIO; @@ -563,72 +689,66 @@ static int simplefs_create(struct inode *dir, return ret; } -static int simplefs_remove_from_dir(struct inode *dir, struct dentry *dentry) +static int simplefs_remove_from_dir(struct inode *dir, + struct dentry *dentry, + int *ret_ei, + struct buffer_head **ret_ei_bh) { struct super_block *sb = dir->i_sb; struct inode *inode = d_inode(dentry); - struct buffer_head *bh = NULL, *bh2 = NULL; + struct buffer_head *bh2 = NULL; struct simplefs_file_ei_block *eblock = NULL; struct simplefs_dir_block *dirblk = NULL; - int ei = 0, bi = 0, fi = 0; - int ret = 0, found = false; - + int ei = 0, bi = 0, idx_bi; + int ret = 0, found = false, dir_nr_files; + uint32_t hash_code; /* Read parent directory index */ - bh = sb_bread(sb, SIMPLEFS_INODE(dir)->ei_block); - if (!bh) + *ret_ei_bh = sb_bread(sb, SIMPLEFS_INODE(dir)->ei_block); + if (!*ret_ei_bh) return -EIO; - eblock = (struct simplefs_file_ei_block *) bh->b_data; + eblock = (struct simplefs_file_ei_block *) (*ret_ei_bh)->b_data; + dir_nr_files = eblock->nr_files; + + hash_code = simplefs_hash(dentry) % + (SIMPLEFS_MAX_EXTENTS * SIMPLEFS_MAX_BLOCKS_PER_EXTENT); + ei = hash_code / SIMPLEFS_MAX_BLOCKS_PER_EXTENT; + bi = hash_code % SIMPLEFS_MAX_BLOCKS_PER_EXTENT; + + for (; dir_nr_files; ei++) { + CHECK_AND_SET_RING_INDEX(ei, SIMPLEFS_MAX_EXTENTS); - 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++) { + /* simplefs_extent */ + for (idx_bi = 0; idx_bi < eblock->extents[ei].ee_len; + bi++, idx_bi++) { + CHECK_AND_SET_RING_INDEX(bi, eblock->extents[ei].ee_len); bh2 = sb_bread(sb, eblock->extents[ei].ee_start + bi); if (!bh2) { ret = -EIO; - goto release_bh; + goto end_ret; } + /* simplefs_dir_block */ 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--; - } - fi += dirblk->files[fi].nr_blk; + if (simplefs_try_remove_entry(dirblk, eblock, ei, inode->i_ino, + dentry->d_name.name)) { + mark_buffer_dirty(bh2); + brelse(bh2); + found = true; + *ret_ei = ei; + goto found_data; } brelse(bh2); } } + bi = 0; } found_data: if (found) { - mark_buffer_dirty(bh); + mark_buffer_dirty(*ret_ei_bh); } -release_bh: - brelse(bh); +end_ret: return ret; } @@ -645,7 +765,7 @@ static int simplefs_unlink(struct inode *dir, struct dentry *dentry) struct simplefs_sb_info *sbi = SIMPLEFS_SB(sb); struct inode *inode = d_inode(dentry); struct buffer_head *bh = NULL, *bh2 = NULL; - struct simplefs_file_ei_block *file_block = NULL; + struct simplefs_file_ei_block *eblk = NULL; char *block; #if SIMPLEFS_AT_LEAST(6, 6, 0) && SIMPLEFS_LESS_EQUAL(6, 7, 0) struct timespec64 cur_time; @@ -656,9 +776,20 @@ static int simplefs_unlink(struct inode *dir, struct dentry *dentry) uint32_t ino = inode->i_ino; uint32_t bno = 0; - ret = simplefs_remove_from_dir(dir, dentry); - if (ret != 0) + ret = simplefs_remove_from_dir(dir, dentry, &ei, &bh); + + if (ret != 0) { + brelse(bh); return ret; + } + + eblk = (struct simplefs_file_ei_block *) bh->b_data; + if (!eblk->extents[ei].nr_files) { + put_blocks(sbi, eblk->extents[ei].ee_start, eblk->extents[ei].ee_len); + memset(&eblk->extents[ei], 0, sizeof(struct simplefs_extent)); + mark_buffer_dirty(bh); + } + brelse(bh); if (S_ISLNK(inode->i_mode)) goto clean_inode; @@ -695,18 +826,16 @@ static int simplefs_unlink(struct inode *dir, struct dentry *dentry) bh = sb_bread(sb, bno); if (!bh) goto clean_inode; - file_block = (struct simplefs_file_ei_block *) bh->b_data; - + eblk = (struct simplefs_file_ei_block *) bh->b_data; for (ei = 0; ei < SIMPLEFS_MAX_EXTENTS; ei++) { - if (!file_block->extents[ei].ee_start) + if (!eblk->extents[ei].ee_start) break; - put_blocks(sbi, file_block->extents[ei].ee_start, - file_block->extents[ei].ee_len); + put_blocks(sbi, eblk->extents[ei].ee_start, eblk->extents[ei].ee_len); /* Scrub the extent */ - for (bi = 0; bi < file_block->extents[ei].ee_len; bi++) { - bh2 = sb_bread(sb, file_block->extents[ei].ee_start + bi); + for (bi = 0; bi < eblk->extents[ei].ee_len; bi++) { + bh2 = sb_bread(sb, eblk->extents[ei].ee_start + bi); if (!bh2) continue; block = (char *) bh2->b_data; @@ -717,7 +846,7 @@ static int simplefs_unlink(struct inode *dir, struct dentry *dentry) } /* Scrub index block */ - memset(file_block, 0, SIMPLEFS_BLOCK_SIZE); + memset(eblk, 0, SIMPLEFS_BLOCK_SIZE); mark_buffer_dirty(bh); brelse(bh); @@ -774,118 +903,146 @@ static int simplefs_rename(struct inode *src_dir, #endif { struct super_block *sb = src_dir->i_sb; + struct simplefs_sb_info *sbi = SIMPLEFS_SB(sb); struct simplefs_inode_info *ci_dest = SIMPLEFS_INODE(dest_dir); - struct inode *src = d_inode(src_dentry); - struct buffer_head *bh_new = NULL, *bh2 = NULL; - struct simplefs_file_ei_block *eblk_dest = NULL; + struct inode *src_in = d_inode(src_dentry); + struct buffer_head *bh_fei_blk_src = NULL, *bh_fei_blk_dest = NULL, + *bh_ext = NULL, *dest_bh_ext = NULL; + struct simplefs_file_ei_block *eblk_src = NULL, *eblk_dest = NULL; struct simplefs_dir_block *dblock = NULL; #if SIMPLEFS_AT_LEAST(6, 6, 0) && SIMPLEFS_LESS_EQUAL(6, 7, 0) struct timespec64 cur_time; #endif - int new_pos = -1, ret = 0; - int ei = 0, bi = 0, fi = 0, bno = 0; + int ret = 0, new_pos = 0, idx, chk; + int src_ei = 0, dest_ei = 0, bi = 0, fi = 0; + int dest_inserted = 0; + uint32_t hash_code; /* fail with these unsupported flags */ if (flags & (RENAME_EXCHANGE | RENAME_WHITEOUT)) return -EINVAL; /* Check if filename is not too long */ - if (strlen(dest_dentry->d_name.name) > SIMPLEFS_FILENAME_LEN) + if (strlen(dest_dentry->d_name.name) >= SIMPLEFS_FILENAME_LEN) return -ENAMETOOLONG; /* Fail if dest_dentry exists or if dest_dir is full */ - bh_new = sb_bread(sb, ci_dest->ei_block); - if (!bh_new) + bh_fei_blk_dest = sb_bread(sb, ci_dest->ei_block); + if (!bh_fei_blk_dest) return -EIO; - eblk_dest = (struct simplefs_file_ei_block *) bh_new->b_data; - for (ei = 0; new_pos < 0 && ei < SIMPLEFS_MAX_EXTENTS; ei++) { - if (!eblk_dest->extents[ei].ee_start) - break; + eblk_dest = (struct simplefs_file_ei_block *) bh_fei_blk_dest->b_data; + /* Search for the file in directory */ + chk = __file_lookup(dest_dir, dest_dentry, &dest_ei, &bi, &fi); + if (chk != -ENOENT) { + if (chk == 0) { /* found, return exist */ + ret = -EEXIST; + } else if (chk < 0) { /* I/O error */ + ret = chk; + } + goto release_new; + } - for (bi = 0; new_pos < 0 && bi < eblk_dest->extents[ei].ee_len; bi++) { - bh2 = sb_bread(sb, eblk_dest->extents[ei].ee_start + bi); - if (!bh2) { - ret = -EIO; - goto release_new; - } + if (dest_dir != src_dir && eblk_dest->nr_files == SIMPLEFS_MAX_SUBFILES) { + ret = -EMLINK; + goto release_new; + } + if (dest_dir == src_dir && eblk_dest->nr_files == SIMPLEFS_MAX_SUBFILES) { + chk = __file_lookup(src_dir, src_dentry, &src_ei, &bi, &fi); + if (chk != 0) { + ret = chk; + goto release_new; + } - dblock = (struct simplefs_dir_block *) bh2->b_data; - int blk_nr_files = dblock->nr_files; - for (fi = 0; blk_nr_files;) { - /* src and target are the same dir (inode is same) */ - if (dest_dir == src_dir) { - if (dblock->files[fi].inode && - !strncmp(dblock->files[fi].filename, - src_dentry->d_name.name, - SIMPLEFS_FILENAME_LEN)) { - strncpy(dblock->files[fi].filename, - dest_dentry->d_name.name, SIMPLEFS_FILENAME_LEN); - mark_buffer_dirty(bh2); - 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, - dest_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; - } - } - blk_nr_files--; - fi += dblock->files[fi].nr_blk; - } - brelse(bh2); + bh_ext = sb_bread(sb, eblk_dest->extents[src_ei].ee_start + bi); + if (!bh_ext) { + ret = -EIO; + goto release_new; } + dblock = (struct simplefs_dir_block *) bh_ext->b_data; + + strncpy(dblock->files[fi].filename, dest_dentry->d_name.name, + SIMPLEFS_FILENAME_LEN - 1); + dblock->files[fi].filename[SIMPLEFS_FILENAME_LEN - 1] = '\0'; + mark_buffer_dirty(bh_ext); + + brelse(bh_ext); + bh_ext = NULL; + goto update_metadata; } - /* If new directory is full, fail */ - if (new_pos < 0 && eblk_dest->nr_files == SIMPLEFS_FILES_PER_EXT) { + hash_code = simplefs_hash(dest_dentry) % + (SIMPLEFS_MAX_EXTENTS * SIMPLEFS_MAX_BLOCKS_PER_EXTENT); + dest_ei = simplefs_get_available_ext_idx(eblk_dest, hash_code); + if (dest_ei >= SIMPLEFS_MAX_EXTENTS) { ret = -EMLINK; goto release_new; } - /* insert in new parent directory */ - /* Get new freeblocks for extent if needed*/ - if (new_pos < 0) { - bno = get_free_blocks(sb, SIMPLEFS_MAX_BLOCKS_PER_EXTENT); - if (!bno) { + if (!eblk_dest->extents[dest_ei].ee_start) { + ret = simplefs_get_new_ext(sb, dest_ei, eblk_dest); + switch (ret) { + case -ENOSPC: ret = -ENOSPC; goto release_new; + case -EIO: + ret = -EIO; + goto release_new; } - eblk_dest->extents[ei].ee_start = bno; - eblk_dest->extents[ei].ee_len = SIMPLEFS_MAX_BLOCKS_PER_EXTENT; - eblk_dest->extents[ei].ee_block = - ei ? eblk_dest->extents[ei - 1].ee_block + - eblk_dest->extents[ei - 1].ee_len - : 0; - bh2 = sb_bread(sb, eblk_dest->extents[ei].ee_start + 0); - if (!bh2) { + mark_buffer_dirty(bh_fei_blk_dest); + new_pos = 1; + } + /* copy src info into new directory */ + bi = hash_code % eblk_dest->extents[dest_ei].ee_len; + for (idx = 0; idx < eblk_dest->extents[dest_ei].ee_len; bi++, idx++) { + CHECK_AND_SET_RING_INDEX(bi, eblk_dest->extents[dest_ei].ee_len); + dest_bh_ext = sb_bread(sb, eblk_dest->extents[dest_ei].ee_start + bi); + if (!dest_bh_ext) { ret = -EIO; goto put_block; } - dblock = (struct simplefs_dir_block *) bh2->b_data; - mark_buffer_dirty(bh_new); - new_pos = 0; + dblock = (struct simplefs_dir_block *) dest_bh_ext->b_data; + + /* check if dir block is full*/ + if (dblock->nr_files != SIMPLEFS_FILES_PER_BLOCK) { + simplefs_set_file_into_dir(dblock, src_in->i_ino, + dest_dentry->d_name.name); + eblk_dest->extents[dest_ei].nr_files++; + eblk_dest->nr_files++; + mark_buffer_dirty(dest_bh_ext); + mark_buffer_dirty(bh_fei_blk_dest); + /* Track that we inserted the file for cleanup on error */ + dest_inserted = 1; + /* Hold dest_bh_ext until the source is removed successfully or + * the operation is rolled back. + */ + break; + } + brelse(dest_bh_ext); + } + + if (!dest_inserted) { + ret = -ENOSPC; + goto put_block; } - dblock->files[new_pos].inode = src->i_ino; - strncpy(dblock->files[new_pos].filename, dest_dentry->d_name.name, - SIMPLEFS_FILENAME_LEN); - mark_buffer_dirty(bh2); - brelse(bh2); + /* remove target from old parent directory */ + ret = + simplefs_remove_from_dir(src_dir, src_dentry, &src_ei, &bh_fei_blk_src); + if (ret != 0) + goto rm_new; + + eblk_src = (struct simplefs_file_ei_block *) bh_fei_blk_src->b_data; + if (!eblk_src->extents[src_ei].nr_files) { + put_blocks(sbi, eblk_src->extents[src_ei].ee_start, + eblk_src->extents[src_ei].ee_len); + memset(&eblk_src->extents[src_ei], 0, sizeof(struct simplefs_extent)); + mark_buffer_dirty(bh_fei_blk_src); + } + +update_metadata: /* Update new parent inode metadata */ #if SIMPLEFS_AT_LEAST(6, 7, 0) simple_inode_init_ts(dest_dir); @@ -898,16 +1055,10 @@ static int simplefs_rename(struct inode *src_dir, current_time(dest_dir); #endif - if (S_ISDIR(src->i_mode)) + if (S_ISDIR(src_in->i_mode)) inc_nlink(dest_dir); mark_inode_dirty(dest_dir); - /* remove target from old parent directory */ - ret = simplefs_remove_from_dir(src_dir, src_dentry); - if (ret != 0) - goto release_new; - - /* Update old parent inode metadata */ #if SIMPLEFS_AT_LEAST(6, 7, 0) simple_inode_init_ts(src_dir); #elif SIMPLEFS_AT_LEAST(6, 6, 0) @@ -919,20 +1070,41 @@ static int simplefs_rename(struct inode *src_dir, current_time(src_dir); #endif - if (S_ISDIR(src->i_mode)) + if (S_ISDIR(src_in->i_mode)) drop_nlink(src_dir); mark_inode_dirty(src_dir); - return ret; + goto release_new; + +rm_new: + /* dest_dentry has no inode; undo insert without simplefs_remove_from_dir */ + if (dest_inserted) { + /* Use the held directory block buffer to remove the inserted entry */ + dblock = (struct simplefs_dir_block *) dest_bh_ext->b_data; + if (simplefs_try_remove_entry(dblock, eblk_dest, dest_ei, src_in->i_ino, + dest_dentry->d_name.name)) { + mark_buffer_dirty(dest_bh_ext); + mark_buffer_dirty(bh_fei_blk_dest); + } else { /* this should never happen */ + pr_warn( + "simplefs: failed to remove inserted entry on rename rollback " + "(leak)\n"); + } + brelse(dest_bh_ext); + dest_bh_ext = NULL; + } put_block: - if (eblk_dest->extents[ei].ee_start) { - put_blocks(SIMPLEFS_SB(sb), eblk_dest->extents[ei].ee_start, - eblk_dest->extents[ei].ee_len); - memset(&eblk_dest->extents[ei], 0, sizeof(struct simplefs_extent)); + if (eblk_dest->extents[dest_ei].ee_start && new_pos) { + put_blocks(SIMPLEFS_SB(sb), eblk_dest->extents[dest_ei].ee_start, + eblk_dest->extents[dest_ei].ee_len); + memset(&eblk_dest->extents[dest_ei], 0, sizeof(struct simplefs_extent)); } + release_new: - brelse(bh_new); + brelse(bh_fei_blk_dest); + brelse(bh_fei_blk_src); + brelse(dest_bh_ext); return ret; } @@ -1007,8 +1179,8 @@ static int simplefs_link(struct dentry *src_dentry, struct simplefs_dir_block *dblock; struct buffer_head *bh = NULL, *bh2 = NULL; int ret = 0, alloc = false; - int ei = 0, bi = 0; - uint32_t avail; + int bi = 0, idx_bi; + uint32_t avail, hash_code; bh = sb_bread(sb, ci_dir->ei_block); if (!bh) @@ -1021,8 +1193,10 @@ static int simplefs_link(struct dentry *src_dentry, goto end; } - int dir_nr_files = eblock->nr_files; - avail = simplefs_get_available_ext_idx(&dir_nr_files, eblock); + + hash_code = simplefs_hash(dentry) % + (SIMPLEFS_MAX_EXTENTS * SIMPLEFS_MAX_BLOCKS_PER_EXTENT); + avail = simplefs_get_available_ext_idx(eblock, hash_code); /* Validate avail index is within bounds */ if (avail >= SIMPLEFS_MAX_EXTENTS) { @@ -1031,8 +1205,8 @@ static int simplefs_link(struct dentry *src_dentry, } /* 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); + if (!eblock->extents[avail].ee_start) { + ret = simplefs_get_new_ext(sb, avail, eblock); switch (ret) { case -ENOSPC: ret = -ENOSPC; @@ -1046,12 +1220,16 @@ static int simplefs_link(struct dentry *src_dentry, /* 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++) { + bi = hash_code % eblock->extents[avail].ee_len; + for (idx_bi = 0; idx_bi < eblock->extents[avail].ee_len; bi++, idx_bi++) { + CHECK_AND_SET_RING_INDEX(bi, eblock->extents[avail].ee_len); + 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; @@ -1061,7 +1239,6 @@ static int simplefs_link(struct dentry *src_dentry, /* write the file info into simplefs_dir_block */ simplefs_set_file_into_dir(dblock, old_inode->i_ino, dentry->d_name.name); - eblock->extents[avail].nr_files++; eblock->nr_files++; mark_buffer_dirty(bh2); @@ -1075,10 +1252,10 @@ static int simplefs_link(struct dentry *src_dentry, return ret; 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)); } end: brelse(bh); @@ -1110,8 +1287,8 @@ static int simplefs_symlink(struct inode *dir, struct simplefs_dir_block *dblock = NULL; struct buffer_head *bh = NULL, *bh2 = NULL; int ret = 0, alloc = false; - int ei = 0, bi = 0; - uint32_t avail; + int bi = 0, idx_bi; + uint32_t avail, hash_code; /* Check if symlink content is not too long */ if (l > sizeof(ci->i_data)) { @@ -1133,8 +1310,10 @@ static int simplefs_symlink(struct inode *dir, goto iput; } - int dir_nr_files = eblock->nr_files; - avail = simplefs_get_available_ext_idx(&dir_nr_files, eblock); + + hash_code = simplefs_hash(dentry) % + (SIMPLEFS_MAX_EXTENTS * SIMPLEFS_MAX_BLOCKS_PER_EXTENT); + avail = simplefs_get_available_ext_idx(eblock, hash_code); /* Validate avail index is within bounds */ if (avail >= SIMPLEFS_MAX_EXTENTS) { @@ -1143,8 +1322,8 @@ static int simplefs_symlink(struct inode *dir, } /* 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); + if (!eblock->extents[avail].ee_start) { + ret = simplefs_get_new_ext(sb, avail, eblock); switch (ret) { case -ENOSPC: ret = -ENOSPC; @@ -1158,12 +1337,16 @@ static int simplefs_symlink(struct inode *dir, /* 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++) { + bi = hash_code % eblock->extents[avail].ee_len; + for (idx_bi = 0; idx_bi < eblock->extents[avail].ee_len; bi++, idx_bi++) { + CHECK_AND_SET_RING_INDEX(bi, eblock->extents[avail].ee_len); + 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; @@ -1189,10 +1372,10 @@ static int simplefs_symlink(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), ci->ei_block, 1); diff --git a/simplefs.h b/simplefs.h index f99353f..66f9d88 100644 --- a/simplefs.h +++ b/simplefs.h @@ -115,6 +115,9 @@ struct dentry *simplefs_mount(struct file_system_type *fs_type, const char *dev_name, void *data); +/* hash.c */ +uint32_t simplefs_hash(struct dentry *dentry); + /* file functions */ extern const struct file_operations simplefs_file_ops; extern const struct file_operations simplefs_dir_ops; From 02f0e2d6ccb48b9c27e46ec2a84c3fcade4f9c37 Mon Sep 17 00:00:00 2001 From: RoyHuang Date: Sun, 12 Apr 2026 13:50:38 +0800 Subject: [PATCH 7/7] Optimize inode cache read and update logic Streamline the cache lookup for frequently accessed inodes. Reduce unnecessary overhead in block allocation checks. --- inode.c | 210 +++++++++++++++++++++++--------------------------------- 1 file changed, 84 insertions(+), 126 deletions(-) diff --git a/inode.c b/inode.c index 294e5ee..59740ff 100644 --- a/inode.c +++ b/inode.c @@ -16,6 +16,12 @@ static const struct inode_operations symlink_inode_ops; if (unlikely(idx >= len)) \ idx -= len; \ } while (0) + +#define RELEASE_BUFFER_HEAD(bh) \ + do { \ + brelse(bh); \ + bh = NULL; \ + } while (0) /* Either return the inode that corresponds to a given inode number (ino), if * it is already in the cache, or create a new inode object if it is not in the * cache. @@ -102,7 +108,7 @@ struct inode *simplefs_iget(struct super_block *sb, unsigned long ino) inode->i_op = &symlink_inode_ops; } - brelse(bh); + RELEASE_BUFFER_HEAD(bh); /* Unlock the inode to make it usable */ unlock_new_inode(inode); @@ -110,7 +116,7 @@ struct inode *simplefs_iget(struct super_block *sb, unsigned long ino) return inode; failed: - brelse(bh); + RELEASE_BUFFER_HEAD(bh); iget_failed(inode); return ERR_PTR(ret); } @@ -119,11 +125,12 @@ static int __file_lookup(struct inode *dir, struct dentry *dentry, int *ei, int *bi, - int *fi) + int *fi, + struct buffer_head **ret_ei_bh, + struct buffer_head **ret_bi_bh) { struct super_block *sb = dir->i_sb; struct simplefs_inode_info *ci_dir = SIMPLEFS_INODE(dir); - 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; @@ -132,10 +139,10 @@ static int __file_lookup(struct inode *dir, uint32_t hash_code; /* Read the directory block on disk */ - bh = sb_bread(sb, ci_dir->ei_block); - if (!bh) + *ret_ei_bh = sb_bread(sb, ci_dir->ei_block); + if (!*ret_ei_bh) return -EIO; - eblock = (struct simplefs_file_ei_block *) bh->b_data; + eblock = (struct simplefs_file_ei_block *) (*ret_ei_bh)->b_data; hash_code = simplefs_hash(dentry) % (SIMPLEFS_MAX_EXTENTS * SIMPLEFS_MAX_BLOCKS_PER_EXTENT); _ei = hash_code / SIMPLEFS_MAX_BLOCKS_PER_EXTENT; @@ -153,13 +160,13 @@ static int __file_lookup(struct inode *dir, for (idx_bi = 0; nr_bi_files; _bi++, idx_bi++) { CHECK_AND_SET_RING_INDEX(_bi, eblock->extents[_ei].ee_len); - bh2 = sb_bread(sb, eblock->extents[_ei].ee_start + _bi); - if (!bh2) { + *ret_bi_bh = sb_bread(sb, eblock->extents[_ei].ee_start + _bi); + if (!*ret_bi_bh) { ret = -EIO; goto file_search_end; } - dblock = (struct simplefs_dir_block *) bh2->b_data; + dblock = (struct simplefs_dir_block *) (*ret_bi_bh)->b_data; /* Search file in ei_block */ nr_bi_files -= dblock->nr_files; for (_fi = 0; _fi < SIMPLEFS_FILES_PER_BLOCK;) { @@ -169,19 +176,15 @@ static int __file_lookup(struct inode *dir, *ei = _ei; *bi = _bi; *fi = _fi; - - brelse(bh); - brelse(bh2); return 0; } _fi += dblock->files[_fi].nr_blk; } - brelse(bh2); + RELEASE_BUFFER_HEAD(*ret_bi_bh); } _bi = 0; } file_search_end: - brelse(bh); return ret; } @@ -196,10 +199,8 @@ static struct dentry *simplefs_lookup(struct inode *dir, unsigned int flags) { struct super_block *sb = dir->i_sb; - struct simplefs_inode_info *ci_dir = SIMPLEFS_INODE(dir); struct inode *inode = NULL; - struct buffer_head *bh = NULL, *bh2 = NULL; - struct simplefs_file_ei_block *eblock = NULL; + struct buffer_head *ei_bh = NULL, *bi_bh = NULL; struct simplefs_dir_block *dblock = NULL; int ei, bi, fi, chk; @@ -210,61 +211,27 @@ static struct dentry *simplefs_lookup(struct inode *dir, /* Read the directory block on disk */ - chk = __file_lookup(dir, dentry, &ei, &bi, &fi); + chk = __file_lookup(dir, dentry, &ei, &bi, &fi, &ei_bh, &bi_bh); if (chk == -ENOENT) goto search_end; /* Not found, return NULL dentry */ - if (chk < 0) + if (chk < 0) { + RELEASE_BUFFER_HEAD(ei_bh); + RELEASE_BUFFER_HEAD(bi_bh); return ERR_PTR(chk); /* I/O error */ - - bh = sb_bread(sb, ci_dir->ei_block); - if (!bh) - return ERR_PTR(-EIO); - - eblock = (struct simplefs_file_ei_block *) bh->b_data; - bh2 = sb_bread(sb, eblock->extents[ei].ee_start + bi); - if (!bh2) { - brelse(bh); - return ERR_PTR(-EIO); } - /* Search for the file in directory */ - for (ei = 0; ei < SIMPLEFS_MAX_EXTENTS; ei++) { - if (!eblock->extents[ei].ee_start) - break; + dblock = (struct simplefs_dir_block *) bi_bh->b_data; + inode = simplefs_iget(sb, (&dblock->files[fi])->inode); - /* Iterate blocks in extent */ - for (bi = 0; bi < eblock->extents[ei].ee_len; bi++) { - bh2 = sb_bread(sb, eblock->extents[ei].ee_start + bi); - if (!bh2) { - brelse(bh); - return ERR_PTR(-EIO); - } - - dblock = (struct simplefs_dir_block *) bh2->b_data; - int nr_files = dblock->nr_files; - /* Search file in ei_block */ - for (fi = 0; nr_files && fi < SIMPLEFS_FILES_PER_BLOCK;) { - f = &dblock->files[fi]; - - if (f->inode) { - nr_files--; - if (!strncmp(f->filename, dentry->d_name.name, - SIMPLEFS_FILENAME_LEN)) { - inode = simplefs_iget(sb, f->inode); - brelse(bh2); - goto search_end; - } - } - fi += f->nr_blk; - } - brelse(bh2); - bh2 = NULL; - } + if (IS_ERR(inode)) { + RELEASE_BUFFER_HEAD(ei_bh); + RELEASE_BUFFER_HEAD(bi_bh); + return ERR_PTR(PTR_ERR(inode)); } search_end: - brelse(bh); - bh = NULL; + RELEASE_BUFFER_HEAD(ei_bh); + RELEASE_BUFFER_HEAD(bi_bh); /* Update directory access time */ #if SIMPLEFS_AT_LEAST(6, 7, 0) inode_set_atime_to_ts(dir, current_time(dir)); @@ -455,7 +422,7 @@ static int simplefs_get_new_ext(struct super_block *sb, 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); + RELEASE_BUFFER_HEAD(bh); } return 0; } @@ -598,7 +565,7 @@ static int simplefs_create(struct inode *dir, fblock = (char *) bh2->b_data; memset(fblock, 0, SIMPLEFS_BLOCK_SIZE); mark_buffer_dirty(bh2); - brelse(bh2); + RELEASE_BUFFER_HEAD(bh2); hash_code = simplefs_hash(dentry) % (SIMPLEFS_MAX_EXTENTS * SIMPLEFS_MAX_BLOCKS_PER_EXTENT); @@ -639,7 +606,7 @@ static int simplefs_create(struct inode *dir, if (dblock->nr_files != SIMPLEFS_FILES_PER_BLOCK) break; else - brelse(bh2); + RELEASE_BUFFER_HEAD(bh2); } /* write the file info into simplefs_dir_block */ @@ -649,8 +616,8 @@ static int simplefs_create(struct inode *dir, eblock->nr_files++; mark_buffer_dirty(bh2); mark_buffer_dirty(bh); - brelse(bh2); - brelse(bh); + RELEASE_BUFFER_HEAD(bh2); + RELEASE_BUFFER_HEAD(bh); /* Update stats and mark dir and new inode dirty */ mark_inode_dirty(inode); @@ -685,7 +652,7 @@ static int simplefs_create(struct inode *dir, put_inode(SIMPLEFS_SB(sb), inode->i_ino); iput(inode); end: - brelse(bh); + RELEASE_BUFFER_HEAD(bh); return ret; } @@ -734,12 +701,12 @@ static int simplefs_remove_from_dir(struct inode *dir, if (simplefs_try_remove_entry(dirblk, eblock, ei, inode->i_ino, dentry->d_name.name)) { mark_buffer_dirty(bh2); - brelse(bh2); + RELEASE_BUFFER_HEAD(bh2); found = true; *ret_ei = ei; goto found_data; } - brelse(bh2); + RELEASE_BUFFER_HEAD(bh2); } } bi = 0; @@ -779,7 +746,7 @@ static int simplefs_unlink(struct inode *dir, struct dentry *dentry) ret = simplefs_remove_from_dir(dir, dentry, &ei, &bh); if (ret != 0) { - brelse(bh); + RELEASE_BUFFER_HEAD(bh); return ret; } @@ -789,7 +756,7 @@ static int simplefs_unlink(struct inode *dir, struct dentry *dentry) memset(&eblk->extents[ei], 0, sizeof(struct simplefs_extent)); mark_buffer_dirty(bh); } - brelse(bh); + RELEASE_BUFFER_HEAD(bh); if (S_ISLNK(inode->i_mode)) goto clean_inode; @@ -841,14 +808,14 @@ static int simplefs_unlink(struct inode *dir, struct dentry *dentry) block = (char *) bh2->b_data; memset(block, 0, SIMPLEFS_BLOCK_SIZE); mark_buffer_dirty(bh2); - brelse(bh2); + RELEASE_BUFFER_HEAD(bh2); } } /* Scrub index block */ memset(eblk, 0, SIMPLEFS_BLOCK_SIZE); mark_buffer_dirty(bh); - brelse(bh); + RELEASE_BUFFER_HEAD(bh); clean_inode: /* Cleanup inode and mark dirty */ @@ -904,10 +871,9 @@ static int simplefs_rename(struct inode *src_dir, { struct super_block *sb = src_dir->i_sb; struct simplefs_sb_info *sbi = SIMPLEFS_SB(sb); - struct simplefs_inode_info *ci_dest = SIMPLEFS_INODE(dest_dir); struct inode *src_in = d_inode(src_dentry); - struct buffer_head *bh_fei_blk_src = NULL, *bh_fei_blk_dest = NULL, - *bh_ext = NULL, *dest_bh_ext = NULL; + struct buffer_head *src_ei_bh = NULL, *dest_ei_bh = NULL, *src_bi_bh = NULL, + *dest_bi_bh = NULL; struct simplefs_file_ei_block *eblk_src = NULL, *eblk_dest = NULL; struct simplefs_dir_block *dblock = NULL; @@ -928,14 +894,9 @@ static int simplefs_rename(struct inode *src_dir, if (strlen(dest_dentry->d_name.name) >= SIMPLEFS_FILENAME_LEN) return -ENAMETOOLONG; - /* Fail if dest_dentry exists or if dest_dir is full */ - bh_fei_blk_dest = sb_bread(sb, ci_dest->ei_block); - if (!bh_fei_blk_dest) - return -EIO; - - eblk_dest = (struct simplefs_file_ei_block *) bh_fei_blk_dest->b_data; /* Search for the file in directory */ - chk = __file_lookup(dest_dir, dest_dentry, &dest_ei, &bi, &fi); + chk = __file_lookup(dest_dir, dest_dentry, &dest_ei, &bi, &fi, &dest_ei_bh, + &dest_bi_bh); if (chk != -ENOENT) { if (chk == 0) { /* found, return exist */ ret = -EEXIST; @@ -945,31 +906,29 @@ static int simplefs_rename(struct inode *src_dir, goto release_new; } + RELEASE_BUFFER_HEAD(dest_bi_bh); /* dest_bi_bh is not used */ + eblk_dest = (struct simplefs_file_ei_block *) dest_ei_bh->b_data; + if (dest_dir != src_dir && eblk_dest->nr_files == SIMPLEFS_MAX_SUBFILES) { ret = -EMLINK; goto release_new; } if (dest_dir == src_dir && eblk_dest->nr_files == SIMPLEFS_MAX_SUBFILES) { - chk = __file_lookup(src_dir, src_dentry, &src_ei, &bi, &fi); + chk = __file_lookup(src_dir, src_dentry, &src_ei, &bi, &fi, &src_ei_bh, + &src_bi_bh); if (chk != 0) { ret = chk; goto release_new; } - bh_ext = sb_bread(sb, eblk_dest->extents[src_ei].ee_start + bi); - if (!bh_ext) { - ret = -EIO; - goto release_new; - } - dblock = (struct simplefs_dir_block *) bh_ext->b_data; + dblock = (struct simplefs_dir_block *) src_bi_bh->b_data; strncpy(dblock->files[fi].filename, dest_dentry->d_name.name, SIMPLEFS_FILENAME_LEN - 1); dblock->files[fi].filename[SIMPLEFS_FILENAME_LEN - 1] = '\0'; - mark_buffer_dirty(bh_ext); + mark_buffer_dirty(src_bi_bh); - brelse(bh_ext); - bh_ext = NULL; + RELEASE_BUFFER_HEAD(src_bi_bh); goto update_metadata; } @@ -991,19 +950,19 @@ static int simplefs_rename(struct inode *src_dir, ret = -EIO; goto release_new; } - mark_buffer_dirty(bh_fei_blk_dest); + mark_buffer_dirty(dest_ei_bh); new_pos = 1; } /* copy src info into new directory */ bi = hash_code % eblk_dest->extents[dest_ei].ee_len; for (idx = 0; idx < eblk_dest->extents[dest_ei].ee_len; bi++, idx++) { CHECK_AND_SET_RING_INDEX(bi, eblk_dest->extents[dest_ei].ee_len); - dest_bh_ext = sb_bread(sb, eblk_dest->extents[dest_ei].ee_start + bi); - if (!dest_bh_ext) { + dest_bi_bh = sb_bread(sb, eblk_dest->extents[dest_ei].ee_start + bi); + if (!dest_bi_bh) { ret = -EIO; goto put_block; } - dblock = (struct simplefs_dir_block *) dest_bh_ext->b_data; + dblock = (struct simplefs_dir_block *) dest_bi_bh->b_data; /* check if dir block is full*/ if (dblock->nr_files != SIMPLEFS_FILES_PER_BLOCK) { @@ -1011,16 +970,16 @@ static int simplefs_rename(struct inode *src_dir, dest_dentry->d_name.name); eblk_dest->extents[dest_ei].nr_files++; eblk_dest->nr_files++; - mark_buffer_dirty(dest_bh_ext); - mark_buffer_dirty(bh_fei_blk_dest); + mark_buffer_dirty(dest_bi_bh); + mark_buffer_dirty(dest_ei_bh); /* Track that we inserted the file for cleanup on error */ dest_inserted = 1; - /* Hold dest_bh_ext until the source is removed successfully or + /* Hold dest_bi_bh until the source is removed successfully or * the operation is rolled back. */ break; } - brelse(dest_bh_ext); + RELEASE_BUFFER_HEAD(dest_bi_bh); } if (!dest_inserted) { @@ -1029,17 +988,16 @@ static int simplefs_rename(struct inode *src_dir, } /* remove target from old parent directory */ - ret = - simplefs_remove_from_dir(src_dir, src_dentry, &src_ei, &bh_fei_blk_src); + ret = simplefs_remove_from_dir(src_dir, src_dentry, &src_ei, &src_ei_bh); if (ret != 0) goto rm_new; - eblk_src = (struct simplefs_file_ei_block *) bh_fei_blk_src->b_data; + eblk_src = (struct simplefs_file_ei_block *) src_ei_bh->b_data; if (!eblk_src->extents[src_ei].nr_files) { put_blocks(sbi, eblk_src->extents[src_ei].ee_start, eblk_src->extents[src_ei].ee_len); memset(&eblk_src->extents[src_ei], 0, sizeof(struct simplefs_extent)); - mark_buffer_dirty(bh_fei_blk_src); + mark_buffer_dirty(src_ei_bh); } update_metadata: @@ -1080,18 +1038,17 @@ static int simplefs_rename(struct inode *src_dir, /* dest_dentry has no inode; undo insert without simplefs_remove_from_dir */ if (dest_inserted) { /* Use the held directory block buffer to remove the inserted entry */ - dblock = (struct simplefs_dir_block *) dest_bh_ext->b_data; + dblock = (struct simplefs_dir_block *) dest_bi_bh->b_data; if (simplefs_try_remove_entry(dblock, eblk_dest, dest_ei, src_in->i_ino, dest_dentry->d_name.name)) { - mark_buffer_dirty(dest_bh_ext); - mark_buffer_dirty(bh_fei_blk_dest); + mark_buffer_dirty(dest_bi_bh); + mark_buffer_dirty(dest_ei_bh); } else { /* this should never happen */ pr_warn( "simplefs: failed to remove inserted entry on rename rollback " "(leak)\n"); } - brelse(dest_bh_ext); - dest_bh_ext = NULL; + RELEASE_BUFFER_HEAD(dest_bi_bh); } put_block: @@ -1102,9 +1059,10 @@ static int simplefs_rename(struct inode *src_dir, } release_new: - brelse(bh_fei_blk_dest); - brelse(bh_fei_blk_src); - brelse(dest_bh_ext); + RELEASE_BUFFER_HEAD(dest_ei_bh); + RELEASE_BUFFER_HEAD(src_ei_bh); + RELEASE_BUFFER_HEAD(dest_bi_bh); + RELEASE_BUFFER_HEAD(src_bi_bh); return ret; } @@ -1159,10 +1117,10 @@ static int simplefs_rmdir(struct inode *dir, struct dentry *dentry) eblock = (struct simplefs_file_ei_block *) bh->b_data; if (eblock->nr_files != 0) { - brelse(bh); + RELEASE_BUFFER_HEAD(bh); return -ENOTEMPTY; } - brelse(bh); + RELEASE_BUFFER_HEAD(bh); /* Remove directory with unlink */ return simplefs_unlink(dir, dentry); @@ -1234,7 +1192,7 @@ static int simplefs_link(struct dentry *src_dentry, if (dblock->nr_files != SIMPLEFS_FILES_PER_BLOCK) break; else - brelse(bh2); + RELEASE_BUFFER_HEAD(bh2); } /* write the file info into simplefs_dir_block */ @@ -1243,8 +1201,8 @@ static int simplefs_link(struct dentry *src_dentry, eblock->nr_files++; mark_buffer_dirty(bh2); mark_buffer_dirty(bh); - brelse(bh2); - brelse(bh); + RELEASE_BUFFER_HEAD(bh2); + RELEASE_BUFFER_HEAD(bh); inode_inc_link_count(old_inode); ihold(old_inode); @@ -1258,7 +1216,7 @@ static int simplefs_link(struct dentry *src_dentry, memset(&eblock->extents[avail], 0, sizeof(struct simplefs_extent)); } end: - brelse(bh); + RELEASE_BUFFER_HEAD(bh); return ret; } @@ -1351,7 +1309,7 @@ static int simplefs_symlink(struct inode *dir, if (dblock->nr_files != SIMPLEFS_FILES_PER_BLOCK) break; else - brelse(bh2); + RELEASE_BUFFER_HEAD(bh2); } /* write the file info into simplefs_dir_block */ @@ -1361,8 +1319,8 @@ static int simplefs_symlink(struct inode *dir, eblock->nr_files++; mark_buffer_dirty(bh2); mark_buffer_dirty(bh); - brelse(bh2); - brelse(bh); + RELEASE_BUFFER_HEAD(bh2); + RELEASE_BUFFER_HEAD(bh); inode->i_link = (char *) ci->i_data; memcpy(inode->i_link, symname, l); @@ -1381,7 +1339,7 @@ static int simplefs_symlink(struct inode *dir, put_blocks(SIMPLEFS_SB(sb), ci->ei_block, 1); put_inode(SIMPLEFS_SB(sb), inode->i_ino); iput(inode); - brelse(bh); + RELEASE_BUFFER_HEAD(bh); return ret; }