diff --git a/simplyblock_core/controllers/lvol_controller.py b/simplyblock_core/controllers/lvol_controller.py index b5e1b3344..41d2ca5a2 100644 --- a/simplyblock_core/controllers/lvol_controller.py +++ b/simplyblock_core/controllers/lvol_controller.py @@ -930,14 +930,6 @@ def _create_bdev_stack(lvol, snode, is_primary=True): type = bdev['type'] name = bdev['name'] params = bdev['params'] - # Idempotency probe per stack bdev. A by-name bdev_get_bdevs resolves - # names, aliases and uuids server-side and returns [] / an -ENODEV - # error (→ None) when absent — equivalent to the previous full-dump - # membership test, but O(1) instead of serializing every bdev on the - # node into the response (the dump grows with lvol count and was the - # single largest cost of mass creates). - if rpc_client.get_bdevs(name): - continue ret = None if type == "bmap_init": @@ -1043,12 +1035,50 @@ def _fail_after_bdev(lvol, rpc_client, msg): the SPDK clone-blob in place, which then blocks the parent snapshot delete with "vbdev_lvol_destroy: ... has N clones". Logs but does not raise on rollback failure so the caller still sees the original error.""" - try: - _remove_bdev_stack(lvol.bdev_stack[::-1], rpc_client) - lvol.status = LVol.STATUS_IN_DELETION - lvol.write_to_db(DBController().kv_store) - except Exception: - logger.exception("rollback of bdev stack failed for %s", lvol.get_id()) + db_controller = DBController() + host_node = db_controller.get_storage_node_by_id(lvol.node_id) + secondary_ids = [host_node.secondary_node_id] + if host_node.tertiary_node_id: + secondary_ids.append(host_node.tertiary_node_id) + + all_nodes = [host_node] + for sid in secondary_ids: + try: + all_nodes.append(db_controller.get_storage_node_by_id(sid)) + except KeyError: + logger.debug( + "Skipping missing secondary/tertiary node '%s' during rollback for lvol '%s'", + sid, + lvol.get_id(), + ) + + if lvol.blobid: + try: + from simplyblock_core.storage_node_ops import find_leader_with_failover + primary_node, non_leaders = find_leader_with_failover(all_nodes, lvol.lvs_name) + if primary_node is None: + msg = "No leader available, marking it for deletion and let lvol monitor handle deletion" + else: + existing_on_primary = primary_node.rpc_client().get_bdevs(f"{lvol.lvs_name}/{lvol.lvol_bdev}") + if not existing_on_primary: + for sn_id in lvol.nodes: + if sn_id != lvol.node_id: + rpc_client = db_controller.get_storage_node_by_id(sn_id).rpc_client() + existing_on_secondary = rpc_client.get_bdevs(f"{lvol.lvs_name}/{lvol.lvol_bdev}") + if existing_on_secondary: + # register on primary + rpc_client.bdev_lvol_register( + existing_on_secondary[0], lvol.lvs_name, lvol.lvol_uuid, lvol.blobid, lvol.lvol_priority_class) + + lvol.status = LVol.STATUS_IN_DELETION + lvol.deletion_status = "" + lvol.write_to_db(DBController().kv_store) + except Exception: + logger.exception("rollback of bdev stack failed for %s", lvol.get_id()) + else: + for node in all_nodes: + _remove_lvol_subsys_from_node(lvol, node.rpc_client()) + lvol.remove_from_db(db_controller.kv_store) return False, msg diff --git a/simplyblock_core/env_var b/simplyblock_core/env_var index 5abdecd44..e1b73b6b3 100644 --- a/simplyblock_core/env_var +++ b/simplyblock_core/env_var @@ -1,5 +1,5 @@ SIMPLY_BLOCK_COMMAND_NAME=sbcli-dev SIMPLY_BLOCK_VERSION=19.2.34 -SIMPLY_BLOCK_DOCKER_IMAGE=public.ecr.aws/simply-block/simplyblock:main +SIMPLY_BLOCK_DOCKER_IMAGE=public.ecr.aws/simply-block/simplyblock:main-sfam-2793 SIMPLY_BLOCK_SPDK_ULTRA_IMAGE=public.ecr.aws/simply-block/ultra:main-latest diff --git a/simplyblock_core/storage_node_ops.py b/simplyblock_core/storage_node_ops.py index 4628fc6b6..a109512f5 100644 --- a/simplyblock_core/storage_node_ops.py +++ b/simplyblock_core/storage_node_ops.py @@ -6988,8 +6988,10 @@ def check_non_leader_for_operation(node_id, lvs_name, operation_type="create", StorageNode.RESTART_PHASE_POST_UNBLOCK): return "queue" - # 3. Fabric is connected — check RPC responsiveness - if _is_node_rpc_responsive(node, lvs_name): + # 3. Fabric is connected — check the SPDK process + nodeapi = SNodeClient(node) + is_up, _ = nodeapi.spdk_process_is_up(node.rpc_port, node.cluster_id) + if is_up: return "proceed" # 4. RPC failing but fabric connected