Skip to content

Commit

Permalink
UBI: hide EBA internals
Browse files Browse the repository at this point in the history
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: Boris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
  • Loading branch information
Boris Brezillon authored and Richard Weinberger committed Oct 2, 2016
1 parent 1f81a5c commit 799dca3
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 51 deletions.
2 changes: 1 addition & 1 deletion drivers/mtd/ubi/build.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
}
}
Expand Down
166 changes: 140 additions & 26 deletions drivers/mtd/ubi/eba.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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;
}

/**
Expand All @@ -362,15 +473,15 @@ 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;

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);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
}
}

Expand Down Expand Up @@ -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;
}
8 changes: 7 additions & 1 deletion drivers/mtd/ubi/ubi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 799dca3

Please sign in to comment.