summaryrefslogtreecommitdiff
path: root/recipes
diff options
context:
space:
mode:
authorSteffen Sledz <sledz@dresearch.de>2009-04-24 16:06:58 +0200
committerSteffen Sledz <sledz@dresearch.de>2009-04-24 16:06:58 +0200
commitf39b6e0d805fc55cd7bcc6edd03f81bd2441301a (patch)
tree9dd7eb4bfe0fffad9a44c89291c8f9203cf1232f /recipes
parentd03984dc6ef1414c1983361229434b97606ff42d (diff)
linux-2.6.24: make ubifs available for all machines
Diffstat (limited to 'recipes')
-rw-r--r--recipes/linux/linux-2.6.24/hipox/hipox-ubifs.patch43970
-rw-r--r--recipes/linux/linux-2.6.24/ubifs-v2.6.24.patch45442
-rw-r--r--recipes/linux/linux_2.6.24.bb3
3 files changed, 45447 insertions, 43968 deletions
diff --git a/recipes/linux/linux-2.6.24/hipox/hipox-ubifs.patch b/recipes/linux/linux-2.6.24/hipox/hipox-ubifs.patch
index 2aef97d4eb..670f22518c 100644
--- a/recipes/linux/linux-2.6.24/hipox/hipox-ubifs.patch
+++ b/recipes/linux/linux-2.6.24/hipox/hipox-ubifs.patch
@@ -1,43974 +1,10 @@
-diff -Nurd linux-2.6.24.orig/crypto/Kconfig linux-2.6.24/crypto/Kconfig
---- linux-2.6.24.orig/crypto/Kconfig 2009-04-17 09:45:12.000000000 +0200
-+++ linux-2.6.24/crypto/Kconfig 2009-04-17 09:49:26.000000000 +0200
-@@ -502,6 +502,14 @@
- Authenc: Combined mode wrapper for IPsec.
- This is required for IPSec.
-
-+config CRYPTO_LZO
-+ tristate "LZO compression algorithm"
-+ select CRYPTO_ALGAPI
-+ select LZO_COMPRESS
-+ select LZO_DECOMPRESS
-+ help
-+ This is the LZO algorithm.
-+
- source "drivers/crypto/Kconfig"
-
- endif # if CRYPTO
-diff -Nurd linux-2.6.24.orig/crypto/Makefile linux-2.6.24/crypto/Makefile
---- linux-2.6.24.orig/crypto/Makefile 2009-04-17 09:45:12.000000000 +0200
-+++ linux-2.6.24/crypto/Makefile 2009-04-17 09:49:26.000000000 +0200
-@@ -51,6 +51,7 @@
- obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
- obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
- obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
-+obj-$(CONFIG_CRYPTO_LZO) += lzo.o
- obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o
-
- obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
-diff -Nurd linux-2.6.24.orig/crypto/lzo.c linux-2.6.24/crypto/lzo.c
---- linux-2.6.24.orig/crypto/lzo.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.24/crypto/lzo.c 2009-04-17 09:49:26.000000000 +0200
-@@ -0,0 +1,106 @@
-+/*
-+ * Cryptographic API.
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 as published by
-+ * the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-+ * more details.
-+ *
-+ * You should have received a copy of the GNU General Public License along with
-+ * this program; if not, write to the Free Software Foundation, Inc., 51
-+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ *
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/crypto.h>
-+#include <linux/vmalloc.h>
-+#include <linux/lzo.h>
-+
-+struct lzo_ctx {
-+ void *lzo_comp_mem;
-+};
-+
-+static int lzo_init(struct crypto_tfm *tfm)
-+{
-+ struct lzo_ctx *ctx = crypto_tfm_ctx(tfm);
-+
-+ ctx->lzo_comp_mem = vmalloc(LZO1X_MEM_COMPRESS);
-+ if (!ctx->lzo_comp_mem)
-+ return -ENOMEM;
-+
-+ return 0;
-+}
-+
-+static void lzo_exit(struct crypto_tfm *tfm)
-+{
-+ struct lzo_ctx *ctx = crypto_tfm_ctx(tfm);
-+
-+ vfree(ctx->lzo_comp_mem);
-+}
-+
-+static int lzo_compress(struct crypto_tfm *tfm, const u8 *src,
-+ unsigned int slen, u8 *dst, unsigned int *dlen)
-+{
-+ struct lzo_ctx *ctx = crypto_tfm_ctx(tfm);
-+ size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */
-+ int err;
-+
-+ err = lzo1x_1_compress(src, slen, dst, &tmp_len, ctx->lzo_comp_mem);
-+
-+ if (err != LZO_E_OK)
-+ return -EINVAL;
-+
-+ *dlen = tmp_len;
-+ return 0;
-+}
-+
-+static int lzo_decompress(struct crypto_tfm *tfm, const u8 *src,
-+ unsigned int slen, u8 *dst, unsigned int *dlen)
-+{
-+ int err;
-+ size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */
-+
-+ err = lzo1x_decompress_safe(src, slen, dst, &tmp_len);
-+
-+ if (err != LZO_E_OK)
-+ return -EINVAL;
-+
-+ *dlen = tmp_len;
-+ return 0;
-+
-+}
-+
-+static struct crypto_alg alg = {
-+ .cra_name = "lzo",
-+ .cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
-+ .cra_ctxsize = sizeof(struct lzo_ctx),
-+ .cra_module = THIS_MODULE,
-+ .cra_list = LIST_HEAD_INIT(alg.cra_list),
-+ .cra_init = lzo_init,
-+ .cra_exit = lzo_exit,
-+ .cra_u = { .compress = {
-+ .coa_compress = lzo_compress,
-+ .coa_decompress = lzo_decompress } }
-+};
-+
-+static int __init init(void)
-+{
-+ return crypto_register_alg(&alg);
-+}
-+
-+static void __exit fini(void)
-+{
-+ crypto_unregister_alg(&alg);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("LZO Compression Algorithm");
-diff -Nurd linux-2.6.24.orig/drivers/mtd/ubi/Kconfig linux-2.6.24/drivers/mtd/ubi/Kconfig
---- linux-2.6.24.orig/drivers/mtd/ubi/Kconfig 2009-04-17 09:45:11.000000000 +0200
-+++ linux-2.6.24/drivers/mtd/ubi/Kconfig 2009-04-17 09:49:26.000000000 +0200
-@@ -24,8 +24,13 @@
- erase counter value and the lowest erase counter value of eraseblocks
- of UBI devices. When this threshold is exceeded, UBI starts performing
- wear leveling by means of moving data from eraseblock with low erase
-- counter to eraseblocks with high erase counter. Leave the default
-- value if unsure.
-+ counter to eraseblocks with high erase counter.
-+
-+ The default value should be OK for SLC NAND flashes, NOR flashes and
-+ other flashes which have eraseblock life-cycle 100000 or more.
-+ However, in case of MLC NAND flashes which typically have eraseblock
-+ life-cycle less then 10000, the threshold should be lessened (e.g.,
-+ to 128 or 256, although it does not have to be power of 2).
-
- config MTD_UBI_BEB_RESERVE
- int "Percentage of reserved eraseblocks for bad eraseblocks handling"
-diff -Nurd linux-2.6.24.orig/drivers/mtd/ubi/build.c linux-2.6.24/drivers/mtd/ubi/build.c
---- linux-2.6.24.orig/drivers/mtd/ubi/build.c 2009-04-17 09:45:11.000000000 +0200
-+++ linux-2.6.24/drivers/mtd/ubi/build.c 2009-04-17 09:49:26.000000000 +0200
-@@ -21,11 +21,16 @@
- */
-
- /*
-- * This file includes UBI initialization and building of UBI devices. At the
-- * moment UBI devices may only be added while UBI is initialized, but dynamic
-- * device add/remove functionality is planned. Also, at the moment we only
-- * attach UBI devices by scanning, which will become a bottleneck when flashes
-- * reach certain large size. Then one may improve UBI and add other methods.
-+ * This file includes UBI initialization and building of UBI devices.
-+ *
-+ * When UBI is initialized, it attaches all the MTD devices specified as the
-+ * module load parameters or the kernel boot parameters. If MTD devices were
-+ * specified, UBI does not attach any MTD device, but it is possible to do
-+ * later using the "UBI control device".
-+ *
-+ * At the moment we only attach UBI devices by scanning, which will become a
-+ * bottleneck when flashes reach certain large size. Then one may improve UBI
-+ * and add other methods, although it does not seem to be easy to do.
- */
-
- #include <linux/err.h>
-@@ -33,7 +38,9 @@
- #include <linux/moduleparam.h>
- #include <linux/stringify.h>
- #include <linux/stat.h>
-+#include <linux/miscdevice.h>
- #include <linux/log2.h>
-+#include <linux/kthread.h>
- #include "ubi.h"
-
- /* Maximum length of the 'mtd=' parameter */
-@@ -43,29 +50,39 @@
- * struct mtd_dev_param - MTD device parameter description data structure.
- * @name: MTD device name or number string
- * @vid_hdr_offs: VID header offset
-- * @data_offs: data offset
- */
--struct mtd_dev_param
--{
-+struct mtd_dev_param {
- char name[MTD_PARAM_LEN_MAX];
- int vid_hdr_offs;
-- int data_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];
-
--/* Number of UBI devices in system */
--int ubi_devices_cnt;
-+/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
-+struct class *ubi_class;
-+
-+/* Slab cache for wear-leveling entries */
-+struct kmem_cache *ubi_wl_entry_slab;
-+
-+/* UBI control character device */
-+static struct miscdevice ubi_ctrl_cdev = {
-+ .minor = MISC_DYNAMIC_MINOR,
-+ .name = "ubi_ctrl",
-+ .fops = &ubi_ctrl_cdev_operations,
-+};
-
- /* All UBI devices in system */
--struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
-+static struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
-
--/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
--struct class *ubi_class;
-+/* Serializes UBI devices creations and removals */
-+DEFINE_MUTEX(ubi_devices_mutex);
-+
-+/* Protects @ubi_devices and @ubi->ref_count */
-+static DEFINE_SPINLOCK(ubi_devices_lock);
-
- /* "Show" method for files in '/<sysfs>/class/ubi/' */
- static ssize_t ubi_version_show(struct class *class, char *buf)
-@@ -101,42 +118,157 @@
- __ATTR(min_io_size, S_IRUGO, dev_attribute_show, NULL);
- static struct device_attribute dev_bgt_enabled =
- __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL);
-+static struct device_attribute dev_mtd_num =
-+ __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL);
-+
-+/**
-+ * ubi_get_device - get UBI device.
-+ * @ubi_num: UBI device number
-+ *
-+ * This function returns UBI device description object for UBI device number
-+ * @ubi_num, or %NULL if the device does not exist. This function increases the
-+ * device reference count to prevent removal of the device. In other words, the
-+ * device cannot be removed if its reference count is not zero.
-+ */
-+struct ubi_device *ubi_get_device(int ubi_num)
-+{
-+ struct ubi_device *ubi;
-+
-+ spin_lock(&ubi_devices_lock);
-+ ubi = ubi_devices[ubi_num];
-+ if (ubi) {
-+ ubi_assert(ubi->ref_count >= 0);
-+ ubi->ref_count += 1;
-+ get_device(&ubi->dev);
-+ }
-+ spin_unlock(&ubi_devices_lock);
-+
-+ return ubi;
-+}
-+
-+/**
-+ * ubi_put_device - drop an UBI device reference.
-+ * @ubi: UBI device description object
-+ */
-+void ubi_put_device(struct ubi_device *ubi)
-+{
-+ spin_lock(&ubi_devices_lock);
-+ ubi->ref_count -= 1;
-+ put_device(&ubi->dev);
-+ spin_unlock(&ubi_devices_lock);
-+}
-+
-+/**
-+ * 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
-+ * by its major number.
-+ */
-+struct ubi_device *ubi_get_by_major(int major)
-+{
-+ int i;
-+ struct ubi_device *ubi;
-+
-+ spin_lock(&ubi_devices_lock);
-+ for (i = 0; i < UBI_MAX_DEVICES; i++) {
-+ ubi = ubi_devices[i];
-+ if (ubi && MAJOR(ubi->cdev.dev) == major) {
-+ ubi_assert(ubi->ref_count >= 0);
-+ ubi->ref_count += 1;
-+ get_device(&ubi->dev);
-+ spin_unlock(&ubi_devices_lock);
-+ return ubi;
-+ }
-+ }
-+ spin_unlock(&ubi_devices_lock);
-+
-+ return NULL;
-+}
-+
-+/**
-+ * ubi_major2num - get UBI device number by character device major number.
-+ * @major: major number
-+ *
-+ * This function searches UBI device number object by its major number. If UBI
-+ * device was not found, this function returns -ENODEV, otherwise the UBI device
-+ * number is returned.
-+ */
-+int ubi_major2num(int major)
-+{
-+ int i, ubi_num = -ENODEV;
-+
-+ spin_lock(&ubi_devices_lock);
-+ for (i = 0; i < UBI_MAX_DEVICES; i++) {
-+ struct ubi_device *ubi = ubi_devices[i];
-+
-+ if (ubi && MAJOR(ubi->cdev.dev) == major) {
-+ ubi_num = ubi->ubi_num;
-+ break;
-+ }
-+ }
-+ spin_unlock(&ubi_devices_lock);
-+
-+ return ubi_num;
-+}
-
- /* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */
- static ssize_t dev_attribute_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
-- const struct ubi_device *ubi;
-+ ssize_t ret;
-+ struct ubi_device *ubi;
-
-+ /*
-+ * The below code looks weird, but it actually makes sense. We get the
-+ * UBI device reference from the contained 'struct ubi_device'. But it
-+ * is unclear if the device was removed or not yet. Indeed, if the
-+ * device was removed before we increased its reference count,
-+ * 'ubi_get_device()' will return -ENODEV and we fail.
-+ *
-+ * Remember, 'struct ubi_device' is freed in the release function, so
-+ * we still can use 'ubi->ubi_num'.
-+ */
- ubi = container_of(dev, struct ubi_device, dev);
-+ ubi = ubi_get_device(ubi->ubi_num);
-+ if (!ubi)
-+ return -ENODEV;
-+
- if (attr == &dev_eraseblock_size)
-- return sprintf(buf, "%d\n", ubi->leb_size);
-+ ret = sprintf(buf, "%d\n", ubi->leb_size);
- else if (attr == &dev_avail_eraseblocks)
-- return sprintf(buf, "%d\n", ubi->avail_pebs);
-+ ret = sprintf(buf, "%d\n", ubi->avail_pebs);
- else if (attr == &dev_total_eraseblocks)
-- return sprintf(buf, "%d\n", ubi->good_peb_count);
-+ ret = sprintf(buf, "%d\n", ubi->good_peb_count);
- else if (attr == &dev_volumes_count)
-- return sprintf(buf, "%d\n", ubi->vol_count);
-+ ret = sprintf(buf, "%d\n", ubi->vol_count - UBI_INT_VOL_COUNT);
- else if (attr == &dev_max_ec)
-- return sprintf(buf, "%d\n", ubi->max_ec);
-+ ret = sprintf(buf, "%d\n", ubi->max_ec);
- else if (attr == &dev_reserved_for_bad)
-- return sprintf(buf, "%d\n", ubi->beb_rsvd_pebs);
-+ ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs);
- else if (attr == &dev_bad_peb_count)
-- return sprintf(buf, "%d\n", ubi->bad_peb_count);
-+ ret = sprintf(buf, "%d\n", ubi->bad_peb_count);
- else if (attr == &dev_max_vol_count)
-- return sprintf(buf, "%d\n", ubi->vtbl_slots);
-+ ret = sprintf(buf, "%d\n", ubi->vtbl_slots);
- else if (attr == &dev_min_io_size)
-- return sprintf(buf, "%d\n", ubi->min_io_size);
-+ ret = sprintf(buf, "%d\n", ubi->min_io_size);
- else if (attr == &dev_bgt_enabled)
-- return sprintf(buf, "%d\n", ubi->thread_enabled);
-+ ret = sprintf(buf, "%d\n", ubi->thread_enabled);
-+ else if (attr == &dev_mtd_num)
-+ ret = sprintf(buf, "%d\n", ubi->mtd->index);
- else
-- BUG();
-+ ret = -EINVAL;
-
-- return 0;
-+ ubi_put_device(ubi);
-+ return ret;
- }
-
--/* Fake "release" method for UBI devices */
--static void dev_release(struct device *dev) { }
-+static void dev_release(struct device *dev)
-+{
-+ struct ubi_device *ubi = container_of(dev, struct ubi_device, dev);
-+
-+ kfree(ubi);
-+}
-
- /**
- * ubi_sysfs_init - initialize sysfs for an UBI device.
-@@ -150,68 +282,44 @@
- int err;
-
- ubi->dev.release = dev_release;
-- ubi->dev.devt = MKDEV(ubi->major, 0);
-+ ubi->dev.devt = ubi->cdev.dev;
- ubi->dev.class = ubi_class;
- sprintf(&ubi->dev.bus_id[0], UBI_NAME_STR"%d", ubi->ubi_num);
- err = device_register(&ubi->dev);
- if (err)
-- goto out;
-+ return err;
-
- err = device_create_file(&ubi->dev, &dev_eraseblock_size);
- if (err)
-- goto out_unregister;
-+ return err;
- err = device_create_file(&ubi->dev, &dev_avail_eraseblocks);
- if (err)
-- goto out_eraseblock_size;
-+ return err;
- err = device_create_file(&ubi->dev, &dev_total_eraseblocks);
- if (err)
-- goto out_avail_eraseblocks;
-+ return err;
- err = device_create_file(&ubi->dev, &dev_volumes_count);
- if (err)
-- goto out_total_eraseblocks;
-+ return err;
- err = device_create_file(&ubi->dev, &dev_max_ec);
- if (err)
-- goto out_volumes_count;
-+ return err;
- err = device_create_file(&ubi->dev, &dev_reserved_for_bad);
- if (err)
-- goto out_volumes_max_ec;
-+ return err;
- err = device_create_file(&ubi->dev, &dev_bad_peb_count);
- if (err)
-- goto out_reserved_for_bad;
-+ return err;
- err = device_create_file(&ubi->dev, &dev_max_vol_count);
- if (err)
-- goto out_bad_peb_count;
-+ return err;
- err = device_create_file(&ubi->dev, &dev_min_io_size);
- if (err)
-- goto out_max_vol_count;
-+ return err;
- err = device_create_file(&ubi->dev, &dev_bgt_enabled);
- if (err)
-- goto out_min_io_size;
--
-- return 0;
--
--out_min_io_size:
-- device_remove_file(&ubi->dev, &dev_min_io_size);
--out_max_vol_count:
-- device_remove_file(&ubi->dev, &dev_max_vol_count);
--out_bad_peb_count:
-- device_remove_file(&ubi->dev, &dev_bad_peb_count);
--out_reserved_for_bad:
-- device_remove_file(&ubi->dev, &dev_reserved_for_bad);
--out_volumes_max_ec:
-- device_remove_file(&ubi->dev, &dev_max_ec);
--out_volumes_count:
-- device_remove_file(&ubi->dev, &dev_volumes_count);
--out_total_eraseblocks:
-- device_remove_file(&ubi->dev, &dev_total_eraseblocks);
--out_avail_eraseblocks:
-- device_remove_file(&ubi->dev, &dev_avail_eraseblocks);
--out_eraseblock_size:
-- device_remove_file(&ubi->dev, &dev_eraseblock_size);
--out_unregister:
-- device_unregister(&ubi->dev);
--out:
-- ubi_err("failed to initialize sysfs for %s", ubi->ubi_name);
-+ return err;
-+ err = device_create_file(&ubi->dev, &dev_mtd_num);
- return err;
- }
-
-@@ -221,6 +329,7 @@
- */
- static void ubi_sysfs_close(struct ubi_device *ubi)
- {
-+ device_remove_file(&ubi->dev, &dev_mtd_num);
- device_remove_file(&ubi->dev, &dev_bgt_enabled);
- device_remove_file(&ubi->dev, &dev_min_io_size);
- device_remove_file(&ubi->dev, &dev_max_vol_count);
-@@ -244,7 +353,26 @@
-
- for (i = 0; i < ubi->vtbl_slots; i++)
- if (ubi->volumes[i])
-- ubi_free_volume(ubi, i);
-+ ubi_free_volume(ubi, ubi->volumes[i]);
-+}
-+
-+/**
-+ * free_user_volumes - free all user volumes.
-+ * @ubi: UBI device description object
-+ *
-+ * Normally the volumes are freed at the release function of the volume device
-+ * objects. However, on error paths the volumes have to be freed before the
-+ * device objects have been initialized.
-+ */
-+static void free_user_volumes(struct ubi_device *ubi)
-+{
-+ int i;
-+
-+ for (i = 0; i < ubi->vtbl_slots; i++)
-+ if (ubi->volumes[i]) {
-+ kfree(ubi->volumes[i]->eba_tbl);
-+ kfree(ubi->volumes[i]);
-+ }
- }
-
- /**
-@@ -252,16 +380,13 @@
- * @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;
- dev_t dev;
-
-- mutex_init(&ubi->vtbl_mutex);
-- spin_lock_init(&ubi->volumes_lock);
--
- sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);
-
- /*
-@@ -278,52 +403,72 @@
- return err;
- }
-
-+ ubi_assert(MINOR(dev) == 0);
- cdev_init(&ubi->cdev, &ubi_cdev_operations);
-- ubi->major = MAJOR(dev);
-- dbg_msg("%s major is %u", ubi->ubi_name, ubi->major);
-+ dbg_gen("%s major is %u", ubi->ubi_name, MAJOR(dev));
- ubi->cdev.owner = THIS_MODULE;
-
-- dev = MKDEV(ubi->major, 0);
- err = cdev_add(&ubi->cdev, dev, 1);
- if (err) {
-- ubi_err("cannot add character device %s", ubi->ubi_name);
-+ ubi_err("cannot add character device");
- goto out_unreg;
- }
-
- err = ubi_sysfs_init(ubi);
- if (err)
-- goto out_cdev;
-+ goto out_sysfs;
-
- for (i = 0; i < ubi->vtbl_slots; i++)
- if (ubi->volumes[i]) {
-- err = ubi_add_volume(ubi, i);
-- if (err)
-+ err = ubi_add_volume(ubi, ubi->volumes[i]);
-+ if (err) {
-+ ubi_err("cannot add volume %d", i);
- goto out_volumes;
-+ }
- }
-
- return 0;
-
- out_volumes:
- kill_volumes(ubi);
-+out_sysfs:
- ubi_sysfs_close(ubi);
--out_cdev:
- cdev_del(&ubi->cdev);
- out_unreg:
-- unregister_chrdev_region(MKDEV(ubi->major, 0),
-- ubi->vtbl_slots + 1);
-+ unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
-+ ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err);
- 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)
- {
- kill_volumes(ubi);
- ubi_sysfs_close(ubi);
- cdev_del(&ubi->cdev);
-- unregister_chrdev_region(MKDEV(ubi->major, 0), ubi->vtbl_slots + 1);
-+ unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
-+}
-+
-+/**
-+ * free_internal_volumes - free internal volumes.
-+ * @ubi: UBI device description object
-+ */
-+static void free_internal_volumes(struct ubi_device *ubi)
-+{
-+ int i;
-+
-+ for (i = ubi->vtbl_slots;
-+ i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
-+ kfree(ubi->volumes[i]->eba_tbl);
-+ kfree(ubi->volumes[i]);
-+ }
- }
-
- /**
-@@ -370,6 +515,7 @@
- out_wl:
- ubi_wl_close(ubi);
- out_vtbl:
-+ free_internal_volumes(ubi);
- vfree(ubi->vtbl);
- out_si:
- ubi_scan_destroy_si(si);
-@@ -377,16 +523,16 @@
- }
-
- /**
-- * 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
- * assumed:
- * o EC header is always at offset zero - this cannot be changed;
- * o VID header starts just after the EC header at the closest address
-- * aligned to @io->@hdrs_min_io_size;
-+ * aligned to @io->hdrs_min_io_size;
- * o data starts just after the VID header at the closest address aligned to
-- * @io->@min_io_size
-+ * @io->min_io_size
- *
- * This function returns zero in case of success and a negative error code in
- * case of failure.
-@@ -407,6 +553,9 @@
- return -EINVAL;
- }
-
-+ if (ubi->vid_hdr_offset < 0)
-+ return -EINVAL;
-+
- /*
- * Note, in this implementation we support MTD devices with 0x7FFFFFFF
- * physical eraseblocks maximum.
-@@ -422,9 +571,14 @@
- 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("bad min. I/O unit");
-+ ubi_err("min. I/O unit (%d) is not power of 2",
-+ ubi->min_io_size);
- return -EINVAL;
- }
-
-@@ -453,10 +607,8 @@
- }
-
- /* Similar for the data offset */
-- if (ubi->leb_start == 0) {
-- ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize;
-- ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
-- }
-+ 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);
- dbg_msg("vid_hdr_aloffset %d", ubi->vid_hdr_aloffset);
-@@ -474,7 +626,7 @@
- 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;
-@@ -499,8 +651,16 @@
- 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
-@@ -514,89 +674,162 @@
- }
-
- /**
-- * attach_mtd_dev - attach an MTD device.
-- * @mtd_dev: MTD device name or number string
-- * @vid_hdr_offset: VID header offset
-- * @data_offset: data offset
-+ * 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 attaches an MTD device to UBI. It first treats @mtd_dev as the
-- * MTD device name, and tries to open it by this name. If it is unable to open,
-- * it tries to convert @mtd_dev to an integer and open the MTD device by its
-- * number. Returns zero in case of success and a negative error code in case of
-- * failure.
-+ * 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 attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
-- int data_offset)
-+static int autoresize(struct ubi_device *ubi, int vol_id)
- {
-- struct ubi_device *ubi;
-- struct mtd_info *mtd;
-- int i, err;
-+ struct ubi_volume_desc desc;
-+ struct ubi_volume *vol = ubi->volumes[vol_id];
-+ int err, old_reserved_pebs = vol->reserved_pebs;
-
-- mtd = get_mtd_device_nm(mtd_dev);
-- if (IS_ERR(mtd)) {
-- int mtd_num;
-- char *endp;
-+ /*
-+ * 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 (PTR_ERR(mtd) != -ENODEV)
-- return PTR_ERR(mtd);
-+ if (ubi->avail_pebs == 0) {
-+ struct ubi_vtbl_record vtbl_rec;
-
- /*
-- * Probably this is not MTD device name but MTD device number -
-- * check this out.
-+ * No available PEBs to re-size the volume, clear the flag on
-+ * flash and exit.
- */
-- mtd_num = simple_strtoul(mtd_dev, &endp, 0);
-- if (*endp != '\0' || mtd_dev == endp) {
-- ubi_err("incorrect MTD device: \"%s\"", mtd_dev);
-- return -ENODEV;
-+ 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: 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 number and assigns it
-+ * automatically. Returns the new UBI device number in case of success and a
-+ * negative error code in case of failure.
-+ *
-+ * Note, the invocations of this function has to be serialized by the
-+ * @ubi_devices_mutex.
-+ */
-+int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
-+{
-+ struct ubi_device *ubi;
-+ int i, err, do_free = 1;
-+
-+ /*
-+ * Check if we already have the same MTD device attached.
-+ *
-+ * Note, this function assumes that UBI devices creations and deletions
-+ * are serialized, so it does not take the &ubi_devices_lock.
-+ */
-+ for (i = 0; i < UBI_MAX_DEVICES; i++) {
-+ ubi = ubi_devices[i];
-+ if (ubi && mtd->index == ubi->mtd->index) {
-+ dbg_err("mtd%d is already attached to ubi%d",
-+ mtd->index, i);
-+ return -EEXIST;
- }
-+ }
-
-- mtd = get_mtd_device(NULL, mtd_num);
-- if (IS_ERR(mtd))
-- return PTR_ERR(mtd);
-+ /*
-+ * Make sure this MTD device is not emulated on top of an UBI volume
-+ * already. Well, generally this recursion works fine, but there are
-+ * different problems like the UBI module takes a reference to itself
-+ * by attaching (and thus, opening) the emulated MTD device. This
-+ * results in inability to unload the module. And in general it makes
-+ * no sense to attach emulated MTD devices, so we prohibit this.
-+ */
-+ if (mtd->type == MTD_UBIVOLUME) {
-+ ubi_err("refuse attaching mtd%d - it is already emulated on "
-+ "top of UBI", mtd->index);
-+ return -EINVAL;
- }
-
-- /* Check if we already have the same MTD device attached */
-- for (i = 0; i < ubi_devices_cnt; i++)
-- if (ubi_devices[i]->mtd->index == mtd->index) {
-- ubi_err("mtd%d is already attached to ubi%d",
-- mtd->index, i);
-- err = -EINVAL;
-- goto out_mtd;
-+ if (ubi_num == UBI_DEV_NUM_AUTO) {
-+ /* Search for an empty slot in the @ubi_devices array */
-+ for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++)
-+ if (!ubi_devices[ubi_num])
-+ break;
-+ if (ubi_num == UBI_MAX_DEVICES) {
-+ dbg_err("only %d UBI devices may be created",
-+ UBI_MAX_DEVICES);
-+ return -ENFILE;
- }
-+ } else {
-+ if (ubi_num >= UBI_MAX_DEVICES)
-+ return -EINVAL;
-
-- ubi = ubi_devices[ubi_devices_cnt] = kzalloc(sizeof(struct ubi_device),
-- GFP_KERNEL);
-- if (!ubi) {
-- err = -ENOMEM;
-- goto out_mtd;
-+ /* Make sure ubi_num is not busy */
-+ if (ubi_devices[ubi_num]) {
-+ dbg_err("ubi%d already exists", ubi_num);
-+ return -EEXIST;
-+ }
- }
-
-- ubi->ubi_num = ubi_devices_cnt;
-+ ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL);
-+ if (!ubi)
-+ return -ENOMEM;
-+
- ubi->mtd = mtd;
-+ ubi->ubi_num = ubi_num;
-+ ubi->vid_hdr_offset = vid_hdr_offset;
-+ ubi->autoresize_vol_id = -1;
-
-- dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d",
-- ubi->mtd->index, ubi_devices_cnt, vid_hdr_offset, data_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);
-+
-+ ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num);
-
-- ubi->vid_hdr_offset = vid_hdr_offset;
-- ubi->leb_start = data_offset;
- err = io_init(ubi);
- if (err)
- goto out_free;
-
-- mutex_init(&ubi->buf_mutex);
-+ err = -ENOMEM;
- ubi->peb_buf1 = vmalloc(ubi->peb_size);
- if (!ubi->peb_buf1)
- goto out_free;
-
- ubi->peb_buf2 = vmalloc(ubi->peb_size);
- if (!ubi->peb_buf2)
-- goto out_free;
-+ goto out_free;
-
- #ifdef CONFIG_MTD_UBI_DEBUG
- mutex_init(&ubi->dbg_buf_mutex);
- ubi->dbg_peb_buf = vmalloc(ubi->peb_size);
- if (!ubi->dbg_peb_buf)
-- goto out_free;
-+ goto out_free;
- #endif
-
- err = attach_by_scanning(ubi);
-@@ -605,22 +838,29 @@
- 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_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt);
-- ubi_msg("MTD device name: \"%s\"", ubi->mtd->name);
-+ ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
-+ if (IS_ERR(ubi->bgt_thread)) {
-+ err = PTR_ERR(ubi->bgt_thread);
-+ ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name,
-+ err);
-+ goto out_uif;
-+ }
-+
-+ 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);
-@@ -632,18 +872,22 @@
- 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);
-- }
-+ wake_up_process(ubi->bgt_thread);
-
-- ubi_devices_cnt += 1;
-- return 0;
-+ 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);
-@@ -652,24 +896,67 @@
- vfree(ubi->dbg_peb_buf);
- #endif
- kfree(ubi);
--out_mtd:
-- put_mtd_device(mtd);
-- ubi_devices[ubi_devices_cnt] = NULL;
- return err;
- }
-
- /**
-- * detach_mtd_dev - detach an MTD device.
-- * @ubi: UBI device description object
-+ * ubi_detach_mtd_dev - detach an MTD device.
-+ * @ubi_num: UBI device number to detach from
-+ * @anyway: detach MTD even if device reference count is not zero
-+ *
-+ * This function destroys an UBI device number @ubi_num and detaches the
-+ * underlying MTD device. Returns zero in case of success and %-EBUSY if the
-+ * UBI device is busy and cannot be destroyed, and %-EINVAL if it does not
-+ * exist.
-+ *
-+ * Note, the invocations of this function has to be serialized by the
-+ * @ubi_devices_mutex.
- */
--static void detach_mtd_dev(struct ubi_device *ubi)
-+int ubi_detach_mtd_dev(int ubi_num, int anyway)
- {
-- int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index;
-+ struct ubi_de