dm.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /*
  2. * Copyright (C) 2018 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "libdm/dm.h"
  17. #include <sys/ioctl.h>
  18. #include <sys/sysmacros.h>
  19. #include <sys/types.h>
  20. #include <android-base/logging.h>
  21. #include <android-base/macros.h>
  22. namespace android {
  23. namespace dm {
  24. DeviceMapper::DeviceMapper() : fd_(-1) {
  25. fd_ = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
  26. if (fd_ < 0) {
  27. PLOG(ERROR) << "Failed to open device-mapper";
  28. }
  29. }
  30. DeviceMapper& DeviceMapper::Instance() {
  31. static DeviceMapper instance;
  32. return instance;
  33. }
  34. // Creates a new device mapper device
  35. bool DeviceMapper::CreateDevice(const std::string& name) {
  36. if (name.empty()) {
  37. LOG(ERROR) << "Unnamed device mapper device creation is not supported";
  38. return false;
  39. }
  40. if (name.size() >= DM_NAME_LEN) {
  41. LOG(ERROR) << "[" << name << "] is too long to be device mapper name";
  42. return false;
  43. }
  44. struct dm_ioctl io;
  45. InitIo(&io, name);
  46. if (ioctl(fd_, DM_DEV_CREATE, &io)) {
  47. PLOG(ERROR) << "DM_DEV_CREATE failed for [" << name << "]";
  48. return false;
  49. }
  50. // Check to make sure the newly created device doesn't already have targets
  51. // added or opened by someone
  52. CHECK(io.target_count == 0) << "Unexpected targets for newly created [" << name << "] device";
  53. CHECK(io.open_count == 0) << "Unexpected opens for newly created [" << name << "] device";
  54. // Creates a new device mapper device with the name passed in
  55. return true;
  56. }
  57. bool DeviceMapper::DeleteDevice(const std::string& name) {
  58. if (name.empty()) {
  59. LOG(ERROR) << "Unnamed device mapper device creation is not supported";
  60. return false;
  61. }
  62. if (name.size() >= DM_NAME_LEN) {
  63. LOG(ERROR) << "[" << name << "] is too long to be device mapper name";
  64. return false;
  65. }
  66. struct dm_ioctl io;
  67. InitIo(&io, name);
  68. if (ioctl(fd_, DM_DEV_REMOVE, &io)) {
  69. PLOG(ERROR) << "DM_DEV_REMOVE failed for [" << name << "]";
  70. return false;
  71. }
  72. // Check to make sure appropriate uevent is generated so ueventd will
  73. // do the right thing and remove the corresponding device node and symlinks.
  74. CHECK(io.flags & DM_UEVENT_GENERATED_FLAG)
  75. << "Didn't generate uevent for [" << name << "] removal";
  76. return true;
  77. }
  78. const std::unique_ptr<DmTable> DeviceMapper::table(const std::string& /* name */) const {
  79. // TODO(b/110035986): Return the table, as read from the kernel instead
  80. return nullptr;
  81. }
  82. DmDeviceState DeviceMapper::GetState(const std::string& name) const {
  83. struct dm_ioctl io;
  84. InitIo(&io, name);
  85. if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
  86. return DmDeviceState::INVALID;
  87. }
  88. if ((io.flags & DM_ACTIVE_PRESENT_FLAG) && !(io.flags & DM_SUSPEND_FLAG)) {
  89. return DmDeviceState::ACTIVE;
  90. }
  91. return DmDeviceState::SUSPENDED;
  92. }
  93. bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table) {
  94. if (!CreateDevice(name)) {
  95. return false;
  96. }
  97. if (!LoadTableAndActivate(name, table)) {
  98. DeleteDevice(name);
  99. return false;
  100. }
  101. return true;
  102. }
  103. bool DeviceMapper::LoadTableAndActivate(const std::string& name, const DmTable& table) {
  104. std::string ioctl_buffer(sizeof(struct dm_ioctl), 0);
  105. ioctl_buffer += table.Serialize();
  106. struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(&ioctl_buffer[0]);
  107. InitIo(io, name);
  108. io->data_size = ioctl_buffer.size();
  109. io->data_start = sizeof(struct dm_ioctl);
  110. io->target_count = static_cast<uint32_t>(table.num_targets());
  111. if (table.readonly()) {
  112. io->flags |= DM_READONLY_FLAG;
  113. }
  114. if (ioctl(fd_, DM_TABLE_LOAD, io)) {
  115. PLOG(ERROR) << "DM_TABLE_LOAD failed";
  116. return false;
  117. }
  118. InitIo(io, name);
  119. if (ioctl(fd_, DM_DEV_SUSPEND, io)) {
  120. PLOG(ERROR) << "DM_TABLE_SUSPEND resume failed";
  121. return false;
  122. }
  123. return true;
  124. }
  125. // Reads all the available device mapper targets and their corresponding
  126. // versions from the kernel and returns in a vector
  127. bool DeviceMapper::GetAvailableTargets(std::vector<DmTargetTypeInfo>* targets) {
  128. targets->clear();
  129. // calculate the space needed to read a maximum of kMaxPossibleDmTargets
  130. uint32_t payload_size = sizeof(struct dm_target_versions);
  131. payload_size += DM_MAX_TYPE_NAME;
  132. // device mapper wants every target spec to be aligned at 8-byte boundary
  133. payload_size = DM_ALIGN(payload_size);
  134. payload_size *= kMaxPossibleDmTargets;
  135. uint32_t data_size = sizeof(struct dm_ioctl) + payload_size;
  136. auto buffer = std::unique_ptr<void, void (*)(void*)>(calloc(1, data_size), free);
  137. if (buffer == nullptr) {
  138. LOG(ERROR) << "failed to allocate memory";
  139. return false;
  140. }
  141. // Sets appropriate data size and data_start to make sure we tell kernel
  142. // about the total size of the buffer we are passing and where to start
  143. // writing the list of targets.
  144. struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
  145. InitIo(io);
  146. io->data_size = data_size;
  147. io->data_start = sizeof(*io);
  148. if (ioctl(fd_, DM_LIST_VERSIONS, io)) {
  149. PLOG(ERROR) << "DM_LIST_VERSIONS failed";
  150. return false;
  151. }
  152. // If the provided buffer wasn't enough to list all targets, note that
  153. // any data beyond sizeof(*io) must not be read in this case
  154. if (io->flags & DM_BUFFER_FULL_FLAG) {
  155. LOG(INFO) << data_size << " is not enough memory to list all dm targets";
  156. return false;
  157. }
  158. // if there are no targets registered, return success with empty vector
  159. if (io->data_size == sizeof(*io)) {
  160. return true;
  161. }
  162. // Parse each target and list the name and version
  163. // TODO(b/110035986): Templatize this
  164. uint32_t next = sizeof(*io);
  165. data_size = io->data_size - next;
  166. struct dm_target_versions* vers =
  167. reinterpret_cast<struct dm_target_versions*>(static_cast<char*>(buffer.get()) + next);
  168. while (next && data_size) {
  169. targets->emplace_back(vers);
  170. if (vers->next == 0) {
  171. break;
  172. }
  173. next += vers->next;
  174. data_size -= vers->next;
  175. vers = reinterpret_cast<struct dm_target_versions*>(static_cast<char*>(buffer.get()) +
  176. next);
  177. }
  178. return true;
  179. }
  180. bool DeviceMapper::GetAvailableDevices(std::vector<DmBlockDevice>* devices) {
  181. devices->clear();
  182. // calculate the space needed to read a maximum of 256 targets, each with
  183. // name with maximum length of 16 bytes
  184. uint32_t payload_size = sizeof(struct dm_name_list);
  185. // 128-bytes for the name
  186. payload_size += DM_NAME_LEN;
  187. // dm wants every device spec to be aligned at 8-byte boundary
  188. payload_size = DM_ALIGN(payload_size);
  189. payload_size *= kMaxPossibleDmDevices;
  190. uint32_t data_size = sizeof(struct dm_ioctl) + payload_size;
  191. auto buffer = std::unique_ptr<void, void (*)(void*)>(calloc(1, data_size), free);
  192. if (buffer == nullptr) {
  193. LOG(ERROR) << "failed to allocate memory";
  194. return false;
  195. }
  196. // Sets appropriate data size and data_start to make sure we tell kernel
  197. // about the total size of the buffer we are passing and where to start
  198. // writing the list of targets.
  199. struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
  200. InitIo(io);
  201. io->data_size = data_size;
  202. io->data_start = sizeof(*io);
  203. if (ioctl(fd_, DM_LIST_DEVICES, io)) {
  204. PLOG(ERROR) << "DM_LIST_DEVICES failed";
  205. return false;
  206. }
  207. // If the provided buffer wasn't enough to list all devices any data
  208. // beyond sizeof(*io) must not be read.
  209. if (io->flags & DM_BUFFER_FULL_FLAG) {
  210. LOG(INFO) << data_size << " is not enough memory to list all dm devices";
  211. return false;
  212. }
  213. // if there are no devices created yet, return success with empty vector
  214. if (io->data_size == sizeof(*io)) {
  215. return true;
  216. }
  217. // Parse each device and add a new DmBlockDevice to the vector
  218. // created from the kernel data.
  219. uint32_t next = sizeof(*io);
  220. data_size = io->data_size - next;
  221. struct dm_name_list* dm_dev =
  222. reinterpret_cast<struct dm_name_list*>(static_cast<char*>(buffer.get()) + next);
  223. while (next && data_size) {
  224. devices->emplace_back((dm_dev));
  225. if (dm_dev->next == 0) {
  226. break;
  227. }
  228. next += dm_dev->next;
  229. data_size -= dm_dev->next;
  230. dm_dev = reinterpret_cast<struct dm_name_list*>(static_cast<char*>(buffer.get()) + next);
  231. }
  232. return true;
  233. }
  234. // Accepts a device mapper device name (like system_a, vendor_b etc) and
  235. // returns the path to it's device node (or symlink to the device node)
  236. bool DeviceMapper::GetDmDevicePathByName(const std::string& name, std::string* path) {
  237. struct dm_ioctl io;
  238. InitIo(&io, name);
  239. if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
  240. PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
  241. return false;
  242. }
  243. uint32_t dev_num = minor(io.dev);
  244. *path = "/dev/block/dm-" + std::to_string(dev_num);
  245. return true;
  246. }
  247. bool DeviceMapper::GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) {
  248. return GetTable(name, 0, table);
  249. }
  250. bool DeviceMapper::GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) {
  251. return GetTable(name, DM_STATUS_TABLE_FLAG, table);
  252. }
  253. // private methods of DeviceMapper
  254. bool DeviceMapper::GetTable(const std::string& name, uint32_t flags,
  255. std::vector<TargetInfo>* table) {
  256. std::vector<char> buffer;
  257. struct dm_ioctl* io = nullptr;
  258. for (buffer.resize(4096);; buffer.resize(buffer.size() * 2)) {
  259. io = reinterpret_cast<struct dm_ioctl*>(&buffer[0]);
  260. InitIo(io, name);
  261. io->data_size = buffer.size();
  262. io->data_start = sizeof(*io);
  263. io->flags = flags;
  264. if (ioctl(fd_, DM_TABLE_STATUS, io) < 0) {
  265. PLOG(ERROR) << "DM_TABLE_STATUS failed for " << name;
  266. return false;
  267. }
  268. if (!(io->flags & DM_BUFFER_FULL_FLAG)) break;
  269. }
  270. uint32_t cursor = io->data_start;
  271. uint32_t data_end = std::min(io->data_size, uint32_t(buffer.size()));
  272. for (uint32_t i = 0; i < io->target_count; i++) {
  273. if (cursor + sizeof(struct dm_target_spec) > data_end) {
  274. break;
  275. }
  276. // After each dm_target_spec is a status string. spec->next is an
  277. // offset from |io->data_start|, and we clamp it to the size of our
  278. // buffer.
  279. struct dm_target_spec* spec = reinterpret_cast<struct dm_target_spec*>(&buffer[cursor]);
  280. uint32_t data_offset = cursor + sizeof(dm_target_spec);
  281. uint32_t next_cursor = std::min(io->data_start + spec->next, data_end);
  282. std::string data;
  283. if (next_cursor > data_offset) {
  284. // Note: we use c_str() to eliminate any extra trailing 0s.
  285. data = std::string(&buffer[data_offset], next_cursor - data_offset).c_str();
  286. }
  287. table->emplace_back(*spec, data);
  288. cursor = next_cursor;
  289. }
  290. return true;
  291. }
  292. void DeviceMapper::InitIo(struct dm_ioctl* io, const std::string& name) const {
  293. CHECK(io != nullptr) << "nullptr passed to dm_ioctl initialization";
  294. memset(io, 0, sizeof(*io));
  295. io->version[0] = DM_VERSION0;
  296. io->version[1] = DM_VERSION1;
  297. io->version[2] = DM_VERSION2;
  298. io->data_size = sizeof(*io);
  299. io->data_start = 0;
  300. if (!name.empty()) {
  301. snprintf(io->name, sizeof(io->name), "%s", name.c_str());
  302. }
  303. }
  304. } // namespace dm
  305. } // namespace android