Skip to content

Commit

Permalink
f2fs: support hot file extension
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Jaegeuk Kim <[email protected]>
  • Loading branch information
chaseyu authored and Jaegeuk Kim committed Mar 12, 2018
1 parent 1dc0f89 commit b6a06cb
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 31 deletions.
6 changes: 4 additions & 2 deletions Documentation/ABI/testing/sysfs-fs-f2fs
Original file line number Diff line number Diff line change
Expand Up @@ -199,5 +199,7 @@ Contact: "Chao Yu" <[email protected]>
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
6 changes: 5 additions & 1 deletion fs/f2fs/f2fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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

Expand Down Expand Up @@ -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);

/*
Expand Down
79 changes: 59 additions & 20 deletions fs/f2fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
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);
Expand All @@ -168,54 +168,93 @@ 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;

if (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;
}

Expand All @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion fs/f2fs/segment.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
30 changes: 24 additions & 6 deletions fs/f2fs/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
Expand All @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion include/linux/f2fs_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/*
Expand Down

0 comments on commit b6a06cb

Please sign in to comment.