| Summary: | [geom] panic when accessing GPT disk with a large number of entries | ||
|---|---|---|---|
| Product: | Base System | Reporter: | Rebecca Cran <bcran> |
| Component: | kern | Assignee: | Andrey V. Elsukov <ae> |
| Status: | Closed FIXED | ||
| Severity: | Affects Only Me | ||
| Priority: | Normal | ||
| Version: | 9.0-CURRENT | ||
| Hardware: | Any | ||
| OS: | Any | ||
|
Description
Rebecca Cran
2010-03-22 18:50:02 UTC
Responsible Changed From-To: freebsd-bugs->freebsd-geom Over to maintainer(s). tried this too under HEAD (r205390): `gpart create -s gpt -n 1000000 /dev/da0` gave me "gpart: provider: No space left on device" so i did `gpart create -s gpt -n 1000000 /dev/da0` instead which worked. reattaching the device caused no problem. when i tried to create a label with `glabel label usb da0` i got: GEOM: da0: the secondary GPT table is corrupt or invalid. GEOM: da0: using the primary only -- recovery suggested. GEOM: da0: the secondary GPT table is corrupt or invalid. GEOM: da0: using the primary only -- recovery suggested. GEOM: label/usb: the secondary GPT table is corrupt or invalid. GEOM: label/usb: using the primary only -- recovery suggested. seems -n 1000000 is not enough to fill up kernel virtual memory in my case. -- Alexander Best sorry. the command i used was `gpart create -s gpt -n 100000 /dev/da0`. -- Alexander Best I've just recreated the panic - it seems 10,000,000 entries are required to fill virtual memory, not 1,000,000. It takes a very long time for gpart to create them, but on reboot after the disk is detected the system will wait for a couple of minutes before panicing. -- Bruce Cran Responsible Changed From-To: freebsd-geom->ae Take it. Author: ae Date: Tue Jan 18 09:52:53 2011 New Revision: 217531 URL: http://svn.freebsd.org/changeset/base/217531 Log: Limit maximum number of GPT entries to 4k. It is most realistic value and can prevent kernel memory exhausting when big value is specified from command line. Split reading and writing operation to several iteration to do not trigger KASSERT when data length is greater than MAXPHYS. PR: kern/144962, kern/147851 MFC after: 2 weeks Modified: head/sys/geom/part/g_part_gpt.c Modified: head/sys/geom/part/g_part_gpt.c ============================================================================== --- head/sys/geom/part/g_part_gpt.c Tue Jan 18 06:24:52 2011 (r217530) +++ head/sys/geom/part/g_part_gpt.c Tue Jan 18 09:52:53 2011 (r217531) @@ -134,7 +134,7 @@ static struct g_part_scheme g_part_gpt_s sizeof(struct g_part_gpt_table), .gps_entrysz = sizeof(struct g_part_gpt_entry), .gps_minent = 128, - .gps_maxent = INT_MAX, + .gps_maxent = 4096, .gps_bootcodesz = MBRSIZE, }; G_PART_SCHEME_DECLARE(g_part_gpt); @@ -317,7 +317,7 @@ gpt_read_tbl(struct g_part_gpt_table *ta struct g_provider *pp; struct gpt_ent *ent, *tbl; char *buf, *p; - unsigned int idx, sectors, tblsz; + unsigned int idx, sectors, tblsz, size; int error; if (hdr == NULL) @@ -329,11 +329,19 @@ gpt_read_tbl(struct g_part_gpt_table *ta table->state[elt] = GPT_STATE_MISSING; tblsz = hdr->hdr_entries * hdr->hdr_entsz; sectors = (tblsz + pp->sectorsize - 1) / pp->sectorsize; - buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, - sectors * pp->sectorsize, &error); - if (buf == NULL) - return (NULL); - + buf = g_malloc(sectors * pp->sectorsize, M_WAITOK | M_ZERO); + for (idx = 0; idx < sectors; idx += MAXPHYS / pp->sectorsize) { + size = (sectors - idx > MAXPHYS / pp->sectorsize) ? MAXPHYS: + (sectors - idx) * pp->sectorsize; + p = g_read_data(cp, (table->lba[elt] + idx) * pp->sectorsize, + size, &error); + if (p == NULL) { + g_free(buf); + return (NULL); + } + bcopy(p, buf + idx * pp->sectorsize, size); + g_free(p); + } table->state[elt] = GPT_STATE_CORRUPT; if (crc32(buf, tblsz) != hdr->hdr_crc_table) { g_free(buf); @@ -986,10 +994,15 @@ g_part_gpt_write(struct g_part_table *ba crc = crc32(buf, table->hdr->hdr_size); le32enc(buf + 16, crc); - error = g_write_data(cp, table->lba[GPT_ELT_PRITBL] * pp->sectorsize, - buf + pp->sectorsize, tblsz * pp->sectorsize); - if (error) - goto out; + for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) { + error = g_write_data(cp, + (table->lba[GPT_ELT_PRITBL] + index) * pp->sectorsize, + buf + (index + 1) * pp->sectorsize, + (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS: + (tblsz - index) * pp->sectorsize); + if (error) + goto out; + } error = g_write_data(cp, table->lba[GPT_ELT_PRIHDR] * pp->sectorsize, buf, pp->sectorsize); if (error) @@ -1003,10 +1016,15 @@ g_part_gpt_write(struct g_part_table *ba crc = crc32(buf, table->hdr->hdr_size); le32enc(buf + 16, crc); - error = g_write_data(cp, table->lba[GPT_ELT_SECTBL] * pp->sectorsize, - buf + pp->sectorsize, tblsz * pp->sectorsize); - if (error) - goto out; + for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) { + error = g_write_data(cp, + (table->lba[GPT_ELT_SECTBL] + index) * pp->sectorsize, + buf + (index + 1) * pp->sectorsize, + (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS: + (tblsz - index) * pp->sectorsize); + if (error) + goto out; + } error = g_write_data(cp, table->lba[GPT_ELT_SECHDR] * pp->sectorsize, buf, pp->sectorsize); _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" State Changed From-To: open->patched Patched in head/. Author: ae Date: Tue Feb 1 09:27:28 2011 New Revision: 218162 URL: http://svn.freebsd.org/changeset/base/218162 Log: MFC r217531: Limit maximum number of GPT entries to 4k. It is most realistic value and can prevent kernel memory exhausting when big value is specified from command line. Split reading and writing operation to several iterations to do not trigger KASSERT when data length is greater than MAXPHYS. PR: kern/144962, kern/147851 Modified: stable/8/sys/geom/part/g_part_gpt.c Directory Properties: stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/cddl/contrib/opensolaris/ (props changed) stable/8/sys/contrib/dev/acpica/ (props changed) stable/8/sys/contrib/pf/ (props changed) Modified: stable/8/sys/geom/part/g_part_gpt.c ============================================================================== --- stable/8/sys/geom/part/g_part_gpt.c Tue Feb 1 09:27:24 2011 (r218161) +++ stable/8/sys/geom/part/g_part_gpt.c Tue Feb 1 09:27:28 2011 (r218162) @@ -134,7 +134,7 @@ static struct g_part_scheme g_part_gpt_s sizeof(struct g_part_gpt_table), .gps_entrysz = sizeof(struct g_part_gpt_entry), .gps_minent = 128, - .gps_maxent = INT_MAX, + .gps_maxent = 4096, .gps_bootcodesz = MBRSIZE, }; G_PART_SCHEME_DECLARE(g_part_gpt); @@ -317,7 +317,7 @@ gpt_read_tbl(struct g_part_gpt_table *ta struct g_provider *pp; struct gpt_ent *ent, *tbl; char *buf, *p; - unsigned int idx, sectors, tblsz; + unsigned int idx, sectors, tblsz, size; int error; if (hdr == NULL) @@ -329,11 +329,19 @@ gpt_read_tbl(struct g_part_gpt_table *ta table->state[elt] = GPT_STATE_MISSING; tblsz = hdr->hdr_entries * hdr->hdr_entsz; sectors = (tblsz + pp->sectorsize - 1) / pp->sectorsize; - buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, - sectors * pp->sectorsize, &error); - if (buf == NULL) - return (NULL); - + buf = g_malloc(sectors * pp->sectorsize, M_WAITOK | M_ZERO); + for (idx = 0; idx < sectors; idx += MAXPHYS / pp->sectorsize) { + size = (sectors - idx > MAXPHYS / pp->sectorsize) ? MAXPHYS: + (sectors - idx) * pp->sectorsize; + p = g_read_data(cp, (table->lba[elt] + idx) * pp->sectorsize, + size, &error); + if (p == NULL) { + g_free(buf); + return (NULL); + } + bcopy(p, buf + idx * pp->sectorsize, size); + g_free(p); + } table->state[elt] = GPT_STATE_CORRUPT; if (crc32(buf, tblsz) != hdr->hdr_crc_table) { g_free(buf); @@ -986,10 +994,15 @@ g_part_gpt_write(struct g_part_table *ba crc = crc32(buf, table->hdr->hdr_size); le32enc(buf + 16, crc); - error = g_write_data(cp, table->lba[GPT_ELT_PRITBL] * pp->sectorsize, - buf + pp->sectorsize, tblsz * pp->sectorsize); - if (error) - goto out; + for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) { + error = g_write_data(cp, + (table->lba[GPT_ELT_PRITBL] + index) * pp->sectorsize, + buf + (index + 1) * pp->sectorsize, + (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS: + (tblsz - index) * pp->sectorsize); + if (error) + goto out; + } error = g_write_data(cp, table->lba[GPT_ELT_PRIHDR] * pp->sectorsize, buf, pp->sectorsize); if (error) @@ -1003,10 +1016,15 @@ g_part_gpt_write(struct g_part_table *ba crc = crc32(buf, table->hdr->hdr_size); le32enc(buf + 16, crc); - error = g_write_data(cp, table->lba[GPT_ELT_SECTBL] * pp->sectorsize, - buf + pp->sectorsize, tblsz * pp->sectorsize); - if (error) - goto out; + for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) { + error = g_write_data(cp, + (table->lba[GPT_ELT_SECTBL] + index) * pp->sectorsize, + buf + (index + 1) * pp->sectorsize, + (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS: + (tblsz - index) * pp->sectorsize); + if (error) + goto out; + } error = g_write_data(cp, table->lba[GPT_ELT_SECHDR] * pp->sectorsize, buf, pp->sectorsize); _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" State Changed From-To: patched->closed Fixed in head/ and stable/8. |