From d122d51aea2418eda8110c7c6be1aa5c11e1ed11 Mon Sep 17 00:00:00 2001 From: Eric Kim Date: Tue, 5 May 2026 11:54:41 +0900 Subject: [PATCH 1/7] fs: added support for fs_context operations -> parse_param --- fs.c | 10 +++++++ simplefs.h | 13 +++++++-- super.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 94 insertions(+), 6 deletions(-) diff --git a/fs.c b/fs.c index a442005..53e3c79 100644 --- a/fs.c +++ b/fs.c @@ -3,6 +3,7 @@ #if SIMPLEFS_AT_LEAST(6, 18, 0) #include +#include #endif #include #include @@ -16,12 +17,20 @@ static int simplefs_get_tree(struct fs_context *fc) } static const struct fs_context_operations simplefs_context_ops = { .get_tree = simplefs_get_tree, + .parse_param = simplefs_parse_param, }; static int init_simplefs_context(struct fs_context *fc) { + struct simplefs_fs_context *ctx; + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if(!ctx) + return -ENOMEM; + fc->fs_private = ctx; fc->ops = &simplefs_context_ops; + return 0; } +extern const struct fs_parameter_spec simplefs_param_specs; #else /* Mount a simplefs partition */ struct dentry *simplefs_mount(struct file_system_type *fs_type, @@ -60,6 +69,7 @@ static struct file_system_type simplefs_file_system_type = { .name = "simplefs", #if SIMPLEFS_AT_LEAST(6, 18, 0) .init_fs_context = init_simplefs_context, + .parameters = &simplefs_param_specs, #else .mount = simplefs_mount, #endif diff --git a/simplefs.h b/simplefs.h index 8bc1de3..ff113ef 100644 --- a/simplefs.h +++ b/simplefs.h @@ -99,7 +99,12 @@ struct simplefs_dir_block { uint32_t nr_files; struct simplefs_file files[SIMPLEFS_FILES_PER_BLOCK]; }; - +#if SIMPLEFS_AT_LEAST(6, 18, 0) +struct simplefs_fs_context { + u32 journal_dev; + char *journal_path; +}; +#endif /* superblock functions */ #if SIMPLEFS_AT_LEAST(6, 18, 0) int simplefs_fill_super(struct super_block *sb, struct fs_context *fc); @@ -107,7 +112,11 @@ int simplefs_fill_super(struct super_block *sb, struct fs_context *fc); int simplefs_fill_super(struct super_block *sb, void *data, int silent); #endif void simplefs_kill_sb(struct super_block *sb); - +#if SIMPLEFS_AT_LEAST(6, 18, 0) +#include +#include +int simplefs_parse_param(struct fs_context *fc, struct fs_parameter *param); +#endif /* inode functions */ int simplefs_init_inode_cache(void); void simplefs_destroy_inode_cache(void); diff --git a/super.c b/super.c index c453603..ed853c0 100644 --- a/super.c +++ b/super.c @@ -15,6 +15,7 @@ #include "simplefs.h" #if SIMPLEFS_AT_LEAST(6, 18, 0) #include +#include #endif struct dentry *simplefs_mount(struct file_system_type *fs_type, int flags, @@ -449,6 +450,40 @@ static const match_table_t tokens = { {SIMPLEFS_OPT_JOURNAL_DEV, "journal_dev=%u"}, {SIMPLEFS_OPT_JOURNAL_PATH, "journal_path=%s"}, }; +#if SIMPLEFS_AT_LEAST(6, 18, 0) +const struct fs_parameter_spec simplefs_param_specs[] = { + fsparam_u32("journal_dev", SIMPLEFS_OPT_JOURNAL_DEV), + fsparam_string("journal_path", SIMPLEFS_OPT_JOURNAL_PATH), + {} +}; +int simplefs_parse_param(struct fs_context *fc, struct fs_parameter *param) +{ + struct simplefs_fs_context *ctx = fc->fs_private; + struct fs_parse_result result; + int opt; + + opt = fs_parse(fc, simplefs_param_specs, param, &result); + if (opt < 0) + return opt; + + switch (opt) { + case SIMPLEFS_OPT_JOURNAL_DEV: + ctx->journal_dev = result.uint_32; + break; + + case SIMPLEFS_OPT_JOURNAL_PATH: { + kfree(ctx->journal_path); + ctx->journal_path = kstrdup(param->string, GFP_KERNEL); + if(!ctx->journal_path) + return -ENOMEM; + break; + default: + return -EINVAL; + } + } + return 0; +} +#else static int simplefs_parse_options(struct super_block *sb, char *options) { substring_t args[MAX_OPT_ARGS]; @@ -520,7 +555,7 @@ static int simplefs_parse_options(struct super_block *sb, char *options) return 0; } - +#endif static struct super_operations simplefs_super_ops = { .put_super = simplefs_put_super, .alloc_inode = simplefs_alloc_inode, @@ -534,6 +569,7 @@ static struct super_operations simplefs_super_ops = { #if SIMPLEFS_AT_LEAST(6, 18, 0) int simplefs_fill_super(struct super_block *sb, struct fs_context *fc) { + struct simplefs_fs_context *ctx = fc->fs_private; #else int simplefs_fill_super(struct super_block *sb, void *data, int silent) { @@ -651,9 +687,42 @@ inode_init_owner(root_inode, NULL, root_inode->i_mode); ret = -ENOMEM; goto iput; } - /* Since parse_options is not available at fill_super stage at kernels - * v6.18+, it is disabled for now. */ -#if SIMPLEFS_LESS_EQUAL(6, 17, 0) + +#if SIMPLEFS_AT_LEAST(6, 18, 0) + if(ctx->journal_dev) { + ret = simplefs_load_journal(sb, ctx->journal_dev); + if(ret) { + pr_err( + "simplefs_parse_options: simplefs_load_journal failed with " + "%d\n", + ret); + return ret; + } + } + if(ctx->journal_path) { + struct path path; + struct inode *inode; + ret = kern_path(ctx->journal_path, LOOKUP_FOLLOW, &path); + if(ret) { + pr_err( + "simplefs_parse_options: kern_path failed with error %d\n", + ret); + return ret; + } + inode = d_inode(path.dentry); + if(S_ISBLK(inode->i_mode)) { + unsigned long journal_devnum = + new_encode_dev(inode->i_rdev); + if((ret = simplefs_load_journal(sb, journal_devnum))) { + pr_err( + "simplefs_parse_options: simplefs_load_journal failed " + "with %d\n", + ret); + return ret; + } + } + } +#else ret = simplefs_parse_options(sb, data); if (ret) { pr_err("simplefs_fill_super: Failed to parse options, error code: %d\n", From 2420809480692ad49120333bd02bf53bbeeb125a Mon Sep 17 00:00:00 2001 From: Eric Kim Date: Tue, 5 May 2026 12:10:31 +0900 Subject: [PATCH 2/7] formatting correction --- fs.c | 2 +- simplefs.h | 2 +- super.c | 27 ++++++++++++--------------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/fs.c b/fs.c index 53e3c79..4986899 100644 --- a/fs.c +++ b/fs.c @@ -23,7 +23,7 @@ static int init_simplefs_context(struct fs_context *fc) { struct simplefs_fs_context *ctx; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if(!ctx) + if (!ctx) return -ENOMEM; fc->fs_private = ctx; fc->ops = &simplefs_context_ops; diff --git a/simplefs.h b/simplefs.h index ff113ef..a6cf9e1 100644 --- a/simplefs.h +++ b/simplefs.h @@ -113,8 +113,8 @@ int simplefs_fill_super(struct super_block *sb, void *data, int silent); #endif void simplefs_kill_sb(struct super_block *sb); #if SIMPLEFS_AT_LEAST(6, 18, 0) -#include #include +#include int simplefs_parse_param(struct fs_context *fc, struct fs_parameter *param); #endif /* inode functions */ diff --git a/super.c b/super.c index ed853c0..af21f8a 100644 --- a/super.c +++ b/super.c @@ -454,18 +454,17 @@ static const match_table_t tokens = { const struct fs_parameter_spec simplefs_param_specs[] = { fsparam_u32("journal_dev", SIMPLEFS_OPT_JOURNAL_DEV), fsparam_string("journal_path", SIMPLEFS_OPT_JOURNAL_PATH), - {} -}; + {}}; int simplefs_parse_param(struct fs_context *fc, struct fs_parameter *param) { struct simplefs_fs_context *ctx = fc->fs_private; struct fs_parse_result result; int opt; - + opt = fs_parse(fc, simplefs_param_specs, param, &result); if (opt < 0) return opt; - + switch (opt) { case SIMPLEFS_OPT_JOURNAL_DEV: ctx->journal_dev = result.uint_32; @@ -474,11 +473,11 @@ int simplefs_parse_param(struct fs_context *fc, struct fs_parameter *param) case SIMPLEFS_OPT_JOURNAL_PATH: { kfree(ctx->journal_path); ctx->journal_path = kstrdup(param->string, GFP_KERNEL); - if(!ctx->journal_path) + if (!ctx->journal_path) return -ENOMEM; break; default: - return -EINVAL; + return -EINVAL; } } return 0; @@ -689,7 +688,7 @@ inode_init_owner(root_inode, NULL, root_inode->i_mode); } #if SIMPLEFS_AT_LEAST(6, 18, 0) - if(ctx->journal_dev) { + if (ctx->journal_dev) { ret = simplefs_load_journal(sb, ctx->journal_dev); if(ret) { pr_err( @@ -699,21 +698,19 @@ inode_init_owner(root_inode, NULL, root_inode->i_mode); return ret; } } - if(ctx->journal_path) { + if (ctx->journal_path) { struct path path; struct inode *inode; ret = kern_path(ctx->journal_path, LOOKUP_FOLLOW, &path); if(ret) { - pr_err( - "simplefs_parse_options: kern_path failed with error %d\n", - ret); + pr_err("simplefs_parse_options: kern_path failed with error %d\n", + ret); return ret; } inode = d_inode(path.dentry); - if(S_ISBLK(inode->i_mode)) { - unsigned long journal_devnum = - new_encode_dev(inode->i_rdev); - if((ret = simplefs_load_journal(sb, journal_devnum))) { + if (S_ISBLK(inode->i_mode)) { + unsigned long journal_devnum = new_encode_dev(inode->i_rdev); + if ((ret = simplefs_load_journal(sb, journal_devnum))) { pr_err( "simplefs_parse_options: simplefs_load_journal failed " "with %d\n", From 9c911de71183c74dc0fb11bc5810e25a7e3c6503 Mon Sep 17 00:00:00 2001 From: Eric Kim Date: Tue, 5 May 2026 12:13:28 +0900 Subject: [PATCH 3/7] formatting correction according to coding style tests --- fs.c | 2 +- super.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fs.c b/fs.c index 4986899..031032d 100644 --- a/fs.c +++ b/fs.c @@ -27,7 +27,7 @@ static int init_simplefs_context(struct fs_context *fc) return -ENOMEM; fc->fs_private = ctx; fc->ops = &simplefs_context_ops; - + return 0; } extern const struct fs_parameter_spec simplefs_param_specs; diff --git a/super.c b/super.c index af21f8a..24d4a36 100644 --- a/super.c +++ b/super.c @@ -477,7 +477,7 @@ int simplefs_parse_param(struct fs_context *fc, struct fs_parameter *param) return -ENOMEM; break; default: - return -EINVAL; + return -EINVAL; } } return 0; @@ -702,9 +702,9 @@ inode_init_owner(root_inode, NULL, root_inode->i_mode); struct path path; struct inode *inode; ret = kern_path(ctx->journal_path, LOOKUP_FOLLOW, &path); - if(ret) { + if (ret) { pr_err("simplefs_parse_options: kern_path failed with error %d\n", - ret); + ret); return ret; } inode = d_inode(path.dentry); From 53e386f688aa9b2f7f9d8d027e5ad038dd74f2a3 Mon Sep 17 00:00:00 2001 From: Eric Kim Date: Tue, 5 May 2026 12:15:15 +0900 Subject: [PATCH 4/7] fix: formatting correction according to the coding style failures --- super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/super.c b/super.c index 24d4a36..5188699 100644 --- a/super.c +++ b/super.c @@ -690,7 +690,7 @@ inode_init_owner(root_inode, NULL, root_inode->i_mode); #if SIMPLEFS_AT_LEAST(6, 18, 0) if (ctx->journal_dev) { ret = simplefs_load_journal(sb, ctx->journal_dev); - if(ret) { + if (ret) { pr_err( "simplefs_parse_options: simplefs_load_journal failed with " "%d\n", From 3e232e651399f6c921cda9a6bf8a3eee71876a7b Mon Sep 17 00:00:00 2001 From: Eric Kim Date: Tue, 5 May 2026 12:32:23 +0900 Subject: [PATCH 5/7] fix: potential memory leak fixes at fs_context_operations by adding free_context and path_put after inode = d_inode() and minor fixes --- fs.c | 12 +++++++++++- simplefs.h | 2 +- super.c | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/fs.c b/fs.c index 031032d..dec714e 100644 --- a/fs.c +++ b/fs.c @@ -3,7 +3,7 @@ #if SIMPLEFS_AT_LEAST(6, 18, 0) #include -#include +#include #endif #include #include @@ -15,9 +15,19 @@ static int simplefs_get_tree(struct fs_context *fc) { return get_tree_bdev(fc, simplefs_fill_super); } +static void simplefs_free_context(struct fs_context *fc) { + struct simplefs_fs_context *ctx = fc->fs_private; + + if (!ctx) + return; + + kfree(ctx->journal_path); + kfree(ctx); +} static const struct fs_context_operations simplefs_context_ops = { .get_tree = simplefs_get_tree, .parse_param = simplefs_parse_param, + .free = simplefs_free_context, }; static int init_simplefs_context(struct fs_context *fc) { diff --git a/simplefs.h b/simplefs.h index a6cf9e1..1ee01c7 100644 --- a/simplefs.h +++ b/simplefs.h @@ -114,7 +114,7 @@ int simplefs_fill_super(struct super_block *sb, void *data, int silent); void simplefs_kill_sb(struct super_block *sb); #if SIMPLEFS_AT_LEAST(6, 18, 0) #include -#include +#include int simplefs_parse_param(struct fs_context *fc, struct fs_parameter *param); #endif /* inode functions */ diff --git a/super.c b/super.c index 5188699..b721dc4 100644 --- a/super.c +++ b/super.c @@ -708,6 +708,7 @@ inode_init_owner(root_inode, NULL, root_inode->i_mode); return ret; } inode = d_inode(path.dentry); + path_put(&path); if (S_ISBLK(inode->i_mode)) { unsigned long journal_devnum = new_encode_dev(inode->i_rdev); if ((ret = simplefs_load_journal(sb, journal_devnum))) { From bce121051d9172037a459a415099174ceb44f073 Mon Sep 17 00:00:00 2001 From: Eric Kim Date: Tue, 5 May 2026 12:34:20 +0900 Subject: [PATCH 6/7] coding style formatting correction accordingly to coding style checks --- fs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs.c b/fs.c index dec714e..09f0890 100644 --- a/fs.c +++ b/fs.c @@ -15,7 +15,8 @@ static int simplefs_get_tree(struct fs_context *fc) { return get_tree_bdev(fc, simplefs_fill_super); } -static void simplefs_free_context(struct fs_context *fc) { +static void simplefs_free_context(struct fs_context *fc) +{ struct simplefs_fs_context *ctx = fc->fs_private; if (!ctx) From e60949bb65dbfce8c1b25adf8362a3d4cbbbfd54 Mon Sep 17 00:00:00 2001 From: Eric Kim Date: Tue, 5 May 2026 19:18:02 +0900 Subject: [PATCH 7/7] Replaced path_put to resolve possible use-after-free --- super.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/super.c b/super.c index b721dc4..a2c44b2 100644 --- a/super.c +++ b/super.c @@ -530,12 +530,9 @@ static int simplefs_parse_options(struct super_block *sb, char *options) kfree(journal_path); return ret; } - - journal_inode = path.dentry->d_inode; - - path_put(&path); kfree(journal_path); + journal_inode = path.dentry->d_inode; if (S_ISBLK(journal_inode->i_mode)) { unsigned long journal_devnum = new_encode_dev(journal_inode->i_rdev); @@ -547,6 +544,7 @@ static int simplefs_parse_options(struct super_block *sb, char *options) return ret; } } + path_put(&path); break; } }