diff options
author | Richard Weinberger <richard@nod.at> | 2014-09-22 09:36:40 -0400 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2015-03-26 17:46:05 -0400 |
commit | daef3dd1f0ae71bf04a32af4ef643baf040bb73d (patch) | |
tree | 74ce5537d58c2489653b3a9643a63f8c0eec84d7 | |
parent | ee59ba8b064f692a1dee99b6f3ba30b0e904b2c1 (diff) |
UBI: Fastmap: Add self check to detect absent PEBs
This self check allows Fastmap to detect absent PEBs while
writing a new fastmap to the MTD device.
It will help to find implementation issues in Fastmap.
Signed-off-by: Richard Weinberger <richard@nod.at>
-rw-r--r-- | drivers/mtd/ubi/fastmap.c | 86 |
1 files changed, 84 insertions, 2 deletions
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index db2625d3ecd9..13492fef6471 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2012 Linutronix GmbH | 2 | * Copyright (c) 2012 Linutronix GmbH |
3 | * Copyright (c) 2014 sigma star gmbh | ||
3 | * Author: Richard Weinberger <richard@nod.at> | 4 | * Author: Richard Weinberger <richard@nod.at> |
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
@@ -17,6 +18,69 @@ | |||
17 | #include "ubi.h" | 18 | #include "ubi.h" |
18 | 19 | ||
19 | /** | 20 | /** |
21 | * init_seen - allocate memory for used for debugging. | ||
22 | * @ubi: UBI device description object | ||
23 | */ | ||
24 | static inline int *init_seen(struct ubi_device *ubi) | ||
25 | { | ||
26 | int *ret; | ||
27 | |||
28 | if (!ubi_dbg_chk_fastmap(ubi)) | ||
29 | return NULL; | ||
30 | |||
31 | ret = kcalloc(ubi->peb_count, sizeof(int), GFP_KERNEL); | ||
32 | if (!ret) | ||
33 | return ERR_PTR(-ENOMEM); | ||
34 | |||
35 | return ret; | ||
36 | } | ||
37 | |||
38 | /** | ||
39 | * free_seen - free the seen logic integer array. | ||
40 | * @seen: integer array of @ubi->peb_count size | ||
41 | */ | ||
42 | static inline void free_seen(int *seen) | ||
43 | { | ||
44 | kfree(seen); | ||
45 | } | ||
46 | |||
47 | /** | ||
48 | * set_seen - mark a PEB as seen. | ||
49 | * @ubi: UBI device description object | ||
50 | * @pnum: The PEB to be makred as seen | ||
51 | * @seen: integer array of @ubi->peb_count size | ||
52 | */ | ||
53 | static inline void set_seen(struct ubi_device *ubi, int pnum, int *seen) | ||
54 | { | ||
55 | if (!ubi_dbg_chk_fastmap(ubi) || !seen) | ||
56 | return; | ||
57 | |||
58 | seen[pnum] = 1; | ||
59 | } | ||
60 | |||
61 | /** | ||
62 | * self_check_seen - check whether all PEB have been seen by fastmap. | ||
63 | * @ubi: UBI device description object | ||
64 | * @seen: integer array of @ubi->peb_count size | ||
65 | */ | ||
66 | static int self_check_seen(struct ubi_device *ubi, int *seen) | ||
67 | { | ||
68 | int pnum, ret = 0; | ||
69 | |||
70 | if (!ubi_dbg_chk_fastmap(ubi) || !seen) | ||
71 | return 0; | ||
72 | |||
73 | for (pnum = 0; pnum < ubi->peb_count; pnum++) { | ||
74 | if (!seen[pnum] && ubi->lookuptbl[pnum]) { | ||
75 | ubi_err(ubi, "self-check failed for PEB %d, fastmap didn't see it", pnum); | ||
76 | ret = -EINVAL; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | /** | ||
20 | * ubi_calc_fm_size - calculates the fastmap size in bytes for an UBI device. | 84 | * ubi_calc_fm_size - calculates the fastmap size in bytes for an UBI device. |
21 | * @ubi: UBI device description object | 85 | * @ubi: UBI device description object |
22 | */ | 86 | */ |
@@ -1030,6 +1094,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, | |||
1030 | struct ubi_work *ubi_wrk; | 1094 | struct ubi_work *ubi_wrk; |
1031 | int ret, i, j, free_peb_count, used_peb_count, vol_count; | 1095 | int ret, i, j, free_peb_count, used_peb_count, vol_count; |
1032 | int scrub_peb_count, erase_peb_count; | 1096 | int scrub_peb_count, erase_peb_count; |
1097 | int *seen_pebs = NULL; | ||
1033 | 1098 | ||
1034 | fm_raw = ubi->fm_buf; | 1099 | fm_raw = ubi->fm_buf; |
1035 | memset(ubi->fm_buf, 0, ubi->fm_size); | 1100 | memset(ubi->fm_buf, 0, ubi->fm_size); |
@@ -1046,6 +1111,12 @@ static int ubi_write_fastmap(struct ubi_device *ubi, | |||
1046 | goto out_kfree; | 1111 | goto out_kfree; |
1047 | } | 1112 | } |
1048 | 1113 | ||
1114 | seen_pebs = init_seen(ubi); | ||
1115 | if (IS_ERR(seen_pebs)) { | ||
1116 | ret = PTR_ERR(seen_pebs); | ||
1117 | goto out_kfree; | ||
1118 | } | ||
1119 | |||
1049 | spin_lock(&ubi->volumes_lock); | 1120 | spin_lock(&ubi->volumes_lock); |
1050 | spin_lock(&ubi->wl_lock); | 1121 | spin_lock(&ubi->wl_lock); |
1051 | 1122 | ||
@@ -1076,8 +1147,10 @@ static int ubi_write_fastmap(struct ubi_device *ubi, | |||
1076 | fmpl1->size = cpu_to_be16(ubi->fm_pool.size); | 1147 | fmpl1->size = cpu_to_be16(ubi->fm_pool.size); |
1077 | fmpl1->max_size = cpu_to_be16(ubi->fm_pool.max_size); | 1148 | fmpl1->max_size = cpu_to_be16(ubi->fm_pool.max_size); |
1078 | 1149 | ||
1079 | for (i = 0; i < ubi->fm_pool.size; i++) | 1150 | for (i = 0; i < ubi->fm_pool.size; i++) { |
1080 | fmpl1->pebs[i] = cpu_to_be32(ubi->fm_pool.pebs[i]); | 1151 | fmpl1->pebs[i] = cpu_to_be32(ubi->fm_pool.pebs[i]); |
1152 | set_seen(ubi, ubi->fm_pool.pebs[i], seen_pebs); | ||
1153 | } | ||
1081 | 1154 | ||
1082 | fmpl2 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos); | 1155 | fmpl2 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos); |
1083 | fm_pos += sizeof(*fmpl2); | 1156 | fm_pos += sizeof(*fmpl2); |
@@ -1085,14 +1158,17 @@ static int ubi_write_fastmap(struct ubi_device *ubi, | |||
1085 | fmpl2->size = cpu_to_be16(ubi->fm_wl_pool.size); | 1158 | fmpl2->size = cpu_to_be16(ubi->fm_wl_pool.size); |
1086 | fmpl2->max_size = cpu_to_be16(ubi->fm_wl_pool.max_size); | 1159 | fmpl2->max_size = cpu_to_be16(ubi->fm_wl_pool.max_size); |
1087 | 1160 | ||
1088 | for (i = 0; i < ubi->fm_wl_pool.size; i++) | 1161 | for (i = 0; i < ubi->fm_wl_pool.size; i++) { |
1089 | fmpl2->pebs[i] = cpu_to_be32(ubi->fm_wl_pool.pebs[i]); | 1162 | fmpl2->pebs[i] = cpu_to_be32(ubi->fm_wl_pool.pebs[i]); |
1163 | set_seen(ubi, ubi->fm_wl_pool.pebs[i], seen_pebs); | ||
1164 | } | ||
1090 | 1165 | ||
1091 | for (node = rb_first(&ubi->free); node; node = rb_next(node)) { | 1166 | for (node = rb_first(&ubi->free); node; node = rb_next(node)) { |
1092 | wl_e = rb_entry(node, struct ubi_wl_entry, u.rb); | 1167 | wl_e = rb_entry(node, struct ubi_wl_entry, u.rb); |
1093 | fec = (struct ubi_fm_ec *)(fm_raw + fm_pos); | 1168 | fec = (struct ubi_fm_ec *)(fm_raw + fm_pos); |
1094 | 1169 | ||
1095 | fec->pnum = cpu_to_be32(wl_e->pnum); | 1170 | fec->pnum = cpu_to_be32(wl_e->pnum); |
1171 | set_seen(ubi, wl_e->pnum, seen_pebs); | ||
1096 | fec->ec = cpu_to_be32(wl_e->ec); | 1172 | fec->ec = cpu_to_be32(wl_e->ec); |
1097 | 1173 | ||
1098 | free_peb_count++; | 1174 | free_peb_count++; |
@@ -1106,6 +1182,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, | |||
1106 | fec = (struct ubi_fm_ec *)(fm_raw + fm_pos); | 1182 | fec = (struct ubi_fm_ec *)(fm_raw + fm_pos); |
1107 | 1183 | ||
1108 | fec->pnum = cpu_to_be32(wl_e->pnum); | 1184 | fec->pnum = cpu_to_be32(wl_e->pnum); |
1185 | set_seen(ubi, wl_e->pnum, seen_pebs); | ||
1109 | fec->ec = cpu_to_be32(wl_e->ec); | 1186 | fec->ec = cpu_to_be32(wl_e->ec); |
1110 | 1187 | ||
1111 | used_peb_count++; | 1188 | used_peb_count++; |
@@ -1132,6 +1209,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, | |||
1132 | fec = (struct ubi_fm_ec *)(fm_raw + fm_pos); | 1209 | fec = (struct ubi_fm_ec *)(fm_raw + fm_pos); |
1133 | 1210 | ||
1134 | fec->pnum = cpu_to_be32(wl_e->pnum); | 1211 | fec->pnum = cpu_to_be32(wl_e->pnum); |
1212 | set_seen(ubi, wl_e->pnum, seen_pebs); | ||
1135 | fec->ec = cpu_to_be32(wl_e->ec); | 1213 | fec->ec = cpu_to_be32(wl_e->ec); |
1136 | 1214 | ||
1137 | scrub_peb_count++; | 1215 | scrub_peb_count++; |
@@ -1149,6 +1227,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, | |||
1149 | fec = (struct ubi_fm_ec *)(fm_raw + fm_pos); | 1227 | fec = (struct ubi_fm_ec *)(fm_raw + fm_pos); |
1150 | 1228 | ||
1151 | fec->pnum = cpu_to_be32(wl_e->pnum); | 1229 | fec->pnum = cpu_to_be32(wl_e->pnum); |
1230 | set_seen(ubi, wl_e->pnum, seen_pebs); | ||
1152 | fec->ec = cpu_to_be32(wl_e->ec); | 1231 | fec->ec = cpu_to_be32(wl_e->ec); |
1153 | 1232 | ||
1154 | erase_peb_count++; | 1233 | erase_peb_count++; |
@@ -1208,6 +1287,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, | |||
1208 | 1287 | ||
1209 | for (i = 0; i < new_fm->used_blocks; i++) { | 1288 | for (i = 0; i < new_fm->used_blocks; i++) { |
1210 | fmsb->block_loc[i] = cpu_to_be32(new_fm->e[i]->pnum); | 1289 | fmsb->block_loc[i] = cpu_to_be32(new_fm->e[i]->pnum); |
1290 | set_seen(ubi, new_fm->e[i]->pnum, seen_pebs); | ||
1211 | fmsb->block_ec[i] = cpu_to_be32(new_fm->e[i]->ec); | 1291 | fmsb->block_ec[i] = cpu_to_be32(new_fm->e[i]->ec); |
1212 | } | 1292 | } |
1213 | 1293 | ||
@@ -1241,11 +1321,13 @@ static int ubi_write_fastmap(struct ubi_device *ubi, | |||
1241 | ubi_assert(new_fm); | 1321 | ubi_assert(new_fm); |
1242 | ubi->fm = new_fm; | 1322 | ubi->fm = new_fm; |
1243 | 1323 | ||
1324 | ret = self_check_seen(ubi, seen_pebs); | ||
1244 | dbg_bld("fastmap written!"); | 1325 | dbg_bld("fastmap written!"); |
1245 | 1326 | ||
1246 | out_kfree: | 1327 | out_kfree: |
1247 | ubi_free_vid_hdr(ubi, avhdr); | 1328 | ubi_free_vid_hdr(ubi, avhdr); |
1248 | ubi_free_vid_hdr(ubi, dvhdr); | 1329 | ubi_free_vid_hdr(ubi, dvhdr); |
1330 | free_seen(seen_pebs); | ||
1249 | out: | 1331 | out: |
1250 | return ret; | 1332 | return ret; |
1251 | } | 1333 | } |