3 * Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
4 * Copyright © 2012 Canonical Ltd.
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.
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.
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
31 #include <lxc/lxccontainer.h>
36 #ifdef MUTEX_DEBUGGING
40 #define OFLAG (O_CREAT | O_RDWR)
43 #define SEMVALUE_LOCKED 0
45 lxc_log_define(lxc_lock
, lxc
);
47 #ifdef MUTEX_DEBUGGING
48 static pthread_mutex_t thread_mutex
= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
;
50 static inline void dump_stacktrace(void)
52 void *array
[MAX_STACKDEPTH
];
57 size
= backtrace(array
, MAX_STACKDEPTH
);
58 strings
= backtrace_symbols(array
, size
);
60 // Using fprintf here as our logging module is not thread safe
61 fprintf(stderr
, "\tObtained %zd stack frames.\n", size
);
63 for (i
= 0; i
< size
; i
++)
64 fprintf(stderr
, "\t\t%s\n", strings
[i
]);
69 static pthread_mutex_t thread_mutex
= PTHREAD_MUTEX_INITIALIZER
;
71 static inline void dump_stacktrace(void) {;}
74 static void lock_mutex(pthread_mutex_t
*l
)
78 if ((ret
= pthread_mutex_lock(l
)) != 0) {
79 fprintf(stderr
, "pthread_mutex_lock returned:%d %s\n", ret
, strerror(ret
));
85 static void unlock_mutex(pthread_mutex_t
*l
)
89 if ((ret
= pthread_mutex_unlock(l
)) != 0) {
90 fprintf(stderr
, "pthread_mutex_unlock returned:%d %s\n", ret
, strerror(ret
));
96 static char *lxclock_name(const char *p
, const char *n
)
104 * "/run" + "/lock/lxc/$lxcpath/$lxcname + '\0' if root
106 * $XDG_RUNTIME_DIR + "/lock/lxc/$lxcpath/$lxcname + '\0' if non-root
109 /* length of "/lock/lxc/" + $lxcpath + "/" + $lxcname + '\0' */
110 len
= strlen("/lock/lxc/") + strlen(n
) + strlen(p
) + 2;
111 rundir
= get_rundir();
114 len
+= strlen(rundir
);
116 if ((dest
= malloc(len
)) == NULL
)
119 ret
= snprintf(dest
, len
, "%s/lock/lxc/%s", rundir
, p
);
120 if (ret
< 0 || ret
>= len
) {
124 ret
= mkdir_p(dest
, 0755);
126 /* fall back to "/tmp/" $(id -u) "/lxc/" $lxcpath / $lxcname + '\0' */
127 int l2
= 33 + strlen(n
) + strlen(p
);
130 d
= realloc(dest
, l2
);
138 ret
= snprintf(dest
, len
, "/tmp/%d/lxc/%s", geteuid(), p
);
139 if (ret
< 0 || ret
>= len
) {
143 ret
= snprintf(dest
, len
, "/tmp/%d/lxc/%s/%s", geteuid(), p
, n
);
145 ret
= snprintf(dest
, len
, "%s/lock/lxc/%s/%s", rundir
, p
, n
);
147 if (ret
< 0 || ret
>= len
) {
154 static sem_t
*lxc_new_unnamed_sem(void)
159 s
= malloc(sizeof(*s
));
162 ret
= sem_init(s
, 0, 1);
170 struct lxc_lock
*lxc_newlock(const char *lxcpath
, const char *name
)
174 l
= malloc(sizeof(*l
));
179 l
->type
= LXC_LOCK_ANON_SEM
;
180 l
->u
.sem
= lxc_new_unnamed_sem();
188 l
->type
= LXC_LOCK_FLOCK
;
189 l
->u
.f
.fname
= lxclock_name(lxcpath
, name
);
201 int lxclock(struct lxc_lock
*l
, int timeout
)
203 int ret
= -1, saved_errno
= errno
;
207 case LXC_LOCK_ANON_SEM
:
209 ret
= sem_wait(l
->u
.sem
);
214 if (clock_gettime(CLOCK_REALTIME
, &ts
) == -1) {
218 ts
.tv_sec
+= timeout
;
219 ret
= sem_timedwait(l
->u
.sem
, &ts
);
227 ERROR("Error: timeout not supported with flock");
232 ERROR("Error: filename not set for flock");
236 if (l
->u
.f
.fd
== -1) {
237 l
->u
.f
.fd
= open(l
->u
.f
.fname
, O_RDWR
|O_CREAT
,
239 if (l
->u
.f
.fd
== -1) {
240 ERROR("Error opening %s", l
->u
.f
.fname
);
245 lk
.l_whence
= SEEK_SET
;
248 ret
= fcntl(l
->u
.f
.fd
, F_SETLKW
, &lk
);
259 int lxcunlock(struct lxc_lock
*l
)
261 int ret
= 0, saved_errno
= errno
;
265 case LXC_LOCK_ANON_SEM
:
269 ret
= sem_post(l
->u
.sem
);
274 if (l
->u
.f
.fd
!= -1) {
276 lk
.l_whence
= SEEK_SET
;
279 ret
= fcntl(l
->u
.f
.fd
, F_SETLK
, &lk
);
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).
300 void lxc_putlock(struct lxc_lock
*l
)
305 case LXC_LOCK_ANON_SEM
:
307 sem_destroy(l
->u
.sem
);
313 if (l
->u
.f
.fd
!= -1) {
326 void process_lock(void)
328 lock_mutex(&thread_mutex
);
331 void process_unlock(void)
333 unlock_mutex(&thread_mutex
);
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.
345 #ifdef HAVE_PTHREAD_ATFORK
346 __attribute__((constructor
))
347 static void process_lock_setup_atfork(void)
349 pthread_atfork(process_lock
, process_unlock
, process_unlock
);
353 int container_mem_lock(struct lxc_container
*c
)
355 return lxclock(c
->privlock
, 0);
358 void container_mem_unlock(struct lxc_container
*c
)
360 lxcunlock(c
->privlock
);
363 int container_disk_lock(struct lxc_container
*c
)
367 if ((ret
= lxclock(c
->privlock
, 0)))
369 if ((ret
= lxclock(c
->slock
, 0))) {
370 lxcunlock(c
->privlock
);
376 void container_disk_unlock(struct lxc_container
*c
)
379 lxcunlock(c
->privlock
);