Loading fs/btrfs/ctree.h +5 −0 Original line number Diff line number Diff line Loading @@ -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, struct inode *inode, u64 start, u64 end); 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 */ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, Loading fs/btrfs/disk-io.c +1 −1 Original line number Diff line number Diff line Loading @@ -3136,7 +3136,7 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root) btrfs_destroy_pinned_extent(root, root->fs_info->pinned_extents); t->use_count = 0; atomic_set(&t->use_count, 0); list_del_init(&t->list); memset(t, 0, sizeof(*t)); kmem_cache_free(btrfs_transaction_cachep, t); Loading fs/btrfs/file.c +9 −12 Original line number Diff line number Diff line Loading @@ -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 */ 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; for (i = 0; i < num_pages; i++) { Loading @@ -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 * doing real data extents, marking pages dirty and delalloc as required. */ static noinline int dirty_and_release_pages(struct btrfs_root *root, struct file *file, struct page **pages, size_t num_pages, loff_t pos, size_t write_bytes) 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) { int err = 0; int i; struct inode *inode = fdentry(file)->d_inode; u64 num_bytes; u64 start_pos; u64 end_of_last_block; Loading @@ -149,7 +146,7 @@ static noinline int dirty_and_release_pages(struct btrfs_root *root, end_of_last_block = start_pos + num_bytes - 1; err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block, NULL); cached); if (err) return err; Loading Loading @@ -992,9 +989,9 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file, } if (copied > 0) { ret = dirty_and_release_pages(root, file, pages, dirty_pages, pos, copied); ret = btrfs_dirty_pages(root, inode, pages, dirty_pages, pos, copied, NULL); if (ret) { btrfs_delalloc_release_space(inode, dirty_pages << PAGE_CACHE_SHIFT); Loading fs/btrfs/free-space-cache.c +55 −62 Original line number Diff line number Diff line Loading @@ -508,6 +508,7 @@ int btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode; struct rb_node *node; struct list_head *pos, *n; struct page **pages; struct page *page; struct extent_state *cached_state = NULL; struct btrfs_free_cluster *cluster = NULL; Loading @@ -517,13 +518,13 @@ int btrfs_write_out_cache(struct btrfs_root *root, u64 start, end, len; u64 bytes = 0; u32 *crc, *checksums; pgoff_t index = 0, last_index = 0; unsigned long first_page_offset; int num_checksums; int index = 0, num_pages = 0; int entries = 0; int bitmaps = 0; int ret = 0; bool next_page = false; bool out_of_space = false; root = root->fs_info->tree_root; Loading Loading @@ -551,24 +552,31 @@ int btrfs_write_out_cache(struct btrfs_root *root, 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); btrfs_wait_ordered_range(inode, inode->i_size & ~(root->sectorsize - 1), (u64)-1); /* We need a checksum per page. */ num_checksums = i_size_read(inode) / PAGE_CACHE_SIZE; crc = checksums = kzalloc(sizeof(u32) * num_checksums, GFP_NOFS); crc = checksums = kzalloc(sizeof(u32) * num_pages, GFP_NOFS); if (!crc) { iput(inode); 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 * need to calculate the offset into the page that we can start writing * 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 */ if (!list_empty(&block_group->cluster_list)) Loading @@ -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 * know and don't freak out. */ while (index <= last_index) { while (index < num_pages) { page = grab_cache_page(inode->i_mapping, index); if (!page) { pgoff_t i = 0; int i; while (i < index) { page = find_get_page(inode->i_mapping, i); unlock_page(page); page_cache_release(page); page_cache_release(page); i++; for (i = 0; i < num_pages; i++) { unlock_page(pages[i]); page_cache_release(pages[i]); } goto out_free; } pages[index] = page; index++; } Loading Loading @@ -631,7 +637,12 @@ int btrfs_write_out_cache(struct btrfs_root *root, 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); entry = addr + start_offset; Loading Loading @@ -708,23 +719,6 @@ int btrfs_write_out_cache(struct btrfs_root *root, 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++; } while (node || next_page); Loading @@ -734,6 +728,10 @@ int btrfs_write_out_cache(struct btrfs_root *root, struct btrfs_free_space *entry = 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); addr = kmap(page); Loading @@ -745,64 +743,58 @@ int btrfs_write_out_cache(struct btrfs_root *root, crc++; 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); 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 */ while (index <= last_index) { while (index < num_pages) { void *addr; page = find_get_page(inode->i_mapping, index); page = pages[index]; addr = kmap(page); memset(addr, 0, PAGE_CACHE_SIZE); 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; index++; } btrfs_set_extent_delalloc(inode, 0, bytes - 1, &cached_state); /* Write the checksums and trans id to the first page */ { void *addr; u64 *gen; page = find_get_page(inode->i_mapping, 0); page = pages[0]; addr = kmap(page); memcpy(addr, checksums, sizeof(u32) * num_checksums); gen = addr + (sizeof(u32) * num_checksums); memcpy(addr, checksums, sizeof(u32) * num_pages); gen = addr + (sizeof(u32) * num_pages); *gen = trans->transid; 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, 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); key.objectid = BTRFS_FREE_SPACE_OBJECTID; Loading Loading @@ -853,6 +845,7 @@ int btrfs_write_out_cache(struct btrfs_root *root, BTRFS_I(inode)->generation = 0; } kfree(checksums); kfree(pages); btrfs_update_inode(trans, root, inode); iput(inode); return ret; Loading fs/btrfs/inode.c +82 −25 Original line number Diff line number Diff line Loading @@ -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, &ordered_extent->list); btrfs_ordered_update_i_size(inode, 0, ordered_extent); ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent); if (!ret) { ret = btrfs_update_inode(trans, root, inode); BUG_ON(ret); } ret = 0; out: if (nolock) { if (trans) Loading Loading @@ -2589,6 +2592,13 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, struct btrfs_inode_item *item, 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_gid(leaf, item, inode->i_gid); btrfs_set_inode_size(leaf, item, BTRFS_I(inode)->disk_i_size); Loading Loading @@ -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_flags(leaf, item, BTRFS_I(inode)->flags); 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; } } /* Loading Loading @@ -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, struct extent_map *em, u64 start, u64 len) { struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_trans_handle *trans; struct extent_map *em; struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; struct btrfs_key ins; u64 alloc_hint; int ret; bool insert = false; /* * 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); if (IS_ERR(trans)) Loading @@ -5459,11 +5487,13 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, goto out; } if (!em) { em = alloc_extent_map(GFP_NOFS); if (!em) { em = ERR_PTR(-ENOMEM); goto out; } } em->start = start; em->orig_start = em->start; Loading @@ -5472,9 +5502,15 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, em->block_start = ins.objectid; em->block_len = ins.offset; 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); while (1) { while (insert) { write_lock(&em_tree->lock); ret = add_extent_mapping(em_tree, em); write_unlock(&em_tree->lock); Loading Loading @@ -5692,8 +5728,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, * it above */ len = bh_result->b_size; free_extent_map(em); em = btrfs_new_extent_direct(inode, start, len); em = btrfs_new_extent_direct(inode, em, start, len); if (IS_ERR(em)) return PTR_ERR(em); len = min(len, em->len - (start - em->start)); Loading Loading @@ -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); btrfs_ordered_update_i_size(inode, 0, ordered); ret = btrfs_ordered_update_i_size(inode, 0, ordered); if (!ret) btrfs_update_inode(trans, root, inode); ret = 0; out_unlock: unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset, ordered->file_offset + ordered->len - 1, Loading Loading @@ -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, int rw, u64 file_offset, int skip_sum, u32 *csums) u32 *csums, int async_submit) { int write = rw & REQ_WRITE; struct btrfs_root *root = BTRFS_I(inode)->root; Loading @@ -5954,13 +5991,24 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, if (ret) goto err; if (write && !skip_sum) { if (skip_sum) goto map; if (write && async_submit) { ret = btrfs_wq_submit_bio(root->fs_info, inode, rw, bio, 0, 0, file_offset, __btrfs_submit_bio_start_direct_io, __btrfs_submit_bio_done); 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) { ret = btrfs_lookup_bio_sums_dio(root, inode, bio, file_offset, csums); Loading @@ -5968,7 +6016,8 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, goto err; } ret = btrfs_map_bio(root, rw, bio, 0, 1); map: ret = btrfs_map_bio(root, rw, bio, 0, async_submit); err: bio_put(bio); return ret; Loading @@ -5990,15 +6039,9 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, int nr_pages = 0; u32 *csums = dip->csums; int ret = 0; int async_submit = 0; 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; ret = btrfs_map_block(map_tree, READ, start_sector << 9, &map_length, NULL, 0); Loading @@ -6007,6 +6050,19 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, 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)) { if (unlikely(map_length < submit_len + bvec->bv_len || bio_add_page(bio, bvec->bv_page, bvec->bv_len, Loading @@ -6020,7 +6076,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, atomic_inc(&dip->pending_bios); ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum, csums); csums, async_submit); if (ret) { bio_put(bio); atomic_dec(&dip->pending_bios); Loading Loading @@ -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, csums); csums, async_submit); if (!ret) return 0; Loading Loading
fs/btrfs/ctree.h +5 −0 Original line number Diff line number Diff line Loading @@ -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, struct inode *inode, u64 start, u64 end); 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 */ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, Loading
fs/btrfs/disk-io.c +1 −1 Original line number Diff line number Diff line Loading @@ -3136,7 +3136,7 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root) btrfs_destroy_pinned_extent(root, root->fs_info->pinned_extents); t->use_count = 0; atomic_set(&t->use_count, 0); list_del_init(&t->list); memset(t, 0, sizeof(*t)); kmem_cache_free(btrfs_transaction_cachep, t); Loading
fs/btrfs/file.c +9 −12 Original line number Diff line number Diff line Loading @@ -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 */ 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; for (i = 0; i < num_pages; i++) { Loading @@ -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 * doing real data extents, marking pages dirty and delalloc as required. */ static noinline int dirty_and_release_pages(struct btrfs_root *root, struct file *file, struct page **pages, size_t num_pages, loff_t pos, size_t write_bytes) 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) { int err = 0; int i; struct inode *inode = fdentry(file)->d_inode; u64 num_bytes; u64 start_pos; u64 end_of_last_block; Loading @@ -149,7 +146,7 @@ static noinline int dirty_and_release_pages(struct btrfs_root *root, end_of_last_block = start_pos + num_bytes - 1; err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block, NULL); cached); if (err) return err; Loading Loading @@ -992,9 +989,9 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file, } if (copied > 0) { ret = dirty_and_release_pages(root, file, pages, dirty_pages, pos, copied); ret = btrfs_dirty_pages(root, inode, pages, dirty_pages, pos, copied, NULL); if (ret) { btrfs_delalloc_release_space(inode, dirty_pages << PAGE_CACHE_SHIFT); Loading
fs/btrfs/free-space-cache.c +55 −62 Original line number Diff line number Diff line Loading @@ -508,6 +508,7 @@ int btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode; struct rb_node *node; struct list_head *pos, *n; struct page **pages; struct page *page; struct extent_state *cached_state = NULL; struct btrfs_free_cluster *cluster = NULL; Loading @@ -517,13 +518,13 @@ int btrfs_write_out_cache(struct btrfs_root *root, u64 start, end, len; u64 bytes = 0; u32 *crc, *checksums; pgoff_t index = 0, last_index = 0; unsigned long first_page_offset; int num_checksums; int index = 0, num_pages = 0; int entries = 0; int bitmaps = 0; int ret = 0; bool next_page = false; bool out_of_space = false; root = root->fs_info->tree_root; Loading Loading @@ -551,24 +552,31 @@ int btrfs_write_out_cache(struct btrfs_root *root, 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); btrfs_wait_ordered_range(inode, inode->i_size & ~(root->sectorsize - 1), (u64)-1); /* We need a checksum per page. */ num_checksums = i_size_read(inode) / PAGE_CACHE_SIZE; crc = checksums = kzalloc(sizeof(u32) * num_checksums, GFP_NOFS); crc = checksums = kzalloc(sizeof(u32) * num_pages, GFP_NOFS); if (!crc) { iput(inode); 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 * need to calculate the offset into the page that we can start writing * 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 */ if (!list_empty(&block_group->cluster_list)) Loading @@ -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 * know and don't freak out. */ while (index <= last_index) { while (index < num_pages) { page = grab_cache_page(inode->i_mapping, index); if (!page) { pgoff_t i = 0; int i; while (i < index) { page = find_get_page(inode->i_mapping, i); unlock_page(page); page_cache_release(page); page_cache_release(page); i++; for (i = 0; i < num_pages; i++) { unlock_page(pages[i]); page_cache_release(pages[i]); } goto out_free; } pages[index] = page; index++; } Loading Loading @@ -631,7 +637,12 @@ int btrfs_write_out_cache(struct btrfs_root *root, 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); entry = addr + start_offset; Loading Loading @@ -708,23 +719,6 @@ int btrfs_write_out_cache(struct btrfs_root *root, 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++; } while (node || next_page); Loading @@ -734,6 +728,10 @@ int btrfs_write_out_cache(struct btrfs_root *root, struct btrfs_free_space *entry = 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); addr = kmap(page); Loading @@ -745,64 +743,58 @@ int btrfs_write_out_cache(struct btrfs_root *root, crc++; 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); 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 */ while (index <= last_index) { while (index < num_pages) { void *addr; page = find_get_page(inode->i_mapping, index); page = pages[index]; addr = kmap(page); memset(addr, 0, PAGE_CACHE_SIZE); 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; index++; } btrfs_set_extent_delalloc(inode, 0, bytes - 1, &cached_state); /* Write the checksums and trans id to the first page */ { void *addr; u64 *gen; page = find_get_page(inode->i_mapping, 0); page = pages[0]; addr = kmap(page); memcpy(addr, checksums, sizeof(u32) * num_checksums); gen = addr + (sizeof(u32) * num_checksums); memcpy(addr, checksums, sizeof(u32) * num_pages); gen = addr + (sizeof(u32) * num_pages); *gen = trans->transid; 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, 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); key.objectid = BTRFS_FREE_SPACE_OBJECTID; Loading Loading @@ -853,6 +845,7 @@ int btrfs_write_out_cache(struct btrfs_root *root, BTRFS_I(inode)->generation = 0; } kfree(checksums); kfree(pages); btrfs_update_inode(trans, root, inode); iput(inode); return ret; Loading
fs/btrfs/inode.c +82 −25 Original line number Diff line number Diff line Loading @@ -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, &ordered_extent->list); btrfs_ordered_update_i_size(inode, 0, ordered_extent); ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent); if (!ret) { ret = btrfs_update_inode(trans, root, inode); BUG_ON(ret); } ret = 0; out: if (nolock) { if (trans) Loading Loading @@ -2589,6 +2592,13 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, struct btrfs_inode_item *item, 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_gid(leaf, item, inode->i_gid); btrfs_set_inode_size(leaf, item, BTRFS_I(inode)->disk_i_size); Loading Loading @@ -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_flags(leaf, item, BTRFS_I(inode)->flags); 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; } } /* Loading Loading @@ -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, struct extent_map *em, u64 start, u64 len) { struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_trans_handle *trans; struct extent_map *em; struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; struct btrfs_key ins; u64 alloc_hint; int ret; bool insert = false; /* * 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); if (IS_ERR(trans)) Loading @@ -5459,11 +5487,13 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, goto out; } if (!em) { em = alloc_extent_map(GFP_NOFS); if (!em) { em = ERR_PTR(-ENOMEM); goto out; } } em->start = start; em->orig_start = em->start; Loading @@ -5472,9 +5502,15 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, em->block_start = ins.objectid; em->block_len = ins.offset; 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); while (1) { while (insert) { write_lock(&em_tree->lock); ret = add_extent_mapping(em_tree, em); write_unlock(&em_tree->lock); Loading Loading @@ -5692,8 +5728,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, * it above */ len = bh_result->b_size; free_extent_map(em); em = btrfs_new_extent_direct(inode, start, len); em = btrfs_new_extent_direct(inode, em, start, len); if (IS_ERR(em)) return PTR_ERR(em); len = min(len, em->len - (start - em->start)); Loading Loading @@ -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); btrfs_ordered_update_i_size(inode, 0, ordered); ret = btrfs_ordered_update_i_size(inode, 0, ordered); if (!ret) btrfs_update_inode(trans, root, inode); ret = 0; out_unlock: unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset, ordered->file_offset + ordered->len - 1, Loading Loading @@ -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, int rw, u64 file_offset, int skip_sum, u32 *csums) u32 *csums, int async_submit) { int write = rw & REQ_WRITE; struct btrfs_root *root = BTRFS_I(inode)->root; Loading @@ -5954,13 +5991,24 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, if (ret) goto err; if (write && !skip_sum) { if (skip_sum) goto map; if (write && async_submit) { ret = btrfs_wq_submit_bio(root->fs_info, inode, rw, bio, 0, 0, file_offset, __btrfs_submit_bio_start_direct_io, __btrfs_submit_bio_done); 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) { ret = btrfs_lookup_bio_sums_dio(root, inode, bio, file_offset, csums); Loading @@ -5968,7 +6016,8 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, goto err; } ret = btrfs_map_bio(root, rw, bio, 0, 1); map: ret = btrfs_map_bio(root, rw, bio, 0, async_submit); err: bio_put(bio); return ret; Loading @@ -5990,15 +6039,9 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, int nr_pages = 0; u32 *csums = dip->csums; int ret = 0; int async_submit = 0; 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; ret = btrfs_map_block(map_tree, READ, start_sector << 9, &map_length, NULL, 0); Loading @@ -6007,6 +6050,19 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, 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)) { if (unlikely(map_length < submit_len + bvec->bv_len || bio_add_page(bio, bvec->bv_page, bvec->bv_len, Loading @@ -6020,7 +6076,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, atomic_inc(&dip->pending_bios); ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum, csums); csums, async_submit); if (ret) { bio_put(bio); atomic_dec(&dip->pending_bios); Loading Loading @@ -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, csums); csums, async_submit); if (!ret) return 0; Loading