diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-01 13:12:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-01 13:12:15 -0400 |
commit | 4edebed86690eb8db9af3ab85baf4a34e73266cc (patch) | |
tree | 8ab144b08f490f239fa62be52470860c9311664d /fs/ext4/super.c | |
parent | 51eab603f5c86dd1eae4c525df3e7f7eeab401d6 (diff) | |
parent | 5e44f8c374dc4f8eadf61cd18b2c0d46bc87c1b7 (diff) |
Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull Ext4 updates from Theodore Ts'o:
"The major new feature added in this update is Darrick J Wong's
metadata checksum feature, which adds crc32 checksums to ext4's
metadata fields.
There is also the usual set of cleanups and bug fixes."
* tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (44 commits)
ext4: hole-punch use truncate_pagecache_range
jbd2: use kmem_cache_zalloc wrapper instead of flag
ext4: remove mb_groups before tearing down the buddy_cache
ext4: add ext4_mb_unload_buddy in the error path
ext4: don't trash state flags in EXT4_IOC_SETFLAGS
ext4: let getattr report the right blocks in delalloc+bigalloc
ext4: add missing save_error_info() to ext4_error()
ext4: add debugging trigger for ext4_error()
ext4: protect group inode free counting with group lock
ext4: use consistent ssize_t type in ext4_file_write()
ext4: fix format flag in ext4_ext_binsearch_idx()
ext4: cleanup in ext4_discard_allocated_blocks()
ext4: return ENOMEM when mounts fail due to lack of memory
ext4: remove redundundant "(char *) bh->b_data" casts
ext4: disallow hard-linked directory in ext4_lookup
ext4: fix potential integer overflow in alloc_flex_gd()
ext4: remove needs_recovery in ext4_mb_init()
ext4: force ro mount if ext4_setup_super() fails
ext4: fix potential NULL dereference in ext4_free_inodes_counts()
ext4/jbd2: add metadata checksumming to the list of supported features
...
Diffstat (limited to 'fs/ext4/super.c')
-rw-r--r-- | fs/ext4/super.c | 253 |
1 files changed, 210 insertions, 43 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 35b5954489ee..eb7aa3e4ef05 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -112,6 +112,48 @@ static struct file_system_type ext3_fs_type = { | |||
112 | #define IS_EXT3_SB(sb) (0) | 112 | #define IS_EXT3_SB(sb) (0) |
113 | #endif | 113 | #endif |
114 | 114 | ||
115 | static int ext4_verify_csum_type(struct super_block *sb, | ||
116 | struct ext4_super_block *es) | ||
117 | { | ||
118 | if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
119 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
120 | return 1; | ||
121 | |||
122 | return es->s_checksum_type == EXT4_CRC32C_CHKSUM; | ||
123 | } | ||
124 | |||
125 | static __le32 ext4_superblock_csum(struct super_block *sb, | ||
126 | struct ext4_super_block *es) | ||
127 | { | ||
128 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
129 | int offset = offsetof(struct ext4_super_block, s_checksum); | ||
130 | __u32 csum; | ||
131 | |||
132 | csum = ext4_chksum(sbi, ~0, (char *)es, offset); | ||
133 | |||
134 | return cpu_to_le32(csum); | ||
135 | } | ||
136 | |||
137 | int ext4_superblock_csum_verify(struct super_block *sb, | ||
138 | struct ext4_super_block *es) | ||
139 | { | ||
140 | if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
141 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
142 | return 1; | ||
143 | |||
144 | return es->s_checksum == ext4_superblock_csum(sb, es); | ||
145 | } | ||
146 | |||
147 | void ext4_superblock_csum_set(struct super_block *sb, | ||
148 | struct ext4_super_block *es) | ||
149 | { | ||
150 | if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
151 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
152 | return; | ||
153 | |||
154 | es->s_checksum = ext4_superblock_csum(sb, es); | ||
155 | } | ||
156 | |||
115 | void *ext4_kvmalloc(size_t size, gfp_t flags) | 157 | void *ext4_kvmalloc(size_t size, gfp_t flags) |
116 | { | 158 | { |
117 | void *ret; | 159 | void *ret; |
@@ -497,6 +539,7 @@ void __ext4_error(struct super_block *sb, const char *function, | |||
497 | printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: comm %s: %pV\n", | 539 | printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: comm %s: %pV\n", |
498 | sb->s_id, function, line, current->comm, &vaf); | 540 | sb->s_id, function, line, current->comm, &vaf); |
499 | va_end(args); | 541 | va_end(args); |
542 | save_error_info(sb, function, line); | ||
500 | 543 | ||
501 | ext4_handle_error(sb); | 544 | ext4_handle_error(sb); |
502 | } | 545 | } |
@@ -905,6 +948,8 @@ static void ext4_put_super(struct super_block *sb) | |||
905 | unlock_super(sb); | 948 | unlock_super(sb); |
906 | kobject_put(&sbi->s_kobj); | 949 | kobject_put(&sbi->s_kobj); |
907 | wait_for_completion(&sbi->s_kobj_unregister); | 950 | wait_for_completion(&sbi->s_kobj_unregister); |
951 | if (sbi->s_chksum_driver) | ||
952 | crypto_free_shash(sbi->s_chksum_driver); | ||
908 | kfree(sbi->s_blockgroup_lock); | 953 | kfree(sbi->s_blockgroup_lock); |
909 | kfree(sbi); | 954 | kfree(sbi); |
910 | } | 955 | } |
@@ -1922,43 +1967,69 @@ failed: | |||
1922 | return 0; | 1967 | return 0; |
1923 | } | 1968 | } |
1924 | 1969 | ||
1925 | __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group, | 1970 | static __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group, |
1926 | struct ext4_group_desc *gdp) | 1971 | struct ext4_group_desc *gdp) |
1927 | { | 1972 | { |
1973 | int offset; | ||
1928 | __u16 crc = 0; | 1974 | __u16 crc = 0; |
1975 | __le32 le_group = cpu_to_le32(block_group); | ||
1929 | 1976 | ||
1930 | if (sbi->s_es->s_feature_ro_compat & | 1977 | if ((sbi->s_es->s_feature_ro_compat & |
1931 | cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { | 1978 | cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))) { |
1932 | int offset = offsetof(struct ext4_group_desc, bg_checksum); | 1979 | /* Use new metadata_csum algorithm */ |
1933 | __le32 le_group = cpu_to_le32(block_group); | 1980 | __u16 old_csum; |
1934 | 1981 | __u32 csum32; | |
1935 | crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid)); | 1982 | |
1936 | crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group)); | 1983 | old_csum = gdp->bg_checksum; |
1937 | crc = crc16(crc, (__u8 *)gdp, offset); | 1984 | gdp->bg_checksum = 0; |
1938 | offset += sizeof(gdp->bg_checksum); /* skip checksum */ | 1985 | csum32 = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&le_group, |
1939 | /* for checksum of struct ext4_group_desc do the rest...*/ | 1986 | sizeof(le_group)); |
1940 | if ((sbi->s_es->s_feature_incompat & | 1987 | csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp, |
1941 | cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) && | 1988 | sbi->s_desc_size); |
1942 | offset < le16_to_cpu(sbi->s_es->s_desc_size)) | 1989 | gdp->bg_checksum = old_csum; |
1943 | crc = crc16(crc, (__u8 *)gdp + offset, | 1990 | |
1944 | le16_to_cpu(sbi->s_es->s_desc_size) - | 1991 | crc = csum32 & 0xFFFF; |
1945 | offset); | 1992 | goto out; |
1946 | } | 1993 | } |
1947 | 1994 | ||
1995 | /* old crc16 code */ | ||
1996 | offset = offsetof(struct ext4_group_desc, bg_checksum); | ||
1997 | |||
1998 | crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid)); | ||
1999 | crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group)); | ||
2000 | crc = crc16(crc, (__u8 *)gdp, offset); | ||
2001 | offset += sizeof(gdp->bg_checksum); /* skip checksum */ | ||
2002 | /* for checksum of struct ext4_group_desc do the rest...*/ | ||
2003 | if ((sbi->s_es->s_feature_incompat & | ||
2004 | cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) && | ||
2005 | offset < le16_to_cpu(sbi->s_es->s_desc_size)) | ||
2006 | crc = crc16(crc, (__u8 *)gdp + offset, | ||
2007 | le16_to_cpu(sbi->s_es->s_desc_size) - | ||
2008 | offset); | ||
2009 | |||
2010 | out: | ||
1948 | return cpu_to_le16(crc); | 2011 | return cpu_to_le16(crc); |
1949 | } | 2012 | } |
1950 | 2013 | ||
1951 | int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 block_group, | 2014 | int ext4_group_desc_csum_verify(struct super_block *sb, __u32 block_group, |
1952 | struct ext4_group_desc *gdp) | 2015 | struct ext4_group_desc *gdp) |
1953 | { | 2016 | { |
1954 | if ((sbi->s_es->s_feature_ro_compat & | 2017 | if (ext4_has_group_desc_csum(sb) && |
1955 | cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) && | 2018 | (gdp->bg_checksum != ext4_group_desc_csum(EXT4_SB(sb), |
1956 | (gdp->bg_checksum != ext4_group_desc_csum(sbi, block_group, gdp))) | 2019 | block_group, gdp))) |
1957 | return 0; | 2020 | return 0; |
1958 | 2021 | ||
1959 | return 1; | 2022 | return 1; |
1960 | } | 2023 | } |
1961 | 2024 | ||
2025 | void ext4_group_desc_csum_set(struct super_block *sb, __u32 block_group, | ||
2026 | struct ext4_group_desc *gdp) | ||
2027 | { | ||
2028 | if (!ext4_has_group_desc_csum(sb)) | ||
2029 | return; | ||
2030 | gdp->bg_checksum = ext4_group_desc_csum(EXT4_SB(sb), block_group, gdp); | ||
2031 | } | ||
2032 | |||
1962 | /* Called at mount-time, super-block is locked */ | 2033 | /* Called at mount-time, super-block is locked */ |
1963 | static int ext4_check_descriptors(struct super_block *sb, | 2034 | static int ext4_check_descriptors(struct super_block *sb, |
1964 | ext4_group_t *first_not_zeroed) | 2035 | ext4_group_t *first_not_zeroed) |
@@ -2013,7 +2084,7 @@ static int ext4_check_descriptors(struct super_block *sb, | |||
2013 | return 0; | 2084 | return 0; |
2014 | } | 2085 | } |
2015 | ext4_lock_group(sb, i); | 2086 | ext4_lock_group(sb, i); |
2016 | if (!ext4_group_desc_csum_verify(sbi, i, gdp)) { | 2087 | if (!ext4_group_desc_csum_verify(sb, i, gdp)) { |
2017 | ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " | 2088 | ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " |
2018 | "Checksum for group %u failed (%u!=%u)", | 2089 | "Checksum for group %u failed (%u!=%u)", |
2019 | i, le16_to_cpu(ext4_group_desc_csum(sbi, i, | 2090 | i, le16_to_cpu(ext4_group_desc_csum(sbi, i, |
@@ -2417,6 +2488,23 @@ static ssize_t sbi_ui_store(struct ext4_attr *a, | |||
2417 | return count; | 2488 | return count; |
2418 | } | 2489 | } |
2419 | 2490 | ||
2491 | static ssize_t trigger_test_error(struct ext4_attr *a, | ||
2492 | struct ext4_sb_info *sbi, | ||
2493 | const char *buf, size_t count) | ||
2494 | { | ||
2495 | int len = count; | ||
2496 | |||
2497 | if (!capable(CAP_SYS_ADMIN)) | ||
2498 | return -EPERM; | ||
2499 | |||
2500 | if (len && buf[len-1] == '\n') | ||
2501 | len--; | ||
2502 | |||
2503 | if (len) | ||
2504 | ext4_error(sbi->s_sb, "%.*s", len, buf); | ||
2505 | return count; | ||
2506 | } | ||
2507 | |||
2420 | #define EXT4_ATTR_OFFSET(_name,_mode,_show,_store,_elname) \ | 2508 | #define EXT4_ATTR_OFFSET(_name,_mode,_show,_store,_elname) \ |
2421 | static struct ext4_attr ext4_attr_##_name = { \ | 2509 | static struct ext4_attr ext4_attr_##_name = { \ |
2422 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | 2510 | .attr = {.name = __stringify(_name), .mode = _mode }, \ |
@@ -2447,6 +2535,7 @@ EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs); | |||
2447 | EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request); | 2535 | EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request); |
2448 | EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc); | 2536 | EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc); |
2449 | EXT4_RW_ATTR_SBI_UI(max_writeback_mb_bump, s_max_writeback_mb_bump); | 2537 | EXT4_RW_ATTR_SBI_UI(max_writeback_mb_bump, s_max_writeback_mb_bump); |
2538 | EXT4_ATTR(trigger_fs_error, 0200, NULL, trigger_test_error); | ||
2450 | 2539 | ||
2451 | static struct attribute *ext4_attrs[] = { | 2540 | static struct attribute *ext4_attrs[] = { |
2452 | ATTR_LIST(delayed_allocation_blocks), | 2541 | ATTR_LIST(delayed_allocation_blocks), |
@@ -2461,6 +2550,7 @@ static struct attribute *ext4_attrs[] = { | |||
2461 | ATTR_LIST(mb_stream_req), | 2550 | ATTR_LIST(mb_stream_req), |
2462 | ATTR_LIST(mb_group_prealloc), | 2551 | ATTR_LIST(mb_group_prealloc), |
2463 | ATTR_LIST(max_writeback_mb_bump), | 2552 | ATTR_LIST(max_writeback_mb_bump), |
2553 | ATTR_LIST(trigger_fs_error), | ||
2464 | NULL, | 2554 | NULL, |
2465 | }; | 2555 | }; |
2466 | 2556 | ||
@@ -2957,6 +3047,44 @@ static void ext4_destroy_lazyinit_thread(void) | |||
2957 | kthread_stop(ext4_lazyinit_task); | 3047 | kthread_stop(ext4_lazyinit_task); |
2958 | } | 3048 | } |
2959 | 3049 | ||
3050 | static int set_journal_csum_feature_set(struct super_block *sb) | ||
3051 | { | ||
3052 | int ret = 1; | ||
3053 | int compat, incompat; | ||
3054 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
3055 | |||
3056 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
3057 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) { | ||
3058 | /* journal checksum v2 */ | ||
3059 | compat = 0; | ||
3060 | incompat = JBD2_FEATURE_INCOMPAT_CSUM_V2; | ||
3061 | } else { | ||
3062 | /* journal checksum v1 */ | ||
3063 | compat = JBD2_FEATURE_COMPAT_CHECKSUM; | ||
3064 | incompat = 0; | ||
3065 | } | ||
3066 | |||
3067 | if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) { | ||
3068 | ret = jbd2_journal_set_features(sbi->s_journal, | ||
3069 | compat, 0, | ||
3070 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT | | ||
3071 | incompat); | ||
3072 | } else if (test_opt(sb, JOURNAL_CHECKSUM)) { | ||
3073 | ret = jbd2_journal_set_features(sbi->s_journal, | ||
3074 | compat, 0, | ||
3075 | incompat); | ||
3076 | jbd2_journal_clear_features(sbi->s_journal, 0, 0, | ||
3077 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); | ||
3078 | } else { | ||
3079 | jbd2_journal_clear_features(sbi->s_journal, | ||
3080 | JBD2_FEATURE_COMPAT_CHECKSUM, 0, | ||
3081 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT | | ||
3082 | JBD2_FEATURE_INCOMPAT_CSUM_V2); | ||
3083 | } | ||
3084 | |||
3085 | return ret; | ||
3086 | } | ||
3087 | |||
2960 | static int ext4_fill_super(struct super_block *sb, void *data, int silent) | 3088 | static int ext4_fill_super(struct super_block *sb, void *data, int silent) |
2961 | { | 3089 | { |
2962 | char *orig_data = kstrdup(data, GFP_KERNEL); | 3090 | char *orig_data = kstrdup(data, GFP_KERNEL); |
@@ -2993,6 +3121,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2993 | goto out_free_orig; | 3121 | goto out_free_orig; |
2994 | } | 3122 | } |
2995 | sb->s_fs_info = sbi; | 3123 | sb->s_fs_info = sbi; |
3124 | sbi->s_sb = sb; | ||
2996 | sbi->s_mount_opt = 0; | 3125 | sbi->s_mount_opt = 0; |
2997 | sbi->s_resuid = make_kuid(&init_user_ns, EXT4_DEF_RESUID); | 3126 | sbi->s_resuid = make_kuid(&init_user_ns, EXT4_DEF_RESUID); |
2998 | sbi->s_resgid = make_kgid(&init_user_ns, EXT4_DEF_RESGID); | 3127 | sbi->s_resgid = make_kgid(&init_user_ns, EXT4_DEF_RESGID); |
@@ -3032,13 +3161,54 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3032 | * Note: s_es must be initialized as soon as possible because | 3161 | * Note: s_es must be initialized as soon as possible because |
3033 | * some ext4 macro-instructions depend on its value | 3162 | * some ext4 macro-instructions depend on its value |
3034 | */ | 3163 | */ |
3035 | es = (struct ext4_super_block *) (((char *)bh->b_data) + offset); | 3164 | es = (struct ext4_super_block *) (bh->b_data + offset); |
3036 | sbi->s_es = es; | 3165 | sbi->s_es = es; |
3037 | sb->s_magic = le16_to_cpu(es->s_magic); | 3166 | sb->s_magic = le16_to_cpu(es->s_magic); |
3038 | if (sb->s_magic != EXT4_SUPER_MAGIC) | 3167 | if (sb->s_magic != EXT4_SUPER_MAGIC) |
3039 | goto cantfind_ext4; | 3168 | goto cantfind_ext4; |
3040 | sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written); | 3169 | sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written); |
3041 | 3170 | ||
3171 | /* Warn if metadata_csum and gdt_csum are both set. */ | ||
3172 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
3173 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) && | ||
3174 | EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) | ||
3175 | ext4_warning(sb, KERN_INFO "metadata_csum and uninit_bg are " | ||
3176 | "redundant flags; please run fsck."); | ||
3177 | |||
3178 | /* Check for a known checksum algorithm */ | ||
3179 | if (!ext4_verify_csum_type(sb, es)) { | ||
3180 | ext4_msg(sb, KERN_ERR, "VFS: Found ext4 filesystem with " | ||
3181 | "unknown checksum algorithm."); | ||
3182 | silent = 1; | ||
3183 | goto cantfind_ext4; | ||
3184 | } | ||
3185 | |||
3186 | /* Load the checksum driver */ | ||
3187 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
3188 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) { | ||
3189 | sbi->s_chksum_driver = crypto_alloc_shash("crc32c", 0, 0); | ||
3190 | if (IS_ERR(sbi->s_chksum_driver)) { | ||
3191 | ext4_msg(sb, KERN_ERR, "Cannot load crc32c driver."); | ||
3192 | ret = PTR_ERR(sbi->s_chksum_driver); | ||
3193 | sbi->s_chksum_driver = NULL; | ||
3194 | goto failed_mount; | ||
3195 | } | ||
3196 | } | ||
3197 | |||
3198 | /* Check superblock checksum */ | ||
3199 | if (!ext4_superblock_csum_verify(sb, es)) { | ||
3200 | ext4_msg(sb, KERN_ERR, "VFS: Found ext4 filesystem with " | ||
3201 | "invalid superblock checksum. Run e2fsck?"); | ||
3202 | silent = 1; | ||
3203 | goto cantfind_ext4; | ||
3204 | } | ||
3205 | |||
3206 | /* Precompute checksum seed for all metadata */ | ||
3207 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
3208 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
3209 | sbi->s_csum_seed = ext4_chksum(sbi, ~0, es->s_uuid, | ||
3210 | sizeof(es->s_uuid)); | ||
3211 | |||
3042 | /* Set defaults before we parse the mount options */ | 3212 | /* Set defaults before we parse the mount options */ |
3043 | def_mount_opts = le32_to_cpu(es->s_default_mount_opts); | 3213 | def_mount_opts = le32_to_cpu(es->s_default_mount_opts); |
3044 | set_opt(sb, INIT_INODE_TABLE); | 3214 | set_opt(sb, INIT_INODE_TABLE); |
@@ -3200,7 +3370,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3200 | "Can't read superblock on 2nd try"); | 3370 | "Can't read superblock on 2nd try"); |
3201 | goto failed_mount; | 3371 | goto failed_mount; |
3202 | } | 3372 | } |
3203 | es = (struct ext4_super_block *)(((char *)bh->b_data) + offset); | 3373 | es = (struct ext4_super_block *)(bh->b_data + offset); |
3204 | sbi->s_es = es; | 3374 | sbi->s_es = es; |
3205 | if (es->s_magic != cpu_to_le16(EXT4_SUPER_MAGIC)) { | 3375 | if (es->s_magic != cpu_to_le16(EXT4_SUPER_MAGIC)) { |
3206 | ext4_msg(sb, KERN_ERR, | 3376 | ext4_msg(sb, KERN_ERR, |
@@ -3392,6 +3562,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3392 | GFP_KERNEL); | 3562 | GFP_KERNEL); |
3393 | if (sbi->s_group_desc == NULL) { | 3563 | if (sbi->s_group_desc == NULL) { |
3394 | ext4_msg(sb, KERN_ERR, "not enough memory"); | 3564 | ext4_msg(sb, KERN_ERR, "not enough memory"); |
3565 | ret = -ENOMEM; | ||
3395 | goto failed_mount; | 3566 | goto failed_mount; |
3396 | } | 3567 | } |
3397 | 3568 | ||
@@ -3449,6 +3620,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3449 | } | 3620 | } |
3450 | if (err) { | 3621 | if (err) { |
3451 | ext4_msg(sb, KERN_ERR, "insufficient memory"); | 3622 | ext4_msg(sb, KERN_ERR, "insufficient memory"); |
3623 | ret = err; | ||
3452 | goto failed_mount3; | 3624 | goto failed_mount3; |
3453 | } | 3625 | } |
3454 | 3626 | ||
@@ -3506,26 +3678,17 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3506 | goto no_journal; | 3678 | goto no_journal; |
3507 | } | 3679 | } |
3508 | 3680 | ||
3509 | if (ext4_blocks_count(es) > 0xffffffffULL && | 3681 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_64BIT) && |
3510 | !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0, | 3682 | !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0, |
3511 | JBD2_FEATURE_INCOMPAT_64BIT)) { | 3683 | JBD2_FEATURE_INCOMPAT_64BIT)) { |
3512 | ext4_msg(sb, KERN_ERR, "Failed to set 64-bit journal feature"); | 3684 | ext4_msg(sb, KERN_ERR, "Failed to set 64-bit journal feature"); |
3513 | goto failed_mount_wq; | 3685 | goto failed_mount_wq; |
3514 | } | 3686 | } |
3515 | 3687 | ||
3516 | if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) { | 3688 | if (!set_journal_csum_feature_set(sb)) { |
3517 | jbd2_journal_set_features(sbi->s_journal, | 3689 | ext4_msg(sb, KERN_ERR, "Failed to set journal checksum " |
3518 | JBD2_FEATURE_COMPAT_CHECKSUM, 0, | 3690 | "feature set"); |
3519 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); | 3691 | goto failed_mount_wq; |
3520 | } else if (test_opt(sb, JOURNAL_CHECKSUM)) { | ||
3521 | jbd2_journal_set_features(sbi->s_journal, | ||
3522 | JBD2_FEATURE_COMPAT_CHECKSUM, 0, 0); | ||
3523 | jbd2_journal_clear_features(sbi->s_journal, 0, 0, | ||
3524 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); | ||
3525 | } else { | ||
3526 | jbd2_journal_clear_features(sbi->s_journal, | ||
3527 | JBD2_FEATURE_COMPAT_CHECKSUM, 0, | ||
3528 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); | ||
3529 | } | 3692 | } |
3530 | 3693 | ||
3531 | /* We have now updated the journal if required, so we can | 3694 | /* We have now updated the journal if required, so we can |
@@ -3606,7 +3769,8 @@ no_journal: | |||
3606 | goto failed_mount4; | 3769 | goto failed_mount4; |
3607 | } | 3770 | } |
3608 | 3771 | ||
3609 | ext4_setup_super(sb, es, sb->s_flags & MS_RDONLY); | 3772 | if (ext4_setup_super(sb, es, sb->s_flags & MS_RDONLY)) |
3773 | sb->s_flags |= MS_RDONLY; | ||
3610 | 3774 | ||
3611 | /* determine the minimum size of new large inodes, if present */ | 3775 | /* determine the minimum size of new large inodes, if present */ |
3612 | if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) { | 3776 | if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) { |
@@ -3641,7 +3805,7 @@ no_journal: | |||
3641 | } | 3805 | } |
3642 | 3806 | ||
3643 | ext4_ext_init(sb); | 3807 | ext4_ext_init(sb); |
3644 | err = ext4_mb_init(sb, needs_recovery); | 3808 | err = ext4_mb_init(sb); |
3645 | if (err) { | 3809 | if (err) { |
3646 | ext4_msg(sb, KERN_ERR, "failed to initialize mballoc (%d)", | 3810 | ext4_msg(sb, KERN_ERR, "failed to initialize mballoc (%d)", |
3647 | err); | 3811 | err); |
@@ -3724,6 +3888,8 @@ failed_mount2: | |||
3724 | brelse(sbi->s_group_desc[i]); | 3888 | brelse(sbi->s_group_desc[i]); |
3725 | ext4_kvfree(sbi->s_group_desc); | 3889 | ext4_kvfree(sbi->s_group_desc); |
3726 | failed_mount: | 3890 | failed_mount: |
3891 | if (sbi->s_chksum_driver) | ||
3892 | crypto_free_shash(sbi->s_chksum_driver); | ||
3727 | if (sbi->s_proc) { | 3893 | if (sbi->s_proc) { |
3728 | remove_proc_entry("options", sbi->s_proc); | 3894 | remove_proc_entry("options", sbi->s_proc); |
3729 | remove_proc_entry(sb->s_id, ext4_proc_root); | 3895 | remove_proc_entry(sb->s_id, ext4_proc_root); |
@@ -3847,7 +4013,7 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb, | |||
3847 | goto out_bdev; | 4013 | goto out_bdev; |
3848 | } | 4014 | } |
3849 | 4015 | ||
3850 | es = (struct ext4_super_block *) (((char *)bh->b_data) + offset); | 4016 | es = (struct ext4_super_block *) (bh->b_data + offset); |
3851 | if ((le16_to_cpu(es->s_magic) != EXT4_SUPER_MAGIC) || | 4017 | if ((le16_to_cpu(es->s_magic) != EXT4_SUPER_MAGIC) || |
3852 | !(le32_to_cpu(es->s_feature_incompat) & | 4018 | !(le32_to_cpu(es->s_feature_incompat) & |
3853 | EXT4_FEATURE_INCOMPAT_JOURNAL_DEV)) { | 4019 | EXT4_FEATURE_INCOMPAT_JOURNAL_DEV)) { |
@@ -4039,6 +4205,7 @@ static int ext4_commit_super(struct super_block *sb, int sync) | |||
4039 | &EXT4_SB(sb)->s_freeinodes_counter)); | 4205 | &EXT4_SB(sb)->s_freeinodes_counter)); |
4040 | sb->s_dirt = 0; | 4206 | sb->s_dirt = 0; |
4041 | BUFFER_TRACE(sbh, "marking dirty"); | 4207 | BUFFER_TRACE(sbh, "marking dirty"); |
4208 | ext4_superblock_csum_set(sb, es); | ||
4042 | mark_buffer_dirty(sbh); | 4209 | mark_buffer_dirty(sbh); |
4043 | if (sync) { | 4210 | if (sync) { |
4044 | error = sync_dirty_buffer(sbh); | 4211 | error = sync_dirty_buffer(sbh); |
@@ -4333,7 +4500,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) | |||
4333 | struct ext4_group_desc *gdp = | 4500 | struct ext4_group_desc *gdp = |
4334 | ext4_get_group_desc(sb, g, NULL); | 4501 | ext4_get_group_desc(sb, g, NULL); |
4335 | 4502 | ||
4336 | if (!ext4_group_desc_csum_verify(sbi, g, gdp)) { | 4503 | if (!ext4_group_desc_csum_verify(sb, g, gdp)) { |
4337 | ext4_msg(sb, KERN_ERR, | 4504 | ext4_msg(sb, KERN_ERR, |
4338 | "ext4_remount: Checksum for group %u failed (%u!=%u)", | 4505 | "ext4_remount: Checksum for group %u failed (%u!=%u)", |
4339 | g, le16_to_cpu(ext4_group_desc_csum(sbi, g, gdp)), | 4506 | g, le16_to_cpu(ext4_group_desc_csum(sbi, g, gdp)), |