aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-09-11 11:57:23 -0400
committerChris Mason <chris.mason@fusionio.com>2013-09-21 11:05:25 -0400
commitdd8e721773fdab5ccc7fde44ec57e30b563243b2 (patch)
treecb008cbc777277de5f08b45d26141a1562b4f728
parenta5874ce6ce4a3e4fc3db254ccf6d59d8501a56d8 (diff)
Btrfs: replay dir_index items before other items
A user reported a bug where his log would not replay because he was getting -EEXIST back. This was because he had a file moved into a directory that was logged. What happens is the file had a lower inode number, and so it is processed first when replaying the log, and so we add the inode ref in for the directory it was moved to. But then we process the directories DIR_INDEX item and try to add the inode ref for that inode and it fails because we already added it when we replayed the inode. To solve this problem we need to just process any DIR_INDEX items we have in the log first so this all is taken care of, and then we can replay the rest of the items. With this patch my reproducer can remount the file system properly instead of erroring out. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
-rw-r--r--fs/btrfs/tree-log.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index aaa2e2b67478..c91309dea8da 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,
@@ -2027,6 +2028,15 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
2027 if (ret) 2028 if (ret)
2028 break; 2029 break;
2029 } 2030 }
2031
2032 if (key.type == BTRFS_DIR_INDEX_KEY &&
2033 wc->stage == LOG_WALK_REPLAY_DIR_INDEX) {
2034 ret = replay_one_dir_item(wc->trans, root, path,
2035 eb, i, &key);
2036 if (ret)
2037 break;
2038 }
2039
2030 if (wc->stage < LOG_WALK_REPLAY_ALL) 2040 if (wc->stage < LOG_WALK_REPLAY_ALL)
2031 continue; 2041 continue;
2032 2042
@@ -2048,8 +2058,7 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
2048 eb, i, &key); 2058 eb, i, &key);
2049 if (ret) 2059 if (ret)
2050 break; 2060 break;
2051 } else if (key.type == BTRFS_DIR_ITEM_KEY || 2061 } 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, 2062 ret = replay_one_dir_item(wc->trans, root, path,
2054 eb, i, &key); 2063 eb, i, &key);
2055 if (ret) 2064 if (ret)