[PATCH 1/2] f2fs_io: add [get|set_attr] to access inode extra attributes

From: Sheng Yong
Date: Sun May 28 2023 - 21:36:02 EST


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

Signed-off-by: Sheng Yong <shengyong@xxxxxxxx>
---
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