1 /*        $NetBSD: vgchange.c,v 1.1.1.3 2009/12/02 00:25:51 haad Exp $          */
2 
3 /*
4  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6  *
7  * This file is part of LVM2.
8  *
9  * This copyrighted material is made available to anyone wishing to use,
10  * modify, copy, or redistribute it subject to the terms and conditions
11  * of the GNU Lesser General Public License v.2.1.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, write to the Free Software Foundation,
15  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17 
18 #include "tools.h"
19 
_monitor_lvs_in_vg(struct cmd_context * cmd,struct volume_group * vg,int reg)20 static int _monitor_lvs_in_vg(struct cmd_context *cmd,
21                                      struct volume_group *vg, int reg)
22 {
23           struct lv_list *lvl;
24           struct logical_volume *lv;
25           struct lvinfo info;
26           int lv_active;
27           int count = 0;
28 
29           dm_list_iterate_items(lvl, &vg->lvs) {
30                     lv = lvl->lv;
31 
32                     if (!lv_info(cmd, lv, &info, 0, 0))
33                               lv_active = 0;
34                     else
35                               lv_active = info.exists;
36 
37                     /*
38                      * FIXME: Need to consider all cases... PVMOVE, etc
39                      */
40                     if ((lv->status & PVMOVE) || !lv_active)
41                               continue;
42 
43                     if (!monitor_dev_for_events(cmd, lv, reg)) {
44                               continue;
45                     } else
46                               count++;
47           }
48 
49           /*
50            * returns the number of _new_ monitored devices
51            */
52 
53           return count;
54 }
55 
_activate_lvs_in_vg(struct cmd_context * cmd,struct volume_group * vg,int activate)56 static int _activate_lvs_in_vg(struct cmd_context *cmd,
57                                      struct volume_group *vg, int activate)
58 {
59           struct lv_list *lvl;
60           struct logical_volume *lv;
61           int count = 0, expected_count = 0;
62 
63           dm_list_iterate_items(lvl, &vg->lvs) {
64                     lv = lvl->lv;
65 
66                     if (!lv_is_visible(lv))
67                               continue;
68 
69                     /* Only request activation of snapshot origin devices */
70                     if ((lv->status & SNAPSHOT) || lv_is_cow(lv))
71                               continue;
72 
73                     /* Only request activation of mirror LV */
74                     if ((lv->status & MIRROR_IMAGE) || (lv->status & MIRROR_LOG))
75                               continue;
76 
77                     /* Can't deactivate a pvmove LV */
78                     /* FIXME There needs to be a controlled way of doing this */
79                     if (((activate == CHANGE_AN) || (activate == CHANGE_ALN)) &&
80                         ((lv->status & PVMOVE) ))
81                               continue;
82 
83                     expected_count++;
84 
85                     if (activate == CHANGE_AN) {
86                               if (!deactivate_lv(cmd, lv))
87                                         continue;
88                     } else if (activate == CHANGE_ALN) {
89                               if (!deactivate_lv_local(cmd, lv))
90                                         continue;
91                     } else if (lv_is_origin(lv) || (activate == CHANGE_AE)) {
92                               if (!activate_lv_excl(cmd, lv))
93                                         continue;
94                     } else if (activate == CHANGE_ALY) {
95                               if (!activate_lv_local(cmd, lv))
96                                         continue;
97                     } else if (!activate_lv(cmd, lv))
98                               continue;
99 
100                     if (activate != CHANGE_AN && activate != CHANGE_ALN &&
101                         (lv->status & (PVMOVE|CONVERTING)))
102                               lv_spawn_background_polling(cmd, lv);
103 
104                     count++;
105           }
106 
107           if (expected_count)
108                     log_verbose("%s %d logical volumes in volume group %s",
109                                   activate ? "Activated" : "Deactivated",
110                                   count, vg->name);
111 
112           return (expected_count != count) ? ECMD_FAILED : ECMD_PROCESSED;
113 }
114 
_vgchange_monitoring(struct cmd_context * cmd,struct volume_group * vg)115 static int _vgchange_monitoring(struct cmd_context *cmd, struct volume_group *vg)
116 {
117           int active, monitored;
118 
119           if ((active = lvs_in_vg_activated(vg)) &&
120               dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) {
121                     monitored = _monitor_lvs_in_vg(cmd, vg, dmeventd_monitor_mode());
122                     log_print("%d logical volume(s) in volume group "
123                                   "\"%s\" %smonitored",
124                                   monitored, vg->name, (dmeventd_monitor_mode()) ? "" : "un");
125           }
126 
127           return ECMD_PROCESSED;
128 }
129 
_vgchange_available(struct cmd_context * cmd,struct volume_group * vg)130 static int _vgchange_available(struct cmd_context *cmd, struct volume_group *vg)
131 {
132           int lv_open, active, monitored;
133           int available, ret;
134           int activate = 1;
135 
136           /*
137            * Safe, since we never write out new metadata here. Required for
138            * partial activation to work.
139            */
140           cmd->handles_missing_pvs = 1;
141 
142           available = arg_uint_value(cmd, available_ARG, 0);
143 
144           if ((available == CHANGE_AN) || (available == CHANGE_ALN))
145                     activate = 0;
146 
147           /* FIXME: Force argument to deactivate them? */
148           if (!activate && (lv_open = lvs_in_vg_opened(vg))) {
149                     log_error("Can't deactivate volume group \"%s\" with %d open "
150                                 "logical volume(s)", vg->name, lv_open);
151                     return ECMD_FAILED;
152           }
153 
154           /* FIXME Move into library where clvmd can use it */
155           if (activate)
156                     check_current_backup(vg);
157 
158           if (activate && (active = lvs_in_vg_activated(vg))) {
159                     log_verbose("%d logical volume(s) in volume group \"%s\" "
160                                   "already active", active, vg->name);
161                     if (dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) {
162                               monitored = _monitor_lvs_in_vg(cmd, vg, dmeventd_monitor_mode());
163                               log_verbose("%d existing logical volume(s) in volume "
164                                             "group \"%s\" %smonitored",
165                                             monitored, vg->name,
166                                             dmeventd_monitor_mode() ? "" : "un");
167                     }
168           }
169 
170           ret = _activate_lvs_in_vg(cmd, vg, available);
171 
172           log_print("%d logical volume(s) in volume group \"%s\" now active",
173                       lvs_in_vg_activated(vg), vg->name);
174           return ret;
175 }
176 
_vgchange_alloc(struct cmd_context * cmd,struct volume_group * vg)177 static int _vgchange_alloc(struct cmd_context *cmd, struct volume_group *vg)
178 {
179           alloc_policy_t alloc;
180 
181           alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_NORMAL);
182 
183           if (!archive(vg)) {
184                     stack;
185                     return ECMD_FAILED;
186           }
187 
188           /* FIXME: make consistent with vg_set_alloc_policy() */
189           if (alloc == vg->alloc) {
190                     log_error("Volume group allocation policy is already %s",
191                                 get_alloc_string(vg->alloc));
192                     return ECMD_FAILED;
193           }
194           if (!vg_set_alloc_policy(vg, alloc)) {
195                     stack;
196                     return ECMD_FAILED;
197           }
198 
199           if (!vg_write(vg) || !vg_commit(vg)) {
200                     stack;
201                     return ECMD_FAILED;
202           }
203 
204           backup(vg);
205 
206           log_print("Volume group \"%s\" successfully changed", vg->name);
207 
208           return ECMD_PROCESSED;
209 }
210 
_vgchange_resizeable(struct cmd_context * cmd,struct volume_group * vg)211 static int _vgchange_resizeable(struct cmd_context *cmd,
212                                         struct volume_group *vg)
213 {
214           int resizeable = !strcmp(arg_str_value(cmd, resizeable_ARG, "n"), "y");
215 
216           if (resizeable && vg_is_resizeable(vg)) {
217                     log_error("Volume group \"%s\" is already resizeable",
218                                 vg->name);
219                     return ECMD_FAILED;
220           }
221 
222           if (!resizeable && !vg_is_resizeable(vg)) {
223                     log_error("Volume group \"%s\" is already not resizeable",
224                                 vg->name);
225                     return ECMD_FAILED;
226           }
227 
228           if (!archive(vg)) {
229                     stack;
230                     return ECMD_FAILED;
231           }
232 
233           if (resizeable)
234                     vg->status |= RESIZEABLE_VG;
235           else
236                     vg->status &= ~RESIZEABLE_VG;
237 
238           if (!vg_write(vg) || !vg_commit(vg)) {
239                     stack;
240                     return ECMD_FAILED;
241           }
242 
243           backup(vg);
244 
245           log_print("Volume group \"%s\" successfully changed", vg->name);
246 
247           return ECMD_PROCESSED;
248 }
249 
_vgchange_clustered(struct cmd_context * cmd,struct volume_group * vg)250 static int _vgchange_clustered(struct cmd_context *cmd,
251                                      struct volume_group *vg)
252 {
253           int clustered = !strcmp(arg_str_value(cmd, clustered_ARG, "n"), "y");
254 
255           if (clustered && (vg_is_clustered(vg))) {
256                     log_error("Volume group \"%s\" is already clustered",
257                                 vg->name);
258                     return ECMD_FAILED;
259           }
260 
261           if (!clustered && !(vg_is_clustered(vg))) {
262                     log_error("Volume group \"%s\" is already not clustered",
263                                 vg->name);
264                     return ECMD_FAILED;
265           }
266 
267           if (!archive(vg)) {
268                     stack;
269                     return ECMD_FAILED;
270           }
271 
272           if (!vg_set_clustered(vg, clustered))
273                     return ECMD_FAILED;
274 
275           if (!vg_write(vg) || !vg_commit(vg)) {
276                     stack;
277                     return ECMD_FAILED;
278           }
279 
280           backup(vg);
281 
282           log_print("Volume group \"%s\" successfully changed", vg->name);
283 
284           return ECMD_PROCESSED;
285 }
286 
_vgchange_logicalvolume(struct cmd_context * cmd,struct volume_group * vg)287 static int _vgchange_logicalvolume(struct cmd_context *cmd,
288                                            struct volume_group *vg)
289 {
290           uint32_t max_lv = arg_uint_value(cmd, logicalvolume_ARG, 0);
291 
292           if (!archive(vg)) {
293                     stack;
294                     return ECMD_FAILED;
295           }
296 
297           if (!vg_set_max_lv(vg, max_lv)) {
298                     stack;
299                     return ECMD_FAILED;
300           }
301 
302           if (!vg_write(vg) || !vg_commit(vg)) {
303                     stack;
304                     return ECMD_FAILED;
305           }
306 
307           backup(vg);
308 
309           log_print("Volume group \"%s\" successfully changed", vg->name);
310 
311           return ECMD_PROCESSED;
312 }
313 
_vgchange_physicalvolumes(struct cmd_context * cmd,struct volume_group * vg)314 static int _vgchange_physicalvolumes(struct cmd_context *cmd,
315                                              struct volume_group *vg)
316 {
317           uint32_t max_pv = arg_uint_value(cmd, maxphysicalvolumes_ARG, 0);
318 
319           if (arg_sign_value(cmd, maxphysicalvolumes_ARG, 0) == SIGN_MINUS) {
320                     log_error("MaxPhysicalVolumes may not be negative");
321                     return EINVALID_CMD_LINE;
322           }
323 
324           if (!archive(vg)) {
325                     stack;
326                     return ECMD_FAILED;
327           }
328 
329           if (!vg_set_max_pv(vg, max_pv)) {
330                     stack;
331                     return ECMD_FAILED;
332           }
333 
334           if (!vg_write(vg) || !vg_commit(vg)) {
335                     stack;
336                     return ECMD_FAILED;
337           }
338 
339           backup(vg);
340 
341           log_print("Volume group \"%s\" successfully changed", vg->name);
342 
343           return ECMD_PROCESSED;
344 }
345 
_vgchange_pesize(struct cmd_context * cmd,struct volume_group * vg)346 static int _vgchange_pesize(struct cmd_context *cmd, struct volume_group *vg)
347 {
348           uint32_t extent_size;
349 
350           if (arg_sign_value(cmd, physicalextentsize_ARG, 0) == SIGN_MINUS) {
351                     log_error("Physical extent size may not be negative");
352                     return EINVALID_CMD_LINE;
353           }
354 
355           extent_size = arg_uint_value(cmd, physicalextentsize_ARG, 0);
356           /* FIXME: remove check - redundant with vg_change_pesize */
357           if (extent_size == vg->extent_size) {
358                     log_error("Physical extent size of VG %s is already %s",
359                                 vg->name, display_size(cmd, (uint64_t) extent_size));
360                     return ECMD_PROCESSED;
361           }
362 
363           if (!archive(vg)) {
364                     stack;
365                     return ECMD_FAILED;
366           }
367 
368           if (!vg_set_extent_size(vg, extent_size)) {
369                     stack;
370                     return EINVALID_CMD_LINE;
371           }
372 
373           if (!vg_write(vg) || !vg_commit(vg)) {
374                     stack;
375                     return ECMD_FAILED;
376           }
377 
378           backup(vg);
379 
380           log_print("Volume group \"%s\" successfully changed", vg->name);
381 
382           return ECMD_PROCESSED;
383 }
384 
_vgchange_tag(struct cmd_context * cmd,struct volume_group * vg,int arg)385 static int _vgchange_tag(struct cmd_context *cmd, struct volume_group *vg,
386                                int arg)
387 {
388           const char *tag;
389 
390           if (!(tag = arg_str_value(cmd, arg, NULL))) {
391                     log_error("Failed to get tag");
392                     return ECMD_FAILED;
393           }
394 
395           if (!(vg->fid->fmt->features & FMT_TAGS)) {
396                     log_error("Volume group %s does not support tags", vg->name);
397                     return ECMD_FAILED;
398           }
399 
400           if (!archive(vg)) {
401                     stack;
402                     return ECMD_FAILED;
403           }
404 
405           if ((arg == addtag_ARG)) {
406                     if (!str_list_add(cmd->mem, &vg->tags, tag)) {
407                               log_error("Failed to add tag %s to volume group %s",
408                                           tag, vg->name);
409                               return ECMD_FAILED;
410                     }
411           } else {
412                     if (!str_list_del(&vg->tags, tag)) {
413                               log_error("Failed to remove tag %s from volume group "
414                                           "%s", tag, vg->name);
415                               return ECMD_FAILED;
416                     }
417           }
418 
419           if (!vg_write(vg) || !vg_commit(vg)) {
420                     stack;
421                     return ECMD_FAILED;
422           }
423 
424           backup(vg);
425 
426           log_print("Volume group \"%s\" successfully changed", vg->name);
427 
428           return ECMD_PROCESSED;
429 }
430 
_vgchange_uuid(struct cmd_context * cmd __attribute ((unused)),struct volume_group * vg)431 static int _vgchange_uuid(struct cmd_context *cmd __attribute((unused)),
432                                 struct volume_group *vg)
433 {
434           struct lv_list *lvl;
435 
436           if (lvs_in_vg_activated(vg)) {
437                     log_error("Volume group has active logical volumes");
438                     return ECMD_FAILED;
439           }
440 
441           if (!archive(vg)) {
442                     stack;
443                     return ECMD_FAILED;
444           }
445 
446           if (!id_create(&vg->id)) {
447                     log_error("Failed to generate new random UUID for VG %s.",
448                                 vg->name);
449                     return ECMD_FAILED;
450           }
451 
452           dm_list_iterate_items(lvl, &vg->lvs) {
453                     memcpy(&lvl->lv->lvid, &vg->id, sizeof(vg->id));
454           }
455 
456           if (!vg_write(vg) || !vg_commit(vg)) {
457                     stack;
458                     return ECMD_FAILED;
459           }
460 
461           backup(vg);
462 
463           log_print("Volume group \"%s\" successfully changed", vg->name);
464 
465           return ECMD_PROCESSED;
466 }
467 
_vgchange_refresh(struct cmd_context * cmd,struct volume_group * vg)468 static int _vgchange_refresh(struct cmd_context *cmd, struct volume_group *vg)
469 {
470           log_verbose("Refreshing volume group \"%s\"", vg->name);
471 
472           if (!vg_refresh_visible(cmd, vg)) {
473                     stack;
474                     return ECMD_FAILED;
475           }
476 
477           return ECMD_PROCESSED;
478 }
479 
vgchange_single(struct cmd_context * cmd,const char * vg_name,struct volume_group * vg,void * handle __attribute ((unused)))480 static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
481                                  struct volume_group *vg,
482                                  void *handle __attribute((unused)))
483 {
484           int r = ECMD_FAILED;
485 
486           if (vg_is_exported(vg)) {
487                     log_error("Volume group \"%s\" is exported", vg_name);
488                     return ECMD_FAILED;
489           }
490 
491           init_dmeventd_monitor(arg_int_value(cmd, monitor_ARG,
492                                                       (is_static() || arg_count(cmd, ignoremonitoring_ARG)) ?
493                                                       DMEVENTD_MONITOR_IGNORE : DEFAULT_DMEVENTD_MONITOR));
494 
495           if (arg_count(cmd, available_ARG))
496                     r = _vgchange_available(cmd, vg);
497 
498           else if (arg_count(cmd, monitor_ARG))
499                     r = _vgchange_monitoring(cmd, vg);
500 
501           else if (arg_count(cmd, resizeable_ARG))
502                     r = _vgchange_resizeable(cmd, vg);
503 
504           else if (arg_count(cmd, logicalvolume_ARG))
505                     r = _vgchange_logicalvolume(cmd, vg);
506 
507           else if (arg_count(cmd, maxphysicalvolumes_ARG))
508                     r = _vgchange_physicalvolumes(cmd, vg);
509 
510           else if (arg_count(cmd, addtag_ARG))
511                     r = _vgchange_tag(cmd, vg, addtag_ARG);
512 
513           else if (arg_count(cmd, deltag_ARG))
514                     r = _vgchange_tag(cmd, vg, deltag_ARG);
515 
516           else if (arg_count(cmd, physicalextentsize_ARG))
517                     r = _vgchange_pesize(cmd, vg);
518 
519           else if (arg_count(cmd, uuid_ARG))
520                     r = _vgchange_uuid(cmd, vg);
521 
522           else if (arg_count(cmd, alloc_ARG))
523                     r = _vgchange_alloc(cmd, vg);
524 
525           else if (arg_count(cmd, clustered_ARG))
526                     r = _vgchange_clustered(cmd, vg);
527 
528           else if (arg_count(cmd, refresh_ARG))
529                     r = _vgchange_refresh(cmd, vg);
530 
531           return r;
532 }
533 
vgchange(struct cmd_context * cmd,int argc,char ** argv)534 int vgchange(struct cmd_context *cmd, int argc, char **argv)
535 {
536           if (!
537               (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
538                arg_count(cmd, maxphysicalvolumes_ARG) +
539                arg_count(cmd, resizeable_ARG) + arg_count(cmd, deltag_ARG) +
540                arg_count(cmd, addtag_ARG) + arg_count(cmd, uuid_ARG) +
541                arg_count(cmd, physicalextentsize_ARG) +
542                arg_count(cmd, clustered_ARG) + arg_count(cmd, alloc_ARG) +
543                arg_count(cmd, monitor_ARG) + arg_count(cmd, refresh_ARG))) {
544                     log_error("One of -a, -c, -l, -p, -s, -x, --refresh, "
545                                         "--uuid, --alloc, --addtag or --deltag required");
546                     return EINVALID_CMD_LINE;
547           }
548 
549           /* FIXME Cope with several changes at once! */
550           if (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
551               arg_count(cmd, maxphysicalvolumes_ARG) +
552               arg_count(cmd, resizeable_ARG) + arg_count(cmd, deltag_ARG) +
553               arg_count(cmd, addtag_ARG) + arg_count(cmd, alloc_ARG) +
554               arg_count(cmd, uuid_ARG) + arg_count(cmd, clustered_ARG) +
555               arg_count(cmd, physicalextentsize_ARG) > 1) {
556                     log_error("Only one of -a, -c, -l, -p, -s, -x, --uuid, "
557                                 "--alloc, --addtag or --deltag allowed");
558                     return EINVALID_CMD_LINE;
559           }
560 
561           if (arg_count(cmd, ignorelockingfailure_ARG) &&
562               !arg_count(cmd, available_ARG)) {
563                     log_error("--ignorelockingfailure only available with -a");
564                     return EINVALID_CMD_LINE;
565           }
566 
567           if (arg_count(cmd, available_ARG) == 1
568               && arg_count(cmd, autobackup_ARG)) {
569                     log_error("-A option not necessary with -a option");
570                     return EINVALID_CMD_LINE;
571           }
572 
573           return process_each_vg(cmd, argc, argv,
574                                      (arg_count(cmd, available_ARG)) ?
575                                      0 : READ_FOR_UPDATE,
576                                      NULL,
577                                      &vgchange_single);
578 }
579