]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/lxclock.c
github: Update for main branch
[mirror_lxc.git] / src / lxc / lxclock.c
CommitLineData
cc73685d 1/* SPDX-License-Identifier: LGPL-2.1+ */
72d0e1cb 2
1160ce89
CB
3#include "config.h"
4
df271a59 5#include <errno.h>
93dc5327 6#include <fcntl.h>
56474555 7#include <malloc.h>
052616eb 8#include <pthread.h>
56474555
CB
9#include <stdio.h>
10#include <stdlib.h>
11#include <sys/file.h>
12#include <unistd.h>
f2363e38 13
12ae2a33 14#include "lxc.h"
72d0e1cb 15
d38dd64a 16#include "log.h"
ccfc84ca 17#include "lxclock.h"
a04dc637 18#include "memory_utils.h"
f2363e38 19#include "utils.h"
f2363e38 20
41f68357
ÇO
21#ifdef MUTEX_DEBUGGING
22#include <execinfo.h>
23#endif
24
5b28d063
SH
25#define MAX_STACKDEPTH 25
26
ac2cecc4 27lxc_log_define(lxclock, lxc);
72d0e1cb 28
052616eb 29#ifdef MUTEX_DEBUGGING
74a3920a 30static pthread_mutex_t thread_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
41f68357 31
74a3920a 32static inline void dump_stacktrace(void)
41f68357
ÇO
33{
34 void *array[MAX_STACKDEPTH];
35 size_t size;
36 char **strings;
41f68357
ÇO
37
38 size = backtrace(array, MAX_STACKDEPTH);
39 strings = backtrace_symbols(array, size);
40
1a0e70ac 41 /* Using fprintf here as our logging module is not thread safe. */
b19aabf5 42 fprintf(stderr, "\tObtained %zu stack frames\n", size);
41f68357 43
e00c91eb 44 for (int i = 0; i < size; i++)
41f68357
ÇO
45 fprintf(stderr, "\t\t%s\n", strings[i]);
46
157ad8d4 47 free(strings);
41f68357 48}
052616eb 49#else
74a3920a 50static pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER;
41f68357 51
74a3920a 52static inline void dump_stacktrace(void) {;}
052616eb 53#endif
df271a59 54
74a3920a 55static void lock_mutex(pthread_mutex_t *l)
41f68357
ÇO
56{
57 int ret;
58
7249588c
CB
59 ret = pthread_mutex_lock(l);
60 if (ret != 0) {
79cda71d 61 SYSERROR("Failed to acquire mutex");
41f68357 62 dump_stacktrace();
7249588c 63 _exit(EXIT_FAILURE);
41f68357
ÇO
64 }
65}
66
74a3920a 67static void unlock_mutex(pthread_mutex_t *l)
41f68357
ÇO
68{
69 int ret;
70
7249588c
CB
71 ret = pthread_mutex_unlock(l);
72 if (ret != 0) {
79cda71d 73 SYSERROR("Failed to release mutex");
41f68357 74 dump_stacktrace();
7249588c 75 _exit(EXIT_FAILURE);
41f68357
ÇO
76 }
77}
78
df271a59 79static char *lxclock_name(const char *p, const char *n)
72d0e1cb 80{
f175de7c 81 __do_free char *dest = NULL, *rundir = NULL;
72d0e1cb 82 int ret;
ecd8cb99 83 size_t len;
71b0fed6 84
469b5787 85 /* lockfile will be:
72cf81f6 86 * "/run" + "/lxc/lock/$lxcpath/$lxcname + '\0' if root
469b5787 87 * or
72cf81f6 88 * $XDG_RUNTIME_DIR + "/lxc/lock/$lxcpath/$lxcname + '\0' if non-root
469b5787
SH
89 */
90
72cf81f6 91 /* length of "/lxc/lock/" + $lxcpath + "/" + "." + $lxcname + '\0' */
6333c915 92 len = STRLITERALLEN("/lxc/lock/") + strlen(n) + strlen(p) + 3;
ecd8cb99 93
9e60f51d 94 rundir = get_rundir();
97a696c6
SG
95 if (!rundir)
96 return NULL;
79cda71d 97
469b5787
SH
98 len += strlen(rundir);
99
ecd8cb99 100 dest = malloc(len);
82c1fd64 101 if (!dest)
72d0e1cb 102 return NULL;
469b5787 103
ff88c2b4
CB
104 ret = strnprintf(dest, len, "%s/lxc/lock/%s", rundir, p);
105 if (ret < 0)
106 return NULL;
79cda71d 107
539c3977 108 ret = lxc_mkdir_p(dest, 0755);
f175de7c 109 if (ret < 0)
72cf81f6 110 return NULL;
72d0e1cb 111
ff88c2b4
CB
112 ret = strnprintf(dest, len, "%s/lxc/lock/%s/.%s", rundir, p, n);
113 if (ret < 0)
114 return NULL;
79cda71d 115
f175de7c 116 return move_ptr(dest);
72d0e1cb
SG
117}
118
119static sem_t *lxc_new_unnamed_sem(void)
120{
82c1fd64 121 __do_free sem_t *s = NULL;
87677950 122 int ret;
72d0e1cb 123
87677950
SH
124 s = malloc(sizeof(*s));
125 if (!s)
82c1fd64 126 return ret_set_errno(NULL, ENOMEM);
79cda71d 127
87677950 128 ret = sem_init(s, 0, 1);
82c1fd64 129 if (ret < 0)
87677950 130 return NULL;
79cda71d 131
82c1fd64 132 return move_ptr(s);
72d0e1cb
SG
133}
134
df271a59 135struct lxc_lock *lxc_newlock(const char *lxcpath, const char *name)
72d0e1cb 136{
a04dc637 137 __do_free struct lxc_lock *l = NULL;
72d0e1cb 138
a04dc637 139 l = zalloc(sizeof(*l));
df271a59 140 if (!l)
a04dc637
CB
141 return ret_set_errno(NULL, ENOMEM);
142
143 if (name) {
144 l->type = LXC_LOCK_FLOCK;
145 l->u.f.fname = lxclock_name(lxcpath, name);
146 if (!l->u.f.fname)
147 return ret_set_errno(NULL, ENOMEM);
148 l->u.f.fd = -EBADF;
149 } else {
df271a59
SH
150 l->type = LXC_LOCK_ANON_SEM;
151 l->u.sem = lxc_new_unnamed_sem();
a04dc637
CB
152 if (!l->u.sem)
153 return ret_set_errno(NULL, ENOMEM);
df271a59
SH
154 }
155
a04dc637 156 return move_ptr(l);
72d0e1cb
SG
157}
158
df271a59 159int lxclock(struct lxc_lock *l, int timeout)
72d0e1cb 160{
2263fd99 161 int ret = -1;
93dc5327 162 struct flock lk;
72d0e1cb 163
2263fd99 164 switch (l->type) {
df271a59
SH
165 case LXC_LOCK_ANON_SEM:
166 if (!timeout) {
167 ret = sem_wait(l->u.sem);
df271a59
SH
168 } else {
169 struct timespec ts;
79cda71d 170
ecd8cb99 171 ret = clock_gettime(CLOCK_REALTIME, &ts);
2263fd99
CB
172 if (ret < 0)
173 return -2;
79cda71d 174
df271a59
SH
175 ts.tv_sec += timeout;
176 ret = sem_timedwait(l->u.sem, &ts);
df271a59 177 }
ecd8cb99 178
df271a59
SH
179 break;
180 case LXC_LOCK_FLOCK:
2263fd99
CB
181 if (timeout)
182 return log_error(-2, "Timeouts are not supported with file locks");
79cda71d 183
2263fd99
CB
184 if (!l->u.f.fname)
185 return log_error(-2, "No filename set for file lock");
79cda71d 186
2263fd99 187 if (l->u.f.fd < 0) {
b19aabf5 188 l->u.f.fd = open(l->u.f.fname, O_CREAT | O_RDWR | O_NOFOLLOW | O_CLOEXEC | O_NOCTTY, S_IWUSR | S_IRUSR);
2263fd99
CB
189 if (l->u.f.fd < 0)
190 return log_error_errno(-2, errno, "Failed to open \"%s\"", l->u.f.fname);
df271a59 191 }
79cda71d 192
b19aabf5 193 memset(&lk, 0, sizeof(struct flock));
79cda71d 194
93dc5327
SH
195 lk.l_type = F_WRLCK;
196 lk.l_whence = SEEK_SET;
79cda71d 197
b19aabf5 198 ret = fcntl(l->u.f.fd, F_OFD_SETLKW, &lk);
2263fd99
CB
199 if (ret < 0 && errno == EINVAL)
200 ret = flock(l->u.f.fd, LOCK_EX);
df271a59 201 break;
2263fd99
CB
202 default:
203 return ret_set_errno(-1, EINVAL);
72d0e1cb
SG
204 }
205
206 return ret;
207}
208
df271a59 209int lxcunlock(struct lxc_lock *l)
72d0e1cb 210{
93dc5327 211 struct flock lk;
129c915f 212 int ret = 0;
df271a59 213
ecd8cb99 214 switch (l->type) {
df271a59 215 case LXC_LOCK_ANON_SEM:
129c915f
CB
216 if (!l->u.sem)
217 return -2;
ecd8cb99 218
129c915f 219 ret = sem_post(l->u.sem);
df271a59
SH
220 break;
221 case LXC_LOCK_FLOCK:
129c915f
CB
222 if (l->u.f.fd < 0)
223 return -2;
79cda71d 224
129c915f 225 memset(&lk, 0, sizeof(struct flock));
79cda71d 226
129c915f
CB
227 lk.l_type = F_UNLCK;
228 lk.l_whence = SEEK_SET;
79cda71d 229
129c915f
CB
230 ret = fcntl(l->u.f.fd, F_OFD_SETLK, &lk);
231 if (ret < 0 && errno == EINVAL)
232 ret = flock(l->u.f.fd, LOCK_EX | LOCK_NB);
ecd8cb99 233
129c915f 234 close_prot_errno_disarm(l->u.f.fd);
df271a59 235 break;
129c915f
CB
236 default:
237 return ret_set_errno(-1, EINVAL);
df271a59
SH
238 }
239
df271a59
SH
240 return ret;
241}
242
5cee8c50
SH
243/*
244 * lxc_putlock() is only called when a container_new() fails,
245 * or during container_put(), which is already guaranteed to
246 * only be done by one task.
247 * So the only exclusion we need to provide here is for regular
248 * thread safety (i.e. file descriptor table changes).
249 */
df271a59
SH
250void lxc_putlock(struct lxc_lock *l)
251{
df271a59 252 if (!l)
5cee8c50 253 return;
79cda71d 254
e4423229 255 switch (l->type) {
df271a59 256 case LXC_LOCK_ANON_SEM:
41c3b7c7 257 if (l->u.sem) {
527dacf6 258 sem_destroy(l->u.sem);
e4423229 259 free_disarm(l->u.sem);
41c3b7c7 260 }
df271a59
SH
261 break;
262 case LXC_LOCK_FLOCK:
e4423229
CB
263 close_prot_errno_disarm(l->u.f.fd);
264 free_disarm(l->u.f.fname);
df271a59
SH
265 break;
266 }
ecd8cb99 267
41c3b7c7 268 free(l);
5cee8c50
SH
269}
270
025ed0f3 271void process_lock(void)
5cee8c50 272{
41f68357 273 lock_mutex(&thread_mutex);
5cee8c50
SH
274}
275
276void process_unlock(void)
277{
41f68357
ÇO
278 unlock_mutex(&thread_mutex);
279}
052616eb 280
5cee8c50
SH
281int container_mem_lock(struct lxc_container *c)
282{
283 return lxclock(c->privlock, 0);
284}
285
286void container_mem_unlock(struct lxc_container *c)
287{
288 lxcunlock(c->privlock);
289}
290
291int container_disk_lock(struct lxc_container *c)
292{
293 int ret;
294
ecd8cb99
CB
295 ret = lxclock(c->privlock, 0);
296 if (ret < 0)
5cee8c50 297 return ret;
79cda71d 298
ecd8cb99
CB
299 ret = lxclock(c->slock, 0);
300 if (ret < 0) {
5cee8c50
SH
301 lxcunlock(c->privlock);
302 return ret;
303 }
79cda71d 304
5cee8c50
SH
305 return 0;
306}
307
308void container_disk_unlock(struct lxc_container *c)
309{
310 lxcunlock(c->slock);
311 lxcunlock(c->privlock);
312}