diff options
| author | David Woodhouse <David.Woodhouse@intel.com> | 2010-06-03 03:03:39 -0400 |
|---|---|---|
| committer | David Woodhouse <David.Woodhouse@intel.com> | 2010-06-03 03:03:39 -0400 |
| commit | f324e4cb2cadd9a42932c8a158e761ae31b88e72 (patch) | |
| tree | deb742349c87becaa711a807c0c13b5b7a857c02 | |
| parent | 5869d2c387e75814334697c9d702d91b7c63a308 (diff) | |
jffs2: Fix in-core inode leaks on error paths
Pointed out by Al Viro.
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
| -rw-r--r-- | fs/jffs2/dir.c | 115 |
1 files changed, 56 insertions, 59 deletions
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 7aa4417e085f..cb7ef34d384c 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c | |||
| @@ -360,8 +360,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
| 360 | /* Eeek. Wave bye bye */ | 360 | /* Eeek. Wave bye bye */ |
| 361 | mutex_unlock(&f->sem); | 361 | mutex_unlock(&f->sem); |
| 362 | jffs2_complete_reservation(c); | 362 | jffs2_complete_reservation(c); |
| 363 | jffs2_clear_inode(inode); | 363 | ret = PTR_ERR(fn); |
| 364 | return PTR_ERR(fn); | 364 | goto fail; |
| 365 | } | 365 | } |
| 366 | 366 | ||
| 367 | /* We use f->target field to store the target path. */ | 367 | /* We use f->target field to store the target path. */ |
| @@ -370,8 +370,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
| 370 | printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); | 370 | printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); |
| 371 | mutex_unlock(&f->sem); | 371 | mutex_unlock(&f->sem); |
| 372 | jffs2_complete_reservation(c); | 372 | jffs2_complete_reservation(c); |
| 373 | jffs2_clear_inode(inode); | 373 | ret = -ENOMEM; |
| 374 | return -ENOMEM; | 374 | goto fail; |
| 375 | } | 375 | } |
| 376 | 376 | ||
| 377 | memcpy(f->target, target, targetlen + 1); | 377 | memcpy(f->target, target, targetlen + 1); |
| @@ -386,30 +386,24 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
| 386 | jffs2_complete_reservation(c); | 386 | jffs2_complete_reservation(c); |
| 387 | 387 | ||
| 388 | ret = jffs2_init_security(inode, dir_i); | 388 | ret = jffs2_init_security(inode, dir_i); |
| 389 | if (ret) { | 389 | if (ret) |
| 390 | jffs2_clear_inode(inode); | 390 | goto fail; |
| 391 | return ret; | 391 | |
| 392 | } | ||
| 393 | ret = jffs2_init_acl_post(inode); | 392 | ret = jffs2_init_acl_post(inode); |
| 394 | if (ret) { | 393 | if (ret) |
| 395 | jffs2_clear_inode(inode); | 394 | goto fail; |
| 396 | return ret; | ||
| 397 | } | ||
| 398 | 395 | ||
| 399 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, | 396 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, |
| 400 | ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); | 397 | ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); |
| 401 | if (ret) { | 398 | if (ret) |
| 402 | /* Eep. */ | 399 | goto fail; |
| 403 | jffs2_clear_inode(inode); | ||
| 404 | return ret; | ||
| 405 | } | ||
| 406 | 400 | ||
| 407 | rd = jffs2_alloc_raw_dirent(); | 401 | rd = jffs2_alloc_raw_dirent(); |
| 408 | if (!rd) { | 402 | if (!rd) { |
| 409 | /* Argh. Now we treat it like a normal delete */ | 403 | /* Argh. Now we treat it like a normal delete */ |
| 410 | jffs2_complete_reservation(c); | 404 | jffs2_complete_reservation(c); |
| 411 | jffs2_clear_inode(inode); | 405 | ret = -ENOMEM; |
| 412 | return -ENOMEM; | 406 | goto fail; |
| 413 | } | 407 | } |
| 414 | 408 | ||
| 415 | dir_f = JFFS2_INODE_INFO(dir_i); | 409 | dir_f = JFFS2_INODE_INFO(dir_i); |
| @@ -437,8 +431,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
| 437 | jffs2_complete_reservation(c); | 431 | jffs2_complete_reservation(c); |
| 438 | jffs2_free_raw_dirent(rd); | 432 | jffs2_free_raw_dirent(rd); |
| 439 | mutex_unlock(&dir_f->sem); | 433 | mutex_unlock(&dir_f->sem); |
| 440 | jffs2_clear_inode(inode); | 434 | ret = PTR_ERR(fd); |
| 441 | return PTR_ERR(fd); | 435 | goto fail; |
| 442 | } | 436 | } |
| 443 | 437 | ||
| 444 | dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); | 438 | dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); |
| @@ -454,6 +448,11 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
| 454 | 448 | ||
| 455 | d_instantiate(dentry, inode); | 449 | d_instantiate(dentry, inode); |
| 456 | return 0; | 450 | return 0; |
| 451 | |||
| 452 | fail: | ||
| 453 | make_bad_inode(inode); | ||
| 454 | iput(inode); | ||
| 455 | return ret; | ||
| 457 | } | 456 | } |
| 458 | 457 | ||
| 459 | 458 | ||
| @@ -519,8 +518,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
| 519 | /* Eeek. Wave bye bye */ | 518 | /* Eeek. Wave bye bye */ |
| 520 | mutex_unlock(&f->sem); | 519 | mutex_unlock(&f->sem); |
| 521 | jffs2_complete_reservation(c); | 520 | jffs2_complete_reservation(c); |
| 522 | jffs2_clear_inode(inode); | 521 | ret = PTR_ERR(fn); |
| 523 | return PTR_ERR(fn); | 522 | goto fail; |
| 524 | } | 523 | } |
| 525 | /* No data here. Only a metadata node, which will be | 524 | /* No data here. Only a metadata node, which will be |
| 526 | obsoleted by the first data write | 525 | obsoleted by the first data write |
| @@ -531,30 +530,24 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
| 531 | jffs2_complete_reservation(c); | 530 | jffs2_complete_reservation(c); |
| 532 | 531 | ||
| 533 | ret = jffs2_init_security(inode, dir_i); | 532 | ret = jffs2_init_security(inode, dir_i); |
| 534 | if (ret) { | 533 | if (ret) |
| 535 | jffs2_clear_inode(inode); | 534 | goto fail; |
| 536 | return ret; | 535 | |
| 537 | } | ||
| 538 | ret = jffs2_init_acl_post(inode); | 536 | ret = jffs2_init_acl_post(inode); |
| 539 | if (ret) { | 537 | if (ret) |
| 540 | jffs2_clear_inode(inode); | 538 | goto fail; |
| 541 | return ret; | ||
| 542 | } | ||
| 543 | 539 | ||
| 544 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, | 540 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, |
| 545 | ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); | 541 | ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); |
| 546 | if (ret) { | 542 | if (ret) |
| 547 | /* Eep. */ | 543 | goto fail; |
| 548 | jffs2_clear_inode(inode); | ||
| 549 | return ret; | ||
| 550 | } | ||
| 551 | 544 | ||
| 552 | rd = jffs2_alloc_raw_dirent(); | 545 | rd = jffs2_alloc_raw_dirent(); |
| 553 | if (!rd) { | 546 | if (!rd) { |
| 554 | /* Argh. Now we treat it like a normal delete */ | 547 | /* Argh. Now we treat it like a normal delete */ |
| 555 | jffs2_complete_reservation(c); | 548 | jffs2_complete_reservation(c); |
| 556 | jffs2_clear_inode(inode); | 549 | ret = -ENOMEM; |
| 557 | return -ENOMEM; | 550 | goto fail; |
| 558 | } | 551 | } |
| 559 | 552 | ||
| 560 | dir_f = JFFS2_INODE_INFO(dir_i); | 553 | dir_f = JFFS2_INODE_INFO(dir_i); |
| @@ -582,8 +575,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
| 582 | jffs2_complete_reservation(c); | 575 | jffs2_complete_reservation(c); |
| 583 | jffs2_free_raw_dirent(rd); | 576 | jffs2_free_raw_dirent(rd); |
| 584 | mutex_unlock(&dir_f->sem); | 577 | mutex_unlock(&dir_f->sem); |
| 585 | jffs2_clear_inode(inode); | 578 | ret = PTR_ERR(fd); |
| 586 | return PTR_ERR(fd); | 579 | goto fail; |
| 587 | } | 580 | } |
| 588 | 581 | ||
| 589 | dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); | 582 | dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); |
| @@ -600,6 +593,11 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
| 600 | 593 | ||
| 601 | d_instantiate(dentry, inode); | 594 | d_instantiate(dentry, inode); |
| 602 | return 0; | 595 | return 0; |
| 596 | |||
| 597 | fail: | ||
| 598 | make_bad_inode(inode); | ||
| 599 | iput(inode); | ||
| 600 | return ret; | ||
| 603 | } | 601 | } |
| 604 | 602 | ||
| 605 | static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) | 603 | static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) |
| @@ -693,8 +691,8 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
| 693 | /* Eeek. Wave bye bye */ | 691 | /* Eeek. Wave bye bye */ |
| 694 | mutex_unlock(&f->sem); | 692 | mutex_unlock(&f->sem); |
| 695 | jffs2_complete_reservation(c); | 693 | jffs2_complete_reservation(c); |
| 696 | jffs2_clear_inode(inode); | 694 | ret = PTR_ERR(fn); |
| 697 | return PTR_ERR(fn); | 695 | goto fail; |
| 698 | } | 696 | } |
| 699 | /* No data here. Only a metadata node, which will be | 697 | /* No data here. Only a metadata node, which will be |
| 700 | obsoleted by the first data write | 698 | obsoleted by the first data write |
| @@ -705,30 +703,24 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
| 705 | jffs2_complete_reservation(c); | 703 | jffs2_complete_reservation(c); |
| 706 | 704 | ||
| 707 | ret = jffs2_init_security(inode, dir_i); | 705 | ret = jffs2_init_security(inode, dir_i); |
| 708 | if (ret) { | 706 | if (ret) |
| 709 | jffs2_clear_inode(inode); | 707 | goto fail; |
| 710 | return ret; | 708 | |
| 711 | } | ||
| 712 | ret = jffs2_init_acl_post(inode); | 709 | ret = jffs2_init_acl_post(inode); |
| 713 | if (ret) { | 710 | if (ret) |
| 714 | jffs2_clear_inode(inode); | 711 | goto fail; |
| 715 | return ret; | ||
| 716 | } | ||
| 717 | 712 | ||
| 718 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, | 713 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, |
| 719 | ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); | 714 | ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); |
| 720 | if (ret) { | 715 | if (ret) |
| 721 | /* Eep. */ | 716 | goto fail; |
| 722 | jffs2_clear_inode(inode); | ||
| 723 | return ret; | ||
| 724 | } | ||
| 725 | 717 | ||
| 726 | rd = jffs2_alloc_raw_dirent(); | 718 | rd = jffs2_alloc_raw_dirent(); |
| 727 | if (!rd) { | 719 | if (!rd) { |
| 728 | /* Argh. Now we treat it like a normal delete */ | 720 | /* Argh. Now we treat it like a normal delete */ |
| 729 | jffs2_complete_reservation(c); | 721 | jffs2_complete_reservation(c); |
| 730 | jffs2_clear_inode(inode); | 722 | ret = -ENOMEM; |
| 731 | return -ENOMEM; | 723 | goto fail; |
| 732 | } | 724 | } |
| 733 | 725 | ||
| 734 | dir_f = JFFS2_INODE_INFO(dir_i); | 726 | dir_f = JFFS2_INODE_INFO(dir_i); |
| @@ -759,8 +751,8 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
| 759 | jffs2_complete_reservation(c); | 751 | jffs2_complete_reservation(c); |
| 760 | jffs2_free_raw_dirent(rd); | 752 | jffs2_free_raw_dirent(rd); |
| 761 | mutex_unlock(&dir_f->sem); | 753 | mutex_unlock(&dir_f->sem); |
| 762 | jffs2_clear_inode(inode); | 754 | ret = PTR_ERR(fd); |
| 763 | return PTR_ERR(fd); | 755 | goto fail; |
| 764 | } | 756 | } |
| 765 | 757 | ||
| 766 | dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); | 758 | dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); |
| @@ -777,6 +769,11 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
| 777 | d_instantiate(dentry, inode); | 769 | d_instantiate(dentry, inode); |
| 778 | 770 | ||
| 779 | return 0; | 771 | return 0; |
| 772 | |||
| 773 | fail: | ||
| 774 | make_bad_inode(inode); | ||
| 775 | iput(inode); | ||
| 776 | return ret; | ||
| 780 | } | 777 | } |
| 781 | 778 | ||
| 782 | static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, | 779 | static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, |
