hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
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 }
....@@ -259,11 +225,15 @@
259225 return -ENOMEM;
260226
261227 for (i=0; i < ngroups; i++) {
228
+ cond_resched();
262229 if (ext4_bg_has_super(sb, i) &&
263
- ((i < 5) || ((i % flex_size) == 0)))
264
- add_system_zone(system_blks,
230
+ ((i < 5) || ((i % flex_size) == 0))) {
231
+ ret = add_system_zone(system_blks,
265232 ext4_group_first_block_no(sb, i),
266233 ext4_bg_num_gdb(sb, i) + 1, 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,32 @@
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
297
+/*
298
+ * Returns 1 if the passed-in block region (start_blk,
299
+ * start_blk+count) is valid; 0 if some part of the block region
300
+ * overlaps with some other filesystem metadata blocks.
301
+ */
327302 int ext4_inode_block_valid(struct inode *inode, ext4_fsblk_t start_blk,
328303 unsigned int count)
329304 {
305
+ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
330306 struct ext4_system_blocks *system_blks;
331
- int ret;
307
+ struct ext4_system_zone *entry;
308
+ struct rb_node *n;
309
+ int ret = 1;
310
+
311
+ if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
312
+ (start_blk + count < start_blk) ||
313
+ (start_blk + count > ext4_blocks_count(sbi->s_es)))
314
+ return 0;
332315
333316 /*
334317 * Lock the system zone to prevent it being released concurrently
....@@ -336,9 +319,23 @@
336319 * mount option.
337320 */
338321 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);
322
+ system_blks = rcu_dereference(sbi->s_system_blks);
323
+ if (system_blks == NULL)
324
+ goto out_rcu;
325
+
326
+ n = system_blks->root.rb_node;
327
+ while (n) {
328
+ entry = rb_entry(n, struct ext4_system_zone, node);
329
+ if (start_blk + count - 1 < entry->start_blk)
330
+ n = n->rb_left;
331
+ else if (start_blk >= (entry->start_blk + entry->count))
332
+ n = n->rb_right;
333
+ else {
334
+ ret = (entry->ino == inode->i_ino);
335
+ break;
336
+ }
337
+ }
338
+out_rcu:
342339 rcu_read_unlock();
343340 return ret;
344341 }
....@@ -346,7 +343,6 @@
346343 int ext4_check_blockref(const char *function, unsigned int line,
347344 struct inode *inode, __le32 *p, unsigned int max)
348345 {
349
- struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
350346 __le32 *bref = p;
351347 unsigned int blk;
352348
....@@ -359,7 +355,6 @@
359355 blk = le32_to_cpu(*bref++);
360356 if (blk &&
361357 unlikely(!ext4_inode_block_valid(inode, blk, 1))) {
362
- es->s_last_error_block = cpu_to_le64(blk);
363358 ext4_error_inode(inode, function, line, blk,
364359 "invalid block");
365360 return -EFSCORRUPTED;