Commit f48d4277 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs

Pull btrfs fixes from Chris Mason:
 "This has our series of fixes for the next rc.  The biggest batch is
  from Jan Schmidt, fixing up some problems in our subvolume quota code
  and fixing btrfs send/receive to work with the new extended inode
  refs."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: do not bug when we fail to commit the transaction
  Btrfs: fix memory leak when cloning root's node
  Btrfs: Use btrfs_update_inode_fallback when creating a snapshot
  Btrfs: Send: preserve ownership (uid and gid) also for symlinks.
  Btrfs: fix deadlock caused by the nested chunk allocation
  btrfs: Return EINVAL when length to trim is less than FSB
  Btrfs: fix memory leak in btrfs_quota_enable()
  Btrfs: send correct rdev and mode in btrfs-send
  Btrfs: extended inode refs support for send mechanism
  Btrfs: Fix wrong error handling code
  Fix a sign bug causing invalid memory access in the ino_paths ioctl.
  Btrfs: comment for loop in tree_mod_log_insert_move
  Btrfs: fix extent buffer reference for tree mod log roots
  Btrfs: determine level of old roots
  Btrfs: tree mod log's old roots could still be part of the tree
  Btrfs: fix a tree mod logging issue for root replacement operations
  Btrfs: don't put removals from push_node_left into tree mod log twice
parents b394209c c37b2b62
...@@ -283,9 +283,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, ...@@ -283,9 +283,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
goto out; goto out;
} }
rcu_read_lock(); root_level = btrfs_old_root_level(root, time_seq);
root_level = btrfs_header_level(root->node);
rcu_read_unlock();
if (root_level + 1 == level) if (root_level + 1 == level)
goto out; goto out;
...@@ -1177,8 +1175,7 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid, ...@@ -1177,8 +1175,7 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
return ret; return ret;
} }
static char *ref_to_path(struct btrfs_root *fs_root, char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
struct btrfs_path *path,
u32 name_len, unsigned long name_off, u32 name_len, unsigned long name_off,
struct extent_buffer *eb_in, u64 parent, struct extent_buffer *eb_in, u64 parent,
char *dest, u32 size) char *dest, u32 size)
...@@ -1186,7 +1183,7 @@ static char *ref_to_path(struct btrfs_root *fs_root, ...@@ -1186,7 +1183,7 @@ static char *ref_to_path(struct btrfs_root *fs_root,
int slot; int slot;
u64 next_inum; u64 next_inum;
int ret; int ret;
s64 bytes_left = size - 1; s64 bytes_left = ((s64)size) - 1;
struct extent_buffer *eb = eb_in; struct extent_buffer *eb = eb_in;
struct btrfs_key found_key; struct btrfs_key found_key;
int leave_spinning = path->leave_spinning; int leave_spinning = path->leave_spinning;
...@@ -1266,7 +1263,7 @@ char *btrfs_iref_to_path(struct btrfs_root *fs_root, ...@@ -1266,7 +1263,7 @@ char *btrfs_iref_to_path(struct btrfs_root *fs_root,
struct extent_buffer *eb_in, u64 parent, struct extent_buffer *eb_in, u64 parent,
char *dest, u32 size) char *dest, u32 size)
{ {
return ref_to_path(fs_root, path, return btrfs_ref_to_path(fs_root, path,
btrfs_inode_ref_name_len(eb_in, iref), btrfs_inode_ref_name_len(eb_in, iref),
(unsigned long)(iref + 1), (unsigned long)(iref + 1),
eb_in, parent, dest, size); eb_in, parent, dest, size);
...@@ -1715,9 +1712,8 @@ static int inode_to_path(u64 inum, u32 name_len, unsigned long name_off, ...@@ -1715,9 +1712,8 @@ static int inode_to_path(u64 inum, u32 name_len, unsigned long name_off,
ipath->fspath->bytes_left - s_ptr : 0; ipath->fspath->bytes_left - s_ptr : 0;
fspath_min = (char *)ipath->fspath->val + (i + 1) * s_ptr; fspath_min = (char *)ipath->fspath->val + (i + 1) * s_ptr;
fspath = ref_to_path(ipath->fs_root, ipath->btrfs_path, name_len, fspath = btrfs_ref_to_path(ipath->fs_root, ipath->btrfs_path, name_len,
name_off, eb, inum, fspath_min, name_off, eb, inum, fspath_min, bytes_left);
bytes_left);
if (IS_ERR(fspath)) if (IS_ERR(fspath))
return PTR_ERR(fspath); return PTR_ERR(fspath);
......
...@@ -62,6 +62,10 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans, ...@@ -62,6 +62,10 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
struct btrfs_inode_ref *iref, struct extent_buffer *eb, struct btrfs_inode_ref *iref, struct extent_buffer *eb,
u64 parent, char *dest, u32 size); u64 parent, char *dest, u32 size);
char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
u32 name_len, unsigned long name_off,
struct extent_buffer *eb_in, u64 parent,
char *dest, u32 size);
struct btrfs_data_container *init_data_container(u32 total_bytes); struct btrfs_data_container *init_data_container(u32 total_bytes);
struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root, struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root,
......
...@@ -596,6 +596,11 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info, ...@@ -596,6 +596,11 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,
if (tree_mod_dont_log(fs_info, eb)) if (tree_mod_dont_log(fs_info, eb))
return 0; return 0;
/*
* When we override something during the move, we log these removals.
* This can only happen when we move towards the beginning of the
* buffer, i.e. dst_slot < src_slot.
*/
for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) { for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) {
ret = tree_mod_log_insert_key_locked(fs_info, eb, i + dst_slot, ret = tree_mod_log_insert_key_locked(fs_info, eb, i + dst_slot,
MOD_LOG_KEY_REMOVE_WHILE_MOVING); MOD_LOG_KEY_REMOVE_WHILE_MOVING);
...@@ -647,8 +652,6 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info, ...@@ -647,8 +652,6 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
if (tree_mod_dont_log(fs_info, NULL)) if (tree_mod_dont_log(fs_info, NULL))
return 0; return 0;
__tree_mod_log_free_eb(fs_info, old_root);
ret = tree_mod_alloc(fs_info, flags, &tm); ret = tree_mod_alloc(fs_info, flags, &tm);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -926,11 +929,6 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, ...@@ -926,11 +929,6 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
ret = btrfs_dec_ref(trans, root, buf, 1, 1); ret = btrfs_dec_ref(trans, root, buf, 1, 1);
BUG_ON(ret); /* -ENOMEM */ BUG_ON(ret); /* -ENOMEM */
} }
/*
* don't log freeing in case we're freeing the root node, this
* is done by tree_mod_log_set_root_pointer later
*/
if (buf != root->node && btrfs_header_level(buf) != 0)
tree_mod_log_free_eb(root->fs_info, buf); tree_mod_log_free_eb(root->fs_info, buf);
clean_tree_block(trans, root, buf); clean_tree_block(trans, root, buf);
*last_ref = 1; *last_ref = 1;
...@@ -1225,6 +1223,8 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, ...@@ -1225,6 +1223,8 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,
free_extent_buffer(eb); free_extent_buffer(eb);
__tree_mod_log_rewind(eb_rewin, time_seq, tm); __tree_mod_log_rewind(eb_rewin, time_seq, tm);
WARN_ON(btrfs_header_nritems(eb_rewin) >
BTRFS_NODEPTRS_PER_BLOCK(fs_info->fs_root));
return eb_rewin; return eb_rewin;
} }
...@@ -1241,9 +1241,11 @@ get_old_root(struct btrfs_root *root, u64 time_seq) ...@@ -1241,9 +1241,11 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
{ {
struct tree_mod_elem *tm; struct tree_mod_elem *tm;
struct extent_buffer *eb; struct extent_buffer *eb;
struct extent_buffer *old;
struct tree_mod_root *old_root = NULL; struct tree_mod_root *old_root = NULL;
u64 old_generation = 0; u64 old_generation = 0;
u64 logical; u64 logical;
u32 blocksize;
eb = btrfs_read_lock_root_node(root); eb = btrfs_read_lock_root_node(root);
tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq); tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq);
...@@ -1259,14 +1261,32 @@ get_old_root(struct btrfs_root *root, u64 time_seq) ...@@ -1259,14 +1261,32 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
} }
tm = tree_mod_log_search(root->fs_info, logical, time_seq); tm = tree_mod_log_search(root->fs_info, logical, time_seq);
if (old_root) if (old_root && tm && tm->op != MOD_LOG_KEY_REMOVE_WHILE_FREEING) {
btrfs_tree_read_unlock(root->node);
free_extent_buffer(root->node);
blocksize = btrfs_level_size(root, old_root->level);
old = read_tree_block(root, logical, blocksize, 0);
if (!old) {
pr_warn("btrfs: failed to read tree block %llu from get_old_root\n",
logical);
WARN_ON(1);
} else {
eb = btrfs_clone_extent_buffer(old);
free_extent_buffer(old);
}
} else if (old_root) {
btrfs_tree_read_unlock(root->node);
free_extent_buffer(root->node);
eb = alloc_dummy_extent_buffer(logical, root->nodesize); eb = alloc_dummy_extent_buffer(logical, root->nodesize);
else } else {
eb = btrfs_clone_extent_buffer(root->node); eb = btrfs_clone_extent_buffer(root->node);
btrfs_tree_read_unlock(root->node); btrfs_tree_read_unlock(root->node);
free_extent_buffer(root->node); free_extent_buffer(root->node);
}
if (!eb) if (!eb)
return NULL; return NULL;
extent_buffer_get(eb);
btrfs_tree_read_lock(eb); btrfs_tree_read_lock(eb);
if (old_root) { if (old_root) {
btrfs_set_header_bytenr(eb, eb->start); btrfs_set_header_bytenr(eb, eb->start);
...@@ -1279,11 +1299,28 @@ get_old_root(struct btrfs_root *root, u64 time_seq) ...@@ -1279,11 +1299,28 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
__tree_mod_log_rewind(eb, time_seq, tm); __tree_mod_log_rewind(eb, time_seq, tm);
else else
WARN_ON(btrfs_header_level(eb) != 0); WARN_ON(btrfs_header_level(eb) != 0);
extent_buffer_get(eb); WARN_ON(btrfs_header_nritems(eb) > BTRFS_NODEPTRS_PER_BLOCK(root));
return eb; return eb;
} }
int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq)
{
struct tree_mod_elem *tm;
int level;
tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq);
if (tm && tm->op == MOD_LOG_ROOT_REPLACE) {
level = tm->old_root.level;
} else {
rcu_read_lock();
level = btrfs_header_level(root->node);
rcu_read_unlock();
}
return level;
}
static inline int should_cow_block(struct btrfs_trans_handle *trans, static inline int should_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct extent_buffer *buf) struct extent_buffer *buf)
...@@ -1725,6 +1762,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, ...@@ -1725,6 +1762,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
goto enospc; goto enospc;
} }
tree_mod_log_free_eb(root->fs_info, root->node);
tree_mod_log_set_root_pointer(root, child); tree_mod_log_set_root_pointer(root, child);
rcu_assign_pointer(root->node, child); rcu_assign_pointer(root->node, child);
...@@ -2970,8 +3008,10 @@ static int push_node_left(struct btrfs_trans_handle *trans, ...@@ -2970,8 +3008,10 @@ static int push_node_left(struct btrfs_trans_handle *trans,
push_items * sizeof(struct btrfs_key_ptr)); push_items * sizeof(struct btrfs_key_ptr));
if (push_items < src_nritems) { if (push_items < src_nritems) {
tree_mod_log_eb_move(root->fs_info, src, 0, push_items, /*
src_nritems - push_items); * don't call tree_mod_log_eb_move here, key removal was already
* fully logged by tree_mod_log_eb_copy above.
*/
memmove_extent_buffer(src, btrfs_node_key_ptr_offset(0), memmove_extent_buffer(src, btrfs_node_key_ptr_offset(0),
btrfs_node_key_ptr_offset(push_items), btrfs_node_key_ptr_offset(push_items),
(src_nritems - push_items) * (src_nritems - push_items) *
......
...@@ -3120,6 +3120,7 @@ static inline u64 btrfs_inc_tree_mod_seq(struct btrfs_fs_info *fs_info) ...@@ -3120,6 +3120,7 @@ static inline u64 btrfs_inc_tree_mod_seq(struct btrfs_fs_info *fs_info)
{ {
return atomic_inc_return(&fs_info->tree_mod_seq); return atomic_inc_return(&fs_info->tree_mod_seq);
} }
int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq);
/* root-item.c */ /* root-item.c */
int btrfs_find_root_ref(struct btrfs_root *tree_root, int btrfs_find_root_ref(struct btrfs_root *tree_root,
...@@ -3338,6 +3339,8 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, ...@@ -3338,6 +3339,8 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
int btrfs_update_inode(struct btrfs_trans_handle *trans, int btrfs_update_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct inode *inode); struct inode *inode);
int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode);
int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode); int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode);
int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode); int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode);
int btrfs_orphan_cleanup(struct btrfs_root *root); int btrfs_orphan_cleanup(struct btrfs_root *root);
......
...@@ -4110,8 +4110,8 @@ struct extent_buffer *alloc_dummy_extent_buffer(u64 start, unsigned long len) ...@@ -4110,8 +4110,8 @@ struct extent_buffer *alloc_dummy_extent_buffer(u64 start, unsigned long len)
return eb; return eb;
err: err:
for (i--; i >= 0; i--) for (; i > 0; i--)
__free_page(eb->pages[i]); __free_page(eb->pages[i - 1]);
__free_extent_buffer(eb); __free_extent_buffer(eb);
return NULL; return NULL;
} }
......
...@@ -94,8 +94,6 @@ static noinline int cow_file_range(struct inode *inode, ...@@ -94,8 +94,6 @@ static noinline int cow_file_range(struct inode *inode,
struct page *locked_page, struct page *locked_page,
u64 start, u64 end, int *page_started, u64 start, u64 end, int *page_started,
unsigned long *nr_written, int unlock); unsigned long *nr_written, int unlock);
static noinline int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode);
static int btrfs_init_inode_security(struct btrfs_trans_handle *trans, static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
struct inode *inode, struct inode *dir, struct inode *inode, struct inode *dir,
...@@ -2746,8 +2744,9 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans, ...@@ -2746,8 +2744,9 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
return btrfs_update_inode_item(trans, root, inode); return btrfs_update_inode_item(trans, root, inode);
} }
static noinline int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans, noinline int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode) struct btrfs_root *root,
struct inode *inode)
{ {
int ret; int ret;
......
...@@ -343,7 +343,8 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) ...@@ -343,7 +343,8 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (copy_from_user(&range, arg, sizeof(range))) if (copy_from_user(&range, arg, sizeof(range)))
return -EFAULT; return -EFAULT;
if (range.start > total_bytes) if (range.start > total_bytes ||
range.len < fs_info->sb->s_blocksize)
return -EINVAL; return -EINVAL;
range.len = min(range.len, total_bytes - range.start); range.len = min(range.len, total_bytes - range.start);
...@@ -570,7 +571,8 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, ...@@ -570,7 +571,8 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
ret = btrfs_commit_transaction(trans, ret = btrfs_commit_transaction(trans,
root->fs_info->extent_root); root->fs_info->extent_root);
} }
BUG_ON(ret); if (ret)
goto fail;
ret = pending_snapshot->error; ret = pending_snapshot->error;
if (ret) if (ret)
......
...@@ -790,8 +790,10 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans, ...@@ -790,8 +790,10 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans,
} }
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) if (!path) {
return -ENOMEM; ret = -ENOMEM;
goto out_free_root;
}
key.objectid = 0; key.objectid = 0;
key.type = BTRFS_QGROUP_STATUS_KEY; key.type = BTRFS_QGROUP_STATUS_KEY;
...@@ -800,7 +802,7 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans, ...@@ -800,7 +802,7 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans,
ret = btrfs_insert_empty_item(trans, quota_root, path, &key, ret = btrfs_insert_empty_item(trans, quota_root, path, &key,
sizeof(*ptr)); sizeof(*ptr));
if (ret) if (ret)
goto out; goto out_free_path;
leaf = path->nodes[0]; leaf = path->nodes[0];
ptr = btrfs_item_ptr(leaf, path->slots[0], ptr = btrfs_item_ptr(leaf, path->slots[0],
...@@ -818,8 +820,15 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans, ...@@ -818,8 +820,15 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans,
fs_info->quota_root = quota_root; fs_info->quota_root = quota_root;
fs_info->pending_quota_state = 1; fs_info->pending_quota_state = 1;
spin_unlock(&fs_info->qgroup_lock); spin_unlock(&fs_info->qgroup_lock);
out: out_free_path:
btrfs_free_path(path); btrfs_free_path(path);
out_free_root:
if (ret) {
free_extent_buffer(quota_root->node);
free_extent_buffer(quota_root->commit_root);
kfree(quota_root);
}
out:
return ret; return ret;
} }
......
...@@ -745,31 +745,36 @@ typedef int (*iterate_inode_ref_t)(int num, u64 dir, int index, ...@@ -745,31 +745,36 @@ typedef int (*iterate_inode_ref_t)(int num, u64 dir, int index,
void *ctx); void *ctx);
/* /*
* Helper function to iterate the entries in ONE btrfs_inode_ref. * Helper function to iterate the entries in ONE btrfs_inode_ref or
* btrfs_inode_extref.
* The iterate callback may return a non zero value to stop iteration. This can * The iterate callback may return a non zero value to stop iteration. This can
* be a negative value for error codes or 1 to simply stop it. * be a negative value for error codes or 1 to simply stop it.
* *
* path must point to the INODE_REF when called. * path must point to the INODE_REF or INODE_EXTREF when called.
*/ */
static int iterate_inode_ref(struct send_ctx *sctx, static int iterate_inode_ref(struct send_ctx *sctx,
struct btrfs_root *root, struct btrfs_path *path, struct btrfs_root *root, struct btrfs_path *path,
struct btrfs_key *found_key, int resolve, struct btrfs_key *found_key, int resolve,
iterate_inode_ref_t iterate, void *ctx) iterate_inode_ref_t iterate, void *ctx)
{ {
struct extent_buffer *eb; struct extent_buffer *eb = path->nodes[0];
struct btrfs_item *item; struct btrfs_item *item;
struct btrfs_inode_ref *iref; struct btrfs_inode_ref *iref;
struct btrfs_inode_extref *extref;
struct btrfs_path *tmp_path; struct btrfs_path *tmp_path;
struct fs_path *p; struct fs_path *p;
u32 cur; u32 cur = 0;
u32 len;
u32 total; u32 total;
int slot; int slot = path->slots[0];
u32 name_len; u32 name_len;
char *start; char *start;
int ret = 0; int ret = 0;
int num; int num = 0;
int index; int index;
u64 dir;
unsigned long name_off;
unsigned long elem_size;
unsigned long ptr;
p = fs_path_alloc_reversed(sctx); p = fs_path_alloc_reversed(sctx);
if (!p) if (!p)
...@@ -781,24 +786,40 @@ static int iterate_inode_ref(struct send_ctx *sctx, ...@@ -781,24 +786,40 @@ static int iterate_inode_ref(struct send_ctx *sctx,
return -ENOMEM; return -ENOMEM;
} }
eb = path->nodes[0];
slot = path->slots[0]; if (found_key->type == BTRFS_INODE_REF_KEY) {
ptr = (unsigned long)btrfs_item_ptr(eb, slot,
struct btrfs_inode_ref);
item = btrfs_item_nr(eb, slot); item = btrfs_item_nr(eb, slot);
iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref);
cur = 0;
len = 0;
total = btrfs_item_size(eb, item); total = btrfs_item_size(eb, item);
elem_size = sizeof(*iref);
} else {
ptr = btrfs_item_ptr_offset(eb, slot);
total = btrfs_item_size_nr(eb, slot);
elem_size = sizeof(*extref);
}
num = 0;
while (cur < total) { while (cur < total) {
fs_path_reset(p); fs_path_reset(p);
if (found_key->type == BTRFS_INODE_REF_KEY) {
iref = (struct btrfs_inode_ref *)(ptr + cur);
name_len = btrfs_inode_ref_name_len(eb, iref); name_len = btrfs_inode_ref_name_len(eb, iref);
name_off = (unsigned long)(iref + 1);
index = btrfs_inode_ref_index(eb, iref); index = btrfs_inode_ref_index(eb, iref);
dir = found_key->offset;
} else {
extref = (struct btrfs_inode_extref *)(ptr + cur);
name_len = btrfs_inode_extref_name_len(eb, extref);
name_off = (unsigned long)&extref->name;
index = btrfs_inode_extref_index(eb, extref);
dir = btrfs_inode_extref_parent(eb, extref);
}
if (resolve) { if (resolve) {
start = btrfs_iref_to_path(root, tmp_path, iref, eb, start = btrfs_ref_to_path(root, tmp_path, name_len,
found_key->offset, p->buf, name_off, eb, dir,
p->buf_len); p->buf, p->buf_len);
if (IS_ERR(start)) { if (IS_ERR(start)) {
ret = PTR_ERR(start); ret = PTR_ERR(start);
goto out; goto out;
...@@ -809,9 +830,10 @@ static int iterate_inode_ref(struct send_ctx *sctx, ...@@ -809,9 +830,10 @@ static int iterate_inode_ref(struct send_ctx *sctx,
p->buf_len + p->buf - start); p->buf_len + p->buf - start);
if (ret < 0) if (ret < 0)
goto out; goto out;
start = btrfs_iref_to_path(root, tmp_path, iref, start = btrfs_ref_to_path(root, tmp_path,
eb, found_key->offset, p->buf, name_len, name_off,
p->buf_len); eb, dir,
p->buf, p->buf_len);
if (IS_ERR(start)) { if (IS_ERR(start)) {
ret = PTR_ERR(start); ret = PTR_ERR(start);
goto out; goto out;
...@@ -820,21 +842,16 @@ static int iterate_inode_ref(struct send_ctx *sctx, ...@@ -820,21 +842,16 @@ static int iterate_inode_ref(struct send_ctx *sctx,
} }
p->start = start; p->start = start;
} else { } else {
ret = fs_path_add_from_extent_buffer(p, eb, ret = fs_path_add_from_extent_buffer(p, eb, name_off,
(unsigned long)(iref + 1), name_len); name_len);
if (ret < 0) if (ret < 0)
goto out; goto out;
} }
cur += elem_size + name_len;
len = sizeof(*iref) + name_len; ret = iterate(num, dir, index, p, ctx);
iref = (struct btrfs_inode_ref *)((char *)iref + len);
cur += len;
ret = iterate(num, found_key->offset, index, p, ctx);
if (ret) if (ret)
goto out; goto out;
num++; num++;
} }
...@@ -998,7 +1015,8 @@ static int get_inode_path(struct send_ctx *sctx, struct btrfs_root *root, ...@@ -998,7 +1015,8 @@ static int get_inode_path(struct send_ctx *sctx, struct btrfs_root *root,
} }
btrfs_item_key_to_cpu(p->nodes[0], &found_key, p->slots[0]); btrfs_item_key_to_cpu(p->nodes[0], &found_key, p->slots[0]);
if (found_key.objectid != ino || if (found_key.objectid != ino ||
found_key.type != BTRFS_INODE_REF_KEY) { (found_key.type != BTRFS_INODE_REF_KEY &&
found_key.type != BTRFS_INODE_EXTREF_KEY)) {
ret = -ENOENT; ret = -ENOENT;
goto out; goto out;
} }
...@@ -1551,8 +1569,8 @@ static int get_first_ref(struct send_ctx *sctx, ...@@ -1551,8 +1569,8 @@ static int get_first_ref(struct send_ctx *sctx,
struct btrfs_key key; struct btrfs_key key;
struct btrfs_key found_key; struct btrfs_key found_key;
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_inode_ref *iref;
int len; int len;
u64 parent_dir;
path = alloc_path_for_send(); path = alloc_path_for_send();
if (!path) if (!path)
...@@ -1568,27 +1586,41 @@ static int get_first_ref(struct send_ctx *sctx, ...@@ -1568,27 +1586,41 @@ static int get_first_ref(struct send_ctx *sctx,
if (!ret) if (!ret)
btrfs_item_key_to_cpu(path->nodes[0], &found_key, btrfs_item_key_to_cpu(path->nodes[0], &found_key,
path->slots[0]); path->slots[0]);
if (ret || found_key.objectid != key.objectid || if (ret || found_key.objectid != ino ||
found_key.type != key.type) { (found_key.type != BTRFS_INODE_REF_KEY &&
found_key.type != BTRFS_INODE_EXTREF_KEY)) {
ret = -ENOENT; ret = -ENOENT;
goto out; goto out;
} }
if (key.type == BTRFS_INODE_REF_KEY) {
struct btrfs_inode_ref *iref;
iref = btrfs_item_ptr(path->nodes[0], path->slots[0], iref = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_inode_ref); struct btrfs_inode_ref);
len = btrfs_inode_ref_name_len(path->nodes[0], iref); len = btrfs_inode_ref_name_len(path->nodes[0], iref);
ret = fs_path_add_from_extent_buffer(name, path->nodes[0], ret = fs_path_add_from_extent_buffer(name, path->nodes[0],
(unsigned long)(iref + 1), len); (unsigned long)(iref + 1),
len);
parent_dir = found_key.offset;
} else {
struct btrfs_inode_extref *extref;
extref = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_inode_extref);
len = btrfs_inode_extref_name_len(path->nodes[0], extref);
ret = fs_path_add_from_extent_buffer(name, path->nodes[0],
(unsigned long)&extref->name, len);
parent_dir = btrfs_inode_extref_parent(path->nodes[0], extref);
}
if (ret < 0) if (ret < 0)
goto out; goto out;
btrfs_release_path(path); btrfs_release_path(path);
ret = get_inode_info(root, found_key.offset, NULL, dir_gen, NULL, NULL, ret = get_inode_info(root, parent_dir, NULL, dir_gen, NULL, NULL,
NULL, NULL); NULL, NULL);
if (ret < 0) if (ret < 0)
goto out; goto out;
*dir = found_key.offset; *dir = parent_dir;
out: out:
btrfs_free_path(path); btrfs_free_path(path);
...@@ -2430,7 +2462,8 @@ verbose_printk("btrfs: send_create_inode %llu\n", ino); ...@@ -2430,7 +2462,8 @@ verbose_printk("btrfs: send_create_inode %llu\n", ino);
TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH_LINK, p); TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH_LINK, p);
} else if (S_ISCHR(mode) || S_ISBLK(mode) || } else if (S_ISCHR(mode) || S_ISBLK(mode) ||
S_ISFIFO(mode) || S_ISSOCK(mode)) { S_ISFIFO(mode) || S_ISSOCK(mode)) {
TLV_PUT_U64(sctx, BTRFS_SEND_A_RDEV, rdev); TLV_PUT_U64(sctx, BTRFS_SEND_A_RDEV, new_encode_dev(rdev));
TLV_PUT_U64(sctx, BTRFS_SEND_A_MODE, mode);
} }
ret = send_cmd(sctx); ret = send_cmd(sctx);
...@@ -3226,7 +3259,8 @@ static int process_all_refs(struct send_ctx *sctx, ...@@ -3226,7 +3259,8 @@ static int process_all_refs(struct send_ctx *sctx,
btrfs_item_key_to_cpu(eb, &found_key, slot); btrfs_item_key_to_cpu(eb, &found_key, slot);
if (found_key.objectid != key.objectid || if (found_key.objectid != key.objectid ||
found_key.type != key.type) (found_key.type != BTRFS_INODE_REF_KEY &&
found_key.type != BTRFS_INODE_EXTREF_KEY))
break; break;
ret = iterate_inode_ref(sctx, root, path, &found_key, 0, cb, ret = iterate_inode_ref(sctx, root, path, &found_key, 0, cb,
...@@ -3987,7 +4021,7 @@ static int process_recorded_refs_if_needed(struct send_ctx *sctx, int at_end) ...@@ -3987,7 +4021,7 @@ static int process_recorded_refs_if_needed(struct send_ctx *sctx, int at_end)
if (sctx->cur_ino == 0) if (sctx->cur_ino == 0)
goto out; goto out;
if (!at_end && sctx->cur_ino == sctx->cmp_key->objectid && if (!at_end && sctx->cur_ino == sctx->cmp_key->objectid &&
sctx->cmp_key->type <= BTRFS_INODE_REF_KEY) sctx->cmp_key->type <= BTRFS_INODE_EXTREF_KEY)
goto out; goto out;
if (list_empty(&sctx->new_refs) && list_empty(&sctx->deleted_refs)) if (list_empty(&sctx->new_refs) && list_empty(&sctx->deleted_refs))
goto out; goto out;
...@@ -4033,10 +4067,10 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end) ...@@ -4033,10 +4067,10 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
if (ret < 0) if (ret < 0)
goto out; goto out;
if (!S_ISLNK(sctx->cur_inode_mode)) {
if (!sctx->parent_root || sctx->cur_inode_new) { if (!sctx->parent_root || sctx->cur_inode_new) {
need_chmod = 1;
need_chown = 1; need_chown = 1;
if (!S_ISLNK(sctx->cur_inode_mode))
need_chmod = 1;
} else { } else {
ret = get_inode_info(sctx->parent_root, sctx->cur_ino, ret = get_inode_info(sctx->parent_root, sctx->cur_ino,
NULL, NULL, &right_mode, &right_uid, NULL, NULL, &right_mode, &right_uid,
...@@ -4046,10 +4080,9 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end) ...@@ -4046,10 +4080,9 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
if (left_uid != right_uid || left_gid != right_gid) if (left_uid != right_uid || left_gid != right_gid)
need_chown = 1; need_chown = 1;
if (left_mode != right_mode) if (!S_ISLNK(sctx->cur_inode_mode) && left_mode != right_mode)
need_chmod = 1; need_chmod = 1;
} }
}
if (S_ISREG(sctx->cur_inode_mode)) { if (S_ISREG(sctx->cur_inode_mode)) {
ret = send_truncate(sctx, sctx->cur_ino, sctx->cur_inode_gen, ret = send_truncate(sctx, sctx->cur_ino, sctx->cur_inode_gen,
...@@ -4335,7 +4368,8 @@ static int changed_cb(struct btrfs_root *left_root, ...@@ -4335,7 +4368,8 @@ static int changed_cb(struct btrfs_root *left_root,
if (key->type == BTRFS_INODE_ITEM_KEY) if (key->type == BTRFS_INODE_ITEM_KEY)
ret = changed_inode(sctx, result); ret = changed_inode(sctx, result);
else if (key->type == BTRFS_INODE_REF_KEY) else if (key->type == BTRFS_INODE_REF_KEY ||
key->type == BTRFS_INODE_EXTREF_KEY)
ret = changed_ref(sctx, result); ret = changed_ref(sctx, result);
else if (key->type == BTRFS_XATTR_ITEM_KEY) else if (key->type == BTRFS_XATTR_ITEM_KEY)
ret = changed_xattr(sctx, result); ret = changed_xattr(sctx, result);
......
...@@ -1200,7 +1200,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ...@@ -1200,7 +1200,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
btrfs_i_size_write(parent_inode, parent_inode->i_size + btrfs_i_size_write(parent_inode, parent_inode->i_size +
dentry->d_name.len * 2); dentry->d_name.len * 2);
parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME; parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
ret = btrfs_update_inode(trans, parent_root, parent_inode); ret = btrfs_update_inode_fallback(trans, parent_root, parent_inode);
if (ret) if (ret)
btrfs_abort_transaction(trans, root, ret); btrfs_abort_transaction(trans, root, ret);
fail: fail:
......
...@@ -1819,6 +1819,13 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) ...@@ -1819,6 +1819,13 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
"Failed to relocate sys chunks after " "Failed to relocate sys chunks after "
"device initialization. This can be fixed " "device initialization. This can be fixed "
"using the \"btrfs balance\" command."); "using the \"btrfs balance\" command.");
trans = btrfs_attach_transaction(root);
if (IS_ERR(trans)) {
if (PTR_ERR(trans) == -ENOENT)
return 0;
return PTR_ERR(trans);
}
ret = btrfs_commit_transaction(trans, root);
} }
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment