diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-12-05 06:37:02 -0500 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-12-05 06:46:50 -0500 |
commit | 6fa6f5bbc3a2ad833a3d4b798140602004f70f5a (patch) | |
tree | 96aa4b8b9f672c098f12db1d359d8e942c8a80aa /drivers/mtd/ubi/eba.c | |
parent | 3c98b0a043f25fa44b289c2f35b9d6ad1d859ac9 (diff) |
UBI: handle write errors in WL worker
When a PEB is moved and a write error happens, UBI switches
to R/O mode, which is wrong, because we just copy the data
and may select a different PEB and re-try this. This patch
fixes WL worker's behavior.
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 | 37 |
1 files changed, 24 insertions, 13 deletions
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 2e4d6bf94582..048a606cebde 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c | |||
@@ -949,10 +949,14 @@ write_error: | |||
949 | * This function copies logical eraseblock from physical eraseblock @from to | 949 | * This function copies logical eraseblock from physical eraseblock @from to |
950 | * physical eraseblock @to. The @vid_hdr buffer may be changed by this | 950 | * physical eraseblock @to. The @vid_hdr buffer may be changed by this |
951 | * function. Returns: | 951 | * function. Returns: |
952 | * o %0 in case of success; | 952 | * o %0 in case of success; |
953 | * o %1 if the operation was canceled and should be tried later (e.g., | 953 | * o %1 if the operation was canceled because the volume is being deleted |
954 | * because a bit-flip was detected at the target PEB); | 954 | * or because the PEB was put meanwhile; |
955 | * o %2 if the volume is being deleted and this LEB should not be moved. | 955 | * o %2 if the operation was canceled because there was a write error to the |
956 | * target PEB; | ||
957 | * o %-EAGAIN if the operation was canceled because a bit-flip was detected | ||
958 | * in the target PEB; | ||
959 | * o a negative error code in case of failure. | ||
956 | */ | 960 | */ |
957 | int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | 961 | int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, |
958 | struct ubi_vid_hdr *vid_hdr) | 962 | struct ubi_vid_hdr *vid_hdr) |
@@ -978,7 +982,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
978 | /* | 982 | /* |
979 | * Note, we may race with volume deletion, which means that the volume | 983 | * Note, we may race with volume deletion, which means that the volume |
980 | * this logical eraseblock belongs to might be being deleted. Since the | 984 | * this logical eraseblock belongs to might be being deleted. Since the |
981 | * volume deletion unmaps all the volume's logical eraseblocks, it will | 985 | * volume deletion un-maps all the volume's logical eraseblocks, it will |
982 | * be locked in 'ubi_wl_put_peb()' and wait for the WL worker to finish. | 986 | * be locked in 'ubi_wl_put_peb()' and wait for the WL worker to finish. |
983 | */ | 987 | */ |
984 | vol = ubi->volumes[idx]; | 988 | vol = ubi->volumes[idx]; |
@@ -986,7 +990,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
986 | /* No need to do further work, cancel */ | 990 | /* No need to do further work, cancel */ |
987 | dbg_eba("volume %d is being removed, cancel", vol_id); | 991 | dbg_eba("volume %d is being removed, cancel", vol_id); |
988 | spin_unlock(&ubi->volumes_lock); | 992 | spin_unlock(&ubi->volumes_lock); |
989 | return 2; | 993 | return 1; |
990 | } | 994 | } |
991 | spin_unlock(&ubi->volumes_lock); | 995 | spin_unlock(&ubi->volumes_lock); |
992 | 996 | ||
@@ -1023,7 +1027,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
1023 | 1027 | ||
1024 | /* | 1028 | /* |
1025 | * OK, now the LEB is locked and we can safely start moving it. Since | 1029 | * OK, now the LEB is locked and we can safely start moving it. Since |
1026 | * this function utilizes thie @ubi->peb1_buf buffer which is shared | 1030 | * this function utilizes the @ubi->peb1_buf buffer which is shared |
1027 | * with some other functions, so lock the buffer by taking the | 1031 | * with some other functions, so lock the buffer by taking the |
1028 | * @ubi->buf_mutex. | 1032 | * @ubi->buf_mutex. |
1029 | */ | 1033 | */ |
@@ -1068,8 +1072,11 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
1068 | vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); | 1072 | vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); |
1069 | 1073 | ||
1070 | err = ubi_io_write_vid_hdr(ubi, to, vid_hdr); | 1074 | err = ubi_io_write_vid_hdr(ubi, to, vid_hdr); |
1071 | if (err) | 1075 | if (err) { |
1076 | if (err == -EIO) | ||
1077 | err = 2; | ||
1072 | goto out_unlock_buf; | 1078 | goto out_unlock_buf; |
1079 | } | ||
1073 | 1080 | ||
1074 | cond_resched(); | 1081 | cond_resched(); |
1075 | 1082 | ||
@@ -1079,14 +1086,17 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
1079 | if (err != UBI_IO_BITFLIPS) | 1086 | if (err != UBI_IO_BITFLIPS) |
1080 | ubi_warn("cannot read VID header back from PEB %d", to); | 1087 | ubi_warn("cannot read VID header back from PEB %d", to); |
1081 | else | 1088 | else |
1082 | err = 1; | 1089 | err = -EAGAIN; |
1083 | goto out_unlock_buf; | 1090 | goto out_unlock_buf; |
1084 | } | 1091 | } |
1085 | 1092 | ||
1086 | if (data_size > 0) { | 1093 | if (data_size > 0) { |
1087 | err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size); | 1094 | err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size); |
1088 | if (err) | 1095 | if (err) { |
1096 | if (err == -EIO) | ||
1097 | err = 2; | ||
1089 | goto out_unlock_buf; | 1098 | goto out_unlock_buf; |
1099 | } | ||
1090 | 1100 | ||
1091 | cond_resched(); | 1101 | cond_resched(); |
1092 | 1102 | ||
@@ -1101,15 +1111,16 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
1101 | ubi_warn("cannot read data back from PEB %d", | 1111 | ubi_warn("cannot read data back from PEB %d", |
1102 | to); | 1112 | to); |
1103 | else | 1113 | else |
1104 | err = 1; | 1114 | err = -EAGAIN; |
1105 | goto out_unlock_buf; | 1115 | goto out_unlock_buf; |
1106 | } | 1116 | } |
1107 | 1117 | ||
1108 | cond_resched(); | 1118 | cond_resched(); |
1109 | 1119 | ||
1110 | if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) { | 1120 | if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) { |
1111 | ubi_warn("read data back from PEB %d - it is different", | 1121 | ubi_warn("read data back from PEB %d and it is " |
1112 | to); | 1122 | "different", to); |
1123 | err = -EINVAL; | ||
1113 | goto out_unlock_buf; | 1124 | goto out_unlock_buf; |
1114 | } | 1125 | } |
1115 | } | 1126 | } |