#define sector(s) ((s) & 0x3f)
#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
-#define fdisk_is_disklabel(c, x) fdisk_dev_is_disklabel(c, FDISK_DISKLABEL_ ## x)
/* menu list description */
partitions = 4; /* maximum partition + 1 */
unsigned int user_cylinders, user_heads, user_sectors;
-sector_t sector_offset = 1;
unsigned int units_per_sector = 1, display_in_cyl_units = 0;
static void __attribute__ ((__noreturn__)) usage(FILE *out)
else {
sector_t sects_in_phy = cxt->grain / cxt->sector_size;
- if (lba < sector_offset)
- res = sector_offset;
+ if (lba < cxt->first_lba)
+ res = cxt->first_lba;
else if (direction == ALIGN_UP)
res = ((lba + sects_in_phy) / sects_in_phy) * sects_in_phy;
}
-/*
- * Sets LBA of the first partition
- */
-void
-update_sector_offset(struct fdisk_context *cxt)
-{
- cxt->grain = cxt->io_size;
-
- if (dos_compatible_flag)
- sector_offset = cxt->geom.sectors; /* usually 63 sectors */
- else {
- /*
- * Align the begin of partitions to:
- *
- * a) topology
- * a2) alignment offset
- * a1) or physical sector (minimal_io_size, aka "grain")
- *
- * b) or default to 1MiB (2048 sectrors, Windows Vista default)
- *
- * c) or for very small devices use 1 phy.sector
- */
- sector_t x = 0;
-
- if (fdisk_dev_has_topology(cxt)) {
- if (cxt->alignment_offset)
- x = cxt->alignment_offset;
- else if (cxt->io_size > 2048 * 512)
- x = cxt->io_size;
- }
- /* default to 1MiB */
- if (!x)
- x = 2048 * 512;
-
- sector_offset = x / cxt->sector_size;
-
- /* don't use huge offset on small devices */
- if (cxt->total_sectors <= sector_offset * 4)
- sector_offset = cxt->phy_sector_size / cxt->sector_size;
-
- /* use 1MiB grain always when possible */
- if (cxt->grain < 2048 * 512)
- cxt->grain = 2048 * 512;
-
- /* don't use huge grain on small devices */
- if (cxt->total_sectors <= (cxt->grain * 4 / cxt->sector_size))
- cxt->grain = cxt->phy_sector_size;
- }
-}
-
static int is_partition_table_changed(void)
{
int i;
else
printf(_("DOS Compatibility flag is not set\n"));
- update_sector_offset(cxt);
+ fdisk_reset_alignment(cxt);
}
static void delete_partition(struct fdisk_context *cxt, int partnum)
move_begin(cxt, get_partition(cxt, 0, partitions));
break;
case 'c':
- user_cylinders = cxt->geom.cylinders =
- read_int(cxt, 1, cxt->geom.cylinders, 1048576, 0,
+ user_cylinders = read_int(cxt, 1, cxt->geom.cylinders, 1048576, 0,
_("Number of cylinders"));
+ fdisk_context_set_user_geometry(cxt, user_cylinders, user_heads, user_sectors);
if (fdisk_is_disklabel(cxt, SUN))
sun_set_ncyl(cxt, cxt->geom.cylinders);
break;
fdisk_create_disklabel(cxt, "sgi");
break;
case 'h':
- user_heads = cxt->geom.heads = read_int(cxt, 1, cxt->geom.heads, 256, 0,
+ user_heads = read_int(cxt, 1, cxt->geom.heads, 256, 0,
_("Number of heads"));
+ fdisk_context_set_user_geometry(cxt, user_cylinders, user_heads, user_sectors);
update_units(cxt);
break;
case 'i':
case 'r':
return;
case 's':
- user_sectors = cxt->geom.sectors = read_int(cxt, 1, cxt->geom.sectors, 63, 0,
+ user_sectors = read_int(cxt, 1, cxt->geom.sectors, 63, 0,
_("Number of sectors"));
if (dos_compatible_flag)
fprintf(stderr, _("Warning: setting "
"sector offset for DOS "
"compatibility\n"));
- update_sector_offset(cxt);
+ fdisk_context_set_user_geometry(cxt, user_cylinders, user_heads, user_sectors);
update_units(cxt);
break;
case 'v':
if (sector_size != 512 && sector_size != 1024 &&
sector_size != 2048 && sector_size != 4096)
usage(stderr);
- sector_offset = 2;
break;
case 'C':
user_cylinders = strtou32_or_err(optarg, _("invalid cylinders argument"));
enum fdisk_labeltype disklabel; /* current disklabel */
+ /* alignment */
unsigned long grain; /* alignment unit */
+ sector_t first_lba; /* recommended begin of the first partition */
/* geometry */
sector_t total_sectors; /* in logical sectors */
const struct fdisk_label *label;
};
+#define fdisk_is_disklabel(c, x) fdisk_dev_is_disklabel(c, FDISK_DISKLABEL_ ## x)
+
/*
* Label specific operations
*/
struct fdisk_parttype *(*part_get_type)(struct fdisk_context *cxt, int partnum);
/* set partition type */
int (*part_set_type)(struct fdisk_context *cxt, int partnum, struct fdisk_parttype *t);
+ /* refresh alignment setting */
+ int (*reset_alignment)(struct fdisk_context *cxt);
};
/*
extern int fdisk_write_disklabel(struct fdisk_context *cxt);
extern int fdisk_verify_disklabel(struct fdisk_context *cxt);
extern int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name);
+extern int fdisk_reset_alignment(struct fdisk_context *cxt);
extern struct fdisk_parttype *fdisk_get_partition_type(struct fdisk_context *cxt, int partnum);
extern int fdisk_set_partition_type(struct fdisk_context *cxt, int partnum,
struct fdisk_parttype *t);
extern struct fdisk_parttype *fdisk_new_unknown_parttype(unsigned int type, const char *typestr);
extern void fdisk_free_parttype(struct fdisk_parttype *type);
+extern sector_t fdisk_topology_get_first_lba(struct fdisk_context *cxt);
+extern unsigned long fdisk_topology_get_grain(struct fdisk_context *cxt);
+
/* prototypes for fdisk.c */
extern char *line_ptr;
extern int partitions;
unsigned int base, char *mesg, int *is_suffix_used);
extern sector_t align_lba(struct fdisk_context *cxt, sector_t lba, int direction);
extern int get_partition_dflt(struct fdisk_context *cxt, int warn, int max, int dflt);
-extern void update_sector_offset(struct fdisk_context *cxt);
#define PLURAL 0
#define SINGULAR 1
s |= (sector >> 2) & 0xc0; \
}
-#define alignment_required (cxt->grain != cxt->sector_size)
+#define alignment_required(_x) ((_x)->grain != (_x)->sector_size)
struct pte ptes[MAXIMUM_PARTS];
sector_t extended_offset;
*ph = hh;
*ps = ss;
}
+
+ DBG(CONTEXT, dbgprint("DOS PT geometry: heads=%u, sectors=%u", *ph, *ps));
}
+static int dos_reset_alignment(struct fdisk_context *cxt)
+{
+ /* overwrite necessary stuff by DOS deprecated stuff */
+ if (dos_compatible_flag) {
+ if (cxt->geom.sectors)
+ cxt->first_lba = cxt->geom.sectors; /* usually 63 */
+
+ cxt->grain = cxt->sector_size; /* usually 512 */
+ }
+ /* units_per_sector has impact to deprecated DOS stuff */
+ update_units(cxt);
+
+ return 0;
+}
static int dos_probe_label(struct fdisk_context *cxt)
{
ptes[i].changed = 1;
}
-static sector_t get_unused_start(int part_n, sector_t start,
+static sector_t get_unused_start(struct fdisk_context *cxt,
+ int part_n, sector_t start,
sector_t first[], sector_t last[])
{
int i;
sector_t lastplusoff;
if (start == ptes[i].offset)
- start += sector_offset;
- lastplusoff = last[i] + ((part_n < 4) ? 0 : sector_offset);
+ start += cxt->first_lba;
+ lastplusoff = last[i] + ((part_n < 4) ? 0 : cxt->first_lba);
if (start >= first[i] && start <= lastplusoff)
start = lastplusoff + 1;
}
}
fill_bounds(first, last);
if (n < 4) {
- start = sector_offset;
+ start = cxt->first_lba;
if (display_in_cyl_units || !cxt->total_sectors)
limit = cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders - 1;
else
get_nr_sects(q) - 1;
}
} else {
- start = extended_offset + sector_offset;
+ start = extended_offset + cxt->first_lba;
limit = get_start_sect(q) + get_nr_sects(q) - 1;
}
if (display_in_cyl_units)
sector_t dflt, aligned;
temp = start;
- dflt = start = get_unused_start(n, start, first, last);
+ dflt = start = get_unused_start(cxt, n, start, first, last);
/* the default sector should be aligned and unused */
do {
aligned = align_lba_in_range(cxt, dflt, dflt, limit);
- dflt = get_unused_start(n, aligned, first, last);
+ dflt = get_unused_start(cxt, n, aligned, first, last);
} while (dflt != aligned && dflt > aligned && dflt < limit);
if (dflt >= limit)
if (n > 4) { /* NOT for fifth partition */
struct pte *pe = &ptes[n];
- pe->offset = start - sector_offset;
+ pe->offset = start - cxt->first_lba;
if (pe->offset == extended_offset) { /* must be corrected */
pe->offset++;
- if (sector_offset == 1)
+ if (cxt->first_lba == 1)
start++;
}
}
stop = limit;
}
- if (is_suffix_used && alignment_required) {
+ if (is_suffix_used && alignment_required(cxt)) {
/* the last sector has not been exactly requested (but
* defined by +size{K,M,G} convention), so be smart
* and align the end of the partition. The next
.part_delete = dos_delete_partition,
.part_get_type = dos_get_parttype,
.part_set_type = dos_set_parttype,
+ .reset_alignment = dos_reset_alignment,
};
(n) * sizeof(struct partition)))
extern int ext_index; /* the prime extended partition */
-extern sector_t extended_offset, sector_offset;
+extern sector_t extended_offset;
/* A valid partition table sector ends in 0x55 0xaa */
static inline unsigned int part_table_flag(unsigned char *b)
cxt->phy_sector_size = cxt->sector_size = s;
cxt->min_io_size = cxt->io_size = s;
- update_sector_offset(cxt);
+ fdisk_reset_alignment(cxt);
return 0;
}
else
recount_geometry(cxt);
- update_sector_offset(cxt);
+ fdisk_reset_alignment(cxt);
return 0;
}
return 0;
}
+
/**
* fdisk_zeroize_firstsector:
* @cxt: fdisk context
return 0;
}
+/*
+ * The LBA of the first partition is based on the device geometry and topology.
+ * This offset is generic (and recommended) for all labels.
+ *
+ * Returns: 0 on error or number of logical sectors.
+ */
+sector_t fdisk_topology_get_first_lba(struct fdisk_context *cxt)
+{
+ sector_t x = 0, res;
+
+ if (!cxt)
+ return 0;
+
+ if (!cxt->io_size)
+ __discover_topology(cxt);
+
+ /*
+ * Align the begin of partitions to:
+ *
+ * a) topology
+ * a2) alignment offset
+ * a1) or physical sector (minimal_io_size, aka "grain")
+ *
+ * b) or default to 1MiB (2048 sectrors, Windows Vista default)
+ *
+ * c) or for very small devices use 1 phy.sector
+ */
+ if (fdisk_dev_has_topology(cxt)) {
+ if (cxt->alignment_offset)
+ x = cxt->alignment_offset;
+ else if (cxt->io_size > 2048 * 512)
+ x = cxt->io_size;
+ }
+ /* default to 1MiB */
+ if (!x)
+ x = 2048 * 512;
+
+ res = x / cxt->sector_size;
+
+ /* don't use huge offset on small devices */
+ if (cxt->total_sectors <= res * 4)
+ res = cxt->phy_sector_size / cxt->sector_size;
+
+ return res;
+}
+
+/*
+ * The LBA of the first partition is based on the device geometry and topology.
+ * This offset is generic generic (and recommended) for all labels.
+ *
+ * Returns: 0 on error or number of bytes.
+ */
+unsigned long fdisk_topology_get_grain(struct fdisk_context *cxt)
+{
+ unsigned long res;
+
+ if (!cxt)
+ return 0;
+
+ if (!cxt->io_size)
+ __discover_topology(cxt);
+
+ res = cxt->io_size;
+
+ /* use 1MiB grain always when possible */
+ if (res < 2048 * 512)
+ res = 2048 * 512;
+
+ /* don't use huge grain on small devices */
+ if (cxt->total_sectors <= (res * 4 / cxt->sector_size))
+ res = cxt->phy_sector_size;
+
+ return res;
+}
+
+/**
+ * fdisk_reset_alignment:
+ * @cxt: fdisk context
+ *
+ * Resets alignment setting to the default or label specific values.
+ *
+ * Returns: 0 on success, < 0 in case of error.
+ */
+int fdisk_reset_alignment(struct fdisk_context *cxt)
+{
+ int rc = 0;
+
+ if (!cxt)
+ return -EINVAL;
+
+ /* default */
+ cxt->grain = fdisk_topology_get_grain(cxt);
+ cxt->first_lba = fdisk_topology_get_first_lba(cxt);
+
+ /* overwrite default by label stuff */
+ if (cxt->label && cxt->label->reset_alignment)
+ rc = cxt->label->reset_alignment(cxt);
+
+ DBG(LABEL, dbgprint("%s alignment reseted to: "
+ "first LBA=%ju, grain=%lu [rc=%d]",
+ cxt->label ? cxt->label->name : NULL,
+ (uintmax_t) cxt->first_lba,
+ cxt->grain, rc));
+ return rc;
+}
+
/**
* fdisk_dev_has_disklabel:
* @cxt: fdisk context
if (!cxt->label->create)
return -ENOSYS;
+ fdisk_reset_alignment(cxt);
+
return cxt->label->create(cxt);
}
* to the context */
__probe_labels(cxt);
- update_sector_offset(cxt);
+ fdisk_reset_alignment(cxt);
DBG(CONTEXT, dbgprint("context %p initialized for %s [%s]",
cxt, fname,