forked from Minki/linux
mtd: Stop assuming mtd_erase() is asynchronous
None of the mtd->_erase() implementations work in an asynchronous manner, so let's simplify MTD users that call mtd_erase(). All they need to do is check the value returned by mtd_erase() and assume that != 0 means failure. Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> Reviewed-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
parent
dcba51bbb9
commit
884cfd9023
@ -95,9 +95,6 @@ static int bcm47xxsflash_erase(struct mtd_info *mtd, struct erase_info *erase)
|
||||
else
|
||||
erase->state = MTD_ERASE_DONE;
|
||||
|
||||
if (erase->callback)
|
||||
erase->callback(erase);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -140,12 +140,6 @@ typedef struct partition_t {
|
||||
#define XFER_PREPARED 0x03
|
||||
#define XFER_FAILED 0x04
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
|
||||
static void ftl_erase_callback(struct erase_info *done);
|
||||
|
||||
|
||||
/*======================================================================
|
||||
|
||||
Scan_header() checks to see if a memory region contains an FTL
|
||||
@ -349,17 +343,19 @@ static int erase_xfer(partition_t *part,
|
||||
return -ENOMEM;
|
||||
|
||||
erase->mtd = part->mbd.mtd;
|
||||
erase->callback = ftl_erase_callback;
|
||||
erase->addr = xfer->Offset;
|
||||
erase->len = 1 << part->header.EraseUnitSize;
|
||||
erase->priv = (u_long)part;
|
||||
|
||||
ret = mtd_erase(part->mbd.mtd, erase);
|
||||
if (!ret) {
|
||||
xfer->state = XFER_ERASED;
|
||||
xfer->EraseCount++;
|
||||
} else {
|
||||
xfer->state = XFER_FAILED;
|
||||
pr_notice("ftl_cs: erase failed: err = %d\n", ret);
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
xfer->EraseCount++;
|
||||
else
|
||||
kfree(erase);
|
||||
kfree(erase);
|
||||
|
||||
return ret;
|
||||
} /* erase_xfer */
|
||||
@ -371,37 +367,6 @@ static int erase_xfer(partition_t *part,
|
||||
|
||||
======================================================================*/
|
||||
|
||||
static void ftl_erase_callback(struct erase_info *erase)
|
||||
{
|
||||
partition_t *part;
|
||||
struct xfer_info_t *xfer;
|
||||
int i;
|
||||
|
||||
/* Look up the transfer unit */
|
||||
part = (partition_t *)(erase->priv);
|
||||
|
||||
for (i = 0; i < part->header.NumTransferUnits; i++)
|
||||
if (part->XferInfo[i].Offset == erase->addr) break;
|
||||
|
||||
if (i == part->header.NumTransferUnits) {
|
||||
printk(KERN_NOTICE "ftl_cs: internal error: "
|
||||
"erase lookup failed!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
xfer = &part->XferInfo[i];
|
||||
if (erase->state == MTD_ERASE_DONE)
|
||||
xfer->state = XFER_ERASED;
|
||||
else {
|
||||
xfer->state = XFER_FAILED;
|
||||
printk(KERN_NOTICE "ftl_cs: erase failed: state = %d\n",
|
||||
erase->state);
|
||||
}
|
||||
|
||||
kfree(erase);
|
||||
|
||||
} /* ftl_erase_callback */
|
||||
|
||||
static int prepare_xfer(partition_t *part, int i)
|
||||
{
|
||||
erase_unit_header_t header;
|
||||
|
@ -393,9 +393,10 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block)
|
||||
mark only the failed block in the bbt. */
|
||||
for (physblock = 0; physblock < inftl->EraseSize;
|
||||
physblock += instr->len, instr->addr += instr->len) {
|
||||
mtd_erase(inftl->mbd.mtd, instr);
|
||||
int ret;
|
||||
|
||||
if (instr->state == MTD_ERASE_FAILED) {
|
||||
ret = mtd_erase(inftl->mbd.mtd, instr);
|
||||
if (ret) {
|
||||
printk(KERN_WARNING "INFTL: error while formatting block %d\n",
|
||||
block);
|
||||
goto fail;
|
||||
|
@ -55,48 +55,28 @@ struct mtdblk_dev {
|
||||
* being written to until a different sector is required.
|
||||
*/
|
||||
|
||||
static void erase_callback(struct erase_info *done)
|
||||
{
|
||||
wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
|
||||
wake_up(wait_q);
|
||||
}
|
||||
|
||||
static int erase_write (struct mtd_info *mtd, unsigned long pos,
|
||||
int len, const char *buf)
|
||||
{
|
||||
struct erase_info erase;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
wait_queue_head_t wait_q;
|
||||
size_t retlen;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* First, let's erase the flash block.
|
||||
*/
|
||||
|
||||
init_waitqueue_head(&wait_q);
|
||||
erase.mtd = mtd;
|
||||
erase.callback = erase_callback;
|
||||
erase.addr = pos;
|
||||
erase.len = len;
|
||||
erase.priv = (u_long)&wait_q;
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
add_wait_queue(&wait_q, &wait);
|
||||
|
||||
ret = mtd_erase(mtd, &erase);
|
||||
if (ret) {
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&wait_q, &wait);
|
||||
printk (KERN_WARNING "mtdblock: erase of region [0x%lx, 0x%x] "
|
||||
"on \"%s\" failed\n",
|
||||
pos, len, mtd->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
schedule(); /* Wait for erase to finish. */
|
||||
remove_wait_queue(&wait_q, &wait);
|
||||
|
||||
/*
|
||||
* Next, write the data to flash.
|
||||
*/
|
||||
|
@ -324,10 +324,6 @@ static ssize_t mtdchar_write(struct file *file, const char __user *buf, size_t c
|
||||
IOCTL calls for getting device parameters.
|
||||
|
||||
======================================================================*/
|
||||
static void mtdchar_erase_callback (struct erase_info *instr)
|
||||
{
|
||||
wake_up((wait_queue_head_t *)instr->priv);
|
||||
}
|
||||
|
||||
static int otp_select_filemode(struct mtd_file_info *mfi, int mode)
|
||||
{
|
||||
@ -709,11 +705,6 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
|
||||
if (!erase)
|
||||
ret = -ENOMEM;
|
||||
else {
|
||||
wait_queue_head_t waitq;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
init_waitqueue_head(&waitq);
|
||||
|
||||
if (cmd == MEMERASE64) {
|
||||
struct erase_info_user64 einfo64;
|
||||
|
||||
@ -736,30 +727,8 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
|
||||
erase->len = einfo32.length;
|
||||
}
|
||||
erase->mtd = mtd;
|
||||
erase->callback = mtdchar_erase_callback;
|
||||
erase->priv = (unsigned long)&waitq;
|
||||
|
||||
/*
|
||||
FIXME: Allow INTERRUPTIBLE. Which means
|
||||
not having the wait_queue head on the stack.
|
||||
|
||||
If the wq_head is on the stack, and we
|
||||
leave because we got interrupted, then the
|
||||
wq_head is no longer there when the
|
||||
callback routine tries to wake us up.
|
||||
*/
|
||||
ret = mtd_erase(mtd, erase);
|
||||
if (!ret) {
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
add_wait_queue(&waitq, &wait);
|
||||
if (erase->state != MTD_ERASE_DONE &&
|
||||
erase->state != MTD_ERASE_FAILED)
|
||||
schedule();
|
||||
remove_wait_queue(&waitq, &wait);
|
||||
set_current_state(TASK_RUNNING);
|
||||
|
||||
ret = (erase->state == MTD_ERASE_FAILED)?-EIO:0;
|
||||
}
|
||||
kfree(erase);
|
||||
}
|
||||
break;
|
||||
|
@ -333,45 +333,6 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void concat_erase_callback(struct erase_info *instr)
|
||||
{
|
||||
wake_up((wait_queue_head_t *) instr->priv);
|
||||
}
|
||||
|
||||
static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
|
||||
{
|
||||
int err;
|
||||
wait_queue_head_t waitq;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
/*
|
||||
* This code was stol^H^H^H^Hinspired by mtdchar.c
|
||||
*/
|
||||
init_waitqueue_head(&waitq);
|
||||
|
||||
erase->mtd = mtd;
|
||||
erase->callback = concat_erase_callback;
|
||||
erase->priv = (unsigned long) &waitq;
|
||||
|
||||
/*
|
||||
* FIXME: Allow INTERRUPTIBLE. Which means
|
||||
* not having the wait_queue head on the stack.
|
||||
*/
|
||||
err = mtd_erase(mtd, erase);
|
||||
if (!err) {
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
add_wait_queue(&waitq, &wait);
|
||||
if (erase->state != MTD_ERASE_DONE
|
||||
&& erase->state != MTD_ERASE_FAILED)
|
||||
schedule();
|
||||
remove_wait_queue(&waitq, &wait);
|
||||
set_current_state(TASK_RUNNING);
|
||||
|
||||
err = (erase->state == MTD_ERASE_FAILED) ? -EIO : 0;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
{
|
||||
struct mtd_concat *concat = CONCAT(mtd);
|
||||
@ -466,7 +427,8 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
erase->len = length;
|
||||
|
||||
length -= erase->len;
|
||||
if ((err = concat_dev_erase(subdev, erase))) {
|
||||
erase->mtd = subdev;
|
||||
if ((err = mtd_erase(subdev, erase))) {
|
||||
/* sanity check: should never happen since
|
||||
* block alignment has been checked above */
|
||||
BUG_ON(err == -EINVAL);
|
||||
@ -487,12 +449,8 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
}
|
||||
instr->state = erase->state;
|
||||
kfree(erase);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (instr->callback)
|
||||
instr->callback(instr);
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
|
@ -945,11 +945,9 @@ void __put_mtd_device(struct mtd_info *mtd)
|
||||
EXPORT_SYMBOL_GPL(__put_mtd_device);
|
||||
|
||||
/*
|
||||
* Erase is an asynchronous operation. Device drivers are supposed
|
||||
* to call instr->callback() whenever the operation completes, even
|
||||
* if it completes with a failure.
|
||||
* Callers are supposed to pass a callback function and wait for it
|
||||
* to be called before writing to the block.
|
||||
* Erase is an synchronous operation. Device drivers are epected to return a
|
||||
* negative error code if the operation failed and update instr->fail_addr
|
||||
* to point the portion that was not properly erased.
|
||||
*/
|
||||
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
{
|
||||
|
@ -84,12 +84,6 @@ static int page_is_used(struct mtdoops_context *cxt, int page)
|
||||
return test_bit(page, cxt->oops_page_used);
|
||||
}
|
||||
|
||||
static void mtdoops_erase_callback(struct erase_info *done)
|
||||
{
|
||||
wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
|
||||
wake_up(wait_q);
|
||||
}
|
||||
|
||||
static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset)
|
||||
{
|
||||
struct mtd_info *mtd = cxt->mtd;
|
||||
@ -97,34 +91,21 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset)
|
||||
u32 start_page = start_page_offset / record_size;
|
||||
u32 erase_pages = mtd->erasesize / record_size;
|
||||
struct erase_info erase;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
wait_queue_head_t wait_q;
|
||||
int ret;
|
||||
int page;
|
||||
|
||||
init_waitqueue_head(&wait_q);
|
||||
erase.mtd = mtd;
|
||||
erase.callback = mtdoops_erase_callback;
|
||||
erase.addr = offset;
|
||||
erase.len = mtd->erasesize;
|
||||
erase.priv = (u_long)&wait_q;
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
add_wait_queue(&wait_q, &wait);
|
||||
|
||||
ret = mtd_erase(mtd, &erase);
|
||||
if (ret) {
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&wait_q, &wait);
|
||||
printk(KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] on \"%s\" failed\n",
|
||||
(unsigned long long)erase.addr,
|
||||
(unsigned long long)erase.len, mtddev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
schedule(); /* Wait for erase to finish. */
|
||||
remove_wait_queue(&wait_q, &wait);
|
||||
|
||||
/* Mark pages as unused */
|
||||
for (page = start_page; page < start_page + erase_pages; page++)
|
||||
mark_page_unused(cxt, page);
|
||||
|
@ -222,8 +222,6 @@ void mtd_erase_callback(struct erase_info *instr)
|
||||
instr->fail_addr -= part->offset;
|
||||
instr->addr -= part->offset;
|
||||
}
|
||||
if (instr->callback)
|
||||
instr->callback(instr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtd_erase_callback);
|
||||
|
||||
|
@ -536,18 +536,10 @@ static void mtdswap_store_eb(struct mtdswap_dev *d, struct swap_eb *eb)
|
||||
mtdswap_rb_add(d, eb, MTDSWAP_HIFRAG);
|
||||
}
|
||||
|
||||
|
||||
static void mtdswap_erase_callback(struct erase_info *done)
|
||||
{
|
||||
wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
|
||||
wake_up(wait_q);
|
||||
}
|
||||
|
||||
static int mtdswap_erase_block(struct mtdswap_dev *d, struct swap_eb *eb)
|
||||
{
|
||||
struct mtd_info *mtd = d->mtd;
|
||||
struct erase_info erase;
|
||||
wait_queue_head_t wq;
|
||||
unsigned int retries = 0;
|
||||
int ret;
|
||||
|
||||
@ -556,14 +548,11 @@ static int mtdswap_erase_block(struct mtdswap_dev *d, struct swap_eb *eb)
|
||||
d->max_erase_count = eb->erase_count;
|
||||
|
||||
retry:
|
||||
init_waitqueue_head(&wq);
|
||||
memset(&erase, 0, sizeof(struct erase_info));
|
||||
|
||||
erase.mtd = mtd;
|
||||
erase.callback = mtdswap_erase_callback;
|
||||
erase.addr = mtdswap_eb_offset(d, eb);
|
||||
erase.len = mtd->erasesize;
|
||||
erase.priv = (u_long)&wq;
|
||||
|
||||
ret = mtd_erase(mtd, &erase);
|
||||
if (ret) {
|
||||
@ -582,27 +571,6 @@ retry:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = wait_event_interruptible(wq, erase.state == MTD_ERASE_DONE ||
|
||||
erase.state == MTD_ERASE_FAILED);
|
||||
if (ret) {
|
||||
dev_err(d->dev, "Interrupted erase block %#llx erasure on %s\n",
|
||||
erase.addr, mtd->name);
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if (erase.state == MTD_ERASE_FAILED) {
|
||||
if (retries++ < MTDSWAP_ERASE_RETRIES) {
|
||||
dev_warn(d->dev,
|
||||
"erase of erase block %#llx on %s failed",
|
||||
erase.addr, mtd->name);
|
||||
yield();
|
||||
goto retry;
|
||||
}
|
||||
|
||||
mtdswap_handle_badblock(d, eb);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -331,9 +331,7 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block)
|
||||
instr->mtd = nftl->mbd.mtd;
|
||||
instr->addr = block * nftl->EraseSize;
|
||||
instr->len = nftl->EraseSize;
|
||||
mtd_erase(mtd, instr);
|
||||
|
||||
if (instr->state == MTD_ERASE_FAILED) {
|
||||
if (mtd_erase(mtd, instr)) {
|
||||
printk("Error while formatting block %d\n", block);
|
||||
goto fail;
|
||||
}
|
||||
|
@ -266,91 +266,55 @@ static int rfd_ftl_readsect(struct mtd_blktrans_dev *dev, u_long sector, char *b
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void erase_callback(struct erase_info *erase)
|
||||
{
|
||||
struct partition *part;
|
||||
u16 magic;
|
||||
int i, rc;
|
||||
size_t retlen;
|
||||
|
||||
part = (struct partition*)erase->priv;
|
||||
|
||||
i = (u32)erase->addr / part->block_size;
|
||||
if (i >= part->total_blocks || part->blocks[i].offset != erase->addr ||
|
||||
erase->addr > UINT_MAX) {
|
||||
printk(KERN_ERR PREFIX "erase callback for unknown offset %llx "
|
||||
"on '%s'\n", (unsigned long long)erase->addr, part->mbd.mtd->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (erase->state != MTD_ERASE_DONE) {
|
||||
printk(KERN_WARNING PREFIX "erase failed at 0x%llx on '%s', "
|
||||
"state %d\n", (unsigned long long)erase->addr,
|
||||
part->mbd.mtd->name, erase->state);
|
||||
|
||||
part->blocks[i].state = BLOCK_FAILED;
|
||||
part->blocks[i].free_sectors = 0;
|
||||
part->blocks[i].used_sectors = 0;
|
||||
|
||||
kfree(erase);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
magic = cpu_to_le16(RFD_MAGIC);
|
||||
|
||||
part->blocks[i].state = BLOCK_ERASED;
|
||||
part->blocks[i].free_sectors = part->data_sectors_per_block;
|
||||
part->blocks[i].used_sectors = 0;
|
||||
part->blocks[i].erases++;
|
||||
|
||||
rc = mtd_write(part->mbd.mtd, part->blocks[i].offset, sizeof(magic),
|
||||
&retlen, (u_char *)&magic);
|
||||
|
||||
if (!rc && retlen != sizeof(magic))
|
||||
rc = -EIO;
|
||||
|
||||
if (rc) {
|
||||
printk(KERN_ERR PREFIX "'%s': unable to write RFD "
|
||||
"header at 0x%lx\n",
|
||||
part->mbd.mtd->name,
|
||||
part->blocks[i].offset);
|
||||
part->blocks[i].state = BLOCK_FAILED;
|
||||
}
|
||||
else
|
||||
part->blocks[i].state = BLOCK_OK;
|
||||
|
||||
kfree(erase);
|
||||
}
|
||||
|
||||
static int erase_block(struct partition *part, int block)
|
||||
{
|
||||
struct erase_info *erase;
|
||||
int rc = -ENOMEM;
|
||||
int rc;
|
||||
|
||||
erase = kmalloc(sizeof(struct erase_info), GFP_KERNEL);
|
||||
if (!erase)
|
||||
goto err;
|
||||
return -ENOMEM;
|
||||
|
||||
erase->mtd = part->mbd.mtd;
|
||||
erase->callback = erase_callback;
|
||||
erase->addr = part->blocks[block].offset;
|
||||
erase->len = part->block_size;
|
||||
erase->priv = (u_long)part;
|
||||
|
||||
part->blocks[block].state = BLOCK_ERASING;
|
||||
part->blocks[block].free_sectors = 0;
|
||||
|
||||
rc = mtd_erase(part->mbd.mtd, erase);
|
||||
|
||||
if (rc) {
|
||||
printk(KERN_ERR PREFIX "erase of region %llx,%llx on '%s' "
|
||||
"failed\n", (unsigned long long)erase->addr,
|
||||
(unsigned long long)erase->len, part->mbd.mtd->name);
|
||||
kfree(erase);
|
||||
part->blocks[block].state = BLOCK_FAILED;
|
||||
part->blocks[block].free_sectors = 0;
|
||||
part->blocks[block].used_sectors = 0;
|
||||
} else {
|
||||
u16 magic = cpu_to_le16(RFD_MAGIC);
|
||||
size_t retlen;
|
||||
|
||||
part->blocks[block].state = BLOCK_ERASED;
|
||||
part->blocks[block].free_sectors = part->data_sectors_per_block;
|
||||
part->blocks[block].used_sectors = 0;
|
||||
part->blocks[block].erases++;
|
||||
|
||||
rc = mtd_write(part->mbd.mtd, part->blocks[block].offset,
|
||||
sizeof(magic), &retlen, (u_char *)&magic);
|
||||
if (!rc && retlen != sizeof(magic))
|
||||
rc = -EIO;
|
||||
|
||||
if (rc) {
|
||||
pr_err(PREFIX "'%s': unable to write RFD header at 0x%lx\n",
|
||||
part->mbd.mtd->name, part->blocks[block].offset);
|
||||
part->blocks[block].state = BLOCK_FAILED;
|
||||
} else {
|
||||
part->blocks[block].state = BLOCK_OK;
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
kfree(erase);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -461,10 +461,8 @@ static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block,
|
||||
struct erase_info erase;
|
||||
|
||||
erase.mtd = mtd;
|
||||
erase.callback = sm_erase_callback;
|
||||
erase.addr = sm_mkoffset(ftl, zone_num, block, 0);
|
||||
erase.len = ftl->block_size;
|
||||
erase.priv = (u_long)ftl;
|
||||
|
||||
if (ftl->unstable)
|
||||
return -EIO;
|
||||
@ -482,15 +480,6 @@ static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (erase.state == MTD_ERASE_PENDING)
|
||||
wait_for_completion(&ftl->erase_completion);
|
||||
|
||||
if (erase.state != MTD_ERASE_DONE) {
|
||||
sm_printk("erase of block %d in zone %d failed after wait",
|
||||
block, zone_num);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (put_free)
|
||||
kfifo_in(&zone->free_sectors,
|
||||
(const unsigned char *)&block, sizeof(block));
|
||||
@ -501,12 +490,6 @@ error:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static void sm_erase_callback(struct erase_info *self)
|
||||
{
|
||||
struct sm_ftl *ftl = (struct sm_ftl *)self->priv;
|
||||
complete(&ftl->erase_completion);
|
||||
}
|
||||
|
||||
/* Thoroughly test that block is valid. */
|
||||
static int sm_check_block(struct sm_ftl *ftl, int zone, int block)
|
||||
{
|
||||
@ -1141,7 +1124,6 @@ static void sm_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
|
||||
mutex_init(&ftl->mutex);
|
||||
timer_setup(&ftl->timer, sm_cache_flush_timer, 0);
|
||||
INIT_WORK(&ftl->flush_work, sm_cache_flush_work);
|
||||
init_completion(&ftl->erase_completion);
|
||||
|
||||
/* Read media information */
|
||||
if (sm_get_media_info(ftl, mtd)) {
|
||||
|
@ -53,9 +53,6 @@ struct sm_ftl {
|
||||
struct work_struct flush_work;
|
||||
struct timer_list timer;
|
||||
|
||||
/* Async erase stuff */
|
||||
struct completion erase_completion;
|
||||
|
||||
/* Geometry stuff */
|
||||
int heads;
|
||||
int sectors;
|
||||
@ -86,7 +83,6 @@ struct chs_entry {
|
||||
printk(KERN_DEBUG "sm_ftl" ": " format "\n", ## __VA_ARGS__)
|
||||
|
||||
|
||||
static void sm_erase_callback(struct erase_info *self);
|
||||
static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block,
|
||||
int put_free);
|
||||
static void sm_mark_block_bad(struct sm_ftl *ftl, int zone_num, int block);
|
||||
|
@ -24,10 +24,6 @@ int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (ei.state == MTD_ERASE_FAILED) {
|
||||
pr_info("some erase error occurred at EB %d\n", ebnum);
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -70,12 +70,6 @@ static int multiblock_erase(int ebnum, int blocks)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (ei.state == MTD_ERASE_FAILED) {
|
||||
pr_err("some erase error occurred at EB %d,"
|
||||
"blocks %d\n", ebnum, blocks);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -308,18 +308,6 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* erase_callback - MTD erasure call-back.
|
||||
* @ei: MTD erase information object.
|
||||
*
|
||||
* Note, even though MTD erase interface is asynchronous, all the current
|
||||
* implementations are synchronous anyway.
|
||||
*/
|
||||
static void erase_callback(struct erase_info *ei)
|
||||
{
|
||||
wake_up_interruptible((wait_queue_head_t *)ei->priv);
|
||||
}
|
||||
|
||||
/**
|
||||
* do_sync_erase - synchronously erase a physical eraseblock.
|
||||
* @ubi: UBI device description object
|
||||
@ -333,7 +321,6 @@ static int do_sync_erase(struct ubi_device *ubi, int pnum)
|
||||
{
|
||||
int err, retries = 0;
|
||||
struct erase_info ei;
|
||||
wait_queue_head_t wq;
|
||||
|
||||
dbg_io("erase PEB %d", pnum);
|
||||
ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
|
||||
@ -344,14 +331,11 @@ static int do_sync_erase(struct ubi_device *ubi, int pnum)
|
||||
}
|
||||
|
||||
retry:
|
||||
init_waitqueue_head(&wq);
|
||||
memset(&ei, 0, sizeof(struct erase_info));
|
||||
|
||||
ei.mtd = ubi->mtd;
|
||||
ei.addr = (loff_t)pnum * ubi->peb_size;
|
||||
ei.len = ubi->peb_size;
|
||||
ei.callback = erase_callback;
|
||||
ei.priv = (unsigned long)&wq;
|
||||
|
||||
err = mtd_erase(ubi->mtd, &ei);
|
||||
if (err) {
|
||||
@ -366,25 +350,6 @@ retry:
|
||||
return err;
|
||||
}
|
||||
|
||||
err = wait_event_interruptible(wq, ei.state == MTD_ERASE_DONE ||
|
||||
ei.state == MTD_ERASE_FAILED);
|
||||
if (err) {
|
||||
ubi_err(ubi, "interrupted PEB %d erasure", pnum);
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if (ei.state == MTD_ERASE_FAILED) {
|
||||
if (retries++ < UBI_IO_RETRIES) {
|
||||
ubi_warn(ubi, "error while erasing PEB %d, retry",
|
||||
pnum);
|
||||
yield();
|
||||
goto retry;
|
||||
}
|
||||
ubi_err(ubi, "cannot erase PEB %d", pnum);
|
||||
dump_stack();
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
err = ubi_self_check_all_ff(ubi, pnum, 0, ubi->peb_size);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -21,14 +21,6 @@
|
||||
#include <linux/pagemap.h>
|
||||
#include "nodelist.h"
|
||||
|
||||
struct erase_priv_struct {
|
||||
struct jffs2_eraseblock *jeb;
|
||||
struct jffs2_sb_info *c;
|
||||
};
|
||||
|
||||
#ifndef __ECOS
|
||||
static void jffs2_erase_callback(struct erase_info *);
|
||||
#endif
|
||||
static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
|
||||
static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
|
||||
static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
|
||||
@ -51,7 +43,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
|
||||
jffs2_dbg(1, "%s(): erase block %#08x (range %#08x-%#08x)\n",
|
||||
__func__,
|
||||
jeb->offset, jeb->offset, jeb->offset + c->sector_size);
|
||||
instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL);
|
||||
instr = kmalloc(sizeof(struct erase_info), GFP_KERNEL);
|
||||
if (!instr) {
|
||||
pr_warn("kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
|
||||
mutex_lock(&c->erase_free_sem);
|
||||
@ -70,15 +62,13 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
|
||||
instr->mtd = c->mtd;
|
||||
instr->addr = jeb->offset;
|
||||
instr->len = c->sector_size;
|
||||
instr->callback = jffs2_erase_callback;
|
||||
instr->priv = (unsigned long)(&instr[1]);
|
||||
|
||||
((struct erase_priv_struct *)instr->priv)->jeb = jeb;
|
||||
((struct erase_priv_struct *)instr->priv)->c = c;
|
||||
|
||||
ret = mtd_erase(c->mtd, instr);
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
jffs2_erase_succeeded(c, jeb);
|
||||
kfree(instr);
|
||||
return;
|
||||
}
|
||||
|
||||
bad_offset = instr->fail_addr;
|
||||
kfree(instr);
|
||||
@ -214,22 +204,6 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock
|
||||
wake_up(&c->erase_wait);
|
||||
}
|
||||
|
||||
#ifndef __ECOS
|
||||
static void jffs2_erase_callback(struct erase_info *instr)
|
||||
{
|
||||
struct erase_priv_struct *priv = (void *)instr->priv;
|
||||
|
||||
if(instr->state != MTD_ERASE_DONE) {
|
||||
pr_warn("Erase at 0x%08llx finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n",
|
||||
(unsigned long long)instr->addr, instr->state);
|
||||
jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr);
|
||||
} else {
|
||||
jffs2_erase_succeeded(priv->c, priv->jeb);
|
||||
}
|
||||
kfree(instr);
|
||||
}
|
||||
#endif /* !__ECOS */
|
||||
|
||||
/* Hmmm. Maybe we should accept the extra space it takes and make
|
||||
this a standard doubly-linked list? */
|
||||
static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
|
||||
|
@ -48,8 +48,6 @@ struct erase_info {
|
||||
uint64_t addr;
|
||||
uint64_t len;
|
||||
uint64_t fail_addr;
|
||||
void (*callback) (struct erase_info *self);
|
||||
u_long priv;
|
||||
u_char state;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user