[PATCH 08/14] Add ngnfs_dir_get_dirent() and debugfs lookup command

Valerie Aurora val at versity.com
Thu Feb 27 06:16:17 PST 2025


Add function to return ngnfs directory entries and associated debugfs
command for debugging purposes.

Signed-off-by: Valerie Aurora <val at versity.com>
---
 cli/debugfs.c |  47 ++++++++++++++++++-
 shared/dir.c  | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++
 shared/dir.h  |   8 ++++
 3 files changed, 181 insertions(+), 1 deletion(-)

diff --git a/cli/debugfs.c b/cli/debugfs.c
index 1972f13..9d3bd5d 100644
--- a/cli/debugfs.c
+++ b/cli/debugfs.c
@@ -14,8 +14,8 @@
 #include "shared/lk/kernel.h"
 #include "shared/lk/types.h"
 
-#include "shared/format-block.h"
 #include "shared/dir.h"
+#include "shared/format-block.h"
 #include "shared/inode.h"
 #include "shared/log.h"
 #include "shared/mkfs.h"
@@ -48,6 +48,50 @@ static void cmd_create(struct debugfs_context *ctx, int argc, char **argv)
 		printf("create error: "ENOF"\n", ENOA(-ret));
 }
 
+static void cmd_lookup(struct debugfs_context *ctx, int argc, char **argv)
+{
+	struct ngnfs_dirent *dent;
+	char *name;
+	int ret;
+
+	if (argc != 2) {
+		printf("usage: lookup <pathname>\n");
+		return;
+	}
+
+	name = argv[1];
+
+	dent = malloc(offsetof(struct ngnfs_dirent, name) + strlen(name));
+	if (!dent) {
+		log("lookup error: "ENOF"\n", ENOA(ENOENT));
+		return;
+	}
+
+
+	ret = ngnfs_dir_get_dirent(ctx->nfi, ctx->cwd_ino, name, strlen(name), dent);
+	if (ret < 0) {
+		if (ret == -ENAMETOOLONG)
+			printf("lookup: %s name too long\n", name);
+		else if (ret == -ENOENT)
+			printf("lookup: %s does not exist\n", name);
+		else
+			log("lookup error: "ENOF"\n", ENOA(-ret));
+		return;
+	}
+
+	printf("name: %.*s\n"
+	       "name_len: %d\n"
+	       "dtype: %o\n"
+	       "ino: %llu\n"
+	       "gen: %llu\n",
+	       dent->name_len,
+	       dent->name,
+	       dent->name_len,
+	       ngnfs_type_to_dtype(dent->type),
+	       le64_to_cpu(dent->ino),
+	       le64_to_cpu(dent->version));
+}
+
 static void cmd_mkfs(struct debugfs_context *ctx, int argc, char **argv)
 {
 	int ret;
@@ -158,6 +202,7 @@ static struct command {
 	void (*func)(struct debugfs_context *ctx, int argc, char **argv);
 } commands[] = {
 	{ "create", cmd_create, },
+	{ "lookup", cmd_lookup, },
 	{ "mkfs", cmd_mkfs, },
 	{ "quit", cmd_quit, },
 	{ "readdir", cmd_readdir, },
diff --git a/shared/dir.c b/shared/dir.c
index 0439816..4b95835 100644
--- a/shared/dir.c
+++ b/shared/dir.c
@@ -6,6 +6,7 @@
 #include "shared/lk/bug.h"
 #include "shared/lk/byteorder.h"
 #include "shared/lk/container_of.h"
+#include "shared/lk/err.h"
 #include "shared/lk/errno.h"
 #include "shared/lk/fs_types.h"
 #include "shared/lk/kernel.h"
@@ -446,3 +447,129 @@ int ngnfs_dir_readdir(struct ngnfs_fs_info *nfi, u64 dir_ino, u64 pos,
 out:
 	return ret ?: ra.nr;
 }
+
+static int fill_lookup_rd(struct ngnfs_btree_key *key, void *val, size_t val_size, void *arg)
+{
+	struct dirent_args *da = arg;
+	struct ngnfs_dirent *dst = &da->dent;
+	struct ngnfs_dirent *src = val;
+
+	if (!src)
+		return -ENOENT;
+
+	if (!names_equal(src->name, src->name_len, dst->name, dst->name_len))
+		return NGNFS_BTREE_ITER_CONTINUE;
+
+	da->dent_size = offsetof(struct ngnfs_dirent, name) + src->name_len;
+	memcpy(dst, src, da->dent_size);
+
+	return 0;
+}
+
+static int lookup_dots(struct ngnfs_fs_info *nfi, struct ngnfs_transaction *txn,
+		       struct ngnfs_inode_txn_ref *dir, struct dirent_args *da)
+{
+	struct ngnfs_inode_txn_ref parent_dir;
+	int ret;
+
+	if (da->hash >= NGNFS_DIRENT_MIN_HASH)
+		return -ENOENT;
+
+	if (da->hash == NGNFS_DIRENT_DOT_HASH) {
+		fill_dent(dir->ninode->ino, dir->ninode->version,
+			  mode_to_type(le32_to_cpu(dir->ninode->mode)), ".", 1, &da->dent);
+		return 0;
+	}
+
+	/* remaining case is .. */
+	ret = ngnfs_inode_get(nfi, txn, NBF_READ, le64_to_cpu(dir->ninode->parent_ino),
+			      &parent_dir);
+	if (ret < 0)
+		return ret;
+
+	fill_dent(parent_dir.ninode->ino, parent_dir.ninode->version,
+		  mode_to_type(le32_to_cpu(parent_dir.ninode->mode)), "..", 2, &da->dent);
+
+	return 0;
+}
+
+static int lookup_iter(struct ngnfs_fs_info *nfi, struct ngnfs_transaction *txn,
+		       struct ngnfs_inode_txn_ref *dir, struct dirent_args *da)
+{
+	struct ngnfs_btree_key key;
+	struct ngnfs_btree_key last;
+	int ret;
+
+	init_dirent_key(&key, da->hash);
+	init_dirent_key(&last, da->hash | NGNFS_DIRENT_COLL_BIT);
+
+	ret = lookup_dots(nfi, txn, dir, da);
+	if (ret == 0)
+		return ret;
+
+	return ngnfs_btree_read_iter(nfi, txn, &dir->ninode->dirents, &key, NULL, &last,
+				     fill_lookup_rd, da);
+
+}
+
+static int do_lookup(struct ngnfs_fs_info *nfi, u64 dir_ino, char *name, size_t name_len,
+		     struct dirent_args *da)
+{
+	struct {
+		struct ngnfs_transaction txn;
+		struct ngnfs_inode_txn_ref dir;
+		struct ngnfs_btree_key key;
+		struct ngnfs_btree_key last;
+	} *op;
+	int ret;
+
+	if (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(da, name, name_len, 0, 0);
+	init_dirent_key(&op->key, da->hash);
+	init_dirent_key(&op->last, da->hash | NGNFS_DIRENT_COLL_BIT);
+
+	do {
+		ret = ngnfs_inode_get(nfi, &op->txn, NBF_READ, dir_ino, &op->dir)		?:
+		      check_ifmt(op->dir.ninode, S_IFDIR, -ENOTDIR)				?:
+		      lookup_iter(nfi, &op->txn, &op->dir, da);
+
+	} while (ngnfs_txn_retry(nfi, &op->txn, &ret));
+
+	ngnfs_txn_teardown(nfi, &op->txn);
+
+	kfree(op);
+out:
+	return ret;
+}
+
+int ngnfs_dir_get_dirent(struct ngnfs_fs_info *nfi, u64 dir_ino, char *name, size_t name_len,
+			 struct ngnfs_dirent *dent)
+{
+	struct dirent_args *da;
+	int ret;
+
+	da = kmalloc(sizeof(struct dirent_args), GFP_NOFS);
+	if (!da) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = do_lookup(nfi, dir_ino, name, name_len, da);
+	if (ret == 0)
+		memcpy(dent, &da->dent, da->dent_size);
+
+	kfree(da);
+out:
+	return ret;
+}
diff --git a/shared/dir.h b/shared/dir.h
index b333686..714ee1a 100644
--- a/shared/dir.h
+++ b/shared/dir.h
@@ -42,4 +42,12 @@ enum ngnfs_dentry_type;
 
 unsigned int ngnfs_type_to_dtype(enum ngnfs_dentry_type type);
 
+/*
+ * Lookup and return an on-disk directory entry, for debugging purposes.
+ * Does not return . or .., for example.
+ */
+struct ngnfs_dirent;
+int ngnfs_dir_get_dirent(struct ngnfs_fs_info *nfi, u64 dir_ino, char *name, size_t name_len,
+			 struct ngnfs_dirent *dent);
+
 #endif
-- 
2.48.1




More information about the ngnfs-devel mailing list