You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
842 lines
31 KiB
842 lines
31 KiB
From 31ab97cfe0233191a73a1dd9cb7cd193451491da Mon Sep 17 00:00:00 2001 |
|
From: "Brian C. Lane" <bcl@redhat.com> |
|
Date: Fri, 11 Aug 2017 08:37:11 -0700 |
|
Subject: [PATCH 46/48] libparted: Backport partition resize code |
|
|
|
This adds _blkpg_resize_partition, _dm_resize_partition, and adjust the |
|
current code to support it. Changes are somewhat extensive, since they |
|
also touch _disk_sync_part_table. |
|
|
|
This is based on code from commit f09ca967a0bc443b869a6fad5b5ffe8e95c3fe9a |
|
|
|
Related: rhbz#1423357 |
|
--- |
|
libparted/arch/linux.c | 673 +++++++++++++++++++++++++++++-------------------- |
|
1 file changed, 403 insertions(+), 270 deletions(-) |
|
|
|
diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c |
|
index fa329f4..6e78faf 100644 |
|
--- a/libparted/arch/linux.c |
|
+++ b/libparted/arch/linux.c |
|
@@ -288,6 +288,7 @@ struct blkdev_ioctl_param { |
|
|
|
static char* _device_get_part_path (PedDevice* dev, int num); |
|
static int _partition_is_mounted_by_path (const char* path); |
|
+static unsigned int _device_get_partition_range(PedDevice const* dev); |
|
static int _device_open (PedDevice* dev, int flags); |
|
static int _device_open_ro (PedDevice* dev); |
|
static int _device_close (PedDevice* dev); |
|
@@ -446,6 +447,17 @@ _is_blkext_major (int major) |
|
|
|
#ifdef ENABLE_DEVICE_MAPPER |
|
static int |
|
+_dm_task_run_wait (struct dm_task *task, uint32_t cookie) |
|
+{ |
|
+ int rc = 0; |
|
+ |
|
+ rc = dm_task_run (task); |
|
+ dm_udev_wait (cookie); |
|
+ |
|
+ return rc; |
|
+} |
|
+ |
|
+static int |
|
_is_dm_major (int major) |
|
{ |
|
return _major_type_in_devices (major, "device-mapper"); |
|
@@ -1521,6 +1533,7 @@ _flush_cache (PedDevice* dev) |
|
{ |
|
LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev); |
|
int i; |
|
+ int lpn = _device_get_partition_range(dev); |
|
|
|
if (dev->read_only) |
|
return; |
|
@@ -1532,7 +1545,7 @@ _flush_cache (PedDevice* dev) |
|
if (_have_kern26()) |
|
return; |
|
|
|
- for (i = 1; i < 16; i++) { |
|
+ for (i = 1; i < lpn; i++) { |
|
char* name; |
|
int fd; |
|
|
|
@@ -2268,28 +2281,63 @@ zasprintf (const char *format, ...) |
|
return r < 0 ? NULL : resultp; |
|
} |
|
|
|
+#ifdef ENABLE_DEVICE_MAPPER |
|
+static char * |
|
+dm_canonical_path (PedDevice const *dev) |
|
+{ |
|
+ LinuxSpecific const *arch_specific = LINUX_SPECIFIC (dev); |
|
+ |
|
+ /* Get map name from devicemapper */ |
|
+ struct dm_task *task = dm_task_create (DM_DEVICE_INFO); |
|
+ if (!task) |
|
+ goto err; |
|
+ if (!dm_task_set_major_minor (task, arch_specific->major, |
|
+ arch_specific->minor, 0)) |
|
+ goto err; |
|
+ if (!dm_task_run(task)) |
|
+ goto err; |
|
+ char *dev_name = zasprintf ("/dev/mapper/%s", dm_task_get_name (task)); |
|
+ if (dev_name == NULL) |
|
+ goto err; |
|
+ dm_task_destroy (task); |
|
+ return dev_name; |
|
+err: |
|
+ return NULL; |
|
+} |
|
+#endif |
|
+ |
|
static char* |
|
_device_get_part_path (PedDevice *dev, int num) |
|
{ |
|
- size_t path_len = strlen (dev->path); |
|
- |
|
+ char *devpath; |
|
+ size_t path_len; |
|
char *result; |
|
+#ifdef ENABLE_DEVICE_MAPPER |
|
+ devpath = (dev->type == PED_DEVICE_DM |
|
+ ? dm_canonical_path (dev) : dev->path); |
|
+#else |
|
+ devpath = dev->path; |
|
+#endif |
|
+ path_len = strlen (devpath); |
|
/* Check for devfs-style /disc => /partN transformation |
|
unconditionally; the system might be using udev with devfs rules, |
|
and if not the test is harmless. */ |
|
- if (5 < path_len && !strcmp (dev->path + path_len - 5, "/disc")) { |
|
+ if (5 < path_len && !strcmp (devpath + path_len - 5, "/disc")) { |
|
/* replace /disc with /part%d */ |
|
result = zasprintf ("%.*s/part%d", |
|
- (int) (path_len - 5), dev->path, num); |
|
+ (int) (path_len - 5), devpath, num); |
|
} else { |
|
char const *p = (dev->type == PED_DEVICE_DAC960 |
|
|| dev->type == PED_DEVICE_CPQARRAY |
|
|| dev->type == PED_DEVICE_ATARAID |
|
|| isdigit (dev->path[path_len - 1]) |
|
? "p" : ""); |
|
- result = zasprintf ("%s%s%d", dev->path, p, num); |
|
+ result = zasprintf ("%s%s%d", devpath, p, num); |
|
} |
|
- |
|
+#ifdef ENABLE_DEVICE_MAPPER |
|
+ if (dev->type == PED_DEVICE_DM) |
|
+ free (devpath); |
|
+#endif |
|
return result; |
|
} |
|
|
|
@@ -2438,6 +2486,62 @@ _blkpg_add_partition (PedDisk* disk, const PedPartition *part) |
|
|
|
if (!_blkpg_part_command (disk->dev, &linux_part, |
|
BLKPG_ADD_PARTITION)) { |
|
+ return 0; |
|
+ } |
|
+ |
|
+ return 1; |
|
+} |
|
+ |
|
+static int |
|
+_blkpg_remove_partition (PedDisk* disk, int n) |
|
+{ |
|
+ struct blkpg_partition linux_part; |
|
+ |
|
+ memset (&linux_part, 0, sizeof (linux_part)); |
|
+ linux_part.pno = n; |
|
+ return _blkpg_part_command (disk->dev, &linux_part, |
|
+ BLKPG_DEL_PARTITION); |
|
+} |
|
+ |
|
+#ifdef BLKPG_RESIZE_PARTITION |
|
+static int _blkpg_resize_partition (PedDisk* disk, const PedPartition *part) |
|
+{ |
|
+ struct blkpg_partition linux_part; |
|
+ char* dev_name; |
|
+ |
|
+ PED_ASSERT(disk != NULL); |
|
+ PED_ASSERT(disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0); |
|
+ |
|
+ dev_name = _device_get_part_path (disk->dev, part->num); |
|
+ if (!dev_name) |
|
+ return 0; |
|
+ memset (&linux_part, 0, sizeof (linux_part)); |
|
+ linux_part.start = part->geom.start * disk->dev->sector_size; |
|
+ /* see fs/partitions/msdos.c:msdos_partition(): "leave room for LILO" */ |
|
+ if (part->type & PED_PARTITION_EXTENDED) { |
|
+ if (disk->dev->sector_size == 512) { |
|
+ linux_part.length = 2; |
|
+ PedPartition *walk; |
|
+ /* if the second sector is claimed by a logical partition, |
|
+ then there's just no room for lilo, so don't try to use it */ |
|
+ for (walk = part->part_list; walk; walk = walk->next) { |
|
+ if (walk->geom.start == part->geom.start+1) |
|
+ linux_part.length = 1; |
|
+ } |
|
+ } else { |
|
+ linux_part.length = 1; |
|
+ } |
|
+ linux_part.length *= disk->dev->sector_size; |
|
+ } |
|
+ else |
|
+ linux_part.length = part->geom.length * disk->dev->sector_size; |
|
+ linux_part.pno = part->num; |
|
+ strncpy (linux_part.devname, dev_name, BLKPG_DEVNAMELTH); |
|
+ |
|
+ free (dev_name); |
|
+ |
|
+ if (!_blkpg_part_command (disk->dev, &linux_part, |
|
+ BLKPG_RESIZE_PARTITION)) { |
|
return ped_exception_throw ( |
|
PED_EXCEPTION_ERROR, |
|
PED_EXCEPTION_IGNORE_CANCEL, |
|
@@ -2454,17 +2558,7 @@ _blkpg_add_partition (PedDisk* disk, const PedPartition *part) |
|
|
|
return 1; |
|
} |
|
- |
|
-static int |
|
-_blkpg_remove_partition (PedDisk* disk, int n) |
|
-{ |
|
- struct blkpg_partition linux_part; |
|
- |
|
- memset (&linux_part, 0, sizeof (linux_part)); |
|
- linux_part.pno = n; |
|
- return _blkpg_part_command (disk->dev, &linux_part, |
|
- BLKPG_DEL_PARTITION); |
|
-} |
|
+#endif |
|
|
|
/* Read the integer from /sys/block/DEV_BASE/ENTRY and set *VAL |
|
to that value, where DEV_BASE is the last component of DEV->path. |
|
@@ -2586,6 +2680,8 @@ static unsigned int |
|
_device_get_partition_range(PedDevice const* dev) |
|
{ |
|
int range; |
|
+ if (dev->type == PED_DEVICE_DM) |
|
+ return MAX_NUM_PARTS; |
|
bool ok = _sysfs_int_entry_from_dev(dev, "ext_range", &range); |
|
|
|
if (!ok) |
|
@@ -2594,264 +2690,78 @@ _device_get_partition_range(PedDevice const* dev) |
|
return range > 1 ? range : 0; |
|
} |
|
|
|
-/* |
|
- * Sync the partition table in two step process: |
|
- * 1. Remove all of the partitions from the kernel's tables, but do not attempt |
|
- * removal of any partition for which the corresponding ioctl call fails. |
|
- * 2. Add all the partitions that we hold in disk, throwing a warning |
|
- * if we cannot because step 1 failed to remove it and it is not being |
|
- * added back with the same start and length. |
|
- * |
|
- * To achieve this two step process we must calculate the minimum number of |
|
- * maximum possible partitions between what linux supports and what the label |
|
- * type supports. EX: |
|
- * |
|
- * number=MIN(max_parts_supported_in_linux,max_parts_supported_in_msdos_tables) |
|
- */ |
|
-static int |
|
-_disk_sync_part_table (PedDisk* disk) |
|
-{ |
|
- PED_ASSERT(disk != NULL); |
|
- PED_ASSERT(disk->dev != NULL); |
|
- int lpn; |
|
- |
|
- unsigned int part_range = _device_get_partition_range(disk->dev); |
|
- |
|
- /* lpn = largest partition number. */ |
|
- if (ped_disk_get_max_supported_partition_count(disk, &lpn)) |
|
- lpn = PED_MIN(lpn, part_range); |
|
- else |
|
- lpn = part_range; |
|
- |
|
- /* Its not possible to support largest_partnum < 0. |
|
- * largest_partnum == 0 would mean does not support partitions. |
|
- * */ |
|
- if (lpn < 1) |
|
- return 0; |
|
- int ret = 0; |
|
- int *ok = calloc (lpn, sizeof *ok); |
|
- if (!ok) |
|
- return 0; |
|
- int *errnums = ped_malloc(sizeof(int) * lpn); |
|
- if (!errnums) |
|
- goto cleanup; |
|
- |
|
- /* Attempt to remove each and every partition, retrying for |
|
- up to max_sleep_seconds upon any failure due to EBUSY. */ |
|
- unsigned int sleep_microseconds = 10000; |
|
- unsigned int max_sleep_seconds = 1; |
|
- unsigned int n_sleep = (max_sleep_seconds |
|
- * 1000000 / sleep_microseconds); |
|
- int i; |
|
- for (i = 0; i < n_sleep; i++) { |
|
- if (i) |
|
- usleep (sleep_microseconds); |
|
- bool busy = false; |
|
- int j; |
|
- for (j = 0; j < lpn; j++) { |
|
- if (!ok[j]) { |
|
- ok[j] = _blkpg_remove_partition (disk, j + 1); |
|
- errnums[j] = errno; |
|
- if (!ok[j] && errnums[j] == EBUSY) |
|
- busy = true; |
|
- } |
|
- } |
|
- if (!busy) |
|
- break; |
|
- } |
|
- |
|
- for (i = 1; i <= lpn; i++) { |
|
- PedPartition *part = ped_disk_get_partition (disk, i); |
|
- if (part) { |
|
- if (!ok[i - 1] && errnums[i - 1] == EBUSY) { |
|
- unsigned long long length; |
|
- unsigned long long start; |
|
- /* get start and length of existing partition */ |
|
- if (!_kernel_get_partition_start_and_length(part, |
|
- &start, &length)) |
|
- goto cleanup; |
|
- if (start == part->geom.start |
|
- && length == part->geom.length) |
|
- ok[i - 1] = 1; |
|
- /* If the new partition is unchanged and the |
|
- existing one was not removed because it was |
|
- in use, then reset the error flag and do not |
|
- try to add it since it is already there. */ |
|
- continue; |
|
- } |
|
- |
|
- /* add the (possibly modified or new) partition */ |
|
- if (!_blkpg_add_partition (disk, part)) { |
|
- ped_exception_throw ( |
|
- PED_EXCEPTION_ERROR, |
|
- PED_EXCEPTION_RETRY_CANCEL, |
|
- _("Failed to add partition %d (%s)"), |
|
- i, strerror (errno)); |
|
- goto cleanup; |
|
- } |
|
- } |
|
- } |
|
- |
|
- char *bad_part_list = NULL; |
|
- /* now warn about any errors */ |
|
- for (i = 1; i <= lpn; i++) { |
|
- if (ok[i - 1] || errnums[i - 1] == ENXIO) |
|
- continue; |
|
- if (bad_part_list == NULL) { |
|
- bad_part_list = malloc (lpn * 5); |
|
- if (!bad_part_list) |
|
- goto cleanup; |
|
- bad_part_list[0] = 0; |
|
- } |
|
- sprintf (bad_part_list + strlen (bad_part_list), "%d, ", i); |
|
- } |
|
- if (bad_part_list == NULL) |
|
- ret = 1; |
|
- else { |
|
- bad_part_list[strlen (bad_part_list) - 2] = 0; |
|
- if (ped_exception_throw ( |
|
- PED_EXCEPTION_ERROR, |
|
- PED_EXCEPTION_IGNORE_CANCEL, |
|
- _("Partition(s) %s on %s have been written, but we have " |
|
- "been unable to inform the kernel of the change, " |
|
- "probably because it/they are in use. As a result, " |
|
- "the old partition(s) will remain in use. You " |
|
- "should reboot now before making further changes."), |
|
- bad_part_list, disk->dev->path) == PED_EXCEPTION_IGNORE) |
|
- ret = 1; |
|
- free (bad_part_list); |
|
- } |
|
- cleanup: |
|
- free (errnums); |
|
- free (ok); |
|
- return ret; |
|
-} |
|
- |
|
#ifdef ENABLE_DEVICE_MAPPER |
|
static int |
|
-_dm_remove_map_name(char *name) |
|
+_dm_remove_partition(PedDisk* disk, int partno) |
|
{ |
|
- struct dm_task *task = NULL; |
|
int rc = 0; |
|
uint32_t cookie = 0; |
|
+ char *part_name = _device_get_part_path (disk->dev, partno); |
|
|
|
- task = dm_task_create(DM_DEVICE_REMOVE); |
|
+ int fd = open (part_name, O_RDONLY | O_EXCL); |
|
+ if (fd == -1) { |
|
+ if (errno == ENOENT) |
|
+ errno = ENXIO; /* nothing to remove, device already doesn't exist */ |
|
+ goto err; |
|
+ } |
|
+ close (fd); |
|
+ struct dm_task *task = dm_task_create(DM_DEVICE_REMOVE); |
|
if (!task) |
|
- return 1; |
|
- |
|
- dm_task_set_name (task, name); |
|
- if (!dm_task_set_cookie(task, &cookie, 0)) |
|
- goto err; |
|
- |
|
- rc = dm_task_run(task); |
|
- dm_udev_wait(cookie); |
|
+ goto err; |
|
+ dm_task_set_name (task, part_name); |
|
+ if (!dm_task_set_cookie (task, &cookie, 0)) |
|
+ goto err; |
|
+ rc = _dm_task_run_wait (task, cookie); |
|
dm_task_update_nodes(); |
|
-err: |
|
dm_task_destroy(task); |
|
- if (!rc) |
|
- return 1; |
|
- |
|
- return 0; |
|
+err: |
|
+ free (part_name); |
|
+ return rc; |
|
} |
|
|
|
-static int |
|
-_dm_is_part (struct dm_info *this, char *name) |
|
+static bool |
|
+_dm_get_partition_start_and_length(PedPartition const *part, |
|
+ unsigned long long *start, |
|
+ unsigned long long *length) |
|
{ |
|
struct dm_task* task = NULL; |
|
- struct dm_info* info = alloca(sizeof *info); |
|
- struct dm_deps* deps = NULL; |
|
int rc = 0; |
|
- unsigned int i; |
|
|
|
- task = dm_task_create(DM_DEVICE_DEPS); |
|
- if (!task) |
|
+ if (!(task = dm_task_create(DM_DEVICE_TABLE))) |
|
return 0; |
|
- |
|
- dm_task_set_name(task, name); |
|
- if (!dm_task_run(task)) |
|
+ char *path = _device_get_part_path (part->disk->dev, part->num); |
|
+ PED_ASSERT(path); |
|
+ /* libdevmapper likes to complain on stderr instead of quietly |
|
+ returning ENOENT or ENXIO, so try to stat first */ |
|
+ struct stat st; |
|
+ if (stat(path, &st)) |
|
goto err; |
|
- |
|
- memset(info, '\0', sizeof *info); |
|
- dm_task_get_info(task, info); |
|
- if (!info->exists) |
|
+ dm_task_set_name(task, path); |
|
+ if (!dm_task_run(task)) |
|
goto err; |
|
|
|
- deps = dm_task_get_deps(task); |
|
- if (!deps) |
|
+ int major, minor; |
|
+ char *params; |
|
+ char *target_type; |
|
+ dm_get_next_target(task, NULL, (uint64_t *)start, (uint64_t *)length, &target_type, ¶ms); |
|
+ if (sscanf (params, "%d:%d %Ld", &major, &minor, start) != 3) |
|
goto err; |
|
+ rc = 1; |
|
|
|
- for (i = 0; i < deps->count; i++) { |
|
- unsigned int ma = major(deps->device[i]), |
|
- mi = minor(deps->device[i]); |
|
- |
|
- if (ma == this->major && mi == this->minor) |
|
- rc = 1; |
|
- } |
|
- |
|
+ /* device-mapper uses 512b units, make sure we return length and start in terms of the device's |
|
+ * sector size. |
|
+ */ |
|
+ *start /= (part->disk->dev->sector_size / PED_SECTOR_SIZE_DEFAULT); |
|
+ *length /= (part->disk->dev->sector_size / PED_SECTOR_SIZE_DEFAULT); |
|
err: |
|
+ free (path); |
|
dm_task_destroy(task); |
|
return rc; |
|
} |
|
|
|
-static int |
|
-_dm_remove_parts (PedDevice* dev) |
|
-{ |
|
- struct dm_task* task = NULL; |
|
- struct dm_info* info = alloca(sizeof *info); |
|
- struct dm_names* names = NULL; |
|
- unsigned int next = 0; |
|
- int rc; |
|
- LinuxSpecific* arch_specific = LINUX_SPECIFIC (dev); |
|
- |
|
- task = dm_task_create(DM_DEVICE_LIST); |
|
- if (!task) |
|
- goto err; |
|
- |
|
- if (!dm_task_set_major_minor (task, arch_specific->major, |
|
- arch_specific->minor, 0)) |
|
- goto err; |
|
- |
|
- if (!dm_task_run(task)) |
|
- goto err; |
|
- |
|
- memset(info, '\0', sizeof *info); |
|
- dm_task_get_info(task, info); |
|
- if (!info->exists) |
|
- goto err; |
|
- |
|
- names = dm_task_get_names(task); |
|
- if (!names) |
|
- goto err; |
|
- |
|
- rc = 0; |
|
- do { |
|
- names = (void *) ((char *) names + next); |
|
- |
|
- if (_dm_is_part(info, names->name)) |
|
- rc += _dm_remove_map_name(names->name); |
|
- |
|
- next = names->next; |
|
- } while (next); |
|
- |
|
- dm_task_update_nodes(); |
|
- dm_task_destroy(task); |
|
- task = NULL; |
|
- |
|
- if (!rc) |
|
- return 1; |
|
-err: |
|
- if (task) |
|
- dm_task_destroy(task); |
|
- ped_exception_throw (PED_EXCEPTION_WARNING, PED_EXCEPTION_IGNORE, |
|
- _("parted was unable to re-read the partition " |
|
- "table on %s (%s). This means Linux won't know " |
|
- "anything about the modifications you made. "), |
|
- dev->path, strerror (errno)); |
|
- return 0; |
|
-} |
|
|
|
static int |
|
-_dm_add_partition (PedDisk* disk, PedPartition* part) |
|
+_dm_add_partition (PedDisk* disk, const PedPartition* part) |
|
{ |
|
char* vol_name = NULL; |
|
const char* dev_name = NULL; |
|
@@ -2908,9 +2818,8 @@ _dm_add_partition (PedDisk* disk, PedPartition* part) |
|
"linear", params); |
|
if (!dm_task_set_cookie(task, &cookie, 0)) |
|
goto err; |
|
- if (dm_task_run (task)) { |
|
+ if (_dm_task_run_wait (task, cookie)) { |
|
//printf("0 %ld linear %s\n", part->geom.length, params); |
|
- dm_udev_wait(cookie); |
|
dm_task_update_nodes(); |
|
dm_task_destroy(task); |
|
free(params); |
|
@@ -2918,8 +2827,7 @@ _dm_add_partition (PedDisk* disk, PedPartition* part) |
|
free(vol_name); |
|
return 1; |
|
} else { |
|
- dm_udev_wait(cookie); |
|
- _dm_remove_map_name(vol_name); |
|
+ _dm_remove_partition (disk, part->num); |
|
} |
|
err: |
|
dm_task_update_nodes(); |
|
@@ -2932,30 +2840,259 @@ err: |
|
} |
|
|
|
static int |
|
-_dm_reread_part_table (PedDisk* disk) |
|
+_dm_resize_partition (PedDisk* disk, const PedPartition* part) |
|
{ |
|
- int largest_partnum = ped_disk_get_last_partition_num (disk); |
|
- int rc = 1; |
|
- int i; |
|
+ LinuxSpecific* arch_specific = LINUX_SPECIFIC (disk->dev); |
|
+ char* params = NULL; |
|
+ char* vol_name = NULL; |
|
+ const char* dev_name = NULL; |
|
+ uint32_t cookie = 0; |
|
+ int rc = 0; |
|
|
|
- sync(); |
|
- if (!_dm_remove_parts(disk->dev)) |
|
- rc = 0; |
|
+ /* Get map name from devicemapper */ |
|
+ struct dm_task *task = dm_task_create (DM_DEVICE_INFO); |
|
+ if (!task) |
|
+ goto err; |
|
|
|
- for (i = 1; i <= largest_partnum; i++) { |
|
- PedPartition* part; |
|
+ if (!dm_task_set_major_minor (task, arch_specific->major, |
|
+ arch_specific->minor, 0)) |
|
+ goto err; |
|
|
|
- part = ped_disk_get_partition (disk, i); |
|
- if (!part) |
|
- continue; |
|
+ if (!dm_task_run(task)) |
|
+ goto err; |
|
+ |
|
+ dev_name = dm_task_get_name (task); |
|
+ size_t name_len = strlen (dev_name); |
|
+ vol_name = zasprintf ("%s%s%d", |
|
+ dev_name, |
|
+ isdigit (dev_name[name_len - 1]) ? "p" : "", |
|
+ part->num); |
|
+ if (vol_name == NULL) |
|
+ goto err; |
|
+ |
|
+ /* Caution: dm_task_destroy frees dev_name. */ |
|
+ dm_task_destroy (task); |
|
+ task = NULL; |
|
+ |
|
+ /* device-mapper uses 512b units, not the device's sector size */ |
|
+ if ( ! (params = zasprintf ("%d:%d %lld", arch_specific->major, |
|
+ arch_specific->minor, |
|
+ part->geom.start * (disk->dev->sector_size / PED_SECTOR_SIZE_DEFAULT)))) |
|
+ goto err; |
|
+ |
|
+ task = dm_task_create (DM_DEVICE_RELOAD); |
|
+ if (!task) |
|
+ goto err; |
|
|
|
- if (!_dm_add_partition (disk, part)) |
|
- rc = 0; |
|
+ dm_task_set_name (task, vol_name); |
|
+ /* device-mapper uses 512b units, not the device's sector size */ |
|
+ dm_task_add_target (task, 0, part->geom.length * (disk->dev->sector_size / PED_SECTOR_SIZE_DEFAULT), |
|
+ "linear", params); |
|
+ /* NOTE: DM_DEVICE_RELOAD doesn't generate udev events, so no cookie is needed (it will freeze). |
|
+ * DM_DEVICE_RESUME does, so get a cookie and synchronize with udev. |
|
+ */ |
|
+ if (dm_task_run (task)) { |
|
+ dm_task_destroy (task); |
|
+ task = dm_task_create (DM_DEVICE_RESUME); |
|
+ if (!task) |
|
+ goto err; |
|
+ dm_task_set_name (task, vol_name); |
|
+ if (!dm_task_set_cookie (task, &cookie, 0)) |
|
+ goto err; |
|
+ if (_dm_task_run_wait (task, cookie)) { |
|
+ rc = 1; |
|
+ } |
|
} |
|
+err: |
|
+ dm_task_update_nodes(); |
|
+ if (task) |
|
+ dm_task_destroy (task); |
|
+ free (params); |
|
+ free (vol_name); |
|
return rc; |
|
} |
|
+ |
|
#endif |
|
|
|
+/* |
|
+ * Sync the partition table in two step process: |
|
+ * 1. Remove all of the partitions from the kernel's tables, but do not attempt |
|
+ * removal of any partition for which the corresponding ioctl call fails. |
|
+ * 2. Add all the partitions that we hold in disk, throwing a warning |
|
+ * if we cannot because step 1 failed to remove it and it is not being |
|
+ * added back with the same start and length. |
|
+ * |
|
+ * To achieve this two step process we must calculate the minimum number of |
|
+ * maximum possible partitions between what linux supports and what the label |
|
+ * type supports. EX: |
|
+ * |
|
+ * number=MIN(max_parts_supported_in_linux,max_parts_supported_in_msdos_tables) |
|
+ */ |
|
+static int |
|
+_disk_sync_part_table (PedDisk* disk) |
|
+{ |
|
+ PED_ASSERT(disk != NULL); |
|
+ PED_ASSERT(disk->dev != NULL); |
|
+ int lpn, lpn2; |
|
+ unsigned int part_range = _device_get_partition_range(disk->dev); |
|
+ int (*add_partition)(PedDisk* disk, const PedPartition *part); |
|
+ int (*resize_partition)(PedDisk* disk, const PedPartition *part); |
|
+ int (*remove_partition)(PedDisk* disk, int partno); |
|
+ bool (*get_partition_start_and_length)(PedPartition const *part, |
|
+ unsigned long long *start, |
|
+ unsigned long long *length); |
|
+ |
|
+ |
|
+#ifdef ENABLE_DEVICE_MAPPER |
|
+ if (disk->dev->type == PED_DEVICE_DM) { |
|
+ add_partition = _dm_add_partition; |
|
+ remove_partition = _dm_remove_partition; |
|
+ resize_partition = _dm_resize_partition; |
|
+ get_partition_start_and_length = _dm_get_partition_start_and_length; |
|
+ } else |
|
+#endif |
|
+ { |
|
+ add_partition = _blkpg_add_partition; |
|
+ remove_partition = _blkpg_remove_partition; |
|
+#ifdef BLKPG_RESIZE_PARTITION |
|
+ resize_partition = _blkpg_resize_partition; |
|
+#else |
|
+ resize_partition = NULL; |
|
+#endif |
|
+ get_partition_start_and_length = _kernel_get_partition_start_and_length; |
|
+ } |
|
+ |
|
+ /* lpn = largest partition number. |
|
+ * for remove pass, use greater of device or label limit */ |
|
+ if (ped_disk_get_max_supported_partition_count(disk, &lpn)) |
|
+ lpn = PED_MAX(lpn, part_range); |
|
+ else |
|
+ lpn = part_range; |
|
+ /* for add pass, use lesser of device or label limit */ |
|
+ if (ped_disk_get_max_supported_partition_count(disk, &lpn2)) |
|
+ lpn2 = PED_MIN(lpn2, part_range); |
|
+ else |
|
+ lpn2 = part_range; |
|
+ /* Its not possible to support largest_partnum < 0. |
|
+ * largest_partnum == 0 would mean does not support partitions. |
|
+ * */ |
|
+ if (lpn < 1) |
|
+ return 0; |
|
+ int ret = 0; |
|
+ int *ok = calloc (lpn, sizeof *ok); |
|
+ if (!ok) |
|
+ return 0; |
|
+ int *errnums = ped_malloc(sizeof(int) * lpn); |
|
+ if (!errnums) |
|
+ goto cleanup; |
|
+ |
|
+ int i; |
|
+ /* remove old partitions first */ |
|
+ for (i = 1; i <= lpn; i++) { |
|
+ PedPartition *part = ped_disk_get_partition (disk, i); |
|
+ if (part) { |
|
+ unsigned long long length; |
|
+ unsigned long long start; |
|
+ /* get start and length of existing partition */ |
|
+ if (get_partition_start_and_length(part, |
|
+ &start, &length) |
|
+ && start == part->geom.start |
|
+ && (length == part->geom.length |
|
+ || (resize_partition && part->num < lpn2))) |
|
+ { |
|
+ /* partition is unchanged, or will be resized so nothing to do */ |
|
+ ok[i - 1] = 1; |
|
+ continue; |
|
+ } |
|
+ } |
|
+ /* Attempt to remove the partition, retrying for |
|
+ up to max_sleep_seconds upon any failure due to EBUSY. */ |
|
+ unsigned int sleep_microseconds = 10000; |
|
+ unsigned int max_sleep_seconds = 1; |
|
+ unsigned int n_sleep = (max_sleep_seconds |
|
+ * 1000000 / sleep_microseconds); |
|
+ do { |
|
+ ok[i - 1] = remove_partition (disk, i); |
|
+ errnums[i - 1] = errno; |
|
+ if (ok[i - 1] || errnums[i - 1] != EBUSY) |
|
+ break; |
|
+ usleep (sleep_microseconds); |
|
+ } while (n_sleep--); |
|
+ if (!ok[i - 1] && errnums[i - 1] == ENXIO) |
|
+ ok[i - 1] = 1; /* it already doesn't exist */ |
|
+ } |
|
+ lpn = lpn2; |
|
+ /* don't actually add partitions for loop */ |
|
+ if (strcmp (disk->type->name, "loop") == 0) |
|
+ lpn = 0; |
|
+ for (i = 1; i <= lpn; i++) { |
|
+ PedPartition *part = ped_disk_get_partition (disk, i); |
|
+ if (!part) |
|
+ continue; |
|
+ unsigned long long length; |
|
+ unsigned long long start; |
|
+ /* get start and length of existing partition */ |
|
+ if (get_partition_start_and_length(part, |
|
+ &start, &length) |
|
+ && start == part->geom.start) |
|
+ { |
|
+ if (length == part->geom.length) { |
|
+ ok[i - 1] = 1; |
|
+ /* partition is unchanged, so nothing to do */ |
|
+ continue; |
|
+ } |
|
+ if (resize_partition |
|
+ && start == part->geom.start) |
|
+ { |
|
+ /* try to resize */ |
|
+ if (resize_partition (disk, part)) { |
|
+ ok[i - 1] = 1; |
|
+ continue; |
|
+ } |
|
+ } |
|
+ } |
|
+ /* add the (possibly modified or new) partition */ |
|
+ if (!add_partition (disk, part)) { |
|
+ ok[i - 1] = 0; |
|
+ errnums[i - 1] = errno; |
|
+ } |
|
+ } |
|
+ |
|
+ char *bad_part_list = NULL; |
|
+ /* now warn about any errors */ |
|
+ for (i = 1; i <= lpn; i++) { |
|
+ if (ok[i - 1] || errnums[i - 1] == ENXIO) |
|
+ continue; |
|
+ if (bad_part_list == NULL) { |
|
+ bad_part_list = malloc (lpn * 5); |
|
+ if (!bad_part_list) |
|
+ goto cleanup; |
|
+ bad_part_list[0] = 0; |
|
+ } |
|
+ sprintf (bad_part_list + strlen (bad_part_list), "%d, ", i); |
|
+ } |
|
+ if (bad_part_list == NULL) |
|
+ ret = 1; |
|
+ else { |
|
+ bad_part_list[strlen (bad_part_list) - 2] = 0; |
|
+ if (ped_exception_throw ( |
|
+ PED_EXCEPTION_ERROR, |
|
+ PED_EXCEPTION_IGNORE_CANCEL, |
|
+ _("Partition(s) %s on %s have been written, but we have " |
|
+ "been unable to inform the kernel of the change, " |
|
+ "probably because it/they are in use. As a result, " |
|
+ "the old partition(s) will remain in use. You " |
|
+ "should reboot now before making further changes."), |
|
+ bad_part_list, disk->dev->path) == PED_EXCEPTION_IGNORE) |
|
+ ret = 1; |
|
+ free (bad_part_list); |
|
+ } |
|
+ cleanup: |
|
+ free (errnums); |
|
+ free (ok); |
|
+ return ret; |
|
+} |
|
+ |
|
static int |
|
_have_blkpg () |
|
{ |
|
@@ -2973,10 +3110,6 @@ _have_blkpg () |
|
static int |
|
linux_disk_commit (PedDisk* disk) |
|
{ |
|
-#ifdef ENABLE_DEVICE_MAPPER |
|
- if (disk->dev->type == PED_DEVICE_DM) |
|
- return _dm_reread_part_table (disk); |
|
-#endif |
|
if (disk->dev->type != PED_DEVICE_FILE) { |
|
|
|
/* We now require BLKPG support. If this assertion fails, |
|
-- |
|
2.9.4 |
|
|
|
|