diff options
author | Eric Sandeen <sandeen@redhat.com> | 2009-08-18 00:20:23 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2009-08-18 00:20:23 -0400 |
commit | a13fb1a4533f26c1e2b0204d5283b696689645af (patch) | |
tree | 1f779dfe2057bef2a5985989f2a347ed32ca9179 /fs/ext4/super.c | |
parent | 38877f4e8dbbec12c6fde85ee1fce1dc27ef3290 (diff) |
ext4: Add feature set check helper for mount & remount paths
A user reported that although his root ext4 filesystem was mounting
fine, other filesystems would not mount, with the:
"Filesystem with huge files cannot be mounted RDWR without CONFIG_LBDAF"
error on his 32-bit box built without CONFIG_LBDAF. This is because
the test at mount time for this situation was not being re-checked
on remount, and the normal boot process makes an ro->rw transition,
so this was being missed.
Refactor to make a common helper function to test the filesystem
features against the type of mount request (RO vs. RW) so that we
stay consistent.
Addresses Red-Hat-Bugzilla: #517650
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/super.c')
-rw-r--r-- | fs/ext4/super.c | 91 |
1 files changed, 49 insertions, 42 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index de67c3657b83..4037fe0b5a5c 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -2254,6 +2254,49 @@ static struct kobj_type ext4_ktype = { | |||
2254 | .release = ext4_sb_release, | 2254 | .release = ext4_sb_release, |
2255 | }; | 2255 | }; |
2256 | 2256 | ||
2257 | /* | ||
2258 | * Check whether this filesystem can be mounted based on | ||
2259 | * the features present and the RDONLY/RDWR mount requested. | ||
2260 | * Returns 1 if this filesystem can be mounted as requested, | ||
2261 | * 0 if it cannot be. | ||
2262 | */ | ||
2263 | static int ext4_feature_set_ok(struct super_block *sb, int readonly) | ||
2264 | { | ||
2265 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT4_FEATURE_INCOMPAT_SUPP)) { | ||
2266 | ext4_msg(sb, KERN_ERR, | ||
2267 | "Couldn't mount because of " | ||
2268 | "unsupported optional features (%x)", | ||
2269 | (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_incompat) & | ||
2270 | ~EXT4_FEATURE_INCOMPAT_SUPP)); | ||
2271 | return 0; | ||
2272 | } | ||
2273 | |||
2274 | if (readonly) | ||
2275 | return 1; | ||
2276 | |||
2277 | /* Check that feature set is OK for a read-write mount */ | ||
2278 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT4_FEATURE_RO_COMPAT_SUPP)) { | ||
2279 | ext4_msg(sb, KERN_ERR, "couldn't mount RDWR because of " | ||
2280 | "unsupported optional features (%x)", | ||
2281 | (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_ro_compat) & | ||
2282 | ~EXT4_FEATURE_RO_COMPAT_SUPP)); | ||
2283 | return 0; | ||
2284 | } | ||
2285 | /* | ||
2286 | * Large file size enabled file system can only be mounted | ||
2287 | * read-write on 32-bit systems if kernel is built with CONFIG_LBDAF | ||
2288 | */ | ||
2289 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) { | ||
2290 | if (sizeof(blkcnt_t) < sizeof(u64)) { | ||
2291 | ext4_msg(sb, KERN_ERR, "Filesystem with huge files " | ||
2292 | "cannot be mounted RDWR without " | ||
2293 | "CONFIG_LBDAF"); | ||
2294 | return 0; | ||
2295 | } | ||
2296 | } | ||
2297 | return 1; | ||
2298 | } | ||
2299 | |||
2257 | static int ext4_fill_super(struct super_block *sb, void *data, int silent) | 2300 | static int ext4_fill_super(struct super_block *sb, void *data, int silent) |
2258 | __releases(kernel_lock) | 2301 | __releases(kernel_lock) |
2259 | __acquires(kernel_lock) | 2302 | __acquires(kernel_lock) |
@@ -2275,7 +2318,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2275 | unsigned int db_count; | 2318 | unsigned int db_count; |
2276 | unsigned int i; | 2319 | unsigned int i; |
2277 | int needs_recovery, has_huge_files; | 2320 | int needs_recovery, has_huge_files; |
2278 | int features; | ||
2279 | __u64 blocks_count; | 2321 | __u64 blocks_count; |
2280 | int err; | 2322 | int err; |
2281 | unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO; | 2323 | unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO; |
@@ -2402,39 +2444,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2402 | * previously didn't change the revision level when setting the flags, | 2444 | * previously didn't change the revision level when setting the flags, |
2403 | * so there is a chance incompat flags are set on a rev 0 filesystem. | 2445 | * so there is a chance incompat flags are set on a rev 0 filesystem. |
2404 | */ | 2446 | */ |
2405 | features = EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT4_FEATURE_INCOMPAT_SUPP); | 2447 | if (!ext4_feature_set_ok(sb, (sb->s_flags & MS_RDONLY))) |
2406 | if (features) { | ||
2407 | ext4_msg(sb, KERN_ERR, | ||
2408 | "Couldn't mount because of " | ||
2409 | "unsupported optional features (%x)", | ||
2410 | (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_incompat) & | ||
2411 | ~EXT4_FEATURE_INCOMPAT_SUPP)); | ||
2412 | goto failed_mount; | ||
2413 | } | ||
2414 | features = EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT4_FEATURE_RO_COMPAT_SUPP); | ||
2415 | if (!(sb->s_flags & MS_RDONLY) && features) { | ||
2416 | ext4_msg(sb, KERN_ERR, | ||
2417 | "Couldn't mount RDWR because of " | ||
2418 | "unsupported optional features (%x)", | ||
2419 | (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_ro_compat) & | ||
2420 | ~EXT4_FEATURE_RO_COMPAT_SUPP)); | ||
2421 | goto failed_mount; | 2448 | goto failed_mount; |
2422 | } | 2449 | |
2423 | has_huge_files = EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
2424 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE); | ||
2425 | if (has_huge_files) { | ||
2426 | /* | ||
2427 | * Large file size enabled file system can only be | ||
2428 | * mount if kernel is build with CONFIG_LBDAF | ||
2429 | */ | ||
2430 | if (sizeof(root->i_blocks) < sizeof(u64) && | ||
2431 | !(sb->s_flags & MS_RDONLY)) { | ||
2432 | ext4_msg(sb, KERN_ERR, "Filesystem with huge " | ||
2433 | "files cannot be mounted read-write " | ||
2434 | "without CONFIG_LBDAF"); | ||
2435 | goto failed_mount; | ||
2436 | } | ||
2437 | } | ||
2438 | blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size); | 2450 | blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size); |
2439 | 2451 | ||
2440 | if (blocksize < EXT4_MIN_BLOCK_SIZE || | 2452 | if (blocksize < EXT4_MIN_BLOCK_SIZE || |
@@ -2470,6 +2482,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2470 | } | 2482 | } |
2471 | } | 2483 | } |
2472 | 2484 | ||
2485 | has_huge_files = EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
2486 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE); | ||
2473 | sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits, | 2487 | sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits, |
2474 | has_huge_files); | 2488 | has_huge_files); |
2475 | sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits, has_huge_files); | 2489 | sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits, has_huge_files); |
@@ -3485,18 +3499,11 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) | |||
3485 | if (sbi->s_journal) | 3499 | if (sbi->s_journal) |
3486 | ext4_mark_recovery_complete(sb, es); | 3500 | ext4_mark_recovery_complete(sb, es); |
3487 | } else { | 3501 | } else { |
3488 | int ret; | 3502 | /* Make sure we can mount this feature set readwrite */ |
3489 | if ((ret = EXT4_HAS_RO_COMPAT_FEATURE(sb, | 3503 | if (!ext4_feature_set_ok(sb, 0)) { |
3490 | ~EXT4_FEATURE_RO_COMPAT_SUPP))) { | ||
3491 | ext4_msg(sb, KERN_WARNING, "couldn't " | ||
3492 | "remount RDWR because of unsupported " | ||
3493 | "optional features (%x)", | ||
3494 | (le32_to_cpu(sbi->s_es->s_feature_ro_compat) & | ||
3495 | ~EXT4_FEATURE_RO_COMPAT_SUPP)); | ||
3496 | err = -EROFS; | 3504 | err = -EROFS; |
3497 | goto restore_opts; | 3505 | goto restore_opts; |
3498 | } | 3506 | } |
3499 | |||
3500 | /* | 3507 | /* |
3501 | * Make sure the group descriptor checksums | 3508 | * Make sure the group descriptor checksums |
3502 | * are sane. If they aren't, refuse to remount r/w. | 3509 | * are sane. If they aren't, refuse to remount r/w. |