Skip to content

Commit d647c5b

Browse files
zhaohemakpm00
authored andcommitted
ocfs2: split transactions in dio completion to avoid credit exhaustion
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>
1 parent 510a750 commit d647c5b

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
{
@@ -2277,7 +2279,7 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
22772279
struct ocfs2_alloc_context *meta_ac = NULL;
22782280
handle_t *handle = NULL;
22792281
loff_t end = offset + bytes;
2280-
int ret = 0, credits = 0;
2282+
int ret = 0, credits = 0, batch = 0;
22812283

22822284
ocfs2_init_dealloc_ctxt(&dealloc);
22832285

@@ -2294,18 +2296,6 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
22942296
goto out;
22952297
}
22962298

2297-
/* Delete orphan before acquire i_rwsem. */
2298-
if (dwc->dw_orphaned) {
2299-
BUG_ON(dwc->dw_writer_pid != task_pid_nr(current));
2300-
2301-
end = end > i_size_read(inode) ? end : 0;
2302-
2303-
ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh,
2304-
!!end, end);
2305-
if (ret < 0)
2306-
mlog_errno(ret);
2307-
}
2308-
23092299
down_write(&oi->ip_alloc_sem);
23102300
di = (struct ocfs2_dinode *)di_bh->b_data;
23112301

@@ -2326,44 +2316,70 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
23262316

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

2329-
handle = ocfs2_start_trans(osb, credits);
2330-
if (IS_ERR(handle)) {
2331-
ret = PTR_ERR(handle);
2332-
mlog_errno(ret);
2333-
goto unlock;
2334-
}
2335-
ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
2336-
OCFS2_JOURNAL_ACCESS_WRITE);
2337-
if (ret) {
2338-
mlog_errno(ret);
2339-
goto commit;
2340-
}
2341-
23422319
list_for_each_entry(ue, &dwc->dw_zero_list, ue_node) {
2320+
if (!handle) {
2321+
handle = ocfs2_start_trans(osb, credits);
2322+
if (IS_ERR(handle)) {
2323+
ret = PTR_ERR(handle);
2324+
mlog_errno(ret);
2325+
goto unlock;
2326+
}
2327+
ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
2328+
OCFS2_JOURNAL_ACCESS_WRITE);
2329+
if (ret) {
2330+
mlog_errno(ret);
2331+
goto commit;
2332+
}
2333+
}
23432334
ret = ocfs2_assure_trans_credits(handle, credits);
23442335
if (ret < 0) {
23452336
mlog_errno(ret);
2346-
break;
2337+
goto commit;
23472338
}
23482339
ret = ocfs2_mark_extent_written(inode, &et, handle,
23492340
ue->ue_cpos, 1,
23502341
ue->ue_phys,
23512342
meta_ac, &dealloc);
23522343
if (ret < 0) {
23532344
mlog_errno(ret);
2354-
break;
2345+
goto commit;
2346+
}
2347+
2348+
if (++batch == OCFS2_DIO_MARK_EXTENT_BATCH) {
2349+
ocfs2_commit_trans(osb, handle);
2350+
handle = NULL;
2351+
batch = 0;
23552352
}
23562353
}
23572354

23582355
if (end > i_size_read(inode)) {
2356+
if (!handle) {
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+
}
23592364
ret = ocfs2_set_inode_size(handle, inode, di_bh, end);
23602365
if (ret < 0)
23612366
mlog_errno(ret);
23622367
}
2368+
23632369
commit:
2364-
ocfs2_commit_trans(osb, handle);
2370+
if (handle)
2371+
ocfs2_commit_trans(osb, handle);
23652372
unlock:
23662373
up_write(&oi->ip_alloc_sem);
2374+
2375+
/* everything looks good, let's start the cleanup */
2376+
if (!ret && dwc->dw_orphaned) {
2377+
BUG_ON(dwc->dw_writer_pid != task_pid_nr(current));
2378+
2379+
ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh, 0, 0);
2380+
if (ret < 0)
2381+
mlog_errno(ret);
2382+
}
23672383
ocfs2_inode_unlock(inode, 1);
23682384
brelse(di_bh);
23692385
out:

0 commit comments

Comments
 (0)