Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Daeho Jeong and committed by
Jaegeuk Kim
5fdb322f 602a16d5

+187
+185
fs/f2fs/file.c
··· 4026 4026 return ret; 4027 4027 } 4028 4028 4029 + static 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 + 4060 + static 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); 4127 + out: 4128 + inode_unlock(inode); 4129 + file_end_write(filp); 4130 + 4131 + return ret; 4132 + } 4133 + 4134 + static 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); 4201 + out: 4202 + inode_unlock(inode); 4203 + file_end_write(filp); 4204 + 4205 + return ret; 4206 + } 4207 + 4029 4208 static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 4030 4209 { 4031 4210 switch (cmd) { ··· 4292 4113 return f2fs_ioc_get_compress_option(filp, arg); 4293 4114 case F2FS_IOC_SET_COMPRESS_OPTION: 4294 4115 return f2fs_ioc_set_compress_option(filp, arg); 4116 + case F2FS_IOC_DECOMPRESS_FILE: 4117 + return f2fs_ioc_decompress_file(filp, arg); 4118 + case F2FS_IOC_COMPRESS_FILE: 4119 + return f2fs_ioc_compress_file(filp, arg); 4295 4120 default: 4296 4121 return -ENOTTY; 4297 4122 } ··· 4535 4352 case F2FS_IOC_SEC_TRIM_FILE: 4536 4353 case F2FS_IOC_GET_COMPRESS_OPTION: 4537 4354 case F2FS_IOC_SET_COMPRESS_OPTION: 4355 + case F2FS_IOC_DECOMPRESS_FILE: 4356 + case F2FS_IOC_COMPRESS_FILE: 4538 4357 break; 4539 4358 default: 4540 4359 return -ENOIOCTLCMD;
+2
include/uapi/linux/f2fs.h
··· 40 40 struct f2fs_comp_option) 41 41 #define F2FS_IOC_SET_COMPRESS_OPTION _IOW(F2FS_IOCTL_MAGIC, 22, \ 42 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 47 * should be same as XFS_IOC_GOINGDOWN.