gparted/include/GParted_Core.h

251 lines
12 KiB
C
Raw Normal View History

/* Copyright (C) 2004 Bart
* Copyright (C) 2008, 2009, 2010, 2011, 2012 Curtis Gedak
*
* 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 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GPARTED_GPARTED_CORE_H
#define GPARTED_GPARTED_CORE_H
#include "BlockSpecial.h"
#include "Device.h"
#include "FileSystem.h"
#include "Operation.h"
#include "Partition.h"
#include "PartitionLUKS.h"
#include "PartitionVector.h"
#include "SupportedFileSystems.h"
#include "Utils.h"
#include <parted/parted.h>
#include <vector>
#include <fstream>
#include <glibmm/thread.h>
#include <glibmm/ustring.h>
namespace GParted
{
class GParted_Core
{
Add initial unit test of erase_filesystem_signatures() (#220) Initially just testing erasing of Intel Software RAID signatures. Chosen because it was expected to work, but turned out not to be true in all cases. The code needs to initialise GParted_Core::mainthread, construct Gtk::Main() and execute xvfb-run because of this call chain: GParted_Core::erase_filesystem_signatures() GParted_Core::settle_device() Utils::execute_command ("udevadm settle ...") status.foreground = (Glib::Thread::self() == GParted_Core::mainthread) Gtk::Main::run() This was also needed when testing file system interface classes as discussed in commits [1][2]. The test fails like this: $ ./test_EraseFileSystemSignatures ... [ RUN ] EraseFileSystemSignaturesTest.IntelSoftwareRAIDAligned [ OK ] EraseFileSystemSignaturesTest.IntelSoftwareRAIDAligned (155 ms) [ RUN ] EraseFileSystemSignaturesTest.IntelSoftwareRAIDUnaligned test_EraseFileSystemSignatures.cc:286: Failure Failed image_contains_all_zeros(): First non-zero bytes: 0x00001A00 "Intel Raid ISM C" 49 6E 74 65 6C 20 52 61 69 64 20 49 53 4D 20 43 test_EraseFileSystemSignatures.cc:320: Failure Value of: image_contains_all_zeros() Actual: false Expected: true [ FAILED ] EraseFileSystemSignaturesTest.IntelSoftwareRAIDUnaligned (92 ms) Manually write the same test image: $ python << 'EOF' signature = b'Intel Raid ISM Cfg Sig. ' import os fd = os.open('/tmp/test.img', os.O_CREAT|os.O_WRONLY) os.ftruncate(fd, 16*1024*1024 - 512) os.lseek(fd, -(2*512), os.SEEK_END) os.write(fd, signature) os.close(fd) EOF Run gpartedbin /tmp/test.img and Format to > Cleared. GParted continues to display the the image file as containing an ataraid signature. $ blkid /tmp/test.img /tmp/test.img: TYPE="isw_raid_member" $ hexdump -C /tmp/test.img 00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00fffa00 49 6e 74 65 6c 20 52 61 69 64 20 49 53 4d 20 43 |Intel Raid ISM C| 00fffa10 66 67 20 53 69 67 2e 20 00 00 00 00 00 00 00 00 |fg Sig. ........| 00fffa20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00fffe00 This signature is not being cleared when the device/partition/image size is 512 bytes smaller than a whole MiB because the last 3.5 KiB is left unwritten. This is because the last block of zeros written is 8 KiB aligned to 4 KiB at the end of the device. [1] a97c23c57c693b77724970d2f99702d7be18b4bc Add initial create ext2 only FileSystem interface class test (!49) [2] 8db9a83b39b82785dcbcc776ac259aa7986c0955 Run test program under xvfb-run to satisfy need for an X11 display (!49) Closes #220 - Format to Cleared not clearing "pdc" ataraid signature
2023-02-04 08:36:37 -07:00
friend class EraseFileSystemSignaturesTest; // To allow unit testing to call private
// method.
public:
static Glib::Thread *mainthread;
GParted_Core() ;
~GParted_Core() ;
static Glib::ustring get_version_and_config_string();
static void find_supported_core();
void find_supported_filesystems() ;
void set_user_devices( const std::vector<Glib::ustring> & user_devices ) ;
void set_devices( std::vector<Device> & devices ) ;
void set_devices_thread( std::vector<Device> * pdevices );
Separate partition alignment from validation (#48) PATCHSET OVERVIEW A user had 2 adjacent partitions which were aligned to multiples of 33553920 bytes (32 MiB - 512 bytes), not MiB or cylinders. As far as GParted is concerned this is not aligned. The second partition contained closed LUKS encrypted data. Recreate this setup with: # truncate -s 200G /tmp/disk.img # losetup -f --show /tmp/disk.img /dev/loop0 # sfdisk -u S /dev/loop0 << EOF 65535 2162655 83 2228190 78904140 83 EOF # partprobe /dev/loop0 # echo -n badpassword | cryptsetup luksFormat /dev/loop0p2 - When trying to move the second LUKS encrypted partition to the right by any amount, with the default MiB alignment, GParted displays this error dialog and fails to even queue the operation: Could not add this operation to the list A partition with used sectors (78907392) greater than its length (78905344) is not valid [ OK ] Overview of the steps involved: 1. The Resize/Move dialog composed a new partition to start a whole multiple of MiB after the end of the previous non-aligned partition. The new partition also had it's size increased to a whole multiple of MiB, to 78907392 sectors (38529 MiB) which was 1.59 MiB larger than before. Neither the start or end of the new partition are aligned at this point. 2. Win_GParted::activate_resize() applied the change back to the closed LUKS partition object, additionally making the used sectors equal to the partition size. (To match the fact that when opened the LUKS mapping it will automatically fill the new larger partition size). 3. GParted_Core::snap_to_mebibyte() then aligned the partition start and end to whole MiB boundaries, reducing the partition size in the process to 78905344 (38528 MiB). 4. GParted_Core::snap_to_alignment() reported the error saying that it couldn't add the operation to the list because it was invalid to have the file system used sectors larger than the partition size. Fix this by having the snap to alignment adjustments applied before the dialogs update any associated file system usage. Specifically the Resize/Move, Paste (into new) and Create New dialogs as these are the only ones which either create or modify partition boundaries. Validation done by snap_to_alignment() will continue to occur at the current point when the operation is added to the list. THIS COMMIT snap_to_alignment() is doing two different jobs, it is (1) optionally adjusting the new partition boundaries for MiB or Cylinder alignment; and (2) checking that the partition boundaries and file system usage are valid. Split those into two different functions (1) snap_to_alignment() and (2) valid_partition(). For now valid_partition() still calls snap_to_alignment() so there is no functional change with this commit. Closes #48 - Error when moving locked LUKS-encrypted partition
2019-05-08 09:29:13 -06:00
bool valid_partition(const Device& device, Partition& partition, Glib::ustring& error);
bool apply_operation_to_disk( Operation * operation );
bool set_disklabel( const Device & device, const Glib::ustring & disklabel );
Fix failure to recognise whole disk file systems in certain cases (#743181) When the following conditions were met GParted would fail to recognise a newly created whole disk device file system, and instead show an unknown file system filling the disk: 1) Disk was previously partitioned and contained at least one partition. 2) Using libparted version 2.0 to 3.0 inclusive. Initial status: # blkid | fgrep sdc # fgrep sdc /proc/partitions 8 32 976762584 sdc 8 33 104857600 sdc1 # parted /dev/sdc GNU Parted 2.4 Using /dev/sdc Welcome to GNU Parted! Type 'help' to view a list of commands. (parted) print Model: ATA ST1000LM024 HN-M (scsi) Disk /dev/sdc: 1000GB Sector size (logical/physical): 512B/4096B Partition Table: msdos Number Start End Size Type File system Flags 1 1049kB 107GB 107GB primary When creating the loop partition table libparted would not inform the kernel to delete the old partitions. /proc/partitions still contained the details of the old partitions. (parted) mktable loop Warning: The existing disk label on /dev/sdc will be destroyed and all data on this disk will be lost. Do you want to continue? Yes/No? Yes (parted) print Model: ATA ST1000LM024 HN-M (scsi) Disk /dev/sdc: 1000GB Sector size (logical/physical): 512B/4096B Partition Table: loop Number Start End Size File system Flags (parted) quit # fgrep sdc /proc/partitions 8 32 976762584 sdc 8 33 104857600 sdc1 Creation of the whole disk device file system goes unnoticed by blkid because the kernel and therefore blkid's cache have stale partition information. # mkfs.xfs -f /dev/sdc # blkid | fgrep sdc NOTE: On a Linux Software RAID array, as opposed to a hard disk, blkid does notice creation of the whole disk device file system. However the kernel still has old partition details. This was fixed in libparted 3.1 by commit: http://git.savannah.gnu.org/cgit/parted.git/commit/?id=f5c909c0cd50ed52a48dae6d35907dc08b137e88 libparted: remove has_partitions check to allow loopback partitions Fix by deleting old partitions before creating the loop table when compiled with a broken version of libparted. The GParted UI provides no feedback while a new partition table is created, and with some versions of GTK the UI become unresponsive too, so it is important to be as fast as possible. Evaluated three different methods, deleting 15 and 22 MSDOS partitions on a physical 5400 RPM hard drive using libparted 2.4: M1) Delete and commit one partition at a time. Takes up to 24 seconds to delete 15 partitions. With 22 partitions libparted always reports finding some of the partitions busy and unable to inform the kernel about the modifications. Too slow and doesn't work. M2) Delete all partitions in one go and commit once. Takes up to 1.4 seconds to delete either 15 or 22 partitions. Never removes partitions 17 and higher from the kernel. Doesn't work. M3) Write GPT table (letting libparted delete any old partitions). Takes up to 0.8 seconds to delete either 15 or 22 partitions. Fast and works. Use method 3 - write a GPT table thus using libparted code to inform the kernel of the old partition deletions. Bug 743181 - Add unpartitioned drive read-write support
2015-02-21 09:43:42 -07:00
bool new_disklabel( const Glib::ustring & device_path, const Glib::ustring & disklabel,
bool recreate_dmraid_devs = true );
bool toggle_flag( const Partition & partition, const Glib::ustring & flag, bool state ) ;
const std::vector<FS> & get_filesystems() const ;
const FS& get_fs(FSType fstype) const;
static std::vector<Glib::ustring> get_disklabeltypes() ;
std::map<Glib::ustring, bool> get_available_flags( const Partition & partition ) ;
Glib::ustring get_thread_status_message() ;
static FileSystem * get_filesystem_object( FSType fstype );
static bool supported_filesystem( FSType fstype );
static FS_Limits get_filesystem_limits( FSType fstype, const Partition & partition );
static bool filesystem_resize_disallowed( const Partition & partition ) ;
static void insert_unallocated( const Glib::ustring & device_path,
PartitionVector & partitions,
Sector start,
Sector end,
Byte_Value sector_size,
bool inside_extended );
private:
//detectionstuff..
void set_thread_status_message( Glib::ustring msg ) ;
static Glib::ustring get_partition_path(const PedPartition *lp_partition);
void set_device_from_disk( Device & device, const Glib::ustring & device_path );
void set_device_serial_number( Device & device );
void set_device_partitions( Device & device, PedDevice* lp_device, PedDisk* lp_disk ) ;
void set_device_one_partition( Device & device, PedDevice * lp_device, FSType fstype,
std::vector<Glib::ustring> & messages );
void set_luks_partition( PartitionLUKS & partition );
void set_partition_label_and_uuid( Partition & partition );
static FSType detect_filesystem_in_encryption_mapping(const Glib::ustring& path,
std::vector<Glib::ustring>& messages);
static FSType detect_filesystem_internal(const Glib::ustring& path, Byte_Value sector_size);
static FSType detect_filesystem(const PedDevice *lp_device, const PedPartition *lp_partition,
std::vector<Glib::ustring> &messages);
void read_label( Partition & partition ) ;
void read_uuid( Partition & partition ) ;
void set_mountpoints( Partition & partition );
bool set_mountpoints_helper( Partition & partition, const Glib::ustring & path );
bool is_busy(const Glib::ustring& device_path, FSType fstype, const Glib::ustring& partition_path);
void set_used_sectors( Partition & partition, PedDisk* lp_disk );
Fix false usage figures for busy SWRAID members (#27) Create an active Linux Software RAID member which is larger than /dev virtual file system and GParted will report the usage figure of the /dev virtual file system for the SWRAID member. # df -h /dev Filesystem Size Used Avail Use% Mounted on devtmpfs 732M 0 732M 0% /dev # sgdisk -n 1:1M:+1G /dev/sdb # mdadm --create --verbose /dev/md1 --level=linear --raid-devices=1 --force /dev/sdb1 mdadm: Defaulting to version 1.2 metadata mdadm: array /dev/md1 started. GParted reports the usage of /dev/sdb1 as: Partition Mount Point Size Used Unused Unallocated /dev/sdb1 /dev/md1 1.00GiB 0.00B 731.04MiB 292.96MiB However GParted should have reported the usage as "---" for unknown because it isn't coded to query the size of the SWRAID member within a partition. The fault has been bisected to this commit: Extend un/mounting and usage reporting to unsupported file systems (!13) 95903efb1f284f3d6819f38e894dc6c3464b2183 What happens for busy Linux Software RAID array members: * GParted_Core::is_busy() has custom code to identify busy members. * GParted_Core::set_mountpoints() has custom code to add the array device name as the "mount point" of the member. * GParted_Core::set_used_sectors() falls into the else not a supported file system (because SWRAID doesn't have a derived FileSystem implementation class). * GParted_Core::mounted_set_used_sectors() is called to get the file system usage of mounted, but unsupported file systems, such as UFS and any others. * Utils::get_mounted_filesystem_usage() is called which queries the kernel using statvfs() and gets the file system usage of the /dev virtual file system because the array device name will always start /dev. Fix by ensuring that GParted only asks the kernel for the usage of paths which it knows are mount points of mounted file systems. (As read from /proc/mounts and cached in the Mount_Info module). Also rename the method, by inserting "_fs", to mounted_fs_set_used_sectors() to remind us that it is for mounted *file systems* only. Closes #27 - GParted may report incorrect usage for SWRAID partitions instead of unknown S
2018-11-18 05:41:56 -07:00
void mounted_fs_set_used_sectors(Partition& partition);
#ifdef HAVE_LIBPARTED_FS_RESIZE
void LP_set_used_sectors( Partition & partition, PedDisk* lp_disk ) ;
#endif
void set_flags( Partition & partition, PedPartition* lp_partition ) ;
//operationstuff...
bool create( Partition & new_partition, OperationDetail & operationdetail );
bool create_partition( Partition & new_partition, OperationDetail & operationdetail, Sector min_size = 0 ) ;
bool create_filesystem( const Partition & partition, OperationDetail & operationdetail ) ;
bool format( const Partition & partition, OperationDetail & operationdetail ) ;
bool delete_partition( const Partition & partition, OperationDetail & operationdetail );
bool remove_filesystem( const Partition & partition, OperationDetail & operationdetail ) ;
bool label_filesystem( const Partition & partition, OperationDetail & operationdetail );
bool name_partition( const Partition & partition, OperationDetail & operationdetail );
bool change_filesystem_uuid( const Partition & partition, OperationDetail & operation_detail );
bool resize_move( const Partition & partition_old,
Partition & partition_new,
OperationDetail & operationdetail );
bool move( const Partition & partition_old,
const Partition & partition_new,
OperationDetail & operationdetail );
bool move_filesystem( const Partition & partition_old,
const Partition & partition_new,
OperationDetail & operationdetail ) ;
#ifdef HAVE_LIBPARTED_FS_RESIZE
bool resize_move_filesystem_using_libparted( const Partition & partition_old,
const Partition & partition_new,
OperationDetail & operationdetail ) ;
void thread_lp_ped_file_system_resize( PedFileSystem * fs,
PedGeometry * lp_geom,
bool * return_value );
#endif
bool resize( const Partition & partition_old,
const Partition & partition_new,
OperationDetail & operationdetail ) ;
bool resize_encryption( const Partition & partition_old,
const Partition & partition_new,
OperationDetail & operationdetail );
bool resize_plain( const Partition & partition_old,
const Partition & partition_new,
OperationDetail & operationdetail );
bool resize_move_partition( const Partition & partition_old,
Implement rollback of failed partition resize/move steps (#791875) Even after implementing a fix for bug 790418 "Unable to inform the kernel of the change message may lead to corrupted partition table" GParted/libparted can still encounter errors informing the kernel of the new partition layout. This has been seen with GParted on CentOS 7 with libparted 3.1. In such a case the partition has been successfully written to the disk but just informing the kernel failed. This is a problem because when a partition is being moved in advance of a file system move step, failure to inform the kernel leaves the partition boundaries not matching the on disk limits of the file system. For a move to the left this leaves the partition reported as unknown, apparently losing the user's data. For example start with a 512 MiB partition containing an XFS file system. This is recognised by blkid and parted, hence also by GParted. # blkid /dev/sdb1 /dev/sdb1: UUID=... TYPE="xfs" PARTUUID="37965980-01" # parted /dev/sdb unit s print Model: ATA VBOX HARDDISK (scsi) Disk /dev/sdb: 16777216s Sector size (logical/physical): 512B/512B Partition Table: msdos Disk Flags: Number Start End Size Type File system Flags 1 1048576s 2097151s 1048576s primary xfs Now move the partition 100 MiB to the left and have it fail to inform the kernel after the first partition change step. Operation details: Move /dev/sdb1 to the left (ERROR) * calibrate /dev/sdb1 (SUCCESS) * check file system on /dev/sdb1 for errors and (if poss...(SUCCESS) * grow partition from 512.00 MiB to 612.00 MiB (ERROR) old start: 1048576 old end: 2097151 old size: 1048576 (512.00 MiB) requested start: 843776 requested end: 2097151 requested size: 1253376 (612.00 MiB) * libparted messages (ERROR) Error informing the kernel about modifications to partition /dev/sdb1 -- Device or resource busy. This means Linux won't know about any changes you made to /dev/sdb1 until you reboot -- so you shouldn't mount it or use it in any way before rebooting. Failed to add partition 1 (resource temporarily unavailable) Now because the start of the partition is 100 MiB before the start of the file system, the file system is no longer recognised, and apparently the user's data has been lost. # blkid /dev/sdb1 /dev/sdb1: PARTUUID="37965980-01" # parted /dev/sdb unit s print ... Number Start End Size Type File system Flags 1 843776s 2097151s 1253376s primary It doesn't matter why updating the partition failed, even if it was because of an error writing to the disk. Rollback of the change to the partition should be attempted. The worst case scenario is that rollback of the change fails, which is the equivalent to how the code worked before this patch set. However in other cases where the partition boundaries are being updated after a file system move or shrink step then the partition should be updated to match the new location of the file system itself. And no rollback is wanted. If the failure was only informing the kernel then in fact the partition has actually been updated on disk after all. So each partition resize/move step needs examining on a case by case basis to decide if rolling back the change to the partition is wanted or not. This patch only adds partition change rollback into resize_move_partition(). Rollback remains disabled until all cases are examined in the following patch. Bug 791875 - Rollback specific failed partition change steps
2017-12-08 09:46:31 -07:00
const Partition & partition_new,
OperationDetail & operationdetail,
Enable failed partition change rollback for selected steps (#791875) The general rule is that: 1) For a partition change step BEFORE a file system change step, rollback on failure; 2) For a partition change step AFTER a file system change step, don't rollback on failure. Examining every case where resize_move_partition() is called and whether rollback on failure is wanted or not: * In resize_move() Resize / move extended partition. No associated file system change. NO ROLLBACK Just to keep possibly applied operation. * #1 in move() Making all encompassing partition before moving file system. ROLLBACK To restore partition boundaries back to those of the file system. * #2 in move() Recreating original partition boundaries after file system move failed or was cancelled and has been rolled back. NO ROLLBACK To keep updated partition boundaries to match restored file system data. * #3 in move() Replacing all encompassing partition with final partition after successful file system move. NO ROLLBACK Keep new partition boundaries to match moved file system. * #1 in resize_encryption() Making the partition larger before growing closed LUKS encrypted data. ROLLBACK Restore partition boundaries back to those of the closed LUKS encrypted data. * #2 in resize_encryption() Shrinking the partition after open LUKS mapping has been shrunk, but before swap is re-created (smaller). NO ROLLBACK Difficult case because the partition shrink is in the middle of a LUKS shrink and a swap shrink (re-create). If swap was actually shrunk like other types of file system, rather than re-created, then the operation sequence would be (1) shrink swap, (2) shrink LUKS encryption, (3) shrink partition. In this hypothetical case and the actual case no rollback is preferred to try to keep the new partition boundaries match the shrunk open LUKS encryption mapping. * #3 in resize_encryption() Grow the partition before growing open LUKS mapping and re-creating swap larger. ROLLBACK Restore partition boundaries back to those of the smaller open LUKS encryption mapping. * #4 in resize_encryption() Shrink the partition after shrinking the file system and open LUKS encryption mapping. NO ROLLBACK Keep new smaller partition boundaries to match shrunk encrypted file system. * #5 in resize_encryption() Grow the partition before growing the open LUKS encryption mapping and file system. ROLLBACK Restore partition boundaries back to those of the not yet grown encrypted file system. * #1 in resize_plain() Resize partition before re-creating swap a different size. ROLLBACK Restore partition boundaries back to those of the not yet resized (re-created) swap space. * #2 in resize_plain() Shrink partition after shrinking the file system. NO ROLLBACK Keep new smaller partition boundaries to match shrunk file system. * #3 in resize_plain() Grow partition before growing the file system. ROLLBACK Restore partition boundaries back to those of the not yet grown file system. Removes the default value from the rollback_on_fail parameter so rollback or not has to be explicitly specified for every call of resize_move_partition(). Bug 791875 - Rollback specific failed partition change steps
2017-12-18 09:39:37 -07:00
bool rollback_on_fail );
bool resize_move_partition_implement( const Partition & partition_old,
const Partition & partition_new,
Sector & new_start,
Sector & new_end );
bool shrink_encryption( const Partition & partition_old,
const Partition & partition_new,
OperationDetail & operationdetail );
bool maximize_encryption( const Partition & partition,
OperationDetail & operationdetail );
bool shrink_filesystem( const Partition & partition_old,
const Partition & partition_new,
OperationDetail & operationdetail );
bool maximize_filesystem( const Partition & partition, OperationDetail & operationdetail ) ;
Refactor linux-swap recreation (#775932) Linux-swap is recreated as part of copy, resize and move operations and the code was special cased to implement that by calling the linux-swap specific resize method. However the displayed text always said "growing file system" and then proceeded to recreate linux swap. Example operation: Copy /dev/sdb1 to /dev/sdb2 ... + copy file system from /dev/sdb1 to /dev/sdb2 Partition copy action skipped because linux-swap file system does not contain data + grow file system to fill the partition + create new linux-swap file system + mkswap -L"" -U "77d939ef-54d6-427a-a2bf-a053da7eed4c" /dev/sdb2 Setting up swapspace version 1, size = 262140 KiB LABEL=, UUID=77d939ef-54d6-427a-a2bf-a053da7eed4c Fix by writing recreate_linux_swap_filesystem() method with better messaging and use everywhere maximise_filesystem() was previously used to recreate linux-swap. Also as this is a create step, erase the partition first to prevent the possibility of any other file system signatures being found afterwards. Now the operation steps are more reflective of what is actually being performed. Copy /dev/sdb1 to /dev/sdb2 ... + copy file system from /dev/sdb1 to /dev/sdb2 Partition copy action skipped because linux-swap file system does not contain data + clear old file system signatures in /dev/sdb2 + create new linux-swap file system + mkswap -L"" -U "77d939ef-54d6-427a-a2bf-a053da7eed4c" /dev/sdb2 Setting up swapspace version 1, size = 262140 KiB LABEL=, UUID=77d939ef-54d6-427a-a2bf-a053da7eed4c Bug 775932 - Refactor mostly applying of operations
2016-11-19 16:48:22 -07:00
bool recreate_linux_swap_filesystem( const Partition & partition,
OperationDetail & operationdetail );
bool resize_filesystem_implement( const Partition & partition_old,
const Partition & partition_new,
OperationDetail & operationdetail );
bool copy( const Partition & partition_src,
Partition & partition_dst,
OperationDetail & operationdetail );
bool copy_filesystem( const Partition & partition_src,
Partition & partition_dst,
OperationDetail & operationdetail );
bool copy_filesystem_internal( const Partition & partition_src,
const Partition & partition_dst,
OperationDetail & operationdetail,
bool cancel_safe );
bool copy_filesystem_internal( const Partition & partition_src,
const Partition & partition_dst,
OperationDetail & operationdetail,
Byte_Value & total_done,
bool cancel_safe );
bool copy_blocks( const Glib::ustring & src_device,
const Glib::ustring & dst_device,
Sector src_start,
Sector dst_start,
Byte_Value src_sector_size,
Byte_Value dst_sector_size,
Byte_Value src_length,
OperationDetail & operationdetail,
Byte_Value & total_done,
bool cancel_safe );
void rollback_move_filesystem( const Partition & partition_src,
const Partition & partition_dst,
OperationDetail & operationdetail,
Byte_Value total_done );
bool check_repair_filesystem( const Partition & partition, OperationDetail & operationdetail ) ;
bool check_repair_maximize( const Partition & partition,
OperationDetail & operationdetail );
bool set_partition_type( const Partition & partition, OperationDetail & operationdetail ) ;
bool calibrate_partition( Partition & partition, OperationDetail & operationdetail ) ;
bool calculate_exact_geom( const Partition & partition_old,
Partition & partition_new,
OperationDetail & operationdetail ) ;
bool update_dmraid_entry( const Partition & partition_new, OperationDetail & operationdetail );
Use wipefs to clear old signatures before creating new file systems (#688882) Previously the function erase_filesystem_signatures() was used to clear file system signatures when a new partition was created and when an existing partition was formatted with a file system. However this was only available with libparted <= 2.4 and then only for the file systems which libparted supports. Having multiple different file system signatures on a partition leads to misidentification of file system. For example creating a nilfs2 over the top of a fat32 file system is detected as a fat32, not nilfs2. This shows that old file system signatures must be cleared before a new file system is created. Fix by always using "wipefs -a /dev/PARTITION" command to clear all old file system signatures rather than libparted API calls. Failure from wipefs is only considered a warning so doesn't fail the file system creation. (This doesn't yet fully meet the "MUST be cleared" requirement above. Will be fully met later in this patchset). Output from the wipefs command is displayed as a new sub-step which looks like this: v Format /dev/sda7 as xfs 00:00:05 > calibrate /dev/sda14 00:00:01 v clear old file system signatures in /dev/sda7 00:00:01 [NEW] > wipefs -a /dev/sda7 [NEW] > set partition type on /dev/sda7 00:00:02 v create new xfs file system 00:00:01 > mkfs.xfs -f -L "" /dev/sda7 Also signatures are only cleared immediately before a new file system is written and not when an unformatted partition is created. This allows recovery from accidental partition deletion by re-creating the deleted partition as unformatted. Bug #688882 - Improve clearing of file system signatures
2012-12-01 05:49:29 -07:00
bool erase_filesystem_signatures( const Partition & partition, OperationDetail & operationdetail ) ;
bool update_bootsector( const Partition & partition, OperationDetail & operationdetail ) ;
//general..
void capture_libparted_messages( OperationDetail & operationdetail, bool success );
Only explicitly flush devices when using libparted < 3.2 (#259) During device probing GParted always explicitly calls ped_device_sync() to flush the caches for coherency between the whole disk device and the partition devices [1]. As the GParted_Core::flush_device() comment explains, since v3.1.61-gfb99ba5 [2], libparted flushes the devices every time a device is opened [3], so also explicitly doing this in GParted is unnecessary. Therefore stop explicitly flushing the devices in GParted, except when using libparted 3.1 and older which doesn't do it itself. The ped_device_open() and ped_device_close() needed for the ped_device_sync() is also a trigger of device changes and udev rule execution performing LVM Volume Group activation, because libparted opens the device read-write [4]. This is another reason to remove it when possible. However even when eliminated it does not solve the issue of LVM VG activation because other triggers remain. Do want this change first though so that the sequence of libparted calls isn't changed immediately after documenting them and fixing the issue and so that there is no doubt that this change doesn't fix the issue. Removing this extra device flush saves a little bit of time, depending on the speed of the drive and number of partitions. Sample savings on my desktop: Drive type and partitions Saving (seconds) ----------------------------- ---------------- fast SSD with 3 partitions 0.05 slow SSD with 12 partitions 0.27 HDD with 1 partition 0.05 VHDD in VM with 1 partition 0.14 VHDD in VM with 10 partitions 0.58 Also the settle_device() call in flush_device() needs to be kept to wait for device changes and udev rule execution whether it is GParted explicitly flushing the device or just libparted automatically doing it for cache coherency in ped_device_get(). This is because: 1. Libparted <= 3.2 opens the whole disk device read-write for ped_device_get() [5]. (This was changed with parted v3.2.26-g44d5ae0 [6] to open the whole disk device read-only). 2. Libparted up to and including the latest 3.6 release still opens all partition devices read-write for ped_device_get() [7]. 3. A whole disk device FAT32 file system looks enough like a partition table that both the Linux kernel and libparted think it is partitioned: # mkfs.fat -F32 /dev/sdb mkfs.fat 4.2 (2021-01-31) # grep sdb /proc/partitions 8 16 8388608 sdb 8 17 8388607 sdb1 # parted /dev/sdb print Model: ATA VBOX HARDDISK (scsi) Disk /dev/sdb: 8590MB Sector size (logical/physical): 512B/512B Partition Table: loop Disk Flags: Number Start End Size File system Flags 1 0s 16777215s 16777216s fat32 So the ped_device_get() call on a whole disk device FAT32 file system still triggers device change and udev rule execution which needs to be waited for, as this is exactly the case fixed previously by commit: 1382e0b828f630a705cecd97c346dfc6267909bf Wait for udev change on /dev/DISK when querying whole device FS (!46) [1] 3bea067596e3e2d6513cda2a66df1b3e4fa432fb Flush devices when scanning to prevent reading stale signatures (#723842) [2] Revert "linux-commit: do not unnecessarily open partition device nodes" http://git.savannah.gnu.org/cgit/parted.git/commit/?id=fb99ba5ebd0dc34204fc9f1014131d5d494805bc [3] parted libparted/arch/linux.c:_device_open() https://git.savannah.gnu.org/cgit/parted.git/tree/libparted/arch/linux.c?h=v3.6#n1752 1709 static int 1710 linux_open (PedDevice* dev) 1711 { 1712 return _device_open (dev, RW_MODE); 1713 } 1714 1715 static int 1716 _device_open (PedDevice* dev, int flags) ... 1752 _flush_cache (dev); [4] parted libparted/device.c:ped_device_open() v3.6 https://git.savannah.gnu.org/cgit/parted.git/tree/libparted/device.c?h=v3.6#n226 parted libparted/arch/linux.c v3.6 https://git.savannah.gnu.org/cgit/parted.git/tree/libparted/arch/linux.c?h=v3.6 ped_device_open(...) ped_architecture->dev_ops->open(...) = linux_open(...) _device_open(..., RW_MODE) open(..., O_RDWR) [5] parted libparted/device.c:ped_device_get() v3.2 https://git.savannah.gnu.org/cgit/parted.git/tree/libparted/device.c?h=v3.2#n149 parted libparted/arch/linux.c v3.2 https://git.savannah.gnu.org/cgit/parted.git/tree/libparted/arch/linux.c?h=v3.2 ped_device_get(...) ped_architecture->dev_ops->_new(...) = linux_new() init_ide(...) init_scsi(...) init_generic(...) ped_device_open(...) ped_architecture->dev_ops->open(...) = linux_open(...) open(..., O_RDWR) [6] libparted: Use read only when probing devices on linux (#1245144) http://git.savannah.gnu.org/cgit/parted.git/commit/?id=44d5ae0115c4ecfe3158748309e9912c5aede92d [7] parted libparted/arch/linux.v v3.6 http://git.savannah.gnu.org/cgit/parted.git/tree/libparted/arch/linux.c?h=v3.6#n1660 1660 static void 1661 _flush_cache (PedDevice* dev) ... 1673 for (i = 1; i < lpn; i++) { ... 1680 if (!_partition_is_mounted_by_path(name)) { 1681 fd = open (name, WR_MODE, 0); Closes #259 - Trying to deactivate LVM PV fails
2024-08-25 13:19:09 -06:00
#ifdef ENABLE_EXPLICIT_FLUSH_WORKAROUND
static bool flush_device( PedDevice * lp_device );
Only explicitly flush devices when using libparted < 3.2 (#259) During device probing GParted always explicitly calls ped_device_sync() to flush the caches for coherency between the whole disk device and the partition devices [1]. As the GParted_Core::flush_device() comment explains, since v3.1.61-gfb99ba5 [2], libparted flushes the devices every time a device is opened [3], so also explicitly doing this in GParted is unnecessary. Therefore stop explicitly flushing the devices in GParted, except when using libparted 3.1 and older which doesn't do it itself. The ped_device_open() and ped_device_close() needed for the ped_device_sync() is also a trigger of device changes and udev rule execution performing LVM Volume Group activation, because libparted opens the device read-write [4]. This is another reason to remove it when possible. However even when eliminated it does not solve the issue of LVM VG activation because other triggers remain. Do want this change first though so that the sequence of libparted calls isn't changed immediately after documenting them and fixing the issue and so that there is no doubt that this change doesn't fix the issue. Removing this extra device flush saves a little bit of time, depending on the speed of the drive and number of partitions. Sample savings on my desktop: Drive type and partitions Saving (seconds) ----------------------------- ---------------- fast SSD with 3 partitions 0.05 slow SSD with 12 partitions 0.27 HDD with 1 partition 0.05 VHDD in VM with 1 partition 0.14 VHDD in VM with 10 partitions 0.58 Also the settle_device() call in flush_device() needs to be kept to wait for device changes and udev rule execution whether it is GParted explicitly flushing the device or just libparted automatically doing it for cache coherency in ped_device_get(). This is because: 1. Libparted <= 3.2 opens the whole disk device read-write for ped_device_get() [5]. (This was changed with parted v3.2.26-g44d5ae0 [6] to open the whole disk device read-only). 2. Libparted up to and including the latest 3.6 release still opens all partition devices read-write for ped_device_get() [7]. 3. A whole disk device FAT32 file system looks enough like a partition table that both the Linux kernel and libparted think it is partitioned: # mkfs.fat -F32 /dev/sdb mkfs.fat 4.2 (2021-01-31) # grep sdb /proc/partitions 8 16 8388608 sdb 8 17 8388607 sdb1 # parted /dev/sdb print Model: ATA VBOX HARDDISK (scsi) Disk /dev/sdb: 8590MB Sector size (logical/physical): 512B/512B Partition Table: loop Disk Flags: Number Start End Size File system Flags 1 0s 16777215s 16777216s fat32 So the ped_device_get() call on a whole disk device FAT32 file system still triggers device change and udev rule execution which needs to be waited for, as this is exactly the case fixed previously by commit: 1382e0b828f630a705cecd97c346dfc6267909bf Wait for udev change on /dev/DISK when querying whole device FS (!46) [1] 3bea067596e3e2d6513cda2a66df1b3e4fa432fb Flush devices when scanning to prevent reading stale signatures (#723842) [2] Revert "linux-commit: do not unnecessarily open partition device nodes" http://git.savannah.gnu.org/cgit/parted.git/commit/?id=fb99ba5ebd0dc34204fc9f1014131d5d494805bc [3] parted libparted/arch/linux.c:_device_open() https://git.savannah.gnu.org/cgit/parted.git/tree/libparted/arch/linux.c?h=v3.6#n1752 1709 static int 1710 linux_open (PedDevice* dev) 1711 { 1712 return _device_open (dev, RW_MODE); 1713 } 1714 1715 static int 1716 _device_open (PedDevice* dev, int flags) ... 1752 _flush_cache (dev); [4] parted libparted/device.c:ped_device_open() v3.6 https://git.savannah.gnu.org/cgit/parted.git/tree/libparted/device.c?h=v3.6#n226 parted libparted/arch/linux.c v3.6 https://git.savannah.gnu.org/cgit/parted.git/tree/libparted/arch/linux.c?h=v3.6 ped_device_open(...) ped_architecture->dev_ops->open(...) = linux_open(...) _device_open(..., RW_MODE) open(..., O_RDWR) [5] parted libparted/device.c:ped_device_get() v3.2 https://git.savannah.gnu.org/cgit/parted.git/tree/libparted/device.c?h=v3.2#n149 parted libparted/arch/linux.c v3.2 https://git.savannah.gnu.org/cgit/parted.git/tree/libparted/arch/linux.c?h=v3.2 ped_device_get(...) ped_architecture->dev_ops->_new(...) = linux_new() init_ide(...) init_scsi(...) init_generic(...) ped_device_open(...) ped_architecture->dev_ops->open(...) = linux_open(...) open(..., O_RDWR) [6] libparted: Use read only when probing devices on linux (#1245144) http://git.savannah.gnu.org/cgit/parted.git/commit/?id=44d5ae0115c4ecfe3158748309e9912c5aede92d [7] parted libparted/arch/linux.v v3.6 http://git.savannah.gnu.org/cgit/parted.git/tree/libparted/arch/linux.c?h=v3.6#n1660 1660 static void 1661 _flush_cache (PedDevice* dev) ... 1673 for (i = 1; i < lpn; i++) { ... 1680 if (!_partition_is_mounted_by_path(name)) { 1681 fd = open (name, WR_MODE, 0); Closes #259 - Trying to deactivate LVM PV fails
2024-08-25 13:19:09 -06:00
#endif
static bool get_device( const Glib::ustring & device_path, PedDevice *& lp_device, bool flush = false );
Remove coding landmine in get_disk() (#152) get_disk() is the wrapper around libparted's ped_disk_new() which reads a disk label from the specified device and if successful creates the in memory PedDisk object to represent it. In the case that libparted doesn't recognise a disk label or a file system, having get_disk() go and destroy the passed in PedDevice object via parameter lp_device is very unexpected behaviour hence describing it as a coding landmine. BACKGROUND 1. Early on GParted only worked with devices with valid disk labels. FileSystem.h:open_device_and_disk() required both ped_device_get() and ped_disk_new() to succeed or neither to succeed. 2. Commit [1] added support for devices which didn't yet have a disk label. open_device_and_disk() had default parameter strict=true added. While scanning strict=false was passed which allowed open_device_and_disk() to return success if only ped_device_get() succeeded and ped_disk_new() failed when the disk was empty. All other times open_device_and_disk() was called with default strict=true, still requiring both or neither to succeed. 3. Commit [2] added support for whole disk file systems. The now named get_device_and_disk() had it's functionality split between get_device() and get_disk(). This result in the code landmine being left behind: get_disk() destroying the passed device object if default parameter strict=true and no disk label or file system was detected. ANALYSIS 1. Since support for whole disk file systems [2] all current calls to get_device_and_disk() let the strict parameter default to true and are only called on known partitions within disk labels when applying a change to that partition. Therefore they don't care about the behaviour of get_disk(), just that get_device_and_disk() maintains that both ped_device_get() and ped_disk_new() succeed or neither succeed. 2. Two direct calls to get_disk() where the strict parameter defaults to true, from calibrate_partition() and erase_filesystem_signatures(), only do so on known partitions within disk labels as part of applying a change to that partition. Therefore ped_disk_new() will succeed and so PedDevice isn't deleted when not wanted. 3. The two remaining direct calls to get_disk() where the strict parameter is explicitly set to false, from set_device_from_disk() and detect_filesystem_in_encryption_mapping(), are when scanning. As the pass strict=false they don't allow the PedDevice deletion to occur if no recognised disk label is found. FIX Remove the strict parameter from get_disk() and get_device_and_disk() as it's no longer needed. Remove the code landmine by removing the side affect of destroying the PedDevice object if a disk label isn't found. Make sure get_device_and_disk() maintains the all or nothing behaviour. Also don't pass lp_device by reference to a pointer to get_disk() so the code can't change where lp_device points. [1] 038c5c5d99ad842f1a57f12222c884be29f4df4f P (special thanks to mantiena-baltix for bringing this issue to my [2] 51ac4d56489653854cd22787238a14bfa66a6ad4 Split get_device_and_disk() into two (#743181) Closes #152 - GParted crashed when trying to probe an encrypted partition containing content that libparted doesn't recognise
2021-04-10 09:39:22 -06:00
static bool get_disk(PedDevice *lp_device, PedDisk*& lp_disk);
static bool get_device_and_disk(const Glib::ustring& device_path,
PedDevice*& lp_device, PedDisk*& lp_disk, bool flush = false);
static void destroy_device_and_disk( PedDevice*& lp_device, PedDisk*& lp_disk );
static bool commit( PedDisk* lp_disk );
static bool commit_to_os( PedDisk* lp_disk, std::time_t timeout );
static void settle_device( std::time_t timeout );
static bool useable_device(const PedDevice* lp_device);
static PedPartition* get_lp_partition( const PedDisk* lp_disk, const Partition & partition );
static PedExceptionOption ped_exception_handler( PedException * e ) ;
std::vector<PedPartitionFlag> flags;
std::vector<Glib::ustring> device_paths ;
bool probe_devices ;
Glib::ustring thread_status_message; //Used to pass data to show_pulsebar method
static SupportedFileSystems* supported_filesystems;
};
} //GParted
#endif /* GPARTED_GPARTED_CORE_H */