Commit 20e41d9b authored by Linus Torvalds's avatar Linus Torvalds

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.
parents decad3e1 e71f99f2
...@@ -3206,7 +3206,10 @@ static int ext4_split_extent_at(handle_t *handle, ...@@ -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, ...@@ -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, ...@@ -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 { ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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); ...@@ -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[] = { ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment