1 /*        $NetBSD: pvmove.c,v 1.1.1.2 2009/12/02 00:25:54 haad Exp $  */
2 
3 /*
4  * Copyright (C) 2003-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 #include "polldaemon.h"
20 #include "display.h"
21 
22 #define PVMOVE_FIRST_TIME   0x00000001      /* Called for first time */
23 
_pvmove_target_present(struct cmd_context * cmd,int clustered)24 static int _pvmove_target_present(struct cmd_context *cmd, int clustered)
25 {
26           const struct segment_type *segtype;
27           unsigned attr = 0;
28           int found = 1;
29           static int _clustered_found = -1;
30 
31           if (clustered && _clustered_found >= 0)
32                     return _clustered_found;
33 
34           if (!(segtype = get_segtype_from_string(cmd, "mirror")))
35                     return_0;
36 
37           if (activation() && segtype->ops->target_present &&
38               !segtype->ops->target_present(cmd, NULL, clustered ? &attr : NULL))
39                     found = 0;
40 
41           if (activation() && clustered) {
42                     if (found && (attr & MIRROR_LOG_CLUSTERED))
43                               _clustered_found = found = 1;
44                     else
45                               _clustered_found = found = 0;
46           }
47 
48           return found;
49 }
50 
_pvmove_is_exclusive(struct cmd_context * cmd,struct volume_group * vg)51 static unsigned _pvmove_is_exclusive(struct cmd_context *cmd,
52                                              struct volume_group *vg)
53 {
54           if (vg_is_clustered(vg))
55                     if (!_pvmove_target_present(cmd, 1))
56                               return 1;
57 
58           return 0;
59 }
60 
61 /* Allow /dev/vgname/lvname, vgname/lvname or lvname */
_extract_lvname(struct cmd_context * cmd,const char * vgname,const char * arg)62 static const char *_extract_lvname(struct cmd_context *cmd, const char *vgname,
63                                            const char *arg)
64 {
65           const char *lvname;
66 
67           /* Is an lvname supplied directly? */
68           if (!strchr(arg, '/'))
69                     return arg;
70 
71           lvname = skip_dev_dir(cmd, arg, NULL);
72           while (*lvname == '/')
73                     lvname++;
74           if (!strchr(lvname, '/')) {
75                     log_error("--name takes a logical volume name");
76                     return NULL;
77           }
78           if (strncmp(vgname, lvname, strlen(vgname)) ||
79               (lvname += strlen(vgname), *lvname != '/')) {
80                     log_error("Named LV and old PV must be in the same VG");
81                     return NULL;
82           }
83           while (*lvname == '/')
84                     lvname++;
85           if (!*lvname) {
86                     log_error("Incomplete LV name supplied with --name");
87                     return NULL;
88           }
89           return lvname;
90 }
91 
_get_vg(struct cmd_context * cmd,const char * vgname)92 static struct volume_group *_get_vg(struct cmd_context *cmd, const char *vgname)
93 {
94           dev_close_all();
95 
96           return vg_read_for_update(cmd, vgname, NULL, 0);
97 }
98 
99 /* Create list of PVs for allocation of replacement extents */
_get_allocatable_pvs(struct cmd_context * cmd,int argc,char ** argv,struct volume_group * vg,struct physical_volume * pv,alloc_policy_t alloc)100 static struct dm_list *_get_allocatable_pvs(struct cmd_context *cmd, int argc,
101                                                    char **argv, struct volume_group *vg,
102                                                    struct physical_volume *pv,
103                                                    alloc_policy_t alloc)
104 {
105           struct dm_list *allocatable_pvs, *pvht, *pvh;
106           struct pv_list *pvl;
107 
108           if (argc)
109                     allocatable_pvs = create_pv_list(cmd->mem, vg, argc, argv, 1);
110           else
111                     allocatable_pvs = clone_pv_list(cmd->mem, &vg->pvs);
112 
113           if (!allocatable_pvs)
114                     return_NULL;
115 
116           dm_list_iterate_safe(pvh, pvht, allocatable_pvs) {
117                     pvl = dm_list_item(pvh, struct pv_list);
118 
119                     /* Don't allocate onto the PV we're clearing! */
120                     if ((alloc != ALLOC_ANYWHERE) && (pvl->pv->dev == pv_dev(pv))) {
121                               dm_list_del(&pvl->list);
122                               continue;
123                     }
124 
125                     /* Remove PV if full */
126                     if ((pvl->pv->pe_count == pvl->pv->pe_alloc_count))
127                               dm_list_del(&pvl->list);
128           }
129 
130           if (dm_list_empty(allocatable_pvs)) {
131                     log_error("No extents available for allocation");
132                     return NULL;
133           }
134 
135           return allocatable_pvs;
136 }
137 
138 /*
139  * Replace any LV segments on given PV with temporary mirror.
140  * Returns list of LVs changed.
141  */
_insert_pvmove_mirrors(struct cmd_context * cmd,struct logical_volume * lv_mirr,struct dm_list * source_pvl,struct logical_volume * lv,struct dm_list * lvs_changed)142 static int _insert_pvmove_mirrors(struct cmd_context *cmd,
143                                           struct logical_volume *lv_mirr,
144                                           struct dm_list *source_pvl,
145                                           struct logical_volume *lv,
146                                           struct dm_list *lvs_changed)
147 
148 {
149           struct pv_list *pvl;
150           uint32_t prev_le_count;
151 
152           /* Only 1 PV may feature in source_pvl */
153           pvl = dm_list_item(source_pvl->n, struct pv_list);
154 
155           prev_le_count = lv_mirr->le_count;
156           if (!insert_layer_for_segments_on_pv(cmd, lv, lv_mirr, PVMOVE,
157                                                        pvl, lvs_changed))
158                     return_0;
159 
160           /* check if layer was inserted */
161           if (lv_mirr->le_count - prev_le_count) {
162                     lv->status |= LOCKED;
163 
164                     log_verbose("Moving %u extents of logical volume %s/%s",
165                                   lv_mirr->le_count - prev_le_count,
166                                   lv->vg->name, lv->name);
167           }
168 
169           return 1;
170 }
171 
172 /* Create new LV with mirror segments for the required copies */
_set_up_pvmove_lv(struct cmd_context * cmd,struct volume_group * vg,struct dm_list * source_pvl,const char * lv_name,struct dm_list * allocatable_pvs,alloc_policy_t alloc,struct dm_list ** lvs_changed)173 static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
174                                                             struct volume_group *vg,
175                                                             struct dm_list *source_pvl,
176                                                             const char *lv_name,
177                                                             struct dm_list *allocatable_pvs,
178                                                             alloc_policy_t alloc,
179                                                             struct dm_list **lvs_changed)
180 {
181           struct logical_volume *lv_mirr, *lv;
182           struct lv_list *lvl;
183           uint32_t log_count = 0;
184           int lv_found = 0;
185 
186           /* FIXME Cope with non-contiguous => splitting existing segments */
187           if (!(lv_mirr = lv_create_empty("pvmove%d", NULL,
188                                                   LVM_READ | LVM_WRITE,
189                                                   ALLOC_CONTIGUOUS, vg))) {
190                     log_error("Creation of temporary pvmove LV failed");
191                     return NULL;
192           }
193 
194           lv_mirr->status |= (PVMOVE | LOCKED);
195 
196           if (!(*lvs_changed = dm_pool_alloc(cmd->mem, sizeof(**lvs_changed)))) {
197                     log_error("lvs_changed list struct allocation failed");
198                     return NULL;
199           }
200 
201           dm_list_init(*lvs_changed);
202 
203           /* Find segments to be moved and set up mirrors */
204           dm_list_iterate_items(lvl, &vg->lvs) {
205                     lv = lvl->lv;
206                     if ((lv == lv_mirr))
207                               continue;
208                     if (lv_name) {
209                               if (strcmp(lv->name, lv_name))
210                                         continue;
211                               lv_found = 1;
212                     }
213                     if (lv_is_origin(lv) || lv_is_cow(lv)) {
214                               log_print("Skipping snapshot-related LV %s", lv->name);
215                               continue;
216                     }
217                     if (lv->status & MIRRORED) {
218                               log_print("Skipping mirror LV %s", lv->name);
219                               continue;
220                     }
221                     if (lv->status & MIRROR_LOG) {
222                               log_print("Skipping mirror log LV %s", lv->name);
223                               continue;
224                     }
225                     if (lv->status & MIRROR_IMAGE) {
226                               log_print("Skipping mirror image LV %s", lv->name);
227                               continue;
228                     }
229                     if (lv->status & LOCKED) {
230                               log_print("Skipping locked LV %s", lv->name);
231                               continue;
232                     }
233                     if (!_insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv,
234                                                       *lvs_changed))
235                               return_NULL;
236           }
237 
238           if (lv_name && !lv_found) {
239                     log_error("Logical volume %s not found.", lv_name);
240                     return NULL;
241           }
242 
243           /* Is temporary mirror empty? */
244           if (!lv_mirr->le_count) {
245                     log_error("No data to move for %s", vg->name);
246                     return NULL;
247           }
248 
249           if (!lv_add_mirrors(cmd, lv_mirr, 1, 1, 0, log_count,
250                                   allocatable_pvs, alloc, MIRROR_BY_SEG)) {
251                     log_error("Failed to convert pvmove LV to mirrored");
252                     return_NULL;
253           }
254 
255           if (!split_parent_segments_for_layer(cmd, lv_mirr)) {
256                     log_error("Failed to split segments being moved");
257                     return_NULL;
258           }
259 
260           return lv_mirr;
261 }
262 
_activate_lv(struct cmd_context * cmd,struct logical_volume * lv_mirr,unsigned exclusive)263 static int _activate_lv(struct cmd_context *cmd, struct logical_volume *lv_mirr,
264                               unsigned exclusive)
265 {
266           if (exclusive)
267                     return activate_lv_excl(cmd, lv_mirr);
268 
269           return activate_lv(cmd, lv_mirr);
270 }
271 
272 static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg,
273                                 struct logical_volume *lv_mirr,
274                                 struct dm_list *lvs_changed);
275 
_update_metadata(struct cmd_context * cmd,struct volume_group * vg,struct logical_volume * lv_mirr,struct dm_list * lvs_changed,unsigned flags)276 static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg,
277                                   struct logical_volume *lv_mirr,
278                                   struct dm_list *lvs_changed, unsigned flags)
279 {
280           unsigned exclusive = _pvmove_is_exclusive(cmd, vg);
281           unsigned first_time = (flags & PVMOVE_FIRST_TIME) ? 1 : 0;
282           int r = 0;
283 
284           log_verbose("Updating volume group metadata");
285           if (!vg_write(vg)) {
286                     log_error("ABORTING: Volume group metadata update failed.");
287                     return 0;
288           }
289 
290           /* Suspend lvs_changed */
291           if (!suspend_lvs(cmd, lvs_changed))
292                     goto_out;
293 
294           /* Suspend mirrors on subsequent calls */
295           if (!first_time) {
296                     if (!suspend_lv(cmd, lv_mirr)) {
297                               resume_lvs(cmd, lvs_changed);
298                               vg_revert(vg);
299                               goto_out;
300                     }
301           }
302 
303           /* Commit on-disk metadata */
304           if (!vg_commit(vg)) {
305                     log_error("ABORTING: Volume group metadata update failed.");
306                     if (!first_time)
307                               resume_lv(cmd, lv_mirr);
308                     resume_lvs(cmd, lvs_changed);
309                     goto out;
310           }
311 
312           /* Activate the temporary mirror LV */
313           /* Only the first mirror segment gets activated as a mirror */
314           /* FIXME: Add option to use a log */
315           if (first_time) {
316                     if (!_activate_lv(cmd, lv_mirr, exclusive)) {
317                               if (test_mode())
318                                         goto out;
319 
320                               /*
321                                * Nothing changed yet, try to revert pvmove.
322                                */
323                               log_error("Temporary pvmove mirror activation failed.");
324                               if (!_finish_pvmove(cmd, vg, lv_mirr, lvs_changed))
325                                         log_error("ABORTING: Restoring original configuration "
326                                                     "before pvmove failed. Run pvmove --abort.");
327                               goto out;
328                     }
329           } else if (!resume_lv(cmd, lv_mirr)) {
330                     log_error("Unable to reactivate logical volume \"%s\"",
331                                 lv_mirr->name);
332                     resume_lvs(cmd, lvs_changed);
333                     goto out;
334           }
335 
336           /* Unsuspend LVs */
337           if (!resume_lvs(cmd, lvs_changed)) {
338                     log_error("Unable to resume logical volumes");
339                     goto out;
340           }
341 
342           r = 1;
343 out:
344           backup(vg);
345           return r;
346 }
347 
_set_up_pvmove(struct cmd_context * cmd,const char * pv_name,int argc,char ** argv)348 static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
349                                 int argc, char **argv)
350 {
351           const char *lv_name = NULL;
352           char *pv_name_arg;
353           struct volume_group *vg;
354           struct dm_list *source_pvl;
355           struct dm_list *allocatable_pvs;
356           alloc_policy_t alloc;
357           struct dm_list *lvs_changed;
358           struct physical_volume *pv;
359           struct logical_volume *lv_mirr;
360           unsigned first_time = 1;
361           unsigned exclusive;
362           int r = ECMD_FAILED;
363 
364           pv_name_arg = argv[0];
365           argc--;
366           argv++;
367 
368           /* Find PV (in VG) */
369           if (!(pv = find_pv_by_name(cmd, pv_name))) {
370                     stack;
371                     return EINVALID_CMD_LINE;
372           }
373 
374           if (arg_count(cmd, name_ARG)) {
375                     if (!(lv_name = _extract_lvname(cmd, pv_vg_name(pv),
376                                                             arg_value(cmd, name_ARG)))) {
377                               stack;
378                               return EINVALID_CMD_LINE;
379                     }
380 
381                     if (!validate_name(lv_name)) {
382                               log_error("Logical volume name %s is invalid", lv_name);
383                               return EINVALID_CMD_LINE;
384                     }
385           }
386 
387           /* Read VG */
388           log_verbose("Finding volume group \"%s\"", pv_vg_name(pv));
389 
390           vg = _get_vg(cmd, pv_vg_name(pv));
391           if (vg_read_error(vg)) {
392                     vg_release(vg);
393                     stack;
394                     return ECMD_FAILED;
395           }
396 
397           exclusive = _pvmove_is_exclusive(cmd, vg);
398 
399           if ((lv_mirr = find_pvmove_lv(vg, pv_dev(pv), PVMOVE))) {
400                     log_print("Detected pvmove in progress for %s", pv_name);
401                     if (argc || lv_name)
402                               log_error("Ignoring remaining command line arguments");
403 
404                     if (!(lvs_changed = lvs_using_lv(cmd, vg, lv_mirr))) {
405                               log_error("ABORTING: Failed to generate list of moving LVs");
406                               goto out;
407                     }
408 
409                     /* Ensure mirror LV is active */
410                     if (!_activate_lv(cmd, lv_mirr, exclusive)) {
411                               log_error("ABORTING: Temporary mirror activation failed.");
412                               goto out;
413                     }
414 
415                     first_time = 0;
416           } else {
417                     /* Determine PE ranges to be moved */
418                     if (!(source_pvl = create_pv_list(cmd->mem, vg, 1,
419                                                               &pv_name_arg, 0)))
420                               goto_out;
421 
422                     alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
423                     if (alloc == ALLOC_INHERIT)
424                               alloc = vg->alloc;
425 
426                     /* Get PVs we can use for allocation */
427                     if (!(allocatable_pvs = _get_allocatable_pvs(cmd, argc, argv,
428                                                                            vg, pv, alloc)))
429                               goto_out;
430 
431                     if (!archive(vg))
432                               goto_out;
433 
434                     if (!(lv_mirr = _set_up_pvmove_lv(cmd, vg, source_pvl, lv_name,
435                                                               allocatable_pvs, alloc,
436                                                               &lvs_changed)))
437                               goto_out;
438           }
439 
440           /* Lock lvs_changed and activate (with old metadata) */
441           if (!activate_lvs(cmd, lvs_changed, exclusive))
442                     goto_out;
443 
444           /* FIXME Presence of a mirror once set PVMOVE - now remove associated logic */
445           /* init_pvmove(1); */
446           /* vg->status |= PVMOVE; */
447 
448           if (first_time) {
449                     if (!_update_metadata
450                         (cmd, vg, lv_mirr, lvs_changed, PVMOVE_FIRST_TIME))
451                               goto_out;
452           }
453 
454           /* LVs are all in status LOCKED */
455           r = ECMD_PROCESSED;
456 out:
457           unlock_and_release_vg(cmd, vg, pv_vg_name(pv));
458           return r;
459 }
460 
_finish_pvmove(struct cmd_context * cmd,struct volume_group * vg,struct logical_volume * lv_mirr,struct dm_list * lvs_changed)461 static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg,
462                                 struct logical_volume *lv_mirr,
463                                 struct dm_list *lvs_changed)
464 {
465           int r = 1;
466           struct dm_list lvs_completed;
467           struct lv_list *lvl;
468 
469           /* Update metadata to remove mirror segments and break dependencies */
470           dm_list_init(&lvs_completed);
471           if (!lv_remove_mirrors(cmd, lv_mirr, 1, 0, NULL, PVMOVE) ||
472               !remove_layers_for_segments_all(cmd, lv_mirr, PVMOVE,
473                                                       &lvs_completed)) {
474                     log_error("ABORTING: Removal of temporary mirror failed");
475                     return 0;
476           }
477 
478           dm_list_iterate_items(lvl, &lvs_completed)
479                     /* FIXME Assumes only one pvmove at a time! */
480                     lvl->lv->status &= ~LOCKED;
481 
482           /* Store metadata without dependencies on mirror segments */
483           if (!vg_write(vg)) {
484                     log_error("ABORTING: Failed to write new data locations "
485                                 "to disk.");
486                     return 0;
487           }
488 
489           /* Suspend LVs changed */
490           if (!suspend_lvs(cmd, lvs_changed)) {
491                     log_error("Locking LVs to remove temporary mirror failed");
492                     r = 0;
493           }
494 
495           /* Suspend mirror LV to flush pending I/O */
496           if (!suspend_lv(cmd, lv_mirr)) {
497                     log_error("Suspension of temporary mirror LV failed");
498                     r = 0;
499           }
500 
501           /* Store metadata without dependencies on mirror segments */
502           if (!vg_commit(vg)) {
503                     log_error("ABORTING: Failed to write new data locations "
504                                 "to disk.");
505                     vg_revert(vg);
506                     resume_lv(cmd, lv_mirr);
507                     resume_lvs(cmd, lvs_changed);
508                     return 0;
509           }
510 
511           /* Release mirror LV.  (No pending I/O because it's been suspended.) */
512           if (!resume_lv(cmd, lv_mirr)) {
513                     log_error("Unable to reactivate logical volume \"%s\"",
514                                 lv_mirr->name);
515                     r = 0;
516           }
517 
518           /* Unsuspend LVs */
519           resume_lvs(cmd, lvs_changed);
520 
521           /* Deactivate mirror LV */
522           if (!deactivate_lv(cmd, lv_mirr)) {
523                     log_error("ABORTING: Unable to deactivate temporary logical "
524                                 "volume \"%s\"", lv_mirr->name);
525                     r = 0;
526           }
527 
528           log_verbose("Removing temporary pvmove LV");
529           if (!lv_remove(lv_mirr)) {
530                     log_error("ABORTING: Removal of temporary pvmove LV failed");
531                     return 0;
532           }
533 
534           /* Store it on disks */
535           log_verbose("Writing out final volume group after pvmove");
536           if (!vg_write(vg) || !vg_commit(vg)) {
537                     log_error("ABORTING: Failed to write new data locations "
538                                 "to disk.");
539                     return 0;
540           }
541 
542           /* FIXME backup positioning */
543           backup(vg);
544 
545           return r;
546 }
547 
_get_move_vg(struct cmd_context * cmd,const char * name,const char * uuid)548 static struct volume_group *_get_move_vg(struct cmd_context *cmd,
549                                                    const char *name, const char *uuid)
550 {
551           struct physical_volume *pv;
552 
553           /* Reread all metadata in case it got changed */
554           if (!(pv = find_pv_by_name(cmd, name))) {
555                     log_error("ABORTING: Can't reread PV %s", name);
556                     /* What more could we do here? */
557                     return NULL;
558           }
559 
560           return _get_vg(cmd, pv_vg_name(pv));
561 }
562 
563 static struct poll_functions _pvmove_fns = {
564           .get_copy_name_from_lv = get_pvmove_pvname_from_lv_mirr,
565           .get_copy_vg = _get_move_vg,
566           .get_copy_lv = find_pvmove_lv_from_pvname,
567           .poll_progress = poll_mirror_progress,
568           .update_metadata = _update_metadata,
569           .finish_copy = _finish_pvmove,
570 };
571 
pvmove_poll(struct cmd_context * cmd,const char * pv_name,unsigned background)572 int pvmove_poll(struct cmd_context *cmd, const char *pv_name,
573                     unsigned background)
574 {
575           return poll_daemon(cmd, pv_name, NULL, background, PVMOVE, &_pvmove_fns,
576                                  "Moved");
577 }
578 
pvmove(struct cmd_context * cmd,int argc,char ** argv)579 int pvmove(struct cmd_context *cmd, int argc, char **argv)
580 {
581           char *pv_name = NULL;
582           char *colon;
583           int ret;
584 
585           /* dm raid1 target must be present in every case */
586           if (!_pvmove_target_present(cmd, 0)) {
587                     log_error("Required device-mapper target(s) not "
588                                 "detected in your kernel");
589                     return ECMD_FAILED;
590           }
591 
592           if (argc) {
593                     pv_name = argv[0];
594 
595                     /* Drop any PE lists from PV name */
596                     if ((colon = strchr(pv_name, ':'))) {
597                               if (!(pv_name = dm_pool_strndup(cmd->mem, pv_name,
598                                                                  (unsigned) (colon -
599                                                                                  pv_name)))) {
600                                         log_error("Failed to clone PV name");
601                                         return ECMD_FAILED;
602                               }
603                     }
604 
605                     if (!arg_count(cmd, abort_ARG) &&
606                         (ret = _set_up_pvmove(cmd, pv_name, argc, argv)) !=
607                         ECMD_PROCESSED) {
608                               stack;
609                               return ret;
610                     }
611           }
612 
613           return pvmove_poll(cmd, pv_name, arg_is_set(cmd, background_ARG));
614 }
615