Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 799dca34 authored by Boris Brezillon's avatar Boris Brezillon Committed by Richard Weinberger
Browse files

UBI: hide EBA internals



Create a private ubi_eba_table struct to hide EBA internals and provide
helpers to allocate, destroy, copy and assing an EBA table to a volume.

Now that external EBA users are using helpers to query/modify the EBA
state we can safely change the internal representation, which will be
needed to support the LEB consolidation concept.

Signed-off-by: default avatarBoris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
parent 1f81a5cc
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -574,7 +574,7 @@ void ubi_free_internal_volumes(struct ubi_device *ubi)

	for (i = ubi->vtbl_slots;
	     i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
		kfree(ubi->volumes[i]->eba_tbl);
		ubi_eba_replace_table(ubi->volumes[i], NULL);
		kfree(ubi->volumes[i]);
	}
}
+140 −26
Original line number Diff line number Diff line
@@ -49,6 +49,30 @@
/* Number of physical eraseblocks reserved for atomic LEB change operation */
#define EBA_RESERVED_PEBS 1

/**
 * struct ubi_eba_entry - structure encoding a single LEB -> PEB association
 * @pnum: the physical eraseblock number attached to the LEB
 *
 * This structure is encoding a LEB -> PEB association. Note that the LEB
 * number is not stored here, because it is the index used to access the
 * entries table.
 */
struct ubi_eba_entry {
	int pnum;
};

/**
 * struct ubi_eba_table - LEB -> PEB association information
 * @entries: the LEB to PEB mapping (one entry per LEB).
 *
 * This structure is private to the EBA logic and should be kept here.
 * It is encoding the LEB to PEB association table, and is subject to
 * changes.
 */
struct ubi_eba_table {
	struct ubi_eba_entry *entries;
};

/**
 * next_sqnum - get next sequence number.
 * @ubi: UBI device description object
@@ -97,7 +121,94 @@ void ubi_eba_get_ldesc(struct ubi_volume *vol, int lnum,
		       struct ubi_eba_leb_desc *ldesc)
{
	ldesc->lnum = lnum;
	ldesc->pnum = vol->eba_tbl[lnum];
	ldesc->pnum = vol->eba_tbl->entries[lnum].pnum;
}

/**
 * ubi_eba_create_table - allocate a new EBA table and initialize it with all
 *			  LEBs unmapped
 * @vol: volume containing the EBA table to copy
 * @nentries: number of entries in the table
 *
 * Allocate a new EBA table and initialize it with all LEBs unmapped.
 * Returns a valid pointer if it succeed, an ERR_PTR() otherwise.
 */
struct ubi_eba_table *ubi_eba_create_table(struct ubi_volume *vol,
					   int nentries)
{
	struct ubi_eba_table *tbl;
	int err = -ENOMEM;
	int i;

	tbl = kzalloc(sizeof(*tbl), GFP_KERNEL);
	if (!tbl)
		return ERR_PTR(-ENOMEM);

	tbl->entries = kmalloc_array(nentries, sizeof(*tbl->entries),
				     GFP_KERNEL);
	if (!tbl->entries)
		goto err;

	for (i = 0; i < nentries; i++)
		tbl->entries[i].pnum = UBI_LEB_UNMAPPED;

	return tbl;

err:
	kfree(tbl->entries);
	kfree(tbl);

	return ERR_PTR(err);
}

/**
 * ubi_eba_destroy_table - destroy an EBA table
 * @tbl: the table to destroy
 *
 * Destroy an EBA table.
 */
void ubi_eba_destroy_table(struct ubi_eba_table *tbl)
{
	if (!tbl)
		return;

	kfree(tbl->entries);
	kfree(tbl);
}

/**
 * ubi_eba_copy_table - copy the EBA table attached to vol into another table
 * @vol: volume containing the EBA table to copy
 * @dst: destination
 * @nentries: number of entries to copy
 *
 * Copy the EBA table stored in vol into the one pointed by dst.
 */
void ubi_eba_copy_table(struct ubi_volume *vol, struct ubi_eba_table *dst,
			int nentries)
{
	struct ubi_eba_table *src;
	int i;

	ubi_assert(dst && vol && vol->eba_tbl);

	src = vol->eba_tbl;

	for (i = 0; i < nentries; i++)
		dst->entries[i].pnum = src->entries[i].pnum;
}

/**
 * ubi_eba_replace_table - assign a new EBA table to a volume
 * @vol: volume containing the EBA table to copy
 * @tbl: new EBA table
 *
 * Assign a new EBA table to the volume and release the old one.
 */
void ubi_eba_replace_table(struct ubi_volume *vol, struct ubi_eba_table *tbl)
{
	ubi_eba_destroy_table(vol->eba_tbl);
	vol->eba_tbl = tbl;
}

/**
@@ -337,7 +448,7 @@ static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum)
 */
bool ubi_eba_is_mapped(struct ubi_volume *vol, int lnum)
{
	return vol->eba_tbl[lnum] >= 0;
	return vol->eba_tbl->entries[lnum].pnum >= 0;
}

/**
@@ -362,7 +473,7 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
	if (err)
		return err;

	pnum = vol->eba_tbl[lnum];
	pnum = vol->eba_tbl->entries[lnum].pnum;
	if (pnum < 0)
		/* This logical eraseblock is already unmapped */
		goto out_unlock;
@@ -370,7 +481,7 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
	dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum);

	down_read(&ubi->fm_eba_sem);
	vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED;
	vol->eba_tbl->entries[lnum].pnum = UBI_LEB_UNMAPPED;
	up_read(&ubi->fm_eba_sem);
	err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 0);

@@ -409,7 +520,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
	if (err)
		return err;

	pnum = vol->eba_tbl[lnum];
	pnum = vol->eba_tbl->entries[lnum].pnum;
	if (pnum < 0) {
		/*
		 * The logical eraseblock is not mapped, fill the whole buffer
@@ -658,7 +769,7 @@ static int try_recover_peb(struct ubi_volume *vol, int pnum, int lnum,
	mutex_unlock(&ubi->buf_mutex);

	if (!err)
		vol->eba_tbl[lnum] = new_pnum;
		vol->eba_tbl->entries[lnum].pnum = new_pnum;

out_put:
	up_read(&ubi->fm_eba_sem);
@@ -749,7 +860,7 @@ static int try_write_vid_and_data(struct ubi_volume *vol, int lnum,
		goto out_put;
	}

	opnum = vol->eba_tbl[lnum];
	opnum = vol->eba_tbl->entries[lnum].pnum;

	dbg_eba("write VID hdr and %d bytes at offset %d of LEB %d:%d, PEB %d",
		len, offset, vol_id, lnum, pnum);
@@ -771,7 +882,7 @@ static int try_write_vid_and_data(struct ubi_volume *vol, int lnum,
		}
	}

	vol->eba_tbl[lnum] = pnum;
	vol->eba_tbl->entries[lnum].pnum = pnum;

out_put:
	up_read(&ubi->fm_eba_sem);
@@ -812,7 +923,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
	if (err)
		return err;

	pnum = vol->eba_tbl[lnum];
	pnum = vol->eba_tbl->entries[lnum].pnum;
	if (pnum >= 0) {
		dbg_eba("write %d bytes at offset %d of LEB %d:%d, PEB %d",
			len, offset, vol_id, lnum, pnum);
@@ -930,7 +1041,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
	vid_hdr->used_ebs = cpu_to_be32(used_ebs);
	vid_hdr->data_crc = cpu_to_be32(crc);

	ubi_assert(vol->eba_tbl[lnum] < 0);
	ubi_assert(vol->eba_tbl->entries[lnum].pnum < 0);

	for (tries = 0; tries <= UBI_IO_RETRIES; tries++) {
		err = try_write_vid_and_data(vol, lnum, vid_hdr, buf, 0, len);
@@ -1140,9 +1251,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
	 * probably waiting on @ubi->move_mutex. No need to continue the work,
	 * cancel it.
	 */
	if (vol->eba_tbl[lnum] != from) {
	if (vol->eba_tbl->entries[lnum].pnum != from) {
		dbg_wl("LEB %d:%d is no longer mapped to PEB %d, mapped to PEB %d, cancel",
		       vol_id, lnum, from, vol->eba_tbl[lnum]);
		       vol_id, lnum, from, vol->eba_tbl->entries[lnum].pnum);
		err = MOVE_CANCEL_RACE;
		goto out_unlock_leb;
	}
@@ -1227,9 +1338,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
		cond_resched();
	}

	ubi_assert(vol->eba_tbl[lnum] == from);
	ubi_assert(vol->eba_tbl->entries[lnum].pnum == from);
	down_read(&ubi->fm_eba_sem);
	vol->eba_tbl[lnum] = to;
	vol->eba_tbl->entries[lnum].pnum = to;
	up_read(&ubi->fm_eba_sem);

out_unlock_buf:
@@ -1386,7 +1497,7 @@ int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap,
 */
int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
{
	int i, j, err, num_volumes;
	int i, err, num_volumes;
	struct ubi_ainf_volume *av;
	struct ubi_volume *vol;
	struct ubi_ainf_peb *aeb;
@@ -1402,35 +1513,39 @@ int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
	num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT;

	for (i = 0; i < num_volumes; i++) {
		struct ubi_eba_table *tbl;

		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;
		tbl = ubi_eba_create_table(vol, vol->reserved_pebs);
		if (IS_ERR(tbl)) {
			err = PTR_ERR(tbl);
			goto out_free;
		}

		for (j = 0; j < vol->reserved_pebs; j++)
			vol->eba_tbl[j] = UBI_LEB_UNMAPPED;
		ubi_eba_replace_table(vol, tbl);

		av = ubi_find_av(ai, idx2vol_id(ubi, i));
		if (!av)
			continue;

		ubi_rb_for_each_entry(rb, aeb, &av->root, u.rb) {
			if (aeb->lnum >= vol->reserved_pebs)
			if (aeb->lnum >= vol->reserved_pebs) {
				/*
				 * This may happen in case of an unclean reboot
				 * during re-size.
				 */
				ubi_move_aeb_to_list(av, aeb, &ai->erase);
			else
				vol->eba_tbl[aeb->lnum] = aeb->pnum;
			} else {
				struct ubi_eba_entry *entry;

				entry = &vol->eba_tbl->entries[aeb->lnum];
				entry->pnum = aeb->pnum;
			}
		}
	}

@@ -1467,8 +1582,7 @@ int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
	for (i = 0; i < num_volumes; i++) {
		if (!ubi->volumes[i])
			continue;
		kfree(ubi->volumes[i]->eba_tbl);
		ubi->volumes[i]->eba_tbl = NULL;
		ubi_eba_replace_table(ubi->volumes[i], NULL);
	}
	return err;
}
+7 −1
Original line number Diff line number Diff line
@@ -359,7 +359,7 @@ struct ubi_volume {
	long long upd_received;
	void *upd_buf;

	int *eba_tbl;
	struct ubi_eba_table *eba_tbl;
	unsigned int checked:1;
	unsigned int corrupted:1;
	unsigned int upd_marker:1;
@@ -864,6 +864,12 @@ static inline bool ubi_leb_valid(struct ubi_volume *vol, int lnum)
}

/* eba.c */
struct ubi_eba_table *ubi_eba_create_table(struct ubi_volume *vol,
					   int nentries);
void ubi_eba_destroy_table(struct ubi_eba_table *tbl);
void ubi_eba_copy_table(struct ubi_volume *vol, struct ubi_eba_table *dst,
			int nentries);
void ubi_eba_replace_table(struct ubi_volume *vol, struct ubi_eba_table *tbl);
void ubi_eba_get_ldesc(struct ubi_volume *vol, int lnum,
		       struct ubi_eba_leb_desc *ldesc);
bool ubi_eba_is_mapped(struct ubi_volume *vol, int lnum);
+17 −23
Original line number Diff line number Diff line
@@ -138,7 +138,7 @@ static void vol_release(struct device *dev)
{
	struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);

	kfree(vol->eba_tbl);
	ubi_eba_replace_table(vol, NULL);
	kfree(vol);
}

@@ -158,6 +158,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
	int i, err, vol_id = req->vol_id, do_free = 1;
	struct ubi_volume *vol;
	struct ubi_vtbl_record vtbl_rec;
	struct ubi_eba_table *eba_tbl = NULL;
	dev_t dev;

	if (ubi->ro_mode)
@@ -241,14 +242,13 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
	if (err)
		goto out_acc;

	vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int), GFP_KERNEL);
	if (!vol->eba_tbl) {
		err = -ENOMEM;
	eba_tbl = ubi_eba_create_table(vol, vol->reserved_pebs);
	if (IS_ERR(eba_tbl)) {
		err = PTR_ERR(eba_tbl);
		goto out_acc;
	}

	for (i = 0; i < vol->reserved_pebs; i++)
		vol->eba_tbl[i] = UBI_LEB_UNMAPPED;
	ubi_eba_replace_table(vol, eba_tbl);

	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
		vol->used_ebs = vol->reserved_pebs;
@@ -329,7 +329,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
	cdev_del(&vol->cdev);
out_mapping:
	if (do_free)
		kfree(vol->eba_tbl);
		ubi_eba_destroy_table(eba_tbl);
out_acc:
	spin_lock(&ubi->volumes_lock);
	ubi->rsvd_pebs -= vol->reserved_pebs;
@@ -427,10 +427,11 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
 */
int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
{
	int i, err, pebs, *new_mapping;
	int i, err, pebs;
	struct ubi_volume *vol = desc->vol;
	struct ubi_device *ubi = vol->ubi;
	struct ubi_vtbl_record vtbl_rec;
	struct ubi_eba_table *new_eba_tbl = NULL;
	int vol_id = vol->vol_id;

	if (ubi->ro_mode)
@@ -450,12 +451,9 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
	if (reserved_pebs == vol->reserved_pebs)
		return 0;

	new_mapping = kmalloc(reserved_pebs * sizeof(int), GFP_KERNEL);
	if (!new_mapping)
		return -ENOMEM;

	for (i = 0; i < reserved_pebs; i++)
		new_mapping[i] = UBI_LEB_UNMAPPED;
	new_eba_tbl = ubi_eba_create_table(vol, reserved_pebs);
	if (IS_ERR(new_eba_tbl))
		return PTR_ERR(new_eba_tbl);

	spin_lock(&ubi->volumes_lock);
	if (vol->ref_count > 1) {
@@ -481,10 +479,8 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
		}
		ubi->avail_pebs -= pebs;
		ubi->rsvd_pebs += pebs;
		for (i = 0; i < vol->reserved_pebs; i++)
			new_mapping[i] = vol->eba_tbl[i];
		kfree(vol->eba_tbl);
		vol->eba_tbl = new_mapping;
		ubi_eba_copy_table(vol, new_eba_tbl, vol->reserved_pebs);
		ubi_eba_replace_table(vol, new_eba_tbl);
		spin_unlock(&ubi->volumes_lock);
	}

@@ -498,10 +494,8 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
		ubi->rsvd_pebs += pebs;
		ubi->avail_pebs -= pebs;
		ubi_update_reserved(ubi);
		for (i = 0; i < reserved_pebs; i++)
			new_mapping[i] = vol->eba_tbl[i];
		kfree(vol->eba_tbl);
		vol->eba_tbl = new_mapping;
		ubi_eba_copy_table(vol, new_eba_tbl, reserved_pebs);
		ubi_eba_replace_table(vol, new_eba_tbl);
		spin_unlock(&ubi->volumes_lock);
	}

@@ -543,7 +537,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
		spin_unlock(&ubi->volumes_lock);
	}
out_free:
	kfree(new_mapping);
	kfree(new_eba_tbl);
	return err;
}