.. | .. |
---|
126 | 126 | { |
---|
127 | 127 | struct rb_node *node; |
---|
128 | 128 | struct ext4_system_zone *entry; |
---|
| 129 | + struct ext4_system_blocks *system_blks; |
---|
129 | 130 | int first = 1; |
---|
130 | 131 | |
---|
131 | 132 | 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); |
---|
133 | 136 | while (node) { |
---|
134 | 137 | entry = rb_entry(node, struct ext4_system_zone, node); |
---|
135 | 138 | printk(KERN_CONT "%s%llu-%llu", first ? "" : ", ", |
---|
.. | .. |
---|
137 | 140 | first = 0; |
---|
138 | 141 | node = rb_next(node); |
---|
139 | 142 | } |
---|
| 143 | + rcu_read_unlock(); |
---|
140 | 144 | 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; |
---|
181 | 145 | } |
---|
182 | 146 | |
---|
183 | 147 | static int ext4_protect_reserved_inode(struct super_block *sb, |
---|
.. | .. |
---|
212 | 176 | err = add_system_zone(system_blks, map.m_pblk, n, ino); |
---|
213 | 177 | if (err < 0) { |
---|
214 | 178 | 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); |
---|
219 | 185 | } |
---|
220 | 186 | break; |
---|
221 | 187 | } |
---|
.. | .. |
---|
259 | 225 | return -ENOMEM; |
---|
260 | 226 | |
---|
261 | 227 | for (i=0; i < ngroups; i++) { |
---|
| 228 | + cond_resched(); |
---|
262 | 229 | 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, |
---|
265 | 232 | ext4_group_first_block_no(sb, i), |
---|
266 | 233 | ext4_bg_num_gdb(sb, i) + 1, 0); |
---|
| 234 | + if (ret) |
---|
| 235 | + goto err; |
---|
| 236 | + } |
---|
267 | 237 | gdp = ext4_get_group_desc(sb, i, NULL); |
---|
268 | 238 | ret = add_system_zone(system_blks, |
---|
269 | 239 | ext4_block_bitmap(sb, gdp), 1, 0); |
---|
.. | .. |
---|
291 | 261 | * with ext4_data_block_valid() accessing the rbtree at the same |
---|
292 | 262 | * time. |
---|
293 | 263 | */ |
---|
294 | | - rcu_assign_pointer(sbi->system_blks, system_blks); |
---|
| 264 | + rcu_assign_pointer(sbi->s_system_blks, system_blks); |
---|
295 | 265 | |
---|
296 | 266 | if (test_opt(sb, DEBUG)) |
---|
297 | 267 | debug_print_tree(sbi); |
---|
.. | .. |
---|
316 | 286 | { |
---|
317 | 287 | struct ext4_system_blocks *system_blks; |
---|
318 | 288 | |
---|
319 | | - system_blks = rcu_dereference_protected(EXT4_SB(sb)->system_blks, |
---|
| 289 | + system_blks = rcu_dereference_protected(EXT4_SB(sb)->s_system_blks, |
---|
320 | 290 | 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); |
---|
322 | 292 | |
---|
323 | 293 | if (system_blks) |
---|
324 | 294 | call_rcu(&system_blks->rcu, ext4_destroy_system_zone); |
---|
325 | 295 | } |
---|
326 | 296 | |
---|
| 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 | + */ |
---|
327 | 302 | int ext4_inode_block_valid(struct inode *inode, ext4_fsblk_t start_blk, |
---|
328 | 303 | unsigned int count) |
---|
329 | 304 | { |
---|
| 305 | + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); |
---|
330 | 306 | 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; |
---|
332 | 315 | |
---|
333 | 316 | /* |
---|
334 | 317 | * Lock the system zone to prevent it being released concurrently |
---|
.. | .. |
---|
336 | 319 | * mount option. |
---|
337 | 320 | */ |
---|
338 | 321 | 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: |
---|
342 | 339 | rcu_read_unlock(); |
---|
343 | 340 | return ret; |
---|
344 | 341 | } |
---|
.. | .. |
---|
346 | 343 | int ext4_check_blockref(const char *function, unsigned int line, |
---|
347 | 344 | struct inode *inode, __le32 *p, unsigned int max) |
---|
348 | 345 | { |
---|
349 | | - struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es; |
---|
350 | 346 | __le32 *bref = p; |
---|
351 | 347 | unsigned int blk; |
---|
352 | 348 | |
---|
.. | .. |
---|
359 | 355 | blk = le32_to_cpu(*bref++); |
---|
360 | 356 | if (blk && |
---|
361 | 357 | unlikely(!ext4_inode_block_valid(inode, blk, 1))) { |
---|
362 | | - es->s_last_error_block = cpu_to_le64(blk); |
---|
363 | 358 | ext4_error_inode(inode, function, line, blk, |
---|
364 | 359 | "invalid block"); |
---|
365 | 360 | return -EFSCORRUPTED; |
---|