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 */
+};
