libfdisk: use BLKPG ioctls to inform kernel about changes
This patch introduces fdisk_reread_changes(). The function is less invasive alternative to fdisk_reread_partition_table(). The new function uses BLKPG ioctls for modified partitions. The another partitions are not affected. This solution allows to successfully use fdisks on disk where some partitions are still use (mounted). For example if you want to resize the last partition on the device. Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
87d04a3339
commit
1dd63a3b05
|
@ -325,6 +325,7 @@ fdisk_new_context
|
|||
fdisk_new_nested_context
|
||||
FDISK_PLURAL
|
||||
fdisk_ref_context
|
||||
fdisk_reread_changes
|
||||
fdisk_reread_partition_table
|
||||
fdisk_set_first_lba
|
||||
fdisk_set_last_lba
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#endif
|
||||
|
||||
#include "blkdev.h"
|
||||
#include "partx.h"
|
||||
#include "loopdev.h"
|
||||
#include "fdiskP.h"
|
||||
|
||||
|
@ -734,6 +735,107 @@ int fdisk_reread_partition_table(struct fdisk_context *cxt)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int add_to_partitions_array(
|
||||
struct fdisk_partition ***ary,
|
||||
struct fdisk_partition *pa,
|
||||
size_t *n, size_t nmax)
|
||||
{
|
||||
if (!*ary) {
|
||||
*ary = calloc(nmax, sizeof(struct fdisk_partition *));
|
||||
if (!*ary)
|
||||
return -ENOMEM;
|
||||
}
|
||||
(*ary)[*n] = pa;
|
||||
(*n)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fdisk_reread_changes:
|
||||
* @cxt: context
|
||||
* @org: original layout (on disk)
|
||||
*
|
||||
* Like fdisk_reread_partition_table() but don't forces kernel re-read all
|
||||
* partition table. The BLKPG_* ioctls are used for individual partitions. The
|
||||
* advantage is that unmodified partitions maybe mounted.
|
||||
*
|
||||
* Returns: <0 on error, or 0.
|
||||
*/
|
||||
int fdisk_reread_changes(struct fdisk_context *cxt, struct fdisk_table *org)
|
||||
{
|
||||
struct fdisk_table *tb = NULL;
|
||||
struct fdisk_iter itr;
|
||||
struct fdisk_partition *pa;
|
||||
struct fdisk_partition **rem = NULL, **add = NULL, **upd = NULL;
|
||||
int change, rc = 0, err = 0;
|
||||
size_t nparts, i, nadds = 0, nupds = 0, nrems = 0;
|
||||
|
||||
DBG(CXT, ul_debugobj(cxt, "rereading changes"));
|
||||
|
||||
fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
|
||||
|
||||
/* the current layout */
|
||||
fdisk_get_partitions(cxt, &tb);
|
||||
/* maximal number of partitions */
|
||||
nparts = max(fdisk_table_get_nents(tb), fdisk_table_get_nents(org));
|
||||
|
||||
while (fdisk_diff_tables(org, tb, &itr, &pa, &change) == 0) {
|
||||
if (change == FDISK_DIFF_UNCHANGED)
|
||||
continue;
|
||||
switch (change) {
|
||||
case FDISK_DIFF_REMOVED:
|
||||
rc = add_to_partitions_array(&rem, pa, &nrems, nparts);
|
||||
break;
|
||||
case FDISK_DIFF_ADDED:
|
||||
rc = add_to_partitions_array(&add, pa, &nadds, nparts);
|
||||
break;
|
||||
case FDISK_DIFF_RESIZED:
|
||||
rc = add_to_partitions_array(&upd, pa, &nupds, nparts);
|
||||
break;
|
||||
case FDISK_DIFF_MOVED:
|
||||
rc = add_to_partitions_array(&rem, pa, &nrems, nparts);
|
||||
rc = add_to_partitions_array(&add, pa, &nadds, nparts);
|
||||
break;
|
||||
}
|
||||
if (rc != 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0; i < nrems; i++) {
|
||||
pa = rem[i];
|
||||
DBG(PART, ul_debugobj(pa, "#%zu calling BLKPG_DEL_PARTITION", pa->partno));
|
||||
if (partx_del_partition(cxt->dev_fd, pa->partno + 1) != 0) {
|
||||
fdisk_warn(cxt, _("Failed to remove partition %zu from system"), pa->partno + 1);
|
||||
err++;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < nupds; i++) {
|
||||
pa = upd[i];
|
||||
DBG(PART, ul_debugobj(pa, "#%zu calling BLKPG_RESIZE_PARTITION", pa->partno));
|
||||
if (partx_resize_partition(cxt->dev_fd, pa->partno + 1, pa->start, pa->size) != 0) {
|
||||
fdisk_warn(cxt, _("Failed to update system information about partition %zu"), pa->partno + 1);
|
||||
err++;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < nadds; i++) {
|
||||
pa = add[i];
|
||||
DBG(PART, ul_debugobj(pa, "#%zu calling BLKPG_ADD_PARTITION", pa->partno));
|
||||
if (partx_add_partition(cxt->dev_fd, pa->partno + 1, pa->start, pa->size) != 0) {
|
||||
fdisk_warn(cxt, _("Failed to add partition %zu to system"), pa->partno + 1);
|
||||
err++;
|
||||
}
|
||||
}
|
||||
if (err)
|
||||
fdisk_info(cxt, _(
|
||||
"The kernel still uses the old partitions. The new "
|
||||
"table will be used at the next reboot. "));
|
||||
done:
|
||||
free(rem);
|
||||
free(add);
|
||||
free(upd);
|
||||
fdisk_unref_table(tb);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* fdisk_device_is_used:
|
||||
|
|
|
@ -412,6 +412,17 @@ struct fdisk_context {
|
|||
struct fdisk_script *script; /* what we want to follow */
|
||||
};
|
||||
|
||||
/* table */
|
||||
enum {
|
||||
FDISK_DIFF_UNCHANGED = 0,
|
||||
FDISK_DIFF_REMOVED,
|
||||
FDISK_DIFF_ADDED,
|
||||
FDISK_DIFF_MOVED,
|
||||
FDISK_DIFF_RESIZED
|
||||
};
|
||||
extern int fdisk_diff_tables(struct fdisk_table *a, struct fdisk_table *b,
|
||||
struct fdisk_iter *itr,
|
||||
struct fdisk_partition **res, int *change);
|
||||
|
||||
/* context.c */
|
||||
extern int __fdisk_switch_label(struct fdisk_context *cxt,
|
||||
|
|
|
@ -459,6 +459,7 @@ extern int fdisk_table_remove_partition(struct fdisk_table *tb, struct fdisk_par
|
|||
extern int fdisk_get_partitions(struct fdisk_context *cxt, struct fdisk_table **tb);
|
||||
extern int fdisk_get_freespaces(struct fdisk_context *cxt, struct fdisk_table **tb);
|
||||
|
||||
|
||||
extern int fdisk_table_wrong_order(struct fdisk_table *tb);
|
||||
extern int fdisk_table_sort_partitions(struct fdisk_table *tb,
|
||||
int (*cmp)(struct fdisk_partition *,
|
||||
|
@ -503,6 +504,7 @@ int fdisk_has_user_device_properties(struct fdisk_context *cxt);
|
|||
int fdisk_reset_alignment(struct fdisk_context *cxt);
|
||||
int fdisk_reset_device_properties(struct fdisk_context *cxt);
|
||||
int fdisk_reread_partition_table(struct fdisk_context *cxt);
|
||||
int fdisk_reread_changes(struct fdisk_context *cxt, struct fdisk_table *org);
|
||||
|
||||
/* iter.c */
|
||||
enum {
|
||||
|
|
|
@ -286,4 +286,5 @@ FDISK_2.30 {
|
|||
FDISK_2.31 {
|
||||
fdisk_reassign_device;
|
||||
fdisk_device_is_used;
|
||||
fdisk_reread_changes;
|
||||
} FDISK_2.30;
|
||||
|
|
|
@ -709,3 +709,72 @@ int fdisk_apply_table(struct fdisk_context *cxt, struct fdisk_table *tb)
|
|||
return rc;
|
||||
}
|
||||
|
||||
int fdisk_diff_tables(struct fdisk_table *a, struct fdisk_table *b,
|
||||
struct fdisk_iter *itr,
|
||||
struct fdisk_partition **res, int *change)
|
||||
{
|
||||
struct fdisk_partition *pa, *pb;
|
||||
int rc = 1;
|
||||
|
||||
assert(itr);
|
||||
assert(res);
|
||||
assert(change);
|
||||
|
||||
DBG(TAB, ul_debugobj(a, "table diff [new table=%p]", b));
|
||||
|
||||
if (a && (itr->head == NULL || itr->head == &a->parts)) {
|
||||
DBG(TAB, ul_debugobj(a, " scanning old table"));
|
||||
do {
|
||||
rc = fdisk_table_next_partition(a, itr, &pa);
|
||||
if (rc != 0)
|
||||
break;
|
||||
} while (!fdisk_partition_has_partno(pa));
|
||||
}
|
||||
|
||||
if (rc == 1 && b) {
|
||||
DBG(TAB, ul_debugobj(a, " scanning new table"));
|
||||
if (itr->head != &b->parts) {
|
||||
DBG(TAB, ul_debugobj(a, " initialize to TAB=%p", b));
|
||||
fdisk_reset_iter(itr, FDISK_ITER_FORWARD);
|
||||
}
|
||||
|
||||
while (fdisk_table_next_partition(b, itr, &pb) == 0) {
|
||||
if (!fdisk_partition_has_partno(pb))
|
||||
continue;
|
||||
if (a == NULL ||
|
||||
fdisk_table_get_partition_by_partno(a, pb->partno) == NULL) {
|
||||
DBG(TAB, ul_debugobj(a, " #%zu ADDED", pb->partno));
|
||||
*change = FDISK_DIFF_ADDED;
|
||||
*res = pb;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
DBG(TAB, ul_debugobj(a, "table diff done [rc=%d]", rc));
|
||||
return rc; /* error or done */
|
||||
}
|
||||
|
||||
pb = fdisk_table_get_partition_by_partno(b, pa->partno);
|
||||
|
||||
if (!pb) {
|
||||
DBG(TAB, ul_debugobj(a, " #%zu REMOVED", pa->partno));
|
||||
*change = FDISK_DIFF_REMOVED;
|
||||
*res = pa;
|
||||
} else if (pb->start != pa->start) {
|
||||
DBG(TAB, ul_debugobj(a, " #%zu MOVED", pb->partno));
|
||||
*change = FDISK_DIFF_MOVED;
|
||||
*res = pb;
|
||||
} else if (pb->size != pa->size) {
|
||||
DBG(TAB, ul_debugobj(a, " #%zu RESIZED", pb->partno));
|
||||
*change = FDISK_DIFF_RESIZED;
|
||||
*res = pb;
|
||||
} else {
|
||||
DBG(TAB, ul_debugobj(a, " #%zu UNCHANGED", pb->partno));
|
||||
*change = FDISK_DIFF_UNCHANGED;
|
||||
*res = pa;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue