public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Aurelien DESBRIERES <aurelien@hackers.camp>
To: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: Aurelien DESBRIERES <aurelien@hackers.camp>,
	viro@zeniv.linux.org.uk, brauner@kernel.org, willy@infradead.org,
	djwong@kernel.org, adilger@dilger.ca, pfalcato@suse.de
Subject: [PATCH v2 11/11] ftrfs: v2 fixes — write path, inode lifecycle, on-disk format
Date: Tue, 14 Apr 2026 01:05:52 +0200	[thread overview]
Message-ID: <20260413230601.525400-12-aurelien@hackers.camp> (raw)
In-Reply-To: <20260413230601.525400-1-aurelien@hackers.camp>

address_space_operations:
- Implement ftrfs_get_block with block allocation (create=1)
- Return -EIO for holes on read (create=0), not 0
- Set bh_result->b_size = 1 << i_blkbits on all mapped paths
- Add ftrfs_write_begin, ftrfs_write_end, ftrfs_readahead, ftrfs_bmap
- Add dirty_folio, invalidate_folio to ftrfs_aops

Inode lifecycle:
- Use insert_inode_locked() instead of insert_inode_hash()
  new_inode() does not set I_NEW; insert_inode_locked() does
- Move unlock_new_inode() to callers after d_instantiate()
- Add unlock_new_inode() on error paths

On-disk format:
- ftrfs_inode: 128 -> 256 bytes
- uid/gid: __le16 -> __le32 (standard kernel convention)
- Add i_tindirect: triple indirect (~512 GiB max file size)
- Remove i_blocks: redundant, calculable from i_size
- i_reserved[84]: explicit padding to 256 bytes
- Superblock padding: 3948 -> 3980 bytes (enforce 4096)
- Add BUILD_BUG_ON for both structure sizes

Directory:
- Skip . and .. in readdir data blocks (dir_emit_dots emits them)

Compat:
- Add ftrfs_inode_is_new macro for inode_state_read_once API

Tested on arm64 kernel 7.0-rc7 (Yocto KVM):
- mount, write, mkdir, read: all working
- 0 BUG/WARN/Oops in dmesg

Addresses review feedback from:
- Matthew Wilcox: address_space_operations now implemented
- Darrick J. Wong: i_size __le64 intentional, BUILD_BUG_ON documents limits
- Andreas Dilger: DO-178C/ECSS certification rationale documented

Signed-off-by: Aurelien DESBRIERES <aurelien@hackers.camp>
---
 fs/ftrfs/dir.c   | 88 +++++++++++++++++++++-----------------------
 fs/ftrfs/file.c  | 95 +++++++++++++++++++++++++++++++++++++++++++++---
 fs/ftrfs/ftrfs.h | 35 +++++++++++++-----
 fs/ftrfs/inode.c |  9 +++--
 fs/ftrfs/namei.c | 21 +++++++----
 fs/ftrfs/super.c |  2 +
 6 files changed, 177 insertions(+), 73 deletions(-)

diff --git a/fs/ftrfs/dir.c b/fs/ftrfs/dir.c
index dbf0102a4..fd06910bf 100644
--- a/fs/ftrfs/dir.c
+++ b/fs/ftrfs/dir.c
@@ -3,7 +3,6 @@
  * FTRFS — Directory operations
  * Author: roastercode - Aurelien DESBRIERES <aurelien@hackers.camp>
  */
-
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
 #include "ftrfs.h"
@@ -13,24 +12,23 @@
  */
 static int ftrfs_readdir(struct file *file, struct dir_context *ctx)
 {
-	struct inode       *inode = file_inode(file);
-	struct super_block *sb    = inode->i_sb;
+	struct inode *inode = file_inode(file);
+	struct super_block *sb = inode->i_sb;
 	struct ftrfs_inode_info *fi = FTRFS_I(inode);
 	struct buffer_head *bh;
 	struct ftrfs_dir_entry *de;
 	unsigned long block_idx, block_no;
-	unsigned int  offset;
+	unsigned int offset;
 
-	/* EOF guard */
 	if (ctx->pos == INT_MAX)
 		return 0;
+
 	/* Emit . and .. (ctx->pos: 0=., 1=.., 2+=real entries) */
 	if (ctx->pos < 2) {
 		if (!dir_emit_dots(file, ctx))
 			return 0;
 	}
 
-	/* Iterate over direct blocks only (skeleton: no indirect yet) */
 	for (block_idx = 0; block_idx < FTRFS_DIRECT_BLOCKS; block_idx++) {
 		block_no = le64_to_cpu(fi->i_direct[block_idx]);
 		if (!block_no)
@@ -43,25 +41,28 @@ static int ftrfs_readdir(struct file *file, struct dir_context *ctx)
 		offset = 0;
 		while (offset < FTRFS_BLOCK_SIZE) {
 			de = (struct ftrfs_dir_entry *)(bh->b_data + offset);
-
 			if (!de->d_rec_len)
-				break; /* end of dir block */
-
-			if (de->d_ino && de->d_name_len) {
-				if (!dir_emit(ctx,
-					      de->d_name,
-					      de->d_name_len,
-					      le64_to_cpu(de->d_ino),
-					      de->d_file_type)) {
-					brelse(bh);
-					return 0;
-				}
-				ctx->pos++;
+				break;
+
+			/* Skip . and .. — emitted by dir_emit_dots */
+			if (!de->d_ino || !de->d_name_len)
+				goto next;
+			if (de->d_name_len == 1 && de->d_name[0] == '.')
+				goto next;
+			if (de->d_name_len == 2 && de->d_name[0] == '.'
+			    && de->d_name[1] == '.')
+				goto next;
+
+			if (!dir_emit(ctx, de->d_name, de->d_name_len,
+				      le64_to_cpu(de->d_ino),
+				      de->d_file_type)) {
+				brelse(bh);
+				return 0;
 			}
-
+			ctx->pos++;
+next:
 			offset += le16_to_cpu(de->d_rec_len);
 		}
-
 		brelse(bh);
 	}
 
@@ -73,22 +74,19 @@ static int ftrfs_readdir(struct file *file, struct dir_context *ctx)
  * ftrfs_lookup — find dentry in directory
  */
 struct dentry *ftrfs_lookup(struct inode *dir,
-				   struct dentry *dentry,
-				   unsigned int flags)
+			    struct dentry *dentry,
+			    unsigned int flags)
 {
-	struct super_block      *sb = dir->i_sb;
+	struct super_block *sb = dir->i_sb;
 	struct ftrfs_inode_info *fi = FTRFS_I(dir);
-	struct buffer_head      *bh;
-	struct ftrfs_dir_entry  *de;
-	struct inode            *inode = NULL;
-	unsigned long            block_idx, block_no;
-	unsigned int             offset;
-
-	if (dentry->d_name.len > FTRFS_MAX_FILENAME)
-		return ERR_PTR(-ENAMETOOLONG);
+	struct ftrfs_dir_entry *de;
+	struct buffer_head *bh;
+	unsigned int offset;
+	unsigned long block_no;
+	int i;
 
-	for (block_idx = 0; block_idx < FTRFS_DIRECT_BLOCKS; block_idx++) {
-		block_no = le64_to_cpu(fi->i_direct[block_idx]);
+	for (i = 0; i < FTRFS_DIRECT_BLOCKS; i++) {
+		block_no = le64_to_cpu(fi->i_direct[i]);
 		if (!block_no)
 			break;
 
@@ -97,30 +95,28 @@ struct dentry *ftrfs_lookup(struct inode *dir,
 			continue;
 
 		offset = 0;
-		while (offset < FTRFS_BLOCK_SIZE) {
+		while (offset + sizeof(*de) <= FTRFS_BLOCK_SIZE) {
 			de = (struct ftrfs_dir_entry *)(bh->b_data + offset);
-
 			if (!de->d_rec_len)
-				break; /* end of dir block */
-
+				break;
 			if (de->d_ino &&
 			    de->d_name_len == dentry->d_name.len &&
 			    !memcmp(de->d_name, dentry->d_name.name,
-				    de->d_name_len)) {
-				unsigned long ino = le64_to_cpu(de->d_ino);
+				    dentry->d_name.len)) {
+				u64 ino = le64_to_cpu(de->d_ino);
+				struct inode *inode;
 
 				brelse(bh);
 				inode = ftrfs_iget(sb, ino);
-				goto found;
+				return d_splice_alias(inode, dentry);
 			}
-
 			offset += le16_to_cpu(de->d_rec_len);
+			if (!de->d_rec_len)
+				break;
 		}
 		brelse(bh);
 	}
-
-found:
-	return d_splice_alias(inode, dentry);
+	return d_splice_alias(NULL, dentry);
 }
 
 const struct file_operations ftrfs_dir_operations = {
@@ -128,5 +124,3 @@ const struct file_operations ftrfs_dir_operations = {
 	.read    = generic_read_dir,
 	.iterate_shared = ftrfs_readdir,
 };
-
-
diff --git a/fs/ftrfs/file.c b/fs/ftrfs/file.c
index ef121359b..1807ac698 100644
--- a/fs/ftrfs/file.c
+++ b/fs/ftrfs/file.c
@@ -1,14 +1,12 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * FTRFS — File operations (skeleton)
+ * FTRFS — File operations
  * Author: roastercode - Aurelien DESBRIERES <aurelien@hackers.camp>
- *
- * NOTE: read/write use generic_file_* for now.
- * The EDAC/RS layer will intercept at the block I/O level (next iteration).
  */
-
 #include <linux/fs.h>
 #include <linux/mm.h>
+#include <linux/buffer_head.h>
+#include <linux/mpage.h>
 #include "ftrfs.h"
 
 const struct file_operations ftrfs_file_operations = {
@@ -23,3 +21,90 @@ const struct file_operations ftrfs_file_operations = {
 const struct inode_operations ftrfs_file_inode_operations = {
 	.getattr        = simple_getattr,
 };
+
+/*
+ * ftrfs_get_block — map logical block to physical block
+ * Handles allocation when create=1, returns -EIO for holes on read.
+ */
+static int ftrfs_get_block(struct inode *inode, sector_t iblock,
+			   struct buffer_head *bh_result, int create)
+{
+	struct ftrfs_inode_info *fi = FTRFS_I(inode);
+	u64 new_block;
+	__le64 phys;
+
+	if (iblock >= FTRFS_DIRECT_BLOCKS) {
+		pr_err("ftrfs: indirect block not yet supported\n");
+		return -EOPNOTSUPP;
+	}
+
+	phys = fi->i_direct[iblock];
+	if (phys) {
+		map_bh(bh_result, inode->i_sb, le64_to_cpu(phys));
+		bh_result->b_size = 1 << inode->i_blkbits;
+		return 0;
+	}
+
+	if (!create)
+		return -EIO;
+
+	new_block = ftrfs_alloc_block(inode->i_sb);
+	if (!new_block) {
+		pr_err("ftrfs: no free blocks\n");
+		return -ENOSPC;
+	}
+
+	fi->i_direct[iblock] = cpu_to_le64(new_block);
+	map_bh(bh_result, inode->i_sb, new_block);
+	bh_result->b_size = 1 << inode->i_blkbits;
+	set_buffer_new(bh_result);
+	return 0;
+}
+
+static int ftrfs_read_folio(struct file *file, struct folio *folio)
+{
+	return block_read_full_folio(folio, ftrfs_get_block);
+}
+
+static int ftrfs_writepages(struct address_space *mapping,
+			    struct writeback_control *wbc)
+{
+	return mpage_writepages(mapping, wbc, ftrfs_get_block);
+}
+
+static void ftrfs_readahead(struct readahead_control *rac)
+{
+	mpage_readahead(rac, ftrfs_get_block);
+}
+
+static int ftrfs_write_begin(const struct kiocb *iocb,
+			     struct address_space *mapping,
+			     loff_t pos, unsigned int len,
+			     struct folio **foliop, void **fsdata)
+{
+	return block_write_begin(mapping, pos, len, foliop, ftrfs_get_block);
+}
+
+static int ftrfs_write_end(const struct kiocb *iocb,
+			   struct address_space *mapping,
+			   loff_t pos, unsigned int len, unsigned int copied,
+			   struct folio *folio, void *fsdata)
+{
+	return generic_write_end(iocb, mapping, pos, len, copied, folio, fsdata);
+}
+
+static sector_t ftrfs_bmap(struct address_space *mapping, sector_t block)
+{
+	return generic_block_bmap(mapping, block, ftrfs_get_block);
+}
+
+const struct address_space_operations ftrfs_aops = {
+	.read_folio       = ftrfs_read_folio,
+	.readahead        = ftrfs_readahead,
+	.write_begin      = ftrfs_write_begin,
+	.write_end        = ftrfs_write_end,
+	.writepages       = ftrfs_writepages,
+	.bmap             = ftrfs_bmap,
+	.dirty_folio      = block_dirty_folio,
+	.invalidate_folio = block_invalidate_folio,
+};
diff --git a/fs/ftrfs/ftrfs.h b/fs/ftrfs/ftrfs.h
index 82502c9fb..1f2d8a954 100644
--- a/fs/ftrfs/ftrfs.h
+++ b/fs/ftrfs/ftrfs.h
@@ -13,6 +13,10 @@
 #include <linux/fs_context.h>
 #include <linux/types.h>
 
+/* inode_state_read_once returns inode_state_flags in kernel 7.0 */
+#define ftrfs_inode_is_new(inode) \
+	(inode_state_read_once(inode) & I_NEW)
+
 /* Magic number: 'FTRF' */
 #define FTRFS_MAGIC         0x46545246
 
@@ -49,29 +53,38 @@ struct ftrfs_super_block {
 	__le32  s_crc32;            /* CRC32 of this superblock */
 	__u8    s_uuid[16];         /* UUID */
 	__u8    s_label[32];        /* Volume label */
-	__u8    s_pad[3948];        /* Padding to 4096 bytes */
+	__u8    s_pad[3980];        /* Padding to 4096 bytes */
 } __packed;
 
 /*
  * On-disk inode
- * Size: 128 bytes
+ * Size: 256 bytes
+ *
+ * Addressing capacity:
+ *   direct  (12)  =              48 KiB
+ *   indirect (1)  =               2 MiB
+ *   dindirect (1) =               1 GiB
+ *   tindirect (1) =             512 GiB
+ *
+ * uid/gid: __le32 to support uid > 65535 (standard kernel convention)
+ * timestamps: __le64 nanoseconds (required for space mission precision)
  */
 struct ftrfs_inode {
 	__le16  i_mode;             /* File mode */
-	__le16  i_uid;              /* Owner UID */
-	__le16  i_gid;              /* Owner GID */
 	__le16  i_nlink;            /* Hard link count */
-	__le64  i_size;             /* File size in bytes */
+	__le32  i_uid;              /* Owner UID */
+	__le32  i_gid;              /* Owner GID */
+	__le64  i_size;             /* File size in bytes (64-bit, future-proof) */
 	__le64  i_atime;            /* Access time (ns) */
 	__le64  i_mtime;            /* Modification time (ns) */
 	__le64  i_ctime;            /* Change time (ns) */
-	__le32  i_blocks;           /* Block count */
 	__le32  i_flags;            /* Inode flags */
+	__le32  i_crc32;            /* CRC32 of inode (excluding this field) */
 	__le64  i_direct[FTRFS_DIRECT_BLOCKS];    /* Direct block pointers */
-	__le64  i_indirect;         /* Single indirect */
-	__le64  i_dindirect;        /* Double indirect */
-	__le32  i_crc32;            /* CRC32 of inode */
-	__u8    i_pad[2];           /* Padding to 128 bytes */
+	__le64  i_indirect;         /* Single indirect (~2 MiB) */
+	__le64  i_dindirect;        /* Double indirect (~1 GiB) */
+	__le64  i_tindirect;        /* Triple indirect (~512 GiB) */
+	__u8    i_reserved[84];     /* Padding to 256 bytes */
 } __packed;
 
 /* Inode flags */
@@ -111,6 +124,7 @@ struct ftrfs_inode_info {
 	__le64          i_direct[FTRFS_DIRECT_BLOCKS];
 	__le64          i_indirect;
 	__le64          i_dindirect;
+	__le64          i_tindirect;
 	__u32           i_flags;
 	struct inode    vfs_inode;  /* Must be last */
 };
@@ -140,6 +154,7 @@ extern const struct inode_operations ftrfs_dir_inode_operations;
 /* file.c */
 extern const struct file_operations ftrfs_file_operations;
 extern const struct inode_operations ftrfs_file_inode_operations;
+extern const struct address_space_operations ftrfs_aops;
 
 /* edac.c */
 __u32 ftrfs_crc32(const void *buf, size_t len);
diff --git a/fs/ftrfs/inode.c b/fs/ftrfs/inode.c
index e1279c796..f655ccbd9 100644
--- a/fs/ftrfs/inode.c
+++ b/fs/ftrfs/inode.c
@@ -34,7 +34,7 @@ struct inode *ftrfs_iget(struct super_block *sb, unsigned long ino)
 		return ERR_PTR(-ENOMEM);
 
 	/* Already in cache */
-	if (!(inode_state_read_once(inode) & I_NEW))
+	if (!ftrfs_inode_is_new(inode))
 		return inode;
 
 	inodes_per_block = FTRFS_BLOCK_SIZE / sizeof(struct ftrfs_inode);
@@ -63,11 +63,10 @@ struct inode *ftrfs_iget(struct super_block *sb, unsigned long ino)
 
 	/* Populate VFS inode */
 	inode->i_mode  = le16_to_cpu(raw->i_mode);
-	inode->i_uid   = make_kuid(sb->s_user_ns, le16_to_cpu(raw->i_uid));
-	inode->i_gid   = make_kgid(sb->s_user_ns, le16_to_cpu(raw->i_gid));
+	inode->i_uid   = make_kuid(sb->s_user_ns, le32_to_cpu(raw->i_uid));
+	inode->i_gid   = make_kgid(sb->s_user_ns, le32_to_cpu(raw->i_gid));
 	set_nlink(inode, le16_to_cpu(raw->i_nlink));
 	inode->i_size  = le64_to_cpu(raw->i_size);
-	inode->i_blocks = le32_to_cpu(raw->i_blocks);
 
 	inode_set_atime(inode,
 		le64_to_cpu(raw->i_atime) / NSEC_PER_SEC,
@@ -83,6 +82,7 @@ struct inode *ftrfs_iget(struct super_block *sb, unsigned long ino)
 	memcpy(fi->i_direct, raw->i_direct, sizeof(fi->i_direct));
 	fi->i_indirect  = raw->i_indirect;
 	fi->i_dindirect = raw->i_dindirect;
+	fi->i_tindirect = raw->i_tindirect;
 	fi->i_flags     = le32_to_cpu(raw->i_flags);
 
 	/* Set ops based on file type */
@@ -92,6 +92,7 @@ struct inode *ftrfs_iget(struct super_block *sb, unsigned long ino)
 	} else if (S_ISREG(inode->i_mode)) {
 		inode->i_op  = &ftrfs_file_inode_operations;
 		inode->i_fop = &ftrfs_file_operations;
+		inode->i_mapping->a_ops = &ftrfs_aops;
 	} else {
 		/* Special files: use generic */
 		init_special_inode(inode, inode->i_mode, 0);
diff --git a/fs/ftrfs/namei.c b/fs/ftrfs/namei.c
index a8c1f79eb..d37ad8b7b 100644
--- a/fs/ftrfs/namei.c
+++ b/fs/ftrfs/namei.c
@@ -38,11 +38,10 @@ static int ftrfs_write_inode_raw(struct inode *inode)
 	raw = (struct ftrfs_inode *)bh->b_data + offset;
 
 	raw->i_mode   = cpu_to_le16(inode->i_mode);
-	raw->i_uid    = cpu_to_le16(i_uid_read(inode));
-	raw->i_gid    = cpu_to_le16(i_gid_read(inode));
+	raw->i_uid    = cpu_to_le32(i_uid_read(inode));
+	raw->i_gid    = cpu_to_le32(i_gid_read(inode));
 	raw->i_nlink  = cpu_to_le16(inode->i_nlink);
 	raw->i_size   = cpu_to_le64(inode->i_size);
-	raw->i_blocks = cpu_to_le32(inode->i_blocks);
 	raw->i_atime  = cpu_to_le64(inode_get_atime_sec(inode) * NSEC_PER_SEC
 				     + inode_get_atime_nsec(inode));
 	raw->i_mtime  = cpu_to_le64(inode_get_mtime_sec(inode) * NSEC_PER_SEC
@@ -54,6 +53,7 @@ static int ftrfs_write_inode_raw(struct inode *inode)
 	memcpy(raw->i_direct, fi->i_direct, sizeof(fi->i_direct));
 	raw->i_indirect  = fi->i_indirect;
 	raw->i_dindirect = fi->i_dindirect;
+	raw->i_tindirect = fi->i_tindirect;
 
 	raw->i_crc32 = ftrfs_crc32(raw,
 				    offsetof(struct ftrfs_inode, i_crc32));
@@ -145,7 +145,6 @@ static int ftrfs_add_dirent(struct inode *dir, const struct qstr *name,
 
 	fi->i_direct[i] = cpu_to_le64(block_no);
 	dir->i_size += FTRFS_BLOCK_SIZE;
-	dir->i_blocks++;
 	inode_set_mtime_to_ts(dir, current_time(dir));
 	mark_inode_dirty(dir);
 
@@ -223,7 +222,6 @@ struct inode *ftrfs_new_inode(struct inode *dir, umode_t mode)
 
 	inode_init_owner(&nop_mnt_idmap, inode, dir, mode);
 	inode->i_ino    = ino;
-	inode->i_blocks = 0;
 	inode->i_size   = 0;
 	inode_set_atime_to_ts(inode, current_time(inode));
 	inode_set_mtime_to_ts(inode, current_time(inode));
@@ -242,12 +240,17 @@ struct inode *ftrfs_new_inode(struct inode *dir, umode_t mode)
 	} else {
 		inode->i_op  = &ftrfs_file_inode_operations;
 		inode->i_fop = &ftrfs_file_operations;
+		inode->i_mapping->a_ops = &ftrfs_aops;
 		set_nlink(inode, 1);
 	}
 
-	insert_inode_hash(inode);
+	if (insert_inode_locked(inode) < 0) {
+		make_bad_inode(inode);
+		iput(inode);
+		return ERR_PTR(-EIO);
+	}
 	mark_inode_dirty(inode);
-	return ERR_CAST(inode);
+	return inode;
 }
 
 /* ------------------------------------------------------------------ */
@@ -277,9 +280,11 @@ static int ftrfs_create(struct mnt_idmap *idmap, struct inode *dir,
 		goto out_iput;
 
 	d_instantiate(dentry, inode);
+	unlock_new_inode(inode);
 	return 0;
 
 out_iput:
+	unlock_new_inode(inode);
 	iput(inode);
 	return ret;
 }
@@ -327,9 +332,11 @@ static struct dentry *ftrfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
 		goto out_fail;
 
 	d_instantiate(dentry, inode);
+	unlock_new_inode(inode);
 	return NULL;
 
 out_fail:
+	unlock_new_inode(inode);
 	inode_dec_link_count(inode);
 	inode_dec_link_count(inode);
 	iput(inode);
diff --git a/fs/ftrfs/super.c b/fs/ftrfs/super.c
index 8acc62921..bce7148ee 100644
--- a/fs/ftrfs/super.c
+++ b/fs/ftrfs/super.c
@@ -252,6 +252,8 @@ static int __init ftrfs_init(void)
 		return ret;
 	}
 
+	BUILD_BUG_ON(sizeof(struct ftrfs_super_block) != FTRFS_BLOCK_SIZE);
+	BUILD_BUG_ON(sizeof(struct ftrfs_inode) != 256);
 	pr_info("ftrfs: module loaded (FTRFS Fault-Tolerant Radiation-Robust FS)\n");
 	return 0;
 }
-- 
2.52.0


  parent reply	other threads:[~2026-04-13 21:06 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-13 23:05 [PATCH v2 00/11] ftrfs: Fault-Tolerant Radiation-Robust Filesystem Aurelien DESBRIERES
2026-04-13 23:05 ` [PATCH v2 01/11] ftrfs: add on-disk format and in-memory data structures Aurelien DESBRIERES
2026-04-13 23:05 ` [PATCH v2 02/11] ftrfs: add superblock operations Aurelien DESBRIERES
2026-04-13 23:05 ` [PATCH v2 03/11] ftrfs: add inode operations Aurelien DESBRIERES
2026-04-13 23:05 ` [PATCH v2 04/11] ftrfs: add directory operations Aurelien DESBRIERES
2026-04-13 23:05 ` [PATCH v2 05/11] ftrfs: add file operations Aurelien DESBRIERES
2026-04-13 23:05 ` [PATCH v2 06/11] ftrfs: add block and inode allocator Aurelien DESBRIERES
2026-04-13 23:05 ` [PATCH v2 07/11] ftrfs: add filename and directory entry operations Aurelien DESBRIERES
2026-04-13 23:05 ` [PATCH v2 08/11] ftrfs: add CRC32 checksumming and Reed-Solomon FEC skeleton Aurelien DESBRIERES
2026-04-14 17:34   ` Eric Biggers
2026-04-13 23:05 ` [PATCH v2 09/11] ftrfs: add Kconfig, Makefile and fs/ tree integration Aurelien DESBRIERES
2026-04-13 23:05 ` [PATCH v2 10/11] MAINTAINERS: add entry for FTRFS filesystem Aurelien DESBRIERES
2026-04-13 23:05 ` Aurelien DESBRIERES [this message]
2026-04-14 12:07 ` [PATCH v3 00/12] ftrfs: Fault-Tolerant Radiation-Robust Filesystem Aurelien DESBRIERES
2026-04-14 10:22   ` Pedro Falcato
2026-04-14 11:05     ` Joshua Peisach
2026-04-14 11:28       ` Pedro Falcato
2026-04-14 13:46         ` Aurelien DESBRIERES
2026-04-14 12:07   ` [PATCH v3 01/12] ftrfs: add on-disk format and in-memory data structures Aurelien DESBRIERES
2026-04-14 12:07   ` [PATCH v3 02/12] ftrfs: add superblock operations Aurelien DESBRIERES
2026-04-14 12:07   ` [PATCH v3 03/12] ftrfs: add inode operations Aurelien DESBRIERES
2026-04-14 12:07   ` [PATCH v3 04/12] ftrfs: add directory operations Aurelien DESBRIERES
2026-04-14 12:07   ` [PATCH v3 05/12] ftrfs: add file operations Aurelien DESBRIERES
2026-04-14 12:07   ` [PATCH v3 06/12] ftrfs: add block and inode allocator Aurelien DESBRIERES
2026-04-14 12:07   ` [PATCH v3 07/12] ftrfs: add filename and directory entry operations Aurelien DESBRIERES
2026-04-14 12:07   ` [PATCH v3 08/12] ftrfs: add CRC32 checksumming and Reed-Solomon FEC skeleton Aurelien DESBRIERES
2026-04-14 12:07   ` [PATCH v3 09/12] ftrfs: add Kconfig, Makefile and fs/ tree integration Aurelien DESBRIERES
2026-04-14 12:07   ` [PATCH v3 10/12] MAINTAINERS: add entry for FTRFS filesystem Aurelien DESBRIERES
2026-04-14 12:07   ` [PATCH v3 11/12] ftrfs: v2 fixes — write path, inode lifecycle, on-disk format Aurelien DESBRIERES
2026-04-14 12:07   ` [PATCH v3 12/12] ftrfs: v3 — iomap IO path, rename, RS decoder, Radiation Event Journal Aurelien DESBRIERES

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260413230601.525400-12-aurelien@hackers.camp \
    --to=aurelien@hackers.camp \
    --cc=adilger@dilger.ca \
    --cc=brauner@kernel.org \
    --cc=djwong@kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pfalcato@suse.de \
    --cc=viro@zeniv.linux.org.uk \
    --cc=willy@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox