diff options
| author | Junxiao Bi <junxiao.bi@oracle.com> | 2016-09-19 14:44:21 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-09-19 15:36:17 -0700 | 
| commit | 2b0ad0085aa47ace4756aa501274a7de0325c09c (patch) | |
| tree | 431d2727f92749b9aa6e9b7450ce293a15c3d1da | |
| parent | 31b4beb473e3bdee1bf79db849502dcb24b5c202 (diff) | |
ocfs2: fix trans extend while flush truncate log
Every time, ocfs2_extend_trans() included a credit for truncate log
inode, but as that inode had been managed by jbd2 running transaction
first time, it will not consume that credit until
jbd2_journal_restart().
Since total credits to extend always included the un-consumed ones,
there will be more and more un-consumed credit, at last
jbd2_journal_restart() will fail due to credit number over the half of
max transction credit.
The following error was caught when unlinking a large file with many
extents:
  ------------[ cut here ]------------
  WARNING: CPU: 0 PID: 13626 at fs/jbd2/transaction.c:269 start_this_handle+0x4c3/0x510 [jbd2]()
  Modules linked in: ocfs2 nfsd lockd grace nfs_acl auth_rpcgss sunrpc autofs4 ocfs2_dlmfs ocfs2_stack_o2cb ocfs2_dlm ocfs2_nodemanager ocfs2_stackglue configfs sd_mod sg ip6t_REJECT nf_reject_ipv6 nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables be2iscsi iscsi_boot_sysfs bnx2i cnic uio cxgb4i cxgb4 cxgb3i libcxgbi cxgb3 mdio ib_iser rdma_cm ib_cm iw_cm ib_sa ib_mad ib_core ib_addr ipv6 iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi ppdev xen_kbdfront xen_netfront fb_sys_fops sysimgblt sysfillrect syscopyarea parport_pc parport pcspkr i2c_piix4 i2c_core acpi_cpufreq ext4 jbd2 mbcache xen_blkfront floppy pata_acpi ata_generic ata_piix dm_mirror dm_region_hash dm_log dm_mod
  CPU: 0 PID: 13626 Comm: unlink Tainted: G        W       4.1.12-37.6.3.el6uek.x86_64 #2
  Hardware name: Xen HVM domU, BIOS 4.4.4OVM 02/11/2016
  Call Trace:
    dump_stack+0x48/0x5c
    warn_slowpath_common+0x95/0xe0
    warn_slowpath_null+0x1a/0x20
    start_this_handle+0x4c3/0x510 [jbd2]
    jbd2__journal_restart+0x161/0x1b0 [jbd2]
    jbd2_journal_restart+0x13/0x20 [jbd2]
    ocfs2_extend_trans+0x74/0x220 [ocfs2]
    ocfs2_replay_truncate_records+0x93/0x360 [ocfs2]
    __ocfs2_flush_truncate_log+0x13e/0x3a0 [ocfs2]
    ocfs2_remove_btree_range+0x458/0x7f0 [ocfs2]
    ocfs2_commit_truncate+0x1b3/0x6f0 [ocfs2]
    ocfs2_truncate_for_delete+0xbd/0x380 [ocfs2]
    ocfs2_wipe_inode+0x136/0x6a0 [ocfs2]
    ocfs2_delete_inode+0x2a2/0x3e0 [ocfs2]
    ocfs2_evict_inode+0x28/0x60 [ocfs2]
    evict+0xab/0x1a0
    iput_final+0xf6/0x190
    iput+0xc8/0xe0
    do_unlinkat+0x1b7/0x310
    SyS_unlink+0x16/0x20
    system_call_fastpath+0x12/0x71
  ---[ end trace 28aa7410e69369cf ]---
  JBD2: unlink wants too many credits (251 > 128)
Link: http://lkml.kernel.org/r/1473674623-11810-1-git-send-email-junxiao.bi@oracle.com
Signed-off-by: Junxiao Bi <junxiao.bi@oracle.com>
Reviewed-by: Joseph Qi <joseph.qi@huawei.com>
Cc: Mark Fasheh <mfasheh@suse.de>
Cc: Joel Becker <jlbec@evilplan.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | fs/ocfs2/alloc.c | 29 | 
1 files changed, 10 insertions, 19 deletions
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 7dabbc31060e..51128789a661 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -5922,7 +5922,6 @@ bail:  }  static int ocfs2_replay_truncate_records(struct ocfs2_super *osb, -					 handle_t *handle,  					 struct inode *data_alloc_inode,  					 struct buffer_head *data_alloc_bh)  { @@ -5935,11 +5934,19 @@ static int ocfs2_replay_truncate_records(struct ocfs2_super *osb,  	struct ocfs2_truncate_log *tl;  	struct inode *tl_inode = osb->osb_tl_inode;  	struct buffer_head *tl_bh = osb->osb_tl_bh; +	handle_t *handle;  	di = (struct ocfs2_dinode *) tl_bh->b_data;  	tl = &di->id2.i_dealloc;  	i = le16_to_cpu(tl->tl_used) - 1;  	while (i >= 0) { +		handle = ocfs2_start_trans(osb, OCFS2_TRUNCATE_LOG_FLUSH_ONE_REC); +		if (IS_ERR(handle)) { +			status = PTR_ERR(handle); +			mlog_errno(status); +			goto bail; +		} +  		/* Caller has given us at least enough credits to  		 * update the truncate log dinode */  		status = ocfs2_journal_access_di(handle, INODE_CACHE(tl_inode), tl_bh, @@ -5974,12 +5981,7 @@ static int ocfs2_replay_truncate_records(struct ocfs2_super *osb,  			}  		} -		status = ocfs2_extend_trans(handle, -				OCFS2_TRUNCATE_LOG_FLUSH_ONE_REC); -		if (status < 0) { -			mlog_errno(status); -			goto bail; -		} +		ocfs2_commit_trans(osb, handle);  		i--;  	} @@ -5994,7 +5996,6 @@ int __ocfs2_flush_truncate_log(struct ocfs2_super *osb)  {  	int status;  	unsigned int num_to_flush; -	handle_t *handle;  	struct inode *tl_inode = osb->osb_tl_inode;  	struct inode *data_alloc_inode = NULL;  	struct buffer_head *tl_bh = osb->osb_tl_bh; @@ -6038,21 +6039,11 @@ int __ocfs2_flush_truncate_log(struct ocfs2_super *osb)  		goto out_mutex;  	} -	handle = ocfs2_start_trans(osb, OCFS2_TRUNCATE_LOG_FLUSH_ONE_REC); -	if (IS_ERR(handle)) { -		status = PTR_ERR(handle); -		mlog_errno(status); -		goto out_unlock; -	} - -	status = ocfs2_replay_truncate_records(osb, handle, data_alloc_inode, +	status = ocfs2_replay_truncate_records(osb, data_alloc_inode,  					       data_alloc_bh);  	if (status < 0)  		mlog_errno(status); -	ocfs2_commit_trans(osb, handle); - -out_unlock:  	brelse(data_alloc_bh);  	ocfs2_inode_unlock(data_alloc_inode, 1);  | 
