linux-f2fs-devel.lists.sourceforge.net archive mirror
 help / color / mirror / Atom feed
* [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr
@ 2023-05-29  1:35 Sheng Yong via Linux-f2fs-devel
  2023-05-29  1:35 ` [f2fs-dev] [PATCH 1/2] f2fs_io: add [get|set_attr] to access inode extra attributes Sheng Yong via Linux-f2fs-devel
                   ` (6 more replies)
  0 siblings, 7 replies; 15+ messages in thread
From: Sheng Yong via Linux-f2fs-devel @ 2023-05-29  1:35 UTC (permalink / raw)
  To: jaegeuk, chao; +Cc: linux-kernel, linux-f2fs-devel

This patch introduces two ioctls:
  * f2fs_ioc_get_extra_attr
  * f2fs_ioc_set_extra_attr
to get or modify values in 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 <shengyong@oppo.com>
---
 fs/f2fs/f2fs.h            |   2 +
 fs/f2fs/file.c            | 289 ++++++++++++++++++++++++++++++++++++--
 fs/f2fs/inode.c           |  21 +++
 fs/f2fs/super.c           |   2 +-
 fs/f2fs/xattr.h           |   1 +
 include/uapi/linux/f2fs.h |  35 +++++
 6 files changed, 337 insertions(+), 13 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index faa27f41f39d4..08e8527734df5 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3475,6 +3475,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/file.c b/fs/f2fs/file.c
index 78aa8cff4b41d..cdb192faf7c36 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -25,6 +25,8 @@
 #include <linux/fileattr.h>
 #include <linux/fadvise.h>
 #include <linux/iomap.h>
+#include <linux/lz4.h>
+#include <linux/zstd.h>
 
 #include "f2fs.h"
 #include "node.h"
@@ -3376,10 +3378,12 @@ 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 file *filp, unsigned int attr_size)
 {
 	struct inode *inode = file_inode(filp);
-	__u64 blocks;
+
+	if (attr_size != sizeof(__u64))
+		return -EINVAL;
 
 	if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
 		return -EOPNOTSUPP;
@@ -3387,7 +3391,14 @@ static int f2fs_get_compress_blocks(struct file *filp, unsigned long arg)
 	if (!f2fs_compressed_file(inode))
 		return -EINVAL;
 
-	blocks = atomic_read(&F2FS_I(inode)->i_compr_blocks);
+	return atomic_read(&F2FS_I(inode)->i_compr_blocks);
+}
+
+static int f2fs_ioc_get_compress_blocks(struct file *filp, unsigned long arg)
+{
+	__u64 blocks;
+
+	blocks = f2fs_get_compress_blocks(filp, sizeof(blocks));
 	return put_user(blocks, (u64 __user *)arg);
 }
 
@@ -3905,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;
@@ -3922,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) ||
@@ -3955,6 +3981,28 @@ 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 (option.level != 0) {
+			switch (option.algorithm) {
+			case COMPRESS_LZO:
+			case COMPRESS_LZORLE:
+				return -EINVAL;
+			case COMPRESS_LZ4:
+				if (option.level < LZ4HC_MIN_CLEVEL ||
+				    option.level > LZ4HC_MAX_CLEVEL)
+					return -EINVAL;
+				break;
+			case COMPRESS_ZSTD:
+				if (option.level > zstd_max_clevel())
+					return -EINVAL;
+				break;
+			}
+		}
+
+		if (option.flag > BIT(COMPRESS_MAX_FLAG) - 1)
+			return -EINVAL;
+	}
+
 	file_start_write(filp);
 	inode_lock(inode);
 
@@ -3971,6 +4019,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))
@@ -3983,6 +4035,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);
@@ -4168,6 +4227,208 @@ 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 *)attr.attr))
+				return -EFAULT;
+		} else if (attr.attr_size == sizeof(struct old_timespec32)) {
+			if (put_old_timespec32(&fi->i_crtime,
+					       (void __user *)attr.attr))
+				return -EFAULT;
+		} else {
+			return -EINVAL;
+		}
+		break;
+	case F2FS_EXTRA_ATTR_COMPR_BLOCKS:
+		ret = f2fs_get_compress_blocks(filp, attr.attr_size);
+		attr.attr = ret;
+		break;
+	case F2FS_EXTRA_ATTR_COMPR_OPTION:
+		ret = f2fs_get_compress_option_v2(filp, attr.attr,
+						  &attr.attr_size);
+		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_set_compress_option_v2(filp, attr.attr,
+						  &attr.attr_size);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
 static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	switch (cmd) {
@@ -4239,7 +4500,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:
@@ -4254,6 +4515,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/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 0a17484443299..aef9c1fd37dca 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)
 {
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 374c990810ead..64adaec4e98e0 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) -	\
diff --git a/include/uapi/linux/f2fs.h b/include/uapi/linux/f2fs.h
index 955d440be1046..a8fdaa22c7bda 100644
--- a/include/uapi/linux/f2fs.h
+++ b/include/uapi/linux/f2fs.h
@@ -44,6 +44,11 @@
 #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.
  * Flags for going down operation used by FS_IOC_GOINGDOWN
@@ -96,4 +101,34 @@ 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 */
+	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,
+						 * i_compress_flag
+						 */
+	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



_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [f2fs-dev] [PATCH 1/2] f2fs_io: add [get|set_attr] to access inode extra attributes
  2023-05-29  1:35 [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr Sheng Yong via Linux-f2fs-devel
@ 2023-05-29  1:35 ` Sheng Yong via Linux-f2fs-devel
  2023-06-01  3:13   ` Chao Yu
  2023-05-29  1:35 ` [f2fs-dev] [PATCH " Sheng Yong via Linux-f2fs-devel
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: Sheng Yong via Linux-f2fs-devel @ 2023-05-29  1:35 UTC (permalink / raw)
  To: jaegeuk, chao; +Cc: linux-kernel, linux-f2fs-devel

This patch adds get_attr and set_attr to access inode's extra
attributes.

Signed-off-by: Sheng Yong <shengyong@oppo.com>
---
 tools/f2fs_io/f2fs_io.c | 165 ++++++++++++++++++++++++++++++++++++++++
 tools/f2fs_io/f2fs_io.h |  34 +++++++++
 2 files changed, 199 insertions(+)

diff --git a/tools/f2fs_io/f2fs_io.c b/tools/f2fs_io/f2fs_io.c
index 5bc0baf..70e0347 100644
--- a/tools/f2fs_io/f2fs_io.c
+++ b/tools/f2fs_io/f2fs_io.c
@@ -1311,6 +1311,169 @@ static void do_gc(int argc, char **argv, const struct cmd_desc *cmd)
 	exit(0);
 }
 
+#define get_attr_desc "get inode extra attribute"
+#define get_attr_help "f2fs_io get_attr [field] [file_path]\n\n"	\
+"field can be\n"							\
+"  total_size\n"							\
+"  isize\n"								\
+"  inline_xattr_size\n"							\
+"  projid\n"								\
+"  inode_chksum\n"							\
+"  crtime\n"								\
+"  cblocks\n"								\
+"  coption\n"
+
+static const char *extra_attr_fields[] = {
+	[F2FS_EXTRA_ATTR_TOTAL_SIZE] = "total_size",
+	[F2FS_EXTRA_ATTR_ISIZE] = "isize",
+	[F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE] = "inline_xattr_size",
+	[F2FS_EXTRA_ATTR_PROJID] = "projid",
+	[F2FS_EXTRA_ATTR_INODE_CHKSUM] = "inode_chksum",
+	[F2FS_EXTRA_ATTR_CRTIME] = "crtime",
+	[F2FS_EXTRA_ATTR_COMPR_BLOCKS] = "cblocks",
+	[F2FS_EXTRA_ATTR_COMPR_OPTION] = "coption",
+};
+
+static void do_get_attr(int argc, char **argv, const struct cmd_desc *cmd)
+{
+	struct f2fs_extra_attr attr = {0};
+	struct timespec ts = {0};
+	struct f2fs_comp_option_v2 coption = {0};
+	int ret, fd;
+
+	if (argc != 3) {
+		fputs("Excess arguments\n\n", stderr);
+		fputs(cmd->cmd_help, stderr);
+		exit(1);
+	}
+
+	for (attr.field = 0; attr.field < F2FS_EXTRA_ATTR_MAX; attr.field++) {
+		if (!strcmp(extra_attr_fields[attr.field], argv[1]))
+			break;
+	}
+
+	switch (attr.field) {
+	case F2FS_EXTRA_ATTR_TOTAL_SIZE:
+	case F2FS_EXTRA_ATTR_ISIZE:
+	case F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE:
+	case F2FS_EXTRA_ATTR_PROJID:
+	case F2FS_EXTRA_ATTR_INODE_CHKSUM:
+	case F2FS_EXTRA_ATTR_COMPR_BLOCKS:
+		attr.attr_size = sizeof(attr.attr);
+		break;
+	case F2FS_EXTRA_ATTR_CRTIME:
+		attr.attr_size = sizeof(ts);
+		attr.attr = (unsigned long)&ts;
+		break;
+	case F2FS_EXTRA_ATTR_COMPR_OPTION:
+		attr.attr_size = sizeof(coption);
+		attr.attr = (unsigned long)&coption;
+		break;
+	default:
+		die("Unknown field");
+	}
+
+	fd = xopen(argv[2], O_RDONLY, 0);
+
+	ret = ioctl(fd, F2FS_IOC_GET_EXTRA_ATTR, &attr);
+	if (ret < 0)
+		die_errno("F2FS_IOC_GET_EXTRA_ATTR failed");
+
+	switch (attr.field) {
+	case F2FS_EXTRA_ATTR_TOTAL_SIZE:
+	case F2FS_EXTRA_ATTR_ISIZE:
+	case F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE:
+	case F2FS_EXTRA_ATTR_PROJID:
+	case F2FS_EXTRA_ATTR_COMPR_BLOCKS:
+		printf("%"PRIu64"\n", attr.attr);
+		break;
+	case F2FS_EXTRA_ATTR_INODE_CHKSUM:
+		printf("0x%"PRIx64"\n", attr.attr);
+		break;
+	case F2FS_EXTRA_ATTR_CRTIME:
+		printf("sec: %lu\nnsec: %lu\n", ts.tv_sec, ts.tv_nsec);
+		break;
+	case F2FS_EXTRA_ATTR_COMPR_OPTION:
+		printf("compression algorithm:%u\n", coption.algorithm);
+		printf("compression cluster log size:%u\n", coption.log_cluster_size);
+		printf("compression level:%u\n", coption.level);
+		printf("compression flag:0x%x\n", coption.flag);
+		break;
+	default:
+		die("Unknown field");
+	}
+
+	exit(0);
+}
+
+#define set_attr_desc "set inode extra attribute"
+#define set_attr_help "f2fs_io set_attr [field] [values] [file_path]\n\n"	\
+"field can be\n"								\
+"  inline_xattr_size : [values] is [size]\n"					\
+"  coption : [values] are [algorithm] [log_cluster_size] [level] [flag]\n"	\
+"    algorithm        : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n"	\
+"    log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n"	\
+"    level            : compression level\n"					\
+"    flag             : compression flag (1:chksum)\n"
+
+static void do_set_attr(int argc, char **argv, const struct cmd_desc *cmd)
+{
+	struct f2fs_extra_attr attr = {0};
+	struct f2fs_comp_option_v2 coption = {0};
+	int i;
+	int ret, fd;
+
+	if (argc < 4)
+		goto out;
+
+	if (!strcmp(argv[1], extra_attr_fields[F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE])) {
+		if (argc != 4)
+			goto out;
+		i = 2;
+		attr.field = F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE;
+		attr.attr_size = sizeof(attr.attr);
+		attr.attr = atoi(argv[i++]);
+	} else if (!strcmp(argv[1], extra_attr_fields[F2FS_EXTRA_ATTR_COMPR_OPTION])) {
+		if (argc != 7)
+			goto out;
+		i = 2;
+		coption.algorithm = atoi(argv[i++]);
+		coption.log_cluster_size = atoi(argv[i++]);
+		coption.level = atoi(argv[i++]);
+		coption.flag = atoi(argv[i++]);
+		attr.field = F2FS_EXTRA_ATTR_COMPR_OPTION;
+		attr.attr_size = sizeof(coption);
+		attr.attr = (unsigned long)&coption;
+	} else {
+		die("Unknown or read only field");
+	}
+
+	fd = xopen(argv[i], O_WRONLY, 0);
+
+	ret = ioctl(fd, F2FS_IOC_SET_EXTRA_ATTR, &attr);
+	if (ret < 0)
+		die_errno("F2FS_IOC_SET_EXTRA_ATTR failed");
+
+	switch (attr.field) {
+	case F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE:
+		printf("set inline_xattr_size:%"PRIu64"\n", attr.attr);
+		break;
+	case F2FS_EXTRA_ATTR_COMPR_OPTION:
+		printf("set compression option: algorithm=%u, "
+			"log_cluster_size=%u, level=%u, flag=0x%x\n",
+			coption.algorithm, coption.log_cluster_size,
+			coption.level, coption.flag);
+		break;
+	}
+
+	exit(0);
+out:
+	fputs("Excess arguments\n\n", stderr);
+	fputs(cmd->cmd_help, stderr);
+	exit(1);
+}
+
+
 #define CMD_HIDDEN 	0x0001
 #define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 }
 #define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN }
@@ -1343,6 +1506,8 @@ const struct cmd_desc cmd_list[] = {
 	CMD(get_filename_encrypt_mode),
 	CMD(rename),
 	CMD(gc),
+	CMD(get_attr),
+	CMD(set_attr),
 	{ NULL, NULL, NULL, NULL, 0 }
 };
 
diff --git a/tools/f2fs_io/f2fs_io.h b/tools/f2fs_io/f2fs_io.h
index 58be8f8..b0be15c 100644
--- a/tools/f2fs_io/f2fs_io.h
+++ b/tools/f2fs_io/f2fs_io.h
@@ -91,6 +91,10 @@ typedef u32	__be32;
 #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)
 
 #ifndef FSCRYPT_POLICY_V1
 #define FSCRYPT_POLICY_V1		0
@@ -216,3 +220,33 @@ struct f2fs_comp_option {
 	u8 algorithm;
 	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 */
+	F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE,	/* r2, 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,
+						 * i_compress_flag
+						 */
+	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 */
+};
-- 
2.40.1



_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [f2fs-dev] [PATCH 2/2] f2fs_io: convert compression ioctls to [get|set]_attr
  2023-05-29  1:35 [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr Sheng Yong via Linux-f2fs-devel
  2023-05-29  1:35 ` [f2fs-dev] [PATCH 1/2] f2fs_io: add [get|set_attr] to access inode extra attributes Sheng Yong via Linux-f2fs-devel
@ 2023-05-29  1:35 ` Sheng Yong via Linux-f2fs-devel
  2023-05-29  6:10 ` [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr kernel test robot
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Sheng Yong via Linux-f2fs-devel @ 2023-05-29  1:35 UTC (permalink / raw)
  To: jaegeuk, chao; +Cc: linux-kernel, linux-f2fs-devel

Convert compression related ioctls to get extra attr ioctls.

Signed-off-by: Sheng Yong <shengyong@oppo.com>
---
 tools/f2fs_io/f2fs_io.c | 25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/tools/f2fs_io/f2fs_io.c b/tools/f2fs_io/f2fs_io.c
index 70e0347..f6e6057 100644
--- a/tools/f2fs_io/f2fs_io.c
+++ b/tools/f2fs_io/f2fs_io.c
@@ -1012,7 +1012,9 @@ static void do_copy(int argc, char **argv, const struct cmd_desc *cmd)
 
 static void do_get_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
 {
-	unsigned long long blkcnt;
+	struct f2fs_extra_attr attr = {
+		.field = F2FS_EXTRA_ATTR_COMPR_BLOCKS,
+	};
 	int ret, fd;
 
 	if (argc != 2) {
@@ -1023,11 +1025,11 @@ static void do_get_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
 
 	fd = xopen(argv[1], O_RDONLY, 0);
 
-	ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_BLOCKS, &blkcnt);
+	ret = ioctl(fd, F2FS_IOC_GET_EXTRA_ATTR, &attr);
 	if (ret < 0)
 		die_errno("F2FS_IOC_GET_COMPRESS_BLOCKS failed");
 
-	printf("%llu\n", blkcnt);
+	printf("%llu\n", (unsigned long long)attr.attr);
 
 	exit(0);
 }
@@ -1090,6 +1092,7 @@ static void do_reserve_cblocks(int argc, char **argv, const struct cmd_desc *cmd
 
 static void do_get_coption(int argc, char **argv, const struct cmd_desc *cmd)
 {
+	struct f2fs_extra_attr attr = {0};
 	struct f2fs_comp_option option;
 	int ret, fd;
 
@@ -1099,11 +1102,15 @@ static void do_get_coption(int argc, char **argv, const struct cmd_desc *cmd)
 		exit(1);
 	}
 
+	attr.field = F2FS_EXTRA_ATTR_COMPR_OPTION;
+	attr.attr_size = sizeof(option);
+	attr.attr = (unsigned long)&option;
+
 	fd = xopen(argv[1], O_RDONLY, 0);
 
-	ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_OPTION, &option);
+	ret = ioctl(fd, F2FS_IOC_GET_EXTRA_ATTR, &attr);
 	if (ret < 0)
-		die_errno("F2FS_IOC_GET_COMPRESS_OPTION failed");
+		die_errno("F2FS_IOC_GET_EXTRA_ATTR failed");
 
 	printf("compression algorithm:%u\n", option.algorithm);
 	printf("compression cluster log size:%u\n", option.log_cluster_size);
@@ -1119,6 +1126,7 @@ static void do_get_coption(int argc, char **argv, const struct cmd_desc *cmd)
 
 static void do_set_coption(int argc, char **argv, const struct cmd_desc *cmd)
 {
+	struct f2fs_extra_attr attr = {0};
 	struct f2fs_comp_option option;
 	int fd, ret;
 
@@ -1130,12 +1138,15 @@ static void do_set_coption(int argc, char **argv, const struct cmd_desc *cmd)
 
 	option.algorithm = atoi(argv[1]);
 	option.log_cluster_size = atoi(argv[2]);
+	attr.field = F2FS_EXTRA_ATTR_COMPR_OPTION;
+	attr.attr_size = sizeof(option);
+	attr.attr = (unsigned long)&option;
 
 	fd = xopen(argv[3], O_WRONLY, 0);
 
-	ret = ioctl(fd, F2FS_IOC_SET_COMPRESS_OPTION, &option);
+	ret = ioctl(fd, F2FS_IOC_SET_EXTRA_ATTR, &attr);
 	if (ret < 0)
-		die_errno("F2FS_IOC_SET_COMPRESS_OPTION failed");
+		die_errno("F2FS_IOC_SET_EXTRA_ATTR failed");
 
 	printf("set compression option: algorithm=%u, log_cluster_size=%u\n",
 			option.algorithm, option.log_cluster_size);
-- 
2.40.1



_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr
  2023-05-29  1:35 [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr Sheng Yong via Linux-f2fs-devel
  2023-05-29  1:35 ` [f2fs-dev] [PATCH 1/2] f2fs_io: add [get|set_attr] to access inode extra attributes Sheng Yong via Linux-f2fs-devel
  2023-05-29  1:35 ` [f2fs-dev] [PATCH " Sheng Yong via Linux-f2fs-devel
@ 2023-05-29  6:10 ` kernel test robot
  2023-05-29  6:20 ` kernel test robot
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: kernel test robot @ 2023-05-29  6:10 UTC (permalink / raw)
  To: Sheng Yong, jaegeuk, chao; +Cc: linux-f2fs-devel, linux-kernel, oe-kbuild-all

Hi Sheng,

kernel test robot noticed the following build errors:

[auto build test ERROR on jaegeuk-f2fs/dev-test]
[also build test ERROR on jaegeuk-f2fs/dev next-20230525]
[cannot apply to linus/master v6.4-rc4]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Sheng-Yong/f2fs-add-f2fs_ioc_-get-set-_extra_attr/20230529-093611
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git dev-test
patch link:    https://lore.kernel.org/r/20230529013502.2230810-1-shengyong%40oppo.com
patch subject: [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr
config: i386-randconfig-i086-20230529 (https://download.01.org/0day-ci/archive/20230529/202305291323.u3OTwJgK-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build):
        # https://github.com/intel-lab-lkp/linux/commit/519a8b3bbd4d743ae67c32dfef61e8bfa0951cc5
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Sheng-Yong/f2fs-add-f2fs_ioc_-get-set-_extra_attr/20230529-093611
        git checkout 519a8b3bbd4d743ae67c32dfef61e8bfa0951cc5
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        make W=1 O=build_dir ARCH=i386 olddefconfig
        make W=1 O=build_dir ARCH=i386 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202305291323.u3OTwJgK-lkp@intel.com/

All errors (new ones prefixed by >>):

   ld: fs/f2fs/file.o: in function `f2fs_set_compress_option_v2':
>> fs/f2fs/file.c:3996: undefined reference to `zstd_max_clevel'


vim +3996 fs/f2fs/file.c

  3957	
  3958	static int f2fs_set_compress_option_v2(struct file *filp,
  3959					       unsigned long attr, __u16 *attr_size)
  3960	{
  3961		struct inode *inode = file_inode(filp);
  3962		struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
  3963		struct f2fs_comp_option_v2 option;
  3964		int ret = 0;
  3965	
  3966		if (sizeof(option) < *attr_size)
  3967			*attr_size = sizeof(option);
  3968	
  3969		if (!f2fs_sb_has_compression(sbi))
  3970			return -EOPNOTSUPP;
  3971	
  3972		if (!(filp->f_mode & FMODE_WRITE))
  3973			return -EBADF;
  3974	
  3975		if (copy_from_user(&option, (void __user *)attr, *attr_size))
  3976			return -EFAULT;
  3977	
  3978		if (!f2fs_compressed_file(inode) ||
  3979				option.log_cluster_size < MIN_COMPRESS_LOG_SIZE ||
  3980				option.log_cluster_size > MAX_COMPRESS_LOG_SIZE ||
  3981				option.algorithm >= COMPRESS_MAX)
  3982			return -EINVAL;
  3983	
  3984		if (*attr_size == sizeof(struct f2fs_comp_option_v2)) {
  3985			if (option.level != 0) {
  3986				switch (option.algorithm) {
  3987				case COMPRESS_LZO:
  3988				case COMPRESS_LZORLE:
  3989					return -EINVAL;
  3990				case COMPRESS_LZ4:
  3991					if (option.level < LZ4HC_MIN_CLEVEL ||
  3992					    option.level > LZ4HC_MAX_CLEVEL)
  3993						return -EINVAL;
  3994					break;
  3995				case COMPRESS_ZSTD:
> 3996					if (option.level > zstd_max_clevel())
  3997						return -EINVAL;
  3998					break;
  3999				}
  4000			}
  4001	
  4002			if (option.flag > BIT(COMPRESS_MAX_FLAG) - 1)
  4003				return -EINVAL;
  4004		}
  4005	
  4006		file_start_write(filp);
  4007		inode_lock(inode);
  4008	
  4009		if (f2fs_is_mmap_file(inode) || get_dirty_pages(inode)) {
  4010			ret = -EBUSY;
  4011			goto out;
  4012		}
  4013	
  4014		if (F2FS_HAS_BLOCKS(inode)) {
  4015			ret = -EFBIG;
  4016			goto out;
  4017		}
  4018	
  4019		F2FS_I(inode)->i_compress_algorithm = option.algorithm;
  4020		F2FS_I(inode)->i_log_cluster_size = option.log_cluster_size;
  4021		F2FS_I(inode)->i_cluster_size = BIT(option.log_cluster_size);
  4022		if (*attr_size == sizeof(struct f2fs_comp_option_v2)) {
  4023			F2FS_I(inode)->i_compress_level = option.level;
  4024			F2FS_I(inode)->i_compress_flag = option.flag;
  4025		}
  4026		f2fs_mark_inode_dirty_sync(inode, true);
  4027	
  4028		if (!f2fs_is_compress_backend_ready(inode))
  4029			f2fs_warn(sbi, "compression algorithm is successfully set, "
  4030				"but current kernel doesn't support this algorithm.");
  4031	out:
  4032		inode_unlock(inode);
  4033		file_end_write(filp);
  4034	
  4035		return ret;
  4036	}
  4037	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr
  2023-05-29  1:35 [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr Sheng Yong via Linux-f2fs-devel
                   ` (2 preceding siblings ...)
  2023-05-29  6:10 ` [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr kernel test robot
@ 2023-05-29  6:20 ` kernel test robot
  2023-05-29  8:19 ` kernel test robot
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: kernel test robot @ 2023-05-29  6:20 UTC (permalink / raw)
  To: Sheng Yong, jaegeuk, chao; +Cc: linux-f2fs-devel, linux-kernel, oe-kbuild-all

Hi Sheng,

kernel test robot noticed the following build warnings:

[auto build test WARNING on jaegeuk-f2fs/dev-test]
[also build test WARNING on jaegeuk-f2fs/dev next-20230525]
[cannot apply to linus/master v6.4-rc4]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Sheng-Yong/f2fs-add-f2fs_ioc_-get-set-_extra_attr/20230529-093611
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git dev-test
patch link:    https://lore.kernel.org/r/20230529013502.2230810-1-shengyong%40oppo.com
patch subject: [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr
config: arc-buildonly-randconfig-r004-20230529 (https://download.01.org/0day-ci/archive/20230529/202305291408.kdy2Itan-lkp@intel.com/config)
compiler: arceb-elf-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        mkdir -p ~/bin
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/519a8b3bbd4d743ae67c32dfef61e8bfa0951cc5
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Sheng-Yong/f2fs-add-f2fs_ioc_-get-set-_extra_attr/20230529-093611
        git checkout 519a8b3bbd4d743ae67c32dfef61e8bfa0951cc5
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 ~/bin/make.cross W=1 O=build_dir ARCH=arc olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 ~/bin/make.cross W=1 O=build_dir ARCH=arc SHELL=/bin/bash fs/f2fs/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202305291408.kdy2Itan-lkp@intel.com/

All warnings (new ones prefixed by >>):

   fs/f2fs/file.c: In function 'f2fs_ioc_get_extra_attr':
>> fs/f2fs/file.c:4312:44: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
    4312 |                                            (void __user *)attr.attr))
         |                                            ^
   fs/f2fs/file.c:4316:48: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
    4316 |                                                (void __user *)attr.attr))
         |                                                ^


vim +4312 fs/f2fs/file.c

  4262	
  4263	static int f2fs_ioc_get_extra_attr(struct file *filp, unsigned long arg)
  4264	{
  4265		struct inode *inode = file_inode(filp);
  4266		struct f2fs_inode_info *fi = F2FS_I(inode);
  4267		struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
  4268		struct f2fs_extra_attr attr;
  4269		u32 chksum;
  4270		int ret = 0;
  4271	
  4272		if (!f2fs_has_extra_attr(inode))
  4273			return -EOPNOTSUPP;
  4274	
  4275		if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
  4276			return -EFAULT;
  4277	
  4278		if (attr.field >= F2FS_EXTRA_ATTR_MAX)
  4279			return -EINVAL;
  4280	
  4281		if (!extra_attr_fits_in_inode(inode, attr.field))
  4282			return -EOPNOTSUPP;
  4283	
  4284		switch (attr.field) {
  4285		case F2FS_EXTRA_ATTR_TOTAL_SIZE:
  4286			attr.attr = F2FS_TOTAL_EXTRA_ATTR_SIZE;
  4287			break;
  4288		case F2FS_EXTRA_ATTR_ISIZE:
  4289			attr.attr = fi->i_extra_isize;
  4290			break;
  4291		case F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE:
  4292			if (!f2fs_has_inline_xattr(inode))
  4293				return -EOPNOTSUPP;
  4294			attr.attr = get_inline_xattr_addrs(inode);
  4295			break;
  4296		case F2FS_EXTRA_ATTR_PROJID:
  4297			if (!f2fs_sb_has_project_quota(F2FS_I_SB(inode)))
  4298				return -EOPNOTSUPP;
  4299			attr.attr = from_kprojid(&init_user_ns, fi->i_projid);
  4300			break;
  4301		case F2FS_EXTRA_ATTR_INODE_CHKSUM:
  4302			ret = f2fs_inode_chksum_get(sbi, inode, &chksum);
  4303			if (ret)
  4304				return ret;
  4305			attr.attr = chksum;
  4306			break;
  4307		case F2FS_EXTRA_ATTR_CRTIME:
  4308			if (!f2fs_sb_has_inode_crtime(sbi))
  4309				return -EOPNOTSUPP;
  4310			if (attr.attr_size == sizeof(struct timespec64)) {
  4311				if (put_timespec64(&fi->i_crtime,
> 4312						   (void __user *)attr.attr))
  4313					return -EFAULT;
  4314			} else if (attr.attr_size == sizeof(struct old_timespec32)) {
  4315				if (put_old_timespec32(&fi->i_crtime,
  4316						       (void __user *)attr.attr))
  4317					return -EFAULT;
  4318			} else {
  4319				return -EINVAL;
  4320			}
  4321			break;
  4322		case F2FS_EXTRA_ATTR_COMPR_BLOCKS:
  4323			ret = f2fs_get_compress_blocks(filp, attr.attr_size);
  4324			attr.attr = ret;
  4325			break;
  4326		case F2FS_EXTRA_ATTR_COMPR_OPTION:
  4327			ret = f2fs_get_compress_option_v2(filp, attr.attr,
  4328							  &attr.attr_size);
  4329			break;
  4330		default:
  4331			return -EINVAL;
  4332		}
  4333	
  4334		if (ret < 0)
  4335			return ret;
  4336	
  4337		if (copy_to_user((void __user *)arg, &attr, sizeof(attr)))
  4338			return -EFAULT;
  4339	
  4340		return 0;
  4341	}
  4342	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr
  2023-05-29  1:35 [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr Sheng Yong via Linux-f2fs-devel
                   ` (3 preceding siblings ...)
  2023-05-29  6:20 ` kernel test robot
@ 2023-05-29  8:19 ` kernel test robot
  2023-05-30  6:34 ` [f2fs-dev] [PATCH v2] " Sheng Yong via Linux-f2fs-devel
  2023-06-01  3:16 ` [f2fs-dev] [PATCH] " Eric Biggers
  6 siblings, 0 replies; 15+ messages in thread
From: kernel test robot @ 2023-05-29  8:19 UTC (permalink / raw)
  To: Sheng Yong, jaegeuk, chao; +Cc: linux-f2fs-devel, linux-kernel, oe-kbuild-all

Hi Sheng,

kernel test robot noticed the following build errors:

[auto build test ERROR on jaegeuk-f2fs/dev-test]
[also build test ERROR on jaegeuk-f2fs/dev next-20230525]
[cannot apply to linus/master v6.4-rc4]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Sheng-Yong/f2fs-add-f2fs_ioc_-get-set-_extra_attr/20230529-093611
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git dev-test
patch link:    https://lore.kernel.org/r/20230529013502.2230810-1-shengyong%40oppo.com
patch subject: [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr
config: x86_64-randconfig-x093-20230529 (https://download.01.org/0day-ci/archive/20230529/202305291515.JQ8RLQH1-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build):
        # https://github.com/intel-lab-lkp/linux/commit/519a8b3bbd4d743ae67c32dfef61e8bfa0951cc5
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Sheng-Yong/f2fs-add-f2fs_ioc_-get-set-_extra_attr/20230529-093611
        git checkout 519a8b3bbd4d743ae67c32dfef61e8bfa0951cc5
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        make W=1 O=build_dir ARCH=x86_64 olddefconfig
        make W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202305291515.JQ8RLQH1-lkp@intel.com/

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "zstd_max_clevel" [fs/f2fs/f2fs.ko] undefined!

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [f2fs-dev] [PATCH v2] f2fs: add f2fs_ioc_[get|set]_extra_attr
  2023-05-29  1:35 [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr Sheng Yong via Linux-f2fs-devel
                   ` (4 preceding siblings ...)
  2023-05-29  8:19 ` kernel test robot
@ 2023-05-30  6:34 ` Sheng Yong via Linux-f2fs-devel
  2023-06-01  3:06   ` Chao Yu
  2023-06-01  3:16 ` [f2fs-dev] [PATCH] " Eric Biggers
  6 siblings, 1 reply; 15+ messages in thread
From: Sheng Yong via Linux-f2fs-devel @ 2023-05-30  6:34 UTC (permalink / raw)
  To: jaegeuk, chao; +Cc: linux-kernel, linux-f2fs-devel

This patch introduces two ioctls:
  * f2fs_ioc_get_extra_attr
  * f2fs_ioc_set_extra_attr
to get or modify values in 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 <shengyong@oppo.com>
---
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

---
 fs/f2fs/compress.c        |  34 +++++
 fs/f2fs/f2fs.h            |   4 +
 fs/f2fs/file.c            | 273 ++++++++++++++++++++++++++++++++++++--
 fs/f2fs/inode.c           |  21 +++
 fs/f2fs/super.c           |   2 +-
 fs/f2fs/xattr.h           |   1 +
 include/uapi/linux/f2fs.h |  35 +++++
 7 files changed, 357 insertions(+), 13 deletions(-)

diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index 905b7c39a2b32..3a2c05c849b0a 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)(struct inode *inode, int level);
 };
 
 static unsigned int offset_in_cluster(struct compress_ctx *cc, pgoff_t index)
@@ -232,6 +233,7 @@ static const struct f2fs_compress_ops f2fs_lzo_ops = {
 	.destroy_compress_ctx	= lzo_destroy_compress_ctx,
 	.compress_pages		= lzo_compress_pages,
 	.decompress_pages	= lzo_decompress_pages,
+	.is_level_valid		= NULL,
 };
 #endif
 
@@ -308,11 +310,24 @@ static int lz4_decompress_pages(struct decompress_io_ctx *dic)
 	return 0;
 }
 
+static bool lz4_is_level_valid(struct inode *inode, int level)
+{
+	if (F2FS_I(inode)->i_compress_level == 0)
+		/* lz4 */
+		return level == 0;
+
+	/* lz4hc */
+	if (level >= LZ4HC_MIN_CLEVEL && level <= LZ4HC_MAX_CLEVEL)
+			return true;
+	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 +492,13 @@ static int zstd_decompress_pages(struct decompress_io_ctx *dic)
 	return 0;
 }
 
+static bool zstd_is_level_valid(struct inode *inode, int level)
+{
+	if (level < zstd_min_clevel() || level > 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 +506,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
 
@@ -508,6 +531,7 @@ static const struct f2fs_compress_ops f2fs_lzorle_ops = {
 	.destroy_compress_ctx	= lzo_destroy_compress_ctx,
 	.compress_pages		= lzorle_compress_pages,
 	.decompress_pages	= lzo_decompress_pages,
+	.is_level_valid		= NULL,
 };
 #endif
 #endif
@@ -542,6 +566,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(struct inode *inode, int alg, int lvl)
+{
+	const struct f2fs_compress_ops *cops = f2fs_cops[alg];
+
+	if (cops->is_level_valid)
+		return cops->is_level_valid(inode, 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 faa27f41f39d4..b92b96eb133cb 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3475,6 +3475,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);
@@ -4232,6 +4234,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(struct inode *inode, 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);
@@ -4296,6 +4299,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(struct inode *inode, 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/file.c b/fs/f2fs/file.c
index 78aa8cff4b41d..3de64ce8dd491 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -3376,10 +3376,12 @@ 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 file *filp, unsigned int attr_size)
 {
 	struct inode *inode = file_inode(filp);
-	__u64 blocks;
+
+	if (attr_size != sizeof(__u64))
+		return -EINVAL;
 
 	if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
 		return -EOPNOTSUPP;
@@ -3387,7 +3389,14 @@ static int f2fs_get_compress_blocks(struct file *filp, unsigned long arg)
 	if (!f2fs_compressed_file(inode))
 		return -EINVAL;
 
-	blocks = atomic_read(&F2FS_I(inode)->i_compr_blocks);
+	return atomic_read(&F2FS_I(inode)->i_compr_blocks);
+}
+
+static int f2fs_ioc_get_compress_blocks(struct file *filp, unsigned long arg)
+{
+	__u64 blocks;
+
+	blocks = f2fs_get_compress_blocks(filp, sizeof(blocks));
 	return put_user(blocks, (u64 __user *)arg);
 }
 
@@ -3905,10 +3914,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;
@@ -3922,31 +3935,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) ||
@@ -3955,6 +3979,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(inode, option.algorithm,
+						  option.level))
+			return -EINVAL;
+		if (option.flag > BIT(COMPRESS_MAX_FLAG) - 1)
+			return -EINVAL;
+	}
+
 	file_start_write(filp);
 	inode_lock(inode);
 
@@ -3971,6 +4003,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))
@@ -3983,6 +4019,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);
@@ -4168,6 +4211,208 @@ 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:
+		ret = f2fs_get_compress_blocks(filp, attr.attr_size);
+		attr.attr = ret;
+		break;
+	case F2FS_EXTRA_ATTR_COMPR_OPTION:
+		ret = f2fs_get_compress_option_v2(filp, attr.attr,
+						  &attr.attr_size);
+		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_set_compress_option_v2(filp, attr.attr,
+						  &attr.attr_size);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
 static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	switch (cmd) {
@@ -4239,7 +4484,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:
@@ -4254,6 +4499,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/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 0a17484443299..aef9c1fd37dca 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)
 {
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 374c990810ead..64adaec4e98e0 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) -	\
diff --git a/include/uapi/linux/f2fs.h b/include/uapi/linux/f2fs.h
index 955d440be1046..a8fdaa22c7bda 100644
--- a/include/uapi/linux/f2fs.h
+++ b/include/uapi/linux/f2fs.h
@@ -44,6 +44,11 @@
 #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.
  * Flags for going down operation used by FS_IOC_GOINGDOWN
@@ -96,4 +101,34 @@ 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 */
+	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,
+						 * i_compress_flag
+						 */
+	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



_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [f2fs-dev] [PATCH v2] f2fs: add f2fs_ioc_[get|set]_extra_attr
  2023-05-30  6:34 ` [f2fs-dev] [PATCH v2] " Sheng Yong via Linux-f2fs-devel
@ 2023-06-01  3:06   ` Chao Yu
  2023-06-04  2:28     ` [f2fs-dev] [PATCH v3] " Sheng Yong via Linux-f2fs-devel
  0 siblings, 1 reply; 15+ messages in thread
From: Chao Yu @ 2023-06-01  3:06 UTC (permalink / raw)
  To: Sheng Yong, jaegeuk; +Cc: linux-kernel, linux-f2fs-devel

On 2023/5/30 14:34, Sheng Yong wrote:
> This patch introduces two ioctls:
>    * f2fs_ioc_get_extra_attr
>    * f2fs_ioc_set_extra_attr
> to get or modify values in 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 <shengyong@oppo.com>

Reviewed-by: Chao Yu <chao@kernel.org>

Thanks,


_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [f2fs-dev] [PATCH 1/2] f2fs_io: add [get|set_attr] to access inode extra attributes
  2023-05-29  1:35 ` [f2fs-dev] [PATCH 1/2] f2fs_io: add [get|set_attr] to access inode extra attributes Sheng Yong via Linux-f2fs-devel
@ 2023-06-01  3:13   ` Chao Yu
  2023-06-04  3:56     ` [f2fs-dev] [PATCH v2 " Sheng Yong via Linux-f2fs-devel
  2023-06-04  3:56     ` [f2fs-dev] [PATCH v2 2/2] f2fs_io: convert compression ioctls to [get|set]_attr Sheng Yong via Linux-f2fs-devel
  0 siblings, 2 replies; 15+ messages in thread
From: Chao Yu @ 2023-06-01  3:13 UTC (permalink / raw)
  To: Sheng Yong, jaegeuk; +Cc: linux-kernel, linux-f2fs-devel

On 2023/5/29 9:35, Sheng Yong wrote:
> This patch adds get_attr and set_attr to access inode's extra
> attributes.

It needs to update f2fs_io(8) manual as well?

Thanks,


_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr
  2023-05-29  1:35 [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr Sheng Yong via Linux-f2fs-devel
                   ` (5 preceding siblings ...)
  2023-05-30  6:34 ` [f2fs-dev] [PATCH v2] " Sheng Yong via Linux-f2fs-devel
@ 2023-06-01  3:16 ` Eric Biggers
  2023-06-01 14:37   ` Sheng Yong via Linux-f2fs-devel
  6 siblings, 1 reply; 15+ messages in thread
From: Eric Biggers @ 2023-06-01  3:16 UTC (permalink / raw)
  To: Sheng Yong; +Cc: jaegeuk, linux-kernel, linux-f2fs-devel

On Mon, May 29, 2023 at 09:35:00AM +0800, Sheng Yong via Linux-f2fs-devel wrote:
> This patch introduces two ioctls:
>   * f2fs_ioc_get_extra_attr
>   * f2fs_ioc_set_extra_attr
> to get or modify values in 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 <shengyong@oppo.com>

Aren't there enough things called extra or extended attributes already?  Besides
the standard "extended attributes" retrievable with the getxattr() system call,
there is already the FS_IOC_FSGETXATTR ioctl too.

- Eric


_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr
  2023-06-01  3:16 ` [f2fs-dev] [PATCH] " Eric Biggers
@ 2023-06-01 14:37   ` Sheng Yong via Linux-f2fs-devel
  0 siblings, 0 replies; 15+ messages in thread
From: Sheng Yong via Linux-f2fs-devel @ 2023-06-01 14:37 UTC (permalink / raw)
  To: Eric Biggers; +Cc: jaegeuk, linux-kernel, linux-f2fs-devel



On 2023/6/1 11:16, Eric Biggers wrote:
> On Mon, May 29, 2023 at 09:35:00AM +0800, Sheng Yong via Linux-f2fs-devel wrote:
>> This patch introduces two ioctls:
>>    * f2fs_ioc_get_extra_attr
>>    * f2fs_ioc_set_extra_attr
>> to get or modify values in 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 <shengyong@oppo.com>
> 
> Aren't there enough things called extra or extended attributes already?  Besides
> the standard "extended attributes" retrievable with the getxattr() system call,
> there is already the FS_IOC_FSGETXATTR ioctl too.
Hi, Eric,

The name extra_attr is a bit confusing :-(
But f2fs usually extends new features through extra_attr, like compression, inode
chksum. Since this area is easy to extend, new features could also be added here
in the future. To avoid adding new ioctls for new features, these two could help
integrate with all extra_attr related ioctls. And it seems not appropriate to add
new fields or get/set f2fs-only attributes by FS_IOC_FSGETXATTR/FS_IOC_FSGETXATTR.
xattrs could not be accessed through these two, only inline xattr size is allowed
to be modified for an empty file.

thanks,
shengyong

> 
> - Eric


_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [f2fs-dev] [PATCH v3] f2fs: add f2fs_ioc_[get|set]_extra_attr
  2023-06-01  3:06   ` Chao Yu
@ 2023-06-04  2:28     ` Sheng Yong via Linux-f2fs-devel
  2023-06-07 17:09       ` Jaegeuk Kim
  0 siblings, 1 reply; 15+ messages in thread
From: Sheng Yong via Linux-f2fs-devel @ 2023-06-04  2:28 UTC (permalink / raw)
  To: jaegeuk, chao; +Cc: ebiggers, linux-kernel, linux-f2fs-devel

This patch introduces two ioctls:
  * f2fs_ioc_get_extra_attr
  * f2fs_ioc_set_extra_attr
to get or modify values in 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 <shengyong@oppo.com>
---
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

---
 fs/f2fs/compress.c        |  33 +++++
 fs/f2fs/f2fs.h            |   4 +
 fs/f2fs/file.c            | 273 ++++++++++++++++++++++++++++++++++++--
 fs/f2fs/inode.c           |  21 +++
 fs/f2fs/super.c           |   2 +-
 fs/f2fs/xattr.h           |   1 +
 include/uapi/linux/f2fs.h |  35 +++++
 7 files changed, 356 insertions(+), 13 deletions(-)

diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index 905b7c39a2b32..3fd804277059d 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)
@@ -232,6 +233,7 @@ static const struct f2fs_compress_ops f2fs_lzo_ops = {
 	.destroy_compress_ctx	= lzo_destroy_compress_ctx,
 	.compress_pages		= lzo_compress_pages,
 	.decompress_pages	= lzo_decompress_pages,
+	.is_level_valid		= NULL,
 };
 #endif
 
@@ -308,11 +310,23 @@ static int lz4_decompress_pages(struct decompress_io_ctx *dic)
 	return 0;
 }
 
+static bool lz4_is_level_valid(int level)
+{
+	if (level == 0)
+		return true;
+#ifdef CONFIG_F2FS_FS_LZ4HC
+	if (level >= LZ4HC_MIN_CLEVEL && level <= 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 +491,13 @@ static int zstd_decompress_pages(struct decompress_io_ctx *dic)
 	return 0;
 }
 
+static bool zstd_is_level_valid(int level)
+{
+	if (level < zstd_min_clevel() || level > 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 +505,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
 
@@ -508,6 +530,7 @@ static const struct f2fs_compress_ops f2fs_lzorle_ops = {
 	.destroy_compress_ctx	= lzo_destroy_compress_ctx,
 	.compress_pages		= lzorle_compress_pages,
 	.decompress_pages	= lzo_decompress_pages,
+	.is_level_valid		= NULL,
 };
 #endif
 #endif
@@ -542,6 +565,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 faa27f41f39d4..9fcf8f66c860c 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3475,6 +3475,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);
@@ -4232,6 +4234,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);
@@ -4296,6 +4299,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/file.c b/fs/f2fs/file.c
index 78aa8cff4b41d..353a2edacc549 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -3376,10 +3376,12 @@ 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 file *filp, unsigned int attr_size)
 {
 	struct inode *inode = file_inode(filp);
-	__u64 blocks;
+
+	if (attr_size != sizeof(__u64))
+		return -EINVAL;
 
 	if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
 		return -EOPNOTSUPP;
@@ -3387,7 +3389,14 @@ static int f2fs_get_compress_blocks(struct file *filp, unsigned long arg)
 	if (!f2fs_compressed_file(inode))
 		return -EINVAL;
 
-	blocks = atomic_read(&F2FS_I(inode)->i_compr_blocks);
+	return atomic_read(&F2FS_I(inode)->i_compr_blocks);
+}
+
+static int f2fs_ioc_get_compress_blocks(struct file *filp, unsigned long arg)
+{
+	__u64 blocks;
+
+	blocks = f2fs_get_compress_blocks(filp, sizeof(blocks));
 	return put_user(blocks, (u64 __user *)arg);
 }
 
@@ -3905,10 +3914,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;
@@ -3922,31 +3935,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) ||
@@ -3955,6 +3979,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);
 
@@ -3971,6 +4003,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))
@@ -3983,6 +4019,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);
@@ -4168,6 +4211,208 @@ 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:
+		ret = f2fs_get_compress_blocks(filp, attr.attr_size);
+		attr.attr = ret;
+		break;
+	case F2FS_EXTRA_ATTR_COMPR_OPTION:
+		ret = f2fs_get_compress_option_v2(filp, attr.attr,
+						  &attr.attr_size);
+		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_set_compress_option_v2(filp, attr.attr,
+						  &attr.attr_size);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
 static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	switch (cmd) {
@@ -4239,7 +4484,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:
@@ -4254,6 +4499,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/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 0a17484443299..aef9c1fd37dca 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)
 {
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 374c990810ead..64adaec4e98e0 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) -	\
diff --git a/include/uapi/linux/f2fs.h b/include/uapi/linux/f2fs.h
index 955d440be1046..a8fdaa22c7bda 100644
--- a/include/uapi/linux/f2fs.h
+++ b/include/uapi/linux/f2fs.h
@@ -44,6 +44,11 @@
 #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.
  * Flags for going down operation used by FS_IOC_GOINGDOWN
@@ -96,4 +101,34 @@ 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 */
+	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,
+						 * i_compress_flag
+						 */
+	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



_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [f2fs-dev] [PATCH v2 1/2] f2fs_io: add [get|set_attr] to access inode extra attributes
  2023-06-01  3:13   ` Chao Yu
@ 2023-06-04  3:56     ` Sheng Yong via Linux-f2fs-devel
  2023-06-04  3:56     ` [f2fs-dev] [PATCH v2 2/2] f2fs_io: convert compression ioctls to [get|set]_attr Sheng Yong via Linux-f2fs-devel
  1 sibling, 0 replies; 15+ messages in thread
From: Sheng Yong via Linux-f2fs-devel @ 2023-06-04  3:56 UTC (permalink / raw)
  To: jaegeuk, chao; +Cc: linux-f2fs-devel

This patch adds get_attr and set_attr to access inode's extra
attributes.

Signed-off-by: Sheng Yong <shengyong@oppo.com>
---
v2: update manpage of f2fs_io

---
 man/f2fs_io.8           |  65 ++++++++++++++++
 tools/f2fs_io/f2fs_io.c | 165 ++++++++++++++++++++++++++++++++++++++++
 tools/f2fs_io/f2fs_io.h |  34 +++++++++
 3 files changed, 264 insertions(+)

diff --git a/man/f2fs_io.8 b/man/f2fs_io.8
index 33789c2..591599f 100644
--- a/man/f2fs_io.8
+++ b/man/f2fs_io.8
@@ -135,6 +135,71 @@ Reserve free blocks to prepare decompressing blocks in the file.
 .TP
 \fBgc\fR \fI[sync_mode] [file]\fR
 Trigger filesystem GC
+.TP
+\fBget_attr\fR \fI[field] [file]\fR
+Get value of an extra attribution from a f2fs inode. The
+.I field
+parameter can be:
+.RS 1.2in
+.TP
+.B total_size
+total size of extra attribution area
+.TP
+.B isize
+size of extra attribution area of the f2fs inode
+.TP
+.B inline_xattr_size
+size of inline xattr size
+.TP
+.B projid
+project quota ID
+.TP
+.B inode_chksum
+inode checksum
+.TP
+.B crtime
+inode create time
+.TP
+.B cblocks
+number of compressed blocks
+.TP
+.B coption
+options of compression
+.RE
+.TP
+\fBset_attr\fR \fI[field] [values] [file]\fR
+Set value of a writable extra attribution to a f2fs inode. The
+.I field
+and
+.I values
+can be:
+.RS 1.2in
+.TP
+.B inline_xattr_size
+.I values
+is \fI[size]\fR
+.TP
+.B coption
+.I values
+are \fI[algorithm] [log_cluster_size] [level] [flag]\fR
+.TP
+.RS
+.TP
+.I
+algorithm
+compression algorithm (0:lz0, 1:lz4: 2:zstd, 3:lzorle)
+.TP
+.I log_cluster_size
+compression cluster log size (2 <= log_cluster_size <= 8)
+.TP
+.I level
+compression level
+.TP
+.I flag
+compression flag (1:chksum)
+.RE 1
+.RE 2
+.TP
 .SH AUTHOR
 This version of
 .B f2fs_io
diff --git a/tools/f2fs_io/f2fs_io.c b/tools/f2fs_io/f2fs_io.c
index 5bc0baf..70e0347 100644
--- a/tools/f2fs_io/f2fs_io.c
+++ b/tools/f2fs_io/f2fs_io.c
@@ -1311,6 +1311,169 @@ static void do_gc(int argc, char **argv, const struct cmd_desc *cmd)
 	exit(0);
 }
 
+#define get_attr_desc "get inode extra attribute"
+#define get_attr_help "f2fs_io get_attr [field] [file_path]\n\n"	\
+"field can be\n"							\
+"  total_size\n"							\
+"  isize\n"								\
+"  inline_xattr_size\n"							\
+"  projid\n"								\
+"  inode_chksum\n"							\
+"  crtime\n"								\
+"  cblocks\n"								\
+"  coption\n"
+
+static const char *extra_attr_fields[] = {
+	[F2FS_EXTRA_ATTR_TOTAL_SIZE] = "total_size",
+	[F2FS_EXTRA_ATTR_ISIZE] = "isize",
+	[F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE] = "inline_xattr_size",
+	[F2FS_EXTRA_ATTR_PROJID] = "projid",
+	[F2FS_EXTRA_ATTR_INODE_CHKSUM] = "inode_chksum",
+	[F2FS_EXTRA_ATTR_CRTIME] = "crtime",
+	[F2FS_EXTRA_ATTR_COMPR_BLOCKS] = "cblocks",
+	[F2FS_EXTRA_ATTR_COMPR_OPTION] = "coption",
+};
+
+static void do_get_attr(int argc, char **argv, const struct cmd_desc *cmd)
+{
+	struct f2fs_extra_attr attr = {0};
+	struct timespec ts = {0};
+	struct f2fs_comp_option_v2 coption = {0};
+	int ret, fd;
+
+	if (argc != 3) {
+		fputs("Excess arguments\n\n", stderr);
+		fputs(cmd->cmd_help, stderr);
+		exit(1);
+	}
+
+	for (attr.field = 0; attr.field < F2FS_EXTRA_ATTR_MAX; attr.field++) {
+		if (!strcmp(extra_attr_fields[attr.field], argv[1]))
+			break;
+	}
+
+	switch (attr.field) {
+	case F2FS_EXTRA_ATTR_TOTAL_SIZE:
+	case F2FS_EXTRA_ATTR_ISIZE:
+	case F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE:
+	case F2FS_EXTRA_ATTR_PROJID:
+	case F2FS_EXTRA_ATTR_INODE_CHKSUM:
+	case F2FS_EXTRA_ATTR_COMPR_BLOCKS:
+		attr.attr_size = sizeof(attr.attr);
+		break;
+	case F2FS_EXTRA_ATTR_CRTIME:
+		attr.attr_size = sizeof(ts);
+		attr.attr = (unsigned long)&ts;
+		break;
+	case F2FS_EXTRA_ATTR_COMPR_OPTION:
+		attr.attr_size = sizeof(coption);
+		attr.attr = (unsigned long)&coption;
+		break;
+	default:
+		die("Unknown field");
+	}
+
+	fd = xopen(argv[2], O_RDONLY, 0);
+
+	ret = ioctl(fd, F2FS_IOC_GET_EXTRA_ATTR, &attr);
+	if (ret < 0)
+		die_errno("F2FS_IOC_GET_EXTRA_ATTR failed");
+
+	switch (attr.field) {
+	case F2FS_EXTRA_ATTR_TOTAL_SIZE:
+	case F2FS_EXTRA_ATTR_ISIZE:
+	case F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE:
+	case F2FS_EXTRA_ATTR_PROJID:
+	case F2FS_EXTRA_ATTR_COMPR_BLOCKS:
+		printf("%"PRIu64"\n", attr.attr);
+		break;
+	case F2FS_EXTRA_ATTR_INODE_CHKSUM:
+		printf("0x%"PRIx64"\n", attr.attr);
+		break;
+	case F2FS_EXTRA_ATTR_CRTIME:
+		printf("sec: %lu\nnsec: %lu\n", ts.tv_sec, ts.tv_nsec);
+		break;
+	case F2FS_EXTRA_ATTR_COMPR_OPTION:
+		printf("compression algorithm:%u\n", coption.algorithm);
+		printf("compression cluster log size:%u\n", coption.log_cluster_size);
+		printf("compression level:%u\n", coption.level);
+		printf("compression flag:0x%x\n", coption.flag);
+		break;
+	default:
+		die("Unknown field");
+	}
+
+	exit(0);
+}
+
+#define set_attr_desc "set inode extra attribute"
+#define set_attr_help "f2fs_io set_attr [field] [values] [file_path]\n\n"	\
+"field can be\n"								\
+"  inline_xattr_size : [values] is [size]\n"					\
+"  coption : [values] are [algorithm] [log_cluster_size] [level] [flag]\n"	\
+"    algorithm        : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n"	\
+"    log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n"	\
+"    level            : compression level\n"					\
+"    flag             : compression flag (1:chksum)\n"
+
+static void do_set_attr(int argc, char **argv, const struct cmd_desc *cmd)
+{
+	struct f2fs_extra_attr attr = {0};
+	struct f2fs_comp_option_v2 coption = {0};
+	int i;
+	int ret, fd;
+
+	if (argc < 4)
+		goto out;
+
+	if (!strcmp(argv[1], extra_attr_fields[F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE])) {
+		if (argc != 4)
+			goto out;
+		i = 2;
+		attr.field = F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE;
+		attr.attr_size = sizeof(attr.attr);
+		attr.attr = atoi(argv[i++]);
+	} else if (!strcmp(argv[1], extra_attr_fields[F2FS_EXTRA_ATTR_COMPR_OPTION])) {
+		if (argc != 7)
+			goto out;
+		i = 2;
+		coption.algorithm = atoi(argv[i++]);
+		coption.log_cluster_size = atoi(argv[i++]);
+		coption.level = atoi(argv[i++]);
+		coption.flag = atoi(argv[i++]);
+		attr.field = F2FS_EXTRA_ATTR_COMPR_OPTION;
+		attr.attr_size = sizeof(coption);
+		attr.attr = (unsigned long)&coption;
+	} else {
+		die("Unknown or read only field");
+	}
+
+	fd = xopen(argv[i], O_WRONLY, 0);
+
+	ret = ioctl(fd, F2FS_IOC_SET_EXTRA_ATTR, &attr);
+	if (ret < 0)
+		die_errno("F2FS_IOC_SET_EXTRA_ATTR failed");
+
+	switch (attr.field) {
+	case F2FS_EXTRA_ATTR_INLINE_XATTR_SIZE:
+		printf("set inline_xattr_size:%"PRIu64"\n", attr.attr);
+		break;
+	case F2FS_EXTRA_ATTR_COMPR_OPTION:
+		printf("set compression option: algorithm=%u, "
+			"log_cluster_size=%u, level=%u, flag=0x%x\n",
+			coption.algorithm, coption.log_cluster_size,
+			coption.level, coption.flag);
+		break;
+	}
+
+	exit(0);
+out:
+	fputs("Excess arguments\n\n", stderr);
+	fputs(cmd->cmd_help, stderr);
+	exit(1);
+}
+
+
 #define CMD_HIDDEN 	0x0001
 #define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 }
 #define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN }
@@ -1343,6 +1506,8 @@ const struct cmd_desc cmd_list[] = {
 	CMD(get_filename_encrypt_mode),
 	CMD(rename),
 	CMD(gc),
+	CMD(get_attr),
+	CMD(set_attr),
 	{ NULL, NULL, NULL, NULL, 0 }
 };
 
diff --git a/tools/f2fs_io/f2fs_io.h b/tools/f2fs_io/f2fs_io.h
index 58be8f8..2c181e5 100644
--- a/tools/f2fs_io/f2fs_io.h
+++ b/tools/f2fs_io/f2fs_io.h
@@ -91,6 +91,10 @@ typedef u32	__be32;
 #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)
 
 #ifndef FSCRYPT_POLICY_V1
 #define FSCRYPT_POLICY_V1		0
@@ -216,3 +220,33 @@ struct f2fs_comp_option {
 	u8 algorithm;
 	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 */
+	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,
+						 * i_compress_flag
+						 */
+	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 */
+};
-- 
2.40.1



_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [f2fs-dev] [PATCH v2 2/2] f2fs_io: convert compression ioctls to [get|set]_attr
  2023-06-01  3:13   ` Chao Yu
  2023-06-04  3:56     ` [f2fs-dev] [PATCH v2 " Sheng Yong via Linux-f2fs-devel
@ 2023-06-04  3:56     ` Sheng Yong via Linux-f2fs-devel
  1 sibling, 0 replies; 15+ messages in thread
From: Sheng Yong via Linux-f2fs-devel @ 2023-06-04  3:56 UTC (permalink / raw)
  To: jaegeuk, chao; +Cc: linux-f2fs-devel

Convert old compression ioctls to get extra attr ioctls.

Signed-off-by: Sheng Yong <shengyong@oppo.com>
---
 tools/f2fs_io/f2fs_io.c | 25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/tools/f2fs_io/f2fs_io.c b/tools/f2fs_io/f2fs_io.c
index 70e0347..f6e6057 100644
--- a/tools/f2fs_io/f2fs_io.c
+++ b/tools/f2fs_io/f2fs_io.c
@@ -1012,7 +1012,9 @@ static void do_copy(int argc, char **argv, const struct cmd_desc *cmd)
 
 static void do_get_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
 {
-	unsigned long long blkcnt;
+	struct f2fs_extra_attr attr = {
+		.field = F2FS_EXTRA_ATTR_COMPR_BLOCKS,
+	};
 	int ret, fd;
 
 	if (argc != 2) {
@@ -1023,11 +1025,11 @@ static void do_get_cblocks(int argc, char **argv, const struct cmd_desc *cmd)
 
 	fd = xopen(argv[1], O_RDONLY, 0);
 
-	ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_BLOCKS, &blkcnt);
+	ret = ioctl(fd, F2FS_IOC_GET_EXTRA_ATTR, &attr);
 	if (ret < 0)
 		die_errno("F2FS_IOC_GET_COMPRESS_BLOCKS failed");
 
-	printf("%llu\n", blkcnt);
+	printf("%llu\n", (unsigned long long)attr.attr);
 
 	exit(0);
 }
@@ -1090,6 +1092,7 @@ static void do_reserve_cblocks(int argc, char **argv, const struct cmd_desc *cmd
 
 static void do_get_coption(int argc, char **argv, const struct cmd_desc *cmd)
 {
+	struct f2fs_extra_attr attr = {0};
 	struct f2fs_comp_option option;
 	int ret, fd;
 
@@ -1099,11 +1102,15 @@ static void do_get_coption(int argc, char **argv, const struct cmd_desc *cmd)
 		exit(1);
 	}
 
+	attr.field = F2FS_EXTRA_ATTR_COMPR_OPTION;
+	attr.attr_size = sizeof(option);
+	attr.attr = (unsigned long)&option;
+
 	fd = xopen(argv[1], O_RDONLY, 0);
 
-	ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_OPTION, &option);
+	ret = ioctl(fd, F2FS_IOC_GET_EXTRA_ATTR, &attr);
 	if (ret < 0)
-		die_errno("F2FS_IOC_GET_COMPRESS_OPTION failed");
+		die_errno("F2FS_IOC_GET_EXTRA_ATTR failed");
 
 	printf("compression algorithm:%u\n", option.algorithm);
 	printf("compression cluster log size:%u\n", option.log_cluster_size);
@@ -1119,6 +1126,7 @@ static void do_get_coption(int argc, char **argv, const struct cmd_desc *cmd)
 
 static void do_set_coption(int argc, char **argv, const struct cmd_desc *cmd)
 {
+	struct f2fs_extra_attr attr = {0};
 	struct f2fs_comp_option option;
 	int fd, ret;
 
@@ -1130,12 +1138,15 @@ static void do_set_coption(int argc, char **argv, const struct cmd_desc *cmd)
 
 	option.algorithm = atoi(argv[1]);
 	option.log_cluster_size = atoi(argv[2]);
+	attr.field = F2FS_EXTRA_ATTR_COMPR_OPTION;
+	attr.attr_size = sizeof(option);
+	attr.attr = (unsigned long)&option;
 
 	fd = xopen(argv[3], O_WRONLY, 0);
 
-	ret = ioctl(fd, F2FS_IOC_SET_COMPRESS_OPTION, &option);
+	ret = ioctl(fd, F2FS_IOC_SET_EXTRA_ATTR, &attr);
 	if (ret < 0)
-		die_errno("F2FS_IOC_SET_COMPRESS_OPTION failed");
+		die_errno("F2FS_IOC_SET_EXTRA_ATTR failed");
 
 	printf("set compression option: algorithm=%u, log_cluster_size=%u\n",
 			option.algorithm, option.log_cluster_size);
-- 
2.40.1



_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [f2fs-dev] [PATCH v3] f2fs: add f2fs_ioc_[get|set]_extra_attr
  2023-06-04  2:28     ` [f2fs-dev] [PATCH v3] " Sheng Yong via Linux-f2fs-devel
@ 2023-06-07 17:09       ` Jaegeuk Kim
  0 siblings, 0 replies; 15+ messages in thread
From: Jaegeuk Kim @ 2023-06-07 17:09 UTC (permalink / raw)
  To: Sheng Yong; +Cc: ebiggers, linux-kernel, linux-f2fs-devel

Could you please split the patches to have one topic each?
I do see
 - is_level_valid
 - f2fs_ioc_get_compress_blocks
 - f2fs_get_compress_option_v2
 - f2fs_ioc_get|set_extra_attr

Thanks,

On 06/04, Sheng Yong wrote:
> This patch introduces two ioctls:
>   * f2fs_ioc_get_extra_attr
>   * f2fs_ioc_set_extra_attr
> to get or modify values in 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 <shengyong@oppo.com>
> ---
> 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
> 
> ---
>  fs/f2fs/compress.c        |  33 +++++
>  fs/f2fs/f2fs.h            |   4 +
>  fs/f2fs/file.c            | 273 ++++++++++++++++++++++++++++++++++++--
>  fs/f2fs/inode.c           |  21 +++
>  fs/f2fs/super.c           |   2 +-
>  fs/f2fs/xattr.h           |   1 +
>  include/uapi/linux/f2fs.h |  35 +++++
>  7 files changed, 356 insertions(+), 13 deletions(-)
> 
> diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
> index 905b7c39a2b32..3fd804277059d 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)
> @@ -232,6 +233,7 @@ static const struct f2fs_compress_ops f2fs_lzo_ops = {
>  	.destroy_compress_ctx	= lzo_destroy_compress_ctx,
>  	.compress_pages		= lzo_compress_pages,
>  	.decompress_pages	= lzo_decompress_pages,
> +	.is_level_valid		= NULL,
>  };
>  #endif
>  
> @@ -308,11 +310,23 @@ static int lz4_decompress_pages(struct decompress_io_ctx *dic)
>  	return 0;
>  }
>  
> +static bool lz4_is_level_valid(int level)
> +{
> +	if (level == 0)
> +		return true;
> +#ifdef CONFIG_F2FS_FS_LZ4HC
> +	if (level >= LZ4HC_MIN_CLEVEL && level <= 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 +491,13 @@ static int zstd_decompress_pages(struct decompress_io_ctx *dic)
>  	return 0;
>  }
>  
> +static bool zstd_is_level_valid(int level)
> +{
> +	if (level < zstd_min_clevel() || level > 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 +505,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
>  
> @@ -508,6 +530,7 @@ static const struct f2fs_compress_ops f2fs_lzorle_ops = {
>  	.destroy_compress_ctx	= lzo_destroy_compress_ctx,
>  	.compress_pages		= lzorle_compress_pages,
>  	.decompress_pages	= lzo_decompress_pages,
> +	.is_level_valid		= NULL,
>  };
>  #endif
>  #endif
> @@ -542,6 +565,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 faa27f41f39d4..9fcf8f66c860c 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -3475,6 +3475,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);
> @@ -4232,6 +4234,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);
> @@ -4296,6 +4299,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/file.c b/fs/f2fs/file.c
> index 78aa8cff4b41d..353a2edacc549 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -3376,10 +3376,12 @@ 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 file *filp, unsigned int attr_size)
>  {
>  	struct inode *inode = file_inode(filp);
> -	__u64 blocks;
> +
> +	if (attr_size != sizeof(__u64))
> +		return -EINVAL;
>  
>  	if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
>  		return -EOPNOTSUPP;
> @@ -3387,7 +3389,14 @@ static int f2fs_get_compress_blocks(struct file *filp, unsigned long arg)
>  	if (!f2fs_compressed_file(inode))
>  		return -EINVAL;
>  
> -	blocks = atomic_read(&F2FS_I(inode)->i_compr_blocks);
> +	return atomic_read(&F2FS_I(inode)->i_compr_blocks);
> +}
> +
> +static int f2fs_ioc_get_compress_blocks(struct file *filp, unsigned long arg)
> +{
> +	__u64 blocks;
> +
> +	blocks = f2fs_get_compress_blocks(filp, sizeof(blocks));
>  	return put_user(blocks, (u64 __user *)arg);
>  }
>  
> @@ -3905,10 +3914,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;
> @@ -3922,31 +3935,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) ||
> @@ -3955,6 +3979,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);
>  
> @@ -3971,6 +4003,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))
> @@ -3983,6 +4019,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);
> @@ -4168,6 +4211,208 @@ 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:
> +		ret = f2fs_get_compress_blocks(filp, attr.attr_size);
> +		attr.attr = ret;
> +		break;
> +	case F2FS_EXTRA_ATTR_COMPR_OPTION:
> +		ret = f2fs_get_compress_option_v2(filp, attr.attr,
> +						  &attr.attr_size);
> +		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_set_compress_option_v2(filp, attr.attr,
> +						  &attr.attr_size);
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
>  static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
>  {
>  	switch (cmd) {
> @@ -4239,7 +4484,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:
> @@ -4254,6 +4499,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/fs/f2fs/inode.c b/fs/f2fs/inode.c
> index 0a17484443299..aef9c1fd37dca 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)
>  {
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index 374c990810ead..64adaec4e98e0 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) -	\
> diff --git a/include/uapi/linux/f2fs.h b/include/uapi/linux/f2fs.h
> index 955d440be1046..a8fdaa22c7bda 100644
> --- a/include/uapi/linux/f2fs.h
> +++ b/include/uapi/linux/f2fs.h
> @@ -44,6 +44,11 @@
>  #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.
>   * Flags for going down operation used by FS_IOC_GOINGDOWN
> @@ -96,4 +101,34 @@ 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 */
> +	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,
> +						 * i_compress_flag
> +						 */
> +	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


_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2023-06-07 17:10 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-05-29  1:35 [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr Sheng Yong via Linux-f2fs-devel
2023-05-29  1:35 ` [f2fs-dev] [PATCH 1/2] f2fs_io: add [get|set_attr] to access inode extra attributes Sheng Yong via Linux-f2fs-devel
2023-06-01  3:13   ` Chao Yu
2023-06-04  3:56     ` [f2fs-dev] [PATCH v2 " Sheng Yong via Linux-f2fs-devel
2023-06-04  3:56     ` [f2fs-dev] [PATCH v2 2/2] f2fs_io: convert compression ioctls to [get|set]_attr Sheng Yong via Linux-f2fs-devel
2023-05-29  1:35 ` [f2fs-dev] [PATCH " Sheng Yong via Linux-f2fs-devel
2023-05-29  6:10 ` [f2fs-dev] [PATCH] f2fs: add f2fs_ioc_[get|set]_extra_attr kernel test robot
2023-05-29  6:20 ` kernel test robot
2023-05-29  8:19 ` kernel test robot
2023-05-30  6:34 ` [f2fs-dev] [PATCH v2] " Sheng Yong via Linux-f2fs-devel
2023-06-01  3:06   ` Chao Yu
2023-06-04  2:28     ` [f2fs-dev] [PATCH v3] " Sheng Yong via Linux-f2fs-devel
2023-06-07 17:09       ` Jaegeuk Kim
2023-06-01  3:16 ` [f2fs-dev] [PATCH] " Eric Biggers
2023-06-01 14:37   ` Sheng Yong via Linux-f2fs-devel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).