user.c: #ifdef ->mq_bytes
[safe/jmp/linux-2.6] / kernel / relay.c
index d1d1920..ad85501 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Public API and common code for kernel->userspace relay file support.
  *
- * See Documentation/filesystems/relayfs.txt for an overview of relayfs.
+ * See Documentation/filesystems/relay.txt for an overview.
  *
  * Copyright (C) 2002-2005 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
  * Copyright (C) 1999-2005 - Karim Yaghmour (karim@opersys.com)
@@ -21,7 +21,7 @@
 #include <linux/vmalloc.h>
 #include <linux/mm.h>
 #include <linux/cpu.h>
-#include <linux/pipe_fs_i.h>
+#include <linux/splice.h>
 
 /* list of open channels, for cpu hotplug */
 static DEFINE_MUTEX(relay_channels_mutex);
@@ -80,7 +80,7 @@ static struct vm_operations_struct relay_file_mmap_ops = {
  *
  *     Caller should already have grabbed mmap_sem.
  */
-int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma)
+static int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma)
 {
        unsigned long length = vma->vm_end - vma->vm_start;
        struct file *filp = vma->vm_file;
@@ -145,7 +145,7 @@ depopulate:
  *
  *     Returns channel buffer if successful, %NULL otherwise.
  */
-struct rchan_buf *relay_create_buf(struct rchan *chan)
+static struct rchan_buf *relay_create_buf(struct rchan *chan)
 {
        struct rchan_buf *buf = kzalloc(sizeof(struct rchan_buf), GFP_KERNEL);
        if (!buf)
@@ -175,7 +175,7 @@ free_buf:
  *
  *     Should only be called from kref_put().
  */
-void relay_destroy_channel(struct kref *kref)
+static void relay_destroy_channel(struct kref *kref)
 {
        struct rchan *chan = container_of(kref, struct rchan, kref);
        kfree(chan);
@@ -185,7 +185,7 @@ void relay_destroy_channel(struct kref *kref)
  *     relay_destroy_buf - destroy an rchan_buf struct and associated buffer
  *     @buf: the buffer struct
  */
-void relay_destroy_buf(struct rchan_buf *buf)
+static void relay_destroy_buf(struct rchan_buf *buf)
 {
        struct rchan *chan = buf->chan;
        unsigned int i;
@@ -210,7 +210,7 @@ void relay_destroy_buf(struct rchan_buf *buf)
  *     rchan_buf_struct and the channel buffer.  Should only be called from
  *     kref_put().
  */
-void relay_remove_buf(struct kref *kref)
+static void relay_remove_buf(struct kref *kref)
 {
        struct rchan_buf *buf = container_of(kref, struct rchan_buf, kref);
        buf->chan->cb->remove_buf_file(buf->dentry);
@@ -223,11 +223,10 @@ void relay_remove_buf(struct kref *kref)
  *
  *     Returns 1 if the buffer is empty, 0 otherwise.
  */
-int relay_buf_empty(struct rchan_buf *buf)
+static int relay_buf_empty(struct rchan_buf *buf)
 {
        return (buf->subbufs_produced - buf->subbufs_consumed) ? 0 : 1;
 }
-EXPORT_SYMBOL_GPL(relay_buf_empty);
 
 /**
  *     relay_buf_full - boolean, is the channel buffer full?
@@ -427,6 +426,7 @@ static struct rchan_buf *relay_open_buf(struct rchan *chan, unsigned int cpu)
 
 free_buf:
        relay_destroy_buf(buf);
+       buf = NULL;
 free_name:
        kfree(tmpname);
 end:
@@ -1032,32 +1032,36 @@ static ssize_t relay_file_read(struct file *filp,
                                       NULL, &desc);
 }
 
+static void relay_consume_bytes(struct rchan_buf *rbuf, int bytes_consumed)
+{
+       rbuf->bytes_consumed += bytes_consumed;
+
+       if (rbuf->bytes_consumed >= rbuf->chan->subbuf_size) {
+               relay_subbufs_consumed(rbuf->chan, rbuf->cpu, 1);
+               rbuf->bytes_consumed %= rbuf->chan->subbuf_size;
+       }
+}
+
 static void relay_pipe_buf_release(struct pipe_inode_info *pipe,
                                   struct pipe_buffer *buf)
 {
        struct rchan_buf *rbuf;
 
        rbuf = (struct rchan_buf *)page_private(buf->page);
-
-       rbuf->bytes_consumed += PAGE_SIZE;
-
-       if (rbuf->bytes_consumed == rbuf->chan->subbuf_size) {
-               relay_subbufs_consumed(rbuf->chan, rbuf->cpu, 1);
-               rbuf->bytes_consumed = 0;
-       }
+       relay_consume_bytes(rbuf, buf->private);
 }
 
 static struct pipe_buf_operations relay_pipe_buf_ops = {
        .can_merge = 0,
        .map = generic_pipe_buf_map,
        .unmap = generic_pipe_buf_unmap,
-       .pin = generic_pipe_buf_pin,
+       .confirm = generic_pipe_buf_confirm,
        .release = relay_pipe_buf_release,
        .steal = generic_pipe_buf_steal,
        .get = generic_pipe_buf_get,
 };
 
-/**
+/*
  *     subbuf_splice_actor - splice up to one subbuf's worth of data
  */
 static int subbuf_splice_actor(struct file *in,
@@ -1067,118 +1071,81 @@ static int subbuf_splice_actor(struct file *in,
                               unsigned int flags,
                               int *nonpad_ret)
 {
-       unsigned int pidx, poff;
-       unsigned int subbuf_pages;
-       int ret = 0;
-       int do_wakeup = 0;
+       unsigned int pidx, poff, total_len, subbuf_pages, ret;
        struct rchan_buf *rbuf = in->private_data;
        unsigned int subbuf_size = rbuf->chan->subbuf_size;
-       size_t read_start = ((size_t)*ppos) % rbuf->chan->alloc_size;
-       size_t avail = subbuf_size - read_start % subbuf_size;
+       uint64_t pos = (uint64_t) *ppos;
+       uint32_t alloc_size = (uint32_t) rbuf->chan->alloc_size;
+       size_t read_start = (size_t) do_div(pos, alloc_size);
        size_t read_subbuf = read_start / subbuf_size;
        size_t padding = rbuf->padding[read_subbuf];
        size_t nonpad_end = read_subbuf * subbuf_size + subbuf_size - padding;
+       struct page *pages[PIPE_BUFFERS];
+       struct partial_page partial[PIPE_BUFFERS];
+       struct splice_pipe_desc spd = {
+               .pages = pages,
+               .nr_pages = 0,
+               .partial = partial,
+               .flags = flags,
+               .ops = &relay_pipe_buf_ops,
+       };
 
        if (rbuf->subbufs_produced == rbuf->subbufs_consumed)
                return 0;
 
-       if (len > avail)
-               len = avail;
-
-       if (pipe->inode)
-               mutex_lock(&pipe->inode->i_mutex);
+       /*
+        * Adjust read len, if longer than what is available
+        */
+       if (len > (subbuf_size - read_start % subbuf_size))
+               len = subbuf_size - read_start % subbuf_size;
 
        subbuf_pages = rbuf->chan->alloc_size >> PAGE_SHIFT;
        pidx = (read_start / PAGE_SIZE) % subbuf_pages;
        poff = read_start & ~PAGE_MASK;
 
-       for (;;) {
-               unsigned int this_len;
-               unsigned int this_end;
-               int newbuf = (pipe->curbuf + pipe->nrbufs) & (PIPE_BUFFERS - 1);
-               struct pipe_buffer *buf = pipe->bufs + newbuf;
+       for (total_len = 0; spd.nr_pages < subbuf_pages; spd.nr_pages++) {
+               unsigned int this_len, this_end, private;
+               unsigned int cur_pos = read_start + total_len;
 
-               if (!pipe->readers) {
-                       send_sig(SIGPIPE, current, 0);
-                       if (!ret)
-                               ret = -EPIPE;
+               if (!len)
                        break;
-               }
-
-               if (pipe->nrbufs < PIPE_BUFFERS) {
-                       this_len = PAGE_SIZE - poff;
-                       if (this_len > avail)
-                               this_len = avail;
-
-                       buf->page = rbuf->page_array[pidx];
-                       buf->offset = poff;
-                       this_end = read_start + ret + this_len;
-                       if (this_end > nonpad_end) {
-                               if (read_start + ret >= nonpad_end)
-                                       buf->len = 0;
-                               else
-                                       buf->len = nonpad_end - (read_start + ret);
-                       } else
-                               buf->len = this_len;
-
-                       *nonpad_ret += buf->len;
 
-                       buf->ops = &relay_pipe_buf_ops;
-                       pipe->nrbufs++;
+               this_len = min_t(unsigned long, len, PAGE_SIZE - poff);
+               private = this_len;
 
-                       avail -= this_len;
-                       ret += this_len;
-                       poff = 0;
-                       pidx = (pidx + 1) % subbuf_pages;
+               spd.pages[spd.nr_pages] = rbuf->page_array[pidx];
+               spd.partial[spd.nr_pages].offset = poff;
 
-                       if (pipe->inode)
-                               do_wakeup = 1;
-
-                       if (!avail)
-                               break;
-
-                       if (pipe->nrbufs < PIPE_BUFFERS)
-                               continue;
-
-                       break;
+               this_end = cur_pos + this_len;
+               if (this_end >= nonpad_end) {
+                       this_len = nonpad_end - cur_pos;
+                       private = this_len + padding;
                }
+               spd.partial[spd.nr_pages].len = this_len;
+               spd.partial[spd.nr_pages].private = private;
 
-               if (flags & SPLICE_F_NONBLOCK) {
-                       if (!ret)
-                               ret = -EAGAIN;
-                       break;
-               }
+               len -= this_len;
+               total_len += this_len;
+               poff = 0;
+               pidx = (pidx + 1) % subbuf_pages;
 
-               if (signal_pending(current)) {
-                       if (!ret)
-                               ret = -ERESTARTSYS;
+               if (this_end >= nonpad_end) {
+                       spd.nr_pages++;
                        break;
                }
-
-               if (do_wakeup) {
-                       smp_mb();
-                       if (waitqueue_active(&pipe->wait))
-                               wake_up_interruptible_sync(&pipe->wait);
-                       kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
-                       do_wakeup = 0;
-               }
-
-               pipe->waiting_writers++;
-               pipe_wait(pipe);
-               pipe->waiting_writers--;
        }
 
-       if (pipe->inode)
-               mutex_unlock(&pipe->inode->i_mutex);
+       if (!spd.nr_pages)
+               return 0;
 
-       if (do_wakeup) {
-               smp_mb();
-               if (waitqueue_active(&pipe->wait))
-                       wake_up_interruptible(&pipe->wait);
-               kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
-       }
+       ret = *nonpad_ret = splice_to_pipe(pipe, &spd);
+       if (ret < 0 || ret < total_len)
+               return ret;
 
-       return ret;
+        if (read_start + ret == nonpad_end)
+                ret += padding;
+
+        return ret;
 }
 
 static ssize_t relay_file_splice_read(struct file *in,
@@ -1199,7 +1166,6 @@ static ssize_t relay_file_splice_read(struct file *in,
                if (ret < 0)
                        break;
                else if (!ret) {
-                       break;
                        if (spliced)
                                break;
                        if (flags & SPLICE_F_NONBLOCK) {