1 ext4: Add the journal checksum feature
3 From: Girish Shilamkar <girish@clusterfs.com>
5 The journal checksum feature adds two new flags i.e
6 JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT and JBD2_FEATURE_COMPAT_CHECKSUM.
8 JBD2_FEATURE_CHECKSUM flag indicates that the commit block contains the
9 checksum for the blocks described by the descriptor blocks.
10 Due to checksums, writing of the commit record no longer needs to be
11 synchronous. Now commit record can be sent to disk without waiting for
12 descriptor blocks to be written to disk. This behavior is controlled
13 using JBD2_FEATURE_ASYNC_COMMIT flag. Older kernels/e2fsck should not be
14 able to recover the journal with _ASYNC_COMMIT hence it is made
16 The commit header has been extended to hold the checksum along with the
19 For recovery in pass scan checksums are verified to ensure the sanity
20 and completeness(in case of _ASYNC_COMMIT) of every transaction.
22 Signed-off-by: Andreas Dilger <adilger@clusterfs.com>
23 Signed-off-by: Girish Shilamkar <girish@clusterfs.com>
24 Signed-off-by: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
25 Signed-off-by: Mingming Cao <cmm@us.ibm.com>
28 fs/ext4/super.c | 25 ++++++
29 fs/jbd2/commit.c | 175 ++++++++++++++++++++++++++++++++++++------------
30 fs/jbd2/journal.c | 28 +++++++
31 fs/jbd2/recovery.c | 125 ++++++++++++++++++++++++++++++++--
32 include/linux/ext4_fs.h | 3
33 include/linux/jbd2.h | 37 +++++++++-
34 6 files changed, 338 insertions(+), 55 deletions(-)
37 Index: linux-2.6.23-rc6/fs/ext4/super.c
38 ===================================================================
39 --- linux-2.6.23-rc6.orig/fs/ext4/super.c 2007-09-20 17:25:46.000000000 -0700
40 +++ linux-2.6.23-rc6/fs/ext4/super.c 2007-09-20 17:25:49.000000000 -0700
41 @@ -733,6 +733,7 @@ enum {
42 Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
43 Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh,
44 Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
45 + Opt_journal_checksum, Opt_journal_async_commit,
46 Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
47 Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
48 Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
49 @@ -772,6 +773,8 @@ static match_table_t tokens = {
50 {Opt_journal_update, "journal=update"},
51 {Opt_journal_inum, "journal=%u"},
52 {Opt_journal_dev, "journal_dev=%u"},
53 + {Opt_journal_checksum, "journal_checksum"},
54 + {Opt_journal_async_commit, "journal_async_commit"},
56 {Opt_data_journal, "data=journal"},
57 {Opt_data_ordered, "data=ordered"},
58 @@ -959,6 +962,13 @@ static int parse_options (char *options,
60 *journal_devnum = option;
62 + case Opt_journal_checksum:
63 + set_opt (sbi->s_mount_opt, JOURNAL_CHECKSUM);
65 + case Opt_journal_async_commit:
66 + set_opt (sbi->s_mount_opt, JOURNAL_ASYNC_COMMIT);
67 + set_opt (sbi->s_mount_opt, JOURNAL_CHECKSUM);
70 set_opt (sbi->s_mount_opt, NOLOAD);
72 @@ -1875,6 +1885,21 @@ static int ext4_fill_super (struct super
76 + if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
77 + jbd2_journal_set_features(sbi->s_journal,
78 + JBD2_FEATURE_COMPAT_CHECKSUM, 0,
79 + JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT);
80 + } else if (test_opt(sb, JOURNAL_CHECKSUM)) {
81 + jbd2_journal_set_features(sbi->s_journal,
82 + JBD2_FEATURE_COMPAT_CHECKSUM, 0, 0);
83 + jbd2_journal_clear_features(sbi->s_journal, 0, 0,
84 + JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT);
86 + jbd2_journal_clear_features(sbi->s_journal,
87 + JBD2_FEATURE_COMPAT_CHECKSUM, 0,
88 + JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT);
91 /* We have now updated the journal if required, so we can
92 * validate the data journaling mode. */
93 switch (test_opt(sb, DATA_FLAGS)) {
94 Index: linux-2.6.23-rc6/fs/jbd2/commit.c
95 ===================================================================
96 --- linux-2.6.23-rc6.orig/fs/jbd2/commit.c 2007-09-19 11:37:41.000000000 -0700
97 +++ linux-2.6.23-rc6/fs/jbd2/commit.c 2007-09-20 17:25:49.000000000 -0700
99 #include <linux/slab.h>
100 #include <linux/mm.h>
101 #include <linux/pagemap.h>
102 +#include <linux/crc32.h>
105 * Default IO end handler for temporary BJ_IO buffer_heads.
106 @@ -92,15 +93,18 @@ static int inverted_lock(journal_t *jour
110 -/* Done it all: now write the commit record. We should have
112 + * Done it all: now submit the commit record. We should have
113 * cleaned up our previous buffers by now, so if we are in abort
114 * mode we can now just skip the rest of the journal write
117 * Returns 1 if the journal needs to be aborted or 0 on success
119 -static int journal_write_commit_record(journal_t *journal,
120 - transaction_t *commit_transaction)
121 +static int journal_submit_commit_record(journal_t *journal,
122 + transaction_t *commit_transaction,
123 + struct buffer_head **cbh,
126 struct journal_head *descriptor;
127 struct buffer_head *bh;
128 @@ -116,21 +120,36 @@ static int journal_write_commit_record(j
130 bh = jh2bh(descriptor);
132 - /* AKPM: buglet - add `i' to tmp! */
133 for (i = 0; i < bh->b_size; i += 512) {
134 - journal_header_t *tmp = (journal_header_t*)bh->b_data;
135 + struct commit_header *tmp =
136 + (struct commit_header *)(bh->b_data + i);
137 tmp->h_magic = cpu_to_be32(JBD2_MAGIC_NUMBER);
138 tmp->h_blocktype = cpu_to_be32(JBD2_COMMIT_BLOCK);
139 tmp->h_sequence = cpu_to_be32(commit_transaction->t_tid);
141 + if (JBD2_HAS_COMPAT_FEATURE(journal,
142 + JBD2_FEATURE_COMPAT_CHECKSUM)) {
143 + tmp->h_chksum_type = JBD2_CRC32_CHKSUM;
144 + tmp->h_chksum_size = JBD2_CRC32_CHKSUM_SIZE;
145 + tmp->h_chksum[0] = cpu_to_be32(crc32_sum);
149 - JBUFFER_TRACE(descriptor, "write commit block");
150 + JBUFFER_TRACE(descriptor, "submit commit block");
153 set_buffer_dirty(bh);
154 - if (journal->j_flags & JBD2_BARRIER) {
155 + set_buffer_uptodate(bh);
156 + bh->b_end_io = journal_end_buffer_io_sync;
158 + if (journal->j_flags & JBD2_BARRIER &&
159 + !JBD2_HAS_COMPAT_FEATURE(journal,
160 + JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
161 set_buffer_ordered(bh);
164 - ret = sync_dirty_buffer(bh);
165 + ret = submit_bh(WRITE, bh);
167 /* is it possible for another commit to fail at roughly
168 * the same time as this one? If so, we don't want to
169 * trust the barrier flag in the super, but instead want
170 @@ -151,14 +170,72 @@ static int journal_write_commit_record(j
171 clear_buffer_ordered(bh);
172 set_buffer_uptodate(bh);
173 set_buffer_dirty(bh);
174 - ret = sync_dirty_buffer(bh);
175 + ret = submit_bh(WRITE, bh);
177 - put_bh(bh); /* One for getblk() */
178 - jbd2_journal_put_journal_head(descriptor);
184 + * This function along with journal_submit_commit_record
185 + * allows to write the commit record asynchronously.
187 +static int journal_wait_on_commit_record(struct buffer_head *bh)
191 - return (ret == -EIO);
192 + if (buffer_locked(bh))
193 + wait_on_buffer(bh);
195 + if (unlikely(!buffer_uptodate(bh)))
197 + put_bh(bh); /* One for getblk() */
198 + jbd2_journal_put_journal_head(bh2jh(bh));
204 + * Wait for all submitted IO to complete.
206 +static int journal_wait_on_locked_list(journal_t *journal,
207 + transaction_t *commit_transaction)
210 + struct journal_head *jh;
212 + while (commit_transaction->t_locked_list) {
213 + struct buffer_head *bh;
215 + jh = commit_transaction->t_locked_list->b_tprev;
218 + if (buffer_locked(bh)) {
219 + spin_unlock(&journal->j_list_lock);
220 + wait_on_buffer(bh);
221 + if (unlikely(!buffer_uptodate(bh)))
223 + spin_lock(&journal->j_list_lock);
225 + if (!inverted_lock(journal, bh)) {
227 + spin_lock(&journal->j_list_lock);
230 + if (buffer_jbd(bh) && jh->b_jlist == BJ_Locked) {
231 + __jbd2_journal_unfile_buffer(jh);
232 + jbd_unlock_bh_state(bh);
233 + jbd2_journal_remove_journal_head(bh);
236 + jbd_unlock_bh_state(bh);
239 + cond_resched_lock(&journal->j_list_lock);
244 static void journal_do_submit_data(struct buffer_head **wbuf, int bufs)
247 @@ -305,6 +382,8 @@ void jbd2_journal_commit_transaction(jou
250 int tag_bytes = journal_tag_bytes(journal);
251 + struct buffer_head *cbh = NULL; /* For transactional checksums */
252 + __u32 crc32_sum = ~0;
255 * First job: lock down the current transaction and wait for
256 @@ -440,38 +519,15 @@ void jbd2_journal_commit_transaction(jou
257 journal_submit_data_buffers(journal, commit_transaction);
260 - * Wait for all previously submitted IO to complete.
261 + * Wait for all previously submitted IO to complete if commit
262 + * record is to be written synchronously.
264 spin_lock(&journal->j_list_lock);
265 - while (commit_transaction->t_locked_list) {
266 - struct buffer_head *bh;
267 + if (!JBD2_HAS_INCOMPAT_FEATURE(journal,
268 + JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT))
269 + err = journal_wait_on_locked_list(journal,
270 + commit_transaction);
272 - jh = commit_transaction->t_locked_list->b_tprev;
275 - if (buffer_locked(bh)) {
276 - spin_unlock(&journal->j_list_lock);
277 - wait_on_buffer(bh);
278 - if (unlikely(!buffer_uptodate(bh)))
280 - spin_lock(&journal->j_list_lock);
282 - if (!inverted_lock(journal, bh)) {
284 - spin_lock(&journal->j_list_lock);
287 - if (buffer_jbd(bh) && jh->b_jlist == BJ_Locked) {
288 - __jbd2_journal_unfile_buffer(jh);
289 - jbd_unlock_bh_state(bh);
290 - jbd2_journal_remove_journal_head(bh);
293 - jbd_unlock_bh_state(bh);
296 - cond_resched_lock(&journal->j_list_lock);
298 spin_unlock(&journal->j_list_lock);
301 @@ -639,6 +695,16 @@ void jbd2_journal_commit_transaction(jou
303 for (i = 0; i < bufs; i++) {
304 struct buffer_head *bh = wbuf[i];
306 + * Compute checksum.
308 + if (JBD2_HAS_COMPAT_FEATURE(journal,
309 + JBD2_FEATURE_COMPAT_CHECKSUM)) {
310 + crc32_sum = crc32_be(crc32_sum,
311 + (void *)bh->b_data,
316 clear_buffer_dirty(bh);
317 set_buffer_uptodate(bh);
318 @@ -654,6 +720,23 @@ start_journal_io:
322 + /* Done it all: now write the commit record asynchronously. */
324 + if (JBD2_HAS_INCOMPAT_FEATURE(journal,
325 + JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
326 + err = journal_submit_commit_record(journal, commit_transaction,
329 + __jbd2_journal_abort_hard(journal);
331 + spin_lock(&journal->j_list_lock);
332 + err = journal_wait_on_locked_list(journal,
333 + commit_transaction);
334 + spin_unlock(&journal->j_list_lock);
336 + __jbd2_journal_abort_hard(journal);
339 /* Lo and behold: we have just managed to send a transaction to
340 the log. Before we can commit it, wait for the IO so far to
341 complete. Control buffers being written are on the
342 @@ -753,8 +836,14 @@ wait_for_iobuf:
344 jbd_debug(3, "JBD: commit phase 6\n");
346 - if (journal_write_commit_record(journal, commit_transaction))
348 + if (!JBD2_HAS_INCOMPAT_FEATURE(journal,
349 + JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
350 + err = journal_submit_commit_record(journal, commit_transaction,
353 + __jbd2_journal_abort_hard(journal);
355 + err = journal_wait_on_commit_record(cbh);
358 __jbd2_journal_abort_hard(journal);
359 Index: linux-2.6.23-rc6/fs/jbd2/journal.c
360 ===================================================================
361 --- linux-2.6.23-rc6.orig/fs/jbd2/journal.c 2007-09-19 14:23:45.000000000 -0700
362 +++ linux-2.6.23-rc6/fs/jbd2/journal.c 2007-09-20 17:25:49.000000000 -0700
363 @@ -65,6 +65,7 @@ EXPORT_SYMBOL(jbd2_journal_update_format
364 EXPORT_SYMBOL(jbd2_journal_check_used_features);
365 EXPORT_SYMBOL(jbd2_journal_check_available_features);
366 EXPORT_SYMBOL(jbd2_journal_set_features);
367 +EXPORT_SYMBOL(jbd2_journal_clear_features);
368 EXPORT_SYMBOL(jbd2_journal_create);
369 EXPORT_SYMBOL(jbd2_journal_load);
370 EXPORT_SYMBOL(jbd2_journal_destroy);
371 @@ -1265,6 +1266,33 @@ int jbd2_journal_set_features (journal_t
376 + * int jbd2_journal_clear_features () - Clear a given journal feature in the superblock
377 + * @journal: Journal to act on.
378 + * @compat: bitmask of compatible features
379 + * @ro: bitmask of features that force read-only mount
380 + * @incompat: bitmask of incompatible features
382 + * Clear a given journal feature as present on the
383 + * superblock. Returns true if the requested features could be reset.
386 +int jbd2_journal_clear_features (journal_t *journal, unsigned long compat,
387 + unsigned long ro, unsigned long incompat)
389 + journal_superblock_t *sb;
391 + jbd_debug(1, "Clear features 0x%lx/0x%lx/0x%lx\n",
392 + compat, ro, incompat);
394 + sb = journal->j_superblock;
396 + sb->s_feature_compat &= ~cpu_to_be32(compat);
397 + sb->s_feature_ro_compat &= ~cpu_to_be32(ro);
398 + sb->s_feature_incompat &= ~cpu_to_be32(incompat);
404 * int jbd2_journal_update_format () - Update on-disk journal structure.
405 Index: linux-2.6.23-rc6/fs/jbd2/recovery.c
406 ===================================================================
407 --- linux-2.6.23-rc6.orig/fs/jbd2/recovery.c 2007-09-19 11:37:35.000000000 -0700
408 +++ linux-2.6.23-rc6/fs/jbd2/recovery.c 2007-09-20 17:25:49.000000000 -0700
410 #include <linux/jbd2.h>
411 #include <linux/errno.h>
412 #include <linux/slab.h>
413 +#include <linux/crc32.h>
417 @@ -316,6 +317,37 @@ static inline unsigned long long read_ta
422 + * cal_chksums calculates the checksums for the blocks described in the
423 + * descriptor block.
425 +static int cal_chksums(journal_t *journal, struct buffer_head *bh,
426 + unsigned long *next_log_block, __u32 *crc32_sum)
428 + int i, num_blks, err;
429 + unsigned long io_block;
430 + struct buffer_head *obh;
432 + num_blks = count_tags(journal, bh);
433 + /* Calculate checksum of the descriptor block. */
434 + *crc32_sum = crc32_be(*crc32_sum, (void *)bh->b_data, bh->b_size);
436 + for (i = 0; i < num_blks; i++) {
437 + io_block = (*next_log_block)++;
438 + wrap(journal, *next_log_block);
439 + err = jread(&obh, journal, io_block);
441 + printk(KERN_ERR "JBD: IO error %d recovering block "
442 + "%ld in log\n", err, io_block);
445 + *crc32_sum = crc32_be(*crc32_sum, (void *)obh->b_data,
452 static int do_one_pass(journal_t *journal,
453 struct recovery_info *info, enum passtype pass)
455 @@ -328,6 +360,7 @@ static int do_one_pass(journal_t *journa
456 unsigned int sequence;
458 int tag_bytes = journal_tag_bytes(journal);
459 + __u32 crc32_sum = ~0; /* Transactional Checksums */
461 /* Precompute the maximum metadata descriptors in a descriptor block */
462 int MAX_BLOCKS_PER_DESC;
463 @@ -419,9 +452,23 @@ static int do_one_pass(journal_t *journa
465 case JBD2_DESCRIPTOR_BLOCK:
466 /* If it is a valid descriptor block, replay it
467 - * in pass REPLAY; otherwise, just skip over the
468 - * blocks it describes. */
469 + * in pass REPLAY; if journal_checksums enabled, then
470 + * calculate checksums in PASS_SCAN, otherwise,
471 + * just skip over the blocks it describes. */
472 if (pass != PASS_REPLAY) {
473 + if (pass == PASS_SCAN &&
474 + JBD2_HAS_COMPAT_FEATURE(journal,
475 + JBD2_FEATURE_COMPAT_CHECKSUM) &&
476 + !info->end_transaction) {
477 + if (cal_chksums(journal, bh,
486 next_log_block += count_tags(journal, bh);
487 wrap(journal, next_log_block);
489 @@ -516,9 +563,72 @@ static int do_one_pass(journal_t *journa
492 case JBD2_COMMIT_BLOCK:
493 - /* Found an expected commit block: not much to
494 - * do other than move on to the next sequence
495 + /* How to differentiate between interrupted commit
496 + * and journal corruption ?
498 + * {nth transaction}
499 + * Checksum Verification Failed
501 + * ____________________
503 + * async_commit sync_commit
505 + * | GO TO NEXT "Journal Corruption"
508 + * {(n+1)th transanction}
510 + * _______|______________
512 + * Commit block found Commit block not found
514 + * "Journal Corruption" |
515 + * _____________|_________
517 + * nth trans corrupt OR nth trans
518 + * and (n+1)th interrupted interrupted
519 + * before commit block
520 + * could reach the disk.
521 + * (Cannot find the difference in above
522 + * mentioned conditions. Hence assume
523 + * "Interrupted Commit".)
526 + /* Found an expected commit block: if checksums
527 + * are present verify them in PASS_SCAN; else not
528 + * much to do other than move on to the next sequence
530 + if (pass == PASS_SCAN &&
531 + JBD2_HAS_COMPAT_FEATURE(journal,
532 + JBD2_FEATURE_COMPAT_CHECKSUM)) {
533 + struct commit_header *cbh =
534 + (struct commit_header *)bh->b_data;
535 + unsigned found_chksum =
536 + be32_to_cpu(cbh->h_chksum[0]);
538 + if (info->end_transaction) {
539 + printk(KERN_ERR "JBD: Transaction %u "
540 + "found to be corrupt.\n",
541 + next_commit_ID - 1);
546 + if (crc32_sum != found_chksum) {
547 + info->end_transaction = next_commit_ID;
549 + if (!JBD2_HAS_COMPAT_FEATURE(journal,
550 + JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)){
552 + "JBD: Transaction %u "
553 + "found to be corrupt.\n",
564 @@ -554,9 +664,10 @@ static int do_one_pass(journal_t *journa
565 * transaction marks the end of the valid log.
568 - if (pass == PASS_SCAN)
569 - info->end_transaction = next_commit_ID;
571 + if (pass == PASS_SCAN) {
572 + if (!info->end_transaction)
573 + info->end_transaction = next_commit_ID;
575 /* It's really bad news if different passes end up at
576 * different places (but possible due to IO errors). */
577 if (info->end_transaction != next_commit_ID) {
578 Index: linux-2.6.23-rc6/include/linux/ext4_fs.h
579 ===================================================================
580 --- linux-2.6.23-rc6.orig/include/linux/ext4_fs.h 2007-09-20 17:25:46.000000000 -0700
581 +++ linux-2.6.23-rc6/include/linux/ext4_fs.h 2007-09-20 17:25:49.000000000 -0700
582 @@ -488,7 +488,8 @@ do { \
583 #define EXT4_MOUNT_USRQUOTA 0x100000 /* "old" user quota */
584 #define EXT4_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */
585 #define EXT4_MOUNT_EXTENTS 0x400000 /* Extents support */
587 +#define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000 /* Journal checksums */
588 +#define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */
589 /* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */
590 #ifndef _LINUX_EXT2_FS_H
591 #define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt
592 Index: linux-2.6.23-rc6/include/linux/jbd2.h
593 ===================================================================
594 --- linux-2.6.23-rc6.orig/include/linux/jbd2.h 2007-09-19 11:37:41.000000000 -0700
595 +++ linux-2.6.23-rc6/include/linux/jbd2.h 2007-09-20 17:25:49.000000000 -0700
596 @@ -149,6 +149,29 @@ typedef struct journal_header_s
603 +#define JBD2_CRC32_CHKSUM 1
604 +#define JBD2_MD5_CHKSUM 2
605 +#define JBD2_SHA1_CHKSUM 3
607 +#define JBD2_CRC32_CHKSUM_SIZE 4
609 +#define JBD2_CHECKSUM_BYTES (32 / sizeof(u32))
611 + * Commit block header for storing transactional checksums:
613 +struct commit_header
616 + __be32 h_blocktype;
618 + unsigned char h_chksum_type;
619 + unsigned char h_chksum_size;
620 + unsigned char h_padding[2];
621 + __be32 h_chksum[JBD2_CHECKSUM_BYTES];
625 * The block tag: used to describe a single buffer in the journal.
626 @@ -242,14 +265,18 @@ typedef struct journal_superblock_s
627 ((j)->j_format_version >= 2 && \
628 ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask))))
630 -#define JBD2_FEATURE_INCOMPAT_REVOKE 0x00000001
631 -#define JBD2_FEATURE_INCOMPAT_64BIT 0x00000002
632 +#define JBD2_FEATURE_COMPAT_CHECKSUM 0x00000001
634 +#define JBD2_FEATURE_INCOMPAT_REVOKE 0x00000001
635 +#define JBD2_FEATURE_INCOMPAT_64BIT 0x00000002
636 +#define JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004
638 /* Features known to this kernel version: */
639 -#define JBD2_KNOWN_COMPAT_FEATURES 0
640 +#define JBD2_KNOWN_COMPAT_FEATURES JBD2_FEATURE_COMPAT_CHECKSUM
641 #define JBD2_KNOWN_ROCOMPAT_FEATURES 0
642 #define JBD2_KNOWN_INCOMPAT_FEATURES (JBD2_FEATURE_INCOMPAT_REVOKE | \
643 - JBD2_FEATURE_INCOMPAT_64BIT)
644 + JBD2_FEATURE_INCOMPAT_64BIT | \
645 + JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)
649 @@ -932,6 +959,8 @@ extern int jbd2_journal_check_availab
650 (journal_t *, unsigned long, unsigned long, unsigned long);
651 extern int jbd2_journal_set_features
652 (journal_t *, unsigned long, unsigned long, unsigned long);
653 +extern int jbd2_journal_clear_features
654 + (journal_t *, unsigned long, unsigned long, unsigned long);
655 extern int jbd2_journal_create (journal_t *);
656 extern int jbd2_journal_load (journal_t *journal);
657 extern void jbd2_journal_destroy (journal_t *);