cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

erase.c (13697B)


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