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"
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
;
98 assert(major(m
->devnum
) != 0);
101 fd
= open(m
->path
, O_RDONLY
|O_CLOEXEC
|O_NONBLOCK
);
103 log_debug_errno(errno
, "Failed to open DM block device %s for syncing, ignoring: %m", m
->path
);
105 (void) sync_with_progress(fd
);
109 fd
= open("/dev/mapper/control", O_RDWR
|O_CLOEXEC
);
111 return log_debug_errno(errno
, "Failed to open /dev/mapper/control: %m");
113 return RET_NERRNO(ioctl(fd
, DM_DEV_REMOVE
, &(struct dm_ioctl
) {
117 DM_VERSION_PATCHLEVEL
119 .data_size
= sizeof(struct dm_ioctl
),
124 static int dm_points_list_detach(DeviceMapper
**head
, bool *changed
, bool last_try
) {
126 dev_t rootdev
= 0, usrdev
= 0;
131 (void) get_block_device("/", &rootdev
);
132 (void) get_block_device("/usr", &usrdev
);
134 LIST_FOREACH(device_mapper
, m
, *head
) {
135 if ((major(rootdev
) != 0 && rootdev
== m
->devnum
) ||
136 (major(usrdev
) != 0 && usrdev
== m
->devnum
)) {
137 log_debug("Not detaching DM %s that backs the OS itself, skipping.", m
->path
);
142 log_info("Detaching DM %s (" DEVNUM_FORMAT_STR
").", m
->path
, DEVNUM_FORMAT_VAL(m
->devnum
));
145 log_full_errno(last_try
? LOG_ERR
: LOG_INFO
, r
, "Could not detach DM %s: %m", m
->path
);
151 device_mapper_free(head
, m
);
157 int dm_detach_all(bool *changed
, bool last_try
) {
158 _cleanup_(device_mapper_list_free
) LIST_HEAD(DeviceMapper
, dm_list_head
);
163 LIST_HEAD_INIT(dm_list_head
);
165 r
= dm_list_get(&dm_list_head
);
169 return dm_points_list_detach(&dm_list_head
, changed
, last_try
);