Systemd/src/shared/dm-util.c
Luca Boccassi ac1f3ad05f verity: re-use already open devices if the hashes match
Opening a verity device is an expensive operation. The kernelspace operations
are mostly sequential with a global lock held regardless of which device
is being opened. In userspace jumps in and out of multiple libraries are
required. When signatures are used, there's the additional cryptographic
checks.

We know when two devices are identical: they have the same root hash.
If libcrypsetup returns EEXIST, double check that the hashes are really
the same, and that either both or none have a signature, and if everything
matches simply remount the already open device. The kernel will do
reference counting for us.

In order to quickly and reliably discover if a device is already open,
change the node naming scheme from '/dev/mapper/major:minor-verity' to
'/dev/mapper/$roothash-verity'.

Unfortunately libdevmapper is not 100% reliable, so in some case it
will say that the device already exists and it is active, but in
reality it is not usable. Fallback to an individually-activated
unique device name in those cases for robustness.
2020-07-21 23:42:03 +01:00

44 lines
1.3 KiB
C

#include <fcntl.h>
#include <linux/dm-ioctl.h>
#include <sys/ioctl.h>
#include "dm-util.h"
#include "fd-util.h"
#include "string-util.h"
int dm_deferred_remove_cancel(const char *name) {
_cleanup_close_ int fd = -1;
struct message {
struct dm_ioctl dm_ioctl;
struct dm_target_msg dm_target_msg;
char msg_text[STRLEN("@cancel_deferred_remove") + 1];
} _packed_ message = {
.dm_ioctl = {
.version = {
DM_VERSION_MAJOR,
DM_VERSION_MINOR,
DM_VERSION_PATCHLEVEL
},
.data_size = sizeof(struct message),
.data_start = sizeof(struct dm_ioctl),
},
.msg_text = "@cancel_deferred_remove",
};
assert(name);
if (strlen(name) >= sizeof(message.dm_ioctl.name))
return -ENODEV; /* A device with a name longer than this cannot possibly exist */
strncpy_exact(message.dm_ioctl.name, name, sizeof(message.dm_ioctl.name));
fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
if (fd < 0)
return -errno;
if (ioctl(fd, DM_TARGET_MSG, &message))
return -errno;
return 0;
}