aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/tree-log.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r--fs/btrfs/tree-log.c64
1 files changed, 60 insertions, 4 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 9c45431e69ab..cb5666e7c3f9 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -1613,6 +1613,9 @@ static bool name_in_log_ref(struct btrfs_root *log_root,
1613 * not exist in the FS, it is skipped. fsyncs on directories 1613 * not exist in the FS, it is skipped. fsyncs on directories
1614 * do not force down inodes inside that directory, just changes to the 1614 * do not force down inodes inside that directory, just changes to the
1615 * names or unlinks in a directory. 1615 * names or unlinks in a directory.
1616 *
1617 * Returns < 0 on error, 0 if the name wasn't replayed (dentry points to a
1618 * non-existing inode) and 1 if the name was replayed.
1616 */ 1619 */
1617static noinline int replay_one_name(struct btrfs_trans_handle *trans, 1620static noinline int replay_one_name(struct btrfs_trans_handle *trans,
1618 struct btrfs_root *root, 1621 struct btrfs_root *root,
@@ -1631,6 +1634,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
1631 int exists; 1634 int exists;
1632 int ret = 0; 1635 int ret = 0;
1633 bool update_size = (key->type == BTRFS_DIR_INDEX_KEY); 1636 bool update_size = (key->type == BTRFS_DIR_INDEX_KEY);
1637 bool name_added = false;
1634 1638
1635 dir = read_one_inode(root, key->objectid); 1639 dir = read_one_inode(root, key->objectid);
1636 if (!dir) 1640 if (!dir)
@@ -1708,6 +1712,8 @@ out:
1708 } 1712 }
1709 kfree(name); 1713 kfree(name);
1710 iput(dir); 1714 iput(dir);
1715 if (!ret && name_added)
1716 ret = 1;
1711 return ret; 1717 return ret;
1712 1718
1713insert: 1719insert:
@@ -1723,6 +1729,8 @@ insert:
1723 name, name_len, log_type, &log_key); 1729 name, name_len, log_type, &log_key);
1724 if (ret && ret != -ENOENT && ret != -EEXIST) 1730 if (ret && ret != -ENOENT && ret != -EEXIST)
1725 goto out; 1731 goto out;
1732 if (!ret)
1733 name_added = true;
1726 update_size = false; 1734 update_size = false;
1727 ret = 0; 1735 ret = 0;
1728 goto out; 1736 goto out;
@@ -1740,12 +1748,13 @@ static noinline int replay_one_dir_item(struct btrfs_trans_handle *trans,
1740 struct extent_buffer *eb, int slot, 1748 struct extent_buffer *eb, int slot,
1741 struct btrfs_key *key) 1749 struct btrfs_key *key)
1742{ 1750{
1743 int ret; 1751 int ret = 0;
1744 u32 item_size = btrfs_item_size_nr(eb, slot); 1752 u32 item_size = btrfs_item_size_nr(eb, slot);
1745 struct btrfs_dir_item *di; 1753 struct btrfs_dir_item *di;
1746 int name_len; 1754 int name_len;
1747 unsigned long ptr; 1755 unsigned long ptr;
1748 unsigned long ptr_end; 1756 unsigned long ptr_end;
1757 struct btrfs_path *fixup_path = NULL;
1749 1758
1750 ptr = btrfs_item_ptr_offset(eb, slot); 1759 ptr = btrfs_item_ptr_offset(eb, slot);
1751 ptr_end = ptr + item_size; 1760 ptr_end = ptr + item_size;
@@ -1755,12 +1764,59 @@ static noinline int replay_one_dir_item(struct btrfs_trans_handle *trans,
1755 return -EIO; 1764 return -EIO;
1756 name_len = btrfs_dir_name_len(eb, di); 1765 name_len = btrfs_dir_name_len(eb, di);
1757 ret = replay_one_name(trans, root, path, eb, di, key); 1766 ret = replay_one_name(trans, root, path, eb, di, key);
1758 if (ret) 1767 if (ret < 0)
1759 return ret; 1768 break;
1760 ptr = (unsigned long)(di + 1); 1769 ptr = (unsigned long)(di + 1);
1761 ptr += name_len; 1770 ptr += name_len;
1771
1772 /*
1773 * If this entry refers to a non-directory (directories can not
1774 * have a link count > 1) and it was added in the transaction
1775 * that was not committed, make sure we fixup the link count of
1776 * the inode it the entry points to. Otherwise something like
1777 * the following would result in a directory pointing to an
1778 * inode with a wrong link that does not account for this dir
1779 * entry:
1780 *
1781 * mkdir testdir
1782 * touch testdir/foo
1783 * touch testdir/bar
1784 * sync
1785 *
1786 * ln testdir/bar testdir/bar_link
1787 * ln testdir/foo testdir/foo_link
1788 * xfs_io -c "fsync" testdir/bar
1789 *
1790 * <power failure>
1791 *
1792 * mount fs, log replay happens
1793 *
1794 * File foo would remain with a link count of 1 when it has two
1795 * entries pointing to it in the directory testdir. This would
1796 * make it impossible to ever delete the parent directory has
1797 * it would result in stale dentries that can never be deleted.
1798 */
1799 if (ret == 1 && btrfs_dir_type(eb, di) != BTRFS_FT_DIR) {
1800 struct btrfs_key di_key;
1801
1802 if (!fixup_path) {
1803 fixup_path = btrfs_alloc_path();
1804 if (!fixup_path) {
1805 ret = -ENOMEM;
1806 break;
1807 }
1808 }
1809
1810 btrfs_dir_item_key_to_cpu(eb, di, &di_key);
1811 ret = link_to_fixup_dir(trans, root, fixup_path,
1812 di_key.objectid);
1813 if (ret)
1814 break;
1815 }
1816 ret = 0;
1762 } 1817 }
1763 return 0; 1818 btrfs_free_path(fixup_path);
1819 return ret;
1764} 1820}
1765 1821
1766/* 1822/*