forked from Minki/linux
Merge git://git.infradead.org/~dedekind/ubi-2.6
This commit is contained in:
commit
6208e77e7f
@ -66,9 +66,6 @@ static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES];
|
||||
/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
|
||||
struct class *ubi_class;
|
||||
|
||||
/* Slab cache for lock-tree entries */
|
||||
struct kmem_cache *ubi_ltree_slab;
|
||||
|
||||
/* Slab cache for wear-leveling entries */
|
||||
struct kmem_cache *ubi_wl_entry_slab;
|
||||
|
||||
@ -369,9 +366,6 @@ static int uif_init(struct ubi_device *ubi)
|
||||
int i, err;
|
||||
dev_t dev;
|
||||
|
||||
mutex_init(&ubi->volumes_mutex);
|
||||
spin_lock_init(&ubi->volumes_lock);
|
||||
|
||||
sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);
|
||||
|
||||
/*
|
||||
@ -568,7 +562,7 @@ static int io_init(struct ubi_device *ubi)
|
||||
}
|
||||
|
||||
/* Similar for the data offset */
|
||||
ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize;
|
||||
ubi->leb_start = ubi->vid_hdr_offset + UBI_EC_HDR_SIZE;
|
||||
ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
|
||||
|
||||
dbg_msg("vid_hdr_offset %d", ubi->vid_hdr_offset);
|
||||
@ -626,6 +620,58 @@ static int io_init(struct ubi_device *ubi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* autoresize - re-size the volume which has the "auto-resize" flag set.
|
||||
* @ubi: UBI device description object
|
||||
* @vol_id: ID of the volume to re-size
|
||||
*
|
||||
* This function re-sizes the volume marked by the @UBI_VTBL_AUTORESIZE_FLG in
|
||||
* the volume table to the largest possible size. See comments in ubi-header.h
|
||||
* for more description of the flag. Returns zero in case of success and a
|
||||
* negative error code in case of failure.
|
||||
*/
|
||||
static int autoresize(struct ubi_device *ubi, int vol_id)
|
||||
{
|
||||
struct ubi_volume_desc desc;
|
||||
struct ubi_volume *vol = ubi->volumes[vol_id];
|
||||
int err, old_reserved_pebs = vol->reserved_pebs;
|
||||
|
||||
/*
|
||||
* Clear the auto-resize flag in the volume in-memory copy of the
|
||||
* volume table, and 'ubi_resize_volume()' will propogate this change
|
||||
* to the flash.
|
||||
*/
|
||||
ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG;
|
||||
|
||||
if (ubi->avail_pebs == 0) {
|
||||
struct ubi_vtbl_record vtbl_rec;
|
||||
|
||||
/*
|
||||
* No avalilable PEBs to re-size the volume, clear the flag on
|
||||
* flash and exit.
|
||||
*/
|
||||
memcpy(&vtbl_rec, &ubi->vtbl[vol_id],
|
||||
sizeof(struct ubi_vtbl_record));
|
||||
err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
|
||||
if (err)
|
||||
ubi_err("cannot clean auto-resize flag for volume %d",
|
||||
vol_id);
|
||||
} else {
|
||||
desc.vol = vol;
|
||||
err = ubi_resize_volume(&desc,
|
||||
old_reserved_pebs + ubi->avail_pebs);
|
||||
if (err)
|
||||
ubi_err("cannot auto-resize volume %d", vol_id);
|
||||
}
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id,
|
||||
vol->name, old_reserved_pebs, vol->reserved_pebs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubi_attach_mtd_dev - attach an MTD device.
|
||||
* @mtd_dev: MTD device description object
|
||||
@ -702,6 +748,12 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
|
||||
ubi->mtd = mtd;
|
||||
ubi->ubi_num = ubi_num;
|
||||
ubi->vid_hdr_offset = vid_hdr_offset;
|
||||
ubi->autoresize_vol_id = -1;
|
||||
|
||||
mutex_init(&ubi->buf_mutex);
|
||||
mutex_init(&ubi->ckvol_mutex);
|
||||
mutex_init(&ubi->volumes_mutex);
|
||||
spin_lock_init(&ubi->volumes_lock);
|
||||
|
||||
dbg_msg("attaching mtd%d to ubi%d: VID header offset %d",
|
||||
mtd->index, ubi_num, vid_hdr_offset);
|
||||
@ -710,8 +762,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
|
||||
if (err)
|
||||
goto out_free;
|
||||
|
||||
mutex_init(&ubi->buf_mutex);
|
||||
mutex_init(&ubi->ckvol_mutex);
|
||||
ubi->peb_buf1 = vmalloc(ubi->peb_size);
|
||||
if (!ubi->peb_buf1)
|
||||
goto out_free;
|
||||
@ -733,6 +783,12 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (ubi->autoresize_vol_id != -1) {
|
||||
err = autoresize(ubi, ubi->autoresize_vol_id);
|
||||
if (err)
|
||||
goto out_detach;
|
||||
}
|
||||
|
||||
err = uif_init(ubi);
|
||||
if (err)
|
||||
goto out_detach;
|
||||
@ -857,20 +913,6 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ltree_entry_ctor - lock tree entries slab cache constructor.
|
||||
* @obj: the lock-tree entry to construct
|
||||
* @cache: the lock tree entry slab cache
|
||||
* @flags: constructor flags
|
||||
*/
|
||||
static void ltree_entry_ctor(struct kmem_cache *cache, void *obj)
|
||||
{
|
||||
struct ubi_ltree_entry *le = obj;
|
||||
|
||||
le->users = 0;
|
||||
init_rwsem(&le->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* find_mtd_device - open an MTD device by its name or number.
|
||||
* @mtd_dev: name or number of the device
|
||||
@ -933,17 +975,11 @@ static int __init ubi_init(void)
|
||||
goto out_version;
|
||||
}
|
||||
|
||||
ubi_ltree_slab = kmem_cache_create("ubi_ltree_slab",
|
||||
sizeof(struct ubi_ltree_entry), 0,
|
||||
0, <ree_entry_ctor);
|
||||
if (!ubi_ltree_slab)
|
||||
goto out_dev_unreg;
|
||||
|
||||
ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
|
||||
sizeof(struct ubi_wl_entry),
|
||||
0, 0, NULL);
|
||||
if (!ubi_wl_entry_slab)
|
||||
goto out_ltree;
|
||||
goto out_dev_unreg;
|
||||
|
||||
/* Attach MTD devices */
|
||||
for (i = 0; i < mtd_devs; i++) {
|
||||
@ -980,8 +1016,6 @@ out_detach:
|
||||
mutex_unlock(&ubi_devices_mutex);
|
||||
}
|
||||
kmem_cache_destroy(ubi_wl_entry_slab);
|
||||
out_ltree:
|
||||
kmem_cache_destroy(ubi_ltree_slab);
|
||||
out_dev_unreg:
|
||||
misc_deregister(&ubi_ctrl_cdev);
|
||||
out_version:
|
||||
@ -1005,7 +1039,6 @@ static void __exit ubi_exit(void)
|
||||
mutex_unlock(&ubi_devices_mutex);
|
||||
}
|
||||
kmem_cache_destroy(ubi_wl_entry_slab);
|
||||
kmem_cache_destroy(ubi_ltree_slab);
|
||||
misc_deregister(&ubi_ctrl_cdev);
|
||||
class_remove_file(ubi_class, &ubi_version);
|
||||
class_destroy(ubi_class);
|
||||
@ -1066,7 +1099,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
|
||||
struct mtd_dev_param *p;
|
||||
char buf[MTD_PARAM_LEN_MAX];
|
||||
char *pbuf = &buf[0];
|
||||
char *tokens[3] = {NULL, NULL, NULL};
|
||||
char *tokens[2] = {NULL, NULL};
|
||||
|
||||
if (!val)
|
||||
return -EINVAL;
|
||||
@ -1096,7 +1129,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
|
||||
if (buf[len - 1] == '\n')
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
for (i = 0; i < 2; i++)
|
||||
tokens[i] = strsep(&pbuf, ",");
|
||||
|
||||
if (pbuf) {
|
||||
|
@ -132,8 +132,15 @@ static int vol_cdev_release(struct inode *inode, struct file *file)
|
||||
if (vol->updating) {
|
||||
ubi_warn("update of volume %d not finished, volume is damaged",
|
||||
vol->vol_id);
|
||||
ubi_assert(!vol->changing_leb);
|
||||
vol->updating = 0;
|
||||
vfree(vol->upd_buf);
|
||||
} else if (vol->changing_leb) {
|
||||
dbg_msg("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;
|
||||
vfree(vol->upd_buf);
|
||||
}
|
||||
|
||||
ubi_close_volume(desc);
|
||||
@ -184,13 +191,13 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
|
||||
struct ubi_volume_desc *desc = file->private_data;
|
||||
struct ubi_volume *vol = desc->vol;
|
||||
struct ubi_device *ubi = vol->ubi;
|
||||
int err, lnum, off, len, vol_id = desc->vol->vol_id, tbuf_size;
|
||||
int err, lnum, off, len, tbuf_size;
|
||||
size_t count_save = count;
|
||||
void *tbuf;
|
||||
uint64_t tmp;
|
||||
|
||||
dbg_msg("read %zd bytes from offset %lld of volume %d",
|
||||
count, *offp, vol_id);
|
||||
count, *offp, vol->vol_id);
|
||||
|
||||
if (vol->updating) {
|
||||
dbg_err("updating");
|
||||
@ -204,7 +211,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_id);
|
||||
dbg_msg("read from corrupted volume %d", vol->vol_id);
|
||||
|
||||
if (*offp + count > vol->used_bytes)
|
||||
count_save = count = vol->used_bytes - *offp;
|
||||
@ -274,7 +281,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
|
||||
uint64_t tmp;
|
||||
|
||||
dbg_msg("requested: write %zd bytes to offset %lld of volume %u",
|
||||
count, *offp, desc->vol->vol_id);
|
||||
count, *offp, vol->vol_id);
|
||||
|
||||
if (vol->vol_type == UBI_STATIC_VOLUME)
|
||||
return -EROFS;
|
||||
@ -351,23 +358,32 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
|
||||
struct ubi_volume *vol = desc->vol;
|
||||
struct ubi_device *ubi = vol->ubi;
|
||||
|
||||
if (!vol->updating)
|
||||
if (!vol->updating && !vol->changing_leb)
|
||||
return vol_cdev_direct_write(file, buf, count, offp);
|
||||
|
||||
err = ubi_more_update_data(ubi, vol->vol_id, buf, count);
|
||||
if (vol->updating)
|
||||
err = ubi_more_update_data(ubi, vol, buf, count);
|
||||
else
|
||||
err = ubi_more_leb_change_data(ubi, vol, buf, count);
|
||||
|
||||
if (err < 0) {
|
||||
ubi_err("cannot write %zd bytes of update data, error %d",
|
||||
ubi_err("cannot accept more %zd bytes of data, error %d",
|
||||
count, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
/*
|
||||
* Update is finished, @err contains number of actually written
|
||||
* bytes now.
|
||||
* The operation is finished, @err contains number of actually
|
||||
* written bytes.
|
||||
*/
|
||||
count = err;
|
||||
|
||||
if (vol->changing_leb) {
|
||||
revoke_exclusive(desc, UBI_READWRITE);
|
||||
return count;
|
||||
}
|
||||
|
||||
err = ubi_check_volume(ubi, vol->vol_id);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@ -382,7 +398,6 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
|
||||
revoke_exclusive(desc, UBI_READWRITE);
|
||||
}
|
||||
|
||||
*offp += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -427,11 +442,46 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
|
||||
if (err < 0)
|
||||
break;
|
||||
|
||||
err = ubi_start_update(ubi, vol->vol_id, bytes);
|
||||
err = ubi_start_update(ubi, vol, bytes);
|
||||
if (bytes == 0)
|
||||
revoke_exclusive(desc, UBI_READWRITE);
|
||||
break;
|
||||
}
|
||||
|
||||
file->f_pos = 0;
|
||||
/* Atomic logical eraseblock change command */
|
||||
case UBI_IOCEBCH:
|
||||
{
|
||||
struct ubi_leb_change_req req;
|
||||
|
||||
err = copy_from_user(&req, argp,
|
||||
sizeof(struct ubi_leb_change_req));
|
||||
if (err) {
|
||||
err = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (desc->mode == UBI_READONLY ||
|
||||
vol->vol_type == UBI_STATIC_VOLUME) {
|
||||
err = -EROFS;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Validate the request */
|
||||
err = -EINVAL;
|
||||
if (req.lnum < 0 || req.lnum >= vol->reserved_pebs ||
|
||||
req.bytes < 0 || req.lnum >= vol->usable_leb_size)
|
||||
break;
|
||||
if (req.dtype != UBI_LONGTERM && req.dtype != UBI_SHORTTERM &&
|
||||
req.dtype != UBI_UNKNOWN)
|
||||
break;
|
||||
|
||||
err = get_exclusive(desc);
|
||||
if (err < 0)
|
||||
break;
|
||||
|
||||
err = ubi_start_leb_change(ubi, vol, &req);
|
||||
if (req.bytes == 0)
|
||||
revoke_exclusive(desc, UBI_READWRITE);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -447,7 +497,8 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
|
||||
break;
|
||||
}
|
||||
|
||||
if (desc->mode == UBI_READONLY) {
|
||||
if (desc->mode == UBI_READONLY ||
|
||||
vol->vol_type == UBI_STATIC_VOLUME) {
|
||||
err = -EROFS;
|
||||
break;
|
||||
}
|
||||
@ -457,11 +508,6 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
|
||||
break;
|
||||
}
|
||||
|
||||
if (vol->vol_type != UBI_DYNAMIC_VOLUME) {
|
||||
err = -EROFS;
|
||||
break;
|
||||
}
|
||||
|
||||
dbg_msg("erase LEB %d:%d", vol->vol_id, lnum);
|
||||
err = ubi_eba_unmap_leb(ubi, vol, lnum);
|
||||
if (err)
|
||||
|
@ -78,7 +78,7 @@ static unsigned long long next_sqnum(struct ubi_device *ubi)
|
||||
*/
|
||||
static int ubi_get_compat(const struct ubi_device *ubi, int vol_id)
|
||||
{
|
||||
if (vol_id == UBI_LAYOUT_VOL_ID)
|
||||
if (vol_id == UBI_LAYOUT_VOLUME_ID)
|
||||
return UBI_LAYOUT_VOLUME_COMPAT;
|
||||
return 0;
|
||||
}
|
||||
@ -137,10 +137,12 @@ static struct ubi_ltree_entry *ltree_add_entry(struct ubi_device *ubi,
|
||||
{
|
||||
struct ubi_ltree_entry *le, *le1, *le_free;
|
||||
|
||||
le = kmem_cache_alloc(ubi_ltree_slab, GFP_NOFS);
|
||||
le = kmalloc(sizeof(struct ubi_ltree_entry), GFP_NOFS);
|
||||
if (!le)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
le->users = 0;
|
||||
init_rwsem(&le->mutex);
|
||||
le->vol_id = vol_id;
|
||||
le->lnum = lnum;
|
||||
|
||||
@ -188,7 +190,7 @@ static struct ubi_ltree_entry *ltree_add_entry(struct ubi_device *ubi,
|
||||
spin_unlock(&ubi->ltree_lock);
|
||||
|
||||
if (le_free)
|
||||
kmem_cache_free(ubi_ltree_slab, le_free);
|
||||
kfree(le_free);
|
||||
|
||||
return le;
|
||||
}
|
||||
@ -236,7 +238,7 @@ static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum)
|
||||
|
||||
up_read(&le->mutex);
|
||||
if (free)
|
||||
kmem_cache_free(ubi_ltree_slab, le);
|
||||
kfree(le);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -292,7 +294,7 @@ static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum)
|
||||
free = 0;
|
||||
spin_unlock(&ubi->ltree_lock);
|
||||
if (free)
|
||||
kmem_cache_free(ubi_ltree_slab, le);
|
||||
kfree(le);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -321,7 +323,7 @@ static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum)
|
||||
|
||||
up_write(&le->mutex);
|
||||
if (free)
|
||||
kmem_cache_free(ubi_ltree_slab, le);
|
||||
kfree(le);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -339,9 +341,6 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
|
||||
{
|
||||
int err, pnum, vol_id = vol->vol_id;
|
||||
|
||||
ubi_assert(ubi->ref_count > 0);
|
||||
ubi_assert(vol->ref_count > 0);
|
||||
|
||||
if (ubi->ro_mode)
|
||||
return -EROFS;
|
||||
|
||||
@ -390,9 +389,6 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
|
||||
struct ubi_vid_hdr *vid_hdr;
|
||||
uint32_t uninitialized_var(crc);
|
||||
|
||||
ubi_assert(ubi->ref_count > 0);
|
||||
ubi_assert(vol->ref_count > 0);
|
||||
|
||||
err = leb_read_lock(ubi, vol_id, lnum);
|
||||
if (err)
|
||||
return err;
|
||||
@ -616,9 +612,6 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
|
||||
int err, pnum, tries = 0, vol_id = vol->vol_id;
|
||||
struct ubi_vid_hdr *vid_hdr;
|
||||
|
||||
ubi_assert(ubi->ref_count > 0);
|
||||
ubi_assert(vol->ref_count > 0);
|
||||
|
||||
if (ubi->ro_mode)
|
||||
return -EROFS;
|
||||
|
||||
@ -752,9 +745,6 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
|
||||
struct ubi_vid_hdr *vid_hdr;
|
||||
uint32_t crc;
|
||||
|
||||
ubi_assert(ubi->ref_count > 0);
|
||||
ubi_assert(vol->ref_count > 0);
|
||||
|
||||
if (ubi->ro_mode)
|
||||
return -EROFS;
|
||||
|
||||
@ -869,12 +859,20 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
|
||||
struct ubi_vid_hdr *vid_hdr;
|
||||
uint32_t crc;
|
||||
|
||||
ubi_assert(ubi->ref_count > 0);
|
||||
ubi_assert(vol->ref_count > 0);
|
||||
|
||||
if (ubi->ro_mode)
|
||||
return -EROFS;
|
||||
|
||||
if (len == 0) {
|
||||
/*
|
||||
* Special case when data length is zero. In this case the LEB
|
||||
* has to be unmapped and mapped somewhere else.
|
||||
*/
|
||||
err = ubi_eba_unmap_leb(ubi, vol, lnum);
|
||||
if (err)
|
||||
return err;
|
||||
return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype);
|
||||
}
|
||||
|
||||
vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
|
||||
if (!vid_hdr)
|
||||
return -ENOMEM;
|
||||
|
@ -480,9 +480,9 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum)
|
||||
{
|
||||
struct ubi_volume *vol = desc->vol;
|
||||
struct ubi_device *ubi = vol->ubi;
|
||||
int err, vol_id = vol->vol_id;
|
||||
int err;
|
||||
|
||||
dbg_msg("erase LEB %d:%d", vol_id, lnum);
|
||||
dbg_msg("erase LEB %d:%d", vol->vol_id, lnum);
|
||||
|
||||
if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
|
||||
return -EROFS;
|
||||
@ -541,9 +541,8 @@ int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum)
|
||||
{
|
||||
struct ubi_volume *vol = desc->vol;
|
||||
struct ubi_device *ubi = vol->ubi;
|
||||
int vol_id = vol->vol_id;
|
||||
|
||||
dbg_msg("unmap LEB %d:%d", vol_id, lnum);
|
||||
dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum);
|
||||
|
||||
if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
|
||||
return -EROFS;
|
||||
@ -579,9 +578,8 @@ 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;
|
||||
int vol_id = vol->vol_id;
|
||||
|
||||
dbg_msg("unmap LEB %d:%d", vol_id, lnum);
|
||||
dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum);
|
||||
|
||||
if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
|
||||
return -EROFS;
|
||||
|
@ -286,9 +286,14 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
|
||||
* FIXME: but this is anyway obsolete and will be removed at
|
||||
* some point.
|
||||
*/
|
||||
|
||||
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);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
abs = v1 - v2;
|
||||
if (abs < 0)
|
||||
abs = -abs;
|
||||
@ -390,7 +395,6 @@ out_free_buf:
|
||||
vfree(buf);
|
||||
out_free_vidh:
|
||||
ubi_free_vid_hdr(ubi, vh);
|
||||
ubi_assert(err < 0);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -854,7 +858,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
|
||||
}
|
||||
|
||||
vol_id = be32_to_cpu(vidh->vol_id);
|
||||
if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) {
|
||||
if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) {
|
||||
int lnum = be32_to_cpu(vidh->lnum);
|
||||
|
||||
/* Unsupported internal volume */
|
||||
|
@ -144,7 +144,6 @@ struct ubi_volume_desc;
|
||||
* @readers: number of users holding this volume in read-only mode
|
||||
* @writers: number of users holding this volume in read-write mode
|
||||
* @exclusive: whether somebody holds this volume in exclusive mode
|
||||
* @checked: if this static volume was checked
|
||||
*
|
||||
* @reserved_pebs: how many physical eraseblocks are reserved for this volume
|
||||
* @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
|
||||
@ -152,21 +151,30 @@ struct ubi_volume_desc;
|
||||
* @used_ebs: how many logical eraseblocks in this volume contain data
|
||||
* @last_eb_bytes: how many bytes are stored in the last logical eraseblock
|
||||
* @used_bytes: how many bytes of data this volume contains
|
||||
* @upd_marker: non-zero if the update marker is set for this volume
|
||||
* @corrupted: non-zero if the volume is corrupted (static volumes only)
|
||||
* @alignment: volume alignment
|
||||
* @data_pad: how many bytes are not used at the end of physical eraseblocks to
|
||||
* satisfy the requested alignment
|
||||
* @name_len: volume name length
|
||||
* @name: volume name
|
||||
*
|
||||
* @updating: whether the volume is being updated
|
||||
* @upd_ebs: how many eraseblocks are expected to be updated
|
||||
* @upd_bytes: how many bytes are expected to be received
|
||||
* @upd_received: how many update bytes were already received
|
||||
* @upd_buf: update buffer which is used to collect update data
|
||||
* @ch_lnum: LEB number which is being changing by the atomic LEB change
|
||||
* operation
|
||||
* @ch_dtype: data persistency type which is being changing by the atomic LEB
|
||||
* change operation
|
||||
* @upd_bytes: how many bytes are expected to be received for volume update or
|
||||
* atomic LEB change
|
||||
* @upd_received: how many bytes were already received for volume update or
|
||||
* atomic LEB change
|
||||
* @upd_buf: update buffer which is used to collect update data or data for
|
||||
* atomic LEB change
|
||||
*
|
||||
* @eba_tbl: EBA table of this volume (LEB->PEB mapping)
|
||||
* @checked: %1 if this static volume was checked
|
||||
* @corrupted: %1 if the volume is corrupted (static volumes only)
|
||||
* @upd_marker: %1 if the update marker is set for this volume
|
||||
* @updating: %1 if the volume is being updated
|
||||
* @changing_leb: %1 if the atomic LEB change ioctl command is in progress
|
||||
*
|
||||
* @gluebi_desc: gluebi UBI volume descriptor
|
||||
* @gluebi_refcount: reference count of the gluebi MTD device
|
||||
@ -189,7 +197,6 @@ struct ubi_volume {
|
||||
int readers;
|
||||
int writers;
|
||||
int exclusive;
|
||||
int checked;
|
||||
|
||||
int reserved_pebs;
|
||||
int vol_type;
|
||||
@ -197,23 +204,31 @@ struct ubi_volume {
|
||||
int used_ebs;
|
||||
int last_eb_bytes;
|
||||
long long used_bytes;
|
||||
int upd_marker;
|
||||
int corrupted;
|
||||
int alignment;
|
||||
int data_pad;
|
||||
int name_len;
|
||||
char name[UBI_VOL_NAME_MAX+1];
|
||||
|
||||
int updating;
|
||||
int upd_ebs;
|
||||
int ch_lnum;
|
||||
int ch_dtype;
|
||||
long long upd_bytes;
|
||||
long long upd_received;
|
||||
void *upd_buf;
|
||||
|
||||
int *eba_tbl;
|
||||
int checked:1;
|
||||
int corrupted:1;
|
||||
int upd_marker:1;
|
||||
int updating:1;
|
||||
int changing_leb:1;
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_GLUEBI
|
||||
/* Gluebi-related stuff may be compiled out */
|
||||
/*
|
||||
* Gluebi-related stuff may be compiled out.
|
||||
* TODO: this should not be built into UBI but should be a separate
|
||||
* ubimtd driver which works on top of UBI and emulates MTD devices.
|
||||
*/
|
||||
struct ubi_volume_desc *gluebi_desc;
|
||||
int gluebi_refcount;
|
||||
struct mtd_info gluebi_mtd;
|
||||
@ -250,9 +265,11 @@ struct ubi_wl_entry;
|
||||
* @rsvd_pebs: count of reserved physical eraseblocks
|
||||
* @avail_pebs: count of available physical eraseblocks
|
||||
* @beb_rsvd_pebs: how many physical eraseblocks are reserved for bad PEB
|
||||
* handling
|
||||
* handling
|
||||
* @beb_rsvd_level: normal level of PEBs reserved for bad PEB handling
|
||||
*
|
||||
* @autoresize_vol_id: ID of the volume which has to be auto-resized at the end
|
||||
* of UBI ititializetion
|
||||
* @vtbl_slots: how many slots are available in the volume table
|
||||
* @vtbl_size: size of the volume table in bytes
|
||||
* @vtbl: in-RAM volume table copy
|
||||
@ -333,12 +350,14 @@ struct ubi_device {
|
||||
int beb_rsvd_pebs;
|
||||
int beb_rsvd_level;
|
||||
|
||||
int autoresize_vol_id;
|
||||
int vtbl_slots;
|
||||
int vtbl_size;
|
||||
struct ubi_vtbl_record *vtbl;
|
||||
struct mutex volumes_mutex;
|
||||
|
||||
int max_ec;
|
||||
/* TODO: mean_ec is not updated run-time, fix */
|
||||
int mean_ec;
|
||||
|
||||
/* EBA unit's stuff */
|
||||
@ -399,7 +418,6 @@ struct ubi_device {
|
||||
#endif
|
||||
};
|
||||
|
||||
extern struct kmem_cache *ubi_ltree_slab;
|
||||
extern struct kmem_cache *ubi_wl_entry_slab;
|
||||
extern struct file_operations ubi_ctrl_cdev_operations;
|
||||
extern struct file_operations ubi_cdev_operations;
|
||||
@ -420,9 +438,14 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol);
|
||||
void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol);
|
||||
|
||||
/* upd.c */
|
||||
int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes);
|
||||
int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
|
||||
int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
|
||||
long long bytes);
|
||||
int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
|
||||
const void __user *buf, int count);
|
||||
int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
|
||||
const struct ubi_leb_change_req *req);
|
||||
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);
|
||||
|
@ -22,7 +22,8 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains implementation of the volume update functionality.
|
||||
* This file contains implementation of the volume update and atomic LEB change
|
||||
* functionality.
|
||||
*
|
||||
* The update operation is based on the per-volume update marker which is
|
||||
* stored in the volume table. The update marker is set before the update
|
||||
@ -45,30 +46,30 @@
|
||||
/**
|
||||
* set_update_marker - set update marker.
|
||||
* @ubi: UBI device description object
|
||||
* @vol_id: volume ID
|
||||
* @vol: volume description object
|
||||
*
|
||||
* This function sets the update marker flag for volume @vol_id. Returns zero
|
||||
* This function sets the update marker flag for volume @vol. Returns zero
|
||||
* in case of success and a negative error code in case of failure.
|
||||
*/
|
||||
static int set_update_marker(struct ubi_device *ubi, int vol_id)
|
||||
static int set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol)
|
||||
{
|
||||
int err;
|
||||
struct ubi_vtbl_record vtbl_rec;
|
||||
struct ubi_volume *vol = ubi->volumes[vol_id];
|
||||
|
||||
dbg_msg("set update marker for volume %d", vol_id);
|
||||
dbg_msg("set update marker for volume %d", vol->vol_id);
|
||||
|
||||
if (vol->upd_marker) {
|
||||
ubi_assert(ubi->vtbl[vol_id].upd_marker);
|
||||
ubi_assert(ubi->vtbl[vol->vol_id].upd_marker);
|
||||
dbg_msg("already set");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
|
||||
memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id],
|
||||
sizeof(struct ubi_vtbl_record));
|
||||
vtbl_rec.upd_marker = 1;
|
||||
|
||||
mutex_lock(&ubi->volumes_mutex);
|
||||
err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
|
||||
err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec);
|
||||
mutex_unlock(&ubi->volumes_mutex);
|
||||
vol->upd_marker = 1;
|
||||
return err;
|
||||
@ -77,23 +78,24 @@ static int set_update_marker(struct ubi_device *ubi, int vol_id)
|
||||
/**
|
||||
* clear_update_marker - clear update marker.
|
||||
* @ubi: UBI device description object
|
||||
* @vol_id: volume ID
|
||||
* @vol: volume description object
|
||||
* @bytes: new data size in bytes
|
||||
*
|
||||
* This function clears the update marker for volume @vol_id, sets new volume
|
||||
* This function clears the update marker for volume @vol, sets new volume
|
||||
* data size and clears the "corrupted" flag (static volumes only). Returns
|
||||
* zero in case of success and a negative error code in case of failure.
|
||||
*/
|
||||
static int clear_update_marker(struct ubi_device *ubi, int vol_id, long long bytes)
|
||||
static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol,
|
||||
long long bytes)
|
||||
{
|
||||
int err;
|
||||
uint64_t tmp;
|
||||
struct ubi_vtbl_record vtbl_rec;
|
||||
struct ubi_volume *vol = ubi->volumes[vol_id];
|
||||
|
||||
dbg_msg("clear update marker for volume %d", vol_id);
|
||||
dbg_msg("clear update marker for volume %d", vol->vol_id);
|
||||
|
||||
memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
|
||||
memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id],
|
||||
sizeof(struct ubi_vtbl_record));
|
||||
ubi_assert(vol->upd_marker && vtbl_rec.upd_marker);
|
||||
vtbl_rec.upd_marker = 0;
|
||||
|
||||
@ -109,7 +111,7 @@ static int clear_update_marker(struct ubi_device *ubi, int vol_id, long long byt
|
||||
}
|
||||
|
||||
mutex_lock(&ubi->volumes_mutex);
|
||||
err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
|
||||
err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec);
|
||||
mutex_unlock(&ubi->volumes_mutex);
|
||||
vol->upd_marker = 0;
|
||||
return err;
|
||||
@ -118,23 +120,24 @@ static int clear_update_marker(struct ubi_device *ubi, int vol_id, long long byt
|
||||
/**
|
||||
* ubi_start_update - start volume update.
|
||||
* @ubi: UBI device description object
|
||||
* @vol_id: volume ID
|
||||
* @vol: volume description object
|
||||
* @bytes: update bytes
|
||||
*
|
||||
* This function starts volume update operation. If @bytes is zero, the volume
|
||||
* is just wiped out. Returns zero in case of success and a negative error code
|
||||
* in case of failure.
|
||||
*/
|
||||
int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes)
|
||||
int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
|
||||
long long bytes)
|
||||
{
|
||||
int i, err;
|
||||
uint64_t tmp;
|
||||
struct ubi_volume *vol = ubi->volumes[vol_id];
|
||||
|
||||
dbg_msg("start update of volume %d, %llu bytes", vol_id, bytes);
|
||||
dbg_msg("start update of volume %d, %llu bytes", vol->vol_id, bytes);
|
||||
ubi_assert(!vol->updating && !vol->changing_leb);
|
||||
vol->updating = 1;
|
||||
|
||||
err = set_update_marker(ubi, vol_id);
|
||||
err = set_update_marker(ubi, vol);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -146,7 +149,7 @@ int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes)
|
||||
}
|
||||
|
||||
if (bytes == 0) {
|
||||
err = clear_update_marker(ubi, vol_id, 0);
|
||||
err = clear_update_marker(ubi, vol, 0);
|
||||
if (err)
|
||||
return err;
|
||||
err = ubi_wl_flush(ubi);
|
||||
@ -166,10 +169,43 @@ int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubi_start_leb_change - start atomic LEB change.
|
||||
* @ubi: UBI device description object
|
||||
* @vol: volume description object
|
||||
* @req: operation request
|
||||
*
|
||||
* This function starts atomic LEB change operation. Returns zero in case of
|
||||
* success and a negative error code in case of failure.
|
||||
*/
|
||||
int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
|
||||
const struct ubi_leb_change_req *req)
|
||||
{
|
||||
ubi_assert(!vol->updating && !vol->changing_leb);
|
||||
|
||||
dbg_msg("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,
|
||||
req->dtype);
|
||||
|
||||
vol->upd_bytes = req->bytes;
|
||||
vol->upd_received = 0;
|
||||
vol->changing_leb = 1;
|
||||
vol->ch_lnum = req->lnum;
|
||||
vol->ch_dtype = req->dtype;
|
||||
|
||||
vol->upd_buf = vmalloc(req->bytes);
|
||||
if (!vol->upd_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* write_leb - write update data.
|
||||
* @ubi: UBI device description object
|
||||
* @vol_id: volume ID
|
||||
* @vol: volume description object
|
||||
* @lnum: logical eraseblock number
|
||||
* @buf: data to write
|
||||
* @len: data size
|
||||
@ -195,25 +231,22 @@ int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes)
|
||||
* This function returns zero in case of success and a negative error code in
|
||||
* case of failure.
|
||||
*/
|
||||
static int write_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
|
||||
int len, int used_ebs)
|
||||
static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
|
||||
void *buf, int len, int used_ebs)
|
||||
{
|
||||
int err, l;
|
||||
struct ubi_volume *vol = ubi->volumes[vol_id];
|
||||
int err;
|
||||
|
||||
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
|
||||
l = ALIGN(len, ubi->min_io_size);
|
||||
memset(buf + len, 0xFF, l - len);
|
||||
len = ALIGN(len, ubi->min_io_size);
|
||||
memset(buf + len, 0xFF, len - len);
|
||||
|
||||
l = ubi_calc_data_len(ubi, buf, l);
|
||||
if (l == 0) {
|
||||
len = ubi_calc_data_len(ubi, buf, len);
|
||||
if (len == 0) {
|
||||
dbg_msg("all %d bytes contain 0xFF - skip", len);
|
||||
return 0;
|
||||
}
|
||||
if (len != l)
|
||||
dbg_msg("skip last %d bytes (0xFF)", len - l);
|
||||
|
||||
err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, l, 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
|
||||
@ -239,16 +272,15 @@ static int write_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
|
||||
* @count: how much bytes to write
|
||||
*
|
||||
* This function writes more data to the volume which is being updated. It may
|
||||
* be called arbitrary number of times until all of the update data arrive.
|
||||
* This function returns %0 in case of success, number of bytes written during
|
||||
* the last call if the whole volume update was successfully finished, and a
|
||||
* be called arbitrary number of times until all the update data arriveis. This
|
||||
* function returns %0 in case of success, number of bytes written during the
|
||||
* last call if the whole volume update has been successfully finished, and a
|
||||
* negative error code in case of failure.
|
||||
*/
|
||||
int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
|
||||
int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
|
||||
const void __user *buf, int count)
|
||||
{
|
||||
uint64_t tmp;
|
||||
struct ubi_volume *vol = ubi->volumes[vol_id];
|
||||
int lnum, offs, err = 0, len, to_write = count;
|
||||
|
||||
dbg_msg("write %d of %lld bytes, %lld already passed",
|
||||
@ -293,8 +325,8 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
|
||||
* is the last chunk, it's time to flush the buffer.
|
||||
*/
|
||||
ubi_assert(flush_len <= vol->usable_leb_size);
|
||||
err = write_leb(ubi, vol_id, lnum, vol->upd_buf,
|
||||
flush_len, vol->upd_ebs);
|
||||
err = write_leb(ubi, vol, lnum, vol->upd_buf, flush_len,
|
||||
vol->upd_ebs);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@ -321,8 +353,8 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
|
||||
|
||||
if (len == vol->usable_leb_size ||
|
||||
vol->upd_received + len == vol->upd_bytes) {
|
||||
err = write_leb(ubi, vol_id, lnum, vol->upd_buf, len,
|
||||
vol->upd_ebs);
|
||||
err = write_leb(ubi, vol, lnum, vol->upd_buf,
|
||||
len, vol->upd_ebs);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
@ -336,16 +368,70 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
|
||||
ubi_assert(vol->upd_received <= vol->upd_bytes);
|
||||
if (vol->upd_received == vol->upd_bytes) {
|
||||
/* The update is finished, clear the update marker */
|
||||
err = clear_update_marker(ubi, vol_id, vol->upd_bytes);
|
||||
err = clear_update_marker(ubi, vol, vol->upd_bytes);
|
||||
if (err)
|
||||
return err;
|
||||
err = ubi_wl_flush(ubi);
|
||||
if (err == 0) {
|
||||
vol->updating = 0;
|
||||
err = to_write;
|
||||
vfree(vol->upd_buf);
|
||||
vol->updating = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubi_more_leb_change_data - accept more data for atomic LEB change.
|
||||
* @vol: volume description object
|
||||
* @buf: write data (user-space memory buffer)
|
||||
* @count: how much bytes to write
|
||||
*
|
||||
* This function accepts more data to the volume which is being under the
|
||||
* "atomic LEB change" operation. It may be called arbitrary number of times
|
||||
* until all data arrives. This function returns %0 in case of success, number
|
||||
* of bytes written during the last call if the whole "atomic LEB change"
|
||||
* operation has been successfully finished, and a negative error code in case
|
||||
* of failure.
|
||||
*/
|
||||
int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
|
||||
const void __user *buf, int count)
|
||||
{
|
||||
int err;
|
||||
|
||||
dbg_msg("write %d of %lld bytes, %lld already passed",
|
||||
count, vol->upd_bytes, vol->upd_received);
|
||||
|
||||
if (ubi->ro_mode)
|
||||
return -EROFS;
|
||||
|
||||
if (vol->upd_received + count > vol->upd_bytes)
|
||||
count = vol->upd_bytes - vol->upd_received;
|
||||
|
||||
err = copy_from_user(vol->upd_buf + vol->upd_received, buf, count);
|
||||
if (err)
|
||||
return -EFAULT;
|
||||
|
||||
vol->upd_received += count;
|
||||
|
||||
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);
|
||||
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);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
ubi_assert(vol->upd_received <= vol->upd_bytes);
|
||||
if (vol->upd_received == vol->upd_bytes) {
|
||||
vol->changing_leb = 0;
|
||||
err = count;
|
||||
vfree(vol->upd_buf);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -497,8 +497,6 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
|
||||
|
||||
dbg_msg("re-size volume %d to from %d to %d PEBs",
|
||||
vol_id, vol->reserved_pebs, reserved_pebs);
|
||||
ubi_assert(desc->mode == UBI_EXCLUSIVE);
|
||||
ubi_assert(vol == ubi->volumes[vol_id]);
|
||||
|
||||
if (vol->vol_type == UBI_STATIC_VOLUME &&
|
||||
reserved_pebs < vol->used_ebs) {
|
||||
@ -526,7 +524,6 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
|
||||
}
|
||||
spin_unlock(&ubi->volumes_lock);
|
||||
|
||||
|
||||
/* Reserve physical eraseblocks */
|
||||
pebs = reserved_pebs - vol->reserved_pebs;
|
||||
if (pebs > 0) {
|
||||
@ -746,11 +743,6 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (vol->upd_marker != 0 && vol->upd_marker != 1) {
|
||||
ubi_err("bad upd_marker");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (vol->upd_marker && vol->corrupted) {
|
||||
dbg_err("update marker and corrupted simultaneously");
|
||||
goto fail;
|
||||
@ -785,7 +777,7 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
|
||||
|
||||
n = (long long)vol->used_ebs * vol->usable_leb_size;
|
||||
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
|
||||
if (vol->corrupted != 0) {
|
||||
if (vol->corrupted) {
|
||||
ubi_err("corrupted dynamic volume");
|
||||
goto fail;
|
||||
}
|
||||
@ -802,10 +794,6 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
if (vol->corrupted != 0 && vol->corrupted != 1) {
|
||||
ubi_err("bad corrupted");
|
||||
goto fail;
|
||||
}
|
||||
if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) {
|
||||
ubi_err("bad used_ebs");
|
||||
goto fail;
|
||||
|
@ -89,7 +89,7 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
|
||||
struct ubi_volume *layout_vol;
|
||||
|
||||
ubi_assert(idx >= 0 && idx < ubi->vtbl_slots);
|
||||
layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOL_ID)];
|
||||
layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)];
|
||||
|
||||
if (!vtbl_rec)
|
||||
vtbl_rec = &empty_vtbl_record;
|
||||
@ -111,7 +111,7 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
|
||||
}
|
||||
|
||||
paranoid_vtbl_check(ubi);
|
||||
return ubi_wl_flush(ubi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -269,7 +269,7 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
|
||||
* this volume table copy was found during scanning. It has to be wiped
|
||||
* out.
|
||||
*/
|
||||
sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOL_ID);
|
||||
sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID);
|
||||
if (sv)
|
||||
old_seb = ubi_scan_find_seb(sv, copy);
|
||||
|
||||
@ -281,7 +281,7 @@ retry:
|
||||
}
|
||||
|
||||
vid_hdr->vol_type = UBI_VID_DYNAMIC;
|
||||
vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOL_ID);
|
||||
vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOLUME_ID);
|
||||
vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT;
|
||||
vid_hdr->data_size = vid_hdr->used_ebs =
|
||||
vid_hdr->data_pad = cpu_to_be32(0);
|
||||
@ -514,6 +514,17 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
|
||||
vol->name[vol->name_len] = '\0';
|
||||
vol->vol_id = i;
|
||||
|
||||
if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) {
|
||||
/* Auto re-size flag may be set only for one volume */
|
||||
if (ubi->autoresize_vol_id != -1) {
|
||||
ubi_err("more then one auto-resize volume (%d "
|
||||
"and %d)", ubi->autoresize_vol_id, i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ubi->autoresize_vol_id = i;
|
||||
}
|
||||
|
||||
ubi_assert(!ubi->volumes[i]);
|
||||
ubi->volumes[i] = vol;
|
||||
ubi->vol_count += 1;
|
||||
@ -579,7 +590,7 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
|
||||
vol->last_eb_bytes = vol->reserved_pebs;
|
||||
vol->used_bytes =
|
||||
(long long)vol->used_ebs * (ubi->leb_size - vol->data_pad);
|
||||
vol->vol_id = UBI_LAYOUT_VOL_ID;
|
||||
vol->vol_id = UBI_LAYOUT_VOLUME_ID;
|
||||
vol->ref_count = 1;
|
||||
|
||||
ubi_assert(!ubi->volumes[i]);
|
||||
@ -732,7 +743,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
|
||||
ubi->vtbl_size = ubi->vtbl_slots * UBI_VTBL_RECORD_SIZE;
|
||||
ubi->vtbl_size = ALIGN(ubi->vtbl_size, ubi->min_io_size);
|
||||
|
||||
sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOL_ID);
|
||||
sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID);
|
||||
if (!sv) {
|
||||
/*
|
||||
* No logical eraseblocks belonging to the layout volume were
|
||||
|
@ -1303,7 +1303,6 @@ int ubi_wl_flush(struct ubi_device *ubi)
|
||||
* Make sure all the works which have been done in parallel are
|
||||
* finished.
|
||||
*/
|
||||
ubi_assert(ubi->ref_count > 0);
|
||||
down_write(&ubi->work_sem);
|
||||
up_write(&ubi->work_sem);
|
||||
|
||||
|
@ -25,23 +25,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <mtd/ubi-user.h>
|
||||
|
||||
/*
|
||||
* UBI data type hint constants.
|
||||
*
|
||||
* UBI_LONGTERM: long-term data
|
||||
* UBI_SHORTTERM: short-term data
|
||||
* UBI_UNKNOWN: data persistence is unknown
|
||||
*
|
||||
* These constants are used when data is written to UBI volumes in order to
|
||||
* help the UBI wear-leveling unit to find more appropriate physical
|
||||
* eraseblocks.
|
||||
*/
|
||||
enum {
|
||||
UBI_LONGTERM = 1,
|
||||
UBI_SHORTTERM,
|
||||
UBI_UNKNOWN
|
||||
};
|
||||
|
||||
/*
|
||||
* enum ubi_open_mode - UBI volume open mode constants.
|
||||
*
|
||||
|
@ -57,6 +57,43 @@ enum {
|
||||
UBI_VID_STATIC = 2
|
||||
};
|
||||
|
||||
/*
|
||||
* Volume flags used in the volume table record.
|
||||
*
|
||||
* @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume
|
||||
*
|
||||
* %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume
|
||||
* table. UBI automatically re-sizes the volume which has this flag and makes
|
||||
* the volume to be of largest possible size. This means that if after the
|
||||
* initialization UBI finds out that there are available physical eraseblocks
|
||||
* present on the device, it automatically appends all of them to the volume
|
||||
* (the physical eraseblocks reserved for bad eraseblocks handling and other
|
||||
* reserved physical eraseblocks are not taken). So, if there is a volume with
|
||||
* the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical
|
||||
* eraseblocks will be zero after UBI is loaded, because all of them will be
|
||||
* reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared
|
||||
* after the volume had been initialized.
|
||||
*
|
||||
* The auto-resize feature is useful for device production purposes. For
|
||||
* example, different NAND flash chips may have different amount of initial bad
|
||||
* eraseblocks, depending of particular chip instance. Manufacturers of NAND
|
||||
* chips usually guarantee that the amount of initial bad eraseblocks does not
|
||||
* exceed certain percent, e.g. 2%. When one creates an UBI image which will be
|
||||
* flashed to the end devices in production, he does not know the exact amount
|
||||
* of good physical eraseblocks the NAND chip on the device will have, but this
|
||||
* number is required to calculate the volume sized and put them to the volume
|
||||
* table of the UBI image. In this case, one of the volumes (e.g., the one
|
||||
* which will store the root file system) is marked as "auto-resizable", and
|
||||
* UBI will adjust its size on the first boot if needed.
|
||||
*
|
||||
* Note, first UBI reserves some amount of physical eraseblocks for bad
|
||||
* eraseblock handling, and then re-sizes the volume, not vice-versa. This
|
||||
* means that the pool of reserved physical eraseblocks will always be present.
|
||||
*/
|
||||
enum {
|
||||
UBI_VTBL_AUTORESIZE_FLG = 0x01,
|
||||
};
|
||||
|
||||
/*
|
||||
* Compatibility constants used by internal volumes.
|
||||
*
|
||||
@ -262,7 +299,9 @@ struct ubi_vid_hdr {
|
||||
|
||||
/* The layout volume contains the volume table */
|
||||
|
||||
#define UBI_LAYOUT_VOL_ID UBI_INTERNAL_VOL_START
|
||||
#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START
|
||||
#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC
|
||||
#define UBI_LAYOUT_VOLUME_ALIGN 1
|
||||
#define UBI_LAYOUT_VOLUME_EBS 2
|
||||
#define UBI_LAYOUT_VOLUME_NAME "layout volume"
|
||||
#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT
|
||||
@ -289,7 +328,8 @@ struct ubi_vid_hdr {
|
||||
* @upd_marker: if volume update was started but not finished
|
||||
* @name_len: volume name length
|
||||
* @name: the volume name
|
||||
* @padding2: reserved, zeroes
|
||||
* @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG)
|
||||
* @padding: reserved, zeroes
|
||||
* @crc: a CRC32 checksum of the record
|
||||
*
|
||||
* The volume table records are stored in the volume table, which is stored in
|
||||
@ -324,7 +364,8 @@ struct ubi_vtbl_record {
|
||||
__u8 upd_marker;
|
||||
__be16 name_len;
|
||||
__u8 name[UBI_VOL_NAME_MAX+1];
|
||||
__u8 padding2[24];
|
||||
__u8 flags;
|
||||
__u8 padding[23];
|
||||
__be32 crc;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
@ -63,7 +63,7 @@
|
||||
*
|
||||
* Volume update should be done via the %UBI_IOCVOLUP IOCTL command of the
|
||||
* corresponding UBI volume character device. A pointer to a 64-bit update
|
||||
* size should be passed to the IOCTL. After then, UBI expects user to write
|
||||
* size should be passed to the IOCTL. After this, UBI expects user to write
|
||||
* this number of bytes to the volume character device. The update is finished
|
||||
* when the claimed number of bytes is passed. So, the volume update sequence
|
||||
* is something like:
|
||||
@ -72,6 +72,15 @@
|
||||
* ioctl(fd, UBI_IOCVOLUP, &image_size);
|
||||
* write(fd, buf, image_size);
|
||||
* close(fd);
|
||||
*
|
||||
* Atomic eraseblock change
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* Atomic eraseblock change operation is done via the %UBI_IOCEBCH IOCTL
|
||||
* command of the corresponding UBI volume character device. A pointer to
|
||||
* &struct ubi_leb_change_req has to be passed to the IOCTL. Then the user is
|
||||
* expected to write the requested amount of bytes. This is similar to the
|
||||
* "volume update" IOCTL.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -113,10 +122,29 @@
|
||||
#define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t)
|
||||
/* An eraseblock erasure command, used for debugging, disabled by default */
|
||||
#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t)
|
||||
/* An atomic eraseblock change command */
|
||||
#define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t)
|
||||
|
||||
/* Maximum MTD device name length supported by UBI */
|
||||
#define MAX_UBI_MTD_NAME_LEN 127
|
||||
|
||||
/*
|
||||
* UBI data type hint constants.
|
||||
*
|
||||
* UBI_LONGTERM: long-term data
|
||||
* UBI_SHORTTERM: short-term data
|
||||
* UBI_UNKNOWN: data persistence is unknown
|
||||
*
|
||||
* These constants are used when data is written to UBI volumes in order to
|
||||
* help the UBI wear-leveling unit to find more appropriate physical
|
||||
* eraseblocks.
|
||||
*/
|
||||
enum {
|
||||
UBI_LONGTERM = 1,
|
||||
UBI_SHORTTERM = 2,
|
||||
UBI_UNKNOWN = 3,
|
||||
};
|
||||
|
||||
/*
|
||||
* UBI volume type constants.
|
||||
*
|
||||
@ -125,7 +153,7 @@
|
||||
*/
|
||||
enum {
|
||||
UBI_DYNAMIC_VOLUME = 3,
|
||||
UBI_STATIC_VOLUME = 4,
|
||||
UBI_STATIC_VOLUME = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -137,7 +165,7 @@ enum {
|
||||
*
|
||||
* This data structure is used to specify MTD device UBI has to attach and the
|
||||
* parameters it has to use. The number which should be assigned to the new UBI
|
||||
* device is passed in @ubi_num. UBI may automatically assing the number if
|
||||
* device is passed in @ubi_num. UBI may automatically assign the number if
|
||||
* @UBI_DEV_NUM_AUTO is passed. In this case, the device number is returned in
|
||||
* @ubi_num.
|
||||
*
|
||||
@ -176,7 +204,7 @@ struct ubi_attach_req {
|
||||
* @padding2: reserved for future, not used, has to be zeroed
|
||||
* @name: volume name
|
||||
*
|
||||
* This structure is used by userspace programs when creating new volumes. The
|
||||
* This structure is used by user-space programs when creating new volumes. The
|
||||
* @used_bytes field is only necessary when creating static volumes.
|
||||
*
|
||||
* The @alignment field specifies the required alignment of the volume logical
|
||||
@ -222,4 +250,19 @@ struct ubi_rsvol_req {
|
||||
int32_t vol_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/**
|
||||
* struct ubi_leb_change_req - a data structure used in atomic logical
|
||||
* eraseblock change requests.
|
||||
* @lnum: logical eraseblock number to change
|
||||
* @bytes: how many bytes will be written to the logical eraseblock
|
||||
* @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
|
||||
* @padding: reserved for future, not used, has to be zeroed
|
||||
*/
|
||||
struct ubi_leb_change_req {
|
||||
int32_t lnum;
|
||||
int32_t bytes;
|
||||
uint8_t dtype;
|
||||
uint8_t padding[7];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#endif /* __UBI_USER_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user