[PATCH v4 6/6] f2fs: access compression level and flags by extra attr ioctls

From: Sheng Yong
Date: Sun Jun 11 2023 - 23:02:39 EST


Allow getting or setting compression level and flags through
F2FS_IOC_GET_EXTRA_ATTR and F2FS_IOC_SET_EXTRA_ATTR.

Signed-off-by: Sheng Yong <shengyong@xxxxxxxx>
---
fs/f2fs/file.c | 56 ++++++++++++++++++++++++++++++++-------
include/uapi/linux/f2fs.h | 10 ++++++-
2 files changed, 55 insertions(+), 11 deletions(-)

diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 39d04f8f0bb6b..1ac73cd59db79 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -3916,10 +3916,14 @@ static int f2fs_sec_trim_file(struct file *filp, unsigned long arg)
return ret;
}

-static int f2fs_ioc_get_compress_option(struct file *filp, unsigned long arg)
+static int f2fs_get_compress_option_v2(struct file *filp,
+ unsigned long attr, __u16 *attr_size)
{
struct inode *inode = file_inode(filp);
- struct f2fs_comp_option option;
+ struct f2fs_comp_option_v2 option;
+
+ if (sizeof(option) < *attr_size)
+ *attr_size = sizeof(option);

if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
return -EOPNOTSUPP;
@@ -3933,31 +3937,42 @@ static int f2fs_ioc_get_compress_option(struct file *filp, unsigned long arg)

option.algorithm = F2FS_I(inode)->i_compress_algorithm;
option.log_cluster_size = F2FS_I(inode)->i_log_cluster_size;
+ option.level = F2FS_I(inode)->i_compress_level;
+ option.flag = F2FS_I(inode)->i_compress_flag;

inode_unlock_shared(inode);

- if (copy_to_user((struct f2fs_comp_option __user *)arg, &option,
- sizeof(option)))
+ if (copy_to_user((void __user *)attr, &option, *attr_size))
return -EFAULT;

return 0;
}

-static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg)
+static int f2fs_ioc_get_compress_option(struct file *filp, unsigned long arg)
+{
+ __u16 size = sizeof(struct f2fs_comp_option);
+
+ return f2fs_get_compress_option_v2(filp, arg, &size);
+}
+
+static int f2fs_set_compress_option_v2(struct file *filp,
+ unsigned long attr, __u16 *attr_size)
{
struct inode *inode = file_inode(filp);
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- struct f2fs_comp_option option;
+ struct f2fs_comp_option_v2 option;
int ret = 0;

+ if (sizeof(option) < *attr_size)
+ *attr_size = sizeof(option);
+
if (!f2fs_sb_has_compression(sbi))
return -EOPNOTSUPP;

if (!(filp->f_mode & FMODE_WRITE))
return -EBADF;

- if (copy_from_user(&option, (struct f2fs_comp_option __user *)arg,
- sizeof(option)))
+ if (copy_from_user(&option, (void __user *)attr, *attr_size))
return -EFAULT;

if (!f2fs_compressed_file(inode) ||
@@ -3966,6 +3981,14 @@ static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg)
option.algorithm >= COMPRESS_MAX)
return -EINVAL;

+ if (*attr_size == sizeof(struct f2fs_comp_option_v2)) {
+ if (!f2fs_is_compress_level_valid(option.algorithm,
+ option.level))
+ return -EINVAL;
+ if (option.flag > BIT(COMPRESS_MAX_FLAG) - 1)
+ return -EINVAL;
+ }
+
file_start_write(filp);
inode_lock(inode);

@@ -3982,6 +4005,10 @@ static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg)
F2FS_I(inode)->i_compress_algorithm = option.algorithm;
F2FS_I(inode)->i_log_cluster_size = option.log_cluster_size;
F2FS_I(inode)->i_cluster_size = BIT(option.log_cluster_size);
+ if (*attr_size == sizeof(struct f2fs_comp_option_v2)) {
+ F2FS_I(inode)->i_compress_level = option.level;
+ F2FS_I(inode)->i_compress_flag = option.flag;
+ }
f2fs_mark_inode_dirty_sync(inode, true);

if (!f2fs_is_compress_backend_ready(inode))
@@ -3994,6 +4021,13 @@ static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg)
return ret;
}

+static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg)
+{
+ __u16 size = sizeof(struct f2fs_comp_option);
+
+ return f2fs_set_compress_option_v2(filp, arg, &size);
+}
+
static int redirty_blocks(struct inode *inode, pgoff_t page_idx, int len)
{
DEFINE_READAHEAD(ractl, NULL, NULL, inode->i_mapping, page_idx);
@@ -4277,7 +4311,8 @@ static int f2fs_ioc_get_extra_attr(struct file *filp, unsigned long arg)
ret = f2fs_get_compress_blocks(inode, &attr.attr);
break;
case F2FS_EXTRA_ATTR_COMPR_OPTION:
- ret = f2fs_ioc_get_compress_option(filp, attr.attr);
+ ret = f2fs_get_compress_option_v2(filp, attr.attr,
+ &attr.attr_size);
break;
default:
return -EINVAL;
@@ -4371,7 +4406,8 @@ static int f2fs_ioc_set_extra_attr(struct file *filp, unsigned long arg)
f2fs_balance_fs(sbi, true);
break;
case F2FS_EXTRA_ATTR_COMPR_OPTION:
- ret = f2fs_ioc_set_compress_option(filp, attr.attr);
+ ret = f2fs_set_compress_option_v2(filp, attr.attr,
+ &attr.attr_size);
break;
default:
return -EINVAL;
diff --git a/include/uapi/linux/f2fs.h b/include/uapi/linux/f2fs.h
index 2b53e90421bfc..153a6395c5f35 100644
--- a/include/uapi/linux/f2fs.h
+++ b/include/uapi/linux/f2fs.h
@@ -100,6 +100,13 @@ struct f2fs_comp_option {
__u8 log_cluster_size;
};

+struct f2fs_comp_option_v2 {
+ __u8 algorithm;
+ __u8 log_cluster_size;
+ __u8 level;
+ __u8 flag;
+};
+
enum {
F2FS_EXTRA_ATTR_TOTAL_SIZE, /* ro, size of extra attr area */
F2FS_EXTRA_ATTR_ISIZE, /* ro, i_extra_isize */
@@ -109,7 +116,8 @@ enum {
F2FS_EXTRA_ATTR_CRTIME, /* ro, i_crtime, i_crtime_nsec */
F2FS_EXTRA_ATTR_COMPR_BLOCKS, /* ro, i_compr_blocks */
F2FS_EXTRA_ATTR_COMPR_OPTION, /* rw, i_compress_algorithm,
- * i_log_cluster_size
+ * i_log_cluster_size,
+ * i_compress_flag
*/
F2FS_EXTRA_ATTR_MAX,
};
--
2.40.1