Fix PartitionTable sector representation and used space for LVM partition

This commit is contained in:
Chantara Tith 2016-06-19 02:54:52 +07:00
parent 0f3c4b0a8c
commit 542db88336
5 changed files with 110 additions and 51 deletions

View File

@ -27,10 +27,12 @@
#include <QRegularExpression>
#include <QStringList>
#include <KMountPoint>
#include <KDiskFreeSpaceInfo>
/** 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<Partition*> LvmDevice::scanPartitions(const Device& dev, PartitionTable* pTable) const
{
QList<Partition*> pList;
QList<QString> 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<QString> 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<QString> LvmDevice::deviceNodeList() const
{
QList<QString> devPathList;
@ -138,10 +153,23 @@ QList<QString> LvmDevice::deviceNodeList() const
devPathList.append(devPath.trimmed());
}
}
return devPathList;
}
QList<QString> LvmDevice::lvPathList() const
{
QList<QString> lvPathList;
QString cmdOutput = getField(QStringLiteral("lv_path"), name());
if (cmdOutput.size()) {
QList<QString> 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;
}

View File

@ -51,16 +51,21 @@ public:
QList<Partition*> 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<QString> deviceNodeList() const override;
qint64 mappedSector(const QString& lvpath, qint64 sector) const override;
QList<QString> lvPathList() const;
public:
qint32 peSize() const {
@ -85,6 +90,7 @@ private:
qint32 m_allocPE;
qint32 m_freePE;
QString m_UUID;
};
#endif

View File

@ -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<const DiskDevice&>(d);
return PartitionAlignment::sectorAlignment(diskDevice);
if (d.type() == Device::LVM_Device) {
return 0;
} else {
const DiskDevice& diskDevice = dynamic_cast<const DiskDevice&>(d);
return PartitionAlignment::sectorAlignment(diskDevice);
}
}
qint64 PartitionTable::defaultLastUsable(const Device& d, TableType t)

View File

@ -1,6 +1,5 @@
/*************************************************************************
* Copyright (C) 2008 by Volker Lanz <vl@fidra.de> *
* Copyright (C) 2016 by Andrius Štikonas <andrius@stikonas.eu> *
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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;

View File

@ -1,4 +1,6 @@
/*************************************************************************
* Copyright (C) 2016 by Chantara Tith <tith.chantara@gmail.com> *
* *
* 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 <vl@fidra.de>
*/
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<QString> 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<Partition*> listDevices() const = 0;
/** string deviceNodeList together into comma-sperated list */
virtual QString prettyDeviceNodeList() const;
/** Mapper return absolute sector representing the VG */
private:
//QMap<QString, qint32> deviceSizeMapper;
};
#endif