diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-04-24 11:42:15 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-04-24 11:42:15 -0400 |
| commit | 1f91f48b65a075c29c4adc57a895ff0e7306e2ee (patch) | |
| tree | 5966d172b8f484011ebb2b4c00988b81060afb82 | |
| parent | 3ba41621156681afcdbcd624e3191cbc65eb94f4 (diff) | |
| parent | 6e0d9fd38b750d678bf9fd07db23582f52fafa55 (diff) | |
Merge branch 'for-linus' of git://git.infradead.org/ubifs-2.6
* 'for-linus' of git://git.infradead.org/ubifs-2.6:
UBIFS: fix master node recovery
UBIFS: fix false assertion warning in case of I/O failures
UBIFS: fix false space checking failure
| -rw-r--r-- | fs/ubifs/recovery.c | 26 | ||||
| -rw-r--r-- | fs/ubifs/super.c | 29 |
2 files changed, 47 insertions, 8 deletions
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c index 936f2cbfe6b..3dbad6fbd1e 100644 --- a/fs/ubifs/recovery.c +++ b/fs/ubifs/recovery.c | |||
| @@ -317,6 +317,32 @@ int ubifs_recover_master_node(struct ubifs_info *c) | |||
| 317 | goto out_free; | 317 | goto out_free; |
| 318 | } | 318 | } |
| 319 | memcpy(c->rcvrd_mst_node, c->mst_node, UBIFS_MST_NODE_SZ); | 319 | memcpy(c->rcvrd_mst_node, c->mst_node, UBIFS_MST_NODE_SZ); |
| 320 | |||
| 321 | /* | ||
| 322 | * We had to recover the master node, which means there was an | ||
| 323 | * unclean reboot. However, it is possible that the master node | ||
| 324 | * is clean at this point, i.e., %UBIFS_MST_DIRTY is not set. | ||
| 325 | * E.g., consider the following chain of events: | ||
| 326 | * | ||
| 327 | * 1. UBIFS was cleanly unmounted, so the master node is clean | ||
| 328 | * 2. UBIFS is being mounted R/W and starts changing the master | ||
| 329 | * node in the first (%UBIFS_MST_LNUM). A power cut happens, | ||
| 330 | * so this LEB ends up with some amount of garbage at the | ||
| 331 | * end. | ||
| 332 | * 3. UBIFS is being mounted R/O. We reach this place and | ||
| 333 | * recover the master node from the second LEB | ||
| 334 | * (%UBIFS_MST_LNUM + 1). But we cannot update the media | ||
| 335 | * because we are being mounted R/O. We have to defer the | ||
| 336 | * operation. | ||
| 337 | * 4. However, this master node (@c->mst_node) is marked as | ||
| 338 | * clean (since the step 1). And if we just return, the | ||
| 339 | * mount code will be confused and won't recover the master | ||
| 340 | * node when it is re-mounter R/W later. | ||
| 341 | * | ||
| 342 | * Thus, to force the recovery by marking the master node as | ||
| 343 | * dirty. | ||
| 344 | */ | ||
| 345 | c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY); | ||
| 320 | } else { | 346 | } else { |
| 321 | /* Write the recovered master node */ | 347 | /* Write the recovered master node */ |
| 322 | c->max_sqnum = le64_to_cpu(mst->ch.sqnum) - 1; | 348 | c->max_sqnum = le64_to_cpu(mst->ch.sqnum) - 1; |
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index c75f6133206..be6c7b008f3 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c | |||
| @@ -1671,14 +1671,25 @@ static int ubifs_remount_rw(struct ubifs_info *c) | |||
| 1671 | if (err) | 1671 | if (err) |
| 1672 | goto out; | 1672 | goto out; |
| 1673 | 1673 | ||
| 1674 | dbg_gen("re-mounted read-write"); | ||
| 1675 | c->remounting_rw = 0; | ||
| 1676 | |||
| 1674 | if (c->need_recovery) { | 1677 | if (c->need_recovery) { |
| 1675 | c->need_recovery = 0; | 1678 | c->need_recovery = 0; |
| 1676 | ubifs_msg("deferred recovery completed"); | 1679 | ubifs_msg("deferred recovery completed"); |
| 1680 | } else { | ||
| 1681 | /* | ||
| 1682 | * Do not run the debugging space check if the were doing | ||
| 1683 | * recovery, because when we saved the information we had the | ||
| 1684 | * file-system in a state where the TNC and lprops has been | ||
| 1685 | * modified in memory, but all the I/O operations (including a | ||
| 1686 | * commit) were deferred. So the file-system was in | ||
| 1687 | * "non-committed" state. Now the file-system is in committed | ||
| 1688 | * state, and of course the amount of free space will change | ||
| 1689 | * because, for example, the old index size was imprecise. | ||
| 1690 | */ | ||
| 1691 | err = dbg_check_space_info(c); | ||
| 1677 | } | 1692 | } |
| 1678 | |||
| 1679 | dbg_gen("re-mounted read-write"); | ||
| 1680 | c->remounting_rw = 0; | ||
| 1681 | err = dbg_check_space_info(c); | ||
| 1682 | mutex_unlock(&c->umount_mutex); | 1693 | mutex_unlock(&c->umount_mutex); |
| 1683 | return err; | 1694 | return err; |
| 1684 | 1695 | ||
| @@ -1761,10 +1772,12 @@ static void ubifs_put_super(struct super_block *sb) | |||
| 1761 | * of the media. For example, there will be dirty inodes if we failed | 1772 | * of the media. For example, there will be dirty inodes if we failed |
| 1762 | * to write them back because of I/O errors. | 1773 | * to write them back because of I/O errors. |
| 1763 | */ | 1774 | */ |
| 1764 | ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0); | 1775 | if (!c->ro_error) { |
| 1765 | ubifs_assert(c->budg_idx_growth == 0); | 1776 | ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0); |
| 1766 | ubifs_assert(c->budg_dd_growth == 0); | 1777 | ubifs_assert(c->budg_idx_growth == 0); |
| 1767 | ubifs_assert(c->budg_data_growth == 0); | 1778 | ubifs_assert(c->budg_dd_growth == 0); |
| 1779 | ubifs_assert(c->budg_data_growth == 0); | ||
| 1780 | } | ||
| 1768 | 1781 | ||
| 1769 | /* | 1782 | /* |
| 1770 | * The 'c->umount_lock' prevents races between UBIFS memory shrinker | 1783 | * The 'c->umount_lock' prevents races between UBIFS memory shrinker |
