diff options
-rw-r--r-- | fs/jbd2/commit.c | 17 | ||||
-rw-r--r-- | fs/jbd2/journal.c | 11 | ||||
-rw-r--r-- | fs/jbd2/recovery.c | 43 | ||||
-rw-r--r-- | fs/jbd2/revoke.c | 14 | ||||
-rw-r--r-- | include/linux/jbd2.h | 14 |
5 files changed, 77 insertions, 22 deletions
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index b1a4eaf..44d68a1 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -271,6 +271,14 @@ write_out_data: journal_do_submit_data(wbuf, bufs); } +static inline void write_tag_block(int tag_bytes, journal_block_tag_t *tag, + sector_t block) +{ + tag->t_blocknr = cpu_to_be32(block & (u32)~0); + if (tag_bytes > JBD_TAG_SIZE32) + tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1); +} + /* * jbd2_journal_commit_transaction * @@ -293,6 +301,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) int first_tag = 0; int tag_flag; int i; + int tag_bytes = journal_tag_bytes(journal); /* * First job: lock down the current transaction and wait for @@ -597,10 +606,10 @@ void jbd2_journal_commit_transaction(journal_t *journal) tag_flag |= JBD2_FLAG_SAME_UUID; tag = (journal_block_tag_t *) tagp; - tag->t_blocknr = cpu_to_be32(jh2bh(jh)->b_blocknr); + write_tag_block(tag_bytes, tag, jh2bh(jh)->b_blocknr); tag->t_flags = cpu_to_be32(tag_flag); - tagp += sizeof(journal_block_tag_t); - space_left -= sizeof(journal_block_tag_t); + tagp += tag_bytes; + space_left -= tag_bytes; if (first_tag) { memcpy (tagp, journal->j_uuid, 16); @@ -614,7 +623,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) if (bufs == journal->j_wbufsize || commit_transaction->t_buffers == NULL || - space_left < sizeof(journal_block_tag_t) + 16) { + space_left < tag_bytes + 16) { jbd_debug(4, "JBD: Submit %d IOs\n", bufs); diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 8d0f71e..926ebcb 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1610,6 +1610,17 @@ int jbd2_journal_blocks_per_page(struct inode *inode) } /* + * helper functions to deal with 32 or 64bit block numbers. + */ +size_t journal_tag_bytes(journal_t *journal) +{ + if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) + return JBD_TAG_SIZE64; + else + return JBD_TAG_SIZE32; +} + +/* * Simple support for retrying memory allocations. Introduced to help to * debug different VM deadlock avoidance strategies. */ diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index b2012d1..2486843 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c @@ -178,19 +178,20 @@ static int jread(struct buffer_head **bhp, journal_t *journal, * Count the number of in-use tags in a journal descriptor block. */ -static int count_tags(struct buffer_head *bh, int size) +static int count_tags(journal_t *journal, struct buffer_head *bh) { char * tagp; journal_block_tag_t * tag; - int nr = 0; + int nr = 0, size = journal->j_blocksize; + int tag_bytes = journal_tag_bytes(journal); tagp = &bh->b_data[sizeof(journal_header_t)]; - while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) { + while ((tagp - bh->b_data + tag_bytes) <= size) { tag = (journal_block_tag_t *) tagp; nr++; - tagp += sizeof(journal_block_tag_t); + tagp += tag_bytes; if (!(tag->t_flags & cpu_to_be32(JBD2_FLAG_SAME_UUID))) tagp += 16; @@ -307,6 +308,14 @@ int jbd2_journal_skip_recovery(journal_t *journal) return err; } +static inline sector_t read_tag_block(int tag_bytes, journal_block_tag_t *tag) +{ + sector_t block = be32_to_cpu(tag->t_blocknr); + if (tag_bytes > JBD_TAG_SIZE32) + block |= (u64)be32_to_cpu(tag->t_blocknr_high) << 32; + return block; +} + static int do_one_pass(journal_t *journal, struct recovery_info *info, enum passtype pass) { @@ -318,11 +327,12 @@ static int do_one_pass(journal_t *journal, struct buffer_head * bh; unsigned int sequence; int blocktype; + int tag_bytes = journal_tag_bytes(journal); /* Precompute the maximum metadata descriptors in a descriptor block */ int MAX_BLOCKS_PER_DESC; MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t)) - / sizeof(journal_block_tag_t)); + / tag_bytes); /* * First thing is to establish what we expect to find in the log @@ -412,8 +422,7 @@ static int do_one_pass(journal_t *journal, * in pass REPLAY; otherwise, just skip over the * blocks it describes. */ if (pass != PASS_REPLAY) { - next_log_block += - count_tags(bh, journal->j_blocksize); + next_log_block += count_tags(journal, bh); wrap(journal, next_log_block); brelse(bh); continue; @@ -424,7 +433,7 @@ static int do_one_pass(journal_t *journal, * getting done here! */ tagp = &bh->b_data[sizeof(journal_header_t)]; - while ((tagp - bh->b_data +sizeof(journal_block_tag_t)) + while ((tagp - bh->b_data + tag_bytes) <= journal->j_blocksize) { unsigned long io_block; @@ -446,7 +455,8 @@ static int do_one_pass(journal_t *journal, unsigned long blocknr; J_ASSERT(obh != NULL); - blocknr = be32_to_cpu(tag->t_blocknr); + blocknr = read_tag_block(tag_bytes, + tag); /* If the block has been * revoked, then we're all done @@ -494,7 +504,7 @@ static int do_one_pass(journal_t *journal, } skip_write: - tagp += sizeof(journal_block_tag_t); + tagp += tag_bytes; if (!(flags & JBD2_FLAG_SAME_UUID)) tagp += 16; @@ -572,17 +582,24 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, { jbd2_journal_revoke_header_t *header; int offset, max; + int record_len = 4; header = (jbd2_journal_revoke_header_t *) bh->b_data; offset = sizeof(jbd2_journal_revoke_header_t); max = be32_to_cpu(header->r_count); - while (offset < max) { + if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) + record_len = 8; + + while (offset + record_len <= max) { unsigned long blocknr; int err; - blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset))); - offset += 4; + if (record_len == 4) + blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset))); + else + blocknr = be64_to_cpu(* ((__be64 *) (bh->b_data+offset))); + offset += record_len; err = jbd2_journal_set_revoke(journal, blocknr, sequence); if (err) return err; diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index 5820a0c..8aac875 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -584,9 +584,17 @@ static void write_one_revoke_record(journal_t *journal, *descriptorp = descriptor; } - * ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) = - cpu_to_be32(record->blocknr); - offset += 4; + if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) { + * ((__be64 *)(&jh2bh(descriptor)->b_data[offset])) = + cpu_to_be64(record->blocknr); + offset += 8; + + } else { + * ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) = + cpu_to_be32(record->blocknr); + offset += 4; + } + *offsetp = offset; } diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 3251f7a..5e5aa64 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -150,14 +150,21 @@ typedef struct journal_header_s /* - * The block tag: used to describe a single buffer in the journal + * The block tag: used to describe a single buffer in the journal. + * t_blocknr_high is only used if INCOMPAT_64BIT is set, so this + * raw struct shouldn't be used for pointer math or sizeof() - use + * journal_tag_bytes(journal) instead to compute this. */ typedef struct journal_block_tag_s { __be32 t_blocknr; /* The on-disk block number */ __be32 t_flags; /* See below */ + __be32 t_blocknr_high; /* most-significant high 32bits. */ } journal_block_tag_t; +#define JBD_TAG_SIZE32 (offsetof(journal_block_tag_t, t_blocknr_high)) +#define JBD_TAG_SIZE64 (sizeof(journal_block_tag_t)) + /* * The revoke descriptor: used on disk to describe a series of blocks to * be revoked from the log @@ -235,11 +242,13 @@ typedef struct journal_superblock_s ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask)))) #define JBD2_FEATURE_INCOMPAT_REVOKE 0x00000001 +#define JBD2_FEATURE_INCOMPAT_64BIT 0x00000002 /* Features known to this kernel version: */ #define JBD2_KNOWN_COMPAT_FEATURES 0 #define JBD2_KNOWN_ROCOMPAT_FEATURES 0 -#define JBD2_KNOWN_INCOMPAT_FEATURES JBD2_FEATURE_INCOMPAT_REVOKE +#define JBD2_KNOWN_INCOMPAT_FEATURES (JBD2_FEATURE_INCOMPAT_REVOKE | \ + JBD2_FEATURE_INCOMPAT_64BIT) #ifdef __KERNEL__ @@ -1052,6 +1061,7 @@ static inline int tid_geq(tid_t x, tid_t y) } extern int jbd2_journal_blocks_per_page(struct inode *inode); +extern size_t journal_tag_bytes(journal_t *journal); /* * Return the minimum number of blocks which must be free in the journal |