mirror of
https://github.com/adulau/aha.git
synced 2024-12-27 03:06:10 +00:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable: Btrfs: make sure fallocate properly starts a transaction Btrfs: make metadata chunks smaller Btrfs: Show discard option in /proc/mounts Btrfs: deny sys_link across subvolumes. Btrfs: fail mount on bad mount options Btrfs: don't add extent 0 to the free space cache v2 Btrfs: Fix per root used space accounting Btrfs: Fix btrfs_drop_extent_cache for skip pinned case Btrfs: Add delayed iput Btrfs: Pass transaction handle to security and ACL initialization functions Btrfs: Make truncate(2) more ENOSPC friendly Btrfs: Make fallocate(2) more ENOSPC friendly Btrfs: Avoid orphan inodes cleanup during committing transaction Btrfs: Avoid orphan inodes cleanup while replaying log Btrfs: Fix disk_i_size update corner case Btrfs: Rewrite btrfs_drop_extents Btrfs: Add btrfs_duplicate_item Btrfs: Avoid superfluous tree-log writeout
This commit is contained in:
commit
7c508e50be
20 changed files with 1185 additions and 928 deletions
|
@ -94,7 +94,8 @@ static int btrfs_xattr_acl_get(struct dentry *dentry, const char *name,
|
||||||
/*
|
/*
|
||||||
* Needs to be called with fs_mutex held
|
* Needs to be called with fs_mutex held
|
||||||
*/
|
*/
|
||||||
static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
static int btrfs_set_acl(struct btrfs_trans_handle *trans,
|
||||||
|
struct inode *inode, struct posix_acl *acl, int type)
|
||||||
{
|
{
|
||||||
int ret, size = 0;
|
int ret, size = 0;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -140,8 +141,7 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = __btrfs_setxattr(inode, name, value, size, 0);
|
ret = __btrfs_setxattr(trans, inode, name, value, size, 0);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kfree(value);
|
kfree(value);
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ out:
|
||||||
static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
|
static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
|
||||||
const void *value, size_t size, int flags, int type)
|
const void *value, size_t size, int flags, int type)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret;
|
||||||
struct posix_acl *acl = NULL;
|
struct posix_acl *acl = NULL;
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
|
@ -167,7 +167,7 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_set_acl(dentry->d_inode, acl, type);
|
ret = btrfs_set_acl(NULL, dentry->d_inode, acl, type);
|
||||||
|
|
||||||
posix_acl_release(acl);
|
posix_acl_release(acl);
|
||||||
|
|
||||||
|
@ -196,7 +196,8 @@ int btrfs_check_acl(struct inode *inode, int mask)
|
||||||
* stuff has been fixed to work with that. If the locking stuff changes, we
|
* stuff has been fixed to work with that. If the locking stuff changes, we
|
||||||
* need to re-evaluate the acl locking stuff.
|
* need to re-evaluate the acl locking stuff.
|
||||||
*/
|
*/
|
||||||
int btrfs_init_acl(struct inode *inode, struct inode *dir)
|
int btrfs_init_acl(struct btrfs_trans_handle *trans,
|
||||||
|
struct inode *inode, struct inode *dir)
|
||||||
{
|
{
|
||||||
struct posix_acl *acl = NULL;
|
struct posix_acl *acl = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -221,7 +222,8 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir)
|
||||||
mode_t mode;
|
mode_t mode;
|
||||||
|
|
||||||
if (S_ISDIR(inode->i_mode)) {
|
if (S_ISDIR(inode->i_mode)) {
|
||||||
ret = btrfs_set_acl(inode, acl, ACL_TYPE_DEFAULT);
|
ret = btrfs_set_acl(trans, inode, acl,
|
||||||
|
ACL_TYPE_DEFAULT);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
@ -236,7 +238,7 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir)
|
||||||
inode->i_mode = mode;
|
inode->i_mode = mode;
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
/* we need an acl */
|
/* we need an acl */
|
||||||
ret = btrfs_set_acl(inode, clone,
|
ret = btrfs_set_acl(trans, inode, clone,
|
||||||
ACL_TYPE_ACCESS);
|
ACL_TYPE_ACCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,7 +271,7 @@ int btrfs_acl_chmod(struct inode *inode)
|
||||||
|
|
||||||
ret = posix_acl_chmod_masq(clone, inode->i_mode);
|
ret = posix_acl_chmod_masq(clone, inode->i_mode);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = btrfs_set_acl(inode, clone, ACL_TYPE_ACCESS);
|
ret = btrfs_set_acl(NULL, inode, clone, ACL_TYPE_ACCESS);
|
||||||
|
|
||||||
posix_acl_release(clone);
|
posix_acl_release(clone);
|
||||||
|
|
||||||
|
@ -297,7 +299,8 @@ int btrfs_acl_chmod(struct inode *inode)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_init_acl(struct inode *inode, struct inode *dir)
|
int btrfs_init_acl(struct btrfs_trans_handle *trans,
|
||||||
|
struct inode *inode, struct inode *dir)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,9 +44,6 @@ struct btrfs_inode {
|
||||||
*/
|
*/
|
||||||
struct extent_io_tree io_failure_tree;
|
struct extent_io_tree io_failure_tree;
|
||||||
|
|
||||||
/* held while inesrting or deleting extents from files */
|
|
||||||
struct mutex extent_mutex;
|
|
||||||
|
|
||||||
/* held while logging the inode in tree-log.c */
|
/* held while logging the inode in tree-log.c */
|
||||||
struct mutex log_mutex;
|
struct mutex log_mutex;
|
||||||
|
|
||||||
|
@ -166,7 +163,7 @@ static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
|
||||||
|
|
||||||
static inline void btrfs_i_size_write(struct inode *inode, u64 size)
|
static inline void btrfs_i_size_write(struct inode *inode, u64 size)
|
||||||
{
|
{
|
||||||
inode->i_size = size;
|
i_size_write(inode, size);
|
||||||
BTRFS_I(inode)->disk_i_size = size;
|
BTRFS_I(inode)->disk_i_size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
229
fs/btrfs/ctree.c
229
fs/btrfs/ctree.c
|
@ -37,6 +37,11 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
|
||||||
struct extent_buffer *src_buf);
|
struct extent_buffer *src_buf);
|
||||||
static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||||
struct btrfs_path *path, int level, int slot);
|
struct btrfs_path *path, int level, int slot);
|
||||||
|
static int setup_items_for_insert(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root, struct btrfs_path *path,
|
||||||
|
struct btrfs_key *cpu_key, u32 *data_size,
|
||||||
|
u32 total_data, u32 total_size, int nr);
|
||||||
|
|
||||||
|
|
||||||
struct btrfs_path *btrfs_alloc_path(void)
|
struct btrfs_path *btrfs_alloc_path(void)
|
||||||
{
|
{
|
||||||
|
@ -451,9 +456,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
|
||||||
extent_buffer_get(cow);
|
extent_buffer_get(cow);
|
||||||
spin_unlock(&root->node_lock);
|
spin_unlock(&root->node_lock);
|
||||||
|
|
||||||
btrfs_free_extent(trans, root, buf->start, buf->len,
|
btrfs_free_tree_block(trans, root, buf->start, buf->len,
|
||||||
parent_start, root->root_key.objectid,
|
parent_start, root->root_key.objectid, level);
|
||||||
level, 0);
|
|
||||||
free_extent_buffer(buf);
|
free_extent_buffer(buf);
|
||||||
add_root_to_dirty_list(root);
|
add_root_to_dirty_list(root);
|
||||||
} else {
|
} else {
|
||||||
|
@ -468,9 +472,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
|
||||||
btrfs_set_node_ptr_generation(parent, parent_slot,
|
btrfs_set_node_ptr_generation(parent, parent_slot,
|
||||||
trans->transid);
|
trans->transid);
|
||||||
btrfs_mark_buffer_dirty(parent);
|
btrfs_mark_buffer_dirty(parent);
|
||||||
btrfs_free_extent(trans, root, buf->start, buf->len,
|
btrfs_free_tree_block(trans, root, buf->start, buf->len,
|
||||||
parent_start, root->root_key.objectid,
|
parent_start, root->root_key.objectid, level);
|
||||||
level, 0);
|
|
||||||
}
|
}
|
||||||
if (unlock_orig)
|
if (unlock_orig)
|
||||||
btrfs_tree_unlock(buf);
|
btrfs_tree_unlock(buf);
|
||||||
|
@ -1030,8 +1033,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
|
||||||
btrfs_tree_unlock(mid);
|
btrfs_tree_unlock(mid);
|
||||||
/* once for the path */
|
/* once for the path */
|
||||||
free_extent_buffer(mid);
|
free_extent_buffer(mid);
|
||||||
ret = btrfs_free_extent(trans, root, mid->start, mid->len,
|
ret = btrfs_free_tree_block(trans, root, mid->start, mid->len,
|
||||||
0, root->root_key.objectid, level, 1);
|
0, root->root_key.objectid, level);
|
||||||
/* once for the root ptr */
|
/* once for the root ptr */
|
||||||
free_extent_buffer(mid);
|
free_extent_buffer(mid);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1095,10 +1098,10 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
|
||||||
1);
|
1);
|
||||||
if (wret)
|
if (wret)
|
||||||
ret = wret;
|
ret = wret;
|
||||||
wret = btrfs_free_extent(trans, root, bytenr,
|
wret = btrfs_free_tree_block(trans, root,
|
||||||
blocksize, 0,
|
bytenr, blocksize, 0,
|
||||||
root->root_key.objectid,
|
root->root_key.objectid,
|
||||||
level, 0);
|
level);
|
||||||
if (wret)
|
if (wret)
|
||||||
ret = wret;
|
ret = wret;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1143,9 +1146,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
|
||||||
wret = del_ptr(trans, root, path, level + 1, pslot);
|
wret = del_ptr(trans, root, path, level + 1, pslot);
|
||||||
if (wret)
|
if (wret)
|
||||||
ret = wret;
|
ret = wret;
|
||||||
wret = btrfs_free_extent(trans, root, bytenr, blocksize,
|
wret = btrfs_free_tree_block(trans, root, bytenr, blocksize,
|
||||||
0, root->root_key.objectid,
|
0, root->root_key.objectid, level);
|
||||||
level, 0);
|
|
||||||
if (wret)
|
if (wret)
|
||||||
ret = wret;
|
ret = wret;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2997,75 +2999,85 @@ again:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans,
|
||||||
* This function splits a single item into two items,
|
struct btrfs_root *root,
|
||||||
* giving 'new_key' to the new item and splitting the
|
struct btrfs_path *path, int ins_len)
|
||||||
* old one at split_offset (from the start of the item).
|
|
||||||
*
|
|
||||||
* The path may be released by this operation. After
|
|
||||||
* the split, the path is pointing to the old item. The
|
|
||||||
* new item is going to be in the same node as the old one.
|
|
||||||
*
|
|
||||||
* Note, the item being split must be smaller enough to live alone on
|
|
||||||
* a tree block with room for one extra struct btrfs_item
|
|
||||||
*
|
|
||||||
* This allows us to split the item in place, keeping a lock on the
|
|
||||||
* leaf the entire time.
|
|
||||||
*/
|
|
||||||
int btrfs_split_item(struct btrfs_trans_handle *trans,
|
|
||||||
struct btrfs_root *root,
|
|
||||||
struct btrfs_path *path,
|
|
||||||
struct btrfs_key *new_key,
|
|
||||||
unsigned long split_offset)
|
|
||||||
{
|
{
|
||||||
u32 item_size;
|
struct btrfs_key key;
|
||||||
struct extent_buffer *leaf;
|
struct extent_buffer *leaf;
|
||||||
struct btrfs_key orig_key;
|
struct btrfs_file_extent_item *fi;
|
||||||
struct btrfs_item *item;
|
u64 extent_len = 0;
|
||||||
struct btrfs_item *new_item;
|
u32 item_size;
|
||||||
int ret = 0;
|
int ret;
|
||||||
int slot;
|
|
||||||
u32 nritems;
|
|
||||||
u32 orig_offset;
|
|
||||||
struct btrfs_disk_key disk_key;
|
|
||||||
char *buf;
|
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
btrfs_item_key_to_cpu(leaf, &orig_key, path->slots[0]);
|
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
|
||||||
if (btrfs_leaf_free_space(root, leaf) >= sizeof(struct btrfs_item))
|
|
||||||
goto split;
|
BUG_ON(key.type != BTRFS_EXTENT_DATA_KEY &&
|
||||||
|
key.type != BTRFS_EXTENT_CSUM_KEY);
|
||||||
|
|
||||||
|
if (btrfs_leaf_free_space(root, leaf) >= ins_len)
|
||||||
|
return 0;
|
||||||
|
|
||||||
item_size = btrfs_item_size_nr(leaf, path->slots[0]);
|
item_size = btrfs_item_size_nr(leaf, path->slots[0]);
|
||||||
|
if (key.type == BTRFS_EXTENT_DATA_KEY) {
|
||||||
|
fi = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
|
struct btrfs_file_extent_item);
|
||||||
|
extent_len = btrfs_file_extent_num_bytes(leaf, fi);
|
||||||
|
}
|
||||||
btrfs_release_path(root, path);
|
btrfs_release_path(root, path);
|
||||||
|
|
||||||
path->search_for_split = 1;
|
|
||||||
path->keep_locks = 1;
|
path->keep_locks = 1;
|
||||||
|
path->search_for_split = 1;
|
||||||
ret = btrfs_search_slot(trans, root, &orig_key, path, 0, 1);
|
ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
|
||||||
path->search_for_split = 0;
|
path->search_for_split = 0;
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
ret = -EAGAIN;
|
||||||
|
leaf = path->nodes[0];
|
||||||
/* if our item isn't there or got smaller, return now */
|
/* if our item isn't there or got smaller, return now */
|
||||||
if (ret != 0 || item_size != btrfs_item_size_nr(path->nodes[0],
|
if (ret > 0 || item_size != btrfs_item_size_nr(leaf, path->slots[0]))
|
||||||
path->slots[0])) {
|
goto err;
|
||||||
path->keep_locks = 0;
|
|
||||||
return -EAGAIN;
|
if (key.type == BTRFS_EXTENT_DATA_KEY) {
|
||||||
|
fi = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
|
struct btrfs_file_extent_item);
|
||||||
|
if (extent_len != btrfs_file_extent_num_bytes(leaf, fi))
|
||||||
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_set_path_blocking(path);
|
btrfs_set_path_blocking(path);
|
||||||
ret = split_leaf(trans, root, &orig_key, path,
|
ret = split_leaf(trans, root, &key, path, ins_len, 1);
|
||||||
sizeof(struct btrfs_item), 1);
|
|
||||||
path->keep_locks = 0;
|
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
|
path->keep_locks = 0;
|
||||||
btrfs_unlock_up_safe(path, 1);
|
btrfs_unlock_up_safe(path, 1);
|
||||||
|
return 0;
|
||||||
|
err:
|
||||||
|
path->keep_locks = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static noinline int split_item(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root,
|
||||||
|
struct btrfs_path *path,
|
||||||
|
struct btrfs_key *new_key,
|
||||||
|
unsigned long split_offset)
|
||||||
|
{
|
||||||
|
struct extent_buffer *leaf;
|
||||||
|
struct btrfs_item *item;
|
||||||
|
struct btrfs_item *new_item;
|
||||||
|
int slot;
|
||||||
|
char *buf;
|
||||||
|
u32 nritems;
|
||||||
|
u32 item_size;
|
||||||
|
u32 orig_offset;
|
||||||
|
struct btrfs_disk_key disk_key;
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item));
|
BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item));
|
||||||
|
|
||||||
split:
|
|
||||||
/*
|
|
||||||
* make sure any changes to the path from split_leaf leave it
|
|
||||||
* in a blocking state
|
|
||||||
*/
|
|
||||||
btrfs_set_path_blocking(path);
|
btrfs_set_path_blocking(path);
|
||||||
|
|
||||||
item = btrfs_item_nr(leaf, path->slots[0]);
|
item = btrfs_item_nr(leaf, path->slots[0]);
|
||||||
|
@ -3073,19 +3085,19 @@ split:
|
||||||
item_size = btrfs_item_size(leaf, item);
|
item_size = btrfs_item_size(leaf, item);
|
||||||
|
|
||||||
buf = kmalloc(item_size, GFP_NOFS);
|
buf = kmalloc(item_size, GFP_NOFS);
|
||||||
|
if (!buf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf,
|
read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf,
|
||||||
path->slots[0]), item_size);
|
path->slots[0]), item_size);
|
||||||
|
|
||||||
slot = path->slots[0] + 1;
|
slot = path->slots[0] + 1;
|
||||||
leaf = path->nodes[0];
|
|
||||||
|
|
||||||
nritems = btrfs_header_nritems(leaf);
|
nritems = btrfs_header_nritems(leaf);
|
||||||
|
|
||||||
if (slot != nritems) {
|
if (slot != nritems) {
|
||||||
/* shift the items */
|
/* shift the items */
|
||||||
memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + 1),
|
memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + 1),
|
||||||
btrfs_item_nr_offset(slot),
|
btrfs_item_nr_offset(slot),
|
||||||
(nritems - slot) * sizeof(struct btrfs_item));
|
(nritems - slot) * sizeof(struct btrfs_item));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_cpu_key_to_disk(&disk_key, new_key);
|
btrfs_cpu_key_to_disk(&disk_key, new_key);
|
||||||
|
@ -3113,15 +3125,80 @@ split:
|
||||||
item_size - split_offset);
|
item_size - split_offset);
|
||||||
btrfs_mark_buffer_dirty(leaf);
|
btrfs_mark_buffer_dirty(leaf);
|
||||||
|
|
||||||
ret = 0;
|
BUG_ON(btrfs_leaf_free_space(root, leaf) < 0);
|
||||||
if (btrfs_leaf_free_space(root, leaf) < 0) {
|
|
||||||
btrfs_print_leaf(root, leaf);
|
|
||||||
BUG();
|
|
||||||
}
|
|
||||||
kfree(buf);
|
kfree(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function splits a single item into two items,
|
||||||
|
* giving 'new_key' to the new item and splitting the
|
||||||
|
* old one at split_offset (from the start of the item).
|
||||||
|
*
|
||||||
|
* The path may be released by this operation. After
|
||||||
|
* the split, the path is pointing to the old item. The
|
||||||
|
* new item is going to be in the same node as the old one.
|
||||||
|
*
|
||||||
|
* Note, the item being split must be smaller enough to live alone on
|
||||||
|
* a tree block with room for one extra struct btrfs_item
|
||||||
|
*
|
||||||
|
* This allows us to split the item in place, keeping a lock on the
|
||||||
|
* leaf the entire time.
|
||||||
|
*/
|
||||||
|
int btrfs_split_item(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root,
|
||||||
|
struct btrfs_path *path,
|
||||||
|
struct btrfs_key *new_key,
|
||||||
|
unsigned long split_offset)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
ret = setup_leaf_for_split(trans, root, path,
|
||||||
|
sizeof(struct btrfs_item));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = split_item(trans, root, path, new_key, split_offset);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function duplicate a item, giving 'new_key' to the new item.
|
||||||
|
* It guarantees both items live in the same tree leaf and the new item
|
||||||
|
* is contiguous with the original item.
|
||||||
|
*
|
||||||
|
* This allows us to split file extent in place, keeping a lock on the
|
||||||
|
* leaf the entire time.
|
||||||
|
*/
|
||||||
|
int btrfs_duplicate_item(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root,
|
||||||
|
struct btrfs_path *path,
|
||||||
|
struct btrfs_key *new_key)
|
||||||
|
{
|
||||||
|
struct extent_buffer *leaf;
|
||||||
|
int ret;
|
||||||
|
u32 item_size;
|
||||||
|
|
||||||
|
leaf = path->nodes[0];
|
||||||
|
item_size = btrfs_item_size_nr(leaf, path->slots[0]);
|
||||||
|
ret = setup_leaf_for_split(trans, root, path,
|
||||||
|
item_size + sizeof(struct btrfs_item));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
path->slots[0]++;
|
||||||
|
ret = setup_items_for_insert(trans, root, path, new_key, &item_size,
|
||||||
|
item_size, item_size +
|
||||||
|
sizeof(struct btrfs_item), 1);
|
||||||
|
BUG_ON(ret);
|
||||||
|
|
||||||
|
leaf = path->nodes[0];
|
||||||
|
memcpy_extent_buffer(leaf,
|
||||||
|
btrfs_item_ptr_offset(leaf, path->slots[0]),
|
||||||
|
btrfs_item_ptr_offset(leaf, path->slots[0] - 1),
|
||||||
|
item_size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* make the item pointed to by the path smaller. new_size indicates
|
* make the item pointed to by the path smaller. new_size indicates
|
||||||
* how small to make it, and from_end tells us if we just chop bytes
|
* how small to make it, and from_end tells us if we just chop bytes
|
||||||
|
@ -3714,8 +3791,8 @@ static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans,
|
||||||
*/
|
*/
|
||||||
btrfs_unlock_up_safe(path, 0);
|
btrfs_unlock_up_safe(path, 0);
|
||||||
|
|
||||||
ret = btrfs_free_extent(trans, root, leaf->start, leaf->len,
|
ret = btrfs_free_tree_block(trans, root, leaf->start, leaf->len,
|
||||||
0, root->root_key.objectid, 0, 0);
|
0, root->root_key.objectid, 0);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -310,6 +310,9 @@ struct btrfs_header {
|
||||||
#define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \
|
#define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \
|
||||||
sizeof(struct btrfs_item) - \
|
sizeof(struct btrfs_item) - \
|
||||||
sizeof(struct btrfs_file_extent_item))
|
sizeof(struct btrfs_file_extent_item))
|
||||||
|
#define BTRFS_MAX_XATTR_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \
|
||||||
|
sizeof(struct btrfs_item) -\
|
||||||
|
sizeof(struct btrfs_dir_item))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -859,8 +862,9 @@ struct btrfs_fs_info {
|
||||||
struct mutex ordered_operations_mutex;
|
struct mutex ordered_operations_mutex;
|
||||||
struct rw_semaphore extent_commit_sem;
|
struct rw_semaphore extent_commit_sem;
|
||||||
|
|
||||||
struct rw_semaphore subvol_sem;
|
struct rw_semaphore cleanup_work_sem;
|
||||||
|
|
||||||
|
struct rw_semaphore subvol_sem;
|
||||||
struct srcu_struct subvol_srcu;
|
struct srcu_struct subvol_srcu;
|
||||||
|
|
||||||
struct list_head trans_list;
|
struct list_head trans_list;
|
||||||
|
@ -868,6 +872,9 @@ struct btrfs_fs_info {
|
||||||
struct list_head dead_roots;
|
struct list_head dead_roots;
|
||||||
struct list_head caching_block_groups;
|
struct list_head caching_block_groups;
|
||||||
|
|
||||||
|
spinlock_t delayed_iput_lock;
|
||||||
|
struct list_head delayed_iputs;
|
||||||
|
|
||||||
atomic_t nr_async_submits;
|
atomic_t nr_async_submits;
|
||||||
atomic_t async_submit_draining;
|
atomic_t async_submit_draining;
|
||||||
atomic_t nr_async_bios;
|
atomic_t nr_async_bios;
|
||||||
|
@ -1034,12 +1041,12 @@ struct btrfs_root {
|
||||||
int ref_cows;
|
int ref_cows;
|
||||||
int track_dirty;
|
int track_dirty;
|
||||||
int in_radix;
|
int in_radix;
|
||||||
|
int clean_orphans;
|
||||||
|
|
||||||
u64 defrag_trans_start;
|
u64 defrag_trans_start;
|
||||||
struct btrfs_key defrag_progress;
|
struct btrfs_key defrag_progress;
|
||||||
struct btrfs_key defrag_max;
|
struct btrfs_key defrag_max;
|
||||||
int defrag_running;
|
int defrag_running;
|
||||||
int defrag_level;
|
|
||||||
char *name;
|
char *name;
|
||||||
int in_sysfs;
|
int in_sysfs;
|
||||||
|
|
||||||
|
@ -1975,6 +1982,10 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
||||||
u64 parent, u64 root_objectid,
|
u64 parent, u64 root_objectid,
|
||||||
struct btrfs_disk_key *key, int level,
|
struct btrfs_disk_key *key, int level,
|
||||||
u64 hint, u64 empty_size);
|
u64 hint, u64 empty_size);
|
||||||
|
int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root,
|
||||||
|
u64 bytenr, u32 blocksize,
|
||||||
|
u64 parent, u64 root_objectid, int level);
|
||||||
struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
|
struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
u64 bytenr, u32 blocksize,
|
u64 bytenr, u32 blocksize,
|
||||||
|
@ -2089,6 +2100,10 @@ int btrfs_split_item(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_path *path,
|
struct btrfs_path *path,
|
||||||
struct btrfs_key *new_key,
|
struct btrfs_key *new_key,
|
||||||
unsigned long split_offset);
|
unsigned long split_offset);
|
||||||
|
int btrfs_duplicate_item(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root,
|
||||||
|
struct btrfs_path *path,
|
||||||
|
struct btrfs_key *new_key);
|
||||||
int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
|
int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||||
*root, struct btrfs_key *key, struct btrfs_path *p, int
|
*root, struct btrfs_key *key, struct btrfs_path *p, int
|
||||||
ins_len, int cow);
|
ins_len, int cow);
|
||||||
|
@ -2196,9 +2211,10 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_path *path,
|
struct btrfs_path *path,
|
||||||
struct btrfs_dir_item *di);
|
struct btrfs_dir_item *di);
|
||||||
int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
|
int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, const char *name,
|
struct btrfs_root *root,
|
||||||
u16 name_len, const void *data, u16 data_len,
|
struct btrfs_path *path, u64 objectid,
|
||||||
u64 dir);
|
const char *name, u16 name_len,
|
||||||
|
const void *data, u16 data_len);
|
||||||
struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
|
struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
struct btrfs_path *path, u64 dir,
|
struct btrfs_path *path, u64 dir,
|
||||||
|
@ -2292,7 +2308,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
|
||||||
struct inode *inode, u64 new_size,
|
struct inode *inode, u64 new_size,
|
||||||
u32 min_type);
|
u32 min_type);
|
||||||
|
|
||||||
int btrfs_start_delalloc_inodes(struct btrfs_root *root);
|
int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput);
|
||||||
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end);
|
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end);
|
||||||
int btrfs_writepages(struct address_space *mapping,
|
int btrfs_writepages(struct address_space *mapping,
|
||||||
struct writeback_control *wbc);
|
struct writeback_control *wbc);
|
||||||
|
@ -2332,6 +2348,8 @@ int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode);
|
||||||
void btrfs_orphan_cleanup(struct btrfs_root *root);
|
void btrfs_orphan_cleanup(struct btrfs_root *root);
|
||||||
int btrfs_cont_expand(struct inode *inode, loff_t size);
|
int btrfs_cont_expand(struct inode *inode, loff_t size);
|
||||||
int btrfs_invalidate_inodes(struct btrfs_root *root);
|
int btrfs_invalidate_inodes(struct btrfs_root *root);
|
||||||
|
void btrfs_add_delayed_iput(struct inode *inode);
|
||||||
|
void btrfs_run_delayed_iputs(struct btrfs_root *root);
|
||||||
extern const struct dentry_operations btrfs_dentry_operations;
|
extern const struct dentry_operations btrfs_dentry_operations;
|
||||||
|
|
||||||
/* ioctl.c */
|
/* ioctl.c */
|
||||||
|
@ -2345,12 +2363,9 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
|
||||||
int skip_pinned);
|
int skip_pinned);
|
||||||
int btrfs_check_file(struct btrfs_root *root, struct inode *inode);
|
int btrfs_check_file(struct btrfs_root *root, struct inode *inode);
|
||||||
extern const struct file_operations btrfs_file_operations;
|
extern const struct file_operations btrfs_file_operations;
|
||||||
int btrfs_drop_extents(struct btrfs_trans_handle *trans,
|
int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
|
||||||
struct btrfs_root *root, struct inode *inode,
|
u64 start, u64 end, u64 *hint_byte, int drop_cache);
|
||||||
u64 start, u64 end, u64 locked_end,
|
|
||||||
u64 inline_limit, u64 *hint_block, int drop_cache);
|
|
||||||
int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
|
int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
|
||||||
struct inode *inode, u64 start, u64 end);
|
struct inode *inode, u64 start, u64 end);
|
||||||
int btrfs_release_file(struct inode *inode, struct file *file);
|
int btrfs_release_file(struct inode *inode, struct file *file);
|
||||||
|
|
||||||
|
@ -2380,7 +2395,8 @@ int btrfs_check_acl(struct inode *inode, int mask);
|
||||||
#else
|
#else
|
||||||
#define btrfs_check_acl NULL
|
#define btrfs_check_acl NULL
|
||||||
#endif
|
#endif
|
||||||
int btrfs_init_acl(struct inode *inode, struct inode *dir);
|
int btrfs_init_acl(struct btrfs_trans_handle *trans,
|
||||||
|
struct inode *inode, struct inode *dir);
|
||||||
int btrfs_acl_chmod(struct inode *inode);
|
int btrfs_acl_chmod(struct inode *inode);
|
||||||
|
|
||||||
/* relocation.c */
|
/* relocation.c */
|
||||||
|
|
|
@ -68,12 +68,12 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
|
||||||
* into the tree
|
* into the tree
|
||||||
*/
|
*/
|
||||||
int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
|
int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, const char *name,
|
struct btrfs_root *root,
|
||||||
u16 name_len, const void *data, u16 data_len,
|
struct btrfs_path *path, u64 objectid,
|
||||||
u64 dir)
|
const char *name, u16 name_len,
|
||||||
|
const void *data, u16 data_len)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct btrfs_path *path;
|
|
||||||
struct btrfs_dir_item *dir_item;
|
struct btrfs_dir_item *dir_item;
|
||||||
unsigned long name_ptr, data_ptr;
|
unsigned long name_ptr, data_ptr;
|
||||||
struct btrfs_key key, location;
|
struct btrfs_key key, location;
|
||||||
|
@ -81,15 +81,11 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
|
||||||
struct extent_buffer *leaf;
|
struct extent_buffer *leaf;
|
||||||
u32 data_size;
|
u32 data_size;
|
||||||
|
|
||||||
key.objectid = dir;
|
BUG_ON(name_len + data_len > BTRFS_MAX_XATTR_SIZE(root));
|
||||||
|
|
||||||
|
key.objectid = objectid;
|
||||||
btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
|
btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
|
||||||
key.offset = btrfs_name_hash(name, name_len);
|
key.offset = btrfs_name_hash(name, name_len);
|
||||||
path = btrfs_alloc_path();
|
|
||||||
if (!path)
|
|
||||||
return -ENOMEM;
|
|
||||||
if (name_len + data_len + sizeof(struct btrfs_dir_item) >
|
|
||||||
BTRFS_LEAF_DATA_SIZE(root) - sizeof(struct btrfs_item))
|
|
||||||
return -ENOSPC;
|
|
||||||
|
|
||||||
data_size = sizeof(*dir_item) + name_len + data_len;
|
data_size = sizeof(*dir_item) + name_len + data_len;
|
||||||
dir_item = insert_with_overflow(trans, root, path, &key, data_size,
|
dir_item = insert_with_overflow(trans, root, path, &key, data_size,
|
||||||
|
@ -117,7 +113,6 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
|
||||||
write_extent_buffer(leaf, data, data_ptr, data_len);
|
write_extent_buffer(leaf, data, data_ptr, data_len);
|
||||||
btrfs_mark_buffer_dirty(path->nodes[0]);
|
btrfs_mark_buffer_dirty(path->nodes[0]);
|
||||||
|
|
||||||
btrfs_free_path(path);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -892,6 +892,8 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
|
||||||
root->stripesize = stripesize;
|
root->stripesize = stripesize;
|
||||||
root->ref_cows = 0;
|
root->ref_cows = 0;
|
||||||
root->track_dirty = 0;
|
root->track_dirty = 0;
|
||||||
|
root->in_radix = 0;
|
||||||
|
root->clean_orphans = 0;
|
||||||
|
|
||||||
root->fs_info = fs_info;
|
root->fs_info = fs_info;
|
||||||
root->objectid = objectid;
|
root->objectid = objectid;
|
||||||
|
@ -928,7 +930,6 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
|
||||||
root->defrag_trans_start = fs_info->generation;
|
root->defrag_trans_start = fs_info->generation;
|
||||||
init_completion(&root->kobj_unregister);
|
init_completion(&root->kobj_unregister);
|
||||||
root->defrag_running = 0;
|
root->defrag_running = 0;
|
||||||
root->defrag_level = 0;
|
|
||||||
root->root_key.objectid = objectid;
|
root->root_key.objectid = objectid;
|
||||||
root->anon_super.s_root = NULL;
|
root->anon_super.s_root = NULL;
|
||||||
root->anon_super.s_dev = 0;
|
root->anon_super.s_dev = 0;
|
||||||
|
@ -980,12 +981,12 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = find_first_extent_bit(&log_root_tree->dirty_log_pages,
|
ret = find_first_extent_bit(&log_root_tree->dirty_log_pages,
|
||||||
0, &start, &end, EXTENT_DIRTY);
|
0, &start, &end, EXTENT_DIRTY | EXTENT_NEW);
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
clear_extent_dirty(&log_root_tree->dirty_log_pages,
|
clear_extent_bits(&log_root_tree->dirty_log_pages, start, end,
|
||||||
start, end, GFP_NOFS);
|
EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS);
|
||||||
}
|
}
|
||||||
eb = fs_info->log_root_tree->node;
|
eb = fs_info->log_root_tree->node;
|
||||||
|
|
||||||
|
@ -1210,8 +1211,10 @@ again:
|
||||||
ret = radix_tree_insert(&fs_info->fs_roots_radix,
|
ret = radix_tree_insert(&fs_info->fs_roots_radix,
|
||||||
(unsigned long)root->root_key.objectid,
|
(unsigned long)root->root_key.objectid,
|
||||||
root);
|
root);
|
||||||
if (ret == 0)
|
if (ret == 0) {
|
||||||
root->in_radix = 1;
|
root->in_radix = 1;
|
||||||
|
root->clean_orphans = 1;
|
||||||
|
}
|
||||||
spin_unlock(&fs_info->fs_roots_radix_lock);
|
spin_unlock(&fs_info->fs_roots_radix_lock);
|
||||||
radix_tree_preload_end();
|
radix_tree_preload_end();
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -1225,10 +1228,6 @@ again:
|
||||||
ret = btrfs_find_dead_roots(fs_info->tree_root,
|
ret = btrfs_find_dead_roots(fs_info->tree_root,
|
||||||
root->root_key.objectid);
|
root->root_key.objectid);
|
||||||
WARN_ON(ret);
|
WARN_ON(ret);
|
||||||
|
|
||||||
if (!(fs_info->sb->s_flags & MS_RDONLY))
|
|
||||||
btrfs_orphan_cleanup(root);
|
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
fail:
|
fail:
|
||||||
free_fs_root(root);
|
free_fs_root(root);
|
||||||
|
@ -1477,6 +1476,7 @@ static int cleaner_kthread(void *arg)
|
||||||
|
|
||||||
if (!(root->fs_info->sb->s_flags & MS_RDONLY) &&
|
if (!(root->fs_info->sb->s_flags & MS_RDONLY) &&
|
||||||
mutex_trylock(&root->fs_info->cleaner_mutex)) {
|
mutex_trylock(&root->fs_info->cleaner_mutex)) {
|
||||||
|
btrfs_run_delayed_iputs(root);
|
||||||
btrfs_clean_old_snapshots(root);
|
btrfs_clean_old_snapshots(root);
|
||||||
mutex_unlock(&root->fs_info->cleaner_mutex);
|
mutex_unlock(&root->fs_info->cleaner_mutex);
|
||||||
}
|
}
|
||||||
|
@ -1606,6 +1606,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||||
INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
|
INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
|
||||||
INIT_LIST_HEAD(&fs_info->trans_list);
|
INIT_LIST_HEAD(&fs_info->trans_list);
|
||||||
INIT_LIST_HEAD(&fs_info->dead_roots);
|
INIT_LIST_HEAD(&fs_info->dead_roots);
|
||||||
|
INIT_LIST_HEAD(&fs_info->delayed_iputs);
|
||||||
INIT_LIST_HEAD(&fs_info->hashers);
|
INIT_LIST_HEAD(&fs_info->hashers);
|
||||||
INIT_LIST_HEAD(&fs_info->delalloc_inodes);
|
INIT_LIST_HEAD(&fs_info->delalloc_inodes);
|
||||||
INIT_LIST_HEAD(&fs_info->ordered_operations);
|
INIT_LIST_HEAD(&fs_info->ordered_operations);
|
||||||
|
@ -1614,6 +1615,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||||
spin_lock_init(&fs_info->new_trans_lock);
|
spin_lock_init(&fs_info->new_trans_lock);
|
||||||
spin_lock_init(&fs_info->ref_cache_lock);
|
spin_lock_init(&fs_info->ref_cache_lock);
|
||||||
spin_lock_init(&fs_info->fs_roots_radix_lock);
|
spin_lock_init(&fs_info->fs_roots_radix_lock);
|
||||||
|
spin_lock_init(&fs_info->delayed_iput_lock);
|
||||||
|
|
||||||
init_completion(&fs_info->kobj_unregister);
|
init_completion(&fs_info->kobj_unregister);
|
||||||
fs_info->tree_root = tree_root;
|
fs_info->tree_root = tree_root;
|
||||||
|
@ -1689,6 +1691,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||||
mutex_init(&fs_info->cleaner_mutex);
|
mutex_init(&fs_info->cleaner_mutex);
|
||||||
mutex_init(&fs_info->volume_mutex);
|
mutex_init(&fs_info->volume_mutex);
|
||||||
init_rwsem(&fs_info->extent_commit_sem);
|
init_rwsem(&fs_info->extent_commit_sem);
|
||||||
|
init_rwsem(&fs_info->cleanup_work_sem);
|
||||||
init_rwsem(&fs_info->subvol_sem);
|
init_rwsem(&fs_info->subvol_sem);
|
||||||
|
|
||||||
btrfs_init_free_cluster(&fs_info->meta_alloc_cluster);
|
btrfs_init_free_cluster(&fs_info->meta_alloc_cluster);
|
||||||
|
@ -2386,8 +2389,14 @@ int btrfs_commit_super(struct btrfs_root *root)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
mutex_lock(&root->fs_info->cleaner_mutex);
|
mutex_lock(&root->fs_info->cleaner_mutex);
|
||||||
|
btrfs_run_delayed_iputs(root);
|
||||||
btrfs_clean_old_snapshots(root);
|
btrfs_clean_old_snapshots(root);
|
||||||
mutex_unlock(&root->fs_info->cleaner_mutex);
|
mutex_unlock(&root->fs_info->cleaner_mutex);
|
||||||
|
|
||||||
|
/* wait until ongoing cleanup work done */
|
||||||
|
down_write(&root->fs_info->cleanup_work_sem);
|
||||||
|
up_write(&root->fs_info->cleanup_work_sem);
|
||||||
|
|
||||||
trans = btrfs_start_transaction(root, 1);
|
trans = btrfs_start_transaction(root, 1);
|
||||||
ret = btrfs_commit_transaction(trans, root);
|
ret = btrfs_commit_transaction(trans, root);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
|
@ -195,6 +195,14 @@ static int exclude_super_stripes(struct btrfs_root *root,
|
||||||
int stripe_len;
|
int stripe_len;
|
||||||
int i, nr, ret;
|
int i, nr, ret;
|
||||||
|
|
||||||
|
if (cache->key.objectid < BTRFS_SUPER_INFO_OFFSET) {
|
||||||
|
stripe_len = BTRFS_SUPER_INFO_OFFSET - cache->key.objectid;
|
||||||
|
cache->bytes_super += stripe_len;
|
||||||
|
ret = add_excluded_extent(root, cache->key.objectid,
|
||||||
|
stripe_len);
|
||||||
|
BUG_ON(ret);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
|
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
|
||||||
bytenr = btrfs_sb_offset(i);
|
bytenr = btrfs_sb_offset(i);
|
||||||
ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
|
ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
|
||||||
|
@ -255,7 +263,7 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (extent_start == start) {
|
if (extent_start <= start) {
|
||||||
start = extent_end + 1;
|
start = extent_end + 1;
|
||||||
} else if (extent_start > start && extent_start < end) {
|
} else if (extent_start > start && extent_start < end) {
|
||||||
size = extent_start - start;
|
size = extent_start - start;
|
||||||
|
@ -2880,9 +2888,9 @@ static noinline void flush_delalloc_async(struct btrfs_work *work)
|
||||||
root = async->root;
|
root = async->root;
|
||||||
info = async->info;
|
info = async->info;
|
||||||
|
|
||||||
btrfs_start_delalloc_inodes(root);
|
btrfs_start_delalloc_inodes(root, 0);
|
||||||
wake_up(&info->flush_wait);
|
wake_up(&info->flush_wait);
|
||||||
btrfs_wait_ordered_extents(root, 0);
|
btrfs_wait_ordered_extents(root, 0, 0);
|
||||||
|
|
||||||
spin_lock(&info->lock);
|
spin_lock(&info->lock);
|
||||||
info->flushing = 0;
|
info->flushing = 0;
|
||||||
|
@ -2956,8 +2964,8 @@ static void flush_delalloc(struct btrfs_root *root,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
flush:
|
flush:
|
||||||
btrfs_start_delalloc_inodes(root);
|
btrfs_start_delalloc_inodes(root, 0);
|
||||||
btrfs_wait_ordered_extents(root, 0);
|
btrfs_wait_ordered_extents(root, 0, 0);
|
||||||
|
|
||||||
spin_lock(&info->lock);
|
spin_lock(&info->lock);
|
||||||
info->flushing = 0;
|
info->flushing = 0;
|
||||||
|
@ -3454,14 +3462,6 @@ static int update_block_group(struct btrfs_trans_handle *trans,
|
||||||
else
|
else
|
||||||
old_val -= num_bytes;
|
old_val -= num_bytes;
|
||||||
btrfs_set_super_bytes_used(&info->super_copy, old_val);
|
btrfs_set_super_bytes_used(&info->super_copy, old_val);
|
||||||
|
|
||||||
/* block accounting for root item */
|
|
||||||
old_val = btrfs_root_used(&root->root_item);
|
|
||||||
if (alloc)
|
|
||||||
old_val += num_bytes;
|
|
||||||
else
|
|
||||||
old_val -= num_bytes;
|
|
||||||
btrfs_set_root_used(&root->root_item, old_val);
|
|
||||||
spin_unlock(&info->delalloc_lock);
|
spin_unlock(&info->delalloc_lock);
|
||||||
|
|
||||||
while (total) {
|
while (total) {
|
||||||
|
@ -4049,6 +4049,21 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root,
|
||||||
|
u64 bytenr, u32 blocksize,
|
||||||
|
u64 parent, u64 root_objectid, int level)
|
||||||
|
{
|
||||||
|
u64 used;
|
||||||
|
spin_lock(&root->node_lock);
|
||||||
|
used = btrfs_root_used(&root->root_item) - blocksize;
|
||||||
|
btrfs_set_root_used(&root->root_item, used);
|
||||||
|
spin_unlock(&root->node_lock);
|
||||||
|
|
||||||
|
return btrfs_free_extent(trans, root, bytenr, blocksize,
|
||||||
|
parent, root_objectid, level, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static u64 stripe_align(struct btrfs_root *root, u64 val)
|
static u64 stripe_align(struct btrfs_root *root, u64 val)
|
||||||
{
|
{
|
||||||
u64 mask = ((u64)root->stripesize - 1);
|
u64 mask = ((u64)root->stripesize - 1);
|
||||||
|
@ -4578,7 +4593,6 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
u64 search_start = 0;
|
u64 search_start = 0;
|
||||||
struct btrfs_fs_info *info = root->fs_info;
|
|
||||||
|
|
||||||
data = btrfs_get_alloc_profile(root, data);
|
data = btrfs_get_alloc_profile(root, data);
|
||||||
again:
|
again:
|
||||||
|
@ -4586,17 +4600,9 @@ again:
|
||||||
* the only place that sets empty_size is btrfs_realloc_node, which
|
* the only place that sets empty_size is btrfs_realloc_node, which
|
||||||
* is not called recursively on allocations
|
* is not called recursively on allocations
|
||||||
*/
|
*/
|
||||||
if (empty_size || root->ref_cows) {
|
if (empty_size || root->ref_cows)
|
||||||
if (!(data & BTRFS_BLOCK_GROUP_METADATA)) {
|
|
||||||
ret = do_chunk_alloc(trans, root->fs_info->extent_root,
|
|
||||||
2 * 1024 * 1024,
|
|
||||||
BTRFS_BLOCK_GROUP_METADATA |
|
|
||||||
(info->metadata_alloc_profile &
|
|
||||||
info->avail_metadata_alloc_bits), 0);
|
|
||||||
}
|
|
||||||
ret = do_chunk_alloc(trans, root->fs_info->extent_root,
|
ret = do_chunk_alloc(trans, root->fs_info->extent_root,
|
||||||
num_bytes + 2 * 1024 * 1024, data, 0);
|
num_bytes + 2 * 1024 * 1024, data, 0);
|
||||||
}
|
|
||||||
|
|
||||||
WARN_ON(num_bytes < root->sectorsize);
|
WARN_ON(num_bytes < root->sectorsize);
|
||||||
ret = find_free_extent(trans, root, num_bytes, empty_size,
|
ret = find_free_extent(trans, root, num_bytes, empty_size,
|
||||||
|
@ -4897,6 +4903,14 @@ static int alloc_tree_block(struct btrfs_trans_handle *trans,
|
||||||
extent_op);
|
extent_op);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (root_objectid == root->root_key.objectid) {
|
||||||
|
u64 used;
|
||||||
|
spin_lock(&root->node_lock);
|
||||||
|
used = btrfs_root_used(&root->root_item) + num_bytes;
|
||||||
|
btrfs_set_root_used(&root->root_item, used);
|
||||||
|
spin_unlock(&root->node_lock);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4919,8 +4933,16 @@ struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
|
||||||
btrfs_set_buffer_uptodate(buf);
|
btrfs_set_buffer_uptodate(buf);
|
||||||
|
|
||||||
if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) {
|
if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) {
|
||||||
set_extent_dirty(&root->dirty_log_pages, buf->start,
|
/*
|
||||||
buf->start + buf->len - 1, GFP_NOFS);
|
* we allow two log transactions at a time, use different
|
||||||
|
* EXENT bit to differentiate dirty pages.
|
||||||
|
*/
|
||||||
|
if (root->log_transid % 2 == 0)
|
||||||
|
set_extent_dirty(&root->dirty_log_pages, buf->start,
|
||||||
|
buf->start + buf->len - 1, GFP_NOFS);
|
||||||
|
else
|
||||||
|
set_extent_new(&root->dirty_log_pages, buf->start,
|
||||||
|
buf->start + buf->len - 1, GFP_NOFS);
|
||||||
} else {
|
} else {
|
||||||
set_extent_dirty(&trans->transaction->dirty_pages, buf->start,
|
set_extent_dirty(&trans->transaction->dirty_pages, buf->start,
|
||||||
buf->start + buf->len - 1, GFP_NOFS);
|
buf->start + buf->len - 1, GFP_NOFS);
|
||||||
|
|
691
fs/btrfs/file.c
691
fs/btrfs/file.c
|
@ -179,18 +179,14 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
|
||||||
}
|
}
|
||||||
flags = em->flags;
|
flags = em->flags;
|
||||||
if (skip_pinned && test_bit(EXTENT_FLAG_PINNED, &em->flags)) {
|
if (skip_pinned && test_bit(EXTENT_FLAG_PINNED, &em->flags)) {
|
||||||
if (em->start <= start &&
|
if (testend && em->start + em->len >= start + len) {
|
||||||
(!testend || em->start + em->len >= start + len)) {
|
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
write_unlock(&em_tree->lock);
|
write_unlock(&em_tree->lock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (start < em->start) {
|
start = em->start + em->len;
|
||||||
len = em->start - start;
|
if (testend)
|
||||||
} else {
|
|
||||||
len = start + len - (em->start + em->len);
|
len = start + len - (em->start + em->len);
|
||||||
start = em->start + em->len;
|
|
||||||
}
|
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
write_unlock(&em_tree->lock);
|
write_unlock(&em_tree->lock);
|
||||||
continue;
|
continue;
|
||||||
|
@ -265,319 +261,247 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
|
||||||
* If an extent intersects the range but is not entirely inside the range
|
* If an extent intersects the range but is not entirely inside the range
|
||||||
* it is either truncated or split. Anything entirely inside the range
|
* it is either truncated or split. Anything entirely inside the range
|
||||||
* is deleted from the tree.
|
* is deleted from the tree.
|
||||||
*
|
|
||||||
* inline_limit is used to tell this code which offsets in the file to keep
|
|
||||||
* if they contain inline extents.
|
|
||||||
*/
|
*/
|
||||||
noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans,
|
int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
|
||||||
struct btrfs_root *root, struct inode *inode,
|
u64 start, u64 end, u64 *hint_byte, int drop_cache)
|
||||||
u64 start, u64 end, u64 locked_end,
|
|
||||||
u64 inline_limit, u64 *hint_byte, int drop_cache)
|
|
||||||
{
|
{
|
||||||
u64 extent_end = 0;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
u64 search_start = start;
|
|
||||||
u64 ram_bytes = 0;
|
|
||||||
u64 disk_bytenr = 0;
|
|
||||||
u64 orig_locked_end = locked_end;
|
|
||||||
u8 compression;
|
|
||||||
u8 encryption;
|
|
||||||
u16 other_encoding = 0;
|
|
||||||
struct extent_buffer *leaf;
|
struct extent_buffer *leaf;
|
||||||
struct btrfs_file_extent_item *extent;
|
struct btrfs_file_extent_item *fi;
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
struct btrfs_file_extent_item old;
|
struct btrfs_key new_key;
|
||||||
int keep;
|
u64 search_start = start;
|
||||||
int slot;
|
u64 disk_bytenr = 0;
|
||||||
int bookend;
|
u64 num_bytes = 0;
|
||||||
int found_type = 0;
|
u64 extent_offset = 0;
|
||||||
int found_extent;
|
u64 extent_end = 0;
|
||||||
int found_inline;
|
int del_nr = 0;
|
||||||
|
int del_slot = 0;
|
||||||
|
int extent_type;
|
||||||
int recow;
|
int recow;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
inline_limit = 0;
|
|
||||||
if (drop_cache)
|
if (drop_cache)
|
||||||
btrfs_drop_extent_cache(inode, start, end - 1, 0);
|
btrfs_drop_extent_cache(inode, start, end - 1, 0);
|
||||||
|
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
if (!path)
|
if (!path)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
recow = 0;
|
recow = 0;
|
||||||
btrfs_release_path(root, path);
|
|
||||||
ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
|
ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
|
||||||
search_start, -1);
|
search_start, -1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
break;
|
||||||
if (ret > 0) {
|
if (ret > 0 && path->slots[0] > 0 && search_start == start) {
|
||||||
if (path->slots[0] == 0) {
|
leaf = path->nodes[0];
|
||||||
ret = 0;
|
btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1);
|
||||||
goto out;
|
if (key.objectid == inode->i_ino &&
|
||||||
}
|
key.type == BTRFS_EXTENT_DATA_KEY)
|
||||||
path->slots[0]--;
|
path->slots[0]--;
|
||||||
}
|
}
|
||||||
next_slot:
|
|
||||||
keep = 0;
|
|
||||||
bookend = 0;
|
|
||||||
found_extent = 0;
|
|
||||||
found_inline = 0;
|
|
||||||
compression = 0;
|
|
||||||
encryption = 0;
|
|
||||||
extent = NULL;
|
|
||||||
leaf = path->nodes[0];
|
|
||||||
slot = path->slots[0];
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
btrfs_item_key_to_cpu(leaf, &key, slot);
|
next_slot:
|
||||||
if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY &&
|
leaf = path->nodes[0];
|
||||||
key.offset >= end) {
|
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
|
||||||
goto out;
|
BUG_ON(del_nr > 0);
|
||||||
}
|
ret = btrfs_next_leaf(root, path);
|
||||||
if (btrfs_key_type(&key) > BTRFS_EXTENT_DATA_KEY ||
|
if (ret < 0)
|
||||||
key.objectid != inode->i_ino) {
|
break;
|
||||||
goto out;
|
if (ret > 0) {
|
||||||
}
|
ret = 0;
|
||||||
if (recow) {
|
break;
|
||||||
search_start = max(key.offset, start);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) {
|
|
||||||
extent = btrfs_item_ptr(leaf, slot,
|
|
||||||
struct btrfs_file_extent_item);
|
|
||||||
found_type = btrfs_file_extent_type(leaf, extent);
|
|
||||||
compression = btrfs_file_extent_compression(leaf,
|
|
||||||
extent);
|
|
||||||
encryption = btrfs_file_extent_encryption(leaf,
|
|
||||||
extent);
|
|
||||||
other_encoding = btrfs_file_extent_other_encoding(leaf,
|
|
||||||
extent);
|
|
||||||
if (found_type == BTRFS_FILE_EXTENT_REG ||
|
|
||||||
found_type == BTRFS_FILE_EXTENT_PREALLOC) {
|
|
||||||
extent_end =
|
|
||||||
btrfs_file_extent_disk_bytenr(leaf,
|
|
||||||
extent);
|
|
||||||
if (extent_end)
|
|
||||||
*hint_byte = extent_end;
|
|
||||||
|
|
||||||
extent_end = key.offset +
|
|
||||||
btrfs_file_extent_num_bytes(leaf, extent);
|
|
||||||
ram_bytes = btrfs_file_extent_ram_bytes(leaf,
|
|
||||||
extent);
|
|
||||||
found_extent = 1;
|
|
||||||
} else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
|
|
||||||
found_inline = 1;
|
|
||||||
extent_end = key.offset +
|
|
||||||
btrfs_file_extent_inline_len(leaf, extent);
|
|
||||||
}
|
}
|
||||||
|
leaf = path->nodes[0];
|
||||||
|
recow = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
|
||||||
|
if (key.objectid > inode->i_ino ||
|
||||||
|
key.type > BTRFS_EXTENT_DATA_KEY || key.offset >= end)
|
||||||
|
break;
|
||||||
|
|
||||||
|
fi = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
|
struct btrfs_file_extent_item);
|
||||||
|
extent_type = btrfs_file_extent_type(leaf, fi);
|
||||||
|
|
||||||
|
if (extent_type == BTRFS_FILE_EXTENT_REG ||
|
||||||
|
extent_type == BTRFS_FILE_EXTENT_PREALLOC) {
|
||||||
|
disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
|
||||||
|
num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi);
|
||||||
|
extent_offset = btrfs_file_extent_offset(leaf, fi);
|
||||||
|
extent_end = key.offset +
|
||||||
|
btrfs_file_extent_num_bytes(leaf, fi);
|
||||||
|
} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
|
||||||
|
extent_end = key.offset +
|
||||||
|
btrfs_file_extent_inline_len(leaf, fi);
|
||||||
} else {
|
} else {
|
||||||
|
WARN_ON(1);
|
||||||
extent_end = search_start;
|
extent_end = search_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we found nothing we can drop */
|
if (extent_end <= search_start) {
|
||||||
if ((!found_extent && !found_inline) ||
|
path->slots[0]++;
|
||||||
search_start >= extent_end) {
|
|
||||||
int nextret;
|
|
||||||
u32 nritems;
|
|
||||||
nritems = btrfs_header_nritems(leaf);
|
|
||||||
if (slot >= nritems - 1) {
|
|
||||||
nextret = btrfs_next_leaf(root, path);
|
|
||||||
if (nextret)
|
|
||||||
goto out;
|
|
||||||
recow = 1;
|
|
||||||
} else {
|
|
||||||
path->slots[0]++;
|
|
||||||
}
|
|
||||||
goto next_slot;
|
goto next_slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end <= extent_end && start >= key.offset && found_inline)
|
search_start = max(key.offset, start);
|
||||||
*hint_byte = EXTENT_MAP_INLINE;
|
if (recow) {
|
||||||
|
|
||||||
if (found_extent) {
|
|
||||||
read_extent_buffer(leaf, &old, (unsigned long)extent,
|
|
||||||
sizeof(old));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (end < extent_end && end >= key.offset) {
|
|
||||||
bookend = 1;
|
|
||||||
if (found_inline && start <= key.offset)
|
|
||||||
keep = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bookend && found_extent) {
|
|
||||||
if (locked_end < extent_end) {
|
|
||||||
ret = try_lock_extent(&BTRFS_I(inode)->io_tree,
|
|
||||||
locked_end, extent_end - 1,
|
|
||||||
GFP_NOFS);
|
|
||||||
if (!ret) {
|
|
||||||
btrfs_release_path(root, path);
|
|
||||||
lock_extent(&BTRFS_I(inode)->io_tree,
|
|
||||||
locked_end, extent_end - 1,
|
|
||||||
GFP_NOFS);
|
|
||||||
locked_end = extent_end;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
locked_end = extent_end;
|
|
||||||
}
|
|
||||||
disk_bytenr = le64_to_cpu(old.disk_bytenr);
|
|
||||||
if (disk_bytenr != 0) {
|
|
||||||
ret = btrfs_inc_extent_ref(trans, root,
|
|
||||||
disk_bytenr,
|
|
||||||
le64_to_cpu(old.disk_num_bytes), 0,
|
|
||||||
root->root_key.objectid,
|
|
||||||
key.objectid, key.offset -
|
|
||||||
le64_to_cpu(old.offset));
|
|
||||||
BUG_ON(ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found_inline) {
|
|
||||||
u64 mask = root->sectorsize - 1;
|
|
||||||
search_start = (extent_end + mask) & ~mask;
|
|
||||||
} else
|
|
||||||
search_start = extent_end;
|
|
||||||
|
|
||||||
/* truncate existing extent */
|
|
||||||
if (start > key.offset) {
|
|
||||||
u64 new_num;
|
|
||||||
u64 old_num;
|
|
||||||
keep = 1;
|
|
||||||
WARN_ON(start & (root->sectorsize - 1));
|
|
||||||
if (found_extent) {
|
|
||||||
new_num = start - key.offset;
|
|
||||||
old_num = btrfs_file_extent_num_bytes(leaf,
|
|
||||||
extent);
|
|
||||||
*hint_byte =
|
|
||||||
btrfs_file_extent_disk_bytenr(leaf,
|
|
||||||
extent);
|
|
||||||
if (btrfs_file_extent_disk_bytenr(leaf,
|
|
||||||
extent)) {
|
|
||||||
inode_sub_bytes(inode, old_num -
|
|
||||||
new_num);
|
|
||||||
}
|
|
||||||
btrfs_set_file_extent_num_bytes(leaf,
|
|
||||||
extent, new_num);
|
|
||||||
btrfs_mark_buffer_dirty(leaf);
|
|
||||||
} else if (key.offset < inline_limit &&
|
|
||||||
(end > extent_end) &&
|
|
||||||
(inline_limit < extent_end)) {
|
|
||||||
u32 new_size;
|
|
||||||
new_size = btrfs_file_extent_calc_inline_size(
|
|
||||||
inline_limit - key.offset);
|
|
||||||
inode_sub_bytes(inode, extent_end -
|
|
||||||
inline_limit);
|
|
||||||
btrfs_set_file_extent_ram_bytes(leaf, extent,
|
|
||||||
new_size);
|
|
||||||
if (!compression && !encryption) {
|
|
||||||
btrfs_truncate_item(trans, root, path,
|
|
||||||
new_size, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* delete the entire extent */
|
|
||||||
if (!keep) {
|
|
||||||
if (found_inline)
|
|
||||||
inode_sub_bytes(inode, extent_end -
|
|
||||||
key.offset);
|
|
||||||
ret = btrfs_del_item(trans, root, path);
|
|
||||||
/* TODO update progress marker and return */
|
|
||||||
BUG_ON(ret);
|
|
||||||
extent = NULL;
|
|
||||||
btrfs_release_path(root, path);
|
btrfs_release_path(root, path);
|
||||||
/* the extent will be freed later */
|
continue;
|
||||||
}
|
}
|
||||||
if (bookend && found_inline && start <= key.offset) {
|
|
||||||
u32 new_size;
|
|
||||||
new_size = btrfs_file_extent_calc_inline_size(
|
|
||||||
extent_end - end);
|
|
||||||
inode_sub_bytes(inode, end - key.offset);
|
|
||||||
btrfs_set_file_extent_ram_bytes(leaf, extent,
|
|
||||||
new_size);
|
|
||||||
if (!compression && !encryption)
|
|
||||||
ret = btrfs_truncate_item(trans, root, path,
|
|
||||||
new_size, 0);
|
|
||||||
BUG_ON(ret);
|
|
||||||
}
|
|
||||||
/* create bookend, splitting the extent in two */
|
|
||||||
if (bookend && found_extent) {
|
|
||||||
struct btrfs_key ins;
|
|
||||||
ins.objectid = inode->i_ino;
|
|
||||||
ins.offset = end;
|
|
||||||
btrfs_set_key_type(&ins, BTRFS_EXTENT_DATA_KEY);
|
|
||||||
|
|
||||||
btrfs_release_path(root, path);
|
/*
|
||||||
path->leave_spinning = 1;
|
* | - range to drop - |
|
||||||
ret = btrfs_insert_empty_item(trans, root, path, &ins,
|
* | -------- extent -------- |
|
||||||
sizeof(*extent));
|
*/
|
||||||
BUG_ON(ret);
|
if (start > key.offset && end < extent_end) {
|
||||||
|
BUG_ON(del_nr > 0);
|
||||||
|
BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE);
|
||||||
|
|
||||||
|
memcpy(&new_key, &key, sizeof(new_key));
|
||||||
|
new_key.offset = start;
|
||||||
|
ret = btrfs_duplicate_item(trans, root, path,
|
||||||
|
&new_key);
|
||||||
|
if (ret == -EAGAIN) {
|
||||||
|
btrfs_release_path(root, path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ret < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
extent = btrfs_item_ptr(leaf, path->slots[0],
|
fi = btrfs_item_ptr(leaf, path->slots[0] - 1,
|
||||||
struct btrfs_file_extent_item);
|
struct btrfs_file_extent_item);
|
||||||
write_extent_buffer(leaf, &old,
|
btrfs_set_file_extent_num_bytes(leaf, fi,
|
||||||
(unsigned long)extent, sizeof(old));
|
start - key.offset);
|
||||||
|
|
||||||
btrfs_set_file_extent_compression(leaf, extent,
|
fi = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
compression);
|
struct btrfs_file_extent_item);
|
||||||
btrfs_set_file_extent_encryption(leaf, extent,
|
|
||||||
encryption);
|
|
||||||
btrfs_set_file_extent_other_encoding(leaf, extent,
|
|
||||||
other_encoding);
|
|
||||||
btrfs_set_file_extent_offset(leaf, extent,
|
|
||||||
le64_to_cpu(old.offset) + end - key.offset);
|
|
||||||
WARN_ON(le64_to_cpu(old.num_bytes) <
|
|
||||||
(extent_end - end));
|
|
||||||
btrfs_set_file_extent_num_bytes(leaf, extent,
|
|
||||||
extent_end - end);
|
|
||||||
|
|
||||||
/*
|
extent_offset += start - key.offset;
|
||||||
* set the ram bytes to the size of the full extent
|
btrfs_set_file_extent_offset(leaf, fi, extent_offset);
|
||||||
* before splitting. This is a worst case flag,
|
btrfs_set_file_extent_num_bytes(leaf, fi,
|
||||||
* but its the best we can do because we don't know
|
extent_end - start);
|
||||||
* how splitting affects compression
|
btrfs_mark_buffer_dirty(leaf);
|
||||||
*/
|
|
||||||
btrfs_set_file_extent_ram_bytes(leaf, extent,
|
|
||||||
ram_bytes);
|
|
||||||
btrfs_set_file_extent_type(leaf, extent, found_type);
|
|
||||||
|
|
||||||
btrfs_unlock_up_safe(path, 1);
|
if (disk_bytenr > 0) {
|
||||||
btrfs_mark_buffer_dirty(path->nodes[0]);
|
ret = btrfs_inc_extent_ref(trans, root,
|
||||||
btrfs_set_lock_blocking(path->nodes[0]);
|
disk_bytenr, num_bytes, 0,
|
||||||
|
root->root_key.objectid,
|
||||||
path->leave_spinning = 0;
|
new_key.objectid,
|
||||||
btrfs_release_path(root, path);
|
start - extent_offset);
|
||||||
if (disk_bytenr != 0)
|
|
||||||
inode_add_bytes(inode, extent_end - end);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found_extent && !keep) {
|
|
||||||
u64 old_disk_bytenr = le64_to_cpu(old.disk_bytenr);
|
|
||||||
|
|
||||||
if (old_disk_bytenr != 0) {
|
|
||||||
inode_sub_bytes(inode,
|
|
||||||
le64_to_cpu(old.num_bytes));
|
|
||||||
ret = btrfs_free_extent(trans, root,
|
|
||||||
old_disk_bytenr,
|
|
||||||
le64_to_cpu(old.disk_num_bytes),
|
|
||||||
0, root->root_key.objectid,
|
|
||||||
key.objectid, key.offset -
|
|
||||||
le64_to_cpu(old.offset));
|
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
*hint_byte = old_disk_bytenr;
|
*hint_byte = disk_bytenr;
|
||||||
}
|
}
|
||||||
|
key.offset = start;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* | ---- range to drop ----- |
|
||||||
|
* | -------- extent -------- |
|
||||||
|
*/
|
||||||
|
if (start <= key.offset && end < extent_end) {
|
||||||
|
BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE);
|
||||||
|
|
||||||
|
memcpy(&new_key, &key, sizeof(new_key));
|
||||||
|
new_key.offset = end;
|
||||||
|
btrfs_set_item_key_safe(trans, root, path, &new_key);
|
||||||
|
|
||||||
|
extent_offset += end - key.offset;
|
||||||
|
btrfs_set_file_extent_offset(leaf, fi, extent_offset);
|
||||||
|
btrfs_set_file_extent_num_bytes(leaf, fi,
|
||||||
|
extent_end - end);
|
||||||
|
btrfs_mark_buffer_dirty(leaf);
|
||||||
|
if (disk_bytenr > 0) {
|
||||||
|
inode_sub_bytes(inode, end - key.offset);
|
||||||
|
*hint_byte = disk_bytenr;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (search_start >= end) {
|
search_start = extent_end;
|
||||||
ret = 0;
|
/*
|
||||||
goto out;
|
* | ---- range to drop ----- |
|
||||||
|
* | -------- extent -------- |
|
||||||
|
*/
|
||||||
|
if (start > key.offset && end >= extent_end) {
|
||||||
|
BUG_ON(del_nr > 0);
|
||||||
|
BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE);
|
||||||
|
|
||||||
|
btrfs_set_file_extent_num_bytes(leaf, fi,
|
||||||
|
start - key.offset);
|
||||||
|
btrfs_mark_buffer_dirty(leaf);
|
||||||
|
if (disk_bytenr > 0) {
|
||||||
|
inode_sub_bytes(inode, extent_end - start);
|
||||||
|
*hint_byte = disk_bytenr;
|
||||||
|
}
|
||||||
|
if (end == extent_end)
|
||||||
|
break;
|
||||||
|
|
||||||
|
path->slots[0]++;
|
||||||
|
goto next_slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* | ---- range to drop ----- |
|
||||||
|
* | ------ extent ------ |
|
||||||
|
*/
|
||||||
|
if (start <= key.offset && end >= extent_end) {
|
||||||
|
if (del_nr == 0) {
|
||||||
|
del_slot = path->slots[0];
|
||||||
|
del_nr = 1;
|
||||||
|
} else {
|
||||||
|
BUG_ON(del_slot + del_nr != path->slots[0]);
|
||||||
|
del_nr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
|
||||||
|
inode_sub_bytes(inode,
|
||||||
|
extent_end - key.offset);
|
||||||
|
extent_end = ALIGN(extent_end,
|
||||||
|
root->sectorsize);
|
||||||
|
} else if (disk_bytenr > 0) {
|
||||||
|
ret = btrfs_free_extent(trans, root,
|
||||||
|
disk_bytenr, num_bytes, 0,
|
||||||
|
root->root_key.objectid,
|
||||||
|
key.objectid, key.offset -
|
||||||
|
extent_offset);
|
||||||
|
BUG_ON(ret);
|
||||||
|
inode_sub_bytes(inode,
|
||||||
|
extent_end - key.offset);
|
||||||
|
*hint_byte = disk_bytenr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end == extent_end)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (path->slots[0] + 1 < btrfs_header_nritems(leaf)) {
|
||||||
|
path->slots[0]++;
|
||||||
|
goto next_slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = btrfs_del_items(trans, root, path, del_slot,
|
||||||
|
del_nr);
|
||||||
|
BUG_ON(ret);
|
||||||
|
|
||||||
|
del_nr = 0;
|
||||||
|
del_slot = 0;
|
||||||
|
|
||||||
|
btrfs_release_path(root, path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BUG_ON(1);
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
|
if (del_nr > 0) {
|
||||||
|
ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
|
||||||
|
BUG_ON(ret);
|
||||||
|
}
|
||||||
|
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
if (locked_end > orig_locked_end) {
|
|
||||||
unlock_extent(&BTRFS_I(inode)->io_tree, orig_locked_end,
|
|
||||||
locked_end - 1, GFP_NOFS);
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -620,23 +544,23 @@ static int extent_mergeable(struct extent_buffer *leaf, int slot,
|
||||||
* two or three.
|
* two or three.
|
||||||
*/
|
*/
|
||||||
int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
|
int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
|
||||||
struct inode *inode, u64 start, u64 end)
|
struct inode *inode, u64 start, u64 end)
|
||||||
{
|
{
|
||||||
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
struct extent_buffer *leaf;
|
struct extent_buffer *leaf;
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
struct btrfs_file_extent_item *fi;
|
struct btrfs_file_extent_item *fi;
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
|
struct btrfs_key new_key;
|
||||||
u64 bytenr;
|
u64 bytenr;
|
||||||
u64 num_bytes;
|
u64 num_bytes;
|
||||||
u64 extent_end;
|
u64 extent_end;
|
||||||
u64 orig_offset;
|
u64 orig_offset;
|
||||||
u64 other_start;
|
u64 other_start;
|
||||||
u64 other_end;
|
u64 other_end;
|
||||||
u64 split = start;
|
u64 split;
|
||||||
u64 locked_end = end;
|
int del_nr = 0;
|
||||||
int extent_type;
|
int del_slot = 0;
|
||||||
int split_end = 1;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
btrfs_drop_extent_cache(inode, start, end - 1, 0);
|
btrfs_drop_extent_cache(inode, start, end - 1, 0);
|
||||||
|
@ -644,12 +568,10 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
BUG_ON(!path);
|
BUG_ON(!path);
|
||||||
again:
|
again:
|
||||||
|
split = start;
|
||||||
key.objectid = inode->i_ino;
|
key.objectid = inode->i_ino;
|
||||||
key.type = BTRFS_EXTENT_DATA_KEY;
|
key.type = BTRFS_EXTENT_DATA_KEY;
|
||||||
if (split == start)
|
key.offset = split;
|
||||||
key.offset = split;
|
|
||||||
else
|
|
||||||
key.offset = split - 1;
|
|
||||||
|
|
||||||
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
||||||
if (ret > 0 && path->slots[0] > 0)
|
if (ret > 0 && path->slots[0] > 0)
|
||||||
|
@ -661,8 +583,8 @@ again:
|
||||||
key.type != BTRFS_EXTENT_DATA_KEY);
|
key.type != BTRFS_EXTENT_DATA_KEY);
|
||||||
fi = btrfs_item_ptr(leaf, path->slots[0],
|
fi = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
struct btrfs_file_extent_item);
|
struct btrfs_file_extent_item);
|
||||||
extent_type = btrfs_file_extent_type(leaf, fi);
|
BUG_ON(btrfs_file_extent_type(leaf, fi) !=
|
||||||
BUG_ON(extent_type != BTRFS_FILE_EXTENT_PREALLOC);
|
BTRFS_FILE_EXTENT_PREALLOC);
|
||||||
extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi);
|
extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi);
|
||||||
BUG_ON(key.offset > start || extent_end < end);
|
BUG_ON(key.offset > start || extent_end < end);
|
||||||
|
|
||||||
|
@ -670,150 +592,91 @@ again:
|
||||||
num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi);
|
num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi);
|
||||||
orig_offset = key.offset - btrfs_file_extent_offset(leaf, fi);
|
orig_offset = key.offset - btrfs_file_extent_offset(leaf, fi);
|
||||||
|
|
||||||
if (key.offset == start)
|
while (start > key.offset || end < extent_end) {
|
||||||
split = end;
|
if (key.offset == start)
|
||||||
|
split = end;
|
||||||
|
|
||||||
if (key.offset == start && extent_end == end) {
|
memcpy(&new_key, &key, sizeof(new_key));
|
||||||
int del_nr = 0;
|
new_key.offset = split;
|
||||||
int del_slot = 0;
|
ret = btrfs_duplicate_item(trans, root, path, &new_key);
|
||||||
other_start = end;
|
if (ret == -EAGAIN) {
|
||||||
other_end = 0;
|
btrfs_release_path(root, path);
|
||||||
if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino,
|
goto again;
|
||||||
bytenr, &other_start, &other_end)) {
|
|
||||||
extent_end = other_end;
|
|
||||||
del_slot = path->slots[0] + 1;
|
|
||||||
del_nr++;
|
|
||||||
ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
|
|
||||||
0, root->root_key.objectid,
|
|
||||||
inode->i_ino, orig_offset);
|
|
||||||
BUG_ON(ret);
|
|
||||||
}
|
|
||||||
other_start = 0;
|
|
||||||
other_end = start;
|
|
||||||
if (extent_mergeable(leaf, path->slots[0] - 1, inode->i_ino,
|
|
||||||
bytenr, &other_start, &other_end)) {
|
|
||||||
key.offset = other_start;
|
|
||||||
del_slot = path->slots[0];
|
|
||||||
del_nr++;
|
|
||||||
ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
|
|
||||||
0, root->root_key.objectid,
|
|
||||||
inode->i_ino, orig_offset);
|
|
||||||
BUG_ON(ret);
|
|
||||||
}
|
|
||||||
split_end = 0;
|
|
||||||
if (del_nr == 0) {
|
|
||||||
btrfs_set_file_extent_type(leaf, fi,
|
|
||||||
BTRFS_FILE_EXTENT_REG);
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
BUG_ON(ret < 0);
|
||||||
|
|
||||||
fi = btrfs_item_ptr(leaf, del_slot - 1,
|
leaf = path->nodes[0];
|
||||||
|
fi = btrfs_item_ptr(leaf, path->slots[0] - 1,
|
||||||
struct btrfs_file_extent_item);
|
struct btrfs_file_extent_item);
|
||||||
btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG);
|
|
||||||
btrfs_set_file_extent_num_bytes(leaf, fi,
|
btrfs_set_file_extent_num_bytes(leaf, fi,
|
||||||
extent_end - key.offset);
|
split - key.offset);
|
||||||
|
|
||||||
|
fi = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
|
struct btrfs_file_extent_item);
|
||||||
|
|
||||||
|
btrfs_set_file_extent_offset(leaf, fi, split - orig_offset);
|
||||||
|
btrfs_set_file_extent_num_bytes(leaf, fi,
|
||||||
|
extent_end - split);
|
||||||
btrfs_mark_buffer_dirty(leaf);
|
btrfs_mark_buffer_dirty(leaf);
|
||||||
|
|
||||||
ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
|
ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0,
|
||||||
|
root->root_key.objectid,
|
||||||
|
inode->i_ino, orig_offset);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
goto release;
|
|
||||||
} else if (split == start) {
|
|
||||||
if (locked_end < extent_end) {
|
|
||||||
ret = try_lock_extent(&BTRFS_I(inode)->io_tree,
|
|
||||||
locked_end, extent_end - 1, GFP_NOFS);
|
|
||||||
if (!ret) {
|
|
||||||
btrfs_release_path(root, path);
|
|
||||||
lock_extent(&BTRFS_I(inode)->io_tree,
|
|
||||||
locked_end, extent_end - 1, GFP_NOFS);
|
|
||||||
locked_end = extent_end;
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
locked_end = extent_end;
|
|
||||||
}
|
|
||||||
btrfs_set_file_extent_num_bytes(leaf, fi, split - key.offset);
|
|
||||||
} else {
|
|
||||||
BUG_ON(key.offset != start);
|
|
||||||
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);
|
|
||||||
extent_end = split;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extent_end == end) {
|
if (split == start) {
|
||||||
split_end = 0;
|
key.offset = start;
|
||||||
extent_type = BTRFS_FILE_EXTENT_REG;
|
} else {
|
||||||
}
|
BUG_ON(start != key.offset);
|
||||||
if (extent_end == end && split == start) {
|
|
||||||
other_start = end;
|
|
||||||
other_end = 0;
|
|
||||||
if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino,
|
|
||||||
bytenr, &other_start, &other_end)) {
|
|
||||||
path->slots[0]++;
|
|
||||||
fi = btrfs_item_ptr(leaf, path->slots[0],
|
|
||||||
struct btrfs_file_extent_item);
|
|
||||||
key.offset = split;
|
|
||||||
btrfs_set_item_key_safe(trans, root, path, &key);
|
|
||||||
btrfs_set_file_extent_offset(leaf, fi, key.offset -
|
|
||||||
orig_offset);
|
|
||||||
btrfs_set_file_extent_num_bytes(leaf, fi,
|
|
||||||
other_end - split);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (extent_end == end && split == end) {
|
|
||||||
other_start = 0;
|
|
||||||
other_end = start;
|
|
||||||
if (extent_mergeable(leaf, path->slots[0] - 1 , inode->i_ino,
|
|
||||||
bytenr, &other_start, &other_end)) {
|
|
||||||
path->slots[0]--;
|
path->slots[0]--;
|
||||||
fi = btrfs_item_ptr(leaf, path->slots[0],
|
extent_end = end;
|
||||||
struct btrfs_file_extent_item);
|
|
||||||
btrfs_set_file_extent_num_bytes(leaf, fi, extent_end -
|
|
||||||
other_start);
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_mark_buffer_dirty(leaf);
|
|
||||||
|
|
||||||
ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0,
|
|
||||||
root->root_key.objectid,
|
|
||||||
inode->i_ino, orig_offset);
|
|
||||||
BUG_ON(ret);
|
|
||||||
btrfs_release_path(root, path);
|
|
||||||
|
|
||||||
key.offset = start;
|
|
||||||
ret = btrfs_insert_empty_item(trans, root, path, &key, sizeof(*fi));
|
|
||||||
BUG_ON(ret);
|
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
|
||||||
fi = btrfs_item_ptr(leaf, path->slots[0],
|
fi = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
struct btrfs_file_extent_item);
|
struct btrfs_file_extent_item);
|
||||||
btrfs_set_file_extent_generation(leaf, fi, trans->transid);
|
|
||||||
btrfs_set_file_extent_type(leaf, fi, extent_type);
|
other_start = end;
|
||||||
btrfs_set_file_extent_disk_bytenr(leaf, fi, bytenr);
|
other_end = 0;
|
||||||
btrfs_set_file_extent_disk_num_bytes(leaf, fi, num_bytes);
|
if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino,
|
||||||
btrfs_set_file_extent_offset(leaf, fi, key.offset - orig_offset);
|
bytenr, &other_start, &other_end)) {
|
||||||
btrfs_set_file_extent_num_bytes(leaf, fi, extent_end - key.offset);
|
extent_end = other_end;
|
||||||
btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes);
|
del_slot = path->slots[0] + 1;
|
||||||
btrfs_set_file_extent_compression(leaf, fi, 0);
|
del_nr++;
|
||||||
btrfs_set_file_extent_encryption(leaf, fi, 0);
|
ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
|
||||||
btrfs_set_file_extent_other_encoding(leaf, fi, 0);
|
0, root->root_key.objectid,
|
||||||
done:
|
inode->i_ino, orig_offset);
|
||||||
|
BUG_ON(ret);
|
||||||
|
}
|
||||||
|
other_start = 0;
|
||||||
|
other_end = start;
|
||||||
|
if (extent_mergeable(leaf, path->slots[0] - 1, inode->i_ino,
|
||||||
|
bytenr, &other_start, &other_end)) {
|
||||||
|
key.offset = other_start;
|
||||||
|
del_slot = path->slots[0];
|
||||||
|
del_nr++;
|
||||||
|
ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
|
||||||
|
0, root->root_key.objectid,
|
||||||
|
inode->i_ino, orig_offset);
|
||||||
|
BUG_ON(ret);
|
||||||
|
}
|
||||||
|
if (del_nr == 0) {
|
||||||
|
btrfs_set_file_extent_type(leaf, fi,
|
||||||
|
BTRFS_FILE_EXTENT_REG);
|
||||||
|
btrfs_mark_buffer_dirty(leaf);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fi = btrfs_item_ptr(leaf, del_slot - 1,
|
||||||
|
struct btrfs_file_extent_item);
|
||||||
|
btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG);
|
||||||
|
btrfs_set_file_extent_num_bytes(leaf, fi,
|
||||||
|
extent_end - key.offset);
|
||||||
btrfs_mark_buffer_dirty(leaf);
|
btrfs_mark_buffer_dirty(leaf);
|
||||||
|
|
||||||
release:
|
ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
|
||||||
btrfs_release_path(root, path);
|
BUG_ON(ret);
|
||||||
if (split_end && split == start) {
|
out:
|
||||||
split = end;
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
if (locked_end > end) {
|
|
||||||
unlock_extent(&BTRFS_I(inode)->io_tree, end, locked_end - 1,
|
|
||||||
GFP_NOFS);
|
|
||||||
}
|
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
573
fs/btrfs/inode.c
573
fs/btrfs/inode.c
File diff suppressed because it is too large
Load diff
|
@ -237,7 +237,6 @@ static noinline int create_subvol(struct btrfs_root *root,
|
||||||
u64 objectid;
|
u64 objectid;
|
||||||
u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
|
u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
|
||||||
u64 index = 0;
|
u64 index = 0;
|
||||||
unsigned long nr = 1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 1 - inode item
|
* 1 - inode item
|
||||||
|
@ -290,7 +289,7 @@ static noinline int create_subvol(struct btrfs_root *root,
|
||||||
btrfs_set_root_generation(&root_item, trans->transid);
|
btrfs_set_root_generation(&root_item, trans->transid);
|
||||||
btrfs_set_root_level(&root_item, 0);
|
btrfs_set_root_level(&root_item, 0);
|
||||||
btrfs_set_root_refs(&root_item, 1);
|
btrfs_set_root_refs(&root_item, 1);
|
||||||
btrfs_set_root_used(&root_item, 0);
|
btrfs_set_root_used(&root_item, leaf->len);
|
||||||
btrfs_set_root_last_snapshot(&root_item, 0);
|
btrfs_set_root_last_snapshot(&root_item, 0);
|
||||||
|
|
||||||
memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress));
|
memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress));
|
||||||
|
@ -342,24 +341,21 @@ static noinline int create_subvol(struct btrfs_root *root,
|
||||||
|
|
||||||
d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
|
d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
|
||||||
fail:
|
fail:
|
||||||
nr = trans->blocks_used;
|
|
||||||
err = btrfs_commit_transaction(trans, root);
|
err = btrfs_commit_transaction(trans, root);
|
||||||
if (err && !ret)
|
if (err && !ret)
|
||||||
ret = err;
|
ret = err;
|
||||||
|
|
||||||
btrfs_unreserve_metadata_space(root, 6);
|
btrfs_unreserve_metadata_space(root, 6);
|
||||||
btrfs_btree_balance_dirty(root, nr);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
|
static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
|
||||||
char *name, int namelen)
|
char *name, int namelen)
|
||||||
{
|
{
|
||||||
|
struct inode *inode;
|
||||||
struct btrfs_pending_snapshot *pending_snapshot;
|
struct btrfs_pending_snapshot *pending_snapshot;
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
int ret = 0;
|
int ret;
|
||||||
int err;
|
|
||||||
unsigned long nr = 0;
|
|
||||||
|
|
||||||
if (!root->ref_cows)
|
if (!root->ref_cows)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -372,20 +368,20 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
|
||||||
*/
|
*/
|
||||||
ret = btrfs_reserve_metadata_space(root, 6);
|
ret = btrfs_reserve_metadata_space(root, 6);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fail_unlock;
|
goto fail;
|
||||||
|
|
||||||
pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS);
|
pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS);
|
||||||
if (!pending_snapshot) {
|
if (!pending_snapshot) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
btrfs_unreserve_metadata_space(root, 6);
|
btrfs_unreserve_metadata_space(root, 6);
|
||||||
goto fail_unlock;
|
goto fail;
|
||||||
}
|
}
|
||||||
pending_snapshot->name = kmalloc(namelen + 1, GFP_NOFS);
|
pending_snapshot->name = kmalloc(namelen + 1, GFP_NOFS);
|
||||||
if (!pending_snapshot->name) {
|
if (!pending_snapshot->name) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
kfree(pending_snapshot);
|
kfree(pending_snapshot);
|
||||||
btrfs_unreserve_metadata_space(root, 6);
|
btrfs_unreserve_metadata_space(root, 6);
|
||||||
goto fail_unlock;
|
goto fail;
|
||||||
}
|
}
|
||||||
memcpy(pending_snapshot->name, name, namelen);
|
memcpy(pending_snapshot->name, name, namelen);
|
||||||
pending_snapshot->name[namelen] = '\0';
|
pending_snapshot->name[namelen] = '\0';
|
||||||
|
@ -395,10 +391,19 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
|
||||||
pending_snapshot->root = root;
|
pending_snapshot->root = root;
|
||||||
list_add(&pending_snapshot->list,
|
list_add(&pending_snapshot->list,
|
||||||
&trans->transaction->pending_snapshots);
|
&trans->transaction->pending_snapshots);
|
||||||
err = btrfs_commit_transaction(trans, root);
|
ret = btrfs_commit_transaction(trans, root);
|
||||||
|
BUG_ON(ret);
|
||||||
|
btrfs_unreserve_metadata_space(root, 6);
|
||||||
|
|
||||||
fail_unlock:
|
inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry);
|
||||||
btrfs_btree_balance_dirty(root, nr);
|
if (IS_ERR(inode)) {
|
||||||
|
ret = PTR_ERR(inode);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
BUG_ON(!inode);
|
||||||
|
d_instantiate(dentry, inode);
|
||||||
|
ret = 0;
|
||||||
|
fail:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1027,8 +1032,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
||||||
BUG_ON(!trans);
|
BUG_ON(!trans);
|
||||||
|
|
||||||
/* punch hole in destination first */
|
/* punch hole in destination first */
|
||||||
btrfs_drop_extents(trans, root, inode, off, off + len,
|
btrfs_drop_extents(trans, inode, off, off + len, &hint_byte, 1);
|
||||||
off + len, 0, &hint_byte, 1);
|
|
||||||
|
|
||||||
/* clone data */
|
/* clone data */
|
||||||
key.objectid = src->i_ino;
|
key.objectid = src->i_ino;
|
||||||
|
|
|
@ -291,16 +291,16 @@ int btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* remove an ordered extent from the tree. No references are dropped
|
* remove an ordered extent from the tree. No references are dropped
|
||||||
* but, anyone waiting on this extent is woken up.
|
* and you must wake_up entry->wait. You must hold the tree mutex
|
||||||
|
* while you call this function.
|
||||||
*/
|
*/
|
||||||
int btrfs_remove_ordered_extent(struct inode *inode,
|
static int __btrfs_remove_ordered_extent(struct inode *inode,
|
||||||
struct btrfs_ordered_extent *entry)
|
struct btrfs_ordered_extent *entry)
|
||||||
{
|
{
|
||||||
struct btrfs_ordered_inode_tree *tree;
|
struct btrfs_ordered_inode_tree *tree;
|
||||||
struct rb_node *node;
|
struct rb_node *node;
|
||||||
|
|
||||||
tree = &BTRFS_I(inode)->ordered_tree;
|
tree = &BTRFS_I(inode)->ordered_tree;
|
||||||
mutex_lock(&tree->mutex);
|
|
||||||
node = &entry->rb_node;
|
node = &entry->rb_node;
|
||||||
rb_erase(node, &tree->tree);
|
rb_erase(node, &tree->tree);
|
||||||
tree->last = NULL;
|
tree->last = NULL;
|
||||||
|
@ -326,16 +326,34 @@ int btrfs_remove_ordered_extent(struct inode *inode,
|
||||||
}
|
}
|
||||||
spin_unlock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
|
spin_unlock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* remove an ordered extent from the tree. No references are dropped
|
||||||
|
* but any waiters are woken.
|
||||||
|
*/
|
||||||
|
int btrfs_remove_ordered_extent(struct inode *inode,
|
||||||
|
struct btrfs_ordered_extent *entry)
|
||||||
|
{
|
||||||
|
struct btrfs_ordered_inode_tree *tree;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
tree = &BTRFS_I(inode)->ordered_tree;
|
||||||
|
mutex_lock(&tree->mutex);
|
||||||
|
ret = __btrfs_remove_ordered_extent(inode, entry);
|
||||||
mutex_unlock(&tree->mutex);
|
mutex_unlock(&tree->mutex);
|
||||||
wake_up(&entry->wait);
|
wake_up(&entry->wait);
|
||||||
return 0;
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* wait for all the ordered extents in a root. This is done when balancing
|
* wait for all the ordered extents in a root. This is done when balancing
|
||||||
* space between drives.
|
* space between drives.
|
||||||
*/
|
*/
|
||||||
int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only)
|
int btrfs_wait_ordered_extents(struct btrfs_root *root,
|
||||||
|
int nocow_only, int delay_iput)
|
||||||
{
|
{
|
||||||
struct list_head splice;
|
struct list_head splice;
|
||||||
struct list_head *cur;
|
struct list_head *cur;
|
||||||
|
@ -372,7 +390,10 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only)
|
||||||
if (inode) {
|
if (inode) {
|
||||||
btrfs_start_ordered_extent(inode, ordered, 1);
|
btrfs_start_ordered_extent(inode, ordered, 1);
|
||||||
btrfs_put_ordered_extent(ordered);
|
btrfs_put_ordered_extent(ordered);
|
||||||
iput(inode);
|
if (delay_iput)
|
||||||
|
btrfs_add_delayed_iput(inode);
|
||||||
|
else
|
||||||
|
iput(inode);
|
||||||
} else {
|
} else {
|
||||||
btrfs_put_ordered_extent(ordered);
|
btrfs_put_ordered_extent(ordered);
|
||||||
}
|
}
|
||||||
|
@ -430,7 +451,7 @@ again:
|
||||||
btrfs_wait_ordered_range(inode, 0, (u64)-1);
|
btrfs_wait_ordered_range(inode, 0, (u64)-1);
|
||||||
else
|
else
|
||||||
filemap_flush(inode->i_mapping);
|
filemap_flush(inode->i_mapping);
|
||||||
iput(inode);
|
btrfs_add_delayed_iput(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_resched();
|
cond_resched();
|
||||||
|
@ -589,7 +610,7 @@ out:
|
||||||
* After an extent is done, call this to conditionally update the on disk
|
* After an extent is done, call this to conditionally update the on disk
|
||||||
* i_size. i_size is updated to cover any fully written part of the file.
|
* i_size. i_size is updated to cover any fully written part of the file.
|
||||||
*/
|
*/
|
||||||
int btrfs_ordered_update_i_size(struct inode *inode,
|
int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
|
||||||
struct btrfs_ordered_extent *ordered)
|
struct btrfs_ordered_extent *ordered)
|
||||||
{
|
{
|
||||||
struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree;
|
struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree;
|
||||||
|
@ -597,18 +618,30 @@ int btrfs_ordered_update_i_size(struct inode *inode,
|
||||||
u64 disk_i_size;
|
u64 disk_i_size;
|
||||||
u64 new_i_size;
|
u64 new_i_size;
|
||||||
u64 i_size_test;
|
u64 i_size_test;
|
||||||
|
u64 i_size = i_size_read(inode);
|
||||||
struct rb_node *node;
|
struct rb_node *node;
|
||||||
|
struct rb_node *prev = NULL;
|
||||||
struct btrfs_ordered_extent *test;
|
struct btrfs_ordered_extent *test;
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
if (ordered)
|
||||||
|
offset = entry_end(ordered);
|
||||||
|
|
||||||
mutex_lock(&tree->mutex);
|
mutex_lock(&tree->mutex);
|
||||||
disk_i_size = BTRFS_I(inode)->disk_i_size;
|
disk_i_size = BTRFS_I(inode)->disk_i_size;
|
||||||
|
|
||||||
|
/* truncate file */
|
||||||
|
if (disk_i_size > i_size) {
|
||||||
|
BTRFS_I(inode)->disk_i_size = i_size;
|
||||||
|
ret = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if the disk i_size is already at the inode->i_size, or
|
* if the disk i_size is already at the inode->i_size, or
|
||||||
* this ordered extent is inside the disk i_size, we're done
|
* this ordered extent is inside the disk i_size, we're done
|
||||||
*/
|
*/
|
||||||
if (disk_i_size >= inode->i_size ||
|
if (disk_i_size == i_size || offset <= disk_i_size) {
|
||||||
ordered->file_offset + ordered->len <= disk_i_size) {
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -616,8 +649,7 @@ int btrfs_ordered_update_i_size(struct inode *inode,
|
||||||
* we can't update the disk_isize if there are delalloc bytes
|
* we can't update the disk_isize if there are delalloc bytes
|
||||||
* between disk_i_size and this ordered extent
|
* between disk_i_size and this ordered extent
|
||||||
*/
|
*/
|
||||||
if (test_range_bit(io_tree, disk_i_size,
|
if (test_range_bit(io_tree, disk_i_size, offset - 1,
|
||||||
ordered->file_offset + ordered->len - 1,
|
|
||||||
EXTENT_DELALLOC, 0, NULL)) {
|
EXTENT_DELALLOC, 0, NULL)) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -626,20 +658,32 @@ int btrfs_ordered_update_i_size(struct inode *inode,
|
||||||
* if we find an ordered extent then we can't update disk i_size
|
* if we find an ordered extent then we can't update disk i_size
|
||||||
* yet
|
* yet
|
||||||
*/
|
*/
|
||||||
node = &ordered->rb_node;
|
if (ordered) {
|
||||||
while (1) {
|
node = rb_prev(&ordered->rb_node);
|
||||||
node = rb_prev(node);
|
} else {
|
||||||
if (!node)
|
prev = tree_search(tree, offset);
|
||||||
break;
|
/*
|
||||||
|
* we insert file extents without involving ordered struct,
|
||||||
|
* so there should be no ordered struct cover this offset
|
||||||
|
*/
|
||||||
|
if (prev) {
|
||||||
|
test = rb_entry(prev, struct btrfs_ordered_extent,
|
||||||
|
rb_node);
|
||||||
|
BUG_ON(offset_in_entry(test, offset));
|
||||||
|
}
|
||||||
|
node = prev;
|
||||||
|
}
|
||||||
|
while (node) {
|
||||||
test = rb_entry(node, struct btrfs_ordered_extent, rb_node);
|
test = rb_entry(node, struct btrfs_ordered_extent, rb_node);
|
||||||
if (test->file_offset + test->len <= disk_i_size)
|
if (test->file_offset + test->len <= disk_i_size)
|
||||||
break;
|
break;
|
||||||
if (test->file_offset >= inode->i_size)
|
if (test->file_offset >= i_size)
|
||||||
break;
|
break;
|
||||||
if (test->file_offset >= disk_i_size)
|
if (test->file_offset >= disk_i_size)
|
||||||
goto out;
|
goto out;
|
||||||
|
node = rb_prev(node);
|
||||||
}
|
}
|
||||||
new_i_size = min_t(u64, entry_end(ordered), i_size_read(inode));
|
new_i_size = min_t(u64, offset, i_size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* at this point, we know we can safely update i_size to at least
|
* at this point, we know we can safely update i_size to at least
|
||||||
|
@ -647,7 +691,14 @@ int btrfs_ordered_update_i_size(struct inode *inode,
|
||||||
* walk forward and see if ios from higher up in the file have
|
* walk forward and see if ios from higher up in the file have
|
||||||
* finished.
|
* finished.
|
||||||
*/
|
*/
|
||||||
node = rb_next(&ordered->rb_node);
|
if (ordered) {
|
||||||
|
node = rb_next(&ordered->rb_node);
|
||||||
|
} else {
|
||||||
|
if (prev)
|
||||||
|
node = rb_next(prev);
|
||||||
|
else
|
||||||
|
node = rb_first(&tree->tree);
|
||||||
|
}
|
||||||
i_size_test = 0;
|
i_size_test = 0;
|
||||||
if (node) {
|
if (node) {
|
||||||
/*
|
/*
|
||||||
|
@ -655,10 +706,10 @@ int btrfs_ordered_update_i_size(struct inode *inode,
|
||||||
* between our ordered extent and the next one.
|
* between our ordered extent and the next one.
|
||||||
*/
|
*/
|
||||||
test = rb_entry(node, struct btrfs_ordered_extent, rb_node);
|
test = rb_entry(node, struct btrfs_ordered_extent, rb_node);
|
||||||
if (test->file_offset > entry_end(ordered))
|
if (test->file_offset > offset)
|
||||||
i_size_test = test->file_offset;
|
i_size_test = test->file_offset;
|
||||||
} else {
|
} else {
|
||||||
i_size_test = i_size_read(inode);
|
i_size_test = i_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -667,15 +718,25 @@ int btrfs_ordered_update_i_size(struct inode *inode,
|
||||||
* are no delalloc bytes in this area, it is safe to update
|
* are no delalloc bytes in this area, it is safe to update
|
||||||
* disk_i_size to the end of the region.
|
* disk_i_size to the end of the region.
|
||||||
*/
|
*/
|
||||||
if (i_size_test > entry_end(ordered) &&
|
if (i_size_test > offset &&
|
||||||
!test_range_bit(io_tree, entry_end(ordered), i_size_test - 1,
|
!test_range_bit(io_tree, offset, i_size_test - 1,
|
||||||
EXTENT_DELALLOC, 0, NULL)) {
|
EXTENT_DELALLOC, 0, NULL)) {
|
||||||
new_i_size = min_t(u64, i_size_test, i_size_read(inode));
|
new_i_size = min_t(u64, i_size_test, i_size);
|
||||||
}
|
}
|
||||||
BTRFS_I(inode)->disk_i_size = new_i_size;
|
BTRFS_I(inode)->disk_i_size = new_i_size;
|
||||||
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
|
/*
|
||||||
|
* we need to remove the ordered extent with the tree lock held
|
||||||
|
* so that other people calling this function don't find our fully
|
||||||
|
* processed ordered entry and skip updating the i_size
|
||||||
|
*/
|
||||||
|
if (ordered)
|
||||||
|
__btrfs_remove_ordered_extent(inode, ordered);
|
||||||
mutex_unlock(&tree->mutex);
|
mutex_unlock(&tree->mutex);
|
||||||
return 0;
|
if (ordered)
|
||||||
|
wake_up(&ordered->wait);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -150,12 +150,13 @@ void btrfs_start_ordered_extent(struct inode *inode,
|
||||||
int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len);
|
int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len);
|
||||||
struct btrfs_ordered_extent *
|
struct btrfs_ordered_extent *
|
||||||
btrfs_lookup_first_ordered_extent(struct inode * inode, u64 file_offset);
|
btrfs_lookup_first_ordered_extent(struct inode * inode, u64 file_offset);
|
||||||
int btrfs_ordered_update_i_size(struct inode *inode,
|
int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
|
||||||
struct btrfs_ordered_extent *ordered);
|
struct btrfs_ordered_extent *ordered);
|
||||||
int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, u32 *sum);
|
int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, u32 *sum);
|
||||||
int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only);
|
|
||||||
int btrfs_run_ordered_operations(struct btrfs_root *root, int wait);
|
int btrfs_run_ordered_operations(struct btrfs_root *root, int wait);
|
||||||
int btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
|
int btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
struct inode *inode);
|
struct inode *inode);
|
||||||
|
int btrfs_wait_ordered_extents(struct btrfs_root *root,
|
||||||
|
int nocow_only, int delay_iput);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1561,6 +1561,20 @@ static int invalidate_extent_cache(struct btrfs_root *root,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void put_inodes(struct list_head *list)
|
||||||
|
{
|
||||||
|
struct inodevec *ivec;
|
||||||
|
while (!list_empty(list)) {
|
||||||
|
ivec = list_entry(list->next, struct inodevec, list);
|
||||||
|
list_del(&ivec->list);
|
||||||
|
while (ivec->nr > 0) {
|
||||||
|
ivec->nr--;
|
||||||
|
iput(ivec->inode[ivec->nr]);
|
||||||
|
}
|
||||||
|
kfree(ivec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int find_next_key(struct btrfs_path *path, int level,
|
static int find_next_key(struct btrfs_path *path, int level,
|
||||||
struct btrfs_key *key)
|
struct btrfs_key *key)
|
||||||
|
|
||||||
|
@ -1723,6 +1737,11 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
|
||||||
|
|
||||||
btrfs_btree_balance_dirty(root, nr);
|
btrfs_btree_balance_dirty(root, nr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* put inodes outside transaction, otherwise we may deadlock.
|
||||||
|
*/
|
||||||
|
put_inodes(&inode_list);
|
||||||
|
|
||||||
if (replaced && rc->stage == UPDATE_DATA_PTRS)
|
if (replaced && rc->stage == UPDATE_DATA_PTRS)
|
||||||
invalidate_extent_cache(root, &key, &next_key);
|
invalidate_extent_cache(root, &key, &next_key);
|
||||||
}
|
}
|
||||||
|
@ -1752,19 +1771,7 @@ out:
|
||||||
|
|
||||||
btrfs_btree_balance_dirty(root, nr);
|
btrfs_btree_balance_dirty(root, nr);
|
||||||
|
|
||||||
/*
|
put_inodes(&inode_list);
|
||||||
* put inodes while we aren't holding the tree locks
|
|
||||||
*/
|
|
||||||
while (!list_empty(&inode_list)) {
|
|
||||||
struct inodevec *ivec;
|
|
||||||
ivec = list_entry(inode_list.next, struct inodevec, list);
|
|
||||||
list_del(&ivec->list);
|
|
||||||
while (ivec->nr > 0) {
|
|
||||||
ivec->nr--;
|
|
||||||
iput(ivec->inode[ivec->nr]);
|
|
||||||
}
|
|
||||||
kfree(ivec);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (replaced && rc->stage == UPDATE_DATA_PTRS)
|
if (replaced && rc->stage == UPDATE_DATA_PTRS)
|
||||||
invalidate_extent_cache(root, &key, &next_key);
|
invalidate_extent_cache(root, &key, &next_key);
|
||||||
|
@ -3534,8 +3541,8 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
|
||||||
(unsigned long long)rc->block_group->key.objectid,
|
(unsigned long long)rc->block_group->key.objectid,
|
||||||
(unsigned long long)rc->block_group->flags);
|
(unsigned long long)rc->block_group->flags);
|
||||||
|
|
||||||
btrfs_start_delalloc_inodes(fs_info->tree_root);
|
btrfs_start_delalloc_inodes(fs_info->tree_root, 0);
|
||||||
btrfs_wait_ordered_extents(fs_info->tree_root, 0);
|
btrfs_wait_ordered_extents(fs_info->tree_root, 0, 0);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
rc->extents_found = 0;
|
rc->extents_found = 0;
|
||||||
|
@ -3755,6 +3762,7 @@ out:
|
||||||
BTRFS_DATA_RELOC_TREE_OBJECTID);
|
BTRFS_DATA_RELOC_TREE_OBJECTID);
|
||||||
if (IS_ERR(fs_root))
|
if (IS_ERR(fs_root))
|
||||||
err = PTR_ERR(fs_root);
|
err = PTR_ERR(fs_root);
|
||||||
|
btrfs_orphan_cleanup(fs_root);
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,6 +128,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
|
||||||
substring_t args[MAX_OPT_ARGS];
|
substring_t args[MAX_OPT_ARGS];
|
||||||
char *p, *num;
|
char *p, *num;
|
||||||
int intarg;
|
int intarg;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (!options)
|
if (!options)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -262,12 +263,18 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
|
||||||
case Opt_discard:
|
case Opt_discard:
|
||||||
btrfs_set_opt(info->mount_opt, DISCARD);
|
btrfs_set_opt(info->mount_opt, DISCARD);
|
||||||
break;
|
break;
|
||||||
|
case Opt_err:
|
||||||
|
printk(KERN_INFO "btrfs: unrecognized mount option "
|
||||||
|
"'%s'\n", p);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
kfree(options);
|
kfree(options);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -405,8 +412,8 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_start_delalloc_inodes(root);
|
btrfs_start_delalloc_inodes(root, 0);
|
||||||
btrfs_wait_ordered_extents(root, 0);
|
btrfs_wait_ordered_extents(root, 0, 0);
|
||||||
|
|
||||||
trans = btrfs_start_transaction(root, 1);
|
trans = btrfs_start_transaction(root, 1);
|
||||||
ret = btrfs_commit_transaction(trans, root);
|
ret = btrfs_commit_transaction(trans, root);
|
||||||
|
@ -450,6 +457,8 @@ static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
|
||||||
seq_puts(seq, ",notreelog");
|
seq_puts(seq, ",notreelog");
|
||||||
if (btrfs_test_opt(root, FLUSHONCOMMIT))
|
if (btrfs_test_opt(root, FLUSHONCOMMIT))
|
||||||
seq_puts(seq, ",flushoncommit");
|
seq_puts(seq, ",flushoncommit");
|
||||||
|
if (btrfs_test_opt(root, DISCARD))
|
||||||
|
seq_puts(seq, ",discard");
|
||||||
if (!(root->fs_info->sb->s_flags & MS_POSIXACL))
|
if (!(root->fs_info->sb->s_flags & MS_POSIXACL))
|
||||||
seq_puts(seq, ",noacl");
|
seq_puts(seq, ",noacl");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -333,6 +333,9 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
|
||||||
memset(trans, 0, sizeof(*trans));
|
memset(trans, 0, sizeof(*trans));
|
||||||
kmem_cache_free(btrfs_trans_handle_cachep, trans);
|
kmem_cache_free(btrfs_trans_handle_cachep, trans);
|
||||||
|
|
||||||
|
if (throttle)
|
||||||
|
btrfs_run_delayed_iputs(root);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,7 +357,7 @@ int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
|
||||||
* those extents are sent to disk but does not wait on them
|
* those extents are sent to disk but does not wait on them
|
||||||
*/
|
*/
|
||||||
int btrfs_write_marked_extents(struct btrfs_root *root,
|
int btrfs_write_marked_extents(struct btrfs_root *root,
|
||||||
struct extent_io_tree *dirty_pages)
|
struct extent_io_tree *dirty_pages, int mark)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
@ -367,7 +370,7 @@ int btrfs_write_marked_extents(struct btrfs_root *root,
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = find_first_extent_bit(dirty_pages, start, &start, &end,
|
ret = find_first_extent_bit(dirty_pages, start, &start, &end,
|
||||||
EXTENT_DIRTY);
|
mark);
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
while (start <= end) {
|
while (start <= end) {
|
||||||
|
@ -413,7 +416,7 @@ int btrfs_write_marked_extents(struct btrfs_root *root,
|
||||||
* on all the pages and clear them from the dirty pages state tree
|
* on all the pages and clear them from the dirty pages state tree
|
||||||
*/
|
*/
|
||||||
int btrfs_wait_marked_extents(struct btrfs_root *root,
|
int btrfs_wait_marked_extents(struct btrfs_root *root,
|
||||||
struct extent_io_tree *dirty_pages)
|
struct extent_io_tree *dirty_pages, int mark)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
@ -425,12 +428,12 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
|
||||||
unsigned long index;
|
unsigned long index;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = find_first_extent_bit(dirty_pages, 0, &start, &end,
|
ret = find_first_extent_bit(dirty_pages, start, &start, &end,
|
||||||
EXTENT_DIRTY);
|
mark);
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
clear_extent_dirty(dirty_pages, start, end, GFP_NOFS);
|
clear_extent_bits(dirty_pages, start, end, mark, GFP_NOFS);
|
||||||
while (start <= end) {
|
while (start <= end) {
|
||||||
index = start >> PAGE_CACHE_SHIFT;
|
index = start >> PAGE_CACHE_SHIFT;
|
||||||
start = (u64)(index + 1) << PAGE_CACHE_SHIFT;
|
start = (u64)(index + 1) << PAGE_CACHE_SHIFT;
|
||||||
|
@ -460,13 +463,13 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
|
||||||
* those extents are on disk for transaction or log commit
|
* those extents are on disk for transaction or log commit
|
||||||
*/
|
*/
|
||||||
int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
|
int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
|
||||||
struct extent_io_tree *dirty_pages)
|
struct extent_io_tree *dirty_pages, int mark)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int ret2;
|
int ret2;
|
||||||
|
|
||||||
ret = btrfs_write_marked_extents(root, dirty_pages);
|
ret = btrfs_write_marked_extents(root, dirty_pages, mark);
|
||||||
ret2 = btrfs_wait_marked_extents(root, dirty_pages);
|
ret2 = btrfs_wait_marked_extents(root, dirty_pages, mark);
|
||||||
return ret || ret2;
|
return ret || ret2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,7 +482,8 @@ int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
|
||||||
return filemap_write_and_wait(btree_inode->i_mapping);
|
return filemap_write_and_wait(btree_inode->i_mapping);
|
||||||
}
|
}
|
||||||
return btrfs_write_and_wait_marked_extents(root,
|
return btrfs_write_and_wait_marked_extents(root,
|
||||||
&trans->transaction->dirty_pages);
|
&trans->transaction->dirty_pages,
|
||||||
|
EXTENT_DIRTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -497,13 +501,16 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
u64 old_root_bytenr;
|
u64 old_root_bytenr;
|
||||||
|
u64 old_root_used;
|
||||||
struct btrfs_root *tree_root = root->fs_info->tree_root;
|
struct btrfs_root *tree_root = root->fs_info->tree_root;
|
||||||
|
|
||||||
|
old_root_used = btrfs_root_used(&root->root_item);
|
||||||
btrfs_write_dirty_block_groups(trans, root);
|
btrfs_write_dirty_block_groups(trans, root);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
old_root_bytenr = btrfs_root_bytenr(&root->root_item);
|
old_root_bytenr = btrfs_root_bytenr(&root->root_item);
|
||||||
if (old_root_bytenr == root->node->start)
|
if (old_root_bytenr == root->node->start &&
|
||||||
|
old_root_used == btrfs_root_used(&root->root_item))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
btrfs_set_root_node(&root->root_item, root->node);
|
btrfs_set_root_node(&root->root_item, root->node);
|
||||||
|
@ -512,6 +519,7 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
|
||||||
&root->root_item);
|
&root->root_item);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
|
old_root_used = btrfs_root_used(&root->root_item);
|
||||||
ret = btrfs_write_dirty_block_groups(trans, root);
|
ret = btrfs_write_dirty_block_groups(trans, root);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
}
|
}
|
||||||
|
@ -795,7 +803,6 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
||||||
memcpy(&pending->root_key, &key, sizeof(key));
|
memcpy(&pending->root_key, &key, sizeof(key));
|
||||||
fail:
|
fail:
|
||||||
kfree(new_root_item);
|
kfree(new_root_item);
|
||||||
btrfs_unreserve_metadata_space(root, 6);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -807,7 +814,6 @@ static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info,
|
||||||
u64 index = 0;
|
u64 index = 0;
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
struct inode *parent_inode;
|
struct inode *parent_inode;
|
||||||
struct inode *inode;
|
|
||||||
struct btrfs_root *parent_root;
|
struct btrfs_root *parent_root;
|
||||||
|
|
||||||
parent_inode = pending->dentry->d_parent->d_inode;
|
parent_inode = pending->dentry->d_parent->d_inode;
|
||||||
|
@ -839,8 +845,6 @@ static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info,
|
||||||
|
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
inode = btrfs_lookup_dentry(parent_inode, pending->dentry);
|
|
||||||
d_instantiate(pending->dentry, inode);
|
|
||||||
fail:
|
fail:
|
||||||
btrfs_end_transaction(trans, fs_info->fs_root);
|
btrfs_end_transaction(trans, fs_info->fs_root);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -994,11 +998,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
|
||||||
mutex_unlock(&root->fs_info->trans_mutex);
|
mutex_unlock(&root->fs_info->trans_mutex);
|
||||||
|
|
||||||
if (flush_on_commit) {
|
if (flush_on_commit) {
|
||||||
btrfs_start_delalloc_inodes(root);
|
btrfs_start_delalloc_inodes(root, 1);
|
||||||
ret = btrfs_wait_ordered_extents(root, 0);
|
ret = btrfs_wait_ordered_extents(root, 0, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
} else if (snap_pending) {
|
} else if (snap_pending) {
|
||||||
ret = btrfs_wait_ordered_extents(root, 1);
|
ret = btrfs_wait_ordered_extents(root, 0, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1116,6 +1120,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
|
||||||
current->journal_info = NULL;
|
current->journal_info = NULL;
|
||||||
|
|
||||||
kmem_cache_free(btrfs_trans_handle_cachep, trans);
|
kmem_cache_free(btrfs_trans_handle_cachep, trans);
|
||||||
|
|
||||||
|
if (current != root->fs_info->transaction_kthread)
|
||||||
|
btrfs_run_delayed_iputs(root);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,10 +107,10 @@ void btrfs_throttle(struct btrfs_root *root);
|
||||||
int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
|
int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root);
|
struct btrfs_root *root);
|
||||||
int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
|
int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
|
||||||
struct extent_io_tree *dirty_pages);
|
struct extent_io_tree *dirty_pages, int mark);
|
||||||
int btrfs_write_marked_extents(struct btrfs_root *root,
|
int btrfs_write_marked_extents(struct btrfs_root *root,
|
||||||
struct extent_io_tree *dirty_pages);
|
struct extent_io_tree *dirty_pages, int mark);
|
||||||
int btrfs_wait_marked_extents(struct btrfs_root *root,
|
int btrfs_wait_marked_extents(struct btrfs_root *root,
|
||||||
struct extent_io_tree *dirty_pages);
|
struct extent_io_tree *dirty_pages, int mark);
|
||||||
int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
|
int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -542,8 +542,8 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
saved_nbytes = inode_get_bytes(inode);
|
saved_nbytes = inode_get_bytes(inode);
|
||||||
/* drop any overlapping extents */
|
/* drop any overlapping extents */
|
||||||
ret = btrfs_drop_extents(trans, root, inode,
|
ret = btrfs_drop_extents(trans, inode, start, extent_end,
|
||||||
start, extent_end, extent_end, start, &alloc_hint, 1);
|
&alloc_hint, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
if (found_type == BTRFS_FILE_EXTENT_REG ||
|
if (found_type == BTRFS_FILE_EXTENT_REG ||
|
||||||
|
@ -930,6 +930,17 @@ out_nowrite:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int insert_orphan_item(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root, u64 offset)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
ret = btrfs_find_orphan_item(root, offset);
|
||||||
|
if (ret > 0)
|
||||||
|
ret = btrfs_insert_orphan_item(trans, root, offset);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There are a few corners where the link count of the file can't
|
* There are a few corners where the link count of the file can't
|
||||||
* be properly maintained during replay. So, instead of adding
|
* be properly maintained during replay. So, instead of adding
|
||||||
|
@ -997,9 +1008,13 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
|
||||||
}
|
}
|
||||||
BTRFS_I(inode)->index_cnt = (u64)-1;
|
BTRFS_I(inode)->index_cnt = (u64)-1;
|
||||||
|
|
||||||
if (inode->i_nlink == 0 && S_ISDIR(inode->i_mode)) {
|
if (inode->i_nlink == 0) {
|
||||||
ret = replay_dir_deletes(trans, root, NULL, path,
|
if (S_ISDIR(inode->i_mode)) {
|
||||||
inode->i_ino, 1);
|
ret = replay_dir_deletes(trans, root, NULL, path,
|
||||||
|
inode->i_ino, 1);
|
||||||
|
BUG_ON(ret);
|
||||||
|
}
|
||||||
|
ret = insert_orphan_item(trans, root, inode->i_ino);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
}
|
}
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
|
@ -1587,7 +1602,6 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
|
||||||
/* inode keys are done during the first stage */
|
/* inode keys are done during the first stage */
|
||||||
if (key.type == BTRFS_INODE_ITEM_KEY &&
|
if (key.type == BTRFS_INODE_ITEM_KEY &&
|
||||||
wc->stage == LOG_WALK_REPLAY_INODES) {
|
wc->stage == LOG_WALK_REPLAY_INODES) {
|
||||||
struct inode *inode;
|
|
||||||
struct btrfs_inode_item *inode_item;
|
struct btrfs_inode_item *inode_item;
|
||||||
u32 mode;
|
u32 mode;
|
||||||
|
|
||||||
|
@ -1603,31 +1617,16 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
|
||||||
eb, i, &key);
|
eb, i, &key);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
/* for regular files, truncate away
|
/* for regular files, make sure corresponding
|
||||||
* extents past the new EOF
|
* orhpan item exist. extents past the new EOF
|
||||||
|
* will be truncated later by orphan cleanup.
|
||||||
*/
|
*/
|
||||||
if (S_ISREG(mode)) {
|
if (S_ISREG(mode)) {
|
||||||
inode = read_one_inode(root,
|
ret = insert_orphan_item(wc->trans, root,
|
||||||
key.objectid);
|
key.objectid);
|
||||||
BUG_ON(!inode);
|
|
||||||
|
|
||||||
ret = btrfs_truncate_inode_items(wc->trans,
|
|
||||||
root, inode, inode->i_size,
|
|
||||||
BTRFS_EXTENT_DATA_KEY);
|
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
/* if the nlink count is zero here, the iput
|
|
||||||
* will free the inode. We bump it to make
|
|
||||||
* sure it doesn't get freed until the link
|
|
||||||
* count fixup is done
|
|
||||||
*/
|
|
||||||
if (inode->i_nlink == 0) {
|
|
||||||
btrfs_inc_nlink(inode);
|
|
||||||
btrfs_update_inode(wc->trans,
|
|
||||||
root, inode);
|
|
||||||
}
|
|
||||||
iput(inode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = link_to_fixup_dir(wc->trans, root,
|
ret = link_to_fixup_dir(wc->trans, root,
|
||||||
path, key.objectid);
|
path, key.objectid);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
@ -1977,10 +1976,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
||||||
{
|
{
|
||||||
int index1;
|
int index1;
|
||||||
int index2;
|
int index2;
|
||||||
|
int mark;
|
||||||
int ret;
|
int ret;
|
||||||
struct btrfs_root *log = root->log_root;
|
struct btrfs_root *log = root->log_root;
|
||||||
struct btrfs_root *log_root_tree = root->fs_info->log_root_tree;
|
struct btrfs_root *log_root_tree = root->fs_info->log_root_tree;
|
||||||
u64 log_transid = 0;
|
unsigned long log_transid = 0;
|
||||||
|
|
||||||
mutex_lock(&root->log_mutex);
|
mutex_lock(&root->log_mutex);
|
||||||
index1 = root->log_transid % 2;
|
index1 = root->log_transid % 2;
|
||||||
|
@ -2014,24 +2014,29 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_transid = root->log_transid;
|
||||||
|
if (log_transid % 2 == 0)
|
||||||
|
mark = EXTENT_DIRTY;
|
||||||
|
else
|
||||||
|
mark = EXTENT_NEW;
|
||||||
|
|
||||||
/* we start IO on all the marked extents here, but we don't actually
|
/* we start IO on all the marked extents here, but we don't actually
|
||||||
* wait for them until later.
|
* wait for them until later.
|
||||||
*/
|
*/
|
||||||
ret = btrfs_write_marked_extents(log, &log->dirty_log_pages);
|
ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
btrfs_set_root_node(&log->root_item, log->node);
|
btrfs_set_root_node(&log->root_item, log->node);
|
||||||
|
|
||||||
root->log_batch = 0;
|
root->log_batch = 0;
|
||||||
log_transid = root->log_transid;
|
|
||||||
root->log_transid++;
|
root->log_transid++;
|
||||||
log->log_transid = root->log_transid;
|
log->log_transid = root->log_transid;
|
||||||
root->log_start_pid = 0;
|
root->log_start_pid = 0;
|
||||||
smp_mb();
|
smp_mb();
|
||||||
/*
|
/*
|
||||||
* log tree has been flushed to disk, new modifications of
|
* IO has been started, blocks of the log tree have WRITTEN flag set
|
||||||
* the log will be written to new positions. so it's safe to
|
* in their headers. new modifications of the log will be written to
|
||||||
* allow log writers to go in.
|
* new positions. so it's safe to allow log writers to go in.
|
||||||
*/
|
*/
|
||||||
mutex_unlock(&root->log_mutex);
|
mutex_unlock(&root->log_mutex);
|
||||||
|
|
||||||
|
@ -2052,7 +2057,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
index2 = log_root_tree->log_transid % 2;
|
index2 = log_root_tree->log_transid % 2;
|
||||||
if (atomic_read(&log_root_tree->log_commit[index2])) {
|
if (atomic_read(&log_root_tree->log_commit[index2])) {
|
||||||
btrfs_wait_marked_extents(log, &log->dirty_log_pages);
|
btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
|
||||||
wait_log_commit(trans, log_root_tree,
|
wait_log_commit(trans, log_root_tree,
|
||||||
log_root_tree->log_transid);
|
log_root_tree->log_transid);
|
||||||
mutex_unlock(&log_root_tree->log_mutex);
|
mutex_unlock(&log_root_tree->log_mutex);
|
||||||
|
@ -2072,16 +2077,17 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
||||||
* check the full commit flag again
|
* check the full commit flag again
|
||||||
*/
|
*/
|
||||||
if (root->fs_info->last_trans_log_full_commit == trans->transid) {
|
if (root->fs_info->last_trans_log_full_commit == trans->transid) {
|
||||||
btrfs_wait_marked_extents(log, &log->dirty_log_pages);
|
btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
|
||||||
mutex_unlock(&log_root_tree->log_mutex);
|
mutex_unlock(&log_root_tree->log_mutex);
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
goto out_wake_log_root;
|
goto out_wake_log_root;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_write_and_wait_marked_extents(log_root_tree,
|
ret = btrfs_write_and_wait_marked_extents(log_root_tree,
|
||||||
&log_root_tree->dirty_log_pages);
|
&log_root_tree->dirty_log_pages,
|
||||||
|
EXTENT_DIRTY | EXTENT_NEW);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
btrfs_wait_marked_extents(log, &log->dirty_log_pages);
|
btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
|
||||||
|
|
||||||
btrfs_set_super_log_root(&root->fs_info->super_for_commit,
|
btrfs_set_super_log_root(&root->fs_info->super_for_commit,
|
||||||
log_root_tree->node->start);
|
log_root_tree->node->start);
|
||||||
|
@ -2147,12 +2153,12 @@ int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root)
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = find_first_extent_bit(&log->dirty_log_pages,
|
ret = find_first_extent_bit(&log->dirty_log_pages,
|
||||||
0, &start, &end, EXTENT_DIRTY);
|
0, &start, &end, EXTENT_DIRTY | EXTENT_NEW);
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
clear_extent_dirty(&log->dirty_log_pages,
|
clear_extent_bits(&log->dirty_log_pages, start, end,
|
||||||
start, end, GFP_NOFS);
|
EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log->log_transid > 0) {
|
if (log->log_transid > 0) {
|
||||||
|
|
|
@ -2209,7 +2209,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
|
||||||
max_chunk_size = 10 * calc_size;
|
max_chunk_size = 10 * calc_size;
|
||||||
min_stripe_size = 64 * 1024 * 1024;
|
min_stripe_size = 64 * 1024 * 1024;
|
||||||
} else if (type & BTRFS_BLOCK_GROUP_METADATA) {
|
} else if (type & BTRFS_BLOCK_GROUP_METADATA) {
|
||||||
max_chunk_size = 4 * calc_size;
|
max_chunk_size = 256 * 1024 * 1024;
|
||||||
min_stripe_size = 32 * 1024 * 1024;
|
min_stripe_size = 32 * 1024 * 1024;
|
||||||
} else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
|
} else if (type & BTRFS_BLOCK_GROUP_SYSTEM) {
|
||||||
calc_size = 8 * 1024 * 1024;
|
calc_size = 8 * 1024 * 1024;
|
||||||
|
|
|
@ -85,22 +85,23 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __btrfs_setxattr(struct inode *inode, const char *name,
|
static int do_setxattr(struct btrfs_trans_handle *trans,
|
||||||
const void *value, size_t size, int flags)
|
struct inode *inode, const char *name,
|
||||||
|
const void *value, size_t size, int flags)
|
||||||
{
|
{
|
||||||
struct btrfs_dir_item *di;
|
struct btrfs_dir_item *di;
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
struct btrfs_trans_handle *trans;
|
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
int ret = 0, mod = 0;
|
size_t name_len = strlen(name);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (name_len + size > BTRFS_MAX_XATTR_SIZE(root))
|
||||||
|
return -ENOSPC;
|
||||||
|
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
if (!path)
|
if (!path)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
trans = btrfs_join_transaction(root, 1);
|
|
||||||
btrfs_set_trans_block_group(trans, inode);
|
|
||||||
|
|
||||||
/* first lets see if we already have this xattr */
|
/* first lets see if we already have this xattr */
|
||||||
di = btrfs_lookup_xattr(trans, root, path, inode->i_ino, name,
|
di = btrfs_lookup_xattr(trans, root, path, inode->i_ino, name,
|
||||||
strlen(name), -1);
|
strlen(name), -1);
|
||||||
|
@ -118,15 +119,12 @@ int __btrfs_setxattr(struct inode *inode, const char *name,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_delete_one_dir_name(trans, root, path, di);
|
ret = btrfs_delete_one_dir_name(trans, root, path, di);
|
||||||
if (ret)
|
BUG_ON(ret);
|
||||||
goto out;
|
|
||||||
btrfs_release_path(root, path);
|
btrfs_release_path(root, path);
|
||||||
|
|
||||||
/* if we don't have a value then we are removing the xattr */
|
/* if we don't have a value then we are removing the xattr */
|
||||||
if (!value) {
|
if (!value)
|
||||||
mod = 1;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
btrfs_release_path(root, path);
|
btrfs_release_path(root, path);
|
||||||
|
|
||||||
|
@ -138,20 +136,45 @@ int __btrfs_setxattr(struct inode *inode, const char *name,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ok we have to create a completely new xattr */
|
/* ok we have to create a completely new xattr */
|
||||||
ret = btrfs_insert_xattr_item(trans, root, name, strlen(name),
|
ret = btrfs_insert_xattr_item(trans, root, path, inode->i_ino,
|
||||||
value, size, inode->i_ino);
|
name, name_len, value, size);
|
||||||
|
BUG_ON(ret);
|
||||||
|
out:
|
||||||
|
btrfs_free_path(path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __btrfs_setxattr(struct btrfs_trans_handle *trans,
|
||||||
|
struct inode *inode, const char *name,
|
||||||
|
const void *value, size_t size, int flags)
|
||||||
|
{
|
||||||
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (trans)
|
||||||
|
return do_setxattr(trans, inode, name, value, size, flags);
|
||||||
|
|
||||||
|
ret = btrfs_reserve_metadata_space(root, 2);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
trans = btrfs_start_transaction(root, 1);
|
||||||
|
if (!trans) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
btrfs_set_trans_block_group(trans, inode);
|
||||||
|
|
||||||
|
ret = do_setxattr(trans, inode, name, value, size, flags);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
mod = 1;
|
|
||||||
|
|
||||||
|
inode->i_ctime = CURRENT_TIME;
|
||||||
|
ret = btrfs_update_inode(trans, root, inode);
|
||||||
|
BUG_ON(ret);
|
||||||
out:
|
out:
|
||||||
if (mod) {
|
btrfs_end_transaction_throttle(trans, root);
|
||||||
inode->i_ctime = CURRENT_TIME;
|
btrfs_unreserve_metadata_space(root, 2);
|
||||||
ret = btrfs_update_inode(trans, root, inode);
|
|
||||||
}
|
|
||||||
|
|
||||||
btrfs_end_transaction(trans, root);
|
|
||||||
btrfs_free_path(path);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +337,9 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
|
||||||
|
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
value = ""; /* empty EA, do not remove */
|
value = ""; /* empty EA, do not remove */
|
||||||
return __btrfs_setxattr(dentry->d_inode, name, value, size, flags);
|
|
||||||
|
return __btrfs_setxattr(NULL, dentry->d_inode, name, value, size,
|
||||||
|
flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_removexattr(struct dentry *dentry, const char *name)
|
int btrfs_removexattr(struct dentry *dentry, const char *name)
|
||||||
|
@ -329,10 +354,13 @@ int btrfs_removexattr(struct dentry *dentry, const char *name)
|
||||||
|
|
||||||
if (!btrfs_is_valid_xattr(name))
|
if (!btrfs_is_valid_xattr(name))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
return __btrfs_setxattr(dentry->d_inode, name, NULL, 0, XATTR_REPLACE);
|
|
||||||
|
return __btrfs_setxattr(NULL, dentry->d_inode, name, NULL, 0,
|
||||||
|
XATTR_REPLACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_xattr_security_init(struct inode *inode, struct inode *dir)
|
int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
|
||||||
|
struct inode *inode, struct inode *dir)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
@ -354,7 +382,7 @@ int btrfs_xattr_security_init(struct inode *inode, struct inode *dir)
|
||||||
} else {
|
} else {
|
||||||
strcpy(name, XATTR_SECURITY_PREFIX);
|
strcpy(name, XATTR_SECURITY_PREFIX);
|
||||||
strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix);
|
strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix);
|
||||||
err = __btrfs_setxattr(inode, name, value, len, 0);
|
err = __btrfs_setxattr(trans, inode, name, value, len, 0);
|
||||||
kfree(name);
|
kfree(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,15 +27,16 @@ extern struct xattr_handler *btrfs_xattr_handlers[];
|
||||||
|
|
||||||
extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
|
extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
|
||||||
void *buffer, size_t size);
|
void *buffer, size_t size);
|
||||||
extern int __btrfs_setxattr(struct inode *inode, const char *name,
|
extern int __btrfs_setxattr(struct btrfs_trans_handle *trans,
|
||||||
const void *value, size_t size, int flags);
|
struct inode *inode, const char *name,
|
||||||
|
const void *value, size_t size, int flags);
|
||||||
extern ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
|
extern ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
|
||||||
void *buffer, size_t size);
|
void *buffer, size_t size);
|
||||||
extern int btrfs_setxattr(struct dentry *dentry, const char *name,
|
extern int btrfs_setxattr(struct dentry *dentry, const char *name,
|
||||||
const void *value, size_t size, int flags);
|
const void *value, size_t size, int flags);
|
||||||
extern int btrfs_removexattr(struct dentry *dentry, const char *name);
|
extern int btrfs_removexattr(struct dentry *dentry, const char *name);
|
||||||
|
|
||||||
extern int btrfs_xattr_security_init(struct inode *inode, struct inode *dir);
|
extern int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
|
||||||
|
struct inode *inode, struct inode *dir);
|
||||||
|
|
||||||
#endif /* __XATTR__ */
|
#endif /* __XATTR__ */
|
||||||
|
|
Loading…
Reference in a new issue