162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2012 Linutronix GmbH 462306a36Sopenharmony_ci * Copyright (c) 2014 sigma star gmbh 562306a36Sopenharmony_ci * Author: Richard Weinberger <richard@nod.at> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/crc32.h> 962306a36Sopenharmony_ci#include <linux/bitmap.h> 1062306a36Sopenharmony_ci#include "ubi.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/** 1362306a36Sopenharmony_ci * init_seen - allocate memory for used for debugging. 1462306a36Sopenharmony_ci * @ubi: UBI device description object 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_cistatic inline unsigned long *init_seen(struct ubi_device *ubi) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci unsigned long *ret; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci if (!ubi_dbg_chk_fastmap(ubi)) 2162306a36Sopenharmony_ci return NULL; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci ret = bitmap_zalloc(ubi->peb_count, GFP_KERNEL); 2462306a36Sopenharmony_ci if (!ret) 2562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci return ret; 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/** 3162306a36Sopenharmony_ci * free_seen - free the seen logic integer array. 3262306a36Sopenharmony_ci * @seen: integer array of @ubi->peb_count size 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_cistatic inline void free_seen(unsigned long *seen) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci bitmap_free(seen); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/** 4062306a36Sopenharmony_ci * set_seen - mark a PEB as seen. 4162306a36Sopenharmony_ci * @ubi: UBI device description object 4262306a36Sopenharmony_ci * @pnum: The PEB to be makred as seen 4362306a36Sopenharmony_ci * @seen: integer array of @ubi->peb_count size 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_cistatic inline void set_seen(struct ubi_device *ubi, int pnum, unsigned long *seen) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci if (!ubi_dbg_chk_fastmap(ubi) || !seen) 4862306a36Sopenharmony_ci return; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci set_bit(pnum, seen); 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/** 5462306a36Sopenharmony_ci * self_check_seen - check whether all PEB have been seen by fastmap. 5562306a36Sopenharmony_ci * @ubi: UBI device description object 5662306a36Sopenharmony_ci * @seen: integer array of @ubi->peb_count size 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_cistatic int self_check_seen(struct ubi_device *ubi, unsigned long *seen) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci int pnum, ret = 0; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (!ubi_dbg_chk_fastmap(ubi) || !seen) 6362306a36Sopenharmony_ci return 0; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci for (pnum = 0; pnum < ubi->peb_count; pnum++) { 6662306a36Sopenharmony_ci if (!test_bit(pnum, seen) && ubi->lookuptbl[pnum]) { 6762306a36Sopenharmony_ci ubi_err(ubi, "self-check failed for PEB %d, fastmap didn't see it", pnum); 6862306a36Sopenharmony_ci ret = -EINVAL; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return ret; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/** 7662306a36Sopenharmony_ci * ubi_calc_fm_size - calculates the fastmap size in bytes for an UBI device. 7762306a36Sopenharmony_ci * @ubi: UBI device description object 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_cisize_t ubi_calc_fm_size(struct ubi_device *ubi) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci size_t size; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci size = sizeof(struct ubi_fm_sb) + 8462306a36Sopenharmony_ci sizeof(struct ubi_fm_hdr) + 8562306a36Sopenharmony_ci sizeof(struct ubi_fm_scan_pool) + 8662306a36Sopenharmony_ci sizeof(struct ubi_fm_scan_pool) + 8762306a36Sopenharmony_ci (ubi->peb_count * sizeof(struct ubi_fm_ec)) + 8862306a36Sopenharmony_ci ((sizeof(struct ubi_fm_eba) + 8962306a36Sopenharmony_ci sizeof(struct ubi_fm_volhdr)) * 9062306a36Sopenharmony_ci (UBI_MAX_VOLUMES + UBI_INT_VOL_COUNT)) + 9162306a36Sopenharmony_ci (ubi->peb_count * sizeof(__be32)); 9262306a36Sopenharmony_ci return roundup(size, ubi->leb_size); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/** 9762306a36Sopenharmony_ci * new_fm_vbuf() - allocate a new volume header for fastmap usage. 9862306a36Sopenharmony_ci * @ubi: UBI device description object 9962306a36Sopenharmony_ci * @vol_id: the VID of the new header 10062306a36Sopenharmony_ci * 10162306a36Sopenharmony_ci * Returns a new struct ubi_vid_hdr on success. 10262306a36Sopenharmony_ci * NULL indicates out of memory. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_cistatic struct ubi_vid_io_buf *new_fm_vbuf(struct ubi_device *ubi, int vol_id) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct ubi_vid_io_buf *new; 10762306a36Sopenharmony_ci struct ubi_vid_hdr *vh; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci new = ubi_alloc_vid_buf(ubi, GFP_KERNEL); 11062306a36Sopenharmony_ci if (!new) 11162306a36Sopenharmony_ci goto out; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci vh = ubi_get_vid_hdr(new); 11462306a36Sopenharmony_ci vh->vol_type = UBI_VID_DYNAMIC; 11562306a36Sopenharmony_ci vh->vol_id = cpu_to_be32(vol_id); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* UBI implementations without fastmap support have to delete the 11862306a36Sopenharmony_ci * fastmap. 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci vh->compat = UBI_COMPAT_DELETE; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ciout: 12362306a36Sopenharmony_ci return new; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/** 12762306a36Sopenharmony_ci * add_aeb - create and add a attach erase block to a given list. 12862306a36Sopenharmony_ci * @ai: UBI attach info object 12962306a36Sopenharmony_ci * @list: the target list 13062306a36Sopenharmony_ci * @pnum: PEB number of the new attach erase block 13162306a36Sopenharmony_ci * @ec: erease counter of the new LEB 13262306a36Sopenharmony_ci * @scrub: scrub this PEB after attaching 13362306a36Sopenharmony_ci * 13462306a36Sopenharmony_ci * Returns 0 on success, < 0 indicates an internal error. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_cistatic int add_aeb(struct ubi_attach_info *ai, struct list_head *list, 13762306a36Sopenharmony_ci int pnum, int ec, int scrub) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct ubi_ainf_peb *aeb; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci aeb = ubi_alloc_aeb(ai, pnum, ec); 14262306a36Sopenharmony_ci if (!aeb) 14362306a36Sopenharmony_ci return -ENOMEM; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci aeb->lnum = -1; 14662306a36Sopenharmony_ci aeb->scrub = scrub; 14762306a36Sopenharmony_ci aeb->copy_flag = aeb->sqnum = 0; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci ai->ec_sum += aeb->ec; 15062306a36Sopenharmony_ci ai->ec_count++; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (ai->max_ec < aeb->ec) 15362306a36Sopenharmony_ci ai->max_ec = aeb->ec; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (ai->min_ec > aeb->ec) 15662306a36Sopenharmony_ci ai->min_ec = aeb->ec; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci list_add_tail(&aeb->u.list, list); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci return 0; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci/** 16462306a36Sopenharmony_ci * add_vol - create and add a new volume to ubi_attach_info. 16562306a36Sopenharmony_ci * @ai: ubi_attach_info object 16662306a36Sopenharmony_ci * @vol_id: VID of the new volume 16762306a36Sopenharmony_ci * @used_ebs: number of used EBS 16862306a36Sopenharmony_ci * @data_pad: data padding value of the new volume 16962306a36Sopenharmony_ci * @vol_type: volume type 17062306a36Sopenharmony_ci * @last_eb_bytes: number of bytes in the last LEB 17162306a36Sopenharmony_ci * 17262306a36Sopenharmony_ci * Returns the new struct ubi_ainf_volume on success. 17362306a36Sopenharmony_ci * NULL indicates an error. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_cistatic struct ubi_ainf_volume *add_vol(struct ubi_attach_info *ai, int vol_id, 17662306a36Sopenharmony_ci int used_ebs, int data_pad, u8 vol_type, 17762306a36Sopenharmony_ci int last_eb_bytes) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct ubi_ainf_volume *av; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci av = ubi_add_av(ai, vol_id); 18262306a36Sopenharmony_ci if (IS_ERR(av)) 18362306a36Sopenharmony_ci return av; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci av->data_pad = data_pad; 18662306a36Sopenharmony_ci av->last_data_size = last_eb_bytes; 18762306a36Sopenharmony_ci av->compat = 0; 18862306a36Sopenharmony_ci av->vol_type = vol_type; 18962306a36Sopenharmony_ci if (av->vol_type == UBI_STATIC_VOLUME) 19062306a36Sopenharmony_ci av->used_ebs = used_ebs; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci dbg_bld("found volume (ID %i)", vol_id); 19362306a36Sopenharmony_ci return av; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/** 19762306a36Sopenharmony_ci * assign_aeb_to_av - assigns a SEB to a given ainf_volume and removes it 19862306a36Sopenharmony_ci * from it's original list. 19962306a36Sopenharmony_ci * @ai: ubi_attach_info object 20062306a36Sopenharmony_ci * @aeb: the to be assigned SEB 20162306a36Sopenharmony_ci * @av: target scan volume 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_cistatic void assign_aeb_to_av(struct ubi_attach_info *ai, 20462306a36Sopenharmony_ci struct ubi_ainf_peb *aeb, 20562306a36Sopenharmony_ci struct ubi_ainf_volume *av) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct ubi_ainf_peb *tmp_aeb; 20862306a36Sopenharmony_ci struct rb_node **p = &av->root.rb_node, *parent = NULL; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci while (*p) { 21162306a36Sopenharmony_ci parent = *p; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci tmp_aeb = rb_entry(parent, struct ubi_ainf_peb, u.rb); 21462306a36Sopenharmony_ci if (aeb->lnum != tmp_aeb->lnum) { 21562306a36Sopenharmony_ci if (aeb->lnum < tmp_aeb->lnum) 21662306a36Sopenharmony_ci p = &(*p)->rb_left; 21762306a36Sopenharmony_ci else 21862306a36Sopenharmony_ci p = &(*p)->rb_right; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci continue; 22162306a36Sopenharmony_ci } else 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci list_del(&aeb->u.list); 22662306a36Sopenharmony_ci av->leb_count++; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci rb_link_node(&aeb->u.rb, parent, p); 22962306a36Sopenharmony_ci rb_insert_color(&aeb->u.rb, &av->root); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci/** 23362306a36Sopenharmony_ci * update_vol - inserts or updates a LEB which was found a pool. 23462306a36Sopenharmony_ci * @ubi: the UBI device object 23562306a36Sopenharmony_ci * @ai: attach info object 23662306a36Sopenharmony_ci * @av: the volume this LEB belongs to 23762306a36Sopenharmony_ci * @new_vh: the volume header derived from new_aeb 23862306a36Sopenharmony_ci * @new_aeb: the AEB to be examined 23962306a36Sopenharmony_ci * 24062306a36Sopenharmony_ci * Returns 0 on success, < 0 indicates an internal error. 24162306a36Sopenharmony_ci */ 24262306a36Sopenharmony_cistatic int update_vol(struct ubi_device *ubi, struct ubi_attach_info *ai, 24362306a36Sopenharmony_ci struct ubi_ainf_volume *av, struct ubi_vid_hdr *new_vh, 24462306a36Sopenharmony_ci struct ubi_ainf_peb *new_aeb) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct rb_node **p = &av->root.rb_node, *parent = NULL; 24762306a36Sopenharmony_ci struct ubi_ainf_peb *aeb, *victim; 24862306a36Sopenharmony_ci int cmp_res; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci while (*p) { 25162306a36Sopenharmony_ci parent = *p; 25262306a36Sopenharmony_ci aeb = rb_entry(parent, struct ubi_ainf_peb, u.rb); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (be32_to_cpu(new_vh->lnum) != aeb->lnum) { 25562306a36Sopenharmony_ci if (be32_to_cpu(new_vh->lnum) < aeb->lnum) 25662306a36Sopenharmony_ci p = &(*p)->rb_left; 25762306a36Sopenharmony_ci else 25862306a36Sopenharmony_ci p = &(*p)->rb_right; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci continue; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* This case can happen if the fastmap gets written 26462306a36Sopenharmony_ci * because of a volume change (creation, deletion, ..). 26562306a36Sopenharmony_ci * Then a PEB can be within the persistent EBA and the pool. 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_ci if (aeb->pnum == new_aeb->pnum) { 26862306a36Sopenharmony_ci ubi_assert(aeb->lnum == new_aeb->lnum); 26962306a36Sopenharmony_ci ubi_free_aeb(ai, new_aeb); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci return 0; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci cmp_res = ubi_compare_lebs(ubi, aeb, new_aeb->pnum, new_vh); 27562306a36Sopenharmony_ci if (cmp_res < 0) 27662306a36Sopenharmony_ci return cmp_res; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* new_aeb is newer */ 27962306a36Sopenharmony_ci if (cmp_res & 1) { 28062306a36Sopenharmony_ci victim = ubi_alloc_aeb(ai, aeb->pnum, aeb->ec); 28162306a36Sopenharmony_ci if (!victim) 28262306a36Sopenharmony_ci return -ENOMEM; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci list_add_tail(&victim->u.list, &ai->erase); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (av->highest_lnum == be32_to_cpu(new_vh->lnum)) 28762306a36Sopenharmony_ci av->last_data_size = 28862306a36Sopenharmony_ci be32_to_cpu(new_vh->data_size); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci dbg_bld("vol %i: AEB %i's PEB %i is the newer", 29162306a36Sopenharmony_ci av->vol_id, aeb->lnum, new_aeb->pnum); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci aeb->ec = new_aeb->ec; 29462306a36Sopenharmony_ci aeb->pnum = new_aeb->pnum; 29562306a36Sopenharmony_ci aeb->copy_flag = new_vh->copy_flag; 29662306a36Sopenharmony_ci aeb->scrub = new_aeb->scrub; 29762306a36Sopenharmony_ci aeb->sqnum = new_aeb->sqnum; 29862306a36Sopenharmony_ci ubi_free_aeb(ai, new_aeb); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* new_aeb is older */ 30162306a36Sopenharmony_ci } else { 30262306a36Sopenharmony_ci dbg_bld("vol %i: AEB %i's PEB %i is old, dropping it", 30362306a36Sopenharmony_ci av->vol_id, aeb->lnum, new_aeb->pnum); 30462306a36Sopenharmony_ci list_add_tail(&new_aeb->u.list, &ai->erase); 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci return 0; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci /* This LEB is new, let's add it to the volume */ 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (av->highest_lnum <= be32_to_cpu(new_vh->lnum)) { 31262306a36Sopenharmony_ci av->highest_lnum = be32_to_cpu(new_vh->lnum); 31362306a36Sopenharmony_ci av->last_data_size = be32_to_cpu(new_vh->data_size); 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (av->vol_type == UBI_STATIC_VOLUME) 31762306a36Sopenharmony_ci av->used_ebs = be32_to_cpu(new_vh->used_ebs); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci av->leb_count++; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci rb_link_node(&new_aeb->u.rb, parent, p); 32262306a36Sopenharmony_ci rb_insert_color(&new_aeb->u.rb, &av->root); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci return 0; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci/** 32862306a36Sopenharmony_ci * process_pool_aeb - we found a non-empty PEB in a pool. 32962306a36Sopenharmony_ci * @ubi: UBI device object 33062306a36Sopenharmony_ci * @ai: attach info object 33162306a36Sopenharmony_ci * @new_vh: the volume header derived from new_aeb 33262306a36Sopenharmony_ci * @new_aeb: the AEB to be examined 33362306a36Sopenharmony_ci * 33462306a36Sopenharmony_ci * Returns 0 on success, < 0 indicates an internal error. 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_cistatic int process_pool_aeb(struct ubi_device *ubi, struct ubi_attach_info *ai, 33762306a36Sopenharmony_ci struct ubi_vid_hdr *new_vh, 33862306a36Sopenharmony_ci struct ubi_ainf_peb *new_aeb) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci int vol_id = be32_to_cpu(new_vh->vol_id); 34162306a36Sopenharmony_ci struct ubi_ainf_volume *av; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (vol_id == UBI_FM_SB_VOLUME_ID || vol_id == UBI_FM_DATA_VOLUME_ID) { 34462306a36Sopenharmony_ci ubi_free_aeb(ai, new_aeb); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return 0; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* Find the volume this SEB belongs to */ 35062306a36Sopenharmony_ci av = ubi_find_av(ai, vol_id); 35162306a36Sopenharmony_ci if (!av) { 35262306a36Sopenharmony_ci ubi_err(ubi, "orphaned volume in fastmap pool!"); 35362306a36Sopenharmony_ci ubi_free_aeb(ai, new_aeb); 35462306a36Sopenharmony_ci return UBI_BAD_FASTMAP; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci ubi_assert(vol_id == av->vol_id); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return update_vol(ubi, ai, av, new_vh, new_aeb); 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci/** 36362306a36Sopenharmony_ci * unmap_peb - unmap a PEB. 36462306a36Sopenharmony_ci * If fastmap detects a free PEB in the pool it has to check whether 36562306a36Sopenharmony_ci * this PEB has been unmapped after writing the fastmap. 36662306a36Sopenharmony_ci * 36762306a36Sopenharmony_ci * @ai: UBI attach info object 36862306a36Sopenharmony_ci * @pnum: The PEB to be unmapped 36962306a36Sopenharmony_ci */ 37062306a36Sopenharmony_cistatic void unmap_peb(struct ubi_attach_info *ai, int pnum) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci struct ubi_ainf_volume *av; 37362306a36Sopenharmony_ci struct rb_node *node, *node2; 37462306a36Sopenharmony_ci struct ubi_ainf_peb *aeb; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci ubi_rb_for_each_entry(node, av, &ai->volumes, rb) { 37762306a36Sopenharmony_ci ubi_rb_for_each_entry(node2, aeb, &av->root, u.rb) { 37862306a36Sopenharmony_ci if (aeb->pnum == pnum) { 37962306a36Sopenharmony_ci rb_erase(&aeb->u.rb, &av->root); 38062306a36Sopenharmony_ci av->leb_count--; 38162306a36Sopenharmony_ci ubi_free_aeb(ai, aeb); 38262306a36Sopenharmony_ci return; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci/** 38962306a36Sopenharmony_ci * scan_pool - scans a pool for changed (no longer empty PEBs). 39062306a36Sopenharmony_ci * @ubi: UBI device object 39162306a36Sopenharmony_ci * @ai: attach info object 39262306a36Sopenharmony_ci * @pebs: an array of all PEB numbers in the to be scanned pool 39362306a36Sopenharmony_ci * @pool_size: size of the pool (number of entries in @pebs) 39462306a36Sopenharmony_ci * @max_sqnum: pointer to the maximal sequence number 39562306a36Sopenharmony_ci * @free: list of PEBs which are most likely free (and go into @ai->free) 39662306a36Sopenharmony_ci * 39762306a36Sopenharmony_ci * Returns 0 on success, if the pool is unusable UBI_BAD_FASTMAP is returned. 39862306a36Sopenharmony_ci * < 0 indicates an internal error. 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_cistatic int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, 40162306a36Sopenharmony_ci __be32 *pebs, int pool_size, unsigned long long *max_sqnum, 40262306a36Sopenharmony_ci struct list_head *free) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci struct ubi_vid_io_buf *vb; 40562306a36Sopenharmony_ci struct ubi_vid_hdr *vh; 40662306a36Sopenharmony_ci struct ubi_ec_hdr *ech; 40762306a36Sopenharmony_ci struct ubi_ainf_peb *new_aeb; 40862306a36Sopenharmony_ci int i, pnum, err, ret = 0; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); 41162306a36Sopenharmony_ci if (!ech) 41262306a36Sopenharmony_ci return -ENOMEM; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci vb = ubi_alloc_vid_buf(ubi, GFP_KERNEL); 41562306a36Sopenharmony_ci if (!vb) { 41662306a36Sopenharmony_ci kfree(ech); 41762306a36Sopenharmony_ci return -ENOMEM; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci vh = ubi_get_vid_hdr(vb); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci dbg_bld("scanning fastmap pool: size = %i", pool_size); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* 42562306a36Sopenharmony_ci * Now scan all PEBs in the pool to find changes which have been made 42662306a36Sopenharmony_ci * after the creation of the fastmap 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_ci for (i = 0; i < pool_size; i++) { 42962306a36Sopenharmony_ci int scrub = 0; 43062306a36Sopenharmony_ci int image_seq; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci pnum = be32_to_cpu(pebs[i]); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (ubi_io_is_bad(ubi, pnum)) { 43562306a36Sopenharmony_ci ubi_err(ubi, "bad PEB in fastmap pool!"); 43662306a36Sopenharmony_ci ret = UBI_BAD_FASTMAP; 43762306a36Sopenharmony_ci goto out; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); 44162306a36Sopenharmony_ci if (err && err != UBI_IO_BITFLIPS) { 44262306a36Sopenharmony_ci ubi_err(ubi, "unable to read EC header! PEB:%i err:%i", 44362306a36Sopenharmony_ci pnum, err); 44462306a36Sopenharmony_ci ret = err > 0 ? UBI_BAD_FASTMAP : err; 44562306a36Sopenharmony_ci goto out; 44662306a36Sopenharmony_ci } else if (err == UBI_IO_BITFLIPS) 44762306a36Sopenharmony_ci scrub = 1; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* 45062306a36Sopenharmony_ci * Older UBI implementations have image_seq set to zero, so 45162306a36Sopenharmony_ci * we shouldn't fail if image_seq == 0. 45262306a36Sopenharmony_ci */ 45362306a36Sopenharmony_ci image_seq = be32_to_cpu(ech->image_seq); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (image_seq && (image_seq != ubi->image_seq)) { 45662306a36Sopenharmony_ci ubi_err(ubi, "bad image seq: 0x%x, expected: 0x%x", 45762306a36Sopenharmony_ci be32_to_cpu(ech->image_seq), ubi->image_seq); 45862306a36Sopenharmony_ci ret = UBI_BAD_FASTMAP; 45962306a36Sopenharmony_ci goto out; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci err = ubi_io_read_vid_hdr(ubi, pnum, vb, 0); 46362306a36Sopenharmony_ci if (err == UBI_IO_FF || err == UBI_IO_FF_BITFLIPS) { 46462306a36Sopenharmony_ci unsigned long long ec = be64_to_cpu(ech->ec); 46562306a36Sopenharmony_ci unmap_peb(ai, pnum); 46662306a36Sopenharmony_ci dbg_bld("Adding PEB to free: %i", pnum); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (err == UBI_IO_FF_BITFLIPS) 46962306a36Sopenharmony_ci scrub = 1; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci ret = add_aeb(ai, free, pnum, ec, scrub); 47262306a36Sopenharmony_ci if (ret) 47362306a36Sopenharmony_ci goto out; 47462306a36Sopenharmony_ci continue; 47562306a36Sopenharmony_ci } else if (err == 0 || err == UBI_IO_BITFLIPS) { 47662306a36Sopenharmony_ci dbg_bld("Found non empty PEB:%i in pool", pnum); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (err == UBI_IO_BITFLIPS) 47962306a36Sopenharmony_ci scrub = 1; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci new_aeb = ubi_alloc_aeb(ai, pnum, be64_to_cpu(ech->ec)); 48262306a36Sopenharmony_ci if (!new_aeb) { 48362306a36Sopenharmony_ci ret = -ENOMEM; 48462306a36Sopenharmony_ci goto out; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci new_aeb->lnum = be32_to_cpu(vh->lnum); 48862306a36Sopenharmony_ci new_aeb->sqnum = be64_to_cpu(vh->sqnum); 48962306a36Sopenharmony_ci new_aeb->copy_flag = vh->copy_flag; 49062306a36Sopenharmony_ci new_aeb->scrub = scrub; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (*max_sqnum < new_aeb->sqnum) 49362306a36Sopenharmony_ci *max_sqnum = new_aeb->sqnum; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci err = process_pool_aeb(ubi, ai, vh, new_aeb); 49662306a36Sopenharmony_ci if (err) { 49762306a36Sopenharmony_ci ret = err > 0 ? UBI_BAD_FASTMAP : err; 49862306a36Sopenharmony_ci goto out; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci } else { 50162306a36Sopenharmony_ci /* We are paranoid and fall back to scanning mode */ 50262306a36Sopenharmony_ci ubi_err(ubi, "fastmap pool PEBs contains damaged PEBs!"); 50362306a36Sopenharmony_ci ret = err > 0 ? UBI_BAD_FASTMAP : err; 50462306a36Sopenharmony_ci goto out; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ciout: 51062306a36Sopenharmony_ci ubi_free_vid_buf(vb); 51162306a36Sopenharmony_ci kfree(ech); 51262306a36Sopenharmony_ci return ret; 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci/** 51662306a36Sopenharmony_ci * count_fastmap_pebs - Counts the PEBs found by fastmap. 51762306a36Sopenharmony_ci * @ai: The UBI attach info object 51862306a36Sopenharmony_ci */ 51962306a36Sopenharmony_cistatic int count_fastmap_pebs(struct ubi_attach_info *ai) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci struct ubi_ainf_peb *aeb; 52262306a36Sopenharmony_ci struct ubi_ainf_volume *av; 52362306a36Sopenharmony_ci struct rb_node *rb1, *rb2; 52462306a36Sopenharmony_ci int n = 0; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci list_for_each_entry(aeb, &ai->erase, u.list) 52762306a36Sopenharmony_ci n++; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci list_for_each_entry(aeb, &ai->free, u.list) 53062306a36Sopenharmony_ci n++; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) 53362306a36Sopenharmony_ci ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb) 53462306a36Sopenharmony_ci n++; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return n; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci/** 54062306a36Sopenharmony_ci * ubi_attach_fastmap - creates ubi_attach_info from a fastmap. 54162306a36Sopenharmony_ci * @ubi: UBI device object 54262306a36Sopenharmony_ci * @ai: UBI attach info object 54362306a36Sopenharmony_ci * @fm: the fastmap to be attached 54462306a36Sopenharmony_ci * 54562306a36Sopenharmony_ci * Returns 0 on success, UBI_BAD_FASTMAP if the found fastmap was unusable. 54662306a36Sopenharmony_ci * < 0 indicates an internal error. 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_cistatic int ubi_attach_fastmap(struct ubi_device *ubi, 54962306a36Sopenharmony_ci struct ubi_attach_info *ai, 55062306a36Sopenharmony_ci struct ubi_fastmap_layout *fm) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct list_head used, free; 55362306a36Sopenharmony_ci struct ubi_ainf_volume *av; 55462306a36Sopenharmony_ci struct ubi_ainf_peb *aeb, *tmp_aeb, *_tmp_aeb; 55562306a36Sopenharmony_ci struct ubi_fm_sb *fmsb; 55662306a36Sopenharmony_ci struct ubi_fm_hdr *fmhdr; 55762306a36Sopenharmony_ci struct ubi_fm_scan_pool *fmpl, *fmpl_wl; 55862306a36Sopenharmony_ci struct ubi_fm_ec *fmec; 55962306a36Sopenharmony_ci struct ubi_fm_volhdr *fmvhdr; 56062306a36Sopenharmony_ci struct ubi_fm_eba *fm_eba; 56162306a36Sopenharmony_ci int ret, i, j, pool_size, wl_pool_size; 56262306a36Sopenharmony_ci size_t fm_pos = 0, fm_size = ubi->fm_size; 56362306a36Sopenharmony_ci unsigned long long max_sqnum = 0; 56462306a36Sopenharmony_ci void *fm_raw = ubi->fm_buf; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci INIT_LIST_HEAD(&used); 56762306a36Sopenharmony_ci INIT_LIST_HEAD(&free); 56862306a36Sopenharmony_ci ai->min_ec = UBI_MAX_ERASECOUNTER; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci fmsb = (struct ubi_fm_sb *)(fm_raw); 57162306a36Sopenharmony_ci ai->max_sqnum = fmsb->sqnum; 57262306a36Sopenharmony_ci fm_pos += sizeof(struct ubi_fm_sb); 57362306a36Sopenharmony_ci if (fm_pos >= fm_size) 57462306a36Sopenharmony_ci goto fail_bad; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci fmhdr = (struct ubi_fm_hdr *)(fm_raw + fm_pos); 57762306a36Sopenharmony_ci fm_pos += sizeof(*fmhdr); 57862306a36Sopenharmony_ci if (fm_pos >= fm_size) 57962306a36Sopenharmony_ci goto fail_bad; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (be32_to_cpu(fmhdr->magic) != UBI_FM_HDR_MAGIC) { 58262306a36Sopenharmony_ci ubi_err(ubi, "bad fastmap header magic: 0x%x, expected: 0x%x", 58362306a36Sopenharmony_ci be32_to_cpu(fmhdr->magic), UBI_FM_HDR_MAGIC); 58462306a36Sopenharmony_ci goto fail_bad; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci fmpl = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos); 58862306a36Sopenharmony_ci fm_pos += sizeof(*fmpl); 58962306a36Sopenharmony_ci if (fm_pos >= fm_size) 59062306a36Sopenharmony_ci goto fail_bad; 59162306a36Sopenharmony_ci if (be32_to_cpu(fmpl->magic) != UBI_FM_POOL_MAGIC) { 59262306a36Sopenharmony_ci ubi_err(ubi, "bad fastmap pool magic: 0x%x, expected: 0x%x", 59362306a36Sopenharmony_ci be32_to_cpu(fmpl->magic), UBI_FM_POOL_MAGIC); 59462306a36Sopenharmony_ci goto fail_bad; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci fmpl_wl = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos); 59862306a36Sopenharmony_ci fm_pos += sizeof(*fmpl_wl); 59962306a36Sopenharmony_ci if (fm_pos >= fm_size) 60062306a36Sopenharmony_ci goto fail_bad; 60162306a36Sopenharmony_ci if (be32_to_cpu(fmpl_wl->magic) != UBI_FM_POOL_MAGIC) { 60262306a36Sopenharmony_ci ubi_err(ubi, "bad fastmap WL pool magic: 0x%x, expected: 0x%x", 60362306a36Sopenharmony_ci be32_to_cpu(fmpl_wl->magic), UBI_FM_POOL_MAGIC); 60462306a36Sopenharmony_ci goto fail_bad; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci pool_size = be16_to_cpu(fmpl->size); 60862306a36Sopenharmony_ci wl_pool_size = be16_to_cpu(fmpl_wl->size); 60962306a36Sopenharmony_ci fm->max_pool_size = be16_to_cpu(fmpl->max_size); 61062306a36Sopenharmony_ci fm->max_wl_pool_size = be16_to_cpu(fmpl_wl->max_size); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci if (pool_size > UBI_FM_MAX_POOL_SIZE || pool_size < 0) { 61362306a36Sopenharmony_ci ubi_err(ubi, "bad pool size: %i", pool_size); 61462306a36Sopenharmony_ci goto fail_bad; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci if (wl_pool_size > UBI_FM_MAX_POOL_SIZE || wl_pool_size < 0) { 61862306a36Sopenharmony_ci ubi_err(ubi, "bad WL pool size: %i", wl_pool_size); 61962306a36Sopenharmony_ci goto fail_bad; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (fm->max_pool_size > UBI_FM_MAX_POOL_SIZE || 62462306a36Sopenharmony_ci fm->max_pool_size < 0) { 62562306a36Sopenharmony_ci ubi_err(ubi, "bad maximal pool size: %i", fm->max_pool_size); 62662306a36Sopenharmony_ci goto fail_bad; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (fm->max_wl_pool_size > UBI_FM_MAX_POOL_SIZE || 63062306a36Sopenharmony_ci fm->max_wl_pool_size < 0) { 63162306a36Sopenharmony_ci ubi_err(ubi, "bad maximal WL pool size: %i", 63262306a36Sopenharmony_ci fm->max_wl_pool_size); 63362306a36Sopenharmony_ci goto fail_bad; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci /* read EC values from free list */ 63762306a36Sopenharmony_ci for (i = 0; i < be32_to_cpu(fmhdr->free_peb_count); i++) { 63862306a36Sopenharmony_ci fmec = (struct ubi_fm_ec *)(fm_raw + fm_pos); 63962306a36Sopenharmony_ci fm_pos += sizeof(*fmec); 64062306a36Sopenharmony_ci if (fm_pos >= fm_size) 64162306a36Sopenharmony_ci goto fail_bad; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci ret = add_aeb(ai, &ai->free, be32_to_cpu(fmec->pnum), 64462306a36Sopenharmony_ci be32_to_cpu(fmec->ec), 0); 64562306a36Sopenharmony_ci if (ret) 64662306a36Sopenharmony_ci goto fail; 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* read EC values from used list */ 65062306a36Sopenharmony_ci for (i = 0; i < be32_to_cpu(fmhdr->used_peb_count); i++) { 65162306a36Sopenharmony_ci fmec = (struct ubi_fm_ec *)(fm_raw + fm_pos); 65262306a36Sopenharmony_ci fm_pos += sizeof(*fmec); 65362306a36Sopenharmony_ci if (fm_pos >= fm_size) 65462306a36Sopenharmony_ci goto fail_bad; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci ret = add_aeb(ai, &used, be32_to_cpu(fmec->pnum), 65762306a36Sopenharmony_ci be32_to_cpu(fmec->ec), 0); 65862306a36Sopenharmony_ci if (ret) 65962306a36Sopenharmony_ci goto fail; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* read EC values from scrub list */ 66362306a36Sopenharmony_ci for (i = 0; i < be32_to_cpu(fmhdr->scrub_peb_count); i++) { 66462306a36Sopenharmony_ci fmec = (struct ubi_fm_ec *)(fm_raw + fm_pos); 66562306a36Sopenharmony_ci fm_pos += sizeof(*fmec); 66662306a36Sopenharmony_ci if (fm_pos >= fm_size) 66762306a36Sopenharmony_ci goto fail_bad; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci ret = add_aeb(ai, &used, be32_to_cpu(fmec->pnum), 67062306a36Sopenharmony_ci be32_to_cpu(fmec->ec), 1); 67162306a36Sopenharmony_ci if (ret) 67262306a36Sopenharmony_ci goto fail; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* read EC values from erase list */ 67662306a36Sopenharmony_ci for (i = 0; i < be32_to_cpu(fmhdr->erase_peb_count); i++) { 67762306a36Sopenharmony_ci fmec = (struct ubi_fm_ec *)(fm_raw + fm_pos); 67862306a36Sopenharmony_ci fm_pos += sizeof(*fmec); 67962306a36Sopenharmony_ci if (fm_pos >= fm_size) 68062306a36Sopenharmony_ci goto fail_bad; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci ret = add_aeb(ai, &ai->erase, be32_to_cpu(fmec->pnum), 68362306a36Sopenharmony_ci be32_to_cpu(fmec->ec), 1); 68462306a36Sopenharmony_ci if (ret) 68562306a36Sopenharmony_ci goto fail; 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci ai->mean_ec = div_u64(ai->ec_sum, ai->ec_count); 68962306a36Sopenharmony_ci ai->bad_peb_count = be32_to_cpu(fmhdr->bad_peb_count); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci /* Iterate over all volumes and read their EBA table */ 69262306a36Sopenharmony_ci for (i = 0; i < be32_to_cpu(fmhdr->vol_count); i++) { 69362306a36Sopenharmony_ci fmvhdr = (struct ubi_fm_volhdr *)(fm_raw + fm_pos); 69462306a36Sopenharmony_ci fm_pos += sizeof(*fmvhdr); 69562306a36Sopenharmony_ci if (fm_pos >= fm_size) 69662306a36Sopenharmony_ci goto fail_bad; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci if (be32_to_cpu(fmvhdr->magic) != UBI_FM_VHDR_MAGIC) { 69962306a36Sopenharmony_ci ubi_err(ubi, "bad fastmap vol header magic: 0x%x, expected: 0x%x", 70062306a36Sopenharmony_ci be32_to_cpu(fmvhdr->magic), UBI_FM_VHDR_MAGIC); 70162306a36Sopenharmony_ci goto fail_bad; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci av = add_vol(ai, be32_to_cpu(fmvhdr->vol_id), 70562306a36Sopenharmony_ci be32_to_cpu(fmvhdr->used_ebs), 70662306a36Sopenharmony_ci be32_to_cpu(fmvhdr->data_pad), 70762306a36Sopenharmony_ci fmvhdr->vol_type, 70862306a36Sopenharmony_ci be32_to_cpu(fmvhdr->last_eb_bytes)); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (IS_ERR(av)) { 71162306a36Sopenharmony_ci if (PTR_ERR(av) == -EEXIST) 71262306a36Sopenharmony_ci ubi_err(ubi, "volume (ID %i) already exists", 71362306a36Sopenharmony_ci fmvhdr->vol_id); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci goto fail_bad; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci ai->vols_found++; 71962306a36Sopenharmony_ci if (ai->highest_vol_id < be32_to_cpu(fmvhdr->vol_id)) 72062306a36Sopenharmony_ci ai->highest_vol_id = be32_to_cpu(fmvhdr->vol_id); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci fm_eba = (struct ubi_fm_eba *)(fm_raw + fm_pos); 72362306a36Sopenharmony_ci fm_pos += sizeof(*fm_eba); 72462306a36Sopenharmony_ci fm_pos += (sizeof(__be32) * be32_to_cpu(fm_eba->reserved_pebs)); 72562306a36Sopenharmony_ci if (fm_pos >= fm_size) 72662306a36Sopenharmony_ci goto fail_bad; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (be32_to_cpu(fm_eba->magic) != UBI_FM_EBA_MAGIC) { 72962306a36Sopenharmony_ci ubi_err(ubi, "bad fastmap EBA header magic: 0x%x, expected: 0x%x", 73062306a36Sopenharmony_ci be32_to_cpu(fm_eba->magic), UBI_FM_EBA_MAGIC); 73162306a36Sopenharmony_ci goto fail_bad; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci for (j = 0; j < be32_to_cpu(fm_eba->reserved_pebs); j++) { 73562306a36Sopenharmony_ci int pnum = be32_to_cpu(fm_eba->pnum[j]); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (pnum < 0) 73862306a36Sopenharmony_ci continue; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci aeb = NULL; 74162306a36Sopenharmony_ci list_for_each_entry(tmp_aeb, &used, u.list) { 74262306a36Sopenharmony_ci if (tmp_aeb->pnum == pnum) { 74362306a36Sopenharmony_ci aeb = tmp_aeb; 74462306a36Sopenharmony_ci break; 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (!aeb) { 74962306a36Sopenharmony_ci ubi_err(ubi, "PEB %i is in EBA but not in used list", pnum); 75062306a36Sopenharmony_ci goto fail_bad; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci aeb->lnum = j; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (av->highest_lnum <= aeb->lnum) 75662306a36Sopenharmony_ci av->highest_lnum = aeb->lnum; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci assign_aeb_to_av(ai, aeb, av); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci dbg_bld("inserting PEB:%i (LEB %i) to vol %i", 76162306a36Sopenharmony_ci aeb->pnum, aeb->lnum, av->vol_id); 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci ret = scan_pool(ubi, ai, fmpl->pebs, pool_size, &max_sqnum, &free); 76662306a36Sopenharmony_ci if (ret) 76762306a36Sopenharmony_ci goto fail; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci ret = scan_pool(ubi, ai, fmpl_wl->pebs, wl_pool_size, &max_sqnum, &free); 77062306a36Sopenharmony_ci if (ret) 77162306a36Sopenharmony_ci goto fail; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci if (max_sqnum > ai->max_sqnum) 77462306a36Sopenharmony_ci ai->max_sqnum = max_sqnum; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list) 77762306a36Sopenharmony_ci list_move_tail(&tmp_aeb->u.list, &ai->free); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &used, u.list) 78062306a36Sopenharmony_ci list_move_tail(&tmp_aeb->u.list, &ai->erase); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci ubi_assert(list_empty(&free)); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci /* 78562306a36Sopenharmony_ci * If fastmap is leaking PEBs (must not happen), raise a 78662306a36Sopenharmony_ci * fat warning and fall back to scanning mode. 78762306a36Sopenharmony_ci * We do this here because in ubi_wl_init() it's too late 78862306a36Sopenharmony_ci * and we cannot fall back to scanning. 78962306a36Sopenharmony_ci */ 79062306a36Sopenharmony_ci if (WARN_ON(count_fastmap_pebs(ai) != ubi->peb_count - 79162306a36Sopenharmony_ci ai->bad_peb_count - fm->used_blocks)) 79262306a36Sopenharmony_ci goto fail_bad; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci return 0; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_cifail_bad: 79762306a36Sopenharmony_ci ret = UBI_BAD_FASTMAP; 79862306a36Sopenharmony_cifail: 79962306a36Sopenharmony_ci list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &used, u.list) { 80062306a36Sopenharmony_ci list_del(&tmp_aeb->u.list); 80162306a36Sopenharmony_ci ubi_free_aeb(ai, tmp_aeb); 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list) { 80462306a36Sopenharmony_ci list_del(&tmp_aeb->u.list); 80562306a36Sopenharmony_ci ubi_free_aeb(ai, tmp_aeb); 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci return ret; 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci/** 81262306a36Sopenharmony_ci * find_fm_anchor - find the most recent Fastmap superblock (anchor) 81362306a36Sopenharmony_ci * @ai: UBI attach info to be filled 81462306a36Sopenharmony_ci */ 81562306a36Sopenharmony_cistatic int find_fm_anchor(struct ubi_attach_info *ai) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci int ret = -1; 81862306a36Sopenharmony_ci struct ubi_ainf_peb *aeb; 81962306a36Sopenharmony_ci unsigned long long max_sqnum = 0; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci list_for_each_entry(aeb, &ai->fastmap, u.list) { 82262306a36Sopenharmony_ci if (aeb->vol_id == UBI_FM_SB_VOLUME_ID && aeb->sqnum > max_sqnum) { 82362306a36Sopenharmony_ci max_sqnum = aeb->sqnum; 82462306a36Sopenharmony_ci ret = aeb->pnum; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci return ret; 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic struct ubi_ainf_peb *clone_aeb(struct ubi_attach_info *ai, 83262306a36Sopenharmony_ci struct ubi_ainf_peb *old) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci struct ubi_ainf_peb *new; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci new = ubi_alloc_aeb(ai, old->pnum, old->ec); 83762306a36Sopenharmony_ci if (!new) 83862306a36Sopenharmony_ci return NULL; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci new->vol_id = old->vol_id; 84162306a36Sopenharmony_ci new->sqnum = old->sqnum; 84262306a36Sopenharmony_ci new->lnum = old->lnum; 84362306a36Sopenharmony_ci new->scrub = old->scrub; 84462306a36Sopenharmony_ci new->copy_flag = old->copy_flag; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci return new; 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci/** 85062306a36Sopenharmony_ci * ubi_scan_fastmap - scan the fastmap. 85162306a36Sopenharmony_ci * @ubi: UBI device object 85262306a36Sopenharmony_ci * @ai: UBI attach info to be filled 85362306a36Sopenharmony_ci * @scan_ai: UBI attach info from the first 64 PEBs, 85462306a36Sopenharmony_ci * used to find the most recent Fastmap data structure 85562306a36Sopenharmony_ci * 85662306a36Sopenharmony_ci * Returns 0 on success, UBI_NO_FASTMAP if no fastmap was found, 85762306a36Sopenharmony_ci * UBI_BAD_FASTMAP if one was found but is not usable. 85862306a36Sopenharmony_ci * < 0 indicates an internal error. 85962306a36Sopenharmony_ci */ 86062306a36Sopenharmony_ciint ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, 86162306a36Sopenharmony_ci struct ubi_attach_info *scan_ai) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci struct ubi_fm_sb *fmsb, *fmsb2; 86462306a36Sopenharmony_ci struct ubi_vid_io_buf *vb; 86562306a36Sopenharmony_ci struct ubi_vid_hdr *vh; 86662306a36Sopenharmony_ci struct ubi_ec_hdr *ech; 86762306a36Sopenharmony_ci struct ubi_fastmap_layout *fm; 86862306a36Sopenharmony_ci struct ubi_ainf_peb *aeb; 86962306a36Sopenharmony_ci int i, used_blocks, pnum, fm_anchor, ret = 0; 87062306a36Sopenharmony_ci size_t fm_size; 87162306a36Sopenharmony_ci __be32 crc, tmp_crc; 87262306a36Sopenharmony_ci unsigned long long sqnum = 0; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci fm_anchor = find_fm_anchor(scan_ai); 87562306a36Sopenharmony_ci if (fm_anchor < 0) 87662306a36Sopenharmony_ci return UBI_NO_FASTMAP; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci /* Copy all (possible) fastmap blocks into our new attach structure. */ 87962306a36Sopenharmony_ci list_for_each_entry(aeb, &scan_ai->fastmap, u.list) { 88062306a36Sopenharmony_ci struct ubi_ainf_peb *new; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci new = clone_aeb(ai, aeb); 88362306a36Sopenharmony_ci if (!new) 88462306a36Sopenharmony_ci return -ENOMEM; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci list_add(&new->u.list, &ai->fastmap); 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci down_write(&ubi->fm_protect); 89062306a36Sopenharmony_ci memset(ubi->fm_buf, 0, ubi->fm_size); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci fmsb = kmalloc(sizeof(*fmsb), GFP_KERNEL); 89362306a36Sopenharmony_ci if (!fmsb) { 89462306a36Sopenharmony_ci ret = -ENOMEM; 89562306a36Sopenharmony_ci goto out; 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci fm = kzalloc(sizeof(*fm), GFP_KERNEL); 89962306a36Sopenharmony_ci if (!fm) { 90062306a36Sopenharmony_ci ret = -ENOMEM; 90162306a36Sopenharmony_ci kfree(fmsb); 90262306a36Sopenharmony_ci goto out; 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci ret = ubi_io_read_data(ubi, fmsb, fm_anchor, 0, sizeof(*fmsb)); 90662306a36Sopenharmony_ci if (ret && ret != UBI_IO_BITFLIPS) 90762306a36Sopenharmony_ci goto free_fm_sb; 90862306a36Sopenharmony_ci else if (ret == UBI_IO_BITFLIPS) 90962306a36Sopenharmony_ci fm->to_be_tortured[0] = 1; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci if (be32_to_cpu(fmsb->magic) != UBI_FM_SB_MAGIC) { 91262306a36Sopenharmony_ci ubi_err(ubi, "bad super block magic: 0x%x, expected: 0x%x", 91362306a36Sopenharmony_ci be32_to_cpu(fmsb->magic), UBI_FM_SB_MAGIC); 91462306a36Sopenharmony_ci ret = UBI_BAD_FASTMAP; 91562306a36Sopenharmony_ci goto free_fm_sb; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (fmsb->version != UBI_FM_FMT_VERSION) { 91962306a36Sopenharmony_ci ubi_err(ubi, "bad fastmap version: %i, expected: %i", 92062306a36Sopenharmony_ci fmsb->version, UBI_FM_FMT_VERSION); 92162306a36Sopenharmony_ci ret = UBI_BAD_FASTMAP; 92262306a36Sopenharmony_ci goto free_fm_sb; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci used_blocks = be32_to_cpu(fmsb->used_blocks); 92662306a36Sopenharmony_ci if (used_blocks > UBI_FM_MAX_BLOCKS || used_blocks < 1) { 92762306a36Sopenharmony_ci ubi_err(ubi, "number of fastmap blocks is invalid: %i", 92862306a36Sopenharmony_ci used_blocks); 92962306a36Sopenharmony_ci ret = UBI_BAD_FASTMAP; 93062306a36Sopenharmony_ci goto free_fm_sb; 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci fm_size = ubi->leb_size * used_blocks; 93462306a36Sopenharmony_ci if (fm_size != ubi->fm_size) { 93562306a36Sopenharmony_ci ubi_err(ubi, "bad fastmap size: %zi, expected: %zi", 93662306a36Sopenharmony_ci fm_size, ubi->fm_size); 93762306a36Sopenharmony_ci ret = UBI_BAD_FASTMAP; 93862306a36Sopenharmony_ci goto free_fm_sb; 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); 94262306a36Sopenharmony_ci if (!ech) { 94362306a36Sopenharmony_ci ret = -ENOMEM; 94462306a36Sopenharmony_ci goto free_fm_sb; 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci vb = ubi_alloc_vid_buf(ubi, GFP_KERNEL); 94862306a36Sopenharmony_ci if (!vb) { 94962306a36Sopenharmony_ci ret = -ENOMEM; 95062306a36Sopenharmony_ci goto free_hdr; 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci vh = ubi_get_vid_hdr(vb); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci for (i = 0; i < used_blocks; i++) { 95662306a36Sopenharmony_ci int image_seq; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci pnum = be32_to_cpu(fmsb->block_loc[i]); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci if (ubi_io_is_bad(ubi, pnum)) { 96162306a36Sopenharmony_ci ret = UBI_BAD_FASTMAP; 96262306a36Sopenharmony_ci goto free_hdr; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci if (i == 0 && pnum != fm_anchor) { 96662306a36Sopenharmony_ci ubi_err(ubi, "Fastmap anchor PEB mismatch: PEB: %i vs. %i", 96762306a36Sopenharmony_ci pnum, fm_anchor); 96862306a36Sopenharmony_ci ret = UBI_BAD_FASTMAP; 96962306a36Sopenharmony_ci goto free_hdr; 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci ret = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); 97362306a36Sopenharmony_ci if (ret && ret != UBI_IO_BITFLIPS) { 97462306a36Sopenharmony_ci ubi_err(ubi, "unable to read fastmap block# %i EC (PEB: %i)", 97562306a36Sopenharmony_ci i, pnum); 97662306a36Sopenharmony_ci if (ret > 0) 97762306a36Sopenharmony_ci ret = UBI_BAD_FASTMAP; 97862306a36Sopenharmony_ci goto free_hdr; 97962306a36Sopenharmony_ci } else if (ret == UBI_IO_BITFLIPS) 98062306a36Sopenharmony_ci fm->to_be_tortured[i] = 1; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci image_seq = be32_to_cpu(ech->image_seq); 98362306a36Sopenharmony_ci if (!ubi->image_seq) 98462306a36Sopenharmony_ci ubi->image_seq = image_seq; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci /* 98762306a36Sopenharmony_ci * Older UBI implementations have image_seq set to zero, so 98862306a36Sopenharmony_ci * we shouldn't fail if image_seq == 0. 98962306a36Sopenharmony_ci */ 99062306a36Sopenharmony_ci if (image_seq && (image_seq != ubi->image_seq)) { 99162306a36Sopenharmony_ci ubi_err(ubi, "wrong image seq:%d instead of %d", 99262306a36Sopenharmony_ci be32_to_cpu(ech->image_seq), ubi->image_seq); 99362306a36Sopenharmony_ci ret = UBI_BAD_FASTMAP; 99462306a36Sopenharmony_ci goto free_hdr; 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci ret = ubi_io_read_vid_hdr(ubi, pnum, vb, 0); 99862306a36Sopenharmony_ci if (ret && ret != UBI_IO_BITFLIPS) { 99962306a36Sopenharmony_ci ubi_err(ubi, "unable to read fastmap block# %i (PEB: %i)", 100062306a36Sopenharmony_ci i, pnum); 100162306a36Sopenharmony_ci goto free_hdr; 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci if (i == 0) { 100562306a36Sopenharmony_ci if (be32_to_cpu(vh->vol_id) != UBI_FM_SB_VOLUME_ID) { 100662306a36Sopenharmony_ci ubi_err(ubi, "bad fastmap anchor vol_id: 0x%x, expected: 0x%x", 100762306a36Sopenharmony_ci be32_to_cpu(vh->vol_id), 100862306a36Sopenharmony_ci UBI_FM_SB_VOLUME_ID); 100962306a36Sopenharmony_ci ret = UBI_BAD_FASTMAP; 101062306a36Sopenharmony_ci goto free_hdr; 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci } else { 101362306a36Sopenharmony_ci if (be32_to_cpu(vh->vol_id) != UBI_FM_DATA_VOLUME_ID) { 101462306a36Sopenharmony_ci ubi_err(ubi, "bad fastmap data vol_id: 0x%x, expected: 0x%x", 101562306a36Sopenharmony_ci be32_to_cpu(vh->vol_id), 101662306a36Sopenharmony_ci UBI_FM_DATA_VOLUME_ID); 101762306a36Sopenharmony_ci ret = UBI_BAD_FASTMAP; 101862306a36Sopenharmony_ci goto free_hdr; 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci if (sqnum < be64_to_cpu(vh->sqnum)) 102362306a36Sopenharmony_ci sqnum = be64_to_cpu(vh->sqnum); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci ret = ubi_io_read_data(ubi, ubi->fm_buf + (ubi->leb_size * i), 102662306a36Sopenharmony_ci pnum, 0, ubi->leb_size); 102762306a36Sopenharmony_ci if (ret && ret != UBI_IO_BITFLIPS) { 102862306a36Sopenharmony_ci ubi_err(ubi, "unable to read fastmap block# %i (PEB: %i, " 102962306a36Sopenharmony_ci "err: %i)", i, pnum, ret); 103062306a36Sopenharmony_ci goto free_hdr; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci kfree(fmsb); 103562306a36Sopenharmony_ci fmsb = NULL; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci fmsb2 = (struct ubi_fm_sb *)(ubi->fm_buf); 103862306a36Sopenharmony_ci tmp_crc = be32_to_cpu(fmsb2->data_crc); 103962306a36Sopenharmony_ci fmsb2->data_crc = 0; 104062306a36Sopenharmony_ci crc = crc32(UBI_CRC32_INIT, ubi->fm_buf, fm_size); 104162306a36Sopenharmony_ci if (crc != tmp_crc) { 104262306a36Sopenharmony_ci ubi_err(ubi, "fastmap data CRC is invalid"); 104362306a36Sopenharmony_ci ubi_err(ubi, "CRC should be: 0x%x, calc: 0x%x", 104462306a36Sopenharmony_ci tmp_crc, crc); 104562306a36Sopenharmony_ci ret = UBI_BAD_FASTMAP; 104662306a36Sopenharmony_ci goto free_hdr; 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci fmsb2->sqnum = sqnum; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci fm->used_blocks = used_blocks; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci ret = ubi_attach_fastmap(ubi, ai, fm); 105462306a36Sopenharmony_ci if (ret) { 105562306a36Sopenharmony_ci if (ret > 0) 105662306a36Sopenharmony_ci ret = UBI_BAD_FASTMAP; 105762306a36Sopenharmony_ci goto free_hdr; 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci for (i = 0; i < used_blocks; i++) { 106162306a36Sopenharmony_ci struct ubi_wl_entry *e; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); 106462306a36Sopenharmony_ci if (!e) { 106562306a36Sopenharmony_ci while (i--) 106662306a36Sopenharmony_ci kmem_cache_free(ubi_wl_entry_slab, fm->e[i]); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci ret = -ENOMEM; 106962306a36Sopenharmony_ci goto free_hdr; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci e->pnum = be32_to_cpu(fmsb2->block_loc[i]); 107362306a36Sopenharmony_ci e->ec = be32_to_cpu(fmsb2->block_ec[i]); 107462306a36Sopenharmony_ci fm->e[i] = e; 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci ubi->fm = fm; 107862306a36Sopenharmony_ci ubi->fm_pool.max_size = ubi->fm->max_pool_size; 107962306a36Sopenharmony_ci ubi->fm_wl_pool.max_size = ubi->fm->max_wl_pool_size; 108062306a36Sopenharmony_ci ubi_msg(ubi, "attached by fastmap"); 108162306a36Sopenharmony_ci ubi_msg(ubi, "fastmap pool size: %d", ubi->fm_pool.max_size); 108262306a36Sopenharmony_ci ubi_msg(ubi, "fastmap WL pool size: %d", 108362306a36Sopenharmony_ci ubi->fm_wl_pool.max_size); 108462306a36Sopenharmony_ci ubi->fm_disabled = 0; 108562306a36Sopenharmony_ci ubi->fast_attach = 1; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci ubi_free_vid_buf(vb); 108862306a36Sopenharmony_ci kfree(ech); 108962306a36Sopenharmony_ciout: 109062306a36Sopenharmony_ci up_write(&ubi->fm_protect); 109162306a36Sopenharmony_ci if (ret == UBI_BAD_FASTMAP) 109262306a36Sopenharmony_ci ubi_err(ubi, "Attach by fastmap failed, doing a full scan!"); 109362306a36Sopenharmony_ci return ret; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_cifree_hdr: 109662306a36Sopenharmony_ci ubi_free_vid_buf(vb); 109762306a36Sopenharmony_ci kfree(ech); 109862306a36Sopenharmony_cifree_fm_sb: 109962306a36Sopenharmony_ci kfree(fmsb); 110062306a36Sopenharmony_ci kfree(fm); 110162306a36Sopenharmony_ci goto out; 110262306a36Sopenharmony_ci} 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ciint ubi_fastmap_init_checkmap(struct ubi_volume *vol, int leb_count) 110562306a36Sopenharmony_ci{ 110662306a36Sopenharmony_ci struct ubi_device *ubi = vol->ubi; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (!ubi->fast_attach) 110962306a36Sopenharmony_ci return 0; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci vol->checkmap = bitmap_zalloc(leb_count, GFP_KERNEL); 111262306a36Sopenharmony_ci if (!vol->checkmap) 111362306a36Sopenharmony_ci return -ENOMEM; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci return 0; 111662306a36Sopenharmony_ci} 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_civoid ubi_fastmap_destroy_checkmap(struct ubi_volume *vol) 111962306a36Sopenharmony_ci{ 112062306a36Sopenharmony_ci bitmap_free(vol->checkmap); 112162306a36Sopenharmony_ci} 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci/** 112462306a36Sopenharmony_ci * ubi_write_fastmap - writes a fastmap. 112562306a36Sopenharmony_ci * @ubi: UBI device object 112662306a36Sopenharmony_ci * @new_fm: the to be written fastmap 112762306a36Sopenharmony_ci * 112862306a36Sopenharmony_ci * Returns 0 on success, < 0 indicates an internal error. 112962306a36Sopenharmony_ci */ 113062306a36Sopenharmony_cistatic int ubi_write_fastmap(struct ubi_device *ubi, 113162306a36Sopenharmony_ci struct ubi_fastmap_layout *new_fm) 113262306a36Sopenharmony_ci{ 113362306a36Sopenharmony_ci size_t fm_pos = 0; 113462306a36Sopenharmony_ci void *fm_raw; 113562306a36Sopenharmony_ci struct ubi_fm_sb *fmsb; 113662306a36Sopenharmony_ci struct ubi_fm_hdr *fmh; 113762306a36Sopenharmony_ci struct ubi_fm_scan_pool *fmpl, *fmpl_wl; 113862306a36Sopenharmony_ci struct ubi_fm_ec *fec; 113962306a36Sopenharmony_ci struct ubi_fm_volhdr *fvh; 114062306a36Sopenharmony_ci struct ubi_fm_eba *feba; 114162306a36Sopenharmony_ci struct ubi_wl_entry *wl_e; 114262306a36Sopenharmony_ci struct ubi_volume *vol; 114362306a36Sopenharmony_ci struct ubi_vid_io_buf *avbuf, *dvbuf; 114462306a36Sopenharmony_ci struct ubi_vid_hdr *avhdr, *dvhdr; 114562306a36Sopenharmony_ci struct ubi_work *ubi_wrk; 114662306a36Sopenharmony_ci struct rb_node *tmp_rb; 114762306a36Sopenharmony_ci int ret, i, j, free_peb_count, used_peb_count, vol_count; 114862306a36Sopenharmony_ci int scrub_peb_count, erase_peb_count; 114962306a36Sopenharmony_ci unsigned long *seen_pebs; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci fm_raw = ubi->fm_buf; 115262306a36Sopenharmony_ci memset(ubi->fm_buf, 0, ubi->fm_size); 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci avbuf = new_fm_vbuf(ubi, UBI_FM_SB_VOLUME_ID); 115562306a36Sopenharmony_ci if (!avbuf) { 115662306a36Sopenharmony_ci ret = -ENOMEM; 115762306a36Sopenharmony_ci goto out; 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci dvbuf = new_fm_vbuf(ubi, UBI_FM_DATA_VOLUME_ID); 116162306a36Sopenharmony_ci if (!dvbuf) { 116262306a36Sopenharmony_ci ret = -ENOMEM; 116362306a36Sopenharmony_ci goto out_free_avbuf; 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci avhdr = ubi_get_vid_hdr(avbuf); 116762306a36Sopenharmony_ci dvhdr = ubi_get_vid_hdr(dvbuf); 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci seen_pebs = init_seen(ubi); 117062306a36Sopenharmony_ci if (IS_ERR(seen_pebs)) { 117162306a36Sopenharmony_ci ret = PTR_ERR(seen_pebs); 117262306a36Sopenharmony_ci goto out_free_dvbuf; 117362306a36Sopenharmony_ci } 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci spin_lock(&ubi->volumes_lock); 117662306a36Sopenharmony_ci spin_lock(&ubi->wl_lock); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci fmsb = (struct ubi_fm_sb *)fm_raw; 117962306a36Sopenharmony_ci fm_pos += sizeof(*fmsb); 118062306a36Sopenharmony_ci ubi_assert(fm_pos <= ubi->fm_size); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci fmh = (struct ubi_fm_hdr *)(fm_raw + fm_pos); 118362306a36Sopenharmony_ci fm_pos += sizeof(*fmh); 118462306a36Sopenharmony_ci ubi_assert(fm_pos <= ubi->fm_size); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci fmsb->magic = cpu_to_be32(UBI_FM_SB_MAGIC); 118762306a36Sopenharmony_ci fmsb->version = UBI_FM_FMT_VERSION; 118862306a36Sopenharmony_ci fmsb->used_blocks = cpu_to_be32(new_fm->used_blocks); 118962306a36Sopenharmony_ci /* the max sqnum will be filled in while *reading* the fastmap */ 119062306a36Sopenharmony_ci fmsb->sqnum = 0; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci fmh->magic = cpu_to_be32(UBI_FM_HDR_MAGIC); 119362306a36Sopenharmony_ci free_peb_count = 0; 119462306a36Sopenharmony_ci used_peb_count = 0; 119562306a36Sopenharmony_ci scrub_peb_count = 0; 119662306a36Sopenharmony_ci erase_peb_count = 0; 119762306a36Sopenharmony_ci vol_count = 0; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci fmpl = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos); 120062306a36Sopenharmony_ci fm_pos += sizeof(*fmpl); 120162306a36Sopenharmony_ci fmpl->magic = cpu_to_be32(UBI_FM_POOL_MAGIC); 120262306a36Sopenharmony_ci fmpl->size = cpu_to_be16(ubi->fm_pool.size); 120362306a36Sopenharmony_ci fmpl->max_size = cpu_to_be16(ubi->fm_pool.max_size); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci for (i = 0; i < ubi->fm_pool.size; i++) { 120662306a36Sopenharmony_ci fmpl->pebs[i] = cpu_to_be32(ubi->fm_pool.pebs[i]); 120762306a36Sopenharmony_ci set_seen(ubi, ubi->fm_pool.pebs[i], seen_pebs); 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci fmpl_wl = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos); 121162306a36Sopenharmony_ci fm_pos += sizeof(*fmpl_wl); 121262306a36Sopenharmony_ci fmpl_wl->magic = cpu_to_be32(UBI_FM_POOL_MAGIC); 121362306a36Sopenharmony_ci fmpl_wl->size = cpu_to_be16(ubi->fm_wl_pool.size); 121462306a36Sopenharmony_ci fmpl_wl->max_size = cpu_to_be16(ubi->fm_wl_pool.max_size); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci for (i = 0; i < ubi->fm_wl_pool.size; i++) { 121762306a36Sopenharmony_ci fmpl_wl->pebs[i] = cpu_to_be32(ubi->fm_wl_pool.pebs[i]); 121862306a36Sopenharmony_ci set_seen(ubi, ubi->fm_wl_pool.pebs[i], seen_pebs); 121962306a36Sopenharmony_ci } 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci ubi_for_each_free_peb(ubi, wl_e, tmp_rb) { 122262306a36Sopenharmony_ci fec = (struct ubi_fm_ec *)(fm_raw + fm_pos); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci fec->pnum = cpu_to_be32(wl_e->pnum); 122562306a36Sopenharmony_ci set_seen(ubi, wl_e->pnum, seen_pebs); 122662306a36Sopenharmony_ci fec->ec = cpu_to_be32(wl_e->ec); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci free_peb_count++; 122962306a36Sopenharmony_ci fm_pos += sizeof(*fec); 123062306a36Sopenharmony_ci ubi_assert(fm_pos <= ubi->fm_size); 123162306a36Sopenharmony_ci } 123262306a36Sopenharmony_ci fmh->free_peb_count = cpu_to_be32(free_peb_count); 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci ubi_for_each_used_peb(ubi, wl_e, tmp_rb) { 123562306a36Sopenharmony_ci fec = (struct ubi_fm_ec *)(fm_raw + fm_pos); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci fec->pnum = cpu_to_be32(wl_e->pnum); 123862306a36Sopenharmony_ci set_seen(ubi, wl_e->pnum, seen_pebs); 123962306a36Sopenharmony_ci fec->ec = cpu_to_be32(wl_e->ec); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci used_peb_count++; 124262306a36Sopenharmony_ci fm_pos += sizeof(*fec); 124362306a36Sopenharmony_ci ubi_assert(fm_pos <= ubi->fm_size); 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci ubi_for_each_protected_peb(ubi, i, wl_e) { 124762306a36Sopenharmony_ci fec = (struct ubi_fm_ec *)(fm_raw + fm_pos); 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci fec->pnum = cpu_to_be32(wl_e->pnum); 125062306a36Sopenharmony_ci set_seen(ubi, wl_e->pnum, seen_pebs); 125162306a36Sopenharmony_ci fec->ec = cpu_to_be32(wl_e->ec); 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci used_peb_count++; 125462306a36Sopenharmony_ci fm_pos += sizeof(*fec); 125562306a36Sopenharmony_ci ubi_assert(fm_pos <= ubi->fm_size); 125662306a36Sopenharmony_ci } 125762306a36Sopenharmony_ci fmh->used_peb_count = cpu_to_be32(used_peb_count); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci ubi_for_each_scrub_peb(ubi, wl_e, tmp_rb) { 126062306a36Sopenharmony_ci fec = (struct ubi_fm_ec *)(fm_raw + fm_pos); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci fec->pnum = cpu_to_be32(wl_e->pnum); 126362306a36Sopenharmony_ci set_seen(ubi, wl_e->pnum, seen_pebs); 126462306a36Sopenharmony_ci fec->ec = cpu_to_be32(wl_e->ec); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci scrub_peb_count++; 126762306a36Sopenharmony_ci fm_pos += sizeof(*fec); 126862306a36Sopenharmony_ci ubi_assert(fm_pos <= ubi->fm_size); 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci fmh->scrub_peb_count = cpu_to_be32(scrub_peb_count); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci list_for_each_entry(ubi_wrk, &ubi->works, list) { 127462306a36Sopenharmony_ci if (ubi_is_erase_work(ubi_wrk)) { 127562306a36Sopenharmony_ci wl_e = ubi_wrk->e; 127662306a36Sopenharmony_ci ubi_assert(wl_e); 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci fec = (struct ubi_fm_ec *)(fm_raw + fm_pos); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci fec->pnum = cpu_to_be32(wl_e->pnum); 128162306a36Sopenharmony_ci set_seen(ubi, wl_e->pnum, seen_pebs); 128262306a36Sopenharmony_ci fec->ec = cpu_to_be32(wl_e->ec); 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci erase_peb_count++; 128562306a36Sopenharmony_ci fm_pos += sizeof(*fec); 128662306a36Sopenharmony_ci ubi_assert(fm_pos <= ubi->fm_size); 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci fmh->erase_peb_count = cpu_to_be32(erase_peb_count); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci for (i = 0; i < UBI_MAX_VOLUMES + UBI_INT_VOL_COUNT; i++) { 129262306a36Sopenharmony_ci vol = ubi->volumes[i]; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci if (!vol) 129562306a36Sopenharmony_ci continue; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci vol_count++; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci fvh = (struct ubi_fm_volhdr *)(fm_raw + fm_pos); 130062306a36Sopenharmony_ci fm_pos += sizeof(*fvh); 130162306a36Sopenharmony_ci ubi_assert(fm_pos <= ubi->fm_size); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci fvh->magic = cpu_to_be32(UBI_FM_VHDR_MAGIC); 130462306a36Sopenharmony_ci fvh->vol_id = cpu_to_be32(vol->vol_id); 130562306a36Sopenharmony_ci fvh->vol_type = vol->vol_type; 130662306a36Sopenharmony_ci fvh->used_ebs = cpu_to_be32(vol->used_ebs); 130762306a36Sopenharmony_ci fvh->data_pad = cpu_to_be32(vol->data_pad); 130862306a36Sopenharmony_ci fvh->last_eb_bytes = cpu_to_be32(vol->last_eb_bytes); 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci ubi_assert(vol->vol_type == UBI_DYNAMIC_VOLUME || 131162306a36Sopenharmony_ci vol->vol_type == UBI_STATIC_VOLUME); 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci feba = (struct ubi_fm_eba *)(fm_raw + fm_pos); 131462306a36Sopenharmony_ci fm_pos += sizeof(*feba) + (sizeof(__be32) * vol->reserved_pebs); 131562306a36Sopenharmony_ci ubi_assert(fm_pos <= ubi->fm_size); 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci for (j = 0; j < vol->reserved_pebs; j++) { 131862306a36Sopenharmony_ci struct ubi_eba_leb_desc ldesc; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci ubi_eba_get_ldesc(vol, j, &ldesc); 132162306a36Sopenharmony_ci feba->pnum[j] = cpu_to_be32(ldesc.pnum); 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci feba->reserved_pebs = cpu_to_be32(j); 132562306a36Sopenharmony_ci feba->magic = cpu_to_be32(UBI_FM_EBA_MAGIC); 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci fmh->vol_count = cpu_to_be32(vol_count); 132862306a36Sopenharmony_ci fmh->bad_peb_count = cpu_to_be32(ubi->bad_peb_count); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci avhdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); 133162306a36Sopenharmony_ci avhdr->lnum = 0; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci spin_unlock(&ubi->wl_lock); 133462306a36Sopenharmony_ci spin_unlock(&ubi->volumes_lock); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci dbg_bld("writing fastmap SB to PEB %i", new_fm->e[0]->pnum); 133762306a36Sopenharmony_ci ret = ubi_io_write_vid_hdr(ubi, new_fm->e[0]->pnum, avbuf); 133862306a36Sopenharmony_ci if (ret) { 133962306a36Sopenharmony_ci ubi_err(ubi, "unable to write vid_hdr to fastmap SB!"); 134062306a36Sopenharmony_ci goto out_free_seen; 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci for (i = 0; i < new_fm->used_blocks; i++) { 134462306a36Sopenharmony_ci fmsb->block_loc[i] = cpu_to_be32(new_fm->e[i]->pnum); 134562306a36Sopenharmony_ci set_seen(ubi, new_fm->e[i]->pnum, seen_pebs); 134662306a36Sopenharmony_ci fmsb->block_ec[i] = cpu_to_be32(new_fm->e[i]->ec); 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci fmsb->data_crc = 0; 135062306a36Sopenharmony_ci fmsb->data_crc = cpu_to_be32(crc32(UBI_CRC32_INIT, fm_raw, 135162306a36Sopenharmony_ci ubi->fm_size)); 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci for (i = 1; i < new_fm->used_blocks; i++) { 135462306a36Sopenharmony_ci dvhdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); 135562306a36Sopenharmony_ci dvhdr->lnum = cpu_to_be32(i); 135662306a36Sopenharmony_ci dbg_bld("writing fastmap data to PEB %i sqnum %llu", 135762306a36Sopenharmony_ci new_fm->e[i]->pnum, be64_to_cpu(dvhdr->sqnum)); 135862306a36Sopenharmony_ci ret = ubi_io_write_vid_hdr(ubi, new_fm->e[i]->pnum, dvbuf); 135962306a36Sopenharmony_ci if (ret) { 136062306a36Sopenharmony_ci ubi_err(ubi, "unable to write vid_hdr to PEB %i!", 136162306a36Sopenharmony_ci new_fm->e[i]->pnum); 136262306a36Sopenharmony_ci goto out_free_seen; 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci for (i = 0; i < new_fm->used_blocks; i++) { 136762306a36Sopenharmony_ci ret = ubi_io_write_data(ubi, fm_raw + (i * ubi->leb_size), 136862306a36Sopenharmony_ci new_fm->e[i]->pnum, 0, ubi->leb_size); 136962306a36Sopenharmony_ci if (ret) { 137062306a36Sopenharmony_ci ubi_err(ubi, "unable to write fastmap to PEB %i!", 137162306a36Sopenharmony_ci new_fm->e[i]->pnum); 137262306a36Sopenharmony_ci goto out_free_seen; 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci ubi_assert(new_fm); 137762306a36Sopenharmony_ci ubi->fm = new_fm; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci ret = self_check_seen(ubi, seen_pebs); 138062306a36Sopenharmony_ci dbg_bld("fastmap written!"); 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ciout_free_seen: 138362306a36Sopenharmony_ci free_seen(seen_pebs); 138462306a36Sopenharmony_ciout_free_dvbuf: 138562306a36Sopenharmony_ci ubi_free_vid_buf(dvbuf); 138662306a36Sopenharmony_ciout_free_avbuf: 138762306a36Sopenharmony_ci ubi_free_vid_buf(avbuf); 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ciout: 139062306a36Sopenharmony_ci return ret; 139162306a36Sopenharmony_ci} 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci/** 139462306a36Sopenharmony_ci * erase_block - Manually erase a PEB. 139562306a36Sopenharmony_ci * @ubi: UBI device object 139662306a36Sopenharmony_ci * @pnum: PEB to be erased 139762306a36Sopenharmony_ci * 139862306a36Sopenharmony_ci * Returns the new EC value on success, < 0 indicates an internal error. 139962306a36Sopenharmony_ci */ 140062306a36Sopenharmony_cistatic int erase_block(struct ubi_device *ubi, int pnum) 140162306a36Sopenharmony_ci{ 140262306a36Sopenharmony_ci int ret; 140362306a36Sopenharmony_ci struct ubi_ec_hdr *ec_hdr; 140462306a36Sopenharmony_ci long long ec; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); 140762306a36Sopenharmony_ci if (!ec_hdr) 140862306a36Sopenharmony_ci return -ENOMEM; 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci ret = ubi_io_read_ec_hdr(ubi, pnum, ec_hdr, 0); 141162306a36Sopenharmony_ci if (ret < 0) 141262306a36Sopenharmony_ci goto out; 141362306a36Sopenharmony_ci else if (ret && ret != UBI_IO_BITFLIPS) { 141462306a36Sopenharmony_ci ret = -EINVAL; 141562306a36Sopenharmony_ci goto out; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci ret = ubi_io_sync_erase(ubi, pnum, 0); 141962306a36Sopenharmony_ci if (ret < 0) 142062306a36Sopenharmony_ci goto out; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci ec = be64_to_cpu(ec_hdr->ec); 142362306a36Sopenharmony_ci ec += ret; 142462306a36Sopenharmony_ci if (ec > UBI_MAX_ERASECOUNTER) { 142562306a36Sopenharmony_ci ret = -EINVAL; 142662306a36Sopenharmony_ci goto out; 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci ec_hdr->ec = cpu_to_be64(ec); 143062306a36Sopenharmony_ci ret = ubi_io_write_ec_hdr(ubi, pnum, ec_hdr); 143162306a36Sopenharmony_ci if (ret < 0) 143262306a36Sopenharmony_ci goto out; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci ret = ec; 143562306a36Sopenharmony_ciout: 143662306a36Sopenharmony_ci kfree(ec_hdr); 143762306a36Sopenharmony_ci return ret; 143862306a36Sopenharmony_ci} 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci/** 144162306a36Sopenharmony_ci * invalidate_fastmap - destroys a fastmap. 144262306a36Sopenharmony_ci * @ubi: UBI device object 144362306a36Sopenharmony_ci * 144462306a36Sopenharmony_ci * This function ensures that upon next UBI attach a full scan 144562306a36Sopenharmony_ci * is issued. We need this if UBI is about to write a new fastmap 144662306a36Sopenharmony_ci * but is unable to do so. In this case we have two options: 144762306a36Sopenharmony_ci * a) Make sure that the current fastmap will not be usued upon 144862306a36Sopenharmony_ci * attach time and contine or b) fall back to RO mode to have the 144962306a36Sopenharmony_ci * current fastmap in a valid state. 145062306a36Sopenharmony_ci * Returns 0 on success, < 0 indicates an internal error. 145162306a36Sopenharmony_ci */ 145262306a36Sopenharmony_cistatic int invalidate_fastmap(struct ubi_device *ubi) 145362306a36Sopenharmony_ci{ 145462306a36Sopenharmony_ci int ret; 145562306a36Sopenharmony_ci struct ubi_fastmap_layout *fm; 145662306a36Sopenharmony_ci struct ubi_wl_entry *e; 145762306a36Sopenharmony_ci struct ubi_vid_io_buf *vb = NULL; 145862306a36Sopenharmony_ci struct ubi_vid_hdr *vh; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci if (!ubi->fm) 146162306a36Sopenharmony_ci return 0; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci ubi->fm = NULL; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci ret = -ENOMEM; 146662306a36Sopenharmony_ci fm = kzalloc(sizeof(*fm), GFP_KERNEL); 146762306a36Sopenharmony_ci if (!fm) 146862306a36Sopenharmony_ci goto out; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci vb = new_fm_vbuf(ubi, UBI_FM_SB_VOLUME_ID); 147162306a36Sopenharmony_ci if (!vb) 147262306a36Sopenharmony_ci goto out_free_fm; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci vh = ubi_get_vid_hdr(vb); 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci ret = -ENOSPC; 147762306a36Sopenharmony_ci e = ubi_wl_get_fm_peb(ubi, 1); 147862306a36Sopenharmony_ci if (!e) 147962306a36Sopenharmony_ci goto out_free_fm; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci /* 148262306a36Sopenharmony_ci * Create fake fastmap such that UBI will fall back 148362306a36Sopenharmony_ci * to scanning mode. 148462306a36Sopenharmony_ci */ 148562306a36Sopenharmony_ci vh->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); 148662306a36Sopenharmony_ci ret = ubi_io_write_vid_hdr(ubi, e->pnum, vb); 148762306a36Sopenharmony_ci if (ret < 0) { 148862306a36Sopenharmony_ci ubi_wl_put_fm_peb(ubi, e, 0, 0); 148962306a36Sopenharmony_ci goto out_free_fm; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci fm->used_blocks = 1; 149362306a36Sopenharmony_ci fm->e[0] = e; 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci ubi->fm = fm; 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ciout: 149862306a36Sopenharmony_ci ubi_free_vid_buf(vb); 149962306a36Sopenharmony_ci return ret; 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ciout_free_fm: 150262306a36Sopenharmony_ci kfree(fm); 150362306a36Sopenharmony_ci goto out; 150462306a36Sopenharmony_ci} 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci/** 150762306a36Sopenharmony_ci * return_fm_pebs - returns all PEBs used by a fastmap back to the 150862306a36Sopenharmony_ci * WL sub-system. 150962306a36Sopenharmony_ci * @ubi: UBI device object 151062306a36Sopenharmony_ci * @fm: fastmap layout object 151162306a36Sopenharmony_ci */ 151262306a36Sopenharmony_cistatic void return_fm_pebs(struct ubi_device *ubi, 151362306a36Sopenharmony_ci struct ubi_fastmap_layout *fm) 151462306a36Sopenharmony_ci{ 151562306a36Sopenharmony_ci int i; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci if (!fm) 151862306a36Sopenharmony_ci return; 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci for (i = 0; i < fm->used_blocks; i++) { 152162306a36Sopenharmony_ci if (fm->e[i]) { 152262306a36Sopenharmony_ci ubi_wl_put_fm_peb(ubi, fm->e[i], i, 152362306a36Sopenharmony_ci fm->to_be_tortured[i]); 152462306a36Sopenharmony_ci fm->e[i] = NULL; 152562306a36Sopenharmony_ci } 152662306a36Sopenharmony_ci } 152762306a36Sopenharmony_ci} 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci/** 153062306a36Sopenharmony_ci * ubi_update_fastmap - will be called by UBI if a volume changes or 153162306a36Sopenharmony_ci * a fastmap pool becomes full. 153262306a36Sopenharmony_ci * @ubi: UBI device object 153362306a36Sopenharmony_ci * 153462306a36Sopenharmony_ci * Returns 0 on success, < 0 indicates an internal error. 153562306a36Sopenharmony_ci */ 153662306a36Sopenharmony_ciint ubi_update_fastmap(struct ubi_device *ubi) 153762306a36Sopenharmony_ci{ 153862306a36Sopenharmony_ci int ret, i, j; 153962306a36Sopenharmony_ci struct ubi_fastmap_layout *new_fm, *old_fm; 154062306a36Sopenharmony_ci struct ubi_wl_entry *tmp_e; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci down_write(&ubi->fm_protect); 154362306a36Sopenharmony_ci down_write(&ubi->work_sem); 154462306a36Sopenharmony_ci down_write(&ubi->fm_eba_sem); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci ubi_refill_pools(ubi); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci if (ubi->ro_mode || ubi->fm_disabled) { 154962306a36Sopenharmony_ci up_write(&ubi->fm_eba_sem); 155062306a36Sopenharmony_ci up_write(&ubi->work_sem); 155162306a36Sopenharmony_ci up_write(&ubi->fm_protect); 155262306a36Sopenharmony_ci return 0; 155362306a36Sopenharmony_ci } 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci new_fm = kzalloc(sizeof(*new_fm), GFP_KERNEL); 155662306a36Sopenharmony_ci if (!new_fm) { 155762306a36Sopenharmony_ci up_write(&ubi->fm_eba_sem); 155862306a36Sopenharmony_ci up_write(&ubi->work_sem); 155962306a36Sopenharmony_ci up_write(&ubi->fm_protect); 156062306a36Sopenharmony_ci return -ENOMEM; 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci new_fm->used_blocks = ubi->fm_size / ubi->leb_size; 156462306a36Sopenharmony_ci old_fm = ubi->fm; 156562306a36Sopenharmony_ci ubi->fm = NULL; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci if (new_fm->used_blocks > UBI_FM_MAX_BLOCKS) { 156862306a36Sopenharmony_ci ubi_err(ubi, "fastmap too large"); 156962306a36Sopenharmony_ci ret = -ENOSPC; 157062306a36Sopenharmony_ci goto err; 157162306a36Sopenharmony_ci } 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci for (i = 1; i < new_fm->used_blocks; i++) { 157462306a36Sopenharmony_ci spin_lock(&ubi->wl_lock); 157562306a36Sopenharmony_ci tmp_e = ubi_wl_get_fm_peb(ubi, 0); 157662306a36Sopenharmony_ci spin_unlock(&ubi->wl_lock); 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci if (!tmp_e) { 157962306a36Sopenharmony_ci if (old_fm && old_fm->e[i]) { 158062306a36Sopenharmony_ci ret = erase_block(ubi, old_fm->e[i]->pnum); 158162306a36Sopenharmony_ci if (ret < 0) { 158262306a36Sopenharmony_ci ubi_err(ubi, "could not erase old fastmap PEB"); 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci for (j = 1; j < i; j++) { 158562306a36Sopenharmony_ci ubi_wl_put_fm_peb(ubi, new_fm->e[j], 158662306a36Sopenharmony_ci j, 0); 158762306a36Sopenharmony_ci new_fm->e[j] = NULL; 158862306a36Sopenharmony_ci } 158962306a36Sopenharmony_ci goto err; 159062306a36Sopenharmony_ci } 159162306a36Sopenharmony_ci new_fm->e[i] = old_fm->e[i]; 159262306a36Sopenharmony_ci old_fm->e[i] = NULL; 159362306a36Sopenharmony_ci } else { 159462306a36Sopenharmony_ci ubi_err(ubi, "could not get any free erase block"); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci for (j = 1; j < i; j++) { 159762306a36Sopenharmony_ci ubi_wl_put_fm_peb(ubi, new_fm->e[j], j, 0); 159862306a36Sopenharmony_ci new_fm->e[j] = NULL; 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci ret = -ENOSPC; 160262306a36Sopenharmony_ci goto err; 160362306a36Sopenharmony_ci } 160462306a36Sopenharmony_ci } else { 160562306a36Sopenharmony_ci new_fm->e[i] = tmp_e; 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci if (old_fm && old_fm->e[i]) { 160862306a36Sopenharmony_ci ubi_wl_put_fm_peb(ubi, old_fm->e[i], i, 160962306a36Sopenharmony_ci old_fm->to_be_tortured[i]); 161062306a36Sopenharmony_ci old_fm->e[i] = NULL; 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci } 161362306a36Sopenharmony_ci } 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci /* Old fastmap is larger than the new one */ 161662306a36Sopenharmony_ci if (old_fm && new_fm->used_blocks < old_fm->used_blocks) { 161762306a36Sopenharmony_ci for (i = new_fm->used_blocks; i < old_fm->used_blocks; i++) { 161862306a36Sopenharmony_ci ubi_wl_put_fm_peb(ubi, old_fm->e[i], i, 161962306a36Sopenharmony_ci old_fm->to_be_tortured[i]); 162062306a36Sopenharmony_ci old_fm->e[i] = NULL; 162162306a36Sopenharmony_ci } 162262306a36Sopenharmony_ci } 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci spin_lock(&ubi->wl_lock); 162562306a36Sopenharmony_ci tmp_e = ubi->fm_anchor; 162662306a36Sopenharmony_ci ubi->fm_anchor = NULL; 162762306a36Sopenharmony_ci spin_unlock(&ubi->wl_lock); 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci if (old_fm) { 163062306a36Sopenharmony_ci /* no fresh anchor PEB was found, reuse the old one */ 163162306a36Sopenharmony_ci if (!tmp_e) { 163262306a36Sopenharmony_ci ret = erase_block(ubi, old_fm->e[0]->pnum); 163362306a36Sopenharmony_ci if (ret < 0) { 163462306a36Sopenharmony_ci ubi_err(ubi, "could not erase old anchor PEB"); 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci for (i = 1; i < new_fm->used_blocks; i++) { 163762306a36Sopenharmony_ci ubi_wl_put_fm_peb(ubi, new_fm->e[i], 163862306a36Sopenharmony_ci i, 0); 163962306a36Sopenharmony_ci new_fm->e[i] = NULL; 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci goto err; 164262306a36Sopenharmony_ci } 164362306a36Sopenharmony_ci new_fm->e[0] = old_fm->e[0]; 164462306a36Sopenharmony_ci new_fm->e[0]->ec = ret; 164562306a36Sopenharmony_ci old_fm->e[0] = NULL; 164662306a36Sopenharmony_ci } else { 164762306a36Sopenharmony_ci /* we've got a new anchor PEB, return the old one */ 164862306a36Sopenharmony_ci ubi_wl_put_fm_peb(ubi, old_fm->e[0], 0, 164962306a36Sopenharmony_ci old_fm->to_be_tortured[0]); 165062306a36Sopenharmony_ci new_fm->e[0] = tmp_e; 165162306a36Sopenharmony_ci old_fm->e[0] = NULL; 165262306a36Sopenharmony_ci } 165362306a36Sopenharmony_ci } else { 165462306a36Sopenharmony_ci if (!tmp_e) { 165562306a36Sopenharmony_ci ubi_err(ubi, "could not find any anchor PEB"); 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci for (i = 1; i < new_fm->used_blocks; i++) { 165862306a36Sopenharmony_ci ubi_wl_put_fm_peb(ubi, new_fm->e[i], i, 0); 165962306a36Sopenharmony_ci new_fm->e[i] = NULL; 166062306a36Sopenharmony_ci } 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci ret = -ENOSPC; 166362306a36Sopenharmony_ci goto err; 166462306a36Sopenharmony_ci } 166562306a36Sopenharmony_ci new_fm->e[0] = tmp_e; 166662306a36Sopenharmony_ci } 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci ret = ubi_write_fastmap(ubi, new_fm); 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci if (ret) 167162306a36Sopenharmony_ci goto err; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ciout_unlock: 167462306a36Sopenharmony_ci up_write(&ubi->fm_eba_sem); 167562306a36Sopenharmony_ci up_write(&ubi->work_sem); 167662306a36Sopenharmony_ci up_write(&ubi->fm_protect); 167762306a36Sopenharmony_ci kfree(old_fm); 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci ubi_ensure_anchor_pebs(ubi); 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci return ret; 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_cierr: 168462306a36Sopenharmony_ci ubi_warn(ubi, "Unable to write new fastmap, err=%i", ret); 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci ret = invalidate_fastmap(ubi); 168762306a36Sopenharmony_ci if (ret < 0) { 168862306a36Sopenharmony_ci ubi_err(ubi, "Unable to invalidate current fastmap!"); 168962306a36Sopenharmony_ci ubi_ro_mode(ubi); 169062306a36Sopenharmony_ci } else { 169162306a36Sopenharmony_ci return_fm_pebs(ubi, old_fm); 169262306a36Sopenharmony_ci return_fm_pebs(ubi, new_fm); 169362306a36Sopenharmony_ci ret = 0; 169462306a36Sopenharmony_ci } 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci kfree(new_fm); 169762306a36Sopenharmony_ci goto out_unlock; 169862306a36Sopenharmony_ci} 1699