diff options
Diffstat (limited to 'fs/jffs2/wbuf.c')
-rw-r--r-- | fs/jffs2/wbuf.c | 968 |
1 files changed, 485 insertions, 483 deletions
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 4cebf0e57c46..a7f153f79ecb 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
@@ -156,69 +156,130 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
156 | jffs2_erase_pending_trigger(c); | 156 | jffs2_erase_pending_trigger(c); |
157 | } | 157 | } |
158 | 158 | ||
159 | /* Adjust its size counts accordingly */ | 159 | if (!jffs2_prealloc_raw_node_refs(c, jeb, 1)) { |
160 | c->wasted_size += jeb->free_size; | 160 | uint32_t oldfree = jeb->free_size; |
161 | c->free_size -= jeb->free_size; | 161 | |
162 | jeb->wasted_size += jeb->free_size; | 162 | jffs2_link_node_ref(c, jeb, |
163 | jeb->free_size = 0; | 163 | (jeb->offset+c->sector_size-oldfree) | REF_OBSOLETE, |
164 | oldfree, NULL); | ||
165 | /* convert to wasted */ | ||
166 | c->wasted_size += oldfree; | ||
167 | jeb->wasted_size += oldfree; | ||
168 | c->dirty_size -= oldfree; | ||
169 | jeb->dirty_size -= oldfree; | ||
170 | } | ||
164 | 171 | ||
165 | jffs2_dbg_dump_block_lists_nolock(c); | 172 | jffs2_dbg_dump_block_lists_nolock(c); |
166 | jffs2_dbg_acct_sanity_check_nolock(c,jeb); | 173 | jffs2_dbg_acct_sanity_check_nolock(c,jeb); |
167 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); | 174 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); |
168 | } | 175 | } |
169 | 176 | ||
177 | static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info *c, | ||
178 | struct jffs2_inode_info *f, | ||
179 | struct jffs2_raw_node_ref *raw, | ||
180 | union jffs2_node_union *node) | ||
181 | { | ||
182 | struct jffs2_node_frag *frag; | ||
183 | struct jffs2_full_dirent *fd; | ||
184 | |||
185 | dbg_noderef("incore_replace_raw: node at %p is {%04x,%04x}\n", | ||
186 | node, je16_to_cpu(node->u.magic), je16_to_cpu(node->u.nodetype)); | ||
187 | |||
188 | BUG_ON(je16_to_cpu(node->u.magic) != 0x1985 && | ||
189 | je16_to_cpu(node->u.magic) != 0); | ||
190 | |||
191 | switch (je16_to_cpu(node->u.nodetype)) { | ||
192 | case JFFS2_NODETYPE_INODE: | ||
193 | if (f->metadata && f->metadata->raw == raw) { | ||
194 | dbg_noderef("Will replace ->raw in f->metadata at %p\n", f->metadata); | ||
195 | return &f->metadata->raw; | ||
196 | } | ||
197 | frag = jffs2_lookup_node_frag(&f->fragtree, je32_to_cpu(node->i.offset)); | ||
198 | BUG_ON(!frag); | ||
199 | /* Find a frag which refers to the full_dnode we want to modify */ | ||
200 | while (!frag->node || frag->node->raw != raw) { | ||
201 | frag = frag_next(frag); | ||
202 | BUG_ON(!frag); | ||
203 | } | ||
204 | dbg_noderef("Will replace ->raw in full_dnode at %p\n", frag->node); | ||
205 | return &frag->node->raw; | ||
206 | |||
207 | case JFFS2_NODETYPE_DIRENT: | ||
208 | for (fd = f->dents; fd; fd = fd->next) { | ||
209 | if (fd->raw == raw) { | ||
210 | dbg_noderef("Will replace ->raw in full_dirent at %p\n", fd); | ||
211 | return &fd->raw; | ||
212 | } | ||
213 | } | ||
214 | BUG(); | ||
215 | |||
216 | default: | ||
217 | dbg_noderef("Don't care about replacing raw for nodetype %x\n", | ||
218 | je16_to_cpu(node->u.nodetype)); | ||
219 | break; | ||
220 | } | ||
221 | return NULL; | ||
222 | } | ||
223 | |||
170 | /* Recover from failure to write wbuf. Recover the nodes up to the | 224 | /* Recover from failure to write wbuf. Recover the nodes up to the |
171 | * wbuf, not the one which we were starting to try to write. */ | 225 | * wbuf, not the one which we were starting to try to write. */ |
172 | 226 | ||
173 | static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | 227 | static void jffs2_wbuf_recover(struct jffs2_sb_info *c) |
174 | { | 228 | { |
175 | struct jffs2_eraseblock *jeb, *new_jeb; | 229 | struct jffs2_eraseblock *jeb, *new_jeb; |
176 | struct jffs2_raw_node_ref **first_raw, **raw; | 230 | struct jffs2_raw_node_ref *raw, *next, *first_raw = NULL; |
177 | size_t retlen; | 231 | size_t retlen; |
178 | int ret; | 232 | int ret; |
233 | int nr_refile = 0; | ||
179 | unsigned char *buf; | 234 | unsigned char *buf; |
180 | uint32_t start, end, ofs, len; | 235 | uint32_t start, end, ofs, len; |
181 | 236 | ||
182 | spin_lock(&c->erase_completion_lock); | ||
183 | |||
184 | jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; | 237 | jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; |
185 | 238 | ||
239 | spin_lock(&c->erase_completion_lock); | ||
186 | jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); | 240 | jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); |
241 | spin_unlock(&c->erase_completion_lock); | ||
242 | |||
243 | BUG_ON(!ref_obsolete(jeb->last_node)); | ||
187 | 244 | ||
188 | /* Find the first node to be recovered, by skipping over every | 245 | /* Find the first node to be recovered, by skipping over every |
189 | node which ends before the wbuf starts, or which is obsolete. */ | 246 | node which ends before the wbuf starts, or which is obsolete. */ |
190 | first_raw = &jeb->first_node; | 247 | for (next = raw = jeb->first_node; next; raw = next) { |
191 | while (*first_raw && | 248 | next = ref_next(raw); |
192 | (ref_obsolete(*first_raw) || | 249 | |
193 | (ref_offset(*first_raw)+ref_totlen(c, jeb, *first_raw)) < c->wbuf_ofs)) { | 250 | if (ref_obsolete(raw) || |
194 | D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n", | 251 | (next && ref_offset(next) <= c->wbuf_ofs)) { |
195 | ref_offset(*first_raw), ref_flags(*first_raw), | 252 | dbg_noderef("Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n", |
196 | (ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw)), | 253 | ref_offset(raw), ref_flags(raw), |
197 | c->wbuf_ofs)); | 254 | (ref_offset(raw) + ref_totlen(c, jeb, raw)), |
198 | first_raw = &(*first_raw)->next_phys; | 255 | c->wbuf_ofs); |
256 | continue; | ||
257 | } | ||
258 | dbg_noderef("First node to be recovered is at 0x%08x(%d)-0x%08x\n", | ||
259 | ref_offset(raw), ref_flags(raw), | ||
260 | (ref_offset(raw) + ref_totlen(c, jeb, raw))); | ||
261 | |||
262 | first_raw = raw; | ||
263 | break; | ||
199 | } | 264 | } |
200 | 265 | ||
201 | if (!*first_raw) { | 266 | if (!first_raw) { |
202 | /* All nodes were obsolete. Nothing to recover. */ | 267 | /* All nodes were obsolete. Nothing to recover. */ |
203 | D1(printk(KERN_DEBUG "No non-obsolete nodes to be recovered. Just filing block bad\n")); | 268 | D1(printk(KERN_DEBUG "No non-obsolete nodes to be recovered. Just filing block bad\n")); |
204 | spin_unlock(&c->erase_completion_lock); | 269 | c->wbuf_len = 0; |
205 | return; | 270 | return; |
206 | } | 271 | } |
207 | 272 | ||
208 | start = ref_offset(*first_raw); | 273 | start = ref_offset(first_raw); |
209 | end = ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw); | 274 | end = ref_offset(jeb->last_node); |
210 | 275 | nr_refile = 1; | |
211 | /* Find the last node to be recovered */ | ||
212 | raw = first_raw; | ||
213 | while ((*raw)) { | ||
214 | if (!ref_obsolete(*raw)) | ||
215 | end = ref_offset(*raw) + ref_totlen(c, jeb, *raw); | ||
216 | 276 | ||
217 | raw = &(*raw)->next_phys; | 277 | /* Count the number of refs which need to be copied */ |
218 | } | 278 | while ((raw = ref_next(raw)) != jeb->last_node) |
219 | spin_unlock(&c->erase_completion_lock); | 279 | nr_refile++; |
220 | 280 | ||
221 | D1(printk(KERN_DEBUG "wbuf recover %08x-%08x\n", start, end)); | 281 | dbg_noderef("wbuf recover %08x-%08x (%d bytes in %d nodes)\n", |
282 | start, end, end - start, nr_refile); | ||
222 | 283 | ||
223 | buf = NULL; | 284 | buf = NULL; |
224 | if (start < c->wbuf_ofs) { | 285 | if (start < c->wbuf_ofs) { |
@@ -233,28 +294,37 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
233 | } | 294 | } |
234 | 295 | ||
235 | /* Do the read... */ | 296 | /* Do the read... */ |
236 | if (jffs2_cleanmarker_oob(c)) | 297 | ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf); |
237 | ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo); | ||
238 | else | ||
239 | ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf); | ||
240 | 298 | ||
241 | if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) { | 299 | /* ECC recovered ? */ |
242 | /* ECC recovered */ | 300 | if ((ret == -EUCLEAN || ret == -EBADMSG) && |
301 | (retlen == c->wbuf_ofs - start)) | ||
243 | ret = 0; | 302 | ret = 0; |
244 | } | 303 | |
245 | if (ret || retlen != c->wbuf_ofs - start) { | 304 | if (ret || retlen != c->wbuf_ofs - start) { |
246 | printk(KERN_CRIT "Old data are already lost in wbuf recovery. Data loss ensues.\n"); | 305 | printk(KERN_CRIT "Old data are already lost in wbuf recovery. Data loss ensues.\n"); |
247 | 306 | ||
248 | kfree(buf); | 307 | kfree(buf); |
249 | buf = NULL; | 308 | buf = NULL; |
250 | read_failed: | 309 | read_failed: |
251 | first_raw = &(*first_raw)->next_phys; | 310 | first_raw = ref_next(first_raw); |
311 | nr_refile--; | ||
312 | while (first_raw && ref_obsolete(first_raw)) { | ||
313 | first_raw = ref_next(first_raw); | ||
314 | nr_refile--; | ||
315 | } | ||
316 | |||
252 | /* If this was the only node to be recovered, give up */ | 317 | /* If this was the only node to be recovered, give up */ |
253 | if (!(*first_raw)) | 318 | if (!first_raw) { |
319 | c->wbuf_len = 0; | ||
254 | return; | 320 | return; |
321 | } | ||
255 | 322 | ||
256 | /* It wasn't. Go on and try to recover nodes complete in the wbuf */ | 323 | /* It wasn't. Go on and try to recover nodes complete in the wbuf */ |
257 | start = ref_offset(*first_raw); | 324 | start = ref_offset(first_raw); |
325 | dbg_noderef("wbuf now recover %08x-%08x (%d bytes in %d nodes)\n", | ||
326 | start, end, end - start, nr_refile); | ||
327 | |||
258 | } else { | 328 | } else { |
259 | /* Read succeeded. Copy the remaining data from the wbuf */ | 329 | /* Read succeeded. Copy the remaining data from the wbuf */ |
260 | memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs); | 330 | memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs); |
@@ -263,14 +333,23 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
263 | /* OK... we're to rewrite (end-start) bytes of data from first_raw onwards. | 333 | /* OK... we're to rewrite (end-start) bytes of data from first_raw onwards. |
264 | Either 'buf' contains the data, or we find it in the wbuf */ | 334 | Either 'buf' contains the data, or we find it in the wbuf */ |
265 | 335 | ||
266 | |||
267 | /* ... and get an allocation of space from a shiny new block instead */ | 336 | /* ... and get an allocation of space from a shiny new block instead */ |
268 | ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len, JFFS2_SUMMARY_NOSUM_SIZE); | 337 | ret = jffs2_reserve_space_gc(c, end-start, &len, JFFS2_SUMMARY_NOSUM_SIZE); |
269 | if (ret) { | 338 | if (ret) { |
270 | printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n"); | 339 | printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n"); |
271 | kfree(buf); | 340 | kfree(buf); |
272 | return; | 341 | return; |
273 | } | 342 | } |
343 | |||
344 | ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, nr_refile); | ||
345 | if (ret) { | ||
346 | printk(KERN_WARNING "Failed to allocate node refs for wbuf recovery. Data loss ensues.\n"); | ||
347 | kfree(buf); | ||
348 | return; | ||
349 | } | ||
350 | |||
351 | ofs = write_ofs(c); | ||
352 | |||
274 | if (end-start >= c->wbuf_pagesize) { | 353 | if (end-start >= c->wbuf_pagesize) { |
275 | /* Need to do another write immediately, but it's possible | 354 | /* Need to do another write immediately, but it's possible |
276 | that this is just because the wbuf itself is completely | 355 | that this is just because the wbuf itself is completely |
@@ -288,36 +367,22 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
288 | if (breakme++ == 20) { | 367 | if (breakme++ == 20) { |
289 | printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs); | 368 | printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs); |
290 | breakme = 0; | 369 | breakme = 0; |
291 | c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, | 370 | c->mtd->write(c->mtd, ofs, towrite, &retlen, |
292 | brokenbuf, NULL, c->oobinfo); | 371 | brokenbuf); |
293 | ret = -EIO; | 372 | ret = -EIO; |
294 | } else | 373 | } else |
295 | #endif | 374 | #endif |
296 | if (jffs2_cleanmarker_oob(c)) | 375 | ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, |
297 | ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, | 376 | rewrite_buf); |
298 | rewrite_buf, NULL, c->oobinfo); | ||
299 | else | ||
300 | ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, rewrite_buf); | ||
301 | 377 | ||
302 | if (ret || retlen != towrite) { | 378 | if (ret || retlen != towrite) { |
303 | /* Argh. We tried. Really we did. */ | 379 | /* Argh. We tried. Really we did. */ |
304 | printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n"); | 380 | printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n"); |
305 | kfree(buf); | 381 | kfree(buf); |
306 | 382 | ||
307 | if (retlen) { | 383 | if (retlen) |
308 | struct jffs2_raw_node_ref *raw2; | 384 | jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, first_raw), NULL); |
309 | |||
310 | raw2 = jffs2_alloc_raw_node_ref(); | ||
311 | if (!raw2) | ||
312 | return; | ||
313 | 385 | ||
314 | raw2->flash_offset = ofs | REF_OBSOLETE; | ||
315 | raw2->__totlen = ref_totlen(c, jeb, *first_raw); | ||
316 | raw2->next_phys = NULL; | ||
317 | raw2->next_in_ino = NULL; | ||
318 | |||
319 | jffs2_add_physical_node_ref(c, raw2); | ||
320 | } | ||
321 | return; | 386 | return; |
322 | } | 387 | } |
323 | printk(KERN_NOTICE "Recovery of wbuf succeeded to %08x\n", ofs); | 388 | printk(KERN_NOTICE "Recovery of wbuf succeeded to %08x\n", ofs); |
@@ -326,12 +391,10 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
326 | c->wbuf_ofs = ofs + towrite; | 391 | c->wbuf_ofs = ofs + towrite; |
327 | memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len); | 392 | memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len); |
328 | /* Don't muck about with c->wbuf_inodes. False positives are harmless. */ | 393 | /* Don't muck about with c->wbuf_inodes. False positives are harmless. */ |
329 | kfree(buf); | ||
330 | } else { | 394 | } else { |
331 | /* OK, now we're left with the dregs in whichever buffer we're using */ | 395 | /* OK, now we're left with the dregs in whichever buffer we're using */ |
332 | if (buf) { | 396 | if (buf) { |
333 | memcpy(c->wbuf, buf, end-start); | 397 | memcpy(c->wbuf, buf, end-start); |
334 | kfree(buf); | ||
335 | } else { | 398 | } else { |
336 | memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start); | 399 | memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start); |
337 | } | 400 | } |
@@ -343,62 +406,111 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
343 | new_jeb = &c->blocks[ofs / c->sector_size]; | 406 | new_jeb = &c->blocks[ofs / c->sector_size]; |
344 | 407 | ||
345 | spin_lock(&c->erase_completion_lock); | 408 | spin_lock(&c->erase_completion_lock); |
346 | if (new_jeb->first_node) { | 409 | for (raw = first_raw; raw != jeb->last_node; raw = ref_next(raw)) { |
347 | /* Odd, but possible with ST flash later maybe */ | 410 | uint32_t rawlen = ref_totlen(c, jeb, raw); |
348 | new_jeb->last_node->next_phys = *first_raw; | 411 | struct jffs2_inode_cache *ic; |
349 | } else { | 412 | struct jffs2_raw_node_ref *new_ref; |
350 | new_jeb->first_node = *first_raw; | 413 | struct jffs2_raw_node_ref **adjust_ref = NULL; |
351 | } | 414 | struct jffs2_inode_info *f = NULL; |
352 | |||
353 | raw = first_raw; | ||
354 | while (*raw) { | ||
355 | uint32_t rawlen = ref_totlen(c, jeb, *raw); | ||
356 | 415 | ||
357 | D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n", | 416 | D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n", |
358 | rawlen, ref_offset(*raw), ref_flags(*raw), ofs)); | 417 | rawlen, ref_offset(raw), ref_flags(raw), ofs)); |
418 | |||
419 | ic = jffs2_raw_ref_to_ic(raw); | ||
420 | |||
421 | /* Ick. This XATTR mess should be fixed shortly... */ | ||
422 | if (ic && ic->class == RAWNODE_CLASS_XATTR_DATUM) { | ||
423 | struct jffs2_xattr_datum *xd = (void *)ic; | ||
424 | BUG_ON(xd->node != raw); | ||
425 | adjust_ref = &xd->node; | ||
426 | raw->next_in_ino = NULL; | ||
427 | ic = NULL; | ||
428 | } else if (ic && ic->class == RAWNODE_CLASS_XATTR_REF) { | ||
429 | struct jffs2_xattr_datum *xr = (void *)ic; | ||
430 | BUG_ON(xr->node != raw); | ||
431 | adjust_ref = &xr->node; | ||
432 | raw->next_in_ino = NULL; | ||
433 | ic = NULL; | ||
434 | } else if (ic && ic->class == RAWNODE_CLASS_INODE_CACHE) { | ||
435 | struct jffs2_raw_node_ref **p = &ic->nodes; | ||
436 | |||
437 | /* Remove the old node from the per-inode list */ | ||
438 | while (*p && *p != (void *)ic) { | ||
439 | if (*p == raw) { | ||
440 | (*p) = (raw->next_in_ino); | ||
441 | raw->next_in_ino = NULL; | ||
442 | break; | ||
443 | } | ||
444 | p = &((*p)->next_in_ino); | ||
445 | } | ||
359 | 446 | ||
360 | if (ref_obsolete(*raw)) { | 447 | if (ic->state == INO_STATE_PRESENT && !ref_obsolete(raw)) { |
361 | /* Shouldn't really happen much */ | 448 | /* If it's an in-core inode, then we have to adjust any |
362 | new_jeb->dirty_size += rawlen; | 449 | full_dirent or full_dnode structure to point to the |
363 | new_jeb->free_size -= rawlen; | 450 | new version instead of the old */ |
364 | c->dirty_size += rawlen; | 451 | f = jffs2_gc_fetch_inode(c, ic->ino, ic->nlink); |
365 | } else { | 452 | if (IS_ERR(f)) { |
366 | new_jeb->used_size += rawlen; | 453 | /* Should never happen; it _must_ be present */ |
367 | new_jeb->free_size -= rawlen; | 454 | JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n", |
455 | ic->ino, PTR_ERR(f)); | ||
456 | BUG(); | ||
457 | } | ||
458 | /* We don't lock f->sem. There's a number of ways we could | ||
459 | end up in here with it already being locked, and nobody's | ||
460 | going to modify it on us anyway because we hold the | ||
461 | alloc_sem. We're only changing one ->raw pointer too, | ||
462 | which we can get away with without upsetting readers. */ | ||
463 | adjust_ref = jffs2_incore_replace_raw(c, f, raw, | ||
464 | (void *)(buf?:c->wbuf) + (ref_offset(raw) - start)); | ||
465 | } else if (unlikely(ic->state != INO_STATE_PRESENT && | ||
466 | ic->state != INO_STATE_CHECKEDABSENT && | ||
467 | ic->state != INO_STATE_GC)) { | ||
468 | JFFS2_ERROR("Inode #%u is in strange state %d!\n", ic->ino, ic->state); | ||
469 | BUG(); | ||
470 | } | ||
471 | } | ||
472 | |||
473 | new_ref = jffs2_link_node_ref(c, new_jeb, ofs | ref_flags(raw), rawlen, ic); | ||
474 | |||
475 | if (adjust_ref) { | ||
476 | BUG_ON(*adjust_ref != raw); | ||
477 | *adjust_ref = new_ref; | ||
478 | } | ||
479 | if (f) | ||
480 | jffs2_gc_release_inode(c, f); | ||
481 | |||
482 | if (!ref_obsolete(raw)) { | ||
368 | jeb->dirty_size += rawlen; | 483 | jeb->dirty_size += rawlen; |
369 | jeb->used_size -= rawlen; | 484 | jeb->used_size -= rawlen; |
370 | c->dirty_size += rawlen; | 485 | c->dirty_size += rawlen; |
486 | c->used_size -= rawlen; | ||
487 | raw->flash_offset = ref_offset(raw) | REF_OBSOLETE; | ||
488 | BUG_ON(raw->next_in_ino); | ||
371 | } | 489 | } |
372 | c->free_size -= rawlen; | ||
373 | (*raw)->flash_offset = ofs | ref_flags(*raw); | ||
374 | ofs += rawlen; | 490 | ofs += rawlen; |
375 | new_jeb->last_node = *raw; | ||
376 | |||
377 | raw = &(*raw)->next_phys; | ||
378 | } | 491 | } |
379 | 492 | ||
493 | kfree(buf); | ||
494 | |||
380 | /* Fix up the original jeb now it's on the bad_list */ | 495 | /* Fix up the original jeb now it's on the bad_list */ |
381 | *first_raw = NULL; | 496 | if (first_raw == jeb->first_node) { |
382 | if (first_raw == &jeb->first_node) { | ||
383 | jeb->last_node = NULL; | ||
384 | D1(printk(KERN_DEBUG "Failing block at %08x is now empty. Moving to erase_pending_list\n", jeb->offset)); | 497 | D1(printk(KERN_DEBUG "Failing block at %08x is now empty. Moving to erase_pending_list\n", jeb->offset)); |
385 | list_del(&jeb->list); | 498 | list_del(&jeb->list); |
386 | list_add(&jeb->list, &c->erase_pending_list); | 499 | list_add(&jeb->list, &c->erase_pending_list); |
387 | c->nr_erasing_blocks++; | 500 | c->nr_erasing_blocks++; |
388 | jffs2_erase_pending_trigger(c); | 501 | jffs2_erase_pending_trigger(c); |
389 | } | 502 | } |
390 | else | ||
391 | jeb->last_node = container_of(first_raw, struct jffs2_raw_node_ref, next_phys); | ||
392 | 503 | ||
393 | jffs2_dbg_acct_sanity_check_nolock(c, jeb); | 504 | jffs2_dbg_acct_sanity_check_nolock(c, jeb); |
394 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); | 505 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); |
395 | 506 | ||
396 | jffs2_dbg_acct_sanity_check_nolock(c, new_jeb); | 507 | jffs2_dbg_acct_sanity_check_nolock(c, new_jeb); |
397 | jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb); | 508 | jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb); |
398 | 509 | ||
399 | spin_unlock(&c->erase_completion_lock); | 510 | spin_unlock(&c->erase_completion_lock); |
400 | 511 | ||
401 | D1(printk(KERN_DEBUG "wbuf recovery completed OK\n")); | 512 | D1(printk(KERN_DEBUG "wbuf recovery completed OK. wbuf_ofs 0x%08x, len 0x%x\n", c->wbuf_ofs, c->wbuf_len)); |
513 | |||
402 | } | 514 | } |
403 | 515 | ||
404 | /* Meaning of pad argument: | 516 | /* Meaning of pad argument: |
@@ -412,6 +524,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
412 | 524 | ||
413 | static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | 525 | static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) |
414 | { | 526 | { |
527 | struct jffs2_eraseblock *wbuf_jeb; | ||
415 | int ret; | 528 | int ret; |
416 | size_t retlen; | 529 | size_t retlen; |
417 | 530 | ||
@@ -429,6 +542,10 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
429 | if (!c->wbuf_len) /* already checked c->wbuf above */ | 542 | if (!c->wbuf_len) /* already checked c->wbuf above */ |
430 | return 0; | 543 | return 0; |
431 | 544 | ||
545 | wbuf_jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; | ||
546 | if (jffs2_prealloc_raw_node_refs(c, wbuf_jeb, c->nextblock->allocated_refs + 1)) | ||
547 | return -ENOMEM; | ||
548 | |||
432 | /* claim remaining space on the page | 549 | /* claim remaining space on the page |
433 | this happens, if we have a change to a new block, | 550 | this happens, if we have a change to a new block, |
434 | or if fsync forces us to flush the writebuffer. | 551 | or if fsync forces us to flush the writebuffer. |
@@ -458,15 +575,12 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
458 | if (breakme++ == 20) { | 575 | if (breakme++ == 20) { |
459 | printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs); | 576 | printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs); |
460 | breakme = 0; | 577 | breakme = 0; |
461 | c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, | 578 | c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, |
462 | &retlen, brokenbuf, NULL, c->oobinfo); | 579 | brokenbuf); |
463 | ret = -EIO; | 580 | ret = -EIO; |
464 | } else | 581 | } else |
465 | #endif | 582 | #endif |
466 | 583 | ||
467 | if (jffs2_cleanmarker_oob(c)) | ||
468 | ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo); | ||
469 | else | ||
470 | ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf); | 584 | ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf); |
471 | 585 | ||
472 | if (ret || retlen != c->wbuf_pagesize) { | 586 | if (ret || retlen != c->wbuf_pagesize) { |
@@ -483,32 +597,34 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
483 | return ret; | 597 | return ret; |
484 | } | 598 | } |
485 | 599 | ||
486 | spin_lock(&c->erase_completion_lock); | ||
487 | |||
488 | /* Adjust free size of the block if we padded. */ | 600 | /* Adjust free size of the block if we padded. */ |
489 | if (pad) { | 601 | if (pad) { |
490 | struct jffs2_eraseblock *jeb; | 602 | uint32_t waste = c->wbuf_pagesize - c->wbuf_len; |
491 | |||
492 | jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; | ||
493 | 603 | ||
494 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n", | 604 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n", |
495 | (jeb==c->nextblock)?"next":"", jeb->offset)); | 605 | (wbuf_jeb==c->nextblock)?"next":"", wbuf_jeb->offset)); |
496 | 606 | ||
497 | /* wbuf_pagesize - wbuf_len is the amount of space that's to be | 607 | /* wbuf_pagesize - wbuf_len is the amount of space that's to be |
498 | padded. If there is less free space in the block than that, | 608 | padded. If there is less free space in the block than that, |
499 | something screwed up */ | 609 | something screwed up */ |
500 | if (jeb->free_size < (c->wbuf_pagesize - c->wbuf_len)) { | 610 | if (wbuf_jeb->free_size < waste) { |
501 | printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n", | 611 | printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n", |
502 | c->wbuf_ofs, c->wbuf_len, c->wbuf_pagesize-c->wbuf_len); | 612 | c->wbuf_ofs, c->wbuf_len, waste); |
503 | printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n", | 613 | printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n", |
504 | jeb->offset, jeb->free_size); | 614 | wbuf_jeb->offset, wbuf_jeb->free_size); |
505 | BUG(); | 615 | BUG(); |
506 | } | 616 | } |
507 | jeb->free_size -= (c->wbuf_pagesize - c->wbuf_len); | 617 | |
508 | c->free_size -= (c->wbuf_pagesize - c->wbuf_len); | 618 | spin_lock(&c->erase_completion_lock); |
509 | jeb->wasted_size += (c->wbuf_pagesize - c->wbuf_len); | 619 | |
510 | c->wasted_size += (c->wbuf_pagesize - c->wbuf_len); | 620 | jffs2_link_node_ref(c, wbuf_jeb, (c->wbuf_ofs + c->wbuf_len) | REF_OBSOLETE, waste, NULL); |
511 | } | 621 | /* FIXME: that made it count as dirty. Convert to wasted */ |
622 | wbuf_jeb->dirty_size -= waste; | ||
623 | c->dirty_size -= waste; | ||
624 | wbuf_jeb->wasted_size += waste; | ||
625 | c->wasted_size += waste; | ||
626 | } else | ||
627 | spin_lock(&c->erase_completion_lock); | ||
512 | 628 | ||
513 | /* Stick any now-obsoleted blocks on the erase_pending_list */ | 629 | /* Stick any now-obsoleted blocks on the erase_pending_list */ |
514 | jffs2_refile_wbuf_blocks(c); | 630 | jffs2_refile_wbuf_blocks(c); |
@@ -603,20 +719,30 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) | |||
603 | 719 | ||
604 | return ret; | 720 | return ret; |
605 | } | 721 | } |
606 | int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino) | 722 | |
723 | static size_t jffs2_fill_wbuf(struct jffs2_sb_info *c, const uint8_t *buf, | ||
724 | size_t len) | ||
607 | { | 725 | { |
608 | struct kvec outvecs[3]; | 726 | if (len && !c->wbuf_len && (len >= c->wbuf_pagesize)) |
609 | uint32_t totlen = 0; | 727 | return 0; |
610 | uint32_t split_ofs = 0; | 728 | |
611 | uint32_t old_totlen; | 729 | if (len > (c->wbuf_pagesize - c->wbuf_len)) |
612 | int ret, splitvec = -1; | 730 | len = c->wbuf_pagesize - c->wbuf_len; |
613 | int invec, outvec; | 731 | memcpy(c->wbuf + c->wbuf_len, buf, len); |
614 | size_t wbuf_retlen; | 732 | c->wbuf_len += (uint32_t) len; |
615 | unsigned char *wbuf_ptr; | 733 | return len; |
616 | size_t donelen = 0; | 734 | } |
735 | |||
736 | int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, | ||
737 | unsigned long count, loff_t to, size_t *retlen, | ||
738 | uint32_t ino) | ||
739 | { | ||
740 | struct jffs2_eraseblock *jeb; | ||
741 | size_t wbuf_retlen, donelen = 0; | ||
617 | uint32_t outvec_to = to; | 742 | uint32_t outvec_to = to; |
743 | int ret, invec; | ||
618 | 744 | ||
619 | /* If not NAND flash, don't bother */ | 745 | /* If not writebuffered flash, don't bother */ |
620 | if (!jffs2_is_writebuffered(c)) | 746 | if (!jffs2_is_writebuffered(c)) |
621 | return jffs2_flash_direct_writev(c, invecs, count, to, retlen); | 747 | return jffs2_flash_direct_writev(c, invecs, count, to, retlen); |
622 | 748 | ||
@@ -629,34 +755,22 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig | |||
629 | memset(c->wbuf,0xff,c->wbuf_pagesize); | 755 | memset(c->wbuf,0xff,c->wbuf_pagesize); |
630 | } | 756 | } |
631 | 757 | ||
632 | /* Fixup the wbuf if we are moving to a new eraseblock. The checks below | 758 | /* |
633 | fail for ECC'd NOR because cleanmarker == 16, so a block starts at | 759 | * Sanity checks on target address. It's permitted to write |
634 | xxx0010. */ | 760 | * at PAD(c->wbuf_len+c->wbuf_ofs), and it's permitted to |
635 | if (jffs2_nor_ecc(c)) { | 761 | * write at the beginning of a new erase block. Anything else, |
636 | if (((c->wbuf_ofs % c->sector_size) == 0) && !c->wbuf_len) { | 762 | * and you die. New block starts at xxx000c (0-b = block |
637 | c->wbuf_ofs = PAGE_DIV(to); | 763 | * header) |
638 | c->wbuf_len = PAGE_MOD(to); | 764 | */ |
639 | memset(c->wbuf,0xff,c->wbuf_pagesize); | ||
640 | } | ||
641 | } | ||
642 | |||
643 | /* Sanity checks on target address. | ||
644 | It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs), | ||
645 | and it's permitted to write at the beginning of a new | ||
646 | erase block. Anything else, and you die. | ||
647 | New block starts at xxx000c (0-b = block header) | ||
648 | */ | ||
649 | if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) { | 765 | if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) { |
650 | /* It's a write to a new block */ | 766 | /* It's a write to a new block */ |
651 | if (c->wbuf_len) { | 767 | if (c->wbuf_len) { |
652 | D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs)); | 768 | D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx " |
769 | "causes flush of wbuf at 0x%08x\n", | ||
770 | (unsigned long)to, c->wbuf_ofs)); | ||
653 | ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); | 771 | ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); |
654 | if (ret) { | 772 | if (ret) |
655 | /* the underlying layer has to check wbuf_len to do the cleanup */ | 773 | goto outerr; |
656 | D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret)); | ||
657 | *retlen = 0; | ||
658 | goto exit; | ||
659 | } | ||
660 | } | 774 | } |
661 | /* set pointer to new block */ | 775 | /* set pointer to new block */ |
662 | c->wbuf_ofs = PAGE_DIV(to); | 776 | c->wbuf_ofs = PAGE_DIV(to); |
@@ -665,165 +779,70 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig | |||
665 | 779 | ||
666 | if (to != PAD(c->wbuf_ofs + c->wbuf_len)) { | 780 | if (to != PAD(c->wbuf_ofs + c->wbuf_len)) { |
667 | /* We're not writing immediately after the writebuffer. Bad. */ | 781 | /* We're not writing immediately after the writebuffer. Bad. */ |
668 | printk(KERN_CRIT "jffs2_flash_writev(): Non-contiguous write to %08lx\n", (unsigned long)to); | 782 | printk(KERN_CRIT "jffs2_flash_writev(): Non-contiguous write " |
783 | "to %08lx\n", (unsigned long)to); | ||
669 | if (c->wbuf_len) | 784 | if (c->wbuf_len) |
670 | printk(KERN_CRIT "wbuf was previously %08x-%08x\n", | 785 | printk(KERN_CRIT "wbuf was previously %08x-%08x\n", |
671 | c->wbuf_ofs, c->wbuf_ofs+c->wbuf_len); | 786 | c->wbuf_ofs, c->wbuf_ofs+c->wbuf_len); |
672 | BUG(); | 787 | BUG(); |
673 | } | 788 | } |
674 | 789 | ||
675 | /* Note outvecs[3] above. We know count is never greater than 2 */ | 790 | /* adjust alignment offset */ |
676 | if (count > 2) { | 791 | if (c->wbuf_len != PAGE_MOD(to)) { |
677 | printk(KERN_CRIT "jffs2_flash_writev(): count is %ld\n", count); | 792 | c->wbuf_len = PAGE_MOD(to); |
678 | BUG(); | 793 | /* take care of alignment to next page */ |
679 | } | 794 | if (!c->wbuf_len) { |
680 | 795 | c->wbuf_len = c->wbuf_pagesize; | |
681 | invec = 0; | 796 | ret = __jffs2_flush_wbuf(c, NOPAD); |
682 | outvec = 0; | 797 | if (ret) |
683 | 798 | goto outerr; | |
684 | /* Fill writebuffer first, if already in use */ | ||
685 | if (c->wbuf_len) { | ||
686 | uint32_t invec_ofs = 0; | ||
687 | |||
688 | /* adjust alignment offset */ | ||
689 | if (c->wbuf_len != PAGE_MOD(to)) { | ||
690 | c->wbuf_len = PAGE_MOD(to); | ||
691 | /* take care of alignment to next page */ | ||
692 | if (!c->wbuf_len) | ||
693 | c->wbuf_len = c->wbuf_pagesize; | ||
694 | } | ||
695 | |||
696 | while(c->wbuf_len < c->wbuf_pagesize) { | ||
697 | uint32_t thislen; | ||
698 | |||
699 | if (invec == count) | ||
700 | goto alldone; | ||
701 | |||
702 | thislen = c->wbuf_pagesize - c->wbuf_len; | ||
703 | |||
704 | if (thislen >= invecs[invec].iov_len) | ||
705 | thislen = invecs[invec].iov_len; | ||
706 | |||
707 | invec_ofs = thislen; | ||
708 | |||
709 | memcpy(c->wbuf + c->wbuf_len, invecs[invec].iov_base, thislen); | ||
710 | c->wbuf_len += thislen; | ||
711 | donelen += thislen; | ||
712 | /* Get next invec, if actual did not fill the buffer */ | ||
713 | if (c->wbuf_len < c->wbuf_pagesize) | ||
714 | invec++; | ||
715 | } | ||
716 | |||
717 | /* write buffer is full, flush buffer */ | ||
718 | ret = __jffs2_flush_wbuf(c, NOPAD); | ||
719 | if (ret) { | ||
720 | /* the underlying layer has to check wbuf_len to do the cleanup */ | ||
721 | D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret)); | ||
722 | /* Retlen zero to make sure our caller doesn't mark the space dirty. | ||
723 | We've already done everything that's necessary */ | ||
724 | *retlen = 0; | ||
725 | goto exit; | ||
726 | } | ||
727 | outvec_to += donelen; | ||
728 | c->wbuf_ofs = outvec_to; | ||
729 | |||
730 | /* All invecs done ? */ | ||
731 | if (invec == count) | ||
732 | goto alldone; | ||
733 | |||
734 | /* Set up the first outvec, containing the remainder of the | ||
735 | invec we partially used */ | ||
736 | if (invecs[invec].iov_len > invec_ofs) { | ||
737 | outvecs[0].iov_base = invecs[invec].iov_base+invec_ofs; | ||
738 | totlen = outvecs[0].iov_len = invecs[invec].iov_len-invec_ofs; | ||
739 | if (totlen > c->wbuf_pagesize) { | ||
740 | splitvec = outvec; | ||
741 | split_ofs = outvecs[0].iov_len - PAGE_MOD(totlen); | ||
742 | } | ||
743 | outvec++; | ||
744 | } | ||
745 | invec++; | ||
746 | } | ||
747 | |||
748 | /* OK, now we've flushed the wbuf and the start of the bits | ||
749 | we have been asked to write, now to write the rest.... */ | ||
750 | |||
751 | /* totlen holds the amount of data still to be written */ | ||
752 | old_totlen = totlen; | ||
753 | for ( ; invec < count; invec++,outvec++ ) { | ||
754 | outvecs[outvec].iov_base = invecs[invec].iov_base; | ||
755 | totlen += outvecs[outvec].iov_len = invecs[invec].iov_len; | ||
756 | if (PAGE_DIV(totlen) != PAGE_DIV(old_totlen)) { | ||
757 | splitvec = outvec; | ||
758 | split_ofs = outvecs[outvec].iov_len - PAGE_MOD(totlen); | ||
759 | old_totlen = totlen; | ||
760 | } | 799 | } |
761 | } | 800 | } |
762 | 801 | ||
763 | /* Now the outvecs array holds all the remaining data to write */ | 802 | for (invec = 0; invec < count; invec++) { |
764 | /* Up to splitvec,split_ofs is to be written immediately. The rest | 803 | int vlen = invecs[invec].iov_len; |
765 | goes into the (now-empty) wbuf */ | 804 | uint8_t *v = invecs[invec].iov_base; |
766 | |||
767 | if (splitvec != -1) { | ||
768 | uint32_t remainder; | ||
769 | |||
770 | remainder = outvecs[splitvec].iov_len - split_ofs; | ||
771 | outvecs[splitvec].iov_len = split_ofs; | ||
772 | |||
773 | /* We did cross a page boundary, so we write some now */ | ||
774 | if (jffs2_cleanmarker_oob(c)) | ||
775 | ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); | ||
776 | else | ||
777 | ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen); | ||
778 | |||
779 | if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { | ||
780 | /* At this point we have no problem, | ||
781 | c->wbuf is empty. However refile nextblock to avoid | ||
782 | writing again to same address. | ||
783 | */ | ||
784 | struct jffs2_eraseblock *jeb; | ||
785 | 805 | ||
786 | spin_lock(&c->erase_completion_lock); | 806 | wbuf_retlen = jffs2_fill_wbuf(c, v, vlen); |
787 | 807 | ||
788 | jeb = &c->blocks[outvec_to / c->sector_size]; | 808 | if (c->wbuf_len == c->wbuf_pagesize) { |
789 | jffs2_block_refile(c, jeb, REFILE_ANYWAY); | 809 | ret = __jffs2_flush_wbuf(c, NOPAD); |
790 | 810 | if (ret) | |
791 | *retlen = 0; | 811 | goto outerr; |
792 | spin_unlock(&c->erase_completion_lock); | ||
793 | goto exit; | ||
794 | } | 812 | } |
795 | 813 | vlen -= wbuf_retlen; | |
814 | outvec_to += wbuf_retlen; | ||
796 | donelen += wbuf_retlen; | 815 | donelen += wbuf_retlen; |
797 | c->wbuf_ofs = PAGE_DIV(outvec_to) + PAGE_DIV(totlen); | 816 | v += wbuf_retlen; |
798 | 817 | ||
799 | if (remainder) { | 818 | if (vlen >= c->wbuf_pagesize) { |
800 | outvecs[splitvec].iov_base += split_ofs; | 819 | ret = c->mtd->write(c->mtd, outvec_to, PAGE_DIV(vlen), |
801 | outvecs[splitvec].iov_len = remainder; | 820 | &wbuf_retlen, v); |
802 | } else { | 821 | if (ret < 0 || wbuf_retlen != PAGE_DIV(vlen)) |
803 | splitvec++; | 822 | goto outfile; |
823 | |||
824 | vlen -= wbuf_retlen; | ||
825 | outvec_to += wbuf_retlen; | ||
826 | c->wbuf_ofs = outvec_to; | ||
827 | donelen += wbuf_retlen; | ||
828 | v += wbuf_retlen; | ||
804 | } | 829 | } |
805 | 830 | ||
806 | } else { | 831 | wbuf_retlen = jffs2_fill_wbuf(c, v, vlen); |
807 | splitvec = 0; | 832 | if (c->wbuf_len == c->wbuf_pagesize) { |
808 | } | 833 | ret = __jffs2_flush_wbuf(c, NOPAD); |
809 | 834 | if (ret) | |
810 | /* Now splitvec points to the start of the bits we have to copy | 835 | goto outerr; |
811 | into the wbuf */ | 836 | } |
812 | wbuf_ptr = c->wbuf; | ||
813 | 837 | ||
814 | for ( ; splitvec < outvec; splitvec++) { | 838 | outvec_to += wbuf_retlen; |
815 | /* Don't copy the wbuf into itself */ | 839 | donelen += wbuf_retlen; |
816 | if (outvecs[splitvec].iov_base == c->wbuf) | ||
817 | continue; | ||
818 | memcpy(wbuf_ptr, outvecs[splitvec].iov_base, outvecs[splitvec].iov_len); | ||
819 | wbuf_ptr += outvecs[splitvec].iov_len; | ||
820 | donelen += outvecs[splitvec].iov_len; | ||
821 | } | 840 | } |
822 | c->wbuf_len = wbuf_ptr - c->wbuf; | ||
823 | 841 | ||
824 | /* If there's a remainder in the wbuf and it's a non-GC write, | 842 | /* |
825 | remember that the wbuf affects this ino */ | 843 | * If there's a remainder in the wbuf and it's a non-GC write, |
826 | alldone: | 844 | * remember that the wbuf affects this ino |
845 | */ | ||
827 | *retlen = donelen; | 846 | *retlen = donelen; |
828 | 847 | ||
829 | if (jffs2_sum_active()) { | 848 | if (jffs2_sum_active()) { |
@@ -836,8 +855,24 @@ alldone: | |||
836 | jffs2_wbuf_dirties_inode(c, ino); | 855 | jffs2_wbuf_dirties_inode(c, ino); |
837 | 856 | ||
838 | ret = 0; | 857 | ret = 0; |
858 | up_write(&c->wbuf_sem); | ||
859 | return ret; | ||
839 | 860 | ||
840 | exit: | 861 | outfile: |
862 | /* | ||
863 | * At this point we have no problem, c->wbuf is empty. However | ||
864 | * refile nextblock to avoid writing again to same address. | ||
865 | */ | ||
866 | |||
867 | spin_lock(&c->erase_completion_lock); | ||
868 | |||
869 | jeb = &c->blocks[outvec_to / c->sector_size]; | ||
870 | jffs2_block_refile(c, jeb, REFILE_ANYWAY); | ||
871 | |||
872 | spin_unlock(&c->erase_completion_lock); | ||
873 | |||
874 | outerr: | ||
875 | *retlen = 0; | ||
841 | up_write(&c->wbuf_sem); | 876 | up_write(&c->wbuf_sem); |
842 | return ret; | 877 | return ret; |
843 | } | 878 | } |
@@ -846,7 +881,8 @@ exit: | |||
846 | * This is the entry for flash write. | 881 | * This is the entry for flash write. |
847 | * Check, if we work on NAND FLASH, if so build an kvec and write it via vritev | 882 | * Check, if we work on NAND FLASH, if so build an kvec and write it via vritev |
848 | */ | 883 | */ |
849 | int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf) | 884 | int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, |
885 | size_t *retlen, const u_char *buf) | ||
850 | { | 886 | { |
851 | struct kvec vecs[1]; | 887 | struct kvec vecs[1]; |
852 | 888 | ||
@@ -871,25 +907,23 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re | |||
871 | 907 | ||
872 | /* Read flash */ | 908 | /* Read flash */ |
873 | down_read(&c->wbuf_sem); | 909 | down_read(&c->wbuf_sem); |
874 | if (jffs2_cleanmarker_oob(c)) | 910 | ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); |
875 | ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); | 911 | |
876 | else | 912 | if ( (ret == -EBADMSG || ret == -EUCLEAN) && (*retlen == len) ) { |
877 | ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); | 913 | if (ret == -EBADMSG) |
878 | 914 | printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx)" | |
879 | if ( (ret == -EBADMSG) && (*retlen == len) ) { | 915 | " returned ECC error\n", len, ofs); |
880 | printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", | ||
881 | len, ofs); | ||
882 | /* | 916 | /* |
883 | * We have the raw data without ECC correction in the buffer, maybe | 917 | * We have the raw data without ECC correction in the buffer, |
884 | * we are lucky and all data or parts are correct. We check the node. | 918 | * maybe we are lucky and all data or parts are correct. We |
885 | * If data are corrupted node check will sort it out. | 919 | * check the node. If data are corrupted node check will sort |
886 | * We keep this block, it will fail on write or erase and the we | 920 | * it out. We keep this block, it will fail on write or erase |
887 | * mark it bad. Or should we do that now? But we should give him a chance. | 921 | * and the we mark it bad. Or should we do that now? But we |
888 | * Maybe we had a system crash or power loss before the ecc write or | 922 | * should give him a chance. Maybe we had a system crash or |
889 | * a erase was completed. | 923 | * power loss before the ecc write or a erase was completed. |
890 | * So we return success. :) | 924 | * So we return success. :) |
891 | */ | 925 | */ |
892 | ret = 0; | 926 | ret = 0; |
893 | } | 927 | } |
894 | 928 | ||
895 | /* if no writebuffer available or write buffer empty, return */ | 929 | /* if no writebuffer available or write buffer empty, return */ |
@@ -911,7 +945,7 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re | |||
911 | orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */ | 945 | orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */ |
912 | if (orbf > len) /* is write beyond write buffer ? */ | 946 | if (orbf > len) /* is write beyond write buffer ? */ |
913 | goto exit; | 947 | goto exit; |
914 | lwbf = len - orbf; /* number of bytes to copy */ | 948 | lwbf = len - orbf; /* number of bytes to copy */ |
915 | if (lwbf > c->wbuf_len) | 949 | if (lwbf > c->wbuf_len) |
916 | lwbf = c->wbuf_len; | 950 | lwbf = c->wbuf_len; |
917 | } | 951 | } |
@@ -923,158 +957,159 @@ exit: | |||
923 | return ret; | 957 | return ret; |
924 | } | 958 | } |
925 | 959 | ||
960 | #define NR_OOB_SCAN_PAGES 4 | ||
961 | |||
926 | /* | 962 | /* |
927 | * Check, if the out of band area is empty | 963 | * Check, if the out of band area is empty |
928 | */ | 964 | */ |
929 | int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int mode) | 965 | int jffs2_check_oob_empty(struct jffs2_sb_info *c, |
966 | struct jffs2_eraseblock *jeb, int mode) | ||
930 | { | 967 | { |
931 | unsigned char *buf; | 968 | int i, page, ret; |
932 | int ret = 0; | 969 | int oobsize = c->mtd->oobsize; |
933 | int i,len,page; | 970 | struct mtd_oob_ops ops; |
934 | size_t retlen; | 971 | |
935 | int oob_size; | 972 | ops.len = NR_OOB_SCAN_PAGES * oobsize; |
936 | 973 | ops.ooblen = oobsize; | |
937 | /* allocate a buffer for all oob data in this sector */ | 974 | ops.oobbuf = c->oobbuf; |
938 | oob_size = c->mtd->oobsize; | 975 | ops.ooboffs = 0; |
939 | len = 4 * oob_size; | 976 | ops.datbuf = NULL; |
940 | buf = kmalloc(len, GFP_KERNEL); | 977 | ops.mode = MTD_OOB_PLACE; |
941 | if (!buf) { | 978 | |
942 | printk(KERN_NOTICE "jffs2_check_oob_empty(): allocation of temporary data buffer for oob check failed\n"); | 979 | ret = c->mtd->read_oob(c->mtd, jeb->offset, &ops); |
943 | return -ENOMEM; | ||
944 | } | ||
945 | /* | ||
946 | * if mode = 0, we scan for a total empty oob area, else we have | ||
947 | * to take care of the cleanmarker in the first page of the block | ||
948 | */ | ||
949 | ret = jffs2_flash_read_oob(c, jeb->offset, len , &retlen, buf); | ||
950 | if (ret) { | 980 | if (ret) { |
951 | D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB failed %d for block at %08x\n", ret, jeb->offset)); | 981 | D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB " |
952 | goto out; | 982 | "failed %d for block at %08x\n", ret, jeb->offset)); |
983 | return ret; | ||
953 | } | 984 | } |
954 | 985 | ||
955 | if (retlen < len) { | 986 | if (ops.retlen < ops.len) { |
956 | D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB return short read " | 987 | D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB " |
957 | "(%zd bytes not %d) for block at %08x\n", retlen, len, jeb->offset)); | 988 | "returned short read (%zd bytes not %d) for block " |
958 | ret = -EIO; | 989 | "at %08x\n", ops.retlen, ops.len, jeb->offset)); |
959 | goto out; | 990 | return -EIO; |
960 | } | 991 | } |
961 | 992 | ||
962 | /* Special check for first page */ | 993 | /* Special check for first page */ |
963 | for(i = 0; i < oob_size ; i++) { | 994 | for(i = 0; i < oobsize ; i++) { |
964 | /* Yeah, we know about the cleanmarker. */ | 995 | /* Yeah, we know about the cleanmarker. */ |
965 | if (mode && i >= c->fsdata_pos && | 996 | if (mode && i >= c->fsdata_pos && |
966 | i < c->fsdata_pos + c->fsdata_len) | 997 | i < c->fsdata_pos + c->fsdata_len) |
967 | continue; | 998 | continue; |
968 | 999 | ||
969 | if (buf[i] != 0xFF) { | 1000 | if (ops.oobbuf[i] != 0xFF) { |
970 | D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n", | 1001 | D2(printk(KERN_DEBUG "Found %02x at %x in OOB for " |
971 | buf[i], i, jeb->offset)); | 1002 | "%08x\n", ops.oobbuf[i], i, jeb->offset)); |
972 | ret = 1; | 1003 | return 1; |
973 | goto out; | ||
974 | } | 1004 | } |
975 | } | 1005 | } |
976 | 1006 | ||
977 | /* we know, we are aligned :) */ | 1007 | /* we know, we are aligned :) */ |
978 | for (page = oob_size; page < len; page += sizeof(long)) { | 1008 | for (page = oobsize; page < ops.len; page += sizeof(long)) { |
979 | unsigned long dat = *(unsigned long *)(&buf[page]); | 1009 | long dat = *(long *)(&ops.oobbuf[page]); |
980 | if(dat != -1) { | 1010 | if(dat != -1) |
981 | ret = 1; | 1011 | return 1; |
982 | goto out; | ||
983 | } | ||
984 | } | 1012 | } |
985 | 1013 | return 0; | |
986 | out: | ||
987 | kfree(buf); | ||
988 | |||
989 | return ret; | ||
990 | } | 1014 | } |
991 | 1015 | ||
992 | /* | 1016 | /* |
993 | * Scan for a valid cleanmarker and for bad blocks | 1017 | * Scan for a valid cleanmarker and for bad blocks |
994 | * For virtual blocks (concatenated physical blocks) check the cleanmarker | 1018 | */ |
995 | * only in the first page of the first physical block, but scan for bad blocks in all | 1019 | int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, |
996 | * physical blocks | 1020 | struct jffs2_eraseblock *jeb) |
997 | */ | ||
998 | int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) | ||
999 | { | 1021 | { |
1000 | struct jffs2_unknown_node n; | 1022 | struct jffs2_unknown_node n; |
1001 | unsigned char buf[2 * NAND_MAX_OOBSIZE]; | 1023 | struct mtd_oob_ops ops; |
1002 | unsigned char *p; | 1024 | int oobsize = c->mtd->oobsize; |
1003 | int ret, i, cnt, retval = 0; | 1025 | unsigned char *p,*b; |
1004 | size_t retlen, offset; | 1026 | int i, ret; |
1005 | int oob_size; | 1027 | size_t offset = jeb->offset; |
1006 | 1028 | ||
1007 | offset = jeb->offset; | 1029 | /* Check first if the block is bad. */ |
1008 | oob_size = c->mtd->oobsize; | 1030 | if (c->mtd->block_isbad(c->mtd, offset)) { |
1009 | 1031 | D1 (printk(KERN_WARNING "jffs2_check_nand_cleanmarker()" | |
1010 | /* Loop through the physical blocks */ | 1032 | ": Bad block at %08x\n", jeb->offset)); |
1011 | for (cnt = 0; cnt < (c->sector_size / c->mtd->erasesize); cnt++) { | 1033 | return 2; |
1012 | /* Check first if the block is bad. */ | 1034 | } |
1013 | if (c->mtd->block_isbad (c->mtd, offset)) { | ||
1014 | D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n", jeb->offset)); | ||
1015 | return 2; | ||
1016 | } | ||
1017 | /* | ||
1018 | * We read oob data from page 0 and 1 of the block. | ||
1019 | * page 0 contains cleanmarker and badblock info | ||
1020 | * page 1 contains failure count of this block | ||
1021 | */ | ||
1022 | ret = c->mtd->read_oob (c->mtd, offset, oob_size << 1, &retlen, buf); | ||
1023 | 1035 | ||
1024 | if (ret) { | 1036 | ops.len = oobsize; |
1025 | D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB failed %d for block at %08x\n", ret, jeb->offset)); | 1037 | ops.ooblen = oobsize; |
1026 | return ret; | 1038 | ops.oobbuf = c->oobbuf; |
1027 | } | 1039 | ops.ooboffs = 0; |
1028 | if (retlen < (oob_size << 1)) { | 1040 | ops.datbuf = NULL; |
1029 | D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size << 1, jeb->offset)); | 1041 | ops.mode = MTD_OOB_PLACE; |
1030 | return -EIO; | ||
1031 | } | ||
1032 | 1042 | ||
1033 | /* Check cleanmarker only on the first physical block */ | 1043 | ret = c->mtd->read_oob(c->mtd, offset, &ops); |
1034 | if (!cnt) { | 1044 | if (ret) { |
1035 | n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK); | 1045 | D1 (printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): " |
1036 | n.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER); | 1046 | "Read OOB failed %d for block at %08x\n", |
1037 | n.totlen = cpu_to_je32 (8); | 1047 | ret, jeb->offset)); |
1038 | p = (unsigned char *) &n; | 1048 | return ret; |
1049 | } | ||
1039 | 1050 | ||
1040 | for (i = 0; i < c->fsdata_len; i++) { | 1051 | if (ops.retlen < ops.len) { |
1041 | if (buf[c->fsdata_pos + i] != p[i]) { | 1052 | D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): " |
1042 | retval = 1; | 1053 | "Read OOB return short read (%zd bytes not %d) " |
1043 | } | 1054 | "for block at %08x\n", ops.retlen, ops.len, |
1044 | } | 1055 | jeb->offset)); |
1045 | D1(if (retval == 1) { | 1056 | return -EIO; |
1046 | printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset); | ||
1047 | printk(KERN_WARNING "OOB at %08x was ", offset); | ||
1048 | for (i=0; i < oob_size; i++) { | ||
1049 | printk("%02x ", buf[i]); | ||
1050 | } | ||
1051 | printk("\n"); | ||
1052 | }) | ||
1053 | } | ||
1054 | offset += c->mtd->erasesize; | ||
1055 | } | 1057 | } |
1056 | return retval; | 1058 | |
1059 | n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK); | ||
1060 | n.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER); | ||
1061 | n.totlen = cpu_to_je32 (8); | ||
1062 | p = (unsigned char *) &n; | ||
1063 | b = c->oobbuf + c->fsdata_pos; | ||
1064 | |||
1065 | for (i = c->fsdata_len; i; i--) { | ||
1066 | if (*b++ != *p++) | ||
1067 | ret = 1; | ||
1068 | } | ||
1069 | |||
1070 | D1(if (ret == 1) { | ||
1071 | printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): " | ||
1072 | "Cleanmarker node not detected in block at %08x\n", | ||
1073 | offset); | ||
1074 | printk(KERN_WARNING "OOB at %08zx was ", offset); | ||
1075 | for (i=0; i < oobsize; i++) | ||
1076 | printk("%02x ", c->oobbuf[i]); | ||
1077 | printk("\n"); | ||
1078 | }); | ||
1079 | return ret; | ||
1057 | } | 1080 | } |
1058 | 1081 | ||
1059 | int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) | 1082 | int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, |
1083 | struct jffs2_eraseblock *jeb) | ||
1060 | { | 1084 | { |
1061 | struct jffs2_unknown_node n; | 1085 | struct jffs2_unknown_node n; |
1062 | int ret; | 1086 | int ret; |
1063 | size_t retlen; | 1087 | struct mtd_oob_ops ops; |
1064 | 1088 | ||
1065 | n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 1089 | n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
1066 | n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); | 1090 | n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); |
1067 | n.totlen = cpu_to_je32(8); | 1091 | n.totlen = cpu_to_je32(8); |
1068 | 1092 | ||
1069 | ret = jffs2_flash_write_oob(c, jeb->offset + c->fsdata_pos, c->fsdata_len, &retlen, (unsigned char *)&n); | 1093 | ops.len = c->fsdata_len; |
1094 | ops.ooblen = c->fsdata_len;; | ||
1095 | ops.oobbuf = (uint8_t *)&n; | ||
1096 | ops.ooboffs = c->fsdata_pos; | ||
1097 | ops.datbuf = NULL; | ||
1098 | ops.mode = MTD_OOB_PLACE; | ||
1099 | |||
1100 | ret = c->mtd->write_oob(c->mtd, jeb->offset, &ops); | ||
1070 | 1101 | ||
1071 | if (ret) { | 1102 | if (ret) { |
1072 | D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Write failed for block at %08x: error %d\n", jeb->offset, ret)); | 1103 | D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): " |
1104 | "Write failed for block at %08x: error %d\n", | ||
1105 | jeb->offset, ret)); | ||
1073 | return ret; | 1106 | return ret; |
1074 | } | 1107 | } |
1075 | if (retlen != c->fsdata_len) { | 1108 | if (ops.retlen != ops.len) { |
1076 | D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %zd not %d\n", jeb->offset, retlen, c->fsdata_len)); | 1109 | D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): " |
1077 | return ret; | 1110 | "Short write for block at %08x: %zd not %d\n", |
1111 | jeb->offset, ops.retlen, ops.len)); | ||
1112 | return -EIO; | ||
1078 | } | 1113 | } |
1079 | return 0; | 1114 | return 0; |
1080 | } | 1115 | } |
@@ -1108,18 +1143,9 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock * | |||
1108 | return 1; | 1143 | return 1; |
1109 | } | 1144 | } |
1110 | 1145 | ||
1111 | #define NAND_JFFS2_OOB16_FSDALEN 8 | ||
1112 | |||
1113 | static struct nand_oobinfo jffs2_oobinfo_docecc = { | ||
1114 | .useecc = MTD_NANDECC_PLACE, | ||
1115 | .eccbytes = 6, | ||
1116 | .eccpos = {0,1,2,3,4,5} | ||
1117 | }; | ||
1118 | |||
1119 | |||
1120 | static int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c) | 1146 | static int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c) |
1121 | { | 1147 | { |
1122 | struct nand_oobinfo *oinfo = &c->mtd->oobinfo; | 1148 | struct nand_ecclayout *oinfo = c->mtd->ecclayout; |
1123 | 1149 | ||
1124 | /* Do this only, if we have an oob buffer */ | 1150 | /* Do this only, if we have an oob buffer */ |
1125 | if (!c->mtd->oobsize) | 1151 | if (!c->mtd->oobsize) |
@@ -1129,33 +1155,23 @@ static int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c) | |||
1129 | c->cleanmarker_size = 0; | 1155 | c->cleanmarker_size = 0; |
1130 | 1156 | ||
1131 | /* Should we use autoplacement ? */ | 1157 | /* Should we use autoplacement ? */ |
1132 | if (oinfo && oinfo->useecc == MTD_NANDECC_AUTOPLACE) { | 1158 | if (!oinfo) { |
1133 | D1(printk(KERN_DEBUG "JFFS2 using autoplace on NAND\n")); | 1159 | D1(printk(KERN_DEBUG "JFFS2 on NAND. No autoplacment info found\n")); |
1134 | /* Get the position of the free bytes */ | 1160 | return -EINVAL; |
1135 | if (!oinfo->oobfree[0][1]) { | 1161 | } |
1136 | printk (KERN_WARNING "jffs2_nand_set_oobinfo(): Eeep. Autoplacement selected and no empty space in oob\n"); | ||
1137 | return -ENOSPC; | ||
1138 | } | ||
1139 | c->fsdata_pos = oinfo->oobfree[0][0]; | ||
1140 | c->fsdata_len = oinfo->oobfree[0][1]; | ||
1141 | if (c->fsdata_len > 8) | ||
1142 | c->fsdata_len = 8; | ||
1143 | } else { | ||
1144 | /* This is just a legacy fallback and should go away soon */ | ||
1145 | switch(c->mtd->ecctype) { | ||
1146 | case MTD_ECC_RS_DiskOnChip: | ||
1147 | printk(KERN_WARNING "JFFS2 using DiskOnChip hardware ECC without autoplacement. Fix it!\n"); | ||
1148 | c->oobinfo = &jffs2_oobinfo_docecc; | ||
1149 | c->fsdata_pos = 6; | ||
1150 | c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN; | ||
1151 | c->badblock_pos = 15; | ||
1152 | break; | ||
1153 | 1162 | ||
1154 | default: | 1163 | D1(printk(KERN_DEBUG "JFFS2 using autoplace on NAND\n")); |
1155 | D1(printk(KERN_DEBUG "JFFS2 on NAND. No autoplacment info found\n")); | 1164 | /* Get the position of the free bytes */ |
1156 | return -EINVAL; | 1165 | if (!oinfo->oobfree[0].length) { |
1157 | } | 1166 | printk (KERN_WARNING "jffs2_nand_set_oobinfo(): Eeep." |
1167 | " Autoplacement selected and no empty space in oob\n"); | ||
1168 | return -ENOSPC; | ||
1158 | } | 1169 | } |
1170 | c->fsdata_pos = oinfo->oobfree[0].offset; | ||
1171 | c->fsdata_len = oinfo->oobfree[0].length; | ||
1172 | if (c->fsdata_len > 8) | ||
1173 | c->fsdata_len = 8; | ||
1174 | |||
1159 | return 0; | 1175 | return 0; |
1160 | } | 1176 | } |
1161 | 1177 | ||
@@ -1165,13 +1181,17 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c) | |||
1165 | 1181 | ||
1166 | /* Initialise write buffer */ | 1182 | /* Initialise write buffer */ |
1167 | init_rwsem(&c->wbuf_sem); | 1183 | init_rwsem(&c->wbuf_sem); |
1168 | c->wbuf_pagesize = c->mtd->oobblock; | 1184 | c->wbuf_pagesize = c->mtd->writesize; |
1169 | c->wbuf_ofs = 0xFFFFFFFF; | 1185 | c->wbuf_ofs = 0xFFFFFFFF; |
1170 | 1186 | ||
1171 | c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); | 1187 | c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); |
1172 | if (!c->wbuf) | 1188 | if (!c->wbuf) |
1173 | return -ENOMEM; | 1189 | return -ENOMEM; |
1174 | 1190 | ||
1191 | c->oobbuf = kmalloc(NR_OOB_SCAN_PAGES * c->mtd->oobsize, GFP_KERNEL); | ||
1192 | if (!c->oobbuf) | ||
1193 | return -ENOMEM; | ||
1194 | |||
1175 | res = jffs2_nand_set_oobinfo(c); | 1195 | res = jffs2_nand_set_oobinfo(c); |
1176 | 1196 | ||
1177 | #ifdef BREAKME | 1197 | #ifdef BREAKME |
@@ -1189,6 +1209,7 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c) | |||
1189 | void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) | 1209 | void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) |
1190 | { | 1210 | { |
1191 | kfree(c->wbuf); | 1211 | kfree(c->wbuf); |
1212 | kfree(c->oobbuf); | ||
1192 | } | 1213 | } |
1193 | 1214 | ||
1194 | int jffs2_dataflash_setup(struct jffs2_sb_info *c) { | 1215 | int jffs2_dataflash_setup(struct jffs2_sb_info *c) { |
@@ -1236,33 +1257,14 @@ void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { | |||
1236 | kfree(c->wbuf); | 1257 | kfree(c->wbuf); |
1237 | } | 1258 | } |
1238 | 1259 | ||
1239 | int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { | ||
1240 | /* Cleanmarker is actually larger on the flashes */ | ||
1241 | c->cleanmarker_size = 16; | ||
1242 | |||
1243 | /* Initialize write buffer */ | ||
1244 | init_rwsem(&c->wbuf_sem); | ||
1245 | c->wbuf_pagesize = c->mtd->eccsize; | ||
1246 | c->wbuf_ofs = 0xFFFFFFFF; | ||
1247 | |||
1248 | c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); | ||
1249 | if (!c->wbuf) | ||
1250 | return -ENOMEM; | ||
1251 | |||
1252 | return 0; | ||
1253 | } | ||
1254 | |||
1255 | void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) { | ||
1256 | kfree(c->wbuf); | ||
1257 | } | ||
1258 | |||
1259 | int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) { | 1260 | int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) { |
1260 | /* Cleanmarker currently occupies a whole programming region */ | 1261 | /* Cleanmarker currently occupies whole programming regions, |
1261 | c->cleanmarker_size = MTD_PROGREGION_SIZE(c->mtd); | 1262 | * either one or 2 for 8Byte STMicro flashes. */ |
1263 | c->cleanmarker_size = max(16u, c->mtd->writesize); | ||
1262 | 1264 | ||
1263 | /* Initialize write buffer */ | 1265 | /* Initialize write buffer */ |
1264 | init_rwsem(&c->wbuf_sem); | 1266 | init_rwsem(&c->wbuf_sem); |
1265 | c->wbuf_pagesize = MTD_PROGREGION_SIZE(c->mtd); | 1267 | c->wbuf_pagesize = c->mtd->writesize; |
1266 | c->wbuf_ofs = 0xFFFFFFFF; | 1268 | c->wbuf_ofs = 0xFFFFFFFF; |
1267 | 1269 | ||
1268 | c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); | 1270 | c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); |