]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/relay.c
pxafb: introduce lcd_{read,write}l() to wrap the __raw_{read,write}l()
[linux-2.6-omap-h63xx.git] / kernel / relay.c
index a615a8f513fc890eaa1a11a34ae5e08c78895bba..7de644cdec43590be390d3037206e5722aa46856 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)
@@ -37,40 +37,63 @@ static void relay_file_mmap_close(struct vm_area_struct *vma)
 }
 
 /*
- * nopage() vm_op implementation for relay file mapping.
+ * fault() vm_op implementation for relay file mapping.
  */
-static struct page *relay_buf_nopage(struct vm_area_struct *vma,
-                                    unsigned long address,
-                                    int *type)
+static int relay_buf_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct page *page;
        struct rchan_buf *buf = vma->vm_private_data;
-       unsigned long offset = address - vma->vm_start;
+       pgoff_t pgoff = vmf->pgoff;
 
-       if (address > vma->vm_end)
-               return NOPAGE_SIGBUS; /* Disallow mremap */
        if (!buf)
-               return NOPAGE_OOM;
+               return VM_FAULT_OOM;
 
-       page = vmalloc_to_page(buf->start + offset);
+       page = vmalloc_to_page(buf->start + (pgoff << PAGE_SHIFT));
        if (!page)
-               return NOPAGE_OOM;
+               return VM_FAULT_SIGBUS;
        get_page(page);
+       vmf->page = page;
 
-       if (type)
-               *type = VM_FAULT_MINOR;
-
-       return page;
+       return 0;
 }
 
 /*
  * vm_ops for relay file mappings.
  */
 static struct vm_operations_struct relay_file_mmap_ops = {
-       .nopage = relay_buf_nopage,
+       .fault = relay_buf_fault,
        .close = relay_file_mmap_close,
 };
 
+/*
+ * allocate an array of pointers of struct page
+ */
+static struct page **relay_alloc_page_array(unsigned int n_pages)
+{
+       struct page **array;
+       size_t pa_size = n_pages * sizeof(struct page *);
+
+       if (pa_size > PAGE_SIZE) {
+               array = vmalloc(pa_size);
+               if (array)
+                       memset(array, 0, pa_size);
+       } else {
+               array = kzalloc(pa_size, GFP_KERNEL);
+       }
+       return array;
+}
+
+/*
+ * free an array of pointers of struct page
+ */
+static void relay_free_page_array(struct page **array)
+{
+       if (is_vmalloc_addr(array))
+               vfree(array);
+       else
+               kfree(array);
+}
+
 /**
  *     relay_mmap_buf: - mmap channel buffer to process address space
  *     @buf: relay channel buffer
@@ -80,7 +103,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;
@@ -92,6 +115,7 @@ int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma)
                return -EINVAL;
 
        vma->vm_ops = &relay_file_mmap_ops;
+       vma->vm_flags |= VM_DONTEXPAND;
        vma->vm_private_data = buf;
        buf->chan->cb->buf_mapped(buf, filp);
 
@@ -114,7 +138,7 @@ static void *relay_alloc_buf(struct rchan_buf *buf, size_t *size)
        *size = PAGE_ALIGN(*size);
        n_pages = *size >> PAGE_SHIFT;
 
-       buf->page_array = kcalloc(n_pages, sizeof(struct page *), GFP_KERNEL);
+       buf->page_array = relay_alloc_page_array(n_pages);
        if (!buf->page_array)
                return NULL;
 
@@ -135,7 +159,7 @@ static void *relay_alloc_buf(struct rchan_buf *buf, size_t *size)
 depopulate:
        for (j = 0; j < i; j++)
                __free_page(buf->page_array[j]);
-       kfree(buf->page_array);
+       relay_free_page_array(buf->page_array);
        return NULL;
 }
 
@@ -145,7 +169,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 +199,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 +209,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;
@@ -194,7 +218,7 @@ void relay_destroy_buf(struct rchan_buf *buf)
                vunmap(buf->start);
                for (i = 0; i < buf->page_count; i++)
                        __free_page(buf->page_array[i]);
-               kfree(buf->page_array);
+               relay_free_page_array(buf->page_array);
        }
        chan->buf[buf->cpu] = NULL;
        kfree(buf->padding);
@@ -210,7 +234,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 +247,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?
@@ -371,7 +394,7 @@ void relay_reset(struct rchan *chan)
        if (!chan)
                return;
 
-       if (chan->is_global && chan->buf[0]) {
+       if (chan->is_global && chan->buf[0]) {
                __relay_reset(chan->buf[0], 0);
                return;
        }
@@ -427,6 +450,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:
@@ -741,7 +765,7 @@ static int relay_file_open(struct inode *inode, struct file *filp)
        kref_get(&buf->kref);
        filp->private_data = buf;
 
-       return 0;
+       return nonseekable_open(inode, filp);
 }
 
 /**
@@ -850,13 +874,13 @@ static int relay_file_read_avail(struct rchan_buf *buf, size_t read_pos)
                buf->subbufs_consumed = consumed;
                buf->bytes_consumed = 0;
        }
-       
+
        produced = (produced % n_subbufs) * subbuf_size + buf->offset;
        consumed = (consumed % n_subbufs) * subbuf_size + buf->bytes_consumed;
 
        if (consumed > produced)
                produced += n_subbufs * subbuf_size;
-       
+
        if (consumed == produced)
                return 0;
 
@@ -1061,6 +1085,10 @@ static struct pipe_buf_operations relay_pipe_buf_ops = {
        .get = generic_pipe_buf_get,
 };
 
+static void relay_page_release(struct splice_pipe_desc *spd, unsigned int i)
+{
+}
+
 /*
  *     subbuf_splice_actor - splice up to one subbuf's worth of data
  */
@@ -1071,7 +1099,7 @@ static int subbuf_splice_actor(struct file *in,
                               unsigned int flags,
                               int *nonpad_ret)
 {
-       unsigned int pidx, poff, total_len, subbuf_pages, ret;
+       unsigned int pidx, poff, total_len, subbuf_pages, nr_pages, ret;
        struct rchan_buf *rbuf = in->private_data;
        unsigned int subbuf_size = rbuf->chan->subbuf_size;
        uint64_t pos = (uint64_t) *ppos;
@@ -1088,6 +1116,7 @@ static int subbuf_splice_actor(struct file *in,
                .partial = partial,
                .flags = flags,
                .ops = &relay_pipe_buf_ops,
+               .spd_release = relay_page_release,
        };
 
        if (rbuf->subbufs_produced == rbuf->subbufs_consumed)
@@ -1102,8 +1131,9 @@ static int subbuf_splice_actor(struct file *in,
        subbuf_pages = rbuf->chan->alloc_size >> PAGE_SHIFT;
        pidx = (read_start / PAGE_SIZE) % subbuf_pages;
        poff = read_start & ~PAGE_MASK;
+       nr_pages = min_t(unsigned int, subbuf_pages, PIPE_BUFFERS);
 
-       for (total_len = 0; spd.nr_pages < subbuf_pages; spd.nr_pages++) {
+       for (total_len = 0; spd.nr_pages < nr_pages; spd.nr_pages++) {
                unsigned int this_len, this_end, private;
                unsigned int cur_pos = read_start + total_len;
 
@@ -1161,7 +1191,7 @@ static ssize_t relay_file_splice_read(struct file *in,
        ret = 0;
        spliced = 0;
 
-       while (len) {
+       while (len && !spliced) {
                ret = subbuf_splice_actor(in, ppos, pipe, len, flags, &nonpad_ret);
                if (ret < 0)
                        break;