4 Commits
Author SHA1 Message Date
Ernesto A. Fernández 628b6810e4 0.3.20
This quick release adds support for the fsconfig() syscall, otherwise
newer versions of the mount tool won't accept any options.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-04-25 16:28:02 -03:00
Ernesto A. Fernández 7aca589f9e Use ->parse_param(), not ->parse_monolithic()
SergDL reports that mounts seem broken for the 7.0 kernel:

  https://github.com/linux-apfs/linux-apfs-rw/issues/119

I never encountered this problem during testing, probably because my
version of the mount tool is older. It seems that mount options are now
set one by one using the fsconfig() syscall, and that's not possible if
we parse them all at once with ->parse_monolithic().

Implement ->parse_param() instead, at least for the latest kernel. I do
wonder if this issue won't pop up with older kernels though, since the
fsconfig() syscall has been around since 5.2. I guess I'll wait to see
if somebody complains about it.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-04-24 17:10:07 -03:00
Ernesto A. Fernández 36df7e0b35 Set default mount options as soon as possible
Instead of setting the default mount options right before parsing the
actual options, set them on the superblock as soon as it gets allocated.
This will allow the parsing code to be called more than once by the new
mount api.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-04-24 14:56:03 -03:00
Ernesto A. Fernández ae381fbc3d Move default mount options into separate function
The new mount api forces me to make one function call for each option to
parse. This change means that the default options will need to get set
elsewhere, otherwise each new call would reset to default.

As a first step, move that code from parse_options() into a new
apfs_set_default_opts().

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-04-24 14:48:27 -03:00
2 changed files with 94 additions and 21 deletions

No files matched your search

+1 -1
View File
@@ -1,5 +1,5 @@
PACKAGE_NAME="linux-apfs-rw"
PACKAGE_VERSION="0.3.19"
PACKAGE_VERSION="0.3.20"
BUILT_MODULE_NAME[0]="apfs"
DEST_MODULE_LOCATION[0]="/extra"
+93 -20
View File
@@ -17,6 +17,7 @@
#include "version.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 0, 0)
#include <linux/fs_context.h>
#include <linux/fs_parser.h>
#endif
#define APFS_MODULE_ID_STRING "linux-apfs by eafer (" GIT_COMMIT ")"
@@ -1203,6 +1204,7 @@ enum {
Opt_readwrite, Opt_cknodes, Opt_uid, Opt_gid, Opt_vol, Opt_snap, Opt_tier2, Opt_err,
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(7, 0, 0)
static const match_table_t tokens = {
{Opt_readwrite, "readwrite"},
{Opt_cknodes, "cknodes"},
@@ -1213,6 +1215,18 @@ static const match_table_t tokens = {
{Opt_tier2, "tier2=%s"},
{Opt_err, NULL}
};
#else
static const struct fs_parameter_spec apfs_param_spec[] = {
fsparam_flag ("readwrite", Opt_readwrite),
fsparam_flag ("cknodes", Opt_cknodes),
fsparam_uid ("uid", Opt_uid),
fsparam_gid ("gid", Opt_gid),
fsparam_u32 ("vol", Opt_vol),
fsparam_string ("snap", Opt_snap),
fsparam_string ("tier2", Opt_tier2),
{}
};
#endif
/**
* apfs_set_nx_flags - Set the mount flags for the container, if allowed
@@ -1252,6 +1266,26 @@ static void parse_options_set_flags(struct super_block *sb, struct apfs_sb_info
}
}
/**
* apfs_set_default_opts - Set the default mount options in the superblock
* @sbi: in-memory superblock info
*/
static void apfs_set_default_opts(struct apfs_sb_info *sbi)
{
sbi->s_vol_nr = 0;
sbi->s_snap_name = NULL;
sbi->s_tier2_path = NULL;
sbi->s_mount_opt = 0;
#ifdef CONFIG_APFS_RW_ALWAYS
/* Still risky, but some packagers want writable mounts by default */
sbi->s_mount_opt |= APFS_READWRITE;
#endif
sbi->s_uid = INVALID_UID;
sbi->s_gid = INVALID_GID;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(7, 0, 0)
/*
* Many of the parse_options() functions in other file systems return 0
* on error. This one returns an error code, and 0 on success.
@@ -1266,20 +1300,6 @@ static int parse_options(struct apfs_sb_info *sbi, char *options)
int option;
int err = 0;
/* Set default values before parsing */
sbi->s_vol_nr = 0;
sbi->s_snap_name = NULL;
sbi->s_tier2_path = NULL;
sbi->s_mount_opt = 0;
#ifdef CONFIG_APFS_RW_ALWAYS
/* Still risky, but some packagers want writable mounts by default */
sbi->s_mount_opt |= APFS_READWRITE;
#endif
sbi->s_uid = INVALID_UID;
sbi->s_gid = INVALID_GID;
if (!options)
return 0;
@@ -1351,6 +1371,62 @@ static int parse_options(struct apfs_sb_info *sbi, char *options)
return 0;
}
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(7, 0, 0) */
static int apfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
{
struct apfs_sb_info *sbi = fc->s_fs_info;
int opt;
struct fs_parse_result result;
opt = fs_parse(fc, apfs_param_spec, param, &result);
if (opt < 0)
return opt;
switch (opt) {
case Opt_readwrite:
/*
* Write support is not safe yet, so keep it disabled
* unless the user requests it explicitly.
*/
sbi->s_mount_opt |= APFS_READWRITE;
break;
case Opt_cknodes:
/*
* Right now, node checksums are too costly to enable
* by default. TODO: try to improve this.
*/
sbi->s_mount_opt |= APFS_CHECK_NODES;
break;
case Opt_uid:
sbi->s_uid = result.uid;
break;
case Opt_gid:
sbi->s_gid = result.gid;
break;
case Opt_vol:
sbi->s_vol_nr = result.uint_32;
break;
case Opt_snap:
kfree(sbi->s_snap_name);
sbi->s_snap_name = kstrdup(param->string, GFP_KERNEL);
if (!sbi->s_snap_name)
return -ENOMEM;
break;
case Opt_tier2:
kfree(sbi->s_tier2_path);
sbi->s_tier2_path = kstrdup(param->string, GFP_KERNEL);
if (!sbi->s_tier2_path)
return -ENOMEM;
break;
default:
return -EINVAL;
}
return 0;
}
#endif
/**
* apfs_check_nx_features - Check for unsupported features in the container
* @sb: superblock structure
@@ -1924,6 +2000,7 @@ static struct dentry *apfs_mount(struct file_system_type *fs_type, int flags,
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
return ERR_PTR(-ENOMEM);
apfs_set_default_opts(sbi);
/* Set up the fields that sget() will need to id the superblock */
error = parse_options(sbi, data);
if (error)
@@ -2123,16 +2200,11 @@ static void apfs_free_fc(struct fs_context *fc)
}
}
static int apfs_parse_monolithic(struct fs_context *fc, void *data)
{
return parse_options(fc->s_fs_info, data);
}
static const struct fs_context_operations apfs_context_ops = {
.get_tree = apfs_get_tree,
.reconfigure = apfs_reconfigure,
.free = apfs_free_fc,
.parse_monolithic = apfs_parse_monolithic,
.parse_param = apfs_parse_param,
};
static int apfs_init_fs_context(struct fs_context *fc)
@@ -2143,6 +2215,7 @@ static int apfs_init_fs_context(struct fs_context *fc)
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
apfs_set_default_opts(sbi);
fc->s_fs_info = sbi;
fc->ops = &apfs_context_ops;