提交 c0d268c3 编写于 作者: M Miklos Szeredi

ext4: rename: create ext4_renament structure for local vars

Need to split up ext4_rename() into helpers but there are too many local
variables involved, so create a new structure.  This also, apparently,
makes the generated code size slightly smaller.
Signed-off-by: NMiklos Szeredi <mszeredi@suse.cz>
Reviewed-by: NJan Kara <jack@suse.cz>
上级 da1ce067
...@@ -3000,6 +3000,22 @@ static struct buffer_head *ext4_get_first_dir_block(handle_t *handle, ...@@ -3000,6 +3000,22 @@ static struct buffer_head *ext4_get_first_dir_block(handle_t *handle,
return ext4_get_first_inline_block(inode, parent_de, retval); return ext4_get_first_inline_block(inode, parent_de, retval);
} }
struct ext4_renament {
struct inode *dir;
struct dentry *dentry;
struct inode *inode;
/* entry for "dentry" */
struct buffer_head *bh;
struct ext4_dir_entry_2 *de;
int inlined;
/* entry for ".." in inode if it's a directory */
struct buffer_head *dir_bh;
struct ext4_dir_entry_2 *parent_de;
int dir_inlined;
};
/* /*
* Anybody can rename anything with this: the permission checks are left to the * Anybody can rename anything with this: the permission checks are left to the
* higher-level routines. * higher-level routines.
...@@ -3012,193 +3028,194 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -3012,193 +3028,194 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry) struct inode *new_dir, struct dentry *new_dentry)
{ {
handle_t *handle = NULL; handle_t *handle = NULL;
struct inode *old_inode, *new_inode; struct ext4_renament old = {
struct buffer_head *old_bh, *new_bh, *dir_bh; .dir = old_dir,
struct ext4_dir_entry_2 *old_de, *new_de; .dentry = old_dentry,
.inode = old_dentry->d_inode,
};
struct ext4_renament new = {
.dir = new_dir,
.dentry = new_dentry,
.inode = new_dentry->d_inode,
};
int retval; int retval;
int inlined = 0, new_inlined = 0;
struct ext4_dir_entry_2 *parent_de;
dquot_initialize(old_dir);
dquot_initialize(new_dir);
old_bh = new_bh = dir_bh = NULL; dquot_initialize(old.dir);
dquot_initialize(new.dir);
/* Initialize quotas before so that eventual writes go /* Initialize quotas before so that eventual writes go
* in separate transaction */ * in separate transaction */
if (new_dentry->d_inode) if (new.inode)
dquot_initialize(new_dentry->d_inode); dquot_initialize(new.inode);
old_bh = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de, NULL); old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL);
/* /*
* Check for inode number is _not_ due to possible IO errors. * Check for inode number is _not_ due to possible IO errors.
* We might rmdir the source, keep it as pwd of some process * We might rmdir the source, keep it as pwd of some process
* and merrily kill the link to whatever was created under the * and merrily kill the link to whatever was created under the
* same name. Goodbye sticky bit ;-< * same name. Goodbye sticky bit ;-<
*/ */
old_inode = old_dentry->d_inode;
retval = -ENOENT; retval = -ENOENT;
if (!old_bh || le32_to_cpu(old_de->inode) != old_inode->i_ino) if (!old.bh || le32_to_cpu(old.de->inode) != old.inode->i_ino)
goto end_rename; goto end_rename;
new_inode = new_dentry->d_inode; new.bh = ext4_find_entry(new.dir, &new.dentry->d_name,
new_bh = ext4_find_entry(new_dir, &new_dentry->d_name, &new.de, &new.inlined);
&new_de, &new_inlined); if (new.bh) {
if (new_bh) { if (!new.inode) {
if (!new_inode) { brelse(new.bh);
brelse(new_bh); new.bh = NULL;
new_bh = NULL;
} }
} }
if (new_inode && !test_opt(new_dir->i_sb, NO_AUTO_DA_ALLOC)) if (new.inode && !test_opt(new.dir->i_sb, NO_AUTO_DA_ALLOC))
ext4_alloc_da_blocks(old_inode); ext4_alloc_da_blocks(old.inode);
handle = ext4_journal_start(old_dir, EXT4_HT_DIR, handle = ext4_journal_start(old.dir, EXT4_HT_DIR,
(2 * EXT4_DATA_TRANS_BLOCKS(old_dir->i_sb) + (2 * EXT4_DATA_TRANS_BLOCKS(old.dir->i_sb) +
EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2)); EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2));
if (IS_ERR(handle)) if (IS_ERR(handle))
return PTR_ERR(handle); return PTR_ERR(handle);
if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir))
ext4_handle_sync(handle); ext4_handle_sync(handle);
if (S_ISDIR(old_inode->i_mode)) { if (S_ISDIR(old.inode->i_mode)) {
if (new_inode) { if (new.inode) {
retval = -ENOTEMPTY; retval = -ENOTEMPTY;
if (!empty_dir(new_inode)) if (!empty_dir(new.inode))
goto end_rename; goto end_rename;
} }
retval = -EIO; retval = -EIO;
dir_bh = ext4_get_first_dir_block(handle, old_inode, old.dir_bh = ext4_get_first_dir_block(handle, old.inode,
&retval, &parent_de, &retval, &old.parent_de,
&inlined); &old.dir_inlined);
if (!dir_bh) if (!old.dir_bh)
goto end_rename; goto end_rename;
if (le32_to_cpu(parent_de->inode) != old_dir->i_ino) if (le32_to_cpu(old.parent_de->inode) != old.dir->i_ino)
goto end_rename; goto end_rename;
retval = -EMLINK; retval = -EMLINK;
if (!new_inode && new_dir != old_dir && if (!new.inode && new.dir != old.dir &&
EXT4_DIR_LINK_MAX(new_dir)) EXT4_DIR_LINK_MAX(new.dir))
goto end_rename; goto end_rename;
BUFFER_TRACE(dir_bh, "get_write_access"); BUFFER_TRACE(old.dir_bh, "get_write_access");
retval = ext4_journal_get_write_access(handle, dir_bh); retval = ext4_journal_get_write_access(handle, old.dir_bh);
if (retval) if (retval)
goto end_rename; goto end_rename;
} }
if (!new_bh) { if (!new.bh) {
retval = ext4_add_entry(handle, new_dentry, old_inode); retval = ext4_add_entry(handle, new.dentry, old.inode);
if (retval) if (retval)
goto end_rename; goto end_rename;
} else { } else {
BUFFER_TRACE(new_bh, "get write access"); BUFFER_TRACE(new.bh, "get write access");
retval = ext4_journal_get_write_access(handle, new_bh); retval = ext4_journal_get_write_access(handle, new.bh);
if (retval) if (retval)
goto end_rename; goto end_rename;
new_de->inode = cpu_to_le32(old_inode->i_ino); new.de->inode = cpu_to_le32(old.inode->i_ino);
if (EXT4_HAS_INCOMPAT_FEATURE(new_dir->i_sb, if (EXT4_HAS_INCOMPAT_FEATURE(new.dir->i_sb,
EXT4_FEATURE_INCOMPAT_FILETYPE)) EXT4_FEATURE_INCOMPAT_FILETYPE))
new_de->file_type = old_de->file_type; new.de->file_type = old.de->file_type;
new_dir->i_version++; new.dir->i_version++;
new_dir->i_ctime = new_dir->i_mtime = new.dir->i_ctime = new.dir->i_mtime =
ext4_current_time(new_dir); ext4_current_time(new.dir);
ext4_mark_inode_dirty(handle, new_dir); ext4_mark_inode_dirty(handle, new.dir);
BUFFER_TRACE(new_bh, "call ext4_handle_dirty_metadata"); BUFFER_TRACE(new.bh, "call ext4_handle_dirty_metadata");
if (!new_inlined) { if (!new.inlined) {
retval = ext4_handle_dirty_dirent_node(handle, retval = ext4_handle_dirty_dirent_node(handle,
new_dir, new_bh); new.dir, new.bh);
if (unlikely(retval)) { if (unlikely(retval)) {
ext4_std_error(new_dir->i_sb, retval); ext4_std_error(new.dir->i_sb, retval);
goto end_rename; goto end_rename;
} }
} }
brelse(new_bh); brelse(new.bh);
new_bh = NULL; new.bh = NULL;
} }
/* /*
* Like most other Unix systems, set the ctime for inodes on a * Like most other Unix systems, set the ctime for inodes on a
* rename. * rename.
*/ */
old_inode->i_ctime = ext4_current_time(old_inode); old.inode->i_ctime = ext4_current_time(old.inode);
ext4_mark_inode_dirty(handle, old_inode); ext4_mark_inode_dirty(handle, old.inode);
/* /*
* ok, that's it * ok, that's it
*/ */
if (le32_to_cpu(old_de->inode) != old_inode->i_ino || if (le32_to_cpu(old.de->inode) != old.inode->i_ino ||
old_de->name_len != old_dentry->d_name.len || old.de->name_len != old.dentry->d_name.len ||
strncmp(old_de->name, old_dentry->d_name.name, old_de->name_len) || strncmp(old.de->name, old.dentry->d_name.name, old.de->name_len) ||
(retval = ext4_delete_entry(handle, old_dir, (retval = ext4_delete_entry(handle, old.dir,
old_de, old_bh)) == -ENOENT) { old.de, old.bh)) == -ENOENT) {
/* old_de could have moved from under us during htree split, so /* old.de could have moved from under us during htree split, so
* make sure that we are deleting the right entry. We might * make sure that we are deleting the right entry. We might
* also be pointing to a stale entry in the unused part of * also be pointing to a stale entry in the unused part of
* old_bh so just checking inum and the name isn't enough. */ * old.bh so just checking inum and the name isn't enough. */
struct buffer_head *old_bh2; struct buffer_head *old_bh2;
struct ext4_dir_entry_2 *old_de2; struct ext4_dir_entry_2 *old_de2;
old_bh2 = ext4_find_entry(old_dir, &old_dentry->d_name, old_bh2 = ext4_find_entry(old.dir, &old.dentry->d_name,
&old_de2, NULL); &old_de2, NULL);
if (old_bh2) { if (old_bh2) {
retval = ext4_delete_entry(handle, old_dir, retval = ext4_delete_entry(handle, old.dir,
old_de2, old_bh2); old_de2, old_bh2);
brelse(old_bh2); brelse(old_bh2);
} }
} }
if (retval) { if (retval) {
ext4_warning(old_dir->i_sb, ext4_warning(old.dir->i_sb,
"Deleting old file (%lu), %d, error=%d", "Deleting old file (%lu), %d, error=%d",
old_dir->i_ino, old_dir->i_nlink, retval); old.dir->i_ino, old.dir->i_nlink, retval);
} }
if (new_inode) { if (new.inode) {
ext4_dec_count(handle, new_inode); ext4_dec_count(handle, new.inode);
new_inode->i_ctime = ext4_current_time(new_inode); new.inode->i_ctime = ext4_current_time(new.inode);
} }
old_dir->i_ctime = old_dir->i_mtime = ext4_current_time(old_dir); old.dir->i_ctime = old.dir->i_mtime = ext4_current_time(old.dir);
ext4_update_dx_flag(old_dir); ext4_update_dx_flag(old.dir);
if (dir_bh) { if (old.dir_bh) {
parent_de->inode = cpu_to_le32(new_dir->i_ino); old.parent_de->inode = cpu_to_le32(new.dir->i_ino);
BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata"); BUFFER_TRACE(old.dir_bh, "call ext4_handle_dirty_metadata");
if (!inlined) { if (!old.dir_inlined) {
if (is_dx(old_inode)) { if (is_dx(old.inode)) {
retval = ext4_handle_dirty_dx_node(handle, retval = ext4_handle_dirty_dx_node(handle,
old_inode, old.inode,
dir_bh); old.dir_bh);
} else { } else {
retval = ext4_handle_dirty_dirent_node(handle, retval = ext4_handle_dirty_dirent_node(handle,
old_inode, dir_bh); old.inode, old.dir_bh);
} }
} else { } else {
retval = ext4_mark_inode_dirty(handle, old_inode); retval = ext4_mark_inode_dirty(handle, old.inode);
} }
if (retval) { if (retval) {
ext4_std_error(old_dir->i_sb, retval); ext4_std_error(old.dir->i_sb, retval);
goto end_rename; goto end_rename;
} }
ext4_dec_count(handle, old_dir); ext4_dec_count(handle, old.dir);
if (new_inode) { if (new.inode) {
/* checked empty_dir above, can't have another parent, /* checked empty_dir above, can't have another parent,
* ext4_dec_count() won't work for many-linked dirs */ * ext4_dec_count() won't work for many-linked dirs */
clear_nlink(new_inode); clear_nlink(new.inode);
} else { } else {
ext4_inc_count(handle, new_dir); ext4_inc_count(handle, new.dir);
ext4_update_dx_flag(new_dir); ext4_update_dx_flag(new.dir);
ext4_mark_inode_dirty(handle, new_dir); ext4_mark_inode_dirty(handle, new.dir);
} }
} }
ext4_mark_inode_dirty(handle, old_dir); ext4_mark_inode_dirty(handle, old.dir);
if (new_inode) { if (new.inode) {
ext4_mark_inode_dirty(handle, new_inode); ext4_mark_inode_dirty(handle, new.inode);
if (!new_inode->i_nlink) if (!new.inode->i_nlink)
ext4_orphan_add(handle, new_inode); ext4_orphan_add(handle, new.inode);
} }
retval = 0; retval = 0;
end_rename: end_rename:
brelse(dir_bh); brelse(old.dir_bh);
brelse(old_bh); brelse(old.bh);
brelse(new_bh); brelse(new.bh);
if (handle) if (handle)
ext4_journal_stop(handle); ext4_journal_stop(handle);
return retval; return retval;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册