Blame view
fs/jffs2/wbuf.c
36.9 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 |
/* * JFFS2 -- Journalling Flash File System, Version 2. * |
c00c310ea [JFFS2] Tidy up l... |
4 5 |
* Copyright © 2001-2007 Red Hat, Inc. * Copyright © 2004 Thomas Gleixner <tglx@linutronix.de> |
1da177e4c Linux-2.6.12-rc2 |
6 7 8 9 10 11 |
* * Created by David Woodhouse <dwmw2@infradead.org> * Modified debugged and enhanced by Thomas Gleixner <tglx@linutronix.de> * * For licensing information, see the file 'LICENCE' in this directory. * |
1da177e4c Linux-2.6.12-rc2 |
12 |
*/ |
5a528957e jffs2: Use pr_fmt... |
13 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4c Linux-2.6.12-rc2 |
14 15 16 17 |
#include <linux/kernel.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/crc32.h> |
d4092d76a mtd: nand: Rename... |
18 |
#include <linux/mtd/rawnand.h> |
4e57b6817 [PATCH] fix missi... |
19 |
#include <linux/jiffies.h> |
914e26379 [PATCH] severing ... |
20 |
#include <linux/sched.h> |
8bdc81c50 jffs2: get rid of... |
21 |
#include <linux/writeback.h> |
4e57b6817 [PATCH] fix missi... |
22 |
|
1da177e4c Linux-2.6.12-rc2 |
23 24 25 26 27 28 29 30 31 |
#include "nodelist.h" /* For testing write failures */ #undef BREAKME #undef BREAKMEHEADER #ifdef BREAKME static unsigned char *brokenbuf; #endif |
daba5cc4b [JFFS2] Fix dataf... |
32 33 |
#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) ) #define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) ) |
1da177e4c Linux-2.6.12-rc2 |
34 35 |
/* max. erase failures before we mark a block bad */ #define MAX_ERASE_FAILURES 2 |
1da177e4c Linux-2.6.12-rc2 |
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
struct jffs2_inodirty { uint32_t ino; struct jffs2_inodirty *next; }; static struct jffs2_inodirty inodirty_nomem; static int jffs2_wbuf_pending_for_ino(struct jffs2_sb_info *c, uint32_t ino) { struct jffs2_inodirty *this = c->wbuf_inodes; /* If a malloc failed, consider _everything_ dirty */ if (this == &inodirty_nomem) return 1; /* If ino == 0, _any_ non-GC writes mean 'yes' */ if (this && !ino) return 1; /* Look to see if the inode in question is pending in the wbuf */ while (this) { if (this->ino == ino) return 1; this = this->next; } return 0; } static void jffs2_clear_wbuf_ino_list(struct jffs2_sb_info *c) { struct jffs2_inodirty *this; this = c->wbuf_inodes; if (this != &inodirty_nomem) { while (this) { struct jffs2_inodirty *next = this->next; kfree(this); this = next; } } c->wbuf_inodes = NULL; } static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino) { struct jffs2_inodirty *new; |
8bdc81c50 jffs2: get rid of... |
83 |
/* Schedule delayed write-buffer write-out */ |
64a5c2eb8 jffs2: Rename jff... |
84 |
jffs2_dirty_trigger(c); |
1da177e4c Linux-2.6.12-rc2 |
85 86 87 88 89 90 |
if (jffs2_wbuf_pending_for_ino(c, ino)) return; new = kmalloc(sizeof(*new), GFP_KERNEL); if (!new) { |
9c261b33a jffs2: Convert mo... |
91 92 |
jffs2_dbg(1, "No memory to allocate inodirty. Fallback to all considered dirty "); |
1da177e4c Linux-2.6.12-rc2 |
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
jffs2_clear_wbuf_ino_list(c); c->wbuf_inodes = &inodirty_nomem; return; } new->ino = ino; new->next = c->wbuf_inodes; c->wbuf_inodes = new; return; } static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c) { struct list_head *this, *next; static int n; if (list_empty(&c->erasable_pending_wbuf_list)) return; list_for_each_safe(this, next, &c->erasable_pending_wbuf_list) { struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); |
9c261b33a jffs2: Convert mo... |
113 114 115 |
jffs2_dbg(1, "Removing eraseblock at 0x%08x from erasable_pending_wbuf_list... ", jeb->offset); |
1da177e4c Linux-2.6.12-rc2 |
116 117 118 119 |
list_del(this); if ((jiffies + (n++)) & 127) { /* Most of the time, we just erase it immediately. Otherwise we spend ages scanning it on mount, etc. */ |
9c261b33a jffs2: Convert mo... |
120 121 |
jffs2_dbg(1, "...and adding to erase_pending_list "); |
1da177e4c Linux-2.6.12-rc2 |
122 123 |
list_add_tail(&jeb->list, &c->erase_pending_list); c->nr_erasing_blocks++; |
ae3b6ba06 jffs2: Use jffs2_... |
124 |
jffs2_garbage_collect_trigger(c); |
1da177e4c Linux-2.6.12-rc2 |
125 126 127 |
} else { /* Sometimes, however, we leave it elsewhere so it doesn't get immediately reused, and we spread the load a bit. */ |
9c261b33a jffs2: Convert mo... |
128 129 |
jffs2_dbg(1, "...and adding to erasable_list "); |
1da177e4c Linux-2.6.12-rc2 |
130 131 132 133 |
list_add_tail(&jeb->list, &c->erasable_list); } } } |
7f716cf3f [JFFS2] Fix block... |
134 135 136 137 |
#define REFILE_NOTEMPTY 0 #define REFILE_ANYWAY 1 static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int allow_empty) |
1da177e4c Linux-2.6.12-rc2 |
138 |
{ |
9c261b33a jffs2: Convert mo... |
139 140 |
jffs2_dbg(1, "About to refile bad block at %08x ", jeb->offset); |
1da177e4c Linux-2.6.12-rc2 |
141 |
|
1da177e4c Linux-2.6.12-rc2 |
142 143 144 145 146 147 |
/* File the existing block on the bad_used_list.... */ if (c->nextblock == jeb) c->nextblock = NULL; else /* Not sure this should ever happen... need more coffee */ list_del(&jeb->list); if (jeb->first_node) { |
9c261b33a jffs2: Convert mo... |
148 149 150 |
jffs2_dbg(1, "Refiling block at %08x to bad_used_list ", jeb->offset); |
1da177e4c Linux-2.6.12-rc2 |
151 152 |
list_add(&jeb->list, &c->bad_used_list); } else { |
9b88f4739 [JFFS2] Code clea... |
153 |
BUG_ON(allow_empty == REFILE_NOTEMPTY); |
1da177e4c Linux-2.6.12-rc2 |
154 |
/* It has to have had some nodes or we couldn't be here */ |
9c261b33a jffs2: Convert mo... |
155 156 157 |
jffs2_dbg(1, "Refiling block at %08x to erase_pending_list ", jeb->offset); |
1da177e4c Linux-2.6.12-rc2 |
158 159 |
list_add(&jeb->list, &c->erase_pending_list); c->nr_erasing_blocks++; |
ae3b6ba06 jffs2: Use jffs2_... |
160 |
jffs2_garbage_collect_trigger(c); |
1da177e4c Linux-2.6.12-rc2 |
161 |
} |
1da177e4c Linux-2.6.12-rc2 |
162 |
|
9bfeb691e [JFFS2] Switch to... |
163 164 165 166 167 168 169 170 171 172 173 174 |
if (!jffs2_prealloc_raw_node_refs(c, jeb, 1)) { uint32_t oldfree = jeb->free_size; jffs2_link_node_ref(c, jeb, (jeb->offset+c->sector_size-oldfree) | REF_OBSOLETE, oldfree, NULL); /* convert to wasted */ c->wasted_size += oldfree; jeb->wasted_size += oldfree; c->dirty_size -= oldfree; jeb->dirty_size -= oldfree; } |
1da177e4c Linux-2.6.12-rc2 |
175 |
|
e0c8e42f8 [JFFS2] Debug cod... |
176 177 178 |
jffs2_dbg_dump_block_lists_nolock(c); jffs2_dbg_acct_sanity_check_nolock(c,jeb); jffs2_dbg_acct_paranoia_check_nolock(c, jeb); |
1da177e4c Linux-2.6.12-rc2 |
179 |
} |
9bfeb691e [JFFS2] Switch to... |
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_node_ref *raw, union jffs2_node_union *node) { struct jffs2_node_frag *frag; struct jffs2_full_dirent *fd; dbg_noderef("incore_replace_raw: node at %p is {%04x,%04x} ", node, je16_to_cpu(node->u.magic), je16_to_cpu(node->u.nodetype)); BUG_ON(je16_to_cpu(node->u.magic) != 0x1985 && je16_to_cpu(node->u.magic) != 0); switch (je16_to_cpu(node->u.nodetype)) { case JFFS2_NODETYPE_INODE: |
ddc58bd65 [JFFS2] Fix wbuf ... |
197 198 199 200 201 |
if (f->metadata && f->metadata->raw == raw) { dbg_noderef("Will replace ->raw in f->metadata at %p ", f->metadata); return &f->metadata->raw; } |
9bfeb691e [JFFS2] Switch to... |
202 203 204 205 206 207 208 209 210 211 |
frag = jffs2_lookup_node_frag(&f->fragtree, je32_to_cpu(node->i.offset)); BUG_ON(!frag); /* Find a frag which refers to the full_dnode we want to modify */ while (!frag->node || frag->node->raw != raw) { frag = frag_next(frag); BUG_ON(!frag); } dbg_noderef("Will replace ->raw in full_dnode at %p ", frag->node); return &frag->node->raw; |
9bfeb691e [JFFS2] Switch to... |
212 213 214 215 216 217 218 219 220 221 |
case JFFS2_NODETYPE_DIRENT: for (fd = f->dents; fd; fd = fd->next) { if (fd->raw == raw) { dbg_noderef("Will replace ->raw in full_dirent at %p ", fd); return &fd->raw; } } BUG(); |
ddc58bd65 [JFFS2] Fix wbuf ... |
222 |
|
9bfeb691e [JFFS2] Switch to... |
223 224 225 226 227 228 229 230 |
default: dbg_noderef("Don't care about replacing raw for nodetype %x ", je16_to_cpu(node->u.nodetype)); break; } return NULL; } |
a6bc432e2 [JFFS2] Add suppo... |
231 232 233 234 235 236 237 |
#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf, uint32_t ofs) { int ret; size_t retlen; char *eccstr; |
329ad399a mtd: introduce mt... |
238 |
ret = mtd_read(c->mtd, ofs, c->wbuf_pagesize, &retlen, c->wbuf_verify); |
a6bc432e2 [JFFS2] Add suppo... |
239 |
if (ret && ret != -EUCLEAN && ret != -EBADMSG) { |
da320f055 jffs2: Convert pr... |
240 241 242 |
pr_warn("%s(): Read back of page at %08x failed: %d ", __func__, c->wbuf_ofs, ret); |
a6bc432e2 [JFFS2] Add suppo... |
243 244 |
return ret; } else if (retlen != c->wbuf_pagesize) { |
da320f055 jffs2: Convert pr... |
245 246 247 |
pr_warn("%s(): Read back of page at %08x gave short read: %zd not %d ", __func__, ofs, retlen, c->wbuf_pagesize); |
a6bc432e2 [JFFS2] Add suppo... |
248 249 250 251 252 253 254 255 256 257 258 |
return -EIO; } if (!memcmp(buf, c->wbuf_verify, c->wbuf_pagesize)) return 0; if (ret == -EUCLEAN) eccstr = "corrected"; else if (ret == -EBADMSG) eccstr = "correction failed"; else eccstr = "OK or unused"; |
da320f055 jffs2: Convert pr... |
259 260 261 |
pr_warn("Write verify error (ECC %s) at %08x. Wrote: ", eccstr, c->wbuf_ofs); |
a6bc432e2 [JFFS2] Add suppo... |
262 263 |
print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, c->wbuf, c->wbuf_pagesize, 0); |
da320f055 jffs2: Convert pr... |
264 265 |
pr_warn("Read back: "); |
a6bc432e2 [JFFS2] Add suppo... |
266 267 268 269 270 271 272 273 |
print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, c->wbuf_verify, c->wbuf_pagesize, 0); return -EIO; } #else #define jffs2_verify_write(c,b,o) (0) #endif |
1da177e4c Linux-2.6.12-rc2 |
274 275 276 277 278 279 |
/* Recover from failure to write wbuf. Recover the nodes up to the * wbuf, not the one which we were starting to try to write. */ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) { struct jffs2_eraseblock *jeb, *new_jeb; |
9bfeb691e [JFFS2] Switch to... |
280 |
struct jffs2_raw_node_ref *raw, *next, *first_raw = NULL; |
1da177e4c Linux-2.6.12-rc2 |
281 282 |
size_t retlen; int ret; |
9bfeb691e [JFFS2] Switch to... |
283 |
int nr_refile = 0; |
1da177e4c Linux-2.6.12-rc2 |
284 285 |
unsigned char *buf; uint32_t start, end, ofs, len; |
046b8b980 [JFFS2] Add 'jeb'... |
286 |
jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; |
1da177e4c Linux-2.6.12-rc2 |
287 |
spin_lock(&c->erase_completion_lock); |
180bfb31f [JFFS2] Fix write... |
288 289 290 291 |
if (c->wbuf_ofs % c->mtd->erasesize) jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); else jffs2_block_refile(c, jeb, REFILE_ANYWAY); |
9bfeb691e [JFFS2] Switch to... |
292 293 294 |
spin_unlock(&c->erase_completion_lock); BUG_ON(!ref_obsolete(jeb->last_node)); |
1da177e4c Linux-2.6.12-rc2 |
295 296 297 |
/* Find the first node to be recovered, by skipping over every node which ends before the wbuf starts, or which is obsolete. */ |
9bfeb691e [JFFS2] Switch to... |
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 |
for (next = raw = jeb->first_node; next; raw = next) { next = ref_next(raw); if (ref_obsolete(raw) || (next && ref_offset(next) <= c->wbuf_ofs)) { dbg_noderef("Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete ", ref_offset(raw), ref_flags(raw), (ref_offset(raw) + ref_totlen(c, jeb, raw)), c->wbuf_ofs); continue; } dbg_noderef("First node to be recovered is at 0x%08x(%d)-0x%08x ", ref_offset(raw), ref_flags(raw), (ref_offset(raw) + ref_totlen(c, jeb, raw))); first_raw = raw; break; } if (!first_raw) { |
1da177e4c Linux-2.6.12-rc2 |
320 |
/* All nodes were obsolete. Nothing to recover. */ |
9c261b33a jffs2: Convert mo... |
321 322 |
jffs2_dbg(1, "No non-obsolete nodes to be recovered. Just filing block bad "); |
9bfeb691e [JFFS2] Switch to... |
323 |
c->wbuf_len = 0; |
1da177e4c Linux-2.6.12-rc2 |
324 325 |
return; } |
9bfeb691e [JFFS2] Switch to... |
326 327 328 |
start = ref_offset(first_raw); end = ref_offset(jeb->last_node); nr_refile = 1; |
1da177e4c Linux-2.6.12-rc2 |
329 |
|
9bfeb691e [JFFS2] Switch to... |
330 331 332 |
/* Count the number of refs which need to be copied */ while ((raw = ref_next(raw)) != jeb->last_node) nr_refile++; |
1da177e4c Linux-2.6.12-rc2 |
333 |
|
9bfeb691e [JFFS2] Switch to... |
334 335 336 |
dbg_noderef("wbuf recover %08x-%08x (%d bytes in %d nodes) ", start, end, end - start, nr_refile); |
1da177e4c Linux-2.6.12-rc2 |
337 338 339 340 341 342 343 344 |
buf = NULL; if (start < c->wbuf_ofs) { /* First affected node was already partially written. * Attempt to reread the old data into our buffer. */ buf = kmalloc(end - start, GFP_KERNEL); if (!buf) { |
da320f055 jffs2: Convert pr... |
345 346 |
pr_crit("Malloc failure in wbuf recovery. Data loss ensues. "); |
1da177e4c Linux-2.6.12-rc2 |
347 348 349 350 351 |
goto read_failed; } /* Do the read... */ |
329ad399a mtd: introduce mt... |
352 353 |
ret = mtd_read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf); |
182ec4eee [JFFS2] Clean up ... |
354 |
|
9a1fcdfd4 [MTD] NAND Signal... |
355 356 357 |
/* ECC recovered ? */ if ((ret == -EUCLEAN || ret == -EBADMSG) && (retlen == c->wbuf_ofs - start)) |
1da177e4c Linux-2.6.12-rc2 |
358 |
ret = 0; |
9a1fcdfd4 [MTD] NAND Signal... |
359 |
|
1da177e4c Linux-2.6.12-rc2 |
360 |
if (ret || retlen != c->wbuf_ofs - start) { |
da320f055 jffs2: Convert pr... |
361 362 |
pr_crit("Old data are already lost in wbuf recovery. Data loss ensues. "); |
1da177e4c Linux-2.6.12-rc2 |
363 364 365 366 |
kfree(buf); buf = NULL; read_failed: |
9bfeb691e [JFFS2] Switch to... |
367 368 369 370 371 372 |
first_raw = ref_next(first_raw); nr_refile--; while (first_raw && ref_obsolete(first_raw)) { first_raw = ref_next(first_raw); nr_refile--; } |
1da177e4c Linux-2.6.12-rc2 |
373 |
/* If this was the only node to be recovered, give up */ |
9bfeb691e [JFFS2] Switch to... |
374 375 |
if (!first_raw) { c->wbuf_len = 0; |
1da177e4c Linux-2.6.12-rc2 |
376 |
return; |
9bfeb691e [JFFS2] Switch to... |
377 |
} |
1da177e4c Linux-2.6.12-rc2 |
378 379 |
/* It wasn't. Go on and try to recover nodes complete in the wbuf */ |
9bfeb691e [JFFS2] Switch to... |
380 381 382 383 |
start = ref_offset(first_raw); dbg_noderef("wbuf now recover %08x-%08x (%d bytes in %d nodes) ", start, end, end - start, nr_refile); |
1da177e4c Linux-2.6.12-rc2 |
384 385 386 387 388 389 390 |
} else { /* Read succeeded. Copy the remaining data from the wbuf */ memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs); } } /* OK... we're to rewrite (end-start) bytes of data from first_raw onwards. Either 'buf' contains the data, or we find it in the wbuf */ |
1da177e4c Linux-2.6.12-rc2 |
391 |
/* ... and get an allocation of space from a shiny new block instead */ |
9fe4854cd [JFFS2] Remove fl... |
392 |
ret = jffs2_reserve_space_gc(c, end-start, &len, JFFS2_SUMMARY_NOSUM_SIZE); |
1da177e4c Linux-2.6.12-rc2 |
393 |
if (ret) { |
da320f055 jffs2: Convert pr... |
394 395 |
pr_warn("Failed to allocate space for wbuf recovery. Data loss ensues. "); |
9b88f4739 [JFFS2] Code clea... |
396 |
kfree(buf); |
1da177e4c Linux-2.6.12-rc2 |
397 398 |
return; } |
9bfeb691e [JFFS2] Switch to... |
399 |
|
7f762ab24 [JFFS2] Disable s... |
400 401 |
/* The summary is not recovered, so it must be disabled for this erase block */ jffs2_sum_disable_collecting(c->summary); |
9bfeb691e [JFFS2] Switch to... |
402 403 |
ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, nr_refile); if (ret) { |
da320f055 jffs2: Convert pr... |
404 405 |
pr_warn("Failed to allocate node refs for wbuf recovery. Data loss ensues. "); |
9bfeb691e [JFFS2] Switch to... |
406 407 408 |
kfree(buf); return; } |
9fe4854cd [JFFS2] Remove fl... |
409 |
ofs = write_ofs(c); |
1da177e4c Linux-2.6.12-rc2 |
410 |
if (end-start >= c->wbuf_pagesize) { |
7f716cf3f [JFFS2] Fix block... |
411 |
/* Need to do another write immediately, but it's possible |
9b88f4739 [JFFS2] Code clea... |
412 |
that this is just because the wbuf itself is completely |
182ec4eee [JFFS2] Clean up ... |
413 414 |
full, and there's nothing earlier read back from the flash. Hence 'buf' isn't necessarily what we're writing |
9b88f4739 [JFFS2] Code clea... |
415 |
from. */ |
7f716cf3f [JFFS2] Fix block... |
416 |
unsigned char *rewrite_buf = buf?:c->wbuf; |
1da177e4c Linux-2.6.12-rc2 |
417 |
uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize); |
9c261b33a jffs2: Convert mo... |
418 419 420 |
jffs2_dbg(1, "Write 0x%x bytes at 0x%08x in wbuf recover ", towrite, ofs); |
182ec4eee [JFFS2] Clean up ... |
421 |
|
1da177e4c Linux-2.6.12-rc2 |
422 423 424 |
#ifdef BREAKMEHEADER static int breakme; if (breakme++ == 20) { |
da320f055 jffs2: Convert pr... |
425 426 |
pr_notice("Faking write error at 0x%08x ", ofs); |
1da177e4c Linux-2.6.12-rc2 |
427 |
breakme = 0; |
eda95cbf7 mtd: introduce mt... |
428 |
mtd_write(c->mtd, ofs, towrite, &retlen, brokenbuf); |
1da177e4c Linux-2.6.12-rc2 |
429 430 431 |
ret = -EIO; } else #endif |
eda95cbf7 mtd: introduce mt... |
432 433 |
ret = mtd_write(c->mtd, ofs, towrite, &retlen, rewrite_buf); |
1da177e4c Linux-2.6.12-rc2 |
434 |
|
a6bc432e2 [JFFS2] Add suppo... |
435 |
if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs)) { |
1da177e4c Linux-2.6.12-rc2 |
436 |
/* Argh. We tried. Really we did. */ |
da320f055 jffs2: Convert pr... |
437 438 |
pr_crit("Recovery of wbuf failed due to a second write error "); |
9b88f4739 [JFFS2] Code clea... |
439 |
kfree(buf); |
1da177e4c Linux-2.6.12-rc2 |
440 |
|
2f785402f [JFFS2] Reduce vi... |
441 |
if (retlen) |
9bfeb691e [JFFS2] Switch to... |
442 |
jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, first_raw), NULL); |
1da177e4c Linux-2.6.12-rc2 |
443 |
|
1da177e4c Linux-2.6.12-rc2 |
444 445 |
return; } |
da320f055 jffs2: Convert pr... |
446 447 |
pr_notice("Recovery of wbuf succeeded to %08x ", ofs); |
1da177e4c Linux-2.6.12-rc2 |
448 449 450 |
c->wbuf_len = (end - start) - towrite; c->wbuf_ofs = ofs + towrite; |
7f716cf3f [JFFS2] Fix block... |
451 |
memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len); |
1da177e4c Linux-2.6.12-rc2 |
452 |
/* Don't muck about with c->wbuf_inodes. False positives are harmless. */ |
1da177e4c Linux-2.6.12-rc2 |
453 454 455 456 |
} else { /* OK, now we're left with the dregs in whichever buffer we're using */ if (buf) { memcpy(c->wbuf, buf, end-start); |
1da177e4c Linux-2.6.12-rc2 |
457 458 459 460 461 462 463 464 465 466 467 |
} else { memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start); } c->wbuf_ofs = ofs; c->wbuf_len = end - start; } /* Now sort out the jffs2_raw_node_refs, moving them from the old to the next block */ new_jeb = &c->blocks[ofs / c->sector_size]; spin_lock(&c->erase_completion_lock); |
9bfeb691e [JFFS2] Switch to... |
468 469 470 471 472 473 |
for (raw = first_raw; raw != jeb->last_node; raw = ref_next(raw)) { uint32_t rawlen = ref_totlen(c, jeb, raw); struct jffs2_inode_cache *ic; struct jffs2_raw_node_ref *new_ref; struct jffs2_raw_node_ref **adjust_ref = NULL; struct jffs2_inode_info *f = NULL; |
1da177e4c Linux-2.6.12-rc2 |
474 |
|
9c261b33a jffs2: Convert mo... |
475 476 477 |
jffs2_dbg(1, "Refiling block of %08x at %08x(%d) to %08x ", rawlen, ref_offset(raw), ref_flags(raw), ofs); |
9bfeb691e [JFFS2] Switch to... |
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 |
ic = jffs2_raw_ref_to_ic(raw); /* Ick. This XATTR mess should be fixed shortly... */ if (ic && ic->class == RAWNODE_CLASS_XATTR_DATUM) { struct jffs2_xattr_datum *xd = (void *)ic; BUG_ON(xd->node != raw); adjust_ref = &xd->node; raw->next_in_ino = NULL; ic = NULL; } else if (ic && ic->class == RAWNODE_CLASS_XATTR_REF) { struct jffs2_xattr_datum *xr = (void *)ic; BUG_ON(xr->node != raw); adjust_ref = &xr->node; raw->next_in_ino = NULL; ic = NULL; } else if (ic && ic->class == RAWNODE_CLASS_INODE_CACHE) { struct jffs2_raw_node_ref **p = &ic->nodes; /* Remove the old node from the per-inode list */ while (*p && *p != (void *)ic) { if (*p == raw) { (*p) = (raw->next_in_ino); raw->next_in_ino = NULL; break; } p = &((*p)->next_in_ino); } |
1da177e4c Linux-2.6.12-rc2 |
506 |
|
9bfeb691e [JFFS2] Switch to... |
507 508 509 510 |
if (ic->state == INO_STATE_PRESENT && !ref_obsolete(raw)) { /* If it's an in-core inode, then we have to adjust any full_dirent or full_dnode structure to point to the new version instead of the old */ |
27c72b040 [JFFS2] Track par... |
511 |
f = jffs2_gc_fetch_inode(c, ic->ino, !ic->pino_nlink); |
9bfeb691e [JFFS2] Switch to... |
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 |
if (IS_ERR(f)) { /* Should never happen; it _must_ be present */ JFFS2_ERROR("Failed to iget() ino #%u, err %ld ", ic->ino, PTR_ERR(f)); BUG(); } /* We don't lock f->sem. There's a number of ways we could end up in here with it already being locked, and nobody's going to modify it on us anyway because we hold the alloc_sem. We're only changing one ->raw pointer too, which we can get away with without upsetting readers. */ adjust_ref = jffs2_incore_replace_raw(c, f, raw, (void *)(buf?:c->wbuf) + (ref_offset(raw) - start)); } else if (unlikely(ic->state != INO_STATE_PRESENT && ic->state != INO_STATE_CHECKEDABSENT && ic->state != INO_STATE_GC)) { JFFS2_ERROR("Inode #%u is in strange state %d! ", ic->ino, ic->state); BUG(); } } new_ref = jffs2_link_node_ref(c, new_jeb, ofs | ref_flags(raw), rawlen, ic); if (adjust_ref) { BUG_ON(*adjust_ref != raw); *adjust_ref = new_ref; } if (f) jffs2_gc_release_inode(c, f); if (!ref_obsolete(raw)) { |
1da177e4c Linux-2.6.12-rc2 |
545 546 547 |
jeb->dirty_size += rawlen; jeb->used_size -= rawlen; c->dirty_size += rawlen; |
9bfeb691e [JFFS2] Switch to... |
548 549 550 |
c->used_size -= rawlen; raw->flash_offset = ref_offset(raw) | REF_OBSOLETE; BUG_ON(raw->next_in_ino); |
1da177e4c Linux-2.6.12-rc2 |
551 |
} |
1da177e4c Linux-2.6.12-rc2 |
552 |
ofs += rawlen; |
1da177e4c Linux-2.6.12-rc2 |
553 |
} |
9bfeb691e [JFFS2] Switch to... |
554 |
kfree(buf); |
1da177e4c Linux-2.6.12-rc2 |
555 |
/* Fix up the original jeb now it's on the bad_list */ |
9bfeb691e [JFFS2] Switch to... |
556 |
if (first_raw == jeb->first_node) { |
9c261b33a jffs2: Convert mo... |
557 558 559 |
jffs2_dbg(1, "Failing block at %08x is now empty. Moving to erase_pending_list ", jeb->offset); |
f116629d0 [PATCH] fs: use l... |
560 |
list_move(&jeb->list, &c->erase_pending_list); |
1da177e4c Linux-2.6.12-rc2 |
561 |
c->nr_erasing_blocks++; |
ae3b6ba06 jffs2: Use jffs2_... |
562 |
jffs2_garbage_collect_trigger(c); |
1da177e4c Linux-2.6.12-rc2 |
563 |
} |
1da177e4c Linux-2.6.12-rc2 |
564 |
|
e0c8e42f8 [JFFS2] Debug cod... |
565 |
jffs2_dbg_acct_sanity_check_nolock(c, jeb); |
9bfeb691e [JFFS2] Switch to... |
566 |
jffs2_dbg_acct_paranoia_check_nolock(c, jeb); |
1da177e4c Linux-2.6.12-rc2 |
567 |
|
e0c8e42f8 [JFFS2] Debug cod... |
568 |
jffs2_dbg_acct_sanity_check_nolock(c, new_jeb); |
9bfeb691e [JFFS2] Switch to... |
569 |
jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb); |
1da177e4c Linux-2.6.12-rc2 |
570 571 |
spin_unlock(&c->erase_completion_lock); |
9c261b33a jffs2: Convert mo... |
572 573 574 |
jffs2_dbg(1, "wbuf recovery completed OK. wbuf_ofs 0x%08x, len 0x%x ", c->wbuf_ofs, c->wbuf_len); |
9bfeb691e [JFFS2] Switch to... |
575 |
|
1da177e4c Linux-2.6.12-rc2 |
576 577 578 579 580 581 582 583 584 585 586 587 588 |
} /* Meaning of pad argument: 0: Do not pad. Probably pointless - we only ever use this when we can't pad anyway. 1: Pad, do not adjust nextblock free_size 2: Pad, adjust nextblock free_size */ #define NOPAD 0 #define PAD_NOACCOUNT 1 #define PAD_ACCOUNTING 2 static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) { |
9bfeb691e [JFFS2] Switch to... |
589 |
struct jffs2_eraseblock *wbuf_jeb; |
1da177e4c Linux-2.6.12-rc2 |
590 591 |
int ret; size_t retlen; |
3be36675d [JFFS2] Core chan... |
592 |
/* Nothing to do if not write-buffering the flash. In particular, we shouldn't |
1da177e4c Linux-2.6.12-rc2 |
593 |
del_timer() the timer we never initialised. */ |
3be36675d [JFFS2] Core chan... |
594 |
if (!jffs2_is_writebuffered(c)) |
1da177e4c Linux-2.6.12-rc2 |
595 |
return 0; |
51b11e363 jffs2: use mutex_... |
596 |
if (!mutex_is_locked(&c->alloc_sem)) { |
da320f055 jffs2: Convert pr... |
597 598 |
pr_crit("jffs2_flush_wbuf() called with alloc_sem not locked! "); |
1da177e4c Linux-2.6.12-rc2 |
599 600 |
BUG(); } |
3be36675d [JFFS2] Core chan... |
601 |
if (!c->wbuf_len) /* already checked c->wbuf above */ |
1da177e4c Linux-2.6.12-rc2 |
602 |
return 0; |
9bfeb691e [JFFS2] Switch to... |
603 604 |
wbuf_jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; if (jffs2_prealloc_raw_node_refs(c, wbuf_jeb, c->nextblock->allocated_refs + 1)) |
2f785402f [JFFS2] Reduce vi... |
605 |
return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
606 607 608 609 |
/* claim remaining space on the page this happens, if we have a change to a new block, or if fsync forces us to flush the writebuffer. if we have a switch to next page, we will not have |
182ec4eee [JFFS2] Clean up ... |
610 |
enough remaining space for this. |
1da177e4c Linux-2.6.12-rc2 |
611 |
*/ |
daba5cc4b [JFFS2] Fix dataf... |
612 |
if (pad ) { |
1da177e4c Linux-2.6.12-rc2 |
613 614 615 616 617 |
c->wbuf_len = PAD(c->wbuf_len); /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR with 8 byte page size */ memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len); |
182ec4eee [JFFS2] Clean up ... |
618 |
|
1da177e4c Linux-2.6.12-rc2 |
619 620 621 622 623 624 625 626 627 628 |
if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) { struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len); padnode->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); padnode->nodetype = cpu_to_je16(JFFS2_NODETYPE_PADDING); padnode->totlen = cpu_to_je32(c->wbuf_pagesize - c->wbuf_len); padnode->hdr_crc = cpu_to_je32(crc32(0, padnode, sizeof(*padnode)-4)); } } /* else jffs2_flash_writev has actually filled in the rest of the buffer for us, and will deal with the node refs etc. later. */ |
182ec4eee [JFFS2] Clean up ... |
629 |
|
1da177e4c Linux-2.6.12-rc2 |
630 631 632 |
#ifdef BREAKME static int breakme; if (breakme++ == 20) { |
da320f055 jffs2: Convert pr... |
633 634 |
pr_notice("Faking write error at 0x%08x ", c->wbuf_ofs); |
1da177e4c Linux-2.6.12-rc2 |
635 |
breakme = 0; |
eda95cbf7 mtd: introduce mt... |
636 637 |
mtd_write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, brokenbuf); |
1da177e4c Linux-2.6.12-rc2 |
638 |
ret = -EIO; |
182ec4eee [JFFS2] Clean up ... |
639 |
} else |
1da177e4c Linux-2.6.12-rc2 |
640 |
#endif |
182ec4eee [JFFS2] Clean up ... |
641 |
|
eda95cbf7 mtd: introduce mt... |
642 643 |
ret = mtd_write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf); |
1da177e4c Linux-2.6.12-rc2 |
644 |
|
a6bc432e2 [JFFS2] Add suppo... |
645 |
if (ret) { |
da320f055 jffs2: Convert pr... |
646 647 |
pr_warn("jffs2_flush_wbuf(): Write failed with %d ", ret); |
a6bc432e2 [JFFS2] Add suppo... |
648 649 |
goto wfail; } else if (retlen != c->wbuf_pagesize) { |
da320f055 jffs2: Convert pr... |
650 651 652 |
pr_warn("jffs2_flush_wbuf(): Write was short: %zd instead of %d ", retlen, c->wbuf_pagesize); |
a6bc432e2 [JFFS2] Add suppo... |
653 654 655 656 |
ret = -EIO; goto wfail; } else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) { wfail: |
1da177e4c Linux-2.6.12-rc2 |
657 658 659 660 |
jffs2_wbuf_recover(c); return ret; } |
1da177e4c Linux-2.6.12-rc2 |
661 |
/* Adjust free size of the block if we padded. */ |
daba5cc4b [JFFS2] Fix dataf... |
662 |
if (pad) { |
0bcc099d6 [JFFS2] File node... |
663 |
uint32_t waste = c->wbuf_pagesize - c->wbuf_len; |
1da177e4c Linux-2.6.12-rc2 |
664 |
|
9c261b33a jffs2: Convert mo... |
665 666 667 668 |
jffs2_dbg(1, "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x ", (wbuf_jeb == c->nextblock) ? "next" : "", wbuf_jeb->offset); |
1da177e4c Linux-2.6.12-rc2 |
669 |
|
182ec4eee [JFFS2] Clean up ... |
670 |
/* wbuf_pagesize - wbuf_len is the amount of space that's to be |
1da177e4c Linux-2.6.12-rc2 |
671 672 |
padded. If there is less free space in the block than that, something screwed up */ |
9bfeb691e [JFFS2] Switch to... |
673 |
if (wbuf_jeb->free_size < waste) { |
da320f055 jffs2: Convert pr... |
674 675 676 677 678 679 |
pr_crit("jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left. ", c->wbuf_ofs, c->wbuf_len, waste); pr_crit("jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x ", wbuf_jeb->offset, wbuf_jeb->free_size); |
1da177e4c Linux-2.6.12-rc2 |
680 681 |
BUG(); } |
0bcc099d6 [JFFS2] File node... |
682 683 |
spin_lock(&c->erase_completion_lock); |
9bfeb691e [JFFS2] Switch to... |
684 |
jffs2_link_node_ref(c, wbuf_jeb, (c->wbuf_ofs + c->wbuf_len) | REF_OBSOLETE, waste, NULL); |
0bcc099d6 [JFFS2] File node... |
685 |
/* FIXME: that made it count as dirty. Convert to wasted */ |
9bfeb691e [JFFS2] Switch to... |
686 |
wbuf_jeb->dirty_size -= waste; |
0bcc099d6 [JFFS2] File node... |
687 |
c->dirty_size -= waste; |
9bfeb691e [JFFS2] Switch to... |
688 |
wbuf_jeb->wasted_size += waste; |
0bcc099d6 [JFFS2] File node... |
689 690 691 |
c->wasted_size += waste; } else spin_lock(&c->erase_completion_lock); |
1da177e4c Linux-2.6.12-rc2 |
692 693 694 695 696 697 698 699 |
/* Stick any now-obsoleted blocks on the erase_pending_list */ jffs2_refile_wbuf_blocks(c); jffs2_clear_wbuf_ino_list(c); spin_unlock(&c->erase_completion_lock); memset(c->wbuf,0xff,c->wbuf_pagesize); /* adjust write buffer offset, else we get a non contiguous write bug */ |
5bf172372 [JFFS2] Write buf... |
700 |
c->wbuf_ofs += c->wbuf_pagesize; |
1da177e4c Linux-2.6.12-rc2 |
701 702 703 |
c->wbuf_len = 0; return 0; } |
182ec4eee [JFFS2] Clean up ... |
704 |
/* Trigger garbage collection to flush the write-buffer. |
1da177e4c Linux-2.6.12-rc2 |
705 |
If ino arg is zero, do it if _any_ real (i.e. not GC) writes are |
182ec4eee [JFFS2] Clean up ... |
706 |
outstanding. If ino arg non-zero, do it only if a write for the |
1da177e4c Linux-2.6.12-rc2 |
707 708 709 710 711 712 |
given inode is outstanding. */ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) { uint32_t old_wbuf_ofs; uint32_t old_wbuf_len; int ret = 0; |
9c261b33a jffs2: Convert mo... |
713 714 |
jffs2_dbg(1, "jffs2_flush_wbuf_gc() called for ino #%u... ", ino); |
1da177e4c Linux-2.6.12-rc2 |
715 |
|
8aee6ac14 [JFFS2] Remove NA... |
716 717 |
if (!c->wbuf) return 0; |
ced220703 [JFFS2] semaphore... |
718 |
mutex_lock(&c->alloc_sem); |
1da177e4c Linux-2.6.12-rc2 |
719 |
if (!jffs2_wbuf_pending_for_ino(c, ino)) { |
9c261b33a jffs2: Convert mo... |
720 721 |
jffs2_dbg(1, "Ino #%d not pending in wbuf. Returning ", ino); |
ced220703 [JFFS2] semaphore... |
722 |
mutex_unlock(&c->alloc_sem); |
1da177e4c Linux-2.6.12-rc2 |
723 724 725 726 727 728 729 730 |
return 0; } old_wbuf_ofs = c->wbuf_ofs; old_wbuf_len = c->wbuf_len; if (c->unchecked_size) { /* GC won't make any progress for a while */ |
9c261b33a jffs2: Convert mo... |
731 732 733 |
jffs2_dbg(1, "%s(): padding. Not finished checking ", __func__); |
1da177e4c Linux-2.6.12-rc2 |
734 735 |
down_write(&c->wbuf_sem); ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); |
7f716cf3f [JFFS2] Fix block... |
736 737 738 |
/* retry flushing wbuf in case jffs2_wbuf_recover left some data in the wbuf */ if (ret) |
7f716cf3f [JFFS2] Fix block... |
739 |
ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); |
1da177e4c Linux-2.6.12-rc2 |
740 741 742 |
up_write(&c->wbuf_sem); } else while (old_wbuf_len && old_wbuf_ofs == c->wbuf_ofs) { |
ced220703 [JFFS2] semaphore... |
743 |
mutex_unlock(&c->alloc_sem); |
1da177e4c Linux-2.6.12-rc2 |
744 |
|
9c261b33a jffs2: Convert mo... |
745 746 |
jffs2_dbg(1, "%s(): calls gc pass ", __func__); |
1da177e4c Linux-2.6.12-rc2 |
747 748 749 750 |
ret = jffs2_garbage_collect_pass(c); if (ret) { /* GC failed. Flush it with padding instead */ |
ced220703 [JFFS2] semaphore... |
751 |
mutex_lock(&c->alloc_sem); |
1da177e4c Linux-2.6.12-rc2 |
752 753 |
down_write(&c->wbuf_sem); ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); |
7f716cf3f [JFFS2] Fix block... |
754 755 756 |
/* retry flushing wbuf in case jffs2_wbuf_recover left some data in the wbuf */ if (ret) |
7f716cf3f [JFFS2] Fix block... |
757 |
ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); |
1da177e4c Linux-2.6.12-rc2 |
758 759 760 |
up_write(&c->wbuf_sem); break; } |
ced220703 [JFFS2] semaphore... |
761 |
mutex_lock(&c->alloc_sem); |
1da177e4c Linux-2.6.12-rc2 |
762 |
} |
9c261b33a jffs2: Convert mo... |
763 764 |
jffs2_dbg(1, "%s(): ends... ", __func__); |
1da177e4c Linux-2.6.12-rc2 |
765 |
|
ced220703 [JFFS2] semaphore... |
766 |
mutex_unlock(&c->alloc_sem); |
1da177e4c Linux-2.6.12-rc2 |
767 768 769 770 771 772 773 |
return ret; } /* Pad write-buffer to end and write it, wasting space. */ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) { int ret; |
8aee6ac14 [JFFS2] Remove NA... |
774 775 |
if (!c->wbuf) return 0; |
1da177e4c Linux-2.6.12-rc2 |
776 777 |
down_write(&c->wbuf_sem); ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); |
7f716cf3f [JFFS2] Fix block... |
778 779 780 |
/* retry - maybe wbuf recover left some data in wbuf. */ if (ret) ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); |
1da177e4c Linux-2.6.12-rc2 |
781 782 783 784 |
up_write(&c->wbuf_sem); return ret; } |
dcb093288 [JFFS2] Simplify ... |
785 786 787 |
static size_t jffs2_fill_wbuf(struct jffs2_sb_info *c, const uint8_t *buf, size_t len) |
1da177e4c Linux-2.6.12-rc2 |
788 |
{ |
dcb093288 [JFFS2] Simplify ... |
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 |
if (len && !c->wbuf_len && (len >= c->wbuf_pagesize)) return 0; if (len > (c->wbuf_pagesize - c->wbuf_len)) len = c->wbuf_pagesize - c->wbuf_len; memcpy(c->wbuf + c->wbuf_len, buf, len); c->wbuf_len += (uint32_t) len; return len; } 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) { struct jffs2_eraseblock *jeb; size_t wbuf_retlen, donelen = 0; |
1da177e4c Linux-2.6.12-rc2 |
805 |
uint32_t outvec_to = to; |
dcb093288 [JFFS2] Simplify ... |
806 |
int ret, invec; |
1da177e4c Linux-2.6.12-rc2 |
807 |
|
dcb093288 [JFFS2] Simplify ... |
808 |
/* If not writebuffered flash, don't bother */ |
3be36675d [JFFS2] Core chan... |
809 |
if (!jffs2_is_writebuffered(c)) |
1da177e4c Linux-2.6.12-rc2 |
810 |
return jffs2_flash_direct_writev(c, invecs, count, to, retlen); |
182ec4eee [JFFS2] Clean up ... |
811 |
|
1da177e4c Linux-2.6.12-rc2 |
812 813 814 815 816 |
down_write(&c->wbuf_sem); /* If wbuf_ofs is not initialized, set it to target address */ if (c->wbuf_ofs == 0xFFFFFFFF) { c->wbuf_ofs = PAGE_DIV(to); |
182ec4eee [JFFS2] Clean up ... |
817 |
c->wbuf_len = PAGE_MOD(to); |
1da177e4c Linux-2.6.12-rc2 |
818 819 |
memset(c->wbuf,0xff,c->wbuf_pagesize); } |
dcb093288 [JFFS2] Simplify ... |
820 |
/* |
dcb093288 [JFFS2] Simplify ... |
821 822 823 824 825 826 |
* Sanity checks on target address. It's permitted to write * at PAD(c->wbuf_len+c->wbuf_ofs), and it's permitted to * write at the beginning of a new erase block. Anything else, * and you die. New block starts at xxx000c (0-b = block * header) */ |
3be36675d [JFFS2] Core chan... |
827 |
if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) { |
1da177e4c Linux-2.6.12-rc2 |
828 829 |
/* It's a write to a new block */ if (c->wbuf_len) { |
9c261b33a jffs2: Convert mo... |
830 831 832 |
jffs2_dbg(1, "%s(): to 0x%lx causes flush of wbuf at 0x%08x ", __func__, (unsigned long)to, c->wbuf_ofs); |
1da177e4c Linux-2.6.12-rc2 |
833 |
ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); |
dcb093288 [JFFS2] Simplify ... |
834 835 |
if (ret) goto outerr; |
1da177e4c Linux-2.6.12-rc2 |
836 837 838 |
} /* set pointer to new block */ c->wbuf_ofs = PAGE_DIV(to); |
182ec4eee [JFFS2] Clean up ... |
839 840 |
c->wbuf_len = PAGE_MOD(to); } |
1da177e4c Linux-2.6.12-rc2 |
841 842 843 |
if (to != PAD(c->wbuf_ofs + c->wbuf_len)) { /* We're not writing immediately after the writebuffer. Bad. */ |
da320f055 jffs2: Convert pr... |
844 845 846 |
pr_crit("%s(): Non-contiguous write to %08lx ", __func__, (unsigned long)to); |
1da177e4c Linux-2.6.12-rc2 |
847 |
if (c->wbuf_len) |
da320f055 jffs2: Convert pr... |
848 849 850 |
pr_crit("wbuf was previously %08x-%08x ", c->wbuf_ofs, c->wbuf_ofs + c->wbuf_len); |
1da177e4c Linux-2.6.12-rc2 |
851 852 |
BUG(); } |
dcb093288 [JFFS2] Simplify ... |
853 854 855 856 857 858 859 860 861 |
/* adjust alignment offset */ if (c->wbuf_len != PAGE_MOD(to)) { c->wbuf_len = PAGE_MOD(to); /* take care of alignment to next page */ if (!c->wbuf_len) { c->wbuf_len = c->wbuf_pagesize; ret = __jffs2_flush_wbuf(c, NOPAD); if (ret) goto outerr; |
1da177e4c Linux-2.6.12-rc2 |
862 863 |
} } |
dcb093288 [JFFS2] Simplify ... |
864 865 866 |
for (invec = 0; invec < count; invec++) { int vlen = invecs[invec].iov_len; uint8_t *v = invecs[invec].iov_base; |
7f716cf3f [JFFS2] Fix block... |
867 |
|
dcb093288 [JFFS2] Simplify ... |
868 |
wbuf_retlen = jffs2_fill_wbuf(c, v, vlen); |
7f716cf3f [JFFS2] Fix block... |
869 |
|
dcb093288 [JFFS2] Simplify ... |
870 871 872 873 |
if (c->wbuf_len == c->wbuf_pagesize) { ret = __jffs2_flush_wbuf(c, NOPAD); if (ret) goto outerr; |
1da177e4c Linux-2.6.12-rc2 |
874 |
} |
dcb093288 [JFFS2] Simplify ... |
875 876 |
vlen -= wbuf_retlen; outvec_to += wbuf_retlen; |
1da177e4c Linux-2.6.12-rc2 |
877 |
donelen += wbuf_retlen; |
dcb093288 [JFFS2] Simplify ... |
878 879 880 |
v += wbuf_retlen; if (vlen >= c->wbuf_pagesize) { |
eda95cbf7 mtd: introduce mt... |
881 882 |
ret = mtd_write(c->mtd, outvec_to, PAGE_DIV(vlen), &wbuf_retlen, v); |
dcb093288 [JFFS2] Simplify ... |
883 884 885 886 887 888 889 890 |
if (ret < 0 || wbuf_retlen != PAGE_DIV(vlen)) goto outfile; vlen -= wbuf_retlen; outvec_to += wbuf_retlen; c->wbuf_ofs = outvec_to; donelen += wbuf_retlen; v += wbuf_retlen; |
1da177e4c Linux-2.6.12-rc2 |
891 |
} |
dcb093288 [JFFS2] Simplify ... |
892 893 894 895 896 897 |
wbuf_retlen = jffs2_fill_wbuf(c, v, vlen); if (c->wbuf_len == c->wbuf_pagesize) { ret = __jffs2_flush_wbuf(c, NOPAD); if (ret) goto outerr; } |
1da177e4c Linux-2.6.12-rc2 |
898 |
|
dcb093288 [JFFS2] Simplify ... |
899 900 |
outvec_to += wbuf_retlen; donelen += wbuf_retlen; |
1da177e4c Linux-2.6.12-rc2 |
901 |
} |
1da177e4c Linux-2.6.12-rc2 |
902 |
|
dcb093288 [JFFS2] Simplify ... |
903 904 905 906 |
/* * If there's a remainder in the wbuf and it's a non-GC write, * remember that the wbuf affects this ino */ |
1da177e4c Linux-2.6.12-rc2 |
907 |
*retlen = donelen; |
e631ddba5 [JFFS2] Add erase... |
908 909 910 911 912 |
if (jffs2_sum_active()) { int res = jffs2_sum_add_kvec(c, invecs, count, (uint32_t) to); if (res) return res; } |
1da177e4c Linux-2.6.12-rc2 |
913 914 915 916 |
if (c->wbuf_len && ino) jffs2_wbuf_dirties_inode(c, ino); ret = 0; |
dcb093288 [JFFS2] Simplify ... |
917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 |
up_write(&c->wbuf_sem); return ret; outfile: /* * At this point we have no problem, c->wbuf is empty. However * refile nextblock to avoid writing again to same address. */ spin_lock(&c->erase_completion_lock); jeb = &c->blocks[outvec_to / c->sector_size]; jffs2_block_refile(c, jeb, REFILE_ANYWAY); spin_unlock(&c->erase_completion_lock); |
182ec4eee [JFFS2] Clean up ... |
932 |
|
dcb093288 [JFFS2] Simplify ... |
933 934 |
outerr: *retlen = 0; |
1da177e4c Linux-2.6.12-rc2 |
935 936 937 938 939 940 941 942 |
up_write(&c->wbuf_sem); return ret; } /* * This is the entry for flash write. * Check, if we work on NAND FLASH, if so build an kvec and write it via vritev */ |
9bfeb691e [JFFS2] Switch to... |
943 944 |
int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf) |
1da177e4c Linux-2.6.12-rc2 |
945 946 |
{ struct kvec vecs[1]; |
3be36675d [JFFS2] Core chan... |
947 |
if (!jffs2_is_writebuffered(c)) |
e631ddba5 [JFFS2] Add erase... |
948 |
return jffs2_flash_direct_write(c, ofs, len, retlen, buf); |
1da177e4c Linux-2.6.12-rc2 |
949 950 951 952 953 954 955 956 957 958 959 960 961 |
vecs[0].iov_base = (unsigned char *) buf; vecs[0].iov_len = len; return jffs2_flash_writev(c, vecs, 1, ofs, retlen, 0); } /* Handle readback from writebuffer and ECC failure return */ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf) { loff_t orbf = 0, owbf = 0, lwbf = 0; int ret; |
3be36675d [JFFS2] Core chan... |
962 |
if (!jffs2_is_writebuffered(c)) |
329ad399a mtd: introduce mt... |
963 |
return mtd_read(c->mtd, ofs, len, retlen, buf); |
1da177e4c Linux-2.6.12-rc2 |
964 |
|
3be36675d [JFFS2] Core chan... |
965 |
/* Read flash */ |
894214d1a [JFFS2] Fix race ... |
966 |
down_read(&c->wbuf_sem); |
329ad399a mtd: introduce mt... |
967 |
ret = mtd_read(c->mtd, ofs, len, retlen, buf); |
3be36675d [JFFS2] Core chan... |
968 |
|
9a1fcdfd4 [MTD] NAND Signal... |
969 970 |
if ( (ret == -EBADMSG || ret == -EUCLEAN) && (*retlen == len) ) { if (ret == -EBADMSG) |
da320f055 jffs2: Convert pr... |
971 972 973 |
pr_warn("mtd->read(0x%zx bytes from 0x%llx) returned ECC error ", len, ofs); |
182ec4eee [JFFS2] Clean up ... |
974 |
/* |
9a1fcdfd4 [MTD] NAND Signal... |
975 976 977 978 979 980 981 |
* We have the raw data without ECC correction in the buffer, * maybe we are lucky and all data or parts are correct. We * check the node. If data are corrupted node check will sort * it out. We keep this block, it will fail on write or erase * and the we mark it bad. Or should we do that now? But we * should give him a chance. Maybe we had a system crash or * power loss before the ecc write or a erase was completed. |
3be36675d [JFFS2] Core chan... |
982 983 |
* So we return success. :) */ |
9a1fcdfd4 [MTD] NAND Signal... |
984 |
ret = 0; |
182ec4eee [JFFS2] Clean up ... |
985 |
} |
3be36675d [JFFS2] Core chan... |
986 |
|
1da177e4c Linux-2.6.12-rc2 |
987 988 |
/* if no writebuffer available or write buffer empty, return */ if (!c->wbuf_pagesize || !c->wbuf_len) |
894214d1a [JFFS2] Fix race ... |
989 |
goto exit; |
1da177e4c Linux-2.6.12-rc2 |
990 991 |
/* if we read in a different block, return */ |
3be36675d [JFFS2] Core chan... |
992 |
if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs)) |
894214d1a [JFFS2] Fix race ... |
993 |
goto exit; |
1da177e4c Linux-2.6.12-rc2 |
994 995 996 997 998 999 |
if (ofs >= c->wbuf_ofs) { owbf = (ofs - c->wbuf_ofs); /* offset in write buffer */ if (owbf > c->wbuf_len) /* is read beyond write buffer ? */ goto exit; lwbf = c->wbuf_len - owbf; /* number of bytes to copy */ |
182ec4eee [JFFS2] Clean up ... |
1000 |
if (lwbf > len) |
1da177e4c Linux-2.6.12-rc2 |
1001 |
lwbf = len; |
182ec4eee [JFFS2] Clean up ... |
1002 |
} else { |
1da177e4c Linux-2.6.12-rc2 |
1003 1004 1005 |
orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */ if (orbf > len) /* is write beyond write buffer ? */ goto exit; |
9a1fcdfd4 [MTD] NAND Signal... |
1006 |
lwbf = len - orbf; /* number of bytes to copy */ |
182ec4eee [JFFS2] Clean up ... |
1007 |
if (lwbf > c->wbuf_len) |
1da177e4c Linux-2.6.12-rc2 |
1008 |
lwbf = c->wbuf_len; |
182ec4eee [JFFS2] Clean up ... |
1009 |
} |
1da177e4c Linux-2.6.12-rc2 |
1010 1011 1012 1013 1014 1015 1016 |
if (lwbf > 0) memcpy(buf+orbf,c->wbuf+owbf,lwbf); exit: up_read(&c->wbuf_sem); return ret; } |
a7a6ace14 [JFFS2] Use MTD_O... |
1017 |
#define NR_OOB_SCAN_PAGES 4 |
09b3fba56 [JFFS2] Correct c... |
1018 1019 |
/* For historical reasons we use only 8 bytes for OOB clean marker */ #define OOB_CM_SIZE 8 |
a7a6ace14 [JFFS2] Use MTD_O... |
1020 1021 1022 |
static const struct jffs2_unknown_node oob_cleanmarker = { |
566865a2a [JFFS2] Fix cross... |
1023 1024 1025 |
.magic = constant_cpu_to_je16(JFFS2_MAGIC_BITMASK), .nodetype = constant_cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER), .totlen = constant_cpu_to_je32(8) |
a7a6ace14 [JFFS2] Use MTD_O... |
1026 |
}; |
8593fbc68 [MTD] Rework the ... |
1027 |
|
1da177e4c Linux-2.6.12-rc2 |
1028 |
/* |
a7a6ace14 [JFFS2] Use MTD_O... |
1029 1030 |
* Check, if the out of band area is empty. This function knows about the clean * marker and if it is present in OOB, treats the OOB as empty anyway. |
1da177e4c Linux-2.6.12-rc2 |
1031 |
*/ |
8593fbc68 [MTD] Rework the ... |
1032 1033 |
int jffs2_check_oob_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int mode) |
1da177e4c Linux-2.6.12-rc2 |
1034 |
{ |
a7a6ace14 [JFFS2] Use MTD_O... |
1035 1036 |
int i, ret; int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); |
8593fbc68 [MTD] Rework the ... |
1037 |
struct mtd_oob_ops ops; |
0612b9ddc mtd: rename MTD_O... |
1038 |
ops.mode = MTD_OPS_AUTO_OOB; |
a7a6ace14 [JFFS2] Use MTD_O... |
1039 |
ops.ooblen = NR_OOB_SCAN_PAGES * c->oobavail; |
8593fbc68 [MTD] Rework the ... |
1040 |
ops.oobbuf = c->oobbuf; |
a7a6ace14 [JFFS2] Use MTD_O... |
1041 |
ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; |
8593fbc68 [MTD] Rework the ... |
1042 |
ops.datbuf = NULL; |
8593fbc68 [MTD] Rework the ... |
1043 |
|
fd2819bbc mtd: introduce mt... |
1044 |
ret = mtd_read_oob(c->mtd, jeb->offset, &ops); |
74d83beaa JFFS2: don't fail... |
1045 |
if ((ret && !mtd_is_bitflip(ret)) || ops.oobretlen != ops.ooblen) { |
da320f055 jffs2: Convert pr... |
1046 1047 1048 |
pr_err("cannot read OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d ", jeb->offset, ops.ooblen, ops.oobretlen, ret); |
74d83beaa JFFS2: don't fail... |
1049 |
if (!ret || mtd_is_bitflip(ret)) |
a7a6ace14 [JFFS2] Use MTD_O... |
1050 |
ret = -EIO; |
8593fbc68 [MTD] Rework the ... |
1051 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
1052 |
} |
182ec4eee [JFFS2] Clean up ... |
1053 |
|
a7a6ace14 [JFFS2] Use MTD_O... |
1054 1055 1056 |
for(i = 0; i < ops.ooblen; i++) { if (mode && i < cmlen) /* Yeah, we know about the cleanmarker */ |
1da177e4c Linux-2.6.12-rc2 |
1057 |
continue; |
8593fbc68 [MTD] Rework the ... |
1058 |
if (ops.oobbuf[i] != 0xFF) { |
9c261b33a jffs2: Convert mo... |
1059 1060 1061 |
jffs2_dbg(2, "Found %02x at %x in OOB for " "%08x ", ops.oobbuf[i], i, jeb->offset); |
8593fbc68 [MTD] Rework the ... |
1062 |
return 1; |
1da177e4c Linux-2.6.12-rc2 |
1063 1064 |
} } |
8593fbc68 [MTD] Rework the ... |
1065 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1066 1067 1068 |
} /* |
a7a6ace14 [JFFS2] Use MTD_O... |
1069 1070 |
* Check for a valid cleanmarker. * Returns: 0 if a valid cleanmarker was found |
ef53cb02f [JFFS2] Whitespac... |
1071 1072 |
* 1 if no cleanmarker was found * negative error code if an error occurred |
8593fbc68 [MTD] Rework the ... |
1073 |
*/ |
a7a6ace14 [JFFS2] Use MTD_O... |
1074 1075 |
int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) |
1da177e4c Linux-2.6.12-rc2 |
1076 |
{ |
8593fbc68 [MTD] Rework the ... |
1077 |
struct mtd_oob_ops ops; |
a7a6ace14 [JFFS2] Use MTD_O... |
1078 |
int ret, cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); |
1da177e4c Linux-2.6.12-rc2 |
1079 |
|
0612b9ddc mtd: rename MTD_O... |
1080 |
ops.mode = MTD_OPS_AUTO_OOB; |
a7a6ace14 [JFFS2] Use MTD_O... |
1081 |
ops.ooblen = cmlen; |
8593fbc68 [MTD] Rework the ... |
1082 |
ops.oobbuf = c->oobbuf; |
a7a6ace14 [JFFS2] Use MTD_O... |
1083 |
ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; |
8593fbc68 [MTD] Rework the ... |
1084 |
ops.datbuf = NULL; |
1da177e4c Linux-2.6.12-rc2 |
1085 |
|
fd2819bbc mtd: introduce mt... |
1086 |
ret = mtd_read_oob(c->mtd, jeb->offset, &ops); |
74d83beaa JFFS2: don't fail... |
1087 |
if ((ret && !mtd_is_bitflip(ret)) || ops.oobretlen != ops.ooblen) { |
da320f055 jffs2: Convert pr... |
1088 1089 1090 |
pr_err("cannot read OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d ", jeb->offset, ops.ooblen, ops.oobretlen, ret); |
74d83beaa JFFS2: don't fail... |
1091 |
if (!ret || mtd_is_bitflip(ret)) |
a7a6ace14 [JFFS2] Use MTD_O... |
1092 |
ret = -EIO; |
8593fbc68 [MTD] Rework the ... |
1093 1094 |
return ret; } |
1da177e4c Linux-2.6.12-rc2 |
1095 |
|
a7a6ace14 [JFFS2] Use MTD_O... |
1096 |
return !!memcmp(&oob_cleanmarker, c->oobbuf, cmlen); |
1da177e4c Linux-2.6.12-rc2 |
1097 |
} |
8593fbc68 [MTD] Rework the ... |
1098 1099 |
int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) |
1da177e4c Linux-2.6.12-rc2 |
1100 |
{ |
a7a6ace14 [JFFS2] Use MTD_O... |
1101 |
int ret; |
8593fbc68 [MTD] Rework the ... |
1102 |
struct mtd_oob_ops ops; |
a7a6ace14 [JFFS2] Use MTD_O... |
1103 |
int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); |
1da177e4c Linux-2.6.12-rc2 |
1104 |
|
0612b9ddc mtd: rename MTD_O... |
1105 |
ops.mode = MTD_OPS_AUTO_OOB; |
a7a6ace14 [JFFS2] Use MTD_O... |
1106 1107 1108 |
ops.ooblen = cmlen; ops.oobbuf = (uint8_t *)&oob_cleanmarker; ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; |
8593fbc68 [MTD] Rework the ... |
1109 |
ops.datbuf = NULL; |
8593fbc68 [MTD] Rework the ... |
1110 |
|
a2cc5ba07 mtd: introduce mt... |
1111 |
ret = mtd_write_oob(c->mtd, jeb->offset, &ops); |
a7a6ace14 [JFFS2] Use MTD_O... |
1112 |
if (ret || ops.oobretlen != ops.ooblen) { |
da320f055 jffs2: Convert pr... |
1113 1114 1115 |
pr_err("cannot write OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d ", jeb->offset, ops.ooblen, ops.oobretlen, ret); |
a7a6ace14 [JFFS2] Use MTD_O... |
1116 1117 |
if (!ret) ret = -EIO; |
1da177e4c Linux-2.6.12-rc2 |
1118 1119 |
return ret; } |
a7a6ace14 [JFFS2] Use MTD_O... |
1120 |
|
1da177e4c Linux-2.6.12-rc2 |
1121 1122 |
return 0; } |
182ec4eee [JFFS2] Clean up ... |
1123 |
/* |
1da177e4c Linux-2.6.12-rc2 |
1124 |
* On NAND we try to mark this block bad. If the block was erased more |
25985edce Fix common misspe... |
1125 |
* than MAX_ERASE_FAILURES we mark it finally bad. |
1da177e4c Linux-2.6.12-rc2 |
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 |
* Don't care about failures. This block remains on the erase-pending * or badblock list as long as nobody manipulates the flash with * a bootloader or something like that. */ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset) { int ret; /* if the count is < max, we try to write the counter to the 2nd page oob area */ if( ++jeb->bad_count < MAX_ERASE_FAILURES) return 0; |
5a528957e jffs2: Use pr_fmt... |
1138 1139 |
pr_warn("marking eraseblock at %08x as bad ", bad_offset); |
5942ddbc5 mtd: introduce mt... |
1140 |
ret = mtd_block_markbad(c->mtd, bad_offset); |
182ec4eee [JFFS2] Clean up ... |
1141 |
|
1da177e4c Linux-2.6.12-rc2 |
1142 |
if (ret) { |
9c261b33a jffs2: Convert mo... |
1143 1144 1145 |
jffs2_dbg(1, "%s(): Write failed for block at %08x: error %d ", __func__, jeb->offset, ret); |
1da177e4c Linux-2.6.12-rc2 |
1146 1147 1148 1149 |
return ret; } return 1; } |
8bdc81c50 jffs2: get rid of... |
1150 1151 1152 |
static struct jffs2_sb_info *work_to_sb(struct work_struct *work) { struct delayed_work *dwork; |
43584c1d4 jffs2: use to_del... |
1153 |
dwork = to_delayed_work(work); |
8bdc81c50 jffs2: get rid of... |
1154 1155 1156 1157 1158 1159 1160 |
return container_of(dwork, struct jffs2_sb_info, wbuf_dwork); } static void delayed_wbuf_sync(struct work_struct *work) { struct jffs2_sb_info *c = work_to_sb(work); struct super_block *sb = OFNI_BS_2SFFJ(c); |
bc98a42c1 VFS: Convert sb->... |
1161 |
if (!sb_rdonly(sb)) { |
8bdc81c50 jffs2: get rid of... |
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 |
jffs2_dbg(1, "%s() ", __func__); jffs2_flush_wbuf_gc(c, 0); } } void jffs2_dirty_trigger(struct jffs2_sb_info *c) { struct super_block *sb = OFNI_BS_2SFFJ(c); unsigned long delay; |
bc98a42c1 VFS: Convert sb->... |
1172 |
if (sb_rdonly(sb)) |
8bdc81c50 jffs2: get rid of... |
1173 |
return; |
99358a1ca [jffs2] kill wbuf... |
1174 1175 |
delay = msecs_to_jiffies(dirty_writeback_interval * 10); if (queue_delayed_work(system_long_wq, &c->wbuf_dwork, delay)) |
8bdc81c50 jffs2: get rid of... |
1176 1177 |
jffs2_dbg(1, "%s() ", __func__); |
8bdc81c50 jffs2: get rid of... |
1178 |
} |
a7a6ace14 [JFFS2] Use MTD_O... |
1179 |
int jffs2_nand_flash_setup(struct jffs2_sb_info *c) |
1da177e4c Linux-2.6.12-rc2 |
1180 |
{ |
1da177e4c Linux-2.6.12-rc2 |
1181 1182 |
if (!c->mtd->oobsize) return 0; |
182ec4eee [JFFS2] Clean up ... |
1183 |
|
1da177e4c Linux-2.6.12-rc2 |
1184 1185 |
/* Cleanmarker is out-of-band, so inline size zero */ c->cleanmarker_size = 0; |
f5b8aa78e mtd: kill the ecc... |
1186 |
if (c->mtd->oobavail == 0) { |
da320f055 jffs2: Convert pr... |
1187 1188 |
pr_err("inconsistent device description "); |
5bd34c091 [MTD] NAND Replac... |
1189 1190 |
return -EINVAL; } |
182ec4eee [JFFS2] Clean up ... |
1191 |
|
5a528957e jffs2: Use pr_fmt... |
1192 1193 |
jffs2_dbg(1, "using OOB on NAND "); |
5bd34c091 [MTD] NAND Replac... |
1194 |
|
f5b8aa78e mtd: kill the ecc... |
1195 |
c->oobavail = c->mtd->oobavail; |
1da177e4c Linux-2.6.12-rc2 |
1196 1197 1198 |
/* Initialise write buffer */ init_rwsem(&c->wbuf_sem); |
8bdc81c50 jffs2: get rid of... |
1199 |
INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); |
28318776a [MTD] Introduce w... |
1200 |
c->wbuf_pagesize = c->mtd->writesize; |
1da177e4c Linux-2.6.12-rc2 |
1201 |
c->wbuf_ofs = 0xFFFFFFFF; |
182ec4eee [JFFS2] Clean up ... |
1202 |
|
1da177e4c Linux-2.6.12-rc2 |
1203 1204 1205 |
c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); if (!c->wbuf) return -ENOMEM; |
6da2ec560 treewide: kmalloc... |
1206 |
c->oobbuf = kmalloc_array(NR_OOB_SCAN_PAGES, c->oobavail, GFP_KERNEL); |
a7a6ace14 [JFFS2] Use MTD_O... |
1207 |
if (!c->oobbuf) { |
1da177e4c Linux-2.6.12-rc2 |
1208 1209 1210 |
kfree(c->wbuf); return -ENOMEM; } |
a7a6ace14 [JFFS2] Use MTD_O... |
1211 |
|
a6bc432e2 [JFFS2] Add suppo... |
1212 1213 1214 1215 1216 1217 1218 1219 |
#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL); if (!c->wbuf_verify) { kfree(c->oobbuf); kfree(c->wbuf); return -ENOMEM; } #endif |
a7a6ace14 [JFFS2] Use MTD_O... |
1220 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1221 1222 1223 1224 |
} void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) { |
a6bc432e2 [JFFS2] Add suppo... |
1225 1226 1227 |
#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY kfree(c->wbuf_verify); #endif |
1da177e4c Linux-2.6.12-rc2 |
1228 |
kfree(c->wbuf); |
8593fbc68 [MTD] Rework the ... |
1229 |
kfree(c->oobbuf); |
1da177e4c Linux-2.6.12-rc2 |
1230 |
} |
8f15fd55f [JFFS2] Add suppo... |
1231 1232 |
int jffs2_dataflash_setup(struct jffs2_sb_info *c) { c->cleanmarker_size = 0; /* No cleanmarkers needed */ |
182ec4eee [JFFS2] Clean up ... |
1233 |
|
8f15fd55f [JFFS2] Add suppo... |
1234 1235 |
/* Initialize write buffer */ init_rwsem(&c->wbuf_sem); |
8bdc81c50 jffs2: get rid of... |
1236 |
INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); |
daba5cc4b [JFFS2] Fix dataf... |
1237 |
c->wbuf_pagesize = c->mtd->erasesize; |
182ec4eee [JFFS2] Clean up ... |
1238 |
|
daba5cc4b [JFFS2] Fix dataf... |
1239 1240 1241 1242 1243 1244 1245 1246 1247 |
/* Find a suitable c->sector_size * - Not too much sectors * - Sectors have to be at least 4 K + some bytes * - All known dataflashes have erase sizes of 528 or 1056 * - we take at least 8 eraseblocks and want to have at least 8K size * - The concatenation should be a power of 2 */ c->sector_size = 8 * c->mtd->erasesize; |
182ec4eee [JFFS2] Clean up ... |
1248 |
|
daba5cc4b [JFFS2] Fix dataf... |
1249 1250 1251 |
while (c->sector_size < 8192) { c->sector_size *= 2; } |
182ec4eee [JFFS2] Clean up ... |
1252 |
|
daba5cc4b [JFFS2] Fix dataf... |
1253 1254 |
/* It may be necessary to adjust the flash size */ c->flash_size = c->mtd->size; |
8f15fd55f [JFFS2] Add suppo... |
1255 |
|
daba5cc4b [JFFS2] Fix dataf... |
1256 1257 |
if ((c->flash_size % c->sector_size) != 0) { c->flash_size = (c->flash_size / c->sector_size) * c->sector_size; |
5a528957e jffs2: Use pr_fmt... |
1258 1259 |
pr_warn("flash size adjusted to %dKiB ", c->flash_size); |
eac44a5e0 fs/jffs2/wbuf.c: ... |
1260 |
} |
182ec4eee [JFFS2] Clean up ... |
1261 |
|
daba5cc4b [JFFS2] Fix dataf... |
1262 |
c->wbuf_ofs = 0xFFFFFFFF; |
8f15fd55f [JFFS2] Add suppo... |
1263 1264 1265 |
c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); if (!c->wbuf) return -ENOMEM; |
cca158417 [JFFS2] add write... |
1266 1267 1268 |
#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL); if (!c->wbuf_verify) { |
cca158417 [JFFS2] add write... |
1269 1270 1271 1272 |
kfree(c->wbuf); return -ENOMEM; } #endif |
5a528957e jffs2: Use pr_fmt... |
1273 1274 |
pr_info("write-buffering enabled buffer (%d) erasesize (%d) ", |
da320f055 jffs2: Convert pr... |
1275 |
c->wbuf_pagesize, c->sector_size); |
8f15fd55f [JFFS2] Add suppo... |
1276 1277 1278 1279 1280 |
return 0; } void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { |
cca158417 [JFFS2] add write... |
1281 1282 1283 |
#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY kfree(c->wbuf_verify); #endif |
8f15fd55f [JFFS2] Add suppo... |
1284 1285 |
kfree(c->wbuf); } |
8f15fd55f [JFFS2] Add suppo... |
1286 |
|
59da721a2 [JFFS2] Teach JFF... |
1287 |
int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) { |
c8b229de2 [MTD] Merge STMic... |
1288 1289 1290 |
/* Cleanmarker currently occupies whole programming regions, * either one or 2 for 8Byte STMicro flashes. */ c->cleanmarker_size = max(16u, c->mtd->writesize); |
59da721a2 [JFFS2] Teach JFF... |
1291 1292 1293 |
/* Initialize write buffer */ init_rwsem(&c->wbuf_sem); |
8bdc81c50 jffs2: get rid of... |
1294 |
INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); |
28318776a [MTD] Introduce w... |
1295 |
c->wbuf_pagesize = c->mtd->writesize; |
59da721a2 [JFFS2] Teach JFF... |
1296 1297 1298 1299 1300 |
c->wbuf_ofs = 0xFFFFFFFF; c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); if (!c->wbuf) return -ENOMEM; |
bc8cec0df JFFS2: add missin... |
1301 1302 1303 1304 1305 1306 1307 |
#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL); if (!c->wbuf_verify) { kfree(c->wbuf); return -ENOMEM; } #endif |
59da721a2 [JFFS2] Teach JFF... |
1308 1309 1310 1311 |
return 0; } void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c) { |
bc8cec0df JFFS2: add missin... |
1312 1313 1314 |
#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY kfree(c->wbuf_verify); #endif |
59da721a2 [JFFS2] Teach JFF... |
1315 1316 |
kfree(c->wbuf); } |
0029da3bf JFFS2: add UBI su... |
1317 1318 1319 1320 1321 1322 1323 1324 1325 |
int jffs2_ubivol_setup(struct jffs2_sb_info *c) { c->cleanmarker_size = 0; if (c->mtd->writesize == 1) /* We do not need write-buffer */ return 0; init_rwsem(&c->wbuf_sem); |
8bdc81c50 jffs2: get rid of... |
1326 |
INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); |
0029da3bf JFFS2: add UBI su... |
1327 1328 1329 1330 1331 1332 |
c->wbuf_pagesize = c->mtd->writesize; c->wbuf_ofs = 0xFFFFFFFF; c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); if (!c->wbuf) return -ENOMEM; |
5a528957e jffs2: Use pr_fmt... |
1333 1334 |
pr_info("write-buffering enabled buffer (%d) erasesize (%d) ", |
da320f055 jffs2: Convert pr... |
1335 |
c->wbuf_pagesize, c->sector_size); |
0029da3bf JFFS2: add UBI su... |
1336 1337 1338 1339 1340 1341 1342 |
return 0; } void jffs2_ubivol_cleanup(struct jffs2_sb_info *c) { kfree(c->wbuf); } |