On Thu, 27 Jun 2013 11:05:40 +0800 Younger Liu <younger....@huawei.com> wrote:
> 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 setted (~OCFS2_VALID_FL). > > ... > > --- a/fs/ocfs2/namei.c > +++ b/fs/ocfs2/namei.c > @@ -790,7 +790,7 @@ static int ocfs2_unlink(struct inode *dir, > struct dentry *dentry) > { > int status; > - int child_locked = 0; > + int child_locked = 0, is_unlinkable = 0; Please note that the surrounding code was carful to use the one-definition-per-line convention. That's a good convention - more readable, less patch rejects during code evolution, leaves room for a nice little comment. Also, type `bool' would have been appropraite here. > struct inode *inode = dentry->d_inode; > struct inode *orphan_dir = NULL; > struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); > @@ -873,6 +873,7 @@ static int ocfs2_unlink(struct inode *dir, > mlog_errno(status); > goto leave; > } > + is_unlinkable = 1; > } > > handle = ocfs2_start_trans(osb, ocfs2_unlink_credits(osb->sb)); > @@ -892,15 +893,6 @@ static int ocfs2_unlink(struct inode *dir, > > fe = (struct ocfs2_dinode *) fe_bh->b_data; > > - if (inode_is_unlinkable(inode)) { > - status = ocfs2_orphan_add(osb, handle, inode, fe_bh, > orphan_name, > - &orphan_insert, orphan_dir); > - if (status < 0) { > - mlog_errno(status); > - goto leave; > - } > - } > - > /* delete the name from the parent dir */ > status = ocfs2_delete_entry(handle, dir, &lookup); > if (status < 0) { > @@ -923,6 +915,14 @@ static int ocfs2_unlink(struct inode *dir, > mlog_errno(status); > if (S_ISDIR(inode->i_mode)) > inc_nlink(dir); > + goto leave; > + } > + > + if (is_unlinkable) { > + status = ocfs2_orphan_add(osb, handle, inode, fe_bh, > orphan_name, > + &orphan_insert, orphan_dir); > + if (status < 0) > + mlog_errno(status); > } This is yet another ocfs2 function which reports the same error two times. ho hum. Please review: --- a/fs/ocfs2/namei.c~ocfs2-fix-readonly-issue-in-ocfs2_unlink-fix +++ a/fs/ocfs2/namei.c @@ -790,7 +790,8 @@ static int ocfs2_unlink(struct inode *di struct dentry *dentry) { int status; - int child_locked = 0, is_unlinkable = 0; + int child_locked = 0; + bool is_unlinkable = false; struct inode *inode = dentry->d_inode; struct inode *orphan_dir = NULL; struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); @@ -873,7 +874,7 @@ static int ocfs2_unlink(struct inode *di mlog_errno(status); goto leave; } - is_unlinkable = 1; + is_unlinkable = true; } handle = ocfs2_start_trans(osb, ocfs2_unlink_credits(osb->sb)); @@ -919,8 +920,8 @@ static int ocfs2_unlink(struct inode *di } if (is_unlinkable) { - status = ocfs2_orphan_add(osb, handle, inode, fe_bh, orphan_name, - &orphan_insert, orphan_dir); + status = ocfs2_orphan_add(osb, handle, inode, fe_bh, + orphan_name, &orphan_insert, orphan_dir); if (status < 0) mlog_errno(status); } _ _______________________________________________ Ocfs2-devel mailing list Ocfs2-devel@oss.oracle.com https://oss.oracle.com/mailman/listinfo/ocfs2-devel