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_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); }