kernel: backport the ubiblock patches from 3.14->3.10
authorblogic <blogic@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Wed, 11 Jun 2014 12:59:15 +0000 (12:59 +0000)
committerblogic <blogic@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Wed, 11 Jun 2014 12:59:15 +0000 (12:59 +0000)
Signed-off-by: John Crispin <blogic@openwrt.org>
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@41120 3c298f89-4303-0410-b956-a3cf2f4a3e73

13 files changed:
target/linux/generic/patches-3.10/040-UBI-R-O-block-driver-on-top-of-UBI-volumes.patch [new file with mode: 0644]
target/linux/generic/patches-3.10/041-UBI-block-do-not-use-term-attach.patch [new file with mode: 0644]
target/linux/generic/patches-3.10/042-UBI-block-Mark-init-only-symbol-as-__initdata.patch [new file with mode: 0644]
target/linux/generic/patches-3.10/043-UBI-block-Use-u64-for-the-64-bit-dividend.patch [new file with mode: 0644]
target/linux/generic/patches-3.10/044-UBI-rename-block-device-ioctls.patch [new file with mode: 0644]
target/linux/generic/patches-3.10/045-UBI-block-Remove-__initdata-from-ubiblock_param_ops.patch [new file with mode: 0644]
target/linux/generic/patches-3.10/046-UBI-avoid-workqueue-format-string-leak.patch [new file with mode: 0644]
target/linux/generic/patches-3.10/047-UBI-make-UBI_IOCVOLCRBLK-take-a-parameter-for-future.patch [new file with mode: 0644]
target/linux/generic/patches-3.10/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch [new file with mode: 0644]
target/linux/generic/patches-3.10/491-ubi-auto-create-ubiblock-device-for-rootfs.patch [new file with mode: 0644]
target/linux/generic/patches-3.10/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch [new file with mode: 0644]
target/linux/generic/patches-3.10/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch [new file with mode: 0644]
target/linux/generic/patches-3.10/552-ubifs-respect-silent-mount-flag.patch [new file with mode: 0644]

diff --git a/target/linux/generic/patches-3.10/040-UBI-R-O-block-driver-on-top-of-UBI-volumes.patch b/target/linux/generic/patches-3.10/040-UBI-R-O-block-driver-on-top-of-UBI-volumes.patch
new file mode 100644 (file)
index 0000000..50e9e2f
--- /dev/null
@@ -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.10/041-UBI-block-do-not-use-term-attach.patch b/target/linux/generic/patches-3.10/041-UBI-block-do-not-use-term-attach.patch
new file mode 100644 (file)
index 0000000..bcbb92c
--- /dev/null
@@ -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.10/042-UBI-block-Mark-init-only-symbol-as-__initdata.patch b/target/linux/generic/patches-3.10/042-UBI-block-Mark-init-only-symbol-as-__initdata.patch
new file mode 100644 (file)
index 0000000..181cecb
--- /dev/null
@@ -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.10/043-UBI-block-Use-u64-for-the-64-bit-dividend.patch b/target/linux/generic/patches-3.10/043-UBI-block-Use-u64-for-the-64-bit-dividend.patch
new file mode 100644 (file)
index 0000000..648b42f
--- /dev/null
@@ -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.10/044-UBI-rename-block-device-ioctls.patch b/target/linux/generic/patches-3.10/044-UBI-rename-block-device-ioctls.patch
new file mode 100644 (file)
index 0000000..a010a3c
--- /dev/null
@@ -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.10/045-UBI-block-Remove-__initdata-from-ubiblock_param_ops.patch b/target/linux/generic/patches-3.10/045-UBI-block-Remove-__initdata-from-ubiblock_param_ops.patch
new file mode 100644 (file)
index 0000000..f5ae724
--- /dev/null
@@ -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.10/046-UBI-avoid-workqueue-format-string-leak.patch b/target/linux/generic/patches-3.10/046-UBI-avoid-workqueue-format-string-leak.patch
new file mode 100644 (file)
index 0000000..86f0d63
--- /dev/null
@@ -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.10/047-UBI-make-UBI_IOCVOLCRBLK-take-a-parameter-for-future.patch b/target/linux/generic/patches-3.10/047-UBI-make-UBI_IOCVOLCRBLK-take-a-parameter-for-future.patch
new file mode 100644 (file)
index 0000000..0a0230f
--- /dev/null
@@ -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
+
diff --git a/target/linux/generic/patches-3.10/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch b/target/linux/generic/patches-3.10/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
new file mode 100644 (file)
index 0000000..440c6bf
--- /dev/null
@@ -0,0 +1,68 @@
+From 8a52e4100d7c3a4a1dfddfa02b8864a9b0068c13 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sat, 17 May 2014 03:36:18 +0200
+Subject: [PATCH 1/5] ubi: auto-attach mtd device named "ubi" or "data" on boot
+To: openwrt-devel@lists.openwrt.org
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/build.c | 36 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
+index 6e30a3c..999a36b 100644
+--- a/drivers/mtd/ubi/build.c
++++ b/drivers/mtd/ubi/build.c
+@@ -1209,6 +1209,36 @@ static struct mtd_info * __init open_mtd_device(const char *mtd_dev)
+       return mtd;
+ }
++/*
++ * This function tries attaching mtd partitions named either "ubi" or "data"
++ * during boot.
++ */
++static void __init ubi_auto_attach(void)
++{
++      int err;
++      struct mtd_info *mtd;
++      /* try attaching mtd device named "ubi" or "data" */
++      mtd = open_mtd_device("ubi");
++      if (IS_ERR(mtd))
++              mtd = open_mtd_device("data");
++
++      if (!IS_ERR(mtd)) {
++              /* auto-add only media types where UBI makes sense */
++              if (mtd->type == MTD_NANDFLASH ||
++                  mtd->type == MTD_DATAFLASH ||
++                  mtd->type == MTD_MLCNANDFLASH) {
++                      mutex_lock(&ubi_devices_mutex);
++                      ubi_msg("auto-attach mtd%d", mtd->index);
++                      err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0);
++                      mutex_unlock(&ubi_devices_mutex);
++                      if (err < 0) {
++                              ubi_err("cannot attach mtd%d", mtd->index);
++                              put_mtd_device(mtd);
++                      }
++              }
++      }
++}
++
+ static int __init ubi_init(void)
+ {
+       int err, i, k;
+@@ -1298,6 +1328,12 @@ static int __init ubi_init(void)
+               }
+       }
++      /* auto-attach mtd devices only if built-in to the kernel and no ubi.mtd
++       * parameter was given */
++      if (config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
++          !ubi_is_module() && !mtd_devs)
++              ubi_auto_attach();
++
+       err = ubiblock_init();
+       if (err) {
+               ubi_err("block: cannot initialize, error %d", err);
+-- 
+1.9.2
+
diff --git a/target/linux/generic/patches-3.10/491-ubi-auto-create-ubiblock-device-for-rootfs.patch b/target/linux/generic/patches-3.10/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
new file mode 100644 (file)
index 0000000..e1992c9
--- /dev/null
@@ -0,0 +1,74 @@
+From 0f3966579815f889bb2fcb4846152c35f65e79c4 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 15 May 2014 21:06:33 +0200
+Subject: [PATCH 2/5] ubi: auto-create ubiblock device for rootfs
+To: openwrt-devel@lists.openwrt.org
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/block.c | 42 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+
+diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
+index 8d659e6..2dbe2f4 100644
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -593,6 +593,44 @@ static int __init ubiblock_create_from_param(void)
+       return ret;
+ }
++#define UBIFS_NODE_MAGIC  0x06101831
++static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc)
++{
++      int ret;
++      uint32_t magic_of, magic;
++      ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4);
++      if (ret)
++              return 0;
++      magic = le32_to_cpu(magic_of);
++      return magic == UBIFS_NODE_MAGIC;
++}
++
++static void __init ubiblock_create_auto_rootfs(void)
++{
++      int ubi_num, ret, is_ubifs;
++      struct ubi_volume_desc *desc;
++      struct ubi_volume_info vi;
++
++      for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) {
++              desc = ubi_open_volume_nm(ubi_num, "rootfs", UBI_READONLY);
++              if (IS_ERR(desc))
++                      continue;
++
++              ubi_get_volume_info(desc, &vi);
++              is_ubifs = ubi_vol_is_ubifs(desc);
++              ubi_close_volume(desc);
++              if (is_ubifs)
++                      break;
++
++              ret = ubiblock_create(&vi);
++              if (ret)
++                      ubi_err("block: can't add '%s' volume, err=%d\n",
++                              vi.name, ret);
++              /* always break if we get here */
++              break;
++      }
++}
++
+ static void ubiblock_remove_all(void)
+ {
+       struct ubiblock *next;
+@@ -623,6 +661,10 @@ int __init ubiblock_init(void)
+       if (ret)
+               goto err_remove;
++      /* auto-attach "rootfs" volume if existing and non-ubifs */
++      if (config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV))
++              ubiblock_create_auto_rootfs();
++
+       /*
+        * Block devices are only created upon user requests, so we ignore
+        * existing volumes.
+-- 
+1.9.2
+
diff --git a/target/linux/generic/patches-3.10/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch b/target/linux/generic/patches-3.10/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch
new file mode 100644 (file)
index 0000000..75a0bc0
--- /dev/null
@@ -0,0 +1,58 @@
+From eea9e1785e4c05c2a3444506aabafa0ae958538f Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sat, 17 May 2014 03:35:02 +0200
+Subject: [PATCH 4/5] try auto-mounting ubi0:rootfs in init/do_mounts.c
+To: openwrt-devel@lists.openwrt.org
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ init/do_mounts.c | 26 +++++++++++++++++++++++++-
+ 1 file changed, 25 insertions(+), 1 deletion(-)
+
+diff --git a/init/do_mounts.c b/init/do_mounts.c
+index 82f2288..faba9c6 100644
+--- a/init/do_mounts.c
++++ b/init/do_mounts.c
+@@ -432,7 +432,27 @@ retry:
+ out:
+       put_page(page);
+ }
+- 
++
++static int __init mount_ubi_rootfs(void)
++{
++      int flags = MS_SILENT;
++      int err, tried = 0;
++
++      while (tried < 2) {
++              err = do_mount_root("ubi0:rootfs", "ubifs", flags, \
++                                      root_mount_data);
++              switch (err) {
++                      case -EACCES:
++                              flags |= MS_RDONLY;
++                              tried++;
++                      default:
++                              return err;
++              }
++      }
++
++      return -EINVAL;
++}
++
+ #ifdef CONFIG_ROOT_NFS
+ #define NFSROOT_TIMEOUT_MIN   5
+@@ -526,6 +546,10 @@ void __init mount_root(void)
+                       change_floppy("root floppy");
+       }
+ #endif
++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
++      if (!mount_ubi_rootfs())
++              return;
++#endif
+ #ifdef CONFIG_BLOCK
+       create_dev("/dev/root", ROOT_DEV);
+       mount_block_root("/dev/root", root_mountflags);
+-- 
+1.9.2
+
diff --git a/target/linux/generic/patches-3.10/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch b/target/linux/generic/patches-3.10/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
new file mode 100644 (file)
index 0000000..4ceedf3
--- /dev/null
@@ -0,0 +1,42 @@
+From cd68d1b12b5ea4c01a664c064179ada42bf55d3d Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 15 May 2014 20:55:42 +0200
+Subject: [PATCH 5/5] ubi: set ROOT_DEV to ubiblock "rootfs" if unset
+To: openwrt-devel@lists.openwrt.org
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/block.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
+index 2dbe2f4..eaa29f8 100644
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -48,6 +48,7 @@
+ #include <linux/blkdev.h>
+ #include <linux/hdreg.h>
+ #include <asm/div64.h>
++#include <linux/root_dev.h>
+ #include "ubi-media.h"
+ #include "ubi.h"
+@@ -444,6 +445,15 @@ int ubiblock_create(struct ubi_volume_info *vi)
+       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);
++
++      if (!strcmp(vi->name, "rootfs") &&
++          config_enabled(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
++          ROOT_DEV == 0) {
++              pr_notice("ubiblock: device ubiblock%d_%d (%s) set to be root filesystem\n",
++                        dev->ubi_num, dev->vol_id, vi->name);
++              ROOT_DEV = MKDEV(gd->major, gd->first_minor);
++      }
++
+       return 0;
+ out_free_queue:
+-- 
+1.9.2
+
diff --git a/target/linux/generic/patches-3.10/552-ubifs-respect-silent-mount-flag.patch b/target/linux/generic/patches-3.10/552-ubifs-respect-silent-mount-flag.patch
new file mode 100644 (file)
index 0000000..ab89b98
--- /dev/null
@@ -0,0 +1,176 @@
+From 248b89b95d27659c5360ef5b68cca21d096ee909 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sat, 17 May 2014 03:16:54 +0200
+Subject: [PATCH 3/5] ubifs: respect MS_SILENT mount flag
+To: dedekind1@gmail.com,
+    linux-mtd@lists.infradead.org
+
+When attempting to mount a non-ubifs formatted volume, lots of error
+messages (including a stack dump) are thrown to the kernel log even if
+the MS_SILENT mount flag is set.
+Fix this by checking the MS_SILENT flag in ubifs_read_sb_node and
+passing it down to ubifs_read_node, which now got an additional
+parameter for that purpose.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ fs/ubifs/commit.c   |  4 ++--
+ fs/ubifs/io.c       | 23 ++++++++++++++---------
+ fs/ubifs/sb.c       |  5 +++--
+ fs/ubifs/tnc_misc.c |  4 ++--
+ fs/ubifs/ubifs.h    |  2 +-
+ 5 files changed, 22 insertions(+), 16 deletions(-)
+
+diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c
+index ff82293..865d13f 100644
+--- a/fs/ubifs/commit.c
++++ b/fs/ubifs/commit.c
+@@ -542,7 +542,7 @@ int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot)
+       if (!idx)
+               return -ENOMEM;
+-      err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs);
++      err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs, 0);
+       if (err)
+               goto out;
+@@ -610,7 +610,7 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
+               list_add_tail(&i->list, &list);
+               /* Read the index node */
+               idx = &i->idx;
+-              err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs);
++              err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs, 0);
+               if (err)
+                       goto out_free;
+               /* Validate index node */
+diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
+index e18b988..51c4072 100644
+--- a/fs/ubifs/io.c
++++ b/fs/ubifs/io.c
+@@ -912,7 +912,7 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
+       if (!overlap) {
+               /* We may safely unlock the write-buffer and read the data */
+               spin_unlock(&wbuf->lock);
+-              return ubifs_read_node(c, buf, type, len, lnum, offs);
++              return ubifs_read_node(c, buf, type, len, lnum, offs, 0);
+       }
+       /* Don't read under wbuf */
+@@ -966,13 +966,14 @@ out:
+  * @len: node length (not aligned)
+  * @lnum: logical eraseblock number
+  * @offs: offset within the logical eraseblock
++ * @silent: suppress error messages
+  *
+  * This function reads a node of known type and and length, checks it and
+  * stores in @buf. Returns zero in case of success, %-EUCLEAN if CRC mismatched
+  * and a negative error code in case of failure.
+  */
+ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
+-                  int lnum, int offs)
++                  int lnum, int offs, int silent)
+ {
+       int err, l;
+       struct ubifs_ch *ch = buf;
+@@ -988,30 +989,34 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
+               return err;
+       if (type != ch->node_type) {
+-              ubifs_err("bad node type (%d but expected %d)",
++              if (!silent) ubifs_err("bad node type (%d but expected %d)",
+                         ch->node_type, type);
+               goto out;
+       }
+       err = ubifs_check_node(c, buf, lnum, offs, 0, 0);
+       if (err) {
+-              ubifs_err("expected node type %d", type);
++              if (!silent)
++                      ubifs_err("expected node type %d", type);
+               return err;
+       }
+       l = le32_to_cpu(ch->len);
+       if (l != len) {
+-              ubifs_err("bad node length %d, expected %d", l, len);
++              if (!silent)
++                      ubifs_err("bad node length %d, expected %d", l, len);
+               goto out;
+       }
+       return 0;
+ out:
+-      ubifs_err("bad node at LEB %d:%d, LEB mapping status %d", lnum, offs,
+-                ubi_is_mapped(c->ubi, lnum));
+-      ubifs_dump_node(c, buf);
+-      dump_stack();
++      if (!silent) {
++              ubifs_err("bad node at LEB %d:%d, LEB mapping status %d", lnum,
++                        offs, ubi_is_mapped(c->ubi, lnum));
++              ubifs_dump_node(c, buf);
++              dump_stack();
++      }
+       return -EINVAL;
+ }
+diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
+index 4c37607..b46847d 100644
+--- a/fs/ubifs/sb.c
++++ b/fs/ubifs/sb.c
+@@ -482,14 +482,15 @@ failed:
+ struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
+ {
+       struct ubifs_sb_node *sup;
+-      int err;
++      int silent, err;
+       sup = kmalloc(ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size), GFP_NOFS);
+       if (!sup)
+               return ERR_PTR(-ENOMEM);
++      silent = !!(c->vfs_sb->s_flags & MS_SILENT);
+       err = ubifs_read_node(c, sup, UBIFS_SB_NODE, UBIFS_SB_NODE_SZ,
+-                            UBIFS_SB_LNUM, 0);
++                            UBIFS_SB_LNUM, 0, silent);
+       if (err) {
+               kfree(sup);
+               return ERR_PTR(err);
+diff --git a/fs/ubifs/tnc_misc.c b/fs/ubifs/tnc_misc.c
+index f6bf899..e128689 100644
+--- a/fs/ubifs/tnc_misc.c
++++ b/fs/ubifs/tnc_misc.c
+@@ -280,7 +280,7 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
+       if (!idx)
+               return -ENOMEM;
+-      err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs);
++      err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs, 0);
+       if (err < 0) {
+               kfree(idx);
+               return err;
+@@ -472,7 +472,7 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+                                          zbr->lnum, zbr->offs);
+       else
+               err = ubifs_read_node(c, node, type, zbr->len, zbr->lnum,
+-                                    zbr->offs);
++                                    zbr->offs, 0);
+       if (err) {
+               dbg_tnck(key, "key ");
+diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
+index e8c8cfe..85fdd11 100644
+--- a/fs/ubifs/ubifs.h
++++ b/fs/ubifs/ubifs.h
+@@ -1481,7 +1481,7 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len);
+ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs);
+ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf);
+ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
+-                  int lnum, int offs);
++                  int lnum, int offs, int silent);
+ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
+                        int lnum, int offs);
+ int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum,
+-- 
+1.9.2
+