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