34 Commits
Author SHA1 Message Date
Ernesto A. Fernández a10279ce66 Plug buffer head leak on submit for the 7.2 kernel
Starting with the 7.2 kernel, buffer heads no longer lose a reference
during the submit-wait procedure. I didn't notice that change, so now I
would expect all buffer heads to be leaking. The fact that I still can't
tell the difference makes me believe, like I mentioned before, that
somehow the kernel is still disposing of the buffer heads. Either way,
fix this.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-08-14 21:35:59 -03:00
Ernesto A. Fernández 7711c4704e Plug buffer head leak for checkpoint mapping block
This is the last of the three leaks discovered by Valgrind in the
userland port. During the loop that writes ephemeral objects to disk,
checkpoint mapping blocks are created and kept around for multiple
iterations until they are full. At that point, the cpm buffer head gets
released and we get a new one. All that looks correct, but no release
happens after the final loop. Fix it.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-08-14 19:41:33 -03:00
Ernesto A. Fernández 9619c53686 Plug leak of ip bitmap buffer head
This is the second bug discovered by valgrind in the userland tool. The
buffer head for the ip bitmap gets nulled after joining the transaction,
but we still hold a reference to it (the transactions takes a new one).
Fix it.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-08-14 19:21:41 -03:00
Ernesto A. Fernández f5b71842e6 Plug checkpoint buffer head leak during mount
Work on the userland port with valgrind has reavealed a number of
longstanding leaks in the kernel driver. For some reason I always
assumed that kmemleak would eventually notice issues with buffer heads,
but it clearly doesn't. This bug in particular must have been around
since the very beginning: all buffer heads for checkpoint descriptor
blocks get leaked during mount.

Since nobody noticed the problem so far, I'm guessing that the kernel
somehow disposes of abandoned buffer heads. Perhaps it has something to
do with the old issue from patch 517dd221df ("Forcefully free buffer
heads on transaction commit")? Either way, fix the leak and get the code
to match the userland port.

One thing to note: before pushing this patch I tried asking Github
Copilot to look for leaks in the super.c file and it spotted the problem
immediately. It seems to have become far more useful since the last time
I tried it, so once I'm done fixing the current crop of leaks I should
try and see what it can find.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-08-14 18:48:48 -03:00
Ernesto A. Fernández 83205caaad Fix build for RHEL 9.8
Kexianliang reports that the build is broken once more for RHEL:

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

Fix it.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-08-12 17:16:00 -03:00
Ernesto A. Fernández 8a37600293 0.3.21
This release adds support for the upcoming 7.2 kernel version.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-08-12 15:42:53 -03:00
Ernesto A. Fernández f0e88ca368 Switch to bh_submit() for kernel 7.2
The build is broken for the 7.2 release candidate. The reason is that
submit_bh() is gone now, replaced with a new bh_submit() that also takes
the I/O end handler as an argument. Adjust apfs_submit_bh() to these
changes.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-07-14 19:38:12 -03:00
Ernesto A. Fernández 96d5614d04 Put macos macro guards around uintmax_t typedef
I've been trying to build the driver for userland lately. Most of the
code can be left as it is as long as I spoof the kernel headers and
everything else that the kernel provides. The one exception is my
uintmax_t typedef, because macos is very determined to provide its own
definition for that type. I guess that makes sense, given that the lzfse
code came from Apple in the first place.

Anyway, none of this is a problem for the driver, but since I want to
keep both codebases identical, put the same macro guards in here.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-06-24 17:41:11 -03:00
Ernesto A. Fernández b2418aaaa7 Clarify the modprobe situation in the README
I notice a lot of traffic to the following issue:

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

Recent distro kernels seem to ship with a built-in libcrc32c, so the
modprobe step described in the README is not necessary and will fail. I
assumed it would be clear to the users that they can just keep going
when that happens, but some of them are being extra careful, which is
probably the right attitude to have when dealing with a filesystem.

Rephrase the README to make it clear that the modprobe step is not
usually needed anymore.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-05-27 16:58:08 -03:00
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
Ernesto A. Fernández f95bcc94c9 0.3.19
This release adds support for the upcoming 7.0 kernel version, with a
patch by Alessio Faina. Aditya Garg also contributes a fix for a build
issue caused by the makefile.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-04-10 17:55:21 -03:00
Ernesto A. Fernández 911bbe1743 Simplify cleanup labels in mount/get_tree()
Reorganize the version check in the out_free_sbi label to better match
the simpler one at out_unmap_super.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-04-03 21:01:11 -03:00
Ernesto A. Fernández 6d54029be9 Unify parse_options() and preparse_options()
Following the previous patch, which made parse_options() always run
right after preparse_options(), merge both functions into one.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-04-03 20:58:00 -03:00
Ernesto A. Fernández 88b36a788e Run parse_options() earlier for kernels < 7.0
Since the mount api conversion, kernel version 7.0 and above parse all
the options at once before moving on to the rest of the mount process.
There is no reason that other kernel versions can't do the same; in fact
that was originally my intention, as explained in the commit message for
af2ee526c0 ("Avoid double parsing of mount options"). So always call
parse_options() right after preparse_options(). The plan is to unify
these functions next.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-04-03 20:26:01 -03:00
Ernesto A. Fernández ef79bb1bee Always call parse_options() with the sb info
Inside parse_options(), some kernel versions retrieve the superblock
info from the vfs superblock, while others retrieve it from the
filesystem context. Instead just pass the info as an argument and
simplify the version checks.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-04-03 20:06:10 -03:00
Ernesto A. Fernández 67eb48bb34 Fix whitespace issues from mount api conversion
I seem to have missed a few whitespace issues during my review of the
recent mount api conversion. Fix them now.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-04-03 19:47:39 -03:00
Ernesto A. Fernández 9aadac614c Get rid of nx_flags variable from parse_options()
At this point, the nx_flags variable only exists to get copied into
s_mount_opt of the superblock. Just work with s_mount_opt directly and
get rid of the goto label.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-04-03 19:44:47 -03:00
Ernesto A. Fernández 1158bd03a6 Use s_mount_opt for all kernel versions
I'm trying to unify mount option processing across kernel versions as
much as possible. Instead of calling parse_options_set_flags() directly
from parse_options() whenever possible, always set the new s_mount_opt
and use it to call parse_options_set_flags() later.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-04-03 19:26:43 -03:00
Ernesto A. Fernández 351c7cf826 Always init s_uid/s_gid inside parse_options()
Move s_uid/s_gid initialization inside parse_options() for all kernel
versions, getting rid of a version check for kernels 7.0 and above.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-04-03 19:09:40 -03:00
Alessio Faina 61672f2caf Add support to kernel 7.0 fs new mount APIs (LP: #2142837) (#114)
As all the in-tree modules has been ported to the new Kernel 7
fs mount API, the old API has been removed.

This patch add the support for the new set of APIs, while
keeping previous kernel support intact.

The code is in review on the Canonical Launchpad bug
https://launchpad.net/bugs/2142837 as well

Signed-off-by: Alessio Faina <alessio.faina@canonical.com>
2026-03-17 13:12:50 -03:00
Aditya Garg 0459ba0998 Rename $(CONFIG) to $(APFS_CONFIG) (#116) 2026-03-12 13:08:09 -03:00
Ernesto A. Fernández 1db8a6d92a 0.3.18
This release adds support for the upcoming 6.19 kernel version.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2026-01-30 18:44:25 -03:00
Ernesto A. Fernández a3bca211bd Don't access inode state directly in 6.19
The build is broken for the 6.19 release candidate:

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

The problem is that the inode i_state field can no longer be accessed
directly. Switch to the new helpers, using a wrapper to keep the code
consistent for all kernel versions.

Note that I always use the *_raw version of the helpers to avoid a lockdep
check that will not pass. I can't tell for sure if this is a bug.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2025-12-30 20:51:14 -03:00
Ernesto A. Fernández de721cd995 0.3.17
This release adds support for the upcoming 6.18 kernel version.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2025-11-26 18:28:54 -03:00
Ernesto A. Fernández 0daf28cef7 Always treat ->d_name as const
The build is broken for the 6.18 release candidate:

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

The problem is that ->d_name has become const, and that qualifier gets
dropped when we pass it around in the driver. Just treat is as const for
all kernel versions.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2025-10-27 22:30:27 -03:00
Ernesto A. Fernández c76aecff25 0.3.16
This release adds support for the upcoming 6.17 kernel version.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2025-09-27 13:17:31 -03:00
Ernesto A. Fernández 714202fefa Set dentry operations in the new way
Once more, the build is still broken for the 6.17 release candidate.
This time the problem is that we are no longer allowed to set s_d_op
directly. Use the new helper instead.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2025-09-16 14:02:10 -03:00
Ernesto A. Fernández 44db9dc02e Fix the apfs_write_begin/end() type for 6.17
The build is still broken for the 6.17 release candidate. The problem is
that ->write_begin() and ->write_end() now take a kiocb struct as the
first argument instead of a file. Add the proper version checks. The
driver does nothing with this argument but pass it along, so continue to
call it "file" to keep the patch simple.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2025-09-16 13:43:22 -03:00
Ernesto A. Fernández aefae5433f Rename "struct fileattr" to "struct file_kattr"
The build is broken for the 6.17 release candidate:

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

Upstream has renamed the fileattr struct to file_kattr, so that needs to
happen here as well. To avoid excessive nesting of version checks, don't
change the actual code and just rewrite it on build time with a macro. I
hope this doesn't cause any trouble in the future...

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2025-09-15 20:15:01 -03:00
Ernesto A. Fernández de4083a506 0.3.15
This release adds support for the upcoming 6.16 kernel version.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2025-07-25 19:27:24 -03:00
Ernesto A. Fernández a3c23dffc3 Don't reference page index in 6.16
The build is broken for the 6.16 release candidate:

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

The problem is that the page struct no longer has a member called
"index". Use folios for this instead.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
2025-07-01 20:45:23 -03:00
13 changed files with 401 additions and 157 deletions

No files matched your search

+2 -2
View File
@@ -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
View File
@@ -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
=====
+67 -5
View File
@@ -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);
+4
View File
@@ -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);
+7 -6
View File
@@ -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 -1
View File
@@ -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"
-2
View File
@@ -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);
+4
View File
@@ -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;
+26 -7
View File
@@ -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);
+2
View File
@@ -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 {
+1
View File
@@ -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;
+276 -130
View File
File diff suppressed because it is too large. Load diff
+4 -2
View File
@@ -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) {