Commit 30a0f5e1 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable

* git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable:
  Btrfs: fix possible panic on unmount
  Btrfs: deal with NULL acl sent to btrfs_set_acl
  Btrfs: fix regression in orphan cleanup
  Btrfs: Fix race in btrfs_mark_extent_written
  Btrfs, fix memory leaks in error paths
  Btrfs: align offsets for btrfs_ordered_update_i_size
  btrfs: fix missing last-entry in readdir(3)
parents 88f50044 11dfe35a
...@@ -112,12 +112,14 @@ static int btrfs_set_acl(struct btrfs_trans_handle *trans, ...@@ -112,12 +112,14 @@ static int btrfs_set_acl(struct btrfs_trans_handle *trans,
switch (type) { switch (type) {
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
mode = inode->i_mode; mode = inode->i_mode;
ret = posix_acl_equiv_mode(acl, &mode);
if (ret < 0)
return ret;
ret = 0;
inode->i_mode = mode;
name = POSIX_ACL_XATTR_ACCESS; name = POSIX_ACL_XATTR_ACCESS;
if (acl) {
ret = posix_acl_equiv_mode(acl, &mode);
if (ret < 0)
return ret;
inode->i_mode = mode;
}
ret = 0;
break; break;
case ACL_TYPE_DEFAULT: case ACL_TYPE_DEFAULT:
if (!S_ISDIR(inode->i_mode)) if (!S_ISDIR(inode->i_mode))
......
...@@ -83,6 +83,17 @@ static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits) ...@@ -83,6 +83,17 @@ static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits)
return (cache->flags & bits) == bits; return (cache->flags & bits) == bits;
} }
void btrfs_get_block_group(struct btrfs_block_group_cache *cache)
{
atomic_inc(&cache->count);
}
void btrfs_put_block_group(struct btrfs_block_group_cache *cache)
{
if (atomic_dec_and_test(&cache->count))
kfree(cache);
}
/* /*
* this adds the block group to the fs_info rb tree for the block group * this adds the block group to the fs_info rb tree for the block group
* cache * cache
...@@ -156,7 +167,7 @@ block_group_cache_tree_search(struct btrfs_fs_info *info, u64 bytenr, ...@@ -156,7 +167,7 @@ block_group_cache_tree_search(struct btrfs_fs_info *info, u64 bytenr,
} }
} }
if (ret) if (ret)
atomic_inc(&ret->count); btrfs_get_block_group(ret);
spin_unlock(&info->block_group_cache_lock); spin_unlock(&info->block_group_cache_lock);
return ret; return ret;
...@@ -407,6 +418,8 @@ static int caching_kthread(void *data) ...@@ -407,6 +418,8 @@ static int caching_kthread(void *data)
put_caching_control(caching_ctl); put_caching_control(caching_ctl);
atomic_dec(&block_group->space_info->caching_threads); atomic_dec(&block_group->space_info->caching_threads);
btrfs_put_block_group(block_group);
return 0; return 0;
} }
...@@ -447,6 +460,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache) ...@@ -447,6 +460,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache)
up_write(&fs_info->extent_commit_sem); up_write(&fs_info->extent_commit_sem);
atomic_inc(&cache->space_info->caching_threads); atomic_inc(&cache->space_info->caching_threads);
btrfs_get_block_group(cache);
tsk = kthread_run(caching_kthread, cache, "btrfs-cache-%llu\n", tsk = kthread_run(caching_kthread, cache, "btrfs-cache-%llu\n",
cache->key.objectid); cache->key.objectid);
...@@ -486,12 +500,6 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group( ...@@ -486,12 +500,6 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(
return cache; return cache;
} }
void btrfs_put_block_group(struct btrfs_block_group_cache *cache)
{
if (atomic_dec_and_test(&cache->count))
kfree(cache);
}
static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info, static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info,
u64 flags) u64 flags)
{ {
...@@ -2582,7 +2590,7 @@ next_block_group(struct btrfs_root *root, ...@@ -2582,7 +2590,7 @@ next_block_group(struct btrfs_root *root,
if (node) { if (node) {
cache = rb_entry(node, struct btrfs_block_group_cache, cache = rb_entry(node, struct btrfs_block_group_cache,
cache_node); cache_node);
atomic_inc(&cache->count); btrfs_get_block_group(cache);
} else } else
cache = NULL; cache = NULL;
spin_unlock(&root->fs_info->block_group_cache_lock); spin_unlock(&root->fs_info->block_group_cache_lock);
...@@ -4227,7 +4235,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, ...@@ -4227,7 +4235,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
u64 offset; u64 offset;
int cached; int cached;
atomic_inc(&block_group->count); btrfs_get_block_group(block_group);
search_start = block_group->key.objectid; search_start = block_group->key.objectid;
have_block_group: have_block_group:
...@@ -4315,7 +4323,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, ...@@ -4315,7 +4323,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
btrfs_put_block_group(block_group); btrfs_put_block_group(block_group);
block_group = last_ptr->block_group; block_group = last_ptr->block_group;
atomic_inc(&block_group->count); btrfs_get_block_group(block_group);
spin_unlock(&last_ptr->lock); spin_unlock(&last_ptr->lock);
spin_unlock(&last_ptr->refill_lock); spin_unlock(&last_ptr->refill_lock);
...@@ -7395,9 +7403,7 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) ...@@ -7395,9 +7403,7 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
wait_block_group_cache_done(block_group); wait_block_group_cache_done(block_group);
btrfs_remove_free_space_cache(block_group); btrfs_remove_free_space_cache(block_group);
btrfs_put_block_group(block_group);
WARN_ON(atomic_read(&block_group->count) != 1);
kfree(block_group);
spin_lock(&info->block_group_cache_lock); spin_lock(&info->block_group_cache_lock);
} }
......
...@@ -506,7 +506,8 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode, ...@@ -506,7 +506,8 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
} }
static int extent_mergeable(struct extent_buffer *leaf, int slot, static int extent_mergeable(struct extent_buffer *leaf, int slot,
u64 objectid, u64 bytenr, u64 *start, u64 *end) u64 objectid, u64 bytenr, u64 orig_offset,
u64 *start, u64 *end)
{ {
struct btrfs_file_extent_item *fi; struct btrfs_file_extent_item *fi;
struct btrfs_key key; struct btrfs_key key;
...@@ -522,6 +523,7 @@ static int extent_mergeable(struct extent_buffer *leaf, int slot, ...@@ -522,6 +523,7 @@ static int extent_mergeable(struct extent_buffer *leaf, int slot,
fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
if (btrfs_file_extent_type(leaf, fi) != BTRFS_FILE_EXTENT_REG || if (btrfs_file_extent_type(leaf, fi) != BTRFS_FILE_EXTENT_REG ||
btrfs_file_extent_disk_bytenr(leaf, fi) != bytenr || btrfs_file_extent_disk_bytenr(leaf, fi) != bytenr ||
btrfs_file_extent_offset(leaf, fi) != key.offset - orig_offset ||
btrfs_file_extent_compression(leaf, fi) || btrfs_file_extent_compression(leaf, fi) ||
btrfs_file_extent_encryption(leaf, fi) || btrfs_file_extent_encryption(leaf, fi) ||
btrfs_file_extent_other_encoding(leaf, fi)) btrfs_file_extent_other_encoding(leaf, fi))
...@@ -561,6 +563,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -561,6 +563,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
u64 split; u64 split;
int del_nr = 0; int del_nr = 0;
int del_slot = 0; int del_slot = 0;
int recow;
int ret; int ret;
btrfs_drop_extent_cache(inode, start, end - 1, 0); btrfs_drop_extent_cache(inode, start, end - 1, 0);
...@@ -568,6 +571,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -568,6 +571,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
path = btrfs_alloc_path(); path = btrfs_alloc_path();
BUG_ON(!path); BUG_ON(!path);
again: again:
recow = 0;
split = start; split = start;
key.objectid = inode->i_ino; key.objectid = inode->i_ino;
key.type = BTRFS_EXTENT_DATA_KEY; key.type = BTRFS_EXTENT_DATA_KEY;
...@@ -591,12 +595,60 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -591,12 +595,60 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi);
orig_offset = key.offset - btrfs_file_extent_offset(leaf, fi); orig_offset = key.offset - btrfs_file_extent_offset(leaf, fi);
memcpy(&new_key, &key, sizeof(new_key));
if (start == key.offset && end < extent_end) {
other_start = 0;
other_end = start;
if (extent_mergeable(leaf, path->slots[0] - 1,
inode->i_ino, bytenr, orig_offset,
&other_start, &other_end)) {
new_key.offset = end;
btrfs_set_item_key_safe(trans, root, path, &new_key);
fi = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
btrfs_set_file_extent_num_bytes(leaf, fi,
extent_end - end);
btrfs_set_file_extent_offset(leaf, fi,
end - orig_offset);
fi = btrfs_item_ptr(leaf, path->slots[0] - 1,
struct btrfs_file_extent_item);
btrfs_set_file_extent_num_bytes(leaf, fi,
end - other_start);
btrfs_mark_buffer_dirty(leaf);
goto out;
}
}
if (start > key.offset && end == extent_end) {
other_start = end;
other_end = 0;
if (extent_mergeable(leaf, path->slots[0] + 1,
inode->i_ino, bytenr, orig_offset,
&other_start, &other_end)) {
fi = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
btrfs_set_file_extent_num_bytes(leaf, fi,
start - key.offset);
path->slots[0]++;
new_key.offset = start;
btrfs_set_item_key_safe(trans, root, path, &new_key);
fi = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
btrfs_set_file_extent_num_bytes(leaf, fi,
other_end - start);
btrfs_set_file_extent_offset(leaf, fi,
start - orig_offset);
btrfs_mark_buffer_dirty(leaf);
goto out;
}
}
while (start > key.offset || end < extent_end) { while (start > key.offset || end < extent_end) {
if (key.offset == start) if (key.offset == start)
split = end; split = end;
memcpy(&new_key, &key, sizeof(new_key));
new_key.offset = split; new_key.offset = split;
ret = btrfs_duplicate_item(trans, root, path, &new_key); ret = btrfs_duplicate_item(trans, root, path, &new_key);
if (ret == -EAGAIN) { if (ret == -EAGAIN) {
...@@ -631,15 +683,18 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -631,15 +683,18 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
path->slots[0]--; path->slots[0]--;
extent_end = end; extent_end = end;
} }
recow = 1;
} }
fi = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
other_start = end; other_start = end;
other_end = 0; other_end = 0;
if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino, if (extent_mergeable(leaf, path->slots[0] + 1,
bytenr, &other_start, &other_end)) { inode->i_ino, bytenr, orig_offset,
&other_start, &other_end)) {
if (recow) {
btrfs_release_path(root, path);
goto again;
}
extent_end = other_end; extent_end = other_end;
del_slot = path->slots[0] + 1; del_slot = path->slots[0] + 1;
del_nr++; del_nr++;
...@@ -650,8 +705,13 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -650,8 +705,13 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
} }
other_start = 0; other_start = 0;
other_end = start; other_end = start;
if (extent_mergeable(leaf, path->slots[0] - 1, inode->i_ino, if (extent_mergeable(leaf, path->slots[0] - 1,
bytenr, &other_start, &other_end)) { inode->i_ino, bytenr, orig_offset,
&other_start, &other_end)) {
if (recow) {
btrfs_release_path(root, path);
goto again;
}
key.offset = other_start; key.offset = other_start;
del_slot = path->slots[0]; del_slot = path->slots[0];
del_nr++; del_nr++;
...@@ -660,22 +720,22 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -660,22 +720,22 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
inode->i_ino, orig_offset); inode->i_ino, orig_offset);
BUG_ON(ret); BUG_ON(ret);
} }
fi = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
if (del_nr == 0) { if (del_nr == 0) {
btrfs_set_file_extent_type(leaf, fi, btrfs_set_file_extent_type(leaf, fi,
BTRFS_FILE_EXTENT_REG); BTRFS_FILE_EXTENT_REG);
btrfs_mark_buffer_dirty(leaf); btrfs_mark_buffer_dirty(leaf);
goto out; } else {
} btrfs_set_file_extent_type(leaf, fi,
BTRFS_FILE_EXTENT_REG);
fi = btrfs_item_ptr(leaf, del_slot - 1, btrfs_set_file_extent_num_bytes(leaf, fi,
struct btrfs_file_extent_item); extent_end - key.offset);
btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG); btrfs_mark_buffer_dirty(leaf);
btrfs_set_file_extent_num_bytes(leaf, fi,
extent_end - key.offset);
btrfs_mark_buffer_dirty(leaf);
ret = btrfs_del_items(trans, root, path, del_slot, del_nr); ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
BUG_ON(ret); BUG_ON(ret);
}
out: out:
btrfs_free_path(path); btrfs_free_path(path);
return 0; return 0;
......
...@@ -3796,6 +3796,12 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) ...@@ -3796,6 +3796,12 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
if (location.type == BTRFS_INODE_ITEM_KEY) { if (location.type == BTRFS_INODE_ITEM_KEY) {
inode = btrfs_iget(dir->i_sb, &location, root); inode = btrfs_iget(dir->i_sb, &location, root);
if (unlikely(root->clean_orphans) &&
!(inode->i_sb->s_flags & MS_RDONLY)) {
down_read(&root->fs_info->cleanup_work_sem);
btrfs_orphan_cleanup(root);
up_read(&root->fs_info->cleanup_work_sem);
}
return inode; return inode;
} }
...@@ -3995,7 +4001,11 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, ...@@ -3995,7 +4001,11 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
/* Reached end of directory/root. Bump pos past the last item. */ /* Reached end of directory/root. Bump pos past the last item. */
if (key_type == BTRFS_DIR_INDEX_KEY) if (key_type == BTRFS_DIR_INDEX_KEY)
filp->f_pos = INT_LIMIT(off_t); /*
* 32-bit glibc will use getdents64, but then strtol -
* so the last number we can serve is this.
*/
filp->f_pos = 0x7fffffff;
else else
filp->f_pos++; filp->f_pos++;
nopos: nopos:
......
...@@ -626,6 +626,8 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset, ...@@ -626,6 +626,8 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
if (ordered) if (ordered)
offset = entry_end(ordered); offset = entry_end(ordered);
else
offset = ALIGN(offset, BTRFS_I(inode)->root->sectorsize);
mutex_lock(&tree->mutex); mutex_lock(&tree->mutex);
disk_i_size = BTRFS_I(inode)->disk_i_size; disk_i_size = BTRFS_I(inode)->disk_i_size;
......
...@@ -3281,8 +3281,10 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc) ...@@ -3281,8 +3281,10 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
return -ENOMEM; return -ENOMEM;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) if (!path) {
kfree(cluster);
return -ENOMEM; return -ENOMEM;
}
rc->extents_found = 0; rc->extents_found = 0;
rc->extents_skipped = 0; rc->extents_skipped = 0;
......
...@@ -2649,8 +2649,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -2649,8 +2649,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
em = lookup_extent_mapping(em_tree, logical, *length); em = lookup_extent_mapping(em_tree, logical, *length);
read_unlock(&em_tree->lock); read_unlock(&em_tree->lock);
if (!em && unplug_page) if (!em && unplug_page) {
kfree(multi);
return 0; return 0;
}
if (!em) { if (!em) {
printk(KERN_CRIT "unable to find logical %llu len %llu\n", printk(KERN_CRIT "unable to find logical %llu len %llu\n",
......
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