[Ocfs2-devel] [PATCH] ocfs2: fix readonly issue in ocfs2_unlink()
Andrew Morton
akpm at linux-foundation.org
Thu Jun 27 14:58:55 PDT 2013
On Thu, 27 Jun 2013 11:05:40 +0800 Younger Liu <younger.liu at 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);
}
_
More information about the Ocfs2-devel
mailing list