// initialize or reload cache variables void init_le_to_pe() { void *handle; int r; if(pv_segments) le_to_pe_exit(); vg_pe_sizes = NULL; vg_pe_sizes_len = 0; lvm2_log_fn(parse_pvs_segments); handle = lvm2_init(); lvm2_log_level(handle, 1); r = lvm2_run(handle, "pvs --noheadings --segments -o+lv_name," "seg_start_pe,segtype"); // if (r) // fprintf(stderr, "command failed\n"); sort_segments(pv_segments, pv_segments_num); lvm2_log_fn(parse_vgs_pe_size); r = lvm2_run(handle, "vgs -o vg_name,vg_extent_size --noheadings"); lvm2_exit(handle); return; }
int main(int argc, char **argv) { void *handle; int r; lvm2_log_fn(test_log_fn); handle = lvm2_init(); lvm2_log_level(handle, 1); r = lvm2_run(handle, "vgs --noheadings vg1"); /* More commands here */ lvm2_exit(handle); return r; }
// convert logical extent from logical volume specified by lv_name, // vg_name and logical extent number (le_num) to physical extent // on specific device struct pv_info *LE_to_PE(const char *vg_name, const char *lv_name, uint64_t le_num) { struct pv_allocations pv_alloc = { .lv_name = (char *)lv_name, .vg_name = (char *)vg_name, .lv_start = le_num }; struct pv_allocations *needle; needle = bsearch(&pv_alloc, pv_segments, pv_segments_num, sizeof(struct pv_allocations), _find_segment); if (!needle) return NULL; struct pv_info *pv_info; pv_info = malloc(sizeof(struct pv_info)); if (!pv_info) { fprintf(stderr, "Out of memory\n"); exit(1); } pv_info->pv_name = strdup(needle->pv_name); if (!pv_info->pv_name) { fprintf(stderr, "Out of memory\n"); exit(1); } pv_info->start_seg = needle->pv_start + (le_num - needle->lv_start); return pv_info; } struct vg_pe_sizes { char *vg_name; uint64_t pe_size; }; struct vg_pe_sizes *vg_pe_sizes; size_t vg_pe_sizes_len; // parse output from lvm2cmd about extent sizes void parse_vgs_pe_size(int level, const char *file, int line, int dm_errno, const char *format) { // disregard debug output if (level != 4) return; char vg_name[4096], pe_size[4096]; uint64_t pe_size_bytes=0; int r; r = sscanf(format, " %4095s %4095s ", vg_name, pe_size); if (r == EOF || r != 2) { fprintf(stderr, "%s:%i Error parsing line %i: %s\n", __FILE__, __LINE__, line, format); return; } double temp; char *tail; temp = strtod(pe_size, &tail); if (temp == 0.0) { fprintf(stderr, "%s:%i Error parsing line %i: %s\n", __FILE__, __LINE__, line, format); return; } switch(tail[0]){ case 'b': case 'B': pe_size_bytes = temp; break; case 'S': pe_size_bytes = temp * 512; break; case 'k': pe_size_bytes = temp * 1024; break; case 'K': pe_size_bytes = temp * 1000; break; case 'm': pe_size_bytes = temp * 1024 * 1024; break; case 'M': pe_size_bytes = temp * 1000 * 1000; break; case 'g': pe_size_bytes = temp * 1024 * 1024 * 1024; break; case 'G': pe_size_bytes = temp * 1000 * 1000 * 1000; break; case 't': pe_size_bytes = temp * 1024 * 1024 * 1024 * 1024; break; case 'T': pe_size_bytes = temp * 1000 * 1000 * 1000 * 1000; break; case 'p': pe_size_bytes = temp * 1024 * 1024 * 1024 * 1024 * 1024; break; case 'P': pe_size_bytes = temp * 1000 * 1000 * 1000 * 1000 * 1000; break; case 'e': pe_size_bytes = temp * 1024 * 1024 * 1024 * 1024 * 1024 * 1024; break; case 'E': pe_size_bytes = temp * 1000 * 1000 * 1000 * 1000 * 1000 * 1000; break; default: pe_size_bytes = temp; /* break; */ } // save info about first volume group if (vg_pe_sizes_len == 0) { vg_pe_sizes = malloc(sizeof(struct vg_pe_sizes)); if (!vg_pe_sizes) goto vgs_failure; vg_pe_sizes[0].vg_name = strdup(vg_name); if (!vg_pe_sizes[0].vg_name) goto vgs_failure; vg_pe_sizes[0].pe_size = pe_size_bytes; vg_pe_sizes_len=1; return; } // save info about subsequent groups vg_pe_sizes = realloc(vg_pe_sizes, sizeof(struct vg_pe_sizes)* (vg_pe_sizes_len+1)); if (!vg_pe_sizes) goto vgs_failure; vg_pe_sizes[vg_pe_sizes_len].vg_name = malloc(strlen(vg_name)+1); if(!vg_pe_sizes[vg_pe_sizes_len].vg_name) goto vgs_failure; strcpy(vg_pe_sizes[vg_pe_sizes_len].vg_name, vg_name); vg_pe_sizes[vg_pe_sizes_len].pe_size = pe_size_bytes; vg_pe_sizes_len+=1; return; vgs_failure: fprintf(stderr, "Out of memory\n"); exit(1); } // return size of extents in provided volume group uint64_t get_pe_size(const char *vg_name) { for(size_t i=0; i<vg_pe_sizes_len; i++) if (!strcmp(vg_pe_sizes[i].vg_name, vg_name)) return vg_pe_sizes[i].pe_size; return 0; } // free allocated memory and objects void le_to_pe_exit(struct program_params *pp) { for(size_t i=0; i<pv_segments_num; i++){ free(pv_segments[i].pv_name); free(pv_segments[i].vg_name); free(pv_segments[i].vg_format); free(pv_segments[i].vg_attr); free(pv_segments[i].lv_name); free(pv_segments[i].pv_type); } free(pv_segments); pv_segments = NULL; pv_segments_num = 0; for(size_t i=0; i<vg_pe_sizes_len; i++) free(vg_pe_sizes[i].vg_name); free(vg_pe_sizes); vg_pe_sizes = NULL; vg_pe_sizes_len = 0; } // initialize or reload cache variables void init_le_to_pe(struct program_params *pp) { // int r; if(pv_segments) le_to_pe_exit(pp); vg_pe_sizes = NULL; vg_pe_sizes_len = 0; lvm2_log_fn(parse_pvs_segments); if (!pp->lvm2_handle) pp->lvm2_handle = lvm2_init(); lvm2_log_level(pp->lvm2_handle, 1); // r = lvm2_run(pp->lvm2_handle, "pvs --noheadings --segments -o+lv_name," "seg_start_pe,segtype --units=b"); // if (r) // fprintf(stderr, "command failed\n"); sort_segments(pv_segments, pv_segments_num); lvm2_log_fn(parse_vgs_pe_size); // r = lvm2_run(pp->lvm2_handle, "vgs -o vg_name,vg_extent_size --noheadings --units=b"); return; } // return number of free extents in PV in specified volume group // or in whole volume group if pv_name is NULL uint64_t get_free_extent_number(const char *vg_name, const char *pv_name) { if (!vg_name) return 0; uint64_t sum=0; if(pv_name) for(size_t i=0; i < pv_segments_num; i++) { if (!strcmp(pv_segments[i].vg_name, vg_name) && !strcmp(pv_segments[i].pv_name, pv_name) && !strcmp(pv_segments[i].pv_type, "free")) sum+=pv_segments[i].pv_length; } else for(size_t i=0; i < pv_segments_num; i++) if (!strcmp(pv_segments[i].vg_name, vg_name) && !strcmp(pv_segments[i].pv_type, "free")) sum+=pv_segments[i].pv_length; return sum; } struct le_info get_first_LE_info(const char *vg_name, const char *lv_name, const char *pv_name) { struct le_info ret = { .dev = NULL }; for (size_t i=0; i < pv_segments_num; i++) { if (!strcmp(pv_segments[i].vg_name, vg_name) && !strcmp(pv_segments[i].pv_name, pv_name) && !strcmp(pv_segments[i].lv_name, lv_name)) { if (ret.dev == NULL) { // save first segment info ret.le = pv_segments[i].lv_start; ret.pe = pv_segments[i].pv_start; ret.dev = pv_segments[i].pv_name; } else { if (ret.le > pv_segments[i].lv_start) { ret.le = pv_segments[i].lv_start; ret.pe = pv_segments[i].pv_start; ret.dev = pv_segments[i].pv_name; } } } } return ret; } struct le_info get_PE_allocation(const char *vg_name, const char *pv_name, uint64_t pe_num) { const char *free_str = "free"; struct le_info ret = { .dev = NULL, .lv_name = NULL }; for (size_t i=0; i < pv_segments_num; i++) { if (!strcmp(pv_segments[i].vg_name, vg_name) && !strcmp(pv_segments[i].pv_name, pv_name) && pv_segments[i].pv_start <= pe_num && pv_segments[i].pv_start + pv_segments[i].pv_length > pe_num) { ret.dev = pv_segments[i].pv_name; if (!strcmp(pv_segments[i].pv_type, free_str)) ret.lv_name = free_str; else ret.lv_name = pv_segments[i].lv_name; uint64_t diff = pe_num - pv_segments[i].pv_start; ret.le = pv_segments[i].lv_start + diff; ret.pe = pv_segments[i].pv_start + diff; return ret; } } return ret; } // return used number of extents by LV on provided PV uint64_t get_used_space_on_pv(const char *vg_name, const char *lv_name, const char *pv_name) { assert(vg_name); assert(lv_name); assert(pv_name); uint64_t sum = 0; for(size_t i=0; i < pv_segments_num; i++) { if(!strcmp(pv_segments[i].lv_name, lv_name) && !strcmp(pv_segments[i].vg_name, vg_name) && !strcmp(pv_segments[i].pv_name, pv_name)) { sum += pv_segments[i].pv_length; } } return sum; }