Skip to content

Commit 2d78aee

Browse files
Boris Brezillonrichardweinberger
authored andcommitted
UBI: simplify LEB write and atomic LEB change code
ubi_eba_write_leb(), ubi_eba_write_leb_st() and ubi_eba_atomic_leb_change() are using a convoluted retry/exit path. Add the try_write_vid_and_data() function to simplify the retry logic and make sure we have a single exit path instead of manually releasing the resources in each error path. Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> Signed-off-by: Richard Weinberger <richard@nod.at>
1 parent f036dfe commit 2d78aee

File tree

1 file changed

+115
-170
lines changed

1 file changed

+115
-170
lines changed

drivers/mtd/ubi/eba.c

Lines changed: 115 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,69 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
692692
return err;
693693
}
694694

695+
/**
696+
* try_write_vid_and_data - try to write VID header and data to a new PEB.
697+
* @vol: volume description object
698+
* @lnum: logical eraseblock number
699+
* @vid_hdr: VID header to write
700+
* @buf: buffer containing the data
701+
* @offset: where to start writing data
702+
* @len: how many bytes should be written
703+
*
704+
* This function tries to write VID header and data belonging to logical
705+
* eraseblock @lnum of volume @vol to a new physical eraseblock. Returns zero
706+
* in case of success and a negative error code in case of failure.
707+
* In case of error, it is possible that something was still written to the
708+
* flash media, but may be some garbage.
709+
*/
710+
static int try_write_vid_and_data(struct ubi_volume *vol, int lnum,
711+
struct ubi_vid_hdr *vid_hdr, const void *buf,
712+
int offset, int len)
713+
{
714+
struct ubi_device *ubi = vol->ubi;
715+
int pnum, opnum, err, vol_id = vol->vol_id;
716+
717+
pnum = ubi_wl_get_peb(ubi);
718+
if (pnum < 0) {
719+
err = pnum;
720+
goto out_put;
721+
}
722+
723+
opnum = vol->eba_tbl[lnum];
724+
725+
dbg_eba("write VID hdr and %d bytes at offset %d of LEB %d:%d, PEB %d",
726+
len, offset, vol_id, lnum, pnum);
727+
728+
err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
729+
if (err) {
730+
ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d",
731+
vol_id, lnum, pnum);
732+
goto out_put;
733+
}
734+
735+
if (len) {
736+
err = ubi_io_write_data(ubi, buf, pnum, offset, len);
737+
if (err) {
738+
ubi_warn(ubi,
739+
"failed to write %d bytes at offset %d of LEB %d:%d, PEB %d",
740+
len, offset, vol_id, lnum, pnum);
741+
goto out_put;
742+
}
743+
}
744+
745+
vol->eba_tbl[lnum] = pnum;
746+
747+
out_put:
748+
up_read(&ubi->fm_eba_sem);
749+
750+
if (err && pnum >= 0)
751+
err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
752+
else if (!err && opnum >= 0)
753+
err = ubi_wl_put_peb(ubi, vol_id, lnum, opnum, 0);
754+
755+
return err;
756+
}
757+
695758
/**
696759
* ubi_eba_write_leb - write data to dynamic volume.
697760
* @ubi: UBI device description object
@@ -705,11 +768,12 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
705768
* @vol. Returns zero in case of success and a negative error code in case
706769
* of failure. In case of error, it is possible that something was still
707770
* written to the flash media, but may be some garbage.
771+
* This function retries %UBI_IO_RETRIES times before giving up.
708772
*/
709773
int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
710774
const void *buf, int offset, int len)
711775
{
712-
int err, pnum, tries = 0, vol_id = vol->vol_id;
776+
int err, pnum, tries, vol_id = vol->vol_id;
713777
struct ubi_vid_hdr *vid_hdr;
714778

715779
if (ubi->ro_mode)
@@ -730,11 +794,9 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
730794
if (err == -EIO && ubi->bad_allowed)
731795
err = recover_peb(ubi, pnum, vol_id, lnum, buf,
732796
offset, len);
733-
if (err)
734-
ubi_ro_mode(ubi);
735797
}
736-
leb_write_unlock(ubi, vol_id, lnum);
737-
return err;
798+
799+
goto out;
738800
}
739801

740802
/*
@@ -754,67 +816,31 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
754816
vid_hdr->compat = ubi_get_compat(ubi, vol_id);
755817
vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
756818

757-
retry:
758-
pnum = ubi_wl_get_peb(ubi);
759-
if (pnum < 0) {
760-
ubi_free_vid_hdr(ubi, vid_hdr);
761-
leb_write_unlock(ubi, vol_id, lnum);
762-
up_read(&ubi->fm_eba_sem);
763-
return pnum;
764-
}
765-
766-
dbg_eba("write VID hdr and %d bytes at offset %d of LEB %d:%d, PEB %d",
767-
len, offset, vol_id, lnum, pnum);
768-
769-
err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
770-
if (err) {
771-
ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d",
772-
vol_id, lnum, pnum);
773-
up_read(&ubi->fm_eba_sem);
774-
goto write_error;
775-
}
819+
for (tries = 0; tries <= UBI_IO_RETRIES; tries++) {
820+
err = try_write_vid_and_data(vol, lnum, vid_hdr, buf, offset,
821+
len);
822+
if (err != -EIO || !ubi->bad_allowed)
823+
break;
776824

777-
if (len) {
778-
err = ubi_io_write_data(ubi, buf, pnum, offset, len);
779-
if (err) {
780-
ubi_warn(ubi, "failed to write %d bytes at offset %d of LEB %d:%d, PEB %d",
781-
len, offset, vol_id, lnum, pnum);
782-
up_read(&ubi->fm_eba_sem);
783-
goto write_error;
784-
}
825+
/*
826+
* Fortunately, this is the first write operation to this
827+
* physical eraseblock, so just put it and request a new one.
828+
* We assume that if this physical eraseblock went bad, the
829+
* erase code will handle that.
830+
*/
831+
vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
832+
ubi_msg(ubi, "try another PEB");
785833
}
786834

787-
vol->eba_tbl[lnum] = pnum;
788-
up_read(&ubi->fm_eba_sem);
789-
790-
leb_write_unlock(ubi, vol_id, lnum);
791835
ubi_free_vid_hdr(ubi, vid_hdr);
792-
return 0;
793836

794-
write_error:
795-
if (err != -EIO || !ubi->bad_allowed) {
837+
out:
838+
if (err)
796839
ubi_ro_mode(ubi);
797-
leb_write_unlock(ubi, vol_id, lnum);
798-
ubi_free_vid_hdr(ubi, vid_hdr);
799-
return err;
800-
}
801840

802-
/*
803-
* Fortunately, this is the first write operation to this physical
804-
* eraseblock, so just put it and request a new one. We assume that if
805-
* this physical eraseblock went bad, the erase code will handle that.
806-
*/
807-
err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
808-
if (err || ++tries > UBI_IO_RETRIES) {
809-
ubi_ro_mode(ubi);
810-
leb_write_unlock(ubi, vol_id, lnum);
811-
ubi_free_vid_hdr(ubi, vid_hdr);
812-
return err;
813-
}
841+
leb_write_unlock(ubi, vol_id, lnum);
814842

815-
vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
816-
ubi_msg(ubi, "try another PEB");
817-
goto retry;
843+
return err;
818844
}
819845

820846
/**
@@ -842,7 +868,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
842868
int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
843869
int lnum, const void *buf, int len, int used_ebs)
844870
{
845-
int err, pnum, tries = 0, data_size = len, vol_id = vol->vol_id;
871+
int err, tries, data_size = len, vol_id = vol->vol_id;
846872
struct ubi_vid_hdr *vid_hdr;
847873
uint32_t crc;
848874

@@ -860,10 +886,8 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
860886
return -ENOMEM;
861887

862888
err = leb_write_lock(ubi, vol_id, lnum);
863-
if (err) {
864-
ubi_free_vid_hdr(ubi, vid_hdr);
865-
return err;
866-
}
889+
if (err)
890+
goto out;
867891

868892
vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
869893
vid_hdr->vol_id = cpu_to_be32(vol_id);
@@ -877,66 +901,26 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
877901
vid_hdr->used_ebs = cpu_to_be32(used_ebs);
878902
vid_hdr->data_crc = cpu_to_be32(crc);
879903

880-
retry:
881-
pnum = ubi_wl_get_peb(ubi);
882-
if (pnum < 0) {
883-
ubi_free_vid_hdr(ubi, vid_hdr);
884-
leb_write_unlock(ubi, vol_id, lnum);
885-
up_read(&ubi->fm_eba_sem);
886-
return pnum;
887-
}
888-
889-
dbg_eba("write VID hdr and %d bytes at LEB %d:%d, PEB %d, used_ebs %d",
890-
len, vol_id, lnum, pnum, used_ebs);
904+
ubi_assert(vol->eba_tbl[lnum] < 0);
891905

892-
err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
893-
if (err) {
894-
ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d",
895-
vol_id, lnum, pnum);
896-
up_read(&ubi->fm_eba_sem);
897-
goto write_error;
898-
}
906+
for (tries = 0; tries <= UBI_IO_RETRIES; tries++) {
907+
err = try_write_vid_and_data(vol, lnum, vid_hdr, buf, 0, len);
908+
if (err != -EIO || !ubi->bad_allowed)
909+
break;
899910

900-
err = ubi_io_write_data(ubi, buf, pnum, 0, len);
901-
if (err) {
902-
ubi_warn(ubi, "failed to write %d bytes of data to PEB %d",
903-
len, pnum);
904-
up_read(&ubi->fm_eba_sem);
905-
goto write_error;
911+
vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
912+
ubi_msg(ubi, "try another PEB");
906913
}
907914

908-
ubi_assert(vol->eba_tbl[lnum] < 0);
909-
vol->eba_tbl[lnum] = pnum;
910-
up_read(&ubi->fm_eba_sem);
915+
if (err)
916+
ubi_ro_mode(ubi);
911917

912918
leb_write_unlock(ubi, vol_id, lnum);
913-
ubi_free_vid_hdr(ubi, vid_hdr);
914-
return 0;
915-
916-
write_error:
917-
if (err != -EIO || !ubi->bad_allowed) {
918-
/*
919-
* This flash device does not admit of bad eraseblocks or
920-
* something nasty and unexpected happened. Switch to read-only
921-
* mode just in case.
922-
*/
923-
ubi_ro_mode(ubi);
924-
leb_write_unlock(ubi, vol_id, lnum);
925-
ubi_free_vid_hdr(ubi, vid_hdr);
926-
return err;
927-
}
928919

929-
err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
930-
if (err || ++tries > UBI_IO_RETRIES) {
931-
ubi_ro_mode(ubi);
932-
leb_write_unlock(ubi, vol_id, lnum);
933-
ubi_free_vid_hdr(ubi, vid_hdr);
934-
return err;
935-
}
920+
out:
921+
ubi_free_vid_hdr(ubi, vid_hdr);
936922

937-
vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
938-
ubi_msg(ubi, "try another PEB");
939-
goto retry;
923+
return err;
940924
}
941925

942926
/*
@@ -959,7 +943,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
959943
int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
960944
int lnum, const void *buf, int len)
961945
{
962-
int err, pnum, old_pnum, tries = 0, vol_id = vol->vol_id;
946+
int err, tries, vol_id = vol->vol_id;
963947
struct ubi_vid_hdr *vid_hdr;
964948
uint32_t crc;
965949

@@ -998,70 +982,31 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
998982
vid_hdr->copy_flag = 1;
999983
vid_hdr->data_crc = cpu_to_be32(crc);
1000984

1001-
retry:
1002-
pnum = ubi_wl_get_peb(ubi);
1003-
if (pnum < 0) {
1004-
err = pnum;
1005-
up_read(&ubi->fm_eba_sem);
1006-
goto out_leb_unlock;
1007-
}
1008-
1009-
dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d",
1010-
vol_id, lnum, vol->eba_tbl[lnum], pnum);
985+
dbg_eba("change LEB %d:%d", vol_id, lnum);
1011986

1012-
err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
1013-
if (err) {
1014-
ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d",
1015-
vol_id, lnum, pnum);
1016-
up_read(&ubi->fm_eba_sem);
1017-
goto write_error;
1018-
}
987+
for (tries = 0; tries <= UBI_IO_RETRIES; tries++) {
988+
err = try_write_vid_and_data(vol, lnum, vid_hdr, buf, 0, len);
989+
if (err != -EIO || !ubi->bad_allowed)
990+
break;
1019991

1020-
err = ubi_io_write_data(ubi, buf, pnum, 0, len);
1021-
if (err) {
1022-
ubi_warn(ubi, "failed to write %d bytes of data to PEB %d",
1023-
len, pnum);
1024-
up_read(&ubi->fm_eba_sem);
1025-
goto write_error;
992+
vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
993+
ubi_msg(ubi, "try another PEB");
1026994
}
1027995

1028-
old_pnum = vol->eba_tbl[lnum];
1029-
vol->eba_tbl[lnum] = pnum;
1030-
up_read(&ubi->fm_eba_sem);
1031-
1032-
if (old_pnum >= 0) {
1033-
err = ubi_wl_put_peb(ubi, vol_id, lnum, old_pnum, 0);
1034-
if (err)
1035-
goto out_leb_unlock;
1036-
}
996+
/*
997+
* This flash device does not admit of bad eraseblocks or
998+
* something nasty and unexpected happened. Switch to read-only
999+
* mode just in case.
1000+
*/
1001+
if (err)
1002+
ubi_ro_mode(ubi);
10371003

1038-
out_leb_unlock:
10391004
leb_write_unlock(ubi, vol_id, lnum);
1005+
10401006
out_mutex:
10411007
mutex_unlock(&ubi->alc_mutex);
10421008
ubi_free_vid_hdr(ubi, vid_hdr);
10431009
return err;
1044-
1045-
write_error:
1046-
if (err != -EIO || !ubi->bad_allowed) {
1047-
/*
1048-
* This flash device does not admit of bad eraseblocks or
1049-
* something nasty and unexpected happened. Switch to read-only
1050-
* mode just in case.
1051-
*/
1052-
ubi_ro_mode(ubi);
1053-
goto out_leb_unlock;
1054-
}
1055-
1056-
err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
1057-
if (err || ++tries > UBI_IO_RETRIES) {
1058-
ubi_ro_mode(ubi);
1059-
goto out_leb_unlock;
1060-
}
1061-
1062-
vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
1063-
ubi_msg(ubi, "try another PEB");
1064-
goto retry;
10651010
}
10661011

10671012
/**

0 commit comments

Comments
 (0)