[PATCH 07/23] Move inode number and generation into ino_gen struct
Valerie Aurora
val at versity.com
Fri Apr 4 11:45:23 PDT 2025
Files/dirs are uniquely identifed by the combination of inode number
and generation number. The generation number is incremented every time
an inode is freed and reallocated. In almost every case, we should use
both inode and generation number when performing operations. Encourage
this by using a combination inode number/generation struct. Also
remove the unused inode number argument from init_dirent_args().
Signed-off-by: Valerie Aurora <val at versity.com>
---
cli/debugfs.c | 21 +++++++++++----------
shared/dir.c | 43 ++++++++++++++++++++++---------------------
shared/dir.h | 18 +++++++++---------
shared/format-block.h | 22 ++++++++++++++++++----
shared/inode.c | 34 +++++++++++++++++++---------------
shared/inode.h | 20 +++++++++++++-------
shared/mkfs.c | 5 +++--
7 files changed, 95 insertions(+), 68 deletions(-)
diff --git a/cli/debugfs.c b/cli/debugfs.c
index 3b9aab6..a556cc7 100644
--- a/cli/debugfs.c
+++ b/cli/debugfs.c
@@ -26,7 +26,7 @@
struct debugfs_context {
struct ngnfs_fs_info *nfi;
- u64 cwd_ino;
+ struct ngnfs_inode_ino_gen cwd_ig;
bool quit;
int ret;
};
@@ -43,7 +43,7 @@ static void cmd_create(struct debugfs_context *ctx, int argc, char **argv)
return;
}
- ret = ngnfs_dir_create(ctx->nfi, ctx->cwd_ino, 0644, argv[1], strlen(argv[1]));
+ ret = ngnfs_dir_create(ctx->nfi, &ctx->cwd_ig, 0644, argv[1], strlen(argv[1]));
if (ret < 0)
printf("create error: "ENOF"\n", ENOA(-ret));
}
@@ -87,7 +87,7 @@ static void cmd_readdir(struct debugfs_context *ctx, int argc, char **argv)
pos = 0;
while (true) {
- ret = ngnfs_dir_readdir(ctx->nfi, ctx->cwd_ino, pos, buf, size);
+ ret = ngnfs_dir_readdir(ctx->nfi, &ctx->cwd_ig, pos, buf, size);
if (ret <= 0) {
if (ret < 0)
printf("readdir error: "ENOF"\n", ENOA(-ret));
@@ -96,8 +96,8 @@ static void cmd_readdir(struct debugfs_context *ctx, int argc, char **argv)
ent = buf;
for (i = 0; i < ret; i++) {
- printf("%020llu %10llu %5llu %05o %.*s\n", ent->pos, ent->ino, ent->gen,
- ent->dtype, ent->name_len, ent->name);
+ printf("%020llu %10llu %5llu %05o %.*s\n", ent->pos, ent->ig.ino,
+ ent->ig.gen, ent->dtype, ent->name_len, ent->name);
pos = ent->pos;
ent = (void *)ent + ent->next_offset;
}
@@ -113,10 +113,11 @@ static void cmd_readdir(struct debugfs_context *ctx, int argc, char **argv)
static void cmd_stat(struct debugfs_context *ctx, int argc, char **argv)
{
+ struct ngnfs_inode_ino_gen root_ig = INIT_NGNFS_ROOT_IG;
struct ngnfs_inode ninode;
int ret;
- ret = ngnfs_inode_read_copy(ctx->nfi, NGNFS_ROOT_INO, &ninode, sizeof(ninode));
+ ret = ngnfs_inode_read_copy(ctx->nfi, &root_ig, &ninode, sizeof(ninode));
if (ret < 0) {
log("stat error: %d", ret);
@@ -132,8 +133,8 @@ static void cmd_stat(struct debugfs_context *ctx, int argc, char **argv)
"ctime: %llu\n"
"mtime: %llu\n"
"crtime: %llu\n",
- le64_to_cpu(ninode.ino),
- le64_to_cpu(ninode.gen),
+ le64_to_cpu(ninode.ig.ino),
+ le64_to_cpu(ninode.ig.gen),
le32_to_cpu(ninode.nlink),
le32_to_cpu(ninode.mode),
le64_to_cpu(ninode.atime_nsec),
@@ -232,7 +233,7 @@ static void debugfs_thread(struct thread *thr, void *arg)
qsort(commands, ARRAY_SIZE(commands), sizeof(commands[0]), compar_cmd_names);
for (;;) {
- fprintf(stdout, "<%llu> $ ", ctx->cwd_ino);
+ fprintf(stdout, "<%llu> $ ", ctx->cwd_ig.ino);
fflush(stdout);
if (!fgets(line, LINE_SIZE, stdin))
break;
@@ -268,7 +269,7 @@ static int debugfs_func(int argc, char **argv)
struct ngnfs_fs_info nfi = INIT_NGNFS_FS_INFO;
struct debugfs_context ctx = {
.nfi = &nfi,
- .cwd_ino = NGNFS_ROOT_INO,
+ .cwd_ig = { NGNFS_ROOT_INO, 1 },
.quit = false,
};
struct thread thr;
diff --git a/shared/dir.c b/shared/dir.c
index b642c6e..fe2441a 100644
--- a/shared/dir.c
+++ b/shared/dir.c
@@ -52,9 +52,9 @@ static u64 name_hash(void *name, size_t name_len)
* copy in and out any dirent as we work with them.
*/
struct dirent_args {
+ struct ngnfs_inode_ino_gen ig;
u64 hash;
size_t dent_size;
- u64 ino;
struct ngnfs_dirent dent;
u8 __max_name_storage[NGNFS_NAME_MAX - sizeof_field(struct ngnfs_dirent, name)];
@@ -109,29 +109,31 @@ static unsigned int pers_dtype_to_abi_dtype(enum ngnfs_dentry_type type)
return DT_UNKNOWN;
}
-static void init_dirent_args(struct dirent_args *da, char *name, size_t name_len, u64 ino,
- mode_t mode)
+static void init_dirent_args(struct dirent_args *da, char *name, size_t name_len, mode_t mode)
{
+ da->ig.ino = 0;
+ da->ig.gen = 0;
da->hash = name_hash(name, name_len);
da->dent_size = offsetof(struct ngnfs_dirent, name) + name_len;
- da->dent.ino = cpu_to_le64(ino);
- da->dent.version = cpu_to_le64(0); /* XXX :/ */
+ da->dent.ig.ino = cpu_to_le64(0);
+ da->dent.ig.gen = cpu_to_le64(0);
da->dent.pers_dtype = mode_to_pers_type(mode);
da->dent.name_len = name_len;
+ memcpy(da->dent.name, name, name_len);
/* ensure that we're stitching together a contiguous max name buffer */
BUILD_BUG_ON(offsetofend(struct dirent_args, dent.name) !=
offsetof(struct dirent_args, __max_name_storage));
BUILD_BUG_ON((sizeof_field(struct dirent_args, dent.name) +
sizeof_field(struct dirent_args, __max_name_storage)) != NGNFS_NAME_MAX);
-
- memcpy(da->dent.name, name, name_len);
}
-static int update_dirent_args_ino(struct dirent_args *da, u64 ino)
+/* caller has filled out da->ig, update the dent.ig to match */
+static int update_dirent_args_dent(struct dirent_args *da)
{
- da->dent.ino = cpu_to_le64(ino);
+ da->dent.ig.ino = cpu_to_le64(da->ig.ino);
+ da->dent.ig.gen = cpu_to_le64(da->ig.gen);
return 0;
}
@@ -236,14 +238,13 @@ static int insert_dirent(struct ngnfs_fs_info *nfi, struct ngnfs_transaction *tx
/*
* Allocate a new inode and add a directory entry referencing it.
*/
-int ngnfs_dir_create(struct ngnfs_fs_info *nfi, u64 dir_ino, umode_t mode, char *name,
- size_t name_len)
+int ngnfs_dir_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;
- u64 ino;
u64 nsec;
struct dirent_args da;
} *op;
@@ -257,14 +258,14 @@ int ngnfs_dir_create(struct ngnfs_fs_info *nfi, u64 dir_ino, umode_t mode, char
ngnfs_txn_init(&op->txn);
op->nsec = ktime_to_ns(ktime_get_real());
- init_dirent_args(&op->da, name, name_len, 0, mode | S_IFREG);
+ init_dirent_args(&op->da, name, name_len, mode | S_IFREG);
do {
- ret = ngnfs_inode_get(nfi, &op->txn, NBF_WRITE, dir_ino, &op->dir) ?:
+ ret = ngnfs_inode_get(nfi, &op->txn, NBF_WRITE, dir, &op->dir) ?:
check_ifmt(op->dir.ninode, S_IFDIR, -ENOTDIR) ?:
- ngnfs_inode_alloc(nfi, &op->txn, &op->ino, &op->inode) ?:
- ngnfs_inode_init(&op->inode, op->ino, 1, 1, mode | S_IFREG, op->nsec) ?:
- update_dirent_args_ino(&op->da, op->ino) ?:
+ 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) ?:
+ 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);
@@ -296,8 +297,8 @@ static int fill_dirent_rd(struct ngnfs_btree_key *key, void *val, size_t val_siz
aligned = ALIGN(bytes, __alignof__(struct ngnfs_readdir_entry));
ra->ent->pos = le64_to_cpu(key->k[0]);
- ra->ent->ino = le64_to_cpu(dent->ino);
- ra->ent->gen = le64_to_cpu(dent->version);
+ ra->ent->ig.ino = le64_to_cpu(dent->ig.ino);
+ ra->ent->ig.gen = le64_to_cpu(dent->ig.gen);
ra->ent->next_offset = aligned;
ra->ent->dtype = pers_dtype_to_abi_dtype(dent->pers_dtype);
ra->ent->name_len = dent->name_len;
@@ -333,7 +334,7 @@ static int fill_dirent_rd(struct ngnfs_btree_key *key, void *val, size_t val_siz
* the last entry so that the caller doesn't have to discover eof with a
* final call that returns nothing.)
*/
-int ngnfs_dir_readdir(struct ngnfs_fs_info *nfi, u64 dir_ino, u64 pos,
+int ngnfs_dir_readdir(struct ngnfs_fs_info *nfi, struct ngnfs_inode_ino_gen *dir_ig, u64 pos,
struct ngnfs_readdir_entry *buf, size_t size)
{
struct ngnfs_inode_txn_ref dir;
@@ -355,7 +356,7 @@ int ngnfs_dir_readdir(struct ngnfs_fs_info *nfi, u64 dir_ino, u64 pos,
ra.size = size;
ra.nr = 0;
- ret = ngnfs_inode_get(nfi, &txn, NBF_READ, dir_ino, &dir) ?:
+ ret = ngnfs_inode_get(nfi, &txn, NBF_READ, dir_ig, &dir) ?:
check_ifmt(dir.ninode, S_IFDIR, -ENOTDIR) ?:
ngnfs_btree_read_iter(nfi, &txn, &dir.ninode->dirents, &key,
NULL, NULL, fill_dirent_rd, &ra);
diff --git a/shared/dir.h b/shared/dir.h
index 5594162..8ca28b8 100644
--- a/shared/dir.h
+++ b/shared/dir.h
@@ -2,25 +2,25 @@
#ifndef NGNFS_SHARED_DIR_H
#define NGNFS_SHARED_DIR_H
+#include "shared/inode.h"
#include "shared/fs_info.h"
-int ngnfs_dir_create(struct ngnfs_fs_info *nfi, u64 dir_ino, umode_t mode, char *name,
- size_t name_len);
+int ngnfs_dir_create(struct ngnfs_fs_info *nfi, struct ngnfs_inode_ino_gen *dir, umode_t mode,
+ char *name, size_t name_len);
/*
- * Readddr fills the buffer with entries. The start of the buffer must
+ * Readdir fills the buffer with entries. The start of the buffer must
* be at least as aligned as the entry. Entries are padded for
* alignment. Use next_off to iterate through them instead of trying to
* skip name length bytes past the end of the struct.
*/
struct ngnfs_readdir_entry {
u64 pos;
- u64 ino;
- u64 gen;
- u16 next_offset; /* bytes to add to entry to get next entry */
+ struct ngnfs_inode_ino_gen ig;
+ u16 next_offset; /* bytes to add to entry to get next entry */
u8 dtype;
- u8 name_len; /* does not include terminating null, like strlen */
- u8 name[]; /* is null terminated, name_len doesn't include null byte */
+ u8 name_len; /* does not include terminating null, like strlen */
+ u8 name[]; /* is null terminated, name_len doesn't include null byte */
};
/*
@@ -35,7 +35,7 @@ struct ngnfs_readdir_entry {
* Returns the number of entries filled into the buffer, not the number
* of bytes.
*/
-int ngnfs_dir_readdir(struct ngnfs_fs_info *nfi, u64 dir_ino, u64 pos,
+int ngnfs_dir_readdir(struct ngnfs_fs_info *nfi, struct ngnfs_inode_ino_gen *dir_ig, u64 pos,
struct ngnfs_readdir_entry *buf, size_t size);
#endif
diff --git a/shared/format-block.h b/shared/format-block.h
index 95ba9ff..787de90 100644
--- a/shared/format-block.h
+++ b/shared/format-block.h
@@ -80,6 +80,21 @@ struct ngnfs_btree_item {
#define NGNFS_BTREE_MAX_FREE \
(NGNFS_BLOCK_SIZE - offsetof(struct ngnfs_btree_block, ihdrs[NGNFS_BTREE_MAX_ITEMS]))
+/*
+ * The inode generation number changes every time a specific inode is
+ * freed and reallocated. The inode number and generation number
+ * uniquely identify a file/dir over its lifetime. This lets users of
+ * references to inodes find out if the inode has changed out from
+ * underneath them. Generally, the inode number and generation number
+ * should be referenced together, so make a struct to keep them
+ * together.
+ */
+
+struct ngnfs_ino_gen {
+ __le64 ino; /* inode number, starts at 1 */
+ __le64 gen; /* inode generation, starts at 1 */
+};
+
/*
* Inodes are stored in inode blocks. Inode blocks numbers are directly
* calculated from the inode number. The block itself is formatted as a
@@ -87,8 +102,7 @@ struct ngnfs_btree_item {
* as btree items in the block.
*/
struct ngnfs_inode {
- __le64 ino;
- __le64 gen;
+ struct ngnfs_ino_gen ig;
__le64 size;
__le64 version;
__le32 nlink;
@@ -105,6 +119,7 @@ struct ngnfs_inode {
};
#define NGNFS_ROOT_INO 1
+#define INIT_NGNFS_ROOT_IG { NGNFS_ROOT_INO, 1 }
/*
* This is totally arbitrary. It looks like it's 32bit in the stat ABI.
@@ -123,8 +138,7 @@ enum ngnfs_dentry_type {
};
struct ngnfs_dirent {
- __le64 ino;
- __le64 version; /* XXX ? */
+ struct ngnfs_ino_gen ig; /* inode number and generation */
__u8 pers_dtype; /* ngnfs persistent directory entry type */
__u8 name_len; /* no null termination */
__u8 name[6]; /* definition pads to alignment, stored can be smaller */
diff --git a/shared/inode.c b/shared/inode.c
index 131e195..92a74fe 100644
--- a/shared/inode.c
+++ b/shared/inode.c
@@ -19,14 +19,14 @@
* to pack inode data into the rest of the block.
*/
-int ngnfs_inode_init(struct ngnfs_inode_txn_ref *itref, u64 ino, u64 gen, u32 nlink, umode_t mode,
- u64 nsec)
+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_txn_block *tblk = itref->tblk;
struct ngnfs_inode *ninode = itref->ninode;
- ngnfs_tblk_assign(tblk, ninode->ino, cpu_to_le64(ino));
- ngnfs_tblk_assign(tblk, ninode->gen, cpu_to_le64(gen));
+ 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->version, cpu_to_le64(1));
ngnfs_tblk_assign(tblk, ninode->nlink, cpu_to_le32(nlink));
@@ -47,22 +47,25 @@ int ngnfs_inode_init(struct ngnfs_inode_txn_ref *itref, u64 ino, u64 gen, u32 nl
/*
* XXX should be validating that the block is a valid inode, etc.
*/
-int ngnfs_inode_get(struct ngnfs_fs_info *nfi, struct ngnfs_transaction *txn, nbf_t nbf, u64 ino,
- struct ngnfs_inode_txn_ref *itref)
+int ngnfs_inode_get(struct ngnfs_fs_info *nfi, struct ngnfs_transaction *txn, nbf_t nbf,
+ struct ngnfs_inode_ino_gen *ig, struct ngnfs_inode_txn_ref *itref)
{
- return ngnfs_txn_get_block(nfi, txn, ino, nbf, &itref->tblk, (void **)&itref->ninode);
+ return ngnfs_txn_get_block(nfi, txn, ig->ino, nbf, &itref->tblk, (void **)&itref->ninode);
}
-int ngnfs_inode_alloc(struct ngnfs_fs_info *nfi, struct ngnfs_transaction *txn, u64 *ino,
- struct ngnfs_inode_txn_ref *itref)
+int ngnfs_inode_alloc(struct ngnfs_fs_info *nfi, struct ngnfs_transaction *txn,
+ struct ngnfs_inode_ino_gen *ig, struct ngnfs_inode_txn_ref *itref)
{
- u64 bnr;
+ struct ngnfs_inode_ino_gen new;
int ret;
- ret = ngnfs_txn_alloc_meta(txn, &bnr) ?:
- ngnfs_inode_get(nfi, txn, NBF_WRITE | NBF_NEW, bnr, itref);
+ new.gen = 1; /* XXX should look up previous gen and increment */
+ ret = ngnfs_txn_alloc_meta(txn, &new.ino) ?:
+ ngnfs_inode_get(nfi, txn, NBF_WRITE | NBF_NEW, &new, itref);
+
if (ret == 0)
- *ino = bnr;
+ *ig = new;
+
return ret;
}
@@ -70,7 +73,8 @@ int ngnfs_inode_alloc(struct ngnfs_fs_info *nfi, struct ngnfs_transaction *txn,
* A transaction that just copies the inode in the block to the caller's
* buffer.
*/
-int ngnfs_inode_read_copy(struct ngnfs_fs_info *nfi, u64 ino, void *buf, int size)
+int ngnfs_inode_read_copy(struct ngnfs_fs_info *nfi, struct ngnfs_inode_ino_gen *ig,
+ void *buf, int size)
{
struct ngnfs_inode_txn_ref itref;
struct ngnfs_transaction txn;
@@ -84,7 +88,7 @@ int ngnfs_inode_read_copy(struct ngnfs_fs_info *nfi, u64 ino, void *buf, int siz
ngnfs_txn_init(&txn);
do {
- ret = ngnfs_inode_get(nfi, &txn, NBF_READ, ino, &itref);
+ ret = ngnfs_inode_get(nfi, &txn, NBF_READ, ig, &itref);
if (ret == 0) {
ret = min(size, sizeof(struct ngnfs_inode));
memcpy(buf, itref.ninode, ret);
diff --git a/shared/inode.h b/shared/inode.h
index 3f6328b..d9dbb77 100644
--- a/shared/inode.h
+++ b/shared/inode.h
@@ -14,12 +14,18 @@ struct ngnfs_inode_txn_ref {
struct ngnfs_inode *ninode;
};
-int ngnfs_inode_init(struct ngnfs_inode_txn_ref *itref, u64 ino, u64 gen, u32 nlink, umode_t mode,
- u64 nsec);
-int ngnfs_inode_get(struct ngnfs_fs_info *nfi, struct ngnfs_transaction *txn, nbf_t nbf, u64 ino,
- struct ngnfs_inode_txn_ref *itref);
-int ngnfs_inode_alloc(struct ngnfs_fs_info *nfi, struct ngnfs_transaction *txn, u64 *ino,
- struct ngnfs_inode_txn_ref *itref);
-int ngnfs_inode_read_copy(struct ngnfs_fs_info *nfi, u64 ino, void *buf, int size);
+struct ngnfs_inode_ino_gen {
+ u64 ino;
+ u64 gen;
+};
+
+int ngnfs_inode_init(struct ngnfs_inode_txn_ref *itref, struct ngnfs_inode_ino_gen *ig, u32 nlink,
+ umode_t mode, u64 nsec);
+int ngnfs_inode_get(struct ngnfs_fs_info *nfi, struct ngnfs_transaction *txn, nbf_t nbf,
+ struct ngnfs_inode_ino_gen *ig, struct ngnfs_inode_txn_ref *itref);
+int ngnfs_inode_alloc(struct ngnfs_fs_info *nfi, struct ngnfs_transaction *txn,
+ struct ngnfs_inode_ino_gen *ig, struct ngnfs_inode_txn_ref *itref);
+int ngnfs_inode_read_copy(struct ngnfs_fs_info *nfi, struct ngnfs_inode_ino_gen *ig,
+ void *buf, int size);
#endif
diff --git a/shared/mkfs.c b/shared/mkfs.c
index dee8cbe..3e84393 100644
--- a/shared/mkfs.c
+++ b/shared/mkfs.c
@@ -18,6 +18,7 @@ int ngnfs_mkfs(struct ngnfs_fs_info *nfi)
{
struct ngnfs_inode_txn_ref itref;
struct ngnfs_transaction txn;
+ struct ngnfs_inode_ino_gen ig = INIT_NGNFS_ROOT_IG;
u64 nsec;
int ret;
@@ -25,8 +26,8 @@ int ngnfs_mkfs(struct ngnfs_fs_info *nfi)
nsec = ktime_to_ns(ktime_get_real());
do {
- ret = ngnfs_inode_get(nfi, &txn, NBF_WRITE, NGNFS_ROOT_INO, &itref) ?:
- ngnfs_inode_init(&itref, NGNFS_ROOT_INO, 1, 2, S_IFDIR | 0755, nsec);
+ ret = ngnfs_inode_get(nfi, &txn, NBF_WRITE, &ig, &itref) ?:
+ ngnfs_inode_init(&itref, &ig, 2, S_IFDIR | 0755, nsec);
} while (ngnfs_txn_retry(nfi, &txn, &ret));
--
2.48.1
More information about the ngnfs-devel
mailing list