Commit 3e79d978 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

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()
parents b098d672 b37199e6
...@@ -2833,9 +2833,9 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name) ...@@ -2833,9 +2833,9 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
u32 dlen = ACCESS_ONCE(name->len); u32 dlen = ACCESS_ONCE(name->len);
char *p; char *p;
if (*buflen < dlen + 1)
return -ENAMETOOLONG;
*buflen -= dlen + 1; *buflen -= dlen + 1;
if (*buflen < 0)
return -ENAMETOOLONG;
p = *buffer -= dlen + 1; p = *buffer -= dlen + 1;
*p++ = '/'; *p++ = '/';
while (dlen--) { while (dlen--) {
......
...@@ -713,27 +713,16 @@ unsigned long __fdget_raw(unsigned int fd) ...@@ -713,27 +713,16 @@ unsigned long __fdget_raw(unsigned int fd)
unsigned long __fdget_pos(unsigned int fd) unsigned long __fdget_pos(unsigned int fd)
{ {
struct files_struct *files = current->files; unsigned long v = __fdget(fd);
struct file *file; struct file *file = (struct file *)(v & ~3);
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;
if (file->f_mode & FMODE_ATOMIC_POS) { if (file && (file->f_mode & FMODE_ATOMIC_POS)) {
if (file_count(file) > 1) { if (file_count(file) > 1) {
v |= FDPUT_POS_UNLOCK; v |= FDPUT_POS_UNLOCK;
mutex_lock(&file->f_pos_lock); mutex_lock(&file->f_pos_lock);
} }
} }
return v | (unsigned long)file; return v;
} }
/* /*
......
...@@ -1109,7 +1109,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, ...@@ -1109,7 +1109,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
return false; return false;
if (!d_mountpoint(path->dentry)) if (!d_mountpoint(path->dentry))
break; return true;
mounted = __lookup_mnt(path->mnt, path->dentry); mounted = __lookup_mnt(path->mnt, path->dentry);
if (!mounted) if (!mounted)
...@@ -1125,20 +1125,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, ...@@ -1125,20 +1125,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
*/ */
*inode = path->dentry->d_inode; *inode = path->dentry->d_inode;
} }
return true; return read_seqretry(&mount_lock, nd->m_seq);
}
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);
}
} }
static int follow_dotdot_rcu(struct nameidata *nd) static int follow_dotdot_rcu(struct nameidata *nd)
...@@ -1166,7 +1153,17 @@ static int follow_dotdot_rcu(struct nameidata *nd) ...@@ -1166,7 +1153,17 @@ static int follow_dotdot_rcu(struct nameidata *nd)
break; break;
nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); 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; nd->inode = nd->path.dentry->d_inode;
return 0; return 0;
......
...@@ -307,7 +307,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high, ...@@ -307,7 +307,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
unsigned int, whence) unsigned int, whence)
{ {
int retval; int retval;
struct fd f = fdget(fd); struct fd f = fdget_pos(fd);
loff_t offset; loff_t offset;
if (!f.file) if (!f.file)
...@@ -327,7 +327,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high, ...@@ -327,7 +327,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
retval = 0; retval = 0;
} }
out_putf: out_putf:
fdput(f); fdput_pos(f);
return retval; return retval;
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment