nspawn: add file system locks for controlling access to container images

This adds three kinds of file system locks for container images:

a) a file system lock next to the actual image, in a .lck file in the
   same directory the image is located. This lock has the benefit of
   usually being located on the same NFS share as the image itself, and
   thus allows locking container images across NFS shares.

b) a file system lock in /run, named after st_dev and st_ino of the
   root of the image. This lock has the advantage that it is unique even
   if the same image is bind mounted to two different places at the same
   time, as the ino/dev stays constant for them.

c) a file system lock that is only taken when a new disk image is about
   to be created, that ensures that checking whether the name is already
   used across the search path, and actually placing the image is not
   interrupted by other code taking the name.

a + b are read-write locks. When a container is booted in read-only mode
a read lock is taken, otherwise a write lock.

Lock b is always taken after a, to avoid ABBA problems.

Lock c is mostly relevant when renaming or cloning images.
This commit is contained in:
Lennart Poettering
2015-01-14 23:18:33 +01:00
parent 805e5dda0a
commit 30535c1692
5 changed files with 304 additions and 32 deletions
+44 -14
View File
@@ -3337,6 +3337,7 @@ int main(int argc, char *argv[]) {
pid_t pid = 0;
int ret = EXIT_SUCCESS;
union in_addr_union exposed = {};
_cleanup_release_lock_file_ LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
log_parse_environment();
log_open();
@@ -3382,20 +3383,8 @@ int main(int argc, char *argv[]) {
goto finish;
}
if (arg_template) {
r = btrfs_subvol_snapshot(arg_template, arg_directory, arg_read_only, true);
if (r == -EEXIST) {
if (!arg_quiet)
log_info("Directory %s already exists, not populating from template %s.", arg_directory, arg_template);
} else if (r < 0) {
log_error_errno(r, "Couldn't create snapshort %s from %s: %m", arg_directory, arg_template);
goto finish;
} else {
if (!arg_quiet)
log_info("Populated %s from template %s.", arg_directory, arg_template);
}
} else if (arg_ephemeral) {
if (arg_ephemeral) {
_cleanup_release_lock_file_ LockFile original_lock = LOCK_FILE_INIT;
char *np;
/* If the specified path is a mount point we
@@ -3418,6 +3407,12 @@ int main(int argc, char *argv[]) {
goto finish;
}
r = image_path_lock(np, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, &tree_global_lock, &tree_local_lock);
if (r < 0) {
log_error_errno(r, "Failed to lock %s: %m", np);
goto finish;
}
r = btrfs_subvol_snapshot(arg_directory, np, arg_read_only, true);
if (r < 0) {
free(np);
@@ -3429,6 +3424,31 @@ int main(int argc, char *argv[]) {
arg_directory = np;
remove_subvol = true;
} else {
r = image_path_lock(arg_directory, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, &tree_global_lock, &tree_local_lock);
if (r == -EBUSY) {
log_error_errno(r, "Directory tree %s is currently busy.", arg_directory);
goto finish;
}
if (r < 0) {
log_error_errno(r, "Failed to lock %s: %m", arg_directory);
return r;
}
if (arg_template) {
r = btrfs_subvol_snapshot(arg_template, arg_directory, arg_read_only, true);
if (r == -EEXIST) {
if (!arg_quiet)
log_info("Directory %s already exists, not populating from template %s.", arg_directory, arg_template);
} else if (r < 0) {
log_error_errno(r, "Couldn't create snapshort %s from %s: %m", arg_directory, arg_template);
goto finish;
} else {
if (!arg_quiet)
log_info("Populated %s from template %s.", arg_directory, arg_template);
}
}
}
if (arg_boot) {
@@ -3455,6 +3475,16 @@ int main(int argc, char *argv[]) {
assert(arg_image);
assert(!arg_template);
r = image_path_lock(arg_image, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, &tree_global_lock, &tree_local_lock);
if (r == -EBUSY) {
r = log_error_errno(r, "Disk image %s is currently busy.", arg_image);
goto finish;
}
if (r < 0) {
r = log_error_errno(r, "Failed to create image lock: %m");
goto finish;
}
if (!mkdtemp(template)) {
log_error_errno(errno, "Failed to create temporary directory: %m");
r = -errno;