[gparted] Implement rollback of failed partition resize/move steps (#791875)
- From: Curtis Gedak <gedakc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gparted] Implement rollback of failed partition resize/move steps (#791875)
- Date: Tue, 2 Jan 2018 17:40:46 +0000 (UTC)
commit 0f16703bbbae9c7d8d54d46af4a7b3a7e725f17f
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date: Fri Dec 8 16:46:31 2017 +0000
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
include/GParted_Core.h | 5 +++--
src/GParted_Core.cc | 37 ++++++++++++++++++++++++++++++++++---
2 files changed, 37 insertions(+), 5 deletions(-)
---
diff --git a/include/GParted_Core.h b/include/GParted_Core.h
index b805e95..6a46647 100644
--- a/include/GParted_Core.h
+++ b/include/GParted_Core.h
@@ -144,8 +144,9 @@ private:
const Partition & partition_new,
OperationDetail & operationdetail );
bool resize_move_partition( const Partition & partition_old,
- const Partition & partition_new,
- OperationDetail & operationdetail ) ;
+ const Partition & partition_new,
+ OperationDetail & operationdetail,
+ bool rollback_on_fail = false );
bool resize_move_partition_implement( const Partition & partition_old,
const Partition & partition_new,
Sector & new_start,
diff --git a/src/GParted_Core.cc b/src/GParted_Core.cc
index 6a84201..27f178a 100644
--- a/src/GParted_Core.cc
+++ b/src/GParted_Core.cc
@@ -2640,8 +2640,9 @@ bool GParted_Core::resize_plain( const Partition & partition_old,
}
bool GParted_Core::resize_move_partition( const Partition & partition_old,
- const Partition & partition_new,
- OperationDetail & operationdetail )
+ const Partition & partition_new,
+ OperationDetail & operationdetail,
+ bool rollback_on_fail )
{
if ( partition_new.type == TYPE_UNPARTITIONED )
// Trying to resize/move a non-partitioned whole disk device is a
@@ -2770,8 +2771,38 @@ bool GParted_Core::resize_move_partition( const Partition & partition_old,
FONT_ITALIC )
) ;
}
-
operationdetail.get_last_child().set_success_and_capture_errors( success );
+
+ if ( ! success && rollback_on_fail )
+ {
+ operationdetail.add_child(
+ OperationDetail( _("attempt to rollback failed change to the partition") ) );
+
+ Partition *partition_restore = partition_old.clone();
+ // Ensure that old partition boundaries are not modified
+ partition_restore->alignment = ALIGN_STRICT;
+
+ bool rollback_success = resize_move_partition_implement( partition_new, *partition_restore,
+ new_start, new_end );
+
+ operationdetail.get_last_child().add_child(
+ OperationDetail(
+ String::ucompose( _("original start: %1"), partition_restore->sector_start )
+ "\n" +
+ String::ucompose( _("original end: %1"), partition_restore->sector_end ) +
"\n" +
+ String::ucompose( _("original size: %1 (%2)"),
+ partition_restore->get_sector_length(),
+ Utils::format_size( partition_restore->get_sector_length(),
partition_restore->sector_size ) ),
+ STATUS_NONE, FONT_ITALIC ) );
+
+ // Update dev mapper entry if partition is dmraid.
+ rollback_success = rollback_success && update_dmraid_entry( *partition_restore,
operationdetail );
+
+ delete partition_restore;
+ partition_restore = NULL;
+
+ operationdetail.get_last_child().set_success_and_capture_errors( rollback_success );
+ }
+
return success;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]