diff options
Diffstat (limited to 'fs/relayfs/relay.c')
-rw-r--r-- | fs/relayfs/relay.c | 77 |
1 files changed, 64 insertions, 13 deletions
diff --git a/fs/relayfs/relay.c b/fs/relayfs/relay.c index 16446a15c96d..abf3ceaace49 100644 --- a/fs/relayfs/relay.c +++ b/fs/relayfs/relay.c | |||
@@ -80,11 +80,34 @@ static void buf_unmapped_default_callback(struct rchan_buf *buf, | |||
80 | { | 80 | { |
81 | } | 81 | } |
82 | 82 | ||
83 | /* | ||
84 | * create_buf_file_create() default callback. Creates file to represent buf. | ||
85 | */ | ||
86 | static struct dentry *create_buf_file_default_callback(const char *filename, | ||
87 | struct dentry *parent, | ||
88 | int mode, | ||
89 | struct rchan_buf *buf, | ||
90 | int *is_global) | ||
91 | { | ||
92 | return relayfs_create_file(filename, parent, mode, | ||
93 | &relay_file_operations, buf); | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * remove_buf_file() default callback. Removes file representing relay buffer. | ||
98 | */ | ||
99 | static int remove_buf_file_default_callback(struct dentry *dentry) | ||
100 | { | ||
101 | return relayfs_remove(dentry); | ||
102 | } | ||
103 | |||
83 | /* relay channel default callbacks */ | 104 | /* relay channel default callbacks */ |
84 | static struct rchan_callbacks default_channel_callbacks = { | 105 | static struct rchan_callbacks default_channel_callbacks = { |
85 | .subbuf_start = subbuf_start_default_callback, | 106 | .subbuf_start = subbuf_start_default_callback, |
86 | .buf_mapped = buf_mapped_default_callback, | 107 | .buf_mapped = buf_mapped_default_callback, |
87 | .buf_unmapped = buf_unmapped_default_callback, | 108 | .buf_unmapped = buf_unmapped_default_callback, |
109 | .create_buf_file = create_buf_file_default_callback, | ||
110 | .remove_buf_file = remove_buf_file_default_callback, | ||
88 | }; | 111 | }; |
89 | 112 | ||
90 | /** | 113 | /** |
@@ -148,14 +171,16 @@ static inline void __relay_reset(struct rchan_buf *buf, unsigned int init) | |||
148 | void relay_reset(struct rchan *chan) | 171 | void relay_reset(struct rchan *chan) |
149 | { | 172 | { |
150 | unsigned int i; | 173 | unsigned int i; |
174 | struct rchan_buf *prev = NULL; | ||
151 | 175 | ||
152 | if (!chan) | 176 | if (!chan) |
153 | return; | 177 | return; |
154 | 178 | ||
155 | for (i = 0; i < NR_CPUS; i++) { | 179 | for (i = 0; i < NR_CPUS; i++) { |
156 | if (!chan->buf[i]) | 180 | if (!chan->buf[i] || chan->buf[i] == prev) |
157 | continue; | 181 | break; |
158 | __relay_reset(chan->buf[i], 0); | 182 | __relay_reset(chan->buf[i], 0); |
183 | prev = chan->buf[i]; | ||
159 | } | 184 | } |
160 | } | 185 | } |
161 | 186 | ||
@@ -166,17 +191,27 @@ void relay_reset(struct rchan *chan) | |||
166 | */ | 191 | */ |
167 | static struct rchan_buf *relay_open_buf(struct rchan *chan, | 192 | static struct rchan_buf *relay_open_buf(struct rchan *chan, |
168 | const char *filename, | 193 | const char *filename, |
169 | struct dentry *parent) | 194 | struct dentry *parent, |
195 | int *is_global) | ||
170 | { | 196 | { |
171 | struct rchan_buf *buf; | 197 | struct rchan_buf *buf; |
172 | struct dentry *dentry; | 198 | struct dentry *dentry; |
173 | 199 | ||
200 | if (*is_global) | ||
201 | return chan->buf[0]; | ||
202 | |||
203 | buf = relay_create_buf(chan); | ||
204 | if (!buf) | ||
205 | return NULL; | ||
206 | |||
174 | /* Create file in fs */ | 207 | /* Create file in fs */ |
175 | dentry = relayfs_create_file(filename, parent, S_IRUSR, chan); | 208 | dentry = chan->cb->create_buf_file(filename, parent, S_IRUSR, |
176 | if (!dentry) | 209 | buf, is_global); |
210 | if (!dentry) { | ||
211 | relay_destroy_buf(buf); | ||
177 | return NULL; | 212 | return NULL; |
213 | } | ||
178 | 214 | ||
179 | buf = RELAYFS_I(dentry->d_inode)->buf; | ||
180 | buf->dentry = dentry; | 215 | buf->dentry = dentry; |
181 | __relay_reset(buf, 1); | 216 | __relay_reset(buf, 1); |
182 | 217 | ||
@@ -214,6 +249,10 @@ static inline void setup_callbacks(struct rchan *chan, | |||
214 | cb->buf_mapped = buf_mapped_default_callback; | 249 | cb->buf_mapped = buf_mapped_default_callback; |
215 | if (!cb->buf_unmapped) | 250 | if (!cb->buf_unmapped) |
216 | cb->buf_unmapped = buf_unmapped_default_callback; | 251 | cb->buf_unmapped = buf_unmapped_default_callback; |
252 | if (!cb->create_buf_file) | ||
253 | cb->create_buf_file = create_buf_file_default_callback; | ||
254 | if (!cb->remove_buf_file) | ||
255 | cb->remove_buf_file = remove_buf_file_default_callback; | ||
217 | chan->cb = cb; | 256 | chan->cb = cb; |
218 | } | 257 | } |
219 | 258 | ||
@@ -241,6 +280,7 @@ struct rchan *relay_open(const char *base_filename, | |||
241 | unsigned int i; | 280 | unsigned int i; |
242 | struct rchan *chan; | 281 | struct rchan *chan; |
243 | char *tmpname; | 282 | char *tmpname; |
283 | int is_global = 0; | ||
244 | 284 | ||
245 | if (!base_filename) | 285 | if (!base_filename) |
246 | return NULL; | 286 | return NULL; |
@@ -265,7 +305,8 @@ struct rchan *relay_open(const char *base_filename, | |||
265 | 305 | ||
266 | for_each_online_cpu(i) { | 306 | for_each_online_cpu(i) { |
267 | sprintf(tmpname, "%s%d", base_filename, i); | 307 | sprintf(tmpname, "%s%d", base_filename, i); |
268 | chan->buf[i] = relay_open_buf(chan, tmpname, parent); | 308 | chan->buf[i] = relay_open_buf(chan, tmpname, parent, |
309 | &is_global); | ||
269 | chan->buf[i]->cpu = i; | 310 | chan->buf[i]->cpu = i; |
270 | if (!chan->buf[i]) | 311 | if (!chan->buf[i]) |
271 | goto free_bufs; | 312 | goto free_bufs; |
@@ -279,6 +320,8 @@ free_bufs: | |||
279 | if (!chan->buf[i]) | 320 | if (!chan->buf[i]) |
280 | break; | 321 | break; |
281 | relay_close_buf(chan->buf[i]); | 322 | relay_close_buf(chan->buf[i]); |
323 | if (is_global) | ||
324 | break; | ||
282 | } | 325 | } |
283 | kfree(tmpname); | 326 | kfree(tmpname); |
284 | 327 | ||
@@ -333,8 +376,7 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length) | |||
333 | return length; | 376 | return length; |
334 | 377 | ||
335 | toobig: | 378 | toobig: |
336 | printk(KERN_WARNING "relayfs: event too large (%Zd)\n", length); | 379 | buf->chan->last_toobig = length; |
337 | WARN_ON(1); | ||
338 | return 0; | 380 | return 0; |
339 | } | 381 | } |
340 | 382 | ||
@@ -389,16 +431,23 @@ void relay_destroy_channel(struct kref *kref) | |||
389 | void relay_close(struct rchan *chan) | 431 | void relay_close(struct rchan *chan) |
390 | { | 432 | { |
391 | unsigned int i; | 433 | unsigned int i; |
434 | struct rchan_buf *prev = NULL; | ||
392 | 435 | ||
393 | if (!chan) | 436 | if (!chan) |
394 | return; | 437 | return; |
395 | 438 | ||
396 | for (i = 0; i < NR_CPUS; i++) { | 439 | for (i = 0; i < NR_CPUS; i++) { |
397 | if (!chan->buf[i]) | 440 | if (!chan->buf[i] || chan->buf[i] == prev) |
398 | continue; | 441 | break; |
399 | relay_close_buf(chan->buf[i]); | 442 | relay_close_buf(chan->buf[i]); |
443 | prev = chan->buf[i]; | ||
400 | } | 444 | } |
401 | 445 | ||
446 | if (chan->last_toobig) | ||
447 | printk(KERN_WARNING "relayfs: one or more items not logged " | ||
448 | "[item size (%Zd) > sub-buffer size (%Zd)]\n", | ||
449 | chan->last_toobig, chan->subbuf_size); | ||
450 | |||
402 | kref_put(&chan->kref, relay_destroy_channel); | 451 | kref_put(&chan->kref, relay_destroy_channel); |
403 | } | 452 | } |
404 | 453 | ||
@@ -411,14 +460,16 @@ void relay_close(struct rchan *chan) | |||
411 | void relay_flush(struct rchan *chan) | 460 | void relay_flush(struct rchan *chan) |
412 | { | 461 | { |
413 | unsigned int i; | 462 | unsigned int i; |
463 | struct rchan_buf *prev = NULL; | ||
414 | 464 | ||
415 | if (!chan) | 465 | if (!chan) |
416 | return; | 466 | return; |
417 | 467 | ||
418 | for (i = 0; i < NR_CPUS; i++) { | 468 | for (i = 0; i < NR_CPUS; i++) { |
419 | if (!chan->buf[i]) | 469 | if (!chan->buf[i] || chan->buf[i] == prev) |
420 | continue; | 470 | break; |
421 | relay_switch_subbuf(chan->buf[i], 0); | 471 | relay_switch_subbuf(chan->buf[i], 0); |
472 | prev = chan->buf[i]; | ||
422 | } | 473 | } |
423 | } | 474 | } |
424 | 475 | ||