aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorYounger Liu <younger.liu@huawei.com>2013-07-03 18:01:01 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-03 19:07:24 -0400
commitb5a8bb717e29b549584cc27ac8e109a803c4f8c4 (patch)
tree8047e4dfbd7c03e7b3b755bfe331430f8358b4af /fs
parent25e2892101ba541dce8593c698d70ccc278bc1fd (diff)
ocfs2: fix readonly issue in ocfs2_unlink()
While deleting a file with ocfs2_unlink(), there is a bug in this function. This bug will result in filesystem read-only. After calling ocfs2_orphan_add(), the file which will be deleted is added into orphan dir. If ocfs2_delete_entry() fails, the file still exists in the parent dir. And this scenario introduces a conflict of metadata. If a file is added into orphan dir, when we put inode of the file with iput(), the inode i_flags is setted (~OCFS2_VALID_FL) in ocfs2_remove_inode(), and then write back to disk. But as previously mentioned, the file still exists in the parent dir. On other nodes, the file can be still accessed. When first read the file with ocfs2_read_blocks() from disk, It will check and avalidate inode using ocfs2_validate_inode_block(). So File system will be readonly because the inode is invalid. In other words, the inode i_flags has been set (~OCFS2_VALID_FL). [akpm@linux-foundation.org: cleanups] [jeff.liu@oracle.com: s/inode_is_unlinkable/ocfs2_inode_is_unlinkable/] Signed-off-by: Younger Liu <younger.liu@huawei.com> Signed-off-by: Jensen <shencanquan@huawei.com> Cc: Jie Liu <jeff.liu@oracle.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Mark Fasheh <mfasheh@suse.com> Cc: Sunil Mushran <sunil.mushran@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/ocfs2/namei.c23
1 files changed, 12 insertions, 11 deletions
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 30842f5cf590..be3f8676a438 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -773,7 +773,7 @@ static int ocfs2_remote_dentry_delete(struct dentry *dentry)
773 return ret; 773 return ret;
774} 774}
775 775
776static inline int inode_is_unlinkable(struct inode *inode) 776static inline int ocfs2_inode_is_unlinkable(struct inode *inode)
777{ 777{
778 if (S_ISDIR(inode->i_mode)) { 778 if (S_ISDIR(inode->i_mode)) {
779 if (inode->i_nlink == 2) 779 if (inode->i_nlink == 2)
@@ -791,6 +791,7 @@ static int ocfs2_unlink(struct inode *dir,
791{ 791{
792 int status; 792 int status;
793 int child_locked = 0; 793 int child_locked = 0;
794 bool is_unlinkable = false;
794 struct inode *inode = dentry->d_inode; 795 struct inode *inode = dentry->d_inode;
795 struct inode *orphan_dir = NULL; 796 struct inode *orphan_dir = NULL;
796 struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); 797 struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
@@ -865,7 +866,7 @@ static int ocfs2_unlink(struct inode *dir,
865 goto leave; 866 goto leave;
866 } 867 }
867 868
868 if (inode_is_unlinkable(inode)) { 869 if (ocfs2_inode_is_unlinkable(inode)) {
869 status = ocfs2_prepare_orphan_dir(osb, &orphan_dir, 870 status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
870 OCFS2_I(inode)->ip_blkno, 871 OCFS2_I(inode)->ip_blkno,
871 orphan_name, &orphan_insert); 872 orphan_name, &orphan_insert);
@@ -873,6 +874,7 @@ static int ocfs2_unlink(struct inode *dir,
873 mlog_errno(status); 874 mlog_errno(status);
874 goto leave; 875 goto leave;
875 } 876 }
877 is_unlinkable = true;
876 } 878 }
877 879
878 handle = ocfs2_start_trans(osb, ocfs2_unlink_credits(osb->sb)); 880 handle = ocfs2_start_trans(osb, ocfs2_unlink_credits(osb->sb));
@@ -892,15 +894,6 @@ static int ocfs2_unlink(struct inode *dir,
892 894
893 fe = (struct ocfs2_dinode *) fe_bh->b_data; 895 fe = (struct ocfs2_dinode *) fe_bh->b_data;
894 896
895 if (inode_is_unlinkable(inode)) {
896 status = ocfs2_orphan_add(osb, handle, inode, fe_bh, orphan_name,
897 &orphan_insert, orphan_dir);
898 if (status < 0) {
899 mlog_errno(status);
900 goto leave;
901 }
902 }
903
904 /* delete the name from the parent dir */ 897 /* delete the name from the parent dir */
905 status = ocfs2_delete_entry(handle, dir, &lookup); 898 status = ocfs2_delete_entry(handle, dir, &lookup);
906 if (status < 0) { 899 if (status < 0) {
@@ -923,6 +916,14 @@ static int ocfs2_unlink(struct inode *dir,
923 mlog_errno(status); 916 mlog_errno(status);
924 if (S_ISDIR(inode->i_mode)) 917 if (S_ISDIR(inode->i_mode))
925 inc_nlink(dir); 918 inc_nlink(dir);
919 goto leave;
920 }
921
922 if (is_unlinkable) {
923 status = ocfs2_orphan_add(osb, handle, inode, fe_bh,
924 orphan_name, &orphan_insert, orphan_dir);
925 if (status < 0)
926 mlog_errno(status);
926 } 927 }
927 928
928leave: 929leave: