diff options
Diffstat (limited to 'drivers/mtd/mtdoops.c')
-rw-r--r-- | drivers/mtd/mtdoops.c | 109 |
1 files changed, 62 insertions, 47 deletions
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index 3d4a2ffb5b01..2f11585b5613 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -7,6 +7,8 @@ * Author: Richard Purdie <rpurdie@openedhand.com> */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/console.h> @@ -93,9 +95,9 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset) ret = mtd_erase(mtd, &erase); if (ret) { - 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); + pr_warn("erase of region [0x%llx, 0x%llx] on \"%s\" failed\n", + (unsigned long long)erase.addr, + (unsigned long long)erase.len, mtddev); return ret; } @@ -106,29 +108,8 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset) return 0; } -static void mtdoops_inc_counter(struct mtdoops_context *cxt) -{ - cxt->nextpage++; - if (cxt->nextpage >= cxt->oops_pages) - cxt->nextpage = 0; - cxt->nextcount++; - if (cxt->nextcount == 0xffffffff) - cxt->nextcount = 0; - - if (page_is_used(cxt, cxt->nextpage)) { - schedule_work(&cxt->work_erase); - return; - } - - printk(KERN_DEBUG "mtdoops: ready %d, %d (no erase)\n", - cxt->nextpage, cxt->nextcount); -} - -/* Scheduled work - when we can't proceed without erasing a block */ -static void mtdoops_workfunc_erase(struct work_struct *work) +static void mtdoops_erase(struct mtdoops_context *cxt) { - struct mtdoops_context *cxt = - container_of(work, struct mtdoops_context, work_erase); struct mtd_info *mtd = cxt->mtd; int i = 0, j, ret, mod; @@ -145,20 +126,20 @@ static void mtdoops_workfunc_erase(struct work_struct *work) while ((ret = mtd_block_isbad(mtd, cxt->nextpage * record_size)) > 0) { badblock: - printk(KERN_WARNING "mtdoops: bad block at %08lx\n", - cxt->nextpage * record_size); + pr_warn("bad block at %08lx\n", + cxt->nextpage * record_size); i++; cxt->nextpage = cxt->nextpage + (mtd->erasesize / record_size); if (cxt->nextpage >= cxt->oops_pages) cxt->nextpage = 0; if (i == cxt->oops_pages / (mtd->erasesize / record_size)) { - printk(KERN_ERR "mtdoops: all blocks bad!\n"); + pr_err("all blocks bad!\n"); return; } } if (ret < 0) { - printk(KERN_ERR "mtdoops: mtd_block_isbad failed, aborting\n"); + pr_err("mtd_block_isbad failed, aborting\n"); return; } @@ -166,21 +147,55 @@ badblock: ret = mtdoops_erase_block(cxt, cxt->nextpage * record_size); if (ret >= 0) { - printk(KERN_DEBUG "mtdoops: ready %d, %d\n", - cxt->nextpage, cxt->nextcount); + pr_debug("ready %d, %d\n", + cxt->nextpage, cxt->nextcount); return; } if (ret == -EIO) { ret = mtd_block_markbad(mtd, cxt->nextpage * record_size); if (ret < 0 && ret != -EOPNOTSUPP) { - printk(KERN_ERR "mtdoops: block_markbad failed, aborting\n"); + pr_err("block_markbad failed, aborting\n"); return; } } goto badblock; } +/* Scheduled work - when we can't proceed without erasing a block */ +static void mtdoops_workfunc_erase(struct work_struct *work) +{ + struct mtdoops_context *cxt = + container_of(work, struct mtdoops_context, work_erase); + mtdoops_erase(cxt); +} + +static void mtdoops_inc_counter(struct mtdoops_context *cxt, int panic) +{ + cxt->nextpage++; + if (cxt->nextpage >= cxt->oops_pages) + cxt->nextpage = 0; + cxt->nextcount++; + if (cxt->nextcount == 0xffffffff) + cxt->nextcount = 0; + + if (page_is_used(cxt, cxt->nextpage)) { + pr_debug("not ready %d, %d (erase %s)\n", + cxt->nextpage, cxt->nextcount, + panic ? "immediately" : "scheduled"); + if (panic) { + /* In case of panic, erase immediately */ + mtdoops_erase(cxt); + } else { + /* Otherwise, schedule work to erase it "nicely" */ + schedule_work(&cxt->work_erase); + } + } else { + pr_debug("ready %d, %d (no erase)\n", + cxt->nextpage, cxt->nextcount); + } +} + static void mtdoops_write(struct mtdoops_context *cxt, int panic) { struct mtd_info *mtd = cxt->mtd; @@ -201,7 +216,7 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic) ret = mtd_panic_write(mtd, cxt->nextpage * record_size, record_size, &retlen, cxt->oops_buf); if (ret == -EOPNOTSUPP) { - printk(KERN_ERR "mtdoops: Cannot write from panic without panic_write\n"); + pr_err("Cannot write from panic without panic_write\n"); goto out; } } else @@ -209,12 +224,12 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic) record_size, &retlen, cxt->oops_buf); if (retlen != record_size || ret < 0) - printk(KERN_ERR "mtdoops: write failure at %ld (%td of %ld written), error %d\n", + pr_err("write failure at %ld (%td of %ld written), error %d\n", cxt->nextpage * record_size, retlen, record_size, ret); mark_page_used(cxt, cxt->nextpage); memset(cxt->oops_buf, 0xff, record_size); - mtdoops_inc_counter(cxt); + mtdoops_inc_counter(cxt, panic); out: clear_bit(0, &cxt->oops_buf_busy); } @@ -244,7 +259,7 @@ static void find_next_position(struct mtdoops_context *cxt) &retlen, (u_char *)&hdr); if (retlen != sizeof(hdr) || (ret < 0 && !mtd_is_bitflip(ret))) { - printk(KERN_ERR "mtdoops: read failure at %ld (%zu of %zu read), err %d\n", + pr_err("read failure at %ld (%zu of %zu read), err %d\n", page * record_size, retlen, sizeof(hdr), ret); continue; } @@ -279,7 +294,7 @@ static void find_next_position(struct mtdoops_context *cxt) cxt->nextcount = maxcount; } - mtdoops_inc_counter(cxt); + mtdoops_inc_counter(cxt, 0); } static void mtdoops_do_dump(struct kmsg_dumper *dumper, @@ -324,17 +339,17 @@ static void mtdoops_notify_add(struct mtd_info *mtd) return; if (mtd->size < mtd->erasesize * 2) { - printk(KERN_ERR "mtdoops: MTD partition %d not big enough for mtdoops\n", + pr_err("MTD partition %d not big enough for mtdoops\n", mtd->index); return; } if (mtd->erasesize < record_size) { - printk(KERN_ERR "mtdoops: eraseblock size of MTD partition %d too small\n", + pr_err("eraseblock size of MTD partition %d too small\n", mtd->index); return; } if (mtd->size > MTDOOPS_MAX_MTD_SIZE) { - printk(KERN_ERR "mtdoops: mtd%d is too large (limit is %d MiB)\n", + pr_err("mtd%d is too large (limit is %d MiB)\n", mtd->index, MTDOOPS_MAX_MTD_SIZE / 1024 / 1024); return; } @@ -345,7 +360,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd) DIV_ROUND_UP(mtdoops_pages, BITS_PER_LONG))); if (!cxt->oops_page_used) { - printk(KERN_ERR "mtdoops: could not allocate page array\n"); + pr_err("could not allocate page array\n"); return; } @@ -353,7 +368,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd) cxt->dump.dump = mtdoops_do_dump; err = kmsg_dump_register(&cxt->dump); if (err) { - printk(KERN_ERR "mtdoops: registering kmsg dumper failed, error %d\n", err); + pr_err("registering kmsg dumper failed, error %d\n", err); vfree(cxt->oops_page_used); cxt->oops_page_used = NULL; return; @@ -362,7 +377,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd) cxt->mtd = mtd; cxt->oops_pages = (int)mtd->size / record_size; find_next_position(cxt); - printk(KERN_INFO "mtdoops: Attached to MTD device %d\n", mtd->index); + pr_info("Attached to MTD device %d\n", mtd->index); } static void mtdoops_notify_remove(struct mtd_info *mtd) @@ -373,7 +388,7 @@ static void mtdoops_notify_remove(struct mtd_info *mtd) return; if (kmsg_dump_unregister(&cxt->dump) < 0) - printk(KERN_WARNING "mtdoops: could not unregister kmsg_dumper\n"); + pr_warn("could not unregister kmsg_dumper\n"); cxt->mtd = NULL; flush_work(&cxt->work_erase); @@ -393,15 +408,15 @@ static int __init mtdoops_init(void) char *endp; if (strlen(mtddev) == 0) { - printk(KERN_ERR "mtdoops: mtd device (mtddev=name/number) must be supplied\n"); + pr_err("mtd device (mtddev=name/number) must be supplied\n"); return -EINVAL; } if ((record_size & 4095) != 0) { - printk(KERN_ERR "mtdoops: record_size must be a multiple of 4096\n"); + pr_err("record_size must be a multiple of 4096\n"); return -EINVAL; } if (record_size < 4096) { - printk(KERN_ERR "mtdoops: record_size must be over 4096 bytes\n"); + pr_err("record_size must be over 4096 bytes\n"); return -EINVAL; } |