Skip to content

Commit 2070ad1

Browse files
Eric Rentorvalds
authored andcommitted
ocfs2: retry on ENOSPC if sufficient space in truncate log
The testcase "mmaptruncate" in ocfs2 test suite always fails with ENOSPC error on small volume (say less than 10G). This testcase repeatedly performs "extend" and "truncate" on a file. Continuously, it truncates the file to 1/2 of the size, and then extends to 100% of the size. The main bitmap will quickly run out of space because the "truncate" code prevent truncate log from being flushed by ocfs2_schedule_truncate_log_flush(osb, 1), while truncate log may have cached lots of clusters. So retry to allocate after flushing truncate log when ENOSPC is returned. And we cannot reuse the deleted blocks before the transaction committed. Fortunately, we already have a function to do this - ocfs2_try_to_free_truncate_log(). Just need to remove the "static" modifier and put it into the right place. The "unlock"/"lock" code isn't elegant, but there seems to be no better option. [[email protected]: locking fix] Link: http://lkml.kernel.org/r/[email protected] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Eric Ren <[email protected]> Reviewed-by: Gang He <[email protected]> Reviewed-by: Joseph Qi <[email protected]> Reviewed-by: Mark Fasheh <[email protected]> Cc: Joel Becker <[email protected]> Cc: Junxiao Bi <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 01a36b6 commit 2070ad1

File tree

4 files changed

+58
-38
lines changed

4 files changed

+58
-38
lines changed

fs/ocfs2/alloc.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6106,6 +6106,43 @@ void ocfs2_schedule_truncate_log_flush(struct ocfs2_super *osb,
61066106
}
61076107
}
61086108

6109+
/*
6110+
* Try to flush truncate logs if we can free enough clusters from it.
6111+
* As for return value, "< 0" means error, "0" no space and "1" means
6112+
* we have freed enough spaces and let the caller try to allocate again.
6113+
*/
6114+
int ocfs2_try_to_free_truncate_log(struct ocfs2_super *osb,
6115+
unsigned int needed)
6116+
{
6117+
tid_t target;
6118+
int ret = 0;
6119+
unsigned int truncated_clusters;
6120+
6121+
inode_lock(osb->osb_tl_inode);
6122+
truncated_clusters = osb->truncated_clusters;
6123+
inode_unlock(osb->osb_tl_inode);
6124+
6125+
/*
6126+
* Check whether we can succeed in allocating if we free
6127+
* the truncate log.
6128+
*/
6129+
if (truncated_clusters < needed)
6130+
goto out;
6131+
6132+
ret = ocfs2_flush_truncate_log(osb);
6133+
if (ret) {
6134+
mlog_errno(ret);
6135+
goto out;
6136+
}
6137+
6138+
if (jbd2_journal_start_commit(osb->journal->j_journal, &target)) {
6139+
jbd2_log_wait_commit(osb->journal->j_journal, target);
6140+
ret = 1;
6141+
}
6142+
out:
6143+
return ret;
6144+
}
6145+
61096146
static int ocfs2_get_truncate_log_info(struct ocfs2_super *osb,
61106147
int slot_num,
61116148
struct inode **tl_inode,

fs/ocfs2/alloc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ int ocfs2_truncate_log_append(struct ocfs2_super *osb,
188188
u64 start_blk,
189189
unsigned int num_clusters);
190190
int __ocfs2_flush_truncate_log(struct ocfs2_super *osb);
191+
int ocfs2_try_to_free_truncate_log(struct ocfs2_super *osb,
192+
unsigned int needed);
191193

192194
/*
193195
* Process local structure which describes the block unlinks done

fs/ocfs2/aops.c

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,43 +1645,6 @@ static int ocfs2_zero_tail(struct inode *inode, struct buffer_head *di_bh,
16451645
return ret;
16461646
}
16471647

1648-
/*
1649-
* Try to flush truncate logs if we can free enough clusters from it.
1650-
* As for return value, "< 0" means error, "0" no space and "1" means
1651-
* we have freed enough spaces and let the caller try to allocate again.
1652-
*/
1653-
static int ocfs2_try_to_free_truncate_log(struct ocfs2_super *osb,
1654-
unsigned int needed)
1655-
{
1656-
tid_t target;
1657-
int ret = 0;
1658-
unsigned int truncated_clusters;
1659-
1660-
inode_lock(osb->osb_tl_inode);
1661-
truncated_clusters = osb->truncated_clusters;
1662-
inode_unlock(osb->osb_tl_inode);
1663-
1664-
/*
1665-
* Check whether we can succeed in allocating if we free
1666-
* the truncate log.
1667-
*/
1668-
if (truncated_clusters < needed)
1669-
goto out;
1670-
1671-
ret = ocfs2_flush_truncate_log(osb);
1672-
if (ret) {
1673-
mlog_errno(ret);
1674-
goto out;
1675-
}
1676-
1677-
if (jbd2_journal_start_commit(osb->journal->j_journal, &target)) {
1678-
jbd2_log_wait_commit(osb->journal->j_journal, target);
1679-
ret = 1;
1680-
}
1681-
out:
1682-
return ret;
1683-
}
1684-
16851648
int ocfs2_write_begin_nolock(struct address_space *mapping,
16861649
loff_t pos, unsigned len, ocfs2_write_type_t type,
16871650
struct page **pagep, void **fsdata,

fs/ocfs2/suballoc.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1164,7 +1164,8 @@ static int ocfs2_reserve_clusters_with_limit(struct ocfs2_super *osb,
11641164
int flags,
11651165
struct ocfs2_alloc_context **ac)
11661166
{
1167-
int status;
1167+
int status, ret = 0;
1168+
int retried = 0;
11681169

11691170
*ac = kzalloc(sizeof(struct ocfs2_alloc_context), GFP_KERNEL);
11701171
if (!(*ac)) {
@@ -1189,7 +1190,24 @@ static int ocfs2_reserve_clusters_with_limit(struct ocfs2_super *osb,
11891190
}
11901191

11911192
if (status == -ENOSPC) {
1193+
retry:
11921194
status = ocfs2_reserve_cluster_bitmap_bits(osb, *ac);
1195+
/* Retry if there is sufficient space cached in truncate log */
1196+
if (status == -ENOSPC && !retried) {
1197+
retried = 1;
1198+
ocfs2_inode_unlock((*ac)->ac_inode, 1);
1199+
inode_unlock((*ac)->ac_inode);
1200+
1201+
ret = ocfs2_try_to_free_truncate_log(osb, bits_wanted);
1202+
if (ret == 1)
1203+
goto retry;
1204+
1205+
if (ret < 0)
1206+
mlog_errno(ret);
1207+
1208+
inode_lock((*ac)->ac_inode);
1209+
ocfs2_inode_lock((*ac)->ac_inode, NULL, 1);
1210+
}
11931211
if (status < 0) {
11941212
if (status != -ENOSPC)
11951213
mlog_errno(status);

0 commit comments

Comments
 (0)