xref: /dflybsd-src/contrib/lvm2/dist/tools/pvresize.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /*	$NetBSD: pvresize.c,v 1.1.1.2 2009/12/02 00:25:54 haad Exp $	*/
286d7f5d3SJohn Marino 
386d7f5d3SJohn Marino /*
486d7f5d3SJohn Marino  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
586d7f5d3SJohn Marino  * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
686d7f5d3SJohn Marino  * Copyright (C) 2005 Zak Kipling. All rights reserved.
786d7f5d3SJohn Marino  *
886d7f5d3SJohn Marino  * This file is part of LVM2.
986d7f5d3SJohn Marino  *
1086d7f5d3SJohn Marino  * This copyrighted material is made available to anyone wishing to use,
1186d7f5d3SJohn Marino  * modify, copy, or redistribute it subject to the terms and conditions
1286d7f5d3SJohn Marino  * of the GNU Lesser General Public License v.2.1.
1386d7f5d3SJohn Marino  *
1486d7f5d3SJohn Marino  * You should have received a copy of the GNU Lesser General Public License
1586d7f5d3SJohn Marino  * along with this program; if not, write to the Free Software Foundation,
1686d7f5d3SJohn Marino  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1786d7f5d3SJohn Marino  */
1886d7f5d3SJohn Marino 
1986d7f5d3SJohn Marino #include "tools.h"
2086d7f5d3SJohn Marino 
2186d7f5d3SJohn Marino struct pvresize_params {
2286d7f5d3SJohn Marino 	uint64_t new_size;
2386d7f5d3SJohn Marino 
2486d7f5d3SJohn Marino 	unsigned done;
2586d7f5d3SJohn Marino 	unsigned total;
2686d7f5d3SJohn Marino };
2786d7f5d3SJohn Marino 
_pv_resize_single(struct cmd_context * cmd,struct volume_group * vg,struct physical_volume * pv,const uint64_t new_size)2886d7f5d3SJohn Marino static int _pv_resize_single(struct cmd_context *cmd,
2986d7f5d3SJohn Marino 			     struct volume_group *vg,
3086d7f5d3SJohn Marino 			     struct physical_volume *pv,
3186d7f5d3SJohn Marino 			     const uint64_t new_size)
3286d7f5d3SJohn Marino {
3386d7f5d3SJohn Marino 	struct pv_list *pvl;
3486d7f5d3SJohn Marino 	uint64_t size = 0;
3586d7f5d3SJohn Marino 	uint32_t new_pe_count = 0;
3686d7f5d3SJohn Marino 	int r = 0;
3786d7f5d3SJohn Marino 	struct dm_list mdas;
3886d7f5d3SJohn Marino 	const char *pv_name = pv_dev_name(pv);
3986d7f5d3SJohn Marino 	const char *vg_name;
4086d7f5d3SJohn Marino 	struct lvmcache_info *info;
4186d7f5d3SJohn Marino 	int mda_count = 0;
4286d7f5d3SJohn Marino 	struct volume_group *old_vg = vg;
4386d7f5d3SJohn Marino 
4486d7f5d3SJohn Marino 	dm_list_init(&mdas);
4586d7f5d3SJohn Marino 
4686d7f5d3SJohn Marino 	if (is_orphan_vg(pv_vg_name(pv))) {
4786d7f5d3SJohn Marino 		vg_name = VG_ORPHANS;
4886d7f5d3SJohn Marino 		if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
4986d7f5d3SJohn Marino 			log_error("Can't get lock for orphans");
5086d7f5d3SJohn Marino 			return 0;
5186d7f5d3SJohn Marino 		}
5286d7f5d3SJohn Marino 
5386d7f5d3SJohn Marino 		if (!(pv = pv_read(cmd, pv_name, &mdas, NULL, 1, 0))) {
5486d7f5d3SJohn Marino 			unlock_vg(cmd, vg_name);
5586d7f5d3SJohn Marino 			log_error("Unable to read PV \"%s\"", pv_name);
5686d7f5d3SJohn Marino 			return 0;
5786d7f5d3SJohn Marino 		}
5886d7f5d3SJohn Marino 
5986d7f5d3SJohn Marino 		mda_count = dm_list_size(&mdas);
6086d7f5d3SJohn Marino 	} else {
6186d7f5d3SJohn Marino 		vg_name = pv_vg_name(pv);
6286d7f5d3SJohn Marino 
6386d7f5d3SJohn Marino 		vg = vg_read_for_update(cmd, vg_name, NULL, 0);
6486d7f5d3SJohn Marino 
6586d7f5d3SJohn Marino 		if (vg_read_error(vg))
6686d7f5d3SJohn Marino 			goto bad;
6786d7f5d3SJohn Marino 
6886d7f5d3SJohn Marino 		if (!(pvl = find_pv_in_vg(vg, pv_name))) {
6986d7f5d3SJohn Marino 			log_error("Unable to find \"%s\" in volume group \"%s\"",
7086d7f5d3SJohn Marino 				  pv_name, vg->name);
7186d7f5d3SJohn Marino 			goto bad;
7286d7f5d3SJohn Marino 		}
7386d7f5d3SJohn Marino 
7486d7f5d3SJohn Marino 		pv = pvl->pv;
7586d7f5d3SJohn Marino 
7686d7f5d3SJohn Marino 		if (!(info = info_from_pvid(pv->dev->pvid, 0))) {
7786d7f5d3SJohn Marino 			log_error("Can't get info for PV %s in volume group %s",
7886d7f5d3SJohn Marino 				  pv_name, vg->name);
7986d7f5d3SJohn Marino 			goto bad;
8086d7f5d3SJohn Marino 		}
8186d7f5d3SJohn Marino 
8286d7f5d3SJohn Marino 		mda_count = dm_list_size(&info->mdas);
8386d7f5d3SJohn Marino 
8486d7f5d3SJohn Marino 		if (!archive(vg))
8586d7f5d3SJohn Marino 			goto bad;
8686d7f5d3SJohn Marino 	}
8786d7f5d3SJohn Marino 
8886d7f5d3SJohn Marino 	/* FIXME Create function to test compatibility properly */
8986d7f5d3SJohn Marino 	if (mda_count > 1) {
9086d7f5d3SJohn Marino 		log_error("%s: too many metadata areas for pvresize", pv_name);
9186d7f5d3SJohn Marino 		goto bad;
9286d7f5d3SJohn Marino 	}
9386d7f5d3SJohn Marino 
9486d7f5d3SJohn Marino 	if (!(pv->fmt->features & FMT_RESIZE_PV)) {
9586d7f5d3SJohn Marino 		log_error("Physical volume %s format does not support resizing.",
9686d7f5d3SJohn Marino 			  pv_name);
9786d7f5d3SJohn Marino 		goto bad;
9886d7f5d3SJohn Marino 	}
9986d7f5d3SJohn Marino 
10086d7f5d3SJohn Marino 	/* Get new size */
10186d7f5d3SJohn Marino 	if (!dev_get_size(pv_dev(pv), &size)) {
10286d7f5d3SJohn Marino 		log_error("%s: Couldn't get size.", pv_name);
10386d7f5d3SJohn Marino 		goto bad;
10486d7f5d3SJohn Marino 	}
10586d7f5d3SJohn Marino 
10686d7f5d3SJohn Marino 	if (new_size) {
10786d7f5d3SJohn Marino 		if (new_size > size)
10886d7f5d3SJohn Marino 			log_warn("WARNING: %s: Overriding real size. "
10986d7f5d3SJohn Marino 				  "You could lose data.", pv_name);
11086d7f5d3SJohn Marino 		log_verbose("%s: Pretending size is %" PRIu64 " not %" PRIu64
11186d7f5d3SJohn Marino 			    " sectors.", pv_name, new_size, pv_size(pv));
11286d7f5d3SJohn Marino 		size = new_size;
11386d7f5d3SJohn Marino 	}
11486d7f5d3SJohn Marino 
11586d7f5d3SJohn Marino 	if (size < PV_MIN_SIZE) {
11686d7f5d3SJohn Marino 		log_error("%s: Size must exceed minimum of %ld sectors.",
11786d7f5d3SJohn Marino 			  pv_name, PV_MIN_SIZE);
11886d7f5d3SJohn Marino 		goto bad;
11986d7f5d3SJohn Marino 	}
12086d7f5d3SJohn Marino 
12186d7f5d3SJohn Marino 	if (size < pv_pe_start(pv)) {
12286d7f5d3SJohn Marino 		log_error("%s: Size must exceed physical extent start of "
12386d7f5d3SJohn Marino 			  "%" PRIu64 " sectors.", pv_name, pv_pe_start(pv));
12486d7f5d3SJohn Marino 		goto bad;
12586d7f5d3SJohn Marino 	}
12686d7f5d3SJohn Marino 
12786d7f5d3SJohn Marino 	pv->size = size;
12886d7f5d3SJohn Marino 
12986d7f5d3SJohn Marino 	if (vg) {
13086d7f5d3SJohn Marino 		pv->size -= pv_pe_start(pv);
13186d7f5d3SJohn Marino 		new_pe_count = pv_size(pv) / vg->extent_size;
13286d7f5d3SJohn Marino 
13386d7f5d3SJohn Marino  		if (!new_pe_count) {
13486d7f5d3SJohn Marino 			log_error("%s: Size must leave space for at "
13586d7f5d3SJohn Marino 				  "least one physical extent of "
13686d7f5d3SJohn Marino 				  "%" PRIu32 " sectors.", pv_name,
13786d7f5d3SJohn Marino 				  pv_pe_size(pv));
13886d7f5d3SJohn Marino 			goto bad;
13986d7f5d3SJohn Marino 		}
14086d7f5d3SJohn Marino 
14186d7f5d3SJohn Marino 		if (!pv_resize(pv, vg, new_pe_count))
14286d7f5d3SJohn Marino 			goto_bad;
14386d7f5d3SJohn Marino 	}
14486d7f5d3SJohn Marino 
14586d7f5d3SJohn Marino 	log_verbose("Resizing volume \"%s\" to %" PRIu64 " sectors.",
14686d7f5d3SJohn Marino 		    pv_name, pv_size(pv));
14786d7f5d3SJohn Marino 
14886d7f5d3SJohn Marino 	log_verbose("Updating physical volume \"%s\"", pv_name);
14986d7f5d3SJohn Marino 	if (!is_orphan_vg(pv_vg_name(pv))) {
15086d7f5d3SJohn Marino 		if (!vg_write(vg) || !vg_commit(vg)) {
15186d7f5d3SJohn Marino 			log_error("Failed to store physical volume \"%s\" in "
15286d7f5d3SJohn Marino 				  "volume group \"%s\"", pv_name, vg->name);
15386d7f5d3SJohn Marino 			goto bad;
15486d7f5d3SJohn Marino 		}
15586d7f5d3SJohn Marino 		backup(vg);
15686d7f5d3SJohn Marino 	} else if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
15786d7f5d3SJohn Marino 		log_error("Failed to store physical volume \"%s\"",
15886d7f5d3SJohn Marino 			  pv_name);
15986d7f5d3SJohn Marino 		goto bad;;
16086d7f5d3SJohn Marino 	}
16186d7f5d3SJohn Marino 
16286d7f5d3SJohn Marino 	log_print("Physical volume \"%s\" changed", pv_name);
16386d7f5d3SJohn Marino 	r = 1;
16486d7f5d3SJohn Marino 
16586d7f5d3SJohn Marino bad:
16686d7f5d3SJohn Marino 	unlock_vg(cmd, vg_name);
16786d7f5d3SJohn Marino 	if (!old_vg)
16886d7f5d3SJohn Marino 		vg_release(vg);
16986d7f5d3SJohn Marino 	return r;
17086d7f5d3SJohn Marino }
17186d7f5d3SJohn Marino 
_pvresize_single(struct cmd_context * cmd,struct volume_group * vg,struct physical_volume * pv,void * handle)17286d7f5d3SJohn Marino static int _pvresize_single(struct cmd_context *cmd,
17386d7f5d3SJohn Marino 			    struct volume_group *vg,
17486d7f5d3SJohn Marino 			    struct physical_volume *pv,
17586d7f5d3SJohn Marino 			    void *handle)
17686d7f5d3SJohn Marino {
17786d7f5d3SJohn Marino 	struct pvresize_params *params = (struct pvresize_params *) handle;
17886d7f5d3SJohn Marino 
17986d7f5d3SJohn Marino 	params->total++;
18086d7f5d3SJohn Marino 
18186d7f5d3SJohn Marino 	if (!_pv_resize_single(cmd, vg, pv, params->new_size)) {
18286d7f5d3SJohn Marino 		stack;
18386d7f5d3SJohn Marino 		return ECMD_FAILED;
18486d7f5d3SJohn Marino 	}
18586d7f5d3SJohn Marino 
18686d7f5d3SJohn Marino 	params->done++;
18786d7f5d3SJohn Marino 
18886d7f5d3SJohn Marino 	return ECMD_PROCESSED;
18986d7f5d3SJohn Marino }
19086d7f5d3SJohn Marino 
pvresize(struct cmd_context * cmd,int argc,char ** argv)19186d7f5d3SJohn Marino int pvresize(struct cmd_context *cmd, int argc, char **argv)
19286d7f5d3SJohn Marino {
19386d7f5d3SJohn Marino 	struct pvresize_params params;
19486d7f5d3SJohn Marino 	int ret;
19586d7f5d3SJohn Marino 
19686d7f5d3SJohn Marino 	if (!argc) {
19786d7f5d3SJohn Marino 		log_error("Please supply physical volume(s)");
19886d7f5d3SJohn Marino 		return EINVALID_CMD_LINE;
19986d7f5d3SJohn Marino 	}
20086d7f5d3SJohn Marino 
20186d7f5d3SJohn Marino 	if (arg_sign_value(cmd, physicalvolumesize_ARG, 0) == SIGN_MINUS) {
20286d7f5d3SJohn Marino 		log_error("Physical volume size may not be negative");
20386d7f5d3SJohn Marino 		return 0;
20486d7f5d3SJohn Marino 	}
20586d7f5d3SJohn Marino 
20686d7f5d3SJohn Marino 	params.new_size = arg_uint64_value(cmd, physicalvolumesize_ARG,
20786d7f5d3SJohn Marino 					   UINT64_C(0));
20886d7f5d3SJohn Marino 
20986d7f5d3SJohn Marino 	params.done = 0;
21086d7f5d3SJohn Marino 	params.total = 0;
21186d7f5d3SJohn Marino 
21286d7f5d3SJohn Marino 	ret = process_each_pv(cmd, argc, argv, NULL, READ_FOR_UPDATE, 0, &params,
21386d7f5d3SJohn Marino 			      _pvresize_single);
21486d7f5d3SJohn Marino 
21586d7f5d3SJohn Marino 	log_print("%d physical volume(s) resized / %d physical volume(s) "
21686d7f5d3SJohn Marino 		  "not resized", params.done, params.total - params.done);
21786d7f5d3SJohn Marino 
21886d7f5d3SJohn Marino 	return ret;
21986d7f5d3SJohn Marino }
220