mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 04:31:50 +00:00
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>
This commit is contained in:
parent
602a16d58e
commit
5fdb322ff2
185
fs/f2fs/file.c
185
fs/f2fs/file.c
@ -4026,6 +4026,185 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int redirty_blocks(struct inode *inode, pgoff_t page_idx, int len)
|
||||
{
|
||||
DEFINE_READAHEAD(ractl, NULL, inode->i_mapping, page_idx);
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
struct page *page;
|
||||
pgoff_t redirty_idx = page_idx;
|
||||
int i, page_len = 0, ret = 0;
|
||||
|
||||
page_cache_ra_unbounded(&ractl, len, 0);
|
||||
|
||||
for (i = 0; i < len; i++, page_idx++) {
|
||||
page = read_cache_page(mapping, page_idx, NULL, NULL);
|
||||
if (IS_ERR(page)) {
|
||||
ret = PTR_ERR(page);
|
||||
break;
|
||||
}
|
||||
page_len++;
|
||||
}
|
||||
|
||||
for (i = 0; i < page_len; i++, redirty_idx++) {
|
||||
page = find_lock_page(mapping, redirty_idx);
|
||||
if (!page)
|
||||
ret = -ENOENT;
|
||||
set_page_dirty(page);
|
||||
f2fs_put_page(page, 1);
|
||||
f2fs_put_page(page, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int f2fs_ioc_decompress_file(struct file *filp, unsigned long arg)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
pgoff_t page_idx = 0, last_idx;
|
||||
unsigned int blk_per_seg = sbi->blocks_per_seg;
|
||||
int cluster_size = F2FS_I(inode)->i_cluster_size;
|
||||
int count, ret;
|
||||
|
||||
if (!f2fs_sb_has_compression(sbi) ||
|
||||
F2FS_OPTION(sbi).compress_mode != COMPR_MODE_USER)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
return -EBADF;
|
||||
|
||||
if (!f2fs_compressed_file(inode))
|
||||
return -EINVAL;
|
||||
|
||||
f2fs_balance_fs(F2FS_I_SB(inode), true);
|
||||
|
||||
file_start_write(filp);
|
||||
inode_lock(inode);
|
||||
|
||||
if (!f2fs_is_compress_backend_ready(inode)) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (f2fs_is_mmap_file(inode)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (!atomic_read(&fi->i_compr_blocks))
|
||||
goto out;
|
||||
|
||||
last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
|
||||
|
||||
count = last_idx - page_idx;
|
||||
while (count) {
|
||||
int len = min(cluster_size, count);
|
||||
|
||||
ret = redirty_blocks(inode, page_idx, len);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
if (get_dirty_pages(inode) >= blk_per_seg)
|
||||
filemap_fdatawrite(inode->i_mapping);
|
||||
|
||||
count -= len;
|
||||
page_idx += len;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
ret = filemap_write_and_wait_range(inode->i_mapping, 0,
|
||||
LLONG_MAX);
|
||||
|
||||
if (ret)
|
||||
f2fs_warn(sbi, "%s: The file might be partially decompressed "
|
||||
"(errno=%d). Please delete the file.\n",
|
||||
__func__, ret);
|
||||
out:
|
||||
inode_unlock(inode);
|
||||
file_end_write(filp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int f2fs_ioc_compress_file(struct file *filp, unsigned long arg)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
pgoff_t page_idx = 0, last_idx;
|
||||
unsigned int blk_per_seg = sbi->blocks_per_seg;
|
||||
int cluster_size = F2FS_I(inode)->i_cluster_size;
|
||||
int count, ret;
|
||||
|
||||
if (!f2fs_sb_has_compression(sbi) ||
|
||||
F2FS_OPTION(sbi).compress_mode != COMPR_MODE_USER)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
return -EBADF;
|
||||
|
||||
if (!f2fs_compressed_file(inode))
|
||||
return -EINVAL;
|
||||
|
||||
f2fs_balance_fs(F2FS_I_SB(inode), true);
|
||||
|
||||
file_start_write(filp);
|
||||
inode_lock(inode);
|
||||
|
||||
if (!f2fs_is_compress_backend_ready(inode)) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (f2fs_is_mmap_file(inode)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
set_inode_flag(inode, FI_ENABLE_COMPRESS);
|
||||
|
||||
last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
|
||||
|
||||
count = last_idx - page_idx;
|
||||
while (count) {
|
||||
int len = min(cluster_size, count);
|
||||
|
||||
ret = redirty_blocks(inode, page_idx, len);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
if (get_dirty_pages(inode) >= blk_per_seg)
|
||||
filemap_fdatawrite(inode->i_mapping);
|
||||
|
||||
count -= len;
|
||||
page_idx += len;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
ret = filemap_write_and_wait_range(inode->i_mapping, 0,
|
||||
LLONG_MAX);
|
||||
|
||||
clear_inode_flag(inode, FI_ENABLE_COMPRESS);
|
||||
|
||||
if (ret)
|
||||
f2fs_warn(sbi, "%s: The file might be partially compressed "
|
||||
"(errno=%d). Please delete the file.\n",
|
||||
__func__, ret);
|
||||
out:
|
||||
inode_unlock(inode);
|
||||
file_end_write(filp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
@ -4113,6 +4292,10 @@ static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
return f2fs_ioc_get_compress_option(filp, arg);
|
||||
case F2FS_IOC_SET_COMPRESS_OPTION:
|
||||
return f2fs_ioc_set_compress_option(filp, arg);
|
||||
case F2FS_IOC_DECOMPRESS_FILE:
|
||||
return f2fs_ioc_decompress_file(filp, arg);
|
||||
case F2FS_IOC_COMPRESS_FILE:
|
||||
return f2fs_ioc_compress_file(filp, arg);
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
@ -4352,6 +4535,8 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
case F2FS_IOC_SEC_TRIM_FILE:
|
||||
case F2FS_IOC_GET_COMPRESS_OPTION:
|
||||
case F2FS_IOC_SET_COMPRESS_OPTION:
|
||||
case F2FS_IOC_DECOMPRESS_FILE:
|
||||
case F2FS_IOC_COMPRESS_FILE:
|
||||
break;
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
|
@ -40,6 +40,8 @@
|
||||
struct f2fs_comp_option)
|
||||
#define F2FS_IOC_SET_COMPRESS_OPTION _IOW(F2FS_IOCTL_MAGIC, 22, \
|
||||
struct f2fs_comp_option)
|
||||
#define F2FS_IOC_DECOMPRESS_FILE _IO(F2FS_IOCTL_MAGIC, 23)
|
||||
#define F2FS_IOC_COMPRESS_FILE _IO(F2FS_IOCTL_MAGIC, 24)
|
||||
|
||||
/*
|
||||
* should be same as XFS_IOC_GOINGDOWN.
|
||||
|
Loading…
Reference in New Issue
Block a user