📄 eba.c
字号:
vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); ubi_msg("try another PEB"); goto retry;}/* * ubi_eba_atomic_leb_change - change logical eraseblock atomically. * @ubi: UBI device description object * @vol: volume description object * @lnum: logical eraseblock number * @buf: data to write * @len: how many bytes to write * @dtype: data type * * This function changes the contents of a logical eraseblock atomically. @buf * has to contain new logical eraseblock data, and @len - the length of the * data, which has to be aligned. This function guarantees that in case of an * unclean reboot the old contents is preserved. Returns zero in case of * success and a negative error code in case of failure. * * UBI reserves one LEB for the "atomic LEB change" operation, so only one * LEB change may be done at a time. This is ensured by @ubi->alc_mutex. */int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, const void *buf, int len, int dtype){ int err, pnum, tries = 0, vol_id = vol->vol_id; struct ubi_vid_hdr *vid_hdr; uint32_t crc; if (ubi->ro_mode) return -EROFS; if (len == 0) { /* * Special case when data length is zero. In this case the LEB * has to be unmapped and mapped somewhere else. */ err = ubi_eba_unmap_leb(ubi, vol, lnum); if (err) return err; return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype); } vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); if (!vid_hdr) return -ENOMEM; mutex_lock(&ubi->alc_mutex); err = leb_write_lock(ubi, vol_id, lnum); if (err) goto out_mutex; vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); vid_hdr->vol_id = cpu_to_be32(vol_id); vid_hdr->lnum = cpu_to_be32(lnum); vid_hdr->compat = ubi_get_compat(ubi, vol_id); vid_hdr->data_pad = cpu_to_be32(vol->data_pad); crc = crc32(UBI_CRC32_INIT, buf, len); vid_hdr->vol_type = UBI_VID_DYNAMIC; vid_hdr->data_size = cpu_to_be32(len); vid_hdr->copy_flag = 1; vid_hdr->data_crc = cpu_to_be32(crc);retry: pnum = ubi_wl_get_peb(ubi, dtype); if (pnum < 0) { err = pnum; goto out_leb_unlock; } dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d", vol_id, lnum, vol->eba_tbl[lnum], pnum); err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); if (err) { ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", vol_id, lnum, pnum); goto write_error; } err = ubi_io_write_data(ubi, buf, pnum, 0, len); if (err) { ubi_warn("failed to write %d bytes of data to PEB %d", len, pnum); goto write_error; } if (vol->eba_tbl[lnum] >= 0) { err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 0); if (err) goto out_leb_unlock; } vol->eba_tbl[lnum] = pnum;out_leb_unlock: leb_write_unlock(ubi, vol_id, lnum);out_mutex: mutex_unlock(&ubi->alc_mutex); ubi_free_vid_hdr(ubi, vid_hdr); return err;write_error: if (err != -EIO || !ubi->bad_allowed) { /* * This flash device does not admit of bad eraseblocks or * something nasty and unexpected happened. Switch to read-only * mode just in case. */ ubi_ro_mode(ubi); goto out_leb_unlock; } err = ubi_wl_put_peb(ubi, pnum, 1); if (err || ++tries > UBI_IO_RETRIES) { ubi_ro_mode(ubi); goto out_leb_unlock; } vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); ubi_msg("try another PEB"); goto retry;}/** * ubi_eba_copy_leb - copy logical eraseblock. * @ubi: UBI device description object * @from: physical eraseblock number from where to copy * @to: physical eraseblock number where to copy * @vid_hdr: VID header of the @from physical eraseblock * * This function copies logical eraseblock from physical eraseblock @from to * physical eraseblock @to. The @vid_hdr buffer may be changed by this * function. Returns: * o %0 in case of success; * o %1 if the operation was canceled and should be tried later (e.g., * because a bit-flip was detected at the target PEB); * o %2 if the volume is being deleted and this LEB should not be moved. */int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, struct ubi_vid_hdr *vid_hdr){ int err, vol_id, lnum, data_size, aldata_size, idx; struct ubi_volume *vol; uint32_t crc; vol_id = be32_to_cpu(vid_hdr->vol_id); lnum = be32_to_cpu(vid_hdr->lnum); dbg_eba("copy LEB %d:%d, PEB %d to PEB %d", vol_id, lnum, from, to); if (vid_hdr->vol_type == UBI_VID_STATIC) { data_size = be32_to_cpu(vid_hdr->data_size); aldata_size = ALIGN(data_size, ubi->min_io_size); } else data_size = aldata_size = ubi->leb_size - be32_to_cpu(vid_hdr->data_pad); idx = vol_id2idx(ubi, vol_id); spin_lock(&ubi->volumes_lock); /* * Note, we may race with volume deletion, which means that the volume * this logical eraseblock belongs to might be being deleted. Since the * volume deletion unmaps all the volume's logical eraseblocks, it will * be locked in 'ubi_wl_put_peb()' and wait for the WL worker to finish. */ vol = ubi->volumes[idx]; if (!vol) { /* No need to do further work, cancel */ dbg_eba("volume %d is being removed, cancel", vol_id); spin_unlock(&ubi->volumes_lock); return 2; } spin_unlock(&ubi->volumes_lock); /* * We do not want anybody to write to this logical eraseblock while we * are moving it, so lock it. * * Note, we are using non-waiting locking here, because we cannot sleep * on the LEB, since it may cause deadlocks. Indeed, imagine a task is * unmapping the LEB which is mapped to the PEB we are going to move * (@from). This task locks the LEB and goes sleep in the * 'ubi_wl_put_peb()' function on the @ubi->move_mutex. In turn, we are * holding @ubi->move_mutex and go sleep on the LEB lock. So, if the * LEB is already locked, we just do not move it and return %1. */ err = leb_write_trylock(ubi, vol_id, lnum); if (err) { dbg_eba("contention on LEB %d:%d, cancel", vol_id, lnum); return err; } /* * The LEB might have been put meanwhile, and the task which put it is * probably waiting on @ubi->move_mutex. No need to continue the work, * cancel it. */ if (vol->eba_tbl[lnum] != from) { dbg_eba("LEB %d:%d is no longer mapped to PEB %d, mapped to " "PEB %d, cancel", vol_id, lnum, from, vol->eba_tbl[lnum]); err = 1; goto out_unlock_leb; } /* * OK, now the LEB is locked and we can safely start moving it. Since * this function utilizes thie @ubi->peb1_buf buffer which is shared * with some other functions, so lock the buffer by taking the * @ubi->buf_mutex. */ mutex_lock(&ubi->buf_mutex); dbg_eba("read %d bytes of data", aldata_size); err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size); if (err && err != UBI_IO_BITFLIPS) { ubi_warn("error %d while reading data from PEB %d", err, from); goto out_unlock_buf; } /* * Now we have got to calculate how much data we have to to copy. In * case of a static volume it is fairly easy - the VID header contains * the data size. In case of a dynamic volume it is more difficult - we * have to read the contents, cut 0xFF bytes from the end and copy only * the first part. We must do this to avoid writing 0xFF bytes as it * may have some side-effects. And not only this. It is important not * to include those 0xFFs to CRC because later the they may be filled * by data. */ if (vid_hdr->vol_type == UBI_VID_DYNAMIC) aldata_size = data_size = ubi_calc_data_len(ubi, ubi->peb_buf1, data_size); cond_resched(); crc = crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size); cond_resched(); /* * It may turn out to me that the whole @from physical eraseblock * contains only 0xFF bytes. Then we have to only write the VID header * and do not write any data. This also means we should not set * @vid_hdr->copy_flag, @vid_hdr->data_size, and @vid_hdr->data_crc. */ if (data_size > 0) { vid_hdr->copy_flag = 1; vid_hdr->data_size = cpu_to_be32(data_size); vid_hdr->data_crc = cpu_to_be32(crc); } vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); err = ubi_io_write_vid_hdr(ubi, to, vid_hdr); if (err) goto out_unlock_buf; cond_resched(); /* Read the VID header back and check if it was written correctly */ err = ubi_io_read_vid_hdr(ubi, to, vid_hdr, 1); if (err) { if (err != UBI_IO_BITFLIPS) ubi_warn("cannot read VID header back from PEB %d", to); else err = 1; goto out_unlock_buf; } if (data_size > 0) { err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size); if (err) goto out_unlock_buf; cond_resched(); /* * We've written the data and are going to read it back to make * sure it was written correctly. */ err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size); if (err) { if (err != UBI_IO_BITFLIPS) ubi_warn("cannot read data back from PEB %d", to); else err = 1; goto out_unlock_buf; } cond_resched(); if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) { ubi_warn("read data back from PEB %d - it is different", to); goto out_unlock_buf; } } ubi_assert(vol->eba_tbl[lnum] == from); vol->eba_tbl[lnum] = to;out_unlock_buf: mutex_unlock(&ubi->buf_mutex);out_unlock_leb: leb_write_unlock(ubi, vol_id, lnum); return err;}/** * ubi_eba_init_scan - initialize the EBA sub-system using scanning information. * @ubi: UBI device description object * @si: scanning information * * This function returns zero in case of success and a negative error code in * case of failure. */int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si){ int i, j, err, num_volumes; struct ubi_scan_volume *sv; struct ubi_volume *vol; struct ubi_scan_leb *seb; struct rb_node *rb; dbg_eba("initialize EBA sub-system"); spin_lock_init(&ubi->ltree_lock); mutex_init(&ubi->alc_mutex); ubi->ltree = RB_ROOT; ubi->global_sqnum = si->max_sqnum + 1; num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT; for (i = 0; i < num_volumes; i++) { vol = ubi->volumes[i]; if (!vol) continue; cond_resched(); vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int), GFP_KERNEL); if (!vol->eba_tbl) { err = -ENOMEM; goto out_free; } for (j = 0; j < vol->reserved_pebs; j++) vol->eba_tbl[j] = UBI_LEB_UNMAPPED; sv = ubi_scan_find_sv(si, idx2vol_id(ubi, i)); if (!sv) continue; ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { if (seb->lnum >= vol->reserved_pebs) /* * This may happen in case of an unclean reboot * during re-size. */ ubi_scan_move_to_list(sv, seb, &si->erase); vol->eba_tbl[seb->lnum] = seb->pnum; } } if (ubi->avail_pebs < EBA_RESERVED_PEBS) { ubi_err("no enough physical eraseblocks (%d, need %d)", ubi->avail_pebs, EBA_RESERVED_PEBS); err = -ENOSPC; goto out_free; } ubi->avail_pebs -= EBA_RESERVED_PEBS; ubi->rsvd_pebs += EBA_RESERVED_PEBS; if (ubi->bad_allowed) { ubi_calculate_reserved(ubi); if (ubi->avail_pebs < ubi->beb_rsvd_level) { /* No enough free physical eraseblocks */ ubi->beb_rsvd_pebs = ubi->avail_pebs; ubi_warn("cannot reserve enough PEBs for bad PEB " "handling, reserved %d, need %d", ubi->beb_rsvd_pebs, ubi->beb_rsvd_level); } else ubi->beb_rsvd_pebs = ubi->beb_rsvd_level; ubi->avail_pebs -= ubi->beb_rsvd_pebs; ubi->rsvd_pebs += ubi->beb_rsvd_pebs; } dbg_eba("EBA sub-system is initialized"); return 0;out_free: for (i = 0; i < num_volumes; i++) { if (!ubi->volumes[i]) continue; kfree(ubi->volumes[i]->eba_tbl); } return err;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -