diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/file.c | 56 | ||||
| -rw-r--r-- | fs/file_table.c | 1 | ||||
| -rw-r--r-- | fs/namei.c | 2 | ||||
| -rw-r--r-- | fs/ocfs2/file.c | 8 | ||||
| -rw-r--r-- | fs/open.c | 4 | ||||
| -rw-r--r-- | fs/read_write.c | 40 | 
6 files changed, 79 insertions, 32 deletions
diff --git a/fs/file.c b/fs/file.c index db25c2bdfe46..60a45e9f5323 100644 --- a/fs/file.c +++ b/fs/file.c @@ -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; diff --git a/fs/file_table.c b/fs/file_table.c index 5fff9030be34..5b24008ea4f6 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -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; diff --git a/fs/namei.c b/fs/namei.c index 385f7817bfcc..2f730ef9b4b3 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -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(); diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 8450262bcf2a..51632c40e896 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -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);  	}  	/* diff --git a/fs/open.c b/fs/open.c index 4b3e1edf2fe4..b9ed8b25c108 100644 --- a/fs/open.c +++ b/fs/open.c @@ -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; diff --git a/fs/read_write.c b/fs/read_write.c index edc5746a902a..54e19b9392dc 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -264,10 +264,22 @@ loff_t vfs_llseek(struct file *file, loff_t offset, int whence)  }  EXPORT_SYMBOL(vfs_llseek); +static inline struct fd fdget_pos(int fd) +{ +	return __to_fd(__fdget_pos(fd)); +} + +static inline void fdput_pos(struct fd f) +{ +	if (f.flags & FDPUT_POS_UNLOCK) +		mutex_unlock(&f.file->f_pos_lock); +	fdput(f); +} +  SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence)  {  	off_t retval; -	struct fd f = fdget(fd); +	struct fd f = fdget_pos(fd);  	if (!f.file)  		return -EBADF; @@ -278,7 +290,7 @@ SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence)  		if (res != (loff_t)retval)  			retval = -EOVERFLOW;	/* LFS: should only happen on 32 bit platforms */  	} -	fdput(f); +	fdput_pos(f);  	return retval;  } @@ -498,7 +510,7 @@ static inline void file_pos_write(struct file *file, loff_t pos)  SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)  { -	struct fd f = fdget(fd); +	struct fd f = fdget_pos(fd);  	ssize_t ret = -EBADF;  	if (f.file) { @@ -506,7 +518,7 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)  		ret = vfs_read(f.file, buf, count, &pos);  		if (ret >= 0)  			file_pos_write(f.file, pos); -		fdput(f); +		fdput_pos(f);  	}  	return ret;  } @@ -514,7 +526,7 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)  SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,  		size_t, count)  { -	struct fd f = fdget(fd); +	struct fd f = fdget_pos(fd);  	ssize_t ret = -EBADF;  	if (f.file) { @@ -522,7 +534,7 @@ SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,  		ret = vfs_write(f.file, buf, count, &pos);  		if (ret >= 0)  			file_pos_write(f.file, pos); -		fdput(f); +		fdput_pos(f);  	}  	return ret; @@ -797,7 +809,7 @@ EXPORT_SYMBOL(vfs_writev);  SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,  		unsigned long, vlen)  { -	struct fd f = fdget(fd); +	struct fd f = fdget_pos(fd);  	ssize_t ret = -EBADF;  	if (f.file) { @@ -805,7 +817,7 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,  		ret = vfs_readv(f.file, vec, vlen, &pos);  		if (ret >= 0)  			file_pos_write(f.file, pos); -		fdput(f); +		fdput_pos(f);  	}  	if (ret > 0) @@ -817,7 +829,7 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,  SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,  		unsigned long, vlen)  { -	struct fd f = fdget(fd); +	struct fd f = fdget_pos(fd);  	ssize_t ret = -EBADF;  	if (f.file) { @@ -825,7 +837,7 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,  		ret = vfs_writev(f.file, vec, vlen, &pos);  		if (ret >= 0)  			file_pos_write(f.file, pos); -		fdput(f); +		fdput_pos(f);  	}  	if (ret > 0) @@ -968,7 +980,7 @@ COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd,  		const struct compat_iovec __user *,vec,  		compat_ulong_t, vlen)  { -	struct fd f = fdget(fd); +	struct fd f = fdget_pos(fd);  	ssize_t ret;  	loff_t pos; @@ -978,7 +990,7 @@ COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd,  	ret = compat_readv(f.file, vec, vlen, &pos);  	if (ret >= 0)  		f.file->f_pos = pos; -	fdput(f); +	fdput_pos(f);  	return ret;  } @@ -1035,7 +1047,7 @@ COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd,  		const struct compat_iovec __user *, vec,  		compat_ulong_t, vlen)  { -	struct fd f = fdget(fd); +	struct fd f = fdget_pos(fd);  	ssize_t ret;  	loff_t pos; @@ -1045,7 +1057,7 @@ COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd,  	ret = compat_writev(f.file, vec, vlen, &pos);  	if (ret >= 0)  		f.file->f_pos = pos; -	fdput(f); +	fdput_pos(f);  	return ret;  }  | 
