Commit 354a3399 authored by Jaegeuk Kim's avatar Jaegeuk Kim

f2fs: recover wrong pino after checkpoint during fsync

If a file is linked, f2fs loose its parent inode number so that fsync calls
for the linked file should do checkpoint all the time.
But, if we can recover its parent inode number after the checkpoint, we can
adjust roll-forward mechanism for the further fsync calls, which is able to
improve the fsync performance significatly.
Signed-off-by: default avatarJaegeuk Kim <jaegeuk.kim@samsung.com>
parent b25958b6
...@@ -356,7 +356,7 @@ static struct page *init_inode_metadata(struct inode *inode, ...@@ -356,7 +356,7 @@ static struct page *init_inode_metadata(struct inode *inode,
* We lost i_pino from now on. * We lost i_pino from now on.
*/ */
if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) { if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) {
set_cp_file(inode); file_lost_pino(inode);
inc_nlink(inode); inc_nlink(inode);
} }
return page; return page;
......
...@@ -151,7 +151,7 @@ struct extent_info { ...@@ -151,7 +151,7 @@ struct extent_info {
* i_advise uses FADVISE_XXX_BIT. We can add additional hints later. * i_advise uses FADVISE_XXX_BIT. We can add additional hints later.
*/ */
#define FADVISE_COLD_BIT 0x01 #define FADVISE_COLD_BIT 0x01
#define FADVISE_CP_BIT 0x02 #define FADVISE_LOST_PINO_BIT 0x02
struct f2fs_inode_info { struct f2fs_inode_info {
struct inode vfs_inode; /* serve a vfs inode */ struct inode vfs_inode; /* serve a vfs inode */
......
...@@ -102,6 +102,24 @@ static const struct vm_operations_struct f2fs_file_vm_ops = { ...@@ -102,6 +102,24 @@ static const struct vm_operations_struct f2fs_file_vm_ops = {
.remap_pages = generic_file_remap_pages, .remap_pages = generic_file_remap_pages,
}; };
static int get_parent_ino(struct inode *inode, nid_t *pino)
{
struct dentry *dentry;
inode = igrab(inode);
dentry = d_find_any_alias(inode);
iput(inode);
if (!dentry)
return 0;
inode = igrab(dentry->d_parent->d_inode);
dput(dentry);
*pino = inode->i_ino;
iput(inode);
return 1;
}
int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
{ {
struct inode *inode = file->f_mapping->host; struct inode *inode = file->f_mapping->host;
...@@ -134,7 +152,7 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) ...@@ -134,7 +152,7 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1) if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1)
need_cp = true; need_cp = true;
else if (is_cp_file(inode)) else if (file_wrong_pino(inode))
need_cp = true; need_cp = true;
else if (!space_for_roll_forward(sbi)) else if (!space_for_roll_forward(sbi))
need_cp = true; need_cp = true;
...@@ -142,8 +160,19 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) ...@@ -142,8 +160,19 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
need_cp = true; need_cp = true;
if (need_cp) { if (need_cp) {
nid_t pino;
/* all the dirty node pages should be flushed for POR */ /* all the dirty node pages should be flushed for POR */
ret = f2fs_sync_fs(inode->i_sb, 1); ret = f2fs_sync_fs(inode->i_sb, 1);
if (file_wrong_pino(inode) && inode->i_nlink == 1 &&
get_parent_ino(inode, &pino)) {
F2FS_I(inode)->i_pino = pino;
file_got_pino(inode);
mark_inode_dirty_sync(inode);
ret = f2fs_write_inode(inode, NULL);
if (ret)
goto out;
}
} else { } else {
/* if there is no written node page, write its inode page */ /* if there is no written node page, write its inode page */
while (!sync_node_pages(sbi, inode->i_ino, &wbc)) { while (!sync_node_pages(sbi, inode->i_ino, &wbc)) {
......
...@@ -112,7 +112,7 @@ static inline void set_cold_files(struct f2fs_sb_info *sbi, struct inode *inode, ...@@ -112,7 +112,7 @@ static inline void set_cold_files(struct f2fs_sb_info *sbi, struct inode *inode,
int count = le32_to_cpu(sbi->raw_super->extension_count); int count = le32_to_cpu(sbi->raw_super->extension_count);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (is_multimedia_file(name, extlist[i])) { if (is_multimedia_file(name, extlist[i])) {
set_cold_file(inode); file_set_cold(inode);
break; break;
} }
} }
......
...@@ -285,10 +285,17 @@ static inline void set_file(struct inode *inode, int type) ...@@ -285,10 +285,17 @@ static inline void set_file(struct inode *inode, int type)
F2FS_I(inode)->i_advise |= type; F2FS_I(inode)->i_advise |= type;
} }
#define is_cold_file(inode) is_file(inode, FADVISE_COLD_BIT) static inline void clear_file(struct inode *inode, int type)
#define is_cp_file(inode) is_file(inode, FADVISE_CP_BIT) {
#define set_cold_file(inode) set_file(inode, FADVISE_COLD_BIT) F2FS_I(inode)->i_advise &= ~type;
#define set_cp_file(inode) set_file(inode, FADVISE_CP_BIT) }
#define file_is_cold(inode) is_file(inode, FADVISE_COLD_BIT)
#define file_wrong_pino(inode) is_file(inode, FADVISE_LOST_PINO_BIT)
#define file_set_cold(inode) set_file(inode, FADVISE_COLD_BIT)
#define file_lost_pino(inode) set_file(inode, FADVISE_LOST_PINO_BIT)
#define file_clear_cold(inode) clear_file(inode, FADVISE_COLD_BIT)
#define file_got_pino(inode) clear_file(inode, FADVISE_LOST_PINO_BIT)
static inline int is_cold_data(struct page *page) static inline int is_cold_data(struct page *page)
{ {
......
...@@ -796,7 +796,7 @@ static int __get_segment_type_6(struct page *page, enum page_type p_type) ...@@ -796,7 +796,7 @@ static int __get_segment_type_6(struct page *page, enum page_type p_type)
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
return CURSEG_HOT_DATA; return CURSEG_HOT_DATA;
else if (is_cold_data(page) || is_cold_file(inode)) else if (is_cold_data(page) || file_is_cold(inode))
return CURSEG_COLD_DATA; return CURSEG_COLD_DATA;
else else
return CURSEG_WARM_DATA; return CURSEG_WARM_DATA;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment