/** * refill_wl_pool - refills all the fastmap pool used by the * WL sub-system and ubi_wl_get_peb. * @ubi: UBI device description object */ static void ubi_refill_pools(struct ubigen_info *ui, int fd) { struct ubi_fm_pool *pool = &ui->fm_wl_pool; int start = ui->used_peb; off_t seek; char *outbuf; outbuf = malloc(ui->peb_size); memset(outbuf, 0xFF, ui->peb_size); ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ui->ec); printf("Start PEB %d for wl pool size %d\n", start, pool->max_size); for (pool->size = 0; pool->size < pool->max_size; pool->size++) { if (ui->peb_count - start < 5) break; seek = start * ui->peb_size; if (lseek(fd, seek, SEEK_SET) != seek) { sys_errmsg("cannot seek output file"); break; } if (write(fd, outbuf, ui->peb_size) != ui->peb_size) { sys_errmsg("cannot write %d bytes to the output file", ui->peb_size); break; } pool->pebs[pool->size] = start; start++; } printf( "End PEB %d for wl pool\n", start-1); printf( "found %d PEB for wl pool\n", pool->size); pool->used = 0; pool = &ui->fm_pool; printf( "Start PEB %d for user wl pool size %d\n", start, pool->max_size); for (pool->size = 0; pool->size < pool->max_size; pool->size++) { if (ui->peb_count - start < 1) break; seek = start * ui->peb_size; if (lseek(fd, seek, SEEK_SET) != seek) { sys_errmsg("cannot seek output file"); break; } if (write(fd, outbuf, ui->peb_size) != ui->peb_size) { sys_errmsg("cannot write %d bytes to the output file", ui->peb_size); break; } pool->pebs[pool->size] = start; start++; } printf( "End PEB %d for user wl pool\n", start-1); printf( "found %d PEB for wl pool\n", pool->size); pool->used = 0; }
/** * ubigen_write_volume - write UBI volume. * @ui: libubigen information * @vi: volume information * @ec: erase coutner value to put to EC headers * @bytes: volume size in bytes * @in: input file descriptor (has to be properly seeked) * @out: output file descriptor * * This function reads the contents of the volume from the input file @in and * writes the UBI volume to the output file @out. Returns zero on success and * %-1 on failure. */ int ubigen_write_volume(const struct ubigen_info *ui, const struct ubigen_vol_info *vi, long long ec, long long bytes, int in, int out) { int len = vi->usable_leb_size, rd, lnum = 0; char inbuf[ui->leb_size], outbuf[ui->peb_size]; if (vi->id >= ui->max_volumes) return errmsg("too high volume id %d, max. volumes is %d", vi->id, ui->max_volumes); if (vi->alignment >= ui->leb_size) return errmsg("too large alignment %d, max is %d (LEB size)", vi->alignment, ui->leb_size); memset(outbuf, 0xFF, ui->data_offs); ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec); while (bytes) { int l; struct ubi_vid_hdr *vid_hdr; if (bytes < len) len = bytes; bytes -= len; l = len; do { rd = read(in, inbuf + len - l, l); if (rd != l) return sys_errmsg("cannot read %d bytes from the input file", l); l -= rd; } while (l); vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]); init_vid_hdr(ui, vi, vid_hdr, lnum, inbuf, len); memcpy(outbuf + ui->data_offs, inbuf, len); memset(outbuf + ui->data_offs + len, 0xFF, ui->peb_size - ui->data_offs - len); if (write(out, outbuf, ui->peb_size) != ui->peb_size) return sys_errmsg("cannot write %d bytes to the output file", ui->peb_size); lnum += 1; } return 0; }
/** * ubi_write_fastmap - writes a fastmap. * @ubi: UBI device object * @new_fm: the to be written fastmap * * Returns 0 on success, < 0 indicates an internal error. */ static int ubi_write_fastmap(struct ubigen_info *ubi, struct ubi_fastmap_layout *new_fm, struct ubigen_vol_info *vi, int vc, int out_fd) { size_t fm_pos = 0; char *fm_raw; struct ubi_fm_sb *fmsb; struct ubi_fm_hdr *fmh; struct ubi_fm_scan_pool *fmpl1, *fmpl2; struct ubi_fm_ec *fec; struct ubi_fm_volhdr *fvh; struct ubi_fm_eba *feba; struct ubigen_vol_info *vol; struct ubi_vid_hdr *vid_hdr; int ret, i, j, free_peb_count, used_peb_count, vol_count; int scrub_peb_count, erase_peb_count; struct ubigen_vol_info fm_vi; int free_start; memset(&fm_vi, 0, sizeof(struct ubigen_vol_info)); fm_vi.id = UBI_FM_SB_VOLUME_ID; fm_vi.type = UBI_VID_DYNAMIC; fm_vi.compat = UBI_COMPAT_DELETE; fm_raw = malloc(ubi->peb_size); memset(fm_raw, 0, ubi->peb_size); ubigen_init_ec_hdr(ubi, (struct ubi_ec_hdr *)fm_raw, ubi->ec); vid_hdr = (struct ubi_vid_hdr *)(fm_raw + ubi->vid_hdr_offs); ubigen_init_vid_hdr(ubi, &fm_vi, vid_hdr, 0, 1, NULL, 0); fm_pos += ubi->data_offs; fmsb = (struct ubi_fm_sb *)(fm_raw + fm_pos); fm_pos += sizeof(*fmsb); fmh = (struct ubi_fm_hdr *)(fm_raw + fm_pos); fm_pos += sizeof(*fmh); fmsb->magic = cpu_to_be32(UBI_FM_SB_MAGIC); fmsb->version = UBI_FM_FMT_VERSION; fmsb->used_blocks = cpu_to_be32(new_fm->used_blocks); fmh->magic = cpu_to_be32(UBI_FM_HDR_MAGIC); free_peb_count = 0; used_peb_count = 0; scrub_peb_count = 0; erase_peb_count = 0; vol_count = 0; fmpl1 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos); fm_pos += sizeof(*fmpl1); fmpl1->magic = cpu_to_be32(UBI_FM_POOL_MAGIC); fmpl1->size = cpu_to_be16(ubi->fm_pool.size); fmpl1->max_size = cpu_to_be16(ubi->fm_pool.max_size); for (i = 0; i < ubi->fm_pool.size; i++) fmpl1->pebs[i] = cpu_to_be32(ubi->fm_pool.pebs[i]); fmpl2 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos); fm_pos += sizeof(*fmpl2); fmpl2->magic = cpu_to_be32(UBI_FM_POOL_MAGIC); fmpl2->size = cpu_to_be16(ubi->fm_wl_pool.size); fmpl2->max_size = cpu_to_be16(ubi->fm_wl_pool.max_size); for (i = 0; i < ubi->fm_wl_pool.size; i++) fmpl2->pebs[i] = cpu_to_be32(ubi->fm_wl_pool.pebs[i]); free_start = ubi->used_peb + ubi->fm_pool.size + ubi->fm_wl_pool.size; fmh->free_peb_count = cpu_to_be32(free_peb_count); //0 /* used list*/ for (i = 0 ; i < ubi->used_peb; i++) { if(i == 2) //Skip PEB 2 continue; fec = (struct ubi_fm_ec *)(fm_raw + fm_pos); fec->pnum = cpu_to_be32(i); fec->ec = cpu_to_be32(ubi->ec); used_peb_count++; fm_pos += sizeof(*fec); } fmh->used_peb_count = cpu_to_be32(used_peb_count); fmh->scrub_peb_count = cpu_to_be32(scrub_peb_count); //0 /* empty pebs to erase*/ for (i = free_start ; i < ubi->peb_count; i++) { fec = (struct ubi_fm_ec *)(fm_raw + fm_pos); fec->pnum = cpu_to_be32(i); fec->ec = cpu_to_be32(ubi->ec); erase_peb_count++; fm_pos += sizeof(*fec); } fmh->erase_peb_count = cpu_to_be32(erase_peb_count); for (i = 0; i < vc; i++) { int32_t tmp, reserved_pebs; vol = &vi[i]; if (vol->bytes == 0) continue; vol_count++; fvh = (struct ubi_fm_volhdr *)(fm_raw + fm_pos); fm_pos += sizeof(*fvh); fvh->magic = cpu_to_be32(UBI_FM_VHDR_MAGIC); fvh->vol_id = cpu_to_be32(vol->id); fvh->vol_type = UBI_DYNAMIC_VOLUME; reserved_pebs = (vol->bytes + ubi->leb_size - 1) / ubi->leb_size; fvh->used_ebs = cpu_to_be32(reserved_pebs); tmp = ubi->leb_size % vol->alignment; fvh->data_pad = cpu_to_be32(tmp); fvh->last_eb_bytes = cpu_to_be32(vol->usable_leb_size); feba = (struct ubi_fm_eba *)(fm_raw + fm_pos); fm_pos += sizeof(*feba) + (sizeof(__be32) * reserved_pebs); printf("vol %d reserved_pebs %d\n", i, reserved_pebs); printf("vol %d start %d stop %d\n", i, vol->start, vol->stop); for (j = 0; j < reserved_pebs; j++) { if(vol->start > 0 && j < vol->stop - vol->start) feba->pnum[j] = cpu_to_be32(vol->start+j); else feba->pnum[j] = cpu_to_be32(-1); } feba->reserved_pebs = cpu_to_be32(reserved_pebs); feba->magic = cpu_to_be32(UBI_FM_EBA_MAGIC); } //for vol table { uint32_t tmp; vol_count++; fvh = (struct ubi_fm_volhdr *)(fm_raw + fm_pos); fm_pos += sizeof(*fvh); fvh->magic = cpu_to_be32(UBI_FM_VHDR_MAGIC); fvh->vol_id = cpu_to_be32(UBI_LAYOUT_VOLUME_ID); fvh->vol_type = UBI_DYNAMIC_VOLUME; fvh->used_ebs = cpu_to_be32(UBI_LAYOUT_VOLUME_EBS); tmp = ubi->leb_size % UBI_LAYOUT_VOLUME_ALIGN; fvh->data_pad = cpu_to_be32(tmp); fvh->last_eb_bytes = cpu_to_be32(UBI_LAYOUT_VOLUME_EBS); feba = (struct ubi_fm_eba *)(fm_raw + fm_pos); fm_pos += sizeof(*feba) + (sizeof(__be32) * UBI_LAYOUT_VOLUME_EBS); for (j = 0; j < UBI_LAYOUT_VOLUME_EBS; j++) feba->pnum[j] = cpu_to_be32(j); feba->reserved_pebs = cpu_to_be32(UBI_LAYOUT_VOLUME_EBS); feba->magic = cpu_to_be32(UBI_FM_EBA_MAGIC); } fmh->vol_count = cpu_to_be32(vol_count); fmh->bad_peb_count = cpu_to_be32(0); vid_hdr->lnum = 0; for (i = 0; i < new_fm->used_blocks; i++) { fmsb->block_loc[i] = cpu_to_be32(new_fm->e[i]->pnum); fmsb->block_ec[i] = cpu_to_be32(new_fm->e[i]->ec); } fmsb->data_crc = 0; fmsb->data_crc = cpu_to_be32(mtd_crc32(UBI_CRC32_INIT, fmsb, ubi->fm_size)); for (i = 0; i < new_fm->used_blocks; i++) { off_t seek = ubi->peb_size*(2+i); printf("writing fastmap SB to PEB %i\n", new_fm->e[i]->pnum); if(lseek(out_fd, seek, SEEK_SET) != seek) { sys_errmsg("cannot seek output file"); goto out_free; } ret = write(out_fd, fm_raw, ubi->peb_size); if (ret != ubi->peb_size) { sys_errmsg("cannot write %d bytes", ubi->peb_size); goto out_free; } else ret = 0; } printf("fastmap written!"); out_free: free(fm_raw); return ret; }
int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2, long long ec1, long long ec2, struct ubi_vtbl_record *vtbl, int fd) { int ret; struct ubigen_vol_info vi; char *outbuf; struct ubi_vid_hdr *vid_hdr; off_t seek; vi.bytes = ui->leb_size * UBI_LAYOUT_VOLUME_EBS; vi.id = UBI_LAYOUT_VOLUME_ID; vi.alignment = UBI_LAYOUT_VOLUME_ALIGN; vi.data_pad = ui->leb_size % UBI_LAYOUT_VOLUME_ALIGN; vi.usable_leb_size = ui->leb_size - vi.data_pad; vi.data_pad = ui->leb_size - vi.usable_leb_size; vi.type = UBI_LAYOUT_VOLUME_TYPE; vi.name = UBI_LAYOUT_VOLUME_NAME; vi.name_len = strlen(UBI_LAYOUT_VOLUME_NAME); vi.compat = UBI_LAYOUT_VOLUME_COMPAT; outbuf = malloc(ui->peb_size); if (!outbuf) return sys_errmsg("failed to allocate %d bytes", ui->peb_size); memset(outbuf, 0xFF, ui->data_offs); vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]); memcpy(outbuf + ui->data_offs, vtbl, ui->vtbl_size); memset(outbuf + ui->data_offs + ui->vtbl_size, 0xFF, ui->peb_size - ui->data_offs - ui->vtbl_size); seek = peb1 * ui->peb_size; if (lseek(fd, seek, SEEK_SET) != seek) { sys_errmsg("cannot seek output file"); goto out_free; } ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec1); ubigen_init_vid_hdr(ui, &vi, vid_hdr, 0, 0, NULL, 0); ret = write(fd, outbuf, ui->peb_size); if (ret != ui->peb_size) { sys_errmsg("cannot write %d bytes", ui->peb_size); goto out_free; } seek = peb2 * ui->peb_size; if (lseek(fd, seek, SEEK_SET) != seek) { sys_errmsg("cannot seek output file"); goto out_free; } ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec2); ubigen_init_vid_hdr(ui, &vi, vid_hdr, 1, 0, NULL, 0); ret = write(fd, outbuf, ui->peb_size); if (ret != ui->peb_size) { sys_errmsg("cannot write %d bytes", ui->peb_size); goto out_free; } free(outbuf); return 0; out_free: free(outbuf); return -1; }
int ubigen_write_volume(const struct ubigen_info *ui, const struct ubigen_vol_info *vi, long long ec, long long bytes, int in, int out, int *out_lnum) { int len = vi->usable_leb_size, rd, lnum = 0; char *inbuf, *outbuf; if (vi->id >= ui->max_volumes) { errmsg("too high volume id %d, max. volumes is %d", vi->id, ui->max_volumes); errno = EINVAL; return -1; } if (vi->alignment >= ui->leb_size) { errmsg("too large alignment %d, max is %d (LEB size)", vi->alignment, ui->leb_size); errno = EINVAL; return -1; } inbuf = malloc(ui->leb_size); if (!inbuf) return sys_errmsg("cannot allocate %d bytes of memory", ui->leb_size); outbuf = malloc(ui->peb_size); if (!outbuf) { sys_errmsg("cannot allocate %d bytes of memory", ui->peb_size); goto out_free; } memset(outbuf, 0xFF, ui->data_offs); ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec); while (bytes) { int l; struct ubi_vid_hdr *vid_hdr; if (bytes < len) len = bytes; bytes -= len; l = len; do { rd = read(in, inbuf + len - l, l); if (rd != l) { sys_errmsg("cannot read %d bytes from the input file", l); goto out_free1; } l -= rd; } while (l); vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]); ubigen_init_vid_hdr(ui, vi, vid_hdr, lnum, 0, inbuf, len); memcpy(outbuf + ui->data_offs, inbuf, len); memset(outbuf + ui->data_offs + len, 0xFF, ui->peb_size - ui->data_offs - len); if (write(out, outbuf, ui->peb_size) != ui->peb_size) { sys_errmsg("cannot write %d bytes to the output file", ui->peb_size); goto out_free1; } lnum += 1; } *out_lnum = lnum; //MTK: output used LEB free(outbuf); free(inbuf); return 0; out_free1: free(outbuf); out_free: free(inbuf); return -1; }
static int format(const struct mtd_dev_info *mtd, const struct ubigen_info *ui, struct ubi_scan_info *si, int start_eb, int novtbl) { int eb, err, write_size; struct ubi_ec_hdr *hdr; struct ubi_vtbl_record *vtbl; int eb1 = -1, eb2 = -1; long long ec1 = -1, ec2 = -1; write_size = UBI_EC_HDR_SIZE + mtd->subpage_size - 1; write_size /= mtd->subpage_size; write_size *= mtd->subpage_size; hdr = malloc(write_size); if (!hdr) return sys_errmsg("cannot allocate %d bytes of memory", write_size); memset(hdr, 0xFF, write_size); for (eb = start_eb; eb < mtd->eb_cnt; eb++) { long long ec; if (!args.quiet && !args.verbose) { printf("\r" PROGRAM_NAME ": formatting eraseblock %d -- %2u %% complete ", eb, (eb + 1 - start_eb) * 100 / (mtd->eb_cnt - start_eb)); } if (si->ec[eb] == EB_BAD) continue; if (args.override_ec) ec = args.ec; else if (si->ec[eb] <= EC_MAX) ec = si->ec[eb] + 1; else ec = si->mean_ec; ubigen_init_ec_hdr(ui, hdr, ec); if (args.verbose) { normsg_cont("eraseblock %d: erase", eb); } err = libmtd_erase(mtd, args.node_fd, eb); if (err) { if (!args.quiet) printf("\n"); sys_errmsg("failed to erase eraseblock %d", eb); if (errno != EIO) goto out_free; if (mark_bad(mtd, si, eb)) goto out_free; continue; } if ((eb1 == -1 || eb2 == -1) && !novtbl) { if (eb1 == -1) { eb1 = eb; ec1 = ec; } else if (eb2 == -1) { eb2 = eb; ec2 = ec; } if (args.verbose) printf(", do not write EC, leave for vtbl\n"); continue; } if (args.verbose) { printf(", write EC %lld\n", ec); } err = libmtd_write(mtd, args.node_fd, eb, 0, hdr, write_size); if (err) { if (!args.quiet && !args.verbose) printf("\n"); sys_errmsg("cannot write EC header (%d bytes buffer) to eraseblock %d", write_size, eb); if (errno != EIO) { if (!args.subpage_size != mtd->min_io_size) normsg("may be sub-page size is " "incorrect?"); goto out_free; } err = mtd_torture(mtd, args.node_fd, eb); if (err) { if (mark_bad(mtd, si, eb)) goto out_free; } continue; } } if (!args.quiet && !args.verbose) printf("\n"); if (!novtbl) { if (eb1 == -1 || eb2 == -1) { errmsg("no eraseblocks for volume table"); goto out_free; } verbose(args.verbose, "write volume table to eraseblocks %d and %d", eb1, eb2); vtbl = ubigen_create_empty_vtbl(ui); if (!vtbl) goto out_free; err = ubigen_write_layout_vol(ui, eb1, eb2, ec1, ec2, vtbl, args.node_fd); free(vtbl); if (err) { errmsg("cannot write layout volume"); goto out_free; } } free(hdr); return 0; out_free: free(hdr); return -1; }