aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2014-04-01 11:08:42 -0400
committerMiklos Szeredi <mszeredi@suse.cz>2014-04-01 11:08:42 -0400
commitbc27027a73e8b80376b51a1583ad1c7445605e8a (patch)
tree31ae955e5cf6bcf1fee02b4605dd0e3ef9eff5f5
parentde22a4c3720a96f1c2ebf12b0857b6db6a991f2c (diff)
vfs: rename: use common code for dir and non-dir
There's actually very little difference between vfs_rename_dir() and vfs_rename_other() so move both inline into vfs_rename() which still stays reasonably readable. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Reviewed-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/namei.c187
1 files changed, 75 insertions, 112 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 2e86d2c4ec8a..12b8f56ba942 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3973,7 +3973,27 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname
3973 return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname, 0); 3973 return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname, 0);
3974} 3974}
3975 3975
3976/* 3976/**
3977 * vfs_rename - rename a filesystem object
3978 * @old_dir: parent of source
3979 * @old_dentry: source
3980 * @new_dir: parent of destination
3981 * @new_dentry: destination
3982 * @delegated_inode: returns an inode needing a delegation break
3983 *
3984 * The caller must hold multiple mutexes--see lock_rename()).
3985 *
3986 * If vfs_rename discovers a delegation in need of breaking at either
3987 * the source or destination, it will return -EWOULDBLOCK and return a
3988 * reference to the inode in delegated_inode. The caller should then
3989 * break the delegation and retry. Because breaking a delegation may
3990 * take a long time, the caller should drop all locks before doing
3991 * so.
3992 *
3993 * Alternatively, a caller may pass NULL for delegated_inode. This may
3994 * be appropriate for callers that expect the underlying filesystem not
3995 * to be NFS exported.
3996 *
3977 * The worst of all namespace operations - renaming directory. "Perverted" 3997 * The worst of all namespace operations - renaming directory. "Perverted"
3978 * doesn't even start to describe it. Somebody in UCB had a heck of a trip... 3998 * doesn't even start to describe it. Somebody in UCB had a heck of a trip...
3979 * Problems: 3999 * Problems:
@@ -4001,19 +4021,39 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname
4001 * ->i_mutex on parents, which works but leads to some truly excessive 4021 * ->i_mutex on parents, which works but leads to some truly excessive
4002 * locking]. 4022 * locking].
4003 */ 4023 */
4004static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, 4024int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
4005 struct inode *new_dir, struct dentry *new_dentry) 4025 struct inode *new_dir, struct dentry *new_dentry,
4026 struct inode **delegated_inode)
4006{ 4027{
4007 int error = 0; 4028 int error;
4029 bool is_dir = d_is_dir(old_dentry);
4030 const unsigned char *old_name;
4031 struct inode *source = old_dentry->d_inode;
4008 struct inode *target = new_dentry->d_inode; 4032 struct inode *target = new_dentry->d_inode;
4009 unsigned max_links = new_dir->i_sb->s_max_links; 4033
4034 if (source == target)
4035 return 0;
4036
4037 error = may_delete(old_dir, old_dentry, is_dir);
4038 if (error)
4039 return error;
4040
4041 if (!target)
4042 error = may_create(new_dir, new_dentry);
4043 else
4044 error = may_delete(new_dir, new_dentry, is_dir);
4045 if (error)
4046 return error;
4047
4048 if (!old_dir->i_op->rename)
4049 return -EPERM;
4010 4050
4011 /* 4051 /*
4012 * If we are going to change the parent - check write permissions, 4052 * If we are going to change the parent - check write permissions,
4013 * we'll need to flip '..'. 4053 * we'll need to flip '..'.
4014 */ 4054 */
4015 if (new_dir != old_dir) { 4055 if (is_dir && new_dir != old_dir) {
4016 error = inode_permission(old_dentry->d_inode, MAY_WRITE); 4056 error = inode_permission(source, MAY_WRITE);
4017 if (error) 4057 if (error)
4018 return error; 4058 return error;
4019 } 4059 }
@@ -4022,134 +4062,57 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
4022 if (error) 4062 if (error)
4023 return error; 4063 return error;
4024 4064
4065 old_name = fsnotify_oldname_init(old_dentry->d_name.name);
4025 dget(new_dentry); 4066 dget(new_dentry);
4026 if (target) 4067 if (!is_dir)
4068 lock_two_nondirectories(source, target);
4069 else if (target)
4027 mutex_lock(&target->i_mutex); 4070 mutex_lock(&target->i_mutex);
4028 4071
4029 error = -EBUSY; 4072 error = -EBUSY;
4030 if (d_mountpoint(old_dentry) || d_mountpoint(new_dentry)) 4073 if (d_mountpoint(old_dentry) || d_mountpoint(new_dentry))
4031 goto out; 4074 goto out;
4032 4075
4033 error = -EMLINK; 4076 if (is_dir) {
4034 if (max_links && !target && new_dir != old_dir && 4077 unsigned max_links = new_dir->i_sb->s_max_links;
4035 new_dir->i_nlink >= max_links)
4036 goto out;
4037
4038 if (target)
4039 shrink_dcache_parent(new_dentry);
4040 error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
4041 if (error)
4042 goto out;
4043
4044 if (target) {
4045 target->i_flags |= S_DEAD;
4046 dont_mount(new_dentry);
4047 }
4048 if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
4049 d_move(old_dentry, new_dentry);
4050out:
4051 if (target)
4052 mutex_unlock(&target->i_mutex);
4053 dput(new_dentry);
4054 return error;
4055}
4056
4057static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
4058 struct inode *new_dir, struct dentry *new_dentry,
4059 struct inode **delegated_inode)
4060{
4061 struct inode *target = new_dentry->d_inode;
4062 struct inode *source = old_dentry->d_inode;
4063 int error;
4064
4065 error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry);
4066 if (error)
4067 return error;
4068
4069 dget(new_dentry);
4070 lock_two_nondirectories(source, target);
4071 4078
4072 error = -EBUSY; 4079 error = -EMLINK;
4073 if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) 4080 if (max_links && !target && new_dir != old_dir &&
4074 goto out; 4081 new_dir->i_nlink >= max_links)
4082 goto out;
4075 4083
4076 error = try_break_deleg(source, delegated_inode); 4084 if (target)
4077 if (error) 4085 shrink_dcache_parent(new_dentry);
4078 goto out; 4086 } else {
4079 if (target) { 4087 error = try_break_deleg(source, delegated_inode);
4080 error = try_break_deleg(target, delegated_inode);
4081 if (error) 4088 if (error)
4082 goto out; 4089 goto out;
4090 if (target) {
4091 error = try_break_deleg(target, delegated_inode);
4092 if (error)
4093 goto out;
4094 }
4083 } 4095 }
4084 error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); 4096 error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
4085 if (error) 4097 if (error)
4086 goto out; 4098 goto out;
4087 4099
4088 if (target) 4100 if (target) {
4101 if (is_dir)
4102 target->i_flags |= S_DEAD;
4089 dont_mount(new_dentry); 4103 dont_mount(new_dentry);
4104 }
4090 if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE)) 4105 if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
4091 d_move(old_dentry, new_dentry); 4106 d_move(old_dentry, new_dentry);
4092out: 4107out:
4093 unlock_two_nondirectories(source, target); 4108 if (!is_dir)
4109 unlock_two_nondirectories(source, target);
4110 else if (target)
4111 mutex_unlock(&target->i_mutex);
4094 dput(new_dentry); 4112 dput(new_dentry);
4095 return error;
4096}
4097
4098/**
4099 * vfs_rename - rename a filesystem object
4100 * @old_dir: parent of source
4101 * @old_dentry: source
4102 * @new_dir: parent of destination
4103 * @new_dentry: destination
4104 * @delegated_inode: returns an inode needing a delegation break
4105 *
4106 * The caller must hold multiple mutexes--see lock_rename()).
4107 *
4108 * If vfs_rename discovers a delegation in need of breaking at either
4109 * the source or destination, it will return -EWOULDBLOCK and return a
4110 * reference to the inode in delegated_inode. The caller should then
4111 * break the delegation and retry. Because breaking a delegation may
4112 * take a long time, the caller should drop all locks before doing
4113 * so.
4114 *
4115 * Alternatively, a caller may pass NULL for delegated_inode. This may
4116 * be appropriate for callers that expect the underlying filesystem not
4117 * to be NFS exported.
4118 */
4119int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
4120 struct inode *new_dir, struct dentry *new_dentry,
4121 struct inode **delegated_inode)
4122{
4123 int error;
4124 int is_dir = d_is_dir(old_dentry);
4125 const unsigned char *old_name;
4126
4127 if (old_dentry->d_inode == new_dentry->d_inode)
4128 return 0;
4129
4130 error = may_delete(old_dir, old_dentry, is_dir);
4131 if (error)
4132 return error;
4133
4134 if (!new_dentry->d_inode)
4135 error = may_create(new_dir, new_dentry);
4136 else
4137 error = may_delete(new_dir, new_dentry, is_dir);
4138 if (error)
4139 return error;
4140
4141 if (!old_dir->i_op->rename)
4142 return -EPERM;
4143
4144 old_name = fsnotify_oldname_init(old_dentry->d_name.name);
4145
4146 if (is_dir)
4147 error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
4148 else
4149 error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry,delegated_inode);
4150 if (!error) 4113 if (!error)
4151 fsnotify_move(old_dir, new_dir, old_name, is_dir, 4114 fsnotify_move(old_dir, new_dir, old_name, is_dir,
4152 new_dentry->d_inode, old_dentry); 4115 target, old_dentry);
4153 fsnotify_oldname_free(old_name); 4116 fsnotify_oldname_free(old_name);
4154 4117
4155 return error; 4118 return error;