| .. | .. | 
|---|
 | 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 |  	} | 
|---|