mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-16 23:45:31 +08:00
UBI: Add initial support for scatter gather
Adds a new set of functions to deal with scatter gather. ubi_eba_read_leb_sg() will read from a LEB into a scatter gather list. The new data structure struct ubi_sgl will be used within UBI to hold the scatter gather list itself and metadata to have a cursor within the list. Signed-off-by: Richard Weinberger <richard@nod.at> Tested-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> Reviewed-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
This commit is contained in:
parent
892abde56c
commit
9ff08979e1
@ -479,6 +479,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
|
||||
|
@ -365,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
|
||||
@ -401,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;
|
||||
|
||||
@ -430,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
|
||||
|
@ -795,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,
|
||||
|
@ -23,11 +23,18 @@
|
||||
|
||||
#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.
|
||||
*
|
||||
@ -118,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
|
||||
@ -213,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,
|
||||
@ -233,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