[PATCH 17/23] Add ngnfs_dir_rename() and very basic debugfs command
Zach Brown
zab at zabbo.net
Wed Apr 9 16:24:30 PDT 2025
On Fri, Apr 04, 2025 at 08:45:33PM +0200, Valerie Aurora wrote:
> Add mostly functional ngnfs_dir_rename() that removes any existing
> target and checks for directory loops and non-empty target
> directories. The debugfs command is very limited: it can only rename a
> file from the current working directory to the parent directory.
> +static int igs_equal(struct ngnfs_inode_ino_gen *a, struct ngnfs_inode_ino_gen *b)
> +{
> + return (a->ino == b->ino) && (a->gen == b->gen);
I think we should use _Generic() to compare igs, regardless of which
endian type they're in at the time.
#define _ig_ino(a) \
_Generic(a, struct ngnfs_ino_gen *: le64_to_cpu(a->ino), \
struct ngnfs_node_ino_gen *: a->ino)
#define _ig_gen(a) \
_Generic(a, struct ngnfs_ino_gen *: le64_to_cpu(a->gen), \
struct ngnfs_node_ino_gen *: a->gen)
#define igs_equal(a, b) \
(_ig_ino(a) == _ig_ino(b) && _ig_gen(a) == _ig_gen(b))
It seemed better to compare the fields than to chose a type to convert
to and have a comparison of structs of that type. Maybe it results in
better code? Dunno, all this is totally untested.
> +/*
> + * To prevent loops when renaming a directory, we refuse to rename a
> + * source directory into one of its children. Check by walking up the
> + * path starting from the dst parent directory and comparing each
> + * directory to the src until we get to the root inode. On entry to this
> + * function, src_da is a directory.
> + */
> +static int check_ancestors(struct ngnfs_fs_info *nfi, struct ngnfs_transaction *txn,
> + struct ngnfs_inode_txn_ref *src_dir, struct dirent_args *src_da,
> + struct ngnfs_inode_txn_ref *dst_dir)
> +{
> + struct ngnfs_inode_txn_ref walk;
> + struct ngnfs_inode_ino_gen ig;
> + int ret;
> +
> + /* common case: parent dirs the same, therefore no loop */
> + if ((src_dir->ninode->ig.ino == dst_dir->ninode->ig.ino) &&
> + (src_dir->ninode->ig.gen == dst_dir->ninode->ig.gen))
> + return 0;
igs_equal()
> +static int inodes_equal(struct ngnfs_inode *a, struct ngnfs_inode *b) {
> + return (a->ig.ino == b->ig.ino) && (a->ig.gen == b->ig.gen);
> +}
And can get rid of this (which would have needed that '{' on a new line).
> +int ngnfs_dir_rename(struct ngnfs_fs_info *nfi, struct ngnfs_inode_ino_gen *src_dir_ig,
> + char *src_name, size_t src_name_len, struct ngnfs_inode_ino_gen *dst_dir_ig,
> + char *dst_name, size_t dst_name_len)
> +{
> + struct {
> + struct ngnfs_transaction txn;
> + struct ngnfs_inode_txn_ref src_dir, dst_dir, dst;
> + struct dirent_args src_da, dst_da;
> + } *op;
> + int ret;
> +
> + if ((src_name_len > NGNFS_NAME_MAX) || (dst_name_len > NGNFS_NAME_MAX)) {
> + ret = -ENAMETOOLONG;
> + goto out;
> + }
> +
> + op = kmalloc(sizeof(*op), GFP_NOFS);
> + if (!op) {
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + ngnfs_txn_init(&op->txn);
> + init_dirent_args(&op->src_da, src_name, src_name_len, 0);
> + init_dirent_args(&op->dst_da, dst_name, dst_name_len, 0);
> +
> + do {
> + ret = ngnfs_inode_get(nfi, &op->txn, NBF_WRITE, src_dir_ig, &op->src_dir) ?:
> + check_ifmt(op->src_dir.ninode, S_IFDIR, -ENOTDIR) ?:
> + lookup_dirent(nfi, &op->txn, &op->src_dir, &op->src_da) ?:
> + ngnfs_inode_get(nfi, &op->txn, NBF_WRITE, dst_dir_ig, &op->dst_dir) ?:
> + check_ifmt(op->dst_dir.ninode, S_IFDIR, -ENOTDIR) ?:
> + lookup_dirent_enoent_ok(nfi, &op->txn, &op->dst_dir, &op->dst_da) ?:
> + check_rename(nfi, &op->txn, &op->src_dir, &op->src_da, &op->dst_dir,
> + &op->dst_da) ?:
> + remove_dirent(nfi, &op->txn, &op->src_dir, &op->src_da) ?:
> + update_dir(op->src_dir.tblk, op->src_dir.ninode, &op->src_da, -1) ?:
> + replace_dirent(nfi, &op->txn, &op->dst_dir, &op->src_da) ?:
> + update_dir(op->dst_dir.tblk, op->dst_dir.ninode, &op->src_da, 1);
We should remove the lookups here and fold their error handling into the
dirents that are found, or not, by the removal of the source and the
insertion/change of the dest. The btree walks are expensive enough that
it's worth not doing it all twice.
- z
More information about the ngnfs-devel
mailing list