Skip to content

Commit 5cb1589

Browse files
gadididimergify[bot]
authored andcommitted
nvmeof: implement NodeExpandVolume for filesystem resize
Resize filesystem after ControllerExpandVolume expands the block device, with support for old Kubernetes versions via staging path lookup (as rbd driver does). Signed-off-by: gadi-didi <gadi.didi@ibm.com>
1 parent 131230b commit 5cb1589

File tree

1 file changed

+79
-0
lines changed

1 file changed

+79
-0
lines changed

internal/nvmeof/nodeserver/nodeserver.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,13 @@ func (ns *NodeServer) NodeGetCapabilities(
121121
},
122122
},
123123
},
124+
{
125+
Type: &csi.NodeServiceCapability_Rpc{
126+
Rpc: &csi.NodeServiceCapability_RPC{
127+
Type: csi.NodeServiceCapability_RPC_EXPAND_VOLUME,
128+
},
129+
},
130+
},
124131
},
125132
}, nil
126133
}
@@ -337,6 +344,60 @@ func (ns *NodeServer) NodeUnstageVolume(
337344
return &csi.NodeUnstageVolumeResponse{}, nil
338345
}
339346

347+
// NodeExpandVolume resizes nvmeof volumes (namespace).
348+
func (ns *NodeServer) NodeExpandVolume(
349+
ctx context.Context,
350+
req *csi.NodeExpandVolumeRequest,
351+
) (*csi.NodeExpandVolumeResponse, error) {
352+
volumeID := req.GetVolumeId()
353+
if volumeID == "" {
354+
return nil, status.Error(codes.InvalidArgument, "volume ID must be provided")
355+
}
356+
357+
// Block mode - nothing to do
358+
if req.GetVolumeCapability() != nil && req.GetVolumeCapability().GetBlock() != nil {
359+
log.DebugLog(ctx, "nvmeof: block mode volume, no filesystem resize needed for %s", volumeID)
360+
361+
return &csi.NodeExpandVolumeResponse{}, nil
362+
}
363+
364+
// Get staging path
365+
volumePath := req.GetStagingTargetPath()
366+
if volumePath == "" {
367+
return nil, status.Error(codes.InvalidArgument, "volume path must be provided")
368+
}
369+
370+
if acquired := ns.volumeLocks.TryAcquire(volumeID); !acquired {
371+
log.ErrorLog(ctx, util.VolumeOperationAlreadyExistsFmt, volumeID)
372+
373+
return nil, status.Errorf(codes.Aborted, util.VolumeOperationAlreadyExistsFmt, volumeID)
374+
}
375+
defer ns.volumeLocks.Release(volumeID)
376+
377+
mountPath := volumePath + "/" + volumeID
378+
379+
// Find device from mount (no metadata needed!)
380+
devicePath, err := ns.getDeviceFromMount(ctx, mountPath)
381+
if err != nil {
382+
log.ErrorLog(ctx, "failed to find device for mount %s: %v", mountPath, err)
383+
384+
return nil, status.Errorf(codes.Internal, "failed to find device: %v", err)
385+
}
386+
387+
log.DebugLog(ctx, "nvmeof: resizing filesystem on device %s at mount path %s", devicePath, mountPath)
388+
389+
resizer := mount.NewResizeFs(utilexec.New())
390+
var ok bool
391+
ok, err = resizer.Resize(devicePath, mountPath)
392+
if !ok {
393+
return nil, status.Errorf(codes.Internal,
394+
"nvmeof: resize failed on path %s, error: %v", req.GetVolumePath(), err)
395+
}
396+
log.DebugLog(ctx, "nvmeof: successfully resized filesystem for volume %s", volumeID)
397+
398+
return &csi.NodeExpandVolumeResponse{}, nil
399+
}
400+
340401
func (ns *NodeServer) mountVolume(ctx context.Context, stagingPath string, req *csi.NodePublishVolumeRequest) error {
341402
// Publish Path
342403
fsType := req.GetVolumeCapability().GetMount().GetFsType()
@@ -653,3 +714,21 @@ func getStagingTargetPath(req interface{}) string {
653714

654715
return ""
655716
}
717+
718+
// getDeviceFromMount finds the device path for a given mount path.
719+
func (ns *NodeServer) getDeviceFromMount(ctx context.Context, mountPath string) (string, error) {
720+
mountPoints, err := ns.Mounter.List()
721+
if err != nil {
722+
return "", fmt.Errorf("failed to list mounts: %w", err)
723+
}
724+
725+
for _, mp := range mountPoints {
726+
if mp.Path == mountPath {
727+
log.DebugLog(ctx, "found device %s for mount path %s", mp.Device, mountPath)
728+
729+
return mp.Device, nil
730+
}
731+
}
732+
733+
return "", fmt.Errorf("no mount found for path %s", mountPath)
734+
}

0 commit comments

Comments
 (0)