Miscellaneous ext4 bug fixes for v5.13
-----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEK2m5VNv+CHkogTfJ8vlZVpUNgaMFAmC82AQACgkQ8vlZVpUN gaOkAgf+KH57P/P0sB6aVBHpAzqa9jTKJWMA5kpCqYUDkYlfF7n2hwsjMzWpJ5MY ZvFpKAflmRnve/ULUZQX6+zrcbieNs3e+6VFZrZ0PmxN0dupyISLY7jnvCRDleA7 BFO34AcH+QEst9zXJmgta9eoy3LA8sawhQ/d7ujVY+IRFk40m26fuAMiaGznlQJ5 dmrx7pHZWKFIDFIg2TdFlP+Voqbxs2VTT16gmWpGBdTyWYHKjbSOLKJFc9DwYeE9 aANf6iIzwXz7y9pZiOnTrGuKDEJcIZNESkbIqw62YgqsoObLbsbCZNmNcqxyHpYQ Mh3L59KtmjANW3iOxQfyxkNTugxchw== =BSnf -----END PGP SIGNATURE----- Merge tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4 Pull ext4 fixes from Ted Ts'o: "Miscellaneous ext4 bug fixes" * tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: ext4: Only advertise encrypted_casefold when encryption and unicode are enabled ext4: fix no-key deletion for encrypt+casefold ext4: fix memory leak in ext4_fill_super ext4: fix fast commit alignment issues ext4: fix bug on in ext4_es_cache_extent as ext4_split_extent_at failed ext4: fix accessing uninit percpu counter variable with fast_commit ext4: fix memory leak in ext4_mb_init_backend on error path.
This commit is contained in:
commit
20e41d9bc8
8 changed files with 135 additions and 126 deletions
|
@ -3206,7 +3206,10 @@ static int ext4_split_extent_at(handle_t *handle,
|
||||||
ext4_ext_mark_unwritten(ex2);
|
ext4_ext_mark_unwritten(ex2);
|
||||||
|
|
||||||
err = ext4_ext_insert_extent(handle, inode, ppath, &newex, flags);
|
err = ext4_ext_insert_extent(handle, inode, ppath, &newex, flags);
|
||||||
if (err == -ENOSPC && (EXT4_EXT_MAY_ZEROOUT & split_flag)) {
|
if (err != -ENOSPC && err != -EDQUOT)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (EXT4_EXT_MAY_ZEROOUT & split_flag) {
|
||||||
if (split_flag & (EXT4_EXT_DATA_VALID1|EXT4_EXT_DATA_VALID2)) {
|
if (split_flag & (EXT4_EXT_DATA_VALID1|EXT4_EXT_DATA_VALID2)) {
|
||||||
if (split_flag & EXT4_EXT_DATA_VALID1) {
|
if (split_flag & EXT4_EXT_DATA_VALID1) {
|
||||||
err = ext4_ext_zeroout(inode, ex2);
|
err = ext4_ext_zeroout(inode, ex2);
|
||||||
|
@ -3232,25 +3235,22 @@ static int ext4_split_extent_at(handle_t *handle,
|
||||||
ext4_ext_pblock(&orig_ex));
|
ext4_ext_pblock(&orig_ex));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err)
|
if (!err) {
|
||||||
goto fix_extent_len;
|
/* update the extent length and mark as initialized */
|
||||||
/* update the extent length and mark as initialized */
|
ex->ee_len = cpu_to_le16(ee_len);
|
||||||
ex->ee_len = cpu_to_le16(ee_len);
|
ext4_ext_try_to_merge(handle, inode, path, ex);
|
||||||
ext4_ext_try_to_merge(handle, inode, path, ex);
|
err = ext4_ext_dirty(handle, inode, path + path->p_depth);
|
||||||
err = ext4_ext_dirty(handle, inode, path + path->p_depth);
|
if (!err)
|
||||||
if (err)
|
/* update extent status tree */
|
||||||
goto fix_extent_len;
|
err = ext4_zeroout_es(inode, &zero_ex);
|
||||||
|
/* If we failed at this point, we don't know in which
|
||||||
/* update extent status tree */
|
* state the extent tree exactly is so don't try to fix
|
||||||
err = ext4_zeroout_es(inode, &zero_ex);
|
* length of the original extent as it may do even more
|
||||||
|
* damage.
|
||||||
goto out;
|
*/
|
||||||
} else if (err)
|
goto out;
|
||||||
goto fix_extent_len;
|
}
|
||||||
|
}
|
||||||
out:
|
|
||||||
ext4_ext_show_leaf(inode, path);
|
|
||||||
return err;
|
|
||||||
|
|
||||||
fix_extent_len:
|
fix_extent_len:
|
||||||
ex->ee_len = orig_ex.ee_len;
|
ex->ee_len = orig_ex.ee_len;
|
||||||
|
@ -3260,6 +3260,9 @@ static int ext4_split_extent_at(handle_t *handle,
|
||||||
*/
|
*/
|
||||||
ext4_ext_dirty(handle, inode, path + path->p_depth);
|
ext4_ext_dirty(handle, inode, path + path->p_depth);
|
||||||
return err;
|
return err;
|
||||||
|
out:
|
||||||
|
ext4_ext_show_leaf(inode, path);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1288,28 +1288,29 @@ struct dentry_info_args {
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void tl_to_darg(struct dentry_info_args *darg,
|
static inline void tl_to_darg(struct dentry_info_args *darg,
|
||||||
struct ext4_fc_tl *tl)
|
struct ext4_fc_tl *tl, u8 *val)
|
||||||
{
|
{
|
||||||
struct ext4_fc_dentry_info *fcd;
|
struct ext4_fc_dentry_info fcd;
|
||||||
|
|
||||||
fcd = (struct ext4_fc_dentry_info *)ext4_fc_tag_val(tl);
|
memcpy(&fcd, val, sizeof(fcd));
|
||||||
|
|
||||||
darg->parent_ino = le32_to_cpu(fcd->fc_parent_ino);
|
darg->parent_ino = le32_to_cpu(fcd.fc_parent_ino);
|
||||||
darg->ino = le32_to_cpu(fcd->fc_ino);
|
darg->ino = le32_to_cpu(fcd.fc_ino);
|
||||||
darg->dname = fcd->fc_dname;
|
darg->dname = val + offsetof(struct ext4_fc_dentry_info, fc_dname);
|
||||||
darg->dname_len = ext4_fc_tag_len(tl) -
|
darg->dname_len = le16_to_cpu(tl->fc_len) -
|
||||||
sizeof(struct ext4_fc_dentry_info);
|
sizeof(struct ext4_fc_dentry_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unlink replay function */
|
/* Unlink replay function */
|
||||||
static int ext4_fc_replay_unlink(struct super_block *sb, struct ext4_fc_tl *tl)
|
static int ext4_fc_replay_unlink(struct super_block *sb, struct ext4_fc_tl *tl,
|
||||||
|
u8 *val)
|
||||||
{
|
{
|
||||||
struct inode *inode, *old_parent;
|
struct inode *inode, *old_parent;
|
||||||
struct qstr entry;
|
struct qstr entry;
|
||||||
struct dentry_info_args darg;
|
struct dentry_info_args darg;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
tl_to_darg(&darg, tl);
|
tl_to_darg(&darg, tl, val);
|
||||||
|
|
||||||
trace_ext4_fc_replay(sb, EXT4_FC_TAG_UNLINK, darg.ino,
|
trace_ext4_fc_replay(sb, EXT4_FC_TAG_UNLINK, darg.ino,
|
||||||
darg.parent_ino, darg.dname_len);
|
darg.parent_ino, darg.dname_len);
|
||||||
|
@ -1399,13 +1400,14 @@ static int ext4_fc_replay_link_internal(struct super_block *sb,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Link replay function */
|
/* Link replay function */
|
||||||
static int ext4_fc_replay_link(struct super_block *sb, struct ext4_fc_tl *tl)
|
static int ext4_fc_replay_link(struct super_block *sb, struct ext4_fc_tl *tl,
|
||||||
|
u8 *val)
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct dentry_info_args darg;
|
struct dentry_info_args darg;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
tl_to_darg(&darg, tl);
|
tl_to_darg(&darg, tl, val);
|
||||||
trace_ext4_fc_replay(sb, EXT4_FC_TAG_LINK, darg.ino,
|
trace_ext4_fc_replay(sb, EXT4_FC_TAG_LINK, darg.ino,
|
||||||
darg.parent_ino, darg.dname_len);
|
darg.parent_ino, darg.dname_len);
|
||||||
|
|
||||||
|
@ -1450,9 +1452,10 @@ static int ext4_fc_record_modified_inode(struct super_block *sb, int ino)
|
||||||
/*
|
/*
|
||||||
* Inode replay function
|
* Inode replay function
|
||||||
*/
|
*/
|
||||||
static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl)
|
static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl,
|
||||||
|
u8 *val)
|
||||||
{
|
{
|
||||||
struct ext4_fc_inode *fc_inode;
|
struct ext4_fc_inode fc_inode;
|
||||||
struct ext4_inode *raw_inode;
|
struct ext4_inode *raw_inode;
|
||||||
struct ext4_inode *raw_fc_inode;
|
struct ext4_inode *raw_fc_inode;
|
||||||
struct inode *inode = NULL;
|
struct inode *inode = NULL;
|
||||||
|
@ -1460,9 +1463,9 @@ static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl)
|
||||||
int inode_len, ino, ret, tag = le16_to_cpu(tl->fc_tag);
|
int inode_len, ino, ret, tag = le16_to_cpu(tl->fc_tag);
|
||||||
struct ext4_extent_header *eh;
|
struct ext4_extent_header *eh;
|
||||||
|
|
||||||
fc_inode = (struct ext4_fc_inode *)ext4_fc_tag_val(tl);
|
memcpy(&fc_inode, val, sizeof(fc_inode));
|
||||||
|
|
||||||
ino = le32_to_cpu(fc_inode->fc_ino);
|
ino = le32_to_cpu(fc_inode.fc_ino);
|
||||||
trace_ext4_fc_replay(sb, tag, ino, 0, 0);
|
trace_ext4_fc_replay(sb, tag, ino, 0, 0);
|
||||||
|
|
||||||
inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL);
|
inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL);
|
||||||
|
@ -1474,12 +1477,13 @@ static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl)
|
||||||
|
|
||||||
ext4_fc_record_modified_inode(sb, ino);
|
ext4_fc_record_modified_inode(sb, ino);
|
||||||
|
|
||||||
raw_fc_inode = (struct ext4_inode *)fc_inode->fc_raw_inode;
|
raw_fc_inode = (struct ext4_inode *)
|
||||||
|
(val + offsetof(struct ext4_fc_inode, fc_raw_inode));
|
||||||
ret = ext4_get_fc_inode_loc(sb, ino, &iloc);
|
ret = ext4_get_fc_inode_loc(sb, ino, &iloc);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
inode_len = ext4_fc_tag_len(tl) - sizeof(struct ext4_fc_inode);
|
inode_len = le16_to_cpu(tl->fc_len) - sizeof(struct ext4_fc_inode);
|
||||||
raw_inode = ext4_raw_inode(&iloc);
|
raw_inode = ext4_raw_inode(&iloc);
|
||||||
|
|
||||||
memcpy(raw_inode, raw_fc_inode, offsetof(struct ext4_inode, i_block));
|
memcpy(raw_inode, raw_fc_inode, offsetof(struct ext4_inode, i_block));
|
||||||
|
@ -1547,14 +1551,15 @@ static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl)
|
||||||
* inode for which we are trying to create a dentry here, should already have
|
* inode for which we are trying to create a dentry here, should already have
|
||||||
* been replayed before we start here.
|
* been replayed before we start here.
|
||||||
*/
|
*/
|
||||||
static int ext4_fc_replay_create(struct super_block *sb, struct ext4_fc_tl *tl)
|
static int ext4_fc_replay_create(struct super_block *sb, struct ext4_fc_tl *tl,
|
||||||
|
u8 *val)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct inode *inode = NULL;
|
struct inode *inode = NULL;
|
||||||
struct inode *dir = NULL;
|
struct inode *dir = NULL;
|
||||||
struct dentry_info_args darg;
|
struct dentry_info_args darg;
|
||||||
|
|
||||||
tl_to_darg(&darg, tl);
|
tl_to_darg(&darg, tl, val);
|
||||||
|
|
||||||
trace_ext4_fc_replay(sb, EXT4_FC_TAG_CREAT, darg.ino,
|
trace_ext4_fc_replay(sb, EXT4_FC_TAG_CREAT, darg.ino,
|
||||||
darg.parent_ino, darg.dname_len);
|
darg.parent_ino, darg.dname_len);
|
||||||
|
@ -1633,9 +1638,9 @@ static int ext4_fc_record_regions(struct super_block *sb, int ino,
|
||||||
|
|
||||||
/* Replay add range tag */
|
/* Replay add range tag */
|
||||||
static int ext4_fc_replay_add_range(struct super_block *sb,
|
static int ext4_fc_replay_add_range(struct super_block *sb,
|
||||||
struct ext4_fc_tl *tl)
|
struct ext4_fc_tl *tl, u8 *val)
|
||||||
{
|
{
|
||||||
struct ext4_fc_add_range *fc_add_ex;
|
struct ext4_fc_add_range fc_add_ex;
|
||||||
struct ext4_extent newex, *ex;
|
struct ext4_extent newex, *ex;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
ext4_lblk_t start, cur;
|
ext4_lblk_t start, cur;
|
||||||
|
@ -1645,15 +1650,14 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
|
||||||
struct ext4_ext_path *path = NULL;
|
struct ext4_ext_path *path = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
fc_add_ex = (struct ext4_fc_add_range *)ext4_fc_tag_val(tl);
|
memcpy(&fc_add_ex, val, sizeof(fc_add_ex));
|
||||||
ex = (struct ext4_extent *)&fc_add_ex->fc_ex;
|
ex = (struct ext4_extent *)&fc_add_ex.fc_ex;
|
||||||
|
|
||||||
trace_ext4_fc_replay(sb, EXT4_FC_TAG_ADD_RANGE,
|
trace_ext4_fc_replay(sb, EXT4_FC_TAG_ADD_RANGE,
|
||||||
le32_to_cpu(fc_add_ex->fc_ino), le32_to_cpu(ex->ee_block),
|
le32_to_cpu(fc_add_ex.fc_ino), le32_to_cpu(ex->ee_block),
|
||||||
ext4_ext_get_actual_len(ex));
|
ext4_ext_get_actual_len(ex));
|
||||||
|
|
||||||
inode = ext4_iget(sb, le32_to_cpu(fc_add_ex->fc_ino),
|
inode = ext4_iget(sb, le32_to_cpu(fc_add_ex.fc_ino), EXT4_IGET_NORMAL);
|
||||||
EXT4_IGET_NORMAL);
|
|
||||||
if (IS_ERR(inode)) {
|
if (IS_ERR(inode)) {
|
||||||
jbd_debug(1, "Inode not found.");
|
jbd_debug(1, "Inode not found.");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1762,32 +1766,33 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
|
||||||
|
|
||||||
/* Replay DEL_RANGE tag */
|
/* Replay DEL_RANGE tag */
|
||||||
static int
|
static int
|
||||||
ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl)
|
ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl,
|
||||||
|
u8 *val)
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct ext4_fc_del_range *lrange;
|
struct ext4_fc_del_range lrange;
|
||||||
struct ext4_map_blocks map;
|
struct ext4_map_blocks map;
|
||||||
ext4_lblk_t cur, remaining;
|
ext4_lblk_t cur, remaining;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
lrange = (struct ext4_fc_del_range *)ext4_fc_tag_val(tl);
|
memcpy(&lrange, val, sizeof(lrange));
|
||||||
cur = le32_to_cpu(lrange->fc_lblk);
|
cur = le32_to_cpu(lrange.fc_lblk);
|
||||||
remaining = le32_to_cpu(lrange->fc_len);
|
remaining = le32_to_cpu(lrange.fc_len);
|
||||||
|
|
||||||
trace_ext4_fc_replay(sb, EXT4_FC_TAG_DEL_RANGE,
|
trace_ext4_fc_replay(sb, EXT4_FC_TAG_DEL_RANGE,
|
||||||
le32_to_cpu(lrange->fc_ino), cur, remaining);
|
le32_to_cpu(lrange.fc_ino), cur, remaining);
|
||||||
|
|
||||||
inode = ext4_iget(sb, le32_to_cpu(lrange->fc_ino), EXT4_IGET_NORMAL);
|
inode = ext4_iget(sb, le32_to_cpu(lrange.fc_ino), EXT4_IGET_NORMAL);
|
||||||
if (IS_ERR(inode)) {
|
if (IS_ERR(inode)) {
|
||||||
jbd_debug(1, "Inode %d not found", le32_to_cpu(lrange->fc_ino));
|
jbd_debug(1, "Inode %d not found", le32_to_cpu(lrange.fc_ino));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ext4_fc_record_modified_inode(sb, inode->i_ino);
|
ret = ext4_fc_record_modified_inode(sb, inode->i_ino);
|
||||||
|
|
||||||
jbd_debug(1, "DEL_RANGE, inode %ld, lblk %d, len %d\n",
|
jbd_debug(1, "DEL_RANGE, inode %ld, lblk %d, len %d\n",
|
||||||
inode->i_ino, le32_to_cpu(lrange->fc_lblk),
|
inode->i_ino, le32_to_cpu(lrange.fc_lblk),
|
||||||
le32_to_cpu(lrange->fc_len));
|
le32_to_cpu(lrange.fc_len));
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
map.m_lblk = cur;
|
map.m_lblk = cur;
|
||||||
map.m_len = remaining;
|
map.m_len = remaining;
|
||||||
|
@ -1808,8 +1813,8 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ext4_punch_hole(inode,
|
ret = ext4_punch_hole(inode,
|
||||||
le32_to_cpu(lrange->fc_lblk) << sb->s_blocksize_bits,
|
le32_to_cpu(lrange.fc_lblk) << sb->s_blocksize_bits,
|
||||||
le32_to_cpu(lrange->fc_len) << sb->s_blocksize_bits);
|
le32_to_cpu(lrange.fc_len) << sb->s_blocksize_bits);
|
||||||
if (ret)
|
if (ret)
|
||||||
jbd_debug(1, "ext4_punch_hole returned %d", ret);
|
jbd_debug(1, "ext4_punch_hole returned %d", ret);
|
||||||
ext4_ext_replay_shrink_inode(inode,
|
ext4_ext_replay_shrink_inode(inode,
|
||||||
|
@ -1925,11 +1930,11 @@ static int ext4_fc_replay_scan(journal_t *journal,
|
||||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||||
struct ext4_fc_replay_state *state;
|
struct ext4_fc_replay_state *state;
|
||||||
int ret = JBD2_FC_REPLAY_CONTINUE;
|
int ret = JBD2_FC_REPLAY_CONTINUE;
|
||||||
struct ext4_fc_add_range *ext;
|
struct ext4_fc_add_range ext;
|
||||||
struct ext4_fc_tl *tl;
|
struct ext4_fc_tl tl;
|
||||||
struct ext4_fc_tail *tail;
|
struct ext4_fc_tail tail;
|
||||||
__u8 *start, *end;
|
__u8 *start, *end, *cur, *val;
|
||||||
struct ext4_fc_head *head;
|
struct ext4_fc_head head;
|
||||||
struct ext4_extent *ex;
|
struct ext4_extent *ex;
|
||||||
|
|
||||||
state = &sbi->s_fc_replay_state;
|
state = &sbi->s_fc_replay_state;
|
||||||
|
@ -1956,15 +1961,17 @@ static int ext4_fc_replay_scan(journal_t *journal,
|
||||||
}
|
}
|
||||||
|
|
||||||
state->fc_replay_expected_off++;
|
state->fc_replay_expected_off++;
|
||||||
fc_for_each_tl(start, end, tl) {
|
for (cur = start; cur < end; cur = cur + sizeof(tl) + le16_to_cpu(tl.fc_len)) {
|
||||||
|
memcpy(&tl, cur, sizeof(tl));
|
||||||
|
val = cur + sizeof(tl);
|
||||||
jbd_debug(3, "Scan phase, tag:%s, blk %lld\n",
|
jbd_debug(3, "Scan phase, tag:%s, blk %lld\n",
|
||||||
tag2str(le16_to_cpu(tl->fc_tag)), bh->b_blocknr);
|
tag2str(le16_to_cpu(tl.fc_tag)), bh->b_blocknr);
|
||||||
switch (le16_to_cpu(tl->fc_tag)) {
|
switch (le16_to_cpu(tl.fc_tag)) {
|
||||||
case EXT4_FC_TAG_ADD_RANGE:
|
case EXT4_FC_TAG_ADD_RANGE:
|
||||||
ext = (struct ext4_fc_add_range *)ext4_fc_tag_val(tl);
|
memcpy(&ext, val, sizeof(ext));
|
||||||
ex = (struct ext4_extent *)&ext->fc_ex;
|
ex = (struct ext4_extent *)&ext.fc_ex;
|
||||||
ret = ext4_fc_record_regions(sb,
|
ret = ext4_fc_record_regions(sb,
|
||||||
le32_to_cpu(ext->fc_ino),
|
le32_to_cpu(ext.fc_ino),
|
||||||
le32_to_cpu(ex->ee_block), ext4_ext_pblock(ex),
|
le32_to_cpu(ex->ee_block), ext4_ext_pblock(ex),
|
||||||
ext4_ext_get_actual_len(ex));
|
ext4_ext_get_actual_len(ex));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -1978,18 +1985,18 @@ static int ext4_fc_replay_scan(journal_t *journal,
|
||||||
case EXT4_FC_TAG_INODE:
|
case EXT4_FC_TAG_INODE:
|
||||||
case EXT4_FC_TAG_PAD:
|
case EXT4_FC_TAG_PAD:
|
||||||
state->fc_cur_tag++;
|
state->fc_cur_tag++;
|
||||||
state->fc_crc = ext4_chksum(sbi, state->fc_crc, tl,
|
state->fc_crc = ext4_chksum(sbi, state->fc_crc, cur,
|
||||||
sizeof(*tl) + ext4_fc_tag_len(tl));
|
sizeof(tl) + le16_to_cpu(tl.fc_len));
|
||||||
break;
|
break;
|
||||||
case EXT4_FC_TAG_TAIL:
|
case EXT4_FC_TAG_TAIL:
|
||||||
state->fc_cur_tag++;
|
state->fc_cur_tag++;
|
||||||
tail = (struct ext4_fc_tail *)ext4_fc_tag_val(tl);
|
memcpy(&tail, val, sizeof(tail));
|
||||||
state->fc_crc = ext4_chksum(sbi, state->fc_crc, tl,
|
state->fc_crc = ext4_chksum(sbi, state->fc_crc, cur,
|
||||||
sizeof(*tl) +
|
sizeof(tl) +
|
||||||
offsetof(struct ext4_fc_tail,
|
offsetof(struct ext4_fc_tail,
|
||||||
fc_crc));
|
fc_crc));
|
||||||
if (le32_to_cpu(tail->fc_tid) == expected_tid &&
|
if (le32_to_cpu(tail.fc_tid) == expected_tid &&
|
||||||
le32_to_cpu(tail->fc_crc) == state->fc_crc) {
|
le32_to_cpu(tail.fc_crc) == state->fc_crc) {
|
||||||
state->fc_replay_num_tags = state->fc_cur_tag;
|
state->fc_replay_num_tags = state->fc_cur_tag;
|
||||||
state->fc_regions_valid =
|
state->fc_regions_valid =
|
||||||
state->fc_regions_used;
|
state->fc_regions_used;
|
||||||
|
@ -2000,19 +2007,19 @@ static int ext4_fc_replay_scan(journal_t *journal,
|
||||||
state->fc_crc = 0;
|
state->fc_crc = 0;
|
||||||
break;
|
break;
|
||||||
case EXT4_FC_TAG_HEAD:
|
case EXT4_FC_TAG_HEAD:
|
||||||
head = (struct ext4_fc_head *)ext4_fc_tag_val(tl);
|
memcpy(&head, val, sizeof(head));
|
||||||
if (le32_to_cpu(head->fc_features) &
|
if (le32_to_cpu(head.fc_features) &
|
||||||
~EXT4_FC_SUPPORTED_FEATURES) {
|
~EXT4_FC_SUPPORTED_FEATURES) {
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (le32_to_cpu(head->fc_tid) != expected_tid) {
|
if (le32_to_cpu(head.fc_tid) != expected_tid) {
|
||||||
ret = JBD2_FC_REPLAY_STOP;
|
ret = JBD2_FC_REPLAY_STOP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
state->fc_cur_tag++;
|
state->fc_cur_tag++;
|
||||||
state->fc_crc = ext4_chksum(sbi, state->fc_crc, tl,
|
state->fc_crc = ext4_chksum(sbi, state->fc_crc, cur,
|
||||||
sizeof(*tl) + ext4_fc_tag_len(tl));
|
sizeof(tl) + le16_to_cpu(tl.fc_len));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = state->fc_replay_num_tags ?
|
ret = state->fc_replay_num_tags ?
|
||||||
|
@ -2036,11 +2043,11 @@ static int ext4_fc_replay(journal_t *journal, struct buffer_head *bh,
|
||||||
{
|
{
|
||||||
struct super_block *sb = journal->j_private;
|
struct super_block *sb = journal->j_private;
|
||||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||||
struct ext4_fc_tl *tl;
|
struct ext4_fc_tl tl;
|
||||||
__u8 *start, *end;
|
__u8 *start, *end, *cur, *val;
|
||||||
int ret = JBD2_FC_REPLAY_CONTINUE;
|
int ret = JBD2_FC_REPLAY_CONTINUE;
|
||||||
struct ext4_fc_replay_state *state = &sbi->s_fc_replay_state;
|
struct ext4_fc_replay_state *state = &sbi->s_fc_replay_state;
|
||||||
struct ext4_fc_tail *tail;
|
struct ext4_fc_tail tail;
|
||||||
|
|
||||||
if (pass == PASS_SCAN) {
|
if (pass == PASS_SCAN) {
|
||||||
state->fc_current_pass = PASS_SCAN;
|
state->fc_current_pass = PASS_SCAN;
|
||||||
|
@ -2067,49 +2074,52 @@ static int ext4_fc_replay(journal_t *journal, struct buffer_head *bh,
|
||||||
start = (u8 *)bh->b_data;
|
start = (u8 *)bh->b_data;
|
||||||
end = (__u8 *)bh->b_data + journal->j_blocksize - 1;
|
end = (__u8 *)bh->b_data + journal->j_blocksize - 1;
|
||||||
|
|
||||||
fc_for_each_tl(start, end, tl) {
|
for (cur = start; cur < end; cur = cur + sizeof(tl) + le16_to_cpu(tl.fc_len)) {
|
||||||
|
memcpy(&tl, cur, sizeof(tl));
|
||||||
|
val = cur + sizeof(tl);
|
||||||
|
|
||||||
if (state->fc_replay_num_tags == 0) {
|
if (state->fc_replay_num_tags == 0) {
|
||||||
ret = JBD2_FC_REPLAY_STOP;
|
ret = JBD2_FC_REPLAY_STOP;
|
||||||
ext4_fc_set_bitmaps_and_counters(sb);
|
ext4_fc_set_bitmaps_and_counters(sb);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
jbd_debug(3, "Replay phase, tag:%s\n",
|
jbd_debug(3, "Replay phase, tag:%s\n",
|
||||||
tag2str(le16_to_cpu(tl->fc_tag)));
|
tag2str(le16_to_cpu(tl.fc_tag)));
|
||||||
state->fc_replay_num_tags--;
|
state->fc_replay_num_tags--;
|
||||||
switch (le16_to_cpu(tl->fc_tag)) {
|
switch (le16_to_cpu(tl.fc_tag)) {
|
||||||
case EXT4_FC_TAG_LINK:
|
case EXT4_FC_TAG_LINK:
|
||||||
ret = ext4_fc_replay_link(sb, tl);
|
ret = ext4_fc_replay_link(sb, &tl, val);
|
||||||
break;
|
break;
|
||||||
case EXT4_FC_TAG_UNLINK:
|
case EXT4_FC_TAG_UNLINK:
|
||||||
ret = ext4_fc_replay_unlink(sb, tl);
|
ret = ext4_fc_replay_unlink(sb, &tl, val);
|
||||||
break;
|
break;
|
||||||
case EXT4_FC_TAG_ADD_RANGE:
|
case EXT4_FC_TAG_ADD_RANGE:
|
||||||
ret = ext4_fc_replay_add_range(sb, tl);
|
ret = ext4_fc_replay_add_range(sb, &tl, val);
|
||||||
break;
|
break;
|
||||||
case EXT4_FC_TAG_CREAT:
|
case EXT4_FC_TAG_CREAT:
|
||||||
ret = ext4_fc_replay_create(sb, tl);
|
ret = ext4_fc_replay_create(sb, &tl, val);
|
||||||
break;
|
break;
|
||||||
case EXT4_FC_TAG_DEL_RANGE:
|
case EXT4_FC_TAG_DEL_RANGE:
|
||||||
ret = ext4_fc_replay_del_range(sb, tl);
|
ret = ext4_fc_replay_del_range(sb, &tl, val);
|
||||||
break;
|
break;
|
||||||
case EXT4_FC_TAG_INODE:
|
case EXT4_FC_TAG_INODE:
|
||||||
ret = ext4_fc_replay_inode(sb, tl);
|
ret = ext4_fc_replay_inode(sb, &tl, val);
|
||||||
break;
|
break;
|
||||||
case EXT4_FC_TAG_PAD:
|
case EXT4_FC_TAG_PAD:
|
||||||
trace_ext4_fc_replay(sb, EXT4_FC_TAG_PAD, 0,
|
trace_ext4_fc_replay(sb, EXT4_FC_TAG_PAD, 0,
|
||||||
ext4_fc_tag_len(tl), 0);
|
le16_to_cpu(tl.fc_len), 0);
|
||||||
break;
|
break;
|
||||||
case EXT4_FC_TAG_TAIL:
|
case EXT4_FC_TAG_TAIL:
|
||||||
trace_ext4_fc_replay(sb, EXT4_FC_TAG_TAIL, 0,
|
trace_ext4_fc_replay(sb, EXT4_FC_TAG_TAIL, 0,
|
||||||
ext4_fc_tag_len(tl), 0);
|
le16_to_cpu(tl.fc_len), 0);
|
||||||
tail = (struct ext4_fc_tail *)ext4_fc_tag_val(tl);
|
memcpy(&tail, val, sizeof(tail));
|
||||||
WARN_ON(le32_to_cpu(tail->fc_tid) != expected_tid);
|
WARN_ON(le32_to_cpu(tail.fc_tid) != expected_tid);
|
||||||
break;
|
break;
|
||||||
case EXT4_FC_TAG_HEAD:
|
case EXT4_FC_TAG_HEAD:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
trace_ext4_fc_replay(sb, le16_to_cpu(tl->fc_tag), 0,
|
trace_ext4_fc_replay(sb, le16_to_cpu(tl.fc_tag), 0,
|
||||||
ext4_fc_tag_len(tl), 0);
|
le16_to_cpu(tl.fc_len), 0);
|
||||||
ret = -ECANCELED;
|
ret = -ECANCELED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,13 +153,6 @@ struct ext4_fc_replay_state {
|
||||||
#define region_last(__region) (((__region)->lblk) + ((__region)->len) - 1)
|
#define region_last(__region) (((__region)->lblk) + ((__region)->len) - 1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define fc_for_each_tl(__start, __end, __tl) \
|
|
||||||
for (tl = (struct ext4_fc_tl *)(__start); \
|
|
||||||
(__u8 *)tl < (__u8 *)(__end); \
|
|
||||||
tl = (struct ext4_fc_tl *)((__u8 *)tl + \
|
|
||||||
sizeof(struct ext4_fc_tl) + \
|
|
||||||
+ le16_to_cpu(tl->fc_len)))
|
|
||||||
|
|
||||||
static inline const char *tag2str(__u16 tag)
|
static inline const char *tag2str(__u16 tag)
|
||||||
{
|
{
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
|
@ -186,16 +179,4 @@ static inline const char *tag2str(__u16 tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get length of a particular tlv */
|
|
||||||
static inline int ext4_fc_tag_len(struct ext4_fc_tl *tl)
|
|
||||||
{
|
|
||||||
return le16_to_cpu(tl->fc_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get a pointer to "value" of a tlv */
|
|
||||||
static inline __u8 *ext4_fc_tag_val(struct ext4_fc_tl *tl)
|
|
||||||
{
|
|
||||||
return (__u8 *)tl + sizeof(*tl);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __FAST_COMMIT_H__ */
|
#endif /* __FAST_COMMIT_H__ */
|
||||||
|
|
|
@ -322,14 +322,16 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
|
||||||
if (is_directory) {
|
if (is_directory) {
|
||||||
count = ext4_used_dirs_count(sb, gdp) - 1;
|
count = ext4_used_dirs_count(sb, gdp) - 1;
|
||||||
ext4_used_dirs_set(sb, gdp, count);
|
ext4_used_dirs_set(sb, gdp, count);
|
||||||
percpu_counter_dec(&sbi->s_dirs_counter);
|
if (percpu_counter_initialized(&sbi->s_dirs_counter))
|
||||||
|
percpu_counter_dec(&sbi->s_dirs_counter);
|
||||||
}
|
}
|
||||||
ext4_inode_bitmap_csum_set(sb, block_group, gdp, bitmap_bh,
|
ext4_inode_bitmap_csum_set(sb, block_group, gdp, bitmap_bh,
|
||||||
EXT4_INODES_PER_GROUP(sb) / 8);
|
EXT4_INODES_PER_GROUP(sb) / 8);
|
||||||
ext4_group_desc_csum_set(sb, block_group, gdp);
|
ext4_group_desc_csum_set(sb, block_group, gdp);
|
||||||
ext4_unlock_group(sb, block_group);
|
ext4_unlock_group(sb, block_group);
|
||||||
|
|
||||||
percpu_counter_inc(&sbi->s_freeinodes_counter);
|
if (percpu_counter_initialized(&sbi->s_freeinodes_counter))
|
||||||
|
percpu_counter_inc(&sbi->s_freeinodes_counter);
|
||||||
if (sbi->s_log_groups_per_flex) {
|
if (sbi->s_log_groups_per_flex) {
|
||||||
struct flex_groups *fg;
|
struct flex_groups *fg;
|
||||||
|
|
||||||
|
|
|
@ -3217,7 +3217,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
|
||||||
*/
|
*/
|
||||||
if (sbi->s_es->s_log_groups_per_flex >= 32) {
|
if (sbi->s_es->s_log_groups_per_flex >= 32) {
|
||||||
ext4_msg(sb, KERN_ERR, "too many log groups per flexible block group");
|
ext4_msg(sb, KERN_ERR, "too many log groups per flexible block group");
|
||||||
goto err_freesgi;
|
goto err_freebuddy;
|
||||||
}
|
}
|
||||||
sbi->s_mb_prefetch = min_t(uint, 1 << sbi->s_es->s_log_groups_per_flex,
|
sbi->s_mb_prefetch = min_t(uint, 1 << sbi->s_es->s_log_groups_per_flex,
|
||||||
BLK_MAX_SEGMENT_SIZE >> (sb->s_blocksize_bits - 9));
|
BLK_MAX_SEGMENT_SIZE >> (sb->s_blocksize_bits - 9));
|
||||||
|
|
|
@ -1376,7 +1376,8 @@ int ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
|
||||||
struct dx_hash_info *hinfo = &name->hinfo;
|
struct dx_hash_info *hinfo = &name->hinfo;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (!IS_CASEFOLDED(dir) || !dir->i_sb->s_encoding) {
|
if (!IS_CASEFOLDED(dir) || !dir->i_sb->s_encoding ||
|
||||||
|
(IS_ENCRYPTED(dir) && !fscrypt_has_encryption_key(dir))) {
|
||||||
cf_name->name = NULL;
|
cf_name->name = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1427,7 +1428,8 @@ static bool ext4_match(struct inode *parent,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_UNICODE
|
#ifdef CONFIG_UNICODE
|
||||||
if (parent->i_sb->s_encoding && IS_CASEFOLDED(parent)) {
|
if (parent->i_sb->s_encoding && IS_CASEFOLDED(parent) &&
|
||||||
|
(!IS_ENCRYPTED(parent) || fscrypt_has_encryption_key(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};
|
||||||
|
|
|
@ -4462,14 +4462,20 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sb->s_blocksize != blocksize) {
|
if (sb->s_blocksize != blocksize) {
|
||||||
|
/*
|
||||||
|
* bh must be released before kill_bdev(), otherwise
|
||||||
|
* it won't be freed and its page also. kill_bdev()
|
||||||
|
* is called by sb_set_blocksize().
|
||||||
|
*/
|
||||||
|
brelse(bh);
|
||||||
/* Validate the filesystem blocksize */
|
/* Validate the filesystem blocksize */
|
||||||
if (!sb_set_blocksize(sb, blocksize)) {
|
if (!sb_set_blocksize(sb, blocksize)) {
|
||||||
ext4_msg(sb, KERN_ERR, "bad block size %d",
|
ext4_msg(sb, KERN_ERR, "bad block size %d",
|
||||||
blocksize);
|
blocksize);
|
||||||
|
bh = NULL;
|
||||||
goto failed_mount;
|
goto failed_mount;
|
||||||
}
|
}
|
||||||
|
|
||||||
brelse(bh);
|
|
||||||
logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE;
|
logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE;
|
||||||
offset = do_div(logical_sb_block, blocksize);
|
offset = do_div(logical_sb_block, blocksize);
|
||||||
bh = ext4_sb_bread_unmovable(sb, logical_sb_block);
|
bh = ext4_sb_bread_unmovable(sb, logical_sb_block);
|
||||||
|
@ -5202,8 +5208,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
kfree(get_qf_name(sb, sbi, i));
|
kfree(get_qf_name(sb, sbi, i));
|
||||||
#endif
|
#endif
|
||||||
fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy);
|
fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy);
|
||||||
ext4_blkdev_remove(sbi);
|
/* ext4_blkdev_remove() calls kill_bdev(), release bh before it. */
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
|
ext4_blkdev_remove(sbi);
|
||||||
out_fail:
|
out_fail:
|
||||||
sb->s_fs_info = NULL;
|
sb->s_fs_info = NULL;
|
||||||
kfree(sbi->s_blockgroup_lock);
|
kfree(sbi->s_blockgroup_lock);
|
||||||
|
|
|
@ -315,7 +315,9 @@ EXT4_ATTR_FEATURE(verity);
|
||||||
#endif
|
#endif
|
||||||
EXT4_ATTR_FEATURE(metadata_csum_seed);
|
EXT4_ATTR_FEATURE(metadata_csum_seed);
|
||||||
EXT4_ATTR_FEATURE(fast_commit);
|
EXT4_ATTR_FEATURE(fast_commit);
|
||||||
|
#if defined(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION)
|
||||||
EXT4_ATTR_FEATURE(encrypted_casefold);
|
EXT4_ATTR_FEATURE(encrypted_casefold);
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct attribute *ext4_feat_attrs[] = {
|
static struct attribute *ext4_feat_attrs[] = {
|
||||||
ATTR_LIST(lazy_itable_init),
|
ATTR_LIST(lazy_itable_init),
|
||||||
|
@ -333,7 +335,9 @@ static struct attribute *ext4_feat_attrs[] = {
|
||||||
#endif
|
#endif
|
||||||
ATTR_LIST(metadata_csum_seed),
|
ATTR_LIST(metadata_csum_seed),
|
||||||
ATTR_LIST(fast_commit),
|
ATTR_LIST(fast_commit),
|
||||||
|
#if defined(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION)
|
||||||
ATTR_LIST(encrypted_casefold),
|
ATTR_LIST(encrypted_casefold),
|
||||||
|
#endif
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
ATTRIBUTE_GROUPS(ext4_feat);
|
ATTRIBUTE_GROUPS(ext4_feat);
|
||||||
|
|
Loading…
Reference in a new issue