diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-14 09:02:40 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-14 09:02:40 -0700 |
commit | f248488b397d52717f6683e2e53200aa687ffc89 (patch) | |
tree | 649f4700d1d2a881d12ad77ba536ae7691395def /drivers | |
parent | cbe619b162121577bc1e8ed4384dfb85f19e43d8 (diff) | |
parent | e3d18658d4f28e4783e1bb1c41e9134c9e5db0a9 (diff) |
Merge git://git.infradead.org/mtd-2.6
* git://git.infradead.org/mtd-2.6:
[MTD] fix mtdconcat for subpage-write NAND
[MTD] [OneNAND] Avoid deadlock in erase callback; release chip lock first.
[MTD] [OneNAND] Return only negative error codes
[MTD] [OneNAND] Synchronize block locking operations
UBI: return correct error code
UBI: remove useless inlines
UBI: fix atomic LEB change problems
UBI: use byte hexdump
UBI: do not use vmalloc on I/O path
UBI: allocate memory with GFP_NOFS
UBI: use linux print_hex_dump(), not home-grown one
UBI: don't use array index before testing if it is negative
UBI: add more prints
UBI: fix sparse warnings
UBI: fix leak in ubi_scan_erase_peb
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/mtdconcat.c | 1 | ||||
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 29 | ||||
-rw-r--r-- | drivers/mtd/ubi/build.c | 28 | ||||
-rw-r--r-- | drivers/mtd/ubi/debug.c | 37 | ||||
-rw-r--r-- | drivers/mtd/ubi/debug.h | 2 | ||||
-rw-r--r-- | drivers/mtd/ubi/eba.c | 131 | ||||
-rw-r--r-- | drivers/mtd/ubi/io.c | 75 | ||||
-rw-r--r-- | drivers/mtd/ubi/kapi.c | 9 | ||||
-rw-r--r-- | drivers/mtd/ubi/scan.c | 45 | ||||
-rw-r--r-- | drivers/mtd/ubi/scan.h | 8 | ||||
-rw-r--r-- | drivers/mtd/ubi/ubi.h | 42 | ||||
-rw-r--r-- | drivers/mtd/ubi/vmt.c | 70 | ||||
-rw-r--r-- | drivers/mtd/ubi/vtbl.c | 8 | ||||
-rw-r--r-- | drivers/mtd/ubi/wl.c | 136 |
14 files changed, 295 insertions, 326 deletions
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 96be7ef62f3..d563dcd4b26 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -726,6 +726,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.size = subdev[0]->size; concat->mtd.erasesize = subdev[0]->erasesize; concat->mtd.writesize = subdev[0]->writesize; + concat->mtd.subpage_sft = subdev[0]->subpage_sft; concat->mtd.oobsize = subdev[0]->oobsize; concat->mtd.oobavail = subdev[0]->oobavail; if (subdev[0]->writev) diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index b2c40f67db8..dd283556909 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -327,7 +327,7 @@ static int onenand_wait(struct mtd_info *mtd, int state) printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", ctrl); if (ctrl & ONENAND_CTRL_LOCK) printk(KERN_ERR "onenand_wait: it's locked error.\n"); - return ctrl; + return -EIO; } if (interrupt & ONENAND_INT_READ) { @@ -336,7 +336,7 @@ static int onenand_wait(struct mtd_info *mtd, int state) if (ecc & ONENAND_ECC_2BIT_ALL) { printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc); mtd->ecc_stats.failed++; - return ecc; + return -EBADMSG; } else if (ecc & ONENAND_ECC_1BIT_ALL) { printk(KERN_INFO "onenand_wait: correctable ECC error = 0x%04x\n", ecc); mtd->ecc_stats.corrected++; @@ -1711,13 +1711,14 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) erase_exit: ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; - /* Do call back function */ - if (!ret) - mtd_erase_callback(instr); /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); + /* Do call back function */ + if (!ret) + mtd_erase_callback(instr); + return ret; } @@ -1904,7 +1905,12 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int */ static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len) { - return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK); + int ret; + + onenand_get_device(mtd, FL_LOCKING); + ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK); + onenand_release_device(mtd); + return ret; } /** @@ -1917,7 +1923,12 @@ static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len) */ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) { - return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); + int ret; + + onenand_get_device(mtd, FL_LOCKING); + ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); + onenand_release_device(mtd); + return ret; } /** @@ -1979,7 +1990,7 @@ static int onenand_unlock_all(struct mtd_info *mtd) loff_t ofs = this->chipsize >> 1; size_t len = mtd->erasesize; - onenand_unlock(mtd, ofs, len); + onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); } onenand_check_lock_status(this); @@ -1987,7 +1998,7 @@ static int onenand_unlock_all(struct mtd_info *mtd) return 0; } - onenand_unlock(mtd, 0x0, this->chipsize); + onenand_do_lock_cmd(mtd, 0x0, this->chipsize, ONENAND_CMD_UNLOCK); return 0; } diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 1cb22bfae75..023653977a1 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -565,7 +565,7 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, } ubi = ubi_devices[ubi_devices_cnt] = kzalloc(sizeof(struct ubi_device), - GFP_KERNEL); + GFP_KERNEL); if (!ubi) { err = -ENOMEM; goto out_mtd; @@ -583,6 +583,22 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, if (err) goto out_free; + mutex_init(&ubi->buf_mutex); + 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) + goto out_free; + +#ifdef CONFIG_MTD_UBI_DEBUG + mutex_init(&ubi->dbg_buf_mutex); + ubi->dbg_peb_buf = vmalloc(ubi->peb_size); + if (!ubi->dbg_peb_buf) + goto out_free; +#endif + err = attach_by_scanning(ubi); if (err) { dbg_err("failed to attach by scanning, error %d", err); @@ -630,6 +646,11 @@ out_detach: ubi_wl_close(ubi); vfree(ubi->vtbl); out_free: + vfree(ubi->peb_buf1); + vfree(ubi->peb_buf2); +#ifdef CONFIG_MTD_UBI_DEBUG + vfree(ubi->dbg_peb_buf); +#endif kfree(ubi); out_mtd: put_mtd_device(mtd); @@ -651,6 +672,11 @@ static void detach_mtd_dev(struct ubi_device *ubi) ubi_wl_close(ubi); vfree(ubi->vtbl); put_mtd_device(ubi->mtd); + vfree(ubi->peb_buf1); + vfree(ubi->peb_buf2); +#ifdef CONFIG_MTD_UBI_DEBUG + vfree(ubi->dbg_peb_buf); +#endif kfree(ubi_devices[ubi_num]); ubi_devices[ubi_num] = NULL; ubi_devices_cnt -= 1; diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index 310341e5cd4..56956ec2845 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -42,7 +42,8 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) dbg_msg("data_offset %d", be32_to_cpu(ec_hdr->data_offset)); dbg_msg("hdr_crc %#08x", be32_to_cpu(ec_hdr->hdr_crc)); dbg_msg("erase counter header hexdump:"); - ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, + ec_hdr, UBI_EC_HDR_SIZE, 1); } /** @@ -187,38 +188,4 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req) dbg_msg("the 1st 16 characters of the name: %s", nm); } -#define BYTES_PER_LINE 32 - -/** - * ubi_dbg_hexdump - dump a buffer. - * @ptr: the buffer to dump - * @size: buffer size which must be multiple of 4 bytes - */ -void ubi_dbg_hexdump(const void *ptr, int size) -{ - int i, k = 0, rows, columns; - const uint8_t *p = ptr; - - size = ALIGN(size, 4); - rows = size/BYTES_PER_LINE + size % BYTES_PER_LINE; - for (i = 0; i < rows; i++) { - int j; - - cond_resched(); - columns = min(size - k, BYTES_PER_LINE) / 4; - if (columns == 0) - break; - printk(KERN_DEBUG "%5d: ", i * BYTES_PER_LINE); - for (j = 0; j < columns; j++) { - int n, N; - - N = size - k > 4 ? 4 : size - k; - for (n = 0; n < N; n++) - printk("%02x", p[k++]); - printk(" "); - } - printk("\n"); - } -} - #endif /* CONFIG_MTD_UBI_DEBUG_MSG */ diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index ff8f39548cd..467722eb618 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -59,7 +59,6 @@ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx); void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv); void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type); void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req); -void ubi_dbg_hexdump(const void *buf, int size); #else @@ -72,7 +71,6 @@ void ubi_dbg_hexdump(const void *buf, int size); #define ubi_dbg_dump_sv(sv) ({}) #define ubi_dbg_dump_seb(seb, type) ({}) #define ubi_dbg_dump_mkvol_req(req) ({}) -#define ubi_dbg_hexdump(buf, size) ({}) #endif /* CONFIG_MTD_UBI_DEBUG_MSG */ diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 7c5e29eaf11..1297732f4db 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -46,6 +46,9 @@ #include <linux/err.h> #include "ubi.h" +/* Number of physical eraseblocks reserved for atomic LEB change operation */ +#define EBA_RESERVED_PEBS 1 + /** * struct ltree_entry - an entry in the lock tree. * @rb: links RB-tree nodes @@ -157,7 +160,7 @@ static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id, { struct ltree_entry *le, *le1, *le_free; - le = kmem_cache_alloc(ltree_slab, GFP_KERNEL); + le = kmem_cache_alloc(ltree_slab, GFP_NOFS); if (!le) return ERR_PTR(-ENOMEM); @@ -397,7 +400,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, retry: if (check) { - vid_hdr = ubi_zalloc_vid_hdr(ubi); + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); if (!vid_hdr) { err = -ENOMEM; goto out_unlock; @@ -495,16 +498,18 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0; struct ubi_volume *vol = ubi->volumes[idx]; struct ubi_vid_hdr *vid_hdr; - unsigned char *new_buf; - vid_hdr = ubi_zalloc_vid_hdr(ubi); + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); if (!vid_hdr) { return -ENOMEM; } + mutex_lock(&ubi->buf_mutex); + retry: new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN); if (new_pnum < 0) { + mutex_unlock(&ubi->buf_mutex); ubi_free_vid_hdr(ubi, vid_hdr); return new_pnum; } @@ -524,31 +529,22 @@ retry: goto write_error; data_size = offset + len; - new_buf = vmalloc(data_size); - if (!new_buf) { - err = -ENOMEM; - goto out_put; - } - memset(new_buf + offset, 0xFF, len); + memset(ubi->peb_buf1 + offset, 0xFF, len); /* Read everything before the area where the write failure happened */ if (offset > 0) { - err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset); - if (err && err != UBI_IO_BITFLIPS) { - vfree(new_buf); + err = ubi_io_read_data(ubi, ubi->peb_buf1, pnum, 0, offset); + if (err && err != UBI_IO_BITFLIPS) goto out_put; - } } - memcpy(new_buf + offset, buf, len); + memcpy(ubi->peb_buf1 + offset, buf, len); - err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size); - if (err) { - vfree(new_buf); + err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size); + if (err) goto write_error; - } - vfree(new_buf); + mutex_unlock(&ubi->buf_mutex); ubi_free_vid_hdr(ubi, vid_hdr); vol->eba_tbl[lnum] = new_pnum; @@ -558,6 +554,7 @@ retry: return 0; out_put: + mutex_unlock(&ubi->buf_mutex); ubi_wl_put_peb(ubi, new_pnum, 1); ubi_free_vid_hdr(ubi, vid_hdr); return err; @@ -570,6 +567,7 @@ write_error: ubi_warn("failed to write to PEB %d", new_pnum); ubi_wl_put_peb(ubi, new_pnum, 1); if (++tries > UBI_IO_RETRIES) { + mutex_unlock(&ubi->buf_mutex); ubi_free_vid_hdr(ubi, vid_hdr); return err; } @@ -627,7 +625,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum, * The logical eraseblock is not mapped. We have to get a free physical * eraseblock and write the volume identifier header there first. */ - vid_hdr = ubi_zalloc_vid_hdr(ubi); + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); if (!vid_hdr) { leb_write_unlock(ubi, vol_id, lnum); return -ENOMEM; @@ -738,7 +736,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum, else ubi_assert(len % ubi->min_io_size == 0); - vid_hdr = ubi_zalloc_vid_hdr(ubi); + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); if (!vid_hdr) return -ENOMEM; @@ -832,6 +830,9 @@ write_error: * data, which has to be aligned. This function guarantees that in case of an * unclean reboot the old contents is preserved. Returns zero in case of * success and a negative error code in case of failure. + * + * UBI reserves one LEB for the "atomic LEB change" operation, so only one + * LEB change may be done at a time. This is ensured by @ubi->alc_mutex. */ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, const void *buf, int len, int dtype) @@ -844,15 +845,14 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, if (ubi->ro_mode) return -EROFS; - vid_hdr = ubi_zalloc_vid_hdr(ubi); + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); if (!vid_hdr) return -ENOMEM; + mutex_lock(&ubi->alc_mutex); err = leb_write_lock(ubi, vol_id, lnum); - if (err) { - ubi_free_vid_hdr(ubi, vid_hdr); - return err; - } + if (err) + goto out_mutex; vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); vid_hdr->vol_id = cpu_to_be32(vol_id); @@ -869,9 +869,8 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, retry: pnum = ubi_wl_get_peb(ubi, dtype); if (pnum < 0) { - ubi_free_vid_hdr(ubi, vid_hdr); - leb_write_unlock(ubi, vol_id, lnum); - return pnum; + err = pnum; + goto out_leb_unlock; } dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d", @@ -893,17 +892,18 @@ retry: if (vol->eba_tbl[lnum] >= 0) { err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1); - if (err) { - ubi_free_vid_hdr(ubi, vid_hdr); - leb_write_unlock(ubi, vol_id, lnum); - return err; - } + if (err) + goto out_leb_unlock; } vol->eba_tbl[lnum] = pnum; + +out_leb_unlock: leb_write_unlock(ubi, vol_id, lnum); +out_mutex: + mutex_unlock(&ubi->alc_mutex); ubi_free_vid_hdr(ubi, vid_hdr); - return 0; + return err; write_error: if (err != -EIO || !ubi->bad_allowed) { @@ -913,17 +913,13 @@ write_error: * mode just in case. */ ubi_ro_mode(ubi); - leb_write_unlock(ubi, vol_id, lnum); - ubi_free_vid_hdr(ubi, vid_hdr); - return err; + goto out_leb_unlock; } err = ubi_wl_put_peb(ubi, pnum, 1); if (err || ++tries > UBI_IO_RETRIES) { ubi_ro_mode(ubi); - leb_write_unlock(ubi, vol_id, lnum); - ubi_free_vid_hdr(ubi, vid_hdr); - return err; + goto out_leb_unlock; } vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); @@ -965,7 +961,6 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, int err, vol_id, lnum, data_size, aldata_size, pnum, idx; struct ubi_volume *vol; uint32_t crc; - void *buf, *buf1 = NULL; vol_id = be32_to_cpu(vid_hdr->vol_id); lnum = be32_to_cpu(vid_hdr->lnum); @@ -979,19 +974,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, data_size = aldata_size = ubi->leb_size - be32_to_cpu(vid_hdr->data_pad); - buf = vmalloc(aldata_size); - if (!buf) - return -ENOMEM; - /* * We do not want anybody to write to this logical eraseblock while we * are moving it, so we lock it. */ err = leb_write_lock(ubi, vol_id, lnum); - if (err) { - vfree(buf); + if (err) return err; - } + + mutex_lock(&ubi->buf_mutex); /* * But the logical eraseblock might have been put by this time. @@ -1023,7 +1014,7 @@ 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 */ dbg_eba("read %d bytes of data", aldata_size); - err = ubi_io_read_data(ubi, buf, from, 0, aldata_size); + err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size); if (err && err != UBI_IO_BITFLIPS) { ubi_warn("error %d while reading data from PEB %d", err, from); @@ -1042,10 +1033,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, buf, data_size); + ubi_calc_data_len(ubi, ubi->peb_buf1, data_size); cond_resched(); - crc = crc32(UBI_CRC32_INIT, buf, data_size); + crc = crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size); cond_resched(); /* @@ -1076,23 +1067,18 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, } if (data_size > 0) { - err = ubi_io_write_data(ubi, buf, to, 0, aldata_size); + err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size); if (err) goto out_unlock; + cond_resched(); + /* * We've written the data and are going to read it back to make * sure it was written correctly. */ - buf1 = vmalloc(aldata_size); - if (!buf1) { - err = -ENOMEM; - goto out_unlock; - } - - cond_resched(); - err = ubi_io_read_data(ubi, buf1, to, 0, aldata_size); + err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size); if (err) { if (err != UBI_IO_BITFLIPS) ubi_warn("cannot read data back from PEB %d", @@ -1102,7 +1088,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, cond_resched(); - if (memcmp(buf, buf1, aldata_size)) { + if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) { ubi_warn("read data back from PEB %d - it is different", to); goto out_unlock; @@ -1112,16 +1098,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, ubi_assert(vol->eba_tbl[lnum] == from); vol->eba_tbl[lnum] = to; - leb_write_unlock(ubi, vol_id, lnum); - vfree(buf); - vfree(buf1); - - return 0; - out_unlock: + mutex_unlock(&ubi->buf_mutex); leb_write_unlock(ubi, vol_id, lnum); - vfree(buf); - vfree(buf1); return err; } @@ -1144,6 +1123,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) dbg_eba("initialize EBA unit"); spin_lock_init(&ubi->ltree_lock); + mutex_init(&ubi->alc_mutex); ubi->ltree = RB_ROOT; if (ubi_devices_cnt == 0) { @@ -1205,6 +1185,15 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) ubi->rsvd_pebs += ubi->beb_rsvd_pebs; } + if (ubi->avail_pebs < EBA_RESERVED_PEBS) { + ubi_err("no enough physical eraseblocks (%d, need %d)", + ubi->avail_pebs, EBA_RESERVED_PEBS); + err = -ENOSPC; + goto out_free; + } + ubi->avail_pebs -= EBA_RESERVED_PEBS; + ubi->rsvd_pebs += EBA_RESERVED_PEBS; + dbg_eba("EBA unit is initialized"); return 0; diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index b0d8f4cede9..7c304eec78b 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -98,8 +98,8 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum, static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum); static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum, const struct ubi_vid_hdr *vid_hdr); -static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum, - int offset, int len); +static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset, + int len); #else #define paranoid_check_not_bad(ubi, pnum) 0 #define paranoid_check_peb_ec_hdr(ubi, pnum) 0 @@ -202,8 +202,8 @@ retry: * Note, in case of an error, it is possible that something was still written * to the flash media, but may be some garbage. */ -int ubi_io_write(const struct ubi_device *ubi, const void *buf, int pnum, - int offset, int len) +int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, + int len) { int err; size_t written; @@ -285,7 +285,7 @@ static void erase_callback(struct erase_info *ei) * zero in case of success and a negative error code in case of failure. If * %-EIO is returned, the physical eraseblock most probably went bad. */ -static int do_sync_erase(const struct ubi_device *ubi, int pnum) +static int do_sync_erase(struct ubi_device *ubi, int pnum) { int err, retries = 0; struct erase_info ei; @@ -377,29 +377,25 @@ static uint8_t patterns[] = {0xa5, 0x5a, 0x0}; * test, a positive number of erase operations done if the test was * successfully passed, and other negative error codes in case of other errors. */ -static int torture_peb(const struct ubi_device *ubi, int pnum) +static int torture_peb(struct ubi_device *ubi, int pnum) { - void *buf; int err, i, patt_count; - buf = vmalloc(ubi->peb_size); - if (!buf) - return -ENOMEM; - patt_count = ARRAY_SIZE(patterns); ubi_assert(patt_count > 0); + mutex_lock(&ubi->buf_mutex); for (i = 0; i < patt_count; i++) { err = do_sync_erase(ubi, pnum); if (err) goto out; /* Make sure the PEB contains only 0xFF bytes */ - err = ubi_io_read(ubi, buf, pnum, 0, ubi->peb_size); + err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size); if (err) goto out; - err = check_pattern(buf, 0xFF, ubi->peb_size); + err = check_pattern(ubi->peb_buf1, 0xFF, ubi->peb_size); if (err == 0) { ubi_err("erased PEB %d, but a non-0xFF byte found", pnum); @@ -408,17 +404,17 @@ static int torture_peb(const struct ubi_device *ubi, int pnum) } /* Write a pattern and check it */ - memset(buf, patterns[i], ubi->peb_size); - err = ubi_io_write(ubi, buf, pnum, 0, ubi->peb_size); + memset(ubi->peb_buf1, patterns[i], ubi->peb_size); + err = ubi_io_write(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size); if (err) goto out; - memset(buf, ~patterns[i], ubi->peb_size); - err = ubi_io_read(ubi, buf, pnum, 0, ubi->peb_size); + memset(ubi->peb_buf1, ~patterns[i], ubi->peb_size); + err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size); if (err) goto out; - err = check_pattern(buf, patterns[i], ubi->peb_size); + err = check_pattern(ubi->peb_buf1, patterns[i], ubi->peb_size); if (err == 0) { ubi_err("pattern %x checking failed for PEB %d", patterns[i], pnum); @@ -430,14 +426,17 @@ static int torture_peb(const struct ubi_device *ubi, int pnum) err = patt_count; out: - if (err == UBI_IO_BITFLIPS || err == -EBADMSG) + mutex_unlock(&ubi->buf_mutex); + if (err == UBI_IO_BITFLIPS || err == -EBADMSG) { /* * If a bit-flip or data integrity error was detected, the test * has not passed because it happened on a freshly erased * physical eraseblock which means something is wrong with it. */ + ubi_err("read problems on freshly erased PEB %d, must be bad", + pnum); err = -EIO; - vfree(buf); + } return err; } @@ -457,7 +456,7 @@ out: * codes in case of other errors. Note, %-EIO means that the physical * eraseblock is bad. */ -int ubi_io_sync_erase(const struct ubi_device *ubi, int pnum, int torture) +int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture) { int err, ret = 0; @@ -614,7 +613,7 @@ bad: * o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty; * o a negative error code in case of failure. */ -int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum, +int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, struct ubi_ec_hdr *ec_hdr, int verbose) { int err, read_err = 0; @@ -720,7 +719,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum, * case of failure. If %-EIO is returned, the physical eraseblock most probably * went bad. */ -int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum, +int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum, struct ubi_ec_hdr *ec_hdr) { int err; @@ -886,7 +885,7 @@ bad: * header there); * o a negative error code in case of failure. */ -int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum, +int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, struct ubi_vid_hdr *vid_hdr, int verbose) { int err, read_err = 0; @@ -993,7 +992,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum, * case of failure. If %-EIO is returned, the physical eraseblock probably went * bad. */ -int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum, +int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, struct ubi_vid_hdr *vid_hdr) { int err; @@ -1096,7 +1095,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum) uint32_t crc, hdr_crc; struct ubi_ec_hdr *ec_hdr; - ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); + ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS); if (!ec_hdr) return -ENOMEM; @@ -1176,7 +1175,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) struct ubi_vid_hdr *vid_hdr; void *p; - vid_hdr = ubi_zalloc_vid_hdr(ubi); + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); if (!vid_hdr) return -ENOMEM; @@ -1216,44 +1215,40 @@ exit: * @offset of the physical eraseblock @pnum, %1 if not, and a negative error * code if an error occurred. */ -static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum, - int offset, int len) +static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset, + int len) { size_t read; int err; - void *buf; loff_t addr = (loff_t)pnum * ubi->peb_size + offset; - buf = vmalloc(len); - if (!buf) - return -ENOMEM; - memset(buf, 0, len); - - err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); + mutex_lock(&ubi->dbg_buf_mutex); + err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf); if (err && err != -EUCLEAN) { ubi_err("error %d while reading %d bytes from PEB %d:%d, " "read %zd bytes", err, len, pnum, offset, read); goto error; } - err = check_pattern(buf, 0xFF, len); + err = check_pattern(ubi->dbg_peb_buf, 0xFF, len); if (err == 0) { ubi_err("flash region at PEB %d:%d, length %d does not " "contain all 0xFF bytes", pnum, offset, len); goto fail; } + mutex_unlock(&ubi->dbg_buf_mutex); - vfree(buf); return 0; fail: ubi_err("paranoid check failed for PEB %d", pnum); dbg_msg("hex dump of the %d-%d region", offset, offset + len); - ubi_dbg_hexdump(buf, len); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, + ubi->dbg_peb_buf, len, 1); err = 1; error: ubi_dbg_dump_stack(); - vfree(buf); + mutex_unlock(&ubi->dbg_buf_mutex); return err; } diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index 4a458e83e4e..03c774f4154 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -99,16 +99,21 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) { int err; struct ubi_volume_desc *desc; - struct ubi_device *ubi = ubi_devices[ubi_num]; + struct ubi_device *ubi; struct ubi_volume *vol; dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode); err = -ENODEV; + if (ubi_num < 0) + return ERR_PTR(err); + + ubi = ubi_devices[ubi_num]; + if (!try_module_get(THIS_MODULE)) return ERR_PTR(err); - if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || !ubi) + if (ubi_num >= UBI_MAX_DEVICES || !ubi) goto out_put; err = -EINVAL; diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index 29c41eeb09f..c7b0afc9d28 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -45,8 +45,7 @@ #include "ubi.h" #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID -static int paranoid_check_si(const struct ubi_device *ubi, - struct ubi_scan_info *si); +static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si); #else #define paranoid_check_si(ubi, si) 0 #endif @@ -259,14 +258,13 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id, * o bit 2 is cleared: the older LEB is not corrupted; * o bit 2 is set: the older LEB is corrupted. */ -static int compare_lebs(const struct ubi_device *ubi, - const struct ubi_scan_leb *seb, int pnum, - const struct ubi_vid_hdr *vid_hdr) +static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb, + int pnum, const struct ubi_vid_hdr *vid_hdr) { void *buf; int len, err, second_is_newer, bitflips = 0, corrupted = 0; uint32_t data_crc, crc; - struct ubi_vid_hdr *vidh = NULL; + struct ubi_vid_hdr *vh = NULL; unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum); if (seb->sqnum == 0 && sqnum2 == 0) { @@ -323,11 +321,11 @@ static int compare_lebs(const struct ubi_device *ubi, } else { pnum = seb->pnum; - vidh = ubi_zalloc_vid_hdr(ubi); - if (!vidh) + vh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); + if (!vh) return -ENOMEM; - err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0); + err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0); if (err) { if (err == UBI_IO_BITFLIPS) bitflips = 1; @@ -341,7 +339,7 @@ static int compare_lebs(const struct ubi_device *ubi, } } - if (!vidh->copy_flag) { + if (!vh->copy_flag) { /* It is not a copy, so it is newer */ dbg_bld("first PEB %d is newer, copy_flag is unset", pnum); @@ -349,7 +347,7 @@ static int compare_lebs(const struct ubi_device *ubi, goto out_free_vidh; } - vid_hdr = vidh; + vid_hdr = vh; } /* Read the data of the copy and check the CRC */ @@ -379,7 +377,7 @@ static int compare_lebs(const struct ubi_device *ubi, } vfree(buf); - ubi_free_vid_hdr(ubi, vidh); + ubi_free_vid_hdr(ubi, vh); if (second_is_newer) dbg_bld("second PEB %d is newer, copy_flag is set", pnum); @@ -391,7 +389,7 @@ static int compare_lebs(const struct ubi_device *ubi, out_free_buf: vfree(buf); out_free_vidh: - ubi_free_vid_hdr(ubi, vidh); + ubi_free_vid_hdr(ubi, vh); ubi_assert(err < 0); return err; } @@ -413,7 +411,7 @@ out_free_vidh: * to be picked, while the older one has to be dropped. This function returns * zero in case of success and a negative error code in case of failure. */ -int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si, +int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips) { @@ -667,16 +665,12 @@ void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv) * function returns zero in case of success and a negative error code in case * of failure. */ -int ubi_scan_erase_peb(const struct ubi_device *ubi, - const struct ubi_scan_info *si, int pnum, int ec) +int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si, + int pnum, int ec) { int err; struct ubi_ec_hdr *ec_hdr; - ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); - if (!ec_hdr) - return -ENOMEM; - if ((long long)ec >= UBI_MAX_ERASECOUNTER) { /* * Erase counter overflow. Upgrade UBI and use 64-bit @@ -686,6 +680,10 @@ int ubi_scan_erase_peb(const struct ubi_device *ubi, return -EINVAL; } + ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); + if (!ec_hdr) + return -ENOMEM; + ec_hdr->ec = cpu_to_be64(ec); err = ubi_io_sync_erase(ubi, pnum, 0); @@ -712,7 +710,7 @@ out_free: * This function returns scanning physical eraseblock information in case of * success and an error code in case of failure. */ -struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi, +struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi, struct ubi_scan_info *si) { int err = 0, i; @@ -948,7 +946,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) if (!ech) goto out_si; - vidh = ubi_zalloc_vid_hdr(ubi); + vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); if (!vidh) goto out_ech; @@ -1110,8 +1108,7 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si) |