aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/Makefile4
-rw-r--r--fs/ext4/block_validity.c244
-rw-r--r--fs/ext4/ext4.h11
-rw-r--r--fs/ext4/extents.c22
-rw-r--r--fs/ext4/inode.c47
-rw-r--r--fs/ext4/mballoc.c11
-rw-r--r--fs/ext4/super.c32
7 files changed, 332 insertions, 39 deletions
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index a8ff003a00f7..8a34710ecf40 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -5,8 +5,8 @@
5obj-$(CONFIG_EXT4_FS) += ext4.o 5obj-$(CONFIG_EXT4_FS) += ext4.o
6 6
7ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ 7ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
8 ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \ 8 ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \
9 ext4_jbd2.o migrate.o mballoc.o 9 ext4_jbd2.o migrate.o mballoc.o block_validity.o
10 10
11ext4-$(CONFIG_EXT4_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o 11ext4-$(CONFIG_EXT4_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
12ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o 12ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o
diff --git a/fs/ext4/block_validity.c b/fs/ext4/block_validity.c
new file mode 100644
index 000000000000..50784ef07563
--- /dev/null
+++ b/fs/ext4/block_validity.c
@@ -0,0 +1,244 @@
1/*
2 * linux/fs/ext4/block_validity.c
3 *
4 * Copyright (C) 2009
5 * Theodore Ts'o (tytso@mit.edu)
6 *
7 * Track which blocks in the filesystem are metadata blocks that
8 * should never be used as data blocks by files or directories.
9 */
10
11#include <linux/time.h>
12#include <linux/fs.h>
13#include <linux/namei.h>
14#include <linux/quotaops.h>
15#include <linux/buffer_head.h>
16#include <linux/module.h>
17#include <linux/swap.h>
18#include <linux/pagemap.h>
19#include <linux/version.h>
20#include <linux/blkdev.h>
21#include <linux/mutex.h>
22#include "ext4.h"
23
24struct ext4_system_zone {
25 struct rb_node node;
26 ext4_fsblk_t start_blk;
27 unsigned int count;
28};
29
30static struct kmem_cache *ext4_system_zone_cachep;
31
32int __init init_ext4_system_zone(void)
33{
34 ext4_system_zone_cachep = KMEM_CACHE(ext4_system_zone,
35 SLAB_RECLAIM_ACCOUNT);
36 if (ext4_system_zone_cachep == NULL)
37 return -ENOMEM;
38 return 0;
39}
40
41void exit_ext4_system_zone(void)
42{
43 kmem_cache_destroy(ext4_system_zone_cachep);
44}
45
46static inline int can_merge(struct ext4_system_zone *entry1,
47 struct ext4_system_zone *entry2)
48{
49 if ((entry1->start_blk + entry1->count) == entry2->start_blk)
50 return 1;
51 return 0;
52}
53
54/*
55 * Mark a range of blocks as belonging to the "system zone" --- that
56 * is, filesystem metadata blocks which should never be used by
57 * inodes.
58 */
59static int add_system_zone(struct ext4_sb_info *sbi,
60 ext4_fsblk_t start_blk,
61 unsigned int count)
62{
63 struct ext4_system_zone *new_entry = NULL, *entry;
64 struct rb_node **n = &sbi->system_blks.rb_node, *node;
65 struct rb_node *parent = NULL, *new_node = NULL;
66
67 while (*n) {
68 parent = *n;
69 entry = rb_entry(parent, struct ext4_system_zone, node);
70 if (start_blk < entry->start_blk)
71 n = &(*n)->rb_left;
72 else if (start_blk >= (entry->start_blk + entry->count))
73 n = &(*n)->rb_right;
74 else {
75 if (start_blk + count > (entry->start_blk +
76 entry->count))
77 entry->count = (start_blk + count -
78 entry->start_blk);
79 new_node = *n;
80 new_entry = rb_entry(new_node, struct ext4_system_zone,
81 node);
82 break;
83 }
84 }
85
86 if (!new_entry) {
87 new_entry = kmem_cache_alloc(ext4_system_zone_cachep,
88 GFP_KERNEL);
89 if (!new_entry)
90 return -ENOMEM;
91 new_entry->start_blk = start_blk;
92 new_entry->count = count;
93 new_node = &new_entry->node;
94
95 rb_link_node(new_node, parent, n);
96 rb_insert_color(new_node, &sbi->system_blks);
97 }
98
99 /* Can we merge to the left? */
100 node = rb_prev(new_node);
101 if (node) {
102 entry = rb_entry(node, struct ext4_system_zone, node);
103 if (can_merge(entry, new_entry)) {
104 new_entry->start_blk = entry->start_blk;
105 new_entry->count += entry->count;
106 rb_erase(node, &sbi->system_blks);
107 kmem_cache_free(ext4_system_zone_cachep, entry);
108 }
109 }
110
111 /* Can we merge to the right? */
112 node = rb_next(new_node);
113 if (node) {
114 entry = rb_entry(node, struct ext4_system_zone, node);
115 if (can_merge(new_entry, entry)) {
116 new_entry->count += entry->count;
117 rb_erase(node, &sbi->system_blks);
118 kmem_cache_free(ext4_system_zone_cachep, entry);
119 }
120 }
121 return 0;
122}
123
124static void debug_print_tree(struct ext4_sb_info *sbi)
125{
126 struct rb_node *node;
127 struct ext4_system_zone *entry;
128 int first = 1;
129
130 printk(KERN_INFO "System zones: ");
131 node = rb_first(&sbi->system_blks);
132 while (node) {
133 entry = rb_entry(node, struct ext4_system_zone, node);
134 printk("%s%llu-%llu", first ? "" : ", ",
135 entry->start_blk, entry->start_blk + entry->count - 1);
136 first = 0;
137 node = rb_next(node);
138 }
139 printk("\n");
140}
141
142int ext4_setup_system_zone(struct super_block *sb)
143{
144 ext4_group_t ngroups = ext4_get_groups_count(sb);
145 struct ext4_sb_info *sbi = EXT4_SB(sb);
146 struct ext4_group_desc *gdp;
147 ext4_group_t i;
148 int flex_size = ext4_flex_bg_size(sbi);
149 int ret;
150
151 if (!test_opt(sb, BLOCK_VALIDITY)) {
152 if (EXT4_SB(sb)->system_blks.rb_node)
153 ext4_release_system_zone(sb);
154 return 0;
155 }
156 if (EXT4_SB(sb)->system_blks.rb_node)
157 return 0;
158
159 for (i=0; i < ngroups; i++) {
160 if (ext4_bg_has_super(sb, i) &&
161 ((i < 5) || ((i % flex_size) == 0)))
162 add_system_zone(sbi, ext4_group_first_block_no(sb, i),
163 sbi->s_gdb_count + 1);
164 gdp = ext4_get_group_desc(sb, i, NULL);
165 ret = add_system_zone(sbi, ext4_block_bitmap(sb, gdp), 1);
166 if (ret)
167 return ret;
168 ret = add_system_zone(sbi, ext4_inode_bitmap(sb, gdp), 1);
169 if (ret)
170 return ret;
171 ret = add_system_zone(sbi, ext4_inode_table(sb, gdp),
172 sbi->s_itb_per_group);
173 if (ret)
174 return ret;
175 }
176
177 if (test_opt(sb, DEBUG))
178 debug_print_tree(EXT4_SB(sb));
179 return 0;
180}
181
182/* Called when the filesystem is unmounted */
183void ext4_release_system_zone(struct super_block *sb)
184{
185 struct rb_node *n = EXT4_SB(sb)->system_blks.rb_node;
186 struct rb_node *parent;
187 struct ext4_system_zone *entry;
188
189 while (n) {
190 /* Do the node's children first */
191 if (n->rb_left) {
192 n = n->rb_left;
193 continue;
194 }
195 if (n->rb_right) {
196 n = n->rb_right;
197 continue;
198 }
199 /*
200 * The node has no children; free it, and then zero
201 * out parent's link to it. Finally go to the
202 * beginning of the loop and try to free the parent
203 * node.
204 */
205 parent = rb_parent(n);
206 entry = rb_entry(n, struct ext4_system_zone, node);
207 kmem_cache_free(ext4_system_zone_cachep, entry);
208 if (!parent)
209 EXT4_SB(sb)->system_blks.rb_node = NULL;
210 else if (parent->rb_left == n)
211 parent->rb_left = NULL;
212 else if (parent->rb_right == n)
213 parent->rb_right = NULL;
214 n = parent;
215 }
216 EXT4_SB(sb)->system_blks.rb_node = NULL;
217}
218
219/*
220 * Returns 1 if the passed-in block region (start_blk,
221 * start_blk+count) is valid; 0 if some part of the block region
222 * overlaps with filesystem metadata blocks.
223 */
224int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk,
225 unsigned int count)
226{
227 struct ext4_system_zone *entry;
228 struct rb_node *n = sbi->system_blks.rb_node;
229
230 if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
231 (start_blk + count > ext4_blocks_count(sbi->s_es)))
232 return 0;
233 while (n) {
234 entry = rb_entry(n, struct ext4_system_zone, node);
235 if (start_blk + count - 1 < entry->start_blk)
236 n = n->rb_left;
237 else if (start_blk >= (entry->start_blk + entry->count))
238 n = n->rb_right;
239 else
240 return 0;
241 }
242 return 1;
243}
244
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index d164f1294e5f..4311cc85b534 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -696,6 +696,7 @@ struct ext4_inode_info {
696#define EXT4_MOUNT_I_VERSION 0x2000000 /* i_version support */ 696#define EXT4_MOUNT_I_VERSION 0x2000000 /* i_version support */
697#define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */ 697#define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */
698#define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */ 698#define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */
699#define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */
699 700
700/* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */ 701/* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */
701#ifndef _LINUX_EXT2_FS_H 702#ifndef _LINUX_EXT2_FS_H
@@ -887,6 +888,7 @@ struct ext4_sb_info {
887 int s_jquota_fmt; /* Format of quota to use */ 888 int s_jquota_fmt; /* Format of quota to use */
888#endif 889#endif
889 unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */ 890 unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */
891 struct rb_root system_blks;
890 892
891#ifdef EXTENTS_STATS 893#ifdef EXTENTS_STATS
892 /* ext4 extents stats */ 894 /* ext4 extents stats */
@@ -1618,6 +1620,15 @@ extern struct dentry *ext4_get_parent(struct dentry *child);
1618extern const struct inode_operations ext4_symlink_inode_operations; 1620extern const struct inode_operations ext4_symlink_inode_operations;
1619extern const struct inode_operations ext4_fast_symlink_inode_operations; 1621extern const struct inode_operations ext4_fast_symlink_inode_operations;
1620 1622
1623/* block_validity */
1624extern void ext4_release_system_zone(struct super_block *sb);
1625extern int ext4_setup_system_zone(struct super_block *sb);
1626extern int __init init_ext4_system_zone(void);
1627extern void exit_ext4_system_zone(void);
1628extern int ext4_data_block_valid(struct ext4_sb_info *sbi,
1629 ext4_fsblk_t start_blk,
1630 unsigned int count);
1631
1621/* extents.c */ 1632/* extents.c */
1622extern int ext4_ext_tree_init(handle_t *handle, struct inode *); 1633extern int ext4_ext_tree_init(handle_t *handle, struct inode *);
1623extern int ext4_ext_writepage_trans_blocks(struct inode *, int); 1634extern int ext4_ext_writepage_trans_blocks(struct inode *, int);
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 27c383c7b43c..d04b779b780e 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -326,32 +326,18 @@ ext4_ext_max_entries(struct inode *inode, int depth)
326 326
327static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext) 327static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext)
328{ 328{
329 ext4_fsblk_t block = ext_pblock(ext), valid_block; 329 ext4_fsblk_t block = ext_pblock(ext);
330 int len = ext4_ext_get_actual_len(ext); 330 int len = ext4_ext_get_actual_len(ext);
331 struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
332 331
333 valid_block = le32_to_cpu(es->s_first_data_block) + 332 return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len);
334 EXT4_SB(inode->i_sb)->s_gdb_count;
335 if (unlikely(block <= valid_block ||
336 ((block + len) > ext4_blocks_count(es))))
337 return 0;
338 else
339 return 1;
340} 333}
341 334
342static int ext4_valid_extent_idx(struct inode *inode, 335static int ext4_valid_extent_idx(struct inode *inode,
343 struct ext4_extent_idx *ext_idx) 336 struct ext4_extent_idx *ext_idx)
344{ 337{
345 ext4_fsblk_t block = idx_pblock(ext_idx), valid_block; 338 ext4_fsblk_t block = idx_pblock(ext_idx);
346 struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
347 339
348 valid_block = le32_to_cpu(es->s_first_data_block) + 340 return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, 1);
349 EXT4_SB(inode->i_sb)->s_gdb_count;
350 if (unlikely(block <= valid_block ||
351 (block >= ext4_blocks_count(es))))
352 return 0;
353 else
354 return 1;
355} 341}
356 342
357static int ext4_valid_extent_entries(struct inode *inode, 343static int ext4_valid_extent_entries(struct inode *inode,
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index d7b7480682b9..dadd3f995db5 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -372,20 +372,21 @@ static int ext4_block_to_path(struct inode *inode,
372} 372}
373 373
374static int __ext4_check_blockref(const char *function, struct inode *inode, 374static int __ext4_check_blockref(const char *function, struct inode *inode,
375 __le32 *p, unsigned int max) { 375 __le32 *p, unsigned int max)
376 376{
377 unsigned int maxblocks = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es);
378 __le32 *bref = p; 377 __le32 *bref = p;
378 unsigned int blk;
379
379 while (bref < p+max) { 380 while (bref < p+max) {
380 if (unlikely(le32_to_cpu(*bref) >= maxblocks)) { 381 blk = le32_to_cpu(*bref++);
382 if (blk &&
383 unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb),
384 blk, 1))) {
381 ext4_error(inode->i_sb, function, 385 ext4_error(inode->i_sb, function,
382 "block reference %u >= max (%u) " 386 "invalid block reference %u "
383 "in inode #%lu, offset=%d", 387 "in inode #%lu", blk, inode->i_ino);
384 le32_to_cpu(*bref), maxblocks,
385 inode->i_ino, (int)(bref-p));
386 return -EIO; 388 return -EIO;
387 } 389 }
388 bref++;
389 } 390 }
390 return 0; 391 return 0;
391} 392}
@@ -1125,6 +1126,21 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used)
1125 ext4_discard_preallocations(inode); 1126 ext4_discard_preallocations(inode);
1126} 1127}
1127 1128
1129static int check_block_validity(struct inode *inode, sector_t logical,
1130 sector_t phys, int len)
1131{
1132 if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), phys, len)) {
1133 ext4_error(inode->i_sb, "check_block_validity",
1134 "inode #%lu logical block %llu mapped to %llu "
1135 "(size %d)", inode->i_ino,
1136 (unsigned long long) logical,
1137 (unsigned long long) phys, len);
1138 WARN_ON(1);
1139 return -EIO;
1140 }
1141 return 0;
1142}
1143
1128/* 1144/*
1129 * The ext4_get_blocks() function tries to look up the requested blocks, 1145 * The ext4_get_blocks() function tries to look up the requested blocks,
1130 * and returns if the blocks are already mapped. 1146 * and returns if the blocks are already mapped.
@@ -1170,6 +1186,13 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
1170 } 1186 }
1171 up_read((&EXT4_I(inode)->i_data_sem)); 1187 up_read((&EXT4_I(inode)->i_data_sem));
1172 1188
1189 if (retval > 0 && buffer_mapped(bh)) {
1190 int ret = check_block_validity(inode, block,
1191 bh->b_blocknr, retval);
1192 if (ret != 0)
1193 return ret;
1194 }
1195
1173 /* If it is only a block(s) look up */ 1196 /* If it is only a block(s) look up */
1174 if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) 1197 if ((flags & EXT4_GET_BLOCKS_CREATE) == 0)
1175 return retval; 1198 return retval;
@@ -1245,6 +1268,12 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
1245 ext4_da_update_reserve_space(inode, retval); 1268 ext4_da_update_reserve_space(inode, retval);
1246 1269
1247 up_write((&EXT4_I(inode)->i_data_sem)); 1270 up_write((&EXT4_I(inode)->i_data_sem));
1271 if (retval > 0 && buffer_mapped(bh)) {
1272 int ret = check_block_validity(inode, block,
1273 bh->b_blocknr, retval);
1274 if (ret != 0)
1275 return ret;
1276 }
1248 return retval; 1277 return retval;
1249} 1278}
1250 1279
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 541bd9adffa2..ed8482e22c0e 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -2961,15 +2961,10 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
2961 + le32_to_cpu(es->s_first_data_block); 2961 + le32_to_cpu(es->s_first_data_block);
2962 2962
2963 len = ac->ac_b_ex.fe_len; 2963 len = ac->ac_b_ex.fe_len;
2964 if (in_range(ext4_block_bitmap(sb, gdp), block, len) || 2964 if (!ext4_data_block_valid(sbi, block, len)) {
2965 in_range(ext4_inode_bitmap(sb, gdp), block, len) ||
2966 in_range(block, ext4_inode_table(sb, gdp),
2967 EXT4_SB(sb)->s_itb_per_group) ||
2968 in_range(block + len - 1, ext4_inode_table(sb, gdp),
2969 EXT4_SB(sb)->s_itb_per_group)) {
2970 ext4_error(sb, __func__, 2965 ext4_error(sb, __func__,
2971 "Allocating block %llu in system zone of %d group\n", 2966 "Allocating blocks %llu-%llu which overlap "
2972 block, ac->ac_b_ex.fe_group); 2967 "fs metadata\n", block, block+len);
2973 /* File system mounted not to panic on error 2968 /* File system mounted not to panic on error
2974 * Fix the bitmap and repeat the block allocation 2969 * Fix the bitmap and repeat the block allocation
2975 * We leak some of the blocks here. 2970 * We leak some of the blocks here.
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index dc34ed3d1327..600b7ad699b5 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -568,6 +568,7 @@ static void ext4_put_super(struct super_block *sb)
568 struct ext4_super_block *es = sbi->s_es; 568 struct ext4_super_block *es = sbi->s_es;
569 int i, err; 569 int i, err;
570 570
571 ext4_release_system_zone(sb);
571 ext4_mb_release(sb); 572 ext4_mb_release(sb);
572 ext4_ext_release(sb); 573 ext4_ext_release(sb);
573 ext4_xattr_put_super(sb); 574 ext4_xattr_put_super(sb);
@@ -1055,6 +1056,7 @@ enum {
1055 Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err, Opt_resize, 1056 Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err, Opt_resize,
1056 Opt_usrquota, Opt_grpquota, Opt_i_version, 1057 Opt_usrquota, Opt_grpquota, Opt_i_version,
1057 Opt_stripe, Opt_delalloc, Opt_nodelalloc, 1058 Opt_stripe, Opt_delalloc, Opt_nodelalloc,
1059 Opt_block_validity, Opt_noblock_validity,
1058 Opt_inode_readahead_blks, Opt_journal_ioprio 1060 Opt_inode_readahead_blks, Opt_journal_ioprio
1059}; 1061};
1060 1062
@@ -1114,6 +1116,8 @@ static const match_table_t tokens = {
1114 {Opt_resize, "resize"}, 1116 {Opt_resize, "resize"},
1115 {Opt_delalloc, "delalloc"}, 1117 {Opt_delalloc, "delalloc"},
1116 {Opt_nodelalloc, "nodelalloc"}, 1118 {Opt_nodelalloc, "nodelalloc"},
1119 {Opt_block_validity, "block_validity"},
1120 {Opt_noblock_validity, "noblock_validity"},
1117 {Opt_inode_readahead_blks, "inode_readahead_blks=%u"}, 1121 {Opt_inode_readahead_blks, "inode_readahead_blks=%u"},
1118 {Opt_journal_ioprio, "journal_ioprio=%u"}, 1122 {Opt_journal_ioprio, "journal_ioprio=%u"},
1119 {Opt_auto_da_alloc, "auto_da_alloc=%u"}, 1123 {Opt_auto_da_alloc, "auto_da_alloc=%u"},
@@ -1508,6 +1512,12 @@ set_qf_format:
1508 case Opt_delalloc: 1512 case Opt_delalloc:
1509 set_opt(sbi->s_mount_opt, DELALLOC); 1513 set_opt(sbi->s_mount_opt, DELALLOC);
1510 break; 1514 break;
1515 case Opt_block_validity:
1516 set_opt(sbi->s_mount_opt, BLOCK_VALIDITY);
1517 break;
1518 case Opt_noblock_validity:
1519 clear_opt(sbi->s_mount_opt, BLOCK_VALIDITY);
1520 break;
1511 case Opt_inode_readahead_blks: 1521 case Opt_inode_readahead_blks:
1512 if (match_int(&args[0], &option)) 1522 if (match_int(&args[0], &option))
1513 return 0; 1523 return 0;
@@ -2826,6 +2836,13 @@ no_journal:
2826 } else if (test_opt(sb, DELALLOC)) 2836 } else if (test_opt(sb, DELALLOC))
2827 printk(KERN_INFO "EXT4-fs: delayed allocation enabled\n"); 2837 printk(KERN_INFO "EXT4-fs: delayed allocation enabled\n");
2828 2838
2839 err = ext4_setup_system_zone(sb);
2840 if (err) {
2841 printk(KERN_ERR "EXT4-fs: failed to initialize system "
2842 "zone (%d)\n", err);
2843 goto failed_mount4;
2844 }
2845
2829 ext4_ext_init(sb); 2846 ext4_ext_init(sb);
2830 err = ext4_mb_init(sb, needs_recovery); 2847 err = ext4_mb_init(sb, needs_recovery);
2831 if (err) { 2848 if (err) {
@@ -2875,6 +2892,7 @@ cantfind_ext4:
2875 2892
2876failed_mount4: 2893failed_mount4:
2877 printk(KERN_ERR "EXT4-fs (device %s): mount failed\n", sb->s_id); 2894 printk(KERN_ERR "EXT4-fs (device %s): mount failed\n", sb->s_id);
2895 ext4_release_system_zone(sb);
2878 if (sbi->s_journal) { 2896 if (sbi->s_journal) {
2879 jbd2_journal_destroy(sbi->s_journal); 2897 jbd2_journal_destroy(sbi->s_journal);
2880 sbi->s_journal = NULL; 2898 sbi->s_journal = NULL;
@@ -3515,6 +3533,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
3515 sb->s_flags &= ~MS_RDONLY; 3533 sb->s_flags &= ~MS_RDONLY;
3516 } 3534 }
3517 } 3535 }
3536 ext4_setup_system_zone(sb);
3518 if (sbi->s_journal == NULL) 3537 if (sbi->s_journal == NULL)
3519 ext4_commit_super(sb, 1); 3538 ext4_commit_super(sb, 1);
3520 3539
@@ -3927,13 +3946,16 @@ static int __init init_ext4_fs(void)
3927{ 3946{
3928 int err; 3947 int err;
3929 3948
3949 err = init_ext4_system_zone();
3950 if (err)
3951 return err;
3930 ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj); 3952 ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj);
3931 if (!ext4_kset) 3953 if (!ext4_kset)
3932 return -ENOMEM; 3954 goto out4;
3933 ext4_proc_root = proc_mkdir("fs/ext4", NULL); 3955 ext4_proc_root = proc_mkdir("fs/ext4", NULL);
3934 err = init_ext4_mballoc(); 3956 err = init_ext4_mballoc();
3935 if (err) 3957 if (err)
3936 return err; 3958 goto out3;
3937 3959
3938 err = init_ext4_xattr(); 3960 err = init_ext4_xattr();
3939 if (err) 3961 if (err)
@@ -3958,6 +3980,11 @@ out1:
3958 exit_ext4_xattr(); 3980 exit_ext4_xattr();
3959out2: 3981out2:
3960 exit_ext4_mballoc(); 3982 exit_ext4_mballoc();
3983out3:
3984 remove_proc_entry("fs/ext4", NULL);
3985 kset_unregister(ext4_kset);
3986out4:
3987 exit_ext4_system_zone();
3961 return err; 3988 return err;
3962} 3989}
3963 3990
@@ -3972,6 +3999,7 @@ static void __exit exit_ext4_fs(void)
3972 exit_ext4_mballoc(); 3999 exit_ext4_mballoc();
3973 remove_proc_entry("fs/ext4", NULL); 4000 remove_proc_entry("fs/ext4", NULL);
3974 kset_unregister(ext4_kset); 4001 kset_unregister(ext4_kset);
4002 exit_ext4_system_zone();
3975} 4003}
3976 4004
3977MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); 4005MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");