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.c52
1 files changed, 48 insertions, 4 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 0d9613c3f5e5..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
98static int btrfs_log_inode(struct btrfs_trans_handle *trans, 99static 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 }
414insert: 435insert:
415 btrfs_release_path(path); 436 btrfs_release_path(path);
@@ -1496,6 +1517,7 @@ static noinline int insert_one_name(struct btrfs_trans_handle *trans,
1496 iput(inode); 1517 iput(inode);
1497 return -EIO; 1518 return -EIO;
1498 } 1519 }
1520
1499 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);
1500 1522
1501 /* FIXME, put inode into FIXUP list */ 1523 /* FIXME, put inode into FIXUP list */
@@ -1534,6 +1556,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
1534 u8 log_type; 1556 u8 log_type;
1535 int exists; 1557 int exists;
1536 int ret = 0; 1558 int ret = 0;
1559 bool update_size = (key->type == BTRFS_DIR_INDEX_KEY);
1537 1560
1538 dir = read_one_inode(root, key->objectid); 1561 dir = read_one_inode(root, key->objectid);
1539 if (!dir) 1562 if (!dir)
@@ -1604,6 +1627,10 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
1604 goto insert; 1627 goto insert;
1605out: 1628out:
1606 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 }
1607 kfree(name); 1634 kfree(name);
1608 iput(dir); 1635 iput(dir);
1609 return ret; 1636 return ret;
@@ -1614,6 +1641,7 @@ insert:
1614 name, name_len, log_type, &log_key); 1641 name, name_len, log_type, &log_key);
1615 if (ret && ret != -ENOENT) 1642 if (ret && ret != -ENOENT)
1616 goto out; 1643 goto out;
1644 update_size = false;
1617 ret = 0; 1645 ret = 0;
1618 goto out; 1646 goto out;
1619} 1647}
@@ -2027,6 +2055,15 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
2027 if (ret) 2055 if (ret)
2028 break; 2056 break;
2029 } 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
2030 if (wc->stage < LOG_WALK_REPLAY_ALL) 2067 if (wc->stage < LOG_WALK_REPLAY_ALL)
2031 continue; 2068 continue;
2032 2069
@@ -2048,8 +2085,7 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
2048 eb, i, &key); 2085 eb, i, &key);
2049 if (ret) 2086 if (ret)
2050 break; 2087 break;
2051 } else if (key.type == BTRFS_DIR_ITEM_KEY || 2088 } else if (key.type == BTRFS_DIR_ITEM_KEY) {
2052 key.type == BTRFS_DIR_INDEX_KEY) {
2053 ret = replay_one_dir_item(wc->trans, root, path, 2089 ret = replay_one_dir_item(wc->trans, root, path,
2054 eb, i, &key); 2090 eb, i, &key);
2055 if (ret) 2091 if (ret)
@@ -3805,6 +3841,7 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
3805 int ret = 0; 3841 int ret = 0;
3806 struct btrfs_root *root; 3842 struct btrfs_root *root;
3807 struct dentry *old_parent = NULL; 3843 struct dentry *old_parent = NULL;
3844 struct inode *orig_inode = inode;
3808 3845
3809 /* 3846 /*
3810 * 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
@@ -3824,7 +3861,14 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
3824 } 3861 }
3825 3862
3826 while (1) { 3863 while (1) {
3827 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;
3828 smp_mb(); 3872 smp_mb();
3829 3873
3830 if (BTRFS_I(inode)->last_unlink_trans > last_committed) { 3874 if (BTRFS_I(inode)->last_unlink_trans > last_committed) {