diff options
Diffstat (limited to 'fs/ubifs/gc.c')
-rw-r--r-- | fs/ubifs/gc.c | 71 |
1 files changed, 38 insertions, 33 deletions
diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c index 151f10882820..ded29f6224c2 100644 --- a/fs/ubifs/gc.c +++ b/fs/ubifs/gc.c | |||
@@ -100,6 +100,10 @@ static int switch_gc_head(struct ubifs_info *c) | |||
100 | if (err) | 100 | if (err) |
101 | return err; | 101 | return err; |
102 | 102 | ||
103 | err = ubifs_wbuf_sync_nolock(wbuf); | ||
104 | if (err) | ||
105 | return err; | ||
106 | |||
103 | err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0); | 107 | err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0); |
104 | if (err) | 108 | if (err) |
105 | return err; | 109 | return err; |
@@ -118,7 +122,7 @@ static int switch_gc_head(struct ubifs_info *c) | |||
118 | * This function compares data nodes @a and @b. Returns %1 if @a has greater | 122 | * This function compares data nodes @a and @b. Returns %1 if @a has greater |
119 | * inode or block number, and %-1 otherwise. | 123 | * inode or block number, and %-1 otherwise. |
120 | */ | 124 | */ |
121 | int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b) | 125 | static int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b) |
122 | { | 126 | { |
123 | ino_t inuma, inumb; | 127 | ino_t inuma, inumb; |
124 | struct ubifs_info *c = priv; | 128 | struct ubifs_info *c = priv; |
@@ -161,7 +165,8 @@ int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b) | |||
161 | * first and sorted by length in descending order. Directory entry nodes go | 165 | * first and sorted by length in descending order. Directory entry nodes go |
162 | * after inode nodes and are sorted in ascending hash valuer order. | 166 | * after inode nodes and are sorted in ascending hash valuer order. |
163 | */ | 167 | */ |
164 | int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b) | 168 | static int nondata_nodes_cmp(void *priv, struct list_head *a, |
169 | struct list_head *b) | ||
165 | { | 170 | { |
166 | ino_t inuma, inumb; | 171 | ino_t inuma, inumb; |
167 | struct ubifs_info *c = priv; | 172 | struct ubifs_info *c = priv; |
@@ -473,6 +478,37 @@ int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp) | |||
473 | ubifs_assert(c->gc_lnum != lnum); | 478 | ubifs_assert(c->gc_lnum != lnum); |
474 | ubifs_assert(wbuf->lnum != lnum); | 479 | ubifs_assert(wbuf->lnum != lnum); |
475 | 480 | ||
481 | if (lp->free + lp->dirty == c->leb_size) { | ||
482 | /* Special case - a free LEB */ | ||
483 | dbg_gc("LEB %d is free, return it", lp->lnum); | ||
484 | ubifs_assert(!(lp->flags & LPROPS_INDEX)); | ||
485 | |||
486 | if (lp->free != c->leb_size) { | ||
487 | /* | ||
488 | * Write buffers must be sync'd before unmapping | ||
489 | * freeable LEBs, because one of them may contain data | ||
490 | * which obsoletes something in 'lp->pnum'. | ||
491 | */ | ||
492 | err = gc_sync_wbufs(c); | ||
493 | if (err) | ||
494 | return err; | ||
495 | err = ubifs_change_one_lp(c, lp->lnum, c->leb_size, | ||
496 | 0, 0, 0, 0); | ||
497 | if (err) | ||
498 | return err; | ||
499 | } | ||
500 | err = ubifs_leb_unmap(c, lp->lnum); | ||
501 | if (err) | ||
502 | return err; | ||
503 | |||
504 | if (c->gc_lnum == -1) { | ||
505 | c->gc_lnum = lnum; | ||
506 | return LEB_RETAINED; | ||
507 | } | ||
508 | |||
509 | return LEB_FREED; | ||
510 | } | ||
511 | |||
476 | /* | 512 | /* |
477 | * We scan the entire LEB even though we only really need to scan up to | 513 | * We scan the entire LEB even though we only really need to scan up to |
478 | * (c->leb_size - lp->free). | 514 | * (c->leb_size - lp->free). |
@@ -682,37 +718,6 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway) | |||
682 | "(min. space %d)", lp.lnum, lp.free, lp.dirty, | 718 | "(min. space %d)", lp.lnum, lp.free, lp.dirty, |
683 | lp.free + lp.dirty, min_space); | 719 | lp.free + lp.dirty, min_space); |
684 | 720 | ||
685 | if (lp.free + lp.dirty == c->leb_size) { | ||
686 | /* An empty LEB was returned */ | ||
687 | dbg_gc("LEB %d is free, return it", lp.lnum); | ||
688 | /* | ||
689 | * ubifs_find_dirty_leb() doesn't return freeable index | ||
690 | * LEBs. | ||
691 | */ | ||
692 | ubifs_assert(!(lp.flags & LPROPS_INDEX)); | ||
693 | if (lp.free != c->leb_size) { | ||
694 | /* | ||
695 | * Write buffers must be sync'd before | ||
696 | * unmapping freeable LEBs, because one of them | ||
697 | * may contain data which obsoletes something | ||
698 | * in 'lp.pnum'. | ||
699 | */ | ||
700 | ret = gc_sync_wbufs(c); | ||
701 | if (ret) | ||
702 | goto out; | ||
703 | ret = ubifs_change_one_lp(c, lp.lnum, | ||
704 | c->leb_size, 0, 0, 0, | ||
705 | 0); | ||
706 | if (ret) | ||
707 | goto out; | ||
708 | } | ||
709 | ret = ubifs_leb_unmap(c, lp.lnum); | ||
710 | if (ret) | ||
711 | goto out; | ||
712 | ret = lp.lnum; | ||
713 | break; | ||
714 | } | ||
715 | |||
716 | space_before = c->leb_size - wbuf->offs - wbuf->used; | 721 | space_before = c->leb_size - wbuf->offs - wbuf->used; |
717 | if (wbuf->lnum == -1) | 722 | if (wbuf->lnum == -1) |
718 | space_before = 0; | 723 | space_before = 0; |