]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 25 Mar 2014 22:05:57 +0000 (15:05 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 25 Mar 2014 22:05:57 +0000 (15:05 -0700)
Pull vfs fixes from Al Viro:
 "These four commits are obvious fixes (a couple of fdget_pos()-related
  ones from Eric Biggers, prepend_name() fix, missing checks for false
  negatives from __lookup_mnt() in fs/namei.c)"

For now I'm pulling just the four obvious fixes, there's another four
pending in Al's 'for-linus' branch wrt the mnt_hash list that were more
involved.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  rcuwalk: recheck mount_lock after mountpoint crossing attempts
  make prepend_name() work correctly when called with negative *buflen
  vfs: Don't let __fdget_pos() get FMODE_PATH files
  vfs: atomic f_pos access in llseek()

fs/dcache.c
fs/file.c
fs/namei.c
fs/read_write.c

index 265e0ce9769c70db65d5f9df11c4365f44c6dd29..ca02c13a84aa24d55b18bbced577ece923605665 100644 (file)
@@ -2833,9 +2833,9 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
        u32 dlen = ACCESS_ONCE(name->len);
        char *p;
 
-       if (*buflen < dlen + 1)
-               return -ENAMETOOLONG;
        *buflen -= dlen + 1;
+       if (*buflen < 0)
+               return -ENAMETOOLONG;
        p = *buffer -= dlen + 1;
        *p++ = '/';
        while (dlen--) {
index 60a45e9f53231379c87b9ee75cb64eb8d6d71979..eb56a13dab3ed5561a9521b2b2d1a6000a7158a3 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -713,27 +713,16 @@ unsigned long __fdget_raw(unsigned int fd)
 
 unsigned long __fdget_pos(unsigned int fd)
 {
-       struct files_struct *files = current->files;
-       struct file *file;
-       unsigned long v;
-
-       if (atomic_read(&files->count) == 1) {
-               file = __fcheck_files(files, fd);
-               v = 0;
-       } else {
-               file = __fget(fd, 0);
-               v = FDPUT_FPUT;
-       }
-       if (!file)
-               return 0;
+       unsigned long v = __fdget(fd);
+       struct file *file = (struct file *)(v & ~3);
 
-       if (file->f_mode & FMODE_ATOMIC_POS) {
+       if (file && (file->f_mode & FMODE_ATOMIC_POS)) {
                if (file_count(file) > 1) {
                        v |= FDPUT_POS_UNLOCK;
                        mutex_lock(&file->f_pos_lock);
                }
        }
-       return v | (unsigned long)file;
+       return v;
 }
 
 /*
index 2f730ef9b4b3da78afd6a830c13c7ba13c706ffe..4b491b4319905b2dd6698d3f58aae1d0d0141499 100644 (file)
@@ -1109,7 +1109,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                        return false;
 
                if (!d_mountpoint(path->dentry))
-                       break;
+                       return true;
 
                mounted = __lookup_mnt(path->mnt, path->dentry);
                if (!mounted)
@@ -1125,20 +1125,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                 */
                *inode = path->dentry->d_inode;
        }
-       return true;
-}
-
-static void follow_mount_rcu(struct nameidata *nd)
-{
-       while (d_mountpoint(nd->path.dentry)) {
-               struct mount *mounted;
-               mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
-               if (!mounted)
-                       break;
-               nd->path.mnt = &mounted->mnt;
-               nd->path.dentry = mounted->mnt.mnt_root;
-               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
-       }
+       return read_seqretry(&mount_lock, nd->m_seq);
 }
 
 static int follow_dotdot_rcu(struct nameidata *nd)
@@ -1166,7 +1153,17 @@ static int follow_dotdot_rcu(struct nameidata *nd)
                        break;
                nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
        }
-       follow_mount_rcu(nd);
+       while (d_mountpoint(nd->path.dentry)) {
+               struct mount *mounted;
+               mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
+               if (!mounted)
+                       break;
+               nd->path.mnt = &mounted->mnt;
+               nd->path.dentry = mounted->mnt.mnt_root;
+               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
+               if (!read_seqretry(&mount_lock, nd->m_seq))
+                       goto failed;
+       }
        nd->inode = nd->path.dentry->d_inode;
        return 0;
 
index 54e19b9392dc74381fec154fe3f0ceab32ce9bd8..28cc9c810744a748d3a071b536c36547be87aa14 100644 (file)
@@ -307,7 +307,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
                unsigned int, whence)
 {
        int retval;
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        loff_t offset;
 
        if (!f.file)
@@ -327,7 +327,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
                        retval = 0;
        }
 out_putf:
-       fdput(f);
+       fdput_pos(f);
        return retval;
 }
 #endif