lttng-modules v0.19-stable: setup_trace_write: Fix recursive locking
[lttng-modules.git] / ltt-relay-splice.c
1 /*
2 * Copyright (C) 2002-2005 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
3 * Copyright (C) 1999-2005 - Karim Yaghmour (karim@opersys.com)
4 * Copyright (C) 2008-2009 - Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
5 *
6 * Re-using content from kernel/relay.c
7 *
8 * This file is released under the GPL.
9 */
10
11 #include <linux/errno.h>
12 #include <linux/stddef.h>
13 #include <linux/slab.h>
14 #include <linux/module.h>
15 #include <linux/string.h>
16 #include <linux/vmalloc.h>
17 #include <linux/mm.h>
18 #include <linux/cpu.h>
19 #include <linux/splice.h>
20 #include <linux/pipe_fs_i.h>
21 #include <linux/bitops.h>
22
23 #include "ltt-relay.h"
24 #include "ltt-relay-lockless.h"
25
26 loff_t ltt_relay_no_llseek(struct file *file, loff_t offset, int origin)
27 {
28 return -ESPIPE;
29 }
30
31 static void ltt_relay_pipe_buf_release(struct pipe_inode_info *pipe,
32 struct pipe_buffer *pbuf)
33 {
34 }
35
36 static struct pipe_buf_operations ltt_relay_pipe_buf_ops = {
37 .can_merge = 0,
38 .map = generic_pipe_buf_map,
39 .unmap = generic_pipe_buf_unmap,
40 .confirm = generic_pipe_buf_confirm,
41 .release = ltt_relay_pipe_buf_release,
42 .steal = generic_pipe_buf_steal,
43 .get = generic_pipe_buf_get,
44 };
45
46 static void ltt_relay_page_release(struct splice_pipe_desc *spd, unsigned int i)
47 {
48 }
49
50 /*
51 * subbuf_splice_actor - splice up to one subbuf's worth of data
52 */
53 static int subbuf_splice_actor(struct file *in,
54 loff_t *ppos,
55 struct pipe_inode_info *pipe,
56 size_t len,
57 unsigned int flags)
58 {
59 struct ltt_chanbuf *buf = in->private_data;
60 struct ltt_chan *chan = container_of(buf->a.chan, struct ltt_chan, a);
61 unsigned int poff, subbuf_pages, nr_pages;
62 struct page *pages[PIPE_DEF_BUFFERS];
63 struct partial_page partial[PIPE_DEF_BUFFERS];
64 struct splice_pipe_desc spd = {
65 .pages = pages,
66 .nr_pages = 0,
67 .partial = partial,
68 .flags = flags,
69 .ops = &ltt_relay_pipe_buf_ops,
70 .spd_release = ltt_relay_page_release,
71 };
72 long consumed_old, consumed_idx, roffset;
73 unsigned long bytes_avail;
74
75 /*
76 * Check that a GET_SUBBUF ioctl has been done before.
77 */
78 WARN_ON(atomic_long_read(&buf->active_readers) != 1);
79 consumed_old = atomic_long_read(&buf->consumed);
80 consumed_old += *ppos;
81 consumed_idx = SUBBUF_INDEX(consumed_old, chan);
82
83 /*
84 * Adjust read len, if longer than what is available.
85 * Max read size is 1 subbuffer due to get_subbuf/put_subbuf for
86 * protection.
87 */
88 bytes_avail = chan->a.sb_size;
89 WARN_ON(bytes_avail > chan->a.buf_size);
90 len = min_t(size_t, len, bytes_avail);
91 subbuf_pages = bytes_avail >> PAGE_SHIFT;
92 nr_pages = min_t(unsigned int, subbuf_pages, PIPE_DEF_BUFFERS);
93 roffset = consumed_old & PAGE_MASK;
94 poff = consumed_old & ~PAGE_MASK;
95 printk_dbg(KERN_DEBUG "SPLICE actor len %zu pos %zd write_pos %ld\n",
96 len, (ssize_t)*ppos, local_read(&buf->offset));
97
98 for (; spd.nr_pages < nr_pages; spd.nr_pages++) {
99 unsigned int this_len;
100 struct page *page;
101
102 if (!len)
103 break;
104 printk_dbg(KERN_DEBUG "SPLICE actor loop len %zu roffset %ld\n",
105 len, roffset);
106
107 this_len = PAGE_SIZE - poff;
108 page = ltt_relay_read_get_page(&buf->a, roffset);
109 spd.pages[spd.nr_pages] = page;
110 spd.partial[spd.nr_pages].offset = poff;
111 spd.partial[spd.nr_pages].len = this_len;
112
113 poff = 0;
114 roffset += PAGE_SIZE;
115 len -= this_len;
116 }
117
118 if (!spd.nr_pages)
119 return 0;
120
121 return splice_to_pipe(pipe, &spd);
122 }
123
124 ssize_t ltt_relay_file_splice_read(struct file *in, loff_t *ppos,
125 struct pipe_inode_info *pipe, size_t len,
126 unsigned int flags)
127 {
128 ssize_t spliced;
129 int ret;
130
131 ret = 0;
132 spliced = 0;
133
134 printk_dbg(KERN_DEBUG "SPLICE read len %zu pos %zd\n", len,
135 (ssize_t)*ppos);
136 while (len && !spliced) {
137 ret = subbuf_splice_actor(in, ppos, pipe, len, flags);
138 printk_dbg(KERN_DEBUG "SPLICE read loop ret %d\n", ret);
139 if (ret < 0)
140 break;
141 else if (!ret) {
142 if (flags & SPLICE_F_NONBLOCK)
143 ret = -EAGAIN;
144 break;
145 }
146
147 *ppos += ret;
148 if (ret > len)
149 len = 0;
150 else
151 len -= ret;
152 spliced += ret;
153 }
154
155 if (spliced)
156 return spliced;
157
158 return ret;
159 }
This page took 0.032147 seconds and 4 git commands to generate.