Patchwork JFFS2 very slow when erasing

login
register
mail settings
Submitter Joakim Tjernlund
Date Oct. 7, 2010, noon
Message ID <OFFCEBB9A1.311BB67A-ONC12577B5.0041BA45-C12577B5.0041F321@transmode.se>
Download mbox | patch
Permalink /patch/67040/
State New
Headers show

Comments

Joakim Tjernlund - Oct. 7, 2010, noon
> > With 2.6.35 JFFS2 takes a very long time cp files while it erases:
> >  cp big_file test
> >  rm test
> >  cp big_file test
> > The last cp op. takes several times longer because JFFS2 is erasing.
> > Revering the patches I helped out with make JFFS2 go fast again:
> >   jffs2: Stop triggering block erases from jffs2_write_super()
> >   jffs2: Rename jffs2_erase_pending_trigger() to jffs2_dirty_trigger()
> >   jffs2: Use jffs2_garbage_collect_trigger() to trigger pending erases
> >   jffs2: Require jffs2_garbage_collect_trigger() to be called with lock held
> >   jffs2: Wake GC thread when there are blocks to be erased
> >   jffs2: Erase pending blocks in GC pass, avoid invalid -EIO return
> >
> > The final patches were somewhat different than the ones I originally wrote
> > and I THINK those didn't make JFFS2 go this slow.
> >
> > I suspect there is a locking problem somewhere.
>
> Commenting out this makes JFFS2 fast again:
> diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
> index f5e96bd..bce3a30 100644
> --- a/fs/jffs2/gc.c
> +++ b/fs/jffs2/gc.c
> @@ -213,7 +213,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
>        mutex_unlock(&c->alloc_sem);
>        return ret;
>     }
> -
> +#if 0
>     /* If there are any blocks which need erasing, erase them now */
>     if (!list_empty(&c->erase_complete_list) ||
>         !list_empty(&c->erase_pending_list)) {
> @@ -226,7 +226,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
>        D1(printk(KERN_DEBUG "No progress from erasing blocks; doing GC anyway\n"));
>        spin_lock(&c->erase_completion_lock);
>     }
> -
> +#endif
>     /* First, work out which block we're garbage-collecting */
>     jeb = c->gcblock;
>
> Seems to me that jffs2_garbage_collect_pass() is trying too much.
> David?

So, if I release the alloc_sem before erase thing gets back to normal.
Is releasing the alloc_sem bad here?

Patch

diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index f5e96bd..042ac66 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -218,13 +218,14 @@  int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
 	if (!list_empty(&c->erase_complete_list) ||
 	    !list_empty(&c->erase_pending_list)) {
 		spin_unlock(&c->erase_completion_lock);
+		mutex_unlock(&c->alloc_sem);
 		D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() erasing pending blocks\n"));
 		if (jffs2_erase_pending_blocks(c, 1)) {
-			mutex_unlock(&c->alloc_sem);
 			return 0;
 		}
 		D1(printk(KERN_DEBUG "No progress from erasing blocks; doing GC anyway\n"));
 		spin_lock(&c->erase_completion_lock);
+		mutex_lock(&c->alloc_sem);
 	}

 	/* First, work out which block we're garbage-collecting */