diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2007-08-29 07:51:52 -0400 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2007-10-14 06:10:21 -0400 |
commit | e88d6e10e5c848fd5be8f89e09e3bce2570886b7 (patch) | |
tree | 27b5547a0e24add89deafedaed784328bc3c173e /drivers/mtd/ubi/eba.c | |
parent | 33818bbb84cd371b63ed8849cc5264d24c8b3aa2 (diff) |
UBI: do not use vmalloc on I/O path
Similar reason as in case of the previous patch: it causes
deadlocks if a filesystem with writeback support works on top
of UBI. So pre-allocate needed buffers when attaching MTD device.
We also need mutexes to protect the buffers, but they do not
cause much contantion because they are used in recovery, torture,
and WL copy routines, which are called seldom.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'drivers/mtd/ubi/eba.c')
-rw-r--r-- | drivers/mtd/ubi/eba.c | 70 |
1 files changed, 24 insertions, 46 deletions
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 89193104c6c8..81bb6a33b555 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c | |||
@@ -495,16 +495,18 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, | |||
495 | int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0; | 495 | int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0; |
496 | struct ubi_volume *vol = ubi->volumes[idx]; | 496 | struct ubi_volume *vol = ubi->volumes[idx]; |
497 | struct ubi_vid_hdr *vid_hdr; | 497 | struct ubi_vid_hdr *vid_hdr; |
498 | unsigned char *new_buf; | ||
499 | 498 | ||
500 | vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); | 499 | vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); |
501 | if (!vid_hdr) { | 500 | if (!vid_hdr) { |
502 | return -ENOMEM; | 501 | return -ENOMEM; |
503 | } | 502 | } |
504 | 503 | ||
504 | mutex_lock(&ubi->buf_mutex); | ||
505 | |||
505 | retry: | 506 | retry: |
506 | new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN); | 507 | new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN); |
507 | if (new_pnum < 0) { | 508 | if (new_pnum < 0) { |
509 | mutex_unlock(&ubi->buf_mutex); | ||
508 | ubi_free_vid_hdr(ubi, vid_hdr); | 510 | ubi_free_vid_hdr(ubi, vid_hdr); |
509 | return new_pnum; | 511 | return new_pnum; |
510 | } | 512 | } |
@@ -524,31 +526,22 @@ retry: | |||
524 | goto write_error; | 526 | goto write_error; |
525 | 527 | ||
526 | data_size = offset + len; | 528 | data_size = offset + len; |
527 | new_buf = vmalloc(data_size); | 529 | memset(ubi->peb_buf1 + offset, 0xFF, len); |
528 | if (!new_buf) { | ||
529 | err = -ENOMEM; | ||
530 | goto out_put; | ||
531 | } | ||
532 | memset(new_buf + offset, 0xFF, len); | ||
533 | 530 | ||
534 | /* Read everything before the area where the write failure happened */ | 531 | /* Read everything before the area where the write failure happened */ |
535 | if (offset > 0) { | 532 | if (offset > 0) { |
536 | err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset); | 533 | err = ubi_io_read_data(ubi, ubi->peb_buf1, pnum, 0, offset); |
537 | if (err && err != UBI_IO_BITFLIPS) { | 534 | if (err && err != UBI_IO_BITFLIPS) |
538 | vfree(new_buf); | ||
539 | goto out_put; | 535 | goto out_put; |
540 | } | ||
541 | } | 536 | } |
542 | 537 | ||
543 | memcpy(new_buf + offset, buf, len); | 538 | memcpy(ubi->peb_buf1 + offset, buf, len); |
544 | 539 | ||
545 | err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size); | 540 | err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size); |
546 | if (err) { | 541 | if (err) |
547 | vfree(new_buf); | ||
548 | goto write_error; | 542 | goto write_error; |
549 | } | ||
550 | 543 | ||
551 | vfree(new_buf); | 544 | mutex_unlock(&ubi->buf_mutex); |
552 | ubi_free_vid_hdr(ubi, vid_hdr); | 545 | ubi_free_vid_hdr(ubi, vid_hdr); |
553 | 546 | ||
554 | vol->eba_tbl[lnum] = new_pnum; | 547 | vol->eba_tbl[lnum] = new_pnum; |
@@ -558,6 +551,7 @@ retry: | |||
558 | return 0; | 551 | return 0; |
559 | 552 | ||
560 | out_put: | 553 | out_put: |
554 | mutex_unlock(&ubi->buf_mutex); | ||
561 | ubi_wl_put_peb(ubi, new_pnum, 1); | 555 | ubi_wl_put_peb(ubi, new_pnum, 1); |
562 | ubi_free_vid_hdr(ubi, vid_hdr); | 556 | ubi_free_vid_hdr(ubi, vid_hdr); |
563 | return err; | 557 | return err; |
@@ -570,6 +564,7 @@ write_error: | |||
570 | ubi_warn("failed to write to PEB %d", new_pnum); | 564 | ubi_warn("failed to write to PEB %d", new_pnum); |
571 | ubi_wl_put_peb(ubi, new_pnum, 1); | 565 | ubi_wl_put_peb(ubi, new_pnum, 1); |
572 | if (++tries > UBI_IO_RETRIES) { | 566 | if (++tries > UBI_IO_RETRIES) { |
567 | mutex_unlock(&ubi->buf_mutex); | ||
573 | ubi_free_vid_hdr(ubi, vid_hdr); | 568 | ubi_free_vid_hdr(ubi, vid_hdr); |
574 | return err; | 569 | return err; |
575 | } | 570 | } |
@@ -965,7 +960,6 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
965 | int err, vol_id, lnum, data_size, aldata_size, pnum, idx; | 960 | int err, vol_id, lnum, data_size, aldata_size, pnum, idx; |
966 | struct ubi_volume *vol; | 961 | struct ubi_volume *vol; |
967 | uint32_t crc; | 962 | uint32_t crc; |
968 | void *buf, *buf1 = NULL; | ||
969 | 963 | ||
970 | vol_id = be32_to_cpu(vid_hdr->vol_id); | 964 | vol_id = be32_to_cpu(vid_hdr->vol_id); |
971 | lnum = be32_to_cpu(vid_hdr->lnum); | 965 | lnum = be32_to_cpu(vid_hdr->lnum); |
@@ -979,19 +973,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
979 | data_size = aldata_size = | 973 | data_size = aldata_size = |
980 | ubi->leb_size - be32_to_cpu(vid_hdr->data_pad); | 974 | ubi->leb_size - be32_to_cpu(vid_hdr->data_pad); |
981 | 975 | ||
982 | buf = vmalloc(aldata_size); | ||
983 | if (!buf) | ||
984 | return -ENOMEM; | ||
985 | |||
986 | /* | 976 | /* |
987 | * We do not want anybody to write to this logical eraseblock while we | 977 | * We do not want anybody to write to this logical eraseblock while we |
988 | * are moving it, so we lock it. | 978 | * are moving it, so we lock it. |
989 | */ | 979 | */ |
990 | err = leb_write_lock(ubi, vol_id, lnum); | 980 | err = leb_write_lock(ubi, vol_id, lnum); |
991 | if (err) { | 981 | if (err) |
992 | vfree(buf); | ||
993 | return err; | 982 | return err; |
994 | } | 983 | |
984 | mutex_lock(&ubi->buf_mutex); | ||
995 | 985 | ||
996 | /* | 986 | /* |
997 | * But the logical eraseblock might have been put by this time. | 987 | * But the logical eraseblock might have been put by this time. |
@@ -1023,7 +1013,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
1023 | /* OK, now the LEB is locked and we can safely start moving it */ | 1013 | /* OK, now the LEB is locked and we can safely start moving it */ |
1024 | 1014 | ||
1025 | dbg_eba("read %d bytes of data", aldata_size); | 1015 | dbg_eba("read %d bytes of data", aldata_size); |
1026 | err = ubi_io_read_data(ubi, buf, from, 0, aldata_size); | 1016 | err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size); |
1027 | if (err && err != UBI_IO_BITFLIPS) { | 1017 | if (err && err != UBI_IO_BITFLIPS) { |
1028 | ubi_warn("error %d while reading data from PEB %d", | 1018 | ubi_warn("error %d while reading data from PEB %d", |
1029 | err, from); | 1019 | err, from); |
@@ -1042,10 +1032,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
1042 | */ | 1032 | */ |
1043 | if (vid_hdr->vol_type == UBI_VID_DYNAMIC) | 1033 | if (vid_hdr->vol_type == UBI_VID_DYNAMIC) |
1044 | aldata_size = data_size = | 1034 | aldata_size = data_size = |
1045 | ubi_calc_data_len(ubi, buf, data_size); | 1035 | ubi_calc_data_len(ubi, ubi->peb_buf1, data_size); |
1046 | 1036 | ||
1047 | cond_resched(); | 1037 | cond_resched(); |
1048 | crc = crc32(UBI_CRC32_INIT, buf, data_size); | 1038 | crc = crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size); |
1049 | cond_resched(); | 1039 | cond_resched(); |
1050 | 1040 | ||
1051 | /* | 1041 | /* |
@@ -1076,23 +1066,18 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
1076 | } | 1066 | } |
1077 | 1067 | ||
1078 | if (data_size > 0) { | 1068 | if (data_size > 0) { |
1079 | err = ubi_io_write_data(ubi, buf, to, 0, aldata_size); | 1069 | err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size); |
1080 | if (err) | 1070 | if (err) |
1081 | goto out_unlock; | 1071 | goto out_unlock; |
1082 | 1072 | ||
1073 | cond_resched(); | ||
1074 | |||
1083 | /* | 1075 | /* |
1084 | * We've written the data and are going to read it back to make | 1076 | * We've written the data and are going to read it back to make |
1085 | * sure it was written correctly. | 1077 | * sure it was written correctly. |
1086 | */ | 1078 | */ |
1087 | buf1 = vmalloc(aldata_size); | ||
1088 | if (!buf1) { | ||
1089 | err = -ENOMEM; | ||
1090 | goto out_unlock; | ||
1091 | } | ||
1092 | 1079 | ||
1093 | cond_resched(); | 1080 | err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size); |
1094 | |||
1095 | err = ubi_io_read_data(ubi, buf1, to, 0, aldata_size); | ||
1096 | if (err) { | 1081 | if (err) { |
1097 | if (err != UBI_IO_BITFLIPS) | 1082 | if (err != UBI_IO_BITFLIPS) |
1098 | ubi_warn("cannot read data back from PEB %d", | 1083 | ubi_warn("cannot read data back from PEB %d", |
@@ -1102,7 +1087,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
1102 | 1087 | ||
1103 | cond_resched(); | 1088 | cond_resched(); |
1104 | 1089 | ||
1105 | if (memcmp(buf, buf1, aldata_size)) { | 1090 | if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) { |
1106 | ubi_warn("read data back from PEB %d - it is different", | 1091 | ubi_warn("read data back from PEB %d - it is different", |
1107 | to); | 1092 | to); |
1108 | goto out_unlock; | 1093 | goto out_unlock; |
@@ -1112,16 +1097,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
1112 | ubi_assert(vol->eba_tbl[lnum] == from); | 1097 | ubi_assert(vol->eba_tbl[lnum] == from); |
1113 | vol->eba_tbl[lnum] = to; | 1098 | vol->eba_tbl[lnum] = to; |
1114 | 1099 | ||
1115 | leb_write_unlock(ubi, vol_id, lnum); | ||
1116 | vfree(buf); | ||
1117 | vfree(buf1); | ||
1118 | |||
1119 | return 0; | ||
1120 | |||
1121 | out_unlock: | 1100 | out_unlock: |
1101 | mutex_unlock(&ubi->buf_mutex); | ||
1122 | leb_write_unlock(ubi, vol_id, lnum); | 1102 | leb_write_unlock(ubi, vol_id, lnum); |
1123 | vfree(buf); | ||
1124 | vfree(buf1); | ||
1125 | return err; | 1103 | return err; |
1126 | } | 1104 | } |
1127 | 1105 | ||