Re: [syzbot] [hfs?] possible deadlock in hfsplus_file_extend (2)

From: Edward Adam Davis
Date: Mon Nov 11 2024 - 07:39:18 EST


AA lock, move extents_lock out of the hfsplus_file_extend.

#syz test

diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
index 9e1732a2b92a..ec6e9bdfe7b4 100644
--- a/fs/hfsplus/btree.c
+++ b/fs/hfsplus/btree.c
@@ -355,7 +355,9 @@ int hfs_bmap_reserve(struct hfs_btree *tree, int rsvd_nodes)
return 0;

while (tree->free_nodes < rsvd_nodes) {
+ mutex_lock(&hip->extents_lock);
res = hfsplus_file_extend(inode, hfs_bnode_need_zeroout(tree));
+ mutex_unlock(&hip->extents_lock);
if (res)
return res;
hip->phys_size = inode->i_size =
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c
index a6d61685ae79..966252d129bc 100644
--- a/fs/hfsplus/extents.c
+++ b/fs/hfsplus/extents.c
@@ -242,7 +242,9 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
if (iblock > hip->fs_blocks)
return -EIO;
if (ablock >= hip->alloc_blocks) {
+ mutex_lock(&hip->extents_lock);
res = hfsplus_file_extend(inode, false);
+ mutex_unlock(&hip->extents_lock);
if (res)
return res;
}
@@ -455,7 +457,6 @@ int hfsplus_file_extend(struct inode *inode, bool zeroout)
return -ENOSPC;
}

- mutex_lock(&hip->extents_lock);
if (hip->alloc_blocks == hip->first_blocks)
goal = hfsplus_ext_lastblock(hip->first_extents);
else {
@@ -516,11 +517,9 @@ int hfsplus_file_extend(struct inode *inode, bool zeroout)
out:
if (!res) {
hip->alloc_blocks += len;
- mutex_unlock(&hip->extents_lock);
hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY);
return 0;
}
- mutex_unlock(&hip->extents_lock);
return res;

insert_extent:
diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c
index 9a1a93e3888b..a589130e42ea 100644
--- a/fs/hfsplus/xattr.c
+++ b/fs/hfsplus/xattr.c
@@ -191,7 +191,9 @@ static int hfsplus_create_attributes_file(struct super_block *sb)
}

while (hip->alloc_blocks < hip->clump_blocks) {
+ mutex_unlock(&hip->extents_lock);
err = hfsplus_file_extend(attr_file, false);
+ mutex_unlock(&hip->extents_lock);
if (unlikely(err)) {
pr_err("failed to extend attributes file\n");
goto end_attr_file_creation;