static int detach_metadata_devices(struct lv_segment *seg, struct dm_list *list) { uint32_t s; uint32_t num_meta_lvs; struct cmd_context *cmd = seg->lv->vg->cmd; struct lv_list *lvl; num_meta_lvs = seg_is_raid(seg) ? seg->area_count : !!seg->log_lv; if (!num_meta_lvs) return_0; if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl) * num_meta_lvs))) return_0; if (seg_is_raid(seg)) { for (s = 0; s < seg->area_count; s++) { if (!seg_metalv(seg, s)) return_0; /* Trap this future possibility */ lvl[s].lv = seg_metalv(seg, s); lv_set_visible(lvl[s].lv); dm_list_add(list, &lvl[s].list); } return 1; } lvl[0].lv = detach_mirror_log(seg); dm_list_add(list, &lvl[0].list); return 1; }
int vg_remove_snapshot(struct logical_volume *cow) { int preload_origin = 0; struct logical_volume *origin = origin_from_cow(cow); dm_list_del(&cow->snapshot->origin_list); origin->origin_count--; if (find_merging_cow(origin) == find_cow(cow)) { clear_snapshot_merge(origin); /* * preload origin IFF "snapshot-merge" target is active * - IMPORTANT: avoids preload if onactivate merge is pending */ if (lv_has_target_type(origin->vg->cmd->mem, origin, NULL, "snapshot-merge")) { /* * preload origin to: * - allow proper release of -cow * - avoid allocations with other devices suspended * when transitioning from "snapshot-merge" to * "snapshot-origin after a merge completes. */ preload_origin = 1; } } if (!lv_remove(cow->snapshot->lv)) { log_error("Failed to remove internal snapshot LV %s", cow->snapshot->lv->name); return 0; } cow->snapshot = NULL; lv_set_visible(cow); if (preload_origin) { if (!vg_write(origin->vg)) return_0; if (!suspend_lv(origin->vg->cmd, origin)) { log_error("Failed to refresh %s without snapshot.", origin->name); return 0; } if (!vg_commit(origin->vg)) return_0; if (!resume_lv(origin->vg->cmd, origin)) { log_error("Failed to resume %s.", origin->name); return 0; } } return 1; }
void clear_snapshot_merge(struct logical_volume *origin) { /* clear merge attributes */ if (origin->snapshot->merge_lv) /* Removed thin volume has to be visible */ lv_set_visible(origin->snapshot->lv); origin->snapshot->merge_lv = NULL; origin->snapshot->status &= ~MERGING; origin->snapshot = NULL; origin->status &= ~MERGING; }
int vg_remove_snapshot(struct logical_volume *cow) { dm_list_del(&cow->snapshot->origin_list); cow->snapshot->origin->origin_count--; if (!lv_remove(cow->snapshot->lv)) { log_error("Failed to remove internal snapshot LV %s", cow->snapshot->lv->name); return 0; } cow->snapshot = NULL; lv_set_visible(cow); return 1; }
int vg_remove_snapshot(struct logical_volume *cow) { int merging_snapshot = 0; struct logical_volume *origin = origin_from_cow(cow); int is_origin_active = lv_is_active(origin); if (is_origin_active && lv_is_virtual_origin(origin)) { if (!deactivate_lv(origin->vg->cmd, origin)) { log_error("Failed to deactivate logical volume \"%s\"", origin->name); return 0; } is_origin_active = 0; } dm_list_del(&cow->snapshot->origin_list); origin->origin_count--; if (lv_is_merging_origin(origin) && (find_snapshot(origin) == find_snapshot(cow))) { clear_snapshot_merge(origin); /* * preload origin IFF "snapshot-merge" target is active * - IMPORTANT: avoids preload if inactivate merge is pending */ if (lv_has_target_type(origin->vg->vgmem, origin, NULL, TARGET_NAME_SNAPSHOT_MERGE)) { /* * preload origin to: * - allow proper release of -cow * - avoid allocations with other devices suspended * when transitioning from "snapshot-merge" to * "snapshot-origin after a merge completes. */ merging_snapshot = 1; } } if (!lv_remove(cow->snapshot->lv)) { log_error("Failed to remove internal snapshot LV %s", cow->snapshot->lv->name); return 0; } cow->snapshot = NULL; lv_set_visible(cow); /* format1 must do the change in one step, with the commit last. */ if (!(origin->vg->fid->fmt->features & FMT_MDAS)) { /* Get the lock for COW volume */ if (is_origin_active && !activate_lv(cow->vg->cmd, cow)) { log_error("Unable to activate logical volume \"%s\"", cow->name); return 0; } return 1; } if (!vg_write(origin->vg)) return_0; /* Skip call suspend, if device is not active */ if (is_origin_active && !suspend_lv(origin->vg->cmd, origin)) { log_error("Failed to refresh %s without snapshot.", origin->name); vg_revert(origin->vg); return 0; } if (!vg_commit(origin->vg)) return_0; if (is_origin_active) { /* * If the snapshot was active and the COW LV is taken away * the LV lock on cluster has to be grabbed, so use * activate_lv() which resumes suspend cow device. */ if (!merging_snapshot && !activate_lv(cow->vg->cmd, cow)) { log_error("Failed to activate %s.", cow->name); return 0; } if (!resume_lv(origin->vg->cmd, origin)) { log_error("Failed to resume %s.", origin->name); return 0; } /* * For merged snapshot and clustered VG activate cow LV so * the following call to deactivate_lv() can clean-up table * entries. For this clustered lock need to be held. */ if (vg_is_clustered(cow->vg) && merging_snapshot && !activate_lv(cow->vg->cmd, cow)) { log_error("Failed to activate %s.", cow->name); return 0; } } return 1; }
/* * lv_cache_remove * @cache_lv * * Given a cache LV, remove the cache layer. This will unlink * the origin and cache_pool, remove the cache LV layer, and promote * the origin to a usable non-cached LV of the same name as the * given cache_lv. * * Returns: 1 on success, 0 on failure */ int lv_cache_remove(struct logical_volume *cache_lv) { struct cmd_context *cmd = cache_lv->vg->cmd; const char *policy_name; uint64_t dirty_blocks; struct lv_segment *cache_seg = first_seg(cache_lv); struct logical_volume *corigin_lv; struct logical_volume *cache_pool_lv; if (!lv_is_cache(cache_lv)) { log_error(INTERNAL_ERROR "LV %s is not cached.", cache_lv->name); return 0; } /* Active volume is needed (writeback only?) */ if (!lv_is_active_locally(cache_lv) && !activate_lv_excl_local(cache_lv->vg->cmd, cache_lv)) { log_error("Failed to active cache locally %s.", cache_lv->name); return 0; } /* * FIXME: * Before the link can be broken, we must ensure that the * cache has been flushed. This may already be the case * if the cache mode is writethrough (or the cleaner * policy is in place from a previous half-finished attempt * to remove the cache_pool). It could take a long time to * flush the cache - it should probably be done in the background. * * Also, if we do perform the flush in the background and we * happen to also be removing the cache/origin LV, then we * could check if the cleaner policy is in place and simply * remove the cache_pool then without waiting for the flush to * complete. */ if (!lv_cache_policy_info(cache_lv, &policy_name, NULL, NULL)) return_0; if (strcmp(policy_name, "cleaner")) { /* We must swap in the cleaner to flush the cache */ log_print_unless_silent("Flushing cache for %s.", cache_lv->name); /* * Is there are clean way to free the memory for the name * and argv when changing the policy? */ cache_seg->policy_name = "cleaner"; cache_seg->policy_argc = 0; cache_seg->policy_argv = NULL; /* update the kernel to put the cleaner policy in place */ if (!vg_write(cache_lv->vg)) return_0; if (!suspend_lv(cmd, cache_lv)) return_0; if (!vg_commit(cache_lv->vg)) return_0; if (!resume_lv(cmd, cache_lv)) return_0; } //FIXME: use polling to do this... do { if (!lv_cache_block_info(cache_lv, NULL, &dirty_blocks, NULL, NULL)) return_0; log_print_unless_silent("%" PRIu64 " blocks must still be flushed.", dirty_blocks); if (dirty_blocks) sleep(1); } while (dirty_blocks); cache_pool_lv = cache_seg->pool_lv; if (!detach_pool_lv(cache_seg)) return_0; /* Regular LV which user may remove if there are problems */ corigin_lv = seg_lv(cache_seg, 0); lv_set_visible(corigin_lv); if (!remove_layer_from_lv(cache_lv, corigin_lv)) return_0; if (!vg_write(cache_lv->vg)) return_0; /* * suspend_lv on this cache LV suspends all components: * - the top-level cache LV * - the origin * - the cache_pool _cdata and _cmeta */ if (!suspend_lv(cmd, cache_lv)) return_0; if (!vg_commit(cache_lv->vg)) return_0; /* resume_lv on this (former) cache LV will resume all */ /* * FIXME: currently we can't easily avoid execution of * blkid on resumed error device */ if (!resume_lv(cmd, cache_lv)) return_0; /* * cleanup orphan devices * * FIXME: * fix _add_dev() to support this case better * since the should be handled interanlly by resume_lv() * which should autoremove any orhpans */ if (!_cleanup_orphan_lv(corigin_lv)) /* _corig */ return_0; if (!_cleanup_orphan_lv(seg_lv(first_seg(cache_pool_lv), 0))) /* _cdata */ return_0; if (!_cleanup_orphan_lv(first_seg(cache_pool_lv)->metadata_lv)) /* _cmeta */ return_0; if (!lv_remove(corigin_lv)) return_0; return 1; }