Skip to content

Commit b1013db

Browse files
gadididimergify[bot]
authored andcommitted
nvmeof: add device tracking and disconnect in NodeUnstageVolume
Implement proper disconnect logic in NodeUnstageVolume that only disconnects controllers when no other volumes are using them. Changes: 1. Add getDeviceFromStagingPath() to find the Nvme device for a volume - Uses findmnt with JSON output for reliable parsing - Handles both filesystem and block volumes 2. Add getNVMeMountedDevices() to get all currently mounted NVMe devices - Single findmnt call scans entire mount table efficiently - Filters for NVMe-oF CSI staging paths only - Returns map of mounted devices for quick lookup 3. Update NodeUnstageVolume to call DisconnectIfLastMount after unmount - Gets device path from staging path - Gets list of all mounted NVMe devices - Passes both to DisconnectIfLastMount for safe disconnect decision - Disconnect failures are non-fatal (logged as warnings) Signed-off-by: gadi-didi <gadi.didi@ibm.com>
1 parent 57c455b commit b1013db

File tree

1 file changed

+33
-17
lines changed

1 file changed

+33
-17
lines changed

internal/nvmeof/nodeserver/nodeserver.go

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232

3333
csicommon "github.com/ceph/ceph-csi/internal/csi-common"
3434
"github.com/ceph/ceph-csi/internal/nvmeof"
35+
nvmeutil "github.com/ceph/ceph-csi/internal/nvmeof/util"
3536
"github.com/ceph/ceph-csi/internal/util"
3637
"github.com/ceph/ceph-csi/internal/util/log"
3738
)
@@ -326,6 +327,8 @@ func (ns *NodeServer) NodeUnstageVolume(
326327

327328
stagingTargetPath := getStagingTargetPath(req)
328329

330+
devPath := getDeviceFromStagingPath(ctx, stagingTargetPath)
331+
329332
isMnt, err := ns.Mounter.IsMountPoint(stagingTargetPath)
330333
if err != nil {
331334
if !os.IsNotExist(err) {
@@ -358,6 +361,20 @@ func (ns *NodeServer) NodeUnstageVolume(
358361
}
359362
log.DebugLog(ctx, "successfully removed staging path (%s)", stagingTargetPath)
360363

364+
// Disconnect controllers if this was the last mounted namespace on each controller.
365+
// Non-fatal - a failed disconnect just means the connection lingers until the
366+
// kernel's ctrl_loss_tmo expires or the next reconnect cycle.
367+
if devPath != "" {
368+
mountedDevices, err := getNVMeMountedDevices(ctx)
369+
if err != nil {
370+
log.WarningLog(ctx, "failed to get mounted devices: %v (skipping disconnect)", err)
371+
} else {
372+
if err := ns.initiator.DisconnectIfLastMount(ctx, devPath, mountedDevices); err != nil {
373+
log.WarningLog(ctx, "failed to disconnect controller for device %s: %v", devPath, err)
374+
}
375+
}
376+
}
377+
361378
return &csi.NodeUnstageVolumeResponse{}, nil
362379
}
363380

@@ -394,18 +411,18 @@ func (ns *NodeServer) NodeExpandVolume(
394411
mountPath := volumePath + "/" + volumeID
395412

396413
// Find device from mount (no metadata needed!)
397-
devicePath, err := ns.getDeviceFromMount(ctx, mountPath)
398-
if err != nil {
399-
log.ErrorLog(ctx, "failed to find device for mount %s: %v", mountPath, err)
414+
devicePath := getDeviceFromStagingPath(ctx, mountPath)
415+
if devicePath == "" {
416+
log.ErrorLog(ctx, "failed to find device for mount %s", mountPath)
400417

401-
return nil, status.Errorf(codes.Internal, "failed to find device: %v", err)
418+
return nil, status.Errorf(codes.Internal, "failed to find device for mount %s", mountPath)
402419
}
403420

404421
log.DebugLog(ctx, "nvmeof: resizing filesystem on device %s at mount path %s", devicePath, mountPath)
405422

406423
resizer := mount.NewResizeFs(utilexec.New())
407424
var ok bool
408-
ok, err = resizer.Resize(devicePath, mountPath)
425+
ok, err := resizer.Resize(devicePath, mountPath)
409426
if !ok {
410427
return nil, status.Errorf(codes.Internal,
411428
"nvmeof: resize failed on path %s, error: %v", req.GetVolumePath(), err)
@@ -758,20 +775,19 @@ func getStagingTargetPath(req interface{}) string {
758775
return ""
759776
}
760777

761-
// getDeviceFromMount finds the device path for a given mount path.
762-
func (ns *NodeServer) getDeviceFromMount(ctx context.Context, mountPath string) (string, error) {
763-
mountPoints, err := ns.Mounter.List()
778+
// getDeviceFromStagingPath returns the device path for either filesystem or block volumes.
779+
func getDeviceFromStagingPath(ctx context.Context, stagingTargetPath string) string {
780+
device, err := nvmeutil.GetDeviceFromMountpoint(ctx, stagingTargetPath)
764781
if err != nil {
765-
return "", fmt.Errorf("failed to list mounts: %w", err)
766-
}
767-
768-
for _, mp := range mountPoints {
769-
if mp.Path == mountPath {
770-
log.DebugLog(ctx, "found device %s for mount path %s", mp.Device, mountPath)
782+
log.DebugLog(ctx, "could not get device from staging path %s: %v", stagingTargetPath, err)
771783

772-
return mp.Device, nil
773-
}
784+
return ""
774785
}
775786

776-
return "", fmt.Errorf("no mount found for path %s", mountPath)
787+
return device
788+
}
789+
790+
// getNVMeMountedDevices returns a map of all currently mounted NVMe devices.
791+
func getNVMeMountedDevices(ctx context.Context) (map[string]bool, error) {
792+
return nvmeutil.GetAllNVMeMountedDevices(ctx)
777793
}

0 commit comments

Comments
 (0)