/* * VG locking is by VG name. * FIXME This should become VG uuid. */ static int _lock_vol(struct cmd_context *cmd, const char *resource, uint32_t flags, lv_operation_t lv_op, struct logical_volume *lv) { uint32_t lck_type = flags & LCK_TYPE_MASK; uint32_t lck_scope = flags & LCK_SCOPE_MASK; int ret = 0; _block_signals(flags); _lock_memory(cmd, lv_op); assert(resource); if (!*resource) { log_error(INTERNAL_ERROR "Use of P_orphans is deprecated."); return 0; } if ((is_orphan_vg(resource) || is_global_vg(resource)) && (flags & LCK_CACHE)) { log_error(INTERNAL_ERROR "P_%s referenced", resource); return 0; } if (cmd->metadata_read_only && lck_type == LCK_WRITE && strcmp(resource, VG_GLOBAL)) { log_error("Operation prohibited while global/metadata_read_only is set."); return 0; } if ((ret = _locking.lock_resource(cmd, resource, flags, lv))) { if (lck_scope == LCK_VG && !(flags & LCK_CACHE)) { if (lck_type != LCK_UNLOCK) lvmcache_lock_vgname(resource, lck_type == LCK_READ); dev_reset_error_count(cmd); } _update_vg_lock_count(resource, flags); } else stack; /* If unlocking, always remove lock from lvmcache even if operation failed. */ if (lck_scope == LCK_VG && !(flags & LCK_CACHE) && lck_type == LCK_UNLOCK) { lvmcache_unlock_vgname(resource); if (!ret) _update_vg_lock_count(resource, flags); } _unlock_memory(cmd, lv_op); _unblock_signals(); return ret; }
int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags) #endif { char lockname[PATH_MAX]; int clvmd_cmd = 0; const char *lock_scope; const char *lock_type = ""; assert(strlen(resource) < sizeof(lockname)); assert(resource); switch (flags & LCK_SCOPE_MASK) { case LCK_VG: if (flags == LCK_VG_BACKUP) { log_very_verbose("Requesting backup of VG metadata for %s", resource); return _lock_for_cluster(cmd, CLVMD_CMD_VG_BACKUP, LCK_CLUSTER_VG, resource); } /* If the VG name is empty then lock the unused PVs */ if (is_orphan_vg(resource) || is_global_vg(resource) || (flags & LCK_CACHE)) dm_snprintf(lockname, sizeof(lockname), "P_%s", resource); else dm_snprintf(lockname, sizeof(lockname), "V_%s", resource); lock_scope = "VG"; clvmd_cmd = CLVMD_CMD_LOCK_VG; /* * Old clvmd does not expect LCK_HOLD which was already processed * in lock_vol, mask it for compatibility reasons. */ if (flags != LCK_VG_COMMIT && flags != LCK_VG_REVERT) flags &= ~LCK_HOLD; break; case LCK_LV: clvmd_cmd = CLVMD_CMD_LOCK_LV; strcpy(lockname, resource); lock_scope = "LV"; flags &= ~LCK_HOLD; /* Mask off HOLD flag */ break; default: log_error("Unrecognised lock scope: %d", flags & LCK_SCOPE_MASK); return 0; } switch(flags & LCK_TYPE_MASK) { case LCK_UNLOCK: lock_type = "UN"; break; case LCK_NULL: lock_type = "NL"; break; case LCK_READ: lock_type = "CR"; break; case LCK_PREAD: lock_type = "PR"; break; case LCK_WRITE: lock_type = "PW"; break; case LCK_EXCL: lock_type = "EX"; break; default: log_error("Unrecognised lock type: %u", flags & LCK_TYPE_MASK); return 0; } log_very_verbose("Locking %s %s %s (%s%s%s%s%s%s) (0x%x)", lock_scope, lockname, lock_type, lock_scope, flags & LCK_NONBLOCK ? "|NONBLOCK" : "", flags & LCK_HOLD ? "|HOLD" : "", flags & LCK_LOCAL ? "|LOCAL" : "", flags & LCK_CLUSTER_VG ? "|CLUSTER" : "", flags & LCK_CACHE ? "|CACHE" : "", flags); /* Send a message to the cluster manager */ return _lock_for_cluster(cmd, clvmd_cmd, flags, lockname); }
int lock_vol(struct cmd_context *cmd, const char *vol, uint32_t flags, struct logical_volume *lv) { char resource[258] __attribute__((aligned(8))); lv_operation_t lv_op; int lck_type = flags & LCK_TYPE_MASK; switch (flags & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) { case LCK_LV_SUSPEND: lv_op = LV_SUSPEND; break; case LCK_LV_RESUME: lv_op = LV_RESUME; break; default: lv_op = LV_NOOP; } if (flags == LCK_NONE) { log_debug_locking(INTERNAL_ERROR "%s: LCK_NONE lock requested", vol); return 1; } switch (flags & LCK_SCOPE_MASK) { case LCK_VG: if (!_blocking_supported) flags |= LCK_NONBLOCK; /* Global VG_ORPHANS lock covers all orphan formats. */ if (is_orphan_vg(vol)) vol = VG_ORPHANS; /* VG locks alphabetical, ORPHAN lock last */ if ((lck_type != LCK_UNLOCK) && !(flags & LCK_CACHE) && !lvmcache_verify_lock_order(vol)) return_0; /* Lock VG to change on-disk metadata. */ /* If LVM1 driver knows about the VG, it can't be accessed. */ if (!check_lvm1_vg_inactive(cmd, vol)) return_0; break; case LCK_LV: /* All LV locks are non-blocking. */ flags |= LCK_NONBLOCK; break; default: log_error("Unrecognised lock scope: %d", flags & LCK_SCOPE_MASK); return 0; } strncpy(resource, vol, sizeof(resource) - 1); resource[sizeof(resource) - 1] = '\0'; if (!_lock_vol(cmd, resource, flags, lv_op, lv)) return_0; /* * If a real lock was acquired (i.e. not LCK_CACHE), * perform an immediate unlock unless LCK_HOLD was requested. */ if ((lck_type == LCK_NULL) || (lck_type == LCK_UNLOCK) || (flags & (LCK_CACHE | LCK_HOLD))) return 1; if (!_lock_vol(cmd, resource, (flags & ~LCK_TYPE_MASK) | LCK_UNLOCK, lv_op, lv)) return_0; return 1; }
static int _pv_resize_single(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv, const uint64_t new_size) { struct pv_list *pvl; uint64_t size = 0; uint32_t new_pe_count = 0; int r = 0; struct dm_list mdas; const char *pv_name = pv_dev_name(pv); const char *vg_name; struct lvmcache_info *info; int mda_count = 0; struct volume_group *old_vg = vg; dm_list_init(&mdas); if (is_orphan_vg(pv_vg_name(pv))) { vg_name = VG_ORPHANS; if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) { log_error("Can't get lock for orphans"); return 0; } if (!(pv = pv_read(cmd, pv_name, &mdas, NULL, 1, 0))) { unlock_vg(cmd, vg_name); log_error("Unable to read PV \"%s\"", pv_name); return 0; } mda_count = dm_list_size(&mdas); } else { vg_name = pv_vg_name(pv); vg = vg_read_for_update(cmd, vg_name, NULL, 0); if (vg_read_error(vg)) goto bad; if (!(pvl = find_pv_in_vg(vg, pv_name))) { log_error("Unable to find \"%s\" in volume group \"%s\"", pv_name, vg->name); goto bad; } pv = pvl->pv; if (!(info = info_from_pvid(pv->dev->pvid, 0))) { log_error("Can't get info for PV %s in volume group %s", pv_name, vg->name); goto bad; } mda_count = dm_list_size(&info->mdas); if (!archive(vg)) goto bad; } /* FIXME Create function to test compatibility properly */ if (mda_count > 1) { log_error("%s: too many metadata areas for pvresize", pv_name); goto bad; } if (!(pv->fmt->features & FMT_RESIZE_PV)) { log_error("Physical volume %s format does not support resizing.", pv_name); goto bad; } /* Get new size */ if (!dev_get_size(pv_dev(pv), &size)) { log_error("%s: Couldn't get size.", pv_name); goto bad; } if (new_size) { if (new_size > size) log_warn("WARNING: %s: Overriding real size. " "You could lose data.", pv_name); log_verbose("%s: Pretending size is %" PRIu64 " not %" PRIu64 " sectors.", pv_name, new_size, pv_size(pv)); size = new_size; } if (size < PV_MIN_SIZE) { log_error("%s: Size must exceed minimum of %ld sectors.", pv_name, PV_MIN_SIZE); goto bad; } if (size < pv_pe_start(pv)) { log_error("%s: Size must exceed physical extent start of " "%" PRIu64 " sectors.", pv_name, pv_pe_start(pv)); goto bad; } pv->size = size; if (vg) { pv->size -= pv_pe_start(pv); new_pe_count = pv_size(pv) / vg->extent_size; if (!new_pe_count) { log_error("%s: Size must leave space for at " "least one physical extent of " "%" PRIu32 " sectors.", pv_name, pv_pe_size(pv)); goto bad; } if (!pv_resize(pv, vg, new_pe_count)) goto_bad; } log_verbose("Resizing volume \"%s\" to %" PRIu64 " sectors.", pv_name, pv_size(pv)); log_verbose("Updating physical volume \"%s\"", pv_name); if (!is_orphan_vg(pv_vg_name(pv))) { if (!vg_write(vg) || !vg_commit(vg)) { log_error("Failed to store physical volume \"%s\" in " "volume group \"%s\"", pv_name, vg->name); goto bad; } backup(vg); } else if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) { log_error("Failed to store physical volume \"%s\"", pv_name); goto bad;; } log_print("Physical volume \"%s\" changed", pv_name); r = 1; bad: unlock_vg(cmd, vg_name); if (!old_vg) vg_release(vg); return r; }
static int _file_lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags, struct logical_volume *lv) { char lockfile[PATH_MAX]; unsigned origin_only = (flags & LCK_ORIGIN_ONLY) ? 1 : 0; unsigned revert = (flags & LCK_REVERT) ? 1 : 0; switch (flags & LCK_SCOPE_MASK) { case LCK_ACTIVATION: if (dm_snprintf(lockfile, sizeof(lockfile), "%s/A_%s", _lock_dir, resource + 1) < 0) { log_error("Too long locking filename %s/A_%s.", _lock_dir, resource + 1); return 0; } if (!lock_file(lockfile, flags)) return_0; break; case LCK_VG: /* Skip cache refresh for VG_GLOBAL - the caller handles it */ if (strcmp(resource, VG_GLOBAL)) lvmcache_drop_metadata(resource, 0); if (!strcmp(resource, VG_SYNC_NAMES)) fs_unlock(); /* LCK_CACHE does not require a real lock */ if (flags & LCK_CACHE) break; if (is_orphan_vg(resource) || is_global_vg(resource)) { if (dm_snprintf(lockfile, sizeof(lockfile), "%s/P_%s", _lock_dir, resource + 1) < 0) { log_error("Too long locking filename %s/P_%s.", _lock_dir, resource + 1); return 0; } } else if (dm_snprintf(lockfile, sizeof(lockfile), "%s/V_%s", _lock_dir, resource) < 0) { log_error("Too long locking filename %s/V_%s.", _lock_dir, resource); return 0; } if (!lock_file(lockfile, flags)) return_0; break; case LCK_LV: switch (flags & LCK_TYPE_MASK) { case LCK_UNLOCK: log_very_verbose("Unlocking LV %s%s%s", resource, origin_only ? " without snapshots" : "", revert ? " (reverting)" : ""); if (!lv_resume_if_active(cmd, resource, origin_only, 0, revert, lv_ondisk(lv))) return 0; break; case LCK_NULL: log_very_verbose("Locking LV %s (NL)", resource); if (!lv_deactivate(cmd, resource, lv_ondisk(lv))) return 0; break; case LCK_READ: log_very_verbose("Locking LV %s (R)", resource); if (!lv_activate_with_filter(cmd, resource, 0, lv->status & LV_NOSCAN ? 1 : 0, lv->status & LV_TEMPORARY ? 1 : 0, lv_ondisk(lv))) return 0; break; case LCK_PREAD: log_very_verbose("Locking LV %s (PR) - ignored", resource); break; case LCK_WRITE: log_very_verbose("Locking LV %s (W)%s", resource, origin_only ? " without snapshots" : ""); if (!lv_suspend_if_active(cmd, resource, origin_only, 0, lv_ondisk(lv), lv)) return 0; break; case LCK_EXCL: log_very_verbose("Locking LV %s (EX)", resource); if (!lv_activate_with_filter(cmd, resource, 1, lv->status & LV_NOSCAN ? 1 : 0, lv->status & LV_TEMPORARY ? 1 : 0, lv_ondisk(lv))) return 0; break; default: break; } break; default: log_error("Unrecognised lock scope: %d", flags & LCK_SCOPE_MASK); return 0; } return 1; }