Skip to content

Commit a7ba36b

Browse files
harshadjstytso
authored andcommitted
ext4: fix fast commit alignment issues
Fast commit recovery data on disk may not be aligned. So, when the recovery code reads it, this patch makes sure that fast commit info found on-disk is first memcpy-ed into an aligned variable before accessing it. As a consequence of it, we also remove some macros that could resulted in unaligned accesses. Cc: stable@kernel.org Fixes: 8016e29 ("ext4: fast commit recovery path") Signed-off-by: Harshad Shirwadkar <harshadshirwadkar@gmail.com> Link: https://lore.kernel.org/r/20210519215920.2037527-1-harshads@google.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent 082cd4e commit a7ba36b

File tree

2 files changed

+90
-99
lines changed

2 files changed

+90
-99
lines changed

fs/ext4/fast_commit.c

Lines changed: 90 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,28 +1288,29 @@ struct dentry_info_args {
12881288
};
12891289

12901290
static inline void tl_to_darg(struct dentry_info_args *darg,
1291-
struct ext4_fc_tl *tl)
1291+
struct ext4_fc_tl *tl, u8 *val)
12921292
{
1293-
struct ext4_fc_dentry_info *fcd;
1293+
struct ext4_fc_dentry_info fcd;
12941294

1295-
fcd = (struct ext4_fc_dentry_info *)ext4_fc_tag_val(tl);
1295+
memcpy(&fcd, val, sizeof(fcd));
12961296

1297-
darg->parent_ino = le32_to_cpu(fcd->fc_parent_ino);
1298-
darg->ino = le32_to_cpu(fcd->fc_ino);
1299-
darg->dname = fcd->fc_dname;
1300-
darg->dname_len = ext4_fc_tag_len(tl) -
1301-
sizeof(struct ext4_fc_dentry_info);
1297+
darg->parent_ino = le32_to_cpu(fcd.fc_parent_ino);
1298+
darg->ino = le32_to_cpu(fcd.fc_ino);
1299+
darg->dname = val + offsetof(struct ext4_fc_dentry_info, fc_dname);
1300+
darg->dname_len = le16_to_cpu(tl->fc_len) -
1301+
sizeof(struct ext4_fc_dentry_info);
13021302
}
13031303

13041304
/* Unlink replay function */
1305-
static int ext4_fc_replay_unlink(struct super_block *sb, struct ext4_fc_tl *tl)
1305+
static int ext4_fc_replay_unlink(struct super_block *sb, struct ext4_fc_tl *tl,
1306+
u8 *val)
13061307
{
13071308
struct inode *inode, *old_parent;
13081309
struct qstr entry;
13091310
struct dentry_info_args darg;
13101311
int ret = 0;
13111312

1312-
tl_to_darg(&darg, tl);
1313+
tl_to_darg(&darg, tl, val);
13131314

13141315
trace_ext4_fc_replay(sb, EXT4_FC_TAG_UNLINK, darg.ino,
13151316
darg.parent_ino, darg.dname_len);
@@ -1399,13 +1400,14 @@ static int ext4_fc_replay_link_internal(struct super_block *sb,
13991400
}
14001401

14011402
/* Link replay function */
1402-
static int ext4_fc_replay_link(struct super_block *sb, struct ext4_fc_tl *tl)
1403+
static int ext4_fc_replay_link(struct super_block *sb, struct ext4_fc_tl *tl,
1404+
u8 *val)
14031405
{
14041406
struct inode *inode;
14051407
struct dentry_info_args darg;
14061408
int ret = 0;
14071409

1408-
tl_to_darg(&darg, tl);
1410+
tl_to_darg(&darg, tl, val);
14091411
trace_ext4_fc_replay(sb, EXT4_FC_TAG_LINK, darg.ino,
14101412
darg.parent_ino, darg.dname_len);
14111413

@@ -1450,19 +1452,20 @@ static int ext4_fc_record_modified_inode(struct super_block *sb, int ino)
14501452
/*
14511453
* Inode replay function
14521454
*/
1453-
static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl)
1455+
static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl,
1456+
u8 *val)
14541457
{
1455-
struct ext4_fc_inode *fc_inode;
1458+
struct ext4_fc_inode fc_inode;
14561459
struct ext4_inode *raw_inode;
14571460
struct ext4_inode *raw_fc_inode;
14581461
struct inode *inode = NULL;
14591462
struct ext4_iloc iloc;
14601463
int inode_len, ino, ret, tag = le16_to_cpu(tl->fc_tag);
14611464
struct ext4_extent_header *eh;
14621465

1463-
fc_inode = (struct ext4_fc_inode *)ext4_fc_tag_val(tl);
1466+
memcpy(&fc_inode, val, sizeof(fc_inode));
14641467

1465-
ino = le32_to_cpu(fc_inode->fc_ino);
1468+
ino = le32_to_cpu(fc_inode.fc_ino);
14661469
trace_ext4_fc_replay(sb, tag, ino, 0, 0);
14671470

14681471
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)
14741477

14751478
ext4_fc_record_modified_inode(sb, ino);
14761479

1477-
raw_fc_inode = (struct ext4_inode *)fc_inode->fc_raw_inode;
1480+
raw_fc_inode = (struct ext4_inode *)
1481+
(val + offsetof(struct ext4_fc_inode, fc_raw_inode));
14781482
ret = ext4_get_fc_inode_loc(sb, ino, &iloc);
14791483
if (ret)
14801484
goto out;
14811485

1482-
inode_len = ext4_fc_tag_len(tl) - sizeof(struct ext4_fc_inode);
1486+
inode_len = le16_to_cpu(tl->fc_len) - sizeof(struct ext4_fc_inode);
14831487
raw_inode = ext4_raw_inode(&iloc);
14841488

14851489
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)
15471551
* inode for which we are trying to create a dentry here, should already have
15481552
* been replayed before we start here.
15491553
*/
1550-
static int ext4_fc_replay_create(struct super_block *sb, struct ext4_fc_tl *tl)
1554+
static int ext4_fc_replay_create(struct super_block *sb, struct ext4_fc_tl *tl,
1555+
u8 *val)
15511556
{
15521557
int ret = 0;
15531558
struct inode *inode = NULL;
15541559
struct inode *dir = NULL;
15551560
struct dentry_info_args darg;
15561561

1557-
tl_to_darg(&darg, tl);
1562+
tl_to_darg(&darg, tl, val);
15581563

15591564
trace_ext4_fc_replay(sb, EXT4_FC_TAG_CREAT, darg.ino,
15601565
darg.parent_ino, darg.dname_len);
@@ -1633,9 +1638,9 @@ static int ext4_fc_record_regions(struct super_block *sb, int ino,
16331638

16341639
/* Replay add range tag */
16351640
static int ext4_fc_replay_add_range(struct super_block *sb,
1636-
struct ext4_fc_tl *tl)
1641+
struct ext4_fc_tl *tl, u8 *val)
16371642
{
1638-
struct ext4_fc_add_range *fc_add_ex;
1643+
struct ext4_fc_add_range fc_add_ex;
16391644
struct ext4_extent newex, *ex;
16401645
struct inode *inode;
16411646
ext4_lblk_t start, cur;
@@ -1645,15 +1650,14 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
16451650
struct ext4_ext_path *path = NULL;
16461651
int ret;
16471652

1648-
fc_add_ex = (struct ext4_fc_add_range *)ext4_fc_tag_val(tl);
1649-
ex = (struct ext4_extent *)&fc_add_ex->fc_ex;
1653+
memcpy(&fc_add_ex, val, sizeof(fc_add_ex));
1654+
ex = (struct ext4_extent *)&fc_add_ex.fc_ex;
16501655

16511656
trace_ext4_fc_replay(sb, EXT4_FC_TAG_ADD_RANGE,
1652-
le32_to_cpu(fc_add_ex->fc_ino), le32_to_cpu(ex->ee_block),
1657+
le32_to_cpu(fc_add_ex.fc_ino), le32_to_cpu(ex->ee_block),
16531658
ext4_ext_get_actual_len(ex));
16541659

1655-
inode = ext4_iget(sb, le32_to_cpu(fc_add_ex->fc_ino),
1656-
EXT4_IGET_NORMAL);
1660+
inode = ext4_iget(sb, le32_to_cpu(fc_add_ex.fc_ino), EXT4_IGET_NORMAL);
16571661
if (IS_ERR(inode)) {
16581662
jbd_debug(1, "Inode not found.");
16591663
return 0;
@@ -1762,32 +1766,33 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
17621766

17631767
/* Replay DEL_RANGE tag */
17641768
static int
1765-
ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl)
1769+
ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl,
1770+
u8 *val)
17661771
{
17671772
struct inode *inode;
1768-
struct ext4_fc_del_range *lrange;
1773+
struct ext4_fc_del_range lrange;
17691774
struct ext4_map_blocks map;
17701775
ext4_lblk_t cur, remaining;
17711776
int ret;
17721777

1773-
lrange = (struct ext4_fc_del_range *)ext4_fc_tag_val(tl);
1774-
cur = le32_to_cpu(lrange->fc_lblk);
1775-
remaining = le32_to_cpu(lrange->fc_len);
1778+
memcpy(&lrange, val, sizeof(lrange));
1779+
cur = le32_to_cpu(lrange.fc_lblk);
1780+
remaining = le32_to_cpu(lrange.fc_len);
17761781

17771782
trace_ext4_fc_replay(sb, EXT4_FC_TAG_DEL_RANGE,
1778-
le32_to_cpu(lrange->fc_ino), cur, remaining);
1783+
le32_to_cpu(lrange.fc_ino), cur, remaining);
17791784

1780-
inode = ext4_iget(sb, le32_to_cpu(lrange->fc_ino), EXT4_IGET_NORMAL);
1785+
inode = ext4_iget(sb, le32_to_cpu(lrange.fc_ino), EXT4_IGET_NORMAL);
17811786
if (IS_ERR(inode)) {
1782-
jbd_debug(1, "Inode %d not found", le32_to_cpu(lrange->fc_ino));
1787+
jbd_debug(1, "Inode %d not found", le32_to_cpu(lrange.fc_ino));
17831788
return 0;
17841789
}
17851790

17861791
ret = ext4_fc_record_modified_inode(sb, inode->i_ino);
17871792

17881793
jbd_debug(1, "DEL_RANGE, inode %ld, lblk %d, len %d\n",
1789-
inode->i_ino, le32_to_cpu(lrange->fc_lblk),
1790-
le32_to_cpu(lrange->fc_len));
1794+
inode->i_ino, le32_to_cpu(lrange.fc_lblk),
1795+
le32_to_cpu(lrange.fc_len));
17911796
while (remaining > 0) {
17921797
map.m_lblk = cur;
17931798
map.m_len = remaining;
@@ -1808,8 +1813,8 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl)
18081813
}
18091814

18101815
ret = ext4_punch_hole(inode,
1811-
le32_to_cpu(lrange->fc_lblk) << sb->s_blocksize_bits,
1812-
le32_to_cpu(lrange->fc_len) << sb->s_blocksize_bits);
1816+
le32_to_cpu(lrange.fc_lblk) << sb->s_blocksize_bits,
1817+
le32_to_cpu(lrange.fc_len) << sb->s_blocksize_bits);
18131818
if (ret)
18141819
jbd_debug(1, "ext4_punch_hole returned %d", ret);
18151820
ext4_ext_replay_shrink_inode(inode,
@@ -1925,11 +1930,11 @@ static int ext4_fc_replay_scan(journal_t *journal,
19251930
struct ext4_sb_info *sbi = EXT4_SB(sb);
19261931
struct ext4_fc_replay_state *state;
19271932
int ret = JBD2_FC_REPLAY_CONTINUE;
1928-
struct ext4_fc_add_range *ext;
1929-
struct ext4_fc_tl *tl;
1930-
struct ext4_fc_tail *tail;
1931-
__u8 *start, *end;
1932-
struct ext4_fc_head *head;
1933+
struct ext4_fc_add_range ext;
1934+
struct ext4_fc_tl tl;
1935+
struct ext4_fc_tail tail;
1936+
__u8 *start, *end, *cur, *val;
1937+
struct ext4_fc_head head;
19331938
struct ext4_extent *ex;
19341939

19351940
state = &sbi->s_fc_replay_state;
@@ -1956,15 +1961,17 @@ static int ext4_fc_replay_scan(journal_t *journal,
19561961
}
19571962

19581963
state->fc_replay_expected_off++;
1959-
fc_for_each_tl(start, end, tl) {
1964+
for (cur = start; cur < end; cur = cur + sizeof(tl) + le16_to_cpu(tl.fc_len)) {
1965+
memcpy(&tl, cur, sizeof(tl));
1966+
val = cur + sizeof(tl);
19601967
jbd_debug(3, "Scan phase, tag:%s, blk %lld\n",
1961-
tag2str(le16_to_cpu(tl->fc_tag)), bh->b_blocknr);
1962-
switch (le16_to_cpu(tl->fc_tag)) {
1968+
tag2str(le16_to_cpu(tl.fc_tag)), bh->b_blocknr);
1969+
switch (le16_to_cpu(tl.fc_tag)) {
19631970
case EXT4_FC_TAG_ADD_RANGE:
1964-
ext = (struct ext4_fc_add_range *)ext4_fc_tag_val(tl);
1965-
ex = (struct ext4_extent *)&ext->fc_ex;
1971+
memcpy(&ext, val, sizeof(ext));
1972+
ex = (struct ext4_extent *)&ext.fc_ex;
19661973
ret = ext4_fc_record_regions(sb,
1967-
le32_to_cpu(ext->fc_ino),
1974+
le32_to_cpu(ext.fc_ino),
19681975
le32_to_cpu(ex->ee_block), ext4_ext_pblock(ex),
19691976
ext4_ext_get_actual_len(ex));
19701977
if (ret < 0)
@@ -1978,18 +1985,18 @@ static int ext4_fc_replay_scan(journal_t *journal,
19781985
case EXT4_FC_TAG_INODE:
19791986
case EXT4_FC_TAG_PAD:
19801987
state->fc_cur_tag++;
1981-
state->fc_crc = ext4_chksum(sbi, state->fc_crc, tl,
1982-
sizeof(*tl) + ext4_fc_tag_len(tl));
1988+
state->fc_crc = ext4_chksum(sbi, state->fc_crc, cur,
1989+
sizeof(tl) + le16_to_cpu(tl.fc_len));
19831990
break;
19841991
case EXT4_FC_TAG_TAIL:
19851992
state->fc_cur_tag++;
1986-
tail = (struct ext4_fc_tail *)ext4_fc_tag_val(tl);
1987-
state->fc_crc = ext4_chksum(sbi, state->fc_crc, tl,
1988-
sizeof(*tl) +
1993+
memcpy(&tail, val, sizeof(tail));
1994+
state->fc_crc = ext4_chksum(sbi, state->fc_crc, cur,
1995+
sizeof(tl) +
19891996
offsetof(struct ext4_fc_tail,
19901997
fc_crc));
1991-
if (le32_to_cpu(tail->fc_tid) == expected_tid &&
1992-
le32_to_cpu(tail->fc_crc) == state->fc_crc) {
1998+
if (le32_to_cpu(tail.fc_tid) == expected_tid &&
1999+
le32_to_cpu(tail.fc_crc) == state->fc_crc) {
19932000
state->fc_replay_num_tags = state->fc_cur_tag;
19942001
state->fc_regions_valid =
19952002
state->fc_regions_used;
@@ -2000,19 +2007,19 @@ static int ext4_fc_replay_scan(journal_t *journal,
20002007
state->fc_crc = 0;
20012008
break;
20022009
case EXT4_FC_TAG_HEAD:
2003-
head = (struct ext4_fc_head *)ext4_fc_tag_val(tl);
2004-
if (le32_to_cpu(head->fc_features) &
2010+
memcpy(&head, val, sizeof(head));
2011+
if (le32_to_cpu(head.fc_features) &
20052012
~EXT4_FC_SUPPORTED_FEATURES) {
20062013
ret = -EOPNOTSUPP;
20072014
break;
20082015
}
2009-
if (le32_to_cpu(head->fc_tid) != expected_tid) {
2016+
if (le32_to_cpu(head.fc_tid) != expected_tid) {
20102017
ret = JBD2_FC_REPLAY_STOP;
20112018
break;
20122019
}
20132020
state->fc_cur_tag++;
2014-
state->fc_crc = ext4_chksum(sbi, state->fc_crc, tl,
2015-
sizeof(*tl) + ext4_fc_tag_len(tl));
2021+
state->fc_crc = ext4_chksum(sbi, state->fc_crc, cur,
2022+
sizeof(tl) + le16_to_cpu(tl.fc_len));
20162023
break;
20172024
default:
20182025
ret = state->fc_replay_num_tags ?
@@ -2036,11 +2043,11 @@ static int ext4_fc_replay(journal_t *journal, struct buffer_head *bh,
20362043
{
20372044
struct super_block *sb = journal->j_private;
20382045
struct ext4_sb_info *sbi = EXT4_SB(sb);
2039-
struct ext4_fc_tl *tl;
2040-
__u8 *start, *end;
2046+
struct ext4_fc_tl tl;
2047+
__u8 *start, *end, *cur, *val;
20412048
int ret = JBD2_FC_REPLAY_CONTINUE;
20422049
struct ext4_fc_replay_state *state = &sbi->s_fc_replay_state;
2043-
struct ext4_fc_tail *tail;
2050+
struct ext4_fc_tail tail;
20442051

20452052
if (pass == PASS_SCAN) {
20462053
state->fc_current_pass = PASS_SCAN;
@@ -2067,49 +2074,52 @@ static int ext4_fc_replay(journal_t *journal, struct buffer_head *bh,
20672074
start = (u8 *)bh->b_data;
20682075
end = (__u8 *)bh->b_data + journal->j_blocksize - 1;
20692076

2070-
fc_for_each_tl(start, end, tl) {
2077+
for (cur = start; cur < end; cur = cur + sizeof(tl) + le16_to_cpu(tl.fc_len)) {
2078+
memcpy(&tl, cur, sizeof(tl));
2079+
val = cur + sizeof(tl);
2080+
20712081
if (state->fc_replay_num_tags == 0) {
20722082
ret = JBD2_FC_REPLAY_STOP;
20732083
ext4_fc_set_bitmaps_and_counters(sb);
20742084
break;
20752085
}
20762086
jbd_debug(3, "Replay phase, tag:%s\n",
2077-
tag2str(le16_to_cpu(tl->fc_tag)));
2087+
tag2str(le16_to_cpu(tl.fc_tag)));
20782088
state->fc_replay_num_tags--;
2079-
switch (le16_to_cpu(tl->fc_tag)) {
2089+
switch (le16_to_cpu(tl.fc_tag)) {
20802090
case EXT4_FC_TAG_LINK:
2081-
ret = ext4_fc_replay_link(sb, tl);
2091+
ret = ext4_fc_replay_link(sb, &tl, val);
20822092
break;
20832093
case EXT4_FC_TAG_UNLINK:
2084-
ret = ext4_fc_replay_unlink(sb, tl);
2094+
ret = ext4_fc_replay_unlink(sb, &tl, val);
20852095
break;
20862096
case EXT4_FC_TAG_ADD_RANGE:
2087-
ret = ext4_fc_replay_add_range(sb, tl);
2097+
ret = ext4_fc_replay_add_range(sb, &tl, val);
20882098
break;
20892099
case EXT4_FC_TAG_CREAT:
2090-
ret = ext4_fc_replay_create(sb, tl);
2100+
ret = ext4_fc_replay_create(sb, &tl, val);
20912101
break;
20922102
case EXT4_FC_TAG_DEL_RANGE:
2093-
ret = ext4_fc_replay_del_range(sb, tl);
2103+
ret = ext4_fc_replay_del_range(sb, &tl, val);
20942104
break;
20952105
case EXT4_FC_TAG_INODE:
2096-
ret = ext4_fc_replay_inode(sb, tl);
2106+
ret = ext4_fc_replay_inode(sb, &tl, val);
20972107
break;
20982108
case EXT4_FC_TAG_PAD:
20992109
trace_ext4_fc_replay(sb, EXT4_FC_TAG_PAD, 0,
2100-
ext4_fc_tag_len(tl), 0);
2110+
le16_to_cpu(tl.fc_len), 0);
21012111
break;
21022112
case EXT4_FC_TAG_TAIL:
21032113
trace_ext4_fc_replay(sb, EXT4_FC_TAG_TAIL, 0,
2104-
ext4_fc_tag_len(tl), 0);
2105-
tail = (struct ext4_fc_tail *)ext4_fc_tag_val(tl);
2106-
WARN_ON(le32_to_cpu(tail->fc_tid) != expected_tid);
2114+
le16_to_cpu(tl.fc_len), 0);
2115+
memcpy(&tail, val, sizeof(tail));
2116+
WARN_ON(le32_to_cpu(tail.fc_tid) != expected_tid);
21072117
break;
21082118
case EXT4_FC_TAG_HEAD:
21092119
break;
21102120
default:
2111-
trace_ext4_fc_replay(sb, le16_to_cpu(tl->fc_tag), 0,
2112-
ext4_fc_tag_len(tl), 0);
2121+
trace_ext4_fc_replay(sb, le16_to_cpu(tl.fc_tag), 0,
2122+
le16_to_cpu(tl.fc_len), 0);
21132123
ret = -ECANCELED;
21142124
break;
21152125
}

0 commit comments

Comments
 (0)