Commit e6a4b6f5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull vfs fixes from Al Viro.

Clean up file table accesses (get rid of fget_light() in favor of the
fdget() interface), add proper file position locking.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  get rid of fget_light()
  sockfd_lookup_light(): switch to fdget^W^Waway from fget_light
  vfs: atomic f_pos accesses as per POSIX
  ocfs2 syncs the wrong range...
parents 2b64c543 bd2a31d5
Loading
Loading
Loading
Loading
+43 −13
Original line number Diff line number Diff line
@@ -683,35 +683,65 @@ EXPORT_SYMBOL(fget_raw);
 * The fput_needed flag returned by fget_light should be passed to the
 * corresponding fput_light.
 */
struct file *__fget_light(unsigned int fd, fmode_t mask, int *fput_needed)
static unsigned long __fget_light(unsigned int fd, fmode_t mask)
{
	struct files_struct *files = current->files;
	struct file *file;

	*fput_needed = 0;
	if (atomic_read(&files->count) == 1) {
		file = __fcheck_files(files, fd);
		if (file && (file->f_mode & mask))
			file = NULL;
		if (!file || unlikely(file->f_mode & mask))
			return 0;
		return (unsigned long)file;
	} else {
		file = __fget(fd, mask);
		if (file)
			*fput_needed = 1;
		if (!file)
			return 0;
		return FDPUT_FPUT | (unsigned long)file;
	}

	return file;
}
struct file *fget_light(unsigned int fd, int *fput_needed)
unsigned long __fdget(unsigned int fd)
{
	return __fget_light(fd, FMODE_PATH, fput_needed);
	return __fget_light(fd, FMODE_PATH);
}
EXPORT_SYMBOL(fget_light);
EXPORT_SYMBOL(__fdget);

struct file *fget_raw_light(unsigned int fd, int *fput_needed)
unsigned long __fdget_raw(unsigned int fd)
{
	return __fget_light(fd, 0, fput_needed);
	return __fget_light(fd, 0);
}

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;

	if (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;
}

/*
 * We only lock f_pos if we have threads or if the file might be
 * shared with another process. In both cases we'll have an elevated
 * file count (done either by fdget() or by fork()).
 */

void set_close_on_exec(unsigned int fd, int flag)
{
	struct files_struct *files = current->files;
+1 −0
Original line number Diff line number Diff line
@@ -135,6 +135,7 @@ struct file *get_empty_filp(void)
	atomic_long_set(&f->f_count, 1);
	rwlock_init(&f->f_owner.lock);
	spin_lock_init(&f->f_lock);
	mutex_init(&f->f_pos_lock);
	eventpoll_init_file(f);
	/* f->f_version: 0 */
	return f;
+1 −1
Original line number Diff line number Diff line
@@ -1884,7 +1884,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,

		nd->path = f.file->f_path;
		if (flags & LOOKUP_RCU) {
			if (f.need_put)
			if (f.flags & FDPUT_FPUT)
				*fp = f.file;
			nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
			rcu_read_lock();
+4 −4
Original line number Diff line number Diff line
@@ -2393,8 +2393,8 @@ out_dio:

	if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) ||
	    ((file->f_flags & O_DIRECT) && !direct_io)) {
		ret = filemap_fdatawrite_range(file->f_mapping, pos,
					       pos + count - 1);
		ret = filemap_fdatawrite_range(file->f_mapping, *ppos,
					       *ppos + count - 1);
		if (ret < 0)
			written = ret;

@@ -2407,8 +2407,8 @@ out_dio:
		}

		if (!ret)
			ret = filemap_fdatawait_range(file->f_mapping, pos,
						      pos + count - 1);
			ret = filemap_fdatawait_range(file->f_mapping, *ppos,
						      *ppos + count - 1);
	}

	/*
+4 −0
Original line number Diff line number Diff line
@@ -705,6 +705,10 @@ static int do_dentry_open(struct file *f,
		return 0;
	}

	/* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */
	if (S_ISREG(inode->i_mode))
		f->f_mode |= FMODE_ATOMIC_POS;

	f->f_op = fops_get(inode->i_fop);
	if (unlikely(WARN_ON(!f->f_op))) {
		error = -ENODEV;
Loading