public inbox for linux-fsdevel@vger.kernel.org
 help / color / mirror / Atom feed
From: Aurelien DESBRIERES <aurelien@hackers.camp>
To: linux-fsdevel@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, viro@zeniv.linux.org.uk,
	brauner@kernel.org, aurelien@hackers.camp
Subject: [RFC PATCH 02/10] ftrfs: add superblock operations
Date: Mon, 13 Apr 2026 16:23:48 +0200	[thread overview]
Message-ID: <20260413142357.515792-3-aurelien@hackers.camp> (raw)
In-Reply-To: <20260413142357.515792-1-aurelien@hackers.camp>

From: Aurélien DESBRIERES <aurelien@hackers.camp>

Implement VFS superblock operations for FTRFS:

- ftrfs_fill_super(): read and validate on-disk superblock (magic,
  CRC32), allocate ftrfs_sb_info, read root inode, initialize
  in-memory free block bitmap
- ftrfs_put_super(): release bitmap and buffer heads on unmount
- ftrfs_statfs(): report filesystem statistics
- ftrfs_write_inode(): persist inode to disk via namei.c
- ftrfs_init_fs_context() / ftrfs_get_tree(): kernel 5.15+ mount API
- ftrfs_free_inode(): kernel 5.9+ inode freeing API

Module init/exit registers ftrfs as a filesystem type and allocates
a dedicated slab cache for ftrfs_inode_info objects.

Signed-off-by: Aurélien DESBRIERES <aurelien@hackers.camp>
---
 fs/ftrfs/super.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 274 insertions(+)
 create mode 100644 fs/ftrfs/super.c

diff --git a/fs/ftrfs/super.c b/fs/ftrfs/super.c
new file mode 100644
index 000000000..8acc62921
--- /dev/null
+++ b/fs/ftrfs/super.c
@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * FTRFS — Superblock operations
+ * Author: roastercode - Aurelien DESBRIERES <aurelien@hackers.camp>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/fs_context.h>
+#include <linux/slab.h>
+#include <linux/buffer_head.h>
+#include <linux/statfs.h>
+#include "ftrfs.h"
+
+/* Inode cache (slab allocator) */
+static struct kmem_cache *ftrfs_inode_cachep;
+
+/*
+ * alloc_inode — allocate a new inode with ftrfs_inode_info embedded
+ */
+static struct inode *ftrfs_alloc_inode(struct super_block *sb)
+{
+	struct ftrfs_inode_info *fi;
+
+	fi = kmem_cache_alloc(ftrfs_inode_cachep, GFP_KERNEL);
+	if (!fi)
+		return NULL;
+
+	memset(fi->i_direct, 0, sizeof(fi->i_direct));
+	fi->i_indirect  = 0;
+	fi->i_dindirect = 0;
+	fi->i_flags     = 0;
+
+	return &fi->vfs_inode;
+}
+
+/*
+ * free_inode — return inode to slab cache (kernel 5.9+ uses free_inode)
+ */
+static void ftrfs_free_inode(struct inode *inode)
+{
+	kmem_cache_free(ftrfs_inode_cachep, FTRFS_I(inode));
+}
+
+/*
+ * statfs — filesystem statistics
+ */
+static int ftrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+	struct super_block   *sb  = dentry->d_sb;
+	struct ftrfs_sb_info *sbi = FTRFS_SB(sb);
+
+	buf->f_type    = FTRFS_MAGIC;
+	buf->f_bsize   = sb->s_blocksize;
+	buf->f_blocks  = le64_to_cpu(sbi->s_ftrfs_sb->s_block_count);
+	buf->f_bfree   = sbi->s_free_blocks;
+	buf->f_bavail  = sbi->s_free_blocks;
+	buf->f_files   = le64_to_cpu(sbi->s_ftrfs_sb->s_inode_count);
+	buf->f_ffree   = sbi->s_free_inodes;
+	buf->f_namelen = FTRFS_MAX_FILENAME;
+
+	return 0;
+}
+
+/*
+ * put_super — release superblock resources
+ */
+static void ftrfs_put_super(struct super_block *sb)
+{
+	struct ftrfs_sb_info *sbi = FTRFS_SB(sb);
+
+	if (sbi) {
+		ftrfs_destroy_bitmap(sb);
+		brelse(sbi->s_sbh);
+		kfree(sbi->s_ftrfs_sb);
+		kfree(sbi);
+		sb->s_fs_info = NULL;
+	}
+}
+
+static const struct super_operations ftrfs_super_ops = {
+	.alloc_inode    = ftrfs_alloc_inode,
+	.free_inode     = ftrfs_free_inode,
+	.put_super      = ftrfs_put_super,
+		.write_inode    = ftrfs_write_inode,
+	.statfs         = ftrfs_statfs,
+};
+
+/*
+ * ftrfs_fill_super — read superblock from disk and initialize VFS sb
+ */
+int ftrfs_fill_super(struct super_block *sb, struct fs_context *fc)
+{
+	struct ftrfs_sb_info     *sbi;
+	struct ftrfs_super_block *fsb;
+	struct buffer_head       *bh;
+	struct inode             *root_inode;
+	__u32                     crc;
+	int                       ret = -EINVAL;
+
+	/* Set block size */
+	if (!sb_set_blocksize(sb, FTRFS_BLOCK_SIZE)) {
+		errorf(fc, "ftrfs: unable to set block size %d", FTRFS_BLOCK_SIZE);
+		return -EINVAL;
+	}
+
+	/* Read block 0 — superblock */
+	bh = sb_bread(sb, 0);
+	if (!bh) {
+		errorf(fc, "ftrfs: unable to read superblock");
+		return -EIO;
+	}
+
+	fsb = (struct ftrfs_super_block *)bh->b_data;
+
+	/* Verify magic */
+	if (le32_to_cpu(fsb->s_magic) != FTRFS_MAGIC) {
+		errorf(fc, "ftrfs: bad magic 0x%08x (expected 0x%08x)",
+		       le32_to_cpu(fsb->s_magic), FTRFS_MAGIC);
+		goto out_brelse;
+	}
+
+	/* Verify CRC32 of superblock (excluding the crc32 field itself) */
+	crc = ftrfs_crc32(fsb, offsetof(struct ftrfs_super_block, s_crc32));
+	if (crc != le32_to_cpu(fsb->s_crc32)) {
+		errorf(fc, "ftrfs: superblock CRC32 mismatch (got 0x%08x, expected 0x%08x)",
+		       crc, le32_to_cpu(fsb->s_crc32));
+		goto out_brelse;
+	}
+
+	/* Allocate in-memory sb info */
+	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
+	if (!sbi) {
+		ret = -ENOMEM;
+		goto out_brelse;
+	}
+
+	sbi->s_ftrfs_sb = kzalloc(sizeof(*sbi->s_ftrfs_sb), GFP_KERNEL);
+	if (!sbi->s_ftrfs_sb) {
+		ret = -ENOMEM;
+		goto out_free_sbi;
+	}
+
+	memcpy(sbi->s_ftrfs_sb, fsb, sizeof(*fsb));
+	sbi->s_sbh         = bh;
+	sbi->s_free_blocks = le64_to_cpu(fsb->s_free_blocks);
+	sbi->s_free_inodes = le64_to_cpu(fsb->s_free_inodes);
+	spin_lock_init(&sbi->s_lock);
+
+	sb->s_fs_info  = sbi;
+	sb->s_magic    = FTRFS_MAGIC;
+	sb->s_op       = &ftrfs_super_ops;
+	sb->s_maxbytes = MAX_LFS_FILESIZE;
+
+	/* Read root inode (inode 1) */
+	root_inode = ftrfs_iget(sb, 1);
+	if (IS_ERR(root_inode)) {
+		ret = PTR_ERR(root_inode);
+		pr_err("ftrfs: failed to read root inode: %d\n", ret);
+		goto out_free_fsb;
+	}
+
+	sb->s_root = d_make_root(root_inode);
+	if (!sb->s_root) {
+		ret = -ENOMEM;
+		goto out_free_fsb;
+	}
+
+	if (ftrfs_setup_bitmap(sb)) {
+		ret = -ENOMEM;
+		goto out_free_fsb;
+	}
+
+	pr_info("ftrfs: mounted (blocks=%llu free=%lu inodes=%llu)\n",
+		le64_to_cpu(fsb->s_block_count),
+		sbi->s_free_blocks,
+		le64_to_cpu(fsb->s_inode_count));
+
+	return 0;
+
+out_free_fsb:
+	kfree(sbi->s_ftrfs_sb);
+out_free_sbi:
+	kfree(sbi);
+	sb->s_fs_info = NULL;
+out_brelse:
+	brelse(bh);
+	return ret;
+}
+
+/*
+ * fs_context ops — kernel 5.15+ mount API
+ */
+static int ftrfs_get_tree(struct fs_context *fc)
+{
+	return get_tree_bdev(fc, ftrfs_fill_super);
+}
+
+static const struct fs_context_operations ftrfs_context_ops = {
+	.get_tree = ftrfs_get_tree,
+};
+
+static int ftrfs_init_fs_context(struct fs_context *fc)
+{
+	fc->ops = &ftrfs_context_ops;
+	return 0;
+}
+
+static struct file_system_type ftrfs_fs_type = {
+	.owner            = THIS_MODULE,
+	.name             = "ftrfs",
+	.init_fs_context  = ftrfs_init_fs_context,
+	.kill_sb          = kill_block_super,
+	.fs_flags         = FS_REQUIRES_DEV,
+};
+
+/*
+ * Inode cache constructor
+ */
+static void ftrfs_inode_init_once(void *obj)
+{
+	struct ftrfs_inode_info *fi = obj;
+
+	inode_init_once(&fi->vfs_inode);
+}
+
+/*
+ * Module init / exit
+ */
+static int __init ftrfs_init(void)
+{
+	int ret;
+
+	ftrfs_inode_cachep = kmem_cache_create(
+		"ftrfs_inode_cache",
+		sizeof(struct ftrfs_inode_info),
+		0,
+		SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT,
+		ftrfs_inode_init_once);
+
+	if (!ftrfs_inode_cachep) {
+		pr_err("ftrfs: failed to create inode cache\n");
+		return -ENOMEM;
+	}
+
+	ret = register_filesystem(&ftrfs_fs_type);
+	if (ret) {
+		pr_err("ftrfs: failed to register filesystem: %d\n", ret);
+		kmem_cache_destroy(ftrfs_inode_cachep);
+		return ret;
+	}
+
+	pr_info("ftrfs: module loaded (FTRFS Fault-Tolerant Radiation-Robust FS)\n");
+	return 0;
+}
+
+static void __exit ftrfs_exit(void)
+{
+	unregister_filesystem(&ftrfs_fs_type);
+	rcu_barrier();
+	kmem_cache_destroy(ftrfs_inode_cachep);
+	pr_info("ftrfs: module unloaded\n");
+}
+
+module_init(ftrfs_init);
+module_exit(ftrfs_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("roastercode - Aurelien DESBRIERES <aurelien@hackers.camp>");
+MODULE_DESCRIPTION("FTRFS: Fault-Tolerant Radiation-Robust Filesystem");
+MODULE_VERSION("0.1.0");
+MODULE_ALIAS_FS("ftrfs");
-- 
2.52.0


  parent reply	other threads:[~2026-04-13 12:24 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-13 14:23 [RFC PATCH 0/10] ftrfs: Fault-Tolerant Radiation-Robust Filesystem Aurelien DESBRIERES
2026-04-13 14:23 ` [RFC PATCH 01/10] ftrfs: add on-disk format and in-memory data structures Aurelien DESBRIERES
2026-04-13 15:11   ` Darrick J. Wong
2026-04-13 17:26     ` Aurelien DESBRIERES
2026-04-13 14:23 ` Aurelien DESBRIERES [this message]
2026-04-13 14:23 ` [RFC PATCH 03/10] ftrfs: add inode operations Aurelien DESBRIERES
2026-04-13 14:23 ` [RFC PATCH 04/10] ftrfs: add directory operations Aurelien DESBRIERES
2026-04-13 14:23 ` [RFC PATCH 05/10] ftrfs: add file operations Aurelien DESBRIERES
2026-04-13 15:09   ` Matthew Wilcox
     [not found]     ` <CAM=40tU5NppEZ9x07qDVkSxLw6Ga4nVg7sDCqcvhfQ51VbsS9Q@mail.gmail.com>
2026-04-13 17:41       ` Matthew Wilcox
2026-04-13 14:23 ` [RFC PATCH 06/10] ftrfs: add block and inode allocator Aurelien DESBRIERES
2026-04-13 15:21   ` Darrick J. Wong
2026-04-14 14:11     ` Aurelien DESBRIERES
2026-04-13 14:23 ` [RFC PATCH 07/10] ftrfs: add filename and directory entry operations Aurelien DESBRIERES
2026-04-13 14:23 ` [RFC PATCH 08/10] ftrfs: add CRC32 checksumming and Reed-Solomon FEC skeleton Aurelien DESBRIERES
2026-04-13 14:23 ` [RFC PATCH 09/10] ftrfs: add Kconfig, Makefile and fs/ tree integration Aurelien DESBRIERES
2026-04-13 14:23 ` [RFC PATCH 10/10] MAINTAINERS: add entry for FTRFS filesystem Aurelien DESBRIERES
2026-04-13 15:04 ` [RFC PATCH 0/10] ftrfs: Fault-Tolerant Radiation-Robust Filesystem Pedro Falcato
2026-04-13 18:03   ` Andreas Dilger
2026-04-14  2:56     ` Gao Xiang
2026-04-14 14:11     ` Aurelien DESBRIERES
2026-04-14 13:30   ` Aurelien DESBRIERES
2026-04-13 15:06 ` Matthew Wilcox
2026-04-13 18:11   ` Darrick J. Wong
2026-04-14 14:11     ` Aurelien DESBRIERES
2026-04-14 13:31   ` 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=20260413142357.515792-3-aurelien@hackers.camp \
    --to=aurelien@hackers.camp \
    --cc=brauner@kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=viro@zeniv.linux.org.uk \
    /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