aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorTom Zanussi <zanussi@us.ibm.com>2005-09-06 18:16:30 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-07 19:57:18 -0400
commite82894f84dbba130ab46c97748c03647f8204f92 (patch)
treedbf20825db44037f0db5d0696d43457292c546c3 /include/linux
parent8446f1d391f3d27e6bf9c43d4cbcdac0ca720417 (diff)
[PATCH] relayfs
Here's the latest version of relayfs, against linux-2.6.11-mm2. I'm hoping you'll consider putting this version back into your tree - the previous rounds of comment seem to have shaken out all the API issues and the number of comments on the code itself have also steadily dwindled. This patch is essentially the same as the relayfs redux part 5 patch, with some minor changes based on reviewer comments. Thanks again to Pekka Enberg for those. The patch size without documentation is now a little smaller at just over 40k. Here's a detailed list of the changes: - removed the attribute_flags in relay open and changed it to a boolean specifying either overwrite or no-overwrite mode, and removed everything referencing the attribute flags. - added a check for NULL names in relayfs_create_entry() - got rid of the unnecessary multiple labels in relay_create_buf() - some minor simplification of relay_alloc_buf() which got rid of a couple params - updated the Documentation In addition, this version (through code contained in the relay-apps tarball linked to below, not as part of the relayfs patch) tries to make it as easy as possible to create the cooperating kernel/user pieces of a typical and common type of logging application, one where kernel logging is kicked off when a user space data collection app starts and stops when the collection app exits, with the data being automatically logged to disk in between. To create this type of application, you basically just include a header file (relay-app.h, included in the relay-apps tarball) in your kernel module, define a couple of callbacks and call an initialization function, and on the user side call a single function that sets up and continuously monitors the buffers, and writes data to files as it becomes available. Channels are created when the collection app is started and destroyed when it exits, not when the kernel module is inserted, so different channel buffer sizes can be specified for each separate run via command-line options. See the README in the relay-apps tarball for details. Also included in the relay-apps tarball are a couple examples demonstrating how you can use this to create quick and dirty kernel logging/debugging applications. They are: - tprintk, short for 'tee printk', which temporarily puts a kprobe on printk() and writes a duplicate stream of printk output to a relayfs channel. This could be used anywhere there's printk() debugging code in the kernel which you'd like to exercise, but would rather not have your system logs cluttered with debugging junk. You'd probably want to kill klogd while you do this, otherwise there wouldn't be much point (since putting a kprobe on printk() doesn't change the output of printk()). I've used this method to temporarily divert the packet logging output of the iptables LOG target from the system logs to relayfs files instead, for instance. - klog, which just provides a printk-like formatted logging function on top of relayfs. Again, you can use this to keep stuff out of your system logs if used in place of printk. The example applications can be found here: http://prdownloads.sourceforge.net/dprobes/relay-apps.tar.gz?download From: Christoph Hellwig <hch@lst.de> avoid lookup_hash usage in relayfs Signed-off-by: Tom Zanussi <zanussi@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/relayfs_fs.h255
1 files changed, 255 insertions, 0 deletions
diff --git a/include/linux/relayfs_fs.h b/include/linux/relayfs_fs.h
new file mode 100644
index 000000000000..cfafc3e76bc2
--- /dev/null
+++ b/include/linux/relayfs_fs.h
@@ -0,0 +1,255 @@
1/*
2 * linux/include/linux/relayfs_fs.h
3 *
4 * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
5 * Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com)
6 *
7 * RelayFS definitions and declarations
8 */
9
10#ifndef _LINUX_RELAYFS_FS_H
11#define _LINUX_RELAYFS_FS_H
12
13#include <linux/config.h>
14#include <linux/types.h>
15#include <linux/sched.h>
16#include <linux/wait.h>
17#include <linux/list.h>
18#include <linux/fs.h>
19#include <linux/poll.h>
20#include <linux/kref.h>
21
22/*
23 * Tracks changes to rchan_buf struct
24 */
25#define RELAYFS_CHANNEL_VERSION 5
26
27/*
28 * Per-cpu relay channel buffer
29 */
30struct rchan_buf
31{
32 void *start; /* start of channel buffer */
33 void *data; /* start of current sub-buffer */
34 size_t offset; /* current offset into sub-buffer */
35 size_t subbufs_produced; /* count of sub-buffers produced */
36 size_t subbufs_consumed; /* count of sub-buffers consumed */
37 struct rchan *chan; /* associated channel */
38 wait_queue_head_t read_wait; /* reader wait queue */
39 struct work_struct wake_readers; /* reader wake-up work struct */
40 struct dentry *dentry; /* channel file dentry */
41 struct kref kref; /* channel buffer refcount */
42 struct page **page_array; /* array of current buffer pages */
43 unsigned int page_count; /* number of current buffer pages */
44 unsigned int finalized; /* buffer has been finalized */
45 size_t *padding; /* padding counts per sub-buffer */
46 size_t prev_padding; /* temporary variable */
47 size_t bytes_consumed; /* bytes consumed in cur read subbuf */
48 unsigned int cpu; /* this buf's cpu */
49} ____cacheline_aligned;
50
51/*
52 * Relay channel data structure
53 */
54struct rchan
55{
56 u32 version; /* the version of this struct */
57 size_t subbuf_size; /* sub-buffer size */
58 size_t n_subbufs; /* number of sub-buffers per buffer */
59 size_t alloc_size; /* total buffer size allocated */
60 struct rchan_callbacks *cb; /* client callbacks */
61 struct kref kref; /* channel refcount */
62 void *private_data; /* for user-defined data */
63 struct rchan_buf *buf[NR_CPUS]; /* per-cpu channel buffers */
64};
65
66/*
67 * Relayfs inode
68 */
69struct relayfs_inode_info
70{
71 struct inode vfs_inode;
72 struct rchan_buf *buf;
73};
74
75static inline struct relayfs_inode_info *RELAYFS_I(struct inode *inode)
76{
77 return container_of(inode, struct relayfs_inode_info, vfs_inode);
78}
79
80/*
81 * Relay channel client callbacks
82 */
83struct rchan_callbacks
84{
85 /*
86 * subbuf_start - called on buffer-switch to a new sub-buffer
87 * @buf: the channel buffer containing the new sub-buffer
88 * @subbuf: the start of the new sub-buffer
89 * @prev_subbuf: the start of the previous sub-buffer
90 * @prev_padding: unused space at the end of previous sub-buffer
91 *
92 * The client should return 1 to continue logging, 0 to stop
93 * logging.
94 *
95 * NOTE: subbuf_start will also be invoked when the buffer is
96 * created, so that the first sub-buffer can be initialized
97 * if necessary. In this case, prev_subbuf will be NULL.
98 *
99 * NOTE: the client can reserve bytes at the beginning of the new
100 * sub-buffer by calling subbuf_start_reserve() in this callback.
101 */
102 int (*subbuf_start) (struct rchan_buf *buf,
103 void *subbuf,
104 void *prev_subbuf,
105 size_t prev_padding);
106
107 /*
108 * buf_mapped - relayfs buffer mmap notification
109 * @buf: the channel buffer
110 * @filp: relayfs file pointer
111 *
112 * Called when a relayfs file is successfully mmapped
113 */
114 void (*buf_mapped)(struct rchan_buf *buf,
115 struct file *filp);
116
117 /*
118 * buf_unmapped - relayfs buffer unmap notification
119 * @buf: the channel buffer
120 * @filp: relayfs file pointer
121 *
122 * Called when a relayfs file is successfully unmapped
123 */
124 void (*buf_unmapped)(struct rchan_buf *buf,
125 struct file *filp);
126};
127
128/*
129 * relayfs kernel API, fs/relayfs/relay.c
130 */
131
132struct rchan *relay_open(const char *base_filename,
133 struct dentry *parent,
134 size_t subbuf_size,
135 size_t n_subbufs,
136 struct rchan_callbacks *cb);
137extern void relay_close(struct rchan *chan);
138extern void relay_flush(struct rchan *chan);
139extern void relay_subbufs_consumed(struct rchan *chan,
140 unsigned int cpu,
141 size_t consumed);
142extern void relay_reset(struct rchan *chan);
143extern int relay_buf_full(struct rchan_buf *buf);
144
145extern size_t relay_switch_subbuf(struct rchan_buf *buf,
146 size_t length);
147extern struct dentry *relayfs_create_dir(const char *name,
148 struct dentry *parent);
149extern int relayfs_remove_dir(struct dentry *dentry);
150
151/**
152 * relay_write - write data into the channel
153 * @chan: relay channel
154 * @data: data to be written
155 * @length: number of bytes to write
156 *
157 * Writes data into the current cpu's channel buffer.
158 *
159 * Protects the buffer by disabling interrupts. Use this
160 * if you might be logging from interrupt context. Try
161 * __relay_write() if you know you won't be logging from
162 * interrupt context.
163 */
164static inline void relay_write(struct rchan *chan,
165 const void *data,
166 size_t length)
167{
168 unsigned long flags;
169 struct rchan_buf *buf;
170
171 local_irq_save(flags);
172 buf = chan->buf[smp_processor_id()];
173 if (unlikely(buf->offset + length > chan->subbuf_size))
174 length = relay_switch_subbuf(buf, length);
175 memcpy(buf->data + buf->offset, data, length);
176 buf->offset += length;
177 local_irq_restore(flags);
178}
179
180/**
181 * __relay_write - write data into the channel
182 * @chan: relay channel
183 * @data: data to be written
184 * @length: number of bytes to write
185 *
186 * Writes data into the current cpu's channel buffer.
187 *
188 * Protects the buffer by disabling preemption. Use
189 * relay_write() if you might be logging from interrupt
190 * context.
191 */
192static inline void __relay_write(struct rchan *chan,
193 const void *data,
194 size_t length)
195{
196 struct rchan_buf *buf;
197
198 buf = chan->buf[get_cpu()];
199 if (unlikely(buf->offset + length > buf->chan->subbuf_size))
200 length = relay_switch_subbuf(buf, length);
201 memcpy(buf->data + buf->offset, data, length);
202 buf->offset += length;
203 put_cpu();
204}
205
206/**
207 * relay_reserve - reserve slot in channel buffer
208 * @chan: relay channel
209 * @length: number of bytes to reserve
210 *
211 * Returns pointer to reserved slot, NULL if full.
212 *
213 * Reserves a slot in the current cpu's channel buffer.
214 * Does not protect the buffer at all - caller must provide
215 * appropriate synchronization.
216 */
217static inline void *relay_reserve(struct rchan *chan, size_t length)
218{
219 void *reserved;
220 struct rchan_buf *buf = chan->buf[smp_processor_id()];
221
222 if (unlikely(buf->offset + length > buf->chan->subbuf_size)) {
223 length = relay_switch_subbuf(buf, length);
224 if (!length)
225 return NULL;
226 }
227 reserved = buf->data + buf->offset;
228 buf->offset += length;
229
230 return reserved;
231}
232
233/**
234 * subbuf_start_reserve - reserve bytes at the start of a sub-buffer
235 * @buf: relay channel buffer
236 * @length: number of bytes to reserve
237 *
238 * Helper function used to reserve bytes at the beginning of
239 * a sub-buffer in the subbuf_start() callback.
240 */
241static inline void subbuf_start_reserve(struct rchan_buf *buf,
242 size_t length)
243{
244 BUG_ON(length >= buf->chan->subbuf_size - 1);
245 buf->offset = length;
246}
247
248/*
249 * exported relayfs file operations, fs/relayfs/inode.c
250 */
251
252extern struct file_operations relayfs_file_operations;
253
254#endif /* _LINUX_RELAYFS_FS_H */
255