Skip to content

Commit 33eb5f4

Browse files
Wengang-oraclesmb49
authored andcommitted
ocfs2: fix deadlock between setattr and dio_end_io_write
BugLink: https://bugs.launchpad.net/bugs/1926489 commit 90bd070 upstream. The following deadlock is detected: truncate -> setattr path is waiting for pending direct IO to be done (inode->i_dio_count become zero) with inode->i_rwsem held (down_write). PID: 14827 TASK: ffff881686a9af80 CPU: 20 COMMAND: "ora_p005_hrltd9" #0 __schedule at ffffffff818667cc #1 schedule at ffffffff81866de6 #2 inode_dio_wait at ffffffff812a2d04 #3 ocfs2_setattr at ffffffffc05f322e [ocfs2] #4 notify_change at ffffffff812a5a09 #5 do_truncate at ffffffff812808f5 #6 do_sys_ftruncate.constprop.18 at ffffffff81280cf2 #7 sys_ftruncate at ffffffff81280d8e #8 do_syscall_64 at ffffffff81003949 #9 entry_SYSCALL_64_after_hwframe at ffffffff81a001ad dio completion path is going to complete one direct IO (decrement inode->i_dio_count), but before that it hung at locking inode->i_rwsem: #0 __schedule+700 at ffffffff818667cc #1 schedule+54 at ffffffff81866de6 #2 rwsem_down_write_failed+536 at ffffffff8186aa28 #3 call_rwsem_down_write_failed+23 at ffffffff8185a1b7 #4 down_write+45 at ffffffff81869c9d #5 ocfs2_dio_end_io_write+180 at ffffffffc05d5444 [ocfs2] #6 ocfs2_dio_end_io+85 at ffffffffc05d5a85 [ocfs2] #7 dio_complete+140 at ffffffff812c873c #8 dio_aio_complete_work+25 at ffffffff812c89f9 #9 process_one_work+361 at ffffffff810b1889 #10 worker_thread+77 at ffffffff810b233d #11 kthread+261 at ffffffff810b7fd5 #12 ret_from_fork+62 at ffffffff81a0035e Thus above forms ABBA deadlock. The same deadlock was mentioned in upstream commit 28f5a8a ("ocfs2: should wait dio before inode lock in ocfs2_setattr()"). It seems that that commit only removed the cluster lock (the victim of above dead lock) from the ABBA deadlock party. End-user visible effects: Process hang in truncate -> ocfs2_setattr path and other processes hang at ocfs2_dio_end_io_write path. This is to fix the deadlock itself. It removes inode_lock() call from dio completion path to remove the deadlock and add ip_alloc_sem lock in setattr path to synchronize the inode modifications. [[email protected]: remove the "had_alloc_lock" as suggested] Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Wengang Wang <[email protected]> Reviewed-by: Joseph Qi <[email protected]> Cc: Mark Fasheh <[email protected]> Cc: Joel Becker <[email protected]> Cc: Junxiao Bi <[email protected]> Cc: Changwei Ge <[email protected]> Cc: Gang He <[email protected]> Cc: Jun Piao <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Kamal Mostafa <[email protected]> Signed-off-by: Stefan Bader <[email protected]>
1 parent b0a93fa commit 33eb5f4

File tree

2 files changed

+7
-12
lines changed

2 files changed

+7
-12
lines changed

fs/ocfs2/aops.c

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2304,7 +2304,7 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
23042304
struct ocfs2_alloc_context *meta_ac = NULL;
23052305
handle_t *handle = NULL;
23062306
loff_t end = offset + bytes;
2307-
int ret = 0, credits = 0, locked = 0;
2307+
int ret = 0, credits = 0;
23082308

23092309
ocfs2_init_dealloc_ctxt(&dealloc);
23102310

@@ -2315,13 +2315,6 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
23152315
!dwc->dw_orphaned)
23162316
goto out;
23172317

2318-
/* ocfs2_file_write_iter will get i_mutex, so we need not lock if we
2319-
* are in that context. */
2320-
if (dwc->dw_writer_pid != task_pid_nr(current)) {
2321-
inode_lock(inode);
2322-
locked = 1;
2323-
}
2324-
23252318
ret = ocfs2_inode_lock(inode, &di_bh, 1);
23262319
if (ret < 0) {
23272320
mlog_errno(ret);
@@ -2402,8 +2395,6 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
24022395
if (meta_ac)
24032396
ocfs2_free_alloc_context(meta_ac);
24042397
ocfs2_run_deallocs(osb, &dealloc);
2405-
if (locked)
2406-
inode_unlock(inode);
24072398
ocfs2_dio_free_write_ctx(inode, dwc);
24082399

24092400
return ret;

fs/ocfs2/file.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,22 +1244,24 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
12441244
goto bail_unlock;
12451245
}
12461246
}
1247+
down_write(&OCFS2_I(inode)->ip_alloc_sem);
12471248
handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS +
12481249
2 * ocfs2_quota_trans_credits(sb));
12491250
if (IS_ERR(handle)) {
12501251
status = PTR_ERR(handle);
12511252
mlog_errno(status);
1252-
goto bail_unlock;
1253+
goto bail_unlock_alloc;
12531254
}
12541255
status = __dquot_transfer(inode, transfer_to);
12551256
if (status < 0)
12561257
goto bail_commit;
12571258
} else {
1259+
down_write(&OCFS2_I(inode)->ip_alloc_sem);
12581260
handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
12591261
if (IS_ERR(handle)) {
12601262
status = PTR_ERR(handle);
12611263
mlog_errno(status);
1262-
goto bail_unlock;
1264+
goto bail_unlock_alloc;
12631265
}
12641266
}
12651267

@@ -1272,6 +1274,8 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
12721274

12731275
bail_commit:
12741276
ocfs2_commit_trans(osb, handle);
1277+
bail_unlock_alloc:
1278+
up_write(&OCFS2_I(inode)->ip_alloc_sem);
12751279
bail_unlock:
12761280
if (status && inode_locked) {
12771281
ocfs2_inode_unlock_tracker(inode, 1, &oh, had_lock);

0 commit comments

Comments
 (0)