diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 76c4f9d1b80a..66f87156882f 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -4117,6 +4117,86 @@ static int logged_inode_size(struct btrfs_root *log, struct inode *inode, | |||
4117 | return 0; | 4117 | return 0; |
4118 | } | 4118 | } |
4119 | 4119 | ||
4120 | /* | ||
4121 | * At the moment we always log all xattrs. This is to figure out at log replay | ||
4122 | * time which xattrs must have their deletion replayed. If a xattr is missing | ||
4123 | * in the log tree and exists in the fs/subvol tree, we delete it. This is | ||
4124 | * because if a xattr is deleted, the inode is fsynced and a power failure | ||
4125 | * happens, causing the log to be replayed the next time the fs is mounted, | ||
4126 | * we want the xattr to not exist anymore (same behaviour as other filesystems | ||
4127 | * with a journal, ext3/4, xfs, f2fs, etc). | ||
4128 | */ | ||
4129 | static int btrfs_log_all_xattrs(struct btrfs_trans_handle *trans, | ||
4130 | struct btrfs_root *root, | ||
4131 | struct inode *inode, | ||
4132 | struct btrfs_path *path, | ||
4133 | struct btrfs_path *dst_path) | ||
4134 | { | ||
4135 | int ret; | ||
4136 | struct btrfs_key key; | ||
4137 | const u64 ino = btrfs_ino(inode); | ||
4138 | int ins_nr = 0; | ||
4139 | int start_slot = 0; | ||
4140 | |||
4141 | key.objectid = ino; | ||
4142 | key.type = BTRFS_XATTR_ITEM_KEY; | ||
4143 | key.offset = 0; | ||
4144 | |||
4145 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | ||
4146 | if (ret < 0) | ||
4147 | return ret; | ||
4148 | |||
4149 | while (true) { | ||
4150 | int slot = path->slots[0]; | ||
4151 | struct extent_buffer *leaf = path->nodes[0]; | ||
4152 | int nritems = btrfs_header_nritems(leaf); | ||
4153 | |||
4154 | if (slot >= nritems) { | ||
4155 | if (ins_nr > 0) { | ||
4156 | u64 last_extent = 0; | ||
4157 | |||
4158 | ret = copy_items(trans, inode, dst_path, path, | ||
4159 | &last_extent, start_slot, | ||
4160 | ins_nr, 1, 0); | ||
4161 | /* can't be 1, extent items aren't processed */ | ||
4162 | ASSERT(ret <= 0); | ||
4163 | if (ret < 0) | ||
4164 | return ret; | ||
4165 | ins_nr = 0; | ||
4166 | } | ||
4167 | ret = btrfs_next_leaf(root, path); | ||
4168 | if (ret < 0) | ||
4169 | return ret; | ||
4170 | else if (ret > 0) | ||
4171 | break; | ||
4172 | continue; | ||
4173 | } | ||
4174 | |||
4175 | btrfs_item_key_to_cpu(leaf, &key, slot); | ||
4176 | if (key.objectid != ino || key.type != BTRFS_XATTR_ITEM_KEY) | ||
4177 | break; | ||
4178 | |||
4179 | if (ins_nr == 0) | ||
4180 | start_slot = slot; | ||
4181 | ins_nr++; | ||
4182 | path->slots[0]++; | ||
4183 | cond_resched(); | ||
4184 | } | ||
4185 | if (ins_nr > 0) { | ||
4186 | u64 last_extent = 0; | ||
4187 | |||
4188 | ret = copy_items(trans, inode, dst_path, path, | ||
4189 | &last_extent, start_slot, | ||
4190 | ins_nr, 1, 0); | ||
4191 | /* can't be 1, extent items aren't processed */ | ||
4192 | ASSERT(ret <= 0); | ||
4193 | if (ret < 0) | ||
4194 | return ret; | ||
4195 | } | ||
4196 | |||
4197 | return 0; | ||
4198 | } | ||
4199 | |||
4120 | /* log a single inode in the tree log. | 4200 | /* log a single inode in the tree log. |
4121 | * At least one parent directory for this inode must exist in the tree | 4201 | * At least one parent directory for this inode must exist in the tree |
4122 | * or be logged already. | 4202 | * or be logged already. |
@@ -4289,6 +4369,25 @@ again: | |||
4289 | if (min_key.type == BTRFS_INODE_ITEM_KEY) | 4369 | if (min_key.type == BTRFS_INODE_ITEM_KEY) |
4290 | need_log_inode_item = false; | 4370 | need_log_inode_item = false; |
4291 | 4371 | ||
4372 | /* Skip xattrs, we log them later with btrfs_log_all_xattrs() */ | ||
4373 | if (min_key.type == BTRFS_XATTR_ITEM_KEY) { | ||
4374 | if (ins_nr == 0) | ||
4375 | goto next_slot; | ||
4376 | ret = copy_items(trans, inode, dst_path, path, | ||
4377 | &last_extent, ins_start_slot, | ||
4378 | ins_nr, inode_only, logged_isize); | ||
4379 | if (ret < 0) { | ||
4380 | err = ret; | ||
4381 | goto out_unlock; | ||
4382 | } | ||
4383 | ins_nr = 0; | ||
4384 | if (ret) { | ||
4385 | btrfs_release_path(path); | ||
4386 | continue; | ||
4387 | } | ||
4388 | goto next_slot; | ||
4389 | } | ||
4390 | |||
4292 | src = path->nodes[0]; | 4391 | src = path->nodes[0]; |
4293 | if (ins_nr && ins_start_slot + ins_nr == path->slots[0]) { | 4392 | if (ins_nr && ins_start_slot + ins_nr == path->slots[0]) { |
4294 | ins_nr++; | 4393 | ins_nr++; |
@@ -4356,6 +4455,11 @@ next_slot: | |||
4356 | ins_nr = 0; | 4455 | ins_nr = 0; |
4357 | } | 4456 | } |
4358 | 4457 | ||
4458 | btrfs_release_path(path); | ||
4459 | btrfs_release_path(dst_path); | ||
4460 | err = btrfs_log_all_xattrs(trans, root, inode, path, dst_path); | ||
4461 | if (err) | ||
4462 | goto out_unlock; | ||
4359 | log_extents: | 4463 | log_extents: |
4360 | btrfs_release_path(path); | 4464 | btrfs_release_path(path); |
4361 | btrfs_release_path(dst_path); | 4465 | btrfs_release_path(dst_path); |