162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright © 2001-2007 Red Hat, Inc. 562306a36Sopenharmony_ci * Copyright © 2004 Thomas Gleixner <tglx@linutronix.de> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Created by David Woodhouse <dwmw2@infradead.org> 862306a36Sopenharmony_ci * Modified debugged and enhanced by Thomas Gleixner <tglx@linutronix.de> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/mtd/mtd.h> 1962306a36Sopenharmony_ci#include <linux/crc32.h> 2062306a36Sopenharmony_ci#include <linux/mtd/rawnand.h> 2162306a36Sopenharmony_ci#include <linux/jiffies.h> 2262306a36Sopenharmony_ci#include <linux/sched.h> 2362306a36Sopenharmony_ci#include <linux/writeback.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "nodelist.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* For testing write failures */ 2862306a36Sopenharmony_ci#undef BREAKME 2962306a36Sopenharmony_ci#undef BREAKMEHEADER 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#ifdef BREAKME 3262306a36Sopenharmony_cistatic unsigned char *brokenbuf; 3362306a36Sopenharmony_ci#endif 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) ) 3662306a36Sopenharmony_ci#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) ) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* max. erase failures before we mark a block bad */ 3962306a36Sopenharmony_ci#define MAX_ERASE_FAILURES 2 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistruct jffs2_inodirty { 4262306a36Sopenharmony_ci uint32_t ino; 4362306a36Sopenharmony_ci struct jffs2_inodirty *next; 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic struct jffs2_inodirty inodirty_nomem; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic int jffs2_wbuf_pending_for_ino(struct jffs2_sb_info *c, uint32_t ino) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct jffs2_inodirty *this = c->wbuf_inodes; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci /* If a malloc failed, consider _everything_ dirty */ 5362306a36Sopenharmony_ci if (this == &inodirty_nomem) 5462306a36Sopenharmony_ci return 1; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* If ino == 0, _any_ non-GC writes mean 'yes' */ 5762306a36Sopenharmony_ci if (this && !ino) 5862306a36Sopenharmony_ci return 1; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci /* Look to see if the inode in question is pending in the wbuf */ 6162306a36Sopenharmony_ci while (this) { 6262306a36Sopenharmony_ci if (this->ino == ino) 6362306a36Sopenharmony_ci return 1; 6462306a36Sopenharmony_ci this = this->next; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci return 0; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic void jffs2_clear_wbuf_ino_list(struct jffs2_sb_info *c) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct jffs2_inodirty *this; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci this = c->wbuf_inodes; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (this != &inodirty_nomem) { 7662306a36Sopenharmony_ci while (this) { 7762306a36Sopenharmony_ci struct jffs2_inodirty *next = this->next; 7862306a36Sopenharmony_ci kfree(this); 7962306a36Sopenharmony_ci this = next; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci c->wbuf_inodes = NULL; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct jffs2_inodirty *new; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* Schedule delayed write-buffer write-out */ 9062306a36Sopenharmony_ci jffs2_dirty_trigger(c); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (jffs2_wbuf_pending_for_ino(c, ino)) 9362306a36Sopenharmony_ci return; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci new = kmalloc(sizeof(*new), GFP_KERNEL); 9662306a36Sopenharmony_ci if (!new) { 9762306a36Sopenharmony_ci jffs2_dbg(1, "No memory to allocate inodirty. Fallback to all considered dirty\n"); 9862306a36Sopenharmony_ci jffs2_clear_wbuf_ino_list(c); 9962306a36Sopenharmony_ci c->wbuf_inodes = &inodirty_nomem; 10062306a36Sopenharmony_ci return; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci new->ino = ino; 10362306a36Sopenharmony_ci new->next = c->wbuf_inodes; 10462306a36Sopenharmony_ci c->wbuf_inodes = new; 10562306a36Sopenharmony_ci return; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct list_head *this, *next; 11162306a36Sopenharmony_ci static int n; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (list_empty(&c->erasable_pending_wbuf_list)) 11462306a36Sopenharmony_ci return; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci list_for_each_safe(this, next, &c->erasable_pending_wbuf_list) { 11762306a36Sopenharmony_ci struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci jffs2_dbg(1, "Removing eraseblock at 0x%08x from erasable_pending_wbuf_list...\n", 12062306a36Sopenharmony_ci jeb->offset); 12162306a36Sopenharmony_ci list_del(this); 12262306a36Sopenharmony_ci if ((jiffies + (n++)) & 127) { 12362306a36Sopenharmony_ci /* Most of the time, we just erase it immediately. Otherwise we 12462306a36Sopenharmony_ci spend ages scanning it on mount, etc. */ 12562306a36Sopenharmony_ci jffs2_dbg(1, "...and adding to erase_pending_list\n"); 12662306a36Sopenharmony_ci list_add_tail(&jeb->list, &c->erase_pending_list); 12762306a36Sopenharmony_ci c->nr_erasing_blocks++; 12862306a36Sopenharmony_ci jffs2_garbage_collect_trigger(c); 12962306a36Sopenharmony_ci } else { 13062306a36Sopenharmony_ci /* Sometimes, however, we leave it elsewhere so it doesn't get 13162306a36Sopenharmony_ci immediately reused, and we spread the load a bit. */ 13262306a36Sopenharmony_ci jffs2_dbg(1, "...and adding to erasable_list\n"); 13362306a36Sopenharmony_ci list_add_tail(&jeb->list, &c->erasable_list); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci#define REFILE_NOTEMPTY 0 13962306a36Sopenharmony_ci#define REFILE_ANYWAY 1 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int allow_empty) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci jffs2_dbg(1, "About to refile bad block at %08x\n", jeb->offset); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* File the existing block on the bad_used_list.... */ 14662306a36Sopenharmony_ci if (c->nextblock == jeb) 14762306a36Sopenharmony_ci c->nextblock = NULL; 14862306a36Sopenharmony_ci else /* Not sure this should ever happen... need more coffee */ 14962306a36Sopenharmony_ci list_del(&jeb->list); 15062306a36Sopenharmony_ci if (jeb->first_node) { 15162306a36Sopenharmony_ci jffs2_dbg(1, "Refiling block at %08x to bad_used_list\n", 15262306a36Sopenharmony_ci jeb->offset); 15362306a36Sopenharmony_ci list_add(&jeb->list, &c->bad_used_list); 15462306a36Sopenharmony_ci } else { 15562306a36Sopenharmony_ci BUG_ON(allow_empty == REFILE_NOTEMPTY); 15662306a36Sopenharmony_ci /* It has to have had some nodes or we couldn't be here */ 15762306a36Sopenharmony_ci jffs2_dbg(1, "Refiling block at %08x to erase_pending_list\n", 15862306a36Sopenharmony_ci jeb->offset); 15962306a36Sopenharmony_ci list_add(&jeb->list, &c->erase_pending_list); 16062306a36Sopenharmony_ci c->nr_erasing_blocks++; 16162306a36Sopenharmony_ci jffs2_garbage_collect_trigger(c); 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (!jffs2_prealloc_raw_node_refs(c, jeb, 1)) { 16562306a36Sopenharmony_ci uint32_t oldfree = jeb->free_size; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci jffs2_link_node_ref(c, jeb, 16862306a36Sopenharmony_ci (jeb->offset+c->sector_size-oldfree) | REF_OBSOLETE, 16962306a36Sopenharmony_ci oldfree, NULL); 17062306a36Sopenharmony_ci /* convert to wasted */ 17162306a36Sopenharmony_ci c->wasted_size += oldfree; 17262306a36Sopenharmony_ci jeb->wasted_size += oldfree; 17362306a36Sopenharmony_ci c->dirty_size -= oldfree; 17462306a36Sopenharmony_ci jeb->dirty_size -= oldfree; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci jffs2_dbg_dump_block_lists_nolock(c); 17862306a36Sopenharmony_ci jffs2_dbg_acct_sanity_check_nolock(c,jeb); 17962306a36Sopenharmony_ci jffs2_dbg_acct_paranoia_check_nolock(c, jeb); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info *c, 18362306a36Sopenharmony_ci struct jffs2_inode_info *f, 18462306a36Sopenharmony_ci struct jffs2_raw_node_ref *raw, 18562306a36Sopenharmony_ci union jffs2_node_union *node) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct jffs2_node_frag *frag; 18862306a36Sopenharmony_ci struct jffs2_full_dirent *fd; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci dbg_noderef("incore_replace_raw: node at %p is {%04x,%04x}\n", 19162306a36Sopenharmony_ci node, je16_to_cpu(node->u.magic), je16_to_cpu(node->u.nodetype)); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci BUG_ON(je16_to_cpu(node->u.magic) != 0x1985 && 19462306a36Sopenharmony_ci je16_to_cpu(node->u.magic) != 0); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci switch (je16_to_cpu(node->u.nodetype)) { 19762306a36Sopenharmony_ci case JFFS2_NODETYPE_INODE: 19862306a36Sopenharmony_ci if (f->metadata && f->metadata->raw == raw) { 19962306a36Sopenharmony_ci dbg_noderef("Will replace ->raw in f->metadata at %p\n", f->metadata); 20062306a36Sopenharmony_ci return &f->metadata->raw; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci frag = jffs2_lookup_node_frag(&f->fragtree, je32_to_cpu(node->i.offset)); 20362306a36Sopenharmony_ci BUG_ON(!frag); 20462306a36Sopenharmony_ci /* Find a frag which refers to the full_dnode we want to modify */ 20562306a36Sopenharmony_ci while (!frag->node || frag->node->raw != raw) { 20662306a36Sopenharmony_ci frag = frag_next(frag); 20762306a36Sopenharmony_ci BUG_ON(!frag); 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci dbg_noderef("Will replace ->raw in full_dnode at %p\n", frag->node); 21062306a36Sopenharmony_ci return &frag->node->raw; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci case JFFS2_NODETYPE_DIRENT: 21362306a36Sopenharmony_ci for (fd = f->dents; fd; fd = fd->next) { 21462306a36Sopenharmony_ci if (fd->raw == raw) { 21562306a36Sopenharmony_ci dbg_noderef("Will replace ->raw in full_dirent at %p\n", fd); 21662306a36Sopenharmony_ci return &fd->raw; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci BUG(); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci default: 22262306a36Sopenharmony_ci dbg_noderef("Don't care about replacing raw for nodetype %x\n", 22362306a36Sopenharmony_ci je16_to_cpu(node->u.nodetype)); 22462306a36Sopenharmony_ci break; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci return NULL; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY 23062306a36Sopenharmony_cistatic int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf, 23162306a36Sopenharmony_ci uint32_t ofs) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci int ret; 23462306a36Sopenharmony_ci size_t retlen; 23562306a36Sopenharmony_ci char *eccstr; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci ret = mtd_read(c->mtd, ofs, c->wbuf_pagesize, &retlen, c->wbuf_verify); 23862306a36Sopenharmony_ci if (ret && ret != -EUCLEAN && ret != -EBADMSG) { 23962306a36Sopenharmony_ci pr_warn("%s(): Read back of page at %08x failed: %d\n", 24062306a36Sopenharmony_ci __func__, c->wbuf_ofs, ret); 24162306a36Sopenharmony_ci return ret; 24262306a36Sopenharmony_ci } else if (retlen != c->wbuf_pagesize) { 24362306a36Sopenharmony_ci pr_warn("%s(): Read back of page at %08x gave short read: %zd not %d\n", 24462306a36Sopenharmony_ci __func__, ofs, retlen, c->wbuf_pagesize); 24562306a36Sopenharmony_ci return -EIO; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci if (!memcmp(buf, c->wbuf_verify, c->wbuf_pagesize)) 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (ret == -EUCLEAN) 25162306a36Sopenharmony_ci eccstr = "corrected"; 25262306a36Sopenharmony_ci else if (ret == -EBADMSG) 25362306a36Sopenharmony_ci eccstr = "correction failed"; 25462306a36Sopenharmony_ci else 25562306a36Sopenharmony_ci eccstr = "OK or unused"; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci pr_warn("Write verify error (ECC %s) at %08x. Wrote:\n", 25862306a36Sopenharmony_ci eccstr, c->wbuf_ofs); 25962306a36Sopenharmony_ci print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, 26062306a36Sopenharmony_ci c->wbuf, c->wbuf_pagesize, 0); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci pr_warn("Read back:\n"); 26362306a36Sopenharmony_ci print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, 26462306a36Sopenharmony_ci c->wbuf_verify, c->wbuf_pagesize, 0); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci return -EIO; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci#else 26962306a36Sopenharmony_ci#define jffs2_verify_write(c,b,o) (0) 27062306a36Sopenharmony_ci#endif 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* Recover from failure to write wbuf. Recover the nodes up to the 27362306a36Sopenharmony_ci * wbuf, not the one which we were starting to try to write. */ 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic void jffs2_wbuf_recover(struct jffs2_sb_info *c) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct jffs2_eraseblock *jeb, *new_jeb; 27862306a36Sopenharmony_ci struct jffs2_raw_node_ref *raw, *next, *first_raw = NULL; 27962306a36Sopenharmony_ci size_t retlen; 28062306a36Sopenharmony_ci int ret; 28162306a36Sopenharmony_ci int nr_refile = 0; 28262306a36Sopenharmony_ci unsigned char *buf; 28362306a36Sopenharmony_ci uint32_t start, end, ofs, len; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 28862306a36Sopenharmony_ci if (c->wbuf_ofs % c->mtd->erasesize) 28962306a36Sopenharmony_ci jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); 29062306a36Sopenharmony_ci else 29162306a36Sopenharmony_ci jffs2_block_refile(c, jeb, REFILE_ANYWAY); 29262306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci BUG_ON(!ref_obsolete(jeb->last_node)); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* Find the first node to be recovered, by skipping over every 29762306a36Sopenharmony_ci node which ends before the wbuf starts, or which is obsolete. */ 29862306a36Sopenharmony_ci for (next = raw = jeb->first_node; next; raw = next) { 29962306a36Sopenharmony_ci next = ref_next(raw); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (ref_obsolete(raw) || 30262306a36Sopenharmony_ci (next && ref_offset(next) <= c->wbuf_ofs)) { 30362306a36Sopenharmony_ci dbg_noderef("Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n", 30462306a36Sopenharmony_ci ref_offset(raw), ref_flags(raw), 30562306a36Sopenharmony_ci (ref_offset(raw) + ref_totlen(c, jeb, raw)), 30662306a36Sopenharmony_ci c->wbuf_ofs); 30762306a36Sopenharmony_ci continue; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci dbg_noderef("First node to be recovered is at 0x%08x(%d)-0x%08x\n", 31062306a36Sopenharmony_ci ref_offset(raw), ref_flags(raw), 31162306a36Sopenharmony_ci (ref_offset(raw) + ref_totlen(c, jeb, raw))); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci first_raw = raw; 31462306a36Sopenharmony_ci break; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (!first_raw) { 31862306a36Sopenharmony_ci /* All nodes were obsolete. Nothing to recover. */ 31962306a36Sopenharmony_ci jffs2_dbg(1, "No non-obsolete nodes to be recovered. Just filing block bad\n"); 32062306a36Sopenharmony_ci c->wbuf_len = 0; 32162306a36Sopenharmony_ci return; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci start = ref_offset(first_raw); 32562306a36Sopenharmony_ci end = ref_offset(jeb->last_node); 32662306a36Sopenharmony_ci nr_refile = 1; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* Count the number of refs which need to be copied */ 32962306a36Sopenharmony_ci while ((raw = ref_next(raw)) != jeb->last_node) 33062306a36Sopenharmony_ci nr_refile++; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci dbg_noderef("wbuf recover %08x-%08x (%d bytes in %d nodes)\n", 33362306a36Sopenharmony_ci start, end, end - start, nr_refile); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci buf = NULL; 33662306a36Sopenharmony_ci if (start < c->wbuf_ofs) { 33762306a36Sopenharmony_ci /* First affected node was already partially written. 33862306a36Sopenharmony_ci * Attempt to reread the old data into our buffer. */ 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci buf = kmalloc(end - start, GFP_KERNEL); 34162306a36Sopenharmony_ci if (!buf) { 34262306a36Sopenharmony_ci pr_crit("Malloc failure in wbuf recovery. Data loss ensues.\n"); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci goto read_failed; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* Do the read... */ 34862306a36Sopenharmony_ci ret = mtd_read(c->mtd, start, c->wbuf_ofs - start, &retlen, 34962306a36Sopenharmony_ci buf); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* ECC recovered ? */ 35262306a36Sopenharmony_ci if ((ret == -EUCLEAN || ret == -EBADMSG) && 35362306a36Sopenharmony_ci (retlen == c->wbuf_ofs - start)) 35462306a36Sopenharmony_ci ret = 0; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (ret || retlen != c->wbuf_ofs - start) { 35762306a36Sopenharmony_ci pr_crit("Old data are already lost in wbuf recovery. Data loss ensues.\n"); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci kfree(buf); 36062306a36Sopenharmony_ci buf = NULL; 36162306a36Sopenharmony_ci read_failed: 36262306a36Sopenharmony_ci first_raw = ref_next(first_raw); 36362306a36Sopenharmony_ci nr_refile--; 36462306a36Sopenharmony_ci while (first_raw && ref_obsolete(first_raw)) { 36562306a36Sopenharmony_ci first_raw = ref_next(first_raw); 36662306a36Sopenharmony_ci nr_refile--; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* If this was the only node to be recovered, give up */ 37062306a36Sopenharmony_ci if (!first_raw) { 37162306a36Sopenharmony_ci c->wbuf_len = 0; 37262306a36Sopenharmony_ci return; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* It wasn't. Go on and try to recover nodes complete in the wbuf */ 37662306a36Sopenharmony_ci start = ref_offset(first_raw); 37762306a36Sopenharmony_ci dbg_noderef("wbuf now recover %08x-%08x (%d bytes in %d nodes)\n", 37862306a36Sopenharmony_ci start, end, end - start, nr_refile); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci } else { 38162306a36Sopenharmony_ci /* Read succeeded. Copy the remaining data from the wbuf */ 38262306a36Sopenharmony_ci memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs); 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci /* OK... we're to rewrite (end-start) bytes of data from first_raw onwards. 38662306a36Sopenharmony_ci Either 'buf' contains the data, or we find it in the wbuf */ 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* ... and get an allocation of space from a shiny new block instead */ 38962306a36Sopenharmony_ci ret = jffs2_reserve_space_gc(c, end-start, &len, JFFS2_SUMMARY_NOSUM_SIZE); 39062306a36Sopenharmony_ci if (ret) { 39162306a36Sopenharmony_ci pr_warn("Failed to allocate space for wbuf recovery. Data loss ensues.\n"); 39262306a36Sopenharmony_ci kfree(buf); 39362306a36Sopenharmony_ci return; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* The summary is not recovered, so it must be disabled for this erase block */ 39762306a36Sopenharmony_ci jffs2_sum_disable_collecting(c->summary); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, nr_refile); 40062306a36Sopenharmony_ci if (ret) { 40162306a36Sopenharmony_ci pr_warn("Failed to allocate node refs for wbuf recovery. Data loss ensues.\n"); 40262306a36Sopenharmony_ci kfree(buf); 40362306a36Sopenharmony_ci return; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci ofs = write_ofs(c); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (end-start >= c->wbuf_pagesize) { 40962306a36Sopenharmony_ci /* Need to do another write immediately, but it's possible 41062306a36Sopenharmony_ci that this is just because the wbuf itself is completely 41162306a36Sopenharmony_ci full, and there's nothing earlier read back from the 41262306a36Sopenharmony_ci flash. Hence 'buf' isn't necessarily what we're writing 41362306a36Sopenharmony_ci from. */ 41462306a36Sopenharmony_ci unsigned char *rewrite_buf = buf?:c->wbuf; 41562306a36Sopenharmony_ci uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci jffs2_dbg(1, "Write 0x%x bytes at 0x%08x in wbuf recover\n", 41862306a36Sopenharmony_ci towrite, ofs); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci#ifdef BREAKMEHEADER 42162306a36Sopenharmony_ci static int breakme; 42262306a36Sopenharmony_ci if (breakme++ == 20) { 42362306a36Sopenharmony_ci pr_notice("Faking write error at 0x%08x\n", ofs); 42462306a36Sopenharmony_ci breakme = 0; 42562306a36Sopenharmony_ci mtd_write(c->mtd, ofs, towrite, &retlen, brokenbuf); 42662306a36Sopenharmony_ci ret = -EIO; 42762306a36Sopenharmony_ci } else 42862306a36Sopenharmony_ci#endif 42962306a36Sopenharmony_ci ret = mtd_write(c->mtd, ofs, towrite, &retlen, 43062306a36Sopenharmony_ci rewrite_buf); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs)) { 43362306a36Sopenharmony_ci /* Argh. We tried. Really we did. */ 43462306a36Sopenharmony_ci pr_crit("Recovery of wbuf failed due to a second write error\n"); 43562306a36Sopenharmony_ci kfree(buf); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (retlen) 43862306a36Sopenharmony_ci jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, first_raw), NULL); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci return; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci pr_notice("Recovery of wbuf succeeded to %08x\n", ofs); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci c->wbuf_len = (end - start) - towrite; 44562306a36Sopenharmony_ci c->wbuf_ofs = ofs + towrite; 44662306a36Sopenharmony_ci memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len); 44762306a36Sopenharmony_ci /* Don't muck about with c->wbuf_inodes. False positives are harmless. */ 44862306a36Sopenharmony_ci } else { 44962306a36Sopenharmony_ci /* OK, now we're left with the dregs in whichever buffer we're using */ 45062306a36Sopenharmony_ci if (buf) { 45162306a36Sopenharmony_ci memcpy(c->wbuf, buf, end-start); 45262306a36Sopenharmony_ci } else { 45362306a36Sopenharmony_ci memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start); 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci c->wbuf_ofs = ofs; 45662306a36Sopenharmony_ci c->wbuf_len = end - start; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* Now sort out the jffs2_raw_node_refs, moving them from the old to the next block */ 46062306a36Sopenharmony_ci new_jeb = &c->blocks[ofs / c->sector_size]; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 46362306a36Sopenharmony_ci for (raw = first_raw; raw != jeb->last_node; raw = ref_next(raw)) { 46462306a36Sopenharmony_ci uint32_t rawlen = ref_totlen(c, jeb, raw); 46562306a36Sopenharmony_ci struct jffs2_inode_cache *ic; 46662306a36Sopenharmony_ci struct jffs2_raw_node_ref *new_ref; 46762306a36Sopenharmony_ci struct jffs2_raw_node_ref **adjust_ref = NULL; 46862306a36Sopenharmony_ci struct jffs2_inode_info *f = NULL; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci jffs2_dbg(1, "Refiling block of %08x at %08x(%d) to %08x\n", 47162306a36Sopenharmony_ci rawlen, ref_offset(raw), ref_flags(raw), ofs); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci ic = jffs2_raw_ref_to_ic(raw); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* Ick. This XATTR mess should be fixed shortly... */ 47662306a36Sopenharmony_ci if (ic && ic->class == RAWNODE_CLASS_XATTR_DATUM) { 47762306a36Sopenharmony_ci struct jffs2_xattr_datum *xd = (void *)ic; 47862306a36Sopenharmony_ci BUG_ON(xd->node != raw); 47962306a36Sopenharmony_ci adjust_ref = &xd->node; 48062306a36Sopenharmony_ci raw->next_in_ino = NULL; 48162306a36Sopenharmony_ci ic = NULL; 48262306a36Sopenharmony_ci } else if (ic && ic->class == RAWNODE_CLASS_XATTR_REF) { 48362306a36Sopenharmony_ci struct jffs2_xattr_datum *xr = (void *)ic; 48462306a36Sopenharmony_ci BUG_ON(xr->node != raw); 48562306a36Sopenharmony_ci adjust_ref = &xr->node; 48662306a36Sopenharmony_ci raw->next_in_ino = NULL; 48762306a36Sopenharmony_ci ic = NULL; 48862306a36Sopenharmony_ci } else if (ic && ic->class == RAWNODE_CLASS_INODE_CACHE) { 48962306a36Sopenharmony_ci struct jffs2_raw_node_ref **p = &ic->nodes; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* Remove the old node from the per-inode list */ 49262306a36Sopenharmony_ci while (*p && *p != (void *)ic) { 49362306a36Sopenharmony_ci if (*p == raw) { 49462306a36Sopenharmony_ci (*p) = (raw->next_in_ino); 49562306a36Sopenharmony_ci raw->next_in_ino = NULL; 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci p = &((*p)->next_in_ino); 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (ic->state == INO_STATE_PRESENT && !ref_obsolete(raw)) { 50262306a36Sopenharmony_ci /* If it's an in-core inode, then we have to adjust any 50362306a36Sopenharmony_ci full_dirent or full_dnode structure to point to the 50462306a36Sopenharmony_ci new version instead of the old */ 50562306a36Sopenharmony_ci f = jffs2_gc_fetch_inode(c, ic->ino, !ic->pino_nlink); 50662306a36Sopenharmony_ci if (IS_ERR(f)) { 50762306a36Sopenharmony_ci /* Should never happen; it _must_ be present */ 50862306a36Sopenharmony_ci JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n", 50962306a36Sopenharmony_ci ic->ino, PTR_ERR(f)); 51062306a36Sopenharmony_ci BUG(); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci /* We don't lock f->sem. There's a number of ways we could 51362306a36Sopenharmony_ci end up in here with it already being locked, and nobody's 51462306a36Sopenharmony_ci going to modify it on us anyway because we hold the 51562306a36Sopenharmony_ci alloc_sem. We're only changing one ->raw pointer too, 51662306a36Sopenharmony_ci which we can get away with without upsetting readers. */ 51762306a36Sopenharmony_ci adjust_ref = jffs2_incore_replace_raw(c, f, raw, 51862306a36Sopenharmony_ci (void *)(buf?:c->wbuf) + (ref_offset(raw) - start)); 51962306a36Sopenharmony_ci } else if (unlikely(ic->state != INO_STATE_PRESENT && 52062306a36Sopenharmony_ci ic->state != INO_STATE_CHECKEDABSENT && 52162306a36Sopenharmony_ci ic->state != INO_STATE_GC)) { 52262306a36Sopenharmony_ci JFFS2_ERROR("Inode #%u is in strange state %d!\n", ic->ino, ic->state); 52362306a36Sopenharmony_ci BUG(); 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci new_ref = jffs2_link_node_ref(c, new_jeb, ofs | ref_flags(raw), rawlen, ic); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (adjust_ref) { 53062306a36Sopenharmony_ci BUG_ON(*adjust_ref != raw); 53162306a36Sopenharmony_ci *adjust_ref = new_ref; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci if (f) 53462306a36Sopenharmony_ci jffs2_gc_release_inode(c, f); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (!ref_obsolete(raw)) { 53762306a36Sopenharmony_ci jeb->dirty_size += rawlen; 53862306a36Sopenharmony_ci jeb->used_size -= rawlen; 53962306a36Sopenharmony_ci c->dirty_size += rawlen; 54062306a36Sopenharmony_ci c->used_size -= rawlen; 54162306a36Sopenharmony_ci raw->flash_offset = ref_offset(raw) | REF_OBSOLETE; 54262306a36Sopenharmony_ci BUG_ON(raw->next_in_ino); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci ofs += rawlen; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci kfree(buf); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci /* Fix up the original jeb now it's on the bad_list */ 55062306a36Sopenharmony_ci if (first_raw == jeb->first_node) { 55162306a36Sopenharmony_ci jffs2_dbg(1, "Failing block at %08x is now empty. Moving to erase_pending_list\n", 55262306a36Sopenharmony_ci jeb->offset); 55362306a36Sopenharmony_ci list_move(&jeb->list, &c->erase_pending_list); 55462306a36Sopenharmony_ci c->nr_erasing_blocks++; 55562306a36Sopenharmony_ci jffs2_garbage_collect_trigger(c); 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci jffs2_dbg_acct_sanity_check_nolock(c, jeb); 55962306a36Sopenharmony_ci jffs2_dbg_acct_paranoia_check_nolock(c, jeb); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci jffs2_dbg_acct_sanity_check_nolock(c, new_jeb); 56262306a36Sopenharmony_ci jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci jffs2_dbg(1, "wbuf recovery completed OK. wbuf_ofs 0x%08x, len 0x%x\n", 56762306a36Sopenharmony_ci c->wbuf_ofs, c->wbuf_len); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci/* Meaning of pad argument: 57262306a36Sopenharmony_ci 0: Do not pad. Probably pointless - we only ever use this when we can't pad anyway. 57362306a36Sopenharmony_ci 1: Pad, do not adjust nextblock free_size 57462306a36Sopenharmony_ci 2: Pad, adjust nextblock free_size 57562306a36Sopenharmony_ci*/ 57662306a36Sopenharmony_ci#define NOPAD 0 57762306a36Sopenharmony_ci#define PAD_NOACCOUNT 1 57862306a36Sopenharmony_ci#define PAD_ACCOUNTING 2 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci struct jffs2_eraseblock *wbuf_jeb; 58362306a36Sopenharmony_ci int ret; 58462306a36Sopenharmony_ci size_t retlen; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /* Nothing to do if not write-buffering the flash. In particular, we shouldn't 58762306a36Sopenharmony_ci del_timer() the timer we never initialised. */ 58862306a36Sopenharmony_ci if (!jffs2_is_writebuffered(c)) 58962306a36Sopenharmony_ci return 0; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (!mutex_is_locked(&c->alloc_sem)) { 59262306a36Sopenharmony_ci pr_crit("jffs2_flush_wbuf() called with alloc_sem not locked!\n"); 59362306a36Sopenharmony_ci BUG(); 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (!c->wbuf_len) /* already checked c->wbuf above */ 59762306a36Sopenharmony_ci return 0; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci wbuf_jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; 60062306a36Sopenharmony_ci if (jffs2_prealloc_raw_node_refs(c, wbuf_jeb, c->nextblock->allocated_refs + 1)) 60162306a36Sopenharmony_ci return -ENOMEM; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* claim remaining space on the page 60462306a36Sopenharmony_ci this happens, if we have a change to a new block, 60562306a36Sopenharmony_ci or if fsync forces us to flush the writebuffer. 60662306a36Sopenharmony_ci if we have a switch to next page, we will not have 60762306a36Sopenharmony_ci enough remaining space for this. 60862306a36Sopenharmony_ci */ 60962306a36Sopenharmony_ci if (pad ) { 61062306a36Sopenharmony_ci c->wbuf_len = PAD(c->wbuf_len); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR 61362306a36Sopenharmony_ci with 8 byte page size */ 61462306a36Sopenharmony_ci memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) { 61762306a36Sopenharmony_ci struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len); 61862306a36Sopenharmony_ci padnode->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 61962306a36Sopenharmony_ci padnode->nodetype = cpu_to_je16(JFFS2_NODETYPE_PADDING); 62062306a36Sopenharmony_ci padnode->totlen = cpu_to_je32(c->wbuf_pagesize - c->wbuf_len); 62162306a36Sopenharmony_ci padnode->hdr_crc = cpu_to_je32(crc32(0, padnode, sizeof(*padnode)-4)); 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci /* else jffs2_flash_writev has actually filled in the rest of the 62562306a36Sopenharmony_ci buffer for us, and will deal with the node refs etc. later. */ 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci#ifdef BREAKME 62862306a36Sopenharmony_ci static int breakme; 62962306a36Sopenharmony_ci if (breakme++ == 20) { 63062306a36Sopenharmony_ci pr_notice("Faking write error at 0x%08x\n", c->wbuf_ofs); 63162306a36Sopenharmony_ci breakme = 0; 63262306a36Sopenharmony_ci mtd_write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, 63362306a36Sopenharmony_ci brokenbuf); 63462306a36Sopenharmony_ci ret = -EIO; 63562306a36Sopenharmony_ci } else 63662306a36Sopenharmony_ci#endif 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci ret = mtd_write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, 63962306a36Sopenharmony_ci &retlen, c->wbuf); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (ret) { 64262306a36Sopenharmony_ci pr_warn("jffs2_flush_wbuf(): Write failed with %d\n", ret); 64362306a36Sopenharmony_ci goto wfail; 64462306a36Sopenharmony_ci } else if (retlen != c->wbuf_pagesize) { 64562306a36Sopenharmony_ci pr_warn("jffs2_flush_wbuf(): Write was short: %zd instead of %d\n", 64662306a36Sopenharmony_ci retlen, c->wbuf_pagesize); 64762306a36Sopenharmony_ci ret = -EIO; 64862306a36Sopenharmony_ci goto wfail; 64962306a36Sopenharmony_ci } else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) { 65062306a36Sopenharmony_ci wfail: 65162306a36Sopenharmony_ci jffs2_wbuf_recover(c); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci return ret; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci /* Adjust free size of the block if we padded. */ 65762306a36Sopenharmony_ci if (pad) { 65862306a36Sopenharmony_ci uint32_t waste = c->wbuf_pagesize - c->wbuf_len; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci jffs2_dbg(1, "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n", 66162306a36Sopenharmony_ci (wbuf_jeb == c->nextblock) ? "next" : "", 66262306a36Sopenharmony_ci wbuf_jeb->offset); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* wbuf_pagesize - wbuf_len is the amount of space that's to be 66562306a36Sopenharmony_ci padded. If there is less free space in the block than that, 66662306a36Sopenharmony_ci something screwed up */ 66762306a36Sopenharmony_ci if (wbuf_jeb->free_size < waste) { 66862306a36Sopenharmony_ci pr_crit("jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n", 66962306a36Sopenharmony_ci c->wbuf_ofs, c->wbuf_len, waste); 67062306a36Sopenharmony_ci pr_crit("jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n", 67162306a36Sopenharmony_ci wbuf_jeb->offset, wbuf_jeb->free_size); 67262306a36Sopenharmony_ci BUG(); 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci jffs2_link_node_ref(c, wbuf_jeb, (c->wbuf_ofs + c->wbuf_len) | REF_OBSOLETE, waste, NULL); 67862306a36Sopenharmony_ci /* FIXME: that made it count as dirty. Convert to wasted */ 67962306a36Sopenharmony_ci wbuf_jeb->dirty_size -= waste; 68062306a36Sopenharmony_ci c->dirty_size -= waste; 68162306a36Sopenharmony_ci wbuf_jeb->wasted_size += waste; 68262306a36Sopenharmony_ci c->wasted_size += waste; 68362306a36Sopenharmony_ci } else 68462306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* Stick any now-obsoleted blocks on the erase_pending_list */ 68762306a36Sopenharmony_ci jffs2_refile_wbuf_blocks(c); 68862306a36Sopenharmony_ci jffs2_clear_wbuf_ino_list(c); 68962306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci memset(c->wbuf,0xff,c->wbuf_pagesize); 69262306a36Sopenharmony_ci /* adjust write buffer offset, else we get a non contiguous write bug */ 69362306a36Sopenharmony_ci c->wbuf_ofs += c->wbuf_pagesize; 69462306a36Sopenharmony_ci c->wbuf_len = 0; 69562306a36Sopenharmony_ci return 0; 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci/* Trigger garbage collection to flush the write-buffer. 69962306a36Sopenharmony_ci If ino arg is zero, do it if _any_ real (i.e. not GC) writes are 70062306a36Sopenharmony_ci outstanding. If ino arg non-zero, do it only if a write for the 70162306a36Sopenharmony_ci given inode is outstanding. */ 70262306a36Sopenharmony_ciint jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci uint32_t old_wbuf_ofs; 70562306a36Sopenharmony_ci uint32_t old_wbuf_len; 70662306a36Sopenharmony_ci int ret = 0; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci jffs2_dbg(1, "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (!c->wbuf) 71162306a36Sopenharmony_ci return 0; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci mutex_lock(&c->alloc_sem); 71462306a36Sopenharmony_ci if (!jffs2_wbuf_pending_for_ino(c, ino)) { 71562306a36Sopenharmony_ci jffs2_dbg(1, "Ino #%d not pending in wbuf. Returning\n", ino); 71662306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 71762306a36Sopenharmony_ci return 0; 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci old_wbuf_ofs = c->wbuf_ofs; 72162306a36Sopenharmony_ci old_wbuf_len = c->wbuf_len; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci if (c->unchecked_size) { 72462306a36Sopenharmony_ci /* GC won't make any progress for a while */ 72562306a36Sopenharmony_ci jffs2_dbg(1, "%s(): padding. Not finished checking\n", 72662306a36Sopenharmony_ci __func__); 72762306a36Sopenharmony_ci down_write(&c->wbuf_sem); 72862306a36Sopenharmony_ci ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); 72962306a36Sopenharmony_ci /* retry flushing wbuf in case jffs2_wbuf_recover 73062306a36Sopenharmony_ci left some data in the wbuf */ 73162306a36Sopenharmony_ci if (ret) 73262306a36Sopenharmony_ci ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); 73362306a36Sopenharmony_ci up_write(&c->wbuf_sem); 73462306a36Sopenharmony_ci } else while (old_wbuf_len && 73562306a36Sopenharmony_ci old_wbuf_ofs == c->wbuf_ofs) { 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci jffs2_dbg(1, "%s(): calls gc pass\n", __func__); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci ret = jffs2_garbage_collect_pass(c); 74262306a36Sopenharmony_ci if (ret) { 74362306a36Sopenharmony_ci /* GC failed. Flush it with padding instead */ 74462306a36Sopenharmony_ci mutex_lock(&c->alloc_sem); 74562306a36Sopenharmony_ci down_write(&c->wbuf_sem); 74662306a36Sopenharmony_ci ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); 74762306a36Sopenharmony_ci /* retry flushing wbuf in case jffs2_wbuf_recover 74862306a36Sopenharmony_ci left some data in the wbuf */ 74962306a36Sopenharmony_ci if (ret) 75062306a36Sopenharmony_ci ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); 75162306a36Sopenharmony_ci up_write(&c->wbuf_sem); 75262306a36Sopenharmony_ci break; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci mutex_lock(&c->alloc_sem); 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci jffs2_dbg(1, "%s(): ends...\n", __func__); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 76062306a36Sopenharmony_ci return ret; 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci/* Pad write-buffer to end and write it, wasting space. */ 76462306a36Sopenharmony_ciint jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci int ret; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (!c->wbuf) 76962306a36Sopenharmony_ci return 0; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci down_write(&c->wbuf_sem); 77262306a36Sopenharmony_ci ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); 77362306a36Sopenharmony_ci /* retry - maybe wbuf recover left some data in wbuf. */ 77462306a36Sopenharmony_ci if (ret) 77562306a36Sopenharmony_ci ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); 77662306a36Sopenharmony_ci up_write(&c->wbuf_sem); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci return ret; 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cistatic size_t jffs2_fill_wbuf(struct jffs2_sb_info *c, const uint8_t *buf, 78262306a36Sopenharmony_ci size_t len) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci if (len && !c->wbuf_len && (len >= c->wbuf_pagesize)) 78562306a36Sopenharmony_ci return 0; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (len > (c->wbuf_pagesize - c->wbuf_len)) 78862306a36Sopenharmony_ci len = c->wbuf_pagesize - c->wbuf_len; 78962306a36Sopenharmony_ci memcpy(c->wbuf + c->wbuf_len, buf, len); 79062306a36Sopenharmony_ci c->wbuf_len += (uint32_t) len; 79162306a36Sopenharmony_ci return len; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ciint jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, 79562306a36Sopenharmony_ci unsigned long count, loff_t to, size_t *retlen, 79662306a36Sopenharmony_ci uint32_t ino) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci struct jffs2_eraseblock *jeb; 79962306a36Sopenharmony_ci size_t wbuf_retlen, donelen = 0; 80062306a36Sopenharmony_ci uint32_t outvec_to = to; 80162306a36Sopenharmony_ci int ret, invec; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci /* If not writebuffered flash, don't bother */ 80462306a36Sopenharmony_ci if (!jffs2_is_writebuffered(c)) 80562306a36Sopenharmony_ci return jffs2_flash_direct_writev(c, invecs, count, to, retlen); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci down_write(&c->wbuf_sem); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci /* If wbuf_ofs is not initialized, set it to target address */ 81062306a36Sopenharmony_ci if (c->wbuf_ofs == 0xFFFFFFFF) { 81162306a36Sopenharmony_ci c->wbuf_ofs = PAGE_DIV(to); 81262306a36Sopenharmony_ci c->wbuf_len = PAGE_MOD(to); 81362306a36Sopenharmony_ci memset(c->wbuf,0xff,c->wbuf_pagesize); 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci /* 81762306a36Sopenharmony_ci * Sanity checks on target address. It's permitted to write 81862306a36Sopenharmony_ci * at PAD(c->wbuf_len+c->wbuf_ofs), and it's permitted to 81962306a36Sopenharmony_ci * write at the beginning of a new erase block. Anything else, 82062306a36Sopenharmony_ci * and you die. New block starts at xxx000c (0-b = block 82162306a36Sopenharmony_ci * header) 82262306a36Sopenharmony_ci */ 82362306a36Sopenharmony_ci if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) { 82462306a36Sopenharmony_ci /* It's a write to a new block */ 82562306a36Sopenharmony_ci if (c->wbuf_len) { 82662306a36Sopenharmony_ci jffs2_dbg(1, "%s(): to 0x%lx causes flush of wbuf at 0x%08x\n", 82762306a36Sopenharmony_ci __func__, (unsigned long)to, c->wbuf_ofs); 82862306a36Sopenharmony_ci ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); 82962306a36Sopenharmony_ci if (ret) 83062306a36Sopenharmony_ci goto outerr; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci /* set pointer to new block */ 83362306a36Sopenharmony_ci c->wbuf_ofs = PAGE_DIV(to); 83462306a36Sopenharmony_ci c->wbuf_len = PAGE_MOD(to); 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (to != PAD(c->wbuf_ofs + c->wbuf_len)) { 83862306a36Sopenharmony_ci /* We're not writing immediately after the writebuffer. Bad. */ 83962306a36Sopenharmony_ci pr_crit("%s(): Non-contiguous write to %08lx\n", 84062306a36Sopenharmony_ci __func__, (unsigned long)to); 84162306a36Sopenharmony_ci if (c->wbuf_len) 84262306a36Sopenharmony_ci pr_crit("wbuf was previously %08x-%08x\n", 84362306a36Sopenharmony_ci c->wbuf_ofs, c->wbuf_ofs + c->wbuf_len); 84462306a36Sopenharmony_ci BUG(); 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci /* adjust alignment offset */ 84862306a36Sopenharmony_ci if (c->wbuf_len != PAGE_MOD(to)) { 84962306a36Sopenharmony_ci c->wbuf_len = PAGE_MOD(to); 85062306a36Sopenharmony_ci /* take care of alignment to next page */ 85162306a36Sopenharmony_ci if (!c->wbuf_len) { 85262306a36Sopenharmony_ci c->wbuf_len = c->wbuf_pagesize; 85362306a36Sopenharmony_ci ret = __jffs2_flush_wbuf(c, NOPAD); 85462306a36Sopenharmony_ci if (ret) 85562306a36Sopenharmony_ci goto outerr; 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci for (invec = 0; invec < count; invec++) { 86062306a36Sopenharmony_ci int vlen = invecs[invec].iov_len; 86162306a36Sopenharmony_ci uint8_t *v = invecs[invec].iov_base; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci wbuf_retlen = jffs2_fill_wbuf(c, v, vlen); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (c->wbuf_len == c->wbuf_pagesize) { 86662306a36Sopenharmony_ci ret = __jffs2_flush_wbuf(c, NOPAD); 86762306a36Sopenharmony_ci if (ret) 86862306a36Sopenharmony_ci goto outerr; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci vlen -= wbuf_retlen; 87162306a36Sopenharmony_ci outvec_to += wbuf_retlen; 87262306a36Sopenharmony_ci donelen += wbuf_retlen; 87362306a36Sopenharmony_ci v += wbuf_retlen; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci if (vlen >= c->wbuf_pagesize) { 87662306a36Sopenharmony_ci ret = mtd_write(c->mtd, outvec_to, PAGE_DIV(vlen), 87762306a36Sopenharmony_ci &wbuf_retlen, v); 87862306a36Sopenharmony_ci if (ret < 0 || wbuf_retlen != PAGE_DIV(vlen)) 87962306a36Sopenharmony_ci goto outfile; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci vlen -= wbuf_retlen; 88262306a36Sopenharmony_ci outvec_to += wbuf_retlen; 88362306a36Sopenharmony_ci c->wbuf_ofs = outvec_to; 88462306a36Sopenharmony_ci donelen += wbuf_retlen; 88562306a36Sopenharmony_ci v += wbuf_retlen; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci wbuf_retlen = jffs2_fill_wbuf(c, v, vlen); 88962306a36Sopenharmony_ci if (c->wbuf_len == c->wbuf_pagesize) { 89062306a36Sopenharmony_ci ret = __jffs2_flush_wbuf(c, NOPAD); 89162306a36Sopenharmony_ci if (ret) 89262306a36Sopenharmony_ci goto outerr; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci outvec_to += wbuf_retlen; 89662306a36Sopenharmony_ci donelen += wbuf_retlen; 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci /* 90062306a36Sopenharmony_ci * If there's a remainder in the wbuf and it's a non-GC write, 90162306a36Sopenharmony_ci * remember that the wbuf affects this ino 90262306a36Sopenharmony_ci */ 90362306a36Sopenharmony_ci *retlen = donelen; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci if (jffs2_sum_active()) { 90662306a36Sopenharmony_ci int res = jffs2_sum_add_kvec(c, invecs, count, (uint32_t) to); 90762306a36Sopenharmony_ci if (res) 90862306a36Sopenharmony_ci return res; 90962306a36Sopenharmony_ci } 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci if (c->wbuf_len && ino) 91262306a36Sopenharmony_ci jffs2_wbuf_dirties_inode(c, ino); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci ret = 0; 91562306a36Sopenharmony_ci up_write(&c->wbuf_sem); 91662306a36Sopenharmony_ci return ret; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_cioutfile: 91962306a36Sopenharmony_ci /* 92062306a36Sopenharmony_ci * At this point we have no problem, c->wbuf is empty. However 92162306a36Sopenharmony_ci * refile nextblock to avoid writing again to same address. 92262306a36Sopenharmony_ci */ 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci jeb = &c->blocks[outvec_to / c->sector_size]; 92762306a36Sopenharmony_ci jffs2_block_refile(c, jeb, REFILE_ANYWAY); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ciouterr: 93262306a36Sopenharmony_ci *retlen = 0; 93362306a36Sopenharmony_ci up_write(&c->wbuf_sem); 93462306a36Sopenharmony_ci return ret; 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci/* 93862306a36Sopenharmony_ci * This is the entry for flash write. 93962306a36Sopenharmony_ci * Check, if we work on NAND FLASH, if so build an kvec and write it via vritev 94062306a36Sopenharmony_ci*/ 94162306a36Sopenharmony_ciint jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, 94262306a36Sopenharmony_ci size_t *retlen, const u_char *buf) 94362306a36Sopenharmony_ci{ 94462306a36Sopenharmony_ci struct kvec vecs[1]; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (!jffs2_is_writebuffered(c)) 94762306a36Sopenharmony_ci return jffs2_flash_direct_write(c, ofs, len, retlen, buf); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci vecs[0].iov_base = (unsigned char *) buf; 95062306a36Sopenharmony_ci vecs[0].iov_len = len; 95162306a36Sopenharmony_ci return jffs2_flash_writev(c, vecs, 1, ofs, retlen, 0); 95262306a36Sopenharmony_ci} 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci/* 95562306a36Sopenharmony_ci Handle readback from writebuffer and ECC failure return 95662306a36Sopenharmony_ci*/ 95762306a36Sopenharmony_ciint jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci loff_t orbf = 0, owbf = 0, lwbf = 0; 96062306a36Sopenharmony_ci int ret; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if (!jffs2_is_writebuffered(c)) 96362306a36Sopenharmony_ci return mtd_read(c->mtd, ofs, len, retlen, buf); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci /* Read flash */ 96662306a36Sopenharmony_ci down_read(&c->wbuf_sem); 96762306a36Sopenharmony_ci ret = mtd_read(c->mtd, ofs, len, retlen, buf); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if ( (ret == -EBADMSG || ret == -EUCLEAN) && (*retlen == len) ) { 97062306a36Sopenharmony_ci if (ret == -EBADMSG) 97162306a36Sopenharmony_ci pr_warn("mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", 97262306a36Sopenharmony_ci len, ofs); 97362306a36Sopenharmony_ci /* 97462306a36Sopenharmony_ci * We have the raw data without ECC correction in the buffer, 97562306a36Sopenharmony_ci * maybe we are lucky and all data or parts are correct. We 97662306a36Sopenharmony_ci * check the node. If data are corrupted node check will sort 97762306a36Sopenharmony_ci * it out. We keep this block, it will fail on write or erase 97862306a36Sopenharmony_ci * and the we mark it bad. Or should we do that now? But we 97962306a36Sopenharmony_ci * should give him a chance. Maybe we had a system crash or 98062306a36Sopenharmony_ci * power loss before the ecc write or a erase was completed. 98162306a36Sopenharmony_ci * So we return success. :) 98262306a36Sopenharmony_ci */ 98362306a36Sopenharmony_ci ret = 0; 98462306a36Sopenharmony_ci } 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci /* if no writebuffer available or write buffer empty, return */ 98762306a36Sopenharmony_ci if (!c->wbuf_pagesize || !c->wbuf_len) 98862306a36Sopenharmony_ci goto exit; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci /* if we read in a different block, return */ 99162306a36Sopenharmony_ci if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs)) 99262306a36Sopenharmony_ci goto exit; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci if (ofs >= c->wbuf_ofs) { 99562306a36Sopenharmony_ci owbf = (ofs - c->wbuf_ofs); /* offset in write buffer */ 99662306a36Sopenharmony_ci if (owbf > c->wbuf_len) /* is read beyond write buffer ? */ 99762306a36Sopenharmony_ci goto exit; 99862306a36Sopenharmony_ci lwbf = c->wbuf_len - owbf; /* number of bytes to copy */ 99962306a36Sopenharmony_ci if (lwbf > len) 100062306a36Sopenharmony_ci lwbf = len; 100162306a36Sopenharmony_ci } else { 100262306a36Sopenharmony_ci orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */ 100362306a36Sopenharmony_ci if (orbf > len) /* is write beyond write buffer ? */ 100462306a36Sopenharmony_ci goto exit; 100562306a36Sopenharmony_ci lwbf = len - orbf; /* number of bytes to copy */ 100662306a36Sopenharmony_ci if (lwbf > c->wbuf_len) 100762306a36Sopenharmony_ci lwbf = c->wbuf_len; 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci if (lwbf > 0) 101062306a36Sopenharmony_ci memcpy(buf+orbf,c->wbuf+owbf,lwbf); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ciexit: 101362306a36Sopenharmony_ci up_read(&c->wbuf_sem); 101462306a36Sopenharmony_ci return ret; 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci#define NR_OOB_SCAN_PAGES 4 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci/* For historical reasons we use only 8 bytes for OOB clean marker */ 102062306a36Sopenharmony_ci#define OOB_CM_SIZE 8 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_cistatic const struct jffs2_unknown_node oob_cleanmarker = 102362306a36Sopenharmony_ci{ 102462306a36Sopenharmony_ci .magic = constant_cpu_to_je16(JFFS2_MAGIC_BITMASK), 102562306a36Sopenharmony_ci .nodetype = constant_cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER), 102662306a36Sopenharmony_ci .totlen = constant_cpu_to_je32(8) 102762306a36Sopenharmony_ci}; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci/* 103062306a36Sopenharmony_ci * Check, if the out of band area is empty. This function knows about the clean 103162306a36Sopenharmony_ci * marker and if it is present in OOB, treats the OOB as empty anyway. 103262306a36Sopenharmony_ci */ 103362306a36Sopenharmony_ciint jffs2_check_oob_empty(struct jffs2_sb_info *c, 103462306a36Sopenharmony_ci struct jffs2_eraseblock *jeb, int mode) 103562306a36Sopenharmony_ci{ 103662306a36Sopenharmony_ci int i, ret; 103762306a36Sopenharmony_ci int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); 103862306a36Sopenharmony_ci struct mtd_oob_ops ops = { }; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci ops.mode = MTD_OPS_AUTO_OOB; 104162306a36Sopenharmony_ci ops.ooblen = NR_OOB_SCAN_PAGES * c->oobavail; 104262306a36Sopenharmony_ci ops.oobbuf = c->oobbuf; 104362306a36Sopenharmony_ci ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; 104462306a36Sopenharmony_ci ops.datbuf = NULL; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci ret = mtd_read_oob(c->mtd, jeb->offset, &ops); 104762306a36Sopenharmony_ci if ((ret && !mtd_is_bitflip(ret)) || ops.oobretlen != ops.ooblen) { 104862306a36Sopenharmony_ci pr_err("cannot read OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n", 104962306a36Sopenharmony_ci jeb->offset, ops.ooblen, ops.oobretlen, ret); 105062306a36Sopenharmony_ci if (!ret || mtd_is_bitflip(ret)) 105162306a36Sopenharmony_ci ret = -EIO; 105262306a36Sopenharmony_ci return ret; 105362306a36Sopenharmony_ci } 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci for(i = 0; i < ops.ooblen; i++) { 105662306a36Sopenharmony_ci if (mode && i < cmlen) 105762306a36Sopenharmony_ci /* Yeah, we know about the cleanmarker */ 105862306a36Sopenharmony_ci continue; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if (ops.oobbuf[i] != 0xFF) { 106162306a36Sopenharmony_ci jffs2_dbg(2, "Found %02x at %x in OOB for " 106262306a36Sopenharmony_ci "%08x\n", ops.oobbuf[i], i, jeb->offset); 106362306a36Sopenharmony_ci return 1; 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci return 0; 106862306a36Sopenharmony_ci} 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci/* 107162306a36Sopenharmony_ci * Check for a valid cleanmarker. 107262306a36Sopenharmony_ci * Returns: 0 if a valid cleanmarker was found 107362306a36Sopenharmony_ci * 1 if no cleanmarker was found 107462306a36Sopenharmony_ci * negative error code if an error occurred 107562306a36Sopenharmony_ci */ 107662306a36Sopenharmony_ciint jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, 107762306a36Sopenharmony_ci struct jffs2_eraseblock *jeb) 107862306a36Sopenharmony_ci{ 107962306a36Sopenharmony_ci struct mtd_oob_ops ops = { }; 108062306a36Sopenharmony_ci int ret, cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci ops.mode = MTD_OPS_AUTO_OOB; 108362306a36Sopenharmony_ci ops.ooblen = cmlen; 108462306a36Sopenharmony_ci ops.oobbuf = c->oobbuf; 108562306a36Sopenharmony_ci ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; 108662306a36Sopenharmony_ci ops.datbuf = NULL; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci ret = mtd_read_oob(c->mtd, jeb->offset, &ops); 108962306a36Sopenharmony_ci if ((ret && !mtd_is_bitflip(ret)) || ops.oobretlen != ops.ooblen) { 109062306a36Sopenharmony_ci pr_err("cannot read OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n", 109162306a36Sopenharmony_ci jeb->offset, ops.ooblen, ops.oobretlen, ret); 109262306a36Sopenharmony_ci if (!ret || mtd_is_bitflip(ret)) 109362306a36Sopenharmony_ci ret = -EIO; 109462306a36Sopenharmony_ci return ret; 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci return !!memcmp(&oob_cleanmarker, c->oobbuf, cmlen); 109862306a36Sopenharmony_ci} 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ciint jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, 110162306a36Sopenharmony_ci struct jffs2_eraseblock *jeb) 110262306a36Sopenharmony_ci{ 110362306a36Sopenharmony_ci int ret; 110462306a36Sopenharmony_ci struct mtd_oob_ops ops = { }; 110562306a36Sopenharmony_ci int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci ops.mode = MTD_OPS_AUTO_OOB; 110862306a36Sopenharmony_ci ops.ooblen = cmlen; 110962306a36Sopenharmony_ci ops.oobbuf = (uint8_t *)&oob_cleanmarker; 111062306a36Sopenharmony_ci ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; 111162306a36Sopenharmony_ci ops.datbuf = NULL; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci ret = mtd_write_oob(c->mtd, jeb->offset, &ops); 111462306a36Sopenharmony_ci if (ret || ops.oobretlen != ops.ooblen) { 111562306a36Sopenharmony_ci pr_err("cannot write OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n", 111662306a36Sopenharmony_ci jeb->offset, ops.ooblen, ops.oobretlen, ret); 111762306a36Sopenharmony_ci if (!ret) 111862306a36Sopenharmony_ci ret = -EIO; 111962306a36Sopenharmony_ci return ret; 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci return 0; 112362306a36Sopenharmony_ci} 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci/* 112662306a36Sopenharmony_ci * On NAND we try to mark this block bad. If the block was erased more 112762306a36Sopenharmony_ci * than MAX_ERASE_FAILURES we mark it finally bad. 112862306a36Sopenharmony_ci * Don't care about failures. This block remains on the erase-pending 112962306a36Sopenharmony_ci * or badblock list as long as nobody manipulates the flash with 113062306a36Sopenharmony_ci * a bootloader or something like that. 113162306a36Sopenharmony_ci */ 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ciint jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset) 113462306a36Sopenharmony_ci{ 113562306a36Sopenharmony_ci int ret; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci /* if the count is < max, we try to write the counter to the 2nd page oob area */ 113862306a36Sopenharmony_ci if( ++jeb->bad_count < MAX_ERASE_FAILURES) 113962306a36Sopenharmony_ci return 0; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci pr_warn("marking eraseblock at %08x as bad\n", bad_offset); 114262306a36Sopenharmony_ci ret = mtd_block_markbad(c->mtd, bad_offset); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci if (ret) { 114562306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Write failed for block at %08x: error %d\n", 114662306a36Sopenharmony_ci __func__, jeb->offset, ret); 114762306a36Sopenharmony_ci return ret; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci return 1; 115062306a36Sopenharmony_ci} 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_cistatic struct jffs2_sb_info *work_to_sb(struct work_struct *work) 115362306a36Sopenharmony_ci{ 115462306a36Sopenharmony_ci struct delayed_work *dwork; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci dwork = to_delayed_work(work); 115762306a36Sopenharmony_ci return container_of(dwork, struct jffs2_sb_info, wbuf_dwork); 115862306a36Sopenharmony_ci} 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_cistatic void delayed_wbuf_sync(struct work_struct *work) 116162306a36Sopenharmony_ci{ 116262306a36Sopenharmony_ci struct jffs2_sb_info *c = work_to_sb(work); 116362306a36Sopenharmony_ci struct super_block *sb = OFNI_BS_2SFFJ(c); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 116662306a36Sopenharmony_ci jffs2_dbg(1, "%s()\n", __func__); 116762306a36Sopenharmony_ci jffs2_flush_wbuf_gc(c, 0); 116862306a36Sopenharmony_ci } 116962306a36Sopenharmony_ci} 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_civoid jffs2_dirty_trigger(struct jffs2_sb_info *c) 117262306a36Sopenharmony_ci{ 117362306a36Sopenharmony_ci struct super_block *sb = OFNI_BS_2SFFJ(c); 117462306a36Sopenharmony_ci unsigned long delay; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci if (sb_rdonly(sb)) 117762306a36Sopenharmony_ci return; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci delay = msecs_to_jiffies(dirty_writeback_interval * 10); 118062306a36Sopenharmony_ci if (queue_delayed_work(system_long_wq, &c->wbuf_dwork, delay)) 118162306a36Sopenharmony_ci jffs2_dbg(1, "%s()\n", __func__); 118262306a36Sopenharmony_ci} 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ciint jffs2_nand_flash_setup(struct jffs2_sb_info *c) 118562306a36Sopenharmony_ci{ 118662306a36Sopenharmony_ci if (!c->mtd->oobsize) 118762306a36Sopenharmony_ci return 0; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci /* Cleanmarker is out-of-band, so inline size zero */ 119062306a36Sopenharmony_ci c->cleanmarker_size = 0; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci if (c->mtd->oobavail == 0) { 119362306a36Sopenharmony_ci pr_err("inconsistent device description\n"); 119462306a36Sopenharmony_ci return -EINVAL; 119562306a36Sopenharmony_ci } 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci jffs2_dbg(1, "using OOB on NAND\n"); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci c->oobavail = c->mtd->oobavail; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci /* Initialise write buffer */ 120262306a36Sopenharmony_ci init_rwsem(&c->wbuf_sem); 120362306a36Sopenharmony_ci INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); 120462306a36Sopenharmony_ci c->wbuf_pagesize = c->mtd->writesize; 120562306a36Sopenharmony_ci c->wbuf_ofs = 0xFFFFFFFF; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); 120862306a36Sopenharmony_ci if (!c->wbuf) 120962306a36Sopenharmony_ci return -ENOMEM; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci c->oobbuf = kmalloc_array(NR_OOB_SCAN_PAGES, c->oobavail, GFP_KERNEL); 121262306a36Sopenharmony_ci if (!c->oobbuf) { 121362306a36Sopenharmony_ci kfree(c->wbuf); 121462306a36Sopenharmony_ci return -ENOMEM; 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY 121862306a36Sopenharmony_ci c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL); 121962306a36Sopenharmony_ci if (!c->wbuf_verify) { 122062306a36Sopenharmony_ci kfree(c->oobbuf); 122162306a36Sopenharmony_ci kfree(c->wbuf); 122262306a36Sopenharmony_ci return -ENOMEM; 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci#endif 122562306a36Sopenharmony_ci return 0; 122662306a36Sopenharmony_ci} 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_civoid jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) 122962306a36Sopenharmony_ci{ 123062306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY 123162306a36Sopenharmony_ci kfree(c->wbuf_verify); 123262306a36Sopenharmony_ci#endif 123362306a36Sopenharmony_ci kfree(c->wbuf); 123462306a36Sopenharmony_ci kfree(c->oobbuf); 123562306a36Sopenharmony_ci} 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ciint jffs2_dataflash_setup(struct jffs2_sb_info *c) { 123862306a36Sopenharmony_ci c->cleanmarker_size = 0; /* No cleanmarkers needed */ 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci /* Initialize write buffer */ 124162306a36Sopenharmony_ci init_rwsem(&c->wbuf_sem); 124262306a36Sopenharmony_ci INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); 124362306a36Sopenharmony_ci c->wbuf_pagesize = c->mtd->erasesize; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci /* Find a suitable c->sector_size 124662306a36Sopenharmony_ci * - Not too much sectors 124762306a36Sopenharmony_ci * - Sectors have to be at least 4 K + some bytes 124862306a36Sopenharmony_ci * - All known dataflashes have erase sizes of 528 or 1056 124962306a36Sopenharmony_ci * - we take at least 8 eraseblocks and want to have at least 8K size 125062306a36Sopenharmony_ci * - The concatenation should be a power of 2 125162306a36Sopenharmony_ci */ 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci c->sector_size = 8 * c->mtd->erasesize; 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci while (c->sector_size < 8192) { 125662306a36Sopenharmony_ci c->sector_size *= 2; 125762306a36Sopenharmony_ci } 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci /* It may be necessary to adjust the flash size */ 126062306a36Sopenharmony_ci c->flash_size = c->mtd->size; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci if ((c->flash_size % c->sector_size) != 0) { 126362306a36Sopenharmony_ci c->flash_size = (c->flash_size / c->sector_size) * c->sector_size; 126462306a36Sopenharmony_ci pr_warn("flash size adjusted to %dKiB\n", c->flash_size); 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci c->wbuf_ofs = 0xFFFFFFFF; 126862306a36Sopenharmony_ci c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); 126962306a36Sopenharmony_ci if (!c->wbuf) 127062306a36Sopenharmony_ci return -ENOMEM; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY 127362306a36Sopenharmony_ci c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL); 127462306a36Sopenharmony_ci if (!c->wbuf_verify) { 127562306a36Sopenharmony_ci kfree(c->wbuf); 127662306a36Sopenharmony_ci return -ENOMEM; 127762306a36Sopenharmony_ci } 127862306a36Sopenharmony_ci#endif 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci pr_info("write-buffering enabled buffer (%d) erasesize (%d)\n", 128162306a36Sopenharmony_ci c->wbuf_pagesize, c->sector_size); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci return 0; 128462306a36Sopenharmony_ci} 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_civoid jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { 128762306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY 128862306a36Sopenharmony_ci kfree(c->wbuf_verify); 128962306a36Sopenharmony_ci#endif 129062306a36Sopenharmony_ci kfree(c->wbuf); 129162306a36Sopenharmony_ci} 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ciint jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) { 129462306a36Sopenharmony_ci /* Cleanmarker currently occupies whole programming regions, 129562306a36Sopenharmony_ci * either one or 2 for 8Byte STMicro flashes. */ 129662306a36Sopenharmony_ci c->cleanmarker_size = max(16u, c->mtd->writesize); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci /* Initialize write buffer */ 129962306a36Sopenharmony_ci init_rwsem(&c->wbuf_sem); 130062306a36Sopenharmony_ci INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci c->wbuf_pagesize = c->mtd->writesize; 130362306a36Sopenharmony_ci c->wbuf_ofs = 0xFFFFFFFF; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); 130662306a36Sopenharmony_ci if (!c->wbuf) 130762306a36Sopenharmony_ci return -ENOMEM; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY 131062306a36Sopenharmony_ci c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL); 131162306a36Sopenharmony_ci if (!c->wbuf_verify) { 131262306a36Sopenharmony_ci kfree(c->wbuf); 131362306a36Sopenharmony_ci return -ENOMEM; 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci#endif 131662306a36Sopenharmony_ci return 0; 131762306a36Sopenharmony_ci} 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_civoid jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c) { 132062306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY 132162306a36Sopenharmony_ci kfree(c->wbuf_verify); 132262306a36Sopenharmony_ci#endif 132362306a36Sopenharmony_ci kfree(c->wbuf); 132462306a36Sopenharmony_ci} 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ciint jffs2_ubivol_setup(struct jffs2_sb_info *c) { 132762306a36Sopenharmony_ci c->cleanmarker_size = 0; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci if (c->mtd->writesize == 1) 133062306a36Sopenharmony_ci /* We do not need write-buffer */ 133162306a36Sopenharmony_ci return 0; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci init_rwsem(&c->wbuf_sem); 133462306a36Sopenharmony_ci INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci c->wbuf_pagesize = c->mtd->writesize; 133762306a36Sopenharmony_ci c->wbuf_ofs = 0xFFFFFFFF; 133862306a36Sopenharmony_ci c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); 133962306a36Sopenharmony_ci if (!c->wbuf) 134062306a36Sopenharmony_ci return -ENOMEM; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci pr_info("write-buffering enabled buffer (%d) erasesize (%d)\n", 134362306a36Sopenharmony_ci c->wbuf_pagesize, c->sector_size); 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci return 0; 134662306a36Sopenharmony_ci} 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_civoid jffs2_ubivol_cleanup(struct jffs2_sb_info *c) { 134962306a36Sopenharmony_ci kfree(c->wbuf); 135062306a36Sopenharmony_ci} 1351