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 ...
This commit is contained in:
commit
996abf053e
|
@ -51,14 +51,13 @@
|
|||
* @name: MTD device name or number string
|
||||
* @vid_hdr_offs: VID header offset
|
||||
*/
|
||||
struct mtd_dev_param
|
||||
{
|
||||
struct mtd_dev_param {
|
||||
char name[MTD_PARAM_LEN_MAX];
|
||||
int vid_hdr_offs;
|
||||
};
|
||||
|
||||
/* Numbers of elements set in the @mtd_dev_param array */
|
||||
static int mtd_devs = 0;
|
||||
static int mtd_devs;
|
||||
|
||||
/* MTD devices specification parameters */
|
||||
static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES];
|
||||
|
@ -160,8 +159,7 @@ void ubi_put_device(struct ubi_device *ubi)
|
|||
}
|
||||
|
||||
/**
|
||||
* ubi_get_by_major - get UBI device description object by character device
|
||||
* major number.
|
||||
* ubi_get_by_major - get UBI device by character device major number.
|
||||
* @major: major number
|
||||
*
|
||||
* 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)
|
|||
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.
|
||||
* @ubi: UBI device description object
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
int i, err;
|
||||
int i, err, do_free = 0;
|
||||
dev_t dev;
|
||||
|
||||
sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);
|
||||
|
@ -384,7 +401,7 @@ static int uif_init(struct ubi_device *ubi)
|
|||
|
||||
ubi_assert(MINOR(dev) == 0);
|
||||
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;
|
||||
|
||||
err = cdev_add(&ubi->cdev, dev, 1);
|
||||
|
@ -410,10 +427,13 @@ static int uif_init(struct ubi_device *ubi)
|
|||
|
||||
out_volumes:
|
||||
kill_volumes(ubi);
|
||||
do_free = 0;
|
||||
out_sysfs:
|
||||
ubi_sysfs_close(ubi);
|
||||
cdev_del(&ubi->cdev);
|
||||
out_unreg:
|
||||
if (do_free)
|
||||
free_user_volumes(ubi);
|
||||
unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
|
||||
ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err);
|
||||
return err;
|
||||
|
@ -422,6 +442,10 @@ out_unreg:
|
|||
/**
|
||||
* uif_close - close user interfaces for an UBI device.
|
||||
* @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)
|
||||
{
|
||||
|
@ -431,6 +455,21 @@ static void uif_close(struct ubi_device *ubi)
|
|||
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.
|
||||
* @ubi: UBI device descriptor
|
||||
|
@ -475,6 +514,7 @@ static int attach_by_scanning(struct ubi_device *ubi)
|
|||
out_wl:
|
||||
ubi_wl_close(ubi);
|
||||
out_vtbl:
|
||||
free_internal_volumes(ubi);
|
||||
vfree(ubi->vtbl);
|
||||
out_si:
|
||||
ubi_scan_destroy_si(si);
|
||||
|
@ -482,7 +522,7 @@ out_si:
|
|||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* 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)
|
|||
ubi->min_io_size = ubi->mtd->writesize;
|
||||
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)) {
|
||||
ubi_err("min. I/O unit (%d) is not power of 2",
|
||||
ubi->min_io_size);
|
||||
|
@ -581,7 +625,7 @@ static int io_init(struct ubi_device *ubi)
|
|||
if (ubi->vid_hdr_offset < UBI_EC_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->min_io_size) {
|
||||
ubi->leb_start & (ubi->min_io_size - 1)) {
|
||||
ubi_err("bad VID header (%d) or data offsets (%d)",
|
||||
ubi->vid_hdr_offset, ubi->leb_start);
|
||||
return -EINVAL;
|
||||
|
@ -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
|
||||
* volume table, and 'ubi_resize_volume()' will propogate this change
|
||||
* volume table, and 'ubi_resize_volume()' will propagate this change
|
||||
* to the flash.
|
||||
*/
|
||||
ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG;
|
||||
|
@ -655,7 +699,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id)
|
|||
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.
|
||||
*/
|
||||
memcpy(&vtbl_rec, &ubi->vtbl[vol_id],
|
||||
|
@ -682,13 +726,13 @@ static int autoresize(struct ubi_device *ubi, int vol_id)
|
|||
|
||||
/**
|
||||
* 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
|
||||
* @vid_hdr_offset: VID header offset
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* negative error code in case of failure.
|
||||
*
|
||||
|
@ -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)
|
||||
{
|
||||
struct ubi_device *ubi;
|
||||
int i, err;
|
||||
int i, err, do_free = 1;
|
||||
|
||||
/*
|
||||
* 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)
|
|||
if (!ubi_devices[ubi_num])
|
||||
break;
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
|
@ -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->ckvol_mutex);
|
||||
mutex_init(&ubi->mult_mutex);
|
||||
mutex_init(&ubi->volumes_mutex);
|
||||
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)
|
|||
|
||||
err = uif_init(ubi);
|
||||
if (err)
|
||||
goto out_detach;
|
||||
goto out_nofree;
|
||||
|
||||
ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
|
||||
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)
|
|||
ubi->beb_rsvd_pebs);
|
||||
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;
|
||||
wake_up_process(ubi->bgt_thread);
|
||||
}
|
||||
|
||||
ubi_devices[ubi_num] = ubi;
|
||||
return ubi_num;
|
||||
|
||||
out_uif:
|
||||
uif_close(ubi);
|
||||
out_nofree:
|
||||
do_free = 0;
|
||||
out_detach:
|
||||
ubi_eba_close(ubi);
|
||||
ubi_wl_close(ubi);
|
||||
if (do_free)
|
||||
free_user_volumes(ubi);
|
||||
free_internal_volumes(ubi);
|
||||
vfree(ubi->vtbl);
|
||||
out_free:
|
||||
vfree(ubi->peb_buf1);
|
||||
|
@ -899,8 +947,8 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
|
|||
kthread_stop(ubi->bgt_thread);
|
||||
|
||||
uif_close(ubi);
|
||||
ubi_eba_close(ubi);
|
||||
ubi_wl_close(ubi);
|
||||
free_internal_volumes(ubi);
|
||||
vfree(ubi->vtbl);
|
||||
put_mtd_device(ubi->mtd);
|
||||
vfree(ubi->peb_buf1);
|
||||
|
@ -1044,8 +1092,7 @@ static void __exit ubi_exit(void)
|
|||
module_exit(ubi_exit);
|
||||
|
||||
/**
|
||||
* bytes_str_to_int - convert a string representing number of bytes to an
|
||||
* integer.
|
||||
* bytes_str_to_int - convert a number of bytes string into an integer.
|
||||
* @str: the string to convert
|
||||
*
|
||||
* This function returns positive resulting integer in case of success and a
|
||||
|
|
|
@ -39,9 +39,9 @@
|
|||
#include <linux/stat.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <mtd/ubi-user.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/div64.h>
|
||||
#include "ubi.h"
|
||||
|
||||
|
@ -116,7 +116,7 @@ static int vol_cdev_open(struct inode *inode, struct file *file)
|
|||
else
|
||||
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);
|
||||
unlock_kernel();
|
||||
|
@ -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 *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) {
|
||||
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)
|
|||
vol->updating = 0;
|
||||
vfree(vol->upd_buf);
|
||||
} 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,
|
||||
vol->upd_bytes, vol->ubi->ubi_num, vol->vol_id);
|
||||
vol->changing_leb = 0;
|
||||
|
@ -183,7 +183,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
|
|||
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);
|
||||
|
||||
file->f_pos = new_offset;
|
||||
|
@ -201,7 +201,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
|
|||
void *tbuf;
|
||||
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);
|
||||
|
||||
if (vol->updating) {
|
||||
|
@ -216,7 +216,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
|
|||
return 0;
|
||||
|
||||
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)
|
||||
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,
|
|||
char *tbuf;
|
||||
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);
|
||||
|
||||
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,
|
|||
off = do_div(tmp, vol->usable_leb_size);
|
||||
lnum = tmp;
|
||||
|
||||
if (off % ubi->min_io_size) {
|
||||
if (off & (ubi->min_io_size - 1)) {
|
||||
dbg_err("unaligned position");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
/* 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");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -352,7 +352,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
|
|||
}
|
||||
|
||||
#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 */
|
||||
|
||||
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,
|
|||
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) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
|
@ -513,7 +514,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
|
|||
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);
|
||||
if (err)
|
||||
break;
|
||||
|
@ -564,7 +565,7 @@ static int verify_mkvol_req(const struct ubi_device *ubi,
|
|||
if (req->alignment > ubi->leb_size)
|
||||
goto bad;
|
||||
|
||||
n = req->alignment % ubi->min_io_size;
|
||||
n = req->alignment & (ubi->min_io_size - 1);
|
||||
if (req->alignment != 1 && n)
|
||||
goto bad;
|
||||
|
||||
|
@ -573,6 +574,10 @@ static int verify_mkvol_req(const struct ubi_device *ubi,
|
|||
goto bad;
|
||||
}
|
||||
|
||||
n = strnlen(req->name, req->name_len + 1);
|
||||
if (n != req->name_len)
|
||||
goto bad;
|
||||
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
|
@ -600,6 +605,166 @@ static int verify_rsvol_req(const struct ubi_device *ubi,
|
|||
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,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
|
@ -621,19 +786,18 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
|
|||
{
|
||||
struct ubi_mkvol_req req;
|
||||
|
||||
dbg_msg("create volume");
|
||||
dbg_gen("create volume");
|
||||
err = copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req));
|
||||
if (err) {
|
||||
err = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
req.name[req.name_len] = '\0';
|
||||
err = verify_mkvol_req(ubi, &req);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
req.name[req.name_len] = '\0';
|
||||
|
||||
mutex_lock(&ubi->volumes_mutex);
|
||||
err = ubi_create_volume(ubi, &req);
|
||||
mutex_unlock(&ubi->volumes_mutex);
|
||||
|
@ -652,7 +816,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
|
|||
{
|
||||
int vol_id;
|
||||
|
||||
dbg_msg("remove volume");
|
||||
dbg_gen("remove volume");
|
||||
err = get_user(vol_id, (__user int32_t *)argp);
|
||||
if (err) {
|
||||
err = -EFAULT;
|
||||
|
@ -666,7 +830,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
|
|||
}
|
||||
|
||||
mutex_lock(&ubi->volumes_mutex);
|
||||
err = ubi_remove_volume(desc);
|
||||
err = ubi_remove_volume(desc, 0);
|
||||
mutex_unlock(&ubi->volumes_mutex);
|
||||
|
||||
/*
|
||||
|
@ -685,7 +849,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
|
|||
uint64_t tmp;
|
||||
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));
|
||||
if (err) {
|
||||
err = -EFAULT;
|
||||
|
@ -713,6 +877,32 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
|
|||
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:
|
||||
err = -ENOTTY;
|
||||
break;
|
||||
|
@ -738,7 +928,7 @@ static int ctrl_cdev_ioctl(struct inode *inode, struct file *file,
|
|||
struct ubi_attach_req req;
|
||||
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));
|
||||
if (err) {
|
||||
err = -EFAULT;
|
||||
|
@ -778,7 +968,7 @@ static int ctrl_cdev_ioctl(struct inode *inode, struct file *file,
|
|||
{
|
||||
int ubi_num;
|
||||
|
||||
dbg_msg("dettach MTD device");
|
||||
dbg_gen("dettach MTD device");
|
||||
err = get_user(ubi_num, (__user int32_t *)argp);
|
||||
if (err) {
|
||||
err = -EFAULT;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
* changes.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_MSG
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||
|
||||
#include "ubi.h"
|
||||
|
||||
|
@ -34,14 +34,19 @@
|
|||
*/
|
||||
void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
|
||||
{
|
||||
dbg_msg("erase counter header dump:");
|
||||
dbg_msg("magic %#08x", be32_to_cpu(ec_hdr->magic));
|
||||
dbg_msg("version %d", (int)ec_hdr->version);
|
||||
dbg_msg("ec %llu", (long long)be64_to_cpu(ec_hdr->ec));
|
||||
dbg_msg("vid_hdr_offset %d", be32_to_cpu(ec_hdr->vid_hdr_offset));
|
||||
dbg_msg("data_offset %d", be32_to_cpu(ec_hdr->data_offset));
|
||||
dbg_msg("hdr_crc %#08x", be32_to_cpu(ec_hdr->hdr_crc));
|
||||
dbg_msg("erase counter header hexdump:");
|
||||
printk(KERN_DEBUG "Erase counter header dump:\n");
|
||||
printk(KERN_DEBUG "\tmagic %#08x\n",
|
||||
be32_to_cpu(ec_hdr->magic));
|
||||
printk(KERN_DEBUG "\tversion %d\n", (int)ec_hdr->version);
|
||||
printk(KERN_DEBUG "\tec %llu\n",
|
||||
(long long)be64_to_cpu(ec_hdr->ec));
|
||||
printk(KERN_DEBUG "\tvid_hdr_offset %d\n",
|
||||
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,
|
||||
ec_hdr, UBI_EC_HDR_SIZE, 1);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
dbg_msg("volume identifier header dump:");
|
||||
dbg_msg("magic %08x", be32_to_cpu(vid_hdr->magic));
|
||||
dbg_msg("version %d", (int)vid_hdr->version);
|
||||
dbg_msg("vol_type %d", (int)vid_hdr->vol_type);
|
||||
dbg_msg("copy_flag %d", (int)vid_hdr->copy_flag);
|
||||
dbg_msg("compat %d", (int)vid_hdr->compat);
|
||||
dbg_msg("vol_id %d", be32_to_cpu(vid_hdr->vol_id));
|
||||
dbg_msg("lnum %d", be32_to_cpu(vid_hdr->lnum));
|
||||
dbg_msg("leb_ver %u", be32_to_cpu(vid_hdr->leb_ver));
|
||||
dbg_msg("data_size %d", be32_to_cpu(vid_hdr->data_size));
|
||||
dbg_msg("used_ebs %d", be32_to_cpu(vid_hdr->used_ebs));
|
||||
dbg_msg("data_pad %d", be32_to_cpu(vid_hdr->data_pad));
|
||||
dbg_msg("sqnum %llu",
|
||||
printk(KERN_DEBUG "Volume identifier header dump:\n");
|
||||
printk(KERN_DEBUG "\tmagic %08x\n", be32_to_cpu(vid_hdr->magic));
|
||||
printk(KERN_DEBUG "\tversion %d\n", (int)vid_hdr->version);
|
||||
printk(KERN_DEBUG "\tvol_type %d\n", (int)vid_hdr->vol_type);
|
||||
printk(KERN_DEBUG "\tcopy_flag %d\n", (int)vid_hdr->copy_flag);
|
||||
printk(KERN_DEBUG "\tcompat %d\n", (int)vid_hdr->compat);
|
||||
printk(KERN_DEBUG "\tvol_id %d\n", be32_to_cpu(vid_hdr->vol_id));
|
||||
printk(KERN_DEBUG "\tlnum %d\n", be32_to_cpu(vid_hdr->lnum));
|
||||
printk(KERN_DEBUG "\tdata_size %d\n", be32_to_cpu(vid_hdr->data_size));
|
||||
printk(KERN_DEBUG "\tused_ebs %d\n", be32_to_cpu(vid_hdr->used_ebs));
|
||||
printk(KERN_DEBUG "\tdata_pad %d\n", be32_to_cpu(vid_hdr->data_pad));
|
||||
printk(KERN_DEBUG "\tsqnum %llu\n",
|
||||
(unsigned long long)be64_to_cpu(vid_hdr->sqnum));
|
||||
dbg_msg("hdr_crc %08x", be32_to_cpu(vid_hdr->hdr_crc));
|
||||
dbg_msg("volume identifier header hexdump:");
|
||||
printk(KERN_DEBUG "\thdr_crc %08x\n", be32_to_cpu(vid_hdr->hdr_crc));
|
||||
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,25 +82,25 @@ void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
|
|||
*/
|
||||
void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
|
||||
{
|
||||
dbg_msg("volume information dump:");
|
||||
dbg_msg("vol_id %d", vol->vol_id);
|
||||
dbg_msg("reserved_pebs %d", vol->reserved_pebs);
|
||||
dbg_msg("alignment %d", vol->alignment);
|
||||
dbg_msg("data_pad %d", vol->data_pad);
|
||||
dbg_msg("vol_type %d", vol->vol_type);
|
||||
dbg_msg("name_len %d", vol->name_len);
|
||||
dbg_msg("usable_leb_size %d", vol->usable_leb_size);
|
||||
dbg_msg("used_ebs %d", vol->used_ebs);
|
||||
dbg_msg("used_bytes %lld", vol->used_bytes);
|
||||
dbg_msg("last_eb_bytes %d", vol->last_eb_bytes);
|
||||
dbg_msg("corrupted %d", vol->corrupted);
|
||||
dbg_msg("upd_marker %d", vol->upd_marker);
|
||||
printk(KERN_DEBUG "Volume information dump:\n");
|
||||
printk(KERN_DEBUG "\tvol_id %d\n", vol->vol_id);
|
||||
printk(KERN_DEBUG "\treserved_pebs %d\n", vol->reserved_pebs);
|
||||
printk(KERN_DEBUG "\talignment %d\n", vol->alignment);
|
||||
printk(KERN_DEBUG "\tdata_pad %d\n", vol->data_pad);
|
||||
printk(KERN_DEBUG "\tvol_type %d\n", vol->vol_type);
|
||||
printk(KERN_DEBUG "\tname_len %d\n", vol->name_len);
|
||||
printk(KERN_DEBUG "\tusable_leb_size %d\n", vol->usable_leb_size);
|
||||
printk(KERN_DEBUG "\tused_ebs %d\n", vol->used_ebs);
|
||||
printk(KERN_DEBUG "\tused_bytes %lld\n", vol->used_bytes);
|
||||
printk(KERN_DEBUG "\tlast_eb_bytes %d\n", vol->last_eb_bytes);
|
||||
printk(KERN_DEBUG "\tcorrupted %d\n", vol->corrupted);
|
||||
printk(KERN_DEBUG "\tupd_marker %d\n", vol->upd_marker);
|
||||
|
||||
if (vol->name_len <= UBI_VOL_NAME_MAX &&
|
||||
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 {
|
||||
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[3], vol->name[4]);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
dbg_msg("volume table record %d dump:", idx);
|
||||
dbg_msg("reserved_pebs %d", be32_to_cpu(r->reserved_pebs));
|
||||
dbg_msg("alignment %d", be32_to_cpu(r->alignment));
|
||||
dbg_msg("data_pad %d", be32_to_cpu(r->data_pad));
|
||||
dbg_msg("vol_type %d", (int)r->vol_type);
|
||||
dbg_msg("upd_marker %d", (int)r->upd_marker);
|
||||
dbg_msg("name_len %d", name_len);
|
||||
printk(KERN_DEBUG "Volume table record %d dump:\n", idx);
|
||||
printk(KERN_DEBUG "\treserved_pebs %d\n",
|
||||
be32_to_cpu(r->reserved_pebs));
|
||||
printk(KERN_DEBUG "\talignment %d\n", be32_to_cpu(r->alignment));
|
||||
printk(KERN_DEBUG "\tdata_pad %d\n", be32_to_cpu(r->data_pad));
|
||||
printk(KERN_DEBUG "\tvol_type %d\n", (int)r->vol_type);
|
||||
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') {
|
||||
dbg_msg("name NULL");
|
||||
printk(KERN_DEBUG "\tname NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (name_len <= UBI_VOL_NAME_MAX &&
|
||||
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 {
|
||||
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[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)
|
|||
*/
|
||||
void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv)
|
||||
{
|
||||
dbg_msg("volume scanning information dump:");
|
||||
dbg_msg("vol_id %d", sv->vol_id);
|
||||
dbg_msg("highest_lnum %d", sv->highest_lnum);
|
||||
dbg_msg("leb_count %d", sv->leb_count);
|
||||
dbg_msg("compat %d", sv->compat);
|
||||
dbg_msg("vol_type %d", sv->vol_type);
|
||||
dbg_msg("used_ebs %d", sv->used_ebs);
|
||||
dbg_msg("last_data_size %d", sv->last_data_size);
|
||||
dbg_msg("data_pad %d", sv->data_pad);
|
||||
printk(KERN_DEBUG "Volume scanning information dump:\n");
|
||||
printk(KERN_DEBUG "\tvol_id %d\n", sv->vol_id);
|
||||
printk(KERN_DEBUG "\thighest_lnum %d\n", sv->highest_lnum);
|
||||
printk(KERN_DEBUG "\tleb_count %d\n", sv->leb_count);
|
||||
printk(KERN_DEBUG "\tcompat %d\n", sv->compat);
|
||||
printk(KERN_DEBUG "\tvol_type %d\n", sv->vol_type);
|
||||
printk(KERN_DEBUG "\tused_ebs %d\n", sv->used_ebs);
|
||||
printk(KERN_DEBUG "\tlast_data_size %d\n", sv->last_data_size);
|
||||
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)
|
|||
*/
|
||||
void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type)
|
||||
{
|
||||
dbg_msg("eraseblock scanning information dump:");
|
||||
dbg_msg("ec %d", seb->ec);
|
||||
dbg_msg("pnum %d", seb->pnum);
|
||||
printk(KERN_DEBUG "eraseblock scanning information dump:\n");
|
||||
printk(KERN_DEBUG "\tec %d\n", seb->ec);
|
||||
printk(KERN_DEBUG "\tpnum %d\n", seb->pnum);
|
||||
if (type == 0) {
|
||||
dbg_msg("lnum %d", seb->lnum);
|
||||
dbg_msg("scrub %d", seb->scrub);
|
||||
dbg_msg("sqnum %llu", seb->sqnum);
|
||||
dbg_msg("leb_ver %u", seb->leb_ver);
|
||||
printk(KERN_DEBUG "\tlnum %d\n", seb->lnum);
|
||||
printk(KERN_DEBUG "\tscrub %d\n", seb->scrub);
|
||||
printk(KERN_DEBUG "\tsqnum %llu\n", seb->sqnum);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,16 +182,16 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
|
|||
{
|
||||
char nm[17];
|
||||
|
||||
dbg_msg("volume creation request dump:");
|
||||
dbg_msg("vol_id %d", req->vol_id);
|
||||
dbg_msg("alignment %d", req->alignment);
|
||||
dbg_msg("bytes %lld", (long long)req->bytes);
|
||||
dbg_msg("vol_type %d", req->vol_type);
|
||||
dbg_msg("name_len %d", req->name_len);
|
||||
printk(KERN_DEBUG "Volume creation request dump:\n");
|
||||
printk(KERN_DEBUG "\tvol_id %d\n", req->vol_id);
|
||||
printk(KERN_DEBUG "\talignment %d\n", req->alignment);
|
||||
printk(KERN_DEBUG "\tbytes %lld\n", (long long)req->bytes);
|
||||
printk(KERN_DEBUG "\tvol_type %d\n", req->vol_type);
|
||||
printk(KERN_DEBUG "\tname_len %d\n", req->name_len);
|
||||
|
||||
memcpy(nm, req->name, 16);
|
||||
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 @@
|
|||
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||
#include <linux/random.h>
|
||||
|
||||
#define ubi_assert(expr) BUG_ON(!(expr))
|
||||
#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 DBG_DISABLE_BGT 1
|
||||
#else
|
||||
#define DBG_DISABLE_BGT 0
|
||||
#endif
|
||||
#define ubi_assert(expr) do { \
|
||||
if (unlikely(!(expr))) { \
|
||||
printk(KERN_CRIT "UBI assert failed in %s at %u (pid %d)\n", \
|
||||
__func__, __LINE__, current->pid); \
|
||||
ubi_dbg_dump_stack(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_MSG
|
||||
/* Generic debugging message */
|
||||
#define dbg_msg(fmt, ...) \
|
||||
printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \
|
||||
current->pid, __func__, ##__VA_ARGS__)
|
||||
|
@ -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_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
|
||||
|
||||
#define dbg_msg(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) ({})
|
||||
|
||||
#endif /* CONFIG_MTD_UBI_DEBUG_MSG */
|
||||
#define dbg_gen(fmt, ...) ({})
|
||||
#endif
|
||||
|
||||
#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__)
|
||||
#else
|
||||
#define dbg_eba(fmt, ...) ({})
|
||||
#endif
|
||||
|
||||
#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__)
|
||||
#else
|
||||
#define dbg_wl(fmt, ...) ({})
|
||||
#endif
|
||||
|
||||
#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__)
|
||||
#else
|
||||
#define dbg_io(fmt, ...) ({})
|
||||
|
@ -105,6 +93,12 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
|
|||
#define UBI_IO_DEBUG 0
|
||||
#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
|
||||
/**
|
||||
* 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)
|
|||
#define ubi_dbg_is_erase_failure() 0
|
||||
#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__ */
|
||||
|
|
|
@ -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
|
||||
* RAM, which assumes poor scalability, it might be (partially) maintained on
|
||||
* flash in future implementations.
|
||||
*
|
||||
* The EBA unit implements per-logical eraseblock locking. Before accessing a
|
||||
* logical eraseblock it is locked for reading or writing. The per-logical
|
||||
* eraseblock locking is implemented by means of the lock tree. The lock tree
|
||||
* is an RB-tree which refers all the currently locked logical eraseblocks. The
|
||||
* lock tree elements are &struct ubi_ltree_entry objects. They are indexed by
|
||||
* (@vol_id, @lnum) pairs.
|
||||
* The EBA sub-system implements per-logical eraseblock locking. Before
|
||||
* accessing a logical eraseblock it is locked for reading or writing. The
|
||||
* per-logical eraseblock locking is implemented by means of the lock tree. The
|
||||
* lock tree is an RB-tree which refers all the currently locked logical
|
||||
* eraseblocks. The lock tree elements are &struct ubi_ltree_entry objects.
|
||||
* They are indexed by (@vol_id, @lnum) pairs.
|
||||
*
|
||||
* EBA also maintains the global sequence counter which is incremented each
|
||||
* 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,
|
|||
le->users += 1;
|
||||
spin_unlock(&ubi->ltree_lock);
|
||||
|
||||
if (le_free)
|
||||
kfree(le_free);
|
||||
|
||||
return le;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
int free = 0;
|
||||
struct ubi_ltree_entry *le;
|
||||
|
||||
spin_lock(&ubi->ltree_lock);
|
||||
le = ltree_lookup(ubi, vol_id, lnum);
|
||||
le->users -= 1;
|
||||
ubi_assert(le->users >= 0);
|
||||
up_read(&le->mutex);
|
||||
if (le->users == 0) {
|
||||
rb_erase(&le->rb, &ubi->ltree);
|
||||
free = 1;
|
||||
kfree(le);
|
||||
}
|
||||
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)
|
|||
*/
|
||||
static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum)
|
||||
{
|
||||
int free;
|
||||
struct ubi_ltree_entry *le;
|
||||
|
||||
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)
|
|||
ubi_assert(le->users >= 0);
|
||||
if (le->users == 0) {
|
||||
rb_erase(&le->rb, &ubi->ltree);
|
||||
free = 1;
|
||||
} else
|
||||
free = 0;
|
||||
spin_unlock(&ubi->ltree_lock);
|
||||
if (free)
|
||||
kfree(le);
|
||||
}
|
||||
spin_unlock(&ubi->ltree_lock);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -307,24 +297,19 @@ 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)
|
||||
{
|
||||
int free;
|
||||
struct ubi_ltree_entry *le;
|
||||
|
||||
spin_lock(&ubi->ltree_lock);
|
||||
le = ltree_lookup(ubi, vol_id, lnum);
|
||||
le->users -= 1;
|
||||
ubi_assert(le->users >= 0);
|
||||
up_write(&le->mutex);
|
||||
if (le->users == 0) {
|
||||
rb_erase(&le->rb, &ubi->ltree);
|
||||
free = 1;
|
||||
} else
|
||||
free = 0;
|
||||
spin_unlock(&ubi->ltree_lock);
|
||||
|
||||
up_write(&le->mutex);
|
||||
if (free)
|
||||
kfree(le);
|
||||
}
|
||||
spin_unlock(&ubi->ltree_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* ubi_eba_unmap_leb - un-map logical eraseblock.
|
||||
|
@ -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;
|
||||
|
||||
vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
|
||||
if (!vid_hdr) {
|
||||
if (!vid_hdr)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mutex_lock(&ubi->buf_mutex);
|
||||
|
||||
|
@ -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 */
|
||||
len = ALIGN(data_size, ubi->min_io_size);
|
||||
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);
|
||||
if (!vid_hdr)
|
||||
|
@ -919,7 +903,7 @@ retry:
|
|||
}
|
||||
|
||||
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)
|
||||
goto out_leb_unlock;
|
||||
}
|
||||
|
@ -1141,7 +1125,7 @@ out_unlock_leb:
|
|||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @si: scanning information
|
||||
*
|
||||
|
@ -1156,7 +1140,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
|
|||
struct ubi_scan_leb *seb;
|
||||
struct rb_node *rb;
|
||||
|
||||
dbg_eba("initialize EBA unit");
|
||||
dbg_eba("initialize EBA sub-system");
|
||||
|
||||
spin_lock_init(&ubi->ltree_lock);
|
||||
mutex_init(&ubi->alc_mutex);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
dbg_eba("EBA unit is initialized");
|
||||
dbg_eba("EBA sub-system is initialized");
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
|
@ -1233,20 +1217,3 @@ out_free:
|
|||
}
|
||||
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,
|
|||
struct ubi_device *ubi;
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
@ -162,7 +162,7 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|||
struct ubi_device *ubi;
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
@ -215,7 +215,7 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|||
struct ubi_volume *vol;
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
@ -299,12 +299,12 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
|
|||
mtd->size = vol->used_bytes;
|
||||
|
||||
if (add_mtd_device(mtd)) {
|
||||
ubi_err("cannot not add MTD device\n");
|
||||
ubi_err("cannot not add MTD device");
|
||||
kfree(mtd->name);
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
@ -322,7 +322,7 @@ int ubi_destroy_gluebi(struct ubi_volume *vol)
|
|||
int err;
|
||||
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);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
|
@ -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
|
||||
* MTD devices. It also implements handy functions for reading and writing UBI
|
||||
* headers.
|
||||
* This sub-system provides a uniform way to work with all kinds of the
|
||||
* underlying MTD devices. It also implements handy functions for reading and
|
||||
* writing UBI headers.
|
||||
*
|
||||
* 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
|
||||
* validates every single header it reads from the flash media.
|
||||
* from the flash media in order to be more secure and robust. So this
|
||||
* sub-system validates every single header it reads from the flash media.
|
||||
*
|
||||
* Some words about how the eraseblock headers are stored.
|
||||
*
|
||||
|
@ -79,11 +79,11 @@
|
|||
* 512-byte chunks, we have to allocate one more buffer and copy our VID header
|
||||
* to offset 448 of this buffer.
|
||||
*
|
||||
* The I/O unit does the following trick in order to avoid this extra copy.
|
||||
* It always allocates a @ubi->vid_hdr_alsize bytes buffer for the VID header
|
||||
* and returns a pointer to offset @ubi->vid_hdr_shift of this buffer. When the
|
||||
* VID header is being written out, it shifts the VID header pointer back and
|
||||
* writes the whole sub-page.
|
||||
* The I/O sub-system does the following trick in order to avoid this extra
|
||||
* copy. It always allocates a @ubi->vid_hdr_alsize bytes buffer for the VID
|
||||
* header and returns a pointer to offset @ubi->vid_hdr_shift of this buffer.
|
||||
* When the VID header is being written out, it shifts the VID header pointer
|
||||
* back and writes the whole sub-page.
|
||||
*/
|
||||
|
||||
#include <linux/crc32.h>
|
||||
|
@ -156,8 +156,12 @@ retry:
|
|||
/*
|
||||
* -EUCLEAN is reported if there was a bit-flip which
|
||||
* 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);
|
||||
return UBI_IO_BITFLIPS;
|
||||
}
|
||||
|
@ -187,7 +191,7 @@ retry:
|
|||
ubi_assert(len == read);
|
||||
|
||||
if (ubi_dbg_is_bitflip()) {
|
||||
dbg_msg("bit-flip (emulated)");
|
||||
dbg_gen("bit-flip (emulated)");
|
||||
err = UBI_IO_BITFLIPS;
|
||||
}
|
||||
}
|
||||
|
@ -391,6 +395,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
|
|||
{
|
||||
int err, i, patt_count;
|
||||
|
||||
ubi_msg("run torture test for PEB %d", pnum);
|
||||
patt_count = ARRAY_SIZE(patterns);
|
||||
ubi_assert(patt_count > 0);
|
||||
|
||||
|
@ -434,6 +439,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
|
|||
}
|
||||
|
||||
err = patt_count;
|
||||
ubi_msg("PEB %d passed torture test, do not mark it a bad", pnum);
|
||||
|
||||
out:
|
||||
mutex_unlock(&ubi->buf_mutex);
|
||||
|
@ -699,8 +705,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
|
|||
|
||||
if (hdr_crc != crc) {
|
||||
if (verbose) {
|
||||
ubi_warn("bad EC header CRC at PEB %d, calculated %#08x,"
|
||||
" read %#08x", pnum, crc, hdr_crc);
|
||||
ubi_warn("bad EC header CRC at PEB %d, calculated "
|
||||
"%#08x, read %#08x", pnum, crc, hdr_crc);
|
||||
ubi_dbg_dump_ec_hdr(ec_hdr);
|
||||
}
|
||||
return UBI_IO_BAD_EC_HDR;
|
||||
|
@ -1095,8 +1101,7 @@ fail:
|
|||
}
|
||||
|
||||
/**
|
||||
* paranoid_check_peb_ec_hdr - check that the erase counter header of a
|
||||
* physical eraseblock is in-place and is all right.
|
||||
* paranoid_check_peb_ec_hdr - check erase counter header.
|
||||
* @ubi: UBI device description object
|
||||
* @pnum: the physical eraseblock number to check
|
||||
*
|
||||
|
@ -1174,8 +1179,7 @@ fail:
|
|||
}
|
||||
|
||||
/**
|
||||
* paranoid_check_peb_vid_hdr - check that the volume identifier header of a
|
||||
* physical eraseblock is in-place and is all right.
|
||||
* paranoid_check_peb_vid_hdr - check volume identifier header.
|
||||
* @ubi: UBI device description object
|
||||
* @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,
|
|||
|
||||
fail:
|
||||
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,
|
||||
ubi->dbg_peb_buf, len, 1);
|
||||
err = 1;
|
||||
|
|
|
@ -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_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)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
@ -215,7 +215,7 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
|
|||
struct ubi_device *ubi;
|
||||
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)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
@ -266,7 +266,7 @@ void ubi_close_volume(struct ubi_volume_desc *desc)
|
|||
struct ubi_volume *vol = desc->vol;
|
||||
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);
|
||||
switch (desc->mode) {
|
||||
|
@ -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;
|
||||
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 ||
|
||||
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,
|
|||
struct ubi_device *ubi = vol->ubi;
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
@ -397,8 +397,8 @@ int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
|
|||
return -EROFS;
|
||||
|
||||
if (lnum < 0 || lnum >= vol->reserved_pebs || offset < 0 || len < 0 ||
|
||||
offset + len > vol->usable_leb_size || offset % ubi->min_io_size ||
|
||||
len % ubi->min_io_size)
|
||||
offset + len > vol->usable_leb_size ||
|
||||
offset & (ubi->min_io_size - 1) || len & (ubi->min_io_size - 1))
|
||||
return -EINVAL;
|
||||
|
||||
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,
|
|||
struct ubi_device *ubi = vol->ubi;
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
@ -447,7 +447,7 @@ int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
|
|||
return -EROFS;
|
||||
|
||||
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;
|
||||
|
||||
if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
|
||||
|
@ -482,7 +482,7 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum)
|
|||
struct ubi_device *ubi = vol->ubi;
|
||||
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)
|
||||
return -EROFS;
|
||||
|
@ -542,7 +542,7 @@ int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum)
|
|||
struct ubi_volume *vol = desc->vol;
|
||||
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)
|
||||
return -EROFS;
|
||||
|
@ -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_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)
|
||||
return -EROFS;
|
||||
|
@ -621,7 +621,7 @@ int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum)
|
|||
{
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
@ -632,3 +632,27 @@ int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum)
|
|||
return vol->eba_tbl[lnum] >= 0;
|
||||
}
|
||||
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,
|
|||
{
|
||||
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--)
|
||||
if (((const uint8_t *)buf)[i] != 0xFF)
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* 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,
|
|||
}
|
||||
|
||||
/**
|
||||
* validate_vid_hdr - check that volume identifier header is correct and
|
||||
* consistent.
|
||||
* validate_vid_hdr - check volume identifier header.
|
||||
* @vid_hdr: the volume identifier header to check
|
||||
* @sv: information about the volume this logical eraseblock belongs to
|
||||
* @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,
|
|||
* non-zero if an inconsistency was found and zero if not.
|
||||
*
|
||||
* 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
|
||||
* headers of the same volume.
|
||||
*/
|
||||
|
@ -247,45 +246,21 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
|
|||
struct ubi_vid_hdr *vh = NULL;
|
||||
unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
|
||||
|
||||
if (seb->sqnum == 0 && sqnum2 == 0) {
|
||||
long long abs, v1 = seb->leb_ver, v2 = be32_to_cpu(vid_hdr->leb_ver);
|
||||
|
||||
if (sqnum2 == seb->sqnum) {
|
||||
/*
|
||||
* UBI constantly increases the logical eraseblock version
|
||||
* number and it can overflow. Thus, we have to bear in mind
|
||||
* that versions that are close to %0xFFFFFFFF are less then
|
||||
* versions that are close to %0.
|
||||
*
|
||||
* The UBI WL unit guarantees that the number of pending tasks
|
||||
* 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.
|
||||
* This must be a really ancient UBI image which has been
|
||||
* created before sequence numbers support has been added. At
|
||||
* that times we used 32-bit LEB versions stored in logical
|
||||
* eraseblocks. That was before UBI got into mainline. We do not
|
||||
* support these images anymore. Well, those images will work
|
||||
* still work, but only if no unclean reboots happened.
|
||||
*/
|
||||
dbg_bld("using old crappy leb_ver stuff");
|
||||
|
||||
if (v1 == v2) {
|
||||
ubi_err("PEB %d and PEB %d have the same version %lld",
|
||||
seb->pnum, pnum, v1);
|
||||
ubi_err("unsupported on-flash UBI format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
abs = v1 - v2;
|
||||
if (abs < 0)
|
||||
abs = -abs;
|
||||
|
||||
if (abs < 0x7FFFFFFF)
|
||||
/* Non-overflow situation */
|
||||
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;
|
||||
second_is_newer = !!(sqnum2 > seb->sqnum);
|
||||
|
||||
/*
|
||||
* 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,
|
|||
* 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.
|
||||
*
|
||||
* 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) {
|
||||
|
@ -379,8 +354,7 @@ out_free_vidh:
|
|||
}
|
||||
|
||||
/**
|
||||
* ubi_scan_add_used - add information about a physical eraseblock to the
|
||||
* scanning information.
|
||||
* ubi_scan_add_used - add physical eraseblock to the scanning information.
|
||||
* @ubi: UBI device description object
|
||||
* @si: scanning information
|
||||
* @pnum: the physical eraseblock number
|
||||
|
@ -400,7 +374,6 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
|
|||
int bitflips)
|
||||
{
|
||||
int err, vol_id, lnum;
|
||||
uint32_t leb_ver;
|
||||
unsigned long long sqnum;
|
||||
struct ubi_scan_volume *sv;
|
||||
struct ubi_scan_leb *seb;
|
||||
|
@ -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);
|
||||
lnum = be32_to_cpu(vid_hdr->lnum);
|
||||
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",
|
||||
pnum, vol_id, lnum, ec, sqnum, leb_ver, bitflips);
|
||||
dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, bitflips %d",
|
||||
pnum, vol_id, lnum, ec, sqnum, bitflips);
|
||||
|
||||
sv = add_volume(si, vol_id, pnum, vid_hdr);
|
||||
if (IS_ERR(sv) < 0)
|
||||
|
@ -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, "
|
||||
"LEB ver %u, EC %d", seb->pnum, seb->sqnum,
|
||||
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;
|
||||
}
|
||||
"EC %d", seb->pnum, seb->sqnum, seb->ec);
|
||||
|
||||
/*
|
||||
* Make sure that the logical eraseblocks have different
|
||||
* 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) {
|
||||
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,
|
|||
seb->pnum = pnum;
|
||||
seb->scrub = ((cmp_res & 2) || bitflips);
|
||||
seb->sqnum = sqnum;
|
||||
seb->leb_ver = leb_ver;
|
||||
|
||||
if (sv->highest_lnum == lnum)
|
||||
sv->last_data_size =
|
||||
|
@ -540,7 +506,6 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
|
|||
seb->lnum = lnum;
|
||||
seb->sqnum = sqnum;
|
||||
seb->scrub = bitflips;
|
||||
seb->leb_ver = leb_ver;
|
||||
|
||||
if (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,
|
|||
}
|
||||
|
||||
/**
|
||||
* ubi_scan_find_sv - find information about a particular volume in the
|
||||
* scanning information.
|
||||
* ubi_scan_find_sv - find volume in the scanning information.
|
||||
* @si: scanning information
|
||||
* @vol_id: the requested volume ID
|
||||
*
|
||||
|
@ -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
|
||||
* eraseblock in the volume scanning information.
|
||||
* ubi_scan_find_seb - find LEB in the volume scanning information.
|
||||
* @sv: a pointer to the volume scanning information
|
||||
* @lnum: the requested logical eraseblock
|
||||
*
|
||||
|
@ -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
|
||||
* 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
|
||||
* function returns zero in case of success and a negative error code in case
|
||||
* of failure.
|
||||
* initialization stages, when the EBA sub-system had not been yet initialized.
|
||||
* This function returns zero in case of success and a negative error code in
|
||||
* case of failure.
|
||||
*/
|
||||
int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
|
||||
int pnum, int ec)
|
||||
|
@ -687,9 +650,10 @@ out_free:
|
|||
* @si: scanning information
|
||||
*
|
||||
* 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
|
||||
* initialized yet. This function picks a physical eraseblocks from one of the
|
||||
* lists, writes the EC header if it is needed, and removes it from the list.
|
||||
* called on the UBI initialization stages when the wear-leveling sub-system is
|
||||
* not initialized yet. This function picks a physical eraseblocks from one of
|
||||
* 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
|
||||
* 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,
|
|||
}
|
||||
|
||||
/**
|
||||
* process_eb - read UBI headers, check them and add corresponding data
|
||||
* to the scanning information.
|
||||
* process_eb - read, check UBI headers, and add them to scanning information.
|
||||
* @ubi: UBI device description object
|
||||
* @si: scanning information
|
||||
* @pnum: the physical eraseblock number
|
||||
|
@ -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
|
||||
* 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);
|
||||
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
|
|||
return err;
|
||||
else if (err) {
|
||||
/*
|
||||
* FIXME: this is actually duty of the I/O unit to initialize
|
||||
* this, but MTD does not provide enough information.
|
||||
* FIXME: this is actually duty of the I/O sub-system to
|
||||
* initialize this, but MTD does not provide enough
|
||||
* information.
|
||||
*/
|
||||
si->bad_peb_count += 1;
|
||||
return 0;
|
||||
|
@ -930,7 +895,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
|
|||
for (pnum = 0; pnum < ubi->peb_count; pnum++) {
|
||||
cond_resched();
|
||||
|
||||
dbg_msg("process PEB %d", pnum);
|
||||
dbg_gen("process PEB %d", pnum);
|
||||
err = process_eb(ubi, si, pnum);
|
||||
if (err < 0)
|
||||
goto out_vidh;
|
||||
|
@ -1079,8 +1044,7 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
|
|||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
|
||||
/**
|
||||
* paranoid_check_si - check if the scanning information is correct and
|
||||
* consistent.
|
||||
* paranoid_check_si - check the scanning information.
|
||||
* @ubi: UBI device description object
|
||||
* @si: scanning information
|
||||
*
|
||||
|
@ -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);
|
||||
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)
|
||||
|
@ -1299,8 +1258,7 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
|
|||
if (err < 0) {
|
||||
kfree(buf);
|
||||
return err;
|
||||
}
|
||||
else if (err)
|
||||
} else if (err)
|
||||
buf[pnum] = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
* @u: unions RB-tree or @list links
|
||||
* @u.rb: link in the per-volume RB-tree of &struct ubi_scan_leb objects
|
||||
* @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
|
||||
* scanning.
|
||||
|
@ -49,7 +48,6 @@ struct ubi_scan_leb {
|
|||
struct rb_node rb;
|
||||
struct list_head list;
|
||||
} u;
|
||||
uint32_t leb_ver;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -61,8 +59,8 @@ struct ubi_scan_leb {
|
|||
* @used_ebs: number of used logical eraseblocks in this volume (only for
|
||||
* static volumes)
|
||||
* @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
|
||||
* dynamic volumes)
|
||||
* volume (always equivalent to the usable logical eraseblock
|
||||
* size in case of dynamic volumes)
|
||||
* @data_pad: how many bytes at the end of logical eraseblocks of this volume
|
||||
* are not used (due to volume alignment)
|
||||
* @compat: compatibility flags of this volume
|
||||
|
@ -92,8 +90,8 @@ struct ubi_scan_volume {
|
|||
* @free: list of free physical eraseblocks
|
||||
* @erase: list of physical eraseblocks which have to be erased
|
||||
* @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
|
||||
* @bad_peb_count: count of bad physical eraseblocks
|
||||
* those belonging to "preserve"-compatible internal volumes)
|
||||
* @bad_peb_count: count of bad physical eraseblocks
|
||||
* @vols_found: number of volumes found during scanning
|
||||
* @highest_vol_id: highest volume ID
|
||||
* @alien_peb_count: count of physical eraseblocks in the @alien list
|
||||
|
@ -106,8 +104,8 @@ struct ubi_scan_volume {
|
|||
* @ec_count: a temporary variable used when calculating @mean_ec
|
||||
*
|
||||
* 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
|
||||
* on.
|
||||
* UBI sub-systems to build final UBI data structures, further error-recovery
|
||||
* and so on.
|
||||
*/
|
||||
struct ubi_scan_info {
|
||||
struct rb_root volumes;
|
||||
|
@ -132,8 +130,7 @@ struct ubi_device;
|
|||
struct ubi_vid_hdr;
|
||||
|
||||
/*
|
||||
* ubi_scan_move_to_list - move a physical eraseblock from the volume tree to a
|
||||
* list.
|
||||
* ubi_scan_move_to_list - move a PEB from the volume tree to a list.
|
||||
*
|
||||
* @sv: volume scanning information
|
||||
* @seb: scanning eraseblock infprmation
|
||||
|
|
|
@ -101,7 +101,8 @@ enum {
|
|||
* to the flash
|
||||
* @UBI_COMPAT_RO: attach this device in read-only mode
|
||||
* @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
|
||||
*/
|
||||
enum {
|
||||
|
@ -167,16 +168,15 @@ struct ubi_ec_hdr {
|
|||
* %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
|
||||
* @vol_id: ID of this volume
|
||||
* @lnum: logical eraseblock number
|
||||
* @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be
|
||||
* removed, kept only for not breaking older UBI users)
|
||||
* @padding1: reserved for future, zeroes
|
||||
* @data_size: how many bytes of data this logical eraseblock contains
|
||||
* @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
|
||||
* used
|
||||
* @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
|
||||
* @sqnum: sequence number
|
||||
* @padding3: reserved for future, zeroes
|
||||
* @hdr_crc: volume identifier header CRC checksum
|
||||
*
|
||||
* The @sqnum is the value of the global sequence counter at the time when this
|
||||
|
@ -224,10 +224,6 @@ struct ubi_ec_hdr {
|
|||
* checksum is correct, this physical eraseblock is selected (P1). Otherwise
|
||||
* 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.
|
||||
* 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
|
||||
|
@ -248,9 +244,9 @@ struct ubi_ec_hdr {
|
|||
* 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
|
||||
* 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
|
||||
* the wear-leveling unit calculates the data CRC and stores it in the
|
||||
* @data_crc field. And of course, the @copy_flag is %in this case.
|
||||
* data of the physical eraseblock was moved by the wear-leveling sub-system,
|
||||
* then the wear-leveling sub-system calculates the data CRC and stores it in
|
||||
* 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
|
||||
* how many bytes of data are stored in this eraseblock. For dynamic volumes,
|
||||
|
@ -277,14 +273,14 @@ struct ubi_vid_hdr {
|
|||
__u8 compat;
|
||||
__be32 vol_id;
|
||||
__be32 lnum;
|
||||
__be32 leb_ver; /* obsolete, to be removed, don't use */
|
||||
__u8 padding1[4];
|
||||
__be32 data_size;
|
||||
__be32 used_ebs;
|
||||
__be32 data_pad;
|
||||
__be32 data_crc;
|
||||
__u8 padding1[4];
|
||||
__u8 padding2[4];
|
||||
__be64 sqnum;
|
||||
__u8 padding2[12];
|
||||
__u8 padding3[12];
|
||||
__be32 hdr_crc;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
|
|
@ -74,10 +74,10 @@
|
|||
#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
|
||||
* 0xFF bytes
|
||||
* %0xFF bytes
|
||||
* 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
|
||||
* UBI_IO_BAD_EC_HDR: the erase counter header is corrupted (bad magic or CRC)
|
||||
|
@ -99,9 +99,9 @@ enum {
|
|||
* @ec: erase counter
|
||||
* @pnum: physical eraseblock number
|
||||
*
|
||||
* This data structure is used in the WL unit. Each physical eraseblock has a
|
||||
* corresponding &struct wl_entry object which may be kept in different
|
||||
* RB-trees. See WL unit for details.
|
||||
* This data structure is used in the WL sub-system. Each physical eraseblock
|
||||
* has a corresponding &struct wl_entry object which may be kept in different
|
||||
* RB-trees. See WL sub-system for details.
|
||||
*/
|
||||
struct ubi_wl_entry {
|
||||
struct rb_node rb;
|
||||
|
@ -118,10 +118,10 @@ struct ubi_wl_entry {
|
|||
* @mutex: read/write mutex to implement read/write access serialization to
|
||||
* the (@vol_id, @lnum) logical eraseblock
|
||||
*
|
||||
* This data structure is used in the EBA unit to implement per-LEB locking.
|
||||
* When a logical eraseblock is being locked - corresponding
|
||||
* This data structure is used in the EBA sub-system to implement per-LEB
|
||||
* locking. When a logical eraseblock is being locked - corresponding
|
||||
* &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 rb_node rb;
|
||||
|
@ -131,6 +131,27 @@ struct ubi_ltree_entry {
|
|||
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;
|
||||
|
||||
/**
|
||||
|
@ -225,7 +246,7 @@ struct ubi_volume {
|
|||
#ifdef CONFIG_MTD_UBI_GLUEBI
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
struct ubi_volume_desc *gluebi_desc;
|
||||
|
@ -235,8 +256,7 @@ struct ubi_volume {
|
|||
};
|
||||
|
||||
/**
|
||||
* struct ubi_volume_desc - descriptor of the UBI volume returned when it is
|
||||
* opened.
|
||||
* struct ubi_volume_desc - UBI volume descriptor returned when it is opened.
|
||||
* @vol: reference to the corresponding volume description object
|
||||
* @mode: open mode (%UBI_READONLY, %UBI_READWRITE, or %UBI_EXCLUSIVE)
|
||||
*/
|
||||
|
@ -273,7 +293,7 @@ struct ubi_wl_entry;
|
|||
* @vtbl_size: size of the volume table in bytes
|
||||
* @vtbl: in-RAM volume table copy
|
||||
* @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
|
||||
* @mean_ec: current mean erase counter value
|
||||
|
@ -293,6 +313,7 @@ struct ubi_wl_entry;
|
|||
* @move_to, @move_to_put @erase_pending, @wl_scheduled, and @works
|
||||
* fields
|
||||
* @move_mutex: serializes eraseblock moves
|
||||
* @work_sem: sycnhronizes the WL worker with use tasks
|
||||
* @wl_scheduled: non-zero if the wear-leveling was scheduled
|
||||
* @lookuptbl: a table to quickly find a &struct ubi_wl_entry object for any
|
||||
* physical eraseblock
|
||||
|
@ -331,6 +352,8 @@ struct ubi_wl_entry;
|
|||
* @peb_buf1: a 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
|
||||
* @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_buf_mutex: proptects @dbg_peb_buf
|
||||
*/
|
||||
|
@ -356,16 +379,16 @@ struct ubi_device {
|
|||
struct mutex volumes_mutex;
|
||||
|
||||
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;
|
||||
|
||||
/* EBA unit's stuff */
|
||||
/* EBA sub-system's stuff */
|
||||
unsigned long long global_sqnum;
|
||||
spinlock_t ltree_lock;
|
||||
struct rb_root ltree;
|
||||
struct mutex alc_mutex;
|
||||
|
||||
/* Wear-leveling unit's stuff */
|
||||
/* Wear-leveling sub-system's stuff */
|
||||
struct rb_root used;
|
||||
struct rb_root free;
|
||||
struct rb_root scrub;
|
||||
|
@ -388,7 +411,7 @@ struct ubi_device {
|
|||
int thread_enabled;
|
||||
char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2];
|
||||
|
||||
/* I/O unit's stuff */
|
||||
/* I/O sub-system's stuff */
|
||||
long long flash_size;
|
||||
int peb_count;
|
||||
int peb_size;
|
||||
|
@ -411,6 +434,7 @@ struct ubi_device {
|
|||
void *peb_buf2;
|
||||
struct mutex buf_mutex;
|
||||
struct mutex ckvol_mutex;
|
||||
struct mutex mult_mutex;
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG
|
||||
void *dbg_peb_buf;
|
||||
struct mutex dbg_buf_mutex;
|
||||
|
@ -427,12 +451,15 @@ extern struct mutex ubi_devices_mutex;
|
|||
/* vtbl.c */
|
||||
int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
|
||||
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);
|
||||
|
||||
/* vmt.c */
|
||||
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_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list);
|
||||
int ubi_add_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,
|
|||
const void __user *buf, int count);
|
||||
|
||||
/* 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);
|
||||
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,
|
|||
int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
|
||||
struct ubi_vid_hdr *vid_hdr);
|
||||
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 */
|
||||
int ubi_wl_get_peb(struct ubi_device *ubi, int dtype);
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/div64.h>
|
||||
#include "ubi.h"
|
||||
|
||||
|
@ -56,11 +56,11 @@ static int set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol)
|
|||
int err;
|
||||
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) {
|
||||
ubi_assert(ubi->vtbl[vol->vol_id].upd_marker);
|
||||
dbg_msg("already set");
|
||||
dbg_gen("already set");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol,
|
|||
uint64_t tmp;
|
||||
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],
|
||||
sizeof(struct ubi_vtbl_record));
|
||||
|
@ -133,7 +133,7 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
|
|||
int i, err;
|
||||
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);
|
||||
vol->updating = 1;
|
||||
|
||||
|
@ -183,7 +183,7 @@ int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
|
|||
{
|
||||
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);
|
||||
if (req->bytes == 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,
|
|||
int err;
|
||||
|
||||
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
|
||||
len = ALIGN(len, ubi->min_io_size);
|
||||
memset(buf + len, 0xFF, len - len);
|
||||
int l = ALIGN(len, ubi->min_io_size);
|
||||
|
||||
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) {
|
||||
dbg_msg("all %d bytes contain 0xFF - skip", len);
|
||||
dbg_gen("all %d bytes contain 0xFF - skip", len);
|
||||
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 {
|
||||
/*
|
||||
* 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,
|
|||
|
||||
/**
|
||||
* ubi_more_update_data - write more update data.
|
||||
* @ubi: UBI device description object
|
||||
* @vol: volume description object
|
||||
* @buf: write data (user-space memory buffer)
|
||||
* @count: how much bytes to write
|
||||
|
@ -283,7 +285,7 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
|
|||
uint64_t tmp;
|
||||
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);
|
||||
|
||||
if (ubi->ro_mode)
|
||||
|
@ -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: UBI device description object
|
||||
* @vol: volume description object
|
||||
* @buf: write data (user-space memory buffer)
|
||||
* @count: how much bytes to write
|
||||
|
@ -400,7 +403,7 @@ int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
|
|||
{
|
||||
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);
|
||||
|
||||
if (ubi->ro_mode)
|
||||
|
@ -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) {
|
||||
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);
|
||||
err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum,
|
||||
vol->upd_buf, len, UBI_UNKNOWN);
|
||||
|
|
|
@ -28,9 +28,9 @@
|
|||
#include "ubi.h"
|
||||
|
||||
#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
|
||||
#define paranoid_check_volumes(ubi)
|
||||
#define paranoid_check_volumes(ubi) 0
|
||||
#endif
|
||||
|
||||
static ssize_t vol_attribute_show(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);
|
||||
|
||||
kfree(vol->eba_tbl);
|
||||
kfree(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 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_vtbl_record vtbl_rec;
|
||||
uint64_t bytes;
|
||||
|
@ -217,7 +218,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
|
|||
spin_lock(&ubi->volumes_lock);
|
||||
if (vol_id == UBI_VOL_NUM_AUTO) {
|
||||
/* 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++)
|
||||
if (!ubi->volumes[i]) {
|
||||
vol_id = i;
|
||||
|
@ -232,7 +233,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
|
|||
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,
|
||||
(int)req->vol_type, req->name);
|
||||
|
||||
|
@ -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->vol_type = req->vol_type;
|
||||
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;
|
||||
|
||||
/*
|
||||
|
@ -349,7 +350,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
|
|||
vtbl_rec.vol_type = UBI_VID_DYNAMIC;
|
||||
else
|
||||
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);
|
||||
if (err)
|
||||
|
@ -360,19 +361,19 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
|
|||
ubi->vol_count += 1;
|
||||
spin_unlock(&ubi->volumes_lock);
|
||||
|
||||
paranoid_check_volumes(ubi);
|
||||
return 0;
|
||||
err = paranoid_check_volumes(ubi);
|
||||
return err;
|
||||
|
||||
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
|
||||
* freed by the release function.
|
||||
*
|
||||
* Get device reference to prevent the release function from being
|
||||
* called just after sysfs has been closed.
|
||||
*/
|
||||
dont_free = 1;
|
||||
do_free = 0;
|
||||
get_device(&vol->dev);
|
||||
volume_sysfs_close(vol);
|
||||
out_gluebi:
|
||||
|
@ -382,6 +383,7 @@ out_gluebi:
|
|||
out_cdev:
|
||||
cdev_del(&vol->cdev);
|
||||
out_mapping:
|
||||
if (do_free)
|
||||
kfree(vol->eba_tbl);
|
||||
out_acc:
|
||||
spin_lock(&ubi->volumes_lock);
|
||||
|
@ -389,10 +391,10 @@ out_acc:
|
|||
ubi->avail_pebs += vol->reserved_pebs;
|
||||
out_unlock:
|
||||
spin_unlock(&ubi->volumes_lock);
|
||||
if (dont_free)
|
||||
put_device(&vol->dev);
|
||||
else
|
||||
if (do_free)
|
||||
kfree(vol);
|
||||
else
|
||||
put_device(&vol->dev);
|
||||
ubi_err("cannot create volume %d, error %d", vol_id, err);
|
||||
return err;
|
||||
}
|
||||
|
@ -400,19 +402,20 @@ out_unlock:
|
|||
/**
|
||||
* ubi_remove_volume - remove volume.
|
||||
* @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
|
||||
* 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
|
||||
* 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_device *ubi = vol->ubi;
|
||||
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(vol == ubi->volumes[vol_id]);
|
||||
|
||||
|
@ -435,9 +438,11 @@ int ubi_remove_volume(struct ubi_volume_desc *desc)
|
|||
if (err)
|
||||
goto out_err;
|
||||
|
||||
if (!no_vtbl) {
|
||||
err = ubi_change_vtbl_record(ubi, vol_id, NULL);
|
||||
if (err)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
for (i = 0; i < vol->reserved_pebs; i++) {
|
||||
err = ubi_eba_unmap_leb(ubi, vol, i);
|
||||
|
@ -445,8 +450,6 @@ int ubi_remove_volume(struct ubi_volume_desc *desc)
|
|||
goto out_err;
|
||||
}
|
||||
|
||||
kfree(vol->eba_tbl);
|
||||
vol->eba_tbl = NULL;
|
||||
cdev_del(&vol->cdev);
|
||||
volume_sysfs_close(vol);
|
||||
|
||||
|
@ -465,8 +468,9 @@ int ubi_remove_volume(struct ubi_volume_desc *desc)
|
|||
ubi->vol_count -= 1;
|
||||
spin_unlock(&ubi->volumes_lock);
|
||||
|
||||
paranoid_check_volumes(ubi);
|
||||
return 0;
|
||||
if (!no_vtbl)
|
||||
err = paranoid_check_volumes(ubi);
|
||||
return err;
|
||||
|
||||
out_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)
|
|||
if (ubi->ro_mode)
|
||||
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);
|
||||
|
||||
if (vol->vol_type == UBI_STATIC_VOLUME &&
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
paranoid_check_volumes(ubi);
|
||||
return 0;
|
||||
err = paranoid_check_volumes(ubi);
|
||||
return err;
|
||||
|
||||
out_acc:
|
||||
if (pebs > 0) {
|
||||
|
@ -601,6 +605,44 @@ out_free:
|
|||
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: UBI device description object
|
||||
|
@ -615,8 +657,7 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
|
|||
int err, vol_id = vol->vol_id;
|
||||
dev_t dev;
|
||||
|
||||
dbg_msg("add volume %d", vol_id);
|
||||
ubi_dbg_dump_vol_info(vol);
|
||||
dbg_gen("add volume %d", vol_id);
|
||||
|
||||
/* Register character device for the volume */
|
||||
cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
|
||||
|
@ -650,8 +691,8 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
|
|||
return err;
|
||||
}
|
||||
|
||||
paranoid_check_volumes(ubi);
|
||||
return 0;
|
||||
err = paranoid_check_volumes(ubi);
|
||||
return err;
|
||||
|
||||
out_gluebi:
|
||||
err = ubi_destroy_gluebi(vol);
|
||||
|
@ -672,7 +713,7 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
|
|||
{
|
||||
int err;
|
||||
|
||||
dbg_msg("free volume %d", vol->vol_id);
|
||||
dbg_gen("free volume %d", vol->vol_id);
|
||||
|
||||
ubi->volumes[vol->vol_id] = NULL;
|
||||
err = ubi_destroy_gluebi(vol);
|
||||
|
@ -686,8 +727,10 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
|
|||
* paranoid_check_volume - check volume information.
|
||||
* @ubi: UBI device description object
|
||||
* @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 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)
|
|||
goto fail;
|
||||
}
|
||||
spin_unlock(&ubi->volumes_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
return 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)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
n = vol->alignment % ubi->min_io_size;
|
||||
n = vol->alignment & (ubi->min_io_size - 1);
|
||||
if (vol->alignment != 1 && n) {
|
||||
ubi_err("alignment is not multiple of min I/O unit");
|
||||
goto fail;
|
||||
|
@ -830,25 +864,33 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
|
|||
}
|
||||
|
||||
spin_unlock(&ubi->volumes_lock);
|
||||
return;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ubi_err("paranoid check failed for volume %d", vol_id);
|
||||
if (vol)
|
||||
ubi_dbg_dump_vol_info(vol);
|
||||
ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
|
||||
spin_unlock(&ubi->volumes_lock);
|
||||
BUG();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* paranoid_check_volumes - check information about all volumes.
|
||||
* @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++)
|
||||
paranoid_check_volume(ubi, i);
|
||||
for (i = 0; i < ubi->vtbl_slots; i++) {
|
||||
err = paranoid_check_volume(ubi, i);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
* data.
|
||||
* ubi_vtbl_rename_volumes - rename UBI volumes in the volume table.
|
||||
* @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
|
||||
* @vtbl: volume table
|
||||
*
|
||||
|
@ -127,7 +177,7 @@ static int vtbl_check(const struct ubi_device *ubi,
|
|||
const struct ubi_vtbl_record *vtbl)
|
||||
{
|
||||
int i, n, reserved_pebs, alignment, data_pad, vol_type, name_len;
|
||||
int upd_marker;
|
||||
int upd_marker, err;
|
||||
uint32_t crc;
|
||||
const char *name;
|
||||
|
||||
|
@ -153,7 +203,7 @@ static int vtbl_check(const struct ubi_device *ubi,
|
|||
if (reserved_pebs == 0) {
|
||||
if (memcmp(&vtbl[i], &empty_vtbl_record,
|
||||
UBI_VTBL_RECORD_SIZE)) {
|
||||
dbg_err("bad empty record");
|
||||
err = 2;
|
||||
goto bad;
|
||||
}
|
||||
continue;
|
||||
|
@ -161,56 +211,57 @@ static int vtbl_check(const struct ubi_device *ubi,
|
|||
|
||||
if (reserved_pebs < 0 || alignment < 0 || data_pad < 0 ||
|
||||
name_len < 0) {
|
||||
dbg_err("negative values");
|
||||
err = 3;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (alignment > ubi->leb_size || alignment == 0) {
|
||||
dbg_err("bad alignment");
|
||||
err = 4;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
n = alignment % ubi->min_io_size;
|
||||
n = alignment & (ubi->min_io_size - 1);
|
||||
if (alignment != 1 && n) {
|
||||
dbg_err("alignment is not multiple of min I/O unit");
|
||||
err = 5;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
n = ubi->leb_size % alignment;
|
||||
if (data_pad != n) {
|
||||
dbg_err("bad data_pad, has to be %d", n);
|
||||
err = 6;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) {
|
||||
dbg_err("bad vol_type");
|
||||
err = 7;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (upd_marker != 0 && upd_marker != 1) {
|
||||
dbg_err("bad upd_marker");
|
||||
err = 8;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (reserved_pebs > ubi->good_peb_count) {
|
||||
dbg_err("too large reserved_pebs, good PEBs %d",
|
||||
ubi->good_peb_count);
|
||||
err = 9;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (name_len > UBI_VOL_NAME_MAX) {
|
||||
dbg_err("too long volume name, max %d",
|
||||
UBI_VOL_NAME_MAX);
|
||||
err = 10;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (name[0] == '\0') {
|
||||
dbg_err("NULL volume name");
|
||||
err = 11;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (name_len != strnlen(name, name_len + 1)) {
|
||||
dbg_err("bad name_len");
|
||||
err = 12;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
@ -235,7 +286,7 @@ static int vtbl_check(const struct ubi_device *ubi,
|
|||
return 0;
|
||||
|
||||
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);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -287,7 +338,6 @@ retry:
|
|||
vid_hdr->data_pad = cpu_to_be32(0);
|
||||
vid_hdr->lnum = cpu_to_be32(copy);
|
||||
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 */
|
||||
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,
|
|||
* to LEB 0.
|
||||
*/
|
||||
|
||||
dbg_msg("check layout volume");
|
||||
dbg_gen("check layout volume");
|
||||
|
||||
/* Read both LEB 0 and LEB 1 into memory */
|
||||
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,
|
|||
err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
|
||||
ubi->vtbl_size);
|
||||
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;
|
||||
else if (err)
|
||||
goto out_free;
|
||||
|
@ -400,7 +459,8 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
|
|||
if (!leb_corrupted[0]) {
|
||||
/* LEB 0 is OK */
|
||||
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]) {
|
||||
ubi_warn("volume table copy #2 is corrupted");
|
||||
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,
|
|||
static int check_sv(const struct ubi_volume *vol,
|
||||
const struct ubi_scan_volume *sv)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (sv->highest_lnum >= vol->reserved_pebs) {
|
||||
dbg_err("bad highest_lnum");
|
||||
err = 1;
|
||||
goto bad;
|
||||
}
|
||||
if (sv->leb_count > vol->reserved_pebs) {
|
||||
dbg_err("bad leb_count");
|
||||
err = 2;
|
||||
goto bad;
|
||||
}
|
||||
if (sv->vol_type != vol->vol_type) {
|
||||
dbg_err("bad vol_type");
|
||||
err = 3;
|
||||
goto bad;
|
||||
}
|
||||
if (sv->used_ebs > vol->reserved_pebs) {
|
||||
dbg_err("bad used_ebs");
|
||||
err = 4;
|
||||
goto bad;
|
||||
}
|
||||
if (sv->data_pad != vol->data_pad) {
|
||||
dbg_err("bad data_pad");
|
||||
err = 5;
|
||||
goto bad;
|
||||
}
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
ubi_err("bad scanning information");
|
||||
ubi_err("bad scanning information, error %d", err);
|
||||
ubi_dbg_dump_sv(sv);
|
||||
ubi_dbg_dump_vol_info(vol);
|
||||
return -EINVAL;
|
||||
|
@ -679,7 +741,6 @@ static int check_scanning_info(const struct ubi_device *ubi,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
|
||||
cond_resched();
|
||||
|
||||
|
@ -717,8 +778,7 @@ static int check_scanning_info(const struct ubi_device *ubi,
|
|||
}
|
||||
|
||||
/**
|
||||
* ubi_read_volume_table - read volume table.
|
||||
* information.
|
||||
* ubi_read_volume_table - read the volume table.
|
||||
* @ubi: UBI device description object
|
||||
* @si: scanning information
|
||||
*
|
||||
|
@ -797,8 +857,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
|
|||
|
||||
out_free:
|
||||
vfree(ubi->vtbl);
|
||||
for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++)
|
||||
if (ubi->volumes[i]) {
|
||||
for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
|
||||
kfree(ubi->volumes[i]);
|
||||
ubi->volumes[i] = NULL;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
* eraseblocks and erase counters and knows nothing about logical eraseblocks,
|
||||
* volumes, etc. From this unit's perspective all physical eraseblocks are of
|
||||
* two types - used and free. Used physical eraseblocks are those that were
|
||||
* "get" by the 'ubi_wl_get_peb()' function, and free physical eraseblocks are
|
||||
* those that were put by the 'ubi_wl_put_peb()' function.
|
||||
* This sub-system is responsible for wear-leveling. It works in terms of
|
||||
* physical* eraseblocks and erase counters and knows nothing about logical
|
||||
* eraseblocks, volumes, etc. From this sub-system's perspective all physical
|
||||
* eraseblocks are of two types - used and free. Used physical eraseblocks are
|
||||
* those that were "get" by the 'ubi_wl_get_peb()' function, and free physical
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
* physical eraseblocks with low erase counter to free physical eraseblocks
|
||||
|
@ -43,34 +43,36 @@
|
|||
* 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
|
||||
* 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
|
||||
* so forth.
|
||||
* the WL sub-system may pick a free physical eraseblock with low erase
|
||||
* 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
|
||||
* physical eraseblock, it has to be moved. Technically this is the same as
|
||||
* moving it for wear-leveling reasons.
|
||||
* This sub-system is also responsible for scrubbing. If a bit-flip is detected
|
||||
* in a physical eraseblock, it has to be moved. Technically this is the same
|
||||
* as moving it for wear-leveling reasons.
|
||||
*
|
||||
* As it was said, for the UBI unit all physical eraseblocks are either "free"
|
||||
* or "used". Free eraseblock are kept in the @wl->free RB-tree, while used
|
||||
* eraseblocks are kept in a set of different RB-trees: @wl->used,
|
||||
* As it was said, for the UBI sub-system all physical eraseblocks are either
|
||||
* "free" or "used". Free eraseblock are kept in the @wl->free RB-tree, while
|
||||
* used eraseblocks are kept in a set of different RB-trees: @wl->used,
|
||||
* @wl->prot.pnum, @wl->prot.aec, and @wl->scrub.
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* introduced relatively recently. But it would be wise to do this because the
|
||||
* sequence number of a logical eraseblock characterizes how old is it. For
|
||||
* At the moment this sub-system does not utilize the sequence number, which
|
||||
* was introduced relatively recently. But it would be wise to do this because
|
||||
* 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
|
||||
* 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
|
||||
* 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>
|
||||
|
@ -92,20 +94,21 @@
|
|||
|
||||
/*
|
||||
* Maximum difference between two erase counters. If this threshold is
|
||||
* exceeded, the WL unit starts moving data from used physical eraseblocks with
|
||||
* low erase counter to free physical eraseblocks with high erase counter.
|
||||
* exceeded, the WL sub-system starts moving data from used physical
|
||||
* eraseblocks with low erase counter to free physical eraseblocks with high
|
||||
* erase counter.
|
||||
*/
|
||||
#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
|
||||
* 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
|
||||
* 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
|
||||
* counter of the free physical eraseblock to pick. Namely, the WL unit does
|
||||
* not pick eraseblocks with erase counter greater then the lowest erase
|
||||
* counter of the free physical eraseblock to pick. Namely, the WL sub-system
|
||||
* does not pick eraseblocks with erase counter greater then the lowest erase
|
||||
* counter plus %WL_FREE_MAX_DIFF.
|
||||
*/
|
||||
#define WL_FREE_MAX_DIFF (2*UBI_WL_THRESHOLD)
|
||||
|
@ -123,11 +126,11 @@
|
|||
* @abs_ec: the absolute erase counter value when the protection ends
|
||||
* @e: the wear-leveling entry of the physical eraseblock under protection
|
||||
*
|
||||
* When the WL unit returns a physical eraseblock, the physical eraseblock is
|
||||
* protected from being moved for some "time". For this reason, the physical
|
||||
* eraseblock is not directly moved from the @wl->free tree to the @wl->used
|
||||
* tree. There is one more tree in between where this physical eraseblock is
|
||||
* temporarily stored (@wl->prot).
|
||||
* When the WL sub-system returns a physical eraseblock, the physical
|
||||
* eraseblock is protected from being moved for some "time". For this reason,
|
||||
* the physical eraseblock is not directly moved from the @wl->free tree to the
|
||||
* @wl->used tree. There is one more tree in between where this physical
|
||||
* eraseblock is temporarily stored (@wl->prot).
|
||||
*
|
||||
* All this protection stuff is needed because:
|
||||
* o we don't want to move physical eraseblocks just after we have given them
|
||||
|
@ -175,7 +178,6 @@ struct ubi_wl_prot_entry {
|
|||
* @list: a link in the list of pending works
|
||||
* @func: worker function
|
||||
* @priv: private data of the worker function
|
||||
*
|
||||
* @e: physical eraseblock to erase
|
||||
* @torture: if the physical eraseblock has to be tortured
|
||||
*
|
||||
|
@ -475,26 +477,23 @@ retry:
|
|||
switch (dtype) {
|
||||
case UBI_LONGTERM:
|
||||
/*
|
||||
* For long term data we pick a physical eraseblock
|
||||
* with high erase counter. But the highest erase
|
||||
* counter we can pick is bounded by the the lowest
|
||||
* erase counter plus %WL_FREE_MAX_DIFF.
|
||||
* For long term data we pick a physical eraseblock with high
|
||||
* erase counter. But the highest erase counter we can pick is
|
||||
* bounded by the the lowest erase counter plus
|
||||
* %WL_FREE_MAX_DIFF.
|
||||
*/
|
||||
e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
|
||||
protect = LT_PROTECTION;
|
||||
break;
|
||||
case UBI_UNKNOWN:
|
||||
/*
|
||||
* For unknown data we pick a physical eraseblock with
|
||||
* medium erase counter. But we by no means can pick a
|
||||
* physical eraseblock with erase counter greater or
|
||||
* equivalent than the lowest erase counter plus
|
||||
* %WL_FREE_MAX_DIFF.
|
||||
* For unknown data we pick a physical eraseblock with medium
|
||||
* erase counter. But we by no means can pick a physical
|
||||
* eraseblock with erase counter greater or equivalent than the
|
||||
* lowest erase counter plus %WL_FREE_MAX_DIFF.
|
||||
*/
|
||||
first = rb_entry(rb_first(&ubi->free),
|
||||
struct ubi_wl_entry, rb);
|
||||
last = rb_entry(rb_last(&ubi->free),
|
||||
struct ubi_wl_entry, rb);
|
||||
first = rb_entry(rb_first(&ubi->free), 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)
|
||||
e = rb_entry(ubi->free.rb_node,
|
||||
|
@ -507,12 +506,10 @@ retry:
|
|||
break;
|
||||
case UBI_SHORTTERM:
|
||||
/*
|
||||
* For short term data we pick a physical eraseblock
|
||||
* with the lowest erase counter as we expect it will
|
||||
* be erased soon.
|
||||
* For short term data we pick a physical eraseblock with the
|
||||
* lowest erase counter as we expect it will be erased soon.
|
||||
*/
|
||||
e = rb_entry(rb_first(&ubi->free),
|
||||
struct ubi_wl_entry, rb);
|
||||
e = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry, rb);
|
||||
protect = ST_PROTECTION;
|
||||
break;
|
||||
default:
|
||||
|
@ -582,7 +579,8 @@ found:
|
|||
* This function returns zero in case of success and a negative error code in
|
||||
* 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;
|
||||
struct ubi_ec_hdr *ec_hdr;
|
||||
|
@ -634,8 +632,7 @@ out_free:
|
|||
}
|
||||
|
||||
/**
|
||||
* check_protection_over - check if it is time to stop protecting some
|
||||
* physical eraseblocks.
|
||||
* check_protection_over - check if it is time to stop protecting some PEBs.
|
||||
* @ubi: UBI device description object
|
||||
*
|
||||
* 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,
|
|||
}
|
||||
|
||||
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);
|
||||
if (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,
|
|||
spin_unlock(&ubi->wl_lock);
|
||||
|
||||
/*
|
||||
* One more erase operation has happened, take care about protected
|
||||
* physical eraseblocks.
|
||||
* One more erase operation has happened, take care about
|
||||
* protected physical eraseblocks.
|
||||
*/
|
||||
check_protection_over(ubi);
|
||||
|
||||
|
@ -1136,7 +1137,7 @@ out_ro:
|
|||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @pnum: physical eraseblock to return
|
||||
* @torture: if this physical eraseblock has to be tortured
|
||||
|
@ -1175,11 +1176,11 @@ retry:
|
|||
/*
|
||||
* User is putting the physical eraseblock which was selected
|
||||
* 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
|
||||
* the WL unit has not put the PEB to the "used" tree yet, but
|
||||
* it is about to do this. So we just set a flag which will
|
||||
* tell the WL worker that the PEB is not needed anymore and
|
||||
* should be scheduled for erasure.
|
||||
* sub-system already re-mapped the LEB in 'ubi_eba_copy_leb()'
|
||||
* but the WL sub-system has not put the PEB to the "used" tree
|
||||
* yet, but it is about to do this. So we just set a flag which
|
||||
* will tell the WL worker that the PEB is not needed anymore
|
||||
* and should be scheduled for erasure.
|
||||
*/
|
||||
dbg_wl("PEB %d is the target of data moving", pnum);
|
||||
ubi_assert(!ubi->move_to_put);
|
||||
|
@ -1229,7 +1230,7 @@ int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum)
|
|||
{
|
||||
struct ubi_wl_entry *e;
|
||||
|
||||
ubi_msg("schedule PEB %d for scrubbing", pnum);
|
||||
dbg_msg("schedule PEB %d for scrubbing", pnum);
|
||||
|
||||
retry:
|
||||
spin_lock(&ubi->wl_lock);
|
||||
|
@ -1368,7 +1369,7 @@ int ubi_thread(void *u)
|
|||
int err;
|
||||
|
||||
if (kthread_should_stop())
|
||||
goto out;
|
||||
break;
|
||||
|
||||
if (try_to_freeze())
|
||||
continue;
|
||||
|
@ -1403,7 +1404,6 @@ int ubi_thread(void *u)
|
|||
cond_resched();
|
||||
}
|
||||
|
||||
out:
|
||||
dbg_wl("background thread \"%s\" is killed", ubi->bgt_name);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1426,8 +1426,7 @@ static void cancel_pending(struct ubi_device *ubi)
|
|||
}
|
||||
|
||||
/**
|
||||
* ubi_wl_init_scan - initialize the wear-leveling unit using scanning
|
||||
* information.
|
||||
* ubi_wl_init_scan - initialize the WL sub-system using scanning information.
|
||||
* @ubi: UBI device description object
|
||||
* @si: scanning information
|
||||
*
|
||||
|
@ -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
|
||||
*/
|
||||
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);
|
||||
protection_trees_destroy(ubi);
|
||||
tree_destroy(&ubi->used);
|
||||
|
@ -1602,8 +1600,7 @@ void ubi_wl_close(struct ubi_device *ubi)
|
|||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
|
||||
/**
|
||||
* paranoid_check_ec - make sure that the erase counter of a physical eraseblock
|
||||
* is correct.
|
||||
* paranoid_check_ec - make sure that the erase counter of a PEB is correct.
|
||||
* @ubi: UBI device description object
|
||||
* @pnum: the physical eraseblock number to check
|
||||
* @ec: the erase counter to check
|
||||
|
@ -1644,13 +1641,12 @@ out_free:
|
|||
}
|
||||
|
||||
/**
|
||||
* paranoid_check_in_wl_tree - make sure that a wear-leveling entry is present
|
||||
* in a WL RB-tree.
|
||||
* paranoid_check_in_wl_tree - check that wear-leveling entry is in WL RB-tree.
|
||||
* @e: the wear-leveling entry to check
|
||||
* @root: the root of the tree
|
||||
*
|
||||
* This function returns zero if @e is in the @root RB-tree and %1 if it
|
||||
* is not.
|
||||
* This function returns zero if @e is in the @root RB-tree and %1 if it is
|
||||
* not.
|
||||
*/
|
||||
static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
|
||||
struct rb_root *root)
|
||||
|
|
|
@ -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_map(struct ubi_volume_desc *desc, int lnum, int dtype);
|
||||
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
|
||||
|
|
|
@ -58,6 +58,13 @@
|
|||
* 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.
|
||||
*
|
||||
* 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
|
||||
* ~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
|
@ -104,6 +111,8 @@
|
|||
#define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t)
|
||||
/* Re-size an UBI volume */
|
||||
#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 */
|
||||
|
||||
|
@ -128,6 +137,9 @@
|
|||
/* Maximum MTD device name length supported by UBI */
|
||||
#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.
|
||||
*
|
||||
|
@ -176,20 +188,20 @@ enum {
|
|||
* 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
|
||||
* a different offset. For example, the boot-loader might do things faster if the
|
||||
* VID header sits at the end of the first 2KiB NAND page with 4 sub-pages. As
|
||||
* the boot-loader would not normally need to read EC headers (unless it needs
|
||||
* UBI in RW mode), it might be faster to calculate ECC. This is weird example,
|
||||
* but it real-life example. So, in this example, @vid_hdr_offer would 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
|
||||
* of the first page and add needed padding.
|
||||
* a different offset. For example, the boot-loader might do things faster if
|
||||
* the VID header sits at the end of the first 2KiB NAND page with 4 sub-pages.
|
||||
* As the boot-loader would not normally need to read EC headers (unless it
|
||||
* needs UBI in RW mode), it might be faster to calculate ECC. This is weird
|
||||
* example, but it real-life example. So, in this example, @vid_hdr_offer would
|
||||
* 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 of the first page and add needed padding.
|
||||
*/
|
||||
struct ubi_attach_req {
|
||||
int32_t ubi_num;
|
||||
int32_t mtd_num;
|
||||
int32_t vid_hdr_offset;
|
||||
uint8_t padding[12];
|
||||
int8_t padding[12];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -250,6 +262,48 @@ struct ubi_rsvol_req {
|
|||
int32_t vol_id;
|
||||
} __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
|
||||
* eraseblock change requests.
|
||||
|
@ -261,8 +315,8 @@ struct ubi_rsvol_req {
|
|||
struct ubi_leb_change_req {
|
||||
int32_t lnum;
|
||||
int32_t bytes;
|
||||
uint8_t dtype;
|
||||
uint8_t padding[7];
|
||||
int8_t dtype;
|
||||
int8_t padding[7];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#endif /* __UBI_USER_H__ */
|
||||
|
|
Loading…
Reference in a new issue