提交 88dd9c16 编写于 作者: L Linus Torvalds

Merge branch 'splice' of git://brick.kernel.dk/data/git/linux-2.6-block

* 'splice' of git://brick.kernel.dk/data/git/linux-2.6-block:
  [PATCH] vfs: add splice_write and splice_read to documentation
  [PATCH] Remove sys_ prefix of new syscalls from __NR_sys_*
  [PATCH] splice: warning fix
  [PATCH] another round of fs/pipe.c cleanups
  [PATCH] splice: comment styles
  [PATCH] splice: add Ingo as addition copyright holder
  [PATCH] splice: unlikely() optimizations
  [PATCH] splice: speedups and optimizations
  [PATCH] pipe.c/fifo.c code cleanups
  [PATCH] get rid of the PIPE_*() macros
  [PATCH] splice: speedup __generic_file_splice_read
  [PATCH] splice: add direct fd <-> fd splicing support
  [PATCH] splice: add optional input and output offsets
  [PATCH] introduce a "kernel-internal pipe object" abstraction
  [PATCH] splice: be smarter about calling do_page_cache_readahead()
  [PATCH] splice: optimize the splice buffer mapping
  [PATCH] splice: cleanup __generic_file_splice_read()
  [PATCH] splice: only call wake_up_interruptible() when we really have to
  [PATCH] splice: potential !page dereference
  [PATCH] splice: mark the io page as accessed
......@@ -694,7 +694,7 @@ struct file_operations
----------------------
This describes how the VFS can manipulate an open file. As of kernel
2.6.13, the following members are defined:
2.6.17, the following members are defined:
struct file_operations {
loff_t (*llseek) (struct file *, loff_t, int);
......@@ -723,6 +723,10 @@ struct file_operations {
int (*check_flags)(int);
int (*dir_notify)(struct file *filp, unsigned long arg);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned
int);
ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned
int);
};
Again, all methods are called without any locks being held, unless
......@@ -790,6 +794,12 @@ otherwise noted.
flock: called by the flock(2) system call
splice_write: called by the VFS to splice data from a pipe to a file. This
method is used by the splice(2) system call
splice_read: called by the VFS to splice data from file to a pipe. This
method is used by the splice(2) system call
Note that the file operations are implemented by the specific
filesystem in which the inode resides. When opening a device node
(character or block special) most filesystems will call special
......
......@@ -15,30 +15,35 @@
#include <linux/fs.h>
#include <linux/pipe_fs_i.h>
static void wait_for_partner(struct inode* inode, unsigned int* cnt)
static void wait_for_partner(struct inode* inode, unsigned int *cnt)
{
int cur = *cnt;
while(cur == *cnt) {
pipe_wait(inode);
if(signal_pending(current))
while (cur == *cnt) {
pipe_wait(inode->i_pipe);
if (signal_pending(current))
break;
}
}
static void wake_up_partner(struct inode* inode)
{
wake_up_interruptible(PIPE_WAIT(*inode));
wake_up_interruptible(&inode->i_pipe->wait);
}
static int fifo_open(struct inode *inode, struct file *filp)
{
struct pipe_inode_info *pipe;
int ret;
mutex_lock(PIPE_MUTEX(*inode));
if (!inode->i_pipe) {
mutex_lock(&inode->i_mutex);
pipe = inode->i_pipe;
if (!pipe) {
ret = -ENOMEM;
if(!pipe_new(inode))
pipe = alloc_pipe_info(inode);
if (!pipe)
goto err_nocleanup;
inode->i_pipe = pipe;
}
filp->f_version = 0;
......@@ -53,18 +58,18 @@ static int fifo_open(struct inode *inode, struct file *filp)
* opened, even when there is no process writing the FIFO.
*/
filp->f_op = &read_fifo_fops;
PIPE_RCOUNTER(*inode)++;
if (PIPE_READERS(*inode)++ == 0)
pipe->r_counter++;
if (pipe->readers++ == 0)
wake_up_partner(inode);
if (!PIPE_WRITERS(*inode)) {
if (!pipe->writers) {
if ((filp->f_flags & O_NONBLOCK)) {
/* suppress POLLHUP until we have
* seen a writer */
filp->f_version = PIPE_WCOUNTER(*inode);
filp->f_version = pipe->w_counter;
} else
{
wait_for_partner(inode, &PIPE_WCOUNTER(*inode));
wait_for_partner(inode, &pipe->w_counter);
if(signal_pending(current))
goto err_rd;
}
......@@ -78,16 +83,16 @@ static int fifo_open(struct inode *inode, struct file *filp)
* errno=ENXIO when there is no process reading the FIFO.
*/
ret = -ENXIO;
if ((filp->f_flags & O_NONBLOCK) && !PIPE_READERS(*inode))
if ((filp->f_flags & O_NONBLOCK) && !pipe->readers)
goto err;
filp->f_op = &write_fifo_fops;
PIPE_WCOUNTER(*inode)++;
if (!PIPE_WRITERS(*inode)++)
pipe->w_counter++;
if (!pipe->writers++)
wake_up_partner(inode);
if (!PIPE_READERS(*inode)) {
wait_for_partner(inode, &PIPE_RCOUNTER(*inode));
if (!pipe->readers) {
wait_for_partner(inode, &pipe->r_counter);
if (signal_pending(current))
goto err_wr;
}
......@@ -102,11 +107,11 @@ static int fifo_open(struct inode *inode, struct file *filp)
*/
filp->f_op = &rdwr_fifo_fops;
PIPE_READERS(*inode)++;
PIPE_WRITERS(*inode)++;
PIPE_RCOUNTER(*inode)++;
PIPE_WCOUNTER(*inode)++;
if (PIPE_READERS(*inode) == 1 || PIPE_WRITERS(*inode) == 1)
pipe->readers++;
pipe->writers++;
pipe->r_counter++;
pipe->w_counter++;
if (pipe->readers == 1 || pipe->writers == 1)
wake_up_partner(inode);
break;
......@@ -116,27 +121,27 @@ static int fifo_open(struct inode *inode, struct file *filp)
}
/* Ok! */
mutex_unlock(PIPE_MUTEX(*inode));
mutex_unlock(&inode->i_mutex);
return 0;
err_rd:
if (!--PIPE_READERS(*inode))
wake_up_interruptible(PIPE_WAIT(*inode));
if (!--pipe->readers)
wake_up_interruptible(&pipe->wait);
ret = -ERESTARTSYS;
goto err;
err_wr:
if (!--PIPE_WRITERS(*inode))
wake_up_interruptible(PIPE_WAIT(*inode));
if (!--pipe->writers)
wake_up_interruptible(&pipe->wait);
ret = -ERESTARTSYS;
goto err;
err:
if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode))
if (!pipe->readers && !pipe->writers)
free_pipe_info(inode);
err_nocleanup:
mutex_unlock(PIPE_MUTEX(*inode));
mutex_unlock(&inode->i_mutex);
return ret;
}
......
......@@ -36,7 +36,7 @@
*/
/* Drop the inode semaphore and wait for a pipe event, atomically */
void pipe_wait(struct inode * inode)
void pipe_wait(struct pipe_inode_info *pipe)
{
DEFINE_WAIT(wait);
......@@ -44,11 +44,14 @@ void pipe_wait(struct inode * inode)
* Pipes are system-local resources, so sleeping on them
* is considered a noninteractive wait:
*/
prepare_to_wait(PIPE_WAIT(*inode), &wait, TASK_INTERRUPTIBLE|TASK_NONINTERACTIVE);
mutex_unlock(PIPE_MUTEX(*inode));
prepare_to_wait(&pipe->wait, &wait,
TASK_INTERRUPTIBLE | TASK_NONINTERACTIVE);
if (pipe->inode)
mutex_unlock(&pipe->inode->i_mutex);
schedule();
finish_wait(PIPE_WAIT(*inode), &wait);
mutex_lock(PIPE_MUTEX(*inode));
finish_wait(&pipe->wait, &wait);
if (pipe->inode)
mutex_lock(&pipe->inode->i_mutex);
}
static int
......@@ -91,7 +94,8 @@ pipe_iov_copy_to_user(struct iovec *iov, const void *from, unsigned long len)
return 0;
}
static void anon_pipe_buf_release(struct pipe_inode_info *info, struct pipe_buffer *buf)
static void anon_pipe_buf_release(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
struct page *page = buf->page;
......@@ -100,30 +104,27 @@ static void anon_pipe_buf_release(struct pipe_inode_info *info, struct pipe_buff
/*
* If nobody else uses this page, and we don't already have a
* temporary page, let's keep track of it as a one-deep
* allocation cache
* allocation cache. (Otherwise just release our reference to it)
*/
if (page_count(page) == 1 && !info->tmp_page) {
info->tmp_page = page;
return;
}
/*
* Otherwise just release our reference to it
*/
page_cache_release(page);
if (page_count(page) == 1 && !pipe->tmp_page)
pipe->tmp_page = page;
else
page_cache_release(page);
}
static void *anon_pipe_buf_map(struct file *file, struct pipe_inode_info *info, struct pipe_buffer *buf)
static void * anon_pipe_buf_map(struct file *file, struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
return kmap(buf->page);
}
static void anon_pipe_buf_unmap(struct pipe_inode_info *info, struct pipe_buffer *buf)
static void anon_pipe_buf_unmap(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
kunmap(buf->page);
}
static int anon_pipe_buf_steal(struct pipe_inode_info *info,
static int anon_pipe_buf_steal(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
buf->flags |= PIPE_BUF_FLAG_STOLEN;
......@@ -143,7 +144,7 @@ pipe_readv(struct file *filp, const struct iovec *_iov,
unsigned long nr_segs, loff_t *ppos)
{
struct inode *inode = filp->f_dentry->d_inode;
struct pipe_inode_info *info;
struct pipe_inode_info *pipe;
int do_wakeup;
ssize_t ret;
struct iovec *iov = (struct iovec *)_iov;
......@@ -156,13 +157,13 @@ pipe_readv(struct file *filp, const struct iovec *_iov,
do_wakeup = 0;
ret = 0;
mutex_lock(PIPE_MUTEX(*inode));
info = inode->i_pipe;
mutex_lock(&inode->i_mutex);
pipe = inode->i_pipe;
for (;;) {
int bufs = info->nrbufs;
int bufs = pipe->nrbufs;
if (bufs) {
int curbuf = info->curbuf;
struct pipe_buffer *buf = info->bufs + curbuf;
int curbuf = pipe->curbuf;
struct pipe_buffer *buf = pipe->bufs + curbuf;
struct pipe_buf_operations *ops = buf->ops;
void *addr;
size_t chars = buf->len;
......@@ -171,16 +172,17 @@ pipe_readv(struct file *filp, const struct iovec *_iov,
if (chars > total_len)
chars = total_len;
addr = ops->map(filp, info, buf);
addr = ops->map(filp, pipe, buf);
if (IS_ERR(addr)) {
if (!ret)
ret = PTR_ERR(addr);
break;
}
error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars);
ops->unmap(info, buf);
ops->unmap(pipe, buf);
if (unlikely(error)) {
if (!ret) ret = -EFAULT;
if (!ret)
ret = -EFAULT;
break;
}
ret += chars;
......@@ -188,10 +190,10 @@ pipe_readv(struct file *filp, const struct iovec *_iov,
buf->len -= chars;
if (!buf->len) {
buf->ops = NULL;
ops->release(info, buf);
ops->release(pipe, buf);
curbuf = (curbuf + 1) & (PIPE_BUFFERS-1);
info->curbuf = curbuf;
info->nrbufs = --bufs;
pipe->curbuf = curbuf;
pipe->nrbufs = --bufs;
do_wakeup = 1;
}
total_len -= chars;
......@@ -200,9 +202,9 @@ pipe_readv(struct file *filp, const struct iovec *_iov,
}
if (bufs) /* More to do? */
continue;
if (!PIPE_WRITERS(*inode))
if (!pipe->writers)
break;
if (!PIPE_WAITING_WRITERS(*inode)) {
if (!pipe->waiting_writers) {
/* syscall merging: Usually we must not sleep
* if O_NONBLOCK is set, or if we got some data.
* But if a writer sleeps in kernel space, then
......@@ -216,20 +218,22 @@ pipe_readv(struct file *filp, const struct iovec *_iov,
}
}
if (signal_pending(current)) {
if (!ret) ret = -ERESTARTSYS;
if (!ret)
ret = -ERESTARTSYS;
break;
}
if (do_wakeup) {
wake_up_interruptible_sync(PIPE_WAIT(*inode));
kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT);
wake_up_interruptible_sync(&pipe->wait);
kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
}
pipe_wait(inode);
pipe_wait(pipe);
}
mutex_unlock(PIPE_MUTEX(*inode));
/* Signal writers asynchronously that there is more room. */
mutex_unlock(&inode->i_mutex);
/* Signal writers asynchronously that there is more room. */
if (do_wakeup) {
wake_up_interruptible(PIPE_WAIT(*inode));
kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT);
wake_up_interruptible(&pipe->wait);
kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
}
if (ret > 0)
file_accessed(filp);
......@@ -240,6 +244,7 @@ static ssize_t
pipe_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
struct iovec iov = { .iov_base = buf, .iov_len = count };
return pipe_readv(filp, &iov, 1, ppos);
}
......@@ -248,7 +253,7 @@ pipe_writev(struct file *filp, const struct iovec *_iov,
unsigned long nr_segs, loff_t *ppos)
{
struct inode *inode = filp->f_dentry->d_inode;
struct pipe_inode_info *info;
struct pipe_inode_info *pipe;
ssize_t ret;
int do_wakeup;
struct iovec *iov = (struct iovec *)_iov;
......@@ -262,10 +267,10 @@ pipe_writev(struct file *filp, const struct iovec *_iov,
do_wakeup = 0;
ret = 0;
mutex_lock(PIPE_MUTEX(*inode));
info = inode->i_pipe;
mutex_lock(&inode->i_mutex);
pipe = inode->i_pipe;
if (!PIPE_READERS(*inode)) {
if (!pipe->readers) {
send_sig(SIGPIPE, current, 0);
ret = -EPIPE;
goto out;
......@@ -273,23 +278,25 @@ pipe_writev(struct file *filp, const struct iovec *_iov,
/* We try to merge small writes */
chars = total_len & (PAGE_SIZE-1); /* size of the last buffer */
if (info->nrbufs && chars != 0) {
int lastbuf = (info->curbuf + info->nrbufs - 1) & (PIPE_BUFFERS-1);
struct pipe_buffer *buf = info->bufs + lastbuf;
if (pipe->nrbufs && chars != 0) {
int lastbuf = (pipe->curbuf + pipe->nrbufs - 1) &
(PIPE_BUFFERS-1);
struct pipe_buffer *buf = pipe->bufs + lastbuf;
struct pipe_buf_operations *ops = buf->ops;
int offset = buf->offset + buf->len;
if (ops->can_merge && offset + chars <= PAGE_SIZE) {
void *addr;
int error;
addr = ops->map(filp, info, buf);
addr = ops->map(filp, pipe, buf);
if (IS_ERR(addr)) {
error = PTR_ERR(addr);
goto out;
}
error = pipe_iov_copy_from_user(offset + addr, iov,
chars);
ops->unmap(info, buf);
ops->unmap(pipe, buf);
ret = error;
do_wakeup = 1;
if (error)
......@@ -304,16 +311,18 @@ pipe_writev(struct file *filp, const struct iovec *_iov,
for (;;) {
int bufs;
if (!PIPE_READERS(*inode)) {
if (!pipe->readers) {
send_sig(SIGPIPE, current, 0);
if (!ret) ret = -EPIPE;
if (!ret)
ret = -EPIPE;
break;
}
bufs = info->nrbufs;
bufs = pipe->nrbufs;
if (bufs < PIPE_BUFFERS) {
int newbuf = (info->curbuf + bufs) & (PIPE_BUFFERS-1);
struct pipe_buffer *buf = info->bufs + newbuf;
struct page *page = info->tmp_page;
int newbuf = (pipe->curbuf + bufs) & (PIPE_BUFFERS-1);
struct pipe_buffer *buf = pipe->bufs + newbuf;
struct page *page = pipe->tmp_page;
int error;
if (!page) {
......@@ -322,9 +331,9 @@ pipe_writev(struct file *filp, const struct iovec *_iov,
ret = ret ? : -ENOMEM;
break;
}
info->tmp_page = page;
pipe->tmp_page = page;
}
/* Always wakeup, even if the copy fails. Otherwise
/* Always wake up, even if the copy fails. Otherwise
* we lock up (O_NONBLOCK-)readers that sleep due to
* syscall merging.
* FIXME! Is this really true?
......@@ -337,7 +346,8 @@ pipe_writev(struct file *filp, const struct iovec *_iov,
error = pipe_iov_copy_from_user(kmap(page), iov, chars);
kunmap(page);
if (unlikely(error)) {
if (!ret) ret = -EFAULT;
if (!ret)
ret = -EFAULT;
break;
}
ret += chars;
......@@ -347,8 +357,8 @@ pipe_writev(struct file *filp, const struct iovec *_iov,
buf->ops = &anon_pipe_buf_ops;
buf->offset = 0;
buf->len = chars;
info->nrbufs = ++bufs;
info->tmp_page = NULL;
pipe->nrbufs = ++bufs;
pipe->tmp_page = NULL;
total_len -= chars;
if (!total_len)
......@@ -357,27 +367,29 @@ pipe_writev(struct file *filp, const struct iovec *_iov,
if (bufs < PIPE_BUFFERS)
continue;
if (filp->f_flags & O_NONBLOCK) {
if (!ret) ret = -EAGAIN;
if (!ret)
ret = -EAGAIN;
break;
}
if (signal_pending(current)) {
if (!ret) ret = -ERESTARTSYS;
if (!ret)
ret = -ERESTARTSYS;
break;
}
if (do_wakeup) {
wake_up_interruptible_sync(PIPE_WAIT(*inode));
kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN);
wake_up_interruptible_sync(&pipe->wait);
kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
do_wakeup = 0;
}
PIPE_WAITING_WRITERS(*inode)++;
pipe_wait(inode);
PIPE_WAITING_WRITERS(*inode)--;
pipe->waiting_writers++;
pipe_wait(pipe);
pipe->waiting_writers--;
}
out:
mutex_unlock(PIPE_MUTEX(*inode));
mutex_unlock(&inode->i_mutex);
if (do_wakeup) {
wake_up_interruptible(PIPE_WAIT(*inode));
kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN);
wake_up_interruptible(&pipe->wait);
kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
}
if (ret > 0)
file_update_time(filp);
......@@ -389,6 +401,7 @@ pipe_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count };
return pipe_writev(filp, &iov, 1, ppos);
}
......@@ -399,7 +412,8 @@ bad_pipe_r(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
}
static ssize_t
bad_pipe_w(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
bad_pipe_w(struct file *filp, const char __user *buf, size_t count,
loff_t *ppos)
{
return -EBADF;
}
......@@ -409,21 +423,22 @@ pipe_ioctl(struct inode *pino, struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct inode *inode = filp->f_dentry->d_inode;
struct pipe_inode_info *info;
struct pipe_inode_info *pipe;
int count, buf, nrbufs;
switch (cmd) {
case FIONREAD:
mutex_lock(PIPE_MUTEX(*inode));
info = inode->i_pipe;
mutex_lock(&inode->i_mutex);
pipe = inode->i_pipe;
count = 0;
buf = info->curbuf;
nrbufs = info->nrbufs;
buf = pipe->curbuf;
nrbufs = pipe->nrbufs;
while (--nrbufs >= 0) {
count += info->bufs[buf].len;
count += pipe->bufs[buf].len;
buf = (buf+1) & (PIPE_BUFFERS-1);
}
mutex_unlock(PIPE_MUTEX(*inode));
mutex_unlock(&inode->i_mutex);
return put_user(count, (int __user *)arg);
default:
return -EINVAL;
......@@ -436,17 +451,17 @@ pipe_poll(struct file *filp, poll_table *wait)
{
unsigned int mask;
struct inode *inode = filp->f_dentry->d_inode;
struct pipe_inode_info *info = inode->i_pipe;
struct pipe_inode_info *pipe = inode->i_pipe;
int nrbufs;
poll_wait(filp, PIPE_WAIT(*inode), wait);
poll_wait(filp, &pipe->wait, wait);
/* Reading only -- no need for acquiring the semaphore. */
nrbufs = info->nrbufs;
nrbufs = pipe->nrbufs;
mask = 0;
if (filp->f_mode & FMODE_READ) {
mask = (nrbufs > 0) ? POLLIN | POLLRDNORM : 0;
if (!PIPE_WRITERS(*inode) && filp->f_version != PIPE_WCOUNTER(*inode))
if (!pipe->writers && filp->f_version != pipe->w_counter)
mask |= POLLHUP;
}
......@@ -456,7 +471,7 @@ pipe_poll(struct file *filp, poll_table *wait)
* Most Unices do not set POLLERR for FIFOs but on Linux they
* behave exactly like pipes for poll().
*/
if (!PIPE_READERS(*inode))
if (!pipe->readers)
mask |= POLLERR;
}
......@@ -466,17 +481,21 @@ pipe_poll(struct file *filp, poll_table *wait)
static int
pipe_release(struct inode *inode, int decr, int decw)
{
mutex_lock(PIPE_MUTEX(*inode));
PIPE_READERS(*inode) -= decr;
PIPE_WRITERS(*inode) -= decw;
if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) {
struct pipe_inode_info *pipe;
mutex_lock(&inode->i_mutex);
pipe = inode->i_pipe;
pipe->readers -= decr;
pipe->writers -= decw;
if (!pipe->readers && !pipe->writers) {
free_pipe_info(inode);
} else {
wake_up_interruptible(PIPE_WAIT(*inode));
kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN);
kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT);
wake_up_interruptible(&pipe->wait);
kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
}
mutex_unlock(PIPE_MUTEX(*inode));
mutex_unlock(&inode->i_mutex);
return 0;
}
......@@ -487,9 +506,9 @@ pipe_read_fasync(int fd, struct file *filp, int on)
struct inode *inode = filp->f_dentry->d_inode;
int retval;
mutex_lock(PIPE_MUTEX(*inode));
retval = fasync_helper(fd, filp, on, PIPE_FASYNC_READERS(*inode));
mutex_unlock(PIPE_MUTEX(*inode));
mutex_lock(&inode->i_mutex);
retval = fasync_helper(fd, filp, on, &inode->i_pipe->fasync_readers);
mutex_unlock(&inode->i_mutex);
if (retval < 0)
return retval;
......@@ -504,9 +523,9 @@ pipe_write_fasync(int fd, struct file *filp, int on)
struct inode *inode = filp->f_dentry->d_inode;
int retval;
mutex_lock(PIPE_MUTEX(*inode));
retval = fasync_helper(fd, filp, on, PIPE_FASYNC_WRITERS(*inode));
mutex_unlock(PIPE_MUTEX(*inode));
mutex_lock(&inode->i_mutex);
retval = fasync_helper(fd, filp, on, &inode->i_pipe->fasync_writers);
mutex_unlock(&inode->i_mutex);
if (retval < 0)
return retval;
......@@ -519,16 +538,17 @@ static int
pipe_rdwr_fasync(int fd, struct file *filp, int on)
{
struct inode *inode = filp->f_dentry->d_inode;
struct pipe_inode_info *pipe = inode->i_pipe;
int retval;
mutex_lock(PIPE_MUTEX(*inode));
mutex_lock(&inode->i_mutex);
retval = fasync_helper(fd, filp, on, PIPE_FASYNC_READERS(*inode));
retval = fasync_helper(fd, filp, on, &pipe->fasync_readers);
if (retval >= 0)
retval = fasync_helper(fd, filp, on, PIPE_FASYNC_WRITERS(*inode));
retval = fasync_helper(fd, filp, on, &pipe->fasync_writers);
mutex_unlock(PIPE_MUTEX(*inode));
mutex_unlock(&inode->i_mutex);
if (retval < 0)
return retval;
......@@ -567,9 +587,9 @@ pipe_read_open(struct inode *inode, struct file *filp)
{
/* We could have perhaps used atomic_t, but this and friends
below are the only places. So it doesn't seem worthwhile. */
mutex_lock(PIPE_MUTEX(*inode));
PIPE_READERS(*inode)++;
mutex_unlock(PIPE_MUTEX(*inode));
mutex_lock(&inode->i_mutex);
inode->i_pipe->readers++;
mutex_unlock(&inode->i_mutex);
return 0;
}
......@@ -577,9 +597,9 @@ pipe_read_open(struct inode *inode, struct file *filp)
static int
pipe_write_open(struct inode *inode, struct file *filp)
{
mutex_lock(PIPE_MUTEX(*inode));
PIPE_WRITERS(*inode)++;
mutex_unlock(PIPE_MUTEX(*inode));
mutex_lock(&inode->i_mutex);
inode->i_pipe->writers++;
mutex_unlock(&inode->i_mutex);
return 0;
}
......@@ -587,12 +607,12 @@ pipe_write_open(struct inode *inode, struct file *filp)
static int
pipe_rdwr_open(struct inode *inode, struct file *filp)
{
mutex_lock(PIPE_MUTEX(*inode));
mutex_lock(&inode->i_mutex);
if (filp->f_mode & FMODE_READ)
PIPE_READERS(*inode)++;
inode->i_pipe->readers++;
if (filp->f_mode & FMODE_WRITE)
PIPE_WRITERS(*inode)++;
mutex_unlock(PIPE_MUTEX(*inode));
inode->i_pipe->writers++;
mutex_unlock(&inode->i_mutex);
return 0;
}
......@@ -675,37 +695,38 @@ static struct file_operations rdwr_pipe_fops = {
.fasync = pipe_rdwr_fasync,
};
void free_pipe_info(struct inode *inode)
struct pipe_inode_info * alloc_pipe_info(struct inode *inode)
{
struct pipe_inode_info *pipe;
pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
if (pipe) {
init_waitqueue_head(&pipe->wait);
pipe->r_counter = pipe->w_counter = 1;
pipe->inode = inode;
}
return pipe;
}
void __free_pipe_info(struct pipe_inode_info *pipe)
{
int i;
struct pipe_inode_info *info = inode->i_pipe;
inode->i_pipe = NULL;
for (i = 0; i < PIPE_BUFFERS; i++) {
struct pipe_buffer *buf = info->bufs + i;
struct pipe_buffer *buf = pipe->bufs + i;
if (buf->ops)
buf->ops->release(info, buf);
buf->ops->release(pipe, buf);
}
if (info->tmp_page)
__free_page(info->tmp_page);
kfree(info);
if (pipe->tmp_page)
__free_page(pipe->tmp_page);
kfree(pipe);
}
struct inode* pipe_new(struct inode* inode)
void free_pipe_info(struct inode *inode)
{
struct pipe_inode_info *info;
info = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
if (!info)
goto fail_page;
inode->i_pipe = info;
init_waitqueue_head(PIPE_WAIT(*inode));
PIPE_RCOUNTER(*inode) = PIPE_WCOUNTER(*inode) = 1;
return inode;
fail_page:
return NULL;
__free_pipe_info(inode->i_pipe);
inode->i_pipe = NULL;
}
static struct vfsmount *pipe_mnt __read_mostly;
......@@ -713,6 +734,7 @@ static int pipefs_delete_dentry(struct dentry *dentry)
{
return 1;
}
static struct dentry_operations pipefs_dentry_operations = {
.d_delete = pipefs_delete_dentry,
};
......@@ -720,13 +742,17 @@ static struct dentry_operations pipefs_dentry_operations = {
static struct inode * get_pipe_inode(void)
{
struct inode *inode = new_inode(pipe_mnt->mnt_sb);
struct pipe_inode_info *pipe;
if (!inode)
goto fail_inode;
if(!pipe_new(inode))
pipe = alloc_pipe_info(inode);
if (!pipe)
goto fail_iput;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
inode->i_pipe = pipe;
pipe->readers = pipe->writers = 1;
inode->i_fop = &rdwr_pipe_fops;
/*
......@@ -741,10 +767,12 @@ static struct inode * get_pipe_inode(void)
inode->i_gid = current->fsgid;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_blksize = PAGE_SIZE;
return inode;
fail_iput:
iput(inode);
fail_inode:
return NULL;
}
......@@ -757,7 +785,7 @@ int do_pipe(int *fd)
struct inode * inode;
struct file *f1, *f2;
int error;
int i,j;
int i, j;
error = -ENFILE;
f1 = get_empty_filp();
......@@ -790,6 +818,7 @@ int do_pipe(int *fd)
dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &this);
if (!dentry)
goto close_f12_inode_i_j;
dentry->d_op = &pipefs_dentry_operations;
d_add(dentry, inode);
f1->f_vfsmnt = f2->f_vfsmnt = mntget(mntget(pipe_mnt));
......@@ -813,6 +842,7 @@ int do_pipe(int *fd)
fd_install(j, f2);
fd[0] = i;
fd[1] = j;
return 0;
close_f12_inode_i_j:
......@@ -837,8 +867,9 @@ int do_pipe(int *fd)
* d_name - pipe: will go nicely and kill the special-casing in procfs.
*/
static struct super_block *pipefs_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
static struct super_block *
pipefs_get_sb(struct file_system_type *fs_type, int flags,
const char *dev_name, void *data)
{
return get_sb_pseudo(fs_type, "pipe:", NULL, PIPEFS_MAGIC);
}
......@@ -852,6 +883,7 @@ static struct file_system_type pipe_fs_type = {
static int __init init_pipe_fs(void)
{
int err = register_filesystem(&pipe_fs_type);
if (!err) {
pipe_mnt = kern_mount(&pipe_fs_type);
if (IS_ERR(pipe_mnt)) {
......
......@@ -202,7 +202,7 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count
goto Einval;
inode = file->f_dentry->d_inode;
if (inode->i_flock && MANDATORY_LOCK(inode)) {
if (unlikely(inode->i_flock && MANDATORY_LOCK(inode))) {
int retval = locks_mandatory_area(
read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
inode, file, pos, count);
......
此差异已折叠。
......@@ -252,7 +252,7 @@ xfs_file_sendfile_invis(
STATIC ssize_t
xfs_file_splice_read(
struct file *infilp,
struct inode *pipe,
struct pipe_inode_info *pipe,
size_t len,
unsigned int flags)
{
......@@ -266,7 +266,7 @@ xfs_file_splice_read(
STATIC ssize_t
xfs_file_splice_read_invis(
struct file *infilp,
struct inode *pipe,
struct pipe_inode_info *pipe,
size_t len,
unsigned int flags)
{
......@@ -279,7 +279,7 @@ xfs_file_splice_read_invis(
STATIC ssize_t
xfs_file_splice_write(
struct inode *pipe,
struct pipe_inode_info *pipe,
struct file *outfilp,
size_t len,
unsigned int flags)
......@@ -293,7 +293,7 @@ xfs_file_splice_write(
STATIC ssize_t
xfs_file_splice_write_invis(
struct inode *pipe,
struct pipe_inode_info *pipe,
struct file *outfilp,
size_t len,
unsigned int flags)
......
......@@ -338,7 +338,7 @@ ssize_t
xfs_splice_read(
bhv_desc_t *bdp,
struct file *infilp,
struct inode *pipe,
struct pipe_inode_info *pipe,
size_t count,
int flags,
int ioflags,
......@@ -380,7 +380,7 @@ xfs_splice_read(
ssize_t
xfs_splice_write(
bhv_desc_t *bdp,
struct inode *pipe,
struct pipe_inode_info *pipe,
struct file *outfilp,
size_t count,
int flags,
......
......@@ -94,9 +94,9 @@ extern ssize_t xfs_sendfile(struct bhv_desc *, struct file *,
loff_t *, int, size_t, read_actor_t,
void *, struct cred *);
extern ssize_t xfs_splice_read(struct bhv_desc *, struct file *,
struct inode *, size_t, int, int,
struct pipe_inode_info *, size_t, int, int,
struct cred *);
extern ssize_t xfs_splice_write(struct bhv_desc *, struct inode *,
extern ssize_t xfs_splice_write(struct bhv_desc *, struct pipe_inode_info *,
struct file *, size_t, int, int,
struct cred *);
......
......@@ -174,9 +174,9 @@ typedef ssize_t (*vop_sendfile_t)(bhv_desc_t *, struct file *,
loff_t *, int, size_t, read_actor_t,
void *, struct cred *);
typedef ssize_t (*vop_splice_read_t)(bhv_desc_t *, struct file *,
struct inode *, size_t, int, int,
struct pipe_inode_info *, size_t, int, int,
struct cred *);
typedef ssize_t (*vop_splice_write_t)(bhv_desc_t *, struct inode *,
typedef ssize_t (*vop_splice_write_t)(bhv_desc_t *, struct pipe_inode_info *,
struct file *, size_t, int, int,
struct cred *);
typedef int (*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *,
......
......@@ -318,8 +318,8 @@
#define __NR_unshare 310
#define __NR_set_robust_list 311
#define __NR_get_robust_list 312
#define __NR_sys_splice 313
#define __NR_sys_sync_file_range 314
#define __NR_splice 313
#define __NR_sync_file_range 314
#define NR_syscalls 315
......
......@@ -1039,8 +1039,8 @@ struct file_operations {
int (*check_flags)(int);
int (*dir_notify)(struct file *filp, unsigned long arg);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct inode *, struct file *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, struct inode *, size_t, unsigned int);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int);
};
struct inode_operations {
......@@ -1611,8 +1611,17 @@ extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor
extern void do_generic_mapping_read(struct address_space *mapping,
struct file_ra_state *, struct file *,
loff_t *, read_descriptor_t *, read_actor_t);
extern ssize_t generic_file_splice_read(struct file *, struct inode *, size_t, unsigned int);
extern ssize_t generic_file_splice_write(struct inode *, struct file *, size_t, unsigned int);
/* fs/splice.c */
extern ssize_t generic_file_splice_read(struct file *,
struct pipe_inode_info *, size_t, unsigned int);
extern ssize_t generic_file_splice_write(struct pipe_inode_info *,
struct file *, size_t, unsigned int);
extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe,
struct file *out, size_t len, unsigned int flags);
extern long do_splice_direct(struct file *in, struct file *out,
size_t len, unsigned int flags);
extern void
file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
extern ssize_t generic_file_readv(struct file *filp, const struct iovec *iov,
......
......@@ -36,27 +36,19 @@ struct pipe_inode_info {
unsigned int w_counter;
struct fasync_struct *fasync_readers;
struct fasync_struct *fasync_writers;
struct inode *inode;
};
/* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual
memory allocation, whereas PIPE_BUF makes atomicity guarantees. */
#define PIPE_SIZE PAGE_SIZE
#define PIPE_MUTEX(inode) (&(inode).i_mutex)
#define PIPE_WAIT(inode) (&(inode).i_pipe->wait)
#define PIPE_READERS(inode) ((inode).i_pipe->readers)
#define PIPE_WRITERS(inode) ((inode).i_pipe->writers)
#define PIPE_WAITING_WRITERS(inode) ((inode).i_pipe->waiting_writers)
#define PIPE_RCOUNTER(inode) ((inode).i_pipe->r_counter)
#define PIPE_WCOUNTER(inode) ((inode).i_pipe->w_counter)
#define PIPE_FASYNC_READERS(inode) (&((inode).i_pipe->fasync_readers))
#define PIPE_FASYNC_WRITERS(inode) (&((inode).i_pipe->fasync_writers))
/* Drop the inode semaphore and wait for a pipe event, atomically */
void pipe_wait(struct inode * inode);
void pipe_wait(struct pipe_inode_info *pipe);
struct inode* pipe_new(struct inode* inode);
void free_pipe_info(struct inode* inode);
struct pipe_inode_info * alloc_pipe_info(struct inode * inode);
void free_pipe_info(struct inode * inode);
void __free_pipe_info(struct pipe_inode_info *);
/*
* splice is tied to pipes as a transport (at least for now), so we'll just
......
......@@ -684,6 +684,7 @@ static inline void prefetch_stack(struct task_struct *t) { }
struct audit_context; /* See audit.c */
struct mempolicy;
struct pipe_inode_info;
enum sleep_type {
SLEEP_NORMAL,
......@@ -882,6 +883,11 @@ struct task_struct {
atomic_t fs_excl; /* holding fs exclusive resources */
struct rcu_head rcu;
/*
* cache last used pipe for splice
*/
struct pipe_inode_info *splice_pipe;
};
static inline pid_t process_group(struct task_struct *tsk)
......
......@@ -569,8 +569,11 @@ asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user * filename,
asmlinkage long compat_sys_openat(unsigned int dfd, const char __user *filename,
int flags, int mode);
asmlinkage long sys_unshare(unsigned long unshare_flags);
asmlinkage long sys_splice(int fdin, int fdout, size_t len,
unsigned int flags);
asmlinkage long sys_splice(int fd_in, loff_t __user *off_in,
int fd_out, loff_t __user *off_out,
size_t len, unsigned int flags);
asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
unsigned int flags);
......
......@@ -34,6 +34,7 @@
#include <linux/mutex.h>
#include <linux/futex.h>
#include <linux/compat.h>
#include <linux/pipe_fs_i.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
......@@ -941,6 +942,9 @@ fastcall NORET_TYPE void do_exit(long code)
if (tsk->io_context)
exit_io_context();
if (tsk->splice_pipe)
__free_pipe_info(tsk->splice_pipe);
/* PF_DEAD causes final put_task_struct after we schedule. */
preempt_disable();
BUG_ON(tsk->flags & PF_DEAD);
......
......@@ -119,10 +119,6 @@ static ssize_t sock_writev(struct file *file, const struct iovec *vector,
static ssize_t sock_sendpage(struct file *file, struct page *page,
int offset, size_t size, loff_t *ppos, int more);
extern ssize_t generic_splice_sendpage(struct inode *inode, struct file *out,
size_t len, unsigned int flags);
/*
* Socket files have a set of 'special' operations as well as the generic file ones. These don't appear
* in the operation structures but are done directly via the socketcall() multiplexor.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册