Commit a525890c authored by Linus Torvalds's avatar Linus Torvalds

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

* git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable: (23 commits)
  Btrfs: fix extent_buffer leak during tree log replay
  Btrfs: fix oops when btrfs_inherit_iflags called with a NULL dir
  Btrfs: fix -o nodatasum printk spelling
  Btrfs: check duplicate backrefs for both data and metadata
  Btrfs: init worker struct fields before kthread-run
  Btrfs: pin buffers during write_dev_supers
  Btrfs: avoid races between super writeout and device list updates
  Fix btrfs when ACLs are configured out
  Btrfs: fdatasync should skip metadata writeout
  Btrfs: remove crc32c.h and use libcrc32c directly.
  Btrfs: implement FS_IOC_GETFLAGS/SETFLAGS/GETVERSION
  Btrfs: autodetect SSD devices
  Btrfs: add mount -o ssd_spread to spread allocations out
  Btrfs: avoid allocation clusters that are too spread out
  Btrfs: Add mount -o nossd
  Btrfs: avoid IO stalls behind congested devices in a multi-device FS
  Btrfs: don't allow WRITE_SYNC bios to starve out regular writes
  Btrfs: fix metadata dirty throttling limits
  Btrfs: reduce mount -o ssd CPU usage
  Btrfs: balance btree more often
  ...
parents 3bb66d7f b263c2c8
...@@ -6,5 +6,5 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ ...@@ -6,5 +6,5 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
transaction.o inode.o file.o tree-defrag.o \ transaction.o inode.o file.o tree-defrag.o \
extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \ extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \ extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
ref-cache.o export.o tree-log.o acl.o free-space-cache.o zlib.o \ export.o tree-log.o acl.o free-space-cache.o zlib.o \
compression.o delayed-ref.o compression.o delayed-ref.o relocation.o
...@@ -351,9 +351,4 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir) ...@@ -351,9 +351,4 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir)
return 0; return 0;
} }
int btrfs_check_acl(struct inode *inode, int mask)
{
return 0;
}
#endif /* CONFIG_FS_POSIX_ACL */ #endif /* CONFIG_FS_POSIX_ACL */
...@@ -294,10 +294,10 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers) ...@@ -294,10 +294,10 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers)
INIT_LIST_HEAD(&worker->worker_list); INIT_LIST_HEAD(&worker->worker_list);
spin_lock_init(&worker->lock); spin_lock_init(&worker->lock);
atomic_set(&worker->num_pending, 0); atomic_set(&worker->num_pending, 0);
worker->workers = workers;
worker->task = kthread_run(worker_loop, worker, worker->task = kthread_run(worker_loop, worker,
"btrfs-%s-%d", workers->name, "btrfs-%s-%d", workers->name,
workers->num_workers + i); workers->num_workers + i);
worker->workers = workers;
if (IS_ERR(worker->task)) { if (IS_ERR(worker->task)) {
kfree(worker); kfree(worker);
ret = PTR_ERR(worker->task); ret = PTR_ERR(worker->task);
......
...@@ -72,6 +72,9 @@ struct btrfs_inode { ...@@ -72,6 +72,9 @@ struct btrfs_inode {
*/ */
struct list_head ordered_operations; struct list_head ordered_operations;
/* node for the red-black tree that links inodes in subvolume root */
struct rb_node rb_node;
/* the space_info for where this inode's data allocations are done */ /* the space_info for where this inode's data allocations are done */
struct btrfs_space_info *space_info; struct btrfs_space_info *space_info;
...@@ -154,5 +157,4 @@ static inline void btrfs_i_size_write(struct inode *inode, u64 size) ...@@ -154,5 +157,4 @@ static inline void btrfs_i_size_write(struct inode *inode, u64 size)
BTRFS_I(inode)->disk_i_size = size; BTRFS_I(inode)->disk_i_size = size;
} }
#endif #endif
...@@ -123,7 +123,7 @@ static int check_compressed_csum(struct inode *inode, ...@@ -123,7 +123,7 @@ static int check_compressed_csum(struct inode *inode,
u32 csum; u32 csum;
u32 *cb_sum = &cb->sums; u32 *cb_sum = &cb->sums;
if (btrfs_test_flag(inode, NODATASUM)) if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)
return 0; return 0;
for (i = 0; i < cb->nr_pages; i++) { for (i = 0; i < cb->nr_pages; i++) {
...@@ -670,7 +670,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, ...@@ -670,7 +670,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
*/ */
atomic_inc(&cb->pending_bios); atomic_inc(&cb->pending_bios);
if (!btrfs_test_flag(inode, NODATASUM)) { if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
btrfs_lookup_bio_sums(root, inode, comp_bio, btrfs_lookup_bio_sums(root, inode, comp_bio,
sums); sums);
} }
...@@ -697,7 +697,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, ...@@ -697,7 +697,7 @@ 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_test_flag(inode, NODATASUM)) if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM))
btrfs_lookup_bio_sums(root, inode, comp_bio, sums); btrfs_lookup_bio_sums(root, inode, comp_bio, sums);
ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0); ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0);
......
/*
* Copyright (C) 2008 Oracle. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License v2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 021110-1307, USA.
*/
#ifndef __BTRFS_CRC32C__
#define __BTRFS_CRC32C__
#include <linux/crc32c.h>
/*
* this file used to do more for selecting the HW version of crc32c,
* perhaps it will one day again soon.
*/
#define btrfs_crc32c(seed, data, length) crc32c(seed, data, length)
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -30,9 +30,6 @@ struct btrfs_delayed_ref_node { ...@@ -30,9 +30,6 @@ struct btrfs_delayed_ref_node {
/* the starting bytenr of the extent */ /* the starting bytenr of the extent */
u64 bytenr; u64 bytenr;
/* the parent our backref will point to */
u64 parent;
/* the size of the extent */ /* the size of the extent */
u64 num_bytes; u64 num_bytes;
...@@ -50,10 +47,21 @@ struct btrfs_delayed_ref_node { ...@@ -50,10 +47,21 @@ struct btrfs_delayed_ref_node {
*/ */
int ref_mod; int ref_mod;
unsigned int action:8;
unsigned int type:8;
/* is this node still in the rbtree? */ /* is this node still in the rbtree? */
unsigned int is_head:1;
unsigned int in_tree:1; unsigned int in_tree:1;
}; };
struct btrfs_delayed_extent_op {
struct btrfs_disk_key key;
u64 flags_to_set;
unsigned int update_key:1;
unsigned int update_flags:1;
unsigned int is_data:1;
};
/* /*
* the head refs are used to hold a lock on a given extent, which allows us * the head refs are used to hold a lock on a given extent, which allows us
* to make sure that only one process is running the delayed refs * to make sure that only one process is running the delayed refs
...@@ -71,6 +79,7 @@ struct btrfs_delayed_ref_head { ...@@ -71,6 +79,7 @@ struct btrfs_delayed_ref_head {
struct list_head cluster; struct list_head cluster;
struct btrfs_delayed_extent_op *extent_op;
/* /*
* when a new extent is allocated, it is just reserved in memory * when a new extent is allocated, it is just reserved in memory
* The actual extent isn't inserted into the extent allocation tree * The actual extent isn't inserted into the extent allocation tree
...@@ -84,27 +93,26 @@ struct btrfs_delayed_ref_head { ...@@ -84,27 +93,26 @@ struct btrfs_delayed_ref_head {
* the free has happened. * the free has happened.
*/ */
unsigned int must_insert_reserved:1; unsigned int must_insert_reserved:1;
unsigned int is_data:1;
}; };
struct btrfs_delayed_ref { struct btrfs_delayed_tree_ref {
struct btrfs_delayed_ref_node node; struct btrfs_delayed_ref_node node;
union {
u64 root;
u64 parent;
};
int level;
};
/* the root objectid our ref will point to */ struct btrfs_delayed_data_ref {
u64 root; struct btrfs_delayed_ref_node node;
union {
/* the generation for the backref */ u64 root;
u64 generation; u64 parent;
};
/* owner_objectid of the backref */ u64 objectid;
u64 owner_objectid; u64 offset;
/* operation done by this entry in the rbtree */
u8 action;
/* if pin == 1, when the extent is freed it will be pinned until
* transaction commit
*/
unsigned int pin:1;
}; };
struct btrfs_delayed_ref_root { struct btrfs_delayed_ref_root {
...@@ -143,17 +151,25 @@ static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref) ...@@ -143,17 +151,25 @@ static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref)
} }
} }
int btrfs_add_delayed_ref(struct btrfs_trans_handle *trans, int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans,
u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root, u64 bytenr, u64 num_bytes, u64 parent,
u64 ref_generation, u64 owner_objectid, int action, u64 ref_root, int level, int action,
int pin); struct btrfs_delayed_extent_op *extent_op);
int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans,
u64 bytenr, u64 num_bytes,
u64 parent, u64 ref_root,
u64 owner, u64 offset, int action,
struct btrfs_delayed_extent_op *extent_op);
int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans,
u64 bytenr, u64 num_bytes,
struct btrfs_delayed_extent_op *extent_op);
struct btrfs_delayed_ref_head * struct btrfs_delayed_ref_head *
btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr); btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr);
int btrfs_delayed_ref_pending(struct btrfs_trans_handle *trans, u64 bytenr); int btrfs_delayed_ref_pending(struct btrfs_trans_handle *trans, u64 bytenr);
int btrfs_lookup_extent_ref(struct btrfs_trans_handle *trans, int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr, struct btrfs_root *root, u64 bytenr,
u64 num_bytes, u32 *refs); u64 num_bytes, u64 *refs, u64 *flags);
int btrfs_update_delayed_ref(struct btrfs_trans_handle *trans, int btrfs_update_delayed_ref(struct btrfs_trans_handle *trans,
u64 bytenr, u64 num_bytes, u64 orig_parent, u64 bytenr, u64 num_bytes, u64 orig_parent,
u64 parent, u64 orig_ref_root, u64 ref_root, u64 parent, u64 orig_ref_root, u64 ref_root,
...@@ -169,18 +185,24 @@ int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans, ...@@ -169,18 +185,24 @@ int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
*/ */
static int btrfs_delayed_ref_is_head(struct btrfs_delayed_ref_node *node) static int btrfs_delayed_ref_is_head(struct btrfs_delayed_ref_node *node)
{ {
return node->parent == (u64)-1; return node->is_head;
} }
/* /*
* helper functions to cast a node into its container * helper functions to cast a node into its container
*/ */
static inline struct btrfs_delayed_ref * static inline struct btrfs_delayed_tree_ref *
btrfs_delayed_node_to_ref(struct btrfs_delayed_ref_node *node) btrfs_delayed_node_to_tree_ref(struct btrfs_delayed_ref_node *node)
{ {
WARN_ON(btrfs_delayed_ref_is_head(node)); WARN_ON(btrfs_delayed_ref_is_head(node));
return container_of(node, struct btrfs_delayed_ref, node); return container_of(node, struct btrfs_delayed_tree_ref, node);
}
static inline struct btrfs_delayed_data_ref *
btrfs_delayed_node_to_data_ref(struct btrfs_delayed_ref_node *node)
{
WARN_ON(btrfs_delayed_ref_is_head(node));
return container_of(node, struct btrfs_delayed_data_ref, node);
} }
static inline struct btrfs_delayed_ref_head * static inline struct btrfs_delayed_ref_head *
...@@ -188,6 +210,5 @@ btrfs_delayed_node_to_head(struct btrfs_delayed_ref_node *node) ...@@ -188,6 +210,5 @@ btrfs_delayed_node_to_head(struct btrfs_delayed_ref_node *node)
{ {
WARN_ON(!btrfs_delayed_ref_is_head(node)); WARN_ON(!btrfs_delayed_ref_is_head(node));
return container_of(node, struct btrfs_delayed_ref_head, node); return container_of(node, struct btrfs_delayed_ref_head, node);
} }
#endif #endif
This diff is collapsed.
...@@ -78,7 +78,7 @@ static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid, ...@@ -78,7 +78,7 @@ static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
key.offset = 0; key.offset = 0;
inode = btrfs_iget(sb, &key, root, NULL); inode = btrfs_iget(sb, &key, root);
if (IS_ERR(inode)) if (IS_ERR(inode))
return (void *)inode; return (void *)inode;
...@@ -192,7 +192,7 @@ static struct dentry *btrfs_get_parent(struct dentry *child) ...@@ -192,7 +192,7 @@ static struct dentry *btrfs_get_parent(struct dentry *child)
btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
key.offset = 0; key.offset = 0;
return d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root, NULL)); return d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root));
} }
const struct export_operations btrfs_export_ops = { const struct export_operations btrfs_export_ops = {
......
This diff is collapsed.
...@@ -476,6 +476,7 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -476,6 +476,7 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
struct extent_state *state; struct extent_state *state;
struct extent_state *prealloc = NULL; struct extent_state *prealloc = NULL;
struct rb_node *node; struct rb_node *node;
u64 last_end;
int err; int err;
int set = 0; int set = 0;
...@@ -498,6 +499,7 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -498,6 +499,7 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
if (state->start > end) if (state->start > end)
goto out; goto out;
WARN_ON(state->end < start); WARN_ON(state->end < start);
last_end = state->end;
/* /*
* | ---- desired range ---- | * | ---- desired range ---- |
...@@ -524,9 +526,11 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -524,9 +526,11 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
if (err) if (err)
goto out; goto out;
if (state->end <= end) { if (state->end <= end) {
start = state->end + 1;
set |= clear_state_bit(tree, state, bits, set |= clear_state_bit(tree, state, bits,
wake, delete); wake, delete);
if (last_end == (u64)-1)
goto out;
start = last_end + 1;
} else { } else {
start = state->start; start = state->start;
} }
...@@ -552,8 +556,10 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -552,8 +556,10 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
goto out; goto out;
} }
start = state->end + 1;
set |= clear_state_bit(tree, state, bits, wake, delete); set |= clear_state_bit(tree, state, bits, wake, delete);
if (last_end == (u64)-1)
goto out;
start = last_end + 1;
goto search_again; goto search_again;
out: out:
...@@ -707,8 +713,10 @@ static int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -707,8 +713,10 @@ static int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
goto out; goto out;
} }
set_state_bits(tree, state, bits); set_state_bits(tree, state, bits);
start = state->end + 1;
merge_state(tree, state); merge_state(tree, state);
if (last_end == (u64)-1)
goto out;
start = last_end + 1;
goto search_again; goto search_again;
} }
...@@ -742,8 +750,10 @@ static int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -742,8 +750,10 @@ static int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
goto out; goto out;
if (state->end <= end) { if (state->end <= end) {
set_state_bits(tree, state, bits); set_state_bits(tree, state, bits);
start = state->end + 1;
merge_state(tree, state); merge_state(tree, state);
if (last_end == (u64)-1)
goto out;
start = last_end + 1;
} else { } else {
start = state->start; start = state->start;
} }
......
...@@ -291,16 +291,12 @@ noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -291,16 +291,12 @@ noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans,
{ {
u64 extent_end = 0; u64 extent_end = 0;
u64 search_start = start; u64 search_start = start;
u64 leaf_start;
u64 ram_bytes = 0; u64 ram_bytes = 0;
u64 orig_parent = 0;
u64 disk_bytenr = 0; u64 disk_bytenr = 0;
u64 orig_locked_end = locked_end; u64 orig_locked_end = locked_end;
u8 compression; u8 compression;
u8 encryption; u8 encryption;
u16 other_encoding = 0; u16 other_encoding = 0;
u64 root_gen;
u64 root_owner;
struct extent_buffer *leaf; struct extent_buffer *leaf;
struct btrfs_file_extent_item *extent; struct btrfs_file_extent_item *extent;
struct btrfs_path *path; struct btrfs_path *path;
...@@ -340,9 +336,6 @@ noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -340,9 +336,6 @@ noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans,
bookend = 0; bookend = 0;
found_extent = 0; found_extent = 0;
found_inline = 0; found_inline = 0;
leaf_start = 0;
root_gen = 0;
root_owner = 0;
compression = 0; compression = 0;
encryption = 0; encryption = 0;
extent = NULL; extent = NULL;
...@@ -417,9 +410,6 @@ noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -417,9 +410,6 @@ noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans,
if (found_extent) { if (found_extent) {
read_extent_buffer(leaf, &old, (unsigned long)extent, read_extent_buffer(leaf, &old, (unsigned long)extent,
sizeof(old)); sizeof(old));
root_gen = btrfs_header_generation(leaf);
root_owner = btrfs_header_owner(leaf);
leaf_start = leaf->start;
} }
if (end < extent_end && end >= key.offset) { if (end < extent_end && end >= key.offset) {
...@@ -443,14 +433,14 @@ noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -443,14 +433,14 @@ noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans,
} }
locked_end = extent_end; locked_end = extent_end;
} }
orig_parent = path->nodes[0]->start;
disk_bytenr = le64_to_cpu(old.disk_bytenr); disk_bytenr = le64_to_cpu(old.disk_bytenr);
if (disk_bytenr != 0) { if (disk_bytenr != 0) {
ret = btrfs_inc_extent_ref(trans, root, ret = btrfs_inc_extent_ref(trans, root,
disk_bytenr, disk_bytenr,
le64_to_cpu(old.disk_num_bytes), le64_to_cpu(old.disk_num_bytes), 0,
orig_parent, root->root_key.objectid, root->root_key.objectid,
trans->transid, inode->i_ino); key.objectid, key.offset -
le64_to_cpu(old.offset));
BUG_ON(ret); BUG_ON(ret);
} }
} }
...@@ -568,17 +558,6 @@ noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -568,17 +558,6 @@ noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_mark_buffer_dirty(path->nodes[0]);
btrfs_set_lock_blocking(path->nodes[0]); btrfs_set_lock_blocking(path->nodes[0]);
if (disk_bytenr != 0) {
ret = btrfs_update_extent_ref(trans, root,
disk_bytenr,
le64_to_cpu(old.disk_num_bytes),
orig_parent,
leaf->start,
root->root_key.objectid,
trans->transid, ins.objectid);
BUG_ON(ret);
}
path->leave_spinning = 0; path->leave_spinning = 0;
btrfs_release_path(root, path); btrfs_release_path(root, path);
if (disk_bytenr != 0) if (disk_bytenr != 0)
...@@ -594,8 +573,9 @@ noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -594,8 +573,9 @@ noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans,
ret = btrfs_free_extent(trans, root, ret = btrfs_free_extent(trans, root,
old_disk_bytenr, old_disk_bytenr,
le64_to_cpu(old.disk_num_bytes), le64_to_cpu(old.disk_num_bytes),
leaf_start, root_owner, 0, root->root_key.objectid,
root_gen, key.objectid, 0); key.objectid, key.offset -
le64_to_cpu(old.offset));
BUG_ON(ret); BUG_ON(ret);
*hint_byte = old_disk_bytenr; *hint_byte = old_disk_bytenr;
} }
...@@ -664,12 +644,11 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -664,12 +644,11 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
u64 bytenr; u64 bytenr;
u64 num_bytes; u64 num_bytes;
u64 extent_end; u64 extent_end;
u64 extent_offset; u64 orig_offset;
u64 other_start; u64 other_start;
u64 other_end; u64 other_end;
u64 split = start; u64 split = start;
u64 locked_end = end; u64 locked_end = end;
u64 orig_parent;
int extent_type; int extent_type;
int split_end = 1; int split_end = 1;
int ret; int ret;
...@@ -703,7 +682,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -703,7 +682,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi);
extent_offset = btrfs_file_extent_offset(leaf, fi); orig_offset = key.offset - btrfs_file_extent_offset(leaf, fi);
if (key.offset == start) if (key.offset == start)
split = end; split = end;
...@@ -711,8 +690,6 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -711,8 +690,6 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
if (key.offset == start && extent_end == end) { if (key.offset == start && extent_end == end) {
int del_nr = 0; int del_nr = 0;
int del_slot = 0; int del_slot = 0;
u64 leaf_owner = btrfs_header_owner(leaf);
u64 leaf_gen = btrfs_header_generation(leaf);
other_start = end; other_start = end;
other_end = 0; other_end = 0;
if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino, if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino,
...@@ -721,8 +698,8 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -721,8 +698,8 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
del_slot = path->slots[0] + 1; del_slot = path->slots[0] + 1;
del_nr++; del_nr++;
ret = btrfs_free_extent(trans, root, bytenr, num_bytes, ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
leaf->start, leaf_owner, 0, root->root_key.objectid,
leaf_gen, inode->i_ino, 0); inode->i_ino, orig_offset);
BUG_ON(ret); BUG_ON(ret);
} }
other_start = 0; other_start = 0;
...@@ -733,8 +710,8 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -733,8 +710,8 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
del_slot = path->slots[0]; del_slot = path->slots[0];
del_nr++; del_nr++;
ret = btrfs_free_extent(trans, root, bytenr, num_bytes, ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
leaf->start, leaf_owner, 0, root->root_key.objectid,
leaf_gen, inode->i_ino, 0); inode->i_ino, orig_offset);
BUG_ON(ret); BUG_ON(ret);
} }
split_end = 0; split_end = 0;
...@@ -768,13 +745,12 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -768,13 +745,12 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
locked_end = extent_end; locked_end = extent_end;
} }
btrfs_set_file_extent_num_bytes(leaf, fi, split - key.offset); btrfs_set_file_extent_num_bytes(leaf, fi, split - key.offset);
extent_offset += split - key.offset;
} else { } else {
BUG_ON(key.offset != start); BUG_ON(key.offset != start);
btrfs_set_file_extent_offset(leaf, fi, extent_offset +
split - key.offset);
btrfs_set_file_extent_num_bytes(leaf, fi, extent_end - split);
key.offset = split; key.offset = split;
btrfs_set_file_extent_offset(leaf, fi, key.offset -
orig_offset);
btrfs_set_file_extent_num_bytes(leaf, fi, extent_end - split);
btrfs_set_item_key_safe(trans, root, path, &key); btrfs_set_item_key_safe(trans, root, path, &key);
extent_end = split; extent_end = split;
} }
...@@ -793,7 +769,8 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -793,7 +769,8 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
struct btrfs_file_extent_item); struct btrfs_file_extent_item);
key.offset = split; key.offset = split;
btrfs_set_item_key_safe(trans, root, path, &key); btrfs_set_item_key_safe(trans, root, path, &key);
btrfs_set_file_extent_offset(leaf, fi, extent_offset); btrfs_set_file_extent_offset(leaf, fi, key.offset -
orig_offset);
btrfs_set_file_extent_num_bytes(leaf, fi, btrfs_set_file_extent_num_bytes(leaf, fi,
other_end - split); other_end - split);
goto done; goto done;
...@@ -815,10 +792,9 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -815,10 +792,9 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(leaf); btrfs_mark_buffer_dirty(leaf);
orig_parent = leaf->start; ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0,
ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, root->root_key.objectid,
orig_parent, root->root_key.objectid, inode->i_ino, orig_offset);
trans->transid, inode->i_ino);
BUG_ON(ret); BUG_ON(ret);
btrfs_release_path(root, path); btrfs_release_path(root, path);
...@@ -833,20 +809,12 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -833,20 +809,12 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
btrfs_set_file_extent_type(leaf, fi, extent_type); btrfs_set_file_extent_type(leaf, fi, extent_type);
btrfs_set_file_extent_disk_bytenr(leaf, fi, bytenr); btrfs_set_file_extent_disk_bytenr(leaf, fi, bytenr);
btrfs_set_file_extent_disk_num_bytes(leaf, fi, num_bytes); btrfs_set_file_extent_disk_num_bytes(leaf, fi, num_bytes);
btrfs_set_file_extent_offset(leaf, fi, extent_offset); btrfs_set_file_extent_offset(leaf, fi, key.offset - orig_offset);
btrfs_set_file_extent_num_bytes(leaf, fi, extent_end - key.offset); btrfs_set_file_extent_num_bytes(leaf, fi, extent_end - key.offset);
btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes); btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes);
btrfs_set_file_extent_compression(leaf, fi, 0); btrfs_set_file_extent_compression(leaf, fi, 0);
btrfs_set_file_extent_encryption(leaf, fi, 0); btrfs_set_file_extent_encryption(leaf, fi, 0);
btrfs_set_file_extent_other_encoding(leaf, fi, 0); btrfs_set_file_extent_other_encoding(leaf, fi, 0);
if (orig_parent != leaf->start) {
ret = btrfs_update_extent_ref(trans, root, bytenr, num_bytes,
orig_parent, leaf->start,
root->root_key.objectid,
trans->transid, inode->i_ino);
BUG_ON(ret);
}
done: done:
btrfs_mark_buffer_dirty(leaf); btrfs_mark_buffer_dirty(leaf);
...@@ -1189,6 +1157,8 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync) ...@@ -1189,6 +1157,8 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
btrfs_wait_ordered_range(inode, 0, (u64)-1); btrfs_wait_ordered_range(inode, 0, (u64)-1);
root->log_batch++; root->log_batch++;
if (datasync && !(inode->i_state & I_DIRTY_PAGES))
goto out;
/* /*
* ok we haven't committed the transaction yet, lets do a commit * ok we haven't committed the transaction yet, lets do a commit
*/ */
......
...@@ -579,6 +579,7 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group, ...@@ -579,6 +579,7 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
* it returns -enospc * it returns -enospc
*/ */
int btrfs_find_space_cluster(struct btrfs_trans_handle *trans, int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_block_group_cache *block_group, struct btrfs_block_group_cache *block_group,
struct btrfs_free_cluster *cluster, struct btrfs_free_cluster *cluster,
u64 offset, u64 bytes, u64 empty_size) u64 offset, u64 bytes, u64 empty_size)
...@@ -595,7 +596,9 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans, ...@@ -595,7 +596,9 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
int ret; int ret;
/* for metadata, allow allocates with more holes */ /* for metadata, allow allocates with more holes */
if (block_group->flags & BTRFS_BLOCK_GROUP_METADATA) { if (btrfs_test_opt(root, SSD_SPREAD)) {
min_bytes = bytes + empty_size;
} else if (block_group->flags & BTRFS_BLOCK_GROUP_METADATA) {
/* /*
* we want to do larger allocations when we are * we want to do larger allocations when we are
* flushing out the delayed refs, it helps prevent * flushing out the delayed refs, it helps prevent
...@@ -645,14 +648,15 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans, ...@@ -645,14 +648,15 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
* we haven't filled the empty size and the window is * we haven't filled the empty size and the window is
* very large. reset and try again * very large. reset and try again
*/ */
if (next->offset - window_start > (bytes + empty_size) * 2) { if (next->offset - (last->offset + last->bytes) > 128 * 1024 ||
next->offset - window_start > (bytes + empty_size) * 2) {
entry = next; entry = next;
window_start = entry->offset; window_start = entry->offset;
window_free = entry->bytes; window_free = entry->bytes;
last = entry; last = entry;
max_extent = 0; max_extent = 0;
total_retries++; total_retries++;
if (total_retries % 256 == 0) { if (total_retries % 64 == 0) {
if (min_bytes >= (bytes + empty_size)) { if (min_bytes >= (bytes + empty_size)) {
ret = -ENOSPC; ret = -ENOSPC;
goto out; goto out;
......
...@@ -31,6 +31,7 @@ void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group, ...@@ -31,6 +31,7 @@ void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
u64 bytes); u64 bytes);
u64 btrfs_block_group_free_space(struct btrfs_block_group_cache *block_group); u64 btrfs_block_group_free_space(struct btrfs_block_group_cache *block_group);
int btrfs_find_space_cluster(struct btrfs_trans_handle *trans, int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_block_group_cache *block_group, struct btrfs_block_group_cache *block_group,
struct btrfs_free_cluster *cluster, struct btrfs_free_cluster *cluster,
u64 offset, u64 bytes, u64 empty_size); u64 offset, u64 bytes, u64 empty_size);
......
...@@ -19,9 +19,9 @@ ...@@ -19,9 +19,9 @@
#ifndef __HASH__ #ifndef __HASH__
#define __HASH__ #define __HASH__
#include "crc32c.h" #include <linux/crc32c.h>
static inline u64 btrfs_name_hash(const char *name, int len) static inline u64 btrfs_name_hash(const char *name, int len)
{ {
return btrfs_crc32c((u32)~1, name, len); return crc32c((u32)~1, name, len);
} }
#endif #endif
This diff is collapsed.
...@@ -50,7 +50,177 @@ ...@@ -50,7 +50,177 @@
#include "volumes.h" #include "volumes.h"
#include "locking.h" #include "locking.h"
/* Mask out flags that are inappropriate for the given type of inode. */
static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags)
{
if (S_ISDIR(mode))
return flags;
else if (S_ISREG(mode))
return flags & ~FS_DIRSYNC_FL;
else
return flags & (FS_NODUMP_FL | FS_NOATIME_FL);
}
/*
* Export inode flags to the format expected by the FS_IOC_GETFLAGS ioctl.
*/
static unsigned int btrfs_flags_to_ioctl(unsigned int flags)
{
unsigned int iflags = 0;
if (flags & BTRFS_INODE_SYNC)
iflags |= FS_SYNC_FL;
if (flags & BTRFS_INODE_IMMUTABLE)
iflags |= FS_IMMUTABLE_FL;
if (flags & BTRFS_INODE_APPEND)
iflags |= FS_APPEND_FL;
if (flags & BTRFS_INODE_NODUMP)
iflags |= FS_NODUMP_FL;
if (flags & BTRFS_INODE_NOATIME)
iflags |= FS_NOATIME_FL;
if (flags & BTRFS_INODE_DIRSYNC)
iflags |= FS_DIRSYNC_FL;
return iflags;
}
/*
* Update inode->i_flags based on the btrfs internal flags.
*/
void btrfs_update_iflags(struct inode *inode)
{
struct btrfs_inode *ip = BTRFS_I(inode);
inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
if (ip->flags & BTRFS_INODE_SYNC)
inode->i_flags |= S_SYNC;
if (ip->flags & BTRFS_INODE_IMMUTABLE)
inode->i_flags |= S_IMMUTABLE;
if (ip->flags & BTRFS_INODE_APPEND)
inode->i_flags |= S_APPEND;
if (ip->flags & BTRFS_INODE_NOATIME)
inode->i_flags |= S_NOATIME;
if (ip->flags & BTRFS_INODE_DIRSYNC)
inode->i_flags |= S_DIRSYNC;
}
/*
* Inherit flags from the parent inode.
*
* Unlike extN we don't have any flags we don't want to inherit currently.
*/
void btrfs_inherit_iflags(struct inode *inode, struct inode *dir)
{
unsigned int flags;
if (!dir)
return;
flags = BTRFS_I(dir)->flags;
if (S_ISREG(inode->i_mode))
flags &= ~BTRFS_INODE_DIRSYNC;
else if (!S_ISDIR(inode->i_mode))
flags &= (BTRFS_INODE_NODUMP | BTRFS_INODE_NOATIME);
BTRFS_I(inode)->flags = flags;
btrfs_update_iflags(inode);
}
static int btrfs_ioctl_getflags(struct file *file, void __user *arg)
{
struct btrfs_inode *ip = BTRFS_I(file->f_path.dentry->d_inode);
unsigned int flags = btrfs_flags_to_ioctl(ip->flags);
if (copy_to_user(arg, &flags, sizeof(flags)))
return -EFAULT;
return 0;
}
static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
{
struct inode *inode = file->f_path.dentry->d_inode;
struct btrfs_inode *ip = BTRFS_I(inode);
struct btrfs_root *root = ip->root;
struct btrfs_trans_handle *trans;
unsigned int flags, oldflags;
int ret;
if (copy_from_user(&flags, arg, sizeof(flags)))
return -EFAULT;
if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
FS_NOATIME_FL | FS_NODUMP_FL | \
FS_SYNC_FL | FS_DIRSYNC_FL))
return -EOPNOTSUPP;
if (!is_owner_or_cap(inode))
return -EACCES;
mutex_lock(&inode->i_mutex);
flags = btrfs_mask_flags(inode->i_mode, flags);
oldflags = btrfs_flags_to_ioctl(ip->flags);
if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) {
if (!capable(CAP_LINUX_IMMUTABLE)) {
ret = -EPERM;
goto out_unlock;
}
}
ret = mnt_want_write(file->f_path.mnt);
if (ret)
goto out_unlock;
if (flags & FS_SYNC_FL)
ip->flags |= BTRFS_INODE_SYNC;
else
ip->flags &= ~BTRFS_INODE_SYNC;
if (flags & FS_IMMUTABLE_FL)
ip->flags |= BTRFS_INODE_IMMUTABLE;
else
ip->flags &= ~BTRFS_INODE_IMMUTABLE;
if (flags & FS_APPEND_FL)
ip->flags |= BTRFS_INODE_APPEND;
else
ip->flags &= ~BTRFS_INODE_APPEND;
if (flags & FS_NODUMP_FL)
ip->flags |= BTRFS_INODE_NODUMP;
else
ip->flags &= ~BTRFS_INODE_NODUMP;
if (flags & FS_NOATIME_FL)
ip->flags |= BTRFS_INODE_NOATIME;
else
ip->flags &= ~BTRFS_INODE_NOATIME;
if (flags & FS_DIRSYNC_FL)
ip->flags |= BTRFS_INODE_DIRSYNC;
else
ip->flags &= ~BTRFS_INODE_DIRSYNC;
trans = btrfs_join_transaction(root, 1);
BUG_ON(!trans);
ret = btrfs_update_inode(trans, root, inode);
BUG_ON(ret);
btrfs_update_iflags(inode);
inode->i_ctime = CURRENT_TIME;
btrfs_end_transaction(trans, root);
mnt_drop_write(file->f_path.mnt);
out_unlock:
mutex_unlock(&inode->i_mutex);
return 0;
}
static int btrfs_ioctl_getversion(struct file *file, int __user *arg)
{
struct inode *inode = file->f_path.dentry->d_inode;
return put_user(inode->i_generation, arg);
}
static noinline int create_subvol(struct btrfs_root *root, static noinline int create_subvol(struct btrfs_root *root,
struct dentry *dentry, struct dentry *dentry,
...@@ -82,22 +252,25 @@ static noinline int create_subvol(struct btrfs_root *root, ...@@ -82,22 +252,25 @@ static noinline int create_subvol(struct btrfs_root *root,
if (ret) if (ret)
goto fail; goto fail;
leaf = btrfs_alloc_free_block(trans, root, root->leafsize, 0, leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
objectid, trans->transid, 0, 0, 0); 0, objectid, NULL, 0, 0, 0);
if (IS_ERR(leaf)) { if (IS_ERR(leaf)) {
ret = PTR_ERR(leaf); ret = PTR_ERR(leaf);
goto fail; goto fail;
} }
btrfs_set_header_nritems(leaf, 0); memset_extent_buffer(leaf, 0, 0, sizeof(struct btrfs_header));
btrfs_set_header_level(leaf, 0);
btrfs_set_header_bytenr(leaf, leaf->start); btrfs_set_header_bytenr(leaf, leaf->start);
btrfs_set_header_generation(leaf, trans->transid); btrfs_set_header_generation(leaf, trans->transid);
btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV);
btrfs_set_header_owner(leaf, objectid); btrfs_set_header_owner(leaf, objectid);
write_extent_buffer(leaf, root->fs_info->fsid, write_extent_buffer(leaf, root->fs_info->fsid,
(unsigned long)btrfs_header_fsid(leaf), (unsigned long)btrfs_header_fsid(leaf),
BTRFS_FSID_SIZE); BTRFS_FSID_SIZE);
write_extent_buffer(leaf, root->fs_info->chunk_tree_uuid,
(unsigned long)btrfs_header_chunk_tree_uuid(leaf),
BTRFS_UUID_SIZE);
btrfs_mark_buffer_dirty(leaf); btrfs_mark_buffer_dirty(leaf);
inode_item = &root_item.inode; inode_item = &root_item.inode;
...@@ -125,7 +298,7 @@ static noinline int create_subvol(struct btrfs_root *root, ...@@ -125,7 +298,7 @@ static noinline int create_subvol(struct btrfs_root *root,
btrfs_set_root_dirid(&root_item, new_dirid); btrfs_set_root_dirid(&root_item, new_dirid);
key.objectid = objectid; key.objectid = objectid;
key.offset = 1; key.offset = 0;
btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
&root_item); &root_item);
...@@ -911,10 +1084,10 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, ...@@ -911,10 +1084,10 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
if (disko) { if (disko) {
inode_add_bytes(inode, datal); inode_add_bytes(inode, datal);
ret = btrfs_inc_extent_ref(trans, root, ret = btrfs_inc_extent_ref(trans, root,
disko, diskl, leaf->start, disko, diskl, 0,
root->root_key.objectid, root->root_key.objectid,
trans->transid, inode->i_ino,
inode->i_ino); new_key.offset - datao);
BUG_ON(ret); BUG_ON(ret);
} }
} else if (type == BTRFS_FILE_EXTENT_INLINE) { } else if (type == BTRFS_FILE_EXTENT_INLINE) {
...@@ -1074,6 +1247,12 @@ long btrfs_ioctl(struct file *file, unsigned int ...@@ -1074,6 +1247,12 @@ long btrfs_ioctl(struct file *file, unsigned int
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
switch (cmd) { switch (cmd) {
case FS_IOC_GETFLAGS:
return btrfs_ioctl_getflags(file, argp);
case FS_IOC_SETFLAGS:
return btrfs_ioctl_setflags(file, argp);
case FS_IOC_GETVERSION:
return btrfs_ioctl_getversion(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_SUBVOL_CREATE: case BTRFS_IOC_SUBVOL_CREATE:
......
...@@ -45,22 +45,132 @@ static void print_dev_item(struct extent_buffer *eb, ...@@ -45,22 +45,132 @@ static void print_dev_item(struct extent_buffer *eb,
(unsigned long long)btrfs_device_total_bytes(eb, dev_item), (unsigned long long)btrfs_device_total_bytes(eb, dev_item),
(unsigned long long)btrfs_device_bytes_used(eb, dev_item)); (unsigned long long)btrfs_device_bytes_used(eb, dev_item));
} }
static void print_extent_data_ref(struct extent_buffer *eb,
struct btrfs_extent_data_ref *ref)
{
printk(KERN_INFO "\t\textent data backref root %llu "
"objectid %llu offset %llu count %u\n",
(unsigned long long)btrfs_extent_data_ref_root(eb, ref),
(unsigned long long)btrfs_extent_data_ref_objectid(eb, ref),
(unsigned long long)btrfs_extent_data_ref_offset(eb, ref),
btrfs_extent_data_ref_count(eb, ref));
}
static void print_extent_item(struct extent_buffer *eb, int slot)
{
struct btrfs_extent_item *ei;
struct btrfs_extent_inline_ref *iref;
struct btrfs_extent_data_ref *dref;
struct btrfs_shared_data_ref *sref;
struct btrfs_disk_key key;
unsigned long end;
unsigned long ptr;
int type;
u32 item_size = btrfs_item_size_nr(eb, slot);
u64 flags;
u64 offset;
if (item_size < sizeof(*ei)) {
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
struct btrfs_extent_item_v0 *ei0;
BUG_ON(item_size != sizeof(*ei0));
ei0 = btrfs_item_ptr(eb, slot, struct btrfs_extent_item_v0);
printk(KERN_INFO "\t\textent refs %u\n",
btrfs_extent_refs_v0(eb, ei0));
return;
#else
BUG();
#endif
}
ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item);
flags = btrfs_extent_flags(eb, ei);
printk(KERN_INFO "\t\textent refs %llu gen %llu flags %llu\n",
(unsigned long long)btrfs_extent_refs(eb, ei),
(unsigned long long)btrfs_extent_generation(eb, ei),
(unsigned long long)flags);
if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
struct btrfs_tree_block_info *info;
info = (struct btrfs_tree_block_info *)(ei + 1);
btrfs_tree_block_key(eb, info, &key);
printk(KERN_INFO "\t\ttree block key (%llu %x %llu) "
"level %d\n",
(unsigned long long)btrfs_disk_key_objectid(&key),
key.type,
(unsigned long long)btrfs_disk_key_offset(&key),
btrfs_tree_block_level(eb, info));
iref = (struct btrfs_extent_inline_ref *)(info + 1);
} else {
iref = (struct btrfs_extent_inline_ref *)(ei + 1);
}
ptr = (unsigned long)iref;
end = (unsigned long)ei + item_size;
while (ptr < end) {
iref = (struct btrfs_extent_inline_ref *)ptr;
type = btrfs_extent_inline_ref_type(eb, iref);
offset = btrfs_extent_inline_ref_offset(eb, iref);
switch (type) {
case BTRFS_TREE_BLOCK_REF_KEY:
printk(KERN_INFO "\t\ttree block backref "
"root %llu\n", (unsigned long long)offset);
break;
case BTRFS_SHARED_BLOCK_REF_KEY:
printk(KERN_INFO "\t\tshared block backref "
"parent %llu\n", (unsigned long long)offset);
break;
case BTRFS_EXTENT_DATA_REF_KEY:
dref = (struct btrfs_extent_data_ref *)(&iref->offset);
print_extent_data_ref(eb, dref);
break;
case BTRFS_SHARED_DATA_REF_KEY:
sref = (struct btrfs_shared_data_ref *)(iref + 1);
printk(KERN_INFO "\t\tshared data backref "
"parent %llu count %u\n",
(unsigned long long)offset,
btrfs_shared_data_ref_count(eb, sref));
break;
default:
BUG();
}
ptr += btrfs_extent_inline_ref_size(type);
}
WARN_ON(ptr > end);
}
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
static void print_extent_ref_v0(struct extent_buffer *eb, int slot)
{
struct btrfs_extent_ref_v0 *ref0;
ref0 = btrfs_item_ptr(eb, slot, struct btrfs_extent_ref_v0);
printk("\t\textent back ref root %llu gen %llu "
"owner %llu num_refs %lu\n",
(unsigned long long)btrfs_ref_root_v0(eb, ref0),
(unsigned long long)btrfs_ref_generation_v0(eb, ref0),
(unsigned long long)btrfs_ref_objectid_v0(eb, ref0),
(unsigned long)btrfs_ref_count_v0(eb, ref0));
}
#endif
void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l) void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
{ {
int i; int i;
u32 type;
u32 nr = btrfs_header_nritems(l); u32 nr = btrfs_header_nritems(l);
struct btrfs_item *item; struct btrfs_item *item;
struct btrfs_extent_item *ei;
struct btrfs_root_item *ri; struct btrfs_root_item *ri;
struct btrfs_dir_item *di; struct btrfs_dir_item *di;
struct btrfs_inode_item *ii; struct btrfs_inode_item *ii;
struct btrfs_block_group_item *bi; struct btrfs_block_group_item *bi;
struct btrfs_file_extent_item *fi; struct btrfs_file_extent_item *fi;
struct btrfs_extent_data_ref *dref;
struct btrfs_shared_data_ref *sref;
struct btrfs_dev_extent *dev_extent;
struct btrfs_key key; struct btrfs_key key;
struct btrfs_key found_key; struct btrfs_key found_key;
struct btrfs_extent_ref *ref;
struct btrfs_dev_extent *dev_extent;
u32 type;
printk(KERN_INFO "leaf %llu total ptrs %d free space %d\n", printk(KERN_INFO "leaf %llu total ptrs %d free space %d\n",
(unsigned long long)btrfs_header_bytenr(l), nr, (unsigned long long)btrfs_header_bytenr(l), nr,
...@@ -100,20 +210,25 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l) ...@@ -100,20 +210,25 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
btrfs_disk_root_refs(l, ri)); btrfs_disk_root_refs(l, ri));
break; break;
case BTRFS_EXTENT_ITEM_KEY: case BTRFS_EXTENT_ITEM_KEY:
ei = btrfs_item_ptr(l, i, struct btrfs_extent_item); print_extent_item(l, i);
printk(KERN_INFO "\t\textent data refs %u\n", break;
btrfs_extent_refs(l, ei)); case BTRFS_TREE_BLOCK_REF_KEY:
break; printk(KERN_INFO "\t\ttree block backref\n");
case BTRFS_EXTENT_REF_KEY: break;
ref = btrfs_item_ptr(l, i, struct btrfs_extent_ref); case BTRFS_SHARED_BLOCK_REF_KEY:
printk(KERN_INFO "\t\textent back ref root %llu " printk(KERN_INFO "\t\tshared block backref\n");
"gen %llu owner %llu num_refs %lu\n", break;
(unsigned long long)btrfs_ref_root(l, ref), case BTRFS_EXTENT_DATA_REF_KEY:
(unsigned long long)btrfs_ref_generation(l, ref), dref = btrfs_item_ptr(l, i,
(unsigned long long)btrfs_ref_objectid(l, ref), struct btrfs_extent_data_ref);
(unsigned long)btrfs_ref_num_refs(l, ref)); print_extent_data_ref(l, dref);
break;
case BTRFS_SHARED_DATA_REF_KEY:
sref = btrfs_item_ptr(l, i,
struct btrfs_shared_data_ref);
printk(KERN_INFO "\t\tshared data backref count %u\n",
btrfs_shared_data_ref_count(l, sref));
break; break;
case BTRFS_EXTENT_DATA_KEY: case BTRFS_EXTENT_DATA_KEY:
fi = btrfs_item_ptr(l, i, fi = btrfs_item_ptr(l, i,
struct btrfs_file_extent_item); struct btrfs_file_extent_item);
...@@ -139,6 +254,12 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l) ...@@ -139,6 +254,12 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
(unsigned long long) (unsigned long long)
btrfs_file_extent_ram_bytes(l, fi)); btrfs_file_extent_ram_bytes(l, fi));
break; break;
case BTRFS_EXTENT_REF_V0_KEY:
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
print_extent_ref_v0(l, i);
#else
BUG();
#endif
case BTRFS_BLOCK_GROUP_ITEM_KEY: case BTRFS_BLOCK_GROUP_ITEM_KEY:
bi = btrfs_item_ptr(l, i, bi = btrfs_item_ptr(l, i,
struct btrfs_block_group_item); struct btrfs_block_group_item);
......
This diff is collapsed.
...@@ -111,6 +111,15 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, ...@@ -111,6 +111,15 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
return ret; return ret;
} }
int btrfs_set_root_node(struct btrfs_root_item *item,
struct extent_buffer *node)
{
btrfs_set_root_bytenr(item, node->start);
btrfs_set_root_level(item, btrfs_header_level(node));
btrfs_set_root_generation(item, btrfs_header_generation(node));
return 0;
}
/* /*
* copy the data in 'item' into the btree * copy the data in 'item' into the btree
*/ */
...@@ -164,8 +173,7 @@ int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -164,8 +173,7 @@ int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
* offset lower than the latest root. They need to be queued for deletion to * offset lower than the latest root. They need to be queued for deletion to
* finish what was happening when we crashed. * finish what was happening when we crashed.
*/ */
int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid, int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid)
struct btrfs_root *latest)
{ {
struct btrfs_root *dead_root; struct btrfs_root *dead_root;
struct btrfs_item *item; struct btrfs_item *item;
...@@ -227,10 +235,7 @@ int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid, ...@@ -227,10 +235,7 @@ int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid,
goto err; goto err;
} }
if (objectid == BTRFS_TREE_RELOC_OBJECTID) ret = btrfs_add_dead_root(dead_root);
ret = btrfs_add_dead_reloc_root(dead_root);
else
ret = btrfs_add_dead_root(dead_root, latest);
if (ret) if (ret)
goto err; goto err;
goto again; goto again;
......
...@@ -52,7 +52,6 @@ ...@@ -52,7 +52,6 @@
#include "export.h" #include "export.h"
#include "compression.h" #include "compression.h"
static struct super_operations btrfs_super_ops; static struct super_operations btrfs_super_ops;
static void btrfs_put_super(struct super_block *sb) static void btrfs_put_super(struct super_block *sb)
...@@ -67,8 +66,8 @@ static void btrfs_put_super(struct super_block *sb) ...@@ -67,8 +66,8 @@ static void btrfs_put_super(struct super_block *sb)
enum { enum {
Opt_degraded, Opt_subvol, Opt_device, Opt_nodatasum, Opt_nodatacow, Opt_degraded, Opt_subvol, Opt_device, Opt_nodatasum, Opt_nodatacow,
Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier, Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier,
Opt_ssd, Opt_thread_pool, Opt_noacl, Opt_compress, Opt_notreelog, Opt_ssd, Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl,
Opt_ratio, Opt_flushoncommit, Opt_err, Opt_compress, Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_err,
}; };
static match_table_t tokens = { static match_table_t tokens = {
...@@ -84,6 +83,8 @@ static match_table_t tokens = { ...@@ -84,6 +83,8 @@ static match_table_t tokens = {
{Opt_thread_pool, "thread_pool=%d"}, {Opt_thread_pool, "thread_pool=%d"},
{Opt_compress, "compress"}, {Opt_compress, "compress"},
{Opt_ssd, "ssd"}, {Opt_ssd, "ssd"},
{Opt_ssd_spread, "ssd_spread"},
{Opt_nossd, "nossd"},
{Opt_noacl, "noacl"}, {Opt_noacl, "noacl"},
{Opt_notreelog, "notreelog"}, {Opt_notreelog, "notreelog"},
{Opt_flushoncommit, "flushoncommit"}, {Opt_flushoncommit, "flushoncommit"},
...@@ -158,7 +159,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) ...@@ -158,7 +159,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
*/ */
break; break;
case Opt_nodatasum: case Opt_nodatasum:
printk(KERN_INFO "btrfs: setting nodatacsum\n"); printk(KERN_INFO "btrfs: setting nodatasum\n");
btrfs_set_opt(info->mount_opt, NODATASUM); btrfs_set_opt(info->mount_opt, NODATASUM);
break; break;
case Opt_nodatacow: case Opt_nodatacow:
...@@ -174,6 +175,19 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) ...@@ -174,6 +175,19 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
printk(KERN_INFO "btrfs: use ssd allocation scheme\n"); printk(KERN_INFO "btrfs: use ssd allocation scheme\n");
btrfs_set_opt(info->mount_opt, SSD); btrfs_set_opt(info->mount_opt, SSD);
break; break;
case Opt_ssd_spread:
printk(KERN_INFO "btrfs: use spread ssd "
"allocation scheme\n");
btrfs_set_opt(info->mount_opt, SSD);
btrfs_set_opt(info->mount_opt, SSD_SPREAD);
break;
case Opt_nossd:
printk(KERN_INFO "btrfs: not using ssd allocation "
"scheme\n");
btrfs_set_opt(info->mount_opt, NOSSD);
btrfs_clear_opt(info->mount_opt, SSD);
btrfs_clear_opt(info->mount_opt, SSD_SPREAD);
break;
case Opt_nobarrier: case Opt_nobarrier:
printk(KERN_INFO "btrfs: turning off barriers\n"); printk(KERN_INFO "btrfs: turning off barriers\n");
btrfs_set_opt(info->mount_opt, NOBARRIER); btrfs_set_opt(info->mount_opt, NOBARRIER);
...@@ -322,7 +336,7 @@ static int btrfs_fill_super(struct super_block *sb, ...@@ -322,7 +336,7 @@ static int btrfs_fill_super(struct super_block *sb,
struct dentry *root_dentry; struct dentry *root_dentry;
struct btrfs_super_block *disk_super; struct btrfs_super_block *disk_super;
struct btrfs_root *tree_root; struct btrfs_root *tree_root;
struct btrfs_inode *bi; struct btrfs_key key;
int err; int err;
sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_maxbytes = MAX_LFS_FILESIZE;
...@@ -341,23 +355,15 @@ static int btrfs_fill_super(struct super_block *sb, ...@@ -341,23 +355,15 @@ static int btrfs_fill_super(struct super_block *sb,
} }
sb->s_fs_info = tree_root; sb->s_fs_info = tree_root;
disk_super = &tree_root->fs_info->super_copy; disk_super = &tree_root->fs_info->super_copy;
inode = btrfs_iget_locked(sb, BTRFS_FIRST_FREE_OBJECTID,
tree_root->fs_info->fs_root);
bi = BTRFS_I(inode);
bi->location.objectid = inode->i_ino;
bi->location.offset = 0;
bi->root = tree_root->fs_info->fs_root;
btrfs_set_key_type(&bi->location, BTRFS_INODE_ITEM_KEY); key.objectid = BTRFS_FIRST_FREE_OBJECTID;
key.type = BTRFS_INODE_ITEM_KEY;
if (!inode) { key.offset = 0;
err = -ENOMEM; inode = btrfs_iget(sb, &key, tree_root->fs_info->fs_root);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
goto fail_close; goto fail_close;
} }
if (inode->i_state & I_NEW) {
btrfs_read_locked_inode(inode);
unlock_new_inode(inode);
}
root_dentry = d_alloc_root(inode); root_dentry = d_alloc_root(inode);
if (!root_dentry) { if (!root_dentry) {
...@@ -433,7 +439,11 @@ static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs) ...@@ -433,7 +439,11 @@ static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
seq_printf(seq, ",thread_pool=%d", info->thread_pool_size); seq_printf(seq, ",thread_pool=%d", info->thread_pool_size);
if (btrfs_test_opt(root, COMPRESS)) if (btrfs_test_opt(root, COMPRESS))
seq_puts(seq, ",compress"); seq_puts(seq, ",compress");
if (btrfs_test_opt(root, SSD)) if (btrfs_test_opt(root, NOSSD))
seq_puts(seq, ",nossd");
if (btrfs_test_opt(root, SSD_SPREAD))
seq_puts(seq, ",ssd_spread");
else if (btrfs_test_opt(root, SSD))
seq_puts(seq, ",ssd"); seq_puts(seq, ",ssd");
if (btrfs_test_opt(root, NOTREELOG)) if (btrfs_test_opt(root, NOTREELOG))
seq_puts(seq, ",notreelog"); seq_puts(seq, ",notreelog");
...@@ -584,7 +594,8 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) ...@@ -584,7 +594,8 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
if (btrfs_super_log_root(&root->fs_info->super_copy) != 0) if (btrfs_super_log_root(&root->fs_info->super_copy) != 0)
return -EINVAL; return -EINVAL;
ret = btrfs_cleanup_reloc_trees(root); /* recover relocation */
ret = btrfs_recover_relocation(root);
WARN_ON(ret); WARN_ON(ret);
ret = btrfs_cleanup_fs_roots(root->fs_info); ret = btrfs_cleanup_fs_roots(root->fs_info);
......
This diff is collapsed.
...@@ -62,12 +62,6 @@ struct btrfs_pending_snapshot { ...@@ -62,12 +62,6 @@ struct btrfs_pending_snapshot {
struct list_head list; struct list_head list;
}; };
struct btrfs_dirty_root {
struct list_head list;
struct btrfs_root *root;
struct btrfs_root *latest_root;
};
static inline void btrfs_set_trans_block_group(struct btrfs_trans_handle *trans, static inline void btrfs_set_trans_block_group(struct btrfs_trans_handle *trans,
struct inode *inode) struct inode *inode)
{ {
...@@ -100,7 +94,8 @@ int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, ...@@ -100,7 +94,8 @@ int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans, int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
struct btrfs_root *root); struct btrfs_root *root);
int btrfs_add_dead_root(struct btrfs_root *root, struct btrfs_root *latest); int btrfs_add_dead_root(struct btrfs_root *root);
int btrfs_drop_dead_root(struct btrfs_root *root);
int btrfs_defrag_root(struct btrfs_root *root, int cacheonly); int btrfs_defrag_root(struct btrfs_root *root, int cacheonly);
int btrfs_clean_old_snapshots(struct btrfs_root *root); int btrfs_clean_old_snapshots(struct btrfs_root *root);
int btrfs_commit_transaction(struct btrfs_trans_handle *trans, int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
...@@ -108,7 +103,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -108,7 +103,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
struct btrfs_root *root); struct btrfs_root *root);
void btrfs_throttle(struct btrfs_root *root); void btrfs_throttle(struct btrfs_root *root);
int btrfs_record_root_in_trans(struct btrfs_root *root); int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_write_and_wait_marked_extents(struct btrfs_root *root, int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
struct extent_io_tree *dirty_pages); struct extent_io_tree *dirty_pages);
#endif #endif
This diff is collapsed.
This diff is collapsed.
...@@ -96,7 +96,12 @@ struct btrfs_fs_devices { ...@@ -96,7 +96,12 @@ struct btrfs_fs_devices {
u64 rw_devices; u64 rw_devices;
u64 total_rw_bytes; u64 total_rw_bytes;
struct block_device *latest_bdev; struct block_device *latest_bdev;
/* all of the devices in the FS */
/* all of the devices in the FS, protected by a mutex
* so we can safely walk it to write out the supers without
* worrying about add/remove by the multi-device code
*/
struct mutex device_list_mutex;
struct list_head devices; struct list_head devices;
/* devices not currently being allocated */ /* devices not currently being allocated */
...@@ -107,6 +112,11 @@ struct btrfs_fs_devices { ...@@ -107,6 +112,11 @@ struct btrfs_fs_devices {
int seeding; int seeding;
int opened; int opened;
/* set when we find or add a device that doesn't have the
* nonrot flag set
*/
int rotating;
}; };
struct btrfs_bio_stripe { struct btrfs_bio_stripe {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment