Ext4 bug fixes for 3.20. We also reserved code points for encryption
and read-only images (for which the implementation is mostly just the reserved code point for a read-only feature :-) -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJU6lssAAoJENNvdpvBGATwpsEQAOcpCqj0gp/istbsoFpl5v5K +BU2aPvR5CPLtUQz9MqrVF5/6zwDbHGN+GIB6CEmh/qHIVQAhhS4XR+opSc7qqUr fAQ1AhL5Oh8Dyn9DRy5Io8oRv+wo5lRdD7aG7SPiizCMRQ34JwJ2sWIAwbP2Ea7W Xg51v3LWEu+UpqpgY3YWBoJKHj4hXwFvTVOCHs94239Y2zlcg2c4WwbKPzkvPcV/ TvvZOOctty+l3FOB2bqFj3VnvywQmNv8/OixKjSprxlR7nuQlhKaLTWCtRjFbND4 J/rk2ls5Bl79dnMvyVfV5ghpmGYBf5kkXCP716YsQkRCZUfNVrTOPJrNHZtYilAb opRo2UjAyTWxZBvyssnCorHJZUdxlYeIuSTpaG0zUbR0Y6p/7qd31F5k41GbBCFf B0lV3IaiVnXk23S2jFVHGhrzoKdFqu30tY7LMaO4xyGVMigOZJyBu8TZ7Utj9HmW /4GfjlvYqlfB7p+6yBkDv/87hjdmfMWIw48A7xWCiIeguQhB79gwTV7uAHVtgfng h5RF2EH/fx5klbAZx9vlaAh3pGFBHbh9fkeBmW9qNm7glz7aMUuxQaSo6X8HrCAJ LrECgDGbuiOHnMYuzZRERZiqwLB7JT82C1xopGzefsE/i0kN1eMjITkfggjQ5whu caLPn49tAb9U8P6TsPeE =PF+t -----END PGP SIGNATURE----- Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4 Pull ext4 fixes from Ted Ts'o: "Ext4 bug fixes. We also reserved code points for encryption and read-only images (for which the implementation is mostly just the reserved code point for a read-only feature :-)" * tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: ext4: fix indirect punch hole corruption ext4: ignore journal checksum on remount; don't fail ext4: remove duplicate remount check for JOURNAL_CHECKSUM change ext4: fix mmap data corruption in nodelalloc mode when blocksize < pagesize ext4: support read-only images ext4: change to use setup_timer() instead of init_timer() ext4: reserve codepoints used by the ext4 encryption feature jbd2: complain about descriptor block checksum errors
This commit is contained in:
commit
feaf222925
|
@ -364,7 +364,8 @@ struct flex_groups {
|
|||
#define EXT4_DIRTY_FL 0x00000100
|
||||
#define EXT4_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
|
||||
#define EXT4_NOCOMPR_FL 0x00000400 /* Don't compress */
|
||||
#define EXT4_ECOMPR_FL 0x00000800 /* Compression error */
|
||||
/* nb: was previously EXT2_ECOMPR_FL */
|
||||
#define EXT4_ENCRYPT_FL 0x00000800 /* encrypted file */
|
||||
/* End compression flags --- maybe not all used */
|
||||
#define EXT4_INDEX_FL 0x00001000 /* hash-indexed directory */
|
||||
#define EXT4_IMAGIC_FL 0x00002000 /* AFS directory */
|
||||
|
@ -421,7 +422,7 @@ enum {
|
|||
EXT4_INODE_DIRTY = 8,
|
||||
EXT4_INODE_COMPRBLK = 9, /* One or more compressed clusters */
|
||||
EXT4_INODE_NOCOMPR = 10, /* Don't compress */
|
||||
EXT4_INODE_ECOMPR = 11, /* Compression error */
|
||||
EXT4_INODE_ENCRYPT = 11, /* Compression error */
|
||||
/* End compression flags --- maybe not all used */
|
||||
EXT4_INODE_INDEX = 12, /* hash-indexed directory */
|
||||
EXT4_INODE_IMAGIC = 13, /* AFS directory */
|
||||
|
@ -466,7 +467,7 @@ static inline void ext4_check_flag_values(void)
|
|||
CHECK_FLAG_VALUE(DIRTY);
|
||||
CHECK_FLAG_VALUE(COMPRBLK);
|
||||
CHECK_FLAG_VALUE(NOCOMPR);
|
||||
CHECK_FLAG_VALUE(ECOMPR);
|
||||
CHECK_FLAG_VALUE(ENCRYPT);
|
||||
CHECK_FLAG_VALUE(INDEX);
|
||||
CHECK_FLAG_VALUE(IMAGIC);
|
||||
CHECK_FLAG_VALUE(JOURNAL_DATA);
|
||||
|
@ -1048,6 +1049,12 @@ extern void ext4_set_bits(void *bm, int cur, int len);
|
|||
/* Metadata checksum algorithm codes */
|
||||
#define EXT4_CRC32C_CHKSUM 1
|
||||
|
||||
/* Encryption algorithms */
|
||||
#define EXT4_ENCRYPTION_MODE_INVALID 0
|
||||
#define EXT4_ENCRYPTION_MODE_AES_256_XTS 1
|
||||
#define EXT4_ENCRYPTION_MODE_AES_256_GCM 2
|
||||
#define EXT4_ENCRYPTION_MODE_AES_256_CBC 3
|
||||
|
||||
/*
|
||||
* Structure of the super block
|
||||
*/
|
||||
|
@ -1161,7 +1168,8 @@ struct ext4_super_block {
|
|||
__le32 s_grp_quota_inum; /* inode for tracking group quota */
|
||||
__le32 s_overhead_clusters; /* overhead blocks/clusters in fs */
|
||||
__le32 s_backup_bgs[2]; /* groups with sparse_super2 SBs */
|
||||
__le32 s_reserved[106]; /* Padding to the end of the block */
|
||||
__u8 s_encrypt_algos[4]; /* Encryption algorithms in use */
|
||||
__le32 s_reserved[105]; /* Padding to the end of the block */
|
||||
__le32 s_checksum; /* crc32c(superblock) */
|
||||
};
|
||||
|
||||
|
@ -1527,6 +1535,7 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
|
|||
* GDT_CSUM bits are mutually exclusive.
|
||||
*/
|
||||
#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400
|
||||
#define EXT4_FEATURE_RO_COMPAT_READONLY 0x1000
|
||||
|
||||
#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001
|
||||
#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002
|
||||
|
@ -1542,6 +1551,7 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
|
|||
#define EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM 0x2000 /* use crc32c for bg */
|
||||
#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */
|
||||
#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */
|
||||
#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000
|
||||
|
||||
#define EXT2_FEATURE_COMPAT_SUPP EXT4_FEATURE_COMPAT_EXT_ATTR
|
||||
#define EXT2_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \
|
||||
|
|
|
@ -1401,10 +1401,7 @@ end_range:
|
|||
* to free. Everything was covered by the start
|
||||
* of the range.
|
||||
*/
|
||||
return 0;
|
||||
} else {
|
||||
/* Shared branch grows from an indirect block */
|
||||
partial2--;
|
||||
goto do_indirects;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
|
@ -1435,56 +1432,96 @@ end_range:
|
|||
/* Punch happened within the same level (n == n2) */
|
||||
partial = ext4_find_shared(inode, n, offsets, chain, &nr);
|
||||
partial2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2);
|
||||
/*
|
||||
* ext4_find_shared returns Indirect structure which
|
||||
* points to the last element which should not be
|
||||
* removed by truncate. But this is end of the range
|
||||
* in punch_hole so we need to point to the next element
|
||||
*/
|
||||
partial2->p++;
|
||||
while ((partial > chain) || (partial2 > chain2)) {
|
||||
/* We're at the same block, so we're almost finished */
|
||||
if ((partial->bh && partial2->bh) &&
|
||||
(partial->bh->b_blocknr == partial2->bh->b_blocknr)) {
|
||||
if ((partial > chain) && (partial2 > chain2)) {
|
||||
ext4_free_branches(handle, inode, partial->bh,
|
||||
partial->p + 1,
|
||||
partial2->p,
|
||||
(chain+n-1) - partial);
|
||||
BUFFER_TRACE(partial->bh, "call brelse");
|
||||
brelse(partial->bh);
|
||||
BUFFER_TRACE(partial2->bh, "call brelse");
|
||||
brelse(partial2->bh);
|
||||
|
||||
/* Free top, but only if partial2 isn't its subtree. */
|
||||
if (nr) {
|
||||
int level = min(partial - chain, partial2 - chain2);
|
||||
int i;
|
||||
int subtree = 1;
|
||||
|
||||
for (i = 0; i <= level; i++) {
|
||||
if (offsets[i] != offsets2[i]) {
|
||||
subtree = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!subtree) {
|
||||
if (partial == chain) {
|
||||
/* Shared branch grows from the inode */
|
||||
ext4_free_branches(handle, inode, NULL,
|
||||
&nr, &nr+1,
|
||||
(chain+n-1) - partial);
|
||||
*partial->p = 0;
|
||||
} else {
|
||||
/* Shared branch grows from an indirect block */
|
||||
BUFFER_TRACE(partial->bh, "get_write_access");
|
||||
ext4_free_branches(handle, inode, partial->bh,
|
||||
partial->p,
|
||||
partial->p+1,
|
||||
(chain+n-1) - partial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!nr2) {
|
||||
/*
|
||||
* ext4_find_shared returns Indirect structure which
|
||||
* points to the last element which should not be
|
||||
* removed by truncate. But this is end of the range
|
||||
* in punch_hole so we need to point to the next element
|
||||
*/
|
||||
partial2->p++;
|
||||
}
|
||||
|
||||
while (partial > chain || partial2 > chain2) {
|
||||
int depth = (chain+n-1) - partial;
|
||||
int depth2 = (chain2+n2-1) - partial2;
|
||||
|
||||
if (partial > chain && partial2 > chain2 &&
|
||||
partial->bh->b_blocknr == partial2->bh->b_blocknr) {
|
||||
/*
|
||||
* We've converged on the same block. Clear the range,
|
||||
* then we're done.
|
||||
*/
|
||||
ext4_free_branches(handle, inode, partial->bh,
|
||||
partial->p + 1,
|
||||
partial2->p,
|
||||
(chain+n-1) - partial);
|
||||
BUFFER_TRACE(partial->bh, "call brelse");
|
||||
brelse(partial->bh);
|
||||
BUFFER_TRACE(partial2->bh, "call brelse");
|
||||
brelse(partial2->bh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the ends of indirect blocks on the shared branch
|
||||
* at the start of the range
|
||||
* The start and end partial branches may not be at the same
|
||||
* level even though the punch happened within one level. So, we
|
||||
* give them a chance to arrive at the same level, then walk
|
||||
* them in step with each other until we converge on the same
|
||||
* block.
|
||||
*/
|
||||
if (partial > chain) {
|
||||
if (partial > chain && depth <= depth2) {
|
||||
ext4_free_branches(handle, inode, partial->bh,
|
||||
partial->p + 1,
|
||||
(__le32 *)partial->bh->b_data+addr_per_block,
|
||||
(chain+n-1) - partial);
|
||||
partial->p + 1,
|
||||
(__le32 *)partial->bh->b_data+addr_per_block,
|
||||
(chain+n-1) - partial);
|
||||
BUFFER_TRACE(partial->bh, "call brelse");
|
||||
brelse(partial->bh);
|
||||
partial--;
|
||||
}
|
||||
/*
|
||||
* Clear the ends of indirect blocks on the shared branch
|
||||
* at the end of the range
|
||||
*/
|
||||
if (partial2 > chain2) {
|
||||
if (partial2 > chain2 && depth2 <= depth) {
|
||||
ext4_free_branches(handle, inode, partial2->bh,
|
||||
(__le32 *)partial2->bh->b_data,
|
||||
partial2->p,
|
||||
(chain2+n-1) - partial2);
|
||||
(chain2+n2-1) - partial2);
|
||||
BUFFER_TRACE(partial2->bh, "call brelse");
|
||||
brelse(partial2->bh);
|
||||
partial2--;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
do_indirects:
|
||||
/* Kill the remaining (whole) subtrees */
|
||||
|
|
|
@ -1024,6 +1024,7 @@ static int ext4_write_end(struct file *file,
|
|||
{
|
||||
handle_t *handle = ext4_journal_current_handle();
|
||||
struct inode *inode = mapping->host;
|
||||
loff_t old_size = inode->i_size;
|
||||
int ret = 0, ret2;
|
||||
int i_size_changed = 0;
|
||||
|
||||
|
@ -1054,6 +1055,8 @@ static int ext4_write_end(struct file *file,
|
|||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
|
||||
if (old_size < pos)
|
||||
pagecache_isize_extended(inode, old_size, pos);
|
||||
/*
|
||||
* Don't mark the inode dirty under page lock. First, it unnecessarily
|
||||
* makes the holding time of page lock longer. Second, it forces lock
|
||||
|
@ -1095,6 +1098,7 @@ static int ext4_journalled_write_end(struct file *file,
|
|||
{
|
||||
handle_t *handle = ext4_journal_current_handle();
|
||||
struct inode *inode = mapping->host;
|
||||
loff_t old_size = inode->i_size;
|
||||
int ret = 0, ret2;
|
||||
int partial = 0;
|
||||
unsigned from, to;
|
||||
|
@ -1127,6 +1131,9 @@ static int ext4_journalled_write_end(struct file *file,
|
|||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
|
||||
if (old_size < pos)
|
||||
pagecache_isize_extended(inode, old_size, pos);
|
||||
|
||||
if (size_changed) {
|
||||
ret2 = ext4_mark_inode_dirty(handle, inode);
|
||||
if (!ret)
|
||||
|
|
|
@ -2779,6 +2779,12 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
|
|||
if (readonly)
|
||||
return 1;
|
||||
|
||||
if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_READONLY)) {
|
||||
ext4_msg(sb, KERN_INFO, "filesystem is read-only");
|
||||
sb->s_flags |= MS_RDONLY;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check that feature set is OK for a read-write mount */
|
||||
if (EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT4_FEATURE_RO_COMPAT_SUPP)) {
|
||||
ext4_msg(sb, KERN_ERR, "couldn't mount RDWR because of "
|
||||
|
@ -3936,9 +3942,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
|||
get_random_bytes(&sbi->s_next_generation, sizeof(u32));
|
||||
spin_lock_init(&sbi->s_next_gen_lock);
|
||||
|
||||
init_timer(&sbi->s_err_report);
|
||||
sbi->s_err_report.function = print_daily_error_info;
|
||||
sbi->s_err_report.data = (unsigned long) sb;
|
||||
setup_timer(&sbi->s_err_report, print_daily_error_info,
|
||||
(unsigned long) sb);
|
||||
|
||||
/* Register extent status tree shrinker */
|
||||
if (ext4_es_register_shrinker(sbi))
|
||||
|
@ -4866,9 +4871,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
|||
if (sbi->s_journal && sbi->s_journal->j_task->io_context)
|
||||
journal_ioprio = sbi->s_journal->j_task->io_context->ioprio;
|
||||
|
||||
/*
|
||||
* Allow the "check" option to be passed as a remount option.
|
||||
*/
|
||||
if (!parse_options(data, sb, NULL, &journal_ioprio, 1)) {
|
||||
err = -EINVAL;
|
||||
goto restore_opts;
|
||||
|
@ -4877,17 +4879,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
|||
if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^
|
||||
test_opt(sb, JOURNAL_CHECKSUM)) {
|
||||
ext4_msg(sb, KERN_ERR, "changing journal_checksum "
|
||||
"during remount not supported");
|
||||
err = -EINVAL;
|
||||
goto restore_opts;
|
||||
}
|
||||
|
||||
if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^
|
||||
test_opt(sb, JOURNAL_CHECKSUM)) {
|
||||
ext4_msg(sb, KERN_ERR, "changing journal_checksum "
|
||||
"during remount not supported");
|
||||
err = -EINVAL;
|
||||
goto restore_opts;
|
||||
"during remount not supported; ignoring");
|
||||
sbi->s_mount_opt ^= EXT4_MOUNT_JOURNAL_CHECKSUM;
|
||||
}
|
||||
|
||||
if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
|
||||
|
@ -4963,7 +4956,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
|||
ext4_mark_recovery_complete(sb, es);
|
||||
} else {
|
||||
/* Make sure we can mount this feature set readwrite */
|
||||
if (!ext4_feature_set_ok(sb, 0)) {
|
||||
if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_RO_COMPAT_READONLY) ||
|
||||
!ext4_feature_set_ok(sb, 0)) {
|
||||
err = -EROFS;
|
||||
goto restore_opts;
|
||||
}
|
||||
|
|
|
@ -524,6 +524,9 @@ static int do_one_pass(journal_t *journal,
|
|||
if (descr_csum_size > 0 &&
|
||||
!jbd2_descr_block_csum_verify(journal,
|
||||
bh->b_data)) {
|
||||
printk(KERN_ERR "JBD2: Invalid checksum "
|
||||
"recovering block %lu in log\n",
|
||||
next_log_block);
|
||||
err = -EIO;
|
||||
brelse(bh);
|
||||
goto failed;
|
||||
|
|
Loading…
Reference in New Issue