diff options
Diffstat (limited to 'fs/ubifs/recovery.c')
-rw-r--r-- | fs/ubifs/recovery.c | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c index 936f2cbfe6b6..3dbad6fbd1eb 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; |