2 * Ceph - scalable distributed file system
4 * Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
6 * This is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License version 2.1, as published by the Free Software
9 * Foundation. See file COPYING.
14 #include <sys/ioctl.h>
17 #include "include/uuid.h"
21 #include <blkid/blkid.h>
25 static const char *sandbox_dir = "";
27 void set_block_device_sandbox_dir(const char *dir)
35 int get_block_device_size(int fd, int64_t *psize)
38 int ret = ::ioctl(fd, BLKGETSIZE64, psize);
39 #elif defined(BLKGETSIZE)
40 unsigned long sectors = 0;
41 int ret = ::ioctl(fd, BLKGETSIZE, §ors);
42 *psize = sectors * 512ULL;
44 // cppcheck-suppress preprocessorErrorDirective
45 # error "Linux configuration error (get_block_device_size)"
53 * get the base device (strip off partition suffix and /dev/ prefix)
56 * /dev/cciss/c0d1p2 -> cciss/c0d1
57 * dev can a symbolic link.
59 int get_block_device_base(const char *dev, char *out, size_t out_len)
64 char devname[PATH_MAX] = {0}, fn[PATH_MAX] = {0};
66 char realname[PATH_MAX] = {0};
68 if (strncmp(dev, "/dev/", 5) != 0) {
69 if (realpath(dev, realname) == NULL || (strncmp(realname, "/dev/", 5) != 0)) {
75 strncpy(devname, realname + 5, PATH_MAX - 5);
77 strncpy(devname, dev + 5, strlen(dev) - 5);
79 devname[PATH_MAX - 1] = '\0';
81 for (p = devname; *p; ++p)
85 snprintf(fn, sizeof(fn), "%s/sys/block/%s", sandbox_dir, devname);
86 if (stat(fn, &st) == 0) {
87 if (strlen(devname) + 1 > out_len) {
90 strncpy(out, devname, out_len);
94 snprintf(fn, sizeof(fn), "%s/sys/block", sandbox_dir);
99 struct dirent *de = nullptr;
100 while ((de = ::readdir(dir))) {
101 if (de->d_name[0] == '.')
103 snprintf(fn, sizeof(fn), "%s/sys/block/%s/%s", sandbox_dir, de->d_name,
106 if (stat(fn, &st) == 0) {
108 if (strlen(de->d_name) + 1 > out_len) {
112 strncpy(out, de->d_name, out_len);
125 * get a block device property as a string
127 * store property in *val, up to maxlen chars
128 * return 0 on success
129 * return negative error on error
131 int64_t get_block_device_string_property(const char *devname,
132 const char *property,
133 char *val, size_t maxlen)
135 char filename[PATH_MAX];
136 snprintf(filename, sizeof(filename),
137 "%s/sys/block/%s/%s", sandbox_dir, devname, property);
139 FILE *fp = fopen(filename, "r");
145 if (fgets(val, maxlen - 1, fp)) {
146 // truncate at newline
148 while (*p && *p != '\n')
159 * get a block device property
161 * return the value (we assume it is positive)
162 * return negative error on error
164 int64_t get_block_device_int_property(const char *devname, const char *property)
166 char buff[256] = {0};
167 int r = get_block_device_string_property(devname, property, buff, sizeof(buff));
171 for (char *p = buff; *p; ++p) {
178 r = strtoll(buff, &endptr, 10);
179 if (endptr != buff + strlen(buff))
184 bool block_device_support_discard(const char *devname)
186 return get_block_device_int_property(devname, "queue/discard_granularity") > 0;
189 int block_device_discard(int fd, int64_t offset, int64_t len)
191 uint64_t range[2] = {(uint64_t)offset, (uint64_t)len};
192 return ioctl(fd, BLKDISCARD, range);
195 bool block_device_is_rotational(const char *devname)
197 return get_block_device_int_property(devname, "queue/rotational") > 0;
200 int block_device_model(const char *devname, char *model, size_t max)
202 return get_block_device_string_property(devname, "device/model", model, max);
205 int get_device_by_uuid(uuid_d dev_uuid, const char* label, char* partition,
208 char uuid_str[UUID_LEN+1];
209 char basename[PATH_MAX];
210 const char* temp_partition_ptr = NULL;
211 blkid_cache cache = NULL;
212 blkid_dev dev = NULL;
215 dev_uuid.print(uuid_str);
217 if (blkid_get_cache(&cache, NULL) >= 0)
218 dev = blkid_find_dev_with_tag(cache, label, (const char*)uuid_str);
223 temp_partition_ptr = blkid_dev_devname(dev);
224 strncpy(partition, temp_partition_ptr, PATH_MAX);
225 rc = get_block_device_base(partition, basename,
228 strncpy(device, basename, sizeof(basename));
237 /* From what I can tell, blkid_put_cache cleans up dev, which
238 * appears to be a pointer into cache, as well */
240 blkid_put_cache(cache);
244 int get_device_by_fd(int fd, char *partition, char *device, size_t max)
247 int r = fstat(fd, &st);
249 return -EINVAL; // hrm.
251 dev_t devid = S_ISBLK(st.st_mode) ? st.st_rdev : st.st_dev;
252 char *t = blkid_devno_to_devname(devid);
256 strncpy(partition, t, max);
259 r = blkid_devno_to_wholedisk(devid, device, max, &diskdev);
266 #elif defined(__APPLE__)
267 #include <sys/disk.h>
269 int get_block_device_size(int fd, int64_t *psize)
271 unsigned long blocksize = 0;
272 int ret = ::ioctl(fd, DKIOCGETBLOCKSIZE, &blocksize);
274 unsigned long nblocks;
275 ret = ::ioctl(fd, DKIOCGETBLOCKCOUNT, &nblocks);
277 *psize = (int64_t)nblocks * blocksize;
284 bool block_device_support_discard(const char *devname)
289 int block_device_discard(int fd, int64_t offset, int64_t len)
294 bool block_device_is_rotational(const char *devname)
299 int get_device_by_uuid(uuid_d dev_uuid, const char* label, char* partition,
304 #elif defined(__FreeBSD__)
305 #include <sys/disk.h>
307 int get_block_device_size(int fd, int64_t *psize)
309 int ret = ::ioctl(fd, DIOCGMEDIASIZE, psize);
315 bool block_device_support_discard(const char *devname)
320 int block_device_discard(int fd, int64_t offset, int64_t len)
325 bool block_device_is_rotational(const char *devname)
330 int get_device_by_uuid(uuid_d dev_uuid, const char* label, char* partition,
335 int get_device_by_fd(int fd, char *partition, char *device, size_t max)
340 int get_block_device_size(int fd, int64_t *psize)
345 bool block_device_support_discard(const char *devname)
350 int block_device_discard(int fd, int64_t offset, int64_t len)
355 bool block_device_is_rotational(const char *devname)
360 int get_device_by_uuid(uuid_d dev_uuid, const char* label, char* partition,
366 int get_device_by_fd(int fd, char *partition, char *device, size_t max)