From: Ingo Molnar The attached patch fixes long scheduling latencies in the ext3 code, and it also cleans up the existing lock-break functionality to use the new primitives. This patch has been in the -VP patchset for quite some time. Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton --- 25-akpm/fs/ext3/balloc.c | 5 +++++ 25-akpm/fs/ext3/ialloc.c | 1 + 25-akpm/fs/ext3/namei.c | 1 + 25-akpm/fs/ext3/super.c | 8 +++++++- 25-akpm/fs/jbd/checkpoint.c | 12 ++++++++++++ 25-akpm/fs/jbd/commit.c | 17 ++++++++++------- 25-akpm/fs/jbd/recovery.c | 2 ++ 7 files changed, 38 insertions(+), 8 deletions(-) diff -puN fs/ext3/balloc.c~sched-ext3-fix-scheduling-latencies-in-ext3 fs/ext3/balloc.c --- 25/fs/ext3/balloc.c~sched-ext3-fix-scheduling-latencies-in-ext3 2004-12-03 20:56:34.947447368 -0800 +++ 25-akpm/fs/ext3/balloc.c 2004-12-03 20:56:34.960445392 -0800 @@ -378,6 +378,11 @@ do_more: } jbd_lock_bh_state(bitmap_bh); #endif + if (need_resched()) { + jbd_unlock_bh_state(bitmap_bh); + cond_resched(); + jbd_lock_bh_state(bitmap_bh); + } /* @@@ This prevents newly-allocated data from being * freed and then reallocated within the same * transaction. diff -puN fs/ext3/ialloc.c~sched-ext3-fix-scheduling-latencies-in-ext3 fs/ext3/ialloc.c --- 25/fs/ext3/ialloc.c~sched-ext3-fix-scheduling-latencies-in-ext3 2004-12-03 20:56:34.948447216 -0800 +++ 25-akpm/fs/ext3/ialloc.c 2004-12-03 20:56:34.961445240 -0800 @@ -737,6 +737,7 @@ unsigned long ext3_count_free_inodes (st if (!gdp) continue; desc_count += le16_to_cpu(gdp->bg_free_inodes_count); + cond_resched(); } return desc_count; #endif diff -puN fs/ext3/namei.c~sched-ext3-fix-scheduling-latencies-in-ext3 fs/ext3/namei.c --- 25/fs/ext3/namei.c~sched-ext3-fix-scheduling-latencies-in-ext3 2004-12-03 20:56:34.950446912 -0800 +++ 25-akpm/fs/ext3/namei.c 2004-12-03 20:56:34.963444936 -0800 @@ -675,6 +675,7 @@ static int dx_make_map (struct ext3_dir_ map_tail->hash = h.hash; map_tail->offs = (u32) ((char *) de - base); count++; + cond_resched(); } /* XXX: do we need to check rec_len == 0 case? -Chris */ de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); diff -puN fs/ext3/super.c~sched-ext3-fix-scheduling-latencies-in-ext3 fs/ext3/super.c --- 25/fs/ext3/super.c~sched-ext3-fix-scheduling-latencies-in-ext3 2004-12-03 20:56:34.951446760 -0800 +++ 25-akpm/fs/ext3/super.c 2004-12-03 20:56:34.965444632 -0800 @@ -1263,6 +1263,8 @@ static int ext3_fill_super (struct super sbi->s_resuid = EXT3_DEF_RESUID; sbi->s_resgid = EXT3_DEF_RESGID; + unlock_kernel(); + blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE); if (!blocksize) { printk(KERN_ERR "EXT3-fs: unable to set blocksize\n"); @@ -1619,6 +1621,7 @@ static int ext3_fill_super (struct super percpu_counter_mod(&sbi->s_dirs_counter, ext3_count_dirs(sb)); + lock_kernel(); return 0; cantfind_ext3: @@ -1643,6 +1646,7 @@ failed_mount: out_fail: sb->s_fs_info = NULL; kfree(sbi); + lock_kernel(); return -EINVAL; } @@ -2167,9 +2171,11 @@ int ext3_statfs (struct super_block * sb * block group descriptors. If the sparse superblocks * feature is turned on, then not all groups have this. */ - for (i = 0; i < ngroups; i++) + for (i = 0; i < ngroups; i++) { overhead += ext3_bg_has_super(sb, i) + ext3_bg_num_gdb(sb, i); + cond_resched(); + } /* * Every block group has an inode bitmap, a block diff -puN fs/jbd/checkpoint.c~sched-ext3-fix-scheduling-latencies-in-ext3 fs/jbd/checkpoint.c --- 25/fs/jbd/checkpoint.c~sched-ext3-fix-scheduling-latencies-in-ext3 2004-12-03 20:56:34.953446456 -0800 +++ 25-akpm/fs/jbd/checkpoint.c 2004-12-03 20:56:34.966444480 -0800 @@ -333,6 +333,10 @@ int log_do_checkpoint(journal_t *journal break; } retry = __flush_buffer(journal, jh, bhs, &batch_count, &drop_count); + if (cond_resched_lock(&journal->j_list_lock)) { + retry = 1; + break; + } } while (jh != last_jh && !retry); if (batch_count) @@ -487,6 +491,14 @@ int __journal_clean_checkpoint_list(jour /* Use trylock because of the ranknig */ if (jbd_trylock_bh_state(jh2bh(jh))) ret += __try_to_free_cp_buf(jh); + /* + * This function only frees up some memory + * if possible so we dont have an obligation + * to finish processing. Bail out if preemption + * requested: + */ + if (need_resched()) + goto out; } while (jh != last_jh); } } while (transaction != last_transaction); diff -puN fs/jbd/commit.c~sched-ext3-fix-scheduling-latencies-in-ext3 fs/jbd/commit.c --- 25/fs/jbd/commit.c~sched-ext3-fix-scheduling-latencies-in-ext3 2004-12-03 20:56:34.955446152 -0800 +++ 25-akpm/fs/jbd/commit.c 2004-12-03 20:56:34.967444328 -0800 @@ -262,7 +262,7 @@ write_out_data: __journal_file_buffer(jh, commit_transaction, BJ_Locked); jbd_unlock_bh_state(bh); - if (need_resched()) { + if (lock_need_resched(&journal->j_list_lock)) { spin_unlock(&journal->j_list_lock); goto write_out_data; } @@ -288,7 +288,7 @@ write_out_data: jbd_unlock_bh_state(bh); journal_remove_journal_head(bh); put_bh(bh); - if (need_resched()) { + if (lock_need_resched(&journal->j_list_lock)) { spin_unlock(&journal->j_list_lock); goto write_out_data; } @@ -333,11 +333,7 @@ write_out_data: jbd_unlock_bh_state(bh); } put_bh(bh); - if (need_resched()) { - spin_unlock(&journal->j_list_lock); - cond_resched(); - spin_lock(&journal->j_list_lock); - } + cond_resched_lock(&journal->j_list_lock); } spin_unlock(&journal->j_list_lock); @@ -545,6 +541,8 @@ wait_for_iobuf: wait_on_buffer(bh); goto wait_for_iobuf; } + if (cond_resched()) + goto wait_for_iobuf; if (unlikely(!buffer_uptodate(bh))) err = -EIO; @@ -599,6 +597,8 @@ wait_for_iobuf: wait_on_buffer(bh); goto wait_for_ctlbuf; } + if (cond_resched()) + goto wait_for_ctlbuf; if (unlikely(!buffer_uptodate(bh))) err = -EIO; @@ -695,6 +695,7 @@ skip_commit: /* The journal should be un J_ASSERT(commit_transaction->t_shadow_list == NULL); J_ASSERT(commit_transaction->t_log_list == NULL); +restart_loop: while (commit_transaction->t_forget) { transaction_t *cp_transaction; struct buffer_head *bh; @@ -768,6 +769,8 @@ skip_commit: /* The journal should be un release_buffer_page(bh); } spin_unlock(&journal->j_list_lock); + if (cond_resched()) + goto restart_loop; } /* Done with this transaction! */ diff -puN fs/jbd/recovery.c~sched-ext3-fix-scheduling-latencies-in-ext3 fs/jbd/recovery.c --- 25/fs/jbd/recovery.c~sched-ext3-fix-scheduling-latencies-in-ext3 2004-12-03 20:56:34.956446000 -0800 +++ 25-akpm/fs/jbd/recovery.c 2004-12-03 20:56:34.967444328 -0800 @@ -354,6 +354,8 @@ static int do_one_pass(journal_t *journa struct buffer_head * obh; struct buffer_head * nbh; + cond_resched(); /* We're under lock_kernel() */ + /* If we already know where to stop the log traversal, * check right now that we haven't gone past the end of * the log. */ _