diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-12-04 13:52:44 -0500 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-12-05 06:46:49 -0500 |
commit | 4df581f3dc6a91a63b9965ac8bdb47d8db294e37 (patch) | |
tree | ddd44e9b424c999b615185c6c6d34c1d2983f6f4 /drivers/mtd/ubi | |
parent | ed45819f315b5a8844b5bfce881a18e9f3a055e7 (diff) |
UBI: fix deadlock
We cannot call 'ubi_wl_get_peb()' with @ubi->buf_mutex locked,
because 'ubi_wl_get_peb()' may force erasure, which, in turn,
may call 'torture_peb()' which also locks the @ubi->buf_mutex
and deadlocks.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'drivers/mtd/ubi')
-rw-r--r-- | drivers/mtd/ubi/eba.c | 14 |
1 files changed, 7 insertions, 7 deletions
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index d8966bae0e0b..2e4d6bf94582 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c | |||
@@ -504,12 +504,9 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, | |||
504 | if (!vid_hdr) | 504 | if (!vid_hdr) |
505 | return -ENOMEM; | 505 | return -ENOMEM; |
506 | 506 | ||
507 | mutex_lock(&ubi->buf_mutex); | ||
508 | |||
509 | retry: | 507 | retry: |
510 | new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN); | 508 | new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN); |
511 | if (new_pnum < 0) { | 509 | if (new_pnum < 0) { |
512 | mutex_unlock(&ubi->buf_mutex); | ||
513 | ubi_free_vid_hdr(ubi, vid_hdr); | 510 | ubi_free_vid_hdr(ubi, vid_hdr); |
514 | return new_pnum; | 511 | return new_pnum; |
515 | } | 512 | } |
@@ -529,20 +526,23 @@ retry: | |||
529 | goto write_error; | 526 | goto write_error; |
530 | 527 | ||
531 | data_size = offset + len; | 528 | data_size = offset + len; |
529 | mutex_lock(&ubi->buf_mutex); | ||
532 | memset(ubi->peb_buf1 + offset, 0xFF, len); | 530 | memset(ubi->peb_buf1 + offset, 0xFF, len); |
533 | 531 | ||
534 | /* Read everything before the area where the write failure happened */ | 532 | /* Read everything before the area where the write failure happened */ |
535 | if (offset > 0) { | 533 | if (offset > 0) { |
536 | err = ubi_io_read_data(ubi, ubi->peb_buf1, pnum, 0, offset); | 534 | err = ubi_io_read_data(ubi, ubi->peb_buf1, pnum, 0, offset); |
537 | if (err && err != UBI_IO_BITFLIPS) | 535 | if (err && err != UBI_IO_BITFLIPS) |
538 | goto out_put; | 536 | goto out_unlock; |
539 | } | 537 | } |
540 | 538 | ||
541 | memcpy(ubi->peb_buf1 + offset, buf, len); | 539 | memcpy(ubi->peb_buf1 + offset, buf, len); |
542 | 540 | ||
543 | err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size); | 541 | err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size); |
544 | if (err) | 542 | if (err) { |
543 | mutex_unlock(&ubi->buf_mutex); | ||
545 | goto write_error; | 544 | goto write_error; |
545 | } | ||
546 | 546 | ||
547 | mutex_unlock(&ubi->buf_mutex); | 547 | mutex_unlock(&ubi->buf_mutex); |
548 | ubi_free_vid_hdr(ubi, vid_hdr); | 548 | ubi_free_vid_hdr(ubi, vid_hdr); |
@@ -553,8 +553,9 @@ retry: | |||
553 | ubi_msg("data was successfully recovered"); | 553 | ubi_msg("data was successfully recovered"); |
554 | return 0; | 554 | return 0; |
555 | 555 | ||
556 | out_put: | 556 | out_unlock: |
557 | mutex_unlock(&ubi->buf_mutex); | 557 | mutex_unlock(&ubi->buf_mutex); |
558 | out_put: | ||
558 | ubi_wl_put_peb(ubi, new_pnum, 1); | 559 | ubi_wl_put_peb(ubi, new_pnum, 1); |
559 | ubi_free_vid_hdr(ubi, vid_hdr); | 560 | ubi_free_vid_hdr(ubi, vid_hdr); |
560 | return err; | 561 | return err; |
@@ -567,7 +568,6 @@ write_error: | |||
567 | ubi_warn("failed to write to PEB %d", new_pnum); | 568 | ubi_warn("failed to write to PEB %d", new_pnum); |
568 | ubi_wl_put_peb(ubi, new_pnum, 1); | 569 | ubi_wl_put_peb(ubi, new_pnum, 1); |
569 | if (++tries > UBI_IO_RETRIES) { | 570 | if (++tries > UBI_IO_RETRIES) { |
570 | mutex_unlock(&ubi->buf_mutex); | ||
571 | ubi_free_vid_hdr(ubi, vid_hdr); | 571 | ubi_free_vid_hdr(ubi, vid_hdr); |
572 | return err; | 572 | return err; |
573 | } | 573 | } |