]> sourceware.org Git - lvm2.git/commitdiff
Improve the way VGs with PVs missing are handled so manual intervention
authorAlasdair Kergon <agk@redhat.com>
Fri, 19 Sep 2008 06:42:00 +0000 (06:42 +0000)
committerAlasdair Kergon <agk@redhat.com>
Fri, 19 Sep 2008 06:42:00 +0000 (06:42 +0000)
is required in fewer circumstances.  (mornfall)

31 files changed:
WHATS_NEW
daemons/clvmd/lvm-functions.c
doc/example.conf
lib/activate/activate.c
lib/activate/dev_manager.c
lib/commands/toolcontext.c
lib/commands/toolcontext.h
lib/config/defaults.h
lib/display/display.c
lib/format1/disk-rep.h
lib/format1/format1.c
lib/format1/import-export.c
lib/format_text/archiver.c
lib/format_text/flags.c
lib/format_text/import_vsn1.c
lib/locking/cluster_locking.c
lib/locking/locking.h
lib/log/log.c
lib/log/log.h
lib/metadata/metadata-exported.h
lib/metadata/metadata.c
lib/metadata/metadata.h
lib/report/report.c
man/lvm.conf.5
man/vgreduce.8
tools/commands.h
tools/lvmcmdline.c
tools/lvremove.c
tools/pvcreate.c
tools/vgcfgbackup.c
tools/vgreduce.c

index 2a27861b24389338d3869e8a31b2144bc2d28dd6..5abf6dc3520c24eb7b269d51533a28ce573aa771 100644 (file)
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,11 @@
 Version 2.02.40 - 
 ================================
+  In VG with PVs missing, by default allow activation of LVs that are complete.
+  Track PARTIAL_LV and MISSING_PV flags internally.
+  Require --force with --removemissing in vgreduce to remove partial LVs.
+  No longer write out PARTIAL flag into metadata backups.
+  Treat new default activation/missing_stripe_filler "error" as an error target.
+  Remove internal partial_mode.
   Add device/md_chunk_alignment to lvm.conf.
   Pass struct physical_volume to pe_align and adjust for md chunk size.
   Store sysfs location in struct cmd_context.
index 977cc4284cfb25531cc9333b562552373c94d429..c312949aeaa4a6dec2d03a005082110d4016acb1 100644 (file)
@@ -413,9 +413,6 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
                }
        }
 
-       if (lock_flags & LCK_PARTIAL_MODE)
-               init_partial(1);
-
        if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
                init_mirror_in_sync(1);
 
@@ -454,9 +451,6 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
                break;
        }
 
-       if (lock_flags & LCK_PARTIAL_MODE)
-               init_partial(0);
-
        if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
                init_mirror_in_sync(0);
 
index ca85d32a5fc560b08c5a65c5213122ada85e58c6..16cefb2f18e192af840daaf365c68b07eb1a77a6 100644 (file)
@@ -271,11 +271,13 @@ global {
 }
 
 activation {
-    # Device used in place of missing stripes if activating incomplete volume.
-    # For now, you need to set this up yourself first (e.g. with 'dmsetup')
-    # For example, you could make it return I/O errors using the 'error' 
-    # target or make it return zeros.
-    missing_stripe_filler = "/dev/ioerror"
+    # How to fill in missing stripes if activating an incomplete volume.
+    # Using "error" will make inaccessible parts of the device return
+    # I/O errors on access.  You can instead use a device path, in which 
+    # case, that device will be used to in place of missing stripes.
+    # But note that using anything other than "error" with mirrored 
+    # or snapshotted volumes is likely to result in data corruption.
+    missing_stripe_filler = "error"
 
     # How much stack (in KB) to reserve for use while devices suspended
     reserved_stack = 256
index fa1aafd5c0f75e671b738bd971331292befa5903..06954d16e6f6d0a5b0e94b968140040fe8b773c7 100644 (file)
@@ -1027,6 +1027,12 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
                return 0;
        }
 
+       if ((!lv->vg->cmd->partial_activate) && (lv->status & PARTIAL_LV)) {
+               log_error("Refusing activation of partial LV %s. Use --partial to override.",
+                         lv->name);
+               return_0;
+       }
+
        if (test_mode()) {
                _skip("Activating '%s'.", lv->name);
                return 1;
index a081dad73cbaa4efb0a007f5d5878bfde56f1e31..41731922fe900bb0736275affb3a3ed6be886802 100644 (file)
@@ -47,7 +47,6 @@ struct dev_manager {
 
        struct cmd_context *cmd;
 
-       const char *stripe_filler;
        void *target_state;
        uint32_t pvmove_mirror_count;
 
@@ -59,8 +58,6 @@ struct lv_layer {
        const char *old_name;
 };
 
-static const char *stripe_filler = NULL;
-
 static char *_build_dlid(struct dm_pool *mem, const char *lvid, const char *layer)
 {
        char *dlid;
@@ -443,13 +440,6 @@ struct dev_manager *dev_manager_create(struct cmd_context *cmd,
        dm->cmd = cmd;
        dm->mem = mem;
 
-       if (!stripe_filler) {
-               stripe_filler = find_config_tree_str(cmd,
-                                               "activation/missing_stripe_filler",
-                                               DEFAULT_STRIPE_FILLER);
-       }
-       dm->stripe_filler = stripe_filler;
-
        if (!(dm->vg_name = dm_pool_strdup(dm->mem, vg_name)))
                goto_bad;
 
@@ -699,6 +689,68 @@ bad:
        return NULL;
 }
 
+static char *_add_error_device(struct dev_manager *dm, struct dm_tree *dtree,
+                              struct lv_segment *seg, int s)
+{
+       char *id, *name;
+       char errid[32];
+       struct dm_tree_node *node;
+       struct lv_segment *seg_i;
+       int segno = -1, i = 0;;
+       uint64_t size = seg->len * seg->lv->vg->extent_size;
+
+       list_iterate_items(seg_i, &seg->lv->segments) {
+               if (seg == seg_i)
+                       segno = i;
+               ++i;
+       }
+
+       if (segno < 0) {
+               log_error("_add_error_device called with bad segment");
+               return_NULL;
+       }
+
+       sprintf(errid, "missing_%d_%d", segno, s);
+
+       if (!(id = build_dlid(dm, seg->lv->lvid.s, errid))) 
+               return_NULL;
+
+       if (!(name = build_dm_name(dm->mem, seg->lv->vg->name,
+                                  seg->lv->name, errid)))
+               return_NULL;
+       if (!(node = dm_tree_add_new_dev(dtree, name, id, 0, 0, 0, 0, 0)))
+               return_NULL;
+       if (!dm_tree_node_add_error_target(node, size))
+               return_NULL;
+
+       return id;
+}
+
+static int _add_error_area(struct dev_manager *dm, struct dm_tree_node *node,
+                          struct lv_segment *seg, int s)
+{
+       char *dlid;
+       uint64_t extent_size = seg->lv->vg->extent_size;
+
+       if (!strcmp(dm->cmd->stripe_filler, "error")) {
+               /*
+                * FIXME, the tree pointer is first field of dm_tree_node, but
+                * we don't have the struct definition available.
+                */
+               struct dm_tree **tree = (struct dm_tree **) node;
+               dlid = _add_error_device(dm, *tree, seg, s);
+               if (!dlid)
+                       return_0;
+               dm_tree_node_add_target_area(node, NULL, dlid,
+                                            extent_size * seg_le(seg, s));
+       } else {
+               dm_tree_node_add_target_area(node,
+                                            dm->cmd->stripe_filler,
+                                            NULL, UINT64_C(0));
+       }
+       return 1;
+}
+
 int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
                   struct dm_tree_node *node, uint32_t start_area,
                   uint32_t areas)
@@ -712,11 +764,10 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
                     (!seg_pvseg(seg, s) ||
                      !seg_pv(seg, s) ||
                      !seg_dev(seg, s))) ||
-                   (seg_type(seg, s) == AREA_LV && !seg_lv(seg, s)))
-                       dm_tree_node_add_target_area(node,
-                                                       dm->stripe_filler,
-                                                       NULL, UINT64_C(0));
-               else if (seg_type(seg, s) == AREA_PV)
+                   (seg_type(seg, s) == AREA_LV && !seg_lv(seg, s))) {
+                       if (!_add_error_area(dm, node, seg, s))
+                               return_0;
+               } else if (seg_type(seg, s) == AREA_PV)
                        dm_tree_node_add_target_area(node,
                                                        dev_name(seg_dev(seg, s)),
                                                        NULL,
index cbf63df459c57f2fc3861f63d69d766b5f6f4e20..8f89fee3673dbd21c90b64d96583ef8d9763b1b0 100644 (file)
@@ -197,6 +197,7 @@ static int _process_config(struct cmd_context *cmd)
 {
        mode_t old_umask;
        const char *read_ahead;
+       struct stat st;
 
        /* umask */
        cmd->default_settings.umask = find_config_tree_int(cmd,
@@ -263,6 +264,24 @@ static int _process_config(struct cmd_context *cmd)
                return 0;
        }
 
+       cmd->stripe_filler = find_config_tree_str(cmd,
+                                                 "activation/missing_stripe_filler",
+                                                 DEFAULT_STRIPE_FILLER);
+       if (strcmp(cmd->stripe_filler, "error")) {
+               if (stat(cmd->stripe_filler, &st)) {
+                       log_warn("WARNING: activation/missing_stripe_filler = \"%s\" "
+                                "is invalid,", cmd->stripe_filler);
+                       log_warn("         stat failed: %s", strerror(errno));
+                       log_warn("Falling back to \"error\" missing_stripe_filler.");
+                       cmd->stripe_filler = "error";
+               } else if (!S_ISBLK(st.st_mode)) {
+                       log_warn("WARNING: activation/missing_stripe_filler = \"%s\" "
+                                "is not a block device.", cmd->stripe_filler);
+                       log_warn("Falling back to \"error\" missing_stripe_filler.");
+                       cmd->stripe_filler = "error";
+               }
+       }
+
        return 1;
 }
 
@@ -981,6 +1000,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static,
        cmd->args = the_args;
        cmd->is_static = is_static;
        cmd->is_long_lived = is_long_lived;
+       cmd->handles_missing_pvs = 0;
        cmd->hosttags = 0;
        list_init(&cmd->formats);
        list_init(&cmd->segtypes);
index 0d9d844fb638173aa257209dbf77093e3437e05c..8f6cfc7a8328f0fda227596b59202cd54eb0c8b3 100644 (file)
@@ -66,8 +66,10 @@ struct cmd_context {
        struct command *command;
        struct arg *args;
        char **argv;
-       unsigned is_static;     /* Static binary? */
-       unsigned is_long_lived; /* Optimises persistent_filter handling */
+       unsigned is_static:1;   /* Static binary? */
+       unsigned is_long_lived:1;       /* Optimises persistent_filter handling */
+       unsigned handles_missing_pvs:1;
+       unsigned partial_activate:1;
 
        struct dev_filter *filter;
        int dump_filter;        /* Dump filter when exiting? */
@@ -81,6 +83,7 @@ struct cmd_context {
 
        struct archive_params *archive_params;
        struct backup_params *backup_params;
+       const char *stripe_filler;
 
        /* List of defined tags */
        struct list tags;
index 9566c6ea23facf495a3d4cb4ecb2a3bf41b6a408..605bc497576c18e711e16f46d816695b24e99561 100644 (file)
@@ -92,7 +92,7 @@
 #  define DEFAULT_ACTIVATION 0
 #endif
 
-#define DEFAULT_STRIPE_FILLER "/dev/ioerror"
+#define DEFAULT_STRIPE_FILLER "error"
 #define DEFAULT_MIRROR_REGION_SIZE 512 /* KB */
 #define DEFAULT_INTERVAL 15
 
index 6f8bdebde27bed8968223498b56da44bbd1968c7..d9358fb8f8e2eb8a09da62b87449d1d1df56ae6e 100644 (file)
@@ -578,10 +578,7 @@ void vgdisplay_full(const struct volume_group *vg)
        struct lv_list *lvl;
        char uuid[64] __attribute((aligned(8)));
 
-       if (vg->status & PARTIAL_VG)
-               active_pvs = list_size(&vg->pvs);
-       else
-               active_pvs = vg->pv_count;
+       active_pvs = vg->pv_count - vg_missing_pv_count(vg);
 
        log_print("--- Volume group ---");
        log_print("VG Name               %s", vg->name);
@@ -664,10 +661,7 @@ void vgdisplay_colons(const struct volume_group *vg)
        const char *access;
        char uuid[64] __attribute((aligned(8)));
 
-       if (vg->status & PARTIAL_VG)
-               active_pvs = list_size(&vg->pvs);
-       else
-               active_pvs = vg->pv_count;
+       active_pvs = vg->pv_count - vg_missing_pv_count(vg);
 
        list_iterate_items(lvl, &vg->lvs)
                if (lv_is_visible(lvl->lv) && !(lvl->lv->status & SNAPSHOT))
index 9a04c7b8da51a6becda5fc594550b884e4c749d4..0ef57190f97ce6f5868af53d1b0eced901d63933 100644 (file)
@@ -212,7 +212,7 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem,
              struct pv_disk *pvd, struct physical_volume *pv);
 
 int import_vg(struct dm_pool *mem,
-             struct volume_group *vg, struct disk_list *dl, int partial);
+             struct volume_group *vg, struct disk_list *dl);
 int export_vg(struct vg_disk *vgd, struct volume_group *vg);
 
 int import_lv(struct dm_pool *mem, struct logical_volume *lv, struct lv_disk *lvd);
index b38cf6f3ebe9e75a621d4477a591efb0c2686698..342079147849384d72d2bc4d52b89232592ab7de 100644 (file)
@@ -23,7 +23,7 @@
 #include "segtype.h"
 
 /* VG consistency checks */
-static int _check_vgs(struct list *pvs, int *partial)
+static int _check_vgs(struct list *pvs)
 {
        struct list *pvh, *t;
        struct disk_list *dl = NULL;
@@ -33,8 +33,6 @@ static int _check_vgs(struct list *pvs, int *partial)
        uint32_t exported = 0;
        int first_time = 1;
 
-       *partial = 0;
-
        /*
         * If there are exported and unexported PVs, ignore exported ones.
         * This means an active VG won't be affected if disks are inserted
@@ -98,10 +96,6 @@ static int _check_vgs(struct list *pvs, int *partial)
                                  dl->vgd.pe_total, dl->vgd.pe_allocated,
                                  dl->vgd.pvg_total);
                        list_del(pvh);
-                       if (partial_mode()) {
-                               *partial = 1;
-                               continue;
-                       }
                        return 0;
                }
                pv_count++;
@@ -111,9 +105,6 @@ static int _check_vgs(struct list *pvs, int *partial)
        if (pv_count != first->vgd.pv_cur) {
                log_error("%d PV(s) found for VG %s: expected %d",
                          pv_count, first->pvd.vg_name, first->vgd.pv_cur);
-               if (!partial_mode())
-                       return 0;
-               *partial = 1;
        }
 
        return 1;
@@ -125,7 +116,6 @@ static struct volume_group *_build_vg(struct format_instance *fid,
        struct dm_pool *mem = fid->fmt->cmd->mem;
        struct volume_group *vg = dm_pool_alloc(mem, sizeof(*vg));
        struct disk_list *dl;
-       int partial;
 
        if (!vg)
                goto_bad;
@@ -142,12 +132,12 @@ static struct volume_group *_build_vg(struct format_instance *fid,
        list_init(&vg->lvs);
        list_init(&vg->tags);
 
-       if (!_check_vgs(pvs, &partial))
+       if (!_check_vgs(pvs))
                goto_bad;
 
        dl = list_item(pvs->n, struct disk_list);
 
-       if (!import_vg(mem, vg, dl, partial))
+       if (!import_vg(mem, vg, dl))
                goto_bad;
 
        if (!import_pvs(fid->fmt, mem, vg, pvs, &vg->pvs, &vg->pv_count))
index 4bb51160254a5a728116b9bc8996f4da2b86ef0c..c80011d9345de28c794ef72a96e1f39eb6df1cf4 100644 (file)
@@ -214,7 +214,7 @@ int export_pv(struct cmd_context *cmd, struct dm_pool *mem __attribute((unused))
 }
 
 int import_vg(struct dm_pool *mem,
-             struct volume_group *vg, struct disk_list *dl, int partial)
+             struct volume_group *vg, struct disk_list *dl)
 {
        struct vg_disk *vgd = &dl->vgd;
        memcpy(vg->id.uuid, vgd->vg_uuid, ID_LEN);
@@ -236,10 +236,10 @@ int import_vg(struct dm_pool *mem,
        if (vgd->vg_status & VG_EXTENDABLE)
                vg->status |= RESIZEABLE_VG;
 
-       if (partial || (vgd->vg_access & VG_READ))
+       if (vgd->vg_access & VG_READ)
                vg->status |= LVM_READ;
 
-       if (!partial && (vgd->vg_access & VG_WRITE))
+       if (vgd->vg_access & VG_WRITE)
                vg->status |= LVM_WRITE;
 
        if (vgd->vg_access & VG_CLUSTERED)
@@ -255,9 +255,6 @@ int import_vg(struct dm_pool *mem,
        vg->max_pv = vgd->pv_max;
        vg->alloc = ALLOC_NORMAL;
 
-       if (partial)
-               vg->status |= PARTIAL_VG;
-
        return 1;
 }
 
index 1d2c5ededf83f4ab528dadcf0e1555d46261d206..e54535c97e1ad6810d5c6da13e931ff547549e75 100644 (file)
@@ -134,10 +134,8 @@ int archive_display(struct cmd_context *cmd, const char *vg_name)
 {
        int r1, r2;
 
-       init_partial(1);
        r1 = archive_list(cmd, cmd->archive_params->dir, vg_name);
        r2 = backup_list(cmd, cmd->backup_params->dir, vg_name);
-       init_partial(0);
 
        return r1 && r2;
 }
@@ -146,9 +144,7 @@ int archive_display_file(struct cmd_context *cmd, const char *file)
 {
        int r;
 
-       init_partial(1);
        r = archive_list_file(cmd, file);
-       init_partial(0);
 
        return r;
 }
@@ -393,7 +389,7 @@ void check_current_backup(struct volume_group *vg)
        char path[PATH_MAX];
        struct volume_group *vg_backup;
 
-       if ((vg->status & PARTIAL_VG) || (vg->status & EXPORTED_VG))
+       if (vg->status & EXPORTED_VG)
                return;
 
        if (dm_snprintf(path, sizeof(path), "%s/%s",
index 868542425449f197bc18152937e1aa567a7e81de..eb281b6b1fa3335ba9b3d254902a8d7261ea022c 100644 (file)
@@ -31,12 +31,12 @@ struct flag {
 static struct flag _vg_flags[] = {
        {EXPORTED_VG, "EXPORTED", STATUS_FLAG},
        {RESIZEABLE_VG, "RESIZEABLE", STATUS_FLAG},
-       {PARTIAL_VG, "PARTIAL", STATUS_FLAG},
        {PVMOVE, "PVMOVE", STATUS_FLAG},
        {LVM_READ, "READ", STATUS_FLAG},
        {LVM_WRITE, "WRITE", STATUS_FLAG},
        {CLUSTERED, "CLUSTERED", STATUS_FLAG},
        {SHARED, "SHARED", STATUS_FLAG},
+       {PARTIAL_VG, NULL, 0},
        {PRECOMMITTED, NULL, 0},
        {0, NULL, 0}
 };
@@ -44,6 +44,7 @@ static struct flag _vg_flags[] = {
 static struct flag _pv_flags[] = {
        {ALLOCATABLE_PV, "ALLOCATABLE", STATUS_FLAG},
        {EXPORTED_VG, "EXPORTED", STATUS_FLAG},
+       {MISSING_PV, "MISSING", COMPATIBLE_FLAG},
        {0, NULL, 0}
 };
 
@@ -62,6 +63,8 @@ static struct flag _lv_flags[] = {
        {SNAPSHOT, NULL, 0},
        {ACTIVATE_EXCL, NULL, 0},
        {CONVERTING, NULL, 0},
+       {PARTIAL_LV, NULL, 0},
+       {POSTORDER_FLAG, NULL, 0},
        {0, NULL, 0}
 };
 
@@ -155,7 +158,16 @@ int read_flags(uint32_t *status, int type, struct config_value *cv)
                                break;
                        }
 
-               if (!flags[f].description && (type & STATUS_FLAG)) {
+               if (type == VG_FLAGS && !strcmp(cv->v.str, "PARTIAL")) {
+                       /*
+                        * Exception: We no longer write this flag out, but it
+                        * might be encountered in old backup files, so restore
+                        * it in that case. It is never part of live metadata
+                        * though, so only vgcfgrestore needs to be concerned
+                        * by this case.
+                        */
+                       s |= PARTIAL_VG;
+               } else if (!flags[f].description && (type & STATUS_FLAG)) {
                        log_err("Unknown status flag '%s'.", cv->v.str);
                        return 0;
                }
index f32573a996f8e521441e39a194a45b4fe1db509f..653be29d392fc6d6ca6a48233964f3fdd526b4c4 100644 (file)
@@ -194,11 +194,6 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
                else
                        log_error("Couldn't find device with uuid '%s'.",
                                  buffer);
-
-               if (partial_mode())
-                       vg->status |= PARTIAL_VG;
-               else
-                       return 0;
        }
 
        if (!(pv->vg_name = dm_pool_strdup(mem, vg->name)))
@@ -211,6 +206,9 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
                return 0;
        }
 
+       if (!pv->dev)
+               pv->status |= MISSING_PV;
+
        /* Late addition */
        _read_int64(pvn, "dev_size", &pv->size);
 
@@ -800,11 +798,6 @@ static struct volume_group *_read_vg(struct format_instance *fid,
 
        dm_hash_destroy(pv_hash);
 
-       if (vg->status & PARTIAL_VG) {
-               vg->status &= ~LVM_WRITE;
-               vg->status |= LVM_READ;
-       }
-
        /*
         * Finished.
         */
index 3cbc9de9e6a7fd883e3eddc9ee9fc32a2db49afb..94b39de5a2a0a9aa31ecaa7a3b9eb82cd35d9cc8 100644 (file)
@@ -315,9 +315,6 @@ static int _lock_for_cluster(unsigned char cmd, uint32_t flags, const char *name
        args[0] = flags & 0x7F; /* Maskoff lock flags */
        args[1] = flags & 0xC0; /* Bitmap flags */
 
-       if (partial_mode())
-               args[1] |= LCK_PARTIAL_MODE;
-
        if (mirror_in_sync())
                args[1] |= LCK_MIRROR_NOSYNC_MODE;
 
index 6a34a6d3a58fe74284b5c2511b89a16cdb344521..c900e54fa58d7f793a4f43512a4b6afd00a4dbfe 100644 (file)
@@ -83,7 +83,6 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
 /*
  * Additional lock bits for cluster communication
  */
-#define LCK_PARTIAL_MODE       0x00000001U     /* Running in partial mode */
 #define LCK_MIRROR_NOSYNC_MODE 0x00000002U     /* Mirrors don't require sync */
 #define LCK_DMEVENTD_MONITOR_MODE      0x00000004U     /* Register with dmeventd */
 
index 78686817015a78d0802509f0428be486ef416824..c8b80a281c9c9517421aea8a6ad59afda964fb20 100644 (file)
@@ -29,7 +29,6 @@ static struct str_list _log_dev_alias;
 
 static int _verbose_level = VERBOSE_BASE_LEVEL;
 static int _test = 0;
-static int _partial = 0;
 static int _md_filtering = 0;
 static int _pvmove = 0;
 static int _full_scan_done = 0;        /* Restrict to one full scan during each cmd */
@@ -154,11 +153,6 @@ void init_test(int level)
        _test = level;
 }
 
-void init_partial(int level)
-{
-       _partial = level;
-}
-
 void init_md_filtering(int level)
 {
        _md_filtering = level;
@@ -254,11 +248,6 @@ int test_mode()
        return _test;
 }
 
-int partial_mode()
-{
-       return _partial;
-}
-
 int md_filtering()
 {
        return _md_filtering;
index 8b85758bf2842f7e3b936ccfe089af2f283faa8f..133b170a84a83ab3fba13606783ccc9e42b5a110 100644 (file)
@@ -64,7 +64,6 @@ void fin_syslog(void);
 
 void init_verbose(int level);
 void init_test(int level);
-void init_partial(int level);
 void init_md_filtering(int level);
 void init_pvmove(int level);
 void init_full_scan_done(int level);
@@ -84,7 +83,6 @@ void init_error_message_produced(int error_message_produced);
 void set_cmd_name(const char *cmd_name);
 
 int test_mode(void);
-int partial_mode(void);
 int md_filtering(void);
 int pvmove_mode(void);
 int full_scan_done(void);
index 280646a28b29ced150e76e6515ea0c9bf8656961..6cdfdb4ae1c96c7f1f5246c8d0c9daac3ff4577c 100644 (file)
@@ -71,6 +71,13 @@ struct pv_segment;
 //#define PRECOMMITTED         0x00200000U     /* VG - internal use only */
 #define CONVERTING             0x00400000U     /* LV */
 
+#define MISSING_PV              0x00800000U    /* PV */
+#define PARTIAL_LV              0x01000000U    /* LV - derived flag, not
+                                                  written out in metadata*/
+
+//#define POSTORDER_FLAG       0x02000000U /* Not a real flag, reserved for
+//                                            temporary use inside vg_read. */
+
 #define LVM_READ               0x00000100U     /* LV VG */
 #define LVM_WRITE              0x00000200U     /* LV VG */
 #define CLUSTERED              0x00000400U     /* VG */
@@ -564,6 +571,7 @@ uint64_t pv_pe_start(const pv_t *pv);
 uint32_t pv_pe_count(const pv_t *pv);
 uint32_t pv_pe_alloc_count(const pv_t *pv);
 
+int vg_missing_pv_count(const vg_t *vg);
 uint32_t vg_status(const vg_t *vg);
 #define vg_is_clustered(vg) (vg_status((vg)) & CLUSTERED)
 
index ecf4152a32693d7dc88903fab5887ef0c2303811..e9e944c5dba8a21345d8b0f234b3703289cbafe8 100644 (file)
@@ -334,9 +334,9 @@ int vg_remove_single(struct cmd_context *cmd, const char *vg_name,
        struct pv_list *pvl;
        int ret = 1;
 
-       if (!vg || !consistent || (vg_status(vg) & PARTIAL_VG)) {
-               log_error("Volume group \"%s\" not found or inconsistent.",
-                         vg_name);
+       if (!vg || !consistent || vg_missing_pv_count(vg)) {
+               log_error("Volume group \"%s\" not found, is inconsistent "
+                         "or has PVs missing.", vg_name);
                log_error("Consider vgreduce --removemissing if metadata "
                          "is inconsistent.");
                return 0;
@@ -488,19 +488,15 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
        struct volume_group *vg;
        struct dm_pool *mem = cmd->mem;
        int consistent = 0;
-       int old_partial;
 
        if (!(vg = dm_pool_zalloc(mem, sizeof(*vg))))
                return_NULL;
 
        /* is this vg name already in use ? */
-       old_partial = partial_mode();
-       init_partial(1);
        if (vg_read(cmd, vg_name, NULL, &consistent)) {
                log_err("A volume group called '%s' already exists.", vg_name);
                goto bad;
        }
-       init_partial(old_partial);
 
        if (!id_create(&vg->id)) {
                log_err("Couldn't create uuid for volume group '%s'.", vg_name);
@@ -1191,6 +1187,157 @@ int vgs_are_compatible(struct cmd_context *cmd __attribute((unused)),
        return 1;
 }
 
+struct _lv_postorder_baton {
+       int (*fn)(struct logical_volume *lv, void *data);
+       void *data;
+};
+
+static int _lv_postorder_visit(struct logical_volume *,
+                              int (*fn)(struct logical_volume *lv, void *data),
+                              void *data);
+
+static int _lv_postorder_level(struct logical_volume *lv, void *data)
+{
+       struct _lv_postorder_baton *baton = data;
+       int r =_lv_postorder_visit(lv, baton->fn, baton->data);
+       lv->status |= POSTORDER_FLAG;
+       return r;
+};
+
+static int _lv_each_dependency(struct logical_volume *lv,
+                              int (*fn)(struct logical_volume *lv, void *data),
+                              void *data)
+{
+       int i, s;
+       struct lv_segment *lvseg;
+
+       struct logical_volume *deps[] = {
+               lv->snapshot ? lv->snapshot->origin : 0,
+               lv->snapshot ? lv->snapshot->cow : 0 };
+       for (i = 0; i < sizeof(deps) / sizeof(*deps); ++i) {
+               if (deps[i] && !fn(deps[i], data))
+                       return_0;
+       }
+
+       list_iterate_items(lvseg, &lv->segments) {
+               if (lvseg->log_lv && !fn(lvseg->log_lv, data))
+                       return_0;
+               for (s = 0; s < lvseg->area_count; ++s) {
+                       if (seg_type(lvseg, s) == AREA_LV && !fn(seg_lv(lvseg,s), data))
+                               return_0;
+               }
+       }
+       return 1;
+}
+
+static int _lv_postorder_cleanup(struct logical_volume *lv, void *data)
+{
+       if (!(lv->status & POSTORDER_FLAG))
+               return 1;
+       lv->status &= ~POSTORDER_FLAG;
+
+       if (!_lv_each_dependency(lv, _lv_postorder_cleanup, data))
+               return_0;
+       return 1;
+}
+
+static int _lv_postorder_visit(struct logical_volume *lv,
+                              int (*fn)(struct logical_volume *lv, void *data),
+                              void *data)
+{
+       struct _lv_postorder_baton baton;
+       int r;
+
+       if (lv->status & POSTORDER_FLAG)
+               return 1;
+
+       baton.fn = fn;
+       baton.data = data;
+       r = _lv_each_dependency(lv, _lv_postorder_level, &baton);
+       if (r) {
+               r = fn(lv, data);
+               log_verbose("visited %s", lv->name);
+       }
+       return r;
+}
+
+/*
+ * This will walk the LV dependency graph in depth-first order and in the
+ * postorder, call a callback function "fn". The void *data is passed along all
+ * the calls. The callback may return zero to indicate an error and terminate
+ * the depth-first walk. The error is propagated to return value of
+ * _lv_postorder.
+ */
+static int _lv_postorder(struct logical_volume *lv,
+                              int (*fn)(struct logical_volume *lv, void *data),
+                              void *data)
+{
+       int r;
+       r = _lv_postorder_visit(lv, fn, data);
+       _lv_postorder_cleanup(lv, 0);
+       return r;
+}
+
+struct _lv_mark_if_partial_baton {
+       int partial;
+};
+
+static int _lv_mark_if_partial_collect(struct logical_volume *lv, void *data)
+{
+       struct _lv_mark_if_partial_baton *baton = data;
+       if (lv->status & PARTIAL_LV)
+               baton->partial = 1;
+
+       return 1;
+}
+
+static int _lv_mark_if_partial_single(struct logical_volume *lv, void *data)
+{
+       int s;
+       struct _lv_mark_if_partial_baton baton;
+       struct lv_segment *lvseg;
+
+       list_iterate_items(lvseg, &lv->segments) {
+               for (s = 0; s < lvseg->area_count; ++s) {
+                       if (seg_type(lvseg, s) == AREA_PV) {
+                               if (seg_pv(lvseg, s)->status & MISSING_PV)
+                                       lv->status |= PARTIAL_LV;
+                       }
+               }
+       }
+
+       baton.partial = 0;
+       _lv_each_dependency(lv, _lv_mark_if_partial_collect, &baton);
+
+       if (baton.partial)
+               lv->status |= PARTIAL_LV;
+
+       return 1;
+}
+
+static int _lv_mark_if_partial(struct logical_volume *lv)
+{
+       return _lv_postorder(lv, _lv_mark_if_partial_single, NULL);
+}
+
+/*
+ * Mark LVs with missing PVs using PARTIAL_LV status flag. The flag is
+ * propagated transitively, so LVs referencing other LVs are marked
+ * partial as well, if any of their referenced LVs are marked partial.
+ */
+static int _vg_mark_partial_lvs(struct volume_group *vg)
+{
+       struct logical_volume *lv;
+       struct lv_list *lvl;
+
+       list_iterate_items(lvl, &vg->lvs) {
+               lv = lvl->lv;
+               if (!_lv_mark_if_partial(lv))
+                       return_0;
+       }
+       return 1;
+}
+
 int vg_validate(struct volume_group *vg)
 {
        struct pv_list *pvl, *pvl2;
@@ -1295,8 +1442,13 @@ int vg_write(struct volume_group *vg)
                return_0;
 
        if (vg->status & PARTIAL_VG) {
-               log_error("Cannot change metadata for partial volume group %s",
-                         vg->name);
+               log_error("Cannot update partial volume group %s.", vg->name);
+               return 0;
+       }
+
+       if (vg_missing_pv_count(vg) && !vg->cmd->handles_missing_pvs) {
+               log_error("Cannot update volume group %s while physical "
+                         "volumes are missing.", vg->name);
                return 0;
        }
 
@@ -1495,9 +1647,20 @@ static int _update_pv_list(struct list *all_pvs, struct volume_group *vg)
        return 1;
 }
 
+int vg_missing_pv_count(const vg_t *vg)
+{
+       int ret = 0;
+       struct pv_list *pvl;
+       list_iterate_items(pvl, &vg->pvs) {
+               if (pvl->pv->status & MISSING_PV)
+                       ++ ret;
+       }
+       return ret;
+}
+
 /* Caller sets consistent to 1 if it's safe for vg_read to correct
  * inconsistent metadata on disk (i.e. the VG write lock is held).
- * This guarantees only consistent metadata is returned unless PARTIAL_VG.
+ * This guarantees only consistent metadata is returned.
  * If consistent is 0, caller must check whether consistent == 1 on return
  * and take appropriate action if it isn't (e.g. abort; get write lock
  * and call vg_read again).
@@ -1536,6 +1699,11 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
        }
 
        if ((correct_vg = lvmcache_get_vg(vgid, precommitted))) {
+               if (vg_missing_pv_count(correct_vg)) {
+                       log_verbose("There are %d physical volumes missing.",
+                                   vg_missing_pv_count(correct_vg));
+                       _vg_mark_partial_lvs(correct_vg);
+               }
                *consistent = 1;
                return correct_vg;
        }
@@ -1631,7 +1799,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                        }
                }
 
-               if (list_size(&correct_vg->pvs) != list_size(pvids)) {
+               if (list_size(&correct_vg->pvs) != list_size(pvids)
+                   + vg_missing_pv_count(correct_vg)) {
                        log_debug("Cached VG %s had incorrect PV list",
                                  vgname);
 
@@ -1640,6 +1809,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                        else
                                correct_vg = NULL;
                } else list_iterate_items(pvl, &correct_vg->pvs) {
+                       if (pvl->pv->status & MISSING_PV)
+                               continue;
                        if (!str_list_match_item(pvids, pvl->pv->dev->pvid)) {
                                log_debug("Cached VG %s had incorrect PV list",
                                          vgname);
@@ -1722,15 +1893,6 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                if (!*consistent)
                        return correct_vg;
 
-               /* Don't touch partial volume group metadata */
-               /* Should be fixed manually with vgcfgbackup/restore etc. */
-               if ((correct_vg->status & PARTIAL_VG)) {
-                       log_error("Inconsistent metadata copies found for "
-                                 "partial volume group %s", vgname);
-                       *consistent = 0;
-                       return correct_vg;
-               }
-
                /* Don't touch if vgids didn't match */
                if (inconsistent_vgid) {
                        log_error("Inconsistent metadata UUIDs found for "
@@ -1769,6 +1931,12 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
                }
        }
 
+       if (vg_missing_pv_count(correct_vg)) {
+               log_verbose("There are %d physical volumes missing.",
+                           vg_missing_pv_count(correct_vg));
+               _vg_mark_partial_lvs(correct_vg);
+       }
+
        if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {
                log_error("WARNING: Interrupted pvmove detected in "
                          "volume group %s", correct_vg->name);
@@ -1828,11 +1996,10 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
                if ((vg = _vg_read(cmd, NULL, vgid,
                                   &consistent, precommitted)) &&
                    !strncmp((char *)vg->id.uuid, vgid, ID_LEN)) {
+
                        if (!consistent) {
                                log_error("Volume group %s metadata is "
                                          "inconsistent", vg->name);
-                               if (!partial_mode())
-                                       return NULL;
                        }
                        return vg;
                }
@@ -1860,6 +2027,7 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
                if ((vg = _vg_read(cmd, vgname, vgid, &consistent,
                                   precommitted)) &&
                    !strncmp((char *)vg->id.uuid, vgid, ID_LEN)) {
+
                        if (!consistent) {
                                log_error("Volume group %s metadata is "
                                          "inconsistent", vgname);
@@ -1993,7 +2161,6 @@ static int _get_pvs(struct cmd_context *cmd, struct list **pvslist)
        struct list *vgids;
        struct volume_group *vg;
        int consistent = 0;
-       int old_partial;
        int old_pvmove;
 
        lvmcache_label_scan(cmd, 0);
@@ -2015,9 +2182,7 @@ static int _get_pvs(struct cmd_context *cmd, struct list **pvslist)
 
        /* Read every VG to ensure cache consistency */
        /* Orphan VG is last on list */
-       old_partial = partial_mode();
        old_pvmove = pvmove_mode();
-       init_partial(1);
        init_pvmove(1);
        list_iterate_items(strl, vgids) {
                vgid = strl->str;
@@ -2042,7 +2207,6 @@ static int _get_pvs(struct cmd_context *cmd, struct list **pvslist)
                                list_add(results, pvh);
        }
        init_pvmove(old_pvmove);
-       init_partial(old_partial);
 
        if (pvslist)
                *pvslist = results;
index e5538b91db5403d4d50daf12b54733317ab5c036..6d12653b6e84bceeadd96e2e782c457533e88cee 100644 (file)
 //#define MIRROR_NOTSYNCED     0x00080000U     /* LV */
 #define ACTIVATE_EXCL          0x00100000U     /* LV - internal use only */
 #define PRECOMMITTED           0x00200000U     /* VG - internal use only */
+//#define CONVERTING           0x00400000U     /* LV */
+
+//#define MISSING_PV           0x00800000U     /* PV */
+//#define PARTIAL_LV           0x01000000U     /* LV - derived flag, not
+//                                                written out in metadata*/
+
+#define POSTORDER_FLAG         0x02000000U /* Not a real flag, reserved for
+                                              temporary use inside vg_read. */
 
 //#define LVM_READ                     0x00000100U     /* LV VG */
 //#define LVM_WRITE                    0x00000200U     /* LV VG */
index 70e25aec7f1ab77866a0d0b1161a977d4ed5b56c..a34d61746fadd5489016b8a3d11445f700239729 100644 (file)
@@ -439,7 +439,7 @@ static int _vgstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_
        else
                repstr[2] = '-';
 
-       if (vg->status & PARTIAL_VG)
+       if (vg_missing_pv_count(vg))
                repstr[3] = 'p';
        else
                repstr[3] = '-';
index 0bb1972456271f62e13e137b2984195eeff90606..47666b4e7fb97fd0f13418c258928c301dc42954 100644 (file)
@@ -300,12 +300,16 @@ in \fBlvm\fP (8).
 .TP
 \fBactivation\fP \(em Settings affecting device-mapper activation
 .IP
-\fBmissing_stripe_filler\fP \(em When activating an incomplete
-logical volume in partial mode, this missing data is replaced
-with this device.  It could perhaps be a block device that always
-returns an error when it is accessed, or one that always
-returns zeros.  See \fBlvcreate\fP (8) for how to create
-such devices.
+\fBmissing_stripe_filler\fP \(em When activating an incomplete logical
+volume in partial mode, this option dictates how the missing data is
+replaced.  A value of "error" will cause activation to create error
+mappings for the missing data, meaning that read access to missing
+portions of the volume will result in I/O errors. You can instead also
+use a device path, and in that case this device will be used in place of
+missing stripes. However, note that using anything other than
+"error" with mirrored or snapshotted volumes is likely to result in data
+corruption.  For instructions on how to create a device that always
+returns zeros, see \fBlvcreate\fP (8).
 .IP
 \fBmirror_region_size\fP \(em Unit size in KB for copy operations
 when mirroring.
index 8f4fe1b7ae617a56d6cf44e4cb0cab216e7e28d4..a382454d76bea9195a463a7b205de57b32ae2674 100644 (file)
@@ -18,11 +18,13 @@ See \fBlvm\fP for common options.
 Removes all empty physical volumes if none are given on command line.
 .TP
 .I \-\-removemissing
-Removes all missing physical volumes from the volume group and makes 
-the volume group consistent again.  
+Removes all missing physical volumes from the volume group, if there are no
+logical volumes allocated on those. This resumes normal operation of the volume
+group (new logical volumes may again be created, changed and so on).
 
-It's a good idea to run this option with --test first to find out what it 
-would remove before running it for real.  
+If this is not possible (there are logical volumes referencing the missing
+physical volumes) and you cannot or do not want to remove them manually, you
+can run this option with --force to have vgreduce remove any partial LVs.
 
 Any logical volumes and dependent snapshots that were partly on the 
 missing disks get removed completely. This includes those parts 
index fddc6a33e298fc578c77fa23e67c0afb21c8e705..7121a76461b40f9320a34e64507d5db69a99eb66 100644 (file)
@@ -850,13 +850,15 @@ xx(vgreduce,
    "\t[-h|--help]\n"
    "\t[--mirrorsonly]\n"
    "\t[--removemissing]\n"
+   "\t[-f|--force]\n"
    "\t[-t|--test]\n"
    "\t[-v|--verbose]\n"
    "\t[--version]" "\n"
    "\tVolumeGroupName\n"
    "\t[PhysicalVolumePath...]\n",
 
-   all_ARG, autobackup_ARG, mirrorsonly_ARG, removemissing_ARG, test_ARG)
+   all_ARG, autobackup_ARG, mirrorsonly_ARG, removemissing_ARG,
+   force_ARG, test_ARG)
 
 xx(vgremove,
    "Remove volume group(s)",
index e97cf65db36de4b770ec9ef223443795a935b894..c50641663a1db6618188bf9a7dd28717f5b70f9d 100644 (file)
@@ -710,13 +710,13 @@ static int _get_settings(struct cmd_context *cmd)
        cmd->current_settings.archive = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.archive);
        cmd->current_settings.backup = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.backup);
        cmd->current_settings.cache_vgmetadata = cmd->command->flags & CACHE_VGMETADATA ? 1 : 0;
+       cmd->partial_activate = 0;
 
        if (arg_count(cmd, partial_ARG)) {
-               init_partial(1);
+               cmd->partial_activate = 1;
                log_print("Partial mode. Incomplete volume groups will "
                          "be activated read-only.");
-       } else
-               init_partial(0);
+       }
 
        if (arg_count(cmd, ignorelockingfailure_ARG))
                init_ignorelockingfailure(1);
@@ -826,6 +826,7 @@ static void _apply_settings(struct cmd_context *cmd)
 
        cmd->fmt = arg_ptr_value(cmd, metadatatype_ARG,
                                 cmd->current_settings.fmt);
+       cmd->handles_missing_pvs = 0;
 }
 
 static char *_copy_command_line(struct cmd_context *cmd, int argc, char **argv)
index 703cf143696425a01f41650818a59ed25a438fe8..24278b25618f0f509b8ae5d9a12ad30c36fe7ef0 100644 (file)
@@ -31,6 +31,8 @@ int lvremove(struct cmd_context *cmd, int argc, char **argv)
                return EINVALID_CMD_LINE;
        }
 
+       cmd->handles_missing_pvs = 1;
+
        return process_each_lv(cmd, argc, argv, LCK_VG_WRITE, NULL,
                               &lvremove_single);
 }
index b18609d24a1067b611595a6c159d77e590e4c71f..b8af0e7be133cb4d3ee4e064fda4b7b100abd05e 100644 (file)
@@ -49,7 +49,6 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name,
        /* FIXME Check partition type is LVM unless --force is given */
 
        /* Is there a pv here already? */
-       /* FIXME Use partial mode here? */
        pv = pv_read(cmd, name, NULL, NULL, 0);
 
        /*
@@ -272,13 +271,11 @@ static int pvcreate_validate_params(struct cmd_context *cmd,
        if (arg_count(cmd, restorefile_ARG)) {
                pp->restorefile = arg_str_value(cmd, restorefile_ARG, "");
                /* The uuid won't already exist */
-               init_partial(1);
                if (!(vg = backup_read_vg(cmd, NULL, pp->restorefile))) {
                        log_error("Unable to read volume group from %s",
                                  pp->restorefile);
                        return 0;
                }
-               init_partial(0);
                if (!(existing_pv = find_pv_in_vg_by_uuid(vg, pp->idp))) {
                        log_error("Can't find uuid %s in backup file %s",
                                  uuid, pp->restorefile);
index 6418e04d476ff0ff200f219dc1bb0634a5db3760..7a67e6a3b89136cacf8ed6c5edd30365759ac2ff 100644 (file)
@@ -96,8 +96,7 @@ int vgcfgbackup(struct cmd_context *cmd, int argc, char **argv)
        int ret;
        char *last_filename = NULL;
 
-       if (partial_mode())
-               init_pvmove(1);
+       init_pvmove(1);
 
        ret = process_each_vg(cmd, argc, argv, LCK_VG_READ, 0, &last_filename,
                              &vg_backup_single);
index c0747bfc3272b4b839c8cd757b44ceddd1be3a96..a32aa505ff3428c922664d4d66eb6e61a855e489 100644 (file)
@@ -16,7 +16,7 @@
 #include "tools.h"
 #include "lv_alloc.h"
 
-static int _remove_pv(struct volume_group *vg, struct pv_list *pvl)
+static int _remove_pv(struct volume_group *vg, struct pv_list *pvl, int silent)
 {
        char uuid[64] __attribute((aligned(8)));
 
@@ -31,8 +31,9 @@ static int _remove_pv(struct volume_group *vg, struct pv_list *pvl)
        log_verbose("Removing PV with UUID %s from VG %s", uuid, vg->name);
 
        if (pvl->pv->pe_alloc_count) {
-               log_error("LVs still present on PV with UUID %s: Can't remove "
-                         "from VG %s", uuid, vg->name);
+               if (!silent)
+                       log_error("LVs still present on PV with UUID %s: "
+                                 "Can't remove from VG %s", uuid, vg->name);
                return 0;
        }
 
@@ -130,11 +131,39 @@ static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
        return 1;
 }
 
+static int _consolidate_vg(struct cmd_context *cmd, struct volume_group *vg)
+{
+       struct pv_list *pvl;
+       struct lv_list *lvl;
+       int r = 1;
+
+       list_iterate_items(lvl, &vg->lvs)
+               if (lvl->lv->status & PARTIAL_LV) {
+                       log_warn("WARNING: Partial LV %s needs to be repaired "
+                                "or removed. ", lvl->lv->name);
+                       r = 0;
+               }
+
+       if (!r) {
+               cmd->handles_missing_pvs = 1;
+               log_warn("WARNING: There are still partial LVs in VG %s.", vg->name);
+               log_warn("To remove them unconditionally use: vgreduce --removemissing --force.");
+               log_warn("Proceeding to remove empty missing PVs.");
+       }
+
+       list_iterate_items(pvl, &vg->pvs) {
+               if (pvl->pv->dev && !(pvl->pv->status & MISSING_PV))
+                       continue;
+               if (r && !_remove_pv(vg, pvl, 0))
+                       return_0;
+       }
+
+       return r;
+}
+
 static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
 {
-       struct list *pvh, *pvht;
        struct list *lvh, *lvht;
-       struct pv_list *pvl;
        struct lv_list *lvl, *lvl2, *lvlt;
        struct logical_volume *lv;
        struct physical_volume *pv;
@@ -182,20 +211,8 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
                return 0;
        }
 
-       /* Remove missing PVs */
-       list_iterate_safe(pvh, pvht, &vg->pvs) {
-               pvl = list_item(pvh, struct pv_list);
-               if (pvl->pv->dev)
-                       continue;
-               if (!_remove_pv(vg, pvl))
-                       return_0;
-       }
-
-       /* VG is now consistent */
-       vg->status &= ~PARTIAL_VG;
-       vg->status |= LVM_WRITE;
-
-       init_partial(0);
+       if (!_consolidate_vg(cmd, vg))
+               return_0;
 
        /* FIXME Recovery.  For now people must clean up by hand. */
 
@@ -208,14 +225,11 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
 
                if (!test_mode()) {
                        /* Suspend lvs_changed */
-                       init_partial(1);
                        if (!suspend_lvs(cmd, &lvs_changed)) {
                                stack;
-                               init_partial(0);
                                vg_revert(vg);
                                return 0;
                        }
-                       init_partial(0);
                }
 
                if (!vg_commit(vg)) {
@@ -439,26 +453,26 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
        char *vg_name;
        int ret = 1;
        int consistent = 1;
+       int fixed = 1;
+       int repairing = arg_count(cmd, removemissing_ARG);
 
-       if (!argc && !arg_count(cmd, removemissing_ARG)) {
+       if (!argc && !repairing) {
                log_error("Please give volume group name and "
                          "physical volume paths");
                return EINVALID_CMD_LINE;
        }
-
-       if (!argc && arg_count(cmd, removemissing_ARG)) {
+       
+       if (!argc && repairing) {
                log_error("Please give volume group name");
                return EINVALID_CMD_LINE;
        }
 
-       if (arg_count(cmd, mirrorsonly_ARG) &&
-           !arg_count(cmd, removemissing_ARG)) {
+       if (arg_count(cmd, mirrorsonly_ARG) && !repairing) {
                log_error("--mirrorsonly requires --removemissing");
                return EINVALID_CMD_LINE;
        }
 
-       if (argc == 1 && !arg_count(cmd, all_ARG)
-           && !arg_count(cmd, removemissing_ARG)) {
+       if (argc == 1 && !arg_count(cmd, all_ARG) && !repairing) {
                log_error("Please enter physical volume paths or option -a");
                return EINVALID_CMD_LINE;
        }
@@ -469,7 +483,7 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
                return EINVALID_CMD_LINE;
        }
 
-       if (argc > 1 && arg_count(cmd, removemissing_ARG)) {
+       if (argc > 1 && repairing) {
                log_error("Please only specify the volume group");
                return EINVALID_CMD_LINE;
        }
@@ -490,8 +504,8 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
                return ECMD_FAILED;
        }
 
-       if ((!(vg = vg_read(cmd, vg_name, NULL, &consistent)) || !consistent) &&
-           !arg_count(cmd, removemissing_ARG)) {
+       if ((!(vg = vg_read(cmd, vg_name, NULL, &consistent)) || !consistent)
+           && !repairing) {
                log_error("Volume group \"%s\" doesn't exist", vg_name);
                unlock_vg(cmd, vg_name);
                return ECMD_FAILED;
@@ -502,16 +516,15 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
                return ECMD_FAILED;
        }
 
-       if (arg_count(cmd, removemissing_ARG)) {
-               if (vg && consistent) {
+       if (repairing) {
+               if (vg && consistent && !vg_missing_pv_count(vg)) {
                        log_error("Volume group \"%s\" is already consistent",
                                  vg_name);
                        unlock_vg(cmd, vg_name);
                        return ECMD_PROCESSED;
                }
 
-               init_partial(1);
-               consistent = 0;
+               consistent = !arg_count(cmd, force_ARG);
                if (!(vg = vg_read(cmd, vg_name, NULL, &consistent))) {
                        log_error("Volume group \"%s\" not found", vg_name);
                        unlock_vg(cmd, vg_name);
@@ -522,16 +535,17 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
                        return ECMD_FAILED;
                }
                if (!archive(vg)) {
-                       init_partial(0);
                        unlock_vg(cmd, vg_name);
                        return ECMD_FAILED;
                }
 
-               if (!_make_vg_consistent(cmd, vg)) {
-                       init_partial(0);
-                       unlock_vg(cmd, vg_name);
-                       return ECMD_FAILED;
-               }
+               if (arg_count(cmd, force_ARG)) {
+                       if (!_make_vg_consistent(cmd, vg)) {
+                               unlock_vg(cmd, vg_name);
+                               return ECMD_FAILED;
+                       }
+               } else
+                       fixed = _consolidate_vg(cmd, vg);
 
                if (!vg_write(vg) || !vg_commit(vg)) {
                        log_error("Failed to write out a consistent VG for %s",
@@ -542,7 +556,9 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
 
                backup(vg);
 
-               log_print("Wrote out consistent volume group %s", vg_name);
+               if (fixed)
+                       log_print("Wrote out consistent volume group %s",
+                                 vg_name);
 
        } else {
                if (!vg_check_status(vg, EXPORTED_VG | LVM_WRITE | RESIZEABLE_VG)) {
This page took 0.092114 seconds and 5 git commands to generate.