1
0
Fork 0

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
hifive-unleashed-5.1
Linus Torvalds 2015-02-15 10:11:39 -08:00
commit 8c988ae787
20 changed files with 521 additions and 193 deletions

View File

@ -9990,20 +9990,15 @@ F: drivers/scsi/ufs/
UNSORTED BLOCK IMAGES (UBI)
M: Artem Bityutskiy <dedekind1@gmail.com>
M: Richard Weinberger <richard@nod.at>
W: http://www.linux-mtd.infradead.org/
L: linux-mtd@lists.infradead.org
T: git git://git.infradead.org/ubifs-2.6.git
S: Maintained
S: Supported
F: drivers/mtd/ubi/
F: include/linux/mtd/ubi.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
M: Oliver Neukum <oliver@neukum.org>
L: linux-usb@vger.kernel.org

View File

@ -42,11 +42,12 @@
#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/blk-mq.h>
#include <linux/hdreg.h>
#include <linux/scatterlist.h>
#include <asm/div64.h>
#include "ubi-media.h"
@ -67,6 +68,11 @@ struct ubiblock_param {
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 */
static int ubiblock_devs __initdata;
@ -84,11 +90,10 @@ struct ubiblock {
struct request_queue *rq;
struct workqueue_struct *wq;
struct work_struct work;
struct mutex dev_mutex;
spinlock_t queue_lock;
struct list_head list;
struct blk_mq_tag_set tag_set;
};
/* Linked list of all ubiblock instances */
@ -181,31 +186,20 @@ static struct ubiblock *find_dev_nolock(int ubi_num, int vol_id)
return NULL;
}
static int ubiblock_read_to_buf(struct ubiblock *dev, char *buffer,
int leb, int offset, int len)
static int ubiblock_read(struct ubiblock_pdu *pdu)
{
int ret;
int ret, leb, offset, bytes_left, to_read;
u64 pos;
struct request *req = blk_mq_rq_from_pdu(pdu);
struct ubiblock *dev = req->q->queuedata;
ret = ubi_read(dev->desc, leb, buffer, offset, len);
if (ret) {
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,
sector_t sec, int len)
{
int ret, leb, offset;
int bytes_left = len;
int to_read = len;
u64 pos = sec << 9;
to_read = blk_rq_bytes(req);
pos = blk_rq_pos(req) << 9;
/* Get LEB:offset address to read from */
offset = do_div(pos, dev->leb_size);
leb = pos;
bytes_left = to_read;
while (bytes_left) {
/*
@ -215,11 +209,10 @@ static int ubiblock_read(struct ubiblock *dev, char *buffer,
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)
ret = ubi_read_sg(dev->desc, leb, &pdu->usgl, offset, to_read);
if (ret < 0)
return ret;
buffer += to_read;
bytes_left -= to_read;
to_read = bytes_left;
leb += 1;
@ -228,79 +221,6 @@ static int ubiblock_read(struct ubiblock *dev, char *buffer,
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)
{
struct ubiblock *dev = bdev->bd_disk->private_data;
@ -374,6 +294,63 @@ static const struct block_device_operations ubiblock_ops = {
.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)
{
struct ubiblock *dev;
@ -417,14 +394,28 @@ int ubiblock_create(struct ubi_volume_info *vi)
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) {
dev_err(disk_to_dev(gd), "blk_init_queue failed");
ret = -ENODEV;
dev->tag_set.ops = &ubiblock_mq_ops;
dev->tag_set.queue_depth = 64;
dev->tag_set.numa_node = NUMA_NO_NODE;
dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
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;
}
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->gd->queue = dev->rq;
@ -437,7 +428,6 @@ int ubiblock_create(struct ubi_volume_info *vi)
ret = -ENOMEM;
goto out_free_queue;
}
INIT_WORK(&dev->work, ubiblock_do_work);
mutex_lock(&devices_mutex);
list_add_tail(&dev->list, &ubiblock_devices);
@ -451,6 +441,8 @@ int ubiblock_create(struct ubi_volume_info *vi)
out_free_queue:
blk_cleanup_queue(dev->rq);
out_free_tags:
blk_mq_free_tag_set(&dev->tag_set);
out_put_disk:
put_disk(dev->gd);
out_free_dev:
@ -461,8 +453,13 @@ out_free_dev:
static void ubiblock_cleanup(struct ubiblock *dev)
{
/* Stop new requests to arrive */
del_gendisk(dev->gd);
/* Flush pending work */
destroy_workqueue(dev->wq);
/* Finally destroy the blk queue */
blk_cleanup_queue(dev->rq);
blk_mq_free_tag_set(&dev->tag_set);
dev_info(disk_to_dev(dev->gd), "released");
put_disk(dev->gd);
}
@ -490,9 +487,6 @@ int ubiblock_remove(struct ubi_volume_info *vi)
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);
@ -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);
}
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 ubi_volume_desc *desc;
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++) {
p = &ubiblock_param[i];
desc = open_volume_desc(p->name, p->ubi_num, p->vol_id);
if (IS_ERR(desc)) {
pr_err("UBI: block: can't open volume, err=%ld\n",
PTR_ERR(desc));
ret = PTR_ERR(desc);
break;
pr_err(
"UBI: block: can't open volume on ubi%d_%d, err=%ld",
p->ubi_num, p->vol_id, PTR_ERR(desc));
continue;
}
ubi_get_volume_info(desc, &vi);
@ -606,12 +606,12 @@ static int __init ubiblock_create_from_param(void)
ret = ubiblock_create(&vi);
if (ret) {
pr_err("UBI: block: can't add '%s' volume, err=%d\n",
vi.name, ret);
break;
pr_err(
"UBI: block: can't add '%s' volume on ubi%d_%d, err=%d",
vi.name, p->ubi_num, p->vol_id, ret);
continue;
}
}
return ret;
}
static void ubiblock_remove_all(void)
@ -620,8 +620,6 @@ static void ubiblock_remove_all(void)
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 */
@ -639,10 +637,12 @@ int __init ubiblock_init(void)
if (ubiblock_major < 0)
return ubiblock_major;
/* Attach block devices from 'block=' module param */
ret = ubiblock_create_from_param();
if (ret)
goto err_remove;
/*
* Attach block devices from 'block=' module param.
* Even if one block device in the param list fails to come up,
* 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
@ -655,7 +655,6 @@ int __init ubiblock_init(void)
err_unreg:
unregister_blkdev(ubiblock_major, "ubiblock");
err_remove:
ubiblock_remove_all();
return ret;
}

View File

@ -923,7 +923,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
/* Make sure ubi_num is not busy */
if (ubi_devices[ubi_num]) {
ubi_err(ubi, "ubi%d already exists", ubi_num);
ubi_err(ubi, "already exists");
return -EEXIST;
}
}
@ -973,7 +973,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
mutex_init(&ubi->fm_mutex);
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);
if (err)
@ -1428,7 +1428,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
}
if (len == 0) {
pr_err("UBI warning: empty 'mtd=' parameter - ignored\n");
pr_warn("UBI warning: empty 'mtd=' parameter - ignored\n");
return 0;
}

View File

@ -48,26 +48,25 @@
/**
* get_exclusive - get exclusive access to an UBI volume.
* @ubi: UBI device description object
* @desc: volume descriptor
*
* This function changes UBI volume open mode to "exclusive". Returns previous
* mode value (positive integer) in case of success and a negative error code
* 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;
struct ubi_volume *vol = desc->vol;
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);
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;
} else {
vol->readers = vol->writers = 0;
vol->readers = vol->writers = vol->metaonly = 0;
vol->exclusive = 1;
err = desc->mode;
desc->mode = UBI_EXCLUSIVE;
@ -87,13 +86,15 @@ static void revoke_exclusive(struct ubi_volume_desc *desc, int mode)
struct ubi_volume *vol = desc->vol;
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);
vol->exclusive = 0;
if (mode == UBI_READONLY)
vol->readers = 1;
else if (mode == UBI_READWRITE)
vol->writers = 1;
else if (mode == UBI_METAONLY)
vol->metaonly = 1;
else
vol->exclusive = 1;
spin_unlock(&vol->ubi->volumes_lock);
@ -421,7 +422,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
break;
}
err = get_exclusive(ubi, desc);
err = get_exclusive(desc);
if (err < 0)
break;
@ -457,7 +458,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
req.bytes < 0 || req.lnum >= vol->usable_leb_size)
break;
err = get_exclusive(ubi, desc);
err = get_exclusive(desc);
if (err < 0)
break;
@ -734,7 +735,7 @@ static int rename_volumes(struct ubi_device *ubi,
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)) {
err = PTR_ERR(re->desc);
ubi_err(ubi, "cannot open volume %d, error %d",

View File

@ -426,6 +426,7 @@ retry:
pnum, vol_id, lnum);
err = -EBADMSG;
} else
err = -EINVAL;
ubi_ro_mode(ubi);
}
goto out_free;
@ -479,6 +480,61 @@ out_unlock:
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.
* @ubi: UBI device description object

View File

@ -1196,6 +1196,19 @@ static int ubi_write_fastmap(struct ubi_device *ubi,
fm_pos += sizeof(*fec);
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);
for (node = rb_first(&ubi->scrub); node; node = rb_next(node)) {

View File

@ -1419,8 +1419,7 @@ int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
fail:
ubi_err(ubi, "self-check failed for PEB %d", pnum);
ubi_msg(ubi, "hex dump of the %d-%d region",
offset, offset + len);
ubi_msg(ubi, "hex dump of the %d-%d region", offset, offset + len);
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
err = -EINVAL;
error:

View File

@ -137,7 +137,7 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
return ERR_PTR(-EINVAL);
if (mode != UBI_READONLY && mode != UBI_READWRITE &&
mode != UBI_EXCLUSIVE)
mode != UBI_EXCLUSIVE && mode != UBI_METAONLY)
return ERR_PTR(-EINVAL);
/*
@ -182,10 +182,17 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
break;
case UBI_EXCLUSIVE:
if (vol->exclusive || vol->writers || vol->readers)
if (vol->exclusive || vol->writers || vol->readers ||
vol->metaonly)
goto out_unlock;
vol->exclusive = 1;
break;
case UBI_METAONLY:
if (vol->metaonly || vol->exclusive)
goto out_unlock;
vol->metaonly = 1;
break;
}
get_device(&vol->dev);
vol->ref_count += 1;
@ -343,6 +350,10 @@ void ubi_close_volume(struct ubi_volume_desc *desc)
break;
case UBI_EXCLUSIVE:
vol->exclusive = 0;
break;
case UBI_METAONLY:
vol->metaonly = 0;
break;
}
vol->ref_count -= 1;
spin_unlock(&ubi->volumes_lock);
@ -354,6 +365,43 @@ void ubi_close_volume(struct ubi_volume_desc *desc)
}
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.
* @desc: volume descriptor
@ -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);
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;
err = leb_read_sanity_check(desc, lnum, offset, len);
if (err < 0)
return err;
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)
return 0;
@ -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);
/**
* 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.
* @desc: volume descriptor

View File

@ -74,6 +74,8 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
for (i = 0; i < vol->used_ebs; i++) {
int size;
cond_resched();
if (i == vol->used_ebs - 1)
size = vol->last_eb_bytes;
else

View File

@ -50,13 +50,13 @@
#define UBI_NAME_STR "ubi"
/* Normal UBI messages */
#define ubi_msg(ubi, fmt, ...) pr_notice("UBI-%d: %s:" fmt "\n", \
ubi->ubi_num, __func__, ##__VA_ARGS__)
#define ubi_msg(ubi, fmt, ...) pr_notice(UBI_NAME_STR "%d: " fmt "\n", \
ubi->ubi_num, ##__VA_ARGS__)
/* 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 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__)
/* Background thread name pattern */
@ -261,6 +261,7 @@ struct ubi_fm_pool {
* @readers: number of users holding this volume in read-only mode
* @writers: number of users holding this volume in read-write 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
* @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
@ -309,6 +310,7 @@ struct ubi_volume {
int readers;
int writers;
int exclusive;
int metaonly;
int reserved_pebs;
int vol_type;
@ -339,7 +341,8 @@ struct ubi_volume {
/**
* struct ubi_volume_desc - UBI volume descriptor returned when it is opened.
* @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 *vol;
@ -390,7 +393,8 @@ struct ubi_debug_info {
* @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs,
* @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count,
* @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
* @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,
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);
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,
const void *buf, int offset, int len);
int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,

View File

@ -655,14 +655,13 @@ static int init_volumes(struct ubi_device *ubi,
/**
* check_av - check volume attaching information.
* @ubi: UBI device description object
* @vol: UBI volume description object
* @av: volume attaching information
*
* This function returns zero if the volume attaching information is consistent
* 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)
{
int err;
@ -690,7 +689,7 @@ static int check_av(const struct ubi_device *ubi, const struct ubi_volume *vol,
return 0;
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_vol_info(vol);
return -EINVAL;
@ -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_remove_av(ai, av);
} else if (av) {
err = check_av(ubi, vol, av);
err = check_av(vol, av);
if (err)
return err;
}

View File

@ -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;
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);
if (!ubi->free.rb_node || (ubi->free_count - ubi->beb_rsvd_pebs < 1))
goto out;
}
if (anchor)
e = find_anchor_wl_entry(&ubi->free);
@ -1806,11 +1803,8 @@ int ubi_thread(void *u)
for (;;) {
int err;
if (kthread_should_stop()) {
ubi_msg(ubi, "background thread \"%s\" should stop, PID %d",
ubi->bgt_name, task_pid_nr(current));
if (kthread_should_stop())
break;
}
if (try_to_freeze())
continue;

View File

@ -2032,6 +2032,8 @@ static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr,
long long blk_offs;
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
* it to the RB-tree of inodes.
@ -2060,6 +2062,8 @@ static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr,
struct ubifs_dent_node *dent = node;
struct fsck_inode *fscki1;
ubifs_assert(zbr->len >= UBIFS_DENT_NODE_SZ);
err = ubifs_validate_entry(c, dent);
if (err)
goto out_dump;

View File

@ -270,6 +270,10 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
goto out_budg;
}
err = ubifs_init_security(dir, inode, &dentry->d_name);
if (err)
goto out_cancel;
mutex_lock(&dir_ui->ui_mutex);
dir->i_size += sz_change;
dir_ui->ui_size = dir->i_size;
@ -726,6 +730,10 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
goto out_budg;
}
err = ubifs_init_security(dir, inode, &dentry->d_name);
if (err)
goto out_cancel;
mutex_lock(&dir_ui->ui_mutex);
insert_inode_hash(inode);
inc_nlink(inode);
@ -806,6 +814,10 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
ui->data = dev;
ui->data_len = devlen;
err = ubifs_init_security(dir, inode, &dentry->d_name);
if (err)
goto out_cancel;
mutex_lock(&dir_ui->ui_mutex);
dir->i_size += sz_change;
dir_ui->ui_size = dir->i_size;
@ -882,6 +894,10 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
ui->data_len = 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);
dir->i_size += sz_change;
dir_ui->ui_size = dir->i_size;

View File

@ -1573,6 +1573,10 @@ const struct inode_operations ubifs_symlink_inode_operations = {
.follow_link = ubifs_follow_link,
.setattr = ubifs_setattr,
.getattr = ubifs_getattr,
.setxattr = ubifs_setxattr,
.getxattr = ubifs_getxattr,
.listxattr = ubifs_listxattr,
.removexattr = ubifs_removexattr,
};
const struct file_operations ubifs_file_operations = {

View File

@ -1028,9 +1028,22 @@ int ubifs_replay_journal(struct ubifs_info *c)
do {
err = replay_log_leb(c, lnum, 0, c->sbuf);
if (err == 1)
/* We hit the end of the log */
break;
if (err == 1) {
if (lnum != c->lhead_lnum)
/* 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)
goto out;
lnum = ubifs_next_log_lnum(c, lnum);

View File

@ -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)
sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
sb->s_op = &ubifs_super_operations;
sb->s_xattr = ubifs_xattr_handlers;
mutex_lock(&c->umount_mutex);
err = mount_ubifs(c);

View File

@ -36,6 +36,7 @@
#include <linux/mtd/ubi.h>
#include <linux/pagemap.h>
#include <linux/backing-dev.h>
#include <linux/security.h>
#include "ubifs-media.h"
/* Version of this UBIFS implementation */
@ -1465,6 +1466,7 @@ extern spinlock_t ubifs_infos_lock;
extern atomic_long_t ubifs_clean_zn_cnt;
extern struct kmem_cache *ubifs_inode_slab;
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 file_operations ubifs_file_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,
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_init_security(struct inode *dentry, struct inode *inode,
const struct qstr *qstr);
/* super.c */
struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);

View File

@ -100,24 +100,30 @@ static const struct file_operations empty_fops;
static int create_xattr(struct ubifs_info *c, struct inode *host,
const struct qstr *nm, const void *value, int size)
{
int err;
int err, names_len;
struct inode *inode;
struct ubifs_inode *ui, *host_ui = ubifs_inode(host);
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
.new_ino_d = ALIGN(size, 8), .dirtied_ino = 1,
.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;
}
/*
* Linux limits the maximum size of the extended attribute names list
* to %XATTR_LIST_MAX. This means we should not allow creating more
* extended attributes if the name list becomes larger. This limitation
* is artificial for UBIFS, though.
*/
if (host_ui->xattr_names + host_ui->xattr_cnt +
nm->len + 1 > XATTR_LIST_MAX)
names_len = host_ui->xattr_names + host_ui->xattr_cnt + nm->len + 1;
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;
}
err = ubifs_budget_space(c, &req);
if (err)
@ -293,18 +299,16 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum)
return ERR_PTR(-EINVAL);
}
int ubifs_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
static int setxattr(struct inode *host, const char *name, const void *value,
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 qstr nm = QSTR_INIT(name, strlen(name));
struct ubifs_dent_node *xent;
union ubifs_key key;
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));
if (size > UBIFS_MAX_INO_DATA)
@ -356,6 +360,15 @@ out_free:
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,
size_t size)
{
@ -568,3 +581,84 @@ out_free:
kfree(xent);
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;
}

View File

@ -23,22 +23,32 @@
#include <linux/ioctl.h>
#include <linux/types.h>
#include <linux/scatterlist.h>
#include <mtd/ubi-user.h>
/* All voumes/LEBs */
#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.
*
* UBI_READONLY: read-only mode
* UBI_READWRITE: read-write 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 {
UBI_READONLY = 1,
UBI_READWRITE,
UBI_EXCLUSIVE
UBI_EXCLUSIVE,
UBI_METAONLY
};
/**
@ -115,6 +125,35 @@ struct ubi_volume_info {
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.
* @ubi_num: ubi device number
@ -210,6 +249,8 @@ int ubi_unregister_volume_notifier(struct notifier_block *nb);
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 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 offset, int len);
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,
{
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__ */