linstor: add stale bitmap adjust retry patch

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
This commit is contained in:
Andrei Kvapil committed 2026-04-03 21:53:41 +02:00
1 parent e4468148f6
commit fd6bae62b2
2 files changed
+144

No files matched your search

@@ -12,3 +12,6 @@ Custom patches for piraeus-server (linstor-server) v1.33.1.
- Source PR/comment: [#472](https://github.com/LINBIT/linstor-server/pull/472), [maintainer note](https://github.com/LINBIT/linstor-server/pull/472#issuecomment-3949687603)
- Backported from commits: [`ccc85fbd2`](https://github.com/LINBIT/linstor-server/commit/ccc85fbd2c65f0b97c52403fa80f1efdb886ec4e), [`71b601554`](https://github.com/LINBIT/linstor-server/commit/71b601554f41bcb50cd5bd06989c5b0d3a814acd)
- Note: upstream commit [`3d0402a0c`](https://github.com/LINBIT/linstor-server/commit/3d0402a0c25f0a4b57b380321f10e89982f26e7a) is already included in `v1.33.1`
- **retry-adjust-after-stale-bitmap.diff** — Retry `drbdadm adjust` after detaching a stale local bitmap state
- Source PR: [#491](https://github.com/LINBIT/linstor-server/pull/491)
- Backported from commit: [`51ae50a84`](https://github.com/kvaps/linstor-server/commit/51ae50a84dcb98093f543b819652c750a94d96c9)
@@ -0,0 +1,141 @@
diff --git a/satellite/src/main/java/com/linbit/linstor/layer/drbd/utils/DrbdAdm.java b/satellite/src/main/java/com/linbit/linstor/layer/drbd/utils/DrbdAdm.java
index 5627d1be8..ece191292 100644
--- a/satellite/src/main/java/com/linbit/linstor/layer/drbd/utils/DrbdAdm.java
+++ b/satellite/src/main/java/com/linbit/linstor/layer/drbd/utils/DrbdAdm.java
@@ -42,6 +42,9 @@ import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
+import java.nio.charset.StandardCharsets;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Singleton
@@ -56,6 +58,9 @@ public class DrbdAdm
public static final int WAIT_CONNECT_RES_TIME = 10;
private static final long DOWN_WAIT_TIMEOUT_SEC = 5;
+ private static final long FORCE_DETACH_RETRY_WAIT_MS = 250;
+ private static final String BITMAP_LEAK_ERR_MSG = "already has a bitmap, this should not happen";
+ private static final Pattern BITMAP_LEAK_MINOR_PATTERN = Pattern.compile("\\bminor\\s+(\\d+)\\b");
private final ExtCmdFactory extCmdFactory;
private final AccessContext sysCtx;
@@ -131,8 +136,38 @@ public class DrbdAdm
// command.add(resName);
command.add(drbdRscData.getSuffixedResourceName());
// execute(Arrays.asList("drbdsetup", "show", drbdRscData.getSuffixedResourceName()));
- execute(command);
- // execute(Arrays.asList("drbdsetup", "show", drbdRscData.getSuffixedResourceName()));
+ String[] commandArr = command.toArray(new String[0]);
+ try
+ {
+ File nullDevice = new File(Platform.nullDevice());
+ ExtCmd extCmd = extCmdFactory.create();
+ if (Platform.isWindows())
+ {
+ extCmd.setTimeout(TimeoutType.WAIT, 5 * 60 * 1000);
+ }
+
+ OutputData outputData = extCmd.pipeExec(ProcessBuilder.Redirect.from(nullDevice), commandArr);
+ if (
+ outputData.exitCode != 0 &&
+ isBitmapLeakOnAttach(outputData) &&
+ cleanupStaleBitmapAndRetry(extCmd, nullDevice, outputData)
+ )
+ {
+ outputData = extCmd.pipeExec(ProcessBuilder.Redirect.from(nullDevice), commandArr);
+ }
+ if (outputData.exitCode != 0)
+ {
+ throw new ExtCmdFailedException(commandArr, outputData);
+ }
+ }
+ catch (ChildProcessTimeoutException timeoutExc)
+ {
+ throw new ExtCmdFailedException(commandArr, timeoutExc);
+ }
+ catch (IOException ioExc)
+ {
+ throw new ExtCmdFailedException(commandArr, ioExc);
+ }
drbdRscData.setAdjustRequired(false);
}
@@ -805,6 +840,75 @@ public class DrbdAdm
}
}
+ static boolean isBitmapLeakOnAttach(OutputData outputData)
+ {
+ return extractBitmapLeakMinor(outputData) != null;
+ }
+
+ static @Nullable Integer extractBitmapLeakMinor(OutputData outputData)
+ {
+ String stderr = new String(outputData.stderrData, StandardCharsets.UTF_8);
+ if (!stderr.contains(BITMAP_LEAK_ERR_MSG))
+ {
+ return null;
+ }
+
+ Matcher matcher = BITMAP_LEAK_MINOR_PATTERN.matcher(stderr);
+ if (!matcher.find())
+ {
+ return null;
+ }
+
+ return Integer.parseInt(matcher.group(1));
+ }
+
+ private boolean cleanupStaleBitmapAndRetry(
+ ExtCmd extCmd,
+ File nullDevice,
+ OutputData outputData
+ )
+ throws IOException, ChildProcessTimeoutException, ExtCmdFailedException
+ {
+ @Nullable Integer minor = extractBitmapLeakMinor(outputData);
+ if (minor == null)
+ {
+ return false;
+ }
+
+ OutputData detachOut = extCmd.pipeExec(
+ ProcessBuilder.Redirect.from(nullDevice),
+ DRBDSETUP_UTIL,
+ "detach",
+ Integer.toString(minor)
+ );
+ if (detachOut.exitCode == 0)
+ {
+ return true;
+ }
+
+ OutputData forceDetachOut = extCmd.pipeExec(
+ ProcessBuilder.Redirect.from(nullDevice),
+ DRBDSETUP_UTIL,
+ "detach",
+ Integer.toString(minor),
+ "--force"
+ );
+ if (forceDetachOut.exitCode != 0)
+ {
+ throw new ExtCmdFailedException(forceDetachOut.executedCommand, forceDetachOut);
+ }
+
+ try
+ {
+ Thread.sleep(FORCE_DETACH_RETRY_WAIT_MS);
+ }
+ catch (InterruptedException ignored)
+ {
+ Thread.currentThread().interrupt();
+ }
+ return true;
+ }
+
public static class DrbdPrimary implements AutoCloseable
{
private final DrbdAdm drbdAdm;