Commit 4582a30c authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.infradead.org/ubi-2.6

* git://git.infradead.org/ubi-2.6:
  UBI: add write checking
  UBI: simplify debugging return codes
  UBI: fix attaching error path
  UBI: support attaching by MTD character device name
  UBI: mark few variables as __initdata
parents 9cc0cb3c 6e9065d7
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/stringify.h> #include <linux/stringify.h>
#include <linux/namei.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/log2.h> #include <linux/log2.h>
...@@ -50,7 +51,8 @@ ...@@ -50,7 +51,8 @@
/** /**
* struct mtd_dev_param - MTD device parameter description data structure. * struct mtd_dev_param - MTD device parameter description data structure.
* @name: MTD device name or number string * @name: MTD character device node path, MTD device name, or MTD device number
* string
* @vid_hdr_offs: VID header offset * @vid_hdr_offs: VID header offset
*/ */
struct mtd_dev_param { struct mtd_dev_param {
...@@ -59,10 +61,10 @@ struct mtd_dev_param { ...@@ -59,10 +61,10 @@ struct mtd_dev_param {
}; };
/* Numbers of elements set in the @mtd_dev_param array */ /* Numbers of elements set in the @mtd_dev_param array */
static int mtd_devs; static int __initdata mtd_devs;
/* MTD devices specification parameters */ /* MTD devices specification parameters */
static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES]; static struct mtd_dev_param __initdata mtd_dev_param[UBI_MAX_DEVICES];
/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */ /* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
struct class *ubi_class; struct class *ubi_class;
...@@ -363,11 +365,13 @@ static void dev_release(struct device *dev) ...@@ -363,11 +365,13 @@ static void dev_release(struct device *dev)
/** /**
* ubi_sysfs_init - initialize sysfs for an UBI device. * ubi_sysfs_init - initialize sysfs for an UBI device.
* @ubi: UBI device description object * @ubi: UBI device description object
* @ref: set to %1 on exit in case of failure if a reference to @ubi->dev was
* taken
* *
* This function returns zero in case of success and a negative error code in * This function returns zero in case of success and a negative error code in
* case of failure. * case of failure.
*/ */
static int ubi_sysfs_init(struct ubi_device *ubi) static int ubi_sysfs_init(struct ubi_device *ubi, int *ref)
{ {
int err; int err;
...@@ -379,6 +383,7 @@ static int ubi_sysfs_init(struct ubi_device *ubi) ...@@ -379,6 +383,7 @@ static int ubi_sysfs_init(struct ubi_device *ubi)
if (err) if (err)
return err; return err;
*ref = 1;
err = device_create_file(&ubi->dev, &dev_eraseblock_size); err = device_create_file(&ubi->dev, &dev_eraseblock_size);
if (err) if (err)
return err; return err;
...@@ -434,7 +439,7 @@ static void ubi_sysfs_close(struct ubi_device *ubi) ...@@ -434,7 +439,7 @@ static void ubi_sysfs_close(struct ubi_device *ubi)
} }
/** /**
* kill_volumes - destroy all volumes. * kill_volumes - destroy all user volumes.
* @ubi: UBI device description object * @ubi: UBI device description object
*/ */
static void kill_volumes(struct ubi_device *ubi) static void kill_volumes(struct ubi_device *ubi)
...@@ -446,37 +451,30 @@ static void kill_volumes(struct ubi_device *ubi) ...@@ -446,37 +451,30 @@ static void kill_volumes(struct ubi_device *ubi)
ubi_free_volume(ubi, ubi->volumes[i]); ubi_free_volume(ubi, ubi->volumes[i]);
} }
/**
* free_user_volumes - free all user volumes.
* @ubi: UBI device description object
*
* Normally the volumes are freed at the release function of the volume device
* objects. However, on error paths the volumes have to be freed before the
* device objects have been initialized.
*/
static void free_user_volumes(struct ubi_device *ubi)
{
int i;
for (i = 0; i < ubi->vtbl_slots; i++)
if (ubi->volumes[i]) {
kfree(ubi->volumes[i]->eba_tbl);
kfree(ubi->volumes[i]);
}
}
/** /**
* uif_init - initialize user interfaces for an UBI device. * uif_init - initialize user interfaces for an UBI device.
* @ubi: UBI device description object * @ubi: UBI device description object
* @ref: set to %1 on exit in case of failure if a reference to @ubi->dev was
* taken, otherwise set to %0
*
* This function initializes various user interfaces for an UBI device. If the
* initialization fails at an early stage, this function frees all the
* resources it allocated, returns an error, and @ref is set to %0. However,
* if the initialization fails after the UBI device was registered in the
* driver core subsystem, this function takes a reference to @ubi->dev, because
* otherwise the release function ('dev_release()') would free whole @ubi
* object. The @ref argument is set to %1 in this case. The caller has to put
* this reference.
* *
* This function returns zero in case of success and a negative error code in * This function returns zero in case of success and a negative error code in
* case of failure. Note, this function destroys all volumes if it fails. * case of failure.
*/ */
static int uif_init(struct ubi_device *ubi) static int uif_init(struct ubi_device *ubi, int *ref)
{ {
int i, err; int i, err;
dev_t dev; dev_t dev;
*ref = 0;
sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);
/* /*
...@@ -504,7 +502,7 @@ static int uif_init(struct ubi_device *ubi) ...@@ -504,7 +502,7 @@ static int uif_init(struct ubi_device *ubi)
goto out_unreg; goto out_unreg;
} }
err = ubi_sysfs_init(ubi); err = ubi_sysfs_init(ubi, ref);
if (err) if (err)
goto out_sysfs; goto out_sysfs;
...@@ -522,6 +520,8 @@ static int uif_init(struct ubi_device *ubi) ...@@ -522,6 +520,8 @@ static int uif_init(struct ubi_device *ubi)
out_volumes: out_volumes:
kill_volumes(ubi); kill_volumes(ubi);
out_sysfs: out_sysfs:
if (*ref)
get_device(&ubi->dev);
ubi_sysfs_close(ubi); ubi_sysfs_close(ubi);
cdev_del(&ubi->cdev); cdev_del(&ubi->cdev);
out_unreg: out_unreg:
...@@ -875,7 +875,7 @@ static int ubi_reboot_notifier(struct notifier_block *n, unsigned long state, ...@@ -875,7 +875,7 @@ static int ubi_reboot_notifier(struct notifier_block *n, unsigned long state,
int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
{ {
struct ubi_device *ubi; struct ubi_device *ubi;
int i, err, do_free = 1; int i, err, ref = 0;
/* /*
* Check if we already have the same MTD device attached. * Check if we already have the same MTD device attached.
...@@ -975,9 +975,9 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ...@@ -975,9 +975,9 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
goto out_detach; goto out_detach;
} }
err = uif_init(ubi); err = uif_init(ubi, &ref);
if (err) if (err)
goto out_nofree; goto out_detach;
ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name); ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
if (IS_ERR(ubi->bgt_thread)) { if (IS_ERR(ubi->bgt_thread)) {
...@@ -1025,12 +1025,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ...@@ -1025,12 +1025,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
out_uif: out_uif:
uif_close(ubi); uif_close(ubi);
out_nofree:
do_free = 0;
out_detach: out_detach:
ubi_wl_close(ubi); ubi_wl_close(ubi);
if (do_free)
free_user_volumes(ubi);
free_internal_volumes(ubi); free_internal_volumes(ubi);
vfree(ubi->vtbl); vfree(ubi->vtbl);
out_free: out_free:
...@@ -1039,7 +1035,10 @@ out_free: ...@@ -1039,7 +1035,10 @@ out_free:
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
vfree(ubi->dbg_peb_buf); vfree(ubi->dbg_peb_buf);
#endif #endif
kfree(ubi); if (ref)
put_device(&ubi->dev);
else
kfree(ubi);
return err; return err;
} }
...@@ -1096,7 +1095,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) ...@@ -1096,7 +1095,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
/* /*
* Get a reference to the device in order to prevent 'dev_release()' * Get a reference to the device in order to prevent 'dev_release()'
* from freeing @ubi object. * from freeing the @ubi object.
*/ */
get_device(&ubi->dev); get_device(&ubi->dev);
...@@ -1116,13 +1115,50 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) ...@@ -1116,13 +1115,50 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
} }
/** /**
* find_mtd_device - open an MTD device by its name or number. * open_mtd_by_chdev - open an MTD device by its character device node path.
* @mtd_dev: name or number of the device * @mtd_dev: MTD character device node path
*
* This helper function opens an MTD device by its character node device path.
* Returns MTD device description object in case of success and a negative
* error code in case of failure.
*/
static struct mtd_info * __init open_mtd_by_chdev(const char *mtd_dev)
{
int err, major, minor, mode;
struct path path;
/* Probably this is an MTD character device node path */
err = kern_path(mtd_dev, LOOKUP_FOLLOW, &path);
if (err)
return ERR_PTR(err);
/* MTD device number is defined by the major / minor numbers */
major = imajor(path.dentry->d_inode);
minor = iminor(path.dentry->d_inode);
mode = path.dentry->d_inode->i_mode;
path_put(&path);
if (major != MTD_CHAR_MAJOR || !S_ISCHR(mode))
return ERR_PTR(-EINVAL);
if (minor & 1)
/*
* Just do not think the "/dev/mtdrX" devices support is need,
* so do not support them to avoid doing extra work.
*/
return ERR_PTR(-EINVAL);
return get_mtd_device(NULL, minor / 2);
}
/**
* open_mtd_device - open MTD device by name, character device path, or number.
* @mtd_dev: name, character device node path, or MTD device device number
* *
* This function tries to open and MTD device described by @mtd_dev string, * This function tries to open and MTD device described by @mtd_dev string,
* which is first treated as an ASCII number, and if it is not true, it is * which is first treated as ASCII MTD device number, and if it is not true, it
* treated as MTD device name. Returns MTD device description object in case of * is treated as MTD device name, and if that is also not true, it is treated
* success and a negative error code in case of failure. * as MTD character device node path. Returns MTD device description object in
* case of success and a negative error code in case of failure.
*/ */
static struct mtd_info * __init open_mtd_device(const char *mtd_dev) static struct mtd_info * __init open_mtd_device(const char *mtd_dev)
{ {
...@@ -1137,6 +1173,9 @@ static struct mtd_info * __init open_mtd_device(const char *mtd_dev) ...@@ -1137,6 +1173,9 @@ static struct mtd_info * __init open_mtd_device(const char *mtd_dev)
* MTD device name. * MTD device name.
*/ */
mtd = get_mtd_device_nm(mtd_dev); mtd = get_mtd_device_nm(mtd_dev);
if (IS_ERR(mtd) && PTR_ERR(mtd) == -ENODEV)
/* Probably this is an MTD character device node path */
mtd = open_mtd_by_chdev(mtd_dev);
} else } else
mtd = get_mtd_device(NULL, mtd_num); mtd = get_mtd_device(NULL, mtd_num);
...@@ -1352,13 +1391,15 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) ...@@ -1352,13 +1391,15 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000); module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000);
MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: " MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: "
"mtd=<name|num>[,<vid_hdr_offs>].\n" "mtd=<name|num|path>[,<vid_hdr_offs>].\n"
"Multiple \"mtd\" parameters may be specified.\n" "Multiple \"mtd\" parameters may be specified.\n"
"MTD devices may be specified by their number or name.\n" "MTD devices may be specified by their number, name, or "
"path to the MTD character device node.\n"
"Optional \"vid_hdr_offs\" parameter specifies UBI VID " "Optional \"vid_hdr_offs\" parameter specifies UBI VID "
"header position and data starting position to be used " "header position to be used by UBI.\n"
"by UBI.\n" "Example 1: mtd=/dev/mtd0 - attach MTD device "
"Example: mtd=content,1984 mtd=4 - attach MTD device" "/dev/mtd0.\n"
"Example 2: mtd=content,1984 mtd=4 - attach MTD device "
"with name \"content\" using VID header offset 1984, and " "with name \"content\" using VID header offset 1984, and "
"MTD device number 4 with default VID header offset."); "MTD device number 4 with default VID header offset.");
......
...@@ -96,8 +96,11 @@ void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len); ...@@ -96,8 +96,11 @@ void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len); int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len);
int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
int offset, int len);
#else #else
#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0 #define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
#define ubi_dbg_check_write(ubi, buf, pnum, offset, len) 0
#endif #endif
#ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT #ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT
...@@ -176,6 +179,7 @@ static inline int ubi_dbg_is_erase_failure(void) ...@@ -176,6 +179,7 @@ static inline int ubi_dbg_is_erase_failure(void)
#define ubi_dbg_is_write_failure() 0 #define ubi_dbg_is_write_failure() 0
#define ubi_dbg_is_erase_failure() 0 #define ubi_dbg_is_erase_failure() 0
#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0 #define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
#define ubi_dbg_check_write(ubi, buf, pnum, offset, len) 0
#endif /* !CONFIG_MTD_UBI_DEBUG */ #endif /* !CONFIG_MTD_UBI_DEBUG */
#endif /* !__UBI_DEBUG_H__ */ #endif /* !__UBI_DEBUG_H__ */
...@@ -143,7 +143,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, ...@@ -143,7 +143,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
err = paranoid_check_not_bad(ubi, pnum); err = paranoid_check_not_bad(ubi, pnum);
if (err) if (err)
return err > 0 ? -EINVAL : err; return err;
addr = (loff_t)pnum * ubi->peb_size + offset; addr = (loff_t)pnum * ubi->peb_size + offset;
retry: retry:
...@@ -236,12 +236,12 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, ...@@ -236,12 +236,12 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
err = paranoid_check_not_bad(ubi, pnum); err = paranoid_check_not_bad(ubi, pnum);
if (err) if (err)
return err > 0 ? -EINVAL : err; return err;
/* The area we are writing to has to contain all 0xFF bytes */ /* The area we are writing to has to contain all 0xFF bytes */
err = ubi_dbg_check_all_ff(ubi, pnum, offset, len); err = ubi_dbg_check_all_ff(ubi, pnum, offset, len);
if (err) if (err)
return err > 0 ? -EINVAL : err; return err;
if (offset >= ubi->leb_start) { if (offset >= ubi->leb_start) {
/* /*
...@@ -250,10 +250,10 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, ...@@ -250,10 +250,10 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
*/ */
err = paranoid_check_peb_ec_hdr(ubi, pnum); err = paranoid_check_peb_ec_hdr(ubi, pnum);
if (err) if (err)
return err > 0 ? -EINVAL : err; return err;
err = paranoid_check_peb_vid_hdr(ubi, pnum); err = paranoid_check_peb_vid_hdr(ubi, pnum);
if (err) if (err)
return err > 0 ? -EINVAL : err; return err;
} }
if (ubi_dbg_is_write_failure()) { if (ubi_dbg_is_write_failure()) {
...@@ -273,6 +273,21 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, ...@@ -273,6 +273,21 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
} else } else
ubi_assert(written == len); ubi_assert(written == len);
if (!err) {
err = ubi_dbg_check_write(ubi, buf, pnum, offset, len);
if (err)
return err;
/*
* Since we always write sequentially, the rest of the PEB has
* to contain only 0xFF bytes.
*/
offset += len;
len = ubi->peb_size - offset;
if (len)
err = ubi_dbg_check_all_ff(ubi, pnum, offset, len);
}
return err; return err;
} }
...@@ -348,7 +363,7 @@ retry: ...@@ -348,7 +363,7 @@ retry:
err = ubi_dbg_check_all_ff(ubi, pnum, 0, ubi->peb_size); err = ubi_dbg_check_all_ff(ubi, pnum, 0, ubi->peb_size);
if (err) if (err)
return err > 0 ? -EINVAL : err; return err;
if (ubi_dbg_is_erase_failure() && !err) { if (ubi_dbg_is_erase_failure() && !err) {
dbg_err("cannot erase PEB %d (emulated)", pnum); dbg_err("cannot erase PEB %d (emulated)", pnum);
...@@ -542,7 +557,7 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture) ...@@ -542,7 +557,7 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
err = paranoid_check_not_bad(ubi, pnum); err = paranoid_check_not_bad(ubi, pnum);
if (err != 0) if (err != 0)
return err > 0 ? -EINVAL : err; return err;
if (ubi->ro_mode) { if (ubi->ro_mode) {
ubi_err("read-only mode"); ubi_err("read-only mode");
...@@ -819,7 +834,7 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum, ...@@ -819,7 +834,7 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr); err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
if (err) if (err)
return -EINVAL; return err;
err = ubi_io_write(ubi, ec_hdr, pnum, 0, ubi->ec_hdr_alsize); err = ubi_io_write(ubi, ec_hdr, pnum, 0, ubi->ec_hdr_alsize);
return err; return err;
...@@ -1083,7 +1098,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, ...@@ -1083,7 +1098,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
err = paranoid_check_peb_ec_hdr(ubi, pnum); err = paranoid_check_peb_ec_hdr(ubi, pnum);
if (err) if (err)
return err > 0 ? -EINVAL : err; return err;
vid_hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC); vid_hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
vid_hdr->version = UBI_VERSION; vid_hdr->version = UBI_VERSION;
...@@ -1092,7 +1107,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, ...@@ -1092,7 +1107,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr); err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
if (err) if (err)
return -EINVAL; return err;
p = (char *)vid_hdr - ubi->vid_hdr_shift; p = (char *)vid_hdr - ubi->vid_hdr_shift;
err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset, err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset,
...@@ -1107,8 +1122,8 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, ...@@ -1107,8 +1122,8 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
* @ubi: UBI device description object * @ubi: UBI device description object
* @pnum: physical eraseblock number to check * @pnum: physical eraseblock number to check
* *
* This function returns zero if the physical eraseblock is good, a positive * This function returns zero if the physical eraseblock is good, %-EINVAL if
* number if it is bad and a negative error code if an error occurred. * it is bad and a negative error code if an error occurred.
*/ */
static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum) static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
{ {
...@@ -1120,7 +1135,7 @@ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum) ...@@ -1120,7 +1135,7 @@ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
ubi_err("paranoid check failed for PEB %d", pnum); ubi_err("paranoid check failed for PEB %d", pnum);
ubi_dbg_dump_stack(); ubi_dbg_dump_stack();
return err; return err > 0 ? -EINVAL : err;
} }
/** /**
...@@ -1130,7 +1145,7 @@ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum) ...@@ -1130,7 +1145,7 @@ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
* @ec_hdr: the erase counter header to check * @ec_hdr: the erase counter header to check
* *
* This function returns zero if the erase counter header contains valid * This function returns zero if the erase counter header contains valid
* values, and %1 if not. * values, and %-EINVAL if not.
*/ */
static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum, static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
const struct ubi_ec_hdr *ec_hdr) const struct ubi_ec_hdr *ec_hdr)
...@@ -1156,7 +1171,7 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum, ...@@ -1156,7 +1171,7 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
fail: fail:
ubi_dbg_dump_ec_hdr(ec_hdr); ubi_dbg_dump_ec_hdr(ec_hdr);
ubi_dbg_dump_stack(); ubi_dbg_dump_stack();
return 1; return -EINVAL;
} }
/** /**
...@@ -1164,8 +1179,8 @@ fail: ...@@ -1164,8 +1179,8 @@ fail:
* @ubi: UBI device description object * @ubi: UBI device description object
* @pnum: the physical eraseblock number to check * @pnum: the physical eraseblock number to check
* *
* This function returns zero if the erase counter header is all right, %1 if * This function returns zero if the erase counter header is all right and and
* not, and a negative error code if an error occurred. * a negative error code if not or if an error occurred.
*/ */
static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum) static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
{ {
...@@ -1188,7 +1203,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum) ...@@ -1188,7 +1203,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
ubi_err("paranoid check failed for PEB %d", pnum); ubi_err("paranoid check failed for PEB %d", pnum);
ubi_dbg_dump_ec_hdr(ec_hdr); ubi_dbg_dump_ec_hdr(ec_hdr);
ubi_dbg_dump_stack(); ubi_dbg_dump_stack();
err = 1; err = -EINVAL;
goto exit; goto exit;
} }
...@@ -1206,7 +1221,7 @@ exit: ...@@ -1206,7 +1221,7 @@ exit:
* @vid_hdr: the volume identifier header to check * @vid_hdr: the volume identifier header to check
* *
* This function returns zero if the volume identifier header is all right, and * This function returns zero if the volume identifier header is all right, and
* %1 if not. * %-EINVAL if not.
*/ */
static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum, static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
const struct ubi_vid_hdr *vid_hdr) const struct ubi_vid_hdr *vid_hdr)
...@@ -1233,7 +1248,7 @@ fail: ...@@ -1233,7 +1248,7 @@ fail:
ubi_err("paranoid check failed for PEB %d", pnum); ubi_err("paranoid check failed for PEB %d", pnum);
ubi_dbg_dump_vid_hdr(vid_hdr); ubi_dbg_dump_vid_hdr(vid_hdr);
ubi_dbg_dump_stack(); ubi_dbg_dump_stack();
return 1; return -EINVAL;
} }
...@@ -1243,7 +1258,7 @@ fail: ...@@ -1243,7 +1258,7 @@ fail:
* @pnum: the physical eraseblock number to check * @pnum: the physical eraseblock number to check
* *
* This function returns zero if the volume identifier header is all right, * This function returns zero if the volume identifier header is all right,
* %1 if not, and a negative error code if an error occurred. * and a negative error code if not or if an error occurred.
*/ */
static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
{ {
...@@ -1270,7 +1285,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) ...@@ -1270,7 +1285,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
ubi_err("paranoid check failed for PEB %d", pnum); ubi_err("paranoid check failed for PEB %d", pnum);
ubi_dbg_dump_vid_hdr(vid_hdr); ubi_dbg_dump_vid_hdr(vid_hdr);
ubi_dbg_dump_stack(); ubi_dbg_dump_stack();
err = 1; err = -EINVAL;
goto exit; goto exit;
} }
...@@ -1281,6 +1296,61 @@ exit: ...@@ -1281,6 +1296,61 @@ exit:
return err; return err;
} }
/**
* ubi_dbg_check_write - make sure write succeeded.
* @ubi: UBI device description object
* @buf: buffer with data which were written
* @pnum: physical eraseblock number the data were written to
* @offset: offset within the physical eraseblock the data were written to
* @len: how many bytes were written
*
* This functions reads data which were recently written and compares it with
* the original data buffer - the data have to match. Returns zero if the data
* match and a negative error code if not or in case of failure.
*/
int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
int offset, int len)
{
int err, i;
mutex_lock(&ubi->dbg_buf_mutex);
err = ubi_io_read(ubi, ubi->dbg_peb_buf, pnum, offset, len);
if (err)
goto out_unlock;
for (i = 0; i < len; i++) {
uint8_t c = ((uint8_t *)buf)[i];
uint8_t c1 = ((uint8_t *)ubi->dbg_peb_buf)[i];
int dump_len;
if (c == c1)
continue;
ubi_err("paranoid check failed for PEB %d:%d, len %d",
pnum, offset, len);
ubi_msg("data differ at position %d", i);
dump_len = max_t(int, 128, len - i);
ubi_msg("hex dump of the original buffer from %d to %d",
i, i + dump_len);
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
buf + i, dump_len, 1);
ubi_msg("hex dump of the read buffer from %d to %d",
i, i + dump_len);
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
ubi->dbg_peb_buf + i, dump_len, 1);
ubi_dbg_dump_stack();
err = -EINVAL;
goto out_unlock;
}
mutex_unlock(&ubi->dbg_buf_mutex);
return 0;
out_unlock:
mutex_unlock(&ubi->dbg_buf_mutex);
return err;
}
/** /**
* ubi_dbg_check_all_ff - check that a region of flash is empty. * ubi_dbg_check_all_ff - check that a region of flash is empty.
* @ubi: UBI device description object * @ubi: UBI device description object
...@@ -1289,8 +1359,8 @@ exit: ...@@ -1289,8 +1359,8 @@ exit:
* @len: the length of the region to check * @len: the length of the region to check
* *
* This function returns zero if only 0xFF bytes are present at offset * This function returns zero if only 0xFF bytes are present at offset
* @offset of the physical eraseblock @pnum, %1 if not, and a negative error * @offset of the physical eraseblock @pnum, and a negative error code if not
* code if an error occurred. * or if an error occurred.
*/ */
int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
{ {
...@@ -1321,7 +1391,7 @@ fail: ...@@ -1321,7 +1391,7 @@ fail:
ubi_msg("hex dump of the %d-%d region", offset, offset + len); ubi_msg("hex dump of the %d-%d region", offset, offset + len);
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
ubi->dbg_peb_buf, len, 1); ubi->dbg_peb_buf, len, 1);
err = 1; err = -EINVAL;
error: error:
ubi_dbg_dump_stack(); ubi_dbg_dump_stack();
mutex_unlock(&ubi->dbg_buf_mutex); mutex_unlock(&ubi->dbg_buf_mutex);
......
...@@ -974,11 +974,8 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) ...@@ -974,11 +974,8 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
seb->ec = si->mean_ec; seb->ec = si->mean_ec;
err = paranoid_check_si(ubi, si); err = paranoid_check_si(ubi, si);
if (err) { if (err)
if (err > 0)
err = -EINVAL;
goto out_vidh; goto out_vidh;
}
ubi_free_vid_hdr(ubi, vidh); ubi_free_vid_hdr(ubi, vidh);
kfree(ech); kfree(ech);
...@@ -1086,8 +1083,8 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si) ...@@ -1086,8 +1083,8 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
* @ubi: UBI device description object * @ubi: UBI device description object
* @si: scanning information * @si: scanning information
* *
* This function returns zero if the scanning information is all right, %1 if * This function returns zero if the scanning information is all right, and a
* not and a negative error code if an error occurred. * negative error code if not or if an error occurred.
*/ */
static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si) static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
{ {
...@@ -1346,7 +1343,7 @@ bad_vid_hdr: ...@@ -1346,7 +1343,7 @@ bad_vid_hdr:
out: out:
ubi_dbg_dump_stack(); ubi_dbg_dump_stack();
return 1; return -EINVAL;
} }
#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */ #endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
...@@ -464,7 +464,7 @@ retry: ...@@ -464,7 +464,7 @@ retry:
ubi->peb_size - ubi->vid_hdr_aloffset); ubi->peb_size - ubi->vid_hdr_aloffset);
if (err) { if (err) {
ubi_err("new PEB %d does not contain all 0xFF bytes", e->pnum); ubi_err("new PEB %d does not contain all 0xFF bytes", e->pnum);
return err > 0 ? -EINVAL : err; return err;
} }
return e->pnum; return e->pnum;
...@@ -513,7 +513,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, ...@@ -513,7 +513,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
dbg_wl("erase PEB %d, old EC %llu", e->pnum, ec); dbg_wl("erase PEB %d, old EC %llu", e->pnum, ec);
err = paranoid_check_ec(ubi, e->pnum, e->ec); err = paranoid_check_ec(ubi, e->pnum, e->ec);
if (err > 0) if (err)
return -EINVAL; return -EINVAL;
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS); ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
...@@ -1572,8 +1572,7 @@ void ubi_wl_close(struct ubi_device *ubi) ...@@ -1572,8 +1572,7 @@ void ubi_wl_close(struct ubi_device *ubi)
* @ec: the erase counter to check * @ec: the erase counter to check
* *
* This function returns zero if the erase counter of physical eraseblock @pnum * This function returns zero if the erase counter of physical eraseblock @pnum
* is equivalent to @ec, %1 if not, and a negative error code if an error * is equivalent to @ec, and a negative error code if not or if an error occurred.
* occurred.
*/ */
static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec) static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
{ {
...@@ -1611,8 +1610,8 @@ out_free: ...@@ -1611,8 +1610,8 @@ out_free:
* @e: the wear-leveling entry to check * @e: the wear-leveling entry to check
* @root: the root of the tree * @root: the root of the tree
* *
* This function returns zero if @e is in the @root RB-tree and %1 if it is * This function returns zero if @e is in the @root RB-tree and %-EINVAL if it
* not. * is not.
*/ */
static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e, static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
struct rb_root *root) struct rb_root *root)
...@@ -1623,7 +1622,7 @@ static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e, ...@@ -1623,7 +1622,7 @@ static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
ubi_err("paranoid check failed for PEB %d, EC %d, RB-tree %p ", ubi_err("paranoid check failed for PEB %d, EC %d, RB-tree %p ",
e->pnum, e->ec, root); e->pnum, e->ec, root);
ubi_dbg_dump_stack(); ubi_dbg_dump_stack();
return 1; return -EINVAL;
} }
/** /**
...@@ -1632,7 +1631,7 @@ static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e, ...@@ -1632,7 +1631,7 @@ static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
* @ubi: UBI device description object * @ubi: UBI device description object
* @e: the wear-leveling entry to check * @e: the wear-leveling entry to check
* *
* This function returns zero if @e is in @ubi->pq and %1 if it is not. * This function returns zero if @e is in @ubi->pq and %-EINVAL if it is not.
*/ */
static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e) static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e)
{ {
...@@ -1647,6 +1646,6 @@ static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e) ...@@ -1647,6 +1646,6 @@ static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e)
ubi_err("paranoid check failed for PEB %d, EC %d, Protect queue", ubi_err("paranoid check failed for PEB %d, EC %d, Protect queue",
e->pnum, e->ec); e->pnum, e->ec);
ubi_dbg_dump_stack(); ubi_dbg_dump_stack();
return 1; return -EINVAL;
} }
#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */ #endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment