]>
Commit | Line | Data |
---|---|---|
b44411c7 LP |
1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
2 | /*** | |
3 | Copyright © 2010 ProFUSION embedded systems | |
4 | ***/ | |
5 | ||
6 | #include <linux/dm-ioctl.h> | |
7 | #include <sys/ioctl.h> | |
8 | ||
9 | #include "sd-device.h" | |
10 | ||
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" | |
17 | #include "fd-util.h" | |
18 | #include "sync-util.h" | |
b44411c7 | 19 | |
015937f9 LP |
20 | typedef struct DeviceMapper { |
21 | char *path; | |
22 | dev_t devnum; | |
23 | LIST_FIELDS(struct DeviceMapper, device_mapper); | |
24 | } DeviceMapper; | |
25 | ||
26 | static void device_mapper_free(DeviceMapper **head, DeviceMapper *m) { | |
27 | assert(head); | |
28 | assert(m); | |
29 | ||
30 | LIST_REMOVE(device_mapper, *head, m); | |
31 | ||
32 | free(m->path); | |
33 | free(m); | |
34 | } | |
35 | ||
36 | static void device_mapper_list_free(DeviceMapper **head) { | |
37 | assert(head); | |
38 | ||
39 | while (*head) | |
40 | device_mapper_free(head, *head); | |
41 | } | |
42 | ||
43 | static int dm_list_get(DeviceMapper **head) { | |
b44411c7 | 44 | _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; |
b44411c7 LP |
45 | int r; |
46 | ||
47 | assert(head); | |
48 | ||
49 | r = sd_device_enumerator_new(&e); | |
50 | if (r < 0) | |
51 | return r; | |
52 | ||
53 | r = sd_device_enumerator_allow_uninitialized(e); | |
54 | if (r < 0) | |
55 | return r; | |
56 | ||
57 | r = sd_device_enumerator_add_match_subsystem(e, "block", true); | |
58 | if (r < 0) | |
59 | return r; | |
60 | ||
61 | r = sd_device_enumerator_add_match_sysname(e, "dm-*"); | |
62 | if (r < 0) | |
63 | return r; | |
64 | ||
65 | FOREACH_DEVICE(e, d) { | |
66 | _cleanup_free_ char *p = NULL; | |
67 | const char *dn; | |
015937f9 | 68 | DeviceMapper *m; |
b44411c7 LP |
69 | dev_t devnum; |
70 | ||
71 | if (sd_device_get_devnum(d, &devnum) < 0 || | |
72 | sd_device_get_devname(d, &dn) < 0) | |
73 | continue; | |
74 | ||
75 | p = strdup(dn); | |
76 | if (!p) | |
77 | return -ENOMEM; | |
78 | ||
015937f9 | 79 | m = new(DeviceMapper, 1); |
b44411c7 LP |
80 | if (!m) |
81 | return -ENOMEM; | |
82 | ||
015937f9 | 83 | *m = (DeviceMapper) { |
b44411c7 LP |
84 | .path = TAKE_PTR(p), |
85 | .devnum = devnum, | |
86 | }; | |
87 | ||
015937f9 | 88 | LIST_PREPEND(device_mapper, *head, m); |
b44411c7 LP |
89 | } |
90 | ||
91 | return 0; | |
92 | } | |
93 | ||
015937f9 | 94 | static int delete_dm(DeviceMapper *m) { |
b44411c7 LP |
95 | _cleanup_close_ int fd = -EBADF; |
96 | int r; | |
97 | ||
98 | assert(m); | |
99 | assert(major(m->devnum) != 0); | |
100 | assert(m->path); | |
101 | ||
102 | fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC); | |
103 | if (fd < 0) | |
104 | return -errno; | |
105 | ||
106 | r = fsync_path_at(AT_FDCWD, m->path); | |
107 | if (r < 0) | |
108 | log_debug_errno(r, "Failed to sync DM block device %s, ignoring: %m", m->path); | |
109 | ||
110 | return RET_NERRNO(ioctl(fd, DM_DEV_REMOVE, &(struct dm_ioctl) { | |
111 | .version = { | |
112 | DM_VERSION_MAJOR, | |
113 | DM_VERSION_MINOR, | |
114 | DM_VERSION_PATCHLEVEL | |
115 | }, | |
116 | .data_size = sizeof(struct dm_ioctl), | |
117 | .dev = m->devnum, | |
118 | })); | |
119 | } | |
120 | ||
015937f9 | 121 | static int dm_points_list_detach(DeviceMapper **head, bool *changed, bool last_try) { |
b44411c7 | 122 | int n_failed = 0, r; |
31d34620 | 123 | dev_t rootdev = 0, usrdev = 0; |
b44411c7 LP |
124 | |
125 | assert(head); | |
126 | assert(changed); | |
127 | ||
128 | (void) get_block_device("/", &rootdev); | |
31d34620 | 129 | (void) get_block_device("/usr", &usrdev); |
b44411c7 | 130 | |
015937f9 | 131 | LIST_FOREACH(device_mapper, m, *head) { |
31d34620 LP |
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); | |
b3a9d980 | 135 | n_failed++; |
b44411c7 LP |
136 | continue; |
137 | } | |
138 | ||
139 | log_info("Detaching DM %s (" DEVNUM_FORMAT_STR ").", m->path, DEVNUM_FORMAT_VAL(m->devnum)); | |
140 | r = delete_dm(m); | |
141 | if (r < 0) { | |
142 | log_full_errno(last_try ? LOG_ERR : LOG_INFO, r, "Could not detach DM %s: %m", m->path); | |
143 | n_failed++; | |
144 | continue; | |
145 | } | |
146 | ||
147 | *changed = true; | |
015937f9 | 148 | device_mapper_free(head, m); |
b44411c7 LP |
149 | } |
150 | ||
151 | return n_failed; | |
152 | } | |
153 | ||
154 | int dm_detach_all(bool *changed, bool last_try) { | |
015937f9 | 155 | _cleanup_(device_mapper_list_free) LIST_HEAD(DeviceMapper, dm_list_head); |
b44411c7 LP |
156 | int r; |
157 | ||
158 | assert(changed); | |
159 | ||
160 | LIST_HEAD_INIT(dm_list_head); | |
161 | ||
162 | r = dm_list_get(&dm_list_head); | |
163 | if (r < 0) | |
164 | return r; | |
165 | ||
166 | return dm_points_list_detach(&dm_list_head, changed, last_try); | |
167 | } |