diff options
Diffstat (limited to 'patches.tizen/0517-f2fs-fix-handling-orphan-inodes.patch')
-rw-r--r-- | patches.tizen/0517-f2fs-fix-handling-orphan-inodes.patch | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/patches.tizen/0517-f2fs-fix-handling-orphan-inodes.patch b/patches.tizen/0517-f2fs-fix-handling-orphan-inodes.patch new file mode 100644 index 00000000000..01eaf959e60 --- /dev/null +++ b/patches.tizen/0517-f2fs-fix-handling-orphan-inodes.patch @@ -0,0 +1,165 @@ +From 99d07ec7f4d6f77f5eeb4507243432d6df72c067 Mon Sep 17 00:00:00 2001 +From: Jaegeuk Kim <jaegeuk.kim@samsung.com> +Date: Tue, 30 Jul 2013 11:36:53 +0900 +Subject: [PATCH 0517/1302] f2fs: fix handling orphan inodes + +This patch fixes mishandling of the sbi->n_orphans variable. + +If users request lots of f2fs_unlink(), check_orphan_space() could be contended. +In such the case, sbi->n_orphans can be read incorrectly so that f2fs_unlink() +would fall into the wrong state which results in the failure of +add_orphan_inode(). + +So, let's increment sbi->n_orphans virtually prior to the actual orphan inode +stuffs. After that, let's release sbi->n_orphans by calling release_orphan_inode +or remove_orphan_inode. + +Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com> +Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com> +--- + fs/f2fs/checkpoint.c | 13 ++++++++++--- + fs/f2fs/dir.c | 2 ++ + fs/f2fs/f2fs.h | 3 ++- + fs/f2fs/namei.c | 19 ++++++++++++++----- + 4 files changed, 28 insertions(+), 9 deletions(-) + +diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c +index fe91773..c5a5c39 100644 +--- a/fs/f2fs/checkpoint.c ++++ b/fs/f2fs/checkpoint.c +@@ -182,7 +182,7 @@ const struct address_space_operations f2fs_meta_aops = { + .set_page_dirty = f2fs_set_meta_page_dirty, + }; + +-int check_orphan_space(struct f2fs_sb_info *sbi) ++int acquire_orphan_inode(struct f2fs_sb_info *sbi) + { + unsigned int max_orphans; + int err = 0; +@@ -197,10 +197,19 @@ int check_orphan_space(struct f2fs_sb_info *sbi) + mutex_lock(&sbi->orphan_inode_mutex); + if (sbi->n_orphans >= max_orphans) + err = -ENOSPC; ++ else ++ sbi->n_orphans++; + mutex_unlock(&sbi->orphan_inode_mutex); + return err; + } + ++void release_orphan_inode(struct f2fs_sb_info *sbi) ++{ ++ mutex_lock(&sbi->orphan_inode_mutex); ++ sbi->n_orphans--; ++ mutex_unlock(&sbi->orphan_inode_mutex); ++} ++ + void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) + { + struct list_head *head, *this; +@@ -229,8 +238,6 @@ retry: + list_add(&new->list, this->prev); + else + list_add_tail(&new->list, head); +- +- sbi->n_orphans++; + out: + mutex_unlock(&sbi->orphan_inode_mutex); + } +diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c +index 4d96362..ecf0fde 100644 +--- a/fs/f2fs/dir.c ++++ b/fs/f2fs/dir.c +@@ -572,6 +572,8 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, + + if (inode->i_nlink == 0) + add_orphan_inode(sbi, inode->i_ino); ++ else ++ release_orphan_inode(sbi); + } + + if (bit_pos == NR_DENTRY_IN_BLOCK) { +diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h +index a6858c7..78777cd 100644 +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -1044,7 +1044,8 @@ void destroy_segment_manager(struct f2fs_sb_info *); + struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t); + struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t); + long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long); +-int check_orphan_space(struct f2fs_sb_info *); ++int acquire_orphan_inode(struct f2fs_sb_info *); ++void release_orphan_inode(struct f2fs_sb_info *); + void add_orphan_inode(struct f2fs_sb_info *, nid_t); + void remove_orphan_inode(struct f2fs_sb_info *, nid_t); + int recover_orphan_inodes(struct f2fs_sb_info *); +diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c +index 3297278..4e47518 100644 +--- a/fs/f2fs/namei.c ++++ b/fs/f2fs/namei.c +@@ -239,7 +239,7 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) + if (!de) + goto fail; + +- err = check_orphan_space(sbi); ++ err = acquire_orphan_inode(sbi); + if (err) { + kunmap(page); + f2fs_put_page(page, 0); +@@ -393,7 +393,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *old_inode = old_dentry->d_inode; + struct inode *new_inode = new_dentry->d_inode; + struct page *old_dir_page; +- struct page *old_page; ++ struct page *old_page, *new_page; + struct f2fs_dir_entry *old_dir_entry = NULL; + struct f2fs_dir_entry *old_entry; + struct f2fs_dir_entry *new_entry; +@@ -415,7 +415,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, + ilock = mutex_lock_op(sbi); + + if (new_inode) { +- struct page *new_page; + + err = -ENOTEMPTY; + if (old_dir_entry && !f2fs_empty_dir(new_inode)) +@@ -427,9 +426,13 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, + if (!new_entry) + goto out_dir; + ++ err = acquire_orphan_inode(sbi); ++ if (err) ++ goto put_out_dir; ++ + if (update_dent_inode(old_inode, &new_dentry->d_name)) { +- f2fs_put_page(new_page, 1); +- goto out_dir; ++ release_orphan_inode(sbi); ++ goto put_out_dir; + } + + f2fs_set_link(new_dir, new_entry, new_page, old_inode); +@@ -438,8 +441,12 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, + if (old_dir_entry) + drop_nlink(new_inode); + drop_nlink(new_inode); ++ + if (!new_inode->i_nlink) + add_orphan_inode(sbi, new_inode->i_ino); ++ else ++ release_orphan_inode(sbi); ++ + update_inode_page(new_inode); + } else { + err = f2fs_add_link(new_dentry, old_inode); +@@ -472,6 +479,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, + mutex_unlock_op(sbi, ilock); + return 0; + ++put_out_dir: ++ f2fs_put_page(new_page, 1); + out_dir: + if (old_dir_entry) { + kunmap(old_dir_page); +-- +1.8.3.2 + |