forked from Minki/linux
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: ext4: enable barriers by default jbd2: Fix barrier fallback code to re-lock the buffer head ext4: Display the journal_async_commit mount option in /proc/mounts jbd2: If a journal checksum error is detected, propagate the error to ext4 jbd2: Fix memory leak when verifying checksums in the journal ext4: fix online resize bug ext4: Fix uninit block group initialization with FLEX_BG ext4: Fix use of uninitialized data with debug enabled.
This commit is contained in:
commit
5f0e62c3e1
@ -139,8 +139,16 @@ commit=nrsec (*) Ext4 can be told to sync all its data and metadata
|
|||||||
Setting it to very large values will improve
|
Setting it to very large values will improve
|
||||||
performance.
|
performance.
|
||||||
|
|
||||||
barrier=1 This enables/disables barriers. barrier=0 disables
|
barrier=<0|1(*)> This enables/disables the use of write barriers in
|
||||||
it, barrier=1 enables it.
|
the jbd code. barrier=0 disables, barrier=1 enables.
|
||||||
|
This also requires an IO stack which can support
|
||||||
|
barriers, and if jbd gets an error on a barrier
|
||||||
|
write, it will disable again with a warning.
|
||||||
|
Write barriers enforce proper on-disk ordering
|
||||||
|
of journal commits, making volatile disk write caches
|
||||||
|
safe to use, at some performance penalty. If
|
||||||
|
your disks are battery-backed in one way or another,
|
||||||
|
disabling barriers may safely improve performance.
|
||||||
|
|
||||||
orlov (*) This enables the new Orlov block allocator. It is
|
orlov (*) This enables the new Orlov block allocator. It is
|
||||||
enabled by default.
|
enabled by default.
|
||||||
|
@ -43,6 +43,46 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ext4_block_in_group(struct super_block *sb, ext4_fsblk_t block,
|
||||||
|
ext4_group_t block_group)
|
||||||
|
{
|
||||||
|
ext4_group_t actual_group;
|
||||||
|
ext4_get_group_no_and_offset(sb, block, &actual_group, 0);
|
||||||
|
if (actual_group == block_group)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ext4_group_used_meta_blocks(struct super_block *sb,
|
||||||
|
ext4_group_t block_group)
|
||||||
|
{
|
||||||
|
ext4_fsblk_t tmp;
|
||||||
|
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||||
|
/* block bitmap, inode bitmap, and inode table blocks */
|
||||||
|
int used_blocks = sbi->s_itb_per_group + 2;
|
||||||
|
|
||||||
|
if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
|
||||||
|
struct ext4_group_desc *gdp;
|
||||||
|
struct buffer_head *bh;
|
||||||
|
|
||||||
|
gdp = ext4_get_group_desc(sb, block_group, &bh);
|
||||||
|
if (!ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp),
|
||||||
|
block_group))
|
||||||
|
used_blocks--;
|
||||||
|
|
||||||
|
if (!ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp),
|
||||||
|
block_group))
|
||||||
|
used_blocks--;
|
||||||
|
|
||||||
|
tmp = ext4_inode_table(sb, gdp);
|
||||||
|
for (; tmp < ext4_inode_table(sb, gdp) +
|
||||||
|
sbi->s_itb_per_group; tmp++) {
|
||||||
|
if (!ext4_block_in_group(sb, tmp, block_group))
|
||||||
|
used_blocks -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return used_blocks;
|
||||||
|
}
|
||||||
/* Initializes an uninitialized block bitmap if given, and returns the
|
/* Initializes an uninitialized block bitmap if given, and returns the
|
||||||
* number of blocks free in the group. */
|
* number of blocks free in the group. */
|
||||||
unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
|
unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
|
||||||
@ -105,20 +145,34 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
|
|||||||
free_blocks = group_blocks - bit_max;
|
free_blocks = group_blocks - bit_max;
|
||||||
|
|
||||||
if (bh) {
|
if (bh) {
|
||||||
ext4_fsblk_t start;
|
ext4_fsblk_t start, tmp;
|
||||||
|
int flex_bg = 0;
|
||||||
|
|
||||||
for (bit = 0; bit < bit_max; bit++)
|
for (bit = 0; bit < bit_max; bit++)
|
||||||
ext4_set_bit(bit, bh->b_data);
|
ext4_set_bit(bit, bh->b_data);
|
||||||
|
|
||||||
start = ext4_group_first_block_no(sb, block_group);
|
start = ext4_group_first_block_no(sb, block_group);
|
||||||
|
|
||||||
/* Set bits for block and inode bitmaps, and inode table */
|
if (EXT4_HAS_INCOMPAT_FEATURE(sb,
|
||||||
ext4_set_bit(ext4_block_bitmap(sb, gdp) - start, bh->b_data);
|
EXT4_FEATURE_INCOMPAT_FLEX_BG))
|
||||||
ext4_set_bit(ext4_inode_bitmap(sb, gdp) - start, bh->b_data);
|
flex_bg = 1;
|
||||||
for (bit = (ext4_inode_table(sb, gdp) - start),
|
|
||||||
bit_max = bit + sbi->s_itb_per_group; bit < bit_max; bit++)
|
|
||||||
ext4_set_bit(bit, bh->b_data);
|
|
||||||
|
|
||||||
|
/* Set bits for block and inode bitmaps, and inode table */
|
||||||
|
tmp = ext4_block_bitmap(sb, gdp);
|
||||||
|
if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
|
||||||
|
ext4_set_bit(tmp - start, bh->b_data);
|
||||||
|
|
||||||
|
tmp = ext4_inode_bitmap(sb, gdp);
|
||||||
|
if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
|
||||||
|
ext4_set_bit(tmp - start, bh->b_data);
|
||||||
|
|
||||||
|
tmp = ext4_inode_table(sb, gdp);
|
||||||
|
for (; tmp < ext4_inode_table(sb, gdp) +
|
||||||
|
sbi->s_itb_per_group; tmp++) {
|
||||||
|
if (!flex_bg ||
|
||||||
|
ext4_block_in_group(sb, tmp, block_group))
|
||||||
|
ext4_set_bit(tmp - start, bh->b_data);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Also if the number of blocks within the group is
|
* Also if the number of blocks within the group is
|
||||||
* less than the blocksize * 8 ( which is the size
|
* less than the blocksize * 8 ( which is the size
|
||||||
@ -126,8 +180,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
|
|||||||
*/
|
*/
|
||||||
mark_bitmap_end(group_blocks, sb->s_blocksize * 8, bh->b_data);
|
mark_bitmap_end(group_blocks, sb->s_blocksize * 8, bh->b_data);
|
||||||
}
|
}
|
||||||
|
return free_blocks - ext4_group_used_meta_blocks(sb, block_group);
|
||||||
return free_blocks - sbi->s_itb_per_group - 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2745,8 +2745,6 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
|
|||||||
sbi = EXT4_SB(sb);
|
sbi = EXT4_SB(sb);
|
||||||
es = sbi->s_es;
|
es = sbi->s_es;
|
||||||
|
|
||||||
ext4_debug("using block group %lu(%d)\n", ac->ac_b_ex.fe_group,
|
|
||||||
gdp->bg_free_blocks_count);
|
|
||||||
|
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
bitmap_bh = read_block_bitmap(sb, ac->ac_b_ex.fe_group);
|
bitmap_bh = read_block_bitmap(sb, ac->ac_b_ex.fe_group);
|
||||||
@ -2762,6 +2760,9 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
|
|||||||
if (!gdp)
|
if (!gdp)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
|
||||||
|
ext4_debug("using block group %lu(%d)\n", ac->ac_b_ex.fe_group,
|
||||||
|
gdp->bg_free_blocks_count);
|
||||||
|
|
||||||
err = ext4_journal_get_write_access(handle, gdp_bh);
|
err = ext4_journal_get_write_access(handle, gdp_bh);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
@ -3094,8 +3095,7 @@ static void ext4_mb_use_inode_pa(struct ext4_allocation_context *ac,
|
|||||||
static void ext4_mb_use_group_pa(struct ext4_allocation_context *ac,
|
static void ext4_mb_use_group_pa(struct ext4_allocation_context *ac,
|
||||||
struct ext4_prealloc_space *pa)
|
struct ext4_prealloc_space *pa)
|
||||||
{
|
{
|
||||||
unsigned len = ac->ac_o_ex.fe_len;
|
unsigned int len = ac->ac_o_ex.fe_len;
|
||||||
|
|
||||||
ext4_get_group_no_and_offset(ac->ac_sb, pa->pa_pstart,
|
ext4_get_group_no_and_offset(ac->ac_sb, pa->pa_pstart,
|
||||||
&ac->ac_b_ex.fe_group,
|
&ac->ac_b_ex.fe_group,
|
||||||
&ac->ac_b_ex.fe_start);
|
&ac->ac_b_ex.fe_start);
|
||||||
|
@ -563,7 +563,8 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
blk = EXT4_SB(sb)->s_sbh->b_blocknr + 1 + EXT4_SB(sb)->s_gdb_count;
|
blk = EXT4_SB(sb)->s_sbh->b_blocknr + 1 + EXT4_SB(sb)->s_gdb_count;
|
||||||
data = (__le32 *)dind->b_data + EXT4_SB(sb)->s_gdb_count;
|
data = (__le32 *)dind->b_data + (EXT4_SB(sb)->s_gdb_count %
|
||||||
|
EXT4_ADDR_PER_BLOCK(sb));
|
||||||
end = (__le32 *)dind->b_data + EXT4_ADDR_PER_BLOCK(sb);
|
end = (__le32 *)dind->b_data + EXT4_ADDR_PER_BLOCK(sb);
|
||||||
|
|
||||||
/* Get each reserved primary GDT block and verify it holds backups */
|
/* Get each reserved primary GDT block and verify it holds backups */
|
||||||
|
@ -671,6 +671,7 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
|
|||||||
unsigned long def_mount_opts;
|
unsigned long def_mount_opts;
|
||||||
struct super_block *sb = vfs->mnt_sb;
|
struct super_block *sb = vfs->mnt_sb;
|
||||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||||
|
journal_t *journal = sbi->s_journal;
|
||||||
struct ext4_super_block *es = sbi->s_es;
|
struct ext4_super_block *es = sbi->s_es;
|
||||||
|
|
||||||
def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
|
def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
|
||||||
@ -729,8 +730,15 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
|
|||||||
seq_printf(seq, ",commit=%u",
|
seq_printf(seq, ",commit=%u",
|
||||||
(unsigned) (sbi->s_commit_interval / HZ));
|
(unsigned) (sbi->s_commit_interval / HZ));
|
||||||
}
|
}
|
||||||
if (test_opt(sb, BARRIER))
|
/*
|
||||||
seq_puts(seq, ",barrier=1");
|
* We're changing the default of barrier mount option, so
|
||||||
|
* let's always display its mount state so it's clear what its
|
||||||
|
* status is.
|
||||||
|
*/
|
||||||
|
seq_puts(seq, ",barrier=");
|
||||||
|
seq_puts(seq, test_opt(sb, BARRIER) ? "1" : "0");
|
||||||
|
if (test_opt(sb, JOURNAL_ASYNC_COMMIT))
|
||||||
|
seq_puts(seq, ",journal_async_commit");
|
||||||
if (test_opt(sb, NOBH))
|
if (test_opt(sb, NOBH))
|
||||||
seq_puts(seq, ",nobh");
|
seq_puts(seq, ",nobh");
|
||||||
if (!test_opt(sb, EXTENTS))
|
if (!test_opt(sb, EXTENTS))
|
||||||
@ -1907,6 +1915,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
|
|||||||
sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
|
sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
|
||||||
|
|
||||||
set_opt(sbi->s_mount_opt, RESERVATION);
|
set_opt(sbi->s_mount_opt, RESERVATION);
|
||||||
|
set_opt(sbi->s_mount_opt, BARRIER);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* turn on extents feature by default in ext4 filesystem
|
* turn on extents feature by default in ext4 filesystem
|
||||||
@ -2189,6 +2198,29 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
|
|||||||
EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
|
EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
|
||||||
if (ext4_load_journal(sb, es, journal_devnum))
|
if (ext4_load_journal(sb, es, journal_devnum))
|
||||||
goto failed_mount3;
|
goto failed_mount3;
|
||||||
|
if (!(sb->s_flags & MS_RDONLY) &&
|
||||||
|
EXT4_SB(sb)->s_journal->j_failed_commit) {
|
||||||
|
printk(KERN_CRIT "EXT4-fs error (device %s): "
|
||||||
|
"ext4_fill_super: Journal transaction "
|
||||||
|
"%u is corrupt\n", sb->s_id,
|
||||||
|
EXT4_SB(sb)->s_journal->j_failed_commit);
|
||||||
|
if (test_opt (sb, ERRORS_RO)) {
|
||||||
|
printk (KERN_CRIT
|
||||||
|
"Mounting filesystem read-only\n");
|
||||||
|
sb->s_flags |= MS_RDONLY;
|
||||||
|
EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
|
||||||
|
es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
|
||||||
|
}
|
||||||
|
if (test_opt(sb, ERRORS_PANIC)) {
|
||||||
|
EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
|
||||||
|
es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
|
||||||
|
ext4_commit_super(sb, es, 1);
|
||||||
|
printk(KERN_CRIT
|
||||||
|
"EXT4-fs (device %s): mount failed\n",
|
||||||
|
sb->s_id);
|
||||||
|
goto failed_mount4;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (journal_inum) {
|
} else if (journal_inum) {
|
||||||
if (ext4_create_journal(sb, es, journal_inum))
|
if (ext4_create_journal(sb, es, journal_inum))
|
||||||
goto failed_mount3;
|
goto failed_mount3;
|
||||||
|
@ -168,6 +168,7 @@ static int journal_submit_commit_record(journal_t *journal,
|
|||||||
spin_unlock(&journal->j_state_lock);
|
spin_unlock(&journal->j_state_lock);
|
||||||
|
|
||||||
/* And try again, without the barrier */
|
/* And try again, without the barrier */
|
||||||
|
lock_buffer(bh);
|
||||||
set_buffer_uptodate(bh);
|
set_buffer_uptodate(bh);
|
||||||
set_buffer_dirty(bh);
|
set_buffer_dirty(bh);
|
||||||
ret = submit_bh(WRITE, bh);
|
ret = submit_bh(WRITE, bh);
|
||||||
|
@ -344,6 +344,7 @@ static int calc_chksums(journal_t *journal, struct buffer_head *bh,
|
|||||||
*crc32_sum = crc32_be(*crc32_sum, (void *)obh->b_data,
|
*crc32_sum = crc32_be(*crc32_sum, (void *)obh->b_data,
|
||||||
obh->b_size);
|
obh->b_size);
|
||||||
}
|
}
|
||||||
|
put_bh(obh);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -610,9 +611,8 @@ static int do_one_pass(journal_t *journal,
|
|||||||
chksum_err = chksum_seen = 0;
|
chksum_err = chksum_seen = 0;
|
||||||
|
|
||||||
if (info->end_transaction) {
|
if (info->end_transaction) {
|
||||||
printk(KERN_ERR "JBD: Transaction %u "
|
journal->j_failed_commit =
|
||||||
"found to be corrupt.\n",
|
info->end_transaction;
|
||||||
next_commit_ID - 1);
|
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -643,10 +643,8 @@ static int do_one_pass(journal_t *journal,
|
|||||||
|
|
||||||
if (!JBD2_HAS_INCOMPAT_FEATURE(journal,
|
if (!JBD2_HAS_INCOMPAT_FEATURE(journal,
|
||||||
JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)){
|
JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)){
|
||||||
printk(KERN_ERR
|
journal->j_failed_commit =
|
||||||
"JBD: Transaction %u "
|
next_commit_ID;
|
||||||
"found to be corrupt.\n",
|
|
||||||
next_commit_ID);
|
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -919,6 +919,9 @@ struct journal_s
|
|||||||
struct proc_dir_entry *j_proc_entry;
|
struct proc_dir_entry *j_proc_entry;
|
||||||
struct transaction_stats_s j_stats;
|
struct transaction_stats_s j_stats;
|
||||||
|
|
||||||
|
/* Failed journal commit ID */
|
||||||
|
unsigned int j_failed_commit;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* An opaque pointer to fs-private information. ext3 puts its
|
* An opaque pointer to fs-private information. ext3 puts its
|
||||||
* superblock pointer here
|
* superblock pointer here
|
||||||
|
Loading…
Reference in New Issue
Block a user