From owner-svn-src-head@FreeBSD.ORG Mon Feb 16 03:54:29 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 033D7106566B; Mon, 16 Feb 2009 03:54:29 +0000 (UTC) (envelope-from marcel@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id E504D8FC12; Mon, 16 Feb 2009 03:54:28 +0000 (UTC) (envelope-from marcel@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n1G3sSRC043311; Mon, 16 Feb 2009 03:54:28 GMT (envelope-from marcel@svn.freebsd.org) Received: (from marcel@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n1G3sS4J043310; Mon, 16 Feb 2009 03:54:28 GMT (envelope-from marcel@svn.freebsd.org) Message-Id: <200902160354.n1G3sS4J043310@svn.freebsd.org> From: Marcel Moolenaar Date: Mon, 16 Feb 2009 03:54:28 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r188667 - head/sys/geom/part X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 16 Feb 2009 03:54:29 -0000 Author: marcel Date: Mon Feb 16 03:54:28 2009 New Revision: 188667 URL: http://svn.freebsd.org/changeset/base/188667 Log: Add support to add, delete and modify logical partitions, as well as to create and destroy the extended partitioning scheme. In other words: full support. Modified: head/sys/geom/part/g_part_ebr.c Modified: head/sys/geom/part/g_part_ebr.c ============================================================================== --- head/sys/geom/part/g_part_ebr.c Mon Feb 16 02:42:17 2009 (r188666) +++ head/sys/geom/part/g_part_ebr.c Mon Feb 16 03:54:28 2009 (r188667) @@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include @@ -68,6 +67,8 @@ static int g_part_ebr_modify(struct g_pa struct g_part_parms *); static const char *g_part_ebr_name(struct g_part_table *, struct g_part_entry *, char *, size_t); +static int g_part_ebr_precheck(struct g_part_table *, enum g_part_ctl, + struct g_part_parms *); static int g_part_ebr_probe(struct g_part_table *, struct g_consumer *); static int g_part_ebr_read(struct g_part_table *, struct g_consumer *); static int g_part_ebr_setunset(struct g_part_table *, struct g_part_entry *, @@ -84,6 +85,7 @@ static kobj_method_t g_part_ebr_methods[ KOBJMETHOD(g_part_dumpto, g_part_ebr_dumpto), KOBJMETHOD(g_part_modify, g_part_ebr_modify), KOBJMETHOD(g_part_name, g_part_ebr_name), + KOBJMETHOD(g_part_precheck, g_part_ebr_precheck), KOBJMETHOD(g_part_probe, g_part_ebr_probe), KOBJMETHOD(g_part_read, g_part_ebr_read), KOBJMETHOD(g_part_setunset, g_part_ebr_setunset), @@ -102,6 +104,9 @@ static struct g_part_scheme g_part_ebr_s }; G_PART_SCHEME_DECLARE(g_part_ebr); +static void ebr_set_chs(struct g_part_table *, uint32_t, u_char *, u_char *, + u_char *); + static void ebr_entry_decode(const char *p, struct dos_partition *ent) { @@ -117,19 +122,140 @@ ebr_entry_decode(const char *p, struct d ent->dp_size = le32dec(p + 12); } +static void +ebr_entry_link(struct g_part_table *table, uint32_t start, uint32_t end, + u_char *buf) +{ + + buf[0] = 0 /* dp_flag */; + ebr_set_chs(table, start, &buf[3] /* dp_scyl */, &buf[1] /* dp_shd */, + &buf[2] /* dp_ssect */); + buf[4] = 5 /* dp_typ */; + ebr_set_chs(table, end, &buf[7] /* dp_ecyl */, &buf[5] /* dp_ehd */, + &buf[6] /* dp_esect */); + le32enc(buf + 8, start); + le32enc(buf + 12, end - start + 1); +} + +static int +ebr_parse_type(const char *type, u_char *dp_typ) +{ + const char *alias; + char *endp; + long lt; + + if (type[0] == '!') { + lt = strtol(type + 1, &endp, 0); + if (type[1] == '\0' || *endp != '\0' || lt <= 0 || lt >= 256) + return (EINVAL); + *dp_typ = (u_char)lt; + return (0); + } + alias = g_part_alias_name(G_PART_ALIAS_FREEBSD); + if (!strcasecmp(type, alias)) { + *dp_typ = DOSPTYP_386BSD; + return (0); + } + return (EINVAL); +} + +static void +ebr_set_chs(struct g_part_table *table, uint32_t lba, u_char *cylp, u_char *hdp, + u_char *secp) +{ + uint32_t cyl, hd, sec; + + sec = lba % table->gpt_sectors + 1; + lba /= table->gpt_sectors; + hd = lba % table->gpt_heads; + lba /= table->gpt_heads; + cyl = lba; + if (cyl > 1023) + sec = hd = cyl = ~0; + + *cylp = cyl & 0xff; + *hdp = hd & 0xff; + *secp = (sec & 0x3f) | ((cyl >> 2) & 0xc0); +} + static int g_part_ebr_add(struct g_part_table *basetable, struct g_part_entry *baseentry, struct g_part_parms *gpp) { + struct g_geom *gp; + struct g_provider *pp; + struct g_part_ebr_entry *entry; + uint32_t start, size, sectors; + + if (gpp->gpp_parms & G_PART_PARM_LABEL) + return (EINVAL); - return (ENOSYS); + gp = basetable->gpt_gp; + pp = LIST_FIRST(&gp->consumer)->provider; + sectors = basetable->gpt_sectors; + + entry = (struct g_part_ebr_entry *)baseentry; + + start = gpp->gpp_start; + size = gpp->gpp_size; + if (size < 2 * sectors) + return (EINVAL); + if (start % sectors) { + size = size - sectors + (start % sectors); + start = start - (start % sectors) + sectors; + } + if (size % sectors) + size = size - (size % sectors); + if (size < 2 * sectors) + return (EINVAL); + + if (baseentry->gpe_deleted) + bzero(&entry->ent, sizeof(entry->ent)); + + KASSERT(baseentry->gpe_start <= start, (__func__)); + KASSERT(baseentry->gpe_end >= start + size - 1, (__func__)); + baseentry->gpe_offset = (off_t)(start + sectors) * pp->sectorsize; + baseentry->gpe_start = start; + baseentry->gpe_end = start + size - 1; + entry->ent.dp_start = sectors; + entry->ent.dp_size = size - sectors; + ebr_set_chs(basetable, entry->ent.dp_start, &entry->ent.dp_scyl, + &entry->ent.dp_shd, &entry->ent.dp_ssect); + ebr_set_chs(basetable, baseentry->gpe_end, &entry->ent.dp_ecyl, + &entry->ent.dp_ehd, &entry->ent.dp_esect); + return (ebr_parse_type(gpp->gpp_type, &entry->ent.dp_typ)); } static int g_part_ebr_create(struct g_part_table *basetable, struct g_part_parms *gpp) { + char psn[8]; + struct g_consumer *cp; + struct g_provider *pp; + uint64_t msize; + int error; + + pp = gpp->gpp_provider; + + if (pp->sectorsize < EBRSIZE) + return (ENOSPC); + if (pp->sectorsize > 4096) + return (ENXIO); + + /* Check that we have a parent and that it's a MBR. */ + if (basetable->gpt_depth == 0) + return (ENXIO); + cp = LIST_FIRST(&pp->consumers); + error = g_getattr("PART::scheme", cp, &psn); + if (error) + return (error); + if (strcmp(psn, "MBR")) + return (ENXIO); - return (ENOSYS); + msize = pp->mediasize / pp->sectorsize; + basetable->gpt_first = 0; + basetable->gpt_last = msize - (msize % basetable->gpt_sectors) - 1; + return (0); } static int @@ -176,8 +302,15 @@ static int g_part_ebr_modify(struct g_part_table *basetable, struct g_part_entry *baseentry, struct g_part_parms *gpp) { + struct g_part_ebr_entry *entry; + + if (gpp->gpp_parms & G_PART_PARM_LABEL) + return (EINVAL); - return (ENOSYS); + entry = (struct g_part_ebr_entry *)baseentry; + if (gpp->gpp_parms & G_PART_PARM_TYPE) + return (ebr_parse_type(gpp->gpp_type, &entry->ent.dp_typ)); + return (0); } static const char * @@ -190,6 +323,23 @@ g_part_ebr_name(struct g_part_table *tab } static int +g_part_ebr_precheck(struct g_part_table *table, enum g_part_ctl req, + struct g_part_parms *gpp) +{ + + /* + * The index is a function of the start of the partition. + * This is not something the user can override, nor is it + * something the common code will do right. We can set the + * index now so that we get what we need. + */ + if (req == G_PART_CTL_ADD) + gpp->gpp_index = (gpp->gpp_start / table->gpt_sectors) + 1; + + return (0); +} + +static int g_part_ebr_probe(struct g_part_table *table, struct g_consumer *cp) { char psn[8]; @@ -312,8 +462,37 @@ static int g_part_ebr_setunset(struct g_part_table *table, struct g_part_entry *baseentry, const char *attrib, unsigned int set) { + struct g_part_entry *iter; + struct g_part_ebr_entry *entry; + int changed; + + if (strcasecmp(attrib, "active") != 0) + return (EINVAL); - return (ENOSYS); + /* Only one entry can have the active attribute. */ + LIST_FOREACH(iter, &table->gpt_entry, gpe_entry) { + if (iter->gpe_deleted) + continue; + changed = 0; + entry = (struct g_part_ebr_entry *)iter; + if (iter == baseentry) { + if (set && (entry->ent.dp_flag & 0x80) == 0) { + entry->ent.dp_flag |= 0x80; + changed = 1; + } else if (!set && (entry->ent.dp_flag & 0x80)) { + entry->ent.dp_flag &= ~0x80; + changed = 1; + } + } else { + if (set && (entry->ent.dp_flag & 0x80)) { + entry->ent.dp_flag &= ~0x80; + changed = 1; + } + } + if (changed && !iter->gpe_created) + iter->gpe_modified = 1; + } + return (0); } static const char * @@ -334,6 +513,72 @@ g_part_ebr_type(struct g_part_table *bas static int g_part_ebr_write(struct g_part_table *basetable, struct g_consumer *cp) { + struct g_provider *pp; + struct g_part_entry *baseentry, *next; + struct g_part_ebr_entry *entry; + u_char *buf; + u_char *p; + int error; + + pp = cp->provider; + buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); + le16enc(buf + DOSMAGICOFFSET, DOSMAGIC); + + baseentry = LIST_FIRST(&basetable->gpt_entry); + while (baseentry != NULL && baseentry->gpe_deleted) + baseentry = LIST_NEXT(baseentry, gpe_entry); + + /* Wipe-out the the first EBR when there are no slices. */ + if (baseentry == NULL) { + error = g_write_data(cp, 0, buf, pp->sectorsize); + goto out; + } + + /* + * If the first partition is not in LBA 0, we need to + * put a "link" EBR in LBA 0. + */ + if (baseentry->gpe_start != 0) { + ebr_entry_link(basetable, (uint32_t)baseentry->gpe_start, + (uint32_t)baseentry->gpe_end, buf + DOSPARTOFF); + error = g_write_data(cp, 0, buf, pp->sectorsize); + if (error) + goto out; + } + + do { + entry = (struct g_part_ebr_entry *)baseentry; + + p = buf + DOSPARTOFF; + p[0] = entry->ent.dp_flag; + p[1] = entry->ent.dp_shd; + p[2] = entry->ent.dp_ssect; + p[3] = entry->ent.dp_scyl; + p[4] = entry->ent.dp_typ; + 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); + + do { + next = LIST_NEXT(baseentry, gpe_entry); + } while (next != NULL && next->gpe_deleted); + + p += DOSPARTSIZE; + if (next != NULL) + ebr_entry_link(basetable, (uint32_t)next->gpe_start, + (uint32_t)next->gpe_end, p); + else + bzero(p, DOSPARTSIZE); + + error = g_write_data(cp, baseentry->gpe_start * pp->sectorsize, + buf, pp->sectorsize); + + baseentry = next; + } while (!error && baseentry != NULL); - return (ENOSYS); + out: + g_free(buf); + return (error); }