[PATCH 15/23] Add ngnfs_dir_mkdir() and debugfs command
Valerie Aurora
val at versity.com
Fri Apr 4 11:45:31 PDT 2025
Add ngnfs_dir_mkdir() and corresponding debugfs command. Other file
systems report a non-zero i_size for empty directories, so we also
give empty directories a non-zero file size. In our case it is 5
bytes, to match our convention for the effect on directory i_size of
real dirents of name plus null terminator, applied to "." and "..".
Signed-off-by: Valerie Aurora <val at versity.com>
---
cli/debugfs.c | 15 +++++++++++++++
shared/dir.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++----
shared/dir.h | 2 ++
shared/inode.c | 18 +++++++++++++++++-
4 files changed, 80 insertions(+), 5 deletions(-)
diff --git a/cli/debugfs.c b/cli/debugfs.c
index f2f12ba..4a13795 100644
--- a/cli/debugfs.c
+++ b/cli/debugfs.c
@@ -132,6 +132,20 @@ static void cmd_lookup(struct debugfs_context *ctx, int argc, char **argv)
lent.ig.gen);
}
+static void cmd_mkdir(struct debugfs_context *ctx, int argc, char **argv)
+{
+ int ret;
+
+ if (argc != 2) {
+ printf("must have one, and only one, directory name to create\n");
+ return;
+ }
+
+ ret = ngnfs_dir_mkdir(ctx->nfi, &ctx->cwd_ig, 0755, argv[1], strlen(argv[1]));
+ if (ret < 0)
+ print_err("mkdir", ret);
+}
+
static void cmd_mkfs(struct debugfs_context *ctx, int argc, char **argv)
{
int ret;
@@ -281,6 +295,7 @@ static struct command {
{ "cd", cmd_cd, },
{ "create", cmd_create, },
{ "lookup", cmd_lookup, },
+ { "mkdir", cmd_mkdir, },
{ "mkfs", cmd_mkfs, },
{ "quit", cmd_quit, },
{ "readdir", cmd_readdir, },
diff --git a/shared/dir.c b/shared/dir.c
index af5fd55..0dc69cf 100644
--- a/shared/dir.c
+++ b/shared/dir.c
@@ -263,22 +263,43 @@ static int insert_dirent(struct ngnfs_fs_info *nfi, struct ngnfs_transaction *tx
&last, insert_dirent_wr, da);
}
+/*
+ * Prevent creation of "." and "..", with appropriate error return
+ * codes.
+ */
+static int check_create_dots(u64 hash, mode_t mode)
+{
+ if (hash >= NGNFS_DIRENT_MIN_HASH)
+ return 0;
+
+ if (S_ISDIR(mode))
+ return -EEXIST;
+ else
+ return -EISDIR;
+}
/*
* Allocate a new inode and add a directory entry referencing it.
*/
-int ngnfs_dir_create(struct ngnfs_fs_info *nfi, struct ngnfs_inode_ino_gen *dir, umode_t mode,
+static int do_create(struct ngnfs_fs_info *nfi, struct ngnfs_inode_ino_gen *dir, umode_t mode,
char *name, size_t name_len)
{
struct {
struct ngnfs_transaction txn;
struct ngnfs_inode_txn_ref dir;
struct ngnfs_inode_txn_ref inode;
+ struct ngnfs_inode_ino_gen *parent_ig;
+ int nlink;
u64 nsec;
struct dirent_args da;
} *op;
int ret;
+ if (name_len > NGNFS_NAME_MAX) {
+ ret = -ENAMETOOLONG;
+ goto out;
+ }
+
op = kmalloc(sizeof(*op), GFP_NOFS);
if (!op) {
ret = -ENOMEM;
@@ -287,14 +308,23 @@ int ngnfs_dir_create(struct ngnfs_fs_info *nfi, struct ngnfs_inode_ino_gen *dir,
ngnfs_txn_init(&op->txn);
op->nsec = ktime_to_ns(ktime_get_real());
- init_dirent_args(&op->da, name, name_len, mode | S_IFREG);
+ if (S_ISDIR(mode)) {
+ op->nlink = 2;
+ op->parent_ig = dir;
+ } else {
+ op->nlink = 1;
+ op->parent_ig = NULL;
+ }
+
+ init_dirent_args(&op->da, name, name_len, mode);
do {
ret = ngnfs_inode_get(nfi, &op->txn, NBF_WRITE, dir, &op->dir) ?:
check_ifmt(op->dir.ninode, S_IFDIR, -ENOTDIR) ?:
+ check_create_dots(op->da.hash, mode) ?:
ngnfs_inode_alloc(nfi, &op->txn, &op->da.ig, &op->inode) ?:
- ngnfs_inode_init(&op->inode, &op->da.ig, 1, mode | S_IFREG, op->nsec,
- NULL) ?:
+ ngnfs_inode_init(&op->inode, &op->da.ig, op->nlink, mode, op->nsec,
+ op->parent_ig) ?:
update_dirent_args_dent(&op->da) ?:
insert_dirent(nfi, &op->txn, &op->dir, &op->da) ?:
update_dir(op->dir.tblk, op->dir.ninode, &op->da, 1);
@@ -307,6 +337,18 @@ out:
return ret;
}
+int ngnfs_dir_create(struct ngnfs_fs_info *nfi, struct ngnfs_inode_ino_gen *dir, umode_t mode,
+ char *name, size_t name_len)
+{
+ return do_create(nfi, dir, mode | S_IFREG, name, name_len);
+}
+
+int ngnfs_dir_mkdir(struct ngnfs_fs_info *nfi, struct ngnfs_inode_ino_gen *dir, umode_t mode,
+ char *name, size_t name_len)
+{
+ return do_create(nfi, dir, mode | S_IFDIR, name, name_len);
+}
+
struct readdir_args {
struct ngnfs_readdir_entry *ent;
size_t size;
diff --git a/shared/dir.h b/shared/dir.h
index 38c3095..b3ef067 100644
--- a/shared/dir.h
+++ b/shared/dir.h
@@ -8,6 +8,8 @@
int ngnfs_dir_create(struct ngnfs_fs_info *nfi, struct ngnfs_inode_ino_gen *dir, umode_t mode,
char *name, size_t name_len);
+int ngnfs_dir_mkdir(struct ngnfs_fs_info *nfi, struct ngnfs_inode_ino_gen *dir, umode_t mode,
+ char *name, size_t name_len);
/*
* Readdir fills the buffer with entries. The start of the buffer must
diff --git a/shared/inode.c b/shared/inode.c
index 982f8af..3698920 100644
--- a/shared/inode.c
+++ b/shared/inode.c
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
+#include <sys/stat.h>
+
#include "shared/lk/bug.h"
#include "shared/lk/byteorder.h"
#include "shared/lk/errno.h"
@@ -19,15 +21,29 @@
* to pack inode data into the rest of the block.
*/
+/*
+ * Most (all?) file systems have a non-zero i_size for a dir containing
+ * only "." and "..", so define one that matches how we count i_size for
+ * other dentries (name_len plus null terminator). It doesn't really
+ * matter.
+ */
+#define NGNFS_DIR_SIZE 5
+
int ngnfs_inode_init(struct ngnfs_inode_txn_ref *itref, struct ngnfs_inode_ino_gen *ig, u32 nlink,
umode_t mode, u64 nsec, struct ngnfs_inode_ino_gen *parent_ig)
{
struct ngnfs_txn_block *tblk = itref->tblk;
struct ngnfs_inode *ninode = itref->ninode;
+ u64 isize;
+
+ if (S_ISDIR(mode))
+ isize = NGNFS_DIR_SIZE;
+ else
+ isize = 0;
ngnfs_tblk_assign(tblk, ninode->ig.ino, cpu_to_le64(ig->ino));
ngnfs_tblk_assign(tblk, ninode->ig.gen, cpu_to_le64(ig->gen));
- ngnfs_tblk_assign(tblk, ninode->size, 0);
+ ngnfs_tblk_assign(tblk, ninode->size, cpu_to_le64(isize));
ngnfs_tblk_assign(tblk, ninode->version, cpu_to_le64(1));
if (parent_ig != NULL) {
ngnfs_tblk_assign(tblk, ninode->parent_ig.ino, cpu_to_le64(parent_ig->ino));
--
2.48.1
More information about the ngnfs-devel
mailing list