hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/fs/ext4/block_validity.c
....@@ -126,10 +126,13 @@
126126 {
127127 struct rb_node *node;
128128 struct ext4_system_zone *entry;
129
+ struct ext4_system_blocks *system_blks;
129130 int first = 1;
130131
131132 printk(KERN_INFO "System zones: ");
132
- node = rb_first(&sbi->system_blks->root);
133
+ rcu_read_lock();
134
+ system_blks = rcu_dereference(sbi->s_system_blks);
135
+ node = rb_first(&system_blks->root);
133136 while (node) {
134137 entry = rb_entry(node, struct ext4_system_zone, node);
135138 printk(KERN_CONT "%s%llu-%llu", first ? "" : ", ",
....@@ -137,47 +140,8 @@
137140 first = 0;
138141 node = rb_next(node);
139142 }
143
+ rcu_read_unlock();
140144 printk(KERN_CONT "\n");
141
-}
142
-
143
-/*
144
- * Returns 1 if the passed-in block region (start_blk,
145
- * start_blk+count) is valid; 0 if some part of the block region
146
- * overlaps with filesystem metadata blocks.
147
- */
148
-static int ext4_data_block_valid_rcu(struct ext4_sb_info *sbi,
149
- struct ext4_system_blocks *system_blks,
150
- ext4_fsblk_t start_blk,
151
- unsigned int count, ino_t ino)
152
-{
153
- struct ext4_system_zone *entry;
154
- struct rb_node *n;
155
-
156
- if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
157
- (start_blk + count < start_blk) ||
158
- (start_blk + count > ext4_blocks_count(sbi->s_es))) {
159
- sbi->s_es->s_last_error_block = cpu_to_le64(start_blk);
160
- return 0;
161
- }
162
-
163
- if (system_blks == NULL)
164
- return 1;
165
-
166
- n = system_blks->root.rb_node;
167
- while (n) {
168
- entry = rb_entry(n, struct ext4_system_zone, node);
169
- if (start_blk + count - 1 < entry->start_blk)
170
- n = n->rb_left;
171
- else if (start_blk >= (entry->start_blk + entry->count))
172
- n = n->rb_right;
173
- else {
174
- if (entry->ino == ino)
175
- return 1;
176
- sbi->s_es->s_last_error_block = cpu_to_le64(start_blk);
177
- return 0;
178
- }
179
- }
180
- return 1;
181145 }
182146
183147 static int ext4_protect_reserved_inode(struct super_block *sb,
....@@ -212,10 +176,12 @@
212176 err = add_system_zone(system_blks, map.m_pblk, n, ino);
213177 if (err < 0) {
214178 if (err == -EFSCORRUPTED) {
215
- ext4_error(sb,
216
- "blocks %llu-%llu from inode %u "
217
- "overlap system zone", map.m_pblk,
218
- map.m_pblk + map.m_len - 1, ino);
179
+ __ext4_error(sb, __func__, __LINE__,
180
+ -err, map.m_pblk,
181
+ "blocks %llu-%llu from inode %u overlap system zone",
182
+ map.m_pblk,
183
+ map.m_pblk + map.m_len - 1,
184
+ ino);
219185 }
220186 break;
221187 }
....@@ -251,7 +217,6 @@
251217 struct ext4_system_blocks *system_blks;
252218 struct ext4_group_desc *gdp;
253219 ext4_group_t i;
254
- int flex_size = ext4_flex_bg_size(sbi);
255220 int ret;
256221
257222 system_blks = kzalloc(sizeof(*system_blks), GFP_KERNEL);
....@@ -259,11 +224,16 @@
259224 return -ENOMEM;
260225
261226 for (i=0; i < ngroups; i++) {
262
- if (ext4_bg_has_super(sb, i) &&
263
- ((i < 5) || ((i % flex_size) == 0)))
264
- add_system_zone(system_blks,
227
+ unsigned int meta_blks = ext4_num_base_meta_blocks(sb, i);
228
+
229
+ cond_resched();
230
+ if (meta_blks != 0) {
231
+ ret = add_system_zone(system_blks,
265232 ext4_group_first_block_no(sb, i),
266
- ext4_bg_num_gdb(sb, i) + 1, 0);
233
+ meta_blks, 0);
234
+ if (ret)
235
+ goto err;
236
+ }
267237 gdp = ext4_get_group_desc(sb, i, NULL);
268238 ret = add_system_zone(system_blks,
269239 ext4_block_bitmap(sb, gdp), 1, 0);
....@@ -291,7 +261,7 @@
291261 * with ext4_data_block_valid() accessing the rbtree at the same
292262 * time.
293263 */
294
- rcu_assign_pointer(sbi->system_blks, system_blks);
264
+ rcu_assign_pointer(sbi->s_system_blks, system_blks);
295265
296266 if (test_opt(sb, DEBUG))
297267 debug_print_tree(sbi);
....@@ -316,19 +286,27 @@
316286 {
317287 struct ext4_system_blocks *system_blks;
318288
319
- system_blks = rcu_dereference_protected(EXT4_SB(sb)->system_blks,
289
+ system_blks = rcu_dereference_protected(EXT4_SB(sb)->s_system_blks,
320290 lockdep_is_held(&sb->s_umount));
321
- rcu_assign_pointer(EXT4_SB(sb)->system_blks, NULL);
291
+ rcu_assign_pointer(EXT4_SB(sb)->s_system_blks, NULL);
322292
323293 if (system_blks)
324294 call_rcu(&system_blks->rcu, ext4_destroy_system_zone);
325295 }
326296
327
-int ext4_inode_block_valid(struct inode *inode, ext4_fsblk_t start_blk,
328
- unsigned int count)
297
+int ext4_sb_block_valid(struct super_block *sb, struct inode *inode,
298
+ ext4_fsblk_t start_blk, unsigned int count)
329299 {
300
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
330301 struct ext4_system_blocks *system_blks;
331
- int ret;
302
+ struct ext4_system_zone *entry;
303
+ struct rb_node *n;
304
+ int ret = 1;
305
+
306
+ if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
307
+ (start_blk + count < start_blk) ||
308
+ (start_blk + count > ext4_blocks_count(sbi->s_es)))
309
+ return 0;
332310
333311 /*
334312 * Lock the system zone to prevent it being released concurrently
....@@ -336,17 +314,43 @@
336314 * mount option.
337315 */
338316 rcu_read_lock();
339
- system_blks = rcu_dereference(EXT4_SB(inode->i_sb)->system_blks);
340
- ret = ext4_data_block_valid_rcu(EXT4_SB(inode->i_sb), system_blks,
341
- start_blk, count, inode->i_ino);
317
+ system_blks = rcu_dereference(sbi->s_system_blks);
318
+ if (system_blks == NULL)
319
+ goto out_rcu;
320
+
321
+ n = system_blks->root.rb_node;
322
+ while (n) {
323
+ entry = rb_entry(n, struct ext4_system_zone, node);
324
+ if (start_blk + count - 1 < entry->start_blk)
325
+ n = n->rb_left;
326
+ else if (start_blk >= (entry->start_blk + entry->count))
327
+ n = n->rb_right;
328
+ else {
329
+ ret = 0;
330
+ if (inode)
331
+ ret = (entry->ino == inode->i_ino);
332
+ break;
333
+ }
334
+ }
335
+out_rcu:
342336 rcu_read_unlock();
343337 return ret;
338
+}
339
+
340
+/*
341
+ * Returns 1 if the passed-in block region (start_blk,
342
+ * start_blk+count) is valid; 0 if some part of the block region
343
+ * overlaps with some other filesystem metadata blocks.
344
+ */
345
+int ext4_inode_block_valid(struct inode *inode, ext4_fsblk_t start_blk,
346
+ unsigned int count)
347
+{
348
+ return ext4_sb_block_valid(inode->i_sb, inode, start_blk, count);
344349 }
345350
346351 int ext4_check_blockref(const char *function, unsigned int line,
347352 struct inode *inode, __le32 *p, unsigned int max)
348353 {
349
- struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
350354 __le32 *bref = p;
351355 unsigned int blk;
352356
....@@ -359,7 +363,6 @@
359363 blk = le32_to_cpu(*bref++);
360364 if (blk &&
361365 unlikely(!ext4_inode_block_valid(inode, blk, 1))) {
362
- es->s_last_error_block = cpu_to_le64(blk);
363366 ext4_error_inode(inode, function, line, blk,
364367 "invalid block");
365368 return -EFSCORRUPTED;