From a29852be492d61001d86c6ebf5fff9b93d7b4be9 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Mon, 30 Jan 2012 18:20:13 +0100 Subject: UBI: fix error handling in ubi_scan() Two bad things can happen in ubi_scan(): 1. If kmem_cache_create() fails we jump to out_si and call ubi_scan_destroy_si() which calls kmem_cache_destroy(). But si->scan_leb_slab is NULL. 2. If process_eb() fails we jump to out_vidh, call kmem_cache_destroy() and ubi_scan_destroy_si() which calls again kmem_cache_destroy(). Signed-off-by: Richard Weinberger Signed-off-by: Artem Bityutskiy Cc: stable@kernel.org diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index 0cb17d9..b99318e 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -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); } -- cgit v0.10.2 From add8287e3fa2160229117c9e1b7c9ca8cb661423 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 7 Mar 2012 18:56:29 +0200 Subject: UBI: fix documentation and improve readability The "max" parameter of 'find_wl_entry()' was documented incorrectly and it actually means the maximum possible difference from the smallest erase counter. Rename it to "diff" instead, and amend the documentation. Reported-by: Shmulik Ladkani Signed-off-by: Artem Bityutskiy Reviewed-by: Shmulik Ladkani diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 0696e36..8616f52 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -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) { -- cgit v0.10.2 From 7eb3aa65853e1b223bfc786b023b702018cb76c0 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 7 Mar 2012 19:08:36 +0200 Subject: UBI: fix eraseblock picking criteria The 'find_wl_entry()' function expects the maximum difference as the second argument, not the maximum absolute value. So the "unknown" eraseblock picking was incorrect, as Shmulik Ladkani spotted. This patch fixes the issue. Reported-by: Shmulik Ladkani Signed-off-by: Artem Bityutskiy Reviewed-by: Shmulik Ladkani Cc: stable@kernel.org diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 8616f52..512eab0 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -390,7 +390,7 @@ static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int diff) */ 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 || @@ -428,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); @@ -437,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: /* -- cgit v0.10.2 From 43b043e78b876ce27034f167897b57fd2556ad29 Mon Sep 17 00:00:00 2001 From: Josselin Costanzi Date: Wed, 22 Feb 2012 16:37:05 +0100 Subject: UBI: reduce memory consumption Remove the pre-allocated 'peb_buf2' buffer because we do not really need it. The only reason UBI has it is to check that the data were written correctly. But we do not have to have 2 buffers for this and waste RAM - we can just compare CRC checksums instead. This reduces UBI memory consumption. Artem bityutskiy: massaged the patch and commit message Signed-off-by: Josselin Costanzi Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 115749f..6e0806b 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -949,10 +949,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) if (!ubi->peb_buf1) goto out_free; - ubi->peb_buf2 = vmalloc(ubi->peb_size); - if (!ubi->peb_buf2) - goto out_free; - err = ubi_debugging_init_dev(ubi); if (err) goto out_free; @@ -1030,7 +1026,6 @@ out_debugging: ubi_debugging_exit_dev(ubi); out_free: vfree(ubi->peb_buf1); - vfree(ubi->peb_buf2); if (ref) put_device(&ubi->dev); else @@ -1102,7 +1097,6 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) put_mtd_device(ubi->mtd); ubi_debugging_exit_dev(ubi); vfree(ubi->peb_buf1); - vfree(ubi->peb_buf2); ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num); put_device(&ubi->dev); return 0; diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index cd26da8..f548af3 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -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_buf1, 0xFF, aldata_size); + err = ubi_io_read_data(ubi, ubi->peb_buf1, to, 0, aldata_size); if (err) { if (err != UBI_IO_BITFLIPS) { ubi_warn("error %d while reading data back " @@ -1149,7 +1149,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, cond_resched(); - if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) { + if (crc != crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size)) { ubi_warn("read data back from PEB %d and it is " "different", to); err = -EINVAL; diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index d51d75d..cb93ad9 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -388,8 +388,7 @@ struct ubi_wl_entry; * @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 + * @buf_mutex: protects @peb_buf1 * @ckvol_mutex: serializes static volume checking when opening * * @dbg: debugging information for this UBI device @@ -472,7 +471,6 @@ struct ubi_device { struct mtd_info *mtd; void *peb_buf1; - void *peb_buf2; struct mutex buf_mutex; struct mutex ckvol_mutex; -- cgit v0.10.2 From 0ca39d74de8b269fb61eac11b75bd6c3fc887c28 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 8 Mar 2012 15:29:37 +0200 Subject: UBI: rename peb_buf1 to peb_buf Now we have only one buffer so let's rename it to just 'peb_buf1'. Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 6e0806b..0fde9fc 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -945,8 +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) + ubi->peb_buf = vmalloc(ubi->peb_size); + if (!ubi->peb_buf) goto out_free; err = ubi_debugging_init_dev(ubi); @@ -1025,7 +1025,7 @@ out_detach: out_debugging: ubi_debugging_exit_dev(ubi); out_free: - vfree(ubi->peb_buf1); + vfree(ubi->peb_buf); if (ref) put_device(&ubi->dev); else @@ -1096,7 +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_buf); ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num); put_device(&ubi->dev); return 0; diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index f548af3..63edee0 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -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; @@ -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(); /* @@ -1121,7 +1121,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, } 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. */ - memset(ubi->peb_buf1, 0xFF, aldata_size); - err = ubi_io_read_data(ubi, ubi->peb_buf1, 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 " @@ -1149,7 +1149,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, cond_resched(); - if (crc != crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_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; diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 5cde4e5..43f1a00 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -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", diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index b99318e..12c43b4 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -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: diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index cb93ad9..bd6120c 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -387,8 +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 - * @buf_mutex: protects @peb_buf1 + * @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 @@ -470,7 +470,7 @@ struct ubi_device { int max_write_size; struct mtd_info *mtd; - void *peb_buf1; + void *peb_buf; struct mutex buf_mutex; struct mutex ckvol_mutex; -- cgit v0.10.2 From cc831464f839dc2559f896b96d13eaa0366282b0 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 9 Mar 2012 10:31:18 +0200 Subject: UBI: rename MOVE_CANCEL_BITFLIPS to MOVE_TARGET_BITFLIPS While looking at a problem reported by UBI around the PEB moving area I noticed that the 'MOVE_CANCEL_BITFLIPS' is a bit inconsistent name and 'MOVE_TARGET_BITFLIPS' better - let's rename it. Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 63edee0..2455d62 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -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, @@ -1116,7 +1116,7 @@ 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; } @@ -1143,7 +1143,7 @@ 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; } diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index bd6120c..b162790 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -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, }; diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 512eab0..7c1a9bf 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -798,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. -- cgit v0.10.2