|
@@ -3840,15 +3840,17 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
|
|
|
struct nameidata oldnd, newnd;
|
|
|
struct filename *from;
|
|
|
struct filename *to;
|
|
|
+ unsigned int lookup_flags = 0;
|
|
|
+ bool should_retry = false;
|
|
|
int error;
|
|
|
-
|
|
|
- from = user_path_parent(olddfd, oldname, &oldnd, 0);
|
|
|
+retry:
|
|
|
+ from = user_path_parent(olddfd, oldname, &oldnd, lookup_flags);
|
|
|
if (IS_ERR(from)) {
|
|
|
error = PTR_ERR(from);
|
|
|
goto exit;
|
|
|
}
|
|
|
|
|
|
- to = user_path_parent(newdfd, newname, &newnd, 0);
|
|
|
+ to = user_path_parent(newdfd, newname, &newnd, lookup_flags);
|
|
|
if (IS_ERR(to)) {
|
|
|
error = PTR_ERR(to);
|
|
|
goto exit1;
|
|
@@ -3920,11 +3922,18 @@ exit3:
|
|
|
unlock_rename(new_dir, old_dir);
|
|
|
mnt_drop_write(oldnd.path.mnt);
|
|
|
exit2:
|
|
|
+ if (retry_estale(error, lookup_flags))
|
|
|
+ should_retry = true;
|
|
|
path_put(&newnd.path);
|
|
|
putname(to);
|
|
|
exit1:
|
|
|
path_put(&oldnd.path);
|
|
|
putname(from);
|
|
|
+ if (should_retry) {
|
|
|
+ should_retry = false;
|
|
|
+ lookup_flags |= LOOKUP_REVAL;
|
|
|
+ goto retry;
|
|
|
+ }
|
|
|
exit:
|
|
|
return error;
|
|
|
}
|