Skip to content

Commit 19bf1c2

Browse files
committed
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()
2 parents 3be542d + 63b9996 commit 19bf1c2

File tree

3 files changed

+60
-21
lines changed

3 files changed

+60
-21
lines changed

fs/ext4/extents.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2835,6 +2835,9 @@ int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
28352835
err = -EIO;
28362836
break;
28372837
}
2838+
/* Yield here to deal with large extent trees.
2839+
* Should be a no-op if we did IO above. */
2840+
cond_resched();
28382841
if (WARN_ON(i + 1 > depth)) {
28392842
err = -EIO;
28402843
break;
@@ -4261,8 +4264,8 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
42614264
/* not a good idea to call discard here directly,
42624265
* but otherwise we'd need to call it every free() */
42634266
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);
42664269
goto out2;
42674270
}
42684271

@@ -4382,8 +4385,9 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
43824385
}
43834386

43844387
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);
43874391
return err ? err : allocated;
43884392
}
43894393

@@ -4405,9 +4409,20 @@ void ext4_ext_truncate(handle_t *handle, struct inode *inode)
44054409

44064410
last_block = (inode->i_size + sb->s_blocksize - 1)
44074411
>> EXT4_BLOCK_SIZE_BITS(sb);
4412+
retry:
44084413
err = ext4_es_remove_extent(inode, last_block,
44094414
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+
}
44104424
err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1);
4425+
ext4_std_error(inode->i_sb, err);
44114426
}
44124427

44134428
static void ext4_falloc_update_inode(struct inode *inode,

fs/ext4/extents_status.c

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk,
148148
ext4_lblk_t end);
149149
static int __es_try_to_reclaim_extents(struct ext4_inode_info *ei,
150150
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);
151153

152154
int __init ext4_init_es(void)
153155
{
@@ -665,7 +667,13 @@ int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk,
665667
err = __es_remove_extent(inode, lblk, end);
666668
if (err != 0)
667669
goto error;
670+
retry:
668671
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;
669677

670678
error:
671679
write_unlock(&EXT4_I(inode)->i_es_lock);
@@ -744,8 +752,10 @@ static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk,
744752
struct extent_status orig_es;
745753
ext4_lblk_t len1, len2;
746754
ext4_fsblk_t block;
747-
int err = 0;
755+
int err;
748756

757+
retry:
758+
err = 0;
749759
es = __es_tree_search(&tree->root, lblk);
750760
if (!es)
751761
goto out;
@@ -780,6 +790,10 @@ static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk,
780790
if (err) {
781791
es->es_lblk = orig_es.es_lblk;
782792
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;
783797
goto out;
784798
}
785799
} else {
@@ -889,22 +903,14 @@ static int ext4_inode_touch_time_cmp(void *priv, struct list_head *a,
889903
return -1;
890904
}
891905

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)
893908
{
894-
struct ext4_sb_info *sbi = container_of(shrink,
895-
struct ext4_sb_info, s_es_shrinker);
896909
struct ext4_inode_info *ei;
897910
struct list_head *cur, *tmp;
898911
LIST_HEAD(skiped);
899-
int nr_to_scan = sc->nr_to_scan;
900912
int ret, nr_shrunk = 0;
901913

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-
908914
spin_lock(&sbi->s_es_lru_lock);
909915

910916
/*
@@ -933,7 +939,7 @@ static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc)
933939
continue;
934940
}
935941

936-
if (ei->i_es_lru_nr == 0)
942+
if (ei->i_es_lru_nr == 0 || ei == locked_ei)
937943
continue;
938944

939945
write_lock(&ei->i_es_lock);
@@ -952,6 +958,27 @@ static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc)
952958
list_splice_tail(&skiped, &sbi->s_es_lru);
953959
spin_unlock(&sbi->s_es_lru_lock);
954960

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);
981+
955982
ret = percpu_counter_read_positive(&sbi->s_extent_cache_cnt);
956983
trace_ext4_es_shrink_exit(sbi->s_sb, nr_shrunk, ret);
957984
return ret;

fs/ext4/inode.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -514,10 +514,9 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
514514
"logical block %lu\n", inode->i_ino, flags, map->m_len,
515515
(unsigned long) map->m_lblk);
516516

517-
ext4_es_lru_add(inode);
518-
519517
/* Lookup extent status tree firstly */
520518
if (ext4_es_lookup_extent(inode, map->m_lblk, &es)) {
519+
ext4_es_lru_add(inode);
521520
if (ext4_es_is_written(&es) || ext4_es_is_unwritten(&es)) {
522521
map->m_pblk = ext4_es_pblock(&es) +
523522
map->m_lblk - es.es_lblk;
@@ -1529,11 +1528,9 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
15291528
"logical block %lu\n", inode->i_ino, map->m_len,
15301529
(unsigned long) map->m_lblk);
15311530

1532-
ext4_es_lru_add(inode);
1533-
15341531
/* Lookup extent status tree firstly */
15351532
if (ext4_es_lookup_extent(inode, iblock, &es)) {
1536-
1533+
ext4_es_lru_add(inode);
15371534
if (ext4_es_is_hole(&es)) {
15381535
retval = 0;
15391536
down_read((&EXT4_I(inode)->i_data_sem));

0 commit comments

Comments
 (0)