mirror of
https://github.com/linux-apfs/linux-apfs-rw.git
synced 2026-08-18 02:19:59 -07:00
Compare commits
34
Commits
v0.3.14
...
development
No files matched your search
@@ -14,9 +14,9 @@ apfs-y := btree.o compress.o dir.o extents.o file.o inode.o key.o libzbitmap.o \
|
||||
spaceman.o super.o symlink.o transaction.o unicode.o xattr.o xfield.o
|
||||
|
||||
# If you want mounts to be writable by default, run the build as:
|
||||
# make CONFIG=-DCONFIG_APFS_RW_ALWAYS
|
||||
# make APFS_CONFIG=-DCONFIG_APFS_RW_ALWAYS
|
||||
# This is risky and not generally recommended.
|
||||
ccflags-y += $(CONFIG)
|
||||
ccflags-y += $(APFS_CONFIG)
|
||||
|
||||
default:
|
||||
./genver.sh
|
||||
|
||||
+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
|
||||
|
||||
/*
|
||||
@@ -380,6 +403,7 @@ struct apfs_sb_info {
|
||||
unsigned int s_vol_nr; /* Index of the volume in the sb list */
|
||||
kuid_t s_uid; /* uid to override on-disk uid */
|
||||
kgid_t s_gid; /* gid to override on-disk gid */
|
||||
unsigned int s_mount_opt;
|
||||
|
||||
struct apfs_crypto_state_val *s_dflt_pfk; /* default per-file key */
|
||||
|
||||
@@ -1021,8 +1045,13 @@ extern struct inode *apfs_new_inode(struct inode *dir, umode_t mode,
|
||||
extern int apfs_create_inode_rec(struct super_block *sb, struct inode *inode,
|
||||
struct dentry *dentry);
|
||||
extern int apfs_inode_create_exclusive_dstream(struct inode *inode);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0)
|
||||
extern int __apfs_write_begin(const struct kiocb *iocb, struct address_space *mapping, loff_t pos, unsigned int len, unsigned int flags, struct page **pagep, void **fsdata);
|
||||
extern int __apfs_write_end(const struct kiocb *iocb, struct address_space *mapping, loff_t pos, unsigned int len, unsigned int copied, struct page *page, void *fsdata);
|
||||
#else
|
||||
extern int __apfs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned int len, unsigned int flags, struct page **pagep, void **fsdata);
|
||||
extern int __apfs_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned int len, unsigned int copied, struct page *page, void *fsdata);
|
||||
#endif
|
||||
extern int apfs_dstream_adj_refcnt(struct apfs_dstream_info *dstream, u32 delta);
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 12, 0)
|
||||
@@ -1035,7 +1064,9 @@ extern int apfs_setattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, struct iattr *iattr);
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 0, 0)
|
||||
extern int apfs_update_time(struct inode *inode, enum fs_update_time time, unsigned int flags);
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
||||
extern int apfs_update_time(struct inode *inode, struct timespec64 *time, int flags);
|
||||
#else
|
||||
extern int apfs_update_time(struct inode *inode, int flags);
|
||||
@@ -1061,6 +1092,10 @@ extern int apfs_getattr(struct mnt_idmap *idmap,
|
||||
|
||||
extern int apfs_crypto_adj_refcnt(struct super_block *sb, u64 crypto_id, int delta);
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0)
|
||||
#define fileattr file_kattr
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0) || RHEL_VERSION_GE(9, 6)
|
||||
extern int apfs_fileattr_get(struct dentry *dentry, struct fileattr *fa);
|
||||
extern int apfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, struct fileattr *fa);
|
||||
@@ -1207,6 +1242,33 @@ static inline void apfs_assert_query_is_valid(const struct apfs_query *query)
|
||||
#define page_has_buffers(page) folio_buffers(page_folio(page))
|
||||
#endif
|
||||
|
||||
static inline int apfs_inode_state_read_once(struct inode *inode)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 19, 0)
|
||||
return inode_state_read_once(inode);
|
||||
#else
|
||||
return inode->i_state;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void apfs_inode_state_set_raw(struct inode *inode, int flags)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 19, 0)
|
||||
inode_state_set_raw(inode, flags);
|
||||
#else
|
||||
inode->i_state |= flags;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void apfs_inode_state_clear_raw(struct inode *inode, int flags)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 19, 0)
|
||||
inode_state_clear_raw(inode, flags);
|
||||
#else
|
||||
inode->i_state &= ~flags;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: the following are modified variants of buffer head functions that will
|
||||
* work with the shared block device for the container. The correct approach
|
||||
@@ -1285,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);
|
||||
|
||||
@@ -422,7 +422,11 @@ static int apfs_compress_readpage(struct file *filp, struct page *page)
|
||||
loff_t off;
|
||||
|
||||
/* Mostly copied from ext4_read_inline_page() */
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 16, 0)
|
||||
off = page_folio(page)->index << PAGE_SHIFT;
|
||||
#else
|
||||
off = page->index << PAGE_SHIFT;
|
||||
#endif
|
||||
addr = kmap(page);
|
||||
ret = apfs_compress_file_read_page(filp, addr, off);
|
||||
flush_dcache_page(page);
|
||||
|
||||
@@ -261,7 +261,7 @@ const struct file_operations apfs_dir_operations = {
|
||||
*
|
||||
* Returns the length of the key, or a negative error code in case of failure.
|
||||
*/
|
||||
static int apfs_build_dentry_unhashed_key(struct qstr *qname, u64 parent_id,
|
||||
static int apfs_build_dentry_unhashed_key(const struct qstr *qname, u64 parent_id,
|
||||
struct apfs_drec_key **key_p)
|
||||
{
|
||||
struct apfs_drec_key *key;
|
||||
@@ -290,7 +290,7 @@ static int apfs_build_dentry_unhashed_key(struct qstr *qname, u64 parent_id,
|
||||
*
|
||||
* Returns the length of the key, or a negative error code in case of failure.
|
||||
*/
|
||||
static int apfs_build_dentry_hashed_key(struct qstr *qname, u64 hash, u64 parent_id,
|
||||
static int apfs_build_dentry_hashed_key(const struct qstr *qname, u64 hash, u64 parent_id,
|
||||
struct apfs_drec_hashed_key **key_p)
|
||||
{
|
||||
struct apfs_drec_hashed_key *key;
|
||||
@@ -363,7 +363,7 @@ static int apfs_build_dentry_val(struct inode *inode, u64 sibling_id,
|
||||
*
|
||||
* Returns 0 on success or a negative error code in case of failure.
|
||||
*/
|
||||
static int apfs_create_dentry_rec(struct inode *inode, struct qstr *qname,
|
||||
static int apfs_create_dentry_rec(struct inode *inode, const struct qstr *qname,
|
||||
u64 parent_id, u64 sibling_id)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
@@ -426,7 +426,7 @@ static int apfs_build_sibling_val(struct dentry *dentry,
|
||||
struct apfs_sibling_val **val_p)
|
||||
{
|
||||
struct apfs_sibling_val *val;
|
||||
struct qstr *qname = &dentry->d_name;
|
||||
const struct qstr *qname = &dentry->d_name;
|
||||
u16 namelen = qname->len + 1; /* We count the null-termination */
|
||||
struct inode *parent = d_inode(dentry->d_parent);
|
||||
int val_len;
|
||||
@@ -1255,9 +1255,10 @@ static void __apfs_undo_unlink(struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
|
||||
inode->i_state |= I_LINKABLE; /* Silence warning about nlink 0->1 */
|
||||
/* Silence warning about nlink 0->1 */
|
||||
apfs_inode_state_set_raw(inode, I_LINKABLE);
|
||||
inc_nlink(inode);
|
||||
inode->i_state &= ~I_LINKABLE;
|
||||
apfs_inode_state_clear_raw(inode, I_LINKABLE);
|
||||
|
||||
apfs_undo_delete_dentry(dentry);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
PACKAGE_NAME="linux-apfs-rw"
|
||||
PACKAGE_VERSION="0.3.14"
|
||||
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);
|
||||
|
||||
@@ -72,7 +72,11 @@ static vm_fault_t apfs_page_mkwrite(struct vm_fault *vmf)
|
||||
}
|
||||
|
||||
size = i_size_read(inode);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 16, 0)
|
||||
if (page_folio(page)->index == size >> PAGE_SHIFT)
|
||||
#else
|
||||
if (page->index == size >> PAGE_SHIFT)
|
||||
#endif
|
||||
len = size & ~PAGE_MASK;
|
||||
else
|
||||
len = PAGE_SIZE;
|
||||
|
||||
@@ -470,7 +470,11 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0)
|
||||
int __apfs_write_begin(const struct kiocb *file, struct address_space *mapping, loff_t pos, unsigned int len, unsigned int flags, struct page **pagep, void **fsdata)
|
||||
#else
|
||||
int __apfs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned int len, unsigned int flags, struct page **pagep, void **fsdata)
|
||||
#endif
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
struct apfs_dstream_info *dstream = &APFS_I(inode)->i_dstream;
|
||||
@@ -552,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)) {
|
||||
@@ -584,7 +587,11 @@ out_put_page:
|
||||
return err;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0)
|
||||
static int apfs_write_begin(const struct kiocb *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned int len,
|
||||
struct folio **foliop, void **fsdata)
|
||||
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
|
||||
static int apfs_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned int len,
|
||||
struct folio **foliop, void **fsdata)
|
||||
@@ -629,7 +636,11 @@ fail:
|
||||
return err;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0)
|
||||
int __apfs_write_end(const struct kiocb *file, struct address_space *mapping, loff_t pos, unsigned int len, unsigned int copied, struct page *page, void *fsdata)
|
||||
#else
|
||||
int __apfs_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned int len, unsigned int copied, struct page *page, void *fsdata)
|
||||
#endif
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
struct apfs_dstream_info *dstream = &APFS_I(inode)->i_dstream;
|
||||
@@ -652,7 +663,11 @@ int __apfs_write_end(struct file *file, struct address_space *mapping, loff_t po
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0)
|
||||
static int apfs_write_end(const struct kiocb *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned int len, unsigned int copied,
|
||||
struct folio *folio, void *fsdata)
|
||||
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
|
||||
static int apfs_write_end(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned int len, unsigned int copied,
|
||||
struct folio *folio, void *fsdata)
|
||||
@@ -1021,7 +1036,7 @@ struct inode *apfs_iget(struct super_block *sb, u64 cnid)
|
||||
inode = apfs_iget_locked(sb, cnid);
|
||||
if (!inode)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (!(inode->i_state & I_NEW))
|
||||
if (!(apfs_inode_state_read_once(inode) & I_NEW))
|
||||
return inode;
|
||||
|
||||
down_read(&nxi->nx_big_sem);
|
||||
@@ -1133,7 +1148,7 @@ int apfs_getattr(struct mnt_idmap *idmap,
|
||||
*
|
||||
* Returns the length of the value, or a negative error code in case of failure.
|
||||
*/
|
||||
static int apfs_build_inode_val(struct inode *inode, struct qstr *qname,
|
||||
static int apfs_build_inode_val(struct inode *inode, const struct qstr *qname,
|
||||
struct apfs_inode_val **val_p)
|
||||
{
|
||||
struct apfs_inode_val *val;
|
||||
@@ -2093,7 +2108,9 @@ fail:
|
||||
}
|
||||
|
||||
/* TODO: this only seems to be necessary because ->write_inode() isn't firing */
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 0, 0)
|
||||
int apfs_update_time(struct inode *inode, enum fs_update_time time, unsigned int flags)
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
||||
int apfs_update_time(struct inode *inode, struct timespec64 *time, int flags)
|
||||
#else
|
||||
int apfs_update_time(struct inode *inode, int flags)
|
||||
@@ -2107,7 +2124,9 @@ int apfs_update_time(struct inode *inode, int flags)
|
||||
return err;
|
||||
apfs_inode_join_transaction(sb, inode);
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && !RHEL_VERSION_GE(9, 6)
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 0, 0)
|
||||
generic_update_time(inode, time, flags);
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && !RHEL_VERSION_GE(9, 6)
|
||||
generic_update_time(inode, time, flags);
|
||||
#else
|
||||
generic_update_time(inode, flags);
|
||||
|
||||
@@ -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;
|
||||
|
||||
+4
-2
@@ -468,7 +468,7 @@ int apfs_transaction_flush_all_inodes(struct super_block *sb)
|
||||
curr_err = apfs_update_inode(inode, NULL /* new_name */);
|
||||
if (curr_err)
|
||||
err = curr_err;
|
||||
inode->i_state &= ~I_DIRTY_ALL;
|
||||
apfs_inode_state_clear_raw(inode, I_DIRTY_ALL);
|
||||
|
||||
/*
|
||||
* The same inode may get dirtied again as soon as we release
|
||||
@@ -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