]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxclock.c
Set a reasonable fallback for get_rundir
[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\n", 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\n", 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 if (!rundir)
113 return NULL;
114 len += strlen(rundir);
115
116 if ((dest = malloc(len)) == NULL)
117 return NULL;
118
119 ret = snprintf(dest, len, "%s/lock/lxc/%s", rundir, p);
120 if (ret < 0 || ret >= len) {
121 free(dest);
122 return NULL;
123 }
124 ret = mkdir_p(dest, 0755);
125 if (ret < 0) {
126 /* fall back to "/tmp/" $(id -u) "/lxc/" $lxcpath / $lxcname + '\0' */
127 int l2 = 33 + strlen(n) + strlen(p);
128 if (l2 > len) {
129 char *d;
130 d = realloc(dest, l2);
131 if (!d) {
132 free(dest);
133 return NULL;
134 }
135 len = l2;
136 dest = d;
137 }
138 ret = snprintf(dest, len, "/tmp/%d/lxc/%s", geteuid(), p);
139 if (ret < 0 || ret >= len) {
140 free(dest);
141 return NULL;
142 }
143 ret = snprintf(dest, len, "/tmp/%d/lxc/%s/%s", geteuid(), p, n);
144 } else
145 ret = snprintf(dest, len, "%s/lock/lxc/%s/%s", rundir, p, n);
146
147 if (ret < 0 || ret >= len) {
148 free(dest);
149 return NULL;
150 }
151 return dest;
152 }
153
154 static sem_t *lxc_new_unnamed_sem(void)
155 {
156 sem_t *s;
157 int ret;
158
159 s = malloc(sizeof(*s));
160 if (!s)
161 return NULL;
162 ret = sem_init(s, 0, 1);
163 if (ret) {
164 free(s);
165 return NULL;
166 }
167 return s;
168 }
169
170 struct lxc_lock *lxc_newlock(const char *lxcpath, const char *name)
171 {
172 struct lxc_lock *l;
173
174 l = malloc(sizeof(*l));
175 if (!l)
176 goto out;
177
178 if (!name) {
179 l->type = LXC_LOCK_ANON_SEM;
180 l->u.sem = lxc_new_unnamed_sem();
181 if (!l->u.sem) {
182 free(l);
183 l = NULL;
184 }
185 goto out;
186 }
187
188 l->type = LXC_LOCK_FLOCK;
189 l->u.f.fname = lxclock_name(lxcpath, name);
190 if (!l->u.f.fname) {
191 free(l);
192 l = NULL;
193 goto out;
194 }
195 l->u.f.fd = -1;
196
197 out:
198 return l;
199 }
200
201 int lxclock(struct lxc_lock *l, int timeout)
202 {
203 int ret = -1, saved_errno = errno;
204 struct flock lk;
205
206 switch(l->type) {
207 case LXC_LOCK_ANON_SEM:
208 if (!timeout) {
209 ret = sem_wait(l->u.sem);
210 if (ret == -1)
211 saved_errno = errno;
212 } else {
213 struct timespec ts;
214 if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
215 ret = -2;
216 goto out;
217 }
218 ts.tv_sec += timeout;
219 ret = sem_timedwait(l->u.sem, &ts);
220 if (ret == -1)
221 saved_errno = errno;
222 }
223 break;
224 case LXC_LOCK_FLOCK:
225 ret = -2;
226 if (timeout) {
227 ERROR("Error: timeout not supported with flock");
228 ret = -2;
229 goto out;
230 }
231 if (!l->u.f.fname) {
232 ERROR("Error: filename not set for flock");
233 ret = -2;
234 goto out;
235 }
236 if (l->u.f.fd == -1) {
237 l->u.f.fd = open(l->u.f.fname, O_RDWR|O_CREAT,
238 S_IWUSR | S_IRUSR);
239 if (l->u.f.fd == -1) {
240 ERROR("Error opening %s", l->u.f.fname);
241 goto out;
242 }
243 }
244 lk.l_type = F_WRLCK;
245 lk.l_whence = SEEK_SET;
246 lk.l_start = 0;
247 lk.l_len = 0;
248 ret = fcntl(l->u.f.fd, F_SETLKW, &lk);
249 if (ret == -1)
250 saved_errno = errno;
251 break;
252 }
253
254 out:
255 errno = saved_errno;
256 return ret;
257 }
258
259 int lxcunlock(struct lxc_lock *l)
260 {
261 int ret = 0, saved_errno = errno;
262 struct flock lk;
263
264 switch(l->type) {
265 case LXC_LOCK_ANON_SEM:
266 if (!l->u.sem)
267 ret = -2;
268 else {
269 ret = sem_post(l->u.sem);
270 saved_errno = errno;
271 }
272 break;
273 case LXC_LOCK_FLOCK:
274 if (l->u.f.fd != -1) {
275 lk.l_type = F_UNLCK;
276 lk.l_whence = SEEK_SET;
277 lk.l_start = 0;
278 lk.l_len = 0;
279 ret = fcntl(l->u.f.fd, F_SETLK, &lk);
280 if (ret < 0)
281 saved_errno = errno;
282 close(l->u.f.fd);
283 l->u.f.fd = -1;
284 } else
285 ret = -2;
286 break;
287 }
288
289 errno = saved_errno;
290 return ret;
291 }
292
293 /*
294 * lxc_putlock() is only called when a container_new() fails,
295 * or during container_put(), which is already guaranteed to
296 * only be done by one task.
297 * So the only exclusion we need to provide here is for regular
298 * thread safety (i.e. file descriptor table changes).
299 */
300 void lxc_putlock(struct lxc_lock *l)
301 {
302 if (!l)
303 return;
304 switch(l->type) {
305 case LXC_LOCK_ANON_SEM:
306 if (l->u.sem) {
307 sem_destroy(l->u.sem);
308 free(l->u.sem);
309 l->u.sem = NULL;
310 }
311 break;
312 case LXC_LOCK_FLOCK:
313 if (l->u.f.fd != -1) {
314 close(l->u.f.fd);
315 l->u.f.fd = -1;
316 }
317 if (l->u.f.fname) {
318 free(l->u.f.fname);
319 l->u.f.fname = NULL;
320 }
321 break;
322 }
323 free(l);
324 }
325
326 void process_lock(void)
327 {
328 lock_mutex(&thread_mutex);
329 }
330
331 void process_unlock(void)
332 {
333 unlock_mutex(&thread_mutex);
334 }
335
336 /* One thread can do fork() while another one is holding a mutex.
337 * There is only one thread in child just after the fork(), so noone will ever release that mutex.
338 * We setup a "child" fork handler to unlock the mutex just after the fork().
339 * For several mutex types, unlocking an unlocked mutex can lead to undefined behavior.
340 * One way to deal with it is to setup "prepare" fork handler
341 * to lock the mutex before fork() and both "parent" and "child" fork handlers
342 * to unlock the mutex.
343 * This forbids doing fork() while explicitly holding the lock.
344 */
345 #ifdef HAVE_PTHREAD_ATFORK
346 __attribute__((constructor))
347 static void process_lock_setup_atfork(void)
348 {
349 pthread_atfork(process_lock, process_unlock, process_unlock);
350 }
351 #endif
352
353 int container_mem_lock(struct lxc_container *c)
354 {
355 return lxclock(c->privlock, 0);
356 }
357
358 void container_mem_unlock(struct lxc_container *c)
359 {
360 lxcunlock(c->privlock);
361 }
362
363 int container_disk_lock(struct lxc_container *c)
364 {
365 int ret;
366
367 if ((ret = lxclock(c->privlock, 0)))
368 return ret;
369 if ((ret = lxclock(c->slock, 0))) {
370 lxcunlock(c->privlock);
371 return ret;
372 }
373 return 0;
374 }
375
376 void container_disk_unlock(struct lxc_container *c)
377 {
378 lxcunlock(c->slock);
379 lxcunlock(c->privlock);
380 }