aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorRichard Weinberger <richard@nod.at>2014-11-10 10:11:40 -0500
committerRichard Weinberger <richard@nod.at>2015-03-26 17:46:03 -0400
commit5ca97ad83800938e8aeea622821a26d69d2052bf (patch)
tree91c62e747bd2dfd33dbed9bba7faa89c1b38b91d /drivers/mtd
parent61de74ce2fa2cc9eee85cf5edc6525b12831b507 (diff)
UBI: Fastmap: Rework fastmap error paths
If UBI is unable to write the fastmap to the device we have make sure that upon next attach UBI will fall back to scanning mode. In case we cannot ensure that they only thing we can do is falling back to read-only mode. The current error handling code is not powercut proof. It could happen that a powercut while invalidating would lead to a state where an too old fastmap could be used upon attach. This patch addresses the issue by writing a fake fastmap super block to a fresh PEB instead of reerasing the existing one. The fake fastmap super block will UBI case to do a full scan. Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/ubi/fastmap.c162
1 files changed, 114 insertions, 48 deletions
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index 762e25c6a2d2..db2625d3ecd9 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -1300,31 +1300,87 @@ out:
1300/** 1300/**
1301 * invalidate_fastmap - destroys a fastmap. 1301 * invalidate_fastmap - destroys a fastmap.
1302 * @ubi: UBI device object 1302 * @ubi: UBI device object
1303 * @fm: the fastmap to be destroyed
1304 * 1303 *
1304 * This function ensures that upon next UBI attach a full scan
1305 * is issued. We need this if UBI is about to write a new fastmap
1306 * but is unable to do so. In this case we have two options:
1307 * a) Make sure that the current fastmap will not be usued upon
1308 * attach time and contine or b) fall back to RO mode to have the
1309 * current fastmap in a valid state.
1305 * Returns 0 on success, < 0 indicates an internal error. 1310 * Returns 0 on success, < 0 indicates an internal error.
1306 */ 1311 */
1307static int invalidate_fastmap(struct ubi_device *ubi, 1312static int invalidate_fastmap(struct ubi_device *ubi)
1308 struct ubi_fastmap_layout *fm)
1309{ 1313{
1310 int ret; 1314 int ret;
1311 struct ubi_vid_hdr *vh; 1315 struct ubi_fastmap_layout *fm;
1316 struct ubi_wl_entry *e;
1317 struct ubi_vid_hdr *vh = NULL;
1312 1318
1313 ret = erase_block(ubi, fm->e[0]->pnum); 1319 if (!ubi->fm)
1314 if (ret < 0) 1320 return 0;
1315 return ret; 1321
1322 ubi->fm = NULL;
1323
1324 ret = -ENOMEM;
1325 fm = kzalloc(sizeof(*fm), GFP_KERNEL);
1326 if (!fm)
1327 goto out;
1316 1328
1317 vh = new_fm_vhdr(ubi, UBI_FM_SB_VOLUME_ID); 1329 vh = new_fm_vhdr(ubi, UBI_FM_SB_VOLUME_ID);
1318 if (!vh) 1330 if (!vh)
1319 return -ENOMEM; 1331 goto out_free_fm;
1332
1333 ret = -ENOSPC;
1334 e = ubi_wl_get_fm_peb(ubi, 1);
1335 if (!e)
1336 goto out_free_fm;
1320 1337
1321 /* deleting the current fastmap SB is not enough, an old SB may exist, 1338 /*
1322 * so create a (corrupted) SB such that fastmap will find it and fall 1339 * Create fake fastmap such that UBI will fall back
1323 * back to scanning mode in any case */ 1340 * to scanning mode.
1341 */
1324 vh->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); 1342 vh->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
1325 ret = ubi_io_write_vid_hdr(ubi, fm->e[0]->pnum, vh); 1343 ret = ubi_io_write_vid_hdr(ubi, e->pnum, vh);
1344 if (ret < 0) {
1345 ubi_wl_put_fm_peb(ubi, e, 0, 0);
1346 goto out_free_fm;
1347 }
1326 1348
1349 fm->used_blocks = 1;
1350 fm->e[0] = e;
1351
1352 ubi->fm = fm;
1353
1354out:
1355 ubi_free_vid_hdr(ubi, vh);
1327 return ret; 1356 return ret;
1357
1358out_free_fm:
1359 kfree(fm);
1360 goto out;
1361}
1362
1363/**
1364 * return_fm_pebs - returns all PEBs used by a fastmap back to the
1365 * WL sub-system.
1366 * @ubi: UBI device object
1367 * @fm: fastmap layout object
1368 */
1369static void return_fm_pebs(struct ubi_device *ubi,
1370 struct ubi_fastmap_layout *fm)
1371{
1372 int i;
1373
1374 if (!fm)
1375 return;
1376
1377 for (i = 0; i < fm->used_blocks; i++) {
1378 if (fm->e[i]) {
1379 ubi_wl_put_fm_peb(ubi, fm->e[i], i,
1380 fm->to_be_tortured[i]);
1381 fm->e[i] = NULL;
1382 }
1383 }
1328} 1384}
1329 1385
1330/** 1386/**
@@ -1336,7 +1392,7 @@ static int invalidate_fastmap(struct ubi_device *ubi,
1336 */ 1392 */
1337int ubi_update_fastmap(struct ubi_device *ubi) 1393int ubi_update_fastmap(struct ubi_device *ubi)
1338{ 1394{
1339 int ret, i; 1395 int ret, i, j;
1340 struct ubi_fastmap_layout *new_fm, *old_fm; 1396 struct ubi_fastmap_layout *new_fm, *old_fm;
1341 struct ubi_wl_entry *tmp_e; 1397 struct ubi_wl_entry *tmp_e;
1342 1398
@@ -1376,34 +1432,40 @@ int ubi_update_fastmap(struct ubi_device *ubi)
1376 tmp_e = ubi_wl_get_fm_peb(ubi, 0); 1432 tmp_e = ubi_wl_get_fm_peb(ubi, 0);
1377 spin_unlock(&ubi->wl_lock); 1433 spin_unlock(&ubi->wl_lock);
1378 1434
1379 if (!tmp_e && !old_fm) { 1435 if (!tmp_e) {
1380 int j; 1436 if (old_fm && old_fm->e[i]) {
1381 ubi_err(ubi, "could not get any free erase block"); 1437 ret = erase_block(ubi, old_fm->e[i]->pnum);
1382 1438 if (ret < 0) {
1383 for (j = 1; j < i; j++) 1439 ubi_err(ubi, "could not erase old fastmap PEB");
1384 ubi_wl_put_fm_peb(ubi, new_fm->e[j], j, 0); 1440
1385 1441 for (j = 1; j < i; j++) {
1386 ret = -ENOSPC; 1442 ubi_wl_put_fm_peb(ubi, new_fm->e[j],
1387 goto err; 1443 j, 0);
1388 } else if (!tmp_e && old_fm && old_fm->e[i]) { 1444 new_fm->e[j] = NULL;
1389 ret = erase_block(ubi, old_fm->e[i]->pnum); 1445 }
1390 if (ret < 0) { 1446 goto err;
1391 int j; 1447 }
1392 1448 new_fm->e[i] = old_fm->e[i];
1393 for (j = 1; j < i; j++) 1449 old_fm->e[i] = NULL;
1394 ubi_wl_put_fm_peb(ubi, new_fm->e[j], 1450 } else {
1395 j, 0); 1451 ubi_err(ubi, "could not get any free erase block");
1452
1453 for (j = 1; j < i; j++) {
1454 ubi_wl_put_fm_peb(ubi, new_fm->e[j], j, 0);
1455 new_fm->e[j] = NULL;
1456 }
1396 1457
1397 ubi_err(ubi, "could not erase old fastmap PEB"); 1458 ret = -ENOSPC;
1398 goto err; 1459 goto err;
1399 } 1460 }
1400 new_fm->e[i] = old_fm->e[i];
1401 } else { 1461 } else {
1402 new_fm->e[i] = tmp_e; 1462 new_fm->e[i] = tmp_e;
1403 1463
1404 if (old_fm && old_fm->e[i]) 1464 if (old_fm && old_fm->e[i]) {
1405 ubi_wl_put_fm_peb(ubi, old_fm->e[i], i, 1465 ubi_wl_put_fm_peb(ubi, old_fm->e[i], i,
1406 old_fm->to_be_tortured[i]); 1466 old_fm->to_be_tortured[i]);
1467 old_fm->e[i] = NULL;
1468 }
1407 } 1469 }
1408 } 1470 }
1409 1471
@@ -1412,6 +1474,7 @@ int ubi_update_fastmap(struct ubi_device *ubi)
1412 for (i = new_fm->used_blocks; i < old_fm->used_blocks; i++) { 1474 for (i = new_fm->used_blocks; i < old_fm->used_blocks; i++) {
1413 ubi_wl_put_fm_peb(ubi, old_fm->e[i], i, 1475 ubi_wl_put_fm_peb(ubi, old_fm->e[i], i,
1414 old_fm->to_be_tortured[i]); 1476 old_fm->to_be_tortured[i]);
1477 old_fm->e[i] = NULL;
1415 } 1478 }
1416 } 1479 }
1417 1480
@@ -1424,29 +1487,33 @@ int ubi_update_fastmap(struct ubi_device *ubi)
1424 if (!tmp_e) { 1487 if (!tmp_e) {
1425 ret = erase_block(ubi, old_fm->e[0]->pnum); 1488 ret = erase_block(ubi, old_fm->e[0]->pnum);
1426 if (ret < 0) { 1489 if (ret < 0) {
1427 int i;
1428 ubi_err(ubi, "could not erase old anchor PEB"); 1490 ubi_err(ubi, "could not erase old anchor PEB");
1429 1491
1430 for (i = 1; i < new_fm->used_blocks; i++) 1492 for (i = 1; i < new_fm->used_blocks; i++) {
1431 ubi_wl_put_fm_peb(ubi, new_fm->e[i], 1493 ubi_wl_put_fm_peb(ubi, new_fm->e[i],
1432 i, 0); 1494 i, 0);
1495 new_fm->e[i] = NULL;
1496 }
1433 goto err; 1497 goto err;
1434 } 1498 }
1435 new_fm->e[0] = old_fm->e[0]; 1499 new_fm->e[0] = old_fm->e[0];
1436 new_fm->e[0]->ec = ret; 1500 new_fm->e[0]->ec = ret;
1501 old_fm->e[0] = NULL;
1437 } else { 1502 } else {
1438 /* we've got a new anchor PEB, return the old one */ 1503 /* we've got a new anchor PEB, return the old one */
1439 ubi_wl_put_fm_peb(ubi, old_fm->e[0], 0, 1504 ubi_wl_put_fm_peb(ubi, old_fm->e[0], 0,
1440 old_fm->to_be_tortured[0]); 1505 old_fm->to_be_tortured[0]);
1441 new_fm->e[0] = tmp_e; 1506 new_fm->e[0] = tmp_e;
1507 old_fm->e[0] = NULL;
1442 } 1508 }
1443 } else { 1509 } else {
1444 if (!tmp_e) { 1510 if (!tmp_e) {
1445 int i;
1446 ubi_err(ubi, "could not find any anchor PEB"); 1511 ubi_err(ubi, "could not find any anchor PEB");
1447 1512
1448 for (i = 1; i < new_fm->used_blocks; i++) 1513 for (i = 1; i < new_fm->used_blocks; i++) {
1449 ubi_wl_put_fm_peb(ubi, new_fm->e[i], i, 0); 1514 ubi_wl_put_fm_peb(ubi, new_fm->e[i], i, 0);
1515 new_fm->e[i] = NULL;
1516 }
1450 1517
1451 ret = -ENOSPC; 1518 ret = -ENOSPC;
1452 goto err; 1519 goto err;
@@ -1469,19 +1536,18 @@ out_unlock:
1469 return ret; 1536 return ret;
1470 1537
1471err: 1538err:
1472 kfree(new_fm);
1473
1474 ubi_warn(ubi, "Unable to write new fastmap, err=%i", ret); 1539 ubi_warn(ubi, "Unable to write new fastmap, err=%i", ret);
1475 1540
1476 ret = 0; 1541 ret = invalidate_fastmap(ubi);
1477 if (old_fm) { 1542 if (ret < 0) {
1478 ret = invalidate_fastmap(ubi, old_fm); 1543 ubi_err(ubi, "Unable to invalidiate current fastmap!");
1479 if (ret < 0) { 1544 ubi_ro_mode(ubi);
1480 ubi_err(ubi, "Unable to invalidiate current fastmap!"); 1545 } else {
1481 ubi_ro_mode(ubi); 1546 return_fm_pebs(ubi, old_fm);
1482 } 1547 return_fm_pebs(ubi, new_fm);
1483 else if (ret) 1548 ret = 0;
1484 ret = 0;
1485 } 1549 }
1550
1551 kfree(new_fm);
1486 goto out_unlock; 1552 goto out_unlock;
1487} 1553}