~lttng/lttng-modules/trunk

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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
/* SPDX-License-Identifier: (GPL-2.0 or LGPL-2.1)
 *
 * lttng-context.c
 *
 * LTTng trace/channel/event context management.
 *
 * Copyright (C) 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
 */

#include <linux/module.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <wrapper/vmalloc.h>	/* for wrapper_vmalloc_sync_all() */
#include <lttng-events.h>
#include <lttng-tracer.h>

/*
 * The filter implementation requires that two consecutive "get" for the
 * same context performed by the same thread return the same result.
 */

/*
 * Static array of contexts, for $ctx filters.
 */
struct lttng_ctx *lttng_static_ctx;

int lttng_find_context(struct lttng_ctx *ctx, const char *name)
{
	unsigned int i;

	for (i = 0; i < ctx->nr_fields; i++) {
		/* Skip allocated (but non-initialized) contexts */
		if (!ctx->fields[i].event_field.name)
			continue;
		if (!strcmp(ctx->fields[i].event_field.name, name))
			return 1;
	}
	return 0;
}
EXPORT_SYMBOL_GPL(lttng_find_context);

int lttng_get_context_index(struct lttng_ctx *ctx, const char *name)
{
	unsigned int i;
	const char *subname;

	if (!ctx)
		return -1;
	if (strncmp(name, "$ctx.", strlen("$ctx.")) == 0) {
		subname = name + strlen("$ctx.");
	} else {
		subname = name;
	}
	for (i = 0; i < ctx->nr_fields; i++) {
		/* Skip allocated (but non-initialized) contexts */
		if (!ctx->fields[i].event_field.name)
			continue;
		if (!strcmp(ctx->fields[i].event_field.name, subname))
			return i;
	}
	return -1;
}
EXPORT_SYMBOL_GPL(lttng_get_context_index);

/*
 * Note: as we append context information, the pointer location may change.
 */
struct lttng_ctx_field *lttng_append_context(struct lttng_ctx **ctx_p)
{
	struct lttng_ctx_field *field;
	struct lttng_ctx *ctx;

	if (!*ctx_p) {
		*ctx_p = kzalloc(sizeof(struct lttng_ctx), GFP_KERNEL);
		if (!*ctx_p)
			return NULL;
		(*ctx_p)->largest_align = 1;
	}
	ctx = *ctx_p;
	if (ctx->nr_fields + 1 > ctx->allocated_fields) {
		struct lttng_ctx_field *new_fields;

		ctx->allocated_fields = max_t(size_t, 1, 2 * ctx->allocated_fields);
		new_fields = lttng_kvzalloc(ctx->allocated_fields * sizeof(struct lttng_ctx_field), GFP_KERNEL);
		if (!new_fields)
			return NULL;
		if (ctx->fields)
			memcpy(new_fields, ctx->fields, sizeof(*ctx->fields) * ctx->nr_fields);
		lttng_kvfree(ctx->fields);
		ctx->fields = new_fields;
	}
	field = &ctx->fields[ctx->nr_fields];
	ctx->nr_fields++;
	return field;
}
EXPORT_SYMBOL_GPL(lttng_append_context);

/*
 * lttng_context_update() should be called at least once between context
 * modification and trace start.
 */
void lttng_context_update(struct lttng_ctx *ctx)
{
	int i;
	size_t largest_align = 8;	/* in bits */

	for (i = 0; i < ctx->nr_fields; i++) {
		struct lttng_type *type;
		size_t field_align = 8;

		type = &ctx->fields[i].event_field.type;
		switch (type->atype) {
		case atype_integer:
			field_align = type->u.basic.integer.alignment;
			break;
		case atype_array:
		case atype_array_bitfield:
		{
			struct lttng_basic_type *btype;

			btype = &type->u.array.elem_type;
			switch (btype->atype) {
			case atype_integer:
				field_align = btype->u.basic.integer.alignment;
				break;
			case atype_string:
				break;

			case atype_array:
			case atype_sequence:
			case atype_array_bitfield:
			case atype_sequence_bitfield:
			case atype_struct:
			case atype_array_compound:
			case atype_sequence_compound:
			case atype_variant:
			default:
				WARN_ON_ONCE(1);
				break;
			}
			break;
		}
		case atype_sequence:
		case atype_sequence_bitfield:
		{
			struct lttng_basic_type *btype;

			btype = &type->u.sequence.length_type;
			switch (btype->atype) {
			case atype_integer:
				field_align = btype->u.basic.integer.alignment;
				break;

			case atype_string:
			case atype_array:
			case atype_sequence:
			case atype_array_bitfield:
			case atype_sequence_bitfield:
			case atype_struct:
			case atype_array_compound:
			case atype_sequence_compound:
			case atype_variant:
			default:
				WARN_ON_ONCE(1);
				break;
			}

			btype = &type->u.sequence.elem_type;
			switch (btype->atype) {
			case atype_integer:
				field_align = max_t(size_t,
					field_align,
					btype->u.basic.integer.alignment);
				break;

			case atype_string:
				break;

			case atype_array:
			case atype_sequence:
			case atype_array_bitfield:
			case atype_sequence_bitfield:
			case atype_struct:
			case atype_array_compound:
			case atype_sequence_compound:
			case atype_variant:
			default:
				WARN_ON_ONCE(1);
				break;
			}
			break;
		}
		case atype_string:
			break;

		case atype_struct:
		case atype_array_compound:
		case atype_sequence_compound:
		case atype_variant:
			break;

		case atype_enum:
		default:
			WARN_ON_ONCE(1);
			break;
		}
		largest_align = max_t(size_t, largest_align, field_align);
	}
	ctx->largest_align = largest_align >> 3;	/* bits to bytes */
}

/*
 * Remove last context field.
 */
void lttng_remove_context_field(struct lttng_ctx **ctx_p,
				struct lttng_ctx_field *field)
{
	struct lttng_ctx *ctx;

	ctx = *ctx_p;
	ctx->nr_fields--;
	WARN_ON_ONCE(&ctx->fields[ctx->nr_fields] != field);
	memset(&ctx->fields[ctx->nr_fields], 0, sizeof(struct lttng_ctx_field));
}
EXPORT_SYMBOL_GPL(lttng_remove_context_field);

void lttng_destroy_context(struct lttng_ctx *ctx)
{
	int i;

	if (!ctx)
		return;
	for (i = 0; i < ctx->nr_fields; i++) {
		if (ctx->fields[i].destroy)
			ctx->fields[i].destroy(&ctx->fields[i]);
	}
	lttng_kvfree(ctx->fields);
	kfree(ctx);
}

int lttng_context_init(void)
{
	int ret;

	ret = lttng_add_hostname_to_ctx(&lttng_static_ctx);
	if (ret) {
		printk(KERN_WARNING "Cannot add context lttng_add_hostname_to_ctx");
	}
	ret = lttng_add_nice_to_ctx(&lttng_static_ctx);
	if (ret) {
		printk(KERN_WARNING "Cannot add context lttng_add_nice_to_ctx");
	}
	ret = lttng_add_pid_to_ctx(&lttng_static_ctx);
	if (ret) {
		printk(KERN_WARNING "Cannot add context lttng_add_pid_to_ctx");
	}
	ret = lttng_add_ppid_to_ctx(&lttng_static_ctx);
	if (ret) {
		printk(KERN_WARNING "Cannot add context lttng_add_ppid_to_ctx");
	}
	ret = lttng_add_prio_to_ctx(&lttng_static_ctx);
	if (ret) {
		printk(KERN_WARNING "Cannot add context lttng_add_prio_to_ctx");
	}
	ret = lttng_add_procname_to_ctx(&lttng_static_ctx);
	if (ret) {
		printk(KERN_WARNING "Cannot add context lttng_add_procname_to_ctx");
	}
	ret = lttng_add_tid_to_ctx(&lttng_static_ctx);
	if (ret) {
		printk(KERN_WARNING "Cannot add context lttng_add_tid_to_ctx");
	}
	ret = lttng_add_vppid_to_ctx(&lttng_static_ctx);
	if (ret) {
		printk(KERN_WARNING "Cannot add context lttng_add_vppid_to_ctx");
	}
	ret = lttng_add_vtid_to_ctx(&lttng_static_ctx);
	if (ret) {
		printk(KERN_WARNING "Cannot add context lttng_add_vtid_to_ctx");
	}
	ret = lttng_add_vpid_to_ctx(&lttng_static_ctx);
	if (ret) {
		printk(KERN_WARNING "Cannot add context lttng_add_vpid_to_ctx");
	}
	ret = lttng_add_cpu_id_to_ctx(&lttng_static_ctx);
	if (ret) {
		printk(KERN_WARNING "Cannot add context lttng_add_cpu_id_to_ctx");
	}
	ret = lttng_add_interruptible_to_ctx(&lttng_static_ctx);
	if (ret) {
		printk(KERN_WARNING "Cannot add context lttng_add_interruptible_to_ctx");
	}
	ret = lttng_add_need_reschedule_to_ctx(&lttng_static_ctx);
	if (ret) {
		printk(KERN_WARNING "Cannot add context lttng_add_need_reschedule_to_ctx");
	}
	ret = lttng_add_preemptible_to_ctx(&lttng_static_ctx);
	if (ret && ret != -ENOSYS) {
		printk(KERN_WARNING "Cannot add context lttng_add_preemptible_to_ctx");
	}
	ret = lttng_add_migratable_to_ctx(&lttng_static_ctx);
	if (ret && ret != -ENOSYS) {
		printk(KERN_WARNING "Cannot add context lttng_add_migratable_to_ctx");
	}
	/* TODO: perf counters for filtering */
	return 0;
}

void lttng_context_exit(void)
{
	lttng_destroy_context(lttng_static_ctx);
	lttng_static_ctx = NULL;
}