|
@@ -930,6 +930,17 @@ out_nowrite:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int insert_orphan_item(struct btrfs_trans_handle *trans,
|
|
|
+ struct btrfs_root *root, u64 offset)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ ret = btrfs_find_orphan_item(root, offset);
|
|
|
+ if (ret > 0)
|
|
|
+ ret = btrfs_insert_orphan_item(trans, root, offset);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/*
|
|
|
* There are a few corners where the link count of the file can't
|
|
|
* be properly maintained during replay. So, instead of adding
|
|
@@ -997,9 +1008,13 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
|
|
|
}
|
|
|
BTRFS_I(inode)->index_cnt = (u64)-1;
|
|
|
|
|
|
- if (inode->i_nlink == 0 && S_ISDIR(inode->i_mode)) {
|
|
|
- ret = replay_dir_deletes(trans, root, NULL, path,
|
|
|
- inode->i_ino, 1);
|
|
|
+ if (inode->i_nlink == 0) {
|
|
|
+ if (S_ISDIR(inode->i_mode)) {
|
|
|
+ ret = replay_dir_deletes(trans, root, NULL, path,
|
|
|
+ inode->i_ino, 1);
|
|
|
+ BUG_ON(ret);
|
|
|
+ }
|
|
|
+ ret = insert_orphan_item(trans, root, inode->i_ino);
|
|
|
BUG_ON(ret);
|
|
|
}
|
|
|
btrfs_free_path(path);
|
|
@@ -1587,7 +1602,6 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
|
|
|
/* inode keys are done during the first stage */
|
|
|
if (key.type == BTRFS_INODE_ITEM_KEY &&
|
|
|
wc->stage == LOG_WALK_REPLAY_INODES) {
|
|
|
- struct inode *inode;
|
|
|
struct btrfs_inode_item *inode_item;
|
|
|
u32 mode;
|
|
|
|
|
@@ -1603,31 +1617,16 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
|
|
|
eb, i, &key);
|
|
|
BUG_ON(ret);
|
|
|
|
|
|
- /* for regular files, truncate away
|
|
|
- * extents past the new EOF
|
|
|
+ /* for regular files, make sure corresponding
|
|
|
+ * orhpan item exist. extents past the new EOF
|
|
|
+ * will be truncated later by orphan cleanup.
|
|
|
*/
|
|
|
if (S_ISREG(mode)) {
|
|
|
- inode = read_one_inode(root,
|
|
|
- key.objectid);
|
|
|
- BUG_ON(!inode);
|
|
|
-
|
|
|
- ret = btrfs_truncate_inode_items(wc->trans,
|
|
|
- root, inode, inode->i_size,
|
|
|
- BTRFS_EXTENT_DATA_KEY);
|
|
|
+ ret = insert_orphan_item(wc->trans, root,
|
|
|
+ key.objectid);
|
|
|
BUG_ON(ret);
|
|
|
-
|
|
|
- /* if the nlink count is zero here, the iput
|
|
|
- * will free the inode. We bump it to make
|
|
|
- * sure it doesn't get freed until the link
|
|
|
- * count fixup is done
|
|
|
- */
|
|
|
- if (inode->i_nlink == 0) {
|
|
|
- btrfs_inc_nlink(inode);
|
|
|
- btrfs_update_inode(wc->trans,
|
|
|
- root, inode);
|
|
|
- }
|
|
|
- iput(inode);
|
|
|
}
|
|
|
+
|
|
|
ret = link_to_fixup_dir(wc->trans, root,
|
|
|
path, key.objectid);
|
|
|
BUG_ON(ret);
|