aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jffs2/nodemgmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/jffs2/nodemgmt.c')
-rw-r--r--fs/jffs2/nodemgmt.c250
1 files changed, 166 insertions, 84 deletions
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index fe7e70a4055b..208b2bdf01e5 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: nodemgmt.c,v 1.124 2005/07/20 15:32:28 dedekind Exp $ 10 * $Id: nodemgmt.c,v 1.125 2005/09/07 08:34:54 havasi Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -17,6 +17,7 @@
17#include <linux/compiler.h> 17#include <linux/compiler.h>
18#include <linux/sched.h> /* For cond_resched() */ 18#include <linux/sched.h> /* For cond_resched() */
19#include "nodelist.h" 19#include "nodelist.h"
20#include "debug.h"
20 21
21/** 22/**
22 * jffs2_reserve_space - request physical space to write nodes to flash 23 * jffs2_reserve_space - request physical space to write nodes to flash
@@ -38,9 +39,11 @@
38 * for the requested allocation. 39 * for the requested allocation.
39 */ 40 */
40 41
41static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len); 42static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
43 uint32_t *ofs, uint32_t *len, uint32_t sumsize);
42 44
43int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio) 45int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
46 uint32_t *len, int prio, uint32_t sumsize)
44{ 47{
45 int ret = -EAGAIN; 48 int ret = -EAGAIN;
46 int blocksneeded = c->resv_blocks_write; 49 int blocksneeded = c->resv_blocks_write;
@@ -129,7 +132,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
129 spin_lock(&c->erase_completion_lock); 132 spin_lock(&c->erase_completion_lock);
130 } 133 }
131 134
132 ret = jffs2_do_reserve_space(c, minsize, ofs, len); 135 ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize);
133 if (ret) { 136 if (ret) {
134 D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret)); 137 D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret));
135 } 138 }
@@ -140,7 +143,8 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
140 return ret; 143 return ret;
141} 144}
142 145
143int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len) 146int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
147 uint32_t *len, uint32_t sumsize)
144{ 148{
145 int ret = -EAGAIN; 149 int ret = -EAGAIN;
146 minsize = PAD(minsize); 150 minsize = PAD(minsize);
@@ -149,7 +153,7 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *
149 153
150 spin_lock(&c->erase_completion_lock); 154 spin_lock(&c->erase_completion_lock);
151 while(ret == -EAGAIN) { 155 while(ret == -EAGAIN) {
152 ret = jffs2_do_reserve_space(c, minsize, ofs, len); 156 ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize);
153 if (ret) { 157 if (ret) {
154 D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); 158 D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret));
155 } 159 }
@@ -158,105 +162,183 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *
158 return ret; 162 return ret;
159} 163}
160 164
161/* Called with alloc sem _and_ erase_completion_lock */ 165
162static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len) 166/* Classify nextblock (clean, dirty of verydirty) and force to select an other one */
167
168static void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
163{ 169{
164 struct jffs2_eraseblock *jeb = c->nextblock; 170
171 /* Check, if we have a dirty block now, or if it was dirty already */
172 if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) {
173 c->dirty_size += jeb->wasted_size;
174 c->wasted_size -= jeb->wasted_size;
175 jeb->dirty_size += jeb->wasted_size;
176 jeb->wasted_size = 0;
177 if (VERYDIRTY(c, jeb->dirty_size)) {
178 D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
179 jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
180 list_add_tail(&jeb->list, &c->very_dirty_list);
181 } else {
182 D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
183 jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
184 list_add_tail(&jeb->list, &c->dirty_list);
185 }
186 } else {
187 D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
188 jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
189 list_add_tail(&jeb->list, &c->clean_list);
190 }
191 c->nextblock = NULL;
192
193}
194
195/* Select a new jeb for nextblock */
196
197static int jffs2_find_nextblock(struct jffs2_sb_info *c)
198{
199 struct list_head *next;
165 200
166 restart: 201 /* Take the next block off the 'free' list */
167 if (jeb && minsize > jeb->free_size) { 202
168 /* Skip the end of this block and file it as having some dirty space */ 203 if (list_empty(&c->free_list)) {
169 /* If there's a pending write to it, flush now */ 204
170 if (jffs2_wbuf_dirty(c)) { 205 if (!c->nr_erasing_blocks &&
206 !list_empty(&c->erasable_list)) {
207 struct jffs2_eraseblock *ejeb;
208
209 ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list);
210 list_del(&ejeb->list);
211 list_add_tail(&ejeb->list, &c->erase_pending_list);
212 c->nr_erasing_blocks++;
213 jffs2_erase_pending_trigger(c);
214 D1(printk(KERN_DEBUG "jffs2_find_nextblock: Triggering erase of erasable block at 0x%08x\n",
215 ejeb->offset));
216 }
217
218 if (!c->nr_erasing_blocks &&
219 !list_empty(&c->erasable_pending_wbuf_list)) {
220 D1(printk(KERN_DEBUG "jffs2_find_nextblock: Flushing write buffer\n"));
221 /* c->nextblock is NULL, no update to c->nextblock allowed */
171 spin_unlock(&c->erase_completion_lock); 222 spin_unlock(&c->erase_completion_lock);
172 D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
173 jffs2_flush_wbuf_pad(c); 223 jffs2_flush_wbuf_pad(c);
174 spin_lock(&c->erase_completion_lock); 224 spin_lock(&c->erase_completion_lock);
175 jeb = c->nextblock; 225 /* Have another go. It'll be on the erasable_list now */
176 goto restart; 226 return -EAGAIN;
177 } 227 }
178 c->wasted_size += jeb->free_size; 228
179 c->free_size -= jeb->free_size; 229 if (!c->nr_erasing_blocks) {
180 jeb->wasted_size += jeb->free_size; 230 /* Ouch. We're in GC, or we wouldn't have got here.
181 jeb->free_size = 0; 231 And there's no space left. At all. */
182 232 printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n",
183 /* Check, if we have a dirty block now, or if it was dirty already */ 233 c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no",
184 if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) { 234 list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
185 c->dirty_size += jeb->wasted_size; 235 return -ENOSPC;
186 c->wasted_size -= jeb->wasted_size;
187 jeb->dirty_size += jeb->wasted_size;
188 jeb->wasted_size = 0;
189 if (VERYDIRTY(c, jeb->dirty_size)) {
190 D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
191 jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
192 list_add_tail(&jeb->list, &c->very_dirty_list);
193 } else {
194 D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
195 jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
196 list_add_tail(&jeb->list, &c->dirty_list);
197 }
198 } else {
199 D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
200 jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
201 list_add_tail(&jeb->list, &c->clean_list);
202 } 236 }
203 c->nextblock = jeb = NULL; 237
238 spin_unlock(&c->erase_completion_lock);
239 /* Don't wait for it; just erase one right now */
240 jffs2_erase_pending_blocks(c, 1);
241 spin_lock(&c->erase_completion_lock);
242
243 /* An erase may have failed, decreasing the
244 amount of free space available. So we must
245 restart from the beginning */
246 return -EAGAIN;
204 } 247 }
248
249 next = c->free_list.next;
250 list_del(next);
251 c->nextblock = list_entry(next, struct jffs2_eraseblock, list);
252 c->nr_free_blocks--;
205 253
206 if (!jeb) { 254 jffs2_sum_reset_collected(c->summary); /* reset collected summary */
207 struct list_head *next;
208 /* Take the next block off the 'free' list */
209 255
210 if (list_empty(&c->free_list)) { 256 D1(printk(KERN_DEBUG "jffs2_find_nextblock(): new nextblock = 0x%08x\n", c->nextblock->offset));
211 257
212 if (!c->nr_erasing_blocks && 258 return 0;
213 !list_empty(&c->erasable_list)) { 259}
214 struct jffs2_eraseblock *ejeb;
215 260
216 ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list); 261/* Called with alloc sem _and_ erase_completion_lock */
217 list_del(&ejeb->list); 262static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, uint32_t sumsize)
218 list_add_tail(&ejeb->list, &c->erase_pending_list); 263{
219 c->nr_erasing_blocks++; 264 struct jffs2_eraseblock *jeb = c->nextblock;
220 jffs2_erase_pending_trigger(c); 265 uint32_t reserved_size; /* for summary information at the end of the jeb */
221 D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Triggering erase of erasable block at 0x%08x\n", 266 int ret;
222 ejeb->offset)); 267
268 restart:
269 reserved_size = 0;
270
271 if (jffs2_sum_active() && (sumsize != JFFS2_SUMMARY_NOSUM_SIZE)) {
272 /* NOSUM_SIZE means not to generate summary */
273
274 if (jeb) {
275 reserved_size = PAD(sumsize + c->summary->sum_size + JFFS2_SUMMARY_FRAME_SIZE);
276 JFFS2_DBG_SUMMARY("minsize=%d , jeb->free=%d ,"
277 "summary->size=%d , sumsize=%d\n",
278 minsize, jeb->free_size,
279 c->summary->sum_size, sumsize);
280 }
281
282 /* Is there enough space for writing out the current node, or we have to
283 write out summary information now, close this jeb and select new nextblock? */
284 if (jeb && (PAD(minsize) + PAD(c->summary->sum_size + sumsize +
285 JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size)) {
286
287 /* Has summary been disabled for this jeb? */
288 if (jffs2_sum_is_disabled(c->summary)) {
289 sumsize = JFFS2_SUMMARY_NOSUM_SIZE;
290 goto restart;
223 } 291 }
224 292
225 if (!c->nr_erasing_blocks && 293 /* Writing out the collected summary information */
226 !list_empty(&c->erasable_pending_wbuf_list)) { 294 JFFS2_DBG_SUMMARY("generating summary for 0x%08x.\n", jeb->offset);
227 D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); 295 ret = jffs2_sum_write_sumnode(c);
228 /* c->nextblock is NULL, no update to c->nextblock allowed */ 296
297 if (ret)
298 return ret;
299
300 if (jffs2_sum_is_disabled(c->summary)) {
301 /* jffs2_write_sumnode() couldn't write out the summary information
302 diabling summary for this jeb and free the collected information
303 */
304 sumsize = JFFS2_SUMMARY_NOSUM_SIZE;
305 goto restart;
306 }
307
308 jffs2_close_nextblock(c, jeb);
309 jeb = NULL;
310 }
311 } else {
312 if (jeb && minsize > jeb->free_size) {
313 /* Skip the end of this block and file it as having some dirty space */
314 /* If there's a pending write to it, flush now */
315
316 if (jffs2_wbuf_dirty(c)) {
229 spin_unlock(&c->erase_completion_lock); 317 spin_unlock(&c->erase_completion_lock);
318 D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
230 jffs2_flush_wbuf_pad(c); 319 jffs2_flush_wbuf_pad(c);
231 spin_lock(&c->erase_completion_lock); 320 spin_lock(&c->erase_completion_lock);
232 /* Have another go. It'll be on the erasable_list now */ 321 jeb = c->nextblock;
233 return -EAGAIN; 322 goto restart;
234 }
235
236 if (!c->nr_erasing_blocks) {
237 /* Ouch. We're in GC, or we wouldn't have got here.
238 And there's no space left. At all. */
239 printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n",
240 c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no",
241 list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
242 return -ENOSPC;
243 } 323 }
244 324
245 spin_unlock(&c->erase_completion_lock); 325 c->wasted_size += jeb->free_size;
246 /* Don't wait for it; just erase one right now */ 326 c->free_size -= jeb->free_size;
247 jffs2_erase_pending_blocks(c, 1); 327 jeb->wasted_size += jeb->free_size;
248 spin_lock(&c->erase_completion_lock); 328 jeb->free_size = 0;
249 329
250 /* An erase may have failed, decreasing the 330 jffs2_close_nextblock(c, jeb);
251 amount of free space available. So we must 331 jeb = NULL;
252 restart from the beginning */
253 return -EAGAIN;
254 } 332 }
333 }
334
335 if (!jeb) {
336
337 ret = jffs2_find_nextblock(c);
338 if (ret)
339 return ret;
255 340
256 next = c->free_list.next; 341 jeb = c->nextblock;
257 list_del(next);
258 c->nextblock = jeb = list_entry(next, struct jffs2_eraseblock, list);
259 c->nr_free_blocks--;
260 342
261 if (jeb->free_size != c->sector_size - c->cleanmarker_size) { 343 if (jeb->free_size != c->sector_size - c->cleanmarker_size) {
262 printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size); 344 printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
@@ -266,7 +348,7 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui
266 /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has 348 /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has
267 enough space */ 349 enough space */
268 *ofs = jeb->offset + (c->sector_size - jeb->free_size); 350 *ofs = jeb->offset + (c->sector_size - jeb->free_size);
269 *len = jeb->free_size; 351 *len = jeb->free_size - reserved_size;
270 352
271 if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size && 353 if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size &&
272 !jeb->first_node->next_in_ino) { 354 !jeb->first_node->next_in_ino) {