aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Weinberger <richard@nod.at>2014-09-22 09:36:40 -0400
committerRichard Weinberger <richard@nod.at>2015-03-26 17:46:05 -0400
commitdaef3dd1f0ae71bf04a32af4ef643baf040bb73d (patch)
tree74ce5537d58c2489653b3a9643a63f8c0eec84d7
parentee59ba8b064f692a1dee99b6f3ba30b0e904b2c1 (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.c86
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 */
24static 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 */
42static 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 */
53static 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 */
66static 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
1246out_kfree: 1327out_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);
1249out: 1331out:
1250 return ret; 1332 return ret;
1251} 1333}