Re: [f2fs-dev] [PATCH 2/2] f2fs: support data compression

From: Jaegeuk Kim
Date: Mon Nov 25 2019 - 12:42:09 EST


Fix having my additional fixes:

---
fs/f2fs/compress.c | 114 ++++++++++++++++++--------------
fs/f2fs/data.c | 158 ++++++++++++++++++++++++++++++---------------
fs/f2fs/f2fs.h | 29 +++++++--
fs/f2fs/file.c | 25 +++----
fs/f2fs/inode.c | 7 +-
fs/f2fs/namei.c | 7 +-
6 files changed, 208 insertions(+), 132 deletions(-)

diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index e9f633c30942..7ebd2bc018bd 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -8,6 +8,7 @@
#include <linux/fs.h>
#include <linux/f2fs_fs.h>
#include <linux/writeback.h>
+#include <linux/backing-dev.h>
#include <linux/lzo.h>
#include <linux/lz4.h>

@@ -86,15 +87,13 @@ int f2fs_init_compress_ctx(struct compress_ctx *cc)

cc->rpages = f2fs_kzalloc(sbi, sizeof(struct page *) <<
cc->log_cluster_size, GFP_NOFS);
- if (!cc->rpages)
- return -ENOMEM;
- return 0;
+ return cc->rpages ? 0 : -ENOMEM;
}

void f2fs_destroy_compress_ctx(struct compress_ctx *cc)
{
- f2fs_reset_compress_ctx(cc);
kfree(cc->rpages);
+ f2fs_reset_compress_ctx(cc);
}

void f2fs_compress_ctx_add_page(struct compress_ctx *cc, struct page *page)
@@ -378,7 +377,7 @@ void f2fs_decompress_pages(struct bio *bio, struct page *page, bool verity)

dec_page_count(sbi, F2FS_RD_DATA);

- if (bio->bi_status)
+ if (bio->bi_status || PageError(page))
dic->failed = true;

if (refcount_dec_not_one(&dic->ref))
@@ -420,10 +419,14 @@ void f2fs_decompress_pages(struct bio *bio, struct page *page, bool verity)
out_vunmap_rbuf:
vunmap(dic->rbuf);
out_free_dic:
- f2fs_set_cluster_uptodate(dic->rpages, dic->cluster_size, ret, verity);
+ if (!verity)
+ f2fs_decompress_end_io(dic->rpages, dic->cluster_size,
+ ret, false);
+
trace_f2fs_decompress_pages_end(dic->inode, dic->cluster_idx,
- dic->clen, ret);
- f2fs_free_dic(dic);
+ dic->clen, ret);
+ if (!verity)
+ f2fs_free_dic(dic);
}

static bool is_page_in_cluster(struct compress_ctx *cc, pgoff_t index)
@@ -470,22 +473,18 @@ static bool __cluster_may_compress(struct compress_ctx *cc)
/* beyond EOF */
if (page->index >= nr_pages)
return false;
- if (page->index != start_idx_of_cluster(cc) + i)
- return false;
}
return true;
}

-int is_compressed_cluster(struct compress_ctx *cc, pgoff_t index)
+static int is_compressed_cluster(struct compress_ctx *cc)
{
struct dnode_of_data dn;
- unsigned int start_idx = cluster_idx(cc, index) <<
- cc->log_cluster_size;
int ret;
- int i;

set_new_dnode(&dn, cc->inode, NULL, NULL, 0);
- ret = f2fs_get_dnode_of_data(&dn, start_idx, LOOKUP_NODE);
+ ret = f2fs_get_dnode_of_data(&dn, start_idx_of_cluster(cc),
+ LOOKUP_NODE);
if (ret) {
if (ret == -ENOENT)
ret = 0;
@@ -493,6 +492,8 @@ int is_compressed_cluster(struct compress_ctx *cc, pgoff_t index)
}

if (dn.data_blkaddr == COMPRESS_ADDR) {
+ int i;
+
ret = CLUSTER_IS_FULL;
for (i = 1; i < cc->cluster_size; i++) {
block_t blkaddr;
@@ -516,9 +517,10 @@ int f2fs_is_compressed_cluster(struct inode *inode, pgoff_t index)
.inode = inode,
.log_cluster_size = F2FS_I(inode)->i_log_cluster_size,
.cluster_size = F2FS_I(inode)->i_cluster_size,
+ .cluster_idx = index >> F2FS_I(inode)->i_log_cluster_size,
};

- return is_compressed_cluster(&cc, index);
+ return is_compressed_cluster(&cc);
}

static bool cluster_may_compress(struct compress_ctx *cc)
@@ -536,6 +538,7 @@ static bool cluster_may_compress(struct compress_ctx *cc)

void f2fs_reset_compress_ctx(struct compress_ctx *cc)
{
+ cc->rpages = NULL;
cc->nr_rpages = 0;
cc->nr_cpages = 0;
cc->cluster_idx = NULL_CLUSTER;
@@ -565,19 +568,18 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
bool prealloc)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(cc->inode);
- struct bio *bio = NULL;
struct address_space *mapping = cc->inode->i_mapping;
struct page *page;
struct dnode_of_data dn;
sector_t last_block_in_bio;
unsigned fgp_flag = FGP_LOCK | FGP_WRITE | FGP_CREAT;
- unsigned int start_idx = cluster_idx(cc, index) << cc->log_cluster_size;
+ unsigned int start_idx = start_idx_of_cluster(cc);
int i, idx;
int ret;

ret = f2fs_init_compress_ctx(cc);
if (ret)
- goto out;
+ return ret;
retry:
/* keep page reference to avoid page reclaim */
for (i = 0; i < cc->cluster_size; i++) {
@@ -588,26 +590,25 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
goto unlock_pages;
}

- if (PageUptodate(page)) {
+ if (PageUptodate(page))
unlock_page(page);
- continue;
- }
-
- f2fs_compress_ctx_add_page(cc, page);
+ else
+ f2fs_compress_ctx_add_page(cc, page);
}

if (!f2fs_cluster_is_empty(cc)) {
+ struct bio *bio = NULL;
+
ret = f2fs_read_multi_pages(cc, &bio, cc->cluster_size,
&last_block_in_bio, false);
if (ret)
- goto out;
-
+ return ret;
if (bio)
f2fs_submit_bio(sbi, bio, DATA);

ret = f2fs_init_compress_ctx(cc);
if (ret)
- goto out;
+ return ret;
}

for (i = 0; i < cc->cluster_size; i++) {
@@ -620,10 +621,12 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
f2fs_put_page(page, 0);

if (!PageUptodate(page)) {
- for (idx = i; idx >= 0; idx--) {
- f2fs_put_page(cc->rpages[idx], 0);
- f2fs_put_page(cc->rpages[idx], 1);
+ for (idx = 0; idx < cc->cluster_size; idx++) {
+ f2fs_put_page(cc->rpages[idx],
+ (idx <= i) ? 1 : 0);
+ cc->rpages[idx] = NULL;
}
+ cc->nr_rpages = 0;
goto retry;
}
}
@@ -658,11 +661,10 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
release_pages:
for (idx = 0; idx < i; idx++) {
page = find_lock_page(mapping, start_idx + idx);
- f2fs_put_page(page, 0);
f2fs_put_page(page, 1);
+ f2fs_put_page(page, 0);
}
f2fs_destroy_compress_ctx(cc);
-out:
return ret;
}

@@ -671,12 +673,13 @@ int f2fs_prepare_compress_overwrite(struct inode *inode,
{
struct compress_ctx cc = {
.inode = inode,
+ .log_cluster_size = F2FS_I(inode)->i_log_cluster_size,
.cluster_size = F2FS_I(inode)->i_cluster_size,
- .cluster_idx = NULL_CLUSTER,
+ .cluster_idx = index >> F2FS_I(inode)->i_log_cluster_size,
.rpages = NULL,
.nr_rpages = 0,
};
- int ret = is_compressed_cluster(&cc, index);
+ int ret = is_compressed_cluster(&cc);

if (ret <= 0)
return ret;
@@ -687,7 +690,7 @@ int f2fs_prepare_compress_overwrite(struct inode *inode,
}

bool f2fs_compress_write_end(struct inode *inode, void *fsdata,
- pgoff_t index, bool written)
+ pgoff_t index, unsigned copied)

{
struct compress_ctx cc = {
@@ -698,7 +701,7 @@ bool f2fs_compress_write_end(struct inode *inode, void *fsdata,
bool first_index = (index == cc.rpages[0]->index);
int i;

- if (written)
+ if (copied)
set_cluster_dirty(&cc);

for (i = 0; i < cc.cluster_size; i++)
@@ -707,7 +710,6 @@ bool f2fs_compress_write_end(struct inode *inode, void *fsdata,
f2fs_destroy_compress_ctx(&cc);

return first_index;
-
}

static int f2fs_write_compressed_pages(struct compress_ctx *cc,
@@ -857,6 +859,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
fi->last_disk_size = psize;
up_write(&fi->i_sem);
}
+ f2fs_reset_compress_ctx(cc);
return 0;

out_destroy_crypt:
@@ -904,7 +907,8 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page)
static int f2fs_write_raw_pages(struct compress_ctx *cc,
int *submitted,
struct writeback_control *wbc,
- enum iostat_type io_type)
+ enum iostat_type io_type,
+ bool compressed)
{
int i, _submitted;
int ret, err = 0;
@@ -912,12 +916,24 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,
for (i = 0; i < cc->cluster_size; i++) {
if (!cc->rpages[i])
continue;
+retry_write:
BUG_ON(!PageLocked(cc->rpages[i]));
+
ret = f2fs_write_single_data_page(cc->rpages[i], &_submitted,
- NULL, NULL, wbc, io_type);
+ NULL, NULL, wbc, io_type,
+ compressed);
if (ret) {
- if (ret == AOP_WRITEPAGE_ACTIVATE)
+ if (ret == AOP_WRITEPAGE_ACTIVATE) {
unlock_page(cc->rpages[i]);
+ ret = 0;
+ } else if (ret == -EAGAIN) {
+ ret = 0;
+ cond_resched();
+ congestion_wait(BLK_RW_ASYNC, HZ/50);
+ lock_page(cc->rpages[i]);
+ clear_page_dirty_for_io(cc->rpages[i]);
+ goto retry_write;
+ }
err = ret;
goto out_fail;
}
@@ -928,6 +944,8 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,

out_fail:
/* TODO: revoke partially updated block addresses */
+ BUG_ON(compressed);
+
for (++i; i < cc->cluster_size; i++) {
if (!cc->rpages[i])
continue;
@@ -948,7 +966,6 @@ int f2fs_write_multi_pages(struct compress_ctx *cc,
int err = -EAGAIN;

*submitted = 0;
-
if (cluster_may_compress(cc)) {
err = f2fs_compress_pages(cc);
if (err) {
@@ -964,18 +981,19 @@ int f2fs_write_multi_pages(struct compress_ctx *cc,
bool compressed = false;

f2fs_bug_on(F2FS_I_SB(cc->inode), *submitted);
- if (is_compressed_cluster(cc, start_idx_of_cluster(cc)))
+
+ if (is_compressed_cluster(cc))
compressed = true;

- err = f2fs_write_raw_pages(cc, submitted, wbc, io_type);
+ err = f2fs_write_raw_pages(cc, submitted, wbc,
+ io_type, compressed);
if (compressed) {
stat_sub_compr_blocks(cc->inode, *submitted);
F2FS_I(cc->inode)->i_compressed_blocks -= *submitted;
f2fs_mark_inode_dirty_sync(cc->inode, true);
}
+ f2fs_destroy_compress_ctx(cc);
}
-
- f2fs_reset_compress_ctx(cc);
return err;
}

@@ -988,8 +1006,9 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc)

dic = f2fs_kzalloc(sbi, sizeof(struct decompress_io_ctx), GFP_NOFS);
if (!dic)
- goto out;
+ return ERR_PTR(-ENOMEM);

+ dic->magic = F2FS_COMPRESSED_PAGE_MAGIC;
dic->inode = cc->inode;
refcount_set(&dic->ref, 1);
dic->cluster_idx = cc->cluster_idx;
@@ -1042,7 +1061,6 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc)

out_free:
f2fs_free_dic(dic);
-out:
return ERR_PTR(-ENOMEM);
}

@@ -1073,7 +1091,7 @@ void f2fs_free_dic(struct decompress_io_ctx *dic)
kfree(dic);
}

-void f2fs_set_cluster_uptodate(struct page **rpages,
+void f2fs_decompress_end_io(struct page **rpages,
unsigned int cluster_size, bool err, bool verity)
{
int i;
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index c10cbd7d1c06..fcdd6d493f83 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -98,7 +98,7 @@ static void __read_end_io(struct bio *bio, bool compr, bool verity)
page = bv->bv_page;

#ifdef CONFIG_F2FS_FS_COMPRESSION
- if (compr && PagePrivate(page)) {
+ if (compr && f2fs_is_compressed_page(page)) {
f2fs_decompress_pages(bio, page, verity);
continue;
}
@@ -115,9 +115,14 @@ static void __read_end_io(struct bio *bio, bool compr, bool verity)
dec_page_count(F2FS_P_SB(page), __read_io_type(page));
unlock_page(page);
}
- if (bio->bi_private)
- mempool_free(bio->bi_private, bio_post_read_ctx_pool);
- bio_put(bio);
+}
+
+static void f2fs_release_read_bio(struct bio *bio);
+static void __f2fs_read_end_io(struct bio *bio, bool compr, bool verity)
+{
+ if (!compr)
+ __read_end_io(bio, false, verity);
+ f2fs_release_read_bio(bio);
}

static void f2fs_decompress_bio(struct bio *bio, bool verity)
@@ -127,19 +132,45 @@ static void f2fs_decompress_bio(struct bio *bio, bool verity)

static void bio_post_read_processing(struct bio_post_read_ctx *ctx);

-static void decrypt_work(struct bio_post_read_ctx *ctx)
+static void f2fs_decrypt_work(struct bio_post_read_ctx *ctx)
{
fscrypt_decrypt_bio(ctx->bio);
}

-static void decompress_work(struct bio_post_read_ctx *ctx, bool verity)
+static void f2fs_decompress_work(struct bio_post_read_ctx *ctx)
{
- f2fs_decompress_bio(ctx->bio, verity);
+ f2fs_decompress_bio(ctx->bio, ctx->enabled_steps & (1 << STEP_VERITY));
}

-static void verity_work(struct bio_post_read_ctx *ctx)
+#ifdef CONFIG_F2FS_FS_COMPRESSION
+static void f2fs_verify_bio(struct bio *bio)
{
+ struct page *page = bio_first_page_all(bio);
+ struct decompress_io_ctx *dic =
+ (struct decompress_io_ctx *)page_private(page);
+
+ f2fs_decompress_end_io(dic->rpages, dic->cluster_size, false, true);
+ f2fs_free_dic(dic);
+}
+#endif
+
+static void f2fs_verity_work(struct work_struct *work)
+{
+ struct bio_post_read_ctx *ctx =
+ container_of(work, struct bio_post_read_ctx, work);
+
+#ifdef CONFIG_F2FS_FS_COMPRESSION
+ /* previous step is decompression */
+ if (ctx->enabled_steps & (1 << STEP_DECOMPRESS)) {
+
+ f2fs_verify_bio(ctx->bio);
+ f2fs_release_read_bio(ctx->bio);
+ return;
+ }
+#endif
+
fsverity_verify_bio(ctx->bio);
+ __f2fs_read_end_io(ctx->bio, false, false);
}

static void f2fs_post_read_work(struct work_struct *work)
@@ -148,18 +179,19 @@ static void f2fs_post_read_work(struct work_struct *work)
container_of(work, struct bio_post_read_ctx, work);

if (ctx->enabled_steps & (1 << STEP_DECRYPT))
- decrypt_work(ctx);
+ f2fs_decrypt_work(ctx);

- if (ctx->enabled_steps & (1 << STEP_DECOMPRESS)) {
- decompress_work(ctx,
- ctx->enabled_steps & (1 << STEP_VERITY));
+ if (ctx->enabled_steps & (1 << STEP_DECOMPRESS))
+ f2fs_decompress_work(ctx);
+
+ if (ctx->enabled_steps & (1 << STEP_VERITY)) {
+ INIT_WORK(&ctx->work, f2fs_verity_work);
+ fsverity_enqueue_verify_work(&ctx->work);
return;
}

- if (ctx->enabled_steps & (1 << STEP_VERITY))
- verity_work(ctx);
-
- __read_end_io(ctx->bio, false, false);
+ __f2fs_read_end_io(ctx->bio,
+ ctx->enabled_steps & (1 << STEP_DECOMPRESS), false);
}

static void f2fs_enqueue_post_read_work(struct f2fs_sb_info *sbi,
@@ -176,12 +208,20 @@ static void bio_post_read_processing(struct bio_post_read_ctx *ctx)
* we shouldn't recurse to the same workqueue.
*/

- if (ctx->enabled_steps) {
+ if (ctx->enabled_steps & (1 << STEP_DECRYPT) ||
+ ctx->enabled_steps & (1 << STEP_DECOMPRESS)) {
INIT_WORK(&ctx->work, f2fs_post_read_work);
f2fs_enqueue_post_read_work(ctx->sbi, &ctx->work);
return;
}
- __read_end_io(ctx->bio, false, false);
+
+ if (ctx->enabled_steps & (1 << STEP_VERITY)) {
+ INIT_WORK(&ctx->work, f2fs_verity_work);
+ fsverity_enqueue_verify_work(&ctx->work);
+ return;
+ }
+
+ __f2fs_read_end_io(ctx->bio, false, false);
}

static bool f2fs_bio_post_read_required(struct bio *bio)
@@ -205,7 +245,7 @@ static void f2fs_read_end_io(struct bio *bio)
return;
}

- __read_end_io(bio, false, false);
+ __f2fs_read_end_io(bio, false, false);
}

static void f2fs_write_end_io(struct bio *bio)
@@ -624,7 +664,8 @@ static int add_ipu_page(struct f2fs_sb_info *sbi, struct bio **bio,

found = true;

- if (bio_add_page(*bio, page, PAGE_SIZE, 0) == PAGE_SIZE) {
+ if (bio_add_page(*bio, page, PAGE_SIZE, 0) ==
+ PAGE_SIZE) {
ret = 0;
break;
}
@@ -858,6 +899,13 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
return bio;
}

+static void f2fs_release_read_bio(struct bio *bio)
+{
+ if (bio->bi_private)
+ mempool_free(bio->bi_private, bio_post_read_ctx_pool);
+ bio_put(bio);
+}
+
/* This can handle encryption stuffs */
static int f2fs_submit_page_read(struct inode *inode, struct page *page,
block_t blkaddr)
@@ -1963,7 +2011,8 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
if (ret)
goto out;

- f2fs_bug_on(sbi, dn.data_blkaddr != COMPRESS_ADDR);
+ if (dn.data_blkaddr != COMPRESS_ADDR)
+ goto out;

for (i = 1; i < cc->cluster_size; i++) {
block_t blkaddr;
@@ -2017,7 +2066,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
dic->failed = true;
if (refcount_sub_and_test(dic->nr_cpages - i,
&dic->ref))
- f2fs_set_cluster_uptodate(dic->rpages,
+ f2fs_decompress_end_io(dic->rpages,
cc->cluster_size, true,
false);
f2fs_free_dic(dic);
@@ -2047,8 +2096,8 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
out_put_dnode:
f2fs_put_dnode(&dn);
out:
- f2fs_set_cluster_uptodate(cc->rpages, cc->cluster_size, true, false);
- f2fs_reset_compress_ctx(cc);
+ f2fs_decompress_end_io(cc->rpages, cc->cluster_size, true, false);
+ f2fs_destroy_compress_ctx(cc);
*bio_ret = bio;
return ret;
}
@@ -2443,7 +2492,8 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
struct bio **bio,
sector_t *last_block,
struct writeback_control *wbc,
- enum iostat_type io_type)
+ enum iostat_type io_type,
+ bool compressed)
{
struct inode *inode = page->mapping->host;
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
@@ -2488,8 +2538,9 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
goto redirty_out;

- if (f2fs_compressed_file(inode) ||
- page->index < end_index || f2fs_verity_in_progress(inode))
+ if (page->index < end_index ||
+ f2fs_verity_in_progress(inode) ||
+ compressed)
goto write;

/*
@@ -2610,7 +2661,7 @@ static int f2fs_write_data_page(struct page *page,
#endif

return f2fs_write_single_data_page(page, NULL, NULL, NULL,
- wbc, FS_DATA_IO);
+ wbc, FS_DATA_IO, false);
}

/*
@@ -2696,17 +2747,12 @@ static int f2fs_write_cache_pages(struct address_space *mapping,

for (i = 0; i < nr_pages; i++) {
struct page *page = pvec.pages[i];
- bool need_readd = false;
-
+ bool need_readd;
readd:
#ifdef CONFIG_F2FS_FS_COMPRESSION
need_readd = false;

if (f2fs_compressed_file(inode)) {
- void *fsdata = NULL;
- struct page *pagep;
- int ret2;
-
ret = f2fs_init_compress_ctx(&cc);
if (ret) {
done = 1;
@@ -2715,7 +2761,6 @@ static int f2fs_write_cache_pages(struct address_space *mapping,

if (!f2fs_cluster_can_merge_page(&cc,
page->index)) {
-
ret = f2fs_write_multi_pages(&cc,
&submitted, wbc, io_type);
if (!ret)
@@ -2724,6 +2769,10 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
}

if (f2fs_cluster_is_empty(&cc)) {
+ void *fsdata = NULL;
+ struct page *pagep;
+ int ret2;
+
ret2 = f2fs_prepare_compress_overwrite(
inode, &pagep,
page->index, &fsdata);
@@ -2733,24 +2782,27 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
break;
} else if (ret2 &&
!f2fs_compress_write_end(inode,
- fsdata, page->index,
- true)) {
+ fsdata, page->index,
+ 1)) {
retry = 1;
break;
}
+ } else {
+ goto lock_page;
}
}
#endif
-
/* give a priority to WB_SYNC threads */
if (atomic_read(&sbi->wb_sync_req[DATA]) &&
wbc->sync_mode == WB_SYNC_NONE) {
done = 1;
break;
}
-
+#ifdef CONFIG_F2FS_FS_COMPRESSION
+lock_page:
+#endif
done_index = page->index;
-
+retry_write:
lock_page(page);

if (unlikely(page->mapping != mapping)) {
@@ -2782,7 +2834,7 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
}
#endif
ret = f2fs_write_single_data_page(page, &submitted,
- &bio, &last_block, wbc, io_type);
+ &bio, &last_block, wbc, io_type, false);
if (ret == AOP_WRITEPAGE_ACTIVATE)
unlock_page(page);
#ifdef CONFIG_F2FS_FS_COMPRESSION
@@ -2801,6 +2853,12 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
goto next;
} else if (ret == -EAGAIN) {
ret = 0;
+ if (wbc->sync_mode == WB_SYNC_ALL) {
+ cond_resched();
+ congestion_wait(BLK_RW_ASYNC,
+ HZ/50);
+ goto retry_write;
+ }
goto next;
}
done_index = page->index + 1;
@@ -2817,21 +2875,21 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
if (need_readd)
goto readd;
}
-
pagevec_release(&pvec);
cond_resched();
}
-
#ifdef CONFIG_F2FS_FS_COMPRESSION
/* flush remained pages in compress cluster */
if (f2fs_compressed_file(inode) && !f2fs_cluster_is_empty(&cc)) {
ret = f2fs_write_multi_pages(&cc, &submitted, wbc, io_type);
nwritten += submitted;
wbc->nr_to_write -= submitted;
- /* TODO: error handling */
+ if (ret) {
+ done = 1;
+ retry = 0;
+ }
}
#endif
-
if ((!cycled && !done) || retry) {
cycled = 1;
index = 0;
@@ -3606,14 +3664,8 @@ static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,
if (ret)
return ret;

- if (f2fs_compressed_file(inode)) {
- if (F2FS_I(inode)->i_compressed_blocks)
- return -EINVAL;
-
- F2FS_I(inode)->i_flags &= ~FS_COMPR_FL;
- clear_inode_flag(inode, FI_COMPRESSED_FILE);
- stat_dec_compr_inode(inode);
- }
+ if (f2fs_disable_compressed_file(inode))
+ return -EINVAL;

ret = check_swap_activate(file, sis->max);
if (ret)
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 11c42042367b..ee7309ca671a 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1253,6 +1253,7 @@ struct compress_io_ctx {

/* decompress io context for read IO path */
struct decompress_io_ctx {
+ u32 magic; /* magic number to indicate page is compressed */
struct inode *inode; /* inode the context belong to */
unsigned int cluster_idx; /* cluster index number */
unsigned int cluster_size; /* page count in cluster */
@@ -2737,6 +2738,8 @@ static inline void set_compress_context(struct inode *inode)
F2FS_OPTION(sbi).compress_log_size;
F2FS_I(inode)->i_cluster_size =
1 << F2FS_I(inode)->i_log_cluster_size;
+ F2FS_I(inode)->i_flags |= F2FS_COMPR_FL;
+ set_inode_flag(inode, FI_COMPRESSED_FILE);
}

static inline unsigned int addrs_per_inode(struct inode *inode)
@@ -3390,7 +3393,8 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio);
int f2fs_write_single_data_page(struct page *page, int *submitted,
struct bio **bio, sector_t *last_block,
struct writeback_control *wbc,
- enum iostat_type io_type);
+ enum iostat_type io_type,
+ bool compressed);
void f2fs_invalidate_page(struct page *page, unsigned int offset,
unsigned int length);
int f2fs_release_page(struct page *page, gfp_t wait);
@@ -3631,8 +3635,8 @@ void f2fs_destroy_root_stats(void);
#define stat_dec_inline_dir(inode) do { } while (0)
#define stat_inc_compr_inode(inode) do { } while (0)
#define stat_dec_compr_inode(inode) do { } while (0)
-#define stat_add_compr_blocks(inode) do { } while (0)
-#define stat_sub_compr_blocks(inode) do { } while (0)
+#define stat_add_compr_blocks(inode, blocks) do { } while (0)
+#define stat_sub_compr_blocks(inode, blocks) do { } while (0)
#define stat_inc_atomic_write(inode) do { } while (0)
#define stat_dec_atomic_write(inode) do { } while (0)
#define stat_update_max_atomic_write(inode) do { } while (0)
@@ -3786,7 +3790,7 @@ void f2fs_reset_compress_ctx(struct compress_ctx *cc);
int f2fs_prepare_compress_overwrite(struct inode *inode,
struct page **pagep, pgoff_t index, void **fsdata);
bool f2fs_compress_write_end(struct inode *inode, void *fsdata,
- pgoff_t index, bool written);
+ pgoff_t index, unsigned copied);
void f2fs_compress_write_end_io(struct bio *bio, struct page *page);
bool f2fs_is_compress_backend_ready(struct inode *inode);
void f2fs_decompress_pages(struct bio *bio, struct page *page, bool verity);
@@ -3803,7 +3807,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
bool is_readahead);
struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc);
void f2fs_free_dic(struct decompress_io_ctx *dic);
-void f2fs_set_cluster_uptodate(struct page **rpages,
+void f2fs_decompress_end_io(struct page **rpages,
unsigned int cluster_size, bool err, bool verity);
int f2fs_init_compress_ctx(struct compress_ctx *cc);
void f2fs_destroy_compress_ctx(struct compress_ctx *cc);
@@ -3824,6 +3828,21 @@ static inline struct page *f2fs_compress_control_page(struct page *page)
}
#endif

+static inline u64 f2fs_disable_compressed_file(struct inode *inode)
+{
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+
+ if (!f2fs_compressed_file(inode))
+ return 0;
+ if (fi->i_compressed_blocks)
+ return fi->i_compressed_blocks;
+
+ fi->i_flags &= ~F2FS_COMPR_FL;
+ clear_inode_flag(inode, FI_COMPRESSED_FILE);
+ stat_dec_compr_inode(inode);
+ return 0;
+}
+
#define F2FS_FEATURE_FUNCS(name, flagname) \
static inline int f2fs_sb_has_##name(struct f2fs_sb_info *sbi) \
{ \
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index a688a4cb212b..4163fc3db1a3 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -523,6 +523,9 @@ static int f2fs_file_open(struct inode *inode, struct file *filp)
if (err)
return err;

+ if (!f2fs_is_compress_backend_ready(inode))
+ return -EOPNOTSUPP;
+
err = fsverity_file_open(inode, filp);
if (err)
return err;
@@ -1821,7 +1824,6 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
return -EINVAL;

set_compress_context(inode);
- set_inode_flag(inode, FI_COMPRESSED_FILE);
stat_inc_compr_inode(inode);
}
}
@@ -2016,11 +2018,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)

inode_lock(inode);

- if (f2fs_compressed_file(inode) && !fi->i_compressed_blocks) {
- fi->i_flags &= ~F2FS_COMPR_FL;
- clear_inode_flag(inode, FI_COMPRESSED_FILE);
- stat_dec_compr_inode(inode);
- }
+ f2fs_disable_compressed_file(inode);

if (f2fs_is_atomic_file(inode)) {
if (is_inode_flag_set(inode, FI_ATOMIC_REVOKE_REQUEST))
@@ -3224,20 +3222,15 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
goto out;
}

- if (f2fs_compressed_file(inode)) {
- if (F2FS_I(inode)->i_compressed_blocks) {
- ret = -EOPNOTSUPP;
- goto out;
- }
- F2FS_I(inode)->i_flags &= ~F2FS_COMPR_FL;
- clear_inode_flag(inode, FI_COMPRESSED_FILE);
- stat_dec_compr_inode(inode);
- }
-
ret = f2fs_convert_inline_inode(inode);
if (ret)
goto out;

+ if (f2fs_disable_compressed_file(inode)) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
set_inode_flag(inode, FI_PIN_FILE);
ret = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN];
done:
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 7a85060adad5..3fa728f40c2a 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -421,7 +421,8 @@ static int do_read_inode(struct inode *inode)
fi->i_crtime.tv_nsec = le32_to_cpu(ri->i_crtime_nsec);
}

- if (f2fs_has_extra_attr(inode) && f2fs_sb_has_compression(sbi)) {
+ if (f2fs_has_extra_attr(inode) && f2fs_sb_has_compression(sbi) &&
+ (fi->i_flags & F2FS_COMPR_FL)) {
if (F2FS_FITS_IN_INODE(ri, fi->i_extra_isize,
i_log_cluster_size)) {
fi->i_compressed_blocks =
@@ -429,10 +430,8 @@ static int do_read_inode(struct inode *inode)
fi->i_compress_algorithm = ri->i_compress_algorithm;
fi->i_log_cluster_size = ri->i_log_cluster_size;
fi->i_cluster_size = 1 << fi->i_log_cluster_size;
- }
-
- if ((fi->i_flags & F2FS_COMPR_FL) && f2fs_may_compress(inode))
set_inode_flag(inode, FI_COMPRESSED_FILE);
+ }
}

F2FS_I(inode)->i_disk_time[0] = inode->i_atime;
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 00c56a3e944b..ac6b1f946e03 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -122,11 +122,8 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
if (f2fs_sb_has_compression(sbi)) {
/* Inherit the compression flag in directory */
if ((F2FS_I(dir)->i_flags & F2FS_COMPR_FL) &&
- f2fs_may_compress(inode)) {
+ f2fs_may_compress(inode))
set_compress_context(inode);
- F2FS_I(inode)->i_flags |= F2FS_COMPR_FL;
- set_inode_flag(inode, FI_COMPRESSED_FILE);
- }
}

f2fs_set_inode_flags(inode);
@@ -309,9 +306,7 @@ static void set_compress_inode(struct f2fs_sb_info *sbi, struct inode *inode,
if (!is_extension_exist(name, ext[i]))
continue;

- F2FS_I(inode)->i_flags |= F2FS_COMPR_FL;
set_compress_context(inode);
- set_inode_flag(inode, FI_COMPRESSED_FILE);
return;
}
}
--
2.19.0.605.g01d371f741-goog