diff options
author | Avantika Mathur <mathur@us.ibm.com> | 2008-01-28 23:58:27 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2008-01-28 23:58:27 -0500 |
commit | 2aa9fc4c405467f6afbbb2162ff8afaced47d99b (patch) | |
tree | 49fc3490d5b59af8a409207de2d5faac52ab8c91 /fs/ext4/ialloc.c | |
parent | fd2d42912f9f09e5250cb3b024ee0625704e9cb7 (diff) |
ext4: fixes block group number being set to a negative value
This patch fixes various places where the group number is set to a negative
value.
Signed-off-by: Avantika Mathur <mathur@us.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/ialloc.c')
-rw-r--r-- | fs/ext4/ialloc.c | 101 |
1 files changed, 53 insertions, 48 deletions
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 64dea8689e1f..7b5cfa62b663 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -260,12 +260,14 @@ error_return: | |||
260 | * For other inodes, search forward from the parent directory\'s block | 260 | * For other inodes, search forward from the parent directory\'s block |
261 | * group to find a free inode. | 261 | * group to find a free inode. |
262 | */ | 262 | */ |
263 | static ext4_group_t find_group_dir(struct super_block *sb, struct inode *parent) | 263 | static int find_group_dir(struct super_block *sb, struct inode *parent, |
264 | ext4_group_t *best_group) | ||
264 | { | 265 | { |
265 | ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count; | 266 | ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count; |
266 | unsigned int freei, avefreei; | 267 | unsigned int freei, avefreei; |
267 | struct ext4_group_desc *desc, *best_desc = NULL; | 268 | struct ext4_group_desc *desc, *best_desc = NULL; |
268 | ext4_group_t group, best_group = -1; | 269 | ext4_group_t group; |
270 | int ret = -1; | ||
269 | 271 | ||
270 | freei = percpu_counter_read_positive(&EXT4_SB(sb)->s_freeinodes_counter); | 272 | freei = percpu_counter_read_positive(&EXT4_SB(sb)->s_freeinodes_counter); |
271 | avefreei = freei / ngroups; | 273 | avefreei = freei / ngroups; |
@@ -279,11 +281,12 @@ static ext4_group_t find_group_dir(struct super_block *sb, struct inode *parent) | |||
279 | if (!best_desc || | 281 | if (!best_desc || |
280 | (le16_to_cpu(desc->bg_free_blocks_count) > | 282 | (le16_to_cpu(desc->bg_free_blocks_count) > |
281 | le16_to_cpu(best_desc->bg_free_blocks_count))) { | 283 | le16_to_cpu(best_desc->bg_free_blocks_count))) { |
282 | best_group = group; | 284 | *best_group = group; |
283 | best_desc = desc; | 285 | best_desc = desc; |
286 | ret = 0; | ||
284 | } | 287 | } |
285 | } | 288 | } |
286 | return best_group; | 289 | return ret; |
287 | } | 290 | } |
288 | 291 | ||
289 | /* | 292 | /* |
@@ -314,8 +317,8 @@ static ext4_group_t find_group_dir(struct super_block *sb, struct inode *parent) | |||
314 | #define INODE_COST 64 | 317 | #define INODE_COST 64 |
315 | #define BLOCK_COST 256 | 318 | #define BLOCK_COST 256 |
316 | 319 | ||
317 | static ext4_group_t find_group_orlov(struct super_block *sb, | 320 | static int find_group_orlov(struct super_block *sb, struct inode *parent, |
318 | struct inode *parent) | 321 | ext4_group_t *group) |
319 | { | 322 | { |
320 | ext4_group_t parent_group = EXT4_I(parent)->i_block_group; | 323 | ext4_group_t parent_group = EXT4_I(parent)->i_block_group; |
321 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 324 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
@@ -328,7 +331,7 @@ static ext4_group_t find_group_orlov(struct super_block *sb, | |||
328 | unsigned int ndirs; | 331 | unsigned int ndirs; |
329 | int max_debt, max_dirs, min_inodes; | 332 | int max_debt, max_dirs, min_inodes; |
330 | ext4_grpblk_t min_blocks; | 333 | ext4_grpblk_t min_blocks; |
331 | ext4_group_t group = -1, i; | 334 | ext4_group_t i; |
332 | struct ext4_group_desc *desc; | 335 | struct ext4_group_desc *desc; |
333 | 336 | ||
334 | freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter); | 337 | freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter); |
@@ -341,13 +344,14 @@ static ext4_group_t find_group_orlov(struct super_block *sb, | |||
341 | if ((parent == sb->s_root->d_inode) || | 344 | if ((parent == sb->s_root->d_inode) || |
342 | (EXT4_I(parent)->i_flags & EXT4_TOPDIR_FL)) { | 345 | (EXT4_I(parent)->i_flags & EXT4_TOPDIR_FL)) { |
343 | int best_ndir = inodes_per_group; | 346 | int best_ndir = inodes_per_group; |
344 | ext4_group_t best_group = -1; | 347 | ext4_group_t grp; |
348 | int ret = -1; | ||
345 | 349 | ||
346 | get_random_bytes(&group, sizeof(group)); | 350 | get_random_bytes(&grp, sizeof(grp)); |
347 | parent_group = (unsigned)group % ngroups; | 351 | parent_group = (unsigned)grp % ngroups; |
348 | for (i = 0; i < ngroups; i++) { | 352 | for (i = 0; i < ngroups; i++) { |
349 | group = (parent_group + i) % ngroups; | 353 | grp = (parent_group + i) % ngroups; |
350 | desc = ext4_get_group_desc (sb, group, NULL); | 354 | desc = ext4_get_group_desc(sb, grp, NULL); |
351 | if (!desc || !desc->bg_free_inodes_count) | 355 | if (!desc || !desc->bg_free_inodes_count) |
352 | continue; | 356 | continue; |
353 | if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir) | 357 | if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir) |
@@ -356,11 +360,12 @@ static ext4_group_t find_group_orlov(struct super_block *sb, | |||
356 | continue; | 360 | continue; |
357 | if (le16_to_cpu(desc->bg_free_blocks_count) < avefreeb) | 361 | if (le16_to_cpu(desc->bg_free_blocks_count) < avefreeb) |
358 | continue; | 362 | continue; |
359 | best_group = group; | 363 | *group = grp; |
364 | ret = 0; | ||
360 | best_ndir = le16_to_cpu(desc->bg_used_dirs_count); | 365 | best_ndir = le16_to_cpu(desc->bg_used_dirs_count); |
361 | } | 366 | } |
362 | if (best_group >= 0) | 367 | if (ret == 0) |
363 | return best_group; | 368 | return ret; |
364 | goto fallback; | 369 | goto fallback; |
365 | } | 370 | } |
366 | 371 | ||
@@ -381,8 +386,8 @@ static ext4_group_t find_group_orlov(struct super_block *sb, | |||
381 | max_debt = 1; | 386 | max_debt = 1; |
382 | 387 | ||
383 | for (i = 0; i < ngroups; i++) { | 388 | for (i = 0; i < ngroups; i++) { |
384 | group = (parent_group + i) % ngroups; | 389 | *group = (parent_group + i) % ngroups; |
385 | desc = ext4_get_group_desc (sb, group, NULL); | 390 | desc = ext4_get_group_desc(sb, *group, NULL); |
386 | if (!desc || !desc->bg_free_inodes_count) | 391 | if (!desc || !desc->bg_free_inodes_count) |
387 | continue; | 392 | continue; |
388 | if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs) | 393 | if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs) |
@@ -391,17 +396,16 @@ static ext4_group_t find_group_orlov(struct super_block *sb, | |||
391 | continue; | 396 | continue; |
392 | if (le16_to_cpu(desc->bg_free_blocks_count) < min_blocks) | 397 | if (le16_to_cpu(desc->bg_free_blocks_count) < min_blocks) |
393 | continue; | 398 | continue; |
394 | return group; | 399 | return 0; |
395 | } | 400 | } |
396 | 401 | ||
397 | fallback: | 402 | fallback: |
398 | for (i = 0; i < ngroups; i++) { | 403 | for (i = 0; i < ngroups; i++) { |
399 | group = (parent_group + i) % ngroups; | 404 | *group = (parent_group + i) % ngroups; |
400 | desc = ext4_get_group_desc (sb, group, NULL); | 405 | desc = ext4_get_group_desc(sb, *group, NULL); |
401 | if (!desc || !desc->bg_free_inodes_count) | 406 | if (desc && desc->bg_free_inodes_count && |
402 | continue; | 407 | le16_to_cpu(desc->bg_free_inodes_count) >= avefreei) |
403 | if (le16_to_cpu(desc->bg_free_inodes_count) >= avefreei) | 408 | return 0; |
404 | return group; | ||
405 | } | 409 | } |
406 | 410 | ||
407 | if (avefreei) { | 411 | if (avefreei) { |
@@ -416,22 +420,22 @@ fallback: | |||
416 | return -1; | 420 | return -1; |
417 | } | 421 | } |
418 | 422 | ||
419 | static ext4_group_t find_group_other(struct super_block *sb, | 423 | static int find_group_other(struct super_block *sb, struct inode *parent, |
420 | struct inode *parent) | 424 | ext4_group_t *group) |
421 | { | 425 | { |
422 | ext4_group_t parent_group = EXT4_I(parent)->i_block_group; | 426 | ext4_group_t parent_group = EXT4_I(parent)->i_block_group; |
423 | ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count; | 427 | ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count; |
424 | struct ext4_group_desc *desc; | 428 | struct ext4_group_desc *desc; |
425 | ext4_group_t group, i; | 429 | ext4_group_t i; |
426 | 430 | ||
427 | /* | 431 | /* |
428 | * Try to place the inode in its parent directory | 432 | * Try to place the inode in its parent directory |
429 | */ | 433 | */ |
430 | group = parent_group; | 434 | *group = parent_group; |
431 | desc = ext4_get_group_desc (sb, group, NULL); | 435 | desc = ext4_get_group_desc(sb, *group, NULL); |
432 | if (desc && le16_to_cpu(desc->bg_free_inodes_count) && | 436 | if (desc && le16_to_cpu(desc->bg_free_inodes_count) && |
433 | le16_to_cpu(desc->bg_free_blocks_count)) | 437 | le16_to_cpu(desc->bg_free_blocks_count)) |
434 | return group; | 438 | return 0; |
435 | 439 | ||
436 | /* | 440 | /* |
437 | * We're going to place this inode in a different blockgroup from its | 441 | * We're going to place this inode in a different blockgroup from its |
@@ -442,33 +446,33 @@ static ext4_group_t find_group_other(struct super_block *sb, | |||
442 | * | 446 | * |
443 | * So add our directory's i_ino into the starting point for the hash. | 447 | * So add our directory's i_ino into the starting point for the hash. |
444 | */ | 448 | */ |
445 | group = (group + parent->i_ino) % ngroups; | 449 | *group = (*group + parent->i_ino) % ngroups; |
446 | 450 | ||
447 | /* | 451 | /* |
448 | * Use a quadratic hash to find a group with a free inode and some free | 452 | * Use a quadratic hash to find a group with a free inode and some free |
449 | * blocks. | 453 | * blocks. |
450 | */ | 454 | */ |
451 | for (i = 1; i < ngroups; i <<= 1) { | 455 | for (i = 1; i < ngroups; i <<= 1) { |
452 | group += i; | 456 | *group += i; |
453 | if (group >= ngroups) | 457 | if (*group >= ngroups) |
454 | group -= ngroups; | 458 | *group -= ngroups; |
455 | desc = ext4_get_group_desc (sb, group, NULL); | 459 | desc = ext4_get_group_desc(sb, *group, NULL); |
456 | if (desc && le16_to_cpu(desc->bg_free_inodes_count) && | 460 | if (desc && le16_to_cpu(desc->bg_free_inodes_count) && |
457 | le16_to_cpu(desc->bg_free_blocks_count)) | 461 | le16_to_cpu(desc->bg_free_blocks_count)) |
458 | return group; | 462 | return 0; |
459 | } | 463 | } |
460 | 464 | ||
461 | /* | 465 | /* |
462 | * That failed: try linear search for a free inode, even if that group | 466 | * That failed: try linear search for a free inode, even if that group |
463 | * has no free blocks. | 467 | * has no free blocks. |
464 | */ | 468 | */ |
465 | group = parent_group; | 469 | *group = parent_group; |
466 | for (i = 0; i < ngroups; i++) { | 470 | for (i = 0; i < ngroups; i++) { |
467 | if (++group >= ngroups) | 471 | if (++*group >= ngroups) |
468 | group = 0; | 472 | *group = 0; |
469 | desc = ext4_get_group_desc (sb, group, NULL); | 473 | desc = ext4_get_group_desc(sb, *group, NULL); |
470 | if (desc && le16_to_cpu(desc->bg_free_inodes_count)) | 474 | if (desc && le16_to_cpu(desc->bg_free_inodes_count)) |
471 | return group; | 475 | return 0; |
472 | } | 476 | } |
473 | 477 | ||
474 | return -1; | 478 | return -1; |
@@ -489,16 +493,17 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode * dir, int mode) | |||
489 | struct super_block *sb; | 493 | struct super_block *sb; |
490 | struct buffer_head *bitmap_bh = NULL; | 494 | struct buffer_head *bitmap_bh = NULL; |
491 | struct buffer_head *bh2; | 495 | struct buffer_head *bh2; |
492 | ext4_group_t group; | 496 | ext4_group_t group = 0; |
493 | unsigned long ino = 0; | 497 | unsigned long ino = 0; |
494 | struct inode * inode; | 498 | struct inode * inode; |
495 | struct ext4_group_desc * gdp = NULL; | 499 | struct ext4_group_desc * gdp = NULL; |
496 | struct ext4_super_block * es; | 500 | struct ext4_super_block * es; |
497 | struct ext4_inode_info *ei; | 501 | struct ext4_inode_info *ei; |
498 | struct ext4_sb_info *sbi; | 502 | struct ext4_sb_info *sbi; |
499 | int err = 0; | 503 | int ret2, err = 0; |
500 | struct inode *ret; | 504 | struct inode *ret; |
501 | int i, free = 0; | 505 | ext4_group_t i; |
506 | int free = 0; | ||
502 | 507 | ||
503 | /* Cannot create files in a deleted directory */ | 508 | /* Cannot create files in a deleted directory */ |
504 | if (!dir || !dir->i_nlink) | 509 | if (!dir || !dir->i_nlink) |
@@ -514,14 +519,14 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode * dir, int mode) | |||
514 | es = sbi->s_es; | 519 | es = sbi->s_es; |
515 | if (S_ISDIR(mode)) { | 520 | if (S_ISDIR(mode)) { |
516 | if (test_opt (sb, OLDALLOC)) | 521 | if (test_opt (sb, OLDALLOC)) |
517 | group = find_group_dir(sb, dir); | 522 | ret2 = find_group_dir(sb, dir, &group); |
518 | else | 523 | else |
519 | group = find_group_orlov(sb, dir); | 524 | ret2 = find_group_orlov(sb, dir, &group); |
520 | } else | 525 | } else |
521 | group = find_group_other(sb, dir); | 526 | ret2 = find_group_other(sb, dir, &group); |
522 | 527 | ||
523 | err = -ENOSPC; | 528 | err = -ENOSPC; |
524 | if (group == -1) | 529 | if (ret2 == -1) |
525 | goto out; | 530 | goto out; |
526 | 531 | ||
527 | for (i = 0; i < sbi->s_groups_count; i++) { | 532 | for (i = 0; i < sbi->s_groups_count; i++) { |