Commit 996abf05 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'linux-next' of git://git.infradead.org/~dedekind/ubi-2.6

* 'linux-next' of git://git.infradead.org/~dedekind/ubi-2.6: (22 commits)
  UBI: always start the background thread
  UBI: fix gcc warning
  UBI: remove pre-sqnum images support
  UBI: fix kernel-doc errors and warnings
  UBI: fix checkpatch.pl errors and warnings
  UBI: bugfix - do not torture PEB needlessly
  UBI: rework scrubbing messages
  UBI: implement multiple volumes rename
  UBI: fix and re-work debugging stuff
  UBI: amend commentaries
  UBI: fix error message
  UBI: improve mkvol request validation
  UBI: add ubi_sync() interface
  UBI: fix 64-bit calculations
  UBI: fix LEB locking
  UBI: fix memory leak on error path
  UBI: do not forget to free internal volumes
  UBI: fix memory leak
  UBI: avoid unnecessary division operations
  UBI: fix buffer padding
  ...
parents 93082f0b d37e6bf6
...@@ -51,14 +51,13 @@ ...@@ -51,14 +51,13 @@
* @name: MTD device name or number string * @name: MTD device name or number string
* @vid_hdr_offs: VID header offset * @vid_hdr_offs: VID header offset
*/ */
struct mtd_dev_param struct mtd_dev_param {
{
char name[MTD_PARAM_LEN_MAX]; char name[MTD_PARAM_LEN_MAX];
int vid_hdr_offs; int vid_hdr_offs;
}; };
/* Numbers of elements set in the @mtd_dev_param array */ /* Numbers of elements set in the @mtd_dev_param array */
static int mtd_devs = 0; static int 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 mtd_dev_param[UBI_MAX_DEVICES];
...@@ -160,8 +159,7 @@ void ubi_put_device(struct ubi_device *ubi) ...@@ -160,8 +159,7 @@ void ubi_put_device(struct ubi_device *ubi)
} }
/** /**
* ubi_get_by_major - get UBI device description object by character device * ubi_get_by_major - get UBI device by character device major number.
* major number.
* @major: major number * @major: major number
* *
* This function is similar to 'ubi_get_device()', but it searches the device * This function is similar to 'ubi_get_device()', but it searches the device
...@@ -354,16 +352,35 @@ static void kill_volumes(struct ubi_device *ubi) ...@@ -354,16 +352,35 @@ 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
* *
* 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. Note, this function destroys all volumes if it failes.
*/ */
static int uif_init(struct ubi_device *ubi) static int uif_init(struct ubi_device *ubi)
{ {
int i, err; int i, err, do_free = 0;
dev_t dev; dev_t dev;
sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);
...@@ -384,7 +401,7 @@ static int uif_init(struct ubi_device *ubi) ...@@ -384,7 +401,7 @@ static int uif_init(struct ubi_device *ubi)
ubi_assert(MINOR(dev) == 0); ubi_assert(MINOR(dev) == 0);
cdev_init(&ubi->cdev, &ubi_cdev_operations); cdev_init(&ubi->cdev, &ubi_cdev_operations);
dbg_msg("%s major is %u", ubi->ubi_name, MAJOR(dev)); dbg_gen("%s major is %u", ubi->ubi_name, MAJOR(dev));
ubi->cdev.owner = THIS_MODULE; ubi->cdev.owner = THIS_MODULE;
err = cdev_add(&ubi->cdev, dev, 1); err = cdev_add(&ubi->cdev, dev, 1);
...@@ -410,10 +427,13 @@ static int uif_init(struct ubi_device *ubi) ...@@ -410,10 +427,13 @@ static int uif_init(struct ubi_device *ubi)
out_volumes: out_volumes:
kill_volumes(ubi); kill_volumes(ubi);
do_free = 0;
out_sysfs: out_sysfs:
ubi_sysfs_close(ubi); ubi_sysfs_close(ubi);
cdev_del(&ubi->cdev); cdev_del(&ubi->cdev);
out_unreg: out_unreg:
if (do_free)
free_user_volumes(ubi);
unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err); ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err);
return err; return err;
...@@ -422,6 +442,10 @@ static int uif_init(struct ubi_device *ubi) ...@@ -422,6 +442,10 @@ static int uif_init(struct ubi_device *ubi)
/** /**
* uif_close - close user interfaces for an UBI device. * uif_close - close user interfaces for an UBI device.
* @ubi: UBI device description object * @ubi: UBI device description object
*
* Note, since this function un-registers UBI volume device objects (@vol->dev),
* the memory allocated voe the volumes is freed as well (in the release
* function).
*/ */
static void uif_close(struct ubi_device *ubi) static void uif_close(struct ubi_device *ubi)
{ {
...@@ -431,6 +455,21 @@ static void uif_close(struct ubi_device *ubi) ...@@ -431,6 +455,21 @@ static void uif_close(struct ubi_device *ubi)
unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
} }
/**
* free_internal_volumes - free internal volumes.
* @ubi: UBI device description object
*/
static void free_internal_volumes(struct ubi_device *ubi)
{
int i;
for (i = ubi->vtbl_slots;
i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
kfree(ubi->volumes[i]->eba_tbl);
kfree(ubi->volumes[i]);
}
}
/** /**
* attach_by_scanning - attach an MTD device using scanning method. * attach_by_scanning - attach an MTD device using scanning method.
* @ubi: UBI device descriptor * @ubi: UBI device descriptor
...@@ -475,6 +514,7 @@ static int attach_by_scanning(struct ubi_device *ubi) ...@@ -475,6 +514,7 @@ static int attach_by_scanning(struct ubi_device *ubi)
out_wl: out_wl:
ubi_wl_close(ubi); ubi_wl_close(ubi);
out_vtbl: out_vtbl:
free_internal_volumes(ubi);
vfree(ubi->vtbl); vfree(ubi->vtbl);
out_si: out_si:
ubi_scan_destroy_si(si); ubi_scan_destroy_si(si);
...@@ -482,7 +522,7 @@ static int attach_by_scanning(struct ubi_device *ubi) ...@@ -482,7 +522,7 @@ static int attach_by_scanning(struct ubi_device *ubi)
} }
/** /**
* io_init - initialize I/O unit for a given UBI device. * io_init - initialize I/O sub-system for a given UBI device.
* @ubi: UBI device description object * @ubi: UBI device description object
* *
* If @ubi->vid_hdr_offset or @ubi->leb_start is zero, default offsets are * If @ubi->vid_hdr_offset or @ubi->leb_start is zero, default offsets are
...@@ -530,7 +570,11 @@ static int io_init(struct ubi_device *ubi) ...@@ -530,7 +570,11 @@ static int io_init(struct ubi_device *ubi)
ubi->min_io_size = ubi->mtd->writesize; ubi->min_io_size = ubi->mtd->writesize;
ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
/* Make sure minimal I/O unit is power of 2 */ /*
* Make sure minimal I/O unit is power of 2. Note, there is no
* fundamental reason for this assumption. It is just an optimization
* which allows us to avoid costly division operations.
*/
if (!is_power_of_2(ubi->min_io_size)) { if (!is_power_of_2(ubi->min_io_size)) {
ubi_err("min. I/O unit (%d) is not power of 2", ubi_err("min. I/O unit (%d) is not power of 2",
ubi->min_io_size); ubi->min_io_size);
...@@ -581,7 +625,7 @@ static int io_init(struct ubi_device *ubi) ...@@ -581,7 +625,7 @@ static int io_init(struct ubi_device *ubi)
if (ubi->vid_hdr_offset < UBI_EC_HDR_SIZE || if (ubi->vid_hdr_offset < UBI_EC_HDR_SIZE ||
ubi->leb_start < ubi->vid_hdr_offset + UBI_VID_HDR_SIZE || ubi->leb_start < ubi->vid_hdr_offset + UBI_VID_HDR_SIZE ||
ubi->leb_start > ubi->peb_size - UBI_VID_HDR_SIZE || ubi->leb_start > ubi->peb_size - UBI_VID_HDR_SIZE ||
ubi->leb_start % ubi->min_io_size) { ubi->leb_start & (ubi->min_io_size - 1)) {
ubi_err("bad VID header (%d) or data offsets (%d)", ubi_err("bad VID header (%d) or data offsets (%d)",
ubi->vid_hdr_offset, ubi->leb_start); ubi->vid_hdr_offset, ubi->leb_start);
return -EINVAL; return -EINVAL;
...@@ -646,7 +690,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id) ...@@ -646,7 +690,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id)
/* /*
* Clear the auto-resize flag in the volume in-memory copy of the * Clear the auto-resize flag in the volume in-memory copy of the
* volume table, and 'ubi_resize_volume()' will propogate this change * volume table, and 'ubi_resize_volume()' will propagate this change
* to the flash. * to the flash.
*/ */
ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG; ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG;
...@@ -655,7 +699,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id) ...@@ -655,7 +699,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id)
struct ubi_vtbl_record vtbl_rec; struct ubi_vtbl_record vtbl_rec;
/* /*
* No avalilable PEBs to re-size the volume, clear the flag on * No available PEBs to re-size the volume, clear the flag on
* flash and exit. * flash and exit.
*/ */
memcpy(&vtbl_rec, &ubi->vtbl[vol_id], memcpy(&vtbl_rec, &ubi->vtbl[vol_id],
...@@ -682,13 +726,13 @@ static int autoresize(struct ubi_device *ubi, int vol_id) ...@@ -682,13 +726,13 @@ static int autoresize(struct ubi_device *ubi, int vol_id)
/** /**
* ubi_attach_mtd_dev - attach an MTD device. * ubi_attach_mtd_dev - attach an MTD device.
* @mtd_dev: MTD device description object * @mtd: MTD device description object
* @ubi_num: number to assign to the new UBI device * @ubi_num: number to assign to the new UBI device
* @vid_hdr_offset: VID header offset * @vid_hdr_offset: VID header offset
* *
* This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number
* to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in
* which case this function finds a vacant device nubert and assings it * which case this function finds a vacant device number and assigns it
* automatically. Returns the new UBI device number in case of success and a * automatically. Returns the new UBI device number in case of success and a
* negative error code in case of failure. * negative error code in case of failure.
* *
...@@ -698,7 +742,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id) ...@@ -698,7 +742,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id)
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; int i, err, do_free = 1;
/* /*
* Check if we already have the same MTD device attached. * Check if we already have the same MTD device attached.
...@@ -735,7 +779,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ...@@ -735,7 +779,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
if (!ubi_devices[ubi_num]) if (!ubi_devices[ubi_num])
break; break;
if (ubi_num == UBI_MAX_DEVICES) { if (ubi_num == UBI_MAX_DEVICES) {
dbg_err("only %d UBI devices may be created", UBI_MAX_DEVICES); dbg_err("only %d UBI devices may be created",
UBI_MAX_DEVICES);
return -ENFILE; return -ENFILE;
} }
} else { } else {
...@@ -760,6 +805,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ...@@ -760,6 +805,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
mutex_init(&ubi->buf_mutex); mutex_init(&ubi->buf_mutex);
mutex_init(&ubi->ckvol_mutex); mutex_init(&ubi->ckvol_mutex);
mutex_init(&ubi->mult_mutex);
mutex_init(&ubi->volumes_mutex); mutex_init(&ubi->volumes_mutex);
spin_lock_init(&ubi->volumes_lock); spin_lock_init(&ubi->volumes_lock);
...@@ -798,7 +844,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ...@@ -798,7 +844,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
err = uif_init(ubi); err = uif_init(ubi);
if (err) if (err)
goto out_detach; goto out_nofree;
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)) {
...@@ -824,20 +870,22 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ...@@ -824,20 +870,22 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
ubi->beb_rsvd_pebs); ubi->beb_rsvd_pebs);
ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec); ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec);
/* Enable the background thread */ if (!DBG_DISABLE_BGT)
if (!DBG_DISABLE_BGT) {
ubi->thread_enabled = 1; ubi->thread_enabled = 1;
wake_up_process(ubi->bgt_thread); wake_up_process(ubi->bgt_thread);
}
ubi_devices[ubi_num] = ubi; ubi_devices[ubi_num] = ubi;
return ubi_num; return ubi_num;
out_uif: out_uif:
uif_close(ubi); uif_close(ubi);
out_nofree:
do_free = 0;
out_detach: out_detach:
ubi_eba_close(ubi);
ubi_wl_close(ubi); ubi_wl_close(ubi);
if (do_free)
free_user_volumes(ubi);
free_internal_volumes(ubi);
vfree(ubi->vtbl); vfree(ubi->vtbl);
out_free: out_free:
vfree(ubi->peb_buf1); vfree(ubi->peb_buf1);
...@@ -899,8 +947,8 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) ...@@ -899,8 +947,8 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
kthread_stop(ubi->bgt_thread); kthread_stop(ubi->bgt_thread);
uif_close(ubi); uif_close(ubi);
ubi_eba_close(ubi);
ubi_wl_close(ubi); ubi_wl_close(ubi);
free_internal_volumes(ubi);
vfree(ubi->vtbl); vfree(ubi->vtbl);
put_mtd_device(ubi->mtd); put_mtd_device(ubi->mtd);
vfree(ubi->peb_buf1); vfree(ubi->peb_buf1);
...@@ -1044,8 +1092,7 @@ static void __exit ubi_exit(void) ...@@ -1044,8 +1092,7 @@ static void __exit ubi_exit(void)
module_exit(ubi_exit); module_exit(ubi_exit);
/** /**
* bytes_str_to_int - convert a string representing number of bytes to an * bytes_str_to_int - convert a number of bytes string into an integer.
* integer.
* @str: the string to convert * @str: the string to convert
* *
* This function returns positive resulting integer in case of success and a * This function returns positive resulting integer in case of success and a
......
This diff is collapsed.
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
* changes. * changes.
*/ */
#ifdef CONFIG_MTD_UBI_DEBUG_MSG #ifdef CONFIG_MTD_UBI_DEBUG
#include "ubi.h" #include "ubi.h"
...@@ -34,14 +34,19 @@ ...@@ -34,14 +34,19 @@
*/ */
void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
{ {
dbg_msg("erase counter header dump:"); printk(KERN_DEBUG "Erase counter header dump:\n");
dbg_msg("magic %#08x", be32_to_cpu(ec_hdr->magic)); printk(KERN_DEBUG "\tmagic %#08x\n",
dbg_msg("version %d", (int)ec_hdr->version); be32_to_cpu(ec_hdr->magic));
dbg_msg("ec %llu", (long long)be64_to_cpu(ec_hdr->ec)); printk(KERN_DEBUG "\tversion %d\n", (int)ec_hdr->version);
dbg_msg("vid_hdr_offset %d", be32_to_cpu(ec_hdr->vid_hdr_offset)); printk(KERN_DEBUG "\tec %llu\n",
dbg_msg("data_offset %d", be32_to_cpu(ec_hdr->data_offset)); (long long)be64_to_cpu(ec_hdr->ec));
dbg_msg("hdr_crc %#08x", be32_to_cpu(ec_hdr->hdr_crc)); printk(KERN_DEBUG "\tvid_hdr_offset %d\n",
dbg_msg("erase counter header hexdump:"); be32_to_cpu(ec_hdr->vid_hdr_offset));
printk(KERN_DEBUG "\tdata_offset %d\n",
be32_to_cpu(ec_hdr->data_offset));
printk(KERN_DEBUG "\thdr_crc %#08x\n",
be32_to_cpu(ec_hdr->hdr_crc));
printk(KERN_DEBUG "erase counter header hexdump:\n");
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
ec_hdr, UBI_EC_HDR_SIZE, 1); ec_hdr, UBI_EC_HDR_SIZE, 1);
} }
...@@ -52,22 +57,23 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) ...@@ -52,22 +57,23 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
*/ */
void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr) void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
{ {
dbg_msg("volume identifier header dump:"); printk(KERN_DEBUG "Volume identifier header dump:\n");
dbg_msg("magic %08x", be32_to_cpu(vid_hdr->magic)); printk(KERN_DEBUG "\tmagic %08x\n", be32_to_cpu(vid_hdr->magic));
dbg_msg("version %d", (int)vid_hdr->version); printk(KERN_DEBUG "\tversion %d\n", (int)vid_hdr->version);
dbg_msg("vol_type %d", (int)vid_hdr->vol_type); printk(KERN_DEBUG "\tvol_type %d\n", (int)vid_hdr->vol_type);
dbg_msg("copy_flag %d", (int)vid_hdr->copy_flag); printk(KERN_DEBUG "\tcopy_flag %d\n", (int)vid_hdr->copy_flag);
dbg_msg("compat %d", (int)vid_hdr->compat); printk(KERN_DEBUG "\tcompat %d\n", (int)vid_hdr->compat);
dbg_msg("vol_id %d", be32_to_cpu(vid_hdr->vol_id)); printk(KERN_DEBUG "\tvol_id %d\n", be32_to_cpu(vid_hdr->vol_id));
dbg_msg("lnum %d", be32_to_cpu(vid_hdr->lnum)); printk(KERN_DEBUG "\tlnum %d\n", be32_to_cpu(vid_hdr->lnum));
dbg_msg("leb_ver %u", be32_to_cpu(vid_hdr->leb_ver)); printk(KERN_DEBUG "\tdata_size %d\n", be32_to_cpu(vid_hdr->data_size));
dbg_msg("data_size %d", be32_to_cpu(vid_hdr->data_size)); printk(KERN_DEBUG "\tused_ebs %d\n", be32_to_cpu(vid_hdr->used_ebs));
dbg_msg("used_ebs %d", be32_to_cpu(vid_hdr->used_ebs)); printk(KERN_DEBUG "\tdata_pad %d\n", be32_to_cpu(vid_hdr->data_pad));
dbg_msg("data_pad %d", be32_to_cpu(vid_hdr->data_pad)); printk(KERN_DEBUG "\tsqnum %llu\n",
dbg_msg("sqnum %llu",
(unsigned long long)be64_to_cpu(vid_hdr->sqnum)); (unsigned long long)be64_to_cpu(vid_hdr->sqnum));
dbg_msg("hdr_crc %08x", be32_to_cpu(vid_hdr->hdr_crc)); printk(KERN_DEBUG "\thdr_crc %08x\n", be32_to_cpu(vid_hdr->hdr_crc));
dbg_msg("volume identifier header hexdump:"); printk(KERN_DEBUG "Volume identifier header hexdump:\n");
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
vid_hdr, UBI_VID_HDR_SIZE, 1);
} }
/** /**
...@@ -76,27 +82,27 @@ void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr) ...@@ -76,27 +82,27 @@ void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
*/ */
void ubi_dbg_dump_vol_info(const struct ubi_volume *vol) void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
{ {
dbg_msg("volume information dump:"); printk(KERN_DEBUG "Volume information dump:\n");
dbg_msg("vol_id %d", vol->vol_id); printk(KERN_DEBUG "\tvol_id %d\n", vol->vol_id);
dbg_msg("reserved_pebs %d", vol->reserved_pebs); printk(KERN_DEBUG "\treserved_pebs %d\n", vol->reserved_pebs);
dbg_msg("alignment %d", vol->alignment); printk(KERN_DEBUG "\talignment %d\n", vol->alignment);
dbg_msg("data_pad %d", vol->data_pad); printk(KERN_DEBUG "\tdata_pad %d\n", vol->data_pad);
dbg_msg("vol_type %d", vol->vol_type); printk(KERN_DEBUG "\tvol_type %d\n", vol->vol_type);
dbg_msg("name_len %d", vol->name_len); printk(KERN_DEBUG "\tname_len %d\n", vol->name_len);
dbg_msg("usable_leb_size %d", vol->usable_leb_size); printk(KERN_DEBUG "\tusable_leb_size %d\n", vol->usable_leb_size);
dbg_msg("used_ebs %d", vol->used_ebs); printk(KERN_DEBUG "\tused_ebs %d\n", vol->used_ebs);
dbg_msg("used_bytes %lld", vol->used_bytes); printk(KERN_DEBUG "\tused_bytes %lld\n", vol->used_bytes);
dbg_msg("last_eb_bytes %d", vol->last_eb_bytes); printk(KERN_DEBUG "\tlast_eb_bytes %d\n", vol->last_eb_bytes);
dbg_msg("corrupted %d", vol->corrupted); printk(KERN_DEBUG "\tcorrupted %d\n", vol->corrupted);
dbg_msg("upd_marker %d", vol->upd_marker); printk(KERN_DEBUG "\tupd_marker %d\n", vol->upd_marker);
if (vol->name_len <= UBI_VOL_NAME_MAX && if (vol->name_len <= UBI_VOL_NAME_MAX &&
strnlen(vol->name, vol->name_len + 1) == vol->name_len) { strnlen(vol->name, vol->name_len + 1) == vol->name_len) {
dbg_msg("name %s", vol->name); printk(KERN_DEBUG "\tname %s\n", vol->name);
} else { } else {
dbg_msg("the 1st 5 characters of the name: %c%c%c%c%c", printk(KERN_DEBUG "\t1st 5 characters of name: %c%c%c%c%c\n",
vol->name[0], vol->name[1], vol->name[2], vol->name[0], vol->name[1], vol->name[2],
vol->name[3], vol->name[4]); vol->name[3], vol->name[4]);
} }
} }
...@@ -109,28 +115,29 @@ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx) ...@@ -109,28 +115,29 @@ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
{ {
int name_len = be16_to_cpu(r->name_len); int name_len = be16_to_cpu(r->name_len);
dbg_msg("volume table record %d dump:", idx); printk(KERN_DEBUG "Volume table record %d dump:\n", idx);
dbg_msg("reserved_pebs %d", be32_to_cpu(r->reserved_pebs)); printk(KERN_DEBUG "\treserved_pebs %d\n",
dbg_msg("alignment %d", be32_to_cpu(r->alignment)); be32_to_cpu(r->reserved_pebs));
dbg_msg("data_pad %d", be32_to_cpu(r->data_pad)); printk(KERN_DEBUG "\talignment %d\n", be32_to_cpu(r->alignment));
dbg_msg("vol_type %d", (int)r->vol_type); printk(KERN_DEBUG "\tdata_pad %d\n", be32_to_cpu(r->data_pad));
dbg_msg("upd_marker %d", (int)r->upd_marker); printk(KERN_DEBUG "\tvol_type %d\n", (int)r->vol_type);
dbg_msg("name_len %d", name_len); printk(KERN_DEBUG "\tupd_marker %d\n", (int)r->upd_marker);
printk(KERN_DEBUG "\tname_len %d\n", name_len);
if (r->name[0] == '\0') { if (r->name[0] == '\0') {
dbg_msg("name NULL"); printk(KERN_DEBUG "\tname NULL\n");
return; return;
} }
if (name_len <= UBI_VOL_NAME_MAX && if (name_len <= UBI_VOL_NAME_MAX &&
strnlen(&r->name[0], name_len + 1) == name_len) { strnlen(&r->name[0], name_len + 1) == name_len) {
dbg_msg("name %s", &r->name[0]); printk(KERN_DEBUG "\tname %s\n", &r->name[0]);
} else { } else {
dbg_msg("1st 5 characters of the name: %c%c%c%c%c", printk(KERN_DEBUG "\t1st 5 characters of name: %c%c%c%c%c\n",
r->name[0], r->name[1], r->name[2], r->name[3], r->name[0], r->name[1], r->name[2], r->name[3],
r->name[4]); r->name[4]);
} }
dbg_msg("crc %#08x", be32_to_cpu(r->crc)); printk(KERN_DEBUG "\tcrc %#08x\n", be32_to_cpu(r->crc));
} }
/** /**
...@@ -139,15 +146,15 @@ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx) ...@@ -139,15 +146,15 @@ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
*/ */
void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv) void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv)
{ {
dbg_msg("volume scanning information dump:"); printk(KERN_DEBUG "Volume scanning information dump:\n");
dbg_msg("vol_id %d", sv->vol_id); printk(KERN_DEBUG "\tvol_id %d\n", sv->vol_id);
dbg_msg("highest_lnum %d", sv->highest_lnum); printk(KERN_DEBUG "\thighest_lnum %d\n", sv->highest_lnum);
dbg_msg("leb_count %d", sv->leb_count); printk(KERN_DEBUG "\tleb_count %d\n", sv->leb_count);
dbg_msg("compat %d", sv->compat); printk(KERN_DEBUG "\tcompat %d\n", sv->compat);
dbg_msg("vol_type %d", sv->vol_type); printk(KERN_DEBUG "\tvol_type %d\n", sv->vol_type);
dbg_msg("used_ebs %d", sv->used_ebs); printk(KERN_DEBUG "\tused_ebs %d\n", sv->used_ebs);
dbg_msg("last_data_size %d", sv->last_data_size); printk(KERN_DEBUG "\tlast_data_size %d\n", sv->last_data_size);
dbg_msg("data_pad %d", sv->data_pad); printk(KERN_DEBUG "\tdata_pad %d\n", sv->data_pad);
} }
/** /**
...@@ -157,14 +164,13 @@ void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv) ...@@ -157,14 +164,13 @@ void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv)
*/ */
void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type) void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type)
{ {
dbg_msg("eraseblock scanning information dump:"); printk(KERN_DEBUG "eraseblock scanning information dump:\n");
dbg_msg("ec %d", seb->ec); printk(KERN_DEBUG "\tec %d\n", seb->ec);
dbg_msg("pnum %d", seb->pnum); printk(KERN_DEBUG "\tpnum %d\n", seb->pnum);
if (type == 0) { if (type == 0) {
dbg_msg("lnum %d", seb->lnum); printk(KERN_DEBUG "\tlnum %d\n", seb->lnum);
dbg_msg("scrub %d", seb->scrub); printk(KERN_DEBUG "\tscrub %d\n", seb->scrub);
dbg_msg("sqnum %llu", seb->sqnum); printk(KERN_DEBUG "\tsqnum %llu\n", seb->sqnum);
dbg_msg("leb_ver %u", seb->leb_ver);
} }
} }
...@@ -176,16 +182,16 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req) ...@@ -176,16 +182,16 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
{ {
char nm[17]; char nm[17];
dbg_msg("volume creation request dump:"); printk(KERN_DEBUG "Volume creation request dump:\n");
dbg_msg("vol_id %d", req->vol_id); printk(KERN_DEBUG "\tvol_id %d\n", req->vol_id);
dbg_msg("alignment %d", req->alignment); printk(KERN_DEBUG "\talignment %d\n", req->alignment);
dbg_msg("bytes %lld", (long long)req->bytes); printk(KERN_DEBUG "\tbytes %lld\n", (long long)req->bytes);
dbg_msg("vol_type %d", req->vol_type); printk(KERN_DEBUG "\tvol_type %d\n", req->vol_type);
dbg_msg("name_len %d", req->name_len); printk(KERN_DEBUG "\tname_len %d\n", req->name_len);
memcpy(nm, req->name, 16); memcpy(nm, req->name, 16);
nm[16] = 0; nm[16] = 0;
dbg_msg("the 1st 16 characters of the name: %s", nm); printk(KERN_DEBUG "\t1st 16 characters of name: %s\n", nm);
} }
#endif /* CONFIG_MTD_UBI_DEBUG_MSG */ #endif /* CONFIG_MTD_UBI_DEBUG */
...@@ -24,21 +24,16 @@ ...@@ -24,21 +24,16 @@
#ifdef CONFIG_MTD_UBI_DEBUG #ifdef CONFIG_MTD_UBI_DEBUG
#include <linux/random.h> #include <linux/random.h>
#define ubi_assert(expr) BUG_ON(!(expr))
#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__) #define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__)
#else
#define ubi_assert(expr) ({})
#define dbg_err(fmt, ...) ({})
#endif
#ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT #define ubi_assert(expr) do { \
#define DBG_DISABLE_BGT 1 if (unlikely(!(expr))) { \
#else printk(KERN_CRIT "UBI assert failed in %s at %u (pid %d)\n", \
#define DBG_DISABLE_BGT 0 __func__, __LINE__, current->pid); \
#endif ubi_dbg_dump_stack(); \
} \
} while (0)
#ifdef CONFIG_MTD_UBI_DEBUG_MSG
/* Generic debugging message */
#define dbg_msg(fmt, ...) \ #define dbg_msg(fmt, ...) \
printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \ printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \
current->pid, __func__, ##__VA_ARGS__) current->pid, __func__, ##__VA_ARGS__)
...@@ -61,36 +56,29 @@ void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv); ...@@ -61,36 +56,29 @@ void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type); void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req); void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
#ifdef CONFIG_MTD_UBI_DEBUG_MSG
/* General debugging messages */
#define dbg_gen(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
#else #else
#define dbg_gen(fmt, ...) ({})
#define dbg_msg(fmt, ...) ({}) #endif
#define ubi_dbg_dump_stack() ({})
#define ubi_dbg_dump_ec_hdr(ec_hdr) ({})
#define ubi_dbg_dump_vid_hdr(vid_hdr) ({})
#define ubi_dbg_dump_vol_info(vol) ({})
#define ubi_dbg_dump_vtbl_record(r, idx) ({})
#define ubi_dbg_dump_sv(sv) ({})
#define ubi_dbg_dump_seb(seb, type) ({})
#define ubi_dbg_dump_mkvol_req(req) ({})
#endif /* CONFIG_MTD_UBI_DEBUG_MSG */
#ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA #ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA
/* Messages from the eraseblock association unit */ /* Messages from the eraseblock association sub-system */
#define dbg_eba(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) #define dbg_eba(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
#else #else
#define dbg_eba(fmt, ...) ({}) #define dbg_eba(fmt, ...) ({})
#endif #endif
#ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL #ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL
/* Messages from the wear-leveling unit */ /* Messages from the wear-leveling sub-system */
#define dbg_wl(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) #define dbg_wl(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
#else #else
#define dbg_wl(fmt, ...) ({}) #define dbg_wl(fmt, ...) ({})
#endif #endif
#ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO #ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO
/* Messages from the input/output unit */ /* Messages from the input/output sub-system */
#define dbg_io(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) #define dbg_io(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
#else #else
#define dbg_io(fmt, ...) ({}) #define dbg_io(fmt, ...) ({})
...@@ -105,6 +93,12 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req); ...@@ -105,6 +93,12 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
#define UBI_IO_DEBUG 0 #define UBI_IO_DEBUG 0
#endif #endif
#ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT
#define DBG_DISABLE_BGT 1
#else
#define DBG_DISABLE_BGT 0
#endif
#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS #ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS
/** /**
* ubi_dbg_is_bitflip - if it is time to emulate a bit-flip. * ubi_dbg_is_bitflip - if it is time to emulate a bit-flip.
...@@ -149,4 +143,30 @@ static inline int ubi_dbg_is_erase_failure(void) ...@@ -149,4 +143,30 @@ static inline int ubi_dbg_is_erase_failure(void)
#define ubi_dbg_is_erase_failure() 0 #define ubi_dbg_is_erase_failure() 0
#endif #endif
#else
#define ubi_assert(expr) ({})
#define dbg_err(fmt, ...) ({})
#define dbg_msg(fmt, ...) ({})
#define dbg_gen(fmt, ...) ({})
#define dbg_eba(fmt, ...) ({})
#define dbg_wl(fmt, ...) ({})
#define dbg_io(fmt, ...) ({})
#define dbg_bld(fmt, ...) ({})
#define ubi_dbg_dump_stack() ({})
#define ubi_dbg_dump_ec_hdr(ec_hdr) ({})
#define ubi_dbg_dump_vid_hdr(vid_hdr) ({})
#define ubi_dbg_dump_vol_info(vol) ({})
#define ubi_dbg_dump_vtbl_record(r, idx) ({})
#define ubi_dbg_dump_sv(sv) ({})
#define ubi_dbg_dump_seb(seb, type) ({})
#define ubi_dbg_dump_mkvol_req(req) ({})
#define UBI_IO_DEBUG 0
#define DBG_DISABLE_BGT 0
#define ubi_dbg_is_bitflip() 0
#define ubi_dbg_is_write_failure() 0
#define ubi_dbg_is_erase_failure() 0
#endif /* !CONFIG_MTD_UBI_DEBUG */
#endif /* !__UBI_DEBUG_H__ */ #endif /* !__UBI_DEBUG_H__ */
...@@ -19,20 +19,20 @@ ...@@ -19,20 +19,20 @@
*/ */
/* /*
* The UBI Eraseblock Association (EBA) unit. * The UBI Eraseblock Association (EBA) sub-system.
* *
* This unit is responsible for I/O to/from logical eraseblock. * This sub-system is responsible for I/O to/from logical eraseblock.
* *
* Although in this implementation the EBA table is fully kept and managed in * Although in this implementation the EBA table is fully kept and managed in
* RAM, which assumes poor scalability, it might be (partially) maintained on * RAM, which assumes poor scalability, it might be (partially) maintained on
* flash in future implementations. * flash in future implementations.
* *
* The EBA unit implements per-logical eraseblock locking. Before accessing a * The EBA sub-system implements per-logical eraseblock locking. Before
* logical eraseblock it is locked for reading or writing. The per-logical * accessing a logical eraseblock it is locked for reading or writing. The
* eraseblock locking is implemented by means of the lock tree. The lock tree * per-logical eraseblock locking is implemented by means of the lock tree. The
* is an RB-tree which refers all the currently locked logical eraseblocks. The * lock tree is an RB-tree which refers all the currently locked logical
* lock tree elements are &struct ubi_ltree_entry objects. They are indexed by * eraseblocks. The lock tree elements are &struct ubi_ltree_entry objects.
* (@vol_id, @lnum) pairs. * They are indexed by (@vol_id, @lnum) pairs.
* *
* EBA also maintains the global sequence counter which is incremented each * EBA also maintains the global sequence counter which is incremented each
* time a logical eraseblock is mapped to a physical eraseblock and it is * time a logical eraseblock is mapped to a physical eraseblock and it is
...@@ -189,9 +189,7 @@ static struct ubi_ltree_entry *ltree_add_entry(struct ubi_device *ubi, ...@@ -189,9 +189,7 @@ static struct ubi_ltree_entry *ltree_add_entry(struct ubi_device *ubi,
le->users += 1; le->users += 1;
spin_unlock(&ubi->ltree_lock); spin_unlock(&ubi->ltree_lock);
if (le_free) kfree(le_free);
kfree(le_free);
return le; return le;
} }
...@@ -223,22 +221,18 @@ static int leb_read_lock(struct ubi_device *ubi, int vol_id, int lnum) ...@@ -223,22 +221,18 @@ static int leb_read_lock(struct ubi_device *ubi, int vol_id, int lnum)
*/ */
static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum) static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum)
{ {
int free = 0;
struct ubi_ltree_entry *le; struct ubi_ltree_entry *le;
spin_lock(&ubi->ltree_lock); spin_lock(&ubi->ltree_lock);
le = ltree_lookup(ubi, vol_id, lnum); le = ltree_lookup(ubi, vol_id, lnum);
le->users -= 1; le->users -= 1;
ubi_assert(le->users >= 0); ubi_assert(le->users >= 0);
up_read(&le->mutex);
if (le->users == 0) { if (le->users == 0) {
rb_erase(&le->rb, &ubi->ltree); rb_erase(&le->rb, &ubi->ltree);
free = 1; kfree(le);
} }
spin_unlock(&ubi->ltree_lock); spin_unlock(&ubi->ltree_lock);
up_read(&le->mutex);
if (free)
kfree(le);
} }
/** /**
...@@ -274,7 +268,6 @@ static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum) ...@@ -274,7 +268,6 @@ static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum)
*/ */
static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum) static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum)
{ {
int free;
struct ubi_ltree_entry *le; struct ubi_ltree_entry *le;
le = ltree_add_entry(ubi, vol_id, lnum); le = ltree_add_entry(ubi, vol_id, lnum);
...@@ -289,12 +282,9 @@ static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum) ...@@ -289,12 +282,9 @@ static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum)
ubi_assert(le->users >= 0); ubi_assert(le->users >= 0);
if (le->users == 0) { if (le->users == 0) {
rb_erase(&le->rb, &ubi->ltree); rb_erase(&le->rb, &ubi->ltree);
free = 1;
} else
free = 0;
spin_unlock(&ubi->ltree_lock);
if (free)
kfree(le); kfree(le);
}
spin_unlock(&ubi->ltree_lock);
return 1; return 1;
} }
...@@ -307,23 +297,18 @@ static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum) ...@@ -307,23 +297,18 @@ static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum)
*/ */
static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum) static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum)
{ {
int free;
struct ubi_ltree_entry *le; struct ubi_ltree_entry *le;
spin_lock(&ubi->ltree_lock); spin_lock(&ubi->ltree_lock);
le = ltree_lookup(ubi, vol_id, lnum); le = ltree_lookup(ubi, vol_id, lnum);
le->users -= 1; le->users -= 1;
ubi_assert(le->users >= 0); ubi_assert(le->users >= 0);
up_write(&le->mutex);
if (le->users == 0) { if (le->users == 0) {
rb_erase(&le->rb, &ubi->ltree); rb_erase(&le->rb, &ubi->ltree);
free = 1;
} else
free = 0;
spin_unlock(&ubi->ltree_lock);
up_write(&le->mutex);
if (free)
kfree(le); kfree(le);
}
spin_unlock(&ubi->ltree_lock);
} }
/** /**
...@@ -516,9 +501,8 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, ...@@ -516,9 +501,8 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
struct ubi_vid_hdr *vid_hdr; struct ubi_vid_hdr *vid_hdr;
vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) { if (!vid_hdr)
return -ENOMEM; return -ENOMEM;
}
mutex_lock(&ubi->buf_mutex); mutex_lock(&ubi->buf_mutex);
...@@ -752,7 +736,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -752,7 +736,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
/* If this is the last LEB @len may be unaligned */ /* If this is the last LEB @len may be unaligned */
len = ALIGN(data_size, ubi->min_io_size); len = ALIGN(data_size, ubi->min_io_size);
else else
ubi_assert(len % ubi->min_io_size == 0); ubi_assert(!(len & (ubi->min_io_size - 1)));
vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) if (!vid_hdr)
...@@ -919,7 +903,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -919,7 +903,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
} }
if (vol->eba_tbl[lnum] >= 0) { if (vol->eba_tbl[lnum] >= 0) {
err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1); err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 0);
if (err) if (err)
goto out_leb_unlock; goto out_leb_unlock;
} }
...@@ -1141,7 +1125,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, ...@@ -1141,7 +1125,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
} }
/** /**
* ubi_eba_init_scan - initialize the EBA unit using scanning information. * ubi_eba_init_scan - initialize the EBA sub-system using scanning information.
* @ubi: UBI device description object * @ubi: UBI device description object
* @si: scanning information * @si: scanning information
* *
...@@ -1156,7 +1140,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) ...@@ -1156,7 +1140,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
struct ubi_scan_leb *seb; struct ubi_scan_leb *seb;
struct rb_node *rb; struct rb_node *rb;
dbg_eba("initialize EBA unit"); dbg_eba("initialize EBA sub-system");
spin_lock_init(&ubi->ltree_lock); spin_lock_init(&ubi->ltree_lock);
mutex_init(&ubi->alc_mutex); mutex_init(&ubi->alc_mutex);
...@@ -1222,7 +1206,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) ...@@ -1222,7 +1206,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
ubi->rsvd_pebs += ubi->beb_rsvd_pebs; ubi->rsvd_pebs += ubi->beb_rsvd_pebs;
} }
dbg_eba("EBA unit is initialized"); dbg_eba("EBA sub-system is initialized");
return 0; return 0;
out_free: out_free:
...@@ -1233,20 +1217,3 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) ...@@ -1233,20 +1217,3 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
} }
return err; return err;
} }
/**
* ubi_eba_close - close EBA unit.
* @ubi: UBI device description object
*/
void ubi_eba_close(const struct ubi_device *ubi)
{
int i, num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT;
dbg_eba("close EBA unit");
for (i = 0; i < num_volumes; i++) {
if (!ubi->volumes[i])
continue;
kfree(ubi->volumes[i]->eba_tbl);
}
}
...@@ -111,7 +111,7 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -111,7 +111,7 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
struct ubi_device *ubi; struct ubi_device *ubi;
uint64_t tmp = from; uint64_t tmp = from;
dbg_msg("read %zd bytes from offset %lld", len, from); dbg_gen("read %zd bytes from offset %lld", len, from);
if (len < 0 || from < 0 || from + len > mtd->size) if (len < 0 || from < 0 || from + len > mtd->size)
return -EINVAL; return -EINVAL;
...@@ -162,7 +162,7 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -162,7 +162,7 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
struct ubi_device *ubi; struct ubi_device *ubi;
uint64_t tmp = to; uint64_t tmp = to;
dbg_msg("write %zd bytes to offset %lld", len, to); dbg_gen("write %zd bytes to offset %lld", len, to);
if (len < 0 || to < 0 || len + to > mtd->size) if (len < 0 || to < 0 || len + to > mtd->size)
return -EINVAL; return -EINVAL;
...@@ -215,7 +215,7 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) ...@@ -215,7 +215,7 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
struct ubi_volume *vol; struct ubi_volume *vol;
struct ubi_device *ubi; struct ubi_device *ubi;
dbg_msg("erase %u bytes at offset %u", instr->len, instr->addr); dbg_gen("erase %u bytes at offset %u", instr->len, instr->addr);
if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize) if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize)
return -EINVAL; return -EINVAL;
...@@ -249,8 +249,8 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) ...@@ -249,8 +249,8 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
if (err) if (err)
goto out_err; goto out_err;
instr->state = MTD_ERASE_DONE; instr->state = MTD_ERASE_DONE;
mtd_erase_callback(instr); mtd_erase_callback(instr);
return 0; return 0;
out_err: out_err:
...@@ -299,12 +299,12 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol) ...@@ -299,12 +299,12 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
mtd->size = vol->used_bytes; mtd->size = vol->used_bytes;
if (add_mtd_device(mtd)) { if (add_mtd_device(mtd)) {
ubi_err("cannot not add MTD device\n"); ubi_err("cannot not add MTD device");
kfree(mtd->name); kfree(mtd->name);
return -ENFILE; return -ENFILE;
} }
dbg_msg("added mtd%d (\"%s\"), size %u, EB size %u", dbg_gen("added mtd%d (\"%s\"), size %u, EB size %u",
mtd->index, mtd->name, mtd->size, mtd->erasesize); mtd->index, mtd->name, mtd->size, mtd->erasesize);
return 0; return 0;
} }
...@@ -322,7 +322,7 @@ int ubi_destroy_gluebi(struct ubi_volume *vol) ...@@ -322,7 +322,7 @@ int ubi_destroy_gluebi(struct ubi_volume *vol)
int err; int err;
struct mtd_info *mtd = &vol->gluebi_mtd; struct mtd_info *mtd = &vol->gluebi_mtd;
dbg_msg("remove mtd%d", mtd->index); dbg_gen("remove mtd%d", mtd->index);
err = del_mtd_device(mtd); err = del_mtd_device(mtd);
if (err) if (err)
return err; return err;
......
...@@ -20,15 +20,15 @@ ...@@ -20,15 +20,15 @@
*/ */
/* /*
* UBI input/output unit. * UBI input/output sub-system.
* *
* This unit provides a uniform way to work with all kinds of the underlying * This sub-system provides a uniform way to work with all kinds of the
* MTD devices. It also implements handy functions for reading and writing UBI * underlying MTD devices. It also implements handy functions for reading and
* headers. * writing UBI headers.
* *
* We are trying to have a paranoid mindset and not to trust to what we read * We are trying to have a paranoid mindset and not to trust to what we read
* from the flash media in order to be more secure and robust. So this unit * from the flash media in order to be more secure and robust. So this
* validates every single header it reads from the flash media. * sub-system validates every single header it reads from the flash media.
* *
* Some words about how the eraseblock headers are stored. * Some words about how the eraseblock headers are stored.
* *
...@@ -79,11 +79,11 @@ ...@@ -79,11 +79,11 @@
* 512-byte chunks, we have to allocate one more buffer and copy our VID header * 512-byte chunks, we have to allocate one more buffer and copy our VID header
* to offset 448 of this buffer. * to offset 448 of this buffer.
* *
* The I/O unit does the following trick in order to avoid this extra copy. * The I/O sub-system does the following trick in order to avoid this extra
* It always allocates a @ubi->vid_hdr_alsize bytes buffer for the VID header * copy. It always allocates a @ubi->vid_hdr_alsize bytes buffer for the VID
* and returns a pointer to offset @ubi->vid_hdr_shift of this buffer. When the * header and returns a pointer to offset @ubi->vid_hdr_shift of this buffer.
* VID header is being written out, it shifts the VID header pointer back and * When the VID header is being written out, it shifts the VID header pointer
* writes the whole sub-page. * back and writes the whole sub-page.
*/ */
#include <linux/crc32.h> #include <linux/crc32.h>
...@@ -156,15 +156,19 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, ...@@ -156,15 +156,19 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
/* /*
* -EUCLEAN is reported if there was a bit-flip which * -EUCLEAN is reported if there was a bit-flip which
* was corrected, so this is harmless. * was corrected, so this is harmless.
*
* We do not report about it here unless debugging is
* enabled. A corresponding message will be printed
* later, when it is has been scrubbed.
*/ */
ubi_msg("fixable bit-flip detected at PEB %d", pnum); dbg_msg("fixable bit-flip detected at PEB %d", pnum);
ubi_assert(len == read); ubi_assert(len == read);
return UBI_IO_BITFLIPS; return UBI_IO_BITFLIPS;
} }
if (read != len && retries++ < UBI_IO_RETRIES) { if (read != len && retries++ < UBI_IO_RETRIES) {
dbg_io("error %d while reading %d bytes from PEB %d:%d, " dbg_io("error %d while reading %d bytes from PEB %d:%d,"
"read only %zd bytes, retry", " read only %zd bytes, retry",
err, len, pnum, offset, read); err, len, pnum, offset, read);
yield(); yield();
goto retry; goto retry;
...@@ -187,7 +191,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, ...@@ -187,7 +191,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
ubi_assert(len == read); ubi_assert(len == read);
if (ubi_dbg_is_bitflip()) { if (ubi_dbg_is_bitflip()) {
dbg_msg("bit-flip (emulated)"); dbg_gen("bit-flip (emulated)");
err = UBI_IO_BITFLIPS; err = UBI_IO_BITFLIPS;
} }
} }
...@@ -391,6 +395,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum) ...@@ -391,6 +395,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
{ {
int err, i, patt_count; int err, i, patt_count;
ubi_msg("run torture test for PEB %d", pnum);
patt_count = ARRAY_SIZE(patterns); patt_count = ARRAY_SIZE(patterns);
ubi_assert(patt_count > 0); ubi_assert(patt_count > 0);
...@@ -434,6 +439,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum) ...@@ -434,6 +439,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
} }
err = patt_count; err = patt_count;
ubi_msg("PEB %d passed torture test, do not mark it a bad", pnum);
out: out:
mutex_unlock(&ubi->buf_mutex); mutex_unlock(&ubi->buf_mutex);
...@@ -699,8 +705,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, ...@@ -699,8 +705,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
if (hdr_crc != crc) { if (hdr_crc != crc) {
if (verbose) { if (verbose) {
ubi_warn("bad EC header CRC at PEB %d, calculated %#08x," ubi_warn("bad EC header CRC at PEB %d, calculated "
" read %#08x", pnum, crc, hdr_crc); "%#08x, read %#08x", pnum, crc, hdr_crc);
ubi_dbg_dump_ec_hdr(ec_hdr); ubi_dbg_dump_ec_hdr(ec_hdr);
} }
return UBI_IO_BAD_EC_HDR; return UBI_IO_BAD_EC_HDR;
...@@ -1095,8 +1101,7 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum, ...@@ -1095,8 +1101,7 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
} }
/** /**
* paranoid_check_peb_ec_hdr - check that the erase counter header of a * paranoid_check_peb_ec_hdr - check erase counter header.
* physical eraseblock is in-place and is all right.
* @ubi: UBI device description object * @ubi: UBI device description object
* @pnum: the physical eraseblock number to check * @pnum: the physical eraseblock number to check
* *
...@@ -1174,8 +1179,7 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum, ...@@ -1174,8 +1179,7 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
} }
/** /**
* paranoid_check_peb_vid_hdr - check that the volume identifier header of a * paranoid_check_peb_vid_hdr - check volume identifier header.
* physical eraseblock is in-place and is all right.
* @ubi: UBI device description object * @ubi: UBI device description object
* @pnum: the physical eraseblock number to check * @pnum: the physical eraseblock number to check
* *
...@@ -1256,7 +1260,7 @@ static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset, ...@@ -1256,7 +1260,7 @@ static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
fail: fail:
ubi_err("paranoid check failed for PEB %d", pnum); ubi_err("paranoid check failed for PEB %d", pnum);
dbg_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 = 1;
......
...@@ -106,7 +106,7 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) ...@@ -106,7 +106,7 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
struct ubi_device *ubi; struct ubi_device *ubi;
struct ubi_volume *vol; struct ubi_volume *vol;
dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode); dbg_gen("open device %d volume %d, mode %d", ubi_num, vol_id, mode);
if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -215,7 +215,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name, ...@@ -215,7 +215,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
struct ubi_device *ubi; struct ubi_device *ubi;
struct ubi_volume_desc *ret; struct ubi_volume_desc *ret;
dbg_msg("open volume %s, mode %d", name, mode); dbg_gen("open volume %s, mode %d", name, mode);
if (!name) if (!name)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -266,7 +266,7 @@ void ubi_close_volume(struct ubi_volume_desc *desc) ...@@ -266,7 +266,7 @@ void ubi_close_volume(struct ubi_volume_desc *desc)
struct ubi_volume *vol = desc->vol; struct ubi_volume *vol = desc->vol;
struct ubi_device *ubi = vol->ubi; struct ubi_device *ubi = vol->ubi;
dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode); dbg_gen("close volume %d, mode %d", vol->vol_id, desc->mode);
spin_lock(&ubi->volumes_lock); spin_lock(&ubi->volumes_lock);
switch (desc->mode) { switch (desc->mode) {
...@@ -323,7 +323,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, ...@@ -323,7 +323,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
struct ubi_device *ubi = vol->ubi; struct ubi_device *ubi = vol->ubi;
int err, vol_id = vol->vol_id; int err, vol_id = vol->vol_id;
dbg_msg("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset); dbg_gen("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset);
if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 || if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 ||
lnum >= vol->used_ebs || offset < 0 || len < 0 || lnum >= vol->used_ebs || offset < 0 || len < 0 ||
...@@ -388,7 +388,7 @@ int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, ...@@ -388,7 +388,7 @@ int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
struct ubi_device *ubi = vol->ubi; struct ubi_device *ubi = vol->ubi;
int vol_id = vol->vol_id; int vol_id = vol->vol_id;
dbg_msg("write %d bytes to LEB %d:%d:%d", len, vol_id, lnum, offset); dbg_gen("write %d bytes to LEB %d:%d:%d", len, vol_id, lnum, offset);
if (vol_id < 0 || vol_id >= ubi->vtbl_slots) if (vol_id < 0 || vol_id >= ubi->vtbl_slots)
return -EINVAL; return -EINVAL;
...@@ -397,8 +397,8 @@ int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, ...@@ -397,8 +397,8 @@ int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
return -EROFS; return -EROFS;
if (lnum < 0 || lnum >= vol->reserved_pebs || offset < 0 || len < 0 || if (lnum < 0 || lnum >= vol->reserved_pebs || offset < 0 || len < 0 ||
offset + len > vol->usable_leb_size || offset % ubi->min_io_size || offset + len > vol->usable_leb_size ||
len % ubi->min_io_size) offset & (ubi->min_io_size - 1) || len & (ubi->min_io_size - 1))
return -EINVAL; return -EINVAL;
if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM && if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
...@@ -438,7 +438,7 @@ int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf, ...@@ -438,7 +438,7 @@ int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
struct ubi_device *ubi = vol->ubi; struct ubi_device *ubi = vol->ubi;
int vol_id = vol->vol_id; int vol_id = vol->vol_id;
dbg_msg("atomically write %d bytes to LEB %d:%d", len, vol_id, lnum); dbg_gen("atomically write %d bytes to LEB %d:%d", len, vol_id, lnum);
if (vol_id < 0 || vol_id >= ubi->vtbl_slots) if (vol_id < 0 || vol_id >= ubi->vtbl_slots)
return -EINVAL; return -EINVAL;
...@@ -447,7 +447,7 @@ int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf, ...@@ -447,7 +447,7 @@ int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
return -EROFS; return -EROFS;
if (lnum < 0 || lnum >= vol->reserved_pebs || len < 0 || if (lnum < 0 || lnum >= vol->reserved_pebs || len < 0 ||
len > vol->usable_leb_size || len % ubi->min_io_size) len > vol->usable_leb_size || len & (ubi->min_io_size - 1))
return -EINVAL; return -EINVAL;
if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM && if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
...@@ -482,7 +482,7 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum) ...@@ -482,7 +482,7 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum)
struct ubi_device *ubi = vol->ubi; struct ubi_device *ubi = vol->ubi;
int err; int err;
dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); dbg_gen("erase LEB %d:%d", vol->vol_id, lnum);
if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
return -EROFS; return -EROFS;
...@@ -542,7 +542,7 @@ int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum) ...@@ -542,7 +542,7 @@ int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum)
struct ubi_volume *vol = desc->vol; struct ubi_volume *vol = desc->vol;
struct ubi_device *ubi = vol->ubi; struct ubi_device *ubi = vol->ubi;
dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum); dbg_gen("unmap LEB %d:%d", vol->vol_id, lnum);
if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
return -EROFS; return -EROFS;
...@@ -579,7 +579,7 @@ int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype) ...@@ -579,7 +579,7 @@ int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
struct ubi_volume *vol = desc->vol; struct ubi_volume *vol = desc->vol;
struct ubi_device *ubi = vol->ubi; struct ubi_device *ubi = vol->ubi;
dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum); dbg_gen("unmap LEB %d:%d", vol->vol_id, lnum);
if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
return -EROFS; return -EROFS;
...@@ -621,7 +621,7 @@ int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum) ...@@ -621,7 +621,7 @@ int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum)
{ {
struct ubi_volume *vol = desc->vol; struct ubi_volume *vol = desc->vol;
dbg_msg("test LEB %d:%d", vol->vol_id, lnum); dbg_gen("test LEB %d:%d", vol->vol_id, lnum);
if (lnum < 0 || lnum >= vol->reserved_pebs) if (lnum < 0 || lnum >= vol->reserved_pebs)
return -EINVAL; return -EINVAL;
...@@ -632,3 +632,27 @@ int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum) ...@@ -632,3 +632,27 @@ int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum)
return vol->eba_tbl[lnum] >= 0; return vol->eba_tbl[lnum] >= 0;
} }
EXPORT_SYMBOL_GPL(ubi_is_mapped); EXPORT_SYMBOL_GPL(ubi_is_mapped);
/**
* ubi_sync - synchronize UBI device buffers.
* @ubi_num: UBI device to synchronize
*
* The underlying MTD device may cache data in hardware or in software. This
* function ensures the caches are flushed. Returns zero in case of success and
* a negative error code in case of failure.
*/
int ubi_sync(int ubi_num)
{
struct ubi_device *ubi;
ubi = ubi_get_device(ubi_num);
if (!ubi)
return -ENODEV;
if (ubi->mtd->sync)
ubi->mtd->sync(ubi->mtd);
ubi_put_device(ubi);
return 0;
}
EXPORT_SYMBOL_GPL(ubi_sync);
...@@ -37,7 +37,7 @@ int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, ...@@ -37,7 +37,7 @@ int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf,
{ {
int i; int i;
ubi_assert(length % ubi->min_io_size == 0); ubi_assert(!(length & (ubi->min_io_size - 1)));
for (i = length - 1; i >= 0; i--) for (i = length - 1; i >= 0; i--)
if (((const uint8_t *)buf)[i] != 0xFF) if (((const uint8_t *)buf)[i] != 0xFF)
......
This diff is collapsed.
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
* @u: unions RB-tree or @list links * @u: unions RB-tree or @list links
* @u.rb: link in the per-volume RB-tree of &struct ubi_scan_leb objects * @u.rb: link in the per-volume RB-tree of &struct ubi_scan_leb objects
* @u.list: link in one of the eraseblock lists * @u.list: link in one of the eraseblock lists
* @leb_ver: logical eraseblock version (obsolete)
* *
* One object of this type is allocated for each physical eraseblock during * One object of this type is allocated for each physical eraseblock during
* scanning. * scanning.
...@@ -49,7 +48,6 @@ struct ubi_scan_leb { ...@@ -49,7 +48,6 @@ struct ubi_scan_leb {
struct rb_node rb; struct rb_node rb;
struct list_head list; struct list_head list;
} u; } u;
uint32_t leb_ver;
}; };
/** /**
...@@ -59,16 +57,16 @@ struct ubi_scan_leb { ...@@ -59,16 +57,16 @@ struct ubi_scan_leb {
* @leb_count: number of logical eraseblocks in this volume * @leb_count: number of logical eraseblocks in this volume
* @vol_type: volume type * @vol_type: volume type
* @used_ebs: number of used logical eraseblocks in this volume (only for * @used_ebs: number of used logical eraseblocks in this volume (only for
* static volumes) * static volumes)
* @last_data_size: amount of data in the last logical eraseblock of this * @last_data_size: amount of data in the last logical eraseblock of this
* volume (always equivalent to the usable logical eraseblock size in case of * volume (always equivalent to the usable logical eraseblock
* dynamic volumes) * size in case of dynamic volumes)
* @data_pad: how many bytes at the end of logical eraseblocks of this volume * @data_pad: how many bytes at the end of logical eraseblocks of this volume
* are not used (due to volume alignment) * are not used (due to volume alignment)
* @compat: compatibility flags of this volume * @compat: compatibility flags of this volume
* @rb: link in the volume RB-tree * @rb: link in the volume RB-tree
* @root: root of the RB-tree containing all the eraseblock belonging to this * @root: root of the RB-tree containing all the eraseblock belonging to this
* volume (&struct ubi_scan_leb objects) * volume (&struct ubi_scan_leb objects)
* *
* One object of this type is allocated for each volume during scanning. * One object of this type is allocated for each volume during scanning.
*/ */
...@@ -92,8 +90,8 @@ struct ubi_scan_volume { ...@@ -92,8 +90,8 @@ struct ubi_scan_volume {
* @free: list of free physical eraseblocks * @free: list of free physical eraseblocks
* @erase: list of physical eraseblocks which have to be erased * @erase: list of physical eraseblocks which have to be erased
* @alien: list of physical eraseblocks which should not be used by UBI (e.g., * @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
* those belonging to "preserve"-compatible internal volumes)
* @bad_peb_count: count of bad physical eraseblocks * @bad_peb_count: count of bad physical eraseblocks
* those belonging to "preserve"-compatible internal volumes)
* @vols_found: number of volumes found during scanning * @vols_found: number of volumes found during scanning
* @highest_vol_id: highest volume ID * @highest_vol_id: highest volume ID
* @alien_peb_count: count of physical eraseblocks in the @alien list * @alien_peb_count: count of physical eraseblocks in the @alien list
...@@ -106,8 +104,8 @@ struct ubi_scan_volume { ...@@ -106,8 +104,8 @@ struct ubi_scan_volume {
* @ec_count: a temporary variable used when calculating @mean_ec * @ec_count: a temporary variable used when calculating @mean_ec
* *
* This data structure contains the result of scanning and may be used by other * This data structure contains the result of scanning and may be used by other
* UBI units to build final UBI data structures, further error-recovery and so * UBI sub-systems to build final UBI data structures, further error-recovery
* on. * and so on.
*/ */
struct ubi_scan_info { struct ubi_scan_info {
struct rb_root volumes; struct rb_root volumes;
...@@ -132,8 +130,7 @@ struct ubi_device; ...@@ -132,8 +130,7 @@ struct ubi_device;
struct ubi_vid_hdr; struct ubi_vid_hdr;
/* /*
* ubi_scan_move_to_list - move a physical eraseblock from the volume tree to a * ubi_scan_move_to_list - move a PEB from the volume tree to a list.
* list.
* *
* @sv: volume scanning information * @sv: volume scanning information
* @seb: scanning eraseblock infprmation * @seb: scanning eraseblock infprmation
......
...@@ -98,10 +98,11 @@ enum { ...@@ -98,10 +98,11 @@ enum {
* Compatibility constants used by internal volumes. * Compatibility constants used by internal volumes.
* *
* @UBI_COMPAT_DELETE: delete this internal volume before anything is written * @UBI_COMPAT_DELETE: delete this internal volume before anything is written
* to the flash * to the flash
* @UBI_COMPAT_RO: attach this device in read-only mode * @UBI_COMPAT_RO: attach this device in read-only mode
* @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its
* physical eraseblocks, don't allow the wear-leveling unit to move them * physical eraseblocks, don't allow the wear-leveling
* sub-system to move them
* @UBI_COMPAT_REJECT: reject this UBI image * @UBI_COMPAT_REJECT: reject this UBI image
*/ */
enum { enum {
...@@ -123,7 +124,7 @@ enum { ...@@ -123,7 +124,7 @@ enum {
* struct ubi_ec_hdr - UBI erase counter header. * struct ubi_ec_hdr - UBI erase counter header.
* @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC) * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC)
* @version: version of UBI implementation which is supposed to accept this * @version: version of UBI implementation which is supposed to accept this
* UBI image * UBI image
* @padding1: reserved for future, zeroes * @padding1: reserved for future, zeroes
* @ec: the erase counter * @ec: the erase counter
* @vid_hdr_offset: where the VID header starts * @vid_hdr_offset: where the VID header starts
...@@ -159,24 +160,23 @@ struct ubi_ec_hdr { ...@@ -159,24 +160,23 @@ struct ubi_ec_hdr {
* struct ubi_vid_hdr - on-flash UBI volume identifier header. * struct ubi_vid_hdr - on-flash UBI volume identifier header.
* @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC) * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC)
* @version: UBI implementation version which is supposed to accept this UBI * @version: UBI implementation version which is supposed to accept this UBI
* image (%UBI_VERSION) * image (%UBI_VERSION)
* @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC) * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
* @copy_flag: if this logical eraseblock was copied from another physical * @copy_flag: if this logical eraseblock was copied from another physical
* eraseblock (for wear-leveling reasons) * eraseblock (for wear-leveling reasons)
* @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE, * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
* %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT) * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
* @vol_id: ID of this volume * @vol_id: ID of this volume
* @lnum: logical eraseblock number * @lnum: logical eraseblock number
* @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be * @padding1: reserved for future, zeroes
* removed, kept only for not breaking older UBI users)
* @data_size: how many bytes of data this logical eraseblock contains * @data_size: how many bytes of data this logical eraseblock contains
* @used_ebs: total number of used logical eraseblocks in this volume * @used_ebs: total number of used logical eraseblocks in this volume
* @data_pad: how many bytes at the end of this physical eraseblock are not * @data_pad: how many bytes at the end of this physical eraseblock are not
* used * used
* @data_crc: CRC checksum of the data stored in this logical eraseblock * @data_crc: CRC checksum of the data stored in this logical eraseblock
* @padding1: reserved for future, zeroes
* @sqnum: sequence number
* @padding2: reserved for future, zeroes * @padding2: reserved for future, zeroes
* @sqnum: sequence number
* @padding3: reserved for future, zeroes
* @hdr_crc: volume identifier header CRC checksum * @hdr_crc: volume identifier header CRC checksum
* *
* The @sqnum is the value of the global sequence counter at the time when this * The @sqnum is the value of the global sequence counter at the time when this
...@@ -224,10 +224,6 @@ struct ubi_ec_hdr { ...@@ -224,10 +224,6 @@ struct ubi_ec_hdr {
* checksum is correct, this physical eraseblock is selected (P1). Otherwise * checksum is correct, this physical eraseblock is selected (P1). Otherwise
* the older one (P) is selected. * the older one (P) is selected.
* *
* Note, there is an obsolete @leb_ver field which was used instead of @sqnum
* in the past. But it is not used anymore and we keep it in order to be able
* to deal with old UBI images. It will be removed at some point.
*
* There are 2 sorts of volumes in UBI: user volumes and internal volumes. * There are 2 sorts of volumes in UBI: user volumes and internal volumes.
* Internal volumes are not seen from outside and are used for various internal * Internal volumes are not seen from outside and are used for various internal
* UBI purposes. In this implementation there is only one internal volume - the * UBI purposes. In this implementation there is only one internal volume - the
...@@ -248,9 +244,9 @@ struct ubi_ec_hdr { ...@@ -248,9 +244,9 @@ struct ubi_ec_hdr {
* The @data_crc field contains the CRC checksum of the contents of the logical * The @data_crc field contains the CRC checksum of the contents of the logical
* eraseblock if this is a static volume. In case of dynamic volumes, it does * eraseblock if this is a static volume. In case of dynamic volumes, it does
* not contain the CRC checksum as a rule. The only exception is when the * not contain the CRC checksum as a rule. The only exception is when the
* data of the physical eraseblock was moved by the wear-leveling unit, then * data of the physical eraseblock was moved by the wear-leveling sub-system,
* the wear-leveling unit calculates the data CRC and stores it in the * then the wear-leveling sub-system calculates the data CRC and stores it in
* @data_crc field. And of course, the @copy_flag is %in this case. * the @data_crc field. And of course, the @copy_flag is %in this case.
* *
* The @data_size field is used only for static volumes because UBI has to know * The @data_size field is used only for static volumes because UBI has to know
* how many bytes of data are stored in this eraseblock. For dynamic volumes, * how many bytes of data are stored in this eraseblock. For dynamic volumes,
...@@ -277,14 +273,14 @@ struct ubi_vid_hdr { ...@@ -277,14 +273,14 @@ struct ubi_vid_hdr {
__u8 compat; __u8 compat;
__be32 vol_id; __be32 vol_id;
__be32 lnum; __be32 lnum;
__be32 leb_ver; /* obsolete, to be removed, don't use */ __u8 padding1[4];
__be32 data_size; __be32 data_size;
__be32 used_ebs; __be32 used_ebs;
__be32 data_pad; __be32 data_pad;
__be32 data_crc; __be32 data_crc;
__u8 padding1[4]; __u8 padding2[4];
__be64 sqnum; __be64 sqnum;
__u8 padding2[12]; __u8 padding3[12];
__be32 hdr_crc; __be32 hdr_crc;
} __attribute__ ((packed)); } __attribute__ ((packed));
......
...@@ -74,15 +74,15 @@ ...@@ -74,15 +74,15 @@
#define UBI_IO_RETRIES 3 #define UBI_IO_RETRIES 3
/* /*
* Error codes returned by the I/O unit. * Error codes returned by the I/O sub-system.
* *
* UBI_IO_PEB_EMPTY: the physical eraseblock is empty, i.e. it contains only * UBI_IO_PEB_EMPTY: the physical eraseblock is empty, i.e. it contains only
* 0xFF bytes * %0xFF bytes
* UBI_IO_PEB_FREE: the physical eraseblock is free, i.e. it contains only a * UBI_IO_PEB_FREE: the physical eraseblock is free, i.e. it contains only a
* valid erase counter header, and the rest are %0xFF bytes * valid erase counter header, and the rest are %0xFF bytes
* UBI_IO_BAD_EC_HDR: the erase counter header is corrupted (bad magic or CRC) * UBI_IO_BAD_EC_HDR: the erase counter header is corrupted (bad magic or CRC)
* UBI_IO_BAD_VID_HDR: the volume identifier header is corrupted (bad magic or * UBI_IO_BAD_VID_HDR: the volume identifier header is corrupted (bad magic or
* CRC) * CRC)
* UBI_IO_BITFLIPS: bit-flips were detected and corrected * UBI_IO_BITFLIPS: bit-flips were detected and corrected
*/ */
enum { enum {
...@@ -99,9 +99,9 @@ enum { ...@@ -99,9 +99,9 @@ enum {
* @ec: erase counter * @ec: erase counter
* @pnum: physical eraseblock number * @pnum: physical eraseblock number
* *
* This data structure is used in the WL unit. Each physical eraseblock has a * This data structure is used in the WL sub-system. Each physical eraseblock
* corresponding &struct wl_entry object which may be kept in different * has a corresponding &struct wl_entry object which may be kept in different
* RB-trees. See WL unit for details. * RB-trees. See WL sub-system for details.
*/ */
struct ubi_wl_entry { struct ubi_wl_entry {
struct rb_node rb; struct rb_node rb;
...@@ -118,10 +118,10 @@ struct ubi_wl_entry { ...@@ -118,10 +118,10 @@ struct ubi_wl_entry {
* @mutex: read/write mutex to implement read/write access serialization to * @mutex: read/write mutex to implement read/write access serialization to
* the (@vol_id, @lnum) logical eraseblock * the (@vol_id, @lnum) logical eraseblock
* *
* This data structure is used in the EBA unit to implement per-LEB locking. * This data structure is used in the EBA sub-system to implement per-LEB
* When a logical eraseblock is being locked - corresponding * locking. When a logical eraseblock is being locked - corresponding
* &struct ubi_ltree_entry object is inserted to the lock tree (@ubi->ltree). * &struct ubi_ltree_entry object is inserted to the lock tree (@ubi->ltree).
* See EBA unit for details. * See EBA sub-system for details.
*/ */
struct ubi_ltree_entry { struct ubi_ltree_entry {
struct rb_node rb; struct rb_node rb;
...@@ -131,6 +131,27 @@ struct ubi_ltree_entry { ...@@ -131,6 +131,27 @@ struct ubi_ltree_entry {
struct rw_semaphore mutex; struct rw_semaphore mutex;
}; };
/**
* struct ubi_rename_entry - volume re-name description data structure.
* @new_name_len: new volume name length
* @new_name: new volume name
* @remove: if not zero, this volume should be removed, not re-named
* @desc: descriptor of the volume
* @list: links re-name entries into a list
*
* This data structure is utilized in the multiple volume re-name code. Namely,
* UBI first creates a list of &struct ubi_rename_entry objects from the
* &struct ubi_rnvol_req request object, and then utilizes this list to do all
* the job.
*/
struct ubi_rename_entry {
int new_name_len;
char new_name[UBI_VOL_NAME_MAX + 1];
int remove;
struct ubi_volume_desc *desc;
struct list_head list;
};
struct ubi_volume_desc; struct ubi_volume_desc;
/** /**
...@@ -206,7 +227,7 @@ struct ubi_volume { ...@@ -206,7 +227,7 @@ struct ubi_volume {
int alignment; int alignment;
int data_pad; int data_pad;
int name_len; int name_len;
char name[UBI_VOL_NAME_MAX+1]; char name[UBI_VOL_NAME_MAX + 1];
int upd_ebs; int upd_ebs;
int ch_lnum; int ch_lnum;
...@@ -225,7 +246,7 @@ struct ubi_volume { ...@@ -225,7 +246,7 @@ struct ubi_volume {
#ifdef CONFIG_MTD_UBI_GLUEBI #ifdef CONFIG_MTD_UBI_GLUEBI
/* /*
* Gluebi-related stuff may be compiled out. * Gluebi-related stuff may be compiled out.
* TODO: this should not be built into UBI but should be a separate * Note: this should not be built into UBI but should be a separate
* ubimtd driver which works on top of UBI and emulates MTD devices. * ubimtd driver which works on top of UBI and emulates MTD devices.
*/ */
struct ubi_volume_desc *gluebi_desc; struct ubi_volume_desc *gluebi_desc;
...@@ -235,8 +256,7 @@ struct ubi_volume { ...@@ -235,8 +256,7 @@ struct ubi_volume {
}; };
/** /**
* struct ubi_volume_desc - descriptor of the UBI volume returned when it is * struct ubi_volume_desc - UBI volume descriptor returned when it is opened.
* opened.
* @vol: reference to the corresponding volume description object * @vol: reference to the corresponding volume description object
* @mode: open mode (%UBI_READONLY, %UBI_READWRITE, or %UBI_EXCLUSIVE) * @mode: open mode (%UBI_READONLY, %UBI_READWRITE, or %UBI_EXCLUSIVE)
*/ */
...@@ -273,7 +293,7 @@ struct ubi_wl_entry; ...@@ -273,7 +293,7 @@ struct ubi_wl_entry;
* @vtbl_size: size of the volume table in bytes * @vtbl_size: size of the volume table in bytes
* @vtbl: in-RAM volume table copy * @vtbl: in-RAM volume table copy
* @volumes_mutex: protects on-flash volume table and serializes volume * @volumes_mutex: protects on-flash volume table and serializes volume
* changes, like creation, deletion, update, resize * changes, like creation, deletion, update, re-size and re-name
* *
* @max_ec: current highest erase counter value * @max_ec: current highest erase counter value
* @mean_ec: current mean erase counter value * @mean_ec: current mean erase counter value
...@@ -293,6 +313,7 @@ struct ubi_wl_entry; ...@@ -293,6 +313,7 @@ struct ubi_wl_entry;
* @move_to, @move_to_put @erase_pending, @wl_scheduled, and @works * @move_to, @move_to_put @erase_pending, @wl_scheduled, and @works
* fields * fields
* @move_mutex: serializes eraseblock moves * @move_mutex: serializes eraseblock moves
* @work_sem: sycnhronizes the WL worker with use tasks
* @wl_scheduled: non-zero if the wear-leveling was scheduled * @wl_scheduled: non-zero if the wear-leveling was scheduled
* @lookuptbl: a table to quickly find a &struct ubi_wl_entry object for any * @lookuptbl: a table to quickly find a &struct ubi_wl_entry object for any
* physical eraseblock * physical eraseblock
...@@ -316,11 +337,11 @@ struct ubi_wl_entry; ...@@ -316,11 +337,11 @@ struct ubi_wl_entry;
* @ro_mode: if the UBI device is in read-only mode * @ro_mode: if the UBI device is in read-only mode
* @leb_size: logical eraseblock size * @leb_size: logical eraseblock size
* @leb_start: starting offset of logical eraseblocks within physical * @leb_start: starting offset of logical eraseblocks within physical
* eraseblocks * eraseblocks
* @ec_hdr_alsize: size of the EC header aligned to @hdrs_min_io_size * @ec_hdr_alsize: size of the EC header aligned to @hdrs_min_io_size
* @vid_hdr_alsize: size of the VID header aligned to @hdrs_min_io_size * @vid_hdr_alsize: size of the VID header aligned to @hdrs_min_io_size
* @vid_hdr_offset: starting offset of the volume identifier header (might be * @vid_hdr_offset: starting offset of the volume identifier header (might be
* unaligned) * unaligned)
* @vid_hdr_aloffset: starting offset of the VID header aligned to * @vid_hdr_aloffset: starting offset of the VID header aligned to
* @hdrs_min_io_size * @hdrs_min_io_size
* @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset
...@@ -331,6 +352,8 @@ struct ubi_wl_entry; ...@@ -331,6 +352,8 @@ struct ubi_wl_entry;
* @peb_buf1: a buffer of PEB size used for different purposes * @peb_buf1: a buffer of PEB size used for different purposes
* @peb_buf2: another buffer of PEB size used for different purposes * @peb_buf2: another buffer of PEB size used for different purposes
* @buf_mutex: proptects @peb_buf1 and @peb_buf2 * @buf_mutex: proptects @peb_buf1 and @peb_buf2
* @ckvol_mutex: serializes static volume checking when opening
* @mult_mutex: serializes operations on multiple volumes, like re-nameing
* @dbg_peb_buf: buffer of PEB size used for debugging * @dbg_peb_buf: buffer of PEB size used for debugging
* @dbg_buf_mutex: proptects @dbg_peb_buf * @dbg_buf_mutex: proptects @dbg_peb_buf
*/ */
...@@ -356,16 +379,16 @@ struct ubi_device { ...@@ -356,16 +379,16 @@ struct ubi_device {
struct mutex volumes_mutex; struct mutex volumes_mutex;
int max_ec; int max_ec;
/* TODO: mean_ec is not updated run-time, fix */ /* Note, mean_ec is not updated run-time - should be fixed */
int mean_ec; int mean_ec;
/* EBA unit's stuff */ /* EBA sub-system's stuff */
unsigned long long global_sqnum; unsigned long long global_sqnum;
spinlock_t ltree_lock; spinlock_t ltree_lock;
struct rb_root ltree; struct rb_root ltree;
struct mutex alc_mutex; struct mutex alc_mutex;
/* Wear-leveling unit's stuff */ /* Wear-leveling sub-system's stuff */
struct rb_root used; struct rb_root used;
struct rb_root free; struct rb_root free;
struct rb_root scrub; struct rb_root scrub;
...@@ -388,7 +411,7 @@ struct ubi_device { ...@@ -388,7 +411,7 @@ struct ubi_device {
int thread_enabled; int thread_enabled;
char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2]; char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2];
/* I/O unit's stuff */ /* I/O sub-system's stuff */
long long flash_size; long long flash_size;
int peb_count; int peb_count;
int peb_size; int peb_size;
...@@ -411,6 +434,7 @@ struct ubi_device { ...@@ -411,6 +434,7 @@ struct ubi_device {
void *peb_buf2; void *peb_buf2;
struct mutex buf_mutex; struct mutex buf_mutex;
struct mutex ckvol_mutex; struct mutex ckvol_mutex;
struct mutex mult_mutex;
#ifdef CONFIG_MTD_UBI_DEBUG #ifdef CONFIG_MTD_UBI_DEBUG
void *dbg_peb_buf; void *dbg_peb_buf;
struct mutex dbg_buf_mutex; struct mutex dbg_buf_mutex;
...@@ -427,12 +451,15 @@ extern struct mutex ubi_devices_mutex; ...@@ -427,12 +451,15 @@ extern struct mutex ubi_devices_mutex;
/* vtbl.c */ /* vtbl.c */
int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
struct ubi_vtbl_record *vtbl_rec); struct ubi_vtbl_record *vtbl_rec);
int ubi_vtbl_rename_volumes(struct ubi_device *ubi,
struct list_head *rename_list);
int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si); int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si);
/* vmt.c */ /* vmt.c */
int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req); int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req);
int ubi_remove_volume(struct ubi_volume_desc *desc); int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl);
int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs); int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs);
int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list);
int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol); int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol);
void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol); void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol);
...@@ -447,7 +474,8 @@ int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -447,7 +474,8 @@ int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
const void __user *buf, int count); const void __user *buf, int count);
/* misc.c */ /* misc.c */
int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, int length); int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf,
int length);
int ubi_check_volume(struct ubi_device *ubi, int vol_id); int ubi_check_volume(struct ubi_device *ubi, int vol_id);
void ubi_calculate_reserved(struct ubi_device *ubi); void ubi_calculate_reserved(struct ubi_device *ubi);
...@@ -477,7 +505,6 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -477,7 +505,6 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
struct ubi_vid_hdr *vid_hdr); struct ubi_vid_hdr *vid_hdr);
int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si); int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si);
void ubi_eba_close(const struct ubi_device *ubi);
/* wl.c */ /* wl.c */
int ubi_wl_get_peb(struct ubi_device *ubi, int dtype); int ubi_wl_get_peb(struct ubi_device *ubi, int dtype);
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
*/ */
#include <linux/err.h> #include <linux/err.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "ubi.h" #include "ubi.h"
...@@ -56,11 +56,11 @@ static int set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol) ...@@ -56,11 +56,11 @@ static int set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol)
int err; int err;
struct ubi_vtbl_record vtbl_rec; struct ubi_vtbl_record vtbl_rec;
dbg_msg("set update marker for volume %d", vol->vol_id); dbg_gen("set update marker for volume %d", vol->vol_id);
if (vol->upd_marker) { if (vol->upd_marker) {
ubi_assert(ubi->vtbl[vol->vol_id].upd_marker); ubi_assert(ubi->vtbl[vol->vol_id].upd_marker);
dbg_msg("already set"); dbg_gen("already set");
return 0; return 0;
} }
...@@ -92,7 +92,7 @@ static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -92,7 +92,7 @@ static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol,
uint64_t tmp; uint64_t tmp;
struct ubi_vtbl_record vtbl_rec; struct ubi_vtbl_record vtbl_rec;
dbg_msg("clear update marker for volume %d", vol->vol_id); dbg_gen("clear update marker for volume %d", vol->vol_id);
memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id], memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id],
sizeof(struct ubi_vtbl_record)); sizeof(struct ubi_vtbl_record));
...@@ -133,7 +133,7 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -133,7 +133,7 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
int i, err; int i, err;
uint64_t tmp; uint64_t tmp;
dbg_msg("start update of volume %d, %llu bytes", vol->vol_id, bytes); dbg_gen("start update of volume %d, %llu bytes", vol->vol_id, bytes);
ubi_assert(!vol->updating && !vol->changing_leb); ubi_assert(!vol->updating && !vol->changing_leb);
vol->updating = 1; vol->updating = 1;
...@@ -183,7 +183,7 @@ int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -183,7 +183,7 @@ int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
{ {
ubi_assert(!vol->updating && !vol->changing_leb); ubi_assert(!vol->updating && !vol->changing_leb);
dbg_msg("start changing LEB %d:%d, %u bytes", dbg_gen("start changing LEB %d:%d, %u bytes",
vol->vol_id, req->lnum, req->bytes); vol->vol_id, req->lnum, req->bytes);
if (req->bytes == 0) if (req->bytes == 0)
return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0, return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0,
...@@ -237,16 +237,17 @@ static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, ...@@ -237,16 +237,17 @@ static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
int err; int err;
if (vol->vol_type == UBI_DYNAMIC_VOLUME) { if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
len = ALIGN(len, ubi->min_io_size); int l = ALIGN(len, ubi->min_io_size);
memset(buf + len, 0xFF, len - len);
len = ubi_calc_data_len(ubi, buf, len); memset(buf + len, 0xFF, l - len);
len = ubi_calc_data_len(ubi, buf, l);
if (len == 0) { if (len == 0) {
dbg_msg("all %d bytes contain 0xFF - skip", len); dbg_gen("all %d bytes contain 0xFF - skip", len);
return 0; return 0;
} }
err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len, UBI_UNKNOWN); err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len,
UBI_UNKNOWN);
} else { } else {
/* /*
* When writing static volume, and this is the last logical * When writing static volume, and this is the last logical
...@@ -267,6 +268,7 @@ static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, ...@@ -267,6 +268,7 @@ static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
/** /**
* ubi_more_update_data - write more update data. * ubi_more_update_data - write more update data.
* @ubi: UBI device description object
* @vol: volume description object * @vol: volume description object
* @buf: write data (user-space memory buffer) * @buf: write data (user-space memory buffer)
* @count: how much bytes to write * @count: how much bytes to write
...@@ -283,7 +285,7 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -283,7 +285,7 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
uint64_t tmp; uint64_t tmp;
int lnum, offs, err = 0, len, to_write = count; int lnum, offs, err = 0, len, to_write = count;
dbg_msg("write %d of %lld bytes, %lld already passed", dbg_gen("write %d of %lld bytes, %lld already passed",
count, vol->upd_bytes, vol->upd_received); count, vol->upd_bytes, vol->upd_received);
if (ubi->ro_mode) if (ubi->ro_mode)
...@@ -384,6 +386,7 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -384,6 +386,7 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
/** /**
* ubi_more_leb_change_data - accept more data for atomic LEB change. * ubi_more_leb_change_data - accept more data for atomic LEB change.
* @ubi: UBI device description object
* @vol: volume description object * @vol: volume description object
* @buf: write data (user-space memory buffer) * @buf: write data (user-space memory buffer)
* @count: how much bytes to write * @count: how much bytes to write
...@@ -400,7 +403,7 @@ int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -400,7 +403,7 @@ int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
{ {
int err; int err;
dbg_msg("write %d of %lld bytes, %lld already passed", dbg_gen("write %d of %lld bytes, %lld already passed",
count, vol->upd_bytes, vol->upd_received); count, vol->upd_bytes, vol->upd_received);
if (ubi->ro_mode) if (ubi->ro_mode)
...@@ -418,7 +421,8 @@ int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -418,7 +421,8 @@ int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
if (vol->upd_received == vol->upd_bytes) { if (vol->upd_received == vol->upd_bytes) {
int len = ALIGN((int)vol->upd_bytes, ubi->min_io_size); int len = ALIGN((int)vol->upd_bytes, ubi->min_io_size);
memset(vol->upd_buf + vol->upd_bytes, 0xFF, len - vol->upd_bytes); memset(vol->upd_buf + vol->upd_bytes, 0xFF,
len - vol->upd_bytes);
len = ubi_calc_data_len(ubi, vol->upd_buf, len); len = ubi_calc_data_len(ubi, vol->upd_buf, len);
err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum, err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum,
vol->upd_buf, len, UBI_UNKNOWN); vol->upd_buf, len, UBI_UNKNOWN);
......
This diff is collapsed.
...@@ -115,8 +115,58 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, ...@@ -115,8 +115,58 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
} }
/** /**
* vtbl_check - check if volume table is not corrupted and contains sensible * ubi_vtbl_rename_volumes - rename UBI volumes in the volume table.
* data. * @ubi: UBI device description object
* @rename_list: list of &struct ubi_rename_entry objects
*
* This function re-names multiple volumes specified in @req in the volume
* table. Returns zero in case of success and a negative error code in case of
* failure.
*/
int ubi_vtbl_rename_volumes(struct ubi_device *ubi,
struct list_head *rename_list)
{
int i, err;
struct ubi_rename_entry *re;
struct ubi_volume *layout_vol;
list_for_each_entry(re, rename_list, list) {
uint32_t crc;
struct ubi_volume *vol = re->desc->vol;
struct ubi_vtbl_record *vtbl_rec = &ubi->vtbl[vol->vol_id];
if (re->remove) {
memcpy(vtbl_rec, &empty_vtbl_record,
sizeof(struct ubi_vtbl_record));
continue;
}
vtbl_rec->name_len = cpu_to_be16(re->new_name_len);
memcpy(vtbl_rec->name, re->new_name, re->new_name_len);
memset(vtbl_rec->name + re->new_name_len, 0,
UBI_VOL_NAME_MAX + 1 - re->new_name_len);
crc = crc32(UBI_CRC32_INIT, vtbl_rec,
UBI_VTBL_RECORD_SIZE_CRC);
vtbl_rec->crc = cpu_to_be32(crc);
}
layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)];
for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
err = ubi_eba_unmap_leb(ubi, layout_vol, i);
if (err)
return err;
err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0,
ubi->vtbl_size, UBI_LONGTERM);
if (err)
return err;
}
return 0;
}
/**
* vtbl_check - check if volume table is not corrupted and sensible.
* @ubi: UBI device description object * @ubi: UBI device description object
* @vtbl: volume table * @vtbl: volume table
* *
...@@ -127,7 +177,7 @@ static int vtbl_check(const struct ubi_device *ubi, ...@@ -127,7 +177,7 @@ static int vtbl_check(const struct ubi_device *ubi,
const struct ubi_vtbl_record *vtbl) const struct ubi_vtbl_record *vtbl)
{ {
int i, n, reserved_pebs, alignment, data_pad, vol_type, name_len; int i, n, reserved_pebs, alignment, data_pad, vol_type, name_len;
int upd_marker; int upd_marker, err;
uint32_t crc; uint32_t crc;
const char *name; const char *name;
...@@ -153,7 +203,7 @@ static int vtbl_check(const struct ubi_device *ubi, ...@@ -153,7 +203,7 @@ static int vtbl_check(const struct ubi_device *ubi,
if (reserved_pebs == 0) { if (reserved_pebs == 0) {
if (memcmp(&vtbl[i], &empty_vtbl_record, if (memcmp(&vtbl[i], &empty_vtbl_record,
UBI_VTBL_RECORD_SIZE)) { UBI_VTBL_RECORD_SIZE)) {
dbg_err("bad empty record"); err = 2;
goto bad; goto bad;
} }
continue; continue;
...@@ -161,56 +211,57 @@ static int vtbl_check(const struct ubi_device *ubi, ...@@ -161,56 +211,57 @@ static int vtbl_check(const struct ubi_device *ubi,
if (reserved_pebs < 0 || alignment < 0 || data_pad < 0 || if (reserved_pebs < 0 || alignment < 0 || data_pad < 0 ||
name_len < 0) { name_len < 0) {
dbg_err("negative values"); err = 3;
goto bad; goto bad;
} }
if (alignment > ubi->leb_size || alignment == 0) { if (alignment > ubi->leb_size || alignment == 0) {
dbg_err("bad alignment"); err = 4;
goto bad; goto bad;
} }
n = alignment % ubi->min_io_size; n = alignment & (ubi->min_io_size - 1);
if (alignment != 1 && n) { if (alignment != 1 && n) {
dbg_err("alignment is not multiple of min I/O unit"); err = 5;
goto bad; goto bad;
} }
n = ubi->leb_size % alignment; n = ubi->leb_size % alignment;
if (data_pad != n) { if (data_pad != n) {
dbg_err("bad data_pad, has to be %d", n); dbg_err("bad data_pad, has to be %d", n);
err = 6;
goto bad; goto bad;
} }
if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) { if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) {
dbg_err("bad vol_type"); err = 7;
goto bad; goto bad;
} }
if (upd_marker != 0 && upd_marker != 1) { if (upd_marker != 0 && upd_marker != 1) {
dbg_err("bad upd_marker"); err = 8;
goto bad; goto bad;
} }
if (reserved_pebs > ubi->good_peb_count) { if (reserved_pebs > ubi->good_peb_count) {
dbg_err("too large reserved_pebs, good PEBs %d", dbg_err("too large reserved_pebs, good PEBs %d",
ubi->good_peb_count); ubi->good_peb_count);
err = 9;
goto bad; goto bad;
} }
if (name_len > UBI_VOL_NAME_MAX) { if (name_len > UBI_VOL_NAME_MAX) {
dbg_err("too long volume name, max %d", err = 10;
UBI_VOL_NAME_MAX);
goto bad; goto bad;
} }
if (name[0] == '\0') { if (name[0] == '\0') {
dbg_err("NULL volume name"); err = 11;
goto bad; goto bad;
} }
if (name_len != strnlen(name, name_len + 1)) { if (name_len != strnlen(name, name_len + 1)) {
dbg_err("bad name_len"); err = 12;
goto bad; goto bad;
} }
} }
...@@ -235,7 +286,7 @@ static int vtbl_check(const struct ubi_device *ubi, ...@@ -235,7 +286,7 @@ static int vtbl_check(const struct ubi_device *ubi,
return 0; return 0;
bad: bad:
ubi_err("volume table check failed, record %d", i); ubi_err("volume table check failed: record %d, error %d", i, err);
ubi_dbg_dump_vtbl_record(&vtbl[i], i); ubi_dbg_dump_vtbl_record(&vtbl[i], i);
return -EINVAL; return -EINVAL;
} }
...@@ -287,7 +338,6 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si, ...@@ -287,7 +338,6 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
vid_hdr->data_pad = cpu_to_be32(0); vid_hdr->data_pad = cpu_to_be32(0);
vid_hdr->lnum = cpu_to_be32(copy); vid_hdr->lnum = cpu_to_be32(copy);
vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum); vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum);
vid_hdr->leb_ver = cpu_to_be32(old_seb ? old_seb->leb_ver + 1: 0);
/* The EC header is already there, write the VID header */ /* The EC header is already there, write the VID header */
err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr); err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr);
...@@ -370,7 +420,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, ...@@ -370,7 +420,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
* to LEB 0. * to LEB 0.
*/ */
dbg_msg("check layout volume"); dbg_gen("check layout volume");
/* Read both LEB 0 and LEB 1 into memory */ /* Read both LEB 0 and LEB 1 into memory */
ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
...@@ -384,7 +434,16 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, ...@@ -384,7 +434,16 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
ubi->vtbl_size); ubi->vtbl_size);
if (err == UBI_IO_BITFLIPS || err == -EBADMSG) if (err == UBI_IO_BITFLIPS || err == -EBADMSG)
/* Scrub the PEB later */ /*
* Scrub the PEB later. Note, -EBADMSG indicates an
* uncorrectable ECC error, but we have our own CRC and
* the data will be checked later. If the data is OK,
* the PEB will be scrubbed (because we set
* seb->scrub). If the data is not OK, the contents of
* the PEB will be recovered from the second copy, and
* seb->scrub will be cleared in
* 'ubi_scan_add_used()'.
*/
seb->scrub = 1; seb->scrub = 1;
else if (err) else if (err)
goto out_free; goto out_free;
...@@ -400,7 +459,8 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, ...@@ -400,7 +459,8 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
if (!leb_corrupted[0]) { if (!leb_corrupted[0]) {
/* LEB 0 is OK */ /* LEB 0 is OK */
if (leb[1]) if (leb[1])
leb_corrupted[1] = memcmp(leb[0], leb[1], ubi->vtbl_size); leb_corrupted[1] = memcmp(leb[0], leb[1],
ubi->vtbl_size);
if (leb_corrupted[1]) { if (leb_corrupted[1]) {
ubi_warn("volume table copy #2 is corrupted"); ubi_warn("volume table copy #2 is corrupted");
err = create_vtbl(ubi, si, 1, leb[0]); err = create_vtbl(ubi, si, 1, leb[0]);
...@@ -620,30 +680,32 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, ...@@ -620,30 +680,32 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
static int check_sv(const struct ubi_volume *vol, static int check_sv(const struct ubi_volume *vol,
const struct ubi_scan_volume *sv) const struct ubi_scan_volume *sv)
{ {
int err;
if (sv->highest_lnum >= vol->reserved_pebs) { if (sv->highest_lnum >= vol->reserved_pebs) {
dbg_err("bad highest_lnum"); err = 1;
goto bad; goto bad;
} }
if (sv->leb_count > vol->reserved_pebs) { if (sv->leb_count > vol->reserved_pebs) {
dbg_err("bad leb_count"); err = 2;
goto bad; goto bad;
} }
if (sv->vol_type != vol->vol_type) { if (sv->vol_type != vol->vol_type) {
dbg_err("bad vol_type"); err = 3;
goto bad; goto bad;
} }
if (sv->used_ebs > vol->reserved_pebs) { if (sv->used_ebs > vol->reserved_pebs) {
dbg_err("bad used_ebs"); err = 4;
goto bad; goto bad;
} }
if (sv->data_pad != vol->data_pad) { if (sv->data_pad != vol->data_pad) {
dbg_err("bad data_pad"); err = 5;
goto bad; goto bad;
} }
return 0; return 0;
bad: bad:
ubi_err("bad scanning information"); ubi_err("bad scanning information, error %d", err);
ubi_dbg_dump_sv(sv); ubi_dbg_dump_sv(sv);
ubi_dbg_dump_vol_info(vol); ubi_dbg_dump_vol_info(vol);
return -EINVAL; return -EINVAL;
...@@ -672,14 +734,13 @@ static int check_scanning_info(const struct ubi_device *ubi, ...@@ -672,14 +734,13 @@ static int check_scanning_info(const struct ubi_device *ubi,
return -EINVAL; return -EINVAL;
} }
if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT&& if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT &&
si->highest_vol_id < UBI_INTERNAL_VOL_START) { si->highest_vol_id < UBI_INTERNAL_VOL_START) {
ubi_err("too large volume ID %d found by scanning", ubi_err("too large volume ID %d found by scanning",
si->highest_vol_id); si->highest_vol_id);
return -EINVAL; return -EINVAL;
} }
for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) { for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
cond_resched(); cond_resched();
...@@ -717,8 +778,7 @@ static int check_scanning_info(const struct ubi_device *ubi, ...@@ -717,8 +778,7 @@ static int check_scanning_info(const struct ubi_device *ubi,
} }
/** /**
* ubi_read_volume_table - read volume table. * ubi_read_volume_table - read the volume table.
* information.
* @ubi: UBI device description object * @ubi: UBI device description object
* @si: scanning information * @si: scanning information
* *
...@@ -797,11 +857,10 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si) ...@@ -797,11 +857,10 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
out_free: out_free:
vfree(ubi->vtbl); vfree(ubi->vtbl);
for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
if (ubi->volumes[i]) { kfree(ubi->volumes[i]);
kfree(ubi->volumes[i]); ubi->volumes[i] = NULL;
ubi->volumes[i] = NULL; }
}
return err; return err;
} }
......
This diff is collapsed.
...@@ -45,13 +45,13 @@ enum { ...@@ -45,13 +45,13 @@ enum {
* @size: how many physical eraseblocks are reserved for this volume * @size: how many physical eraseblocks are reserved for this volume
* @used_bytes: how many bytes of data this volume contains * @used_bytes: how many bytes of data this volume contains
* @used_ebs: how many physical eraseblocks of this volume actually contain any * @used_ebs: how many physical eraseblocks of this volume actually contain any
* data * data
* @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
* @corrupted: non-zero if the volume is corrupted (static volumes only) * @corrupted: non-zero if the volume is corrupted (static volumes only)
* @upd_marker: non-zero if the volume has update marker set * @upd_marker: non-zero if the volume has update marker set
* @alignment: volume alignment * @alignment: volume alignment
* @usable_leb_size: how many bytes are available in logical eraseblocks of * @usable_leb_size: how many bytes are available in logical eraseblocks of
* this volume * this volume
* @name_len: volume name length * @name_len: volume name length
* @name: volume name * @name: volume name
* @cdev: UBI volume character device major and minor numbers * @cdev: UBI volume character device major and minor numbers
...@@ -152,6 +152,7 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum); ...@@ -152,6 +152,7 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum);
int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum); int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum);
int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype); int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype);
int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum); int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum);
int ubi_sync(int ubi_num);
/* /*
* This function is the same as the 'ubi_leb_read()' function, but it does not * This function is the same as the 'ubi_leb_read()' function, but it does not
......
...@@ -58,6 +58,13 @@ ...@@ -58,6 +58,13 @@
* device should be used. A &struct ubi_rsvol_req object has to be properly * device should be used. A &struct ubi_rsvol_req object has to be properly
* filled and a pointer to it has to be passed to the IOCTL. * filled and a pointer to it has to be passed to the IOCTL.
* *
* UBI volumes re-name
* ~~~~~~~~~~~~~~~~~~~
*
* To re-name several volumes atomically at one go, the %UBI_IOCRNVOL command
* of the UBI character device should be used. A &struct ubi_rnvol_req object
* has to be properly filled and a pointer to it has to be passed to the IOCTL.
*
* UBI volume update * UBI volume update
* ~~~~~~~~~~~~~~~~~ * ~~~~~~~~~~~~~~~~~
* *
...@@ -104,6 +111,8 @@ ...@@ -104,6 +111,8 @@
#define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t) #define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t)
/* Re-size an UBI volume */ /* Re-size an UBI volume */
#define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req) #define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req)
/* Re-name volumes */
#define UBI_IOCRNVOL _IOW(UBI_IOC_MAGIC, 3, struct ubi_rnvol_req)
/* IOCTL commands of the UBI control character device */ /* IOCTL commands of the UBI control character device */
...@@ -128,6 +137,9 @@ ...@@ -128,6 +137,9 @@
/* Maximum MTD device name length supported by UBI */ /* Maximum MTD device name length supported by UBI */
#define MAX_UBI_MTD_NAME_LEN 127 #define MAX_UBI_MTD_NAME_LEN 127
/* Maximum amount of UBI volumes that can be re-named at one go */
#define UBI_MAX_RNVOL 32
/* /*
* UBI data type hint constants. * UBI data type hint constants.
* *
...@@ -176,20 +188,20 @@ enum { ...@@ -176,20 +188,20 @@ enum {
* it will be 512 in case of a 2KiB page NAND flash with 4 512-byte sub-pages. * it will be 512 in case of a 2KiB page NAND flash with 4 512-byte sub-pages.
* *
* But in rare cases, if this optimizes things, the VID header may be placed to * But in rare cases, if this optimizes things, the VID header may be placed to
* a different offset. For example, the boot-loader might do things faster if the * a different offset. For example, the boot-loader might do things faster if
* VID header sits at the end of the first 2KiB NAND page with 4 sub-pages. As * the VID header sits at the end of the first 2KiB NAND page with 4 sub-pages.
* the boot-loader would not normally need to read EC headers (unless it needs * As the boot-loader would not normally need to read EC headers (unless it
* UBI in RW mode), it might be faster to calculate ECC. This is weird example, * needs UBI in RW mode), it might be faster to calculate ECC. This is weird
* but it real-life example. So, in this example, @vid_hdr_offer would be * example, but it real-life example. So, in this example, @vid_hdr_offer would
* 2KiB-64 bytes = 1984. Note, that this position is not even 512-bytes * be 2KiB-64 bytes = 1984. Note, that this position is not even 512-bytes
* aligned, which is OK, as UBI is clever enough to realize this is 4th sub-page * aligned, which is OK, as UBI is clever enough to realize this is 4th
* of the first page and add needed padding. * sub-page of the first page and add needed padding.
*/ */
struct ubi_attach_req { struct ubi_attach_req {
int32_t ubi_num; int32_t ubi_num;
int32_t mtd_num; int32_t mtd_num;
int32_t vid_hdr_offset; int32_t vid_hdr_offset;
uint8_t padding[12]; int8_t padding[12];
}; };
/** /**
...@@ -250,6 +262,48 @@ struct ubi_rsvol_req { ...@@ -250,6 +262,48 @@ struct ubi_rsvol_req {
int32_t vol_id; int32_t vol_id;
} __attribute__ ((packed)); } __attribute__ ((packed));
/**
* struct ubi_rnvol_req - volumes re-name request.
* @count: count of volumes to re-name
* @padding1: reserved for future, not used, has to be zeroed
* @vol_id: ID of the volume to re-name
* @name_len: name length
* @padding2: reserved for future, not used, has to be zeroed
* @name: new volume name
*
* UBI allows to re-name up to %32 volumes at one go. The count of volumes to
* re-name is specified in the @count field. The ID of the volumes to re-name
* and the new names are specified in the @vol_id and @name fields.
*
* The UBI volume re-name operation is atomic, which means that should power cut
* happen, the volumes will have either old name or new name. So the possible
* use-cases of this command is atomic upgrade. Indeed, to upgrade, say, volumes
* A and B one may create temporary volumes %A1 and %B1 with the new contents,
* then atomically re-name A1->A and B1->B, in which case old %A and %B will
* be removed.
*
* If it is not desirable to remove old A and B, the re-name request has to
* contain 4 entries: A1->A, A->A1, B1->B, B->B1, in which case old A1 and B1
* become A and B, and old A and B will become A1 and B1.
*
* It is also OK to request: A1->A, A1->X, B1->B, B->Y, in which case old A1
* and B1 become A and B, and old A and B become X and Y.
*
* In other words, in case of re-naming into an existing volume name, the
* existing volume is removed, unless it is re-named as well at the same
* re-name request.
*/
struct ubi_rnvol_req {
int32_t count;
int8_t padding1[12];
struct {
int32_t vol_id;
int16_t name_len;
int8_t padding2[2];
char name[UBI_MAX_VOLUME_NAME + 1];
} ents[UBI_MAX_RNVOL];
} __attribute__ ((packed));
/** /**
* struct ubi_leb_change_req - a data structure used in atomic logical * struct ubi_leb_change_req - a data structure used in atomic logical
* eraseblock change requests. * eraseblock change requests.
...@@ -261,8 +315,8 @@ struct ubi_rsvol_req { ...@@ -261,8 +315,8 @@ struct ubi_rsvol_req {
struct ubi_leb_change_req { struct ubi_leb_change_req {
int32_t lnum; int32_t lnum;
int32_t bytes; int32_t bytes;
uint8_t dtype; int8_t dtype;
uint8_t padding[7]; int8_t padding[7];
} __attribute__ ((packed)); } __attribute__ ((packed));
#endif /* __UBI_USER_H__ */ #endif /* __UBI_USER_H__ */
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