Commit 8c988ae7 authored by Linus Torvalds's avatar 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
parents d347efeb 8168b9bb
...@@ -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
......
This diff is collapsed.
...@@ -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%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment