* [PATCH 0/3] Add rpdfs_unlink and rpdfs_rmdir
@ 2026-03-09 21:04 Valerie Aurora
2026-03-09 21:04 ` [PATCH 1/3] rpdfs: Initialize dirents field in new rpdfs_inode_info Valerie Aurora
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Valerie Aurora @ 2026-03-09 21:04 UTC (permalink / raw)
To: rpdfs-devel; +Cc: Valerie Aurora
Add rpdfs_unlink() and rpdfs_rmdir(), plus a couple of supporting
patches that fix an initialization problem and add directory i_size
accounting and helper functions.
Valerie Aurora (3):
rpdfs: Initialize dirents field in new rpdfs_inode_info
rpdfs: Add directory i_size accounting and helper functions
rpdfs: Add rpdfs_unlink and rpdfs_rmdir
fs/rpdfs/dir.c | 148 +++++++++++++++++++++++++++++++++++++---
fs/rpdfs/format-block.h | 8 +++
fs/rpdfs/inode.c | 3 +
fs/rpdfs/mkfs.c | 2 +-
4 files changed, 152 insertions(+), 9 deletions(-)
--
2.49.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/3] rpdfs: Initialize dirents field in new rpdfs_inode_info
2026-03-09 21:04 [PATCH 0/3] Add rpdfs_unlink and rpdfs_rmdir Valerie Aurora
@ 2026-03-09 21:04 ` Valerie Aurora
2026-03-09 21:04 ` [PATCH 2/3] rpdfs: Add directory i_size accounting and helper functions Valerie Aurora
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Valerie Aurora @ 2026-03-09 21:04 UTC (permalink / raw)
To: rpdfs-devel; +Cc: Valerie Aurora
A newly allocated rpdfs_inode_info needs its dirents btree_root
initialized to zero.
Signed-off-by: Valerie Aurora <val@versity.com>
---
fs/rpdfs/inode.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/fs/rpdfs/inode.c b/fs/rpdfs/inode.c
index 2d83fa6352be..44f8cd515aa6 100644
--- a/fs/rpdfs/inode.c
+++ b/fs/rpdfs/inode.c
@@ -294,6 +294,9 @@ struct inode *rpdfs_new_inode(struct super_block *sb, struct rpdfs_ino_gen *ig)
ri->refresh_wcount = 0;
ri->xattr_creates = 0;
ri->ig = *ig;
+ ri->dirents.height = 0;
+ ri->dirents.ref.bnr = 0;
+ ri->dirents.ref.alloc_counter = 0;
inode->i_ino = le64_to_cpu(ri->ig.ino);
ret = insert_inode_locked4(inode, ig_hashval(ig), rpdfs_iget_test, ig);
--
2.49.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/3] rpdfs: Add directory i_size accounting and helper functions
2026-03-09 21:04 [PATCH 0/3] Add rpdfs_unlink and rpdfs_rmdir Valerie Aurora
2026-03-09 21:04 ` [PATCH 1/3] rpdfs: Initialize dirents field in new rpdfs_inode_info Valerie Aurora
@ 2026-03-09 21:04 ` Valerie Aurora
2026-03-09 21:04 ` [PATCH 3/3] rpdfs: Add rpdfs_unlink and rpdfs_rmdir Valerie Aurora
2026-03-10 16:34 ` [PATCH 0/3] " Zach Brown
3 siblings, 0 replies; 5+ messages in thread
From: Valerie Aurora @ 2026-03-09 21:04 UTC (permalink / raw)
To: rpdfs-devel; +Cc: Valerie Aurora
Implement directory i_size as the total length of all directory entry
names including a null termination.
Signed-off-by: Valerie Aurora <val@versity.com>
---
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
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/3] rpdfs: Add rpdfs_unlink and rpdfs_rmdir
2026-03-09 21:04 [PATCH 0/3] Add rpdfs_unlink and rpdfs_rmdir Valerie Aurora
2026-03-09 21:04 ` [PATCH 1/3] rpdfs: Initialize dirents field in new rpdfs_inode_info Valerie Aurora
2026-03-09 21:04 ` [PATCH 2/3] rpdfs: Add directory i_size accounting and helper functions Valerie Aurora
@ 2026-03-09 21:04 ` Valerie Aurora
2026-03-10 16:34 ` [PATCH 0/3] " Zach Brown
3 siblings, 0 replies; 5+ messages in thread
From: Valerie Aurora @ 2026-03-09 21:04 UTC (permalink / raw)
To: rpdfs-devel; +Cc: Valerie Aurora
Add unlink and rmdir, including checking for an empty directory and
splitting out error checking into a proper prepare_unlink() function.
Signed-off-by: Valerie Aurora <val@versity.com>
---
fs/rpdfs/dir.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 100 insertions(+)
diff --git a/fs/rpdfs/dir.c b/fs/rpdfs/dir.c
index 0de00704a603..7d51c133cba0 100644
--- a/fs/rpdfs/dir.c
+++ b/fs/rpdfs/dir.c
@@ -503,6 +503,48 @@ static int create_and_instantiate_new(struct mnt_idmap *idmap, struct inode *dir
return ret;
}
+/*
+ * The VFS did a bunch of checks before calling our unlink
+ * implementation, but some other node could have made changes between
+ * then and now. The prepare functions only succeed if the inodes have
+ * not been freed or reused, the directory entry to be removed is still
+ * there, and there is no detected corruption (which is distinct from
+ * changes made by other nodes).
+ */
+static int prepare_unlink(struct inode *dir, struct inode *inode, struct dentry *dentry)
+{
+ int ret;
+
+ /* normal failures due to other nodes making changes */
+ if (S_ISDIR(inode->i_mode)) {
+ if (!is_dir_empty(inode)) {
+ ret = -ENOTEMPTY;
+ goto out;
+ }
+ }
+
+ /* consistency/corruption checks */
+ if (S_ISDIR(inode->i_mode)) {
+ if (inode->i_nlink != 2) {
+ pr_warn("empty dir ino %lu has bad n_link %d",
+ inode->i_ino, inode->i_nlink);
+ ret = -EUCLEAN;
+ goto out;
+ }
+ } else {
+ if (inode->i_nlink < 1) {
+ pr_warn("attempting to unlink ino %lu but n_link %d is already < 1",
+ inode->i_ino, inode->i_nlink);
+ ret = -EUCLEAN;
+ goto out;
+ }
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
static int rpdfs_create(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry,
umode_t mode, bool excl)
{
@@ -515,6 +557,62 @@ static struct dentry *rpdfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
return ERR_PTR(create_and_instantiate_new(idmap, dir, dentry, S_IFDIR | mode));
}
+static int rpdfs_unlink(struct inode *dir, struct dentry *dentry)
+{
+ struct rpdfs_fs_info *rfi = RPDFS_INODE_FS(dir);
+ struct inode *inode = d_inode(dentry);
+ struct key_dent *kd = NULL;
+ DECLARE_RPDFS_TXN(txn);
+ int ret;
+
+ kd = alloc_key_dent(dentry, inode);
+ if (!kd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* prepare all the blocks for the txn */
+ do {
+ ret = rpdfs_inode_txn_prepare(rfi, &txn, dir, RBAF_WRITE) ?:
+ rpdfs_inode_txn_prepare(rfi, &txn, inode, RBAF_WRITE) ?:
+ prepare_remove_entry(rfi, &txn, dir, kd) ?:
+ prepare_unlink(dir, inode, dentry);
+ } while (rpdfs_txn_retry(rfi, &txn, &ret));
+ if (ret < 0)
+ goto out;
+
+ /* apply changes to block structures */
+ apply_remove_entry(rfi, &txn, dir, kd);
+
+ /* update link count and metadata change time */
+ drop_nlink(inode);
+ if (S_ISDIR(inode->i_mode)) {
+ drop_nlink(dir);
+ drop_nlink(inode);
+ }
+ inode_set_ctime_current(inode);
+
+ /* update parent dir size and data/metadata times */
+ update_dir_size(dir, -(dentry->d_name.len + 1));
+ inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
+
+ /* update block storage of vfs inodes */
+ rpdfs_inode_txn_update(rfi, &txn, dir);
+ rpdfs_inode_txn_update(rfi, &txn, inode);
+
+ ret = 0;
+out:
+ rpdfs_txn_reset(rfi, &txn);
+ kfree(kd);
+
+ return ret;
+}
+
+static int rpdfs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ return rpdfs_unlink(dir, dentry);
+}
+
/*
* The vfs has verified the cached directories. Our inode refresh will
* fail if the inodes have been reused, so we don't have to test if
@@ -714,6 +812,8 @@ const struct inode_operations rpdfs_dir_iops = {
.mkdir = rpdfs_mkdir,
.rename = rpdfs_rename,
.setattr = rpdfs_setattr,
+ .unlink = rpdfs_unlink,
+ .rmdir = rpdfs_rmdir,
};
const struct file_operations rpdfs_dir_fops = {
--
2.49.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 0/3] Add rpdfs_unlink and rpdfs_rmdir
2026-03-09 21:04 [PATCH 0/3] Add rpdfs_unlink and rpdfs_rmdir Valerie Aurora
` (2 preceding siblings ...)
2026-03-09 21:04 ` [PATCH 3/3] rpdfs: Add rpdfs_unlink and rpdfs_rmdir Valerie Aurora
@ 2026-03-10 16:34 ` Zach Brown
3 siblings, 0 replies; 5+ messages in thread
From: Zach Brown @ 2026-03-10 16:34 UTC (permalink / raw)
To: Valerie Aurora; +Cc: rpdfs-devel
On Mon, Mar 09, 2026 at 10:04:00PM +0100, Valerie Aurora wrote:
> Add rpdfs_unlink() and rpdfs_rmdir(), plus a couple of supporting
> patches that fix an initialization problem and add directory i_size
> accounting and helper functions.
>
> Valerie Aurora (3):
> rpdfs: Initialize dirents field in new rpdfs_inode_info
> rpdfs: Add directory i_size accounting and helper functions
> rpdfs: Add rpdfs_unlink and rpdfs_rmdir
Great stuff, applied! Thanks,
- z
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-03-10 16:34 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-09 21:04 [PATCH 0/3] Add rpdfs_unlink and rpdfs_rmdir Valerie Aurora
2026-03-09 21:04 ` [PATCH 1/3] rpdfs: Initialize dirents field in new rpdfs_inode_info Valerie Aurora
2026-03-09 21:04 ` [PATCH 2/3] rpdfs: Add directory i_size accounting and helper functions Valerie Aurora
2026-03-09 21:04 ` [PATCH 3/3] rpdfs: Add rpdfs_unlink and rpdfs_rmdir Valerie Aurora
2026-03-10 16:34 ` [PATCH 0/3] " Zach Brown
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.