mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-04 09:59:32 +00:00
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:
commit
1f91f48b65
2 changed files with 47 additions and 8 deletions
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue