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
......
...@@ -39,9 +39,9 @@ ...@@ -39,9 +39,9 @@
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/uaccess.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <mtd/ubi-user.h> #include <mtd/ubi-user.h>
#include <asm/uaccess.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "ubi.h" #include "ubi.h"
...@@ -116,7 +116,7 @@ static int vol_cdev_open(struct inode *inode, struct file *file) ...@@ -116,7 +116,7 @@ static int vol_cdev_open(struct inode *inode, struct file *file)
else else
mode = UBI_READONLY; mode = UBI_READONLY;
dbg_msg("open volume %d, mode %d", vol_id, mode); dbg_gen("open volume %d, mode %d", vol_id, mode);
desc = ubi_open_volume(ubi_num, vol_id, mode); desc = ubi_open_volume(ubi_num, vol_id, mode);
unlock_kernel(); unlock_kernel();
...@@ -132,7 +132,7 @@ static int vol_cdev_release(struct inode *inode, struct file *file) ...@@ -132,7 +132,7 @@ static int vol_cdev_release(struct inode *inode, struct file *file)
struct ubi_volume_desc *desc = file->private_data; struct ubi_volume_desc *desc = file->private_data;
struct ubi_volume *vol = desc->vol; struct ubi_volume *vol = desc->vol;
dbg_msg("release volume %d, mode %d", vol->vol_id, desc->mode); dbg_gen("release volume %d, mode %d", vol->vol_id, desc->mode);
if (vol->updating) { if (vol->updating) {
ubi_warn("update of volume %d not finished, volume is damaged", ubi_warn("update of volume %d not finished, volume is damaged",
...@@ -141,7 +141,7 @@ static int vol_cdev_release(struct inode *inode, struct file *file) ...@@ -141,7 +141,7 @@ static int vol_cdev_release(struct inode *inode, struct file *file)
vol->updating = 0; vol->updating = 0;
vfree(vol->upd_buf); vfree(vol->upd_buf);
} else if (vol->changing_leb) { } else if (vol->changing_leb) {
dbg_msg("only %lld of %lld bytes received for atomic LEB change" dbg_gen("only %lld of %lld bytes received for atomic LEB change"
" for volume %d:%d, cancel", vol->upd_received, " for volume %d:%d, cancel", vol->upd_received,
vol->upd_bytes, vol->ubi->ubi_num, vol->vol_id); vol->upd_bytes, vol->ubi->ubi_num, vol->vol_id);
vol->changing_leb = 0; vol->changing_leb = 0;
...@@ -183,7 +183,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin) ...@@ -183,7 +183,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
return -EINVAL; return -EINVAL;
} }
dbg_msg("seek volume %d, offset %lld, origin %d, new offset %lld", dbg_gen("seek volume %d, offset %lld, origin %d, new offset %lld",
vol->vol_id, offset, origin, new_offset); vol->vol_id, offset, origin, new_offset);
file->f_pos = new_offset; file->f_pos = new_offset;
...@@ -201,7 +201,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, ...@@ -201,7 +201,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
void *tbuf; void *tbuf;
uint64_t tmp; uint64_t tmp;
dbg_msg("read %zd bytes from offset %lld of volume %d", dbg_gen("read %zd bytes from offset %lld of volume %d",
count, *offp, vol->vol_id); count, *offp, vol->vol_id);
if (vol->updating) { if (vol->updating) {
...@@ -216,7 +216,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, ...@@ -216,7 +216,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
return 0; return 0;
if (vol->corrupted) if (vol->corrupted)
dbg_msg("read from corrupted volume %d", vol->vol_id); dbg_gen("read from corrupted volume %d", vol->vol_id);
if (*offp + count > vol->used_bytes) if (*offp + count > vol->used_bytes)
count_save = count = vol->used_bytes - *offp; count_save = count = vol->used_bytes - *offp;
...@@ -285,7 +285,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, ...@@ -285,7 +285,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
char *tbuf; char *tbuf;
uint64_t tmp; uint64_t tmp;
dbg_msg("requested: write %zd bytes to offset %lld of volume %u", dbg_gen("requested: write %zd bytes to offset %lld of volume %u",
count, *offp, vol->vol_id); count, *offp, vol->vol_id);
if (vol->vol_type == UBI_STATIC_VOLUME) if (vol->vol_type == UBI_STATIC_VOLUME)
...@@ -295,7 +295,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, ...@@ -295,7 +295,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
off = do_div(tmp, vol->usable_leb_size); off = do_div(tmp, vol->usable_leb_size);
lnum = tmp; lnum = tmp;
if (off % ubi->min_io_size) { if (off & (ubi->min_io_size - 1)) {
dbg_err("unaligned position"); dbg_err("unaligned position");
return -EINVAL; return -EINVAL;
} }
...@@ -304,7 +304,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, ...@@ -304,7 +304,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
count_save = count = vol->used_bytes - *offp; count_save = count = vol->used_bytes - *offp;
/* We can write only in fractions of the minimum I/O unit */ /* We can write only in fractions of the minimum I/O unit */
if (count % ubi->min_io_size) { if (count & (ubi->min_io_size - 1)) {
dbg_err("unaligned write length"); dbg_err("unaligned write length");
return -EINVAL; return -EINVAL;
} }
...@@ -352,7 +352,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, ...@@ -352,7 +352,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
} }
#else #else
#define vol_cdev_direct_write(file, buf, count, offp) -EPERM #define vol_cdev_direct_write(file, buf, count, offp) (-EPERM)
#endif /* CONFIG_MTD_UBI_DEBUG_USERSPACE_IO */ #endif /* CONFIG_MTD_UBI_DEBUG_USERSPACE_IO */
static ssize_t vol_cdev_write(struct file *file, const char __user *buf, static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
...@@ -437,7 +437,8 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, ...@@ -437,7 +437,8 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
break; break;
} }
rsvd_bytes = vol->reserved_pebs * (ubi->leb_size-vol->data_pad); rsvd_bytes = (long long)vol->reserved_pebs *
ubi->leb_size-vol->data_pad;
if (bytes < 0 || bytes > rsvd_bytes) { if (bytes < 0 || bytes > rsvd_bytes) {
err = -EINVAL; err = -EINVAL;
break; break;
...@@ -513,7 +514,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, ...@@ -513,7 +514,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
break; break;
} }
dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); dbg_gen("erase LEB %d:%d", vol->vol_id, lnum);
err = ubi_eba_unmap_leb(ubi, vol, lnum); err = ubi_eba_unmap_leb(ubi, vol, lnum);
if (err) if (err)
break; break;
...@@ -564,7 +565,7 @@ static int verify_mkvol_req(const struct ubi_device *ubi, ...@@ -564,7 +565,7 @@ static int verify_mkvol_req(const struct ubi_device *ubi,
if (req->alignment > ubi->leb_size) if (req->alignment > ubi->leb_size)
goto bad; goto bad;
n = req->alignment % ubi->min_io_size; n = req->alignment & (ubi->min_io_size - 1);
if (req->alignment != 1 && n) if (req->alignment != 1 && n)
goto bad; goto bad;
...@@ -573,6 +574,10 @@ static int verify_mkvol_req(const struct ubi_device *ubi, ...@@ -573,6 +574,10 @@ static int verify_mkvol_req(const struct ubi_device *ubi,
goto bad; goto bad;
} }
n = strnlen(req->name, req->name_len + 1);
if (n != req->name_len)
goto bad;
return 0; return 0;
bad: bad:
...@@ -600,6 +605,166 @@ static int verify_rsvol_req(const struct ubi_device *ubi, ...@@ -600,6 +605,166 @@ static int verify_rsvol_req(const struct ubi_device *ubi,
return 0; return 0;
} }
/**
* rename_volumes - rename UBI volumes.
* @ubi: UBI device description object
* @req: volumes re-name request
*
* This is a helper function for the volume re-name IOCTL which validates the
* the request, opens the volume and calls corresponding volumes management
* function. Returns zero in case of success and a negative error code in case
* of failure.
*/
static int rename_volumes(struct ubi_device *ubi,
struct ubi_rnvol_req *req)
{
int i, n, err;
struct list_head rename_list;
struct ubi_rename_entry *re, *re1;
if (req->count < 0 || req->count > UBI_MAX_RNVOL)
return -EINVAL;
if (req->count == 0)
return 0;
/* Validate volume IDs and names in the request */
for (i = 0; i < req->count; i++) {
if (req->ents[i].vol_id < 0 ||
req->ents[i].vol_id >= ubi->vtbl_slots)
return -EINVAL;
if (req->ents[i].name_len < 0)
return -EINVAL;
if (req->ents[i].name_len > UBI_VOL_NAME_MAX)
return -ENAMETOOLONG;
req->ents[i].name[req->ents[i].name_len] = '\0';
n = strlen(req->ents[i].name);
if (n != req->ents[i].name_len)
err = -EINVAL;
}
/* Make sure volume IDs and names are unique */
for (i = 0; i < req->count - 1; i++) {
for (n = i + 1; n < req->count; n++) {
if (req->ents[i].vol_id == req->ents[n].vol_id) {
dbg_err("duplicated volume id %d",
req->ents[i].vol_id);
return -EINVAL;
}
if (!strcmp(req->ents[i].name, req->ents[n].name)) {
dbg_err("duplicated volume name \"%s\"",
req->ents[i].name);
return -EINVAL;
}
}
}
/* Create the re-name list */
INIT_LIST_HEAD(&rename_list);
for (i = 0; i < req->count; i++) {
int vol_id = req->ents[i].vol_id;
int name_len = req->ents[i].name_len;
const char *name = req->ents[i].name;
re = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL);
if (!re) {
err = -ENOMEM;
goto out_free;
}
re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_EXCLUSIVE);
if (IS_ERR(re->desc)) {
err = PTR_ERR(re->desc);
dbg_err("cannot open volume %d, error %d", vol_id, err);
kfree(re);
goto out_free;
}
/* Skip this re-naming if the name does not really change */
if (re->desc->vol->name_len == name_len &&
!memcmp(re->desc->vol->name, name, name_len)) {
ubi_close_volume(re->desc);
kfree(re);
continue;
}
re->new_name_len = name_len;
memcpy(re->new_name, name, name_len);
list_add_tail(&re->list, &rename_list);
dbg_msg("will rename volume %d from \"%s\" to \"%s\"",
vol_id, re->desc->vol->name, name);
}
if (list_empty(&rename_list))
return 0;
/* Find out the volumes which have to be removed */
list_for_each_entry(re, &rename_list, list) {
struct ubi_volume_desc *desc;
int no_remove_needed = 0;
/*
* Volume @re->vol_id is going to be re-named to
* @re->new_name, while its current name is @name. If a volume
* with name @re->new_name currently exists, it has to be
* removed, unless it is also re-named in the request (@req).
*/
list_for_each_entry(re1, &rename_list, list) {
if (re->new_name_len == re1->desc->vol->name_len &&
!memcmp(re->new_name, re1->desc->vol->name,
re1->desc->vol->name_len)) {
no_remove_needed = 1;
break;
}
}
if (no_remove_needed)
continue;
/*
* It seems we need to remove volume with name @re->new_name,
* if it exists.
*/
desc = ubi_open_volume_nm(ubi->ubi_num, re->new_name, UBI_EXCLUSIVE);
if (IS_ERR(desc)) {
err = PTR_ERR(desc);
if (err == -ENODEV)
/* Re-naming into a non-existing volume name */
continue;
/* The volume exists but busy, or an error occurred */
dbg_err("cannot open volume \"%s\", error %d",
re->new_name, err);
goto out_free;
}
re = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL);
if (!re) {
err = -ENOMEM;
ubi_close_volume(desc);
goto out_free;
}
re->remove = 1;
re->desc = desc;
list_add(&re->list, &rename_list);
dbg_msg("will remove volume %d, name \"%s\"",
re->desc->vol->vol_id, re->desc->vol->name);
}
mutex_lock(&ubi->volumes_mutex);
err = ubi_rename_volumes(ubi, &rename_list);
mutex_unlock(&ubi->volumes_mutex);
out_free:
list_for_each_entry_safe(re, re1, &rename_list, list) {
ubi_close_volume(re->desc);
list_del(&re->list);
kfree(re);
}
return err;
}
static int ubi_cdev_ioctl(struct inode *inode, struct file *file, static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
...@@ -621,19 +786,18 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, ...@@ -621,19 +786,18 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
{ {
struct ubi_mkvol_req req; struct ubi_mkvol_req req;
dbg_msg("create volume"); dbg_gen("create volume");
err = copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req)); err = copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req));
if (err) { if (err) {
err = -EFAULT; err = -EFAULT;
break; break;
} }
req.name[req.name_len] = '\0';
err = verify_mkvol_req(ubi, &req); err = verify_mkvol_req(ubi, &req);
if (err) if (err)
break; break;
req.name[req.name_len] = '\0';
mutex_lock(&ubi->volumes_mutex); mutex_lock(&ubi->volumes_mutex);
err = ubi_create_volume(ubi, &req); err = ubi_create_volume(ubi, &req);
mutex_unlock(&ubi->volumes_mutex); mutex_unlock(&ubi->volumes_mutex);
...@@ -652,7 +816,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, ...@@ -652,7 +816,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
{ {
int vol_id; int vol_id;
dbg_msg("remove volume"); dbg_gen("remove volume");
err = get_user(vol_id, (__user int32_t *)argp); err = get_user(vol_id, (__user int32_t *)argp);
if (err) { if (err) {
err = -EFAULT; err = -EFAULT;
...@@ -666,7 +830,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, ...@@ -666,7 +830,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
} }
mutex_lock(&ubi->volumes_mutex); mutex_lock(&ubi->volumes_mutex);
err = ubi_remove_volume(desc); err = ubi_remove_volume(desc, 0);
mutex_unlock(&ubi->volumes_mutex); mutex_unlock(&ubi->volumes_mutex);
/* /*
...@@ -685,7 +849,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, ...@@ -685,7 +849,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
uint64_t tmp; uint64_t tmp;
struct ubi_rsvol_req req; struct ubi_rsvol_req req;
dbg_msg("re-size volume"); dbg_gen("re-size volume");
err = copy_from_user(&req, argp, sizeof(struct ubi_rsvol_req)); err = copy_from_user(&req, argp, sizeof(struct ubi_rsvol_req));
if (err) { if (err) {
err = -EFAULT; err = -EFAULT;
...@@ -713,6 +877,32 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, ...@@ -713,6 +877,32 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
break; break;
} }
/* Re-name volumes command */
case UBI_IOCRNVOL:
{
struct ubi_rnvol_req *req;
dbg_msg("re-name volumes");
req = kmalloc(sizeof(struct ubi_rnvol_req), GFP_KERNEL);
if (!req) {
err = -ENOMEM;
break;
};
err = copy_from_user(req, argp, sizeof(struct ubi_rnvol_req));
if (err) {
err = -EFAULT;
kfree(req);
break;
}
mutex_lock(&ubi->mult_mutex);
err = rename_volumes(ubi, req);
mutex_unlock(&ubi->mult_mutex);
kfree(req);
break;
}
default: default:
err = -ENOTTY; err = -ENOTTY;
break; break;
...@@ -738,7 +928,7 @@ static int ctrl_cdev_ioctl(struct inode *inode, struct file *file, ...@@ -738,7 +928,7 @@ static int ctrl_cdev_ioctl(struct inode *inode, struct file *file,
struct ubi_attach_req req; struct ubi_attach_req req;
struct mtd_info *mtd; struct mtd_info *mtd;
dbg_msg("attach MTD device"); dbg_gen("attach MTD device");
err = copy_from_user(&req, argp, sizeof(struct ubi_attach_req)); err = copy_from_user(&req, argp, sizeof(struct ubi_attach_req));
if (err) { if (err) {
err = -EFAULT; err = -EFAULT;
...@@ -778,7 +968,7 @@ static int ctrl_cdev_ioctl(struct inode *inode, struct file *file, ...@@ -778,7 +968,7 @@ static int ctrl_cdev_ioctl(struct inode *inode, struct file *file,
{ {
int ubi_num; int ubi_num;
dbg_msg("dettach MTD device"); dbg_gen("dettach MTD device");
err = get_user(ubi_num, (__user int32_t *)argp); err = get_user(ubi_num, (__user int32_t *)argp);
if (err) { if (err) {
err = -EFAULT; err = -EFAULT;
......
...@@ -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)
......
...@@ -19,9 +19,9 @@ ...@@ -19,9 +19,9 @@
*/ */
/* /*
* UBI scanning unit. * UBI scanning sub-system.
* *
* This unit is responsible for scanning the flash media, checking UBI * This sub-system is responsible for scanning the flash media, checking UBI
* headers and providing complete information about the UBI flash image. * headers and providing complete information about the UBI flash image.
* *
* The scanning information is represented by a &struct ubi_scan_info' object. * The scanning information is represented by a &struct ubi_scan_info' object.
...@@ -93,8 +93,7 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, ...@@ -93,8 +93,7 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
} }
/** /**
* validate_vid_hdr - check that volume identifier header is correct and * validate_vid_hdr - check volume identifier header.
* consistent.
* @vid_hdr: the volume identifier header to check * @vid_hdr: the volume identifier header to check
* @sv: information about the volume this logical eraseblock belongs to * @sv: information about the volume this logical eraseblock belongs to
* @pnum: physical eraseblock number the VID header came from * @pnum: physical eraseblock number the VID header came from
...@@ -103,7 +102,7 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, ...@@ -103,7 +102,7 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
* non-zero if an inconsistency was found and zero if not. * non-zero if an inconsistency was found and zero if not.
* *
* Note, UBI does sanity check of everything it reads from the flash media. * Note, UBI does sanity check of everything it reads from the flash media.
* Most of the checks are done in the I/O unit. Here we check that the * Most of the checks are done in the I/O sub-system. Here we check that the
* information in the VID header is consistent to the information in other VID * information in the VID header is consistent to the information in other VID
* headers of the same volume. * headers of the same volume.
*/ */
...@@ -247,45 +246,21 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb, ...@@ -247,45 +246,21 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
struct ubi_vid_hdr *vh = NULL; struct ubi_vid_hdr *vh = NULL;
unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum); unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
if (seb->sqnum == 0 && sqnum2 == 0) { if (sqnum2 == seb->sqnum) {
long long abs, v1 = seb->leb_ver, v2 = be32_to_cpu(vid_hdr->leb_ver);
/* /*
* UBI constantly increases the logical eraseblock version * This must be a really ancient UBI image which has been
* number and it can overflow. Thus, we have to bear in mind * created before sequence numbers support has been added. At
* that versions that are close to %0xFFFFFFFF are less then * that times we used 32-bit LEB versions stored in logical
* versions that are close to %0. * eraseblocks. That was before UBI got into mainline. We do not
* * support these images anymore. Well, those images will work
* The UBI WL unit guarantees that the number of pending tasks * still work, but only if no unclean reboots happened.
* is not greater then %0x7FFFFFFF. So, if the difference
* between any two versions is greater or equivalent to
* %0x7FFFFFFF, there was an overflow and the logical
* eraseblock with lower version is actually newer then the one
* with higher version.
*
* FIXME: but this is anyway obsolete and will be removed at
* some point.
*/ */
dbg_bld("using old crappy leb_ver stuff"); ubi_err("unsupported on-flash UBI format\n");
return -EINVAL;
if (v1 == v2) { }
ubi_err("PEB %d and PEB %d have the same version %lld",
seb->pnum, pnum, v1);
return -EINVAL;
}
abs = v1 - v2;
if (abs < 0)
abs = -abs;
if (abs < 0x7FFFFFFF) /* Obviously the LEB with lower sequence counter is older */
/* Non-overflow situation */ second_is_newer = !!(sqnum2 > seb->sqnum);
second_is_newer = (v2 > v1);
else
second_is_newer = (v2 < v1);
} else
/* Obviously the LEB with lower sequence counter is older */
second_is_newer = sqnum2 > seb->sqnum;
/* /*
* Now we know which copy is newer. If the copy flag of the PEB with * Now we know which copy is newer. If the copy flag of the PEB with
...@@ -293,7 +268,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb, ...@@ -293,7 +268,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
* check data CRC. For the second PEB we already have the VID header, * check data CRC. For the second PEB we already have the VID header,
* for the first one - we'll need to re-read it from flash. * for the first one - we'll need to re-read it from flash.
* *
* FIXME: this may be optimized so that we wouldn't read twice. * Note: this may be optimized so that we wouldn't read twice.
*/ */
if (second_is_newer) { if (second_is_newer) {
...@@ -379,8 +354,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb, ...@@ -379,8 +354,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
} }
/** /**
* ubi_scan_add_used - add information about a physical eraseblock to the * ubi_scan_add_used - add physical eraseblock to the scanning information.
* scanning information.
* @ubi: UBI device description object * @ubi: UBI device description object
* @si: scanning information * @si: scanning information
* @pnum: the physical eraseblock number * @pnum: the physical eraseblock number
...@@ -400,7 +374,6 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, ...@@ -400,7 +374,6 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
int bitflips) int bitflips)
{ {
int err, vol_id, lnum; int err, vol_id, lnum;
uint32_t leb_ver;
unsigned long long sqnum; unsigned long long sqnum;
struct ubi_scan_volume *sv; struct ubi_scan_volume *sv;
struct ubi_scan_leb *seb; struct ubi_scan_leb *seb;
...@@ -409,10 +382,9 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, ...@@ -409,10 +382,9 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
vol_id = be32_to_cpu(vid_hdr->vol_id); vol_id = be32_to_cpu(vid_hdr->vol_id);
lnum = be32_to_cpu(vid_hdr->lnum); lnum = be32_to_cpu(vid_hdr->lnum);
sqnum = be64_to_cpu(vid_hdr->sqnum); sqnum = be64_to_cpu(vid_hdr->sqnum);
leb_ver = be32_to_cpu(vid_hdr->leb_ver);
dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, ver %u, bitflips %d", dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, bitflips %d",
pnum, vol_id, lnum, ec, sqnum, leb_ver, bitflips); pnum, vol_id, lnum, ec, sqnum, bitflips);
sv = add_volume(si, vol_id, pnum, vid_hdr); sv = add_volume(si, vol_id, pnum, vid_hdr);
if (IS_ERR(sv) < 0) if (IS_ERR(sv) < 0)
...@@ -445,25 +417,20 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, ...@@ -445,25 +417,20 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
*/ */
dbg_bld("this LEB already exists: PEB %d, sqnum %llu, " dbg_bld("this LEB already exists: PEB %d, sqnum %llu, "
"LEB ver %u, EC %d", seb->pnum, seb->sqnum, "EC %d", seb->pnum, seb->sqnum, seb->ec);
seb->leb_ver, seb->ec);
/*
* Make sure that the logical eraseblocks have different
* versions. Otherwise the image is bad.
*/
if (seb->leb_ver == leb_ver && leb_ver != 0) {
ubi_err("two LEBs with same version %u", leb_ver);
ubi_dbg_dump_seb(seb, 0);
ubi_dbg_dump_vid_hdr(vid_hdr);
return -EINVAL;
}
/* /*
* Make sure that the logical eraseblocks have different * Make sure that the logical eraseblocks have different
* sequence numbers. Otherwise the image is bad. * sequence numbers. Otherwise the image is bad.
* *
* FIXME: remove 'sqnum != 0' check when leb_ver is removed. * However, if the sequence number is zero, we assume it must
* be an ancient UBI image from the era when UBI did not have
* sequence numbers. We still can attach these images, unless
* there is a need to distinguish between old and new
* eraseblocks, in which case we'll refuse the image in
* 'compare_lebs()'. In other words, we attach old clean
* images, but refuse attaching old images with duplicated
* logical eraseblocks because there was an unclean reboot.
*/ */
if (seb->sqnum == sqnum && sqnum != 0) { if (seb->sqnum == sqnum && sqnum != 0) {
ubi_err("two LEBs with same sequence number %llu", ubi_err("two LEBs with same sequence number %llu",
...@@ -503,7 +470,6 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, ...@@ -503,7 +470,6 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
seb->pnum = pnum; seb->pnum = pnum;
seb->scrub = ((cmp_res & 2) || bitflips); seb->scrub = ((cmp_res & 2) || bitflips);
seb->sqnum = sqnum; seb->sqnum = sqnum;
seb->leb_ver = leb_ver;
if (sv->highest_lnum == lnum) if (sv->highest_lnum == lnum)
sv->last_data_size = sv->last_data_size =
...@@ -540,7 +506,6 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, ...@@ -540,7 +506,6 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
seb->lnum = lnum; seb->lnum = lnum;
seb->sqnum = sqnum; seb->sqnum = sqnum;
seb->scrub = bitflips; seb->scrub = bitflips;
seb->leb_ver = leb_ver;
if (sv->highest_lnum <= lnum) { if (sv->highest_lnum <= lnum) {
sv->highest_lnum = lnum; sv->highest_lnum = lnum;
...@@ -554,8 +519,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, ...@@ -554,8 +519,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
} }
/** /**
* ubi_scan_find_sv - find information about a particular volume in the * ubi_scan_find_sv - find volume in the scanning information.
* scanning information.
* @si: scanning information * @si: scanning information
* @vol_id: the requested volume ID * @vol_id: the requested volume ID
* *
...@@ -584,8 +548,7 @@ struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si, ...@@ -584,8 +548,7 @@ struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
} }
/** /**
* ubi_scan_find_seb - find information about a particular logical * ubi_scan_find_seb - find LEB in the volume scanning information.
* eraseblock in the volume scanning information.
* @sv: a pointer to the volume scanning information * @sv: a pointer to the volume scanning information
* @lnum: the requested logical eraseblock * @lnum: the requested logical eraseblock
* *
...@@ -645,9 +608,9 @@ void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv) ...@@ -645,9 +608,9 @@ void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
* *
* This function erases physical eraseblock 'pnum', and writes the erase * This function erases physical eraseblock 'pnum', and writes the erase
* counter header to it. This function should only be used on UBI device * counter header to it. This function should only be used on UBI device
* initialization stages, when the EBA unit had not been yet initialized. This * initialization stages, when the EBA sub-system had not been yet initialized.
* function returns zero in case of success and a negative error code in case * This function returns zero in case of success and a negative error code in
* of failure. * case of failure.
*/ */
int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si, int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
int pnum, int ec) int pnum, int ec)
...@@ -687,9 +650,10 @@ int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si, ...@@ -687,9 +650,10 @@ int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
* @si: scanning information * @si: scanning information
* *
* This function returns a free physical eraseblock. It is supposed to be * This function returns a free physical eraseblock. It is supposed to be
* called on the UBI initialization stages when the wear-leveling unit is not * called on the UBI initialization stages when the wear-leveling sub-system is
* initialized yet. This function picks a physical eraseblocks from one of the * not initialized yet. This function picks a physical eraseblocks from one of
* lists, writes the EC header if it is needed, and removes it from the list. * the lists, writes the EC header if it is needed, and removes it from the
* list.
* *
* This function returns scanning physical eraseblock information in case of * This function returns scanning physical eraseblock information in case of
* success and an error code in case of failure. * success and an error code in case of failure.
...@@ -742,8 +706,7 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi, ...@@ -742,8 +706,7 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
} }
/** /**
* process_eb - read UBI headers, check them and add corresponding data * process_eb - read, check UBI headers, and add them to scanning information.
* to the scanning information.
* @ubi: UBI device description object * @ubi: UBI device description object
* @si: scanning information * @si: scanning information
* @pnum: the physical eraseblock number * @pnum: the physical eraseblock number
...@@ -751,7 +714,8 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi, ...@@ -751,7 +714,8 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
* This function returns a zero if the physical eraseblock was successfully * This function returns a zero if the physical eraseblock was successfully
* handled and a negative error code in case of failure. * handled and a negative error code in case of failure.
*/ */
static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum) static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
int pnum)
{ {
long long uninitialized_var(ec); long long uninitialized_var(ec);
int err, bitflips = 0, vol_id, ec_corr = 0; int err, bitflips = 0, vol_id, ec_corr = 0;
...@@ -764,8 +728,9 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum ...@@ -764,8 +728,9 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
return err; return err;
else if (err) { else if (err) {
/* /*
* FIXME: this is actually duty of the I/O unit to initialize * FIXME: this is actually duty of the I/O sub-system to
* this, but MTD does not provide enough information. * initialize this, but MTD does not provide enough
* information.
*/ */
si->bad_peb_count += 1; si->bad_peb_count += 1;
return 0; return 0;
...@@ -930,7 +895,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) ...@@ -930,7 +895,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
for (pnum = 0; pnum < ubi->peb_count; pnum++) { for (pnum = 0; pnum < ubi->peb_count; pnum++) {
cond_resched(); cond_resched();
dbg_msg("process PEB %d", pnum); dbg_gen("process PEB %d", pnum);
err = process_eb(ubi, si, pnum); err = process_eb(ubi, si, pnum);
if (err < 0) if (err < 0)
goto out_vidh; goto out_vidh;
...@@ -1079,8 +1044,7 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si) ...@@ -1079,8 +1044,7 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
/** /**
* paranoid_check_si - check if the scanning information is correct and * paranoid_check_si - check the scanning information.
* consistent.
* @ubi: UBI device description object * @ubi: UBI device description object
* @si: scanning information * @si: scanning information
* *
...@@ -1265,11 +1229,6 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si) ...@@ -1265,11 +1229,6 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
ubi_err("bad data_pad %d", sv->data_pad); ubi_err("bad data_pad %d", sv->data_pad);
goto bad_vid_hdr; goto bad_vid_hdr;
} }
if (seb->leb_ver != be32_to_cpu(vidh->leb_ver)) {
ubi_err("bad leb_ver %u", seb->leb_ver);
goto bad_vid_hdr;
}
} }
if (!last_seb) if (!last_seb)
...@@ -1299,8 +1258,7 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si) ...@@ -1299,8 +1258,7 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
if (err < 0) { if (err < 0) {
kfree(buf); kfree(buf);
return err; return err;
} } else if (err)
else if (err)
buf[pnum] = 1; buf[pnum] = 1;
} }
......
...@@ -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);
......
...@@ -28,9 +28,9 @@ ...@@ -28,9 +28,9 @@
#include "ubi.h" #include "ubi.h"
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
static void paranoid_check_volumes(struct ubi_device *ubi); static int paranoid_check_volumes(struct ubi_device *ubi);
#else #else
#define paranoid_check_volumes(ubi) #define paranoid_check_volumes(ubi) 0
#endif #endif
static ssize_t vol_attribute_show(struct device *dev, static ssize_t vol_attribute_show(struct device *dev,
...@@ -127,6 +127,7 @@ static void vol_release(struct device *dev) ...@@ -127,6 +127,7 @@ static void vol_release(struct device *dev)
{ {
struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
kfree(vol->eba_tbl);
kfree(vol); kfree(vol);
} }
...@@ -201,7 +202,7 @@ static void volume_sysfs_close(struct ubi_volume *vol) ...@@ -201,7 +202,7 @@ static void volume_sysfs_close(struct ubi_volume *vol)
*/ */
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 i, err, vol_id = req->vol_id, dont_free = 0; int i, err, vol_id = req->vol_id, do_free = 1;
struct ubi_volume *vol; struct ubi_volume *vol;
struct ubi_vtbl_record vtbl_rec; struct ubi_vtbl_record vtbl_rec;
uint64_t bytes; uint64_t bytes;
...@@ -217,7 +218,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) ...@@ -217,7 +218,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
spin_lock(&ubi->volumes_lock); spin_lock(&ubi->volumes_lock);
if (vol_id == UBI_VOL_NUM_AUTO) { if (vol_id == UBI_VOL_NUM_AUTO) {
/* Find unused volume ID */ /* Find unused volume ID */
dbg_msg("search for vacant volume ID"); dbg_gen("search for vacant volume ID");
for (i = 0; i < ubi->vtbl_slots; i++) for (i = 0; i < ubi->vtbl_slots; i++)
if (!ubi->volumes[i]) { if (!ubi->volumes[i]) {
vol_id = i; vol_id = i;
...@@ -232,7 +233,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) ...@@ -232,7 +233,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
req->vol_id = vol_id; req->vol_id = vol_id;
} }
dbg_msg("volume ID %d, %llu bytes, type %d, name %s", dbg_gen("volume ID %d, %llu bytes, type %d, name %s",
vol_id, (unsigned long long)req->bytes, vol_id, (unsigned long long)req->bytes,
(int)req->vol_type, req->name); (int)req->vol_type, req->name);
...@@ -252,7 +253,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) ...@@ -252,7 +253,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
goto out_unlock; goto out_unlock;
} }
/* Calculate how many eraseblocks are requested */ /* Calculate how many eraseblocks are requested */
vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment; vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment;
bytes = req->bytes; bytes = req->bytes;
if (do_div(bytes, vol->usable_leb_size)) if (do_div(bytes, vol->usable_leb_size))
...@@ -274,7 +275,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) ...@@ -274,7 +275,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
vol->data_pad = ubi->leb_size % vol->alignment; vol->data_pad = ubi->leb_size % vol->alignment;
vol->vol_type = req->vol_type; vol->vol_type = req->vol_type;
vol->name_len = req->name_len; vol->name_len = req->name_len;
memcpy(vol->name, req->name, vol->name_len + 1); memcpy(vol->name, req->name, vol->name_len);
vol->ubi = ubi; vol->ubi = ubi;
/* /*
...@@ -349,7 +350,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) ...@@ -349,7 +350,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
vtbl_rec.vol_type = UBI_VID_DYNAMIC; vtbl_rec.vol_type = UBI_VID_DYNAMIC;
else else
vtbl_rec.vol_type = UBI_VID_STATIC; vtbl_rec.vol_type = UBI_VID_STATIC;
memcpy(vtbl_rec.name, vol->name, vol->name_len + 1); memcpy(vtbl_rec.name, vol->name, vol->name_len);
err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
if (err) if (err)
...@@ -360,19 +361,19 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) ...@@ -360,19 +361,19 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
ubi->vol_count += 1; ubi->vol_count += 1;
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
paranoid_check_volumes(ubi); err = paranoid_check_volumes(ubi);
return 0; return err;
out_sysfs: out_sysfs:
/* /*
* We have registered our device, we should not free the volume* * We have registered our device, we should not free the volume
* description object in this function in case of an error - it is * description object in this function in case of an error - it is
* freed by the release function. * freed by the release function.
* *
* Get device reference to prevent the release function from being * Get device reference to prevent the release function from being
* called just after sysfs has been closed. * called just after sysfs has been closed.
*/ */
dont_free = 1; do_free = 0;
get_device(&vol->dev); get_device(&vol->dev);
volume_sysfs_close(vol); volume_sysfs_close(vol);
out_gluebi: out_gluebi:
...@@ -382,17 +383,18 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) ...@@ -382,17 +383,18 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
out_cdev: out_cdev:
cdev_del(&vol->cdev); cdev_del(&vol->cdev);
out_mapping: out_mapping:
kfree(vol->eba_tbl); if (do_free)
kfree(vol->eba_tbl);
out_acc: out_acc:
spin_lock(&ubi->volumes_lock); spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs -= vol->reserved_pebs; ubi->rsvd_pebs -= vol->reserved_pebs;
ubi->avail_pebs += vol->reserved_pebs; ubi->avail_pebs += vol->reserved_pebs;
out_unlock: out_unlock:
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
if (dont_free) if (do_free)
put_device(&vol->dev);
else
kfree(vol); kfree(vol);
else
put_device(&vol->dev);
ubi_err("cannot create volume %d, error %d", vol_id, err); ubi_err("cannot create volume %d, error %d", vol_id, err);
return err; return err;
} }
...@@ -400,19 +402,20 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) ...@@ -400,19 +402,20 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
/** /**
* ubi_remove_volume - remove volume. * ubi_remove_volume - remove volume.
* @desc: volume descriptor * @desc: volume descriptor
* @no_vtbl: do not change volume table if not zero
* *
* This function removes volume described by @desc. The volume has to be opened * This function removes volume described by @desc. The volume has to be opened
* in "exclusive" mode. Returns zero in case of success and a negative error * in "exclusive" mode. Returns zero in case of success and a negative error
* code in case of failure. The caller has to have the @ubi->volumes_mutex * code in case of failure. The caller has to have the @ubi->volumes_mutex
* locked. * locked.
*/ */
int ubi_remove_volume(struct ubi_volume_desc *desc) int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
{ {
struct ubi_volume *vol = desc->vol; struct ubi_volume *vol = desc->vol;
struct ubi_device *ubi = vol->ubi; struct ubi_device *ubi = vol->ubi;
int i, err, vol_id = vol->vol_id, reserved_pebs = vol->reserved_pebs; int i, err, vol_id = vol->vol_id, reserved_pebs = vol->reserved_pebs;
dbg_msg("remove UBI volume %d", vol_id); dbg_gen("remove UBI volume %d", vol_id);
ubi_assert(desc->mode == UBI_EXCLUSIVE); ubi_assert(desc->mode == UBI_EXCLUSIVE);
ubi_assert(vol == ubi->volumes[vol_id]); ubi_assert(vol == ubi->volumes[vol_id]);
...@@ -435,9 +438,11 @@ int ubi_remove_volume(struct ubi_volume_desc *desc) ...@@ -435,9 +438,11 @@ int ubi_remove_volume(struct ubi_volume_desc *desc)
if (err) if (err)
goto out_err; goto out_err;
err = ubi_change_vtbl_record(ubi, vol_id, NULL); if (!no_vtbl) {
if (err) err = ubi_change_vtbl_record(ubi, vol_id, NULL);
goto out_err; if (err)
goto out_err;
}
for (i = 0; i < vol->reserved_pebs; i++) { for (i = 0; i < vol->reserved_pebs; i++) {
err = ubi_eba_unmap_leb(ubi, vol, i); err = ubi_eba_unmap_leb(ubi, vol, i);
...@@ -445,8 +450,6 @@ int ubi_remove_volume(struct ubi_volume_desc *desc) ...@@ -445,8 +450,6 @@ int ubi_remove_volume(struct ubi_volume_desc *desc)
goto out_err; goto out_err;
} }
kfree(vol->eba_tbl);
vol->eba_tbl = NULL;
cdev_del(&vol->cdev); cdev_del(&vol->cdev);
volume_sysfs_close(vol); volume_sysfs_close(vol);
...@@ -465,8 +468,9 @@ int ubi_remove_volume(struct ubi_volume_desc *desc) ...@@ -465,8 +468,9 @@ int ubi_remove_volume(struct ubi_volume_desc *desc)
ubi->vol_count -= 1; ubi->vol_count -= 1;
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
paranoid_check_volumes(ubi); if (!no_vtbl)
return 0; err = paranoid_check_volumes(ubi);
return err;
out_err: out_err:
ubi_err("cannot remove volume %d, error %d", vol_id, err); ubi_err("cannot remove volume %d, error %d", vol_id, err);
...@@ -497,7 +501,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) ...@@ -497,7 +501,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
if (ubi->ro_mode) if (ubi->ro_mode)
return -EROFS; return -EROFS;
dbg_msg("re-size volume %d to from %d to %d PEBs", dbg_gen("re-size volume %d to from %d to %d PEBs",
vol_id, vol->reserved_pebs, reserved_pebs); vol_id, vol->reserved_pebs, reserved_pebs);
if (vol->vol_type == UBI_STATIC_VOLUME && if (vol->vol_type == UBI_STATIC_VOLUME &&
...@@ -586,8 +590,8 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) ...@@ -586,8 +590,8 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
(long long)vol->used_ebs * vol->usable_leb_size; (long long)vol->used_ebs * vol->usable_leb_size;
} }
paranoid_check_volumes(ubi); err = paranoid_check_volumes(ubi);
return 0; return err;
out_acc: out_acc:
if (pebs > 0) { if (pebs > 0) {
...@@ -601,6 +605,44 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) ...@@ -601,6 +605,44 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
return err; return err;
} }
/**
* ubi_rename_volumes - re-name UBI volumes.
* @ubi: UBI device description object
* @rename_list: list of &struct ubi_rename_entry objects
*
* This function re-names or removes volumes specified in the re-name list.
* Returns zero in case of success and a negative error code in case of
* failure.
*/
int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list)
{
int err;
struct ubi_rename_entry *re;
err = ubi_vtbl_rename_volumes(ubi, rename_list);
if (err)
return err;
list_for_each_entry(re, rename_list, list) {
if (re->remove) {
err = ubi_remove_volume(re->desc, 1);
if (err)
break;
} else {
struct ubi_volume *vol = re->desc->vol;
spin_lock(&ubi->volumes_lock);
vol->name_len = re->new_name_len;
memcpy(vol->name, re->new_name, re->new_name_len + 1);
spin_unlock(&ubi->volumes_lock);
}
}
if (!err)
err = paranoid_check_volumes(ubi);
return err;
}
/** /**
* ubi_add_volume - add volume. * ubi_add_volume - add volume.
* @ubi: UBI device description object * @ubi: UBI device description object
...@@ -615,8 +657,7 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) ...@@ -615,8 +657,7 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
int err, vol_id = vol->vol_id; int err, vol_id = vol->vol_id;
dev_t dev; dev_t dev;
dbg_msg("add volume %d", vol_id); dbg_gen("add volume %d", vol_id);
ubi_dbg_dump_vol_info(vol);
/* Register character device for the volume */ /* Register character device for the volume */
cdev_init(&vol->cdev, &ubi_vol_cdev_operations); cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
...@@ -650,8 +691,8 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) ...@@ -650,8 +691,8 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
return err; return err;
} }
paranoid_check_volumes(ubi); err = paranoid_check_volumes(ubi);
return 0; return err;
out_gluebi: out_gluebi:
err = ubi_destroy_gluebi(vol); err = ubi_destroy_gluebi(vol);
...@@ -672,7 +713,7 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol) ...@@ -672,7 +713,7 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
{ {
int err; int err;
dbg_msg("free volume %d", vol->vol_id); dbg_gen("free volume %d", vol->vol_id);
ubi->volumes[vol->vol_id] = NULL; ubi->volumes[vol->vol_id] = NULL;
err = ubi_destroy_gluebi(vol); err = ubi_destroy_gluebi(vol);
...@@ -686,8 +727,10 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol) ...@@ -686,8 +727,10 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
* paranoid_check_volume - check volume information. * paranoid_check_volume - check volume information.
* @ubi: UBI device description object * @ubi: UBI device description object
* @vol_id: volume ID * @vol_id: volume ID
*
* Returns zero if volume is all right and a a negative error code if not.
*/ */
static void paranoid_check_volume(struct ubi_device *ubi, int vol_id) static int paranoid_check_volume(struct ubi_device *ubi, int vol_id)
{ {
int idx = vol_id2idx(ubi, vol_id); int idx = vol_id2idx(ubi, vol_id);
int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker; int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker;
...@@ -705,16 +748,7 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id) ...@@ -705,16 +748,7 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
goto fail; goto fail;
} }
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
return; return 0;
}
if (vol->exclusive) {
/*
* The volume may be being created at the moment, do not check
* it (e.g., it may be in the middle of ubi_create_volume().
*/
spin_unlock(&ubi->volumes_lock);
return;
} }
if (vol->reserved_pebs < 0 || vol->alignment < 0 || vol->data_pad < 0 || if (vol->reserved_pebs < 0 || vol->alignment < 0 || vol->data_pad < 0 ||
...@@ -727,7 +761,7 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id) ...@@ -727,7 +761,7 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
goto fail; goto fail;
} }
n = vol->alignment % ubi->min_io_size; n = vol->alignment & (ubi->min_io_size - 1);
if (vol->alignment != 1 && n) { if (vol->alignment != 1 && n) {
ubi_err("alignment is not multiple of min I/O unit"); ubi_err("alignment is not multiple of min I/O unit");
goto fail; goto fail;
...@@ -824,31 +858,39 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id) ...@@ -824,31 +858,39 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
if (alignment != vol->alignment || data_pad != vol->data_pad || if (alignment != vol->alignment || data_pad != vol->data_pad ||
upd_marker != vol->upd_marker || vol_type != vol->vol_type || upd_marker != vol->upd_marker || vol_type != vol->vol_type ||
name_len!= vol->name_len || strncmp(name, vol->name, name_len)) { name_len != vol->name_len || strncmp(name, vol->name, name_len)) {
ubi_err("volume info is different"); ubi_err("volume info is different");
goto fail; goto fail;
} }
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
return; return 0;
fail: fail:
ubi_err("paranoid check failed for volume %d", vol_id); ubi_err("paranoid check failed for volume %d", vol_id);
ubi_dbg_dump_vol_info(vol); if (vol)
ubi_dbg_dump_vol_info(vol);
ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id); ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
BUG(); return -EINVAL;
} }
/** /**
* paranoid_check_volumes - check information about all volumes. * paranoid_check_volumes - check information about all volumes.
* @ubi: UBI device description object * @ubi: UBI device description object
*
* Returns zero if volumes are all right and a a negative error code if not.
*/ */
static void paranoid_check_volumes(struct ubi_device *ubi) static int paranoid_check_volumes(struct ubi_device *ubi)
{ {
int i; int i, err = 0;
for (i = 0; i < ubi->vtbl_slots; i++) for (i = 0; i < ubi->vtbl_slots; i++) {
paranoid_check_volume(ubi, i); err = paranoid_check_volume(ubi, i);
if (err)
break;
}
return err;
} }
#endif #endif
...@@ -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;
} }
......
...@@ -19,22 +19,22 @@ ...@@ -19,22 +19,22 @@
*/ */
/* /*
* UBI wear-leveling unit. * UBI wear-leveling sub-system.
* *
* This unit is responsible for wear-leveling. It works in terms of physical * This sub-system is responsible for wear-leveling. It works in terms of
* eraseblocks and erase counters and knows nothing about logical eraseblocks, * physical* eraseblocks and erase counters and knows nothing about logical
* volumes, etc. From this unit's perspective all physical eraseblocks are of * eraseblocks, volumes, etc. From this sub-system's perspective all physical
* two types - used and free. Used physical eraseblocks are those that were * eraseblocks are of two types - used and free. Used physical eraseblocks are
* "get" by the 'ubi_wl_get_peb()' function, and free physical eraseblocks are * those that were "get" by the 'ubi_wl_get_peb()' function, and free physical
* those that were put by the 'ubi_wl_put_peb()' function. * eraseblocks are those that were put by the 'ubi_wl_put_peb()' function.
* *
* Physical eraseblocks returned by 'ubi_wl_get_peb()' have only erase counter * Physical eraseblocks returned by 'ubi_wl_get_peb()' have only erase counter
* header. The rest of the physical eraseblock contains only 0xFF bytes. * header. The rest of the physical eraseblock contains only %0xFF bytes.
* *
* When physical eraseblocks are returned to the WL unit by means of the * When physical eraseblocks are returned to the WL sub-system by means of the
* 'ubi_wl_put_peb()' function, they are scheduled for erasure. The erasure is * 'ubi_wl_put_peb()' function, they are scheduled for erasure. The erasure is
* done asynchronously in context of the per-UBI device background thread, * done asynchronously in context of the per-UBI device background thread,
* which is also managed by the WL unit. * which is also managed by the WL sub-system.
* *
* The wear-leveling is ensured by means of moving the contents of used * The wear-leveling is ensured by means of moving the contents of used
* physical eraseblocks with low erase counter to free physical eraseblocks * physical eraseblocks with low erase counter to free physical eraseblocks
...@@ -43,34 +43,36 @@ ...@@ -43,34 +43,36 @@
* The 'ubi_wl_get_peb()' function accepts data type hints which help to pick * The 'ubi_wl_get_peb()' function accepts data type hints which help to pick
* an "optimal" physical eraseblock. For example, when it is known that the * an "optimal" physical eraseblock. For example, when it is known that the
* physical eraseblock will be "put" soon because it contains short-term data, * physical eraseblock will be "put" soon because it contains short-term data,
* the WL unit may pick a free physical eraseblock with low erase counter, and * the WL sub-system may pick a free physical eraseblock with low erase
* so forth. * counter, and so forth.
* *
* If the WL unit fails to erase a physical eraseblock, it marks it as bad. * If the WL sub-system fails to erase a physical eraseblock, it marks it as
* bad.
* *
* This unit is also responsible for scrubbing. If a bit-flip is detected in a * This sub-system is also responsible for scrubbing. If a bit-flip is detected
* physical eraseblock, it has to be moved. Technically this is the same as * in a physical eraseblock, it has to be moved. Technically this is the same
* moving it for wear-leveling reasons. * as moving it for wear-leveling reasons.
* *
* As it was said, for the UBI unit all physical eraseblocks are either "free" * As it was said, for the UBI sub-system all physical eraseblocks are either
* or "used". Free eraseblock are kept in the @wl->free RB-tree, while used * "free" or "used". Free eraseblock are kept in the @wl->free RB-tree, while
* eraseblocks are kept in a set of different RB-trees: @wl->used, * used eraseblocks are kept in a set of different RB-trees: @wl->used,
* @wl->prot.pnum, @wl->prot.aec, and @wl->scrub. * @wl->prot.pnum, @wl->prot.aec, and @wl->scrub.
* *
* Note, in this implementation, we keep a small in-RAM object for each physical * Note, in this implementation, we keep a small in-RAM object for each physical
* eraseblock. This is surely not a scalable solution. But it appears to be good * eraseblock. This is surely not a scalable solution. But it appears to be good
* enough for moderately large flashes and it is simple. In future, one may * enough for moderately large flashes and it is simple. In future, one may
* re-work this unit and make it more scalable. * re-work this sub-system and make it more scalable.
* *
* At the moment this unit does not utilize the sequence number, which was * At the moment this sub-system does not utilize the sequence number, which
* introduced relatively recently. But it would be wise to do this because the * was introduced relatively recently. But it would be wise to do this because
* sequence number of a logical eraseblock characterizes how old is it. For * the sequence number of a logical eraseblock characterizes how old is it. For
* example, when we move a PEB with low erase counter, and we need to pick the * example, when we move a PEB with low erase counter, and we need to pick the
* target PEB, we pick a PEB with the highest EC if our PEB is "old" and we * target PEB, we pick a PEB with the highest EC if our PEB is "old" and we
* pick target PEB with an average EC if our PEB is not very "old". This is a * pick target PEB with an average EC if our PEB is not very "old". This is a
* room for future re-works of the WL unit. * room for future re-works of the WL sub-system.
* *
* FIXME: looks too complex, should be simplified (later). * Note: the stuff with protection trees looks too complex and is difficult to
* understand. Should be fixed.
*/ */
#include <linux/slab.h> #include <linux/slab.h>
...@@ -92,20 +94,21 @@ ...@@ -92,20 +94,21 @@
/* /*
* Maximum difference between two erase counters. If this threshold is * Maximum difference between two erase counters. If this threshold is
* exceeded, the WL unit starts moving data from used physical eraseblocks with * exceeded, the WL sub-system starts moving data from used physical
* low erase counter to free physical eraseblocks with high erase counter. * eraseblocks with low erase counter to free physical eraseblocks with high
* erase counter.
*/ */
#define UBI_WL_THRESHOLD CONFIG_MTD_UBI_WL_THRESHOLD #define UBI_WL_THRESHOLD CONFIG_MTD_UBI_WL_THRESHOLD
/* /*
* When a physical eraseblock is moved, the WL unit has to pick the target * When a physical eraseblock is moved, the WL sub-system has to pick the target
* physical eraseblock to move to. The simplest way would be just to pick the * physical eraseblock to move to. The simplest way would be just to pick the
* one with the highest erase counter. But in certain workloads this could lead * one with the highest erase counter. But in certain workloads this could lead
* to an unlimited wear of one or few physical eraseblock. Indeed, imagine a * to an unlimited wear of one or few physical eraseblock. Indeed, imagine a
* situation when the picked physical eraseblock is constantly erased after the * situation when the picked physical eraseblock is constantly erased after the
* data is written to it. So, we have a constant which limits the highest erase * data is written to it. So, we have a constant which limits the highest erase
* counter of the free physical eraseblock to pick. Namely, the WL unit does * counter of the free physical eraseblock to pick. Namely, the WL sub-system
* not pick eraseblocks with erase counter greater then the lowest erase * does not pick eraseblocks with erase counter greater then the lowest erase
* counter plus %WL_FREE_MAX_DIFF. * counter plus %WL_FREE_MAX_DIFF.
*/ */
#define WL_FREE_MAX_DIFF (2*UBI_WL_THRESHOLD) #define WL_FREE_MAX_DIFF (2*UBI_WL_THRESHOLD)
...@@ -123,11 +126,11 @@ ...@@ -123,11 +126,11 @@
* @abs_ec: the absolute erase counter value when the protection ends * @abs_ec: the absolute erase counter value when the protection ends
* @e: the wear-leveling entry of the physical eraseblock under protection * @e: the wear-leveling entry of the physical eraseblock under protection
* *
* When the WL unit returns a physical eraseblock, the physical eraseblock is * When the WL sub-system returns a physical eraseblock, the physical
* protected from being moved for some "time". For this reason, the physical * eraseblock is protected from being moved for some "time". For this reason,
* eraseblock is not directly moved from the @wl->free tree to the @wl->used * the physical eraseblock is not directly moved from the @wl->free tree to the
* tree. There is one more tree in between where this physical eraseblock is * @wl->used tree. There is one more tree in between where this physical
* temporarily stored (@wl->prot). * eraseblock is temporarily stored (@wl->prot).
* *
* All this protection stuff is needed because: * All this protection stuff is needed because:
* o we don't want to move physical eraseblocks just after we have given them * o we don't want to move physical eraseblocks just after we have given them
...@@ -175,7 +178,6 @@ struct ubi_wl_prot_entry { ...@@ -175,7 +178,6 @@ struct ubi_wl_prot_entry {
* @list: a link in the list of pending works * @list: a link in the list of pending works
* @func: worker function * @func: worker function
* @priv: private data of the worker function * @priv: private data of the worker function
*
* @e: physical eraseblock to erase * @e: physical eraseblock to erase
* @torture: if the physical eraseblock has to be tortured * @torture: if the physical eraseblock has to be tortured
* *
...@@ -473,52 +475,47 @@ int ubi_wl_get_peb(struct ubi_device *ubi, int dtype) ...@@ -473,52 +475,47 @@ int ubi_wl_get_peb(struct ubi_device *ubi, int dtype)
} }
switch (dtype) { switch (dtype) {
case UBI_LONGTERM: case UBI_LONGTERM:
/* /*
* For long term data we pick a physical eraseblock * For long term data we pick a physical eraseblock with high
* with high erase counter. But the highest erase * erase counter. But the highest erase counter we can pick is
* counter we can pick is bounded by the the lowest * bounded by the the lowest erase counter plus
* erase counter plus %WL_FREE_MAX_DIFF. * %WL_FREE_MAX_DIFF.
*/ */
e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF); e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
protect = LT_PROTECTION; protect = LT_PROTECTION;
break; break;
case UBI_UNKNOWN: case UBI_UNKNOWN:
/* /*
* For unknown data we pick a physical eraseblock with * For unknown data we pick a physical eraseblock with medium
* medium erase counter. But we by no means can pick a * erase counter. But we by no means can pick a physical
* physical eraseblock with erase counter greater or * eraseblock with erase counter greater or equivalent than the
* equivalent than the lowest erase counter plus * lowest erase counter plus %WL_FREE_MAX_DIFF.
* %WL_FREE_MAX_DIFF. */
*/ first = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry, rb);
first = rb_entry(rb_first(&ubi->free), last = rb_entry(rb_last(&ubi->free), struct ubi_wl_entry, rb);
struct ubi_wl_entry, rb);
last = rb_entry(rb_last(&ubi->free),
struct ubi_wl_entry, rb);
if (last->ec - first->ec < WL_FREE_MAX_DIFF) if (last->ec - first->ec < WL_FREE_MAX_DIFF)
e = rb_entry(ubi->free.rb_node, e = rb_entry(ubi->free.rb_node,
struct ubi_wl_entry, rb); struct ubi_wl_entry, rb);
else { else {
medium_ec = (first->ec + WL_FREE_MAX_DIFF)/2; medium_ec = (first->ec + WL_FREE_MAX_DIFF)/2;
e = find_wl_entry(&ubi->free, medium_ec); e = find_wl_entry(&ubi->free, medium_ec);
} }
protect = U_PROTECTION; protect = U_PROTECTION;
break; break;
case UBI_SHORTTERM: case UBI_SHORTTERM:
/* /*
* For short term data we pick a physical eraseblock * For short term data we pick a physical eraseblock with the
* with the lowest erase counter as we expect it will * lowest erase counter as we expect it will be erased soon.
* be erased soon. */
*/ e = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry, rb);
e = rb_entry(rb_first(&ubi->free), protect = ST_PROTECTION;
struct ubi_wl_entry, rb); break;
protect = ST_PROTECTION; default:
break; protect = 0;
default: e = NULL;
protect = 0; BUG();
e = NULL;
BUG();
} }
/* /*
...@@ -582,7 +579,8 @@ static int prot_tree_del(struct ubi_device *ubi, int pnum) ...@@ -582,7 +579,8 @@ static int prot_tree_del(struct ubi_device *ubi, int pnum)
* This function returns zero in case of success and a negative error code in * This function returns zero in case of success and a negative error code in
* case of failure. * case of failure.
*/ */
static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int torture) static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
int torture)
{ {
int err; int err;
struct ubi_ec_hdr *ec_hdr; struct ubi_ec_hdr *ec_hdr;
...@@ -634,8 +632,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int tortur ...@@ -634,8 +632,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int tortur
} }
/** /**
* check_protection_over - check if it is time to stop protecting some * check_protection_over - check if it is time to stop protecting some PEBs.
* physical eraseblocks.
* @ubi: UBI device description object * @ubi: UBI device description object
* *
* This function is called after each erase operation, when the absolute erase * This function is called after each erase operation, when the absolute erase
...@@ -871,6 +868,10 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, ...@@ -871,6 +868,10 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
} }
ubi_free_vid_hdr(ubi, vid_hdr); ubi_free_vid_hdr(ubi, vid_hdr);
if (scrubbing && !protect)
ubi_msg("scrubbed PEB %d, data moved to PEB %d",
e1->pnum, e2->pnum);
spin_lock(&ubi->wl_lock); spin_lock(&ubi->wl_lock);
if (protect) if (protect)
prot_tree_add(ubi, e1, pe, protect); prot_tree_add(ubi, e1, pe, protect);
...@@ -1054,8 +1055,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ...@@ -1054,8 +1055,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
spin_unlock(&ubi->wl_lock); spin_unlock(&ubi->wl_lock);
/* /*
* One more erase operation has happened, take care about protected * One more erase operation has happened, take care about
* physical eraseblocks. * protected physical eraseblocks.
*/ */
check_protection_over(ubi); check_protection_over(ubi);
...@@ -1136,7 +1137,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ...@@ -1136,7 +1137,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
} }
/** /**
* ubi_wl_put_peb - return a physical eraseblock to the wear-leveling unit. * ubi_wl_put_peb - return a PEB to the wear-leveling sub-system.
* @ubi: UBI device description object * @ubi: UBI device description object
* @pnum: physical eraseblock to return * @pnum: physical eraseblock to return
* @torture: if this physical eraseblock has to be tortured * @torture: if this physical eraseblock has to be tortured
...@@ -1175,11 +1176,11 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture) ...@@ -1175,11 +1176,11 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
/* /*
* User is putting the physical eraseblock which was selected * User is putting the physical eraseblock which was selected
* as the target the data is moved to. It may happen if the EBA * as the target the data is moved to. It may happen if the EBA
* unit already re-mapped the LEB in 'ubi_eba_copy_leb()' but * sub-system already re-mapped the LEB in 'ubi_eba_copy_leb()'
* the WL unit has not put the PEB to the "used" tree yet, but * but the WL sub-system has not put the PEB to the "used" tree
* it is about to do this. So we just set a flag which will * yet, but it is about to do this. So we just set a flag which
* tell the WL worker that the PEB is not needed anymore and * will tell the WL worker that the PEB is not needed anymore
* should be scheduled for erasure. * and should be scheduled for erasure.
*/ */
dbg_wl("PEB %d is the target of data moving", pnum); dbg_wl("PEB %d is the target of data moving", pnum);
ubi_assert(!ubi->move_to_put); ubi_assert(!ubi->move_to_put);
...@@ -1229,7 +1230,7 @@ int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum) ...@@ -1229,7 +1230,7 @@ int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum)
{ {
struct ubi_wl_entry *e; struct ubi_wl_entry *e;
ubi_msg("schedule PEB %d for scrubbing", pnum); dbg_msg("schedule PEB %d for scrubbing", pnum);
retry: retry:
spin_lock(&ubi->wl_lock); spin_lock(&ubi->wl_lock);
...@@ -1368,7 +1369,7 @@ int ubi_thread(void *u) ...@@ -1368,7 +1369,7 @@ int ubi_thread(void *u)
int err; int err;
if (kthread_should_stop()) if (kthread_should_stop())
goto out; break;
if (try_to_freeze()) if (try_to_freeze())
continue; continue;
...@@ -1403,7 +1404,6 @@ int ubi_thread(void *u) ...@@ -1403,7 +1404,6 @@ int ubi_thread(void *u)
cond_resched(); cond_resched();
} }
out:
dbg_wl("background thread \"%s\" is killed", ubi->bgt_name); dbg_wl("background thread \"%s\" is killed", ubi->bgt_name);
return 0; return 0;
} }
...@@ -1426,8 +1426,7 @@ static void cancel_pending(struct ubi_device *ubi) ...@@ -1426,8 +1426,7 @@ static void cancel_pending(struct ubi_device *ubi)
} }
/** /**
* ubi_wl_init_scan - initialize the wear-leveling unit using scanning * ubi_wl_init_scan - initialize the WL sub-system using scanning information.
* information.
* @ubi: UBI device description object * @ubi: UBI device description object
* @si: scanning information * @si: scanning information
* *
...@@ -1584,13 +1583,12 @@ static void protection_trees_destroy(struct ubi_device *ubi) ...@@ -1584,13 +1583,12 @@ static void protection_trees_destroy(struct ubi_device *ubi)
} }
/** /**
* ubi_wl_close - close the wear-leveling unit. * ubi_wl_close - close the wear-leveling sub-system.
* @ubi: UBI device description object * @ubi: UBI device description object
*/ */
void ubi_wl_close(struct ubi_device *ubi) void ubi_wl_close(struct ubi_device *ubi)
{ {
dbg_wl("close the UBI wear-leveling unit"); dbg_wl("close the WL sub-system");
cancel_pending(ubi); cancel_pending(ubi);
protection_trees_destroy(ubi); protection_trees_destroy(ubi);
tree_destroy(&ubi->used); tree_destroy(&ubi->used);
...@@ -1602,8 +1600,7 @@ void ubi_wl_close(struct ubi_device *ubi) ...@@ -1602,8 +1600,7 @@ void ubi_wl_close(struct ubi_device *ubi)
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
/** /**
* paranoid_check_ec - make sure that the erase counter of a physical eraseblock * paranoid_check_ec - make sure that the erase counter of a PEB is correct.
* is correct.
* @ubi: UBI device description object * @ubi: UBI device description object
* @pnum: the physical eraseblock number to check * @pnum: the physical eraseblock number to check
* @ec: the erase counter to check * @ec: the erase counter to check
...@@ -1644,13 +1641,12 @@ static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec) ...@@ -1644,13 +1641,12 @@ static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
} }
/** /**
* paranoid_check_in_wl_tree - make sure that a wear-leveling entry is present * paranoid_check_in_wl_tree - check that wear-leveling entry is in WL RB-tree.
* in a WL RB-tree.
* @e: the wear-leveling entry to check * @e: the wear-leveling entry to check
* @root: the root of the tree * @root: the root of the tree
* *
* This function returns zero if @e is in the @root RB-tree and %1 if it * This function returns zero if @e is in the @root RB-tree and %1 if it is
* is not. * not.
*/ */
static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e, static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
struct rb_root *root) struct rb_root *root)
......
...@@ -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