Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3e79d978 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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--) {
+4 −15
Original line number Diff line number Diff line
@@ -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;
}

/*
+13 −16
Original line number Diff line number Diff line
@@ -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;

+2 −2
Original line number Diff line number Diff line
@@ -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