Commit 7e61b3ff authored by Linus Torvalds's avatar Linus Torvalds

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()
parents 6e55f8ed cc831464
...@@ -945,12 +945,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ...@@ -945,12 +945,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
goto out_free; goto out_free;
err = -ENOMEM; err = -ENOMEM;
ubi->peb_buf1 = vmalloc(ubi->peb_size); ubi->peb_buf = vmalloc(ubi->peb_size);
if (!ubi->peb_buf1) if (!ubi->peb_buf)
goto out_free;
ubi->peb_buf2 = vmalloc(ubi->peb_size);
if (!ubi->peb_buf2)
goto out_free; goto out_free;
err = ubi_debugging_init_dev(ubi); err = ubi_debugging_init_dev(ubi);
...@@ -1029,8 +1025,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) ...@@ -1029,8 +1025,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
out_debugging: out_debugging:
ubi_debugging_exit_dev(ubi); ubi_debugging_exit_dev(ubi);
out_free: out_free:
vfree(ubi->peb_buf1); vfree(ubi->peb_buf);
vfree(ubi->peb_buf2);
if (ref) if (ref)
put_device(&ubi->dev); put_device(&ubi->dev);
else else
...@@ -1101,8 +1096,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) ...@@ -1101,8 +1096,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
vfree(ubi->vtbl); vfree(ubi->vtbl);
put_mtd_device(ubi->mtd); put_mtd_device(ubi->mtd);
ubi_debugging_exit_dev(ubi); ubi_debugging_exit_dev(ubi);
vfree(ubi->peb_buf1); vfree(ubi->peb_buf);
vfree(ubi->peb_buf2);
ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num); ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
put_device(&ubi->dev); put_device(&ubi->dev);
return 0; return 0;
......
...@@ -529,18 +529,18 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, ...@@ -529,18 +529,18 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
data_size = offset + len; data_size = offset + len;
mutex_lock(&ubi->buf_mutex); 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 */ /* Read everything before the area where the write failure happened */
if (offset > 0) { 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) if (err && err != UBI_IO_BITFLIPS)
goto out_unlock; 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) { if (err) {
mutex_unlock(&ubi->buf_mutex); mutex_unlock(&ubi->buf_mutex);
goto write_error; goto write_error;
...@@ -979,7 +979,7 @@ static int is_error_sane(int err) ...@@ -979,7 +979,7 @@ static int is_error_sane(int err)
* physical eraseblock @to. The @vid_hdr buffer may be changed by this * physical eraseblock @to. The @vid_hdr buffer may be changed by this
* function. Returns: * function. Returns:
* o %0 in case of success; * 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. * o a negative error code in case of failure.
*/ */
int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, 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, ...@@ -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 * 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 * with some other functions - we lock the buffer by taking the
* @ubi->buf_mutex. * @ubi->buf_mutex.
*/ */
mutex_lock(&ubi->buf_mutex); mutex_lock(&ubi->buf_mutex);
dbg_wl("read %d bytes of data", aldata_size); 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) { if (err && err != UBI_IO_BITFLIPS) {
ubi_warn("error %d while reading data from PEB %d", ubi_warn("error %d while reading data from PEB %d",
err, from); err, from);
...@@ -1079,10 +1079,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, ...@@ -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) if (vid_hdr->vol_type == UBI_VID_DYNAMIC)
aldata_size = data_size = 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(); cond_resched();
crc = crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size); crc = crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size);
cond_resched(); cond_resched();
/* /*
...@@ -1116,12 +1116,12 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, ...@@ -1116,12 +1116,12 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
if (is_error_sane(err)) if (is_error_sane(err))
err = MOVE_TARGET_RD_ERR; err = MOVE_TARGET_RD_ERR;
} else } else
err = MOVE_CANCEL_BITFLIPS; err = MOVE_TARGET_BITFLIPS;
goto out_unlock_buf; goto out_unlock_buf;
} }
if (data_size > 0) { 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) {
if (err == -EIO) if (err == -EIO)
err = MOVE_TARGET_WR_ERR; err = MOVE_TARGET_WR_ERR;
...@@ -1134,8 +1134,8 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, ...@@ -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 * We've written the data and are going to read it back to make
* sure it was written correctly. * sure it was written correctly.
*/ */
memset(ubi->peb_buf, 0xFF, aldata_size);
err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size); err = ubi_io_read_data(ubi, ubi->peb_buf, to, 0, aldata_size);
if (err) { if (err) {
if (err != UBI_IO_BITFLIPS) { if (err != UBI_IO_BITFLIPS) {
ubi_warn("error %d while reading data back " 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, ...@@ -1143,13 +1143,13 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
if (is_error_sane(err)) if (is_error_sane(err))
err = MOVE_TARGET_RD_ERR; err = MOVE_TARGET_RD_ERR;
} else } else
err = MOVE_CANCEL_BITFLIPS; err = MOVE_TARGET_BITFLIPS;
goto out_unlock_buf; goto out_unlock_buf;
} }
cond_resched(); 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 " ubi_warn("read data back from PEB %d and it is "
"different", to); "different", to);
err = -EINVAL; err = -EINVAL;
......
...@@ -431,11 +431,11 @@ static int torture_peb(struct ubi_device *ubi, int pnum) ...@@ -431,11 +431,11 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
goto out; goto out;
/* Make sure the PEB contains only 0xFF bytes */ /* 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) if (err)
goto out; 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) { if (err == 0) {
ubi_err("erased PEB %d, but a non-0xFF byte found", ubi_err("erased PEB %d, but a non-0xFF byte found",
pnum); pnum);
...@@ -444,17 +444,17 @@ static int torture_peb(struct ubi_device *ubi, int pnum) ...@@ -444,17 +444,17 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
} }
/* Write a pattern and check it */ /* Write a pattern and check it */
memset(ubi->peb_buf1, patterns[i], ubi->peb_size); memset(ubi->peb_buf, patterns[i], ubi->peb_size);
err = ubi_io_write(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size); err = ubi_io_write(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size);
if (err) if (err)
goto out; goto out;
memset(ubi->peb_buf1, ~patterns[i], ubi->peb_size); memset(ubi->peb_buf, ~patterns[i], ubi->peb_size);
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) if (err)
goto out; goto out;
err = ubi_check_pattern(ubi->peb_buf1, patterns[i], err = ubi_check_pattern(ubi->peb_buf, patterns[i],
ubi->peb_size); ubi->peb_size);
if (err == 0) { if (err == 0) {
ubi_err("pattern %x checking failed for PEB %d", 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, ...@@ -789,9 +789,9 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
int err; int err;
mutex_lock(&ubi->buf_mutex); 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); ubi->leb_size);
if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) { 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, ...@@ -808,7 +808,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
if (err) if (err)
goto out_unlock; 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; goto out_unlock;
ubi_err("PEB %d contains corrupted VID header, and the data does not " 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, ...@@ -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", dbg_msg("hexdump of PEB %d offset %d, length %d",
pnum, ubi->leb_start, ubi->leb_size); pnum, ubi->leb_start, ubi->leb_size);
ubi_dbg_print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, 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; err = 1;
out_unlock: out_unlock:
...@@ -1174,7 +1174,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) ...@@ -1174,7 +1174,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
if (!ech) if (!ech)
goto out_slab; goto out_si;
vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vidh) if (!vidh)
...@@ -1235,8 +1235,6 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) ...@@ -1235,8 +1235,6 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
ubi_free_vid_hdr(ubi, vidh); ubi_free_vid_hdr(ubi, vidh);
out_ech: out_ech:
kfree(ech); kfree(ech);
out_slab:
kmem_cache_destroy(si->scan_leb_slab);
out_si: out_si:
ubi_scan_destroy_si(si); ubi_scan_destroy_si(si);
return ERR_PTR(err); return ERR_PTR(err);
...@@ -1325,7 +1323,9 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si) ...@@ -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); kfree(si);
} }
......
...@@ -118,7 +118,7 @@ enum { ...@@ -118,7 +118,7 @@ enum {
* PEB * PEB
* MOVE_TARGET_WR_ERR: canceled because there was a write error to the target * MOVE_TARGET_WR_ERR: canceled because there was a write error to the target
* PEB * 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 * target PEB
* MOVE_RETRY: retry scrubbing the PEB * MOVE_RETRY: retry scrubbing the PEB
*/ */
...@@ -127,7 +127,7 @@ enum { ...@@ -127,7 +127,7 @@ enum {
MOVE_SOURCE_RD_ERR, MOVE_SOURCE_RD_ERR,
MOVE_TARGET_RD_ERR, MOVE_TARGET_RD_ERR,
MOVE_TARGET_WR_ERR, MOVE_TARGET_WR_ERR,
MOVE_CANCEL_BITFLIPS, MOVE_TARGET_BITFLIPS,
MOVE_RETRY, MOVE_RETRY,
}; };
...@@ -387,9 +387,8 @@ struct ubi_wl_entry; ...@@ -387,9 +387,8 @@ struct ubi_wl_entry;
* time (MTD write buffer size) * time (MTD write buffer size)
* @mtd: MTD device descriptor * @mtd: MTD device descriptor
* *
* @peb_buf1: a buffer of PEB size used for different purposes * @peb_buf: a buffer of PEB size used for different purposes
* @peb_buf2: another buffer of PEB size used for different purposes * @buf_mutex: protects @peb_buf
* @buf_mutex: protects @peb_buf1 and @peb_buf2
* @ckvol_mutex: serializes static volume checking when opening * @ckvol_mutex: serializes static volume checking when opening
* *
* @dbg: debugging information for this UBI device * @dbg: debugging information for this UBI device
...@@ -471,8 +470,7 @@ struct ubi_device { ...@@ -471,8 +470,7 @@ struct ubi_device {
int max_write_size; int max_write_size;
struct mtd_info *mtd; struct mtd_info *mtd;
void *peb_buf1; void *peb_buf;
void *peb_buf2;
struct mutex buf_mutex; struct mutex buf_mutex;
struct mutex ckvol_mutex; struct mutex ckvol_mutex;
......
...@@ -350,18 +350,19 @@ static void prot_queue_add(struct ubi_device *ubi, struct ubi_wl_entry *e) ...@@ -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. * find_wl_entry - find wear-leveling entry closest to certain erase counter.
* @root: the RB-tree where to look for * @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 * 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 rb_node *p;
struct ubi_wl_entry *e; struct ubi_wl_entry *e;
int max;
e = rb_entry(rb_first(root), struct ubi_wl_entry, u.rb); e = rb_entry(rb_first(root), struct ubi_wl_entry, u.rb);
max += e->ec; max = e->ec + diff;
p = root->rb_node; p = root->rb_node;
while (p) { while (p) {
...@@ -389,7 +390,7 @@ static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int max) ...@@ -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 ubi_wl_get_peb(struct ubi_device *ubi, int dtype)
{ {
int err, medium_ec; int err;
struct ubi_wl_entry *e, *first, *last; struct ubi_wl_entry *e, *first, *last;
ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM || ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM ||
...@@ -427,7 +428,7 @@ int ubi_wl_get_peb(struct ubi_device *ubi, int dtype) ...@@ -427,7 +428,7 @@ int ubi_wl_get_peb(struct ubi_device *ubi, int dtype)
* For unknown data we pick a physical eraseblock with medium * For unknown data we pick a physical eraseblock with medium
* erase counter. But we by no means can pick a physical * erase counter. But we by no means can pick a physical
* eraseblock with erase counter greater or equivalent than the * 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, first = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry,
u.rb); u.rb);
...@@ -436,10 +437,8 @@ int ubi_wl_get_peb(struct ubi_device *ubi, int dtype) ...@@ -436,10 +437,8 @@ int ubi_wl_get_peb(struct ubi_device *ubi, int dtype)
if (last->ec - first->ec < WL_FREE_MAX_DIFF) if (last->ec - first->ec < WL_FREE_MAX_DIFF)
e = rb_entry(ubi->free.rb_node, e = rb_entry(ubi->free.rb_node,
struct ubi_wl_entry, u.rb); struct ubi_wl_entry, u.rb);
else { else
medium_ec = (first->ec + WL_FREE_MAX_DIFF)/2; e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF/2);
e = find_wl_entry(&ubi->free, medium_ec);
}
break; break;
case UBI_SHORTTERM: case UBI_SHORTTERM:
/* /*
...@@ -799,7 +798,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, ...@@ -799,7 +798,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
scrubbing = 1; scrubbing = 1;
goto out_not_moved; 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) { err == MOVE_TARGET_RD_ERR) {
/* /*
* Target PEB had bit-flips or write error - torture it. * Target PEB had bit-flips or write error - torture it.
......
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