1 /* SPDX-License-Identifier: LGPL-2.1+ */
15 #include <lxc/lxccontainer.h>
20 #include "memory_utils.h"
23 #ifdef MUTEX_DEBUGGING
27 #define MAX_STACKDEPTH 25
29 lxc_log_define(lxclock
, lxc
);
31 #ifdef MUTEX_DEBUGGING
32 static pthread_mutex_t thread_mutex
= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
;
34 static inline void dump_stacktrace(void)
36 void *array
[MAX_STACKDEPTH
];
40 size
= backtrace(array
, MAX_STACKDEPTH
);
41 strings
= backtrace_symbols(array
, size
);
43 /* Using fprintf here as our logging module is not thread safe. */
44 fprintf(stderr
, "\tObtained %zu stack frames\n", size
);
46 for (int i
= 0; i
< size
; i
++)
47 fprintf(stderr
, "\t\t%s\n", strings
[i
]);
52 static pthread_mutex_t thread_mutex
= PTHREAD_MUTEX_INITIALIZER
;
54 static inline void dump_stacktrace(void) {;}
57 static void lock_mutex(pthread_mutex_t
*l
)
61 ret
= pthread_mutex_lock(l
);
63 SYSERROR("Failed to acquire mutex");
69 static void unlock_mutex(pthread_mutex_t
*l
)
73 ret
= pthread_mutex_unlock(l
);
75 SYSERROR("Failed to release mutex");
81 static char *lxclock_name(const char *p
, const char *n
)
83 __do_free
char *dest
= NULL
, *rundir
= NULL
;
88 * "/run" + "/lxc/lock/$lxcpath/$lxcname + '\0' if root
90 * $XDG_RUNTIME_DIR + "/lxc/lock/$lxcpath/$lxcname + '\0' if non-root
93 /* length of "/lxc/lock/" + $lxcpath + "/" + "." + $lxcname + '\0' */
94 len
= STRLITERALLEN("/lxc/lock/") + strlen(n
) + strlen(p
) + 3;
96 rundir
= get_rundir();
100 len
+= strlen(rundir
);
106 ret
= strnprintf(dest
, len
, "%s/lxc/lock/%s", rundir
, p
);
110 ret
= mkdir_p(dest
, 0755);
114 ret
= strnprintf(dest
, len
, "%s/lxc/lock/%s/.%s", rundir
, p
, n
);
118 return move_ptr(dest
);
121 static sem_t
*lxc_new_unnamed_sem(void)
123 __do_free sem_t
*s
= NULL
;
126 s
= malloc(sizeof(*s
));
128 return ret_set_errno(NULL
, ENOMEM
);
130 ret
= sem_init(s
, 0, 1);
137 struct lxc_lock
*lxc_newlock(const char *lxcpath
, const char *name
)
139 __do_free
struct lxc_lock
*l
= NULL
;
141 l
= zalloc(sizeof(*l
));
143 return ret_set_errno(NULL
, ENOMEM
);
146 l
->type
= LXC_LOCK_FLOCK
;
147 l
->u
.f
.fname
= lxclock_name(lxcpath
, name
);
149 return ret_set_errno(NULL
, ENOMEM
);
152 l
->type
= LXC_LOCK_ANON_SEM
;
153 l
->u
.sem
= lxc_new_unnamed_sem();
155 return ret_set_errno(NULL
, ENOMEM
);
161 int lxclock(struct lxc_lock
*l
, int timeout
)
167 case LXC_LOCK_ANON_SEM
:
169 ret
= sem_wait(l
->u
.sem
);
173 ret
= clock_gettime(CLOCK_REALTIME
, &ts
);
177 ts
.tv_sec
+= timeout
;
178 ret
= sem_timedwait(l
->u
.sem
, &ts
);
184 return log_error(-2, "Timeouts are not supported with file locks");
187 return log_error(-2, "No filename set for file lock");
190 l
->u
.f
.fd
= open(l
->u
.f
.fname
, O_CREAT
| O_RDWR
| O_NOFOLLOW
| O_CLOEXEC
| O_NOCTTY
, S_IWUSR
| S_IRUSR
);
192 return log_error_errno(-2, errno
, "Failed to open \"%s\"", l
->u
.f
.fname
);
195 memset(&lk
, 0, sizeof(struct flock
));
198 lk
.l_whence
= SEEK_SET
;
200 ret
= fcntl(l
->u
.f
.fd
, F_OFD_SETLKW
, &lk
);
201 if (ret
< 0 && errno
== EINVAL
)
202 ret
= flock(l
->u
.f
.fd
, LOCK_EX
);
205 return ret_set_errno(-1, EINVAL
);
211 int lxcunlock(struct lxc_lock
*l
)
217 case LXC_LOCK_ANON_SEM
:
221 ret
= sem_post(l
->u
.sem
);
227 memset(&lk
, 0, sizeof(struct flock
));
230 lk
.l_whence
= SEEK_SET
;
232 ret
= fcntl(l
->u
.f
.fd
, F_OFD_SETLK
, &lk
);
233 if (ret
< 0 && errno
== EINVAL
)
234 ret
= flock(l
->u
.f
.fd
, LOCK_EX
| LOCK_NB
);
236 close_prot_errno_disarm(l
->u
.f
.fd
);
239 return ret_set_errno(-1, EINVAL
);
246 * lxc_putlock() is only called when a container_new() fails,
247 * or during container_put(), which is already guaranteed to
248 * only be done by one task.
249 * So the only exclusion we need to provide here is for regular
250 * thread safety (i.e. file descriptor table changes).
252 void lxc_putlock(struct lxc_lock
*l
)
258 case LXC_LOCK_ANON_SEM
:
260 sem_destroy(l
->u
.sem
);
261 free_disarm(l
->u
.sem
);
265 close_prot_errno_disarm(l
->u
.f
.fd
);
266 free_disarm(l
->u
.f
.fname
);
273 void process_lock(void)
275 lock_mutex(&thread_mutex
);
278 void process_unlock(void)
280 unlock_mutex(&thread_mutex
);
283 int container_mem_lock(struct lxc_container
*c
)
285 return lxclock(c
->privlock
, 0);
288 void container_mem_unlock(struct lxc_container
*c
)
290 lxcunlock(c
->privlock
);
293 int container_disk_lock(struct lxc_container
*c
)
297 ret
= lxclock(c
->privlock
, 0);
301 ret
= lxclock(c
->slock
, 0);
303 lxcunlock(c
->privlock
);
310 void container_disk_unlock(struct lxc_container
*c
)
313 lxcunlock(c
->privlock
);