diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-05 15:49:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-05 15:49:17 -0400 |
commit | 1434763ca5b300ad3b880954bd32dc339d16a833 (patch) | |
tree | a9a43ec1574e2df724c0c8573677255adf11bd92 | |
parent | 5037be168f0e4ee910602935b1180291082d3aac (diff) | |
parent | 4f2f76f751433908364ccff82f437a57d0e6e9b7 (diff) |
Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 updates from Ted Ts'o:
"A lot of cleanups and bug fixes, especially dealing with corrupted
file systems"
* tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (23 commits)
ext4: fix fencepost error in check for inode count overflow during resize
ext4: correctly handle a zero-length xattr with a non-zero e_value_offs
ext4: bubble errors from ext4_find_inline_data_nolock() up to ext4_iget()
ext4: do not allow external inodes for inline data
ext4: report delalloc reserve as non-free in statfs for project quota
ext4: remove NULL check before calling kmem_cache_destroy()
jbd2: remove NULL check before calling kmem_cache_destroy()
jbd2: remove bunch of empty lines with jbd2 debug
ext4: handle errors on ext4_commit_super
ext4: do not update s_last_mounted of a frozen fs
ext4: factor out helper ext4_sample_last_mounted()
vfs: add the sb_start_intwrite_trylock() helper
ext4: update mtime in ext4_punch_hole even if no blocks are released
ext4: add verifier check for symlink with append/immutable flags
fs: ext4: add new return type vm_fault_t
ext4: fix hole length detection in ext4_ind_map_blocks()
ext4: mark block bitmap corrupted when found
ext4: mark inode bitmap corrupted when found
ext4: add new ext4_mark_group_bitmap_corrupted() helper
ext4: fix wrong return value in ext4_read_inode_bitmap()
...
-rw-r--r-- | fs/ext4/balloc.c | 33 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 7 | ||||
-rw-r--r-- | fs/ext4/extents_status.c | 3 | ||||
-rw-r--r-- | fs/ext4/file.c | 93 | ||||
-rw-r--r-- | fs/ext4/fsmap.c | 4 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 35 | ||||
-rw-r--r-- | fs/ext4/indirect.c | 14 | ||||
-rw-r--r-- | fs/ext4/inline.c | 6 | ||||
-rw-r--r-- | fs/ext4/inode.c | 77 | ||||
-rw-r--r-- | fs/ext4/mballoc.c | 23 | ||||
-rw-r--r-- | fs/ext4/resize.c | 2 | ||||
-rw-r--r-- | fs/ext4/super.c | 68 | ||||
-rw-r--r-- | fs/ext4/xattr.c | 2 | ||||
-rw-r--r-- | fs/ext4/xattr_security.c | 2 | ||||
-rw-r--r-- | fs/jbd2/journal.c | 20 | ||||
-rw-r--r-- | fs/jbd2/revoke.c | 12 | ||||
-rw-r--r-- | fs/jbd2/transaction.c | 6 | ||||
-rw-r--r-- | include/linux/fs.h | 5 |
18 files changed, 245 insertions, 167 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 508b905d744d..b00481c475cb 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -185,25 +185,15 @@ static int ext4_init_block_bitmap(struct super_block *sb, | |||
185 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 185 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
186 | ext4_fsblk_t start, tmp; | 186 | ext4_fsblk_t start, tmp; |
187 | int flex_bg = 0; | 187 | int flex_bg = 0; |
188 | struct ext4_group_info *grp; | ||
189 | 188 | ||
190 | J_ASSERT_BH(bh, buffer_locked(bh)); | 189 | J_ASSERT_BH(bh, buffer_locked(bh)); |
191 | 190 | ||
192 | /* If checksum is bad mark all blocks used to prevent allocation | 191 | /* If checksum is bad mark all blocks used to prevent allocation |
193 | * essentially implementing a per-group read-only flag. */ | 192 | * essentially implementing a per-group read-only flag. */ |
194 | if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { | 193 | if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { |
195 | grp = ext4_get_group_info(sb, block_group); | 194 | ext4_mark_group_bitmap_corrupted(sb, block_group, |
196 | if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) | 195 | EXT4_GROUP_INFO_BBITMAP_CORRUPT | |
197 | percpu_counter_sub(&sbi->s_freeclusters_counter, | 196 | EXT4_GROUP_INFO_IBITMAP_CORRUPT); |
198 | grp->bb_free); | ||
199 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); | ||
200 | if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { | ||
201 | int count; | ||
202 | count = ext4_free_inodes_count(sb, gdp); | ||
203 | percpu_counter_sub(&sbi->s_freeinodes_counter, | ||
204 | count); | ||
205 | } | ||
206 | set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); | ||
207 | return -EFSBADCRC; | 197 | return -EFSBADCRC; |
208 | } | 198 | } |
209 | memset(bh->b_data, 0, sb->s_blocksize); | 199 | memset(bh->b_data, 0, sb->s_blocksize); |
@@ -375,7 +365,6 @@ static int ext4_validate_block_bitmap(struct super_block *sb, | |||
375 | { | 365 | { |
376 | ext4_fsblk_t blk; | 366 | ext4_fsblk_t blk; |
377 | struct ext4_group_info *grp = ext4_get_group_info(sb, block_group); | 367 | struct ext4_group_info *grp = ext4_get_group_info(sb, block_group); |
378 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
379 | 368 | ||
380 | if (buffer_verified(bh)) | 369 | if (buffer_verified(bh)) |
381 | return 0; | 370 | return 0; |
@@ -387,10 +376,8 @@ static int ext4_validate_block_bitmap(struct super_block *sb, | |||
387 | desc, bh))) { | 376 | desc, bh))) { |
388 | ext4_unlock_group(sb, block_group); | 377 | ext4_unlock_group(sb, block_group); |
389 | ext4_error(sb, "bg %u: bad block bitmap checksum", block_group); | 378 | ext4_error(sb, "bg %u: bad block bitmap checksum", block_group); |
390 | if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) | 379 | ext4_mark_group_bitmap_corrupted(sb, block_group, |
391 | percpu_counter_sub(&sbi->s_freeclusters_counter, | 380 | EXT4_GROUP_INFO_BBITMAP_CORRUPT); |
392 | grp->bb_free); | ||
393 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); | ||
394 | return -EFSBADCRC; | 381 | return -EFSBADCRC; |
395 | } | 382 | } |
396 | blk = ext4_valid_block_bitmap(sb, desc, block_group, bh); | 383 | blk = ext4_valid_block_bitmap(sb, desc, block_group, bh); |
@@ -398,10 +385,8 @@ static int ext4_validate_block_bitmap(struct super_block *sb, | |||
398 | ext4_unlock_group(sb, block_group); | 385 | ext4_unlock_group(sb, block_group); |
399 | ext4_error(sb, "bg %u: block %llu: invalid block bitmap", | 386 | ext4_error(sb, "bg %u: block %llu: invalid block bitmap", |
400 | block_group, blk); | 387 | block_group, blk); |
401 | if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) | 388 | ext4_mark_group_bitmap_corrupted(sb, block_group, |
402 | percpu_counter_sub(&sbi->s_freeclusters_counter, | 389 | EXT4_GROUP_INFO_BBITMAP_CORRUPT); |
403 | grp->bb_free); | ||
404 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); | ||
405 | return -EFSCORRUPTED; | 390 | return -EFSCORRUPTED; |
406 | } | 391 | } |
407 | set_buffer_verified(bh); | 392 | set_buffer_verified(bh); |
@@ -436,6 +421,8 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) | |||
436 | (bitmap_blk >= ext4_blocks_count(sbi->s_es))) { | 421 | (bitmap_blk >= ext4_blocks_count(sbi->s_es))) { |
437 | ext4_error(sb, "Invalid block bitmap block %llu in " | 422 | ext4_error(sb, "Invalid block bitmap block %llu in " |
438 | "block_group %u", bitmap_blk, block_group); | 423 | "block_group %u", bitmap_blk, block_group); |
424 | ext4_mark_group_bitmap_corrupted(sb, block_group, | ||
425 | EXT4_GROUP_INFO_BBITMAP_CORRUPT); | ||
439 | return ERR_PTR(-EFSCORRUPTED); | 426 | return ERR_PTR(-EFSCORRUPTED); |
440 | } | 427 | } |
441 | bh = sb_getblk(sb, bitmap_blk); | 428 | bh = sb_getblk(sb, bitmap_blk); |
@@ -514,6 +501,8 @@ int ext4_wait_block_bitmap(struct super_block *sb, ext4_group_t block_group, | |||
514 | ext4_error(sb, "Cannot read block bitmap - " | 501 | ext4_error(sb, "Cannot read block bitmap - " |
515 | "block_group = %u, block_bitmap = %llu", | 502 | "block_group = %u, block_bitmap = %llu", |
516 | block_group, (unsigned long long) bh->b_blocknr); | 503 | block_group, (unsigned long long) bh->b_blocknr); |
504 | ext4_mark_group_bitmap_corrupted(sb, block_group, | ||
505 | EXT4_GROUP_INFO_BBITMAP_CORRUPT); | ||
517 | return -EIO; | 506 | return -EIO; |
518 | } | 507 | } |
519 | clear_buffer_new(bh); | 508 | clear_buffer_new(bh); |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 229ea4da6785..df95412915ea 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -2530,6 +2530,9 @@ extern int ext4_alloc_flex_bg_array(struct super_block *sb, | |||
2530 | ext4_group_t ngroup); | 2530 | ext4_group_t ngroup); |
2531 | extern const char *ext4_decode_error(struct super_block *sb, int errno, | 2531 | extern const char *ext4_decode_error(struct super_block *sb, int errno, |
2532 | char nbuf[16]); | 2532 | char nbuf[16]); |
2533 | extern void ext4_mark_group_bitmap_corrupted(struct super_block *sb, | ||
2534 | ext4_group_t block_group, | ||
2535 | unsigned int flags); | ||
2533 | 2536 | ||
2534 | extern __printf(4, 5) | 2537 | extern __printf(4, 5) |
2535 | void __ext4_error(struct super_block *, const char *, unsigned int, | 2538 | void __ext4_error(struct super_block *, const char *, unsigned int, |
@@ -2857,6 +2860,10 @@ struct ext4_group_info { | |||
2857 | #define EXT4_GROUP_INFO_WAS_TRIMMED_BIT 1 | 2860 | #define EXT4_GROUP_INFO_WAS_TRIMMED_BIT 1 |
2858 | #define EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT 2 | 2861 | #define EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT 2 |
2859 | #define EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT 3 | 2862 | #define EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT 3 |
2863 | #define EXT4_GROUP_INFO_BBITMAP_CORRUPT \ | ||
2864 | (1 << EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT) | ||
2865 | #define EXT4_GROUP_INFO_IBITMAP_CORRUPT \ | ||
2866 | (1 << EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT) | ||
2860 | 2867 | ||
2861 | #define EXT4_MB_GRP_NEED_INIT(grp) \ | 2868 | #define EXT4_MB_GRP_NEED_INIT(grp) \ |
2862 | (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state))) | 2869 | (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state))) |
diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c index 763ef185dd17..c4e6fb15101b 100644 --- a/fs/ext4/extents_status.c +++ b/fs/ext4/extents_status.c | |||
@@ -162,8 +162,7 @@ int __init ext4_init_es(void) | |||
162 | 162 | ||
163 | void ext4_exit_es(void) | 163 | void ext4_exit_es(void) |
164 | { | 164 | { |
165 | if (ext4_es_cachep) | 165 | kmem_cache_destroy(ext4_es_cachep); |
166 | kmem_cache_destroy(ext4_es_cachep); | ||
167 | } | 166 | } |
168 | 167 | ||
169 | void ext4_es_init_tree(struct ext4_es_tree *tree) | 168 | void ext4_es_init_tree(struct ext4_es_tree *tree) |
diff --git a/fs/ext4/file.c b/fs/ext4/file.c index fb6f023622fe..7f8023340eb8 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c | |||
@@ -277,10 +277,11 @@ out: | |||
277 | } | 277 | } |
278 | 278 | ||
279 | #ifdef CONFIG_FS_DAX | 279 | #ifdef CONFIG_FS_DAX |
280 | static int ext4_dax_huge_fault(struct vm_fault *vmf, | 280 | static vm_fault_t ext4_dax_huge_fault(struct vm_fault *vmf, |
281 | enum page_entry_size pe_size) | 281 | enum page_entry_size pe_size) |
282 | { | 282 | { |
283 | int result, error = 0; | 283 | int error = 0; |
284 | vm_fault_t result; | ||
284 | int retries = 0; | 285 | int retries = 0; |
285 | handle_t *handle = NULL; | 286 | handle_t *handle = NULL; |
286 | struct inode *inode = file_inode(vmf->vma->vm_file); | 287 | struct inode *inode = file_inode(vmf->vma->vm_file); |
@@ -335,7 +336,7 @@ retry: | |||
335 | return result; | 336 | return result; |
336 | } | 337 | } |
337 | 338 | ||
338 | static int ext4_dax_fault(struct vm_fault *vmf) | 339 | static vm_fault_t ext4_dax_fault(struct vm_fault *vmf) |
339 | { | 340 | { |
340 | return ext4_dax_huge_fault(vmf, PE_SIZE_PTE); | 341 | return ext4_dax_huge_fault(vmf, PE_SIZE_PTE); |
341 | } | 342 | } |
@@ -380,50 +381,64 @@ static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma) | |||
380 | return 0; | 381 | return 0; |
381 | } | 382 | } |
382 | 383 | ||
383 | static int ext4_file_open(struct inode * inode, struct file * filp) | 384 | static int ext4_sample_last_mounted(struct super_block *sb, |
385 | struct vfsmount *mnt) | ||
384 | { | 386 | { |
385 | struct super_block *sb = inode->i_sb; | 387 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
386 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | ||
387 | struct vfsmount *mnt = filp->f_path.mnt; | ||
388 | struct path path; | 388 | struct path path; |
389 | char buf[64], *cp; | 389 | char buf[64], *cp; |
390 | handle_t *handle; | ||
391 | int err; | ||
392 | |||
393 | if (likely(sbi->s_mount_flags & EXT4_MF_MNTDIR_SAMPLED)) | ||
394 | return 0; | ||
395 | |||
396 | if (sb_rdonly(sb) || !sb_start_intwrite_trylock(sb)) | ||
397 | return 0; | ||
398 | |||
399 | sbi->s_mount_flags |= EXT4_MF_MNTDIR_SAMPLED; | ||
400 | /* | ||
401 | * Sample where the filesystem has been mounted and | ||
402 | * store it in the superblock for sysadmin convenience | ||
403 | * when trying to sort through large numbers of block | ||
404 | * devices or filesystem images. | ||
405 | */ | ||
406 | memset(buf, 0, sizeof(buf)); | ||
407 | path.mnt = mnt; | ||
408 | path.dentry = mnt->mnt_root; | ||
409 | cp = d_path(&path, buf, sizeof(buf)); | ||
410 | err = 0; | ||
411 | if (IS_ERR(cp)) | ||
412 | goto out; | ||
413 | |||
414 | handle = ext4_journal_start_sb(sb, EXT4_HT_MISC, 1); | ||
415 | err = PTR_ERR(handle); | ||
416 | if (IS_ERR(handle)) | ||
417 | goto out; | ||
418 | BUFFER_TRACE(sbi->s_sbh, "get_write_access"); | ||
419 | err = ext4_journal_get_write_access(handle, sbi->s_sbh); | ||
420 | if (err) | ||
421 | goto out_journal; | ||
422 | strlcpy(sbi->s_es->s_last_mounted, cp, | ||
423 | sizeof(sbi->s_es->s_last_mounted)); | ||
424 | ext4_handle_dirty_super(handle, sb); | ||
425 | out_journal: | ||
426 | ext4_journal_stop(handle); | ||
427 | out: | ||
428 | sb_end_intwrite(sb); | ||
429 | return err; | ||
430 | } | ||
431 | |||
432 | static int ext4_file_open(struct inode * inode, struct file * filp) | ||
433 | { | ||
390 | int ret; | 434 | int ret; |
391 | 435 | ||
392 | if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) | 436 | if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) |
393 | return -EIO; | 437 | return -EIO; |
394 | 438 | ||
395 | if (unlikely(!(sbi->s_mount_flags & EXT4_MF_MNTDIR_SAMPLED) && | 439 | ret = ext4_sample_last_mounted(inode->i_sb, filp->f_path.mnt); |
396 | !sb_rdonly(sb))) { | 440 | if (ret) |
397 | sbi->s_mount_flags |= EXT4_MF_MNTDIR_SAMPLED; | 441 | return ret; |
398 | /* | ||
399 | * Sample where the filesystem has been mounted and | ||
400 | * store it in the superblock for sysadmin convenience | ||
401 | * when trying to sort through large numbers of block | ||
402 | * devices or filesystem images. | ||
403 | */ | ||
404 | memset(buf, 0, sizeof(buf)); | ||
405 | path.mnt = mnt; | ||
406 | path.dentry = mnt->mnt_root; | ||
407 | cp = d_path(&path, buf, sizeof(buf)); | ||
408 | if (!IS_ERR(cp)) { | ||
409 | handle_t *handle; | ||
410 | int err; | ||
411 | |||
412 | handle = ext4_journal_start_sb(sb, EXT4_HT_MISC, 1); | ||
413 | if (IS_ERR(handle)) | ||
414 | return PTR_ERR(handle); | ||
415 | BUFFER_TRACE(sbi->s_sbh, "get_write_access"); | ||
416 | err = ext4_journal_get_write_access(handle, sbi->s_sbh); | ||
417 | if (err) { | ||
418 | ext4_journal_stop(handle); | ||
419 | return err; | ||
420 | } | ||
421 | strlcpy(sbi->s_es->s_last_mounted, cp, | ||
422 | sizeof(sbi->s_es->s_last_mounted)); | ||
423 | ext4_handle_dirty_super(handle, sb); | ||
424 | ext4_journal_stop(handle); | ||
425 | } | ||
426 | } | ||
427 | 442 | ||
428 | ret = fscrypt_file_open(inode, filp); | 443 | ret = fscrypt_file_open(inode, filp); |
429 | if (ret) | 444 | if (ret) |
diff --git a/fs/ext4/fsmap.c b/fs/ext4/fsmap.c index e871c4bf18e9..4b99e2db95b8 100644 --- a/fs/ext4/fsmap.c +++ b/fs/ext4/fsmap.c | |||
@@ -402,8 +402,8 @@ static void ext4_getfsmap_free_fixed_metadata(struct list_head *meta_list) | |||
402 | } | 402 | } |
403 | 403 | ||
404 | /* Find all the fixed metadata in the filesystem. */ | 404 | /* Find all the fixed metadata in the filesystem. */ |
405 | int ext4_getfsmap_find_fixed_metadata(struct super_block *sb, | 405 | static int ext4_getfsmap_find_fixed_metadata(struct super_block *sb, |
406 | struct list_head *meta_list) | 406 | struct list_head *meta_list) |
407 | { | 407 | { |
408 | struct ext4_group_desc *gdp; | 408 | struct ext4_group_desc *gdp; |
409 | ext4_group_t agno; | 409 | ext4_group_t agno; |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index df92e3ec9913..4d6e007f3569 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -83,7 +83,6 @@ static int ext4_validate_inode_bitmap(struct super_block *sb, | |||
83 | { | 83 | { |
84 | ext4_fsblk_t blk; | 84 | ext4_fsblk_t blk; |
85 | struct ext4_group_info *grp = ext4_get_group_info(sb, block_group); | 85 | struct ext4_group_info *grp = ext4_get_group_info(sb, block_group); |
86 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
87 | 86 | ||
88 | if (buffer_verified(bh)) | 87 | if (buffer_verified(bh)) |
89 | return 0; | 88 | return 0; |
@@ -97,14 +96,8 @@ static int ext4_validate_inode_bitmap(struct super_block *sb, | |||
97 | ext4_unlock_group(sb, block_group); | 96 | ext4_unlock_group(sb, block_group); |
98 | ext4_error(sb, "Corrupt inode bitmap - block_group = %u, " | 97 | ext4_error(sb, "Corrupt inode bitmap - block_group = %u, " |
99 | "inode_bitmap = %llu", block_group, blk); | 98 | "inode_bitmap = %llu", block_group, blk); |
100 | grp = ext4_get_group_info(sb, block_group); | 99 | ext4_mark_group_bitmap_corrupted(sb, block_group, |
101 | if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { | 100 | EXT4_GROUP_INFO_IBITMAP_CORRUPT); |
102 | int count; | ||
103 | count = ext4_free_inodes_count(sb, desc); | ||
104 | percpu_counter_sub(&sbi->s_freeinodes_counter, | ||
105 | count); | ||
106 | } | ||
107 | set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); | ||
108 | return -EFSBADCRC; | 101 | return -EFSBADCRC; |
109 | } | 102 | } |
110 | set_buffer_verified(bh); | 103 | set_buffer_verified(bh); |
@@ -136,6 +129,8 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
136 | (bitmap_blk >= ext4_blocks_count(sbi->s_es))) { | 129 | (bitmap_blk >= ext4_blocks_count(sbi->s_es))) { |
137 | ext4_error(sb, "Invalid inode bitmap blk %llu in " | 130 | ext4_error(sb, "Invalid inode bitmap blk %llu in " |
138 | "block_group %u", bitmap_blk, block_group); | 131 | "block_group %u", bitmap_blk, block_group); |
132 | ext4_mark_group_bitmap_corrupted(sb, block_group, | ||
133 | EXT4_GROUP_INFO_IBITMAP_CORRUPT); | ||
139 | return ERR_PTR(-EFSCORRUPTED); | 134 | return ERR_PTR(-EFSCORRUPTED); |
140 | } | 135 | } |
141 | bh = sb_getblk(sb, bitmap_blk); | 136 | bh = sb_getblk(sb, bitmap_blk); |
@@ -143,7 +138,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
143 | ext4_error(sb, "Cannot read inode bitmap - " | 138 | ext4_error(sb, "Cannot read inode bitmap - " |
144 | "block_group = %u, inode_bitmap = %llu", | 139 | "block_group = %u, inode_bitmap = %llu", |
145 | block_group, bitmap_blk); | 140 | block_group, bitmap_blk); |
146 | return ERR_PTR(-EIO); | 141 | return ERR_PTR(-ENOMEM); |
147 | } | 142 | } |
148 | if (bitmap_uptodate(bh)) | 143 | if (bitmap_uptodate(bh)) |
149 | goto verify; | 144 | goto verify; |
@@ -190,6 +185,8 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
190 | ext4_error(sb, "Cannot read inode bitmap - " | 185 | ext4_error(sb, "Cannot read inode bitmap - " |
191 | "block_group = %u, inode_bitmap = %llu", | 186 | "block_group = %u, inode_bitmap = %llu", |
192 | block_group, bitmap_blk); | 187 | block_group, bitmap_blk); |
188 | ext4_mark_group_bitmap_corrupted(sb, block_group, | ||
189 | EXT4_GROUP_INFO_IBITMAP_CORRUPT); | ||
193 | return ERR_PTR(-EIO); | 190 | return ERR_PTR(-EIO); |
194 | } | 191 | } |
195 | 192 | ||
@@ -337,13 +334,8 @@ out: | |||
337 | fatal = err; | 334 | fatal = err; |
338 | } else { | 335 | } else { |
339 | ext4_error(sb, "bit already cleared for inode %lu", ino); | 336 | ext4_error(sb, "bit already cleared for inode %lu", ino); |
340 | if (gdp && !EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { | 337 | ext4_mark_group_bitmap_corrupted(sb, block_group, |
341 | int count; | 338 | EXT4_GROUP_INFO_IBITMAP_CORRUPT); |
342 | count = ext4_free_inodes_count(sb, gdp); | ||
343 | percpu_counter_sub(&sbi->s_freeinodes_counter, | ||
344 | count); | ||
345 | } | ||
346 | set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); | ||
347 | } | 339 | } |
348 | 340 | ||
349 | error_return: | 341 | error_return: |
@@ -914,6 +906,8 @@ repeat_in_this_group: | |||
914 | if (group == 0 && (ino + 1) < EXT4_FIRST_INO(sb)) { | 906 | if (group == 0 && (ino + 1) < EXT4_FIRST_INO(sb)) { |
915 | ext4_error(sb, "reserved inode found cleared - " | 907 | ext4_error(sb, "reserved inode found cleared - " |
916 | "inode=%lu", ino + 1); | 908 | "inode=%lu", ino + 1); |
909 | ext4_mark_group_bitmap_corrupted(sb, group, | ||
910 | EXT4_GROUP_INFO_IBITMAP_CORRUPT); | ||
917 | goto next_group; | 911 | goto next_group; |
918 | } | 912 | } |
919 | 913 | ||
@@ -1105,6 +1099,8 @@ got: | |||
1105 | err = -EIO; | 1099 | err = -EIO; |
1106 | ext4_error(sb, "failed to insert inode %lu: doubly allocated?", | 1100 | ext4_error(sb, "failed to insert inode %lu: doubly allocated?", |
1107 | inode->i_ino); | 1101 | inode->i_ino); |
1102 | ext4_mark_group_bitmap_corrupted(sb, group, | ||
1103 | EXT4_GROUP_INFO_IBITMAP_CORRUPT); | ||
1108 | goto out; | 1104 | goto out; |
1109 | } | 1105 | } |
1110 | inode->i_generation = prandom_u32(); | 1106 | inode->i_generation = prandom_u32(); |
@@ -1206,11 +1202,8 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino) | |||
1206 | block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); | 1202 | block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); |
1207 | bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb); | 1203 | bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb); |
1208 | bitmap_bh = ext4_read_inode_bitmap(sb, block_group); | 1204 | bitmap_bh = ext4_read_inode_bitmap(sb, block_group); |
1209 | if (IS_ERR(bitmap_bh)) { | 1205 | if (IS_ERR(bitmap_bh)) |
1210 | ext4_error(sb, "inode bitmap error %ld for orphan %lu", | ||
1211 | ino, PTR_ERR(bitmap_bh)); | ||
1212 | return (struct inode *) bitmap_bh; | 1206 | return (struct inode *) bitmap_bh; |
1213 | } | ||
1214 | 1207 | ||
1215 | /* Having the inode bit set should be a 100% indicator that this | 1208 | /* Having the inode bit set should be a 100% indicator that this |
1216 | * is a valid orphan (no e2fsck run on fs). Orphans also include | 1209 | * is a valid orphan (no e2fsck run on fs). Orphans also include |
diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index c32802c956d5..bf7fa1507e81 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c | |||
@@ -561,10 +561,16 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, | |||
561 | unsigned epb = inode->i_sb->s_blocksize / sizeof(u32); | 561 | unsigned epb = inode->i_sb->s_blocksize / sizeof(u32); |
562 | int i; | 562 | int i; |
563 | 563 | ||
564 | /* Count number blocks in a subtree under 'partial' */ | 564 | /* |
565 | count = 1; | 565 | * Count number blocks in a subtree under 'partial'. At each |
566 | for (i = 0; partial + i != chain + depth - 1; i++) | 566 | * level we count number of complete empty subtrees beyond |
567 | count *= epb; | 567 | * current offset and then descend into the subtree only |
568 | * partially beyond current offset. | ||
569 | */ | ||
570 | count = 0; | ||
571 | for (i = partial - chain + 1; i < depth; i++) | ||
572 | count = count * epb + (epb - offsets[i] - 1); | ||
573 | count++; | ||
568 | /* Fill in size of a hole we found */ | 574 | /* Fill in size of a hole we found */ |
569 | map->m_pblk = 0; | 575 | map->m_pblk = 0; |
570 | map->m_len = min_t(unsigned int, map->m_len, count); | 576 | map->m_len = min_t(unsigned int, map->m_len, count); |
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 70cf4c7b268a..44b4fcdc3755 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c | |||
@@ -144,6 +144,12 @@ int ext4_find_inline_data_nolock(struct inode *inode) | |||
144 | goto out; | 144 | goto out; |
145 | 145 | ||
146 | if (!is.s.not_found) { | 146 | if (!is.s.not_found) { |
147 | if (is.s.here->e_value_inum) { | ||
148 | EXT4_ERROR_INODE(inode, "inline data xattr refers " | ||
149 | "to an external xattr inode"); | ||
150 | error = -EFSCORRUPTED; | ||
151 | goto out; | ||
152 | } | ||
147 | EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here - | 153 | EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here - |
148 | (void *)ext4_raw_inode(&is.iloc)); | 154 | (void *)ext4_raw_inode(&is.iloc)); |
149 | EXT4_I(inode)->i_inline_size = EXT4_MIN_INLINE_DATA_SIZE + | 155 | EXT4_I(inode)->i_inline_size = EXT4_MIN_INLINE_DATA_SIZE + |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 1e50c5efae67..2ea07efbe016 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -4298,28 +4298,28 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) | |||
4298 | EXT4_BLOCK_SIZE_BITS(sb); | 4298 | EXT4_BLOCK_SIZE_BITS(sb); |
4299 | stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb); | 4299 | stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb); |
4300 | 4300 | ||
4301 | /* If there are no blocks to remove, return now */ | 4301 | /* If there are blocks to remove, do it */ |
4302 | if (first_block >= stop_block) | 4302 | if (stop_block > first_block) { |
4303 | goto out_stop; | ||
4304 | 4303 | ||
4305 | down_write(&EXT4_I(inode)->i_data_sem); | 4304 | down_write(&EXT4_I(inode)->i_data_sem); |
4306 | ext4_discard_preallocations(inode); | 4305 | ext4_discard_preallocations(inode); |
4307 | 4306 | ||
4308 | ret = ext4_es_remove_extent(inode, first_block, | 4307 | ret = ext4_es_remove_extent(inode, first_block, |
4309 | stop_block - first_block); | 4308 | stop_block - first_block); |
4310 | if (ret) { | 4309 | if (ret) { |
4311 | up_write(&EXT4_I(inode)->i_data_sem); | 4310 | up_write(&EXT4_I(inode)->i_data_sem); |
4312 | goto out_stop; | 4311 | goto out_stop; |
4313 | } | 4312 | } |
4314 | 4313 | ||
4315 | if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) | 4314 | if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) |
4316 | ret = ext4_ext_remove_space(inode, first_block, | 4315 | ret = ext4_ext_remove_space(inode, first_block, |
4317 | stop_block - 1); | 4316 | stop_block - 1); |
4318 | else | 4317 | else |
4319 | ret = ext4_ind_remove_space(handle, inode, first_block, | 4318 | ret = ext4_ind_remove_space(handle, inode, first_block, |
4320 | stop_block); | 4319 | stop_block); |
4321 | 4320 | ||
4322 | up_write(&EXT4_I(inode)->i_data_sem); | 4321 | up_write(&EXT4_I(inode)->i_data_sem); |
4322 | } | ||
4323 | if (IS_SYNC(inode)) | 4323 | if (IS_SYNC(inode)) |
4324 | ext4_handle_sync(handle); | 4324 | ext4_handle_sync(handle); |
4325 | 4325 | ||
@@ -4701,19 +4701,21 @@ static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode, | |||
4701 | } | 4701 | } |
4702 | } | 4702 | } |
4703 | 4703 | ||
4704 | static inline void ext4_iget_extra_inode(struct inode *inode, | 4704 | static inline int ext4_iget_extra_inode(struct inode *inode, |
4705 | struct ext4_inode *raw_inode, | 4705 | struct ext4_inode *raw_inode, |
4706 | struct ext4_inode_info *ei) | 4706 | struct ext4_inode_info *ei) |
4707 | { | 4707 | { |
4708 | __le32 *magic = (void *)raw_inode + | 4708 | __le32 *magic = (void *)raw_inode + |
4709 | EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize; | 4709 | EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize; |
4710 | |||
4710 | if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize + sizeof(__le32) <= | 4711 | if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize + sizeof(__le32) <= |
4711 | EXT4_INODE_SIZE(inode->i_sb) && | 4712 | EXT4_INODE_SIZE(inode->i_sb) && |
4712 | *magic == cpu_to_le32(EXT4_XATTR_MAGIC)) { | 4713 | *magic == cpu_to_le32(EXT4_XATTR_MAGIC)) { |
4713 | ext4_set_inode_state(inode, EXT4_STATE_XATTR); | 4714 | ext4_set_inode_state(inode, EXT4_STATE_XATTR); |
4714 | ext4_find_inline_data_nolock(inode); | 4715 | return ext4_find_inline_data_nolock(inode); |
4715 | } else | 4716 | } else |
4716 | EXT4_I(inode)->i_inline_off = 0; | 4717 | EXT4_I(inode)->i_inline_off = 0; |
4718 | return 0; | ||
4717 | } | 4719 | } |
4718 | 4720 | ||
4719 | int ext4_get_projid(struct inode *inode, kprojid_t *projid) | 4721 | int ext4_get_projid(struct inode *inode, kprojid_t *projid) |
@@ -4724,6 +4726,26 @@ int ext4_get_projid(struct inode *inode, kprojid_t *projid) | |||
4724 | return 0; | 4726 | return 0; |
4725 | } | 4727 | } |
4726 | 4728 | ||
4729 | /* | ||
4730 | * ext4 has self-managed i_version for ea inodes, it stores the lower 32bit of | ||
4731 | * refcount in i_version, so use raw values if inode has EXT4_EA_INODE_FL flag | ||
4732 | * set. | ||
4733 | */ | ||
4734 | static inline void ext4_inode_set_iversion_queried(struct inode *inode, u64 val) | ||
4735 | { | ||
4736 | if (unlikely(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) | ||
4737 | inode_set_iversion_raw(inode, val); | ||
4738 | else | ||
4739 | inode_set_iversion_queried(inode, val); | ||
4740 | } | ||
4741 | static inline u64 ext4_inode_peek_iversion(const struct inode *inode) | ||
4742 | { | ||
4743 | if (unlikely(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) | ||
4744 | return inode_peek_iversion_raw(inode); | ||
4745 | else | ||
4746 | return inode_peek_iversion(inode); | ||
4747 | } | ||
4748 | |||
4727 | struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | 4749 | struct inode *ext4_iget(struct super_block *sb, unsigned long ino) |
4728 | { | 4750 | { |
4729 | struct ext4_iloc iloc; | 4751 | struct ext4_iloc iloc; |
@@ -4893,7 +4915,9 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4893 | ei->i_extra_isize = sizeof(struct ext4_inode) - | 4915 | ei->i_extra_isize = sizeof(struct ext4_inode) - |
4894 | EXT4_GOOD_OLD_INODE_SIZE; | 4916 | EXT4_GOOD_OLD_INODE_SIZE; |
4895 | } else { | 4917 | } else { |
4896 | ext4_iget_extra_inode(inode, raw_inode, ei); | 4918 | ret = ext4_iget_extra_inode(inode, raw_inode, ei); |
4919 | if (ret) | ||
4920 | goto bad_inode; | ||
4897 | } | 4921 | } |
4898 | } | 4922 | } |
4899 | 4923 | ||
@@ -4910,7 +4934,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4910 | ivers |= | 4934 | ivers |= |
4911 | (__u64)(le32_to_cpu(raw_inode->i_version_hi)) << 32; | 4935 | (__u64)(le32_to_cpu(raw_inode->i_version_hi)) << 32; |
4912 | } | 4936 | } |
4913 | inode_set_iversion_queried(inode, ivers); | 4937 | ext4_inode_set_iversion_queried(inode, ivers); |
4914 | } | 4938 | } |
4915 | 4939 | ||
4916 | ret = 0; | 4940 | ret = 0; |
@@ -4945,6 +4969,13 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4945 | inode->i_op = &ext4_dir_inode_operations; | 4969 | inode->i_op = &ext4_dir_inode_operations; |
4946 | inode->i_fop = &ext4_dir_operations; | 4970 | inode->i_fop = &ext4_dir_operations; |
4947 | } else if (S_ISLNK(inode->i_mode)) { | 4971 | } else if (S_ISLNK(inode->i_mode)) { |
4972 | /* VFS does not allow setting these so must be corruption */ | ||
4973 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) { | ||
4974 | EXT4_ERROR_INODE(inode, | ||
4975 | "immutable or append flags not allowed on symlinks"); | ||
4976 | ret = -EFSCORRUPTED; | ||
4977 | goto bad_inode; | ||
4978 | } | ||
4948 | if (ext4_encrypted_inode(inode)) { | 4979 | if (ext4_encrypted_inode(inode)) { |
4949 | inode->i_op = &ext4_encrypted_symlink_inode_operations; | 4980 | inode->i_op = &ext4_encrypted_symlink_inode_operations; |
4950 | ext4_set_aops(inode); | 4981 | ext4_set_aops(inode); |
@@ -5196,7 +5227,7 @@ static int ext4_do_update_inode(handle_t *handle, | |||
5196 | } | 5227 | } |
5197 | 5228 | ||
5198 | if (likely(!test_opt2(inode->i_sb, HURD_COMPAT))) { | 5229 | if (likely(!test_opt2(inode->i_sb, HURD_COMPAT))) { |
5199 | u64 ivers = inode_peek_iversion(inode); | 5230 | u64 ivers = ext4_inode_peek_iversion(inode); |
5200 | 5231 | ||
5201 | raw_inode->i_disk_version = cpu_to_le32(ivers); | 5232 | raw_inode->i_disk_version = cpu_to_le32(ivers); |
5202 | if (ei->i_extra_isize) { | 5233 | if (ei->i_extra_isize) { |
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 6884e81c1465..6eae2b91aafa 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -470,6 +470,8 @@ static void mb_free_blocks_double(struct inode *inode, struct ext4_buddy *e4b, | |||
470 | "freeing block already freed " | 470 | "freeing block already freed " |
471 | "(bit %u)", | 471 | "(bit %u)", |
472 | first + i); | 472 | first + i); |
473 | ext4_mark_group_bitmap_corrupted(sb, e4b->bd_group, | ||
474 | EXT4_GROUP_INFO_BBITMAP_CORRUPT); | ||
473 | } | 475 | } |
474 | mb_clear_bit(first + i, e4b->bd_info->bb_bitmap); | 476 | mb_clear_bit(first + i, e4b->bd_info->bb_bitmap); |
475 | } | 477 | } |
@@ -747,10 +749,8 @@ void ext4_mb_generate_buddy(struct super_block *sb, | |||
747 | * corrupt and update bb_free using bitmap value | 749 | * corrupt and update bb_free using bitmap value |
748 | */ | 750 | */ |
749 | grp->bb_free = free; | 751 | grp->bb_free = free; |
750 | if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) | 752 | ext4_mark_group_bitmap_corrupted(sb, group, |
751 | percpu_counter_sub(&sbi->s_freeclusters_counter, | 753 | EXT4_GROUP_INFO_BBITMAP_CORRUPT); |
752 | grp->bb_free); | ||
753 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); | ||
754 | } | 754 | } |
755 | mb_set_largest_free_order(sb, grp); | 755 | mb_set_largest_free_order(sb, grp); |
756 | 756 | ||
@@ -1454,12 +1454,8 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, | |||
1454 | "freeing already freed block " | 1454 | "freeing already freed block " |
1455 | "(bit %u); block bitmap corrupt.", | 1455 | "(bit %u); block bitmap corrupt.", |
1456 | block); | 1456 | block); |
1457 | if (!EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info)) | 1457 | ext4_mark_group_bitmap_corrupted(sb, e4b->bd_group, |
1458 | percpu_counter_sub(&sbi->s_freeclusters_counter, | 1458 | EXT4_GROUP_INFO_BBITMAP_CORRUPT); |
1459 | e4b->bd_info->bb_free); | ||
1460 | /* Mark the block group as corrupt. */ | ||
1461 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, | ||
1462 | &e4b->bd_info->bb_state); | ||
1463 | mb_regenerate_buddy(e4b); | 1459 | mb_regenerate_buddy(e4b); |
1464 | goto done; | 1460 | goto done; |
1465 | } | 1461 | } |
@@ -1956,6 +1952,8 @@ void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac, | |||
1956 | "%d free clusters as per " | 1952 | "%d free clusters as per " |
1957 | "group info. But bitmap says 0", | 1953 | "group info. But bitmap says 0", |
1958 | free); | 1954 | free); |
1955 | ext4_mark_group_bitmap_corrupted(sb, e4b->bd_group, | ||
1956 | EXT4_GROUP_INFO_BBITMAP_CORRUPT); | ||
1959 | break; | 1957 | break; |
1960 | } | 1958 | } |
1961 | 1959 | ||
@@ -1966,6 +1964,8 @@ void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac, | |||
1966 | "%d free clusters as per " | 1964 | "%d free clusters as per " |
1967 | "group info. But got %d blocks", | 1965 | "group info. But got %d blocks", |
1968 | free, ex.fe_len); | 1966 | free, ex.fe_len); |
1967 | ext4_mark_group_bitmap_corrupted(sb, e4b->bd_group, | ||
1968 | EXT4_GROUP_INFO_BBITMAP_CORRUPT); | ||
1969 | /* | 1969 | /* |
1970 | * The number of free blocks differs. This mostly | 1970 | * The number of free blocks differs. This mostly |
1971 | * indicate that the bitmap is corrupt. So exit | 1971 | * indicate that the bitmap is corrupt. So exit |
@@ -2516,8 +2516,7 @@ static void ext4_groupinfo_destroy_slabs(void) | |||
2516 | int i; | 2516 | int i; |
2517 | 2517 | ||
2518 | for (i = 0; i < NR_GRPINFO_CACHES; i++) { | 2518 | for (i = 0; i < NR_GRPINFO_CACHES; i++) { |
2519 | if (ext4_groupinfo_caches[i]) | 2519 | kmem_cache_destroy(ext4_groupinfo_caches[i]); |
2520 | kmem_cache_destroy(ext4_groupinfo_caches[i]); | ||
2521 | ext4_groupinfo_caches[i] = NULL; | 2520 | ext4_groupinfo_caches[i] = NULL; |
2522 | } | 2521 | } |
2523 | } | 2522 | } |
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index b6bec270a8e4..d792b7689d92 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c | |||
@@ -1933,7 +1933,7 @@ retry: | |||
1933 | return 0; | 1933 | return 0; |
1934 | 1934 | ||
1935 | n_group = ext4_get_group_number(sb, n_blocks_count - 1); | 1935 | n_group = ext4_get_group_number(sb, n_blocks_count - 1); |
1936 | if (n_group > (0xFFFFFFFFUL / EXT4_INODES_PER_GROUP(sb))) { | 1936 | if (n_group >= (0xFFFFFFFFUL / EXT4_INODES_PER_GROUP(sb))) { |
1937 | ext4_warning(sb, "resize would cause inodes_count overflow"); | 1937 | ext4_warning(sb, "resize would cause inodes_count overflow"); |
1938 | return -EINVAL; | 1938 | return -EINVAL; |
1939 | } | 1939 | } |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index eb104e8476f0..c1c5c8775ae7 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -763,6 +763,36 @@ __acquires(bitlock) | |||
763 | return; | 763 | return; |
764 | } | 764 | } |
765 | 765 | ||
766 | void ext4_mark_group_bitmap_corrupted(struct super_block *sb, | ||
767 | ext4_group_t group, | ||
768 | unsigned int flags) | ||
769 | { | ||
770 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
771 | struct ext4_group_info *grp = ext4_get_group_info(sb, group); | ||
772 | struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL); | ||
773 | |||
774 | if ((flags & EXT4_GROUP_INFO_BBITMAP_CORRUPT) && | ||
775 | !EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) { | ||
776 | percpu_counter_sub(&sbi->s_freeclusters_counter, | ||
777 | grp->bb_free); | ||
778 | set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, | ||
779 | &grp->bb_state); | ||
780 | } | ||
781 | |||
782 | if ((flags & EXT4_GROUP_INFO_IBITMAP_CORRUPT) && | ||
783 | !EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { | ||
784 | if (gdp) { | ||
785 | int count; | ||
786 | |||
787 | count = ext4_free_inodes_count(sb, gdp); | ||
788 | percpu_counter_sub(&sbi->s_freeinodes_counter, | ||
789 | count); | ||
790 | } | ||
791 | set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, | ||
792 | &grp->bb_state); | ||
793 | } | ||
794 | } | ||
795 | |||
766 | void ext4_update_dynamic_rev(struct super_block *sb) | 796 | void ext4_update_dynamic_rev(struct super_block *sb) |
767 | { | 797 | { |
768 | struct ext4_super_block *es = EXT4_SB(sb)->s_es; | 798 | struct ext4_super_block *es = EXT4_SB(sb)->s_es; |
@@ -2116,12 +2146,12 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, | |||
2116 | int read_only) | 2146 | int read_only) |
2117 | { | 2147 | { |
2118 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 2148 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
2119 | int res = 0; | 2149 | int err = 0; |
2120 | 2150 | ||
2121 | if (le32_to_cpu(es->s_rev_level) > EXT4_MAX_SUPP_REV) { | 2151 | if (le32_to_cpu(es->s_rev_level) > EXT4_MAX_SUPP_REV) { |
2122 | ext4_msg(sb, KERN_ERR, "revision level too high, " | 2152 | ext4_msg(sb, KERN_ERR, "revision level too high, " |
2123 | "forcing read-only mode"); | 2153 | "forcing read-only mode"); |
2124 | res = SB_RDONLY; | 2154 | err = -EROFS; |
2125 | } | 2155 | } |
2126 | if (read_only) | 2156 | if (read_only) |
2127 | goto done; | 2157 | goto done; |
@@ -2154,7 +2184,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, | |||
2154 | if (sbi->s_journal) | 2184 | if (sbi->s_journal) |
2155 | ext4_set_feature_journal_needs_recovery(sb); | 2185 | ext4_set_feature_journal_needs_recovery(sb); |
2156 | 2186 | ||
2157 | ext4_commit_super(sb, 1); | 2187 | err = ext4_commit_super(sb, 1); |
2158 | done: | 2188 | done: |
2159 | if (test_opt(sb, DEBUG)) | 2189 | if (test_opt(sb, DEBUG)) |
2160 | printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%u, " | 2190 | printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%u, " |
@@ -2166,7 +2196,7 @@ done: | |||
2166 | sbi->s_mount_opt, sbi->s_mount_opt2); | 2196 | sbi->s_mount_opt, sbi->s_mount_opt2); |
2167 | 2197 | ||
2168 | cleancache_init_fs(sb); | 2198 | cleancache_init_fs(sb); |
2169 | return res; | 2199 | return err; |
2170 | } | 2200 | } |
2171 | 2201 | ||
2172 | int ext4_alloc_flex_bg_array(struct super_block *sb, ext4_group_t ngroup) | 2202 | int ext4_alloc_flex_bg_array(struct super_block *sb, ext4_group_t ngroup) |
@@ -4224,8 +4254,12 @@ no_journal: | |||
4224 | goto failed_mount4; | 4254 | goto failed_mount4; |
4225 | } | 4255 | } |
4226 | 4256 | ||
4227 | if (ext4_setup_super(sb, es, sb_rdonly(sb))) | 4257 | ret = ext4_setup_super(sb, es, sb_rdonly(sb)); |
4258 | if (ret == -EROFS) { | ||
4228 | sb->s_flags |= SB_RDONLY; | 4259 | sb->s_flags |= SB_RDONLY; |
4260 | ret = 0; | ||
4261 | } else if (ret) | ||
4262 | goto failed_mount4a; | ||
4229 | 4263 | ||
4230 | /* determine the minimum size of new large inodes, if present */ | 4264 | /* determine the minimum size of new large inodes, if present */ |
4231 | if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE && | 4265 | if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE && |
@@ -4760,11 +4794,7 @@ static int ext4_commit_super(struct super_block *sb, int sync) | |||
4760 | unlock_buffer(sbh); | 4794 | unlock_buffer(sbh); |
4761 | error = __sync_dirty_buffer(sbh, | 4795 | error = __sync_dirty_buffer(sbh, |
4762 | REQ_SYNC | (test_opt(sb, BARRIER) ? REQ_FUA : 0)); | 4796 | REQ_SYNC | (test_opt(sb, BARRIER) ? REQ_FUA : 0)); |
4763 | if (error) | 4797 | if (buffer_write_io_error(sbh)) { |
4764 | return error; | ||
4765 | |||
4766 | error = buffer_write_io_error(sbh); | ||
4767 | if (error) { | ||
4768 | ext4_msg(sb, KERN_ERR, "I/O error while writing " | 4798 | ext4_msg(sb, KERN_ERR, "I/O error while writing " |
4769 | "superblock"); | 4799 | "superblock"); |
4770 | clear_buffer_write_io_error(sbh); | 4800 | clear_buffer_write_io_error(sbh); |
@@ -5165,8 +5195,12 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) | |||
5165 | if (sbi->s_journal) | 5195 | if (sbi->s_journal) |
5166 | ext4_clear_journal_err(sb, es); | 5196 | ext4_clear_journal_err(sb, es); |
5167 | sbi->s_mount_state = le16_to_cpu(es->s_state); | 5197 | sbi->s_mount_state = le16_to_cpu(es->s_state); |
5168 | if (!ext4_setup_super(sb, es, 0)) | 5198 | |
5169 | sb->s_flags &= ~SB_RDONLY; | 5199 | err = ext4_setup_super(sb, es, 0); |
5200 | if (err) | ||
5201 | goto restore_opts; | ||
5202 | |||
5203 | sb->s_flags &= ~SB_RDONLY; | ||
5170 | if (ext4_has_feature_mmp(sb)) | 5204 | if (ext4_has_feature_mmp(sb)) |
5171 | if (ext4_multi_mount_protect(sb, | 5205 | if (ext4_multi_mount_protect(sb, |
5172 | le64_to_cpu(es->s_mmp_block))) { | 5206 | le64_to_cpu(es->s_mmp_block))) { |
@@ -5190,8 +5224,11 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) | |||
5190 | } | 5224 | } |
5191 | 5225 | ||
5192 | ext4_setup_system_zone(sb); | 5226 | ext4_setup_system_zone(sb); |
5193 | if (sbi->s_journal == NULL && !(old_sb_flags & SB_RDONLY)) | 5227 | if (sbi->s_journal == NULL && !(old_sb_flags & SB_RDONLY)) { |
5194 | ext4_commit_super(sb, 1); | 5228 | err = ext4_commit_super(sb, 1); |
5229 | if (err) | ||
5230 | goto restore_opts; | ||
5231 | } | ||
5195 | 5232 | ||
5196 | #ifdef CONFIG_QUOTA | 5233 | #ifdef CONFIG_QUOTA |
5197 | /* Release old quota file names */ | 5234 | /* Release old quota file names */ |
@@ -5252,7 +5289,8 @@ static int ext4_statfs_project(struct super_block *sb, | |||
5252 | dquot->dq_dqb.dqb_bsoftlimit : | 5289 | dquot->dq_dqb.dqb_bsoftlimit : |
5253 | dquot->dq_dqb.dqb_bhardlimit) >> sb->s_blocksize_bits; | 5290 | dquot->dq_dqb.dqb_bhardlimit) >> sb->s_blocksize_bits; |
5254 | if (limit && buf->f_blocks > limit) { | 5291 | if (limit && buf->f_blocks > limit) { |
5255 | curblock = dquot->dq_dqb.dqb_curspace >> sb->s_blocksize_bits; | 5292 | curblock = (dquot->dq_dqb.dqb_curspace + |
5293 | dquot->dq_dqb.dqb_rsvspace) >> sb->s_blocksize_bits; | ||
5256 | buf->f_blocks = limit; | 5294 | buf->f_blocks = limit; |
5257 | buf->f_bfree = buf->f_bavail = | 5295 | buf->f_bfree = buf->f_bavail = |
5258 | (buf->f_blocks > curblock) ? | 5296 | (buf->f_blocks > curblock) ? |
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 499cb4b1fbd2..fc4ced59c565 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
@@ -1688,7 +1688,7 @@ static int ext4_xattr_set_entry(struct ext4_xattr_info *i, | |||
1688 | 1688 | ||
1689 | /* No failures allowed past this point. */ | 1689 | /* No failures allowed past this point. */ |
1690 | 1690 | ||
1691 | if (!s->not_found && here->e_value_offs) { | 1691 | if (!s->not_found && here->e_value_size && here->e_value_offs) { |
1692 | /* Remove the old value. */ | 1692 | /* Remove the old value. */ |
1693 | void *first_val = s->base + min_offs; | 1693 | void *first_val = s->base + min_offs; |
1694 | size_t offs = le16_to_cpu(here->e_value_offs); | 1694 | size_t offs = le16_to_cpu(here->e_value_offs); |
diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c index 629001b28632..197a9d8a15ef 100644 --- a/fs/ext4/xattr_security.c +++ b/fs/ext4/xattr_security.c | |||
@@ -43,7 +43,7 @@ ext4_initxattrs(struct inode *inode, const struct xattr *xattr_array, | |||
43 | err = ext4_xattr_set_handle(handle, inode, | 43 | err = ext4_xattr_set_handle(handle, inode, |
44 | EXT4_XATTR_INDEX_SECURITY, | 44 | EXT4_XATTR_INDEX_SECURITY, |
45 | xattr->name, xattr->value, | 45 | xattr->name, xattr->value, |
46 | xattr->value_len, 0); | 46 | xattr->value_len, XATTR_CREATE); |
47 | if (err < 0) | 47 | if (err < 0) |
48 | break; | 48 | break; |
49 | } | 49 | } |
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index dfb057900e79..8ef6b6daaa7a 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c | |||
@@ -114,7 +114,7 @@ void __jbd2_debug(int level, const char *file, const char *func, | |||
114 | va_start(args, fmt); | 114 | va_start(args, fmt); |
115 | vaf.fmt = fmt; | 115 | vaf.fmt = fmt; |
116 | vaf.va = &args; | 116 | vaf.va = &args; |
117 | printk(KERN_DEBUG "%s: (%s, %u): %pV\n", file, func, line, &vaf); | 117 | printk(KERN_DEBUG "%s: (%s, %u): %pV", file, func, line, &vaf); |
118 | va_end(args); | 118 | va_end(args); |
119 | } | 119 | } |
120 | EXPORT_SYMBOL(__jbd2_debug); | 120 | EXPORT_SYMBOL(__jbd2_debug); |
@@ -2302,8 +2302,7 @@ static void jbd2_journal_destroy_slabs(void) | |||
2302 | int i; | 2302 | int i; |
2303 | 2303 | ||
2304 | for (i = 0; i < JBD2_MAX_SLABS; i++) { | 2304 | for (i = 0; i < JBD2_MAX_SLABS; i++) { |
2305 | if (jbd2_slab[i]) | 2305 | kmem_cache_destroy(jbd2_slab[i]); |
2306 | kmem_cache_destroy(jbd2_slab[i]); | ||
2307 | jbd2_slab[i] = NULL; | 2306 | jbd2_slab[i] = NULL; |
2308 | } | 2307 | } |
2309 | } | 2308 | } |
@@ -2404,10 +2403,8 @@ static int jbd2_journal_init_journal_head_cache(void) | |||
2404 | 2403 | ||
2405 | static void jbd2_journal_destroy_journal_head_cache(void) | 2404 | static void jbd2_journal_destroy_journal_head_cache(void) |
2406 | { | 2405 | { |
2407 | if (jbd2_journal_head_cache) { | 2406 | kmem_cache_destroy(jbd2_journal_head_cache); |
2408 | kmem_cache_destroy(jbd2_journal_head_cache); | 2407 | jbd2_journal_head_cache = NULL; |
2409 | jbd2_journal_head_cache = NULL; | ||
2410 | } | ||
2411 | } | 2408 | } |
2412 | 2409 | ||
2413 | /* | 2410 | /* |
@@ -2665,11 +2662,10 @@ static int __init jbd2_journal_init_handle_cache(void) | |||
2665 | 2662 | ||
2666 | static void jbd2_journal_destroy_handle_cache(void) | 2663 | static void jbd2_journal_destroy_handle_cache(void) |
2667 | { | 2664 | { |
2668 | if (jbd2_handle_cache) | 2665 | kmem_cache_destroy(jbd2_handle_cache); |
2669 | kmem_cache_destroy(jbd2_handle_cache); | 2666 | jbd2_handle_cache = NULL; |
2670 | if (jbd2_inode_cache) | 2667 | kmem_cache_destroy(jbd2_inode_cache); |
2671 | kmem_cache_destroy(jbd2_inode_cache); | 2668 | jbd2_inode_cache = NULL; |
2672 | |||
2673 | } | 2669 | } |
2674 | 2670 | ||
2675 | /* | 2671 | /* |
diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index 696ef15ec942..240779e4689c 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c | |||
@@ -180,14 +180,10 @@ static struct jbd2_revoke_record_s *find_revoke_record(journal_t *journal, | |||
180 | 180 | ||
181 | void jbd2_journal_destroy_revoke_caches(void) | 181 | void jbd2_journal_destroy_revoke_caches(void) |
182 | { | 182 | { |
183 | if (jbd2_revoke_record_cache) { | 183 | kmem_cache_destroy(jbd2_revoke_record_cache); |
184 | kmem_cache_destroy(jbd2_revoke_record_cache); | 184 | jbd2_revoke_record_cache = NULL; |
185 | jbd2_revoke_record_cache = NULL; | 185 | kmem_cache_destroy(jbd2_revoke_table_cache); |
186 | } | 186 | jbd2_revoke_table_cache = NULL; |
187 | if (jbd2_revoke_table_cache) { | ||
188 | kmem_cache_destroy(jbd2_revoke_table_cache); | ||
189 | jbd2_revoke_table_cache = NULL; | ||
190 | } | ||
191 | } | 187 | } |
192 | 188 | ||
193 | int __init jbd2_journal_init_revoke_caches(void) | 189 | int __init jbd2_journal_init_revoke_caches(void) |
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 8aa453784402..51dd68e67b0f 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
@@ -49,10 +49,8 @@ int __init jbd2_journal_init_transaction_cache(void) | |||
49 | 49 | ||
50 | void jbd2_journal_destroy_transaction_cache(void) | 50 | void jbd2_journal_destroy_transaction_cache(void) |
51 | { | 51 | { |
52 | if (transaction_cache) { | 52 | kmem_cache_destroy(transaction_cache); |
53 | kmem_cache_destroy(transaction_cache); | 53 | transaction_cache = NULL; |
54 | transaction_cache = NULL; | ||
55 | } | ||
56 | } | 54 | } |
57 | 55 | ||
58 | void jbd2_journal_free_transaction(transaction_t *transaction) | 56 | void jbd2_journal_free_transaction(transaction_t *transaction) |
diff --git a/include/linux/fs.h b/include/linux/fs.h index d4c37d371da5..f4b8c8dc67e3 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1597,6 +1597,11 @@ static inline void sb_start_intwrite(struct super_block *sb) | |||
1597 | __sb_start_write(sb, SB_FREEZE_FS, true); | 1597 | __sb_start_write(sb, SB_FREEZE_FS, true); |
1598 | } | 1598 | } |
1599 | 1599 | ||
1600 | static inline int sb_start_intwrite_trylock(struct super_block *sb) | ||
1601 | { | ||
1602 | return __sb_start_write(sb, SB_FREEZE_FS, false); | ||
1603 | } | ||
1604 | |||
1600 | 1605 | ||
1601 | extern bool inode_owner_or_capable(const struct inode *inode); | 1606 | extern bool inode_owner_or_capable(const struct inode *inode); |
1602 | 1607 | ||