1 /* SPDX-License-Identifier: LGPL-2.1+ */
18 #include "memory_utils.h"
21 #ifdef MUTEX_DEBUGGING
25 #define MAX_STACKDEPTH 25
27 lxc_log_define(lxclock
, lxc
);
29 #ifdef MUTEX_DEBUGGING
30 static pthread_mutex_t thread_mutex
= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
;
32 static inline void dump_stacktrace(void)
34 void *array
[MAX_STACKDEPTH
];
38 size
= backtrace(array
, MAX_STACKDEPTH
);
39 strings
= backtrace_symbols(array
, size
);
41 /* Using fprintf here as our logging module is not thread safe. */
42 fprintf(stderr
, "\tObtained %zu stack frames\n", size
);
44 for (int i
= 0; i
< size
; i
++)
45 fprintf(stderr
, "\t\t%s\n", strings
[i
]);
50 static pthread_mutex_t thread_mutex
= PTHREAD_MUTEX_INITIALIZER
;
52 static inline void dump_stacktrace(void) {;}
55 static void lock_mutex(pthread_mutex_t
*l
)
59 ret
= pthread_mutex_lock(l
);
61 SYSERROR("Failed to acquire mutex");
67 static void unlock_mutex(pthread_mutex_t
*l
)
71 ret
= pthread_mutex_unlock(l
);
73 SYSERROR("Failed to release mutex");
79 static char *lxclock_name(const char *p
, const char *n
)
81 __do_free
char *dest
= NULL
, *rundir
= NULL
;
86 * "/run" + "/lxc/lock/$lxcpath/$lxcname + '\0' if root
88 * $XDG_RUNTIME_DIR + "/lxc/lock/$lxcpath/$lxcname + '\0' if non-root
91 /* length of "/lxc/lock/" + $lxcpath + "/" + "." + $lxcname + '\0' */
92 len
= STRLITERALLEN("/lxc/lock/") + strlen(n
) + strlen(p
) + 3;
94 rundir
= get_rundir();
98 len
+= strlen(rundir
);
104 ret
= strnprintf(dest
, len
, "%s/lxc/lock/%s", rundir
, p
);
108 ret
= lxc_mkdir_p(dest
, 0755);
112 ret
= strnprintf(dest
, len
, "%s/lxc/lock/%s/.%s", rundir
, p
, n
);
116 return move_ptr(dest
);
119 static sem_t
*lxc_new_unnamed_sem(void)
121 __do_free sem_t
*s
= NULL
;
124 s
= malloc(sizeof(*s
));
126 return ret_set_errno(NULL
, ENOMEM
);
128 ret
= sem_init(s
, 0, 1);
135 struct lxc_lock
*lxc_newlock(const char *lxcpath
, const char *name
)
137 __do_free
struct lxc_lock
*l
= NULL
;
139 l
= zalloc(sizeof(*l
));
141 return ret_set_errno(NULL
, ENOMEM
);
144 l
->type
= LXC_LOCK_FLOCK
;
145 l
->u
.f
.fname
= lxclock_name(lxcpath
, name
);
147 return ret_set_errno(NULL
, ENOMEM
);
150 l
->type
= LXC_LOCK_ANON_SEM
;
151 l
->u
.sem
= lxc_new_unnamed_sem();
153 return ret_set_errno(NULL
, ENOMEM
);
159 int lxclock(struct lxc_lock
*l
, int timeout
)
165 case LXC_LOCK_ANON_SEM
:
167 ret
= sem_wait(l
->u
.sem
);
171 ret
= clock_gettime(CLOCK_REALTIME
, &ts
);
175 ts
.tv_sec
+= timeout
;
176 ret
= sem_timedwait(l
->u
.sem
, &ts
);
182 return log_error(-2, "Timeouts are not supported with file locks");
185 return log_error(-2, "No filename set for file lock");
188 l
->u
.f
.fd
= open(l
->u
.f
.fname
, O_CREAT
| O_RDWR
| O_NOFOLLOW
| O_CLOEXEC
| O_NOCTTY
, S_IWUSR
| S_IRUSR
);
190 return log_error_errno(-2, errno
, "Failed to open \"%s\"", l
->u
.f
.fname
);
193 memset(&lk
, 0, sizeof(struct flock
));
196 lk
.l_whence
= SEEK_SET
;
198 ret
= fcntl(l
->u
.f
.fd
, F_OFD_SETLKW
, &lk
);
199 if (ret
< 0 && errno
== EINVAL
)
200 ret
= flock(l
->u
.f
.fd
, LOCK_EX
);
203 return ret_set_errno(-1, EINVAL
);
209 int lxcunlock(struct lxc_lock
*l
)
215 case LXC_LOCK_ANON_SEM
:
219 ret
= sem_post(l
->u
.sem
);
225 memset(&lk
, 0, sizeof(struct flock
));
228 lk
.l_whence
= SEEK_SET
;
230 ret
= fcntl(l
->u
.f
.fd
, F_OFD_SETLK
, &lk
);
231 if (ret
< 0 && errno
== EINVAL
)
232 ret
= flock(l
->u
.f
.fd
, LOCK_EX
| LOCK_NB
);
234 close_prot_errno_disarm(l
->u
.f
.fd
);
237 return ret_set_errno(-1, EINVAL
);
244 * lxc_putlock() is only called when a container_new() fails,
245 * or during container_put(), which is already guaranteed to
246 * only be done by one task.
247 * So the only exclusion we need to provide here is for regular
248 * thread safety (i.e. file descriptor table changes).
250 void lxc_putlock(struct lxc_lock
*l
)
256 case LXC_LOCK_ANON_SEM
:
258 sem_destroy(l
->u
.sem
);
259 free_disarm(l
->u
.sem
);
263 close_prot_errno_disarm(l
->u
.f
.fd
);
264 free_disarm(l
->u
.f
.fname
);
271 void process_lock(void)
273 lock_mutex(&thread_mutex
);
276 void process_unlock(void)
278 unlock_mutex(&thread_mutex
);
281 int container_mem_lock(struct lxc_container
*c
)
283 return lxclock(c
->privlock
, 0);
286 void container_mem_unlock(struct lxc_container
*c
)
288 lxcunlock(c
->privlock
);
291 int container_disk_lock(struct lxc_container
*c
)
295 ret
= lxclock(c
->privlock
, 0);
299 ret
= lxclock(c
->slock
, 0);
301 lxcunlock(c
->privlock
);
308 void container_disk_unlock(struct lxc_container
*c
)
311 lxcunlock(c
->privlock
);