Bug fixes for the new ext4 fast commit feature, plus a fix for the

data=journal bug fix.  Also use the generic casefolding support which
 has now landed in fs/libfs.c for 5.10.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEEK2m5VNv+CHkogTfJ8vlZVpUNgaMFAl+aP/IACgkQ8vlZVpUN
 gaM62gf+JWHXh4d4RS4UcFlQWmT0JlMK8AGEdt90PGeJwO7MmAUC8KRFdMxCSdMQ
 yqJObRH9w7AFVZYCdroLIC2MyeXj4rASD7DxMgFhu/LYrKOTxCHiTt9gdx/slELM
 HQoKB77pYs4AZOMPgo+svqf9aHtHPu1Bk3M2C5WW4/BZHjKCxXDD7wONPFLHOq/0
 qTcj2JS+1GAivNzwq8/ZFntmbz316FuKF3LNVUvCP+aTbOwD77NtyaBDGr8pnsnz
 duNyX4CYPo27FM9K/ywGQL9ISCIRxEwPN0GeILc3Cawu6bsr5z+ZBYKbt3DuUv18
 hl+E7wrOG/+EMLd6TBfvRN1v5YvwPg==
 =0J5C
 -----END PGP SIGNATURE-----

Merge tag 'ext4_for_linus_fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4

Pull ext4 fixes from Ted Ts'o:
 "Bug fixes for the new ext4 fast commit feature, plus a fix for the
  'data=journal' bug fix.

  Also use the generic casefolding support which has now landed in
  fs/libfs.c for 5.10"

* tag 'ext4_for_linus_fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
  ext4: indicate that fast_commit is available via /sys/fs/ext4/feature/...
  ext4: use generic casefolding support
  ext4: do not use extent after put_bh
  ext4: use IS_ERR() for error checking of path
  ext4: fix mmap write protection for data=journal mode
  jbd2: fix a kernel-doc markup
  ext4: use s_mount_flags instead of s_mount_state for fast commit state
  ext4: make num of fast commit blocks configurable
  ext4: properly check for dirty state in ext4_inode_datasync_dirty()
  ext4: fix double locking in ext4_fc_commit_dentry_updates()
This commit is contained in:
Linus Torvalds 2020-10-29 09:36:11 -07:00
commit 58130a6cd0
10 changed files with 78 additions and 135 deletions

View File

@ -669,68 +669,8 @@ const struct file_operations ext4_dir_operations = {
}; };
#ifdef CONFIG_UNICODE #ifdef CONFIG_UNICODE
static int ext4_d_compare(const struct dentry *dentry, unsigned int len,
const char *str, const struct qstr *name)
{
struct qstr qstr = {.name = str, .len = len };
const struct dentry *parent = READ_ONCE(dentry->d_parent);
const struct inode *inode = d_inode_rcu(parent);
char strbuf[DNAME_INLINE_LEN];
if (!inode || !IS_CASEFOLDED(inode) ||
!EXT4_SB(inode->i_sb)->s_encoding) {
if (len != name->len)
return -1;
return memcmp(str, name->name, len);
}
/*
* If the dentry name is stored in-line, then it may be concurrently
* modified by a rename. If this happens, the VFS will eventually retry
* the lookup, so it doesn't matter what ->d_compare() returns.
* However, it's unsafe to call utf8_strncasecmp() with an unstable
* string. Therefore, we have to copy the name into a temporary buffer.
*/
if (len <= DNAME_INLINE_LEN - 1) {
memcpy(strbuf, str, len);
strbuf[len] = 0;
qstr.name = strbuf;
/* prevent compiler from optimizing out the temporary buffer */
barrier();
}
return ext4_ci_compare(inode, name, &qstr, false);
}
static int ext4_d_hash(const struct dentry *dentry, struct qstr *str)
{
const struct ext4_sb_info *sbi = EXT4_SB(dentry->d_sb);
const struct unicode_map *um = sbi->s_encoding;
const struct inode *inode = d_inode_rcu(dentry);
unsigned char *norm;
int len, ret = 0;
if (!inode || !IS_CASEFOLDED(inode) || !um)
return 0;
norm = kmalloc(PATH_MAX, GFP_ATOMIC);
if (!norm)
return -ENOMEM;
len = utf8_casefold(um, str, norm, PATH_MAX);
if (len < 0) {
if (ext4_has_strict_mode(sbi))
ret = -EINVAL;
goto out;
}
str->hash = full_name_hash(dentry, norm, len);
out:
kfree(norm);
return ret;
}
const struct dentry_operations ext4_dentry_ops = { const struct dentry_operations ext4_dentry_ops = {
.d_hash = ext4_d_hash, .d_hash = generic_ci_d_hash,
.d_compare = ext4_d_compare, .d_compare = generic_ci_d_compare,
}; };
#endif #endif

View File

@ -1166,10 +1166,6 @@ struct ext4_inode_info {
#define EXT4_VALID_FS 0x0001 /* Unmounted cleanly */ #define EXT4_VALID_FS 0x0001 /* Unmounted cleanly */
#define EXT4_ERROR_FS 0x0002 /* Errors detected */ #define EXT4_ERROR_FS 0x0002 /* Errors detected */
#define EXT4_ORPHAN_FS 0x0004 /* Orphans being recovered */ #define EXT4_ORPHAN_FS 0x0004 /* Orphans being recovered */
#define EXT4_FC_INELIGIBLE 0x0008 /* Fast commit ineligible */
#define EXT4_FC_COMMITTING 0x0010 /* File system underoing a fast
* commit.
*/
#define EXT4_FC_REPLAY 0x0020 /* Fast commit replay ongoing */ #define EXT4_FC_REPLAY 0x0020 /* Fast commit replay ongoing */
/* /*
@ -1431,6 +1427,10 @@ struct ext4_super_block {
*/ */
#define EXT4_MF_MNTDIR_SAMPLED 0x0001 #define EXT4_MF_MNTDIR_SAMPLED 0x0001
#define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */ #define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */
#define EXT4_MF_FC_INELIGIBLE 0x0004 /* Fast commit ineligible */
#define EXT4_MF_FC_COMMITTING 0x0008 /* File system underoing a fast
* commit.
*/
#ifdef CONFIG_FS_ENCRYPTION #ifdef CONFIG_FS_ENCRYPTION
#define DUMMY_ENCRYPTION_ENABLED(sbi) ((sbi)->s_dummy_enc_policy.policy != NULL) #define DUMMY_ENCRYPTION_ENABLED(sbi) ((sbi)->s_dummy_enc_policy.policy != NULL)
@ -1443,14 +1443,6 @@ struct ext4_super_block {
#define EXT4_ENC_UTF8_12_1 1 #define EXT4_ENC_UTF8_12_1 1
/*
* Flags for ext4_sb_info.s_encoding_flags.
*/
#define EXT4_ENC_STRICT_MODE_FL (1 << 0)
#define ext4_has_strict_mode(sbi) \
(sbi->s_encoding_flags & EXT4_ENC_STRICT_MODE_FL)
/* /*
* fourth extended-fs super-block data in memory * fourth extended-fs super-block data in memory
*/ */
@ -1500,10 +1492,6 @@ struct ext4_sb_info {
struct kobject s_kobj; struct kobject s_kobj;
struct completion s_kobj_unregister; struct completion s_kobj_unregister;
struct super_block *s_sb; struct super_block *s_sb;
#ifdef CONFIG_UNICODE
struct unicode_map *s_encoding;
__u16 s_encoding_flags;
#endif
/* Journaling */ /* Journaling */
struct journal_s *s_journal; struct journal_s *s_journal;

View File

@ -1471,16 +1471,16 @@ static int ext4_ext_search_left(struct inode *inode,
} }
/* /*
* search the closest allocated block to the right for *logical * Search the closest allocated block to the right for *logical
* and returns it at @logical + it's physical address at @phys * and returns it at @logical + it's physical address at @phys.
* if *logical is the largest allocated block, the function * If not exists, return 0 and @phys is set to 0. We will return
* returns 0 at @phys * 1 which means we found an allocated block and ret_ex is valid.
* return value contains 0 (success) or error code * Or return a (< 0) error code.
*/ */
static int ext4_ext_search_right(struct inode *inode, static int ext4_ext_search_right(struct inode *inode,
struct ext4_ext_path *path, struct ext4_ext_path *path,
ext4_lblk_t *logical, ext4_fsblk_t *phys, ext4_lblk_t *logical, ext4_fsblk_t *phys,
struct ext4_extent **ret_ex) struct ext4_extent *ret_ex)
{ {
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct ext4_extent_header *eh; struct ext4_extent_header *eh;
@ -1574,10 +1574,11 @@ got_index:
found_extent: found_extent:
*logical = le32_to_cpu(ex->ee_block); *logical = le32_to_cpu(ex->ee_block);
*phys = ext4_ext_pblock(ex); *phys = ext4_ext_pblock(ex);
*ret_ex = ex; if (ret_ex)
*ret_ex = *ex;
if (bh) if (bh)
put_bh(bh); put_bh(bh);
return 0; return 1;
} }
/* /*
@ -2868,8 +2869,8 @@ again:
*/ */
lblk = ex_end + 1; lblk = ex_end + 1;
err = ext4_ext_search_right(inode, path, &lblk, &pblk, err = ext4_ext_search_right(inode, path, &lblk, &pblk,
&ex); NULL);
if (err) if (err < 0)
goto out; goto out;
if (pblk) { if (pblk) {
partial.pclu = EXT4_B2C(sbi, pblk); partial.pclu = EXT4_B2C(sbi, pblk);
@ -4039,7 +4040,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
struct ext4_map_blocks *map, int flags) struct ext4_map_blocks *map, int flags)
{ {
struct ext4_ext_path *path = NULL; struct ext4_ext_path *path = NULL;
struct ext4_extent newex, *ex, *ex2; struct ext4_extent newex, *ex, ex2;
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
ext4_fsblk_t newblock = 0, pblk; ext4_fsblk_t newblock = 0, pblk;
int err = 0, depth, ret; int err = 0, depth, ret;
@ -4175,15 +4176,14 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
if (err) if (err)
goto out; goto out;
ar.lright = map->m_lblk; ar.lright = map->m_lblk;
ex2 = NULL;
err = ext4_ext_search_right(inode, path, &ar.lright, &ar.pright, &ex2); err = ext4_ext_search_right(inode, path, &ar.lright, &ar.pright, &ex2);
if (err) if (err < 0)
goto out; goto out;
/* Check if the extent after searching to the right implies a /* Check if the extent after searching to the right implies a
* cluster we can use. */ * cluster we can use. */
if ((sbi->s_cluster_ratio > 1) && ex2 && if ((sbi->s_cluster_ratio > 1) && err &&
get_implied_cluster_alloc(inode->i_sb, map, ex2, path)) { get_implied_cluster_alloc(inode->i_sb, map, &ex2, path)) {
ar.len = allocated = map->m_len; ar.len = allocated = map->m_len;
newblock = map->m_pblk; newblock = map->m_pblk;
goto got_allocated_blocks; goto got_allocated_blocks;

View File

@ -269,7 +269,7 @@ void ext4_fc_mark_ineligible(struct super_block *sb, int reason)
(EXT4_SB(sb)->s_mount_state & EXT4_FC_REPLAY)) (EXT4_SB(sb)->s_mount_state & EXT4_FC_REPLAY))
return; return;
sbi->s_mount_state |= EXT4_FC_INELIGIBLE; sbi->s_mount_flags |= EXT4_MF_FC_INELIGIBLE;
WARN_ON(reason >= EXT4_FC_REASON_MAX); WARN_ON(reason >= EXT4_FC_REASON_MAX);
sbi->s_fc_stats.fc_ineligible_reason_count[reason]++; sbi->s_fc_stats.fc_ineligible_reason_count[reason]++;
} }
@ -292,7 +292,7 @@ void ext4_fc_start_ineligible(struct super_block *sb, int reason)
} }
/* /*
* Stop a fast commit ineligible update. We set EXT4_FC_INELIGIBLE flag here * Stop a fast commit ineligible update. We set EXT4_MF_FC_INELIGIBLE flag here
* to ensure that after stopping the ineligible update, at least one full * to ensure that after stopping the ineligible update, at least one full
* commit takes place. * commit takes place.
*/ */
@ -302,13 +302,13 @@ void ext4_fc_stop_ineligible(struct super_block *sb)
(EXT4_SB(sb)->s_mount_state & EXT4_FC_REPLAY)) (EXT4_SB(sb)->s_mount_state & EXT4_FC_REPLAY))
return; return;
EXT4_SB(sb)->s_mount_state |= EXT4_FC_INELIGIBLE; EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FC_INELIGIBLE;
atomic_dec(&EXT4_SB(sb)->s_fc_ineligible_updates); atomic_dec(&EXT4_SB(sb)->s_fc_ineligible_updates);
} }
static inline int ext4_fc_is_ineligible(struct super_block *sb) static inline int ext4_fc_is_ineligible(struct super_block *sb)
{ {
return (EXT4_SB(sb)->s_mount_state & EXT4_FC_INELIGIBLE) || return (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FC_INELIGIBLE) ||
atomic_read(&EXT4_SB(sb)->s_fc_ineligible_updates); atomic_read(&EXT4_SB(sb)->s_fc_ineligible_updates);
} }
@ -358,7 +358,7 @@ static int ext4_fc_track_template(
spin_lock(&sbi->s_fc_lock); spin_lock(&sbi->s_fc_lock);
if (list_empty(&EXT4_I(inode)->i_fc_list)) if (list_empty(&EXT4_I(inode)->i_fc_list))
list_add_tail(&EXT4_I(inode)->i_fc_list, list_add_tail(&EXT4_I(inode)->i_fc_list,
(sbi->s_mount_state & EXT4_FC_COMMITTING) ? (sbi->s_mount_flags & EXT4_MF_FC_COMMITTING) ?
&sbi->s_fc_q[FC_Q_STAGING] : &sbi->s_fc_q[FC_Q_STAGING] :
&sbi->s_fc_q[FC_Q_MAIN]); &sbi->s_fc_q[FC_Q_MAIN]);
spin_unlock(&sbi->s_fc_lock); spin_unlock(&sbi->s_fc_lock);
@ -411,7 +411,7 @@ static int __track_dentry_update(struct inode *inode, void *arg, bool update)
node->fcd_name.len = dentry->d_name.len; node->fcd_name.len = dentry->d_name.len;
spin_lock(&sbi->s_fc_lock); spin_lock(&sbi->s_fc_lock);
if (sbi->s_mount_state & EXT4_FC_COMMITTING) if (sbi->s_mount_flags & EXT4_MF_FC_COMMITTING)
list_add_tail(&node->fcd_list, list_add_tail(&node->fcd_list,
&sbi->s_fc_dentry_q[FC_Q_STAGING]); &sbi->s_fc_dentry_q[FC_Q_STAGING]);
else else
@ -846,7 +846,7 @@ static int ext4_fc_submit_inode_data_all(journal_t *journal)
int ret = 0; int ret = 0;
spin_lock(&sbi->s_fc_lock); spin_lock(&sbi->s_fc_lock);
sbi->s_mount_state |= EXT4_FC_COMMITTING; sbi->s_mount_flags |= EXT4_MF_FC_COMMITTING;
list_for_each(pos, &sbi->s_fc_q[FC_Q_MAIN]) { list_for_each(pos, &sbi->s_fc_q[FC_Q_MAIN]) {
ei = list_entry(pos, struct ext4_inode_info, i_fc_list); ei = list_entry(pos, struct ext4_inode_info, i_fc_list);
ext4_set_inode_state(&ei->vfs_inode, EXT4_STATE_FC_COMMITTING); ext4_set_inode_state(&ei->vfs_inode, EXT4_STATE_FC_COMMITTING);
@ -964,7 +964,6 @@ static int ext4_fc_commit_dentry_updates(journal_t *journal, u32 *crc)
fc_dentry->fcd_parent, fc_dentry->fcd_ino, fc_dentry->fcd_parent, fc_dentry->fcd_ino,
fc_dentry->fcd_name.len, fc_dentry->fcd_name.len,
fc_dentry->fcd_name.name, crc)) { fc_dentry->fcd_name.name, crc)) {
spin_lock(&sbi->s_fc_lock);
ret = -ENOSPC; ret = -ENOSPC;
goto lock_and_exit; goto lock_and_exit;
} }
@ -1191,8 +1190,8 @@ static void ext4_fc_cleanup(journal_t *journal, int full)
list_splice_init(&sbi->s_fc_q[FC_Q_STAGING], list_splice_init(&sbi->s_fc_q[FC_Q_STAGING],
&sbi->s_fc_q[FC_Q_STAGING]); &sbi->s_fc_q[FC_Q_STAGING]);
sbi->s_mount_state &= ~EXT4_FC_COMMITTING; sbi->s_mount_flags &= ~EXT4_MF_FC_COMMITTING;
sbi->s_mount_state &= ~EXT4_FC_INELIGIBLE; sbi->s_mount_flags &= ~EXT4_MF_FC_INELIGIBLE;
if (full) if (full)
sbi->s_fc_bytes = 0; sbi->s_fc_bytes = 0;
@ -1617,8 +1616,10 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
if (ret == 0) { if (ret == 0) {
/* Range is not mapped */ /* Range is not mapped */
path = ext4_find_extent(inode, cur, NULL, 0); path = ext4_find_extent(inode, cur, NULL, 0);
if (!path) if (IS_ERR(path)) {
continue; iput(inode);
return 0;
}
memset(&newex, 0, sizeof(newex)); memset(&newex, 0, sizeof(newex));
newex.ee_block = cpu_to_le32(cur); newex.ee_block = cpu_to_le32(cur);
ext4_ext_store_pblock( ext4_ext_store_pblock(
@ -2078,6 +2079,8 @@ static int ext4_fc_replay(journal_t *journal, struct buffer_head *bh,
void ext4_fc_init(struct super_block *sb, journal_t *journal) void ext4_fc_init(struct super_block *sb, journal_t *journal)
{ {
int num_fc_blocks;
/* /*
* We set replay callback even if fast commit disabled because we may * We set replay callback even if fast commit disabled because we may
* could still have fast commit blocks that need to be replayed even if * could still have fast commit blocks that need to be replayed even if
@ -2087,7 +2090,15 @@ void ext4_fc_init(struct super_block *sb, journal_t *journal)
if (!test_opt2(sb, JOURNAL_FAST_COMMIT)) if (!test_opt2(sb, JOURNAL_FAST_COMMIT))
return; return;
journal->j_fc_cleanup_callback = ext4_fc_cleanup; journal->j_fc_cleanup_callback = ext4_fc_cleanup;
if (jbd2_fc_init(journal, EXT4_NUM_FC_BLKS)) { if (!buffer_uptodate(journal->j_sb_buffer)
&& ext4_read_bh_lock(journal->j_sb_buffer, REQ_META | REQ_PRIO,
true)) {
ext4_msg(sb, KERN_ERR, "I/O error on journal");
return;
}
num_fc_blocks = be32_to_cpu(journal->j_superblock->s_num_fc_blks);
if (jbd2_fc_init(journal, num_fc_blocks ? num_fc_blocks :
EXT4_NUM_FC_BLKS)) {
pr_warn("Error while enabling fast commits, turning off."); pr_warn("Error while enabling fast commits, turning off.");
ext4_clear_feature_fast_commit(sb); ext4_clear_feature_fast_commit(sb);
} }

View File

@ -275,7 +275,7 @@ int ext4fs_dirhash(const struct inode *dir, const char *name, int len,
struct dx_hash_info *hinfo) struct dx_hash_info *hinfo)
{ {
#ifdef CONFIG_UNICODE #ifdef CONFIG_UNICODE
const struct unicode_map *um = EXT4_SB(dir->i_sb)->s_encoding; const struct unicode_map *um = dir->i_sb->s_encoding;
int r, dlen; int r, dlen;
unsigned char *buff; unsigned char *buff;
struct qstr qstr = {.name = name, .len = len }; struct qstr qstr = {.name = name, .len = len };

View File

@ -1918,7 +1918,7 @@ static int __ext4_journalled_writepage(struct page *page,
} }
if (ret == 0) if (ret == 0)
ret = err; ret = err;
err = ext4_jbd2_inode_add_write(handle, inode, 0, len); err = ext4_jbd2_inode_add_write(handle, inode, page_offset(page), len);
if (ret == 0) if (ret == 0)
ret = err; ret = err;
EXT4_I(inode)->i_datasync_tid = handle->h_transaction->t_tid; EXT4_I(inode)->i_datasync_tid = handle->h_transaction->t_tid;
@ -3307,10 +3307,12 @@ static bool ext4_inode_datasync_dirty(struct inode *inode)
if (journal) { if (journal) {
if (jbd2_transaction_committed(journal, if (jbd2_transaction_committed(journal,
EXT4_I(inode)->i_datasync_tid)) EXT4_I(inode)->i_datasync_tid))
return true; return false;
return atomic_read(&EXT4_SB(inode->i_sb)->s_fc_subtid) >= if (test_opt2(inode->i_sb, JOURNAL_FAST_COMMIT))
EXT4_I(inode)->i_fc_committed_subtid; return atomic_read(&EXT4_SB(inode->i_sb)->s_fc_subtid) <
EXT4_I(inode)->i_fc_committed_subtid;
return true;
} }
/* Any metadata buffers to write? */ /* Any metadata buffers to write? */
@ -6157,7 +6159,8 @@ retry_alloc:
if (ext4_walk_page_buffers(handle, page_buffers(page), if (ext4_walk_page_buffers(handle, page_buffers(page),
0, len, NULL, write_end_fn)) 0, len, NULL, write_end_fn))
goto out_error; goto out_error;
if (ext4_jbd2_inode_add_write(handle, inode, 0, len)) if (ext4_jbd2_inode_add_write(handle, inode,
page_offset(page), len))
goto out_error; goto out_error;
ext4_set_inode_state(inode, EXT4_STATE_JDATA); ext4_set_inode_state(inode, EXT4_STATE_JDATA);
} else { } else {

View File

@ -1285,8 +1285,8 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block)
int ext4_ci_compare(const struct inode *parent, const struct qstr *name, int ext4_ci_compare(const struct inode *parent, const struct qstr *name,
const struct qstr *entry, bool quick) const struct qstr *entry, bool quick)
{ {
const struct ext4_sb_info *sbi = EXT4_SB(parent->i_sb); const struct super_block *sb = parent->i_sb;
const struct unicode_map *um = sbi->s_encoding; const struct unicode_map *um = sb->s_encoding;
int ret; int ret;
if (quick) if (quick)
@ -1298,7 +1298,7 @@ int ext4_ci_compare(const struct inode *parent, const struct qstr *name,
/* Handle invalid character sequence as either an error /* Handle invalid character sequence as either an error
* or as an opaque byte sequence. * or as an opaque byte sequence.
*/ */
if (ext4_has_strict_mode(sbi)) if (sb_has_strict_encoding(sb))
return -EINVAL; return -EINVAL;
if (name->len != entry->len) if (name->len != entry->len)
@ -1315,7 +1315,7 @@ void ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
{ {
int len; int len;
if (!IS_CASEFOLDED(dir) || !EXT4_SB(dir->i_sb)->s_encoding) { if (!IS_CASEFOLDED(dir) || !dir->i_sb->s_encoding) {
cf_name->name = NULL; cf_name->name = NULL;
return; return;
} }
@ -1324,7 +1324,7 @@ void ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
if (!cf_name->name) if (!cf_name->name)
return; return;
len = utf8_casefold(EXT4_SB(dir->i_sb)->s_encoding, len = utf8_casefold(dir->i_sb->s_encoding,
iname, cf_name->name, iname, cf_name->name,
EXT4_NAME_LEN); EXT4_NAME_LEN);
if (len <= 0) { if (len <= 0) {
@ -1361,7 +1361,7 @@ static inline bool ext4_match(const struct inode *parent,
#endif #endif
#ifdef CONFIG_UNICODE #ifdef CONFIG_UNICODE
if (EXT4_SB(parent->i_sb)->s_encoding && IS_CASEFOLDED(parent)) { if (parent->i_sb->s_encoding && IS_CASEFOLDED(parent)) {
if (fname->cf_name.name) { if (fname->cf_name.name) {
struct qstr cf = {.name = fname->cf_name.name, struct qstr cf = {.name = fname->cf_name.name,
.len = fname->cf_name.len}; .len = fname->cf_name.len};
@ -2180,9 +2180,6 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct ext4_dir_entry_2 *de; struct ext4_dir_entry_2 *de;
struct super_block *sb; struct super_block *sb;
#ifdef CONFIG_UNICODE
struct ext4_sb_info *sbi;
#endif
struct ext4_filename fname; struct ext4_filename fname;
int retval; int retval;
int dx_fallback=0; int dx_fallback=0;
@ -2199,9 +2196,8 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
return -EINVAL; return -EINVAL;
#ifdef CONFIG_UNICODE #ifdef CONFIG_UNICODE
sbi = EXT4_SB(sb); if (sb_has_strict_encoding(sb) && IS_CASEFOLDED(dir) &&
if (ext4_has_strict_mode(sbi) && IS_CASEFOLDED(dir) && sb->s_encoding && utf8_validate(sb->s_encoding, &dentry->d_name))
sbi->s_encoding && utf8_validate(sbi->s_encoding, &dentry->d_name))
return -EINVAL; return -EINVAL;
#endif #endif

View File

@ -1288,7 +1288,7 @@ static void ext4_put_super(struct super_block *sb)
fs_put_dax(sbi->s_daxdev); fs_put_dax(sbi->s_daxdev);
fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy); fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy);
#ifdef CONFIG_UNICODE #ifdef CONFIG_UNICODE
utf8_unload(sbi->s_encoding); utf8_unload(sb->s_encoding);
#endif #endif
kfree(sbi); kfree(sbi);
} }
@ -4303,7 +4303,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
goto failed_mount; goto failed_mount;
#ifdef CONFIG_UNICODE #ifdef CONFIG_UNICODE
if (ext4_has_feature_casefold(sb) && !sbi->s_encoding) { if (ext4_has_feature_casefold(sb) && !sb->s_encoding) {
const struct ext4_sb_encodings *encoding_info; const struct ext4_sb_encodings *encoding_info;
struct unicode_map *encoding; struct unicode_map *encoding;
__u16 encoding_flags; __u16 encoding_flags;
@ -4334,8 +4334,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
"%s-%s with flags 0x%hx", encoding_info->name, "%s-%s with flags 0x%hx", encoding_info->name,
encoding_info->version?:"\b", encoding_flags); encoding_info->version?:"\b", encoding_flags);
sbi->s_encoding = encoding; sb->s_encoding = encoding;
sbi->s_encoding_flags = encoding_flags; sb->s_encoding_flags = encoding_flags;
} }
#endif #endif
@ -4777,8 +4777,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
INIT_LIST_HEAD(&sbi->s_fc_dentry_q[FC_Q_MAIN]); INIT_LIST_HEAD(&sbi->s_fc_dentry_q[FC_Q_MAIN]);
INIT_LIST_HEAD(&sbi->s_fc_dentry_q[FC_Q_STAGING]); INIT_LIST_HEAD(&sbi->s_fc_dentry_q[FC_Q_STAGING]);
sbi->s_fc_bytes = 0; sbi->s_fc_bytes = 0;
sbi->s_mount_state &= ~EXT4_FC_INELIGIBLE; sbi->s_mount_flags &= ~EXT4_MF_FC_INELIGIBLE;
sbi->s_mount_state &= ~EXT4_FC_COMMITTING; sbi->s_mount_flags &= ~EXT4_MF_FC_COMMITTING;
spin_lock_init(&sbi->s_fc_lock); spin_lock_init(&sbi->s_fc_lock);
memset(&sbi->s_fc_stats, 0, sizeof(sbi->s_fc_stats)); memset(&sbi->s_fc_stats, 0, sizeof(sbi->s_fc_stats));
sbi->s_fc_replay_state.fc_regions = NULL; sbi->s_fc_replay_state.fc_regions = NULL;
@ -4975,7 +4975,7 @@ no_journal:
} }
#ifdef CONFIG_UNICODE #ifdef CONFIG_UNICODE
if (sbi->s_encoding) if (sb->s_encoding)
sb->s_d_op = &ext4_dentry_ops; sb->s_d_op = &ext4_dentry_ops;
#endif #endif
@ -5184,7 +5184,7 @@ failed_mount:
crypto_free_shash(sbi->s_chksum_driver); crypto_free_shash(sbi->s_chksum_driver);
#ifdef CONFIG_UNICODE #ifdef CONFIG_UNICODE
utf8_unload(sbi->s_encoding); utf8_unload(sb->s_encoding);
#endif #endif
#ifdef CONFIG_QUOTA #ifdef CONFIG_QUOTA

View File

@ -315,6 +315,7 @@ EXT4_ATTR_FEATURE(casefold);
EXT4_ATTR_FEATURE(verity); EXT4_ATTR_FEATURE(verity);
#endif #endif
EXT4_ATTR_FEATURE(metadata_csum_seed); EXT4_ATTR_FEATURE(metadata_csum_seed);
EXT4_ATTR_FEATURE(fast_commit);
static struct attribute *ext4_feat_attrs[] = { static struct attribute *ext4_feat_attrs[] = {
ATTR_LIST(lazy_itable_init), ATTR_LIST(lazy_itable_init),
@ -331,6 +332,7 @@ static struct attribute *ext4_feat_attrs[] = {
ATTR_LIST(verity), ATTR_LIST(verity),
#endif #endif
ATTR_LIST(metadata_csum_seed), ATTR_LIST(metadata_csum_seed),
ATTR_LIST(fast_commit),
NULL, NULL,
}; };
ATTRIBUTE_GROUPS(ext4_feat); ATTRIBUTE_GROUPS(ext4_feat);

View File

@ -263,7 +263,10 @@ typedef struct journal_superblock_s
/* 0x0050 */ /* 0x0050 */
__u8 s_checksum_type; /* checksum type */ __u8 s_checksum_type; /* checksum type */
__u8 s_padding2[3]; __u8 s_padding2[3];
__u32 s_padding[42]; /* 0x0054 */
__be32 s_num_fc_blks; /* Number of fast commit blocks */
/* 0x0058 */
__u32 s_padding[41];
__be32 s_checksum; /* crc32c(superblock) */ __be32 s_checksum; /* crc32c(superblock) */
/* 0x0100 */ /* 0x0100 */
@ -1253,7 +1256,7 @@ struct journal_s
*/ */
void (*j_fc_cleanup_callback)(struct journal_s *journal, int); void (*j_fc_cleanup_callback)(struct journal_s *journal, int);
/* /**
* @j_fc_replay_callback: * @j_fc_replay_callback:
* *
* File-system specific function that performs replay of a fast * File-system specific function that performs replay of a fast