Skip to content

Commit 799dca3

Browse files
Boris Brezillonrichardweinberger
authored andcommitted
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: Boris Brezillon <boris.brezillon@free-electrons.com> Signed-off-by: Richard Weinberger <richard@nod.at>
1 parent 1f81a5c commit 799dca3

File tree

4 files changed

+165
-51
lines changed

4 files changed

+165
-51
lines changed

drivers/mtd/ubi/build.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ void ubi_free_internal_volumes(struct ubi_device *ubi)
574574

575575
for (i = ubi->vtbl_slots;
576576
i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
577-
kfree(ubi->volumes[i]->eba_tbl);
577+
ubi_eba_replace_table(ubi->volumes[i], NULL);
578578
kfree(ubi->volumes[i]);
579579
}
580580
}

drivers/mtd/ubi/eba.c

Lines changed: 140 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,30 @@
4949
/* Number of physical eraseblocks reserved for atomic LEB change operation */
5050
#define EBA_RESERVED_PEBS 1
5151

52+
/**
53+
* struct ubi_eba_entry - structure encoding a single LEB -> PEB association
54+
* @pnum: the physical eraseblock number attached to the LEB
55+
*
56+
* This structure is encoding a LEB -> PEB association. Note that the LEB
57+
* number is not stored here, because it is the index used to access the
58+
* entries table.
59+
*/
60+
struct ubi_eba_entry {
61+
int pnum;
62+
};
63+
64+
/**
65+
* struct ubi_eba_table - LEB -> PEB association information
66+
* @entries: the LEB to PEB mapping (one entry per LEB).
67+
*
68+
* This structure is private to the EBA logic and should be kept here.
69+
* It is encoding the LEB to PEB association table, and is subject to
70+
* changes.
71+
*/
72+
struct ubi_eba_table {
73+
struct ubi_eba_entry *entries;
74+
};
75+
5276
/**
5377
* next_sqnum - get next sequence number.
5478
* @ubi: UBI device description object
@@ -97,7 +121,94 @@ void ubi_eba_get_ldesc(struct ubi_volume *vol, int lnum,
97121
struct ubi_eba_leb_desc *ldesc)
98122
{
99123
ldesc->lnum = lnum;
100-
ldesc->pnum = vol->eba_tbl[lnum];
124+
ldesc->pnum = vol->eba_tbl->entries[lnum].pnum;
125+
}
126+
127+
/**
128+
* ubi_eba_create_table - allocate a new EBA table and initialize it with all
129+
* LEBs unmapped
130+
* @vol: volume containing the EBA table to copy
131+
* @nentries: number of entries in the table
132+
*
133+
* Allocate a new EBA table and initialize it with all LEBs unmapped.
134+
* Returns a valid pointer if it succeed, an ERR_PTR() otherwise.
135+
*/
136+
struct ubi_eba_table *ubi_eba_create_table(struct ubi_volume *vol,
137+
int nentries)
138+
{
139+
struct ubi_eba_table *tbl;
140+
int err = -ENOMEM;
141+
int i;
142+
143+
tbl = kzalloc(sizeof(*tbl), GFP_KERNEL);
144+
if (!tbl)
145+
return ERR_PTR(-ENOMEM);
146+
147+
tbl->entries = kmalloc_array(nentries, sizeof(*tbl->entries),
148+
GFP_KERNEL);
149+
if (!tbl->entries)
150+
goto err;
151+
152+
for (i = 0; i < nentries; i++)
153+
tbl->entries[i].pnum = UBI_LEB_UNMAPPED;
154+
155+
return tbl;
156+
157+
err:
158+
kfree(tbl->entries);
159+
kfree(tbl);
160+
161+
return ERR_PTR(err);
162+
}
163+
164+
/**
165+
* ubi_eba_destroy_table - destroy an EBA table
166+
* @tbl: the table to destroy
167+
*
168+
* Destroy an EBA table.
169+
*/
170+
void ubi_eba_destroy_table(struct ubi_eba_table *tbl)
171+
{
172+
if (!tbl)
173+
return;
174+
175+
kfree(tbl->entries);
176+
kfree(tbl);
177+
}
178+
179+
/**
180+
* ubi_eba_copy_table - copy the EBA table attached to vol into another table
181+
* @vol: volume containing the EBA table to copy
182+
* @dst: destination
183+
* @nentries: number of entries to copy
184+
*
185+
* Copy the EBA table stored in vol into the one pointed by dst.
186+
*/
187+
void ubi_eba_copy_table(struct ubi_volume *vol, struct ubi_eba_table *dst,
188+
int nentries)
189+
{
190+
struct ubi_eba_table *src;
191+
int i;
192+
193+
ubi_assert(dst && vol && vol->eba_tbl);
194+
195+
src = vol->eba_tbl;
196+
197+
for (i = 0; i < nentries; i++)
198+
dst->entries[i].pnum = src->entries[i].pnum;
199+
}
200+
201+
/**
202+
* ubi_eba_replace_table - assign a new EBA table to a volume
203+
* @vol: volume containing the EBA table to copy
204+
* @tbl: new EBA table
205+
*
206+
* Assign a new EBA table to the volume and release the old one.
207+
*/
208+
void ubi_eba_replace_table(struct ubi_volume *vol, struct ubi_eba_table *tbl)
209+
{
210+
ubi_eba_destroy_table(vol->eba_tbl);
211+
vol->eba_tbl = tbl;
101212
}
102213

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

343454
/**
@@ -362,15 +473,15 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
362473
if (err)
363474
return err;
364475

365-
pnum = vol->eba_tbl[lnum];
476+
pnum = vol->eba_tbl->entries[lnum].pnum;
366477
if (pnum < 0)
367478
/* This logical eraseblock is already unmapped */
368479
goto out_unlock;
369480

370481
dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum);
371482

372483
down_read(&ubi->fm_eba_sem);
373-
vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED;
484+
vol->eba_tbl->entries[lnum].pnum = UBI_LEB_UNMAPPED;
374485
up_read(&ubi->fm_eba_sem);
375486
err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 0);
376487

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

412-
pnum = vol->eba_tbl[lnum];
523+
pnum = vol->eba_tbl->entries[lnum].pnum;
413524
if (pnum < 0) {
414525
/*
415526
* 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,
658769
mutex_unlock(&ubi->buf_mutex);
659770

660771
if (!err)
661-
vol->eba_tbl[lnum] = new_pnum;
772+
vol->eba_tbl->entries[lnum].pnum = new_pnum;
662773

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

752-
opnum = vol->eba_tbl[lnum];
863+
opnum = vol->eba_tbl->entries[lnum].pnum;
753864

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

774-
vol->eba_tbl[lnum] = pnum;
885+
vol->eba_tbl->entries[lnum].pnum = pnum;
775886

776887
out_put:
777888
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,
812923
if (err)
813924
return err;
814925

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

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

9351046
for (tries = 0; tries <= UBI_IO_RETRIES; tries++) {
9361047
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,
11401251
* probably waiting on @ubi->move_mutex. No need to continue the work,
11411252
* cancel it.
11421253
*/
1143-
if (vol->eba_tbl[lnum] != from) {
1254+
if (vol->eba_tbl->entries[lnum].pnum != from) {
11441255
dbg_wl("LEB %d:%d is no longer mapped to PEB %d, mapped to PEB %d, cancel",
1145-
vol_id, lnum, from, vol->eba_tbl[lnum]);
1256+
vol_id, lnum, from, vol->eba_tbl->entries[lnum].pnum);
11461257
err = MOVE_CANCEL_RACE;
11471258
goto out_unlock_leb;
11481259
}
@@ -1227,9 +1338,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
12271338
cond_resched();
12281339
}
12291340

1230-
ubi_assert(vol->eba_tbl[lnum] == from);
1341+
ubi_assert(vol->eba_tbl->entries[lnum].pnum == from);
12311342
down_read(&ubi->fm_eba_sem);
1232-
vol->eba_tbl[lnum] = to;
1343+
vol->eba_tbl->entries[lnum].pnum = to;
12331344
up_read(&ubi->fm_eba_sem);
12341345

12351346
out_unlock_buf:
@@ -1386,7 +1497,7 @@ int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap,
13861497
*/
13871498
int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
13881499
{
1389-
int i, j, err, num_volumes;
1500+
int i, err, num_volumes;
13901501
struct ubi_ainf_volume *av;
13911502
struct ubi_volume *vol;
13921503
struct ubi_ainf_peb *aeb;
@@ -1402,35 +1513,39 @@ int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
14021513
num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT;
14031514

14041515
for (i = 0; i < num_volumes; i++) {
1516+
struct ubi_eba_table *tbl;
1517+
14051518
vol = ubi->volumes[i];
14061519
if (!vol)
14071520
continue;
14081521

14091522
cond_resched();
14101523

1411-
vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int),
1412-
GFP_KERNEL);
1413-
if (!vol->eba_tbl) {
1414-
err = -ENOMEM;
1524+
tbl = ubi_eba_create_table(vol, vol->reserved_pebs);
1525+
if (IS_ERR(tbl)) {
1526+
err = PTR_ERR(tbl);
14151527
goto out_free;
14161528
}
14171529

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

14211532
av = ubi_find_av(ai, idx2vol_id(ubi, i));
14221533
if (!av)
14231534
continue;
14241535

14251536
ubi_rb_for_each_entry(rb, aeb, &av->root, u.rb) {
1426-
if (aeb->lnum >= vol->reserved_pebs)
1537+
if (aeb->lnum >= vol->reserved_pebs) {
14271538
/*
14281539
* This may happen in case of an unclean reboot
14291540
* during re-size.
14301541
*/
14311542
ubi_move_aeb_to_list(av, aeb, &ai->erase);
1432-
else
1433-
vol->eba_tbl[aeb->lnum] = aeb->pnum;
1543+
} else {
1544+
struct ubi_eba_entry *entry;
1545+
1546+
entry = &vol->eba_tbl->entries[aeb->lnum];
1547+
entry->pnum = aeb->pnum;
1548+
}
14341549
}
14351550
}
14361551

@@ -1467,8 +1582,7 @@ int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
14671582
for (i = 0; i < num_volumes; i++) {
14681583
if (!ubi->volumes[i])
14691584
continue;
1470-
kfree(ubi->volumes[i]->eba_tbl);
1471-
ubi->volumes[i]->eba_tbl = NULL;
1585+
ubi_eba_replace_table(ubi->volumes[i], NULL);
14721586
}
14731587
return err;
14741588
}

drivers/mtd/ubi/ubi.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ struct ubi_volume {
359359
long long upd_received;
360360
void *upd_buf;
361361

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

866866
/* eba.c */
867+
struct ubi_eba_table *ubi_eba_create_table(struct ubi_volume *vol,
868+
int nentries);
869+
void ubi_eba_destroy_table(struct ubi_eba_table *tbl);
870+
void ubi_eba_copy_table(struct ubi_volume *vol, struct ubi_eba_table *dst,
871+
int nentries);
872+
void ubi_eba_replace_table(struct ubi_volume *vol, struct ubi_eba_table *tbl);
867873
void ubi_eba_get_ldesc(struct ubi_volume *vol, int lnum,
868874
struct ubi_eba_leb_desc *ldesc);
869875
bool ubi_eba_is_mapped(struct ubi_volume *vol, int lnum);

0 commit comments

Comments
 (0)