Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 updates from Ted Ts'o: "The major change this cycle is deleting ext4's copy of the file system encryption code and switching things over to using the copies in fs/crypto. I've updated the MAINTAINERS file to add an entry for fs/crypto listing Jaeguk Kim and myself as the maintainers. There are also a number of bug fixes, most notably for some problems found by American Fuzzy Lop (AFL) courtesy of Vegard Nossum. Also fixed is a writeback deadlock detected by generic/130, and some potential races in the metadata checksum code" * tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (21 commits) ext4: verify extent header depth ext4: short-cut orphan cleanup on error ext4: fix reference counting bug on block allocation error MAINTAINRES: fs-crypto maintainers update ext4 crypto: migrate into vfs's crypto engine ext2: fix filesystem deadlock while reading corrupted xattr block ext4: fix project quota accounting without quota limits enabled ext4: validate s_reserved_gdt_blocks on mount ext4: remove unused page_idx ext4: don't call ext4_should_journal_data() on the journal inode ext4: Fix WARN_ON_ONCE in ext4_commit_super() ext4: fix deadlock during page writeback ext4: correct error value of function verifying dx checksum ext4: avoid modifying checksum fields directly during checksum verification ext4: check for extents that wrap around jbd2: make journal y2038 safe jbd2: track more dependencies on transaction commit jbd2: move lockdep tracking to journal_s jbd2: move lockdep instrumentation for jbd2 handles ext4: respect the nobarrier mount option in nojournal mode ...
This commit is contained in:
162
fs/ext4/super.c
162
fs/ext4/super.c
@@ -945,9 +945,6 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
|
||||
ei->i_datasync_tid = 0;
|
||||
atomic_set(&ei->i_unwritten, 0);
|
||||
INIT_WORK(&ei->i_rsv_conversion_work, ext4_end_io_rsv_work);
|
||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
ei->i_crypt_info = NULL;
|
||||
#endif
|
||||
return &ei->vfs_inode;
|
||||
}
|
||||
|
||||
@@ -1026,8 +1023,7 @@ void ext4_clear_inode(struct inode *inode)
|
||||
EXT4_I(inode)->jinode = NULL;
|
||||
}
|
||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
if (EXT4_I(inode)->i_crypt_info)
|
||||
ext4_free_encryption_info(inode, EXT4_I(inode)->i_crypt_info);
|
||||
fscrypt_put_encryption_info(inode, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1094,6 +1090,90 @@ static int bdev_try_to_free_page(struct super_block *sb, struct page *page,
|
||||
return try_to_free_buffers(page);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
static int ext4_get_context(struct inode *inode, void *ctx, size_t len)
|
||||
{
|
||||
return ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
|
||||
EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx, len);
|
||||
}
|
||||
|
||||
static int ext4_key_prefix(struct inode *inode, u8 **key)
|
||||
{
|
||||
*key = EXT4_SB(inode->i_sb)->key_prefix;
|
||||
return EXT4_SB(inode->i_sb)->key_prefix_size;
|
||||
}
|
||||
|
||||
static int ext4_prepare_context(struct inode *inode)
|
||||
{
|
||||
return ext4_convert_inline_data(inode);
|
||||
}
|
||||
|
||||
static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
|
||||
void *fs_data)
|
||||
{
|
||||
handle_t *handle;
|
||||
int res, res2;
|
||||
|
||||
/* fs_data is null when internally used. */
|
||||
if (fs_data) {
|
||||
res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION,
|
||||
EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx,
|
||||
len, 0);
|
||||
if (!res) {
|
||||
ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
|
||||
ext4_clear_inode_state(inode,
|
||||
EXT4_STATE_MAY_INLINE_DATA);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
handle = ext4_journal_start(inode, EXT4_HT_MISC,
|
||||
ext4_jbd2_credits_xattr(inode));
|
||||
if (IS_ERR(handle))
|
||||
return PTR_ERR(handle);
|
||||
|
||||
res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION,
|
||||
EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx,
|
||||
len, 0);
|
||||
if (!res) {
|
||||
ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
|
||||
res = ext4_mark_inode_dirty(handle, inode);
|
||||
if (res)
|
||||
EXT4_ERROR_INODE(inode, "Failed to mark inode dirty");
|
||||
}
|
||||
res2 = ext4_journal_stop(handle);
|
||||
if (!res)
|
||||
res = res2;
|
||||
return res;
|
||||
}
|
||||
|
||||
static int ext4_dummy_context(struct inode *inode)
|
||||
{
|
||||
return DUMMY_ENCRYPTION_ENABLED(EXT4_SB(inode->i_sb));
|
||||
}
|
||||
|
||||
static unsigned ext4_max_namelen(struct inode *inode)
|
||||
{
|
||||
return S_ISLNK(inode->i_mode) ? inode->i_sb->s_blocksize :
|
||||
EXT4_NAME_LEN;
|
||||
}
|
||||
|
||||
static struct fscrypt_operations ext4_cryptops = {
|
||||
.get_context = ext4_get_context,
|
||||
.key_prefix = ext4_key_prefix,
|
||||
.prepare_context = ext4_prepare_context,
|
||||
.set_context = ext4_set_context,
|
||||
.dummy_context = ext4_dummy_context,
|
||||
.is_encrypted = ext4_encrypted_inode,
|
||||
.empty_dir = ext4_empty_dir,
|
||||
.max_namelen = ext4_max_namelen,
|
||||
};
|
||||
#else
|
||||
static struct fscrypt_operations ext4_cryptops = {
|
||||
.is_encrypted = ext4_encrypted_inode,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_QUOTA
|
||||
static char *quotatypes[] = INITQFNAMES;
|
||||
#define QTYPE2NAME(t) (quotatypes[t])
|
||||
@@ -2068,23 +2148,25 @@ failed:
|
||||
static __le16 ext4_group_desc_csum(struct super_block *sb, __u32 block_group,
|
||||
struct ext4_group_desc *gdp)
|
||||
{
|
||||
int offset;
|
||||
int offset = offsetof(struct ext4_group_desc, bg_checksum);
|
||||
__u16 crc = 0;
|
||||
__le32 le_group = cpu_to_le32(block_group);
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
|
||||
if (ext4_has_metadata_csum(sbi->s_sb)) {
|
||||
/* Use new metadata_csum algorithm */
|
||||
__le16 save_csum;
|
||||
__u32 csum32;
|
||||
__u16 dummy_csum = 0;
|
||||
|
||||
save_csum = gdp->bg_checksum;
|
||||
gdp->bg_checksum = 0;
|
||||
csum32 = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&le_group,
|
||||
sizeof(le_group));
|
||||
csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp,
|
||||
sbi->s_desc_size);
|
||||
gdp->bg_checksum = save_csum;
|
||||
csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp, offset);
|
||||
csum32 = ext4_chksum(sbi, csum32, (__u8 *)&dummy_csum,
|
||||
sizeof(dummy_csum));
|
||||
offset += sizeof(dummy_csum);
|
||||
if (offset < sbi->s_desc_size)
|
||||
csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp + offset,
|
||||
sbi->s_desc_size - offset);
|
||||
|
||||
crc = csum32 & 0xFFFF;
|
||||
goto out;
|
||||
@@ -2094,8 +2176,6 @@ static __le16 ext4_group_desc_csum(struct super_block *sb, __u32 block_group,
|
||||
if (!ext4_has_feature_gdt_csum(sb))
|
||||
return 0;
|
||||
|
||||
offset = offsetof(struct ext4_group_desc, bg_checksum);
|
||||
|
||||
crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
|
||||
crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
|
||||
crc = crc16(crc, (__u8 *)gdp, offset);
|
||||
@@ -2278,6 +2358,16 @@ static void ext4_orphan_cleanup(struct super_block *sb,
|
||||
while (es->s_last_orphan) {
|
||||
struct inode *inode;
|
||||
|
||||
/*
|
||||
* We may have encountered an error during cleanup; if
|
||||
* so, skip the rest.
|
||||
*/
|
||||
if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) {
|
||||
jbd_debug(1, "Skipping orphan recovery on fs with errors.\n");
|
||||
es->s_last_orphan = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
inode = ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan));
|
||||
if (IS_ERR(inode)) {
|
||||
es->s_last_orphan = 0;
|
||||
@@ -3416,6 +3506,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) > (blocksize / 4)) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"Number of reserved GDT blocks insanely large: %d",
|
||||
le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks));
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
if (sbi->s_mount_opt & EXT4_MOUNT_DAX) {
|
||||
err = bdev_dax_supported(sb, blocksize);
|
||||
if (err)
|
||||
@@ -3686,6 +3783,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||
sb->s_op = &ext4_sops;
|
||||
sb->s_export_op = &ext4_export_ops;
|
||||
sb->s_xattr = ext4_xattr_handlers;
|
||||
sb->s_cop = &ext4_cryptops;
|
||||
#ifdef CONFIG_QUOTA
|
||||
sb->dq_op = &ext4_quota_operations;
|
||||
if (ext4_has_feature_quota(sb))
|
||||
@@ -3996,6 +4094,11 @@ no_journal:
|
||||
ratelimit_state_init(&sbi->s_msg_ratelimit_state, 5 * HZ, 10);
|
||||
|
||||
kfree(orig_data);
|
||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
memcpy(sbi->key_prefix, EXT4_KEY_DESC_PREFIX,
|
||||
EXT4_KEY_DESC_PREFIX_SIZE);
|
||||
sbi->key_prefix_size = EXT4_KEY_DESC_PREFIX_SIZE;
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
cantfind_ext4:
|
||||
@@ -4327,20 +4430,6 @@ static int ext4_commit_super(struct super_block *sb, int sync)
|
||||
|
||||
if (!sbh || block_device_ejected(sb))
|
||||
return error;
|
||||
if (buffer_write_io_error(sbh)) {
|
||||
/*
|
||||
* Oh, dear. A previous attempt to write the
|
||||
* superblock failed. This could happen because the
|
||||
* USB device was yanked out. Or it could happen to
|
||||
* be a transient write error and maybe the block will
|
||||
* be remapped. Nothing we can do but to retry the
|
||||
* write and hope for the best.
|
||||
*/
|
||||
ext4_msg(sb, KERN_ERR, "previous I/O error to "
|
||||
"superblock detected");
|
||||
clear_buffer_write_io_error(sbh);
|
||||
set_buffer_uptodate(sbh);
|
||||
}
|
||||
/*
|
||||
* If the file system is mounted read-only, don't update the
|
||||
* superblock write time. This avoids updating the superblock
|
||||
@@ -4371,7 +4460,23 @@ static int ext4_commit_super(struct super_block *sb, int sync)
|
||||
&EXT4_SB(sb)->s_freeinodes_counter));
|
||||
BUFFER_TRACE(sbh, "marking dirty");
|
||||
ext4_superblock_csum_set(sb);
|
||||
lock_buffer(sbh);
|
||||
if (buffer_write_io_error(sbh)) {
|
||||
/*
|
||||
* Oh, dear. A previous attempt to write the
|
||||
* superblock failed. This could happen because the
|
||||
* USB device was yanked out. Or it could happen to
|
||||
* be a transient write error and maybe the block will
|
||||
* be remapped. Nothing we can do but to retry the
|
||||
* write and hope for the best.
|
||||
*/
|
||||
ext4_msg(sb, KERN_ERR, "previous I/O error to "
|
||||
"superblock detected");
|
||||
clear_buffer_write_io_error(sbh);
|
||||
set_buffer_uptodate(sbh);
|
||||
}
|
||||
mark_buffer_dirty(sbh);
|
||||
unlock_buffer(sbh);
|
||||
if (sync) {
|
||||
error = __sync_dirty_buffer(sbh,
|
||||
test_opt(sb, BARRIER) ? WRITE_FUA : WRITE_SYNC);
|
||||
@@ -5422,7 +5527,6 @@ out5:
|
||||
|
||||
static void __exit ext4_exit_fs(void)
|
||||
{
|
||||
ext4_exit_crypto();
|
||||
ext4_destroy_lazyinit_thread();
|
||||
unregister_as_ext2();
|
||||
unregister_as_ext3();
|
||||
|
Reference in New Issue
Block a user