aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/ialloc.c
diff options
context:
space:
mode:
authorAvantika Mathur <mathur@us.ibm.com>2008-01-28 23:58:27 -0500
committerTheodore Ts'o <tytso@mit.edu>2008-01-28 23:58:27 -0500
commit2aa9fc4c405467f6afbbb2162ff8afaced47d99b (patch)
tree49fc3490d5b59af8a409207de2d5faac52ab8c91 /fs/ext4/ialloc.c
parentfd2d42912f9f09e5250cb3b024ee0625704e9cb7 (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.c101
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 */
263static ext4_group_t find_group_dir(struct super_block *sb, struct inode *parent) 263static 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
317static ext4_group_t find_group_orlov(struct super_block *sb, 320static 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
397fallback: 402fallback:
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
419static ext4_group_t find_group_other(struct super_block *sb, 423static 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++) {