The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/geom/part/g_part_apm.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2006-2008 Marcel Moolenaar
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  *
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/apm.h>
   34 #include <sys/bio.h>
   35 #include <sys/endian.h>
   36 #include <sys/kernel.h>
   37 #include <sys/kobj.h>
   38 #include <sys/limits.h>
   39 #include <sys/lock.h>
   40 #include <sys/malloc.h>
   41 #include <sys/mutex.h>
   42 #include <sys/queue.h>
   43 #include <sys/sbuf.h>
   44 #include <sys/systm.h>
   45 #include <sys/sysctl.h>
   46 #include <geom/geom.h>
   47 #include <geom/geom_int.h>
   48 #include <geom/part/g_part.h>
   49 
   50 #include "g_part_if.h"
   51 
   52 FEATURE(geom_part_apm, "GEOM partitioning class for Apple-style partitions");
   53 
   54 struct g_part_apm_table {
   55         struct g_part_table     base;
   56         struct apm_ddr          ddr;
   57         struct apm_ent          self;
   58         int                     tivo_series1;
   59 };
   60 
   61 struct g_part_apm_entry {
   62         struct g_part_entry     base;
   63         struct apm_ent          ent;
   64 };
   65 
   66 static int g_part_apm_add(struct g_part_table *, struct g_part_entry *,
   67     struct g_part_parms *);
   68 static int g_part_apm_create(struct g_part_table *, struct g_part_parms *);
   69 static int g_part_apm_destroy(struct g_part_table *, struct g_part_parms *);
   70 static void g_part_apm_dumpconf(struct g_part_table *, struct g_part_entry *,
   71     struct sbuf *, const char *);
   72 static int g_part_apm_dumpto(struct g_part_table *, struct g_part_entry *);
   73 static int g_part_apm_modify(struct g_part_table *, struct g_part_entry *,
   74     struct g_part_parms *);
   75 static const char *g_part_apm_name(struct g_part_table *, struct g_part_entry *,
   76     char *, size_t);
   77 static int g_part_apm_probe(struct g_part_table *, struct g_consumer *);
   78 static int g_part_apm_read(struct g_part_table *, struct g_consumer *);
   79 static const char *g_part_apm_type(struct g_part_table *, struct g_part_entry *,
   80     char *, size_t);
   81 static int g_part_apm_write(struct g_part_table *, struct g_consumer *);
   82 static int g_part_apm_resize(struct g_part_table *, struct g_part_entry *,
   83     struct g_part_parms *);
   84 
   85 static kobj_method_t g_part_apm_methods[] = {
   86         KOBJMETHOD(g_part_add,          g_part_apm_add),
   87         KOBJMETHOD(g_part_create,       g_part_apm_create),
   88         KOBJMETHOD(g_part_destroy,      g_part_apm_destroy),
   89         KOBJMETHOD(g_part_dumpconf,     g_part_apm_dumpconf),
   90         KOBJMETHOD(g_part_dumpto,       g_part_apm_dumpto),
   91         KOBJMETHOD(g_part_modify,       g_part_apm_modify),
   92         KOBJMETHOD(g_part_resize,       g_part_apm_resize),
   93         KOBJMETHOD(g_part_name,         g_part_apm_name),
   94         KOBJMETHOD(g_part_probe,        g_part_apm_probe),
   95         KOBJMETHOD(g_part_read,         g_part_apm_read),
   96         KOBJMETHOD(g_part_type,         g_part_apm_type),
   97         KOBJMETHOD(g_part_write,        g_part_apm_write),
   98         { 0, 0 }
   99 };
  100 
  101 static struct g_part_scheme g_part_apm_scheme = {
  102         "APM",
  103         g_part_apm_methods,
  104         sizeof(struct g_part_apm_table),
  105         .gps_entrysz = sizeof(struct g_part_apm_entry),
  106         .gps_minent = 16,
  107         .gps_maxent = 4096,
  108 };
  109 G_PART_SCHEME_DECLARE(g_part_apm);
  110 MODULE_VERSION(geom_part_apm, 0);
  111 
  112 static void
  113 swab(char *buf, size_t bufsz)
  114 {
  115         int i;
  116         char ch;
  117 
  118         for (i = 0; i < bufsz; i += 2) {
  119                 ch = buf[i];
  120                 buf[i] = buf[i + 1];
  121                 buf[i + 1] = ch;
  122         }
  123 }
  124 
  125 static int
  126 apm_parse_type(const char *type, char *buf, size_t bufsz)
  127 {
  128         const char *alias;
  129 
  130         if (type[0] == '!') {
  131                 type++;
  132                 if (strlen(type) > bufsz)
  133                         return (EINVAL);
  134                 if (!strcmp(type, APM_ENT_TYPE_SELF) ||
  135                     !strcmp(type, APM_ENT_TYPE_UNUSED))
  136                         return (EINVAL);
  137                 strncpy(buf, type, bufsz);
  138                 return (0);
  139         }
  140         alias = g_part_alias_name(G_PART_ALIAS_APPLE_BOOT);
  141         if (!strcasecmp(type, alias)) {
  142                 strcpy(buf, APM_ENT_TYPE_APPLE_BOOT);
  143                 return (0);
  144         }
  145         alias = g_part_alias_name(G_PART_ALIAS_APPLE_HFS);
  146         if (!strcasecmp(type, alias)) {
  147                 strcpy(buf, APM_ENT_TYPE_APPLE_HFS);
  148                 return (0);
  149         }
  150         alias = g_part_alias_name(G_PART_ALIAS_APPLE_UFS);
  151         if (!strcasecmp(type, alias)) {
  152                 strcpy(buf, APM_ENT_TYPE_APPLE_UFS);
  153                 return (0);
  154         }
  155         alias = g_part_alias_name(G_PART_ALIAS_FREEBSD);
  156         if (!strcasecmp(type, alias)) {
  157                 strcpy(buf, APM_ENT_TYPE_FREEBSD);
  158                 return (0);
  159         }
  160         alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_NANDFS);
  161         if (!strcasecmp(type, alias)) {
  162                 strcpy(buf, APM_ENT_TYPE_FREEBSD_NANDFS);
  163                 return (0);
  164         }
  165         alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP);
  166         if (!strcasecmp(type, alias)) {
  167                 strcpy(buf, APM_ENT_TYPE_FREEBSD_SWAP);
  168                 return (0);
  169         }
  170         alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS);
  171         if (!strcasecmp(type, alias)) {
  172                 strcpy(buf, APM_ENT_TYPE_FREEBSD_UFS);
  173                 return (0);
  174         }
  175         alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM);
  176         if (!strcasecmp(type, alias)) {
  177                 strcpy(buf, APM_ENT_TYPE_FREEBSD_VINUM);
  178                 return (0);
  179         }
  180         alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS);
  181         if (!strcasecmp(type, alias)) {
  182                 strcpy(buf, APM_ENT_TYPE_FREEBSD_ZFS);
  183                 return (0);
  184         }
  185         return (EINVAL);
  186 }
  187 
  188 static int
  189 apm_read_ent(struct g_consumer *cp, uint32_t blk, struct apm_ent *ent,
  190     int tivo_series1)
  191 {
  192         struct g_provider *pp;
  193         char *buf;
  194         int error;
  195 
  196         pp = cp->provider;
  197         buf = g_read_data(cp, pp->sectorsize * blk, pp->sectorsize, &error);
  198         if (buf == NULL)
  199                 return (error);
  200         if (tivo_series1)
  201                 swab(buf, pp->sectorsize);
  202         ent->ent_sig = be16dec(buf);
  203         ent->ent_pmblkcnt = be32dec(buf + 4);
  204         ent->ent_start = be32dec(buf + 8);
  205         ent->ent_size = be32dec(buf + 12);
  206         bcopy(buf + 16, ent->ent_name, sizeof(ent->ent_name));
  207         bcopy(buf + 48, ent->ent_type, sizeof(ent->ent_type));
  208         g_free(buf);
  209         return (0);
  210 }
  211 
  212 static int
  213 g_part_apm_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
  214     struct g_part_parms *gpp)
  215 {
  216         struct g_part_apm_entry *entry;
  217         struct g_part_apm_table *table;
  218         int error;
  219 
  220         entry = (struct g_part_apm_entry *)baseentry;
  221         table = (struct g_part_apm_table *)basetable;
  222         entry->ent.ent_sig = APM_ENT_SIG;
  223         entry->ent.ent_pmblkcnt = table->self.ent_pmblkcnt;
  224         entry->ent.ent_start = gpp->gpp_start;
  225         entry->ent.ent_size = gpp->gpp_size;
  226         if (baseentry->gpe_deleted) {
  227                 bzero(entry->ent.ent_type, sizeof(entry->ent.ent_type));
  228                 bzero(entry->ent.ent_name, sizeof(entry->ent.ent_name));
  229         }
  230         error = apm_parse_type(gpp->gpp_type, entry->ent.ent_type,
  231             sizeof(entry->ent.ent_type));
  232         if (error)
  233                 return (error);
  234         if (gpp->gpp_parms & G_PART_PARM_LABEL) {
  235                 if (strlen(gpp->gpp_label) > sizeof(entry->ent.ent_name))
  236                         return (EINVAL);
  237                 strncpy(entry->ent.ent_name, gpp->gpp_label,
  238                     sizeof(entry->ent.ent_name));
  239         }
  240         if (baseentry->gpe_index >= table->self.ent_pmblkcnt)
  241                 table->self.ent_pmblkcnt = baseentry->gpe_index + 1;
  242         KASSERT(table->self.ent_size >= table->self.ent_pmblkcnt,
  243             ("%s", __func__));
  244         KASSERT(table->self.ent_size > baseentry->gpe_index,
  245             ("%s", __func__));
  246         return (0);
  247 }
  248 
  249 static int
  250 g_part_apm_create(struct g_part_table *basetable, struct g_part_parms *gpp)
  251 {
  252         struct g_provider *pp;
  253         struct g_part_apm_table *table;
  254         uint32_t last;
  255 
  256         /* We don't nest, which means that our depth should be 0. */
  257         if (basetable->gpt_depth != 0)
  258                 return (ENXIO);
  259 
  260         table = (struct g_part_apm_table *)basetable;
  261         pp = gpp->gpp_provider;
  262         if (pp->sectorsize != 512 ||
  263             pp->mediasize < (2 + 2 * basetable->gpt_entries) * pp->sectorsize)
  264                 return (ENOSPC);
  265 
  266         /* APM uses 32-bit LBAs. */
  267         last = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX) - 1;
  268 
  269         basetable->gpt_first = 2 + basetable->gpt_entries;
  270         basetable->gpt_last = last;
  271 
  272         table->ddr.ddr_sig = APM_DDR_SIG;
  273         table->ddr.ddr_blksize = pp->sectorsize;
  274         table->ddr.ddr_blkcount = last + 1;
  275 
  276         table->self.ent_sig = APM_ENT_SIG;
  277         table->self.ent_pmblkcnt = basetable->gpt_entries + 1;
  278         table->self.ent_start = 1;
  279         table->self.ent_size = table->self.ent_pmblkcnt;
  280         strcpy(table->self.ent_name, "Apple");
  281         strcpy(table->self.ent_type, APM_ENT_TYPE_SELF);
  282         return (0);
  283 }
  284 
  285 static int
  286 g_part_apm_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
  287 {
  288 
  289         /* Wipe the first 2 sectors to clear the partitioning. */
  290         basetable->gpt_smhead |= 3;
  291         return (0);
  292 }
  293 
  294 static void
  295 g_part_apm_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry,
  296     struct sbuf *sb, const char *indent)
  297 {
  298         union {
  299                 char name[APM_ENT_NAMELEN + 1];
  300                 char type[APM_ENT_TYPELEN + 1];
  301         } u;
  302         struct g_part_apm_entry *entry;
  303 
  304         entry = (struct g_part_apm_entry *)baseentry;
  305         if (indent == NULL) {
  306                 /* conftxt: libdisk compatibility */
  307                 sbuf_printf(sb, " xs APPLE xt %s", entry->ent.ent_type);
  308         } else if (entry != NULL) {
  309                 /* confxml: partition entry information */
  310                 strncpy(u.name, entry->ent.ent_name, APM_ENT_NAMELEN);
  311                 u.name[APM_ENT_NAMELEN] = '\0';
  312                 sbuf_printf(sb, "%s<label>", indent);
  313                 g_conf_cat_escaped(sb, u.name);
  314                 sbuf_cat(sb, "</label>\n");
  315                 strncpy(u.type, entry->ent.ent_type, APM_ENT_TYPELEN);
  316                 u.type[APM_ENT_TYPELEN] = '\0';
  317                 sbuf_printf(sb, "%s<rawtype>", indent);
  318                 g_conf_cat_escaped(sb, u.type);
  319                 sbuf_cat(sb, "</rawtype>\n");
  320         } else {
  321                 /* confxml: scheme information */
  322         }
  323 }
  324 
  325 static int
  326 g_part_apm_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)
  327 {
  328         struct g_part_apm_entry *entry;
  329 
  330         entry = (struct g_part_apm_entry *)baseentry;
  331         return ((!strcmp(entry->ent.ent_type, APM_ENT_TYPE_FREEBSD_SWAP))
  332             ? 1 : 0);
  333 }
  334 
  335 static int
  336 g_part_apm_modify(struct g_part_table *basetable,
  337     struct g_part_entry *baseentry, struct g_part_parms *gpp)
  338 {
  339         struct g_part_apm_entry *entry;
  340         int error;
  341 
  342         entry = (struct g_part_apm_entry *)baseentry;
  343         if (gpp->gpp_parms & G_PART_PARM_LABEL) {
  344                 if (strlen(gpp->gpp_label) > sizeof(entry->ent.ent_name))
  345                         return (EINVAL);
  346         }
  347         if (gpp->gpp_parms & G_PART_PARM_TYPE) {
  348                 error = apm_parse_type(gpp->gpp_type, entry->ent.ent_type,
  349                     sizeof(entry->ent.ent_type));
  350                 if (error)
  351                         return (error);
  352         }
  353         if (gpp->gpp_parms & G_PART_PARM_LABEL) {
  354                 strncpy(entry->ent.ent_name, gpp->gpp_label,
  355                     sizeof(entry->ent.ent_name));
  356         }
  357         return (0);
  358 }
  359 
  360 static int
  361 g_part_apm_resize(struct g_part_table *basetable,
  362     struct g_part_entry *baseentry, struct g_part_parms *gpp)
  363 {
  364         struct g_part_apm_entry *entry;
  365         struct g_provider *pp;
  366 
  367         if (baseentry == NULL) {
  368                 pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
  369                 basetable->gpt_last = MIN(pp->mediasize / pp->sectorsize,
  370                     UINT32_MAX) - 1;
  371                 return (0);
  372         }
  373 
  374         entry = (struct g_part_apm_entry *)baseentry;
  375         baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1;
  376         entry->ent.ent_size = gpp->gpp_size;
  377 
  378         return (0);
  379 }
  380 
  381 static const char *
  382 g_part_apm_name(struct g_part_table *table, struct g_part_entry *baseentry,
  383     char *buf, size_t bufsz)
  384 {
  385 
  386         snprintf(buf, bufsz, "s%d", baseentry->gpe_index + 1);
  387         return (buf);
  388 }
  389 
  390 static int
  391 g_part_apm_probe(struct g_part_table *basetable, struct g_consumer *cp)
  392 {
  393         struct g_provider *pp;
  394         struct g_part_apm_table *table;
  395         char *buf;
  396         int error;
  397 
  398         /* We don't nest, which means that our depth should be 0. */
  399         if (basetable->gpt_depth != 0)
  400                 return (ENXIO);
  401 
  402         table = (struct g_part_apm_table *)basetable;
  403         table->tivo_series1 = 0;
  404         pp = cp->provider;
  405 
  406         /* Sanity-check the provider. */
  407         if (pp->mediasize < 4 * pp->sectorsize)
  408                 return (ENOSPC);
  409 
  410         /* Check that there's a Driver Descriptor Record (DDR). */
  411         buf = g_read_data(cp, 0L, pp->sectorsize, &error);
  412         if (buf == NULL)
  413                 return (error);
  414         if (be16dec(buf) == APM_DDR_SIG) {
  415                 /* Normal Apple DDR */
  416                 table->ddr.ddr_sig = be16dec(buf);
  417                 table->ddr.ddr_blksize = be16dec(buf + 2);
  418                 table->ddr.ddr_blkcount = be32dec(buf + 4);
  419                 g_free(buf);
  420                 if (table->ddr.ddr_blksize != pp->sectorsize)
  421                         return (ENXIO);
  422                 if (table->ddr.ddr_blkcount > pp->mediasize / pp->sectorsize)
  423                         return (ENXIO);
  424         } else {
  425                 /*
  426                  * Check for Tivo drives, which have no DDR and a different
  427                  * signature.  Those whose first two bytes are 14 92 are
  428                  * Series 2 drives, and aren't supported.  Those that start
  429                  * with 92 14 are series 1 drives and are supported.
  430                  */
  431                 if (be16dec(buf) != 0x9214) {
  432                         /* If this is 0x1492 it could be a series 2 drive */
  433                         g_free(buf);
  434                         return (ENXIO);
  435                 }
  436                 table->ddr.ddr_sig = APM_DDR_SIG;               /* XXX */
  437                 table->ddr.ddr_blksize = pp->sectorsize;        /* XXX */
  438                 table->ddr.ddr_blkcount =
  439                     MIN(pp->mediasize / pp->sectorsize, UINT32_MAX);
  440                 table->tivo_series1 = 1;
  441                 g_free(buf);
  442         }
  443 
  444         /* Check that there's a Partition Map. */
  445         error = apm_read_ent(cp, 1, &table->self, table->tivo_series1);
  446         if (error)
  447                 return (error);
  448         if (table->self.ent_sig != APM_ENT_SIG)
  449                 return (ENXIO);
  450         if (strcmp(table->self.ent_type, APM_ENT_TYPE_SELF))
  451                 return (ENXIO);
  452         if (table->self.ent_pmblkcnt >= table->ddr.ddr_blkcount)
  453                 return (ENXIO);
  454         return (G_PART_PROBE_PRI_NORM);
  455 }
  456 
  457 static int
  458 g_part_apm_read(struct g_part_table *basetable, struct g_consumer *cp)
  459 {
  460         struct apm_ent ent;
  461         struct g_part_apm_entry *entry;
  462         struct g_part_apm_table *table;
  463         int error, index;
  464 
  465         table = (struct g_part_apm_table *)basetable;
  466 
  467         basetable->gpt_first = table->self.ent_size + 1;
  468         basetable->gpt_last = table->ddr.ddr_blkcount - 1;
  469         basetable->gpt_entries = table->self.ent_size - 1;
  470 
  471         for (index = table->self.ent_pmblkcnt - 1; index > 0; index--) {
  472                 error = apm_read_ent(cp, index + 1, &ent, table->tivo_series1);
  473                 if (error)
  474                         continue;
  475                 if (!strcmp(ent.ent_type, APM_ENT_TYPE_UNUSED))
  476                         continue;
  477                 entry = (struct g_part_apm_entry *)g_part_new_entry(basetable,
  478                     index, ent.ent_start, ent.ent_start + ent.ent_size - 1);
  479                 entry->ent = ent;
  480         }
  481 
  482         return (0);
  483 }
  484 
  485 static const char *
  486 g_part_apm_type(struct g_part_table *basetable, struct g_part_entry *baseentry,
  487     char *buf, size_t bufsz)
  488 {
  489         struct g_part_apm_entry *entry;
  490         const char *type;
  491         size_t len;
  492 
  493         entry = (struct g_part_apm_entry *)baseentry;
  494         type = entry->ent.ent_type;
  495         if (!strcmp(type, APM_ENT_TYPE_APPLE_BOOT))
  496                 return (g_part_alias_name(G_PART_ALIAS_APPLE_BOOT));
  497         if (!strcmp(type, APM_ENT_TYPE_APPLE_HFS))
  498                 return (g_part_alias_name(G_PART_ALIAS_APPLE_HFS));
  499         if (!strcmp(type, APM_ENT_TYPE_APPLE_UFS))
  500                 return (g_part_alias_name(G_PART_ALIAS_APPLE_UFS));
  501         if (!strcmp(type, APM_ENT_TYPE_FREEBSD))
  502                 return (g_part_alias_name(G_PART_ALIAS_FREEBSD));
  503         if (!strcmp(type, APM_ENT_TYPE_FREEBSD_NANDFS))
  504                 return (g_part_alias_name(G_PART_ALIAS_FREEBSD_NANDFS));
  505         if (!strcmp(type, APM_ENT_TYPE_FREEBSD_SWAP))
  506                 return (g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP));
  507         if (!strcmp(type, APM_ENT_TYPE_FREEBSD_UFS))
  508                 return (g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS));
  509         if (!strcmp(type, APM_ENT_TYPE_FREEBSD_VINUM))
  510                 return (g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM));
  511         if (!strcmp(type, APM_ENT_TYPE_FREEBSD_ZFS))
  512                 return (g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS));
  513         buf[0] = '!';
  514         len = MIN(sizeof(entry->ent.ent_type), bufsz - 2);
  515         bcopy(type, buf + 1, len);
  516         buf[len + 1] = '\0';
  517         return (buf);
  518 }
  519 
  520 static int
  521 g_part_apm_write(struct g_part_table *basetable, struct g_consumer *cp)
  522 {
  523         struct g_provider *pp;
  524         struct g_part_entry *baseentry;
  525         struct g_part_apm_entry *entry;
  526         struct g_part_apm_table *table;
  527         char *buf, *ptr;
  528         uint32_t index;
  529         int error;
  530         size_t tblsz;
  531 
  532         pp = cp->provider;
  533         table = (struct g_part_apm_table *)basetable;
  534         /*
  535          * Tivo Series 1 disk partitions are currently read-only.
  536          */
  537         if (table->tivo_series1)
  538                 return (EOPNOTSUPP);
  539 
  540         /* Write the DDR only when we're newly created. */
  541         if (basetable->gpt_created) {
  542                 buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
  543                 be16enc(buf, table->ddr.ddr_sig);
  544                 be16enc(buf + 2, table->ddr.ddr_blksize);
  545                 be32enc(buf + 4, table->ddr.ddr_blkcount);
  546                 error = g_write_data(cp, 0, buf, pp->sectorsize);
  547                 g_free(buf);
  548                 if (error)
  549                         return (error);
  550         }
  551 
  552         /* Allocate the buffer for all entries */
  553         tblsz = table->self.ent_pmblkcnt;
  554         buf = g_malloc(tblsz * pp->sectorsize, M_WAITOK | M_ZERO);
  555 
  556         /* Fill the self entry */
  557         be16enc(buf, APM_ENT_SIG);
  558         be32enc(buf + 4, table->self.ent_pmblkcnt);
  559         be32enc(buf + 8, table->self.ent_start);
  560         be32enc(buf + 12, table->self.ent_size);
  561         bcopy(table->self.ent_name, buf + 16, sizeof(table->self.ent_name));
  562         bcopy(table->self.ent_type, buf + 48, sizeof(table->self.ent_type));
  563 
  564         baseentry = LIST_FIRST(&basetable->gpt_entry);
  565         for (index = 1; index < tblsz; index++) {
  566                 entry = (baseentry != NULL && index == baseentry->gpe_index)
  567                     ? (struct g_part_apm_entry *)baseentry : NULL;
  568                 ptr = buf + index * pp->sectorsize;
  569                 be16enc(ptr, APM_ENT_SIG);
  570                 be32enc(ptr + 4, table->self.ent_pmblkcnt);
  571                 if (entry != NULL && !baseentry->gpe_deleted) {
  572                         be32enc(ptr + 8, entry->ent.ent_start);
  573                         be32enc(ptr + 12, entry->ent.ent_size);
  574                         bcopy(entry->ent.ent_name, ptr + 16,
  575                             sizeof(entry->ent.ent_name));
  576                         bcopy(entry->ent.ent_type, ptr + 48,
  577                             sizeof(entry->ent.ent_type));
  578                 } else {
  579                         strcpy(ptr + 48, APM_ENT_TYPE_UNUSED);
  580                 }
  581                 if (entry != NULL)
  582                         baseentry = LIST_NEXT(baseentry, gpe_entry);
  583         }
  584 
  585         for (index = 0; index < tblsz; index += maxphys / pp->sectorsize) {
  586                 error = g_write_data(cp, (1 + index) * pp->sectorsize,
  587                     buf + index * pp->sectorsize,
  588                     (tblsz - index > maxphys / pp->sectorsize) ? maxphys:
  589                     (tblsz - index) * pp->sectorsize);
  590                 if (error) {
  591                         g_free(buf);
  592                         return (error);
  593                 }
  594         }
  595         g_free(buf);
  596         return (0);
  597 }

Cache object: 4df8b0b0149b817a06d443767bc05c02


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.