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 <sys/mutex.h>
 #include <sys/queue.h>
 #include <sys/sbuf.h>
-#include <sys/syscallsubr.h>
 #include <sys/systm.h>
 #include <geom/geom.h>
 #include <geom/part/g_part.h>
@@ -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);
 }
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to