Merge branch 'misc' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild
[firefly-linux-kernel-4.4.55.git] / fs / stat.c
index eae494630a36507e03defe8bdf836ee6b337b4ee..04ce1ac20d20b393d13bdfcd0e24c8ca4cde743e 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -37,17 +37,17 @@ void generic_fillattr(struct inode *inode, struct kstat *stat)
 
 EXPORT_SYMBOL(generic_fillattr);
 
-int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int vfs_getattr(struct path *path, struct kstat *stat)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = path->dentry->d_inode;
        int retval;
 
-       retval = security_inode_getattr(mnt, dentry);
+       retval = security_inode_getattr(path->mnt, path->dentry);
        if (retval)
                return retval;
 
        if (inode->i_op->getattr)
-               return inode->i_op->getattr(mnt, dentry, stat);
+               return inode->i_op->getattr(path->mnt, path->dentry, stat);
 
        generic_fillattr(inode, stat);
        return 0;
@@ -61,8 +61,7 @@ int vfs_fstat(unsigned int fd, struct kstat *stat)
        int error = -EBADF;
 
        if (f.file) {
-               error = vfs_getattr(f.file->f_path.mnt, f.file->f_path.dentry,
-                                   stat);
+               error = vfs_getattr(&f.file->f_path, stat);
                fdput(f);
        }
        return error;
@@ -74,7 +73,7 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
 {
        struct path path;
        int error = -EINVAL;
-       int lookup_flags = 0;
+       unsigned int lookup_flags = 0;
 
        if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
                      AT_EMPTY_PATH)) != 0)
@@ -84,13 +83,17 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
                lookup_flags |= LOOKUP_FOLLOW;
        if (flag & AT_EMPTY_PATH)
                lookup_flags |= LOOKUP_EMPTY;
-
+retry:
        error = user_path_at(dfd, filename, lookup_flags, &path);
        if (error)
                goto out;
 
-       error = vfs_getattr(path.mnt, path.dentry, stat);
+       error = vfs_getattr(&path, stat);
        path_put(&path);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
 out:
        return error;
 }
@@ -296,11 +299,13 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
        struct path path;
        int error;
        int empty = 0;
+       unsigned int lookup_flags = LOOKUP_EMPTY;
 
        if (bufsiz <= 0)
                return -EINVAL;
 
-       error = user_path_at_empty(dfd, pathname, LOOKUP_EMPTY, &path, &empty);
+retry:
+       error = user_path_at_empty(dfd, pathname, lookup_flags, &path, &empty);
        if (!error) {
                struct inode *inode = path.dentry->d_inode;
 
@@ -314,6 +319,10 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
                        }
                }
                path_put(&path);
+               if (retry_estale(error, lookup_flags)) {
+                       lookup_flags |= LOOKUP_REVAL;
+                       goto retry;
+               }
        }
        return error;
 }