diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 71 |
1 files changed, 61 insertions, 10 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index ff60d8978ae2..79f057c0619a 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -93,7 +93,8 @@ | |||
93 | */ | 93 | */ |
94 | #define LOG_WALK_PIN_ONLY 0 | 94 | #define LOG_WALK_PIN_ONLY 0 |
95 | #define LOG_WALK_REPLAY_INODES 1 | 95 | #define LOG_WALK_REPLAY_INODES 1 |
96 | #define LOG_WALK_REPLAY_ALL 2 | 96 | #define LOG_WALK_REPLAY_DIR_INDEX 2 |
97 | #define LOG_WALK_REPLAY_ALL 3 | ||
97 | 98 | ||
98 | static int btrfs_log_inode(struct btrfs_trans_handle *trans, | 99 | static int btrfs_log_inode(struct btrfs_trans_handle *trans, |
99 | struct btrfs_root *root, struct inode *inode, | 100 | struct btrfs_root *root, struct inode *inode, |
@@ -393,6 +394,7 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, | |||
393 | if (inode_item) { | 394 | if (inode_item) { |
394 | struct btrfs_inode_item *item; | 395 | struct btrfs_inode_item *item; |
395 | u64 nbytes; | 396 | u64 nbytes; |
397 | u32 mode; | ||
396 | 398 | ||
397 | item = btrfs_item_ptr(path->nodes[0], path->slots[0], | 399 | item = btrfs_item_ptr(path->nodes[0], path->slots[0], |
398 | struct btrfs_inode_item); | 400 | struct btrfs_inode_item); |
@@ -400,9 +402,19 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, | |||
400 | item = btrfs_item_ptr(eb, slot, | 402 | item = btrfs_item_ptr(eb, slot, |
401 | struct btrfs_inode_item); | 403 | struct btrfs_inode_item); |
402 | btrfs_set_inode_nbytes(eb, item, nbytes); | 404 | btrfs_set_inode_nbytes(eb, item, nbytes); |
405 | |||
406 | /* | ||
407 | * If this is a directory we need to reset the i_size to | ||
408 | * 0 so that we can set it up properly when replaying | ||
409 | * the rest of the items in this log. | ||
410 | */ | ||
411 | mode = btrfs_inode_mode(eb, item); | ||
412 | if (S_ISDIR(mode)) | ||
413 | btrfs_set_inode_size(eb, item, 0); | ||
403 | } | 414 | } |
404 | } else if (inode_item) { | 415 | } else if (inode_item) { |
405 | struct btrfs_inode_item *item; | 416 | struct btrfs_inode_item *item; |
417 | u32 mode; | ||
406 | 418 | ||
407 | /* | 419 | /* |
408 | * New inode, set nbytes to 0 so that the nbytes comes out | 420 | * New inode, set nbytes to 0 so that the nbytes comes out |
@@ -410,6 +422,15 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, | |||
410 | */ | 422 | */ |
411 | item = btrfs_item_ptr(eb, slot, struct btrfs_inode_item); | 423 | item = btrfs_item_ptr(eb, slot, struct btrfs_inode_item); |
412 | btrfs_set_inode_nbytes(eb, item, 0); | 424 | btrfs_set_inode_nbytes(eb, item, 0); |
425 | |||
426 | /* | ||
427 | * If this is a directory we need to reset the i_size to 0 so | ||
428 | * that we can set it up properly when replaying the rest of | ||
429 | * the items in this log. | ||
430 | */ | ||
431 | mode = btrfs_inode_mode(eb, item); | ||
432 | if (S_ISDIR(mode)) | ||
433 | btrfs_set_inode_size(eb, item, 0); | ||
413 | } | 434 | } |
414 | insert: | 435 | insert: |
415 | btrfs_release_path(path); | 436 | btrfs_release_path(path); |
@@ -747,7 +768,8 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans, | |||
747 | ret = btrfs_unlink_inode(trans, root, dir, inode, name, name_len); | 768 | ret = btrfs_unlink_inode(trans, root, dir, inode, name, name_len); |
748 | if (ret) | 769 | if (ret) |
749 | goto out; | 770 | goto out; |
750 | btrfs_run_delayed_items(trans, root); | 771 | else |
772 | ret = btrfs_run_delayed_items(trans, root); | ||
751 | out: | 773 | out: |
752 | kfree(name); | 774 | kfree(name); |
753 | iput(inode); | 775 | iput(inode); |
@@ -923,7 +945,9 @@ again: | |||
923 | kfree(victim_name); | 945 | kfree(victim_name); |
924 | if (ret) | 946 | if (ret) |
925 | return ret; | 947 | return ret; |
926 | btrfs_run_delayed_items(trans, root); | 948 | ret = btrfs_run_delayed_items(trans, root); |
949 | if (ret) | ||
950 | return ret; | ||
927 | *search_done = 1; | 951 | *search_done = 1; |
928 | goto again; | 952 | goto again; |
929 | } | 953 | } |
@@ -990,7 +1014,9 @@ again: | |||
990 | inode, | 1014 | inode, |
991 | victim_name, | 1015 | victim_name, |
992 | victim_name_len); | 1016 | victim_name_len); |
993 | btrfs_run_delayed_items(trans, root); | 1017 | if (!ret) |
1018 | ret = btrfs_run_delayed_items( | ||
1019 | trans, root); | ||
994 | } | 1020 | } |
995 | iput(victim_parent); | 1021 | iput(victim_parent); |
996 | kfree(victim_name); | 1022 | kfree(victim_name); |
@@ -1491,6 +1517,7 @@ static noinline int insert_one_name(struct btrfs_trans_handle *trans, | |||
1491 | iput(inode); | 1517 | iput(inode); |
1492 | return -EIO; | 1518 | return -EIO; |
1493 | } | 1519 | } |
1520 | |||
1494 | ret = btrfs_add_link(trans, dir, inode, name, name_len, 1, index); | 1521 | ret = btrfs_add_link(trans, dir, inode, name, name_len, 1, index); |
1495 | 1522 | ||
1496 | /* FIXME, put inode into FIXUP list */ | 1523 | /* FIXME, put inode into FIXUP list */ |
@@ -1529,6 +1556,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, | |||
1529 | u8 log_type; | 1556 | u8 log_type; |
1530 | int exists; | 1557 | int exists; |
1531 | int ret = 0; | 1558 | int ret = 0; |
1559 | bool update_size = (key->type == BTRFS_DIR_INDEX_KEY); | ||
1532 | 1560 | ||
1533 | dir = read_one_inode(root, key->objectid); | 1561 | dir = read_one_inode(root, key->objectid); |
1534 | if (!dir) | 1562 | if (!dir) |
@@ -1536,8 +1564,10 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, | |||
1536 | 1564 | ||
1537 | name_len = btrfs_dir_name_len(eb, di); | 1565 | name_len = btrfs_dir_name_len(eb, di); |
1538 | name = kmalloc(name_len, GFP_NOFS); | 1566 | name = kmalloc(name_len, GFP_NOFS); |
1539 | if (!name) | 1567 | if (!name) { |
1540 | return -ENOMEM; | 1568 | ret = -ENOMEM; |
1569 | goto out; | ||
1570 | } | ||
1541 | 1571 | ||
1542 | log_type = btrfs_dir_type(eb, di); | 1572 | log_type = btrfs_dir_type(eb, di); |
1543 | read_extent_buffer(eb, name, (unsigned long)(di + 1), | 1573 | read_extent_buffer(eb, name, (unsigned long)(di + 1), |
@@ -1597,6 +1627,10 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, | |||
1597 | goto insert; | 1627 | goto insert; |
1598 | out: | 1628 | out: |
1599 | btrfs_release_path(path); | 1629 | btrfs_release_path(path); |
1630 | if (!ret && update_size) { | ||
1631 | btrfs_i_size_write(dir, dir->i_size + name_len * 2); | ||
1632 | ret = btrfs_update_inode(trans, root, dir); | ||
1633 | } | ||
1600 | kfree(name); | 1634 | kfree(name); |
1601 | iput(dir); | 1635 | iput(dir); |
1602 | return ret; | 1636 | return ret; |
@@ -1607,6 +1641,7 @@ insert: | |||
1607 | name, name_len, log_type, &log_key); | 1641 | name, name_len, log_type, &log_key); |
1608 | if (ret && ret != -ENOENT) | 1642 | if (ret && ret != -ENOENT) |
1609 | goto out; | 1643 | goto out; |
1644 | update_size = false; | ||
1610 | ret = 0; | 1645 | ret = 0; |
1611 | goto out; | 1646 | goto out; |
1612 | } | 1647 | } |
@@ -1810,7 +1845,7 @@ again: | |||
1810 | ret = btrfs_unlink_inode(trans, root, dir, inode, | 1845 | ret = btrfs_unlink_inode(trans, root, dir, inode, |
1811 | name, name_len); | 1846 | name, name_len); |
1812 | if (!ret) | 1847 | if (!ret) |
1813 | btrfs_run_delayed_items(trans, root); | 1848 | ret = btrfs_run_delayed_items(trans, root); |
1814 | kfree(name); | 1849 | kfree(name); |
1815 | iput(inode); | 1850 | iput(inode); |
1816 | if (ret) | 1851 | if (ret) |
@@ -2020,6 +2055,15 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, | |||
2020 | if (ret) | 2055 | if (ret) |
2021 | break; | 2056 | break; |
2022 | } | 2057 | } |
2058 | |||
2059 | if (key.type == BTRFS_DIR_INDEX_KEY && | ||
2060 | wc->stage == LOG_WALK_REPLAY_DIR_INDEX) { | ||
2061 | ret = replay_one_dir_item(wc->trans, root, path, | ||
2062 | eb, i, &key); | ||
2063 | if (ret) | ||
2064 | break; | ||
2065 | } | ||
2066 | |||
2023 | if (wc->stage < LOG_WALK_REPLAY_ALL) | 2067 | if (wc->stage < LOG_WALK_REPLAY_ALL) |
2024 | continue; | 2068 | continue; |
2025 | 2069 | ||
@@ -2041,8 +2085,7 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, | |||
2041 | eb, i, &key); | 2085 | eb, i, &key); |
2042 | if (ret) | 2086 | if (ret) |
2043 | break; | 2087 | break; |
2044 | } else if (key.type == BTRFS_DIR_ITEM_KEY || | 2088 | } else if (key.type == BTRFS_DIR_ITEM_KEY) { |
2045 | key.type == BTRFS_DIR_INDEX_KEY) { | ||
2046 | ret = replay_one_dir_item(wc->trans, root, path, | 2089 | ret = replay_one_dir_item(wc->trans, root, path, |
2047 | eb, i, &key); | 2090 | eb, i, &key); |
2048 | if (ret) | 2091 | if (ret) |
@@ -3798,6 +3841,7 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans, | |||
3798 | int ret = 0; | 3841 | int ret = 0; |
3799 | struct btrfs_root *root; | 3842 | struct btrfs_root *root; |
3800 | struct dentry *old_parent = NULL; | 3843 | struct dentry *old_parent = NULL; |
3844 | struct inode *orig_inode = inode; | ||
3801 | 3845 | ||
3802 | /* | 3846 | /* |
3803 | * for regular files, if its inode is already on disk, we don't | 3847 | * for regular files, if its inode is already on disk, we don't |
@@ -3817,7 +3861,14 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans, | |||
3817 | } | 3861 | } |
3818 | 3862 | ||
3819 | while (1) { | 3863 | while (1) { |
3820 | BTRFS_I(inode)->logged_trans = trans->transid; | 3864 | /* |
3865 | * If we are logging a directory then we start with our inode, | ||
3866 | * not our parents inode, so we need to skipp setting the | ||
3867 | * logged_trans so that further down in the log code we don't | ||
3868 | * think this inode has already been logged. | ||
3869 | */ | ||
3870 | if (inode != orig_inode) | ||
3871 | BTRFS_I(inode)->logged_trans = trans->transid; | ||
3821 | smp_mb(); | 3872 | smp_mb(); |
3822 | 3873 | ||
3823 | if (BTRFS_I(inode)->last_unlink_trans > last_committed) { | 3874 | if (BTRFS_I(inode)->last_unlink_trans > last_committed) { |