]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/lxclock.c
seccomp: s/seccomp_notif_alloc/seccomp_notify_alloc/g
[mirror_lxc.git] / src / lxc / lxclock.c
CommitLineData
72d0e1cb
SG
1/* liblxcapi
2 *
3 * Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
4 * Copyright © 2012 Canonical Ltd.
5 *
d75462e4
SH
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
72d0e1cb
SG
19 */
20
d38dd64a
CB
21#ifndef _GNU_SOURCE
22#define _GNU_SOURCE 1
23#endif
df271a59 24#include <errno.h>
93dc5327 25#include <fcntl.h>
56474555 26#include <malloc.h>
052616eb 27#include <pthread.h>
56474555
CB
28#include <stdio.h>
29#include <stdlib.h>
30#include <sys/file.h>
31#include <unistd.h>
f2363e38 32
5cee8c50 33#include <lxc/lxccontainer.h>
72d0e1cb 34
d38dd64a
CB
35#include "config.h"
36#include "log.h"
ccfc84ca 37#include "lxclock.h"
f2363e38 38#include "utils.h"
f2363e38 39
41f68357
ÇO
40#ifdef MUTEX_DEBUGGING
41#include <execinfo.h>
42#endif
43
5b28d063
SH
44#define MAX_STACKDEPTH 25
45
ac2cecc4 46lxc_log_define(lxclock, lxc);
72d0e1cb 47
052616eb 48#ifdef MUTEX_DEBUGGING
74a3920a 49static pthread_mutex_t thread_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
41f68357 50
74a3920a 51static inline void dump_stacktrace(void)
41f68357
ÇO
52{
53 void *array[MAX_STACKDEPTH];
54 size_t size;
55 char **strings;
56 size_t i;
57
58 size = backtrace(array, MAX_STACKDEPTH);
59 strings = backtrace_symbols(array, size);
60
1a0e70ac 61 /* Using fprintf here as our logging module is not thread safe. */
b19aabf5 62 fprintf(stderr, "\tObtained %zu stack frames\n", size);
41f68357
ÇO
63
64 for (i = 0; i < size; i++)
65 fprintf(stderr, "\t\t%s\n", strings[i]);
66
157ad8d4 67 free(strings);
41f68357 68}
052616eb 69#else
74a3920a 70static pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER;
41f68357 71
74a3920a 72static inline void dump_stacktrace(void) {;}
052616eb 73#endif
df271a59 74
74a3920a 75static void lock_mutex(pthread_mutex_t *l)
41f68357
ÇO
76{
77 int ret;
78
7249588c
CB
79 ret = pthread_mutex_lock(l);
80 if (ret != 0) {
79cda71d 81 SYSERROR("Failed to acquire mutex");
41f68357 82 dump_stacktrace();
7249588c 83 _exit(EXIT_FAILURE);
41f68357
ÇO
84 }
85}
86
74a3920a 87static void unlock_mutex(pthread_mutex_t *l)
41f68357
ÇO
88{
89 int ret;
90
7249588c
CB
91 ret = pthread_mutex_unlock(l);
92 if (ret != 0) {
79cda71d 93 SYSERROR("Failed to release mutex");
41f68357 94 dump_stacktrace();
7249588c 95 _exit(EXIT_FAILURE);
41f68357
ÇO
96 }
97}
98
df271a59 99static char *lxclock_name(const char *p, const char *n)
72d0e1cb
SG
100{
101 int ret;
ecd8cb99
CB
102 size_t len;
103 char *dest, *rundir;
71b0fed6 104
469b5787 105 /* lockfile will be:
72cf81f6 106 * "/run" + "/lxc/lock/$lxcpath/$lxcname + '\0' if root
469b5787 107 * or
72cf81f6 108 * $XDG_RUNTIME_DIR + "/lxc/lock/$lxcpath/$lxcname + '\0' if non-root
469b5787
SH
109 */
110
72cf81f6 111 /* length of "/lxc/lock/" + $lxcpath + "/" + "." + $lxcname + '\0' */
6333c915 112 len = STRLITERALLEN("/lxc/lock/") + strlen(n) + strlen(p) + 3;
ecd8cb99 113
9e60f51d 114 rundir = get_rundir();
97a696c6
SG
115 if (!rundir)
116 return NULL;
79cda71d 117
469b5787
SH
118 len += strlen(rundir);
119
ecd8cb99
CB
120 dest = malloc(len);
121 if (!dest) {
44b9ae4b 122 free(rundir);
72d0e1cb 123 return NULL;
44b9ae4b 124 }
469b5787 125
72cf81f6 126 ret = snprintf(dest, len, "%s/lxc/lock/%s", rundir, p);
ecd8cb99 127 if (ret < 0 || (size_t)ret >= len) {
72d0e1cb 128 free(dest);
44b9ae4b 129 free(rundir);
72d0e1cb
SG
130 return NULL;
131 }
79cda71d 132
5cee8c50 133 ret = mkdir_p(dest, 0755);
5cee8c50 134 if (ret < 0) {
72cf81f6
SH
135 free(dest);
136 free(rundir);
137 return NULL;
138 }
72d0e1cb 139
72cf81f6 140 ret = snprintf(dest, len, "%s/lxc/lock/%s/.%s", rundir, p, n);
44b9ae4b 141 free(rundir);
ecd8cb99 142 if (ret < 0 || (size_t)ret >= len) {
df271a59
SH
143 free(dest);
144 return NULL;
145 }
79cda71d 146
df271a59 147 return dest;
72d0e1cb
SG
148}
149
150static sem_t *lxc_new_unnamed_sem(void)
151{
87677950 152 int ret;
ecd8cb99 153 sem_t *s;
72d0e1cb 154
87677950
SH
155 s = malloc(sizeof(*s));
156 if (!s)
157 return NULL;
79cda71d 158
87677950 159 ret = sem_init(s, 0, 1);
ecd8cb99 160 if (ret < 0) {
bdb539b8 161 free(s);
87677950 162 return NULL;
bdb539b8 163 }
79cda71d 164
87677950 165 return s;
72d0e1cb
SG
166}
167
df271a59 168struct lxc_lock *lxc_newlock(const char *lxcpath, const char *name)
72d0e1cb 169{
df271a59 170 struct lxc_lock *l;
72d0e1cb 171
df271a59
SH
172 l = malloc(sizeof(*l));
173 if (!l)
ecd8cb99 174 goto on_error;
72d0e1cb 175
df271a59
SH
176 if (!name) {
177 l->type = LXC_LOCK_ANON_SEM;
178 l->u.sem = lxc_new_unnamed_sem();
41c3b7c7
DE
179 if (!l->u.sem) {
180 free(l);
181 l = NULL;
182 }
79cda71d 183
ecd8cb99 184 goto on_error;
df271a59
SH
185 }
186
187 l->type = LXC_LOCK_FLOCK;
188 l->u.f.fname = lxclock_name(lxcpath, name);
189 if (!l->u.f.fname) {
190 free(l);
191 l = NULL;
ecd8cb99 192 goto on_error;
df271a59 193 }
79cda71d 194
df271a59
SH
195 l->u.f.fd = -1;
196
ecd8cb99 197on_error:
df271a59 198 return l;
72d0e1cb
SG
199}
200
df271a59 201int lxclock(struct lxc_lock *l, int timeout)
72d0e1cb 202{
93dc5327 203 struct flock lk;
ecd8cb99 204 int ret = -1, saved_errno = errno;
72d0e1cb 205
df271a59
SH
206 switch(l->type) {
207 case LXC_LOCK_ANON_SEM:
208 if (!timeout) {
209 ret = sem_wait(l->u.sem);
b19aabf5 210 if (ret < 0)
df271a59
SH
211 saved_errno = errno;
212 } else {
213 struct timespec ts;
79cda71d 214
ecd8cb99
CB
215 ret = clock_gettime(CLOCK_REALTIME, &ts);
216 if (ret < 0) {
df271a59 217 ret = -2;
ecd8cb99 218 goto on_error;
df271a59 219 }
79cda71d 220
df271a59
SH
221 ts.tv_sec += timeout;
222 ret = sem_timedwait(l->u.sem, &ts);
b19aabf5 223 if (ret < 0)
df271a59
SH
224 saved_errno = errno;
225 }
ecd8cb99 226
df271a59
SH
227 break;
228 case LXC_LOCK_FLOCK:
229 ret = -2;
230 if (timeout) {
ecd8cb99
CB
231 ERROR("Timeouts are not supported with file locks");
232 goto on_error;
df271a59 233 }
79cda71d 234
df271a59 235 if (!l->u.f.fname) {
ecd8cb99
CB
236 ERROR("No filename set for file lock");
237 goto on_error;
df271a59 238 }
79cda71d 239
df271a59 240 if (l->u.f.fd == -1) {
b19aabf5 241 l->u.f.fd = open(l->u.f.fname, O_CREAT | O_RDWR | O_NOFOLLOW | O_CLOEXEC | O_NOCTTY, S_IWUSR | S_IRUSR);
df271a59 242 if (l->u.f.fd == -1) {
ecd8cb99 243 SYSERROR("Failed to open \"%s\"", l->u.f.fname);
98375790 244 saved_errno = errno;
ecd8cb99 245 goto on_error;
df271a59
SH
246 }
247 }
79cda71d 248
b19aabf5 249 memset(&lk, 0, sizeof(struct flock));
79cda71d 250
93dc5327
SH
251 lk.l_type = F_WRLCK;
252 lk.l_whence = SEEK_SET;
79cda71d 253
b19aabf5
CB
254 ret = fcntl(l->u.f.fd, F_OFD_SETLKW, &lk);
255 if (ret < 0) {
256 if (errno == EINVAL)
257 ret = flock(l->u.f.fd, LOCK_EX);
df271a59 258 saved_errno = errno;
b19aabf5 259 }
ecd8cb99 260
df271a59 261 break;
72d0e1cb
SG
262 }
263
ecd8cb99 264on_error:
df271a59 265 errno = saved_errno;
72d0e1cb
SG
266 return ret;
267}
268
df271a59 269int lxcunlock(struct lxc_lock *l)
72d0e1cb 270{
93dc5327 271 struct flock lk;
ecd8cb99 272 int ret = 0, saved_errno = errno;
df271a59 273
ecd8cb99 274 switch (l->type) {
df271a59 275 case LXC_LOCK_ANON_SEM:
ecd8cb99 276 if (!l->u.sem) {
df271a59 277 ret = -2;
ecd8cb99 278 } else {
df271a59
SH
279 ret = sem_post(l->u.sem);
280 saved_errno = errno;
659aa061 281 }
ecd8cb99 282
df271a59
SH
283 break;
284 case LXC_LOCK_FLOCK:
285 if (l->u.f.fd != -1) {
b19aabf5 286 memset(&lk, 0, sizeof(struct flock));
79cda71d 287
93dc5327
SH
288 lk.l_type = F_UNLCK;
289 lk.l_whence = SEEK_SET;
79cda71d 290
b19aabf5
CB
291 ret = fcntl(l->u.f.fd, F_OFD_SETLK, &lk);
292 if (ret < 0) {
293 if (errno == EINVAL)
294 ret = flock(l->u.f.fd, LOCK_EX | LOCK_NB);
df271a59 295 saved_errno = errno;
b19aabf5 296 }
79cda71d 297
df271a59
SH
298 close(l->u.f.fd);
299 l->u.f.fd = -1;
ecd8cb99 300 } else {
df271a59 301 ret = -2;
ecd8cb99
CB
302 }
303
df271a59
SH
304 break;
305 }
306
df271a59
SH
307 errno = saved_errno;
308 return ret;
309}
310
5cee8c50
SH
311/*
312 * lxc_putlock() is only called when a container_new() fails,
313 * or during container_put(), which is already guaranteed to
314 * only be done by one task.
315 * So the only exclusion we need to provide here is for regular
316 * thread safety (i.e. file descriptor table changes).
317 */
df271a59
SH
318void lxc_putlock(struct lxc_lock *l)
319{
df271a59 320 if (!l)
5cee8c50 321 return;
79cda71d 322
df271a59
SH
323 switch(l->type) {
324 case LXC_LOCK_ANON_SEM:
41c3b7c7 325 if (l->u.sem) {
527dacf6 326 sem_destroy(l->u.sem);
41c3b7c7
DE
327 free(l->u.sem);
328 l->u.sem = NULL;
329 }
ecd8cb99 330
df271a59
SH
331 break;
332 case LXC_LOCK_FLOCK:
333 if (l->u.f.fd != -1) {
334 close(l->u.f.fd);
335 l->u.f.fd = -1;
336 }
79cda71d 337
f10fad2f
ME
338 free(l->u.f.fname);
339 l->u.f.fname = NULL;
ecd8cb99 340
df271a59
SH
341 break;
342 }
ecd8cb99 343
41c3b7c7 344 free(l);
5cee8c50
SH
345}
346
025ed0f3 347void process_lock(void)
5cee8c50 348{
41f68357 349 lock_mutex(&thread_mutex);
5cee8c50
SH
350}
351
352void process_unlock(void)
353{
41f68357
ÇO
354 unlock_mutex(&thread_mutex);
355}
052616eb 356
5cee8c50
SH
357int container_mem_lock(struct lxc_container *c)
358{
359 return lxclock(c->privlock, 0);
360}
361
362void container_mem_unlock(struct lxc_container *c)
363{
364 lxcunlock(c->privlock);
365}
366
367int container_disk_lock(struct lxc_container *c)
368{
369 int ret;
370
ecd8cb99
CB
371 ret = lxclock(c->privlock, 0);
372 if (ret < 0)
5cee8c50 373 return ret;
79cda71d 374
ecd8cb99
CB
375 ret = lxclock(c->slock, 0);
376 if (ret < 0) {
5cee8c50
SH
377 lxcunlock(c->privlock);
378 return ret;
379 }
79cda71d 380
5cee8c50
SH
381 return 0;
382}
383
384void container_disk_unlock(struct lxc_container *c)
385{
386 lxcunlock(c->slock);
387 lxcunlock(c->privlock);
388}