Commit 33c0022f 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.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: limit the path size in send to PATH_MAX
  Btrfs: correctly set profile flags on seqlock retry
  Btrfs: use correct key when repeating search for extent item
  Btrfs: fix inode caching vs tree log
  Btrfs: fix possible memory leaks in open_ctree()
  Btrfs: avoid triggering bug_on() when we fail to start inode caching task
  Btrfs: move btrfs_{set,clear}_and_info() to ctree.h
  btrfs: replace error code from btrfs_drop_extents
  btrfs: Change the hole range to a more accurate value.
  btrfs: fix use-after-free in mount_subvol()
parents 2b9d1c05 cfd4a535
...@@ -2058,6 +2058,20 @@ struct btrfs_ioctl_defrag_range_args { ...@@ -2058,6 +2058,20 @@ struct btrfs_ioctl_defrag_range_args {
#define btrfs_raw_test_opt(o, opt) ((o) & BTRFS_MOUNT_##opt) #define btrfs_raw_test_opt(o, opt) ((o) & BTRFS_MOUNT_##opt)
#define btrfs_test_opt(root, opt) ((root)->fs_info->mount_opt & \ #define btrfs_test_opt(root, opt) ((root)->fs_info->mount_opt & \
BTRFS_MOUNT_##opt) BTRFS_MOUNT_##opt)
#define btrfs_set_and_info(root, opt, fmt, args...) \
{ \
if (!btrfs_test_opt(root, opt)) \
btrfs_info(root->fs_info, fmt, ##args); \
btrfs_set_opt(root->fs_info->mount_opt, opt); \
}
#define btrfs_clear_and_info(root, opt, fmt, args...) \
{ \
if (btrfs_test_opt(root, opt)) \
btrfs_info(root->fs_info, fmt, ##args); \
btrfs_clear_opt(root->fs_info->mount_opt, opt); \
}
/* /*
* Inode flags * Inode flags
*/ */
......
...@@ -2861,7 +2861,7 @@ int open_ctree(struct super_block *sb, ...@@ -2861,7 +2861,7 @@ int open_ctree(struct super_block *sb,
printk(KERN_ERR "BTRFS: failed to read log tree\n"); printk(KERN_ERR "BTRFS: failed to read log tree\n");
free_extent_buffer(log_tree_root->node); free_extent_buffer(log_tree_root->node);
kfree(log_tree_root); kfree(log_tree_root);
goto fail_trans_kthread; goto fail_qgroup;
} }
/* returns with log_tree_root freed on success */ /* returns with log_tree_root freed on success */
ret = btrfs_recover_log_trees(log_tree_root); ret = btrfs_recover_log_trees(log_tree_root);
...@@ -2870,24 +2870,24 @@ int open_ctree(struct super_block *sb, ...@@ -2870,24 +2870,24 @@ int open_ctree(struct super_block *sb,
"Failed to recover log tree"); "Failed to recover log tree");
free_extent_buffer(log_tree_root->node); free_extent_buffer(log_tree_root->node);
kfree(log_tree_root); kfree(log_tree_root);
goto fail_trans_kthread; goto fail_qgroup;
} }
if (sb->s_flags & MS_RDONLY) { if (sb->s_flags & MS_RDONLY) {
ret = btrfs_commit_super(tree_root); ret = btrfs_commit_super(tree_root);
if (ret) if (ret)
goto fail_trans_kthread; goto fail_qgroup;
} }
} }
ret = btrfs_find_orphan_roots(tree_root); ret = btrfs_find_orphan_roots(tree_root);
if (ret) if (ret)
goto fail_trans_kthread; goto fail_qgroup;
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
ret = btrfs_cleanup_fs_roots(fs_info); ret = btrfs_cleanup_fs_roots(fs_info);
if (ret) if (ret)
goto fail_trans_kthread; goto fail_qgroup;
ret = btrfs_recover_relocation(tree_root); ret = btrfs_recover_relocation(tree_root);
if (ret < 0) { if (ret < 0) {
......
...@@ -1542,6 +1542,7 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans, ...@@ -1542,6 +1542,7 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
ret = 0; ret = 0;
} }
if (ret) { if (ret) {
key.objectid = bytenr;
key.type = BTRFS_EXTENT_ITEM_KEY; key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = num_bytes; key.offset = num_bytes;
btrfs_release_path(path); btrfs_release_path(path);
...@@ -3542,11 +3543,13 @@ static u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags) ...@@ -3542,11 +3543,13 @@ static u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
return extended_to_chunk(flags | tmp); return extended_to_chunk(flags | tmp);
} }
static u64 get_alloc_profile(struct btrfs_root *root, u64 flags) static u64 get_alloc_profile(struct btrfs_root *root, u64 orig_flags)
{ {
unsigned seq; unsigned seq;
u64 flags;
do { do {
flags = orig_flags;
seq = read_seqbegin(&root->fs_info->profiles_lock); seq = read_seqbegin(&root->fs_info->profiles_lock);
if (flags & BTRFS_BLOCK_GROUP_DATA) if (flags & BTRFS_BLOCK_GROUP_DATA)
...@@ -5719,6 +5722,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, ...@@ -5719,6 +5722,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
if (ret > 0 && skinny_metadata) { if (ret > 0 && skinny_metadata) {
skinny_metadata = false; skinny_metadata = false;
key.objectid = bytenr;
key.type = BTRFS_EXTENT_ITEM_KEY; key.type = BTRFS_EXTENT_ITEM_KEY;
key.offset = num_bytes; key.offset = num_bytes;
btrfs_release_path(path); btrfs_release_path(path);
......
...@@ -800,7 +800,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -800,7 +800,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
if (start > key.offset && end < extent_end) { if (start > key.offset && end < extent_end) {
BUG_ON(del_nr > 0); BUG_ON(del_nr > 0);
if (extent_type == BTRFS_FILE_EXTENT_INLINE) { if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
ret = -EINVAL; ret = -EOPNOTSUPP;
break; break;
} }
...@@ -846,7 +846,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -846,7 +846,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
*/ */
if (start <= key.offset && end < extent_end) { if (start <= key.offset && end < extent_end) {
if (extent_type == BTRFS_FILE_EXTENT_INLINE) { if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
ret = -EINVAL; ret = -EOPNOTSUPP;
break; break;
} }
...@@ -872,7 +872,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -872,7 +872,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
if (start > key.offset && end >= extent_end) { if (start > key.offset && end >= extent_end) {
BUG_ON(del_nr > 0); BUG_ON(del_nr > 0);
if (extent_type == BTRFS_FILE_EXTENT_INLINE) { if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
ret = -EINVAL; ret = -EOPNOTSUPP;
break; break;
} }
...@@ -1777,7 +1777,7 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, ...@@ -1777,7 +1777,7 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
start_pos = round_down(pos, root->sectorsize); start_pos = round_down(pos, root->sectorsize);
if (start_pos > i_size_read(inode)) { if (start_pos > i_size_read(inode)) {
/* Expand hole size to cover write data, preventing empty gap */ /* Expand hole size to cover write data, preventing empty gap */
end_pos = round_up(pos + iov->iov_len, root->sectorsize); end_pos = round_up(pos + count, root->sectorsize);
err = btrfs_cont_expand(inode, i_size_read(inode), end_pos); err = btrfs_cont_expand(inode, i_size_read(inode), end_pos);
if (err) { if (err) {
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
......
...@@ -176,7 +176,11 @@ static void start_caching(struct btrfs_root *root) ...@@ -176,7 +176,11 @@ static void start_caching(struct btrfs_root *root)
tsk = kthread_run(caching_kthread, root, "btrfs-ino-cache-%llu\n", tsk = kthread_run(caching_kthread, root, "btrfs-ino-cache-%llu\n",
root->root_key.objectid); root->root_key.objectid);
BUG_ON(IS_ERR(tsk)); /* -ENOMEM */ if (IS_ERR(tsk)) {
btrfs_warn(root->fs_info, "failed to start inode caching task");
btrfs_clear_and_info(root, CHANGE_INODE_CACHE,
"disabling inode map caching");
}
} }
int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid) int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid)
...@@ -205,24 +209,14 @@ int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid) ...@@ -205,24 +209,14 @@ int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid)
void btrfs_return_ino(struct btrfs_root *root, u64 objectid) void btrfs_return_ino(struct btrfs_root *root, u64 objectid)
{ {
struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
struct btrfs_free_space_ctl *pinned = root->free_ino_pinned; struct btrfs_free_space_ctl *pinned = root->free_ino_pinned;
if (!btrfs_test_opt(root, INODE_MAP_CACHE)) if (!btrfs_test_opt(root, INODE_MAP_CACHE))
return; return;
again: again:
if (root->cached == BTRFS_CACHE_FINISHED) { if (root->cached == BTRFS_CACHE_FINISHED) {
__btrfs_add_free_space(ctl, objectid, 1); __btrfs_add_free_space(pinned, objectid, 1);
} else { } else {
/*
* If we are in the process of caching free ino chunks,
* to avoid adding the same inode number to the free_ino
* tree twice due to cross transaction, we'll leave it
* in the pinned tree until a transaction is committed
* or the caching work is done.
*/
down_write(&root->fs_info->commit_root_sem); down_write(&root->fs_info->commit_root_sem);
spin_lock(&root->cache_lock); spin_lock(&root->cache_lock);
if (root->cached == BTRFS_CACHE_FINISHED) { if (root->cached == BTRFS_CACHE_FINISHED) {
...@@ -234,10 +228,6 @@ void btrfs_return_ino(struct btrfs_root *root, u64 objectid) ...@@ -234,10 +228,6 @@ void btrfs_return_ino(struct btrfs_root *root, u64 objectid)
start_caching(root); start_caching(root);
if (objectid <= root->cache_progress ||
objectid >= root->highest_objectid)
__btrfs_add_free_space(ctl, objectid, 1);
else
__btrfs_add_free_space(pinned, objectid, 1); __btrfs_add_free_space(pinned, objectid, 1);
up_write(&root->fs_info->commit_root_sem); up_write(&root->fs_info->commit_root_sem);
......
...@@ -3066,7 +3066,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode, ...@@ -3066,7 +3066,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
new_key.offset + datal, new_key.offset + datal,
1); 1);
if (ret) { if (ret) {
if (ret != -EINVAL) if (ret != -EOPNOTSUPP)
btrfs_abort_transaction(trans, btrfs_abort_transaction(trans,
root, ret); root, ret);
btrfs_end_transaction(trans, root); btrfs_end_transaction(trans, root);
...@@ -3141,7 +3141,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode, ...@@ -3141,7 +3141,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
new_key.offset + datal, new_key.offset + datal,
1); 1);
if (ret) { if (ret) {
if (ret != -EINVAL) if (ret != -EOPNOTSUPP)
btrfs_abort_transaction(trans, btrfs_abort_transaction(trans,
root, ret); root, ret);
btrfs_end_transaction(trans, root); btrfs_end_transaction(trans, root);
......
...@@ -349,6 +349,11 @@ static int fs_path_ensure_buf(struct fs_path *p, int len) ...@@ -349,6 +349,11 @@ static int fs_path_ensure_buf(struct fs_path *p, int len)
if (p->buf_len >= len) if (p->buf_len >= len)
return 0; return 0;
if (len > PATH_MAX) {
WARN_ON(1);
return -ENOMEM;
}
path_len = p->end - p->start; path_len = p->end - p->start;
old_buf_len = p->buf_len; old_buf_len = p->buf_len;
......
...@@ -385,20 +385,6 @@ static match_table_t tokens = { ...@@ -385,20 +385,6 @@ static match_table_t tokens = {
{Opt_err, NULL}, {Opt_err, NULL},
}; };
#define btrfs_set_and_info(root, opt, fmt, args...) \
{ \
if (!btrfs_test_opt(root, opt)) \
btrfs_info(root->fs_info, fmt, ##args); \
btrfs_set_opt(root->fs_info->mount_opt, opt); \
}
#define btrfs_clear_and_info(root, opt, fmt, args...) \
{ \
if (btrfs_test_opt(root, opt)) \
btrfs_info(root->fs_info, fmt, ##args); \
btrfs_clear_opt(root->fs_info->mount_opt, opt); \
}
/* /*
* Regular mount options parser. Everything that is needed only when * Regular mount options parser. Everything that is needed only when
* reading in a new superblock is parsed here. * reading in a new superblock is parsed here.
...@@ -1186,7 +1172,6 @@ static struct dentry *mount_subvol(const char *subvol_name, int flags, ...@@ -1186,7 +1172,6 @@ static struct dentry *mount_subvol(const char *subvol_name, int flags,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
mnt = vfs_kern_mount(&btrfs_fs_type, flags, device_name, mnt = vfs_kern_mount(&btrfs_fs_type, flags, device_name,
newargs); newargs);
kfree(newargs);
if (PTR_RET(mnt) == -EBUSY) { if (PTR_RET(mnt) == -EBUSY) {
if (flags & MS_RDONLY) { if (flags & MS_RDONLY) {
...@@ -1196,17 +1181,22 @@ static struct dentry *mount_subvol(const char *subvol_name, int flags, ...@@ -1196,17 +1181,22 @@ static struct dentry *mount_subvol(const char *subvol_name, int flags,
int r; int r;
mnt = vfs_kern_mount(&btrfs_fs_type, flags | MS_RDONLY, device_name, mnt = vfs_kern_mount(&btrfs_fs_type, flags | MS_RDONLY, device_name,
newargs); newargs);
if (IS_ERR(mnt)) if (IS_ERR(mnt)) {
kfree(newargs);
return ERR_CAST(mnt); return ERR_CAST(mnt);
}
r = btrfs_remount(mnt->mnt_sb, &flags, NULL); r = btrfs_remount(mnt->mnt_sb, &flags, NULL);
if (r < 0) { if (r < 0) {
/* FIXME: release vfsmount mnt ??*/ /* FIXME: release vfsmount mnt ??*/
kfree(newargs);
return ERR_PTR(r); return ERR_PTR(r);
} }
} }
} }
kfree(newargs);
if (IS_ERR(mnt)) if (IS_ERR(mnt))
return ERR_CAST(mnt); return ERR_CAST(mnt);
......
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