/* * Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved. * * This file is part of the device-mapper userspace tools. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "dmlib.h" #include "libdm-common.h" int dm_get_status_snapshot(struct dm_pool *mem, const char *params, struct dm_status_snapshot **status) { struct dm_status_snapshot *s; int r; if (!params) { log_error("Failed to parse invalid snapshot params."); return 0; } if (!(s = dm_pool_zalloc(mem, sizeof(*s)))) { log_error("Failed to allocate snapshot status structure."); return 0; } r = sscanf(params, FMTu64 "/" FMTu64 " " FMTu64, &s->used_sectors, &s->total_sectors, &s->metadata_sectors); if (r == 3 || r == 2) s->has_metadata_sectors = (r == 3); else if (!strcmp(params, "Invalid")) s->invalid = 1; else if (!strcmp(params, "Merge failed")) s->merge_failed = 1; else if (!strcmp(params, "Overflow")) s->overflow = 1; else { dm_pool_free(mem, s); log_error("Failed to parse snapshot params: %s.", params); return 0; } *status = s; return 1; } /* * Various RAID status versions include: * Versions < 1.5.0 (4 fields): * <#devs> * Versions 1.5.0+ (6 fields): * <#devs> */ int dm_get_status_raid(struct dm_pool *mem, const char *params, struct dm_status_raid **status) { int i; const char *pp, *p; struct dm_status_raid *s; if (!params || !(p = strchr(params, ' '))) { log_error("Failed to parse invalid raid params."); return 0; } p++; /* second field holds the device count */ if (sscanf(p, "%d", &i) != 1) return_0; if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_raid)))) return_0; if (!(s->raid_type = dm_pool_zalloc(mem, p - params))) goto_bad; /* memory is freed went pool is destroyed */ if (!(s->dev_health = dm_pool_zalloc(mem, i + 1))) goto_bad; if (sscanf(params, "%s %u %s %" PRIu64 "/%" PRIu64, s->raid_type, &s->dev_count, s->dev_health, &s->insync_regions, &s->total_regions) != 5) { log_error("Failed to parse raid params: %s", params); goto bad; } *status = s; /* * All pre-1.5.0 version parameters are read. Now we check * for additional 1.5.0+ parameters. * * Note that 'sync_action' will be NULL (and mismatch_count * will be 0) if the kernel returns a pre-1.5.0 status. */ for (p = params, i = 0; i < 4; i++, p++) if (!(p = strchr(p, ' '))) return 1; /* return pre-1.5.0 status */ pp = p; if (!(p = strchr(p, ' '))) { log_error(INTERNAL_ERROR "Bad RAID status received."); goto bad; } p++; if (!(s->sync_action = dm_pool_zalloc(mem, p - pp))) goto_bad; if (sscanf(pp, "%s %" PRIu64, s->sync_action, &s->mismatch_count) != 2) { log_error("Failed to parse raid params: %s", params); goto bad; } return 1; bad: dm_pool_free(mem, s); return 0; } static const char *_advance_to_next_word(const char *str, int count) { int i; const char *p; for (p = str, i = 0; i < count; i++, p++) if (!(p = strchr(p, ' '))) return NULL; return p; } /* * <#used metadata blocks>/<#total metadata blocks> * <#used cache blocks>/<#total cache blocks> * <#read hits> <#read misses> <#write hits> <#write misses> * <#demotions> <#promotions> <#dirty> <#features> * * <#core args> * <#policy args> * * * metadata block size : Fixed block size for each metadata block in * sectors * #used metadata blocks : Number of metadata blocks used * #total metadata blocks : Total number of metadata blocks * cache block size : Configurable block size for the cache device * in sectors * #used cache blocks : Number of blocks resident in the cache * #total cache blocks : Total number of cache blocks * #read hits : Number of times a READ bio has been mapped * to the cache * #read misses : Number of times a READ bio has been mapped * to the origin * #write hits : Number of times a WRITE bio has been mapped * to the cache * #write misses : Number of times a WRITE bio has been * mapped to the origin * #demotions : Number of times a block has been removed * from the cache * #promotions : Number of times a block has been moved to * the cache * #dirty : Number of blocks in the cache that differ * from the origin * #feature args : Number of feature args to follow * feature args : 'writethrough' (optional) * #core args : Number of core arguments (must be even) * core args : Key/value pairs for tuning the core * e.g. migration_threshold * *policy name : Name of the policy * #policy args : Number of policy arguments to follow (must be even) * policy args : Key/value pairs * e.g. sequential_threshold */ int dm_get_status_cache(struct dm_pool *mem, const char *params, struct dm_status_cache **status) { int i, feature_argc; char *str; const char *p, *pp; struct dm_status_cache *s; if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_cache)))) return_0; /* Read in args that have definitive placement */ if (sscanf(params, " %" PRIu32 " %" PRIu64 "/%" PRIu64 " %" PRIu32 " %" PRIu64 "/%" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %d", &s->metadata_block_size, &s->metadata_used_blocks, &s->metadata_total_blocks, &s->block_size, /* AKA, chunk_size */ &s->used_blocks, &s->total_blocks, &s->read_hits, &s->read_misses, &s->write_hits, &s->write_misses, &s->demotions, &s->promotions, &s->dirty_blocks, &feature_argc) != 14) goto bad; /* Now jump to "features" section */ if (!(p = _advance_to_next_word(params, 12))) goto bad; /* Read in features */ for (i = 0; i < feature_argc; i++) { if (!strncmp(p, "writethrough ", 13)) s->feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH; else if (!strncmp(p, "writeback ", 10)) s->feature_flags |= DM_CACHE_FEATURE_WRITEBACK; else log_error("Unknown feature in status: %s", params); if (!(p = _advance_to_next_word(p, 1))) goto bad; } /* Read in core_args. */ if (sscanf(p, "%d ", &s->core_argc) != 1) goto bad; if (s->core_argc && (!(s->core_argv = dm_pool_zalloc(mem, sizeof(char *) * s->core_argc)) || !(p = _advance_to_next_word(p, 1)) || !(str = dm_pool_strdup(mem, p)) || !(p = _advance_to_next_word(p, s->core_argc)) || (dm_split_words(str, s->core_argc, 0, s->core_argv) != s->core_argc))) goto bad; /* Read in policy args */ pp = p; if (!(p = _advance_to_next_word(p, 1)) || !(s->policy_name = dm_pool_zalloc(mem, (p - pp)))) goto bad; if (sscanf(pp, "%s %d", s->policy_name, &s->policy_argc) != 2) goto bad; if (s->policy_argc && (!(s->policy_argv = dm_pool_zalloc(mem, sizeof(char *) * s->policy_argc)) || !(p = _advance_to_next_word(p, 1)) || !(str = dm_pool_strdup(mem, p)) || (dm_split_words(str, s->policy_argc, 0, s->policy_argv) != s->policy_argc))) goto bad; *status = s; return 1; bad: log_error("Failed to parse cache params: %s", params); dm_pool_free(mem, s); *status = NULL; return 0; } int parse_thin_pool_status(const char *params, struct dm_status_thin_pool *s) { int pos; if (!params) { log_error("Failed to parse invalid thin params."); return 0; } /* FIXME: add support for held metadata root */ if (sscanf(params, FMTu64 " " FMTu64 "/" FMTu64 " " FMTu64 "/" FMTu64 "%n", &s->transaction_id, &s->used_metadata_blocks, &s->total_metadata_blocks, &s->used_data_blocks, &s->total_data_blocks, &pos) < 5) { log_error("Failed to parse thin pool params: %s.", params); return 0; } /* New status flags */ if (strstr(params + pos, "no_discard_passdown")) s->discards = DM_THIN_DISCARDS_NO_PASSDOWN; else if (strstr(params + pos, "ignore_discard")) s->discards = DM_THIN_DISCARDS_IGNORE; else /* default discard_passdown */ s->discards = DM_THIN_DISCARDS_PASSDOWN; if (strstr(params + pos, "ro ")) s->read_only = 1; else if (strstr(params + pos, "fail")) s->fail = 1; else if (strstr(params + pos, "out_of_data_space")) s->out_of_data_space = 1; if (strstr(params + pos, "error_if_no_space")) s->error_if_no_space = 1; return 1; } int dm_get_status_thin_pool(struct dm_pool *mem, const char *params, struct dm_status_thin_pool **status) { struct dm_status_thin_pool *s; if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_thin_pool)))) { log_error("Failed to allocate thin_pool status structure."); return 0; } if (!parse_thin_pool_status(params, s)) { dm_pool_free(mem, s); return_0; } *status = s; return 1; } int dm_get_status_thin(struct dm_pool *mem, const char *params, struct dm_status_thin **status) { struct dm_status_thin *s; if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_thin)))) { log_error("Failed to allocate thin status structure."); return 0; } if (strchr(params, '-')) { s->mapped_sectors = 0; s->highest_mapped_sector = 0; } else if (sscanf(params, FMTu64 " " FMTu64, &s->mapped_sectors, &s->highest_mapped_sector) != 2) { dm_pool_free(mem, s); log_error("Failed to parse thin params: %s.", params); return 0; } *status = s; return 1; }