aboutsummaryrefslogtreecommitdiff
path: root/fs/jffs2/nodemgmt.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-05-21 07:25:43 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-21 07:25:43 -0700
commit05ec7dd8dd5aa42c22a49682e4a51cadd4166b7e (patch)
tree6370b43c0d8f324aa7421bbb5a647aa04ab5d747 /fs/jffs2/nodemgmt.c
parentc316ba3b518bc35ce5aef5421135220389f4eb98 (diff)
parent8046112818b70329e930b1d4557ef0876c1ad2bb (diff)
Merge git://git.infradead.org/mtd-2.6
* git://git.infradead.org/mtd-2.6: (154 commits) mtd: cfi_cmdset_0002: use AMD standard command-set with Winbond flash chips mtd: cfi_cmdset_0002: Fix MODULE_ALIAS and linkage for new 0701 commandset ID mtd: mxc_nand: Remove duplicate NAND_CMD_RESET case value mtd: update gfp/slab.h includes 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 jffs2: Add 'work_done' return value from jffs2_erase_pending_blocks() mtd: mtdchar: Do not corrupt backing device of device node inode mtd/maps/pcmciamtd: Fix printk format for ssize_t in debug messages drivers/mtd: Use kmemdup mtd: cfi_cmdset_0002: Fix argument order in bootloc warning mtd: nand: add Toshiba TC58NVG0 device ID pcmciamtd: add another ID pcmciamtd: coding style cleanups pcmciamtd: fixing obvious errors mtd: chips: add SST39WF160x NOR-flashes ... Trivial conflicts due to dev_node removal in drivers/mtd/maps/pcmciamtd.c
Diffstat (limited to 'fs/jffs2/nodemgmt.c')
-rw-r--r--fs/jffs2/nodemgmt.c28
1 files changed, 23 insertions, 5 deletions
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index 191359dde4e..694aa5b0350 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -116,9 +116,21 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
ret = jffs2_garbage_collect_pass(c);
- if (ret == -EAGAIN)
- jffs2_erase_pending_blocks(c, 1);
- else if (ret)
+ if (ret == -EAGAIN) {
+ spin_lock(&c->erase_completion_lock);
+ if (c->nr_erasing_blocks &&
+ list_empty(&c->erase_pending_list) &&
+ list_empty(&c->erase_complete_list)) {
+ DECLARE_WAITQUEUE(wait, current);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&c->erase_wait, &wait);
+ D1(printk(KERN_DEBUG "%s waiting for erase to complete\n", __func__));
+ spin_unlock(&c->erase_completion_lock);
+
+ schedule();
+ } else
+ spin_unlock(&c->erase_completion_lock);
+ } else if (ret)
return ret;
cond_resched();
@@ -217,7 +229,7 @@ static int jffs2_find_nextblock(struct jffs2_sb_info *c)
ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list);
list_move_tail(&ejeb->list, &c->erase_pending_list);
c->nr_erasing_blocks++;
- jffs2_erase_pending_trigger(c);
+ jffs2_garbage_collect_trigger(c);
D1(printk(KERN_DEBUG "jffs2_find_nextblock: Triggering erase of erasable block at 0x%08x\n",
ejeb->offset));
}
@@ -469,7 +481,9 @@ struct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c,
void jffs2_complete_reservation(struct jffs2_sb_info *c)
{
D1(printk(KERN_DEBUG "jffs2_complete_reservation()\n"));
+ spin_lock(&c->erase_completion_lock);
jffs2_garbage_collect_trigger(c);
+ spin_unlock(&c->erase_completion_lock);
mutex_unlock(&c->alloc_sem);
}
@@ -611,7 +625,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n"));
list_add_tail(&jeb->list, &c->erase_pending_list);
c->nr_erasing_blocks++;
- jffs2_erase_pending_trigger(c);
+ jffs2_garbage_collect_trigger(c);
} else {
/* Sometimes, however, we leave it elsewhere so it doesn't get
immediately reused, and we spread the load a bit. */
@@ -732,6 +746,10 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c)
int nr_very_dirty = 0;
struct jffs2_eraseblock *jeb;
+ if (!list_empty(&c->erase_complete_list) ||
+ !list_empty(&c->erase_pending_list))
+ return 1;
+
if (c->unchecked_size) {
D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n",
c->unchecked_size, c->checked_ino));