From f3782300d2ebd4a70c594f1eb12a7d79de4b9602 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 17 Jan 2024 11:43:28 -0800 Subject: [PATCH] QStorageInfo/Linux: fix getting information on unmounted btrfs subvols Amends 1cd6c6c69e9813c791f8bebb6c0c9214ce765060. Btrfs can have subvolumes and each one of them is assigned a device ID when the filesystem is loaded into the kernel. But subvolumes don't all have to be a mountpoint of their own: if we insist on matching device IDs, as initRootPath() was doing, we'd fail at finding the mount point. Fixes: QTBUG-121140 Change-Id: I76ffba14ece04f24b43efffd17ab39f503000dd7 Reviewed-by: Edward Welbourne Reviewed-by: Ahmad Samir (cherry picked from commit 987abb92538f8657d861611b1ced4e7eaa660adf) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/io/qstorageinfo_linux.cpp | 28 ++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/corelib/io/qstorageinfo_linux.cpp b/src/corelib/io/qstorageinfo_linux.cpp index 1b2b0adcb04..7d8a5a293d3 100644 --- a/src/corelib/io/qstorageinfo_linux.cpp +++ b/src/corelib/io/qstorageinfo_linux.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include #include @@ -199,15 +201,31 @@ quint64 QStorageInfoPrivate::initRootPath() // # mount | tail -2 // tmpfs on /tmp/foo/bar type tmpfs (rw,relatime,inode64) // tmpfs on /tmp/foo type tmpfs (rw,relatime,inode64) - // But just in case there's a mount --move, we ensure the device ID does - // match. + // + // We try to match the device ID in case there's a mount --move. + // We can't *rely* on it because some filesystems like btrfs will assign + // device IDs to subvolumes that aren't listed in /proc/self/mountinfo. + const QString oldRootPath = std::exchange(rootPath, QString()); const dev_t rootPathDevId = deviceIdForPath(oldRootPath); + MountInfo *best = nullptr; for (auto it = infos.rbegin(); it != infos.rend(); ++it) { - if (rootPathDevId != it->stDev || !isParentOf(it->mountPoint, oldRootPath)) + if (!isParentOf(it->mountPoint, oldRootPath)) continue; - auto stDev = it->stDev; - setFromMountInfo(std::move(*it)); + if (rootPathDevId == it->stDev) { + // device ID matches; this is definitely the best option + best = q20::to_address(it); + break; + } + if (!best) { + // if we can't find a device ID match, this parent path is probably + // the correct one + best = q20::to_address(it); + } + } + if (best) { + auto stDev = best->stDev; + setFromMountInfo(std::move(*best)); return stDev; } return 0;