186d7f5d3SJohn Marino /* $NetBSD: lvconvert.c,v 1.1.1.2 2009/12/02 00:25:50 haad Exp $ */
286d7f5d3SJohn Marino
386d7f5d3SJohn Marino /*
486d7f5d3SJohn Marino * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
586d7f5d3SJohn Marino *
686d7f5d3SJohn Marino * This file is part of LVM2.
786d7f5d3SJohn Marino *
886d7f5d3SJohn Marino * This copyrighted material is made available to anyone wishing to use,
986d7f5d3SJohn Marino * modify, copy, or redistribute it subject to the terms and conditions
1086d7f5d3SJohn Marino * of the GNU Lesser General Public License v.2.1.
1186d7f5d3SJohn Marino *
1286d7f5d3SJohn Marino * You should have received a copy of the GNU Lesser General Public License
1386d7f5d3SJohn Marino * along with this program; if not, write to the Free Software Foundation,
1486d7f5d3SJohn Marino * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1586d7f5d3SJohn Marino */
1686d7f5d3SJohn Marino
1786d7f5d3SJohn Marino #include "tools.h"
1886d7f5d3SJohn Marino #include "polldaemon.h"
1986d7f5d3SJohn Marino #include "lv_alloc.h"
2086d7f5d3SJohn Marino
2186d7f5d3SJohn Marino struct lvconvert_params {
2286d7f5d3SJohn Marino int snapshot;
2386d7f5d3SJohn Marino int zero;
2486d7f5d3SJohn Marino
2586d7f5d3SJohn Marino const char *origin;
2686d7f5d3SJohn Marino const char *lv_name;
2786d7f5d3SJohn Marino const char *lv_name_full;
2886d7f5d3SJohn Marino const char *vg_name;
2986d7f5d3SJohn Marino int wait_completion;
3086d7f5d3SJohn Marino int need_polling;
3186d7f5d3SJohn Marino
3286d7f5d3SJohn Marino uint32_t chunk_size;
3386d7f5d3SJohn Marino uint32_t region_size;
3486d7f5d3SJohn Marino
3586d7f5d3SJohn Marino uint32_t mirrors;
3686d7f5d3SJohn Marino sign_t mirrors_sign;
3786d7f5d3SJohn Marino
3886d7f5d3SJohn Marino struct segment_type *segtype;
3986d7f5d3SJohn Marino
4086d7f5d3SJohn Marino alloc_policy_t alloc;
4186d7f5d3SJohn Marino
4286d7f5d3SJohn Marino int pv_count;
4386d7f5d3SJohn Marino char **pvs;
4486d7f5d3SJohn Marino struct dm_list *pvh;
4586d7f5d3SJohn Marino };
4686d7f5d3SJohn Marino
_lvconvert_name_params(struct lvconvert_params * lp,struct cmd_context * cmd,int * pargc,char *** pargv)4786d7f5d3SJohn Marino static int _lvconvert_name_params(struct lvconvert_params *lp,
4886d7f5d3SJohn Marino struct cmd_context *cmd,
4986d7f5d3SJohn Marino int *pargc, char ***pargv)
5086d7f5d3SJohn Marino {
5186d7f5d3SJohn Marino char *ptr;
5286d7f5d3SJohn Marino const char *vg_name = NULL;
5386d7f5d3SJohn Marino
5486d7f5d3SJohn Marino if (lp->snapshot) {
5586d7f5d3SJohn Marino if (!*pargc) {
5686d7f5d3SJohn Marino log_error("Please specify a logical volume to act as "
5786d7f5d3SJohn Marino "the snapshot origin.");
5886d7f5d3SJohn Marino return 0;
5986d7f5d3SJohn Marino }
6086d7f5d3SJohn Marino
6186d7f5d3SJohn Marino lp->origin = *pargv[0];
6286d7f5d3SJohn Marino (*pargv)++, (*pargc)--;
6386d7f5d3SJohn Marino if (!(lp->vg_name = extract_vgname(cmd, lp->origin))) {
6486d7f5d3SJohn Marino log_error("The origin name should include the "
6586d7f5d3SJohn Marino "volume group.");
6686d7f5d3SJohn Marino return 0;
6786d7f5d3SJohn Marino }
6886d7f5d3SJohn Marino
6986d7f5d3SJohn Marino /* Strip the volume group from the origin */
7086d7f5d3SJohn Marino if ((ptr = strrchr(lp->origin, (int) '/')))
7186d7f5d3SJohn Marino lp->origin = ptr + 1;
7286d7f5d3SJohn Marino }
7386d7f5d3SJohn Marino
7486d7f5d3SJohn Marino if (!*pargc) {
7586d7f5d3SJohn Marino log_error("Please provide logical volume path");
7686d7f5d3SJohn Marino return 0;
7786d7f5d3SJohn Marino }
7886d7f5d3SJohn Marino
7986d7f5d3SJohn Marino lp->lv_name = lp->lv_name_full = (*pargv)[0];
8086d7f5d3SJohn Marino (*pargv)++, (*pargc)--;
8186d7f5d3SJohn Marino
8286d7f5d3SJohn Marino if (strchr(lp->lv_name_full, '/') &&
8386d7f5d3SJohn Marino (vg_name = extract_vgname(cmd, lp->lv_name_full)) &&
8486d7f5d3SJohn Marino lp->vg_name && strcmp(vg_name, lp->vg_name)) {
8586d7f5d3SJohn Marino log_error("Please use a single volume group name "
8686d7f5d3SJohn Marino "(\"%s\" or \"%s\")", vg_name, lp->vg_name);
8786d7f5d3SJohn Marino return 0;
8886d7f5d3SJohn Marino }
8986d7f5d3SJohn Marino
9086d7f5d3SJohn Marino if (!lp->vg_name)
9186d7f5d3SJohn Marino lp->vg_name = vg_name;
9286d7f5d3SJohn Marino
9386d7f5d3SJohn Marino if (!validate_name(lp->vg_name)) {
9486d7f5d3SJohn Marino log_error("Please provide a valid volume group name");
9586d7f5d3SJohn Marino return 0;
9686d7f5d3SJohn Marino }
9786d7f5d3SJohn Marino
9886d7f5d3SJohn Marino if ((ptr = strrchr(lp->lv_name_full, '/')))
9986d7f5d3SJohn Marino lp->lv_name = ptr + 1;
10086d7f5d3SJohn Marino
10186d7f5d3SJohn Marino if (!apply_lvname_restrictions(lp->lv_name))
10286d7f5d3SJohn Marino return_0;
10386d7f5d3SJohn Marino
10486d7f5d3SJohn Marino return 1;
10586d7f5d3SJohn Marino }
10686d7f5d3SJohn Marino
_read_params(struct lvconvert_params * lp,struct cmd_context * cmd,int argc,char ** argv)10786d7f5d3SJohn Marino static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
10886d7f5d3SJohn Marino int argc, char **argv)
10986d7f5d3SJohn Marino {
11086d7f5d3SJohn Marino int region_size;
11186d7f5d3SJohn Marino int pagesize = lvm_getpagesize();
11286d7f5d3SJohn Marino
11386d7f5d3SJohn Marino memset(lp, 0, sizeof(*lp));
11486d7f5d3SJohn Marino
11586d7f5d3SJohn Marino if (arg_count(cmd, snapshot_ARG) &&
11686d7f5d3SJohn Marino (arg_count(cmd, mirrorlog_ARG) || arg_count(cmd, mirrors_ARG) ||
11786d7f5d3SJohn Marino arg_count(cmd, repair_ARG))) {
11886d7f5d3SJohn Marino log_error("--snapshot argument cannot be mixed "
11986d7f5d3SJohn Marino "with --mirrors, --repair or --log");
12086d7f5d3SJohn Marino return 0;
12186d7f5d3SJohn Marino }
12286d7f5d3SJohn Marino
12386d7f5d3SJohn Marino if (!arg_count(cmd, background_ARG))
12486d7f5d3SJohn Marino lp->wait_completion = 1;
12586d7f5d3SJohn Marino
12686d7f5d3SJohn Marino if (arg_count(cmd, snapshot_ARG))
12786d7f5d3SJohn Marino lp->snapshot = 1;
12886d7f5d3SJohn Marino
12986d7f5d3SJohn Marino if (arg_count(cmd, mirrors_ARG)) {
13086d7f5d3SJohn Marino lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0);
13186d7f5d3SJohn Marino lp->mirrors_sign = arg_sign_value(cmd, mirrors_ARG, 0);
13286d7f5d3SJohn Marino }
13386d7f5d3SJohn Marino
13486d7f5d3SJohn Marino lp->alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
13586d7f5d3SJohn Marino
13686d7f5d3SJohn Marino if (lp->snapshot) {
13786d7f5d3SJohn Marino if (arg_count(cmd, regionsize_ARG)) {
13886d7f5d3SJohn Marino log_error("--regionsize is only available with mirrors");
13986d7f5d3SJohn Marino return 0;
14086d7f5d3SJohn Marino }
14186d7f5d3SJohn Marino
14286d7f5d3SJohn Marino if (arg_sign_value(cmd, chunksize_ARG, 0) == SIGN_MINUS) {
14386d7f5d3SJohn Marino log_error("Negative chunk size is invalid");
14486d7f5d3SJohn Marino return 0;
14586d7f5d3SJohn Marino }
14686d7f5d3SJohn Marino lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, 8);
14786d7f5d3SJohn Marino if (lp->chunk_size < 8 || lp->chunk_size > 1024 ||
14886d7f5d3SJohn Marino (lp->chunk_size & (lp->chunk_size - 1))) {
14986d7f5d3SJohn Marino log_error("Chunk size must be a power of 2 in the "
15086d7f5d3SJohn Marino "range 4K to 512K");
15186d7f5d3SJohn Marino return 0;
15286d7f5d3SJohn Marino }
15386d7f5d3SJohn Marino log_verbose("Setting chunksize to %d sectors.", lp->chunk_size);
15486d7f5d3SJohn Marino
15586d7f5d3SJohn Marino if (!(lp->segtype = get_segtype_from_string(cmd, "snapshot")))
15686d7f5d3SJohn Marino return_0;
15786d7f5d3SJohn Marino
15886d7f5d3SJohn Marino lp->zero = strcmp(arg_str_value(cmd, zero_ARG,
15986d7f5d3SJohn Marino (lp->segtype->flags &
16086d7f5d3SJohn Marino SEG_CANNOT_BE_ZEROED) ?
16186d7f5d3SJohn Marino "n" : "y"), "n");
16286d7f5d3SJohn Marino
16386d7f5d3SJohn Marino } else { /* Mirrors */
16486d7f5d3SJohn Marino if (arg_count(cmd, chunksize_ARG)) {
16586d7f5d3SJohn Marino log_error("--chunksize is only available with "
16686d7f5d3SJohn Marino "snapshots");
16786d7f5d3SJohn Marino return 0;
16886d7f5d3SJohn Marino }
16986d7f5d3SJohn Marino
17086d7f5d3SJohn Marino if (arg_count(cmd, zero_ARG)) {
17186d7f5d3SJohn Marino log_error("--zero is only available with snapshots");
17286d7f5d3SJohn Marino return 0;
17386d7f5d3SJohn Marino }
17486d7f5d3SJohn Marino
17586d7f5d3SJohn Marino /*
17686d7f5d3SJohn Marino * --regionsize is only valid if converting an LV into a mirror.
17786d7f5d3SJohn Marino * Checked when we know the state of the LV being converted.
17886d7f5d3SJohn Marino */
17986d7f5d3SJohn Marino
18086d7f5d3SJohn Marino if (arg_count(cmd, regionsize_ARG)) {
18186d7f5d3SJohn Marino if (arg_sign_value(cmd, regionsize_ARG, 0) ==
18286d7f5d3SJohn Marino SIGN_MINUS) {
18386d7f5d3SJohn Marino log_error("Negative regionsize is invalid");
18486d7f5d3SJohn Marino return 0;
18586d7f5d3SJohn Marino }
18686d7f5d3SJohn Marino lp->region_size = arg_uint_value(cmd, regionsize_ARG, 0);
18786d7f5d3SJohn Marino } else {
18886d7f5d3SJohn Marino region_size = 2 * find_config_tree_int(cmd,
18986d7f5d3SJohn Marino "activation/mirror_region_size",
19086d7f5d3SJohn Marino DEFAULT_MIRROR_REGION_SIZE);
19186d7f5d3SJohn Marino if (region_size < 0) {
19286d7f5d3SJohn Marino log_error("Negative regionsize in "
19386d7f5d3SJohn Marino "configuration file is invalid");
19486d7f5d3SJohn Marino return 0;
19586d7f5d3SJohn Marino }
19686d7f5d3SJohn Marino lp->region_size = region_size;
19786d7f5d3SJohn Marino }
19886d7f5d3SJohn Marino
19986d7f5d3SJohn Marino if (lp->region_size % (pagesize >> SECTOR_SHIFT)) {
20086d7f5d3SJohn Marino log_error("Region size (%" PRIu32 ") must be "
20186d7f5d3SJohn Marino "a multiple of machine memory "
20286d7f5d3SJohn Marino "page size (%d)",
20386d7f5d3SJohn Marino lp->region_size, pagesize >> SECTOR_SHIFT);
20486d7f5d3SJohn Marino return 0;
20586d7f5d3SJohn Marino }
20686d7f5d3SJohn Marino
20786d7f5d3SJohn Marino if (lp->region_size & (lp->region_size - 1)) {
20886d7f5d3SJohn Marino log_error("Region size (%" PRIu32
20986d7f5d3SJohn Marino ") must be a power of 2", lp->region_size);
21086d7f5d3SJohn Marino return 0;
21186d7f5d3SJohn Marino }
21286d7f5d3SJohn Marino
21386d7f5d3SJohn Marino if (!lp->region_size) {
21486d7f5d3SJohn Marino log_error("Non-zero region size must be supplied.");
21586d7f5d3SJohn Marino return 0;
21686d7f5d3SJohn Marino }
21786d7f5d3SJohn Marino
21886d7f5d3SJohn Marino if (!(lp->segtype = get_segtype_from_string(cmd, "mirror")))
21986d7f5d3SJohn Marino return_0;
22086d7f5d3SJohn Marino }
22186d7f5d3SJohn Marino
22286d7f5d3SJohn Marino if (activation() && lp->segtype->ops->target_present &&
22386d7f5d3SJohn Marino !lp->segtype->ops->target_present(cmd, NULL, NULL)) {
22486d7f5d3SJohn Marino log_error("%s: Required device-mapper target(s) not "
22586d7f5d3SJohn Marino "detected in your kernel", lp->segtype->name);
22686d7f5d3SJohn Marino return 0;
22786d7f5d3SJohn Marino }
22886d7f5d3SJohn Marino
22986d7f5d3SJohn Marino if (!_lvconvert_name_params(lp, cmd, &argc, &argv))
23086d7f5d3SJohn Marino return_0;
23186d7f5d3SJohn Marino
23286d7f5d3SJohn Marino lp->pv_count = argc;
23386d7f5d3SJohn Marino lp->pvs = argv;
23486d7f5d3SJohn Marino
23586d7f5d3SJohn Marino return 1;
23686d7f5d3SJohn Marino }
23786d7f5d3SJohn Marino
_get_lvconvert_vg(struct cmd_context * cmd,const char * lv_name,const char * uuid)23886d7f5d3SJohn Marino static struct volume_group *_get_lvconvert_vg(struct cmd_context *cmd,
23986d7f5d3SJohn Marino const char *lv_name, const char *uuid)
24086d7f5d3SJohn Marino {
24186d7f5d3SJohn Marino dev_close_all();
24286d7f5d3SJohn Marino
24386d7f5d3SJohn Marino return vg_read_for_update(cmd, extract_vgname(cmd, lv_name),
24486d7f5d3SJohn Marino NULL, 0);
24586d7f5d3SJohn Marino }
24686d7f5d3SJohn Marino
_get_lvconvert_lv(struct cmd_context * cmd __attribute ((unused)),struct volume_group * vg,const char * name,const char * uuid,uint32_t lv_type __attribute ((unused)))24786d7f5d3SJohn Marino static struct logical_volume *_get_lvconvert_lv(struct cmd_context *cmd __attribute((unused)),
24886d7f5d3SJohn Marino struct volume_group *vg,
24986d7f5d3SJohn Marino const char *name,
25086d7f5d3SJohn Marino const char *uuid,
25186d7f5d3SJohn Marino uint32_t lv_type __attribute((unused)))
25286d7f5d3SJohn Marino {
25386d7f5d3SJohn Marino struct logical_volume *lv = find_lv(vg, name);
25486d7f5d3SJohn Marino
25586d7f5d3SJohn Marino if (!lv || (uuid && strcmp(uuid, (char *)&lv->lvid)))
25686d7f5d3SJohn Marino return NULL;
25786d7f5d3SJohn Marino
25886d7f5d3SJohn Marino return lv;
25986d7f5d3SJohn Marino }
26086d7f5d3SJohn Marino
_update_lvconvert_mirror(struct cmd_context * cmd __attribute ((unused)),struct volume_group * vg __attribute ((unused)),struct logical_volume * lv __attribute ((unused)),struct dm_list * lvs_changed __attribute ((unused)),unsigned flags __attribute ((unused)))26186d7f5d3SJohn Marino static int _update_lvconvert_mirror(struct cmd_context *cmd __attribute((unused)),
26286d7f5d3SJohn Marino struct volume_group *vg __attribute((unused)),
26386d7f5d3SJohn Marino struct logical_volume *lv __attribute((unused)),
26486d7f5d3SJohn Marino struct dm_list *lvs_changed __attribute((unused)),
26586d7f5d3SJohn Marino unsigned flags __attribute((unused)))
26686d7f5d3SJohn Marino {
26786d7f5d3SJohn Marino /* lvconvert mirror doesn't require periodical metadata update */
26886d7f5d3SJohn Marino return 1;
26986d7f5d3SJohn Marino }
27086d7f5d3SJohn Marino
_finish_lvconvert_mirror(struct cmd_context * cmd,struct volume_group * vg,struct logical_volume * lv,struct dm_list * lvs_changed __attribute ((unused)))27186d7f5d3SJohn Marino static int _finish_lvconvert_mirror(struct cmd_context *cmd,
27286d7f5d3SJohn Marino struct volume_group *vg,
27386d7f5d3SJohn Marino struct logical_volume *lv,
27486d7f5d3SJohn Marino struct dm_list *lvs_changed __attribute((unused)))
27586d7f5d3SJohn Marino {
27686d7f5d3SJohn Marino int r = 0;
27786d7f5d3SJohn Marino
27886d7f5d3SJohn Marino if (!collapse_mirrored_lv(lv)) {
27986d7f5d3SJohn Marino log_error("Failed to remove temporary sync layer.");
28086d7f5d3SJohn Marino return 0;
28186d7f5d3SJohn Marino }
28286d7f5d3SJohn Marino
28386d7f5d3SJohn Marino lv->status &= ~CONVERTING;
28486d7f5d3SJohn Marino
28586d7f5d3SJohn Marino log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
28686d7f5d3SJohn Marino
28786d7f5d3SJohn Marino if (!vg_write(vg))
28886d7f5d3SJohn Marino return_0;
28986d7f5d3SJohn Marino
29086d7f5d3SJohn Marino if (!suspend_lv(cmd, lv)) {
29186d7f5d3SJohn Marino log_error("Failed to lock %s", lv->name);
29286d7f5d3SJohn Marino vg_revert(vg);
29386d7f5d3SJohn Marino goto out;
29486d7f5d3SJohn Marino }
29586d7f5d3SJohn Marino
29686d7f5d3SJohn Marino if (!vg_commit(vg)) {
29786d7f5d3SJohn Marino resume_lv(cmd, lv);
29886d7f5d3SJohn Marino goto_out;
29986d7f5d3SJohn Marino }
30086d7f5d3SJohn Marino
30186d7f5d3SJohn Marino log_very_verbose("Updating \"%s\" in kernel", lv->name);
30286d7f5d3SJohn Marino
30386d7f5d3SJohn Marino if (!resume_lv(cmd, lv)) {
30486d7f5d3SJohn Marino log_error("Problem reactivating %s", lv->name);
30586d7f5d3SJohn Marino goto out;
30686d7f5d3SJohn Marino }
30786d7f5d3SJohn Marino
30886d7f5d3SJohn Marino r = 1;
30986d7f5d3SJohn Marino log_print("Logical volume %s converted.", lv->name);
31086d7f5d3SJohn Marino out:
31186d7f5d3SJohn Marino backup(vg);
31286d7f5d3SJohn Marino return r;
31386d7f5d3SJohn Marino }
31486d7f5d3SJohn Marino
31586d7f5d3SJohn Marino static struct poll_functions _lvconvert_mirror_fns = {
31686d7f5d3SJohn Marino .get_copy_vg = _get_lvconvert_vg,
31786d7f5d3SJohn Marino .get_copy_lv = _get_lvconvert_lv,
31886d7f5d3SJohn Marino .poll_progress = poll_mirror_progress,
31986d7f5d3SJohn Marino .update_metadata = _update_lvconvert_mirror,
32086d7f5d3SJohn Marino .finish_copy = _finish_lvconvert_mirror,
32186d7f5d3SJohn Marino };
32286d7f5d3SJohn Marino
lvconvert_poll(struct cmd_context * cmd,struct logical_volume * lv,unsigned background)32386d7f5d3SJohn Marino int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv,
32486d7f5d3SJohn Marino unsigned background)
32586d7f5d3SJohn Marino {
32686d7f5d3SJohn Marino int len = strlen(lv->vg->name) + strlen(lv->name) + 2;
32786d7f5d3SJohn Marino char *uuid = alloca(sizeof(lv->lvid));
32886d7f5d3SJohn Marino char *lv_full_name = alloca(len);
32986d7f5d3SJohn Marino
33086d7f5d3SJohn Marino
33186d7f5d3SJohn Marino if (!uuid || !lv_full_name)
33286d7f5d3SJohn Marino return_0;
33386d7f5d3SJohn Marino
33486d7f5d3SJohn Marino if (!dm_snprintf(lv_full_name, len, "%s/%s", lv->vg->name, lv->name))
33586d7f5d3SJohn Marino return_0;
33686d7f5d3SJohn Marino
33786d7f5d3SJohn Marino memcpy(uuid, &lv->lvid, sizeof(lv->lvid));
33886d7f5d3SJohn Marino
33986d7f5d3SJohn Marino return poll_daemon(cmd, lv_full_name, uuid, background, 0,
34086d7f5d3SJohn Marino &_lvconvert_mirror_fns, "Converted");
34186d7f5d3SJohn Marino }
34286d7f5d3SJohn Marino
_insert_lvconvert_layer(struct cmd_context * cmd,struct logical_volume * lv)34386d7f5d3SJohn Marino static int _insert_lvconvert_layer(struct cmd_context *cmd,
34486d7f5d3SJohn Marino struct logical_volume *lv)
34586d7f5d3SJohn Marino {
34686d7f5d3SJohn Marino char *format, *layer_name;
34786d7f5d3SJohn Marino size_t len;
34886d7f5d3SJohn Marino int i;
34986d7f5d3SJohn Marino
35086d7f5d3SJohn Marino /*
35186d7f5d3SJohn Marino * We would like to give the same number for this layer
35286d7f5d3SJohn Marino * and the newly added mimage.
35386d7f5d3SJohn Marino * However, LV name of newly added mimage is determined *after*
35486d7f5d3SJohn Marino * the LV name of this layer is determined.
35586d7f5d3SJohn Marino *
35686d7f5d3SJohn Marino * So, use generate_lv_name() to generate mimage name first
35786d7f5d3SJohn Marino * and take the number from it.
35886d7f5d3SJohn Marino */
35986d7f5d3SJohn Marino
36086d7f5d3SJohn Marino len = strlen(lv->name) + 32;
36186d7f5d3SJohn Marino if (!(format = alloca(len)) ||
36286d7f5d3SJohn Marino !(layer_name = alloca(len)) ||
36386d7f5d3SJohn Marino dm_snprintf(format, len, "%s_mimage_%%d", lv->name) < 0) {
36486d7f5d3SJohn Marino log_error("lvconvert: layer name allocation failed.");
36586d7f5d3SJohn Marino return 0;
36686d7f5d3SJohn Marino }
36786d7f5d3SJohn Marino
36886d7f5d3SJohn Marino if (!generate_lv_name(lv->vg, format, layer_name, len) ||
36986d7f5d3SJohn Marino sscanf(layer_name, format, &i) != 1) {
37086d7f5d3SJohn Marino log_error("lvconvert: layer name generation failed.");
37186d7f5d3SJohn Marino return 0;
37286d7f5d3SJohn Marino }
37386d7f5d3SJohn Marino
37486d7f5d3SJohn Marino if (dm_snprintf(layer_name, len, MIRROR_SYNC_LAYER "_%d", i) < 0) {
37586d7f5d3SJohn Marino log_error("layer name allocation failed.");
37686d7f5d3SJohn Marino return 0;
37786d7f5d3SJohn Marino }
37886d7f5d3SJohn Marino
37986d7f5d3SJohn Marino if (!insert_layer_for_lv(cmd, lv, 0, layer_name)) {
38086d7f5d3SJohn Marino log_error("Failed to insert resync layer");
38186d7f5d3SJohn Marino return 0;
38286d7f5d3SJohn Marino }
38386d7f5d3SJohn Marino
38486d7f5d3SJohn Marino return 1;
38586d7f5d3SJohn Marino }
38686d7f5d3SJohn Marino
_area_missing(struct lv_segment * lvseg,int s)38786d7f5d3SJohn Marino static int _area_missing(struct lv_segment *lvseg, int s)
38886d7f5d3SJohn Marino {
38986d7f5d3SJohn Marino if (seg_type(lvseg, s) == AREA_LV) {
39086d7f5d3SJohn Marino if (seg_lv(lvseg, s)->status & PARTIAL_LV)
39186d7f5d3SJohn Marino return 1;
39286d7f5d3SJohn Marino } else if ((seg_type(lvseg, s) == AREA_PV) &&
39386d7f5d3SJohn Marino (seg_pv(lvseg, s)->status & MISSING_PV))
39486d7f5d3SJohn Marino return 1;
39586d7f5d3SJohn Marino
39686d7f5d3SJohn Marino return 0;
39786d7f5d3SJohn Marino }
39886d7f5d3SJohn Marino
39986d7f5d3SJohn Marino /* FIXME we want to handle mirror stacks here... */
_failed_mirrors_count(struct logical_volume * lv)40086d7f5d3SJohn Marino static int _failed_mirrors_count(struct logical_volume *lv)
40186d7f5d3SJohn Marino {
40286d7f5d3SJohn Marino struct lv_segment *lvseg;
40386d7f5d3SJohn Marino int ret = 0;
40486d7f5d3SJohn Marino int s;
40586d7f5d3SJohn Marino
40686d7f5d3SJohn Marino dm_list_iterate_items(lvseg, &lv->segments) {
40786d7f5d3SJohn Marino if (!seg_is_mirrored(lvseg))
40886d7f5d3SJohn Marino return -1;
40986d7f5d3SJohn Marino for (s = 0; s < lvseg->area_count; s++)
41086d7f5d3SJohn Marino if (_area_missing(lvseg, s))
41186d7f5d3SJohn Marino ret++;
41286d7f5d3SJohn Marino }
41386d7f5d3SJohn Marino
41486d7f5d3SJohn Marino return ret;
41586d7f5d3SJohn Marino }
41686d7f5d3SJohn Marino
_failed_pv_list(struct volume_group * vg)41786d7f5d3SJohn Marino static struct dm_list *_failed_pv_list(struct volume_group *vg)
41886d7f5d3SJohn Marino {
41986d7f5d3SJohn Marino struct dm_list *failed_pvs;
42086d7f5d3SJohn Marino struct pv_list *pvl, *new_pvl;
42186d7f5d3SJohn Marino
42286d7f5d3SJohn Marino if (!(failed_pvs = dm_pool_alloc(vg->vgmem, sizeof(*failed_pvs)))) {
42386d7f5d3SJohn Marino log_error("Allocation of list of failed_pvs failed.");
42486d7f5d3SJohn Marino return_NULL;
42586d7f5d3SJohn Marino }
42686d7f5d3SJohn Marino
42786d7f5d3SJohn Marino dm_list_init(failed_pvs);
42886d7f5d3SJohn Marino
42986d7f5d3SJohn Marino dm_list_iterate_items(pvl, &vg->pvs) {
43086d7f5d3SJohn Marino if (!(pvl->pv->status & MISSING_PV))
43186d7f5d3SJohn Marino continue;
43286d7f5d3SJohn Marino
43386d7f5d3SJohn Marino if (!(new_pvl = dm_pool_alloc(vg->vgmem, sizeof(*new_pvl)))) {
43486d7f5d3SJohn Marino log_error("Allocation of failed_pvs list entry failed.");
43586d7f5d3SJohn Marino return_NULL;
43686d7f5d3SJohn Marino }
43786d7f5d3SJohn Marino new_pvl->pv = pvl->pv;
43886d7f5d3SJohn Marino dm_list_add(failed_pvs, &new_pvl->list);
43986d7f5d3SJohn Marino }
44086d7f5d3SJohn Marino
44186d7f5d3SJohn Marino return failed_pvs;
44286d7f5d3SJohn Marino }
44386d7f5d3SJohn Marino
44486d7f5d3SJohn Marino /*
44586d7f5d3SJohn Marino * Walk down the stacked mirror LV to the original mirror LV.
44686d7f5d3SJohn Marino */
_original_lv(struct logical_volume * lv)44786d7f5d3SJohn Marino static struct logical_volume *_original_lv(struct logical_volume *lv)
44886d7f5d3SJohn Marino {
44986d7f5d3SJohn Marino struct logical_volume *next_lv = lv, *tmp_lv;
45086d7f5d3SJohn Marino
45186d7f5d3SJohn Marino while ((tmp_lv = find_temporary_mirror(next_lv)))
45286d7f5d3SJohn Marino next_lv = tmp_lv;
45386d7f5d3SJohn Marino
45486d7f5d3SJohn Marino return next_lv;
45586d7f5d3SJohn Marino }
45686d7f5d3SJohn Marino
_lvconvert_mirrors_repair_ask(struct cmd_context * cmd,int failed_log,int failed_mirrors,int * replace_log,int * replace_mirrors)45786d7f5d3SJohn Marino static void _lvconvert_mirrors_repair_ask(struct cmd_context *cmd,
45886d7f5d3SJohn Marino int failed_log, int failed_mirrors,
45986d7f5d3SJohn Marino int *replace_log, int *replace_mirrors)
46086d7f5d3SJohn Marino {
46186d7f5d3SJohn Marino const char *leg_policy = NULL, *log_policy = NULL;
46286d7f5d3SJohn Marino
46386d7f5d3SJohn Marino int force = arg_count(cmd, force_ARG);
46486d7f5d3SJohn Marino int yes = arg_count(cmd, yes_ARG);
46586d7f5d3SJohn Marino
46686d7f5d3SJohn Marino *replace_log = *replace_mirrors = 1;
46786d7f5d3SJohn Marino
46886d7f5d3SJohn Marino if (arg_count(cmd, use_policies_ARG)) {
46986d7f5d3SJohn Marino leg_policy = find_config_tree_str(cmd,
47086d7f5d3SJohn Marino "activation/mirror_device_fault_policy",
47186d7f5d3SJohn Marino DEFAULT_MIRROR_DEVICE_FAULT_POLICY);
47286d7f5d3SJohn Marino log_policy = find_config_tree_str(cmd,
47386d7f5d3SJohn Marino "activation/mirror_log_fault_policy",
47486d7f5d3SJohn Marino DEFAULT_MIRROR_LOG_FAULT_POLICY);
47586d7f5d3SJohn Marino *replace_mirrors = strcmp(leg_policy, "remove");
47686d7f5d3SJohn Marino *replace_log = strcmp(log_policy, "remove");
47786d7f5d3SJohn Marino return;
47886d7f5d3SJohn Marino }
47986d7f5d3SJohn Marino
48086d7f5d3SJohn Marino if (yes)
48186d7f5d3SJohn Marino return;
48286d7f5d3SJohn Marino
48386d7f5d3SJohn Marino if (force != PROMPT) {
48486d7f5d3SJohn Marino *replace_log = *replace_mirrors = 0;
48586d7f5d3SJohn Marino return;
48686d7f5d3SJohn Marino }
48786d7f5d3SJohn Marino
48886d7f5d3SJohn Marino if (failed_log &&
48986d7f5d3SJohn Marino yes_no_prompt("Attempt to replace failed mirror log? [y/n]: ") == 'n') {
49086d7f5d3SJohn Marino *replace_log = 0;
49186d7f5d3SJohn Marino }
49286d7f5d3SJohn Marino
49386d7f5d3SJohn Marino if (failed_mirrors &&
49486d7f5d3SJohn Marino yes_no_prompt("Attempt to replace failed mirror images "
49586d7f5d3SJohn Marino "(requires full device resync)? [y/n]: ") == 'n') {
49686d7f5d3SJohn Marino *replace_mirrors = 0;
49786d7f5d3SJohn Marino }
49886d7f5d3SJohn Marino }
49986d7f5d3SJohn Marino
_using_corelog(struct logical_volume * lv)50086d7f5d3SJohn Marino static int _using_corelog(struct logical_volume *lv)
50186d7f5d3SJohn Marino {
50286d7f5d3SJohn Marino return !first_seg(_original_lv(lv))->log_lv;
50386d7f5d3SJohn Marino }
50486d7f5d3SJohn Marino
_lv_update_log_type(struct cmd_context * cmd,struct lvconvert_params * lp,struct logical_volume * lv,int corelog)50586d7f5d3SJohn Marino static int _lv_update_log_type(struct cmd_context *cmd,
50686d7f5d3SJohn Marino struct lvconvert_params *lp,
50786d7f5d3SJohn Marino struct logical_volume *lv,
50886d7f5d3SJohn Marino int corelog)
50986d7f5d3SJohn Marino {
51086d7f5d3SJohn Marino struct logical_volume *original_lv = _original_lv(lv);
51186d7f5d3SJohn Marino if (_using_corelog(lv) && !corelog) {
51286d7f5d3SJohn Marino if (!add_mirror_log(cmd, original_lv, 1,
51386d7f5d3SJohn Marino adjusted_mirror_region_size(
51486d7f5d3SJohn Marino lv->vg->extent_size,
51586d7f5d3SJohn Marino lv->le_count,
51686d7f5d3SJohn Marino lp->region_size),
51786d7f5d3SJohn Marino lp->pvh, lp->alloc))
51886d7f5d3SJohn Marino return_0;
51986d7f5d3SJohn Marino } else if (!_using_corelog(lv) && corelog) {
52086d7f5d3SJohn Marino if (!remove_mirror_log(cmd, original_lv,
52186d7f5d3SJohn Marino lp->pv_count ? lp->pvh : NULL))
52286d7f5d3SJohn Marino return_0;
52386d7f5d3SJohn Marino }
52486d7f5d3SJohn Marino return 1;
52586d7f5d3SJohn Marino }
52686d7f5d3SJohn Marino
_lvconvert_mirrors(struct cmd_context * cmd,struct logical_volume * lv,struct lvconvert_params * lp)52786d7f5d3SJohn Marino static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
52886d7f5d3SJohn Marino struct lvconvert_params *lp)
52986d7f5d3SJohn Marino {
53086d7f5d3SJohn Marino struct lv_segment *seg;
53186d7f5d3SJohn Marino uint32_t existing_mirrors;
53286d7f5d3SJohn Marino const char *mirrorlog;
53386d7f5d3SJohn Marino unsigned corelog = 0;
53486d7f5d3SJohn Marino int r = 0;
53586d7f5d3SJohn Marino struct logical_volume *log_lv, *layer_lv;
53686d7f5d3SJohn Marino int failed_mirrors = 0, failed_log = 0;
53786d7f5d3SJohn Marino struct dm_list *old_pvh = NULL, *remove_pvs = NULL;
53886d7f5d3SJohn Marino
53986d7f5d3SJohn Marino int repair = arg_count(cmd, repair_ARG);
54086d7f5d3SJohn Marino int replace_log = 1, replace_mirrors = 1;
54186d7f5d3SJohn Marino
54286d7f5d3SJohn Marino seg = first_seg(lv);
54386d7f5d3SJohn Marino existing_mirrors = lv_mirror_count(lv);
54486d7f5d3SJohn Marino
54586d7f5d3SJohn Marino /* If called with no argument, try collapsing the resync layers */
54686d7f5d3SJohn Marino if (!arg_count(cmd, mirrors_ARG) && !arg_count(cmd, mirrorlog_ARG) &&
54786d7f5d3SJohn Marino !arg_count(cmd, corelog_ARG) && !arg_count(cmd, regionsize_ARG) &&
54886d7f5d3SJohn Marino !repair) {
54986d7f5d3SJohn Marino if (find_temporary_mirror(lv) || (lv->status & CONVERTING))
55086d7f5d3SJohn Marino lp->need_polling = 1;
55186d7f5d3SJohn Marino return 1;
55286d7f5d3SJohn Marino }
55386d7f5d3SJohn Marino
55486d7f5d3SJohn Marino if (arg_count(cmd, mirrors_ARG) && repair) {
55586d7f5d3SJohn Marino log_error("You may only use one of --mirrors and --repair.");
55686d7f5d3SJohn Marino return 0;
55786d7f5d3SJohn Marino }
55886d7f5d3SJohn Marino
55986d7f5d3SJohn Marino /*
56086d7f5d3SJohn Marino * Adjust required number of mirrors
56186d7f5d3SJohn Marino *
56286d7f5d3SJohn Marino * We check mirrors_ARG again to see if it
56386d7f5d3SJohn Marino * was supplied. If not, they want the mirror
56486d7f5d3SJohn Marino * count to remain the same. They may be changing
56586d7f5d3SJohn Marino * the logging type.
56686d7f5d3SJohn Marino */
56786d7f5d3SJohn Marino if (!arg_count(cmd, mirrors_ARG))
56886d7f5d3SJohn Marino lp->mirrors = existing_mirrors;
56986d7f5d3SJohn Marino else if (lp->mirrors_sign == SIGN_PLUS)
57086d7f5d3SJohn Marino lp->mirrors = existing_mirrors + lp->mirrors;
57186d7f5d3SJohn Marino else if (lp->mirrors_sign == SIGN_MINUS)
57286d7f5d3SJohn Marino lp->mirrors = existing_mirrors - lp->mirrors;
57386d7f5d3SJohn Marino else
57486d7f5d3SJohn Marino lp->mirrors += 1;
57586d7f5d3SJohn Marino
57686d7f5d3SJohn Marino if (repair) {
57786d7f5d3SJohn Marino cmd->handles_missing_pvs = 1;
57886d7f5d3SJohn Marino cmd->partial_activation = 1;
57986d7f5d3SJohn Marino lp->need_polling = 0;
58086d7f5d3SJohn Marino if (!(lv->status & PARTIAL_LV)) {
58186d7f5d3SJohn Marino log_error("The mirror is consistent, nothing to repair.");
58286d7f5d3SJohn Marino return 0;
58386d7f5d3SJohn Marino }
58486d7f5d3SJohn Marino if ((failed_mirrors = _failed_mirrors_count(lv)) < 0)
58586d7f5d3SJohn Marino return_0;
58686d7f5d3SJohn Marino lp->mirrors -= failed_mirrors;
58786d7f5d3SJohn Marino log_error("Mirror status: %d of %d images failed.",
58886d7f5d3SJohn Marino failed_mirrors, existing_mirrors);
58986d7f5d3SJohn Marino old_pvh = lp->pvh;
59086d7f5d3SJohn Marino if (!(lp->pvh = _failed_pv_list(lv->vg)))
59186d7f5d3SJohn Marino return_0;
59286d7f5d3SJohn Marino log_lv=first_seg(lv)->log_lv;
59386d7f5d3SJohn Marino if (!log_lv || log_lv->status & PARTIAL_LV)
59486d7f5d3SJohn Marino failed_log = corelog = 1;
59586d7f5d3SJohn Marino } else {
59686d7f5d3SJohn Marino /*
59786d7f5d3SJohn Marino * Did the user try to subtract more legs than available?
59886d7f5d3SJohn Marino */
59986d7f5d3SJohn Marino if (lp->mirrors < 1) {
60086d7f5d3SJohn Marino log_error("Logical volume %s only has %" PRIu32 " mirrors.",
60186d7f5d3SJohn Marino lv->name, existing_mirrors);
60286d7f5d3SJohn Marino return 0;
60386d7f5d3SJohn Marino }
60486d7f5d3SJohn Marino
60586d7f5d3SJohn Marino /*
60686d7f5d3SJohn Marino * Adjust log type
60786d7f5d3SJohn Marino */
60886d7f5d3SJohn Marino if (arg_count(cmd, corelog_ARG))
60986d7f5d3SJohn Marino corelog = 1;
61086d7f5d3SJohn Marino
61186d7f5d3SJohn Marino mirrorlog = arg_str_value(cmd, mirrorlog_ARG,
61286d7f5d3SJohn Marino corelog ? "core" : DEFAULT_MIRRORLOG);
61386d7f5d3SJohn Marino if (!strcmp("disk", mirrorlog)) {
61486d7f5d3SJohn Marino if (corelog) {
61586d7f5d3SJohn Marino log_error("--mirrorlog disk and --corelog "
61686d7f5d3SJohn Marino "are incompatible");
61786d7f5d3SJohn Marino return 0;
61886d7f5d3SJohn Marino }
61986d7f5d3SJohn Marino corelog = 0;
62086d7f5d3SJohn Marino } else if (!strcmp("core", mirrorlog))
62186d7f5d3SJohn Marino corelog = 1;
62286d7f5d3SJohn Marino else {
62386d7f5d3SJohn Marino log_error("Unknown mirrorlog type: %s", mirrorlog);
62486d7f5d3SJohn Marino return 0;
62586d7f5d3SJohn Marino }
62686d7f5d3SJohn Marino
62786d7f5d3SJohn Marino log_verbose("Setting logging type to %s", mirrorlog);
62886d7f5d3SJohn Marino }
62986d7f5d3SJohn Marino
63086d7f5d3SJohn Marino /*
63186d7f5d3SJohn Marino * Region size must not change on existing mirrors
63286d7f5d3SJohn Marino */
63386d7f5d3SJohn Marino if (arg_count(cmd, regionsize_ARG) && (lv->status & MIRRORED) &&
63486d7f5d3SJohn Marino (lp->region_size != seg->region_size)) {
63586d7f5d3SJohn Marino log_error("Mirror log region size cannot be changed on "
63686d7f5d3SJohn Marino "an existing mirror.");
63786d7f5d3SJohn Marino return 0;
63886d7f5d3SJohn Marino }
63986d7f5d3SJohn Marino
64086d7f5d3SJohn Marino /*
64186d7f5d3SJohn Marino * For the most part, we cannot handle multi-segment mirrors. Bail out
64286d7f5d3SJohn Marino * early if we have encountered one.
64386d7f5d3SJohn Marino */
64486d7f5d3SJohn Marino if ((lv->status & MIRRORED) && dm_list_size(&lv->segments) != 1) {
64586d7f5d3SJohn Marino log_error("Logical volume %s has multiple "
64686d7f5d3SJohn Marino "mirror segments.", lv->name);
64786d7f5d3SJohn Marino return 0;
64886d7f5d3SJohn Marino }
64986d7f5d3SJohn Marino
65086d7f5d3SJohn Marino if (repair)
65186d7f5d3SJohn Marino _lvconvert_mirrors_repair_ask(cmd, failed_log, failed_mirrors,
65286d7f5d3SJohn Marino &replace_log, &replace_mirrors);
65386d7f5d3SJohn Marino
65486d7f5d3SJohn Marino restart:
65586d7f5d3SJohn Marino /*
65686d7f5d3SJohn Marino * Converting from mirror to linear
65786d7f5d3SJohn Marino */
65886d7f5d3SJohn Marino if ((lp->mirrors == 1)) {
65986d7f5d3SJohn Marino if (!(lv->status & MIRRORED)) {
66086d7f5d3SJohn Marino log_error("Logical volume %s is already not mirrored.",
66186d7f5d3SJohn Marino lv->name);
66286d7f5d3SJohn Marino return 1;
66386d7f5d3SJohn Marino }
66486d7f5d3SJohn Marino }
66586d7f5d3SJohn Marino
66686d7f5d3SJohn Marino /*
66786d7f5d3SJohn Marino * Downconversion.
66886d7f5d3SJohn Marino */
66986d7f5d3SJohn Marino if (lp->mirrors < existing_mirrors) {
67086d7f5d3SJohn Marino /* Reduce number of mirrors */
67186d7f5d3SJohn Marino if (repair || lp->pv_count)
67286d7f5d3SJohn Marino remove_pvs = lp->pvh;
67386d7f5d3SJohn Marino if (!lv_remove_mirrors(cmd, lv, existing_mirrors - lp->mirrors,
67486d7f5d3SJohn Marino (corelog || lp->mirrors == 1) ? 1U : 0U,
67586d7f5d3SJohn Marino remove_pvs, 0))
67686d7f5d3SJohn Marino return_0;
67786d7f5d3SJohn Marino if (lp->mirrors > 1 &&
67886d7f5d3SJohn Marino !_lv_update_log_type(cmd, lp, lv, corelog))
67986d7f5d3SJohn Marino return_0;
68086d7f5d3SJohn Marino } else if (!(lv->status & MIRRORED)) {
68186d7f5d3SJohn Marino /*
68286d7f5d3SJohn Marino * Converting from linear to mirror
68386d7f5d3SJohn Marino */
68486d7f5d3SJohn Marino
68586d7f5d3SJohn Marino /* FIXME Share code with lvcreate */
68686d7f5d3SJohn Marino
68786d7f5d3SJohn Marino /* FIXME Why is this restriction here? Fix it! */
68886d7f5d3SJohn Marino dm_list_iterate_items(seg, &lv->segments) {
68986d7f5d3SJohn Marino if (seg_is_striped(seg) && seg->area_count > 1) {
69086d7f5d3SJohn Marino log_error("Mirrors of striped volumes are not yet supported.");
69186d7f5d3SJohn Marino return 0;
69286d7f5d3SJohn Marino }
69386d7f5d3SJohn Marino }
69486d7f5d3SJohn Marino
69586d7f5d3SJohn Marino /*
69686d7f5d3SJohn Marino * FIXME should we give not only lp->pvh, but also all PVs
69786d7f5d3SJohn Marino * currently taken by the mirror? Would make more sense from
69886d7f5d3SJohn Marino * user perspective.
69986d7f5d3SJohn Marino */
70086d7f5d3SJohn Marino if (!lv_add_mirrors(cmd, lv, lp->mirrors - 1, 1,
70186d7f5d3SJohn Marino adjusted_mirror_region_size(
70286d7f5d3SJohn Marino lv->vg->extent_size,
70386d7f5d3SJohn Marino lv->le_count,
70486d7f5d3SJohn Marino lp->region_size),
70586d7f5d3SJohn Marino corelog ? 0U : 1U, lp->pvh, lp->alloc,
70686d7f5d3SJohn Marino MIRROR_BY_LV))
70786d7f5d3SJohn Marino return_0;
70886d7f5d3SJohn Marino if (lp->wait_completion)
70986d7f5d3SJohn Marino lp->need_polling = 1;
71086d7f5d3SJohn Marino } else if (lp->mirrors > existing_mirrors || failed_mirrors) {
71186d7f5d3SJohn Marino if (lv->status & MIRROR_NOTSYNCED) {
71286d7f5d3SJohn Marino log_error("Can't add mirror to out-of-sync mirrored "
71386d7f5d3SJohn Marino "LV: use lvchange --resync first.");
71486d7f5d3SJohn Marino return 0;
71586d7f5d3SJohn Marino }
71686d7f5d3SJohn Marino
71786d7f5d3SJohn Marino /*
71886d7f5d3SJohn Marino * We allow snapshots of mirrors, but for now, we
71986d7f5d3SJohn Marino * do not allow up converting mirrors that are under
72086d7f5d3SJohn Marino * snapshots. The layering logic is somewhat complex,
72186d7f5d3SJohn Marino * and preliminary test show that the conversion can't
72286d7f5d3SJohn Marino * seem to get the correct %'age of completion.
72386d7f5d3SJohn Marino */
72486d7f5d3SJohn Marino if (lv_is_origin(lv)) {
72586d7f5d3SJohn Marino log_error("Can't add additional mirror images to "
72686d7f5d3SJohn Marino "mirrors that are under snapshots");
72786d7f5d3SJohn Marino return 0;
72886d7f5d3SJohn Marino }
72986d7f5d3SJohn Marino
73086d7f5d3SJohn Marino /*
73186d7f5d3SJohn Marino * Log addition/removal should be done before the layer
73286d7f5d3SJohn Marino * insertion to make the end result consistent with
73386d7f5d3SJohn Marino * linear-to-mirror conversion.
73486d7f5d3SJohn Marino */
73586d7f5d3SJohn Marino if (!_lv_update_log_type(cmd, lp, lv, corelog))
73686d7f5d3SJohn Marino return_0;
73786d7f5d3SJohn Marino /* Insert a temporary layer for syncing,
73886d7f5d3SJohn Marino * only if the original lv is using disk log. */
73986d7f5d3SJohn Marino if (seg->log_lv && !_insert_lvconvert_layer(cmd, lv)) {
74086d7f5d3SJohn Marino log_error("Failed to insert resync layer");
74186d7f5d3SJohn Marino return 0;
74286d7f5d3SJohn Marino }
74386d7f5d3SJohn Marino /* FIXME: can't have multiple mlogs. force corelog. */
74486d7f5d3SJohn Marino if (!lv_add_mirrors(cmd, lv, lp->mirrors - existing_mirrors, 1,
74586d7f5d3SJohn Marino adjusted_mirror_region_size(
74686d7f5d3SJohn Marino lv->vg->extent_size,
74786d7f5d3SJohn Marino lv->le_count,
74886d7f5d3SJohn Marino lp->region_size),
74986d7f5d3SJohn Marino 0U, lp->pvh, lp->alloc,
75086d7f5d3SJohn Marino MIRROR_BY_LV)) {
75186d7f5d3SJohn Marino layer_lv = seg_lv(first_seg(lv), 0);
75286d7f5d3SJohn Marino if (!remove_layer_from_lv(lv, layer_lv) ||
75386d7f5d3SJohn Marino !deactivate_lv(cmd, layer_lv) ||
75486d7f5d3SJohn Marino !lv_remove(layer_lv) || !vg_write(lv->vg) ||
75586d7f5d3SJohn Marino !vg_commit(lv->vg)) {
75686d7f5d3SJohn Marino log_error("ABORTING: Failed to remove "
75786d7f5d3SJohn Marino "temporary mirror layer %s.",
75886d7f5d3SJohn Marino layer_lv->name);
75986d7f5d3SJohn Marino log_error("Manual cleanup with vgcfgrestore "
76086d7f5d3SJohn Marino "and dmsetup may be required.");
76186d7f5d3SJohn Marino return 0;
76286d7f5d3SJohn Marino }
76386d7f5d3SJohn Marino return_0;
76486d7f5d3SJohn Marino }
76586d7f5d3SJohn Marino lv->status |= CONVERTING;
76686d7f5d3SJohn Marino lp->need_polling = 1;
76786d7f5d3SJohn Marino }
76886d7f5d3SJohn Marino
76986d7f5d3SJohn Marino if (lp->mirrors == existing_mirrors) {
77086d7f5d3SJohn Marino if (_using_corelog(lv) != corelog) {
77186d7f5d3SJohn Marino if (!_lv_update_log_type(cmd, lp, lv, corelog))
77286d7f5d3SJohn Marino return_0;
77386d7f5d3SJohn Marino } else {
77486d7f5d3SJohn Marino log_error("Logical volume %s already has %"
77586d7f5d3SJohn Marino PRIu32 " mirror(s).", lv->name,
77686d7f5d3SJohn Marino lp->mirrors - 1);
77786d7f5d3SJohn Marino if (lv->status & CONVERTING)
77886d7f5d3SJohn Marino lp->need_polling = 1;
77986d7f5d3SJohn Marino return 1;
78086d7f5d3SJohn Marino }
78186d7f5d3SJohn Marino }
78286d7f5d3SJohn Marino
78386d7f5d3SJohn Marino log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
78486d7f5d3SJohn Marino
78586d7f5d3SJohn Marino if (!vg_write(lv->vg))
78686d7f5d3SJohn Marino return_0;
78786d7f5d3SJohn Marino
78886d7f5d3SJohn Marino if (!suspend_lv(cmd, lv)) {
78986d7f5d3SJohn Marino log_error("Failed to lock %s", lv->name);
79086d7f5d3SJohn Marino vg_revert(lv->vg);
79186d7f5d3SJohn Marino goto out;
79286d7f5d3SJohn Marino }
79386d7f5d3SJohn Marino
79486d7f5d3SJohn Marino if (!vg_commit(lv->vg)) {
79586d7f5d3SJohn Marino resume_lv(cmd, lv);
79686d7f5d3SJohn Marino goto_out;
79786d7f5d3SJohn Marino }
79886d7f5d3SJohn Marino
79986d7f5d3SJohn Marino log_very_verbose("Updating \"%s\" in kernel", lv->name);
80086d7f5d3SJohn Marino
80186d7f5d3SJohn Marino if (!resume_lv(cmd, lv)) {
80286d7f5d3SJohn Marino log_error("Problem reactivating %s", lv->name);
80386d7f5d3SJohn Marino goto out;
80486d7f5d3SJohn Marino }
80586d7f5d3SJohn Marino
80686d7f5d3SJohn Marino if (failed_log || failed_mirrors) {
80786d7f5d3SJohn Marino lp->pvh = old_pvh;
80886d7f5d3SJohn Marino if (failed_log && replace_log)
80986d7f5d3SJohn Marino failed_log = corelog = 0;
81086d7f5d3SJohn Marino if (replace_mirrors)
81186d7f5d3SJohn Marino lp->mirrors += failed_mirrors;
81286d7f5d3SJohn Marino failed_mirrors = 0;
81386d7f5d3SJohn Marino existing_mirrors = lv_mirror_count(lv);
81486d7f5d3SJohn Marino /* Now replace missing devices. */
81586d7f5d3SJohn Marino if (replace_log || replace_mirrors)
81686d7f5d3SJohn Marino goto restart;
81786d7f5d3SJohn Marino }
81886d7f5d3SJohn Marino
81986d7f5d3SJohn Marino if (!lp->need_polling)
82086d7f5d3SJohn Marino log_print("Logical volume %s converted.", lv->name);
82186d7f5d3SJohn Marino
82286d7f5d3SJohn Marino r = 1;
82386d7f5d3SJohn Marino out:
82486d7f5d3SJohn Marino backup(lv->vg);
82586d7f5d3SJohn Marino return r;
82686d7f5d3SJohn Marino }
82786d7f5d3SJohn Marino
lvconvert_snapshot(struct cmd_context * cmd,struct logical_volume * lv,struct lvconvert_params * lp)82886d7f5d3SJohn Marino static int lvconvert_snapshot(struct cmd_context *cmd,
82986d7f5d3SJohn Marino struct logical_volume *lv,
83086d7f5d3SJohn Marino struct lvconvert_params *lp)
83186d7f5d3SJohn Marino {
83286d7f5d3SJohn Marino struct logical_volume *org;
83386d7f5d3SJohn Marino int r = 0;
83486d7f5d3SJohn Marino
83586d7f5d3SJohn Marino if (!(org = find_lv(lv->vg, lp->origin))) {
83686d7f5d3SJohn Marino log_error("Couldn't find origin volume '%s'.", lp->origin);
83786d7f5d3SJohn Marino return 0;
83886d7f5d3SJohn Marino }
83986d7f5d3SJohn Marino
84086d7f5d3SJohn Marino if (org == lv) {
84186d7f5d3SJohn Marino log_error("Unable to use \"%s\" as both snapshot and origin.",
84286d7f5d3SJohn Marino lv->name);
84386d7f5d3SJohn Marino return 0;
84486d7f5d3SJohn Marino }
84586d7f5d3SJohn Marino
84686d7f5d3SJohn Marino if (org->status & (LOCKED|PVMOVE|MIRRORED) || lv_is_cow(org)) {
84786d7f5d3SJohn Marino log_error("Unable to create a snapshot of a %s LV.",
84886d7f5d3SJohn Marino org->status & LOCKED ? "locked" :
84986d7f5d3SJohn Marino org->status & PVMOVE ? "pvmove" :
85086d7f5d3SJohn Marino org->status & MIRRORED ? "mirrored" :
85186d7f5d3SJohn Marino "snapshot");
85286d7f5d3SJohn Marino return 0;
85386d7f5d3SJohn Marino }
85486d7f5d3SJohn Marino
85586d7f5d3SJohn Marino if (!lp->zero || !(lv->status & LVM_WRITE))
85686d7f5d3SJohn Marino log_warn("WARNING: \"%s\" not zeroed", lv->name);
85786d7f5d3SJohn Marino else if (!set_lv(cmd, lv, UINT64_C(0), 0)) {
85886d7f5d3SJohn Marino log_error("Aborting. Failed to wipe snapshot "
85986d7f5d3SJohn Marino "exception store.");
86086d7f5d3SJohn Marino return 0;
86186d7f5d3SJohn Marino }
86286d7f5d3SJohn Marino
86386d7f5d3SJohn Marino if (!deactivate_lv(cmd, lv)) {
86486d7f5d3SJohn Marino log_error("Couldn't deactivate LV %s.", lv->name);
86586d7f5d3SJohn Marino return 0;
86686d7f5d3SJohn Marino }
86786d7f5d3SJohn Marino
86886d7f5d3SJohn Marino if (!vg_add_snapshot(org, lv, NULL, org->le_count, lp->chunk_size)) {
86986d7f5d3SJohn Marino log_error("Couldn't create snapshot.");
87086d7f5d3SJohn Marino return 0;
87186d7f5d3SJohn Marino }
87286d7f5d3SJohn Marino
87386d7f5d3SJohn Marino /* store vg on disk(s) */
87486d7f5d3SJohn Marino if (!vg_write(lv->vg))
87586d7f5d3SJohn Marino return_0;
87686d7f5d3SJohn Marino
87786d7f5d3SJohn Marino if (!suspend_lv(cmd, org)) {
87886d7f5d3SJohn Marino log_error("Failed to suspend origin %s", org->name);
87986d7f5d3SJohn Marino vg_revert(lv->vg);
88086d7f5d3SJohn Marino goto out;
88186d7f5d3SJohn Marino }
88286d7f5d3SJohn Marino
88386d7f5d3SJohn Marino if (!vg_commit(lv->vg))
88486d7f5d3SJohn Marino goto_out;
88586d7f5d3SJohn Marino
88686d7f5d3SJohn Marino if (!resume_lv(cmd, org)) {
88786d7f5d3SJohn Marino log_error("Problem reactivating origin %s", org->name);
88886d7f5d3SJohn Marino goto out;
88986d7f5d3SJohn Marino }
89086d7f5d3SJohn Marino
89186d7f5d3SJohn Marino log_print("Logical volume %s converted to snapshot.", lv->name);
89286d7f5d3SJohn Marino r = 1;
89386d7f5d3SJohn Marino out:
89486d7f5d3SJohn Marino backup(lv->vg);
89586d7f5d3SJohn Marino return r;
89686d7f5d3SJohn Marino }
89786d7f5d3SJohn Marino
lvconvert_single(struct cmd_context * cmd,struct logical_volume * lv,void * handle)89886d7f5d3SJohn Marino static int lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
89986d7f5d3SJohn Marino void *handle)
90086d7f5d3SJohn Marino {
90186d7f5d3SJohn Marino struct lvconvert_params *lp = handle;
90286d7f5d3SJohn Marino
90386d7f5d3SJohn Marino if (lv->status & LOCKED) {
90486d7f5d3SJohn Marino log_error("Cannot convert locked LV %s", lv->name);
90586d7f5d3SJohn Marino return ECMD_FAILED;
90686d7f5d3SJohn Marino }
90786d7f5d3SJohn Marino
90886d7f5d3SJohn Marino if (lv_is_cow(lv)) {
90986d7f5d3SJohn Marino log_error("Can't convert snapshot logical volume \"%s\"",
91086d7f5d3SJohn Marino lv->name);
91186d7f5d3SJohn Marino return ECMD_FAILED;
91286d7f5d3SJohn Marino }
91386d7f5d3SJohn Marino
91486d7f5d3SJohn Marino if (lv->status & PVMOVE) {
91586d7f5d3SJohn Marino log_error("Unable to convert pvmove LV %s", lv->name);
91686d7f5d3SJohn Marino return ECMD_FAILED;
91786d7f5d3SJohn Marino }
91886d7f5d3SJohn Marino
91986d7f5d3SJohn Marino if (arg_count(cmd, repair_ARG) && !(lv->status & MIRRORED)) {
92086d7f5d3SJohn Marino log_error("Can't repair non-mirrored LV \"%s\".", lv->name);
92186d7f5d3SJohn Marino return ECMD_FAILED;
92286d7f5d3SJohn Marino }
92386d7f5d3SJohn Marino
92486d7f5d3SJohn Marino if (lp->snapshot) {
92586d7f5d3SJohn Marino if (lv->status & MIRRORED) {
92686d7f5d3SJohn Marino log_error("Unable to convert mirrored LV \"%s\" into a snapshot.", lv->name);
92786d7f5d3SJohn Marino return ECMD_FAILED;
92886d7f5d3SJohn Marino }
92986d7f5d3SJohn Marino if (!archive(lv->vg)) {
93086d7f5d3SJohn Marino stack;
93186d7f5d3SJohn Marino return ECMD_FAILED;
93286d7f5d3SJohn Marino }
93386d7f5d3SJohn Marino if (!lvconvert_snapshot(cmd, lv, lp)) {
93486d7f5d3SJohn Marino stack;
93586d7f5d3SJohn Marino return ECMD_FAILED;
93686d7f5d3SJohn Marino }
93786d7f5d3SJohn Marino } else if (arg_count(cmd, mirrors_ARG) || (lv->status & MIRRORED)) {
93886d7f5d3SJohn Marino if (!archive(lv->vg)) {
93986d7f5d3SJohn Marino stack;
94086d7f5d3SJohn Marino return ECMD_FAILED;
94186d7f5d3SJohn Marino }
94286d7f5d3SJohn Marino if (!_lvconvert_mirrors(cmd, lv, lp)) {
94386d7f5d3SJohn Marino stack;
94486d7f5d3SJohn Marino return ECMD_FAILED;
94586d7f5d3SJohn Marino }
94686d7f5d3SJohn Marino }
94786d7f5d3SJohn Marino
94886d7f5d3SJohn Marino return ECMD_PROCESSED;
94986d7f5d3SJohn Marino }
95086d7f5d3SJohn Marino
lvconvert(struct cmd_context * cmd,int argc,char ** argv)95186d7f5d3SJohn Marino int lvconvert(struct cmd_context * cmd, int argc, char **argv)
95286d7f5d3SJohn Marino {
95386d7f5d3SJohn Marino struct volume_group *vg;
95486d7f5d3SJohn Marino struct lv_list *lvl;
95586d7f5d3SJohn Marino struct lvconvert_params lp;
95686d7f5d3SJohn Marino int ret = ECMD_FAILED;
95786d7f5d3SJohn Marino struct lvinfo info;
95886d7f5d3SJohn Marino int saved_ignore_suspended_devices = ignore_suspended_devices();
95986d7f5d3SJohn Marino
96086d7f5d3SJohn Marino if (!_read_params(&lp, cmd, argc, argv)) {
96186d7f5d3SJohn Marino stack;
96286d7f5d3SJohn Marino return EINVALID_CMD_LINE;
96386d7f5d3SJohn Marino }
96486d7f5d3SJohn Marino
96586d7f5d3SJohn Marino if (arg_count(cmd, repair_ARG)) {
96686d7f5d3SJohn Marino init_ignore_suspended_devices(1);
96786d7f5d3SJohn Marino cmd->handles_missing_pvs = 1;
96886d7f5d3SJohn Marino }
96986d7f5d3SJohn Marino
97086d7f5d3SJohn Marino log_verbose("Checking for existing volume group \"%s\"", lp.vg_name);
97186d7f5d3SJohn Marino
97286d7f5d3SJohn Marino vg = vg_read_for_update(cmd, lp.vg_name, NULL, 0);
97386d7f5d3SJohn Marino if (vg_read_error(vg))
97486d7f5d3SJohn Marino goto out;
97586d7f5d3SJohn Marino
97686d7f5d3SJohn Marino if (!(lvl = find_lv_in_vg(vg, lp.lv_name))) {
97786d7f5d3SJohn Marino log_error("Logical volume \"%s\" not found in "
97886d7f5d3SJohn Marino "volume group \"%s\"", lp.lv_name, lp.vg_name);
97986d7f5d3SJohn Marino goto bad;
98086d7f5d3SJohn Marino }
98186d7f5d3SJohn Marino
98286d7f5d3SJohn Marino if (lp.pv_count) {
98386d7f5d3SJohn Marino if (!(lp.pvh = create_pv_list(cmd->mem, vg, lp.pv_count,
98486d7f5d3SJohn Marino lp.pvs, 0)))
98586d7f5d3SJohn Marino goto_bad;
98686d7f5d3SJohn Marino } else
98786d7f5d3SJohn Marino lp.pvh = &vg->pvs;
98886d7f5d3SJohn Marino
98986d7f5d3SJohn Marino ret = lvconvert_single(cmd, lvl->lv, &lp);
99086d7f5d3SJohn Marino
99186d7f5d3SJohn Marino bad:
99286d7f5d3SJohn Marino unlock_vg(cmd, lp.vg_name);
99386d7f5d3SJohn Marino
99486d7f5d3SJohn Marino if (ret == ECMD_PROCESSED && lp.need_polling) {
99586d7f5d3SJohn Marino if (!lv_info(cmd, lvl->lv, &info, 1, 0) || !info.exists) {
99686d7f5d3SJohn Marino log_print("Conversion starts after activation");
99786d7f5d3SJohn Marino goto out;
99886d7f5d3SJohn Marino }
99986d7f5d3SJohn Marino ret = lvconvert_poll(cmd, lvl->lv,
100086d7f5d3SJohn Marino lp.wait_completion ? 0 : 1U);
100186d7f5d3SJohn Marino }
100286d7f5d3SJohn Marino out:
100386d7f5d3SJohn Marino init_ignore_suspended_devices(saved_ignore_suspended_devices);
100486d7f5d3SJohn Marino vg_release(vg);
100586d7f5d3SJohn Marino return ret;
100686d7f5d3SJohn Marino }
1007