aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2018-09-07 08:36:44 -0400
committerRichard Weinberger <richard@nod.at>2018-10-23 07:48:57 -0400
commit1e76592f2c3208ac635c2758aa8326d82fa64a72 (patch)
tree7f9deb06a69fc5878c1d352473842c0f4d513915
parent104115a3eb54e7e804cd4ef1d6426c0b8aaaeb60 (diff)
ubifs: Do not update inode size in-place in authenticated mode
In authenticated mode we cannot fixup the inode sizes in-place during recovery as this would invalidate the hashes and HMACs we stored for this inode. Instead, we just write the updated inodes to the journal. We can only do this after ubifs_rcvry_gc_commit() is done though, so for authenticated mode call ubifs_recover_size() after ubifs_rcvry_gc_commit() and not vice versa as normally done. Calling ubifs_recover_size() after ubifs_rcvry_gc_commit() has the drawback that after a commit the size fixup information is gone, so when a powercut happens while recovering from another powercut we may lose some data written right before the first powercut. This is why we only do this in authenticated mode and leave the behaviour for unauthenticated mode untouched. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Richard Weinberger <richard@nod.at>
-rw-r--r--fs/ubifs/recovery.c111
-rw-r--r--fs/ubifs/super.c38
-rw-r--r--fs/ubifs/ubifs.h2
3 files changed, 113 insertions, 38 deletions
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 5c1334e6bc81..8526b7ec4707 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -1463,15 +1463,81 @@ out:
1463} 1463}
1464 1464
1465/** 1465/**
1466 * inode_fix_size - fix inode size
1467 * @c: UBIFS file-system description object
1468 * @e: inode size information for recovery
1469 */
1470static int inode_fix_size(struct ubifs_info *c, struct size_entry *e)
1471{
1472 struct inode *inode;
1473 struct ubifs_inode *ui;
1474 int err;
1475
1476 if (c->ro_mount)
1477 ubifs_assert(c, !e->inode);
1478
1479 if (e->inode) {
1480 /* Remounting rw, pick up inode we stored earlier */
1481 inode = e->inode;
1482 } else {
1483 inode = ubifs_iget(c->vfs_sb, e->inum);
1484 if (IS_ERR(inode))
1485 return PTR_ERR(inode);
1486
1487 if (inode->i_size >= e->d_size) {
1488 /*
1489 * The original inode in the index already has a size
1490 * big enough, nothing to do
1491 */
1492 iput(inode);
1493 return 0;
1494 }
1495
1496 dbg_rcvry("ino %lu size %lld -> %lld",
1497 (unsigned long)e->inum,
1498 inode->i_size, e->d_size);
1499
1500 ui = ubifs_inode(inode);
1501
1502 inode->i_size = e->d_size;
1503 ui->ui_size = e->d_size;
1504 ui->synced_i_size = e->d_size;
1505
1506 e->inode = inode;
1507 }
1508
1509 /*
1510 * In readonly mode just keep the inode pinned in memory until we go
1511 * readwrite. In readwrite mode write the inode to the journal with the
1512 * fixed size.
1513 */
1514 if (c->ro_mount)
1515 return 0;
1516
1517 err = ubifs_jnl_write_inode(c, inode);
1518
1519 iput(inode);
1520
1521 if (err)
1522 return err;
1523
1524 rb_erase(&e->rb, &c->size_tree);
1525 kfree(e);
1526
1527 return 0;
1528}
1529
1530/**
1466 * ubifs_recover_size - recover inode size. 1531 * ubifs_recover_size - recover inode size.
1467 * @c: UBIFS file-system description object 1532 * @c: UBIFS file-system description object
1533 * @in_place: If true, do a in-place size fixup
1468 * 1534 *
1469 * This function attempts to fix inode size discrepancies identified by the 1535 * This function attempts to fix inode size discrepancies identified by the
1470 * 'ubifs_recover_size_accum()' function. 1536 * 'ubifs_recover_size_accum()' function.
1471 * 1537 *
1472 * This functions returns %0 on success and a negative error code on failure. 1538 * This functions returns %0 on success and a negative error code on failure.
1473 */ 1539 */
1474int ubifs_recover_size(struct ubifs_info *c) 1540int ubifs_recover_size(struct ubifs_info *c, bool in_place)
1475{ 1541{
1476 struct rb_node *this = rb_first(&c->size_tree); 1542 struct rb_node *this = rb_first(&c->size_tree);
1477 1543
@@ -1480,6 +1546,9 @@ int ubifs_recover_size(struct ubifs_info *c)
1480 int err; 1546 int err;
1481 1547
1482 e = rb_entry(this, struct size_entry, rb); 1548 e = rb_entry(this, struct size_entry, rb);
1549
1550 this = rb_next(this);
1551
1483 if (!e->exists) { 1552 if (!e->exists) {
1484 union ubifs_key key; 1553 union ubifs_key key;
1485 1554
@@ -1503,40 +1572,26 @@ int ubifs_recover_size(struct ubifs_info *c)
1503 } 1572 }
1504 1573
1505 if (e->exists && e->i_size < e->d_size) { 1574 if (e->exists && e->i_size < e->d_size) {
1506 if (c->ro_mount) { 1575 ubifs_assert(c, !(c->ro_mount && in_place));
1507 /* Fix the inode size and pin it in memory */ 1576
1508 struct inode *inode; 1577 /*
1509 struct ubifs_inode *ui; 1578 * We found data that is outside the found inode size,
1510 1579 * fixup the inode size
1511 ubifs_assert(c, !e->inode); 1580 */
1512 1581
1513 inode = ubifs_iget(c->vfs_sb, e->inum); 1582 if (in_place) {
1514 if (IS_ERR(inode))
1515 return PTR_ERR(inode);
1516
1517 ui = ubifs_inode(inode);
1518 if (inode->i_size < e->d_size) {
1519 dbg_rcvry("ino %lu size %lld -> %lld",
1520 (unsigned long)e->inum,
1521 inode->i_size, e->d_size);
1522 inode->i_size = e->d_size;
1523 ui->ui_size = e->d_size;
1524 ui->synced_i_size = e->d_size;
1525 e->inode = inode;
1526 this = rb_next(this);
1527 continue;
1528 }
1529 iput(inode);
1530 } else {
1531 /* Fix the size in place */
1532 err = fix_size_in_place(c, e); 1583 err = fix_size_in_place(c, e);
1533 if (err) 1584 if (err)
1534 return err; 1585 return err;
1535 iput(e->inode); 1586 iput(e->inode);
1587 } else {
1588 err = inode_fix_size(c, e);
1589 if (err)
1590 return err;
1591 continue;
1536 } 1592 }
1537 } 1593 }
1538 1594
1539 this = rb_next(this);
1540 rb_erase(&e->rb, &c->size_tree); 1595 rb_erase(&e->rb, &c->size_tree);
1541 kfree(e); 1596 kfree(e);
1542 } 1597 }
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 2722ca077d23..e2964ce81dee 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1378,12 +1378,21 @@ static int mount_ubifs(struct ubifs_info *c)
1378 } 1378 }
1379 1379
1380 if (c->need_recovery) { 1380 if (c->need_recovery) {
1381 err = ubifs_recover_size(c); 1381 if (!ubifs_authenticated(c)) {
1382 if (err) 1382 err = ubifs_recover_size(c, true);
1383 goto out_orphans; 1383 if (err)
1384 goto out_orphans;
1385 }
1386
1384 err = ubifs_rcvry_gc_commit(c); 1387 err = ubifs_rcvry_gc_commit(c);
1385 if (err) 1388 if (err)
1386 goto out_orphans; 1389 goto out_orphans;
1390
1391 if (ubifs_authenticated(c)) {
1392 err = ubifs_recover_size(c, false);
1393 if (err)
1394 goto out_orphans;
1395 }
1387 } else { 1396 } else {
1388 err = take_gc_lnum(c); 1397 err = take_gc_lnum(c);
1389 if (err) 1398 if (err)
@@ -1402,7 +1411,7 @@ static int mount_ubifs(struct ubifs_info *c)
1402 if (err) 1411 if (err)
1403 goto out_orphans; 1412 goto out_orphans;
1404 } else if (c->need_recovery) { 1413 } else if (c->need_recovery) {
1405 err = ubifs_recover_size(c); 1414 err = ubifs_recover_size(c, false);
1406 if (err) 1415 if (err)
1407 goto out_orphans; 1416 goto out_orphans;
1408 } else { 1417 } else {
@@ -1629,9 +1638,11 @@ static int ubifs_remount_rw(struct ubifs_info *c)
1629 err = ubifs_write_rcvrd_mst_node(c); 1638 err = ubifs_write_rcvrd_mst_node(c);
1630 if (err) 1639 if (err)
1631 goto out; 1640 goto out;
1632 err = ubifs_recover_size(c); 1641 if (!ubifs_authenticated(c)) {
1633 if (err) 1642 err = ubifs_recover_size(c, true);
1634 goto out; 1643 if (err)
1644 goto out;
1645 }
1635 err = ubifs_clean_lebs(c, c->sbuf); 1646 err = ubifs_clean_lebs(c, c->sbuf);
1636 if (err) 1647 if (err)
1637 goto out; 1648 goto out;
@@ -1697,10 +1708,19 @@ static int ubifs_remount_rw(struct ubifs_info *c)
1697 goto out; 1708 goto out;
1698 } 1709 }
1699 1710
1700 if (c->need_recovery) 1711 if (c->need_recovery) {
1701 err = ubifs_rcvry_gc_commit(c); 1712 err = ubifs_rcvry_gc_commit(c);
1702 else 1713 if (err)
1714 goto out;
1715
1716 if (ubifs_authenticated(c)) {
1717 err = ubifs_recover_size(c, false);
1718 if (err)
1719 goto out;
1720 }
1721 } else {
1703 err = ubifs_leb_unmap(c, c->gc_lnum); 1722 err = ubifs_leb_unmap(c, c->gc_lnum);
1723 }
1704 if (err) 1724 if (err)
1705 goto out; 1725 goto out;
1706 1726
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 504b651b78f1..38401adaa00d 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -2050,7 +2050,7 @@ int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf);
2050int ubifs_rcvry_gc_commit(struct ubifs_info *c); 2050int ubifs_rcvry_gc_commit(struct ubifs_info *c);
2051int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key, 2051int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
2052 int deletion, loff_t new_size); 2052 int deletion, loff_t new_size);
2053int ubifs_recover_size(struct ubifs_info *c); 2053int ubifs_recover_size(struct ubifs_info *c, bool in_place);
2054void ubifs_destroy_size_tree(struct ubifs_info *c); 2054void ubifs_destroy_size_tree(struct ubifs_info *c);
2055 2055
2056/* ioctl.c */ 2056/* ioctl.c */