Release 4.7 fs/read_write.c
/*
* linux/fs/read_write.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/file.h>
#include <linux/uio.h>
#include <linux/fsnotify.h>
#include <linux/security.h>
#include <linux/export.h>
#include <linux/syscalls.h>
#include <linux/pagemap.h>
#include <linux/splice.h>
#include <linux/compat.h>
#include <linux/mount.h>
#include <linux/fs.h>
#include "internal.h"
#include <asm/uaccess.h>
#include <asm/unistd.h>
typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
typedef ssize_t (*iter_fn_t)(struct kiocb *, struct iov_iter *);
const struct file_operations generic_ro_fops = {
.llseek = generic_file_llseek,
.read_iter = generic_file_read_iter,
.mmap = generic_file_readonly_mmap,
.splice_read = generic_file_splice_read,
};
EXPORT_SYMBOL(generic_ro_fops);
static inline int unsigned_offsets(struct file *file)
{
return file->f_mode & FMODE_UNSIGNED_OFFSET;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
kamezawa hiroyuki | kamezawa hiroyuki | 17 | 89.47% | 1 | 50.00% |
al viro | al viro | 2 | 10.53% | 1 | 50.00% |
| Total | 19 | 100.00% | 2 | 100.00% |
/**
* vfs_setpos - update the file offset for lseek
* @file: file structure in question
* @offset: file offset to seek to
* @maxsize: maximum file size
*
* This is a low-level filesystem helper for updating the file offset to
* the value specified by @offset if the given offset is valid and it is
* not equal to the current file offset.
*
* Return the specified offset on success and -EINVAL on invalid offset.
*/
loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize)
{
if (offset < 0 && !unsigned_offsets(file))
return -EINVAL;
if (offset > maxsize)
return -EINVAL;
if (offset != file->f_pos) {
file->f_pos = offset;
file->f_version = 0;
}
return offset;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
linus torvalds | linus torvalds | 35 | 52.24% | 1 | 11.11% |
kamezawa hiroyuki | kamezawa hiroyuki | 11 | 16.42% | 1 | 11.11% |
christoph hellwig | christoph hellwig | 7 | 10.45% | 1 | 11.11% |
andi kleen | andi kleen | 7 | 10.45% | 1 | 11.11% |
al viro | al viro | 2 | 2.99% | 1 | 11.11% |
robert love | robert love | 2 | 2.99% | 1 | 11.11% |
jeff liu | jeff liu | 1 | 1.49% | 1 | 11.11% |
andrew morton | andrew morton | 1 | 1.49% | 1 | 11.11% |
josef bacik | josef bacik | 1 | 1.49% | 1 | 11.11% |
| Total | 67 | 100.00% | 9 | 100.00% |
EXPORT_SYMBOL(vfs_setpos);
/**
* generic_file_llseek_size - generic llseek implementation for regular files
* @file: file structure to seek on
* @offset: file offset to seek to
* @whence: type of seek
* @size: max size of this file in file system
* @eof: offset used for SEEK_END position
*
* This is a variant of generic_file_llseek that allows passing in a custom
* maximum file size and a custom EOF position, for e.g. hashed directories
*
* Synchronization:
* SEEK_SET and SEEK_END are unsynchronized (but atomic on 64bit platforms)
* SEEK_CUR is synchronized against other SEEK_CURs, but not read/writes.
* read/writes behave like SEEK_SET against seeks.
*/
loff_t
generic_file_llseek_size(struct file *file, loff_t offset, int whence,
loff_t maxsize, loff_t eof)
{
switch (whence) {
case SEEK_END:
offset += eof;
break;
case SEEK_CUR:
/*
* Here we special-case the lseek(fd, 0, SEEK_CUR)
* position-querying operation. Avoid rewriting the "same"
* f_pos value back to the file because a concurrent read(),
* write() or lseek() might have altered it
*/
if (offset == 0)
return file->f_pos;
/*
* f_lock protects against read/modify/write race with other
* SEEK_CURs. Note that parallel writes and reads behave
* like SEEK_SET.
*/
spin_lock(&file->f_lock);
offset = vfs_setpos(file, file->f_pos + offset, maxsize);
spin_unlock(&file->f_lock);
return offset;
case SEEK_DATA:
/*
* In the generic case the entire file is data, so as long as
* offset isn't at the end of the file then the offset is data.
*/
if (offset >= eof)
return -ENXIO;
break;
case SEEK_HOLE:
/*
* There is a virtual hole at the end of the file, so as long as
* offset isn't i_size or larger, return i_size.
*/
if (offset >= eof)
return -ENXIO;
offset = eof;
break;
}
return vfs_setpos(file, offset, maxsize);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
andi kleen | andi kleen | 95 | 73.08% | 3 | 42.86% |
robert love | robert love | 24 | 18.46% | 1 | 14.29% |
eric sandeen | eric sandeen | 7 | 5.38% | 1 | 14.29% |
andrew morton | andrew morton | 2 | 1.54% | 1 | 14.29% |
jeff liu | jeff liu | 2 | 1.54% | 1 | 14.29% |
| Total | 130 | 100.00% | 7 | 100.00% |
EXPORT_SYMBOL(generic_file_llseek_size);
/**
* generic_file_llseek - generic llseek implementation for regular files
* @file: file structure to seek on
* @offset: file offset to seek to
* @whence: type of seek
*
* This is a generic implemenation of ->llseek useable for all normal local
* filesystems. It just updates the file offset to the value specified by
* @offset and @whence.
*/
loff_t generic_file_llseek(struct file *file, loff_t offset, int whence)
{
struct inode *inode = file->f_mapping->host;
return generic_file_llseek_size(file, offset, whence,
inode->i_sb->s_maxbytes,
i_size_read(inode));
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
andi kleen | andi kleen | 39 | 81.25% | 2 | 40.00% |
eric sandeen | eric sandeen | 5 | 10.42% | 1 | 20.00% |
andrew morton | andrew morton | 2 | 4.17% | 1 | 20.00% |
linus torvalds | linus torvalds | 2 | 4.17% | 1 | 20.00% |
| Total | 48 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL(generic_file_llseek);
/**
* fixed_size_llseek - llseek implementation for fixed-sized devices
* @file: file structure to seek on
* @offset: file offset to seek to
* @whence: type of seek
* @size: size of the file
*
*/
loff_t fixed_size_llseek(struct file *file, loff_t offset, int whence, loff_t size)
{
switch (whence) {
case SEEK_SET: case SEEK_CUR: case SEEK_END:
return generic_file_llseek_size(file, offset, whence,
size, size);
default:
return -EINVAL;
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 53 | 100.00% | 1 | 100.00% |
| Total | 53 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(fixed_size_llseek);
/**
* no_seek_end_llseek - llseek implementation for fixed-sized devices
* @file: file structure to seek on
* @offset: file offset to seek to
* @whence: type of seek
*
*/
loff_t no_seek_end_llseek(struct file *file, loff_t offset, int whence)
{
switch (whence) {
case SEEK_SET: case SEEK_CUR:
return generic_file_llseek_size(file, offset, whence,
OFFSET_MAX, 0);
default:
return -EINVAL;
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 46 | 97.87% | 1 | 50.00% |
wouter van kesteren | wouter van kesteren | 1 | 2.13% | 1 | 50.00% |
| Total | 47 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(no_seek_end_llseek);
/**
* no_seek_end_llseek_size - llseek implementation for fixed-sized devices
* @file: file structure to seek on
* @offset: file offset to seek to
* @whence: type of seek
* @size: maximal offset allowed
*
*/
loff_t no_seek_end_llseek_size(struct file *file, loff_t offset, int whence, loff_t size)
{
switch (whence) {
case SEEK_SET: case SEEK_CUR:
return generic_file_llseek_size(file, offset, whence,
size, 0);
default:
return -EINVAL;
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 50 | 100.00% | 1 | 100.00% |
| Total | 50 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(no_seek_end_llseek_size);
/**
* noop_llseek - No Operation Performed llseek implementation
* @file: file structure to seek on
* @offset: file offset to seek to
* @whence: type of seek
*
* This is an implementation of ->llseek useable for the rare special case when
* userspace expects the seek to succeed but the (device) file is actually not
* able to perform the seek. In this case you use noop_llseek() instead of
* falling back to the default implementation of ->llseek.
*/
loff_t noop_llseek(struct file *file, loff_t offset, int whence)
{
return file->f_pos;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jan blunck | jan blunck | 20 | 95.24% | 1 | 50.00% |
andrew morton | andrew morton | 1 | 4.76% | 1 | 50.00% |
| Total | 21 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(noop_llseek);
loff_t no_llseek(struct file *file, loff_t offset, int whence)
{
return -ESPIPE;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
linus torvalds | linus torvalds | 19 | 95.00% | 1 | 50.00% |
andrew morton | andrew morton | 1 | 5.00% | 1 | 50.00% |
| Total | 20 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(no_llseek);
loff_t default_llseek(struct file *file, loff_t offset, int whence)
{
struct inode *inode = file_inode(file);
loff_t retval;
inode_lock(inode);
switch (whence) {
case SEEK_END:
offset += i_size_read(inode);
break;
case SEEK_CUR:
if (offset == 0) {
retval = file->f_pos;
goto out;
}
offset += file->f_pos;
break;
case SEEK_DATA:
/*
* In the generic case the entire file is data, so as
* long as offset isn't at the end of the file then the
* offset is data.
*/
if (offset >= inode->i_size) {
retval = -ENXIO;
goto out;
}
break;
case SEEK_HOLE:
/*
* There is a virtual hole at the end of the file, so
* as long as offset isn't i_size or larger, return
* i_size.
*/
if (offset >= inode->i_size) {
retval = -ENXIO;
goto out;
}
offset = inode->i_size;
break;
}
retval = -EINVAL;
if (offset >= 0 || unsigned_offsets(file)) {
if (offset != file->f_pos) {
file->f_pos = offset;
file->f_version = 0;
}
retval = offset;
}
out:
inode_unlock(inode);
return retval;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
pre-git | pre-git | 77 | 41.85% | 4 | 22.22% |
josef bacik | josef bacik | 47 | 25.54% | 1 | 5.56% |
alain knaff | alain knaff | 19 | 10.33% | 1 | 5.56% |
dan carpenter | dan carpenter | 16 | 8.70% | 1 | 5.56% |
andrew morton | andrew morton | 6 | 3.26% | 3 | 16.67% |
al viro | al viro | 6 | 3.26% | 3 | 16.67% |
kamezawa hiroyuki | kamezawa hiroyuki | 4 | 2.17% | 1 | 5.56% |
arnd bergmann | arnd bergmann | 4 | 2.17% | 1 | 5.56% |
linus torvalds | linus torvalds | 2 | 1.09% | 1 | 5.56% |
chris snook | chris snook | 2 | 1.09% | 1 | 5.56% |
david sterba | david sterba | 1 | 0.54% | 1 | 5.56% |
| Total | 184 | 100.00% | 18 | 100.00% |
EXPORT_SYMBOL(default_llseek);
loff_t vfs_llseek(struct file *file, loff_t offset, int whence)
{
loff_t (*fn)(struct file *, loff_t, int);
fn = no_llseek;
if (file->f_mode & FMODE_LSEEK) {
if (file->f_op->llseek)
fn = file->f_op->llseek;
}
return fn(file, offset, whence);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
pre-git | pre-git | 55 | 77.46% | 5 | 55.56% |
linus torvalds | linus torvalds | 13 | 18.31% | 2 | 22.22% |
andrew morton | andrew morton | 2 | 2.82% | 1 | 11.11% |
neil brown | neil brown | 1 | 1.41% | 1 | 11.11% |
| Total | 71 | 100.00% | 9 | 100.00% |
EXPORT_SYMBOL(vfs_llseek);
SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence)
{
off_t retval;
struct fd f = fdget_pos(fd);
if (!f.file)
return -EBADF;
retval = -EINVAL;
if (whence <= SEEK_MAX) {
loff_t res = vfs_llseek(f.file, offset, whence);
retval = res;
if (res != (loff_t)retval)
retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */
}
fdput_pos(f);
return retval;
}
#ifdef CONFIG_COMPAT
COMPAT_SYSCALL_DEFINE3(lseek, unsigned int, fd, compat_off_t, offset, unsigned int, whence)
{
return sys_lseek(fd, offset, whence);
}
#endif
#ifdef __ARCH_WANT_SYS_LLSEEK
SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
unsigned long, offset_low, loff_t __user *, result,
unsigned int, whence)
{
int retval;
struct fd f = fdget_pos(fd);
loff_t offset;
if (!f.file)
return -EBADF;
retval = -EINVAL;
if (whence > SEEK_MAX)
goto out_putf;
offset = vfs_llseek(f.file, ((loff_t) offset_high << 32) | offset_low,
whence);
retval = (int)offset;
if (offset >= 0) {
retval = -EFAULT;
if (!copy_to_user(result, &offset, sizeof(offset)))
retval = 0;
}
out_putf:
fdput_pos(f);
return retval;
}
#endif
ssize_t vfs_iter_read(struct file *file, struct iov_iter *iter, loff_t *ppos)
{
struct kiocb kiocb;
ssize_t ret;
if (!file->f_op->read_iter)
return -EINVAL;
init_sync_kiocb(&kiocb, file);
kiocb.ki_pos = *ppos;
iter->type |= READ;
ret = file->f_op->read_iter(&kiocb, iter);
BUG_ON(ret == -EIOCBQUEUED);
if (ret > 0)
*ppos = kiocb.ki_pos;
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
christoph hellwig | christoph hellwig | 98 | 100.00% | 2 | 100.00% |
| Total | 98 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(vfs_iter_read);
ssize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos)
{
struct kiocb kiocb;
ssize_t ret;
if (!file->f_op->write_iter)
return -EINVAL;
init_sync_kiocb(&kiocb, file);
kiocb.ki_pos = *ppos;
iter->type |= WRITE;
ret = file->f_op->write_iter(&kiocb, iter);
BUG_ON(ret == -EIOCBQUEUED);
if (ret > 0)
*ppos = kiocb.ki_pos;
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
christoph hellwig | christoph hellwig | 98 | 100.00% | 2 | 100.00% |
| Total | 98 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(vfs_iter_write);
int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t count)
{
struct inode *inode;
loff_t pos;
int retval = -EINVAL;
inode = file_inode(file);
if (unlikely((ssize_t) count < 0))
return retval;
pos = *ppos;
if (unlikely(pos < 0)) {
if (!unsigned_offsets(file))
return retval;
if (count >= -pos) /* both values are in 0..LLONG_MAX */
return -EOVERFLOW;
} else if (unlikely((loff_t) (pos + count) < 0)) {
if (!unsigned_offsets(file))
return retval;
}
if (unlikely(inode->i_flctx && mandatory_lock(inode))) {
retval = locks_mandatory_area(inode, file, pos, pos + count - 1,
read_write == READ ? F_RDLCK : F_WRLCK);
if (retval < 0)
return retval;
}
return security_file_permission(file,
read_write == READ ? MAY_READ : MAY_WRITE);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
linus torvalds | linus torvalds | 96 | 50.53% | 4 | 26.67% |
al viro | al viro | 41 | 21.58% | 4 | 26.67% |
james morris | james morris | 26 | 13.68% | 1 | 6.67% |
christoph hellwig | christoph hellwig | 12 | 6.32% | 1 | 6.67% |
kamezawa hiroyuki | kamezawa hiroyuki | 6 | 3.16% | 1 | 6.67% |
eric dumazet | eric dumazet | 4 | 2.11% | 1 | 6.67% |
jens axboe | jens axboe | 3 | 1.58% | 1 | 6.67% |
jeff layton | jeff layton | 1 | 0.53% | 1 | 6.67% |
pavel emelianov | pavel emelianov | 1 | 0.53% | 1 | 6.67% |
| Total | 190 | 100.00% | 15 | 100.00% |
static ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
{
struct iovec iov = { .iov_base = buf, .iov_len = len };
struct kiocb kiocb;
struct iov_iter iter;
ssize_t ret;
init_sync_kiocb(&kiocb, filp);
kiocb.ki_pos = *ppos;
iov_iter_init(&iter, READ, &iov, 1, len);
ret = filp->f_op->read_iter(&kiocb, &iter);
BUG_ON(ret == -EIOCBQUEUED);
*ppos = kiocb.ki_pos;
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 109 | 96.46% | 2 | 66.67% |
christoph hellwig | christoph hellwig | 4 | 3.54% | 1 | 33.33% |
| Total | 113 | 100.00% | 3 | 100.00% |
ssize_t __vfs_read(struct file *file, char __user *buf, size_t count,
loff_t *pos)
{
if (file->f_op->read)
return file->f_op->read(file, buf, count, pos);
else if (file->f_op->read_iter)
return new_sync_read(file, buf, count, pos);
else
return -EINVAL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dmitry kasatkin | dmitry kasatkin | 67 | 93.06% | 1 | 50.00% |
al viro | al viro | 5 | 6.94% | 1 | 50.00% |
| Total | 72 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(__vfs_read);
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
ssize_t ret;
if (!(file->f_mode & FMODE_READ))
return -EBADF;
if (!(file->f_mode & FMODE_CAN_READ))
return -EINVAL;
if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
return -EFAULT;
ret = rw_verify_area(READ, file, pos, count);
if (!ret) {
if (count > MAX_RW_COUNT)
count = MAX_RW_COUNT;
ret = __vfs_read(file, buf, count, pos);
if (ret > 0) {
fsnotify_access(file);
add_rchar(current, ret);
}
inc_syscr(current);
}
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
christoph hellwig | christoph hellwig | 38 | 26.21% | 1 | 5.56% |
pre-git | pre-git | 36 | 24.83% | 6 | 33.33% |
al viro | al viro | 30 | 20.69% | 3 | 16.67% |
linus torvalds | linus torvalds | 25 | 17.24% | 4 | 22.22% |
alexey dobriyan | alexey dobriyan | 7 | 4.83% | 1 | 5.56% |
jay lan | jay lan | 7 | 4.83% | 1 | 5.56% |
robert love | robert love | 1 | 0.69% | 1 | 5.56% |
dmitry kasatkin | dmitry kasatkin | 1 | 0.69% | 1 | 5.56% |
| Total | 145 | 100.00% | 18 | 100.00% |
EXPORT_SYMBOL(vfs_read);
static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
struct kiocb kiocb;
struct iov_iter iter;
ssize_t ret;
init_sync_kiocb(&kiocb, filp);
kiocb.ki_pos = *ppos;
iov_iter_init(&iter, WRITE, &iov, 1, len);
ret = filp->f_op->write_iter(&kiocb, &iter);
BUG_ON(ret == -EIOCBQUEUED);
if (ret > 0)
*ppos = kiocb.ki_pos;
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
christoph hellwig | christoph hellwig | 65 | 52.00% | 2 | 25.00% |
al viro | al viro | 29 | 23.20% | 3 | 37.50% |
badari pulavarty | badari pulavarty | 23 | 18.40% | 1 | 12.50% |
neil brown | neil brown | 7 | 5.60% | 1 | 12.50% |
linus torvalds | linus torvalds | 1 | 0.80% | 1 | 12.50% |
| Total | 125 | 100.00% | 8 | 100.00% |
ssize_t __vfs_write(struct file *file, const char __user *p, size_t count,
loff_t *pos)
{
if (file->f_op->write)
return file->f_op->write(file, p, count, pos);
else if (file->f_op->write_iter)
return new_sync_write(file, p, count, pos);
else
return -EINVAL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 73 | 100.00% | 1 | 100.00% |
| Total | 73 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(__vfs_write);
ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos)
{
mm_segment_t old_fs;
const char __user *p;
ssize_t ret;
if (!(file->f_mode & FMODE_CAN_WRITE))
return -EINVAL;
old_fs = get_fs();
set_fs(get_ds());
p = (__force const char __user *)buf;
if (count > MAX_RW_COUNT)
count = MAX_RW_COUNT;
ret = __vfs_write(file, p, count, pos);
set_fs(old_fs);
if (ret > 0) {
fsnotify_modify(file);
add_wchar(current, ret);
}
inc_syscw(current);
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 127 | 100.00% | 5 | 100.00% |
| Total | 127 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL(__kernel_write);
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{
ssize_t ret;
if (!(file->f_mode & FMODE_WRITE))
return -EBADF;
if (!(file->f_mode & FMODE_CAN_WRITE))
return -EINVAL;
if (unlikely(!access_ok(VERIFY_READ, buf, count)))
return -EFAULT;
ret = rw_verify_area(WRITE, file, pos, count);
if (!ret) {
if (count > MAX_RW_COUNT)
count = MAX_RW_COUNT;
file_start_write(file);
ret = __vfs_write(file, buf, count, pos);
if (ret > 0) {
fsnotify_modify(file);
add_wchar(current, ret);
}
inc_syscw(current);
file_end_write(file);
}
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
neil brown | neil brown | 71 | 45.51% | 1 | 7.14% |
al viro | al viro | 34 | 21.79% | 5 | 35.71% |
linus torvalds | linus torvalds | 25 | 16.03% | 4 | 28.57% |
christoph hellwig | christoph hellwig | 11 | 7.05% | 1 | 7.14% |
alexey dobriyan | alexey dobriyan | 7 | 4.49% | 1 | 7.14% |
jay lan | jay lan | 7 | 4.49% | 1 | 7.14% |
robert love | robert love | 1 | 0.64% | 1 | 7.14% |
| Total | 156 | 100.00% | 14 | 100.00% |
EXPORT_SYMBOL(vfs_write);
static inline loff_t file_pos_read(struct file *file)
{
return file->f_pos;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
linus torvalds | linus torvalds | 17 | 100.00% | 1 | 100.00% |
| Total | 17 | 100.00% | 1 | 100.00% |
static inline void file_pos_write(struct file *file, loff_t pos)
{
file->f_pos = pos;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
linus torvalds | linus torvalds | 21 | 100.00% | 1 | 100.00% |
| Total | 21 | 100.00% | 1 | 100.00% |
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
struct fd f = fdget_pos(fd);
ssize_t ret = -EBADF;
if (f.file) {
loff_t pos = file_pos_read(f.file);
ret = vfs_read(f.file, buf, count, &pos);
if (ret >= 0)
file_pos_write(f.file, pos);
fdput_pos(f);
}
return ret;
}
SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
size_t, count)
{
struct fd f = fdget_pos(fd);
ssize_t ret = -EBADF;
if (f.file) {
loff_t pos = file_pos_read(f.file);
ret = vfs_write(f.file, buf, count, &pos);
if (ret >= 0)
file_pos_write(f.file, pos);
fdput_pos(f);
}
return ret;
}
SYSCALL_DEFINE4(pread64, unsigned int, fd, char __user *, buf,
size_t, count, loff_t, pos)
{
struct fd f;
ssize_t ret = -EBADF;
if (pos < 0)
return -EINVAL;
f = fdget(fd);
if (f.file) {
ret = -ESPIPE;
if (f.file->f_mode & FMODE_PREAD)
ret = vfs_read(f.file, buf, count, &pos);
fdput(f);
}
return ret;
}
SYSCALL_DEFINE4(pwrite64, unsigned int, fd, const char __user *, buf,
size_t, count, loff_t, pos)
{
struct fd f;
ssize_t ret = -EBADF;
if (pos < 0)
return -EINVAL;
f = fdget(fd);
if (f.file) {
ret = -ESPIPE;
if (f.file->f_mode & FMODE_PWRITE)
ret = vfs_write(f.file, buf, count, &pos);
fdput(f);
}
return ret;
}
/*
* Reduce an iovec's length in-place. Return the resulting number of segments
*/
unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
{
unsigned long seg = 0;
size_t len = 0;
while (seg < nr_segs) {
seg++;
if (len + iov->iov_len >= to) {
iov->iov_len = to - len;
break;
}
len += iov->iov_len;
iov++;
}
return seg;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
andrew morton | andrew morton | 73 | 100.00% | 1 | 100.00% |
| Total | 73 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(iov_shorten);
static ssize_t do_iter_readv_writev(struct file *filp, struct iov_iter *iter,
loff_t *ppos, iter_fn_t fn, int flags)
{
struct kiocb kiocb;
ssize_t ret;
if (flags & ~(RWF_HIPRI | RWF_DSYNC | RWF_SYNC))
return