* [PATCH 1/1] rpdfs: Add support for rpdfs_link()
@ 2026-10-19 18:21 Chris Kirby
2026-10-23 17:50 ` Zach Brown
0 siblings, 1 reply; 2+ messages in thread
From: Chris Kirby @ 2026-10-19 18:21 UTC (permalink / raw)
To: rpdfs-devel; +Cc: Chris Kirby
Add support for the link inode operation.
Signed-off-by: Chris Kirby <ckirby@versity.com>
---
fs/rpdfs/dir.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 85 insertions(+)
diff --git a/fs/rpdfs/dir.c b/fs/rpdfs/dir.c
index 8a48817699d7..42af325012ab 100644
--- a/fs/rpdfs/dir.c
+++ b/fs/rpdfs/dir.c
@@ -10,6 +10,7 @@
#include "format-block.h"
#include "inode.h"
#include "rlock.h"
+#include "pr.h"
/*
* A collection of the arguments that describe a directory entry for the
@@ -393,6 +394,89 @@ 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_link(struct dentry *old_dentry, struct inode *new_dir,
+ struct dentry *new_dentry)
+{
+ struct rpdfs_fs_info *rfi = RPDFS_INODE_FS(new_dir);
+ struct inode *old_inode = d_inode(old_dentry);
+ struct inode *new_inode = d_inode(new_dentry);
+ struct inode *old_dir = d_inode(old_dentry->d_parent);
+ DECLARE_RPDFS_RLOCK_HOLD(old_dir_hold);
+ DECLARE_RPDFS_RLOCK_HOLD(new_dir_hold);
+ DECLARE_RPDFS_RLOCK_HOLD(old_inode_hold);
+ DECLARE_RPDFS_RLOCK_HOLD(new_inode_hold);
+ struct dent_args old_da;
+ struct dent_args new_da;
+ struct timespec64 now;
+ int ret = 0;
+
+ /*
+ * max link count and the existence of the link target were both checked
+ * by vfs_link(). But we don't yet have our rlocks, so we need to repeat
+ * those checks below. The existence check is handled by validate_dentry().
+ */
+
+ if (new_dentry->d_name.len > RPDFS_NAME_MAX) {
+ ret = -ENAMETOOLONG;
+ goto out;
+ }
+
+ init_dent_args(&old_da, old_dentry, NULL);
+ init_dent_args(&new_da, new_dentry, NULL);
+
+ ret = rpdfs_inode_rlock_refresh_many(old_dir, &old_dir_hold,
+ new_dir, &new_dir_hold,
+ old_inode, &old_inode_hold,
+ new_inode, &new_inode_hold,
+ RPDFS_RLOCK_MODE_EX_WR) ?:
+ validate_dentry(old_dir, old_dentry, &old_da) ?:
+ validate_dentry(new_dir, new_dentry, &new_da);
+ if (ret < 0)
+ goto out;
+
+ if (old_inode->i_nlink >= RPDFS_LINK_MAX) {
+ ret = -EMLINK;
+ goto out_unlock;
+ }
+
+ set_dent_args_inode(&new_da, old_inode);
+ ret = insert_entry(new_dir, &new_da);
+ if (ret < 0)
+ goto out_unlock;
+
+ inc_nlink(new_dir);
+ inc_nlink(old_inode);
+
+ set_dir_i_size(new_dir);
+
+ now = inode_set_ctime_current(old_dir);
+ inode_set_mtime_to_ts(old_dir, now);
+ if (new_dir != old_dir) {
+ inode_set_ctime_to_ts(new_dir, now);
+ inode_set_mtime_to_ts(new_dir, now);
+ }
+ inode_set_ctime_to_ts(old_inode, now);
+ ihold(old_inode);
+ mark_inode_dirty(old_inode);
+ mark_inode_dirty(new_dir);
+
+ d_instantiate(new_dentry, old_inode);
+
+ rpdfs_inode_update(rfi, old_inode);
+ rpdfs_inode_update(rfi, old_dir);
+ if (new_dir != old_dir)
+ rpdfs_inode_update(rfi, new_dir);
+
+out_unlock:
+ rpdfs_rlock_unlock(rfi, &old_dir_hold);
+ rpdfs_rlock_unlock(rfi, &new_dir_hold);
+ rpdfs_rlock_unlock(rfi, &old_inode_hold);
+ rpdfs_rlock_unlock(rfi, &new_inode_hold);
+
+out:
+ return ret;
+}
+
/*
* The VFS did a bunch of checks before calling our unlink
* implementation, but some other node could have made changes between
@@ -673,6 +757,7 @@ static int rpdfs_readdir(struct file *file, struct dir_context *ctx)
const struct inode_operations rpdfs_dir_iops = {
.create = rpdfs_create,
.getattr = rpdfs_getattr,
+ .link = rpdfs_link,
.lookup = rpdfs_lookup,
.mkdir = rpdfs_mkdir,
.rename = rpdfs_rename,
--
2.55.0
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH 1/1] rpdfs: Add support for rpdfs_link()
2026-10-19 18:21 [PATCH 1/1] rpdfs: Add support for rpdfs_link() Chris Kirby
@ 2026-10-23 17:50 ` Zach Brown
0 siblings, 0 replies; 2+ messages in thread
From: Zach Brown @ 2026-10-23 17:50 UTC (permalink / raw)
To: Chris Kirby; +Cc: rpdfs-devel
On Mon, Oct 19, 2026 at 06:21:50PM +0000, Chris Kirby wrote:
> +static int rpdfs_link(struct dentry *old_dentry, struct inode *new_dir,
> + struct dentry *new_dentry)
> +{
> + struct rpdfs_fs_info *rfi = RPDFS_INODE_FS(new_dir);
> + struct inode *old_inode = d_inode(old_dentry);
> + struct inode *new_inode = d_inode(new_dentry);
> + struct inode *old_dir = d_inode(old_dentry->d_parent);
I'm guessing a lot of this code was lifted from rename. In _link we
don't need to access the old_dir at all. Take a peek at other link
implementations, the pattern seems to be:
link(old_dentry, dir, dentry) { inode = d_inode(dentry); }
Then we don't need to validate the old dir's dentry name (so we can just
have one "da"), lock it, update it, etc.
> + rpdfs_inode_update(rfi, old_inode);
> + rpdfs_inode_update(rfi, old_dir);
> + if (new_dir != old_dir)
> + rpdfs_inode_update(rfi, new_dir);
> +
> +out_unlock:
> + rpdfs_rlock_unlock(rfi, &old_dir_hold);
> + rpdfs_rlock_unlock(rfi, &new_dir_hold);
> + rpdfs_rlock_unlock(rfi, &old_inode_hold);
> + rpdfs_rlock_unlock(rfi, &new_inode_hold);
There's a (unfortunate, gross) pattern here where insert_entry can have
modified the dir's dirent eht blocks before returning an error. We
always need to update the dir if we've called insert_, even on error.
I'm open to ways to clean it up so it's not down to us remembering that
this is the case :(.
- z
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-23 17:50 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-19 18:21 [PATCH 1/1] rpdfs: Add support for rpdfs_link() Chris Kirby
2026-10-23 17:50 ` 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.