Skip to content

Commit 5fdb322

Browse files
Daeho JeongJaegeuk Kim
authored andcommitted
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 <[email protected]> Reviewed-by: Chao Yu <[email protected]> Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent 602a16d commit 5fdb322

File tree

2 files changed

+187
-0
lines changed

2 files changed

+187
-0
lines changed

fs/f2fs/file.c

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4026,6 +4026,185 @@ static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg)
40264026
return ret;
40274027
}
40284028

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+
40294208
static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
40304209
{
40314210
switch (cmd) {
@@ -4113,6 +4292,10 @@ static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
41134292
return f2fs_ioc_get_compress_option(filp, arg);
41144293
case F2FS_IOC_SET_COMPRESS_OPTION:
41154294
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);
41164299
default:
41174300
return -ENOTTY;
41184301
}
@@ -4352,6 +4535,8 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
43524535
case F2FS_IOC_SEC_TRIM_FILE:
43534536
case F2FS_IOC_GET_COMPRESS_OPTION:
43544537
case F2FS_IOC_SET_COMPRESS_OPTION:
4538+
case F2FS_IOC_DECOMPRESS_FILE:
4539+
case F2FS_IOC_COMPRESS_FILE:
43554540
break;
43564541
default:
43574542
return -ENOIOCTLCMD;

include/uapi/linux/f2fs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
struct f2fs_comp_option)
4141
#define F2FS_IOC_SET_COMPRESS_OPTION _IOW(F2FS_IOCTL_MAGIC, 22, \
4242
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)
4345

4446
/*
4547
* should be same as XFS_IOC_GOINGDOWN.

0 commit comments

Comments
 (0)