aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jffs2/nodelist.c
diff options
context:
space:
mode:
authorArtem B. Bityutskiy <dedekind@infradead.org>2005-08-01 08:05:22 -0400
committerThomas Gleixner <tglx@mtd.linutronix.de>2005-11-06 12:22:17 -0500
commit1e0da3cb6cd4a909c64c870344183185bd6815b1 (patch)
treef7ffedba74681cd8f7662990dfb4f3919dcaef23 /fs/jffs2/nodelist.c
parente0e3006f79a6d995c9a7de7556f11a9b97536423 (diff)
[JFFS2] Build fragtree in reverse order
Instead of building fragtree starting from node with the smallest version number, start from the highest. This helps to avoid reading and checking obsolete nodes. Signed-off-by: Artem B. Bityutskiy <dedekind@infradead.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'fs/jffs2/nodelist.c')
-rw-r--r--fs/jffs2/nodelist.c637
1 files changed, 570 insertions, 67 deletions
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
index 0cf5e6f11989..390ce06ab1a7 100644
--- a/fs/jffs2/nodelist.c
+++ b/fs/jffs2/nodelist.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: nodelist.c,v 1.103 2005/07/31 08:20:44 dedekind Exp $ 10 * $Id: nodelist.c,v 1.104 2005/08/01 12:05:19 dedekind Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -59,7 +59,7 @@ void jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint
59 59
60 /* We know frag->ofs <= size. That's what lookup does for us */ 60 /* We know frag->ofs <= size. That's what lookup does for us */
61 if (frag && frag->ofs != size) { 61 if (frag && frag->ofs != size) {
62 if (frag->ofs+frag->size >= size) { 62 if (frag->ofs+frag->size > size) {
63 JFFS2_DBG_FRAGTREE2("truncating frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size); 63 JFFS2_DBG_FRAGTREE2("truncating frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size);
64 frag->size = size - frag->ofs; 64 frag->size = size - frag->ofs;
65 } 65 }
@@ -73,6 +73,20 @@ void jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint
73 jffs2_obsolete_node_frag(c, frag); 73 jffs2_obsolete_node_frag(c, frag);
74 frag = next; 74 frag = next;
75 } 75 }
76
77 if (size == 0)
78 return;
79
80 /*
81 * If the last fragment starts at the RAM page boundary, it is
82 * REF_PRISTINE irrespective of its size.
83 */
84 frag = frag_last(list);
85 if ((frag->ofs & (PAGE_CACHE_SIZE - 1)) == 0) {
86 JFFS2_DBG_FRAGTREE2("marking the last fragment 0x%08x-0x%08x REF_PRISTINE.\n",
87 frag->ofs, frag->ofs + frag->size);
88 frag->node->raw->flash_offset = ref_offset(frag->node->raw) | REF_PRISTINE;
89 }
76} 90}
77 91
78void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this) 92void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this)
@@ -120,14 +134,82 @@ static void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_
120 rb_link_node(&newfrag->rb, &base->rb, link); 134 rb_link_node(&newfrag->rb, &base->rb, link);
121} 135}
122 136
137/*
138 * Allocate and initializes a new fragment.
139 */
140static inline struct jffs2_node_frag * new_fragment(struct jffs2_full_dnode *fn, uint32_t ofs, uint32_t size)
141{
142 struct jffs2_node_frag *newfrag;
143
144 newfrag = jffs2_alloc_node_frag();
145 if (likely(newfrag)) {
146 newfrag->ofs = ofs;
147 newfrag->size = size;
148 newfrag->node = fn;
149 } else {
150 JFFS2_ERROR("cannot allocate a jffs2_node_frag object\n");
151 }
152
153 return newfrag;
154}
155
156/*
157 * Called when there is no overlapping fragment exist. Inserts a hole before the new
158 * fragment and inserts the new fragment to the fragtree.
159 */
160static int no_overlapping_node(struct jffs2_sb_info *c, struct rb_root *root,
161 struct jffs2_node_frag *newfrag,
162 struct jffs2_node_frag *this, uint32_t lastend)
163{
164 if (lastend < newfrag->node->ofs) {
165 /* put a hole in before the new fragment */
166 struct jffs2_node_frag *holefrag;
167
168 holefrag= new_fragment(NULL, lastend, newfrag->node->ofs - lastend);
169 if (unlikely(!holefrag)) {
170 jffs2_free_node_frag(newfrag);
171 return -ENOMEM;
172 }
173
174 if (this) {
175 /* By definition, the 'this' node has no right-hand child,
176 because there are no frags with offset greater than it.
177 So that's where we want to put the hole */
178 JFFS2_DBG_FRAGTREE2("add hole frag %u-%u on the right of the new frag.\n",
179 holefrag->ofs, holefrag->ofs + holefrag->size);
180 rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right);
181 } else {
182 JFFS2_DBG_FRAGTREE2("Add hole frag %u-%u to the root of the tree.\n",
183 holefrag->ofs, holefrag->ofs + holefrag->size);
184 rb_link_node(&holefrag->rb, NULL, &root->rb_node);
185 }
186 rb_insert_color(&holefrag->rb, root);
187 this = holefrag;
188 }
189
190 if (this) {
191 /* By definition, the 'this' node has no right-hand child,
192 because there are no frags with offset greater than it.
193 So that's where we want to put new fragment */
194 JFFS2_DBG_FRAGTREE2("add the new node at the right\n");
195 rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right);
196 } else {
197 JFFS2_DBG_FRAGTREE2("insert the new node at the root of the tree\n");
198 rb_link_node(&newfrag->rb, NULL, &root->rb_node);
199 }
200 rb_insert_color(&newfrag->rb, root);
201
202 return 0;
203}
204
123/* Doesn't set inode->i_size */ 205/* Doesn't set inode->i_size */
124static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag) 206static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *root, struct jffs2_node_frag *newfrag)
125{ 207{
126 struct jffs2_node_frag *this; 208 struct jffs2_node_frag *this;
127 uint32_t lastend; 209 uint32_t lastend;
128 210
129 /* Skip all the nodes which are completed before this one starts */ 211 /* Skip all the nodes which are completed before this one starts */
130 this = jffs2_lookup_node_frag(list, newfrag->node->ofs); 212 this = jffs2_lookup_node_frag(root, newfrag->node->ofs);
131 213
132 if (this) { 214 if (this) {
133 JFFS2_DBG_FRAGTREE2("lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", 215 JFFS2_DBG_FRAGTREE2("lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n",
@@ -138,7 +220,7 @@ static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *l
138 lastend = 0; 220 lastend = 0;
139 } 221 }
140 222
141 /* See if we ran off the end of the list */ 223 /* See if we ran off the end of the fragtree */
142 if (lastend <= newfrag->ofs) { 224 if (lastend <= newfrag->ofs) {
143 /* We did */ 225 /* We did */
144 226
@@ -152,45 +234,16 @@ static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *l
152 mark_ref_normal(newfrag->node->raw); 234 mark_ref_normal(newfrag->node->raw);
153 } 235 }
154 236
155 if (lastend < newfrag->node->ofs) { 237 return no_overlapping_node(c, root, newfrag, this, lastend);
156 /* ... and we need to put a hole in before the new node */
157 struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag();
158 if (!holefrag) {
159 jffs2_free_node_frag(newfrag);
160 return -ENOMEM;
161 }
162 holefrag->ofs = lastend;
163 holefrag->size = newfrag->node->ofs - lastend;
164 holefrag->node = NULL;
165 if (this) {
166 /* By definition, the 'this' node has no right-hand child,
167 because there are no frags with offset greater than it.
168 So that's where we want to put the hole */
169 JFFS2_DBG_FRAGTREE2("adding hole frag (%p) on right of node at (%p)\n", holefrag, this);
170 rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right);
171 } else {
172 JFFS2_DBG_FRAGTREE2("adding hole frag (%p) at root of tree\n", holefrag);
173 rb_link_node(&holefrag->rb, NULL, &list->rb_node);
174 }
175 rb_insert_color(&holefrag->rb, list);
176 this = holefrag;
177 }
178 if (this) {
179 /* By definition, the 'this' node has no right-hand child,
180 because there are no frags with offset greater than it.
181 So that's where we want to put new fragment */
182 JFFS2_DBG_FRAGTREE2("adding new frag (%p) on right of node at (%p)\n", newfrag, this);
183 rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right);
184 } else {
185 JFFS2_DBG_FRAGTREE2("adding new frag (%p) at root of tree\n", newfrag);
186 rb_link_node(&newfrag->rb, NULL, &list->rb_node);
187 }
188 rb_insert_color(&newfrag->rb, list);
189 return 0;
190 } 238 }
191 239
192 JFFS2_DBG_FRAGTREE2("dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", 240 if (this->node)
193 this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this); 241 JFFS2_DBG_FRAGTREE2("dealing with frag %u-%u, phys %#08x(%d).\n",
242 this->ofs, this->ofs + this->size,
243 ref_offset(this->node->raw), ref_flags(this->node->raw));
244 else
245 JFFS2_DBG_FRAGTREE2("dealing with hole frag %u-%u.\n",
246 this->ofs, this->ofs + this->size);
194 247
195 /* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes, 248 /* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes,
196 * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs 249 * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs
@@ -206,11 +259,8 @@ static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *l
206 259
207 if (this->ofs + this->size > newfrag->ofs + newfrag->size) { 260 if (this->ofs + this->size > newfrag->ofs + newfrag->size) {
208 /* The new node splits 'this' frag into two */ 261 /* The new node splits 'this' frag into two */
209 struct jffs2_node_frag *newfrag2 = jffs2_alloc_node_frag(); 262 struct jffs2_node_frag *newfrag2;
210 if (!newfrag2) { 263
211 jffs2_free_node_frag(newfrag);
212 return -ENOMEM;
213 }
214 if (this->node) 264 if (this->node)
215 JFFS2_DBG_FRAGTREE2("split old frag 0x%04x-0x%04x, phys 0x%08x\n", 265 JFFS2_DBG_FRAGTREE2("split old frag 0x%04x-0x%04x, phys 0x%08x\n",
216 this->ofs, this->ofs+this->size, ref_offset(this->node->raw)); 266 this->ofs, this->ofs+this->size, ref_offset(this->node->raw));
@@ -219,9 +269,10 @@ static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *l
219 this->ofs, this->ofs+this->size, ref_offset(this->node->raw)); 269 this->ofs, this->ofs+this->size, ref_offset(this->node->raw));
220 270
221 /* New second frag pointing to this's node */ 271 /* New second frag pointing to this's node */
222 newfrag2->ofs = newfrag->ofs + newfrag->size; 272 newfrag2 = new_fragment(this->node, newfrag->ofs + newfrag->size,
223 newfrag2->size = (this->ofs+this->size) - newfrag2->ofs; 273 this->ofs + this->size - newfrag->ofs - newfrag->size);
224 newfrag2->node = this->node; 274 if (unlikely(!newfrag2))
275 return -ENOMEM;
225 if (this->node) 276 if (this->node)
226 this->node->frags++; 277 this->node->frags++;
227 278
@@ -235,10 +286,10 @@ static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *l
235 'this' to insert newfrag, and a tree insert 286 'this' to insert newfrag, and a tree insert
236 from newfrag to insert newfrag2. */ 287 from newfrag to insert newfrag2. */
237 jffs2_fragtree_insert(newfrag, this); 288 jffs2_fragtree_insert(newfrag, this);
238 rb_insert_color(&newfrag->rb, list); 289 rb_insert_color(&newfrag->rb, root);
239 290
240 jffs2_fragtree_insert(newfrag2, newfrag); 291 jffs2_fragtree_insert(newfrag2, newfrag);
241 rb_insert_color(&newfrag2->rb, list); 292 rb_insert_color(&newfrag2->rb, root);
242 293
243 return 0; 294 return 0;
244 } 295 }
@@ -247,14 +298,14 @@ static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *l
247 298
248 /* Again, we know it lives down here in the tree */ 299 /* Again, we know it lives down here in the tree */
249 jffs2_fragtree_insert(newfrag, this); 300 jffs2_fragtree_insert(newfrag, this);
250 rb_insert_color(&newfrag->rb, list); 301 rb_insert_color(&newfrag->rb, root);
251 } else { 302 } else {
252 /* New frag starts at the same point as 'this' used to. Replace 303 /* New frag starts at the same point as 'this' used to. Replace
253 it in the tree without doing a delete and insertion */ 304 it in the tree without doing a delete and insertion */
254 JFFS2_DBG_FRAGTREE2("inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n", 305 JFFS2_DBG_FRAGTREE2("inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n",
255 newfrag, newfrag->ofs, newfrag->ofs+newfrag->size, this, this->ofs, this->ofs+this->size); 306 newfrag, newfrag->ofs, newfrag->ofs+newfrag->size, this, this->ofs, this->ofs+this->size);
256 307
257 rb_replace_node(&this->rb, &newfrag->rb, list); 308 rb_replace_node(&this->rb, &newfrag->rb, root);
258 309
259 if (newfrag->ofs + newfrag->size >= this->ofs+this->size) { 310 if (newfrag->ofs + newfrag->size >= this->ofs+this->size) {
260 JFFS2_DBG_FRAGTREE2("obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size); 311 JFFS2_DBG_FRAGTREE2("obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size);
@@ -264,7 +315,7 @@ static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *l
264 this->size -= newfrag->size; 315 this->size -= newfrag->size;
265 316
266 jffs2_fragtree_insert(this, newfrag); 317 jffs2_fragtree_insert(this, newfrag);
267 rb_insert_color(&this->rb, list); 318 rb_insert_color(&this->rb, root);
268 return 0; 319 return 0;
269 } 320 }
270 } 321 }
@@ -275,15 +326,15 @@ static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *l
275 /* 'this' frag is obsoleted completely. */ 326 /* 'this' frag is obsoleted completely. */
276 JFFS2_DBG_FRAGTREE2("obsoleting node frag %p (%x-%x) and removing from tree\n", 327 JFFS2_DBG_FRAGTREE2("obsoleting node frag %p (%x-%x) and removing from tree\n",
277 this, this->ofs, this->ofs+this->size); 328 this, this->ofs, this->ofs+this->size);
278 rb_erase(&this->rb, list); 329 rb_erase(&this->rb, root);
279 jffs2_obsolete_node_frag(c, this); 330 jffs2_obsolete_node_frag(c, this);
280 } 331 }
281 /* Now we're pointing at the first frag which isn't totally obsoleted by 332 /* Now we're pointing at the first frag which isn't totally obsoleted by
282 the new frag */ 333 the new frag */
283 334
284 if (!this || newfrag->ofs + newfrag->size == this->ofs) { 335 if (!this || newfrag->ofs + newfrag->size == this->ofs)
285 return 0; 336 return 0;
286 } 337
287 /* Still some overlap but we don't need to move it in the tree */ 338 /* Still some overlap but we don't need to move it in the tree */
288 this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size); 339 this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size);
289 this->ofs = newfrag->ofs + newfrag->size; 340 this->ofs = newfrag->ofs + newfrag->size;
@@ -296,8 +347,9 @@ static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *l
296 return 0; 347 return 0;
297} 348}
298 349
299/* Given an inode, probably with existing list of fragments, add the new node 350/*
300 * to the fragment list. 351 * Given an inode, probably with existing tree of fragments, add the new node
352 * to the fragment tree.
301 */ 353 */
302int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) 354int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn)
303{ 355{
@@ -307,18 +359,14 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in
307 if (unlikely(!fn->size)) 359 if (unlikely(!fn->size))
308 return 0; 360 return 0;
309 361
310 newfrag = jffs2_alloc_node_frag(); 362 newfrag = new_fragment(fn, fn->ofs, fn->size);
311 if (unlikely(!newfrag)) 363 if (unlikely(!newfrag))
312 return -ENOMEM; 364 return -ENOMEM;
365 newfrag->node->frags = 1;
313 366
314 JFFS2_DBG_FRAGTREE("adding node %#04x-%#04x @0x%08x on flash, newfrag *%p\n", 367 JFFS2_DBG_FRAGTREE("adding node %#04x-%#04x @0x%08x on flash, newfrag *%p\n",
315 fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag); 368 fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag);
316 369
317 newfrag->ofs = fn->ofs;
318 newfrag->size = fn->size;
319 newfrag->node = fn;
320 newfrag->node->frags = 1;
321
322 ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag); 370 ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag);
323 if (unlikely(ret)) 371 if (unlikely(ret))
324 return ret; 372 return ret;
@@ -344,10 +392,465 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in
344 } 392 }
345 } 393 }
346 jffs2_dbg_fragtree_paranoia_check_nolock(f); 394 jffs2_dbg_fragtree_paranoia_check_nolock(f);
347 jffs2_dbg_dump_fragtree_nolock(f); 395
396 return 0;
397}
398
399/*
400 * Check the data CRC of the node.
401 *
402 * Returns: 0 if the data CRC is correct;
403 * 1 - if incorrect;
404 * error code if an error occured.
405 */
406static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn)
407{
408 struct jffs2_raw_node_ref *ref = tn->fn->raw;
409 int err = 0, pointed = 0;
410 struct jffs2_eraseblock *jeb;
411 unsigned char *buffer;
412 uint32_t crc, ofs, retlen, len;
413
414 BUG_ON(tn->csize == 0);
415
416 /* Calculate how many bytes were already checked */
417 ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode);
418 len = ofs - (ofs & (PAGE_CACHE_SIZE - 1));
419 len = c->wbuf_pagesize - len;
420
421 if (len >= tn->csize) {
422 JFFS2_DBG_READINODE("no need to check node at %#08x, data length %u, data starts at %#08x - it has already been checked.\n",
423 ref_offset(ref), tn->csize, ofs);
424 goto adj_acc;
425 }
426
427 ofs += len;
428 len = tn->csize - len;
429
430 JFFS2_DBG_READINODE("check node at %#08x, data length %u, partial CRC %#08x, correct CRC %#08x, data starts at %#08x, start checking from %#08x - %u bytes.\n",
431 ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len);
432
433#ifndef __ECOS
434 /* TODO: instead, incapsulate point() stuff to jffs2_flash_read(),
435 * adding and jffs2_flash_read_end() interface. */
436 if (c->mtd->point) {
437 err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer);
438 if (!err && retlen < tn->csize) {
439 JFFS2_WARNING("MTD point returned len too short: %u instead of %u.\n", retlen, tn->csize);
440 c->mtd->unpoint(c->mtd, buffer, ofs, len);
441 } else if (err)
442 JFFS2_WARNING("MTD point failed: error code %d.\n", err);
443 else
444 pointed = 1; /* succefully pointed to device */
445 }
446#endif
447
448 if (!pointed) {
449 buffer = kmalloc(len, GFP_KERNEL);
450 if (unlikely(!buffer))
451 return -ENOMEM;
452
453 /* TODO: this is very frequent pattern, make it a separate
454 * routine */
455 err = jffs2_flash_read(c, ofs, len, &retlen, buffer);
456 if (err) {
457 JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err);
458 goto free_out;
459 }
460
461 if (retlen != len) {
462 JFFS2_ERROR("short read at %#08x: %d instead of %d.\n", ofs, retlen, len);
463 err = -EIO;
464 goto free_out;
465 }
466 }
467
468 /* Continue calculating CRC */
469 crc = crc32(tn->partial_crc, buffer, len);
470 if(!pointed)
471 kfree(buffer);
472#ifndef __ECOS
473 else
474 c->mtd->unpoint(c->mtd, buffer, ofs, len);
475#endif
476
477 if (crc != tn->data_crc) {
478 JFFS2_NOTICE("drong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n",
479 ofs, tn->data_crc, crc);
480 return 1;
481 }
482
483adj_acc:
484 jeb = &c->blocks[ref->flash_offset / c->sector_size];
485 len = ref_totlen(c, jeb, ref);
486
487 /*
488 * Mark the node as having been checked and fix the
489 * accounting accordingly.
490 */
491 spin_lock(&c->erase_completion_lock);
492 jeb->used_size += len;
493 jeb->unchecked_size -= len;
494 c->used_size += len;
495 c->unchecked_size -= len;
496 spin_unlock(&c->erase_completion_lock);
497
348 return 0; 498 return 0;
499
500free_out:
501 if(!pointed)
502 kfree(buffer);
503#ifndef __ECOS
504 else
505 c->mtd->unpoint(c->mtd, buffer, ofs, len);
506#endif
507 return err;
349} 508}
350 509
510/*
511 * Helper function for jffs2_add_older_frag_to_fragtree().
512 *
513 * Checks the node if we are in the checking stage.
514 */
515static inline int check_node(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn)
516{
517 int ret;
518
519 BUG_ON(ref_obsolete(tn->fn->raw));
520
521 /* We only check the data CRC of unchecked nodes */
522 if (ref_flags(tn->fn->raw) != REF_UNCHECKED)
523 return 0;
524
525 JFFS2_DBG_FRAGTREE2("check node %u-%u, phys offs %#08x.\n",
526 tn->fn->ofs, tn->fn->ofs + tn->fn->size,
527 ref_offset(tn->fn->raw));
528
529 ret = check_node_data(c, tn);
530 if (unlikely(ret < 0)) {
531 JFFS2_ERROR("check_node_data() returned error: %d.\n",
532 ret);
533 } else if (unlikely(ret > 0)) {
534 JFFS2_DBG_FRAGTREE2("CRC error, mark it obsolete.\n");
535 jffs2_mark_node_obsolete(c, tn->fn->raw);
536 }
537
538 return ret;
539}
540
541/*
542 * Helper function for jffs2_add_older_frag_to_fragtree().
543 *
544 * Called when the new fragment that is being inserted
545 * splits a hole fragment.
546 */
547static int split_hole(struct jffs2_sb_info *c, struct rb_root *root,
548 struct jffs2_node_frag *newfrag, struct jffs2_node_frag *hole)
549{
550 JFFS2_DBG_FRAGTREE2("fragment %#04x-%#04x splits the hole %#04x-%#04x\n",
551 newfrag->ofs, newfrag->ofs + newfrag->size, hole->ofs, hole->ofs + hole->size);
552
553 if (hole->ofs == newfrag->ofs) {
554 /*
555 * Well, the new fragment actually starts at the same offset as
556 * the hole.
557 */
558 if (hole->ofs + hole->size > newfrag->ofs + newfrag->size) {
559 /*
560 * We replace the overlapped left part of the hole by
561 * the new node.
562 */
563
564 JFFS2_DBG_FRAGTREE2("insert fragment %#04x-%#04x and cut the left part of the hole\n",
565 newfrag->ofs, newfrag->ofs + newfrag->size);
566 rb_replace_node(&hole->rb, &newfrag->rb, root);
567
568 hole->ofs += newfrag->size;
569 hole->size -= newfrag->size;
570
571 /*
572 * We know that 'hole' should be the right hand
573 * fragment.
574 */
575 jffs2_fragtree_insert(hole, newfrag);
576 rb_insert_color(&hole->rb, root);
577 } else {
578 /*
579 * Ah, the new fragment is of the same size as the hole.
580 * Relace the hole by it.
581 */
582 JFFS2_DBG_FRAGTREE2("insert fragment %#04x-%#04x and overwrite hole\n",
583 newfrag->ofs, newfrag->ofs + newfrag->size);
584 rb_replace_node(&hole->rb, &newfrag->rb, root);
585 jffs2_free_node_frag(hole);
586 }
587 } else {
588 /* The new fragment lefts some hole space at the left */
589
590 struct jffs2_node_frag * newfrag2 = NULL;
591
592 if (hole->ofs + hole->size > newfrag->ofs + newfrag->size) {
593 /* The new frag also lefts some space at the right */
594 newfrag2 = new_fragment(NULL, newfrag->ofs +
595 newfrag->size, hole->ofs + hole->size
596 - newfrag->ofs - newfrag->size);
597 if (unlikely(!newfrag2)) {
598 jffs2_free_node_frag(newfrag);
599 return -ENOMEM;
600 }
601 }
602
603 hole->size = newfrag->ofs - hole->ofs;
604 JFFS2_DBG_FRAGTREE2("left the hole %#04x-%#04x at the left and inserd fragment %#04x-%#04x\n",
605 hole->ofs, hole->ofs + hole->size, newfrag->ofs, newfrag->ofs + newfrag->size);
606
607 jffs2_fragtree_insert(newfrag, hole);
608 rb_insert_color(&newfrag->rb, root);
609
610 if (newfrag2) {
611 JFFS2_DBG_FRAGTREE2("left the hole %#04x-%#04x at the right\n",
612 newfrag2->ofs, newfrag2->ofs + newfrag2->size);
613 jffs2_fragtree_insert(newfrag2, newfrag);
614 rb_insert_color(&newfrag2->rb, root);
615 }
616 }
617
618 return 0;
619}
620
621/*
622 * This function is used when we build inode. It expects the nodes are passed
623 * in the decreasing version order. The whole point of this is to improve the
624 * inodes checking on NAND: we check the nodes' data CRC only when they are not
625 * obsoleted. Previously, add_frag_to_fragtree() function was used and
626 * nodes were passed to it in the increasing version ordes and CRCs of all
627 * nodes were checked.
628 *
629 * Note: tn->fn->size shouldn't be zero.
630 *
631 * Returns 0 if the node was inserted
632 * 1 if it wasn't inserted (since it is obsolete)
633 * < 0 an if error occured
634 */
635int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
636 struct jffs2_tmp_dnode_info *tn)
637{
638 struct jffs2_node_frag *this, *newfrag;
639 uint32_t lastend;
640 struct jffs2_full_dnode *fn = tn->fn;
641 struct rb_root *root = &f->fragtree;
642 uint32_t fn_size = fn->size, fn_ofs = fn->ofs;
643 int err, checked = 0;
644 int ref_flag;
645
646 JFFS2_DBG_FRAGTREE("insert fragment %#04x-%#04x\n", fn_ofs, fn_ofs + fn_size);
647
648 /* Skip all the nodes which are completed before this one starts */
649 this = jffs2_lookup_node_frag(root, fn_ofs);
650 if (this)
651 JFFS2_DBG_FRAGTREE2("'this' found %#04x-%#04x (%s)\n", this->ofs, this->ofs + this->size, this->node ? "data" : "hole");
652
653 if (this)
654 lastend = this->ofs + this->size;
655 else
656 lastend = 0;
657
658 /* Detect the preliminary type of node */
659 if (fn->size >= PAGE_CACHE_SIZE)
660 ref_flag = REF_PRISTINE;
661 else
662 ref_flag = REF_NORMAL;
663
664 /* See if we ran off the end of the root */
665 if (lastend <= fn_ofs) {
666 /* We did */
667
668 /*
669 * We are going to insert the new node into the
670 * fragment tree, so check it.
671 */
672 err = check_node(c, f, tn);
673 if (err != 0)
674 return err;
675
676 fn->frags = 1;
677
678 newfrag = new_fragment(fn, fn_ofs, fn_size);
679 if (unlikely(!newfrag))
680 return -ENOMEM;
681
682 err = no_overlapping_node(c, root, newfrag, this, lastend);
683 if (unlikely(err != 0)) {
684 jffs2_free_node_frag(newfrag);
685 return err;
686 }
687
688 goto out_ok;
689 }
690
691 fn->frags = 0;
692
693 while (1) {
694 /*
695 * Here we have:
696 * fn_ofs < this->ofs + this->size && fn_ofs >= this->ofs.
697 *
698 * Remember, 'this' has higher version, any non-hole node
699 * which is already in the fragtree is newer then the newly
700 * inserted.
701 */
702 if (!this->node) {
703 /*
704 * 'this' is the hole fragment, so at least the
705 * beginning of the new fragment is valid.
706 */
707
708 /*
709 * We are going to insert the new node into the
710 * fragment tree, so check it.
711 */
712 if (!checked) {
713 err = check_node(c, f, tn);
714 if (unlikely(err != 0))
715 return err;
716 checked = 1;
717 }
718
719 if (this->ofs + this->size >= fn_ofs + fn_size) {
720 /* We split the hole on two parts */
721
722 fn->frags += 1;
723 newfrag = new_fragment(fn, fn_ofs, fn_size);
724 if (unlikely(!newfrag))
725 return -ENOMEM;
726
727 err = split_hole(c, root, newfrag, this);
728 if (unlikely(err))
729 return err;
730 goto out_ok;
731 }
732
733 /*
734 * The beginning of the new fragment is valid since it
735 * overlaps the hole node.
736 */
737
738 ref_flag = REF_NORMAL;
739
740 fn->frags += 1;
741 newfrag = new_fragment(fn, fn_ofs,
742 this->ofs + this->size - fn_ofs);
743 if (unlikely(!newfrag))
744 return -ENOMEM;
745
746 if (fn_ofs == this->ofs) {
747 /*
748 * The new node starts at the same offset as
749 * the hole and supersieds the hole.
750 */
751 JFFS2_DBG_FRAGTREE2("add the new fragment instead of hole %#04x-%#04x, refcnt %d\n",
752 fn_ofs, fn_ofs + this->ofs + this->size - fn_ofs, fn->frags);
753
754 rb_replace_node(&this->rb, &newfrag->rb, root);
755 jffs2_free_node_frag(this);
756 } else {
757 /*
758 * The hole becomes shorter as its right part
759 * is supersieded by the new fragment.
760 */
761 JFFS2_DBG_FRAGTREE2("reduce size of hole %#04x-%#04x to %#04x-%#04x\n",
762 this->ofs, this->ofs + this->size, this->ofs, this->ofs + this->size - newfrag->size);
763
764 JFFS2_DBG_FRAGTREE2("add new fragment %#04x-%#04x, refcnt %d\n", fn_ofs,
765 fn_ofs + this->ofs + this->size - fn_ofs, fn->frags);
766
767 this->size -= newfrag->size;
768 jffs2_fragtree_insert(newfrag, this);
769 rb_insert_color(&newfrag->rb, root);
770 }
771
772 fn_ofs += newfrag->size;
773 fn_size -= newfrag->size;
774 this = rb_entry(rb_next(&newfrag->rb),
775 struct jffs2_node_frag, rb);
776
777 JFFS2_DBG_FRAGTREE2("switch to the next 'this' fragment: %#04x-%#04x %s\n",
778 this->ofs, this->ofs + this->size, this->node ? "(data)" : "(hole)");
779 }
780
781 /*
782 * 'This' node is not the hole so it obsoletes the new fragment
783 * either fully or partially.
784 */
785 if (this->ofs + this->size >= fn_ofs + fn_size) {
786 /* The new node is obsolete, drop it */
787 if (fn->frags == 0) {
788 JFFS2_DBG_FRAGTREE2("%#04x-%#04x is obsolete, mark it obsolete\n", fn_ofs, fn_ofs + fn_size);
789 ref_flag = REF_OBSOLETE;
790 }
791 goto out_ok;
792 } else {
793 struct jffs2_node_frag *new_this;
794
795 /* 'This' node obsoletes the beginning of the new node */
796 JFFS2_DBG_FRAGTREE2("the beginning %#04x-%#04x is obsolete\n", fn_ofs, this->ofs + this->size);
797
798 ref_flag = REF_NORMAL;
799
800 fn_size -= this->ofs + this->size - fn_ofs;
801 fn_ofs = this->ofs + this->size;
802 JFFS2_DBG_FRAGTREE2("now considering %#04x-%#04x\n", fn_ofs, fn_ofs + fn_size);
803
804 new_this = rb_entry(rb_next(&this->rb), struct jffs2_node_frag, rb);
805 if (!new_this) {
806 /*
807 * There is no next fragment. Add the rest of
808 * the new node as the right-hand child.
809 */
810 if (!checked) {
811 err = check_node(c, f, tn);
812 if (unlikely(err != 0))
813 return err;
814 checked = 1;
815 }
816
817 fn->frags += 1;
818 newfrag = new_fragment(fn, fn_ofs, fn_size);
819 if (unlikely(!newfrag))
820 return -ENOMEM;
821
822 JFFS2_DBG_FRAGTREE2("there are no more fragments, insert %#04x-%#04x\n",
823 newfrag->ofs, newfrag->ofs + newfrag->size);
824 rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right);
825 rb_insert_color(&newfrag->rb, root);
826 goto out_ok;
827 } else {
828 this = new_this;
829 JFFS2_DBG_FRAGTREE2("switch to the next 'this' fragment: %#04x-%#04x %s\n",
830 this->ofs, this->ofs + this->size, this->node ? "(data)" : "(hole)");
831 }
832 }
833 }
834
835out_ok:
836 BUG_ON(fn->size < PAGE_CACHE_SIZE && ref_flag == REF_PRISTINE);
837
838 if (ref_flag == REF_OBSOLETE) {
839 JFFS2_DBG_FRAGTREE2("the node is obsolete now\n");
840 /* jffs2_mark_node_obsolete() will adjust space accounting */
841 jffs2_mark_node_obsolete(c, fn->raw);
842 return 1;
843 }
844
845 JFFS2_DBG_FRAGTREE2("the node is \"%s\" now\n", ref_flag == REF_NORMAL ? "REF_NORMAL" : "REF_PRISTINE");
846
847 /* Space accounting was adjusted at check_node_data() */
848 spin_lock(&c->erase_completion_lock);
849 fn->raw->flash_offset = ref_offset(fn->raw) | ref_flag;
850 spin_unlock(&c->erase_completion_lock);
851
852 return 0;
853}
351 854
352void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state) 855void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state)
353{ 856{