Re: [RFC PATCH v2 5/5] btrfs: implement RWF_ENCODED writes
flat view
From: Omar Sandoval <osandov@osandov.com>
Date: 2019-10-18 23:33:06
Also in:
linux-btrfs, linux-fsdevel
On Fri, Oct 18, 2019 at 03:55:13PM -0700, Omar Sandoval wrote:
On Wed, Oct 16, 2019 at 01:44:56PM +0300, Nikolay Borisov wrote:quoted
On 15.10.19 г. 21:42 ч., Omar Sandoval wrote:quoted
From: Omar Sandoval <redacted> The implementation resembles direct I/O: we have to flush any ordered extents, invalidate the page cache, and do the io tree/delalloc/extent map/ordered extent dance. From there, we can reuse the compression code with a minor modification to distinguish the write from writeback. Now that read and write are implemented, this also sets the FMODE_ENCODED_IO flag in btrfs_file_open(). Signed-off-by: Omar Sandoval <redacted> --- fs/btrfs/compression.c | 6 +- fs/btrfs/compression.h | 5 +- fs/btrfs/ctree.h | 2 + fs/btrfs/file.c | 40 +++++++-- fs/btrfs/inode.c | 197 ++++++++++++++++++++++++++++++++++++++++- 5 files changed, 237 insertions(+), 13 deletions(-)
[snip]
quoted
quoted
+ for (;;) { + struct btrfs_ordered_extent *ordered; + + ret = btrfs_wait_ordered_range(inode, start, end - start + 1); + if (ret) + goto out_pages; + ret = invalidate_inode_pages2_range(inode->i_mapping, + start >> PAGE_SHIFT, + end >> PAGE_SHIFT); + if (ret) + goto out_pages; + lock_extent_bits(io_tree, start, end, &cached_state); + ordered = btrfs_lookup_ordered_range(BTRFS_I(inode), start, + end - start + 1); + if (!ordered && + !filemap_range_has_page(inode->i_mapping, start, end)) + break; + if (ordered) + btrfs_put_ordered_extent(ordered); + unlock_extent_cached(io_tree, start, end, &cached_state); + cond_resched(); + } + + ret = btrfs_delalloc_reserve_space(inode, &data_reserved, start, + num_bytes); + if (ret) + goto out_unlock; + + ret = btrfs_reserve_extent(root, num_bytes, disk_num_bytes, + disk_num_bytes, 0, 0, &ins, 1, 1); + if (ret) + goto out_delalloc_release; + + em = create_io_em(inode, start, num_bytes, start, ins.objectid, + ins.offset, ins.offset, num_bytes, compression, + BTRFS_ORDERED_COMPRESSED); + if (IS_ERR(em)) { + ret = PTR_ERR(em); + goto out_free_reserve; + } + free_extent_map(em); + + ret = btrfs_add_ordered_extent_compress(inode, start, ins.objectid, + num_bytes, ins.offset, + BTRFS_ORDERED_COMPRESSED, + compression); + if (ret) { + btrfs_drop_extent_cache(BTRFS_I(inode), start, end, 0); + goto out_free_reserve; + } + btrfs_dec_block_group_reservations(fs_info, ins.objectid); + + if (start + encoded->len > inode->i_size) + i_size_write(inode, start + encoded->len);Don't we want the inode size to be updated once data hits disk and btrfs_finish_ordered_io is called?Yup, you're right, this is too early.
Actually, no, this part is fine. Compare to the call to i_size_write() in btrfs_get_blocks_direct_write(): we lock the extent in the io_tree, create the ordered extent, update i_size, then unlock the extent. Anyone else who comes in is going to find the ordered extent and wait on that.
quoted
quoted
+ + unlock_extent_cached(io_tree, start, end, &cached_state); + + btrfs_delalloc_release_extents(BTRFS_I(inode), num_bytes, false); + + if (btrfs_submit_compressed_write(inode, start, num_bytes, ins.objectid, + ins.offset, pages, nr_pages, 0, + false)) { + struct page *page = pages[0]; + + page->mapping = inode->i_mapping; + btrfs_writepage_endio_finish_ordered(page, start, end, 0); + page->mapping = NULL; + ret = -EIO; + goto out_pages; + }I also need to wait for the I/O to finish here.quoted
quoted
+ iocb->ki_pos += encoded->len; + return orig_count; + +out_free_reserve: + btrfs_dec_block_group_reservations(fs_info, ins.objectid); + btrfs_free_reserved_extent(fs_info, ins.objectid, ins.offset, 1); +out_delalloc_release: + btrfs_delalloc_release_space(inode, data_reserved, start, num_bytes, + true); +out_unlock: + unlock_extent_cached(io_tree, start, end, &cached_state); +out_pages: + for (i = 0; i < nr_pages; i++) { + if (pages[i]) + put_page(pages[i]); + } + kvfree(pages); + return ret; +} + #ifdef CONFIG_SWAP /* * Add an entry indicating a block group or device which is pinned by a