diff options
Diffstat (limited to 'patches.tizen/0458-f2fs-update-inode-page-after-creation.patch')
-rw-r--r-- | patches.tizen/0458-f2fs-update-inode-page-after-creation.patch | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/patches.tizen/0458-f2fs-update-inode-page-after-creation.patch b/patches.tizen/0458-f2fs-update-inode-page-after-creation.patch new file mode 100644 index 00000000000..b8bc63eb2b6 --- /dev/null +++ b/patches.tizen/0458-f2fs-update-inode-page-after-creation.patch @@ -0,0 +1,256 @@ +From 5eb8b0eeb5f7d51ae8dffdf84ad77fd68aa32c30 Mon Sep 17 00:00:00 2001 +From: Jaegeuk Kim <jaegeuk.kim@samsung.com> +Date: Mon, 20 May 2013 10:10:29 +0900 +Subject: [PATCH 0458/1302] f2fs: update inode page after creation + +I found a bug when testing power-off-recovery as follows. + +[Bug Scenario] +1. create a file +2. fsync the file +3. reboot w/o any sync +4. try to recover the file + - found its fsync mark + - found its dentry mark + : try to recover its dentry + - get its file name + - get its parent inode number + : here we got zero value + +The reason why we get the wrong parent inode number is that we didn't +synchronize the inode page with its newly created inode information perfectly. + +Especially, previous f2fs stores fi->i_pino and writes it to the cached +node page in a wrong order, which incurs the zero-valued i_pino during the +recovery. + +So, this patch modifies the creation flow to fix the synchronization order of +inode page with its inode. + +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com> +--- + fs/f2fs/data.c | 1 + + fs/f2fs/dir.c | 85 +++++++++++++++++++++++++++++++--------------------------- + fs/f2fs/f2fs.h | 3 +-- + fs/f2fs/node.c | 12 +++------ + 4 files changed, 51 insertions(+), 50 deletions(-) + +diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c +index af74549..c320f7f 100644 +--- a/fs/f2fs/data.c ++++ b/fs/f2fs/data.c +@@ -279,6 +279,7 @@ repeat: + * + * Also, caller should grab and release a mutex by calling mutex_lock_op() and + * mutex_unlock_op(). ++ * Note that, npage is set only by make_empty_dir. + */ + struct page *get_new_data_page(struct inode *inode, + struct page *npage, pgoff_t index, bool new_i_size) +diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c +index 7db6e58..fc1dacf 100644 +--- a/fs/f2fs/dir.c ++++ b/fs/f2fs/dir.c +@@ -264,15 +264,10 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de, + f2fs_put_page(page, 1); + } + +-void init_dent_inode(const struct qstr *name, struct page *ipage) ++static void init_dent_inode(const struct qstr *name, struct page *ipage) + { + struct f2fs_node *rn; + +- if (IS_ERR(ipage)) +- return; +- +- wait_on_page_writeback(ipage); +- + /* copy name info. to this inode page */ + rn = (struct f2fs_node *)page_address(ipage); + rn->i.i_namelen = cpu_to_le32(name->len); +@@ -280,14 +275,15 @@ void init_dent_inode(const struct qstr *name, struct page *ipage) + set_page_dirty(ipage); + } + +-static int make_empty_dir(struct inode *inode, struct inode *parent) ++static int make_empty_dir(struct inode *inode, ++ struct inode *parent, struct page *page) + { + struct page *dentry_page; + struct f2fs_dentry_block *dentry_blk; + struct f2fs_dir_entry *de; + void *kaddr; + +- dentry_page = get_new_data_page(inode, NULL, 0, true); ++ dentry_page = get_new_data_page(inode, page, 0, true); + if (IS_ERR(dentry_page)) + return PTR_ERR(dentry_page); + +@@ -317,42 +313,47 @@ static int make_empty_dir(struct inode *inode, struct inode *parent) + return 0; + } + +-static int init_inode_metadata(struct inode *inode, ++static struct page *init_inode_metadata(struct inode *inode, + struct inode *dir, const struct qstr *name) + { ++ struct page *page; ++ int err; ++ + if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { +- int err; +- err = new_inode_page(inode, name); +- if (err) +- return err; ++ page = new_inode_page(inode, name); ++ if (IS_ERR(page)) ++ return page; + + if (S_ISDIR(inode->i_mode)) { +- err = make_empty_dir(inode, dir); +- if (err) { +- remove_inode_page(inode); +- return err; +- } ++ err = make_empty_dir(inode, dir, page); ++ if (err) ++ goto error; + } + + err = f2fs_init_acl(inode, dir); +- if (err) { +- remove_inode_page(inode); +- return err; +- } ++ if (err) ++ goto error; ++ ++ wait_on_page_writeback(page); + } else { +- struct page *ipage; +- ipage = get_node_page(F2FS_SB(dir->i_sb), inode->i_ino); +- if (IS_ERR(ipage)) +- return PTR_ERR(ipage); +- set_cold_node(inode, ipage); +- init_dent_inode(name, ipage); +- f2fs_put_page(ipage, 1); ++ page = get_node_page(F2FS_SB(dir->i_sb), inode->i_ino); ++ if (IS_ERR(page)) ++ return page; ++ ++ wait_on_page_writeback(page); ++ set_cold_node(inode, page); + } +- if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) { ++ ++ init_dent_inode(name, page); ++ ++ if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) + inc_nlink(inode); +- update_inode_page(inode); +- } +- return 0; ++ return page; ++ ++error: ++ f2fs_put_page(page, 1); ++ remove_inode_page(inode); ++ return ERR_PTR(err); + } + + static void update_parent_metadata(struct inode *dir, struct inode *inode, +@@ -423,6 +424,7 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, struct inode *in + struct page *dentry_page = NULL; + struct f2fs_dentry_block *dentry_blk = NULL; + int slots = GET_DENTRY_SLOTS(namelen); ++ struct page *page; + int err = 0; + int i; + +@@ -465,12 +467,13 @@ start: + ++level; + goto start; + add_dentry: +- err = init_inode_metadata(inode, dir, name); +- if (err) +- goto fail; +- + wait_on_page_writeback(dentry_page); + ++ page = init_inode_metadata(inode, dir, name); ++ if (IS_ERR(page)) { ++ err = PTR_ERR(page); ++ goto fail; ++ } + de = &dentry_blk->dentry[bit_pos]; + de->hash_code = dentry_hash; + de->name_len = cpu_to_le16(namelen); +@@ -481,10 +484,12 @@ add_dentry: + test_and_set_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap); + set_page_dirty(dentry_page); + +- update_parent_metadata(dir, inode, current_depth); +- +- /* update parent inode number before releasing dentry page */ ++ /* we don't need to mark_inode_dirty now */ + F2FS_I(inode)->i_pino = dir->i_ino; ++ update_inode(inode, page); ++ f2fs_put_page(page, 1); ++ ++ update_parent_metadata(dir, inode, current_depth); + fail: + kunmap(dentry_page); + f2fs_put_page(dentry_page, 1); +diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h +index cbae2b6..9360a03 100644 +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -914,7 +914,6 @@ struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **); + ino_t f2fs_inode_by_name(struct inode *, struct qstr *); + void f2fs_set_link(struct inode *, struct f2fs_dir_entry *, + struct page *, struct inode *); +-void init_dent_inode(const struct qstr *, struct page *); + int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *); + void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *); + int f2fs_make_empty(struct inode *, struct inode *); +@@ -949,7 +948,7 @@ void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *); + int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int); + int truncate_inode_blocks(struct inode *, pgoff_t); + int remove_inode_page(struct inode *); +-int new_inode_page(struct inode *, const struct qstr *); ++struct page *new_inode_page(struct inode *, const struct qstr *); + struct page *new_node_page(struct dnode_of_data *, unsigned int); + void ra_node_page(struct f2fs_sb_info *, nid_t); + struct page *get_node_page(struct f2fs_sb_info *, pgoff_t); +diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c +index f63f0a4..b41482d 100644 +--- a/fs/f2fs/node.c ++++ b/fs/f2fs/node.c +@@ -806,19 +806,15 @@ int remove_inode_page(struct inode *inode) + return 0; + } + +-int new_inode_page(struct inode *inode, const struct qstr *name) ++struct page *new_inode_page(struct inode *inode, const struct qstr *name) + { +- struct page *page; + struct dnode_of_data dn; + + /* allocate inode page for new inode */ + set_new_dnode(&dn, inode, NULL, NULL, inode->i_ino); +- page = new_node_page(&dn, 0); +- init_dent_inode(name, page); +- if (IS_ERR(page)) +- return PTR_ERR(page); +- f2fs_put_page(page, 1); +- return 0; ++ ++ /* caller should f2fs_put_page(page, 1); */ ++ return new_node_page(&dn, 0); + } + + struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs) +-- +1.8.3.2 + |