nand driver cleanup and new yaffs version
This commit is contained in:
parent
7d8b0f7344
commit
fb517c3008
@ -13,6 +13,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
// WARNING: This driver is designed for HTC LEO (HD2) only.
|
||||
// Changed numbers to match Leo flash layout
|
||||
// Yaffs2 reading and writing with MTD_OOB_AUTO works
|
||||
// -Cotulla
|
||||
|
||||
// Added MTD_OOB_PLACE access to spare, removed most magic constants
|
||||
// YAFFS2 should not pass improper oob len anymore (fix in yaffs_mtdif2.c)
|
||||
// Added missing capabilities for userland mtd interaction (multi-page, data/oob only program)
|
||||
// -Rajko
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
@ -25,92 +35,34 @@
|
||||
#include <linux/stat.h>
|
||||
|
||||
#include <asm/dma.h>
|
||||
#include <asm/mach/flash.h>
|
||||
#include <mach/msm_iomap.h>
|
||||
#include <asm/mach/flash.h>
|
||||
|
||||
#include <mach/dma.h>
|
||||
|
||||
//#define ENABLE_FLASH_RW_DUMP
|
||||
//#define ENABLE_ENTRY_TRACE
|
||||
#if defined(CONFIG_ARCH_MSM7X30)
|
||||
#define MSM_NAND_BASE 0xA0200000
|
||||
#else
|
||||
#define MSM_NAND_BASE 0xA0A00000
|
||||
#endif
|
||||
|
||||
#define VERBOSE 0
|
||||
|
||||
// WARNING: This driver is designed for HTC LEO (HD2) only.
|
||||
// Changed numbers to match Leo flash layout
|
||||
// Yaffs2 reading and writing with MTD_OOB_AUTO works
|
||||
// -Cotulla
|
||||
|
||||
// Added MTD_OOB_PLACE access to spare, removed most magic constants
|
||||
// YAFFS2 should not pass improper oob len anymore (fix in yaffs_mtdif2.c)
|
||||
// Added missing capabilities for userland mtd interaction (multi-page, data/oob only program)
|
||||
// -Rajko
|
||||
|
||||
#define MSM_NAND_BASE 0xA0A00000
|
||||
#define MSM_NAND_REG(off) (MSM_NAND_BASE + (off))
|
||||
|
||||
#define MSM_NAND_FLASH_CMD MSM_NAND_REG(0x0000)
|
||||
#define MSM_NAND_ADDR0 MSM_NAND_REG(0x0004)
|
||||
#define MSM_NAND_ADDR1 MSM_NAND_REG(0x0008)
|
||||
#define MSM_NAND_FLASH_CHIP_SELECT MSM_NAND_REG(0x000C)
|
||||
#define MSM_NAND_EXEC_CMD MSM_NAND_REG(0x0010)
|
||||
#define MSM_NAND_FLASH_STATUS MSM_NAND_REG(0x0014)
|
||||
#define MSM_NAND_BUFFER_STATUS MSM_NAND_REG(0x0018)
|
||||
#define MSM_NAND_DEV0_CFG0 MSM_NAND_REG(0x0020)
|
||||
#define MSM_NAND_DEV0_CFG1 MSM_NAND_REG(0x0024)
|
||||
#define MSM_NAND_DEV1_CFG0 MSM_NAND_REG(0x0030)
|
||||
#define MSM_NAND_DEV1_CFG1 MSM_NAND_REG(0x0034)
|
||||
#define MSM_NAND_READ_ID MSM_NAND_REG(0x0040)
|
||||
#define MSM_NAND_READ_STATUS MSM_NAND_REG(0x0044)
|
||||
#define MSM_NAND_CONFIG_DATA MSM_NAND_REG(0x0050)
|
||||
#define MSM_NAND_CONFIG MSM_NAND_REG(0x0054)
|
||||
#define MSM_NAND_CONFIG_MODE MSM_NAND_REG(0x0058)
|
||||
#define MSM_NAND_CONFIG_STATUS MSM_NAND_REG(0x0060)
|
||||
#define MSM_NAND_MACRO1_REG MSM_NAND_REG(0x0064)
|
||||
#define MSM_NAND_XFR_STEP1 MSM_NAND_REG(0x0070)
|
||||
#define MSM_NAND_XFR_STEP2 MSM_NAND_REG(0x0074)
|
||||
#define MSM_NAND_XFR_STEP3 MSM_NAND_REG(0x0078)
|
||||
#define MSM_NAND_XFR_STEP4 MSM_NAND_REG(0x007C)
|
||||
#define MSM_NAND_XFR_STEP5 MSM_NAND_REG(0x0080)
|
||||
#define MSM_NAND_XFR_STEP6 MSM_NAND_REG(0x0084)
|
||||
#define MSM_NAND_XFR_STEP7 MSM_NAND_REG(0x0088)
|
||||
#define MSM_NAND_DEV_CMD0 MSM_NAND_REG(0x00A0)
|
||||
#define MSM_NAND_DEV_CMD1 MSM_NAND_REG(0x00A4)
|
||||
#define MSM_NAND_DEV_CMD2 MSM_NAND_REG(0x00A8)
|
||||
#define MSM_NAND_DEV_CMD_VLD MSM_NAND_REG(0x00AC)
|
||||
#define MSM_NAND_EBI2_MISR_SIG_REG MSM_NAND_REG(0x00B0)
|
||||
#define MSM_NAND_EBI2_ECC_BUF_CFG MSM_NAND_REG(0x00F0)
|
||||
#define MSM_NAND_FLASH_BUFFER MSM_NAND_REG(0x0100)
|
||||
|
||||
/* device commands */
|
||||
|
||||
#define MSM_NAND_CMD_SOFT_RESET 0x01
|
||||
#define MSM_NAND_CMD_PAGE_READ 0x32
|
||||
#define MSM_NAND_CMD_PAGE_READ_ECC 0x33
|
||||
#define MSM_NAND_CMD_PAGE_READ_ALL 0x34
|
||||
#define MSM_NAND_CMD_SEQ_PAGE_READ 0x15
|
||||
#define MSM_NAND_CMD_PRG_PAGE 0x36
|
||||
#define MSM_NAND_CMD_PRG_PAGE_ECC 0x37
|
||||
#define MSM_NAND_CMD_PRG_PAGE_ALL 0x39
|
||||
#define MSM_NAND_CMD_BLOCK_ERASE 0x3A
|
||||
#define MSM_NAND_CMD_FETCH_ID 0x0B
|
||||
#define MSM_NAND_CMD_STATUS 0x0C
|
||||
#define MSM_NAND_CMD_RESET 0x0D
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#include "msm_nand.h"
|
||||
|
||||
#define MSM_NAND_DMA_BUFFER_SIZE SZ_4K
|
||||
#define MSM_NAND_DMA_BUFFER_SLOTS \
|
||||
(MSM_NAND_DMA_BUFFER_SIZE / (sizeof(((atomic_t *)0)->counter) * 8))
|
||||
|
||||
#define MSM_NAND_CFG0_RAW 0xA80420C0
|
||||
#define MSM_NAND_CFG1_RAW 0x5045D
|
||||
#define MSM_NAND_CFG0_RAW 0xA80420C0
|
||||
#define MSM_NAND_CFG1_RAW 0x5045D
|
||||
|
||||
#define SUPPORT_WRONG_ECC_CONFIG 1
|
||||
#define IGNORE_ARM9_CONFIG 0
|
||||
#define SUPPORT_WRONG_ECC_CONFIG 0
|
||||
#define IGNORE_ARM9_CONFIG 0
|
||||
#define VERBOSE 0
|
||||
|
||||
//#define ENABLE_FLASH_RW_DUMP
|
||||
//#define ENABLE_ENTRY_TRACE
|
||||
|
||||
static struct nand_hw_info *nand_info;
|
||||
struct nand_hw_info
|
||||
{
|
||||
struct nand_hw_info {
|
||||
uint32_t flash_id;
|
||||
uint8_t maker_id;
|
||||
uint8_t maker_name[10];
|
||||
@ -147,7 +99,7 @@ struct msm_nand_chip {
|
||||
|
||||
#define msm_virt_to_dma(chip, vaddr) \
|
||||
((void)(*(vaddr)), (chip)->dma_addr + \
|
||||
((uint8_t *)(vaddr) - (chip)->dma_buffer))
|
||||
((uint8_t *)(vaddr) - (chip)->dma_buffer))
|
||||
|
||||
/**
|
||||
* msm_nand_oob_64 - oob info for 2KB page
|
||||
@ -188,8 +140,8 @@ struct flash_identification {
|
||||
|
||||
static struct flash_identification supported_flash[] =
|
||||
{
|
||||
/* Flash ID ID Mask Density(MB) Wid Pgsz Blksz oobsz Manuf */
|
||||
{0x00000000, 0xFFFFFFFF, 0, 0, 0, 0, 0, }, /*ONFI*/
|
||||
/* Flash ID ID Mask Density(MB) Wid Pgsz Blksz oobsz Manuf */
|
||||
{0x00000000, 0xFFFFFFFF, 0, 0, 0, 0, 0, }, /*ONFI*/
|
||||
{0x1500aaec, 0xFF00FFFF, (256<<20), 0, 2048, (2048<<6), 64, }, /*Samsung 2Gbit*/
|
||||
{0x5500baec, 0xFF00FFFF, (256<<20), 1, 2048, (2048<<6), 64, }, /*Samsung 2Gbit*/
|
||||
{0x6600bcec, 0xFF00FFFF, (512<<20), 1, 4096, (4096<<6), 128,}, /*Samsung 4Gbit 4K Page*/
|
||||
@ -210,7 +162,7 @@ static struct flash_identification supported_flash[] =
|
||||
{0x0000baad, 0x0000FFFF, (256<<20), 1, 2048, (2048<<6), 64, }, /*Hynix 2Gbit*/
|
||||
{0x0000bcad, 0x0000FFFF, (512<<20), 1, 2048, (2048<<6), 64, }, /*Hynix 4Gbit*/
|
||||
{0x0000b3ad, 0x0000FFFF, (1024<<20),1, 2048, (2048<<6), 64, }, /*Hynix 8Gbit*/
|
||||
/* Note: Width flag is 0 for 8 bit Flash and 1 for 16 bit flash */
|
||||
/* Note: Width flag is 0 for 8 bit Flash and 1 for 16 bit flash */
|
||||
/* Note: The First row will be filled at runtime during ONFI probe */
|
||||
};
|
||||
|
||||
@ -246,7 +198,7 @@ static void *msm_nand_get_dma_buffer(struct msm_nand_chip *chip, size_t size)
|
||||
}
|
||||
|
||||
static void msm_nand_release_dma_buffer(struct msm_nand_chip *chip,
|
||||
void *buffer, size_t size)
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
int index;
|
||||
unsigned int used_mask;
|
||||
@ -269,8 +221,8 @@ uint32_t flash_read_id(struct msm_nand_chip *chip)
|
||||
uint32_t rv;
|
||||
|
||||
wait_event(chip->wait_queue,
|
||||
(dma_buffer = msm_nand_get_dma_buffer(
|
||||
chip, sizeof(*dma_buffer))));
|
||||
(dma_buffer = msm_nand_get_dma_buffer(
|
||||
chip, sizeof(*dma_buffer))));
|
||||
|
||||
dma_buffer->data[0] = 0 | 4;
|
||||
dma_buffer->data[1] = MSM_NAND_CMD_FETCH_ID;
|
||||
@ -333,8 +285,8 @@ int flash_read_config(struct msm_nand_chip *chip)
|
||||
} *dma_buffer;
|
||||
|
||||
wait_event(chip->wait_queue,
|
||||
(dma_buffer = msm_nand_get_dma_buffer(
|
||||
chip, sizeof(*dma_buffer))));
|
||||
(dma_buffer = msm_nand_get_dma_buffer(
|
||||
chip, sizeof(*dma_buffer))));
|
||||
dma_buffer->cfg0 = 0;
|
||||
dma_buffer->cfg1 = 0;
|
||||
|
||||
@ -380,15 +332,16 @@ unsigned flash_rd_reg(struct msm_nand_chip *chip, unsigned addr)
|
||||
unsigned rv;
|
||||
|
||||
wait_event(chip->wait_queue,
|
||||
(dma_buffer = msm_nand_get_dma_buffer(
|
||||
chip, sizeof(*dma_buffer))));
|
||||
(dma_buffer = msm_nand_get_dma_buffer(
|
||||
chip, sizeof(*dma_buffer))));
|
||||
|
||||
dma_buffer->cmd.cmd = CMD_LC;
|
||||
dma_buffer->cmd.src = addr;
|
||||
dma_buffer->cmd.dst = msm_virt_to_dma(chip, &dma_buffer->data);
|
||||
dma_buffer->cmd.len = 4;
|
||||
|
||||
dma_buffer->cmdptr = (msm_virt_to_dma(chip, &dma_buffer->cmd) >> 3) | CMD_PTR_LP;
|
||||
dma_buffer->cmdptr =
|
||||
(msm_virt_to_dma(chip, &dma_buffer->cmd) >> 3) | CMD_PTR_LP;
|
||||
dma_buffer->data = 0xeeeeeeee;
|
||||
|
||||
dsb();
|
||||
@ -412,8 +365,8 @@ void flash_wr_reg(struct msm_nand_chip *chip, unsigned addr, unsigned val)
|
||||
} *dma_buffer;
|
||||
|
||||
wait_event(chip->wait_queue,
|
||||
(dma_buffer = msm_nand_get_dma_buffer(
|
||||
chip, sizeof(*dma_buffer))));
|
||||
(dma_buffer = msm_nand_get_dma_buffer(
|
||||
chip, sizeof(*dma_buffer))));
|
||||
|
||||
dma_buffer->cmd.cmd = CMD_LC;
|
||||
dma_buffer->cmd.src = msm_virt_to_dma(chip, &dma_buffer->data);
|
||||
@ -435,7 +388,7 @@ void flash_wr_reg(struct msm_nand_chip *chip, unsigned addr, unsigned val)
|
||||
|
||||
static dma_addr_t
|
||||
msm_nand_dma_map(struct device *dev, void *addr, size_t size,
|
||||
enum dma_data_direction dir)
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
struct page *page;
|
||||
unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
|
||||
@ -850,14 +803,18 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_o
|
||||
//remap dma if there's still data to be read
|
||||
if (data_count > 0)
|
||||
{
|
||||
int offset = ops->len-data_count;
|
||||
#if VERBOSE
|
||||
printk("msm_nand_read_oob dma_map_page offset=%d length=%d\n", (uint32_t)(ops->len-data_count), data_count);
|
||||
printk("msm_nand_read_oob dma_map_page offset=%d length=%d\n", offset, data_count);
|
||||
#endif
|
||||
data_dma_addr = msm_nand_dma_map(chip->dev, ops->datbuf+(ops->len-data_count), data_count, DMA_FROM_DEVICE);
|
||||
data_dma_addr = msm_nand_dma_map(chip->dev, ops->datbuf+offset, data_count, DMA_FROM_DEVICE);
|
||||
data_dma_addr_curr = data_dma_addr;
|
||||
#if VERBOSE
|
||||
printk("msm_nand_read_oob dma_map_page returned %08x\n", (uint32_t)data_dma_addr);
|
||||
#endif
|
||||
|
||||
if (dma_mapping_error(chip->dev, data_dma_addr)) {
|
||||
pr_err("msm_nand_read_oob: failed to re-get dma addr "
|
||||
"for %p+%d initial_size=%d remaining_size=%d\n", ops->datbuf, offset, ops->len, data_count);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1543,7 +1500,6 @@ msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
} *dma_buffer;
|
||||
unsigned page = 0;
|
||||
|
||||
|
||||
if (mtd->writesize == 2048)
|
||||
page = instr->addr >> 11;
|
||||
|
||||
@ -1551,7 +1507,7 @@ msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
page = instr->addr >> 12;
|
||||
|
||||
#ifdef ENABLE_ENTRY_TRACE
|
||||
printk("+msm_nand_erase(%d)\n", page);
|
||||
printk("msm_nand_erase(%d)\n", page);
|
||||
#endif
|
||||
|
||||
if (instr->addr & (mtd->erasesize - 1)) {
|
||||
@ -1559,6 +1515,7 @@ msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
__func__, instr->addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (instr->addr < (NUM_PROTECTED_BLOCKS*mtd->erasesize))
|
||||
{
|
||||
pr_err("%s: cannot erase block in protected area, addr=0x%llx\n",
|
||||
@ -1572,8 +1529,8 @@ msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
}
|
||||
|
||||
wait_event(chip->wait_queue,
|
||||
(dma_buffer = msm_nand_get_dma_buffer(
|
||||
chip, sizeof(*dma_buffer))));
|
||||
(dma_buffer = msm_nand_get_dma_buffer(
|
||||
chip, sizeof(*dma_buffer))));
|
||||
|
||||
dma_buffer->data[0] = MSM_NAND_CMD_BLOCK_ERASE;
|
||||
dma_buffer->data[1] = page;
|
||||
@ -1607,7 +1564,7 @@ msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
dma_buffer->cmd[3].len = 4;
|
||||
|
||||
/* clear the status register in case the OP_ERR is set
|
||||
* due to the write, to work around a h/w bug */
|
||||
* due to the write, to work around a h/w bug */
|
||||
dma_buffer->cmd[4].cmd = CMD_OCU | CMD_LC;
|
||||
dma_buffer->cmd[4].src = msm_virt_to_dma(chip, &dma_buffer->data[8]);
|
||||
dma_buffer->cmd[4].dst = MSM_NAND_FLASH_STATUS;
|
||||
@ -1624,18 +1581,19 @@ msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
dsb();
|
||||
|
||||
/* we fail if there was an operation error, a mpu error, or the
|
||||
* erase success bit was not set.
|
||||
*/
|
||||
* erase success bit was not set.
|
||||
*/
|
||||
|
||||
if (dma_buffer->data[5] & 0x110 || !(dma_buffer->data[5] & 0x80)) {
|
||||
if (dma_buffer->data[5] & 0x10)
|
||||
pr_warning("msm_nand: critical erase error, 0x%llx\n",
|
||||
instr->addr);
|
||||
instr->addr);
|
||||
err = -EIO;
|
||||
} else
|
||||
err = 0;
|
||||
|
||||
msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
|
||||
|
||||
if (err) {
|
||||
pr_err("%s: erase failed, 0x%llx\n", __func__, instr->addr);
|
||||
instr->fail_addr = instr->addr;
|
||||
@ -1645,6 +1603,7 @@ msm_nand_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
instr->fail_addr = 0xffffffff;
|
||||
mtd_erase_callback(instr);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1676,9 +1635,6 @@ msm_nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||
unsigned page = 0;
|
||||
unsigned cwperpage;
|
||||
|
||||
#ifdef ENABLE_ENTRY_TRACE
|
||||
printk("+nand_block_isbad\n");
|
||||
#endif
|
||||
if (mtd->writesize == 2048)
|
||||
page = ofs >> 11;
|
||||
|
||||
@ -1690,11 +1646,12 @@ msm_nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||
/* Check for invalid offset */
|
||||
if (ofs > mtd->size)
|
||||
return -EINVAL;
|
||||
if (ofs & (mtd->erasesize - 1))
|
||||
{
|
||||
pr_err("%s: unsupported block address, 0x%x\n", __func__, (uint32_t)ofs);
|
||||
if (ofs & (mtd->erasesize - 1)) {
|
||||
pr_err("%s: unsupported block address, 0x%x\n",
|
||||
__func__, (uint32_t)ofs);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ofs < (NUM_PROTECTED_BLOCKS*mtd->erasesize))
|
||||
{
|
||||
//protected blocks are always good
|
||||
@ -1703,24 +1660,25 @@ msm_nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||
|
||||
wait_event(chip->wait_queue,
|
||||
(dma_buffer = msm_nand_get_dma_buffer(chip ,
|
||||
sizeof(*dma_buffer) + 4)));
|
||||
sizeof(*dma_buffer) + 4)));
|
||||
buf = (uint8_t *)dma_buffer + sizeof(*dma_buffer);
|
||||
|
||||
/* Read 4 bytes starting from the bad block marker location
|
||||
* in the last code word of the page
|
||||
*/
|
||||
* in the last code word of the page
|
||||
*/
|
||||
|
||||
cmd = dma_buffer->cmd;
|
||||
|
||||
dma_buffer->data.cmd = MSM_NAND_CMD_PAGE_READ;
|
||||
dma_buffer->data.cfg0 = MSM_NAND_CFG0_RAW & ~(7U << 6);
|
||||
// ecc disabled
|
||||
dma_buffer->data.cfg0 = MSM_NAND_CFG0_RAW & ~(7U << 6);
|
||||
dma_buffer->data.cfg1 = MSM_NAND_CFG1_RAW | (chip->CFG1 & CFG1_WIDE_FLASH);
|
||||
|
||||
if (chip->CFG1 & CFG1_WIDE_FLASH)
|
||||
dma_buffer->data.addr0 = (page << 16) | ((528*(cwperpage-1)) >> 1);
|
||||
dma_buffer->data.addr0 = (page << 16) |
|
||||
((528*(cwperpage-1)) >> 1);
|
||||
else
|
||||
dma_buffer->data.addr0 = (page << 16) | (528*(cwperpage-1));
|
||||
dma_buffer->data.addr0 = (page << 16) |
|
||||
(528*(cwperpage-1));
|
||||
|
||||
dma_buffer->data.addr1 = (page >> 16) & 0xff;
|
||||
dma_buffer->data.chipsel = 0 | 4;
|
||||
@ -1766,57 +1724,37 @@ msm_nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||
cmd[-1].cmd |= CMD_OCU | CMD_LC;
|
||||
|
||||
dma_buffer->cmdptr = (msm_virt_to_dma(chip,
|
||||
dma_buffer->cmd) >> 3) | CMD_PTR_LP;
|
||||
dma_buffer->cmd) >> 3) | CMD_PTR_LP;
|
||||
|
||||
dsb();
|
||||
msm_dmov_exec_cmd(chip->dma_channel, DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
|
||||
msm_dmov_exec_cmd(chip->dma_channel, DMOV_CMD_PTR_LIST |
|
||||
DMOV_CMD_ADDR(msm_virt_to_dma(chip, &dma_buffer->cmdptr)));
|
||||
dsb();
|
||||
|
||||
ret = 0;
|
||||
if (dma_buffer->data.result.flash_status & 0x110)
|
||||
{
|
||||
#if VERBOSE
|
||||
if (dma_buffer->data.result.flash_status & 0x100)
|
||||
{
|
||||
pr_err("msm_block_isbad off=%d protection violation\n",(uint32_t)ofs);
|
||||
}
|
||||
if (dma_buffer->data.result.flash_status & 0x10)
|
||||
{
|
||||
pr_err("msm_block_isbad off=%d wrfail\n",(uint32_t)ofs);
|
||||
}
|
||||
#endif
|
||||
ret = -EIO;
|
||||
|
||||
if (!ret) {
|
||||
/* Check for bad block marker byte */
|
||||
if (chip->CFG1 & CFG1_WIDE_FLASH) {
|
||||
if (buf[0] != 0xFF || buf[1] != 0xFF)
|
||||
ret = 1;
|
||||
} else {
|
||||
if (buf[0] != 0xFF)
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
/* Check for bad block marker byte */
|
||||
if (chip->CFG1 & CFG1_WIDE_FLASH)
|
||||
{
|
||||
if (buf[0] != 0xFF || buf[1] != 0xFF)
|
||||
{
|
||||
ret = 1;
|
||||
printk("###BAD BLOCK %d %08X###\n", (uint32_t)(ofs) / mtd->erasesize, (uint32_t)ofs);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buf[0] != 0xFF)
|
||||
{
|
||||
ret = 1;
|
||||
printk("###BAD BLOCK %d %08X###\n", (uint32_t)(ofs) / mtd->erasesize, (uint32_t)ofs);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret==1)
|
||||
printk("###BAD BLOCK %d %08X###\n", (uint32_t)(ofs) / mtd->erasesize, (uint32_t)ofs);
|
||||
else if (ret != 0)
|
||||
printk("###ERROR CHECKING BLOCK %d %08X###\n", (uint32_t)(ofs) / mtd->erasesize, (uint32_t)ofs);
|
||||
|
||||
msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer) + 4);
|
||||
#ifdef ENABLE_ENTRY_TRACE
|
||||
printk("-nand_block_isbad %d\n", ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
msm_nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
@ -1824,8 +1762,7 @@ msm_nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
int ret;
|
||||
|
||||
ret = msm_nand_block_isbad(mtd, ofs);
|
||||
if (ret)
|
||||
{
|
||||
if (ret) {
|
||||
/* If it was bad already, return success and do nothing */
|
||||
if (ret > 0)
|
||||
return 0;
|
||||
@ -1836,28 +1773,28 @@ msm_nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
}
|
||||
|
||||
/**
|
||||
* msm_nand_suspend - [MTD Interface] Suspend the msm_nand flash
|
||||
* @param mtd MTD device structure
|
||||
*/
|
||||
* msm_nand_suspend - [MTD Interface] Suspend the msm_nand flash
|
||||
* @param mtd MTD device structure
|
||||
*/
|
||||
static int msm_nand_suspend(struct mtd_info *mtd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* msm_nand_resume - [MTD Interface] Resume the msm_nand flash
|
||||
* @param mtd MTD device structure
|
||||
*/
|
||||
* msm_nand_resume - [MTD Interface] Resume the msm_nand flash
|
||||
* @param mtd MTD device structure
|
||||
*/
|
||||
static void msm_nand_resume(struct mtd_info *mtd)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Export 3 attributes for HTC SSD HW INFO tool
|
||||
* >info :basic HW spec of this NAND chip
|
||||
* >vendor :vendor information
|
||||
* >pagesize:page size, either 2048 or 4096
|
||||
*/
|
||||
* Export 3 attributes for HTC SSD HW INFO tool
|
||||
* >info :basic HW spec of this NAND chip
|
||||
* >vendor :vendor information
|
||||
* >pagesize:page size, either 2048 or 4096
|
||||
*/
|
||||
static int param_get_vendor_name(char *buffer, struct kernel_param *kp)
|
||||
{
|
||||
return sprintf(buffer, "%s", nand_info->maker_name);
|
||||
@ -1869,17 +1806,17 @@ static int param_get_nand_info(char *buffer, struct kernel_param *kp)
|
||||
int result = 0;
|
||||
result += sprintf(buffer, "<< NAND INFO >>\n");
|
||||
result += sprintf(buffer + result, "flash id\t =%X\n",
|
||||
nand_info->flash_id);
|
||||
nand_info->flash_id);
|
||||
result += sprintf(buffer + result, "vendor\t\t =%s\n",
|
||||
nand_info->maker_name);
|
||||
nand_info->maker_name);
|
||||
result += sprintf(buffer + result, "width\t\t =%d bits\n",
|
||||
nand_info->width);
|
||||
nand_info->width);
|
||||
result += sprintf(buffer + result, "size\t\t =%d MB\n",
|
||||
nand_info->size>>20);
|
||||
nand_info->size>>20);
|
||||
result += sprintf(buffer + result, "block count\t =%d\n",
|
||||
nand_info->block_count);
|
||||
nand_info->block_count);
|
||||
result += sprintf(buffer + result, "page count\t =%d",
|
||||
nand_info->page_count);
|
||||
nand_info->page_count);
|
||||
return result;
|
||||
}
|
||||
module_param_call(info, NULL, param_get_nand_info, NULL, S_IRUGO);
|
||||
@ -1913,17 +1850,16 @@ int msm_nand_scan(struct mtd_info *mtd, int maxchips)
|
||||
flash_id = flash_read_id(chip);
|
||||
for (index = 1; index < ARRAY_SIZE(supported_flash); index++) {
|
||||
if ((flash_id & supported_flash[index].mask) ==
|
||||
(supported_flash[index].flash_id &
|
||||
(supported_flash[index].mask))) {
|
||||
dev_found = 1;
|
||||
break;
|
||||
(supported_flash[index].flash_id &
|
||||
(supported_flash[index].mask))) {
|
||||
dev_found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev_found)
|
||||
{
|
||||
wide_bus = supported_flash[index].widebus;
|
||||
mtd->size = supported_flash[index].density * i;
|
||||
if (dev_found) {
|
||||
wide_bus = supported_flash[index].widebus;
|
||||
mtd->size = supported_flash[index].density * i;
|
||||
mtd->writesize = supported_flash[index].pagesize * i;
|
||||
mtd->oobsize = supported_flash[index].oobsize * i;
|
||||
mtd->erasesize = supported_flash[index].blksize * i;
|
||||
@ -1942,7 +1878,6 @@ int msm_nand_scan(struct mtd_info *mtd, int maxchips)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
if (mtd->writesize != 2048)
|
||||
{
|
||||
pr_err("ERROR: unsupported flash parameters!\n");
|
||||
@ -1961,17 +1896,16 @@ int msm_nand_scan(struct mtd_info *mtd, int maxchips)
|
||||
chip->CFG0 = (((mtd->writesize >> 9)-1) << 6) /* 4/8 cw/per page for 2/4k */
|
||||
| (512 << 9) /* 512 user data bytes */
|
||||
| (10 << 19) /* 10 parity bytes */
|
||||
| (4 << 23) /* spare size */
|
||||
| (5 << 27) /* 5 address cycles */
|
||||
| (1 << 30) /* Read status before data */
|
||||
| (1 << 31) /* Send read cmd */
|
||||
| 0;
|
||||
| (4 << 23) /* spare size */
|
||||
| (5 << 27) /* 5 address cycles */
|
||||
| (1 << 30) /* Read status before data */
|
||||
| (1 << 31); /* Send read cmd */
|
||||
chip->CFG1 = chip->CFG1
|
||||
#if IGNORE_ARM9_CONFIG
|
||||
/* use ARM11 own setting on CFG1 */
|
||||
| (7 << 2) /* 8 recovery cycles */
|
||||
| (0 << 5) /* Allow CS deassertion */
|
||||
| (2 << 17) /* 6 cycle tWB/tRB */
|
||||
| (7 << 2) /* 8 recovery cycles */
|
||||
| (0 << 5) /* Allow CS deassertion */
|
||||
| (2 << 17) /* 6 cycle tWB/tRB */
|
||||
#endif
|
||||
| ((mtd->writesize - (528 * ((mtd->writesize >> 9) - 1)) + 1) << 6) /* Bad block marker location */
|
||||
| (wide_bus << 1); /* Wide flash bit */
|
||||
@ -2004,8 +1938,7 @@ int msm_nand_scan(struct mtd_info *mtd, int maxchips)
|
||||
}
|
||||
else
|
||||
{
|
||||
pr_err("Unsupported Nand, oobsize: 0x%x \n",
|
||||
mtd->oobsize);
|
||||
pr_err("Unsupported Nand, oobsize: 0x%x \n", mtd->oobsize);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -2084,9 +2017,9 @@ int msm_nand_scan(struct mtd_info *mtd, int maxchips)
|
||||
EXPORT_SYMBOL_GPL(msm_nand_scan);
|
||||
|
||||
/**
|
||||
* msm_nand_release - [msm_nand Interface] Free resources held by the msm_nand device
|
||||
* @param mtd MTD device structure
|
||||
*/
|
||||
* msm_nand_release - [msm_nand Interface] Free resources held by the msm_nand device
|
||||
* @param mtd MTD device structure
|
||||
*/
|
||||
void msm_nand_release(struct mtd_info *mtd)
|
||||
{
|
||||
/* struct msm_nand_chip *this = mtd->priv; */
|
||||
@ -2105,7 +2038,7 @@ static const char *part_probes[] = { "cmdlinepart", NULL, };
|
||||
#endif
|
||||
|
||||
struct msm_nand_info {
|
||||
struct mtd_info mtd;
|
||||
struct mtd_info mtd;
|
||||
struct mtd_partition *parts;
|
||||
struct msm_nand_chip msm_nand;
|
||||
};
|
||||
@ -2137,7 +2070,7 @@ static int __devinit msm_nand_probe(struct platform_device *pdev)
|
||||
/* this currently fails if dev is passed in */
|
||||
info->msm_nand.dma_buffer =
|
||||
dma_alloc_coherent(/*dev*/ NULL, MSM_NAND_DMA_BUFFER_SIZE,
|
||||
&info->msm_nand.dma_addr, GFP_KERNEL);
|
||||
&info->msm_nand.dma_addr, GFP_KERNEL);
|
||||
if (info->msm_nand.dma_buffer == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto out_free_info;
|
||||
@ -2159,10 +2092,11 @@ static int __devinit msm_nand_probe(struct platform_device *pdev)
|
||||
|
||||
#ifdef CONFIG_MTD_PARTITIONS
|
||||
/* Re-calculate the partition offset and size with correct page size */
|
||||
for (i = 0; i < pdata->nr_parts; i++)
|
||||
{
|
||||
pdata->parts[i].offset = pdata->parts[i].offset * info->mtd.erasesize;
|
||||
pdata->parts[i].size = pdata->parts[i].size * info->mtd.erasesize;
|
||||
for (i = 0; i < pdata->nr_parts; i++) {
|
||||
pdata->parts[i].offset = pdata->parts[i].offset
|
||||
* info->mtd.erasesize;
|
||||
pdata->parts[i].size = pdata->parts[i].size
|
||||
* info->mtd.erasesize;
|
||||
}
|
||||
|
||||
err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);
|
||||
@ -2179,7 +2113,8 @@ static int __devinit msm_nand_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
out_free_dma_buffer:
|
||||
dma_free_coherent(/*dev*/ NULL, SZ_4K, info->msm_nand.dma_buffer, info->msm_nand.dma_addr);
|
||||
dma_free_coherent(/*dev*/ NULL, SZ_4K, info->msm_nand.dma_buffer,
|
||||
info->msm_nand.dma_addr);
|
||||
out_free_info:
|
||||
kfree(info);
|
||||
|
||||
@ -2202,8 +2137,8 @@ static int __devexit msm_nand_remove(struct platform_device *pdev)
|
||||
|
||||
msm_nand_release(&info->mtd);
|
||||
dma_free_coherent(/*dev*/ NULL, SZ_4K,
|
||||
info->msm_nand.dma_buffer,
|
||||
info->msm_nand.dma_addr);
|
||||
info->msm_nand.dma_buffer,
|
||||
info->msm_nand.dma_addr);
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
@ -2213,10 +2148,10 @@ static int __devexit msm_nand_remove(struct platform_device *pdev)
|
||||
#define DRIVER_NAME "msm_nand"
|
||||
|
||||
static struct platform_driver msm_nand_driver = {
|
||||
.probe = msm_nand_probe,
|
||||
.remove = __devexit_p(msm_nand_remove),
|
||||
.probe = msm_nand_probe,
|
||||
.remove = __devexit_p(msm_nand_remove),
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.name = DRIVER_NAME,
|
||||
}
|
||||
};
|
||||
|
||||
@ -2238,3 +2173,4 @@ module_exit(msm_nand_exit);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("htcleo nand driver code");
|
||||
|
||||
|
||||
|
@ -678,15 +678,12 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from,
|
||||
* was a protection violation (0x100), we lose
|
||||
*/
|
||||
pageerr = rawerr = 0;
|
||||
// This check fails on reading from Leos NAND, we have to check why
|
||||
#ifndef CONFIG_MACH_HTCLEO
|
||||
for (n = start_sector; n < cwperpage; n++) {
|
||||
if (dma_buffer->data.result[n].flash_status & 0x110) {
|
||||
rawerr = -EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (rawerr) {
|
||||
if (ops->datbuf) {
|
||||
uint8_t *datbuf = ops->datbuf +
|
||||
|
@ -4,11 +4,11 @@
|
||||
|
||||
obj-$(CONFIG_YAFFS_FS) += yaffs.o
|
||||
|
||||
yaffs-y := yaffs_ecc.o yaffs_vfs_glue.o yaffs_guts.o yaffs_checkptrw.o
|
||||
yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o
|
||||
yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
|
||||
yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
|
||||
yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
|
||||
yaffs-y += yaffs_nameval.o
|
||||
yaffs-y += yaffs_nameval.o yaffs_attribs.o
|
||||
yaffs-y += yaffs_allocator.o
|
||||
yaffs-y += yaffs_yaffs1.o
|
||||
yaffs-y += yaffs_yaffs2.o
|
||||
|
@ -1,101 +0,0 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2010 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is just holds extra declarations of macros that would normally
|
||||
* be providesd in the Linux kernel. These macros have been written from
|
||||
* scratch but are functionally equivalent to the Linux ones.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __EXTRAS_H__
|
||||
#define __EXTRAS_H__
|
||||
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
#if !(defined __KERNEL__)
|
||||
|
||||
/* Definition of types */
|
||||
typedef unsigned char __u8;
|
||||
typedef unsigned short __u16;
|
||||
typedef unsigned __u32;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if !(defined __KERNEL__)
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_YAFFS_PROVIDE_DEFS
|
||||
/* File types */
|
||||
|
||||
|
||||
#define DT_UNKNOWN 0
|
||||
#define DT_FIFO 1
|
||||
#define DT_CHR 2
|
||||
#define DT_DIR 4
|
||||
#define DT_BLK 6
|
||||
#define DT_REG 8
|
||||
#define DT_LNK 10
|
||||
#define DT_SOCK 12
|
||||
#define DT_WHT 14
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Attribute flags. These should be or-ed together to figure out what
|
||||
* has been changed!
|
||||
*/
|
||||
#define ATTR_MODE 1
|
||||
#define ATTR_UID 2
|
||||
#define ATTR_GID 4
|
||||
#define ATTR_SIZE 8
|
||||
#define ATTR_ATIME 16
|
||||
#define ATTR_MTIME 32
|
||||
#define ATTR_CTIME 64
|
||||
|
||||
struct iattr {
|
||||
unsigned int ia_valid;
|
||||
unsigned ia_mode;
|
||||
unsigned ia_uid;
|
||||
unsigned ia_gid;
|
||||
unsigned ia_size;
|
||||
unsigned ia_atime;
|
||||
unsigned ia_mtime;
|
||||
unsigned ia_ctime;
|
||||
unsigned int ia_attr_flags;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/stat.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
@ -62,13 +62,12 @@
|
||||
/* Meaning: Select to disable background processing */
|
||||
/* #define CONFIG_DISABLE_BACKGROUND */
|
||||
|
||||
|
||||
/* Default: Selected */
|
||||
/* Meaning: Enable XATTR support */
|
||||
#define CONFIG_YAFFS_XATTR
|
||||
|
||||
/*
|
||||
Older-style on-NAND data format has a "pageStatus" byte to record
|
||||
Older-style on-NAND data format has a "page_status" byte to record
|
||||
chunk/page state. This byte is zeroed when the page is discarded.
|
||||
Choose this option if you have existing on-NAND data in this format
|
||||
that you need to continue to support. New data written also uses the
|
||||
@ -78,7 +77,7 @@ adjusted to use the older-style format. See notes on tags formats and
|
||||
MTD versions in yaffs_mtdif1.c.
|
||||
*/
|
||||
/* Default: Not selected */
|
||||
/* Meaning: Use older-style on-NAND data format with pageStatus byte */
|
||||
/* Meaning: Use older-style on-NAND data format with page_status byte */
|
||||
/* #define CONFIG_YAFFS_9BYTE_TAGS */
|
||||
|
||||
#endif /* YAFFS_OUT_OF_TREE */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2010 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
@ -7,13 +7,10 @@
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
|
||||
#include "yaffs_allocator.h"
|
||||
#include "yaffs_guts.h"
|
||||
#include "yaffs_trace.h"
|
||||
@ -21,45 +18,44 @@
|
||||
|
||||
#ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR
|
||||
|
||||
void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
|
||||
void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
|
||||
{
|
||||
dev = dev;
|
||||
}
|
||||
|
||||
void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
|
||||
void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
|
||||
{
|
||||
dev = dev;
|
||||
}
|
||||
|
||||
yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
|
||||
struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
|
||||
{
|
||||
return (yaffs_Tnode *)YMALLOC(dev->tnodeSize);
|
||||
return (struct yaffs_tnode *)YMALLOC(dev->tnode_size);
|
||||
}
|
||||
|
||||
void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
|
||||
void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
|
||||
{
|
||||
dev = dev;
|
||||
YFREE(tn);
|
||||
}
|
||||
|
||||
void yaffs_InitialiseRawObjects(yaffs_Device *dev)
|
||||
void yaffs_init_raw_objs(struct yaffs_dev *dev)
|
||||
{
|
||||
dev = dev;
|
||||
}
|
||||
|
||||
void yaffs_DeinitialiseRawObjects(yaffs_Device *dev)
|
||||
void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
|
||||
{
|
||||
dev = dev;
|
||||
}
|
||||
|
||||
yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
|
||||
struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
|
||||
{
|
||||
dev = dev;
|
||||
return (yaffs_Object *) YMALLOC(sizeof(yaffs_Object));
|
||||
return (struct yaffs_obj *)YMALLOC(sizeof(struct yaffs_obj));
|
||||
}
|
||||
|
||||
|
||||
void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
|
||||
void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
|
||||
{
|
||||
|
||||
dev = dev;
|
||||
@ -68,135 +64,128 @@ void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
|
||||
|
||||
#else
|
||||
|
||||
struct yaffs_TnodeList_struct {
|
||||
struct yaffs_TnodeList_struct *next;
|
||||
yaffs_Tnode *tnodes;
|
||||
struct yaffs_tnode_list {
|
||||
struct yaffs_tnode_list *next;
|
||||
struct yaffs_tnode *tnodes;
|
||||
};
|
||||
|
||||
typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
|
||||
|
||||
struct yaffs_ObjectList_struct {
|
||||
yaffs_Object *objects;
|
||||
struct yaffs_ObjectList_struct *next;
|
||||
struct yaffs_obj_list {
|
||||
struct yaffs_obj_list *next;
|
||||
struct yaffs_obj *objects;
|
||||
};
|
||||
|
||||
typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
|
||||
struct yaffs_allocator {
|
||||
int n_tnodes_created;
|
||||
struct yaffs_tnode *free_tnodes;
|
||||
int n_free_tnodes;
|
||||
struct yaffs_tnode_list *alloc_tnode_list;
|
||||
|
||||
int n_obj_created;
|
||||
struct yaffs_obj *free_objs;
|
||||
int n_free_objects;
|
||||
|
||||
struct yaffs_AllocatorStruct {
|
||||
int nTnodesCreated;
|
||||
yaffs_Tnode *freeTnodes;
|
||||
int nFreeTnodes;
|
||||
yaffs_TnodeList *allocatedTnodeList;
|
||||
|
||||
int nObjectsCreated;
|
||||
yaffs_Object *freeObjects;
|
||||
int nFreeObjects;
|
||||
|
||||
yaffs_ObjectList *allocatedObjectList;
|
||||
struct yaffs_obj_list *allocated_obj_list;
|
||||
};
|
||||
|
||||
typedef struct yaffs_AllocatorStruct yaffs_Allocator;
|
||||
|
||||
|
||||
static void yaffs_DeinitialiseRawTnodes(yaffs_Device *dev)
|
||||
static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
|
||||
{
|
||||
|
||||
yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
|
||||
struct yaffs_allocator *allocator =
|
||||
(struct yaffs_allocator *)dev->allocator;
|
||||
|
||||
yaffs_TnodeList *tmp;
|
||||
struct yaffs_tnode_list *tmp;
|
||||
|
||||
if(!allocator){
|
||||
if (!allocator) {
|
||||
YBUG();
|
||||
return;
|
||||
}
|
||||
|
||||
while (allocator->allocatedTnodeList) {
|
||||
tmp = allocator->allocatedTnodeList->next;
|
||||
while (allocator->alloc_tnode_list) {
|
||||
tmp = allocator->alloc_tnode_list->next;
|
||||
|
||||
YFREE(allocator->allocatedTnodeList->tnodes);
|
||||
YFREE(allocator->allocatedTnodeList);
|
||||
allocator->allocatedTnodeList = tmp;
|
||||
YFREE(allocator->alloc_tnode_list->tnodes);
|
||||
YFREE(allocator->alloc_tnode_list);
|
||||
allocator->alloc_tnode_list = tmp;
|
||||
|
||||
}
|
||||
|
||||
allocator->freeTnodes = NULL;
|
||||
allocator->nFreeTnodes = 0;
|
||||
allocator->nTnodesCreated = 0;
|
||||
allocator->free_tnodes = NULL;
|
||||
allocator->n_free_tnodes = 0;
|
||||
allocator->n_tnodes_created = 0;
|
||||
}
|
||||
|
||||
static void yaffs_InitialiseRawTnodes(yaffs_Device *dev)
|
||||
static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
|
||||
{
|
||||
yaffs_Allocator *allocator = dev->allocator;
|
||||
struct yaffs_allocator *allocator = dev->allocator;
|
||||
|
||||
if(allocator){
|
||||
allocator->allocatedTnodeList = NULL;
|
||||
allocator->freeTnodes = NULL;
|
||||
allocator->nFreeTnodes = 0;
|
||||
allocator->nTnodesCreated = 0;
|
||||
if (allocator) {
|
||||
allocator->alloc_tnode_list = NULL;
|
||||
allocator->free_tnodes = NULL;
|
||||
allocator->n_free_tnodes = 0;
|
||||
allocator->n_tnodes_created = 0;
|
||||
} else
|
||||
YBUG();
|
||||
}
|
||||
|
||||
static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
|
||||
static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
|
||||
{
|
||||
yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
|
||||
struct yaffs_allocator *allocator =
|
||||
(struct yaffs_allocator *)dev->allocator;
|
||||
int i;
|
||||
yaffs_Tnode *newTnodes;
|
||||
__u8 *mem;
|
||||
yaffs_Tnode *curr;
|
||||
yaffs_Tnode *next;
|
||||
yaffs_TnodeList *tnl;
|
||||
struct yaffs_tnode *new_tnodes;
|
||||
u8 *mem;
|
||||
struct yaffs_tnode *curr;
|
||||
struct yaffs_tnode *next;
|
||||
struct yaffs_tnode_list *tnl;
|
||||
|
||||
if(!allocator){
|
||||
if (!allocator) {
|
||||
YBUG();
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
if (nTnodes < 1)
|
||||
if (n_tnodes < 1)
|
||||
return YAFFS_OK;
|
||||
|
||||
|
||||
/* make these things */
|
||||
|
||||
newTnodes = YMALLOC(nTnodes * dev->tnodeSize);
|
||||
mem = (__u8 *)newTnodes;
|
||||
new_tnodes = YMALLOC(n_tnodes * dev->tnode_size);
|
||||
mem = (u8 *) new_tnodes;
|
||||
|
||||
if (!newTnodes) {
|
||||
if (!new_tnodes) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
|
||||
(TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
/* New hookup for wide tnodes */
|
||||
for (i = 0; i < nTnodes - 1; i++) {
|
||||
curr = (yaffs_Tnode *) &mem[i * dev->tnodeSize];
|
||||
next = (yaffs_Tnode *) &mem[(i+1) * dev->tnodeSize];
|
||||
for (i = 0; i < n_tnodes - 1; i++) {
|
||||
curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
|
||||
next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
|
||||
curr->internal[0] = next;
|
||||
}
|
||||
|
||||
curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * dev->tnodeSize];
|
||||
curr->internal[0] = allocator->freeTnodes;
|
||||
allocator->freeTnodes = (yaffs_Tnode *)mem;
|
||||
curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
|
||||
curr->internal[0] = allocator->free_tnodes;
|
||||
allocator->free_tnodes = (struct yaffs_tnode *)mem;
|
||||
|
||||
allocator->nFreeTnodes += nTnodes;
|
||||
allocator->nTnodesCreated += nTnodes;
|
||||
allocator->n_free_tnodes += n_tnodes;
|
||||
allocator->n_tnodes_created += n_tnodes;
|
||||
|
||||
/* Now add this bunch of tnodes to a list for freeing up.
|
||||
* NB If we can't add this to the management list it isn't fatal
|
||||
* but it just means we can't free this bunch of tnodes later.
|
||||
*/
|
||||
|
||||
tnl = YMALLOC(sizeof(yaffs_TnodeList));
|
||||
tnl = YMALLOC(sizeof(struct yaffs_tnode_list));
|
||||
if (!tnl) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("yaffs: Could not add tnodes to management list" TENDSTR)));
|
||||
return YAFFS_FAIL;
|
||||
return YAFFS_FAIL;
|
||||
} else {
|
||||
tnl->tnodes = newTnodes;
|
||||
tnl->next = allocator->allocatedTnodeList;
|
||||
allocator->allocatedTnodeList = tnl;
|
||||
tnl->tnodes = new_tnodes;
|
||||
tnl->next = allocator->alloc_tnode_list;
|
||||
allocator->alloc_tnode_list = tnl;
|
||||
}
|
||||
|
||||
T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
|
||||
@ -204,112 +193,109 @@ static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
|
||||
yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
|
||||
struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
|
||||
{
|
||||
yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
|
||||
yaffs_Tnode *tn = NULL;
|
||||
struct yaffs_allocator *allocator =
|
||||
(struct yaffs_allocator *)dev->allocator;
|
||||
struct yaffs_tnode *tn = NULL;
|
||||
|
||||
if(!allocator){
|
||||
if (!allocator) {
|
||||
YBUG();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If there are none left make more */
|
||||
if (!allocator->freeTnodes)
|
||||
yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
|
||||
if (!allocator->free_tnodes)
|
||||
yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
|
||||
|
||||
if (allocator->freeTnodes) {
|
||||
tn = allocator->freeTnodes;
|
||||
allocator->freeTnodes = allocator->freeTnodes->internal[0];
|
||||
allocator->nFreeTnodes--;
|
||||
if (allocator->free_tnodes) {
|
||||
tn = allocator->free_tnodes;
|
||||
allocator->free_tnodes = allocator->free_tnodes->internal[0];
|
||||
allocator->n_free_tnodes--;
|
||||
}
|
||||
|
||||
return tn;
|
||||
}
|
||||
|
||||
/* FreeTnode frees up a tnode and puts it back on the free list */
|
||||
void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
|
||||
void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
|
||||
{
|
||||
yaffs_Allocator *allocator = dev->allocator;
|
||||
struct yaffs_allocator *allocator = dev->allocator;
|
||||
|
||||
if(!allocator){
|
||||
if (!allocator) {
|
||||
YBUG();
|
||||
return;
|
||||
}
|
||||
|
||||
if (tn) {
|
||||
tn->internal[0] = allocator->freeTnodes;
|
||||
allocator->freeTnodes = tn;
|
||||
allocator->nFreeTnodes++;
|
||||
tn->internal[0] = allocator->free_tnodes;
|
||||
allocator->free_tnodes = tn;
|
||||
allocator->n_free_tnodes++;
|
||||
}
|
||||
dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
|
||||
dev->checkpoint_blocks_required = 0; /* force recalculation */
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void yaffs_InitialiseRawObjects(yaffs_Device *dev)
|
||||
static void yaffs_init_raw_objs(struct yaffs_dev *dev)
|
||||
{
|
||||
yaffs_Allocator *allocator = dev->allocator;
|
||||
struct yaffs_allocator *allocator = dev->allocator;
|
||||
|
||||
if(allocator) {
|
||||
allocator->allocatedObjectList = NULL;
|
||||
allocator->freeObjects = NULL;
|
||||
allocator->nFreeObjects = 0;
|
||||
if (allocator) {
|
||||
allocator->allocated_obj_list = NULL;
|
||||
allocator->free_objs = NULL;
|
||||
allocator->n_free_objects = 0;
|
||||
} else
|
||||
YBUG();
|
||||
}
|
||||
|
||||
static void yaffs_DeinitialiseRawObjects(yaffs_Device *dev)
|
||||
static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
|
||||
{
|
||||
yaffs_Allocator *allocator = dev->allocator;
|
||||
yaffs_ObjectList *tmp;
|
||||
struct yaffs_allocator *allocator = dev->allocator;
|
||||
struct yaffs_obj_list *tmp;
|
||||
|
||||
if(!allocator){
|
||||
if (!allocator) {
|
||||
YBUG();
|
||||
return;
|
||||
}
|
||||
|
||||
while (allocator->allocatedObjectList) {
|
||||
tmp = allocator->allocatedObjectList->next;
|
||||
YFREE(allocator->allocatedObjectList->objects);
|
||||
YFREE(allocator->allocatedObjectList);
|
||||
while (allocator->allocated_obj_list) {
|
||||
tmp = allocator->allocated_obj_list->next;
|
||||
YFREE(allocator->allocated_obj_list->objects);
|
||||
YFREE(allocator->allocated_obj_list);
|
||||
|
||||
allocator->allocatedObjectList = tmp;
|
||||
allocator->allocated_obj_list = tmp;
|
||||
}
|
||||
|
||||
allocator->freeObjects = NULL;
|
||||
allocator->nFreeObjects = 0;
|
||||
allocator->nObjectsCreated = 0;
|
||||
allocator->free_objs = NULL;
|
||||
allocator->n_free_objects = 0;
|
||||
allocator->n_obj_created = 0;
|
||||
}
|
||||
|
||||
|
||||
static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
|
||||
static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
|
||||
{
|
||||
yaffs_Allocator *allocator = dev->allocator;
|
||||
struct yaffs_allocator *allocator = dev->allocator;
|
||||
|
||||
int i;
|
||||
yaffs_Object *newObjects;
|
||||
yaffs_ObjectList *list;
|
||||
struct yaffs_obj *new_objs;
|
||||
struct yaffs_obj_list *list;
|
||||
|
||||
if(!allocator){
|
||||
if (!allocator) {
|
||||
YBUG();
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
if (nObjects < 1)
|
||||
if (n_obj < 1)
|
||||
return YAFFS_OK;
|
||||
|
||||
/* make these things */
|
||||
newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
|
||||
list = YMALLOC(sizeof(yaffs_ObjectList));
|
||||
new_objs = YMALLOC(n_obj * sizeof(struct yaffs_obj));
|
||||
list = YMALLOC(sizeof(struct yaffs_obj_list));
|
||||
|
||||
if (!newObjects || !list) {
|
||||
if (newObjects){
|
||||
YFREE(newObjects);
|
||||
newObjects = NULL;
|
||||
if (!new_objs || !list) {
|
||||
if (new_objs) {
|
||||
YFREE(new_objs);
|
||||
new_objs = NULL;
|
||||
}
|
||||
if (list){
|
||||
if (list) {
|
||||
YFREE(list);
|
||||
list = NULL;
|
||||
}
|
||||
@ -319,91 +305,89 @@ static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
|
||||
}
|
||||
|
||||
/* Hook them into the free list */
|
||||
for (i = 0; i < nObjects - 1; i++) {
|
||||
newObjects[i].siblings.next =
|
||||
(struct ylist_head *)(&newObjects[i + 1]);
|
||||
for (i = 0; i < n_obj - 1; i++) {
|
||||
new_objs[i].siblings.next =
|
||||
(struct list_head *)(&new_objs[i + 1]);
|
||||
}
|
||||
|
||||
newObjects[nObjects - 1].siblings.next = (void *)allocator->freeObjects;
|
||||
allocator->freeObjects = newObjects;
|
||||
allocator->nFreeObjects += nObjects;
|
||||
allocator->nObjectsCreated += nObjects;
|
||||
new_objs[n_obj - 1].siblings.next = (void *)allocator->free_objs;
|
||||
allocator->free_objs = new_objs;
|
||||
allocator->n_free_objects += n_obj;
|
||||
allocator->n_obj_created += n_obj;
|
||||
|
||||
/* Now add this bunch of Objects to a list for freeing up. */
|
||||
|
||||
list->objects = newObjects;
|
||||
list->next = allocator->allocatedObjectList;
|
||||
allocator->allocatedObjectList = list;
|
||||
list->objects = new_objs;
|
||||
list->next = allocator->allocated_obj_list;
|
||||
allocator->allocated_obj_list = list;
|
||||
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
|
||||
struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
|
||||
{
|
||||
yaffs_Object *obj = NULL;
|
||||
yaffs_Allocator *allocator = dev->allocator;
|
||||
struct yaffs_obj *obj = NULL;
|
||||
struct yaffs_allocator *allocator = dev->allocator;
|
||||
|
||||
if(!allocator) {
|
||||
if (!allocator) {
|
||||
YBUG();
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* If there are none left make more */
|
||||
if (!allocator->freeObjects)
|
||||
yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
|
||||
if (!allocator->free_objs)
|
||||
yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
|
||||
|
||||
if (allocator->freeObjects) {
|
||||
obj = allocator->freeObjects;
|
||||
allocator->freeObjects =
|
||||
(yaffs_Object *) (allocator->freeObjects->siblings.next);
|
||||
allocator->nFreeObjects--;
|
||||
if (allocator->free_objs) {
|
||||
obj = allocator->free_objs;
|
||||
allocator->free_objs =
|
||||
(struct yaffs_obj *)(allocator->free_objs->siblings.next);
|
||||
allocator->n_free_objects--;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
|
||||
void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
|
||||
{
|
||||
|
||||
yaffs_Allocator *allocator = dev->allocator;
|
||||
struct yaffs_allocator *allocator = dev->allocator;
|
||||
|
||||
if(!allocator)
|
||||
if (!allocator)
|
||||
YBUG();
|
||||
else {
|
||||
/* Link into the free list. */
|
||||
obj->siblings.next = (struct ylist_head *)(allocator->freeObjects);
|
||||
allocator->freeObjects = obj;
|
||||
allocator->nFreeObjects++;
|
||||
obj->siblings.next = (struct list_head *)(allocator->free_objs);
|
||||
allocator->free_objs = obj;
|
||||
allocator->n_free_objects++;
|
||||
}
|
||||
}
|
||||
|
||||
void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
|
||||
void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
|
||||
{
|
||||
if(dev->allocator){
|
||||
yaffs_DeinitialiseRawTnodes(dev);
|
||||
yaffs_DeinitialiseRawObjects(dev);
|
||||
if (dev->allocator) {
|
||||
yaffs_deinit_raw_tnodes(dev);
|
||||
yaffs_deinit_raw_objs(dev);
|
||||
|
||||
YFREE(dev->allocator);
|
||||
dev->allocator=NULL;
|
||||
dev->allocator = NULL;
|
||||
} else
|
||||
YBUG();
|
||||
}
|
||||
|
||||
void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
|
||||
void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
|
||||
{
|
||||
yaffs_Allocator *allocator;
|
||||
struct yaffs_allocator *allocator;
|
||||
|
||||
if(!dev->allocator){
|
||||
allocator = YMALLOC(sizeof(yaffs_Allocator));
|
||||
if(allocator){
|
||||
if (!dev->allocator) {
|
||||
allocator = YMALLOC(sizeof(struct yaffs_allocator));
|
||||
if (allocator) {
|
||||
dev->allocator = allocator;
|
||||
yaffs_InitialiseRawTnodes(dev);
|
||||
yaffs_InitialiseRawObjects(dev);
|
||||
yaffs_init_raw_tnodes(dev);
|
||||
yaffs_init_raw_objs(dev);
|
||||
}
|
||||
} else
|
||||
YBUG();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -18,13 +18,13 @@
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev);
|
||||
void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev);
|
||||
void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
|
||||
void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
|
||||
|
||||
yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev);
|
||||
void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn);
|
||||
struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
|
||||
void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
|
||||
|
||||
yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev);
|
||||
void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj);
|
||||
struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
|
||||
void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
|
||||
|
||||
#endif
|
||||
|
124
fs/yaffs2/yaffs_attribs.c
Normal file
124
fs/yaffs2/yaffs_attribs.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2010 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
#include "yaffs_attribs.h"
|
||||
|
||||
void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
|
||||
{
|
||||
obj->yst_uid = oh->yst_uid;
|
||||
obj->yst_gid = oh->yst_gid;
|
||||
obj->yst_atime = oh->yst_atime;
|
||||
obj->yst_mtime = oh->yst_mtime;
|
||||
obj->yst_ctime = oh->yst_ctime;
|
||||
obj->yst_rdev = oh->yst_rdev;
|
||||
}
|
||||
|
||||
void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
|
||||
{
|
||||
oh->yst_uid = obj->yst_uid;
|
||||
oh->yst_gid = obj->yst_gid;
|
||||
oh->yst_atime = obj->yst_atime;
|
||||
oh->yst_mtime = obj->yst_mtime;
|
||||
oh->yst_ctime = obj->yst_ctime;
|
||||
oh->yst_rdev = obj->yst_rdev;
|
||||
|
||||
}
|
||||
|
||||
void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
|
||||
{
|
||||
obj->yst_mtime = Y_CURRENT_TIME;
|
||||
if (do_a)
|
||||
obj->yst_atime = obj->yst_atime;
|
||||
if (do_c)
|
||||
obj->yst_ctime = obj->yst_atime;
|
||||
}
|
||||
|
||||
void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
|
||||
{
|
||||
yaffs_load_current_time(obj, 1, 1);
|
||||
obj->yst_rdev = rdev;
|
||||
obj->yst_uid = uid;
|
||||
obj->yst_gid = gid;
|
||||
}
|
||||
|
||||
loff_t yaffs_get_file_size(struct yaffs_obj *obj)
|
||||
{
|
||||
YCHAR *alias = NULL;
|
||||
obj = yaffs_get_equivalent_obj(obj);
|
||||
|
||||
switch (obj->variant_type) {
|
||||
case YAFFS_OBJECT_TYPE_FILE:
|
||||
return obj->variant.file_variant.file_size;
|
||||
case YAFFS_OBJECT_TYPE_SYMLINK:
|
||||
alias = obj->variant.symlink_variant.alias;
|
||||
if (!alias)
|
||||
return 0;
|
||||
return yaffs_strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
|
||||
{
|
||||
unsigned int valid = attr->ia_valid;
|
||||
|
||||
if (valid & ATTR_MODE)
|
||||
obj->yst_mode = attr->ia_mode;
|
||||
if (valid & ATTR_UID)
|
||||
obj->yst_uid = attr->ia_uid;
|
||||
if (valid & ATTR_GID)
|
||||
obj->yst_gid = attr->ia_gid;
|
||||
|
||||
if (valid & ATTR_ATIME)
|
||||
obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
|
||||
if (valid & ATTR_CTIME)
|
||||
obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
|
||||
if (valid & ATTR_MTIME)
|
||||
obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
|
||||
|
||||
if (valid & ATTR_SIZE)
|
||||
yaffs_resize_file(obj, attr->ia_size);
|
||||
|
||||
yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
|
||||
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
|
||||
int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
|
||||
{
|
||||
unsigned int valid = 0;
|
||||
|
||||
attr->ia_mode = obj->yst_mode;
|
||||
valid |= ATTR_MODE;
|
||||
attr->ia_uid = obj->yst_uid;
|
||||
valid |= ATTR_UID;
|
||||
attr->ia_gid = obj->yst_gid;
|
||||
valid |= ATTR_GID;
|
||||
|
||||
Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
|
||||
valid |= ATTR_ATIME;
|
||||
Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
|
||||
valid |= ATTR_CTIME;
|
||||
Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
|
||||
valid |= ATTR_MTIME;
|
||||
|
||||
attr->ia_size = yaffs_get_file_size(obj);
|
||||
valid |= ATTR_SIZE;
|
||||
|
||||
attr->ia_valid = valid;
|
||||
|
||||
return YAFFS_OK;
|
||||
}
|
@ -13,22 +13,16 @@
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_ATTRIBS_H__
|
||||
#define __YAFFS_ATTRIBS_H__
|
||||
|
||||
#ifndef __YAFFS_QSORT_H__
|
||||
#define __YAFFS_QSORT_H__
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/sort.h>
|
||||
|
||||
extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
|
||||
int (*cmp)(const void *, const void *)){
|
||||
sort(base, total_elems, size, cmp, NULL);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
|
||||
int (*cmp)(const void *, const void *));
|
||||
void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
|
||||
void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
|
||||
void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
|
||||
void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
|
||||
int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
|
||||
int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
|
||||
|
||||
#endif
|
||||
#endif
|
@ -17,89 +17,88 @@
|
||||
* Chunk bitmap manipulations
|
||||
*/
|
||||
|
||||
static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
|
||||
static Y_INLINE u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
|
||||
{
|
||||
if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
|
||||
if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
|
||||
blk));
|
||||
(TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
|
||||
blk));
|
||||
YBUG();
|
||||
}
|
||||
return dev->chunkBits +
|
||||
(dev->chunkBitmapStride * (blk - dev->internalStartBlock));
|
||||
return dev->chunk_bits +
|
||||
(dev->chunk_bit_stride * (blk - dev->internal_start_block));
|
||||
}
|
||||
|
||||
void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
|
||||
void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
|
||||
{
|
||||
if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
|
||||
chunk < 0 || chunk >= dev->param.nChunksPerBlock) {
|
||||
if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
|
||||
chunk < 0 || chunk >= dev->param.chunks_per_block) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
|
||||
blk, chunk));
|
||||
(TSTR("**>> yaffs: Chunk Id (%d:%d) invalid" TENDSTR),
|
||||
blk, chunk));
|
||||
YBUG();
|
||||
}
|
||||
}
|
||||
|
||||
void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
|
||||
void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
|
||||
{
|
||||
__u8 *blkBits = yaffs_BlockBits(dev, blk);
|
||||
u8 *blk_bits = yaffs_block_bits(dev, blk);
|
||||
|
||||
memset(blkBits, 0, dev->chunkBitmapStride);
|
||||
memset(blk_bits, 0, dev->chunk_bit_stride);
|
||||
}
|
||||
|
||||
void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
|
||||
void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
|
||||
{
|
||||
__u8 *blkBits = yaffs_BlockBits(dev, blk);
|
||||
u8 *blk_bits = yaffs_block_bits(dev, blk);
|
||||
|
||||
yaffs_VerifyChunkBitId(dev, blk, chunk);
|
||||
yaffs_verify_chunk_bit_id(dev, blk, chunk);
|
||||
|
||||
blkBits[chunk / 8] &= ~(1 << (chunk & 7));
|
||||
blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
|
||||
}
|
||||
|
||||
void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
|
||||
void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
|
||||
{
|
||||
__u8 *blkBits = yaffs_BlockBits(dev, blk);
|
||||
u8 *blk_bits = yaffs_block_bits(dev, blk);
|
||||
|
||||
yaffs_VerifyChunkBitId(dev, blk, chunk);
|
||||
yaffs_verify_chunk_bit_id(dev, blk, chunk);
|
||||
|
||||
blkBits[chunk / 8] |= (1 << (chunk & 7));
|
||||
blk_bits[chunk / 8] |= (1 << (chunk & 7));
|
||||
}
|
||||
|
||||
int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
|
||||
int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
|
||||
{
|
||||
__u8 *blkBits = yaffs_BlockBits(dev, blk);
|
||||
yaffs_VerifyChunkBitId(dev, blk, chunk);
|
||||
u8 *blk_bits = yaffs_block_bits(dev, blk);
|
||||
yaffs_verify_chunk_bit_id(dev, blk, chunk);
|
||||
|
||||
return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
|
||||
return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
|
||||
}
|
||||
|
||||
int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
|
||||
int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
|
||||
{
|
||||
__u8 *blkBits = yaffs_BlockBits(dev, blk);
|
||||
u8 *blk_bits = yaffs_block_bits(dev, blk);
|
||||
int i;
|
||||
for (i = 0; i < dev->chunkBitmapStride; i++) {
|
||||
if (*blkBits)
|
||||
for (i = 0; i < dev->chunk_bit_stride; i++) {
|
||||
if (*blk_bits)
|
||||
return 1;
|
||||
blkBits++;
|
||||
blk_bits++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
|
||||
int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
|
||||
{
|
||||
__u8 *blkBits = yaffs_BlockBits(dev, blk);
|
||||
u8 *blk_bits = yaffs_block_bits(dev, blk);
|
||||
int i;
|
||||
int n = 0;
|
||||
for (i = 0; i < dev->chunkBitmapStride; i++) {
|
||||
__u8 x = *blkBits;
|
||||
for (i = 0; i < dev->chunk_bit_stride; i++) {
|
||||
u8 x = *blk_bits;
|
||||
while (x) {
|
||||
if (x & 1)
|
||||
n++;
|
||||
x >>= 1;
|
||||
}
|
||||
|
||||
blkBits++;
|
||||
blk_bits++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2010 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
@ -7,8 +7,10 @@
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -20,12 +22,12 @@
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk);
|
||||
void yaffs_ClearChunkBits(yaffs_Device *dev, int blk);
|
||||
void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk);
|
||||
void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk);
|
||||
int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk);
|
||||
int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk);
|
||||
int yaffs_CountChunkBits(yaffs_Device *dev, int blk);
|
||||
void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
|
||||
void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
|
||||
void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
|
||||
void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
|
||||
int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
|
||||
int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
|
||||
int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
|
||||
|
||||
#endif
|
||||
|
@ -14,388 +14,406 @@
|
||||
#include "yaffs_checkptrw.h"
|
||||
#include "yaffs_getblockinfo.h"
|
||||
|
||||
static int yaffs2_CheckpointSpaceOk(yaffs_Device *dev)
|
||||
static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
|
||||
{
|
||||
int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks;
|
||||
int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
|
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT,
|
||||
(TSTR("checkpt blocks available = %d" TENDSTR),
|
||||
blocksAvailable));
|
||||
(TSTR("checkpt blocks available = %d" TENDSTR), blocks_avail));
|
||||
|
||||
return (blocksAvailable <= 0) ? 0 : 1;
|
||||
return (blocks_avail <= 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
static int yaffs2_CheckpointErase(yaffs_Device *dev)
|
||||
static int yaffs_checkpt_erase(struct yaffs_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!dev->param.eraseBlockInNAND)
|
||||
if (!dev->param.erase_fn)
|
||||
return 0;
|
||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR),
|
||||
dev->internalStartBlock, dev->internalEndBlock));
|
||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d" TENDSTR),
|
||||
dev->internal_start_block,
|
||||
dev->internal_end_block));
|
||||
|
||||
for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
|
||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
|
||||
if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
|
||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
|
||||
for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
|
||||
struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
|
||||
if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
|
||||
T(YAFFS_TRACE_CHECKPOINT,
|
||||
(TSTR("erasing checkpt block %d" TENDSTR), i));
|
||||
|
||||
dev->nBlockErasures++;
|
||||
dev->n_erasures++;
|
||||
|
||||
if (dev->param.eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
|
||||
bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
|
||||
dev->nErasedBlocks++;
|
||||
dev->nFreeChunks += dev->param.nChunksPerBlock;
|
||||
if (dev->param.
|
||||
erase_fn(dev,
|
||||
i - dev->block_offset /* realign */ )) {
|
||||
bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
|
||||
dev->n_erased_blocks++;
|
||||
dev->n_free_chunks +=
|
||||
dev->param.chunks_per_block;
|
||||
} else {
|
||||
dev->param.markNANDBlockBad(dev, i);
|
||||
bi->blockState = YAFFS_BLOCK_STATE_DEAD;
|
||||
dev->param.bad_block_fn(dev, i);
|
||||
bi->block_state = YAFFS_BLOCK_STATE_DEAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dev->blocksInCheckpoint = 0;
|
||||
dev->blocks_in_checkpt = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void yaffs2_CheckpointFindNextErasedBlock(yaffs_Device *dev)
|
||||
static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
|
||||
{
|
||||
int i;
|
||||
int blocksAvailable = dev->nErasedBlocks - dev->param.nReservedBlocks;
|
||||
int i;
|
||||
int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
|
||||
T(YAFFS_TRACE_CHECKPOINT,
|
||||
(TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
|
||||
dev->nErasedBlocks, dev->param.nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
|
||||
(TSTR
|
||||
("allocating checkpt block: erased %d reserved %d avail %d next %d "
|
||||
TENDSTR), dev->n_erased_blocks, dev->param.n_reserved_blocks,
|
||||
blocks_avail, dev->checkpt_next_block));
|
||||
|
||||
if (dev->checkpointNextBlock >= 0 &&
|
||||
dev->checkpointNextBlock <= dev->internalEndBlock &&
|
||||
blocksAvailable > 0) {
|
||||
if (dev->checkpt_next_block >= 0 &&
|
||||
dev->checkpt_next_block <= dev->internal_end_block &&
|
||||
blocks_avail > 0) {
|
||||
|
||||
for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
|
||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
|
||||
if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
|
||||
dev->checkpointNextBlock = i + 1;
|
||||
dev->checkpointCurrentBlock = i;
|
||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block %d"TENDSTR), i));
|
||||
for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
|
||||
i++) {
|
||||
struct yaffs_block_info *bi =
|
||||
yaffs_get_block_info(dev, i);
|
||||
if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
|
||||
dev->checkpt_next_block = i + 1;
|
||||
dev->checkpt_cur_block = i;
|
||||
T(YAFFS_TRACE_CHECKPOINT,
|
||||
(TSTR("allocating checkpt block %d" TENDSTR),
|
||||
i));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("out of checkpt blocks"TENDSTR)));
|
||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("out of checkpt blocks" TENDSTR)));
|
||||
|
||||
dev->checkpointNextBlock = -1;
|
||||
dev->checkpointCurrentBlock = -1;
|
||||
dev->checkpt_next_block = -1;
|
||||
dev->checkpt_cur_block = -1;
|
||||
}
|
||||
|
||||
static void yaffs2_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
|
||||
static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
|
||||
{
|
||||
int i;
|
||||
yaffs_ExtendedTags tags;
|
||||
int i;
|
||||
struct yaffs_ext_tags tags;
|
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
|
||||
dev->blocksInCheckpoint, dev->checkpointNextBlock));
|
||||
T(YAFFS_TRACE_CHECKPOINT,
|
||||
(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
|
||||
dev->blocks_in_checkpt, dev->checkpt_next_block));
|
||||
|
||||
if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
|
||||
for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
|
||||
int chunk = i * dev->param.nChunksPerBlock;
|
||||
int realignedChunk = chunk - dev->chunkOffset;
|
||||
if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
|
||||
for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
|
||||
i++) {
|
||||
int chunk = i * dev->param.chunks_per_block;
|
||||
int realigned_chunk = chunk - dev->chunk_offset;
|
||||
|
||||
dev->param.readChunkWithTagsFromNAND(dev, realignedChunk,
|
||||
NULL, &tags);
|
||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
|
||||
i, tags.objectId, tags.sequenceNumber, tags.eccResult));
|
||||
dev->param.read_chunk_tags_fn(dev, realigned_chunk,
|
||||
NULL, &tags);
|
||||
T(YAFFS_TRACE_CHECKPOINT,
|
||||
(TSTR
|
||||
("find next checkpt block: search: block %d oid %d seq %d eccr %d"
|
||||
TENDSTR), i, tags.obj_id, tags.seq_number,
|
||||
tags.ecc_result));
|
||||
|
||||
if (tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
|
||||
if (tags.seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
|
||||
/* Right kind of block */
|
||||
dev->checkpointNextBlock = tags.objectId;
|
||||
dev->checkpointCurrentBlock = i;
|
||||
dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
|
||||
dev->blocksInCheckpoint++;
|
||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("found checkpt block %d"TENDSTR), i));
|
||||
dev->checkpt_next_block = tags.obj_id;
|
||||
dev->checkpt_cur_block = i;
|
||||
dev->checkpt_block_list[dev->
|
||||
blocks_in_checkpt] = i;
|
||||
dev->blocks_in_checkpt++;
|
||||
T(YAFFS_TRACE_CHECKPOINT,
|
||||
(TSTR("found checkpt block %d" TENDSTR), i));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("found no more checkpt blocks"TENDSTR)));
|
||||
T(YAFFS_TRACE_CHECKPOINT,
|
||||
(TSTR("found no more checkpt blocks" TENDSTR)));
|
||||
|
||||
dev->checkpointNextBlock = -1;
|
||||
dev->checkpointCurrentBlock = -1;
|
||||
dev->checkpt_next_block = -1;
|
||||
dev->checkpt_cur_block = -1;
|
||||
}
|
||||
|
||||
|
||||
int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting)
|
||||
int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
|
||||
{
|
||||
|
||||
|
||||
dev->checkpointOpenForWrite = forWriting;
|
||||
dev->checkpt_open_write = writing;
|
||||
|
||||
/* Got the functions we need? */
|
||||
if (!dev->param.writeChunkWithTagsToNAND ||
|
||||
!dev->param.readChunkWithTagsFromNAND ||
|
||||
!dev->param.eraseBlockInNAND ||
|
||||
!dev->param.markNANDBlockBad)
|
||||
if (!dev->param.write_chunk_tags_fn ||
|
||||
!dev->param.read_chunk_tags_fn ||
|
||||
!dev->param.erase_fn || !dev->param.bad_block_fn)
|
||||
return 0;
|
||||
|
||||
if (forWriting && !yaffs2_CheckpointSpaceOk(dev))
|
||||
if (writing && !yaffs2_checkpt_space_ok(dev))
|
||||
return 0;
|
||||
|
||||
if (!dev->checkpointBuffer)
|
||||
dev->checkpointBuffer = YMALLOC_DMA(dev->param.totalBytesPerChunk);
|
||||
if (!dev->checkpointBuffer)
|
||||
if (!dev->checkpt_buffer)
|
||||
dev->checkpt_buffer =
|
||||
YMALLOC_DMA(dev->param.total_bytes_per_chunk);
|
||||
if (!dev->checkpt_buffer)
|
||||
return 0;
|
||||
|
||||
|
||||
dev->checkpointPageSequence = 0;
|
||||
dev->checkpointByteCount = 0;
|
||||
dev->checkpointSum = 0;
|
||||
dev->checkpointXor = 0;
|
||||
dev->checkpointCurrentBlock = -1;
|
||||
dev->checkpointCurrentChunk = -1;
|
||||
dev->checkpointNextBlock = dev->internalStartBlock;
|
||||
dev->checkpt_page_seq = 0;
|
||||
dev->checkpt_byte_count = 0;
|
||||
dev->checkpt_sum = 0;
|
||||
dev->checkpt_xor = 0;
|
||||
dev->checkpt_cur_block = -1;
|
||||
dev->checkpt_cur_chunk = -1;
|
||||
dev->checkpt_next_block = dev->internal_start_block;
|
||||
|
||||
/* Erase all the blocks in the checkpoint area */
|
||||
if (forWriting) {
|
||||
memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
|
||||
dev->checkpointByteOffset = 0;
|
||||
return yaffs2_CheckpointErase(dev);
|
||||
if (writing) {
|
||||
memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
|
||||
dev->checkpt_byte_offs = 0;
|
||||
return yaffs_checkpt_erase(dev);
|
||||
} else {
|
||||
int i;
|
||||
/* Set to a value that will kick off a read */
|
||||
dev->checkpointByteOffset = dev->nDataBytesPerChunk;
|
||||
dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
|
||||
/* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
|
||||
* going to be way more than we need */
|
||||
dev->blocksInCheckpoint = 0;
|
||||
dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
|
||||
dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
|
||||
if(!dev->checkpointBlockList)
|
||||
dev->blocks_in_checkpt = 0;
|
||||
dev->checkpt_max_blocks =
|
||||
(dev->internal_end_block - dev->internal_start_block) / 16 +
|
||||
2;
|
||||
dev->checkpt_block_list =
|
||||
YMALLOC(sizeof(int) * dev->checkpt_max_blocks);
|
||||
if (!dev->checkpt_block_list)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < dev->checkpointMaxBlocks; i++)
|
||||
dev->checkpointBlockList[i] = -1;
|
||||
for (i = 0; i < dev->checkpt_max_blocks; i++)
|
||||
dev->checkpt_block_list[i] = -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
|
||||
int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
|
||||
{
|
||||
__u32 compositeSum;
|
||||
compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
|
||||
*sum = compositeSum;
|
||||
u32 composite_sum;
|
||||
composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xFF);
|
||||
*sum = composite_sum;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int yaffs2_CheckpointFlushBuffer(yaffs_Device *dev)
|
||||
static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
|
||||
{
|
||||
int chunk;
|
||||
int realignedChunk;
|
||||
int realigned_chunk;
|
||||
|
||||
yaffs_ExtendedTags tags;
|
||||
struct yaffs_ext_tags tags;
|
||||
|
||||
if (dev->checkpointCurrentBlock < 0) {
|
||||
yaffs2_CheckpointFindNextErasedBlock(dev);
|
||||
dev->checkpointCurrentChunk = 0;
|
||||
if (dev->checkpt_cur_block < 0) {
|
||||
yaffs2_checkpt_find_erased_block(dev);
|
||||
dev->checkpt_cur_chunk = 0;
|
||||
}
|
||||
|
||||
if (dev->checkpointCurrentBlock < 0)
|
||||
if (dev->checkpt_cur_block < 0)
|
||||
return 0;
|
||||
|
||||
tags.chunkDeleted = 0;
|
||||
tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
|
||||
tags.chunkId = dev->checkpointPageSequence + 1;
|
||||
tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA;
|
||||
tags.byteCount = dev->nDataBytesPerChunk;
|
||||
if (dev->checkpointCurrentChunk == 0) {
|
||||
tags.is_deleted = 0;
|
||||
tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
|
||||
tags.chunk_id = dev->checkpt_page_seq + 1;
|
||||
tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
|
||||
tags.n_bytes = dev->data_bytes_per_chunk;
|
||||
if (dev->checkpt_cur_chunk == 0) {
|
||||
/* First chunk we write for the block? Set block state to
|
||||
checkpoint */
|
||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointCurrentBlock);
|
||||
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
|
||||
dev->blocksInCheckpoint++;
|
||||
struct yaffs_block_info *bi =
|
||||
yaffs_get_block_info(dev, dev->checkpt_cur_block);
|
||||
bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
|
||||
dev->blocks_in_checkpt++;
|
||||
}
|
||||
|
||||
chunk = dev->checkpointCurrentBlock * dev->param.nChunksPerBlock + dev->checkpointCurrentChunk;
|
||||
chunk =
|
||||
dev->checkpt_cur_block * dev->param.chunks_per_block +
|
||||
dev->checkpt_cur_chunk;
|
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT,
|
||||
(TSTR
|
||||
("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
|
||||
chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, tags.obj_id,
|
||||
tags.chunk_id));
|
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
|
||||
chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk, tags.objectId, tags.chunkId));
|
||||
realigned_chunk = chunk - dev->chunk_offset;
|
||||
|
||||
realignedChunk = chunk - dev->chunkOffset;
|
||||
dev->n_page_writes++;
|
||||
|
||||
dev->nPageWrites++;
|
||||
|
||||
dev->param.writeChunkWithTagsToNAND(dev, realignedChunk,
|
||||
dev->checkpointBuffer, &tags);
|
||||
dev->checkpointByteOffset = 0;
|
||||
dev->checkpointPageSequence++;
|
||||
dev->checkpointCurrentChunk++;
|
||||
if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock) {
|
||||
dev->checkpointCurrentChunk = 0;
|
||||
dev->checkpointCurrentBlock = -1;
|
||||
dev->param.write_chunk_tags_fn(dev, realigned_chunk,
|
||||
dev->checkpt_buffer, &tags);
|
||||
dev->checkpt_byte_offs = 0;
|
||||
dev->checkpt_page_seq++;
|
||||
dev->checkpt_cur_chunk++;
|
||||
if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
|
||||
dev->checkpt_cur_chunk = 0;
|
||||
dev->checkpt_cur_block = -1;
|
||||
}
|
||||
memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
|
||||
memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
|
||||
int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
|
||||
{
|
||||
int i = 0;
|
||||
int ok = 1;
|
||||
|
||||
u8 *data_bytes = (u8 *) data;
|
||||
|
||||
__u8 * dataBytes = (__u8 *)data;
|
||||
|
||||
|
||||
|
||||
if (!dev->checkpointBuffer)
|
||||
if (!dev->checkpt_buffer)
|
||||
return 0;
|
||||
|
||||
if (!dev->checkpointOpenForWrite)
|
||||
if (!dev->checkpt_open_write)
|
||||
return -1;
|
||||
|
||||
while (i < nBytes && ok) {
|
||||
dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes;
|
||||
dev->checkpointSum += *dataBytes;
|
||||
dev->checkpointXor ^= *dataBytes;
|
||||
while (i < n_bytes && ok) {
|
||||
dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
|
||||
dev->checkpt_sum += *data_bytes;
|
||||
dev->checkpt_xor ^= *data_bytes;
|
||||
|
||||
dev->checkpointByteOffset++;
|
||||
dev->checkpt_byte_offs++;
|
||||
i++;
|
||||
dataBytes++;
|
||||
dev->checkpointByteCount++;
|
||||
data_bytes++;
|
||||
dev->checkpt_byte_count++;
|
||||
|
||||
|
||||
if (dev->checkpointByteOffset < 0 ||
|
||||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
|
||||
ok = yaffs2_CheckpointFlushBuffer(dev);
|
||||
if (dev->checkpt_byte_offs < 0 ||
|
||||
dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
|
||||
ok = yaffs2_checkpt_flush_buffer(dev);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
|
||||
int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
|
||||
{
|
||||
int i = 0;
|
||||
int ok = 1;
|
||||
yaffs_ExtendedTags tags;
|
||||
|
||||
struct yaffs_ext_tags tags;
|
||||
|
||||
int chunk;
|
||||
int realignedChunk;
|
||||
int realigned_chunk;
|
||||
|
||||
__u8 *dataBytes = (__u8 *)data;
|
||||
u8 *data_bytes = (u8 *) data;
|
||||
|
||||
if (!dev->checkpointBuffer)
|
||||
if (!dev->checkpt_buffer)
|
||||
return 0;
|
||||
|
||||
if (dev->checkpointOpenForWrite)
|
||||
if (dev->checkpt_open_write)
|
||||
return -1;
|
||||
|
||||
while (i < nBytes && ok) {
|
||||
while (i < n_bytes && ok) {
|
||||
|
||||
if (dev->checkpt_byte_offs < 0 ||
|
||||
dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
|
||||
|
||||
if (dev->checkpointByteOffset < 0 ||
|
||||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
|
||||
|
||||
if (dev->checkpointCurrentBlock < 0) {
|
||||
yaffs2_CheckpointFindNextCheckpointBlock(dev);
|
||||
dev->checkpointCurrentChunk = 0;
|
||||
if (dev->checkpt_cur_block < 0) {
|
||||
yaffs2_checkpt_find_block(dev);
|
||||
dev->checkpt_cur_chunk = 0;
|
||||
}
|
||||
|
||||
if (dev->checkpointCurrentBlock < 0)
|
||||
if (dev->checkpt_cur_block < 0)
|
||||
ok = 0;
|
||||
else {
|
||||
chunk = dev->checkpointCurrentBlock *
|
||||
dev->param.nChunksPerBlock +
|
||||
dev->checkpointCurrentChunk;
|
||||
chunk = dev->checkpt_cur_block *
|
||||
dev->param.chunks_per_block +
|
||||
dev->checkpt_cur_chunk;
|
||||
|
||||
realignedChunk = chunk - dev->chunkOffset;
|
||||
|
||||
dev->nPageReads++;
|
||||
realigned_chunk = chunk - dev->chunk_offset;
|
||||
|
||||
dev->n_page_reads++;
|
||||
|
||||
/* read in the next chunk */
|
||||
/* printf("read checkpoint page %d\n",dev->checkpointPage); */
|
||||
dev->param.readChunkWithTagsFromNAND(dev,
|
||||
realignedChunk,
|
||||
dev->checkpointBuffer,
|
||||
&tags);
|
||||
dev->param.read_chunk_tags_fn(dev,
|
||||
realigned_chunk,
|
||||
dev->
|
||||
checkpt_buffer,
|
||||
&tags);
|
||||
|
||||
if (tags.chunkId != (dev->checkpointPageSequence + 1) ||
|
||||
tags.eccResult > YAFFS_ECC_RESULT_FIXED ||
|
||||
tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
|
||||
if (tags.chunk_id != (dev->checkpt_page_seq + 1)
|
||||
|| tags.ecc_result > YAFFS_ECC_RESULT_FIXED
|
||||
|| tags.seq_number !=
|
||||
YAFFS_SEQUENCE_CHECKPOINT_DATA)
|
||||
ok = 0;
|
||||
|
||||
dev->checkpointByteOffset = 0;
|
||||
dev->checkpointPageSequence++;
|
||||
dev->checkpointCurrentChunk++;
|
||||
dev->checkpt_byte_offs = 0;
|
||||
dev->checkpt_page_seq++;
|
||||
dev->checkpt_cur_chunk++;
|
||||
|
||||
if (dev->checkpointCurrentChunk >= dev->param.nChunksPerBlock)
|
||||
dev->checkpointCurrentBlock = -1;
|
||||
if (dev->checkpt_cur_chunk >=
|
||||
dev->param.chunks_per_block)
|
||||
dev->checkpt_cur_block = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
*dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
|
||||
dev->checkpointSum += *dataBytes;
|
||||
dev->checkpointXor ^= *dataBytes;
|
||||
dev->checkpointByteOffset++;
|
||||
*data_bytes =
|
||||
dev->checkpt_buffer[dev->checkpt_byte_offs];
|
||||
dev->checkpt_sum += *data_bytes;
|
||||
dev->checkpt_xor ^= *data_bytes;
|
||||
dev->checkpt_byte_offs++;
|
||||
i++;
|
||||
dataBytes++;
|
||||
dev->checkpointByteCount++;
|
||||
data_bytes++;
|
||||
dev->checkpt_byte_count++;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
return i;
|
||||
}
|
||||
|
||||
int yaffs2_CheckpointClose(yaffs_Device *dev)
|
||||
int yaffs_checkpt_close(struct yaffs_dev *dev)
|
||||
{
|
||||
|
||||
if (dev->checkpointOpenForWrite) {
|
||||
if (dev->checkpointByteOffset != 0)
|
||||
yaffs2_CheckpointFlushBuffer(dev);
|
||||
} else if(dev->checkpointBlockList){
|
||||
if (dev->checkpt_open_write) {
|
||||
if (dev->checkpt_byte_offs != 0)
|
||||
yaffs2_checkpt_flush_buffer(dev);
|
||||
} else if (dev->checkpt_block_list) {
|
||||
int i;
|
||||
for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) {
|
||||
int blk = dev->checkpointBlockList[i];
|
||||
yaffs_BlockInfo *bi = NULL;
|
||||
if( dev->internalStartBlock <= blk && blk <= dev->internalEndBlock)
|
||||
bi = yaffs_GetBlockInfo(dev, blk);
|
||||
if (bi && bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
|
||||
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
|
||||
for (i = 0;
|
||||
i < dev->blocks_in_checkpt
|
||||
&& dev->checkpt_block_list[i] >= 0; i++) {
|
||||
int blk = dev->checkpt_block_list[i];
|
||||
struct yaffs_block_info *bi = NULL;
|
||||
if (dev->internal_start_block <= blk
|
||||
&& blk <= dev->internal_end_block)
|
||||
bi = yaffs_get_block_info(dev, blk);
|
||||
if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
|
||||
bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
|
||||
else {
|
||||
/* Todo this looks odd... */
|
||||
}
|
||||
}
|
||||
YFREE(dev->checkpointBlockList);
|
||||
dev->checkpointBlockList = NULL;
|
||||
YFREE(dev->checkpt_block_list);
|
||||
dev->checkpt_block_list = NULL;
|
||||
}
|
||||
|
||||
dev->nFreeChunks -= dev->blocksInCheckpoint * dev->param.nChunksPerBlock;
|
||||
dev->nErasedBlocks -= dev->blocksInCheckpoint;
|
||||
|
||||
dev->n_free_chunks -=
|
||||
dev->blocks_in_checkpt * dev->param.chunks_per_block;
|
||||
dev->n_erased_blocks -= dev->blocks_in_checkpt;
|
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint byte count %d" TENDSTR),
|
||||
dev->checkpointByteCount));
|
||||
dev->checkpt_byte_count));
|
||||
|
||||
if (dev->checkpointBuffer) {
|
||||
if (dev->checkpt_buffer) {
|
||||
/* free the buffer */
|
||||
YFREE(dev->checkpointBuffer);
|
||||
dev->checkpointBuffer = NULL;
|
||||
YFREE(dev->checkpt_buffer);
|
||||
dev->checkpt_buffer = NULL;
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev)
|
||||
int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
|
||||
{
|
||||
/* Erase the checkpoint data */
|
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR),
|
||||
dev->blocksInCheckpoint));
|
||||
T(YAFFS_TRACE_CHECKPOINT,
|
||||
(TSTR("checkpoint invalidate of %d blocks" TENDSTR),
|
||||
dev->blocks_in_checkpt));
|
||||
|
||||
return yaffs2_CheckpointErase(dev);
|
||||
return yaffs_checkpt_erase(dev);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -18,17 +18,16 @@
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
int yaffs2_CheckpointOpen(yaffs_Device *dev, int forWriting);
|
||||
int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
|
||||
|
||||
int yaffs2_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);
|
||||
int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
|
||||
|
||||
int yaffs2_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);
|
||||
int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
|
||||
|
||||
int yaffs2_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
|
||||
int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
|
||||
|
||||
int yaffs2_CheckpointClose(yaffs_Device *dev);
|
||||
|
||||
int yaffs2_CheckpointInvalidateStream(yaffs_Device *dev);
|
||||
int yaffs_checkpt_close(struct yaffs_dev *dev);
|
||||
|
||||
int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
|
||||
|
||||
#endif
|
||||
|
@ -69,7 +69,7 @@ static const unsigned char column_parity_table[] = {
|
||||
|
||||
/* Count the bits in an unsigned char or a U32 */
|
||||
|
||||
static int yaffs_CountBits(unsigned char x)
|
||||
static int yaffs_count_bits(unsigned char x)
|
||||
{
|
||||
int r = 0;
|
||||
while (x) {
|
||||
@ -80,7 +80,7 @@ static int yaffs_CountBits(unsigned char x)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int yaffs_CountBits32(unsigned x)
|
||||
static int yaffs_count_bits32(unsigned x)
|
||||
{
|
||||
int r = 0;
|
||||
while (x) {
|
||||
@ -92,7 +92,7 @@ static int yaffs_CountBits32(unsigned x)
|
||||
}
|
||||
|
||||
/* Calculate the ECC for a 256-byte block of data */
|
||||
void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
|
||||
void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@ -106,7 +106,7 @@ void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
|
||||
b = column_parity_table[*data++];
|
||||
col_parity ^= b;
|
||||
|
||||
if (b & 0x01) { /* odd number of bits in the byte */
|
||||
if (b & 0x01) { /* odd number of bits in the byte */
|
||||
line_parity ^= i;
|
||||
line_parity_prime ^= ~i;
|
||||
}
|
||||
@ -160,11 +160,10 @@ void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Correct the ECC on a 256 byte block of data */
|
||||
|
||||
int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
|
||||
const unsigned char *test_ecc)
|
||||
int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
|
||||
const unsigned char *test_ecc)
|
||||
{
|
||||
unsigned char d0, d1, d2; /* deltas */
|
||||
|
||||
@ -173,7 +172,7 @@ int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
|
||||
d2 = read_ecc[2] ^ test_ecc[2];
|
||||
|
||||
if ((d0 | d1 | d2) == 0)
|
||||
return 0; /* no error */
|
||||
return 0; /* no error */
|
||||
|
||||
if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
|
||||
((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
|
||||
@ -220,19 +219,18 @@ int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
|
||||
|
||||
data[byte] ^= (1 << bit);
|
||||
|
||||
return 1; /* Corrected the error */
|
||||
return 1; /* Corrected the error */
|
||||
}
|
||||
|
||||
if ((yaffs_CountBits(d0) +
|
||||
yaffs_CountBits(d1) +
|
||||
yaffs_CountBits(d2)) == 1) {
|
||||
if ((yaffs_count_bits(d0) +
|
||||
yaffs_count_bits(d1) + yaffs_count_bits(d2)) == 1) {
|
||||
/* Reccoverable error in ecc */
|
||||
|
||||
read_ecc[0] = test_ecc[0];
|
||||
read_ecc[1] = test_ecc[1];
|
||||
read_ecc[2] = test_ecc[2];
|
||||
|
||||
return 1; /* Corrected the error */
|
||||
return 1; /* Corrected the error */
|
||||
}
|
||||
|
||||
/* Unrecoverable error */
|
||||
@ -241,12 +239,11 @@ int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ECCxxxOther does ECC calcs on arbitrary n bytes of data
|
||||
*/
|
||||
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
|
||||
yaffs_ECCOther *eccOther)
|
||||
void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
|
||||
struct yaffs_ecc_other *ecc_other)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@ -255,11 +252,11 @@ void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
|
||||
unsigned line_parity_prime = 0;
|
||||
unsigned char b;
|
||||
|
||||
for (i = 0; i < nBytes; i++) {
|
||||
for (i = 0; i < n_bytes; i++) {
|
||||
b = column_parity_table[*data++];
|
||||
col_parity ^= b;
|
||||
|
||||
if (b & 0x01) {
|
||||
if (b & 0x01) {
|
||||
/* odd number of bits in the byte */
|
||||
line_parity ^= i;
|
||||
line_parity_prime ^= ~i;
|
||||
@ -267,54 +264,56 @@ void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
|
||||
|
||||
}
|
||||
|
||||
eccOther->colParity = (col_parity >> 2) & 0x3f;
|
||||
eccOther->lineParity = line_parity;
|
||||
eccOther->lineParityPrime = line_parity_prime;
|
||||
ecc_other->col_parity = (col_parity >> 2) & 0x3f;
|
||||
ecc_other->line_parity = line_parity;
|
||||
ecc_other->line_parity_prime = line_parity_prime;
|
||||
}
|
||||
|
||||
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
|
||||
yaffs_ECCOther *read_ecc,
|
||||
const yaffs_ECCOther *test_ecc)
|
||||
int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
|
||||
struct yaffs_ecc_other *read_ecc,
|
||||
const struct yaffs_ecc_other *test_ecc)
|
||||
{
|
||||
unsigned char cDelta; /* column parity delta */
|
||||
unsigned lDelta; /* line parity delta */
|
||||
unsigned lDeltaPrime; /* line parity delta */
|
||||
unsigned char delta_col; /* column parity delta */
|
||||
unsigned delta_line; /* line parity delta */
|
||||
unsigned delta_line_prime; /* line parity delta */
|
||||
unsigned bit;
|
||||
|
||||
cDelta = read_ecc->colParity ^ test_ecc->colParity;
|
||||
lDelta = read_ecc->lineParity ^ test_ecc->lineParity;
|
||||
lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;
|
||||
delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
|
||||
delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
|
||||
delta_line_prime =
|
||||
read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
|
||||
|
||||
if ((cDelta | lDelta | lDeltaPrime) == 0)
|
||||
return 0; /* no error */
|
||||
if ((delta_col | delta_line | delta_line_prime) == 0)
|
||||
return 0; /* no error */
|
||||
|
||||
if (lDelta == ~lDeltaPrime &&
|
||||
(((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15)) {
|
||||
if (delta_line == ~delta_line_prime &&
|
||||
(((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
|
||||
/* Single bit (recoverable) error in data */
|
||||
|
||||
bit = 0;
|
||||
|
||||
if (cDelta & 0x20)
|
||||
if (delta_col & 0x20)
|
||||
bit |= 0x04;
|
||||
if (cDelta & 0x08)
|
||||
if (delta_col & 0x08)
|
||||
bit |= 0x02;
|
||||
if (cDelta & 0x02)
|
||||
if (delta_col & 0x02)
|
||||
bit |= 0x01;
|
||||
|
||||
if (lDelta >= nBytes)
|
||||
if (delta_line >= n_bytes)
|
||||
return -1;
|
||||
|
||||
data[lDelta] ^= (1 << bit);
|
||||
data[delta_line] ^= (1 << bit);
|
||||
|
||||
return 1; /* corrected */
|
||||
return 1; /* corrected */
|
||||
}
|
||||
|
||||
if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
|
||||
yaffs_CountBits(cDelta)) == 1) {
|
||||
if ((yaffs_count_bits32(delta_line) +
|
||||
yaffs_count_bits32(delta_line_prime) +
|
||||
yaffs_count_bits(delta_col)) == 1) {
|
||||
/* Reccoverable error in ecc */
|
||||
|
||||
*read_ecc = *test_ecc;
|
||||
return 1; /* corrected */
|
||||
return 1; /* corrected */
|
||||
}
|
||||
|
||||
/* Unrecoverable error */
|
||||
|
@ -26,19 +26,19 @@
|
||||
#ifndef __YAFFS_ECC_H__
|
||||
#define __YAFFS_ECC_H__
|
||||
|
||||
typedef struct {
|
||||
unsigned char colParity;
|
||||
unsigned lineParity;
|
||||
unsigned lineParityPrime;
|
||||
} yaffs_ECCOther;
|
||||
struct yaffs_ecc_other {
|
||||
unsigned char col_parity;
|
||||
unsigned line_parity;
|
||||
unsigned line_parity_prime;
|
||||
};
|
||||
|
||||
void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc);
|
||||
int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
|
||||
const unsigned char *test_ecc);
|
||||
void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc);
|
||||
int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
|
||||
const unsigned char *test_ecc);
|
||||
|
||||
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
|
||||
yaffs_ECCOther *ecc);
|
||||
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
|
||||
yaffs_ECCOther *read_ecc,
|
||||
const yaffs_ECCOther *test_ecc);
|
||||
void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
|
||||
struct yaffs_ecc_other *ecc);
|
||||
int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
|
||||
struct yaffs_ecc_other *read_ecc,
|
||||
const struct yaffs_ecc_other *test_ecc);
|
||||
#endif
|
||||
|
@ -20,16 +20,17 @@
|
||||
#include "yaffs_trace.h"
|
||||
|
||||
/* Function to manipulate block info */
|
||||
static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
|
||||
static Y_INLINE struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
|
||||
*dev, int blk)
|
||||
{
|
||||
if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
|
||||
if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
|
||||
("**>> yaffs: get_block_info block %d is not valid" TENDSTR),
|
||||
blk));
|
||||
YBUG();
|
||||
}
|
||||
return &dev->blockInfo[blk - dev->internalStartBlock];
|
||||
return &dev->block_info[blk - dev->internal_start_block];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -16,28 +16,26 @@
|
||||
#ifndef __YAFFS_LINUX_H__
|
||||
#define __YAFFS_LINUX_H__
|
||||
|
||||
#include "devextras.h"
|
||||
#include "yportenv.h"
|
||||
|
||||
struct yaffs_LinuxContext {
|
||||
struct ylist_head contextList; /* List of these we have mounted */
|
||||
struct yaffs_DeviceStruct *dev;
|
||||
struct super_block * superBlock;
|
||||
struct task_struct *bgThread; /* Background thread for this device */
|
||||
int bgRunning;
|
||||
struct semaphore grossLock; /* Gross locking semaphore */
|
||||
__u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
|
||||
struct yaffs_linux_context {
|
||||
struct list_head context_list; /* List of these we have mounted */
|
||||
struct yaffs_dev *dev;
|
||||
struct super_block *super;
|
||||
struct task_struct *bg_thread; /* Background thread for this device */
|
||||
int bg_running;
|
||||
struct mutex gross_lock; /* Gross locking mutex*/
|
||||
u8 *spare_buffer; /* For mtdif2 use. Don't know the size of the buffer
|
||||
* at compile time so we have to allocate it.
|
||||
*/
|
||||
struct ylist_head searchContexts;
|
||||
void (*putSuperFunc)(struct super_block *sb);
|
||||
struct list_head search_contexts;
|
||||
void (*put_super_fn) (struct super_block * sb);
|
||||
|
||||
struct task_struct *readdirProcess;
|
||||
struct task_struct *readdir_process;
|
||||
unsigned mount_id;
|
||||
};
|
||||
|
||||
#define yaffs_DeviceToLC(dev) ((struct yaffs_LinuxContext *)((dev)->osContext))
|
||||
#define yaffs_DeviceToMtd(dev) ((struct mtd_info *)((dev)->driverContext))
|
||||
#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context))
|
||||
#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,200 +0,0 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2010 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*
|
||||
* Note: Tis code is currently unused. Being checked in in case it becomes useful.
|
||||
*/
|
||||
|
||||
|
||||
#include "yaffs_allocator.h"
|
||||
#include "yaffs_guts.h"
|
||||
#include "yaffs_trace.h"
|
||||
#include "yportenv.h"
|
||||
#include "yaffs_linux.h"
|
||||
/*
|
||||
* Start out with the same allocator as yaffs direct.
|
||||
* Todo: Change to Linux slab allocator.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define NAMELEN 20
|
||||
struct yaffs_AllocatorStruct {
|
||||
char tnode_name[NAMELEN+1];
|
||||
char object_name[NAMELEN+1];
|
||||
struct kmem_cache *tnode_cache;
|
||||
struct kmem_cache *object_cache;
|
||||
};
|
||||
|
||||
typedef struct yaffs_AllocatorStruct yaffs_Allocator;
|
||||
|
||||
int mount_id;
|
||||
|
||||
void yaffs_DeinitialiseRawTnodesAndObjects(yaffs_Device *dev)
|
||||
{
|
||||
yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
|
||||
|
||||
T(YAFFS_TRACE_ALLOCATE,(TSTR("Deinitialising yaffs allocator\n")));
|
||||
|
||||
if(allocator){
|
||||
if(allocator->tnode_cache){
|
||||
kmem_cache_destroy(allocator->tnode_cache);
|
||||
allocator->tnode_cache = NULL;
|
||||
} else {
|
||||
T(YAFFS_TRACE_ALWAYS,
|
||||
(TSTR("NULL tnode cache\n")));
|
||||
YBUG();
|
||||
}
|
||||
|
||||
if(allocator->object_cache){
|
||||
kmem_cache_destroy(allocator->object_cache);
|
||||
allocator->object_cache = NULL;
|
||||
} else {
|
||||
T(YAFFS_TRACE_ALWAYS,
|
||||
(TSTR("NULL object cache\n")));
|
||||
YBUG();
|
||||
}
|
||||
|
||||
YFREE(allocator);
|
||||
|
||||
} else {
|
||||
T(YAFFS_TRACE_ALWAYS,
|
||||
(TSTR("Deinitialising NULL allocator\n")));
|
||||
YBUG();
|
||||
}
|
||||
dev->allocator = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void fake_ctor0(void *data){data = data;}
|
||||
static void fake_ctor1(void *data){data = data;}
|
||||
static void fake_ctor2(void *data){data = data;}
|
||||
static void fake_ctor3(void *data){data = data;}
|
||||
static void fake_ctor4(void *data){data = data;}
|
||||
static void fake_ctor5(void *data){data = data;}
|
||||
static void fake_ctor6(void *data){data = data;}
|
||||
static void fake_ctor7(void *data){data = data;}
|
||||
static void fake_ctor8(void *data){data = data;}
|
||||
static void fake_ctor9(void *data){data = data;}
|
||||
|
||||
static void (*fake_ctor_list[10]) (void *) = {
|
||||
fake_ctor0,
|
||||
fake_ctor1,
|
||||
fake_ctor2,
|
||||
fake_ctor3,
|
||||
fake_ctor4,
|
||||
fake_ctor5,
|
||||
fake_ctor6,
|
||||
fake_ctor7,
|
||||
fake_ctor8,
|
||||
fake_ctor9,
|
||||
};
|
||||
|
||||
void yaffs_InitialiseRawTnodesAndObjects(yaffs_Device *dev)
|
||||
{
|
||||
yaffs_Allocator *allocator;
|
||||
unsigned mount_id = yaffs_DeviceToLC(dev)->mount_id;
|
||||
|
||||
T(YAFFS_TRACE_ALLOCATE,(TSTR("Initialising yaffs allocator\n")));
|
||||
|
||||
if(dev->allocator)
|
||||
YBUG();
|
||||
else if(mount_id >= 10){
|
||||
T(YAFFS_TRACE_ALWAYS,(TSTR("Bad mount_id %u\n"),mount_id));
|
||||
} else {
|
||||
allocator = YMALLOC(sizeof(yaffs_Allocator));
|
||||
memset(allocator,0,sizeof(yaffs_Allocator));
|
||||
dev->allocator = allocator;
|
||||
|
||||
if(!dev->allocator){
|
||||
T(YAFFS_TRACE_ALWAYS,
|
||||
(TSTR("yaffs allocator creation failed\n")));
|
||||
YBUG();
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
sprintf(allocator->tnode_name,"yaffs_t_%u",mount_id);
|
||||
sprintf(allocator->object_name,"yaffs_o_%u",mount_id);
|
||||
|
||||
allocator->tnode_cache =
|
||||
kmem_cache_create(allocator->tnode_name,
|
||||
dev->tnodeSize,
|
||||
0, 0,
|
||||
fake_ctor_list[mount_id]);
|
||||
if(allocator->tnode_cache)
|
||||
T(YAFFS_TRACE_ALLOCATE,
|
||||
(TSTR("tnode cache \"%s\" %p\n"),
|
||||
allocator->tnode_name,allocator->tnode_cache));
|
||||
else {
|
||||
T(YAFFS_TRACE_ALWAYS,
|
||||
(TSTR("yaffs cache creation failed\n")));
|
||||
YBUG();
|
||||
}
|
||||
|
||||
|
||||
allocator->object_cache =
|
||||
kmem_cache_create(allocator->object_name,
|
||||
sizeof(yaffs_Object),
|
||||
0, 0,
|
||||
fake_ctor_list[mount_id]);
|
||||
|
||||
if(allocator->object_cache)
|
||||
T(YAFFS_TRACE_ALLOCATE,
|
||||
(TSTR("object cache \"%s\" %p\n"),
|
||||
allocator->object_name,allocator->object_cache));
|
||||
|
||||
else {
|
||||
T(YAFFS_TRACE_ALWAYS,
|
||||
(TSTR("yaffs cache creation failed\n")));
|
||||
YBUG();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
yaffs_Tnode *yaffs_AllocateRawTnode(yaffs_Device *dev)
|
||||
{
|
||||
yaffs_Allocator *allocator = dev->allocator;
|
||||
if(!allocator || !allocator->tnode_cache){
|
||||
YBUG();
|
||||
return NULL;
|
||||
}
|
||||
return kmem_cache_alloc(allocator->tnode_cache, GFP_NOFS);
|
||||
}
|
||||
|
||||
void yaffs_FreeRawTnode(yaffs_Device *dev, yaffs_Tnode *tn)
|
||||
{
|
||||
yaffs_Allocator *allocator = dev->allocator;
|
||||
kmem_cache_free(allocator->tnode_cache,tn);
|
||||
}
|
||||
|
||||
yaffs_Object *yaffs_AllocateRawObject(yaffs_Device *dev)
|
||||
{
|
||||
yaffs_Allocator *allocator = dev->allocator;
|
||||
if(!allocator){
|
||||
YBUG();
|
||||
return NULL;
|
||||
}
|
||||
if(!allocator->object_cache){
|
||||
YBUG();
|
||||
return NULL;
|
||||
}
|
||||
return kmem_cache_alloc(allocator->object_cache, GFP_NOFS);
|
||||
}
|
||||
|
||||
void yaffs_FreeRawObject(yaffs_Device *dev, yaffs_Object *obj)
|
||||
{
|
||||
yaffs_Allocator *allocator = dev->allocator;
|
||||
kmem_cache_free(allocator->object_cache,obj);
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2010 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is just holds extra declarations of macros that would normally
|
||||
* be providesd in the Linux kernel. These macros have been written from
|
||||
* scratch but are functionally equivalent to the Linux ones.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_LIST_H__
|
||||
#define __YAFFS_LIST_H__
|
||||
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
/*
|
||||
* This is a simple doubly linked list implementation that matches the
|
||||
* way the Linux kernel doubly linked list implementation works.
|
||||
*/
|
||||
|
||||
struct ylist_head {
|
||||
struct ylist_head *next; /* next in chain */
|
||||
struct ylist_head *prev; /* previous in chain */
|
||||
};
|
||||
|
||||
|
||||
/* Initialise a static list */
|
||||
#define YLIST_HEAD(name) \
|
||||
struct ylist_head name = { &(name), &(name)}
|
||||
|
||||
|
||||
|
||||
/* Initialise a list head to an empty list */
|
||||
#define YINIT_LIST_HEAD(p) \
|
||||
do { \
|
||||
(p)->next = (p);\
|
||||
(p)->prev = (p); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Add an element to a list */
|
||||
static Y_INLINE void ylist_add(struct ylist_head *newEntry,
|
||||
struct ylist_head *list)
|
||||
{
|
||||
struct ylist_head *listNext = list->next;
|
||||
|
||||
list->next = newEntry;
|
||||
newEntry->prev = list;
|
||||
newEntry->next = listNext;
|
||||
listNext->prev = newEntry;
|
||||
|
||||
}
|
||||
|
||||
static Y_INLINE void ylist_add_tail(struct ylist_head *newEntry,
|
||||
struct ylist_head *list)
|
||||
{
|
||||
struct ylist_head *listPrev = list->prev;
|
||||
|
||||
list->prev = newEntry;
|
||||
newEntry->next = list;
|
||||
newEntry->prev = listPrev;
|
||||
listPrev->next = newEntry;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Take an element out of its current list, with or without
|
||||
* reinitialising the links.of the entry*/
|
||||
static Y_INLINE void ylist_del(struct ylist_head *entry)
|
||||
{
|
||||
struct ylist_head *listNext = entry->next;
|
||||
struct ylist_head *listPrev = entry->prev;
|
||||
|
||||
listNext->prev = listPrev;
|
||||
listPrev->next = listNext;
|
||||
|
||||
}
|
||||
|
||||
static Y_INLINE void ylist_del_init(struct ylist_head *entry)
|
||||
{
|
||||
ylist_del(entry);
|
||||
entry->next = entry->prev = entry;
|
||||
}
|
||||
|
||||
|
||||
/* Test if the list is empty */
|
||||
static Y_INLINE int ylist_empty(struct ylist_head *entry)
|
||||
{
|
||||
return (entry->next == entry);
|
||||
}
|
||||
|
||||
|
||||
/* ylist_entry takes a pointer to a list entry and offsets it to that
|
||||
* we can find a pointer to the object it is embedded in.
|
||||
*/
|
||||
|
||||
|
||||
#define ylist_entry(entry, type, member) \
|
||||
((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
|
||||
|
||||
|
||||
/* ylist_for_each and list_for_each_safe iterate over lists.
|
||||
* ylist_for_each_safe uses temporary storage to make the list delete safe
|
||||
*/
|
||||
|
||||
#define ylist_for_each(itervar, list) \
|
||||
for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
|
||||
|
||||
#define ylist_for_each_safe(itervar, saveVar, list) \
|
||||
for (itervar = (list)->next, saveVar = (list)->next->next; \
|
||||
itervar != (list); itervar = saveVar, saveVar = saveVar->next)
|
||||
|
||||
|
||||
#endif
|
@ -13,7 +13,6 @@
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
|
||||
#include "yaffs_mtdif.h"
|
||||
|
||||
#include "linux/mtd/mtd.h"
|
||||
@ -23,19 +22,19 @@
|
||||
|
||||
#include "yaffs_linux.h"
|
||||
|
||||
int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
|
||||
int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
|
||||
{
|
||||
struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
|
||||
__u32 addr =
|
||||
((loff_t) blockNumber) * dev->param.totalBytesPerChunk
|
||||
* dev->param.nChunksPerBlock;
|
||||
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
|
||||
u32 addr =
|
||||
((loff_t) block_no) * dev->param.total_bytes_per_chunk
|
||||
* dev->param.chunks_per_block;
|
||||
struct erase_info ei;
|
||||
|
||||
|
||||
int retval = 0;
|
||||
|
||||
ei.mtd = mtd;
|
||||
ei.addr = addr;
|
||||
ei.len = dev->param.totalBytesPerChunk * dev->param.nChunksPerBlock;
|
||||
ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
|
||||
ei.time = 1000;
|
||||
ei.retries = 2;
|
||||
ei.callback = NULL;
|
||||
@ -49,8 +48,7 @@ int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
int nandmtd_InitialiseNAND(yaffs_Device *dev)
|
||||
int nandmtd_initialise(struct yaffs_dev *dev)
|
||||
{
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
|
@ -18,10 +18,6 @@
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18))
|
||||
extern struct nand_oobinfo yaffs_oobinfo;
|
||||
extern struct nand_oobinfo yaffs_noeccinfo;
|
||||
#endif
|
||||
int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
|
||||
int nandmtd_InitialiseNAND(yaffs_Device *dev);
|
||||
int nandmtd_erase_block(struct yaffs_dev *dev, int block_no);
|
||||
int nandmtd_initialise(struct yaffs_dev *dev);
|
||||
#endif
|
||||
|
@ -1,10 +1,11 @@
|
||||
/*
|
||||
* YAFFS: Yet another FFS. A NAND-flash specific file system.
|
||||
* yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
|
||||
*
|
||||
* Copyright (C) 2002-2010 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
@ -18,16 +19,16 @@
|
||||
*
|
||||
* These functions are invoked via function pointers in yaffs_nand.c.
|
||||
* This replaces functionality provided by functions in yaffs_mtdif.c
|
||||
* and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
|
||||
* and the yaffs_tags compatability functions in yaffs_tagscompat.c that are
|
||||
* called in yaffs_mtdif.c when the function pointers are NULL.
|
||||
* We assume the MTD layer is performing ECC (useNANDECC is true).
|
||||
* We assume the MTD layer is performing ECC (use_nand_ecc is true).
|
||||
*/
|
||||
|
||||
#include "yportenv.h"
|
||||
#include "yaffs_trace.h"
|
||||
#include "yaffs_guts.h"
|
||||
#include "yaffs_packedtags1.h"
|
||||
#include "yaffs_tagscompat.h" /* for yaffs_CalcTagsECC */
|
||||
#include "yaffs_tagscompat.h" /* for yaffs_calc_tags_ecc */
|
||||
#include "yaffs_linux.h"
|
||||
|
||||
#include "linux/kernel.h"
|
||||
@ -51,19 +52,19 @@
|
||||
* adjust 'oobfree' to match your existing Yaffs data.
|
||||
*
|
||||
* This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
|
||||
* pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
|
||||
* page_status byte (at NAND spare offset 4) scattered/gathered from/to
|
||||
* the 9th byte.
|
||||
*
|
||||
* Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
|
||||
* We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
|
||||
* where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
|
||||
* We have/need packed_tags1 plus page_status: T0,T1,T2,T3,T4,T5,T6,T7,P
|
||||
* where Tn are the tag bytes, En are MTD's ECC bytes, P is the page_status
|
||||
* byte and B is the small-page bad-block indicator byte.
|
||||
*/
|
||||
static struct nand_ecclayout nand_oob_16 = {
|
||||
.eccbytes = 6,
|
||||
.eccpos = { 8, 9, 10, 13, 14, 15 },
|
||||
.eccpos = {8, 9, 10, 13, 14, 15},
|
||||
.oobavail = 9,
|
||||
.oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
|
||||
.oobfree = {{0, 4}, {6, 2}, {11, 2}, {4, 1}}
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -73,12 +74,12 @@ static struct nand_ecclayout nand_oob_16 = {
|
||||
* compact (packed) form for storage in NAND. A mini-ECC runs over the
|
||||
* contents of the tags meta-data; used to valid the tags when read.
|
||||
*
|
||||
* - Pack ExtendedTags to PackedTags1 form
|
||||
* - Compute mini-ECC for PackedTags1
|
||||
* - Pack ExtendedTags to packed_tags1 form
|
||||
* - Compute mini-ECC for packed_tags1
|
||||
* - Write data and packed tags to NAND.
|
||||
*
|
||||
* Note: Due to the use of the PackedTags1 meta-data which does not include
|
||||
* a full sequence number (as found in the larger PackedTags2 form) it is
|
||||
* Note: Due to the use of the packed_tags1 meta-data which does not include
|
||||
* a full sequence number (as found in the larger packed_tags2 form) it is
|
||||
* necessary for Yaffs to re-write a chunk/page (just once) to mark it as
|
||||
* discarded and dirty. This is not ideal: newer NAND parts are supposed
|
||||
* to be written just once. When Yaffs performs this operation, this
|
||||
@ -88,67 +89,68 @@ static struct nand_ecclayout nand_oob_16 = {
|
||||
* Any underlying MTD error results in YAFFS_FAIL.
|
||||
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||
*/
|
||||
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
|
||||
int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags)
|
||||
int nandmtd1_write_chunk_tags(struct yaffs_dev *dev,
|
||||
int nand_chunk, const u8 * data,
|
||||
const struct yaffs_ext_tags *etags)
|
||||
{
|
||||
struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
|
||||
int chunkBytes = dev->nDataBytesPerChunk;
|
||||
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
|
||||
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
|
||||
int chunk_bytes = dev->data_bytes_per_chunk;
|
||||
loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
|
||||
struct mtd_oob_ops ops;
|
||||
yaffs_PackedTags1 pt1;
|
||||
struct yaffs_packed_tags1 pt1;
|
||||
int retval;
|
||||
|
||||
/* we assume that PackedTags1 and yaffs_Tags are compatible */
|
||||
compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
|
||||
compile_time_assertion(sizeof(yaffs_Tags) == 8);
|
||||
/* we assume that packed_tags1 and struct yaffs_tags are compatible */
|
||||
compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12);
|
||||
compile_time_assertion(sizeof(struct yaffs_tags) == 8);
|
||||
|
||||
yaffs_PackTags1(&pt1, etags);
|
||||
yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
|
||||
yaffs_pack_tags1(&pt1, etags);
|
||||
yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1);
|
||||
|
||||
/* When deleting a chunk, the upper layer provides only skeletal
|
||||
* etags, one with chunkDeleted set. However, we need to update the
|
||||
* etags, one with is_deleted set. However, we need to update the
|
||||
* tags, not erase them completely. So we use the NAND write property
|
||||
* that only zeroed-bits stick and set tag bytes to all-ones and
|
||||
* zero just the (not) deleted bit.
|
||||
*/
|
||||
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||
if (etags->chunkDeleted) {
|
||||
if (etags->is_deleted) {
|
||||
memset(&pt1, 0xff, 8);
|
||||
/* clear delete status bit to indicate deleted */
|
||||
pt1.deleted = 0;
|
||||
}
|
||||
#else
|
||||
((__u8 *)&pt1)[8] = 0xff;
|
||||
if (etags->chunkDeleted) {
|
||||
((u8 *) & pt1)[8] = 0xff;
|
||||
if (etags->is_deleted) {
|
||||
memset(&pt1, 0xff, 8);
|
||||
/* zero pageStatus byte to indicate deleted */
|
||||
((__u8 *)&pt1)[8] = 0;
|
||||
/* zero page_status byte to indicate deleted */
|
||||
((u8 *) & pt1)[8] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(&ops, 0, sizeof(ops));
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.len = (data) ? chunkBytes : 0;
|
||||
ops.len = (data) ? chunk_bytes : 0;
|
||||
ops.ooblen = YTAG1_SIZE;
|
||||
ops.datbuf = (__u8 *)data;
|
||||
ops.oobbuf = (__u8 *)&pt1;
|
||||
ops.datbuf = (u8 *) data;
|
||||
ops.oobbuf = (u8 *) & pt1;
|
||||
|
||||
retval = mtd->write_oob(mtd, addr, &ops);
|
||||
if (retval) {
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR),
|
||||
chunkInNAND, retval));
|
||||
(TSTR("write_oob failed, chunk %d, mtd error %d" TENDSTR),
|
||||
nand_chunk, retval));
|
||||
}
|
||||
return retval ? YAFFS_FAIL : YAFFS_OK;
|
||||
}
|
||||
|
||||
/* Return with empty ExtendedTags but add eccResult.
|
||||
/* Return with empty ExtendedTags but add ecc_result.
|
||||
*/
|
||||
static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval)
|
||||
static int rettags(struct yaffs_ext_tags *etags, int ecc_result, int retval)
|
||||
{
|
||||
if (etags) {
|
||||
memset(etags, 0, sizeof(*etags));
|
||||
etags->eccResult = eccResult;
|
||||
etags->ecc_result = ecc_result;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@ -156,34 +158,35 @@ static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval)
|
||||
/* Read a chunk (page) from NAND.
|
||||
*
|
||||
* Caller expects ExtendedTags data to be usable even on error; that is,
|
||||
* all members except eccResult and blockBad are zeroed.
|
||||
* all members except ecc_result and block_bad are zeroed.
|
||||
*
|
||||
* - Check ECC results for data (if applicable)
|
||||
* - Check for blank/erased block (return empty ExtendedTags if blank)
|
||||
* - Check the PackedTags1 mini-ECC (correct if necessary/possible)
|
||||
* - Convert PackedTags1 to ExtendedTags
|
||||
* - Update eccResult and blockBad members to refect state.
|
||||
* - Check the packed_tags1 mini-ECC (correct if necessary/possible)
|
||||
* - Convert packed_tags1 to ExtendedTags
|
||||
* - Update ecc_result and block_bad members to refect state.
|
||||
*
|
||||
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||
*/
|
||||
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
||||
int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags)
|
||||
int nandmtd1_read_chunk_tags(struct yaffs_dev *dev,
|
||||
int nand_chunk, u8 * data,
|
||||
struct yaffs_ext_tags *etags)
|
||||
{
|
||||
struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
|
||||
int chunkBytes = dev->nDataBytesPerChunk;
|
||||
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
|
||||
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
|
||||
int chunk_bytes = dev->data_bytes_per_chunk;
|
||||
loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
|
||||
int eccres = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
struct mtd_oob_ops ops;
|
||||
yaffs_PackedTags1 pt1;
|
||||
struct yaffs_packed_tags1 pt1;
|
||||
int retval;
|
||||
int deleted;
|
||||
|
||||
memset(&ops, 0, sizeof(ops));
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.len = (data) ? chunkBytes : 0;
|
||||
ops.len = (data) ? chunk_bytes : 0;
|
||||
ops.ooblen = YTAG1_SIZE;
|
||||
ops.datbuf = data;
|
||||
ops.oobbuf = (__u8 *)&pt1;
|
||||
ops.oobbuf = (u8 *) & pt1;
|
||||
|
||||
#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
|
||||
/* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
|
||||
@ -197,8 +200,8 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
||||
retval = mtd->read_oob(mtd, addr, &ops);
|
||||
if (retval) {
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR),
|
||||
chunkInNAND, retval));
|
||||
(TSTR("read_oob failed, chunk %d, mtd error %d" TENDSTR),
|
||||
nand_chunk, retval));
|
||||
}
|
||||
|
||||
switch (retval) {
|
||||
@ -209,26 +212,25 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
||||
case -EUCLEAN:
|
||||
/* MTD's ECC fixed the data */
|
||||
eccres = YAFFS_ECC_RESULT_FIXED;
|
||||
dev->eccFixed++;
|
||||
dev->n_ecc_fixed++;
|
||||
break;
|
||||
|
||||
case -EBADMSG:
|
||||
/* MTD's ECC could not fix the data */
|
||||
dev->eccUnfixed++;
|
||||
dev->n_ecc_unfixed++;
|
||||
/* fall into... */
|
||||
default:
|
||||
rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
|
||||
etags->blockBad = (mtd->block_isbad)(mtd, addr);
|
||||
etags->block_bad = (mtd->block_isbad) (mtd, addr);
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
/* Check for a blank/erased chunk.
|
||||
*/
|
||||
if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
|
||||
/* when blank, upper layers want eccResult to be <= NO_ERROR */
|
||||
if (yaffs_check_ff((u8 *) & pt1, 8)) {
|
||||
/* when blank, upper layers want ecc_result to be <= NO_ERROR */
|
||||
return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||
/* Read deleted status (bit) then return it to it's non-deleted
|
||||
* state before performing tags mini-ECC check. pt1.deleted is
|
||||
@ -237,37 +239,37 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
||||
deleted = !pt1.deleted;
|
||||
pt1.deleted = 1;
|
||||
#else
|
||||
deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
|
||||
deleted = (yaffs_count_bits(((u8 *) & pt1)[8]) < 7);
|
||||
#endif
|
||||
|
||||
/* Check the packed tags mini-ECC and correct if necessary/possible.
|
||||
*/
|
||||
retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
|
||||
retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1);
|
||||
switch (retval) {
|
||||
case 0:
|
||||
/* no tags error, use MTD result */
|
||||
break;
|
||||
case 1:
|
||||
/* recovered tags-ECC error */
|
||||
dev->tagsEccFixed++;
|
||||
dev->n_tags_ecc_fixed++;
|
||||
if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
|
||||
eccres = YAFFS_ECC_RESULT_FIXED;
|
||||
break;
|
||||
default:
|
||||
/* unrecovered tags-ECC error */
|
||||
dev->tagsEccUnfixed++;
|
||||
dev->n_tags_ecc_unfixed++;
|
||||
return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
|
||||
}
|
||||
|
||||
/* Unpack the tags to extended form and set ECC result.
|
||||
* [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
|
||||
* [set should_be_ff just to keep yaffs_unpack_tags1 happy]
|
||||
*/
|
||||
pt1.shouldBeFF = 0xFFFFFFFF;
|
||||
yaffs_UnpackTags1(etags, &pt1);
|
||||
etags->eccResult = eccres;
|
||||
pt1.should_be_ff = 0xFFFFFFFF;
|
||||
yaffs_unpack_tags1(etags, &pt1);
|
||||
etags->ecc_result = eccres;
|
||||
|
||||
/* Set deleted state */
|
||||
etags->chunkDeleted = deleted;
|
||||
etags->is_deleted = deleted;
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
@ -278,15 +280,16 @@ int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
||||
*
|
||||
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||
*/
|
||||
int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
|
||||
int nandmtd1_mark_block_bad(struct yaffs_dev *dev, int block_no)
|
||||
{
|
||||
struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
|
||||
int blocksize = dev->param.nChunksPerBlock * dev->nDataBytesPerChunk;
|
||||
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
|
||||
int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
|
||||
int retval;
|
||||
|
||||
T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("marking block %d bad"TENDSTR), blockNo));
|
||||
T(YAFFS_TRACE_BAD_BLOCKS,
|
||||
(TSTR("marking block %d bad" TENDSTR), block_no));
|
||||
|
||||
retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
|
||||
retval = mtd->block_markbad(mtd, (loff_t) blocksize * block_no);
|
||||
return (retval) ? YAFFS_FAIL : YAFFS_OK;
|
||||
}
|
||||
|
||||
@ -294,7 +297,7 @@ int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
|
||||
*
|
||||
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||
*/
|
||||
static int nandmtd1_TestPrerequists(struct mtd_info *mtd)
|
||||
static int nandmtd1_test_prerequists(struct mtd_info *mtd)
|
||||
{
|
||||
/* 2.6.18 has mtd->ecclayout->oobavail */
|
||||
/* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
|
||||
@ -302,8 +305,9 @@ static int nandmtd1_TestPrerequists(struct mtd_info *mtd)
|
||||
|
||||
if (oobavail < YTAG1_SIZE) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR("mtd device has only %d bytes for tags, need %d"TENDSTR),
|
||||
oobavail, YTAG1_SIZE));
|
||||
(TSTR
|
||||
("mtd device has only %d bytes for tags, need %d" TENDSTR),
|
||||
oobavail, YTAG1_SIZE));
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
return YAFFS_OK;
|
||||
@ -318,13 +322,13 @@ static int nandmtd1_TestPrerequists(struct mtd_info *mtd)
|
||||
*
|
||||
* Always returns YAFFS_OK.
|
||||
*/
|
||||
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||
yaffs_BlockState *pState, __u32 *pSequenceNumber)
|
||||
int nandmtd1_query_block(struct yaffs_dev *dev, int block_no,
|
||||
enum yaffs_block_state *state_ptr, u32 * seq_ptr)
|
||||
{
|
||||
struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
|
||||
int chunkNo = blockNo * dev->param.nChunksPerBlock;
|
||||
loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
|
||||
yaffs_ExtendedTags etags;
|
||||
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
|
||||
int chunk_num = block_no * dev->param.chunks_per_block;
|
||||
loff_t addr = (loff_t) chunk_num * dev->data_bytes_per_chunk;
|
||||
struct yaffs_ext_tags etags;
|
||||
int state = YAFFS_BLOCK_STATE_DEAD;
|
||||
int seqnum = 0;
|
||||
int retval;
|
||||
@ -332,30 +336,30 @@ int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||
/* We don't yet have a good place to test for MTD config prerequists.
|
||||
* Do it here as we are called during the initial scan.
|
||||
*/
|
||||
if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK)
|
||||
if (nandmtd1_test_prerequists(mtd) != YAFFS_OK)
|
||||
return YAFFS_FAIL;
|
||||
|
||||
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
|
||||
etags.blockBad = (mtd->block_isbad)(mtd, addr);
|
||||
if (etags.blockBad) {
|
||||
retval = nandmtd1_read_chunk_tags(dev, chunk_num, NULL, &etags);
|
||||
etags.block_bad = (mtd->block_isbad) (mtd, addr);
|
||||
if (etags.block_bad) {
|
||||
T(YAFFS_TRACE_BAD_BLOCKS,
|
||||
(TSTR("block %d is marked bad"TENDSTR), blockNo));
|
||||
(TSTR("block %d is marked bad" TENDSTR), block_no));
|
||||
state = YAFFS_BLOCK_STATE_DEAD;
|
||||
} else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
|
||||
} else if (etags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
|
||||
/* bad tags, need to look more closely */
|
||||
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
} else if (etags.chunkUsed) {
|
||||
} else if (etags.chunk_used) {
|
||||
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
seqnum = etags.sequenceNumber;
|
||||
seqnum = etags.seq_number;
|
||||
} else {
|
||||
state = YAFFS_BLOCK_STATE_EMPTY;
|
||||
}
|
||||
|
||||
*pState = state;
|
||||
*pSequenceNumber = seqnum;
|
||||
*state_ptr = state;
|
||||
*seq_ptr = seqnum;
|
||||
|
||||
/* query always succeeds */
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
#endif /*MTD_VERSION*/
|
||||
#endif /*MTD_VERSION */
|
||||
|
@ -14,15 +14,16 @@
|
||||
#ifndef __YAFFS_MTDIF1_H__
|
||||
#define __YAFFS_MTDIF1_H__
|
||||
|
||||
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
|
||||
const __u8 *data, const yaffs_ExtendedTags *tags);
|
||||
int nandmtd1_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
|
||||
const u8 * data,
|
||||
const struct yaffs_ext_tags *tags);
|
||||
|
||||
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
|
||||
__u8 *data, yaffs_ExtendedTags *tags);
|
||||
int nandmtd1_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
|
||||
u8 * data, struct yaffs_ext_tags *tags);
|
||||
|
||||
int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
|
||||
int nandmtd1_mark_block_bad(struct yaffs_dev *dev, int block_no);
|
||||
|
||||
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||
yaffs_BlockState *state, __u32 *sequenceNumber);
|
||||
int nandmtd1_query_block(struct yaffs_dev *dev, int block_no,
|
||||
enum yaffs_block_state *state, u32 * seq_number);
|
||||
|
||||
#endif
|
||||
|
@ -27,14 +27,14 @@
|
||||
#include "yaffs_linux.h"
|
||||
|
||||
/* NB For use with inband tags....
|
||||
* We assume that the data buffer is of size totalBytersPerChunk so that we can also
|
||||
* We assume that the data buffer is of size total_bytes_per_chunk so that we can also
|
||||
* use it to load the tags.
|
||||
*/
|
||||
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
|
||||
const __u8 *data,
|
||||
const yaffs_ExtendedTags *tags)
|
||||
int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
|
||||
const u8 * data,
|
||||
const struct yaffs_ext_tags *tags)
|
||||
{
|
||||
struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
|
||||
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
|
||||
struct mtd_oob_ops ops;
|
||||
#else
|
||||
@ -44,18 +44,19 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
|
||||
|
||||
loff_t addr;
|
||||
|
||||
yaffs_PackedTags2 pt;
|
||||
struct yaffs_packed_tags2 pt;
|
||||
|
||||
int packed_tags_size = dev->param.noTagsECC ? sizeof(pt.t) : sizeof(pt);
|
||||
void * packed_tags_ptr = dev->param.noTagsECC ? (void *) &pt.t : (void *)&pt;
|
||||
int packed_tags_size =
|
||||
dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
|
||||
void *packed_tags_ptr =
|
||||
dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
|
||||
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR
|
||||
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
|
||||
TENDSTR), chunkInNAND, data, tags));
|
||||
("nandmtd2_write_chunk_tags chunk %d data %p tags %p"
|
||||
TENDSTR), nand_chunk, data, tags));
|
||||
|
||||
|
||||
addr = ((loff_t) chunkInNAND) * dev->param.totalBytesPerChunk;
|
||||
addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
|
||||
|
||||
/* For yaffs2 writing there must be both data and tags.
|
||||
* If we're using inband tags, then the tags are stuffed into
|
||||
@ -63,31 +64,34 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
|
||||
*/
|
||||
if (!data || !tags)
|
||||
BUG();
|
||||
else if (dev->param.inbandTags) {
|
||||
yaffs_PackedTags2TagsPart *pt2tp;
|
||||
pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);
|
||||
yaffs_PackTags2TagsPart(pt2tp, tags);
|
||||
else if (dev->param.inband_tags) {
|
||||
struct yaffs_packed_tags2_tags_only *pt2tp;
|
||||
pt2tp =
|
||||
(struct yaffs_packed_tags2_tags_only *)(data +
|
||||
dev->
|
||||
data_bytes_per_chunk);
|
||||
yaffs_pack_tags2_tags_only(pt2tp, tags);
|
||||
} else
|
||||
yaffs_PackTags2(&pt, tags, !dev->param.noTagsECC);
|
||||
yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.ooblen = (dev->param.inbandTags) ? 0 : packed_tags_size;
|
||||
ops.len = dev->param.totalBytesPerChunk;
|
||||
ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size;
|
||||
ops.len = dev->param.total_bytes_per_chunk;
|
||||
ops.ooboffs = 0;
|
||||
ops.datbuf = (__u8 *)data;
|
||||
ops.oobbuf = (dev->param.inbandTags) ? NULL : packed_tags_ptr;
|
||||
ops.datbuf = (u8 *) data;
|
||||
ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr;
|
||||
retval = mtd->write_oob(mtd, addr, &ops);
|
||||
|
||||
#else
|
||||
if (!dev->param.inbandTags) {
|
||||
if (!dev->param.inband_tags) {
|
||||
retval =
|
||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, (__u8 *) packed_tags_ptr, NULL);
|
||||
mtd->write_ecc(mtd, addr, dev->data_bytes_per_chunk,
|
||||
&dummy, data, (u8 *) packed_tags_ptr, NULL);
|
||||
} else {
|
||||
retval =
|
||||
mtd->write(mtd, addr, dev->param.totalBytesPerChunk, &dummy,
|
||||
data);
|
||||
mtd->write(mtd, addr, dev->param.total_bytes_per_chunk,
|
||||
&dummy, data);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -97,95 +101,99 @@ int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
|
||||
__u8 *data, yaffs_ExtendedTags *tags)
|
||||
int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
|
||||
u8 * data, struct yaffs_ext_tags *tags)
|
||||
{
|
||||
struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
|
||||
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
|
||||
#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
|
||||
struct mtd_oob_ops ops;
|
||||
#endif
|
||||
size_t dummy;
|
||||
int retval = 0;
|
||||
int localData = 0;
|
||||
int local_data = 0;
|
||||
|
||||
loff_t addr = ((loff_t) chunkInNAND) * dev->param.totalBytesPerChunk;
|
||||
loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
|
||||
|
||||
yaffs_PackedTags2 pt;
|
||||
struct yaffs_packed_tags2 pt;
|
||||
|
||||
int packed_tags_size = dev->param.noTagsECC ? sizeof(pt.t) : sizeof(pt);
|
||||
void * packed_tags_ptr = dev->param.noTagsECC ? (void *) &pt.t: (void *)&pt;
|
||||
int packed_tags_size =
|
||||
dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
|
||||
void *packed_tags_ptr =
|
||||
dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
|
||||
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR
|
||||
("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
|
||||
TENDSTR), chunkInNAND, data, tags));
|
||||
("nandmtd2_read_chunk_tags chunk %d data %p tags %p"
|
||||
TENDSTR), nand_chunk, data, tags));
|
||||
|
||||
if (dev->param.inbandTags) {
|
||||
if (dev->param.inband_tags) {
|
||||
|
||||
if (!data) {
|
||||
localData = 1;
|
||||
data = yaffs_GetTempBuffer(dev, __LINE__);
|
||||
local_data = 1;
|
||||
data = yaffs_get_temp_buffer(dev, __LINE__);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
|
||||
if (dev->param.inbandTags || (data && !tags))
|
||||
retval = mtd->read(mtd, addr, dev->param.totalBytesPerChunk,
|
||||
&dummy, data);
|
||||
if (dev->param.inband_tags || (data && !tags))
|
||||
retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk,
|
||||
&dummy, data);
|
||||
else if (tags) {
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.ooblen = packed_tags_size;
|
||||
ops.len = data ? dev->nDataBytesPerChunk : packed_tags_size;
|
||||
ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
|
||||
ops.ooboffs = 0;
|
||||
ops.datbuf = data;
|
||||
ops.oobbuf = yaffs_DeviceToLC(dev)->spareBuffer;
|
||||
ops.oobbuf = yaffs_dev_to_lc(dev)->spare_buffer;
|
||||
retval = mtd->read_oob(mtd, addr, &ops);
|
||||
}
|
||||
#else
|
||||
if (!dev->param.inbandTags && data && tags) {
|
||||
if (!dev->param.inband_tags && data && tags) {
|
||||
|
||||
retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||
&dummy, data, dev->spareBuffer,
|
||||
NULL);
|
||||
retval = mtd->read_ecc(mtd, addr, dev->data_bytes_per_chunk,
|
||||
&dummy, data, dev->spare_buffer, NULL);
|
||||
} else {
|
||||
if (data)
|
||||
retval =
|
||||
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
|
||||
data);
|
||||
if (!dev->param.inbandTags && tags)
|
||||
mtd->read(mtd, addr, dev->data_bytes_per_chunk,
|
||||
&dummy, data);
|
||||
if (!dev->param.inband_tags && tags)
|
||||
retval =
|
||||
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
|
||||
dev->spareBuffer);
|
||||
dev->spare_buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (dev->param.inbandTags) {
|
||||
if (dev->param.inband_tags) {
|
||||
if (tags) {
|
||||
yaffs_PackedTags2TagsPart *pt2tp;
|
||||
pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
|
||||
yaffs_UnpackTags2TagsPart(tags, pt2tp);
|
||||
struct yaffs_packed_tags2_tags_only *pt2tp;
|
||||
pt2tp =
|
||||
(struct yaffs_packed_tags2_tags_only *)&data[dev->
|
||||
data_bytes_per_chunk];
|
||||
yaffs_unpack_tags2_tags_only(tags, pt2tp);
|
||||
}
|
||||
} else {
|
||||
if (tags) {
|
||||
memcpy(packed_tags_ptr, yaffs_DeviceToLC(dev)->spareBuffer, packed_tags_size);
|
||||
yaffs_UnpackTags2(tags, &pt, !dev->param.noTagsECC);
|
||||
memcpy(packed_tags_ptr,
|
||||
yaffs_dev_to_lc(dev)->spare_buffer,
|
||||
packed_tags_size);
|
||||
yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
|
||||
}
|
||||
}
|
||||
|
||||
if (localData)
|
||||
yaffs_ReleaseTempBuffer(dev, data, __LINE__);
|
||||
if (local_data)
|
||||
yaffs_release_temp_buffer(dev, data, __LINE__);
|
||||
|
||||
if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) {
|
||||
tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
||||
dev->eccUnfixed++;
|
||||
if (tags && retval == -EBADMSG
|
||||
&& tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
|
||||
tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
|
||||
dev->n_ecc_unfixed++;
|
||||
}
|
||||
if(tags && retval == -EUCLEAN && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) {
|
||||
tags->eccResult = YAFFS_ECC_RESULT_FIXED;
|
||||
dev->eccFixed++;
|
||||
if (tags && retval == -EUCLEAN
|
||||
&& tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
|
||||
tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
|
||||
dev->n_ecc_fixed++;
|
||||
}
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
@ -193,17 +201,17 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
|
||||
int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no)
|
||||
{
|
||||
struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
|
||||
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
|
||||
int retval;
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
|
||||
(TSTR("nandmtd2_mark_block_bad %d" TENDSTR), block_no));
|
||||
|
||||
retval =
|
||||
mtd->block_markbad(mtd,
|
||||
blockNo * dev->param.nChunksPerBlock *
|
||||
dev->param.totalBytesPerChunk);
|
||||
block_no * dev->param.chunks_per_block *
|
||||
dev->param.total_bytes_per_chunk);
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
@ -212,46 +220,41 @@ int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
|
||||
|
||||
}
|
||||
|
||||
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||
yaffs_BlockState *state, __u32 *sequenceNumber)
|
||||
int nandmtd2_query_block(struct yaffs_dev *dev, int block_no,
|
||||
enum yaffs_block_state *state, u32 * seq_number)
|
||||
{
|
||||
struct mtd_info *mtd = yaffs_DeviceToMtd(dev);
|
||||
struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
|
||||
int retval;
|
||||
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
|
||||
T(YAFFS_TRACE_MTD, (TSTR("nandmtd2_query_block %d" TENDSTR), block_no));
|
||||
retval =
|
||||
mtd->block_isbad(mtd,
|
||||
blockNo * dev->param.nChunksPerBlock *
|
||||
dev->param.totalBytesPerChunk);
|
||||
block_no * dev->param.chunks_per_block *
|
||||
dev->param.total_bytes_per_chunk);
|
||||
|
||||
if (retval) {
|
||||
T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
|
||||
|
||||
*state = YAFFS_BLOCK_STATE_DEAD;
|
||||
*sequenceNumber = 0;
|
||||
*seq_number = 0;
|
||||
} else {
|
||||
yaffs_ExtendedTags t;
|
||||
nandmtd2_ReadChunkWithTagsFromNAND(dev,
|
||||
blockNo *
|
||||
dev->param.nChunksPerBlock, NULL,
|
||||
&t);
|
||||
struct yaffs_ext_tags t;
|
||||
nandmtd2_read_chunk_tags(dev, block_no *
|
||||
dev->param.chunks_per_block, NULL, &t);
|
||||
|
||||
if (t.chunkUsed) {
|
||||
*sequenceNumber = t.sequenceNumber;
|
||||
if (t.chunk_used) {
|
||||
*seq_number = t.seq_number;
|
||||
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
} else {
|
||||
*sequenceNumber = 0;
|
||||
*seq_number = 0;
|
||||
*state = YAFFS_BLOCK_STATE_EMPTY;
|
||||
}
|
||||
}
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
|
||||
*state));
|
||||
(TSTR("block is bad seq %d state %d" TENDSTR), *seq_number, *state));
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
else
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
|
@ -17,13 +17,13 @@
|
||||
#define __YAFFS_MTDIF2_H__
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
|
||||
const __u8 *data,
|
||||
const yaffs_ExtendedTags *tags);
|
||||
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
|
||||
__u8 *data, yaffs_ExtendedTags *tags);
|
||||
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
|
||||
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||
yaffs_BlockState *state, __u32 *sequenceNumber);
|
||||
int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
|
||||
const u8 * data,
|
||||
const struct yaffs_ext_tags *tags);
|
||||
int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
|
||||
u8 * data, struct yaffs_ext_tags *tags);
|
||||
int nandmtd2_mark_block_bad(struct yaffs_dev *dev, int block_no);
|
||||
int nandmtd2_query_block(struct yaffs_dev *dev, int block_no,
|
||||
enum yaffs_block_state *state, u32 * seq_number);
|
||||
|
||||
#endif
|
||||
|
@ -25,118 +25,120 @@
|
||||
* This code has not been tested with unicode yet.
|
||||
*/
|
||||
|
||||
|
||||
#include "yaffs_nameval.h"
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
static int nval_find(const char *xb, int xb_size, const YCHAR *name,
|
||||
int *exist_size)
|
||||
|
||||
static int nval_find(const char *xb, int xb_size, const YCHAR * name,
|
||||
int *exist_size)
|
||||
{
|
||||
int pos=0;
|
||||
int pos = 0;
|
||||
int size;
|
||||
|
||||
memcpy(&size,xb,sizeof(int));
|
||||
while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
|
||||
if(yaffs_strncmp((YCHAR *)(xb+pos+sizeof(int)),name,size) == 0){
|
||||
if(exist_size)
|
||||
memcpy(&size, xb, sizeof(int));
|
||||
while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
|
||||
if (yaffs_strncmp
|
||||
((YCHAR *) (xb + pos + sizeof(int)), name, size) == 0) {
|
||||
if (exist_size)
|
||||
*exist_size = size;
|
||||
return pos;
|
||||
}
|
||||
pos += size;
|
||||
if(pos < xb_size -sizeof(int))
|
||||
memcpy(&size,xb + pos,sizeof(int));
|
||||
if (pos < xb_size - sizeof(int))
|
||||
memcpy(&size, xb + pos, sizeof(int));
|
||||
else
|
||||
size = 0;
|
||||
}
|
||||
if(exist_size)
|
||||
if (exist_size)
|
||||
*exist_size = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int nval_used(const char *xb, int xb_size)
|
||||
{
|
||||
int pos=0;
|
||||
int pos = 0;
|
||||
int size;
|
||||
|
||||
memcpy(&size,xb + pos,sizeof(int));
|
||||
while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
|
||||
memcpy(&size, xb + pos, sizeof(int));
|
||||
while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
|
||||
pos += size;
|
||||
if(pos < xb_size -sizeof(int))
|
||||
memcpy(&size,xb + pos,sizeof(int));
|
||||
if (pos < xb_size - sizeof(int))
|
||||
memcpy(&size, xb + pos, sizeof(int));
|
||||
else
|
||||
size = 0;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
int nval_del(char *xb, int xb_size, const YCHAR *name)
|
||||
int nval_del(char *xb, int xb_size, const YCHAR * name)
|
||||
{
|
||||
int pos = nval_find(xb, xb_size, name, NULL);
|
||||
int pos = nval_find(xb, xb_size, name, NULL);
|
||||
int size;
|
||||
|
||||
if(pos >= 0 && pos < xb_size){
|
||||
|
||||
if (pos >= 0 && pos < xb_size) {
|
||||
/* Find size, shift rest over this record, then zero out the rest of buffer */
|
||||
memcpy(&size,xb+pos,sizeof(int));
|
||||
memcpy(&size, xb + pos, sizeof(int));
|
||||
memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
|
||||
memset(xb + (xb_size - size),0,size);
|
||||
memset(xb + (xb_size - size), 0, size);
|
||||
return 0;
|
||||
} else
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags)
|
||||
int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
|
||||
int bsize, int flags)
|
||||
{
|
||||
int pos;
|
||||
int namelen = yaffs_strnlen(name,xb_size);
|
||||
int namelen = yaffs_strnlen(name, xb_size);
|
||||
int reclen;
|
||||
int size_exist = 0;
|
||||
int space;
|
||||
int start;
|
||||
|
||||
pos = nval_find(xb,xb_size,name, &size_exist);
|
||||
pos = nval_find(xb, xb_size, name, &size_exist);
|
||||
|
||||
if(flags & XATTR_CREATE && pos >= 0)
|
||||
if (flags & XATTR_CREATE && pos >= 0)
|
||||
return -EEXIST;
|
||||
if(flags & XATTR_REPLACE && pos < 0)
|
||||
if (flags & XATTR_REPLACE && pos < 0)
|
||||
return -ENODATA;
|
||||
|
||||
start = nval_used(xb,xb_size);
|
||||
start = nval_used(xb, xb_size);
|
||||
space = xb_size - start + size_exist;
|
||||
|
||||
reclen = (sizeof(int) + namelen + 1 + bsize);
|
||||
|
||||
if(reclen > space)
|
||||
if (reclen > space)
|
||||
return -ENOSPC;
|
||||
|
||||
if(pos >= 0){
|
||||
nval_del(xb,xb_size,name);
|
||||
if (pos >= 0) {
|
||||
nval_del(xb, xb_size, name);
|
||||
start = nval_used(xb, xb_size);
|
||||
}
|
||||
|
||||
pos = start;
|
||||
|
||||
memcpy(xb + pos,&reclen,sizeof(int));
|
||||
pos +=sizeof(int);
|
||||
yaffs_strncpy((YCHAR *)(xb + pos), name, reclen);
|
||||
pos+= (namelen+1);
|
||||
memcpy(xb + pos,buf,bsize);
|
||||
memcpy(xb + pos, &reclen, sizeof(int));
|
||||
pos += sizeof(int);
|
||||
yaffs_strncpy((YCHAR *) (xb + pos), name, reclen);
|
||||
pos += (namelen + 1);
|
||||
memcpy(xb + pos, buf, bsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize)
|
||||
int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
|
||||
int bsize)
|
||||
{
|
||||
int pos = nval_find(xb,xb_size,name,NULL);
|
||||
int pos = nval_find(xb, xb_size, name, NULL);
|
||||
int size;
|
||||
|
||||
if(pos >= 0 && pos< xb_size){
|
||||
|
||||
memcpy(&size,xb +pos,sizeof(int));
|
||||
pos+=sizeof(int); /* advance past record length */
|
||||
|
||||
if (pos >= 0 && pos < xb_size) {
|
||||
|
||||
memcpy(&size, xb + pos, sizeof(int));
|
||||
pos += sizeof(int); /* advance past record length */
|
||||
size -= sizeof(int);
|
||||
|
||||
/* Advance over name string */
|
||||
while(xb[pos] && size > 0 && pos < xb_size){
|
||||
while (xb[pos] && size > 0 && pos < xb_size) {
|
||||
pos++;
|
||||
size--;
|
||||
}
|
||||
@ -144,13 +146,13 @@ int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsiz
|
||||
pos++;
|
||||
size--;
|
||||
|
||||
if(size <= bsize){
|
||||
memcpy(buf,xb + pos,size);
|
||||
if (size <= bsize) {
|
||||
memcpy(buf, xb + pos, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if(pos >= 0)
|
||||
if (pos >= 0)
|
||||
return -ERANGE;
|
||||
else
|
||||
return -ENODATA;
|
||||
@ -164,33 +166,33 @@ int nval_list(const char *xb, int xb_size, char *buf, int bsize)
|
||||
int ncopied = 0;
|
||||
int filled = 0;
|
||||
|
||||
memcpy(&size,xb + pos,sizeof(int));
|
||||
while(size > sizeof(int) && size <= xb_size && (pos + size) < xb_size && !filled){
|
||||
pos+= sizeof(int);
|
||||
size-=sizeof(int);
|
||||
name_len = yaffs_strnlen((YCHAR *)(xb + pos), size);
|
||||
if(ncopied + name_len + 1 < bsize){
|
||||
memcpy(buf,xb+pos,name_len * sizeof(YCHAR));
|
||||
buf+= name_len;
|
||||
memcpy(&size, xb + pos, sizeof(int));
|
||||
while (size > sizeof(int) && size <= xb_size && (pos + size) < xb_size
|
||||
&& !filled) {
|
||||
pos += sizeof(int);
|
||||
size -= sizeof(int);
|
||||
name_len = yaffs_strnlen((YCHAR *) (xb + pos), size);
|
||||
if (ncopied + name_len + 1 < bsize) {
|
||||
memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
|
||||
buf += name_len;
|
||||
*buf = '\0';
|
||||
buf++;
|
||||
if(sizeof(YCHAR) > 1){
|
||||
if (sizeof(YCHAR) > 1) {
|
||||
*buf = '\0';
|
||||
buf++;
|
||||
}
|
||||
ncopied += (name_len+1);
|
||||
ncopied += (name_len + 1);
|
||||
} else
|
||||
filled = 1;
|
||||
pos+=size;
|
||||
if(pos < xb_size -sizeof(int))
|
||||
memcpy(&size,xb + pos,sizeof(int));
|
||||
pos += size;
|
||||
if (pos < xb_size - sizeof(int))
|
||||
memcpy(&size, xb + pos, sizeof(int));
|
||||
else
|
||||
size = 0;
|
||||
}
|
||||
return ncopied;
|
||||
}
|
||||
|
||||
|
||||
int nval_hasvalues(const char *xb, int xb_size)
|
||||
{
|
||||
return nval_used(xb, xb_size) > 0;
|
||||
|
@ -12,14 +12,17 @@
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __NAMEVAL_H__
|
||||
#define __NAMEVAL_H__
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
int nval_del(char *xb, int xb_size, const YCHAR *name);
|
||||
int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags);
|
||||
int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize);
|
||||
int nval_del(char *xb, int xb_size, const YCHAR * name);
|
||||
int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
|
||||
int bsize, int flags);
|
||||
int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
|
||||
int bsize);
|
||||
int nval_list(const char *xb, int xb_size, char *buf, int bsize);
|
||||
int nval_hasvalues(const char *xb, int xb_size);
|
||||
#endif
|
||||
|
@ -17,124 +17,112 @@
|
||||
|
||||
#include "yaffs_getblockinfo.h"
|
||||
|
||||
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
|
||||
__u8 *buffer,
|
||||
yaffs_ExtendedTags *tags)
|
||||
int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
|
||||
u8 * buffer, struct yaffs_ext_tags *tags)
|
||||
{
|
||||
int result;
|
||||
yaffs_ExtendedTags localTags;
|
||||
struct yaffs_ext_tags local_tags;
|
||||
|
||||
int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
|
||||
int realigned_chunk = nand_chunk - dev->chunk_offset;
|
||||
|
||||
dev->nPageReads++;
|
||||
dev->n_page_reads++;
|
||||
|
||||
/* If there are no tags provided, use local tags to get prioritised gc working */
|
||||
if (!tags)
|
||||
tags = &localTags;
|
||||
tags = &local_tags;
|
||||
|
||||
if (dev->param.readChunkWithTagsFromNAND)
|
||||
result = dev->param.readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
|
||||
tags);
|
||||
if (dev->param.read_chunk_tags_fn)
|
||||
result =
|
||||
dev->param.read_chunk_tags_fn(dev, realigned_chunk, buffer,
|
||||
tags);
|
||||
else
|
||||
result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
|
||||
realignedChunkInNAND,
|
||||
buffer,
|
||||
tags);
|
||||
if (tags &&
|
||||
tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) {
|
||||
result = yaffs_tags_compat_rd(dev,
|
||||
realigned_chunk, buffer, tags);
|
||||
if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
|
||||
|
||||
yaffs_BlockInfo *bi;
|
||||
bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->param.nChunksPerBlock);
|
||||
yaffs_HandleChunkError(dev, bi);
|
||||
struct yaffs_block_info *bi;
|
||||
bi = yaffs_get_block_info(dev,
|
||||
nand_chunk /
|
||||
dev->param.chunks_per_block);
|
||||
yaffs_handle_chunk_error(dev, bi);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,
|
||||
int chunkInNAND,
|
||||
const __u8 *buffer,
|
||||
yaffs_ExtendedTags *tags)
|
||||
int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
|
||||
int nand_chunk,
|
||||
const u8 * buffer, struct yaffs_ext_tags *tags)
|
||||
{
|
||||
|
||||
dev->nPageWrites++;
|
||||
|
||||
chunkInNAND -= dev->chunkOffset;
|
||||
dev->n_page_writes++;
|
||||
|
||||
nand_chunk -= dev->chunk_offset;
|
||||
|
||||
if (tags) {
|
||||
tags->sequenceNumber = dev->sequenceNumber;
|
||||
tags->chunkUsed = 1;
|
||||
if (!yaffs_ValidateTags(tags)) {
|
||||
tags->seq_number = dev->seq_number;
|
||||
tags->chunk_used = 1;
|
||||
if (!yaffs_validate_tags(tags)) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR("Writing uninitialised tags" TENDSTR)));
|
||||
YBUG();
|
||||
}
|
||||
T(YAFFS_TRACE_WRITE,
|
||||
(TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
|
||||
tags->objectId, tags->chunkId));
|
||||
(TSTR("Writing chunk %d tags %d %d" TENDSTR), nand_chunk,
|
||||
tags->obj_id, tags->chunk_id));
|
||||
} else {
|
||||
T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
|
||||
YBUG();
|
||||
}
|
||||
|
||||
if (dev->param.writeChunkWithTagsToNAND)
|
||||
return dev->param.writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
|
||||
tags);
|
||||
if (dev->param.write_chunk_tags_fn)
|
||||
return dev->param.write_chunk_tags_fn(dev, nand_chunk, buffer,
|
||||
tags);
|
||||
else
|
||||
return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
|
||||
chunkInNAND,
|
||||
buffer,
|
||||
tags);
|
||||
return yaffs_tags_compat_wr(dev, nand_chunk, buffer, tags);
|
||||
}
|
||||
|
||||
int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo)
|
||||
int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
|
||||
{
|
||||
blockNo -= dev->blockOffset;
|
||||
block_no -= dev->block_offset;
|
||||
|
||||
|
||||
if (dev->param.markNANDBlockBad)
|
||||
return dev->param.markNANDBlockBad(dev, blockNo);
|
||||
if (dev->param.bad_block_fn)
|
||||
return dev->param.bad_block_fn(dev, block_no);
|
||||
else
|
||||
return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
|
||||
return yaffs_tags_compat_mark_bad(dev, block_no);
|
||||
}
|
||||
|
||||
int yaffs_QueryInitialBlockState(yaffs_Device *dev,
|
||||
int blockNo,
|
||||
yaffs_BlockState *state,
|
||||
__u32 *sequenceNumber)
|
||||
int yaffs_query_init_block_state(struct yaffs_dev *dev,
|
||||
int block_no,
|
||||
enum yaffs_block_state *state,
|
||||
u32 * seq_number)
|
||||
{
|
||||
blockNo -= dev->blockOffset;
|
||||
block_no -= dev->block_offset;
|
||||
|
||||
if (dev->param.queryNANDBlock)
|
||||
return dev->param.queryNANDBlock(dev, blockNo, state, sequenceNumber);
|
||||
if (dev->param.query_block_fn)
|
||||
return dev->param.query_block_fn(dev, block_no, state,
|
||||
seq_number);
|
||||
else
|
||||
return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
|
||||
state,
|
||||
sequenceNumber);
|
||||
return yaffs_tags_compat_query_block(dev, block_no,
|
||||
state, seq_number);
|
||||
}
|
||||
|
||||
|
||||
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
|
||||
int blockInNAND)
|
||||
int yaffs_erase_block(struct yaffs_dev *dev, int flash_block)
|
||||
{
|
||||
int result;
|
||||
|
||||
blockInNAND -= dev->blockOffset;
|
||||
flash_block -= dev->block_offset;
|
||||
|
||||
dev->nBlockErasures++;
|
||||
dev->n_erasures++;
|
||||
|
||||
result = dev->param.eraseBlockInNAND(dev, blockInNAND);
|
||||
result = dev->param.erase_fn(dev, flash_block);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
|
||||
int yaffs_init_nand(struct yaffs_dev *dev)
|
||||
{
|
||||
if(dev->param.initialiseNAND)
|
||||
return dev->param.initialiseNAND(dev);
|
||||
if (dev->param.initialise_flash_fn)
|
||||
return dev->param.initialise_flash_fn(dev);
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -17,28 +17,22 @@
|
||||
#define __YAFFS_NAND_H__
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
|
||||
u8 * buffer, struct yaffs_ext_tags *tags);
|
||||
|
||||
int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
|
||||
int nand_chunk,
|
||||
const u8 * buffer, struct yaffs_ext_tags *tags);
|
||||
|
||||
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
|
||||
__u8 *buffer,
|
||||
yaffs_ExtendedTags *tags);
|
||||
int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
|
||||
|
||||
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,
|
||||
int chunkInNAND,
|
||||
const __u8 *buffer,
|
||||
yaffs_ExtendedTags *tags);
|
||||
int yaffs_query_init_block_state(struct yaffs_dev *dev,
|
||||
int block_no,
|
||||
enum yaffs_block_state *state,
|
||||
unsigned *seq_number);
|
||||
|
||||
int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo);
|
||||
int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
|
||||
|
||||
int yaffs_QueryInitialBlockState(yaffs_Device *dev,
|
||||
int blockNo,
|
||||
yaffs_BlockState *state,
|
||||
unsigned *sequenceNumber);
|
||||
|
||||
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
|
||||
int blockInNAND);
|
||||
|
||||
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);
|
||||
int yaffs_init_nand(struct yaffs_dev *dev);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2010 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
/* Interface to emulated NAND functions (2k page size) */
|
||||
|
||||
#ifndef __YAFFS_NANDEMUL2K_H__
|
||||
#define __YAFFS_NANDEMUL2K_H__
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
|
||||
int chunkInNAND, const __u8 *data,
|
||||
const yaffs_ExtendedTags *tags);
|
||||
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
|
||||
int chunkInNAND, __u8 *data,
|
||||
yaffs_ExtendedTags *tags);
|
||||
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
|
||||
int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||
yaffs_BlockState *state, __u32 *sequenceNumber);
|
||||
int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
|
||||
int blockInNAND);
|
||||
int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
|
||||
int nandemul2k_GetBytesPerChunk(void);
|
||||
int nandemul2k_GetChunksPerBlock(void);
|
||||
int nandemul2k_GetNumberOfBlocks(void);
|
||||
|
||||
#endif
|
@ -14,37 +14,40 @@
|
||||
#include "yaffs_packedtags1.h"
|
||||
#include "yportenv.h"
|
||||
|
||||
void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t)
|
||||
void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
|
||||
const struct yaffs_ext_tags *t)
|
||||
{
|
||||
pt->chunkId = t->chunkId;
|
||||
pt->serialNumber = t->serialNumber;
|
||||
pt->byteCount = t->byteCount;
|
||||
pt->objectId = t->objectId;
|
||||
pt->chunk_id = t->chunk_id;
|
||||
pt->serial_number = t->serial_number;
|
||||
pt->n_bytes = t->n_bytes;
|
||||
pt->obj_id = t->obj_id;
|
||||
pt->ecc = 0;
|
||||
pt->deleted = (t->chunkDeleted) ? 0 : 1;
|
||||
pt->unusedStuff = 0;
|
||||
pt->shouldBeFF = 0xFFFFFFFF;
|
||||
pt->deleted = (t->is_deleted) ? 0 : 1;
|
||||
pt->unused_stuff = 0;
|
||||
pt->should_be_ff = 0xFFFFFFFF;
|
||||
|
||||
}
|
||||
|
||||
void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt)
|
||||
void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
|
||||
const struct yaffs_packed_tags1 *pt)
|
||||
{
|
||||
static const __u8 allFF[] =
|
||||
static const u8 all_ff[] =
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff };
|
||||
0xff
|
||||
};
|
||||
|
||||
if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {
|
||||
t->blockBad = 0;
|
||||
if (pt->shouldBeFF != 0xFFFFFFFF)
|
||||
t->blockBad = 1;
|
||||
t->chunkUsed = 1;
|
||||
t->objectId = pt->objectId;
|
||||
t->chunkId = pt->chunkId;
|
||||
t->byteCount = pt->byteCount;
|
||||
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
t->chunkDeleted = (pt->deleted) ? 0 : 1;
|
||||
t->serialNumber = pt->serialNumber;
|
||||
if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) {
|
||||
t->block_bad = 0;
|
||||
if (pt->should_be_ff != 0xFFFFFFFF)
|
||||
t->block_bad = 1;
|
||||
t->chunk_used = 1;
|
||||
t->obj_id = pt->obj_id;
|
||||
t->chunk_id = pt->chunk_id;
|
||||
t->n_bytes = pt->n_bytes;
|
||||
t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
t->is_deleted = (pt->deleted) ? 0 : 1;
|
||||
t->serial_number = pt->serial_number;
|
||||
} else {
|
||||
memset(t, 0, sizeof(yaffs_ExtendedTags));
|
||||
memset(t, 0, sizeof(struct yaffs_ext_tags));
|
||||
}
|
||||
}
|
||||
|
@ -20,18 +20,20 @@
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned chunkId:20;
|
||||
unsigned serialNumber:2;
|
||||
unsigned byteCount:10;
|
||||
unsigned objectId:18;
|
||||
struct yaffs_packed_tags1 {
|
||||
unsigned chunk_id:20;
|
||||
unsigned serial_number:2;
|
||||
unsigned n_bytes:10;
|
||||
unsigned obj_id:18;
|
||||
unsigned ecc:12;
|
||||
unsigned deleted:1;
|
||||
unsigned unusedStuff:1;
|
||||
unsigned shouldBeFF;
|
||||
unsigned unused_stuff:1;
|
||||
unsigned should_be_ff;
|
||||
|
||||
} yaffs_PackedTags1;
|
||||
};
|
||||
|
||||
void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t);
|
||||
void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt);
|
||||
void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
|
||||
const struct yaffs_ext_tags *t);
|
||||
void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
|
||||
const struct yaffs_packed_tags1 *pt);
|
||||
#endif
|
||||
|
@ -25,7 +25,7 @@
|
||||
* This is defined by having the EXTRA_HEADER_INFO_FLAG set.
|
||||
*/
|
||||
|
||||
/* Extra flags applied to chunkId */
|
||||
/* Extra flags applied to chunk_id */
|
||||
|
||||
#define EXTRA_HEADER_INFO_FLAG 0x80000000
|
||||
#define EXTRA_SHRINK_FLAG 0x40000000
|
||||
@ -38,161 +38,160 @@
|
||||
#define EXTRA_OBJECT_TYPE_SHIFT (28)
|
||||
#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
|
||||
|
||||
|
||||
static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart *ptt)
|
||||
static void yaffs_dump_packed_tags2_tags_only(const struct
|
||||
yaffs_packed_tags2_tags_only *ptt)
|
||||
{
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
|
||||
ptt->objectId, ptt->chunkId, ptt->byteCount,
|
||||
ptt->sequenceNumber));
|
||||
}
|
||||
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt)
|
||||
{
|
||||
yaffs_DumpPackedTags2TagsPart(&pt->t);
|
||||
ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number));
|
||||
}
|
||||
|
||||
static void yaffs_DumpTags2(const yaffs_ExtendedTags *t)
|
||||
static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
|
||||
{
|
||||
yaffs_dump_packed_tags2_tags_only(&pt->t);
|
||||
}
|
||||
|
||||
static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
|
||||
{
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR
|
||||
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
|
||||
TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
|
||||
t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
|
||||
t->sequenceNumber));
|
||||
TENDSTR), t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
|
||||
t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
|
||||
t->seq_number));
|
||||
|
||||
}
|
||||
|
||||
void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt,
|
||||
const yaffs_ExtendedTags *t)
|
||||
void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
|
||||
const struct yaffs_ext_tags *t)
|
||||
{
|
||||
ptt->chunkId = t->chunkId;
|
||||
ptt->sequenceNumber = t->sequenceNumber;
|
||||
ptt->byteCount = t->byteCount;
|
||||
ptt->objectId = t->objectId;
|
||||
ptt->chunk_id = t->chunk_id;
|
||||
ptt->seq_number = t->seq_number;
|
||||
ptt->n_bytes = t->n_bytes;
|
||||
ptt->obj_id = t->obj_id;
|
||||
|
||||
if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
|
||||
if (t->chunk_id == 0 && t->extra_available) {
|
||||
/* Store the extra header info instead */
|
||||
/* We save the parent object in the chunkId */
|
||||
ptt->chunkId = EXTRA_HEADER_INFO_FLAG
|
||||
| t->extraParentObjectId;
|
||||
if (t->extraIsShrinkHeader)
|
||||
ptt->chunkId |= EXTRA_SHRINK_FLAG;
|
||||
if (t->extraShadows)
|
||||
ptt->chunkId |= EXTRA_SHADOWS_FLAG;
|
||||
/* We save the parent object in the chunk_id */
|
||||
ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
|
||||
if (t->extra_is_shrink)
|
||||
ptt->chunk_id |= EXTRA_SHRINK_FLAG;
|
||||
if (t->extra_shadows)
|
||||
ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
|
||||
|
||||
ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
ptt->objectId |=
|
||||
(t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
|
||||
ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
|
||||
|
||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
|
||||
ptt->byteCount = t->extraEquivalentObjectId;
|
||||
else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE)
|
||||
ptt->byteCount = t->extraFileLength;
|
||||
if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
|
||||
ptt->n_bytes = t->extra_equiv_id;
|
||||
else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
|
||||
ptt->n_bytes = t->extra_length;
|
||||
else
|
||||
ptt->byteCount = 0;
|
||||
ptt->n_bytes = 0;
|
||||
}
|
||||
|
||||
yaffs_DumpPackedTags2TagsPart(ptt);
|
||||
yaffs_DumpTags2(t);
|
||||
yaffs_dump_packed_tags2_tags_only(ptt);
|
||||
yaffs_dump_tags2(t);
|
||||
}
|
||||
|
||||
|
||||
void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC)
|
||||
void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
|
||||
const struct yaffs_ext_tags *t, int tags_ecc)
|
||||
{
|
||||
yaffs_PackTags2TagsPart(&pt->t, t);
|
||||
yaffs_pack_tags2_tags_only(&pt->t, t);
|
||||
|
||||
if(tagsECC)
|
||||
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
|
||||
sizeof(yaffs_PackedTags2TagsPart),
|
||||
&pt->ecc);
|
||||
if (tags_ecc)
|
||||
yaffs_ecc_calc_other((unsigned char *)&pt->t,
|
||||
sizeof(struct
|
||||
yaffs_packed_tags2_tags_only),
|
||||
&pt->ecc);
|
||||
}
|
||||
|
||||
|
||||
void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t,
|
||||
yaffs_PackedTags2TagsPart *ptt)
|
||||
void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
|
||||
struct yaffs_packed_tags2_tags_only *ptt)
|
||||
{
|
||||
|
||||
memset(t, 0, sizeof(yaffs_ExtendedTags));
|
||||
memset(t, 0, sizeof(struct yaffs_ext_tags));
|
||||
|
||||
yaffs_InitialiseTags(t);
|
||||
yaffs_init_tags(t);
|
||||
|
||||
if (ptt->sequenceNumber != 0xFFFFFFFF) {
|
||||
t->blockBad = 0;
|
||||
t->chunkUsed = 1;
|
||||
t->objectId = ptt->objectId;
|
||||
t->chunkId = ptt->chunkId;
|
||||
t->byteCount = ptt->byteCount;
|
||||
t->chunkDeleted = 0;
|
||||
t->serialNumber = 0;
|
||||
t->sequenceNumber = ptt->sequenceNumber;
|
||||
if (ptt->seq_number != 0xFFFFFFFF) {
|
||||
t->block_bad = 0;
|
||||
t->chunk_used = 1;
|
||||
t->obj_id = ptt->obj_id;
|
||||
t->chunk_id = ptt->chunk_id;
|
||||
t->n_bytes = ptt->n_bytes;
|
||||
t->is_deleted = 0;
|
||||
t->serial_number = 0;
|
||||
t->seq_number = ptt->seq_number;
|
||||
|
||||
/* Do extra header info stuff */
|
||||
|
||||
if (ptt->chunkId & EXTRA_HEADER_INFO_FLAG) {
|
||||
t->chunkId = 0;
|
||||
t->byteCount = 0;
|
||||
if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
|
||||
t->chunk_id = 0;
|
||||
t->n_bytes = 0;
|
||||
|
||||
t->extraHeaderInfoAvailable = 1;
|
||||
t->extraParentObjectId =
|
||||
ptt->chunkId & (~(ALL_EXTRA_FLAGS));
|
||||
t->extraIsShrinkHeader =
|
||||
(ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
|
||||
t->extraShadows =
|
||||
(ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
|
||||
t->extraObjectType =
|
||||
ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT;
|
||||
t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
t->extra_available = 1;
|
||||
t->extra_parent_id =
|
||||
ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
|
||||
t->extra_is_shrink =
|
||||
(ptt->chunk_id & EXTRA_SHRINK_FLAG) ? 1 : 0;
|
||||
t->extra_shadows =
|
||||
(ptt->chunk_id & EXTRA_SHADOWS_FLAG) ? 1 : 0;
|
||||
t->extra_obj_type =
|
||||
ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
|
||||
t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||
|
||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
|
||||
t->extraEquivalentObjectId = ptt->byteCount;
|
||||
if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
|
||||
t->extra_equiv_id = ptt->n_bytes;
|
||||
else
|
||||
t->extraFileLength = ptt->byteCount;
|
||||
t->extra_length = ptt->n_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
yaffs_DumpPackedTags2TagsPart(ptt);
|
||||
yaffs_DumpTags2(t);
|
||||
yaffs_dump_packed_tags2_tags_only(ptt);
|
||||
yaffs_dump_tags2(t);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC)
|
||||
void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
|
||||
int tags_ecc)
|
||||
{
|
||||
|
||||
yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
|
||||
if (pt->t.sequenceNumber != 0xFFFFFFFF &&
|
||||
tagsECC){
|
||||
if (pt->t.seq_number != 0xFFFFFFFF && tags_ecc) {
|
||||
/* Chunk is in use and we need to do ECC */
|
||||
|
||||
yaffs_ECCOther ecc;
|
||||
|
||||
struct yaffs_ecc_other ecc;
|
||||
int result;
|
||||
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
|
||||
sizeof(yaffs_PackedTags2TagsPart),
|
||||
&ecc);
|
||||
result = yaffs_ECCCorrectOther((unsigned char *)&pt->t,
|
||||
sizeof(yaffs_PackedTags2TagsPart),
|
||||
&pt->ecc, &ecc);
|
||||
yaffs_ecc_calc_other((unsigned char *)&pt->t,
|
||||
sizeof(struct
|
||||
yaffs_packed_tags2_tags_only),
|
||||
&ecc);
|
||||
result =
|
||||
yaffs_ecc_correct_other((unsigned char *)&pt->t,
|
||||
sizeof(struct
|
||||
yaffs_packed_tags2_tags_only),
|
||||
&pt->ecc, &ecc);
|
||||
switch (result) {
|
||||
case 0:
|
||||
eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
break;
|
||||
case 1:
|
||||
eccResult = YAFFS_ECC_RESULT_FIXED;
|
||||
break;
|
||||
case -1:
|
||||
eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
||||
break;
|
||||
default:
|
||||
eccResult = YAFFS_ECC_RESULT_UNKNOWN;
|
||||
case 0:
|
||||
ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
break;
|
||||
case 1:
|
||||
ecc_result = YAFFS_ECC_RESULT_FIXED;
|
||||
break;
|
||||
case -1:
|
||||
ecc_result = YAFFS_ECC_RESULT_UNFIXED;
|
||||
break;
|
||||
default:
|
||||
ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
yaffs_UnpackTags2TagsPart(t, &pt->t);
|
||||
yaffs_unpack_tags2_tags_only(t, &pt->t);
|
||||
|
||||
t->eccResult = eccResult;
|
||||
t->ecc_result = ecc_result;
|
||||
|
||||
yaffs_DumpPackedTags2(pt);
|
||||
yaffs_DumpTags2(t);
|
||||
yaffs_dump_packed_tags2(pt);
|
||||
yaffs_dump_tags2(t);
|
||||
}
|
||||
|
||||
|
@ -21,23 +21,27 @@
|
||||
#include "yaffs_guts.h"
|
||||
#include "yaffs_ecc.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned sequenceNumber;
|
||||
unsigned objectId;
|
||||
unsigned chunkId;
|
||||
unsigned byteCount;
|
||||
} yaffs_PackedTags2TagsPart;
|
||||
struct yaffs_packed_tags2_tags_only {
|
||||
unsigned seq_number;
|
||||
unsigned obj_id;
|
||||
unsigned chunk_id;
|
||||
unsigned n_bytes;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
yaffs_PackedTags2TagsPart t;
|
||||
yaffs_ECCOther ecc;
|
||||
} yaffs_PackedTags2;
|
||||
struct yaffs_packed_tags2 {
|
||||
struct yaffs_packed_tags2_tags_only t;
|
||||
struct yaffs_ecc_other ecc;
|
||||
};
|
||||
|
||||
/* Full packed tags with ECC, used for oob tags */
|
||||
void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC);
|
||||
void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt, int tagsECC);
|
||||
void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
|
||||
const struct yaffs_ext_tags *t, int tags_ecc);
|
||||
void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
|
||||
int tags_ecc);
|
||||
|
||||
/* Only the tags part (no ECC for use with inband tags */
|
||||
void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ExtendedTags *t);
|
||||
void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, yaffs_PackedTags2TagsPart *pt);
|
||||
void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
|
||||
const struct yaffs_ext_tags *t);
|
||||
void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
|
||||
struct yaffs_packed_tags2_tags_only *pt);
|
||||
#endif
|
||||
|
@ -1,163 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "yportenv.h"
|
||||
/* #include <linux/string.h> */
|
||||
|
||||
/*
|
||||
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
|
||||
*/
|
||||
#define swapcode(TYPE, parmi, parmj, n) do { \
|
||||
long i = (n) / sizeof (TYPE); \
|
||||
register TYPE *pi = (TYPE *) (parmi); \
|
||||
register TYPE *pj = (TYPE *) (parmj); \
|
||||
do { \
|
||||
register TYPE t = *pi; \
|
||||
*pi++ = *pj; \
|
||||
*pj++ = t; \
|
||||
} while (--i > 0); \
|
||||
} while (0)
|
||||
|
||||
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
|
||||
es % sizeof(long) ? 2 : es == sizeof(long) ? 0 : 1;
|
||||
|
||||
static __inline void
|
||||
swapfunc(char *a, char *b, int n, int swaptype)
|
||||
{
|
||||
if (swaptype <= 1)
|
||||
swapcode(long, a, b, n);
|
||||
else
|
||||
swapcode(char, a, b, n);
|
||||
}
|
||||
|
||||
#define yswap(a, b) do { \
|
||||
if (swaptype == 0) { \
|
||||
long t = *(long *)(a); \
|
||||
*(long *)(a) = *(long *)(b); \
|
||||
*(long *)(b) = t; \
|
||||
} else \
|
||||
swapfunc(a, b, es, swaptype); \
|
||||
} while (0)
|
||||
|
||||
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
|
||||
|
||||
static __inline char *
|
||||
med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
|
||||
{
|
||||
return cmp(a, b) < 0 ?
|
||||
(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a))
|
||||
: (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c));
|
||||
}
|
||||
|
||||
#ifndef min
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
void
|
||||
yaffs_qsort(void *aa, size_t n, size_t es,
|
||||
int (*cmp)(const void *, const void *))
|
||||
{
|
||||
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
|
||||
int d, r, swaptype, swap_cnt;
|
||||
register char *a = aa;
|
||||
|
||||
loop: SWAPINIT(a, es);
|
||||
swap_cnt = 0;
|
||||
if (n < 7) {
|
||||
for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
|
||||
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
|
||||
pl -= es)
|
||||
yswap(pl, pl - es);
|
||||
return;
|
||||
}
|
||||
pm = (char *)a + (n / 2) * es;
|
||||
if (n > 7) {
|
||||
pl = (char *)a;
|
||||
pn = (char *)a + (n - 1) * es;
|
||||
if (n > 40) {
|
||||
d = (n / 8) * es;
|
||||
pl = med3(pl, pl + d, pl + 2 * d, cmp);
|
||||
pm = med3(pm - d, pm, pm + d, cmp);
|
||||
pn = med3(pn - 2 * d, pn - d, pn, cmp);
|
||||
}
|
||||
pm = med3(pl, pm, pn, cmp);
|
||||
}
|
||||
yswap(a, pm);
|
||||
pa = pb = (char *)a + es;
|
||||
|
||||
pc = pd = (char *)a + (n - 1) * es;
|
||||
for (;;) {
|
||||
while (pb <= pc && (r = cmp(pb, a)) <= 0) {
|
||||
if (r == 0) {
|
||||
swap_cnt = 1;
|
||||
yswap(pa, pb);
|
||||
pa += es;
|
||||
}
|
||||
pb += es;
|
||||
}
|
||||
while (pb <= pc && (r = cmp(pc, a)) >= 0) {
|
||||
if (r == 0) {
|
||||
swap_cnt = 1;
|
||||
yswap(pc, pd);
|
||||
pd -= es;
|
||||
}
|
||||
pc -= es;
|
||||
}
|
||||
if (pb > pc)
|
||||
break;
|
||||
yswap(pb, pc);
|
||||
swap_cnt = 1;
|
||||
pb += es;
|
||||
pc -= es;
|
||||
}
|
||||
if (swap_cnt == 0) { /* Switch to insertion sort */
|
||||
for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
|
||||
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
|
||||
pl -= es)
|
||||
yswap(pl, pl - es);
|
||||
return;
|
||||
}
|
||||
|
||||
pn = (char *)a + n * es;
|
||||
r = min(pa - (char *)a, pb - pa);
|
||||
vecswap(a, pb - r, r);
|
||||
r = min((long)(pd - pc), (long)(pn - pd - es));
|
||||
vecswap(pb, pn - r, r);
|
||||
r = pb - pa;
|
||||
if (r > es)
|
||||
yaffs_qsort(a, r / es, es, cmp);
|
||||
r = pd - pc;
|
||||
if (r > es) {
|
||||
/* Iterate rather than recurse to save stack space */
|
||||
a = pn - r;
|
||||
n = r / es;
|
||||
goto loop;
|
||||
}
|
||||
/* yaffs_qsort(pn - r, r / es, es, cmp);*/
|
||||
}
|
@ -17,18 +17,9 @@
|
||||
#include "yaffs_getblockinfo.h"
|
||||
#include "yaffs_trace.h"
|
||||
|
||||
static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND);
|
||||
#ifdef NOTYET
|
||||
static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND);
|
||||
static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
|
||||
const __u8 *data,
|
||||
const yaffs_Spare *spare);
|
||||
static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
|
||||
const yaffs_Spare *spare);
|
||||
static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND);
|
||||
#endif
|
||||
static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
|
||||
|
||||
static const char yaffs_countBitsTable[256] = {
|
||||
static const char yaffs_count_bits_table[256] = {
|
||||
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
@ -47,26 +38,26 @@ static const char yaffs_countBitsTable[256] = {
|
||||
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
|
||||
};
|
||||
|
||||
int yaffs_CountBits(__u8 x)
|
||||
int yaffs_count_bits(u8 x)
|
||||
{
|
||||
int retVal;
|
||||
retVal = yaffs_countBitsTable[x];
|
||||
return retVal;
|
||||
int ret_val;
|
||||
ret_val = yaffs_count_bits_table[x];
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/********** Tags ECC calculations *********/
|
||||
|
||||
void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
|
||||
void yaffs_calc_ecc(const u8 * data, struct yaffs_spare *spare)
|
||||
{
|
||||
yaffs_ECCCalculate(data, spare->ecc1);
|
||||
yaffs_ECCCalculate(&data[256], spare->ecc2);
|
||||
yaffs_ecc_cacl(data, spare->ecc1);
|
||||
yaffs_ecc_cacl(&data[256], spare->ecc2);
|
||||
}
|
||||
|
||||
void yaffs_CalcTagsECC(yaffs_Tags *tags)
|
||||
void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
|
||||
{
|
||||
/* Calculate an ecc */
|
||||
|
||||
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
|
||||
unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
|
||||
unsigned i, j;
|
||||
unsigned ecc = 0;
|
||||
unsigned bit = 0;
|
||||
@ -85,24 +76,24 @@ void yaffs_CalcTagsECC(yaffs_Tags *tags)
|
||||
|
||||
}
|
||||
|
||||
int yaffs_CheckECCOnTags(yaffs_Tags *tags)
|
||||
int yaffs_check_tags_ecc(struct yaffs_tags *tags)
|
||||
{
|
||||
unsigned ecc = tags->ecc;
|
||||
|
||||
yaffs_CalcTagsECC(tags);
|
||||
yaffs_calc_tags_ecc(tags);
|
||||
|
||||
ecc ^= tags->ecc;
|
||||
|
||||
if (ecc && ecc <= 64) {
|
||||
/* TODO: Handle the failure better. Retire? */
|
||||
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
|
||||
unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
|
||||
|
||||
ecc--;
|
||||
|
||||
b[ecc / 8] ^= (1 << (ecc & 7));
|
||||
|
||||
/* Now recvalc the ecc */
|
||||
yaffs_CalcTagsECC(tags);
|
||||
yaffs_calc_tags_ecc(tags);
|
||||
|
||||
return 1; /* recovered error */
|
||||
} else if (ecc) {
|
||||
@ -116,227 +107,205 @@ int yaffs_CheckECCOnTags(yaffs_Tags *tags)
|
||||
|
||||
/********** Tags **********/
|
||||
|
||||
static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr,
|
||||
yaffs_Tags *tagsPtr)
|
||||
static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
|
||||
struct yaffs_tags *tags_ptr)
|
||||
{
|
||||
yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
|
||||
union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
|
||||
|
||||
yaffs_CalcTagsECC(tagsPtr);
|
||||
yaffs_calc_tags_ecc(tags_ptr);
|
||||
|
||||
sparePtr->tagByte0 = tu->asBytes[0];
|
||||
sparePtr->tagByte1 = tu->asBytes[1];
|
||||
sparePtr->tagByte2 = tu->asBytes[2];
|
||||
sparePtr->tagByte3 = tu->asBytes[3];
|
||||
sparePtr->tagByte4 = tu->asBytes[4];
|
||||
sparePtr->tagByte5 = tu->asBytes[5];
|
||||
sparePtr->tagByte6 = tu->asBytes[6];
|
||||
sparePtr->tagByte7 = tu->asBytes[7];
|
||||
spare_ptr->tb0 = tu->as_bytes[0];
|
||||
spare_ptr->tb1 = tu->as_bytes[1];
|
||||
spare_ptr->tb2 = tu->as_bytes[2];
|
||||
spare_ptr->tb3 = tu->as_bytes[3];
|
||||
spare_ptr->tb4 = tu->as_bytes[4];
|
||||
spare_ptr->tb5 = tu->as_bytes[5];
|
||||
spare_ptr->tb6 = tu->as_bytes[6];
|
||||
spare_ptr->tb7 = tu->as_bytes[7];
|
||||
}
|
||||
|
||||
static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,
|
||||
yaffs_Tags *tagsPtr)
|
||||
static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
|
||||
struct yaffs_spare *spare_ptr,
|
||||
struct yaffs_tags *tags_ptr)
|
||||
{
|
||||
yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
|
||||
union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
|
||||
int result;
|
||||
|
||||
tu->asBytes[0] = sparePtr->tagByte0;
|
||||
tu->asBytes[1] = sparePtr->tagByte1;
|
||||
tu->asBytes[2] = sparePtr->tagByte2;
|
||||
tu->asBytes[3] = sparePtr->tagByte3;
|
||||
tu->asBytes[4] = sparePtr->tagByte4;
|
||||
tu->asBytes[5] = sparePtr->tagByte5;
|
||||
tu->asBytes[6] = sparePtr->tagByte6;
|
||||
tu->asBytes[7] = sparePtr->tagByte7;
|
||||
tu->as_bytes[0] = spare_ptr->tb0;
|
||||
tu->as_bytes[1] = spare_ptr->tb1;
|
||||
tu->as_bytes[2] = spare_ptr->tb2;
|
||||
tu->as_bytes[3] = spare_ptr->tb3;
|
||||
tu->as_bytes[4] = spare_ptr->tb4;
|
||||
tu->as_bytes[5] = spare_ptr->tb5;
|
||||
tu->as_bytes[6] = spare_ptr->tb6;
|
||||
tu->as_bytes[7] = spare_ptr->tb7;
|
||||
|
||||
result = yaffs_CheckECCOnTags(tagsPtr);
|
||||
result = yaffs_check_tags_ecc(tags_ptr);
|
||||
if (result > 0)
|
||||
dev->tagsEccFixed++;
|
||||
dev->n_tags_ecc_fixed++;
|
||||
else if (result < 0)
|
||||
dev->tagsEccUnfixed++;
|
||||
dev->n_tags_ecc_unfixed++;
|
||||
}
|
||||
|
||||
static void yaffs_SpareInitialise(yaffs_Spare *spare)
|
||||
static void yaffs_spare_init(struct yaffs_spare *spare)
|
||||
{
|
||||
memset(spare, 0xFF, sizeof(yaffs_Spare));
|
||||
memset(spare, 0xFF, sizeof(struct yaffs_spare));
|
||||
}
|
||||
|
||||
static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
|
||||
int chunkInNAND, const __u8 *data,
|
||||
yaffs_Spare *spare)
|
||||
static int yaffs_wr_nand(struct yaffs_dev *dev,
|
||||
int nand_chunk, const u8 * data,
|
||||
struct yaffs_spare *spare)
|
||||
{
|
||||
if (chunkInNAND < dev->param.startBlock * dev->param.nChunksPerBlock) {
|
||||
if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
|
||||
chunkInNAND));
|
||||
nand_chunk));
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
return dev->param.writeChunkToNAND(dev, chunkInNAND, data, spare);
|
||||
return dev->param.write_chunk_fn(dev, nand_chunk, data, spare);
|
||||
}
|
||||
|
||||
static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
|
||||
int chunkInNAND,
|
||||
__u8 *data,
|
||||
yaffs_Spare *spare,
|
||||
yaffs_ECCResult *eccResult,
|
||||
int doErrorCorrection)
|
||||
static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
|
||||
int nand_chunk,
|
||||
u8 * data,
|
||||
struct yaffs_spare *spare,
|
||||
enum yaffs_ecc_result *ecc_result,
|
||||
int correct_errors)
|
||||
{
|
||||
int retVal;
|
||||
yaffs_Spare localSpare;
|
||||
int ret_val;
|
||||
struct yaffs_spare local_spare;
|
||||
|
||||
if (!spare && data) {
|
||||
/* If we don't have a real spare, then we use a local one. */
|
||||
/* Need this for the calculation of the ecc */
|
||||
spare = &localSpare;
|
||||
spare = &local_spare;
|
||||
}
|
||||
|
||||
if (!dev->param.useNANDECC) {
|
||||
retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data, spare);
|
||||
if (data && doErrorCorrection) {
|
||||
if (!dev->param.use_nand_ecc) {
|
||||
ret_val =
|
||||
dev->param.read_chunk_fn(dev, nand_chunk, data, spare);
|
||||
if (data && correct_errors) {
|
||||
/* Do ECC correction */
|
||||
/* Todo handle any errors */
|
||||
int eccResult1, eccResult2;
|
||||
__u8 calcEcc[3];
|
||||
int ecc_result1, ecc_result2;
|
||||
u8 calc_ecc[3];
|
||||
|
||||
yaffs_ECCCalculate(data, calcEcc);
|
||||
eccResult1 =
|
||||
yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
|
||||
yaffs_ECCCalculate(&data[256], calcEcc);
|
||||
eccResult2 =
|
||||
yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
|
||||
yaffs_ecc_cacl(data, calc_ecc);
|
||||
ecc_result1 =
|
||||
yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
|
||||
yaffs_ecc_cacl(&data[256], calc_ecc);
|
||||
ecc_result2 =
|
||||
yaffs_ecc_correct(&data[256], spare->ecc2,
|
||||
calc_ecc);
|
||||
|
||||
if (eccResult1 > 0) {
|
||||
if (ecc_result1 > 0) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>>yaffs ecc error fix performed on chunk %d:0"
|
||||
TENDSTR), chunkInNAND));
|
||||
dev->eccFixed++;
|
||||
} else if (eccResult1 < 0) {
|
||||
TENDSTR), nand_chunk));
|
||||
dev->n_ecc_fixed++;
|
||||
} else if (ecc_result1 < 0) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>>yaffs ecc error unfixed on chunk %d:0"
|
||||
TENDSTR), chunkInNAND));
|
||||
dev->eccUnfixed++;
|
||||
TENDSTR), nand_chunk));
|
||||
dev->n_ecc_unfixed++;
|
||||
}
|
||||
|
||||
if (eccResult2 > 0) {
|
||||
if (ecc_result2 > 0) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>>yaffs ecc error fix performed on chunk %d:1"
|
||||
TENDSTR), chunkInNAND));
|
||||
dev->eccFixed++;
|
||||
} else if (eccResult2 < 0) {
|
||||
TENDSTR), nand_chunk));
|
||||
dev->n_ecc_fixed++;
|
||||
} else if (ecc_result2 < 0) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>>yaffs ecc error unfixed on chunk %d:1"
|
||||
TENDSTR), chunkInNAND));
|
||||
dev->eccUnfixed++;
|
||||
TENDSTR), nand_chunk));
|
||||
dev->n_ecc_unfixed++;
|
||||
}
|
||||
|
||||
if (eccResult1 || eccResult2) {
|
||||
if (ecc_result1 || ecc_result2) {
|
||||
/* We had a data problem on this page */
|
||||
yaffs_HandleReadDataError(dev, chunkInNAND);
|
||||
yaffs_handle_rd_data_error(dev, nand_chunk);
|
||||
}
|
||||
|
||||
if (eccResult1 < 0 || eccResult2 < 0)
|
||||
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
||||
else if (eccResult1 > 0 || eccResult2 > 0)
|
||||
*eccResult = YAFFS_ECC_RESULT_FIXED;
|
||||
if (ecc_result1 < 0 || ecc_result2 < 0)
|
||||
*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
|
||||
else if (ecc_result1 > 0 || ecc_result2 > 0)
|
||||
*ecc_result = YAFFS_ECC_RESULT_FIXED;
|
||||
else
|
||||
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
}
|
||||
} else {
|
||||
/* Must allocate enough memory for spare+2*sizeof(int) */
|
||||
/* for ecc results from device. */
|
||||
struct yaffs_NANDSpare nspare;
|
||||
struct yaffs_nand_spare nspare;
|
||||
|
||||
memset(&nspare, 0, sizeof(nspare));
|
||||
|
||||
retVal = dev->param.readChunkFromNAND(dev, chunkInNAND, data,
|
||||
(yaffs_Spare *) &nspare);
|
||||
memcpy(spare, &nspare, sizeof(yaffs_Spare));
|
||||
if (data && doErrorCorrection) {
|
||||
ret_val = dev->param.read_chunk_fn(dev, nand_chunk, data,
|
||||
(struct yaffs_spare *)
|
||||
&nspare);
|
||||
memcpy(spare, &nspare, sizeof(struct yaffs_spare));
|
||||
if (data && correct_errors) {
|
||||
if (nspare.eccres1 > 0) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>>mtd ecc error fix performed on chunk %d:0"
|
||||
TENDSTR), chunkInNAND));
|
||||
TENDSTR), nand_chunk));
|
||||
} else if (nspare.eccres1 < 0) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>>mtd ecc error unfixed on chunk %d:0"
|
||||
TENDSTR), chunkInNAND));
|
||||
TENDSTR), nand_chunk));
|
||||
}
|
||||
|
||||
if (nspare.eccres2 > 0) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>>mtd ecc error fix performed on chunk %d:1"
|
||||
TENDSTR), chunkInNAND));
|
||||
TENDSTR), nand_chunk));
|
||||
} else if (nspare.eccres2 < 0) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("**>>mtd ecc error unfixed on chunk %d:1"
|
||||
TENDSTR), chunkInNAND));
|
||||
TENDSTR), nand_chunk));
|
||||
}
|
||||
|
||||
if (nspare.eccres1 || nspare.eccres2) {
|
||||
/* We had a data problem on this page */
|
||||
yaffs_HandleReadDataError(dev, chunkInNAND);
|
||||
yaffs_handle_rd_data_error(dev, nand_chunk);
|
||||
}
|
||||
|
||||
if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
|
||||
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
||||
*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
|
||||
else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
|
||||
*eccResult = YAFFS_ECC_RESULT_FIXED;
|
||||
*ecc_result = YAFFS_ECC_RESULT_FIXED;
|
||||
else
|
||||
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
#ifdef NOTYET
|
||||
static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
|
||||
int chunkInNAND)
|
||||
{
|
||||
static int init;
|
||||
static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
|
||||
static __u8 data[YAFFS_BYTES_PER_CHUNK];
|
||||
/* Might as well always allocate the larger size for */
|
||||
/* dev->param.useNANDECC == true; */
|
||||
static __u8 spare[sizeof(struct yaffs_NANDSpare)];
|
||||
|
||||
dev->param.readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
|
||||
|
||||
if (!init) {
|
||||
memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
|
||||
init = 1;
|
||||
}
|
||||
|
||||
if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
|
||||
return YAFFS_FAIL;
|
||||
if (memcmp(cmpbuf, spare, 16))
|
||||
return YAFFS_FAIL;
|
||||
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Functions for robustisizing
|
||||
*/
|
||||
|
||||
static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND)
|
||||
static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
|
||||
{
|
||||
int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock;
|
||||
int flash_block = nand_chunk / dev->param.chunks_per_block;
|
||||
|
||||
/* Mark the block for retirement */
|
||||
yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1;
|
||||
yaffs_get_block_info(dev,
|
||||
flash_block + dev->block_offset)->needs_retiring =
|
||||
1;
|
||||
T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
|
||||
(TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
|
||||
(TSTR("**>>Block %d marked for retirement" TENDSTR), flash_block));
|
||||
|
||||
/* TODO:
|
||||
* Just do a garbage collection on the affected block
|
||||
@ -345,138 +314,85 @@ static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND)
|
||||
*/
|
||||
}
|
||||
|
||||
#ifdef NOTYET
|
||||
static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND)
|
||||
int yaffs_tags_compat_wr(struct yaffs_dev *dev,
|
||||
int nand_chunk,
|
||||
const u8 * data, const struct yaffs_ext_tags *ext_tags)
|
||||
{
|
||||
}
|
||||
struct yaffs_spare spare;
|
||||
struct yaffs_tags tags;
|
||||
|
||||
static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
|
||||
const __u8 *data,
|
||||
const yaffs_Spare *spare)
|
||||
{
|
||||
}
|
||||
yaffs_spare_init(&spare);
|
||||
|
||||
static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
|
||||
const yaffs_Spare *spare)
|
||||
{
|
||||
}
|
||||
|
||||
static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND)
|
||||
{
|
||||
int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock;
|
||||
|
||||
/* Mark the block for retirement */
|
||||
yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
|
||||
/* Delete the chunk */
|
||||
yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
|
||||
}
|
||||
|
||||
static int yaffs_VerifyCompare(const __u8 *d0, const __u8 *d1,
|
||||
const yaffs_Spare *s0, const yaffs_Spare *s1)
|
||||
{
|
||||
|
||||
if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
|
||||
s0->tagByte0 != s1->tagByte0 ||
|
||||
s0->tagByte1 != s1->tagByte1 ||
|
||||
s0->tagByte2 != s1->tagByte2 ||
|
||||
s0->tagByte3 != s1->tagByte3 ||
|
||||
s0->tagByte4 != s1->tagByte4 ||
|
||||
s0->tagByte5 != s1->tagByte5 ||
|
||||
s0->tagByte6 != s1->tagByte6 ||
|
||||
s0->tagByte7 != s1->tagByte7 ||
|
||||
s0->ecc1[0] != s1->ecc1[0] ||
|
||||
s0->ecc1[1] != s1->ecc1[1] ||
|
||||
s0->ecc1[2] != s1->ecc1[2] ||
|
||||
s0->ecc2[0] != s1->ecc2[0] ||
|
||||
s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* NOTYET */
|
||||
|
||||
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,
|
||||
int chunkInNAND,
|
||||
const __u8 *data,
|
||||
const yaffs_ExtendedTags *eTags)
|
||||
{
|
||||
yaffs_Spare spare;
|
||||
yaffs_Tags tags;
|
||||
|
||||
yaffs_SpareInitialise(&spare);
|
||||
|
||||
if (eTags->chunkDeleted)
|
||||
spare.pageStatus = 0;
|
||||
if (ext_tags->is_deleted)
|
||||
spare.page_status = 0;
|
||||
else {
|
||||
tags.objectId = eTags->objectId;
|
||||
tags.chunkId = eTags->chunkId;
|
||||
tags.obj_id = ext_tags->obj_id;
|
||||
tags.chunk_id = ext_tags->chunk_id;
|
||||
|
||||
tags.byteCountLSB = eTags->byteCount & 0x3ff;
|
||||
tags.n_bytes_lsb = ext_tags->n_bytes & 0x3ff;
|
||||
|
||||
if (dev->nDataBytesPerChunk >= 1024)
|
||||
tags.byteCountMSB = (eTags->byteCount >> 10) & 3;
|
||||
if (dev->data_bytes_per_chunk >= 1024)
|
||||
tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
|
||||
else
|
||||
tags.byteCountMSB = 3;
|
||||
tags.n_bytes_msb = 3;
|
||||
|
||||
tags.serial_number = ext_tags->serial_number;
|
||||
|
||||
tags.serialNumber = eTags->serialNumber;
|
||||
if (!dev->param.use_nand_ecc && data)
|
||||
yaffs_calc_ecc(data, &spare);
|
||||
|
||||
if (!dev->param.useNANDECC && data)
|
||||
yaffs_CalcECC(data, &spare);
|
||||
|
||||
yaffs_LoadTagsIntoSpare(&spare, &tags);
|
||||
yaffs_load_tags_to_spare(&spare, &tags);
|
||||
|
||||
}
|
||||
|
||||
return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
|
||||
return yaffs_wr_nand(dev, nand_chunk, data, &spare);
|
||||
}
|
||||
|
||||
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
||||
int chunkInNAND,
|
||||
__u8 *data,
|
||||
yaffs_ExtendedTags *eTags)
|
||||
int yaffs_tags_compat_rd(struct yaffs_dev *dev,
|
||||
int nand_chunk,
|
||||
u8 * data, struct yaffs_ext_tags *ext_tags)
|
||||
{
|
||||
|
||||
yaffs_Spare spare;
|
||||
yaffs_Tags tags;
|
||||
yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_UNKNOWN;
|
||||
struct yaffs_spare spare;
|
||||
struct yaffs_tags tags;
|
||||
enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
|
||||
|
||||
static yaffs_Spare spareFF;
|
||||
static struct yaffs_spare spare_ff;
|
||||
static int init;
|
||||
|
||||
if (!init) {
|
||||
memset(&spareFF, 0xFF, sizeof(spareFF));
|
||||
memset(&spare_ff, 0xFF, sizeof(spare_ff));
|
||||
init = 1;
|
||||
}
|
||||
|
||||
if (yaffs_ReadChunkFromNAND
|
||||
(dev, chunkInNAND, data, &spare, &eccResult, 1)) {
|
||||
/* eTags may be NULL */
|
||||
if (eTags) {
|
||||
if (yaffs_rd_chunk_nand(dev, nand_chunk, data, &spare, &ecc_result, 1)) {
|
||||
/* ext_tags may be NULL */
|
||||
if (ext_tags) {
|
||||
|
||||
int deleted =
|
||||
(yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
|
||||
(yaffs_count_bits(spare.page_status) < 7) ? 1 : 0;
|
||||
|
||||
eTags->chunkDeleted = deleted;
|
||||
eTags->eccResult = eccResult;
|
||||
eTags->blockBad = 0; /* We're reading it */
|
||||
ext_tags->is_deleted = deleted;
|
||||
ext_tags->ecc_result = ecc_result;
|
||||
ext_tags->block_bad = 0; /* We're reading it */
|
||||
/* therefore it is not a bad block */
|
||||
eTags->chunkUsed =
|
||||
(memcmp(&spareFF, &spare, sizeof(spareFF)) !=
|
||||
ext_tags->chunk_used =
|
||||
(memcmp(&spare_ff, &spare, sizeof(spare_ff)) !=
|
||||
0) ? 1 : 0;
|
||||
|
||||
if (eTags->chunkUsed) {
|
||||
yaffs_GetTagsFromSpare(dev, &spare, &tags);
|
||||
if (ext_tags->chunk_used) {
|
||||
yaffs_get_tags_from_spare(dev, &spare, &tags);
|
||||
|
||||
eTags->objectId = tags.objectId;
|
||||
eTags->chunkId = tags.chunkId;
|
||||
eTags->byteCount = tags.byteCountLSB;
|
||||
ext_tags->obj_id = tags.obj_id;
|
||||
ext_tags->chunk_id = tags.chunk_id;
|
||||
ext_tags->n_bytes = tags.n_bytes_lsb;
|
||||
|
||||
if (dev->nDataBytesPerChunk >= 1024)
|
||||
eTags->byteCount |= (((unsigned) tags.byteCountMSB) << 10);
|
||||
if (dev->data_bytes_per_chunk >= 1024)
|
||||
ext_tags->n_bytes |=
|
||||
(((unsigned)tags.
|
||||
n_bytes_msb) << 10);
|
||||
|
||||
eTags->serialNumber = tags.serialNumber;
|
||||
ext_tags->serial_number = tags.serial_number;
|
||||
}
|
||||
}
|
||||
|
||||
@ -486,51 +402,50 @@ int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
|
||||
int blockInNAND)
|
||||
int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
|
||||
{
|
||||
|
||||
yaffs_Spare spare;
|
||||
struct yaffs_spare spare;
|
||||
|
||||
memset(&spare, 0xff, sizeof(yaffs_Spare));
|
||||
memset(&spare, 0xff, sizeof(struct yaffs_spare));
|
||||
|
||||
spare.blockStatus = 'Y';
|
||||
spare.block_status = 'Y';
|
||||
|
||||
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->param.nChunksPerBlock, NULL,
|
||||
&spare);
|
||||
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->param.nChunksPerBlock + 1,
|
||||
NULL, &spare);
|
||||
yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
|
||||
&spare);
|
||||
yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
|
||||
NULL, &spare);
|
||||
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
|
||||
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
|
||||
int blockNo,
|
||||
yaffs_BlockState *state,
|
||||
__u32 *sequenceNumber)
|
||||
int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
|
||||
int block_no,
|
||||
enum yaffs_block_state *state,
|
||||
u32 * seq_number)
|
||||
{
|
||||
|
||||
yaffs_Spare spare0, spare1;
|
||||
static yaffs_Spare spareFF;
|
||||
struct yaffs_spare spare0, spare1;
|
||||
static struct yaffs_spare spare_ff;
|
||||
static int init;
|
||||
yaffs_ECCResult dummy;
|
||||
enum yaffs_ecc_result dummy;
|
||||
|
||||
if (!init) {
|
||||
memset(&spareFF, 0xFF, sizeof(spareFF));
|
||||
memset(&spare_ff, 0xFF, sizeof(spare_ff));
|
||||
init = 1;
|
||||
}
|
||||
|
||||
*sequenceNumber = 0;
|
||||
*seq_number = 0;
|
||||
|
||||
yaffs_ReadChunkFromNAND(dev, blockNo * dev->param.nChunksPerBlock, NULL,
|
||||
&spare0, &dummy, 1);
|
||||
yaffs_ReadChunkFromNAND(dev, blockNo * dev->param.nChunksPerBlock + 1, NULL,
|
||||
&spare1, &dummy, 1);
|
||||
yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL,
|
||||
&spare0, &dummy, 1);
|
||||
yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,
|
||||
NULL, &spare1, &dummy, 1);
|
||||
|
||||
if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
|
||||
if (yaffs_count_bits(spare0.block_status & spare1.block_status) < 7)
|
||||
*state = YAFFS_BLOCK_STATE_DEAD;
|
||||
else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
|
||||
else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
|
||||
*state = YAFFS_BLOCK_STATE_EMPTY;
|
||||
else
|
||||
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
|
@ -17,23 +17,20 @@
|
||||
#define __YAFFS_TAGSCOMPAT_H__
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,
|
||||
int chunkInNAND,
|
||||
const __u8 *data,
|
||||
const yaffs_ExtendedTags *tags);
|
||||
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
||||
int chunkInNAND,
|
||||
__u8 *data,
|
||||
yaffs_ExtendedTags *tags);
|
||||
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
|
||||
int blockNo);
|
||||
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
|
||||
int blockNo,
|
||||
yaffs_BlockState *state,
|
||||
__u32 *sequenceNumber);
|
||||
int yaffs_tags_compat_wr(struct yaffs_dev *dev,
|
||||
int nand_chunk,
|
||||
const u8 * data, const struct yaffs_ext_tags *tags);
|
||||
int yaffs_tags_compat_rd(struct yaffs_dev *dev,
|
||||
int nand_chunk,
|
||||
u8 * data, struct yaffs_ext_tags *tags);
|
||||
int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no);
|
||||
int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
|
||||
int block_no,
|
||||
enum yaffs_block_state *state,
|
||||
u32 * seq_number);
|
||||
|
||||
void yaffs_CalcTagsECC(yaffs_Tags *tags);
|
||||
int yaffs_CheckECCOnTags(yaffs_Tags *tags);
|
||||
int yaffs_CountBits(__u8 byte);
|
||||
void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
|
||||
int yaffs_check_tags_ecc(struct yaffs_tags *tags);
|
||||
int yaffs_count_bits(u8 byte);
|
||||
|
||||
#endif
|
||||
|
@ -13,16 +13,15 @@
|
||||
|
||||
#include "yaffs_tagsvalidity.h"
|
||||
|
||||
void yaffs_InitialiseTags(yaffs_ExtendedTags *tags)
|
||||
void yaffs_init_tags(struct yaffs_ext_tags *tags)
|
||||
{
|
||||
memset(tags, 0, sizeof(yaffs_ExtendedTags));
|
||||
tags->validMarker0 = 0xAAAAAAAA;
|
||||
tags->validMarker1 = 0x55555555;
|
||||
memset(tags, 0, sizeof(struct yaffs_ext_tags));
|
||||
tags->validity0 = 0xAAAAAAAA;
|
||||
tags->validity1 = 0x55555555;
|
||||
}
|
||||
|
||||
int yaffs_ValidateTags(yaffs_ExtendedTags *tags)
|
||||
int yaffs_validate_tags(struct yaffs_ext_tags *tags)
|
||||
{
|
||||
return (tags->validMarker0 == 0xAAAAAAAA &&
|
||||
tags->validMarker1 == 0x55555555);
|
||||
return (tags->validity0 == 0xAAAAAAAA && tags->validity1 == 0x55555555);
|
||||
|
||||
}
|
||||
|
@ -13,12 +13,11 @@
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __YAFFS_TAGS_VALIDITY_H__
|
||||
#define __YAFFS_TAGS_VALIDITY_H__
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
|
||||
int yaffs_ValidateTags(yaffs_ExtendedTags *tags);
|
||||
void yaffs_init_tags(struct yaffs_ext_tags *tags);
|
||||
int yaffs_validate_tags(struct yaffs_ext_tags *tags);
|
||||
#endif
|
||||
|
@ -13,11 +13,10 @@
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __YTRACE_H__
|
||||
#define __YTRACE_H__
|
||||
|
||||
extern unsigned int yaffs_traceMask;
|
||||
extern unsigned int yaffs_trace_mask;
|
||||
extern unsigned int yaffs_wr_attempts;
|
||||
|
||||
/*
|
||||
@ -54,7 +53,6 @@ extern unsigned int yaffs_wr_attempts;
|
||||
#define YAFFS_TRACE_BUG 0x80000000
|
||||
#define YAFFS_TRACE_ALWAYS 0xF0000000
|
||||
|
||||
|
||||
#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
|
||||
#define T(mask, p) do { if ((mask) & (yaffs_trace_mask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
|
||||
|
||||
#endif
|
||||
|
@ -11,149 +11,159 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
|
||||
#include "yaffs_verify.h"
|
||||
#include "yaffs_trace.h"
|
||||
#include "yaffs_bitmap.h"
|
||||
#include "yaffs_getblockinfo.h"
|
||||
#include "yaffs_nand.h"
|
||||
|
||||
int yaffs_SkipVerification(yaffs_Device *dev)
|
||||
int yaffs_skip_verification(struct yaffs_dev *dev)
|
||||
{
|
||||
dev=dev;
|
||||
return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
|
||||
dev = dev;
|
||||
return !(yaffs_trace_mask &
|
||||
(YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
|
||||
}
|
||||
|
||||
static int yaffs_SkipFullVerification(yaffs_Device *dev)
|
||||
static int yaffs_skip_full_verification(struct yaffs_dev *dev)
|
||||
{
|
||||
dev=dev;
|
||||
return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
|
||||
dev = dev;
|
||||
return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
|
||||
}
|
||||
|
||||
static int yaffs_SkipNANDVerification(yaffs_Device *dev)
|
||||
static int yaffs_skip_nand_verification(struct yaffs_dev *dev)
|
||||
{
|
||||
dev=dev;
|
||||
return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
|
||||
dev = dev;
|
||||
return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
|
||||
}
|
||||
|
||||
|
||||
static const char *blockStateName[] = {
|
||||
"Unknown",
|
||||
"Needs scanning",
|
||||
"Scanning",
|
||||
"Empty",
|
||||
"Allocating",
|
||||
"Full",
|
||||
"Dirty",
|
||||
"Checkpoint",
|
||||
"Collecting",
|
||||
"Dead"
|
||||
static const char *block_state_name[] = {
|
||||
"Unknown",
|
||||
"Needs scanning",
|
||||
"Scanning",
|
||||
"Empty",
|
||||
"Allocating",
|
||||
"Full",
|
||||
"Dirty",
|
||||
"Checkpoint",
|
||||
"Collecting",
|
||||
"Dead"
|
||||
};
|
||||
|
||||
|
||||
void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
|
||||
void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n)
|
||||
{
|
||||
int actuallyUsed;
|
||||
int inUse;
|
||||
int actually_used;
|
||||
int in_use;
|
||||
|
||||
if (yaffs_SkipVerification(dev))
|
||||
if (yaffs_skip_verification(dev))
|
||||
return;
|
||||
|
||||
/* Report illegal runtime states */
|
||||
if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
|
||||
T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
|
||||
if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Block %d has undefined state %d" TENDSTR), n,
|
||||
bi->block_state));
|
||||
|
||||
switch (bi->blockState) {
|
||||
switch (bi->block_state) {
|
||||
case YAFFS_BLOCK_STATE_UNKNOWN:
|
||||
case YAFFS_BLOCK_STATE_SCANNING:
|
||||
case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
|
||||
T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
|
||||
n, blockStateName[bi->blockState]));
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Block %d has bad run-state %s" TENDSTR), n,
|
||||
block_state_name[bi->block_state]));
|
||||
}
|
||||
|
||||
/* Check pages in use and soft deletions are legal */
|
||||
|
||||
actuallyUsed = bi->pagesInUse - bi->softDeletions;
|
||||
|
||||
if (bi->pagesInUse < 0 || bi->pagesInUse > dev->param.nChunksPerBlock ||
|
||||
bi->softDeletions < 0 || bi->softDeletions > dev->param.nChunksPerBlock ||
|
||||
actuallyUsed < 0 || actuallyUsed > dev->param.nChunksPerBlock)
|
||||
T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
|
||||
n, bi->pagesInUse, bi->softDeletions));
|
||||
actually_used = bi->pages_in_use - bi->soft_del_pages;
|
||||
|
||||
if (bi->pages_in_use < 0
|
||||
|| bi->pages_in_use > dev->param.chunks_per_block
|
||||
|| bi->soft_del_pages < 0
|
||||
|| bi->soft_del_pages > dev->param.chunks_per_block
|
||||
|| actually_used < 0 || actually_used > dev->param.chunks_per_block)
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR
|
||||
("Block %d has illegal values pages_in_used %d soft_del_pages %d"
|
||||
TENDSTR), n, bi->pages_in_use, bi->soft_del_pages));
|
||||
|
||||
/* Check chunk bitmap legal */
|
||||
inUse = yaffs_CountChunkBits(dev, n);
|
||||
if (inUse != bi->pagesInUse)
|
||||
T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
|
||||
n, bi->pagesInUse, inUse));
|
||||
in_use = yaffs_count_chunk_bits(dev, n);
|
||||
if (in_use != bi->pages_in_use)
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR
|
||||
("Block %d has inconsistent values pages_in_use %d counted chunk bits %d"
|
||||
TENDSTR), n, bi->pages_in_use, in_use));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
|
||||
void yaffs_verify_collected_blk(struct yaffs_dev *dev,
|
||||
struct yaffs_block_info *bi, int n)
|
||||
{
|
||||
yaffs_VerifyBlock(dev, bi, n);
|
||||
yaffs_verify_blk(dev, bi, n);
|
||||
|
||||
/* After collection the block should be in the erased state */
|
||||
|
||||
if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
|
||||
bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
|
||||
T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
|
||||
n, bi->blockState));
|
||||
if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
|
||||
bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
|
||||
T(YAFFS_TRACE_ERROR,
|
||||
(TSTR
|
||||
("Block %d is in state %d after gc, should be erased"
|
||||
TENDSTR), n, bi->block_state));
|
||||
}
|
||||
}
|
||||
|
||||
void yaffs_VerifyBlocks(yaffs_Device *dev)
|
||||
void yaffs_verify_blocks(struct yaffs_dev *dev)
|
||||
{
|
||||
int i;
|
||||
int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
|
||||
int nIllegalBlockStates = 0;
|
||||
int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];
|
||||
int illegal_states = 0;
|
||||
|
||||
if (yaffs_SkipVerification(dev))
|
||||
if (yaffs_skip_verification(dev))
|
||||
return;
|
||||
|
||||
memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
|
||||
memset(state_count, 0, sizeof(state_count));
|
||||
|
||||
for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
|
||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
|
||||
yaffs_VerifyBlock(dev, bi, i);
|
||||
for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
|
||||
struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
|
||||
yaffs_verify_blk(dev, bi, i);
|
||||
|
||||
if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
|
||||
nBlocksPerState[bi->blockState]++;
|
||||
if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
|
||||
state_count[bi->block_state]++;
|
||||
else
|
||||
nIllegalBlockStates++;
|
||||
illegal_states++;
|
||||
}
|
||||
|
||||
T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
|
||||
T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
|
||||
T(YAFFS_TRACE_VERIFY, (TSTR("" TENDSTR)));
|
||||
T(YAFFS_TRACE_VERIFY, (TSTR("Block summary" TENDSTR)));
|
||||
|
||||
T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
|
||||
if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
|
||||
T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("%d blocks have illegal states" TENDSTR), illegal_states));
|
||||
if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Too many allocating blocks" TENDSTR)));
|
||||
|
||||
for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("%s %d blocks"TENDSTR),
|
||||
blockStateName[i], nBlocksPerState[i]));
|
||||
(TSTR("%s %d blocks" TENDSTR),
|
||||
block_state_name[i], state_count[i]));
|
||||
|
||||
if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
|
||||
if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
|
||||
dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
|
||||
(TSTR("Checkpoint block count wrong dev %d count %d" TENDSTR),
|
||||
dev->blocks_in_checkpt,
|
||||
state_count[YAFFS_BLOCK_STATE_CHECKPOINT]));
|
||||
|
||||
if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
|
||||
if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Erased block count wrong dev %d count %d"TENDSTR),
|
||||
dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
|
||||
(TSTR("Erased block count wrong dev %d count %d" TENDSTR),
|
||||
dev->n_erased_blocks, state_count[YAFFS_BLOCK_STATE_EMPTY]));
|
||||
|
||||
if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
|
||||
if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1)
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
|
||||
nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
|
||||
(TSTR("Too many collecting blocks %d (max is 1)" TENDSTR),
|
||||
state_count[YAFFS_BLOCK_STATE_COLLECTING]));
|
||||
|
||||
T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
|
||||
T(YAFFS_TRACE_VERIFY, (TSTR("" TENDSTR)));
|
||||
|
||||
}
|
||||
|
||||
@ -161,317 +171,272 @@ void yaffs_VerifyBlocks(yaffs_Device *dev)
|
||||
* Verify the object header. oh must be valid, but obj and tags may be NULL in which
|
||||
* case those tests will not be performed.
|
||||
*/
|
||||
void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
|
||||
void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
|
||||
struct yaffs_ext_tags *tags, int parent_check)
|
||||
{
|
||||
if (obj && yaffs_SkipVerification(obj->myDev))
|
||||
if (obj && yaffs_skip_verification(obj->my_dev))
|
||||
return;
|
||||
|
||||
if (!(tags && obj && oh)) {
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR),
|
||||
tags, obj, oh));
|
||||
(TSTR("Verifying object header tags %p obj %p oh %p" TENDSTR),
|
||||
tags, obj, oh));
|
||||
return;
|
||||
}
|
||||
|
||||
if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
|
||||
oh->type > YAFFS_OBJECT_TYPE_MAX)
|
||||
oh->type > YAFFS_OBJECT_TYPE_MAX)
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
|
||||
tags->objectId, oh->type));
|
||||
(TSTR("Obj %d header type is illegal value 0x%x" TENDSTR),
|
||||
tags->obj_id, oh->type));
|
||||
|
||||
if (tags->objectId != obj->objectId)
|
||||
if (tags->obj_id != obj->obj_id)
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Obj %d header mismatch objectId %d"TENDSTR),
|
||||
tags->objectId, obj->objectId));
|
||||
|
||||
(TSTR("Obj %d header mismatch obj_id %d" TENDSTR),
|
||||
tags->obj_id, obj->obj_id));
|
||||
|
||||
/*
|
||||
* Check that the object's parent ids match if parentCheck requested.
|
||||
* Check that the object's parent ids match if parent_check requested.
|
||||
*
|
||||
* Tests do not apply to the root object.
|
||||
*/
|
||||
|
||||
if (parentCheck && tags->objectId > 1 && !obj->parent)
|
||||
if (parent_check && tags->obj_id > 1 && !obj->parent)
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
|
||||
tags->objectId, oh->parentObjectId));
|
||||
(TSTR
|
||||
("Obj %d header mismatch parent_id %d obj->parent is NULL"
|
||||
TENDSTR), tags->obj_id, oh->parent_obj_id));
|
||||
|
||||
if (parentCheck && obj->parent &&
|
||||
oh->parentObjectId != obj->parent->objectId &&
|
||||
(oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
|
||||
obj->parent->objectId != YAFFS_OBJECTID_DELETED))
|
||||
if (parent_check && obj->parent &&
|
||||
oh->parent_obj_id != obj->parent->obj_id &&
|
||||
(oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
|
||||
obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
|
||||
tags->objectId, oh->parentObjectId, obj->parent->objectId));
|
||||
(TSTR
|
||||
("Obj %d header mismatch parent_id %d parent_obj_id %d"
|
||||
TENDSTR), tags->obj_id, oh->parent_obj_id,
|
||||
obj->parent->obj_id));
|
||||
|
||||
if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
|
||||
if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Obj %d header name is NULL"TENDSTR),
|
||||
obj->objectId));
|
||||
(TSTR("Obj %d header name is NULL" TENDSTR), obj->obj_id));
|
||||
|
||||
if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
|
||||
if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Trashed name */
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Obj %d header name is 0xFF"TENDSTR),
|
||||
obj->objectId));
|
||||
(TSTR("Obj %d header name is 0xFF" TENDSTR), obj->obj_id));
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/* Not being used, but don't want to throw away yet */
|
||||
int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
|
||||
__u32 level, int chunkOffset)
|
||||
void yaffs_verify_file(struct yaffs_obj *obj)
|
||||
{
|
||||
int i;
|
||||
yaffs_Device *dev = obj->myDev;
|
||||
int ok = 1;
|
||||
|
||||
if (tn) {
|
||||
if (level > 0) {
|
||||
|
||||
for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
|
||||
if (tn->internal[i]) {
|
||||
ok = yaffs_VerifyTnodeWorker(obj,
|
||||
tn->internal[i],
|
||||
level - 1,
|
||||
(chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
|
||||
}
|
||||
}
|
||||
} else if (level == 0) {
|
||||
yaffs_ExtendedTags tags;
|
||||
__u32 objectId = obj->objectId;
|
||||
|
||||
chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS;
|
||||
|
||||
for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
|
||||
__u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
|
||||
|
||||
if (theChunk > 0) {
|
||||
/* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
|
||||
yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
|
||||
if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
|
||||
T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
|
||||
objectId, chunkOffset, theChunk,
|
||||
tags.objectId, tags.chunkId));
|
||||
}
|
||||
}
|
||||
chunkOffset++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void yaffs_VerifyFile(yaffs_Object *obj)
|
||||
{
|
||||
int requiredTallness;
|
||||
int actualTallness;
|
||||
__u32 lastChunk;
|
||||
__u32 x;
|
||||
__u32 i;
|
||||
yaffs_Device *dev;
|
||||
yaffs_ExtendedTags tags;
|
||||
yaffs_Tnode *tn;
|
||||
__u32 objectId;
|
||||
int required_depth;
|
||||
int actual_depth;
|
||||
u32 last_chunk;
|
||||
u32 x;
|
||||
u32 i;
|
||||
struct yaffs_dev *dev;
|
||||
struct yaffs_ext_tags tags;
|
||||
struct yaffs_tnode *tn;
|
||||
u32 obj_id;
|
||||
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
if (yaffs_SkipVerification(obj->myDev))
|
||||
if (yaffs_skip_verification(obj->my_dev))
|
||||
return;
|
||||
|
||||
dev = obj->myDev;
|
||||
objectId = obj->objectId;
|
||||
dev = obj->my_dev;
|
||||
obj_id = obj->obj_id;
|
||||
|
||||
/* Check file size is consistent with tnode depth */
|
||||
lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
|
||||
x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
|
||||
requiredTallness = 0;
|
||||
last_chunk =
|
||||
obj->variant.file_variant.file_size / dev->data_bytes_per_chunk + 1;
|
||||
x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
|
||||
required_depth = 0;
|
||||
while (x > 0) {
|
||||
x >>= YAFFS_TNODES_INTERNAL_BITS;
|
||||
requiredTallness++;
|
||||
required_depth++;
|
||||
}
|
||||
|
||||
actualTallness = obj->variant.fileVariant.topLevel;
|
||||
actual_depth = obj->variant.file_variant.top_level;
|
||||
|
||||
/* Check that the chunks in the tnode tree are all correct.
|
||||
* We do this by scanning through the tnode tree and
|
||||
* checking the tags for every chunk match.
|
||||
*/
|
||||
|
||||
if (yaffs_SkipNANDVerification(dev))
|
||||
if (yaffs_skip_nand_verification(dev))
|
||||
return;
|
||||
|
||||
for (i = 1; i <= lastChunk; i++) {
|
||||
tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
|
||||
for (i = 1; i <= last_chunk; i++) {
|
||||
tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
|
||||
|
||||
if (tn) {
|
||||
__u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
|
||||
if (theChunk > 0) {
|
||||
/* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
|
||||
yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
|
||||
if (tags.objectId != objectId || tags.chunkId != i) {
|
||||
T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
|
||||
objectId, i, theChunk,
|
||||
tags.objectId, tags.chunkId));
|
||||
u32 the_chunk = yaffs_get_group_base(dev, tn, i);
|
||||
if (the_chunk > 0) {
|
||||
/* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),obj_id,i,the_chunk)); */
|
||||
yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
|
||||
&tags);
|
||||
if (tags.obj_id != obj_id || tags.chunk_id != i) {
|
||||
T(~0,
|
||||
(TSTR
|
||||
("Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)"
|
||||
TENDSTR), obj_id, i, the_chunk,
|
||||
tags.obj_id, tags.chunk_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void yaffs_VerifyHardLink(yaffs_Object *obj)
|
||||
void yaffs_verify_link(struct yaffs_obj *obj)
|
||||
{
|
||||
if (obj && yaffs_SkipVerification(obj->myDev))
|
||||
if (obj && yaffs_skip_verification(obj->my_dev))
|
||||
return;
|
||||
|
||||
/* Verify sane equivalent object */
|
||||
}
|
||||
|
||||
void yaffs_VerifySymlink(yaffs_Object *obj)
|
||||
void yaffs_verify_symlink(struct yaffs_obj *obj)
|
||||
{
|
||||
if (obj && yaffs_SkipVerification(obj->myDev))
|
||||
if (obj && yaffs_skip_verification(obj->my_dev))
|
||||
return;
|
||||
|
||||
/* Verify symlink string */
|
||||
}
|
||||
|
||||
void yaffs_VerifySpecial(yaffs_Object *obj)
|
||||
void yaffs_verify_special(struct yaffs_obj *obj)
|
||||
{
|
||||
if (obj && yaffs_SkipVerification(obj->myDev))
|
||||
if (obj && yaffs_skip_verification(obj->my_dev))
|
||||
return;
|
||||
}
|
||||
|
||||
void yaffs_VerifyObject(yaffs_Object *obj)
|
||||
void yaffs_verify_obj(struct yaffs_obj *obj)
|
||||
{
|
||||
yaffs_Device *dev;
|
||||
struct yaffs_dev *dev;
|
||||
|
||||
__u32 chunkMin;
|
||||
__u32 chunkMax;
|
||||
u32 chunk_min;
|
||||
u32 chunk_max;
|
||||
|
||||
__u32 chunkIdOk;
|
||||
__u32 chunkInRange;
|
||||
__u32 chunkShouldNotBeDeleted;
|
||||
__u32 chunkValid;
|
||||
u32 chunk_id_ok;
|
||||
u32 chunk_in_range;
|
||||
u32 chunk_wrongly_deleted;
|
||||
u32 chunk_valid;
|
||||
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
if (obj->beingCreated)
|
||||
if (obj->being_created)
|
||||
return;
|
||||
|
||||
dev = obj->myDev;
|
||||
dev = obj->my_dev;
|
||||
|
||||
if (yaffs_SkipVerification(dev))
|
||||
if (yaffs_skip_verification(dev))
|
||||
return;
|
||||
|
||||
/* Check sane object header chunk */
|
||||
|
||||
chunkMin = dev->internalStartBlock * dev->param.nChunksPerBlock;
|
||||
chunkMax = (dev->internalEndBlock+1) * dev->param.nChunksPerBlock - 1;
|
||||
chunk_min = dev->internal_start_block * dev->param.chunks_per_block;
|
||||
chunk_max =
|
||||
(dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;
|
||||
|
||||
chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
|
||||
chunkIdOk = chunkInRange || (obj->hdrChunk == 0);
|
||||
chunkValid = chunkInRange &&
|
||||
yaffs_CheckChunkBit(dev,
|
||||
obj->hdrChunk / dev->param.nChunksPerBlock,
|
||||
obj->hdrChunk % dev->param.nChunksPerBlock);
|
||||
chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
|
||||
chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&
|
||||
((unsigned)(obj->hdr_chunk)) <= chunk_max);
|
||||
chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);
|
||||
chunk_valid = chunk_in_range &&
|
||||
yaffs_check_chunk_bit(dev,
|
||||
obj->hdr_chunk / dev->param.chunks_per_block,
|
||||
obj->hdr_chunk % dev->param.chunks_per_block);
|
||||
chunk_wrongly_deleted = chunk_in_range && !chunk_valid;
|
||||
|
||||
if (!obj->fake &&
|
||||
(!chunkIdOk || chunkShouldNotBeDeleted)) {
|
||||
if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted)) {
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
|
||||
obj->objectId, obj->hdrChunk,
|
||||
chunkIdOk ? "" : ",out of range",
|
||||
chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
|
||||
(TSTR("Obj %d has chunk_id %d %s %s" TENDSTR),
|
||||
obj->obj_id, obj->hdr_chunk,
|
||||
chunk_id_ok ? "" : ",out of range",
|
||||
chunk_wrongly_deleted ? ",marked as deleted" : ""));
|
||||
}
|
||||
|
||||
if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
|
||||
yaffs_ExtendedTags tags;
|
||||
yaffs_ObjectHeader *oh;
|
||||
__u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
|
||||
if (chunk_valid && !yaffs_skip_nand_verification(dev)) {
|
||||
struct yaffs_ext_tags tags;
|
||||
struct yaffs_obj_hdr *oh;
|
||||
u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
|
||||
|
||||
oh = (yaffs_ObjectHeader *)buffer;
|
||||
oh = (struct yaffs_obj_hdr *)buffer;
|
||||
|
||||
yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
|
||||
&tags);
|
||||
yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);
|
||||
|
||||
yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
|
||||
yaffs_verify_oh(obj, oh, &tags, 1);
|
||||
|
||||
yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
|
||||
yaffs_release_temp_buffer(dev, buffer, __LINE__);
|
||||
}
|
||||
|
||||
/* Verify it has a parent */
|
||||
if (obj && !obj->fake &&
|
||||
(!obj->parent || obj->parent->myDev != dev)) {
|
||||
if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
|
||||
obj->objectId, obj->parent));
|
||||
(TSTR
|
||||
("Obj %d has parent pointer %p which does not look like an object"
|
||||
TENDSTR), obj->obj_id, obj->parent));
|
||||
}
|
||||
|
||||
/* Verify parent is a directory */
|
||||
if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
|
||||
if (obj->parent
|
||||
&& obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
|
||||
obj->objectId, obj->parent->variantType));
|
||||
(TSTR("Obj %d's parent is not a directory (type %d)" TENDSTR),
|
||||
obj->obj_id, obj->parent->variant_type));
|
||||
}
|
||||
|
||||
switch (obj->variantType) {
|
||||
switch (obj->variant_type) {
|
||||
case YAFFS_OBJECT_TYPE_FILE:
|
||||
yaffs_VerifyFile(obj);
|
||||
yaffs_verify_file(obj);
|
||||
break;
|
||||
case YAFFS_OBJECT_TYPE_SYMLINK:
|
||||
yaffs_VerifySymlink(obj);
|
||||
yaffs_verify_symlink(obj);
|
||||
break;
|
||||
case YAFFS_OBJECT_TYPE_DIRECTORY:
|
||||
yaffs_VerifyDirectory(obj);
|
||||
yaffs_verify_dir(obj);
|
||||
break;
|
||||
case YAFFS_OBJECT_TYPE_HARDLINK:
|
||||
yaffs_VerifyHardLink(obj);
|
||||
yaffs_verify_link(obj);
|
||||
break;
|
||||
case YAFFS_OBJECT_TYPE_SPECIAL:
|
||||
yaffs_VerifySpecial(obj);
|
||||
yaffs_verify_special(obj);
|
||||
break;
|
||||
case YAFFS_OBJECT_TYPE_UNKNOWN:
|
||||
default:
|
||||
T(YAFFS_TRACE_VERIFY,
|
||||
(TSTR("Obj %d has illegaltype %d"TENDSTR),
|
||||
obj->objectId, obj->variantType));
|
||||
(TSTR("Obj %d has illegaltype %d" TENDSTR),
|
||||
obj->obj_id, obj->variant_type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void yaffs_VerifyObjects(yaffs_Device *dev)
|
||||
void yaffs_verify_objects(struct yaffs_dev *dev)
|
||||
{
|
||||
yaffs_Object *obj;
|
||||
struct yaffs_obj *obj;
|
||||
int i;
|
||||
struct ylist_head *lh;
|
||||
struct list_head *lh;
|
||||
|
||||
if (yaffs_SkipVerification(dev))
|
||||
if (yaffs_skip_verification(dev))
|
||||
return;
|
||||
|
||||
/* Iterate through the objects in each hash entry */
|
||||
|
||||
for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
|
||||
ylist_for_each(lh, &dev->objectBucket[i].list) {
|
||||
for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
|
||||
list_for_each(lh, &dev->obj_bucket[i].list) {
|
||||
if (lh) {
|
||||
obj = ylist_entry(lh, yaffs_Object, hashLink);
|
||||
yaffs_VerifyObject(obj);
|
||||
obj =
|
||||
list_entry(lh, struct yaffs_obj, hash_link);
|
||||
yaffs_verify_obj(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
|
||||
void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)
|
||||
{
|
||||
struct ylist_head *lh;
|
||||
yaffs_Object *listObj;
|
||||
struct list_head *lh;
|
||||
struct yaffs_obj *list_obj;
|
||||
|
||||
int count = 0;
|
||||
|
||||
@ -481,146 +446,101 @@ void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
|
||||
return;
|
||||
}
|
||||
|
||||
if (yaffs_SkipVerification(obj->myDev))
|
||||
if (yaffs_skip_verification(obj->my_dev))
|
||||
return;
|
||||
|
||||
if (!obj->parent) {
|
||||
T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
|
||||
T(YAFFS_TRACE_ALWAYS,
|
||||
(TSTR("Object does not have parent" TENDSTR)));
|
||||
YBUG();
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
|
||||
T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
|
||||
if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
|
||||
T(YAFFS_TRACE_ALWAYS,
|
||||
(TSTR("Parent is not directory" TENDSTR)));
|
||||
YBUG();
|
||||
}
|
||||
|
||||
/* Iterate through the objects in each hash entry */
|
||||
|
||||
ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
|
||||
list_for_each(lh, &obj->parent->variant.dir_variant.children) {
|
||||
if (lh) {
|
||||
listObj = ylist_entry(lh, yaffs_Object, siblings);
|
||||
yaffs_VerifyObject(listObj);
|
||||
if (obj == listObj)
|
||||
list_obj = list_entry(lh, struct yaffs_obj, siblings);
|
||||
yaffs_verify_obj(list_obj);
|
||||
if (obj == list_obj)
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count != 1) {
|
||||
T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
|
||||
T(YAFFS_TRACE_ALWAYS,
|
||||
(TSTR("Object in directory %d times" TENDSTR), count));
|
||||
YBUG();
|
||||
}
|
||||
}
|
||||
|
||||
void yaffs_VerifyDirectory(yaffs_Object *directory)
|
||||
void yaffs_verify_dir(struct yaffs_obj *directory)
|
||||
{
|
||||
struct ylist_head *lh;
|
||||
yaffs_Object *listObj;
|
||||
struct list_head *lh;
|
||||
struct yaffs_obj *list_obj;
|
||||
|
||||
if (!directory) {
|
||||
YBUG();
|
||||
return;
|
||||
}
|
||||
|
||||
if (yaffs_SkipFullVerification(directory->myDev))
|
||||
if (yaffs_skip_full_verification(directory->my_dev))
|
||||
return;
|
||||
|
||||
if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
|
||||
T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
|
||||
if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
|
||||
T(YAFFS_TRACE_ALWAYS,
|
||||
(TSTR("Directory has wrong type: %d" TENDSTR),
|
||||
directory->variant_type));
|
||||
YBUG();
|
||||
}
|
||||
|
||||
/* Iterate through the objects in each hash entry */
|
||||
|
||||
ylist_for_each(lh, &directory->variant.directoryVariant.children) {
|
||||
list_for_each(lh, &directory->variant.dir_variant.children) {
|
||||
if (lh) {
|
||||
listObj = ylist_entry(lh, yaffs_Object, siblings);
|
||||
if (listObj->parent != directory) {
|
||||
T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
|
||||
list_obj = list_entry(lh, struct yaffs_obj, siblings);
|
||||
if (list_obj->parent != directory) {
|
||||
T(YAFFS_TRACE_ALWAYS,
|
||||
(TSTR
|
||||
("Object in directory list has wrong parent %p"
|
||||
TENDSTR), list_obj->parent));
|
||||
YBUG();
|
||||
}
|
||||
yaffs_VerifyObjectInDirectory(listObj);
|
||||
yaffs_verify_obj_in_dir(list_obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int yaffs_freeVerificationFailures;
|
||||
static int yaffs_free_verification_failures;
|
||||
|
||||
void yaffs_VerifyFreeChunks(yaffs_Device *dev)
|
||||
void yaffs_verify_free_chunks(struct yaffs_dev *dev)
|
||||
{
|
||||
int counted;
|
||||
int difference;
|
||||
|
||||
if (yaffs_SkipVerification(dev))
|
||||
if (yaffs_skip_verification(dev))
|
||||
return;
|
||||
|
||||
counted = yaffs_CountFreeChunks(dev);
|
||||
counted = yaffs_count_free_chunks(dev);
|
||||
|
||||
difference = dev->nFreeChunks - counted;
|
||||
difference = dev->n_free_chunks - counted;
|
||||
|
||||
if (difference) {
|
||||
T(YAFFS_TRACE_ALWAYS,
|
||||
(TSTR("Freechunks verification failure %d %d %d" TENDSTR),
|
||||
dev->nFreeChunks, counted, difference));
|
||||
yaffs_freeVerificationFailures++;
|
||||
dev->n_free_chunks, counted, difference));
|
||||
yaffs_free_verification_failures++;
|
||||
}
|
||||
}
|
||||
|
||||
int yaffs_VerifyFileSanity(yaffs_Object *in)
|
||||
int yaffs_verify_file_sane(struct yaffs_obj *in)
|
||||
{
|
||||
#if 0
|
||||
int chunk;
|
||||
int nChunks;
|
||||
int fSize;
|
||||
int failed = 0;
|
||||
int objId;
|
||||
yaffs_Tnode *tn;
|
||||
yaffs_Tags localTags;
|
||||
yaffs_Tags *tags = &localTags;
|
||||
int theChunk;
|
||||
int chunkDeleted;
|
||||
|
||||
if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
|
||||
return YAFFS_FAIL;
|
||||
|
||||
objId = in->objectId;
|
||||
fSize = in->variant.fileVariant.fileSize;
|
||||
nChunks =
|
||||
(fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
|
||||
|
||||
for (chunk = 1; chunk <= nChunks; chunk++) {
|
||||
tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
|
||||
chunk);
|
||||
|
||||
if (tn) {
|
||||
|
||||
theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
|
||||
|
||||
if (yaffs_CheckChunkBits
|
||||
(dev, theChunk / dev->param.nChunksPerBlock,
|
||||
theChunk % dev->param.nChunksPerBlock)) {
|
||||
|
||||
yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
|
||||
tags,
|
||||
&chunkDeleted);
|
||||
if (yaffs_TagsMatch
|
||||
(tags, in->objectId, chunk, chunkDeleted)) {
|
||||
/* found it; */
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* T(("No level 0 found for %d\n", chunk)); */
|
||||
}
|
||||
}
|
||||
|
||||
return failed ? YAFFS_FAIL : YAFFS_OK;
|
||||
#else
|
||||
in=in;
|
||||
in = in;
|
||||
return YAFFS_OK;
|
||||
#endif
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2010 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
@ -7,8 +7,10 @@
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_VERIFY_H__
|
||||
@ -16,24 +18,26 @@
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n);
|
||||
void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n);
|
||||
void yaffs_VerifyBlocks(yaffs_Device *dev);
|
||||
void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,
|
||||
int n);
|
||||
void yaffs_verify_collected_blk(struct yaffs_dev *dev,
|
||||
struct yaffs_block_info *bi, int n);
|
||||
void yaffs_verify_blocks(struct yaffs_dev *dev);
|
||||
|
||||
void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck);
|
||||
void yaffs_VerifyFile(yaffs_Object *obj);
|
||||
void yaffs_VerifyHardLink(yaffs_Object *obj);
|
||||
void yaffs_VerifySymlink(yaffs_Object *obj);
|
||||
void yaffs_VerifySpecial(yaffs_Object *obj);
|
||||
void yaffs_VerifyObject(yaffs_Object *obj);
|
||||
void yaffs_VerifyObjects(yaffs_Device *dev);
|
||||
void yaffs_VerifyObjectInDirectory(yaffs_Object *obj);
|
||||
void yaffs_VerifyDirectory(yaffs_Object *directory);
|
||||
void yaffs_VerifyFreeChunks(yaffs_Device *dev);
|
||||
void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
|
||||
struct yaffs_ext_tags *tags, int parent_check);
|
||||
void yaffs_verify_file(struct yaffs_obj *obj);
|
||||
void yaffs_verify_link(struct yaffs_obj *obj);
|
||||
void yaffs_verify_symlink(struct yaffs_obj *obj);
|
||||
void yaffs_verify_special(struct yaffs_obj *obj);
|
||||
void yaffs_verify_obj(struct yaffs_obj *obj);
|
||||
void yaffs_verify_objects(struct yaffs_dev *dev);
|
||||
void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);
|
||||
void yaffs_verify_dir(struct yaffs_obj *directory);
|
||||
void yaffs_verify_free_chunks(struct yaffs_dev *dev);
|
||||
|
||||
int yaffs_VerifyFileSanity(yaffs_Object *obj);
|
||||
int yaffs_verify_file_sane(struct yaffs_obj *obj);
|
||||
|
||||
int yaffs_SkipVerification(yaffs_Device *dev);
|
||||
int yaffs_skip_verification(struct yaffs_dev *dev);
|
||||
|
||||
#endif
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,69 +10,65 @@
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "yaffs_yaffs1.h"
|
||||
#include "yportenv.h"
|
||||
#include "yaffs_trace.h"
|
||||
#include "yaffs_bitmap.h"
|
||||
#include "yaffs_getblockinfo.h"
|
||||
#include "yaffs_nand.h"
|
||||
#include "yaffs_attribs.h"
|
||||
|
||||
|
||||
int yaffs1_Scan(yaffs_Device *dev)
|
||||
int yaffs1_scan(struct yaffs_dev *dev)
|
||||
{
|
||||
yaffs_ExtendedTags tags;
|
||||
struct yaffs_ext_tags tags;
|
||||
int blk;
|
||||
int blockIterator;
|
||||
int startIterator;
|
||||
int endIterator;
|
||||
int result;
|
||||
|
||||
int chunk;
|
||||
int c;
|
||||
int deleted;
|
||||
yaffs_BlockState state;
|
||||
yaffs_Object *hardList = NULL;
|
||||
yaffs_BlockInfo *bi;
|
||||
__u32 sequenceNumber;
|
||||
yaffs_ObjectHeader *oh;
|
||||
yaffs_Object *in;
|
||||
yaffs_Object *parent;
|
||||
enum yaffs_block_state state;
|
||||
struct yaffs_obj *hard_list = NULL;
|
||||
struct yaffs_block_info *bi;
|
||||
u32 seq_number;
|
||||
struct yaffs_obj_hdr *oh;
|
||||
struct yaffs_obj *in;
|
||||
struct yaffs_obj *parent;
|
||||
|
||||
int alloc_failed = 0;
|
||||
|
||||
struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;
|
||||
|
||||
|
||||
__u8 *chunkData;
|
||||
|
||||
struct yaffs_shadow_fixer *shadow_fixers = NULL;
|
||||
|
||||
u8 *chunk_data;
|
||||
|
||||
T(YAFFS_TRACE_SCAN,
|
||||
(TSTR("yaffs1_Scan starts intstartblk %d intendblk %d..." TENDSTR),
|
||||
dev->internalStartBlock, dev->internalEndBlock));
|
||||
(TSTR("yaffs1_scan starts intstartblk %d intendblk %d..." TENDSTR),
|
||||
dev->internal_start_block, dev->internal_end_block));
|
||||
|
||||
chunkData = yaffs_GetTempBuffer(dev, __LINE__);
|
||||
chunk_data = yaffs_get_temp_buffer(dev, __LINE__);
|
||||
|
||||
dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
|
||||
dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
|
||||
|
||||
/* Scan all the blocks to determine their state */
|
||||
bi = dev->blockInfo;
|
||||
for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
|
||||
yaffs_ClearChunkBits(dev, blk);
|
||||
bi->pagesInUse = 0;
|
||||
bi->softDeletions = 0;
|
||||
bi = dev->block_info;
|
||||
for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
|
||||
blk++) {
|
||||
yaffs_clear_chunk_bits(dev, blk);
|
||||
bi->pages_in_use = 0;
|
||||
bi->soft_del_pages = 0;
|
||||
|
||||
yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
|
||||
yaffs_query_init_block_state(dev, blk, &state, &seq_number);
|
||||
|
||||
bi->blockState = state;
|
||||
bi->sequenceNumber = sequenceNumber;
|
||||
bi->block_state = state;
|
||||
bi->seq_number = seq_number;
|
||||
|
||||
if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
|
||||
bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
|
||||
if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
|
||||
bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
|
||||
|
||||
T(YAFFS_TRACE_SCAN_DEBUG,
|
||||
(TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
|
||||
state, sequenceNumber));
|
||||
state, seq_number));
|
||||
|
||||
if (state == YAFFS_BLOCK_STATE_DEAD) {
|
||||
T(YAFFS_TRACE_BAD_BLOCKS,
|
||||
@ -80,49 +76,43 @@ int yaffs1_Scan(yaffs_Device *dev)
|
||||
} else if (state == YAFFS_BLOCK_STATE_EMPTY) {
|
||||
T(YAFFS_TRACE_SCAN_DEBUG,
|
||||
(TSTR("Block empty " TENDSTR)));
|
||||
dev->nErasedBlocks++;
|
||||
dev->nFreeChunks += dev->param.nChunksPerBlock;
|
||||
dev->n_erased_blocks++;
|
||||
dev->n_free_chunks += dev->param.chunks_per_block;
|
||||
}
|
||||
bi++;
|
||||
}
|
||||
|
||||
startIterator = dev->internalStartBlock;
|
||||
endIterator = dev->internalEndBlock;
|
||||
|
||||
/* For each block.... */
|
||||
for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
|
||||
blockIterator++) {
|
||||
for (blk = dev->internal_start_block;
|
||||
!alloc_failed && blk <= dev->internal_end_block; blk++) {
|
||||
|
||||
YYIELD();
|
||||
|
||||
YYIELD();
|
||||
|
||||
blk = blockIterator;
|
||||
|
||||
bi = yaffs_GetBlockInfo(dev, blk);
|
||||
state = bi->blockState;
|
||||
bi = yaffs_get_block_info(dev, blk);
|
||||
state = bi->block_state;
|
||||
|
||||
deleted = 0;
|
||||
|
||||
/* For each chunk in each block that needs scanning....*/
|
||||
for (c = 0; !alloc_failed && c < dev->param.nChunksPerBlock &&
|
||||
/* For each chunk in each block that needs scanning.... */
|
||||
for (c = 0; !alloc_failed && c < dev->param.chunks_per_block &&
|
||||
state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
|
||||
/* Read the tags and decide what to do */
|
||||
chunk = blk * dev->param.nChunksPerBlock + c;
|
||||
chunk = blk * dev->param.chunks_per_block + c;
|
||||
|
||||
result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
|
||||
&tags);
|
||||
result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
|
||||
&tags);
|
||||
|
||||
/* Let's have a good look at this chunk... */
|
||||
|
||||
if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {
|
||||
if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED
|
||||
|| tags.is_deleted) {
|
||||
/* YAFFS1 only...
|
||||
* A deleted chunk
|
||||
*/
|
||||
deleted++;
|
||||
dev->nFreeChunks++;
|
||||
dev->n_free_chunks++;
|
||||
/*T((" %d %d deleted\n",blk,c)); */
|
||||
} else if (!tags.chunkUsed) {
|
||||
} else if (!tags.chunk_used) {
|
||||
/* An unassigned chunk in the block
|
||||
* This means that either the block is empty or
|
||||
* this is the one being allocated from
|
||||
@ -131,7 +121,7 @@ int yaffs1_Scan(yaffs_Device *dev)
|
||||
if (c == 0) {
|
||||
/* We're looking at the first chunk in the block so the block is unused */
|
||||
state = YAFFS_BLOCK_STATE_EMPTY;
|
||||
dev->nErasedBlocks++;
|
||||
dev->n_erased_blocks++;
|
||||
} else {
|
||||
/* this is the block being allocated from */
|
||||
T(YAFFS_TRACE_SCAN,
|
||||
@ -139,102 +129,108 @@ int yaffs1_Scan(yaffs_Device *dev)
|
||||
(" Allocating from %d %d" TENDSTR),
|
||||
blk, c));
|
||||
state = YAFFS_BLOCK_STATE_ALLOCATING;
|
||||
dev->allocationBlock = blk;
|
||||
dev->allocationPage = c;
|
||||
dev->allocationBlockFinder = blk;
|
||||
dev->alloc_block = blk;
|
||||
dev->alloc_page = c;
|
||||
dev->alloc_block_finder = blk;
|
||||
/* Set block finder here to encourage the allocator to go forth from here. */
|
||||
|
||||
}
|
||||
|
||||
dev->nFreeChunks += (dev->param.nChunksPerBlock - c);
|
||||
} else if (tags.chunkId > 0) {
|
||||
/* chunkId > 0 so it is a data chunk... */
|
||||
dev->n_free_chunks +=
|
||||
(dev->param.chunks_per_block - c);
|
||||
} else if (tags.chunk_id > 0) {
|
||||
/* chunk_id > 0 so it is a data chunk... */
|
||||
unsigned int endpos;
|
||||
|
||||
yaffs_SetChunkBit(dev, blk, c);
|
||||
bi->pagesInUse++;
|
||||
yaffs_set_chunk_bit(dev, blk, c);
|
||||
bi->pages_in_use++;
|
||||
|
||||
in = yaffs_FindOrCreateObjectByNumber(dev,
|
||||
tags.
|
||||
objectId,
|
||||
YAFFS_OBJECT_TYPE_FILE);
|
||||
in = yaffs_find_or_create_by_number(dev,
|
||||
tags.obj_id,
|
||||
YAFFS_OBJECT_TYPE_FILE);
|
||||
/* PutChunkIntoFile checks for a clash (two data chunks with
|
||||
* the same chunkId).
|
||||
* the same chunk_id).
|
||||
*/
|
||||
|
||||
if (!in)
|
||||
alloc_failed = 1;
|
||||
|
||||
if (in) {
|
||||
if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))
|
||||
if (!yaffs_put_chunk_in_file
|
||||
(in, tags.chunk_id, chunk, 1))
|
||||
alloc_failed = 1;
|
||||
}
|
||||
|
||||
endpos =
|
||||
(tags.chunkId - 1) * dev->nDataBytesPerChunk +
|
||||
tags.byteCount;
|
||||
if (in &&
|
||||
in->variantType == YAFFS_OBJECT_TYPE_FILE
|
||||
&& in->variant.fileVariant.scannedFileSize <
|
||||
(tags.chunk_id -
|
||||
1) * dev->data_bytes_per_chunk +
|
||||
tags.n_bytes;
|
||||
if (in
|
||||
&& in->variant_type ==
|
||||
YAFFS_OBJECT_TYPE_FILE
|
||||
&& in->variant.file_variant.scanned_size <
|
||||
endpos) {
|
||||
in->variant.fileVariant.
|
||||
scannedFileSize = endpos;
|
||||
if (!dev->param.useHeaderFileSize) {
|
||||
in->variant.fileVariant.
|
||||
fileSize =
|
||||
in->variant.fileVariant.
|
||||
scannedFileSize;
|
||||
in->variant.file_variant.scanned_size =
|
||||
endpos;
|
||||
if (!dev->param.use_header_file_size) {
|
||||
in->variant.
|
||||
file_variant.file_size =
|
||||
in->variant.
|
||||
file_variant.scanned_size;
|
||||
}
|
||||
|
||||
}
|
||||
/* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */
|
||||
/* T((" %d %d data %d %d\n",blk,c,tags.obj_id,tags.chunk_id)); */
|
||||
} else {
|
||||
/* chunkId == 0, so it is an ObjectHeader.
|
||||
/* chunk_id == 0, so it is an ObjectHeader.
|
||||
* Thus, we read in the object header and make the object
|
||||
*/
|
||||
yaffs_SetChunkBit(dev, blk, c);
|
||||
bi->pagesInUse++;
|
||||
yaffs_set_chunk_bit(dev, blk, c);
|
||||
bi->pages_in_use++;
|
||||
|
||||
result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
|
||||
chunkData,
|
||||
NULL);
|
||||
result = yaffs_rd_chunk_tags_nand(dev, chunk,
|
||||
chunk_data,
|
||||
NULL);
|
||||
|
||||
oh = (yaffs_ObjectHeader *) chunkData;
|
||||
oh = (struct yaffs_obj_hdr *)chunk_data;
|
||||
|
||||
in = yaffs_FindObjectByNumber(dev,
|
||||
tags.objectId);
|
||||
if (in && in->variantType != oh->type) {
|
||||
in = yaffs_find_by_number(dev, tags.obj_id);
|
||||
if (in && in->variant_type != oh->type) {
|
||||
/* This should not happen, but somehow
|
||||
* Wev'e ended up with an objectId that has been reused but not yet
|
||||
* Wev'e ended up with an obj_id that has been reused but not yet
|
||||
* deleted, and worse still it has changed type. Delete the old object.
|
||||
*/
|
||||
|
||||
yaffs_DeleteObject(in);
|
||||
yaffs_del_obj(in);
|
||||
|
||||
in = 0;
|
||||
}
|
||||
|
||||
in = yaffs_FindOrCreateObjectByNumber(dev,
|
||||
tags.
|
||||
objectId,
|
||||
oh->type);
|
||||
in = yaffs_find_or_create_by_number(dev,
|
||||
tags.obj_id,
|
||||
oh->type);
|
||||
|
||||
if (!in)
|
||||
alloc_failed = 1;
|
||||
|
||||
if (in && oh->shadowsObject > 0) {
|
||||
if (in && oh->shadows_obj > 0) {
|
||||
|
||||
struct yaffs_ShadowFixerStruct *fixer;
|
||||
fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));
|
||||
struct yaffs_shadow_fixer *fixer;
|
||||
fixer =
|
||||
YMALLOC(sizeof
|
||||
(struct
|
||||
yaffs_shadow_fixer));
|
||||
if (fixer) {
|
||||
fixer->next = shadowFixerList;
|
||||
shadowFixerList = fixer;
|
||||
fixer->objectId = tags.objectId;
|
||||
fixer->shadowedId = oh->shadowsObject;
|
||||
fixer->next = shadow_fixers;
|
||||
shadow_fixers = fixer;
|
||||
fixer->obj_id = tags.obj_id;
|
||||
fixer->shadowed_id =
|
||||
oh->shadows_obj;
|
||||
T(YAFFS_TRACE_SCAN,
|
||||
(TSTR
|
||||
(" Shadow fixer: %d shadows %d" TENDSTR),
|
||||
fixer->objectId, fixer->shadowedId));
|
||||
(" Shadow fixer: %d shadows %d"
|
||||
TENDSTR), fixer->obj_id,
|
||||
fixer->shadowed_id));
|
||||
|
||||
}
|
||||
|
||||
@ -243,74 +239,49 @@ int yaffs1_Scan(yaffs_Device *dev)
|
||||
if (in && in->valid) {
|
||||
/* We have already filled this one. We have a duplicate and need to resolve it. */
|
||||
|
||||
unsigned existingSerial = in->serial;
|
||||
unsigned newSerial = tags.serialNumber;
|
||||
unsigned existing_serial = in->serial;
|
||||
unsigned new_serial =
|
||||
tags.serial_number;
|
||||
|
||||
if (((existingSerial + 1) & 3) == newSerial) {
|
||||
if (((existing_serial + 1) & 3) ==
|
||||
new_serial) {
|
||||
/* Use new one - destroy the exisiting one */
|
||||
yaffs_DeleteChunk(dev,
|
||||
in->hdrChunk,
|
||||
1, __LINE__);
|
||||
yaffs_chunk_del(dev,
|
||||
in->hdr_chunk,
|
||||
1, __LINE__);
|
||||
in->valid = 0;
|
||||
} else {
|
||||
/* Use existing - destroy this one. */
|
||||
yaffs_DeleteChunk(dev, chunk, 1,
|
||||
__LINE__);
|
||||
yaffs_chunk_del(dev, chunk, 1,
|
||||
__LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
if (in && !in->valid &&
|
||||
(tags.objectId == YAFFS_OBJECTID_ROOT ||
|
||||
tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
|
||||
(tags.obj_id == YAFFS_OBJECTID_ROOT ||
|
||||
tags.obj_id ==
|
||||
YAFFS_OBJECTID_LOSTNFOUND)) {
|
||||
/* We only load some info, don't fiddle with directory structure */
|
||||
in->valid = 1;
|
||||
in->variantType = oh->type;
|
||||
in->variant_type = oh->type;
|
||||
|
||||
in->yst_mode = oh->yst_mode;
|
||||
#ifdef CONFIG_YAFFS_WINCE
|
||||
in->win_atime[0] = oh->win_atime[0];
|
||||
in->win_ctime[0] = oh->win_ctime[0];
|
||||
in->win_mtime[0] = oh->win_mtime[0];
|
||||
in->win_atime[1] = oh->win_atime[1];
|
||||
in->win_ctime[1] = oh->win_ctime[1];
|
||||
in->win_mtime[1] = oh->win_mtime[1];
|
||||
#else
|
||||
in->yst_uid = oh->yst_uid;
|
||||
in->yst_gid = oh->yst_gid;
|
||||
in->yst_atime = oh->yst_atime;
|
||||
in->yst_mtime = oh->yst_mtime;
|
||||
in->yst_ctime = oh->yst_ctime;
|
||||
in->yst_rdev = oh->yst_rdev;
|
||||
#endif
|
||||
in->hdrChunk = chunk;
|
||||
in->serial = tags.serialNumber;
|
||||
yaffs_load_attribs(in, oh);
|
||||
in->hdr_chunk = chunk;
|
||||
in->serial = tags.serial_number;
|
||||
|
||||
} else if (in && !in->valid) {
|
||||
/* we need to load this info */
|
||||
|
||||
in->valid = 1;
|
||||
in->variantType = oh->type;
|
||||
in->variant_type = oh->type;
|
||||
|
||||
in->yst_mode = oh->yst_mode;
|
||||
#ifdef CONFIG_YAFFS_WINCE
|
||||
in->win_atime[0] = oh->win_atime[0];
|
||||
in->win_ctime[0] = oh->win_ctime[0];
|
||||
in->win_mtime[0] = oh->win_mtime[0];
|
||||
in->win_atime[1] = oh->win_atime[1];
|
||||
in->win_ctime[1] = oh->win_ctime[1];
|
||||
in->win_mtime[1] = oh->win_mtime[1];
|
||||
#else
|
||||
in->yst_uid = oh->yst_uid;
|
||||
in->yst_gid = oh->yst_gid;
|
||||
in->yst_atime = oh->yst_atime;
|
||||
in->yst_mtime = oh->yst_mtime;
|
||||
in->yst_ctime = oh->yst_ctime;
|
||||
in->yst_rdev = oh->yst_rdev;
|
||||
#endif
|
||||
in->hdrChunk = chunk;
|
||||
in->serial = tags.serialNumber;
|
||||
yaffs_load_attribs(in, oh);
|
||||
in->hdr_chunk = chunk;
|
||||
in->serial = tags.serial_number;
|
||||
|
||||
yaffs_SetObjectNameFromOH(in, oh);
|
||||
yaffs_set_obj_name_from_oh(in, oh);
|
||||
in->dirty = 0;
|
||||
|
||||
/* directory stuff...
|
||||
@ -318,21 +289,22 @@ int yaffs1_Scan(yaffs_Device *dev)
|
||||
*/
|
||||
|
||||
parent =
|
||||
yaffs_FindOrCreateObjectByNumber
|
||||
(dev, oh->parentObjectId,
|
||||
yaffs_find_or_create_by_number
|
||||
(dev, oh->parent_obj_id,
|
||||
YAFFS_OBJECT_TYPE_DIRECTORY);
|
||||
if (!parent)
|
||||
alloc_failed = 1;
|
||||
if (parent && parent->variantType ==
|
||||
if (parent && parent->variant_type ==
|
||||
YAFFS_OBJECT_TYPE_UNKNOWN) {
|
||||
/* Set up as a directory */
|
||||
parent->variantType =
|
||||
YAFFS_OBJECT_TYPE_DIRECTORY;
|
||||
YINIT_LIST_HEAD(&parent->variant.
|
||||
directoryVariant.
|
||||
children);
|
||||
} else if (!parent || parent->variantType !=
|
||||
YAFFS_OBJECT_TYPE_DIRECTORY) {
|
||||
parent->variant_type =
|
||||
YAFFS_OBJECT_TYPE_DIRECTORY;
|
||||
INIT_LIST_HEAD(&parent->
|
||||
variant.dir_variant.children);
|
||||
} else if (!parent
|
||||
|| parent->variant_type !=
|
||||
YAFFS_OBJECT_TYPE_DIRECTORY)
|
||||
{
|
||||
/* Hoosterman, another problem....
|
||||
* We're trying to use a non-directory as a directory
|
||||
*/
|
||||
@ -341,15 +313,16 @@ int yaffs1_Scan(yaffs_Device *dev)
|
||||
(TSTR
|
||||
("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
|
||||
TENDSTR)));
|
||||
parent = dev->lostNFoundDir;
|
||||
parent = dev->lost_n_found;
|
||||
}
|
||||
|
||||
yaffs_AddObjectToDirectory(parent, in);
|
||||
yaffs_add_obj_to_dir(parent, in);
|
||||
|
||||
if (0 && (parent == dev->deletedDir ||
|
||||
parent == dev->unlinkedDir)) {
|
||||
if (0 && (parent == dev->del_dir ||
|
||||
parent ==
|
||||
dev->unlinked_dir)) {
|
||||
in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
|
||||
dev->nDeletedFiles++;
|
||||
dev->n_deleted_files++;
|
||||
}
|
||||
/* Note re hardlinks.
|
||||
* Since we might scan a hardlink before its equivalent object is scanned
|
||||
@ -358,26 +331,27 @@ int yaffs1_Scan(yaffs_Device *dev)
|
||||
* list and fix up all the chains.
|
||||
*/
|
||||
|
||||
switch (in->variantType) {
|
||||
switch (in->variant_type) {
|
||||
case YAFFS_OBJECT_TYPE_UNKNOWN:
|
||||
/* Todo got a problem */
|
||||
break;
|
||||
case YAFFS_OBJECT_TYPE_FILE:
|
||||
if (dev->param.useHeaderFileSize)
|
||||
if (dev->param.
|
||||
use_header_file_size)
|
||||
|
||||
in->variant.fileVariant.
|
||||
fileSize =
|
||||
oh->fileSize;
|
||||
in->variant.
|
||||
file_variant.file_size
|
||||
= oh->file_size;
|
||||
|
||||
break;
|
||||
case YAFFS_OBJECT_TYPE_HARDLINK:
|
||||
in->variant.hardLinkVariant.
|
||||
equivalentObjectId =
|
||||
oh->equivalentObjectId;
|
||||
in->hardLinks.next =
|
||||
(struct ylist_head *)
|
||||
hardList;
|
||||
hardList = in;
|
||||
in->variant.
|
||||
hardlink_variant.equiv_id =
|
||||
oh->equiv_id;
|
||||
in->hard_links.next =
|
||||
(struct list_head *)
|
||||
hard_list;
|
||||
hard_list = in;
|
||||
break;
|
||||
case YAFFS_OBJECT_TYPE_DIRECTORY:
|
||||
/* Do nothing */
|
||||
@ -386,9 +360,11 @@ int yaffs1_Scan(yaffs_Device *dev)
|
||||
/* Do nothing */
|
||||
break;
|
||||
case YAFFS_OBJECT_TYPE_SYMLINK:
|
||||
in->variant.symLinkVariant.alias =
|
||||
yaffs_CloneString(oh->alias);
|
||||
if (!in->variant.symLinkVariant.alias)
|
||||
in->variant.symlink_variant.
|
||||
alias =
|
||||
yaffs_clone_str(oh->alias);
|
||||
if (!in->variant.
|
||||
symlink_variant.alias)
|
||||
alloc_failed = 1;
|
||||
break;
|
||||
}
|
||||
@ -398,68 +374,65 @@ int yaffs1_Scan(yaffs_Device *dev)
|
||||
}
|
||||
|
||||
if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
|
||||
/* If we got this far while scanning, then the block is fully allocated.*/
|
||||
/* If we got this far while scanning, then the block is fully allocated. */
|
||||
state = YAFFS_BLOCK_STATE_FULL;
|
||||
}
|
||||
|
||||
if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
|
||||
/* If the block was partially allocated then treat it as fully allocated.*/
|
||||
/* If the block was partially allocated then treat it as fully allocated. */
|
||||
state = YAFFS_BLOCK_STATE_FULL;
|
||||
dev->allocationBlock = -1;
|
||||
dev->alloc_block = -1;
|
||||
}
|
||||
|
||||
bi->blockState = state;
|
||||
bi->block_state = state;
|
||||
|
||||
/* Now let's see if it was dirty */
|
||||
if (bi->pagesInUse == 0 &&
|
||||
!bi->hasShrinkHeader &&
|
||||
bi->blockState == YAFFS_BLOCK_STATE_FULL) {
|
||||
yaffs_BlockBecameDirty(dev, blk);
|
||||
if (bi->pages_in_use == 0 &&
|
||||
!bi->has_shrink_hdr &&
|
||||
bi->block_state == YAFFS_BLOCK_STATE_FULL) {
|
||||
yaffs_block_became_dirty(dev, blk);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Ok, we've done all the scanning.
|
||||
* Fix up the hard link chains.
|
||||
* We should now have scanned all the objects, now it's time to add these
|
||||
* hardlinks.
|
||||
*/
|
||||
|
||||
yaffs_HardlinkFixup(dev, hardList);
|
||||
yaffs_link_fixup(dev, hard_list);
|
||||
|
||||
/* Fix up any shadowed objects */
|
||||
{
|
||||
struct yaffs_ShadowFixerStruct *fixer;
|
||||
yaffs_Object *obj;
|
||||
struct yaffs_shadow_fixer *fixer;
|
||||
struct yaffs_obj *obj;
|
||||
|
||||
while (shadowFixerList) {
|
||||
fixer = shadowFixerList;
|
||||
shadowFixerList = fixer->next;
|
||||
while (shadow_fixers) {
|
||||
fixer = shadow_fixers;
|
||||
shadow_fixers = fixer->next;
|
||||
/* Complete the rename transaction by deleting the shadowed object
|
||||
* then setting the object header to unshadowed.
|
||||
*/
|
||||
obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);
|
||||
obj = yaffs_find_by_number(dev, fixer->shadowed_id);
|
||||
if (obj)
|
||||
yaffs_DeleteObject(obj);
|
||||
yaffs_del_obj(obj);
|
||||
|
||||
obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
|
||||
obj = yaffs_find_by_number(dev, fixer->obj_id);
|
||||
|
||||
if (obj)
|
||||
yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0, NULL);
|
||||
yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
|
||||
|
||||
YFREE(fixer);
|
||||
}
|
||||
}
|
||||
|
||||
yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
|
||||
yaffs_release_temp_buffer(dev, chunk_data, __LINE__);
|
||||
|
||||
if (alloc_failed)
|
||||
return YAFFS_FAIL;
|
||||
|
||||
T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_Scan ends" TENDSTR)));
|
||||
|
||||
T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_scan ends" TENDSTR)));
|
||||
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,6 @@
|
||||
#define __YAFFS_YAFFS1_H__
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
int yaffs1_Scan(yaffs_Device *dev);
|
||||
int yaffs1_scan(struct yaffs_dev *dev);
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2010 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
@ -7,8 +7,10 @@
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_YAFFS2_H__
|
||||
@ -16,21 +18,22 @@
|
||||
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
void yaffs2_CalcOldestDirtySequence(yaffs_Device *dev);
|
||||
void yaffs2_FindOldestDirtySequence(yaffs_Device *dev);
|
||||
void yaffs2_ClearOldestDirtySequence(yaffs_Device *dev, yaffs_BlockInfo *bi);
|
||||
void yaffs2_UpdateOldestDirtySequence(yaffs_Device *dev, unsigned blockNo, yaffs_BlockInfo *bi);
|
||||
int yaffs2_BlockNotDisqualifiedFromGC(yaffs_Device *dev, yaffs_BlockInfo *bi);
|
||||
__u32 yaffs2_FindRefreshBlock(yaffs_Device *dev);
|
||||
int yaffs2_CheckpointRequired(yaffs_Device *dev);
|
||||
int yaffs2_CalcCheckpointBlocksRequired(yaffs_Device *dev);
|
||||
void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);
|
||||
void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);
|
||||
void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
|
||||
struct yaffs_block_info *bi);
|
||||
void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
|
||||
struct yaffs_block_info *bi);
|
||||
int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);
|
||||
u32 yaffs2_find_refresh_block(struct yaffs_dev *dev);
|
||||
int yaffs2_checkpt_required(struct yaffs_dev *dev);
|
||||
int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev);
|
||||
|
||||
void yaffs2_checkpt_invalidate(struct yaffs_dev *dev);
|
||||
int yaffs2_checkpt_save(struct yaffs_dev *dev);
|
||||
int yaffs2_checkpt_restore(struct yaffs_dev *dev);
|
||||
|
||||
void yaffs2_InvalidateCheckpoint(yaffs_Device *dev);
|
||||
int yaffs2_CheckpointSave(yaffs_Device *dev);
|
||||
int yaffs2_CheckpointRestore(yaffs_Device *dev);
|
||||
|
||||
int yaffs2_HandleHole(yaffs_Object *obj, loff_t newSize);
|
||||
int yaffs2_ScanBackwards(yaffs_Device *dev);
|
||||
int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);
|
||||
int yaffs2_scan_backwards(struct yaffs_dev *dev);
|
||||
|
||||
#endif
|
||||
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2010 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFSINTERFACE_H__
|
||||
#define __YAFFSINTERFACE_H__
|
||||
|
||||
int yaffs_Initialise(unsigned nBlocks);
|
||||
|
||||
#endif
|
@ -13,7 +13,6 @@
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __YPORTENV_H__
|
||||
#define __YPORTENV_H__
|
||||
|
||||
@ -41,7 +40,7 @@
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
|
||||
#include <linux/config.h>
|
||||
#endif
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sched.h>
|
||||
@ -49,6 +48,11 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/sort.h>
|
||||
|
||||
#define YCHAR char
|
||||
#define YUCHAR unsigned char
|
||||
@ -60,6 +64,7 @@
|
||||
#define yaffs_strnlen(s,m) strnlen(s,m)
|
||||
#define yaffs_sprintf sprintf
|
||||
#define yaffs_toupper(a) toupper(a)
|
||||
#define yaffs_sort(base, n, sz, cmp_fn) sort(base, n, sz, cmp_fn, NULL)
|
||||
|
||||
#define Y_INLINE __inline__
|
||||
|
||||
@ -87,7 +92,7 @@
|
||||
#define Y_TIME_CONVERT(x) (x)
|
||||
#endif
|
||||
|
||||
#define yaffs_SumCompare(x, y) ((x) == (y))
|
||||
#define yaffs_sum_cmp(x, y) ((x) == (y))
|
||||
#define yaffs_strcmp(a, b) strcmp(a, b)
|
||||
|
||||
#define TENDSTR "\n"
|
||||
@ -113,7 +118,6 @@
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
|
||||
|
||||
#define YMALLOC(x) malloc(x)
|
||||
#define YFREE(x) free(x)
|
||||
#define YMALLOC_ALT(x) malloc(x)
|
||||
@ -145,7 +149,7 @@
|
||||
#define YAFFS_ROOT_MODE 0755
|
||||
#define YAFFS_LOSTNFOUND_MODE 0700
|
||||
|
||||
#define yaffs_SumCompare(x, y) ((x) == (y))
|
||||
#define yaffs_sum_cmp(x, y) ((x) == (y))
|
||||
#define yaffs_strcmp(a, b) strcmp(a, b)
|
||||
|
||||
#else
|
||||
@ -170,7 +174,7 @@
|
||||
#define O_RDWR 02
|
||||
#endif
|
||||
|
||||
#ifndef O_CREAT
|
||||
#ifndef O_CREAT
|
||||
#define O_CREAT 0100
|
||||
#endif
|
||||
|
||||
@ -210,6 +214,10 @@
|
||||
#define EINVAL 22
|
||||
#endif
|
||||
|
||||
#ifndef ENFILE
|
||||
#define ENFILE 23
|
||||
#endif
|
||||
|
||||
#ifndef EBADF
|
||||
#define EBADF 9
|
||||
#endif
|
||||
@ -218,7 +226,7 @@
|
||||
#define EACCES 13
|
||||
#endif
|
||||
|
||||
#ifndef EXDEV
|
||||
#ifndef EXDEV
|
||||
#define EXDEV 18
|
||||
#endif
|
||||
|
||||
@ -262,7 +270,6 @@
|
||||
#define EISDIR 21
|
||||
#endif
|
||||
|
||||
|
||||
// Mode flags
|
||||
|
||||
#ifndef S_IFMT
|
||||
@ -281,7 +288,7 @@
|
||||
#define S_IFREG 0100000
|
||||
#endif
|
||||
|
||||
#ifndef S_IREAD
|
||||
#ifndef S_IREAD
|
||||
#define S_IREAD 0000400
|
||||
#endif
|
||||
|
||||
@ -329,5 +336,4 @@
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user