提交 8c988ae7 编写于 作者: L Linus Torvalds

Merge branch 'for-linus-v3.20' of git://git.infradead.org/linux-ubifs

Pull UBI and UBIFS updates from Richard Weinberger:
 - cleanups and bug fixes all over UBI and UBIFS
 - block-mq support for UBI Block
 - UBI volumes can now be renamed while they are in use
 - security.* XATTR support for UBIFS
 - a maintainer update

* 'for-linus-v3.20' of git://git.infradead.org/linux-ubifs:
  UBI: block: Fix checking for NULL instead of IS_ERR()
  UBI: block: Continue creating ubiblocks after an initialization error
  UBIFS: return -EINVAL if log head is empty
  UBI: Block: Explain usage of blk_rq_map_sg()
  UBI: fix soft lockup in ubi_check_volume()
  UBI: Fastmap: Care about the protection queue
  UBIFS: add a couple of extra asserts
  UBI: do propagate positive error codes up
  UBI: clean-up printing helpers
  UBI: extend UBI layer debug/messaging capabilities - cosmetics
  UBIFS: add ubifs_err() to print error reason
  UBIFS: Add security.* XATTR support for the UBIFS
  UBIFS: Add xattr support for symlinks
  UBI: Block: Add blk-mq support
  UBI: Add initial support for scatter gather
  UBI: rename_volumes: Use UBI_METAONLY
  UBI: Implement UBI_METAONLY
  Add myself as UBI co-maintainer
...@@ -9990,20 +9990,15 @@ F: drivers/scsi/ufs/ ...@@ -9990,20 +9990,15 @@ F: drivers/scsi/ufs/
UNSORTED BLOCK IMAGES (UBI) UNSORTED BLOCK IMAGES (UBI)
M: Artem Bityutskiy <dedekind1@gmail.com> M: Artem Bityutskiy <dedekind1@gmail.com>
M: Richard Weinberger <richard@nod.at>
W: http://www.linux-mtd.infradead.org/ W: http://www.linux-mtd.infradead.org/
L: linux-mtd@lists.infradead.org L: linux-mtd@lists.infradead.org
T: git git://git.infradead.org/ubifs-2.6.git T: git git://git.infradead.org/ubifs-2.6.git
S: Maintained S: Supported
F: drivers/mtd/ubi/ F: drivers/mtd/ubi/
F: include/linux/mtd/ubi.h F: include/linux/mtd/ubi.h
F: include/uapi/mtd/ubi-user.h F: include/uapi/mtd/ubi-user.h
UNSORTED BLOCK IMAGES (UBI) Fastmap
M: Richard Weinberger <richard@nod.at>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/ubi/fastmap.c
USB ACM DRIVER USB ACM DRIVER
M: Oliver Neukum <oliver@neukum.org> M: Oliver Neukum <oliver@neukum.org>
L: linux-usb@vger.kernel.org L: linux-usb@vger.kernel.org
......
...@@ -42,11 +42,12 @@ ...@@ -42,11 +42,12 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mtd/ubi.h> #include <linux/mtd/ubi.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/blk-mq.h>
#include <linux/hdreg.h> #include <linux/hdreg.h>
#include <linux/scatterlist.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "ubi-media.h" #include "ubi-media.h"
...@@ -67,6 +68,11 @@ struct ubiblock_param { ...@@ -67,6 +68,11 @@ struct ubiblock_param {
char name[UBIBLOCK_PARAM_LEN+1]; char name[UBIBLOCK_PARAM_LEN+1];
}; };
struct ubiblock_pdu {
struct work_struct work;
struct ubi_sgl usgl;
};
/* Numbers of elements set in the @ubiblock_param array */ /* Numbers of elements set in the @ubiblock_param array */
static int ubiblock_devs __initdata; static int ubiblock_devs __initdata;
...@@ -84,11 +90,10 @@ struct ubiblock { ...@@ -84,11 +90,10 @@ struct ubiblock {
struct request_queue *rq; struct request_queue *rq;
struct workqueue_struct *wq; struct workqueue_struct *wq;
struct work_struct work;
struct mutex dev_mutex; struct mutex dev_mutex;
spinlock_t queue_lock;
struct list_head list; struct list_head list;
struct blk_mq_tag_set tag_set;
}; };
/* Linked list of all ubiblock instances */ /* Linked list of all ubiblock instances */
...@@ -181,31 +186,20 @@ static struct ubiblock *find_dev_nolock(int ubi_num, int vol_id) ...@@ -181,31 +186,20 @@ static struct ubiblock *find_dev_nolock(int ubi_num, int vol_id)
return NULL; return NULL;
} }
static int ubiblock_read_to_buf(struct ubiblock *dev, char *buffer, static int ubiblock_read(struct ubiblock_pdu *pdu)
int leb, int offset, int len)
{ {
int ret; int ret, leb, offset, bytes_left, to_read;
u64 pos;
ret = ubi_read(dev->desc, leb, buffer, offset, len); struct request *req = blk_mq_rq_from_pdu(pdu);
if (ret) { struct ubiblock *dev = req->q->queuedata;
dev_err(disk_to_dev(dev->gd), "%d while reading from LEB %d (offset %d, length %d)",
ret, leb, offset, len);
return ret;
}
return 0;
}
static int ubiblock_read(struct ubiblock *dev, char *buffer, to_read = blk_rq_bytes(req);
sector_t sec, int len) pos = blk_rq_pos(req) << 9;
{
int ret, leb, offset;
int bytes_left = len;
int to_read = len;
u64 pos = sec << 9;
/* Get LEB:offset address to read from */ /* Get LEB:offset address to read from */
offset = do_div(pos, dev->leb_size); offset = do_div(pos, dev->leb_size);
leb = pos; leb = pos;
bytes_left = to_read;
while (bytes_left) { while (bytes_left) {
/* /*
...@@ -215,11 +209,10 @@ static int ubiblock_read(struct ubiblock *dev, char *buffer, ...@@ -215,11 +209,10 @@ static int ubiblock_read(struct ubiblock *dev, char *buffer,
if (offset + to_read > dev->leb_size) if (offset + to_read > dev->leb_size)
to_read = dev->leb_size - offset; to_read = dev->leb_size - offset;
ret = ubiblock_read_to_buf(dev, buffer, leb, offset, to_read); ret = ubi_read_sg(dev->desc, leb, &pdu->usgl, offset, to_read);
if (ret) if (ret < 0)
return ret; return ret;
buffer += to_read;
bytes_left -= to_read; bytes_left -= to_read;
to_read = bytes_left; to_read = bytes_left;
leb += 1; leb += 1;
...@@ -228,79 +221,6 @@ static int ubiblock_read(struct ubiblock *dev, char *buffer, ...@@ -228,79 +221,6 @@ static int ubiblock_read(struct ubiblock *dev, char *buffer,
return 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, bio_data(req->bio), 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) static int ubiblock_open(struct block_device *bdev, fmode_t mode)
{ {
struct ubiblock *dev = bdev->bd_disk->private_data; struct ubiblock *dev = bdev->bd_disk->private_data;
...@@ -374,6 +294,63 @@ static const struct block_device_operations ubiblock_ops = { ...@@ -374,6 +294,63 @@ static const struct block_device_operations ubiblock_ops = {
.getgeo = ubiblock_getgeo, .getgeo = ubiblock_getgeo,
}; };
static void ubiblock_do_work(struct work_struct *work)
{
int ret;
struct ubiblock_pdu *pdu = container_of(work, struct ubiblock_pdu, work);
struct request *req = blk_mq_rq_from_pdu(pdu);
blk_mq_start_request(req);
/*
* It is safe to ignore the return value of blk_rq_map_sg() because
* the number of sg entries is limited to UBI_MAX_SG_COUNT
* and ubi_read_sg() will check that limit.
*/
blk_rq_map_sg(req->q, req, pdu->usgl.sg);
ret = ubiblock_read(pdu);
blk_mq_end_request(req, ret);
}
static int ubiblock_queue_rq(struct blk_mq_hw_ctx *hctx,
const struct blk_mq_queue_data *bd)
{
struct request *req = bd->rq;
struct ubiblock *dev = hctx->queue->queuedata;
struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req);
if (req->cmd_type != REQ_TYPE_FS)
return BLK_MQ_RQ_QUEUE_ERROR;
if (rq_data_dir(req) != READ)
return BLK_MQ_RQ_QUEUE_ERROR; /* Write not implemented */
ubi_sgl_init(&pdu->usgl);
queue_work(dev->wq, &pdu->work);
return BLK_MQ_RQ_QUEUE_OK;
}
static int ubiblock_init_request(void *data, struct request *req,
unsigned int hctx_idx,
unsigned int request_idx,
unsigned int numa_node)
{
struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req);
sg_init_table(pdu->usgl.sg, UBI_MAX_SG_COUNT);
INIT_WORK(&pdu->work, ubiblock_do_work);
return 0;
}
static struct blk_mq_ops ubiblock_mq_ops = {
.queue_rq = ubiblock_queue_rq,
.init_request = ubiblock_init_request,
.map_queue = blk_mq_map_queue,
};
int ubiblock_create(struct ubi_volume_info *vi) int ubiblock_create(struct ubi_volume_info *vi)
{ {
struct ubiblock *dev; struct ubiblock *dev;
...@@ -417,14 +394,28 @@ int ubiblock_create(struct ubi_volume_info *vi) ...@@ -417,14 +394,28 @@ int ubiblock_create(struct ubi_volume_info *vi)
set_capacity(gd, disk_capacity); set_capacity(gd, disk_capacity);
dev->gd = gd; dev->gd = gd;
spin_lock_init(&dev->queue_lock); dev->tag_set.ops = &ubiblock_mq_ops;
dev->rq = blk_init_queue(ubiblock_request, &dev->queue_lock); dev->tag_set.queue_depth = 64;
if (!dev->rq) { dev->tag_set.numa_node = NUMA_NO_NODE;
dev_err(disk_to_dev(gd), "blk_init_queue failed"); dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
ret = -ENODEV; dev->tag_set.cmd_size = sizeof(struct ubiblock_pdu);
dev->tag_set.driver_data = dev;
dev->tag_set.nr_hw_queues = 1;
ret = blk_mq_alloc_tag_set(&dev->tag_set);
if (ret) {
dev_err(disk_to_dev(dev->gd), "blk_mq_alloc_tag_set failed");
goto out_put_disk; goto out_put_disk;
} }
dev->rq = blk_mq_init_queue(&dev->tag_set);
if (IS_ERR(dev->rq)) {
dev_err(disk_to_dev(gd), "blk_mq_init_queue failed");
ret = PTR_ERR(dev->rq);
goto out_free_tags;
}
blk_queue_max_segments(dev->rq, UBI_MAX_SG_COUNT);
dev->rq->queuedata = dev; dev->rq->queuedata = dev;
dev->gd->queue = dev->rq; dev->gd->queue = dev->rq;
...@@ -437,7 +428,6 @@ int ubiblock_create(struct ubi_volume_info *vi) ...@@ -437,7 +428,6 @@ int ubiblock_create(struct ubi_volume_info *vi)
ret = -ENOMEM; ret = -ENOMEM;
goto out_free_queue; goto out_free_queue;
} }
INIT_WORK(&dev->work, ubiblock_do_work);
mutex_lock(&devices_mutex); mutex_lock(&devices_mutex);
list_add_tail(&dev->list, &ubiblock_devices); list_add_tail(&dev->list, &ubiblock_devices);
...@@ -451,6 +441,8 @@ int ubiblock_create(struct ubi_volume_info *vi) ...@@ -451,6 +441,8 @@ int ubiblock_create(struct ubi_volume_info *vi)
out_free_queue: out_free_queue:
blk_cleanup_queue(dev->rq); blk_cleanup_queue(dev->rq);
out_free_tags:
blk_mq_free_tag_set(&dev->tag_set);
out_put_disk: out_put_disk:
put_disk(dev->gd); put_disk(dev->gd);
out_free_dev: out_free_dev:
...@@ -461,8 +453,13 @@ int ubiblock_create(struct ubi_volume_info *vi) ...@@ -461,8 +453,13 @@ int ubiblock_create(struct ubi_volume_info *vi)
static void ubiblock_cleanup(struct ubiblock *dev) static void ubiblock_cleanup(struct ubiblock *dev)
{ {
/* Stop new requests to arrive */
del_gendisk(dev->gd); del_gendisk(dev->gd);
/* Flush pending work */
destroy_workqueue(dev->wq);
/* Finally destroy the blk queue */
blk_cleanup_queue(dev->rq); blk_cleanup_queue(dev->rq);
blk_mq_free_tag_set(&dev->tag_set);
dev_info(disk_to_dev(dev->gd), "released"); dev_info(disk_to_dev(dev->gd), "released");
put_disk(dev->gd); put_disk(dev->gd);
} }
...@@ -490,9 +487,6 @@ int ubiblock_remove(struct ubi_volume_info *vi) ...@@ -490,9 +487,6 @@ int ubiblock_remove(struct ubi_volume_info *vi)
list_del(&dev->list); list_del(&dev->list);
mutex_unlock(&devices_mutex); mutex_unlock(&devices_mutex);
/* Flush pending work and stop this workqueue */
destroy_workqueue(dev->wq);
ubiblock_cleanup(dev); ubiblock_cleanup(dev);
mutex_unlock(&dev->dev_mutex); mutex_unlock(&dev->dev_mutex);
kfree(dev); kfree(dev);
...@@ -583,22 +577,28 @@ open_volume_desc(const char *name, int ubi_num, int vol_id) ...@@ -583,22 +577,28 @@ open_volume_desc(const char *name, int ubi_num, int vol_id)
return ubi_open_volume(ubi_num, vol_id, UBI_READONLY); return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
} }
static int __init ubiblock_create_from_param(void) static void __init ubiblock_create_from_param(void)
{ {
int i, ret; int i, ret = 0;
struct ubiblock_param *p; struct ubiblock_param *p;
struct ubi_volume_desc *desc; struct ubi_volume_desc *desc;
struct ubi_volume_info vi; struct ubi_volume_info vi;
/*
* If there is an error creating one of the ubiblocks, continue on to
* create the following ubiblocks. This helps in a circumstance where
* the kernel command-line specifies multiple block devices and some
* may be broken, but we still want the working ones to come up.
*/
for (i = 0; i < ubiblock_devs; i++) { for (i = 0; i < ubiblock_devs; i++) {
p = &ubiblock_param[i]; p = &ubiblock_param[i];
desc = open_volume_desc(p->name, p->ubi_num, p->vol_id); desc = open_volume_desc(p->name, p->ubi_num, p->vol_id);
if (IS_ERR(desc)) { if (IS_ERR(desc)) {
pr_err("UBI: block: can't open volume, err=%ld\n", pr_err(
PTR_ERR(desc)); "UBI: block: can't open volume on ubi%d_%d, err=%ld",
ret = PTR_ERR(desc); p->ubi_num, p->vol_id, PTR_ERR(desc));
break; continue;
} }
ubi_get_volume_info(desc, &vi); ubi_get_volume_info(desc, &vi);
...@@ -606,12 +606,12 @@ static int __init ubiblock_create_from_param(void) ...@@ -606,12 +606,12 @@ static int __init ubiblock_create_from_param(void)
ret = ubiblock_create(&vi); ret = ubiblock_create(&vi);
if (ret) { if (ret) {
pr_err("UBI: block: can't add '%s' volume, err=%d\n", pr_err(
vi.name, ret); "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d",
break; vi.name, p->ubi_num, p->vol_id, ret);
continue;
} }
} }
return ret;
} }
static void ubiblock_remove_all(void) static void ubiblock_remove_all(void)
...@@ -620,8 +620,6 @@ static void ubiblock_remove_all(void) ...@@ -620,8 +620,6 @@ static void ubiblock_remove_all(void)
struct ubiblock *dev; struct ubiblock *dev;
list_for_each_entry_safe(dev, next, &ubiblock_devices, list) { 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 */ /* The module is being forcefully removed */
WARN_ON(dev->desc); WARN_ON(dev->desc);
/* Remove from device list */ /* Remove from device list */
...@@ -639,10 +637,12 @@ int __init ubiblock_init(void) ...@@ -639,10 +637,12 @@ int __init ubiblock_init(void)
if (ubiblock_major < 0) if (ubiblock_major < 0)
return ubiblock_major; return ubiblock_major;
/* Attach block devices from 'block=' module param */ /*
ret = ubiblock_create_from_param(); * Attach block devices from 'block=' module param.
if (ret) * Even if one block device in the param list fails to come up,
goto err_remove; * still allow the module to load and leave any others up.
*/
ubiblock_create_from_param();
/* /*
* Block devices are only created upon user requests, so we ignore * Block devices are only created upon user requests, so we ignore
...@@ -655,7 +655,6 @@ int __init ubiblock_init(void) ...@@ -655,7 +655,6 @@ int __init ubiblock_init(void)
err_unreg: err_unreg:
unregister_blkdev(ubiblock_major, "ubiblock"); unregister_blkdev(ubiblock_major, "ubiblock");
err_remove:
ubiblock_remove_all(); ubiblock_remove_all();
return ret; return ret;
} }
......
...@@ -923,7 +923,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, ...@@ -923,7 +923,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
/* Make sure ubi_num is not busy */ /* Make sure ubi_num is not busy */
if (ubi_devices[ubi_num]) { if (ubi_devices[ubi_num]) {
ubi_err(ubi, "ubi%d already exists", ubi_num); ubi_err(ubi, "already exists");
return -EEXIST; return -EEXIST;
} }
} }
...@@ -973,7 +973,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, ...@@ -973,7 +973,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
mutex_init(&ubi->fm_mutex); mutex_init(&ubi->fm_mutex);
init_rwsem(&ubi->fm_sem); init_rwsem(&ubi->fm_sem);
ubi_msg(ubi, "attaching mtd%d to ubi%d", mtd->index, ubi_num); ubi_msg(ubi, "attaching mtd%d", mtd->index);
err = io_init(ubi, max_beb_per1024); err = io_init(ubi, max_beb_per1024);
if (err) if (err)
...@@ -1428,7 +1428,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) ...@@ -1428,7 +1428,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
} }
if (len == 0) { if (len == 0) {
pr_err("UBI warning: empty 'mtd=' parameter - ignored\n"); pr_warn("UBI warning: empty 'mtd=' parameter - ignored\n");
return 0; return 0;
} }
......
...@@ -48,26 +48,25 @@ ...@@ -48,26 +48,25 @@
/** /**
* get_exclusive - get exclusive access to an UBI volume. * get_exclusive - get exclusive access to an UBI volume.
* @ubi: UBI device description object
* @desc: volume descriptor * @desc: volume descriptor
* *
* This function changes UBI volume open mode to "exclusive". Returns previous * This function changes UBI volume open mode to "exclusive". Returns previous
* mode value (positive integer) in case of success and a negative error code * mode value (positive integer) in case of success and a negative error code
* in case of failure. * in case of failure.
*/ */
static int get_exclusive(struct ubi_device *ubi, struct ubi_volume_desc *desc) static int get_exclusive(struct ubi_volume_desc *desc)
{ {
int users, err; int users, err;
struct ubi_volume *vol = desc->vol; struct ubi_volume *vol = desc->vol;
spin_lock(&vol->ubi->volumes_lock); spin_lock(&vol->ubi->volumes_lock);
users = vol->readers + vol->writers + vol->exclusive; users = vol->readers + vol->writers + vol->exclusive + vol->metaonly;
ubi_assert(users > 0); ubi_assert(users > 0);
if (users > 1) { if (users > 1) {
ubi_err(ubi, "%d users for volume %d", users, vol->vol_id); ubi_err(vol->ubi, "%d users for volume %d", users, vol->vol_id);
err = -EBUSY; err = -EBUSY;
} else { } else {
vol->readers = vol->writers = 0; vol->readers = vol->writers = vol->metaonly = 0;
vol->exclusive = 1; vol->exclusive = 1;
err = desc->mode; err = desc->mode;
desc->mode = UBI_EXCLUSIVE; desc->mode = UBI_EXCLUSIVE;
...@@ -87,13 +86,15 @@ static void revoke_exclusive(struct ubi_volume_desc *desc, int mode) ...@@ -87,13 +86,15 @@ static void revoke_exclusive(struct ubi_volume_desc *desc, int mode)
struct ubi_volume *vol = desc->vol; struct ubi_volume *vol = desc->vol;
spin_lock(&vol->ubi->volumes_lock); spin_lock(&vol->ubi->volumes_lock);
ubi_assert(vol->readers == 0 && vol->writers == 0); ubi_assert(vol->readers == 0 && vol->writers == 0 && vol->metaonly == 0);
ubi_assert(vol->exclusive == 1 && desc->mode == UBI_EXCLUSIVE); ubi_assert(vol->exclusive == 1 && desc->mode == UBI_EXCLUSIVE);
vol->exclusive = 0; vol->exclusive = 0;
if (mode == UBI_READONLY) if (mode == UBI_READONLY)
vol->readers = 1; vol->readers = 1;
else if (mode == UBI_READWRITE) else if (mode == UBI_READWRITE)
vol->writers = 1; vol->writers = 1;
else if (mode == UBI_METAONLY)
vol->metaonly = 1;
else else
vol->exclusive = 1; vol->exclusive = 1;
spin_unlock(&vol->ubi->volumes_lock); spin_unlock(&vol->ubi->volumes_lock);
...@@ -421,7 +422,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd, ...@@ -421,7 +422,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
break; break;
} }
err = get_exclusive(ubi, desc); err = get_exclusive(desc);
if (err < 0) if (err < 0)
break; break;
...@@ -457,7 +458,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd, ...@@ -457,7 +458,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
req.bytes < 0 || req.lnum >= vol->usable_leb_size) req.bytes < 0 || req.lnum >= vol->usable_leb_size)
break; break;
err = get_exclusive(ubi, desc); err = get_exclusive(desc);
if (err < 0) if (err < 0)
break; break;
...@@ -734,7 +735,7 @@ static int rename_volumes(struct ubi_device *ubi, ...@@ -734,7 +735,7 @@ static int rename_volumes(struct ubi_device *ubi,
goto out_free; goto out_free;
} }
re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_READWRITE); re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_METAONLY);
if (IS_ERR(re->desc)) { if (IS_ERR(re->desc)) {
err = PTR_ERR(re->desc); err = PTR_ERR(re->desc);
ubi_err(ubi, "cannot open volume %d, error %d", ubi_err(ubi, "cannot open volume %d, error %d",
......
...@@ -426,6 +426,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, ...@@ -426,6 +426,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
pnum, vol_id, lnum); pnum, vol_id, lnum);
err = -EBADMSG; err = -EBADMSG;
} else } else
err = -EINVAL;
ubi_ro_mode(ubi); ubi_ro_mode(ubi);
} }
goto out_free; goto out_free;
...@@ -479,6 +480,61 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, ...@@ -479,6 +480,61 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
return err; return err;
} }
/**
* ubi_eba_read_leb_sg - read data into a scatter gather list.
* @ubi: UBI device description object
* @vol: volume description object
* @lnum: logical eraseblock number
* @sgl: UBI scatter gather list to store the read data
* @offset: offset from where to read
* @len: how many bytes to read
* @check: data CRC check flag
*
* This function works exactly like ubi_eba_read_leb(). But instead of
* storing the read data into a buffer it writes to an UBI scatter gather
* list.
*/
int ubi_eba_read_leb_sg(struct ubi_device *ubi, struct ubi_volume *vol,
struct ubi_sgl *sgl, int lnum, int offset, int len,
int check)
{
int to_read;
int ret;
struct scatterlist *sg;
for (;;) {
ubi_assert(sgl->list_pos < UBI_MAX_SG_COUNT);
sg = &sgl->sg[sgl->list_pos];
if (len < sg->length - sgl->page_pos)
to_read = len;
else
to_read = sg->length - sgl->page_pos;
ret = ubi_eba_read_leb(ubi, vol, lnum,
sg_virt(sg) + sgl->page_pos, offset,
to_read, check);
if (ret < 0)
return ret;
offset += to_read;
len -= to_read;
if (!len) {
sgl->page_pos += to_read;
if (sgl->page_pos == sg->length) {
sgl->list_pos++;
sgl->page_pos = 0;
}
break;
}
sgl->list_pos++;
sgl->page_pos = 0;
}
return ret;
}
/** /**
* recover_peb - recover from write failure. * recover_peb - recover from write failure.
* @ubi: UBI device description object * @ubi: UBI device description object
......
...@@ -1196,6 +1196,19 @@ static int ubi_write_fastmap(struct ubi_device *ubi, ...@@ -1196,6 +1196,19 @@ static int ubi_write_fastmap(struct ubi_device *ubi,
fm_pos += sizeof(*fec); fm_pos += sizeof(*fec);
ubi_assert(fm_pos <= ubi->fm_size); ubi_assert(fm_pos <= ubi->fm_size);
} }
for (i = 0; i < UBI_PROT_QUEUE_LEN; i++) {
list_for_each_entry(wl_e, &ubi->pq[i], u.list) {
fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
fec->pnum = cpu_to_be32(wl_e->pnum);
fec->ec = cpu_to_be32(wl_e->ec);
used_peb_count++;
fm_pos += sizeof(*fec);
ubi_assert(fm_pos <= ubi->fm_size);
}
}
fmh->used_peb_count = cpu_to_be32(used_peb_count); fmh->used_peb_count = cpu_to_be32(used_peb_count);
for (node = rb_first(&ubi->scrub); node; node = rb_next(node)) { for (node = rb_first(&ubi->scrub); node; node = rb_next(node)) {
......
...@@ -1419,8 +1419,7 @@ int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) ...@@ -1419,8 +1419,7 @@ int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
fail: fail:
ubi_err(ubi, "self-check failed for PEB %d", pnum); ubi_err(ubi, "self-check failed for PEB %d", pnum);
ubi_msg(ubi, "hex dump of the %d-%d region", ubi_msg(ubi, "hex dump of the %d-%d region", offset, offset + len);
offset, offset + len);
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1); print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
err = -EINVAL; err = -EINVAL;
error: error:
......
...@@ -137,7 +137,7 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) ...@@ -137,7 +137,7 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
if (mode != UBI_READONLY && mode != UBI_READWRITE && if (mode != UBI_READONLY && mode != UBI_READWRITE &&
mode != UBI_EXCLUSIVE) mode != UBI_EXCLUSIVE && mode != UBI_METAONLY)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
/* /*
...@@ -182,10 +182,17 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) ...@@ -182,10 +182,17 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
break; break;
case UBI_EXCLUSIVE: case UBI_EXCLUSIVE:
if (vol->exclusive || vol->writers || vol->readers) if (vol->exclusive || vol->writers || vol->readers ||
vol->metaonly)
goto out_unlock; goto out_unlock;
vol->exclusive = 1; vol->exclusive = 1;
break; break;
case UBI_METAONLY:
if (vol->metaonly || vol->exclusive)
goto out_unlock;
vol->metaonly = 1;
break;
} }
get_device(&vol->dev); get_device(&vol->dev);
vol->ref_count += 1; vol->ref_count += 1;
...@@ -343,6 +350,10 @@ void ubi_close_volume(struct ubi_volume_desc *desc) ...@@ -343,6 +350,10 @@ void ubi_close_volume(struct ubi_volume_desc *desc)
break; break;
case UBI_EXCLUSIVE: case UBI_EXCLUSIVE:
vol->exclusive = 0; vol->exclusive = 0;
break;
case UBI_METAONLY:
vol->metaonly = 0;
break;
} }
vol->ref_count -= 1; vol->ref_count -= 1;
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
...@@ -354,6 +365,43 @@ void ubi_close_volume(struct ubi_volume_desc *desc) ...@@ -354,6 +365,43 @@ void ubi_close_volume(struct ubi_volume_desc *desc)
} }
EXPORT_SYMBOL_GPL(ubi_close_volume); EXPORT_SYMBOL_GPL(ubi_close_volume);
/**
* leb_read_sanity_check - does sanity checks on read requests.
* @desc: volume descriptor
* @lnum: logical eraseblock number to read from
* @offset: offset within the logical eraseblock to read from
* @len: how many bytes to read
*
* This function is used by ubi_leb_read() and ubi_leb_read_sg()
* to perform sanity checks.
*/
static int leb_read_sanity_check(struct ubi_volume_desc *desc, int lnum,
int offset, int len)
{
struct ubi_volume *vol = desc->vol;
struct ubi_device *ubi = vol->ubi;
int vol_id = vol->vol_id;
if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 ||
lnum >= vol->used_ebs || offset < 0 || len < 0 ||
offset + len > vol->usable_leb_size)
return -EINVAL;
if (vol->vol_type == UBI_STATIC_VOLUME) {
if (vol->used_ebs == 0)
/* Empty static UBI volume */
return 0;
if (lnum == vol->used_ebs - 1 &&
offset + len > vol->last_eb_bytes)
return -EINVAL;
}
if (vol->upd_marker)
return -EBADF;
return 0;
}
/** /**
* ubi_leb_read - read data. * ubi_leb_read - read data.
* @desc: volume descriptor * @desc: volume descriptor
...@@ -390,22 +438,10 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, ...@@ -390,22 +438,10 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
dbg_gen("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset); dbg_gen("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset);
if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 || err = leb_read_sanity_check(desc, lnum, offset, len);
lnum >= vol->used_ebs || offset < 0 || len < 0 || if (err < 0)
offset + len > vol->usable_leb_size) return err;
return -EINVAL;
if (vol->vol_type == UBI_STATIC_VOLUME) {
if (vol->used_ebs == 0)
/* Empty static UBI volume */
return 0;
if (lnum == vol->used_ebs - 1 &&
offset + len > vol->last_eb_bytes)
return -EINVAL;
}
if (vol->upd_marker)
return -EBADF;
if (len == 0) if (len == 0)
return 0; return 0;
...@@ -419,6 +455,46 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, ...@@ -419,6 +455,46 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
} }
EXPORT_SYMBOL_GPL(ubi_leb_read); EXPORT_SYMBOL_GPL(ubi_leb_read);
/**
* ubi_leb_read_sg - read data into a scatter gather list.
* @desc: volume descriptor
* @lnum: logical eraseblock number to read from
* @buf: buffer where to store the read data
* @offset: offset within the logical eraseblock to read from
* @len: how many bytes to read
* @check: whether UBI has to check the read data's CRC or not.
*
* This function works exactly like ubi_leb_read_sg(). But instead of
* storing the read data into a buffer it writes to an UBI scatter gather
* list.
*/
int ubi_leb_read_sg(struct ubi_volume_desc *desc, int lnum, struct ubi_sgl *sgl,
int offset, int len, int check)
{
struct ubi_volume *vol = desc->vol;
struct ubi_device *ubi = vol->ubi;
int err, vol_id = vol->vol_id;
dbg_gen("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset);
err = leb_read_sanity_check(desc, lnum, offset, len);
if (err < 0)
return err;
if (len == 0)
return 0;
err = ubi_eba_read_leb_sg(ubi, vol, sgl, lnum, offset, len, check);
if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) {
ubi_warn(ubi, "mark volume %d as corrupted", vol_id);
vol->corrupted = 1;
}
return err;
}
EXPORT_SYMBOL_GPL(ubi_leb_read_sg);
/** /**
* ubi_leb_write - write data. * ubi_leb_write - write data.
* @desc: volume descriptor * @desc: volume descriptor
......
...@@ -74,6 +74,8 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id) ...@@ -74,6 +74,8 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
for (i = 0; i < vol->used_ebs; i++) { for (i = 0; i < vol->used_ebs; i++) {
int size; int size;
cond_resched();
if (i == vol->used_ebs - 1) if (i == vol->used_ebs - 1)
size = vol->last_eb_bytes; size = vol->last_eb_bytes;
else else
......
...@@ -50,13 +50,13 @@ ...@@ -50,13 +50,13 @@
#define UBI_NAME_STR "ubi" #define UBI_NAME_STR "ubi"
/* Normal UBI messages */ /* Normal UBI messages */
#define ubi_msg(ubi, fmt, ...) pr_notice("UBI-%d: %s:" fmt "\n", \ #define ubi_msg(ubi, fmt, ...) pr_notice(UBI_NAME_STR "%d: " fmt "\n", \
ubi->ubi_num, __func__, ##__VA_ARGS__) ubi->ubi_num, ##__VA_ARGS__)
/* UBI warning messages */ /* UBI warning messages */
#define ubi_warn(ubi, fmt, ...) pr_warn("UBI-%d warning: %s: " fmt "\n", \ #define ubi_warn(ubi, fmt, ...) pr_warn(UBI_NAME_STR "%d warning: %s: " fmt "\n", \
ubi->ubi_num, __func__, ##__VA_ARGS__) ubi->ubi_num, __func__, ##__VA_ARGS__)
/* UBI error messages */ /* UBI error messages */
#define ubi_err(ubi, fmt, ...) pr_err("UBI-%d error: %s: " fmt "\n", \ #define ubi_err(ubi, fmt, ...) pr_err(UBI_NAME_STR "%d error: %s: " fmt "\n", \
ubi->ubi_num, __func__, ##__VA_ARGS__) ubi->ubi_num, __func__, ##__VA_ARGS__)
/* Background thread name pattern */ /* Background thread name pattern */
...@@ -261,6 +261,7 @@ struct ubi_fm_pool { ...@@ -261,6 +261,7 @@ struct ubi_fm_pool {
* @readers: number of users holding this volume in read-only mode * @readers: number of users holding this volume in read-only mode
* @writers: number of users holding this volume in read-write mode * @writers: number of users holding this volume in read-write mode
* @exclusive: whether somebody holds this volume in exclusive mode * @exclusive: whether somebody holds this volume in exclusive mode
* @metaonly: whether somebody is altering only meta data of this volume
* *
* @reserved_pebs: how many physical eraseblocks are reserved for this volume * @reserved_pebs: how many physical eraseblocks are reserved for this volume
* @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
...@@ -309,6 +310,7 @@ struct ubi_volume { ...@@ -309,6 +310,7 @@ struct ubi_volume {
int readers; int readers;
int writers; int writers;
int exclusive; int exclusive;
int metaonly;
int reserved_pebs; int reserved_pebs;
int vol_type; int vol_type;
...@@ -339,7 +341,8 @@ struct ubi_volume { ...@@ -339,7 +341,8 @@ struct ubi_volume {
/** /**
* struct ubi_volume_desc - UBI volume descriptor returned when it is opened. * struct ubi_volume_desc - UBI volume descriptor returned when it is opened.
* @vol: reference to the corresponding volume description object * @vol: reference to the corresponding volume description object
* @mode: open mode (%UBI_READONLY, %UBI_READWRITE, or %UBI_EXCLUSIVE) * @mode: open mode (%UBI_READONLY, %UBI_READWRITE, %UBI_EXCLUSIVE
* or %UBI_METAONLY)
*/ */
struct ubi_volume_desc { struct ubi_volume_desc {
struct ubi_volume *vol; struct ubi_volume *vol;
...@@ -390,7 +393,8 @@ struct ubi_debug_info { ...@@ -390,7 +393,8 @@ struct ubi_debug_info {
* @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs, * @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs,
* @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count, * @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count,
* @vol->readers, @vol->writers, @vol->exclusive, * @vol->readers, @vol->writers, @vol->exclusive,
* @vol->ref_count, @vol->mapping and @vol->eba_tbl. * @vol->metaonly, @vol->ref_count, @vol->mapping and
* @vol->eba_tbl.
* @ref_count: count of references on the UBI device * @ref_count: count of references on the UBI device
* @image_seq: image sequence number recorded on EC headers * @image_seq: image sequence number recorded on EC headers
* *
...@@ -791,6 +795,9 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -791,6 +795,9 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
int lnum); int lnum);
int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
void *buf, int offset, int len, int check); void *buf, int offset, int len, int check);
int ubi_eba_read_leb_sg(struct ubi_device *ubi, struct ubi_volume *vol,
struct ubi_sgl *sgl, int lnum, int offset, int len,
int check);
int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
const void *buf, int offset, int len); const void *buf, int offset, int len);
int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
......
...@@ -655,14 +655,13 @@ static int init_volumes(struct ubi_device *ubi, ...@@ -655,14 +655,13 @@ static int init_volumes(struct ubi_device *ubi,
/** /**
* check_av - check volume attaching information. * check_av - check volume attaching information.
* @ubi: UBI device description object
* @vol: UBI volume description object * @vol: UBI volume description object
* @av: volume attaching information * @av: volume attaching information
* *
* This function returns zero if the volume attaching information is consistent * This function returns zero if the volume attaching information is consistent
* to the data read from the volume tabla, and %-EINVAL if not. * to the data read from the volume tabla, and %-EINVAL if not.
*/ */
static int check_av(const struct ubi_device *ubi, const struct ubi_volume *vol, static int check_av(const struct ubi_volume *vol,
const struct ubi_ainf_volume *av) const struct ubi_ainf_volume *av)
{ {
int err; int err;
...@@ -690,7 +689,7 @@ static int check_av(const struct ubi_device *ubi, const struct ubi_volume *vol, ...@@ -690,7 +689,7 @@ static int check_av(const struct ubi_device *ubi, const struct ubi_volume *vol,
return 0; return 0;
bad: bad:
ubi_err(ubi, "bad attaching information, error %d", err); ubi_err(vol->ubi, "bad attaching information, error %d", err);
ubi_dump_av(av); ubi_dump_av(av);
ubi_dump_vol_info(vol); ubi_dump_vol_info(vol);
return -EINVAL; return -EINVAL;
...@@ -753,7 +752,7 @@ static int check_attaching_info(const struct ubi_device *ubi, ...@@ -753,7 +752,7 @@ static int check_attaching_info(const struct ubi_device *ubi,
ubi_msg(ubi, "finish volume %d removal", av->vol_id); ubi_msg(ubi, "finish volume %d removal", av->vol_id);
ubi_remove_av(ai, av); ubi_remove_av(ai, av);
} else if (av) { } else if (av) {
err = check_av(ubi, vol, av); err = check_av(vol, av);
if (err) if (err)
return err; return err;
} }
......
...@@ -470,11 +470,8 @@ struct ubi_wl_entry *ubi_wl_get_fm_peb(struct ubi_device *ubi, int anchor) ...@@ -470,11 +470,8 @@ struct ubi_wl_entry *ubi_wl_get_fm_peb(struct ubi_device *ubi, int anchor)
{ {
struct ubi_wl_entry *e = NULL; struct ubi_wl_entry *e = NULL;
if (!ubi->free.rb_node || (ubi->free_count - ubi->beb_rsvd_pebs < 1)) { if (!ubi->free.rb_node || (ubi->free_count - ubi->beb_rsvd_pebs < 1))
ubi_warn(ubi, "Can't get peb for fastmap:anchor=%d, free_cnt=%d, reserved=%d",
anchor, ubi->free_count, ubi->beb_rsvd_pebs);
goto out; goto out;
}
if (anchor) if (anchor)
e = find_anchor_wl_entry(&ubi->free); e = find_anchor_wl_entry(&ubi->free);
...@@ -1806,11 +1803,8 @@ int ubi_thread(void *u) ...@@ -1806,11 +1803,8 @@ int ubi_thread(void *u)
for (;;) { for (;;) {
int err; int err;
if (kthread_should_stop()) { if (kthread_should_stop())
ubi_msg(ubi, "background thread \"%s\" should stop, PID %d",
ubi->bgt_name, task_pid_nr(current));
break; break;
}
if (try_to_freeze()) if (try_to_freeze())
continue; continue;
......
...@@ -2032,6 +2032,8 @@ static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr, ...@@ -2032,6 +2032,8 @@ static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr,
long long blk_offs; long long blk_offs;
struct ubifs_data_node *dn = node; struct ubifs_data_node *dn = node;
ubifs_assert(zbr->len >= UBIFS_DATA_NODE_SZ);
/* /*
* Search the inode node this data node belongs to and insert * Search the inode node this data node belongs to and insert
* it to the RB-tree of inodes. * it to the RB-tree of inodes.
...@@ -2060,6 +2062,8 @@ static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr, ...@@ -2060,6 +2062,8 @@ static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr,
struct ubifs_dent_node *dent = node; struct ubifs_dent_node *dent = node;
struct fsck_inode *fscki1; struct fsck_inode *fscki1;
ubifs_assert(zbr->len >= UBIFS_DENT_NODE_SZ);
err = ubifs_validate_entry(c, dent); err = ubifs_validate_entry(c, dent);
if (err) if (err)
goto out_dump; goto out_dump;
......
...@@ -270,6 +270,10 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -270,6 +270,10 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
goto out_budg; goto out_budg;
} }
err = ubifs_init_security(dir, inode, &dentry->d_name);
if (err)
goto out_cancel;
mutex_lock(&dir_ui->ui_mutex); mutex_lock(&dir_ui->ui_mutex);
dir->i_size += sz_change; dir->i_size += sz_change;
dir_ui->ui_size = dir->i_size; dir_ui->ui_size = dir->i_size;
...@@ -726,6 +730,10 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -726,6 +730,10 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
goto out_budg; goto out_budg;
} }
err = ubifs_init_security(dir, inode, &dentry->d_name);
if (err)
goto out_cancel;
mutex_lock(&dir_ui->ui_mutex); mutex_lock(&dir_ui->ui_mutex);
insert_inode_hash(inode); insert_inode_hash(inode);
inc_nlink(inode); inc_nlink(inode);
...@@ -806,6 +814,10 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -806,6 +814,10 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
ui->data = dev; ui->data = dev;
ui->data_len = devlen; ui->data_len = devlen;
err = ubifs_init_security(dir, inode, &dentry->d_name);
if (err)
goto out_cancel;
mutex_lock(&dir_ui->ui_mutex); mutex_lock(&dir_ui->ui_mutex);
dir->i_size += sz_change; dir->i_size += sz_change;
dir_ui->ui_size = dir->i_size; dir_ui->ui_size = dir->i_size;
...@@ -882,6 +894,10 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -882,6 +894,10 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
ui->data_len = len; ui->data_len = len;
inode->i_size = ubifs_inode(inode)->ui_size = len; inode->i_size = ubifs_inode(inode)->ui_size = len;
err = ubifs_init_security(dir, inode, &dentry->d_name);
if (err)
goto out_cancel;
mutex_lock(&dir_ui->ui_mutex); mutex_lock(&dir_ui->ui_mutex);
dir->i_size += sz_change; dir->i_size += sz_change;
dir_ui->ui_size = dir->i_size; dir_ui->ui_size = dir->i_size;
......
...@@ -1573,6 +1573,10 @@ const struct inode_operations ubifs_symlink_inode_operations = { ...@@ -1573,6 +1573,10 @@ const struct inode_operations ubifs_symlink_inode_operations = {
.follow_link = ubifs_follow_link, .follow_link = ubifs_follow_link,
.setattr = ubifs_setattr, .setattr = ubifs_setattr,
.getattr = ubifs_getattr, .getattr = ubifs_getattr,
.setxattr = ubifs_setxattr,
.getxattr = ubifs_getxattr,
.listxattr = ubifs_listxattr,
.removexattr = ubifs_removexattr,
}; };
const struct file_operations ubifs_file_operations = { const struct file_operations ubifs_file_operations = {
......
...@@ -1028,9 +1028,22 @@ int ubifs_replay_journal(struct ubifs_info *c) ...@@ -1028,9 +1028,22 @@ int ubifs_replay_journal(struct ubifs_info *c)
do { do {
err = replay_log_leb(c, lnum, 0, c->sbuf); err = replay_log_leb(c, lnum, 0, c->sbuf);
if (err == 1) if (err == 1) {
/* We hit the end of the log */ if (lnum != c->lhead_lnum)
break; /* We hit the end of the log */
break;
/*
* The head of the log must always start with the
* "commit start" node on a properly formatted UBIFS.
* But we found no nodes at all, which means that
* someting went wrong and we cannot proceed mounting
* the file-system.
*/
ubifs_err("no UBIFS nodes found at the log head LEB %d:%d, possibly corrupted",
lnum, 0);
err = -EINVAL;
}
if (err) if (err)
goto out; goto out;
lnum = ubifs_next_log_lnum(c, lnum); lnum = ubifs_next_log_lnum(c, lnum);
......
...@@ -2036,6 +2036,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -2036,6 +2036,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
if (c->max_inode_sz > MAX_LFS_FILESIZE) if (c->max_inode_sz > MAX_LFS_FILESIZE)
sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE; sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
sb->s_op = &ubifs_super_operations; sb->s_op = &ubifs_super_operations;
sb->s_xattr = ubifs_xattr_handlers;
mutex_lock(&c->umount_mutex); mutex_lock(&c->umount_mutex);
err = mount_ubifs(c); err = mount_ubifs(c);
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/mtd/ubi.h> #include <linux/mtd/ubi.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/security.h>
#include "ubifs-media.h" #include "ubifs-media.h"
/* Version of this UBIFS implementation */ /* Version of this UBIFS implementation */
...@@ -1465,6 +1466,7 @@ extern spinlock_t ubifs_infos_lock; ...@@ -1465,6 +1466,7 @@ extern spinlock_t ubifs_infos_lock;
extern atomic_long_t ubifs_clean_zn_cnt; extern atomic_long_t ubifs_clean_zn_cnt;
extern struct kmem_cache *ubifs_inode_slab; extern struct kmem_cache *ubifs_inode_slab;
extern const struct super_operations ubifs_super_operations; extern const struct super_operations ubifs_super_operations;
extern const struct xattr_handler *ubifs_xattr_handlers[];
extern const struct address_space_operations ubifs_file_address_operations; extern const struct address_space_operations ubifs_file_address_operations;
extern const struct file_operations ubifs_file_operations; extern const struct file_operations ubifs_file_operations;
extern const struct inode_operations ubifs_file_inode_operations; extern const struct inode_operations ubifs_file_inode_operations;
...@@ -1754,6 +1756,8 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf, ...@@ -1754,6 +1756,8 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
size_t size); size_t size);
ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size); ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
int ubifs_removexattr(struct dentry *dentry, const char *name); int ubifs_removexattr(struct dentry *dentry, const char *name);
int ubifs_init_security(struct inode *dentry, struct inode *inode,
const struct qstr *qstr);
/* super.c */ /* super.c */
struct inode *ubifs_iget(struct super_block *sb, unsigned long inum); struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
......
...@@ -100,24 +100,30 @@ static const struct file_operations empty_fops; ...@@ -100,24 +100,30 @@ static const struct file_operations empty_fops;
static int create_xattr(struct ubifs_info *c, struct inode *host, static int create_xattr(struct ubifs_info *c, struct inode *host,
const struct qstr *nm, const void *value, int size) const struct qstr *nm, const void *value, int size)
{ {
int err; int err, names_len;
struct inode *inode; struct inode *inode;
struct ubifs_inode *ui, *host_ui = ubifs_inode(host); struct ubifs_inode *ui, *host_ui = ubifs_inode(host);
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
.new_ino_d = ALIGN(size, 8), .dirtied_ino = 1, .new_ino_d = ALIGN(size, 8), .dirtied_ino = 1,
.dirtied_ino_d = ALIGN(host_ui->data_len, 8) }; .dirtied_ino_d = ALIGN(host_ui->data_len, 8) };
if (host_ui->xattr_cnt >= MAX_XATTRS_PER_INODE) if (host_ui->xattr_cnt >= MAX_XATTRS_PER_INODE) {
ubifs_err("inode %lu already has too many xattrs (%d), cannot create more",
host->i_ino, host_ui->xattr_cnt);
return -ENOSPC; return -ENOSPC;
}
/* /*
* Linux limits the maximum size of the extended attribute names list * Linux limits the maximum size of the extended attribute names list
* to %XATTR_LIST_MAX. This means we should not allow creating more * to %XATTR_LIST_MAX. This means we should not allow creating more
* extended attributes if the name list becomes larger. This limitation * extended attributes if the name list becomes larger. This limitation
* is artificial for UBIFS, though. * is artificial for UBIFS, though.
*/ */
if (host_ui->xattr_names + host_ui->xattr_cnt + names_len = host_ui->xattr_names + host_ui->xattr_cnt + nm->len + 1;
nm->len + 1 > XATTR_LIST_MAX) if (names_len > XATTR_LIST_MAX) {
ubifs_err("cannot add one more xattr name to inode %lu, total names length would become %d, max. is %d",
host->i_ino, names_len, XATTR_LIST_MAX);
return -ENOSPC; return -ENOSPC;
}
err = ubifs_budget_space(c, &req); err = ubifs_budget_space(c, &req);
if (err) if (err)
...@@ -293,18 +299,16 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum) ...@@ -293,18 +299,16 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
int ubifs_setxattr(struct dentry *dentry, const char *name, static int setxattr(struct inode *host, const char *name, const void *value,
const void *value, size_t size, int flags) size_t size, int flags)
{ {
struct inode *inode, *host = dentry->d_inode; struct inode *inode;
struct ubifs_info *c = host->i_sb->s_fs_info; struct ubifs_info *c = host->i_sb->s_fs_info;
struct qstr nm = QSTR_INIT(name, strlen(name)); struct qstr nm = QSTR_INIT(name, strlen(name));
struct ubifs_dent_node *xent; struct ubifs_dent_node *xent;
union ubifs_key key; union ubifs_key key;
int err, type; int err, type;
dbg_gen("xattr '%s', host ino %lu ('%pd'), size %zd", name,
host->i_ino, dentry, size);
ubifs_assert(mutex_is_locked(&host->i_mutex)); ubifs_assert(mutex_is_locked(&host->i_mutex));
if (size > UBIFS_MAX_INO_DATA) if (size > UBIFS_MAX_INO_DATA)
...@@ -356,6 +360,15 @@ int ubifs_setxattr(struct dentry *dentry, const char *name, ...@@ -356,6 +360,15 @@ int ubifs_setxattr(struct dentry *dentry, const char *name,
return err; return err;
} }
int ubifs_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
dbg_gen("xattr '%s', host ino %lu ('%pd'), size %zd",
name, dentry->d_inode->i_ino, dentry, size);
return setxattr(dentry->d_inode, name, value, size, flags);
}
ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf, ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
size_t size) size_t size)
{ {
...@@ -568,3 +581,84 @@ int ubifs_removexattr(struct dentry *dentry, const char *name) ...@@ -568,3 +581,84 @@ int ubifs_removexattr(struct dentry *dentry, const char *name)
kfree(xent); kfree(xent);
return err; return err;
} }
static size_t security_listxattr(struct dentry *d, char *list, size_t list_size,
const char *name, size_t name_len, int flags)
{
const int prefix_len = XATTR_SECURITY_PREFIX_LEN;
const size_t total_len = prefix_len + name_len + 1;
if (list && total_len <= list_size) {
memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
memcpy(list + prefix_len, name, name_len);
list[prefix_len + name_len] = '\0';
}
return total_len;
}
static int security_getxattr(struct dentry *d, const char *name, void *buffer,
size_t size, int flags)
{
return ubifs_getxattr(d, name, buffer, size);
}
static int security_setxattr(struct dentry *d, const char *name,
const void *value, size_t size, int flags,
int handler_flags)
{
return ubifs_setxattr(d, name, value, size, flags);
}
static const struct xattr_handler ubifs_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.list = security_listxattr,
.get = security_getxattr,
.set = security_setxattr,
};
const struct xattr_handler *ubifs_xattr_handlers[] = {
&ubifs_xattr_security_handler,
NULL,
};
static int init_xattrs(struct inode *inode, const struct xattr *xattr_array,
void *fs_info)
{
const struct xattr *xattr;
char *name;
int err = 0;
for (xattr = xattr_array; xattr->name != NULL; xattr++) {
name = kmalloc(XATTR_SECURITY_PREFIX_LEN +
strlen(xattr->name) + 1, GFP_NOFS);
if (!name) {
err = -ENOMEM;
break;
}
strcpy(name, XATTR_SECURITY_PREFIX);
strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
err = setxattr(inode, name, xattr->value, xattr->value_len, 0);
kfree(name);
if (err < 0)
break;
}
return err;
}
int ubifs_init_security(struct inode *dentry, struct inode *inode,
const struct qstr *qstr)
{
int err;
mutex_lock(&inode->i_mutex);
err = security_inode_init_security(inode, dentry, qstr,
&init_xattrs, 0);
mutex_unlock(&inode->i_mutex);
if (err)
ubifs_err("cannot initialize security for inode %lu, error %d",
inode->i_ino, err);
return err;
}
...@@ -23,22 +23,32 @@ ...@@ -23,22 +23,32 @@
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/scatterlist.h>
#include <mtd/ubi-user.h> #include <mtd/ubi-user.h>
/* All voumes/LEBs */ /* All voumes/LEBs */
#define UBI_ALL -1 #define UBI_ALL -1
/*
* Maximum number of scatter gather list entries,
* we use only 64 to have a lower memory foot print.
*/
#define UBI_MAX_SG_COUNT 64
/* /*
* enum ubi_open_mode - UBI volume open mode constants. * enum ubi_open_mode - UBI volume open mode constants.
* *
* UBI_READONLY: read-only mode * UBI_READONLY: read-only mode
* UBI_READWRITE: read-write mode * UBI_READWRITE: read-write mode
* UBI_EXCLUSIVE: exclusive mode * UBI_EXCLUSIVE: exclusive mode
* UBI_METAONLY: modify only the volume meta-data,
* i.e. the data stored in the volume table, but not in any of volume LEBs.
*/ */
enum { enum {
UBI_READONLY = 1, UBI_READONLY = 1,
UBI_READWRITE, UBI_READWRITE,
UBI_EXCLUSIVE UBI_EXCLUSIVE,
UBI_METAONLY
}; };
/** /**
...@@ -115,6 +125,35 @@ struct ubi_volume_info { ...@@ -115,6 +125,35 @@ struct ubi_volume_info {
dev_t cdev; dev_t cdev;
}; };
/**
* struct ubi_sgl - UBI scatter gather list data structure.
* @list_pos: current position in @sg[]
* @page_pos: current position in @sg[@list_pos]
* @sg: the scatter gather list itself
*
* ubi_sgl is a wrapper around a scatter list which keeps track of the
* current position in the list and the current list item such that
* it can be used across multiple ubi_leb_read_sg() calls.
*/
struct ubi_sgl {
int list_pos;
int page_pos;
struct scatterlist sg[UBI_MAX_SG_COUNT];
};
/**
* ubi_sgl_init - initialize an UBI scatter gather list data structure.
* @usgl: the UBI scatter gather struct itself
*
* Please note that you still have to use sg_init_table() or any adequate
* function to initialize the unterlaying struct scatterlist.
*/
static inline void ubi_sgl_init(struct ubi_sgl *usgl)
{
usgl->list_pos = 0;
usgl->page_pos = 0;
}
/** /**
* struct ubi_device_info - UBI device description data structure. * struct ubi_device_info - UBI device description data structure.
* @ubi_num: ubi device number * @ubi_num: ubi device number
...@@ -210,6 +249,8 @@ int ubi_unregister_volume_notifier(struct notifier_block *nb); ...@@ -210,6 +249,8 @@ int ubi_unregister_volume_notifier(struct notifier_block *nb);
void ubi_close_volume(struct ubi_volume_desc *desc); void ubi_close_volume(struct ubi_volume_desc *desc);
int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
int len, int check); int len, int check);
int ubi_leb_read_sg(struct ubi_volume_desc *desc, int lnum, struct ubi_sgl *sgl,
int offset, int len, int check);
int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
int offset, int len); int offset, int len);
int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf, int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
...@@ -230,4 +271,14 @@ static inline int ubi_read(struct ubi_volume_desc *desc, int lnum, char *buf, ...@@ -230,4 +271,14 @@ static inline int ubi_read(struct ubi_volume_desc *desc, int lnum, char *buf,
{ {
return ubi_leb_read(desc, lnum, buf, offset, len, 0); return ubi_leb_read(desc, lnum, buf, offset, len, 0);
} }
/*
* This function is the same as the 'ubi_leb_read_sg()' function, but it does
* not provide the checking capability.
*/
static inline int ubi_read_sg(struct ubi_volume_desc *desc, int lnum,
struct ubi_sgl *sgl, int offset, int len)
{
return ubi_leb_read_sg(desc, lnum, sgl, offset, len, 0);
}
#endif /* !__LINUX_UBI_H__ */ #endif /* !__LINUX_UBI_H__ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册