@@ -3,6 +3,7 @@ package gceGCEDriver
33import (
44 "context"
55 "fmt"
6+ "math"
67 "regexp"
78 "strconv"
89 "strings"
@@ -16,10 +17,18 @@ import (
1617)
1718
1819const (
19- cacheSuffix = "csi-fast"
20- mainLvSuffix = "csi-main"
21- raidedLocalSsdName = "csi-driver-data-cache"
22- raidMode = "0"
20+ cacheSuffix = "csi-fast"
21+ mainLvSuffix = "csi-main"
22+ raidedLocalSsdName = "csi-driver-data-cache"
23+ raidMode = "0"
24+ maxAllowedChunks int64 = 1000000 // This is the max allowed chunks for LVM
25+ GiB float64 = 1024 * 1024 * 1024
26+ KiB float64 = 1024
27+ )
28+
29+ var (
30+ maxChunkSize float64 = 1 * GiB // Max allowed chunk size as per LVM documentation
31+ minChunkSize float64 = 160 * KiB // This is randomly selected, we need a multiple of 32KiB, the default size would be too small for caching https://man7.org/linux/man-pages/man8/lvcreate.8.html (--chunksize)
2332)
2433
2534func fetchRAIDedLocalSsdPath () (string , error ) {
@@ -84,7 +93,7 @@ func setupCaching(devicePath string, req *csi.NodeStageVolumeRequest, nodeId str
8493 vgNameForPv := strings .TrimSpace (infoSlice [(len (infoSlice ) - 1 )])
8594 klog .V (4 ).Infof ("Physical volume is part of Volume group: %v" , vgNameForPv )
8695 if vgNameForPv == volumeGroupName {
87- klog .V (4 ).Infof ("Physical Volume(PV) already exists in the Volume Group" )
96+ klog .V (4 ).Infof ("Physical Volume(PV) already exists in the Volume Group %v" , volumeGroupName )
8897 } else if vgNameForPv != "VG" && vgNameForPv != "" {
8998
9099 info , err = common .RunCommand ("" /* pipedCmd */ , nil /* pipedCmdArg */ , "vgchange" , []string {"-an" , vgNameForPv }... )
@@ -159,21 +168,30 @@ func setupCaching(devicePath string, req *csi.NodeStageVolumeRequest, nodeId str
159168 // Validate that cache is setup for required size
160169 klog .V (4 ).Infof ("Assuming valid data cache size and mode, resizing cache is not supported" )
161170 } else {
162- fastCacheSize := req .GetPublishContext ()[common .ContextDataCacheSize ]
163- chunkSize := "960" // Cannot use default chunk size(64KiB) as it errors on maxChunksAllowed. Unit - KiB
164- args = []string {
165- "--yes" ,
166- "-n" ,
167- cacheLvName ,
168- "-L" ,
169- // ConvertGiStringToInt64 converts the input size to GiB so default to "g" for cache size - LVM g|G is GiB.
170- fastCacheSize + "g" ,
171- volumeGroupName ,
172- raidedLocalSsdPath ,
173- }
174- info , err = common .RunCommand ("" /* pipedCmd */ , nil /* pipedCmdArg */ , "lvcreate" , args ... )
171+ cacheSize := req .GetPublishContext ()[common .ContextDataCacheSize ]
172+ chunkSize , err := fetchChunkSizeKiB (cacheSize )
175173 if err != nil {
176- return mainDevicePath , fmt .Errorf ("Errored while creating cache %w: %s" , err , info )
174+ klog .Errorf ("Errored to fetch cache size, verify the data-cache-size is valid: got %v, error: %q" , cacheSize , err )
175+ return mainDevicePath , err
176+ }
177+ // Check if LV exists
178+ info , err = common .RunCommand ("" /* pipedCmd */ , nil /* pipedCmdArg */ , "lvs" , args ... )
179+ lvExists := strings .Contains (string (info ), cacheLvName )
180+ if ! lvExists {
181+ args = []string {
182+ "--yes" ,
183+ "-n" ,
184+ cacheLvName ,
185+ "-L" ,
186+ // ConvertGiStringToInt64 converts the input size to GiB so default to "g" for cache size - LVM g|G is GiB.
187+ cacheSize + "g" ,
188+ volumeGroupName ,
189+ raidedLocalSsdPath ,
190+ }
191+ info , err = common .RunCommand ("" /* pipedCmd */ , nil /* pipedCmdArg */ , "lvcreate" , args ... )
192+ if err != nil {
193+ return mainDevicePath , fmt .Errorf ("Errored while creating cache %w: %s" , err , info )
194+ }
177195 }
178196
179197 // Once caching is setup, link the PD to cache
@@ -188,7 +206,7 @@ func setupCaching(devicePath string, req *csi.NodeStageVolumeRequest, nodeId str
188206 req .GetPublishContext ()[common .ContextDataCacheMode ],
189207 volumeGroupName + "/" + mainLvName ,
190208 "--chunksize" ,
191- string ( chunkSize ),
209+ chunkSize , // default unit is KiB
192210 "--force" ,
193211 "-y" ,
194212 }
@@ -357,11 +375,17 @@ func cleanupCache(volumeId string, nodeId string) error {
357375
358376 volumeGroupName := getVolumeGroupName (nodeId )
359377 if ! checkVgExists (volumeGroupName ) {
378+ klog .V (4 ).Infof ("Volume group %s not found, no cache clean up needed" , volumeGroupName )
360379 // If volume group doesn't exist then there's nothing to uncache
361380 return nil
362381 }
363382 reduceVolumeGroup (volumeGroupName , true )
364383 mainLvName := getLvName (mainLvSuffix , volumeId )
384+ if ! checkLvExists (mainLvName ) {
385+ klog .V (4 ).Infof ("Logical volume %s not found, assuming caching wasn't setup for the PVC %s or is cleaned up" , mainLvName , volumeId )
386+ // If logical volume doesn't exist then there's nothing to uncache
387+ return nil
388+ }
365389 args := []string {
366390 "-an" ,
367391 "/dev/" + volumeGroupName + "/" + mainLvName ,
@@ -382,6 +406,17 @@ func cleanupCache(volumeId string, nodeId string) error {
382406 return nil
383407}
384408
409+ func checkLvExists (lvName string ) bool {
410+ args := []string {}
411+ info , err := common .RunCommand ("" /* pipedCmd */ , nil /* pipedCmdArg */ , "lvscan" , args ... )
412+ if err != nil {
413+ klog .Errorf ("Errored while checking if logical volume exists for %s %v: %s" , lvName , err , info )
414+ return false
415+ }
416+ // Check if the required logical volume already exists
417+ return strings .Contains (string (info ), lvName )
418+ }
419+
385420func getVolumeGroupName (nodePath string ) string {
386421 nodeSlice := strings .Split (nodePath , "/" )
387422 nodeId := nodeSlice [len (nodeSlice )- 1 ]
@@ -497,3 +532,18 @@ func isCachingSetup(mainLvName string) (error, bool) {
497532 }
498533 return nil , false
499534}
535+
536+ func fetchChunkSizeKiB (cacheSize string ) (string , error ) {
537+ var chunkSize float64
538+
539+ cacheSizeInt , err := common .ConvertGiStringToInt64 (cacheSize )
540+ if err != nil {
541+ return "0" , err
542+ }
543+ // Chunksize should be divisible by 32Kib so we need (chunksize/32*1024)*32*1024
544+ chunkSize = (float64 (cacheSizeInt ) * GiB ) / float64 (maxAllowedChunks )
545+ chunkSize = math .Round (chunkSize / (32 * KiB )) * (32 * KiB )
546+ chunkSize = math .Min (math .Max (chunkSize , minChunkSize ), maxChunkSize ) / KiB
547+ // default chunk size unit KiB
548+ return strconv .FormatInt (int64 (chunkSize ), 10 ) + "KiB" , nil
549+ }
0 commit comments