2 * include/linux/ltt-relay.h
4 * Copyright (C) 2008,2009 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
6 * Dual LGPL v2.1/GPL v2 license.
8 * Credits to Steven Rostedt for proposing to use an extra-subbuffer owned by
9 * the reader in flight recorder mode.
12 #ifndef _LINUX_LTT_RELAY_H
13 #define _LINUX_LTT_RELAY_H
15 #include <linux/types.h>
16 #include <linux/sched.h>
17 #include <linux/timer.h>
18 #include <linux/wait.h>
20 #include <linux/poll.h>
21 #include <linux/kref.h>
23 #include <linux/ltt-channels.h>
25 #include "ltt-tracer-core.h"
27 /* Use lowest pointer bit to show the sub-buffer has no reference. */
28 #define RCHAN_NOREF_FLAG 0x1UL
30 #define RCHAN_SB_IS_NOREF(x) ((unsigned long)(x) & RCHAN_NOREF_FLAG)
31 #define RCHAN_SB_SET_NOREF(x) \
32 (x = (struct chanbuf_page *)((unsigned long)(x) | RCHAN_NOREF_FLAG))
33 #define RCHAN_SB_CLEAR_NOREF(x) \
34 (x = (struct chanbuf_page *)((unsigned long)(x) & ~RCHAN_NOREF_FLAG))
39 void *virt
; /* page virtual address (cached) */
40 struct page
*page
; /* pointer to page structure */
44 struct chanbuf_page
*pages
; /* Pointer to rchan pages for subbuf */
47 struct ltt_chanbuf_alloc
{
48 struct chanbuf_sb
*buf_wsb
; /* Array of rchan_sb for writer */
49 struct chanbuf_sb buf_rsb
; /* chanbuf_sb for reader */
50 void **_virt
; /* Array of pointers to page addr */
51 struct page
**_pages
; /* Array of pointers to pages */
52 struct dentry
*dentry
; /* Associated file dentry */
53 unsigned int nr_pages
; /* Number pages in buffer */
55 struct ltt_chan_alloc
*chan
; /* Associated channel */
56 unsigned int cpu
; /* This buffer's cpu */
57 unsigned int allocated
:1; /* Bool: is buffer allocated ? */
60 int ltt_chanbuf_alloc_create(struct ltt_chanbuf_alloc
*buf
,
61 struct ltt_chan_alloc
*chan
, int cpu
);
62 void ltt_chanbuf_alloc_free(struct ltt_chanbuf_alloc
*buf
);
63 int ltt_chan_alloc_init(struct ltt_chan_alloc
*chan
, struct ltt_trace
*trace
,
64 const char *base_filename
,
65 struct dentry
*parent
, size_t sb_size
,
66 size_t n_sb
, int extra_reader_sb
, int overwrite
);
67 void ltt_chan_alloc_free(struct ltt_chan_alloc
*chan
);
68 void ltt_chan_alloc_remove_files(struct ltt_chan_alloc
*chan
);
69 int ltt_chanbuf_create_file(const char *filename
, struct dentry
*parent
,
70 int mode
, struct ltt_chanbuf
*buf
);
71 int ltt_chanbuf_remove_file(struct ltt_chanbuf
*buf
);
73 void ltt_chan_for_each_channel(void (*cb
) (struct ltt_chanbuf
*buf
), int cpu
);
75 extern void _ltt_relay_write(struct ltt_chanbuf_alloc
*bufa
,
76 size_t offset
, const void *src
, size_t len
,
79 extern void _ltt_relay_strncpy(struct ltt_chanbuf_alloc
*bufa
,
80 size_t offset
, const void *src
, size_t len
,
83 extern void _ltt_relay_strncpy_fixup(struct ltt_chanbuf_alloc
*bufa
,
84 size_t offset
, size_t len
, size_t copied
,
87 extern int ltt_relay_read(struct ltt_chanbuf_alloc
*bufa
,
88 size_t offset
, void *dest
, size_t len
);
90 extern int ltt_relay_read_cstr(struct ltt_chanbuf_alloc
*bufa
,
91 size_t offset
, void *dest
, size_t len
);
93 extern struct page
*ltt_relay_read_get_page(struct ltt_chanbuf_alloc
*bufa
,
97 * Return the address where a given offset is located.
98 * Should be used to get the current subbuffer header pointer. Given we know
99 * it's never on a page boundary, it's safe to write directly to this address,
100 * as long as the write is never bigger than a page size.
102 extern void *ltt_relay_offset_address(struct ltt_chanbuf_alloc
*bufa
,
104 extern void *ltt_relay_read_offset_address(struct ltt_chanbuf_alloc
*bufa
,
107 #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
109 void ltt_relay_do_copy(void *dest
, const void *src
, size_t len
)
115 *(u8
*)dest
= *(const u8
*)src
;
118 *(u16
*)dest
= *(const u16
*)src
;
121 *(u32
*)dest
= *(const u32
*)src
;
124 *(u64
*)dest
= *(const u64
*)src
;
128 * What we really want here is an __inline__ memcpy, but we don't
129 * have constants, so gcc generally uses a function call.
131 for (; len
> 0; len
--)
132 *(u8
*)dest
++ = *(const u8
*)src
++;
137 * Returns whether the dest and src addresses are aligned on
138 * min(sizeof(void *), len). Call this with statically known len for efficiency.
141 int addr_aligned(const void *dest
, const void *src
, size_t len
)
143 if (ltt_align((size_t)dest
, len
))
145 if (ltt_align((size_t)src
, len
))
151 void ltt_relay_do_copy(void *dest
, const void *src
, size_t len
)
157 *(u8
*)dest
= *(const u8
*)src
;
160 if (unlikely(!addr_aligned(dest
, src
, 2)))
161 goto memcpy_fallback
;
162 *(u16
*)dest
= *(const u16
*)src
;
165 if (unlikely(!addr_aligned(dest
, src
, 4)))
166 goto memcpy_fallback
;
167 *(u32
*)dest
= *(const u32
*)src
;
170 if (unlikely(!addr_aligned(dest
, src
, 8)))
171 goto memcpy_fallback
;
172 *(u64
*)dest
= *(const u64
*)src
;
175 goto memcpy_fallback
;
181 * What we really want here is an inline memcpy, but we don't
182 * have constants, so gcc generally uses a function call.
184 for (; len
> 0; len
--)
185 *(u8
*)dest
++ = *(const u8
*)src
++;
190 * ltt_relay_do_memset - write character into dest.
192 * @src: source character
193 * @len: length to write
196 void ltt_relay_do_memset(void *dest
, char src
, size_t len
)
199 * What we really want here is an __inline__ memset, but we
200 * don't have constants, so gcc generally uses a function call.
202 for (; len
> 0; len
--)
208 * ltt_relay_do_strncpy - copy a string up to a certain number of bytes
211 * @len: max. length to copy
212 * @terminated: output string ends with \0 (output)
214 * returns the number of bytes copied. Does not finalize with \0 if len is
218 size_t ltt_relay_do_strncpy(void *dest
, const void *src
, size_t len
,
221 size_t orig_len
= len
;
225 * What we really want here is an __inline__ strncpy, but we
226 * don't have constants, so gcc generally uses a function call.
228 for (; len
> 0; len
--) {
229 *(u8
*)dest
= ACCESS_ONCE(*(const u8
*)src
);
230 /* Check with dest, because src may be modified concurrently */
231 if (*(const u8
*)dest
== '\0') {
239 return orig_len
- len
;
243 int ltt_relay_write(struct ltt_chanbuf_alloc
*bufa
,
244 struct ltt_chan_alloc
*chana
, size_t offset
,
245 const void *src
, size_t len
)
249 struct chanbuf_page
*rpages
;
251 offset
&= chana
->buf_size
- 1;
252 sbidx
= offset
>> chana
->sb_size_order
;
253 index
= (offset
& (chana
->sb_size
- 1)) >> PAGE_SHIFT
;
254 pagecpy
= min_t(size_t, len
, (- offset
) & ~PAGE_MASK
);
255 rpages
= bufa
->buf_wsb
[sbidx
].pages
;
256 WARN_ON_ONCE(RCHAN_SB_IS_NOREF(rpages
));
257 ltt_relay_do_copy(rpages
[index
].virt
+ (offset
& ~PAGE_MASK
),
260 if (unlikely(len
!= pagecpy
))
261 _ltt_relay_write(bufa
, offset
, src
, len
, pagecpy
);
266 int ltt_relay_strncpy(struct ltt_chanbuf_alloc
*bufa
,
267 struct ltt_chan_alloc
*chana
, size_t offset
,
268 const void *src
, size_t len
)
271 ssize_t pagecpy
, copied
;
272 struct chanbuf_page
*rpages
;
275 offset
&= chana
->buf_size
- 1;
276 sbidx
= offset
>> chana
->sb_size_order
;
277 index
= (offset
& (chana
->sb_size
- 1)) >> PAGE_SHIFT
;
278 pagecpy
= min_t(size_t, len
, (- offset
) & ~PAGE_MASK
);
279 rpages
= bufa
->buf_wsb
[sbidx
].pages
;
280 WARN_ON_ONCE(RCHAN_SB_IS_NOREF(rpages
));
281 copied
= ltt_relay_do_strncpy(rpages
[index
].virt
282 + (offset
& ~PAGE_MASK
),
283 src
, pagecpy
, &terminated
);
284 if (unlikely(copied
< pagecpy
|| ((len
== pagecpy
) && !terminated
)))
285 _ltt_relay_strncpy_fixup(bufa
, offset
, len
, copied
,
288 if (unlikely(len
!= pagecpy
))
289 _ltt_relay_strncpy(bufa
, offset
, src
, len
, pagecpy
);
295 * ltt_clear_noref_flag - Clear the noref subbuffer flag, for writer.
298 void ltt_clear_noref_flag(struct ltt_chanbuf_alloc
*bufa
, long idx
)
300 struct chanbuf_page
*sb_pages
, *new_sb_pages
;
302 sb_pages
= bufa
->buf_wsb
[idx
].pages
;
304 if (!RCHAN_SB_IS_NOREF(sb_pages
))
305 return; /* Already writing to this buffer */
306 new_sb_pages
= sb_pages
;
307 RCHAN_SB_CLEAR_NOREF(new_sb_pages
);
308 new_sb_pages
= cmpxchg(&bufa
->buf_wsb
[idx
].pages
,
309 sb_pages
, new_sb_pages
);
310 if (likely(new_sb_pages
== sb_pages
))
312 sb_pages
= new_sb_pages
;
317 * ltt_set_noref_flag - Set the noref subbuffer flag, for writer.
320 void ltt_set_noref_flag(struct ltt_chanbuf_alloc
*bufa
, long idx
)
322 struct chanbuf_page
*sb_pages
, *new_sb_pages
;
324 sb_pages
= bufa
->buf_wsb
[idx
].pages
;
326 if (RCHAN_SB_IS_NOREF(sb_pages
))
327 return; /* Already set */
328 new_sb_pages
= sb_pages
;
329 RCHAN_SB_SET_NOREF(new_sb_pages
);
330 new_sb_pages
= cmpxchg(&bufa
->buf_wsb
[idx
].pages
,
331 sb_pages
, new_sb_pages
);
332 if (likely(new_sb_pages
== sb_pages
))
334 sb_pages
= new_sb_pages
;
339 * update_read_sb_index - Read-side subbuffer index update.
342 int update_read_sb_index(struct ltt_chanbuf_alloc
*bufa
,
343 struct ltt_chan_alloc
*chana
,
346 struct chanbuf_page
*old_wpage
, *new_wpage
;
348 if (unlikely(chana
->extra_reader_sb
)) {
350 * Exchange the target writer subbuffer with our own unused
353 old_wpage
= bufa
->buf_wsb
[consumed_idx
].pages
;
354 if (unlikely(!RCHAN_SB_IS_NOREF(old_wpage
)))
356 WARN_ON_ONCE(!RCHAN_SB_IS_NOREF(bufa
->buf_rsb
.pages
));
357 new_wpage
= cmpxchg(&bufa
->buf_wsb
[consumed_idx
].pages
,
359 bufa
->buf_rsb
.pages
);
360 if (unlikely(old_wpage
!= new_wpage
))
362 bufa
->buf_rsb
.pages
= new_wpage
;
363 RCHAN_SB_CLEAR_NOREF(bufa
->buf_rsb
.pages
);
365 /* No page exchange, use the writer page directly */
366 bufa
->buf_rsb
.pages
= bufa
->buf_wsb
[consumed_idx
].pages
;
367 RCHAN_SB_CLEAR_NOREF(bufa
->buf_rsb
.pages
);
372 ssize_t
ltt_relay_file_splice_read(struct file
*in
, loff_t
*ppos
,
373 struct pipe_inode_info
*pipe
, size_t len
,
375 loff_t
ltt_relay_no_llseek(struct file
*file
, loff_t offset
, int origin
);
377 extern int ltt_ascii_init(void);
378 extern void ltt_ascii_exit(void);
380 #endif /* _LINUX_LTT_RELAY_H */
This page took 0.075145 seconds and 5 git commands to generate.