Commit 874d0d26 authored by Chris Mason's avatar Chris Mason

Merge branch 'for-chris' of...

Merge branch 'for-chris' of git://git.kernel.org/pub/scm/linux/kernel/git/josef/btrfs-work into for-linus
parents 507903b8 13c5a93e
...@@ -2576,6 +2576,11 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode, ...@@ -2576,6 +2576,11 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
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);
void btrfs_drop_pages(struct page **pages, size_t num_pages);
int btrfs_dirty_pages(struct btrfs_root *root, struct inode *inode,
struct page **pages, size_t num_pages,
loff_t pos, size_t write_bytes,
struct extent_state **cached);
/* tree-defrag.c */ /* tree-defrag.c */
int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
......
...@@ -3136,7 +3136,7 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root) ...@@ -3136,7 +3136,7 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root)
btrfs_destroy_pinned_extent(root, btrfs_destroy_pinned_extent(root,
root->fs_info->pinned_extents); root->fs_info->pinned_extents);
t->use_count = 0; atomic_set(&t->use_count, 0);
list_del_init(&t->list); list_del_init(&t->list);
memset(t, 0, sizeof(*t)); memset(t, 0, sizeof(*t));
kmem_cache_free(btrfs_transaction_cachep, t); kmem_cache_free(btrfs_transaction_cachep, t);
......
...@@ -104,7 +104,7 @@ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages, ...@@ -104,7 +104,7 @@ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages,
/* /*
* unlocks pages after btrfs_file_write is done with them * unlocks pages after btrfs_file_write is done with them
*/ */
static noinline void btrfs_drop_pages(struct page **pages, size_t num_pages) void btrfs_drop_pages(struct page **pages, size_t num_pages)
{ {
size_t i; size_t i;
for (i = 0; i < num_pages; i++) { for (i = 0; i < num_pages; i++) {
...@@ -127,16 +127,13 @@ static noinline void btrfs_drop_pages(struct page **pages, size_t num_pages) ...@@ -127,16 +127,13 @@ static noinline void btrfs_drop_pages(struct page **pages, size_t num_pages)
* this also makes the decision about creating an inline extent vs * this also makes the decision about creating an inline extent vs
* doing real data extents, marking pages dirty and delalloc as required. * doing real data extents, marking pages dirty and delalloc as required.
*/ */
static noinline int dirty_and_release_pages(struct btrfs_root *root, int btrfs_dirty_pages(struct btrfs_root *root, struct inode *inode,
struct file *file, struct page **pages, size_t num_pages,
struct page **pages, loff_t pos, size_t write_bytes,
size_t num_pages, struct extent_state **cached)
loff_t pos,
size_t write_bytes)
{ {
int err = 0; int err = 0;
int i; int i;
struct inode *inode = fdentry(file)->d_inode;
u64 num_bytes; u64 num_bytes;
u64 start_pos; u64 start_pos;
u64 end_of_last_block; u64 end_of_last_block;
...@@ -149,7 +146,7 @@ static noinline int dirty_and_release_pages(struct btrfs_root *root, ...@@ -149,7 +146,7 @@ static noinline int dirty_and_release_pages(struct btrfs_root *root,
end_of_last_block = start_pos + num_bytes - 1; end_of_last_block = start_pos + num_bytes - 1;
err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block, err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block,
NULL); cached);
if (err) if (err)
return err; return err;
...@@ -992,9 +989,9 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file, ...@@ -992,9 +989,9 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
} }
if (copied > 0) { if (copied > 0) {
ret = dirty_and_release_pages(root, file, pages, ret = btrfs_dirty_pages(root, inode, pages,
dirty_pages, pos, dirty_pages, pos, copied,
copied); NULL);
if (ret) { if (ret) {
btrfs_delalloc_release_space(inode, btrfs_delalloc_release_space(inode,
dirty_pages << PAGE_CACHE_SHIFT); dirty_pages << PAGE_CACHE_SHIFT);
......
...@@ -508,6 +508,7 @@ int btrfs_write_out_cache(struct btrfs_root *root, ...@@ -508,6 +508,7 @@ int btrfs_write_out_cache(struct btrfs_root *root,
struct inode *inode; struct inode *inode;
struct rb_node *node; struct rb_node *node;
struct list_head *pos, *n; struct list_head *pos, *n;
struct page **pages;
struct page *page; struct page *page;
struct extent_state *cached_state = NULL; struct extent_state *cached_state = NULL;
struct btrfs_free_cluster *cluster = NULL; struct btrfs_free_cluster *cluster = NULL;
...@@ -517,13 +518,13 @@ int btrfs_write_out_cache(struct btrfs_root *root, ...@@ -517,13 +518,13 @@ int btrfs_write_out_cache(struct btrfs_root *root,
u64 start, end, len; u64 start, end, len;
u64 bytes = 0; u64 bytes = 0;
u32 *crc, *checksums; u32 *crc, *checksums;
pgoff_t index = 0, last_index = 0;
unsigned long first_page_offset; unsigned long first_page_offset;
int num_checksums; int index = 0, num_pages = 0;
int entries = 0; int entries = 0;
int bitmaps = 0; int bitmaps = 0;
int ret = 0; int ret = 0;
bool next_page = false; bool next_page = false;
bool out_of_space = false;
root = root->fs_info->tree_root; root = root->fs_info->tree_root;
...@@ -551,24 +552,31 @@ int btrfs_write_out_cache(struct btrfs_root *root, ...@@ -551,24 +552,31 @@ int btrfs_write_out_cache(struct btrfs_root *root,
return 0; return 0;
} }
last_index = (i_size_read(inode) - 1) >> PAGE_CACHE_SHIFT; num_pages = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT;
filemap_write_and_wait(inode->i_mapping); filemap_write_and_wait(inode->i_mapping);
btrfs_wait_ordered_range(inode, inode->i_size & btrfs_wait_ordered_range(inode, inode->i_size &
~(root->sectorsize - 1), (u64)-1); ~(root->sectorsize - 1), (u64)-1);
/* We need a checksum per page. */ /* We need a checksum per page. */
num_checksums = i_size_read(inode) / PAGE_CACHE_SIZE; crc = checksums = kzalloc(sizeof(u32) * num_pages, GFP_NOFS);
crc = checksums = kzalloc(sizeof(u32) * num_checksums, GFP_NOFS);
if (!crc) { if (!crc) {
iput(inode); iput(inode);
return 0; return 0;
} }
pages = kzalloc(sizeof(struct page *) * num_pages, GFP_NOFS);
if (!pages) {
kfree(crc);
iput(inode);
return 0;
}
/* Since the first page has all of our checksums and our generation we /* Since the first page has all of our checksums and our generation we
* need to calculate the offset into the page that we can start writing * need to calculate the offset into the page that we can start writing
* our entries. * our entries.
*/ */
first_page_offset = (sizeof(u32) * num_checksums) + sizeof(u64); first_page_offset = (sizeof(u32) * num_pages) + sizeof(u64);
/* Get the cluster for this block_group if it exists */ /* Get the cluster for this block_group if it exists */
if (!list_empty(&block_group->cluster_list)) if (!list_empty(&block_group->cluster_list))
...@@ -590,20 +598,18 @@ int btrfs_write_out_cache(struct btrfs_root *root, ...@@ -590,20 +598,18 @@ int btrfs_write_out_cache(struct btrfs_root *root,
* after find_get_page at this point. Just putting this here so people * after find_get_page at this point. Just putting this here so people
* know and don't freak out. * know and don't freak out.
*/ */
while (index <= last_index) { while (index < num_pages) {
page = grab_cache_page(inode->i_mapping, index); page = grab_cache_page(inode->i_mapping, index);
if (!page) { if (!page) {
pgoff_t i = 0; int i;
while (i < index) { for (i = 0; i < num_pages; i++) {
page = find_get_page(inode->i_mapping, i); unlock_page(pages[i]);
unlock_page(page); page_cache_release(pages[i]);
page_cache_release(page);
page_cache_release(page);
i++;
} }
goto out_free; goto out_free;
} }
pages[index] = page;
index++; index++;
} }
...@@ -631,7 +637,12 @@ int btrfs_write_out_cache(struct btrfs_root *root, ...@@ -631,7 +637,12 @@ int btrfs_write_out_cache(struct btrfs_root *root,
offset = start_offset; offset = start_offset;
} }
page = find_get_page(inode->i_mapping, index); if (index >= num_pages) {
out_of_space = true;
break;
}
page = pages[index];
addr = kmap(page); addr = kmap(page);
entry = addr + start_offset; entry = addr + start_offset;
...@@ -708,23 +719,6 @@ int btrfs_write_out_cache(struct btrfs_root *root, ...@@ -708,23 +719,6 @@ int btrfs_write_out_cache(struct btrfs_root *root,
bytes += PAGE_CACHE_SIZE; bytes += PAGE_CACHE_SIZE;
ClearPageChecked(page);
set_page_extent_mapped(page);
SetPageUptodate(page);
set_page_dirty(page);
/*
* We need to release our reference we got for grab_cache_page,
* except for the first page which will hold our checksums, we
* do that below.
*/
if (index != 0) {
unlock_page(page);
page_cache_release(page);
}
page_cache_release(page);
index++; index++;
} while (node || next_page); } while (node || next_page);
...@@ -734,6 +728,10 @@ int btrfs_write_out_cache(struct btrfs_root *root, ...@@ -734,6 +728,10 @@ int btrfs_write_out_cache(struct btrfs_root *root,
struct btrfs_free_space *entry = struct btrfs_free_space *entry =
list_entry(pos, struct btrfs_free_space, list); list_entry(pos, struct btrfs_free_space, list);
if (index >= num_pages) {
out_of_space = true;
break;
}
page = find_get_page(inode->i_mapping, index); page = find_get_page(inode->i_mapping, index);
addr = kmap(page); addr = kmap(page);
...@@ -745,64 +743,58 @@ int btrfs_write_out_cache(struct btrfs_root *root, ...@@ -745,64 +743,58 @@ int btrfs_write_out_cache(struct btrfs_root *root,
crc++; crc++;
bytes += PAGE_CACHE_SIZE; bytes += PAGE_CACHE_SIZE;
ClearPageChecked(page);
set_page_extent_mapped(page);
SetPageUptodate(page);
set_page_dirty(page);
unlock_page(page);
page_cache_release(page);
page_cache_release(page);
list_del_init(&entry->list); list_del_init(&entry->list);
index++; index++;
} }
if (out_of_space) {
btrfs_drop_pages(pages, num_pages);
unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0,
i_size_read(inode) - 1, &cached_state,
GFP_NOFS);
ret = 0;
goto out_free;
}
/* Zero out the rest of the pages just to make sure */ /* Zero out the rest of the pages just to make sure */
while (index <= last_index) { while (index < num_pages) {
void *addr; void *addr;
page = find_get_page(inode->i_mapping, index); page = pages[index];
addr = kmap(page); addr = kmap(page);
memset(addr, 0, PAGE_CACHE_SIZE); memset(addr, 0, PAGE_CACHE_SIZE);
kunmap(page); kunmap(page);
ClearPageChecked(page);
set_page_extent_mapped(page);
SetPageUptodate(page);
set_page_dirty(page);
unlock_page(page);
page_cache_release(page);
page_cache_release(page);
bytes += PAGE_CACHE_SIZE; bytes += PAGE_CACHE_SIZE;
index++; index++;
} }
btrfs_set_extent_delalloc(inode, 0, bytes - 1, &cached_state);
/* Write the checksums and trans id to the first page */ /* Write the checksums and trans id to the first page */
{ {
void *addr; void *addr;
u64 *gen; u64 *gen;
page = find_get_page(inode->i_mapping, 0); page = pages[0];
addr = kmap(page); addr = kmap(page);
memcpy(addr, checksums, sizeof(u32) * num_checksums); memcpy(addr, checksums, sizeof(u32) * num_pages);
gen = addr + (sizeof(u32) * num_checksums); gen = addr + (sizeof(u32) * num_pages);
*gen = trans->transid; *gen = trans->transid;
kunmap(page); kunmap(page);
ClearPageChecked(page);
set_page_extent_mapped(page);
SetPageUptodate(page);
set_page_dirty(page);
unlock_page(page);
page_cache_release(page);
page_cache_release(page);
} }
BTRFS_I(inode)->generation = trans->transid;
ret = btrfs_dirty_pages(root, inode, pages, num_pages, 0,
bytes, &cached_state);
btrfs_drop_pages(pages, num_pages);
unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0, unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0,
i_size_read(inode) - 1, &cached_state, GFP_NOFS); i_size_read(inode) - 1, &cached_state, GFP_NOFS);
if (ret) {
ret = 0;
goto out_free;
}
BTRFS_I(inode)->generation = trans->transid;
filemap_write_and_wait(inode->i_mapping); filemap_write_and_wait(inode->i_mapping);
key.objectid = BTRFS_FREE_SPACE_OBJECTID; key.objectid = BTRFS_FREE_SPACE_OBJECTID;
...@@ -853,6 +845,7 @@ int btrfs_write_out_cache(struct btrfs_root *root, ...@@ -853,6 +845,7 @@ int btrfs_write_out_cache(struct btrfs_root *root,
BTRFS_I(inode)->generation = 0; BTRFS_I(inode)->generation = 0;
} }
kfree(checksums); kfree(checksums);
kfree(pages);
btrfs_update_inode(trans, root, inode); btrfs_update_inode(trans, root, inode);
iput(inode); iput(inode);
return ret; return ret;
......
...@@ -1769,9 +1769,12 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) ...@@ -1769,9 +1769,12 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
add_pending_csums(trans, inode, ordered_extent->file_offset, add_pending_csums(trans, inode, ordered_extent->file_offset,
&ordered_extent->list); &ordered_extent->list);
btrfs_ordered_update_i_size(inode, 0, ordered_extent); ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
ret = btrfs_update_inode(trans, root, inode); if (!ret) {
BUG_ON(ret); ret = btrfs_update_inode(trans, root, inode);
BUG_ON(ret);
}
ret = 0;
out: out:
if (nolock) { if (nolock) {
if (trans) if (trans)
...@@ -2589,6 +2592,13 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, ...@@ -2589,6 +2592,13 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
struct btrfs_inode_item *item, struct btrfs_inode_item *item,
struct inode *inode) struct inode *inode)
{ {
if (!leaf->map_token)
map_private_extent_buffer(leaf, (unsigned long)item,
sizeof(struct btrfs_inode_item),
&leaf->map_token, &leaf->kaddr,
&leaf->map_start, &leaf->map_len,
KM_USER1);
btrfs_set_inode_uid(leaf, item, inode->i_uid); btrfs_set_inode_uid(leaf, item, inode->i_uid);
btrfs_set_inode_gid(leaf, item, inode->i_gid); btrfs_set_inode_gid(leaf, item, inode->i_gid);
btrfs_set_inode_size(leaf, item, BTRFS_I(inode)->disk_i_size); btrfs_set_inode_size(leaf, item, BTRFS_I(inode)->disk_i_size);
...@@ -2617,6 +2627,11 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, ...@@ -2617,6 +2627,11 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
btrfs_set_inode_rdev(leaf, item, inode->i_rdev); btrfs_set_inode_rdev(leaf, item, inode->i_rdev);
btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags); btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags);
btrfs_set_inode_block_group(leaf, item, BTRFS_I(inode)->block_group); btrfs_set_inode_block_group(leaf, item, BTRFS_I(inode)->block_group);
if (leaf->map_token) {
unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
leaf->map_token = NULL;
}
} }
/* /*
...@@ -5433,17 +5448,30 @@ struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *pag ...@@ -5433,17 +5448,30 @@ struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *pag
} }
static struct extent_map *btrfs_new_extent_direct(struct inode *inode, static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
struct extent_map *em,
u64 start, u64 len) u64 start, u64 len)
{ {
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
struct extent_map *em;
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
struct btrfs_key ins; struct btrfs_key ins;
u64 alloc_hint; u64 alloc_hint;
int ret; int ret;
bool insert = false;
btrfs_drop_extent_cache(inode, start, start + len - 1, 0); /*
* Ok if the extent map we looked up is a hole and is for the exact
* range we want, there is no reason to allocate a new one, however if
* it is not right then we need to free this one and drop the cache for
* our range.
*/
if (em->block_start != EXTENT_MAP_HOLE || em->start != start ||
em->len != len) {
free_extent_map(em);
em = NULL;
insert = true;
btrfs_drop_extent_cache(inode, start, start + len - 1, 0);
}
trans = btrfs_join_transaction(root, 0); trans = btrfs_join_transaction(root, 0);
if (IS_ERR(trans)) if (IS_ERR(trans))
...@@ -5459,10 +5487,12 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, ...@@ -5459,10 +5487,12 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
goto out; goto out;
} }
em = alloc_extent_map(GFP_NOFS);
if (!em) { if (!em) {
em = ERR_PTR(-ENOMEM); em = alloc_extent_map(GFP_NOFS);
goto out; if (!em) {
em = ERR_PTR(-ENOMEM);
goto out;
}
} }
em->start = start; em->start = start;
...@@ -5472,9 +5502,15 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, ...@@ -5472,9 +5502,15 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
em->block_start = ins.objectid; em->block_start = ins.objectid;
em->block_len = ins.offset; em->block_len = ins.offset;
em->bdev = root->fs_info->fs_devices->latest_bdev; em->bdev = root->fs_info->fs_devices->latest_bdev;
/*
* We need to do this because if we're using the original em we searched
* for, we could have EXTENT_FLAG_VACANCY set, and we don't want that.
*/
em->flags = 0;
set_bit(EXTENT_FLAG_PINNED, &em->flags); set_bit(EXTENT_FLAG_PINNED, &em->flags);
while (1) { while (insert) {
write_lock(&em_tree->lock); write_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em); ret = add_extent_mapping(em_tree, em);
write_unlock(&em_tree->lock); write_unlock(&em_tree->lock);
...@@ -5692,8 +5728,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, ...@@ -5692,8 +5728,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
* it above * it above
*/ */
len = bh_result->b_size; len = bh_result->b_size;
free_extent_map(em); em = btrfs_new_extent_direct(inode, em, start, len);
em = btrfs_new_extent_direct(inode, start, len);
if (IS_ERR(em)) if (IS_ERR(em))
return PTR_ERR(em); return PTR_ERR(em);
len = min(len, em->len - (start - em->start)); len = min(len, em->len - (start - em->start));
...@@ -5856,8 +5891,10 @@ static void btrfs_endio_direct_write(struct bio *bio, int err) ...@@ -5856,8 +5891,10 @@ static void btrfs_endio_direct_write(struct bio *bio, int err)
} }
add_pending_csums(trans, inode, ordered->file_offset, &ordered->list); add_pending_csums(trans, inode, ordered->file_offset, &ordered->list);
btrfs_ordered_update_i_size(inode, 0, ordered); ret = btrfs_ordered_update_i_size(inode, 0, ordered);
btrfs_update_inode(trans, root, inode); if (!ret)
btrfs_update_inode(trans, root, inode);
ret = 0;
out_unlock: out_unlock:
unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset, unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset,
ordered->file_offset + ordered->len - 1, ordered->file_offset + ordered->len - 1,
...@@ -5943,7 +5980,7 @@ static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev, ...@@ -5943,7 +5980,7 @@ static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev,
static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
int rw, u64 file_offset, int skip_sum, int rw, u64 file_offset, int skip_sum,
u32 *csums) u32 *csums, int async_submit)
{ {
int write = rw & REQ_WRITE; int write = rw & REQ_WRITE;
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
...@@ -5954,13 +5991,24 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, ...@@ -5954,13 +5991,24 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
if (ret) if (ret)
goto err; goto err;
if (write && !skip_sum) { if (skip_sum)
goto map;
if (write && async_submit) {
ret = btrfs_wq_submit_bio(root->fs_info, ret = btrfs_wq_submit_bio(root->fs_info,
inode, rw, bio, 0, 0, inode, rw, bio, 0, 0,
file_offset, file_offset,
__btrfs_submit_bio_start_direct_io, __btrfs_submit_bio_start_direct_io,
__btrfs_submit_bio_done); __btrfs_submit_bio_done);
goto err; goto err;
} else if (write) {
/*
* If we aren't doing async submit, calculate the csum of the
* bio now.
*/
ret = btrfs_csum_one_bio(root, inode, bio, file_offset, 1);
if (ret)
goto err;
} else if (!skip_sum) { } else if (!skip_sum) {
ret = btrfs_lookup_bio_sums_dio(root, inode, bio, ret = btrfs_lookup_bio_sums_dio(root, inode, bio,
file_offset, csums); file_offset, csums);
...@@ -5968,7 +6016,8 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, ...@@ -5968,7 +6016,8 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
goto err; goto err;
} }
ret = btrfs_map_bio(root, rw, bio, 0, 1); map:
ret = btrfs_map_bio(root, rw, bio, 0, async_submit);
err: err:
bio_put(bio); bio_put(bio);
return ret; return ret;
...@@ -5990,15 +6039,9 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, ...@@ -5990,15 +6039,9 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
int nr_pages = 0; int nr_pages = 0;
u32 *csums = dip->csums; u32 *csums = dip->csums;
int ret = 0; int ret = 0;
int async_submit = 0;
int write = rw & REQ_WRITE; int write = rw & REQ_WRITE;
bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS);
if (!bio)
return -ENOMEM;
bio->bi_private = dip;
bio->bi_end_io = btrfs_end_dio_bio;
atomic_inc(&dip->pending_bios);
map_length = orig_bio->bi_size; map_length = orig_bio->bi_size;
ret = btrfs_map_block(map_tree, READ, start_sector << 9, ret = btrfs_map_block(map_tree, READ, start_sector << 9,
&map_length, NULL, 0); &map_length, NULL, 0);
...@@ -6007,6 +6050,19 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, ...@@ -6007,6 +6050,19 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
return -EIO; return -EIO;
} }
if (map_length >= orig_bio->bi_size) {
bio = orig_bio;
goto submit;
}
async_submit = 1;
bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS);
if (!bio)
return -ENOMEM;
bio->bi_private = dip;
bio->bi_end_io = btrfs_end_dio_bio;
atomic_inc(&dip->pending_bios);
while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) { while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) {
if (unlikely(map_length < submit_len + bvec->bv_len || if (unlikely(map_length < submit_len + bvec->bv_len ||
bio_add_page(bio, bvec->bv_page, bvec->bv_len, bio_add_page(bio, bvec->bv_page, bvec->bv_len,
...@@ -6020,7 +6076,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, ...@@ -6020,7 +6076,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
atomic_inc(&dip->pending_bios); atomic_inc(&dip->pending_bios);
ret = __btrfs_submit_dio_bio(bio, inode, rw, ret = __btrfs_submit_dio_bio(bio, inode, rw,
file_offset, skip_sum, file_offset, skip_sum,
csums); csums, async_submit);
if (ret) { if (ret) {
bio_put(bio); bio_put(bio);
atomic_dec(&dip->pending_bios); atomic_dec(&dip->pending_bios);
...@@ -6057,8 +6113,9 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, ...@@ -6057,8 +6113,9 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
} }
} }
submit:
ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum, ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum,
csums); csums, async_submit);
if (!ret) if (!ret)
return 0; return 0;
......
...@@ -32,10 +32,8 @@ ...@@ -32,10 +32,8 @@
static noinline void put_transaction(struct btrfs_transaction *transaction) static noinline void put_transaction(struct btrfs_transaction *transaction)
{ {
WARN_ON(transaction->use_count == 0); WARN_ON(atomic_read(&transaction->use_count) == 0);
transaction->use_count--; if (atomic_dec_and_test(&transaction->use_count)) {
if (transaction->use_count == 0) {
list_del_init(&transaction->list);
memset(transaction, 0, sizeof(*transaction)); memset(transaction, 0, sizeof(*transaction));
kmem_cache_free(btrfs_transaction_cachep, transaction); kmem_cache_free(btrfs_transaction_cachep, transaction);
} }
...@@ -60,14 +58,14 @@ static noinline int join_transaction(struct btrfs_root *root) ...@@ -60,14 +58,14 @@ static noinline int join_transaction(struct btrfs_root *root)
if (!cur_trans) if (!cur_trans)
return -ENOMEM; return -ENOMEM;
root->fs_info->generation++; root->fs_info->generation++;
cur_trans->num_writers = 1; atomic_set(&cur_trans->num_writers, 1);
cur_trans->num_joined = 0; cur_trans->num_joined = 0;
cur_trans->transid = root->fs_info->generation; cur_trans->transid = root->fs_info->generation;
init_waitqueue_head(&cur_trans->writer_wait); init_waitqueue_head(&cur_trans->writer_wait);
init_waitqueue_head(&cur_trans->commit_wait); init_waitqueue_head(&cur_trans->commit_wait);
cur_trans->in_commit = 0; cur_trans->in_commit = 0;
cur_trans->blocked = 0; cur_trans->blocked = 0;
cur_trans->use_count = 1; atomic_set(&cur_trans->use_count, 1);
cur_trans->commit_done = 0; cur_trans->commit_done = 0;
cur_trans->start_time = get_seconds(); cur_trans->start_time = get_seconds();
...@@ -88,7 +86,7 @@ static noinline int join_transaction(struct btrfs_root *root) ...@@ -88,7 +86,7 @@ static noinline int join_transaction(struct btrfs_root *root)
root->fs_info->running_transaction = cur_trans; root->fs_info->running_transaction = cur_trans;
spin_unlock(&root->fs_info->new_trans_lock); spin_unlock(&root->fs_info->new_trans_lock);
} else { } else {
cur_trans->num_writers++; atomic_inc(&cur_trans->num_writers);
cur_trans->num_joined++; cur_trans->num_joined++;
} }
...@@ -145,7 +143,7 @@ static void wait_current_trans(struct btrfs_root *root) ...@@ -145,7 +143,7 @@ static void wait_current_trans(struct btrfs_root *root)
cur_trans = root->fs_info->running_transaction; cur_trans = root->fs_info->running_transaction;
if (cur_trans && cur_trans->blocked) { if (cur_trans && cur_trans->blocked) {
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
cur_trans->use_count++; atomic_inc(&cur_trans->use_count);
while (1) { while (1) {
prepare_to_wait(&root->fs_info->transaction_wait, &wait, prepare_to_wait(&root->fs_info->transaction_wait, &wait,
TASK_UNINTERRUPTIBLE); TASK_UNINTERRUPTIBLE);
...@@ -181,6 +179,7 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, ...@@ -181,6 +179,7 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
{ {
struct btrfs_trans_handle *h; struct btrfs_trans_handle *h;
struct btrfs_transaction *cur_trans; struct btrfs_transaction *cur_trans;
int retries = 0;
int ret; int ret;
if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
...@@ -204,7 +203,7 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, ...@@ -204,7 +203,7 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
} }
cur_trans = root->fs_info->running_transaction; cur_trans = root->fs_info->running_transaction;
cur_trans->use_count++; atomic_inc(&cur_trans->use_count);
if (type != TRANS_JOIN_NOLOCK) if (type != TRANS_JOIN_NOLOCK)
mutex_unlock(&root->fs_info->trans_mutex); mutex_unlock(&root->fs_info->trans_mutex);
...@@ -224,10 +223,18 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, ...@@ -224,10 +223,18 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
if (num_items > 0) { if (num_items > 0) {
ret = btrfs_trans_reserve_metadata(h, root, num_items); ret = btrfs_trans_reserve_metadata(h, root, num_items);
if (ret == -EAGAIN) { if (ret == -EAGAIN && !retries) {
retries++;
btrfs_commit_transaction(h, root); btrfs_commit_transaction(h, root);
goto again; goto again;
} else if (ret == -EAGAIN) {
/*
* We have already retried and got EAGAIN, so really we
* don't have space, so set ret to -ENOSPC.
*/
ret = -ENOSPC;
} }
if (ret < 0) { if (ret < 0) {
btrfs_end_transaction(h, root); btrfs_end_transaction(h, root);
return ERR_PTR(ret); return ERR_PTR(ret);
...@@ -327,7 +334,7 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid) ...@@ -327,7 +334,7 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid)
goto out_unlock; /* nothing committing|committed */ goto out_unlock; /* nothing committing|committed */
} }
cur_trans->use_count++; atomic_inc(&cur_trans->use_count);
mutex_unlock(&root->fs_info->trans_mutex); mutex_unlock(&root->fs_info->trans_mutex);
wait_for_commit(root, cur_trans); wait_for_commit(root, cur_trans);
...@@ -457,18 +464,14 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, ...@@ -457,18 +464,14 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
wake_up_process(info->transaction_kthread); wake_up_process(info->transaction_kthread);
} }
if (lock)
mutex_lock(&info->trans_mutex);
WARN_ON(cur_trans != info->running_transaction); WARN_ON(cur_trans != info->running_transaction);
WARN_ON(cur_trans->num_writers < 1); WARN_ON(atomic_read(&cur_trans->num_writers) < 1);
cur_trans->num_writers--; atomic_dec(&cur_trans->num_writers);
smp_mb(); smp_mb();
if (waitqueue_active(&cur_trans->writer_wait)) if (waitqueue_active(&cur_trans->writer_wait))
wake_up(&cur_trans->writer_wait); wake_up(&cur_trans->writer_wait);
put_transaction(cur_trans); put_transaction(cur_trans);
if (lock)
mutex_unlock(&info->trans_mutex);
if (current->journal_info == trans) if (current->journal_info == trans)
current->journal_info = NULL; current->journal_info = NULL;
...@@ -1178,7 +1181,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, ...@@ -1178,7 +1181,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
/* take transaction reference */ /* take transaction reference */
mutex_lock(&root->fs_info->trans_mutex); mutex_lock(&root->fs_info->trans_mutex);
cur_trans = trans->transaction; cur_trans = trans->transaction;
cur_trans->use_count++; atomic_inc(&cur_trans->use_count);
mutex_unlock(&root->fs_info->trans_mutex); mutex_unlock(&root->fs_info->trans_mutex);
btrfs_end_transaction(trans, root); btrfs_end_transaction(trans, root);
...@@ -1237,7 +1240,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -1237,7 +1240,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
mutex_lock(&root->fs_info->trans_mutex); mutex_lock(&root->fs_info->trans_mutex);
if (cur_trans->in_commit) { if (cur_trans->in_commit) {
cur_trans->use_count++; atomic_inc(&cur_trans->use_count);
mutex_unlock(&root->fs_info->trans_mutex); mutex_unlock(&root->fs_info->trans_mutex);
btrfs_end_transaction(trans, root); btrfs_end_transaction(trans, root);
...@@ -1259,7 +1262,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -1259,7 +1262,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
prev_trans = list_entry(cur_trans->list.prev, prev_trans = list_entry(cur_trans->list.prev,
struct btrfs_transaction, list); struct btrfs_transaction, list);
if (!prev_trans->commit_done) { if (!prev_trans->commit_done) {
prev_trans->use_count++; atomic_inc(&prev_trans->use_count);
mutex_unlock(&root->fs_info->trans_mutex); mutex_unlock(&root->fs_info->trans_mutex);
wait_for_commit(root, prev_trans); wait_for_commit(root, prev_trans);
...@@ -1300,14 +1303,14 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -1300,14 +1303,14 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
TASK_UNINTERRUPTIBLE); TASK_UNINTERRUPTIBLE);
smp_mb(); smp_mb();
if (cur_trans->num_writers > 1) if (atomic_read(&cur_trans->num_writers) > 1)
schedule_timeout(MAX_SCHEDULE_TIMEOUT); schedule_timeout(MAX_SCHEDULE_TIMEOUT);
else if (should_grow) else if (should_grow)
schedule_timeout(1); schedule_timeout(1);
mutex_lock(&root->fs_info->trans_mutex); mutex_lock(&root->fs_info->trans_mutex);
finish_wait(&cur_trans->writer_wait, &wait); finish_wait(&cur_trans->writer_wait, &wait);
} while (cur_trans->num_writers > 1 || } while (atomic_read(&cur_trans->num_writers) > 1 ||
(should_grow && cur_trans->num_joined != joined)); (should_grow && cur_trans->num_joined != joined));
ret = create_pending_snapshots(trans, root->fs_info); ret = create_pending_snapshots(trans, root->fs_info);
...@@ -1394,6 +1397,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -1394,6 +1397,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
wake_up(&cur_trans->commit_wait); wake_up(&cur_trans->commit_wait);
list_del_init(&cur_trans->list);
put_transaction(cur_trans); put_transaction(cur_trans);
put_transaction(cur_trans); put_transaction(cur_trans);
......
...@@ -27,11 +27,11 @@ struct btrfs_transaction { ...@@ -27,11 +27,11 @@ struct btrfs_transaction {
* total writers in this transaction, it must be zero before the * total writers in this transaction, it must be zero before the
* transaction can end * transaction can end
*/ */
unsigned long num_writers; atomic_t num_writers;
unsigned long num_joined; unsigned long num_joined;
int in_commit; int in_commit;
int use_count; atomic_t use_count;
int commit_done; int commit_done;
int blocked; int blocked;
struct list_head list; struct list_head list;
......
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