ocfs2: roll back the reference count modification of the parent directory if an error occurs

Under some conditions, the directory cannot be deleted.  The specific
scenarios are as follows: (for example, /mnt/ocfs2 is the mount point)

1. Create the /mnt/ocfs2/p_dir directory.  At this time, the i_nlink
   corresponding to the inode of the /mnt/ocfs2/p_dir directory is equal
   to 2.

2. During the process of creating the /mnt/ocfs2/p_dir/s_dir
   directory, if the call to the inc_nlink function in ocfs2_mknod
   succeeds, the functions such as ocfs2_init_acl,
   ocfs2_init_security_set, and ocfs2_dentry_attach_lock fail.  At this
   time, the i_nlink corresponding to the inode of the /mnt/ocfs2/p_dir
   directory is equal to 3, but /mnt/ocfs2/p_dir/s_dir is not added to the
   /mnt/ocfs2/p_dir directory entry.

3. Delete the /mnt/ocfs2/p_dir directory (rm -rf /mnt/ocfs2/p_dir).
   At this time, it is found that the i_nlink corresponding to the inode
   corresponding to the /mnt/ocfs2/p_dir directory is equal to 3.
   Therefore, the /mnt/ocfs2/p_dir directory cannot be deleted.

Signed-off-by: Jian wang <wangjian161@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Jun Piao <piaojun@huawei.com>
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Gang He <ghe@suse.com>
Cc: Jun Piao <piaojun@huawei.com>
Link: http://lkml.kernel.org/r/a44f6666-bbc4-405e-0e6c-0f4e922eeef6@huawei.com
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
wangjian 2020-04-01 21:04:02 -07:00 committed by Linus Torvalds
parent 95f3427c24
commit 0434c9f404

View File

@ -406,7 +406,7 @@ static int ocfs2_mknod(struct inode *dir,
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
goto leave; goto roll_back;
} }
if (si.enable) { if (si.enable) {
@ -414,7 +414,7 @@ static int ocfs2_mknod(struct inode *dir,
meta_ac, data_ac); meta_ac, data_ac);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
goto leave; goto roll_back;
} }
} }
@ -427,7 +427,7 @@ static int ocfs2_mknod(struct inode *dir,
OCFS2_I(dir)->ip_blkno); OCFS2_I(dir)->ip_blkno);
if (status) { if (status) {
mlog_errno(status); mlog_errno(status);
goto leave; goto roll_back;
} }
dl = dentry->d_fsdata; dl = dentry->d_fsdata;
@ -437,12 +437,19 @@ static int ocfs2_mknod(struct inode *dir,
&lookup); &lookup);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
goto leave; goto roll_back;
} }
insert_inode_hash(inode); insert_inode_hash(inode);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
status = 0; status = 0;
roll_back:
if (status < 0 && S_ISDIR(mode)) {
ocfs2_add_links_count(dirfe, -1);
drop_nlink(dir);
}
leave: leave:
if (status < 0 && did_quota_inode) if (status < 0 && did_quota_inode)
dquot_free_inode(inode); dquot_free_inode(inode);