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.c158
1 files changed, 138 insertions, 20 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index cb5666e7c3f9..9314adeba946 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -4960,6 +4960,94 @@ next_dir_inode:
4960 return ret; 4960 return ret;
4961} 4961}
4962 4962
4963static int btrfs_log_all_parents(struct btrfs_trans_handle *trans,
4964 struct inode *inode,
4965 struct btrfs_log_ctx *ctx)
4966{
4967 int ret;
4968 struct btrfs_path *path;
4969 struct btrfs_key key;
4970 struct btrfs_root *root = BTRFS_I(inode)->root;
4971 const u64 ino = btrfs_ino(inode);
4972
4973 path = btrfs_alloc_path();
4974 if (!path)
4975 return -ENOMEM;
4976 path->skip_locking = 1;
4977 path->search_commit_root = 1;
4978
4979 key.objectid = ino;
4980 key.type = BTRFS_INODE_REF_KEY;
4981 key.offset = 0;
4982 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
4983 if (ret < 0)
4984 goto out;
4985
4986 while (true) {
4987 struct extent_buffer *leaf = path->nodes[0];
4988 int slot = path->slots[0];
4989 u32 cur_offset = 0;
4990 u32 item_size;
4991 unsigned long ptr;
4992
4993 if (slot >= btrfs_header_nritems(leaf)) {
4994 ret = btrfs_next_leaf(root, path);
4995 if (ret < 0)
4996 goto out;
4997 else if (ret > 0)
4998 break;
4999 continue;
5000 }
5001
5002 btrfs_item_key_to_cpu(leaf, &key, slot);
5003 /* BTRFS_INODE_EXTREF_KEY is BTRFS_INODE_REF_KEY + 1 */
5004 if (key.objectid != ino || key.type > BTRFS_INODE_EXTREF_KEY)
5005 break;
5006
5007 item_size = btrfs_item_size_nr(leaf, slot);
5008 ptr = btrfs_item_ptr_offset(leaf, slot);
5009 while (cur_offset < item_size) {
5010 struct btrfs_key inode_key;
5011 struct inode *dir_inode;
5012
5013 inode_key.type = BTRFS_INODE_ITEM_KEY;
5014 inode_key.offset = 0;
5015
5016 if (key.type == BTRFS_INODE_EXTREF_KEY) {
5017 struct btrfs_inode_extref *extref;
5018
5019 extref = (struct btrfs_inode_extref *)
5020 (ptr + cur_offset);
5021 inode_key.objectid = btrfs_inode_extref_parent(
5022 leaf, extref);
5023 cur_offset += sizeof(*extref);
5024 cur_offset += btrfs_inode_extref_name_len(leaf,
5025 extref);
5026 } else {
5027 inode_key.objectid = key.offset;
5028 cur_offset = item_size;
5029 }
5030
5031 dir_inode = btrfs_iget(root->fs_info->sb, &inode_key,
5032 root, NULL);
5033 /* If parent inode was deleted, skip it. */
5034 if (IS_ERR(dir_inode))
5035 continue;
5036
5037 ret = btrfs_log_inode(trans, root, dir_inode,
5038 LOG_INODE_ALL, 0, LLONG_MAX, ctx);
5039 iput(dir_inode);
5040 if (ret)
5041 goto out;
5042 }
5043 path->slots[0]++;
5044 }
5045 ret = 0;
5046out:
5047 btrfs_free_path(path);
5048 return ret;
5049}
5050
4963/* 5051/*
4964 * helper function around btrfs_log_inode to make sure newly created 5052 * helper function around btrfs_log_inode to make sure newly created
4965 * parent directories also end up in the log. A minimal inode and backref 5053 * parent directories also end up in the log. A minimal inode and backref
@@ -4979,9 +5067,6 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
4979 struct dentry *old_parent = NULL; 5067 struct dentry *old_parent = NULL;
4980 int ret = 0; 5068 int ret = 0;
4981 u64 last_committed = root->fs_info->last_trans_committed; 5069 u64 last_committed = root->fs_info->last_trans_committed;
4982 const struct dentry * const first_parent = parent;
4983 const bool did_unlink = (BTRFS_I(inode)->last_unlink_trans >
4984 last_committed);
4985 bool log_dentries = false; 5070 bool log_dentries = false;
4986 struct inode *orig_inode = inode; 5071 struct inode *orig_inode = inode;
4987 5072
@@ -5042,6 +5127,53 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
5042 if (S_ISDIR(inode->i_mode) && ctx && ctx->log_new_dentries) 5127 if (S_ISDIR(inode->i_mode) && ctx && ctx->log_new_dentries)
5043 log_dentries = true; 5128 log_dentries = true;
5044 5129
5130 /*
5131 * On unlink we must make sure all our current and old parent directores
5132 * inodes are fully logged. This is to prevent leaving dangling
5133 * directory index entries in directories that were our parents but are
5134 * not anymore. Not doing this results in old parent directory being
5135 * impossible to delete after log replay (rmdir will always fail with
5136 * error -ENOTEMPTY).
5137 *
5138 * Example 1:
5139 *
5140 * mkdir testdir
5141 * touch testdir/foo
5142 * ln testdir/foo testdir/bar
5143 * sync
5144 * unlink testdir/bar
5145 * xfs_io -c fsync testdir/foo
5146 * <power failure>
5147 * mount fs, triggers log replay
5148 *
5149 * If we don't log the parent directory (testdir), after log replay the
5150 * directory still has an entry pointing to the file inode using the bar
5151 * name, but a matching BTRFS_INODE_[REF|EXTREF]_KEY does not exist and
5152 * the file inode has a link count of 1.
5153 *
5154 * Example 2:
5155 *
5156 * mkdir testdir
5157 * touch foo
5158 * ln foo testdir/foo2
5159 * ln foo testdir/foo3
5160 * sync
5161 * unlink testdir/foo3
5162 * xfs_io -c fsync foo
5163 * <power failure>
5164 * mount fs, triggers log replay
5165 *
5166 * Similar as the first example, after log replay the parent directory
5167 * testdir still has an entry pointing to the inode file with name foo3
5168 * but the file inode does not have a matching BTRFS_INODE_REF_KEY item
5169 * and has a link count of 2.
5170 */
5171 if (BTRFS_I(inode)->last_unlink_trans > last_committed) {
5172 ret = btrfs_log_all_parents(trans, orig_inode, ctx);
5173 if (ret)
5174 goto end_trans;
5175 }
5176
5045 while (1) { 5177 while (1) {
5046 if (!parent || d_really_is_negative(parent) || sb != d_inode(parent)->i_sb) 5178 if (!parent || d_really_is_negative(parent) || sb != d_inode(parent)->i_sb)
5047 break; 5179 break;
@@ -5050,23 +5182,9 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
5050 if (root != BTRFS_I(inode)->root) 5182 if (root != BTRFS_I(inode)->root)
5051 break; 5183 break;
5052 5184
5053 /* 5185 if (BTRFS_I(inode)->generation > last_committed) {
5054 * On unlink we must make sure our immediate parent directory 5186 ret = btrfs_log_inode(trans, root, inode,
5055 * inode is fully logged. This is to prevent leaving dangling 5187 LOG_INODE_EXISTS,
5056 * directory index entries and a wrong directory inode's i_size.
5057 * Not doing so can result in a directory being impossible to
5058 * delete after log replay (rmdir will always fail with error
5059 * -ENOTEMPTY).
5060 */
5061 if (did_unlink && parent == first_parent)
5062 inode_only = LOG_INODE_ALL;
5063 else
5064 inode_only = LOG_INODE_EXISTS;
5065
5066 if (BTRFS_I(inode)->generation >
5067 root->fs_info->last_trans_committed ||
5068 inode_only == LOG_INODE_ALL) {
5069 ret = btrfs_log_inode(trans, root, inode, inode_only,
5070 0, LLONG_MAX, ctx); 5188 0, LLONG_MAX, ctx);
5071 if (ret) 5189 if (ret)
5072 goto end_trans; 5190 goto end_trans;