aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaeho Jeong2020-12-03 00:56:15 -0600
committerJaegeuk Kim2020-12-21 15:33:17 -0600
commit46806a8d82aa96dcd0afa49da257f5f56c011a09 (patch)
tree7d937f653a9d5b506605cb2940277d0ec69da222
parentf15a200ae8b7bbda6c6ff082994c27d0e71c24a3 (diff)
downloadkernel-46806a8d82aa96dcd0afa49da257f5f56c011a09.tar.gz
kernel-46806a8d82aa96dcd0afa49da257f5f56c011a09.tar.xz
kernel-46806a8d82aa96dcd0afa49da257f5f56c011a09.zip
f2fs: add F2FS_IOC_DECOMPRESS_FILE and F2FS_IOC_COMPRESS_FILE
Added two ioctl to decompress/compress explicitly the compression enabled file in "compress_mode=user" mount option. Using these two ioctls, the users can make a control of compression and decompression of their files. Signed-off-by: Daeho Jeong <daehojeong@google.com> Reviewed-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--fs/f2fs/file.c185
-rw-r--r--include/uapi/linux/f2fs.h2
2 files changed, 187 insertions, 0 deletions
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 8241b8bdb33c..16ea10f2bcf5 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -4026,6 +4026,185 @@ out:
4026 return ret; 4026 return ret;
4027} 4027}
4028 4028
4029static int redirty_blocks(struct inode *inode, pgoff_t page_idx, int len)
4030{
4031 DEFINE_READAHEAD(ractl, NULL, inode->i_mapping, page_idx);
4032 struct address_space *mapping = inode->i_mapping;
4033 struct page *page;
4034 pgoff_t redirty_idx = page_idx;
4035 int i, page_len = 0, ret = 0;
4036
4037 page_cache_ra_unbounded(&ractl, len, 0);
4038
4039 for (i = 0; i < len; i++, page_idx++) {
4040 page = read_cache_page(mapping, page_idx, NULL, NULL);
4041 if (IS_ERR(page)) {
4042 ret = PTR_ERR(page);
4043 break;
4044 }
4045 page_len++;
4046 }
4047
4048 for (i = 0; i < page_len; i++, redirty_idx++) {
4049 page = find_lock_page(mapping, redirty_idx);
4050 if (!page)
4051 ret = -ENOENT;
4052 set_page_dirty(page);
4053 f2fs_put_page(page, 1);
4054 f2fs_put_page(page, 0);
4055 }
4056
4057 return ret;
4058}
4059
4060static int f2fs_ioc_decompress_file(struct file *filp, unsigned long arg)
4061{
4062 struct inode *inode = file_inode(filp);
4063 struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
4064 struct f2fs_inode_info *fi = F2FS_I(inode);
4065 pgoff_t page_idx = 0, last_idx;
4066 unsigned int blk_per_seg = sbi->blocks_per_seg;
4067 int cluster_size = F2FS_I(inode)->i_cluster_size;
4068 int count, ret;
4069
4070 if (!f2fs_sb_has_compression(sbi) ||
4071 F2FS_OPTION(sbi).compress_mode != COMPR_MODE_USER)
4072 return -EOPNOTSUPP;
4073
4074 if (!(filp->f_mode & FMODE_WRITE))
4075 return -EBADF;
4076
4077 if (!f2fs_compressed_file(inode))
4078 return -EINVAL;
4079
4080 f2fs_balance_fs(F2FS_I_SB(inode), true);
4081
4082 file_start_write(filp);
4083 inode_lock(inode);
4084
4085 if (!f2fs_is_compress_backend_ready(inode)) {
4086 ret = -EOPNOTSUPP;
4087 goto out;
4088 }
4089
4090 if (f2fs_is_mmap_file(inode)) {
4091 ret = -EBUSY;
4092 goto out;
4093 }
4094
4095 ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
4096 if (ret)
4097 goto out;
4098
4099 if (!atomic_read(&fi->i_compr_blocks))
4100 goto out;
4101
4102 last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
4103
4104 count = last_idx - page_idx;
4105 while (count) {
4106 int len = min(cluster_size, count);
4107
4108 ret = redirty_blocks(inode, page_idx, len);
4109 if (ret < 0)
4110 break;
4111
4112 if (get_dirty_pages(inode) >= blk_per_seg)
4113 filemap_fdatawrite(inode->i_mapping);
4114
4115 count -= len;
4116 page_idx += len;
4117 }
4118
4119 if (!ret)
4120 ret = filemap_write_and_wait_range(inode->i_mapping, 0,
4121 LLONG_MAX);
4122
4123 if (ret)
4124 f2fs_warn(sbi, "%s: The file might be partially decompressed "
4125 "(errno=%d). Please delete the file.\n",
4126 __func__, ret);
4127out:
4128 inode_unlock(inode);
4129 file_end_write(filp);
4130
4131 return ret;
4132}
4133
4134static int f2fs_ioc_compress_file(struct file *filp, unsigned long arg)
4135{
4136 struct inode *inode = file_inode(filp);
4137 struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
4138 pgoff_t page_idx = 0, last_idx;
4139 unsigned int blk_per_seg = sbi->blocks_per_seg;
4140 int cluster_size = F2FS_I(inode)->i_cluster_size;
4141 int count, ret;
4142
4143 if (!f2fs_sb_has_compression(sbi) ||
4144 F2FS_OPTION(sbi).compress_mode != COMPR_MODE_USER)
4145 return -EOPNOTSUPP;
4146
4147 if (!(filp->f_mode & FMODE_WRITE))
4148 return -EBADF;
4149
4150 if (!f2fs_compressed_file(inode))
4151 return -EINVAL;
4152
4153 f2fs_balance_fs(F2FS_I_SB(inode), true);
4154
4155 file_start_write(filp);
4156 inode_lock(inode);
4157
4158 if (!f2fs_is_compress_backend_ready(inode)) {
4159 ret = -EOPNOTSUPP;
4160 goto out;
4161 }
4162
4163 if (f2fs_is_mmap_file(inode)) {
4164 ret = -EBUSY;
4165 goto out;
4166 }
4167
4168 ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
4169 if (ret)
4170 goto out;
4171
4172 set_inode_flag(inode, FI_ENABLE_COMPRESS);
4173
4174 last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
4175
4176 count = last_idx - page_idx;
4177 while (count) {
4178 int len = min(cluster_size, count);
4179
4180 ret = redirty_blocks(inode, page_idx, len);
4181 if (ret < 0)
4182 break;
4183
4184 if (get_dirty_pages(inode) >= blk_per_seg)
4185 filemap_fdatawrite(inode->i_mapping);
4186
4187 count -= len;
4188 page_idx += len;
4189 }
4190
4191 if (!ret)
4192 ret = filemap_write_and_wait_range(inode->i_mapping, 0,
4193 LLONG_MAX);
4194
4195 clear_inode_flag(inode, FI_ENABLE_COMPRESS);
4196
4197 if (ret)
4198 f2fs_warn(sbi, "%s: The file might be partially compressed "
4199 "(errno=%d). Please delete the file.\n",
4200 __func__, ret);
4201out:
4202 inode_unlock(inode);
4203 file_end_write(filp);
4204
4205 return ret;
4206}
4207
4029static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 4208static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
4030{ 4209{
4031 switch (cmd) { 4210 switch (cmd) {
@@ -4113,6 +4292,10 @@ static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
4113 return f2fs_ioc_get_compress_option(filp, arg); 4292 return f2fs_ioc_get_compress_option(filp, arg);
4114 case F2FS_IOC_SET_COMPRESS_OPTION: 4293 case F2FS_IOC_SET_COMPRESS_OPTION:
4115 return f2fs_ioc_set_compress_option(filp, arg); 4294 return f2fs_ioc_set_compress_option(filp, arg);
4295 case F2FS_IOC_DECOMPRESS_FILE:
4296 return f2fs_ioc_decompress_file(filp, arg);
4297 case F2FS_IOC_COMPRESS_FILE:
4298 return f2fs_ioc_compress_file(filp, arg);
4116 default: 4299 default:
4117 return -ENOTTY; 4300 return -ENOTTY;
4118 } 4301 }
@@ -4352,6 +4535,8 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
4352 case F2FS_IOC_SEC_TRIM_FILE: 4535 case F2FS_IOC_SEC_TRIM_FILE:
4353 case F2FS_IOC_GET_COMPRESS_OPTION: 4536 case F2FS_IOC_GET_COMPRESS_OPTION:
4354 case F2FS_IOC_SET_COMPRESS_OPTION: 4537 case F2FS_IOC_SET_COMPRESS_OPTION:
4538 case F2FS_IOC_DECOMPRESS_FILE:
4539 case F2FS_IOC_COMPRESS_FILE:
4355 break; 4540 break;
4356 default: 4541 default:
4357 return -ENOIOCTLCMD; 4542 return -ENOIOCTLCMD;
diff --git a/include/uapi/linux/f2fs.h b/include/uapi/linux/f2fs.h
index f00199a2e38b..352a822d4370 100644
--- a/include/uapi/linux/f2fs.h
+++ b/include/uapi/linux/f2fs.h
@@ -40,6 +40,8 @@
40 struct f2fs_comp_option) 40 struct f2fs_comp_option)
41#define F2FS_IOC_SET_COMPRESS_OPTION _IOW(F2FS_IOCTL_MAGIC, 22, \ 41#define F2FS_IOC_SET_COMPRESS_OPTION _IOW(F2FS_IOCTL_MAGIC, 22, \
42 struct f2fs_comp_option) 42 struct f2fs_comp_option)
43#define F2FS_IOC_DECOMPRESS_FILE _IO(F2FS_IOCTL_MAGIC, 23)
44#define F2FS_IOC_COMPRESS_FILE _IO(F2FS_IOCTL_MAGIC, 24)
43 45
44/* 46/*
45 * should be same as XFS_IOC_GOINGDOWN. 47 * should be same as XFS_IOC_GOINGDOWN.