mirror of https://gitee.com/openkylin/linux.git
[PATCH] relay: consolidate sendfile() and read() code
Signed-off-by: Jens Axboe <axboe@suse.de>
This commit is contained in:
parent
221415d762
commit
6dac40a7ce
203
kernel/relay.c
203
kernel/relay.c
|
@ -866,131 +866,138 @@ static size_t relay_file_read_end_pos(struct rchan_buf *buf,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* relay_file_read - read file op for relay files
|
* subbuf_read_actor - read up to one subbuf's worth of data
|
||||||
* @filp: the file
|
|
||||||
* @buffer: the userspace buffer
|
|
||||||
* @count: number of bytes to read
|
|
||||||
* @ppos: position to read from
|
|
||||||
*
|
|
||||||
* Reads count bytes or the number of bytes available in the
|
|
||||||
* current sub-buffer being read, whichever is smaller.
|
|
||||||
*/
|
*/
|
||||||
static ssize_t relay_file_read(struct file *filp,
|
static int subbuf_read_actor(size_t read_start,
|
||||||
char __user *buffer,
|
struct rchan_buf *buf,
|
||||||
size_t count,
|
size_t avail,
|
||||||
loff_t *ppos)
|
read_descriptor_t *desc,
|
||||||
|
read_actor_t actor)
|
||||||
{
|
{
|
||||||
struct rchan_buf *buf = filp->private_data;
|
|
||||||
struct inode *inode = filp->f_dentry->d_inode;
|
|
||||||
size_t read_start, avail;
|
|
||||||
ssize_t ret = 0;
|
|
||||||
void *from;
|
void *from;
|
||||||
|
int ret = 0;
|
||||||
mutex_lock(&inode->i_mutex);
|
|
||||||
if(!relay_file_read_avail(buf, *ppos))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
read_start = relay_file_read_start_pos(*ppos, buf);
|
|
||||||
avail = relay_file_read_subbuf_avail(read_start, buf);
|
|
||||||
if (!avail)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
from = buf->start + read_start;
|
from = buf->start + read_start;
|
||||||
ret = count = min(count, avail);
|
ret = avail;
|
||||||
if (copy_to_user(buffer, from, count)) {
|
if (copy_to_user(desc->arg.data, from, avail)) {
|
||||||
ret = -EFAULT;
|
desc->error = -EFAULT;
|
||||||
goto out;
|
ret = 0;
|
||||||
}
|
}
|
||||||
relay_file_read_consume(buf, read_start, count);
|
desc->arg.data += ret;
|
||||||
*ppos = relay_file_read_end_pos(buf, read_start, count);
|
desc->written += ret;
|
||||||
out:
|
desc->count -= ret;
|
||||||
mutex_unlock(&inode->i_mutex);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t relay_file_sendsubbuf(struct file *filp, loff_t *ppos,
|
/**
|
||||||
size_t count, read_actor_t actor,
|
* subbuf_send_actor - send up to one subbuf's worth of data
|
||||||
void *target)
|
*/
|
||||||
|
static int subbuf_send_actor(size_t read_start,
|
||||||
|
struct rchan_buf *buf,
|
||||||
|
size_t avail,
|
||||||
|
read_descriptor_t *desc,
|
||||||
|
read_actor_t actor)
|
||||||
{
|
{
|
||||||
struct rchan_buf *buf = filp->private_data;
|
|
||||||
read_descriptor_t desc;
|
|
||||||
size_t read_start, avail;
|
|
||||||
unsigned long pidx, poff;
|
unsigned long pidx, poff;
|
||||||
unsigned int subbuf_pages;
|
unsigned int subbuf_pages;
|
||||||
ssize_t ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!relay_file_read_avail(buf, *ppos))
|
subbuf_pages = buf->chan->alloc_size >> PAGE_SHIFT;
|
||||||
|
pidx = (read_start / PAGE_SIZE) % subbuf_pages;
|
||||||
|
poff = read_start & ~PAGE_MASK;
|
||||||
|
while (avail) {
|
||||||
|
struct page *p = buf->page_array[pidx];
|
||||||
|
unsigned int len;
|
||||||
|
|
||||||
|
len = PAGE_SIZE - poff;
|
||||||
|
if (len > avail)
|
||||||
|
len = avail;
|
||||||
|
|
||||||
|
len = actor(desc, p, poff, len);
|
||||||
|
if (desc->error)
|
||||||
|
break;
|
||||||
|
|
||||||
|
avail -= len;
|
||||||
|
ret += len;
|
||||||
|
poff = 0;
|
||||||
|
pidx = (pidx + 1) % subbuf_pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef int (*subbuf_actor_t) (size_t read_start,
|
||||||
|
struct rchan_buf *buf,
|
||||||
|
size_t avail,
|
||||||
|
read_descriptor_t *desc,
|
||||||
|
read_actor_t actor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* relay_file_read_subbufs - read count bytes, bridging subbuf boundaries
|
||||||
|
*/
|
||||||
|
static inline ssize_t relay_file_read_subbufs(struct file *filp,
|
||||||
|
loff_t *ppos,
|
||||||
|
size_t count,
|
||||||
|
subbuf_actor_t subbuf_actor,
|
||||||
|
read_actor_t actor,
|
||||||
|
void *target)
|
||||||
|
{
|
||||||
|
struct rchan_buf *buf = filp->private_data;
|
||||||
|
size_t read_start, avail;
|
||||||
|
read_descriptor_t desc;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!count)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
read_start = relay_file_read_start_pos(*ppos, buf);
|
|
||||||
avail = relay_file_read_subbuf_avail(read_start, buf);
|
|
||||||
if (!avail)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
count = min(count, avail);
|
|
||||||
|
|
||||||
desc.written = 0;
|
desc.written = 0;
|
||||||
desc.count = count;
|
desc.count = count;
|
||||||
desc.arg.data = target;
|
desc.arg.data = target;
|
||||||
desc.error = 0;
|
desc.error = 0;
|
||||||
|
|
||||||
subbuf_pages = buf->chan->alloc_size >> PAGE_SHIFT;
|
mutex_lock(&filp->f_dentry->d_inode->i_mutex);
|
||||||
pidx = (read_start / PAGE_SIZE) % subbuf_pages;
|
do {
|
||||||
poff = read_start & ~PAGE_MASK;
|
if (!relay_file_read_avail(buf, *ppos))
|
||||||
while (count) {
|
|
||||||
struct page *p = buf->page_array[pidx];
|
|
||||||
unsigned int len;
|
|
||||||
|
|
||||||
len = PAGE_SIZE - poff;
|
|
||||||
if (len > count)
|
|
||||||
len = count;
|
|
||||||
|
|
||||||
len = actor(&desc, p, poff, len);
|
|
||||||
|
|
||||||
if (desc.error) {
|
|
||||||
if (!ret)
|
|
||||||
ret = desc.error;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
read_start = relay_file_read_start_pos(*ppos, buf);
|
||||||
|
avail = relay_file_read_subbuf_avail(read_start, buf);
|
||||||
|
if (!avail)
|
||||||
|
break;
|
||||||
|
|
||||||
|
avail = min(desc.count, avail);
|
||||||
|
ret = subbuf_actor(read_start, buf, avail, &desc, actor);
|
||||||
|
if (desc.error < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
relay_file_read_consume(buf, read_start, ret);
|
||||||
|
*ppos = relay_file_read_end_pos(buf, read_start, ret);
|
||||||
}
|
}
|
||||||
|
} while (desc.count && ret);
|
||||||
|
mutex_unlock(&filp->f_dentry->d_inode->i_mutex);
|
||||||
|
|
||||||
count -= len;
|
return desc.written;
|
||||||
ret += len;
|
|
||||||
poff = 0;
|
|
||||||
pidx = (pidx + 1) % subbuf_pages;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret > 0) {
|
|
||||||
relay_file_read_consume(buf, read_start, ret);
|
|
||||||
*ppos = relay_file_read_end_pos(buf, read_start, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t relay_file_sendfile(struct file *filp, loff_t *ppos,
|
static ssize_t relay_file_read(struct file *filp,
|
||||||
size_t count, read_actor_t actor,
|
char __user *buffer,
|
||||||
|
size_t count,
|
||||||
|
loff_t *ppos)
|
||||||
|
{
|
||||||
|
return relay_file_read_subbufs(filp, ppos, count, subbuf_read_actor,
|
||||||
|
NULL, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t relay_file_sendfile(struct file *filp,
|
||||||
|
loff_t *ppos,
|
||||||
|
size_t count,
|
||||||
|
read_actor_t actor,
|
||||||
void *target)
|
void *target)
|
||||||
{
|
{
|
||||||
ssize_t sent = 0, ret = 0;
|
return relay_file_read_subbufs(filp, ppos, count, subbuf_send_actor,
|
||||||
|
actor, target);
|
||||||
if (!count)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
mutex_lock(&filp->f_dentry->d_inode->i_mutex);
|
|
||||||
|
|
||||||
do {
|
|
||||||
ret = relay_file_sendsubbuf(filp, ppos, count, actor, target);
|
|
||||||
if (ret < 0) {
|
|
||||||
if (!sent)
|
|
||||||
sent = ret;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
count -= ret;
|
|
||||||
sent += ret;
|
|
||||||
} while (count && ret);
|
|
||||||
|
|
||||||
mutex_unlock(&filp->f_dentry->d_inode->i_mutex);
|
|
||||||
return sent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct file_operations relay_file_operations = {
|
struct file_operations relay_file_operations = {
|
||||||
|
|
Loading…
Reference in New Issue