Fix: namespace contexts !CONFIG_RCU_TLS variable initialization
[deliverable/lttng-ust.git] / liblttng-ust / lttng-context-ipc-ns.c
1 /*
2 * lttng-context-ipc-ns.c
3 *
4 * LTTng UST ipc namespace context.
5 *
6 * Copyright (C) 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 * 2019 Michael Jeanson <mjeanson@efficios.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; only
12 * version 2.1 of the License.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #define _LGPL_SOURCE
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <lttng/ust-events.h>
29 #include <lttng/ust-tracer.h>
30 #include <lttng/ringbuffer-config.h>
31 #include <lttng/ust-tid.h>
32 #include <urcu/tls-compat.h>
33 #include "lttng-tracer-core.h"
34 #include "ns.h"
35
36 /*
37 * We cache the result to ensure we don't stat(2) the proc filesystem on
38 * each event.
39 */
40 #ifdef CONFIG_RCU_TLS
41 static DEFINE_URCU_TLS(ino_t, cached_ipc_ns) = NS_INO_UNINITIALIZED;
42 #else
43 static DEFINE_URCU_TLS_INIT(ino_t, cached_ipc_ns, NS_INO_UNINITIALIZED);
44 #endif
45
46 static
47 ino_t get_ipc_ns(void)
48 {
49 struct stat sb;
50 ino_t ipc_ns;
51
52 ipc_ns = CMM_LOAD_SHARED(URCU_TLS(cached_ipc_ns));
53
54 /*
55 * If the cache is populated, do nothing and return the
56 * cached inode number.
57 */
58 if (caa_likely(ipc_ns != NS_INO_UNINITIALIZED))
59 return ipc_ns;
60
61 /*
62 * At this point we have to populate the cache, set the initial
63 * value to NS_INO_UNAVAILABLE (0), if we fail to get the inode
64 * number from the proc filesystem, this is the value we will
65 * cache.
66 */
67 ipc_ns = NS_INO_UNAVAILABLE;
68
69 /*
70 * /proc/thread-self was introduced in kernel v3.17
71 */
72 if (stat("/proc/thread-self/ns/ipc", &sb) == 0) {
73 ipc_ns = sb.st_ino;
74 } else {
75 char proc_ns_path[LTTNG_PROC_NS_PATH_MAX];
76
77 if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
78 "/proc/self/task/%d/ns/ipc",
79 lttng_gettid()) >= 0) {
80
81 if (stat(proc_ns_path, &sb) == 0) {
82 ipc_ns = sb.st_ino;
83 }
84 }
85 }
86
87 /*
88 * And finally, store the inode number in the cache.
89 */
90 CMM_STORE_SHARED(URCU_TLS(cached_ipc_ns), ipc_ns);
91
92 return ipc_ns;
93 }
94
95 /*
96 * The ipc namespace can change for 3 reasons
97 * * clone(2) called with CLONE_NEWIPC
98 * * setns(2) called with the fd of a different ipc ns
99 * * unshare(2) called with CLONE_NEWIPC
100 */
101 void lttng_context_ipc_ns_reset(void)
102 {
103 CMM_STORE_SHARED(URCU_TLS(cached_ipc_ns), NS_INO_UNINITIALIZED);
104 }
105
106 static
107 size_t ipc_ns_get_size(struct lttng_ctx_field *field, size_t offset)
108 {
109 size_t size = 0;
110
111 size += lib_ring_buffer_align(offset, lttng_alignof(ino_t));
112 size += sizeof(ino_t);
113 return size;
114 }
115
116 static
117 void ipc_ns_record(struct lttng_ctx_field *field,
118 struct lttng_ust_lib_ring_buffer_ctx *ctx,
119 struct lttng_channel *chan)
120 {
121 ino_t ipc_ns;
122
123 ipc_ns = get_ipc_ns();
124 lib_ring_buffer_align_ctx(ctx, lttng_alignof(ipc_ns));
125 chan->ops->event_write(ctx, &ipc_ns, sizeof(ipc_ns));
126 }
127
128 static
129 void ipc_ns_get_value(struct lttng_ctx_field *field,
130 struct lttng_ctx_value *value)
131 {
132 value->u.s64 = get_ipc_ns();
133 }
134
135 int lttng_add_ipc_ns_to_ctx(struct lttng_ctx **ctx)
136 {
137 struct lttng_ctx_field *field;
138
139 field = lttng_append_context(ctx);
140 if (!field)
141 return -ENOMEM;
142 if (lttng_find_context(*ctx, "ipc_ns")) {
143 lttng_remove_context_field(ctx, field);
144 return -EEXIST;
145 }
146 field->event_field.name = "ipc_ns";
147 field->event_field.type.atype = atype_integer;
148 field->event_field.type.u.basic.integer.size = sizeof(ino_t) * CHAR_BIT;
149 field->event_field.type.u.basic.integer.alignment = lttng_alignof(ino_t) * CHAR_BIT;
150 field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(ino_t);
151 field->event_field.type.u.basic.integer.reverse_byte_order = 0;
152 field->event_field.type.u.basic.integer.base = 10;
153 field->event_field.type.u.basic.integer.encoding = lttng_encode_none;
154 field->get_size = ipc_ns_get_size;
155 field->record = ipc_ns_record;
156 field->get_value = ipc_ns_get_value;
157 lttng_context_update(*ctx);
158 return 0;
159 }
160
161 /*
162 * * Force a read (imply TLS fixup for dlopen) of TLS variables.
163 * */
164 void lttng_fixup_ipc_ns_tls(void)
165 {
166 asm volatile ("" : : "m" (URCU_TLS(cached_ipc_ns)));
167 }
This page took 0.042259 seconds and 5 git commands to generate.