[PATCH 2/3] rpdfs: Add directory i_size accounting and helper functions
Valerie Aurora <[email protected]> Mon, 9 Mar 2026 22:04:02 +0100
| Newsgroups | dev.linux.lists.rpdfs-devel |
|---|---|
| Message-ID | <[email protected]> |
Implement directory i_size as the total length of all directory entry names including a null termination. Signed-off-by: Valerie Aurora <[email protected]> --- fs/rpdfs/dir.c | 48 ++++++++++++++++++++++++++++++++++------- fs/rpdfs/format-block.h | 8 +++++++ fs/rpdfs/mkfs.c | 2 +- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/fs/rpdfs/dir.c b/fs/rpdfs/dir.c index 7ae8faf74161..0de00704a603 100644 --- a/fs/rpdfs/dir.c +++ b/fs/rpdfs/dir.c @@ -363,6 +363,26 @@ static struct key_dent *alloc_key_dent(struct dentry *dentry, struct inode *inod return kd; } +static void init_dir_size(struct inode *inode) +{ + i_size_write(inode, RPDFS_EMPTY_DIR_LEN); +} + +static int is_dir_empty(struct inode *inode) +{ + return (i_size_read(inode) == RPDFS_EMPTY_DIR_LEN); +} + +/* + * Helper function for readability. All consistency/corruption checks + * should happen in the prepare phase, so there are no checks when + * making changes. + */ +static void update_dir_size(struct inode *inode, s32 len) +{ + i_size_write(inode, i_size_read(inode) + len); +} + /* * Allocate an inode in a block transaction and return an allocated vfs * inode at its ino/gen position. Like _iget, this inserts an I_NEW @@ -429,17 +449,21 @@ static struct inode *create_new_inode(struct mnt_idmap *idmap, struct inode *dir /* update vfs inodes */ inode_init_owner(idmap, inode, dir, mode); - if (S_ISDIR(mode)) + if (S_ISDIR(mode)) { set_nlink(inode, 2); - else + init_dir_size(inode); + } else { set_nlink(inode, 1); + } + rpdfs_inode_init_ops(inode); + /* update parent vfs inode and apply changes to referenced blocks */ if (S_ISDIR(mode)) inc_nlink(dir); - /* apply changes to referenced blocks */ if (kd) { + update_dir_size(dir, kd->dent.name_len + 1); kd->dent.ig = ig; apply_add_entry(rfi, &txn, dir, kd); } @@ -532,7 +556,7 @@ static int rpdfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, struct d goto out; } - /* prepare all the blocks for in the txn */ + /* prepare all the blocks for the txn */ do { ret = rpdfs_inode_txn_prepare(rfi, &txn, old_dir, RBAF_WRITE) ?: rpdfs_inode_txn_prepare(rfi, &txn, old_inode, RBAF_WRITE) ?: @@ -551,6 +575,11 @@ static int rpdfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, struct d if (ret < 0) goto out; + /* + * TODO: walk ancestors, and if there is a directory to be + * deleted, check if it is empty. + */ + /* apply changes to block structures */ apply_remove_entry(rfi, &txn, old_dir, old_kd); if (new_inode) @@ -558,11 +587,12 @@ static int rpdfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, struct d else apply_add_entry(rfi, &txn, new_dir, new_kd); - /* update vfs inodes: first dir sizes .. */ - i_size_write(old_dir, i_size_read(old_dir) - old_dentry->d_name.len); + /* update dir sizes */ + update_dir_size(old_dir, -(old_dentry->d_name.len + 1)); if (!new_inode) - i_size_write(new_dir, i_size_read(new_dir) + new_dentry->d_name.len); - /* .. then link counts .. */ + update_dir_size(new_dir, new_dentry->d_name.len + 1); + + /* and link counts */ if (new_inode) { drop_nlink(new_inode); if (S_ISDIR(new_inode->i_mode)) { @@ -570,10 +600,12 @@ static int rpdfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, struct d drop_nlink(new_inode); } } + if (S_ISDIR(old_inode->i_mode) && (old_dir != new_dir)) { drop_nlink(old_dir); inc_nlink(new_dir); } + /* .. and finally times */ now = inode_set_ctime_current(old_dir); inode_set_mtime_to_ts(old_dir, now); diff --git a/fs/rpdfs/format-block.h b/fs/rpdfs/format-block.h index 1ff315668d2f..d4a0fb78d670 100644 --- a/fs/rpdfs/format-block.h +++ b/fs/rpdfs/format-block.h @@ -210,6 +210,14 @@ struct rpdfs_dirent { #define RPDFS_DIRENT_DOT_DOT_HASH 1ULL #define RPDFS_DIRENT_MIN_HASH 2ULL +/* + * An empty dir contains pseudo entries for "." and "..". The reported + * size of directory is the length of the null-terminated names of all + * the directory entries. (The actual size is the number of blocks + * necessary to store the dirents btree.) + */ +#define RPDFS_EMPTY_DIR_LEN 5 + /* * xattrs are currently implemented as btree items, whose keys are the * hash of the name combined with the xattr_create_counter value in the diff --git a/fs/rpdfs/mkfs.c b/fs/rpdfs/mkfs.c index f4cbf5538b3b..94798799c960 100644 --- a/fs/rpdfs/mkfs.c +++ b/fs/rpdfs/mkfs.c @@ -45,7 +45,7 @@ int rpdfs_mkfs(struct rpdfs_fs_info *rfi) rinode->ig.ino = cpu_to_le64(RPDFS_ROOT_INO); rinode->ig.gen = cpu_to_le64(RPDFS_ROOT_GEN); - rinode->size = cpu_to_le64(5); /* name lens of . and .. with null term */ + rinode->size = cpu_to_le64(RPDFS_EMPTY_DIR_LEN); rinode->version = cpu_to_le64(1); rinode->nlink = cpu_to_le32(2); rinode->mode = cpu_to_le32(S_IFDIR | 0755); -- 2.49.0