diff options
author | Jeff Layton <jlayton@redhat.com> | 2012-12-11 12:10:10 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-12-20 18:50:05 -0500 |
commit | c6a9428401c00a27d3c17264934d14e284570c97 (patch) | |
tree | 84d5e256e78615794a694cf5b6af80a92e8d01f9 | |
parent | 5d18f8133cad85ccbb7fa6fd351d75025da32504 (diff) |
vfs: fix renameat to retry on ESTALE errors
...as always, rename is the messiest of the bunch. We have to track
whether to retry or not via a separate flag since the error handling
is already quite complex.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/namei.c | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/fs/namei.c b/fs/namei.c index 8a262c2efff8..43a97ee1d4c8 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -3840,15 +3840,17 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, | |||
3840 | struct nameidata oldnd, newnd; | 3840 | struct nameidata oldnd, newnd; |
3841 | struct filename *from; | 3841 | struct filename *from; |
3842 | struct filename *to; | 3842 | struct filename *to; |
3843 | unsigned int lookup_flags = 0; | ||
3844 | bool should_retry = false; | ||
3843 | int error; | 3845 | int error; |
3844 | 3846 | retry: | |
3845 | from = user_path_parent(olddfd, oldname, &oldnd, 0); | 3847 | from = user_path_parent(olddfd, oldname, &oldnd, lookup_flags); |
3846 | if (IS_ERR(from)) { | 3848 | if (IS_ERR(from)) { |
3847 | error = PTR_ERR(from); | 3849 | error = PTR_ERR(from); |
3848 | goto exit; | 3850 | goto exit; |
3849 | } | 3851 | } |
3850 | 3852 | ||
3851 | to = user_path_parent(newdfd, newname, &newnd, 0); | 3853 | to = user_path_parent(newdfd, newname, &newnd, lookup_flags); |
3852 | if (IS_ERR(to)) { | 3854 | if (IS_ERR(to)) { |
3853 | error = PTR_ERR(to); | 3855 | error = PTR_ERR(to); |
3854 | goto exit1; | 3856 | goto exit1; |
@@ -3920,11 +3922,18 @@ exit3: | |||
3920 | unlock_rename(new_dir, old_dir); | 3922 | unlock_rename(new_dir, old_dir); |
3921 | mnt_drop_write(oldnd.path.mnt); | 3923 | mnt_drop_write(oldnd.path.mnt); |
3922 | exit2: | 3924 | exit2: |
3925 | if (retry_estale(error, lookup_flags)) | ||
3926 | should_retry = true; | ||
3923 | path_put(&newnd.path); | 3927 | path_put(&newnd.path); |
3924 | putname(to); | 3928 | putname(to); |
3925 | exit1: | 3929 | exit1: |
3926 | path_put(&oldnd.path); | 3930 | path_put(&oldnd.path); |
3927 | putname(from); | 3931 | putname(from); |
3932 | if (should_retry) { | ||
3933 | should_retry = false; | ||
3934 | lookup_flags |= LOOKUP_REVAL; | ||
3935 | goto retry; | ||
3936 | } | ||
3928 | exit: | 3937 | exit: |
3929 | return error; | 3938 | return error; |
3930 | } | 3939 | } |