summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@free-electrons.com>2016-09-16 10:59:20 -0400
committerRichard Weinberger <richard@nod.at>2016-10-02 16:48:14 -0400
commitf036dfeb859cb412fdbe8e3ee74b632d9ce6387e (patch)
tree9cfd9243e10f5cb7622b100fd6a73218e26f96da /drivers/mtd/ubi
parent7b6b749b125a93d673ba12977007dfbd65a61c32 (diff)
UBI: simplify recover_peb() code
recover_peb() is using a convoluted retry/exit path. Add try_recover_peb() to simplify the retry logic and make sure we have a single exit path instead of manually releasing the resource in each error path. Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'drivers/mtd/ubi')
-rw-r--r--drivers/mtd/ubi/eba.c130
1 files changed, 77 insertions, 53 deletions
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index ebf517271d29..be59cfb81934 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -554,39 +554,37 @@ int ubi_eba_read_leb_sg(struct ubi_device *ubi, struct ubi_volume *vol,
554} 554}
555 555
556/** 556/**
557 * recover_peb - recover from write failure. 557 * try_recover_peb - try to recover from write failure.
558 * @ubi: UBI device description object 558 * @vol: volume description object
559 * @pnum: the physical eraseblock to recover 559 * @pnum: the physical eraseblock to recover
560 * @vol_id: volume ID
561 * @lnum: logical eraseblock number 560 * @lnum: logical eraseblock number
562 * @buf: data which was not written because of the write failure 561 * @buf: data which was not written because of the write failure
563 * @offset: offset of the failed write 562 * @offset: offset of the failed write
564 * @len: how many bytes should have been written 563 * @len: how many bytes should have been written
564 * @vid: VID header
565 * @retry: whether the caller should retry in case of failure
565 * 566 *
566 * This function is called in case of a write failure and moves all good data 567 * This function is called in case of a write failure and moves all good data
567 * from the potentially bad physical eraseblock to a good physical eraseblock. 568 * from the potentially bad physical eraseblock to a good physical eraseblock.
568 * This function also writes the data which was not written due to the failure. 569 * This function also writes the data which was not written due to the failure.
569 * Returns new physical eraseblock number in case of success, and a negative 570 * Returns 0 in case of success, and a negative error code in case of failure.
570 * error code in case of failure. 571 * In case of failure, the %retry parameter is set to false if this is a fatal
572 * error (retrying won't help), and true otherwise.
571 */ 573 */
572static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, 574static int try_recover_peb(struct ubi_volume *vol, int pnum, int lnum,
573 const void *buf, int offset, int len) 575 const void *buf, int offset, int len,
576 struct ubi_vid_hdr *vid_hdr, bool *retry)
574{ 577{
575 int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0; 578 struct ubi_device *ubi = vol->ubi;
576 struct ubi_volume *vol = ubi->volumes[idx]; 579 int new_pnum, err, vol_id = vol->vol_id, data_size;
577 struct ubi_vid_hdr *vid_hdr;
578 uint32_t crc; 580 uint32_t crc;
579 581
580 vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); 582 *retry = false;
581 if (!vid_hdr)
582 return -ENOMEM;
583 583
584retry:
585 new_pnum = ubi_wl_get_peb(ubi); 584 new_pnum = ubi_wl_get_peb(ubi);
586 if (new_pnum < 0) { 585 if (new_pnum < 0) {
587 ubi_free_vid_hdr(ubi, vid_hdr); 586 err = new_pnum;
588 up_read(&ubi->fm_eba_sem); 587 goto out_put;
589 return new_pnum;
590 } 588 }
591 589
592 ubi_msg(ubi, "recover PEB %d, move data to PEB %d", 590 ubi_msg(ubi, "recover PEB %d, move data to PEB %d",
@@ -596,7 +594,6 @@ retry:
596 if (err && err != UBI_IO_BITFLIPS) { 594 if (err && err != UBI_IO_BITFLIPS) {
597 if (err > 0) 595 if (err > 0)
598 err = -EIO; 596 err = -EIO;
599 up_read(&ubi->fm_eba_sem);
600 goto out_put; 597 goto out_put;
601 } 598 }
602 599
@@ -608,12 +605,12 @@ retry:
608 /* Read everything before the area where the write failure happened */ 605 /* Read everything before the area where the write failure happened */
609 if (offset > 0) { 606 if (offset > 0) {
610 err = ubi_io_read_data(ubi, ubi->peb_buf, pnum, 0, offset); 607 err = ubi_io_read_data(ubi, ubi->peb_buf, pnum, 0, offset);
611 if (err && err != UBI_IO_BITFLIPS) { 608 if (err && err != UBI_IO_BITFLIPS)
612 up_read(&ubi->fm_eba_sem);
613 goto out_unlock; 609 goto out_unlock;
614 }
615 } 610 }
616 611
612 *retry = true;
613
617 memcpy(ubi->peb_buf + offset, buf, len); 614 memcpy(ubi->peb_buf + offset, buf, len);
618 615
619 data_size = offset + len; 616 data_size = offset + len;
@@ -623,49 +620,76 @@ retry:
623 vid_hdr->data_size = cpu_to_be32(data_size); 620 vid_hdr->data_size = cpu_to_be32(data_size);
624 vid_hdr->data_crc = cpu_to_be32(crc); 621 vid_hdr->data_crc = cpu_to_be32(crc);
625 err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr); 622 err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
626 if (err) { 623 if (err)
627 mutex_unlock(&ubi->buf_mutex); 624 goto out_unlock;
628 up_read(&ubi->fm_eba_sem);
629 goto write_error;
630 }
631 625
632 err = ubi_io_write_data(ubi, ubi->peb_buf, new_pnum, 0, data_size); 626 err = ubi_io_write_data(ubi, ubi->peb_buf, new_pnum, 0, data_size);
633 if (err) {
634 mutex_unlock(&ubi->buf_mutex);
635 up_read(&ubi->fm_eba_sem);
636 goto write_error;
637 }
638 627
628out_unlock:
639 mutex_unlock(&ubi->buf_mutex); 629 mutex_unlock(&ubi->buf_mutex);
640 ubi_free_vid_hdr(ubi, vid_hdr);
641 630
642 vol->eba_tbl[lnum] = new_pnum; 631 if (!err)
632 vol->eba_tbl[lnum] = new_pnum;
633
634out_put:
643 up_read(&ubi->fm_eba_sem); 635 up_read(&ubi->fm_eba_sem);
644 ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
645 636
646 ubi_msg(ubi, "data was successfully recovered"); 637 if (!err) {
647 return 0; 638 ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
639 ubi_msg(ubi, "data was successfully recovered");
640 } else if (new_pnum >= 0) {
641 /*
642 * Bad luck? This physical eraseblock is bad too? Crud. Let's
643 * try to get another one.
644 */
645 ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1);
646 ubi_warn(ubi, "failed to write to PEB %d", new_pnum);
647 }
648 648
649out_unlock:
650 mutex_unlock(&ubi->buf_mutex);
651out_put:
652 ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1);
653 ubi_free_vid_hdr(ubi, vid_hdr);
654 return err; 649 return err;
650}
655 651
656write_error: 652/**
657 /* 653 * recover_peb - recover from write failure.
658 * Bad luck? This physical eraseblock is bad too? Crud. Let's try to 654 * @ubi: UBI device description object
659 * get another one. 655 * @pnum: the physical eraseblock to recover
660 */ 656 * @vol_id: volume ID
661 ubi_warn(ubi, "failed to write to PEB %d", new_pnum); 657 * @lnum: logical eraseblock number
662 ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1); 658 * @buf: data which was not written because of the write failure
663 if (++tries > UBI_IO_RETRIES) { 659 * @offset: offset of the failed write
664 ubi_free_vid_hdr(ubi, vid_hdr); 660 * @len: how many bytes should have been written
665 return err; 661 *
662 * This function is called in case of a write failure and moves all good data
663 * from the potentially bad physical eraseblock to a good physical eraseblock.
664 * This function also writes the data which was not written due to the failure.
665 * Returns 0 in case of success, and a negative error code in case of failure.
666 * This function tries %UBI_IO_RETRIES before giving up.
667 */
668static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
669 const void *buf, int offset, int len)
670{
671 int err, idx = vol_id2idx(ubi, vol_id), tries;
672 struct ubi_volume *vol = ubi->volumes[idx];
673 struct ubi_vid_hdr *vid_hdr;
674
675 vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
676 if (!vid_hdr)
677 return -ENOMEM;
678
679 for (tries = 0; tries <= UBI_IO_RETRIES; tries++) {
680 bool retry;
681
682 err = try_recover_peb(vol, pnum, lnum, buf, offset, len,
683 vid_hdr, &retry);
684 if (!err || !retry)
685 break;
686
687 ubi_msg(ubi, "try again");
666 } 688 }
667 ubi_msg(ubi, "try again"); 689
668 goto retry; 690 ubi_free_vid_hdr(ubi, vid_hdr);
691
692 return err;
669} 693}
670 694
671/** 695/**