Commit 0efe5e32 authored by Linus Torvalds's avatar Linus Torvalds

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

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable:
  Btrfs: fix data space leak fix
  Btrfs: remove duplicates of filemap_ helpers
  Btrfs: take i_mutex before generic_write_checks
  Btrfs: fix arguments to btrfs_wait_on_page_writeback_range
  Btrfs: fix deadlock with free space handling and user transactions
  Btrfs: fix error cases for ioctl transactions
  Btrfs: Use CONFIG_BTRFS_POSIX_ACL to enable ACL code
  Btrfs: introduce missing kfree
  Btrfs: Fix setting umask when POSIX ACLs are not enabled
  Btrfs: proper -ENOSPC handling
parents e6a0a8bf 9c2693c9
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include "btrfs_inode.h" #include "btrfs_inode.h"
#include "xattr.h" #include "xattr.h"
#ifdef CONFIG_FS_POSIX_ACL #ifdef CONFIG_BTRFS_POSIX_ACL
static struct posix_acl *btrfs_get_acl(struct inode *inode, int type) static struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
{ {
...@@ -313,7 +313,7 @@ struct xattr_handler btrfs_xattr_acl_access_handler = { ...@@ -313,7 +313,7 @@ struct xattr_handler btrfs_xattr_acl_access_handler = {
.set = btrfs_xattr_acl_access_set, .set = btrfs_xattr_acl_access_set,
}; };
#else /* CONFIG_FS_POSIX_ACL */ #else /* CONFIG_BTRFS_POSIX_ACL */
int btrfs_acl_chmod(struct inode *inode) int btrfs_acl_chmod(struct inode *inode)
{ {
...@@ -325,4 +325,4 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir) ...@@ -325,4 +325,4 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir)
return 0; return 0;
} }
#endif /* CONFIG_FS_POSIX_ACL */ #endif /* CONFIG_BTRFS_POSIX_ACL */
...@@ -127,6 +127,14 @@ struct btrfs_inode { ...@@ -127,6 +127,14 @@ struct btrfs_inode {
*/ */
u64 last_unlink_trans; u64 last_unlink_trans;
/*
* These two counters are for delalloc metadata reservations. We keep
* track of how many extents we've accounted for vs how many extents we
* have.
*/
int delalloc_reserved_extents;
int delalloc_extents;
/* /*
* ordered_data_close is set by truncate when a file that used * ordered_data_close is set by truncate when a file that used
* to have good data has been truncated to zero. When it is set * to have good data has been truncated to zero. When it is set
......
...@@ -675,18 +675,19 @@ struct btrfs_space_info { ...@@ -675,18 +675,19 @@ struct btrfs_space_info {
current allocations */ current allocations */
u64 bytes_readonly; /* total bytes that are read only */ u64 bytes_readonly; /* total bytes that are read only */
u64 bytes_super; /* total bytes reserved for the super blocks */ u64 bytes_super; /* total bytes reserved for the super blocks */
u64 bytes_root; /* the number of bytes needed to commit a
/* delalloc accounting */ transaction */
u64 bytes_delalloc; /* number of bytes reserved for allocation,
this space is not necessarily reserved yet
by the allocator */
u64 bytes_may_use; /* number of bytes that may be used for u64 bytes_may_use; /* number of bytes that may be used for
delalloc */ delalloc/allocations */
u64 bytes_delalloc; /* number of bytes currently reserved for
delayed allocation */
int full; /* indicates that we cannot allocate any more int full; /* indicates that we cannot allocate any more
chunks for this space */ chunks for this space */
int force_alloc; /* set if we need to force a chunk alloc for int force_alloc; /* set if we need to force a chunk alloc for
this space */ this space */
int force_delalloc; /* make people start doing filemap_flush until
we're under a threshold */
struct list_head list; struct list_head list;
...@@ -695,6 +696,9 @@ struct btrfs_space_info { ...@@ -695,6 +696,9 @@ struct btrfs_space_info {
spinlock_t lock; spinlock_t lock;
struct rw_semaphore groups_sem; struct rw_semaphore groups_sem;
atomic_t caching_threads; atomic_t caching_threads;
int allocating_chunk;
wait_queue_head_t wait;
}; };
/* /*
...@@ -2022,7 +2026,12 @@ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags); ...@@ -2022,7 +2026,12 @@ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags);
void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *ionde); void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *ionde);
void btrfs_clear_space_info_full(struct btrfs_fs_info *info); void btrfs_clear_space_info_full(struct btrfs_fs_info *info);
int btrfs_check_metadata_free_space(struct btrfs_root *root); int btrfs_reserve_metadata_space(struct btrfs_root *root, int num_items);
int btrfs_unreserve_metadata_space(struct btrfs_root *root, int num_items);
int btrfs_unreserve_metadata_for_delalloc(struct btrfs_root *root,
struct inode *inode, int num_items);
int btrfs_reserve_metadata_for_delalloc(struct btrfs_root *root,
struct inode *inode, int num_items);
int btrfs_check_data_free_space(struct btrfs_root *root, struct inode *inode, int btrfs_check_data_free_space(struct btrfs_root *root, struct inode *inode,
u64 bytes); u64 bytes);
void btrfs_free_reserved_data_space(struct btrfs_root *root, void btrfs_free_reserved_data_space(struct btrfs_root *root,
...@@ -2357,7 +2366,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options); ...@@ -2357,7 +2366,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options);
int btrfs_sync_fs(struct super_block *sb, int wait); int btrfs_sync_fs(struct super_block *sb, int wait);
/* acl.c */ /* acl.c */
#ifdef CONFIG_FS_POSIX_ACL #ifdef CONFIG_BTRFS_POSIX_ACL
int btrfs_check_acl(struct inode *inode, int mask); int btrfs_check_acl(struct inode *inode, int mask);
#else #else
#define btrfs_check_acl NULL #define btrfs_check_acl NULL
......
...@@ -822,14 +822,14 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, ...@@ -822,14 +822,14 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
int btrfs_write_tree_block(struct extent_buffer *buf) int btrfs_write_tree_block(struct extent_buffer *buf)
{ {
return btrfs_fdatawrite_range(buf->first_page->mapping, buf->start, return filemap_fdatawrite_range(buf->first_page->mapping, buf->start,
buf->start + buf->len - 1, WB_SYNC_ALL); buf->start + buf->len - 1);
} }
int btrfs_wait_tree_block_writeback(struct extent_buffer *buf) int btrfs_wait_tree_block_writeback(struct extent_buffer *buf)
{ {
return btrfs_wait_on_page_writeback_range(buf->first_page->mapping, return filemap_fdatawait_range(buf->first_page->mapping,
buf->start, buf->start + buf->len - 1); buf->start, buf->start + buf->len - 1);
} }
struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
...@@ -1630,7 +1630,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1630,7 +1630,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
fs_info->sb = sb; fs_info->sb = sb;
fs_info->max_extent = (u64)-1; fs_info->max_extent = (u64)-1;
fs_info->max_inline = 8192 * 1024; fs_info->max_inline = 8192 * 1024;
fs_info->metadata_ratio = 8; fs_info->metadata_ratio = 0;
fs_info->thread_pool_size = min_t(unsigned long, fs_info->thread_pool_size = min_t(unsigned long,
num_online_cpus() + 2, 8); num_online_cpus() + 2, 8);
......
This diff is collapsed.
...@@ -280,6 +280,14 @@ static struct extent_buffer *buffer_search(struct extent_io_tree *tree, ...@@ -280,6 +280,14 @@ static struct extent_buffer *buffer_search(struct extent_io_tree *tree,
return NULL; return NULL;
} }
static void merge_cb(struct extent_io_tree *tree, struct extent_state *new,
struct extent_state *other)
{
if (tree->ops && tree->ops->merge_extent_hook)
tree->ops->merge_extent_hook(tree->mapping->host, new,
other);
}
/* /*
* utility function to look for merge candidates inside a given range. * utility function to look for merge candidates inside a given range.
* Any extents with matching state are merged together into a single * Any extents with matching state are merged together into a single
...@@ -303,6 +311,7 @@ static int merge_state(struct extent_io_tree *tree, ...@@ -303,6 +311,7 @@ static int merge_state(struct extent_io_tree *tree,
other = rb_entry(other_node, struct extent_state, rb_node); other = rb_entry(other_node, struct extent_state, rb_node);
if (other->end == state->start - 1 && if (other->end == state->start - 1 &&
other->state == state->state) { other->state == state->state) {
merge_cb(tree, state, other);
state->start = other->start; state->start = other->start;
other->tree = NULL; other->tree = NULL;
rb_erase(&other->rb_node, &tree->state); rb_erase(&other->rb_node, &tree->state);
...@@ -314,33 +323,37 @@ static int merge_state(struct extent_io_tree *tree, ...@@ -314,33 +323,37 @@ static int merge_state(struct extent_io_tree *tree,
other = rb_entry(other_node, struct extent_state, rb_node); other = rb_entry(other_node, struct extent_state, rb_node);
if (other->start == state->end + 1 && if (other->start == state->end + 1 &&
other->state == state->state) { other->state == state->state) {
merge_cb(tree, state, other);
other->start = state->start; other->start = state->start;
state->tree = NULL; state->tree = NULL;
rb_erase(&state->rb_node, &tree->state); rb_erase(&state->rb_node, &tree->state);
free_extent_state(state); free_extent_state(state);
state = NULL;
} }
} }
return 0; return 0;
} }
static void set_state_cb(struct extent_io_tree *tree, static int set_state_cb(struct extent_io_tree *tree,
struct extent_state *state, struct extent_state *state,
unsigned long bits) unsigned long bits)
{ {
if (tree->ops && tree->ops->set_bit_hook) { if (tree->ops && tree->ops->set_bit_hook) {
tree->ops->set_bit_hook(tree->mapping->host, state->start, return tree->ops->set_bit_hook(tree->mapping->host,
state->end, state->state, bits); state->start, state->end,
state->state, bits);
} }
return 0;
} }
static void clear_state_cb(struct extent_io_tree *tree, static void clear_state_cb(struct extent_io_tree *tree,
struct extent_state *state, struct extent_state *state,
unsigned long bits) unsigned long bits)
{ {
if (tree->ops && tree->ops->clear_bit_hook) { if (tree->ops && tree->ops->clear_bit_hook)
tree->ops->clear_bit_hook(tree->mapping->host, state->start, tree->ops->clear_bit_hook(tree->mapping->host, state, bits);
state->end, state->state, bits);
}
} }
/* /*
...@@ -358,6 +371,7 @@ static int insert_state(struct extent_io_tree *tree, ...@@ -358,6 +371,7 @@ static int insert_state(struct extent_io_tree *tree,
int bits) int bits)
{ {
struct rb_node *node; struct rb_node *node;
int ret;
if (end < start) { if (end < start) {
printk(KERN_ERR "btrfs end < start %llu %llu\n", printk(KERN_ERR "btrfs end < start %llu %llu\n",
...@@ -365,11 +379,14 @@ static int insert_state(struct extent_io_tree *tree, ...@@ -365,11 +379,14 @@ static int insert_state(struct extent_io_tree *tree,
(unsigned long long)start); (unsigned long long)start);
WARN_ON(1); WARN_ON(1);
} }
if (bits & EXTENT_DIRTY)
tree->dirty_bytes += end - start + 1;
state->start = start; state->start = start;
state->end = end; state->end = end;
set_state_cb(tree, state, bits); ret = set_state_cb(tree, state, bits);
if (ret)
return ret;
if (bits & EXTENT_DIRTY)
tree->dirty_bytes += end - start + 1;
state->state |= bits; state->state |= bits;
node = tree_insert(&tree->state, end, &state->rb_node); node = tree_insert(&tree->state, end, &state->rb_node);
if (node) { if (node) {
...@@ -387,6 +404,15 @@ static int insert_state(struct extent_io_tree *tree, ...@@ -387,6 +404,15 @@ static int insert_state(struct extent_io_tree *tree,
return 0; return 0;
} }
static int split_cb(struct extent_io_tree *tree, struct extent_state *orig,
u64 split)
{
if (tree->ops && tree->ops->split_extent_hook)
return tree->ops->split_extent_hook(tree->mapping->host,
orig, split);
return 0;
}
/* /*
* split a given extent state struct in two, inserting the preallocated * split a given extent state struct in two, inserting the preallocated
* struct 'prealloc' as the newly created second half. 'split' indicates an * struct 'prealloc' as the newly created second half. 'split' indicates an
...@@ -405,6 +431,9 @@ static int split_state(struct extent_io_tree *tree, struct extent_state *orig, ...@@ -405,6 +431,9 @@ static int split_state(struct extent_io_tree *tree, struct extent_state *orig,
struct extent_state *prealloc, u64 split) struct extent_state *prealloc, u64 split)
{ {
struct rb_node *node; struct rb_node *node;
split_cb(tree, orig, split);
prealloc->start = orig->start; prealloc->start = orig->start;
prealloc->end = split - 1; prealloc->end = split - 1;
prealloc->state = orig->state; prealloc->state = orig->state;
...@@ -542,8 +571,8 @@ hit_next: ...@@ -542,8 +571,8 @@ hit_next:
if (err) if (err)
goto out; goto out;
if (state->end <= end) { if (state->end <= end) {
set |= clear_state_bit(tree, state, bits, set |= clear_state_bit(tree, state, bits, wake,
wake, delete); delete);
if (last_end == (u64)-1) if (last_end == (u64)-1)
goto out; goto out;
start = last_end + 1; start = last_end + 1;
...@@ -561,12 +590,11 @@ hit_next: ...@@ -561,12 +590,11 @@ hit_next:
prealloc = alloc_extent_state(GFP_ATOMIC); prealloc = alloc_extent_state(GFP_ATOMIC);
err = split_state(tree, state, prealloc, end + 1); err = split_state(tree, state, prealloc, end + 1);
BUG_ON(err == -EEXIST); BUG_ON(err == -EEXIST);
if (wake) if (wake)
wake_up(&state->wq); wake_up(&state->wq);
set |= clear_state_bit(tree, prealloc, bits, set |= clear_state_bit(tree, prealloc, bits, wake, delete);
wake, delete);
prealloc = NULL; prealloc = NULL;
goto out; goto out;
} }
...@@ -667,16 +695,23 @@ out: ...@@ -667,16 +695,23 @@ out:
return 0; return 0;
} }
static void set_state_bits(struct extent_io_tree *tree, static int set_state_bits(struct extent_io_tree *tree,
struct extent_state *state, struct extent_state *state,
int bits) int bits)
{ {
int ret;
ret = set_state_cb(tree, state, bits);
if (ret)
return ret;
if ((bits & EXTENT_DIRTY) && !(state->state & EXTENT_DIRTY)) { if ((bits & EXTENT_DIRTY) && !(state->state & EXTENT_DIRTY)) {
u64 range = state->end - state->start + 1; u64 range = state->end - state->start + 1;
tree->dirty_bytes += range; tree->dirty_bytes += range;
} }
set_state_cb(tree, state, bits);
state->state |= bits; state->state |= bits;
return 0;
} }
static void cache_state(struct extent_state *state, static void cache_state(struct extent_state *state,
...@@ -758,7 +793,10 @@ hit_next: ...@@ -758,7 +793,10 @@ hit_next:
goto out; goto out;
} }
set_state_bits(tree, state, bits); err = set_state_bits(tree, state, bits);
if (err)
goto out;
cache_state(state, cached_state); cache_state(state, cached_state);
merge_state(tree, state); merge_state(tree, state);
if (last_end == (u64)-1) if (last_end == (u64)-1)
...@@ -805,7 +843,9 @@ hit_next: ...@@ -805,7 +843,9 @@ hit_next:
if (err) if (err)
goto out; goto out;
if (state->end <= end) { if (state->end <= end) {
set_state_bits(tree, state, bits); err = set_state_bits(tree, state, bits);
if (err)
goto out;
cache_state(state, cached_state); cache_state(state, cached_state);
merge_state(tree, state); merge_state(tree, state);
if (last_end == (u64)-1) if (last_end == (u64)-1)
...@@ -829,11 +869,13 @@ hit_next: ...@@ -829,11 +869,13 @@ hit_next:
this_end = last_start - 1; this_end = last_start - 1;
err = insert_state(tree, prealloc, start, this_end, err = insert_state(tree, prealloc, start, this_end,
bits); bits);
cache_state(prealloc, cached_state);
prealloc = NULL;
BUG_ON(err == -EEXIST); BUG_ON(err == -EEXIST);
if (err) if (err) {
prealloc = NULL;
goto out; goto out;
}
cache_state(prealloc, cached_state);
prealloc = NULL;
start = this_end + 1; start = this_end + 1;
goto search_again; goto search_again;
} }
...@@ -852,7 +894,11 @@ hit_next: ...@@ -852,7 +894,11 @@ hit_next:
err = split_state(tree, state, prealloc, end + 1); err = split_state(tree, state, prealloc, end + 1);
BUG_ON(err == -EEXIST); BUG_ON(err == -EEXIST);
set_state_bits(tree, prealloc, bits); err = set_state_bits(tree, prealloc, bits);
if (err) {
prealloc = NULL;
goto out;
}
cache_state(prealloc, cached_state); cache_state(prealloc, cached_state);
merge_state(tree, prealloc); merge_state(tree, prealloc);
prealloc = NULL; prealloc = NULL;
......
...@@ -60,8 +60,13 @@ struct extent_io_ops { ...@@ -60,8 +60,13 @@ struct extent_io_ops {
struct extent_state *state, int uptodate); struct extent_state *state, int uptodate);
int (*set_bit_hook)(struct inode *inode, u64 start, u64 end, int (*set_bit_hook)(struct inode *inode, u64 start, u64 end,
unsigned long old, unsigned long bits); unsigned long old, unsigned long bits);
int (*clear_bit_hook)(struct inode *inode, u64 start, u64 end, int (*clear_bit_hook)(struct inode *inode, struct extent_state *state,
unsigned long old, unsigned long bits); unsigned long bits);
int (*merge_extent_hook)(struct inode *inode,
struct extent_state *new,
struct extent_state *other);
int (*split_extent_hook)(struct inode *inode,
struct extent_state *orig, u64 split);
int (*write_cache_pages_lock_hook)(struct page *page); int (*write_cache_pages_lock_hook)(struct page *page);
}; };
...@@ -79,10 +84,14 @@ struct extent_state { ...@@ -79,10 +84,14 @@ struct extent_state {
u64 start; u64 start;
u64 end; /* inclusive */ u64 end; /* inclusive */
struct rb_node rb_node; struct rb_node rb_node;
/* ADD NEW ELEMENTS AFTER THIS */
struct extent_io_tree *tree; struct extent_io_tree *tree;
wait_queue_head_t wq; wait_queue_head_t wq;
atomic_t refs; atomic_t refs;
unsigned long state; unsigned long state;
u64 split_start;
u64 split_end;
/* for use by the FS */ /* for use by the FS */
u64 private; u64 private;
......
...@@ -123,7 +123,10 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -123,7 +123,10 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans,
root->sectorsize - 1) & ~((u64)root->sectorsize - 1); root->sectorsize - 1) & ~((u64)root->sectorsize - 1);
end_of_last_block = start_pos + num_bytes - 1; end_of_last_block = start_pos + num_bytes - 1;
btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block); err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block);
if (err)
return err;
for (i = 0; i < num_pages; i++) { for (i = 0; i < num_pages; i++) {
struct page *p = pages[i]; struct page *p = pages[i];
SetPageUptodate(p); SetPageUptodate(p);
...@@ -917,21 +920,35 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, ...@@ -917,21 +920,35 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
start_pos = pos; start_pos = pos;
vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
/* do the reserve before the mutex lock in case we have to do some
* flushing. We wouldn't deadlock, but this is more polite.
*/
err = btrfs_reserve_metadata_for_delalloc(root, inode, 1);
if (err)
goto out_nolock;
mutex_lock(&inode->i_mutex);
current->backing_dev_info = inode->i_mapping->backing_dev_info; current->backing_dev_info = inode->i_mapping->backing_dev_info;
err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode));
if (err) if (err)
goto out_nolock; goto out;
if (count == 0) if (count == 0)
goto out_nolock; goto out;
err = file_remove_suid(file); err = file_remove_suid(file);
if (err) if (err)
goto out_nolock; goto out;
file_update_time(file); file_update_time(file);
pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL); pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL);
mutex_lock(&inode->i_mutex); /* generic_write_checks can change our pos */
start_pos = pos;
BTRFS_I(inode)->sequence++; BTRFS_I(inode)->sequence++;
first_index = pos >> PAGE_CACHE_SHIFT; first_index = pos >> PAGE_CACHE_SHIFT;
last_index = (pos + count) >> PAGE_CACHE_SHIFT; last_index = (pos + count) >> PAGE_CACHE_SHIFT;
...@@ -1005,9 +1022,8 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, ...@@ -1005,9 +1022,8 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
} }
if (will_write) { if (will_write) {
btrfs_fdatawrite_range(inode->i_mapping, pos, filemap_fdatawrite_range(inode->i_mapping, pos,
pos + write_bytes - 1, pos + write_bytes - 1);
WB_SYNC_ALL);
} else { } else {
balance_dirty_pages_ratelimited_nr(inode->i_mapping, balance_dirty_pages_ratelimited_nr(inode->i_mapping,
num_pages); num_pages);
...@@ -1028,6 +1044,7 @@ out: ...@@ -1028,6 +1044,7 @@ out:
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
if (ret) if (ret)
err = ret; err = ret;
btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
out_nolock: out_nolock:
kfree(pages); kfree(pages);
......
This diff is collapsed.
...@@ -239,7 +239,13 @@ static noinline int create_subvol(struct btrfs_root *root, ...@@ -239,7 +239,13 @@ static noinline int create_subvol(struct btrfs_root *root,
u64 index = 0; u64 index = 0;
unsigned long nr = 1; unsigned long nr = 1;
ret = btrfs_check_metadata_free_space(root); /*
* 1 - inode item
* 2 - refs
* 1 - root item
* 2 - dir items
*/
ret = btrfs_reserve_metadata_space(root, 6);
if (ret) if (ret)
return ret; return ret;
...@@ -340,6 +346,9 @@ fail: ...@@ -340,6 +346,9 @@ fail:
err = btrfs_commit_transaction(trans, root); err = btrfs_commit_transaction(trans, root);
if (err && !ret) if (err && !ret)
ret = err; ret = err;
btrfs_unreserve_metadata_space(root, 6);
btrfs_btree_balance_dirty(root, nr);
return ret; return ret;
} }
...@@ -355,19 +364,27 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, ...@@ -355,19 +364,27 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
if (!root->ref_cows) if (!root->ref_cows)
return -EINVAL; return -EINVAL;
ret = btrfs_check_metadata_free_space(root); /*
* 1 - inode item
* 2 - refs
* 1 - root item
* 2 - dir items
*/
ret = btrfs_reserve_metadata_space(root, 6);
if (ret) if (ret)
goto fail_unlock; goto fail_unlock;
pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS); pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS);
if (!pending_snapshot) { if (!pending_snapshot) {
ret = -ENOMEM; ret = -ENOMEM;
btrfs_unreserve_metadata_space(root, 6);
goto fail_unlock; goto fail_unlock;
} }
pending_snapshot->name = kmalloc(namelen + 1, GFP_NOFS); pending_snapshot->name = kmalloc(namelen + 1, GFP_NOFS);
if (!pending_snapshot->name) { if (!pending_snapshot->name) {
ret = -ENOMEM; ret = -ENOMEM;
kfree(pending_snapshot); kfree(pending_snapshot);
btrfs_unreserve_metadata_space(root, 6);
goto fail_unlock; goto fail_unlock;
} }
memcpy(pending_snapshot->name, name, namelen); memcpy(pending_snapshot->name, name, namelen);
...@@ -1215,15 +1232,15 @@ static long btrfs_ioctl_trans_start(struct file *file) ...@@ -1215,15 +1232,15 @@ static long btrfs_ioctl_trans_start(struct file *file)
struct inode *inode = fdentry(file)->d_inode; struct inode *inode = fdentry(file)->d_inode;
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
int ret = 0; int ret;
ret = -EPERM;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; goto out;
if (file->private_data) { ret = -EINPROGRESS;
ret = -EINPROGRESS; if (file->private_data)
goto out; goto out;
}
ret = mnt_want_write(file->f_path.mnt); ret = mnt_want_write(file->f_path.mnt);
if (ret) if (ret)
...@@ -1233,12 +1250,19 @@ static long btrfs_ioctl_trans_start(struct file *file) ...@@ -1233,12 +1250,19 @@ static long btrfs_ioctl_trans_start(struct file *file)
root->fs_info->open_ioctl_trans++; root->fs_info->open_ioctl_trans++;
mutex_unlock(&root->fs_info->trans_mutex); mutex_unlock(&root->fs_info->trans_mutex);
ret = -ENOMEM;
trans = btrfs_start_ioctl_transaction(root, 0); trans = btrfs_start_ioctl_transaction(root, 0);
if (trans) if (!trans)
file->private_data = trans; goto out_drop;
else
ret = -ENOMEM; file->private_data = trans;
/*printk(KERN_INFO "btrfs_ioctl_trans_start on %p\n", file);*/ return 0;
out_drop:
mutex_lock(&root->fs_info->trans_mutex);
root->fs_info->open_ioctl_trans--;
mutex_unlock(&root->fs_info->trans_mutex);
mnt_drop_write(file->f_path.mnt);
out: out:
return ret; return ret;
} }
...@@ -1254,24 +1278,20 @@ long btrfs_ioctl_trans_end(struct file *file) ...@@ -1254,24 +1278,20 @@ long btrfs_ioctl_trans_end(struct file *file)
struct inode *inode = fdentry(file)->d_inode; struct inode *inode = fdentry(file)->d_inode;
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
int ret = 0;
trans = file->private_data; trans = file->private_data;
if (!trans) { if (!trans)
ret = -EINVAL; return -EINVAL;
goto out;
}
btrfs_end_transaction(trans, root);
file->private_data = NULL; file->private_data = NULL;
btrfs_end_transaction(trans, root);
mutex_lock(&root->fs_info->trans_mutex); mutex_lock(&root->fs_info->trans_mutex);
root->fs_info->open_ioctl_trans--; root->fs_info->open_ioctl_trans--;
mutex_unlock(&root->fs_info->trans_mutex); mutex_unlock(&root->fs_info->trans_mutex);
mnt_drop_write(file->f_path.mnt); mnt_drop_write(file->f_path.mnt);
return 0;
out:
return ret;
} }
long btrfs_ioctl(struct file *file, unsigned int long btrfs_ioctl(struct file *file, unsigned int
......
...@@ -458,7 +458,7 @@ void btrfs_start_ordered_extent(struct inode *inode, ...@@ -458,7 +458,7 @@ void btrfs_start_ordered_extent(struct inode *inode,
* start IO on any dirty ones so the wait doesn't stall waiting * start IO on any dirty ones so the wait doesn't stall waiting
* for pdflush to find them * for pdflush to find them
*/ */
btrfs_fdatawrite_range(inode->i_mapping, start, end, WB_SYNC_ALL); filemap_fdatawrite_range(inode->i_mapping, start, end);
if (wait) { if (wait) {
wait_event(entry->wait, test_bit(BTRFS_ORDERED_COMPLETE, wait_event(entry->wait, test_bit(BTRFS_ORDERED_COMPLETE,
&entry->flags)); &entry->flags));
...@@ -488,17 +488,15 @@ again: ...@@ -488,17 +488,15 @@ again:
/* start IO across the range first to instantiate any delalloc /* start IO across the range first to instantiate any delalloc
* extents * extents
*/ */
btrfs_fdatawrite_range(inode->i_mapping, start, orig_end, WB_SYNC_ALL); filemap_fdatawrite_range(inode->i_mapping, start, orig_end);
/* The compression code will leave pages locked but return from /* The compression code will leave pages locked but return from
* writepage without setting the page writeback. Starting again * writepage without setting the page writeback. Starting again
* with WB_SYNC_ALL will end up waiting for the IO to actually start. * with WB_SYNC_ALL will end up waiting for the IO to actually start.
*/ */
btrfs_fdatawrite_range(inode->i_mapping, start, orig_end, WB_SYNC_ALL); filemap_fdatawrite_range(inode->i_mapping, start, orig_end);
btrfs_wait_on_page_writeback_range(inode->i_mapping, filemap_fdatawait_range(inode->i_mapping, start, orig_end);
start >> PAGE_CACHE_SHIFT,
orig_end >> PAGE_CACHE_SHIFT);
end = orig_end; end = orig_end;
found = 0; found = 0;
...@@ -716,89 +714,6 @@ out: ...@@ -716,89 +714,6 @@ out:
} }
/**
* taken from mm/filemap.c because it isn't exported
*
* __filemap_fdatawrite_range - start writeback on mapping dirty pages in range
* @mapping: address space structure to write
* @start: offset in bytes where the range starts
* @end: offset in bytes where the range ends (inclusive)
* @sync_mode: enable synchronous operation
*
* Start writeback against all of a mapping's dirty pages that lie
* within the byte offsets <start, end> inclusive.
*
* If sync_mode is WB_SYNC_ALL then this is a "data integrity" operation, as
* opposed to a regular memory cleansing writeback. The difference between
* these two operations is that if a dirty page/buffer is encountered, it must
* be waited upon, and not just skipped over.
*/
int btrfs_fdatawrite_range(struct address_space *mapping, loff_t start,
loff_t end, int sync_mode)
{
struct writeback_control wbc = {
.sync_mode = sync_mode,
.nr_to_write = mapping->nrpages * 2,
.range_start = start,
.range_end = end,
};
return btrfs_writepages(mapping, &wbc);
}
/**
* taken from mm/filemap.c because it isn't exported
*
* wait_on_page_writeback_range - wait for writeback to complete
* @mapping: target address_space
* @start: beginning page index
* @end: ending page index
*
* Wait for writeback to complete against pages indexed by start->end
* inclusive
*/
int btrfs_wait_on_page_writeback_range(struct address_space *mapping,
pgoff_t start, pgoff_t end)
{
struct pagevec pvec;
int nr_pages;
int ret = 0;
pgoff_t index;
if (end < start)
return 0;
pagevec_init(&pvec, 0);
index = start;
while ((index <= end) &&
(nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
PAGECACHE_TAG_WRITEBACK,
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1)) != 0) {
unsigned i;
for (i = 0; i < nr_pages; i++) {
struct page *page = pvec.pages[i];
/* until radix tree lookup accepts end_index */
if (page->index > end)
continue;
wait_on_page_writeback(page);
if (PageError(page))
ret = -EIO;
}
pagevec_release(&pvec);
cond_resched();
}
/* Check for outstanding write errors */
if (test_and_clear_bit(AS_ENOSPC, &mapping->flags))
ret = -ENOSPC;
if (test_and_clear_bit(AS_EIO, &mapping->flags))
ret = -EIO;
return ret;
}
/* /*
* add a given inode to the list of inodes that must be fully on * add a given inode to the list of inodes that must be fully on
* disk before a transaction commit finishes. * disk before a transaction commit finishes.
......
...@@ -153,10 +153,6 @@ btrfs_lookup_first_ordered_extent(struct inode * inode, u64 file_offset); ...@@ -153,10 +153,6 @@ btrfs_lookup_first_ordered_extent(struct inode * inode, u64 file_offset);
int btrfs_ordered_update_i_size(struct inode *inode, int btrfs_ordered_update_i_size(struct inode *inode,
struct btrfs_ordered_extent *ordered); struct btrfs_ordered_extent *ordered);
int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, u32 *sum); int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, u32 *sum);
int btrfs_wait_on_page_writeback_range(struct address_space *mapping,
pgoff_t start, pgoff_t end);
int btrfs_fdatawrite_range(struct address_space *mapping, loff_t start,
loff_t end, int sync_mode);
int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only); int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only);
int btrfs_run_ordered_operations(struct btrfs_root *root, int wait); int btrfs_run_ordered_operations(struct btrfs_root *root, int wait);
int btrfs_add_ordered_operation(struct btrfs_trans_handle *trans, int btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
......
...@@ -344,7 +344,9 @@ static int btrfs_fill_super(struct super_block *sb, ...@@ -344,7 +344,9 @@ static int btrfs_fill_super(struct super_block *sb,
sb->s_export_op = &btrfs_export_ops; sb->s_export_op = &btrfs_export_ops;
sb->s_xattr = btrfs_xattr_handlers; sb->s_xattr = btrfs_xattr_handlers;
sb->s_time_gran = 1; sb->s_time_gran = 1;
#ifdef CONFIG_BTRFS_POSIX_ACL
sb->s_flags |= MS_POSIXACL; sb->s_flags |= MS_POSIXACL;
#endif
tree_root = open_ctree(sb, fs_devices, (char *)data); tree_root = open_ctree(sb, fs_devices, (char *)data);
......
...@@ -186,6 +186,9 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, ...@@ -186,6 +186,9 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
h->alloc_exclude_start = 0; h->alloc_exclude_start = 0;
h->delayed_ref_updates = 0; h->delayed_ref_updates = 0;
if (!current->journal_info)
current->journal_info = h;
root->fs_info->running_transaction->use_count++; root->fs_info->running_transaction->use_count++;
record_root_in_trans(h, root); record_root_in_trans(h, root);
mutex_unlock(&root->fs_info->trans_mutex); mutex_unlock(&root->fs_info->trans_mutex);
...@@ -317,6 +320,9 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, ...@@ -317,6 +320,9 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
wake_up(&cur_trans->writer_wait); wake_up(&cur_trans->writer_wait);
put_transaction(cur_trans); put_transaction(cur_trans);
mutex_unlock(&info->trans_mutex); mutex_unlock(&info->trans_mutex);
if (current->journal_info == trans)
current->journal_info = NULL;
memset(trans, 0, sizeof(*trans)); memset(trans, 0, sizeof(*trans));
kmem_cache_free(btrfs_trans_handle_cachep, trans); kmem_cache_free(btrfs_trans_handle_cachep, trans);
...@@ -743,6 +749,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ...@@ -743,6 +749,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
memcpy(&pending->root_key, &key, sizeof(key)); memcpy(&pending->root_key, &key, sizeof(key));
fail: fail:
kfree(new_root_item); kfree(new_root_item);
btrfs_unreserve_metadata_space(root, 6);
return ret; return ret;
} }
...@@ -1059,6 +1066,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -1059,6 +1066,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
mutex_unlock(&root->fs_info->trans_mutex); mutex_unlock(&root->fs_info->trans_mutex);
if (current->journal_info == trans)
current->journal_info = NULL;
kmem_cache_free(btrfs_trans_handle_cachep, trans); kmem_cache_free(btrfs_trans_handle_cachep, trans);
return ret; return ret;
} }
......
...@@ -446,8 +446,10 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig) ...@@ -446,8 +446,10 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
goto error; goto error;
device->name = kstrdup(orig_dev->name, GFP_NOFS); device->name = kstrdup(orig_dev->name, GFP_NOFS);
if (!device->name) if (!device->name) {
kfree(device);
goto error; goto error;
}
device->devid = orig_dev->devid; device->devid = orig_dev->devid;
device->work.func = pending_bios_fn; device->work.func = pending_bios_fn;
......
...@@ -260,7 +260,7 @@ err: ...@@ -260,7 +260,7 @@ err:
* attributes are handled directly. * attributes are handled directly.
*/ */
struct xattr_handler *btrfs_xattr_handlers[] = { struct xattr_handler *btrfs_xattr_handlers[] = {
#ifdef CONFIG_FS_POSIX_ACL #ifdef CONFIG_BTRFS_POSIX_ACL
&btrfs_xattr_acl_access_handler, &btrfs_xattr_acl_access_handler,
&btrfs_xattr_acl_default_handler, &btrfs_xattr_acl_default_handler,
#endif #endif
......
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