Skip to content

Commit f9550b7

Browse files
lexfreigithub-actions[bot]
authored andcommitted
fix(linstor): mark volumes restored from a snapshot DRBD-initialized
linstor-csi restores a snapshot on one node and autoplaces the other replicas. In LINSTOR v1.33.3 the restored volume definition has no DRBD_INITIALIZED flag, so the initial UpToDate race is still open, and Linstor/Drbd/InitialUptoDateOn, copied from the source volume through the snapshot, names the node that won it for the source. When a replica is autoplaced on that node, the empty new volume wins the race: it gets a random current UUID and a fresh filesystem, and goes StandAlone against the restored replica. A pod attached there sees an empty volume. Backport the upstream fix, released in LINSTOR v1.34.0, which sets the flag on a restore unless the resource definition asks for new metadata through ForceInitialSyncPermanent, as a backup does. Nothing wins the race any more, and an autoplaced replica resyncs from the restored one like any replica added to an existing volume. Link: LINBIT/linstor-server@9d8cdf5 Closes: #4862 Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <[email protected]> (cherry picked from commit e5689e2)
1 parent 37c82f3 commit f9550b7

2 files changed

Lines changed: 73 additions & 0 deletions

File tree

‎packages/system/linstor/images/piraeus-server/patches/README.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,9 @@ Custom patches for piraeus-server (linstor-server) v1.33.3.
2828

2929
- **native-protoc.diff** — Download the protoc build for the build host's architecture instead of always `linux-x86_64`. The builder stage runs on `$BUILDPLATFORM`, so on a native arm64 builder the x86_64 protoc cannot execute and `./gradlew generateJava` fails with `Syntax error: ")" unexpected`.
3030
- Not proposed upstream yet.
31+
32+
- **snapshot-restore-drbd-initialized.diff** — Mark the volume definitions of a restored snapshot as DRBD-initialized, unless the restored resource definition carries `DrbdOptions/ForceInitialSyncPermanent`, which keeps the existing path that recreates metadata, as for a backup. Without the flag the initial UpToDate race is still open on a restored volume, and `Linstor/Drbd/InitialUptoDateOn`, copied from the source volume through the snapshot, names whichever node won it for the source. When linstor-csi autoplaces a replica on that node, the empty new volume wins the race, gets mkfs and goes StandAlone against the restored replica, so a pod attached there sees an empty filesystem. With the flag set, nothing wins the race, and an autoplaced replica resyncs from the restored one like any replica added to an existing volume.
33+
- Backported from upstream commit: [`9d8cdf511`](https://github.com/LINBIT/linstor-server/commit/9d8cdf5118338fc72a34bb99799e452e031ea8f6), first released in v1.34.0; the `CHANGELOG.md` hunk is left out
34+
- Drop when LINSTOR is upgraded to v1.34.0 or later
35+
- On ZFS and thin pools the autoplaced replicas still skip the initial sync and rely on the source volume's day0 UUID being in the restored replica's history, upstream included; if it is not, DRBD reports unrelated data and goes StandAlone rather than syncing
36+
- Fixes [cozystack/cozystack#4862](https://github.com/cozystack/cozystack/issues/4862)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
diff --git a/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlSnapshotRestoreApiCallHandler.java b/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlSnapshotRestoreApiCallHandler.java
2+
index a639c27cc..4dabc1a83 100644
3+
--- a/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlSnapshotRestoreApiCallHandler.java
4+
+++ b/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlSnapshotRestoreApiCallHandler.java
5+
@@ -434,26 +434,39 @@ public class CtrlSnapshotRestoreApiCallHandler
6+
}
7+
}
8+
9+
- /*
10+
- * When a snapshot was received as a backup, it is marked to re-create its local metadata. Before the
11+
- * snapshot was sent the new DRBD_INITIALIZED flag and the VlmDfn property InitialUpToDateOn were
12+
+ /**
13+
+ * <p>Sets the {@value InternalApiConsts#KEY_LINSTOR_DRBD_INITIAL_UPTODATE_ON} property to the nodeName
14+
+ * of the first Snapshot (which has to have a disk) of the given SnapshotDefinition.</p>
15+
+ *
16+
+ * <p>If this SnapshotDefinition is a backup, we also unset the {@link VolumeDefinition.Flags#DRBD_INITIALIZED}
17+
+ * flag. Otherwise we ensure the same flag is set.</p>
18+
+ *
19+
+ * <p>Backup path: When a snapshot was received as a backup, it is marked to re-create its local metadata.
20+
+ * Before the snapshot was sent the new DRBD_INITIALIZED flag and the VlmDfn property InitialUpToDateOn were
21+
* cleared. If DRBD_INITIALZED would be set, no peer would even read the property (on purpose).
22+
* Without the property, no peer would think of itself as a winner, thus the DRBD resource would never
23+
* become UpToDate.
24+
* To avoid this, this method sets the InitialUpToDateOn property to let the first resource win the
25+
- * race, so it can become UpToDate and therefore also pull the other peers eventually into UpToDate state.
26+
+ * race, so it can become UpToDate and therefore also pull the other peers eventually into UpToDate state. </p>
27+
*
28+
- * If the given SnapDfn had also non-backup snapshots, those should be able to keep their metadata.
29+
+ * <p>If the given SnapDfn had also non-backup snapshots, those should be able to keep their metadata.
30+
* In that case we do not have to do anything. If however all snapshots are descendants from backups
31+
* we must pick one and decide the UpToDate race upfront so that the winner can set its local DRBD
32+
- * as UpToDate, which also triggers the controller to set the DRBD_INITIALZED flag eventually.
33+
+ * as UpToDate, which also triggers the controller to set the DRBD_INITIALZED flag eventually.</p>
34+
+ *
35+
+ * <p>Non-Backup path: When a regular snapshot (i.e. not from a backup) is restored, we can or even should
36+
+ * assume that the backing snapshot LVs have correct metadata which do not need be be initialized. When
37+
+ * a SnapshotVolumeDefinition is created it unfortunately does not properly store the VolumeDefinition's flags,
38+
+ * therefore the restored VolumeDefinition will also not have the DRBD_INITIALIZED flag set, although it
39+
+ * refers to a device with healthy and UpToDate metadata. To fix this issue we simply set the flag in this case.</p>
40+
*/
41+
private void checkDrbdInitializedState(ResourceDefinition rscDfnRef) throws AccessDeniedException
42+
{
43+
AccessContext accCtx = peerAccCtx.get();
44+
- if (DrbdLayerUtils.isForceInitialSyncSet(accCtx, rscDfnRef) && rscDfnRef.getDiskfulCount(accCtx) > 0)
45+
+ if (rscDfnRef.getDiskfulCount(accCtx) > 0)
46+
{
47+
String winnerNodeName = rscDfnRef.getDiskfulResources(accCtx).get(0).getNode().getName().value;
48+
+ boolean uninitializeDrbd = DrbdLayerUtils.isForceInitialSyncSet(accCtx, rscDfnRef);
49+
Iterator<VolumeDefinition> vlmDfnIt = rscDfnRef.iterateVolumeDfn(accCtx);
50+
while (vlmDfnIt.hasNext())
51+
{
52+
@@ -462,7 +475,14 @@ public class CtrlSnapshotRestoreApiCallHandler
53+
{
54+
vlmDfn.getProps(accCtx)
55+
.setProp(InternalApiConsts.KEY_LINSTOR_DRBD_INITIAL_UPTODATE_ON, winnerNodeName);
56+
- vlmDfn.getFlags().disableFlags(accCtx, VolumeDefinition.Flags.DRBD_INITIALIZED);
57+
+ if (uninitializeDrbd)
58+
+ {
59+
+ vlmDfn.getFlags().disableFlags(accCtx, VolumeDefinition.Flags.DRBD_INITIALIZED);
60+
+ }
61+
+ else
62+
+ {
63+
+ vlmDfn.getFlags().enableFlags(accCtx, VolumeDefinition.Flags.DRBD_INITIALIZED);
64+
+ }
65+
}
66+
catch (InvalidKeyException | InvalidValueException exc)
67+
{

0 commit comments

Comments
 (0)