summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChao Yu <yuchao0@huawei.com>2020-03-18 16:22:59 +0800
committerJaegeuk Kim <jaegeuk@kernel.org>2020-05-08 06:55:56 -0700
commit3265d3db1f16395cfc6b8ea9b31b4001d98d05ef (patch)
treeb6ed34cd7bde862ad9061b811749a7abded16439 /fs
parentb5f4684b5f5fe6ea3c0d57acf5acdf8e8fbfe503 (diff)
downloadlinux-stable-3265d3db1f16395cfc6b8ea9b31b4001d98d05ef.tar.gz
linux-stable-3265d3db1f16395cfc6b8ea9b31b4001d98d05ef.tar.bz2
linux-stable-3265d3db1f16395cfc6b8ea9b31b4001d98d05ef.zip
f2fs: support partial truncation on compressed inode
Supports to truncate compressed/normal cluster partially on compressed inode. Signed-off-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/f2fs/compress.c49
-rw-r--r--fs/f2fs/f2fs.h2
-rw-r--r--fs/f2fs/file.c19
3 files changed, 65 insertions, 5 deletions
diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index 26b071afe48a..d6283e351c95 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -954,6 +954,55 @@ bool f2fs_compress_write_end(struct inode *inode, void *fsdata,
return first_index;
}
+int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock)
+{
+ void *fsdata = NULL;
+ struct page *pagep;
+ int log_cluster_size = F2FS_I(inode)->i_log_cluster_size;
+ pgoff_t start_idx = from >> (PAGE_SHIFT + log_cluster_size) <<
+ log_cluster_size;
+ int err;
+
+ err = f2fs_is_compressed_cluster(inode, start_idx);
+ if (err < 0)
+ return err;
+
+ /* truncate normal cluster */
+ if (!err)
+ return f2fs_do_truncate_blocks(inode, from, lock);
+
+ /* truncate compressed cluster */
+ err = f2fs_prepare_compress_overwrite(inode, &pagep,
+ start_idx, &fsdata);
+
+ /* should not be a normal cluster */
+ f2fs_bug_on(F2FS_I_SB(inode), err == 0);
+
+ if (err <= 0)
+ return err;
+
+ if (err > 0) {
+ struct page **rpages = fsdata;
+ int cluster_size = F2FS_I(inode)->i_cluster_size;
+ int i;
+
+ for (i = cluster_size - 1; i >= 0; i--) {
+ loff_t start = rpages[i]->index << PAGE_SHIFT;
+
+ if (from <= start) {
+ zero_user_segment(rpages[i], 0, PAGE_SIZE);
+ } else {
+ zero_user_segment(rpages[i], from - start,
+ PAGE_SIZE);
+ break;
+ }
+ }
+
+ f2fs_compress_write_end(inode, fsdata, start_idx, true);
+ }
+ return 0;
+}
+
static int f2fs_write_compressed_pages(struct compress_ctx *cc,
int *submitted,
struct writeback_control *wbc,
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index a3809b092798..cc7a7a0c02d6 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3105,6 +3105,7 @@ static inline void f2fs_clear_page_private(struct page *page)
*/
int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync);
void f2fs_truncate_data_blocks(struct dnode_of_data *dn);
+int f2fs_do_truncate_blocks(struct inode *inode, u64 from, bool lock);
int f2fs_truncate_blocks(struct inode *inode, u64 from, bool lock);
int f2fs_truncate(struct inode *inode);
int f2fs_getattr(const struct path *path, struct kstat *stat,
@@ -3825,6 +3826,7 @@ 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, unsigned copied);
+int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock);
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);
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index a0a4413d6083..175c66190087 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -647,9 +647,6 @@ static int truncate_partial_data_page(struct inode *inode, u64 from,
return 0;
}
- if (f2fs_compressed_file(inode))
- return 0;
-
page = f2fs_get_lock_data_page(inode, index, true);
if (IS_ERR(page))
return PTR_ERR(page) == -ENOENT ? 0 : PTR_ERR(page);
@@ -665,7 +662,7 @@ truncate_out:
return 0;
}
-static int do_truncate_blocks(struct inode *inode, u64 from, bool lock)
+int f2fs_do_truncate_blocks(struct inode *inode, u64 from, bool lock)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct dnode_of_data dn;
@@ -733,7 +730,9 @@ free_partial:
int f2fs_truncate_blocks(struct inode *inode, u64 from, bool lock)
{
u64 free_from = from;
+ int err;
+#ifdef CONFIG_F2FS_FS_COMPRESSION
/*
* for compressed file, only support cluster size
* aligned truncation.
@@ -748,8 +747,18 @@ int f2fs_truncate_blocks(struct inode *inode, u64 from, bool lock)
free_from++;
free_from <<= cluster_shift;
}
+#endif
+
+ err = f2fs_do_truncate_blocks(inode, free_from, lock);
+ if (err)
+ return err;
+
+#ifdef CONFIG_F2FS_FS_COMPRESSION
+ if (from != free_from)
+ err = f2fs_truncate_partial_cluster(inode, from, lock);
+#endif
- return do_truncate_blocks(inode, free_from, lock);
+ return err;
}
int f2fs_truncate(struct inode *inode)