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/label/g_label.c

Version: -  FREEBSD  -  FREEBSD11  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/kernel.h>
   33 #include <sys/module.h>
   34 #include <sys/lock.h>
   35 #include <sys/mutex.h>
   36 #include <sys/bio.h>
   37 #include <sys/sysctl.h>
   38 #include <sys/malloc.h>
   39 #include <sys/libkern.h>
   40 #include <geom/geom.h>
   41 #include <geom/geom_slice.h>
   42 #include <geom/label/g_label.h>
   43 
   44 
   45 SYSCTL_DECL(_kern_geom);
   46 SYSCTL_NODE(_kern_geom, OID_AUTO, label, CTLFLAG_RW, 0, "GEOM_LABEL stuff");
   47 u_int g_label_debug = 0;
   48 TUNABLE_INT("kern.geom.label.debug", &g_label_debug);
   49 SYSCTL_UINT(_kern_geom_label, OID_AUTO, debug, CTLFLAG_RW, &g_label_debug, 0,
   50     "Debug level");
   51 
   52 static int g_label_destroy_geom(struct gctl_req *req, struct g_class *mp,
   53     struct g_geom *gp);
   54 static int g_label_destroy(struct g_geom *gp, boolean_t force);
   55 static struct g_geom *g_label_taste(struct g_class *mp, struct g_provider *pp,
   56     int flags __unused);
   57 static void g_label_config(struct gctl_req *req, struct g_class *mp,
   58     const char *verb);
   59 
   60 struct g_class g_label_class = {
   61         .name = G_LABEL_CLASS_NAME,
   62         .version = G_VERSION,
   63         .ctlreq = g_label_config,
   64         .taste = g_label_taste,
   65         .destroy_geom = g_label_destroy_geom
   66 };
   67 
   68 /*
   69  * To add a new file system where you want to look for volume labels,
   70  * you have to:
   71  * 1. Add a file g_label_<file system>.c which implements labels recognition.
   72  * 2. Add an 'extern const struct g_label_desc g_label_<file system>;' into
   73  *    g_label.h file.
   74  * 3. Add an element to the table below '&g_label_<file system>,'.
   75  * 4. Add your file to sys/conf/files.
   76  * 5. Add your file to sys/modules/geom/geom_label/Makefile.
   77  * 6. Add your file system to manual page sbin/geom/class/label/glabel.8.
   78  */
   79 const struct g_label_desc *g_labels[] = {
   80         &g_label_ufs,
   81         &g_label_iso9660,
   82         &g_label_msdosfs,
   83         &g_label_ext2fs,
   84         &g_label_reiserfs,
   85         &g_label_ntfs,
   86         NULL
   87 };
   88 
   89 
   90 static int
   91 g_label_destroy_geom(struct gctl_req *req __unused, struct g_class *mp,
   92     struct g_geom *gp __unused)
   93 {
   94 
   95         /*
   96          * XXX: Unloading a class which is using geom_slice:1.56 is currently
   97          * XXX: broken, so we deny unloading when we have geoms.
   98          */
   99         return (EOPNOTSUPP);
  100 }
  101 
  102 static void
  103 g_label_orphan(struct g_consumer *cp)
  104 {
  105 
  106         G_LABEL_DEBUG(0, "Label %s removed.",
  107             LIST_FIRST(&cp->geom->provider)->name);
  108         g_slice_orphan(cp);
  109 }
  110 
  111 static void
  112 g_label_spoiled(struct g_consumer *cp)
  113 {
  114 
  115         G_LABEL_DEBUG(0, "Label %s removed.",
  116             LIST_FIRST(&cp->geom->provider)->name);
  117         g_slice_spoiled(cp);
  118 }
  119 
  120 static int
  121 g_label_is_name_ok(const char *label)
  122 {
  123         const char *s;
  124 
  125         /* Check is the label starts from ../ */
  126         if (strncmp(label, "../", 3) == 0)
  127                 return (0);
  128         /* Check is the label contains /../ */
  129         if (strstr(label, "/../") != NULL)
  130                 return (0);
  131         /* Check is the label ends at ../ */
  132         if ((s = strstr(label, "/..")) != NULL && s[3] == '\0')
  133                 return (0);
  134         return (1);
  135 }
  136 
  137 static struct g_geom *
  138 g_label_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp,
  139     const char *label, const char *dir, off_t mediasize)
  140 {
  141         struct g_geom *gp;
  142         struct g_provider *pp2;
  143         struct g_consumer *cp;
  144         char name[64];
  145 
  146         g_topology_assert();
  147 
  148         if (!g_label_is_name_ok(label)) {
  149                 G_LABEL_DEBUG(0, "%s contains suspicious label, skipping.",
  150                     pp->name);
  151                 G_LABEL_DEBUG(1, "%s suspicious label is: %s", pp->name, label);
  152                 return (NULL);
  153         }
  154         gp = NULL;
  155         cp = NULL;
  156         snprintf(name, sizeof(name), "%s/%s", dir, label);
  157         LIST_FOREACH(gp, &mp->geom, geom) {
  158                 pp2 = LIST_FIRST(&gp->provider);
  159                 if (pp2 == NULL)
  160                         continue;
  161                 if (strcmp(pp2->name, name) == 0) {
  162                         G_LABEL_DEBUG(1, "Label %s(%s) already exists (%s).",
  163                             label, name, pp->name);
  164                         if (req != NULL) {
  165                                 gctl_error(req, "Provider %s already exists.",
  166                                     name);
  167                         }
  168                         return (NULL);
  169                 }
  170         }
  171         gp = g_slice_new(mp, 1, pp, &cp, NULL, 0, NULL);
  172         if (gp == NULL) {
  173                 G_LABEL_DEBUG(0, "Cannot create slice %s.", label);
  174                 if (req != NULL)
  175                         gctl_error(req, "Cannot create slice %s.", label);
  176                 return (NULL);
  177         }
  178         gp->orphan = g_label_orphan;
  179         gp->spoiled = g_label_spoiled;
  180         g_access(cp, -1, 0, 0);
  181         g_slice_config(gp, 0, G_SLICE_CONFIG_SET, (off_t)0, mediasize,
  182             pp->sectorsize, name);
  183         G_LABEL_DEBUG(0, "Label for provider %s is %s.", pp->name, name);
  184         return (gp);
  185 }
  186 
  187 static int
  188 g_label_destroy(struct g_geom *gp, boolean_t force)
  189 {
  190         struct g_provider *pp;
  191 
  192         g_topology_assert();
  193         pp = LIST_FIRST(&gp->provider);
  194         if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
  195                 if (force) {
  196                         G_LABEL_DEBUG(0, "Provider %s is still open, so it "
  197                             "can't be definitely removed.", pp->name);
  198                 } else {
  199                         G_LABEL_DEBUG(1,
  200                             "Provider %s is still open (r%dw%de%d).", pp->name,
  201                             pp->acr, pp->acw, pp->ace);
  202                         return (EBUSY);
  203                 }
  204         } else {
  205                 G_LABEL_DEBUG(0, "Label %s removed.",
  206                     LIST_FIRST(&gp->provider)->name);
  207         }
  208         g_slice_spoiled(LIST_FIRST(&gp->consumer));
  209         return (0);
  210 }
  211 
  212 static int
  213 g_label_read_metadata(struct g_consumer *cp, struct g_label_metadata *md)
  214 {
  215         struct g_provider *pp;
  216         u_char *buf;
  217         int error;
  218 
  219         g_topology_assert();
  220 
  221         pp = cp->provider;
  222         g_topology_unlock();
  223         buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize,
  224             &error);
  225         g_topology_lock();
  226         if (buf == NULL)
  227                 return (error);
  228         /* Decode metadata. */
  229         label_metadata_decode(buf, md);
  230         g_free(buf);
  231 
  232         return (0);
  233 }
  234 
  235 static void
  236 g_label_orphan_taste(struct g_consumer *cp __unused)
  237 {
  238 
  239         KASSERT(1 == 0, ("%s called?", __func__));
  240 }
  241 
  242 static void
  243 g_label_start_taste(struct bio *bp __unused)
  244 {
  245 
  246         KASSERT(1 == 0, ("%s called?", __func__));
  247 }
  248 
  249 static int
  250 g_label_access_taste(struct g_provider *pp __unused, int dr __unused,
  251     int dw __unused, int de __unused)
  252 {
  253 
  254         KASSERT(1 == 0, ("%s called", __func__));
  255         return (EOPNOTSUPP);
  256 }
  257 
  258 static struct g_geom *
  259 g_label_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
  260 {
  261         struct g_label_metadata md;
  262         struct g_consumer *cp;
  263         struct g_geom *gp;
  264         int i;
  265 
  266         g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name);
  267         g_topology_assert();
  268 
  269         G_LABEL_DEBUG(2, "Tasting %s.", pp->name);
  270 
  271         if (strcmp(pp->geom->class->name, mp->name) == 0)
  272                 return (NULL);
  273 
  274         gp = g_new_geomf(mp, "label:taste");
  275         gp->start = g_label_start_taste;
  276         gp->access = g_label_access_taste;
  277         gp->orphan = g_label_orphan_taste;
  278         cp = g_new_consumer(gp);
  279         g_attach(cp, pp);
  280         if (g_access(cp, 1, 0, 0) != 0)
  281                 goto end;
  282         do {
  283                 if (g_label_read_metadata(cp, &md) != 0)
  284                         break;
  285                 if (strcmp(md.md_magic, G_LABEL_MAGIC) != 0)
  286                         break;
  287                 if (md.md_version > G_LABEL_VERSION) {
  288                         printf("geom_label.ko module is too old to handle %s.\n",
  289                             pp->name);
  290                         break;
  291                 }
  292 
  293                 /*
  294                  * Backward compatibility:
  295                  */
  296                 /*
  297                  * There was no md_provsize field in earlier versions of
  298                  * metadata.
  299                  */
  300                 if (md.md_version < 2)
  301                         md.md_provsize = pp->mediasize;
  302 
  303                 if (md.md_provsize != pp->mediasize)
  304                         break;
  305 
  306                 g_label_create(NULL, mp, pp, md.md_label, G_LABEL_DIR,
  307                     pp->mediasize - pp->sectorsize);
  308         } while (0);
  309         for (i = 0; g_labels[i] != NULL; i++) {
  310                 char label[64];
  311 
  312                 g_topology_unlock();
  313                 g_labels[i]->ld_taste(cp, label, sizeof(label));
  314                 g_topology_lock();
  315                 if (label[0] == '\0')
  316                         continue;
  317                 g_label_create(NULL, mp, pp, label, g_labels[i]->ld_dir,
  318                     pp->mediasize);
  319         }
  320         g_access(cp, -1, 0, 0);
  321 end:
  322         g_detach(cp);
  323         g_destroy_consumer(cp);
  324         g_destroy_geom(gp);
  325         return (NULL);
  326 }
  327 
  328 static void
  329 g_label_ctl_create(struct gctl_req *req, struct g_class *mp)
  330 {
  331         struct g_provider *pp;
  332         const char *name;
  333         int *nargs;
  334 
  335         g_topology_assert();
  336 
  337         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
  338         if (nargs == NULL) {
  339                 gctl_error(req, "No '%s' argument", "nargs");
  340                 return;
  341         }
  342         if (*nargs != 2) {
  343                 gctl_error(req, "Invalid number of argument.");
  344                 return;
  345         }
  346         /*
  347          * arg1 is the name of provider.
  348          */
  349         name = gctl_get_asciiparam(req, "arg1");
  350         if (name == NULL) {
  351                 gctl_error(req, "No 'arg%d' argument", 1);
  352                 return;
  353         }
  354         if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
  355                 name += strlen("/dev/");
  356         pp = g_provider_by_name(name);
  357         if (pp == NULL) {
  358                 G_LABEL_DEBUG(1, "Provider %s is invalid.", name);
  359                 gctl_error(req, "Provider %s is invalid.", name);
  360                 return;
  361         }
  362         /*
  363          * arg0 is the label.
  364          */
  365         name = gctl_get_asciiparam(req, "arg0");
  366         if (name == NULL) {
  367                 gctl_error(req, "No 'arg%d' argument", 0);
  368                 return;
  369         }
  370         g_label_create(req, mp, pp, name, G_LABEL_DIR, pp->mediasize);
  371 }
  372 
  373 static const char *
  374 g_label_skip_dir(const char *name)
  375 {
  376         char path[64];
  377         u_int i;
  378 
  379         if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
  380                 name += strlen("/dev/");
  381         if (strncmp(name, G_LABEL_DIR "/", strlen(G_LABEL_DIR "/")) == 0)
  382                 name += strlen(G_LABEL_DIR "/");
  383         for (i = 0; g_labels[i] != NULL; i++) {
  384                 snprintf(path, sizeof(path), "%s/", g_labels[i]->ld_dir);
  385                 if (strncmp(name, path, strlen(path)) == 0) {
  386                         name += strlen(path);
  387                         break;
  388                 }
  389         }
  390         return (name);
  391 }
  392 
  393 static struct g_geom *
  394 g_label_find_geom(struct g_class *mp, const char *name)
  395 {
  396         struct g_geom *gp;
  397         struct g_provider *pp;
  398         const char *pname;
  399 
  400         name = g_label_skip_dir(name);
  401         LIST_FOREACH(gp, &mp->geom, geom) {
  402                 pp = LIST_FIRST(&gp->provider);
  403                 pname = g_label_skip_dir(pp->name);
  404                 if (strcmp(pname, name) == 0)
  405                         return (gp);
  406         }
  407         return (NULL);
  408 }
  409 
  410 static void
  411 g_label_ctl_destroy(struct gctl_req *req, struct g_class *mp)
  412 {
  413         int *nargs, *force, error, i;
  414         struct g_geom *gp;
  415         const char *name;
  416         char param[16];
  417 
  418         g_topology_assert();
  419 
  420         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
  421         if (nargs == NULL) {
  422                 gctl_error(req, "No '%s' argument", "nargs");
  423                 return;
  424         }
  425         if (*nargs <= 0) {
  426                 gctl_error(req, "Missing device(s).");
  427                 return;
  428         }
  429         force = gctl_get_paraml(req, "force", sizeof(*force));
  430         if (force == NULL) {
  431                 gctl_error(req, "No 'force' argument");
  432                 return;
  433         }
  434 
  435         for (i = 0; i < *nargs; i++) {
  436                 snprintf(param, sizeof(param), "arg%d", i);
  437                 name = gctl_get_asciiparam(req, param);
  438                 if (name == NULL) {
  439                         gctl_error(req, "No 'arg%d' argument", i);
  440                         return;
  441                 }
  442                 gp = g_label_find_geom(mp, name);
  443                 if (gp == NULL) {
  444                         G_LABEL_DEBUG(1, "Label %s is invalid.", name);
  445                         gctl_error(req, "Label %s is invalid.", name);
  446                         return;
  447                 }
  448                 error = g_label_destroy(gp, *force);
  449                 if (error != 0) {
  450                         gctl_error(req, "Cannot destroy label %s (error=%d).",
  451                             LIST_FIRST(&gp->provider)->name, error);
  452                         return;
  453                 }
  454         }
  455 }
  456 
  457 static void
  458 g_label_config(struct gctl_req *req, struct g_class *mp, const char *verb)
  459 {
  460         uint32_t *version;
  461 
  462         g_topology_assert();
  463 
  464         version = gctl_get_paraml(req, "version", sizeof(*version));
  465         if (version == NULL) {
  466                 gctl_error(req, "No '%s' argument.", "version");
  467                 return;
  468         }
  469         if (*version != G_LABEL_VERSION) {
  470                 gctl_error(req, "Userland and kernel parts are out of sync.");
  471                 return;
  472         }
  473 
  474         if (strcmp(verb, "create") == 0) {
  475                 g_label_ctl_create(req, mp);
  476                 return;
  477         } else if (strcmp(verb, "destroy") == 0 ||
  478             strcmp(verb, "stop") == 0) {
  479                 g_label_ctl_destroy(req, mp);
  480                 return;
  481         }
  482 
  483         gctl_error(req, "Unknown verb.");
  484 }
  485 
  486 DECLARE_GEOM_CLASS(g_label_class, g_label);

Cache object: 54ec848626da614ffb81a24c50a37cb2


[ 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.