[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