Date: Thu, 26 Jan 2012 08:47:30 +0000 (UTC) From: "Andrey V. Elsukov" <ae@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org Subject: svn commit: r230567 - stable/8/sys/geom/part Message-ID: <201201260847.q0Q8lUcm072937@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: ae Date: Thu Jan 26 08:47:29 2012 New Revision: 230567 URL: http://svn.freebsd.org/changeset/base/230567 Log: MFC r221788: Add basic metadata integrity check. In case when partition table was probed and read successfull, but it contains invalid values (e.g. overlapped partitions, offset or size is out of bounds), then table will be rejected. MFC r221972: Add a sysctl kern.geom.part.check_integrity for those who has corrupt partition tables and lost an ability to boot after r221788. Also unhide an error message from bootverbose, this would help to easier determine the problem. MFC r221984: Add diagnostic messages for integrity checks. MFC r221992: Make diagnostic messages more specific. With bootverbose print out all inconsistencies of integrity in the partition table, not first found only. MFC r222642: Add diagnostic message about not aligned partitions. Modified: stable/8/sys/geom/part/g_part.c Directory Properties: stable/8/sys/ (props changed) Modified: stable/8/sys/geom/part/g_part.c ============================================================================== --- stable/8/sys/geom/part/g_part.c Thu Jan 26 07:51:51 2012 (r230566) +++ stable/8/sys/geom/part/g_part.c Thu Jan 26 08:47:29 2012 (r230567) @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include <sys/mutex.h> #include <sys/queue.h> #include <sys/sbuf.h> +#include <sys/sysctl.h> #include <sys/systm.h> #include <sys/uuid.h> #include <geom/geom.h> @@ -104,6 +105,13 @@ struct g_part_alias_list { { "netbsd-swap", G_PART_ALIAS_NETBSD_SWAP }, }; +SYSCTL_DECL(_kern_geom); +SYSCTL_NODE(_kern_geom, OID_AUTO, part, CTLFLAG_RW, 0, "GEOM_PART stuff"); +static u_int check_integrity = 1; +TUNABLE_INT("kern.geom.part.check_integrity", &check_integrity); +SYSCTL_UINT(_kern_geom_part, OID_AUTO, check_integrity, CTLFLAG_RW, + &check_integrity, 1, "Enable integrity checking"); + /* * The GEOM partitioning class. */ @@ -231,6 +239,123 @@ g_part_geometry(struct g_part_table *tab } } +#define DPRINTF(...) if (bootverbose) { \ + printf("GEOM_PART: " __VA_ARGS__); \ +} + +static int +g_part_check_integrity(struct g_part_table *table, struct g_consumer *cp) +{ + struct g_part_entry *e1, *e2; + struct g_provider *pp; + off_t offset; + int failed; + + failed = 0; + pp = cp->provider; + if (table->gpt_last < table->gpt_first) { + DPRINTF("last LBA is below first LBA: %jd < %jd\n", + (intmax_t)table->gpt_last, (intmax_t)table->gpt_first); + failed++; + } + if (table->gpt_last > pp->mediasize / pp->sectorsize - 1) { + DPRINTF("last LBA extends beyond mediasize: " + "%jd > %jd\n", (intmax_t)table->gpt_last, + (intmax_t)pp->mediasize / pp->sectorsize - 1); + failed++; + } + LIST_FOREACH(e1, &table->gpt_entry, gpe_entry) { + if (e1->gpe_deleted || e1->gpe_internal) + continue; + if (e1->gpe_start < table->gpt_first) { + DPRINTF("partition %d has start offset below first " + "LBA: %jd < %jd\n", e1->gpe_index, + (intmax_t)e1->gpe_start, + (intmax_t)table->gpt_first); + failed++; + } + if (e1->gpe_start > table->gpt_last) { + DPRINTF("partition %d has start offset beyond last " + "LBA: %jd > %jd\n", e1->gpe_index, + (intmax_t)e1->gpe_start, + (intmax_t)table->gpt_last); + failed++; + } + if (e1->gpe_end < e1->gpe_start) { + DPRINTF("partition %d has end offset below start " + "offset: %jd < %jd\n", e1->gpe_index, + (intmax_t)e1->gpe_end, + (intmax_t)e1->gpe_start); + failed++; + } + if (e1->gpe_end > table->gpt_last) { + DPRINTF("partition %d has end offset beyond last " + "LBA: %jd > %jd\n", e1->gpe_index, + (intmax_t)e1->gpe_end, + (intmax_t)table->gpt_last); + failed++; + } + if (pp->stripesize > 0) { + offset = e1->gpe_start * pp->sectorsize; + if (e1->gpe_offset > offset) + offset = e1->gpe_offset; + if ((offset + pp->stripeoffset) % pp->stripesize) { + DPRINTF("partition %d is not aligned on %u " + "bytes\n", e1->gpe_index, pp->stripesize); + /* Don't treat this as a critical failure */ + } + } + e2 = e1; + while ((e2 = LIST_NEXT(e2, gpe_entry)) != NULL) { + if (e2->gpe_deleted || e2->gpe_internal) + continue; + if (e1->gpe_start >= e2->gpe_start && + e1->gpe_start <= e2->gpe_end) { + DPRINTF("partition %d has start offset inside " + "partition %d: start[%d] %jd >= start[%d] " + "%jd <= end[%d] %jd\n", + e1->gpe_index, e2->gpe_index, + e2->gpe_index, (intmax_t)e2->gpe_start, + e1->gpe_index, (intmax_t)e1->gpe_start, + e2->gpe_index, (intmax_t)e2->gpe_end); + failed++; + } + if (e1->gpe_end >= e2->gpe_start && + e1->gpe_end <= e2->gpe_end) { + DPRINTF("partition %d has end offset inside " + "partition %d: start[%d] %jd >= end[%d] " + "%jd <= end[%d] %jd\n", + e1->gpe_index, e2->gpe_index, + e2->gpe_index, (intmax_t)e2->gpe_start, + e1->gpe_index, (intmax_t)e1->gpe_end, + e2->gpe_index, (intmax_t)e2->gpe_end); + failed++; + } + if (e1->gpe_start < e2->gpe_start && + e1->gpe_end > e2->gpe_end) { + DPRINTF("partition %d contains partition %d: " + "start[%d] %jd > start[%d] %jd, end[%d] " + "%jd < end[%d] %jd\n", + e1->gpe_index, e2->gpe_index, + e1->gpe_index, (intmax_t)e1->gpe_start, + e2->gpe_index, (intmax_t)e2->gpe_start, + e2->gpe_index, (intmax_t)e2->gpe_end, + e1->gpe_index, (intmax_t)e1->gpe_end); + failed++; + } + } + } + if (failed != 0) { + printf("GEOM_PART: integrity check failed (%s, %s)\n", + pp->name, table->gpt_scheme->name); + if (check_integrity != 0) + return (EINVAL); + table->gpt_corrupt = 1; + } + return (0); +} +#undef DPRINTF + struct g_part_entry * g_part_new_entry(struct g_part_table *table, int index, quad_t start, quad_t end) @@ -542,7 +667,11 @@ g_part_ctl_add(struct gctl_req *req, str if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { sb = sbuf_new_auto(); G_PART_FULLNAME(table, entry, sb, gp->name); - sbuf_cat(sb, " added\n"); + if (pp->stripesize > 0 && entry->gpe_pp->stripeoffset != 0) + sbuf_printf(sb, " added, but partition is not " + "aligned on %u bytes\n", pp->stripesize); + else + sbuf_cat(sb, " added\n"); sbuf_finish(sb); gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); sbuf_delete(sb); @@ -1243,9 +1372,11 @@ g_part_ctl_undo(struct gctl_req *req, st error = G_PART_READ(table, cp); if (error) goto fail; + error = g_part_check_integrity(table, cp); + if (error) + goto fail; g_topology_lock(); - LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { if (!entry->gpe_internal) g_part_new_provider(gp, table, entry); @@ -1711,6 +1842,9 @@ g_part_taste(struct g_class *mp, struct error = G_PART_READ(table, cp); if (error) goto fail; + error = g_part_check_integrity(table, cp); + if (error) + goto fail; g_topology_lock(); LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201201260847.q0Q8lUcm072937>