1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
#ifndef _TRANSPORT_TRANSPORT_C_ /* -*- linux-c -*- */
#define _TRANSPORT_TRANSPORT_C_
/*
* transport.c - stp transport functions
*
* Copyright (C) IBM Corporation, 2005
* Copyright (C) Redhat Inc, 2005
*
* This file is released under the GPL.
*/
/** @file transport.c
* @brief Systemtap transport functions
*/
/** @addtogroup transport Transport Functions
* @{
*/
#include <linux/delay.h>
#include "transport.h"
#include "control.h"
#include "relayfs.c"
/** @file transport.c
* @brief transport functions
*/
/** @addtogroup io transport
* transport functions
* @{
*/
/* transport-related data for this probe */
struct stp_transport *t;
/* forward declaration of probe-defined exit function */
static void probe_exit(void);
/**
* _stp_handle_buf_info - handle relayfs buffer info command
*/
static void _stp_handle_buf_info(int pid, struct buf_info *in)
{
struct buf_info out;
BUG_ON(!(t && t->chan));
out.cpu = in->cpu;
out.produced = atomic_read(&t->chan->buf[in->cpu]->subbufs_produced);
out.consumed = atomic_read(&t->chan->buf[in->cpu]->subbufs_consumed);
_stp_ctrl_send(STP_BUF_INFO, &out, sizeof(out), pid);
}
/**
* _stp_handle_subbufs_consumed - handle relayfs subbufs consumed command
*/
static void _stp_handle_subbufs_consumed(int pid, struct consumed_info *info)
{
BUG_ON(!(t && t->chan));
relay_subbufs_consumed(t->chan, info->cpu, info->consumed);
}
int _stp_exit_called = 0;
static int global_pid;
static void stp_exit_helper (void *data);
static DECLARE_WORK(stp_exit, stp_exit_helper, &global_pid);
extern atomic_t _stp_transport_failures;
static void stp_exit_helper (void *data)
{
int err, pid = *(int *)data;
if (_stp_exit_called == 0) {
_stp_exit_called = 1;
probe_exit();
_stp_transport_flush();
}
//printk("stp_handle_exit: sending STP_EXIT. pid=%d\n",(int)pid);
while ((err =_stp_ctrl_send(STP_EXIT, __this_module.name,
strlen(__this_module.name) + 1, pid)) < 0) {
//printk("stp_handle_exit: sent STP_EXIT. err=%d\n", err);
msleep (5);
}
}
/**
* _stp_cmd_handler - control channel command handler callback
* @pid: the pid of the daemon the command was sent from
* @cmd: the command id
* @data: command-specific data
*
* This function must return 0 if the command was handled, nonzero
* otherwise.
*/
static int _stp_cmd_handler(int pid, int cmd, void *data)
{
int err = 0;
switch (cmd) {
case STP_BUF_INFO:
_stp_handle_buf_info(pid, data);
break;
case STP_SUBBUFS_CONSUMED:
_stp_handle_subbufs_consumed(pid, data);
break;
case STP_EXIT:
schedule_work (&stp_exit);
break;
default:
err = -1;
break;
}
return err;
}
/**
* _stp_transport_close - close netlink and relayfs channels
*
* This must be called after all I/O is done, probably at the end
* of module cleanup.
*/
void _stp_transport_close()
{
if (!t)
return;
_stp_ctrl_unregister(t->pid);
if (!_stp_streaming())
_stp_relayfs_close(t->chan, t->dir);
stp_exit_helper (&t->pid);
kfree(t);
}
/**
* _stp_transport_open - open netlink and relayfs channels
* @n_subbufs: number of relayfs sub-buffers
* @subbuf_size: size of relayfs sub-buffers
* @pid: daemon pid
*
* Returns negative on failure, 0 otherwise.
*
* This function registers the probe with the control channel,
* and if the probe output will not be 'streaming', creates a
* relayfs channel for it. This must be called before any I/O is
* done, probably at the start of module initialization.
*/
int _stp_transport_open(unsigned n_subbufs, unsigned subbuf_size, int pid)
{
BUG_ON(!(n_subbufs && subbuf_size));
t = kcalloc(1, sizeof(struct stp_transport), GFP_KERNEL);
if (!t)
return -ENOMEM;
t->pid = pid;
global_pid = pid;
_stp_ctrl_register(t->pid, _stp_cmd_handler);
if (_stp_streaming())
return 0;
t->chan = _stp_relayfs_open(n_subbufs, subbuf_size, t->pid, &t->dir);
if (!t->chan) {
_stp_ctrl_unregister(t->pid);
kfree(t);
return -ENOMEM;
}
return 0;
}
int _stp_transport_send (int pid, void *data, int len)
{
int err = _stp_ctrl_send(STP_REALTIME_DATA, data, len, pid);
if (err < 0 && _stp_exit_called) {
do {
msleep (5);
err = _stp_ctrl_send(STP_REALTIME_DATA, data, len, pid);
} while (err < 0);
}
return err;
}
/** @} */
#endif /* _TRANSPORT_C_ */
|