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
];
41 size
= backtrace(array
, MAX_STACKDEPTH
);
42 strings
= backtrace_symbols(array
, size
);
44 /* Using fprintf here as our logging module is not thread safe. */
45 fprintf(stderr
, "\tObtained %zu stack frames\n", size
);
47 for (i
= 0; i
< size
; i
++)
48 fprintf(stderr
, "\t\t%s\n", strings
[i
]);
53 static pthread_mutex_t thread_mutex
= PTHREAD_MUTEX_INITIALIZER
;
55 static inline void dump_stacktrace(void) {;}
58 static void lock_mutex(pthread_mutex_t
*l
)
62 ret
= pthread_mutex_lock(l
);
64 SYSERROR("Failed to acquire mutex");
70 static void unlock_mutex(pthread_mutex_t
*l
)
74 ret
= pthread_mutex_unlock(l
);
76 SYSERROR("Failed to release mutex");
82 static char *lxclock_name(const char *p
, const char *n
)
89 * "/run" + "/lxc/lock/$lxcpath/$lxcname + '\0' if root
91 * $XDG_RUNTIME_DIR + "/lxc/lock/$lxcpath/$lxcname + '\0' if non-root
94 /* length of "/lxc/lock/" + $lxcpath + "/" + "." + $lxcname + '\0' */
95 len
= STRLITERALLEN("/lxc/lock/") + strlen(n
) + strlen(p
) + 3;
97 rundir
= get_rundir();
101 len
+= strlen(rundir
);
107 ret
= snprintf(dest
, len
, "%s/lxc/lock/%s", rundir
, p
);
108 if (ret
< 0 || (size_t)ret
>= len
) {
114 ret
= mkdir_p(dest
, 0755);
121 ret
= snprintf(dest
, len
, "%s/lxc/lock/%s/.%s", rundir
, p
, n
);
123 if (ret
< 0 || (size_t)ret
>= len
) {
131 static sem_t
*lxc_new_unnamed_sem(void)
133 __do_free sem_t
*s
= NULL
;
136 s
= malloc(sizeof(*s
));
138 return ret_set_errno(NULL
, ENOMEM
);
140 ret
= sem_init(s
, 0, 1);
147 struct lxc_lock
*lxc_newlock(const char *lxcpath
, const char *name
)
149 __do_free
struct lxc_lock
*l
= NULL
;
151 l
= zalloc(sizeof(*l
));
153 return ret_set_errno(NULL
, ENOMEM
);
156 l
->type
= LXC_LOCK_FLOCK
;
157 l
->u
.f
.fname
= lxclock_name(lxcpath
, name
);
159 return ret_set_errno(NULL
, ENOMEM
);
162 l
->type
= LXC_LOCK_ANON_SEM
;
163 l
->u
.sem
= lxc_new_unnamed_sem();
165 return ret_set_errno(NULL
, ENOMEM
);
171 int lxclock(struct lxc_lock
*l
, int timeout
)
177 case LXC_LOCK_ANON_SEM
:
179 ret
= sem_wait(l
->u
.sem
);
183 ret
= clock_gettime(CLOCK_REALTIME
, &ts
);
187 ts
.tv_sec
+= timeout
;
188 ret
= sem_timedwait(l
->u
.sem
, &ts
);
194 return log_error(-2, "Timeouts are not supported with file locks");
197 return log_error(-2, "No filename set for file lock");
200 l
->u
.f
.fd
= open(l
->u
.f
.fname
, O_CREAT
| O_RDWR
| O_NOFOLLOW
| O_CLOEXEC
| O_NOCTTY
, S_IWUSR
| S_IRUSR
);
202 return log_error_errno(-2, errno
, "Failed to open \"%s\"", l
->u
.f
.fname
);
205 memset(&lk
, 0, sizeof(struct flock
));
208 lk
.l_whence
= SEEK_SET
;
210 ret
= fcntl(l
->u
.f
.fd
, F_OFD_SETLKW
, &lk
);
211 if (ret
< 0 && errno
== EINVAL
)
212 ret
= flock(l
->u
.f
.fd
, LOCK_EX
);
215 return ret_set_errno(-1, EINVAL
);
221 int lxcunlock(struct lxc_lock
*l
)
227 case LXC_LOCK_ANON_SEM
:
231 ret
= sem_post(l
->u
.sem
);
237 memset(&lk
, 0, sizeof(struct flock
));
240 lk
.l_whence
= SEEK_SET
;
242 ret
= fcntl(l
->u
.f
.fd
, F_OFD_SETLK
, &lk
);
243 if (ret
< 0 && errno
== EINVAL
)
244 ret
= flock(l
->u
.f
.fd
, LOCK_EX
| LOCK_NB
);
246 close_prot_errno_disarm(l
->u
.f
.fd
);
249 return ret_set_errno(-1, EINVAL
);
256 * lxc_putlock() is only called when a container_new() fails,
257 * or during container_put(), which is already guaranteed to
258 * only be done by one task.
259 * So the only exclusion we need to provide here is for regular
260 * thread safety (i.e. file descriptor table changes).
262 void lxc_putlock(struct lxc_lock
*l
)
268 case LXC_LOCK_ANON_SEM
:
270 sem_destroy(l
->u
.sem
);
277 if (l
->u
.f
.fd
>= 0) {
291 void process_lock(void)
293 lock_mutex(&thread_mutex
);
296 void process_unlock(void)
298 unlock_mutex(&thread_mutex
);
301 int container_mem_lock(struct lxc_container
*c
)
303 return lxclock(c
->privlock
, 0);
306 void container_mem_unlock(struct lxc_container
*c
)
308 lxcunlock(c
->privlock
);
311 int container_disk_lock(struct lxc_container
*c
)
315 ret
= lxclock(c
->privlock
, 0);
319 ret
= lxclock(c
->slock
, 0);
321 lxcunlock(c
->privlock
);
328 void container_disk_unlock(struct lxc_container
*c
)
331 lxcunlock(c
->privlock
);