diff options
Diffstat (limited to 'fs/ubifs')
-rw-r--r-- | fs/ubifs/log.c | 20 | ||||
-rw-r--r-- | fs/ubifs/recovery.c | 26 | ||||
-rw-r--r-- | fs/ubifs/replay.c | 18 | ||||
-rw-r--r-- | fs/ubifs/super.c | 44 |
4 files changed, 63 insertions, 45 deletions
diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c index 4d0cb1241460..40fa780ebea7 100644 --- a/fs/ubifs/log.c +++ b/fs/ubifs/log.c | |||
@@ -175,26 +175,6 @@ void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud) | |||
175 | } | 175 | } |
176 | 176 | ||
177 | /** | 177 | /** |
178 | * ubifs_create_buds_lists - create journal head buds lists for remount rw. | ||
179 | * @c: UBIFS file-system description object | ||
180 | */ | ||
181 | void ubifs_create_buds_lists(struct ubifs_info *c) | ||
182 | { | ||
183 | struct rb_node *p; | ||
184 | |||
185 | spin_lock(&c->buds_lock); | ||
186 | p = rb_first(&c->buds); | ||
187 | while (p) { | ||
188 | struct ubifs_bud *bud = rb_entry(p, struct ubifs_bud, rb); | ||
189 | struct ubifs_jhead *jhead = &c->jheads[bud->jhead]; | ||
190 | |||
191 | list_add_tail(&bud->list, &jhead->buds_list); | ||
192 | p = rb_next(p); | ||
193 | } | ||
194 | spin_unlock(&c->buds_lock); | ||
195 | } | ||
196 | |||
197 | /** | ||
198 | * ubifs_add_bud_to_log - add a new bud to the log. | 178 | * ubifs_add_bud_to_log - add a new bud to the log. |
199 | * @c: UBIFS file-system description object | 179 | * @c: UBIFS file-system description object |
200 | * @jhead: journal head the bud belongs to | 180 | * @jhead: journal head the bud belongs to |
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; |
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c index eed0fcff8d73..d3d6d365bfc1 100644 --- a/fs/ubifs/replay.c +++ b/fs/ubifs/replay.c | |||
@@ -59,6 +59,7 @@ enum { | |||
59 | * @new_size: truncation new size | 59 | * @new_size: truncation new size |
60 | * @free: amount of free space in a bud | 60 | * @free: amount of free space in a bud |
61 | * @dirty: amount of dirty space in a bud from padding and deletion nodes | 61 | * @dirty: amount of dirty space in a bud from padding and deletion nodes |
62 | * @jhead: journal head number of the bud | ||
62 | * | 63 | * |
63 | * UBIFS journal replay must compare node sequence numbers, which means it must | 64 | * UBIFS journal replay must compare node sequence numbers, which means it must |
64 | * build a tree of node information to insert into the TNC. | 65 | * build a tree of node information to insert into the TNC. |
@@ -80,6 +81,7 @@ struct replay_entry { | |||
80 | struct { | 81 | struct { |
81 | int free; | 82 | int free; |
82 | int dirty; | 83 | int dirty; |
84 | int jhead; | ||
83 | }; | 85 | }; |
84 | }; | 86 | }; |
85 | }; | 87 | }; |
@@ -159,6 +161,11 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r) | |||
159 | err = PTR_ERR(lp); | 161 | err = PTR_ERR(lp); |
160 | goto out; | 162 | goto out; |
161 | } | 163 | } |
164 | |||
165 | /* Make sure the journal head points to the latest bud */ | ||
166 | err = ubifs_wbuf_seek_nolock(&c->jheads[r->jhead].wbuf, r->lnum, | ||
167 | c->leb_size - r->free, UBI_SHORTTERM); | ||
168 | |||
162 | out: | 169 | out: |
163 | ubifs_release_lprops(c); | 170 | ubifs_release_lprops(c); |
164 | return err; | 171 | return err; |
@@ -627,10 +634,6 @@ static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead, | |||
627 | ubifs_assert(sleb->endpt - offs >= used); | 634 | ubifs_assert(sleb->endpt - offs >= used); |
628 | ubifs_assert(sleb->endpt % c->min_io_size == 0); | 635 | ubifs_assert(sleb->endpt % c->min_io_size == 0); |
629 | 636 | ||
630 | if (sleb->endpt + c->min_io_size <= c->leb_size && !c->ro_mount) | ||
631 | err = ubifs_wbuf_seek_nolock(&c->jheads[jhead].wbuf, lnum, | ||
632 | sleb->endpt, UBI_SHORTTERM); | ||
633 | |||
634 | *dirty = sleb->endpt - offs - used; | 637 | *dirty = sleb->endpt - offs - used; |
635 | *free = c->leb_size - sleb->endpt; | 638 | *free = c->leb_size - sleb->endpt; |
636 | 639 | ||
@@ -653,12 +656,14 @@ out_dump: | |||
653 | * @sqnum: sequence number | 656 | * @sqnum: sequence number |
654 | * @free: amount of free space in bud | 657 | * @free: amount of free space in bud |
655 | * @dirty: amount of dirty space from padding and deletion nodes | 658 | * @dirty: amount of dirty space from padding and deletion nodes |
659 | * @jhead: journal head number for the bud | ||
656 | * | 660 | * |
657 | * This function inserts a reference node to the replay tree and returns zero | 661 | * This function inserts a reference node to the replay tree and returns zero |
658 | * in case of success or a negative error code in case of failure. | 662 | * in case of success or a negative error code in case of failure. |
659 | */ | 663 | */ |
660 | static int insert_ref_node(struct ubifs_info *c, int lnum, int offs, | 664 | static int insert_ref_node(struct ubifs_info *c, int lnum, int offs, |
661 | unsigned long long sqnum, int free, int dirty) | 665 | unsigned long long sqnum, int free, int dirty, |
666 | int jhead) | ||
662 | { | 667 | { |
663 | struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL; | 668 | struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL; |
664 | struct replay_entry *r; | 669 | struct replay_entry *r; |
@@ -688,6 +693,7 @@ static int insert_ref_node(struct ubifs_info *c, int lnum, int offs, | |||
688 | r->flags = REPLAY_REF; | 693 | r->flags = REPLAY_REF; |
689 | r->free = free; | 694 | r->free = free; |
690 | r->dirty = dirty; | 695 | r->dirty = dirty; |
696 | r->jhead = jhead; | ||
691 | 697 | ||
692 | rb_link_node(&r->rb, parent, p); | 698 | rb_link_node(&r->rb, parent, p); |
693 | rb_insert_color(&r->rb, &c->replay_tree); | 699 | rb_insert_color(&r->rb, &c->replay_tree); |
@@ -712,7 +718,7 @@ static int replay_buds(struct ubifs_info *c) | |||
712 | if (err) | 718 | if (err) |
713 | return err; | 719 | return err; |
714 | err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum, | 720 | err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum, |
715 | free, dirty); | 721 | free, dirty, b->bud->jhead); |
716 | if (err) | 722 | if (err) |
717 | return err; | 723 | return err; |
718 | } | 724 | } |
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index c75f6133206c..04ad07f4fcc3 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c | |||
@@ -1257,12 +1257,12 @@ static int mount_ubifs(struct ubifs_info *c) | |||
1257 | goto out_free; | 1257 | goto out_free; |
1258 | } | 1258 | } |
1259 | 1259 | ||
1260 | err = alloc_wbufs(c); | ||
1261 | if (err) | ||
1262 | goto out_cbuf; | ||
1263 | |||
1260 | sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id); | 1264 | sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id); |
1261 | if (!c->ro_mount) { | 1265 | if (!c->ro_mount) { |
1262 | err = alloc_wbufs(c); | ||
1263 | if (err) | ||
1264 | goto out_cbuf; | ||
1265 | |||
1266 | /* Create background thread */ | 1266 | /* Create background thread */ |
1267 | c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name); | 1267 | c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name); |
1268 | if (IS_ERR(c->bgt)) { | 1268 | if (IS_ERR(c->bgt)) { |
@@ -1631,12 +1631,6 @@ static int ubifs_remount_rw(struct ubifs_info *c) | |||
1631 | if (err) | 1631 | if (err) |
1632 | goto out; | 1632 | goto out; |
1633 | 1633 | ||
1634 | err = alloc_wbufs(c); | ||
1635 | if (err) | ||
1636 | goto out; | ||
1637 | |||
1638 | ubifs_create_buds_lists(c); | ||
1639 | |||
1640 | /* Create background thread */ | 1634 | /* Create background thread */ |
1641 | c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name); | 1635 | c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name); |
1642 | if (IS_ERR(c->bgt)) { | 1636 | if (IS_ERR(c->bgt)) { |
@@ -1671,14 +1665,25 @@ static int ubifs_remount_rw(struct ubifs_info *c) | |||
1671 | if (err) | 1665 | if (err) |
1672 | goto out; | 1666 | goto out; |
1673 | 1667 | ||
1668 | dbg_gen("re-mounted read-write"); | ||
1669 | c->remounting_rw = 0; | ||
1670 | |||
1674 | if (c->need_recovery) { | 1671 | if (c->need_recovery) { |
1675 | c->need_recovery = 0; | 1672 | c->need_recovery = 0; |
1676 | ubifs_msg("deferred recovery completed"); | 1673 | ubifs_msg("deferred recovery completed"); |
1674 | } else { | ||
1675 | /* | ||
1676 | * Do not run the debugging space check if the were doing | ||
1677 | * recovery, because when we saved the information we had the | ||
1678 | * file-system in a state where the TNC and lprops has been | ||
1679 | * modified in memory, but all the I/O operations (including a | ||
1680 | * commit) were deferred. So the file-system was in | ||
1681 | * "non-committed" state. Now the file-system is in committed | ||
1682 | * state, and of course the amount of free space will change | ||
1683 | * because, for example, the old index size was imprecise. | ||
1684 | */ | ||
1685 | err = dbg_check_space_info(c); | ||
1677 | } | 1686 | } |
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); | 1687 | mutex_unlock(&c->umount_mutex); |
1683 | return err; | 1688 | return err; |
1684 | 1689 | ||
@@ -1733,7 +1738,6 @@ static void ubifs_remount_ro(struct ubifs_info *c) | |||
1733 | if (err) | 1738 | if (err) |
1734 | ubifs_ro_mode(c, err); | 1739 | ubifs_ro_mode(c, err); |
1735 | 1740 | ||
1736 | free_wbufs(c); | ||
1737 | vfree(c->orph_buf); | 1741 | vfree(c->orph_buf); |
1738 | c->orph_buf = NULL; | 1742 | c->orph_buf = NULL; |
1739 | kfree(c->write_reserve_buf); | 1743 | kfree(c->write_reserve_buf); |
@@ -1761,10 +1765,12 @@ static void ubifs_put_super(struct super_block *sb) | |||
1761 | * of the media. For example, there will be dirty inodes if we failed | 1765 | * of the media. For example, there will be dirty inodes if we failed |
1762 | * to write them back because of I/O errors. | 1766 | * to write them back because of I/O errors. |
1763 | */ | 1767 | */ |
1764 | ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0); | 1768 | if (!c->ro_error) { |
1765 | ubifs_assert(c->budg_idx_growth == 0); | 1769 | ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0); |
1766 | ubifs_assert(c->budg_dd_growth == 0); | 1770 | ubifs_assert(c->budg_idx_growth == 0); |
1767 | ubifs_assert(c->budg_data_growth == 0); | 1771 | ubifs_assert(c->budg_dd_growth == 0); |
1772 | ubifs_assert(c->budg_data_growth == 0); | ||
1773 | } | ||
1768 | 1774 | ||
1769 | /* | 1775 | /* |
1770 | * The 'c->umount_lock' prevents races between UBIFS memory shrinker | 1776 | * The 'c->umount_lock' prevents races between UBIFS memory shrinker |