Commit e94e54e8 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by David Sterba

btrfs: streamline compress_file_range

Reorder compress_file_range so that the main compression flow happens
straight line and not in branches.  To do this ensure that pages is
always zeroed before a page allocation happens, which allows the
cleanup_and_bail_uncompressed label to clean up the page allocations
as needed.
Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 00d31d17
...@@ -839,10 +839,11 @@ static void compress_file_range(struct btrfs_work *work) ...@@ -839,10 +839,11 @@ static void compress_file_range(struct btrfs_work *work)
u64 actual_end; u64 actual_end;
u64 i_size; u64 i_size;
int ret = 0; int ret = 0;
struct page **pages = NULL; struct page **pages;
unsigned long nr_pages; unsigned long nr_pages;
unsigned long total_compressed = 0; unsigned long total_compressed = 0;
unsigned long total_in = 0; unsigned long total_in = 0;
unsigned int poff;
int i; int i;
int will_compress; int will_compress;
int compress_type = fs_info->compress_type; int compress_type = fs_info->compress_type;
...@@ -865,6 +866,7 @@ static void compress_file_range(struct btrfs_work *work) ...@@ -865,6 +866,7 @@ static void compress_file_range(struct btrfs_work *work)
actual_end = min_t(u64, i_size, end + 1); actual_end = min_t(u64, i_size, end + 1);
again: again:
will_compress = 0; will_compress = 0;
pages = NULL;
nr_pages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1; nr_pages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1;
nr_pages = min_t(unsigned long, nr_pages, BTRFS_MAX_COMPRESSED_PAGES); nr_pages = min_t(unsigned long, nr_pages, BTRFS_MAX_COMPRESSED_PAGES);
...@@ -908,66 +910,64 @@ static void compress_file_range(struct btrfs_work *work) ...@@ -908,66 +910,64 @@ static void compress_file_range(struct btrfs_work *work)
ret = 0; ret = 0;
/* /*
* we do compression for mount -o compress and when the * We do compression for mount -o compress and when the inode has not
* inode has not been flagged as nocompress. This flag can * been flagged as NOCOMPRESS. This flag can change at any time if we
* change at any time if we discover bad compression ratios. * discover bad compression ratios.
*/ */
if (inode_need_compress(inode, start, end)) { if (!inode_need_compress(inode, start, end))
WARN_ON(pages); goto cont;
pages = kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
if (!pages) {
/* just bail out to the uncompressed code */
nr_pages = 0;
goto cont;
}
if (inode->defrag_compress)
compress_type = inode->defrag_compress;
else if (inode->prop_compress)
compress_type = inode->prop_compress;
pages = kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
if (!pages) {
/* /*
* we need to call clear_page_dirty_for_io on each * Memory allocation failure is not a fatal error, we can fall
* page in the range. Otherwise applications with the file * back to uncompressed code.
* mmap'd can wander in and change the page contents while
* we are compressing them.
*
* If the compression fails for any reason, we set the pages
* dirty again later on.
*
* Note that the remaining part is redirtied, the start pointer
* has moved, the end is the original one.
*/ */
if (!redirty) { nr_pages = 0;
extent_range_clear_dirty_for_io(&inode->vfs_inode, start, end); goto cont;
redirty = 1; }
}
/* Compression level is applied here and only here */
ret = btrfs_compress_pages(
compress_type | (fs_info->compress_level << 4),
mapping, start,
pages,
&nr_pages,
&total_in,
&total_compressed);
if (!ret) { if (inode->defrag_compress)
unsigned long offset = offset_in_page(total_compressed); compress_type = inode->defrag_compress;
struct page *page = pages[nr_pages - 1]; else if (inode->prop_compress)
compress_type = inode->prop_compress;
/* zero the tail end of the last page, we might be /*
* sending it down to disk * We need to call clear_page_dirty_for_io on each page in the range.
*/ * Otherwise applications with the file mmap'd can wander in and change
if (offset) * the page contents while we are compressing them.
memzero_page(page, offset, PAGE_SIZE - offset); *
will_compress = 1; * If the compression fails for any reason, we set the pages dirty again
} * later on.
*
* Note that the remaining part is redirtied, the start pointer has
* moved, the end is the original one.
*/
if (!redirty) {
extent_range_clear_dirty_for_io(&inode->vfs_inode, start, end);
redirty = 1;
} }
/* Compression level is applied here. */
ret = btrfs_compress_pages(compress_type | (fs_info->compress_level << 4),
mapping, start, pages, &nr_pages, &total_in,
&total_compressed);
if (ret)
goto cont;
/*
* Zero the tail end of the last page, as we might be sending it down
* to disk.
*/
poff = offset_in_page(total_compressed);
if (poff)
memzero_page(pages[nr_pages - 1], poff, PAGE_SIZE - poff);
will_compress = 1;
cont: cont:
/* /*
* Check cow_file_range() for why we don't even try to create inline * Check cow_file_range() for why we don't even try to create inline
* extent for subpage case. * extent for the subpage case.
*/ */
if (start == 0 && fs_info->sectorsize == PAGE_SIZE) { if (start == 0 && fs_info->sectorsize == PAGE_SIZE) {
/* lets try to make an inline extent */ /* lets try to make an inline extent */
...@@ -1026,39 +1026,38 @@ static void compress_file_range(struct btrfs_work *work) ...@@ -1026,39 +1026,38 @@ static void compress_file_range(struct btrfs_work *work)
} }
} }
if (will_compress) { if (!will_compress)
/* goto cleanup_and_bail_uncompressed;
* we aren't doing an inline extent round the compressed size
* up to a block size boundary so the allocator does sane
* things
*/
total_compressed = ALIGN(total_compressed, blocksize);
/* /*
* one last check to make sure the compression is really a * We aren't doing an inline extent. Round the compressed size up to a
* win, compare the page count read with the blocks on disk, * block size boundary so the allocator does sane things.
* compression must free at least one sector size */
*/ total_compressed = ALIGN(total_compressed, blocksize);
total_in = round_up(total_in, fs_info->sectorsize);
if (total_compressed + blocksize <= total_in) { /*
/* * One last check to make sure the compression is really a win, compare
* The async work queues will take care of doing actual * the page count read with the blocks on disk, compression must free at
* allocation on disk for these compressed pages, and * least one sector.
* will submit them to the elevator. */
*/ total_in = round_up(total_in, fs_info->sectorsize);
add_async_extent(async_chunk, start, total_in, if (total_compressed + blocksize > total_in)
total_compressed, pages, nr_pages, goto cleanup_and_bail_uncompressed;
compress_type);
/*
if (start + total_in < end) { * The async work queues will take care of doing actual allocation on
start += total_in; * disk for these compressed pages, and will submit the bios.
pages = NULL; */
cond_resched(); add_async_extent(async_chunk, start, total_in, total_compressed, pages,
goto again; nr_pages, compress_type);
} if (start + total_in < end) {
return; start += total_in;
} cond_resched();
goto again;
} }
return;
cleanup_and_bail_uncompressed:
if (pages) { if (pages) {
/* /*
* the compression code ran but failed to make things smaller, * the compression code ran but failed to make things smaller,
...@@ -1079,7 +1078,7 @@ static void compress_file_range(struct btrfs_work *work) ...@@ -1079,7 +1078,7 @@ static void compress_file_range(struct btrfs_work *work)
inode->flags |= BTRFS_INODE_NOCOMPRESS; inode->flags |= BTRFS_INODE_NOCOMPRESS;
} }
} }
cleanup_and_bail_uncompressed:
/* /*
* No compression, but we still need to write the pages in the file * No compression, but we still need to write the pages in the file
* we've been given so far. redirty the locked page if it corresponds * we've been given so far. redirty the locked page if it corresponds
......
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