xref: /netbsd-src/external/gpl2/lvm2/dist/tools/pvresize.c (revision 962766853c385b86328bab806c19ccdf4e22f287)
1 /*	$NetBSD: pvresize.c,v 1.1.1.1 2008/12/22 00:19:07 haad Exp $	*/
2 
3 /*
4  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5  * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
6  * Copyright (C) 2005 Zak Kipling. All rights reserved.
7  *
8  * This file is part of LVM2.
9  *
10  * This copyrighted material is made available to anyone wishing to use,
11  * modify, copy, or redistribute it subject to the terms and conditions
12  * of the GNU Lesser General Public License v.2.1.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 
19 #include "tools.h"
20 
21 struct pvresize_params {
22 	uint64_t new_size;
23 
24 	unsigned done;
25 	unsigned total;
26 };
27 
28 static int _pv_resize_single(struct cmd_context *cmd,
29 			     struct volume_group *vg,
30 			     struct physical_volume *pv,
31 			     const uint64_t new_size)
32 {
33 	struct pv_list *pvl;
34 	int consistent = 1;
35 	uint64_t size = 0;
36 	uint32_t new_pe_count = 0;
37 	struct dm_list mdas;
38 	const char *pv_name = pv_dev_name(pv);
39 	const char *vg_name;
40 	struct lvmcache_info *info;
41 	int mda_count = 0;
42 
43 	dm_list_init(&mdas);
44 
45 	if (is_orphan_vg(pv_vg_name(pv))) {
46 		vg_name = VG_ORPHANS;
47 		if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
48 			log_error("Can't get lock for orphans");
49 			return 0;
50 		}
51 
52 		if (!(pv = pv_read(cmd, pv_name, &mdas, NULL, 1))) {
53 			unlock_vg(cmd, vg_name);
54 			log_error("Unable to read PV \"%s\"", pv_name);
55 			return 0;
56 		}
57 
58 		mda_count = dm_list_size(&mdas);
59 	} else {
60 		vg_name = pv_vg_name(pv);
61 
62 		if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
63 			log_error("Can't get lock for %s", pv_vg_name(pv));
64 			return 0;
65 		}
66 
67 		if (!(vg = vg_read(cmd, vg_name, NULL, &consistent))) {
68 			unlock_vg(cmd, vg_name);
69 			log_error("Unable to find volume group of \"%s\"",
70 				  pv_name);
71 			return 0;
72 		}
73 
74 		if (!vg_check_status(vg, CLUSTERED | EXPORTED_VG | LVM_WRITE)) {
75 			unlock_vg(cmd, vg_name);
76 			return 0;
77 		}
78 
79 		if (!(pvl = find_pv_in_vg(vg, pv_name))) {
80 			unlock_vg(cmd, vg_name);
81 			log_error("Unable to find \"%s\" in volume group \"%s\"",
82 				  pv_name, vg->name);
83 			return 0;
84 		}
85 
86 		pv = pvl->pv;
87 
88 		if (!(info = info_from_pvid(pv->dev->pvid, 0))) {
89 			unlock_vg(cmd, vg_name);
90 			log_error("Can't get info for PV %s in volume group %s",
91 				  pv_name, vg->name);
92 			return 0;
93 		}
94 
95 		mda_count = dm_list_size(&info->mdas);
96 
97 		if (!archive(vg))
98 			return 0;
99 	}
100 
101 	/* FIXME Create function to test compatibility properly */
102 	if (mda_count > 1) {
103 		log_error("%s: too many metadata areas for pvresize", pv_name);
104 		unlock_vg(cmd, vg_name);
105 		return 0;
106 	}
107 
108 	if (!(pv->fmt->features & FMT_RESIZE_PV)) {
109 		log_error("Physical volume %s format does not support resizing.",
110 			  pv_name);
111 		unlock_vg(cmd, vg_name);
112 		return 0;
113 	}
114 
115 	/* Get new size */
116 	if (!dev_get_size(pv_dev(pv), &size)) {
117 		log_error("%s: Couldn't get size.", pv_name);
118 		unlock_vg(cmd, vg_name);
119 		return 0;
120 	}
121 
122 	if (new_size) {
123 		if (new_size > size)
124 			log_warn("WARNING: %s: Overriding real size. "
125 				  "You could lose data.", pv_name);
126 		log_verbose("%s: Pretending size is %" PRIu64 " not %" PRIu64
127 			    " sectors.", pv_name, new_size, pv_size(pv));
128 		size = new_size;
129 	}
130 
131 	if (size < PV_MIN_SIZE) {
132 		log_error("%s: Size must exceed minimum of %ld sectors.",
133 			  pv_name, PV_MIN_SIZE);
134 		unlock_vg(cmd, vg_name);
135 		return 0;
136 	}
137 
138 	if (size < pv_pe_start(pv)) {
139 		log_error("%s: Size must exceed physical extent start of "
140 			  "%" PRIu64 " sectors.", pv_name, pv_pe_start(pv));
141 		unlock_vg(cmd, vg_name);
142 		return 0;
143 	}
144 
145 	pv->size = size;
146 
147 	if (vg) {
148 		pv->size -= pv_pe_start(pv);
149 		new_pe_count = pv_size(pv) / vg->extent_size;
150 
151  		if (!new_pe_count) {
152 			log_error("%s: Size must leave space for at "
153 				  "least one physical extent of "
154 				  "%" PRIu32 " sectors.", pv_name,
155 				  pv_pe_size(pv));
156 			unlock_vg(cmd, vg_name);
157 			return 0;
158 		}
159 
160 		if (!pv_resize(pv, vg, new_pe_count)) {
161 			unlock_vg(cmd, vg_name);
162 			return_0;
163 		}
164 	}
165 
166 	log_verbose("Resizing volume \"%s\" to %" PRIu64 " sectors.",
167 		    pv_name, pv_size(pv));
168 
169 	log_verbose("Updating physical volume \"%s\"", pv_name);
170 	if (!is_orphan_vg(pv_vg_name(pv))) {
171 		if (!vg_write(vg) || !vg_commit(vg)) {
172 			unlock_vg(cmd, pv_vg_name(pv));
173 			log_error("Failed to store physical volume \"%s\" in "
174 				  "volume group \"%s\"", pv_name, vg->name);
175 			return 0;
176 		}
177 		backup(vg);
178 		unlock_vg(cmd, vg_name);
179 	} else {
180 		if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
181 			unlock_vg(cmd, VG_ORPHANS);
182 			log_error("Failed to store physical volume \"%s\"",
183 				  pv_name);
184 			return 0;
185 		}
186 		unlock_vg(cmd, vg_name);
187 	}
188 
189 	log_print("Physical volume \"%s\" changed", pv_name);
190 	return 1;
191 }
192 
193 static int _pvresize_single(struct cmd_context *cmd,
194 			    struct volume_group *vg,
195 			    struct physical_volume *pv,
196 			    void *handle)
197 {
198 	struct pvresize_params *params = (struct pvresize_params *) handle;
199 
200 	params->total++;
201 
202 	if (!_pv_resize_single(cmd, vg, pv, params->new_size))
203 		return ECMD_FAILED;
204 
205 	params->done++;
206 
207 	return ECMD_PROCESSED;
208 }
209 
210 int pvresize(struct cmd_context *cmd, int argc, char **argv)
211 {
212 	struct pvresize_params params;
213 	int ret;
214 
215 	if (!argc) {
216 		log_error("Please supply physical volume(s)");
217 		return EINVALID_CMD_LINE;
218 	}
219 
220 	if (arg_sign_value(cmd, physicalvolumesize_ARG, 0) == SIGN_MINUS) {
221 		log_error("Physical volume size may not be negative");
222 		return 0;
223 	}
224 
225 	params.new_size = arg_uint64_value(cmd, physicalvolumesize_ARG,
226 					   UINT64_C(0));
227 
228 	params.done = 0;
229 	params.total = 0;
230 
231 	ret = process_each_pv(cmd, argc, argv, NULL, LCK_VG_WRITE, &params,
232 			      _pvresize_single);
233 
234 	log_print("%d physical volume(s) resized / %d physical volume(s) "
235 		  "not resized", params.done, params.total - params.done);
236 
237 	return ret;
238 }
239