Index: sys/geom/geom_io.c =================================================================== --- sys/geom/geom_io.c +++ sys/geom/geom_io.c @@ -925,17 +925,25 @@ struct bio *bp; void *ptr; int errorc; + off_t start_align; + off_t end_align; - KASSERT(length > 0 && length >= cp->provider->sectorsize && - length <= MAXPHYS, ("g_read_data(): invalid length %jd", - (intmax_t)length)); + KASSERT(length > 0 && length <= MAXPHYS, + ("g_read_data(): invalid length %jd", (intmax_t)length)); + /* allow unaligned reads */ + start_align = (offset % cp->provider->sectorsize); + end_align = (cp->provider->sectorsize - ((offset + length) % + cp->provider->sectorsize)) % cp->provider->sectorsize; + + /* setup BIO request */ bp = g_alloc_bio(); bp->bio_cmd = BIO_READ; bp->bio_done = NULL; - bp->bio_offset = offset; - bp->bio_length = length; - ptr = g_malloc(length, M_WAITOK); + bp->bio_offset = offset - start_align; + bp->bio_length = length + start_align + end_align; + + ptr = g_malloc(bp->bio_length, M_WAITOK); bp->bio_data = ptr; g_io_request(bp, cp); errorc = biowait(bp, "gread"); @@ -945,6 +953,10 @@ if (errorc) { g_free(ptr); ptr = NULL; + } else { + /* check if buffer data should be shifted down */ + if (start_align != 0) + memmove(ptr, (uint8_t *)ptr + start_align, length); } return (ptr); } @@ -979,21 +991,42 @@ g_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length) { struct bio *bp; + void *fixup; int error; + off_t start_align; + off_t end_align; - KASSERT(length > 0 && length >= cp->provider->sectorsize && - length <= MAXPHYS, ("g_write_data(): invalid length %jd", - (intmax_t)length)); + KASSERT(length > 0 && length <= MAXPHYS, + ("g_write_data(): invalid length %jd", (intmax_t)length)); + /* allow unaligned writes */ + start_align = (offset % cp->provider->sectorsize); + end_align = (cp->provider->sectorsize - ((offset + length) % + cp->provider->sectorsize)) % cp->provider->sectorsize; + + /* check if we need to do a fixup request */ + if (start_align != 0 || end_align != 0) { + fixup = g_read_data(cp, offset - start_align, + length + start_align + end_align, &error); + if (fixup == NULL) + return (error); + memcpy((uint8_t *)fixup + start_align, ptr, length); + } else { + fixup = ptr; + } + + /* setup BIO request */ bp = g_alloc_bio(); bp->bio_cmd = BIO_WRITE; bp->bio_done = NULL; - bp->bio_offset = offset; - bp->bio_length = length; - bp->bio_data = ptr; + bp->bio_offset = offset - start_align; + bp->bio_length = length + start_align + end_align; + bp->bio_data = fixup; g_io_request(bp, cp); error = biowait(bp, "gwrite"); g_destroy_bio(bp); + if (fixup != ptr) + g_free(fixup); return (error); } Index: sys/geom/part/g_part_bsd.c =================================================================== --- sys/geom/part/g_part_bsd.c +++ sys/geom/part/g_part_bsd.c @@ -48,6 +48,7 @@ #include "g_part_if.h" +#define MIN_SECT_SIZE MAX(sizeof(struct disklabel), 512) #define BOOT1_SIZE 512 #define LABEL_SIZE 512 #define BOOT2_OFF (BOOT1_SIZE + LABEL_SIZE) @@ -55,10 +56,20 @@ FEATURE(geom_part_bsd, "GEOM partitioning class for BSD disklabels"); +SYSCTL_DECL(_kern_geom_part); +static SYSCTL_NODE(_kern_geom_part, OID_AUTO, bsd, CTLFLAG_RW, 0, + "GEOM_PART_BSD BSD disklabels"); + +static u_int enforce_512bbs = 1; +SYSCTL_UINT(_kern_geom_part_bsd, OID_AUTO, enforce_512bbs, + CTLFLAG_RWTUN, &enforce_512bbs, 0, "Enforce 512 byte block size"); + struct g_part_bsd_table { struct g_part_table base; u_char *bbarea; uint32_t offset; + off_t sectorsize; + off_t sectorfact; }; struct g_part_bsd_entry { @@ -204,7 +215,7 @@ pp = gpp->gpp_provider; - if (pp->sectorsize < sizeof(struct disklabel)) + if (pp->sectorsize < MIN_SECT_SIZE) return (ENOSPC); if (BBSIZE % pp->sectorsize) return (ENOTBLK); @@ -215,15 +226,24 @@ table = (struct g_part_bsd_table *)basetable; table->bbarea = g_malloc(BBSIZE, M_WAITOK | M_ZERO); - ptr = table->bbarea + pp->sectorsize; + if (enforce_512bbs) { + table->sectorfact = pp->sectorsize / 512; + table->sectorsize = 512; + } else { + table->sectorfact = 1; + table->sectorsize = pp->sectorsize; + } + + ptr = table->bbarea + table->sectorsize; + le32enc(ptr + 0, DISKMAGIC); /* d_magic */ - le32enc(ptr + 40, pp->sectorsize); /* d_secsize */ + le32enc(ptr + 40, table->sectorsize); /* d_secsize */ le32enc(ptr + 44, basetable->gpt_sectors); /* d_nsectors */ le32enc(ptr + 48, basetable->gpt_heads); /* d_ntracks */ le32enc(ptr + 52, ncyls); /* d_ncylinders */ le32enc(ptr + 56, secpercyl); /* d_secpercyl */ - le32enc(ptr + 60, msize); /* d_secperunit */ + le32enc(ptr + 60, msize * table->sectorfact); /* d_secperunit */ le16enc(ptr + 72, 3600); /* d_rpm */ le32enc(ptr + 132, DISKMAGIC); /* d_magic2 */ le16enc(ptr + 138, basetable->gpt_entries); /* d_npartitions */ @@ -313,7 +333,7 @@ table = (struct g_part_bsd_table *)basetable; msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX); - le32enc(table->bbarea + pp->sectorsize + 60, msize); /* d_secperunit */ + le32enc(table->bbarea + pp->sectorsize + 60, msize * table->sectorfact); /* d_secperunit */ basetable->gpt_last = msize - 1; LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) { if (baseentry->gpe_index != RAW_PART + 1) @@ -354,24 +374,33 @@ } static int -g_part_bsd_probe(struct g_part_table *table, struct g_consumer *cp) +g_part_bsd_probe(struct g_part_table *basetable, struct g_consumer *cp) { + struct g_part_bsd_table *table; struct g_provider *pp; u_char *buf; uint32_t magic1, magic2; int error; + table = (struct g_part_bsd_table *)basetable; pp = cp->provider; /* Sanity-check the provider. */ - if (pp->sectorsize < sizeof(struct disklabel) || - pp->mediasize < BBSIZE) + if (pp->sectorsize < MIN_SECT_SIZE || pp->mediasize < BBSIZE) return (ENOSPC); if (BBSIZE % pp->sectorsize) return (ENOTBLK); + if (enforce_512bbs) { + table->sectorfact = pp->sectorsize / 512; + table->sectorsize = 512; + } else { + table->sectorfact = 1; + table->sectorsize = pp->sectorsize; + } + /* Check that there's a disklabel. */ - buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error); + buf = g_read_data(cp, table->sectorsize, table->sectorsize, &error); if (buf == NULL) return (error); magic1 = le32dec(buf + 0); @@ -402,9 +431,9 @@ if (table->bbarea == NULL) return (error); - buf = table->bbarea + pp->sectorsize; + buf = table->bbarea + table->sectorsize; - if (le32dec(buf + 40) != pp->sectorsize) + if (le32dec(buf + 40) != table->sectorsize) goto invalid_label; sectors = le32dec(buf + 44); if (sectors < 1 || sectors > 255) @@ -423,8 +452,10 @@ basetable->gpt_heads = heads; chs = le32dec(buf + 60); - if (chs < 1) + if ((chs % table->sectorfact) != 0 || chs < 1) goto invalid_label; + chs /= table->sectorfact; + /* Fix-up a sysinstall bug. */ if (chs > msize) { chs = msize; @@ -449,10 +480,12 @@ part.p_fstype = p[12]; part.p_frag = p[13]; part.p_cpg = le16dec(p + 14); - if (part.p_size == 0) + if (part.p_size == 0 || (part.p_size % table->sectorfact) != 0) continue; - if (part.p_offset < table->offset) + part.p_size /= table->sectorfact; + if (part.p_offset < table->offset || (part.p_offset % table->sectorfact) != 0) continue; + part.p_offset /= table->sectorfact; if (part.p_offset - table->offset > basetable->gpt_last) goto invalid_label; baseentry = g_part_new_entry(basetable, index + 1, @@ -510,14 +543,14 @@ pp = cp->provider; table = (struct g_part_bsd_table *)basetable; baseentry = LIST_FIRST(&basetable->gpt_entry); - label = table->bbarea + pp->sectorsize; + label = table->bbarea + table->sectorsize; for (index = 1; index <= basetable->gpt_entries; index++) { p = label + 148 + (index - 1) * 16; entry = (baseentry != NULL && index == baseentry->gpe_index) ? (struct g_part_bsd_entry *)baseentry : NULL; if (entry != NULL && !baseentry->gpe_deleted) { - le32enc(p + 0, entry->part.p_size); - le32enc(p + 4, entry->part.p_offset); + le32enc(p + 0, entry->part.p_size * table->sectorfact); + le32enc(p + 4, entry->part.p_offset * table->sectorfact); le32enc(p + 8, entry->part.p_fsize); p[12] = entry->part.p_fstype; p[13] = entry->part.p_frag; Index: sys/geom/part/g_part_mbr.c =================================================================== --- sys/geom/part/g_part_mbr.c +++ sys/geom/part/g_part_mbr.c @@ -59,10 +59,15 @@ SYSCTL_UINT(_kern_geom_part_mbr, OID_AUTO, enforce_chs, CTLFLAG_RWTUN, &enforce_chs, 0, "Enforce alignment to CHS addressing"); +static u_int enforce_512bbs = 1; +SYSCTL_UINT(_kern_geom_part_mbr, OID_AUTO, enforce_512bbs, + CTLFLAG_RWTUN, &enforce_512bbs, 0, "Enforce 512 byte block size"); + #define MBRSIZE 512 struct g_part_mbr_table { struct g_part_table base; + off_t sectorfact; u_char mbr[MBRSIZE]; }; @@ -295,6 +300,11 @@ table = (struct g_part_mbr_table *)basetable; le16enc(table->mbr + DOSMAGICOFFSET, DOSMAGIC); + + if (enforce_512bbs) + table->sectorfact = pp->sectorsize / MBRSIZE; + else + table->sectorfact = 1; return (0); } @@ -366,6 +376,7 @@ g_part_mbr_resize(struct g_part_table *basetable, struct g_part_entry *baseentry, struct g_part_parms *gpp) { + struct g_part_mbr_table *table; struct g_part_mbr_entry *entry; struct g_provider *pp; uint32_t size; @@ -384,6 +395,7 @@ if ((g_debugflags & 0x10) == 0 && size < gpp->gpp_size && pp->mediasize / pp->sectorsize > size) return (EBUSY); + table = (struct g_part_mbr_table *)basetable; entry = (struct g_part_mbr_entry *)baseentry; baseentry->gpe_end = baseentry->gpe_start + size - 1; entry->ent.dp_size = size; @@ -402,14 +414,16 @@ } static int -g_part_mbr_probe(struct g_part_table *table, struct g_consumer *cp) +g_part_mbr_probe(struct g_part_table *basetable, struct g_consumer *cp) { + struct g_part_mbr_table *table; char psn[8]; struct g_provider *pp; u_char *buf, *p; int error, index, res, sum; uint16_t magic; + table = (struct g_part_mbr_table *)basetable; pp = cp->provider; /* Sanity-check the provider. */ @@ -418,13 +432,18 @@ if (pp->sectorsize > 4096) return (ENXIO); + if (enforce_512bbs) + table->sectorfact = pp->sectorsize / MBRSIZE; + else + table->sectorfact = 1; + /* We don't nest under an MBR (see EBR instead). */ error = g_getattr("PART::scheme", cp, &psn); if (error == 0 && strcmp(psn, g_part_mbr_scheme.name) == 0) return (ELOOP); /* Check that there's a MBR. */ - buf = g_read_data(cp, 0L, pp->sectorsize, &error); + buf = g_read_data(cp, 0L, MBRSIZE, &error); if (buf == NULL) return (error); @@ -477,7 +496,7 @@ first = basetable->gpt_sectors; msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX); - buf = g_read_data(cp, 0L, pp->sectorsize, &error); + buf = g_read_data(cp, 0L, MBRSIZE, &error); if (buf == NULL) return (error); @@ -494,6 +513,12 @@ ent.dp_ecyl = p[7]; ent.dp_start = le32dec(p + 8); ent.dp_size = le32dec(p + 12); + if (ent.dp_start % table->sectorfact) + continue; + ent.dp_start /= table->sectorfact; + if (ent.dp_size % table->sectorfact) + continue; + ent.dp_size /= table->sectorfact; if (ent.dp_typ == 0 || ent.dp_typ == DOSPTYP_PMBR) continue; if (ent.dp_start == 0 || ent.dp_size == 0) @@ -604,8 +629,8 @@ p[5] = entry->ent.dp_ehd; p[6] = entry->ent.dp_esect; p[7] = entry->ent.dp_ecyl; - le32enc(p + 8, entry->ent.dp_start); - le32enc(p + 12, entry->ent.dp_size); + le32enc(p + 8, entry->ent.dp_start * table->sectorfact); + le32enc(p + 12, entry->ent.dp_size * table->sectorfact); } else bzero(p, DOSPARTSIZE); @@ -613,6 +638,6 @@ baseentry = LIST_NEXT(baseentry, gpe_entry); } - error = g_write_data(cp, 0, table->mbr, cp->provider->sectorsize); + error = g_write_data(cp, 0, table->mbr, MBRSIZE); return (error); }