[PATCH v2 41/46] mtd: nandsim: Expose support for weakpages/blocks to userspace
From: Richard WeinbergerAllow users to define weakpages/blocks while creating a new nandsim instance. Signed-off-by: Richard Weinberger --- drivers/mtd/nand/nandsim.c | 338 include/linux/mtd/nandsim.h | 7 +- 2 files changed, 285 insertions(+), 60 deletions(-) diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index d1402df..b58d1348 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -322,9 +322,9 @@ struct nandsim { struct ns_backend_ops *bops; void *backend_data; - struct list_head weak_blocks; - struct list_head weak_pages; - struct list_head grave_pages; + struct list_head *weak_blocks; + struct list_head *weak_pages; + struct list_head *grave_pages; unsigned long *erase_block_wear; unsigned int wear_eb_count; @@ -387,6 +387,11 @@ static struct nandsim_operations { STATE_DATAOUT, STATE_READY}}, }; +struct bad_block { + struct list_head list; + unsigned int erase_block_no; +}; + struct weak_block { struct list_head list; unsigned int erase_block_no; @@ -957,16 +962,46 @@ static void free_nandsim(struct nandsim *ns) kfree(ns->buf.byte); } -static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd, +static int process_badblocks(struct nandsim_params *nsparam, struct nandsim *ns) +{ + loff_t offset; + struct bad_block *bb, *_bb; + struct mtd_info *nsmtd = ns_to_mtd(ns); + + if (!nsparam->bad_blocks) + return 0; + + list_for_each_entry_safe(bb, _bb, nsparam->bad_blocks, list) { + offset = (loff_t)bb->erase_block_no * ns->geom.secsz; + if (mtd_block_markbad(nsmtd, offset)) + pr_err("invalid badblocks: %i:\n", bb->erase_block_no); + + list_del(>list); + kfree(bb); + } + + kfree(nsparam->bad_blocks); + nsparam->bad_blocks = NULL; + + return 0; +} + +static int parse_badblocks(struct nandsim_params *nsparam, unsigned char *badblocks) { char *w; int zero_ok; unsigned int erase_block_no; - loff_t offset; + struct bad_block *bb; + + nsparam->bad_blocks = kmalloc(sizeof(struct list_head), GFP_KERNEL); + if (!nsparam->bad_blocks) + return -ENOMEM; + INIT_LIST_HEAD(nsparam->bad_blocks); if (!badblocks) return 0; + w = badblocks; do { zero_ok = (*w == '0' ? 1 : 0); @@ -975,18 +1010,21 @@ static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd, pr_err("invalid badblocks.\n"); return -EINVAL; } - offset = (loff_t)erase_block_no * ns->geom.secsz; - if (mtd_block_markbad(mtd, offset)) { - pr_err("invalid badblocks.\n"); - return -EINVAL; - } + bb = kzalloc(sizeof(*bb), GFP_KERNEL); + if (!bb) + return -ENOMEM; + + bb->erase_block_no = erase_block_no; + list_add(>list, nsparam->bad_blocks); + if (*w == ',') w += 1; } while (*w); return 0; } -static int parse_weakblocks(struct nandsim *ns, unsigned char *weakblocks) +static int parse_weakblocks(struct nandsim_params *nsparam, + unsigned char *weakblocks) { char *w; int zero_ok; @@ -994,8 +1032,14 @@ static int parse_weakblocks(struct nandsim *ns, unsigned char *weakblocks) unsigned int max_erases; struct weak_block *wb; + nsparam->weak_blocks = kmalloc(sizeof(struct list_head), GFP_KERNEL); + if (!nsparam->weak_blocks) + return -ENOMEM; + + INIT_LIST_HEAD(nsparam->weak_blocks); if (!weakblocks) return 0; + w = weakblocks; do { zero_ok = (*w == '0' ? 1 : 0); @@ -1018,7 +1062,7 @@ static int parse_weakblocks(struct nandsim *ns, unsigned char *weakblocks) } wb->erase_block_no = erase_block_no; wb->max_erases = max_erases; - list_add(>list, >weak_blocks); + list_add(>list, nsparam->weak_blocks); } while (*w); return 0; } @@ -1027,7 +1071,7 @@ static int erase_error(struct nandsim *ns, unsigned int erase_block_no) { struct weak_block *wb; - list_for_each_entry(wb, >weak_blocks, list) + list_for_each_entry(wb, ns->weak_blocks, list) if (wb->erase_block_no == erase_block_no) { if (wb->erases_done >= wb->max_erases) return 1; @@ -1037,7 +1081,8 @@ static int erase_error(struct
[PATCH v2 41/46] mtd: nandsim: Expose support for weakpages/blocks to userspace
From: Richard Weinberger Allow users to define weakpages/blocks while creating a new nandsim instance. Signed-off-by: Richard Weinberger --- drivers/mtd/nand/nandsim.c | 338 include/linux/mtd/nandsim.h | 7 +- 2 files changed, 285 insertions(+), 60 deletions(-) diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index d1402df..b58d1348 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -322,9 +322,9 @@ struct nandsim { struct ns_backend_ops *bops; void *backend_data; - struct list_head weak_blocks; - struct list_head weak_pages; - struct list_head grave_pages; + struct list_head *weak_blocks; + struct list_head *weak_pages; + struct list_head *grave_pages; unsigned long *erase_block_wear; unsigned int wear_eb_count; @@ -387,6 +387,11 @@ static struct nandsim_operations { STATE_DATAOUT, STATE_READY}}, }; +struct bad_block { + struct list_head list; + unsigned int erase_block_no; +}; + struct weak_block { struct list_head list; unsigned int erase_block_no; @@ -957,16 +962,46 @@ static void free_nandsim(struct nandsim *ns) kfree(ns->buf.byte); } -static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd, +static int process_badblocks(struct nandsim_params *nsparam, struct nandsim *ns) +{ + loff_t offset; + struct bad_block *bb, *_bb; + struct mtd_info *nsmtd = ns_to_mtd(ns); + + if (!nsparam->bad_blocks) + return 0; + + list_for_each_entry_safe(bb, _bb, nsparam->bad_blocks, list) { + offset = (loff_t)bb->erase_block_no * ns->geom.secsz; + if (mtd_block_markbad(nsmtd, offset)) + pr_err("invalid badblocks: %i:\n", bb->erase_block_no); + + list_del(>list); + kfree(bb); + } + + kfree(nsparam->bad_blocks); + nsparam->bad_blocks = NULL; + + return 0; +} + +static int parse_badblocks(struct nandsim_params *nsparam, unsigned char *badblocks) { char *w; int zero_ok; unsigned int erase_block_no; - loff_t offset; + struct bad_block *bb; + + nsparam->bad_blocks = kmalloc(sizeof(struct list_head), GFP_KERNEL); + if (!nsparam->bad_blocks) + return -ENOMEM; + INIT_LIST_HEAD(nsparam->bad_blocks); if (!badblocks) return 0; + w = badblocks; do { zero_ok = (*w == '0' ? 1 : 0); @@ -975,18 +1010,21 @@ static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd, pr_err("invalid badblocks.\n"); return -EINVAL; } - offset = (loff_t)erase_block_no * ns->geom.secsz; - if (mtd_block_markbad(mtd, offset)) { - pr_err("invalid badblocks.\n"); - return -EINVAL; - } + bb = kzalloc(sizeof(*bb), GFP_KERNEL); + if (!bb) + return -ENOMEM; + + bb->erase_block_no = erase_block_no; + list_add(>list, nsparam->bad_blocks); + if (*w == ',') w += 1; } while (*w); return 0; } -static int parse_weakblocks(struct nandsim *ns, unsigned char *weakblocks) +static int parse_weakblocks(struct nandsim_params *nsparam, + unsigned char *weakblocks) { char *w; int zero_ok; @@ -994,8 +1032,14 @@ static int parse_weakblocks(struct nandsim *ns, unsigned char *weakblocks) unsigned int max_erases; struct weak_block *wb; + nsparam->weak_blocks = kmalloc(sizeof(struct list_head), GFP_KERNEL); + if (!nsparam->weak_blocks) + return -ENOMEM; + + INIT_LIST_HEAD(nsparam->weak_blocks); if (!weakblocks) return 0; + w = weakblocks; do { zero_ok = (*w == '0' ? 1 : 0); @@ -1018,7 +1062,7 @@ static int parse_weakblocks(struct nandsim *ns, unsigned char *weakblocks) } wb->erase_block_no = erase_block_no; wb->max_erases = max_erases; - list_add(>list, >weak_blocks); + list_add(>list, nsparam->weak_blocks); } while (*w); return 0; } @@ -1027,7 +1071,7 @@ static int erase_error(struct nandsim *ns, unsigned int erase_block_no) { struct weak_block *wb; - list_for_each_entry(wb, >weak_blocks, list) + list_for_each_entry(wb, ns->weak_blocks, list) if (wb->erase_block_no == erase_block_no) { if (wb->erases_done >= wb->max_erases) return 1; @@ -1037,7 +1081,8 @@ static int erase_error(struct nandsim *ns, unsigned int