1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2010 ProFUSION embedded systems
6 #include <linux/dm-ioctl.h>
11 #include "alloc-util.h"
12 #include "blockdev-util.h"
13 #include "detach-dm.h"
14 #include "device-util.h"
15 #include "devnum-util.h"
16 #include "errno-util.h"
18 #include "sync-util.h"
20 typedef struct DeviceMapper
{
23 LIST_FIELDS(struct DeviceMapper
, device_mapper
);
26 static void device_mapper_free(DeviceMapper
**head
, DeviceMapper
*m
) {
30 LIST_REMOVE(device_mapper
, *head
, m
);
36 static void device_mapper_list_free(DeviceMapper
**head
) {
40 device_mapper_free(head
, *head
);
43 static int dm_list_get(DeviceMapper
**head
) {
44 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
49 r
= sd_device_enumerator_new(&e
);
53 r
= sd_device_enumerator_allow_uninitialized(e
);
57 r
= sd_device_enumerator_add_match_subsystem(e
, "block", true);
61 r
= sd_device_enumerator_add_match_sysname(e
, "dm-*");
65 FOREACH_DEVICE(e
, d
) {
66 _cleanup_free_
char *p
= NULL
;
71 if (sd_device_get_devnum(d
, &devnum
) < 0 ||
72 sd_device_get_devname(d
, &dn
) < 0)
79 m
= new(DeviceMapper
, 1);
88 LIST_PREPEND(device_mapper
, *head
, m
);
94 static int delete_dm(DeviceMapper
*m
) {
95 _cleanup_close_
int fd
= -EBADF
;
99 assert(major(m
->devnum
) != 0);
102 fd
= open("/dev/mapper/control", O_RDWR
|O_CLOEXEC
);
106 r
= fsync_path_at(AT_FDCWD
, m
->path
);
108 log_debug_errno(r
, "Failed to sync DM block device %s, ignoring: %m", m
->path
);
110 return RET_NERRNO(ioctl(fd
, DM_DEV_REMOVE
, &(struct dm_ioctl
) {
114 DM_VERSION_PATCHLEVEL
116 .data_size
= sizeof(struct dm_ioctl
),
121 static int dm_points_list_detach(DeviceMapper
**head
, bool *changed
, bool last_try
) {
123 dev_t rootdev
= 0, usrdev
= 0;
128 (void) get_block_device("/", &rootdev
);
129 (void) get_block_device("/usr", &usrdev
);
131 LIST_FOREACH(device_mapper
, m
, *head
) {
132 if ((major(rootdev
) != 0 && rootdev
== m
->devnum
) ||
133 (major(usrdev
) != 0 && usrdev
== m
->devnum
)) {
134 log_debug("Not detaching DM %s that backs the OS itself, skipping.", m
->path
);
139 log_info("Detaching DM %s (" DEVNUM_FORMAT_STR
").", m
->path
, DEVNUM_FORMAT_VAL(m
->devnum
));
142 log_full_errno(last_try
? LOG_ERR
: LOG_INFO
, r
, "Could not detach DM %s: %m", m
->path
);
148 device_mapper_free(head
, m
);
154 int dm_detach_all(bool *changed
, bool last_try
) {
155 _cleanup_(device_mapper_list_free
) LIST_HEAD(DeviceMapper
, dm_list_head
);
160 LIST_HEAD_INIT(dm_list_head
);
162 r
= dm_list_get(&dm_list_head
);
166 return dm_points_list_detach(&dm_list_head
, changed
, last_try
);