Date: Sun, 16 Jan 2011 18:46:17 +0000 (UTC) From: Nathan Whitehorn <nwhitehorn@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r217480 - user/nwhitehorn/bsdinstall/partedit Message-ID: <201101161846.p0GIkHXe073337@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: nwhitehorn Date: Sun Jan 16 18:46:17 2011 New Revision: 217480 URL: http://svn.freebsd.org/changeset/base/217480 Log: Improve the robustness of the partition wizard. Modified: user/nwhitehorn/bsdinstall/partedit/gpart_ops.c user/nwhitehorn/bsdinstall/partedit/part_wizard.c user/nwhitehorn/bsdinstall/partedit/partedit.c user/nwhitehorn/bsdinstall/partedit/partedit.h Modified: user/nwhitehorn/bsdinstall/partedit/gpart_ops.c ============================================================================== --- user/nwhitehorn/bsdinstall/partedit/gpart_ops.c Sun Jan 16 18:04:01 2011 (r217479) +++ user/nwhitehorn/bsdinstall/partedit/gpart_ops.c Sun Jan 16 18:46:17 2011 (r217480) @@ -517,6 +517,105 @@ set_default_part_metadata(const char *na } } +static +int part_compare(const void *xa, const void *xb) +{ + struct gprovider **a = (struct gprovider **)xa; + struct gprovider **b = (struct gprovider **)xb; + intmax_t astart, bstart; + struct gconfig *gc; + + astart = bstart = 0; + LIST_FOREACH(gc, &(*a)->lg_config, lg_config) + if (strcmp(gc->lg_name, "start") == 0) { + astart = strtoimax(gc->lg_val, NULL, 0); + break; + } + LIST_FOREACH(gc, &(*b)->lg_config, lg_config) + if (strcmp(gc->lg_name, "start") == 0) { + bstart = strtoimax(gc->lg_val, NULL, 0); + break; + } + + if (astart < bstart) + return -1; + else if (astart > bstart) + return 1; + else + return 0; +} + +intmax_t +gpart_max_free(struct ggeom *geom, intmax_t *npartstart) +{ + struct gconfig *gc; + struct gprovider *pp, **providers; + intmax_t lastend; + intmax_t start, end; + intmax_t maxsize, maxstart; + intmax_t partstart, partend; + int i, nparts; + + /* Now get the maximum free size and free start */ + start = end = 0; + LIST_FOREACH(gc, &geom->lg_config, lg_config) { + if (strcmp(gc->lg_name, "first") == 0) + start = strtoimax(gc->lg_val, NULL, 0); + if (strcmp(gc->lg_name, "last") == 0) + end = strtoimax(gc->lg_val, NULL, 0); + } + + i = nparts = 0; + LIST_FOREACH(pp, &geom->lg_provider, lg_provider) + nparts++; + providers = calloc(nparts, sizeof(providers[0])); + LIST_FOREACH(pp, &geom->lg_provider, lg_provider) + providers[i++] = pp; + qsort(providers, nparts, sizeof(providers[0]), part_compare); + + lastend = start - 1; + maxsize = 0; + for (i = 0; i < nparts; i++) { + pp = providers[i]; + + LIST_FOREACH(gc, &pp->lg_config, lg_config) { + if (strcmp(gc->lg_name, "start") == 0) + partstart = strtoimax(gc->lg_val, NULL, 0); + if (strcmp(gc->lg_name, "end") == 0) + partend = strtoimax(gc->lg_val, NULL, 0); + } + + if (partstart - lastend > maxsize) { + maxsize = partstart - lastend - 1; + maxstart = lastend + 1; + } + + lastend = partend; + } + + if (end - lastend > maxsize) { + maxsize = end - lastend - 1; + maxstart = lastend + 1; + } + + pp = LIST_FIRST(&geom->lg_consumer)->lg_provider; + + /* Compute beginning of new partition and maximum available space */ + if (pp->lg_stripesize > 0 && + (maxstart*pp->lg_sectorsize % pp->lg_stripesize) != 0) { + intmax_t offset = (pp->lg_stripesize - + ((maxstart*pp->lg_sectorsize) % pp->lg_stripesize)) / + pp->lg_sectorsize; + maxstart += offset; + maxsize -= offset; + } + + if (npartstart != NULL) + *npartstart = maxstart; + + return (maxsize); +} + void gpart_create(struct gprovider *pp, char *default_type, char *default_size, char *default_mountpoint, char **partname, int interactive) @@ -527,7 +626,7 @@ gpart_create(struct gprovider *pp, char struct ggeom *geom; const char *errstr, *scheme; char sizestr[32], startstr[32], output[64]; - intmax_t maxsize, size, start, end, sector, firstfree, stripe; + intmax_t maxsize, size, sector, firstfree, stripe; uint64_t bytes; int nitems, choice, junk; unsigned i; @@ -586,34 +685,12 @@ gpart_create(struct gprovider *pp, char if (geom == NULL) return; - /* Now get the maximum free size and free start */ - start = end = 0; - LIST_FOREACH(gc, &geom->lg_config, lg_config) { - if (strcmp(gc->lg_name, "first") == 0) - start = strtoimax(gc->lg_val, NULL, 0); - if (strcmp(gc->lg_name, "last") == 0) - end = strtoimax(gc->lg_val, NULL, 0); + /* Now get the partition scheme */ + LIST_FOREACH(gc, &geom->lg_config, lg_config) if (strcmp(gc->lg_name, "scheme") == 0) scheme = gc->lg_val; - } - - firstfree = start; - LIST_FOREACH(pp, &geom->lg_provider, lg_provider) { - LIST_FOREACH(gc, &pp->lg_config, lg_config) { - if (strcmp(gc->lg_name, "end") == 0) { - intmax_t partend; - partend = strtoimax(gc->lg_val, NULL, 0); - if (partend > firstfree) - firstfree = partend + 1; - } - } - } - - /* Compute beginning of new partition and maximum available space */ - if (stripe > 0 && (firstfree*sector % stripe) != 0) - firstfree += (stripe - ((firstfree*sector) % stripe)) / sector; - size = end - firstfree; + size = gpart_max_free(geom, &firstfree); if (size <= 0) { dialog_msgbox("Error", "No free space left on device.", 0, 0, TRUE); @@ -621,8 +698,8 @@ gpart_create(struct gprovider *pp, char } /* Leave a free megabyte in case we need to write a boot partition */ - if (size*sector >= 1024*1024) - size -= 1024*1024/sector; + if (size*sector >= (intmax_t)bootpart_size(scheme)) + size -= bootpart_size(scheme)/sector; maxsize = size; humanize_number(sizestr, 7, size*sector, "B", HN_AUTOSCALE, Modified: user/nwhitehorn/bsdinstall/partedit/part_wizard.c ============================================================================== --- user/nwhitehorn/bsdinstall/partedit/part_wizard.c Sun Jan 16 18:04:01 2011 (r217479) +++ user/nwhitehorn/bsdinstall/partedit/part_wizard.c Sun Jan 16 18:46:17 2011 (r217480) @@ -9,11 +9,12 @@ #include "partedit.h" -#define GPART_FLAGS "x" /* Do not commit changes by default */ +#define MIN_FREE_SPACE (1024*1024*1024) /* 1 GB */ +#define SWAP_SIZE(available) MIN(available/20, 4*1024*1024*1024LL) static char *boot_disk(struct gmesh *mesh); static char *wizard_partition(struct gmesh *mesh, const char *disk); -static void wizard_makeparts(struct gmesh *mesh, const char *disk); +static int wizard_makeparts(struct gmesh *mesh, const char *disk); int part_wizard(void) { @@ -21,6 +22,7 @@ part_wizard(void) { struct gmesh mesh; char *disk, *schemeroot; +startwizard: error = geom_gettree(&mesh); dlg_put_backtitle(); @@ -40,7 +42,9 @@ part_wizard(void) { geom_deletetree(&mesh); error = geom_gettree(&mesh); - wizard_makeparts(&mesh, schemeroot); + error = wizard_makeparts(&mesh, schemeroot); + if (error) + goto startwizard; free(schemeroot); geom_deletetree(&mesh); @@ -212,7 +216,7 @@ query: return (retval); } -static void +static int wizard_makeparts(struct gmesh *mesh, const char *disk) { struct gmesh submesh; @@ -221,9 +225,9 @@ wizard_makeparts(struct gmesh *mesh, con struct gconfig *gc; const char *scheme; struct gprovider *pp; - intmax_t start, end; - intmax_t swapsize; + intmax_t swapsize, available; char swapsizestr[10], rootsizestr[10]; + int retval; LIST_FOREACH(classp, &mesh->lg_class, lg_class) if (strcmp(classp->lg_name, "PART") == 0) @@ -233,23 +237,37 @@ wizard_makeparts(struct gmesh *mesh, con if (strcmp(gp->lg_name, disk) == 0) break; - LIST_FOREACH(gc, &gp->lg_config, lg_config) { - if (strcmp(gc->lg_name, "first") == 0) - start = strtoimax(gc->lg_val, NULL, 0); - if (strcmp(gc->lg_name, "last") == 0) - end = strtoimax(gc->lg_val, NULL, 0); + LIST_FOREACH(gc, &gp->lg_config, lg_config) if (strcmp(gc->lg_name, "scheme") == 0) scheme = gc->lg_val; - } pp = provider_for_name(mesh, disk); - swapsize = MIN((end - start)*pp->lg_sectorsize/50, - 4*1024*1024*(intmax_t)(1024)); + available = gpart_max_free(gp, NULL)*pp->lg_sectorsize; + if (available < MIN_FREE_SPACE) { + char availablestr[10], neededstr[10], message[512]; + humanize_number(availablestr, 7, available, "B", HN_AUTOSCALE, + HN_DECIMAL); + humanize_number(neededstr, 7, MIN_FREE_SPACE, "B", HN_AUTOSCALE, + HN_DECIMAL); + sprintf(message, "There is not enough free space on %s to " + "install FreeBSD (%s free, %s required). Would you like " + "to choose another disk or to open the partition editor?", + disk, availablestr, neededstr); + + dialog_vars.yes_label = "Another Disk"; + dialog_vars.no_label = "Editor"; + retval = dialog_yesno("Warning", message, 0, 0); + dialog_vars.yes_label = NULL; + dialog_vars.no_label = NULL; + + return (!retval); /* Editor -> return 0 */ + } + + swapsize = SWAP_SIZE(available); humanize_number(swapsizestr, 7, swapsize, "B", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL); - humanize_number(rootsizestr, 7, - (end - start)*pp->lg_sectorsize - swapsize - 1024*1024, + humanize_number(rootsizestr, 7, available - swapsize - 1024*1024, "B", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL); geom_gettree(&submesh); @@ -261,4 +279,7 @@ wizard_makeparts(struct gmesh *mesh, con pp = provider_for_name(&submesh, disk); gpart_create(pp, "freebsd-swap", swapsizestr, NULL, NULL, 0); geom_deletetree(&submesh); + + return (0); } + Modified: user/nwhitehorn/bsdinstall/partedit/partedit.c ============================================================================== --- user/nwhitehorn/bsdinstall/partedit/partedit.c Sun Jan 16 18:04:01 2011 (r217479) +++ user/nwhitehorn/bsdinstall/partedit/partedit.c Sun Jan 16 18:46:17 2011 (r217480) @@ -25,6 +25,7 @@ static int validate_setup(void); int main(int argc, const char **argv) { struct partition_metadata *md; + const char *prompt; struct partedit_item *items; struct gmesh mesh; int i, op, nitems, nscroll; @@ -40,8 +41,14 @@ main(int argc, const char **argv) { dialog_vars.item_help = TRUE; nscroll = i = 0; - if (strcmp(basename(argv[0]), "autopart") == 0) /* Guided */ + if (strcmp(basename(argv[0]), "autopart") == 0) { /* Guided */ + prompt = "Please review the disk setup. When complete, press " + "the Finished button."; part_wizard(); + } else { + prompt = "Create partitions for FreeBSD. No changes will be " + "made until you select Finished."; + } /* Show the part editor either immediately, or to confirm wizard */ while (1) { @@ -53,9 +60,7 @@ main(int argc, const char **argv) { if (i >= nitems) i = nitems - 1; - op = diskeditor_show("Partition Editor", - "Create partitions for FreeBSD. No changes will be made " - "until you select Finished.", + op = diskeditor_show("Partition Editor", prompt, items, nitems, &i, &nscroll); switch (op) { @@ -95,7 +100,7 @@ main(int argc, const char **argv) { if (op == 4 && validate_setup()) { /* Finished */ dialog_vars.extra_button = TRUE; dialog_vars.extra_label = - __DECONST(char *, "Don't Save"); + __DECONST(char *, "Abort"); dialog_vars.ok_label = __DECONST(char *, "Save"); op = dialog_yesno("Confirmation", "Your changes will " "now be written to disk. If you have chosen to " Modified: user/nwhitehorn/bsdinstall/partedit/partedit.h ============================================================================== --- user/nwhitehorn/bsdinstall/partedit/partedit.h Sun Jan 16 18:04:01 2011 (r217479) +++ user/nwhitehorn/bsdinstall/partedit/partedit.h Sun Jan 16 18:46:17 2011 (r217480) @@ -1,4 +1,5 @@ #include <sys/queue.h> +#include <inttypes.h> #include <fstab.h> struct gprovider; @@ -30,6 +31,7 @@ void gpart_destroy(struct ggeom *lg_geom void gpart_edit(struct gprovider *pp); void gpart_create(struct gprovider *pp, char *default_type, char *default_size, char *default_mountpoint, char **output, int interactive); +intmax_t gpart_max_free(struct ggeom *gp, intmax_t *start); void gpart_revert(struct gprovider *pp); void gpart_revert_all(struct gmesh *mesh); void gpart_commit(struct gmesh *mesh);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201101161846.p0GIkHXe073337>