fs: make do_renameat2() take struct filename
Pass in the struct filename pointers instead of the user string, and update the three callers to do the same. This behaves like do_unlinkat(), which also takes a filename struct and puts it when it is done. Converting callers is then trivial. Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
@@ -78,6 +78,8 @@ extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
|
|||||||
long do_rmdir(int dfd, struct filename *name);
|
long do_rmdir(int dfd, struct filename *name);
|
||||||
long do_unlinkat(int dfd, struct filename *name);
|
long do_unlinkat(int dfd, struct filename *name);
|
||||||
int may_linkat(struct path *link);
|
int may_linkat(struct path *link);
|
||||||
|
int do_renameat2(int olddfd, struct filename *oldname, int newdfd,
|
||||||
|
struct filename *newname, unsigned int flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* namespace.c
|
* namespace.c
|
||||||
|
|||||||
40
fs/namei.c
40
fs/namei.c
@@ -4346,8 +4346,8 @@ out:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(vfs_rename);
|
EXPORT_SYMBOL(vfs_rename);
|
||||||
|
|
||||||
static int do_renameat2(int olddfd, const char __user *oldname, int newdfd,
|
int do_renameat2(int olddfd, struct filename *from, int newdfd,
|
||||||
const char __user *newname, unsigned int flags)
|
struct filename *to, unsigned int flags)
|
||||||
{
|
{
|
||||||
struct dentry *old_dentry, *new_dentry;
|
struct dentry *old_dentry, *new_dentry;
|
||||||
struct dentry *trap;
|
struct dentry *trap;
|
||||||
@@ -4355,32 +4355,30 @@ static int do_renameat2(int olddfd, const char __user *oldname, int newdfd,
|
|||||||
struct qstr old_last, new_last;
|
struct qstr old_last, new_last;
|
||||||
int old_type, new_type;
|
int old_type, new_type;
|
||||||
struct inode *delegated_inode = NULL;
|
struct inode *delegated_inode = NULL;
|
||||||
struct filename *from;
|
|
||||||
struct filename *to;
|
|
||||||
unsigned int lookup_flags = 0, target_flags = LOOKUP_RENAME_TARGET;
|
unsigned int lookup_flags = 0, target_flags = LOOKUP_RENAME_TARGET;
|
||||||
bool should_retry = false;
|
bool should_retry = false;
|
||||||
int error;
|
int error = -EINVAL;
|
||||||
|
|
||||||
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
|
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
|
||||||
return -EINVAL;
|
goto put_both;
|
||||||
|
|
||||||
if ((flags & (RENAME_NOREPLACE | RENAME_WHITEOUT)) &&
|
if ((flags & (RENAME_NOREPLACE | RENAME_WHITEOUT)) &&
|
||||||
(flags & RENAME_EXCHANGE))
|
(flags & RENAME_EXCHANGE))
|
||||||
return -EINVAL;
|
goto put_both;
|
||||||
|
|
||||||
if (flags & RENAME_EXCHANGE)
|
if (flags & RENAME_EXCHANGE)
|
||||||
target_flags = 0;
|
target_flags = 0;
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
from = filename_parentat(olddfd, getname(oldname), lookup_flags,
|
from = filename_parentat(olddfd, from, lookup_flags, &old_path,
|
||||||
&old_path, &old_last, &old_type);
|
&old_last, &old_type);
|
||||||
if (IS_ERR(from)) {
|
if (IS_ERR(from)) {
|
||||||
error = PTR_ERR(from);
|
error = PTR_ERR(from);
|
||||||
goto exit;
|
goto put_new;
|
||||||
}
|
}
|
||||||
|
|
||||||
to = filename_parentat(newdfd, getname(newname), lookup_flags,
|
to = filename_parentat(newdfd, to, lookup_flags, &new_path, &new_last,
|
||||||
&new_path, &new_last, &new_type);
|
&new_type);
|
||||||
if (IS_ERR(to)) {
|
if (IS_ERR(to)) {
|
||||||
error = PTR_ERR(to);
|
error = PTR_ERR(to);
|
||||||
goto exit1;
|
goto exit1;
|
||||||
@@ -4473,34 +4471,40 @@ exit2:
|
|||||||
if (retry_estale(error, lookup_flags))
|
if (retry_estale(error, lookup_flags))
|
||||||
should_retry = true;
|
should_retry = true;
|
||||||
path_put(&new_path);
|
path_put(&new_path);
|
||||||
putname(to);
|
|
||||||
exit1:
|
exit1:
|
||||||
path_put(&old_path);
|
path_put(&old_path);
|
||||||
putname(from);
|
|
||||||
if (should_retry) {
|
if (should_retry) {
|
||||||
should_retry = false;
|
should_retry = false;
|
||||||
lookup_flags |= LOOKUP_REVAL;
|
lookup_flags |= LOOKUP_REVAL;
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
exit:
|
put_both:
|
||||||
|
if (!IS_ERR(from))
|
||||||
|
putname(from);
|
||||||
|
put_new:
|
||||||
|
if (!IS_ERR(to))
|
||||||
|
putname(to);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
|
SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
|
||||||
int, newdfd, const char __user *, newname, unsigned int, flags)
|
int, newdfd, const char __user *, newname, unsigned int, flags)
|
||||||
{
|
{
|
||||||
return do_renameat2(olddfd, oldname, newdfd, newname, flags);
|
return do_renameat2(olddfd, getname(oldname), newdfd, getname(newname),
|
||||||
|
flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
|
SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
|
||||||
int, newdfd, const char __user *, newname)
|
int, newdfd, const char __user *, newname)
|
||||||
{
|
{
|
||||||
return do_renameat2(olddfd, oldname, newdfd, newname, 0);
|
return do_renameat2(olddfd, getname(oldname), newdfd, getname(newname),
|
||||||
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newname)
|
SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newname)
|
||||||
{
|
{
|
||||||
return do_renameat2(AT_FDCWD, oldname, AT_FDCWD, newname, 0);
|
return do_renameat2(AT_FDCWD, getname(oldname), AT_FDCWD,
|
||||||
|
getname(newname), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int readlink_copy(char __user *buffer, int buflen, const char *link)
|
int readlink_copy(char __user *buffer, int buflen, const char *link)
|
||||||
|
|||||||
Reference in New Issue
Block a user