📄 eba.c
字号:
} err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1); if (err && err != UBI_IO_BITFLIPS) { if (err > 0) { /* * The header is either absent or corrupted. * The former case means there is a bug - * switch to read-only mode just in case. * The latter case means a real corruption - we * may try to recover data. FIXME: but this is * not implemented. */ if (err == UBI_IO_BAD_VID_HDR) { ubi_warn("bad VID header at PEB %d, LEB" "%d:%d", pnum, vol_id, lnum); err = -EBADMSG; } else ubi_ro_mode(ubi); } goto out_free; } else if (err == UBI_IO_BITFLIPS) scrub = 1; ubi_assert(lnum < be32_to_cpu(vid_hdr->used_ebs)); ubi_assert(len == be32_to_cpu(vid_hdr->data_size)); crc = be32_to_cpu(vid_hdr->data_crc); ubi_free_vid_hdr(ubi, vid_hdr); } err = ubi_io_read_data(ubi, buf, pnum, offset, len); if (err) { if (err == UBI_IO_BITFLIPS) { scrub = 1; err = 0; } else if (err == -EBADMSG) { if (vol->vol_type == UBI_DYNAMIC_VOLUME) goto out_unlock; scrub = 1; if (!check) { ubi_msg("force data checking"); check = 1; goto retry; } } else goto out_unlock; } if (check) { uint32_t crc1 = crc32(UBI_CRC32_INIT, buf, len); if (crc1 != crc) { ubi_warn("CRC error: calculated %#08x, must be %#08x", crc1, crc); err = -EBADMSG; goto out_unlock; } } if (scrub) err = ubi_wl_scrub_peb(ubi, pnum); leb_read_unlock(ubi, vol_id, lnum); return err;out_free: ubi_free_vid_hdr(ubi, vid_hdr);out_unlock: leb_read_unlock(ubi, vol_id, lnum); return err;}/** * recover_peb - recover from write failure. * @ubi: UBI device description object * @pnum: the physical eraseblock to recover * @vol_id: volume ID * @lnum: logical eraseblock number * @buf: data which was not written because of the write failure * @offset: offset of the failed write * @len: how many bytes should have been written * * This function is called in case of a write failure and moves all good data * from the potentially bad physical eraseblock to a good physical eraseblock. * This function also writes the data which was not written due to the failure. * Returns new physical eraseblock number in case of success, and a negative * error code in case of failure. */static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, const void *buf, int offset, int len){ 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; 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; } ubi_msg("recover PEB %d, move data to PEB %d", pnum, new_pnum); err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1); if (err && err != UBI_IO_BITFLIPS) { if (err > 0) err = -EIO; goto out_put; } vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr); if (err) goto write_error; data_size = offset + 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, ubi->peb_buf1, pnum, 0, offset); if (err && err != UBI_IO_BITFLIPS) goto out_put; } memcpy(ubi->peb_buf1 + offset, buf, len); err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size); if (err) goto write_error; mutex_unlock(&ubi->buf_mutex); ubi_free_vid_hdr(ubi, vid_hdr); vol->eba_tbl[lnum] = new_pnum; ubi_wl_put_peb(ubi, pnum, 1); ubi_msg("data was successfully recovered"); 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;write_error: /* * Bad luck? This physical eraseblock is bad too? Crud. Let's try to * get another one. */ 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; } ubi_msg("try again"); goto retry;}/** * ubi_eba_write_leb - write data to dynamic volume. * @ubi: UBI device description object * @vol: volume description object * @lnum: logical eraseblock number * @buf: the data to write * @offset: offset within the logical eraseblock where to write * @len: how many bytes to write * @dtype: data type * * This function writes data to logical eraseblock @lnum of a dynamic volume * @vol. Returns zero in case of success and a negative error code in case * of failure. In case of error, it is possible that something was still * written to the flash media, but may be some garbage. */int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, const void *buf, int offset, int len, int dtype){ int err, pnum, tries = 0, vol_id = vol->vol_id; struct ubi_vid_hdr *vid_hdr; if (ubi->ro_mode) return -EROFS; err = leb_write_lock(ubi, vol_id, lnum); if (err) return err; pnum = vol->eba_tbl[lnum]; if (pnum >= 0) { dbg_eba("write %d bytes at offset %d of LEB %d:%d, PEB %d", len, offset, vol_id, lnum, pnum); err = ubi_io_write_data(ubi, buf, pnum, offset, len); if (err) { ubi_warn("failed to write data to PEB %d", pnum); if (err == -EIO && ubi->bad_allowed) err = recover_peb(ubi, pnum, vol_id, lnum, buf, offset, len); if (err) ubi_ro_mode(ubi); } leb_write_unlock(ubi, vol_id, lnum); return err; } /* * 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, GFP_NOFS); if (!vid_hdr) { leb_write_unlock(ubi, vol_id, lnum); return -ENOMEM; } vid_hdr->vol_type = UBI_VID_DYNAMIC; vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); vid_hdr->vol_id = cpu_to_be32(vol_id); vid_hdr->lnum = cpu_to_be32(lnum); vid_hdr->compat = ubi_get_compat(ubi, vol_id); vid_hdr->data_pad = cpu_to_be32(vol->data_pad);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; } dbg_eba("write VID hdr and %d bytes at offset %d of LEB %d:%d, PEB %d", len, offset, vol_id, lnum, pnum); err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); if (err) { ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", vol_id, lnum, pnum); goto write_error; } if (len) { err = ubi_io_write_data(ubi, buf, pnum, offset, len); if (err) { ubi_warn("failed to write %d bytes at offset %d of " "LEB %d:%d, PEB %d", len, offset, vol_id, lnum, pnum); goto write_error; } } vol->eba_tbl[lnum] = pnum; leb_write_unlock(ubi, vol_id, lnum); ubi_free_vid_hdr(ubi, vid_hdr); return 0;write_error: if (err != -EIO || !ubi->bad_allowed) { ubi_ro_mode(ubi); leb_write_unlock(ubi, vol_id, lnum); ubi_free_vid_hdr(ubi, vid_hdr); return err; } /* * Fortunately, this is the first write operation to this physical * eraseblock, so just put it and request a new one. We assume that if * this physical eraseblock went bad, the erase code will handle that. */ 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; } vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); ubi_msg("try another PEB"); goto retry;}/** * ubi_eba_write_leb_st - write data to static volume. * @ubi: UBI device description object * @vol: volume description object * @lnum: logical eraseblock number * @buf: data to write * @len: how many bytes to write * @dtype: data type * @used_ebs: how many logical eraseblocks will this volume contain * * This function writes data to logical eraseblock @lnum of static volume * @vol. The @used_ebs argument should contain total number of logical * eraseblock in this static volume. * * When writing to the last logical eraseblock, the @len argument doesn't have * to be aligned to the minimal I/O unit size. Instead, it has to be equivalent * to the real data size, although the @buf buffer has to contain the * alignment. In all other cases, @len has to be aligned. * * It is prohibited to write more then once to logical eraseblocks of static * volumes. This function returns zero in case of success and a negative error * code in case of failure. */int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, const void *buf, int len, int dtype, int used_ebs){ int err, pnum, tries = 0, data_size = len, vol_id = vol->vol_id; struct ubi_vid_hdr *vid_hdr; uint32_t crc; if (ubi->ro_mode) return -EROFS; if (lnum == used_ebs - 1) /* If this is the last LEB @len may be unaligned */ len = ALIGN(data_size, ubi->min_io_size); else ubi_assert(!(len & (ubi->min_io_size - 1))); vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); if (!vid_hdr) return -ENOMEM; err = leb_write_lock(ubi, vol_id, lnum); if (err) { ubi_free_vid_hdr(ubi, vid_hdr); return err; } vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); vid_hdr->vol_id = cpu_to_be32(vol_id); vid_hdr->lnum = cpu_to_be32(lnum); vid_hdr->compat = ubi_get_compat(ubi, vol_id); vid_hdr->data_pad = cpu_to_be32(vol->data_pad); crc = crc32(UBI_CRC32_INIT, buf, data_size); vid_hdr->vol_type = UBI_VID_STATIC; vid_hdr->data_size = cpu_to_be32(data_size); vid_hdr->used_ebs = cpu_to_be32(used_ebs); vid_hdr->data_crc = cpu_to_be32(crc);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; } dbg_eba("write VID hdr and %d bytes at LEB %d:%d, PEB %d, used_ebs %d", len, vol_id, lnum, pnum, used_ebs); err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); if (err) { ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", vol_id, lnum, pnum); goto write_error; } err = ubi_io_write_data(ubi, buf, pnum, 0, len); if (err) { ubi_warn("failed to write %d bytes of data to PEB %d", len, pnum); goto write_error; } ubi_assert(vol->eba_tbl[lnum] < 0); vol->eba_tbl[lnum] = pnum; leb_write_unlock(ubi, vol_id, lnum); ubi_free_vid_hdr(ubi, vid_hdr); return 0;write_error: if (err != -EIO || !ubi->bad_allowed) { /* * This flash device does not admit of bad eraseblocks or * something nasty and unexpected happened. Switch to read-only * mode just in case. */ ubi_ro_mode(ubi); leb_write_unlock(ubi, vol_id, lnum); ubi_free_vid_hdr(ubi, vid_hdr); return err; } 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -