mirror of
https://github.com/linux-apfs/linux-apfs-rw.git
synced 2026-08-18 02:19:59 -07:00
Compare commits
13
Commits
v0.3.19
...
development
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a10279ce66 | ||
|
|
7711c4704e | ||
|
|
9619c53686 | ||
|
|
f5b71842e6 | ||
|
|
83205caaad | ||
|
|
8a37600293 | ||
|
|
f0e88ca368 | ||
|
|
96d5614d04 | ||
|
|
b2418aaaa7 | ||
|
|
628b6810e4 | ||
|
|
7aca589f9e | ||
|
|
36df7e0b35 | ||
|
|
ae381fbc3d |
No files matched your search
+7
-2
@@ -57,10 +57,15 @@ Now you can just cd to the linux-apfs-rw directory and run::
|
||||
make
|
||||
|
||||
The resulting module is the apfs.ko file. Before you can use it you must insert
|
||||
it into the kernel, as well as its dependencies. Again as root::
|
||||
it into the kernel. Again as root::
|
||||
|
||||
insmod apfs.ko
|
||||
|
||||
If you get an "unknown symbol in module" error, run::
|
||||
|
||||
modprobe libcrc32c
|
||||
insmod apfs.ko
|
||||
|
||||
and then try the insmod command again.
|
||||
|
||||
Mount
|
||||
=====
|
||||
|
||||
@@ -44,10 +44,33 @@ static inline bool sb_rdonly(const struct super_block *sb) { return sb->s_flags
|
||||
#endif
|
||||
|
||||
/* Compatibility wrapper around submit_bh() */
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) || RHEL_VERSION_GE(9, 2)
|
||||
#define apfs_submit_bh(op, op_flags, bh) submit_bh(op | op_flags, bh)
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 2, 0)
|
||||
#define apfs_submit_bh(op, op_flags, bh) \
|
||||
do { \
|
||||
put_bh(bh); \
|
||||
if (op == REQ_OP_READ) \
|
||||
bh_submit(bh, op | op_flags, bh_end_read); \
|
||||
else \
|
||||
bh_submit(bh, op | op_flags, bh_end_write); \
|
||||
} while (0)
|
||||
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) || RHEL_VERSION_GE(9, 2)
|
||||
#define apfs_submit_bh(op, op_flags, bh) \
|
||||
do { \
|
||||
if (op == REQ_OP_READ) \
|
||||
bh->b_end_io = end_buffer_read_sync; \
|
||||
else \
|
||||
bh->b_end_io = end_buffer_write_sync; \
|
||||
submit_bh(op | op_flags, bh); \
|
||||
} while (0)
|
||||
#else
|
||||
#define apfs_submit_bh(op, op_flags, bh) submit_bh(op, op_flags, bh)
|
||||
#define apfs_submit_bh(op, op_flags, bh) \
|
||||
do { \
|
||||
if (op == REQ_OP_READ) \
|
||||
bh->b_end_io = end_buffer_read_sync; \
|
||||
else \
|
||||
bh->b_end_io = end_buffer_write_sync; \
|
||||
submit_bh(op, op_flags, bh); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -1324,7 +1347,7 @@ __apfs_getblk(struct super_block *sb, sector_t block)
|
||||
block -= nxi->nx_tier2_bno;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0)
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0) && !RHEL_VERSION_GE(9, 8)
|
||||
return __getblk_gfp(info->blki_bdev, block, sb->s_blocksize, __GFP_MOVABLE);
|
||||
#else
|
||||
return bdev_getblk(info->blki_bdev, block, sb->s_blocksize, __GFP_MOVABLE);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
PACKAGE_NAME="linux-apfs-rw"
|
||||
PACKAGE_VERSION="0.3.19"
|
||||
PACKAGE_VERSION="0.3.21"
|
||||
|
||||
BUILT_MODULE_NAME[0]="apfs"
|
||||
DEST_MODULE_LOCATION[0]="/extra"
|
||||
|
||||
@@ -2298,7 +2298,6 @@ int apfs_nonsparse_dstream_read(struct apfs_dstream_info *dstream, void *buf, si
|
||||
if (!buffer_uptodate(bh)) {
|
||||
get_bh(bh);
|
||||
lock_buffer(bh);
|
||||
bh->b_end_io = end_buffer_read_sync;
|
||||
apfs_submit_bh(REQ_OP_READ, 0, bh);
|
||||
}
|
||||
}
|
||||
@@ -2365,7 +2364,6 @@ void apfs_nonsparse_dstream_preread(struct apfs_dstream_info *dstream)
|
||||
if (!buffer_uptodate(bh)) {
|
||||
get_bh(bh);
|
||||
lock_buffer(bh);
|
||||
bh->b_end_io = end_buffer_read_sync;
|
||||
apfs_submit_bh(REQ_OP_READ, 0, bh);
|
||||
}
|
||||
brelse(bh);
|
||||
|
||||
@@ -556,7 +556,6 @@ int __apfs_write_begin(struct file *file, struct address_space *mapping, loff_t
|
||||
if (buffer_mapped(bh) && !buffer_uptodate(bh)) {
|
||||
get_bh(bh);
|
||||
lock_buffer(bh);
|
||||
bh->b_end_io = end_buffer_read_sync;
|
||||
apfs_submit_bh(REQ_OP_READ, 0, bh);
|
||||
wait_on_buffer(bh);
|
||||
if (!buffer_uptodate(bh)) {
|
||||
|
||||
@@ -70,7 +70,9 @@ typedef int64_t lzfse_offset;
|
||||
typedef int32_t lzfse_offset;
|
||||
#endif
|
||||
|
||||
#if !defined(__APPLE__) || !defined(__MACH__)
|
||||
typedef uint64_t uintmax_t;
|
||||
#endif
|
||||
|
||||
/*! @abstract Decoder state object for lzfse compressed blocks. */
|
||||
typedef struct {
|
||||
|
||||
@@ -308,6 +308,7 @@ static int apfs_write_single_ip_bitmap(struct super_block *sb, char *bitmap, u32
|
||||
err = apfs_transaction_join(sb, bh);
|
||||
if (err)
|
||||
goto fail;
|
||||
put_bh(bh);
|
||||
bh = NULL;
|
||||
|
||||
spaceman->sm_ip_bmaps[idx].dirty = false;
|
||||
|
||||
@@ -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 ")"
|
||||
@@ -342,8 +343,8 @@ static int apfs_read_main_super(struct super_block *sb)
|
||||
xid = le64_to_cpu(msb_raw->nx_o.o_xid);
|
||||
for (i = 0; i < desc_blocks; ++i) {
|
||||
struct apfs_nx_superblock *desc_raw;
|
||||
bool ignore;
|
||||
|
||||
brelse(desc_bh);
|
||||
desc_bh = apfs_sb_bread(sb, desc_base + i);
|
||||
if (!desc_bh) {
|
||||
apfs_err(sb, "unable to read checkpoint descriptor");
|
||||
@@ -351,18 +352,24 @@ static int apfs_read_main_super(struct super_block *sb)
|
||||
}
|
||||
desc_raw = (struct apfs_nx_superblock *)desc_bh->b_data;
|
||||
|
||||
ignore = false;
|
||||
if (le32_to_cpu(desc_raw->nx_magic) != APFS_NX_MAGIC)
|
||||
continue; /* Not a superblock */
|
||||
ignore = true; /* Not a superblock */
|
||||
if (le64_to_cpu(desc_raw->nx_o.o_xid) <= xid)
|
||||
continue; /* Old */
|
||||
ignore = true; /* Old */
|
||||
if (!apfs_obj_verify_csum(sb, desc_bh))
|
||||
continue; /* Corrupted */
|
||||
ignore = true; /* Corrupted */
|
||||
|
||||
xid = le64_to_cpu(desc_raw->nx_o.o_xid);
|
||||
msb_raw = desc_raw;
|
||||
bno = desc_base + i;
|
||||
brelse(bh);
|
||||
bh = desc_bh;
|
||||
if (ignore) {
|
||||
brelse(desc_bh);
|
||||
} else {
|
||||
xid = le64_to_cpu(desc_raw->nx_o.o_xid);
|
||||
msb_raw = desc_raw;
|
||||
bno = desc_base + i;
|
||||
brelse(bh);
|
||||
bh = desc_bh;
|
||||
}
|
||||
desc_raw = NULL;
|
||||
desc_bh = NULL;
|
||||
}
|
||||
|
||||
@@ -1203,6 +1210,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 +1221,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 +1272,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 +1306,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 +1377,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 +2006,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 +2206,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 +2221,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;
|
||||
|
||||
+3
-1
@@ -640,6 +640,9 @@ static int apfs_write_ephemeral_objects(struct super_block *sb)
|
||||
}
|
||||
data_len += obj_blkcnt;
|
||||
}
|
||||
brelse(cpm_bh);
|
||||
cpm = NULL;
|
||||
cpm_bh = NULL;
|
||||
|
||||
/*
|
||||
* The checkpoint superblock can't be set until the very end of the
|
||||
@@ -721,7 +724,6 @@ static int apfs_transaction_commit_nx(struct super_block *sb)
|
||||
clear_buffer_dirty(bh);
|
||||
get_bh(bh);
|
||||
lock_buffer(bh);
|
||||
bh->b_end_io = end_buffer_write_sync;
|
||||
apfs_submit_bh(REQ_OP_WRITE, REQ_SYNC, bh);
|
||||
}
|
||||
list_for_each_entry_safe(bhi, tmp, &nx_trans->t_buffers, list) {
|
||||
|
||||
Reference in new issue
Block a user