Skip to content

Commit 0bc9bc1

Browse files
committed
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: "A number of bug fixes for ext4: - Fix for the new fast_commit feature - Fix some error handling codepaths in whiteout handling and mountpoint sampling - Fix how we write ext4_error information so it goes through the journal when journalling is active, to avoid races that can lead to lost error information, superblock checksum failures, or DIF/DIX features" * tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: ext4: remove expensive flush on fast commit ext4: fix bug for rename with RENAME_WHITEOUT ext4: fix wrong list_splice in ext4_fc_cleanup ext4: use IS_ERR instead of IS_ERR_OR_NULL and set inode null when IS_ERR ext4: don't leak old mountpoint samples ext4: drop ext4_handle_dirty_super() ext4: fix superblock checksum failure when setting password salt ext4: use sbi instead of EXT4_SB(sb) in ext4_update_super() ext4: save error info to sb through journal if available ext4: protect superblock modifications with a buffer lock ext4: drop sync argument of ext4_commit_super() ext4: combine ext4_handle_error() and save_error_info()
2 parents 7cd3c41 + e9f5335 commit 0bc9bc1

10 files changed

Lines changed: 186 additions & 129 deletions

File tree

fs/ext4/ext4_jbd2.c

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -372,20 +372,3 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
372372
}
373373
return err;
374374
}
375-
376-
int __ext4_handle_dirty_super(const char *where, unsigned int line,
377-
handle_t *handle, struct super_block *sb)
378-
{
379-
struct buffer_head *bh = EXT4_SB(sb)->s_sbh;
380-
int err = 0;
381-
382-
ext4_superblock_csum_set(sb);
383-
if (ext4_handle_valid(handle)) {
384-
err = jbd2_journal_dirty_metadata(handle, bh);
385-
if (err)
386-
ext4_journal_abort_handle(where, line, __func__,
387-
bh, handle, err);
388-
} else
389-
mark_buffer_dirty(bh);
390-
return err;
391-
}

fs/ext4/ext4_jbd2.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,6 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
244244
handle_t *handle, struct inode *inode,
245245
struct buffer_head *bh);
246246

247-
int __ext4_handle_dirty_super(const char *where, unsigned int line,
248-
handle_t *handle, struct super_block *sb);
249-
250247
#define ext4_journal_get_write_access(handle, bh) \
251248
__ext4_journal_get_write_access(__func__, __LINE__, (handle), (bh))
252249
#define ext4_forget(handle, is_metadata, inode, bh, block_nr) \
@@ -257,8 +254,6 @@ int __ext4_handle_dirty_super(const char *where, unsigned int line,
257254
#define ext4_handle_dirty_metadata(handle, inode, bh) \
258255
__ext4_handle_dirty_metadata(__func__, __LINE__, (handle), (inode), \
259256
(bh))
260-
#define ext4_handle_dirty_super(handle, sb) \
261-
__ext4_handle_dirty_super(__func__, __LINE__, (handle), (sb))
262257

263258
handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line,
264259
int type, int blocks, int rsv_blocks,

fs/ext4/fast_commit.c

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -604,13 +604,13 @@ void ext4_fc_track_range(handle_t *handle, struct inode *inode, ext4_lblk_t star
604604
trace_ext4_fc_track_range(inode, start, end, ret);
605605
}
606606

607-
static void ext4_fc_submit_bh(struct super_block *sb)
607+
static void ext4_fc_submit_bh(struct super_block *sb, bool is_tail)
608608
{
609609
int write_flags = REQ_SYNC;
610610
struct buffer_head *bh = EXT4_SB(sb)->s_fc_bh;
611611

612-
/* TODO: REQ_FUA | REQ_PREFLUSH is unnecessarily expensive. */
613-
if (test_opt(sb, BARRIER))
612+
/* Add REQ_FUA | REQ_PREFLUSH only its tail */
613+
if (test_opt(sb, BARRIER) && is_tail)
614614
write_flags |= REQ_FUA | REQ_PREFLUSH;
615615
lock_buffer(bh);
616616
set_buffer_dirty(bh);
@@ -684,7 +684,7 @@ static u8 *ext4_fc_reserve_space(struct super_block *sb, int len, u32 *crc)
684684
*crc = ext4_chksum(sbi, *crc, tl, sizeof(*tl));
685685
if (pad_len > 0)
686686
ext4_fc_memzero(sb, tl + 1, pad_len, crc);
687-
ext4_fc_submit_bh(sb);
687+
ext4_fc_submit_bh(sb, false);
688688

689689
ret = jbd2_fc_get_buf(EXT4_SB(sb)->s_journal, &bh);
690690
if (ret)
@@ -741,7 +741,7 @@ static int ext4_fc_write_tail(struct super_block *sb, u32 crc)
741741
tail.fc_crc = cpu_to_le32(crc);
742742
ext4_fc_memcpy(sb, dst, &tail.fc_crc, sizeof(tail.fc_crc), NULL);
743743

744-
ext4_fc_submit_bh(sb);
744+
ext4_fc_submit_bh(sb, true);
745745

746746
return 0;
747747
}
@@ -1268,7 +1268,7 @@ static void ext4_fc_cleanup(journal_t *journal, int full)
12681268
list_splice_init(&sbi->s_fc_dentry_q[FC_Q_STAGING],
12691269
&sbi->s_fc_dentry_q[FC_Q_MAIN]);
12701270
list_splice_init(&sbi->s_fc_q[FC_Q_STAGING],
1271-
&sbi->s_fc_q[FC_Q_STAGING]);
1271+
&sbi->s_fc_q[FC_Q_MAIN]);
12721272

12731273
ext4_clear_mount_flag(sb, EXT4_MF_FC_COMMITTING);
12741274
ext4_clear_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
@@ -1318,14 +1318,14 @@ static int ext4_fc_replay_unlink(struct super_block *sb, struct ext4_fc_tl *tl)
13181318
entry.len = darg.dname_len;
13191319
inode = ext4_iget(sb, darg.ino, EXT4_IGET_NORMAL);
13201320

1321-
if (IS_ERR_OR_NULL(inode)) {
1321+
if (IS_ERR(inode)) {
13221322
jbd_debug(1, "Inode %d not found", darg.ino);
13231323
return 0;
13241324
}
13251325

13261326
old_parent = ext4_iget(sb, darg.parent_ino,
13271327
EXT4_IGET_NORMAL);
1328-
if (IS_ERR_OR_NULL(old_parent)) {
1328+
if (IS_ERR(old_parent)) {
13291329
jbd_debug(1, "Dir with inode %d not found", darg.parent_ino);
13301330
iput(inode);
13311331
return 0;
@@ -1410,7 +1410,7 @@ static int ext4_fc_replay_link(struct super_block *sb, struct ext4_fc_tl *tl)
14101410
darg.parent_ino, darg.dname_len);
14111411

14121412
inode = ext4_iget(sb, darg.ino, EXT4_IGET_NORMAL);
1413-
if (IS_ERR_OR_NULL(inode)) {
1413+
if (IS_ERR(inode)) {
14141414
jbd_debug(1, "Inode not found.");
14151415
return 0;
14161416
}
@@ -1466,10 +1466,11 @@ static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl)
14661466
trace_ext4_fc_replay(sb, tag, ino, 0, 0);
14671467

14681468
inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL);
1469-
if (!IS_ERR_OR_NULL(inode)) {
1469+
if (!IS_ERR(inode)) {
14701470
ext4_ext_clear_bb(inode);
14711471
iput(inode);
14721472
}
1473+
inode = NULL;
14731474

14741475
ext4_fc_record_modified_inode(sb, ino);
14751476

@@ -1512,7 +1513,7 @@ static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl)
15121513

15131514
/* Given that we just wrote the inode on disk, this SHOULD succeed. */
15141515
inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL);
1515-
if (IS_ERR_OR_NULL(inode)) {
1516+
if (IS_ERR(inode)) {
15161517
jbd_debug(1, "Inode not found.");
15171518
return -EFSCORRUPTED;
15181519
}
@@ -1564,7 +1565,7 @@ static int ext4_fc_replay_create(struct super_block *sb, struct ext4_fc_tl *tl)
15641565
goto out;
15651566

15661567
inode = ext4_iget(sb, darg.ino, EXT4_IGET_NORMAL);
1567-
if (IS_ERR_OR_NULL(inode)) {
1568+
if (IS_ERR(inode)) {
15681569
jbd_debug(1, "inode %d not found.", darg.ino);
15691570
inode = NULL;
15701571
ret = -EINVAL;
@@ -1577,7 +1578,7 @@ static int ext4_fc_replay_create(struct super_block *sb, struct ext4_fc_tl *tl)
15771578
* dot and dot dot dirents are setup properly.
15781579
*/
15791580
dir = ext4_iget(sb, darg.parent_ino, EXT4_IGET_NORMAL);
1580-
if (IS_ERR_OR_NULL(dir)) {
1581+
if (IS_ERR(dir)) {
15811582
jbd_debug(1, "Dir %d not found.", darg.ino);
15821583
goto out;
15831584
}
@@ -1653,7 +1654,7 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
16531654

16541655
inode = ext4_iget(sb, le32_to_cpu(fc_add_ex->fc_ino),
16551656
EXT4_IGET_NORMAL);
1656-
if (IS_ERR_OR_NULL(inode)) {
1657+
if (IS_ERR(inode)) {
16571658
jbd_debug(1, "Inode not found.");
16581659
return 0;
16591660
}
@@ -1777,7 +1778,7 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl)
17771778
le32_to_cpu(lrange->fc_ino), cur, remaining);
17781779

17791780
inode = ext4_iget(sb, le32_to_cpu(lrange->fc_ino), EXT4_IGET_NORMAL);
1780-
if (IS_ERR_OR_NULL(inode)) {
1781+
if (IS_ERR(inode)) {
17811782
jbd_debug(1, "Inode %d not found", le32_to_cpu(lrange->fc_ino));
17821783
return 0;
17831784
}
@@ -1832,7 +1833,7 @@ static void ext4_fc_set_bitmaps_and_counters(struct super_block *sb)
18321833
for (i = 0; i < state->fc_modified_inodes_used; i++) {
18331834
inode = ext4_iget(sb, state->fc_modified_inodes[i],
18341835
EXT4_IGET_NORMAL);
1835-
if (IS_ERR_OR_NULL(inode)) {
1836+
if (IS_ERR(inode)) {
18361837
jbd_debug(1, "Inode %d not found.",
18371838
state->fc_modified_inodes[i]);
18381839
continue;
@@ -1849,7 +1850,7 @@ static void ext4_fc_set_bitmaps_and_counters(struct super_block *sb)
18491850

18501851
if (ret > 0) {
18511852
path = ext4_find_extent(inode, map.m_lblk, NULL, 0);
1852-
if (!IS_ERR_OR_NULL(path)) {
1853+
if (!IS_ERR(path)) {
18531854
for (j = 0; j < path->p_depth; j++)
18541855
ext4_mb_mark_bb(inode->i_sb,
18551856
path[j].p_block, 1, 1);

fs/ext4/file.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -809,9 +809,12 @@ static int ext4_sample_last_mounted(struct super_block *sb,
809809
err = ext4_journal_get_write_access(handle, sbi->s_sbh);
810810
if (err)
811811
goto out_journal;
812-
strlcpy(sbi->s_es->s_last_mounted, cp,
812+
lock_buffer(sbi->s_sbh);
813+
strncpy(sbi->s_es->s_last_mounted, cp,
813814
sizeof(sbi->s_es->s_last_mounted));
814-
ext4_handle_dirty_super(handle, sb);
815+
ext4_superblock_csum_set(sb);
816+
unlock_buffer(sbi->s_sbh);
817+
ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh);
815818
out_journal:
816819
ext4_journal_stop(handle);
817820
out:

fs/ext4/inode.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5150,9 +5150,13 @@ static int ext4_do_update_inode(handle_t *handle,
51505150
err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
51515151
if (err)
51525152
goto out_brelse;
5153+
lock_buffer(EXT4_SB(sb)->s_sbh);
51535154
ext4_set_feature_large_file(sb);
5155+
ext4_superblock_csum_set(sb);
5156+
unlock_buffer(EXT4_SB(sb)->s_sbh);
51545157
ext4_handle_sync(handle);
5155-
err = ext4_handle_dirty_super(handle, sb);
5158+
err = ext4_handle_dirty_metadata(handle, NULL,
5159+
EXT4_SB(sb)->s_sbh);
51565160
}
51575161
ext4_update_inode_fsync_trans(handle, inode, need_datasync);
51585162
out_brelse:

fs/ext4/ioctl.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,7 +1157,10 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
11571157
err = ext4_journal_get_write_access(handle, sbi->s_sbh);
11581158
if (err)
11591159
goto pwsalt_err_journal;
1160+
lock_buffer(sbi->s_sbh);
11601161
generate_random_uuid(sbi->s_es->s_encrypt_pw_salt);
1162+
ext4_superblock_csum_set(sb);
1163+
unlock_buffer(sbi->s_sbh);
11611164
err = ext4_handle_dirty_metadata(handle, NULL,
11621165
sbi->s_sbh);
11631166
pwsalt_err_journal:

fs/ext4/namei.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2976,14 +2976,17 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
29762976
(le32_to_cpu(sbi->s_es->s_inodes_count))) {
29772977
/* Insert this inode at the head of the on-disk orphan list */
29782978
NEXT_ORPHAN(inode) = le32_to_cpu(sbi->s_es->s_last_orphan);
2979+
lock_buffer(sbi->s_sbh);
29792980
sbi->s_es->s_last_orphan = cpu_to_le32(inode->i_ino);
2981+
ext4_superblock_csum_set(sb);
2982+
unlock_buffer(sbi->s_sbh);
29802983
dirty = true;
29812984
}
29822985
list_add(&EXT4_I(inode)->i_orphan, &sbi->s_orphan);
29832986
mutex_unlock(&sbi->s_orphan_lock);
29842987

29852988
if (dirty) {
2986-
err = ext4_handle_dirty_super(handle, sb);
2989+
err = ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh);
29872990
rc = ext4_mark_iloc_dirty(handle, inode, &iloc);
29882991
if (!err)
29892992
err = rc;
@@ -3059,9 +3062,12 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
30593062
mutex_unlock(&sbi->s_orphan_lock);
30603063
goto out_brelse;
30613064
}
3065+
lock_buffer(sbi->s_sbh);
30623066
sbi->s_es->s_last_orphan = cpu_to_le32(ino_next);
3067+
ext4_superblock_csum_set(inode->i_sb);
3068+
unlock_buffer(sbi->s_sbh);
30633069
mutex_unlock(&sbi->s_orphan_lock);
3064-
err = ext4_handle_dirty_super(handle, inode->i_sb);
3070+
err = ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh);
30653071
} else {
30663072
struct ext4_iloc iloc2;
30673073
struct inode *i_prev =
@@ -3593,9 +3599,6 @@ static int ext4_setent(handle_t *handle, struct ext4_renament *ent,
35933599
return retval2;
35943600
}
35953601
}
3596-
brelse(ent->bh);
3597-
ent->bh = NULL;
3598-
35993602
return retval;
36003603
}
36013604

@@ -3794,6 +3797,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
37943797
}
37953798
}
37963799

3800+
old_file_type = old.de->file_type;
37973801
if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir))
37983802
ext4_handle_sync(handle);
37993803

@@ -3821,7 +3825,6 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
38213825
force_reread = (new.dir->i_ino == old.dir->i_ino &&
38223826
ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA));
38233827

3824-
old_file_type = old.de->file_type;
38253828
if (whiteout) {
38263829
/*
38273830
* Do this before adding a new entry, so the old entry is sure
@@ -3919,15 +3922,19 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
39193922
retval = 0;
39203923

39213924
end_rename:
3922-
brelse(old.dir_bh);
3923-
brelse(old.bh);
3924-
brelse(new.bh);
39253925
if (whiteout) {
3926-
if (retval)
3926+
if (retval) {
3927+
ext4_setent(handle, &old,
3928+
old.inode->i_ino, old_file_type);
39273929
drop_nlink(whiteout);
3930+
}
39283931
unlock_new_inode(whiteout);
39293932
iput(whiteout);
3933+
39303934
}
3935+
brelse(old.dir_bh);
3936+
brelse(old.bh);
3937+
brelse(new.bh);
39313938
if (handle)
39323939
ext4_journal_stop(handle);
39333940
return retval;

fs/ext4/resize.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -899,8 +899,11 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
899899
EXT4_SB(sb)->s_gdb_count++;
900900
ext4_kvfree_array_rcu(o_group_desc);
901901

902+
lock_buffer(EXT4_SB(sb)->s_sbh);
902903
le16_add_cpu(&es->s_reserved_gdt_blocks, -1);
903-
err = ext4_handle_dirty_super(handle, sb);
904+
ext4_superblock_csum_set(sb);
905+
unlock_buffer(EXT4_SB(sb)->s_sbh);
906+
err = ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
904907
if (err)
905908
ext4_std_error(sb, err);
906909
return err;
@@ -1384,6 +1387,7 @@ static void ext4_update_super(struct super_block *sb,
13841387
reserved_blocks *= blocks_count;
13851388
do_div(reserved_blocks, 100);
13861389

1390+
lock_buffer(sbi->s_sbh);
13871391
ext4_blocks_count_set(es, ext4_blocks_count(es) + blocks_count);
13881392
ext4_free_blocks_count_set(es, ext4_free_blocks_count(es) + free_blocks);
13891393
le32_add_cpu(&es->s_inodes_count, EXT4_INODES_PER_GROUP(sb) *
@@ -1421,6 +1425,8 @@ static void ext4_update_super(struct super_block *sb,
14211425
* active. */
14221426
ext4_r_blocks_count_set(es, ext4_r_blocks_count(es) +
14231427
reserved_blocks);
1428+
ext4_superblock_csum_set(sb);
1429+
unlock_buffer(sbi->s_sbh);
14241430

14251431
/* Update the free space counts */
14261432
percpu_counter_add(&sbi->s_freeclusters_counter,
@@ -1515,7 +1521,7 @@ static int ext4_flex_group_add(struct super_block *sb,
15151521

15161522
ext4_update_super(sb, flex_gd);
15171523

1518-
err = ext4_handle_dirty_super(handle, sb);
1524+
err = ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh);
15191525

15201526
exit_journal:
15211527
err2 = ext4_journal_stop(handle);
@@ -1717,15 +1723,18 @@ static int ext4_group_extend_no_check(struct super_block *sb,
17171723
goto errout;
17181724
}
17191725

1726+
lock_buffer(EXT4_SB(sb)->s_sbh);
17201727
ext4_blocks_count_set(es, o_blocks_count + add);
17211728
ext4_free_blocks_count_set(es, ext4_free_blocks_count(es) + add);
1729+
ext4_superblock_csum_set(sb);
1730+
unlock_buffer(EXT4_SB(sb)->s_sbh);
17221731
ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count,
17231732
o_blocks_count + add);
17241733
/* We add the blocks to the bitmap and set the group need init bit */
17251734
err = ext4_group_add_blocks(handle, sb, o_blocks_count, add);
17261735
if (err)
17271736
goto errout;
1728-
ext4_handle_dirty_super(handle, sb);
1737+
ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
17291738
ext4_debug("freed blocks %llu through %llu\n", o_blocks_count,
17301739
o_blocks_count + add);
17311740
errout:
@@ -1874,12 +1883,15 @@ static int ext4_convert_meta_bg(struct super_block *sb, struct inode *inode)
18741883
if (err)
18751884
goto errout;
18761885

1886+
lock_buffer(sbi->s_sbh);
18771887
ext4_clear_feature_resize_inode(sb);
18781888
ext4_set_feature_meta_bg(sb);
18791889
sbi->s_es->s_first_meta_bg =
18801890
cpu_to_le32(num_desc_blocks(sb, sbi->s_groups_count));
1891+
ext4_superblock_csum_set(sb);
1892+
unlock_buffer(sbi->s_sbh);
18811893

1882-
err = ext4_handle_dirty_super(handle, sb);
1894+
err = ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh);
18831895
if (err) {
18841896
ext4_std_error(sb, err);
18851897
goto errout;

0 commit comments

Comments
 (0)