diff options
author | alex chen <alex.chen@huawei.com> | 2014-06-23 16:22:07 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-23 19:47:45 -0400 |
commit | 5fb1beb069dcf616e88be9d330b86878a79aa4ff (patch) | |
tree | d14175b91979c4d64a433710f9a9e0168ef4919e /fs | |
parent | d05f0cdcbe6388723f1900c549b4850360545201 (diff) |
ocfs2: should add inode into orphan dir after updating entry in ocfs2_rename()
There are two files a and b in dir /mnt/ocfs2.
node A node B
mv a b
In ocfs2_rename(), after calling
ocfs2_orphan_add(), the inode of
file b will be added into orphan
dir.
If ocfs2_update_entry() fails,
ocfs2_rename return error and mv
operation fails. But file b still
exists in the parent dir.
ocfs2_queue_orphan_scan
-> ocfs2_queue_recovery_completion
-> ocfs2_complete_recovery
-> ocfs2_recover_orphans
The inode of the file b will be
put with iput().
ocfs2_evict_inode
-> ocfs2_delete_inode
-> ocfs2_wipe_inode
-> ocfs2_remove_inode
OCFS2_VALID_FL in the inode
i_flags will be cleared.
The file b still can be accessed
on node B.
ls /mnt/ocfs2
When first read the file b with
ocfs2_read_inode_block(). It will
validate the inode using
ocfs2_validate_inode_block().
Because OCFS2_VALID_FL not set in
the inode i_flags, so the file
system will be readonly.
So we should add inode into orphan dir after updating entry in
ocfs2_rename().
Signed-off-by: alex.chen <alex.chen@huawei.com>
Reviewed-by: Mark Fasheh <mfasheh@suse.de>
Cc: Joel Becker <jlbec@evilplan.org>
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.c | 22 |
1 files changed, 11 insertions, 11 deletions
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 2060fc398445..5819bb5d6483 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c | |||
@@ -1098,6 +1098,7 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1098 | struct ocfs2_dir_lookup_result old_entry_lookup = { NULL, }; | 1098 | struct ocfs2_dir_lookup_result old_entry_lookup = { NULL, }; |
1099 | struct ocfs2_dir_lookup_result orphan_insert = { NULL, }; | 1099 | struct ocfs2_dir_lookup_result orphan_insert = { NULL, }; |
1100 | struct ocfs2_dir_lookup_result target_insert = { NULL, }; | 1100 | struct ocfs2_dir_lookup_result target_insert = { NULL, }; |
1101 | bool should_add_orphan = false; | ||
1101 | 1102 | ||
1102 | /* At some point it might be nice to break this function up a | 1103 | /* At some point it might be nice to break this function up a |
1103 | * bit. */ | 1104 | * bit. */ |
@@ -1304,6 +1305,7 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1304 | mlog_errno(status); | 1305 | mlog_errno(status); |
1305 | goto bail; | 1306 | goto bail; |
1306 | } | 1307 | } |
1308 | should_add_orphan = true; | ||
1307 | } | 1309 | } |
1308 | } else { | 1310 | } else { |
1309 | BUG_ON(new_dentry->d_parent->d_inode != new_dir); | 1311 | BUG_ON(new_dentry->d_parent->d_inode != new_dir); |
@@ -1348,17 +1350,6 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1348 | goto bail; | 1350 | goto bail; |
1349 | } | 1351 | } |
1350 | 1352 | ||
1351 | if (S_ISDIR(new_inode->i_mode) || | ||
1352 | (ocfs2_read_links_count(newfe) == 1)) { | ||
1353 | status = ocfs2_orphan_add(osb, handle, new_inode, | ||
1354 | newfe_bh, orphan_name, | ||
1355 | &orphan_insert, orphan_dir); | ||
1356 | if (status < 0) { | ||
1357 | mlog_errno(status); | ||
1358 | goto bail; | ||
1359 | } | ||
1360 | } | ||
1361 | |||
1362 | /* change the dirent to point to the correct inode */ | 1353 | /* change the dirent to point to the correct inode */ |
1363 | status = ocfs2_update_entry(new_dir, handle, &target_lookup_res, | 1354 | status = ocfs2_update_entry(new_dir, handle, &target_lookup_res, |
1364 | old_inode); | 1355 | old_inode); |
@@ -1373,6 +1364,15 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1373 | else | 1364 | else |
1374 | ocfs2_add_links_count(newfe, -1); | 1365 | ocfs2_add_links_count(newfe, -1); |
1375 | ocfs2_journal_dirty(handle, newfe_bh); | 1366 | ocfs2_journal_dirty(handle, newfe_bh); |
1367 | if (should_add_orphan) { | ||
1368 | status = ocfs2_orphan_add(osb, handle, new_inode, | ||
1369 | newfe_bh, orphan_name, | ||
1370 | &orphan_insert, orphan_dir); | ||
1371 | if (status < 0) { | ||
1372 | mlog_errno(status); | ||
1373 | goto bail; | ||
1374 | } | ||
1375 | } | ||
1376 | } else { | 1376 | } else { |
1377 | /* if the name was not found in new_dir, add it now */ | 1377 | /* if the name was not found in new_dir, add it now */ |
1378 | status = ocfs2_add_entry(handle, new_dentry, old_inode, | 1378 | status = ocfs2_add_entry(handle, new_dentry, old_inode, |