提交 212a17ab 编写于 作者: L Linus Torvalds

Merge branch 'for-linus-unmerged' of...

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

* 'for-linus-unmerged' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable: (45 commits)
  Btrfs: fix __btrfs_map_block on 32 bit machines
  btrfs: fix possible deadlock by clearing __GFP_FS flag
  btrfs: check link counter overflow in link(2)
  btrfs: don't mess with i_nlink of unlocked inode in rename()
  Btrfs: check return value of btrfs_alloc_path()
  Btrfs: fix OOPS of empty filesystem after balance
  Btrfs: fix memory leak of empty filesystem after balance
  Btrfs: fix return value of setflags ioctl
  Btrfs: fix uncheck memory allocations
  btrfs: make inode ref log recovery faster
  Btrfs: add btrfs_trim_fs() to handle FITRIM
  Btrfs: adjust btrfs_discard_extent() return errors and trimmed bytes
  Btrfs: make btrfs_map_block() return entire free extent for each device of RAID0/1/10/DUP
  Btrfs: make update_reserved_bytes() public
  btrfs: return EXDEV when linking from different subvolumes
  Btrfs: Per file/directory controls for COW and compression
  Btrfs: add datacow flag in inode flag
  btrfs: use GFP_NOFS instead of GFP_KERNEL
  Btrfs: check return value of read_tree_block()
  btrfs: properly access unaligned checksum buffer
  ...

Fix up trivial conflicts in fs/btrfs/volumes.c due to plug removal in
the block layer.
...@@ -136,9 +136,8 @@ struct btrfs_inode { ...@@ -136,9 +136,8 @@ struct btrfs_inode {
* items we think we'll end up using, and reserved_extents is the number * items we think we'll end up using, and reserved_extents is the number
* of extent items we've reserved metadata for. * of extent items we've reserved metadata for.
*/ */
spinlock_t accounting_lock;
atomic_t outstanding_extents; atomic_t outstanding_extents;
int reserved_extents; atomic_t reserved_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
......
...@@ -340,6 +340,8 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start, ...@@ -340,6 +340,8 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
WARN_ON(start & ((u64)PAGE_CACHE_SIZE - 1)); WARN_ON(start & ((u64)PAGE_CACHE_SIZE - 1));
cb = kmalloc(compressed_bio_size(root, compressed_len), GFP_NOFS); cb = kmalloc(compressed_bio_size(root, compressed_len), GFP_NOFS);
if (!cb)
return -ENOMEM;
atomic_set(&cb->pending_bios, 0); atomic_set(&cb->pending_bios, 0);
cb->errors = 0; cb->errors = 0;
cb->inode = inode; cb->inode = inode;
...@@ -354,6 +356,10 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start, ...@@ -354,6 +356,10 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev; bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
bio = compressed_bio_alloc(bdev, first_byte, GFP_NOFS); bio = compressed_bio_alloc(bdev, first_byte, GFP_NOFS);
if(!bio) {
kfree(cb);
return -ENOMEM;
}
bio->bi_private = cb; bio->bi_private = cb;
bio->bi_end_io = end_compressed_bio_write; bio->bi_end_io = end_compressed_bio_write;
atomic_inc(&cb->pending_bios); atomic_inc(&cb->pending_bios);
...@@ -657,8 +663,9 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, ...@@ -657,8 +663,9 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
atomic_inc(&cb->pending_bios); atomic_inc(&cb->pending_bios);
if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) { if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
btrfs_lookup_bio_sums(root, inode, comp_bio, ret = btrfs_lookup_bio_sums(root, inode,
sums); comp_bio, sums);
BUG_ON(ret);
} }
sums += (comp_bio->bi_size + root->sectorsize - 1) / sums += (comp_bio->bi_size + root->sectorsize - 1) /
root->sectorsize; root->sectorsize;
...@@ -683,8 +690,10 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, ...@@ -683,8 +690,10 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0); ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0);
BUG_ON(ret); BUG_ON(ret);
if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
btrfs_lookup_bio_sums(root, inode, comp_bio, sums); ret = btrfs_lookup_bio_sums(root, inode, comp_bio, sums);
BUG_ON(ret);
}
ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0); ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0);
BUG_ON(ret); BUG_ON(ret);
......
...@@ -147,10 +147,11 @@ noinline void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p) ...@@ -147,10 +147,11 @@ noinline void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p)
struct extent_buffer *btrfs_root_node(struct btrfs_root *root) struct extent_buffer *btrfs_root_node(struct btrfs_root *root)
{ {
struct extent_buffer *eb; struct extent_buffer *eb;
spin_lock(&root->node_lock);
eb = root->node; rcu_read_lock();
eb = rcu_dereference(root->node);
extent_buffer_get(eb); extent_buffer_get(eb);
spin_unlock(&root->node_lock); rcu_read_unlock();
return eb; return eb;
} }
...@@ -165,14 +166,8 @@ struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root) ...@@ -165,14 +166,8 @@ struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root)
while (1) { while (1) {
eb = btrfs_root_node(root); eb = btrfs_root_node(root);
btrfs_tree_lock(eb); btrfs_tree_lock(eb);
if (eb == root->node)
spin_lock(&root->node_lock);
if (eb == root->node) {
spin_unlock(&root->node_lock);
break; break;
}
spin_unlock(&root->node_lock);
btrfs_tree_unlock(eb); btrfs_tree_unlock(eb);
free_extent_buffer(eb); free_extent_buffer(eb);
} }
...@@ -458,10 +453,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, ...@@ -458,10 +453,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
else else
parent_start = 0; parent_start = 0;
spin_lock(&root->node_lock);
root->node = cow;
extent_buffer_get(cow); extent_buffer_get(cow);
spin_unlock(&root->node_lock); rcu_assign_pointer(root->node, cow);
btrfs_free_tree_block(trans, root, buf, parent_start, btrfs_free_tree_block(trans, root, buf, parent_start,
last_ref); last_ref);
...@@ -542,6 +535,9 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans, ...@@ -542,6 +535,9 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
ret = __btrfs_cow_block(trans, root, buf, parent, ret = __btrfs_cow_block(trans, root, buf, parent,
parent_slot, cow_ret, search_start, 0); parent_slot, cow_ret, search_start, 0);
trace_btrfs_cow_block(root, buf, *cow_ret);
return ret; return ret;
} }
...@@ -686,6 +682,8 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, ...@@ -686,6 +682,8 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
if (!cur) { if (!cur) {
cur = read_tree_block(root, blocknr, cur = read_tree_block(root, blocknr,
blocksize, gen); blocksize, gen);
if (!cur)
return -EIO;
} else if (!uptodate) { } else if (!uptodate) {
btrfs_read_buffer(cur, gen); btrfs_read_buffer(cur, gen);
} }
...@@ -732,122 +730,6 @@ static inline unsigned int leaf_data_end(struct btrfs_root *root, ...@@ -732,122 +730,6 @@ static inline unsigned int leaf_data_end(struct btrfs_root *root,
return btrfs_item_offset_nr(leaf, nr - 1); return btrfs_item_offset_nr(leaf, nr - 1);
} }
/*
* extra debugging checks to make sure all the items in a key are
* well formed and in the proper order
*/
static int check_node(struct btrfs_root *root, struct btrfs_path *path,
int level)
{
struct extent_buffer *parent = NULL;
struct extent_buffer *node = path->nodes[level];
struct btrfs_disk_key parent_key;
struct btrfs_disk_key node_key;
int parent_slot;
int slot;
struct btrfs_key cpukey;
u32 nritems = btrfs_header_nritems(node);
if (path->nodes[level + 1])
parent = path->nodes[level + 1];
slot = path->slots[level];
BUG_ON(nritems == 0);
if (parent) {
parent_slot = path->slots[level + 1];
btrfs_node_key(parent, &parent_key, parent_slot);
btrfs_node_key(node, &node_key, 0);
BUG_ON(memcmp(&parent_key, &node_key,
sizeof(struct btrfs_disk_key)));
BUG_ON(btrfs_node_blockptr(parent, parent_slot) !=
btrfs_header_bytenr(node));
}
BUG_ON(nritems > BTRFS_NODEPTRS_PER_BLOCK(root));
if (slot != 0) {
btrfs_node_key_to_cpu(node, &cpukey, slot - 1);
btrfs_node_key(node, &node_key, slot);
BUG_ON(comp_keys(&node_key, &cpukey) <= 0);
}
if (slot < nritems - 1) {
btrfs_node_key_to_cpu(node, &cpukey, slot + 1);
btrfs_node_key(node, &node_key, slot);
BUG_ON(comp_keys(&node_key, &cpukey) >= 0);
}
return 0;
}
/*
* extra checking to make sure all the items in a leaf are
* well formed and in the proper order
*/
static int check_leaf(struct btrfs_root *root, struct btrfs_path *path,
int level)
{
struct extent_buffer *leaf = path->nodes[level];
struct extent_buffer *parent = NULL;
int parent_slot;
struct btrfs_key cpukey;
struct btrfs_disk_key parent_key;
struct btrfs_disk_key leaf_key;
int slot = path->slots[0];
u32 nritems = btrfs_header_nritems(leaf);
if (path->nodes[level + 1])
parent = path->nodes[level + 1];
if (nritems == 0)
return 0;
if (parent) {
parent_slot = path->slots[level + 1];
btrfs_node_key(parent, &parent_key, parent_slot);
btrfs_item_key(leaf, &leaf_key, 0);
BUG_ON(memcmp(&parent_key, &leaf_key,
sizeof(struct btrfs_disk_key)));
BUG_ON(btrfs_node_blockptr(parent, parent_slot) !=
btrfs_header_bytenr(leaf));
}
if (slot != 0 && slot < nritems - 1) {
btrfs_item_key(leaf, &leaf_key, slot);
btrfs_item_key_to_cpu(leaf, &cpukey, slot - 1);
if (comp_keys(&leaf_key, &cpukey) <= 0) {
btrfs_print_leaf(root, leaf);
printk(KERN_CRIT "slot %d offset bad key\n", slot);
BUG_ON(1);
}
if (btrfs_item_offset_nr(leaf, slot - 1) !=
btrfs_item_end_nr(leaf, slot)) {
btrfs_print_leaf(root, leaf);
printk(KERN_CRIT "slot %d offset bad\n", slot);
BUG_ON(1);
}
}
if (slot < nritems - 1) {
btrfs_item_key(leaf, &leaf_key, slot);
btrfs_item_key_to_cpu(leaf, &cpukey, slot + 1);
BUG_ON(comp_keys(&leaf_key, &cpukey) >= 0);
if (btrfs_item_offset_nr(leaf, slot) !=
btrfs_item_end_nr(leaf, slot + 1)) {
btrfs_print_leaf(root, leaf);
printk(KERN_CRIT "slot %d offset bad\n", slot);
BUG_ON(1);
}
}
BUG_ON(btrfs_item_offset_nr(leaf, 0) +
btrfs_item_size_nr(leaf, 0) != BTRFS_LEAF_DATA_SIZE(root));
return 0;
}
static noinline int check_block(struct btrfs_root *root,
struct btrfs_path *path, int level)
{
return 0;
if (level == 0)
return check_leaf(root, path, level);
return check_node(root, path, level);
}
/* /*
* search for key in the extent_buffer. The items start at offset p, * search for key in the extent_buffer. The items start at offset p,
...@@ -1046,9 +928,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, ...@@ -1046,9 +928,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
goto enospc; goto enospc;
} }
spin_lock(&root->node_lock); rcu_assign_pointer(root->node, child);
root->node = child;
spin_unlock(&root->node_lock);
add_root_to_dirty_list(root); add_root_to_dirty_list(root);
btrfs_tree_unlock(child); btrfs_tree_unlock(child);
...@@ -1188,7 +1068,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, ...@@ -1188,7 +1068,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
} }
} }
/* double check we haven't messed things up */ /* double check we haven't messed things up */
check_block(root, path, level);
if (orig_ptr != if (orig_ptr !=
btrfs_node_blockptr(path->nodes[level], path->slots[level])) btrfs_node_blockptr(path->nodes[level], path->slots[level]))
BUG(); BUG();
...@@ -1798,12 +1677,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1798,12 +1677,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
if (!cow) if (!cow)
btrfs_unlock_up_safe(p, level + 1); btrfs_unlock_up_safe(p, level + 1);
ret = check_block(root, p, level);
if (ret) {
ret = -1;
goto done;
}
ret = bin_search(b, key, level, &slot); ret = bin_search(b, key, level, &slot);
if (level != 0) { if (level != 0) {
...@@ -2130,10 +2003,8 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans, ...@@ -2130,10 +2003,8 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(c); btrfs_mark_buffer_dirty(c);
spin_lock(&root->node_lock);
old = root->node; old = root->node;
root->node = c; rcu_assign_pointer(root->node, c);
spin_unlock(&root->node_lock);
/* the super has an extra ref to root->node */ /* the super has an extra ref to root->node */
free_extent_buffer(old); free_extent_buffer(old);
...@@ -3840,7 +3711,8 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -3840,7 +3711,8 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
unsigned long ptr; unsigned long ptr;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
BUG_ON(!path); if (!path)
return -ENOMEM;
ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
if (!ret) { if (!ret) {
leaf = path->nodes[0]; leaf = path->nodes[0];
...@@ -4217,6 +4089,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, ...@@ -4217,6 +4089,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
} }
btrfs_set_path_blocking(path); btrfs_set_path_blocking(path);
cur = read_node_slot(root, cur, slot); cur = read_node_slot(root, cur, slot);
BUG_ON(!cur);
btrfs_tree_lock(cur); btrfs_tree_lock(cur);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/kobject.h> #include <linux/kobject.h>
#include <trace/events/btrfs.h>
#include <asm/kmap_types.h> #include <asm/kmap_types.h>
#include "extent_io.h" #include "extent_io.h"
#include "extent_map.h" #include "extent_map.h"
...@@ -40,6 +41,7 @@ extern struct kmem_cache *btrfs_trans_handle_cachep; ...@@ -40,6 +41,7 @@ extern struct kmem_cache *btrfs_trans_handle_cachep;
extern struct kmem_cache *btrfs_transaction_cachep; extern struct kmem_cache *btrfs_transaction_cachep;
extern struct kmem_cache *btrfs_bit_radix_cachep; extern struct kmem_cache *btrfs_bit_radix_cachep;
extern struct kmem_cache *btrfs_path_cachep; extern struct kmem_cache *btrfs_path_cachep;
extern struct kmem_cache *btrfs_free_space_cachep;
struct btrfs_ordered_sum; struct btrfs_ordered_sum;
#define BTRFS_MAGIC "_BHRfS_M" #define BTRFS_MAGIC "_BHRfS_M"
...@@ -782,9 +784,6 @@ struct btrfs_free_cluster { ...@@ -782,9 +784,6 @@ struct btrfs_free_cluster {
/* first extent starting offset */ /* first extent starting offset */
u64 window_start; u64 window_start;
/* if this cluster simply points at a bitmap in the block group */
bool points_to_bitmap;
struct btrfs_block_group_cache *block_group; struct btrfs_block_group_cache *block_group;
/* /*
* when a cluster is allocated from a block group, we put the * when a cluster is allocated from a block group, we put the
...@@ -1283,6 +1282,7 @@ struct btrfs_root { ...@@ -1283,6 +1282,7 @@ struct btrfs_root {
#define BTRFS_INODE_NODUMP (1 << 8) #define BTRFS_INODE_NODUMP (1 << 8)
#define BTRFS_INODE_NOATIME (1 << 9) #define BTRFS_INODE_NOATIME (1 << 9)
#define BTRFS_INODE_DIRSYNC (1 << 10) #define BTRFS_INODE_DIRSYNC (1 << 10)
#define BTRFS_INODE_COMPRESS (1 << 11)
/* some macros to generate set/get funcs for the struct fields. This /* some macros to generate set/get funcs for the struct fields. This
* assumes there is a lefoo_to_cpu for every type, so lets make a simple * assumes there is a lefoo_to_cpu for every type, so lets make a simple
...@@ -2157,6 +2157,8 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, ...@@ -2157,6 +2157,8 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans,
u64 root_objectid, u64 owner, u64 offset); u64 root_objectid, u64 owner, u64 offset);
int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len); int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len);
int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache,
u64 num_bytes, int reserve, int sinfo);
int btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans, int btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans,
struct btrfs_root *root); struct btrfs_root *root);
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
...@@ -2227,10 +2229,12 @@ u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo); ...@@ -2227,10 +2229,12 @@ u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo);
int btrfs_error_unpin_extent_range(struct btrfs_root *root, int btrfs_error_unpin_extent_range(struct btrfs_root *root,
u64 start, u64 end); u64 start, u64 end);
int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr, int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr,
u64 num_bytes); u64 num_bytes, u64 *actual_bytes);
int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 type); struct btrfs_root *root, u64 type);
int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range);
int btrfs_init_space_info(struct btrfs_fs_info *fs_info);
/* ctree.c */ /* ctree.c */
int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key,
int level, int *slot); int level, int *slot);
...@@ -2392,6 +2396,9 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, ...@@ -2392,6 +2396,9 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
struct btrfs_path *path, u64 dir, struct btrfs_path *path, u64 dir,
const char *name, u16 name_len, const char *name, u16 name_len,
int mod); int mod);
int verify_dir_item(struct btrfs_root *root,
struct extent_buffer *leaf,
struct btrfs_dir_item *dir_item);
/* orphan.c */ /* orphan.c */
int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans,
...@@ -2528,7 +2535,7 @@ int btrfs_update_inode(struct btrfs_trans_handle *trans, ...@@ -2528,7 +2535,7 @@ int btrfs_update_inode(struct btrfs_trans_handle *trans,
struct inode *inode); struct inode *inode);
int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode); int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode);
int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode); int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode);
void btrfs_orphan_cleanup(struct btrfs_root *root); int btrfs_orphan_cleanup(struct btrfs_root *root);
void btrfs_orphan_pre_snapshot(struct btrfs_trans_handle *trans, void btrfs_orphan_pre_snapshot(struct btrfs_trans_handle *trans,
struct btrfs_pending_snapshot *pending, struct btrfs_pending_snapshot *pending,
u64 *bytes_to_reserve); u64 *bytes_to_reserve);
...@@ -2536,7 +2543,7 @@ void btrfs_orphan_post_snapshot(struct btrfs_trans_handle *trans, ...@@ -2536,7 +2543,7 @@ void btrfs_orphan_post_snapshot(struct btrfs_trans_handle *trans,
struct btrfs_pending_snapshot *pending); struct btrfs_pending_snapshot *pending);
void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans, void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root); struct btrfs_root *root);
int btrfs_cont_expand(struct inode *inode, loff_t size); int btrfs_cont_expand(struct inode *inode, loff_t oldsize, 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_add_delayed_iput(struct inode *inode);
void btrfs_run_delayed_iputs(struct btrfs_root *root); void btrfs_run_delayed_iputs(struct btrfs_root *root);
......
...@@ -483,6 +483,8 @@ static noinline int add_delayed_ref_head(struct btrfs_trans_handle *trans, ...@@ -483,6 +483,8 @@ static noinline int add_delayed_ref_head(struct btrfs_trans_handle *trans,
INIT_LIST_HEAD(&head_ref->cluster); INIT_LIST_HEAD(&head_ref->cluster);
mutex_init(&head_ref->mutex); mutex_init(&head_ref->mutex);
trace_btrfs_delayed_ref_head(ref, head_ref, action);
existing = tree_insert(&delayed_refs->root, &ref->rb_node); existing = tree_insert(&delayed_refs->root, &ref->rb_node);
if (existing) { if (existing) {
...@@ -537,6 +539,8 @@ static noinline int add_delayed_tree_ref(struct btrfs_trans_handle *trans, ...@@ -537,6 +539,8 @@ static noinline int add_delayed_tree_ref(struct btrfs_trans_handle *trans,
} }
full_ref->level = level; full_ref->level = level;
trace_btrfs_delayed_tree_ref(ref, full_ref, action);
existing = tree_insert(&delayed_refs->root, &ref->rb_node); existing = tree_insert(&delayed_refs->root, &ref->rb_node);
if (existing) { if (existing) {
...@@ -591,6 +595,8 @@ static noinline int add_delayed_data_ref(struct btrfs_trans_handle *trans, ...@@ -591,6 +595,8 @@ static noinline int add_delayed_data_ref(struct btrfs_trans_handle *trans,
full_ref->objectid = owner; full_ref->objectid = owner;
full_ref->offset = offset; full_ref->offset = offset;
trace_btrfs_delayed_data_ref(ref, full_ref, action);
existing = tree_insert(&delayed_refs->root, &ref->rb_node); existing = tree_insert(&delayed_refs->root, &ref->rb_node);
if (existing) { if (existing) {
......
...@@ -151,7 +151,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -151,7 +151,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
ret = PTR_ERR(dir_item); ret = PTR_ERR(dir_item);
if (ret == -EEXIST) if (ret == -EEXIST)
goto second_insert; goto second_insert;
goto out; goto out_free;
} }
leaf = path->nodes[0]; leaf = path->nodes[0];
...@@ -170,7 +170,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -170,7 +170,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
/* FIXME, use some real flag for selecting the extra index */ /* FIXME, use some real flag for selecting the extra index */
if (root == root->fs_info->tree_root) { if (root == root->fs_info->tree_root) {
ret = 0; ret = 0;
goto out; goto out_free;
} }
btrfs_release_path(root, path); btrfs_release_path(root, path);
...@@ -180,7 +180,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -180,7 +180,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
name, name_len); name, name_len);
if (IS_ERR(dir_item)) { if (IS_ERR(dir_item)) {
ret2 = PTR_ERR(dir_item); ret2 = PTR_ERR(dir_item);
goto out; goto out_free;
} }
leaf = path->nodes[0]; leaf = path->nodes[0];
btrfs_cpu_key_to_disk(&disk_key, location); btrfs_cpu_key_to_disk(&disk_key, location);
...@@ -192,7 +192,9 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -192,7 +192,9 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
name_ptr = (unsigned long)(dir_item + 1); name_ptr = (unsigned long)(dir_item + 1);
write_extent_buffer(leaf, name, name_ptr, name_len); write_extent_buffer(leaf, name, name_ptr, name_len);
btrfs_mark_buffer_dirty(leaf); btrfs_mark_buffer_dirty(leaf);
out:
out_free:
btrfs_free_path(path); btrfs_free_path(path);
if (ret) if (ret)
return ret; return ret;
...@@ -377,6 +379,9 @@ struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, ...@@ -377,6 +379,9 @@ struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
leaf = path->nodes[0]; leaf = path->nodes[0];
dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item); dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
if (verify_dir_item(root, leaf, dir_item))
return NULL;
total_len = btrfs_item_size_nr(leaf, path->slots[0]); total_len = btrfs_item_size_nr(leaf, path->slots[0]);
while (cur < total_len) { while (cur < total_len) {
this_len = sizeof(*dir_item) + this_len = sizeof(*dir_item) +
...@@ -429,3 +434,35 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, ...@@ -429,3 +434,35 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
} }
return ret; return ret;
} }
int verify_dir_item(struct btrfs_root *root,
struct extent_buffer *leaf,
struct btrfs_dir_item *dir_item)
{
u16 namelen = BTRFS_NAME_LEN;
u8 type = btrfs_dir_type(leaf, dir_item);
if (type >= BTRFS_FT_MAX) {
printk(KERN_CRIT "btrfs: invalid dir item type: %d\n",
(int)type);
return 1;
}
if (type == BTRFS_FT_XATTR)
namelen = XATTR_NAME_MAX;
if (btrfs_dir_name_len(leaf, dir_item) > namelen) {
printk(KERN_CRIT "btrfS: invalid dir item name len: %u\n",
(unsigned)btrfs_dir_data_len(leaf, dir_item));
return 1;
}
/* BTRFS_MAX_XATTR_SIZE is the same for all dir items */
if (btrfs_dir_data_len(leaf, dir_item) > BTRFS_MAX_XATTR_SIZE(root)) {
printk(KERN_CRIT "btrfs: invalid dir item data len: %u\n",
(unsigned)btrfs_dir_data_len(leaf, dir_item));
return 1;
}
return 0;
}
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/crc32c.h> #include <linux/crc32c.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/migrate.h> #include <linux/migrate.h>
#include <asm/unaligned.h>
#include "compat.h" #include "compat.h"
#include "ctree.h" #include "ctree.h"
#include "disk-io.h" #include "disk-io.h"
...@@ -198,7 +199,7 @@ u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len) ...@@ -198,7 +199,7 @@ u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len)
void btrfs_csum_final(u32 crc, char *result) void btrfs_csum_final(u32 crc, char *result)
{ {
*(__le32 *)result = ~cpu_to_le32(crc); put_unaligned_le32(~crc, result);
} }
/* /*
...@@ -323,6 +324,7 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, ...@@ -323,6 +324,7 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root,
int num_copies = 0; int num_copies = 0;
int mirror_num = 0; int mirror_num = 0;
clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
io_tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree; io_tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree;
while (1) { while (1) {
ret = read_extent_buffer_pages(io_tree, eb, start, 1, ret = read_extent_buffer_pages(io_tree, eb, start, 1,
...@@ -331,6 +333,14 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, ...@@ -331,6 +333,14 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root,
!verify_parent_transid(io_tree, eb, parent_transid)) !verify_parent_transid(io_tree, eb, parent_transid))
return ret; return ret;
/*
* This buffer's crc is fine, but its contents are corrupted, so
* there is no reason to read the other copies, they won't be
* any less wrong.
*/
if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags))
return ret;
num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
eb->start, eb->len); eb->start, eb->len);
if (num_copies == 1) if (num_copies == 1)
...@@ -419,6 +429,73 @@ static int check_tree_block_fsid(struct btrfs_root *root, ...@@ -419,6 +429,73 @@ static int check_tree_block_fsid(struct btrfs_root *root,
return ret; return ret;
} }
#define CORRUPT(reason, eb, root, slot) \
printk(KERN_CRIT "btrfs: corrupt leaf, %s: block=%llu," \
"root=%llu, slot=%d\n", reason, \
(unsigned long long)btrfs_header_bytenr(eb), \
(unsigned long long)root->objectid, slot)
static noinline int check_leaf(struct btrfs_root *root,
struct extent_buffer *leaf)
{
struct btrfs_key key;
struct btrfs_key leaf_key;
u32 nritems = btrfs_header_nritems(leaf);
int slot;
if (nritems == 0)
return 0;
/* Check the 0 item */
if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) !=
BTRFS_LEAF_DATA_SIZE(root)) {
CORRUPT("invalid item offset size pair", leaf, root, 0);
return -EIO;
}
/*
* Check to make sure each items keys are in the correct order and their
* offsets make sense. We only have to loop through nritems-1 because
* we check the current slot against the next slot, which verifies the
* next slot's offset+size makes sense and that the current's slot
* offset is correct.
*/
for (slot = 0; slot < nritems - 1; slot++) {
btrfs_item_key_to_cpu(leaf, &leaf_key, slot);
btrfs_item_key_to_cpu(leaf, &key, slot + 1);
/* Make sure the keys are in the right order */
if (btrfs_comp_cpu_keys(&leaf_key, &key) >= 0) {
CORRUPT("bad key order", leaf, root, slot);
return -EIO;
}
/*
* Make sure the offset and ends are right, remember that the
* item data starts at the end of the leaf and grows towards the
* front.
*/
if (btrfs_item_offset_nr(leaf, slot) !=
btrfs_item_end_nr(leaf, slot + 1)) {
CORRUPT("slot offset bad", leaf, root, slot);
return -EIO;
}
/*
* Check to make sure that we don't point outside of the leaf,
* just incase all the items are consistent to eachother, but
* all point outside of the leaf.
*/
if (btrfs_item_end_nr(leaf, slot) >
BTRFS_LEAF_DATA_SIZE(root)) {
CORRUPT("slot end outside of leaf", leaf, root, slot);
return -EIO;
}
}
return 0;
}
#ifdef CONFIG_DEBUG_LOCK_ALLOC #ifdef CONFIG_DEBUG_LOCK_ALLOC
void btrfs_set_buffer_lockdep_class(struct extent_buffer *eb, int level) void btrfs_set_buffer_lockdep_class(struct extent_buffer *eb, int level)
{ {
...@@ -485,8 +562,20 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, ...@@ -485,8 +562,20 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
btrfs_set_buffer_lockdep_class(eb, found_level); btrfs_set_buffer_lockdep_class(eb, found_level);
ret = csum_tree_block(root, eb, 1); ret = csum_tree_block(root, eb, 1);
if (ret) if (ret) {
ret = -EIO; ret = -EIO;
goto err;
}
/*
* If this is a leaf block and it is corrupt, set the corrupt bit so
* that we don't try and read the other copies of this block, just
* return -EIO.
*/
if (found_level == 0 && check_leaf(root, eb)) {
set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
ret = -EIO;
}
end = min_t(u64, eb->len, PAGE_CACHE_SIZE); end = min_t(u64, eb->len, PAGE_CACHE_SIZE);
end = eb->start + end - 1; end = eb->start + end - 1;
...@@ -1159,7 +1248,10 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, ...@@ -1159,7 +1248,10 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
root, fs_info, location->objectid); root, fs_info, location->objectid);
path = btrfs_alloc_path(); path = btrfs_alloc_path();
BUG_ON(!path); if (!path) {
kfree(root);
return ERR_PTR(-ENOMEM);
}
ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0); ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0);
if (ret == 0) { if (ret == 0) {
l = path->nodes[0]; l = path->nodes[0];
...@@ -1553,6 +1645,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1553,6 +1645,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
goto fail_bdi; goto fail_bdi;
} }
fs_info->btree_inode->i_mapping->flags &= ~__GFP_FS;
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);
...@@ -1683,6 +1777,12 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1683,6 +1777,12 @@ struct btrfs_root *open_ctree(struct super_block *sb,
btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY); btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY);
/*
* In the long term, we'll store the compression type in the super
* block, and it'll be used for per file compression control.
*/
fs_info->compress_type = BTRFS_COMPRESS_ZLIB;
ret = btrfs_parse_options(tree_root, options); ret = btrfs_parse_options(tree_root, options);
if (ret) { if (ret) {
err = ret; err = ret;
...@@ -1888,6 +1988,12 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1888,6 +1988,12 @@ struct btrfs_root *open_ctree(struct super_block *sb,
fs_info->metadata_alloc_profile = (u64)-1; fs_info->metadata_alloc_profile = (u64)-1;
fs_info->system_alloc_profile = fs_info->metadata_alloc_profile; fs_info->system_alloc_profile = fs_info->metadata_alloc_profile;
ret = btrfs_init_space_info(fs_info);
if (ret) {
printk(KERN_ERR "Failed to initial space info: %d\n", ret);
goto fail_block_groups;
}
ret = btrfs_read_block_groups(extent_root); ret = btrfs_read_block_groups(extent_root);
if (ret) { if (ret) {
printk(KERN_ERR "Failed to read block groups: %d\n", ret); printk(KERN_ERR "Failed to read block groups: %d\n", ret);
...@@ -1979,9 +2085,14 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1979,9 +2085,14 @@ struct btrfs_root *open_ctree(struct super_block *sb,
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
down_read(&fs_info->cleanup_work_sem); down_read(&fs_info->cleanup_work_sem);
btrfs_orphan_cleanup(fs_info->fs_root); err = btrfs_orphan_cleanup(fs_info->fs_root);
btrfs_orphan_cleanup(fs_info->tree_root); if (!err)
err = btrfs_orphan_cleanup(fs_info->tree_root);
up_read(&fs_info->cleanup_work_sem); up_read(&fs_info->cleanup_work_sem);
if (err) {
close_ctree(tree_root);
return ERR_PTR(err);
}
} }
return tree_root; return tree_root;
...@@ -2356,8 +2467,12 @@ int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info) ...@@ -2356,8 +2467,12 @@ int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
root_objectid = gang[ret - 1]->root_key.objectid + 1; root_objectid = gang[ret - 1]->root_key.objectid + 1;
for (i = 0; i < ret; i++) { for (i = 0; i < ret; i++) {
int err;
root_objectid = gang[i]->root_key.objectid; root_objectid = gang[i]->root_key.objectid;
btrfs_orphan_cleanup(gang[i]); err = btrfs_orphan_cleanup(gang[i]);
if (err)
return err;
} }
root_objectid++; root_objectid++;
} }
...@@ -2868,7 +2983,10 @@ static int btrfs_destroy_pinned_extent(struct btrfs_root *root, ...@@ -2868,7 +2983,10 @@ static int btrfs_destroy_pinned_extent(struct btrfs_root *root,
break; break;
/* opt_discard */ /* opt_discard */
ret = btrfs_error_discard_extent(root, start, end + 1 - start); if (btrfs_test_opt(root, DISCARD))
ret = btrfs_error_discard_extent(root, start,
end + 1 - start,
NULL);
clear_extent_dirty(unpin, start, end, GFP_NOFS); clear_extent_dirty(unpin, start, end, GFP_NOFS);
btrfs_error_unpin_extent_range(root, start, end); btrfs_error_unpin_extent_range(root, start, end);
......
...@@ -36,8 +36,6 @@ ...@@ -36,8 +36,6 @@
static int update_block_group(struct btrfs_trans_handle *trans, static int update_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
u64 bytenr, u64 num_bytes, int alloc); u64 bytenr, u64 num_bytes, int alloc);
static int update_reserved_bytes(struct btrfs_block_group_cache *cache,
u64 num_bytes, int reserve, int sinfo);
static int __btrfs_free_extent(struct btrfs_trans_handle *trans, static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
u64 bytenr, u64 num_bytes, u64 parent, u64 bytenr, u64 num_bytes, u64 parent,
...@@ -442,7 +440,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache, ...@@ -442,7 +440,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
* allocate blocks for the tree root we can't do the fast caching since * allocate blocks for the tree root we can't do the fast caching since
* we likely hold important locks. * we likely hold important locks.
*/ */
if (!trans->transaction->in_commit && if (trans && (!trans->transaction->in_commit) &&
(root && root != root->fs_info->tree_root)) { (root && root != root->fs_info->tree_root)) {
spin_lock(&cache->lock); spin_lock(&cache->lock);
if (cache->cached != BTRFS_CACHE_NO) { if (cache->cached != BTRFS_CACHE_NO) {
...@@ -471,7 +469,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache, ...@@ -471,7 +469,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
if (load_cache_only) if (load_cache_only)
return 0; return 0;
caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_KERNEL); caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_NOFS);
BUG_ON(!caching_ctl); BUG_ON(!caching_ctl);
INIT_LIST_HEAD(&caching_ctl->list); INIT_LIST_HEAD(&caching_ctl->list);
...@@ -1740,39 +1738,45 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans, ...@@ -1740,39 +1738,45 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans,
return ret; return ret;
} }
static void btrfs_issue_discard(struct block_device *bdev, static int btrfs_issue_discard(struct block_device *bdev,
u64 start, u64 len) u64 start, u64 len)
{ {
blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_KERNEL, 0); return blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_NOFS, 0);
} }
static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr, static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
u64 num_bytes) u64 num_bytes, u64 *actual_bytes)
{ {
int ret; int ret;
u64 map_length = num_bytes; u64 discarded_bytes = 0;
struct btrfs_multi_bio *multi = NULL; struct btrfs_multi_bio *multi = NULL;
if (!btrfs_test_opt(root, DISCARD))
return 0;
/* Tell the block device(s) that the sectors can be discarded */ /* Tell the block device(s) that the sectors can be discarded */
ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, ret = btrfs_map_block(&root->fs_info->mapping_tree, REQ_DISCARD,
bytenr, &map_length, &multi, 0); bytenr, &num_bytes, &multi, 0);
if (!ret) { if (!ret) {
struct btrfs_bio_stripe *stripe = multi->stripes; struct btrfs_bio_stripe *stripe = multi->stripes;
int i; int i;
if (map_length > num_bytes)
map_length = num_bytes;
for (i = 0; i < multi->num_stripes; i++, stripe++) { for (i = 0; i < multi->num_stripes; i++, stripe++) {
btrfs_issue_discard(stripe->dev->bdev, ret = btrfs_issue_discard(stripe->dev->bdev,
stripe->physical, stripe->physical,
map_length); stripe->length);
if (!ret)
discarded_bytes += stripe->length;
else if (ret != -EOPNOTSUPP)
break;
} }
kfree(multi); kfree(multi);
} }
if (discarded_bytes && ret == -EOPNOTSUPP)
ret = 0;
if (actual_bytes)
*actual_bytes = discarded_bytes;
return ret; return ret;
} }
...@@ -3996,6 +4000,7 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes) ...@@ -3996,6 +4000,7 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
struct btrfs_block_rsv *block_rsv = &root->fs_info->delalloc_block_rsv; struct btrfs_block_rsv *block_rsv = &root->fs_info->delalloc_block_rsv;
u64 to_reserve; u64 to_reserve;
int nr_extents; int nr_extents;
int reserved_extents;
int ret; int ret;
if (btrfs_transaction_in_commit(root->fs_info)) if (btrfs_transaction_in_commit(root->fs_info))
...@@ -4003,25 +4008,24 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes) ...@@ -4003,25 +4008,24 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
num_bytes = ALIGN(num_bytes, root->sectorsize); num_bytes = ALIGN(num_bytes, root->sectorsize);
spin_lock(&BTRFS_I(inode)->accounting_lock);
nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents) + 1; nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents) + 1;
if (nr_extents > BTRFS_I(inode)->reserved_extents) { reserved_extents = atomic_read(&BTRFS_I(inode)->reserved_extents);
nr_extents -= BTRFS_I(inode)->reserved_extents;
if (nr_extents > reserved_extents) {
nr_extents -= reserved_extents;
to_reserve = calc_trans_metadata_size(root, nr_extents); to_reserve = calc_trans_metadata_size(root, nr_extents);
} else { } else {
nr_extents = 0; nr_extents = 0;
to_reserve = 0; to_reserve = 0;
} }
spin_unlock(&BTRFS_I(inode)->accounting_lock);
to_reserve += calc_csum_metadata_size(inode, num_bytes); to_reserve += calc_csum_metadata_size(inode, num_bytes);
ret = reserve_metadata_bytes(NULL, root, block_rsv, to_reserve, 1); ret = reserve_metadata_bytes(NULL, root, block_rsv, to_reserve, 1);
if (ret) if (ret)
return ret; return ret;
spin_lock(&BTRFS_I(inode)->accounting_lock); atomic_add(nr_extents, &BTRFS_I(inode)->reserved_extents);
BTRFS_I(inode)->reserved_extents += nr_extents;
atomic_inc(&BTRFS_I(inode)->outstanding_extents); atomic_inc(&BTRFS_I(inode)->outstanding_extents);
spin_unlock(&BTRFS_I(inode)->accounting_lock);
block_rsv_add_bytes(block_rsv, to_reserve, 1); block_rsv_add_bytes(block_rsv, to_reserve, 1);
...@@ -4036,20 +4040,30 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes) ...@@ -4036,20 +4040,30 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
u64 to_free; u64 to_free;
int nr_extents; int nr_extents;
int reserved_extents;
num_bytes = ALIGN(num_bytes, root->sectorsize); num_bytes = ALIGN(num_bytes, root->sectorsize);
atomic_dec(&BTRFS_I(inode)->outstanding_extents); atomic_dec(&BTRFS_I(inode)->outstanding_extents);
WARN_ON(atomic_read(&BTRFS_I(inode)->outstanding_extents) < 0); WARN_ON(atomic_read(&BTRFS_I(inode)->outstanding_extents) < 0);
spin_lock(&BTRFS_I(inode)->accounting_lock); reserved_extents = atomic_read(&BTRFS_I(inode)->reserved_extents);
nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents); do {
if (nr_extents < BTRFS_I(inode)->reserved_extents) { int old, new;
nr_extents = BTRFS_I(inode)->reserved_extents - nr_extents;
BTRFS_I(inode)->reserved_extents -= nr_extents; nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents);
} else { if (nr_extents >= reserved_extents) {
nr_extents = 0; nr_extents = 0;
} break;
spin_unlock(&BTRFS_I(inode)->accounting_lock); }
old = reserved_extents;
nr_extents = reserved_extents - nr_extents;
new = reserved_extents - nr_extents;
old = atomic_cmpxchg(&BTRFS_I(inode)->reserved_extents,
reserved_extents, new);
if (likely(old == reserved_extents))
break;
reserved_extents = old;
} while (1);
to_free = calc_csum_metadata_size(inode, num_bytes); to_free = calc_csum_metadata_size(inode, num_bytes);
if (nr_extents > 0) if (nr_extents > 0)
...@@ -4223,8 +4237,8 @@ int btrfs_pin_extent(struct btrfs_root *root, ...@@ -4223,8 +4237,8 @@ int btrfs_pin_extent(struct btrfs_root *root,
* update size of reserved extents. this function may return -EAGAIN * update size of reserved extents. this function may return -EAGAIN
* if 'reserve' is true or 'sinfo' is false. * if 'reserve' is true or 'sinfo' is false.
*/ */
static int update_reserved_bytes(struct btrfs_block_group_cache *cache, int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache,
u64 num_bytes, int reserve, int sinfo) u64 num_bytes, int reserve, int sinfo)
{ {
int ret = 0; int ret = 0;
if (sinfo) { if (sinfo) {
...@@ -4363,7 +4377,9 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, ...@@ -4363,7 +4377,9 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
if (ret) if (ret)
break; break;
ret = btrfs_discard_extent(root, start, end + 1 - start); if (btrfs_test_opt(root, DISCARD))
ret = btrfs_discard_extent(root, start,
end + 1 - start, NULL);
clear_extent_dirty(unpin, start, end, GFP_NOFS); clear_extent_dirty(unpin, start, end, GFP_NOFS);
unpin_extent_range(root, start, end); unpin_extent_range(root, start, end);
...@@ -4704,10 +4720,10 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans, ...@@ -4704,10 +4720,10 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
WARN_ON(test_bit(EXTENT_BUFFER_DIRTY, &buf->bflags)); WARN_ON(test_bit(EXTENT_BUFFER_DIRTY, &buf->bflags));
btrfs_add_free_space(cache, buf->start, buf->len); btrfs_add_free_space(cache, buf->start, buf->len);
ret = update_reserved_bytes(cache, buf->len, 0, 0); ret = btrfs_update_reserved_bytes(cache, buf->len, 0, 0);
if (ret == -EAGAIN) { if (ret == -EAGAIN) {
/* block group became read-only */ /* block group became read-only */
update_reserved_bytes(cache, buf->len, 0, 1); btrfs_update_reserved_bytes(cache, buf->len, 0, 1);
goto out; goto out;
} }
...@@ -4744,6 +4760,11 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans, ...@@ -4744,6 +4760,11 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
} }
} }
out: out:
/*
* Deleting the buffer, clear the corrupt flag since it doesn't matter
* anymore.
*/
clear_bit(EXTENT_BUFFER_CORRUPT, &buf->bflags);
btrfs_put_block_group(cache); btrfs_put_block_group(cache);
} }
...@@ -5191,7 +5212,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, ...@@ -5191,7 +5212,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
search_start - offset); search_start - offset);
BUG_ON(offset > search_start); BUG_ON(offset > search_start);
ret = update_reserved_bytes(block_group, num_bytes, 1, ret = btrfs_update_reserved_bytes(block_group, num_bytes, 1,
(data & BTRFS_BLOCK_GROUP_DATA)); (data & BTRFS_BLOCK_GROUP_DATA));
if (ret == -EAGAIN) { if (ret == -EAGAIN) {
btrfs_add_free_space(block_group, offset, num_bytes); btrfs_add_free_space(block_group, offset, num_bytes);
...@@ -5397,6 +5418,8 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans, ...@@ -5397,6 +5418,8 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
dump_space_info(sinfo, num_bytes, 1); dump_space_info(sinfo, num_bytes, 1);
} }
trace_btrfs_reserved_extent_alloc(root, ins->objectid, ins->offset);
return ret; return ret;
} }
...@@ -5412,12 +5435,15 @@ int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len) ...@@ -5412,12 +5435,15 @@ int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len)
return -ENOSPC; return -ENOSPC;
} }
ret = btrfs_discard_extent(root, start, len); if (btrfs_test_opt(root, DISCARD))
ret = btrfs_discard_extent(root, start, len, NULL);
btrfs_add_free_space(cache, start, len); btrfs_add_free_space(cache, start, len);
update_reserved_bytes(cache, len, 0, 1); btrfs_update_reserved_bytes(cache, len, 0, 1);
btrfs_put_block_group(cache); btrfs_put_block_group(cache);
trace_btrfs_reserved_extent_free(root, start, len);
return ret; return ret;
} }
...@@ -5444,7 +5470,8 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans, ...@@ -5444,7 +5470,8 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
size = sizeof(*extent_item) + btrfs_extent_inline_ref_size(type); size = sizeof(*extent_item) + btrfs_extent_inline_ref_size(type);
path = btrfs_alloc_path(); path = btrfs_alloc_path();
BUG_ON(!path); if (!path)
return -ENOMEM;
path->leave_spinning = 1; path->leave_spinning = 1;
ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path, ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
...@@ -5614,7 +5641,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, ...@@ -5614,7 +5641,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
put_caching_control(caching_ctl); put_caching_control(caching_ctl);
} }
ret = update_reserved_bytes(block_group, ins->offset, 1, 1); ret = btrfs_update_reserved_bytes(block_group, ins->offset, 1, 1);
BUG_ON(ret); BUG_ON(ret);
btrfs_put_block_group(block_group); btrfs_put_block_group(block_group);
ret = alloc_reserved_file_extent(trans, root, 0, root_objectid, ret = alloc_reserved_file_extent(trans, root, 0, root_objectid,
...@@ -6047,6 +6074,8 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans, ...@@ -6047,6 +6074,8 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
if (reada && level == 1) if (reada && level == 1)
reada_walk_down(trans, root, wc, path); reada_walk_down(trans, root, wc, path);
next = read_tree_block(root, bytenr, blocksize, generation); next = read_tree_block(root, bytenr, blocksize, generation);
if (!next)
return -EIO;
btrfs_tree_lock(next); btrfs_tree_lock(next);
btrfs_set_lock_blocking(next); btrfs_set_lock_blocking(next);
} }
...@@ -6438,10 +6467,14 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans, ...@@ -6438,10 +6467,14 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
BUG_ON(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID); BUG_ON(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID);
path = btrfs_alloc_path(); path = btrfs_alloc_path();
BUG_ON(!path); if (!path)
return -ENOMEM;
wc = kzalloc(sizeof(*wc), GFP_NOFS); wc = kzalloc(sizeof(*wc), GFP_NOFS);
BUG_ON(!wc); if (!wc) {
btrfs_free_path(path);
return -ENOMEM;
}
btrfs_assert_tree_locked(parent); btrfs_assert_tree_locked(parent);
parent_level = btrfs_header_level(parent); parent_level = btrfs_header_level(parent);
...@@ -6899,7 +6932,11 @@ static noinline int get_new_locations(struct inode *reloc_inode, ...@@ -6899,7 +6932,11 @@ static noinline int get_new_locations(struct inode *reloc_inode,
} }
path = btrfs_alloc_path(); path = btrfs_alloc_path();
BUG_ON(!path); if (!path) {
if (exts != *extents)
kfree(exts);
return -ENOMEM;
}
cur_pos = extent_key->objectid - offset; cur_pos = extent_key->objectid - offset;
last_byte = extent_key->objectid + extent_key->offset; last_byte = extent_key->objectid + extent_key->offset;
...@@ -6941,6 +6978,10 @@ static noinline int get_new_locations(struct inode *reloc_inode, ...@@ -6941,6 +6978,10 @@ static noinline int get_new_locations(struct inode *reloc_inode,
struct disk_extent *old = exts; struct disk_extent *old = exts;
max *= 2; max *= 2;
exts = kzalloc(sizeof(*exts) * max, GFP_NOFS); exts = kzalloc(sizeof(*exts) * max, GFP_NOFS);
if (!exts) {
ret = -ENOMEM;
goto out;
}
memcpy(exts, old, sizeof(*exts) * nr); memcpy(exts, old, sizeof(*exts) * nr);
if (old != *extents) if (old != *extents)
kfree(old); kfree(old);
...@@ -7423,7 +7464,8 @@ static noinline int replace_extents_in_leaf(struct btrfs_trans_handle *trans, ...@@ -7423,7 +7464,8 @@ static noinline int replace_extents_in_leaf(struct btrfs_trans_handle *trans,
int ret; int ret;
new_extent = kmalloc(sizeof(*new_extent), GFP_NOFS); new_extent = kmalloc(sizeof(*new_extent), GFP_NOFS);
BUG_ON(!new_extent); if (!new_extent)
return -ENOMEM;
ref = btrfs_lookup_leaf_ref(root, leaf->start); ref = btrfs_lookup_leaf_ref(root, leaf->start);
BUG_ON(!ref); BUG_ON(!ref);
...@@ -7609,7 +7651,8 @@ int btrfs_cleanup_reloc_trees(struct btrfs_root *root) ...@@ -7609,7 +7651,8 @@ int btrfs_cleanup_reloc_trees(struct btrfs_root *root)
reloc_root = btrfs_read_fs_root_no_name(root->fs_info, &location); reloc_root = btrfs_read_fs_root_no_name(root->fs_info, &location);
BUG_ON(!reloc_root); BUG_ON(!reloc_root);
btrfs_orphan_cleanup(reloc_root); ret = btrfs_orphan_cleanup(reloc_root);
BUG_ON(ret);
return 0; return 0;
} }
...@@ -7627,7 +7670,8 @@ static noinline int init_reloc_tree(struct btrfs_trans_handle *trans, ...@@ -7627,7 +7670,8 @@ static noinline int init_reloc_tree(struct btrfs_trans_handle *trans,
return 0; return 0;
root_item = kmalloc(sizeof(*root_item), GFP_NOFS); root_item = kmalloc(sizeof(*root_item), GFP_NOFS);
BUG_ON(!root_item); if (!root_item)
return -ENOMEM;
ret = btrfs_copy_root(trans, root, root->commit_root, ret = btrfs_copy_root(trans, root, root->commit_root,
&eb, BTRFS_TREE_RELOC_OBJECTID); &eb, BTRFS_TREE_RELOC_OBJECTID);
...@@ -7653,7 +7697,7 @@ static noinline int init_reloc_tree(struct btrfs_trans_handle *trans, ...@@ -7653,7 +7697,7 @@ static noinline int init_reloc_tree(struct btrfs_trans_handle *trans,
reloc_root = btrfs_read_fs_root_no_radix(root->fs_info->tree_root, reloc_root = btrfs_read_fs_root_no_radix(root->fs_info->tree_root,
&root_key); &root_key);
BUG_ON(!reloc_root); BUG_ON(IS_ERR(reloc_root));
reloc_root->last_trans = trans->transid; reloc_root->last_trans = trans->transid;
reloc_root->commit_root = NULL; reloc_root->commit_root = NULL;
reloc_root->ref_tree = &root->fs_info->reloc_ref_tree; reloc_root->ref_tree = &root->fs_info->reloc_ref_tree;
...@@ -7906,6 +7950,10 @@ static noinline int relocate_one_extent(struct btrfs_root *extent_root, ...@@ -7906,6 +7950,10 @@ static noinline int relocate_one_extent(struct btrfs_root *extent_root,
eb = read_tree_block(found_root, block_start, eb = read_tree_block(found_root, block_start,
block_size, 0); block_size, 0);
if (!eb) {
ret = -EIO;
goto out;
}
btrfs_tree_lock(eb); btrfs_tree_lock(eb);
BUG_ON(level != btrfs_header_level(eb)); BUG_ON(level != btrfs_header_level(eb));
...@@ -8621,6 +8669,12 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, ...@@ -8621,6 +8669,12 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
BUG_ON(!block_group); BUG_ON(!block_group);
BUG_ON(!block_group->ro); BUG_ON(!block_group->ro);
/*
* Free the reserved super bytes from this block group before
* remove it.
*/
free_excluded_extents(root, block_group);
memcpy(&key, &block_group->key, sizeof(key)); memcpy(&key, &block_group->key, sizeof(key));
if (block_group->flags & (BTRFS_BLOCK_GROUP_DUP | if (block_group->flags & (BTRFS_BLOCK_GROUP_DUP |
BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID1 |
...@@ -8724,13 +8778,84 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, ...@@ -8724,13 +8778,84 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
return ret; return ret;
} }
int btrfs_init_space_info(struct btrfs_fs_info *fs_info)
{
struct btrfs_space_info *space_info;
int ret;
ret = update_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM, 0, 0,
&space_info);
if (ret)
return ret;
ret = update_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA, 0, 0,
&space_info);
if (ret)
return ret;
ret = update_space_info(fs_info, BTRFS_BLOCK_GROUP_DATA, 0, 0,
&space_info);
if (ret)
return ret;
return ret;
}
int btrfs_error_unpin_extent_range(struct btrfs_root *root, u64 start, u64 end) int btrfs_error_unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
{ {
return unpin_extent_range(root, start, end); return unpin_extent_range(root, start, end);
} }
int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr, int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr,
u64 num_bytes) u64 num_bytes, u64 *actual_bytes)
{
return btrfs_discard_extent(root, bytenr, num_bytes, actual_bytes);
}
int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range)
{ {
return btrfs_discard_extent(root, bytenr, num_bytes); struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_block_group_cache *cache = NULL;
u64 group_trimmed;
u64 start;
u64 end;
u64 trimmed = 0;
int ret = 0;
cache = btrfs_lookup_block_group(fs_info, range->start);
while (cache) {
if (cache->key.objectid >= (range->start + range->len)) {
btrfs_put_block_group(cache);
break;
}
start = max(range->start, cache->key.objectid);
end = min(range->start + range->len,
cache->key.objectid + cache->key.offset);
if (end - start >= range->minlen) {
if (!block_group_cache_done(cache)) {
ret = cache_block_group(cache, NULL, root, 0);
if (!ret)
wait_block_group_cache_done(cache);
}
ret = btrfs_trim_block_group(cache,
&group_trimmed,
start,
end,
range->minlen);
trimmed += group_trimmed;
if (ret) {
btrfs_put_block_group(cache);
break;
}
}
cache = next_block_group(fs_info->tree_root, cache);
}
range->len = trimmed;
return ret;
} }
...@@ -2192,6 +2192,8 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, ...@@ -2192,6 +2192,8 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
else else
write_flags = WRITE; write_flags = WRITE;
trace___extent_writepage(page, inode, wbc);
WARN_ON(!PageLocked(page)); WARN_ON(!PageLocked(page));
pg_offset = i_size & (PAGE_CACHE_SIZE - 1); pg_offset = i_size & (PAGE_CACHE_SIZE - 1);
if (page->index > end_index || if (page->index > end_index ||
...@@ -3690,6 +3692,7 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start, ...@@ -3690,6 +3692,7 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
"wanted %lu %lu\n", (unsigned long long)eb->start, "wanted %lu %lu\n", (unsigned long long)eb->start,
eb->len, start, min_len); eb->len, start, min_len);
WARN_ON(1); WARN_ON(1);
return -EINVAL;
} }
p = extent_buffer_page(eb, i); p = extent_buffer_page(eb, i);
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#define EXTENT_BUFFER_UPTODATE 0 #define EXTENT_BUFFER_UPTODATE 0
#define EXTENT_BUFFER_BLOCKING 1 #define EXTENT_BUFFER_BLOCKING 1
#define EXTENT_BUFFER_DIRTY 2 #define EXTENT_BUFFER_DIRTY 2
#define EXTENT_BUFFER_CORRUPT 3
/* these are flags for extent_clear_unlock_delalloc */ /* these are flags for extent_clear_unlock_delalloc */
#define EXTENT_CLEAR_UNLOCK_PAGE 0x1 #define EXTENT_CLEAR_UNLOCK_PAGE 0x1
......
...@@ -48,7 +48,8 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, ...@@ -48,7 +48,8 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
struct extent_buffer *leaf; struct extent_buffer *leaf;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
BUG_ON(!path); if (!path)
return -ENOMEM;
file_key.objectid = objectid; file_key.objectid = objectid;
file_key.offset = pos; file_key.offset = pos;
btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
...@@ -169,6 +170,8 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, ...@@ -169,6 +170,8 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
if (bio->bi_size > PAGE_CACHE_SIZE * 8) if (bio->bi_size > PAGE_CACHE_SIZE * 8)
path->reada = 2; path->reada = 2;
......
...@@ -45,14 +45,14 @@ ...@@ -45,14 +45,14 @@
* and be replaced with calls into generic code. * and be replaced with calls into generic code.
*/ */
static noinline int btrfs_copy_from_user(loff_t pos, int num_pages, static noinline int btrfs_copy_from_user(loff_t pos, int num_pages,
int write_bytes, size_t write_bytes,
struct page **prepared_pages, struct page **prepared_pages,
struct iov_iter *i) struct iov_iter *i)
{ {
size_t copied = 0; size_t copied = 0;
size_t total_copied = 0;
int pg = 0; int pg = 0;
int offset = pos & (PAGE_CACHE_SIZE - 1); int offset = pos & (PAGE_CACHE_SIZE - 1);
int total_copied = 0;
while (write_bytes > 0) { while (write_bytes > 0) {
size_t count = min_t(size_t, size_t count = min_t(size_t,
...@@ -88,9 +88,8 @@ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages, ...@@ -88,9 +88,8 @@ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages,
total_copied += copied; total_copied += copied;
/* Return to btrfs_file_aio_write to fault page */ /* Return to btrfs_file_aio_write to fault page */
if (unlikely(copied == 0)) { if (unlikely(copied == 0))
break; break;
}
if (unlikely(copied < PAGE_CACHE_SIZE - offset)) { if (unlikely(copied < PAGE_CACHE_SIZE - offset)) {
offset += copied; offset += copied;
...@@ -109,8 +108,6 @@ static noinline void btrfs_drop_pages(struct page **pages, size_t num_pages) ...@@ -109,8 +108,6 @@ static noinline void btrfs_drop_pages(struct page **pages, size_t num_pages)
{ {
size_t i; size_t i;
for (i = 0; i < num_pages; i++) { for (i = 0; i < num_pages; i++) {
if (!pages[i])
break;
/* page checked is some magic around finding pages that /* page checked is some magic around finding pages that
* have been modified without going through btrfs_set_page_dirty * have been modified without going through btrfs_set_page_dirty
* clear it here * clear it here
...@@ -130,13 +127,12 @@ static noinline void btrfs_drop_pages(struct page **pages, size_t num_pages) ...@@ -130,13 +127,12 @@ static noinline void btrfs_drop_pages(struct page **pages, size_t num_pages)
* this also makes the decision about creating an inline extent vs * this also makes the decision about creating an inline extent vs
* doing real data extents, marking pages dirty and delalloc as required. * doing real data extents, marking pages dirty and delalloc as required.
*/ */
static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans, static noinline int dirty_and_release_pages(struct btrfs_root *root,
struct btrfs_root *root, struct file *file,
struct file *file, struct page **pages,
struct page **pages, size_t num_pages,
size_t num_pages, loff_t pos,
loff_t pos, size_t write_bytes)
size_t write_bytes)
{ {
int err = 0; int err = 0;
int i; int i;
...@@ -154,7 +150,8 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -154,7 +150,8 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans,
end_of_last_block = start_pos + num_bytes - 1; end_of_last_block = start_pos + num_bytes - 1;
err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block, err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block,
NULL); NULL);
BUG_ON(err); 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];
...@@ -162,13 +159,14 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -162,13 +159,14 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans,
ClearPageChecked(p); ClearPageChecked(p);
set_page_dirty(p); set_page_dirty(p);
} }
if (end_pos > isize) {
/*
* we've only changed i_size in ram, and we haven't updated
* the disk i_size. There is no need to log the inode
* at this time.
*/
if (end_pos > isize)
i_size_write(inode, end_pos); i_size_write(inode, end_pos);
/* we've only changed i_size in ram, and we haven't updated
* the disk i_size. There is no need to log the inode
* at this time.
*/
}
return 0; return 0;
} }
...@@ -610,6 +608,8 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -610,6 +608,8 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
key.offset = split; key.offset = split;
ret = btrfs_search_slot(trans, root, &key, path, -1, 1); ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
if (ret < 0)
goto out;
if (ret > 0 && path->slots[0] > 0) if (ret > 0 && path->slots[0] > 0)
path->slots[0]--; path->slots[0]--;
...@@ -819,12 +819,11 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file, ...@@ -819,12 +819,11 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
last_pos = ((u64)index + num_pages) << PAGE_CACHE_SHIFT; last_pos = ((u64)index + num_pages) << PAGE_CACHE_SHIFT;
if (start_pos > inode->i_size) { if (start_pos > inode->i_size) {
err = btrfs_cont_expand(inode, start_pos); err = btrfs_cont_expand(inode, i_size_read(inode), start_pos);
if (err) if (err)
return err; return err;
} }
memset(pages, 0, num_pages * sizeof(struct page *));
again: again:
for (i = 0; i < num_pages; i++) { for (i = 0; i < num_pages; i++) {
pages[i] = grab_cache_page(inode->i_mapping, index + i); pages[i] = grab_cache_page(inode->i_mapping, index + i);
...@@ -896,156 +895,71 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file, ...@@ -896,156 +895,71 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
} }
static ssize_t btrfs_file_aio_write(struct kiocb *iocb, static noinline ssize_t __btrfs_buffered_write(struct file *file,
const struct iovec *iov, struct iov_iter *i,
unsigned long nr_segs, loff_t pos) loff_t pos)
{ {
struct file *file = iocb->ki_filp;
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 page **pages = NULL; struct page **pages = NULL;
struct iov_iter i;
loff_t *ppos = &iocb->ki_pos;
loff_t start_pos;
ssize_t num_written = 0;
ssize_t err = 0;
size_t count;
size_t ocount;
int ret = 0;
int nrptrs;
unsigned long first_index; unsigned long first_index;
unsigned long last_index; unsigned long last_index;
int will_write; size_t num_written = 0;
int buffered = 0; int nrptrs;
int copied = 0; int ret;
int dirty_pages = 0;
will_write = ((file->f_flags & O_DSYNC) || IS_SYNC(inode) ||
(file->f_flags & O_DIRECT));
start_pos = pos;
vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
mutex_lock(&inode->i_mutex);
err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
if (err)
goto out;
count = ocount;
current->backing_dev_info = inode->i_mapping->backing_dev_info;
err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode));
if (err)
goto out;
if (count == 0)
goto out;
err = file_remove_suid(file);
if (err)
goto out;
/*
* If BTRFS flips readonly due to some impossible error
* (fs_info->fs_state now has BTRFS_SUPER_FLAG_ERROR),
* although we have opened a file as writable, we have
* to stop this write operation to ensure FS consistency.
*/
if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
err = -EROFS;
goto out;
}
file_update_time(file);
BTRFS_I(inode)->sequence++;
if (unlikely(file->f_flags & O_DIRECT)) {
num_written = generic_file_direct_write(iocb, iov, &nr_segs,
pos, ppos, count,
ocount);
/*
* the generic O_DIRECT will update in-memory i_size after the
* DIOs are done. But our endio handlers that update the on
* disk i_size never update past the in memory i_size. So we
* need one more update here to catch any additions to the
* file
*/
if (inode->i_size != BTRFS_I(inode)->disk_i_size) {
btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
mark_inode_dirty(inode);
}
if (num_written < 0) {
ret = num_written;
num_written = 0;
goto out;
} else if (num_written == count) {
/* pick up pos changes done by the generic code */
pos = *ppos;
goto out;
}
/*
* We are going to do buffered for the rest of the range, so we
* need to make sure to invalidate the buffered pages when we're
* done.
*/
buffered = 1;
pos += num_written;
}
iov_iter_init(&i, iov, nr_segs, count, num_written); nrptrs = min((iov_iter_count(i) + PAGE_CACHE_SIZE - 1) /
nrptrs = min((iov_iter_count(&i) + PAGE_CACHE_SIZE - 1) /
PAGE_CACHE_SIZE, PAGE_CACHE_SIZE / PAGE_CACHE_SIZE, PAGE_CACHE_SIZE /
(sizeof(struct page *))); (sizeof(struct page *)));
pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL); pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL);
if (!pages) { if (!pages)
ret = -ENOMEM; return -ENOMEM;
goto out;
}
/* generic_write_checks can change our pos */
start_pos = pos;
first_index = pos >> PAGE_CACHE_SHIFT; first_index = pos >> PAGE_CACHE_SHIFT;
last_index = (pos + iov_iter_count(&i)) >> PAGE_CACHE_SHIFT; last_index = (pos + iov_iter_count(i)) >> PAGE_CACHE_SHIFT;
while (iov_iter_count(&i) > 0) { while (iov_iter_count(i) > 0) {
size_t offset = pos & (PAGE_CACHE_SIZE - 1); size_t offset = pos & (PAGE_CACHE_SIZE - 1);
size_t write_bytes = min(iov_iter_count(&i), size_t write_bytes = min(iov_iter_count(i),
nrptrs * (size_t)PAGE_CACHE_SIZE - nrptrs * (size_t)PAGE_CACHE_SIZE -
offset); offset);
size_t num_pages = (write_bytes + offset + size_t num_pages = (write_bytes + offset +
PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
size_t dirty_pages;
size_t copied;
WARN_ON(num_pages > nrptrs); WARN_ON(num_pages > nrptrs);
memset(pages, 0, sizeof(struct page *) * nrptrs);
/* /*
* Fault pages before locking them in prepare_pages * Fault pages before locking them in prepare_pages
* to avoid recursive lock * to avoid recursive lock
*/ */
if (unlikely(iov_iter_fault_in_readable(&i, write_bytes))) { if (unlikely(iov_iter_fault_in_readable(i, write_bytes))) {
ret = -EFAULT; ret = -EFAULT;
goto out; break;
} }
ret = btrfs_delalloc_reserve_space(inode, ret = btrfs_delalloc_reserve_space(inode,
num_pages << PAGE_CACHE_SHIFT); num_pages << PAGE_CACHE_SHIFT);
if (ret) if (ret)
goto out; break;
/*
* This is going to setup the pages array with the number of
* pages we want, so we don't really need to worry about the
* contents of pages from loop to loop
*/
ret = prepare_pages(root, file, pages, num_pages, ret = prepare_pages(root, file, pages, num_pages,
pos, first_index, last_index, pos, first_index, last_index,
write_bytes); write_bytes);
if (ret) { if (ret) {
btrfs_delalloc_release_space(inode, btrfs_delalloc_release_space(inode,
num_pages << PAGE_CACHE_SHIFT); num_pages << PAGE_CACHE_SHIFT);
goto out; break;
} }
copied = btrfs_copy_from_user(pos, num_pages, copied = btrfs_copy_from_user(pos, num_pages,
write_bytes, pages, &i); write_bytes, pages, i);
/* /*
* if we have trouble faulting in the pages, fall * if we have trouble faulting in the pages, fall
...@@ -1061,6 +975,13 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, ...@@ -1061,6 +975,13 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT; PAGE_CACHE_SHIFT;
/*
* If we had a short copy we need to release the excess delaloc
* bytes we reserved. We need to increment outstanding_extents
* because btrfs_delalloc_release_space will decrement it, but
* we still have an outstanding extent for the chunk we actually
* managed to copy.
*/
if (num_pages > dirty_pages) { if (num_pages > dirty_pages) {
if (copied > 0) if (copied > 0)
atomic_inc( atomic_inc(
...@@ -1071,39 +992,157 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, ...@@ -1071,39 +992,157 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
} }
if (copied > 0) { if (copied > 0) {
dirty_and_release_pages(NULL, root, file, pages, ret = dirty_and_release_pages(root, file, pages,
dirty_pages, pos, copied); dirty_pages, pos,
copied);
if (ret) {
btrfs_delalloc_release_space(inode,
dirty_pages << PAGE_CACHE_SHIFT);
btrfs_drop_pages(pages, num_pages);
break;
}
} }
btrfs_drop_pages(pages, num_pages); btrfs_drop_pages(pages, num_pages);
if (copied > 0) { cond_resched();
if (will_write) {
filemap_fdatawrite_range(inode->i_mapping, pos, balance_dirty_pages_ratelimited_nr(inode->i_mapping,
pos + copied - 1); dirty_pages);
} else { if (dirty_pages < (root->leafsize >> PAGE_CACHE_SHIFT) + 1)
balance_dirty_pages_ratelimited_nr( btrfs_btree_balance_dirty(root, 1);
inode->i_mapping, btrfs_throttle(root);
dirty_pages);
if (dirty_pages <
(root->leafsize >> PAGE_CACHE_SHIFT) + 1)
btrfs_btree_balance_dirty(root, 1);
btrfs_throttle(root);
}
}
pos += copied; pos += copied;
num_written += copied; num_written += copied;
}
cond_resched(); kfree(pages);
return num_written ? num_written : ret;
}
static ssize_t __btrfs_direct_write(struct kiocb *iocb,
const struct iovec *iov,
unsigned long nr_segs, loff_t pos,
loff_t *ppos, size_t count, size_t ocount)
{
struct file *file = iocb->ki_filp;
struct inode *inode = fdentry(file)->d_inode;
struct iov_iter i;
ssize_t written;
ssize_t written_buffered;
loff_t endbyte;
int err;
written = generic_file_direct_write(iocb, iov, &nr_segs, pos, ppos,
count, ocount);
/*
* the generic O_DIRECT will update in-memory i_size after the
* DIOs are done. But our endio handlers that update the on
* disk i_size never update past the in memory i_size. So we
* need one more update here to catch any additions to the
* file
*/
if (inode->i_size != BTRFS_I(inode)->disk_i_size) {
btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
mark_inode_dirty(inode);
} }
if (written < 0 || written == count)
return written;
pos += written;
count -= written;
iov_iter_init(&i, iov, nr_segs, count, written);
written_buffered = __btrfs_buffered_write(file, &i, pos);
if (written_buffered < 0) {
err = written_buffered;
goto out;
}
endbyte = pos + written_buffered - 1;
err = filemap_write_and_wait_range(file->f_mapping, pos, endbyte);
if (err)
goto out;
written += written_buffered;
*ppos = pos + written_buffered;
invalidate_mapping_pages(file->f_mapping, pos >> PAGE_CACHE_SHIFT,
endbyte >> PAGE_CACHE_SHIFT);
out: out:
mutex_unlock(&inode->i_mutex); return written ? written : err;
if (ret) }
err = ret;
kfree(pages); static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
*ppos = pos; const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
struct file *file = iocb->ki_filp;
struct inode *inode = fdentry(file)->d_inode;
struct btrfs_root *root = BTRFS_I(inode)->root;
loff_t *ppos = &iocb->ki_pos;
ssize_t num_written = 0;
ssize_t err = 0;
size_t count, ocount;
vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
mutex_lock(&inode->i_mutex);
err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
if (err) {
mutex_unlock(&inode->i_mutex);
goto out;
}
count = ocount;
current->backing_dev_info = inode->i_mapping->backing_dev_info;
err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode));
if (err) {
mutex_unlock(&inode->i_mutex);
goto out;
}
if (count == 0) {
mutex_unlock(&inode->i_mutex);
goto out;
}
err = file_remove_suid(file);
if (err) {
mutex_unlock(&inode->i_mutex);
goto out;
}
/*
* If BTRFS flips readonly due to some impossible error
* (fs_info->fs_state now has BTRFS_SUPER_FLAG_ERROR),
* although we have opened a file as writable, we have
* to stop this write operation to ensure FS consistency.
*/
if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
mutex_unlock(&inode->i_mutex);
err = -EROFS;
goto out;
}
file_update_time(file);
BTRFS_I(inode)->sequence++;
if (unlikely(file->f_flags & O_DIRECT)) {
num_written = __btrfs_direct_write(iocb, iov, nr_segs,
pos, ppos, count, ocount);
} else {
struct iov_iter i;
iov_iter_init(&i, iov, nr_segs, count, num_written);
num_written = __btrfs_buffered_write(file, &i, pos);
if (num_written > 0)
*ppos = pos + num_written;
}
mutex_unlock(&inode->i_mutex);
/* /*
* we want to make sure fsync finds this change * we want to make sure fsync finds this change
...@@ -1118,43 +1157,12 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, ...@@ -1118,43 +1157,12 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
* one running right now. * one running right now.
*/ */
BTRFS_I(inode)->last_trans = root->fs_info->generation + 1; BTRFS_I(inode)->last_trans = root->fs_info->generation + 1;
if (num_written > 0 || num_written == -EIOCBQUEUED) {
if (num_written > 0 && will_write) { err = generic_write_sync(file, pos, num_written);
struct btrfs_trans_handle *trans; if (err < 0 && num_written > 0)
err = btrfs_wait_ordered_range(inode, start_pos, num_written);
if (err)
num_written = err; num_written = err;
if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) {
trans = btrfs_start_transaction(root, 0);
if (IS_ERR(trans)) {
num_written = PTR_ERR(trans);
goto done;
}
mutex_lock(&inode->i_mutex);
ret = btrfs_log_dentry_safe(trans, root,
file->f_dentry);
mutex_unlock(&inode->i_mutex);
if (ret == 0) {
ret = btrfs_sync_log(trans, root);
if (ret == 0)
btrfs_end_transaction(trans, root);
else
btrfs_commit_transaction(trans, root);
} else if (ret != BTRFS_NO_LOG_SYNC) {
btrfs_commit_transaction(trans, root);
} else {
btrfs_end_transaction(trans, root);
}
}
if (file->f_flags & O_DIRECT && buffered) {
invalidate_mapping_pages(inode->i_mapping,
start_pos >> PAGE_CACHE_SHIFT,
(start_pos + num_written - 1) >> PAGE_CACHE_SHIFT);
}
} }
done: out:
current->backing_dev_info = NULL; current->backing_dev_info = NULL;
return num_written ? num_written : err; return num_written ? num_written : err;
} }
...@@ -1197,6 +1205,7 @@ int btrfs_sync_file(struct file *file, int datasync) ...@@ -1197,6 +1205,7 @@ int btrfs_sync_file(struct file *file, int datasync)
int ret = 0; int ret = 0;
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
trace_btrfs_sync_file(file, datasync);
/* we wait first, since the writeback may change the inode */ /* we wait first, since the writeback may change the inode */
root->log_batch++; root->log_batch++;
...@@ -1324,7 +1333,8 @@ static long btrfs_fallocate(struct file *file, int mode, ...@@ -1324,7 +1333,8 @@ static long btrfs_fallocate(struct file *file, int mode,
goto out; goto out;
if (alloc_start > inode->i_size) { if (alloc_start > inode->i_size) {
ret = btrfs_cont_expand(inode, alloc_start); ret = btrfs_cont_expand(inode, i_size_read(inode),
alloc_start);
if (ret) if (ret)
goto out; goto out;
} }
......
此差异已折叠。
...@@ -68,4 +68,6 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group, ...@@ -68,4 +68,6 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
int btrfs_return_cluster_to_free_space( int btrfs_return_cluster_to_free_space(
struct btrfs_block_group_cache *block_group, struct btrfs_block_group_cache *block_group,
struct btrfs_free_cluster *cluster); struct btrfs_free_cluster *cluster);
int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
u64 *trimmed, u64 start, u64 end, u64 minlen);
#endif #endif
...@@ -30,7 +30,8 @@ int btrfs_find_highest_inode(struct btrfs_root *root, u64 *objectid) ...@@ -30,7 +30,8 @@ int btrfs_find_highest_inode(struct btrfs_root *root, u64 *objectid)
int slot; int slot;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
BUG_ON(!path); if (!path)
return -ENOMEM;
search_key.objectid = BTRFS_LAST_FREE_OBJECTID; search_key.objectid = BTRFS_LAST_FREE_OBJECTID;
search_key.type = -1; search_key.type = -1;
......
此差异已折叠。
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/blkdev.h>
#include "compat.h" #include "compat.h"
#include "ctree.h" #include "ctree.h"
#include "disk-io.h" #include "disk-io.h"
...@@ -138,6 +139,24 @@ static int btrfs_ioctl_getflags(struct file *file, void __user *arg) ...@@ -138,6 +139,24 @@ static int btrfs_ioctl_getflags(struct file *file, void __user *arg)
return 0; return 0;
} }
static int check_flags(unsigned int flags)
{
if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
FS_NOATIME_FL | FS_NODUMP_FL | \
FS_SYNC_FL | FS_DIRSYNC_FL | \
FS_NOCOMP_FL | FS_COMPR_FL | \
FS_NOCOW_FL | FS_COW_FL))
return -EOPNOTSUPP;
if ((flags & FS_NOCOMP_FL) && (flags & FS_COMPR_FL))
return -EINVAL;
if ((flags & FS_NOCOW_FL) && (flags & FS_COW_FL))
return -EINVAL;
return 0;
}
static int btrfs_ioctl_setflags(struct file *file, void __user *arg) static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
{ {
struct inode *inode = file->f_path.dentry->d_inode; struct inode *inode = file->f_path.dentry->d_inode;
...@@ -153,10 +172,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) ...@@ -153,10 +172,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
if (copy_from_user(&flags, arg, sizeof(flags))) if (copy_from_user(&flags, arg, sizeof(flags)))
return -EFAULT; return -EFAULT;
if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ ret = check_flags(flags);
FS_NOATIME_FL | FS_NODUMP_FL | \ if (ret)
FS_SYNC_FL | FS_DIRSYNC_FL)) return ret;
return -EOPNOTSUPP;
if (!inode_owner_or_capable(inode)) if (!inode_owner_or_capable(inode))
return -EACCES; return -EACCES;
...@@ -201,6 +219,22 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) ...@@ -201,6 +219,22 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
else else
ip->flags &= ~BTRFS_INODE_DIRSYNC; ip->flags &= ~BTRFS_INODE_DIRSYNC;
/*
* The COMPRESS flag can only be changed by users, while the NOCOMPRESS
* flag may be changed automatically if compression code won't make
* things smaller.
*/
if (flags & FS_NOCOMP_FL) {
ip->flags &= ~BTRFS_INODE_COMPRESS;
ip->flags |= BTRFS_INODE_NOCOMPRESS;
} else if (flags & FS_COMPR_FL) {
ip->flags |= BTRFS_INODE_COMPRESS;
ip->flags &= ~BTRFS_INODE_NOCOMPRESS;
}
if (flags & FS_NOCOW_FL)
ip->flags |= BTRFS_INODE_NODATACOW;
else if (flags & FS_COW_FL)
ip->flags &= ~BTRFS_INODE_NODATACOW;
trans = btrfs_join_transaction(root, 1); trans = btrfs_join_transaction(root, 1);
BUG_ON(IS_ERR(trans)); BUG_ON(IS_ERR(trans));
...@@ -213,9 +247,11 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) ...@@ -213,9 +247,11 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
btrfs_end_transaction(trans, root); btrfs_end_transaction(trans, root);
mnt_drop_write(file->f_path.mnt); mnt_drop_write(file->f_path.mnt);
ret = 0;
out_unlock: out_unlock:
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
return 0; return ret;
} }
static int btrfs_ioctl_getversion(struct file *file, int __user *arg) static int btrfs_ioctl_getversion(struct file *file, int __user *arg)
...@@ -225,6 +261,49 @@ static int btrfs_ioctl_getversion(struct file *file, int __user *arg) ...@@ -225,6 +261,49 @@ static int btrfs_ioctl_getversion(struct file *file, int __user *arg)
return put_user(inode->i_generation, arg); return put_user(inode->i_generation, arg);
} }
static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
{
struct btrfs_root *root = fdentry(file)->d_sb->s_fs_info;
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_device *device;
struct request_queue *q;
struct fstrim_range range;
u64 minlen = ULLONG_MAX;
u64 num_devices = 0;
int ret;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
mutex_lock(&fs_info->fs_devices->device_list_mutex);
list_for_each_entry(device, &fs_info->fs_devices->devices, dev_list) {
if (!device->bdev)
continue;
q = bdev_get_queue(device->bdev);
if (blk_queue_discard(q)) {
num_devices++;
minlen = min((u64)q->limits.discard_granularity,
minlen);
}
}
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
if (!num_devices)
return -EOPNOTSUPP;
if (copy_from_user(&range, arg, sizeof(range)))
return -EFAULT;
range.minlen = max(range.minlen, minlen);
ret = btrfs_trim_fs(root, &range);
if (ret < 0)
return ret;
if (copy_to_user(arg, &range, sizeof(range)))
return -EFAULT;
return 0;
}
static noinline int create_subvol(struct btrfs_root *root, static noinline int create_subvol(struct btrfs_root *root,
struct dentry *dentry, struct dentry *dentry,
char *name, int namelen, char *name, int namelen,
...@@ -409,7 +488,9 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, ...@@ -409,7 +488,9 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
if (ret) if (ret)
goto fail; goto fail;
btrfs_orphan_cleanup(pending_snapshot->snap); ret = btrfs_orphan_cleanup(pending_snapshot->snap);
if (ret)
goto fail;
parent = dget_parent(dentry); parent = dget_parent(dentry);
inode = btrfs_lookup_dentry(parent->d_inode, dentry); inode = btrfs_lookup_dentry(parent->d_inode, dentry);
...@@ -2348,12 +2429,15 @@ static noinline long btrfs_ioctl_start_sync(struct file *file, void __user *argp ...@@ -2348,12 +2429,15 @@ static noinline long btrfs_ioctl_start_sync(struct file *file, void __user *argp
struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root; struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root;
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
u64 transid; u64 transid;
int ret;
trans = btrfs_start_transaction(root, 0); trans = btrfs_start_transaction(root, 0);
if (IS_ERR(trans)) if (IS_ERR(trans))
return PTR_ERR(trans); return PTR_ERR(trans);
transid = trans->transid; transid = trans->transid;
btrfs_commit_transaction_async(trans, root, 0); ret = btrfs_commit_transaction_async(trans, root, 0);
if (ret)
return ret;
if (argp) if (argp)
if (copy_to_user(argp, &transid, sizeof(transid))) if (copy_to_user(argp, &transid, sizeof(transid)))
...@@ -2388,6 +2472,8 @@ long btrfs_ioctl(struct file *file, unsigned int ...@@ -2388,6 +2472,8 @@ long btrfs_ioctl(struct file *file, unsigned int
return btrfs_ioctl_setflags(file, argp); return btrfs_ioctl_setflags(file, argp);
case FS_IOC_GETVERSION: case FS_IOC_GETVERSION:
return btrfs_ioctl_getversion(file, argp); return btrfs_ioctl_getversion(file, argp);
case FITRIM:
return btrfs_ioctl_fitrim(file, argp);
case BTRFS_IOC_SNAP_CREATE: case BTRFS_IOC_SNAP_CREATE:
return btrfs_ioctl_snap_create(file, argp, 0); return btrfs_ioctl_snap_create(file, argp, 0);
case BTRFS_IOC_SNAP_CREATE_V2: case BTRFS_IOC_SNAP_CREATE_V2:
......
...@@ -202,6 +202,8 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, ...@@ -202,6 +202,8 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
INIT_LIST_HEAD(&entry->list); INIT_LIST_HEAD(&entry->list);
INIT_LIST_HEAD(&entry->root_extent_list); INIT_LIST_HEAD(&entry->root_extent_list);
trace_btrfs_ordered_extent_add(inode, entry);
spin_lock(&tree->lock); spin_lock(&tree->lock);
node = tree_insert(&tree->tree, file_offset, node = tree_insert(&tree->tree, file_offset,
&entry->rb_node); &entry->rb_node);
...@@ -387,6 +389,8 @@ int btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry) ...@@ -387,6 +389,8 @@ int btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry)
struct list_head *cur; struct list_head *cur;
struct btrfs_ordered_sum *sum; struct btrfs_ordered_sum *sum;
trace_btrfs_ordered_extent_put(entry->inode, entry);
if (atomic_dec_and_test(&entry->refs)) { if (atomic_dec_and_test(&entry->refs)) {
while (!list_empty(&entry->list)) { while (!list_empty(&entry->list)) {
cur = entry->list.next; cur = entry->list.next;
...@@ -420,6 +424,8 @@ static int __btrfs_remove_ordered_extent(struct inode *inode, ...@@ -420,6 +424,8 @@ static int __btrfs_remove_ordered_extent(struct inode *inode,
spin_lock(&root->fs_info->ordered_extent_lock); spin_lock(&root->fs_info->ordered_extent_lock);
list_del_init(&entry->root_extent_list); list_del_init(&entry->root_extent_list);
trace_btrfs_ordered_extent_remove(inode, entry);
/* /*
* we have no more ordered extents for this inode and * we have no more ordered extents for this inode and
* no dirty pages. We can safely remove it from the * no dirty pages. We can safely remove it from the
...@@ -585,6 +591,8 @@ void btrfs_start_ordered_extent(struct inode *inode, ...@@ -585,6 +591,8 @@ void btrfs_start_ordered_extent(struct inode *inode,
u64 start = entry->file_offset; u64 start = entry->file_offset;
u64 end = start + entry->len - 1; u64 end = start + entry->len - 1;
trace_btrfs_ordered_extent_start(inode, entry);
/* /*
* pages in the range can be dirty, clean or writeback. We * pages in the range can be dirty, clean or writeback. We
* 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
......
...@@ -1724,6 +1724,7 @@ int replace_path(struct btrfs_trans_handle *trans, ...@@ -1724,6 +1724,7 @@ int replace_path(struct btrfs_trans_handle *trans,
eb = read_tree_block(dest, old_bytenr, blocksize, eb = read_tree_block(dest, old_bytenr, blocksize,
old_ptr_gen); old_ptr_gen);
BUG_ON(!eb);
btrfs_tree_lock(eb); btrfs_tree_lock(eb);
if (cow) { if (cow) {
ret = btrfs_cow_block(trans, dest, eb, parent, ret = btrfs_cow_block(trans, dest, eb, parent,
...@@ -2513,6 +2514,10 @@ static int do_relocation(struct btrfs_trans_handle *trans, ...@@ -2513,6 +2514,10 @@ static int do_relocation(struct btrfs_trans_handle *trans,
blocksize = btrfs_level_size(root, node->level); blocksize = btrfs_level_size(root, node->level);
generation = btrfs_node_ptr_generation(upper->eb, slot); generation = btrfs_node_ptr_generation(upper->eb, slot);
eb = read_tree_block(root, bytenr, blocksize, generation); eb = read_tree_block(root, bytenr, blocksize, generation);
if (!eb) {
err = -EIO;
goto next;
}
btrfs_tree_lock(eb); btrfs_tree_lock(eb);
btrfs_set_lock_blocking(eb); btrfs_set_lock_blocking(eb);
...@@ -2670,6 +2675,7 @@ static int get_tree_block_key(struct reloc_control *rc, ...@@ -2670,6 +2675,7 @@ static int get_tree_block_key(struct reloc_control *rc,
BUG_ON(block->key_ready); BUG_ON(block->key_ready);
eb = read_tree_block(rc->extent_root, block->bytenr, eb = read_tree_block(rc->extent_root, block->bytenr,
block->key.objectid, block->key.offset); block->key.objectid, block->key.offset);
BUG_ON(!eb);
WARN_ON(btrfs_header_level(eb) != block->level); WARN_ON(btrfs_header_level(eb) != block->level);
if (block->level == 0) if (block->level == 0)
btrfs_item_key_to_cpu(eb, &block->key, 0); btrfs_item_key_to_cpu(eb, &block->key, 0);
...@@ -4209,7 +4215,7 @@ int btrfs_recover_relocation(struct btrfs_root *root) ...@@ -4209,7 +4215,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
if (IS_ERR(fs_root)) if (IS_ERR(fs_root))
err = PTR_ERR(fs_root); err = PTR_ERR(fs_root);
else else
btrfs_orphan_cleanup(fs_root); err = btrfs_orphan_cleanup(fs_root);
} }
return err; return err;
} }
......
...@@ -88,7 +88,8 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, ...@@ -88,7 +88,8 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
search_key.offset = (u64)-1; search_key.offset = (u64)-1;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
BUG_ON(!path); if (!path)
return -ENOMEM;
ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -332,7 +333,8 @@ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, ...@@ -332,7 +333,8 @@ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct extent_buffer *leaf; struct extent_buffer *leaf;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
BUG_ON(!path); if (!path)
return -ENOMEM;
ret = btrfs_search_slot(trans, root, key, path, -1, 1); ret = btrfs_search_slot(trans, root, key, path, -1, 1);
if (ret < 0) if (ret < 0)
goto out; goto out;
......
...@@ -52,6 +52,9 @@ ...@@ -52,6 +52,9 @@
#include "export.h" #include "export.h"
#include "compression.h" #include "compression.h"
#define CREATE_TRACE_POINTS
#include <trace/events/btrfs.h>
static const struct super_operations btrfs_super_ops; static const struct super_operations btrfs_super_ops;
static const char *btrfs_decode_error(struct btrfs_fs_info *fs_info, int errno, static const char *btrfs_decode_error(struct btrfs_fs_info *fs_info, int errno,
...@@ -620,6 +623,8 @@ int btrfs_sync_fs(struct super_block *sb, int wait) ...@@ -620,6 +623,8 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
struct btrfs_root *root = btrfs_sb(sb); struct btrfs_root *root = btrfs_sb(sb);
int ret; int ret;
trace_btrfs_sync_fs(wait);
if (!wait) { if (!wait) {
filemap_flush(root->fs_info->btree_inode->i_mapping); filemap_flush(root->fs_info->btree_inode->i_mapping);
return 0; return 0;
......
...@@ -57,7 +57,8 @@ static noinline int join_transaction(struct btrfs_root *root) ...@@ -57,7 +57,8 @@ static noinline int join_transaction(struct btrfs_root *root)
if (!cur_trans) { if (!cur_trans) {
cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, cur_trans = kmem_cache_alloc(btrfs_transaction_cachep,
GFP_NOFS); GFP_NOFS);
BUG_ON(!cur_trans); if (!cur_trans)
return -ENOMEM;
root->fs_info->generation++; root->fs_info->generation++;
cur_trans->num_writers = 1; cur_trans->num_writers = 1;
cur_trans->num_joined = 0; cur_trans->num_joined = 0;
...@@ -195,7 +196,11 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, ...@@ -195,7 +196,11 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
wait_current_trans(root); wait_current_trans(root);
ret = join_transaction(root); ret = join_transaction(root);
BUG_ON(ret); if (ret < 0) {
if (type != TRANS_JOIN_NOLOCK)
mutex_unlock(&root->fs_info->trans_mutex);
return ERR_PTR(ret);
}
cur_trans = root->fs_info->running_transaction; cur_trans = root->fs_info->running_transaction;
cur_trans->use_count++; cur_trans->use_count++;
...@@ -1156,7 +1161,8 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, ...@@ -1156,7 +1161,8 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
struct btrfs_transaction *cur_trans; struct btrfs_transaction *cur_trans;
ac = kmalloc(sizeof(*ac), GFP_NOFS); ac = kmalloc(sizeof(*ac), GFP_NOFS);
BUG_ON(!ac); if (!ac)
return -ENOMEM;
INIT_DELAYED_WORK(&ac->work, do_async_commit); INIT_DELAYED_WORK(&ac->work, do_async_commit);
ac->root = root; ac->root = root;
...@@ -1389,6 +1395,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -1389,6 +1395,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
put_transaction(cur_trans); put_transaction(cur_trans);
put_transaction(cur_trans); put_transaction(cur_trans);
trace_btrfs_transaction_commit(root);
mutex_unlock(&root->fs_info->trans_mutex); mutex_unlock(&root->fs_info->trans_mutex);
if (current->journal_info == trans) if (current->journal_info == trans)
......
...@@ -799,12 +799,12 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, ...@@ -799,12 +799,12 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
struct inode *dir; struct inode *dir;
int ret; int ret;
struct btrfs_inode_ref *ref; struct btrfs_inode_ref *ref;
struct btrfs_dir_item *di;
struct inode *inode; struct inode *inode;
char *name; char *name;
int namelen; int namelen;
unsigned long ref_ptr; unsigned long ref_ptr;
unsigned long ref_end; unsigned long ref_end;
int search_done = 0;
/* /*
* it is possible that we didn't log all the parent directories * it is possible that we didn't log all the parent directories
...@@ -845,7 +845,10 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, ...@@ -845,7 +845,10 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
* existing back reference, and we don't want to create * existing back reference, and we don't want to create
* dangling pointers in the directory. * dangling pointers in the directory.
*/ */
conflict_again:
if (search_done)
goto insert;
ret = btrfs_search_slot(NULL, root, key, path, 0, 0); ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
if (ret == 0) { if (ret == 0) {
char *victim_name; char *victim_name;
...@@ -886,37 +889,21 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, ...@@ -886,37 +889,21 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
ret = btrfs_unlink_inode(trans, root, dir, ret = btrfs_unlink_inode(trans, root, dir,
inode, victim_name, inode, victim_name,
victim_name_len); victim_name_len);
kfree(victim_name);
btrfs_release_path(root, path);
goto conflict_again;
} }
kfree(victim_name); kfree(victim_name);
ptr = (unsigned long)(victim_ref + 1) + victim_name_len; ptr = (unsigned long)(victim_ref + 1) + victim_name_len;
} }
BUG_ON(ret); BUG_ON(ret);
}
btrfs_release_path(root, path);
/* look for a conflicting sequence number */
di = btrfs_lookup_dir_index_item(trans, root, path, dir->i_ino,
btrfs_inode_ref_index(eb, ref),
name, namelen, 0);
if (di && !IS_ERR(di)) {
ret = drop_one_dir_item(trans, root, path, dir, di);
BUG_ON(ret);
}
btrfs_release_path(root, path);
/*
/* look for a conflicting name */ * NOTE: we have searched root tree and checked the
di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino, * coresponding ref, it does not need to check again.
name, namelen, 0); */
if (di && !IS_ERR(di)) { search_done = 1;
ret = drop_one_dir_item(trans, root, path, dir, di);
BUG_ON(ret);
} }
btrfs_release_path(root, path); btrfs_release_path(root, path);
insert:
/* insert our name */ /* insert our name */
ret = btrfs_add_link(trans, dir, inode, name, namelen, 0, ret = btrfs_add_link(trans, dir, inode, name, namelen, 0,
btrfs_inode_ref_index(eb, ref)); btrfs_inode_ref_index(eb, ref));
...@@ -1286,6 +1273,8 @@ static noinline int replay_one_dir_item(struct btrfs_trans_handle *trans, ...@@ -1286,6 +1273,8 @@ static noinline int replay_one_dir_item(struct btrfs_trans_handle *trans,
ptr_end = ptr + item_size; ptr_end = ptr + item_size;
while (ptr < ptr_end) { while (ptr < ptr_end) {
di = (struct btrfs_dir_item *)ptr; di = (struct btrfs_dir_item *)ptr;
if (verify_dir_item(root, eb, di))
return -EIO;
name_len = btrfs_dir_name_len(eb, di); name_len = btrfs_dir_name_len(eb, di);
ret = replay_one_name(trans, root, path, eb, di, key); ret = replay_one_name(trans, root, path, eb, di, key);
BUG_ON(ret); BUG_ON(ret);
...@@ -1412,6 +1401,11 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans, ...@@ -1412,6 +1401,11 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
ptr_end = ptr + item_size; ptr_end = ptr + item_size;
while (ptr < ptr_end) { while (ptr < ptr_end) {
di = (struct btrfs_dir_item *)ptr; di = (struct btrfs_dir_item *)ptr;
if (verify_dir_item(root, eb, di)) {
ret = -EIO;
goto out;
}
name_len = btrfs_dir_name_len(eb, di); name_len = btrfs_dir_name_len(eb, di);
name = kmalloc(name_len, GFP_NOFS); name = kmalloc(name_len, GFP_NOFS);
if (!name) { if (!name) {
...@@ -1821,7 +1815,8 @@ static int walk_log_tree(struct btrfs_trans_handle *trans, ...@@ -1821,7 +1815,8 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
int orig_level; int orig_level;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
BUG_ON(!path); if (!path)
return -ENOMEM;
level = btrfs_header_level(log->node); level = btrfs_header_level(log->node);
orig_level = level; orig_level = level;
...@@ -3107,9 +3102,11 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) ...@@ -3107,9 +3102,11 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
.stage = 0, .stage = 0,
}; };
fs_info->log_root_recovering = 1;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
BUG_ON(!path); if (!path)
return -ENOMEM;
fs_info->log_root_recovering = 1;
trans = btrfs_start_transaction(fs_info->tree_root, 0); trans = btrfs_start_transaction(fs_info->tree_root, 0);
BUG_ON(IS_ERR(trans)); BUG_ON(IS_ERR(trans));
...@@ -3117,7 +3114,8 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) ...@@ -3117,7 +3114,8 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
wc.trans = trans; wc.trans = trans;
wc.pin = 1; wc.pin = 1;
walk_log_tree(trans, log_root_tree, &wc); ret = walk_log_tree(trans, log_root_tree, &wc);
BUG_ON(ret);
again: again:
key.objectid = BTRFS_TREE_LOG_OBJECTID; key.objectid = BTRFS_TREE_LOG_OBJECTID;
...@@ -3141,8 +3139,7 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) ...@@ -3141,8 +3139,7 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
log = btrfs_read_fs_root_no_radix(log_root_tree, log = btrfs_read_fs_root_no_radix(log_root_tree,
&found_key); &found_key);
BUG_ON(!log); BUG_ON(IS_ERR(log));
tmp_key.objectid = found_key.offset; tmp_key.objectid = found_key.offset;
tmp_key.type = BTRFS_ROOT_ITEM_KEY; tmp_key.type = BTRFS_ROOT_ITEM_KEY;
......
...@@ -33,17 +33,6 @@ ...@@ -33,17 +33,6 @@
#include "volumes.h" #include "volumes.h"
#include "async-thread.h" #include "async-thread.h"
struct map_lookup {
u64 type;
int io_align;
int io_width;
int stripe_len;
int sector_size;
int num_stripes;
int sub_stripes;
struct btrfs_bio_stripe stripes[];
};
static int init_first_rw_device(struct btrfs_trans_handle *trans, static int init_first_rw_device(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct btrfs_device *device); struct btrfs_device *device);
...@@ -1879,6 +1868,8 @@ static int btrfs_relocate_chunk(struct btrfs_root *root, ...@@ -1879,6 +1868,8 @@ static int btrfs_relocate_chunk(struct btrfs_root *root,
BUG_ON(ret); BUG_ON(ret);
trace_btrfs_chunk_free(root, map, chunk_offset, em->len);
if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) { if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) {
ret = btrfs_del_sys_chunk(root, chunk_objectid, chunk_offset); ret = btrfs_del_sys_chunk(root, chunk_objectid, chunk_offset);
BUG_ON(ret); BUG_ON(ret);
...@@ -2606,6 +2597,8 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, ...@@ -2606,6 +2597,8 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
*num_bytes = chunk_bytes_by_type(type, calc_size, *num_bytes = chunk_bytes_by_type(type, calc_size,
map->num_stripes, sub_stripes); map->num_stripes, sub_stripes);
trace_btrfs_chunk_alloc(info->chunk_root, map, start, *num_bytes);
em = alloc_extent_map(GFP_NOFS); em = alloc_extent_map(GFP_NOFS);
if (!em) { if (!em) {
ret = -ENOMEM; ret = -ENOMEM;
...@@ -2714,6 +2707,7 @@ static int __finish_chunk_alloc(struct btrfs_trans_handle *trans, ...@@ -2714,6 +2707,7 @@ static int __finish_chunk_alloc(struct btrfs_trans_handle *trans,
item_size); item_size);
BUG_ON(ret); BUG_ON(ret);
} }
kfree(chunk); kfree(chunk);
return 0; return 0;
} }
...@@ -2918,7 +2912,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -2918,7 +2912,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
struct extent_map_tree *em_tree = &map_tree->map_tree; struct extent_map_tree *em_tree = &map_tree->map_tree;
u64 offset; u64 offset;
u64 stripe_offset; u64 stripe_offset;
u64 stripe_end_offset;
u64 stripe_nr; u64 stripe_nr;
u64 stripe_nr_orig;
u64 stripe_nr_end;
int stripes_allocated = 8; int stripes_allocated = 8;
int stripes_required = 1; int stripes_required = 1;
int stripe_index; int stripe_index;
...@@ -2927,7 +2924,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -2927,7 +2924,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
int max_errors = 0; int max_errors = 0;
struct btrfs_multi_bio *multi = NULL; struct btrfs_multi_bio *multi = NULL;
if (multi_ret && !(rw & REQ_WRITE)) if (multi_ret && !(rw & (REQ_WRITE | REQ_DISCARD)))
stripes_allocated = 1; stripes_allocated = 1;
again: again:
if (multi_ret) { if (multi_ret) {
...@@ -2968,7 +2965,15 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -2968,7 +2965,15 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
max_errors = 1; max_errors = 1;
} }
} }
if (multi_ret && (rw & REQ_WRITE) && if (rw & REQ_DISCARD) {
if (map->type & (BTRFS_BLOCK_GROUP_RAID0 |
BTRFS_BLOCK_GROUP_RAID1 |
BTRFS_BLOCK_GROUP_DUP |
BTRFS_BLOCK_GROUP_RAID10)) {
stripes_required = map->num_stripes;
}
}
if (multi_ret && (rw & (REQ_WRITE | REQ_DISCARD)) &&
stripes_allocated < stripes_required) { stripes_allocated < stripes_required) {
stripes_allocated = map->num_stripes; stripes_allocated = map->num_stripes;
free_extent_map(em); free_extent_map(em);
...@@ -2988,12 +2993,15 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -2988,12 +2993,15 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
/* stripe_offset is the offset of this block in its stripe*/ /* stripe_offset is the offset of this block in its stripe*/
stripe_offset = offset - stripe_offset; stripe_offset = offset - stripe_offset;
if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | if (rw & REQ_DISCARD)
BTRFS_BLOCK_GROUP_RAID10 | *length = min_t(u64, em->len - offset, *length);
BTRFS_BLOCK_GROUP_DUP)) { else if (map->type & (BTRFS_BLOCK_GROUP_RAID0 |
BTRFS_BLOCK_GROUP_RAID1 |
BTRFS_BLOCK_GROUP_RAID10 |
BTRFS_BLOCK_GROUP_DUP)) {
/* we limit the length of each bio to what fits in a stripe */ /* we limit the length of each bio to what fits in a stripe */
*length = min_t(u64, em->len - offset, *length = min_t(u64, em->len - offset,
map->stripe_len - stripe_offset); map->stripe_len - stripe_offset);
} else { } else {
*length = em->len - offset; *length = em->len - offset;
} }
...@@ -3003,8 +3011,19 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -3003,8 +3011,19 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
num_stripes = 1; num_stripes = 1;
stripe_index = 0; stripe_index = 0;
if (map->type & BTRFS_BLOCK_GROUP_RAID1) { stripe_nr_orig = stripe_nr;
if (rw & REQ_WRITE) stripe_nr_end = (offset + *length + map->stripe_len - 1) &
(~(map->stripe_len - 1));
do_div(stripe_nr_end, map->stripe_len);
stripe_end_offset = stripe_nr_end * map->stripe_len -
(offset + *length);
if (map->type & BTRFS_BLOCK_GROUP_RAID0) {
if (rw & REQ_DISCARD)
num_stripes = min_t(u64, map->num_stripes,
stripe_nr_end - stripe_nr_orig);
stripe_index = do_div(stripe_nr, map->num_stripes);
} else if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
if (rw & (REQ_WRITE | REQ_DISCARD))
num_stripes = map->num_stripes; num_stripes = map->num_stripes;
else if (mirror_num) else if (mirror_num)
stripe_index = mirror_num - 1; stripe_index = mirror_num - 1;
...@@ -3015,7 +3034,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -3015,7 +3034,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
} }
} else if (map->type & BTRFS_BLOCK_GROUP_DUP) { } else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
if (rw & REQ_WRITE) if (rw & (REQ_WRITE | REQ_DISCARD))
num_stripes = map->num_stripes; num_stripes = map->num_stripes;
else if (mirror_num) else if (mirror_num)
stripe_index = mirror_num - 1; stripe_index = mirror_num - 1;
...@@ -3028,6 +3047,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -3028,6 +3047,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
if (rw & REQ_WRITE) if (rw & REQ_WRITE)
num_stripes = map->sub_stripes; num_stripes = map->sub_stripes;
else if (rw & REQ_DISCARD)
num_stripes = min_t(u64, map->sub_stripes *
(stripe_nr_end - stripe_nr_orig),
map->num_stripes);
else if (mirror_num) else if (mirror_num)
stripe_index += mirror_num - 1; stripe_index += mirror_num - 1;
else { else {
...@@ -3045,12 +3068,101 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, ...@@ -3045,12 +3068,101 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
} }
BUG_ON(stripe_index >= map->num_stripes); BUG_ON(stripe_index >= map->num_stripes);
for (i = 0; i < num_stripes; i++) { if (rw & REQ_DISCARD) {
multi->stripes[i].physical = for (i = 0; i < num_stripes; i++) {
map->stripes[stripe_index].physical + multi->stripes[i].physical =
stripe_offset + stripe_nr * map->stripe_len; map->stripes[stripe_index].physical +
multi->stripes[i].dev = map->stripes[stripe_index].dev; stripe_offset + stripe_nr * map->stripe_len;
stripe_index++; multi->stripes[i].dev = map->stripes[stripe_index].dev;
if (map->type & BTRFS_BLOCK_GROUP_RAID0) {
u64 stripes;
u32 last_stripe = 0;
int j;
div_u64_rem(stripe_nr_end - 1,
map->num_stripes,
&last_stripe);
for (j = 0; j < map->num_stripes; j++) {
u32 test;
div_u64_rem(stripe_nr_end - 1 - j,
map->num_stripes, &test);
if (test == stripe_index)
break;
}
stripes = stripe_nr_end - 1 - j;
do_div(stripes, map->num_stripes);
multi->stripes[i].length = map->stripe_len *
(stripes - stripe_nr + 1);
if (i == 0) {
multi->stripes[i].length -=
stripe_offset;
stripe_offset = 0;
}
if (stripe_index == last_stripe)
multi->stripes[i].length -=
stripe_end_offset;
} else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
u64 stripes;
int j;
int factor = map->num_stripes /
map->sub_stripes;
u32 last_stripe = 0;
div_u64_rem(stripe_nr_end - 1,
factor, &last_stripe);
last_stripe *= map->sub_stripes;
for (j = 0; j < factor; j++) {
u32 test;
div_u64_rem(stripe_nr_end - 1 - j,
factor, &test);
if (test ==
stripe_index / map->sub_stripes)
break;
}
stripes = stripe_nr_end - 1 - j;
do_div(stripes, factor);
multi->stripes[i].length = map->stripe_len *
(stripes - stripe_nr + 1);
if (i < map->sub_stripes) {
multi->stripes[i].length -=
stripe_offset;
if (i == map->sub_stripes - 1)
stripe_offset = 0;
}
if (stripe_index >= last_stripe &&
stripe_index <= (last_stripe +
map->sub_stripes - 1)) {
multi->stripes[i].length -=
stripe_end_offset;
}
} else
multi->stripes[i].length = *length;
stripe_index++;
if (stripe_index == map->num_stripes) {
/* This could only happen for RAID0/10 */
stripe_index = 0;
stripe_nr++;
}
}
} else {
for (i = 0; i < num_stripes; i++) {
multi->stripes[i].physical =
map->stripes[stripe_index].physical +
stripe_offset +
stripe_nr * map->stripe_len;
multi->stripes[i].dev =
map->stripes[stripe_index].dev;
stripe_index++;
}
} }
if (multi_ret) { if (multi_ret) {
*multi_ret = multi; *multi_ret = multi;
......
...@@ -126,6 +126,7 @@ struct btrfs_fs_devices { ...@@ -126,6 +126,7 @@ struct btrfs_fs_devices {
struct btrfs_bio_stripe { struct btrfs_bio_stripe {
struct btrfs_device *dev; struct btrfs_device *dev;
u64 physical; u64 physical;
u64 length; /* only used for discard mappings */
}; };
struct btrfs_multi_bio { struct btrfs_multi_bio {
...@@ -145,6 +146,17 @@ struct btrfs_device_info { ...@@ -145,6 +146,17 @@ struct btrfs_device_info {
u64 max_avail; u64 max_avail;
}; };
struct map_lookup {
u64 type;
int io_align;
int io_width;
int stripe_len;
int sector_size;
int num_stripes;
int sub_stripes;
struct btrfs_bio_stripe stripes[];
};
/* Used to sort the devices by max_avail(descending sort) */ /* Used to sort the devices by max_avail(descending sort) */
int btrfs_cmp_device_free_bytes(const void *dev_info1, const void *dev_info2); int btrfs_cmp_device_free_bytes(const void *dev_info1, const void *dev_info2);
......
...@@ -242,6 +242,8 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) ...@@ -242,6 +242,8 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
break; break;
di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
if (verify_dir_item(root, leaf, di))
continue;
name_len = btrfs_dir_name_len(leaf, di); name_len = btrfs_dir_name_len(leaf, di);
total_size += name_len + 1; total_size += name_len + 1;
......
...@@ -357,6 +357,8 @@ struct inodes_stat_t { ...@@ -357,6 +357,8 @@ struct inodes_stat_t {
#define FS_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ #define FS_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
#define FS_EXTENT_FL 0x00080000 /* Extents */ #define FS_EXTENT_FL 0x00080000 /* Extents */
#define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */ #define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */
#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
#define FS_COW_FL 0x02000000 /* Cow file */
#define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ #define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
#define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ #define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */
......
#undef TRACE_SYSTEM
#define TRACE_SYSTEM btrfs
#if !defined(_TRACE_BTRFS_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_BTRFS_H
#include <linux/writeback.h>
#include <linux/tracepoint.h>
struct btrfs_root;
struct btrfs_fs_info;
struct btrfs_inode;
struct extent_map;
struct btrfs_ordered_extent;
struct btrfs_delayed_ref_node;
struct btrfs_delayed_tree_ref;
struct btrfs_delayed_data_ref;
struct btrfs_delayed_ref_head;
struct map_lookup;
struct extent_buffer;
#define show_ref_type(type) \
__print_symbolic(type, \
{ BTRFS_TREE_BLOCK_REF_KEY, "TREE_BLOCK_REF" }, \
{ BTRFS_EXTENT_DATA_REF_KEY, "EXTENT_DATA_REF" }, \
{ BTRFS_EXTENT_REF_V0_KEY, "EXTENT_REF_V0" }, \
{ BTRFS_SHARED_BLOCK_REF_KEY, "SHARED_BLOCK_REF" }, \
{ BTRFS_SHARED_DATA_REF_KEY, "SHARED_DATA_REF" })
#define __show_root_type(obj) \
__print_symbolic(obj, \
{ BTRFS_ROOT_TREE_OBJECTID, "ROOT_TREE" }, \
{ BTRFS_EXTENT_TREE_OBJECTID, "EXTENT_TREE" }, \
{ BTRFS_CHUNK_TREE_OBJECTID, "CHUNK_TREE" }, \
{ BTRFS_DEV_TREE_OBJECTID, "DEV_TREE" }, \
{ BTRFS_FS_TREE_OBJECTID, "FS_TREE" }, \
{ BTRFS_ROOT_TREE_DIR_OBJECTID, "ROOT_TREE_DIR" }, \
{ BTRFS_CSUM_TREE_OBJECTID, "CSUM_TREE" }, \
{ BTRFS_TREE_LOG_OBJECTID, "TREE_LOG" }, \
{ BTRFS_TREE_RELOC_OBJECTID, "TREE_RELOC" }, \
{ BTRFS_DATA_RELOC_TREE_OBJECTID, "DATA_RELOC_TREE" })
#define show_root_type(obj) \
obj, ((obj >= BTRFS_DATA_RELOC_TREE_OBJECTID) || \
(obj <= BTRFS_CSUM_TREE_OBJECTID )) ? __show_root_type(obj) : "-"
TRACE_EVENT(btrfs_transaction_commit,
TP_PROTO(struct btrfs_root *root),
TP_ARGS(root),
TP_STRUCT__entry(
__field( u64, generation )
__field( u64, root_objectid )
),
TP_fast_assign(
__entry->generation = root->fs_info->generation;
__entry->root_objectid = root->root_key.objectid;
),
TP_printk("root = %llu(%s), gen = %llu",
show_root_type(__entry->root_objectid),
(unsigned long long)__entry->generation)
);
DECLARE_EVENT_CLASS(btrfs__inode,
TP_PROTO(struct inode *inode),
TP_ARGS(inode),
TP_STRUCT__entry(
__field( ino_t, ino )
__field( blkcnt_t, blocks )
__field( u64, disk_i_size )
__field( u64, generation )
__field( u64, last_trans )
__field( u64, logged_trans )
__field( u64, root_objectid )
),
TP_fast_assign(
__entry->ino = inode->i_ino;
__entry->blocks = inode->i_blocks;
__entry->disk_i_size = BTRFS_I(inode)->disk_i_size;
__entry->generation = BTRFS_I(inode)->generation;
__entry->last_trans = BTRFS_I(inode)->last_trans;
__entry->logged_trans = BTRFS_I(inode)->logged_trans;
__entry->root_objectid =
BTRFS_I(inode)->root->root_key.objectid;
),
TP_printk("root = %llu(%s), gen = %llu, ino = %lu, blocks = %llu, "
"disk_i_size = %llu, last_trans = %llu, logged_trans = %llu",
show_root_type(__entry->root_objectid),
(unsigned long long)__entry->generation,
(unsigned long)__entry->ino,
(unsigned long long)__entry->blocks,
(unsigned long long)__entry->disk_i_size,
(unsigned long long)__entry->last_trans,
(unsigned long long)__entry->logged_trans)
);
DEFINE_EVENT(btrfs__inode, btrfs_inode_new,
TP_PROTO(struct inode *inode),
TP_ARGS(inode)
);
DEFINE_EVENT(btrfs__inode, btrfs_inode_request,
TP_PROTO(struct inode *inode),
TP_ARGS(inode)
);
DEFINE_EVENT(btrfs__inode, btrfs_inode_evict,
TP_PROTO(struct inode *inode),
TP_ARGS(inode)
);
#define __show_map_type(type) \
__print_symbolic(type, \
{ EXTENT_MAP_LAST_BYTE, "LAST_BYTE" }, \
{ EXTENT_MAP_HOLE, "HOLE" }, \
{ EXTENT_MAP_INLINE, "INLINE" }, \
{ EXTENT_MAP_DELALLOC, "DELALLOC" })
#define show_map_type(type) \
type, (type >= EXTENT_MAP_LAST_BYTE) ? "-" : __show_map_type(type)
#define show_map_flags(flag) \
__print_flags(flag, "|", \
{ EXTENT_FLAG_PINNED, "PINNED" }, \
{ EXTENT_FLAG_COMPRESSED, "COMPRESSED" }, \
{ EXTENT_FLAG_VACANCY, "VACANCY" }, \
{ EXTENT_FLAG_PREALLOC, "PREALLOC" })
TRACE_EVENT(btrfs_get_extent,
TP_PROTO(struct btrfs_root *root, struct extent_map *map),
TP_ARGS(root, map),
TP_STRUCT__entry(
__field( u64, root_objectid )
__field( u64, start )
__field( u64, len )
__field( u64, orig_start )
__field( u64, block_start )
__field( u64, block_len )
__field( unsigned long, flags )
__field( int, refs )
__field( unsigned int, compress_type )
),
TP_fast_assign(
__entry->root_objectid = root->root_key.objectid;
__entry->start = map->start;
__entry->len = map->len;
__entry->orig_start = map->orig_start;
__entry->block_start = map->block_start;
__entry->block_len = map->block_len;
__entry->flags = map->flags;
__entry->refs = atomic_read(&map->refs);
__entry->compress_type = map->compress_type;
),
TP_printk("root = %llu(%s), start = %llu, len = %llu, "
"orig_start = %llu, block_start = %llu(%s), "
"block_len = %llu, flags = %s, refs = %u, "
"compress_type = %u",
show_root_type(__entry->root_objectid),
(unsigned long long)__entry->start,
(unsigned long long)__entry->len,
(unsigned long long)__entry->orig_start,
show_map_type(__entry->block_start),
(unsigned long long)__entry->block_len,
show_map_flags(__entry->flags),
__entry->refs, __entry->compress_type)
);
#define show_ordered_flags(flags) \
__print_symbolic(flags, \
{ BTRFS_ORDERED_IO_DONE, "IO_DONE" }, \
{ BTRFS_ORDERED_COMPLETE, "COMPLETE" }, \
{ BTRFS_ORDERED_NOCOW, "NOCOW" }, \
{ BTRFS_ORDERED_COMPRESSED, "COMPRESSED" }, \
{ BTRFS_ORDERED_PREALLOC, "PREALLOC" }, \
{ BTRFS_ORDERED_DIRECT, "DIRECT" })
DECLARE_EVENT_CLASS(btrfs__ordered_extent,
TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered),
TP_ARGS(inode, ordered),
TP_STRUCT__entry(
__field( ino_t, ino )
__field( u64, file_offset )
__field( u64, start )
__field( u64, len )
__field( u64, disk_len )
__field( u64, bytes_left )
__field( unsigned long, flags )
__field( int, compress_type )
__field( int, refs )
__field( u64, root_objectid )
),
TP_fast_assign(
__entry->ino = inode->i_ino;
__entry->file_offset = ordered->file_offset;
__entry->start = ordered->start;
__entry->len = ordered->len;
__entry->disk_len = ordered->disk_len;
__entry->bytes_left = ordered->bytes_left;
__entry->flags = ordered->flags;
__entry->compress_type = ordered->compress_type;
__entry->refs = atomic_read(&ordered->refs);
__entry->root_objectid =
BTRFS_I(inode)->root->root_key.objectid;
),
TP_printk("root = %llu(%s), ino = %llu, file_offset = %llu, "
"start = %llu, len = %llu, disk_len = %llu, "
"bytes_left = %llu, flags = %s, compress_type = %d, "
"refs = %d",
show_root_type(__entry->root_objectid),
(unsigned long long)__entry->ino,
(unsigned long long)__entry->file_offset,
(unsigned long long)__entry->start,
(unsigned long long)__entry->len,
(unsigned long long)__entry->disk_len,
(unsigned long long)__entry->bytes_left,
show_ordered_flags(__entry->flags),
__entry->compress_type, __entry->refs)
);
DEFINE_EVENT(btrfs__ordered_extent, btrfs_ordered_extent_add,
TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered),
TP_ARGS(inode, ordered)
);
DEFINE_EVENT(btrfs__ordered_extent, btrfs_ordered_extent_remove,
TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered),
TP_ARGS(inode, ordered)
);
DEFINE_EVENT(btrfs__ordered_extent, btrfs_ordered_extent_start,
TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered),
TP_ARGS(inode, ordered)
);
DEFINE_EVENT(btrfs__ordered_extent, btrfs_ordered_extent_put,
TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered),
TP_ARGS(inode, ordered)
);
DECLARE_EVENT_CLASS(btrfs__writepage,
TP_PROTO(struct page *page, struct inode *inode,
struct writeback_control *wbc),
TP_ARGS(page, inode, wbc),
TP_STRUCT__entry(
__field( ino_t, ino )
__field( pgoff_t, index )
__field( long, nr_to_write )
__field( long, pages_skipped )
__field( loff_t, range_start )
__field( loff_t, range_end )
__field( char, nonblocking )
__field( char, for_kupdate )
__field( char, for_reclaim )
__field( char, range_cyclic )
__field( pgoff_t, writeback_index )
__field( u64, root_objectid )
),
TP_fast_assign(
__entry->ino = inode->i_ino;
__entry->index = page->index;
__entry->nr_to_write = wbc->nr_to_write;
__entry->pages_skipped = wbc->pages_skipped;
__entry->range_start = wbc->range_start;
__entry->range_end = wbc->range_end;
__entry->nonblocking = wbc->nonblocking;
__entry->for_kupdate = wbc->for_kupdate;
__entry->for_reclaim = wbc->for_reclaim;
__entry->range_cyclic = wbc->range_cyclic;
__entry->writeback_index = inode->i_mapping->writeback_index;
__entry->root_objectid =
BTRFS_I(inode)->root->root_key.objectid;
),
TP_printk("root = %llu(%s), ino = %lu, page_index = %lu, "
"nr_to_write = %ld, pages_skipped = %ld, range_start = %llu, "
"range_end = %llu, nonblocking = %d, for_kupdate = %d, "
"for_reclaim = %d, range_cyclic = %d, writeback_index = %lu",
show_root_type(__entry->root_objectid),
(unsigned long)__entry->ino, __entry->index,
__entry->nr_to_write, __entry->pages_skipped,
__entry->range_start, __entry->range_end,
__entry->nonblocking, __entry->for_kupdate,
__entry->for_reclaim, __entry->range_cyclic,
(unsigned long)__entry->writeback_index)
);
DEFINE_EVENT(btrfs__writepage, __extent_writepage,
TP_PROTO(struct page *page, struct inode *inode,
struct writeback_control *wbc),
TP_ARGS(page, inode, wbc)
);
TRACE_EVENT(btrfs_writepage_end_io_hook,
TP_PROTO(struct page *page, u64 start, u64 end, int uptodate),
TP_ARGS(page, start, end, uptodate),
TP_STRUCT__entry(
__field( ino_t, ino )
__field( pgoff_t, index )
__field( u64, start )
__field( u64, end )
__field( int, uptodate )
__field( u64, root_objectid )
),
TP_fast_assign(
__entry->ino = page->mapping->host->i_ino;
__entry->index = page->index;
__entry->start = start;
__entry->end = end;
__entry->uptodate = uptodate;
__entry->root_objectid =
BTRFS_I(page->mapping->host)->root->root_key.objectid;
),
TP_printk("root = %llu(%s), ino = %lu, page_index = %lu, start = %llu, "
"end = %llu, uptodate = %d",
show_root_type(__entry->root_objectid),
(unsigned long)__entry->ino, (unsigned long)__entry->index,
(unsigned long long)__entry->start,
(unsigned long long)__entry->end, __entry->uptodate)
);
TRACE_EVENT(btrfs_sync_file,
TP_PROTO(struct file *file, int datasync),
TP_ARGS(file, datasync),
TP_STRUCT__entry(
__field( ino_t, ino )
__field( ino_t, parent )
__field( int, datasync )
__field( u64, root_objectid )
),
TP_fast_assign(
struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
__entry->ino = inode->i_ino;
__entry->parent = dentry->d_parent->d_inode->i_ino;
__entry->datasync = datasync;
__entry->root_objectid =
BTRFS_I(inode)->root->root_key.objectid;
),
TP_printk("root = %llu(%s), ino = %ld, parent = %ld, datasync = %d",
show_root_type(__entry->root_objectid),
(unsigned long)__entry->ino, (unsigned long)__entry->parent,
__entry->datasync)
);
TRACE_EVENT(btrfs_sync_fs,
TP_PROTO(int wait),
TP_ARGS(wait),
TP_STRUCT__entry(
__field( int, wait )
),
TP_fast_assign(
__entry->wait = wait;
),
TP_printk("wait = %d", __entry->wait)
);
#define show_ref_action(action) \
__print_symbolic(action, \
{ BTRFS_ADD_DELAYED_REF, "ADD_DELAYED_REF" }, \
{ BTRFS_DROP_DELAYED_REF, "DROP_DELAYED_REF" }, \
{ BTRFS_ADD_DELAYED_EXTENT, "ADD_DELAYED_EXTENT" }, \
{ BTRFS_UPDATE_DELAYED_HEAD, "UPDATE_DELAYED_HEAD" })
TRACE_EVENT(btrfs_delayed_tree_ref,
TP_PROTO(struct btrfs_delayed_ref_node *ref,
struct btrfs_delayed_tree_ref *full_ref,
int action),
TP_ARGS(ref, full_ref, action),
TP_STRUCT__entry(
__field( u64, bytenr )
__field( u64, num_bytes )
__field( int, action )
__field( u64, parent )
__field( u64, ref_root )
__field( int, level )
__field( int, type )
),
TP_fast_assign(
__entry->bytenr = ref->bytenr;
__entry->num_bytes = ref->num_bytes;
__entry->action = action;
__entry->parent = full_ref->parent;
__entry->ref_root = full_ref->root;
__entry->level = full_ref->level;
__entry->type = ref->type;
),
TP_printk("bytenr = %llu, num_bytes = %llu, action = %s, "
"parent = %llu(%s), ref_root = %llu(%s), level = %d, "
"type = %s",
(unsigned long long)__entry->bytenr,
(unsigned long long)__entry->num_bytes,
show_ref_action(__entry->action),
show_root_type(__entry->parent),
show_root_type(__entry->ref_root),
__entry->level, show_ref_type(__entry->type))
);
TRACE_EVENT(btrfs_delayed_data_ref,
TP_PROTO(struct btrfs_delayed_ref_node *ref,
struct btrfs_delayed_data_ref *full_ref,
int action),
TP_ARGS(ref, full_ref, action),
TP_STRUCT__entry(
__field( u64, bytenr )
__field( u64, num_bytes )
__field( int, action )
__field( u64, parent )
__field( u64, ref_root )
__field( u64, owner )
__field( u64, offset )
__field( int, type )
),
TP_fast_assign(
__entry->bytenr = ref->bytenr;
__entry->num_bytes = ref->num_bytes;
__entry->action = action;
__entry->parent = full_ref->parent;
__entry->ref_root = full_ref->root;
__entry->owner = full_ref->objectid;
__entry->offset = full_ref->offset;
__entry->type = ref->type;
),
TP_printk("bytenr = %llu, num_bytes = %llu, action = %s, "
"parent = %llu(%s), ref_root = %llu(%s), owner = %llu, "
"offset = %llu, type = %s",
(unsigned long long)__entry->bytenr,
(unsigned long long)__entry->num_bytes,
show_ref_action(__entry->action),
show_root_type(__entry->parent),
show_root_type(__entry->ref_root),
(unsigned long long)__entry->owner,
(unsigned long long)__entry->offset,
show_ref_type(__entry->type))
);
TRACE_EVENT(btrfs_delayed_ref_head,
TP_PROTO(struct btrfs_delayed_ref_node *ref,
struct btrfs_delayed_ref_head *head_ref,
int action),
TP_ARGS(ref, head_ref, action),
TP_STRUCT__entry(
__field( u64, bytenr )
__field( u64, num_bytes )
__field( int, action )
__field( int, is_data )
),
TP_fast_assign(
__entry->bytenr = ref->bytenr;
__entry->num_bytes = ref->num_bytes;
__entry->action = action;
__entry->is_data = head_ref->is_data;
),
TP_printk("bytenr = %llu, num_bytes = %llu, action = %s, is_data = %d",
(unsigned long long)__entry->bytenr,
(unsigned long long)__entry->num_bytes,
show_ref_action(__entry->action),
__entry->is_data)
);
#define show_chunk_type(type) \
__print_flags(type, "|", \
{ BTRFS_BLOCK_GROUP_DATA, "DATA" }, \
{ BTRFS_BLOCK_GROUP_SYSTEM, "SYSTEM"}, \
{ BTRFS_BLOCK_GROUP_METADATA, "METADATA"}, \
{ BTRFS_BLOCK_GROUP_RAID0, "RAID0" }, \
{ BTRFS_BLOCK_GROUP_RAID1, "RAID1" }, \
{ BTRFS_BLOCK_GROUP_DUP, "DUP" }, \
{ BTRFS_BLOCK_GROUP_RAID10, "RAID10"})
DECLARE_EVENT_CLASS(btrfs__chunk,
TP_PROTO(struct btrfs_root *root, struct map_lookup *map,
u64 offset, u64 size),
TP_ARGS(root, map, offset, size),
TP_STRUCT__entry(
__field( int, num_stripes )
__field( u64, type )
__field( int, sub_stripes )
__field( u64, offset )
__field( u64, size )
__field( u64, root_objectid )
),
TP_fast_assign(
__entry->num_stripes = map->num_stripes;
__entry->type = map->type;
__entry->sub_stripes = map->sub_stripes;
__entry->offset = offset;
__entry->size = size;
__entry->root_objectid = root->root_key.objectid;
),
TP_printk("root = %llu(%s), offset = %llu, size = %llu, "
"num_stripes = %d, sub_stripes = %d, type = %s",
show_root_type(__entry->root_objectid),
(unsigned long long)__entry->offset,
(unsigned long long)__entry->size,
__entry->num_stripes, __entry->sub_stripes,
show_chunk_type(__entry->type))
);
DEFINE_EVENT(btrfs__chunk, btrfs_chunk_alloc,
TP_PROTO(struct btrfs_root *root, struct map_lookup *map,
u64 offset, u64 size),
TP_ARGS(root, map, offset, size)
);
DEFINE_EVENT(btrfs__chunk, btrfs_chunk_free,
TP_PROTO(struct btrfs_root *root, struct map_lookup *map,
u64 offset, u64 size),
TP_ARGS(root, map, offset, size)
);
TRACE_EVENT(btrfs_cow_block,
TP_PROTO(struct btrfs_root *root, struct extent_buffer *buf,
struct extent_buffer *cow),
TP_ARGS(root, buf, cow),
TP_STRUCT__entry(
__field( u64, root_objectid )
__field( u64, buf_start )
__field( int, refs )
__field( u64, cow_start )
__field( int, buf_level )
__field( int, cow_level )
),
TP_fast_assign(
__entry->root_objectid = root->root_key.objectid;
__entry->buf_start = buf->start;
__entry->refs = atomic_read(&buf->refs);
__entry->cow_start = cow->start;
__entry->buf_level = btrfs_header_level(buf);
__entry->cow_level = btrfs_header_level(cow);
),
TP_printk("root = %llu(%s), refs = %d, orig_buf = %llu "
"(orig_level = %d), cow_buf = %llu (cow_level = %d)",
show_root_type(__entry->root_objectid),
__entry->refs,
(unsigned long long)__entry->buf_start,
__entry->buf_level,
(unsigned long long)__entry->cow_start,
__entry->cow_level)
);
DECLARE_EVENT_CLASS(btrfs__reserved_extent,
TP_PROTO(struct btrfs_root *root, u64 start, u64 len),
TP_ARGS(root, start, len),
TP_STRUCT__entry(
__field( u64, root_objectid )
__field( u64, start )
__field( u64, len )
),
TP_fast_assign(
__entry->root_objectid = root->root_key.objectid;
__entry->start = start;
__entry->len = len;
),
TP_printk("root = %llu(%s), start = %llu, len = %llu",
show_root_type(__entry->root_objectid),
(unsigned long long)__entry->start,
(unsigned long long)__entry->len)
);
DEFINE_EVENT(btrfs__reserved_extent, btrfs_reserved_extent_alloc,
TP_PROTO(struct btrfs_root *root, u64 start, u64 len),
TP_ARGS(root, start, len)
);
DEFINE_EVENT(btrfs__reserved_extent, btrfs_reserved_extent_free,
TP_PROTO(struct btrfs_root *root, u64 start, u64 len),
TP_ARGS(root, start, len)
);
#endif /* _TRACE_BTRFS_H */
/* This part must be outside protection */
#include <trace/define_trace.h>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册