]>
Commit | Line | Data |
---|---|---|
40f90573 GKH |
1 | From 90ba983f6889e65a3b506b30dc606aa9d1d46cd2 Mon Sep 17 00:00:00 2001 |
2 | From: Theodore Ts'o <tytso@mit.edu> | |
3 | Date: Mon, 11 Mar 2013 23:39:59 -0400 | |
4 | Subject: ext4: use atomic64_t for the per-flexbg free_clusters count | |
5 | ||
6 | From: Theodore Ts'o <tytso@mit.edu> | |
7 | ||
8 | commit 90ba983f6889e65a3b506b30dc606aa9d1d46cd2 upstream. | |
9 | ||
10 | A user who was using a 8TB+ file system and with a very large flexbg | |
11 | size (> 65536) could cause the atomic_t used in the struct flex_groups | |
12 | to overflow. This was detected by PaX security patchset: | |
13 | ||
14 | http://forums.grsecurity.net/viewtopic.php?f=3&t=3289&p=12551#p12551 | |
15 | ||
16 | This bug was introduced in commit 9f24e4208f7e, so it's been around | |
17 | since 2.6.30. :-( | |
18 | ||
19 | Fix this by using an atomic64_t for struct orlav_stats's | |
20 | free_clusters. | |
21 | ||
22 | Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> | |
23 | Reviewed-by: Lukas Czerner <lczerner@redhat.com> | |
24 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
25 | ||
26 | --- | |
27 | fs/ext4/ext4.h | 6 +++--- | |
28 | fs/ext4/ialloc.c | 4 ++-- | |
29 | fs/ext4/mballoc.c | 12 ++++++------ | |
30 | fs/ext4/resize.c | 4 ++-- | |
31 | fs/ext4/super.c | 4 ++-- | |
32 | 5 files changed, 15 insertions(+), 15 deletions(-) | |
33 | ||
34 | --- a/fs/ext4/ext4.h | |
35 | +++ b/fs/ext4/ext4.h | |
36 | @@ -338,9 +338,9 @@ struct ext4_group_desc | |
37 | */ | |
38 | ||
39 | struct flex_groups { | |
40 | - atomic_t free_inodes; | |
41 | - atomic_t free_clusters; | |
42 | - atomic_t used_dirs; | |
43 | + atomic64_t free_clusters; | |
44 | + atomic_t free_inodes; | |
45 | + atomic_t used_dirs; | |
46 | }; | |
47 | ||
48 | #define EXT4_BG_INODE_UNINIT 0x0001 /* Inode table/bitmap not in use */ | |
49 | --- a/fs/ext4/ialloc.c | |
50 | +++ b/fs/ext4/ialloc.c | |
51 | @@ -324,8 +324,8 @@ error_return: | |
52 | } | |
53 | ||
54 | struct orlov_stats { | |
55 | + __u64 free_clusters; | |
56 | __u32 free_inodes; | |
57 | - __u32 free_clusters; | |
58 | __u32 used_dirs; | |
59 | }; | |
60 | ||
61 | @@ -342,7 +342,7 @@ static void get_orlov_stats(struct super | |
62 | ||
63 | if (flex_size > 1) { | |
64 | stats->free_inodes = atomic_read(&flex_group[g].free_inodes); | |
65 | - stats->free_clusters = atomic_read(&flex_group[g].free_clusters); | |
66 | + stats->free_clusters = atomic64_read(&flex_group[g].free_clusters); | |
67 | stats->used_dirs = atomic_read(&flex_group[g].used_dirs); | |
68 | return; | |
69 | } | |
70 | --- a/fs/ext4/mballoc.c | |
71 | +++ b/fs/ext4/mballoc.c | |
72 | @@ -2829,8 +2829,8 @@ ext4_mb_mark_diskspace_used(struct ext4_ | |
73 | if (sbi->s_log_groups_per_flex) { | |
74 | ext4_group_t flex_group = ext4_flex_group(sbi, | |
75 | ac->ac_b_ex.fe_group); | |
76 | - atomic_sub(ac->ac_b_ex.fe_len, | |
77 | - &sbi->s_flex_groups[flex_group].free_clusters); | |
78 | + atomic64_sub(ac->ac_b_ex.fe_len, | |
79 | + &sbi->s_flex_groups[flex_group].free_clusters); | |
80 | } | |
81 | ||
82 | err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); | |
83 | @@ -4691,8 +4691,8 @@ do_more: | |
84 | ||
85 | if (sbi->s_log_groups_per_flex) { | |
86 | ext4_group_t flex_group = ext4_flex_group(sbi, block_group); | |
87 | - atomic_add(count_clusters, | |
88 | - &sbi->s_flex_groups[flex_group].free_clusters); | |
89 | + atomic64_add(count_clusters, | |
90 | + &sbi->s_flex_groups[flex_group].free_clusters); | |
91 | } | |
92 | ||
93 | ext4_mb_unload_buddy(&e4b); | |
94 | @@ -4836,8 +4836,8 @@ int ext4_group_add_blocks(handle_t *hand | |
95 | ||
96 | if (sbi->s_log_groups_per_flex) { | |
97 | ext4_group_t flex_group = ext4_flex_group(sbi, block_group); | |
98 | - atomic_add(EXT4_NUM_B2C(sbi, blocks_freed), | |
99 | - &sbi->s_flex_groups[flex_group].free_clusters); | |
100 | + atomic64_add(EXT4_NUM_B2C(sbi, blocks_freed), | |
101 | + &sbi->s_flex_groups[flex_group].free_clusters); | |
102 | } | |
103 | ||
104 | ext4_mb_unload_buddy(&e4b); | |
105 | --- a/fs/ext4/resize.c | |
106 | +++ b/fs/ext4/resize.c | |
107 | @@ -1360,8 +1360,8 @@ static void ext4_update_super(struct sup | |
108 | sbi->s_log_groups_per_flex) { | |
109 | ext4_group_t flex_group; | |
110 | flex_group = ext4_flex_group(sbi, group_data[0].group); | |
111 | - atomic_add(EXT4_NUM_B2C(sbi, free_blocks), | |
112 | - &sbi->s_flex_groups[flex_group].free_clusters); | |
113 | + atomic64_add(EXT4_NUM_B2C(sbi, free_blocks), | |
114 | + &sbi->s_flex_groups[flex_group].free_clusters); | |
115 | atomic_add(EXT4_INODES_PER_GROUP(sb) * flex_gd->count, | |
116 | &sbi->s_flex_groups[flex_group].free_inodes); | |
117 | } | |
118 | --- a/fs/ext4/super.c | |
119 | +++ b/fs/ext4/super.c | |
120 | @@ -1979,8 +1979,8 @@ static int ext4_fill_flex_info(struct su | |
121 | flex_group = ext4_flex_group(sbi, i); | |
122 | atomic_add(ext4_free_inodes_count(sb, gdp), | |
123 | &sbi->s_flex_groups[flex_group].free_inodes); | |
124 | - atomic_add(ext4_free_group_clusters(sb, gdp), | |
125 | - &sbi->s_flex_groups[flex_group].free_clusters); | |
126 | + atomic64_add(ext4_free_group_clusters(sb, gdp), | |
127 | + &sbi->s_flex_groups[flex_group].free_clusters); | |
128 | atomic_add(ext4_used_dirs_count(sb, gdp), | |
129 | &sbi->s_flex_groups[flex_group].used_dirs); | |
130 | } |