From 542db883361fdf2607669b16c9f8939d5116269d Mon Sep 17 00:00:00 2001 From: Chantara Tith Date: Sun, 19 Jun 2016 02:54:52 +0700 Subject: [PATCH] Fix PartitionTable sector representation and used space for LVM partition --- src/core/lvmdevice.cpp | 119 +++++++++++++++++++++---------- src/core/lvmdevice.h | 16 +++-- src/core/partitiontable.cpp | 9 ++- src/core/volumemanagerdevice.cpp | 4 +- src/core/volumemanagerdevice.h | 13 ++-- 5 files changed, 110 insertions(+), 51 deletions(-) diff --git a/src/core/lvmdevice.cpp b/src/core/lvmdevice.cpp index a54a40f..ee1f99e 100644 --- a/src/core/lvmdevice.cpp +++ b/src/core/lvmdevice.cpp @@ -27,10 +27,12 @@ #include #include #include +#include /** Constructs a representation of LVM device with functionning LV as Partition - @param name Volume Group name -*/ + * + * @param name Volume Group name + */ LvmDevice::LvmDevice(const QString& name, const QString& iconname) : VolumeManagerDevice(name, (QStringLiteral("/dev/") + name), @@ -56,77 +58,90 @@ void LvmDevice::initPartitions() foreach (Partition* p, scanPartitions(*this, pTable)) { pTable->append(p); } - setPartitionTable(pTable); } /** - return sorted Partition(LV) Array -*/ + * @returns sorted Partition(LV) Array + */ QList LvmDevice::scanPartitions(const Device& dev, PartitionTable* pTable) const { QList pList; - QList lvNodeList; - - lvNodeList = getField(QStringLiteral("lv_path"), dev.name()).split(QStringLiteral("\n")); - - foreach (QString lvNode, lvNodeList) { - pList.append(scanPartition(lvNode.trimmed(), dev, pTable)); + foreach (QString lvPath, lvPathList()) { + pList.append(scanPartition(lvPath, dev, pTable)); } - return pList; } /** - return sorted Partition(LV) Array -*/ -Partition* LvmDevice::scanPartition(const QString& lvPath, const Device& dev, PartitionTable* pTable) const + * @returns sorted Partition(LV) Array + */ +Partition* LvmDevice::scanPartition(const QString& lvpath, const Device& dev, PartitionTable* pTable) const { + /* + * NOTE: + * LVM partition have 2 different start and end sector value + * 1. representing the actual LV start from 0 -> size of LV - 1 + * 2. representing abstract LV's sector inside a VG partitionTable + * start from size of last Partitions -> size of LV - 1 + * Reason for this is for the LV Partition to worrks nicely with other parts of the codebase + * without too many special cases. + */ + qint64 startSector; qint64 endSector; + qint64 lvSize; + + bool mounted = isMounted(lvpath); QString mountPoint = QString(); - bool mounted = isMounted(lvPath); KMountPoint::List mountPointList = KMountPoint::currentMountPoints(KMountPoint::NeedRealDeviceName); mountPointList.append(KMountPoint::possibleMountPoints(KMountPoint::NeedRealDeviceName)); - mountPoint = mountPointList.findByDevice(lvPath) ? - mountPointList.findByDevice(lvPath)->mountPoint() : + mountPoint = mountPointList.findByDevice(lvpath) ? + mountPointList.findByDevice(lvpath)->mountPoint() : QString(); - ExternalCommand cmd(QStringLiteral("lvm"), - { QStringLiteral("lvdisplay"), - QStringLiteral("--units"), - QStringLiteral("B"), - QStringLiteral("--maps"), - lvPath}); + lvSize = getTotalLE(lvpath); + startSector = mappedSector(lvpath,0); + endSector = startSector + (lvSize - 1); - if (cmd.run(-1) && cmd.exitCode() == 0) { + const KDiskFreeSpaceInfo freeSpaceInfo = KDiskFreeSpaceInfo::freeSpaceInfo(mountPoint); - //TODO: regex for first and last sector of the LV - //TODO: stringing PE into one large contingiuous array of PE ?? - QRegularExpression re(QStringLiteral("Physical extents\\h+(\\d+)\\sto\\s(\\d+)")); - QRegularExpressionMatch match = re.match(cmd.output()); - if (match.hasMatch()) { - startSector = match.captured(1).toLongLong(); - endSector = match.captured(2).toLongLong(); - } + FileSystem* fs = FileSystemFactory::create(FileSystem::detectFileSystem(lvpath), 0, lvSize - 1); + if (mounted && freeSpaceInfo.isValid() && mountPoint != QString()) { + //TODO: fix used space report. currently incorrect + fs->setSectorsUsed(freeSpaceInfo.used() / logicalSize()); } - FileSystem* fs = FileSystemFactory::create(FileSystem::detectFileSystem(lvPath), startSector, endSector); - Partition* part = new Partition(pTable, dev, PartitionRole(PartitionRole::Lvm_Lv), fs, startSector, endSector, - lvPath, + lvpath, PartitionTable::Flag::FlagLvm, mountPoint, mounted); return part; } +qint64 LvmDevice::mappedSector(const QString& lvpath, qint64 sector) const +{ + qint64 mSector = 0; + QList lvpathList = lvPathList(); + qint32 devIndex = lvpathList.indexOf(lvpath); + + if (devIndex) { + for (int i = 0; i < devIndex; i++) { + //TODO: currently going over the same LV again and again is wasteful. Could use some more optimization + mSector += getTotalLE(lvpathList[i]); + } + mSector += sector; + } + return mSector; +} + QList LvmDevice::deviceNodeList() const { QList devPathList; @@ -138,10 +153,23 @@ QList LvmDevice::deviceNodeList() const devPathList.append(devPath.trimmed()); } } - return devPathList; } +QList LvmDevice::lvPathList() const +{ + QList lvPathList; + QString cmdOutput = getField(QStringLiteral("lv_path"), name()); + + if (cmdOutput.size()) { + QList tempPathList = cmdOutput.split(QStringLiteral("\n"), QString::SkipEmptyParts); + foreach(QString lvPath, tempPathList) { + lvPathList.append(lvPath.trimmed()); + } + } + return lvPathList; +} + qint32 LvmDevice::getPeSize(const QString& vgname) { QString val = getField(QStringLiteral("vg_extent_size"), vgname); @@ -171,6 +199,7 @@ QString LvmDevice::getUUID(const QString& vgname) return val.isEmpty() ? QStringLiteral("---") : val; } + /** Query LVM details with field name * * @param fieldName lvm field name @@ -196,3 +225,19 @@ QString LvmDevice::getField(const QString& fieldName, const QString& vgname) } return QString(); } + +qint32 LvmDevice::getTotalLE(const QString& lvpath) +{ + ExternalCommand cmd(QStringLiteral("lvm"), + { QStringLiteral("lvdisplay"), + lvpath}); + + if (cmd.run(-1) && cmd.exitCode() == 0) { + QRegularExpression re(QStringLiteral("Current LE\\h+(\\d+)")); + QRegularExpressionMatch match = re.match(cmd.output()); + if (match.hasMatch()) { + return match.captured(1).toInt(); + } + } + return -1; +} diff --git a/src/core/lvmdevice.h b/src/core/lvmdevice.h index 47ab17d..d352be6 100644 --- a/src/core/lvmdevice.h +++ b/src/core/lvmdevice.h @@ -51,16 +51,21 @@ public: QList scanPartitions(const Device& dev, PartitionTable* pTable) const; Partition* scanPartition(const QString& lvPath, const Device& dev, PartitionTable* pTable) const; - static qint32 getPeSize(const QString& name); - static qint32 getTotalPE(const QString& name); - static qint32 getAllocatedPE(const QString& name); - static qint32 getFreePE(const QString& name); - static QString getUUID(const QString& name); + static qint32 getPeSize(const QString& vgname); + static qint32 getTotalPE(const QString& vgname); + static qint32 getAllocatedPE(const QString& vgname); + static qint32 getFreePE(const QString& vgname); + static QString getUUID(const QString& vgname); static QString getField(const QString& fieldName, const QString& vgname = QString()); + static qint32 getTotalLE(const QString& lvpath); + protected: void initPartitions(); QList deviceNodeList() const override; + qint64 mappedSector(const QString& lvpath, qint64 sector) const override; + + QList lvPathList() const; public: qint32 peSize() const { @@ -85,6 +90,7 @@ private: qint32 m_allocPE; qint32 m_freePE; QString m_UUID; + }; #endif diff --git a/src/core/partitiontable.cpp b/src/core/partitiontable.cpp index e19554b..53e23c7 100644 --- a/src/core/partitiontable.cpp +++ b/src/core/partitiontable.cpp @@ -266,6 +266,7 @@ bool PartitionTable::getUnallocatedRange(const Device& d, PartitionNode& parent, return end - start + 1 >= PartitionAlignment::sectorAlignment(device); } else if (d.type() == Device::LVM_Device) { return false; + //TODO: return range from last LE to last allocated LE } return false; } @@ -378,8 +379,12 @@ void PartitionTable::updateUnallocated(const Device& d) qint64 PartitionTable::defaultFirstUsable(const Device& d, TableType t) { Q_UNUSED(t) - const DiskDevice& diskDevice = dynamic_cast(d); - return PartitionAlignment::sectorAlignment(diskDevice); + if (d.type() == Device::LVM_Device) { + return 0; + } else { + const DiskDevice& diskDevice = dynamic_cast(d); + return PartitionAlignment::sectorAlignment(diskDevice); + } } qint64 PartitionTable::defaultLastUsable(const Device& d, TableType t) diff --git a/src/core/volumemanagerdevice.cpp b/src/core/volumemanagerdevice.cpp index 255c692..d110708 100644 --- a/src/core/volumemanagerdevice.cpp +++ b/src/core/volumemanagerdevice.cpp @@ -1,6 +1,5 @@ /************************************************************************* - * Copyright (C) 2008 by Volker Lanz * - * Copyright (C) 2016 by Andrius Štikonas * + * Copyright (C) 2016 by Chantara Tith * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * @@ -43,6 +42,7 @@ QString VolumeManagerDevice::prettyDeviceNodeList() const } if (rval.size()) { + //chop off the trailing colon rval.chop(1); } return rval; diff --git a/src/core/volumemanagerdevice.h b/src/core/volumemanagerdevice.h index da5764f..89ae87c 100644 --- a/src/core/volumemanagerdevice.h +++ b/src/core/volumemanagerdevice.h @@ -1,4 +1,6 @@ /************************************************************************* + * Copyright (C) 2016 by Chantara Tith * + * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * @@ -30,14 +32,13 @@ class CoreBackend; class SmartStatus; class Partition; -/** A device. +/** A abstract device represeting real physical devices. - Represents a device like /dev/sda. + Represents a device like /dev/sda, /dev/sdb1. Devices are the outermost entity; they contain a PartitionTable that itself contains Partitions. @see PartitionTable, Partition - @author Volker Lanz */ class LIBKPMCORE_EXPORT VolumeManagerDevice : public Device { @@ -46,13 +47,15 @@ class LIBKPMCORE_EXPORT VolumeManagerDevice : public Device protected: VolumeManagerDevice(const QString& name, const QString& devicenode, const qint32 logicalSize, const qint64 totalLogical, const QString& iconname = QString(), Device::Type type = Device::Unknown_Device); virtual QList deviceNodeList() const = 0; /** Return list of physical device or partitions that makes up volumeManagerDevice */ + virtual qint64 mappedSector(const QString& devNode, qint64 sector) const = 0; public: - //virtual void refresh() const = 0; /* VG infos can be changed, unlike disk_device */ - //virtual Qlist listDevices() const = 0; + /** string deviceNodeList together into comma-sperated list */ virtual QString prettyDeviceNodeList() const; + /** Mapper return absolute sector representing the VG */ private: + //QMap deviceSizeMapper; }; #endif