#define LOG_INODE_ALL 0
#define LOG_INODE_EXISTS 1
#define LOG_OTHER_INODE 2
+#define LOG_OTHER_INODE_ALL 3
/*
* directory trouble cases
const int slot,
const struct btrfs_key *key,
struct btrfs_inode *inode,
- u64 *other_ino)
+ u64 *other_ino, u64 *other_parent)
{
int ret;
struct btrfs_path *search_path;
if (di_key.objectid != key->objectid) {
ret = 1;
*other_ino = di_key.objectid;
+ *other_parent = parent;
} else {
ret = 0;
}
struct btrfs_ino_list {
u64 ino;
+ u64 parent;
struct list_head list;
};
struct btrfs_root *root,
struct btrfs_path *path,
struct btrfs_log_ctx *ctx,
- u64 ino)
+ u64 ino, u64 parent)
{
struct btrfs_ino_list *ino_elem;
LIST_HEAD(inode_list);
if (!ino_elem)
return -ENOMEM;
ino_elem->ino = ino;
+ ino_elem->parent = parent;
list_add_tail(&ino_elem->list, &inode_list);
while (!list_empty(&inode_list)) {
ino_elem = list_first_entry(&inode_list, struct btrfs_ino_list,
list);
ino = ino_elem->ino;
+ parent = ino_elem->parent;
list_del(&ino_elem->list);
kfree(ino_elem);
if (ret)
inode = btrfs_iget(fs_info->sb, &key, root, NULL);
/*
* If the other inode that had a conflicting dir entry was
- * deleted in the current transaction, we don't need to do more
- * work nor fallback to a transaction commit.
+ * deleted in the current transaction, we need to log its parent
+ * directory.
*/
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
- if (ret == -ENOENT)
- ret = 0;
+ if (ret == -ENOENT) {
+ key.objectid = parent;
+ inode = btrfs_iget(fs_info->sb, &key, root,
+ NULL);
+ if (IS_ERR(inode)) {
+ ret = PTR_ERR(inode);
+ } else {
+ ret = btrfs_log_inode(trans, root,
+ BTRFS_I(inode),
+ LOG_OTHER_INODE_ALL,
+ 0, LLONG_MAX, ctx);
+ iput(inode);
+ }
+ }
continue;
}
/*
struct extent_buffer *leaf = path->nodes[0];
int slot = path->slots[0];
u64 other_ino = 0;
+ u64 other_parent = 0;
if (slot >= btrfs_header_nritems(leaf)) {
ret = btrfs_next_leaf(root, path);
}
ret = btrfs_check_ref_name_override(leaf, slot, &key,
- BTRFS_I(inode), &other_ino);
+ BTRFS_I(inode), &other_ino,
+ &other_parent);
if (ret < 0)
break;
if (ret > 0) {
break;
}
ino_elem->ino = other_ino;
+ ino_elem->parent = other_parent;
list_add_tail(&ino_elem->list, &inode_list);
ret = 0;
}
u64 logged_isize = 0;
bool need_log_inode_item = true;
bool xattrs_logged = false;
- bool recursive_logging = (inode_only == LOG_OTHER_INODE);
+ bool recursive_logging = false;
path = btrfs_alloc_path();
if (!path)
return ret;
}
- if (inode_only == LOG_OTHER_INODE) {
- inode_only = LOG_INODE_EXISTS;
+ if (inode_only == LOG_OTHER_INODE || inode_only == LOG_OTHER_INODE_ALL) {
+ recursive_logging = true;
+ if (inode_only == LOG_OTHER_INODE)
+ inode_only = LOG_INODE_EXISTS;
+ else
+ inode_only = LOG_INODE_ALL;
mutex_lock_nested(&inode->log_mutex, SINGLE_DEPTH_NESTING);
} else {
mutex_lock(&inode->log_mutex);
inode->generation == trans->transid &&
!recursive_logging) {
u64 other_ino = 0;
+ u64 other_parent = 0;
ret = btrfs_check_ref_name_override(path->nodes[0],
path->slots[0], &min_key, inode,
- &other_ino);
+ &other_ino, &other_parent);
if (ret < 0) {
err = ret;
goto out_unlock;
ins_nr = 0;
err = log_conflicting_inodes(trans, root, path,
- ctx, other_ino);
+ ctx, other_ino, other_parent);
if (err)
goto out_unlock;
btrfs_release_path(path);