mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-14 04:41:26 +00:00
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
This commit is contained in:
commit
8c988ae787
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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)) {
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 = {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
112
fs/ubifs/xattr.c
112
fs/ubifs/xattr.c
@ -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;
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
Loading…
Reference in New Issue
Block a user