1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * JFFS2 -- Journalling Flash File System, Version 2. 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * Copyright (C) 2001-2003 Red Hat, Inc. 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * Created by David Woodhouse <dwmw2@infradead.org> 7*1da177e4SLinus Torvalds * 8*1da177e4SLinus Torvalds * For licensing information, see the file 'LICENCE' in this directory. 9*1da177e4SLinus Torvalds * 10*1da177e4SLinus Torvalds * $Id: erase.c,v 1.66 2004/11/16 20:36:11 dwmw2 Exp $ 11*1da177e4SLinus Torvalds * 12*1da177e4SLinus Torvalds */ 13*1da177e4SLinus Torvalds 14*1da177e4SLinus Torvalds #include <linux/kernel.h> 15*1da177e4SLinus Torvalds #include <linux/slab.h> 16*1da177e4SLinus Torvalds #include <linux/mtd/mtd.h> 17*1da177e4SLinus Torvalds #include <linux/compiler.h> 18*1da177e4SLinus Torvalds #include <linux/crc32.h> 19*1da177e4SLinus Torvalds #include <linux/sched.h> 20*1da177e4SLinus Torvalds #include <linux/pagemap.h> 21*1da177e4SLinus Torvalds #include "nodelist.h" 22*1da177e4SLinus Torvalds 23*1da177e4SLinus Torvalds struct erase_priv_struct { 24*1da177e4SLinus Torvalds struct jffs2_eraseblock *jeb; 25*1da177e4SLinus Torvalds struct jffs2_sb_info *c; 26*1da177e4SLinus Torvalds }; 27*1da177e4SLinus Torvalds 28*1da177e4SLinus Torvalds #ifndef __ECOS 29*1da177e4SLinus Torvalds static void jffs2_erase_callback(struct erase_info *); 30*1da177e4SLinus Torvalds #endif 31*1da177e4SLinus Torvalds static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset); 32*1da177e4SLinus Torvalds static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); 33*1da177e4SLinus Torvalds static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); 34*1da177e4SLinus Torvalds static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); 35*1da177e4SLinus Torvalds 36*1da177e4SLinus Torvalds static void jffs2_erase_block(struct jffs2_sb_info *c, 37*1da177e4SLinus Torvalds struct jffs2_eraseblock *jeb) 38*1da177e4SLinus Torvalds { 39*1da177e4SLinus Torvalds int ret; 40*1da177e4SLinus Torvalds uint32_t bad_offset; 41*1da177e4SLinus Torvalds #ifdef __ECOS 42*1da177e4SLinus Torvalds ret = jffs2_flash_erase(c, jeb); 43*1da177e4SLinus Torvalds if (!ret) { 44*1da177e4SLinus Torvalds jffs2_erase_succeeded(c, jeb); 45*1da177e4SLinus Torvalds return; 46*1da177e4SLinus Torvalds } 47*1da177e4SLinus Torvalds bad_offset = jeb->offset; 48*1da177e4SLinus Torvalds #else /* Linux */ 49*1da177e4SLinus Torvalds struct erase_info *instr; 50*1da177e4SLinus Torvalds 51*1da177e4SLinus Torvalds instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); 52*1da177e4SLinus Torvalds if (!instr) { 53*1da177e4SLinus Torvalds printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); 54*1da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 55*1da177e4SLinus Torvalds list_del(&jeb->list); 56*1da177e4SLinus Torvalds list_add(&jeb->list, &c->erase_pending_list); 57*1da177e4SLinus Torvalds c->erasing_size -= c->sector_size; 58*1da177e4SLinus Torvalds c->dirty_size += c->sector_size; 59*1da177e4SLinus Torvalds jeb->dirty_size = c->sector_size; 60*1da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 61*1da177e4SLinus Torvalds return; 62*1da177e4SLinus Torvalds } 63*1da177e4SLinus Torvalds 64*1da177e4SLinus Torvalds memset(instr, 0, sizeof(*instr)); 65*1da177e4SLinus Torvalds 66*1da177e4SLinus Torvalds instr->mtd = c->mtd; 67*1da177e4SLinus Torvalds instr->addr = jeb->offset; 68*1da177e4SLinus Torvalds instr->len = c->sector_size; 69*1da177e4SLinus Torvalds instr->callback = jffs2_erase_callback; 70*1da177e4SLinus Torvalds instr->priv = (unsigned long)(&instr[1]); 71*1da177e4SLinus Torvalds instr->fail_addr = 0xffffffff; 72*1da177e4SLinus Torvalds 73*1da177e4SLinus Torvalds ((struct erase_priv_struct *)instr->priv)->jeb = jeb; 74*1da177e4SLinus Torvalds ((struct erase_priv_struct *)instr->priv)->c = c; 75*1da177e4SLinus Torvalds 76*1da177e4SLinus Torvalds ret = c->mtd->erase(c->mtd, instr); 77*1da177e4SLinus Torvalds if (!ret) 78*1da177e4SLinus Torvalds return; 79*1da177e4SLinus Torvalds 80*1da177e4SLinus Torvalds bad_offset = instr->fail_addr; 81*1da177e4SLinus Torvalds kfree(instr); 82*1da177e4SLinus Torvalds #endif /* __ECOS */ 83*1da177e4SLinus Torvalds 84*1da177e4SLinus Torvalds if (ret == -ENOMEM || ret == -EAGAIN) { 85*1da177e4SLinus Torvalds /* Erase failed immediately. Refile it on the list */ 86*1da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret)); 87*1da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 88*1da177e4SLinus Torvalds list_del(&jeb->list); 89*1da177e4SLinus Torvalds list_add(&jeb->list, &c->erase_pending_list); 90*1da177e4SLinus Torvalds c->erasing_size -= c->sector_size; 91*1da177e4SLinus Torvalds c->dirty_size += c->sector_size; 92*1da177e4SLinus Torvalds jeb->dirty_size = c->sector_size; 93*1da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 94*1da177e4SLinus Torvalds return; 95*1da177e4SLinus Torvalds } 96*1da177e4SLinus Torvalds 97*1da177e4SLinus Torvalds if (ret == -EROFS) 98*1da177e4SLinus Torvalds printk(KERN_WARNING "Erase at 0x%08x failed immediately: -EROFS. Is the sector locked?\n", jeb->offset); 99*1da177e4SLinus Torvalds else 100*1da177e4SLinus Torvalds printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret); 101*1da177e4SLinus Torvalds 102*1da177e4SLinus Torvalds jffs2_erase_failed(c, jeb, bad_offset); 103*1da177e4SLinus Torvalds } 104*1da177e4SLinus Torvalds 105*1da177e4SLinus Torvalds void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) 106*1da177e4SLinus Torvalds { 107*1da177e4SLinus Torvalds struct jffs2_eraseblock *jeb; 108*1da177e4SLinus Torvalds 109*1da177e4SLinus Torvalds down(&c->erase_free_sem); 110*1da177e4SLinus Torvalds 111*1da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 112*1da177e4SLinus Torvalds 113*1da177e4SLinus Torvalds while (!list_empty(&c->erase_complete_list) || 114*1da177e4SLinus Torvalds !list_empty(&c->erase_pending_list)) { 115*1da177e4SLinus Torvalds 116*1da177e4SLinus Torvalds if (!list_empty(&c->erase_complete_list)) { 117*1da177e4SLinus Torvalds jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); 118*1da177e4SLinus Torvalds list_del(&jeb->list); 119*1da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 120*1da177e4SLinus Torvalds jffs2_mark_erased_block(c, jeb); 121*1da177e4SLinus Torvalds 122*1da177e4SLinus Torvalds if (!--count) { 123*1da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Count reached. jffs2_erase_pending_blocks leaving\n")); 124*1da177e4SLinus Torvalds goto done; 125*1da177e4SLinus Torvalds } 126*1da177e4SLinus Torvalds 127*1da177e4SLinus Torvalds } else if (!list_empty(&c->erase_pending_list)) { 128*1da177e4SLinus Torvalds jeb = list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list); 129*1da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset)); 130*1da177e4SLinus Torvalds list_del(&jeb->list); 131*1da177e4SLinus Torvalds c->erasing_size += c->sector_size; 132*1da177e4SLinus Torvalds c->wasted_size -= jeb->wasted_size; 133*1da177e4SLinus Torvalds c->free_size -= jeb->free_size; 134*1da177e4SLinus Torvalds c->used_size -= jeb->used_size; 135*1da177e4SLinus Torvalds c->dirty_size -= jeb->dirty_size; 136*1da177e4SLinus Torvalds jeb->wasted_size = jeb->used_size = jeb->dirty_size = jeb->free_size = 0; 137*1da177e4SLinus Torvalds jffs2_free_all_node_refs(c, jeb); 138*1da177e4SLinus Torvalds list_add(&jeb->list, &c->erasing_list); 139*1da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 140*1da177e4SLinus Torvalds 141*1da177e4SLinus Torvalds jffs2_erase_block(c, jeb); 142*1da177e4SLinus Torvalds 143*1da177e4SLinus Torvalds } else { 144*1da177e4SLinus Torvalds BUG(); 145*1da177e4SLinus Torvalds } 146*1da177e4SLinus Torvalds 147*1da177e4SLinus Torvalds /* Be nice */ 148*1da177e4SLinus Torvalds cond_resched(); 149*1da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 150*1da177e4SLinus Torvalds } 151*1da177e4SLinus Torvalds 152*1da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 153*1da177e4SLinus Torvalds done: 154*1da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n")); 155*1da177e4SLinus Torvalds 156*1da177e4SLinus Torvalds up(&c->erase_free_sem); 157*1da177e4SLinus Torvalds } 158*1da177e4SLinus Torvalds 159*1da177e4SLinus Torvalds static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) 160*1da177e4SLinus Torvalds { 161*1da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset)); 162*1da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 163*1da177e4SLinus Torvalds list_del(&jeb->list); 164*1da177e4SLinus Torvalds list_add_tail(&jeb->list, &c->erase_complete_list); 165*1da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 166*1da177e4SLinus Torvalds /* Ensure that kupdated calls us again to mark them clean */ 167*1da177e4SLinus Torvalds jffs2_erase_pending_trigger(c); 168*1da177e4SLinus Torvalds } 169*1da177e4SLinus Torvalds 170*1da177e4SLinus Torvalds static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset) 171*1da177e4SLinus Torvalds { 172*1da177e4SLinus Torvalds /* For NAND, if the failure did not occur at the device level for a 173*1da177e4SLinus Torvalds specific physical page, don't bother updating the bad block table. */ 174*1da177e4SLinus Torvalds if (jffs2_cleanmarker_oob(c) && (bad_offset != 0xffffffff)) { 175*1da177e4SLinus Torvalds /* We had a device-level failure to erase. Let's see if we've 176*1da177e4SLinus Torvalds failed too many times. */ 177*1da177e4SLinus Torvalds if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { 178*1da177e4SLinus Torvalds /* We'd like to give this block another try. */ 179*1da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 180*1da177e4SLinus Torvalds list_del(&jeb->list); 181*1da177e4SLinus Torvalds list_add(&jeb->list, &c->erase_pending_list); 182*1da177e4SLinus Torvalds c->erasing_size -= c->sector_size; 183*1da177e4SLinus Torvalds c->dirty_size += c->sector_size; 184*1da177e4SLinus Torvalds jeb->dirty_size = c->sector_size; 185*1da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 186*1da177e4SLinus Torvalds return; 187*1da177e4SLinus Torvalds } 188*1da177e4SLinus Torvalds } 189*1da177e4SLinus Torvalds 190*1da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 191*1da177e4SLinus Torvalds c->erasing_size -= c->sector_size; 192*1da177e4SLinus Torvalds c->bad_size += c->sector_size; 193*1da177e4SLinus Torvalds list_del(&jeb->list); 194*1da177e4SLinus Torvalds list_add(&jeb->list, &c->bad_list); 195*1da177e4SLinus Torvalds c->nr_erasing_blocks--; 196*1da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 197*1da177e4SLinus Torvalds wake_up(&c->erase_wait); 198*1da177e4SLinus Torvalds } 199*1da177e4SLinus Torvalds 200*1da177e4SLinus Torvalds #ifndef __ECOS 201*1da177e4SLinus Torvalds static void jffs2_erase_callback(struct erase_info *instr) 202*1da177e4SLinus Torvalds { 203*1da177e4SLinus Torvalds struct erase_priv_struct *priv = (void *)instr->priv; 204*1da177e4SLinus Torvalds 205*1da177e4SLinus Torvalds if(instr->state != MTD_ERASE_DONE) { 206*1da177e4SLinus Torvalds printk(KERN_WARNING "Erase at 0x%08x finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n", instr->addr, instr->state); 207*1da177e4SLinus Torvalds jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr); 208*1da177e4SLinus Torvalds } else { 209*1da177e4SLinus Torvalds jffs2_erase_succeeded(priv->c, priv->jeb); 210*1da177e4SLinus Torvalds } 211*1da177e4SLinus Torvalds kfree(instr); 212*1da177e4SLinus Torvalds } 213*1da177e4SLinus Torvalds #endif /* !__ECOS */ 214*1da177e4SLinus Torvalds 215*1da177e4SLinus Torvalds /* Hmmm. Maybe we should accept the extra space it takes and make 216*1da177e4SLinus Torvalds this a standard doubly-linked list? */ 217*1da177e4SLinus Torvalds static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, 218*1da177e4SLinus Torvalds struct jffs2_raw_node_ref *ref, struct jffs2_eraseblock *jeb) 219*1da177e4SLinus Torvalds { 220*1da177e4SLinus Torvalds struct jffs2_inode_cache *ic = NULL; 221*1da177e4SLinus Torvalds struct jffs2_raw_node_ref **prev; 222*1da177e4SLinus Torvalds 223*1da177e4SLinus Torvalds prev = &ref->next_in_ino; 224*1da177e4SLinus Torvalds 225*1da177e4SLinus Torvalds /* Walk the inode's list once, removing any nodes from this eraseblock */ 226*1da177e4SLinus Torvalds while (1) { 227*1da177e4SLinus Torvalds if (!(*prev)->next_in_ino) { 228*1da177e4SLinus Torvalds /* We're looking at the jffs2_inode_cache, which is 229*1da177e4SLinus Torvalds at the end of the linked list. Stash it and continue 230*1da177e4SLinus Torvalds from the beginning of the list */ 231*1da177e4SLinus Torvalds ic = (struct jffs2_inode_cache *)(*prev); 232*1da177e4SLinus Torvalds prev = &ic->nodes; 233*1da177e4SLinus Torvalds continue; 234*1da177e4SLinus Torvalds } 235*1da177e4SLinus Torvalds 236*1da177e4SLinus Torvalds if (((*prev)->flash_offset & ~(c->sector_size -1)) == jeb->offset) { 237*1da177e4SLinus Torvalds /* It's in the block we're erasing */ 238*1da177e4SLinus Torvalds struct jffs2_raw_node_ref *this; 239*1da177e4SLinus Torvalds 240*1da177e4SLinus Torvalds this = *prev; 241*1da177e4SLinus Torvalds *prev = this->next_in_ino; 242*1da177e4SLinus Torvalds this->next_in_ino = NULL; 243*1da177e4SLinus Torvalds 244*1da177e4SLinus Torvalds if (this == ref) 245*1da177e4SLinus Torvalds break; 246*1da177e4SLinus Torvalds 247*1da177e4SLinus Torvalds continue; 248*1da177e4SLinus Torvalds } 249*1da177e4SLinus Torvalds /* Not to be deleted. Skip */ 250*1da177e4SLinus Torvalds prev = &((*prev)->next_in_ino); 251*1da177e4SLinus Torvalds } 252*1da177e4SLinus Torvalds 253*1da177e4SLinus Torvalds /* PARANOIA */ 254*1da177e4SLinus Torvalds if (!ic) { 255*1da177e4SLinus Torvalds printk(KERN_WARNING "inode_cache not found in remove_node_refs()!!\n"); 256*1da177e4SLinus Torvalds return; 257*1da177e4SLinus Torvalds } 258*1da177e4SLinus Torvalds 259*1da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Removed nodes in range 0x%08x-0x%08x from ino #%u\n", 260*1da177e4SLinus Torvalds jeb->offset, jeb->offset + c->sector_size, ic->ino)); 261*1da177e4SLinus Torvalds 262*1da177e4SLinus Torvalds D2({ 263*1da177e4SLinus Torvalds int i=0; 264*1da177e4SLinus Torvalds struct jffs2_raw_node_ref *this; 265*1da177e4SLinus Torvalds printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n" KERN_DEBUG); 266*1da177e4SLinus Torvalds 267*1da177e4SLinus Torvalds this = ic->nodes; 268*1da177e4SLinus Torvalds 269*1da177e4SLinus Torvalds while(this) { 270*1da177e4SLinus Torvalds printk( "0x%08x(%d)->", ref_offset(this), ref_flags(this)); 271*1da177e4SLinus Torvalds if (++i == 5) { 272*1da177e4SLinus Torvalds printk("\n" KERN_DEBUG); 273*1da177e4SLinus Torvalds i=0; 274*1da177e4SLinus Torvalds } 275*1da177e4SLinus Torvalds this = this->next_in_ino; 276*1da177e4SLinus Torvalds } 277*1da177e4SLinus Torvalds printk("\n"); 278*1da177e4SLinus Torvalds }); 279*1da177e4SLinus Torvalds 280*1da177e4SLinus Torvalds if (ic->nodes == (void *)ic) { 281*1da177e4SLinus Torvalds D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino)); 282*1da177e4SLinus Torvalds jffs2_del_ino_cache(c, ic); 283*1da177e4SLinus Torvalds jffs2_free_inode_cache(ic); 284*1da177e4SLinus Torvalds } 285*1da177e4SLinus Torvalds } 286*1da177e4SLinus Torvalds 287*1da177e4SLinus Torvalds static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) 288*1da177e4SLinus Torvalds { 289*1da177e4SLinus Torvalds struct jffs2_raw_node_ref *ref; 290*1da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Freeing all node refs for eraseblock offset 0x%08x\n", jeb->offset)); 291*1da177e4SLinus Torvalds while(jeb->first_node) { 292*1da177e4SLinus Torvalds ref = jeb->first_node; 293*1da177e4SLinus Torvalds jeb->first_node = ref->next_phys; 294*1da177e4SLinus Torvalds 295*1da177e4SLinus Torvalds /* Remove from the inode-list */ 296*1da177e4SLinus Torvalds if (ref->next_in_ino) 297*1da177e4SLinus Torvalds jffs2_remove_node_refs_from_ino_list(c, ref, jeb); 298*1da177e4SLinus Torvalds /* else it was a non-inode node or already removed, so don't bother */ 299*1da177e4SLinus Torvalds 300*1da177e4SLinus Torvalds jffs2_free_raw_node_ref(ref); 301*1da177e4SLinus Torvalds } 302*1da177e4SLinus Torvalds jeb->last_node = NULL; 303*1da177e4SLinus Torvalds } 304*1da177e4SLinus Torvalds 305*1da177e4SLinus Torvalds static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) 306*1da177e4SLinus Torvalds { 307*1da177e4SLinus Torvalds struct jffs2_raw_node_ref *marker_ref = NULL; 308*1da177e4SLinus Torvalds unsigned char *ebuf; 309*1da177e4SLinus Torvalds size_t retlen; 310*1da177e4SLinus Torvalds int ret; 311*1da177e4SLinus Torvalds uint32_t bad_offset; 312*1da177e4SLinus Torvalds 313*1da177e4SLinus Torvalds if (!jffs2_cleanmarker_oob(c)) { 314*1da177e4SLinus Torvalds marker_ref = jffs2_alloc_raw_node_ref(); 315*1da177e4SLinus Torvalds if (!marker_ref) { 316*1da177e4SLinus Torvalds printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n"); 317*1da177e4SLinus Torvalds /* Stick it back on the list from whence it came and come back later */ 318*1da177e4SLinus Torvalds jffs2_erase_pending_trigger(c); 319*1da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 320*1da177e4SLinus Torvalds list_add(&jeb->list, &c->erase_complete_list); 321*1da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 322*1da177e4SLinus Torvalds return; 323*1da177e4SLinus Torvalds } 324*1da177e4SLinus Torvalds } 325*1da177e4SLinus Torvalds ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL); 326*1da177e4SLinus Torvalds if (!ebuf) { 327*1da177e4SLinus Torvalds printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Assuming it worked\n", jeb->offset); 328*1da177e4SLinus Torvalds } else { 329*1da177e4SLinus Torvalds uint32_t ofs = jeb->offset; 330*1da177e4SLinus Torvalds 331*1da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Verifying erase at 0x%08x\n", jeb->offset)); 332*1da177e4SLinus Torvalds while(ofs < jeb->offset + c->sector_size) { 333*1da177e4SLinus Torvalds uint32_t readlen = min((uint32_t)PAGE_SIZE, jeb->offset + c->sector_size - ofs); 334*1da177e4SLinus Torvalds int i; 335*1da177e4SLinus Torvalds 336*1da177e4SLinus Torvalds bad_offset = ofs; 337*1da177e4SLinus Torvalds 338*1da177e4SLinus Torvalds ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf); 339*1da177e4SLinus Torvalds if (ret) { 340*1da177e4SLinus Torvalds printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); 341*1da177e4SLinus Torvalds goto bad; 342*1da177e4SLinus Torvalds } 343*1da177e4SLinus Torvalds if (retlen != readlen) { 344*1da177e4SLinus Torvalds printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen); 345*1da177e4SLinus Torvalds goto bad; 346*1da177e4SLinus Torvalds } 347*1da177e4SLinus Torvalds for (i=0; i<readlen; i += sizeof(unsigned long)) { 348*1da177e4SLinus Torvalds /* It's OK. We know it's properly aligned */ 349*1da177e4SLinus Torvalds unsigned long datum = *(unsigned long *)(&ebuf[i]); 350*1da177e4SLinus Torvalds if (datum + 1) { 351*1da177e4SLinus Torvalds bad_offset += i; 352*1da177e4SLinus Torvalds printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset); 353*1da177e4SLinus Torvalds bad: 354*1da177e4SLinus Torvalds if (!jffs2_cleanmarker_oob(c)) 355*1da177e4SLinus Torvalds jffs2_free_raw_node_ref(marker_ref); 356*1da177e4SLinus Torvalds kfree(ebuf); 357*1da177e4SLinus Torvalds bad2: 358*1da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 359*1da177e4SLinus Torvalds /* Stick it on a list (any list) so 360*1da177e4SLinus Torvalds erase_failed can take it right off 361*1da177e4SLinus Torvalds again. Silly, but shouldn't happen 362*1da177e4SLinus Torvalds often. */ 363*1da177e4SLinus Torvalds list_add(&jeb->list, &c->erasing_list); 364*1da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 365*1da177e4SLinus Torvalds jffs2_erase_failed(c, jeb, bad_offset); 366*1da177e4SLinus Torvalds return; 367*1da177e4SLinus Torvalds } 368*1da177e4SLinus Torvalds } 369*1da177e4SLinus Torvalds ofs += readlen; 370*1da177e4SLinus Torvalds cond_resched(); 371*1da177e4SLinus Torvalds } 372*1da177e4SLinus Torvalds kfree(ebuf); 373*1da177e4SLinus Torvalds } 374*1da177e4SLinus Torvalds 375*1da177e4SLinus Torvalds bad_offset = jeb->offset; 376*1da177e4SLinus Torvalds 377*1da177e4SLinus Torvalds /* Write the erase complete marker */ 378*1da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset)); 379*1da177e4SLinus Torvalds if (jffs2_cleanmarker_oob(c)) { 380*1da177e4SLinus Torvalds 381*1da177e4SLinus Torvalds if (jffs2_write_nand_cleanmarker(c, jeb)) 382*1da177e4SLinus Torvalds goto bad2; 383*1da177e4SLinus Torvalds 384*1da177e4SLinus Torvalds jeb->first_node = jeb->last_node = NULL; 385*1da177e4SLinus Torvalds 386*1da177e4SLinus Torvalds jeb->free_size = c->sector_size; 387*1da177e4SLinus Torvalds jeb->used_size = 0; 388*1da177e4SLinus Torvalds jeb->dirty_size = 0; 389*1da177e4SLinus Torvalds jeb->wasted_size = 0; 390*1da177e4SLinus Torvalds } else { 391*1da177e4SLinus Torvalds struct kvec vecs[1]; 392*1da177e4SLinus Torvalds struct jffs2_unknown_node marker = { 393*1da177e4SLinus Torvalds .magic = cpu_to_je16(JFFS2_MAGIC_BITMASK), 394*1da177e4SLinus Torvalds .nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER), 395*1da177e4SLinus Torvalds .totlen = cpu_to_je32(c->cleanmarker_size) 396*1da177e4SLinus Torvalds }; 397*1da177e4SLinus Torvalds 398*1da177e4SLinus Torvalds marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4)); 399*1da177e4SLinus Torvalds 400*1da177e4SLinus Torvalds vecs[0].iov_base = (unsigned char *) ▮ 401*1da177e4SLinus Torvalds vecs[0].iov_len = sizeof(marker); 402*1da177e4SLinus Torvalds ret = jffs2_flash_direct_writev(c, vecs, 1, jeb->offset, &retlen); 403*1da177e4SLinus Torvalds 404*1da177e4SLinus Torvalds if (ret) { 405*1da177e4SLinus Torvalds printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n", 406*1da177e4SLinus Torvalds jeb->offset, ret); 407*1da177e4SLinus Torvalds goto bad2; 408*1da177e4SLinus Torvalds } 409*1da177e4SLinus Torvalds if (retlen != sizeof(marker)) { 410*1da177e4SLinus Torvalds printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %zd, got %zd\n", 411*1da177e4SLinus Torvalds jeb->offset, sizeof(marker), retlen); 412*1da177e4SLinus Torvalds goto bad2; 413*1da177e4SLinus Torvalds } 414*1da177e4SLinus Torvalds 415*1da177e4SLinus Torvalds marker_ref->next_in_ino = NULL; 416*1da177e4SLinus Torvalds marker_ref->next_phys = NULL; 417*1da177e4SLinus Torvalds marker_ref->flash_offset = jeb->offset | REF_NORMAL; 418*1da177e4SLinus Torvalds marker_ref->__totlen = c->cleanmarker_size; 419*1da177e4SLinus Torvalds 420*1da177e4SLinus Torvalds jeb->first_node = jeb->last_node = marker_ref; 421*1da177e4SLinus Torvalds 422*1da177e4SLinus Torvalds jeb->free_size = c->sector_size - c->cleanmarker_size; 423*1da177e4SLinus Torvalds jeb->used_size = c->cleanmarker_size; 424*1da177e4SLinus Torvalds jeb->dirty_size = 0; 425*1da177e4SLinus Torvalds jeb->wasted_size = 0; 426*1da177e4SLinus Torvalds } 427*1da177e4SLinus Torvalds 428*1da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 429*1da177e4SLinus Torvalds c->erasing_size -= c->sector_size; 430*1da177e4SLinus Torvalds c->free_size += jeb->free_size; 431*1da177e4SLinus Torvalds c->used_size += jeb->used_size; 432*1da177e4SLinus Torvalds 433*1da177e4SLinus Torvalds ACCT_SANITY_CHECK(c,jeb); 434*1da177e4SLinus Torvalds D1(ACCT_PARANOIA_CHECK(jeb)); 435*1da177e4SLinus Torvalds 436*1da177e4SLinus Torvalds list_add_tail(&jeb->list, &c->free_list); 437*1da177e4SLinus Torvalds c->nr_erasing_blocks--; 438*1da177e4SLinus Torvalds c->nr_free_blocks++; 439*1da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 440*1da177e4SLinus Torvalds wake_up(&c->erase_wait); 441*1da177e4SLinus Torvalds } 442*1da177e4SLinus Torvalds 443