Commit | Line | Data |
---|---|---|
1c8284eb MD |
1 | /* |
2 | * ltt/ltt-relay-vfs.c | |
3 | * | |
4 | * (C) Copyright 2009 - Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca) | |
5 | * | |
6 | * LTTng VFS interface. | |
7 | * | |
8 | * Author: | |
9 | * Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca) | |
10 | * | |
11 | * Dual LGPL v2.1/GPL v2 license. | |
12 | */ | |
13 | ||
14 | #include <linux/module.h> | |
15 | #include <linux/fs.h> | |
16 | #include <linux/debugfs.h> | |
17 | #include <linux/ltt-channels.h> | |
18 | #include <asm/atomic.h> | |
19 | ||
20 | #include "ltt-tracer.h" | |
21 | #include "ltt-relay.h" | |
22 | #include "ltt-relay-lockless.h" | |
23 | ||
24 | /** | |
25 | * ltt_open - open file op for ltt files | |
26 | * @inode: opened inode | |
27 | * @file: opened file | |
28 | * | |
29 | * Open implementation. Makes sure only one open instance of a buffer is | |
30 | * done at a given moment. | |
31 | */ | |
32 | static int ltt_open(struct inode *inode, struct file *file) | |
33 | { | |
34 | struct ltt_chanbuf *buf = inode->i_private; | |
35 | int ret; | |
36 | ||
37 | ret = ltt_chanbuf_open_read(buf); | |
38 | if (ret) | |
39 | goto end; | |
40 | ||
41 | file->private_data = buf; | |
42 | ret = nonseekable_open(inode, file); | |
43 | /* | |
44 | * Let LTTng splice operation must believe that the file descriptor is | |
45 | * seekable. This is a temporary fix to follow new checks added to | |
46 | * splice.c. We should probably do the proper thing and implement a | |
47 | * llseek function eventually, which involves modifying the lttng splice | |
48 | * actors accordingly. TODO | |
49 | */ | |
50 | file->f_mode |= FMODE_PREAD; | |
51 | end: | |
52 | return ret; | |
53 | } | |
54 | ||
55 | /** | |
56 | * ltt_release - release file op for ltt files | |
57 | * @inode: opened inode | |
58 | * @file: opened file | |
59 | * | |
60 | * Release implementation. | |
61 | */ | |
62 | static int ltt_release(struct inode *inode, struct file *file) | |
63 | { | |
64 | struct ltt_chanbuf *buf = inode->i_private; | |
65 | ||
66 | ltt_chanbuf_release_read(buf); | |
67 | ||
68 | return 0; | |
69 | } | |
70 | ||
71 | /** | |
72 | * ltt_poll - file op for ltt files | |
73 | * @filp: the file | |
74 | * @wait: poll table | |
75 | * | |
76 | * Poll implementation. | |
77 | */ | |
78 | static unsigned int ltt_poll(struct file *filp, poll_table *wait) | |
79 | { | |
80 | unsigned int mask = 0; | |
81 | struct inode *inode = filp->f_dentry->d_inode; | |
82 | struct ltt_chanbuf *buf = inode->i_private; | |
83 | struct ltt_chan *chan = container_of(buf->a.chan, struct ltt_chan, a); | |
84 | ||
85 | if (filp->f_mode & FMODE_READ) { | |
86 | poll_wait_set_exclusive(wait); | |
87 | poll_wait(filp, &buf->read_wait, wait); | |
88 | ||
89 | WARN_ON(atomic_long_read(&buf->active_readers) != 1); | |
90 | if (SUBBUF_TRUNC(ltt_chanbuf_get_offset(buf), chan) | |
91 | - SUBBUF_TRUNC(ltt_chanbuf_get_consumed(buf), chan) | |
92 | == 0) { | |
93 | if (buf->finalized) | |
94 | return POLLHUP; | |
95 | else | |
96 | return 0; | |
97 | } else { | |
98 | if (SUBBUF_TRUNC(ltt_chanbuf_get_offset(buf), chan) | |
99 | - SUBBUF_TRUNC(ltt_chanbuf_get_consumed(buf), chan) | |
100 | >= chan->a.buf_size) | |
101 | return POLLPRI | POLLRDBAND; | |
102 | else | |
103 | return POLLIN | POLLRDNORM; | |
104 | } | |
105 | } | |
106 | return mask; | |
107 | } | |
108 | ||
109 | /** | |
110 | * ltt_ioctl - control on the debugfs file | |
111 | * | |
112 | * @inode: the inode | |
113 | * @filp: the file | |
114 | * @cmd: the command | |
115 | * @arg: command arg | |
116 | * | |
117 | * This ioctl implements three commands necessary for a minimal | |
118 | * producer/consumer implementation : | |
119 | * RELAY_GET_SB | |
120 | * Get the next sub-buffer that can be read. It never blocks. | |
121 | * RELAY_PUT_SB | |
122 | * Release the currently read sub-buffer. Parameter is the last | |
123 | * put subbuffer (returned by GET_SUBBUF). | |
124 | * RELAY_GET_N_SB | |
125 | * returns the number of sub-buffers in the per cpu channel. | |
126 | * RELAY_GET_SB_SIZE | |
127 | * returns the size of the current sub-buffer. | |
128 | * RELAY_GET_MAX_SB_SIZE | |
129 | * returns the maximum size for sub-buffers. | |
130 | */ | |
131 | static | |
132 | int ltt_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |
133 | unsigned long arg) | |
134 | { | |
135 | struct ltt_chanbuf *buf = inode->i_private; | |
136 | u32 __user *argp = (u32 __user *)arg; | |
137 | ||
138 | switch (cmd) { | |
139 | case RELAY_GET_SB: | |
140 | { | |
141 | unsigned long consumed; | |
142 | int ret; | |
143 | ||
144 | ret = ltt_chanbuf_get_subbuf(buf, &consumed); | |
145 | if (ret) | |
146 | return ret; | |
147 | else | |
148 | return put_user((u32)consumed, argp); | |
149 | break; | |
150 | } | |
151 | case RELAY_PUT_SB: | |
152 | { | |
153 | u32 uconsumed_old; | |
154 | int ret; | |
155 | long consumed_old; | |
156 | ||
157 | ret = get_user(uconsumed_old, argp); | |
158 | if (ret) | |
159 | return ret; /* will return -EFAULT */ | |
160 | ||
161 | consumed_old = ltt_chanbuf_get_consumed(buf); | |
162 | consumed_old = consumed_old & (~0xFFFFFFFFL); | |
163 | consumed_old = consumed_old | uconsumed_old; | |
164 | ret = ltt_chanbuf_put_subbuf(buf, consumed_old); | |
165 | if (ret) | |
166 | return ret; | |
167 | break; | |
168 | } | |
169 | case RELAY_GET_N_SB: | |
170 | return put_user((u32)buf->a.chan->n_sb, argp); | |
171 | break; | |
172 | case RELAY_GET_SB_SIZE: | |
173 | return put_user(get_read_sb_size(buf), argp); | |
174 | break; | |
175 | case RELAY_GET_MAX_SB_SIZE: | |
176 | return put_user((u32)buf->a.chan->sb_size, argp); | |
177 | break; | |
178 | default: | |
179 | return -ENOIOCTLCMD; | |
180 | } | |
181 | return 0; | |
182 | } | |
183 | ||
184 | #ifdef CONFIG_COMPAT | |
185 | static | |
186 | long ltt_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |
187 | { | |
188 | long ret = -ENOIOCTLCMD; | |
189 | ||
190 | lock_kernel(); | |
191 | ret = ltt_ioctl(file->f_dentry->d_inode, file, cmd, arg); | |
192 | unlock_kernel(); | |
193 | ||
194 | return ret; | |
195 | } | |
196 | #endif | |
197 | ||
198 | static const struct file_operations ltt_file_operations = { | |
199 | .open = ltt_open, | |
200 | .release = ltt_release, | |
201 | .poll = ltt_poll, | |
202 | .splice_read = ltt_relay_file_splice_read, | |
203 | .ioctl = ltt_ioctl, | |
204 | .llseek = ltt_relay_no_llseek, | |
205 | #ifdef CONFIG_COMPAT | |
206 | .compat_ioctl = ltt_compat_ioctl, | |
207 | #endif | |
208 | }; | |
209 | ||
210 | int ltt_chanbuf_create_file(const char *filename, struct dentry *parent, | |
211 | int mode, struct ltt_chanbuf *buf) | |
212 | { | |
213 | struct ltt_chan *chan = container_of(buf->a.chan, struct ltt_chan, a); | |
214 | char *tmpname; | |
215 | int ret = 0; | |
216 | ||
217 | tmpname = kzalloc(NAME_MAX + 1, GFP_KERNEL); | |
218 | if (!tmpname) { | |
219 | ret = -ENOMEM; | |
220 | goto end; | |
221 | } | |
222 | ||
223 | snprintf(tmpname, NAME_MAX, "%s%s_%d", | |
224 | chan->overwrite ? LTT_FLIGHT_PREFIX : "", | |
225 | chan->a.filename, buf->a.cpu); | |
226 | ||
227 | buf->a.dentry = debugfs_create_file(tmpname, mode, parent, buf, | |
228 | <t_file_operations); | |
229 | if (!buf->a.dentry) { | |
230 | ret = -ENOMEM; | |
231 | goto free_name; | |
232 | } | |
233 | free_name: | |
234 | kfree(tmpname); | |
235 | end: | |
236 | return ret; | |
237 | } | |
238 | ||
239 | int ltt_chanbuf_remove_file(struct ltt_chanbuf *buf) | |
240 | { | |
241 | debugfs_remove(buf->a.dentry); | |
242 | ||
243 | return 0; | |
244 | } |