diff options
| author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2009-01-23 07:17:36 -0500 |
|---|---|---|
| committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2009-01-26 05:54:11 -0500 |
| commit | e4d9b6cbfc98d696a28d2c24a3d49768695811ee (patch) | |
| tree | 5d76848d68add2830efa29b16425e2f07b4f1967 | |
| parent | 82c1593cad3dfc97661764c8bc62aa1a416e9ea8 (diff) | |
UBIFS: fix LEB list freeing
When freeing the c->idx_lebs list, we have to release the LEBs as well,
because we might be called from mount to read-only mode code. Otherwise
the LEBs stay taken forever, which may cause problems when we re-mount
back ro RW mode.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
| -rw-r--r-- | fs/ubifs/gc.c | 16 | ||||
| -rw-r--r-- | fs/ubifs/lprops.c | 8 | ||||
| -rw-r--r-- | fs/ubifs/super.c | 42 | ||||
| -rw-r--r-- | fs/ubifs/ubifs.h | 2 |
4 files changed, 48 insertions, 20 deletions
diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c index b2e5f1133377..9760154d874b 100644 --- a/fs/ubifs/gc.c +++ b/fs/ubifs/gc.c | |||
| @@ -830,21 +830,29 @@ out: | |||
| 830 | * ubifs_destroy_idx_gc - destroy idx_gc list. | 830 | * ubifs_destroy_idx_gc - destroy idx_gc list. |
| 831 | * @c: UBIFS file-system description object | 831 | * @c: UBIFS file-system description object |
| 832 | * | 832 | * |
| 833 | * This function destroys the idx_gc list. It is called when unmounting or | 833 | * This function destroys the @c->idx_gc list. It is called when unmounting or |
| 834 | * remounting read-only so locks are not needed. | 834 | * remounting read-only so locks are not needed. Returns zero in case of |
| 835 | * success and a negative error code in case of failure. | ||
| 835 | */ | 836 | */ |
| 836 | void ubifs_destroy_idx_gc(struct ubifs_info *c) | 837 | int ubifs_destroy_idx_gc(struct ubifs_info *c) |
| 837 | { | 838 | { |
| 839 | int ret = 0; | ||
| 840 | |||
| 838 | while (!list_empty(&c->idx_gc)) { | 841 | while (!list_empty(&c->idx_gc)) { |
| 842 | int err; | ||
| 839 | struct ubifs_gced_idx_leb *idx_gc; | 843 | struct ubifs_gced_idx_leb *idx_gc; |
| 840 | 844 | ||
| 841 | idx_gc = list_entry(c->idx_gc.next, struct ubifs_gced_idx_leb, | 845 | idx_gc = list_entry(c->idx_gc.next, struct ubifs_gced_idx_leb, |
| 842 | list); | 846 | list); |
| 843 | c->idx_gc_cnt -= 1; | 847 | err = ubifs_change_one_lp(c, idx_gc->lnum, LPROPS_NC, |
| 848 | LPROPS_NC, 0, LPROPS_TAKEN, -1); | ||
| 849 | if (err && !ret) | ||
| 850 | ret = err; | ||
| 844 | list_del(&idx_gc->list); | 851 | list_del(&idx_gc->list); |
| 845 | kfree(idx_gc); | 852 | kfree(idx_gc); |
| 846 | } | 853 | } |
| 847 | 854 | ||
| 855 | return ret; | ||
| 848 | } | 856 | } |
| 849 | 857 | ||
| 850 | /** | 858 | /** |
diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c index dfd2bcece27a..68328c59762b 100644 --- a/fs/ubifs/lprops.c +++ b/fs/ubifs/lprops.c | |||
| @@ -678,6 +678,9 @@ int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty, | |||
| 678 | 678 | ||
| 679 | out: | 679 | out: |
| 680 | ubifs_release_lprops(c); | 680 | ubifs_release_lprops(c); |
| 681 | if (err) | ||
| 682 | ubifs_err("cannot change properties of LEB %d, error %d", | ||
| 683 | lnum, err); | ||
| 681 | return err; | 684 | return err; |
| 682 | } | 685 | } |
| 683 | 686 | ||
| @@ -714,6 +717,9 @@ int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty, | |||
| 714 | 717 | ||
| 715 | out: | 718 | out: |
| 716 | ubifs_release_lprops(c); | 719 | ubifs_release_lprops(c); |
| 720 | if (err) | ||
| 721 | ubifs_err("cannot update properties of LEB %d, error %d", | ||
| 722 | lnum, err); | ||
| 717 | return err; | 723 | return err; |
| 718 | } | 724 | } |
| 719 | 725 | ||
| @@ -737,6 +743,8 @@ int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp) | |||
| 737 | lpp = ubifs_lpt_lookup(c, lnum); | 743 | lpp = ubifs_lpt_lookup(c, lnum); |
| 738 | if (IS_ERR(lpp)) { | 744 | if (IS_ERR(lpp)) { |
| 739 | err = PTR_ERR(lpp); | 745 | err = PTR_ERR(lpp); |
| 746 | ubifs_err("cannot read properties of LEB %d, error %d", | ||
| 747 | lnum, err); | ||
| 740 | goto out; | 748 | goto out; |
| 741 | } | 749 | } |
| 742 | 750 | ||
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index da99da098efd..807bbd3c8b4b 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c | |||
| @@ -1469,9 +1469,6 @@ static int ubifs_remount_rw(struct ubifs_info *c) | |||
| 1469 | { | 1469 | { |
| 1470 | int err, lnum; | 1470 | int err, lnum; |
| 1471 | 1471 | ||
| 1472 | if (c->ro_media) | ||
| 1473 | return -EINVAL; | ||
| 1474 | |||
| 1475 | mutex_lock(&c->umount_mutex); | 1472 | mutex_lock(&c->umount_mutex); |
| 1476 | c->remounting_rw = 1; | 1473 | c->remounting_rw = 1; |
| 1477 | c->always_chk_crc = 1; | 1474 | c->always_chk_crc = 1; |
| @@ -1605,9 +1602,13 @@ out: | |||
| 1605 | */ | 1602 | */ |
| 1606 | static void commit_on_unmount(struct ubifs_info *c) | 1603 | static void commit_on_unmount(struct ubifs_info *c) |
| 1607 | { | 1604 | { |
| 1608 | struct super_block *sb = c->vfs_sb; | ||
| 1609 | long long bud_bytes; | 1605 | long long bud_bytes; |
| 1610 | 1606 | ||
| 1607 | if (!c->fast_unmount) { | ||
| 1608 | dbg_gen("skip committing - fast unmount enabled"); | ||
| 1609 | return; | ||
| 1610 | } | ||
| 1611 | |||
| 1611 | /* | 1612 | /* |
| 1612 | * This function is called before the background thread is stopped, so | 1613 | * This function is called before the background thread is stopped, so |
| 1613 | * we may race with ongoing commit, which means we have to take | 1614 | * we may race with ongoing commit, which means we have to take |
| @@ -1617,8 +1618,11 @@ static void commit_on_unmount(struct ubifs_info *c) | |||
| 1617 | bud_bytes = c->bud_bytes; | 1618 | bud_bytes = c->bud_bytes; |
| 1618 | spin_unlock(&c->buds_lock); | 1619 | spin_unlock(&c->buds_lock); |
| 1619 | 1620 | ||
| 1620 | if (!c->fast_unmount && !(sb->s_flags & MS_RDONLY) && bud_bytes) | 1621 | if (bud_bytes) { |
| 1622 | dbg_gen("run commit"); | ||
| 1621 | ubifs_run_commit(c); | 1623 | ubifs_run_commit(c); |
| 1624 | } else | ||
| 1625 | dbg_gen("journal is empty, do not run commit"); | ||
| 1622 | } | 1626 | } |
| 1623 | 1627 | ||
| 1624 | /** | 1628 | /** |
| @@ -1633,6 +1637,8 @@ static void ubifs_remount_ro(struct ubifs_info *c) | |||
| 1633 | int i, err; | 1637 | int i, err; |
| 1634 | 1638 | ||
| 1635 | ubifs_assert(!c->need_recovery); | 1639 | ubifs_assert(!c->need_recovery); |
| 1640 | ubifs_assert(!c->ro_media); | ||
| 1641 | |||
| 1636 | commit_on_unmount(c); | 1642 | commit_on_unmount(c); |
| 1637 | 1643 | ||
| 1638 | mutex_lock(&c->umount_mutex); | 1644 | mutex_lock(&c->umount_mutex); |
| @@ -1646,16 +1652,17 @@ static void ubifs_remount_ro(struct ubifs_info *c) | |||
| 1646 | del_timer_sync(&c->jheads[i].wbuf.timer); | 1652 | del_timer_sync(&c->jheads[i].wbuf.timer); |
| 1647 | } | 1653 | } |
| 1648 | 1654 | ||
| 1649 | if (!c->ro_media) { | 1655 | c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY); |
| 1650 | c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY); | 1656 | c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS); |
| 1651 | c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS); | 1657 | c->mst_node->gc_lnum = cpu_to_le32(c->gc_lnum); |
| 1652 | c->mst_node->gc_lnum = cpu_to_le32(c->gc_lnum); | 1658 | err = ubifs_write_master(c); |
| 1653 | err = ubifs_write_master(c); | 1659 | if (err) |
| 1654 | if (err) | 1660 | ubifs_ro_mode(c, err); |
| 1655 | ubifs_ro_mode(c, err); | 1661 | |
| 1656 | } | 1662 | err = ubifs_destroy_idx_gc(c); |
| 1663 | if (err) | ||
| 1664 | ubifs_ro_mode(c, err); | ||
| 1657 | 1665 | ||
| 1658 | ubifs_destroy_idx_gc(c); | ||
| 1659 | free_wbufs(c); | 1666 | free_wbufs(c); |
| 1660 | vfree(c->orph_buf); | 1667 | vfree(c->orph_buf); |
| 1661 | c->orph_buf = NULL; | 1668 | c->orph_buf = NULL; |
| @@ -1754,6 +1761,11 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) | |||
| 1754 | } | 1761 | } |
| 1755 | 1762 | ||
| 1756 | if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) { | 1763 | if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) { |
| 1764 | if (c->ro_media) { | ||
| 1765 | ubifs_msg("cannot re-mount R/W, UBIFS is working in " | ||
| 1766 | "R/O mode"); | ||
| 1767 | return -EINVAL; | ||
| 1768 | } | ||
| 1757 | err = ubifs_remount_rw(c); | 1769 | err = ubifs_remount_rw(c); |
| 1758 | if (err) | 1770 | if (err) |
| 1759 | return err; | 1771 | return err; |
| @@ -2044,7 +2056,7 @@ static void ubifs_kill_sb(struct super_block *sb) | |||
| 2044 | * We do 'commit_on_unmount()' here instead of 'ubifs_put_super()' | 2056 | * We do 'commit_on_unmount()' here instead of 'ubifs_put_super()' |
| 2045 | * in order to be outside BKL. | 2057 | * in order to be outside BKL. |
| 2046 | */ | 2058 | */ |
| 2047 | if (sb->s_root) | 2059 | if (sb->s_root && !(sb->s_flags & MS_RDONLY)) |
| 2048 | commit_on_unmount(c); | 2060 | commit_on_unmount(c); |
| 2049 | /* The un-mount routine is actually done in put_super() */ | 2061 | /* The un-mount routine is actually done in put_super() */ |
| 2050 | generic_shutdown_super(sb); | 2062 | generic_shutdown_super(sb); |
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 2e78d6ac007e..ee9517a7b024 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h | |||
| @@ -1593,7 +1593,7 @@ int ubifs_replay_journal(struct ubifs_info *c); | |||
| 1593 | int ubifs_garbage_collect(struct ubifs_info *c, int anyway); | 1593 | int ubifs_garbage_collect(struct ubifs_info *c, int anyway); |
| 1594 | int ubifs_gc_start_commit(struct ubifs_info *c); | 1594 | int ubifs_gc_start_commit(struct ubifs_info *c); |
| 1595 | int ubifs_gc_end_commit(struct ubifs_info *c); | 1595 | int ubifs_gc_end_commit(struct ubifs_info *c); |
| 1596 | void ubifs_destroy_idx_gc(struct ubifs_info *c); | 1596 | int ubifs_destroy_idx_gc(struct ubifs_info *c); |
| 1597 | int ubifs_get_idx_gc_leb(struct ubifs_info *c); | 1597 | int ubifs_get_idx_gc_leb(struct ubifs_info *c); |
| 1598 | int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp); | 1598 | int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp); |
| 1599 | 1599 | ||
