Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5fb1beb0 authored by alex chen's avatar alex chen Committed by Linus Torvalds
Browse files

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: default avataralex.chen <alex.chen@huawei.com>
Reviewed-by: default avatarMark Fasheh <mfasheh@suse.de>
Cc: Joel Becker <jlbec@evilplan.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d05f0cdc
Loading
Loading
Loading
Loading
+11 −11
Original line number Diff line number Diff line
@@ -1098,6 +1098,7 @@ static int ocfs2_rename(struct inode *old_dir,
	struct ocfs2_dir_lookup_result old_entry_lookup = { NULL, };
	struct ocfs2_dir_lookup_result orphan_insert = { NULL, };
	struct ocfs2_dir_lookup_result target_insert = { NULL, };
	bool should_add_orphan = false;

	/* At some point it might be nice to break this function up a
	 * bit. */
@@ -1304,6 +1305,7 @@ static int ocfs2_rename(struct inode *old_dir,
				mlog_errno(status);
				goto bail;
			}
			should_add_orphan = true;
		}
	} else {
		BUG_ON(new_dentry->d_parent->d_inode != new_dir);
@@ -1348,17 +1350,6 @@ static int ocfs2_rename(struct inode *old_dir,
			goto bail;
		}

		if (S_ISDIR(new_inode->i_mode) ||
		    (ocfs2_read_links_count(newfe) == 1)) {
			status = ocfs2_orphan_add(osb, handle, new_inode,
						  newfe_bh, orphan_name,
						  &orphan_insert, orphan_dir);
			if (status < 0) {
				mlog_errno(status);
				goto bail;
			}
		}

		/* change the dirent to point to the correct inode */
		status = ocfs2_update_entry(new_dir, handle, &target_lookup_res,
					    old_inode);
@@ -1373,6 +1364,15 @@ static int ocfs2_rename(struct inode *old_dir,
		else
			ocfs2_add_links_count(newfe, -1);
		ocfs2_journal_dirty(handle, newfe_bh);
		if (should_add_orphan) {
			status = ocfs2_orphan_add(osb, handle, new_inode,
					newfe_bh, orphan_name,
					&orphan_insert, orphan_dir);
			if (status < 0) {
				mlog_errno(status);
				goto bail;
			}
		}
	} else {
		/* if the name was not found in new_dir, add it now */
		status = ocfs2_add_entry(handle, new_dentry, old_inode,