|
| 1 | +diff --git a/pkg/client/linstor.go b/pkg/client/linstor.go |
| 2 | +index ac4651d..9d75c79 100644 |
| 3 | +--- a/pkg/client/linstor.go |
| 4 | ++++ b/pkg/client/linstor.go |
| 5 | +@@ -653,11 +653,35 @@ func (s *Linstor) Attach(ctx context.Context, volId, node string, rwxBlock bool) |
| 6 | + } |
| 7 | + |
| 8 | + if otherResInUse > 0 && rwxBlock { |
| 9 | +- rdPropsModify := lapi.GenericPropsModify{OverrideProps: map[string]string{ |
| 10 | ++ rdProps := map[string]string{ |
| 11 | + linstor.PropertyAllowTwoPrimaries: "yes", |
| 12 | +- }} |
| 13 | ++ } |
| 14 | + |
| 15 | +- err = s.client.ResourceDefinitions.Modify(ctx, volId, rdPropsModify) |
| 16 | ++ // DRBD requires Protocol C whenever allow-two-primaries is enabled. |
| 17 | ++ // If the resource is configured with Protocol A or B (typically |
| 18 | ++ // through its resource-group), drbdadm adjust on the satellites |
| 19 | ++ // fails with "Protocol C required" (errno 139) and live migration |
| 20 | ++ // cannot proceed. Override Protocol to C on the resource-definition |
| 21 | ++ // itself so it applies to every connection (including diskless |
| 22 | ++ // peers, e.g. a TieBreaker). The marker lets Detach revert exactly |
| 23 | ++ // the override we installed without disturbing operator-set props. |
| 24 | ++ proto, protoErr := s.getEffectiveDrbdProtocol(ctx, volId) |
| 25 | ++ if protoErr != nil { |
| 26 | ++ s.log.WithError(protoErr).WithField("volume", volId). |
| 27 | ++ Warn("failed to determine effective DRBD protocol; skipping Protocol=C override for dual-attach") |
| 28 | ++ } else if proto == "A" || proto == "B" { |
| 29 | ++ s.log.WithFields(logrus.Fields{ |
| 30 | ++ "volume": volId, |
| 31 | ++ "protocol": proto, |
| 32 | ++ }).Info("installing Protocol=C override on resource-definition for dual-attach") |
| 33 | ++ |
| 34 | ++ rdProps[linstor.PropertyDrbdNetProtocol] = "C" |
| 35 | ++ rdProps[linstor.PropertyCsiProtocolOverride] = "yes" |
| 36 | ++ } |
| 37 | ++ |
| 38 | ++ err = s.client.ResourceDefinitions.Modify(ctx, volId, lapi.GenericPropsModify{ |
| 39 | ++ OverrideProps: rdProps, |
| 40 | ++ }) |
| 41 | + if err != nil { |
| 42 | + return "", err |
| 43 | + } |
| 44 | +@@ -774,11 +798,26 @@ func (s *Linstor) Detach(ctx context.Context, volId, node string) error { |
| 45 | + } |
| 46 | + |
| 47 | + if resInUse == 1 { |
| 48 | +- rdPropsModify := lapi.GenericPropsModify{DeleteProps: []string{ |
| 49 | +- linstor.PropertyAllowTwoPrimaries, |
| 50 | +- }} |
| 51 | ++ deleteProps := []string{linstor.PropertyAllowTwoPrimaries} |
| 52 | ++ |
| 53 | ++ // Drop the Protocol=C override only if Attach installed it (gated by |
| 54 | ++ // our marker), so an operator-set Protocol property on the |
| 55 | ++ // resource-definition is preserved. |
| 56 | ++ rd, getErr := s.client.ResourceDefinitions.Get(ctx, volId) |
| 57 | ++ if getErr != nil { |
| 58 | ++ log.WithError(getErr).Warn("failed to fetch resource-definition props; skipping Protocol=C override removal") |
| 59 | ++ } else if rd.Props[linstor.PropertyCsiProtocolOverride] != "" { |
| 60 | ++ log.Info("removing Protocol=C override from resource-definition") |
| 61 | + |
| 62 | +- err = s.client.ResourceDefinitions.Modify(ctx, volId, rdPropsModify) |
| 63 | ++ deleteProps = append(deleteProps, |
| 64 | ++ linstor.PropertyDrbdNetProtocol, |
| 65 | ++ linstor.PropertyCsiProtocolOverride, |
| 66 | ++ ) |
| 67 | ++ } |
| 68 | ++ |
| 69 | ++ err = s.client.ResourceDefinitions.Modify(ctx, volId, lapi.GenericPropsModify{ |
| 70 | ++ DeleteProps: deleteProps, |
| 71 | ++ }) |
| 72 | + if err != nil { |
| 73 | + return nil404(err) |
| 74 | + } |
| 75 | +@@ -805,6 +844,33 @@ func (s *Linstor) Detach(ctx context.Context, volId, node string) error { |
| 76 | + return nil404(s.client.Resources.Delete(ctx, volId, node)) |
| 77 | + } |
| 78 | + |
| 79 | ++// getEffectiveDrbdProtocol returns the DRBD network protocol ("A", "B" or "C") |
| 80 | ++// that LINSTOR will hand to drbdadm for the given resource. Resource-definition |
| 81 | ++// properties take precedence; otherwise the value is inherited from the |
| 82 | ++// resource-group. An empty string is returned when neither level sets the |
| 83 | ++// property (LINSTOR's compiled-in default is "C"). |
| 84 | ++func (s *Linstor) getEffectiveDrbdProtocol(ctx context.Context, volId string) (string, error) { |
| 85 | ++ rd, err := s.client.ResourceDefinitions.Get(ctx, volId) |
| 86 | ++ if err != nil { |
| 87 | ++ return "", err |
| 88 | ++ } |
| 89 | ++ |
| 90 | ++ if v, ok := rd.Props[linstor.PropertyDrbdNetProtocol]; ok { |
| 91 | ++ return v, nil |
| 92 | ++ } |
| 93 | ++ |
| 94 | ++ if rd.ResourceGroupName == "" { |
| 95 | ++ return "", nil |
| 96 | ++ } |
| 97 | ++ |
| 98 | ++ rg, err := s.client.ResourceGroups.Get(ctx, rd.ResourceGroupName) |
| 99 | ++ if err != nil { |
| 100 | ++ return "", err |
| 101 | ++ } |
| 102 | ++ |
| 103 | ++ return rg.Props[linstor.PropertyDrbdNetProtocol], nil |
| 104 | ++} |
| 105 | ++ |
| 106 | + // CapacityBytes returns the amount of free space in the storage pool specified by the params and topology. |
| 107 | + func (s *Linstor) CapacityBytes(ctx context.Context, storagePools []string, overProvision *float64, segments map[string]string) (int64, error) { |
| 108 | + log := s.log.WithField("storage-pools", storagePools).WithField("segments", segments) |
| 109 | +diff --git a/pkg/linstor/const.go b/pkg/linstor/const.go |
| 110 | +index 9a5f79c..c8bc9c3 100644 |
| 111 | +--- a/pkg/linstor/const.go |
| 112 | ++++ b/pkg/linstor/const.go |
| 113 | +@@ -44,6 +44,19 @@ const ( |
| 114 | + // PropertyAllowTwoPrimaries is DRBD option to allow second primary. Mainly used for live-migration. |
| 115 | + PropertyAllowTwoPrimaries = lc.NamespcDrbdNetOptions + "/allow-two-primaries" |
| 116 | + |
| 117 | ++ // PropertyDrbdNetProtocol is the DRBD network replication protocol option |
| 118 | ++ // (A = async, B = semi-sync, C = sync). DRBD requires Protocol C whenever |
| 119 | ++ // allow-two-primaries is enabled, otherwise drbdadm adjust fails with |
| 120 | ++ // "Protocol C required" (errno 139). |
| 121 | ++ PropertyDrbdNetProtocol = lc.NamespcDrbdNetOptions + "/protocol" |
| 122 | ++ |
| 123 | ++ // PropertyCsiProtocolOverride marks a resource-connection where this driver |
| 124 | ++ // has installed a temporary Protocol=C override to make a Protocol-A/B |
| 125 | ++ // resource compatible with allow-two-primaries during live migration. The |
| 126 | ++ // marker lets us safely remove only the overrides we set, without touching |
| 127 | ++ // connection-level overrides installed by the operator. |
| 128 | ++ PropertyCsiProtocolOverride = lc.NamespcAuxiliary + "/csi-protocol-override" |
| 129 | ++ |
| 130 | + // CreatedForTemporaryDisklessAttach marks a resource as temporary, i.e. it should be removed after it is no longer |
| 131 | + // needed. |
| 132 | + CreatedForTemporaryDisklessAttach = "temporary-diskless-attach" |
0 commit comments