File indexing completed on 2024-05-05 05:48:52

0001 /*
0002     SPDX-FileCopyrightText: 2016 Chantara Tith <tith.chantara@gmail.com>
0003     SPDX-FileCopyrightText: 2016-2020 Andrius Štikonas <andrius@stikonas.eu>
0004 
0005     SPDX-License-Identifier: GPL-3.0-or-later
0006 */
0007 
0008 #include "ops/resizevolumegroupoperation.h"
0009 
0010 #include "core/lvmdevice.h"
0011 #include "core/partition.h"
0012 #include "fs/lvm2_pv.h"
0013 #include "jobs/resizevolumegroupjob.h"
0014 #include "jobs/movephysicalvolumejob.h"
0015 #include "util/helpers.h"
0016 
0017 #include <utility>
0018 
0019 #include <QString>
0020 
0021 #include <KLocalizedString>
0022 
0023 /** Creates a new ResizeVolumeGroupOperation.
0024     @param d the Device to create the new PartitionTable on
0025     @param partList list of LVM Physical Volumes that should be in LVM Volume Group
0026 */
0027 ResizeVolumeGroupOperation::ResizeVolumeGroupOperation(LvmDevice& d, const QVector<const Partition*>& partList)
0028     : Operation()
0029     , m_Device(d)
0030     , m_TargetList(partList)
0031     , m_CurrentList(d.physicalVolumes())
0032     , m_TargetSize(0)
0033     , m_CurrentSize(0)
0034     , m_GrowVolumeGroupJob(nullptr)
0035     , m_ShrinkVolumeGroupJob(nullptr)
0036     , m_MovePhysicalVolumeJob(nullptr)
0037 {
0038     for (const auto &p : targetList())
0039         m_TargetSize += p->capacity();
0040     for (const auto &p : currentList())
0041         m_CurrentSize += p->capacity();
0042 
0043     QList<const Partition*> toRemoveList;
0044     for (const auto &p : currentList())
0045         if (!targetList().contains(p))
0046             toRemoveList.append(p);
0047 
0048     QList<const Partition*> toInsertList;
0049     for (const auto &p : targetList())
0050         if (!currentList().contains(p))
0051             toInsertList.append(p);
0052 
0053     qint64 currentFreePE = 0;
0054     for (const auto &p : currentList()) {
0055         FS::lvm2_pv *lvm2PVFs;
0056         innerFS(p, lvm2PVFs);
0057         currentFreePE += lvm2PVFs->freePE();
0058     }
0059     qint64 removedFreePE = 0;
0060     for (const auto &p : std::as_const(toRemoveList)) {
0061         FS::lvm2_pv *lvm2PVFs;
0062         innerFS(p, lvm2PVFs);
0063         removedFreePE += lvm2PVFs->freePE();
0064     }
0065     qint64 freePE = currentFreePE - removedFreePE;
0066     qint64 movePE = 0;
0067     for (const auto &p : std::as_const(toRemoveList)) {
0068         FS::lvm2_pv *lvm2PVFs;
0069         innerFS(p, lvm2PVFs);
0070         movePE += lvm2PVFs->allocatedPE();
0071     }
0072     qint64 growPE = 0;
0073     for (const auto &p : std::as_const(toInsertList)) {
0074         growPE += p->capacity() / device().peSize();
0075     }
0076 
0077     if ( movePE > (freePE + growPE)) {
0078         // *ABORT* can't move
0079     } else if (partList == currentList()) {
0080         // *DO NOTHING*
0081     } else {
0082         if (!toInsertList.isEmpty()) {
0083             m_GrowVolumeGroupJob = new ResizeVolumeGroupJob(d, toInsertList, ResizeVolumeGroupJob::Type::Grow);
0084             addJob(growVolumeGroupJob());
0085         }
0086         if (!toRemoveList.isEmpty()) {
0087             m_MovePhysicalVolumeJob = new MovePhysicalVolumeJob(d, toRemoveList);
0088             m_ShrinkVolumeGroupJob = new ResizeVolumeGroupJob(d, toRemoveList, ResizeVolumeGroupJob::Type::Shrink);
0089             addJob(movePhysicalVolumeJob());
0090             addJob(shrinkvolumegroupjob());
0091         }
0092     }
0093 }
0094 
0095 QString ResizeVolumeGroupOperation::description() const
0096 {
0097     QString tList = QString();
0098     for (const auto &p : targetList()) {
0099         tList += p->deviceNode() + QStringLiteral(", ");
0100     }
0101     tList.chop(2);
0102     QString curList = QString();
0103     for (const auto &p : currentList()) {
0104         curList += p->deviceNode() + QStringLiteral(", ");
0105     }
0106     curList.chop(2);
0107 
0108     return xi18nc("@info/plain", "Resize volume %1 from %2 to %3", device().name(), curList, tList);
0109 }
0110 
0111 bool ResizeVolumeGroupOperation::targets(const Device& d) const
0112 {
0113     return d == device();
0114 }
0115 
0116 bool ResizeVolumeGroupOperation::targets(const Partition& p) const
0117 {
0118     for (const auto &partition : targetList()) {
0119         if (partition->partitionPath() == p.partitionPath()) {
0120             return true;
0121         }
0122     }
0123     return false;
0124 }
0125 
0126 void ResizeVolumeGroupOperation::preview()
0127 {
0128     //assuming that targetSize is larger than the allocated space.
0129     device().setTotalLogical(targetSize() / device().logicalSize());
0130     device().partitionTable()->setFirstUsableSector(PartitionTable::defaultFirstUsable(device(), PartitionTable::vmd));
0131     device().partitionTable()->setLastUsableSector(PartitionTable::defaultLastUsable(device(), PartitionTable::vmd));
0132     device().partitionTable()->updateUnallocated(device());
0133 }
0134 
0135 void ResizeVolumeGroupOperation::undo()
0136 {
0137     device().setTotalLogical(currentSize() / device().logicalSize());
0138     device().partitionTable()->setFirstUsableSector(PartitionTable::defaultFirstUsable(device(), PartitionTable::vmd));
0139     device().partitionTable()->setLastUsableSector(PartitionTable::defaultLastUsable(device(), PartitionTable::vmd));
0140     device().partitionTable()->updateUnallocated(device());
0141 }