Skip to content

Commit e8033db

Browse files
authored
Merge pull request #102 from desultory/dev
Fix mount autodetection with overlayfs usage
2 parents f8e4ebc + 5b70c48 commit e8033db

File tree

2 files changed

+30
-11
lines changed

2 files changed

+30
-11
lines changed

src/ugrd/fs/btrfs.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = '1.8.2'
1+
__version__ = '1.9.0'
22
__author__ = 'desultory'
33

44

@@ -15,7 +15,12 @@ class SubvolIsRoot(Exception):
1515

1616
def _get_mount_subvol(self, mountpoint: str) -> list:
1717
""" Returns the subvolume name for a mountpoint. """
18-
for option in self['_mounts'][mountpoint]['options']:
18+
if self["_mounts"][mountpoint]["fstype"] == "overlay":
19+
from ugrd.fs.mounts import _resolve_overlay_lower_dir
20+
mountpoint = _resolve_overlay_lower_dir(self, mountpoint)
21+
elif self["_mounts"][mountpoint]["fstype"] != "btrfs":
22+
raise ValueError("Mountpoint is not a btrfs mount: %s" % mountpoint)
23+
for option in self["_mounts"][mountpoint]['options']:
1924
if option.startswith('subvol='):
2025
subvol = option.split('=')[1]
2126
if subvol == '/':

src/ugrd/fs/mounts.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
__author__ = "desultory"
2-
__version__ = "5.5.0"
2+
__version__ = "5.6.0"
33

44
from pathlib import Path
55
from typing import Union
@@ -364,8 +364,8 @@ def _autodetect_dm(self, mountpoint, device=None) -> None:
364364
if device:
365365
self.logger.debug("[%s] Using provided device for mount autodetection: %s" % (mountpoint, device))
366366
source_device = device
367-
elif mountpoint in self["_mounts"]:
368-
source_device = self["_mounts"][mountpoint]["device"]
367+
elif mountpoint:
368+
source_device = _resolve_overlay_lower_device(self, mountpoint)
369369
else:
370370
raise FileNotFoundError("Mountpoint not found in host mounts: %s" % mountpoint)
371371

@@ -537,6 +537,21 @@ def _resolve_dev(self, device_path) -> str:
537537
return self["_mounts"][device_path]["device"]
538538

539539

540+
541+
def _resolve_overlay_lower_dir(self, mountpoint) -> str:
542+
for option in self["_mounts"][mountpoint]["options"]:
543+
if option.startswith("lowerdir="):
544+
return option.removeprefix("lowerdir=")
545+
raise ValueError("[%s] No lower overlayfs mountpoint found: %s" % mountpoint, self["_mounts"][mountpoint]["options"])
546+
547+
def _resolve_overlay_lower_device(self, mountpoint) -> dict:
548+
""" Returns device for the lower overlayfs mountpoint."""
549+
if self["_mounts"][mountpoint]["fstype"] != "overlay":
550+
return self["_mounts"][mountpoint]["device"]
551+
552+
lowerdir = _resolve_overlay_lower_dir(self, mountpoint)
553+
return self["_mounts"][lowerdir]["device"]
554+
540555
@contains("autodetect_root", "Skipping root autodetection, autodetect_root is disabled.", log_level=30)
541556
@contains("hostonly", "Skipping root autodetection, hostonly mode is disabled.", log_level=30)
542557
def autodetect_root(self) -> None:
@@ -547,14 +562,12 @@ def autodetect_root(self) -> None:
547562
)
548563
# Sometimes the root device listed in '/proc/mounts' differs from the blkid info
549564
root_dev = self["_mounts"]["/"]["device"]
550-
if self["resolve_root_dev"]:
565+
if self["resolve_root_dev"]: # Sometimes the root device listed in '/proc/mounts' differs from the blkid info
551566
root_dev = _resolve_dev(self, "/")
552567
if ":" in root_dev: # only use the first device
553568
root_dev = root_dev.split(":")[0]
554569
for alt_devices in root_dev.split(":")[1:]: # But ensure kmods are loaded for all devices
555570
autodetect_mount_kmods(self, alt_devices)
556-
if root_dev not in self["_blkid_info"]:
557-
get_blkid_info(self, root_dev)
558571
_autodetect_mount(self, "/")
559572

560573

@@ -563,7 +576,8 @@ def _autodetect_mount(self, mountpoint) -> None:
563576
if mountpoint not in self["_mounts"]:
564577
raise FileNotFoundError("auto_mount mountpoint not found in host mounts: %s" % mountpoint)
565578

566-
mount_device = self["_mounts"][mountpoint]["device"]
579+
mount_device = _resolve_overlay_lower_device(self, mountpoint)
580+
567581
if ":" in mount_device: # Handle bcachefs
568582
mount_device = mount_device.split(":")[0]
569583

@@ -688,8 +702,8 @@ def _validate_host_mount(self, mount, destination_path=None) -> bool:
688702
# If a destination path is passed, like for /, use that instead of the mount's destination
689703
destination_path = str(mount["destination"]) if destination_path is None else destination_path
690704

691-
# Using the mount path, get relevant hsot mount info
692-
host_source_dev = self["_mounts"][destination_path]["device"]
705+
# Using the mount path, get relevant host mount info
706+
host_source_dev = _resolve_overlay_lower_device(self, destination_path)
693707
if ":" in host_source_dev: # Handle bcachefs
694708
host_source_dev = host_source_dev.split(":")[0]
695709
if destination_path == "/" and self["resolve_root_dev"]:

0 commit comments

Comments
 (0)