- Reduce memory consumption
- Fix picking unknown blocks - Fix error-path in 'ubi_scan()' - Minor clean-ups -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJPbHnAAAoJECmIfjd9wqK0OnwQAIZuVtfVzla2FyJu6TkCSF2t AgB33YqL/vuRAP7DaW2HaH4vlP35PMiVGpXpBL+bdAL3wjiKEALtSl+tdB0LFLB4 Jmd0e5YGbci8lGxy0jgM4Yw+jBGISa/TLRQdGocHfhdpLAmvf+KfDEU1Bk+Vgi/U HdQidXWWQ7KZJPNv88wJBlmvWOU78IfaDJXrzijm7pBUE4dfdX6hBLmpywh/Z6Df q+GS1YHWMG28bbc7y0tX1iZAhv2tQGTTxQsPgicw9LidGfChRwpDvT4zrYgtzzLd 48k9HWcBbb5DoLUosaka4dQ3GggooGTvnBpkdjcNzXx7yn803vw3/M9XePAMtluz jRw8/GeUPq/rRCWoiEcCB2oBM2XZQo0JkfVBraac0NCaWpSbc8kyYnMjGUcrPg7w gGIPkE6J+g+aYbGiylLXkOEjGIbZOhyVo5RpLiA8Bl36u0rBoF/rwrwk2OgO/0oe UYQ02E8NKYK1ynYOl/PpB4pFuHuP0cqdhzUfx7ceyS3O0aBMnCR+j9RIaiBDbAJz RxdY6jodaJ/G7x0cM/VCH1dKTSj+/aQldhkXarhsphroPYxx4D73AN0YNop97Ulz dX5ZocbFWFFoZ+tOrNa+EAN1r+J/GzDxMrfgTrvTXUV3snNJbL6h8IU7wnTn1jjZ 1kfbzI7iEyAd/FRlaevj =tA3v -----END PGP SIGNATURE----- Merge tag 'upstream-3.4-rc1' of git://git.infradead.org/linux-ubi Pull UBI changes from Artem Bityutskiy: - Reduce memory consumption - Fix picking unknown blocks - Fix error-path in 'ubi_scan()' - Minor clean-ups * tag 'upstream-3.4-rc1' of git://git.infradead.org/linux-ubi: UBI: rename MOVE_CANCEL_BITFLIPS to MOVE_TARGET_BITFLIPS UBI: rename peb_buf1 to peb_buf UBI: reduce memory consumption UBI: fix eraseblock picking criteria UBI: fix documentation and improve readability UBI: fix error handling in ubi_scan()
This commit is contained in:
commit
7e61b3ff50
|
@ -945,12 +945,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
|
|||
goto out_free;
|
||||
|
||||
err = -ENOMEM;
|
||||
ubi->peb_buf1 = vmalloc(ubi->peb_size);
|
||||
if (!ubi->peb_buf1)
|
||||
goto out_free;
|
||||
|
||||
ubi->peb_buf2 = vmalloc(ubi->peb_size);
|
||||
if (!ubi->peb_buf2)
|
||||
ubi->peb_buf = vmalloc(ubi->peb_size);
|
||||
if (!ubi->peb_buf)
|
||||
goto out_free;
|
||||
|
||||
err = ubi_debugging_init_dev(ubi);
|
||||
|
@ -1029,8 +1025,7 @@ out_detach:
|
|||
out_debugging:
|
||||
ubi_debugging_exit_dev(ubi);
|
||||
out_free:
|
||||
vfree(ubi->peb_buf1);
|
||||
vfree(ubi->peb_buf2);
|
||||
vfree(ubi->peb_buf);
|
||||
if (ref)
|
||||
put_device(&ubi->dev);
|
||||
else
|
||||
|
@ -1101,8 +1096,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
|
|||
vfree(ubi->vtbl);
|
||||
put_mtd_device(ubi->mtd);
|
||||
ubi_debugging_exit_dev(ubi);
|
||||
vfree(ubi->peb_buf1);
|
||||
vfree(ubi->peb_buf2);
|
||||
vfree(ubi->peb_buf);
|
||||
ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
|
||||
put_device(&ubi->dev);
|
||||
return 0;
|
||||
|
|
|
@ -529,18 +529,18 @@ retry:
|
|||
|
||||
data_size = offset + len;
|
||||
mutex_lock(&ubi->buf_mutex);
|
||||
memset(ubi->peb_buf1 + offset, 0xFF, len);
|
||||
memset(ubi->peb_buf + offset, 0xFF, len);
|
||||
|
||||
/* Read everything before the area where the write failure happened */
|
||||
if (offset > 0) {
|
||||
err = ubi_io_read_data(ubi, ubi->peb_buf1, pnum, 0, offset);
|
||||
err = ubi_io_read_data(ubi, ubi->peb_buf, pnum, 0, offset);
|
||||
if (err && err != UBI_IO_BITFLIPS)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
memcpy(ubi->peb_buf1 + offset, buf, len);
|
||||
memcpy(ubi->peb_buf + offset, buf, len);
|
||||
|
||||
err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size);
|
||||
err = ubi_io_write_data(ubi, ubi->peb_buf, new_pnum, 0, data_size);
|
||||
if (err) {
|
||||
mutex_unlock(&ubi->buf_mutex);
|
||||
goto write_error;
|
||||
|
@ -979,7 +979,7 @@ static int is_error_sane(int err)
|
|||
* physical eraseblock @to. The @vid_hdr buffer may be changed by this
|
||||
* function. Returns:
|
||||
* o %0 in case of success;
|
||||
* o %MOVE_CANCEL_RACE, %MOVE_TARGET_WR_ERR, %MOVE_CANCEL_BITFLIPS, etc;
|
||||
* o %MOVE_CANCEL_RACE, %MOVE_TARGET_WR_ERR, %MOVE_TARGET_BITFLIPS, etc;
|
||||
* o a negative error code in case of failure.
|
||||
*/
|
||||
int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
|
||||
|
@ -1053,13 +1053,13 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
|
|||
|
||||
/*
|
||||
* OK, now the LEB is locked and we can safely start moving it. Since
|
||||
* this function utilizes the @ubi->peb_buf1 buffer which is shared
|
||||
* this function utilizes the @ubi->peb_buf buffer which is shared
|
||||
* with some other functions - we lock the buffer by taking the
|
||||
* @ubi->buf_mutex.
|
||||
*/
|
||||
mutex_lock(&ubi->buf_mutex);
|
||||
dbg_wl("read %d bytes of data", aldata_size);
|
||||
err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size);
|
||||
err = ubi_io_read_data(ubi, ubi->peb_buf, from, 0, aldata_size);
|
||||
if (err && err != UBI_IO_BITFLIPS) {
|
||||
ubi_warn("error %d while reading data from PEB %d",
|
||||
err, from);
|
||||
|
@ -1079,10 +1079,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
|
|||
*/
|
||||
if (vid_hdr->vol_type == UBI_VID_DYNAMIC)
|
||||
aldata_size = data_size =
|
||||
ubi_calc_data_len(ubi, ubi->peb_buf1, data_size);
|
||||
ubi_calc_data_len(ubi, ubi->peb_buf, data_size);
|
||||
|
||||
cond_resched();
|
||||
crc = crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size);
|
||||
crc = crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size);
|
||||
cond_resched();
|
||||
|
||||
/*
|
||||
|
@ -1116,12 +1116,12 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
|
|||
if (is_error_sane(err))
|
||||
err = MOVE_TARGET_RD_ERR;
|
||||
} else
|
||||
err = MOVE_CANCEL_BITFLIPS;
|
||||
err = MOVE_TARGET_BITFLIPS;
|
||||
goto out_unlock_buf;
|
||||
}
|
||||
|
||||
if (data_size > 0) {
|
||||
err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size);
|
||||
err = ubi_io_write_data(ubi, ubi->peb_buf, to, 0, aldata_size);
|
||||
if (err) {
|
||||
if (err == -EIO)
|
||||
err = MOVE_TARGET_WR_ERR;
|
||||
|
@ -1134,8 +1134,8 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
|
|||
* We've written the data and are going to read it back to make
|
||||
* sure it was written correctly.
|
||||
*/
|
||||
|
||||
err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size);
|
||||
memset(ubi->peb_buf, 0xFF, aldata_size);
|
||||
err = ubi_io_read_data(ubi, ubi->peb_buf, to, 0, aldata_size);
|
||||
if (err) {
|
||||
if (err != UBI_IO_BITFLIPS) {
|
||||
ubi_warn("error %d while reading data back "
|
||||
|
@ -1143,13 +1143,13 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
|
|||
if (is_error_sane(err))
|
||||
err = MOVE_TARGET_RD_ERR;
|
||||
} else
|
||||
err = MOVE_CANCEL_BITFLIPS;
|
||||
err = MOVE_TARGET_BITFLIPS;
|
||||
goto out_unlock_buf;
|
||||
}
|
||||
|
||||
cond_resched();
|
||||
|
||||
if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) {
|
||||
if (crc != crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size)) {
|
||||
ubi_warn("read data back from PEB %d and it is "
|
||||
"different", to);
|
||||
err = -EINVAL;
|
||||
|
|
|
@ -431,11 +431,11 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
|
|||
goto out;
|
||||
|
||||
/* Make sure the PEB contains only 0xFF bytes */
|
||||
err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
|
||||
err = ubi_io_read(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = ubi_check_pattern(ubi->peb_buf1, 0xFF, ubi->peb_size);
|
||||
err = ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->peb_size);
|
||||
if (err == 0) {
|
||||
ubi_err("erased PEB %d, but a non-0xFF byte found",
|
||||
pnum);
|
||||
|
@ -444,17 +444,17 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
|
|||
}
|
||||
|
||||
/* Write a pattern and check it */
|
||||
memset(ubi->peb_buf1, patterns[i], ubi->peb_size);
|
||||
err = ubi_io_write(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
|
||||
memset(ubi->peb_buf, patterns[i], ubi->peb_size);
|
||||
err = ubi_io_write(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
memset(ubi->peb_buf1, ~patterns[i], ubi->peb_size);
|
||||
err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
|
||||
memset(ubi->peb_buf, ~patterns[i], ubi->peb_size);
|
||||
err = ubi_io_read(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = ubi_check_pattern(ubi->peb_buf1, patterns[i],
|
||||
err = ubi_check_pattern(ubi->peb_buf, patterns[i],
|
||||
ubi->peb_size);
|
||||
if (err == 0) {
|
||||
ubi_err("pattern %x checking failed for PEB %d",
|
||||
|
|
|
@ -789,9 +789,9 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
|
|||
int err;
|
||||
|
||||
mutex_lock(&ubi->buf_mutex);
|
||||
memset(ubi->peb_buf1, 0x00, ubi->leb_size);
|
||||
memset(ubi->peb_buf, 0x00, ubi->leb_size);
|
||||
|
||||
err = ubi_io_read(ubi, ubi->peb_buf1, pnum, ubi->leb_start,
|
||||
err = ubi_io_read(ubi, ubi->peb_buf, pnum, ubi->leb_start,
|
||||
ubi->leb_size);
|
||||
if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) {
|
||||
/*
|
||||
|
@ -808,7 +808,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
|
|||
if (err)
|
||||
goto out_unlock;
|
||||
|
||||
if (ubi_check_pattern(ubi->peb_buf1, 0xFF, ubi->leb_size))
|
||||
if (ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->leb_size))
|
||||
goto out_unlock;
|
||||
|
||||
ubi_err("PEB %d contains corrupted VID header, and the data does not "
|
||||
|
@ -818,7 +818,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
|
|||
dbg_msg("hexdump of PEB %d offset %d, length %d",
|
||||
pnum, ubi->leb_start, ubi->leb_size);
|
||||
ubi_dbg_print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
|
||||
ubi->peb_buf1, ubi->leb_size, 1);
|
||||
ubi->peb_buf, ubi->leb_size, 1);
|
||||
err = 1;
|
||||
|
||||
out_unlock:
|
||||
|
@ -1174,7 +1174,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
|
|||
|
||||
ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
|
||||
if (!ech)
|
||||
goto out_slab;
|
||||
goto out_si;
|
||||
|
||||
vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
|
||||
if (!vidh)
|
||||
|
@ -1235,8 +1235,6 @@ out_vidh:
|
|||
ubi_free_vid_hdr(ubi, vidh);
|
||||
out_ech:
|
||||
kfree(ech);
|
||||
out_slab:
|
||||
kmem_cache_destroy(si->scan_leb_slab);
|
||||
out_si:
|
||||
ubi_scan_destroy_si(si);
|
||||
return ERR_PTR(err);
|
||||
|
@ -1325,7 +1323,9 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
|
|||
}
|
||||
}
|
||||
|
||||
kmem_cache_destroy(si->scan_leb_slab);
|
||||
if (si->scan_leb_slab)
|
||||
kmem_cache_destroy(si->scan_leb_slab);
|
||||
|
||||
kfree(si);
|
||||
}
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ enum {
|
|||
* PEB
|
||||
* MOVE_TARGET_WR_ERR: canceled because there was a write error to the target
|
||||
* PEB
|
||||
* MOVE_CANCEL_BITFLIPS: canceled because a bit-flip was detected in the
|
||||
* MOVE_TARGET_BITFLIPS: canceled because a bit-flip was detected in the
|
||||
* target PEB
|
||||
* MOVE_RETRY: retry scrubbing the PEB
|
||||
*/
|
||||
|
@ -127,7 +127,7 @@ enum {
|
|||
MOVE_SOURCE_RD_ERR,
|
||||
MOVE_TARGET_RD_ERR,
|
||||
MOVE_TARGET_WR_ERR,
|
||||
MOVE_CANCEL_BITFLIPS,
|
||||
MOVE_TARGET_BITFLIPS,
|
||||
MOVE_RETRY,
|
||||
};
|
||||
|
||||
|
@ -387,9 +387,8 @@ struct ubi_wl_entry;
|
|||
* time (MTD write buffer size)
|
||||
* @mtd: MTD device descriptor
|
||||
*
|
||||
* @peb_buf1: a buffer of PEB size used for different purposes
|
||||
* @peb_buf2: another buffer of PEB size used for different purposes
|
||||
* @buf_mutex: protects @peb_buf1 and @peb_buf2
|
||||
* @peb_buf: a buffer of PEB size used for different purposes
|
||||
* @buf_mutex: protects @peb_buf
|
||||
* @ckvol_mutex: serializes static volume checking when opening
|
||||
*
|
||||
* @dbg: debugging information for this UBI device
|
||||
|
@ -471,8 +470,7 @@ struct ubi_device {
|
|||
int max_write_size;
|
||||
struct mtd_info *mtd;
|
||||
|
||||
void *peb_buf1;
|
||||
void *peb_buf2;
|
||||
void *peb_buf;
|
||||
struct mutex buf_mutex;
|
||||
struct mutex ckvol_mutex;
|
||||
|
||||
|
|
|
@ -350,18 +350,19 @@ static void prot_queue_add(struct ubi_device *ubi, struct ubi_wl_entry *e)
|
|||
/**
|
||||
* find_wl_entry - find wear-leveling entry closest to certain erase counter.
|
||||
* @root: the RB-tree where to look for
|
||||
* @max: highest possible erase counter
|
||||
* @diff: maximum possible difference from the smallest erase counter
|
||||
*
|
||||
* This function looks for a wear leveling entry with erase counter closest to
|
||||
* @max and less than @max.
|
||||
* min + @diff, where min is the smallest erase counter.
|
||||
*/
|
||||
static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int max)
|
||||
static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int diff)
|
||||
{
|
||||
struct rb_node *p;
|
||||
struct ubi_wl_entry *e;
|
||||
int max;
|
||||
|
||||
e = rb_entry(rb_first(root), struct ubi_wl_entry, u.rb);
|
||||
max += e->ec;
|
||||
max = e->ec + diff;
|
||||
|
||||
p = root->rb_node;
|
||||
while (p) {
|
||||
|
@ -389,7 +390,7 @@ static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int max)
|
|||
*/
|
||||
int ubi_wl_get_peb(struct ubi_device *ubi, int dtype)
|
||||
{
|
||||
int err, medium_ec;
|
||||
int err;
|
||||
struct ubi_wl_entry *e, *first, *last;
|
||||
|
||||
ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM ||
|
||||
|
@ -427,7 +428,7 @@ retry:
|
|||
* For unknown data we pick a physical eraseblock with medium
|
||||
* erase counter. But we by no means can pick a physical
|
||||
* eraseblock with erase counter greater or equivalent than the
|
||||
* lowest erase counter plus %WL_FREE_MAX_DIFF.
|
||||
* lowest erase counter plus %WL_FREE_MAX_DIFF/2.
|
||||
*/
|
||||
first = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry,
|
||||
u.rb);
|
||||
|
@ -436,10 +437,8 @@ retry:
|
|||
if (last->ec - first->ec < WL_FREE_MAX_DIFF)
|
||||
e = rb_entry(ubi->free.rb_node,
|
||||
struct ubi_wl_entry, u.rb);
|
||||
else {
|
||||
medium_ec = (first->ec + WL_FREE_MAX_DIFF)/2;
|
||||
e = find_wl_entry(&ubi->free, medium_ec);
|
||||
}
|
||||
else
|
||||
e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF/2);
|
||||
break;
|
||||
case UBI_SHORTTERM:
|
||||
/*
|
||||
|
@ -799,7 +798,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
|
|||
scrubbing = 1;
|
||||
goto out_not_moved;
|
||||
}
|
||||
if (err == MOVE_CANCEL_BITFLIPS || err == MOVE_TARGET_WR_ERR ||
|
||||
if (err == MOVE_TARGET_BITFLIPS || err == MOVE_TARGET_WR_ERR ||
|
||||
err == MOVE_TARGET_RD_ERR) {
|
||||
/*
|
||||
* Target PEB had bit-flips or write error - torture it.
|
||||
|
|
Loading…
Reference in a new issue