]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxclock.c
check pthread_atfork and thread-local storage
[mirror_lxc.git] / src / lxc / lxclock.c
1 /* liblxcapi
2 *
3 * Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
4 * Copyright © 2012 Canonical Ltd.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #define _GNU_SOURCE
22 #include "lxclock.h"
23 #include <malloc.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <stdlib.h>
29 #include <pthread.h>
30
31 #include <lxc/lxccontainer.h>
32
33 #include "utils.h"
34 #include "log.h"
35
36 #ifdef MUTEX_DEBUGGING
37 #include <execinfo.h>
38 #endif
39
40 #define OFLAG (O_CREAT | O_RDWR)
41 #define SEMMODE 0660
42 #define SEMVALUE 1
43 #define SEMVALUE_LOCKED 0
44
45 lxc_log_define(lxc_lock, lxc);
46
47 #ifdef MUTEX_DEBUGGING
48 static pthread_mutex_t thread_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
49
50 static inline void dump_stacktrace(void)
51 {
52 void *array[MAX_STACKDEPTH];
53 size_t size;
54 char **strings;
55 size_t i;
56
57 size = backtrace(array, MAX_STACKDEPTH);
58 strings = backtrace_symbols(array, size);
59
60 // Using fprintf here as our logging module is not thread safe
61 fprintf(stderr, "\tObtained %zd stack frames.\n", size);
62
63 for (i = 0; i < size; i++)
64 fprintf(stderr, "\t\t%s\n", strings[i]);
65
66 free (strings);
67 }
68 #else
69 static pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER;
70
71 static inline void dump_stacktrace(void) {;}
72 #endif
73
74 static void lock_mutex(pthread_mutex_t *l)
75 {
76 int ret;
77
78 if ((ret = pthread_mutex_lock(l)) != 0) {
79 fprintf(stderr, "pthread_mutex_lock returned:%d %s", ret, strerror(ret));
80 dump_stacktrace();
81 exit(1);
82 }
83 }
84
85 static void unlock_mutex(pthread_mutex_t *l)
86 {
87 int ret;
88
89 if ((ret = pthread_mutex_unlock(l)) != 0) {
90 fprintf(stderr, "pthread_mutex_unlock returned:%d %s", ret, strerror(ret));
91 dump_stacktrace();
92 exit(1);
93 }
94 }
95
96 static char *lxclock_name(const char *p, const char *n)
97 {
98 int ret;
99 int len;
100 char *dest;
101 const char *rundir;
102
103 /* lockfile will be:
104 * "/run" + "/lock/lxc/$lxcpath/$lxcname + '\0' if root
105 * or
106 * $XDG_RUNTIME_DIR + "/lock/lxc/$lxcpath/$lxcname + '\0' if non-root
107 */
108
109 /* length of "/lock/lxc/" + $lxcpath + "/" + $lxcname + '\0' */
110 len = strlen("/lock/lxc/") + strlen(n) + strlen(p) + 2;
111 rundir = get_rundir();
112 len += strlen(rundir);
113
114 if ((dest = malloc(len)) == NULL)
115 return NULL;
116
117 ret = snprintf(dest, len, "%s/lock/lxc/%s", rundir, p);
118 if (ret < 0 || ret >= len) {
119 free(dest);
120 return NULL;
121 }
122 ret = mkdir_p(dest, 0755);
123 if (ret < 0) {
124 free(dest);
125 return NULL;
126 }
127
128 ret = snprintf(dest, len, "%s/lock/lxc/%s/%s", rundir, p, n);
129 if (ret < 0 || ret >= len) {
130 free(dest);
131 return NULL;
132 }
133 return dest;
134 }
135
136 static sem_t *lxc_new_unnamed_sem(void)
137 {
138 sem_t *s;
139 int ret;
140
141 s = malloc(sizeof(*s));
142 if (!s)
143 return NULL;
144 ret = sem_init(s, 0, 1);
145 if (ret) {
146 free(s);
147 return NULL;
148 }
149 return s;
150 }
151
152 struct lxc_lock *lxc_newlock(const char *lxcpath, const char *name)
153 {
154 struct lxc_lock *l;
155
156 l = malloc(sizeof(*l));
157 if (!l)
158 goto out;
159
160 if (!name) {
161 l->type = LXC_LOCK_ANON_SEM;
162 l->u.sem = lxc_new_unnamed_sem();
163 if (!l->u.sem) {
164 free(l);
165 l = NULL;
166 }
167 goto out;
168 }
169
170 l->type = LXC_LOCK_FLOCK;
171 l->u.f.fname = lxclock_name(lxcpath, name);
172 if (!l->u.f.fname) {
173 free(l);
174 l = NULL;
175 goto out;
176 }
177 l->u.f.fd = -1;
178
179 out:
180 return l;
181 }
182
183 int lxclock(struct lxc_lock *l, int timeout)
184 {
185 int ret = -1, saved_errno = errno;
186 struct flock lk;
187
188 switch(l->type) {
189 case LXC_LOCK_ANON_SEM:
190 if (!timeout) {
191 ret = sem_wait(l->u.sem);
192 if (ret == -1)
193 saved_errno = errno;
194 } else {
195 struct timespec ts;
196 if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
197 ret = -2;
198 goto out;
199 }
200 ts.tv_sec += timeout;
201 ret = sem_timedwait(l->u.sem, &ts);
202 if (ret == -1)
203 saved_errno = errno;
204 }
205 break;
206 case LXC_LOCK_FLOCK:
207 ret = -2;
208 if (timeout) {
209 ERROR("Error: timeout not supported with flock");
210 ret = -2;
211 goto out;
212 }
213 if (!l->u.f.fname) {
214 ERROR("Error: filename not set for flock");
215 ret = -2;
216 goto out;
217 }
218 if (l->u.f.fd == -1) {
219 l->u.f.fd = open(l->u.f.fname, O_RDWR|O_CREAT,
220 S_IWUSR | S_IRUSR);
221 if (l->u.f.fd == -1) {
222 ERROR("Error opening %s", l->u.f.fname);
223 goto out;
224 }
225 }
226 lk.l_type = F_WRLCK;
227 lk.l_whence = SEEK_SET;
228 lk.l_start = 0;
229 lk.l_len = 0;
230 ret = fcntl(l->u.f.fd, F_SETLKW, &lk);
231 if (ret == -1)
232 saved_errno = errno;
233 break;
234 }
235
236 out:
237 errno = saved_errno;
238 return ret;
239 }
240
241 int lxcunlock(struct lxc_lock *l)
242 {
243 int ret = 0, saved_errno = errno;
244 struct flock lk;
245
246 switch(l->type) {
247 case LXC_LOCK_ANON_SEM:
248 if (!l->u.sem)
249 ret = -2;
250 else {
251 ret = sem_post(l->u.sem);
252 saved_errno = errno;
253 }
254 break;
255 case LXC_LOCK_FLOCK:
256 if (l->u.f.fd != -1) {
257 lk.l_type = F_UNLCK;
258 lk.l_whence = SEEK_SET;
259 lk.l_start = 0;
260 lk.l_len = 0;
261 ret = fcntl(l->u.f.fd, F_SETLK, &lk);
262 if (ret < 0)
263 saved_errno = errno;
264 close(l->u.f.fd);
265 l->u.f.fd = -1;
266 } else
267 ret = -2;
268 break;
269 }
270
271 errno = saved_errno;
272 return ret;
273 }
274
275 /*
276 * lxc_putlock() is only called when a container_new() fails,
277 * or during container_put(), which is already guaranteed to
278 * only be done by one task.
279 * So the only exclusion we need to provide here is for regular
280 * thread safety (i.e. file descriptor table changes).
281 */
282 void lxc_putlock(struct lxc_lock *l)
283 {
284 if (!l)
285 return;
286 switch(l->type) {
287 case LXC_LOCK_ANON_SEM:
288 if (l->u.sem) {
289 sem_destroy(l->u.sem);
290 free(l->u.sem);
291 l->u.sem = NULL;
292 }
293 break;
294 case LXC_LOCK_FLOCK:
295 if (l->u.f.fd != -1) {
296 close(l->u.f.fd);
297 l->u.f.fd = -1;
298 }
299 if (l->u.f.fname) {
300 free(l->u.f.fname);
301 l->u.f.fname = NULL;
302 }
303 break;
304 }
305 free(l);
306 }
307
308 void process_lock(void)
309 {
310 lock_mutex(&thread_mutex);
311 }
312
313 void process_unlock(void)
314 {
315 unlock_mutex(&thread_mutex);
316 }
317
318 /* One thread can do fork() while another one is holding a mutex.
319 * There is only one thread in child just after the fork(), so noone will ever release that mutex.
320 * We setup a "child" fork handler to unlock the mutex just after the fork().
321 * For several mutex types, unlocking an unlocked mutex can lead to undefined behavior.
322 * One way to deal with it is to setup "prepare" fork handler
323 * to lock the mutex before fork() and both "parent" and "child" fork handlers
324 * to unlock the mutex.
325 * This forbids doing fork() while explicitly holding the lock.
326 */
327 #ifdef HAVE_PTHREAD_ATFORK
328 __attribute__((constructor))
329 static void process_lock_setup_atfork(void)
330 {
331 pthread_atfork(process_lock, process_unlock, process_unlock);
332 }
333 #endif
334
335 int container_mem_lock(struct lxc_container *c)
336 {
337 return lxclock(c->privlock, 0);
338 }
339
340 void container_mem_unlock(struct lxc_container *c)
341 {
342 lxcunlock(c->privlock);
343 }
344
345 int container_disk_lock(struct lxc_container *c)
346 {
347 int ret;
348
349 if ((ret = lxclock(c->privlock, 0)))
350 return ret;
351 if ((ret = lxclock(c->slock, 0))) {
352 lxcunlock(c->privlock);
353 return ret;
354 }
355 return 0;
356 }
357
358 void container_disk_unlock(struct lxc_container *c)
359 {
360 lxcunlock(c->slock);
361 lxcunlock(c->privlock);
362 }