summaryrefslogtreecommitdiffstats
path: root/libfdisk
diff options
context:
space:
mode:
authorKarel Zak2014-02-03 14:40:27 +0100
committerKarel Zak2014-03-11 11:35:14 +0100
commit036439315f4c29748fddd10c33d6cc4868dd9352 (patch)
treeb835ad35c81cab7e2434f04edbecdaa48a007703 /libfdisk
parentlibfdisk: don't ask for pri/log if wanted start within extended partition (diff)
downloadkernel-qcow2-util-linux-036439315f4c29748fddd10c33d6cc4868dd9352.tar.gz
kernel-qcow2-util-linux-036439315f4c29748fddd10c33d6cc4868dd9352.tar.xz
kernel-qcow2-util-linux-036439315f4c29748fddd10c33d6cc4868dd9352.zip
libfdisk: improve freesapce detection
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libfdisk')
-rw-r--r--libfdisk/src/dos.c5
-rw-r--r--libfdisk/src/fdiskP.h11
-rw-r--r--libfdisk/src/libfdisk.h3
-rw-r--r--libfdisk/src/partition.c12
-rw-r--r--libfdisk/src/table.c76
5 files changed, 83 insertions, 24 deletions
diff --git a/libfdisk/src/dos.c b/libfdisk/src/dos.c
index cb34be8ab..327a747cf 100644
--- a/libfdisk/src/dos.c
+++ b/libfdisk/src/dos.c
@@ -1612,6 +1612,11 @@ static int dos_get_partition(struct fdisk_context *cxt, size_t n,
pa->end = get_abs_partition_start(pe) + psects - (psects ? 1 : 0);
pa->size = psects;
+ if (n >= 4) {
+ pa->parent_partno = self_label(cxt)->ext_index;
+ pa->nested = 1;
+ }
+
if (asprintf(&pa->attrs, "%02x", p->boot_ind) < 0)
return -ENOMEM;
diff --git a/libfdisk/src/fdiskP.h b/libfdisk/src/fdiskP.h
index 46e6c430e..899a043b0 100644
--- a/libfdisk/src/fdiskP.h
+++ b/libfdisk/src/fdiskP.h
@@ -158,6 +158,7 @@ enum {
struct fdisk_partition {
int refcount; /* reference counter */
size_t partno; /* partition number */
+ size_t parent_partno; /* for logical partitions */
uint64_t start; /* first sectors */
uint64_t end; /* last sector */
@@ -188,8 +189,7 @@ struct fdisk_partition {
end_follow_default : 1, /* use default end */
freespace : 1, /* dthis is not partition, this is free space */
nested : 1, /* logical partition */
- used : 1, /* partition already used */
- endrel : 1; /* end is specified as relative number */
+ used : 1; /* partition already used */
};
#define FDISK_EMPTY_PARTNO ((size_t) -1)
@@ -201,13 +201,6 @@ struct fdisk_table {
size_t nents; /* number of partitions */
};
-extern int fdisk_table_add_freespace(
- struct fdisk_context *cxt,
- struct fdisk_table *tb,
- uint64_t start,
- uint64_t end,
- int dosort);
-
/*
* Legacy CHS based geometry
*/
diff --git a/libfdisk/src/libfdisk.h b/libfdisk/src/libfdisk.h
index af31b6b8c..726296c32 100644
--- a/libfdisk/src/libfdisk.h
+++ b/libfdisk/src/libfdisk.h
@@ -188,7 +188,7 @@ extern uint64_t fdisk_partition_get_start(struct fdisk_partition *pa);
extern int fdisk_partition_cmp_start(struct fdisk_partition *a,
struct fdisk_partition *b);
-extern int fdisk_partition_set_end(struct fdisk_partition *pa, uint64_t off, int isrel);
+extern int fdisk_partition_set_end(struct fdisk_partition *pa, uint64_t off);
extern uint64_t fdisk_partition_get_end(struct fdisk_partition *pa);
extern int fdisk_partition_set_size(struct fdisk_partition *pa, uint64_t size);
extern uint64_t fdisk_partition_get_size(struct fdisk_partition *pa);
@@ -207,6 +207,7 @@ extern const char *fdisk_partition_get_uuid(struct fdisk_partition *pa);
extern const char *fdisk_partition_get_attrs(struct fdisk_partition *pa);
extern int fdisk_partition_set_nested(struct fdisk_partition *pa, int nested);
extern int fdisk_partition_is_nested(struct fdisk_partition *pa);
+extern int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent);
extern int fdisk_partition_is_used(struct fdisk_partition *pa);
extern int fdisk_partition_to_string(struct fdisk_partition *pa,
struct fdisk_context *cxt,
diff --git a/libfdisk/src/partition.c b/libfdisk/src/partition.c
index da5e75c25..20993ba3a 100644
--- a/libfdisk/src/partition.c
+++ b/libfdisk/src/partition.c
@@ -72,13 +72,12 @@ int fdisk_partition_cmp_start(struct fdisk_partition *a,
return a->start - b->start;
}
-int fdisk_partition_set_end(struct fdisk_partition *pa, uint64_t off, int isrel)
+int fdisk_partition_set_end(struct fdisk_partition *pa, uint64_t off)
{
if (!pa)
return -EINVAL;
pa->end = off;
pa->size = 0;
- pa->endrel = isrel ? 1 : 0;
return 0;
}
@@ -220,6 +219,15 @@ int fdisk_partition_is_nested(struct fdisk_partition *pa)
return pa && pa->nested;
}
+int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent)
+{
+ if (pa && parent)
+ *parent = pa->parent_partno;
+ else
+ return -EINVAL;
+ return 0;
+}
+
int fdisk_partition_is_used(struct fdisk_partition *pa)
{
return pa && pa->used;
diff --git a/libfdisk/src/table.c b/libfdisk/src/table.c
index 84ce357dd..a78be477f 100644
--- a/libfdisk/src/table.c
+++ b/libfdisk/src/table.c
@@ -310,12 +310,13 @@ int fdisk_table_sort_partitions(struct fdisk_table *tb,
return 0;
}
-int fdisk_table_add_freespace(
+static int table_add_freespace(
struct fdisk_context *cxt,
struct fdisk_table *tb,
uint64_t start,
uint64_t end,
- int dosort)
+ int dosort,
+ struct fdisk_partition **res)
{
struct fdisk_partition *pa;
int rc = 0;
@@ -346,6 +347,8 @@ int fdisk_table_add_freespace(
}
rc = table_insert_partition(tb, best, pa);
}
+ if (res)
+ *res = pa;
fdisk_unref_partition(pa);
return rc;
}
@@ -368,6 +371,7 @@ int fdisk_get_freespaces(struct fdisk_context *cxt, struct fdisk_table **tb)
struct fdisk_table *parts = NULL;
struct fdisk_partition *pa;
struct fdisk_iter itr;
+ size_t cont = FDISK_EMPTY_PARTNO;
DBG(LABEL, dbgprint("get freespace"));
@@ -390,31 +394,79 @@ int fdisk_get_freespaces(struct fdisk_context *cxt, struct fdisk_table **tb)
dosort = !fdisk_table_is_empty(*tb);
last = cxt->first_lba;
- grain = cxt->grain / cxt->sector_size;
+ grain = cxt->grain > cxt->sector_size ? cxt->grain / cxt->sector_size : 1;
/* analyze gaps between partitions */
while (fdisk_table_next_partition(parts, &itr, &pa) == 0) {
-
+ if (pa->nested)
+ cont = (int) pa->parent_partno;
+ if (!pa->used || pa->nested)
+ continue;
DBG(LABEL, dbgprint("freespace analyze: partno=%zu, start=%ju, end=%ju",
pa->partno, pa->start, pa->end));
-
- if (!fdisk_partition_is_used(pa))
- continue;
if (last + grain < pa->start) {
- rc = fdisk_table_add_freespace(cxt, *tb,
+ rc = table_add_freespace(cxt, *tb,
last + (last > cxt->first_lba ? 1 : 0),
pa->start - 1,
- dosort);
+ dosort, NULL);
}
last = pa->end;
}
- /* add free-space (behind last partition) to the list */
+ /* add free-space behind last partition to the list */
if (rc == 0 && last + grain < cxt->total_sectors - 1)
- rc = fdisk_table_add_freespace(cxt, *tb,
+ rc = table_add_freespace(cxt, *tb,
last + (last > cxt->first_lba ? 1 : 0),
cxt->last_lba,
- dosort);
+ dosort, NULL);
+
+ /* add gaps between logical partitions */
+ if (cont != FDISK_EMPTY_PARTNO) {
+ uint64_t x;
+ struct fdisk_partition *fr;
+ struct fdisk_partition *parent =
+ fdisk_table_get_partition(parts, cont);
+ if (!parent)
+ goto done;
+ last = fdisk_partition_get_start(parent) + cxt->first_lba;
+
+ DBG(LABEL, dbgprint("check container freespace last=%ju, "
+ "grain=%ju, partno=%zu, start=%ju, end=%ju",
+ last, grain, parent->partno, parent->start,
+ parent->end));
+
+ fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
+
+ while (fdisk_table_next_partition(parts, &itr, &pa) == 0) {
+ uint64_t lastfree = pa->start - 1 - cxt->first_lba;
+
+ if (!pa->used || !pa->nested)
+ continue;
+ if (last + grain < lastfree) {
+ rc = table_add_freespace(cxt, *tb,
+ last + grain, lastfree,
+ dosort, &fr);
+ if (rc == 0 && fr) {
+ fr->parent_partno = parent->partno;
+ fr->nested = 1;
+ }
+ }
+ last = pa->end;
+ }
+
+ /* free-space remaining in extended partition */
+ x = fdisk_partition_get_start(parent)
+ + fdisk_partition_get_size(parent) - 1;
+ if (last + grain < x)
+ rc = table_add_freespace(cxt, *tb,
+ last + grain, x - 1,
+ dosort, &fr);
+ if (rc == 0 && fr) {
+ fr->parent_partno = parent->partno;
+ fr->nested = 1;
+ }
+ }
+
done:
fdisk_unref_table(parts);
return rc;