Merge branch 'linux-next' of git://git.infradead.org/ubi-2.6
* 'linux-next' of git://git.infradead.org/ubi-2.6: UBI: fix compilation warnings UBI: fix NOR flash recovery UBI: nicify image sequence number handling UBI: add image sequence number to EC header UBI: remove bogus debugging checks UBI: add empty eraseblocks verification
This commit is contained in:
commit
d6be791cbd
|
@ -657,6 +657,11 @@ static int io_init(struct ubi_device *ubi)
|
|||
if (ubi->mtd->block_isbad && ubi->mtd->block_markbad)
|
||||
ubi->bad_allowed = 1;
|
||||
|
||||
if (ubi->mtd->type == MTD_NORFLASH) {
|
||||
ubi_assert(ubi->mtd->writesize == 1);
|
||||
ubi->nor_flash = 1;
|
||||
}
|
||||
|
||||
ubi->min_io_size = ubi->mtd->writesize;
|
||||
ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
|
||||
|
||||
|
@ -996,6 +1001,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
|
|||
ubi_msg("number of PEBs reserved for bad PEB handling: %d",
|
||||
ubi->beb_rsvd_pebs);
|
||||
ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec);
|
||||
ubi_msg("image sequence number: %d", ubi->image_seq);
|
||||
|
||||
/*
|
||||
* The below lock makes sure we do not race with 'ubi_thread()' which
|
||||
|
|
|
@ -44,6 +44,8 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
|
|||
be32_to_cpu(ec_hdr->vid_hdr_offset));
|
||||
printk(KERN_DEBUG "\tdata_offset %d\n",
|
||||
be32_to_cpu(ec_hdr->data_offset));
|
||||
printk(KERN_DEBUG "\timage_seq %d\n",
|
||||
be32_to_cpu(ec_hdr->image_seq));
|
||||
printk(KERN_DEBUG "\thdr_crc %#08x\n",
|
||||
be32_to_cpu(ec_hdr->hdr_crc));
|
||||
printk(KERN_DEBUG "erase counter header hexdump:\n");
|
||||
|
|
|
@ -93,6 +93,12 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
|
|||
#define UBI_IO_DEBUG 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
|
||||
int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len);
|
||||
#else
|
||||
#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT
|
||||
#define DBG_DISABLE_BGT 1
|
||||
#else
|
||||
|
@ -167,6 +173,7 @@ static inline int ubi_dbg_is_erase_failure(void)
|
|||
#define ubi_dbg_is_bitflip() 0
|
||||
#define ubi_dbg_is_write_failure() 0
|
||||
#define ubi_dbg_is_erase_failure() 0
|
||||
#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
|
||||
|
||||
#endif /* !CONFIG_MTD_UBI_DEBUG */
|
||||
#endif /* !__UBI_DEBUG_H__ */
|
||||
|
|
|
@ -98,17 +98,12 @@ 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(struct ubi_device *ubi, int pnum, int offset,
|
||||
int len);
|
||||
static int paranoid_check_empty(struct ubi_device *ubi, int pnum);
|
||||
#else
|
||||
#define paranoid_check_not_bad(ubi, pnum) 0
|
||||
#define paranoid_check_peb_ec_hdr(ubi, pnum) 0
|
||||
#define paranoid_check_ec_hdr(ubi, pnum, ec_hdr) 0
|
||||
#define paranoid_check_peb_vid_hdr(ubi, pnum) 0
|
||||
#define paranoid_check_vid_hdr(ubi, pnum, vid_hdr) 0
|
||||
#define paranoid_check_all_ff(ubi, pnum, offset, len) 0
|
||||
#define paranoid_check_empty(ubi, pnum) 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -244,7 +239,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
|
|||
return err > 0 ? -EINVAL : err;
|
||||
|
||||
/* The area we are writing to has to contain all 0xFF bytes */
|
||||
err = paranoid_check_all_ff(ubi, pnum, offset, len);
|
||||
err = ubi_dbg_check_all_ff(ubi, pnum, offset, len);
|
||||
if (err)
|
||||
return err > 0 ? -EINVAL : err;
|
||||
|
||||
|
@ -271,8 +266,8 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
|
|||
addr = (loff_t)pnum * ubi->peb_size + offset;
|
||||
err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf);
|
||||
if (err) {
|
||||
ubi_err("error %d while writing %d bytes to PEB %d:%d, written"
|
||||
" %zd bytes", err, len, pnum, offset, written);
|
||||
ubi_err("error %d while writing %d bytes to PEB %d:%d, written "
|
||||
"%zd bytes", err, len, pnum, offset, written);
|
||||
ubi_dbg_dump_stack();
|
||||
} else
|
||||
ubi_assert(written == len);
|
||||
|
@ -350,7 +345,7 @@ retry:
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
err = paranoid_check_all_ff(ubi, pnum, 0, ubi->peb_size);
|
||||
err = ubi_dbg_check_all_ff(ubi, pnum, 0, ubi->peb_size);
|
||||
if (err)
|
||||
return err > 0 ? -EINVAL : err;
|
||||
|
||||
|
@ -458,6 +453,54 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* nor_erase_prepare - prepare a NOR flash PEB for erasure.
|
||||
* @ubi: UBI device description object
|
||||
* @pnum: physical eraseblock number to prepare
|
||||
*
|
||||
* NOR flash, or at least some of them, have peculiar embedded PEB erasure
|
||||
* algorithm: the PEB is first filled with zeroes, then it is erased. And
|
||||
* filling with zeroes starts from the end of the PEB. This was observed with
|
||||
* Spansion S29GL512N NOR flash.
|
||||
*
|
||||
* This means that in case of a power cut we may end up with intact data at the
|
||||
* beginning of the PEB, and all zeroes at the end of PEB. In other words, the
|
||||
* EC and VID headers are OK, but a large chunk of data at the end of PEB is
|
||||
* zeroed. This makes UBI mistakenly treat this PEB as used and associate it
|
||||
* with an LEB, which leads to subsequent failures (e.g., UBIFS fails).
|
||||
*
|
||||
* This function is called before erasing NOR PEBs and it zeroes out EC and VID
|
||||
* magic numbers in order to invalidate them and prevent the failures. Returns
|
||||
* zero in case of success and a negative error code in case of failure.
|
||||
*/
|
||||
static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
|
||||
{
|
||||
int err;
|
||||
size_t written;
|
||||
loff_t addr;
|
||||
uint32_t data = 0;
|
||||
|
||||
addr = (loff_t)pnum * ubi->peb_size;
|
||||
err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
|
||||
if (err) {
|
||||
ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
|
||||
"%zd bytes", err, pnum, 0, written);
|
||||
ubi_dbg_dump_stack();
|
||||
return err;
|
||||
}
|
||||
|
||||
addr += ubi->vid_hdr_aloffset;
|
||||
err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
|
||||
if (err) {
|
||||
ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
|
||||
"%zd bytes", err, pnum, ubi->vid_hdr_aloffset, written);
|
||||
ubi_dbg_dump_stack();
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubi_io_sync_erase - synchronously erase a physical eraseblock.
|
||||
* @ubi: UBI device description object
|
||||
|
@ -489,6 +532,12 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
|
|||
return -EROFS;
|
||||
}
|
||||
|
||||
if (ubi->nor_flash) {
|
||||
err = nor_erase_prepare(ubi, pnum);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (torture) {
|
||||
ret = torture_peb(ubi, pnum);
|
||||
if (ret < 0)
|
||||
|
@ -672,11 +721,6 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
|
|||
if (read_err != -EBADMSG &&
|
||||
check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) {
|
||||
/* The physical eraseblock is supposedly empty */
|
||||
err = paranoid_check_all_ff(ubi, pnum, 0,
|
||||
ubi->peb_size);
|
||||
if (err)
|
||||
return err > 0 ? UBI_IO_BAD_EC_HDR : err;
|
||||
|
||||
if (verbose)
|
||||
ubi_warn("no EC header found at PEB %d, "
|
||||
"only 0xFF bytes", pnum);
|
||||
|
@ -752,6 +796,7 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
|
|||
ec_hdr->version = UBI_VERSION;
|
||||
ec_hdr->vid_hdr_offset = cpu_to_be32(ubi->vid_hdr_offset);
|
||||
ec_hdr->data_offset = cpu_to_be32(ubi->leb_start);
|
||||
ec_hdr->image_seq = cpu_to_be32(ubi->image_seq);
|
||||
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
|
||||
ec_hdr->hdr_crc = cpu_to_be32(crc);
|
||||
|
||||
|
@ -947,15 +992,6 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
|
|||
if (read_err != -EBADMSG &&
|
||||
check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
|
||||
/* The physical eraseblock is supposedly free */
|
||||
|
||||
/*
|
||||
* The below is just a paranoid check, it has to be
|
||||
* compiled out if paranoid checks are disabled.
|
||||
*/
|
||||
err = paranoid_check_empty(ubi, pnum);
|
||||
if (err)
|
||||
return err > 0 ? UBI_IO_BAD_VID_HDR : err;
|
||||
|
||||
if (verbose)
|
||||
ubi_warn("no VID header found at PEB %d, "
|
||||
"only 0xFF bytes", pnum);
|
||||
|
@ -1229,7 +1265,7 @@ exit:
|
|||
}
|
||||
|
||||
/**
|
||||
* paranoid_check_all_ff - check that a region of flash is empty.
|
||||
* ubi_dbg_check_all_ff - check that a region of flash is empty.
|
||||
* @ubi: UBI device description object
|
||||
* @pnum: the physical eraseblock number to check
|
||||
* @offset: the starting offset within the physical eraseblock to check
|
||||
|
@ -1239,8 +1275,7 @@ 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(struct ubi_device *ubi, int pnum, int offset,
|
||||
int len)
|
||||
int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
|
||||
{
|
||||
size_t read;
|
||||
int err;
|
||||
|
@ -1276,74 +1311,4 @@ error:
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* paranoid_check_empty - whether a PEB is empty.
|
||||
* @ubi: UBI device description object
|
||||
* @pnum: the physical eraseblock number to check
|
||||
*
|
||||
* This function makes sure PEB @pnum is empty, which means it contains only
|
||||
* %0xFF data bytes. Returns zero if the PEB is empty, %1 if not, and a
|
||||
* negative error code in case of failure.
|
||||
*
|
||||
* Empty PEBs have the EC header, and do not have the VID header. The caller of
|
||||
* this function should have already made sure the PEB does not have the VID
|
||||
* header. However, this function re-checks that, because it is possible that
|
||||
* the header and data has already been written to the PEB.
|
||||
*
|
||||
* Let's consider a possible scenario. Suppose there are 2 tasks - A and B.
|
||||
* Task A is in 'wear_leveling_worker()'. It is reading VID header of PEB X to
|
||||
* find which LEB it corresponds to. PEB X is currently unmapped, and has no
|
||||
* VID header. Task B is trying to write to PEB X.
|
||||
*
|
||||
* Task A: in 'ubi_io_read_vid_hdr()': reads the VID header from PEB X. The
|
||||
* read data contain all 0xFF bytes;
|
||||
* Task B: writes VID header and some data to PEB X;
|
||||
* Task A: assumes PEB X is empty, calls 'paranoid_check_empty()'. And if we
|
||||
* do not re-read the VID header, and do not cancel the checking if it
|
||||
* is there, we fail.
|
||||
*/
|
||||
static int paranoid_check_empty(struct ubi_device *ubi, int pnum)
|
||||
{
|
||||
int err, offs = ubi->vid_hdr_aloffset, len = ubi->vid_hdr_alsize;
|
||||
size_t read;
|
||||
uint32_t magic;
|
||||
const struct ubi_vid_hdr *vid_hdr;
|
||||
|
||||
mutex_lock(&ubi->dbg_buf_mutex);
|
||||
err = ubi->mtd->read(ubi->mtd, offs, 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, offs, read);
|
||||
goto error;
|
||||
}
|
||||
|
||||
vid_hdr = ubi->dbg_peb_buf;
|
||||
magic = be32_to_cpu(vid_hdr->magic);
|
||||
if (magic == UBI_VID_HDR_MAGIC)
|
||||
/* The PEB contains VID header, so it is not empty */
|
||||
goto out;
|
||||
|
||||
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, offs, len);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&ubi->dbg_buf_mutex);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ubi_err("paranoid check failed for PEB %d", pnum);
|
||||
ubi_msg("hex dump of the %d-%d region", offs, offs + len);
|
||||
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
|
||||
ubi->dbg_peb_buf, len, 1);
|
||||
err = 1;
|
||||
error:
|
||||
ubi_dbg_dump_stack();
|
||||
mutex_unlock(&ubi->dbg_buf_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
|
||||
|
|
|
@ -757,6 +757,8 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
|
|||
si->is_empty = 0;
|
||||
|
||||
if (!ec_corr) {
|
||||
int image_seq;
|
||||
|
||||
/* Make sure UBI version is OK */
|
||||
if (ech->version != UBI_VERSION) {
|
||||
ubi_err("this UBI version is %d, image version is %d",
|
||||
|
@ -778,6 +780,18 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
|
|||
ubi_dbg_dump_ec_hdr(ech);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
image_seq = be32_to_cpu(ech->ec);
|
||||
if (!si->image_seq_set) {
|
||||
ubi->image_seq = image_seq;
|
||||
si->image_seq_set = 1;
|
||||
} else if (ubi->image_seq != image_seq) {
|
||||
ubi_err("bad image sequence number %d in PEB %d, "
|
||||
"expected %d", image_seq, pnum, ubi->image_seq);
|
||||
ubi_dbg_dump_ec_hdr(ech);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* OK, we've done with the EC header, let's look at the VID header */
|
||||
|
|
|
@ -102,6 +102,7 @@ struct ubi_scan_volume {
|
|||
* @mean_ec: mean erase counter value
|
||||
* @ec_sum: a temporary variable used when calculating @mean_ec
|
||||
* @ec_count: a temporary variable used when calculating @mean_ec
|
||||
* @image_seq_set: indicates @ubi->image_seq is known
|
||||
*
|
||||
* This data structure contains the result of scanning and may be used by other
|
||||
* UBI sub-systems to build final UBI data structures, further error-recovery
|
||||
|
@ -124,6 +125,7 @@ struct ubi_scan_info {
|
|||
int mean_ec;
|
||||
uint64_t ec_sum;
|
||||
int ec_count;
|
||||
int image_seq_set;
|
||||
};
|
||||
|
||||
struct ubi_device;
|
||||
|
|
|
@ -129,6 +129,7 @@ enum {
|
|||
* @ec: the erase counter
|
||||
* @vid_hdr_offset: where the VID header starts
|
||||
* @data_offset: where the user data start
|
||||
* @image_seq: image sequence number
|
||||
* @padding2: reserved for future, zeroes
|
||||
* @hdr_crc: erase counter header CRC checksum
|
||||
*
|
||||
|
@ -144,6 +145,14 @@ enum {
|
|||
* volume identifier header and user data, relative to the beginning of the
|
||||
* physical eraseblock. These values have to be the same for all physical
|
||||
* eraseblocks.
|
||||
*
|
||||
* The @image_seq field is used to validate a UBI image that has been prepared
|
||||
* for a UBI device. The @image_seq value can be any value, but it must be the
|
||||
* same on all eraseblocks. UBI will ensure that all new erase counter headers
|
||||
* also contain this value, and will check the value when scanning at start-up.
|
||||
* One way to make use of @image_seq is to increase its value by one every time
|
||||
* an image is flashed over an existing image, then, if the flashing does not
|
||||
* complete, UBI will detect the error when scanning.
|
||||
*/
|
||||
struct ubi_ec_hdr {
|
||||
__be32 magic;
|
||||
|
@ -152,7 +161,8 @@ struct ubi_ec_hdr {
|
|||
__be64 ec; /* Warning: the current limit is 31-bit anyway! */
|
||||
__be32 vid_hdr_offset;
|
||||
__be32 data_offset;
|
||||
__u8 padding2[36];
|
||||
__be32 image_seq;
|
||||
__u8 padding2[32];
|
||||
__be32 hdr_crc;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
|
|
@ -301,6 +301,7 @@ struct ubi_wl_entry;
|
|||
* @vol->readers, @vol->writers, @vol->exclusive,
|
||||
* @vol->ref_count, @vol->mapping and @vol->eba_tbl.
|
||||
* @ref_count: count of references on the UBI device
|
||||
* @image_seq: image sequence number recorded on EC headers
|
||||
*
|
||||
* @rsvd_pebs: count of reserved physical eraseblocks
|
||||
* @avail_pebs: count of available physical eraseblocks
|
||||
|
@ -372,6 +373,7 @@ struct ubi_wl_entry;
|
|||
* @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset
|
||||
* @bad_allowed: whether the MTD device admits of bad physical eraseblocks or
|
||||
* not
|
||||
* @nor_flash: non-zero if working on top of NOR flash
|
||||
* @mtd: MTD device descriptor
|
||||
*
|
||||
* @peb_buf1: a buffer of PEB size used for different purposes
|
||||
|
@ -390,6 +392,7 @@ struct ubi_device {
|
|||
struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT];
|
||||
spinlock_t volumes_lock;
|
||||
int ref_count;
|
||||
int image_seq;
|
||||
|
||||
int rsvd_pebs;
|
||||
int avail_pebs;
|
||||
|
@ -452,7 +455,8 @@ struct ubi_device {
|
|||
int vid_hdr_offset;
|
||||
int vid_hdr_aloffset;
|
||||
int vid_hdr_shift;
|
||||
int bad_allowed;
|
||||
unsigned int bad_allowed:1;
|
||||
unsigned int nor_flash:1;
|
||||
struct mtd_info *mtd;
|
||||
|
||||
void *peb_buf1;
|
||||
|
|
|
@ -459,6 +459,14 @@ retry:
|
|||
dbg_wl("PEB %d EC %d", e->pnum, e->ec);
|
||||
prot_queue_add(ubi, e);
|
||||
spin_unlock(&ubi->wl_lock);
|
||||
|
||||
err = ubi_dbg_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset,
|
||||
ubi->peb_size - ubi->vid_hdr_aloffset);
|
||||
if (err) {
|
||||
ubi_err("new PEB %d does not contain all 0xFF bytes", e->pnum);
|
||||
return err > 0 ? -EINVAL : err;
|
||||
}
|
||||
|
||||
return e->pnum;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue