diff options
author | Younger Liu <younger.liucn@gmail.com> | 2014-04-03 17:47:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-03 19:20:56 -0400 |
commit | db66c71577d525c0cd65e66ff675747565783ba4 (patch) | |
tree | 94744927610c329533bad994055a37d2e2a3b5d1 | |
parent | e228f6439862359f9b26f9d62634e4fce180b54a (diff) |
ocfs2: rollback alloc_dinode counts when ocfs2_block_group_set_bits() failed
After updating alloc_dinode counts in ocfs2_alloc_dinode_update_counts(),
if ocfs2_alloc_dinode_update_bitmap() failed, there is a rare case that
some space may be lost.
So, roll back alloc_dinode counts when ocfs2_block_group_set_bits()
failed.
[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Younger Liu <younger.liucn@gmail.com>
Reviewed-by: 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/move_extents.c | 5 | ||||
-rw-r--r-- | fs/ocfs2/suballoc.c | 25 | ||||
-rw-r--r-- | fs/ocfs2/suballoc.h | 4 |
3 files changed, 32 insertions, 2 deletions
diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c index 3ca939552d9c..599eb4c4c8be 100644 --- a/fs/ocfs2/move_extents.c +++ b/fs/ocfs2/move_extents.c | |||
@@ -691,8 +691,11 @@ static int ocfs2_move_extent(struct ocfs2_move_extents_context *context, | |||
691 | 691 | ||
692 | ret = ocfs2_block_group_set_bits(handle, gb_inode, gd, gd_bh, | 692 | ret = ocfs2_block_group_set_bits(handle, gb_inode, gd, gd_bh, |
693 | goal_bit, len); | 693 | goal_bit, len); |
694 | if (ret) | 694 | if (ret) { |
695 | ocfs2_rollback_alloc_dinode_counts(gb_inode, gb_bh, len, | ||
696 | le16_to_cpu(gd->bg_chain)); | ||
695 | mlog_errno(ret); | 697 | mlog_errno(ret); |
698 | } | ||
696 | 699 | ||
697 | /* | 700 | /* |
698 | * Here we should write the new page out first if we are | 701 | * Here we should write the new page out first if we are |
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 482d6c2a3ea1..94fb1f3d9e62 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c | |||
@@ -1608,6 +1608,21 @@ out: | |||
1608 | return ret; | 1608 | return ret; |
1609 | } | 1609 | } |
1610 | 1610 | ||
1611 | void ocfs2_rollback_alloc_dinode_counts(struct inode *inode, | ||
1612 | struct buffer_head *di_bh, | ||
1613 | u32 num_bits, | ||
1614 | u16 chain) | ||
1615 | { | ||
1616 | u32 tmp_used; | ||
1617 | struct ocfs2_dinode *di = (struct ocfs2_dinode *) di_bh->b_data; | ||
1618 | struct ocfs2_chain_list *cl; | ||
1619 | |||
1620 | cl = (struct ocfs2_chain_list *)&di->id2.i_chain; | ||
1621 | tmp_used = le32_to_cpu(di->id1.bitmap1.i_used); | ||
1622 | di->id1.bitmap1.i_used = cpu_to_le32(tmp_used - num_bits); | ||
1623 | le32_add_cpu(&cl->cl_recs[chain].c_free, num_bits); | ||
1624 | } | ||
1625 | |||
1611 | static int ocfs2_bg_discontig_fix_by_rec(struct ocfs2_suballoc_result *res, | 1626 | static int ocfs2_bg_discontig_fix_by_rec(struct ocfs2_suballoc_result *res, |
1612 | struct ocfs2_extent_rec *rec, | 1627 | struct ocfs2_extent_rec *rec, |
1613 | struct ocfs2_chain_list *cl) | 1628 | struct ocfs2_chain_list *cl) |
@@ -1708,8 +1723,12 @@ static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac, | |||
1708 | 1723 | ||
1709 | ret = ocfs2_block_group_set_bits(handle, alloc_inode, gd, group_bh, | 1724 | ret = ocfs2_block_group_set_bits(handle, alloc_inode, gd, group_bh, |
1710 | res->sr_bit_offset, res->sr_bits); | 1725 | res->sr_bit_offset, res->sr_bits); |
1711 | if (ret < 0) | 1726 | if (ret < 0) { |
1727 | ocfs2_rollback_alloc_dinode_counts(alloc_inode, ac->ac_bh, | ||
1728 | res->sr_bits, | ||
1729 | le16_to_cpu(gd->bg_chain)); | ||
1712 | mlog_errno(ret); | 1730 | mlog_errno(ret); |
1731 | } | ||
1713 | 1732 | ||
1714 | out_loc_only: | 1733 | out_loc_only: |
1715 | *bits_left = le16_to_cpu(gd->bg_free_bits_count); | 1734 | *bits_left = le16_to_cpu(gd->bg_free_bits_count); |
@@ -1839,6 +1858,8 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, | |||
1839 | res->sr_bit_offset, | 1858 | res->sr_bit_offset, |
1840 | res->sr_bits); | 1859 | res->sr_bits); |
1841 | if (status < 0) { | 1860 | if (status < 0) { |
1861 | ocfs2_rollback_alloc_dinode_counts(alloc_inode, | ||
1862 | ac->ac_bh, res->sr_bits, chain); | ||
1842 | mlog_errno(status); | 1863 | mlog_errno(status); |
1843 | goto bail; | 1864 | goto bail; |
1844 | } | 1865 | } |
@@ -2150,6 +2171,8 @@ int ocfs2_claim_new_inode_at_loc(handle_t *handle, | |||
2150 | res->sr_bit_offset, | 2171 | res->sr_bit_offset, |
2151 | res->sr_bits); | 2172 | res->sr_bits); |
2152 | if (ret < 0) { | 2173 | if (ret < 0) { |
2174 | ocfs2_rollback_alloc_dinode_counts(ac->ac_inode, | ||
2175 | ac->ac_bh, res->sr_bits, chain); | ||
2153 | mlog_errno(ret); | 2176 | mlog_errno(ret); |
2154 | goto out; | 2177 | goto out; |
2155 | } | 2178 | } |
diff --git a/fs/ocfs2/suballoc.h b/fs/ocfs2/suballoc.h index 218d8036b3e7..2d2501767c0c 100644 --- a/fs/ocfs2/suballoc.h +++ b/fs/ocfs2/suballoc.h | |||
@@ -91,6 +91,10 @@ int ocfs2_alloc_dinode_update_counts(struct inode *inode, | |||
91 | struct buffer_head *di_bh, | 91 | struct buffer_head *di_bh, |
92 | u32 num_bits, | 92 | u32 num_bits, |
93 | u16 chain); | 93 | u16 chain); |
94 | void ocfs2_rollback_alloc_dinode_counts(struct inode *inode, | ||
95 | struct buffer_head *di_bh, | ||
96 | u32 num_bits, | ||
97 | u16 chain); | ||
94 | int ocfs2_block_group_set_bits(handle_t *handle, | 98 | int ocfs2_block_group_set_bits(handle_t *handle, |
95 | struct inode *alloc_inode, | 99 | struct inode *alloc_inode, |
96 | struct ocfs2_group_desc *bg, | 100 | struct ocfs2_group_desc *bg, |