482
485
struct dm_info *info, uint32_t *read_ahead)
488
char old_style_dlid[sizeof(UUID_PREFIX) + 2 * ID_LEN];
489
const char *suffix, *suffix_position;
486
493
if ((r = _info_run(NULL, dlid, info, read_ahead, 0, with_open_count,
487
494
with_read_ahead, 0, 0)) && info->exists)
489
else if ((r = _info_run(NULL, dlid + sizeof(UUID_PREFIX) - 1, info,
497
/* Check for original version of dlid before the suffixes got added in 2.02.106 */
498
if ((suffix_position = rindex(dlid, '-'))) {
499
while ((suffix = uuid_suffix_list[i++])) {
500
if (strcmp(suffix_position + 1, suffix))
503
(void) strncpy(old_style_dlid, dlid, sizeof(old_style_dlid));
504
old_style_dlid[sizeof(old_style_dlid) - 1] = '\0';
505
if ((r = _info_run(NULL, old_style_dlid, info, read_ahead, 0, with_open_count,
506
with_read_ahead, 0, 0)) && info->exists)
511
/* Check for dlid before UUID_PREFIX was added */
512
if ((r = _info_run(NULL, dlid + sizeof(UUID_PREFIX) - 1, info,
490
513
read_ahead, 0, with_open_count,
491
514
with_read_ahead, 0, 0)) && info->exists)
722
static percent_range_t _combine_percent(percent_t a, percent_t b,
723
uint32_t numerator, uint32_t denominator)
745
static dm_percent_range_t _combine_percent(dm_percent_t a, dm_percent_t b,
746
uint32_t numerator, uint32_t denominator)
725
if (a == PERCENT_MERGE_FAILED || b == PERCENT_MERGE_FAILED)
726
return PERCENT_MERGE_FAILED;
728
if (a == PERCENT_INVALID || b == PERCENT_INVALID)
729
return PERCENT_INVALID;
731
if (a == PERCENT_100 && b == PERCENT_100)
734
if (a == PERCENT_0 && b == PERCENT_0)
737
return (percent_range_t) make_percent(numerator, denominator);
748
if (a == LVM_PERCENT_MERGE_FAILED || b == LVM_PERCENT_MERGE_FAILED)
749
return LVM_PERCENT_MERGE_FAILED;
751
if (a == DM_PERCENT_INVALID || b == DM_PERCENT_INVALID)
752
return DM_PERCENT_INVALID;
754
if (a == DM_PERCENT_100 && b == DM_PERCENT_100)
755
return DM_PERCENT_100;
757
if (a == DM_PERCENT_0 && b == DM_PERCENT_0)
760
return (dm_percent_range_t) dm_make_percent(numerator, denominator);
740
763
static int _percent_run(struct dev_manager *dm, const char *name,
741
764
const char *dlid,
742
765
const char *target_type, int wait,
743
const struct logical_volume *lv, percent_t *overall_percent,
766
const struct logical_volume *lv, dm_percent_t *overall_percent,
744
767
uint32_t *event_nr, int fail_if_percent_unsupported)
1706
struct thin_cb_data {
1729
struct pool_cb_data {
1730
struct dev_manager *dm;
1707
1731
const struct logical_volume *pool_lv;
1708
struct dev_manager *dm;
1733
int skip_zero; /* to skip zeroed device header (check first 64B) */
1734
int exec; /* which binary to call */
1736
const char *defaults;
1711
static int _thin_pool_callback(struct dm_tree_node *node,
1712
dm_node_callback_t type, void *cb_data)
1740
static int _pool_callback(struct dm_tree_node *node,
1741
dm_node_callback_t type, void *cb_data)
1715
const struct thin_cb_data *data = cb_data;
1716
const char *dmdir = dm_dir();
1743
int ret, status, fd;
1717
1745
const struct dm_config_node *cn;
1718
1746
const struct dm_config_value *cv;
1719
const char *thin_check =
1720
find_config_tree_str_allow_empty(data->pool_lv->vg->cmd, global_thin_check_executable_CFG, NULL);
1721
const struct logical_volume *mlv = first_seg(data->pool_lv)->metadata_lv;
1722
size_t len = strlen(dmdir) + 2 * (strlen(mlv->vg->name) + strlen(mlv->name)) + 3;
1723
char meta_path[len];
1747
const struct pool_cb_data *data = cb_data;
1748
const struct logical_volume *pool_lv = data->pool_lv;
1749
const struct logical_volume *mlv = first_seg(pool_lv)->metadata_lv;
1750
long buf[64 / sizeof(long)]; /* buffer for short disk header (64B) */
1725
const char *argv[19]; /* Max supported 15 args */
1726
char *split, *dm_name;
1752
const char *argv[19] = { /* Max supported 15 args */
1753
find_config_tree_str_allow_empty(pool_lv->vg->cmd, data->exec, NULL) /* argv[0] */
1729
1757
return 1; /* Checking disabled */
1731
if (!(dm_name = dm_build_dm_name(data->dm->mem, mlv->vg->name,
1732
mlv->name, NULL)) ||
1733
(dm_snprintf(meta_path, len, "%s/%s", dmdir, dm_name) < 0)) {
1734
log_error("Failed to build thin metadata path.");
1738
if ((cn = find_config_tree_node(mlv->vg->cmd, global_thin_check_options_CFG, NULL))) {
1759
if ((cn = find_config_tree_node(mlv->vg->cmd, data->opts, NULL))) {
1739
1760
for (cv = cn->v; cv && args < 16; cv = cv->next) {
1740
1761
if (cv->type != DM_CFG_STRING) {
1741
1762
log_error("Invalid string in config file: "
1742
"global/thin_check_options");
1763
"global/%s_check_options",
1745
1767
argv[++args] = cv->v.str;
1748
1770
/* Use default options (no support for options with spaces) */
1749
if (!(split = dm_pool_strdup(data->dm->mem, DEFAULT_THIN_CHECK_OPTIONS))) {
1750
log_error("Failed to duplicate thin check string.");
1771
if (!(split = dm_pool_strdup(data->dm->mem, data->defaults))) {
1772
log_error("Failed to duplicate defaults.");
1753
1775
args = dm_split_words(split, 16, 0, (char**) argv + 1);
1756
1778
if (args == 16) {
1757
log_error("Too many options for thin check command.");
1761
argv[0] = thin_check;
1762
argv[++args] = meta_path;
1763
argv[++args] = NULL;
1765
if (!(ret = exec_cmd(data->pool_lv->vg->cmd, (const char * const *)argv,
1779
log_error("Too many options for %s command.", argv[0]);
1783
if (!(argv[++args] = lv_dmpath_dup(data->dm->mem, mlv))) {
1784
log_error("Failed to build pool metadata path.");
1788
if (data->skip_zero) {
1789
if ((fd = open(argv[args], O_RDONLY)) < 0) {
1790
log_sys_error("open", argv[args]);
1793
/* let's assume there is no problem to read 64 bytes */
1794
if (read(fd, buf, sizeof(buf)) < sizeof(buf)) {
1795
log_sys_error("read", argv[args]);
1798
for (ret = 0; ret < DM_ARRAY_SIZE(buf); ++ret)
1803
log_sys_error("close", argv[args]);
1805
if (ret == DM_ARRAY_SIZE(buf)) {
1806
log_debug("%s skipped, detect empty disk header on %s.",
1807
argv[0], argv[args]);
1812
if (!(ret = exec_cmd(pool_lv->vg->cmd, (const char * const *)argv,
1766
1813
&status, 0))) {
1767
1814
switch (type) {
1768
1815
case DM_NODE_CALLBACK_PRELOADED:
1769
log_err_once("Check of thin pool %s/%s failed (status:%d). "
1770
"Manual repair required (thin_dump --repair %s)!",
1771
data->pool_lv->vg->name, data->pool_lv->name,
1816
log_err_once("Check of pool %s failed (status:%d). "
1817
"Manual repair required!",
1818
display_lvname(pool_lv), status);
1775
log_warn("WARNING: Integrity check of metadata for thin pool "
1777
data->pool_lv->vg->name, data->pool_lv->name);
1821
log_warn("WARNING: Integrity check of metadata for pool "
1822
"%s failed.", display_lvname(pool_lv));
1780
1825
* FIXME: What should we do here??
1782
1827
* Maybe mark the node, so it's not activating
1783
* as thin_pool but as error/linear and let the
1828
* as pool but as error/linear and let the
1784
1829
* dm tree resolve the issue.
1788
dm_pool_free(data->dm->mem, dm_name);
1793
static int _thin_pool_register_callback(struct dev_manager *dm,
1794
struct dm_tree_node *node,
1795
const struct logical_volume *lv)
1836
static int _pool_register_callback(struct dev_manager *dm,
1837
struct dm_tree_node *node,
1838
const struct logical_volume *lv)
1797
struct thin_cb_data *data;
1840
struct pool_cb_data *data;
1799
/* Skip metadata testing for unused pool. */
1800
if (!first_seg(lv)->transaction_id ||
1801
((first_seg(lv)->transaction_id == 1) &&
1802
pool_has_message(first_seg(lv), NULL, 0)))
1842
/* Skip metadata testing for unused thin pool. */
1843
if (lv_is_thin_pool(lv) &&
1844
(!first_seg(lv)->transaction_id ||
1845
((first_seg(lv)->transaction_id == 1) &&
1846
pool_has_message(first_seg(lv), NULL, 0))))
1805
if (!(data = dm_pool_alloc(dm->mem, sizeof(*data)))) {
1849
if (!(data = dm_pool_zalloc(dm->mem, sizeof(*data)))) {
1806
1850
log_error("Failed to allocated path for callback.");
1813
dm_tree_node_set_callback(node, _thin_pool_callback, data);
1856
if (lv_is_thin_pool(lv)) {
1858
data->skip_zero = 1;
1859
data->exec = global_thin_check_executable_CFG;
1860
data->opts = global_thin_check_options_CFG;
1861
data->defaults = DEFAULT_THIN_CHECK_OPTIONS;
1862
data->global = "thin";
1863
} else if (lv_is_cache(lv)) { /* cache pool */
1864
data->pool_lv = first_seg(lv)->pool_lv;
1865
data->skip_zero = dm->activation;
1866
data->exec = global_cache_check_executable_CFG;
1867
data->opts = global_cache_check_options_CFG;
1868
data->defaults = DEFAULT_CACHE_CHECK_OPTIONS;
1869
data->global = "cache";
1871
log_error(INTERNAL_ERROR "Registering unsupported pool callback.");
1875
dm_tree_node_set_callback(node, _pool_callback, data);