Commit 19bf1c2c7b9f21b9fe86315c5758d26c3049c2ad
Exists in
master
and in
20 other branches
Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 bugfixes from Ted Ts'o: "Fixes for 3.11-rc2, sent at 5pm, in the professoinal style. :-)" I'm not sure I like this new level of "professionalism". 9-5, people, 9-5. * tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: ext4: call ext4_es_lru_add() after handling cache miss ext4: yield during large unlinks ext4: make the extent_status code more robust against ENOMEM failures ext4: simplify calculation of blocks to free on error ext4: fix error handling in ext4_ext_truncate()
Showing 3 changed files Side-by-side Diff
fs/ext4/extents.c
... | ... | @@ -2835,6 +2835,9 @@ |
2835 | 2835 | err = -EIO; |
2836 | 2836 | break; |
2837 | 2837 | } |
2838 | + /* Yield here to deal with large extent trees. | |
2839 | + * Should be a no-op if we did IO above. */ | |
2840 | + cond_resched(); | |
2838 | 2841 | if (WARN_ON(i + 1 > depth)) { |
2839 | 2842 | err = -EIO; |
2840 | 2843 | break; |
... | ... | @@ -4261,8 +4264,8 @@ |
4261 | 4264 | /* not a good idea to call discard here directly, |
4262 | 4265 | * but otherwise we'd need to call it every free() */ |
4263 | 4266 | ext4_discard_preallocations(inode); |
4264 | - ext4_free_blocks(handle, inode, NULL, ext4_ext_pblock(&newex), | |
4265 | - ext4_ext_get_actual_len(&newex), fb_flags); | |
4267 | + ext4_free_blocks(handle, inode, NULL, newblock, | |
4268 | + EXT4_C2B(sbi, allocated_clusters), fb_flags); | |
4266 | 4269 | goto out2; |
4267 | 4270 | } |
4268 | 4271 | |
... | ... | @@ -4382,8 +4385,9 @@ |
4382 | 4385 | } |
4383 | 4386 | |
4384 | 4387 | out3: |
4385 | - trace_ext4_ext_map_blocks_exit(inode, flags, map, err ? err : allocated); | |
4386 | - | |
4388 | + trace_ext4_ext_map_blocks_exit(inode, flags, map, | |
4389 | + err ? err : allocated); | |
4390 | + ext4_es_lru_add(inode); | |
4387 | 4391 | return err ? err : allocated; |
4388 | 4392 | } |
4389 | 4393 | |
4390 | 4394 | |
4391 | 4395 | |
... | ... | @@ -4405,9 +4409,20 @@ |
4405 | 4409 | |
4406 | 4410 | last_block = (inode->i_size + sb->s_blocksize - 1) |
4407 | 4411 | >> EXT4_BLOCK_SIZE_BITS(sb); |
4412 | +retry: | |
4408 | 4413 | err = ext4_es_remove_extent(inode, last_block, |
4409 | 4414 | EXT_MAX_BLOCKS - last_block); |
4415 | + if (err == ENOMEM) { | |
4416 | + cond_resched(); | |
4417 | + congestion_wait(BLK_RW_ASYNC, HZ/50); | |
4418 | + goto retry; | |
4419 | + } | |
4420 | + if (err) { | |
4421 | + ext4_std_error(inode->i_sb, err); | |
4422 | + return; | |
4423 | + } | |
4410 | 4424 | err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1); |
4425 | + ext4_std_error(inode->i_sb, err); | |
4411 | 4426 | } |
4412 | 4427 | |
4413 | 4428 | static void ext4_falloc_update_inode(struct inode *inode, |
fs/ext4/extents_status.c
... | ... | @@ -148,6 +148,8 @@ |
148 | 148 | ext4_lblk_t end); |
149 | 149 | static int __es_try_to_reclaim_extents(struct ext4_inode_info *ei, |
150 | 150 | int nr_to_scan); |
151 | +static int __ext4_es_shrink(struct ext4_sb_info *sbi, int nr_to_scan, | |
152 | + struct ext4_inode_info *locked_ei); | |
151 | 153 | |
152 | 154 | int __init ext4_init_es(void) |
153 | 155 | { |
154 | 156 | |
... | ... | @@ -665,7 +667,13 @@ |
665 | 667 | err = __es_remove_extent(inode, lblk, end); |
666 | 668 | if (err != 0) |
667 | 669 | goto error; |
670 | +retry: | |
668 | 671 | err = __es_insert_extent(inode, &newes); |
672 | + if (err == -ENOMEM && __ext4_es_shrink(EXT4_SB(inode->i_sb), 1, | |
673 | + EXT4_I(inode))) | |
674 | + goto retry; | |
675 | + if (err == -ENOMEM && !ext4_es_is_delayed(&newes)) | |
676 | + err = 0; | |
669 | 677 | |
670 | 678 | error: |
671 | 679 | write_unlock(&EXT4_I(inode)->i_es_lock); |
672 | 680 | |
... | ... | @@ -744,8 +752,10 @@ |
744 | 752 | struct extent_status orig_es; |
745 | 753 | ext4_lblk_t len1, len2; |
746 | 754 | ext4_fsblk_t block; |
747 | - int err = 0; | |
755 | + int err; | |
748 | 756 | |
757 | +retry: | |
758 | + err = 0; | |
749 | 759 | es = __es_tree_search(&tree->root, lblk); |
750 | 760 | if (!es) |
751 | 761 | goto out; |
... | ... | @@ -780,6 +790,10 @@ |
780 | 790 | if (err) { |
781 | 791 | es->es_lblk = orig_es.es_lblk; |
782 | 792 | es->es_len = orig_es.es_len; |
793 | + if ((err == -ENOMEM) && | |
794 | + __ext4_es_shrink(EXT4_SB(inode->i_sb), 1, | |
795 | + EXT4_I(inode))) | |
796 | + goto retry; | |
783 | 797 | goto out; |
784 | 798 | } |
785 | 799 | } else { |
786 | 800 | |
787 | 801 | |
788 | 802 | |
... | ... | @@ -889,22 +903,14 @@ |
889 | 903 | return -1; |
890 | 904 | } |
891 | 905 | |
892 | -static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc) | |
906 | +static int __ext4_es_shrink(struct ext4_sb_info *sbi, int nr_to_scan, | |
907 | + struct ext4_inode_info *locked_ei) | |
893 | 908 | { |
894 | - struct ext4_sb_info *sbi = container_of(shrink, | |
895 | - struct ext4_sb_info, s_es_shrinker); | |
896 | 909 | struct ext4_inode_info *ei; |
897 | 910 | struct list_head *cur, *tmp; |
898 | 911 | LIST_HEAD(skiped); |
899 | - int nr_to_scan = sc->nr_to_scan; | |
900 | 912 | int ret, nr_shrunk = 0; |
901 | 913 | |
902 | - ret = percpu_counter_read_positive(&sbi->s_extent_cache_cnt); | |
903 | - trace_ext4_es_shrink_enter(sbi->s_sb, nr_to_scan, ret); | |
904 | - | |
905 | - if (!nr_to_scan) | |
906 | - return ret; | |
907 | - | |
908 | 914 | spin_lock(&sbi->s_es_lru_lock); |
909 | 915 | |
910 | 916 | /* |
... | ... | @@ -933,7 +939,7 @@ |
933 | 939 | continue; |
934 | 940 | } |
935 | 941 | |
936 | - if (ei->i_es_lru_nr == 0) | |
942 | + if (ei->i_es_lru_nr == 0 || ei == locked_ei) | |
937 | 943 | continue; |
938 | 944 | |
939 | 945 | write_lock(&ei->i_es_lock); |
... | ... | @@ -951,6 +957,27 @@ |
951 | 957 | /* Move the newer inodes into the tail of the LRU list. */ |
952 | 958 | list_splice_tail(&skiped, &sbi->s_es_lru); |
953 | 959 | spin_unlock(&sbi->s_es_lru_lock); |
960 | + | |
961 | + if (locked_ei && nr_shrunk == 0) | |
962 | + nr_shrunk = __es_try_to_reclaim_extents(ei, nr_to_scan); | |
963 | + | |
964 | + return nr_shrunk; | |
965 | +} | |
966 | + | |
967 | +static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc) | |
968 | +{ | |
969 | + struct ext4_sb_info *sbi = container_of(shrink, | |
970 | + struct ext4_sb_info, s_es_shrinker); | |
971 | + int nr_to_scan = sc->nr_to_scan; | |
972 | + int ret, nr_shrunk; | |
973 | + | |
974 | + ret = percpu_counter_read_positive(&sbi->s_extent_cache_cnt); | |
975 | + trace_ext4_es_shrink_enter(sbi->s_sb, nr_to_scan, ret); | |
976 | + | |
977 | + if (!nr_to_scan) | |
978 | + return ret; | |
979 | + | |
980 | + nr_shrunk = __ext4_es_shrink(sbi, nr_to_scan, NULL); | |
954 | 981 | |
955 | 982 | ret = percpu_counter_read_positive(&sbi->s_extent_cache_cnt); |
956 | 983 | trace_ext4_es_shrink_exit(sbi->s_sb, nr_shrunk, ret); |
fs/ext4/inode.c
... | ... | @@ -514,10 +514,9 @@ |
514 | 514 | "logical block %lu\n", inode->i_ino, flags, map->m_len, |
515 | 515 | (unsigned long) map->m_lblk); |
516 | 516 | |
517 | - ext4_es_lru_add(inode); | |
518 | - | |
519 | 517 | /* Lookup extent status tree firstly */ |
520 | 518 | if (ext4_es_lookup_extent(inode, map->m_lblk, &es)) { |
519 | + ext4_es_lru_add(inode); | |
521 | 520 | if (ext4_es_is_written(&es) || ext4_es_is_unwritten(&es)) { |
522 | 521 | map->m_pblk = ext4_es_pblock(&es) + |
523 | 522 | map->m_lblk - es.es_lblk; |
524 | 523 | |
... | ... | @@ -1529,11 +1528,9 @@ |
1529 | 1528 | "logical block %lu\n", inode->i_ino, map->m_len, |
1530 | 1529 | (unsigned long) map->m_lblk); |
1531 | 1530 | |
1532 | - ext4_es_lru_add(inode); | |
1533 | - | |
1534 | 1531 | /* Lookup extent status tree firstly */ |
1535 | 1532 | if (ext4_es_lookup_extent(inode, iblock, &es)) { |
1536 | - | |
1533 | + ext4_es_lru_add(inode); | |
1537 | 1534 | if (ext4_es_is_hole(&es)) { |
1538 | 1535 | retval = 0; |
1539 | 1536 | down_read((&EXT4_I(inode)->i_data_sem)); |