FAILED: patch "[PATCH] ocfs2: fix possible deadlock between unlink and" failed to apply to 5.15-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x b02da26a992db0c0e2559acbda0fc48d4a2fd337
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026042002-rumbling-plunder-40f1@gregkh' --subject-prefix 'PATCH 5.15.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From b02da26a992db0c0e2559acbda0fc48d4a2fd337 Mon Sep 17 00:00:00 2001
From: Joseph Qi <[email protected]>
Date: Fri, 6 Mar 2026 11:22:11 +0800
Subject: [PATCH] ocfs2: fix possible deadlock between unlink and
dio_end_io_write
ocfs2_unlink takes orphan dir inode_lock first and then ip_alloc_sem, while in ocfs2_dio_end_io_write, it acquires these locks in reverse order. This creates an ABBA lock ordering violation on lock classes ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE] and ocfs2_file_ip_alloc_sem_key.
Lock Chain #0 (orphan dir inode_lock -> ip_alloc_sem):ocfs2_unlink
ocfs2_prepare_orphan_dir
ocfs2_lookup_lock_orphan_dir
inode_lock(orphan_dir_inode) <- lock A
__ocfs2_prepare_orphan_dir
ocfs2_prepare_dir_for_insert
ocfs2_extend_dir
ocfs2_expand_inline_dir
down_write(&oi->ip_alloc_sem) <- Lock B
Lock Chain #1 (ip_alloc_sem -> orphan dir inode_lock):ocfs2_dio_end_io_write
down_write(&oi->ip_alloc_sem) <- Lock B ocfs2_del_inode_from_orphan()
inode_lock(orphan_dir_inode) <- Lock A
Deadlock Scenario:
CPU0 (unlink) CPU1 (dio_end_io_write)
------ ------
inode_lock(orphan_dir_inode)
down_write(ip_alloc_sem)
down_write(ip_alloc_sem)
inode_lock(orphan_dir_inode)
Since ip_alloc_sem is to protect allocation changes, which is unrelated with operations in ocfs2_del_inode_from_orphan. So move ocfs2_del_inode_from_orphan out of ip_alloc_sem to fix the deadlock.
fs/ocfs2/aops.c +1 -2
@@ -2294,8 +2294,6 @@ static int ocfs2_dio_end_io_write(struct inode *inode, goto out; } -down_write (&oi->ip_alloc_sem); -/* Delete orphan before acquire i_rwsem. */ if (dwc->dw_orphaned) {BUG_ON (dwc->dw_writer_pid !=task_pid_nr (current));
@@ -2308,6 +2306,7 @@ static int ocfs2_dio_end_io_write(struct inode *inode,mlog_errno (ret); } +down_write (&oi->ip_alloc_sem); di = (struct ocfs2_dinode *)di_bh->b_data;ocfs2_init_dinode_extent_tree (&et,INODE_CACHE (inode), di_bh);
Sasha Levin
maintainerPATCH 1/2 fs/ocfs2: fix comments mentioning i_mutex
From: hongnanli <[email protected]>
[ Upstream commit 137cebf9432eae024d0334953ed92a2a78619b52 ]
inode->i_mutex has been replaced with inode->i_rwsem long ago. Fix comments still mentioning i_mutex.
Stable-dep-of: b02da26a992d ("ocfs2: fix possible deadlock between unlink and dio_end_io_write")
--- fs/ocfs2/alloc.c | 2 +- fs/ocfs2/aops.c | 2 +- fs/ocfs2/cluster/nodemanager.c | 2 +- fs/ocfs2/dir.c | 4 ++-- fs/ocfs2/file.c | 4 ++-- fs/ocfs2/inode.c | 2 +- fs/ocfs2/localalloc.c | 6 +++--- fs/ocfs2/namei.c | 2 +- fs/ocfs2/ocfs2.h | 4 ++-- fs/ocfs2/quota_global.c | 2 +- fs/ocfs2/xattr.c | 2 +- 11 files changed, 16 insertions(+), 16 deletions(-)
fs/ocfs2/alloc.c +1 -1
@@ -5986,7 +5986,7 @@ static int ocfs2_replay_truncate_records(struct ocfs2_super *osb,return status; } -/* Expects you to already be holding tl_inode->i_mutex */ +/* Expects you to already be holding tl_inode->i_rwsem */ int __ocfs2_flush_truncate_log (struct ocfs2_super *osb) {int status;
fs/ocfs2/aops.c +1 -1
@@ -2324,7 +2324,7 @@ static int ocfs2_dio_end_io_write(struct inode *inode,down_write (&oi->ip_alloc_sem); -/* Delete orphan before acquire i_mutex. */ +/* Delete orphan before acquire i_rwsem. */ if (dwc->dw_orphaned) {BUG_ON (dwc->dw_writer_pid !=task_pid_nr (current));
fs/ocfs2/cluster/nodemanager.c +1 -1
@@ -689,7 +689,7 @@ static struct config_group *o2nm_cluster_group_make_group(struct config_group *gstruct o2nm_node_group *ns =NULL ;struct config_group *o2hb_group =NULL , *ret =NULL ; -/* this runs under the parent dir's i_mutex; there can be only +/* this runs under the parent dir's i_rwsem; there can be only * one caller in here at a time */ if (o2nm_single_cluster)return ERR_PTR (-ENOSPC );
fs/ocfs2/dir.c +2 -2
@@ -1979,7 +1979,7 @@ int ocfs2_readdir(struct file *file, struct dir_context *ctx) }/* -* NOTE: this should always be called with parent dir i_mutex taken. +* NOTE: this should always be called with parent dir i_rwsem taken. */ int ocfs2_find_files_on_disk(const char *name, int namelen,
@@ -2026,7 +2026,7 @@ int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name,* Return -EEXIST if the directory contains the name * Return -EFSCORRUPTED if found corruption * -* Callers should have i_mutex + a cluster lock on dir +* Callers should have i_rwsem + a cluster lock on dir */ int ocfs2_check_dir_for_entry(struct inode *dir, const char *name,
fs/ocfs2/file.c +2 -2
@@ -270,7 +270,7 @@ int ocfs2_update_inode_atime(struct inode *inode,/* * Don't use ocfs2_mark_inode_dirty() here as we don't always -* have i_mutex to guard against concurrent changes to other +* have i_rwsem to guard against concurrent changes to other * inode fields. */ inode->i_atime =current_time (inode);
@@ -1068,7 +1068,7 @@ static int ocfs2_extend_file(struct inode *inode,/* * The alloc sem blocks people in read/write from reading our * allocation until we're done changing it. We depend on -* i_mutex to block other extend/truncate calls while we're +* i_rwsem to block other extend/truncate calls while we're * here. We even have to hold it for sparse files because there * might be some tail zeroing. */
fs/ocfs2/inode.c +1 -1
@@ -713,7 +713,7 @@ static int ocfs2_remove_inode(struct inode *inode,/* * Serialize with orphan dir recovery. If the process doing * recovery on this orphan dir does an iget() with the dir -* i_mutex held, we'll deadlock here. Instead we detect this +* i_rwsem held, we'll deadlock here. Instead we detect this * and exit early - recovery will wipe this inode for us. */ static int ocfs2_check_orphan_recovery_state(struct ocfs2_super *osb,
fs/ocfs2/localalloc.c +3 -3
@@ -606,7 +606,7 @@ int ocfs2_complete_local_alloc_recovery(struct ocfs2_super *osb,/* * make sure we've got at least bits_wanted contiguous bits in the -* local alloc. You lose them when you drop i_mutex. +* local alloc. You lose them when you drop i_rwsem. * * We will add ourselves to the transaction passed in, but may start * our own in order to shift windows.
@@ -636,7 +636,7 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,/* * We must double check state and allocator bits because -* another process may have changed them while holding i_mutex. +* another process may have changed them while holding i_rwsem. */ spin_lock (&osb->osb_lock); if (!ocfs2_la_state_enabled(osb) ||
@@ -1029,7 +1029,7 @@ enum ocfs2_la_event {/* * Given an event, calculate the size of our next local alloc window. * -* This should always be called under i_mutex of the local alloc inode +* This should always be called under i_rwsem of the local alloc inode * so that local alloc disabling doesn't race with processes trying to * use the allocator. *
fs/ocfs2/namei.c +1 -1
@@ -485,7 +485,7 @@ static int ocfs2_mknod(struct user_namespace *mnt_userns,ocfs2_free_alloc_context (meta_ac);/* -* We should call iput after the i_mutex of the bitmap been +* We should call iput after the i_rwsem of the bitmap been * unlocked in ocfs2_free_alloc_context, or the * ocfs2_delete_inode will mutex_lock again. */
fs/ocfs2/ocfs2.h +2 -2
@@ -369,7 +369,7 @@ struct ocfs2_superstruct delayed_work la_enable_wq;/* -* Must hold local alloc i_mutex and osb->osb_lock to change +* Must hold local alloc i_rwsem and osb->osb_lock to change * local_alloc_bits. Reads can be done under either lock. */ unsigned int local_alloc_bits;
@@ -444,7 +444,7 @@ struct ocfs2_superatomic_t osb_tl_disable;/* * How many clusters in our truncate log. -* It must be protected by osb_tl_inode->i_mutex. +* It must be protected by osb_tl_inode->i_rwsem. */ unsigned int truncated_clusters;
fs/ocfs2/quota_global.c +1 -1
@@ -36,7 +36,7 @@* should be obeyed by all the functions: * - any write of quota structure (either to local or global file) is protected * by dqio_sem or dquot->dq_lock. -* - any modification of global quota file holds inode cluster lock, i_mutex, +* - any modification of global quota file holds inode cluster lock, i_rwsem, * and ip_alloc_sem of the global quota file (achieved by * ocfs2_lock_global_qf). It also has to hold qinfo_lock. * - an allocation of new blocks for local quota file is protected by
fs/ocfs2/xattr.c +1 -1
@@ -7208,7 +7208,7 @@ int ocfs2_reflink_xattrs(struct inode *old_inode,* Used for reflink a non-preserve-security file. * * It uses common api like ocfs2_xattr_set, so the caller -* must not hold any lock expect i_mutex. +* must not hold any lock expect i_rwsem. */ int ocfs2_init_security_and_acl(struct inode *dir, struct inode *inode,
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 ocfs2: fix possible deadlock between unlink and dio_end_io_write
From: Joseph Qi <[email protected]>
[ Upstream commit b02da26a992db0c0e2559acbda0fc48d4a2fd337 ]
ocfs2_unlink takes orphan dir inode_lock first and then ip_alloc_sem, while in ocfs2_dio_end_io_write, it acquires these locks in reverse order. This creates an ABBA lock ordering violation on lock classes ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE] and ocfs2_file_ip_alloc_sem_key.
Lock Chain #0 (orphan dir inode_lock -> ip_alloc_sem):ocfs2_unlink
ocfs2_prepare_orphan_dir
ocfs2_lookup_lock_orphan_dir
inode_lock(orphan_dir_inode) <- lock A
__ocfs2_prepare_orphan_dir
ocfs2_prepare_dir_for_insert
ocfs2_extend_dir
ocfs2_expand_inline_dir
down_write(&oi->ip_alloc_sem) <- Lock B
Lock Chain #1 (ip_alloc_sem -> orphan dir inode_lock):ocfs2_dio_end_io_write
down_write(&oi->ip_alloc_sem) <- Lock B ocfs2_del_inode_from_orphan()
inode_lock(orphan_dir_inode) <- Lock A
Deadlock Scenario:
CPU0 (unlink) CPU1 (dio_end_io_write)
------ ------
inode_lock(orphan_dir_inode)
down_write(ip_alloc_sem)
down_write(ip_alloc_sem)
inode_lock(orphan_dir_inode)
Since ip_alloc_sem is to protect allocation changes, which is unrelated with operations in ocfs2_del_inode_from_orphan. So move ocfs2_del_inode_from_orphan out of ip_alloc_sem to fix the deadlock.
--- fs/ocfs2/aops.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
fs/ocfs2/aops.c +1 -2
@@ -2322,8 +2322,6 @@ static int ocfs2_dio_end_io_write(struct inode *inode, goto out; } -down_write (&oi->ip_alloc_sem); -/* Delete orphan before acquire i_rwsem. */ if (dwc->dw_orphaned) {BUG_ON (dwc->dw_writer_pid !=task_pid_nr (current));
@@ -2336,6 +2334,7 @@ static int ocfs2_dio_end_io_write(struct inode *inode,mlog_errno (ret); } +down_write (&oi->ip_alloc_sem); di = (struct ocfs2_dinode *)di_bh->b_data;ocfs2_init_dinode_extent_tree (&et,INODE_CACHE (inode), di_bh);
Signature · 1 line
2.53.0