1*576ee5dfSChristian Brauner // SPDX-License-Identifier: GPL-2.0-only 2*576ee5dfSChristian Brauner /* Copyright (c) 2026 Christian Brauner <brauner@kernel.org> */ 3*576ee5dfSChristian Brauner #include <linux/fs/super_types.h> 4*576ee5dfSChristian Brauner #include <linux/fs_context.h> 5*576ee5dfSChristian Brauner #include <linux/magic.h> 6*576ee5dfSChristian Brauner 7*576ee5dfSChristian Brauner static const struct super_operations nullfs_super_operations = { 8*576ee5dfSChristian Brauner .statfs = simple_statfs, 9*576ee5dfSChristian Brauner }; 10*576ee5dfSChristian Brauner 11*576ee5dfSChristian Brauner static int nullfs_fs_fill_super(struct super_block *s, struct fs_context *fc) 12*576ee5dfSChristian Brauner { 13*576ee5dfSChristian Brauner struct inode *inode; 14*576ee5dfSChristian Brauner 15*576ee5dfSChristian Brauner s->s_maxbytes = MAX_LFS_FILESIZE; 16*576ee5dfSChristian Brauner s->s_blocksize = PAGE_SIZE; 17*576ee5dfSChristian Brauner s->s_blocksize_bits = PAGE_SHIFT; 18*576ee5dfSChristian Brauner s->s_magic = NULL_FS_MAGIC; 19*576ee5dfSChristian Brauner s->s_op = &nullfs_super_operations; 20*576ee5dfSChristian Brauner s->s_export_op = NULL; 21*576ee5dfSChristian Brauner s->s_xattr = NULL; 22*576ee5dfSChristian Brauner s->s_time_gran = 1; 23*576ee5dfSChristian Brauner s->s_d_flags = 0; 24*576ee5dfSChristian Brauner 25*576ee5dfSChristian Brauner inode = new_inode(s); 26*576ee5dfSChristian Brauner if (!inode) 27*576ee5dfSChristian Brauner return -ENOMEM; 28*576ee5dfSChristian Brauner 29*576ee5dfSChristian Brauner /* nullfs is permanently empty... */ 30*576ee5dfSChristian Brauner make_empty_dir_inode(inode); 31*576ee5dfSChristian Brauner simple_inode_init_ts(inode); 32*576ee5dfSChristian Brauner inode->i_ino = 1; 33*576ee5dfSChristian Brauner /* ... and immutable. */ 34*576ee5dfSChristian Brauner inode->i_flags |= S_IMMUTABLE; 35*576ee5dfSChristian Brauner 36*576ee5dfSChristian Brauner s->s_root = d_make_root(inode); 37*576ee5dfSChristian Brauner if (!s->s_root) 38*576ee5dfSChristian Brauner return -ENOMEM; 39*576ee5dfSChristian Brauner 40*576ee5dfSChristian Brauner return 0; 41*576ee5dfSChristian Brauner } 42*576ee5dfSChristian Brauner 43*576ee5dfSChristian Brauner /* 44*576ee5dfSChristian Brauner * For now this is a single global instance. If needed we can make it 45*576ee5dfSChristian Brauner * mountable by userspace at which point we will need to make it 46*576ee5dfSChristian Brauner * multi-instance. 47*576ee5dfSChristian Brauner */ 48*576ee5dfSChristian Brauner static int nullfs_fs_get_tree(struct fs_context *fc) 49*576ee5dfSChristian Brauner { 50*576ee5dfSChristian Brauner return get_tree_single(fc, nullfs_fs_fill_super); 51*576ee5dfSChristian Brauner } 52*576ee5dfSChristian Brauner 53*576ee5dfSChristian Brauner static const struct fs_context_operations nullfs_fs_context_ops = { 54*576ee5dfSChristian Brauner .get_tree = nullfs_fs_get_tree, 55*576ee5dfSChristian Brauner }; 56*576ee5dfSChristian Brauner 57*576ee5dfSChristian Brauner static int nullfs_init_fs_context(struct fs_context *fc) 58*576ee5dfSChristian Brauner { 59*576ee5dfSChristian Brauner fc->ops = &nullfs_fs_context_ops; 60*576ee5dfSChristian Brauner fc->global = true; 61*576ee5dfSChristian Brauner fc->sb_flags = SB_NOUSER; 62*576ee5dfSChristian Brauner fc->s_iflags = SB_I_NOEXEC | SB_I_NODEV; 63*576ee5dfSChristian Brauner return 0; 64*576ee5dfSChristian Brauner } 65*576ee5dfSChristian Brauner 66*576ee5dfSChristian Brauner struct file_system_type nullfs_fs_type = { 67*576ee5dfSChristian Brauner .name = "nullfs", 68*576ee5dfSChristian Brauner .init_fs_context = nullfs_init_fs_context, 69*576ee5dfSChristian Brauner .kill_sb = kill_anon_super, 70*576ee5dfSChristian Brauner }; 71