@@ -435,6 +435,19 @@ func (s *ControllerService) logCreateVolumeDebugInfo(req *csi.CreateVolumeReques
435435 klog .V (4 ).Infof ("===============================" )
436436}
437437
438+ // parseDataReplicas parses the dataReplicas StorageClass parameter.
439+ // Returns (0, nil) if empty (inherit filesystem default), or the parsed value.
440+ func parseDataReplicas (val string ) (uint32 , error ) {
441+ if val == "" {
442+ return 0 , nil
443+ }
444+ n , err := strconv .ParseUint (val , 10 , 32 )
445+ if err != nil || n < 1 {
446+ return 0 , status .Errorf (codes .InvalidArgument , "dataReplicas must be a positive integer, got %q" , val )
447+ }
448+ return uint32 (n ), nil
449+ }
450+
438451// validateCreateVolumeRequest validates the CreateVolume request parameters.
439452func validateCreateVolumeRequest (req * csi.CreateVolumeRequest ) error {
440453 if req .GetName () == "" {
@@ -1046,14 +1059,22 @@ func (s *ControllerService) checkAndAdoptVolume(ctx context.Context, req *csi.Cr
10461059 subvol , err := s .apiClient .FindSubvolumeByCSIVolumeName (ctx , filesystem , volumeName )
10471060 if err != nil {
10481061 klog .V (4 ).Infof ("Error searching for orphaned volume %s: %v" , volumeName , err )
1049- return nil , false , nil // Not found or error - continue with normal creation
1062+ subvol = nil // Continue to fallback search
1063+ }
1064+
1065+ // Fallback: search by PVC name + namespace stored in xattr properties.
1066+ // This handles the case where a PVC is recreated with a new UID — the CSI volume name
1067+ // changes (pvc-<new-uid>) but the stored pvc_name/pvc_namespace still match.
1068+ if subvol == nil {
1069+ subvol = s .findSubvolumeByPVCIdentity (ctx , params , filesystem )
10501070 }
1071+
10511072 if subvol == nil {
10521073 klog .V (4 ).Infof ("No orphaned volume found for %s" , volumeName )
10531074 return nil , false , nil // Not found - continue with normal creation
10541075 }
10551076
1056- // Found a subvolume with matching CSI volume name - check if adoption is allowed
1077+ // Found a subvolume - check if adoption is allowed
10571078 props := subvol .Properties
10581079 if props == nil {
10591080 klog .V (4 ).Infof ("Subvolume %s/%s has no properties, cannot adopt" , subvol .Filesystem , subvol .Name )
@@ -1123,6 +1144,43 @@ func (s *ControllerService) checkAndAdoptVolume(ctx context.Context, req *csi.Cr
11231144 }
11241145}
11251146
1147+ // findSubvolumeByPVCIdentity searches for an orphaned subvolume by its stored
1148+ // pvc_name and pvc_namespace xattr properties. This is used as a fallback when
1149+ // the CSI volume name search fails, which happens when a PVC is recreated with
1150+ // a new UID (e.g., cluster rebuild) but the underlying subvolume still has the
1151+ // original PVC identity in its properties.
1152+ func (s * ControllerService ) findSubvolumeByPVCIdentity (ctx context.Context , params map [string ]string , filesystem string ) * nastyapi.Subvolume {
1153+ pvcName := params [CSIPVCName ]
1154+ pvcNamespace := params [CSIPVCNamespace ]
1155+ if pvcName == "" || pvcNamespace == "" {
1156+ return nil
1157+ }
1158+
1159+ klog .V (4 ).Infof ("Fallback adoption search: looking for subvolume with pvc_name=%s, pvc_namespace=%s" , pvcName , pvcNamespace )
1160+
1161+ // Search by pvc_name first, then filter by pvc_namespace
1162+ candidates , err := s .apiClient .FindSubvolumesByProperty (ctx , nastyapi .PropertyPVCName , pvcName , filesystem )
1163+ if err != nil {
1164+ klog .V (4 ).Infof ("Error searching by PVC identity (%s/%s): %v" , pvcNamespace , pvcName , err )
1165+ return nil
1166+ }
1167+
1168+ for i := range candidates {
1169+ props := candidates [i ].Properties
1170+ if props == nil {
1171+ continue
1172+ }
1173+ if props [nastyapi .PropertyPVCNamespace ] == pvcNamespace {
1174+ klog .V (4 ).Infof ("Found subvolume by PVC identity: %s/%s (pvc=%s/%s)" ,
1175+ candidates [i ].Filesystem , candidates [i ].Name , pvcNamespace , pvcName )
1176+ return & candidates [i ]
1177+ }
1178+ }
1179+
1180+ klog .V (4 ).Infof ("No subvolume found with pvc_name=%s, pvc_namespace=%s" , pvcName , pvcNamespace )
1181+ return nil
1182+ }
1183+
11261184// ControllerGetCapabilities returns controller capabilities.
11271185func (s * ControllerService ) ControllerGetCapabilities (_ context.Context , _ * csi.ControllerGetCapabilitiesRequest ) (* csi.ControllerGetCapabilitiesResponse , error ) {
11281186 klog .V (4 ).Info ("ControllerGetCapabilities called" )
0 commit comments