[PATCH] libfrog: obtain the actual available device when the root device is /dev/root

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When starting a Fedora virtual machine using QEMU, if the device corresponding
to the root directory is the entire disk or a disk partition, the device
recorded in /proc/self/mounts will be /dev/root instead of the true device.

This can lead to the failure of executing commands such as xfs_growfs/xfs_info.

$ cat /proc/self/mounts
/dev/root / xfs rw,seclabel,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota 0 0
devtmpfs /dev devtmpfs rw,seclabel,relatime,size=4065432k,nr_inodes=1016358,mode=755 0 0
...

$ mount
/dev/sda3 on / type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
devtmpfs on /dev type devtmpfs (rw,relatime,seclabel,size=4065432k,nr_inodes=1016358,mode=755)
...

$ xfs_growfs /
xfs_growfs: / is not a mounted XFS filesystem

$ xfs_growfs /dev/sda3
xfs_growfs: /dev/sda3 is not a mounted XFS filesystem

$ xfs_info /
/: cannot find mount point.#

So, if the root device is found to be /dev/root, we need to obtain the
corresponding real device first.

Signed-off-by: Wu Guanghao <wuguanghao3@xxxxxxxxxx>
---
 libfrog/paths.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/libfrog/paths.c b/libfrog/paths.c
index a5dfab48..6ff649b8 100644
--- a/libfrog/paths.c
+++ b/libfrog/paths.c
@@ -352,6 +352,38 @@ out_nomem:
 	return ENOMEM;
 }

+static char *get_real_root_device(struct mntent *mnt)
+{
+	struct stat st;
+	char path[PATH_MAX], linkpath[PATH_MAX];
+	ssize_t len;
+	char *fake_root_device = "/dev/root";
+	/*
+	 * The /dev/root does not point to a real root device, we need to obtain the
+	 * real device.
+	 */
+	if (strlen(mnt->mnt_fsname) != strlen(fake_root_device) ||
+	    strcmp(mnt->mnt_fsname, fake_root_device))
+		return NULL;
+
+	if (stat(mnt->mnt_dir, &st) < 0)
+		return NULL;
+
+	snprintf(path, sizeof(path), "/sys/dev/block/%d:%d", major(st.st_dev), minor(st.st_dev));
+	len = readlink(path, linkpath, sizeof(linkpath) - 1);
+	if (len < 0 || len >= PATH_MAX)
+		return NULL;
+
+	linkpath[len] = '\0';
+
+	char *p = strrchr(linkpath, '/');
+	if (!p || strlen(p) <= 1)
+		return NULL;
+
+	snprintf(path, sizeof(path), "/dev/%s", p + 1);
+	return strdup(path);
+}
+
 /*
  * If *path is NULL, initialize the fs table with all xfs mount points in mtab
  * If *path is specified, search for that path in mtab
@@ -359,6 +391,7 @@ out_nomem:
  * Everything - path, devices, and mountpoints - are boiled down to realpath()
  * for comparison, but fs_table is populated with what comes from getmntent.
  */
+
 static int
 fs_table_initialise_mounts(
 	char		*path)
@@ -368,6 +401,8 @@ fs_table_initialise_mounts(
 	char		*fslog, *fsrt;
 	int		error, found;
 	char		rpath[PATH_MAX], rmnt_fsname[PATH_MAX], rmnt_dir[PATH_MAX];
+	bool		change_device = false;
+	char		*fsname = NULL;

 	error = found = 0;
 	fslog = fsrt = NULL;
@@ -391,6 +426,13 @@ fs_table_initialise_mounts(
 			continue;
 		if (!realpath(mnt->mnt_dir, rmnt_dir))
 			continue;
+
+		fsname = get_real_root_device(mnt);
+		if (fsname) {
+			change_device = true;
+			mnt->mnt_fsname = fsname;
+		}
+
 		if (!realpath(mnt->mnt_fsname, rmnt_fsname))
 			continue;

@@ -402,6 +444,12 @@ fs_table_initialise_mounts(
 			continue;
 		(void) fs_table_insert(mnt->mnt_dir, 0, FS_MOUNT_POINT,
 					mnt->mnt_fsname, fslog, fsrt);
+
+		if (change_device) {
+			free(fsname);
+			change_device = false;
+		}
+
 		if (path) {
 			found = 1;
 			break;
-- 
2.51.0





[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux