Skip to content

Commit 886f97f

Browse files
zhaohemgregkh
authored andcommitted
ocfs2: split transactions in dio completion to avoid credit exhaustion
commit d647c5b upstream. During ocfs2 dio operations, JBD2 may report warnings via following call trace: ocfs2_dio_end_io_write ocfs2_mark_extent_written ocfs2_change_extent_flag ocfs2_split_extent ocfs2_try_to_merge_extent ocfs2_extend_rotate_transaction ocfs2_extend_trans jbd2__journal_restart start_this_handle output: JBD2: kworker/6:2 wants too many credits credits:5450 rsv_credits:0 max:5449 To prevent exceeding the credits limit, modify ocfs2_dio_end_io_write() to handle extents in a batch of transaction. Additionally, relocate ocfs2_del_inode_from_orphan(). The orphan inode should only be removed from the orphan list after the extent tree update is complete. This ensures that if a crash occurs in the middle of extent tree updates, we won't leave stale blocks beyond EOF. This patch also changes the logic for updating the inode size and removing orphan, making it similar to ext4_dio_write_end_io(). Both operations are performed only when everything looks good. Finally, thanks to Jans and Joseph for providing the bug fix prototype and suggestions. Link: https://lkml.kernel.org/r/20260402134328.27334-2-heming.zhao@suse.com Signed-off-by: Heming Zhao <heming.zhao@suse.com> Suggested-by: Jan Kara <jack@suse.cz> Suggested-by: Joseph Qi <joseph.qi@linux.alibaba.com> Reviewed-by: Jan Kara <jack@suse.cz> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 17b399c commit 886f97f

1 file changed

Lines changed: 45 additions & 29 deletions

File tree

fs/ocfs2/aops.c

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
#include "namei.h"
3838
#include "sysfile.h"
3939

40+
#define OCFS2_DIO_MARK_EXTENT_BATCH 200
41+
4042
static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock,
4143
struct buffer_head *bh_result, int create)
4244
{
@@ -2305,7 +2307,7 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
23052307
struct ocfs2_alloc_context *meta_ac = NULL;
23062308
handle_t *handle = NULL;
23072309
loff_t end = offset + bytes;
2308-
int ret = 0, credits = 0;
2310+
int ret = 0, credits = 0, batch = 0;
23092311

23102312
ocfs2_init_dealloc_ctxt(&dealloc);
23112313

@@ -2322,18 +2324,6 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
23222324
goto out;
23232325
}
23242326

2325-
/* Delete orphan before acquire i_rwsem. */
2326-
if (dwc->dw_orphaned) {
2327-
BUG_ON(dwc->dw_writer_pid != task_pid_nr(current));
2328-
2329-
end = end > i_size_read(inode) ? end : 0;
2330-
2331-
ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh,
2332-
!!end, end);
2333-
if (ret < 0)
2334-
mlog_errno(ret);
2335-
}
2336-
23372327
down_write(&oi->ip_alloc_sem);
23382328
di = (struct ocfs2_dinode *)di_bh->b_data;
23392329

@@ -2354,44 +2344,70 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
23542344

23552345
credits = ocfs2_calc_extend_credits(inode->i_sb, &di->id2.i_list);
23562346

2357-
handle = ocfs2_start_trans(osb, credits);
2358-
if (IS_ERR(handle)) {
2359-
ret = PTR_ERR(handle);
2360-
mlog_errno(ret);
2361-
goto unlock;
2362-
}
2363-
ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
2364-
OCFS2_JOURNAL_ACCESS_WRITE);
2365-
if (ret) {
2366-
mlog_errno(ret);
2367-
goto commit;
2368-
}
2369-
23702347
list_for_each_entry(ue, &dwc->dw_zero_list, ue_node) {
2348+
if (!handle) {
2349+
handle = ocfs2_start_trans(osb, credits);
2350+
if (IS_ERR(handle)) {
2351+
ret = PTR_ERR(handle);
2352+
mlog_errno(ret);
2353+
goto unlock;
2354+
}
2355+
ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
2356+
OCFS2_JOURNAL_ACCESS_WRITE);
2357+
if (ret) {
2358+
mlog_errno(ret);
2359+
goto commit;
2360+
}
2361+
}
23712362
ret = ocfs2_assure_trans_credits(handle, credits);
23722363
if (ret < 0) {
23732364
mlog_errno(ret);
2374-
break;
2365+
goto commit;
23752366
}
23762367
ret = ocfs2_mark_extent_written(inode, &et, handle,
23772368
ue->ue_cpos, 1,
23782369
ue->ue_phys,
23792370
meta_ac, &dealloc);
23802371
if (ret < 0) {
23812372
mlog_errno(ret);
2382-
break;
2373+
goto commit;
2374+
}
2375+
2376+
if (++batch == OCFS2_DIO_MARK_EXTENT_BATCH) {
2377+
ocfs2_commit_trans(osb, handle);
2378+
handle = NULL;
2379+
batch = 0;
23832380
}
23842381
}
23852382

23862383
if (end > i_size_read(inode)) {
2384+
if (!handle) {
2385+
handle = ocfs2_start_trans(osb, credits);
2386+
if (IS_ERR(handle)) {
2387+
ret = PTR_ERR(handle);
2388+
mlog_errno(ret);
2389+
goto unlock;
2390+
}
2391+
}
23872392
ret = ocfs2_set_inode_size(handle, inode, di_bh, end);
23882393
if (ret < 0)
23892394
mlog_errno(ret);
23902395
}
2396+
23912397
commit:
2392-
ocfs2_commit_trans(osb, handle);
2398+
if (handle)
2399+
ocfs2_commit_trans(osb, handle);
23932400
unlock:
23942401
up_write(&oi->ip_alloc_sem);
2402+
2403+
/* everything looks good, let's start the cleanup */
2404+
if (!ret && dwc->dw_orphaned) {
2405+
BUG_ON(dwc->dw_writer_pid != task_pid_nr(current));
2406+
2407+
ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh, 0, 0);
2408+
if (ret < 0)
2409+
mlog_errno(ret);
2410+
}
23952411
ocfs2_inode_unlock(inode, 1);
23962412
brelse(di_bh);
23972413
out:

0 commit comments

Comments
 (0)