• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * do_journal.c --- Scribble onto the journal!
3  *
4  * Copyright (C) 2014 Oracle.  This file may be redistributed
5  * under the terms of the GNU Public License.
6  */
7 
8 #include "config.h"
9 #include <stdio.h>
10 #ifdef HAVE_GETOPT_H
11 #include <getopt.h>
12 #else
13 extern int optind;
14 extern char *optarg;
15 #endif
16 #include <ctype.h>
17 #include <unistd.h>
18 #ifdef HAVE_SYS_TIME_H
19 #include <sys/time.h>
20 #endif
21 
22 #include "debugfs.h"
23 #include "ext2fs/kernel-jbd.h"
24 #include "journal.h"
25 
26 #undef DEBUG
27 
28 #ifdef DEBUG
29 # define dbg_printf(f, a...)  do {printf("JFS DEBUG: " f, ## a); \
30 	fflush(stdout); \
31 } while (0)
32 #else
33 # define dbg_printf(f, a...)
34 #endif
35 
36 #define JOURNAL_CHECK_TRANS_MAGIC(x)	\
37 	do { \
38 		if ((x)->magic != J_TRANS_MAGIC) \
39 			return EXT2_ET_INVALID_ARGUMENT; \
40 	} while (0)
41 
42 #define J_TRANS_MAGIC		0xD15EA5ED
43 #define J_TRANS_OPEN		1
44 #define J_TRANS_COMMITTED	2
45 struct journal_transaction_s {
46 	unsigned int magic;
47 	ext2_filsys fs;
48 	journal_t *journal;
49 	blk64_t block;
50 	blk64_t start, end;
51 	tid_t tid;
52 	int flags;
53 };
54 
55 typedef struct journal_transaction_s journal_transaction_t;
56 
57 static journal_t *current_journal = NULL;
58 
journal_dump_trans(journal_transaction_t * trans EXT2FS_ATTR ((unused)),const char * tag EXT2FS_ATTR ((unused)))59 static void journal_dump_trans(journal_transaction_t *trans EXT2FS_ATTR((unused)),
60 			       const char *tag EXT2FS_ATTR((unused)))
61 {
62 	dbg_printf("TRANS %p(%s): tid=%u start=%llu block=%llu end=%llu "
63 		   "flags=0x%x\n", trans, tag, trans->tid, trans->start,
64 		   trans->block, trans->end, trans->flags);
65 }
66 
journal_commit_trans(journal_transaction_t * trans)67 static errcode_t journal_commit_trans(journal_transaction_t *trans)
68 {
69 	struct buffer_head *bh, *cbh = NULL;
70 	struct commit_header *commit;
71 #ifdef HAVE_SYS_TIME_H
72 	struct timeval tv;
73 #endif
74 	errcode_t err;
75 
76 	JOURNAL_CHECK_TRANS_MAGIC(trans);
77 
78 	if ((trans->flags & J_TRANS_COMMITTED) ||
79 	    !(trans->flags & J_TRANS_OPEN))
80 		return EXT2_ET_INVALID_ARGUMENT;
81 
82 	bh = getblk(trans->journal->j_dev, 0, trans->journal->j_blocksize);
83 	if (bh == NULL)
84 		return ENOMEM;
85 
86 	/* write the descriptor block header */
87 	commit = (struct commit_header *)bh->b_data;
88 	commit->h_magic = ext2fs_cpu_to_be32(JBD2_MAGIC_NUMBER);
89 	commit->h_blocktype = ext2fs_cpu_to_be32(JBD2_COMMIT_BLOCK);
90 	commit->h_sequence = ext2fs_cpu_to_be32(trans->tid);
91 	if (jbd2_has_feature_checksum(trans->journal)) {
92 		__u32 csum_v1 = ~0;
93 		blk64_t cblk;
94 
95 		cbh = getblk(trans->journal->j_dev, 0,
96 			     trans->journal->j_blocksize);
97 		if (cbh == NULL) {
98 			err = ENOMEM;
99 			goto error;
100 		}
101 
102 		for (cblk = trans->start; cblk < trans->block; cblk++) {
103 			err = jbd2_journal_bmap(trans->journal, cblk,
104 						&cbh->b_blocknr);
105 			if (err)
106 				goto error;
107 			mark_buffer_uptodate(cbh, 0);
108 			ll_rw_block(REQ_OP_READ, 0, 1, &cbh);
109 			err = cbh->b_err;
110 			if (err)
111 				goto error;
112 			csum_v1 = ext2fs_crc32_be(csum_v1,
113 					(unsigned char const *)cbh->b_data,
114 					cbh->b_size);
115 		}
116 
117 		commit->h_chksum_type = JBD2_CRC32_CHKSUM;
118 		commit->h_chksum_size = JBD2_CRC32_CHKSUM_SIZE;
119 		commit->h_chksum[0] = ext2fs_cpu_to_be32(csum_v1);
120 	} else {
121 		commit->h_chksum_type = 0;
122 		commit->h_chksum_size = 0;
123 		commit->h_chksum[0] = 0;
124 	}
125 #ifdef HAVE_SYS_TIME_H
126 	gettimeofday(&tv, NULL);
127 	commit->h_commit_sec = ext2fs_cpu_to_be32(tv.tv_sec);
128 	commit->h_commit_nsec = ext2fs_cpu_to_be32(tv.tv_usec * 1000);
129 #else
130 	commit->h_commit_sec = 0;
131 	commit->h_commit_nsec = 0;
132 #endif
133 
134 	/* Write block */
135 	jbd2_commit_block_csum_set(trans->journal, bh);
136 	err = jbd2_journal_bmap(trans->journal, trans->block, &bh->b_blocknr);
137 	if (err)
138 		goto error;
139 
140 	dbg_printf("Writing commit block at %llu:%llu\n", trans->block,
141 		   bh->b_blocknr);
142 	mark_buffer_dirty(bh);
143 	ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
144 	err = bh->b_err;
145 	if (err)
146 		goto error;
147 	trans->flags |= J_TRANS_COMMITTED;
148 	trans->flags &= ~J_TRANS_OPEN;
149 	trans->block++;
150 
151 	ext2fs_set_feature_journal_needs_recovery(trans->fs->super);
152 	ext2fs_mark_super_dirty(trans->fs);
153 error:
154 	if (cbh)
155 		brelse(cbh);
156 	brelse(bh);
157 	return err;
158 }
159 
journal_add_revoke_to_trans(journal_transaction_t * trans,blk64_t * revoke_list,size_t revoke_len)160 static errcode_t journal_add_revoke_to_trans(journal_transaction_t *trans,
161 					     blk64_t *revoke_list,
162 					     size_t revoke_len)
163 {
164 	jbd2_journal_revoke_header_t *jrb;
165 	void *buf;
166 	size_t i, offset;
167 	blk64_t curr_blk;
168 	unsigned int sz;
169 	unsigned csum_size = 0;
170 	struct buffer_head *bh;
171 	errcode_t err;
172 
173 	JOURNAL_CHECK_TRANS_MAGIC(trans);
174 
175 	if ((trans->flags & J_TRANS_COMMITTED) ||
176 	    !(trans->flags & J_TRANS_OPEN))
177 		return EXT2_ET_INVALID_ARGUMENT;
178 
179 	if (revoke_len == 0)
180 		return 0;
181 
182 	/* Do we need to leave space at the end for a checksum? */
183 	if (jbd2_journal_has_csum_v2or3(trans->journal))
184 		csum_size = sizeof(struct jbd2_journal_block_tail);
185 
186 	curr_blk = trans->block;
187 
188 	bh = getblk(trans->journal->j_dev, curr_blk,
189 		    trans->journal->j_blocksize);
190 	if (bh == NULL)
191 		return ENOMEM;
192 	jrb = buf = bh->b_data;
193 	jrb->r_header.h_magic = ext2fs_cpu_to_be32(JBD2_MAGIC_NUMBER);
194 	jrb->r_header.h_blocktype = ext2fs_cpu_to_be32(JBD2_REVOKE_BLOCK);
195 	jrb->r_header.h_sequence = ext2fs_cpu_to_be32(trans->tid);
196 	offset = sizeof(*jrb);
197 
198 	if (jbd2_has_feature_64bit(trans->journal))
199 		sz = 8;
200 	else
201 		sz = 4;
202 
203 	for (i = 0; i < revoke_len; i++) {
204 		/* Block full, write to journal */
205 		if (offset + sz > trans->journal->j_blocksize - csum_size) {
206 			jrb->r_count = ext2fs_cpu_to_be32(offset);
207 			jbd2_revoke_csum_set(trans->journal, bh);
208 
209 			err = jbd2_journal_bmap(trans->journal, curr_blk,
210 						&bh->b_blocknr);
211 			if (err)
212 				goto error;
213 			dbg_printf("Writing revoke block at %llu:%llu\n",
214 				   curr_blk, bh->b_blocknr);
215 			mark_buffer_dirty(bh);
216 			ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
217 			err = bh->b_err;
218 			if (err)
219 				goto error;
220 
221 			offset = sizeof(*jrb);
222 			curr_blk++;
223 		}
224 
225 		if (revoke_list[i] >=
226 		    ext2fs_blocks_count(trans->journal->j_fs_dev->k_fs->super)) {
227 			err = EXT2_ET_BAD_BLOCK_NUM;
228 			goto error;
229 		}
230 
231 		if (jbd2_has_feature_64bit(trans->journal))
232 			*((__u64 *)(&((char *)buf)[offset])) =
233 				ext2fs_cpu_to_be64(revoke_list[i]);
234 		else
235 			*((__u32 *)(&((char *)buf)[offset])) =
236 				ext2fs_cpu_to_be32(revoke_list[i]);
237 		offset += sz;
238 	}
239 
240 	if (offset > 0) {
241 		jrb->r_count = ext2fs_cpu_to_be32(offset);
242 		jbd2_revoke_csum_set(trans->journal, bh);
243 
244 		err = jbd2_journal_bmap(trans->journal, curr_blk,
245 					&bh->b_blocknr);
246 		if (err)
247 			goto error;
248 		dbg_printf("Writing revoke block at %llu:%llu\n",
249 			   curr_blk, bh->b_blocknr);
250 		mark_buffer_dirty(bh);
251 		ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
252 		err = bh->b_err;
253 		if (err)
254 			goto error;
255 		curr_blk++;
256 	}
257 
258 error:
259 	trans->block = curr_blk;
260 	brelse(bh);
261 	return err;
262 }
263 
journal_add_blocks_to_trans(journal_transaction_t * trans,blk64_t * block_list,size_t block_len,FILE * fp)264 static errcode_t journal_add_blocks_to_trans(journal_transaction_t *trans,
265 				      blk64_t *block_list, size_t block_len,
266 				      FILE *fp)
267 {
268 	blk64_t curr_blk, jdb_blk;
269 	size_t i, j;
270 	int csum_size = 0;
271 	journal_header_t *jdb;
272 	journal_block_tag_t *jdbt;
273 	int tag_bytes;
274 	void *buf = NULL, *jdb_buf = NULL;
275 	struct buffer_head *bh = NULL, *data_bh;
276 	errcode_t err;
277 
278 	JOURNAL_CHECK_TRANS_MAGIC(trans);
279 
280 	if ((trans->flags & J_TRANS_COMMITTED) ||
281 	    !(trans->flags & J_TRANS_OPEN))
282 		return EXT2_ET_INVALID_ARGUMENT;
283 
284 	if (block_len == 0)
285 		return 0;
286 
287 	/* Do we need to leave space at the end for a checksum? */
288 	if (jbd2_journal_has_csum_v2or3(trans->journal))
289 		csum_size = sizeof(struct jbd2_journal_block_tail);
290 
291 	curr_blk = jdb_blk = trans->block;
292 
293 	data_bh = getblk(trans->journal->j_dev, curr_blk,
294 			 trans->journal->j_blocksize);
295 	if (data_bh == NULL)
296 		return ENOMEM;
297 	buf = data_bh->b_data;
298 
299 	/* write the descriptor block header */
300 	bh = getblk(trans->journal->j_dev, curr_blk,
301 		    trans->journal->j_blocksize);
302 	if (bh == NULL) {
303 		err = ENOMEM;
304 		goto error;
305 	}
306 	jdb = jdb_buf = bh->b_data;
307 	jdb->h_magic = ext2fs_cpu_to_be32(JBD2_MAGIC_NUMBER);
308 	jdb->h_blocktype = ext2fs_cpu_to_be32(JBD2_DESCRIPTOR_BLOCK);
309 	jdb->h_sequence = ext2fs_cpu_to_be32(trans->tid);
310 	jdbt = (journal_block_tag_t *)(jdb + 1);
311 
312 	curr_blk++;
313 	for (i = 0; i < block_len; i++) {
314 		j = fread(data_bh->b_data, trans->journal->j_blocksize, 1, fp);
315 		if (j != 1) {
316 			err = errno;
317 			goto error;
318 		}
319 
320 		tag_bytes = journal_tag_bytes(trans->journal);
321 
322 		/* No space left in descriptor block, write it out */
323 		if ((char *)jdbt + tag_bytes >
324 		    (char *)jdb_buf + trans->journal->j_blocksize - csum_size) {
325 			jbd2_descr_block_csum_set(trans->journal, bh);
326 			err = jbd2_journal_bmap(trans->journal, jdb_blk,
327 					   &bh->b_blocknr);
328 			if (err)
329 				goto error;
330 			dbg_printf("Writing descriptor block at %llu:%llu\n",
331 				   jdb_blk, bh->b_blocknr);
332 			mark_buffer_dirty(bh);
333 			ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
334 			err = bh->b_err;
335 			if (err)
336 				goto error;
337 
338 			jdbt = (journal_block_tag_t *)(jdb + 1);
339 			jdb_blk = curr_blk;
340 			curr_blk++;
341 		}
342 
343 		if (block_list[i] >=
344 		    ext2fs_blocks_count(trans->journal->j_fs_dev->k_fs->super)) {
345 			err = EXT2_ET_BAD_BLOCK_NUM;
346 			goto error;
347 		}
348 
349 		/* Fill out the block tag */
350 		jdbt->t_blocknr = ext2fs_cpu_to_be32(block_list[i] & 0xFFFFFFFF);
351 		jdbt->t_flags = 0;
352 		if (jdbt != (journal_block_tag_t *)(jdb + 1))
353 			jdbt->t_flags |= ext2fs_cpu_to_be16(JBD2_FLAG_SAME_UUID);
354 		else {
355 			memcpy(jdbt + tag_bytes,
356 			       trans->journal->j_superblock->s_uuid,
357 			       sizeof(trans->journal->j_superblock->s_uuid));
358 			tag_bytes += 16;
359 		}
360 		if (i == block_len - 1)
361 			jdbt->t_flags |= ext2fs_cpu_to_be16(JBD2_FLAG_LAST_TAG);
362 		if (*((__u32 *)buf) == ext2fs_cpu_to_be32(JBD2_MAGIC_NUMBER)) {
363 			*((__u32 *)buf) = 0;
364 			jdbt->t_flags |= ext2fs_cpu_to_be16(JBD2_FLAG_ESCAPE);
365 		}
366 		if (jbd2_has_feature_64bit(trans->journal))
367 			jdbt->t_blocknr_high = ext2fs_cpu_to_be32(block_list[i] >> 32);
368 		jbd2_block_tag_csum_set(trans->journal, jdbt, data_bh,
369 					trans->tid);
370 
371 		/* Write the data block */
372 		err = jbd2_journal_bmap(trans->journal, curr_blk,
373 					&data_bh->b_blocknr);
374 		if (err)
375 			goto error;
376 		dbg_printf("Writing data block %llu at %llu:%llu tag %d\n",
377 			   block_list[i], curr_blk, data_bh->b_blocknr,
378 			   tag_bytes);
379 		mark_buffer_dirty(data_bh);
380 		ll_rw_block(REQ_OP_WRITE, 0, 1, &data_bh);
381 		err = data_bh->b_err;
382 		if (err)
383 			goto error;
384 
385 		curr_blk++;
386 		jdbt = (journal_block_tag_t *)(((char *)jdbt) + tag_bytes);
387 	}
388 
389 	/* Write out the last descriptor block */
390 	if (jdbt != (journal_block_tag_t *)(jdb + 1)) {
391 		jbd2_descr_block_csum_set(trans->journal, bh);
392 		err = jbd2_journal_bmap(trans->journal, jdb_blk,
393 					&bh->b_blocknr);
394 		if (err)
395 			goto error;
396 		dbg_printf("Writing descriptor block at %llu:%llu\n",
397 			   jdb_blk, bh->b_blocknr);
398 		mark_buffer_dirty(bh);
399 		ll_rw_block(REQ_OP_WRITE, 0, 1, &bh);
400 		err = bh->b_err;
401 		if (err)
402 			goto error;
403 	}
404 
405 error:
406 	trans->block = curr_blk;
407 	if (bh)
408 		brelse(bh);
409 	brelse(data_bh);
410 	return err;
411 }
412 
journal_guess_blocks(journal_t * journal,blk64_t data_blocks,blk64_t revoke_blocks)413 static blk64_t journal_guess_blocks(journal_t *journal, blk64_t data_blocks,
414 				    blk64_t revoke_blocks)
415 {
416 	blk64_t ret = 1;
417 	unsigned int bs, sz;
418 
419 	/* Estimate # of revoke blocks */
420 	bs = journal->j_blocksize;
421 	if (jbd2_journal_has_csum_v2or3(journal))
422 		bs -= sizeof(struct jbd2_journal_block_tail);
423 	sz = jbd2_has_feature_64bit(journal) ? sizeof(__u64) : sizeof(__u32);
424 	ret += revoke_blocks * sz / bs;
425 
426 	/* Estimate # of data blocks */
427 	bs = journal->j_blocksize - 16;
428 	if (jbd2_journal_has_csum_v2or3(journal))
429 		bs -= sizeof(struct jbd2_journal_block_tail);
430 	sz = journal_tag_bytes(journal);
431 	ret += data_blocks * sz / bs;
432 
433 	ret += data_blocks;
434 
435 	return ret;
436 }
437 
journal_open_trans(journal_t * journal,journal_transaction_t * trans,blk64_t blocks)438 static errcode_t journal_open_trans(journal_t *journal,
439 				    journal_transaction_t *trans,
440 				    blk64_t blocks)
441 {
442 	trans->fs = journal->j_fs_dev->k_fs;
443 	trans->journal = journal;
444 	trans->flags = J_TRANS_OPEN;
445 
446 	if (journal->j_tail == 0) {
447 		/* Clean journal, start at the tail */
448 		trans->tid = journal->j_tail_sequence;
449 		trans->start = journal->j_first;
450 	} else {
451 		/* Put new transaction at the head of the list */
452 		trans->tid = journal->j_transaction_sequence;
453 		trans->start = journal->j_head;
454 	}
455 
456 	trans->block = trans->start;
457 	if (trans->start + blocks > journal->j_last)
458 		return ENOSPC;
459 	trans->end = trans->block + blocks;
460 	journal_dump_trans(trans, "new transaction");
461 
462 	trans->magic = J_TRANS_MAGIC;
463 	return 0;
464 }
465 
journal_close_trans(journal_transaction_t * trans)466 static errcode_t journal_close_trans(journal_transaction_t *trans)
467 {
468 	journal_t *journal;
469 
470 	JOURNAL_CHECK_TRANS_MAGIC(trans);
471 
472 	if (!(trans->flags & J_TRANS_COMMITTED))
473 		return 0;
474 
475 	journal = trans->journal;
476 	if (journal->j_tail == 0) {
477 		/* Update the tail */
478 		journal->j_tail_sequence = trans->tid;
479 		journal->j_tail = trans->start;
480 		journal->j_superblock->s_start = ext2fs_cpu_to_be32(trans->start);
481 	}
482 
483 	/* Update the head */
484 	journal->j_head = trans->end + 1;
485 	journal->j_transaction_sequence = trans->tid + 1;
486 
487 	trans->magic = 0;
488 
489 	/* Mark ourselves as needing recovery */
490 	if (!ext2fs_has_feature_journal_needs_recovery(trans->fs->super)) {
491 		ext2fs_set_feature_journal_needs_recovery(trans->fs->super);
492 		ext2fs_mark_super_dirty(trans->fs);
493 	}
494 
495 	return 0;
496 }
497 
498 #define JOURNAL_WRITE_NO_COMMIT		1
journal_write(journal_t * journal,int flags,blk64_t * block_list,size_t block_len,blk64_t * revoke_list,size_t revoke_len,FILE * fp)499 static errcode_t journal_write(journal_t *journal,
500 			       int flags, blk64_t *block_list,
501 			       size_t block_len, blk64_t *revoke_list,
502 			       size_t revoke_len, FILE *fp)
503 {
504 	blk64_t blocks;
505 	journal_transaction_t trans;
506 	errcode_t err;
507 
508 	if (revoke_len > 0) {
509 		jbd2_set_feature_revoke(journal);
510 		mark_buffer_dirty(journal->j_sb_buffer);
511 	}
512 
513 	blocks = journal_guess_blocks(journal, block_len, revoke_len);
514 	err = journal_open_trans(journal, &trans, blocks);
515 	if (err)
516 		goto error;
517 
518 	err = journal_add_blocks_to_trans(&trans, block_list, block_len, fp);
519 	if (err)
520 		goto error;
521 
522 	err = journal_add_revoke_to_trans(&trans, revoke_list, revoke_len);
523 	if (err)
524 		goto error;
525 
526 	if (!(flags & JOURNAL_WRITE_NO_COMMIT)) {
527 		err = journal_commit_trans(&trans);
528 		if (err)
529 			goto error;
530 	}
531 
532 	err = journal_close_trans(&trans);
533 error:
534 	return err;
535 }
536 
do_journal_write(int argc,char * argv[],int sci_idx EXT2FS_ATTR ((unused)),void * infop EXT2FS_ATTR ((unused)))537 void do_journal_write(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
538 		      void *infop EXT2FS_ATTR((unused)))
539 {
540 	blk64_t *blist = NULL, *rlist = NULL;
541 	size_t bn = 0, rn = 0;
542 	FILE *fp = NULL;
543 	int opt;
544 	int flags = 0;
545 	errcode_t err;
546 
547 	if (current_journal == NULL) {
548 		printf("Journal not open.\n");
549 		return;
550 	}
551 
552 	reset_getopt();
553 	while ((opt = getopt(argc, argv, "b:r:c")) != -1) {
554 		switch (opt) {
555 		case 'b':
556 			err = read_list(optarg, &blist, &bn);
557 			if (err) {
558 				com_err(argv[0], err,
559 					"while reading block list");
560 				goto out;
561 			}
562 			break;
563 		case 'r':
564 			err = read_list(optarg, &rlist, &rn);
565 			if (err) {
566 				com_err(argv[0], err,
567 					"while reading revoke list");
568 				goto out;
569 			}
570 			break;
571 		case 'c':
572 			flags |= JOURNAL_WRITE_NO_COMMIT;
573 			break;
574 		default:
575 			printf("%s [-b blocks] [-r revoke] [-c] file\n",
576 			       argv[0]);
577 			printf("-b: Write these blocks into transaction.\n");
578 			printf("-c: Do not commit transaction.\n");
579 			printf("-r: Revoke these blocks from transaction.\n");
580 
581 			goto out;
582 		}
583 	}
584 
585 	if (bn > 0 && optind != argc - 1) {
586 		printf("Need a file to read blocks from.\n");
587 		return;
588 	}
589 
590 	if (bn > 0) {
591 		fp = fopen(argv[optind], "r");
592 		if (fp == NULL) {
593 			com_err(argv[0], errno,
594 				"while opening journal data file");
595 			goto out;
596 		}
597 	}
598 
599 	err = journal_write(current_journal, flags, blist, bn,
600 			    rlist, rn, fp);
601 	if (err)
602 		com_err("journal_write", err, "while writing journal");
603 
604 	if (fp)
605 		fclose(fp);
606 out:
607 	if (blist)
608 		free(blist);
609 	if (rlist)
610 		free(rlist);
611 }
612 
613 /* Make sure we wrap around the log correctly! */
614 #define wrap(journal, var)						\
615 do {									\
616 	if (var >= (journal)->j_last)					\
617 		var -= ((journal)->j_last - (journal)->j_first);	\
618 } while (0)
619 
620 /*
621  * Count the number of in-use tags in a journal descriptor block.
622  */
623 
count_tags(journal_t * journal,char * buf)624 static int count_tags(journal_t *journal, char *buf)
625 {
626 	char			*tagp;
627 	journal_block_tag_t	*tag;
628 	int			nr = 0, size = journal->j_blocksize;
629 	int			tag_bytes = journal_tag_bytes(journal);
630 
631 	if (jbd2_journal_has_csum_v2or3(journal))
632 		size -= sizeof(struct jbd2_journal_block_tail);
633 
634 	tagp = buf + sizeof(journal_header_t);
635 
636 	while ((tagp - buf + tag_bytes) <= size) {
637 		tag = (journal_block_tag_t *) tagp;
638 
639 		nr++;
640 		tagp += tag_bytes;
641 		if (!(tag->t_flags & ext2fs_cpu_to_be16(JBD2_FLAG_SAME_UUID)))
642 			tagp += 16;
643 
644 		if (tag->t_flags & ext2fs_cpu_to_be16(JBD2_FLAG_LAST_TAG))
645 			break;
646 	}
647 
648 	return nr;
649 }
650 
journal_find_head(journal_t * journal)651 static errcode_t journal_find_head(journal_t *journal)
652 {
653 	unsigned int		next_commit_ID;
654 	blk64_t			next_log_block, head_block;
655 	int			err;
656 	journal_superblock_t	*sb;
657 	journal_header_t	*tmp;
658 	struct buffer_head	*bh;
659 	unsigned int		sequence;
660 	int			blocktype;
661 
662 	/*
663 	 * First thing is to establish what we expect to find in the log
664 	 * (in terms of transaction IDs), and where (in terms of log
665 	 * block offsets): query the superblock.
666 	 */
667 
668 	sb = journal->j_superblock;
669 	next_commit_ID = ext2fs_be32_to_cpu(sb->s_sequence);
670 	next_log_block = ext2fs_be32_to_cpu(sb->s_start);
671 	head_block = next_log_block;
672 
673 	if (next_log_block == 0)
674 		return 0;
675 
676 	bh = getblk(journal->j_dev, 0, journal->j_blocksize);
677 	if (bh == NULL)
678 		return ENOMEM;
679 
680 	/*
681 	 * Now we walk through the log, transaction by transaction,
682 	 * making sure that each transaction has a commit block in the
683 	 * expected place.  Each complete transaction gets replayed back
684 	 * into the main filesystem.
685 	 */
686 	while (1) {
687 		dbg_printf("Scanning for sequence ID %u at %lu/%lu\n",
688 			  next_commit_ID, (unsigned long)next_log_block,
689 			  journal->j_last);
690 
691 		/* Skip over each chunk of the transaction looking
692 		 * either the next descriptor block or the final commit
693 		 * record. */
694 		err = jbd2_journal_bmap(journal, next_log_block,
695 					&bh->b_blocknr);
696 		if (err)
697 			goto err;
698 		mark_buffer_uptodate(bh, 0);
699 		ll_rw_block(REQ_OP_READ, 0, 1, &bh);
700 		err = bh->b_err;
701 		if (err)
702 			goto err;
703 
704 		next_log_block++;
705 		wrap(journal, next_log_block);
706 
707 		/* What kind of buffer is it?
708 		 *
709 		 * If it is a descriptor block, check that it has the
710 		 * expected sequence number.  Otherwise, we're all done
711 		 * here. */
712 
713 		tmp = (journal_header_t *)bh->b_data;
714 
715 		if (tmp->h_magic != ext2fs_cpu_to_be32(JBD2_MAGIC_NUMBER)) {
716 			dbg_printf("JBD2: wrong magic 0x%x\n", tmp->h_magic);
717 			goto err;
718 		}
719 
720 		blocktype = ext2fs_be32_to_cpu(tmp->h_blocktype);
721 		sequence = ext2fs_be32_to_cpu(tmp->h_sequence);
722 		dbg_printf("Found magic %d, sequence %d\n",
723 			  blocktype, sequence);
724 
725 		if (sequence != next_commit_ID) {
726 			dbg_printf("JBD2: Wrong sequence %d (wanted %d)\n",
727 				   sequence, next_commit_ID);
728 			goto err;
729 		}
730 
731 		/* OK, we have a valid descriptor block which matches
732 		 * all of the sequence number checks.  What are we going
733 		 * to do with it?  That depends on the pass... */
734 
735 		switch (blocktype) {
736 		case JBD2_DESCRIPTOR_BLOCK:
737 			next_log_block += count_tags(journal, bh->b_data);
738 			wrap(journal, next_log_block);
739 			continue;
740 
741 		case JBD2_COMMIT_BLOCK:
742 			head_block = next_log_block;
743 			next_commit_ID++;
744 			continue;
745 
746 		case JBD2_REVOKE_BLOCK:
747 			continue;
748 
749 		default:
750 			dbg_printf("Unrecognised magic %d, end of scan.\n",
751 				  blocktype);
752 			err = -EINVAL;
753 			goto err;
754 		}
755 	}
756 
757 err:
758 	if (err == 0) {
759 		dbg_printf("head seq=%d blk=%llu\n", next_commit_ID,
760 			   head_block);
761 		journal->j_transaction_sequence = next_commit_ID;
762 		journal->j_head = head_block;
763 	}
764 	brelse(bh);
765 	return err;
766 }
767 
update_journal_csum(journal_t * journal,int ver)768 static void update_journal_csum(journal_t *journal, int ver)
769 {
770 	journal_superblock_t *jsb;
771 
772 	if (journal->j_format_version < 2)
773 		return;
774 
775 	if (journal->j_tail != 0 ||
776 	    ext2fs_has_feature_journal_needs_recovery(
777 					journal->j_fs_dev->k_fs->super)) {
778 		printf("Journal needs recovery, will not add csums.\n");
779 		return;
780 	}
781 
782 	/* metadata_csum implies journal csum v3 */
783 	jsb = journal->j_superblock;
784 	if (ext2fs_has_feature_metadata_csum(journal->j_fs_dev->k_fs->super)) {
785 		printf("Setting csum v%d\n", ver);
786 		switch (ver) {
787 		case 2:
788 			jbd2_clear_feature_csum3(journal);
789 			jbd2_set_feature_csum2(journal);
790 			jbd2_clear_feature_checksum(journal);
791 			break;
792 		case 3:
793 			jbd2_set_feature_csum3(journal);
794 			jbd2_clear_feature_csum2(journal);
795 			jbd2_clear_feature_checksum(journal);
796 			break;
797 		default:
798 			printf("Unknown checksum v%d\n", ver);
799 			break;
800 		}
801 		journal->j_superblock->s_checksum_type = JBD2_CRC32C_CHKSUM;
802 		journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid,
803 						   sizeof(jsb->s_uuid));
804 	} else {
805 		jbd2_clear_feature_csum3(journal);
806 		jbd2_clear_feature_csum2(journal);
807 		jbd2_set_feature_checksum(journal);
808 	}
809 }
810 
update_uuid(journal_t * journal)811 static void update_uuid(journal_t *journal)
812 {
813 	size_t z;
814 	ext2_filsys fs;
815 
816 	if (journal->j_format_version < 2)
817 		return;
818 
819 	for (z = 0; z < sizeof(journal->j_superblock->s_uuid); z++)
820 		if (journal->j_superblock->s_uuid[z])
821 			break;
822 	if (z == 0)
823 		return;
824 
825 	fs = journal->j_fs_dev->k_fs;
826 	if (!ext2fs_has_feature_64bit(fs->super))
827 		return;
828 
829 	if (jbd2_has_feature_64bit(journal) &&
830 	    ext2fs_has_feature_64bit(fs->super))
831 		return;
832 
833 	if (journal->j_tail != 0 ||
834 	    ext2fs_has_feature_journal_needs_recovery(fs->super)) {
835 		printf("Journal needs recovery, will not set 64bit.\n");
836 		return;
837 	}
838 
839 	memcpy(journal->j_superblock->s_uuid, fs->super->s_uuid,
840 	       sizeof(fs->super->s_uuid));
841 }
842 
update_64bit_flag(journal_t * journal)843 static void update_64bit_flag(journal_t *journal)
844 {
845 	if (journal->j_format_version < 2)
846 		return;
847 
848 	if (!ext2fs_has_feature_64bit(journal->j_fs_dev->k_fs->super))
849 		return;
850 
851 	if (jbd2_has_feature_64bit(journal) &&
852 	    ext2fs_has_feature_64bit(journal->j_fs_dev->k_fs->super))
853 		return;
854 
855 	if (journal->j_tail != 0 ||
856 	    ext2fs_has_feature_journal_needs_recovery(
857 				journal->j_fs_dev->k_fs->super)) {
858 		printf("Journal needs recovery, will not set 64bit.\n");
859 		return;
860 	}
861 
862 	jbd2_set_feature_64bit(journal);
863 }
864 
do_journal_open(int argc,char * argv[],int sci_idx EXT2FS_ATTR ((unused)),void * infop EXT2FS_ATTR ((unused)))865 void do_journal_open(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)),
866 		     void *infop EXT2FS_ATTR((unused)))
867 {
868 	int opt, enable_csum = 0, csum_ver = 3;
869 	journal_t *journal;
870 	errcode_t err;
871 
872 	if (check_fs_open(argv[0]))
873 		return;
874 	if (check_fs_read_write(argv[0]))
875 		return;
876 	if (check_fs_bitmaps(argv[0]))
877 		return;
878 	if (current_journal) {
879 		printf("Journal is already open.\n");
880 		return;
881 	}
882 	if (!ext2fs_has_feature_journal(current_fs->super)) {
883 		printf("Journalling is not enabled on this filesystem.\n");
884 		return;
885 	}
886 
887 	reset_getopt();
888 	while ((opt = getopt(argc, argv, "cv:f:")) != -1) {
889 		switch (opt) {
890 		case 'c':
891 			enable_csum = 1;
892 			break;
893 		case 'f':
894 			if (current_fs->journal_name)
895 				free(current_fs->journal_name);
896 			current_fs->journal_name = strdup(optarg);
897 			break;
898 		case 'v':
899 			csum_ver = atoi(optarg);
900 			if (csum_ver != 2 && csum_ver != 3) {
901 				printf("Unknown journal csum v%d\n", csum_ver);
902 				csum_ver = 3;
903 			}
904 			break;
905 		default:
906 			printf("%s: [-c] [-v ver] [-f ext_jnl]\n", argv[0]);
907 			printf("-c: Enable journal checksumming.\n");
908 			printf("-v: Use this version checksum format.\n");
909 			printf("-f: Load this external journal.\n");
910 		}
911 	}
912 
913 	err = ext2fs_open_journal(current_fs, &current_journal);
914 	if (err) {
915 		com_err(argv[0], err, "while opening journal");
916 		return;
917 	}
918 	journal = current_journal;
919 
920 	dbg_printf("JOURNAL: seq=%u tailseq=%u start=%lu first=%lu "
921 		   "maxlen=%lu\n", journal->j_tail_sequence,
922 		   journal->j_transaction_sequence, journal->j_tail,
923 		   journal->j_first, journal->j_last);
924 
925 	update_uuid(journal);
926 	update_64bit_flag(journal);
927 	if (enable_csum)
928 		update_journal_csum(journal, csum_ver);
929 
930 	err = journal_find_head(journal);
931 	if (err)
932 		com_err(argv[0], err, "while examining journal");
933 }
934 
do_journal_close(int argc EXT2FS_ATTR ((unused)),char * argv[]EXT2FS_ATTR ((unused)),int sci_idx EXT2FS_ATTR ((unused)),void * infop EXT2FS_ATTR ((unused)))935 void do_journal_close(int argc EXT2FS_ATTR((unused)),
936 		      char *argv[] EXT2FS_ATTR((unused)),
937 		      int sci_idx EXT2FS_ATTR((unused)),
938 		      void *infop EXT2FS_ATTR((unused)))
939 {
940 	if (current_journal == NULL) {
941 		printf("Journal not open.\n");
942 		return;
943 	}
944 
945 	ext2fs_close_journal(current_fs, &current_journal);
946 }
947 
do_journal_run(int argc EXT2FS_ATTR ((unused)),char * argv[],int sci_idx EXT2FS_ATTR ((unused)),void * infop EXT2FS_ATTR ((unused)))948 void do_journal_run(int argc EXT2FS_ATTR((unused)), char *argv[],
949 		    int sci_idx EXT2FS_ATTR((unused)),
950 		    void *infop EXT2FS_ATTR((unused)))
951 {
952 	errcode_t err;
953 
954 	if (check_fs_open(argv[0]))
955 		return;
956 	if (check_fs_read_write(argv[0]))
957 		return;
958 	if (check_fs_bitmaps(argv[0]))
959 		return;
960 	if (current_journal) {
961 		printf("Please close the journal before recovering it.\n");
962 		return;
963 	}
964 
965 	err = ext2fs_run_ext3_journal(&current_fs);
966 	if (err)
967 		com_err("journal_run", err, "while recovering journal");
968 	else {
969 		ext2fs_clear_feature_journal_needs_recovery(current_fs->super);
970 		ext2fs_mark_super_dirty(current_fs);
971 	}
972 }
973