Tizen 2.1 base
[external/device-mapper.git] / tools / pvchange.c
1 /*
2  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
4  *
5  * This file is part of LVM2.
6  *
7  * This copyrighted material is made available to anyone wishing to use,
8  * modify, copy, or redistribute it subject to the terms and conditions
9  * of the GNU Lesser General Public License v.2.1.
10  *
11  * You should have received a copy of the GNU Lesser General Public License
12  * along with this program; if not, write to the Free Software Foundation,
13  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
14  */
15
16 #include "tools.h"
17
18 /* FIXME Locking.  PVs in VG. */
19
20 static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg,
21                             struct physical_volume *pv,
22                             void *handle __attribute__((unused)))
23 {
24         uint32_t orig_pe_alloc_count;
25         /* FIXME Next three only required for format1. */
26         uint32_t orig_pe_count, orig_pe_size;
27         uint64_t orig_pe_start;
28
29         const char *pv_name = pv_dev_name(pv);
30         const char *tag = NULL;
31         const char *orig_vg_name;
32         char uuid[64] __attribute__((aligned(8)));
33
34         int allocatable = 0;
35         int tagarg = 0;
36         int r = 0;
37         int mda_ignore = 0;
38
39         struct arg_value_group_list *current_group;
40
41         if (arg_count(cmd, addtag_ARG))
42                 tagarg = addtag_ARG;
43         else if (arg_count(cmd, deltag_ARG))
44                 tagarg = deltag_ARG;
45
46         if (arg_count(cmd, allocatable_ARG))
47                 allocatable = !strcmp(arg_str_value(cmd, allocatable_ARG, "n"),
48                                       "y");
49         if (arg_count(cmd, metadataignore_ARG))
50                 mda_ignore = !strcmp(arg_str_value(cmd, metadataignore_ARG, "n"),
51                                       "y");
52
53         /* If in a VG, must change using volume group. */
54         if (!is_orphan(pv)) {
55                 if (tagarg && !(vg->fid->fmt->features & FMT_TAGS)) {
56                         log_error("Volume group containing %s does not "
57                                   "support tags", pv_name);
58                         goto out;
59                 }
60                 if (arg_count(cmd, uuid_ARG) && lvs_in_vg_activated(vg)) {
61                         log_error("Volume group containing %s has active "
62                                   "logical volumes", pv_name);
63                         goto out;
64                 }
65                 if (!archive(vg))
66                         goto out;
67         } else {
68                 if (tagarg) {
69                         log_error("Can't change tag on Physical Volume %s not "
70                                   "in volume group", pv_name);
71                         return 0;
72                 }
73         }
74
75         if (arg_count(cmd, allocatable_ARG)) {
76                 if (is_orphan(pv) &&
77                     !(pv->fmt->features & FMT_ORPHAN_ALLOCATABLE)) {
78                         log_error("Allocatability not supported by orphan "
79                                   "%s format PV %s", pv->fmt->name, pv_name);
80                         goto out;
81                 }
82
83                 /* change allocatability for a PV */
84                 if (allocatable && (pv_status(pv) & ALLOCATABLE_PV)) {
85                         log_error("Physical volume \"%s\" is already "
86                                   "allocatable", pv_name);
87                         r = 1;
88                         goto out;
89                 }
90
91                 if (!allocatable && !(pv_status(pv) & ALLOCATABLE_PV)) {
92                         log_error("Physical volume \"%s\" is already "
93                                   "unallocatable", pv_name);
94                         r = 1;
95                         goto out;
96                 }
97
98                 if (allocatable) {
99                         log_verbose("Setting physical volume \"%s\" "
100                                     "allocatable", pv_name);
101                         pv->status |= ALLOCATABLE_PV;
102                 } else {
103                         log_verbose("Setting physical volume \"%s\" NOT "
104                                     "allocatable", pv_name);
105                         pv->status &= ~ALLOCATABLE_PV;
106                 }
107         } else if (tagarg) {
108                 /* tag or deltag */
109
110                 dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
111                         if (!grouped_arg_is_set(current_group->arg_values, tagarg))
112                                 continue;
113
114                         if (!(tag = grouped_arg_str_value(current_group->arg_values, tagarg, NULL))) {
115                                 log_error("Failed to get tag");
116                                 goto out;
117                         }
118
119                         if ((tagarg == addtag_ARG)) {
120                                 if (!str_list_add(cmd->mem, &pv->tags, tag)) {
121                                         log_error("Failed to add tag %s to physical "
122                                                   "volume %s", tag, pv_name);
123                                         goto out;
124                                 }
125                         } else if (!str_list_del(&pv->tags, tag)) {
126                                 log_error("Failed to remove tag %s from "
127                                         "physical volume" "%s", tag, pv_name);
128                                 goto out;
129                         }
130                 }
131         } else if (arg_count(cmd, metadataignore_ARG)) {
132                 if ((vg_mda_copies(vg) != VGMETADATACOPIES_UNMANAGED) &&
133                     (arg_count(cmd, force_ARG) == PROMPT) &&
134                     yes_no_prompt("Override preferred number of copies "
135                                   "of VG %s metadata? [y/n]: ",
136                                   pv_vg_name(pv)) == 'n') {
137                         log_error("Physical volume %s not changed", pv_name);
138                         goto out;
139                 }
140                 if (!pv_change_metadataignore(pv, mda_ignore))
141                         goto out;
142         } else {
143                 /* --uuid: Change PV ID randomly */
144                 if (!id_create(&pv->id)) {
145                         log_error("Failed to generate new random UUID for %s.",
146                                   pv_name);
147                         goto out;
148                 }
149                 if (!id_write_format(&pv->id, uuid, sizeof(uuid)))
150                         goto_out;
151                 log_verbose("Changing uuid of %s to %s.", pv_name, uuid);
152                 if (!is_orphan(pv)) {
153                         orig_vg_name = pv_vg_name(pv);
154                         orig_pe_alloc_count = pv_pe_alloc_count(pv);
155
156                         /* FIXME format1 pv_write doesn't preserve these. */
157                         orig_pe_size = pv_pe_size(pv);
158                         orig_pe_start = pv_pe_start(pv);
159                         orig_pe_count = pv_pe_count(pv);
160
161                         pv->vg_name = pv->fmt->orphan_vg_name;
162                         pv->pe_alloc_count = 0;
163                         if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
164                                 log_error("pv_write with new uuid failed "
165                                           "for %s.", pv_name);
166                                 goto out;
167                         }
168                         pv->vg_name = orig_vg_name;
169                         pv->pe_alloc_count = orig_pe_alloc_count;
170
171                         pv->pe_size = orig_pe_size;
172                         pv->pe_start = orig_pe_start;
173                         pv->pe_count = orig_pe_count;
174                 }
175         }
176
177         log_verbose("Updating physical volume \"%s\"", pv_name);
178         if (!is_orphan(pv)) {
179                 if (!vg_write(vg) || !vg_commit(vg)) {
180                         log_error("Failed to store physical volume \"%s\" in "
181                                   "volume group \"%s\"", pv_name, vg->name);
182                         goto out;
183                 }
184                 backup(vg);
185         } else if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
186                 log_error("Failed to store physical volume \"%s\"",
187                           pv_name);
188                 goto out;
189         }
190
191         log_print("Physical volume \"%s\" changed", pv_name);
192         r = 1;
193 out:
194         return r;
195
196 }
197
198 int pvchange(struct cmd_context *cmd, int argc, char **argv)
199 {
200         int opt = 0;
201         int done = 0;
202         int total = 0;
203
204         struct volume_group *vg;
205         const char *vg_name;
206         char *pv_name;
207
208         struct pv_list *pvl;
209         struct dm_list *vgnames;
210         struct str_list *sll;
211
212         if (arg_count(cmd, allocatable_ARG) + arg_is_set(cmd, addtag_ARG) +
213             arg_is_set(cmd, deltag_ARG) + arg_count(cmd, uuid_ARG) +
214             arg_count(cmd, metadataignore_ARG) != 1) {
215                 log_error("Please give exactly one option of -x, -uuid, "
216                           "--addtag or --deltag");
217                 return EINVALID_CMD_LINE;
218         }
219
220         if (!(arg_count(cmd, all_ARG)) && !argc) {
221                 log_error("Please give a physical volume path");
222                 return EINVALID_CMD_LINE;
223         }
224
225         if (arg_count(cmd, all_ARG) && argc) {
226                 log_error("Option a and PhysicalVolumePath are exclusive");
227                 return EINVALID_CMD_LINE;
228         }
229
230         if (argc) {
231                 log_verbose("Using physical volume(s) on command line");
232                 for (; opt < argc; opt++) {
233                         pv_name = argv[opt];
234                         unescape_colons_and_at_signs(pv_name, NULL, NULL);
235                         vg_name = find_vgname_from_pvname(cmd, pv_name);
236                         if (!vg_name) {
237                                 log_error("Failed to read physical volume %s",
238                                           pv_name);
239                                 continue;
240                         }
241                         vg = vg_read_for_update(cmd, vg_name, NULL, 0);
242                         if (vg_read_error(vg)) {
243                                 free_vg(vg);
244                                 stack;
245                                 continue;
246                         }
247                         pvl = find_pv_in_vg(vg, pv_name);
248                         if (!pvl || !pvl->pv) {
249                                 log_error("Unable to find %s in %s",
250                                           pv_name, vg_name);
251                                 continue;
252                         }
253
254                         total++;
255                         done += _pvchange_single(cmd, vg,
256                                                  pvl->pv, NULL);
257                         unlock_and_free_vg(cmd, vg, vg_name);
258                 }
259         } else {
260                 log_verbose("Scanning for physical volume names");
261                 /* FIXME: share code with toollib */
262                 /*
263                  * Take the global lock here so the lvmcache remains
264                  * consistent across orphan/non-orphan vg locks.  If we don't
265                  * take the lock here, pvs with 0 mdas in a non-orphan VG will
266                  * be processed twice.
267                  */
268                 if (!lock_vol(cmd, VG_GLOBAL, LCK_VG_WRITE)) {
269                         log_error("Unable to obtain global lock.");
270                         return ECMD_FAILED;
271                 }
272
273                 if ((vgnames = get_vgnames(cmd, 1)) &&
274                     !dm_list_empty(vgnames)) {
275                         dm_list_iterate_items(sll, vgnames) {
276                                 vg = vg_read_for_update(cmd, sll->str, NULL, 0);
277                                 if (vg_read_error(vg)) {
278                                         free_vg(vg);
279                                         stack;
280                                         continue;
281                                 }
282                                 dm_list_iterate_items(pvl, &vg->pvs) {
283                                         total++;
284                                         done += _pvchange_single(cmd, vg,
285                                                                  pvl->pv,
286                                                                  NULL);
287                                 }
288                                 unlock_and_free_vg(cmd, vg, sll->str);
289                         }
290                 }
291         }
292
293         unlock_vg(cmd, VG_GLOBAL);
294         log_print("%d physical volume%s changed / %d physical volume%s "
295                   "not changed",
296                   done, done == 1 ? "" : "s",
297                   total - done, (total - done) == 1 ? "" : "s");
298
299         return (total == done) ? ECMD_PROCESSED : ECMD_FAILED;
300 }