Skip to content

Commit feaf222

Browse files
committed
Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 fixes from Ted Ts'o: "Ext4 bug fixes. We also reserved code points for encryption and read-only images (for which the implementation is mostly just the reserved code point for a read-only feature :-)" * tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: ext4: fix indirect punch hole corruption ext4: ignore journal checksum on remount; don't fail ext4: remove duplicate remount check for JOURNAL_CHECKSUM change ext4: fix mmap data corruption in nodelalloc mode when blocksize < pagesize ext4: support read-only images ext4: change to use setup_timer() instead of init_timer() ext4: reserve codepoints used by the ext4 encryption feature jbd2: complain about descriptor block checksum errors
2 parents be5e661 + 6f30b7e commit feaf222

File tree

5 files changed

+108
-56
lines changed

5 files changed

+108
-56
lines changed

fs/ext4/ext4.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,8 @@ struct flex_groups {
364364
#define EXT4_DIRTY_FL 0x00000100
365365
#define EXT4_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
366366
#define EXT4_NOCOMPR_FL 0x00000400 /* Don't compress */
367-
#define EXT4_ECOMPR_FL 0x00000800 /* Compression error */
367+
/* nb: was previously EXT2_ECOMPR_FL */
368+
#define EXT4_ENCRYPT_FL 0x00000800 /* encrypted file */
368369
/* End compression flags --- maybe not all used */
369370
#define EXT4_INDEX_FL 0x00001000 /* hash-indexed directory */
370371
#define EXT4_IMAGIC_FL 0x00002000 /* AFS directory */
@@ -421,7 +422,7 @@ enum {
421422
EXT4_INODE_DIRTY = 8,
422423
EXT4_INODE_COMPRBLK = 9, /* One or more compressed clusters */
423424
EXT4_INODE_NOCOMPR = 10, /* Don't compress */
424-
EXT4_INODE_ECOMPR = 11, /* Compression error */
425+
EXT4_INODE_ENCRYPT = 11, /* Compression error */
425426
/* End compression flags --- maybe not all used */
426427
EXT4_INODE_INDEX = 12, /* hash-indexed directory */
427428
EXT4_INODE_IMAGIC = 13, /* AFS directory */
@@ -466,7 +467,7 @@ static inline void ext4_check_flag_values(void)
466467
CHECK_FLAG_VALUE(DIRTY);
467468
CHECK_FLAG_VALUE(COMPRBLK);
468469
CHECK_FLAG_VALUE(NOCOMPR);
469-
CHECK_FLAG_VALUE(ECOMPR);
470+
CHECK_FLAG_VALUE(ENCRYPT);
470471
CHECK_FLAG_VALUE(INDEX);
471472
CHECK_FLAG_VALUE(IMAGIC);
472473
CHECK_FLAG_VALUE(JOURNAL_DATA);
@@ -1048,6 +1049,12 @@ extern void ext4_set_bits(void *bm, int cur, int len);
10481049
/* Metadata checksum algorithm codes */
10491050
#define EXT4_CRC32C_CHKSUM 1
10501051

1052+
/* Encryption algorithms */
1053+
#define EXT4_ENCRYPTION_MODE_INVALID 0
1054+
#define EXT4_ENCRYPTION_MODE_AES_256_XTS 1
1055+
#define EXT4_ENCRYPTION_MODE_AES_256_GCM 2
1056+
#define EXT4_ENCRYPTION_MODE_AES_256_CBC 3
1057+
10511058
/*
10521059
* Structure of the super block
10531060
*/
@@ -1161,7 +1168,8 @@ struct ext4_super_block {
11611168
__le32 s_grp_quota_inum; /* inode for tracking group quota */
11621169
__le32 s_overhead_clusters; /* overhead blocks/clusters in fs */
11631170
__le32 s_backup_bgs[2]; /* groups with sparse_super2 SBs */
1164-
__le32 s_reserved[106]; /* Padding to the end of the block */
1171+
__u8 s_encrypt_algos[4]; /* Encryption algorithms in use */
1172+
__le32 s_reserved[105]; /* Padding to the end of the block */
11651173
__le32 s_checksum; /* crc32c(superblock) */
11661174
};
11671175

@@ -1527,6 +1535,7 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
15271535
* GDT_CSUM bits are mutually exclusive.
15281536
*/
15291537
#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400
1538+
#define EXT4_FEATURE_RO_COMPAT_READONLY 0x1000
15301539

15311540
#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001
15321541
#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002
@@ -1542,6 +1551,7 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
15421551
#define EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM 0x2000 /* use crc32c for bg */
15431552
#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */
15441553
#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */
1554+
#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000
15451555

15461556
#define EXT2_FEATURE_COMPAT_SUPP EXT4_FEATURE_COMPAT_EXT_ATTR
15471557
#define EXT2_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \

fs/ext4/indirect.c

Lines changed: 71 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,10 +1401,7 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
14011401
* to free. Everything was covered by the start
14021402
* of the range.
14031403
*/
1404-
return 0;
1405-
} else {
1406-
/* Shared branch grows from an indirect block */
1407-
partial2--;
1404+
goto do_indirects;
14081405
}
14091406
} else {
14101407
/*
@@ -1435,56 +1432,96 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
14351432
/* Punch happened within the same level (n == n2) */
14361433
partial = ext4_find_shared(inode, n, offsets, chain, &nr);
14371434
partial2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2);
1438-
/*
1439-
* ext4_find_shared returns Indirect structure which
1440-
* points to the last element which should not be
1441-
* removed by truncate. But this is end of the range
1442-
* in punch_hole so we need to point to the next element
1443-
*/
1444-
partial2->p++;
1445-
while ((partial > chain) || (partial2 > chain2)) {
1446-
/* We're at the same block, so we're almost finished */
1447-
if ((partial->bh && partial2->bh) &&
1448-
(partial->bh->b_blocknr == partial2->bh->b_blocknr)) {
1449-
if ((partial > chain) && (partial2 > chain2)) {
1435+
1436+
/* Free top, but only if partial2 isn't its subtree. */
1437+
if (nr) {
1438+
int level = min(partial - chain, partial2 - chain2);
1439+
int i;
1440+
int subtree = 1;
1441+
1442+
for (i = 0; i <= level; i++) {
1443+
if (offsets[i] != offsets2[i]) {
1444+
subtree = 0;
1445+
break;
1446+
}
1447+
}
1448+
1449+
if (!subtree) {
1450+
if (partial == chain) {
1451+
/* Shared branch grows from the inode */
1452+
ext4_free_branches(handle, inode, NULL,
1453+
&nr, &nr+1,
1454+
(chain+n-1) - partial);
1455+
*partial->p = 0;
1456+
} else {
1457+
/* Shared branch grows from an indirect block */
1458+
BUFFER_TRACE(partial->bh, "get_write_access");
14501459
ext4_free_branches(handle, inode, partial->bh,
1451-
partial->p + 1,
1452-
partial2->p,
1460+
partial->p,
1461+
partial->p+1,
14531462
(chain+n-1) - partial);
1454-
BUFFER_TRACE(partial->bh, "call brelse");
1455-
brelse(partial->bh);
1456-
BUFFER_TRACE(partial2->bh, "call brelse");
1457-
brelse(partial2->bh);
14581463
}
1459-
return 0;
14601464
}
1465+
}
1466+
1467+
if (!nr2) {
14611468
/*
1462-
* Clear the ends of indirect blocks on the shared branch
1463-
* at the start of the range
1469+
* ext4_find_shared returns Indirect structure which
1470+
* points to the last element which should not be
1471+
* removed by truncate. But this is end of the range
1472+
* in punch_hole so we need to point to the next element
14641473
*/
1465-
if (partial > chain) {
1474+
partial2->p++;
1475+
}
1476+
1477+
while (partial > chain || partial2 > chain2) {
1478+
int depth = (chain+n-1) - partial;
1479+
int depth2 = (chain2+n2-1) - partial2;
1480+
1481+
if (partial > chain && partial2 > chain2 &&
1482+
partial->bh->b_blocknr == partial2->bh->b_blocknr) {
1483+
/*
1484+
* We've converged on the same block. Clear the range,
1485+
* then we're done.
1486+
*/
14661487
ext4_free_branches(handle, inode, partial->bh,
1467-
partial->p + 1,
1468-
(__le32 *)partial->bh->b_data+addr_per_block,
1469-
(chain+n-1) - partial);
1488+
partial->p + 1,
1489+
partial2->p,
1490+
(chain+n-1) - partial);
14701491
BUFFER_TRACE(partial->bh, "call brelse");
14711492
brelse(partial->bh);
1472-
partial--;
1493+
BUFFER_TRACE(partial2->bh, "call brelse");
1494+
brelse(partial2->bh);
1495+
return 0;
14731496
}
1497+
14741498
/*
1475-
* Clear the ends of indirect blocks on the shared branch
1476-
* at the end of the range
1499+
* The start and end partial branches may not be at the same
1500+
* level even though the punch happened within one level. So, we
1501+
* give them a chance to arrive at the same level, then walk
1502+
* them in step with each other until we converge on the same
1503+
* block.
14771504
*/
1478-
if (partial2 > chain2) {
1505+
if (partial > chain && depth <= depth2) {
1506+
ext4_free_branches(handle, inode, partial->bh,
1507+
partial->p + 1,
1508+
(__le32 *)partial->bh->b_data+addr_per_block,
1509+
(chain+n-1) - partial);
1510+
BUFFER_TRACE(partial->bh, "call brelse");
1511+
brelse(partial->bh);
1512+
partial--;
1513+
}
1514+
if (partial2 > chain2 && depth2 <= depth) {
14791515
ext4_free_branches(handle, inode, partial2->bh,
14801516
(__le32 *)partial2->bh->b_data,
14811517
partial2->p,
1482-
(chain2+n-1) - partial2);
1518+
(chain2+n2-1) - partial2);
14831519
BUFFER_TRACE(partial2->bh, "call brelse");
14841520
brelse(partial2->bh);
14851521
partial2--;
14861522
}
14871523
}
1524+
return 0;
14881525

14891526
do_indirects:
14901527
/* Kill the remaining (whole) subtrees */

fs/ext4/inode.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,7 @@ static int ext4_write_end(struct file *file,
10241024
{
10251025
handle_t *handle = ext4_journal_current_handle();
10261026
struct inode *inode = mapping->host;
1027+
loff_t old_size = inode->i_size;
10271028
int ret = 0, ret2;
10281029
int i_size_changed = 0;
10291030

@@ -1054,6 +1055,8 @@ static int ext4_write_end(struct file *file,
10541055
unlock_page(page);
10551056
page_cache_release(page);
10561057

1058+
if (old_size < pos)
1059+
pagecache_isize_extended(inode, old_size, pos);
10571060
/*
10581061
* Don't mark the inode dirty under page lock. First, it unnecessarily
10591062
* makes the holding time of page lock longer. Second, it forces lock
@@ -1095,6 +1098,7 @@ static int ext4_journalled_write_end(struct file *file,
10951098
{
10961099
handle_t *handle = ext4_journal_current_handle();
10971100
struct inode *inode = mapping->host;
1101+
loff_t old_size = inode->i_size;
10981102
int ret = 0, ret2;
10991103
int partial = 0;
11001104
unsigned from, to;
@@ -1127,6 +1131,9 @@ static int ext4_journalled_write_end(struct file *file,
11271131
unlock_page(page);
11281132
page_cache_release(page);
11291133

1134+
if (old_size < pos)
1135+
pagecache_isize_extended(inode, old_size, pos);
1136+
11301137
if (size_changed) {
11311138
ret2 = ext4_mark_inode_dirty(handle, inode);
11321139
if (!ret)

fs/ext4/super.c

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2779,6 +2779,12 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
27792779
if (readonly)
27802780
return 1;
27812781

2782+
if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_READONLY)) {
2783+
ext4_msg(sb, KERN_INFO, "filesystem is read-only");
2784+
sb->s_flags |= MS_RDONLY;
2785+
return 1;
2786+
}
2787+
27822788
/* Check that feature set is OK for a read-write mount */
27832789
if (EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT4_FEATURE_RO_COMPAT_SUPP)) {
27842790
ext4_msg(sb, KERN_ERR, "couldn't mount RDWR because of "
@@ -3936,9 +3942,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
39363942
get_random_bytes(&sbi->s_next_generation, sizeof(u32));
39373943
spin_lock_init(&sbi->s_next_gen_lock);
39383944

3939-
init_timer(&sbi->s_err_report);
3940-
sbi->s_err_report.function = print_daily_error_info;
3941-
sbi->s_err_report.data = (unsigned long) sb;
3945+
setup_timer(&sbi->s_err_report, print_daily_error_info,
3946+
(unsigned long) sb);
39423947

39433948
/* Register extent status tree shrinker */
39443949
if (ext4_es_register_shrinker(sbi))
@@ -4866,9 +4871,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
48664871
if (sbi->s_journal && sbi->s_journal->j_task->io_context)
48674872
journal_ioprio = sbi->s_journal->j_task->io_context->ioprio;
48684873

4869-
/*
4870-
* Allow the "check" option to be passed as a remount option.
4871-
*/
48724874
if (!parse_options(data, sb, NULL, &journal_ioprio, 1)) {
48734875
err = -EINVAL;
48744876
goto restore_opts;
@@ -4877,17 +4879,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
48774879
if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^
48784880
test_opt(sb, JOURNAL_CHECKSUM)) {
48794881
ext4_msg(sb, KERN_ERR, "changing journal_checksum "
4880-
"during remount not supported");
4881-
err = -EINVAL;
4882-
goto restore_opts;
4883-
}
4884-
4885-
if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^
4886-
test_opt(sb, JOURNAL_CHECKSUM)) {
4887-
ext4_msg(sb, KERN_ERR, "changing journal_checksum "
4888-
"during remount not supported");
4889-
err = -EINVAL;
4890-
goto restore_opts;
4882+
"during remount not supported; ignoring");
4883+
sbi->s_mount_opt ^= EXT4_MOUNT_JOURNAL_CHECKSUM;
48914884
}
48924885

48934886
if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
@@ -4963,7 +4956,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
49634956
ext4_mark_recovery_complete(sb, es);
49644957
} else {
49654958
/* Make sure we can mount this feature set readwrite */
4966-
if (!ext4_feature_set_ok(sb, 0)) {
4959+
if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
4960+
EXT4_FEATURE_RO_COMPAT_READONLY) ||
4961+
!ext4_feature_set_ok(sb, 0)) {
49674962
err = -EROFS;
49684963
goto restore_opts;
49694964
}

fs/jbd2/recovery.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,9 @@ static int do_one_pass(journal_t *journal,
524524
if (descr_csum_size > 0 &&
525525
!jbd2_descr_block_csum_verify(journal,
526526
bh->b_data)) {
527+
printk(KERN_ERR "JBD2: Invalid checksum "
528+
"recovering block %lu in log\n",
529+
next_log_block);
527530
err = -EIO;
528531
brelse(bh);
529532
goto failed;

0 commit comments

Comments
 (0)