f2fs: support hot file extension
authorChao Yu <yuchao0@huawei.com>
Wed, 28 Feb 2018 09:07:27 +0000 (17:07 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Mon, 12 Mar 2018 23:05:57 +0000 (08:05 +0900)
This patch supports to recognize hot file extension in f2fs, so that we
can allocate proper hot segment location for its data, which can lead to
better hot/cold seperation in filesystem.

In addition, we changes a bit on query/add/del operation method for
extension_list sysfs entry as below:

- Query: cat /sys/fs/f2fs/<disk>/extension_list
- Add: echo 'extension' > /sys/fs/f2fs/<disk>/extension_list
- Del: echo '!extension' > /sys/fs/f2fs/<disk>/extension_list
- Add: echo '[h/c]extension' > /sys/fs/f2fs/<disk>/extension_list
- Del: echo '[h/c]!extension' > /sys/fs/f2fs/<disk>/extension_list
- [h] means add/del hot file extension
- [c] means add/del cold file extension

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Documentation/ABI/testing/sysfs-fs-f2fs
fs/f2fs/f2fs.h
fs/f2fs/namei.c
fs/f2fs/segment.c
fs/f2fs/sysfs.c
include/linux/f2fs_fs.h

index 7fa84e3..540553c 100644 (file)
@@ -199,5 +199,7 @@ Contact:    "Chao Yu" <yuchao0@huawei.com>
 Description:
                 Used to control configure extension list:
                 - Query: cat /sys/fs/f2fs/<disk>/extension_list
-                - Add: echo 'extension' > /sys/fs/f2fs/<disk>/extension_list
-                - Del: echo '!extension' > /sys/fs/f2fs/<disk>/extension_list
+                - Add: echo '[h/c]extension' > /sys/fs/f2fs/<disk>/extension_list
+                - Del: echo '[h/c]!extension' > /sys/fs/f2fs/<disk>/extension_list
+                - [h] means add/del hot file extension
+                - [c] means add/del cold file extension
index 833c9bc..f6dc706 100644 (file)
@@ -576,6 +576,7 @@ enum {
 #define FADVISE_ENCRYPT_BIT    0x04
 #define FADVISE_ENC_NAME_BIT   0x08
 #define FADVISE_KEEP_SIZE_BIT  0x10
+#define FADVISE_HOT_BIT                0x20
 
 #define file_is_cold(inode)    is_file(inode, FADVISE_COLD_BIT)
 #define file_wrong_pino(inode) is_file(inode, FADVISE_LOST_PINO_BIT)
@@ -590,6 +591,9 @@ enum {
 #define file_set_enc_name(inode) set_file(inode, FADVISE_ENC_NAME_BIT)
 #define file_keep_isize(inode) is_file(inode, FADVISE_KEEP_SIZE_BIT)
 #define file_set_keep_isize(inode) set_file(inode, FADVISE_KEEP_SIZE_BIT)
+#define file_is_hot(inode)     is_file(inode, FADVISE_HOT_BIT)
+#define file_set_hot(inode)    set_file(inode, FADVISE_HOT_BIT)
+#define file_clear_hot(inode)  clear_file(inode, FADVISE_HOT_BIT)
 
 #define DEF_DIR_LEVEL          0
 
@@ -2614,7 +2618,7 @@ void handle_failed_inode(struct inode *inode);
  * namei.c
  */
 int update_extension_list(struct f2fs_sb_info *sbi, const char *name,
-                                                               bool set);
+                                                       bool hot, bool set);
 struct dentry *f2fs_get_parent(struct dentry *child);
 
 /*
index 2bd6e9f..78ea015 100644 (file)
@@ -142,7 +142,7 @@ fail_drop:
        return ERR_PTR(err);
 }
 
-static int is_multimedia_file(const unsigned char *s, const char *sub)
+static int is_extension_exist(const unsigned char *s, const char *sub)
 {
        size_t slen = strlen(s);
        size_t sublen = strlen(sub);
@@ -168,33 +168,59 @@ static int is_multimedia_file(const unsigned char *s, const char *sub)
 /*
  * Set multimedia files as cold files for hot/cold data separation
  */
-static inline void set_cold_files(struct f2fs_sb_info *sbi, struct inode *inode,
+static inline void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
                const unsigned char *name)
 {
        __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
-       int i, count;
+       int i, cold_count, hot_count;
 
        down_read(&sbi->sb_lock);
 
-       count = le32_to_cpu(sbi->raw_super->extension_count);
+       cold_count = le32_to_cpu(sbi->raw_super->extension_count);
+       hot_count = sbi->raw_super->hot_ext_count;
 
-       for (i = 0; i < count; i++) {
-               if (is_multimedia_file(name, extlist[i])) {
+       for (i = 0; i < cold_count + hot_count; i++) {
+               if (!is_extension_exist(name, extlist[i]))
+                       continue;
+               if (i < cold_count)
                        file_set_cold(inode);
-                       break;
-               }
+               else
+                       file_set_hot(inode);
+               break;
        }
 
        up_read(&sbi->sb_lock);
 }
 
-int update_extension_list(struct f2fs_sb_info *sbi, const char *name, bool set)
+int update_extension_list(struct f2fs_sb_info *sbi, const char *name,
+                                                       bool hot, bool set)
 {
        __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
-       int count = le32_to_cpu(sbi->raw_super->extension_count);
+       int cold_count = le32_to_cpu(sbi->raw_super->extension_count);
+       int hot_count = sbi->raw_super->hot_ext_count;
+       int total_count = cold_count + hot_count;
+       int start, count;
        int i;
 
-       for (i = 0; i < count; i++) {
+       if (set) {
+               if (total_count == F2FS_MAX_EXTENSION)
+                       return -EINVAL;
+       } else {
+               if (!hot && !cold_count)
+                       return -EINVAL;
+               if (hot && !hot_count)
+                       return -EINVAL;
+       }
+
+       if (hot) {
+               start = cold_count;
+               count = total_count;
+       } else {
+               start = 0;
+               count = cold_count;
+       }
+
+       for (i = start; i < count; i++) {
                if (strcmp(name, extlist[i]))
                        continue;
 
@@ -202,20 +228,33 @@ int update_extension_list(struct f2fs_sb_info *sbi, const char *name, bool set)
                        return -EINVAL;
 
                memcpy(extlist[i], extlist[i + 1],
-                               F2FS_EXTENSION_LEN * (count - i - 1));
-               memset(extlist[count - 1], 0, F2FS_EXTENSION_LEN);
-               sbi->raw_super->extension_count = cpu_to_le32(count - 1);
+                               F2FS_EXTENSION_LEN * (total_count - i - 1));
+               memset(extlist[total_count - 1], 0, F2FS_EXTENSION_LEN);
+               if (hot)
+                       sbi->raw_super->hot_ext_count = hot_count - 1;
+               else
+                       sbi->raw_super->extension_count =
+                                               cpu_to_le32(cold_count - 1);
                return 0;
        }
 
        if (!set)
                return -EINVAL;
 
-       if (count == F2FS_MAX_EXTENSION)
-               return -EINVAL;
-
-       strncpy(extlist[count], name, strlen(name));
-       sbi->raw_super->extension_count = cpu_to_le32(count + 1);
+       if (hot) {
+               strncpy(extlist[count], name, strlen(name));
+               sbi->raw_super->hot_ext_count = hot_count + 1;
+       } else {
+               char buf[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];
+
+               memcpy(buf, &extlist[cold_count],
+                               F2FS_EXTENSION_LEN * hot_count);
+               memset(extlist[cold_count], 0, F2FS_EXTENSION_LEN);
+               strncpy(extlist[cold_count], name, strlen(name));
+               memcpy(&extlist[cold_count + 1], buf,
+                               F2FS_EXTENSION_LEN * hot_count);
+               sbi->raw_super->extension_count = cpu_to_le32(cold_count + 1);
+       }
        return 0;
 }
 
@@ -239,7 +278,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
                return PTR_ERR(inode);
 
        if (!test_opt(sbi, DISABLE_EXT_IDENTIFY))
-               set_cold_files(sbi, inode, dentry->d_name.name);
+               set_file_temperature(sbi, inode, dentry->d_name.name);
 
        inode->i_op = &f2fs_file_inode_operations;
        inode->i_fop = &f2fs_file_operations;
index 1e3dd3d..f61c77b 100644 (file)
@@ -2587,7 +2587,8 @@ static int __get_segment_type_6(struct f2fs_io_info *fio)
 
                if (is_cold_data(fio->page) || file_is_cold(inode))
                        return CURSEG_COLD_DATA;
-               if (is_inode_flag_set(inode, FI_HOT_DATA))
+               if (file_is_hot(inode) ||
+                               is_inode_flag_set(inode, FI_HOT_DATA))
                        return CURSEG_HOT_DATA;
                return rw_hint_to_seg_type(inode->i_write_hint);
        } else {
index d27b28e..23a2d8d 100644 (file)
@@ -139,10 +139,19 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
        if (!strcmp(a->attr.name, "extension_list")) {
                __u8 (*extlist)[F2FS_EXTENSION_LEN] =
                                        sbi->raw_super->extension_list;
-               int count = le32_to_cpu(sbi->raw_super->extension_count);
+               int cold_count = le32_to_cpu(sbi->raw_super->extension_count);
+               int hot_count = sbi->raw_super->hot_ext_count;
                int len = 0, i;
 
-               for (i = 0; i < count; i++)
+               len += snprintf(buf + len, PAGE_SIZE - len,
+                                               "cold file extenstion:\n");
+               for (i = 0; i < cold_count; i++)
+                       len += snprintf(buf + len, PAGE_SIZE - len, "%s\n",
+                                                               extlist[i]);
+
+               len += snprintf(buf + len, PAGE_SIZE - len,
+                                               "hot file extenstion:\n");
+               for (i = cold_count; i < cold_count + hot_count; i++)
                        len += snprintf(buf + len, PAGE_SIZE - len, "%s\n",
                                                                extlist[i]);
                return len;
@@ -168,9 +177,18 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
 
        if (!strcmp(a->attr.name, "extension_list")) {
                const char *name = strim((char *)buf);
-               bool set = true;
+               bool set = true, hot;
+
+               if (!strncmp(name, "[h]", 3))
+                       hot = true;
+               else if (!strncmp(name, "[c]", 3))
+                       hot = false;
+               else
+                       return -EINVAL;
+
+               name += 3;
 
-               if (name[0] == '!') {
+               if (*name == '!') {
                        name++;
                        set = false;
                }
@@ -180,13 +198,13 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
 
                down_write(&sbi->sb_lock);
 
-               ret = update_extension_list(sbi, name, set);
+               ret = update_extension_list(sbi, name, hot, set);
                if (ret)
                        goto out;
 
                ret = f2fs_commit_super(sbi, false);
                if (ret)
-                       update_extension_list(sbi, name, !set);
+                       update_extension_list(sbi, name, hot, !set);
 out:
                up_write(&sbi->sb_lock);
                return ret ? ret : count;
index d8c2414..b06ab1f 100644 (file)
@@ -111,7 +111,8 @@ struct f2fs_super_block {
        __u8 encrypt_pw_salt[16];       /* Salt used for string2key algorithm */
        struct f2fs_device devs[MAX_DEVICES];   /* device list */
        __le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */
-       __u8 reserved[315];             /* valid reserved region */
+       __u8 hot_ext_count;             /* # of hot file extension */
+       __u8 reserved[314];             /* valid reserved region */
 } __packed;
 
 /*