diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-22 19:34:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-22 19:34:03 -0400 |
commit | 06d362931a530e0d48c1a9554a752da4ed240f0b (patch) | |
tree | 283304f08f3c01cec6922e6bb76291a9588352db /fs/ubifs/gc.c | |
parent | f5d9d249b9a6884daff513ef08afa43d3f7e085f (diff) | |
parent | 6599fcbd01baf9d57e847db103d215ea4ec088f9 (diff) |
Merge branch 'linux-next' of git://git.infradead.org/ubifs-2.6
* 'linux-next' of git://git.infradead.org/ubifs-2.6:
UBIFS: do not allocate unneeded scan buffer
UBIFS: do not forget to cancel timers
UBIFS: remove a bit of unneeded code
UBIFS: add a commentary about log recovery
UBIFS: avoid kernel error if ubifs superblock read fails
UBIFS: introduce new flags for RO mounts
UBIFS: introduce new flag for RO due to errors
UBIFS: check return code of pnode_lookup
UBIFS: check return code of ubifs_lpt_lookup
UBIFS: improve error reporting when reading bad node
UBIFS: introduce list sorting debugging checks
UBIFS: fix assertion warnings in comparison function
UBIFS: mark unused key objects as invalid
UBIFS: do not write rubbish into truncation scanning node
UBIFS: improve assertion in node comparison functions
UBIFS: do not use key type in list_sort
UBIFS: do not look up truncation nodes
UBIFS: fix assertion warning
UBIFS: do not treat ENOSPC specially
UBIFS: switch to RO mode after synchronizing
Diffstat (limited to 'fs/ubifs/gc.c')
-rw-r--r-- | fs/ubifs/gc.c | 82 |
1 files changed, 61 insertions, 21 deletions
diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c index 918d1582ca05..151f10882820 100644 --- a/fs/ubifs/gc.c +++ b/fs/ubifs/gc.c | |||
@@ -125,10 +125,16 @@ int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b) | |||
125 | struct ubifs_scan_node *sa, *sb; | 125 | struct ubifs_scan_node *sa, *sb; |
126 | 126 | ||
127 | cond_resched(); | 127 | cond_resched(); |
128 | if (a == b) | ||
129 | return 0; | ||
130 | |||
128 | sa = list_entry(a, struct ubifs_scan_node, list); | 131 | sa = list_entry(a, struct ubifs_scan_node, list); |
129 | sb = list_entry(b, struct ubifs_scan_node, list); | 132 | sb = list_entry(b, struct ubifs_scan_node, list); |
133 | |||
130 | ubifs_assert(key_type(c, &sa->key) == UBIFS_DATA_KEY); | 134 | ubifs_assert(key_type(c, &sa->key) == UBIFS_DATA_KEY); |
131 | ubifs_assert(key_type(c, &sb->key) == UBIFS_DATA_KEY); | 135 | ubifs_assert(key_type(c, &sb->key) == UBIFS_DATA_KEY); |
136 | ubifs_assert(sa->type == UBIFS_DATA_NODE); | ||
137 | ubifs_assert(sb->type == UBIFS_DATA_NODE); | ||
132 | 138 | ||
133 | inuma = key_inum(c, &sa->key); | 139 | inuma = key_inum(c, &sa->key); |
134 | inumb = key_inum(c, &sb->key); | 140 | inumb = key_inum(c, &sb->key); |
@@ -157,28 +163,40 @@ int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b) | |||
157 | */ | 163 | */ |
158 | int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b) | 164 | int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b) |
159 | { | 165 | { |
160 | int typea, typeb; | ||
161 | ino_t inuma, inumb; | 166 | ino_t inuma, inumb; |
162 | struct ubifs_info *c = priv; | 167 | struct ubifs_info *c = priv; |
163 | struct ubifs_scan_node *sa, *sb; | 168 | struct ubifs_scan_node *sa, *sb; |
164 | 169 | ||
165 | cond_resched(); | 170 | cond_resched(); |
171 | if (a == b) | ||
172 | return 0; | ||
173 | |||
166 | sa = list_entry(a, struct ubifs_scan_node, list); | 174 | sa = list_entry(a, struct ubifs_scan_node, list); |
167 | sb = list_entry(b, struct ubifs_scan_node, list); | 175 | sb = list_entry(b, struct ubifs_scan_node, list); |
168 | typea = key_type(c, &sa->key); | 176 | |
169 | typeb = key_type(c, &sb->key); | 177 | ubifs_assert(key_type(c, &sa->key) != UBIFS_DATA_KEY && |
170 | ubifs_assert(typea != UBIFS_DATA_KEY && typeb != UBIFS_DATA_KEY); | 178 | key_type(c, &sb->key) != UBIFS_DATA_KEY); |
179 | ubifs_assert(sa->type != UBIFS_DATA_NODE && | ||
180 | sb->type != UBIFS_DATA_NODE); | ||
171 | 181 | ||
172 | /* Inodes go before directory entries */ | 182 | /* Inodes go before directory entries */ |
173 | if (typea == UBIFS_INO_KEY) { | 183 | if (sa->type == UBIFS_INO_NODE) { |
174 | if (typeb == UBIFS_INO_KEY) | 184 | if (sb->type == UBIFS_INO_NODE) |
175 | return sb->len - sa->len; | 185 | return sb->len - sa->len; |
176 | return -1; | 186 | return -1; |
177 | } | 187 | } |
178 | if (typeb == UBIFS_INO_KEY) | 188 | if (sb->type == UBIFS_INO_NODE) |
179 | return 1; | 189 | return 1; |
180 | 190 | ||
181 | ubifs_assert(typea == UBIFS_DENT_KEY && typeb == UBIFS_DENT_KEY); | 191 | ubifs_assert(key_type(c, &sa->key) == UBIFS_DENT_KEY || |
192 | key_type(c, &sa->key) == UBIFS_XENT_KEY); | ||
193 | ubifs_assert(key_type(c, &sb->key) == UBIFS_DENT_KEY || | ||
194 | key_type(c, &sb->key) == UBIFS_XENT_KEY); | ||
195 | ubifs_assert(sa->type == UBIFS_DENT_NODE || | ||
196 | sa->type == UBIFS_XENT_NODE); | ||
197 | ubifs_assert(sb->type == UBIFS_DENT_NODE || | ||
198 | sb->type == UBIFS_XENT_NODE); | ||
199 | |||
182 | inuma = key_inum(c, &sa->key); | 200 | inuma = key_inum(c, &sa->key); |
183 | inumb = key_inum(c, &sb->key); | 201 | inumb = key_inum(c, &sb->key); |
184 | 202 | ||
@@ -224,17 +242,33 @@ int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b) | |||
224 | static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb, | 242 | static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb, |
225 | struct list_head *nondata, int *min) | 243 | struct list_head *nondata, int *min) |
226 | { | 244 | { |
245 | int err; | ||
227 | struct ubifs_scan_node *snod, *tmp; | 246 | struct ubifs_scan_node *snod, *tmp; |
228 | 247 | ||
229 | *min = INT_MAX; | 248 | *min = INT_MAX; |
230 | 249 | ||
231 | /* Separate data nodes and non-data nodes */ | 250 | /* Separate data nodes and non-data nodes */ |
232 | list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) { | 251 | list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) { |
233 | int err; | 252 | ubifs_assert(snod->type == UBIFS_INO_NODE || |
253 | snod->type == UBIFS_DATA_NODE || | ||
254 | snod->type == UBIFS_DENT_NODE || | ||
255 | snod->type == UBIFS_XENT_NODE || | ||
256 | snod->type == UBIFS_TRUN_NODE); | ||
257 | |||
258 | if (snod->type != UBIFS_INO_NODE && | ||
259 | snod->type != UBIFS_DATA_NODE && | ||
260 | snod->type != UBIFS_DENT_NODE && | ||
261 | snod->type != UBIFS_XENT_NODE) { | ||
262 | /* Probably truncation node, zap it */ | ||
263 | list_del(&snod->list); | ||
264 | kfree(snod); | ||
265 | continue; | ||
266 | } | ||
234 | 267 | ||
235 | ubifs_assert(snod->type != UBIFS_IDX_NODE); | 268 | ubifs_assert(key_type(c, &snod->key) == UBIFS_DATA_KEY || |
236 | ubifs_assert(snod->type != UBIFS_REF_NODE); | 269 | key_type(c, &snod->key) == UBIFS_INO_KEY || |
237 | ubifs_assert(snod->type != UBIFS_CS_NODE); | 270 | key_type(c, &snod->key) == UBIFS_DENT_KEY || |
271 | key_type(c, &snod->key) == UBIFS_XENT_KEY); | ||
238 | 272 | ||
239 | err = ubifs_tnc_has_node(c, &snod->key, 0, sleb->lnum, | 273 | err = ubifs_tnc_has_node(c, &snod->key, 0, sleb->lnum, |
240 | snod->offs, 0); | 274 | snod->offs, 0); |
@@ -258,6 +292,13 @@ static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb, | |||
258 | /* Sort data and non-data nodes */ | 292 | /* Sort data and non-data nodes */ |
259 | list_sort(c, &sleb->nodes, &data_nodes_cmp); | 293 | list_sort(c, &sleb->nodes, &data_nodes_cmp); |
260 | list_sort(c, nondata, &nondata_nodes_cmp); | 294 | list_sort(c, nondata, &nondata_nodes_cmp); |
295 | |||
296 | err = dbg_check_data_nodes_order(c, &sleb->nodes); | ||
297 | if (err) | ||
298 | return err; | ||
299 | err = dbg_check_nondata_nodes_order(c, nondata); | ||
300 | if (err) | ||
301 | return err; | ||
261 | return 0; | 302 | return 0; |
262 | } | 303 | } |
263 | 304 | ||
@@ -575,13 +616,14 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway) | |||
575 | struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; | 616 | struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; |
576 | 617 | ||
577 | ubifs_assert_cmt_locked(c); | 618 | ubifs_assert_cmt_locked(c); |
619 | ubifs_assert(!c->ro_media && !c->ro_mount); | ||
578 | 620 | ||
579 | if (ubifs_gc_should_commit(c)) | 621 | if (ubifs_gc_should_commit(c)) |
580 | return -EAGAIN; | 622 | return -EAGAIN; |
581 | 623 | ||
582 | mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); | 624 | mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); |
583 | 625 | ||
584 | if (c->ro_media) { | 626 | if (c->ro_error) { |
585 | ret = -EROFS; | 627 | ret = -EROFS; |
586 | goto out_unlock; | 628 | goto out_unlock; |
587 | } | 629 | } |
@@ -677,14 +719,12 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway) | |||
677 | 719 | ||
678 | ret = ubifs_garbage_collect_leb(c, &lp); | 720 | ret = ubifs_garbage_collect_leb(c, &lp); |
679 | if (ret < 0) { | 721 | if (ret < 0) { |
680 | if (ret == -EAGAIN || ret == -ENOSPC) { | 722 | if (ret == -EAGAIN) { |
681 | /* | 723 | /* |
682 | * These codes are not errors, so we have to | 724 | * This is not error, so we have to return the |
683 | * return the LEB to lprops. But if the | 725 | * LEB to lprops. But if 'ubifs_return_leb()' |
684 | * 'ubifs_return_leb()' function fails, its | 726 | * fails, its failure code is propagated to the |
685 | * failure code is propagated to the caller | 727 | * caller instead of the original '-EAGAIN'. |
686 | * instead of the original '-EAGAIN' or | ||
687 | * '-ENOSPC'. | ||
688 | */ | 728 | */ |
689 | err = ubifs_return_leb(c, lp.lnum); | 729 | err = ubifs_return_leb(c, lp.lnum); |
690 | if (err) | 730 | if (err) |
@@ -774,8 +814,8 @@ out_unlock: | |||
774 | out: | 814 | out: |
775 | ubifs_assert(ret < 0); | 815 | ubifs_assert(ret < 0); |
776 | ubifs_assert(ret != -ENOSPC && ret != -EAGAIN); | 816 | ubifs_assert(ret != -ENOSPC && ret != -EAGAIN); |
777 | ubifs_ro_mode(c, ret); | ||
778 | ubifs_wbuf_sync_nolock(wbuf); | 817 | ubifs_wbuf_sync_nolock(wbuf); |
818 | ubifs_ro_mode(c, ret); | ||
779 | mutex_unlock(&wbuf->io_mutex); | 819 | mutex_unlock(&wbuf->io_mutex); |
780 | ubifs_return_leb(c, lp.lnum); | 820 | ubifs_return_leb(c, lp.lnum); |
781 | return ret; | 821 | return ret; |