⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eba.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
	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 + -