summaryrefslogtreecommitdiffstats
path: root/fs/ubifs/recovery.c
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 /fs/ubifs/recovery.c
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>
Diffstat (limited to 'fs/ubifs/recovery.c')
-rw-r--r--fs/ubifs/recovery.c111
1 files changed, 83 insertions, 28 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 }