Skip to content

kubevirt-csi: a node plugin restart permanently breaks mounted RWX volumes in tenant clusters #4863

Description

Describe the bug

Restarting the kubevirt-csi node plugin in a tenant cluster breaks every RWX volume that is mounted on that node, for good. Any upgrade that changes the plugin image restarts it, so every such upgrade does this. The pods keep running but their NFS mount answers Network is unreachable, and a pod using it cannot be deleted afterwards.

Environment

  • Cozystack main at 1d813c944 with the kubevirt-csi-driver image rebuilt from an open dependency roll-up. Only the image changed, the DaemonSet template is the one from main.
  • Test cluster, tenant Kubernetes v1.35 on Talos, one worker.
  • RWX PVC on the tenant replicated StorageClass, served by linstor-csi-nfs.cozy-linstor.svc.

To Reproduce

  1. In a tenant cluster, create an RWX PVC and a pod that mounts it, and write a file.
  2. Restart the node plugin pod, for example with kubectl -n cozy-csi rollout restart ds/kubevirt-csi-node. I hit it by changing the image.
  3. Read the file from the pod again, then delete the pod.

Expected behaviour

The mount keeps working after the plugin restarts. Deleting the pod unmounts the volume.

Actual behaviour

About 100 seconds after the plugin pod was replaced, the tenant node's kernel logged:

NFS: state manager: check lease failed on NFSv4 server linstor-csi-nfs.cozy-linstor.svc with error 101

Error 101 is ENETUNREACH. From then on every read from the pod fails:

sha256sum: can't open '/rwx/blob': Network is unreachable

ext4 and xfs volumes on the same node were not affected.

Deleting the pod never finishes. NodeUnpublishVolume fails on every retry:

failed to cleanup mount point Error checking path: stat /var/lib/kubelet/pods/<uid>/volumes/kubernetes.io~csi/<pv>/mount: network is unreachable

Additional context

The plugin mounts NFS from inside its own container (NodePublishVolume in packages/apps/kubernetes/images/kubevirt-csi-driver/node.go), and the DaemonSet in packages/system/kubevirt-csi-node/templates/deploy.yaml does not set hostNetwork. The kernel NFS client is tied to the network namespace of the process that mounted it. The mount showed clientaddr= equal to the plugin pod's IP. When the pod is replaced, its network namespace is gone, and with the fatal_neterrors=ENETDOWN:ENETUNREACH mount option the error is final.

The unpublish hang is a second problem on top of that. mount.CleanupMountPoint only unmounts a path whose stat error passes IsCorruptedMnt. In k8s.io/mount-utils v0.37.1 that list has ENOTCONN, ESTALE, EIO, EACCES, EHOSTDOWN, EWOULDBLOCK and ENODEV, but not ENETUNREACH. So the stat error is returned as is and the mount stays forever.

Two changes look needed. The NFS mount has to live in the node's network namespace, either with hostNetwork: true on the node plugin (it then needs a working DNS policy for the .svc name) or by mounting through a helper that runs in the host namespace. Unpublish should also treat ENETUNREACH as a dead mount and unmount it (lazy or forced). #4581 and #4814 are about a dead NFS server, which is a different trigger for similar hangs.

Activity

  1. added
    kind/bugCategorizes issue or PR as related to a bug
    priority/important-soonMust be staffed and worked on either currently, or very soon, ideally in time for the next release
    area/kubernetesIssues or PRs related to the tenant Kubernetes app
    area/storageIssues or PRs related to storage (linstor, seaweedfs, bucket, velero, harbor)
    on Oct 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/kubernetesIssues or PRs related to the tenant Kubernetes apparea/storageIssues or PRs related to storage (linstor, seaweedfs, bucket, velero, harbor)kind/bugCategorizes issue or PR as related to a bugpriority/important-soonMust be staffed and worked on either currently, or very soon, ideally in time for the next releasetriage/acceptedIndicates an issue is ready to be actively worked on

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions