Commit | Line | Data |
---|---|---|
1c8284eb MD |
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 = <t_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 | } |