summaryrefslogtreecommitdiff
path: root/target/linux/generic
diff options
context:
space:
mode:
authorJohn Crispin <john@openwrt.org>2014-06-11 12:59:06 +0000
committerJohn Crispin <john@openwrt.org>2014-06-11 12:59:06 +0000
commitd494983d020035cacd8d8023afad22d2761fa7fc (patch)
treefd94c75873c35abbaebf7fd3e12f093e147ce4f1 /target/linux/generic
parentba59fab9bbafce7754ef426d267e6ad9f381ed73 (diff)
downloadmtk-20170518-d494983d020035cacd8d8023afad22d2761fa7fc.zip
mtk-20170518-d494983d020035cacd8d8023afad22d2761fa7fc.tar.gz
mtk-20170518-d494983d020035cacd8d8023afad22d2761fa7fc.tar.bz2
kernel: backport ubiblock support from 3.15
Backport ubiblock support from kernel 3.15 as well as all follow-up fixes related to ubiblock. Signed-off-by: Daniel Golle <daniel@makrotopia.org> create mode 100644 target/linux/generic/patches-3.14/040-UBI-R-O-block-driver-on-top-of-UBI-volumes.patch create mode 100644 target/linux/generic/patches-3.14/041-UBI-block-do-not-use-term-attach.patch create mode 100644 target/linux/generic/patches-3.14/042-UBI-block-Mark-init-only-symbol-as-__initdata.patch create mode 100644 target/linux/generic/patches-3.14/043-UBI-block-Use-u64-for-the-64-bit-dividend.patch create mode 100644 target/linux/generic/patches-3.14/044-UBI-rename-block-device-ioctls.patch create mode 100644 target/linux/generic/patches-3.14/045-UBI-block-Remove-__initdata-from-ubiblock_param_ops.patch create mode 100644 target/linux/generic/patches-3.14/046-UBI-avoid-workqueue-format-string-leak.patch create mode 100644 target/linux/generic/patches-3.14/047-UBI-make-UBI_IOCVOLCRBLK-take-a-parameter-for-future.patch SVN-Revision: 41118
Diffstat (limited to 'target/linux/generic')
-rw-r--r--target/linux/generic/patches-3.14/040-UBI-R-O-block-driver-on-top-of-UBI-volumes.patch847
-rw-r--r--target/linux/generic/patches-3.14/041-UBI-block-do-not-use-term-attach.patch194
-rw-r--r--target/linux/generic/patches-3.14/042-UBI-block-Mark-init-only-symbol-as-__initdata.patch42
-rw-r--r--target/linux/generic/patches-3.14/043-UBI-block-Use-u64-for-the-64-bit-dividend.patch33
-rw-r--r--target/linux/generic/patches-3.14/044-UBI-rename-block-device-ioctls.patch92
-rw-r--r--target/linux/generic/patches-3.14/045-UBI-block-Remove-__initdata-from-ubiblock_param_ops.patch35
-rw-r--r--target/linux/generic/patches-3.14/046-UBI-avoid-workqueue-format-string-leak.patch30
-rw-r--r--target/linux/generic/patches-3.14/047-UBI-make-UBI_IOCVOLCRBLK-take-a-parameter-for-future.patch63
8 files changed, 1336 insertions, 0 deletions
diff --git a/target/linux/generic/patches-3.14/040-UBI-R-O-block-driver-on-top-of-UBI-volumes.patch b/target/linux/generic/patches-3.14/040-UBI-R-O-block-driver-on-top-of-UBI-volumes.patch
new file mode 100644
index 0000000..50e9e2f
--- /dev/null
+++ b/target/linux/generic/patches-3.14/040-UBI-R-O-block-driver-on-top-of-UBI-volumes.patch
@@ -0,0 +1,847 @@
+From 9d54c8a33eec78289b1b3f6e10874719c27ce0a7 Mon Sep 17 00:00:00 2001
+From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
+Date: Tue, 25 Feb 2014 13:25:22 -0300
+Subject: [PATCH] UBI: R/O block driver on top of UBI volumes
+
+This commit introduces read-only block device emulation on top of UBI volumes.
+
+Given UBI takes care of wear leveling and bad block management it's possible
+to add a thin layer to enable block device access to UBI volumes.
+This allows to use a block-oriented filesystem on a flash device.
+
+The UBI block devices are meant to be used in conjunction with any
+regular, block-oriented file system (e.g. ext4), although it's primarily
+targeted at read-only file systems, such as squashfs.
+
+Block devices are created upon user request through new ioctls:
+UBI_IOCVOLATTBLK to attach and UBI_IOCVOLDETBLK to detach.
+Also, a new UBI module parameter is added 'ubi.block'. This parameter is
+needed in order to attach a block device on boot-up time, allowing to
+mount the rootfs on a ubiblock device.
+For instance, you could have these kernel parameters:
+
+ ubi.mtd=5 ubi.block=0,0 root=/dev/ubiblock0_0
+
+Or, if you compile ubi as a module:
+
+ $ modprobe ubi mtd=/dev/mtd5 block=/dev/ubi0_0
+
+Artem: amend commentaries and massage the patch a little bit.
+
+Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
+Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+---
+ drivers/mtd/ubi/Kconfig | 15 +
+ drivers/mtd/ubi/Makefile | 1 +
+ drivers/mtd/ubi/block.c | 646 ++++++++++++++++++++++++++++++++++++++++++++
+ drivers/mtd/ubi/build.c | 11 +
+ drivers/mtd/ubi/cdev.c | 20 ++
+ drivers/mtd/ubi/ubi.h | 14 +
+ include/uapi/mtd/ubi-user.h | 11 +
+ 7 files changed, 718 insertions(+)
+ create mode 100644 drivers/mtd/ubi/block.c
+
+diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
+index 36663af..783fb18 100644
+--- a/drivers/mtd/ubi/Kconfig
++++ b/drivers/mtd/ubi/Kconfig
+@@ -87,4 +87,19 @@ config MTD_UBI_GLUEBI
+ work on top of UBI. Do not enable this unless you use legacy
+ software.
+
++config MTD_UBI_BLOCK
++ bool "Read-only block devices on top of UBI volumes"
++ default n
++ help
++ This option enables read-only UBI block devices support. UBI block
++ devices will be layered on top of UBI volumes, which means that the
++ UBI driver will transparently handle things like bad eraseblocks and
++ bit-flips. You can put any block-oriented file system on top of UBI
++ volumes in read-only mode (e.g., ext4), but it is probably most
++ practical for read-only file systems, like squashfs.
++
++ When selected, this feature will be built in the UBI driver.
++
++ If in doubt, say "N".
++
+ endif # MTD_UBI
+diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile
+index b46b0c97..4e3c3d7 100644
+--- a/drivers/mtd/ubi/Makefile
++++ b/drivers/mtd/ubi/Makefile
+@@ -3,5 +3,6 @@ obj-$(CONFIG_MTD_UBI) += ubi.o
+ ubi-y += vtbl.o vmt.o upd.o build.o cdev.o kapi.o eba.o io.o wl.o attach.o
+ ubi-y += misc.o debug.o
+ ubi-$(CONFIG_MTD_UBI_FASTMAP) += fastmap.o
++ubi-$(CONFIG_MTD_UBI_BLOCK) += block.o
+
+ obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
+diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
+new file mode 100644
+index 0000000..cea7d1c
+--- /dev/null
++++ b/drivers/mtd/ubi/block.c
+@@ -0,0 +1,646 @@
++/*
++ * Copyright (c) 2014 Ezequiel Garcia
++ * Copyright (c) 2011 Free Electrons
++ *
++ * Driver parameter handling strongly based on drivers/mtd/ubi/build.c
++ * Copyright (c) International Business Machines Corp., 2006
++ * Copyright (c) Nokia Corporation, 2007
++ * Authors: Artem Bityutskiy, Frank Haverkamp
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, version 2.
++ *
++ * 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.
++ */
++
++/*
++ * Read-only block devices on top of UBI volumes
++ *
++ * A simple implementation to allow a block device to be layered on top of a
++ * UBI volume. The implementation is provided by creating a static 1-to-1
++ * mapping between the block device and the UBI volume.
++ *
++ * The addressed byte is obtained from the addressed block sector, which is
++ * mapped linearly into the corresponding LEB:
++ *
++ * LEB number = addressed byte / LEB size
++ *
++ * This feature is compiled in the UBI core, and adds a new 'block' parameter
++ * to allow early block device attaching. Runtime block attach/detach for UBI
++ * volumes is provided through two new UBI ioctls: UBI_IOCVOLATTBLK and
++ * UBI_IOCVOLDETBLK.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/err.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/mutex.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/mtd/ubi.h>
++#include <linux/workqueue.h>
++#include <linux/blkdev.h>
++#include <linux/hdreg.h>
++#include <asm/div64.h>
++
++#include "ubi-media.h"
++#include "ubi.h"
++
++/* Maximum number of supported devices */
++#define UBIBLOCK_MAX_DEVICES 32
++
++/* Maximum length of the 'block=' parameter */
++#define UBIBLOCK_PARAM_LEN 63
++
++/* Maximum number of comma-separated items in the 'block=' parameter */
++#define UBIBLOCK_PARAM_COUNT 2
++
++struct ubiblock_param {
++ int ubi_num;
++ int vol_id;
++ char name[UBIBLOCK_PARAM_LEN+1];
++};
++
++/* Numbers of elements set in the @ubiblock_param array */
++static int ubiblock_devs __initdata;
++
++/* MTD devices specification parameters */
++static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES] __initdata;
++
++struct ubiblock {
++ struct ubi_volume_desc *desc;
++ int ubi_num;
++ int vol_id;
++ int refcnt;
++ int leb_size;
++
++ struct gendisk *gd;
++ struct request_queue *rq;
++
++ struct workqueue_struct *wq;
++ struct work_struct work;
++
++ struct mutex dev_mutex;
++ spinlock_t queue_lock;
++ struct list_head list;
++};
++
++/* Linked list of all ubiblock instances */
++static LIST_HEAD(ubiblock_devices);
++static DEFINE_MUTEX(devices_mutex);
++static int ubiblock_major;
++
++static int __init ubiblock_set_param(const char *val,
++ const struct kernel_param *kp)
++{
++ int i, ret;
++ size_t len;
++ struct ubiblock_param *param;
++ char buf[UBIBLOCK_PARAM_LEN];
++ char *pbuf = &buf[0];
++ char *tokens[UBIBLOCK_PARAM_COUNT];
++
++ if (!val)
++ return -EINVAL;
++
++ len = strnlen(val, UBIBLOCK_PARAM_LEN);
++ if (len == 0) {
++ ubi_warn("block: empty 'block=' parameter - ignored\n");
++ return 0;
++ }
++
++ if (len == UBIBLOCK_PARAM_LEN) {
++ ubi_err("block: parameter \"%s\" is too long, max. is %d\n",
++ val, UBIBLOCK_PARAM_LEN);
++ return -EINVAL;
++ }
++
++ strcpy(buf, val);
++
++ /* Get rid of the final newline */
++ if (buf[len - 1] == '\n')
++ buf[len - 1] = '\0';
++
++ for (i = 0; i < UBIBLOCK_PARAM_COUNT; i++)
++ tokens[i] = strsep(&pbuf, ",");
++
++ param = &ubiblock_param[ubiblock_devs];
++ if (tokens[1]) {
++ /* Two parameters: can be 'ubi, vol_id' or 'ubi, vol_name' */
++ ret = kstrtoint(tokens[0], 10, &param->ubi_num);
++ if (ret < 0)
++ return -EINVAL;
++
++ /* Second param can be a number or a name */
++ ret = kstrtoint(tokens[1], 10, &param->vol_id);
++ if (ret < 0) {
++ param->vol_id = -1;
++ strcpy(param->name, tokens[1]);
++ }
++
++ } else {
++ /* One parameter: must be device path */
++ strcpy(param->name, tokens[0]);
++ param->ubi_num = -1;
++ param->vol_id = -1;
++ }
++
++ ubiblock_devs++;
++
++ return 0;
++}
++
++static const struct kernel_param_ops ubiblock_param_ops = {
++ .set = ubiblock_set_param,
++};
++module_param_cb(block, &ubiblock_param_ops, NULL, 0);
++MODULE_PARM_DESC(block, "Attach block devices to UBI volumes. Parameter format: block=<path|dev,num|dev,name>.\n"
++ "Multiple \"block\" parameters may be specified.\n"
++ "UBI volumes may be specified by their number, name, or path to the device node.\n"
++ "Examples\n"
++ "Using the UBI volume path:\n"
++ "ubi.block=/dev/ubi0_0\n"
++ "Using the UBI device, and the volume name:\n"
++ "ubi.block=0,rootfs\n"
++ "Using both UBI device number and UBI volume number:\n"
++ "ubi.block=0,0\n");
++
++static struct ubiblock *find_dev_nolock(int ubi_num, int vol_id)
++{
++ struct ubiblock *dev;
++
++ list_for_each_entry(dev, &ubiblock_devices, list)
++ if (dev->ubi_num == ubi_num && dev->vol_id == vol_id)
++ return dev;
++ return NULL;
++}
++
++static int ubiblock_read_to_buf(struct ubiblock *dev, char *buffer,
++ int leb, int offset, int len)
++{
++ int ret;
++
++ ret = ubi_read(dev->desc, leb, buffer, offset, len);
++ if (ret) {
++ ubi_err("%s ubi_read error %d",
++ dev->gd->disk_name, ret);
++ return ret;
++ }
++ return 0;
++}
++
++static int ubiblock_read(struct ubiblock *dev, char *buffer,
++ sector_t sec, int len)
++{
++ int ret, leb, offset;
++ int bytes_left = len;
++ int to_read = len;
++ loff_t pos = sec << 9;
++
++ /* Get LEB:offset address to read from */
++ offset = do_div(pos, dev->leb_size);
++ leb = pos;
++
++ while (bytes_left) {
++ /*
++ * We can only read one LEB at a time. Therefore if the read
++ * length is larger than one LEB size, we split the operation.
++ */
++ if (offset + to_read > dev->leb_size)
++ to_read = dev->leb_size - offset;
++
++ ret = ubiblock_read_to_buf(dev, buffer, leb, offset, to_read);
++ if (ret)
++ return ret;
++
++ buffer += to_read;
++ bytes_left -= to_read;
++ to_read = bytes_left;
++ leb += 1;
++ offset = 0;
++ }
++ return 0;
++}
++
++static int do_ubiblock_request(struct ubiblock *dev, struct request *req)
++{
++ int len, ret;
++ sector_t sec;
++
++ if (req->cmd_type != REQ_TYPE_FS)
++ return -EIO;
++
++ if (blk_rq_pos(req) + blk_rq_cur_sectors(req) >
++ get_capacity(req->rq_disk))
++ return -EIO;
++
++ if (rq_data_dir(req) != READ)
++ return -ENOSYS; /* Write not implemented */
++
++ sec = blk_rq_pos(req);
++ len = blk_rq_cur_bytes(req);
++
++ /*
++ * Let's prevent the device from being removed while we're doing I/O
++ * work. Notice that this means we serialize all the I/O operations,
++ * but it's probably of no impact given the NAND core serializes
++ * flash access anyway.
++ */
++ mutex_lock(&dev->dev_mutex);
++ ret = ubiblock_read(dev, req->buffer, sec, len);
++ mutex_unlock(&dev->dev_mutex);
++
++ return ret;
++}
++
++static void ubiblock_do_work(struct work_struct *work)
++{
++ struct ubiblock *dev =
++ container_of(work, struct ubiblock, work);
++ struct request_queue *rq = dev->rq;
++ struct request *req;
++ int res;
++
++ spin_lock_irq(rq->queue_lock);
++
++ req = blk_fetch_request(rq);
++ while (req) {
++
++ spin_unlock_irq(rq->queue_lock);
++ res = do_ubiblock_request(dev, req);
++ spin_lock_irq(rq->queue_lock);
++
++ /*
++ * If we're done with this request,
++ * we need to fetch a new one
++ */
++ if (!__blk_end_request_cur(req, res))
++ req = blk_fetch_request(rq);
++ }
++
++ spin_unlock_irq(rq->queue_lock);
++}
++
++static void ubiblock_request(struct request_queue *rq)
++{
++ struct ubiblock *dev;
++ struct request *req;
++
++ dev = rq->queuedata;
++
++ if (!dev)
++ while ((req = blk_fetch_request(rq)) != NULL)
++ __blk_end_request_all(req, -ENODEV);
++ else
++ queue_work(dev->wq, &dev->work);
++}
++
++static int ubiblock_open(struct block_device *bdev, fmode_t mode)
++{
++ struct ubiblock *dev = bdev->bd_disk->private_data;
++ int ret;
++
++ mutex_lock(&dev->dev_mutex);
++ if (dev->refcnt > 0) {
++ /*
++ * The volume is already open, just increase the reference
++ * counter.
++ */
++ goto out_done;
++ }
++
++ /*
++ * We want users to be aware they should only mount us as read-only.
++ * It's just a paranoid check, as write requests will get rejected
++ * in any case.
++ */
++ if (mode & FMODE_WRITE) {
++ ret = -EPERM;
++ goto out_unlock;
++ }
++
++ dev->desc = ubi_open_volume(dev->ubi_num, dev->vol_id, UBI_READONLY);
++ if (IS_ERR(dev->desc)) {
++ ubi_err("%s failed to open ubi volume %d_%d",
++ dev->gd->disk_name, dev->ubi_num, dev->vol_id);
++ ret = PTR_ERR(dev->desc);
++ dev->desc = NULL;
++ goto out_unlock;
++ }
++
++out_done:
++ dev->refcnt++;
++ mutex_unlock(&dev->dev_mutex);
++ return 0;
++
++out_unlock:
++ mutex_unlock(&dev->dev_mutex);
++ return ret;
++}
++
++static void ubiblock_release(struct gendisk *gd, fmode_t mode)
++{
++ struct ubiblock *dev = gd->private_data;
++
++ mutex_lock(&dev->dev_mutex);
++ dev->refcnt--;
++ if (dev->refcnt == 0) {
++ ubi_close_volume(dev->desc);
++ dev->desc = NULL;
++ }
++ mutex_unlock(&dev->dev_mutex);
++}
++
++static int ubiblock_getgeo(struct block_device *bdev, struct hd_geometry *geo)
++{
++ /* Some tools might require this information */
++ geo->heads = 1;
++ geo->cylinders = 1;
++ geo->sectors = get_capacity(bdev->bd_disk);
++ geo->start = 0;
++ return 0;
++}
++
++static const struct block_device_operations ubiblock_ops = {
++ .owner = THIS_MODULE,
++ .open = ubiblock_open,
++ .release = ubiblock_release,
++ .getgeo = ubiblock_getgeo,
++};
++
++int ubiblock_add(struct ubi_volume_info *vi)
++{
++ struct ubiblock *dev;
++ struct gendisk *gd;
++ int disk_capacity;
++ int ret;
++
++ /* Check that the volume isn't already handled */
++ mutex_lock(&devices_mutex);
++ if (find_dev_nolock(vi->ubi_num, vi->vol_id)) {
++ mutex_unlock(&devices_mutex);
++ return -EEXIST;
++ }
++ mutex_unlock(&devices_mutex);
++
++ dev = kzalloc(sizeof(struct ubiblock), GFP_KERNEL);
++ if (!dev)
++ return -ENOMEM;
++
++ mutex_init(&dev->dev_mutex);
++
++ dev->ubi_num = vi->ubi_num;
++ dev->vol_id = vi->vol_id;
++ dev->leb_size = vi->usable_leb_size;
++
++ /* Initialize the gendisk of this ubiblock device */
++ gd = alloc_disk(1);
++ if (!gd) {
++ ubi_err("block: alloc_disk failed");
++ ret = -ENODEV;
++ goto out_free_dev;
++ }
++
++ gd->fops = &ubiblock_ops;
++ gd->major = ubiblock_major;
++ gd->first_minor = dev->ubi_num * UBI_MAX_VOLUMES + dev->vol_id;
++ gd->private_data = dev;
++ sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id);
++ disk_capacity = (vi->size * vi->usable_leb_size) >> 9;
++ set_capacity(gd, disk_capacity);
++ dev->gd = gd;
++
++ spin_lock_init(&dev->queue_lock);
++ dev->rq = blk_init_queue(ubiblock_request, &dev->queue_lock);
++ if (!dev->rq) {
++ ubi_err("block: blk_init_queue failed");
++ ret = -ENODEV;
++ goto out_put_disk;
++ }
++
++ dev->rq->queuedata = dev;
++ dev->gd->queue = dev->rq;
++
++ /*
++ * Create one workqueue per volume (per registered block device).
++ * Rembember workqueues are cheap, they're not threads.
++ */
++ dev->wq = alloc_workqueue(gd->disk_name, 0, 0);
++ if (!dev->wq)
++ goto out_free_queue;
++ INIT_WORK(&dev->work, ubiblock_do_work);
++
++ mutex_lock(&devices_mutex);
++ list_add_tail(&dev->list, &ubiblock_devices);
++ mutex_unlock(&devices_mutex);
++
++ /* Must be the last step: anyone can call file ops from now on */
++ add_disk(dev->gd);
++ ubi_msg("%s created from ubi%d:%d(%s)",
++ dev->gd->disk_name, dev->ubi_num, dev->vol_id, vi->name);
++ return 0;
++
++out_free_queue:
++ blk_cleanup_queue(dev->rq);
++out_put_disk:
++ put_disk(dev->gd);
++out_free_dev:
++ kfree(dev);
++
++ return ret;
++}
++
++static void ubiblock_cleanup(struct ubiblock *dev)
++{
++ del_gendisk(dev->gd);
++ blk_cleanup_queue(dev->rq);
++ ubi_msg("%s released", dev->gd->disk_name);
++ put_disk(dev->gd);
++}
++
++int ubiblock_del(struct ubi_volume_info *vi)
++{
++ struct ubiblock *dev;
++
++ mutex_lock(&devices_mutex);
++ dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
++ if (!dev) {
++ mutex_unlock(&devices_mutex);
++ return -ENODEV;
++ }
++
++ /* Found a device, let's lock it so we can check if it's busy */
++ mutex_lock(&dev->dev_mutex);
++ if (dev->refcnt > 0) {
++ mutex_unlock(&dev->dev_mutex);
++ mutex_unlock(&devices_mutex);
++ return -EBUSY;
++ }
++
++ /* Remove from device list */
++ list_del(&dev->list);
++ mutex_unlock(&devices_mutex);
++
++ /* Flush pending work and stop this workqueue */
++ destroy_workqueue(dev->wq);
++
++ ubiblock_cleanup(dev);
++ mutex_unlock(&dev->dev_mutex);
++ kfree(dev);
++ return 0;
++}
++
++static void ubiblock_resize(struct ubi_volume_info *vi)
++{
++ struct ubiblock *dev;
++ int disk_capacity;
++
++ /*
++ * Need to lock the device list until we stop using the device,
++ * otherwise the device struct might get released in 'ubiblock_del()'.
++ */
++ mutex_lock(&devices_mutex);
++ dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
++ if (!dev) {
++ mutex_unlock(&devices_mutex);
++ return;
++ }
++
++ mutex_lock(&dev->dev_mutex);
++ disk_capacity = (vi->size * vi->usable_leb_size) >> 9;
++ set_capacity(dev->gd, disk_capacity);
++ ubi_msg("%s resized to %d LEBs", dev->gd->disk_name, vi->size);
++ mutex_unlock(&dev->dev_mutex);
++ mutex_unlock(&devices_mutex);
++}
++
++static int ubiblock_notify(struct notifier_block *nb,
++ unsigned long notification_type, void *ns_ptr)
++{
++ struct ubi_notification *nt = ns_ptr;
++
++ switch (notification_type) {
++ case UBI_VOLUME_ADDED:
++ /*
++ * We want to enforce explicit block device attaching for
++ * volumes, so when a volume is added we do nothing.
++ */
++ break;
++ case UBI_VOLUME_REMOVED:
++ ubiblock_del(&nt->vi);
++ break;
++ case UBI_VOLUME_RESIZED:
++ ubiblock_resize(&nt->vi);
++ break;
++ default:
++ break;
++ }
++ return NOTIFY_OK;
++}
++
++static struct notifier_block ubiblock_notifier = {
++ .notifier_call = ubiblock_notify,
++};
++
++static struct ubi_volume_desc * __init
++open_volume_desc(const char *name, int ubi_num, int vol_id)
++{
++ if (ubi_num == -1)
++ /* No ubi num, name must be a vol device path */
++ return ubi_open_volume_path(name, UBI_READONLY);
++ else if (vol_id == -1)
++ /* No vol_id, must be vol_name */
++ return ubi_open_volume_nm(ubi_num, name, UBI_READONLY);
++ else
++ return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
++}
++
++static int __init ubiblock_attach_from_param(void)
++{
++ int i, ret;
++ struct ubiblock_param *p;
++ struct ubi_volume_desc *desc;
++ struct ubi_volume_info vi;
++
++ for (i = 0; i < ubiblock_devs; i++) {
++ p = &ubiblock_param[i];
++
++ desc = open_volume_desc(p->name, p->ubi_num, p->vol_id);
++ if (IS_ERR(desc)) {
++ ubi_err("block: can't open volume, err=%ld\n",
++ PTR_ERR(desc));
++ ret = PTR_ERR(desc);
++ break;
++ }
++
++ ubi_get_volume_info(desc, &vi);
++ ubi_close_volume(desc);
++
++ ret = ubiblock_add(&vi);
++ if (ret) {
++ ubi_err("block: can't add '%s' volume, err=%d\n",
++ vi.name, ret);
++ break;
++ }
++ }
++ return ret;
++}
++
++static void ubiblock_detach_all(void)
++{
++ struct ubiblock *next;
++ struct ubiblock *dev;
++
++ list_for_each_entry_safe(dev, next, &ubiblock_devices, list) {
++ /* Flush pending work and stop workqueue */
++ destroy_workqueue(dev->wq);
++ /* The module is being forcefully removed */
++ WARN_ON(dev->desc);
++ /* Remove from device list */
++ list_del(&dev->list);
++ ubiblock_cleanup(dev);
++ kfree(dev);
++ }
++}
++
++int __init ubiblock_init(void)
++{
++ int ret;
++
++ ubiblock_major = register_blkdev(0, "ubiblock");
++ if (ubiblock_major < 0)
++ return ubiblock_major;
++
++ /* Attach block devices from 'block=' module param */
++ ret = ubiblock_attach_from_param();
++ if (ret)
++ goto err_detach;
++
++ /*
++ * Block devices needs to be attached to volumes explicitly
++ * upon user request. So we ignore existing volumes.
++ */
++ ret = ubi_register_volume_notifier(&ubiblock_notifier, 1);
++ if (ret)
++ goto err_unreg;
++ return 0;
++
++err_unreg:
++ unregister_blkdev(ubiblock_major, "ubiblock");
++err_detach:
++ ubiblock_detach_all();
++ return ret;
++}
++
++void __exit ubiblock_exit(void)
++{
++ ubi_unregister_volume_notifier(&ubiblock_notifier);
++ ubiblock_detach_all();
++ unregister_blkdev(ubiblock_major, "ubiblock");
++}
+diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
+index 57deae9..6e30a3c 100644
+--- a/drivers/mtd/ubi/build.c
++++ b/drivers/mtd/ubi/build.c
+@@ -1298,6 +1298,15 @@ static int __init ubi_init(void)
+ }
+ }
+
++ err = ubiblock_init();
++ if (err) {
++ ubi_err("block: cannot initialize, error %d", err);
++
++ /* See comment above re-ubi_is_module(). */
++ if (ubi_is_module())
++ goto out_detach;
++ }
++
+ return 0;
+
+ out_detach:
+@@ -1326,6 +1335,8 @@ static void __exit ubi_exit(void)
+ {
+ int i;
+
++ ubiblock_exit();
++
+ for (i = 0; i < UBI_MAX_DEVICES; i++)
+ if (ubi_devices[i]) {
+ mutex_lock(&ubi_devices_mutex);
+diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
+index 8ca49f2..39d3774 100644
+--- a/drivers/mtd/ubi/cdev.c
++++ b/drivers/mtd/ubi/cdev.c
+@@ -561,6 +561,26 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
+ break;
+ }
+
++ /* Attach a block device to an UBI volume */
++ case UBI_IOCVOLATTBLK:
++ {
++ struct ubi_volume_info vi;
++
++ ubi_get_volume_info(desc, &vi);
++ err = ubiblock_add(&vi);
++ break;
++ }
++
++ /* Dettach a block device from an UBI volume */
++ case UBI_IOCVOLDETBLK:
++ {
++ struct ubi_volume_info vi;
++
++ ubi_get_volume_info(desc, &vi);
++ err = ubiblock_del(&vi);
++ break;
++ }
++
+ default:
+ err = -ENOTTY;
+ break;
+diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
+index 8ea6297..e76ff98 100644
+--- a/drivers/mtd/ubi/ubi.h
++++ b/drivers/mtd/ubi/ubi.h
+@@ -864,6 +864,20 @@ int ubi_update_fastmap(struct ubi_device *ubi);
+ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
+ int fm_anchor);
+
++/* block.c */
++#ifdef CONFIG_MTD_UBI_BLOCK
++int ubiblock_init(void);
++void ubiblock_exit(void);
++int ubiblock_add(struct ubi_volume_info *vi);
++int ubiblock_del(struct ubi_volume_info *vi);
++#else
++static inline int ubiblock_init(void) { return 0; }
++static inline void ubiblock_exit(void) {}
++static inline int ubiblock_add(struct ubi_volume_info *vi) { return -ENOTTY; }
++static inline int ubiblock_del(struct ubi_volume_info *vi) { return -ENOTTY; }
++#endif
++
++
+ /*
+ * ubi_rb_for_each_entry - walk an RB-tree.
+ * @rb: a pointer to type 'struct rb_node' to use as a loop counter
+diff --git a/include/uapi/mtd/ubi-user.h b/include/uapi/mtd/ubi-user.h
+index 723c324..b98585a 100644
+--- a/include/uapi/mtd/ubi-user.h
++++ b/include/uapi/mtd/ubi-user.h
+@@ -134,6 +134,13 @@
+ * used. A pointer to a &struct ubi_set_vol_prop_req object is expected to be
+ * passed. The object describes which property should be set, and to which value
+ * it should be set.
++ *
++ * Block devices on UBI volumes
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * To attach or detach a block device from an UBI volume the %UBI_IOCVOLATTBLK
++ * and %UBI_IOCVOLDETBLK ioctl commands should be used, respectively.
++ * These commands take no arguments.
+ */
+
+ /*
+@@ -191,6 +198,10 @@
+ /* Set an UBI volume property */
+ #define UBI_IOCSETVOLPROP _IOW(UBI_VOL_IOC_MAGIC, 6, \
+ struct ubi_set_vol_prop_req)
++/* Attach a block device to an UBI volume */
++#define UBI_IOCVOLATTBLK _IO(UBI_VOL_IOC_MAGIC, 7)
++/* Detach a block device from an UBI volume */
++#define UBI_IOCVOLDETBLK _IO(UBI_VOL_IOC_MAGIC, 8)
+
+ /* Maximum MTD device name length supported by UBI */
+ #define MAX_UBI_MTD_NAME_LEN 127
+--
+1.9.2
+
diff --git a/target/linux/generic/patches-3.14/041-UBI-block-do-not-use-term-attach.patch b/target/linux/generic/patches-3.14/041-UBI-block-do-not-use-term-attach.patch
new file mode 100644
index 0000000..bcbb92c
--- /dev/null
+++ b/target/linux/generic/patches-3.14/041-UBI-block-do-not-use-term-attach.patch
@@ -0,0 +1,194 @@
+From 4d283ee2517303afa54ad6cbd9342a2f748cf509 Mon Sep 17 00:00:00 2001
+From: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Date: Tue, 4 Mar 2014 12:00:26 +0200
+Subject: [PATCH] UBI: block: do not use term "attach"
+
+We already use term attach/detach for UBI->MTD relations, let's not use this
+for UBI->ubiblock relations to avoid confusion. Just use 'create' and 'remove'
+instead. E.g., "create a R/O block device on top of a UBI volume".
+
+Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+---
+ drivers/mtd/ubi/block.c | 39 ++++++++++++++++++++-------------------
+ drivers/mtd/ubi/cdev.c | 4 ++--
+ drivers/mtd/ubi/ubi.h | 14 ++++++++++----
+ 3 files changed, 32 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
+index cea7d1c..6402e41 100644
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -29,10 +29,10 @@
+ *
+ * LEB number = addressed byte / LEB size
+ *
+- * This feature is compiled in the UBI core, and adds a new 'block' parameter
+- * to allow early block device attaching. Runtime block attach/detach for UBI
+- * volumes is provided through two new UBI ioctls: UBI_IOCVOLATTBLK and
+- * UBI_IOCVOLDETBLK.
++ * This feature is compiled in the UBI core, and adds a 'block' parameter
++ * to allow early creation of block devices on top of UBI volumes. Runtime
++ * block creation/removal for UBI volumes is provided through two UBI ioctls:
++ * UBI_IOCVOLATTBLK and UBI_IOCVOLDETBLK.
+ */
+
+ #include <linux/module.h>
+@@ -374,7 +374,7 @@ static const struct block_device_operations ubiblock_ops = {
+ .getgeo = ubiblock_getgeo,
+ };
+
+-int ubiblock_add(struct ubi_volume_info *vi)
++int ubiblock_create(struct ubi_volume_info *vi)
+ {
+ struct ubiblock *dev;
+ struct gendisk *gd;
+@@ -464,7 +464,7 @@ static void ubiblock_cleanup(struct ubiblock *dev)
+ put_disk(dev->gd);
+ }
+
+-int ubiblock_del(struct ubi_volume_info *vi)
++int ubiblock_remove(struct ubi_volume_info *vi)
+ {
+ struct ubiblock *dev;
+
+@@ -503,7 +503,8 @@ static void ubiblock_resize(struct ubi_volume_info *vi)
+
+ /*
+ * Need to lock the device list until we stop using the device,
+- * otherwise the device struct might get released in 'ubiblock_del()'.
++ * otherwise the device struct might get released in
++ * 'ubiblock_remove()'.
+ */
+ mutex_lock(&devices_mutex);
+ dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
+@@ -528,12 +529,12 @@ static int ubiblock_notify(struct notifier_block *nb,
+ switch (notification_type) {
+ case UBI_VOLUME_ADDED:
+ /*
+- * We want to enforce explicit block device attaching for
++ * We want to enforce explicit block device creation for
+ * volumes, so when a volume is added we do nothing.
+ */
+ break;
+ case UBI_VOLUME_REMOVED:
+- ubiblock_del(&nt->vi);
++ ubiblock_remove(&nt->vi);
+ break;
+ case UBI_VOLUME_RESIZED:
+ ubiblock_resize(&nt->vi);
+@@ -561,7 +562,7 @@ open_volume_desc(const char *name, int ubi_num, int vol_id)
+ return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
+ }
+
+-static int __init ubiblock_attach_from_param(void)
++static int __init ubiblock_create_from_param(void)
+ {
+ int i, ret;
+ struct ubiblock_param *p;
+@@ -582,7 +583,7 @@ static int __init ubiblock_attach_from_param(void)
+ ubi_get_volume_info(desc, &vi);
+ ubi_close_volume(desc);
+
+- ret = ubiblock_add(&vi);
++ ret = ubiblock_create(&vi);
+ if (ret) {
+ ubi_err("block: can't add '%s' volume, err=%d\n",
+ vi.name, ret);
+@@ -592,7 +593,7 @@ static int __init ubiblock_attach_from_param(void)
+ return ret;
+ }
+
+-static void ubiblock_detach_all(void)
++static void ubiblock_remove_all(void)
+ {
+ struct ubiblock *next;
+ struct ubiblock *dev;
+@@ -618,13 +619,13 @@ int __init ubiblock_init(void)
+ return ubiblock_major;
+
+ /* Attach block devices from 'block=' module param */
+- ret = ubiblock_attach_from_param();
++ ret = ubiblock_create_from_param();
+ if (ret)
+- goto err_detach;
++ goto err_remove;
+
+ /*
+- * Block devices needs to be attached to volumes explicitly
+- * upon user request. So we ignore existing volumes.
++ * Block devices are only created upon user requests, so we ignore
++ * existing volumes.
+ */
+ ret = ubi_register_volume_notifier(&ubiblock_notifier, 1);
+ if (ret)
+@@ -633,14 +634,14 @@ int __init ubiblock_init(void)
+
+ err_unreg:
+ unregister_blkdev(ubiblock_major, "ubiblock");
+-err_detach:
+- ubiblock_detach_all();
++err_remove:
++ ubiblock_remove_all();
+ return ret;
+ }
+
+ void __exit ubiblock_exit(void)
+ {
+ ubi_unregister_volume_notifier(&ubiblock_notifier);
+- ubiblock_detach_all();
++ ubiblock_remove_all();
+ unregister_blkdev(ubiblock_major, "ubiblock");
+ }
+diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
+index 39d3774..11c8473 100644
+--- a/drivers/mtd/ubi/cdev.c
++++ b/drivers/mtd/ubi/cdev.c
+@@ -567,7 +567,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
+ struct ubi_volume_info vi;
+
+ ubi_get_volume_info(desc, &vi);
+- err = ubiblock_add(&vi);
++ err = ubiblock_create(&vi);
+ break;
+ }
+
+@@ -577,7 +577,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
+ struct ubi_volume_info vi;
+
+ ubi_get_volume_info(desc, &vi);
+- err = ubiblock_del(&vi);
++ err = ubiblock_remove(&vi);
+ break;
+ }
+
+diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
+index e76ff98..2e588a9 100644
+--- a/drivers/mtd/ubi/ubi.h
++++ b/drivers/mtd/ubi/ubi.h
+@@ -868,13 +868,19 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
+ #ifdef CONFIG_MTD_UBI_BLOCK
+ int ubiblock_init(void);
+ void ubiblock_exit(void);
+-int ubiblock_add(struct ubi_volume_info *vi);
+-int ubiblock_del(struct ubi_volume_info *vi);
++int ubiblock_create(struct ubi_volume_info *vi);
++int ubiblock_remove(struct ubi_volume_info *vi);
+ #else
+ static inline int ubiblock_init(void) { return 0; }
+ static inline void ubiblock_exit(void) {}
+-static inline int ubiblock_add(struct ubi_volume_info *vi) { return -ENOTTY; }
+-static inline int ubiblock_del(struct ubi_volume_info *vi) { return -ENOTTY; }
++static inline int ubiblock_create(struct ubi_volume_info *vi)
++{
++ return -ENOTTY;
++}
++static inline int ubiblock_remove(struct ubi_volume_info *vi)
++{
++ return -ENOTTY;
++}
+ #endif
+
+
+--
+1.9.2
+
diff --git a/target/linux/generic/patches-3.14/042-UBI-block-Mark-init-only-symbol-as-__initdata.patch b/target/linux/generic/patches-3.14/042-UBI-block-Mark-init-only-symbol-as-__initdata.patch
new file mode 100644
index 0000000..181cecb
--- /dev/null
+++ b/target/linux/generic/patches-3.14/042-UBI-block-Mark-init-only-symbol-as-__initdata.patch
@@ -0,0 +1,42 @@
+From ca2b722d1ab5bc3ffc34b5995248968cd8a7cb6f Mon Sep 17 00:00:00 2001
+From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
+Date: Mon, 3 Mar 2014 13:42:38 -0300
+Subject: [PATCH] UBI: block: Mark init-only symbol as __initdata
+
+ubiblock_param_ops should be marked as __init as it's only used to set
+a driver parameter on insertion time. This commit fixes the following:
+
+ WARNING: drivers/mtd/built-in.o(.text+0x653ac): Section mismatch in
+ reference from the variable ubiblock_param_ops to the function
+ .init.text:ubiblock_set_param()
+
+ The function ubiblock_param_ops() references the function __init
+ ubiblock_set_param(). This is often because ubiblock_param_ops lacks a
+ __init annotation or the annotation of ubiblock_set_param is wrong.
+
+Given gcc errors if the struct is marked const __initdata, this commit
+drops the const mark from it.
+
+Reported-by: kbuild test robot <fengguang.wu@intel.com>
+Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
+Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+---
+ drivers/mtd/ubi/block.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
+index 6402e41..cd6be98 100644
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -156,7 +156,7 @@ static int __init ubiblock_set_param(const char *val,
+ return 0;
+ }
+
+-static const struct kernel_param_ops ubiblock_param_ops = {
++static struct kernel_param_ops ubiblock_param_ops __initdata = {
+ .set = ubiblock_set_param,
+ };
+ module_param_cb(block, &ubiblock_param_ops, NULL, 0);
+--
+1.9.2
+
diff --git a/target/linux/generic/patches-3.14/043-UBI-block-Use-u64-for-the-64-bit-dividend.patch b/target/linux/generic/patches-3.14/043-UBI-block-Use-u64-for-the-64-bit-dividend.patch
new file mode 100644
index 0000000..648b42f
--- /dev/null
+++ b/target/linux/generic/patches-3.14/043-UBI-block-Use-u64-for-the-64-bit-dividend.patch
@@ -0,0 +1,33 @@
+From 9981e14ab2f7c6a4d2bb45e51a6371964919837d Mon Sep 17 00:00:00 2001
+From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
+Date: Mon, 3 Mar 2014 13:42:39 -0300
+Subject: [PATCH] UBI: block: Use 'u64' for the 64-bit dividend
+
+Fixes the following warning on ARCH=avr32:
+
+ drivers/mtd/ubi/block.c: In function 'ubiblock_read':
+ drivers/mtd/ubi/block.c:207: warning: comparison of distinct pointer types lacks a cast
+
+Reported-by: kbuild test robot <fengguang.wu@intel.com>
+Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
+Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+---
+ drivers/mtd/ubi/block.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
+index cd6be98..16e6731 100644
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -201,7 +201,7 @@ static int ubiblock_read(struct ubiblock *dev, char *buffer,
+ int ret, leb, offset;
+ int bytes_left = len;
+ int to_read = len;
+- loff_t pos = sec << 9;
++ u64 pos = sec << 9;
+
+ /* Get LEB:offset address to read from */
+ offset = do_div(pos, dev->leb_size);
+--
+1.9.2
+
diff --git a/target/linux/generic/patches-3.14/044-UBI-rename-block-device-ioctls.patch b/target/linux/generic/patches-3.14/044-UBI-rename-block-device-ioctls.patch
new file mode 100644
index 0000000..a010a3c
--- /dev/null
+++ b/target/linux/generic/patches-3.14/044-UBI-rename-block-device-ioctls.patch
@@ -0,0 +1,92 @@
+From 8af871887fcba470ff9265c65cff7d14d9e0e3f9 Mon Sep 17 00:00:00 2001
+From: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Date: Wed, 5 Mar 2014 13:01:56 +0200
+Subject: [PATCH] UBI: rename block device ioctls
+
+Rename the UBI_IOCVOLATTBLK and UBI_IOCVOLDETBLK to UBI_IOCVOLCRBLK and
+UBI_IOCVOLRMBLK, because we do not use terms "attach" and "detach" for the R/O
+block devices on top of UBI volumes. Instead, we use terms "create" and
+"remove". This patch also amends the related commentaries.
+
+Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Acked-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
+---
+ drivers/mtd/ubi/block.c | 2 +-
+ drivers/mtd/ubi/cdev.c | 8 ++++----
+ include/uapi/mtd/ubi-user.h | 14 +++++++-------
+ 3 files changed, 12 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
+index 16e6731..69a74fd 100644
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -32,7 +32,7 @@
+ * This feature is compiled in the UBI core, and adds a 'block' parameter
+ * to allow early creation of block devices on top of UBI volumes. Runtime
+ * block creation/removal for UBI volumes is provided through two UBI ioctls:
+- * UBI_IOCVOLATTBLK and UBI_IOCVOLDETBLK.
++ * UBI_IOCVOLCRBLK and UBI_IOCVOLRMBLK.
+ */
+
+ #include <linux/module.h>
+diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
+index 11c8473..f54562a 100644
+--- a/drivers/mtd/ubi/cdev.c
++++ b/drivers/mtd/ubi/cdev.c
+@@ -561,8 +561,8 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
+ break;
+ }
+
+- /* Attach a block device to an UBI volume */
+- case UBI_IOCVOLATTBLK:
++ /* Create a R/O block device on top of the UBI volume */
++ case UBI_IOCVOLCRBLK:
+ {
+ struct ubi_volume_info vi;
+
+@@ -571,8 +571,8 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
+ break;
+ }
+
+- /* Dettach a block device from an UBI volume */
+- case UBI_IOCVOLDETBLK:
++ /* Remove the R/O block device */
++ case UBI_IOCVOLRMBLK:
+ {
+ struct ubi_volume_info vi;
+
+diff --git a/include/uapi/mtd/ubi-user.h b/include/uapi/mtd/ubi-user.h
+index b98585a..9c885e2 100644
+--- a/include/uapi/mtd/ubi-user.h
++++ b/include/uapi/mtd/ubi-user.h
+@@ -138,9 +138,9 @@
+ * Block devices on UBI volumes
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+- * To attach or detach a block device from an UBI volume the %UBI_IOCVOLATTBLK
+- * and %UBI_IOCVOLDETBLK ioctl commands should be used, respectively.
+- * These commands take no arguments.
++ * To create or remove a R/O block device on top of an UBI volume the
++ * %UBI_IOCVOLCRBLK and %UBI_IOCVOLRMBLK ioctl commands should be used,
++ * respectively. These commands take no arguments.
+ */
+
+ /*
+@@ -198,10 +198,10 @@
+ /* Set an UBI volume property */
+ #define UBI_IOCSETVOLPROP _IOW(UBI_VOL_IOC_MAGIC, 6, \
+ struct ubi_set_vol_prop_req)
+-/* Attach a block device to an UBI volume */
+-#define UBI_IOCVOLATTBLK _IO(UBI_VOL_IOC_MAGIC, 7)
+-/* Detach a block device from an UBI volume */
+-#define UBI_IOCVOLDETBLK _IO(UBI_VOL_IOC_MAGIC, 8)
++/* Create a R/O block device on top of an UBI volume */
++#define UBI_IOCVOLCRBLK _IO(UBI_VOL_IOC_MAGIC, 7)
++/* Remove the R/O block device */
++#define UBI_IOCVOLRMBLK _IO(UBI_VOL_IOC_MAGIC, 8)
+
+ /* Maximum MTD device name length supported by UBI */
+ #define MAX_UBI_MTD_NAME_LEN 127
+--
+1.9.2
+
diff --git a/target/linux/generic/patches-3.14/045-UBI-block-Remove-__initdata-from-ubiblock_param_ops.patch b/target/linux/generic/patches-3.14/045-UBI-block-Remove-__initdata-from-ubiblock_param_ops.patch
new file mode 100644
index 0000000..f5ae724
--- /dev/null
+++ b/target/linux/generic/patches-3.14/045-UBI-block-Remove-__initdata-from-ubiblock_param_ops.patch
@@ -0,0 +1,35 @@
+From d56030ac25d383218045c5d87e98e0494d6af3ad Mon Sep 17 00:00:00 2001
+From: Richard Weinberger <richard@nod.at>
+Date: Wed, 19 Mar 2014 11:43:22 +0100
+Subject: [PATCH] UBI: block: Remove __initdata from ubiblock_param_ops
+
+You cannot mark these parameters as __initdata.
+Otherwise the data is gone upon module exit.
+
+Fixes:
+[ 172.045465] BUG: unable to handle kernel paging request at ffffffffa001db38
+[ 172.046020] IP: [<ffffffff81067aa4>] destroy_params+0x24/0x50
+
+Signed-off-by: Richard Weinberger <richard@nod.at>
+Acked-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
+Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+---
+ drivers/mtd/ubi/block.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
+index 69a74fd..7ff473c 100644
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -156,7 +156,7 @@ static int __init ubiblock_set_param(const char *val,
+ return 0;
+ }
+
+-static struct kernel_param_ops ubiblock_param_ops __initdata = {
++static struct kernel_param_ops ubiblock_param_ops = {
+ .set = ubiblock_set_param,
+ };
+ module_param_cb(block, &ubiblock_param_ops, NULL, 0);
+--
+1.9.2
+
diff --git a/target/linux/generic/patches-3.14/046-UBI-avoid-workqueue-format-string-leak.patch b/target/linux/generic/patches-3.14/046-UBI-avoid-workqueue-format-string-leak.patch
new file mode 100644
index 0000000..86f0d63
--- /dev/null
+++ b/target/linux/generic/patches-3.14/046-UBI-avoid-workqueue-format-string-leak.patch
@@ -0,0 +1,30 @@
+From bebfef150e0b8fa68704cddacf05b8c26462d565 Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook@chromium.org>
+Date: Mon, 7 Apr 2014 21:44:07 -0700
+Subject: [PATCH] UBI: avoid workqueue format string leak
+
+When building the name for the workqueue thread, make sure a format
+string cannot leak in from the disk name.
+
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+---
+ drivers/mtd/ubi/block.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
+index 7ff473c..8d659e6 100644
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -431,7 +431,7 @@ int ubiblock_create(struct ubi_volume_info *vi)
+ * Create one workqueue per volume (per registered block device).
+ * Rembember workqueues are cheap, they're not threads.
+ */
+- dev->wq = alloc_workqueue(gd->disk_name, 0, 0);
++ dev->wq = alloc_workqueue("%s", 0, 0, gd->disk_name);
+ if (!dev->wq)
+ goto out_free_queue;
+ INIT_WORK(&dev->work, ubiblock_do_work);
+--
+1.9.2
+
diff --git a/target/linux/generic/patches-3.14/047-UBI-make-UBI_IOCVOLCRBLK-take-a-parameter-for-future.patch b/target/linux/generic/patches-3.14/047-UBI-make-UBI_IOCVOLCRBLK-take-a-parameter-for-future.patch
new file mode 100644
index 0000000..0a0230f
--- /dev/null
+++ b/target/linux/generic/patches-3.14/047-UBI-make-UBI_IOCVOLCRBLK-take-a-parameter-for-future.patch
@@ -0,0 +1,63 @@
+From 463c5eedb4a13b9aa91f05498a0f2c20bd03f8c4 Mon Sep 17 00:00:00 2001
+From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
+Date: Wed, 5 Mar 2014 11:16:14 -0300
+Subject: [PATCH] UBI: make UBI_IOCVOLCRBLK take a parameter for future usage
+
+In order to allow a future ioctl parameter, such as a creation flag,
+we change the UBI_IOCVOLCRBLK so it accepts a struct ubi_blkcreate_req.
+For the time being the structure is not in use, but fully reserved.
+
+This ABI change is still possible and harmless, because the ioctl has just
+been introduced and there's no userspace program which uses it.
+
+Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
+Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+---
+ include/uapi/mtd/ubi-user.h | 19 +++++++++++++++----
+ 1 file changed, 15 insertions(+), 4 deletions(-)
+
+diff --git a/include/uapi/mtd/ubi-user.h b/include/uapi/mtd/ubi-user.h
+index 9c885e2..1927b0d 100644
+--- a/include/uapi/mtd/ubi-user.h
++++ b/include/uapi/mtd/ubi-user.h
+@@ -138,9 +138,12 @@
+ * Block devices on UBI volumes
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+- * To create or remove a R/O block device on top of an UBI volume the
+- * %UBI_IOCVOLCRBLK and %UBI_IOCVOLRMBLK ioctl commands should be used,
+- * respectively. These commands take no arguments.
++ * To create a R/O block device on top of an UBI volume the %UBI_IOCVOLCRBLK
++ * should be used. A pointer to a &struct ubi_blkcreate_req object is expected
++ * to be passed, which is not used and reserved for future usage.
++ *
++ * Conversely, to remove a block device the %UBI_IOCVOLRMBLK should be used,
++ * which takes no arguments.
+ */
+
+ /*
+@@ -199,7 +202,7 @@
+ #define UBI_IOCSETVOLPROP _IOW(UBI_VOL_IOC_MAGIC, 6, \
+ struct ubi_set_vol_prop_req)
+ /* Create a R/O block device on top of an UBI volume */
+-#define UBI_IOCVOLCRBLK _IO(UBI_VOL_IOC_MAGIC, 7)
++#define UBI_IOCVOLCRBLK _IOW(UBI_VOL_IOC_MAGIC, 7, struct ubi_blkcreate_req)
+ /* Remove the R/O block device */
+ #define UBI_IOCVOLRMBLK _IO(UBI_VOL_IOC_MAGIC, 8)
+
+@@ -431,4 +434,12 @@ struct ubi_set_vol_prop_req {
+ __u64 value;
+ } __packed;
+
++/**
++ * struct ubi_blkcreate_req - a data structure used in block creation requests.
++ * @padding: reserved for future, not used, has to be zeroed
++ */
++struct ubi_blkcreate_req {
++ __s8 padding[128];
++} __packed;
++
+ #endif /* __UBI_USER_H__ */
+--
+1.9.2
+