Commit de428b63 authored by Chris Mason's avatar Chris Mason Committed by David Woodhouse

Btrfs: allocator optimizations, truncate readahead

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 098f59c2
...@@ -1081,7 +1081,7 @@ static inline void btrfs_mark_buffer_dirty(struct buffer_head *bh) ...@@ -1081,7 +1081,7 @@ static inline void btrfs_mark_buffer_dirty(struct buffer_head *bh)
struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
struct btrfs_block_group_cache struct btrfs_block_group_cache
*hint, u64 search_start, *hint, u64 search_start,
int data); int data, int owner);
int btrfs_inc_root_ref(struct btrfs_trans_handle *trans, int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root); struct btrfs_root *root);
struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
......
...@@ -257,24 +257,30 @@ static struct address_space_operations btree_aops = { ...@@ -257,24 +257,30 @@ static struct address_space_operations btree_aops = {
int readahead_tree_block(struct btrfs_root *root, u64 blocknr) int readahead_tree_block(struct btrfs_root *root, u64 blocknr)
{ {
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
int ret = 0;
bh = btrfs_find_create_tree_block(root, blocknr); bh = btrfs_find_create_tree_block(root, blocknr);
if (!bh) if (!bh)
return 0; return 0;
if (buffer_uptodate(bh)) if (buffer_uptodate(bh)) {
ret = 1;
goto done; goto done;
if (test_set_buffer_locked(bh)) }
if (test_set_buffer_locked(bh)) {
ret = 1;
goto done; goto done;
}
if (!buffer_uptodate(bh)) { if (!buffer_uptodate(bh)) {
get_bh(bh); get_bh(bh);
bh->b_end_io = end_buffer_read_sync; bh->b_end_io = end_buffer_read_sync;
submit_bh(READ, bh); submit_bh(READ, bh);
} else { } else {
unlock_buffer(bh); unlock_buffer(bh);
ret = 1;
} }
done: done:
brelse(bh); brelse(bh);
return 0; return ret;
} }
struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr) struct buffer_head *read_tree_block(struct btrfs_root *root, u64 blocknr)
......
...@@ -12,6 +12,33 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct ...@@ -12,6 +12,33 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
static int del_pending_extents(struct btrfs_trans_handle *trans, struct static int del_pending_extents(struct btrfs_trans_handle *trans, struct
btrfs_root *extent_root); btrfs_root *extent_root);
static void reada_extent_leaves(struct btrfs_root *root,
struct btrfs_path *path, u64 limit)
{
struct btrfs_node *node;
int i;
int nritems;
u64 item_objectid;
u64 blocknr;
int slot;
int ret;
if (!path->nodes[1])
return;
node = btrfs_buffer_node(path->nodes[1]);
slot = path->slots[1] + 1;
nritems = btrfs_header_nritems(&node->header);
for (i = slot; i < nritems && i < slot + 8; i++) {
item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key);
if (item_objectid > limit)
break;
blocknr = btrfs_node_blockptr(node, i);
ret = readahead_tree_block(root, blocknr);
if (ret)
break;
}
}
static int cache_block_group(struct btrfs_root *root, static int cache_block_group(struct btrfs_root *root,
struct btrfs_block_group_cache *block_group) struct btrfs_block_group_cache *block_group)
{ {
...@@ -24,6 +51,7 @@ static int cache_block_group(struct btrfs_root *root, ...@@ -24,6 +51,7 @@ static int cache_block_group(struct btrfs_root *root,
u64 i; u64 i;
u64 last = 0; u64 last = 0;
u64 hole_size; u64 hole_size;
u64 limit;
int found = 0; int found = 0;
root = root->fs_info->extent_root; root = root->fs_info->extent_root;
...@@ -46,14 +74,17 @@ printk("cache block group %Lu\n", block_group->key.objectid); ...@@ -46,14 +74,17 @@ printk("cache block group %Lu\n", block_group->key.objectid);
return ret; return ret;
if (ret && path->slots[0] > 0) if (ret && path->slots[0] > 0)
path->slots[0]--; path->slots[0]--;
limit = block_group->key.objectid + block_group->key.offset;
reada_extent_leaves(root, path, limit);
while(1) { while(1) {
leaf = btrfs_buffer_leaf(path->nodes[0]); leaf = btrfs_buffer_leaf(path->nodes[0]);
slot = path->slots[0]; slot = path->slots[0];
if (slot >= btrfs_header_nritems(&leaf->header)) { if (slot >= btrfs_header_nritems(&leaf->header)) {
reada_extent_leaves(root, path, limit);
ret = btrfs_next_leaf(root, path); ret = btrfs_next_leaf(root, path);
if (ret == 0) if (ret == 0) {
continue; continue;
else { } else {
if (found) { if (found) {
hole_size = block_group->key.objectid + hole_size = block_group->key.objectid +
block_group->key.offset - last; block_group->key.offset - last;
...@@ -187,7 +218,7 @@ static u64 find_search_start(struct btrfs_root *root, ...@@ -187,7 +218,7 @@ static u64 find_search_start(struct btrfs_root *root,
return max((*cache_ret)->last_alloc, search_start); return max((*cache_ret)->last_alloc, search_start);
} }
cache = btrfs_find_block_group(root, cache, cache = btrfs_find_block_group(root, cache,
last + cache->key.offset - 1, 0); last + cache->key.offset - 1, 0, 0);
*cache_ret = cache; *cache_ret = cache;
goto again; goto again;
} }
...@@ -195,7 +226,7 @@ static u64 find_search_start(struct btrfs_root *root, ...@@ -195,7 +226,7 @@ static u64 find_search_start(struct btrfs_root *root,
struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
struct btrfs_block_group_cache struct btrfs_block_group_cache
*hint, u64 search_start, *hint, u64 search_start,
int data) int data, int owner)
{ {
struct btrfs_block_group_cache *cache[8]; struct btrfs_block_group_cache *cache[8];
struct btrfs_block_group_cache *found_group = NULL; struct btrfs_block_group_cache *found_group = NULL;
...@@ -207,6 +238,10 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, ...@@ -207,6 +238,10 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
int i; int i;
int ret; int ret;
int full_search = 0; int full_search = 0;
int factor = 8;
if (!owner)
factor = 5;
if (data) if (data)
radix = &info->block_group_data_radix; radix = &info->block_group_data_radix;
...@@ -219,14 +254,14 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, ...@@ -219,14 +254,14 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
if (shint->data == data) { if (shint->data == data) {
used = btrfs_block_group_used(&shint->item); used = btrfs_block_group_used(&shint->item);
if (used + shint->pinned < if (used + shint->pinned <
(shint->key.offset * 8) / 10) { (shint->key.offset * factor) / 10) {
return shint; return shint;
} }
} }
} }
if (hint && hint->data == data) { if (hint && hint->data == data) {
used = btrfs_block_group_used(&hint->item); used = btrfs_block_group_used(&hint->item);
if (used + hint->pinned < (hint->key.offset * 8) / 10) { if (used + hint->pinned < (hint->key.offset * factor) / 10) {
return hint; return hint;
} }
if (used >= (hint->key.offset * 8) / 10) { if (used >= (hint->key.offset * 8) / 10) {
...@@ -261,7 +296,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, ...@@ -261,7 +296,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
cache[i]->key.offset; cache[i]->key.offset;
used = btrfs_block_group_used(&cache[i]->item); used = btrfs_block_group_used(&cache[i]->item);
if (used + cache[i]->pinned < if (used + cache[i]->pinned <
(cache[i]->key.offset * 8) / 10) { (cache[i]->key.offset * factor) / 10) {
found_group = cache[i]; found_group = cache[i];
goto found; goto found;
} }
...@@ -272,6 +307,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, ...@@ -272,6 +307,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
BTRFS_BLOCK_GROUP_AVAIL); BTRFS_BLOCK_GROUP_AVAIL);
} }
} }
cond_resched();
} }
last = hint_last; last = hint_last;
again: again:
...@@ -295,13 +331,16 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, ...@@ -295,13 +331,16 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
BTRFS_BLOCK_GROUP_AVAIL); BTRFS_BLOCK_GROUP_AVAIL);
} }
} }
cond_resched();
} }
if (!full_search) { if (!full_search) {
printk("find block group doing full search data %d start %Lu\n", data, search_start);
last = search_start; last = search_start;
full_search = 1; full_search = 1;
goto again; goto again;
} }
if (!found_group) { if (!found_group) {
printk("find block group bailing to zero data %d\n", data);
ret = radix_tree_gang_lookup(radix, ret = radix_tree_gang_lookup(radix,
(void **)&found_group, 0, 1); (void **)&found_group, 0, 1);
BUG_ON(ret != 1); BUG_ON(ret != 1);
...@@ -554,8 +593,8 @@ static int update_block_group(struct btrfs_trans_handle *trans, ...@@ -554,8 +593,8 @@ static int update_block_group(struct btrfs_trans_handle *trans,
blocknr + i); blocknr + i);
} }
} }
if (old_val < (cache->key.offset * 6) / 10 && if (old_val < (cache->key.offset * 5) / 10 &&
old_val + num >= (cache->key.offset * 6) / 10) { old_val + num >= (cache->key.offset * 5) / 10) {
printk("group %Lu now available\n", cache->key.objectid); printk("group %Lu now available\n", cache->key.objectid);
radix_tree_tag_set(cache->radix, radix_tree_tag_set(cache->radix,
cache->key.objectid + cache->key.objectid +
...@@ -842,6 +881,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -842,6 +881,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
int level; int level;
struct btrfs_block_group_cache *block_group; struct btrfs_block_group_cache *block_group;
int full_scan = 0; int full_scan = 0;
u64 limit;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
ins->flags = 0; ins->flags = 0;
...@@ -858,11 +898,11 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -858,11 +898,11 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
if (search_start) { if (search_start) {
block_group = lookup_block_group(info, search_start); block_group = lookup_block_group(info, search_start);
block_group = btrfs_find_block_group(root, block_group, block_group = btrfs_find_block_group(root, block_group,
search_start, data); search_start, data, 1);
} else { } else {
block_group = btrfs_find_block_group(root, block_group = btrfs_find_block_group(root,
trans->block_group, 0, trans->block_group, 0,
data); data, 1);
} }
check_failed: check_failed:
...@@ -916,6 +956,12 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -916,6 +956,12 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
info->extent_tree_prealloc_nr = 0; info->extent_tree_prealloc_nr = 0;
total_found = 0; total_found = 0;
} }
if (start_found)
limit = last_block +
block_group->key.offset / 2;
else
limit = search_start +
block_group->key.offset / 2;
ret = btrfs_next_leaf(root, path); ret = btrfs_next_leaf(root, path);
if (ret == 0) if (ret == 0)
continue; continue;
...@@ -960,6 +1006,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -960,6 +1006,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
} }
next: next:
path->slots[0]++; path->slots[0]++;
cond_resched();
} }
// FIXME -ENOSPC // FIXME -ENOSPC
check_pending: check_pending:
...@@ -1049,7 +1096,8 @@ printk("doing full scan!\n"); ...@@ -1049,7 +1096,8 @@ printk("doing full scan!\n");
block_group = lookup_block_group(info, search_start); block_group = lookup_block_group(info, search_start);
if (!full_scan) if (!full_scan)
block_group = btrfs_find_block_group(root, block_group, block_group = btrfs_find_block_group(root, block_group,
search_start, data); search_start, data, 0);
cond_resched();
goto check_failed; goto check_failed;
error: error:
...@@ -1102,7 +1150,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, ...@@ -1102,7 +1150,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
* in the correct block group. * in the correct block group.
*/ */
if (data) { if (data) {
ret = find_free_extent(trans, root, 0, search_start, ret = find_free_extent(trans, root, 0, 0,
search_end, &prealloc_key, 0); search_end, &prealloc_key, 0);
if (ret) { if (ret) {
return ret; return ret;
...@@ -1173,7 +1221,7 @@ struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, ...@@ -1173,7 +1221,7 @@ struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
struct buffer_head *buf; struct buffer_head *buf;
ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, ret = btrfs_alloc_extent(trans, root, root->root_key.objectid,
1, 0, (unsigned long)-1, &ins, 0); 1, hint, (unsigned long)-1, &ins, 0);
if (ret) { if (ret) {
BUG(); BUG();
return NULL; return NULL;
......
...@@ -351,6 +351,35 @@ static int btrfs_free_inode(struct btrfs_trans_handle *trans, ...@@ -351,6 +351,35 @@ static int btrfs_free_inode(struct btrfs_trans_handle *trans,
return ret; return ret;
} }
static void reada_truncate(struct btrfs_root *root, struct btrfs_path *path,
u64 objectid)
{
struct btrfs_node *node;
int i;
int nritems;
u64 item_objectid;
u64 blocknr;
int slot;
int ret;
if (!path->nodes[1])
return;
node = btrfs_buffer_node(path->nodes[1]);
slot = path->slots[1];
if (slot == 0)
return;
nritems = btrfs_header_nritems(&node->header);
for (i = slot - 1; i >= 0; i--) {
item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key);
if (item_objectid != objectid)
break;
blocknr = btrfs_node_blockptr(node, i);
ret = readahead_tree_block(root, blocknr);
if (ret)
break;
}
}
static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct inode *inode) struct inode *inode)
...@@ -386,6 +415,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, ...@@ -386,6 +415,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
BUG_ON(path->slots[0] == 0); BUG_ON(path->slots[0] == 0);
path->slots[0]--; path->slots[0]--;
} }
reada_truncate(root, path, inode->i_ino);
leaf = btrfs_buffer_leaf(path->nodes[0]); leaf = btrfs_buffer_leaf(path->nodes[0]);
found_key = &leaf->items[path->slots[0]].key; found_key = &leaf->items[path->slots[0]].key;
if (btrfs_disk_key_objectid(found_key) != inode->i_ino) if (btrfs_disk_key_objectid(found_key) != inode->i_ino)
...@@ -587,28 +617,30 @@ printk("adding new root for inode %lu root %p (found %p)\n", inode->i_ino, sub_r ...@@ -587,28 +617,30 @@ printk("adding new root for inode %lu root %p (found %p)\n", inode->i_ino, sub_r
return d_splice_alias(inode, dentry); return d_splice_alias(inode, dentry);
} }
static void reada_leaves(struct btrfs_root *root, struct btrfs_path *path) static void reada_leaves(struct btrfs_root *root, struct btrfs_path *path,
u64 objectid)
{ {
struct btrfs_node *node; struct btrfs_node *node;
int i; int i;
int nritems; u32 nritems;
u64 objectid;
u64 item_objectid; u64 item_objectid;
u64 blocknr; u64 blocknr;
int slot; int slot;
int ret;
if (!path->nodes[1]) if (!path->nodes[1])
return; return;
node = btrfs_buffer_node(path->nodes[1]); node = btrfs_buffer_node(path->nodes[1]);
slot = path->slots[1]; slot = path->slots[1];
objectid = btrfs_disk_key_objectid(&node->ptrs[slot].key);
nritems = btrfs_header_nritems(&node->header); nritems = btrfs_header_nritems(&node->header);
for (i = slot; i < nritems; i++) { for (i = slot + 1; i < nritems; i++) {
item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key); item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key);
if (item_objectid != objectid) if (item_objectid != objectid)
break; break;
blocknr = btrfs_node_blockptr(node, i); blocknr = btrfs_node_blockptr(node, i);
readahead_tree_block(root, blocknr); ret = readahead_tree_block(root, blocknr);
if (ret)
break;
} }
} }
...@@ -646,21 +678,20 @@ static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -646,21 +678,20 @@ static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (ret < 0) if (ret < 0)
goto err; goto err;
advance = 0; advance = 0;
reada_leaves(root, path); reada_leaves(root, path, inode->i_ino);
while(1) { while(1) {
leaf = btrfs_buffer_leaf(path->nodes[0]); leaf = btrfs_buffer_leaf(path->nodes[0]);
nritems = btrfs_header_nritems(&leaf->header); nritems = btrfs_header_nritems(&leaf->header);
slot = path->slots[0]; slot = path->slots[0];
if (advance || slot >= nritems) { if (advance || slot >= nritems) {
if (slot >= nritems -1) { if (slot >= nritems -1) {
reada_leaves(root, path, inode->i_ino);
ret = btrfs_next_leaf(root, path); ret = btrfs_next_leaf(root, path);
if (ret) if (ret)
break; break;
leaf = btrfs_buffer_leaf(path->nodes[0]); leaf = btrfs_buffer_leaf(path->nodes[0]);
nritems = btrfs_header_nritems(&leaf->header); nritems = btrfs_header_nritems(&leaf->header);
slot = path->slots[0]; slot = path->slots[0];
if (path->slots[1] == 0)
reada_leaves(root, path);
} else { } else {
slot++; slot++;
path->slots[0]++; path->slots[0]++;
...@@ -805,13 +836,18 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, ...@@ -805,13 +836,18 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
struct btrfs_inode_item inode_item; struct btrfs_inode_item inode_item;
struct btrfs_key *location; struct btrfs_key *location;
int ret; int ret;
int owner;
inode = new_inode(root->fs_info->sb); inode = new_inode(root->fs_info->sb);
if (!inode) if (!inode)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
BTRFS_I(inode)->root = root; BTRFS_I(inode)->root = root;
group = btrfs_find_block_group(root, group, 0, 0); if (mode & S_IFDIR)
owner = 0;
else
owner = 1;
group = btrfs_find_block_group(root, group, 0, 0, owner);
BTRFS_I(inode)->block_group = group; BTRFS_I(inode)->block_group = group;
inode->i_uid = current->fsuid; inode->i_uid = current->fsuid;
...@@ -1562,7 +1598,7 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -1562,7 +1598,7 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
static int drop_extents(struct btrfs_trans_handle *trans, static int drop_extents(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct inode *inode, struct inode *inode,
u64 start, u64 end) u64 start, u64 end, u64 *hint_block)
{ {
int ret; int ret;
struct btrfs_key key; struct btrfs_key key;
...@@ -1659,17 +1695,14 @@ static int drop_extents(struct btrfs_trans_handle *trans, ...@@ -1659,17 +1695,14 @@ static int drop_extents(struct btrfs_trans_handle *trans,
new_num = (start - key.offset) >> new_num = (start - key.offset) >>
inode->i_blkbits; inode->i_blkbits;
old_num = btrfs_file_extent_num_blocks(extent); old_num = btrfs_file_extent_num_blocks(extent);
*hint_block =
btrfs_file_extent_disk_blocknr(extent);
inode->i_blocks -= (old_num - new_num) << 3; inode->i_blocks -= (old_num - new_num) << 3;
btrfs_set_file_extent_num_blocks(extent, btrfs_set_file_extent_num_blocks(extent,
new_num); new_num);
mark_buffer_dirty(path->nodes[0]); mark_buffer_dirty(path->nodes[0]);
} else { } else {
WARN_ON(1); WARN_ON(1);
/*
ret = btrfs_truncate_item(trans, root, path,
start - key.offset);
BUG_ON(ret);
*/
} }
} }
if (!keep) { if (!keep) {
...@@ -1683,6 +1716,8 @@ static int drop_extents(struct btrfs_trans_handle *trans, ...@@ -1683,6 +1716,8 @@ static int drop_extents(struct btrfs_trans_handle *trans,
btrfs_file_extent_disk_num_blocks(extent); btrfs_file_extent_disk_num_blocks(extent);
extent_num_blocks = extent_num_blocks =
btrfs_file_extent_num_blocks(extent); btrfs_file_extent_num_blocks(extent);
*hint_block =
btrfs_file_extent_disk_blocknr(extent);
} }
ret = btrfs_del_item(trans, root, path); ret = btrfs_del_item(trans, root, path);
BUG_ON(ret); BUG_ON(ret);
...@@ -1831,6 +1866,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, ...@@ -1831,6 +1866,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
u64 start_pos; u64 start_pos;
u64 num_blocks; u64 num_blocks;
u64 alloc_extent_start; u64 alloc_extent_start;
u64 hint_block;
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
struct btrfs_key ins; struct btrfs_key ins;
pinned[0] = NULL; pinned[0] = NULL;
...@@ -1871,6 +1907,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, ...@@ -1871,6 +1907,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
} }
if (first_index != last_index && if (first_index != last_index &&
(last_index << PAGE_CACHE_SHIFT) < inode->i_size && (last_index << PAGE_CACHE_SHIFT) < inode->i_size &&
pos + count < inode->i_size &&
(count & (PAGE_CACHE_SIZE - 1))) { (count & (PAGE_CACHE_SIZE - 1))) {
pinned[1] = grab_cache_page(inode->i_mapping, last_index); pinned[1] = grab_cache_page(inode->i_mapping, last_index);
if (!PageUptodate(pinned[1])) { if (!PageUptodate(pinned[1])) {
...@@ -1892,18 +1929,20 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, ...@@ -1892,18 +1929,20 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
btrfs_set_trans_block_group(trans, inode); btrfs_set_trans_block_group(trans, inode);
/* FIXME blocksize != 4096 */ /* FIXME blocksize != 4096 */
inode->i_blocks += num_blocks << 3; inode->i_blocks += num_blocks << 3;
hint_block = 0;
if (start_pos < inode->i_size) { if (start_pos < inode->i_size) {
/* FIXME blocksize != pagesize */ /* FIXME blocksize != pagesize */
ret = drop_extents(trans, root, inode, ret = drop_extents(trans, root, inode,
start_pos, start_pos,
(pos + count + root->blocksize -1) & (pos + count + root->blocksize -1) &
~((u64)root->blocksize - 1)); ~((u64)root->blocksize - 1), &hint_block);
BUG_ON(ret); BUG_ON(ret);
} }
if (inode->i_size >= PAGE_CACHE_SIZE || pos + count < inode->i_size || if (inode->i_size >= PAGE_CACHE_SIZE || pos + count < inode->i_size ||
pos + count - start_pos > BTRFS_MAX_INLINE_DATA_SIZE(root)) { pos + count - start_pos > BTRFS_MAX_INLINE_DATA_SIZE(root)) {
ret = btrfs_alloc_extent(trans, root, inode->i_ino, ret = btrfs_alloc_extent(trans, root, inode->i_ino,
num_blocks, 1, (u64)-1, &ins, 1); num_blocks, hint_block, (u64)-1,
&ins, 1);
BUG_ON(ret); BUG_ON(ret);
ret = btrfs_insert_file_extent(trans, root, inode->i_ino, ret = btrfs_insert_file_extent(trans, root, inode->i_ino,
start_pos, ins.objectid, ins.offset); start_pos, ins.objectid, ins.offset);
...@@ -2455,7 +2494,6 @@ static int btrfs_get_sb(struct file_system_type *fs_type, ...@@ -2455,7 +2494,6 @@ static int btrfs_get_sb(struct file_system_type *fs_type,
btrfs_fill_super, mnt); btrfs_fill_super, mnt);
} }
static int btrfs_getattr(struct vfsmount *mnt, static int btrfs_getattr(struct vfsmount *mnt,
struct dentry *dentry, struct kstat *stat) struct dentry *dentry, struct kstat *stat)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment