Commit 7c508e50 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: make sure fallocate properly starts a transaction
  Btrfs: make metadata chunks smaller
  Btrfs: Show discard option in /proc/mounts
  Btrfs: deny sys_link across subvolumes.
  Btrfs: fail mount on bad mount options
  Btrfs: don't add extent 0 to the free space cache v2
  Btrfs: Fix per root used space accounting
  Btrfs: Fix btrfs_drop_extent_cache for skip pinned case
  Btrfs: Add delayed iput
  Btrfs: Pass transaction handle to security and ACL initialization functions
  Btrfs: Make truncate(2) more ENOSPC friendly
  Btrfs: Make fallocate(2) more ENOSPC friendly
  Btrfs: Avoid orphan inodes cleanup during committing transaction
  Btrfs: Avoid orphan inodes cleanup while replaying log
  Btrfs: Fix disk_i_size update corner case
  Btrfs: Rewrite btrfs_drop_extents
  Btrfs: Add btrfs_duplicate_item
  Btrfs: Avoid superfluous tree-log writeout
parents dcc7cd01 7a5d24b1
...@@ -94,7 +94,8 @@ static int btrfs_xattr_acl_get(struct dentry *dentry, const char *name, ...@@ -94,7 +94,8 @@ static int btrfs_xattr_acl_get(struct dentry *dentry, const char *name,
/* /*
* Needs to be called with fs_mutex held * Needs to be called with fs_mutex held
*/ */
static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) static int btrfs_set_acl(struct btrfs_trans_handle *trans,
struct inode *inode, struct posix_acl *acl, int type)
{ {
int ret, size = 0; int ret, size = 0;
const char *name; const char *name;
...@@ -140,8 +141,7 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) ...@@ -140,8 +141,7 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
goto out; goto out;
} }
ret = __btrfs_setxattr(inode, name, value, size, 0); ret = __btrfs_setxattr(trans, inode, name, value, size, 0);
out: out:
kfree(value); kfree(value);
...@@ -154,7 +154,7 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) ...@@ -154,7 +154,7 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name, static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags, int type) const void *value, size_t size, int flags, int type)
{ {
int ret = 0; int ret;
struct posix_acl *acl = NULL; struct posix_acl *acl = NULL;
if (value) { if (value) {
...@@ -167,7 +167,7 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name, ...@@ -167,7 +167,7 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
} }
} }
ret = btrfs_set_acl(dentry->d_inode, acl, type); ret = btrfs_set_acl(NULL, dentry->d_inode, acl, type);
posix_acl_release(acl); posix_acl_release(acl);
...@@ -196,7 +196,8 @@ int btrfs_check_acl(struct inode *inode, int mask) ...@@ -196,7 +196,8 @@ int btrfs_check_acl(struct inode *inode, int mask)
* stuff has been fixed to work with that. If the locking stuff changes, we * stuff has been fixed to work with that. If the locking stuff changes, we
* need to re-evaluate the acl locking stuff. * need to re-evaluate the acl locking stuff.
*/ */
int btrfs_init_acl(struct inode *inode, struct inode *dir) int btrfs_init_acl(struct btrfs_trans_handle *trans,
struct inode *inode, struct inode *dir)
{ {
struct posix_acl *acl = NULL; struct posix_acl *acl = NULL;
int ret = 0; int ret = 0;
...@@ -221,7 +222,8 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir) ...@@ -221,7 +222,8 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir)
mode_t mode; mode_t mode;
if (S_ISDIR(inode->i_mode)) { if (S_ISDIR(inode->i_mode)) {
ret = btrfs_set_acl(inode, acl, ACL_TYPE_DEFAULT); ret = btrfs_set_acl(trans, inode, acl,
ACL_TYPE_DEFAULT);
if (ret) if (ret)
goto failed; goto failed;
} }
...@@ -236,7 +238,7 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir) ...@@ -236,7 +238,7 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir)
inode->i_mode = mode; inode->i_mode = mode;
if (ret > 0) { if (ret > 0) {
/* we need an acl */ /* we need an acl */
ret = btrfs_set_acl(inode, clone, ret = btrfs_set_acl(trans, inode, clone,
ACL_TYPE_ACCESS); ACL_TYPE_ACCESS);
} }
} }
...@@ -269,7 +271,7 @@ int btrfs_acl_chmod(struct inode *inode) ...@@ -269,7 +271,7 @@ int btrfs_acl_chmod(struct inode *inode)
ret = posix_acl_chmod_masq(clone, inode->i_mode); ret = posix_acl_chmod_masq(clone, inode->i_mode);
if (!ret) if (!ret)
ret = btrfs_set_acl(inode, clone, ACL_TYPE_ACCESS); ret = btrfs_set_acl(NULL, inode, clone, ACL_TYPE_ACCESS);
posix_acl_release(clone); posix_acl_release(clone);
...@@ -297,7 +299,8 @@ int btrfs_acl_chmod(struct inode *inode) ...@@ -297,7 +299,8 @@ int btrfs_acl_chmod(struct inode *inode)
return 0; return 0;
} }
int btrfs_init_acl(struct inode *inode, struct inode *dir) int btrfs_init_acl(struct btrfs_trans_handle *trans,
struct inode *inode, struct inode *dir)
{ {
return 0; return 0;
} }
......
...@@ -44,9 +44,6 @@ struct btrfs_inode { ...@@ -44,9 +44,6 @@ struct btrfs_inode {
*/ */
struct extent_io_tree io_failure_tree; struct extent_io_tree io_failure_tree;
/* held while inesrting or deleting extents from files */
struct mutex extent_mutex;
/* held while logging the inode in tree-log.c */ /* held while logging the inode in tree-log.c */
struct mutex log_mutex; struct mutex log_mutex;
...@@ -166,7 +163,7 @@ static inline struct btrfs_inode *BTRFS_I(struct inode *inode) ...@@ -166,7 +163,7 @@ static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
static inline void btrfs_i_size_write(struct inode *inode, u64 size) static inline void btrfs_i_size_write(struct inode *inode, u64 size)
{ {
inode->i_size = size; i_size_write(inode, size);
BTRFS_I(inode)->disk_i_size = size; BTRFS_I(inode)->disk_i_size = size;
} }
......
This diff is collapsed.
...@@ -310,6 +310,9 @@ struct btrfs_header { ...@@ -310,6 +310,9 @@ struct btrfs_header {
#define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \ #define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \
sizeof(struct btrfs_item) - \ sizeof(struct btrfs_item) - \
sizeof(struct btrfs_file_extent_item)) sizeof(struct btrfs_file_extent_item))
#define BTRFS_MAX_XATTR_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \
sizeof(struct btrfs_item) -\
sizeof(struct btrfs_dir_item))
/* /*
...@@ -859,8 +862,9 @@ struct btrfs_fs_info { ...@@ -859,8 +862,9 @@ struct btrfs_fs_info {
struct mutex ordered_operations_mutex; struct mutex ordered_operations_mutex;
struct rw_semaphore extent_commit_sem; struct rw_semaphore extent_commit_sem;
struct rw_semaphore subvol_sem; struct rw_semaphore cleanup_work_sem;
struct rw_semaphore subvol_sem;
struct srcu_struct subvol_srcu; struct srcu_struct subvol_srcu;
struct list_head trans_list; struct list_head trans_list;
...@@ -868,6 +872,9 @@ struct btrfs_fs_info { ...@@ -868,6 +872,9 @@ struct btrfs_fs_info {
struct list_head dead_roots; struct list_head dead_roots;
struct list_head caching_block_groups; struct list_head caching_block_groups;
spinlock_t delayed_iput_lock;
struct list_head delayed_iputs;
atomic_t nr_async_submits; atomic_t nr_async_submits;
atomic_t async_submit_draining; atomic_t async_submit_draining;
atomic_t nr_async_bios; atomic_t nr_async_bios;
...@@ -1034,12 +1041,12 @@ struct btrfs_root { ...@@ -1034,12 +1041,12 @@ struct btrfs_root {
int ref_cows; int ref_cows;
int track_dirty; int track_dirty;
int in_radix; int in_radix;
int clean_orphans;
u64 defrag_trans_start; u64 defrag_trans_start;
struct btrfs_key defrag_progress; struct btrfs_key defrag_progress;
struct btrfs_key defrag_max; struct btrfs_key defrag_max;
int defrag_running; int defrag_running;
int defrag_level;
char *name; char *name;
int in_sysfs; int in_sysfs;
...@@ -1975,6 +1982,10 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, ...@@ -1975,6 +1982,10 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
u64 parent, u64 root_objectid, u64 parent, u64 root_objectid,
struct btrfs_disk_key *key, int level, struct btrfs_disk_key *key, int level,
u64 hint, u64 empty_size); u64 hint, u64 empty_size);
int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 bytenr, u32 blocksize,
u64 parent, u64 root_objectid, int level);
struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
u64 bytenr, u32 blocksize, u64 bytenr, u32 blocksize,
...@@ -2089,6 +2100,10 @@ int btrfs_split_item(struct btrfs_trans_handle *trans, ...@@ -2089,6 +2100,10 @@ int btrfs_split_item(struct btrfs_trans_handle *trans,
struct btrfs_path *path, struct btrfs_path *path,
struct btrfs_key *new_key, struct btrfs_key *new_key,
unsigned long split_offset); unsigned long split_offset);
int btrfs_duplicate_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
struct btrfs_key *new_key);
int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_key *key, struct btrfs_path *p, int *root, struct btrfs_key *key, struct btrfs_path *p, int
ins_len, int cow); ins_len, int cow);
...@@ -2196,9 +2211,10 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, ...@@ -2196,9 +2211,10 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
struct btrfs_path *path, struct btrfs_path *path,
struct btrfs_dir_item *di); struct btrfs_dir_item *di);
int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root, const char *name, struct btrfs_root *root,
u16 name_len, const void *data, u16 data_len, struct btrfs_path *path, u64 objectid,
u64 dir); const char *name, u16 name_len,
const void *data, u16 data_len);
struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct btrfs_path *path, u64 dir, struct btrfs_path *path, u64 dir,
...@@ -2292,7 +2308,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, ...@@ -2292,7 +2308,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
struct inode *inode, u64 new_size, struct inode *inode, u64 new_size,
u32 min_type); u32 min_type);
int btrfs_start_delalloc_inodes(struct btrfs_root *root); int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput);
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end); int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end);
int btrfs_writepages(struct address_space *mapping, int btrfs_writepages(struct address_space *mapping,
struct writeback_control *wbc); struct writeback_control *wbc);
...@@ -2332,6 +2348,8 @@ int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode); ...@@ -2332,6 +2348,8 @@ int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode);
void btrfs_orphan_cleanup(struct btrfs_root *root); void btrfs_orphan_cleanup(struct btrfs_root *root);
int btrfs_cont_expand(struct inode *inode, loff_t size); int btrfs_cont_expand(struct inode *inode, loff_t size);
int btrfs_invalidate_inodes(struct btrfs_root *root); int btrfs_invalidate_inodes(struct btrfs_root *root);
void btrfs_add_delayed_iput(struct inode *inode);
void btrfs_run_delayed_iputs(struct btrfs_root *root);
extern const struct dentry_operations btrfs_dentry_operations; extern const struct dentry_operations btrfs_dentry_operations;
/* ioctl.c */ /* ioctl.c */
...@@ -2345,12 +2363,9 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, ...@@ -2345,12 +2363,9 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
int skip_pinned); int skip_pinned);
int btrfs_check_file(struct btrfs_root *root, struct inode *inode); int btrfs_check_file(struct btrfs_root *root, struct inode *inode);
extern const struct file_operations btrfs_file_operations; extern const struct file_operations btrfs_file_operations;
int btrfs_drop_extents(struct btrfs_trans_handle *trans, int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
struct btrfs_root *root, struct inode *inode, u64 start, u64 end, u64 *hint_byte, int drop_cache);
u64 start, u64 end, u64 locked_end,
u64 inline_limit, u64 *hint_block, int drop_cache);
int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct inode *inode, u64 start, u64 end); struct inode *inode, u64 start, u64 end);
int btrfs_release_file(struct inode *inode, struct file *file); int btrfs_release_file(struct inode *inode, struct file *file);
...@@ -2380,7 +2395,8 @@ int btrfs_check_acl(struct inode *inode, int mask); ...@@ -2380,7 +2395,8 @@ int btrfs_check_acl(struct inode *inode, int mask);
#else #else
#define btrfs_check_acl NULL #define btrfs_check_acl NULL
#endif #endif
int btrfs_init_acl(struct inode *inode, struct inode *dir); int btrfs_init_acl(struct btrfs_trans_handle *trans,
struct inode *inode, struct inode *dir);
int btrfs_acl_chmod(struct inode *inode); int btrfs_acl_chmod(struct inode *inode);
/* relocation.c */ /* relocation.c */
......
...@@ -68,12 +68,12 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle ...@@ -68,12 +68,12 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
* into the tree * into the tree
*/ */
int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root, const char *name, struct btrfs_root *root,
u16 name_len, const void *data, u16 data_len, struct btrfs_path *path, u64 objectid,
u64 dir) const char *name, u16 name_len,
const void *data, u16 data_len)
{ {
int ret = 0; int ret = 0;
struct btrfs_path *path;
struct btrfs_dir_item *dir_item; struct btrfs_dir_item *dir_item;
unsigned long name_ptr, data_ptr; unsigned long name_ptr, data_ptr;
struct btrfs_key key, location; struct btrfs_key key, location;
...@@ -81,15 +81,11 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, ...@@ -81,15 +81,11 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
struct extent_buffer *leaf; struct extent_buffer *leaf;
u32 data_size; u32 data_size;
key.objectid = dir; BUG_ON(name_len + data_len > BTRFS_MAX_XATTR_SIZE(root));
key.objectid = objectid;
btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
key.offset = btrfs_name_hash(name, name_len); key.offset = btrfs_name_hash(name, name_len);
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
if (name_len + data_len + sizeof(struct btrfs_dir_item) >
BTRFS_LEAF_DATA_SIZE(root) - sizeof(struct btrfs_item))
return -ENOSPC;
data_size = sizeof(*dir_item) + name_len + data_len; data_size = sizeof(*dir_item) + name_len + data_len;
dir_item = insert_with_overflow(trans, root, path, &key, data_size, dir_item = insert_with_overflow(trans, root, path, &key, data_size,
...@@ -117,7 +113,6 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, ...@@ -117,7 +113,6 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
write_extent_buffer(leaf, data, data_ptr, data_len); write_extent_buffer(leaf, data, data_ptr, data_len);
btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_mark_buffer_dirty(path->nodes[0]);
btrfs_free_path(path);
return ret; return ret;
} }
......
...@@ -892,6 +892,8 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, ...@@ -892,6 +892,8 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
root->stripesize = stripesize; root->stripesize = stripesize;
root->ref_cows = 0; root->ref_cows = 0;
root->track_dirty = 0; root->track_dirty = 0;
root->in_radix = 0;
root->clean_orphans = 0;
root->fs_info = fs_info; root->fs_info = fs_info;
root->objectid = objectid; root->objectid = objectid;
...@@ -928,7 +930,6 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, ...@@ -928,7 +930,6 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
root->defrag_trans_start = fs_info->generation; root->defrag_trans_start = fs_info->generation;
init_completion(&root->kobj_unregister); init_completion(&root->kobj_unregister);
root->defrag_running = 0; root->defrag_running = 0;
root->defrag_level = 0;
root->root_key.objectid = objectid; root->root_key.objectid = objectid;
root->anon_super.s_root = NULL; root->anon_super.s_root = NULL;
root->anon_super.s_dev = 0; root->anon_super.s_dev = 0;
...@@ -980,12 +981,12 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans, ...@@ -980,12 +981,12 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
while (1) { while (1) {
ret = find_first_extent_bit(&log_root_tree->dirty_log_pages, ret = find_first_extent_bit(&log_root_tree->dirty_log_pages,
0, &start, &end, EXTENT_DIRTY); 0, &start, &end, EXTENT_DIRTY | EXTENT_NEW);
if (ret) if (ret)
break; break;
clear_extent_dirty(&log_root_tree->dirty_log_pages, clear_extent_bits(&log_root_tree->dirty_log_pages, start, end,
start, end, GFP_NOFS); EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS);
} }
eb = fs_info->log_root_tree->node; eb = fs_info->log_root_tree->node;
...@@ -1210,8 +1211,10 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, ...@@ -1210,8 +1211,10 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
ret = radix_tree_insert(&fs_info->fs_roots_radix, ret = radix_tree_insert(&fs_info->fs_roots_radix,
(unsigned long)root->root_key.objectid, (unsigned long)root->root_key.objectid,
root); root);
if (ret == 0) if (ret == 0) {
root->in_radix = 1; root->in_radix = 1;
root->clean_orphans = 1;
}
spin_unlock(&fs_info->fs_roots_radix_lock); spin_unlock(&fs_info->fs_roots_radix_lock);
radix_tree_preload_end(); radix_tree_preload_end();
if (ret) { if (ret) {
...@@ -1225,10 +1228,6 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, ...@@ -1225,10 +1228,6 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
ret = btrfs_find_dead_roots(fs_info->tree_root, ret = btrfs_find_dead_roots(fs_info->tree_root,
root->root_key.objectid); root->root_key.objectid);
WARN_ON(ret); WARN_ON(ret);
if (!(fs_info->sb->s_flags & MS_RDONLY))
btrfs_orphan_cleanup(root);
return root; return root;
fail: fail:
free_fs_root(root); free_fs_root(root);
...@@ -1477,6 +1476,7 @@ static int cleaner_kthread(void *arg) ...@@ -1477,6 +1476,7 @@ static int cleaner_kthread(void *arg)
if (!(root->fs_info->sb->s_flags & MS_RDONLY) && if (!(root->fs_info->sb->s_flags & MS_RDONLY) &&
mutex_trylock(&root->fs_info->cleaner_mutex)) { mutex_trylock(&root->fs_info->cleaner_mutex)) {
btrfs_run_delayed_iputs(root);
btrfs_clean_old_snapshots(root); btrfs_clean_old_snapshots(root);
mutex_unlock(&root->fs_info->cleaner_mutex); mutex_unlock(&root->fs_info->cleaner_mutex);
} }
...@@ -1606,6 +1606,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1606,6 +1606,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC); INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
INIT_LIST_HEAD(&fs_info->trans_list); INIT_LIST_HEAD(&fs_info->trans_list);
INIT_LIST_HEAD(&fs_info->dead_roots); INIT_LIST_HEAD(&fs_info->dead_roots);
INIT_LIST_HEAD(&fs_info->delayed_iputs);
INIT_LIST_HEAD(&fs_info->hashers); INIT_LIST_HEAD(&fs_info->hashers);
INIT_LIST_HEAD(&fs_info->delalloc_inodes); INIT_LIST_HEAD(&fs_info->delalloc_inodes);
INIT_LIST_HEAD(&fs_info->ordered_operations); INIT_LIST_HEAD(&fs_info->ordered_operations);
...@@ -1614,6 +1615,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1614,6 +1615,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
spin_lock_init(&fs_info->new_trans_lock); spin_lock_init(&fs_info->new_trans_lock);
spin_lock_init(&fs_info->ref_cache_lock); spin_lock_init(&fs_info->ref_cache_lock);
spin_lock_init(&fs_info->fs_roots_radix_lock); spin_lock_init(&fs_info->fs_roots_radix_lock);
spin_lock_init(&fs_info->delayed_iput_lock);
init_completion(&fs_info->kobj_unregister); init_completion(&fs_info->kobj_unregister);
fs_info->tree_root = tree_root; fs_info->tree_root = tree_root;
...@@ -1689,6 +1691,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1689,6 +1691,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
mutex_init(&fs_info->cleaner_mutex); mutex_init(&fs_info->cleaner_mutex);
mutex_init(&fs_info->volume_mutex); mutex_init(&fs_info->volume_mutex);
init_rwsem(&fs_info->extent_commit_sem); init_rwsem(&fs_info->extent_commit_sem);
init_rwsem(&fs_info->cleanup_work_sem);
init_rwsem(&fs_info->subvol_sem); init_rwsem(&fs_info->subvol_sem);
btrfs_init_free_cluster(&fs_info->meta_alloc_cluster); btrfs_init_free_cluster(&fs_info->meta_alloc_cluster);
...@@ -2386,8 +2389,14 @@ int btrfs_commit_super(struct btrfs_root *root) ...@@ -2386,8 +2389,14 @@ int btrfs_commit_super(struct btrfs_root *root)
int ret; int ret;
mutex_lock(&root->fs_info->cleaner_mutex); mutex_lock(&root->fs_info->cleaner_mutex);
btrfs_run_delayed_iputs(root);
btrfs_clean_old_snapshots(root); btrfs_clean_old_snapshots(root);
mutex_unlock(&root->fs_info->cleaner_mutex); mutex_unlock(&root->fs_info->cleaner_mutex);
/* wait until ongoing cleanup work done */
down_write(&root->fs_info->cleanup_work_sem);
up_write(&root->fs_info->cleanup_work_sem);
trans = btrfs_start_transaction(root, 1); trans = btrfs_start_transaction(root, 1);
ret = btrfs_commit_transaction(trans, root); ret = btrfs_commit_transaction(trans, root);
BUG_ON(ret); BUG_ON(ret);
......
...@@ -195,6 +195,14 @@ static int exclude_super_stripes(struct btrfs_root *root, ...@@ -195,6 +195,14 @@ static int exclude_super_stripes(struct btrfs_root *root,
int stripe_len; int stripe_len;
int i, nr, ret; int i, nr, ret;
if (cache->key.objectid < BTRFS_SUPER_INFO_OFFSET) {
stripe_len = BTRFS_SUPER_INFO_OFFSET - cache->key.objectid;
cache->bytes_super += stripe_len;
ret = add_excluded_extent(root, cache->key.objectid,
stripe_len);
BUG_ON(ret);
}
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
bytenr = btrfs_sb_offset(i); bytenr = btrfs_sb_offset(i);
ret = btrfs_rmap_block(&root->fs_info->mapping_tree, ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
...@@ -255,7 +263,7 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group, ...@@ -255,7 +263,7 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
if (ret) if (ret)
break; break;
if (extent_start == start) { if (extent_start <= start) {
start = extent_end + 1; start = extent_end + 1;
} else if (extent_start > start && extent_start < end) { } else if (extent_start > start && extent_start < end) {
size = extent_start - start; size = extent_start - start;
...@@ -2880,9 +2888,9 @@ static noinline void flush_delalloc_async(struct btrfs_work *work) ...@@ -2880,9 +2888,9 @@ static noinline void flush_delalloc_async(struct btrfs_work *work)
root = async->root; root = async->root;
info = async->info; info = async->info;
btrfs_start_delalloc_inodes(root); btrfs_start_delalloc_inodes(root, 0);
wake_up(&info->flush_wait); wake_up(&info->flush_wait);
btrfs_wait_ordered_extents(root, 0); btrfs_wait_ordered_extents(root, 0, 0);
spin_lock(&info->lock); spin_lock(&info->lock);
info->flushing = 0; info->flushing = 0;
...@@ -2956,8 +2964,8 @@ static void flush_delalloc(struct btrfs_root *root, ...@@ -2956,8 +2964,8 @@ static void flush_delalloc(struct btrfs_root *root,
return; return;
flush: flush:
btrfs_start_delalloc_inodes(root); btrfs_start_delalloc_inodes(root, 0);
btrfs_wait_ordered_extents(root, 0); btrfs_wait_ordered_extents(root, 0, 0);
spin_lock(&info->lock); spin_lock(&info->lock);
info->flushing = 0; info->flushing = 0;
...@@ -3454,14 +3462,6 @@ static int update_block_group(struct btrfs_trans_handle *trans, ...@@ -3454,14 +3462,6 @@ static int update_block_group(struct btrfs_trans_handle *trans,
else else
old_val -= num_bytes; old_val -= num_bytes;
btrfs_set_super_bytes_used(&info->super_copy, old_val); btrfs_set_super_bytes_used(&info->super_copy, old_val);
/* block accounting for root item */
old_val = btrfs_root_used(&root->root_item);
if (alloc)
old_val += num_bytes;
else
old_val -= num_bytes;
btrfs_set_root_used(&root->root_item, old_val);
spin_unlock(&info->delalloc_lock); spin_unlock(&info->delalloc_lock);
while (total) { while (total) {
...@@ -4049,6 +4049,21 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, ...@@ -4049,6 +4049,21 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans,
return ret; return ret;
} }
int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 bytenr, u32 blocksize,
u64 parent, u64 root_objectid, int level)
{
u64 used;
spin_lock(&root->node_lock);
used = btrfs_root_used(&root->root_item) - blocksize;
btrfs_set_root_used(&root->root_item, used);
spin_unlock(&root->node_lock);
return btrfs_free_extent(trans, root, bytenr, blocksize,
parent, root_objectid, level, 0);
}
static u64 stripe_align(struct btrfs_root *root, u64 val) static u64 stripe_align(struct btrfs_root *root, u64 val)
{ {
u64 mask = ((u64)root->stripesize - 1); u64 mask = ((u64)root->stripesize - 1);
...@@ -4578,7 +4593,6 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans, ...@@ -4578,7 +4593,6 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
{ {
int ret; int ret;
u64 search_start = 0; u64 search_start = 0;
struct btrfs_fs_info *info = root->fs_info;
data = btrfs_get_alloc_profile(root, data); data = btrfs_get_alloc_profile(root, data);
again: again:
...@@ -4586,17 +4600,9 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans, ...@@ -4586,17 +4600,9 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
* the only place that sets empty_size is btrfs_realloc_node, which * the only place that sets empty_size is btrfs_realloc_node, which
* is not called recursively on allocations * is not called recursively on allocations
*/ */
if (empty_size || root->ref_cows) { if (empty_size || root->ref_cows)
if (!(data & BTRFS_BLOCK_GROUP_METADATA)) {
ret = do_chunk_alloc(trans, root->fs_info->extent_root,
2 * 1024 * 1024,
BTRFS_BLOCK_GROUP_METADATA |
(info->metadata_alloc_profile &
info->avail_metadata_alloc_bits), 0);
}
ret = do_chunk_alloc(trans, root->fs_info->extent_root, ret = do_chunk_alloc(trans, root->fs_info->extent_root,
num_bytes + 2 * 1024 * 1024, data, 0); num_bytes + 2 * 1024 * 1024, data, 0);
}
WARN_ON(num_bytes < root->sectorsize); WARN_ON(num_bytes < root->sectorsize);
ret = find_free_extent(trans, root, num_bytes, empty_size, ret = find_free_extent(trans, root, num_bytes, empty_size,
...@@ -4897,6 +4903,14 @@ static int alloc_tree_block(struct btrfs_trans_handle *trans, ...@@ -4897,6 +4903,14 @@ static int alloc_tree_block(struct btrfs_trans_handle *trans,
extent_op); extent_op);
BUG_ON(ret); BUG_ON(ret);
} }
if (root_objectid == root->root_key.objectid) {
u64 used;
spin_lock(&root->node_lock);
used = btrfs_root_used(&root->root_item) + num_bytes;
btrfs_set_root_used(&root->root_item, used);
spin_unlock(&root->node_lock);
}
return ret; return ret;
} }
...@@ -4919,8 +4933,16 @@ struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans, ...@@ -4919,8 +4933,16 @@ struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
btrfs_set_buffer_uptodate(buf); btrfs_set_buffer_uptodate(buf);
if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) { if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) {
set_extent_dirty(&root->dirty_log_pages, buf->start, /*
buf->start + buf->len - 1, GFP_NOFS); * we allow two log transactions at a time, use different
* EXENT bit to differentiate dirty pages.
*/
if (root->log_transid % 2 == 0)
set_extent_dirty(&root->dirty_log_pages, buf->start,
buf->start + buf->len - 1, GFP_NOFS);
else
set_extent_new(&root->dirty_log_pages, buf->start,
buf->start + buf->len - 1, GFP_NOFS);
} else { } else {
set_extent_dirty(&trans->transaction->dirty_pages, buf->start, set_extent_dirty(&trans->transaction->dirty_pages, buf->start,
buf->start + buf->len - 1, GFP_NOFS); buf->start + buf->len - 1, GFP_NOFS);
......
This diff is collapsed.
This diff is collapsed.
...@@ -237,7 +237,6 @@ static noinline int create_subvol(struct btrfs_root *root, ...@@ -237,7 +237,6 @@ static noinline int create_subvol(struct btrfs_root *root,
u64 objectid; u64 objectid;
u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
u64 index = 0; u64 index = 0;
unsigned long nr = 1;
/* /*
* 1 - inode item * 1 - inode item
...@@ -290,7 +289,7 @@ static noinline int create_subvol(struct btrfs_root *root, ...@@ -290,7 +289,7 @@ static noinline int create_subvol(struct btrfs_root *root,
btrfs_set_root_generation(&root_item, trans->transid); btrfs_set_root_generation(&root_item, trans->transid);
btrfs_set_root_level(&root_item, 0); btrfs_set_root_level(&root_item, 0);
btrfs_set_root_refs(&root_item, 1); btrfs_set_root_refs(&root_item, 1);
btrfs_set_root_used(&root_item, 0); btrfs_set_root_used(&root_item, leaf->len);
btrfs_set_root_last_snapshot(&root_item, 0); btrfs_set_root_last_snapshot(&root_item, 0);
memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress)); memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress));
...@@ -342,24 +341,21 @@ static noinline int create_subvol(struct btrfs_root *root, ...@@ -342,24 +341,21 @@ static noinline int create_subvol(struct btrfs_root *root,
d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
fail: fail:
nr = trans->blocks_used;
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_unreserve_metadata_space(root, 6);
btrfs_btree_balance_dirty(root, nr);
return ret; return ret;
} }
static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
char *name, int namelen) char *name, int namelen)
{ {
struct inode *inode;
struct btrfs_pending_snapshot *pending_snapshot; struct btrfs_pending_snapshot *pending_snapshot;
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
int ret = 0; int ret;
int err;
unsigned long nr = 0;
if (!root->ref_cows) if (!root->ref_cows)
return -EINVAL; return -EINVAL;
...@@ -372,20 +368,20 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, ...@@ -372,20 +368,20 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
*/ */
ret = btrfs_reserve_metadata_space(root, 6); ret = btrfs_reserve_metadata_space(root, 6);
if (ret) if (ret)
goto fail_unlock; goto fail;
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); btrfs_unreserve_metadata_space(root, 6);
goto fail_unlock; goto fail;
} }
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); btrfs_unreserve_metadata_space(root, 6);
goto fail_unlock; goto fail;
} }
memcpy(pending_snapshot->name, name, namelen); memcpy(pending_snapshot->name, name, namelen);
pending_snapshot->name[namelen] = '\0'; pending_snapshot->name[namelen] = '\0';
...@@ -395,10 +391,19 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, ...@@ -395,10 +391,19 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
pending_snapshot->root = root; pending_snapshot->root = root;
list_add(&pending_snapshot->list, list_add(&pending_snapshot->list,
&trans->transaction->pending_snapshots); &trans->transaction->pending_snapshots);
err = btrfs_commit_transaction(trans, root); ret = btrfs_commit_transaction(trans, root);
BUG_ON(ret);
btrfs_unreserve_metadata_space(root, 6);
fail_unlock: inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry);
btrfs_btree_balance_dirty(root, nr); if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
goto fail;
}
BUG_ON(!inode);
d_instantiate(dentry, inode);
ret = 0;
fail:
return ret; return ret;
} }
...@@ -1027,8 +1032,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, ...@@ -1027,8 +1032,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
BUG_ON(!trans); BUG_ON(!trans);
/* punch hole in destination first */ /* punch hole in destination first */
btrfs_drop_extents(trans, root, inode, off, off + len, btrfs_drop_extents(trans, inode, off, off + len, &hint_byte, 1);
off + len, 0, &hint_byte, 1);
/* clone data */ /* clone data */
key.objectid = src->i_ino; key.objectid = src->i_ino;
......
...@@ -291,16 +291,16 @@ int btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry) ...@@ -291,16 +291,16 @@ int btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry)
/* /*
* remove an ordered extent from the tree. No references are dropped * remove an ordered extent from the tree. No references are dropped
* but, anyone waiting on this extent is woken up. * and you must wake_up entry->wait. You must hold the tree mutex
* while you call this function.
*/ */
int btrfs_remove_ordered_extent(struct inode *inode, static int __btrfs_remove_ordered_extent(struct inode *inode,
struct btrfs_ordered_extent *entry) struct btrfs_ordered_extent *entry)
{ {
struct btrfs_ordered_inode_tree *tree; struct btrfs_ordered_inode_tree *tree;
struct rb_node *node; struct rb_node *node;
tree = &BTRFS_I(inode)->ordered_tree; tree = &BTRFS_I(inode)->ordered_tree;
mutex_lock(&tree->mutex);
node = &entry->rb_node; node = &entry->rb_node;
rb_erase(node, &tree->tree); rb_erase(node, &tree->tree);
tree->last = NULL; tree->last = NULL;
...@@ -326,16 +326,34 @@ int btrfs_remove_ordered_extent(struct inode *inode, ...@@ -326,16 +326,34 @@ int btrfs_remove_ordered_extent(struct inode *inode,
} }
spin_unlock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock); spin_unlock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
return 0;
}
/*
* remove an ordered extent from the tree. No references are dropped
* but any waiters are woken.
*/
int btrfs_remove_ordered_extent(struct inode *inode,
struct btrfs_ordered_extent *entry)
{
struct btrfs_ordered_inode_tree *tree;
int ret;
tree = &BTRFS_I(inode)->ordered_tree;
mutex_lock(&tree->mutex);
ret = __btrfs_remove_ordered_extent(inode, entry);
mutex_unlock(&tree->mutex); mutex_unlock(&tree->mutex);
wake_up(&entry->wait); wake_up(&entry->wait);
return 0;
return ret;
} }
/* /*
* wait for all the ordered extents in a root. This is done when balancing * wait for all the ordered extents in a root. This is done when balancing
* space between drives. * space between drives.
*/ */
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 delay_iput)
{ {
struct list_head splice; struct list_head splice;
struct list_head *cur; struct list_head *cur;
...@@ -372,7 +390,10 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only) ...@@ -372,7 +390,10 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only)
if (inode) { if (inode) {
btrfs_start_ordered_extent(inode, ordered, 1); btrfs_start_ordered_extent(inode, ordered, 1);
btrfs_put_ordered_extent(ordered); btrfs_put_ordered_extent(ordered);
iput(inode); if (delay_iput)
btrfs_add_delayed_iput(inode);
else
iput(inode);
} else { } else {
btrfs_put_ordered_extent(ordered); btrfs_put_ordered_extent(ordered);
} }
...@@ -430,7 +451,7 @@ int btrfs_run_ordered_operations(struct btrfs_root *root, int wait) ...@@ -430,7 +451,7 @@ int btrfs_run_ordered_operations(struct btrfs_root *root, int wait)
btrfs_wait_ordered_range(inode, 0, (u64)-1); btrfs_wait_ordered_range(inode, 0, (u64)-1);
else else
filemap_flush(inode->i_mapping); filemap_flush(inode->i_mapping);
iput(inode); btrfs_add_delayed_iput(inode);
} }
cond_resched(); cond_resched();
...@@ -589,7 +610,7 @@ btrfs_lookup_first_ordered_extent(struct inode *inode, u64 file_offset) ...@@ -589,7 +610,7 @@ btrfs_lookup_first_ordered_extent(struct inode *inode, u64 file_offset)
* After an extent is done, call this to conditionally update the on disk * After an extent is done, call this to conditionally update the on disk
* i_size. i_size is updated to cover any fully written part of the file. * i_size. i_size is updated to cover any fully written part of the file.
*/ */
int btrfs_ordered_update_i_size(struct inode *inode, int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
struct btrfs_ordered_extent *ordered) struct btrfs_ordered_extent *ordered)
{ {
struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree; struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree;
...@@ -597,18 +618,30 @@ int btrfs_ordered_update_i_size(struct inode *inode, ...@@ -597,18 +618,30 @@ int btrfs_ordered_update_i_size(struct inode *inode,
u64 disk_i_size; u64 disk_i_size;
u64 new_i_size; u64 new_i_size;
u64 i_size_test; u64 i_size_test;
u64 i_size = i_size_read(inode);
struct rb_node *node; struct rb_node *node;
struct rb_node *prev = NULL;
struct btrfs_ordered_extent *test; struct btrfs_ordered_extent *test;
int ret = 1;
if (ordered)
offset = entry_end(ordered);
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;
/* truncate file */
if (disk_i_size > i_size) {
BTRFS_I(inode)->disk_i_size = i_size;
ret = 0;
goto out;
}
/* /*
* if the disk i_size is already at the inode->i_size, or * if the disk i_size is already at the inode->i_size, or
* this ordered extent is inside the disk i_size, we're done * this ordered extent is inside the disk i_size, we're done
*/ */
if (disk_i_size >= inode->i_size || if (disk_i_size == i_size || offset <= disk_i_size) {
ordered->file_offset + ordered->len <= disk_i_size) {
goto out; goto out;
} }
...@@ -616,8 +649,7 @@ int btrfs_ordered_update_i_size(struct inode *inode, ...@@ -616,8 +649,7 @@ int btrfs_ordered_update_i_size(struct inode *inode,
* we can't update the disk_isize if there are delalloc bytes * we can't update the disk_isize if there are delalloc bytes
* between disk_i_size and this ordered extent * between disk_i_size and this ordered extent
*/ */
if (test_range_bit(io_tree, disk_i_size, if (test_range_bit(io_tree, disk_i_size, offset - 1,
ordered->file_offset + ordered->len - 1,
EXTENT_DELALLOC, 0, NULL)) { EXTENT_DELALLOC, 0, NULL)) {
goto out; goto out;
} }
...@@ -626,20 +658,32 @@ int btrfs_ordered_update_i_size(struct inode *inode, ...@@ -626,20 +658,32 @@ int btrfs_ordered_update_i_size(struct inode *inode,
* if we find an ordered extent then we can't update disk i_size * if we find an ordered extent then we can't update disk i_size
* yet * yet
*/ */
node = &ordered->rb_node; if (ordered) {
while (1) { node = rb_prev(&ordered->rb_node);
node = rb_prev(node); } else {
if (!node) prev = tree_search(tree, offset);
break; /*
* we insert file extents without involving ordered struct,
* so there should be no ordered struct cover this offset
*/
if (prev) {
test = rb_entry(prev, struct btrfs_ordered_extent,
rb_node);
BUG_ON(offset_in_entry(test, offset));
}
node = prev;
}
while (node) {
test = rb_entry(node, struct btrfs_ordered_extent, rb_node); test = rb_entry(node, struct btrfs_ordered_extent, rb_node);
if (test->file_offset + test->len <= disk_i_size) if (test->file_offset + test->len <= disk_i_size)
break; break;
if (test->file_offset >= inode->i_size) if (test->file_offset >= i_size)
break; break;
if (test->file_offset >= disk_i_size) if (test->file_offset >= disk_i_size)
goto out; goto out;
node = rb_prev(node);
} }
new_i_size = min_t(u64, entry_end(ordered), i_size_read(inode)); new_i_size = min_t(u64, offset, i_size);
/* /*
* at this point, we know we can safely update i_size to at least * at this point, we know we can safely update i_size to at least
...@@ -647,7 +691,14 @@ int btrfs_ordered_update_i_size(struct inode *inode, ...@@ -647,7 +691,14 @@ int btrfs_ordered_update_i_size(struct inode *inode,
* walk forward and see if ios from higher up in the file have * walk forward and see if ios from higher up in the file have
* finished. * finished.
*/ */
node = rb_next(&ordered->rb_node); if (ordered) {
node = rb_next(&ordered->rb_node);
} else {
if (prev)
node = rb_next(prev);
else
node = rb_first(&tree->tree);
}
i_size_test = 0; i_size_test = 0;
if (node) { if (node) {
/* /*
...@@ -655,10 +706,10 @@ int btrfs_ordered_update_i_size(struct inode *inode, ...@@ -655,10 +706,10 @@ int btrfs_ordered_update_i_size(struct inode *inode,
* between our ordered extent and the next one. * between our ordered extent and the next one.
*/ */
test = rb_entry(node, struct btrfs_ordered_extent, rb_node); test = rb_entry(node, struct btrfs_ordered_extent, rb_node);
if (test->file_offset > entry_end(ordered)) if (test->file_offset > offset)
i_size_test = test->file_offset; i_size_test = test->file_offset;
} else { } else {
i_size_test = i_size_read(inode); i_size_test = i_size;
} }
/* /*
...@@ -667,15 +718,25 @@ int btrfs_ordered_update_i_size(struct inode *inode, ...@@ -667,15 +718,25 @@ int btrfs_ordered_update_i_size(struct inode *inode,
* are no delalloc bytes in this area, it is safe to update * are no delalloc bytes in this area, it is safe to update
* disk_i_size to the end of the region. * disk_i_size to the end of the region.
*/ */
if (i_size_test > entry_end(ordered) && if (i_size_test > offset &&
!test_range_bit(io_tree, entry_end(ordered), i_size_test - 1, !test_range_bit(io_tree, offset, i_size_test - 1,
EXTENT_DELALLOC, 0, NULL)) { EXTENT_DELALLOC, 0, NULL)) {
new_i_size = min_t(u64, i_size_test, i_size_read(inode)); new_i_size = min_t(u64, i_size_test, i_size);
} }
BTRFS_I(inode)->disk_i_size = new_i_size; BTRFS_I(inode)->disk_i_size = new_i_size;
ret = 0;
out: out:
/*
* we need to remove the ordered extent with the tree lock held
* so that other people calling this function don't find our fully
* processed ordered entry and skip updating the i_size
*/
if (ordered)
__btrfs_remove_ordered_extent(inode, ordered);
mutex_unlock(&tree->mutex); mutex_unlock(&tree->mutex);
return 0; if (ordered)
wake_up(&ordered->wait);
return ret;
} }
/* /*
......
...@@ -150,12 +150,13 @@ void btrfs_start_ordered_extent(struct inode *inode, ...@@ -150,12 +150,13 @@ void btrfs_start_ordered_extent(struct inode *inode,
int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len); int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len);
struct btrfs_ordered_extent * struct btrfs_ordered_extent *
btrfs_lookup_first_ordered_extent(struct inode * inode, u64 file_offset); 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, u64 offset,
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_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,
struct btrfs_root *root, struct btrfs_root *root,
struct inode *inode); struct inode *inode);
int btrfs_wait_ordered_extents(struct btrfs_root *root,
int nocow_only, int delay_iput);
#endif #endif
...@@ -1561,6 +1561,20 @@ static int invalidate_extent_cache(struct btrfs_root *root, ...@@ -1561,6 +1561,20 @@ static int invalidate_extent_cache(struct btrfs_root *root,
return 0; return 0;
} }
static void put_inodes(struct list_head *list)
{
struct inodevec *ivec;
while (!list_empty(list)) {
ivec = list_entry(list->next, struct inodevec, list);
list_del(&ivec->list);
while (ivec->nr > 0) {
ivec->nr--;
iput(ivec->inode[ivec->nr]);
}
kfree(ivec);
}
}
static int find_next_key(struct btrfs_path *path, int level, static int find_next_key(struct btrfs_path *path, int level,
struct btrfs_key *key) struct btrfs_key *key)
...@@ -1723,6 +1737,11 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc, ...@@ -1723,6 +1737,11 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
btrfs_btree_balance_dirty(root, nr); btrfs_btree_balance_dirty(root, nr);
/*
* put inodes outside transaction, otherwise we may deadlock.
*/
put_inodes(&inode_list);
if (replaced && rc->stage == UPDATE_DATA_PTRS) if (replaced && rc->stage == UPDATE_DATA_PTRS)
invalidate_extent_cache(root, &key, &next_key); invalidate_extent_cache(root, &key, &next_key);
} }
...@@ -1752,19 +1771,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc, ...@@ -1752,19 +1771,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
btrfs_btree_balance_dirty(root, nr); btrfs_btree_balance_dirty(root, nr);
/* put_inodes(&inode_list);
* put inodes while we aren't holding the tree locks
*/
while (!list_empty(&inode_list)) {
struct inodevec *ivec;
ivec = list_entry(inode_list.next, struct inodevec, list);
list_del(&ivec->list);
while (ivec->nr > 0) {
ivec->nr--;
iput(ivec->inode[ivec->nr]);
}
kfree(ivec);
}
if (replaced && rc->stage == UPDATE_DATA_PTRS) if (replaced && rc->stage == UPDATE_DATA_PTRS)
invalidate_extent_cache(root, &key, &next_key); invalidate_extent_cache(root, &key, &next_key);
...@@ -3534,8 +3541,8 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start) ...@@ -3534,8 +3541,8 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
(unsigned long long)rc->block_group->key.objectid, (unsigned long long)rc->block_group->key.objectid,
(unsigned long long)rc->block_group->flags); (unsigned long long)rc->block_group->flags);
btrfs_start_delalloc_inodes(fs_info->tree_root); btrfs_start_delalloc_inodes(fs_info->tree_root, 0);
btrfs_wait_ordered_extents(fs_info->tree_root, 0); btrfs_wait_ordered_extents(fs_info->tree_root, 0, 0);
while (1) { while (1) {
rc->extents_found = 0; rc->extents_found = 0;
...@@ -3755,6 +3762,7 @@ int btrfs_recover_relocation(struct btrfs_root *root) ...@@ -3755,6 +3762,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
BTRFS_DATA_RELOC_TREE_OBJECTID); BTRFS_DATA_RELOC_TREE_OBJECTID);
if (IS_ERR(fs_root)) if (IS_ERR(fs_root))
err = PTR_ERR(fs_root); err = PTR_ERR(fs_root);
btrfs_orphan_cleanup(fs_root);
} }
return err; return err;
} }
......
...@@ -128,6 +128,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) ...@@ -128,6 +128,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
substring_t args[MAX_OPT_ARGS]; substring_t args[MAX_OPT_ARGS];
char *p, *num; char *p, *num;
int intarg; int intarg;
int ret = 0;
if (!options) if (!options)
return 0; return 0;
...@@ -262,12 +263,18 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) ...@@ -262,12 +263,18 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
case Opt_discard: case Opt_discard:
btrfs_set_opt(info->mount_opt, DISCARD); btrfs_set_opt(info->mount_opt, DISCARD);
break; break;
case Opt_err:
printk(KERN_INFO "btrfs: unrecognized mount option "
"'%s'\n", p);
ret = -EINVAL;
goto out;
default: default:
break; break;
} }
} }
out:
kfree(options); kfree(options);
return 0; return ret;
} }
/* /*
...@@ -405,8 +412,8 @@ int btrfs_sync_fs(struct super_block *sb, int wait) ...@@ -405,8 +412,8 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
return 0; return 0;
} }
btrfs_start_delalloc_inodes(root); btrfs_start_delalloc_inodes(root, 0);
btrfs_wait_ordered_extents(root, 0); btrfs_wait_ordered_extents(root, 0, 0);
trans = btrfs_start_transaction(root, 1); trans = btrfs_start_transaction(root, 1);
ret = btrfs_commit_transaction(trans, root); ret = btrfs_commit_transaction(trans, root);
...@@ -450,6 +457,8 @@ static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs) ...@@ -450,6 +457,8 @@ static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
seq_puts(seq, ",notreelog"); seq_puts(seq, ",notreelog");
if (btrfs_test_opt(root, FLUSHONCOMMIT)) if (btrfs_test_opt(root, FLUSHONCOMMIT))
seq_puts(seq, ",flushoncommit"); seq_puts(seq, ",flushoncommit");
if (btrfs_test_opt(root, DISCARD))
seq_puts(seq, ",discard");
if (!(root->fs_info->sb->s_flags & MS_POSIXACL)) if (!(root->fs_info->sb->s_flags & MS_POSIXACL))
seq_puts(seq, ",noacl"); seq_puts(seq, ",noacl");
return 0; return 0;
......
...@@ -333,6 +333,9 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, ...@@ -333,6 +333,9 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
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);
if (throttle)
btrfs_run_delayed_iputs(root);
return 0; return 0;
} }
...@@ -354,7 +357,7 @@ int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, ...@@ -354,7 +357,7 @@ int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
* those extents are sent to disk but does not wait on them * those extents are sent to disk but does not wait on them
*/ */
int btrfs_write_marked_extents(struct btrfs_root *root, int btrfs_write_marked_extents(struct btrfs_root *root,
struct extent_io_tree *dirty_pages) struct extent_io_tree *dirty_pages, int mark)
{ {
int ret; int ret;
int err = 0; int err = 0;
...@@ -367,7 +370,7 @@ int btrfs_write_marked_extents(struct btrfs_root *root, ...@@ -367,7 +370,7 @@ int btrfs_write_marked_extents(struct btrfs_root *root,
while (1) { while (1) {
ret = find_first_extent_bit(dirty_pages, start, &start, &end, ret = find_first_extent_bit(dirty_pages, start, &start, &end,
EXTENT_DIRTY); mark);
if (ret) if (ret)
break; break;
while (start <= end) { while (start <= end) {
...@@ -413,7 +416,7 @@ int btrfs_write_marked_extents(struct btrfs_root *root, ...@@ -413,7 +416,7 @@ int btrfs_write_marked_extents(struct btrfs_root *root,
* on all the pages and clear them from the dirty pages state tree * on all the pages and clear them from the dirty pages state tree
*/ */
int btrfs_wait_marked_extents(struct btrfs_root *root, int btrfs_wait_marked_extents(struct btrfs_root *root,
struct extent_io_tree *dirty_pages) struct extent_io_tree *dirty_pages, int mark)
{ {
int ret; int ret;
int err = 0; int err = 0;
...@@ -425,12 +428,12 @@ int btrfs_wait_marked_extents(struct btrfs_root *root, ...@@ -425,12 +428,12 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
unsigned long index; unsigned long index;
while (1) { while (1) {
ret = find_first_extent_bit(dirty_pages, 0, &start, &end, ret = find_first_extent_bit(dirty_pages, start, &start, &end,
EXTENT_DIRTY); mark);
if (ret) if (ret)
break; break;
clear_extent_dirty(dirty_pages, start, end, GFP_NOFS); clear_extent_bits(dirty_pages, start, end, mark, GFP_NOFS);
while (start <= end) { while (start <= end) {
index = start >> PAGE_CACHE_SHIFT; index = start >> PAGE_CACHE_SHIFT;
start = (u64)(index + 1) << PAGE_CACHE_SHIFT; start = (u64)(index + 1) << PAGE_CACHE_SHIFT;
...@@ -460,13 +463,13 @@ int btrfs_wait_marked_extents(struct btrfs_root *root, ...@@ -460,13 +463,13 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
* those extents are on disk for transaction or log commit * those extents are on disk for transaction or log commit
*/ */
int btrfs_write_and_wait_marked_extents(struct btrfs_root *root, int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
struct extent_io_tree *dirty_pages) struct extent_io_tree *dirty_pages, int mark)
{ {
int ret; int ret;
int ret2; int ret2;
ret = btrfs_write_marked_extents(root, dirty_pages); ret = btrfs_write_marked_extents(root, dirty_pages, mark);
ret2 = btrfs_wait_marked_extents(root, dirty_pages); ret2 = btrfs_wait_marked_extents(root, dirty_pages, mark);
return ret || ret2; return ret || ret2;
} }
...@@ -479,7 +482,8 @@ int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, ...@@ -479,7 +482,8 @@ int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
return filemap_write_and_wait(btree_inode->i_mapping); return filemap_write_and_wait(btree_inode->i_mapping);
} }
return btrfs_write_and_wait_marked_extents(root, return btrfs_write_and_wait_marked_extents(root,
&trans->transaction->dirty_pages); &trans->transaction->dirty_pages,
EXTENT_DIRTY);
} }
/* /*
...@@ -497,13 +501,16 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans, ...@@ -497,13 +501,16 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
{ {
int ret; int ret;
u64 old_root_bytenr; u64 old_root_bytenr;
u64 old_root_used;
struct btrfs_root *tree_root = root->fs_info->tree_root; struct btrfs_root *tree_root = root->fs_info->tree_root;
old_root_used = btrfs_root_used(&root->root_item);
btrfs_write_dirty_block_groups(trans, root); btrfs_write_dirty_block_groups(trans, root);
while (1) { while (1) {
old_root_bytenr = btrfs_root_bytenr(&root->root_item); old_root_bytenr = btrfs_root_bytenr(&root->root_item);
if (old_root_bytenr == root->node->start) if (old_root_bytenr == root->node->start &&
old_root_used == btrfs_root_used(&root->root_item))
break; break;
btrfs_set_root_node(&root->root_item, root->node); btrfs_set_root_node(&root->root_item, root->node);
...@@ -512,6 +519,7 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans, ...@@ -512,6 +519,7 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
&root->root_item); &root->root_item);
BUG_ON(ret); BUG_ON(ret);
old_root_used = btrfs_root_used(&root->root_item);
ret = btrfs_write_dirty_block_groups(trans, root); ret = btrfs_write_dirty_block_groups(trans, root);
BUG_ON(ret); BUG_ON(ret);
} }
...@@ -795,7 +803,6 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ...@@ -795,7 +803,6 @@ 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;
} }
...@@ -807,7 +814,6 @@ static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info, ...@@ -807,7 +814,6 @@ static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info,
u64 index = 0; u64 index = 0;
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
struct inode *parent_inode; struct inode *parent_inode;
struct inode *inode;
struct btrfs_root *parent_root; struct btrfs_root *parent_root;
parent_inode = pending->dentry->d_parent->d_inode; parent_inode = pending->dentry->d_parent->d_inode;
...@@ -839,8 +845,6 @@ static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info, ...@@ -839,8 +845,6 @@ static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info,
BUG_ON(ret); BUG_ON(ret);
inode = btrfs_lookup_dentry(parent_inode, pending->dentry);
d_instantiate(pending->dentry, inode);
fail: fail:
btrfs_end_transaction(trans, fs_info->fs_root); btrfs_end_transaction(trans, fs_info->fs_root);
return ret; return ret;
...@@ -994,11 +998,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -994,11 +998,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
mutex_unlock(&root->fs_info->trans_mutex); mutex_unlock(&root->fs_info->trans_mutex);
if (flush_on_commit) { if (flush_on_commit) {
btrfs_start_delalloc_inodes(root); btrfs_start_delalloc_inodes(root, 1);
ret = btrfs_wait_ordered_extents(root, 0); ret = btrfs_wait_ordered_extents(root, 0, 1);
BUG_ON(ret); BUG_ON(ret);
} else if (snap_pending) { } else if (snap_pending) {
ret = btrfs_wait_ordered_extents(root, 1); ret = btrfs_wait_ordered_extents(root, 0, 1);
BUG_ON(ret); BUG_ON(ret);
} }
...@@ -1116,6 +1120,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -1116,6 +1120,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
current->journal_info = NULL; current->journal_info = NULL;
kmem_cache_free(btrfs_trans_handle_cachep, trans); kmem_cache_free(btrfs_trans_handle_cachep, trans);
if (current != root->fs_info->transaction_kthread)
btrfs_run_delayed_iputs(root);
return ret; return ret;
} }
......
...@@ -107,10 +107,10 @@ void btrfs_throttle(struct btrfs_root *root); ...@@ -107,10 +107,10 @@ void btrfs_throttle(struct btrfs_root *root);
int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans, int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
struct btrfs_root *root); struct btrfs_root *root);
int btrfs_write_and_wait_marked_extents(struct btrfs_root *root, int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
struct extent_io_tree *dirty_pages); struct extent_io_tree *dirty_pages, int mark);
int btrfs_write_marked_extents(struct btrfs_root *root, int btrfs_write_marked_extents(struct btrfs_root *root,
struct extent_io_tree *dirty_pages); struct extent_io_tree *dirty_pages, int mark);
int btrfs_wait_marked_extents(struct btrfs_root *root, int btrfs_wait_marked_extents(struct btrfs_root *root,
struct extent_io_tree *dirty_pages); struct extent_io_tree *dirty_pages, int mark);
int btrfs_transaction_in_commit(struct btrfs_fs_info *info); int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
#endif #endif
...@@ -542,8 +542,8 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, ...@@ -542,8 +542,8 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
saved_nbytes = inode_get_bytes(inode); saved_nbytes = inode_get_bytes(inode);
/* drop any overlapping extents */ /* drop any overlapping extents */
ret = btrfs_drop_extents(trans, root, inode, ret = btrfs_drop_extents(trans, inode, start, extent_end,
start, extent_end, extent_end, start, &alloc_hint, 1); &alloc_hint, 1);
BUG_ON(ret); BUG_ON(ret);
if (found_type == BTRFS_FILE_EXTENT_REG || if (found_type == BTRFS_FILE_EXTENT_REG ||
...@@ -930,6 +930,17 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, ...@@ -930,6 +930,17 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
return 0; return 0;
} }
static int insert_orphan_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 offset)
{
int ret;
ret = btrfs_find_orphan_item(root, offset);
if (ret > 0)
ret = btrfs_insert_orphan_item(trans, root, offset);
return ret;
}
/* /*
* There are a few corners where the link count of the file can't * There are a few corners where the link count of the file can't
* be properly maintained during replay. So, instead of adding * be properly maintained during replay. So, instead of adding
...@@ -997,9 +1008,13 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans, ...@@ -997,9 +1008,13 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
} }
BTRFS_I(inode)->index_cnt = (u64)-1; BTRFS_I(inode)->index_cnt = (u64)-1;
if (inode->i_nlink == 0 && S_ISDIR(inode->i_mode)) { if (inode->i_nlink == 0) {
ret = replay_dir_deletes(trans, root, NULL, path, if (S_ISDIR(inode->i_mode)) {
inode->i_ino, 1); ret = replay_dir_deletes(trans, root, NULL, path,
inode->i_ino, 1);
BUG_ON(ret);
}
ret = insert_orphan_item(trans, root, inode->i_ino);
BUG_ON(ret); BUG_ON(ret);
} }
btrfs_free_path(path); btrfs_free_path(path);
...@@ -1587,7 +1602,6 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, ...@@ -1587,7 +1602,6 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
/* inode keys are done during the first stage */ /* inode keys are done during the first stage */
if (key.type == BTRFS_INODE_ITEM_KEY && if (key.type == BTRFS_INODE_ITEM_KEY &&
wc->stage == LOG_WALK_REPLAY_INODES) { wc->stage == LOG_WALK_REPLAY_INODES) {
struct inode *inode;
struct btrfs_inode_item *inode_item; struct btrfs_inode_item *inode_item;
u32 mode; u32 mode;
...@@ -1603,31 +1617,16 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, ...@@ -1603,31 +1617,16 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
eb, i, &key); eb, i, &key);
BUG_ON(ret); BUG_ON(ret);
/* for regular files, truncate away /* for regular files, make sure corresponding
* extents past the new EOF * orhpan item exist. extents past the new EOF
* will be truncated later by orphan cleanup.
*/ */
if (S_ISREG(mode)) { if (S_ISREG(mode)) {
inode = read_one_inode(root, ret = insert_orphan_item(wc->trans, root,
key.objectid); key.objectid);
BUG_ON(!inode);
ret = btrfs_truncate_inode_items(wc->trans,
root, inode, inode->i_size,
BTRFS_EXTENT_DATA_KEY);
BUG_ON(ret); BUG_ON(ret);
/* if the nlink count is zero here, the iput
* will free the inode. We bump it to make
* sure it doesn't get freed until the link
* count fixup is done
*/
if (inode->i_nlink == 0) {
btrfs_inc_nlink(inode);
btrfs_update_inode(wc->trans,
root, inode);
}
iput(inode);
} }
ret = link_to_fixup_dir(wc->trans, root, ret = link_to_fixup_dir(wc->trans, root,
path, key.objectid); path, key.objectid);
BUG_ON(ret); BUG_ON(ret);
...@@ -1977,10 +1976,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, ...@@ -1977,10 +1976,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
{ {
int index1; int index1;
int index2; int index2;
int mark;
int ret; int ret;
struct btrfs_root *log = root->log_root; struct btrfs_root *log = root->log_root;
struct btrfs_root *log_root_tree = root->fs_info->log_root_tree; struct btrfs_root *log_root_tree = root->fs_info->log_root_tree;
u64 log_transid = 0; unsigned long log_transid = 0;
mutex_lock(&root->log_mutex); mutex_lock(&root->log_mutex);
index1 = root->log_transid % 2; index1 = root->log_transid % 2;
...@@ -2014,24 +2014,29 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, ...@@ -2014,24 +2014,29 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
goto out; goto out;
} }
log_transid = root->log_transid;
if (log_transid % 2 == 0)
mark = EXTENT_DIRTY;
else
mark = EXTENT_NEW;
/* we start IO on all the marked extents here, but we don't actually /* we start IO on all the marked extents here, but we don't actually
* wait for them until later. * wait for them until later.
*/ */
ret = btrfs_write_marked_extents(log, &log->dirty_log_pages); ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark);
BUG_ON(ret); BUG_ON(ret);
btrfs_set_root_node(&log->root_item, log->node); btrfs_set_root_node(&log->root_item, log->node);
root->log_batch = 0; root->log_batch = 0;
log_transid = root->log_transid;
root->log_transid++; root->log_transid++;
log->log_transid = root->log_transid; log->log_transid = root->log_transid;
root->log_start_pid = 0; root->log_start_pid = 0;
smp_mb(); smp_mb();
/* /*
* log tree has been flushed to disk, new modifications of * IO has been started, blocks of the log tree have WRITTEN flag set
* the log will be written to new positions. so it's safe to * in their headers. new modifications of the log will be written to
* allow log writers to go in. * new positions. so it's safe to allow log writers to go in.
*/ */
mutex_unlock(&root->log_mutex); mutex_unlock(&root->log_mutex);
...@@ -2052,7 +2057,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, ...@@ -2052,7 +2057,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
index2 = log_root_tree->log_transid % 2; index2 = log_root_tree->log_transid % 2;
if (atomic_read(&log_root_tree->log_commit[index2])) { if (atomic_read(&log_root_tree->log_commit[index2])) {
btrfs_wait_marked_extents(log, &log->dirty_log_pages); btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
wait_log_commit(trans, log_root_tree, wait_log_commit(trans, log_root_tree,
log_root_tree->log_transid); log_root_tree->log_transid);
mutex_unlock(&log_root_tree->log_mutex); mutex_unlock(&log_root_tree->log_mutex);
...@@ -2072,16 +2077,17 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, ...@@ -2072,16 +2077,17 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
* check the full commit flag again * check the full commit flag again
*/ */
if (root->fs_info->last_trans_log_full_commit == trans->transid) { if (root->fs_info->last_trans_log_full_commit == trans->transid) {
btrfs_wait_marked_extents(log, &log->dirty_log_pages); btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
mutex_unlock(&log_root_tree->log_mutex); mutex_unlock(&log_root_tree->log_mutex);
ret = -EAGAIN; ret = -EAGAIN;
goto out_wake_log_root; goto out_wake_log_root;
} }
ret = btrfs_write_and_wait_marked_extents(log_root_tree, ret = btrfs_write_and_wait_marked_extents(log_root_tree,
&log_root_tree->dirty_log_pages); &log_root_tree->dirty_log_pages,
EXTENT_DIRTY | EXTENT_NEW);
BUG_ON(ret); BUG_ON(ret);
btrfs_wait_marked_extents(log, &log->dirty_log_pages); btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
btrfs_set_super_log_root(&root->fs_info->super_for_commit, btrfs_set_super_log_root(&root->fs_info->super_for_commit,
log_root_tree->node->start); log_root_tree->node->start);
...@@ -2147,12 +2153,12 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root) ...@@ -2147,12 +2153,12 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
while (1) { while (1) {
ret = find_first_extent_bit(&log->dirty_log_pages, ret = find_first_extent_bit(&log->dirty_log_pages,
0, &start, &end, EXTENT_DIRTY); 0, &start, &end, EXTENT_DIRTY | EXTENT_NEW);
if (ret) if (ret)
break; break;
clear_extent_dirty(&log->dirty_log_pages, clear_extent_bits(&log->dirty_log_pages, start, end,
start, end, GFP_NOFS); EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS);
} }
if (log->log_transid > 0) { if (log->log_transid > 0) {
......
...@@ -2209,7 +2209,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, ...@@ -2209,7 +2209,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
max_chunk_size = 10 * calc_size; max_chunk_size = 10 * calc_size;
min_stripe_size = 64 * 1024 * 1024; min_stripe_size = 64 * 1024 * 1024;
} else if (type & BTRFS_BLOCK_GROUP_METADATA) { } else if (type & BTRFS_BLOCK_GROUP_METADATA) {
max_chunk_size = 4 * calc_size; max_chunk_size = 256 * 1024 * 1024;
min_stripe_size = 32 * 1024 * 1024; min_stripe_size = 32 * 1024 * 1024;
} else if (type & BTRFS_BLOCK_GROUP_SYSTEM) { } else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
calc_size = 8 * 1024 * 1024; calc_size = 8 * 1024 * 1024;
......
...@@ -85,22 +85,23 @@ ssize_t __btrfs_getxattr(struct inode *inode, const char *name, ...@@ -85,22 +85,23 @@ ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
return ret; return ret;
} }
int __btrfs_setxattr(struct inode *inode, const char *name, static int do_setxattr(struct btrfs_trans_handle *trans,
const void *value, size_t size, int flags) struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{ {
struct btrfs_dir_item *di; struct btrfs_dir_item *di;
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_trans_handle *trans;
struct btrfs_path *path; struct btrfs_path *path;
int ret = 0, mod = 0; size_t name_len = strlen(name);
int ret = 0;
if (name_len + size > BTRFS_MAX_XATTR_SIZE(root))
return -ENOSPC;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
trans = btrfs_join_transaction(root, 1);
btrfs_set_trans_block_group(trans, inode);
/* first lets see if we already have this xattr */ /* first lets see if we already have this xattr */
di = btrfs_lookup_xattr(trans, root, path, inode->i_ino, name, di = btrfs_lookup_xattr(trans, root, path, inode->i_ino, name,
strlen(name), -1); strlen(name), -1);
...@@ -118,15 +119,12 @@ int __btrfs_setxattr(struct inode *inode, const char *name, ...@@ -118,15 +119,12 @@ int __btrfs_setxattr(struct inode *inode, const char *name,
} }
ret = btrfs_delete_one_dir_name(trans, root, path, di); ret = btrfs_delete_one_dir_name(trans, root, path, di);
if (ret) BUG_ON(ret);
goto out;
btrfs_release_path(root, path); btrfs_release_path(root, path);
/* if we don't have a value then we are removing the xattr */ /* if we don't have a value then we are removing the xattr */
if (!value) { if (!value)
mod = 1;
goto out; goto out;
}
} else { } else {
btrfs_release_path(root, path); btrfs_release_path(root, path);
...@@ -138,20 +136,45 @@ int __btrfs_setxattr(struct inode *inode, const char *name, ...@@ -138,20 +136,45 @@ int __btrfs_setxattr(struct inode *inode, const char *name,
} }
/* ok we have to create a completely new xattr */ /* ok we have to create a completely new xattr */
ret = btrfs_insert_xattr_item(trans, root, name, strlen(name), ret = btrfs_insert_xattr_item(trans, root, path, inode->i_ino,
value, size, inode->i_ino); name, name_len, value, size);
BUG_ON(ret);
out:
btrfs_free_path(path);
return ret;
}
int __btrfs_setxattr(struct btrfs_trans_handle *trans,
struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
struct btrfs_root *root = BTRFS_I(inode)->root;
int ret;
if (trans)
return do_setxattr(trans, inode, name, value, size, flags);
ret = btrfs_reserve_metadata_space(root, 2);
if (ret) if (ret)
goto out; return ret;
mod = 1;
out: trans = btrfs_start_transaction(root, 1);
if (mod) { if (!trans) {
inode->i_ctime = CURRENT_TIME; ret = -ENOMEM;
ret = btrfs_update_inode(trans, root, inode); goto out;
} }
btrfs_set_trans_block_group(trans, inode);
btrfs_end_transaction(trans, root); ret = do_setxattr(trans, inode, name, value, size, flags);
btrfs_free_path(path); if (ret)
goto out;
inode->i_ctime = CURRENT_TIME;
ret = btrfs_update_inode(trans, root, inode);
BUG_ON(ret);
out:
btrfs_end_transaction_throttle(trans, root);
btrfs_unreserve_metadata_space(root, 2);
return ret; return ret;
} }
...@@ -314,7 +337,9 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value, ...@@ -314,7 +337,9 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
if (size == 0) if (size == 0)
value = ""; /* empty EA, do not remove */ value = ""; /* empty EA, do not remove */
return __btrfs_setxattr(dentry->d_inode, name, value, size, flags);
return __btrfs_setxattr(NULL, dentry->d_inode, name, value, size,
flags);
} }
int btrfs_removexattr(struct dentry *dentry, const char *name) int btrfs_removexattr(struct dentry *dentry, const char *name)
...@@ -329,10 +354,13 @@ int btrfs_removexattr(struct dentry *dentry, const char *name) ...@@ -329,10 +354,13 @@ int btrfs_removexattr(struct dentry *dentry, const char *name)
if (!btrfs_is_valid_xattr(name)) if (!btrfs_is_valid_xattr(name))
return -EOPNOTSUPP; return -EOPNOTSUPP;
return __btrfs_setxattr(dentry->d_inode, name, NULL, 0, XATTR_REPLACE);
return __btrfs_setxattr(NULL, dentry->d_inode, name, NULL, 0,
XATTR_REPLACE);
} }
int btrfs_xattr_security_init(struct inode *inode, struct inode *dir) int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
struct inode *inode, struct inode *dir)
{ {
int err; int err;
size_t len; size_t len;
...@@ -354,7 +382,7 @@ int btrfs_xattr_security_init(struct inode *inode, struct inode *dir) ...@@ -354,7 +382,7 @@ int btrfs_xattr_security_init(struct inode *inode, struct inode *dir)
} else { } else {
strcpy(name, XATTR_SECURITY_PREFIX); strcpy(name, XATTR_SECURITY_PREFIX);
strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix); strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix);
err = __btrfs_setxattr(inode, name, value, len, 0); err = __btrfs_setxattr(trans, inode, name, value, len, 0);
kfree(name); kfree(name);
} }
......
...@@ -27,15 +27,16 @@ extern struct xattr_handler *btrfs_xattr_handlers[]; ...@@ -27,15 +27,16 @@ extern struct xattr_handler *btrfs_xattr_handlers[];
extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name, extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
void *buffer, size_t size); void *buffer, size_t size);
extern int __btrfs_setxattr(struct inode *inode, const char *name, extern int __btrfs_setxattr(struct btrfs_trans_handle *trans,
const void *value, size_t size, int flags); struct inode *inode, const char *name,
const void *value, size_t size, int flags);
extern ssize_t btrfs_getxattr(struct dentry *dentry, const char *name, extern ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
void *buffer, size_t size); void *buffer, size_t size);
extern int btrfs_setxattr(struct dentry *dentry, const char *name, extern int btrfs_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags); const void *value, size_t size, int flags);
extern int btrfs_removexattr(struct dentry *dentry, const char *name); extern int btrfs_removexattr(struct dentry *dentry, const char *name);
extern int btrfs_xattr_security_init(struct inode *inode, struct inode *dir); extern int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
struct inode *inode, struct inode *dir);
#endif /* __XATTR__ */ #endif /* __XATTR__ */
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