add patch rename-GOINGDOWN-to-SHUTDOWN
[ext4-patch-queue.git] / load-jmap-from-journal
blobe00e4c6bdf14e1b11f9d64b15130a02d643c4a08
1 jbd2: load jmap from journal
3 If the lazy journal feature is enabled, instead of replaying the
4 journal, read the journal into journal map.
6 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
7 ---
8  fs/jbd2/journal.c  |  27 ++++++++--------------
9  fs/jbd2/recovery.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
10  2 files changed, 89 insertions(+), 42 deletions(-)
12 diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
13 index ab7b9bbc9296..1e4a9475826f 100644
14 --- a/fs/jbd2/journal.c
15 +++ b/fs/jbd2/journal.c
16 @@ -1275,31 +1275,24 @@ static void journal_fail_superblock (journal_t *journal)
18  /*
19   * Given a journal_t structure, initialise the various fields for
20 - * startup of a new journaling session.  We use this both when creating
21 - * a journal, and after recovering an old journal to reset it for
22 - * subsequent use.
23 + * startup of a new journaling session.
24   */
26  static int journal_reset(journal_t *journal)
27  {
28         journal_superblock_t *sb = journal->j_superblock;
29 -       unsigned long long first, last;
30 +       int free;
32 -       first = be32_to_cpu(sb->s_first);
33 -       last = be32_to_cpu(sb->s_maxlen);
34 -       if (first + JBD2_MIN_JOURNAL_BLOCKS > last + 1) {
35 -               printk(KERN_ERR "JBD2: Journal too short (blocks %llu-%llu).\n",
36 -                      first, last);
37 +       if (journal->j_first + JBD2_MIN_JOURNAL_BLOCKS > journal->j_last + 1) {
38 +               printk(KERN_ERR "JBD2: Journal too short (blocks %lu-%lu).\n",
39 +                      journal->j_first, journal->j_last);
40                 journal_fail_superblock(journal);
41                 return -EINVAL;
42         }
44 -       journal->j_first = first;
45 -       journal->j_last = last;
47 -       journal->j_head = first;
48 -       journal->j_tail = first;
49 -       journal->j_free = last - first;
50 +       free = journal->j_tail - journal->j_head;
51 +       if (free <= 0)
52 +               free += journal->j_last - journal->j_first;
53 +       journal->j_free = free;
55         journal->j_tail_sequence = journal->j_transaction_sequence;
56         journal->j_commit_sequence = journal->j_transaction_sequence - 1;
57 @@ -1319,7 +1312,7 @@ static int journal_reset(journal_t *journal)
58                         journal->j_tail, journal->j_tail_sequence,
59                         journal->j_errno);
60                 journal->j_flags |= JBD2_FLUSHED;
61 -       } else {
62 +       } else if ((journal->j_flags & JBD2_LAZY) == 0) {
63                 /* Lock here to make assertions happy... */
64                 mutex_lock(&journal->j_checkpoint_mutex);
65                 /*
66 diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
67 index da100044566c..c96ccd1f257f 100644
68 --- a/fs/jbd2/recovery.c
69 +++ b/fs/jbd2/recovery.c
70 @@ -32,17 +32,18 @@ struct recovery_info
71  {
72         tid_t           start_transaction;
73         tid_t           end_transaction;
74 +       int             head_block;
76         int             nr_replays;
77         int             nr_revokes;
78         int             nr_revoke_hits;
79  };
81 -enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
82 +enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY, PASS_JMAP};
83  static int do_one_pass(journal_t *journal,
84                                 struct recovery_info *info, enum passtype pass);
85 -static int scan_revoke_records(journal_t *, struct buffer_head *,
86 -                               tid_t, struct recovery_info *);
87 +static int scan_revoke_records(journal_t *, struct buffer_head *, enum passtype,
88 +                              tid_t, struct recovery_info *);
90  #ifdef __KERNEL__
92 @@ -255,11 +256,16 @@ int jbd2_journal_recover(journal_t *journal)
93         sb = journal->j_superblock;
95         /*
96 +        * Initialize journal's head and tail assuming the recovery
97 +        * was successful and we're not doing lazy journalling.
98 +        */
99 +       journal->j_head = journal->j_tail = journal->j_first;
101 +       /*
102          * The journal superblock's s_start field (the current log head)
103          * is always zero if, and only if, the journal was cleanly
104          * unmounted.
105          */
107         if (!sb->s_start) {
108                 jbd_debug(1, "No recovery required, last transaction %d\n",
109                           be32_to_cpu(sb->s_sequence));
110 @@ -267,11 +273,15 @@ int jbd2_journal_recover(journal_t *journal)
111                 return 0;
112         }
114 -       err = do_one_pass(journal, &info, PASS_SCAN);
115 -       if (!err)
116 -               err = do_one_pass(journal, &info, PASS_REVOKE);
117 -       if (!err)
118 -               err = do_one_pass(journal, &info, PASS_REPLAY);
119 +       if (journal->j_flags & JBD2_LAZY)
120 +               err = do_one_pass(journal, &info, PASS_JMAP);
121 +       else {
122 +               err = do_one_pass(journal, &info, PASS_SCAN);
123 +               if (!err)
124 +                       err = do_one_pass(journal, &info, PASS_REVOKE);
125 +               if (!err)
126 +                       err = do_one_pass(journal, &info, PASS_REPLAY);
127 +       }
129         jbd_debug(1, "JBD2: recovery, exit status %d, "
130                   "recovered transactions %u to %u\n",
131 @@ -279,10 +289,22 @@ int jbd2_journal_recover(journal_t *journal)
132         jbd_debug(1, "JBD2: Replayed %d and revoked %d/%d blocks\n",
133                   info.nr_replays, info.nr_revoke_hits, info.nr_revokes);
135 -       /* Restart the log at the next transaction ID, thus invalidating
136 -        * any existing commit records in the log. */
137 +       /* Restart the log at the next transaction ID */
138         journal->j_transaction_sequence = info.end_transaction;
140 +       /*
141 +        * In lazy journalling mode, we need to preserve the existing
142 +        * contents of the journal, so set j_head and j_tail
143 +        * accordingly.
144 +        */
145 +       if (journal->j_flags & JBD2_LAZY) {
146 +               if (err)
147 +                       return err;
148 +               journal->j_head = info.head_block;
149 +               journal->j_tail = be32_to_cpu(sb->s_start);
150 +               return 0;
151 +       }
153         jbd2_journal_clear_revoke(journal);
154         err2 = sync_blockdev(journal->j_fs_dev);
155         if (!err)
156 @@ -431,6 +453,7 @@ static int do_one_pass(journal_t *journal,
157         __u32                   crc32_sum = ~0; /* Transactional Checksums */
158         int                     descr_csum_size = 0;
159         int                     block_error = 0;
160 +       int                     new_txn = 1;
162         /*
163          * First thing is to establish what we expect to find in the log
164 @@ -443,7 +466,7 @@ static int do_one_pass(journal_t *journal,
165         next_log_block = be32_to_cpu(sb->s_start);
167         first_commit_ID = next_commit_ID;
168 -       if (pass == PASS_SCAN)
169 +       if (pass == PASS_SCAN || pass == PASS_JMAP)
170                 info->start_transaction = first_commit_ID;
172         jbd_debug(1, "Starting recovery pass %d\n", pass);
173 @@ -468,7 +491,7 @@ static int do_one_pass(journal_t *journal,
174                  * check right now that we haven't gone past the end of
175                  * the log. */
177 -               if (pass != PASS_SCAN)
178 +               if (pass != PASS_SCAN && pass != PASS_JMAP)
179                         if (tid_geq(next_commit_ID, info->end_transaction))
180                                 break;
182 @@ -484,9 +507,6 @@ static int do_one_pass(journal_t *journal,
183                 if (err)
184                         goto failed;
186 -               next_log_block++;
187 -               wrap(journal, next_log_block);
189                 /* What kind of buffer is it?
190                  *
191                  * If it is a descriptor block, check that it has the
192 @@ -510,6 +530,14 @@ static int do_one_pass(journal_t *journal,
193                         break;
194                 }
196 +               if ((pass == PASS_JMAP) && new_txn) {
197 +                       jbd2_add_new_transaction_infos(journal, sequence, next_log_block);
198 +                       new_txn = 0;
199 +               }
201 +               next_log_block++;
202 +               wrap(journal, next_log_block);
204                 /* OK, we have a valid descriptor block which matches
205                  * all of the sequence number checks.  What are we going
206                  * to do with it?  That depends on the pass... */
207 @@ -535,7 +563,7 @@ static int do_one_pass(journal_t *journal,
208                          * in pass REPLAY; if journal_checksums enabled, then
209                          * calculate checksums in PASS_SCAN, otherwise,
210                          * just skip over the blocks it describes. */
211 -                       if (pass != PASS_REPLAY) {
212 +                       if ((pass != PASS_REPLAY) && (pass != PASS_JMAP)) {
213                                 if (pass == PASS_SCAN &&
214                                     jbd2_has_feature_checksum(journal) &&
215                                     !info->end_transaction) {
216 @@ -562,12 +590,28 @@ static int do_one_pass(journal_t *journal,
217                         while ((tagp - bh->b_data + tag_bytes)
218                                <= journal->j_blocksize - descr_csum_size) {
219                                 unsigned long io_block;
220 +                               unsigned long long log_block;
222                                 tag = (journal_block_tag_t *) tagp;
223                                 flags = be16_to_cpu(tag->t_flags);
225                                 io_block = next_log_block++;
226                                 wrap(journal, next_log_block);
227 +                               if (pass == PASS_JMAP) {
228 +                                       struct blk_mapping map;
230 +                                       err = jbd2_journal_bmap(journal,
231 +                                                               io_block,
232 +                                                               &log_block);
233 +                                       if (err)
234 +                                               goto failed;
235 +                                       map.fsblk = read_tag_block(journal, tag);
236 +                                       map.logblk = log_block;
237 +                                       err = jbd2_add_mapping(journal, &map);
238 +                                       if (err)
239 +                                               goto failed;
240 +                                       goto skip_write;
241 +                               }
242                                 err = jread(&obh, journal, io_block);
243                                 if (err) {
244                                         /* Recover what we can, but
245 @@ -753,6 +797,10 @@ static int do_one_pass(journal_t *journal,
246                                         break;
247                                 }
248                         }
249 +                       if (pass == PASS_JMAP) {
250 +                               jbd2_finish_transaction_infos(journal);
251 +                               new_txn = 1;
252 +                       }
253                         brelse(bh);
254                         next_commit_ID++;
255                         continue;
256 @@ -760,12 +808,12 @@ static int do_one_pass(journal_t *journal,
257                 case JBD2_REVOKE_BLOCK:
258                         /* If we aren't in the REVOKE pass, then we can
259                          * just skip over this block. */
260 -                       if (pass != PASS_REVOKE) {
261 +                       if (pass != PASS_REVOKE && pass != PASS_JMAP) {
262                                 brelse(bh);
263                                 continue;
264                         }
266 -                       err = scan_revoke_records(journal, bh,
267 +                       err = scan_revoke_records(journal, bh, pass,
268                                                   next_commit_ID, info);
269                         brelse(bh);
270                         if (err)
271 @@ -788,9 +836,10 @@ static int do_one_pass(journal_t *journal,
272          * transaction marks the end of the valid log.
273          */
275 -       if (pass == PASS_SCAN) {
276 +       if (pass == PASS_SCAN || pass == PASS_JMAP) {
277                 if (!info->end_transaction)
278                         info->end_transaction = next_commit_ID;
279 +               info->head_block = next_log_block;
280         } else {
281                 /* It's really bad news if different passes end up at
282                  * different places (but possible due to IO errors). */
283 @@ -813,7 +862,8 @@ static int do_one_pass(journal_t *journal,
284  /* Scan a revoke record, marking all blocks mentioned as revoked. */
286  static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
287 -                              tid_t sequence, struct recovery_info *info)
288 +                              enum passtype pass, tid_t sequence,
289 +                              struct recovery_info *info)
291         jbd2_journal_revoke_header_t *header;
292         int offset, max;
293 @@ -839,16 +889,20 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
295         while (offset + record_len <= max) {
296                 unsigned long long blocknr;
297 -               int err;
299                 if (record_len == 4)
300                         blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset)));
301                 else
302                         blocknr = be64_to_cpu(* ((__be64 *) (bh->b_data+offset)));
303                 offset += record_len;
304 -               err = jbd2_journal_set_revoke(journal, blocknr, sequence);
305 -               if (err)
306 -                       return err;
307 +               if (pass == PASS_JMAP)
308 +                       jbd2_jmap_revoke(journal, blocknr);
309 +               else {
310 +                       int err = jbd2_journal_set_revoke(journal, blocknr,
311 +                                                         sequence);
312 +                       if (err)
313 +                               return err;
314 +               }
315                 ++info->nr_revokes;
316         }
317         return 0;