All of lore.kernel.org
 help / color / mirror / Atom feed
* [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.