.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * This file is part of UBIFS. |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2006-2008 Nokia Corporation |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify it |
---|
7 | | - * under the terms of the GNU General Public License version 2 as published by |
---|
8 | | - * the Free Software Foundation. |
---|
9 | | - * |
---|
10 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
---|
11 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
12 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
13 | | - * more details. |
---|
14 | | - * |
---|
15 | | - * You should have received a copy of the GNU General Public License along with |
---|
16 | | - * this program; if not, write to the Free Software Foundation, Inc., 51 |
---|
17 | | - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
---|
18 | 6 | * |
---|
19 | 7 | * Authors: Adrian Hunter |
---|
20 | 8 | * Artem Bityutskiy (Битюцкий Артём) |
---|
.. | .. |
---|
212 | 200 | save_flags = mst->flags; |
---|
213 | 201 | mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY); |
---|
214 | 202 | |
---|
215 | | - ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1); |
---|
| 203 | + err = ubifs_prepare_node_hmac(c, mst, UBIFS_MST_NODE_SZ, |
---|
| 204 | + offsetof(struct ubifs_mst_node, hmac), 1); |
---|
| 205 | + if (err) |
---|
| 206 | + goto out; |
---|
216 | 207 | err = ubifs_leb_change(c, lnum, mst, sz); |
---|
217 | 208 | if (err) |
---|
218 | 209 | goto out; |
---|
.. | .. |
---|
264 | 255 | offs2 = (void *)mst2 - buf2; |
---|
265 | 256 | if (offs1 == offs2) { |
---|
266 | 257 | /* Same offset, so must be the same */ |
---|
267 | | - if (memcmp((void *)mst1 + UBIFS_CH_SZ, |
---|
268 | | - (void *)mst2 + UBIFS_CH_SZ, |
---|
269 | | - UBIFS_MST_NODE_SZ - UBIFS_CH_SZ)) |
---|
| 258 | + if (ubifs_compare_master_node(c, mst1, mst2)) |
---|
270 | 259 | goto out_err; |
---|
271 | 260 | mst = mst1; |
---|
272 | 261 | } else if (offs2 + sz == offs1) { |
---|
.. | .. |
---|
862 | 851 | goto out_err; |
---|
863 | 852 | } |
---|
864 | 853 | if (cs_node->ch.node_type != UBIFS_CS_NODE) { |
---|
865 | | - ubifs_err(c, "Node a CS node, type is %d", cs_node->ch.node_type); |
---|
| 854 | + ubifs_err(c, "Not a CS node, type is %d", cs_node->ch.node_type); |
---|
866 | 855 | goto out_err; |
---|
867 | 856 | } |
---|
868 | 857 | if (le64_to_cpu(cs_node->cmt_no) != c->cmt_no) { |
---|
.. | .. |
---|
1495 | 1484 | } |
---|
1496 | 1485 | |
---|
1497 | 1486 | /** |
---|
| 1487 | + * inode_fix_size - fix inode size |
---|
| 1488 | + * @c: UBIFS file-system description object |
---|
| 1489 | + * @e: inode size information for recovery |
---|
| 1490 | + */ |
---|
| 1491 | +static int inode_fix_size(struct ubifs_info *c, struct size_entry *e) |
---|
| 1492 | +{ |
---|
| 1493 | + struct inode *inode; |
---|
| 1494 | + struct ubifs_inode *ui; |
---|
| 1495 | + int err; |
---|
| 1496 | + |
---|
| 1497 | + if (c->ro_mount) |
---|
| 1498 | + ubifs_assert(c, !e->inode); |
---|
| 1499 | + |
---|
| 1500 | + if (e->inode) { |
---|
| 1501 | + /* Remounting rw, pick up inode we stored earlier */ |
---|
| 1502 | + inode = e->inode; |
---|
| 1503 | + } else { |
---|
| 1504 | + inode = ubifs_iget(c->vfs_sb, e->inum); |
---|
| 1505 | + if (IS_ERR(inode)) |
---|
| 1506 | + return PTR_ERR(inode); |
---|
| 1507 | + |
---|
| 1508 | + if (inode->i_size >= e->d_size) { |
---|
| 1509 | + /* |
---|
| 1510 | + * The original inode in the index already has a size |
---|
| 1511 | + * big enough, nothing to do |
---|
| 1512 | + */ |
---|
| 1513 | + iput(inode); |
---|
| 1514 | + return 0; |
---|
| 1515 | + } |
---|
| 1516 | + |
---|
| 1517 | + dbg_rcvry("ino %lu size %lld -> %lld", |
---|
| 1518 | + (unsigned long)e->inum, |
---|
| 1519 | + inode->i_size, e->d_size); |
---|
| 1520 | + |
---|
| 1521 | + ui = ubifs_inode(inode); |
---|
| 1522 | + |
---|
| 1523 | + inode->i_size = e->d_size; |
---|
| 1524 | + ui->ui_size = e->d_size; |
---|
| 1525 | + ui->synced_i_size = e->d_size; |
---|
| 1526 | + |
---|
| 1527 | + e->inode = inode; |
---|
| 1528 | + } |
---|
| 1529 | + |
---|
| 1530 | + /* |
---|
| 1531 | + * In readonly mode just keep the inode pinned in memory until we go |
---|
| 1532 | + * readwrite. In readwrite mode write the inode to the journal with the |
---|
| 1533 | + * fixed size. |
---|
| 1534 | + */ |
---|
| 1535 | + if (c->ro_mount) |
---|
| 1536 | + return 0; |
---|
| 1537 | + |
---|
| 1538 | + err = ubifs_jnl_write_inode(c, inode); |
---|
| 1539 | + |
---|
| 1540 | + iput(inode); |
---|
| 1541 | + |
---|
| 1542 | + if (err) |
---|
| 1543 | + return err; |
---|
| 1544 | + |
---|
| 1545 | + rb_erase(&e->rb, &c->size_tree); |
---|
| 1546 | + kfree(e); |
---|
| 1547 | + |
---|
| 1548 | + return 0; |
---|
| 1549 | +} |
---|
| 1550 | + |
---|
| 1551 | +/** |
---|
1498 | 1552 | * ubifs_recover_size - recover inode size. |
---|
1499 | 1553 | * @c: UBIFS file-system description object |
---|
| 1554 | + * @in_place: If true, do a in-place size fixup |
---|
1500 | 1555 | * |
---|
1501 | 1556 | * This function attempts to fix inode size discrepancies identified by the |
---|
1502 | 1557 | * 'ubifs_recover_size_accum()' function. |
---|
1503 | 1558 | * |
---|
1504 | 1559 | * This functions returns %0 on success and a negative error code on failure. |
---|
1505 | 1560 | */ |
---|
1506 | | -int ubifs_recover_size(struct ubifs_info *c) |
---|
| 1561 | +int ubifs_recover_size(struct ubifs_info *c, bool in_place) |
---|
1507 | 1562 | { |
---|
1508 | 1563 | struct rb_node *this = rb_first(&c->size_tree); |
---|
1509 | 1564 | |
---|
.. | .. |
---|
1512 | 1567 | int err; |
---|
1513 | 1568 | |
---|
1514 | 1569 | e = rb_entry(this, struct size_entry, rb); |
---|
| 1570 | + |
---|
| 1571 | + this = rb_next(this); |
---|
| 1572 | + |
---|
1515 | 1573 | if (!e->exists) { |
---|
1516 | 1574 | union ubifs_key key; |
---|
1517 | 1575 | |
---|
.. | .. |
---|
1535 | 1593 | } |
---|
1536 | 1594 | |
---|
1537 | 1595 | if (e->exists && e->i_size < e->d_size) { |
---|
1538 | | - if (c->ro_mount) { |
---|
1539 | | - /* Fix the inode size and pin it in memory */ |
---|
1540 | | - struct inode *inode; |
---|
1541 | | - struct ubifs_inode *ui; |
---|
| 1596 | + ubifs_assert(c, !(c->ro_mount && in_place)); |
---|
1542 | 1597 | |
---|
1543 | | - ubifs_assert(c, !e->inode); |
---|
| 1598 | + /* |
---|
| 1599 | + * We found data that is outside the found inode size, |
---|
| 1600 | + * fixup the inode size |
---|
| 1601 | + */ |
---|
1544 | 1602 | |
---|
1545 | | - inode = ubifs_iget(c->vfs_sb, e->inum); |
---|
1546 | | - if (IS_ERR(inode)) |
---|
1547 | | - return PTR_ERR(inode); |
---|
1548 | | - |
---|
1549 | | - ui = ubifs_inode(inode); |
---|
1550 | | - if (inode->i_size < e->d_size) { |
---|
1551 | | - dbg_rcvry("ino %lu size %lld -> %lld", |
---|
1552 | | - (unsigned long)e->inum, |
---|
1553 | | - inode->i_size, e->d_size); |
---|
1554 | | - inode->i_size = e->d_size; |
---|
1555 | | - ui->ui_size = e->d_size; |
---|
1556 | | - ui->synced_i_size = e->d_size; |
---|
1557 | | - e->inode = inode; |
---|
1558 | | - this = rb_next(this); |
---|
1559 | | - continue; |
---|
1560 | | - } |
---|
1561 | | - iput(inode); |
---|
1562 | | - } else { |
---|
1563 | | - /* Fix the size in place */ |
---|
| 1603 | + if (in_place) { |
---|
1564 | 1604 | err = fix_size_in_place(c, e); |
---|
1565 | 1605 | if (err) |
---|
1566 | 1606 | return err; |
---|
1567 | 1607 | iput(e->inode); |
---|
| 1608 | + } else { |
---|
| 1609 | + err = inode_fix_size(c, e); |
---|
| 1610 | + if (err) |
---|
| 1611 | + return err; |
---|
| 1612 | + continue; |
---|
1568 | 1613 | } |
---|
1569 | 1614 | } |
---|
1570 | 1615 | |
---|
1571 | | - this = rb_next(this); |
---|
1572 | 1616 | rb_erase(&e->rb, &c->size_tree); |
---|
1573 | 1617 | kfree(e); |
---|
1574 | 1618 | } |
---|