/* 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;
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;
- mutex_init(&ubi->volumes_mutex);
- spin_lock_init(&ubi->volumes_lock);
-
sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);
/*
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;
/**
* 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)
{
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
out_wl:
ubi_wl_close(ubi);
out_vtbl:
+ free_internal_volumes(ubi);
vfree(ubi->vtbl);
out_si:
ubi_scan_destroy_si(si);
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);
}
/* 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);
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;
ubi->ro_mode = 1;
}
- dbg_msg("leb_size %d", ubi->leb_size);
- dbg_msg("ro_mode %d", ubi->ro_mode);
+ ubi_msg("physical eraseblock size: %d bytes (%d KiB)",
+ ubi->peb_size, ubi->peb_size >> 10);
+ ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size);
+ ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size);
+ if (ubi->hdrs_min_io_size != ubi->min_io_size)
+ ubi_msg("sub-page size: %d",
+ ubi->hdrs_min_io_size);
+ ubi_msg("VID header offset: %d (aligned %d)",
+ ubi->vid_hdr_offset, ubi->vid_hdr_aloffset);
+ ubi_msg("data offset: %d", ubi->leb_start);
/*
* Note, ideally, we have to initialize ubi->bad_peb_count here. But
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 propagate 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 available 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
*
* 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.
*
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.
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);
+ ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num);
err = io_init(ubi);
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;
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;
+ goto out_nofree;
ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
if (IS_ERR(ubi->bgt_thread)) {
ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num);
ubi_msg("MTD device name: \"%s\"", mtd->name);
ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20);
- ubi_msg("physical eraseblock size: %d bytes (%d KiB)",
- ubi->peb_size, ubi->peb_size >> 10);
- ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size);
ubi_msg("number of good PEBs: %d", ubi->good_peb_count);
ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count);
- ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size);
- ubi_msg("VID header offset: %d (aligned %d)",
- ubi->vid_hdr_offset, ubi->vid_hdr_aloffset);
- ubi_msg("data offset: %d", ubi->leb_start);
ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots);
ubi_msg("wear-leveling threshold: %d", CONFIG_MTD_UBI_WL_THRESHOLD);
ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT);
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);
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);
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
BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
if (mtd_devs > UBI_MAX_DEVICES) {
- printk(KERN_ERR "UBI error: too many MTD devices, "
- "maximum is %d\n", UBI_MAX_DEVICES);
+ ubi_err("too many MTD devices, maximum is %d", UBI_MAX_DEVICES);
return -EINVAL;
}
ubi_class = class_create(THIS_MODULE, UBI_NAME_STR);
if (IS_ERR(ubi_class)) {
err = PTR_ERR(ubi_class);
- printk(KERN_ERR "UBI error: cannot create UBI class\n");
+ ubi_err("cannot create UBI class");
goto out;
}
err = class_create_file(ubi_class, &ubi_version);
if (err) {
- printk(KERN_ERR "UBI error: cannot create sysfs file\n");
+ ubi_err("cannot create sysfs file");
goto out_class;
}
err = misc_register(&ubi_ctrl_cdev);
if (err) {
- printk(KERN_ERR "UBI error: cannot register device\n");
+ ubi_err("cannot register device");
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);
+ 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++) {
mutex_unlock(&ubi_devices_mutex);
if (err < 0) {
put_mtd_device(mtd);
- printk(KERN_ERR "UBI error: cannot attach %s\n",
- p->name);
+ ubi_err("cannot attach mtd%d", mtd->index);
goto 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:
out_class:
class_destroy(ubi_class);
out:
- printk(KERN_ERR "UBI error: cannot initialize UBI, error %d\n", err);
+ ubi_err("UBI error: cannot initialize UBI, error %d", err);
return err;
}
module_init(ubi_init);
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);
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;
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) {