X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Fcommon%2Fblkdev.cc;fp=src%2Fceph%2Fsrc%2Fcommon%2Fblkdev.cc;h=d95a397a8441afd37fef8a3f57806fc9a5ebfff9;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/common/blkdev.cc b/src/ceph/src/common/blkdev.cc new file mode 100644 index 0000000..d95a397 --- /dev/null +++ b/src/ceph/src/common/blkdev.cc @@ -0,0 +1,370 @@ +/* + * Ceph - scalable distributed file system + * + * Copyright (c) 2015 Hewlett-Packard Development Company, L.P. + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include +#include +#include +#include +#include "include/uuid.h" + +#ifdef __linux__ +#include +#include + +#define UUID_LEN 36 + +static const char *sandbox_dir = ""; + +void set_block_device_sandbox_dir(const char *dir) +{ + if (dir) + sandbox_dir = dir; + else + sandbox_dir = ""; +} + +int get_block_device_size(int fd, int64_t *psize) +{ +#ifdef BLKGETSIZE64 + int ret = ::ioctl(fd, BLKGETSIZE64, psize); +#elif defined(BLKGETSIZE) + unsigned long sectors = 0; + int ret = ::ioctl(fd, BLKGETSIZE, §ors); + *psize = sectors * 512ULL; +#else +// cppcheck-suppress preprocessorErrorDirective +# error "Linux configuration error (get_block_device_size)" +#endif + if (ret < 0) + ret = -errno; + return ret; +} + +/** + * get the base device (strip off partition suffix and /dev/ prefix) + * e.g., + * /dev/sda3 -> sda + * /dev/cciss/c0d1p2 -> cciss/c0d1 + * dev can a symbolic link. + */ +int get_block_device_base(const char *dev, char *out, size_t out_len) +{ + struct stat st; + int r = 0; + DIR *dir; + char devname[PATH_MAX] = {0}, fn[PATH_MAX] = {0}; + char *p; + char realname[PATH_MAX] = {0}; + + if (strncmp(dev, "/dev/", 5) != 0) { + if (realpath(dev, realname) == NULL || (strncmp(realname, "/dev/", 5) != 0)) { + return -EINVAL; + } + } + + if (strlen(realname)) + strncpy(devname, realname + 5, PATH_MAX - 5); + else + strncpy(devname, dev + 5, strlen(dev) - 5); + + devname[PATH_MAX - 1] = '\0'; + + for (p = devname; *p; ++p) + if (*p == '/') + *p = '!'; + + snprintf(fn, sizeof(fn), "%s/sys/block/%s", sandbox_dir, devname); + if (stat(fn, &st) == 0) { + if (strlen(devname) + 1 > out_len) { + return -ERANGE; + } + strncpy(out, devname, out_len); + return 0; + } + + snprintf(fn, sizeof(fn), "%s/sys/block", sandbox_dir); + dir = opendir(fn); + if (!dir) + return -errno; + + struct dirent *de = nullptr; + while ((de = ::readdir(dir))) { + if (de->d_name[0] == '.') + continue; + snprintf(fn, sizeof(fn), "%s/sys/block/%s/%s", sandbox_dir, de->d_name, + devname); + + if (stat(fn, &st) == 0) { + // match! + if (strlen(de->d_name) + 1 > out_len) { + r = -ERANGE; + goto out; + } + strncpy(out, de->d_name, out_len); + r = 0; + goto out; + } + } + r = -ENOENT; + + out: + closedir(dir); + return r; +} + +/** + * get a block device property as a string + * + * store property in *val, up to maxlen chars + * return 0 on success + * return negative error on error + */ +int64_t get_block_device_string_property(const char *devname, + const char *property, + char *val, size_t maxlen) +{ + char filename[PATH_MAX]; + snprintf(filename, sizeof(filename), + "%s/sys/block/%s/%s", sandbox_dir, devname, property); + + FILE *fp = fopen(filename, "r"); + if (fp == NULL) { + return -errno; + } + + int r = 0; + if (fgets(val, maxlen - 1, fp)) { + // truncate at newline + char *p = val; + while (*p && *p != '\n') + ++p; + *p = 0; + } else { + r = -EINVAL; + } + fclose(fp); + return r; +} + +/** + * get a block device property + * + * return the value (we assume it is positive) + * return negative error on error + */ +int64_t get_block_device_int_property(const char *devname, const char *property) +{ + char buff[256] = {0}; + int r = get_block_device_string_property(devname, property, buff, sizeof(buff)); + if (r < 0) + return r; + // take only digits + for (char *p = buff; *p; ++p) { + if (!isdigit(*p)) { + *p = 0; + break; + } + } + char *endptr = 0; + r = strtoll(buff, &endptr, 10); + if (endptr != buff + strlen(buff)) + r = -EINVAL; + return r; +} + +bool block_device_support_discard(const char *devname) +{ + return get_block_device_int_property(devname, "queue/discard_granularity") > 0; +} + +int block_device_discard(int fd, int64_t offset, int64_t len) +{ + uint64_t range[2] = {(uint64_t)offset, (uint64_t)len}; + return ioctl(fd, BLKDISCARD, range); +} + +bool block_device_is_rotational(const char *devname) +{ + return get_block_device_int_property(devname, "queue/rotational") > 0; +} + +int block_device_model(const char *devname, char *model, size_t max) +{ + return get_block_device_string_property(devname, "device/model", model, max); +} + +int get_device_by_uuid(uuid_d dev_uuid, const char* label, char* partition, + char* device) +{ + char uuid_str[UUID_LEN+1]; + char basename[PATH_MAX]; + const char* temp_partition_ptr = NULL; + blkid_cache cache = NULL; + blkid_dev dev = NULL; + int rc = 0; + + dev_uuid.print(uuid_str); + + if (blkid_get_cache(&cache, NULL) >= 0) + dev = blkid_find_dev_with_tag(cache, label, (const char*)uuid_str); + else + return -EINVAL; + + if (dev) { + temp_partition_ptr = blkid_dev_devname(dev); + strncpy(partition, temp_partition_ptr, PATH_MAX); + rc = get_block_device_base(partition, basename, + sizeof(basename)); + if (rc >= 0) { + strncpy(device, basename, sizeof(basename)); + rc = 0; + } else { + rc = -ENODEV; + } + } else { + rc = -EINVAL; + } + + /* From what I can tell, blkid_put_cache cleans up dev, which + * appears to be a pointer into cache, as well */ + if (cache) + blkid_put_cache(cache); + return rc; +} + +int get_device_by_fd(int fd, char *partition, char *device, size_t max) +{ + struct stat st; + int r = fstat(fd, &st); + if (r < 0) { + return -EINVAL; // hrm. + } + dev_t devid = S_ISBLK(st.st_mode) ? st.st_rdev : st.st_dev; + char *t = blkid_devno_to_devname(devid); + if (!t) { + return -EINVAL; + } + strncpy(partition, t, max); + free(t); + dev_t diskdev; + r = blkid_devno_to_wholedisk(devid, device, max, &diskdev); + if (r < 0) { + return -EINVAL; + } + return 0; +} + +#elif defined(__APPLE__) +#include + +int get_block_device_size(int fd, int64_t *psize) +{ + unsigned long blocksize = 0; + int ret = ::ioctl(fd, DKIOCGETBLOCKSIZE, &blocksize); + if (!ret) { + unsigned long nblocks; + ret = ::ioctl(fd, DKIOCGETBLOCKCOUNT, &nblocks); + if (!ret) + *psize = (int64_t)nblocks * blocksize; + } + if (ret < 0) + ret = -errno; + return ret; +} + +bool block_device_support_discard(const char *devname) +{ + return false; +} + +int block_device_discard(int fd, int64_t offset, int64_t len) +{ + return -EOPNOTSUPP; +} + +bool block_device_is_rotational(const char *devname) +{ + return false; +} + +int get_device_by_uuid(uuid_d dev_uuid, const char* label, char* partition, + char* device) +{ + return -EOPNOTSUPP; +} +#elif defined(__FreeBSD__) +#include + +int get_block_device_size(int fd, int64_t *psize) +{ + int ret = ::ioctl(fd, DIOCGMEDIASIZE, psize); + if (ret < 0) + ret = -errno; + return ret; +} + +bool block_device_support_discard(const char *devname) +{ + return false; +} + +int block_device_discard(int fd, int64_t offset, int64_t len) +{ + return -EOPNOTSUPP; +} + +bool block_device_is_rotational(const char *devname) +{ + return false; +} + +int get_device_by_uuid(uuid_d dev_uuid, const char* label, char* partition, + char* device) +{ + return -EOPNOTSUPP; +} +int get_device_by_fd(int fd, char *partition, char *device, size_t max) +{ + return -EOPNOTSUPP; +} +#else +int get_block_device_size(int fd, int64_t *psize) +{ + return -EOPNOTSUPP; +} + +bool block_device_support_discard(const char *devname) +{ + return false; +} + +int block_device_discard(int fd, int64_t offset, int64_t len) +{ + return -EOPNOTSUPP; +} + +bool block_device_is_rotational(const char *devname) +{ + return false; +} + +int get_device_by_uuid(uuid_d dev_uuid, const char* label, char* partition, + char* device) +{ + return -EOPNOTSUPP; +} + +int get_device_by_fd(int fd, char *partition, char *device, size_t max) +{ + return -EOPNOTSUPP; +} +#endif