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
This commit is contained in:
Linus Torvalds 2011-04-24 08:42:15 -07:00
commit 1f91f48b65
2 changed files with 47 additions and 8 deletions

View File

@ -317,6 +317,32 @@ int ubifs_recover_master_node(struct ubifs_info *c)
goto out_free;
}
memcpy(c->rcvrd_mst_node, c->mst_node, UBIFS_MST_NODE_SZ);
/*
* We had to recover the master node, which means there was an
* unclean reboot. However, it is possible that the master node
* is clean at this point, i.e., %UBIFS_MST_DIRTY is not set.
* E.g., consider the following chain of events:
*
* 1. UBIFS was cleanly unmounted, so the master node is clean
* 2. UBIFS is being mounted R/W and starts changing the master
* node in the first (%UBIFS_MST_LNUM). A power cut happens,
* so this LEB ends up with some amount of garbage at the
* end.
* 3. UBIFS is being mounted R/O. We reach this place and
* recover the master node from the second LEB
* (%UBIFS_MST_LNUM + 1). But we cannot update the media
* because we are being mounted R/O. We have to defer the
* operation.
* 4. However, this master node (@c->mst_node) is marked as
* clean (since the step 1). And if we just return, the
* mount code will be confused and won't recover the master
* node when it is re-mounter R/W later.
*
* Thus, to force the recovery by marking the master node as
* dirty.
*/
c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
} else {
/* Write the recovered master node */
c->max_sqnum = le64_to_cpu(mst->ch.sqnum) - 1;

View File

@ -1671,14 +1671,25 @@ static int ubifs_remount_rw(struct ubifs_info *c)
if (err)
goto out;
dbg_gen("re-mounted read-write");
c->remounting_rw = 0;
if (c->need_recovery) {
c->need_recovery = 0;
ubifs_msg("deferred recovery completed");
} else {
/*
* Do not run the debugging space check if the were doing
* recovery, because when we saved the information we had the
* file-system in a state where the TNC and lprops has been
* modified in memory, but all the I/O operations (including a
* commit) were deferred. So the file-system was in
* "non-committed" state. Now the file-system is in committed
* state, and of course the amount of free space will change
* because, for example, the old index size was imprecise.
*/
err = dbg_check_space_info(c);
}
dbg_gen("re-mounted read-write");
c->remounting_rw = 0;
err = dbg_check_space_info(c);
mutex_unlock(&c->umount_mutex);
return err;
@ -1761,10 +1772,12 @@ static void ubifs_put_super(struct super_block *sb)
* of the media. For example, there will be dirty inodes if we failed
* to write them back because of I/O errors.
*/
ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0);
ubifs_assert(c->budg_idx_growth == 0);
ubifs_assert(c->budg_dd_growth == 0);
ubifs_assert(c->budg_data_growth == 0);
if (!c->ro_error) {
ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0);
ubifs_assert(c->budg_idx_growth == 0);
ubifs_assert(c->budg_dd_growth == 0);
ubifs_assert(c->budg_data_growth == 0);
}
/*
* The 'c->umount_lock' prevents races between UBIFS memory shrinker