]>
Commit | Line | Data |
---|---|---|
7d777456 GKH |
1 | From ae42cce7e825bdc82a8e9c30a87c342d1e364e57 Mon Sep 17 00:00:00 2001 |
2 | From: Dmitry Monakhov <dmonakhov@openvz.org> | |
3 | Date: Sun, 30 May 2010 22:49:54 -0400 | |
4 | Subject: ext4: clean up inode bitmaps manipulation in ext4_free_inode | |
5 | ||
6 | commit d17413c08cd2b1dd2bf2cfdbb0f7b736b2b2b15c upstrea (as of v2..34-git13) | |
7 | ||
8 | - Reorganize locking scheme to batch two atomic operation in to one. | |
9 | This also allow us to state what healthy group must obey following rule | |
10 | ext4_free_inodes_count(sb, gdp) == ext4_count_free(inode_bitmap, NUM); | |
11 | - Fix possible undefined pointer dereference. | |
12 | - Even if group descriptor stats aren't accessible we have to update | |
13 | inode bitmaps. | |
14 | - Move non-group members update out of group_lock. | |
15 | ||
16 | Note: this commit has been observed to fix fs corruption problems | |
17 | under heavy fs load | |
18 | ||
19 | Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org> | |
20 | Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> | |
21 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
22 | --- | |
23 | fs/ext4/ialloc.c | 85 +++++++++++++++++++++++++------------------------------ | |
24 | 1 file changed, 39 insertions(+), 46 deletions(-) | |
25 | ||
26 | --- a/fs/ext4/ialloc.c | |
27 | +++ b/fs/ext4/ialloc.c | |
28 | @@ -244,57 +244,50 @@ void ext4_free_inode(handle_t *handle, s | |
29 | if (fatal) | |
30 | goto error_return; | |
31 | ||
32 | - /* Ok, now we can actually update the inode bitmaps.. */ | |
33 | - cleared = ext4_clear_bit_atomic(ext4_group_lock_ptr(sb, block_group), | |
34 | - bit, bitmap_bh->b_data); | |
35 | - if (!cleared) | |
36 | - ext4_error(sb, "ext4_free_inode", | |
37 | - "bit already cleared for inode %lu", ino); | |
38 | - else { | |
39 | - gdp = ext4_get_group_desc(sb, block_group, &bh2); | |
40 | - | |
41 | + fatal = -ESRCH; | |
42 | + gdp = ext4_get_group_desc(sb, block_group, &bh2); | |
43 | + if (gdp) { | |
44 | BUFFER_TRACE(bh2, "get_write_access"); | |
45 | fatal = ext4_journal_get_write_access(handle, bh2); | |
46 | - if (fatal) goto error_return; | |
47 | - | |
48 | - if (gdp) { | |
49 | - ext4_lock_group(sb, block_group); | |
50 | - count = ext4_free_inodes_count(sb, gdp) + 1; | |
51 | - ext4_free_inodes_set(sb, gdp, count); | |
52 | - if (is_directory) { | |
53 | - count = ext4_used_dirs_count(sb, gdp) - 1; | |
54 | - ext4_used_dirs_set(sb, gdp, count); | |
55 | - if (sbi->s_log_groups_per_flex) { | |
56 | - ext4_group_t f; | |
57 | - | |
58 | - f = ext4_flex_group(sbi, block_group); | |
59 | - atomic_dec(&sbi->s_flex_groups[f].used_dirs); | |
60 | - } | |
61 | - | |
62 | - } | |
63 | - gdp->bg_checksum = ext4_group_desc_csum(sbi, | |
64 | - block_group, gdp); | |
65 | - ext4_unlock_group(sb, block_group); | |
66 | - percpu_counter_inc(&sbi->s_freeinodes_counter); | |
67 | - if (is_directory) | |
68 | - percpu_counter_dec(&sbi->s_dirs_counter); | |
69 | + } | |
70 | + ext4_lock_group(sb, block_group); | |
71 | + cleared = ext4_clear_bit(bit, bitmap_bh->b_data); | |
72 | + if (fatal || !cleared) { | |
73 | + ext4_unlock_group(sb, block_group); | |
74 | + goto out; | |
75 | + } | |
76 | ||
77 | - if (sbi->s_log_groups_per_flex) { | |
78 | - ext4_group_t f; | |
79 | + count = ext4_free_inodes_count(sb, gdp) + 1; | |
80 | + ext4_free_inodes_set(sb, gdp, count); | |
81 | + if (is_directory) { | |
82 | + count = ext4_used_dirs_count(sb, gdp) - 1; | |
83 | + ext4_used_dirs_set(sb, gdp, count); | |
84 | + percpu_counter_dec(&sbi->s_dirs_counter); | |
85 | + } | |
86 | + gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp); | |
87 | + ext4_unlock_group(sb, block_group); | |
88 | ||
89 | - f = ext4_flex_group(sbi, block_group); | |
90 | - atomic_inc(&sbi->s_flex_groups[f].free_inodes); | |
91 | - } | |
92 | - } | |
93 | - BUFFER_TRACE(bh2, "call ext4_handle_dirty_metadata"); | |
94 | - err = ext4_handle_dirty_metadata(handle, NULL, bh2); | |
95 | - if (!fatal) fatal = err; | |
96 | + percpu_counter_inc(&sbi->s_freeinodes_counter); | |
97 | + if (sbi->s_log_groups_per_flex) { | |
98 | + ext4_group_t f = ext4_flex_group(sbi, block_group); | |
99 | + | |
100 | + atomic_inc(&sbi->s_flex_groups[f].free_inodes); | |
101 | + if (is_directory) | |
102 | + atomic_dec(&sbi->s_flex_groups[f].used_dirs); | |
103 | } | |
104 | - BUFFER_TRACE(bitmap_bh, "call ext4_handle_dirty_metadata"); | |
105 | - err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); | |
106 | - if (!fatal) | |
107 | - fatal = err; | |
108 | - sb->s_dirt = 1; | |
109 | + BUFFER_TRACE(bh2, "call ext4_handle_dirty_metadata"); | |
110 | + fatal = ext4_handle_dirty_metadata(handle, NULL, bh2); | |
111 | +out: | |
112 | + if (cleared) { | |
113 | + BUFFER_TRACE(bitmap_bh, "call ext4_handle_dirty_metadata"); | |
114 | + err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); | |
115 | + if (!fatal) | |
116 | + fatal = err; | |
117 | + sb->s_dirt = 1; | |
118 | + } else | |
119 | + ext4_error(sb, "ext4_free_inode", | |
120 | + "bit already cleared for inode %lu", ino); | |
121 | + | |
122 | error_return: | |
123 | brelse(bitmap_bh); | |
124 | ext4_std_error(sb, fatal); |