Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 updates from Ted Ts'o: "Add as a feature case-insensitive directories (the casefold feature) using Unicode 12.1. Also, the usual largish number of cleanups and bug fixes" * tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (25 commits) ext4: export /sys/fs/ext4/feature/casefold if Unicode support is present ext4: fix ext4_show_options for file systems w/o journal unicode: refactor the rule for regenerating utf8data.h docs: ext4.rst: document case-insensitive directories ext4: Support case-insensitive file name lookups ext4: include charset encoding information in the superblock MAINTAINERS: add Unicode subsystem entry unicode: update unicode database unicode version 12.1.0 unicode: introduce test module for normalized utf8 implementation unicode: implement higher level API for string handling unicode: reduce the size of utf8data[] unicode: introduce code for UTF-8 normalization unicode: introduce UTF-8 character database ext4: actually request zeroing of inode table after grow ext4: cond_resched in work-heavy group loops ext4: fix use-after-free race with debug_want_extra_isize ext4: avoid drop reference to iloc.bh twice ext4: ignore e_value_offs for xattrs with value-in-ea-inode ext4: protect journal inode's blocks using block_validity ext4: use BUG() instead of BUG_ON(1) ...
This commit is contained in:
151
fs/ext4/super.c
151
fs/ext4/super.c
@@ -42,6 +42,7 @@
|
||||
#include <linux/cleancache.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/iversion.h>
|
||||
#include <linux/unicode.h>
|
||||
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/freezer.h>
|
||||
@@ -1054,6 +1055,9 @@ static void ext4_put_super(struct super_block *sb)
|
||||
crypto_free_shash(sbi->s_chksum_driver);
|
||||
kfree(sbi->s_blockgroup_lock);
|
||||
fs_put_dax(sbi->s_daxdev);
|
||||
#ifdef CONFIG_UNICODE
|
||||
utf8_unload(sbi->s_encoding);
|
||||
#endif
|
||||
kfree(sbi);
|
||||
}
|
||||
|
||||
@@ -1749,6 +1753,36 @@ static const struct mount_opts {
|
||||
{Opt_err, 0, 0}
|
||||
};
|
||||
|
||||
#ifdef CONFIG_UNICODE
|
||||
static const struct ext4_sb_encodings {
|
||||
__u16 magic;
|
||||
char *name;
|
||||
char *version;
|
||||
} ext4_sb_encoding_map[] = {
|
||||
{EXT4_ENC_UTF8_12_1, "utf8", "12.1.0"},
|
||||
};
|
||||
|
||||
static int ext4_sb_read_encoding(const struct ext4_super_block *es,
|
||||
const struct ext4_sb_encodings **encoding,
|
||||
__u16 *flags)
|
||||
{
|
||||
__u16 magic = le16_to_cpu(es->s_encoding);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ext4_sb_encoding_map); i++)
|
||||
if (magic == ext4_sb_encoding_map[i].magic)
|
||||
break;
|
||||
|
||||
if (i >= ARRAY_SIZE(ext4_sb_encoding_map))
|
||||
return -EINVAL;
|
||||
|
||||
*encoding = &ext4_sb_encoding_map[i];
|
||||
*flags = le16_to_cpu(es->s_encoding_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int handle_mount_opt(struct super_block *sb, char *opt, int token,
|
||||
substring_t *args, unsigned long *journal_devnum,
|
||||
unsigned int *journal_ioprio, int is_remount)
|
||||
@@ -2875,6 +2909,15 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_UNICODE
|
||||
if (ext4_has_feature_casefold(sb)) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"Filesystem with casefold feature cannot be "
|
||||
"mounted without CONFIG_UNICODE");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (readonly)
|
||||
return 1;
|
||||
|
||||
@@ -3496,6 +3539,37 @@ int ext4_calculate_overhead(struct super_block *sb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ext4_clamp_want_extra_isize(struct super_block *sb)
|
||||
{
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
struct ext4_super_block *es = sbi->s_es;
|
||||
|
||||
/* determine the minimum size of new large inodes, if present */
|
||||
if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE &&
|
||||
sbi->s_want_extra_isize == 0) {
|
||||
sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
|
||||
EXT4_GOOD_OLD_INODE_SIZE;
|
||||
if (ext4_has_feature_extra_isize(sb)) {
|
||||
if (sbi->s_want_extra_isize <
|
||||
le16_to_cpu(es->s_want_extra_isize))
|
||||
sbi->s_want_extra_isize =
|
||||
le16_to_cpu(es->s_want_extra_isize);
|
||||
if (sbi->s_want_extra_isize <
|
||||
le16_to_cpu(es->s_min_extra_isize))
|
||||
sbi->s_want_extra_isize =
|
||||
le16_to_cpu(es->s_min_extra_isize);
|
||||
}
|
||||
}
|
||||
/* Check if enough inode space is available */
|
||||
if (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
|
||||
sbi->s_inode_size) {
|
||||
sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
|
||||
EXT4_GOOD_OLD_INODE_SIZE;
|
||||
ext4_msg(sb, KERN_INFO,
|
||||
"required extra inode space not available");
|
||||
}
|
||||
}
|
||||
|
||||
static void ext4_set_resv_clusters(struct super_block *sb)
|
||||
{
|
||||
ext4_fsblk_t resv_clusters;
|
||||
@@ -3722,6 +3796,43 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||
&journal_ioprio, 0))
|
||||
goto failed_mount;
|
||||
|
||||
#ifdef CONFIG_UNICODE
|
||||
if (ext4_has_feature_casefold(sb) && !sbi->s_encoding) {
|
||||
const struct ext4_sb_encodings *encoding_info;
|
||||
struct unicode_map *encoding;
|
||||
__u16 encoding_flags;
|
||||
|
||||
if (ext4_has_feature_encrypt(sb)) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"Can't mount with encoding and encryption");
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
if (ext4_sb_read_encoding(es, &encoding_info,
|
||||
&encoding_flags)) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"Encoding requested by superblock is unknown");
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
encoding = utf8_load(encoding_info->version);
|
||||
if (IS_ERR(encoding)) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"can't mount with superblock charset: %s-%s "
|
||||
"not supported by the kernel. flags: 0x%x.",
|
||||
encoding_info->name, encoding_info->version,
|
||||
encoding_flags);
|
||||
goto failed_mount;
|
||||
}
|
||||
ext4_msg(sb, KERN_INFO,"Using encoding defined by superblock: "
|
||||
"%s-%s with flags 0x%hx", encoding_info->name,
|
||||
encoding_info->version?:"\b", encoding_flags);
|
||||
|
||||
sbi->s_encoding = encoding;
|
||||
sbi->s_encoding_flags = encoding_flags;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
|
||||
printk_once(KERN_WARNING "EXT4-fs: Warning: mounting "
|
||||
"with data=journal disables delayed "
|
||||
@@ -4219,7 +4330,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||
"data=, fs mounted w/o journal");
|
||||
goto failed_mount_wq;
|
||||
}
|
||||
sbi->s_def_mount_opt &= EXT4_MOUNT_JOURNAL_CHECKSUM;
|
||||
sbi->s_def_mount_opt &= ~EXT4_MOUNT_JOURNAL_CHECKSUM;
|
||||
clear_opt(sb, JOURNAL_CHECKSUM);
|
||||
clear_opt(sb, DATA_FLAGS);
|
||||
sbi->s_journal = NULL;
|
||||
@@ -4354,6 +4465,12 @@ no_journal:
|
||||
iput(root);
|
||||
goto failed_mount4;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UNICODE
|
||||
if (sbi->s_encoding)
|
||||
sb->s_d_op = &ext4_dentry_ops;
|
||||
#endif
|
||||
|
||||
sb->s_root = d_make_root(root);
|
||||
if (!sb->s_root) {
|
||||
ext4_msg(sb, KERN_ERR, "get root dentry failed");
|
||||
@@ -4368,30 +4485,7 @@ no_journal:
|
||||
} else if (ret)
|
||||
goto failed_mount4a;
|
||||
|
||||
/* determine the minimum size of new large inodes, if present */
|
||||
if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE &&
|
||||
sbi->s_want_extra_isize == 0) {
|
||||
sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
|
||||
EXT4_GOOD_OLD_INODE_SIZE;
|
||||
if (ext4_has_feature_extra_isize(sb)) {
|
||||
if (sbi->s_want_extra_isize <
|
||||
le16_to_cpu(es->s_want_extra_isize))
|
||||
sbi->s_want_extra_isize =
|
||||
le16_to_cpu(es->s_want_extra_isize);
|
||||
if (sbi->s_want_extra_isize <
|
||||
le16_to_cpu(es->s_min_extra_isize))
|
||||
sbi->s_want_extra_isize =
|
||||
le16_to_cpu(es->s_min_extra_isize);
|
||||
}
|
||||
}
|
||||
/* Check if enough inode space is available */
|
||||
if (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
|
||||
sbi->s_inode_size) {
|
||||
sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
|
||||
EXT4_GOOD_OLD_INODE_SIZE;
|
||||
ext4_msg(sb, KERN_INFO, "required extra inode space not"
|
||||
"available");
|
||||
}
|
||||
ext4_clamp_want_extra_isize(sb);
|
||||
|
||||
ext4_set_resv_clusters(sb);
|
||||
|
||||
@@ -4559,6 +4653,11 @@ failed_mount2:
|
||||
failed_mount:
|
||||
if (sbi->s_chksum_driver)
|
||||
crypto_free_shash(sbi->s_chksum_driver);
|
||||
|
||||
#ifdef CONFIG_UNICODE
|
||||
utf8_unload(sbi->s_encoding);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_QUOTA
|
||||
for (i = 0; i < EXT4_MAXQUOTAS; i++)
|
||||
kfree(sbi->s_qf_names[i]);
|
||||
@@ -5175,6 +5274,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
||||
goto restore_opts;
|
||||
}
|
||||
|
||||
ext4_clamp_want_extra_isize(sb);
|
||||
|
||||
if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^
|
||||
test_opt(sb, JOURNAL_CHECKSUM)) {
|
||||
ext4_msg(sb, KERN_ERR, "changing journal_checksum "
|
||||
|
Reference in New Issue
Block a user