2023-06-12 03:07:07

by Sheng Yong

[permalink] [raw]
Subject: [PATCH v4 0/6] f2fs: add f2fs_ioc_[get|set]_extra_attr

This patchset introduces two ioctls to get or modify values in
f2fs_inode's extra attribute area:
* f2fs_ioc_get_extra_attr
* f2fs_ioc_set_extra_attr

The argument of these two ioctls is `struct f2fs_extra_attr', which has
three members:
* field: indicates which field in extra attribute area is handled
* attr: value or userspace pointer
* attr_size: size of `attr'

The `field' member could help extend functionality of these two ioctls
without modify or add new interfaces, if more fields are added into
extra attributes ares in the feture.

In order to reuse existed functions, several helpers are added to:
* read inode chksum from inode page
* get compress blocks
* verify compression level
And, a compress_option v2 is added to access compress level and flags.

Thanks,
shengyong

v4:
* split into small commits
v3:
* setting lz4(hc) level correctly
v2:
* fix compiling error if CONFIG_F2FS_FS_ZSTD is disabled by adding a
helper f2fs_is_compress_level_valid()
* fix compiling warning for casting unsinged long long to pointer

Sheng Yong (6):
f2fs: add helper to check compression level
f2fs: cleanup MIN_INLINE_XATTR_SIZE
f2fs: add helper to get inode chksum from inode page
f2fs: add f2fs_ioc_get_compress_blocks
f2fs: add f2fs_ioc_[get|set]_extra_attr
f2fs: access compression level and flags by extra attr ioctls

fs/f2fs/compress.c | 31 +++++
fs/f2fs/f2fs.h | 4 +
fs/f2fs/file.c | 280 ++++++++++++++++++++++++++++++++++++--
fs/f2fs/inode.c | 21 +++
fs/f2fs/super.c | 6 +-
fs/f2fs/xattr.h | 1 +
include/uapi/linux/f2fs.h | 33 +++++
7 files changed, 359 insertions(+), 17 deletions(-)

--
2.40.1



2023-06-12 03:07:27

by Sheng Yong

[permalink] [raw]
Subject: [PATCH v4 1/6] f2fs: add helper to check compression level

This patch adds a helper function to check if compression level is
valid.

Signed-off-by: Sheng Yong <[email protected]>
---
fs/f2fs/compress.c | 31 +++++++++++++++++++++++++++++++
fs/f2fs/f2fs.h | 2 ++
fs/f2fs/super.c | 4 ++--
3 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index 1132d3cd8f337..63a496137ebe7 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -55,6 +55,7 @@ struct f2fs_compress_ops {
int (*init_decompress_ctx)(struct decompress_io_ctx *dic);
void (*destroy_decompress_ctx)(struct decompress_io_ctx *dic);
int (*decompress_pages)(struct decompress_io_ctx *dic);
+ bool (*is_level_valid)(int level);
};

static unsigned int offset_in_cluster(struct compress_ctx *cc, pgoff_t index)
@@ -308,11 +309,23 @@ static int lz4_decompress_pages(struct decompress_io_ctx *dic)
return 0;
}

+static bool lz4_is_level_valid(int lvl)
+{
+ if (lvl == 0)
+ return true;
+#ifdef CONFIG_F2FS_FS_LZ4HC
+ if (lvl >= LZ4HC_MIN_CLEVEL && lvl <= LZ4HC_MAX_CLEVEL)
+ return true;
+#endif
+ return false;
+}
+
static const struct f2fs_compress_ops f2fs_lz4_ops = {
.init_compress_ctx = lz4_init_compress_ctx,
.destroy_compress_ctx = lz4_destroy_compress_ctx,
.compress_pages = lz4_compress_pages,
.decompress_pages = lz4_decompress_pages,
+ .is_level_valid = lz4_is_level_valid,
};
#endif

@@ -477,6 +490,13 @@ static int zstd_decompress_pages(struct decompress_io_ctx *dic)
return 0;
}

+static bool zstd_is_level_valid(int lvl)
+{
+ if (lvl < zstd_min_clevel() || lvl > zstd_max_clevel())
+ return false;
+ return true;
+}
+
static const struct f2fs_compress_ops f2fs_zstd_ops = {
.init_compress_ctx = zstd_init_compress_ctx,
.destroy_compress_ctx = zstd_destroy_compress_ctx,
@@ -484,6 +504,7 @@ static const struct f2fs_compress_ops f2fs_zstd_ops = {
.init_decompress_ctx = zstd_init_decompress_ctx,
.destroy_decompress_ctx = zstd_destroy_decompress_ctx,
.decompress_pages = zstd_decompress_pages,
+ .is_level_valid = zstd_is_level_valid,
};
#endif

@@ -542,6 +563,16 @@ bool f2fs_is_compress_backend_ready(struct inode *inode)
return f2fs_cops[F2FS_I(inode)->i_compress_algorithm];
}

+bool f2fs_is_compress_level_valid(int alg, int lvl)
+{
+ const struct f2fs_compress_ops *cops = f2fs_cops[alg];
+
+ if (cops->is_level_valid)
+ return cops->is_level_valid(lvl);
+
+ return lvl == 0;
+}
+
static mempool_t *compress_page_pool;
static int num_compress_pages = 512;
module_param(num_compress_pages, uint, 0444);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 80c783215b5a3..1b17bbe7e8656 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -4236,6 +4236,7 @@ bool f2fs_compress_write_end(struct inode *inode, void *fsdata,
int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock);
void f2fs_compress_write_end_io(struct bio *bio, struct page *page);
bool f2fs_is_compress_backend_ready(struct inode *inode);
+bool f2fs_is_compress_level_valid(int alg, int lvl);
int __init f2fs_init_compress_mempool(void);
void f2fs_destroy_compress_mempool(void);
void f2fs_decompress_cluster(struct decompress_io_ctx *dic, bool in_task);
@@ -4300,6 +4301,7 @@ static inline bool f2fs_is_compress_backend_ready(struct inode *inode)
/* not support compression */
return false;
}
+static inline bool f2fs_is_compress_level_valid(int alg, int lvl) { return false; }
static inline struct page *f2fs_compress_control_page(struct page *page)
{
WARN_ON_ONCE(1);
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 8fd23caa1ed99..023981824d240 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -606,7 +606,7 @@ static int f2fs_set_lz4hc_level(struct f2fs_sb_info *sbi, const char *str)
if (kstrtouint(str + 1, 10, &level))
return -EINVAL;

- if (level < LZ4HC_MIN_CLEVEL || level > LZ4HC_MAX_CLEVEL) {
+ if (!f2fs_is_compress_level_valid(COMPRESS_LZ4, level)) {
f2fs_info(sbi, "invalid lz4hc compress level: %d", level);
return -EINVAL;
}
@@ -640,7 +640,7 @@ static int f2fs_set_zstd_level(struct f2fs_sb_info *sbi, const char *str)
if (kstrtouint(str + 1, 10, &level))
return -EINVAL;

- if (!level || level > zstd_max_clevel()) {
+ if (!f2fs_is_compress_level_valid(COMPRESS_ZSTD, level)) {
f2fs_info(sbi, "invalid zstd compress level: %d", level);
return -EINVAL;
}
--
2.40.1


2023-06-12 03:11:56

by Sheng Yong

[permalink] [raw]
Subject: [PATCH v4 5/6] f2fs: add f2fs_ioc_[get|set]_extra_attr

This patch introduces two ioctls:
* f2fs_ioc_get_extra_attr
* f2fs_ioc_set_extra_attr
to get or modify values in f2fs_inode's extra attribute area.

The argument of these two ioctls is `struct f2fs_extra_attr', which has
three members:
* field: indicates which field in extra attribute area is handled
* attr: value or userspace pointer
* attr_size: size of `attr'

The `field' member could help extend functionality of these two ioctls
without modify or add new interfaces, if more fields are added into
extra attributes ares in the feture.

Signed-off-by: Sheng Yong <[email protected]>
---
fs/f2fs/file.c | 205 ++++++++++++++++++++++++++++++++++++++
include/uapi/linux/f2fs.h | 25 +++++
2 files changed, 230 insertions(+)

diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index f8aa842b5d233..39d04f8f0bb6b 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -4179,6 +4179,207 @@ static int f2fs_ioc_compress_file(struct file *filp)
return ret;
}

+static bool extra_attr_fits_in_inode(struct inode *inode, int field)
+{
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ struct f2fs_inode *ri;
+
+ switch (field) {
+ case F2FS_EXTRA_ATTR_TOTAL_SIZE:
+ case F2FS_EXTRA_ATTR_ISIZE:
+ case F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE:
+ return true;
+ case F2FS_EXTRA_ATTR_PROJID:
+ if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_projid))
+ return false;
+ return true;
+ case F2FS_EXTRA_ATTR_INODE_CHKSUM:
+ if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_inode_checksum))
+ return false;
+ return true;
+ case F2FS_EXTRA_ATTR_CRTIME:
+ if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_crtime))
+ return false;
+ return true;
+ case F2FS_EXTRA_ATTR_COMPR_BLOCKS:
+ case F2FS_EXTRA_ATTR_COMPR_OPTION:
+ if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_compr_blocks))
+ return false;
+ return true;
+ default:
+ BUG_ON(1);
+ return false;
+ }
+}
+
+static int f2fs_ioc_get_extra_attr(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ struct f2fs_extra_attr attr;
+ u32 chksum;
+ int ret = 0;
+
+ if (!f2fs_has_extra_attr(inode))
+ return -EOPNOTSUPP;
+
+ if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
+ return -EFAULT;
+
+ if (attr.field >= F2FS_EXTRA_ATTR_MAX)
+ return -EINVAL;
+
+ if (!extra_attr_fits_in_inode(inode, attr.field))
+ return -EOPNOTSUPP;
+
+ switch (attr.field) {
+ case F2FS_EXTRA_ATTR_TOTAL_SIZE:
+ attr.attr = F2FS_TOTAL_EXTRA_ATTR_SIZE;
+ break;
+ case F2FS_EXTRA_ATTR_ISIZE:
+ attr.attr = fi->i_extra_isize;
+ break;
+ case F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE:
+ if (!f2fs_has_inline_xattr(inode))
+ return -EOPNOTSUPP;
+ attr.attr = get_inline_xattr_addrs(inode);
+ break;
+ case F2FS_EXTRA_ATTR_PROJID:
+ if (!f2fs_sb_has_project_quota(F2FS_I_SB(inode)))
+ return -EOPNOTSUPP;
+ attr.attr = from_kprojid(&init_user_ns, fi->i_projid);
+ break;
+ case F2FS_EXTRA_ATTR_INODE_CHKSUM:
+ ret = f2fs_inode_chksum_get(sbi, inode, &chksum);
+ if (ret)
+ return ret;
+ attr.attr = chksum;
+ break;
+ case F2FS_EXTRA_ATTR_CRTIME:
+ if (!f2fs_sb_has_inode_crtime(sbi))
+ return -EOPNOTSUPP;
+ if (attr.attr_size == sizeof(struct timespec64)) {
+ if (put_timespec64(&fi->i_crtime,
+ (void __user *)(uintptr_t)attr.attr))
+ return -EFAULT;
+ } else if (attr.attr_size == sizeof(struct old_timespec32)) {
+ if (put_old_timespec32(&fi->i_crtime,
+ (void __user *)(uintptr_t)attr.attr))
+ return -EFAULT;
+ } else {
+ return -EINVAL;
+ }
+ break;
+ case F2FS_EXTRA_ATTR_COMPR_BLOCKS:
+ if (attr.attr_size != sizeof(__u64))
+ return -EINVAL;
+ ret = f2fs_get_compress_blocks(inode, &attr.attr);
+ break;
+ case F2FS_EXTRA_ATTR_COMPR_OPTION:
+ ret = f2fs_ioc_get_compress_option(filp, attr.attr);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ if (copy_to_user((void __user *)arg, &attr, sizeof(attr)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int f2fs_ioc_set_extra_attr(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ struct f2fs_extra_attr attr;
+ struct page *ipage;
+ void *inline_addr;
+ int ret;
+
+ if (!f2fs_has_extra_attr(inode))
+ return -EOPNOTSUPP;
+
+ if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
+ return -EFAULT;
+
+ if (attr.field >= F2FS_EXTRA_ATTR_MAX)
+ return -EINVAL;
+
+ if (!extra_attr_fits_in_inode(inode, attr.field))
+ return -EOPNOTSUPP;
+
+ switch (attr.field) {
+ case F2FS_EXTRA_ATTR_TOTAL_SIZE:
+ case F2FS_EXTRA_ATTR_ISIZE:
+ case F2FS_EXTRA_ATTR_PROJID:
+ case F2FS_EXTRA_ATTR_INODE_CHKSUM:
+ case F2FS_EXTRA_ATTR_CRTIME:
+ case F2FS_EXTRA_ATTR_COMPR_BLOCKS:
+ /* read only attribtues */
+ return -EOPNOTSUPP;
+ case F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE:
+ if (!f2fs_sb_has_flexible_inline_xattr(sbi) ||
+ !f2fs_has_inline_xattr(inode))
+ return -EOPNOTSUPP;
+ if (attr.attr < MIN_INLINE_XATTR_SIZE ||
+ attr.attr > MAX_INLINE_XATTR_SIZE)
+ return -EINVAL;
+ inode_lock(inode);
+ f2fs_lock_op(sbi);
+ f2fs_down_write(&F2FS_I(inode)->i_xattr_sem);
+ if (i_size_read(inode) || F2FS_I(inode)->i_xattr_nid) {
+ /*
+ * it is not allowed to set this field if the inode
+ * has data or xattr node
+ */
+ ret = -EFBIG;
+ goto xattr_out_unlock;
+ }
+ ipage = f2fs_get_node_page(sbi, inode->i_ino);
+ if (IS_ERR(ipage)) {
+ ret = PTR_ERR(ipage);
+ goto xattr_out_unlock;
+ }
+ inline_addr = inline_xattr_addr(inode, ipage);
+ if (!IS_XATTR_LAST_ENTRY(XATTR_FIRST_ENTRY(inline_addr))) {
+ ret = -EFBIG;
+ } else {
+ struct f2fs_xattr_header *hdr;
+ struct f2fs_xattr_entry *ent;
+
+ F2FS_I(inode)->i_inline_xattr_size = (int)attr.attr;
+ inline_addr = inline_xattr_addr(inode, ipage);
+ hdr = XATTR_HDR(inline_addr);
+ ent = XATTR_FIRST_ENTRY(inline_addr);
+ hdr->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC);
+ hdr->h_refcount = cpu_to_le32(1);
+ memset(ent, 0, attr.attr - sizeof(*hdr));
+ set_page_dirty(ipage);
+ ret = 0;
+ }
+ f2fs_put_page(ipage, 1);
+xattr_out_unlock:
+ f2fs_up_write(&F2FS_I(inode)->i_xattr_sem);
+ f2fs_unlock_op(sbi);
+ inode_unlock(inode);
+ if (!ret)
+ f2fs_balance_fs(sbi, true);
+ break;
+ case F2FS_EXTRA_ATTR_COMPR_OPTION:
+ ret = f2fs_ioc_set_compress_option(filp, attr.attr);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
@@ -4265,6 +4466,10 @@ static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return f2fs_ioc_decompress_file(filp);
case F2FS_IOC_COMPRESS_FILE:
return f2fs_ioc_compress_file(filp);
+ case F2FS_IOC_GET_EXTRA_ATTR:
+ return f2fs_ioc_get_extra_attr(filp, arg);
+ case F2FS_IOC_SET_EXTRA_ATTR:
+ return f2fs_ioc_set_extra_attr(filp, arg);
default:
return -ENOTTY;
}
diff --git a/include/uapi/linux/f2fs.h b/include/uapi/linux/f2fs.h
index 955d440be1046..2b53e90421bfc 100644
--- a/include/uapi/linux/f2fs.h
+++ b/include/uapi/linux/f2fs.h
@@ -43,6 +43,10 @@
#define F2FS_IOC_DECOMPRESS_FILE _IO(F2FS_IOCTL_MAGIC, 23)
#define F2FS_IOC_COMPRESS_FILE _IO(F2FS_IOCTL_MAGIC, 24)
#define F2FS_IOC_START_ATOMIC_REPLACE _IO(F2FS_IOCTL_MAGIC, 25)
+#define F2FS_IOC_GET_EXTRA_ATTR _IOR(F2FS_IOCTL_MAGIC, 26, \
+ struct f2fs_extra_attr)
+#define F2FS_IOC_SET_EXTRA_ATTR _IOW(F2FS_IOCTL_MAGIC, 27, \
+ struct f2fs_extra_attr)

/*
* should be same as XFS_IOC_GOINGDOWN.
@@ -96,4 +100,25 @@ struct f2fs_comp_option {
__u8 log_cluster_size;
};

+enum {
+ F2FS_EXTRA_ATTR_TOTAL_SIZE, /* ro, size of extra attr area */
+ F2FS_EXTRA_ATTR_ISIZE, /* ro, i_extra_isize */
+ F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE, /* rw, i_inline_xattr_size */
+ F2FS_EXTRA_ATTR_PROJID, /* ro, i_projid */
+ F2FS_EXTRA_ATTR_INODE_CHKSUM, /* ro, i_inode_chksum */
+ 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
+ */
+ F2FS_EXTRA_ATTR_MAX,
+};
+
+struct f2fs_extra_attr {
+ __u8 field; /* F2FS_EXTRA_ATTR_* */
+ __u8 rsvd1;
+ __u16 attr_size; /* size of @attr */
+ __u32 rsvd2;
+ __u64 attr; /* attr value or pointer */
+};
#endif /* _UAPI_LINUX_F2FS_H */
--
2.40.1


2023-06-12 03:16:22

by Sheng Yong

[permalink] [raw]
Subject: [PATCH v4 3/6] f2fs: add helper to get inode chksum from inode page

Signed-off-by: Sheng Yong <[email protected]>
---
fs/f2fs/f2fs.h | 2 ++
fs/f2fs/inode.c | 21 +++++++++++++++++++++
2 files changed, 23 insertions(+)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 1b17bbe7e8656..a30c81ac7299d 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3478,6 +3478,8 @@ int f2fs_pin_file_control(struct inode *inode, bool inc);
void f2fs_set_inode_flags(struct inode *inode);
bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page);
void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page);
+int f2fs_inode_chksum_get(struct f2fs_sb_info *sbi, struct inode *inode,
+ u32 *chksum);
struct inode *f2fs_iget(struct super_block *sb, unsigned long ino);
struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino);
int f2fs_try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink);
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 1e49009831c12..098d1ee72bfcb 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -204,6 +204,27 @@ void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page)
ri->i_inode_checksum = cpu_to_le32(f2fs_inode_chksum(sbi, page));
}

+int f2fs_inode_chksum_get(struct f2fs_sb_info *sbi,
+ struct inode *inode, u32 *chksum)
+{
+ struct page *ipage;
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ struct f2fs_inode *ri;
+
+ if (!f2fs_sb_has_inode_chksum(sbi) ||
+ !f2fs_has_extra_attr(inode) ||
+ !F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_inode_checksum))
+ return -EOPNOTSUPP;
+
+ ipage = f2fs_get_node_page(sbi, inode->i_ino);
+ if (IS_ERR(ipage))
+ return PTR_ERR(ipage);
+
+ *chksum = f2fs_inode_chksum(sbi, ipage);
+ f2fs_put_page(ipage, true);
+ return 0;
+}
+
static bool sanity_check_compress_inode(struct inode *inode,
struct f2fs_inode *ri)
{
--
2.40.1


2023-06-12 03:16:27

by Sheng Yong

[permalink] [raw]
Subject: [PATCH v4 2/6] f2fs: cleanup MIN_INLINE_XATTR_SIZE

Signed-off-by: Sheng Yong <[email protected]>
---
fs/f2fs/super.c | 2 +-
fs/f2fs/xattr.h | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 023981824d240..d7630f6dcbd62 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -1361,7 +1361,7 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
return -EINVAL;
}

- min_size = sizeof(struct f2fs_xattr_header) / sizeof(__le32);
+ min_size = MIN_INLINE_XATTR_SIZE;
max_size = MAX_INLINE_XATTR_SIZE;

if (F2FS_OPTION(sbi).inline_xattr_size < min_size ||
diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h
index 416d652774a33..b1811c392e6f1 100644
--- a/fs/f2fs/xattr.h
+++ b/fs/f2fs/xattr.h
@@ -83,6 +83,7 @@ struct f2fs_xattr_entry {
sizeof(struct f2fs_xattr_header) - \
sizeof(struct f2fs_xattr_entry))

+#define MIN_INLINE_XATTR_SIZE (sizeof(struct f2fs_xattr_header) / sizeof(__le32))
#define MAX_INLINE_XATTR_SIZE \
(DEF_ADDRS_PER_INODE - \
F2FS_TOTAL_EXTRA_ATTR_SIZE / sizeof(__le32) - \
--
2.40.1


2023-06-12 03:16:57

by Sheng Yong

[permalink] [raw]
Subject: [PATCH v4 4/6] f2fs: add f2fs_ioc_get_compress_blocks

This patch adds f2fs_ioc_get_compress_blocks() to provide a common
f2fs_get_compress_blocks().

Signed-off-by: Sheng Yong <[email protected]>
---
fs/f2fs/file.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 23c68ee946e58..f8aa842b5d233 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -3376,18 +3376,29 @@ static int f2fs_ioc_setfslabel(struct file *filp, unsigned long arg)
return err;
}

-static int f2fs_get_compress_blocks(struct file *filp, unsigned long arg)
+static int f2fs_get_compress_blocks(struct inode *inode, __u64 *blocks)
{
- struct inode *inode = file_inode(filp);
- __u64 blocks;
-
if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
return -EOPNOTSUPP;

if (!f2fs_compressed_file(inode))
return -EINVAL;

- blocks = atomic_read(&F2FS_I(inode)->i_compr_blocks);
+ *blocks = atomic_read(&F2FS_I(inode)->i_compr_blocks);
+
+ return 0;
+}
+
+static int f2fs_ioc_get_compress_blocks(struct file *filp, unsigned long arg)
+{
+ struct inode *inode = file_inode(filp);
+ __u64 blocks;
+ int ret;
+
+ ret = f2fs_get_compress_blocks(inode, &blocks);
+ if (ret < 0)
+ return ret;
+
return put_user(blocks, (u64 __user *)arg);
}

@@ -4239,7 +4250,7 @@ static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
case FS_IOC_SETFSLABEL:
return f2fs_ioc_setfslabel(filp, arg);
case F2FS_IOC_GET_COMPRESS_BLOCKS:
- return f2fs_get_compress_blocks(filp, arg);
+ return f2fs_ioc_get_compress_blocks(filp, arg);
case F2FS_IOC_RELEASE_COMPRESS_BLOCKS:
return f2fs_release_compress_blocks(filp, arg);
case F2FS_IOC_RESERVE_COMPRESS_BLOCKS:
--
2.40.1


2023-06-12 03:17:03

by Sheng Yong

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

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 <[email protected]>
---
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


2023-06-12 16:34:29

by Jaegeuk Kim

[permalink] [raw]
Subject: Re: [PATCH v4 5/6] f2fs: add f2fs_ioc_[get|set]_extra_attr

On 06/12, Sheng Yong wrote:
> This patch introduces two ioctls:
> * f2fs_ioc_get_extra_attr
> * f2fs_ioc_set_extra_attr
> to get or modify values in f2fs_inode's extra attribute area.

What'd be the main purpose of this new ioctl? Use-cases or examples?

>
> The argument of these two ioctls is `struct f2fs_extra_attr', which has
> three members:
> * field: indicates which field in extra attribute area is handled
> * attr: value or userspace pointer
> * attr_size: size of `attr'
>
> The `field' member could help extend functionality of these two ioctls
> without modify or add new interfaces, if more fields are added into
> extra attributes ares in the feture.
>
> Signed-off-by: Sheng Yong <[email protected]>
> ---
> fs/f2fs/file.c | 205 ++++++++++++++++++++++++++++++++++++++
> include/uapi/linux/f2fs.h | 25 +++++
> 2 files changed, 230 insertions(+)
>
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index f8aa842b5d233..39d04f8f0bb6b 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -4179,6 +4179,207 @@ static int f2fs_ioc_compress_file(struct file *filp)
> return ret;
> }
>
> +static bool extra_attr_fits_in_inode(struct inode *inode, int field)
> +{
> + struct f2fs_inode_info *fi = F2FS_I(inode);
> + struct f2fs_inode *ri;
> +
> + switch (field) {
> + case F2FS_EXTRA_ATTR_TOTAL_SIZE:
> + case F2FS_EXTRA_ATTR_ISIZE:
> + case F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE:
> + return true;
> + case F2FS_EXTRA_ATTR_PROJID:
> + if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_projid))
> + return false;
> + return true;
> + case F2FS_EXTRA_ATTR_INODE_CHKSUM:
> + if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_inode_checksum))
> + return false;
> + return true;
> + case F2FS_EXTRA_ATTR_CRTIME:
> + if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_crtime))
> + return false;
> + return true;
> + case F2FS_EXTRA_ATTR_COMPR_BLOCKS:
> + case F2FS_EXTRA_ATTR_COMPR_OPTION:
> + if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_compr_blocks))
> + return false;
> + return true;
> + default:
> + BUG_ON(1);
> + return false;
> + }
> +}
> +
> +static int f2fs_ioc_get_extra_attr(struct file *filp, unsigned long arg)
> +{
> + struct inode *inode = file_inode(filp);
> + struct f2fs_inode_info *fi = F2FS_I(inode);
> + struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
> + struct f2fs_extra_attr attr;
> + u32 chksum;
> + int ret = 0;
> +
> + if (!f2fs_has_extra_attr(inode))
> + return -EOPNOTSUPP;
> +
> + if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
> + return -EFAULT;
> +
> + if (attr.field >= F2FS_EXTRA_ATTR_MAX)
> + return -EINVAL;
> +
> + if (!extra_attr_fits_in_inode(inode, attr.field))
> + return -EOPNOTSUPP;
> +
> + switch (attr.field) {
> + case F2FS_EXTRA_ATTR_TOTAL_SIZE:
> + attr.attr = F2FS_TOTAL_EXTRA_ATTR_SIZE;
> + break;
> + case F2FS_EXTRA_ATTR_ISIZE:
> + attr.attr = fi->i_extra_isize;
> + break;
> + case F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE:
> + if (!f2fs_has_inline_xattr(inode))
> + return -EOPNOTSUPP;
> + attr.attr = get_inline_xattr_addrs(inode);
> + break;
> + case F2FS_EXTRA_ATTR_PROJID:
> + if (!f2fs_sb_has_project_quota(F2FS_I_SB(inode)))
> + return -EOPNOTSUPP;
> + attr.attr = from_kprojid(&init_user_ns, fi->i_projid);
> + break;
> + case F2FS_EXTRA_ATTR_INODE_CHKSUM:
> + ret = f2fs_inode_chksum_get(sbi, inode, &chksum);
> + if (ret)
> + return ret;
> + attr.attr = chksum;
> + break;
> + case F2FS_EXTRA_ATTR_CRTIME:
> + if (!f2fs_sb_has_inode_crtime(sbi))
> + return -EOPNOTSUPP;
> + if (attr.attr_size == sizeof(struct timespec64)) {
> + if (put_timespec64(&fi->i_crtime,
> + (void __user *)(uintptr_t)attr.attr))
> + return -EFAULT;
> + } else if (attr.attr_size == sizeof(struct old_timespec32)) {
> + if (put_old_timespec32(&fi->i_crtime,
> + (void __user *)(uintptr_t)attr.attr))
> + return -EFAULT;
> + } else {
> + return -EINVAL;
> + }
> + break;
> + case F2FS_EXTRA_ATTR_COMPR_BLOCKS:
> + if (attr.attr_size != sizeof(__u64))
> + return -EINVAL;
> + ret = f2fs_get_compress_blocks(inode, &attr.attr);
> + break;
> + case F2FS_EXTRA_ATTR_COMPR_OPTION:
> + ret = f2fs_ioc_get_compress_option(filp, attr.attr);
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + if (ret < 0)
> + return ret;
> +
> + if (copy_to_user((void __user *)arg, &attr, sizeof(attr)))
> + return -EFAULT;
> +
> + return 0;
> +}
> +
> +static int f2fs_ioc_set_extra_attr(struct file *filp, unsigned long arg)
> +{
> + struct inode *inode = file_inode(filp);
> + struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
> + struct f2fs_extra_attr attr;
> + struct page *ipage;
> + void *inline_addr;
> + int ret;
> +
> + if (!f2fs_has_extra_attr(inode))
> + return -EOPNOTSUPP;
> +
> + if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
> + return -EFAULT;
> +
> + if (attr.field >= F2FS_EXTRA_ATTR_MAX)
> + return -EINVAL;
> +
> + if (!extra_attr_fits_in_inode(inode, attr.field))
> + return -EOPNOTSUPP;
> +
> + switch (attr.field) {
> + case F2FS_EXTRA_ATTR_TOTAL_SIZE:
> + case F2FS_EXTRA_ATTR_ISIZE:
> + case F2FS_EXTRA_ATTR_PROJID:
> + case F2FS_EXTRA_ATTR_INODE_CHKSUM:
> + case F2FS_EXTRA_ATTR_CRTIME:
> + case F2FS_EXTRA_ATTR_COMPR_BLOCKS:
> + /* read only attribtues */
> + return -EOPNOTSUPP;
> + case F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE:
> + if (!f2fs_sb_has_flexible_inline_xattr(sbi) ||
> + !f2fs_has_inline_xattr(inode))
> + return -EOPNOTSUPP;
> + if (attr.attr < MIN_INLINE_XATTR_SIZE ||
> + attr.attr > MAX_INLINE_XATTR_SIZE)
> + return -EINVAL;
> + inode_lock(inode);
> + f2fs_lock_op(sbi);
> + f2fs_down_write(&F2FS_I(inode)->i_xattr_sem);
> + if (i_size_read(inode) || F2FS_I(inode)->i_xattr_nid) {
> + /*
> + * it is not allowed to set this field if the inode
> + * has data or xattr node
> + */
> + ret = -EFBIG;
> + goto xattr_out_unlock;
> + }
> + ipage = f2fs_get_node_page(sbi, inode->i_ino);
> + if (IS_ERR(ipage)) {
> + ret = PTR_ERR(ipage);
> + goto xattr_out_unlock;
> + }
> + inline_addr = inline_xattr_addr(inode, ipage);
> + if (!IS_XATTR_LAST_ENTRY(XATTR_FIRST_ENTRY(inline_addr))) {
> + ret = -EFBIG;
> + } else {
> + struct f2fs_xattr_header *hdr;
> + struct f2fs_xattr_entry *ent;
> +
> + F2FS_I(inode)->i_inline_xattr_size = (int)attr.attr;
> + inline_addr = inline_xattr_addr(inode, ipage);
> + hdr = XATTR_HDR(inline_addr);
> + ent = XATTR_FIRST_ENTRY(inline_addr);
> + hdr->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC);
> + hdr->h_refcount = cpu_to_le32(1);
> + memset(ent, 0, attr.attr - sizeof(*hdr));
> + set_page_dirty(ipage);
> + ret = 0;
> + }
> + f2fs_put_page(ipage, 1);
> +xattr_out_unlock:
> + f2fs_up_write(&F2FS_I(inode)->i_xattr_sem);
> + f2fs_unlock_op(sbi);
> + inode_unlock(inode);
> + if (!ret)
> + f2fs_balance_fs(sbi, true);
> + break;
> + case F2FS_EXTRA_ATTR_COMPR_OPTION:
> + ret = f2fs_ioc_set_compress_option(filp, attr.attr);
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return ret;
> +}
> +
> static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> {
> switch (cmd) {
> @@ -4265,6 +4466,10 @@ static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> return f2fs_ioc_decompress_file(filp);
> case F2FS_IOC_COMPRESS_FILE:
> return f2fs_ioc_compress_file(filp);
> + case F2FS_IOC_GET_EXTRA_ATTR:
> + return f2fs_ioc_get_extra_attr(filp, arg);
> + case F2FS_IOC_SET_EXTRA_ATTR:
> + return f2fs_ioc_set_extra_attr(filp, arg);
> default:
> return -ENOTTY;
> }
> diff --git a/include/uapi/linux/f2fs.h b/include/uapi/linux/f2fs.h
> index 955d440be1046..2b53e90421bfc 100644
> --- a/include/uapi/linux/f2fs.h
> +++ b/include/uapi/linux/f2fs.h
> @@ -43,6 +43,10 @@
> #define F2FS_IOC_DECOMPRESS_FILE _IO(F2FS_IOCTL_MAGIC, 23)
> #define F2FS_IOC_COMPRESS_FILE _IO(F2FS_IOCTL_MAGIC, 24)
> #define F2FS_IOC_START_ATOMIC_REPLACE _IO(F2FS_IOCTL_MAGIC, 25)
> +#define F2FS_IOC_GET_EXTRA_ATTR _IOR(F2FS_IOCTL_MAGIC, 26, \
> + struct f2fs_extra_attr)
> +#define F2FS_IOC_SET_EXTRA_ATTR _IOW(F2FS_IOCTL_MAGIC, 27, \
> + struct f2fs_extra_attr)
>
> /*
> * should be same as XFS_IOC_GOINGDOWN.
> @@ -96,4 +100,25 @@ struct f2fs_comp_option {
> __u8 log_cluster_size;
> };
>
> +enum {
> + F2FS_EXTRA_ATTR_TOTAL_SIZE, /* ro, size of extra attr area */
> + F2FS_EXTRA_ATTR_ISIZE, /* ro, i_extra_isize */
> + F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE, /* rw, i_inline_xattr_size */
> + F2FS_EXTRA_ATTR_PROJID, /* ro, i_projid */
> + F2FS_EXTRA_ATTR_INODE_CHKSUM, /* ro, i_inode_chksum */
> + 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
> + */
> + F2FS_EXTRA_ATTR_MAX,
> +};
> +
> +struct f2fs_extra_attr {
> + __u8 field; /* F2FS_EXTRA_ATTR_* */
> + __u8 rsvd1;
> + __u16 attr_size; /* size of @attr */
> + __u32 rsvd2;
> + __u64 attr; /* attr value or pointer */
> +};
> #endif /* _UAPI_LINUX_F2FS_H */
> --
> 2.40.1

2023-06-12 23:03:05

by Jaegeuk Kim

[permalink] [raw]
Subject: Re: [PATCH v4 1/6] f2fs: add helper to check compression level

Could you please check this version?

https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git/commit/?h=dev-test&id=9c84aad379019a0d86655bb50bd7b4bc92683c4b

On 06/12, Sheng Yong wrote:
> This patch adds a helper function to check if compression level is
> valid.
>
> Signed-off-by: Sheng Yong <[email protected]>
> ---
> fs/f2fs/compress.c | 31 +++++++++++++++++++++++++++++++
> fs/f2fs/f2fs.h | 2 ++
> fs/f2fs/super.c | 4 ++--
> 3 files changed, 35 insertions(+), 2 deletions(-)
>
> diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
> index 1132d3cd8f337..63a496137ebe7 100644
> --- a/fs/f2fs/compress.c
> +++ b/fs/f2fs/compress.c
> @@ -55,6 +55,7 @@ struct f2fs_compress_ops {
> int (*init_decompress_ctx)(struct decompress_io_ctx *dic);
> void (*destroy_decompress_ctx)(struct decompress_io_ctx *dic);
> int (*decompress_pages)(struct decompress_io_ctx *dic);
> + bool (*is_level_valid)(int level);
> };
>
> static unsigned int offset_in_cluster(struct compress_ctx *cc, pgoff_t index)
> @@ -308,11 +309,23 @@ static int lz4_decompress_pages(struct decompress_io_ctx *dic)
> return 0;
> }
>
> +static bool lz4_is_level_valid(int lvl)
> +{
> + if (lvl == 0)
> + return true;
> +#ifdef CONFIG_F2FS_FS_LZ4HC
> + if (lvl >= LZ4HC_MIN_CLEVEL && lvl <= LZ4HC_MAX_CLEVEL)
> + return true;
> +#endif
> + return false;
> +}
> +
> static const struct f2fs_compress_ops f2fs_lz4_ops = {
> .init_compress_ctx = lz4_init_compress_ctx,
> .destroy_compress_ctx = lz4_destroy_compress_ctx,
> .compress_pages = lz4_compress_pages,
> .decompress_pages = lz4_decompress_pages,
> + .is_level_valid = lz4_is_level_valid,
> };
> #endif
>
> @@ -477,6 +490,13 @@ static int zstd_decompress_pages(struct decompress_io_ctx *dic)
> return 0;
> }
>
> +static bool zstd_is_level_valid(int lvl)
> +{
> + if (lvl < zstd_min_clevel() || lvl > zstd_max_clevel())
> + return false;
> + return true;
> +}
> +
> static const struct f2fs_compress_ops f2fs_zstd_ops = {
> .init_compress_ctx = zstd_init_compress_ctx,
> .destroy_compress_ctx = zstd_destroy_compress_ctx,
> @@ -484,6 +504,7 @@ static const struct f2fs_compress_ops f2fs_zstd_ops = {
> .init_decompress_ctx = zstd_init_decompress_ctx,
> .destroy_decompress_ctx = zstd_destroy_decompress_ctx,
> .decompress_pages = zstd_decompress_pages,
> + .is_level_valid = zstd_is_level_valid,
> };
> #endif
>
> @@ -542,6 +563,16 @@ bool f2fs_is_compress_backend_ready(struct inode *inode)
> return f2fs_cops[F2FS_I(inode)->i_compress_algorithm];
> }
>
> +bool f2fs_is_compress_level_valid(int alg, int lvl)
> +{
> + const struct f2fs_compress_ops *cops = f2fs_cops[alg];
> +
> + if (cops->is_level_valid)
> + return cops->is_level_valid(lvl);
> +
> + return lvl == 0;
> +}
> +
> static mempool_t *compress_page_pool;
> static int num_compress_pages = 512;
> module_param(num_compress_pages, uint, 0444);
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 80c783215b5a3..1b17bbe7e8656 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -4236,6 +4236,7 @@ bool f2fs_compress_write_end(struct inode *inode, void *fsdata,
> int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock);
> void f2fs_compress_write_end_io(struct bio *bio, struct page *page);
> bool f2fs_is_compress_backend_ready(struct inode *inode);
> +bool f2fs_is_compress_level_valid(int alg, int lvl);
> int __init f2fs_init_compress_mempool(void);
> void f2fs_destroy_compress_mempool(void);
> void f2fs_decompress_cluster(struct decompress_io_ctx *dic, bool in_task);
> @@ -4300,6 +4301,7 @@ static inline bool f2fs_is_compress_backend_ready(struct inode *inode)
> /* not support compression */
> return false;
> }
> +static inline bool f2fs_is_compress_level_valid(int alg, int lvl) { return false; }
> static inline struct page *f2fs_compress_control_page(struct page *page)
> {
> WARN_ON_ONCE(1);
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index 8fd23caa1ed99..023981824d240 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -606,7 +606,7 @@ static int f2fs_set_lz4hc_level(struct f2fs_sb_info *sbi, const char *str)
> if (kstrtouint(str + 1, 10, &level))
> return -EINVAL;
>
> - if (level < LZ4HC_MIN_CLEVEL || level > LZ4HC_MAX_CLEVEL) {
> + if (!f2fs_is_compress_level_valid(COMPRESS_LZ4, level)) {
> f2fs_info(sbi, "invalid lz4hc compress level: %d", level);
> return -EINVAL;
> }
> @@ -640,7 +640,7 @@ static int f2fs_set_zstd_level(struct f2fs_sb_info *sbi, const char *str)
> if (kstrtouint(str + 1, 10, &level))
> return -EINVAL;
>
> - if (!level || level > zstd_max_clevel()) {
> + if (!f2fs_is_compress_level_valid(COMPRESS_ZSTD, level)) {
> f2fs_info(sbi, "invalid zstd compress level: %d", level);
> return -EINVAL;
> }
> --
> 2.40.1

2023-06-13 02:09:34

by Chao Yu

[permalink] [raw]
Subject: Re: [PATCH v4 4/6] f2fs: add f2fs_ioc_get_compress_blocks

On 2023/6/12 11:01, Sheng Yong wrote:
> This patch adds f2fs_ioc_get_compress_blocks() to provide a common
> f2fs_get_compress_blocks().
>
> Signed-off-by: Sheng Yong <[email protected]>

Reviewed-by: Chao Yu <[email protected]>

Thanks,

2023-06-13 02:10:33

by Sheng Yong

[permalink] [raw]
Subject: Re: [PATCH v4 5/6] f2fs: add f2fs_ioc_[get|set]_extra_attr



On 2023/6/12 23:47, Jaegeuk Kim wrote:
> On 06/12, Sheng Yong wrote:
>> This patch introduces two ioctls:
>> * f2fs_ioc_get_extra_attr
>> * f2fs_ioc_set_extra_attr
>> to get or modify values in f2fs_inode's extra attribute area.
>
> What'd be the main purpose of this new ioctl? Use-cases or examples?

Hi, Jaegeuk,

When a new feature is added, f2fs_inode extra attributes needs to be
extended sometimes to save status or control values, say compression,
inode chksum, inode crtime.

If some of them could be read or modified during runtime, a new ioctl
is required in most cases, like F2FS_IOC_GET_COMPRESS_BLOCKS,
F2FS_IOC_GET_COMPRESS_OPTION...
And Yangtao [1] and I [2] also tried to add new ioctls to allow getting
and settingcompress level and flags.

If new features are added in the future, we may get a verty long and
not-easy-to-extend ioctl list.

So these 2 ioctls could help manage all extra attributes:
* if a new extra attribute is added, we only need to add a new field type,
and corresponding get/set functions
* attr_size can indicate which version of attribute is used
* besides, ioc_set_extra_attr(i_inline_xattr_size) gives us a chance to
adjust inline xattr size for an empty file

thanks,
shengyong

Links:
[1] https://lore.kernel.org/linux-f2fs-devel/[email protected]/
[2] https://sourceforge.net/p/linux-f2fs/mailman/linux-f2fs-devel/?viewmonth=202303
>
>>
>> The argument of these two ioctls is `struct f2fs_extra_attr', which has
>> three members:
>> * field: indicates which field in extra attribute area is handled
>> * attr: value or userspace pointer
>> * attr_size: size of `attr'
>>
>> The `field' member could help extend functionality of these two ioctls
>> without modify or add new interfaces, if more fields are added into
>> extra attributes ares in the feture.
>>
>> Signed-off-by: Sheng Yong <[email protected]>
>> ---
>> fs/f2fs/file.c | 205 ++++++++++++++++++++++++++++++++++++++
>> include/uapi/linux/f2fs.h | 25 +++++
>> 2 files changed, 230 insertions(+)
>>
>> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
>> index f8aa842b5d233..39d04f8f0bb6b 100644
>> --- a/fs/f2fs/file.c
>> +++ b/fs/f2fs/file.c
>> @@ -4179,6 +4179,207 @@ static int f2fs_ioc_compress_file(struct file *filp)
>> return ret;
>> }
>>
>> +static bool extra_attr_fits_in_inode(struct inode *inode, int field)
>> +{
>> + struct f2fs_inode_info *fi = F2FS_I(inode);
>> + struct f2fs_inode *ri;
>> +
>> + switch (field) {
>> + case F2FS_EXTRA_ATTR_TOTAL_SIZE:
>> + case F2FS_EXTRA_ATTR_ISIZE:
>> + case F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE:
>> + return true;
>> + case F2FS_EXTRA_ATTR_PROJID:
>> + if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_projid))
>> + return false;
>> + return true;
>> + case F2FS_EXTRA_ATTR_INODE_CHKSUM:
>> + if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_inode_checksum))
>> + return false;
>> + return true;
>> + case F2FS_EXTRA_ATTR_CRTIME:
>> + if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_crtime))
>> + return false;
>> + return true;
>> + case F2FS_EXTRA_ATTR_COMPR_BLOCKS:
>> + case F2FS_EXTRA_ATTR_COMPR_OPTION:
>> + if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_compr_blocks))
>> + return false;
>> + return true;
>> + default:
>> + BUG_ON(1);
>> + return false;
>> + }
>> +}
>> +
>> +static int f2fs_ioc_get_extra_attr(struct file *filp, unsigned long arg)
>> +{
>> + struct inode *inode = file_inode(filp);
>> + struct f2fs_inode_info *fi = F2FS_I(inode);
>> + struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
>> + struct f2fs_extra_attr attr;
>> + u32 chksum;
>> + int ret = 0;
>> +
>> + if (!f2fs_has_extra_attr(inode))
>> + return -EOPNOTSUPP;
>> +
>> + if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
>> + return -EFAULT;
>> +
>> + if (attr.field >= F2FS_EXTRA_ATTR_MAX)
>> + return -EINVAL;
>> +
>> + if (!extra_attr_fits_in_inode(inode, attr.field))
>> + return -EOPNOTSUPP;
>> +
>> + switch (attr.field) {
>> + case F2FS_EXTRA_ATTR_TOTAL_SIZE:
>> + attr.attr = F2FS_TOTAL_EXTRA_ATTR_SIZE;
>> + break;
>> + case F2FS_EXTRA_ATTR_ISIZE:
>> + attr.attr = fi->i_extra_isize;
>> + break;
>> + case F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE:
>> + if (!f2fs_has_inline_xattr(inode))
>> + return -EOPNOTSUPP;
>> + attr.attr = get_inline_xattr_addrs(inode);
>> + break;
>> + case F2FS_EXTRA_ATTR_PROJID:
>> + if (!f2fs_sb_has_project_quota(F2FS_I_SB(inode)))
>> + return -EOPNOTSUPP;
>> + attr.attr = from_kprojid(&init_user_ns, fi->i_projid);
>> + break;
>> + case F2FS_EXTRA_ATTR_INODE_CHKSUM:
>> + ret = f2fs_inode_chksum_get(sbi, inode, &chksum);
>> + if (ret)
>> + return ret;
>> + attr.attr = chksum;
>> + break;
>> + case F2FS_EXTRA_ATTR_CRTIME:
>> + if (!f2fs_sb_has_inode_crtime(sbi))
>> + return -EOPNOTSUPP;
>> + if (attr.attr_size == sizeof(struct timespec64)) {
>> + if (put_timespec64(&fi->i_crtime,
>> + (void __user *)(uintptr_t)attr.attr))
>> + return -EFAULT;
>> + } else if (attr.attr_size == sizeof(struct old_timespec32)) {
>> + if (put_old_timespec32(&fi->i_crtime,
>> + (void __user *)(uintptr_t)attr.attr))
>> + return -EFAULT;
>> + } else {
>> + return -EINVAL;
>> + }
>> + break;
>> + case F2FS_EXTRA_ATTR_COMPR_BLOCKS:
>> + if (attr.attr_size != sizeof(__u64))
>> + return -EINVAL;
>> + ret = f2fs_get_compress_blocks(inode, &attr.attr);
>> + break;
>> + case F2FS_EXTRA_ATTR_COMPR_OPTION:
>> + ret = f2fs_ioc_get_compress_option(filp, attr.attr);
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> +
>> + if (ret < 0)
>> + return ret;
>> +
>> + if (copy_to_user((void __user *)arg, &attr, sizeof(attr)))
>> + return -EFAULT;
>> +
>> + return 0;
>> +}
>> +
>> +static int f2fs_ioc_set_extra_attr(struct file *filp, unsigned long arg)
>> +{
>> + struct inode *inode = file_inode(filp);
>> + struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
>> + struct f2fs_extra_attr attr;
>> + struct page *ipage;
>> + void *inline_addr;
>> + int ret;
>> +
>> + if (!f2fs_has_extra_attr(inode))
>> + return -EOPNOTSUPP;
>> +
>> + if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
>> + return -EFAULT;
>> +
>> + if (attr.field >= F2FS_EXTRA_ATTR_MAX)
>> + return -EINVAL;
>> +
>> + if (!extra_attr_fits_in_inode(inode, attr.field))
>> + return -EOPNOTSUPP;
>> +
>> + switch (attr.field) {
>> + case F2FS_EXTRA_ATTR_TOTAL_SIZE:
>> + case F2FS_EXTRA_ATTR_ISIZE:
>> + case F2FS_EXTRA_ATTR_PROJID:
>> + case F2FS_EXTRA_ATTR_INODE_CHKSUM:
>> + case F2FS_EXTRA_ATTR_CRTIME:
>> + case F2FS_EXTRA_ATTR_COMPR_BLOCKS:
>> + /* read only attribtues */
>> + return -EOPNOTSUPP;
>> + case F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE:
>> + if (!f2fs_sb_has_flexible_inline_xattr(sbi) ||
>> + !f2fs_has_inline_xattr(inode))
>> + return -EOPNOTSUPP;
>> + if (attr.attr < MIN_INLINE_XATTR_SIZE ||
>> + attr.attr > MAX_INLINE_XATTR_SIZE)
>> + return -EINVAL;
>> + inode_lock(inode);
>> + f2fs_lock_op(sbi);
>> + f2fs_down_write(&F2FS_I(inode)->i_xattr_sem);
>> + if (i_size_read(inode) || F2FS_I(inode)->i_xattr_nid) {
>> + /*
>> + * it is not allowed to set this field if the inode
>> + * has data or xattr node
>> + */
>> + ret = -EFBIG;
>> + goto xattr_out_unlock;
>> + }
>> + ipage = f2fs_get_node_page(sbi, inode->i_ino);
>> + if (IS_ERR(ipage)) {
>> + ret = PTR_ERR(ipage);
>> + goto xattr_out_unlock;
>> + }
>> + inline_addr = inline_xattr_addr(inode, ipage);
>> + if (!IS_XATTR_LAST_ENTRY(XATTR_FIRST_ENTRY(inline_addr))) {
>> + ret = -EFBIG;
>> + } else {
>> + struct f2fs_xattr_header *hdr;
>> + struct f2fs_xattr_entry *ent;
>> +
>> + F2FS_I(inode)->i_inline_xattr_size = (int)attr.attr;
>> + inline_addr = inline_xattr_addr(inode, ipage);
>> + hdr = XATTR_HDR(inline_addr);
>> + ent = XATTR_FIRST_ENTRY(inline_addr);
>> + hdr->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC);
>> + hdr->h_refcount = cpu_to_le32(1);
>> + memset(ent, 0, attr.attr - sizeof(*hdr));
>> + set_page_dirty(ipage);
>> + ret = 0;
>> + }
>> + f2fs_put_page(ipage, 1);
>> +xattr_out_unlock:
>> + f2fs_up_write(&F2FS_I(inode)->i_xattr_sem);
>> + f2fs_unlock_op(sbi);
>> + inode_unlock(inode);
>> + if (!ret)
>> + f2fs_balance_fs(sbi, true);
>> + break;
>> + case F2FS_EXTRA_ATTR_COMPR_OPTION:
>> + ret = f2fs_ioc_set_compress_option(filp, attr.attr);
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> +
>> + return ret;
>> +}
>> +
>> static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
>> {
>> switch (cmd) {
>> @@ -4265,6 +4466,10 @@ static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
>> return f2fs_ioc_decompress_file(filp);
>> case F2FS_IOC_COMPRESS_FILE:
>> return f2fs_ioc_compress_file(filp);
>> + case F2FS_IOC_GET_EXTRA_ATTR:
>> + return f2fs_ioc_get_extra_attr(filp, arg);
>> + case F2FS_IOC_SET_EXTRA_ATTR:
>> + return f2fs_ioc_set_extra_attr(filp, arg);
>> default:
>> return -ENOTTY;
>> }
>> diff --git a/include/uapi/linux/f2fs.h b/include/uapi/linux/f2fs.h
>> index 955d440be1046..2b53e90421bfc 100644
>> --- a/include/uapi/linux/f2fs.h
>> +++ b/include/uapi/linux/f2fs.h
>> @@ -43,6 +43,10 @@
>> #define F2FS_IOC_DECOMPRESS_FILE _IO(F2FS_IOCTL_MAGIC, 23)
>> #define F2FS_IOC_COMPRESS_FILE _IO(F2FS_IOCTL_MAGIC, 24)
>> #define F2FS_IOC_START_ATOMIC_REPLACE _IO(F2FS_IOCTL_MAGIC, 25)
>> +#define F2FS_IOC_GET_EXTRA_ATTR _IOR(F2FS_IOCTL_MAGIC, 26, \
>> + struct f2fs_extra_attr)
>> +#define F2FS_IOC_SET_EXTRA_ATTR _IOW(F2FS_IOCTL_MAGIC, 27, \
>> + struct f2fs_extra_attr)
>>
>> /*
>> * should be same as XFS_IOC_GOINGDOWN.
>> @@ -96,4 +100,25 @@ struct f2fs_comp_option {
>> __u8 log_cluster_size;
>> };
>>
>> +enum {
>> + F2FS_EXTRA_ATTR_TOTAL_SIZE, /* ro, size of extra attr area */
>> + F2FS_EXTRA_ATTR_ISIZE, /* ro, i_extra_isize */
>> + F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE, /* rw, i_inline_xattr_size */
>> + F2FS_EXTRA_ATTR_PROJID, /* ro, i_projid */
>> + F2FS_EXTRA_ATTR_INODE_CHKSUM, /* ro, i_inode_chksum */
>> + 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
>> + */
>> + F2FS_EXTRA_ATTR_MAX,
>> +};
>> +
>> +struct f2fs_extra_attr {
>> + __u8 field; /* F2FS_EXTRA_ATTR_* */
>> + __u8 rsvd1;
>> + __u16 attr_size; /* size of @attr */
>> + __u32 rsvd2;
>> + __u64 attr; /* attr value or pointer */
>> +};
>> #endif /* _UAPI_LINUX_F2FS_H */
>> --
>> 2.40.1

2023-06-13 02:20:28

by Chao Yu

[permalink] [raw]
Subject: Re: [PATCH v4 2/6] f2fs: cleanup MIN_INLINE_XATTR_SIZE

On 2023/6/12 11:01, Sheng Yong wrote:
> Signed-off-by: Sheng Yong <[email protected]>

Reviewed-by: Chao Yu <[email protected]>

Thanks,

2023-06-13 02:21:35

by Chao Yu

[permalink] [raw]
Subject: Re: [PATCH v4 1/6] f2fs: add helper to check compression level

On 2023/6/13 6:14, Jaegeuk Kim wrote:
> Could you please check this version?
>
> https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git/commit/?h=dev-test&id=9c84aad379019a0d86655bb50bd7b4bc92683c4b
>
> On 06/12, Sheng Yong wrote:
>> This patch adds a helper function to check if compression level is
>> valid.
>>
>> Signed-off-by: Sheng Yong <[email protected]>

Reviewed-by: Chao Yu <[email protected]>

Thanks,

2023-06-13 02:25:46

by Chao Yu

[permalink] [raw]
Subject: Re: [PATCH v4 3/6] f2fs: add helper to get inode chksum from inode page

On 2023/6/12 11:01, Sheng Yong wrote:
> Signed-off-by: Sheng Yong <[email protected]>

Reviewed-by: Chao Yu <[email protected]>

Thanks,

2023-06-13 03:00:39

by Sheng Yong

[permalink] [raw]
Subject: Re: [PATCH v4 1/6] f2fs: add helper to check compression level


On 2023/6/13 6:14, Jaegeuk Kim wrote:
> Could you please check this version?
>
> https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git/commit/?h=dev-test&id=9c84aad379019a0d86655bb50bd7b4bc92683c4b

Hi, Jaegeuk,

Thanks for cleaning it up. This version looks good to me. I tested it
with my testcases, and all are passed.

thanks,
shengyong
>
> On 06/12, Sheng Yong wrote:
>> This patch adds a helper function to check if compression level is
>> valid.
>>
>> Signed-off-by: Sheng Yong <[email protected]>
>> ---
>> fs/f2fs/compress.c | 31 +++++++++++++++++++++++++++++++
>> fs/f2fs/f2fs.h | 2 ++
>> fs/f2fs/super.c | 4 ++--
>> 3 files changed, 35 insertions(+), 2 deletions(-)
>>
>> diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
>> index 1132d3cd8f337..63a496137ebe7 100644
>> --- a/fs/f2fs/compress.c
>> +++ b/fs/f2fs/compress.c
>> @@ -55,6 +55,7 @@ struct f2fs_compress_ops {
>> int (*init_decompress_ctx)(struct decompress_io_ctx *dic);
>> void (*destroy_decompress_ctx)(struct decompress_io_ctx *dic);
>> int (*decompress_pages)(struct decompress_io_ctx *dic);
>> + bool (*is_level_valid)(int level);
>> };
>>
>> static unsigned int offset_in_cluster(struct compress_ctx *cc, pgoff_t index)
>> @@ -308,11 +309,23 @@ static int lz4_decompress_pages(struct decompress_io_ctx *dic)
>> return 0;
>> }
>>
>> +static bool lz4_is_level_valid(int lvl)
>> +{
>> + if (lvl == 0)
>> + return true;
>> +#ifdef CONFIG_F2FS_FS_LZ4HC
>> + if (lvl >= LZ4HC_MIN_CLEVEL && lvl <= LZ4HC_MAX_CLEVEL)
>> + return true;
>> +#endif
>> + return false;
>> +}
>> +
>> static const struct f2fs_compress_ops f2fs_lz4_ops = {
>> .init_compress_ctx = lz4_init_compress_ctx,
>> .destroy_compress_ctx = lz4_destroy_compress_ctx,
>> .compress_pages = lz4_compress_pages,
>> .decompress_pages = lz4_decompress_pages,
>> + .is_level_valid = lz4_is_level_valid,
>> };
>> #endif
>>
>> @@ -477,6 +490,13 @@ static int zstd_decompress_pages(struct decompress_io_ctx *dic)
>> return 0;
>> }
>>
>> +static bool zstd_is_level_valid(int lvl)
>> +{
>> + if (lvl < zstd_min_clevel() || lvl > zstd_max_clevel())
>> + return false;
>> + return true;
>> +}
>> +
>> static const struct f2fs_compress_ops f2fs_zstd_ops = {
>> .init_compress_ctx = zstd_init_compress_ctx,
>> .destroy_compress_ctx = zstd_destroy_compress_ctx,
>> @@ -484,6 +504,7 @@ static const struct f2fs_compress_ops f2fs_zstd_ops = {
>> .init_decompress_ctx = zstd_init_decompress_ctx,
>> .destroy_decompress_ctx = zstd_destroy_decompress_ctx,
>> .decompress_pages = zstd_decompress_pages,
>> + .is_level_valid = zstd_is_level_valid,
>> };
>> #endif
>>
>> @@ -542,6 +563,16 @@ bool f2fs_is_compress_backend_ready(struct inode *inode)
>> return f2fs_cops[F2FS_I(inode)->i_compress_algorithm];
>> }
>>
>> +bool f2fs_is_compress_level_valid(int alg, int lvl)
>> +{
>> + const struct f2fs_compress_ops *cops = f2fs_cops[alg];
>> +
>> + if (cops->is_level_valid)
>> + return cops->is_level_valid(lvl);
>> +
>> + return lvl == 0;
>> +}
>> +
>> static mempool_t *compress_page_pool;
>> static int num_compress_pages = 512;
>> module_param(num_compress_pages, uint, 0444);
>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
>> index 80c783215b5a3..1b17bbe7e8656 100644
>> --- a/fs/f2fs/f2fs.h
>> +++ b/fs/f2fs/f2fs.h
>> @@ -4236,6 +4236,7 @@ bool f2fs_compress_write_end(struct inode *inode, void *fsdata,
>> int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock);
>> void f2fs_compress_write_end_io(struct bio *bio, struct page *page);
>> bool f2fs_is_compress_backend_ready(struct inode *inode);
>> +bool f2fs_is_compress_level_valid(int alg, int lvl);
>> int __init f2fs_init_compress_mempool(void);
>> void f2fs_destroy_compress_mempool(void);
>> void f2fs_decompress_cluster(struct decompress_io_ctx *dic, bool in_task);
>> @@ -4300,6 +4301,7 @@ static inline bool f2fs_is_compress_backend_ready(struct inode *inode)
>> /* not support compression */
>> return false;
>> }
>> +static inline bool f2fs_is_compress_level_valid(int alg, int lvl) { return false; }
>> static inline struct page *f2fs_compress_control_page(struct page *page)
>> {
>> WARN_ON_ONCE(1);
>> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
>> index 8fd23caa1ed99..023981824d240 100644
>> --- a/fs/f2fs/super.c
>> +++ b/fs/f2fs/super.c
>> @@ -606,7 +606,7 @@ static int f2fs_set_lz4hc_level(struct f2fs_sb_info *sbi, const char *str)
>> if (kstrtouint(str + 1, 10, &level))
>> return -EINVAL;
>>
>> - if (level < LZ4HC_MIN_CLEVEL || level > LZ4HC_MAX_CLEVEL) {
>> + if (!f2fs_is_compress_level_valid(COMPRESS_LZ4, level)) {
>> f2fs_info(sbi, "invalid lz4hc compress level: %d", level);
>> return -EINVAL;
>> }
>> @@ -640,7 +640,7 @@ static int f2fs_set_zstd_level(struct f2fs_sb_info *sbi, const char *str)
>> if (kstrtouint(str + 1, 10, &level))
>> return -EINVAL;
>>
>> - if (!level || level > zstd_max_clevel()) {
>> + if (!f2fs_is_compress_level_valid(COMPRESS_ZSTD, level)) {
>> f2fs_info(sbi, "invalid zstd compress level: %d", level);
>> return -EINVAL;
>> }
>> --
>> 2.40.1

2023-06-15 18:15:08

by patchwork-bot+f2fs

[permalink] [raw]
Subject: Re: [f2fs-dev] [PATCH v4 0/6] f2fs: add f2fs_ioc_[get|set]_extra_attr

Hello:

This series was applied to jaegeuk/f2fs.git (dev)
by Jaegeuk Kim <[email protected]>:

On Mon, 12 Jun 2023 11:01:15 +0800 you wrote:
> This patchset introduces two ioctls to get or modify values in
> f2fs_inode's extra attribute area:
> * f2fs_ioc_get_extra_attr
> * f2fs_ioc_set_extra_attr
>
> The argument of these two ioctls is `struct f2fs_extra_attr', which has
> three members:
> * field: indicates which field in extra attribute area is handled
> * attr: value or userspace pointer
> * attr_size: size of `attr'
>
> [...]

Here is the summary with links:
- [f2fs-dev,v4,1/6] f2fs: add helper to check compression level
(no matching commit)
- [f2fs-dev,v4,2/6] f2fs: cleanup MIN_INLINE_XATTR_SIZE
https://git.kernel.org/jaegeuk/f2fs/c/4acc6b9d6104
- [f2fs-dev,v4,3/6] f2fs: add helper to get inode chksum from inode page
(no matching commit)
- [f2fs-dev,v4,4/6] f2fs: add f2fs_ioc_get_compress_blocks
https://git.kernel.org/jaegeuk/f2fs/c/1c5c646596c6
- [f2fs-dev,v4,5/6] f2fs: add f2fs_ioc_[get|set]_extra_attr
(no matching commit)
- [f2fs-dev,v4,6/6] f2fs: access compression level and flags by extra attr ioctls
(no matching commit)

You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html