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/raid/tr_raid0.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) 2010 Alexander Motin <mav@FreeBSD.org>
    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  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/bio.h>
   34 #include <sys/endian.h>
   35 #include <sys/kernel.h>
   36 #include <sys/kobj.h>
   37 #include <sys/lock.h>
   38 #include <sys/malloc.h>
   39 #include <sys/mutex.h>
   40 #include <sys/systm.h>
   41 #include <geom/geom.h>
   42 #include <geom/geom_dbg.h>
   43 #include "geom/raid/g_raid.h"
   44 #include "g_raid_tr_if.h"
   45 
   46 static MALLOC_DEFINE(M_TR_RAID0, "tr_raid0_data", "GEOM_RAID RAID0 data");
   47 
   48 struct g_raid_tr_raid0_object {
   49         struct g_raid_tr_object  trso_base;
   50         int                      trso_starting;
   51         int                      trso_stopped;
   52 };
   53 
   54 static g_raid_tr_taste_t g_raid_tr_taste_raid0;
   55 static g_raid_tr_event_t g_raid_tr_event_raid0;
   56 static g_raid_tr_start_t g_raid_tr_start_raid0;
   57 static g_raid_tr_stop_t g_raid_tr_stop_raid0;
   58 static g_raid_tr_iostart_t g_raid_tr_iostart_raid0;
   59 static g_raid_tr_iodone_t g_raid_tr_iodone_raid0;
   60 static g_raid_tr_kerneldump_t g_raid_tr_kerneldump_raid0;
   61 static g_raid_tr_free_t g_raid_tr_free_raid0;
   62 
   63 static kobj_method_t g_raid_tr_raid0_methods[] = {
   64         KOBJMETHOD(g_raid_tr_taste,     g_raid_tr_taste_raid0),
   65         KOBJMETHOD(g_raid_tr_event,     g_raid_tr_event_raid0),
   66         KOBJMETHOD(g_raid_tr_start,     g_raid_tr_start_raid0),
   67         KOBJMETHOD(g_raid_tr_stop,      g_raid_tr_stop_raid0),
   68         KOBJMETHOD(g_raid_tr_iostart,   g_raid_tr_iostart_raid0),
   69         KOBJMETHOD(g_raid_tr_iodone,    g_raid_tr_iodone_raid0),
   70         KOBJMETHOD(g_raid_tr_kerneldump,        g_raid_tr_kerneldump_raid0),
   71         KOBJMETHOD(g_raid_tr_free,      g_raid_tr_free_raid0),
   72         { 0, 0 }
   73 };
   74 
   75 static struct g_raid_tr_class g_raid_tr_raid0_class = {
   76         "RAID0",
   77         g_raid_tr_raid0_methods,
   78         sizeof(struct g_raid_tr_raid0_object),
   79         .trc_enable = 1,
   80         .trc_priority = 100,
   81         .trc_accept_unmapped = 1
   82 };
   83 
   84 static int
   85 g_raid_tr_taste_raid0(struct g_raid_tr_object *tr, struct g_raid_volume *volume)
   86 {
   87         struct g_raid_tr_raid0_object *trs;
   88 
   89         trs = (struct g_raid_tr_raid0_object *)tr;
   90         if (tr->tro_volume->v_raid_level != G_RAID_VOLUME_RL_RAID0 ||
   91             tr->tro_volume->v_raid_level_qualifier != G_RAID_VOLUME_RLQ_NONE)
   92                 return (G_RAID_TR_TASTE_FAIL);
   93         trs->trso_starting = 1;
   94         return (G_RAID_TR_TASTE_SUCCEED);
   95 }
   96 
   97 static int
   98 g_raid_tr_update_state_raid0(struct g_raid_volume *vol)
   99 {
  100         struct g_raid_tr_raid0_object *trs;
  101         struct g_raid_softc *sc;
  102         u_int s;
  103         int n, f;
  104 
  105         sc = vol->v_softc;
  106         trs = (struct g_raid_tr_raid0_object *)vol->v_tr;
  107         if (trs->trso_stopped)
  108                 s = G_RAID_VOLUME_S_STOPPED;
  109         else if (trs->trso_starting)
  110                 s = G_RAID_VOLUME_S_STARTING;
  111         else {
  112                 n = g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_ACTIVE);
  113                 f = g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_FAILED);
  114                 if (n + f == vol->v_disks_count) {
  115                         if (f == 0)
  116                                 s = G_RAID_VOLUME_S_OPTIMAL;
  117                         else
  118                                 s = G_RAID_VOLUME_S_SUBOPTIMAL;
  119                 } else
  120                         s = G_RAID_VOLUME_S_BROKEN;
  121         }
  122         if (s != vol->v_state) {
  123                 g_raid_event_send(vol, G_RAID_VOLUME_S_ALIVE(s) ?
  124                     G_RAID_VOLUME_E_UP : G_RAID_VOLUME_E_DOWN,
  125                     G_RAID_EVENT_VOLUME);
  126                 g_raid_change_volume_state(vol, s);
  127                 if (!trs->trso_starting && !trs->trso_stopped)
  128                         g_raid_write_metadata(sc, vol, NULL, NULL);
  129         }
  130         return (0);
  131 }
  132 
  133 static int
  134 g_raid_tr_event_raid0(struct g_raid_tr_object *tr,
  135     struct g_raid_subdisk *sd, u_int event)
  136 {
  137         struct g_raid_tr_raid0_object *trs;
  138         struct g_raid_softc *sc;
  139         struct g_raid_volume *vol;
  140         int state;
  141 
  142         trs = (struct g_raid_tr_raid0_object *)tr;
  143         vol = tr->tro_volume;
  144         sc = vol->v_softc;
  145 
  146         state = sd->sd_state;
  147         if (state != G_RAID_SUBDISK_S_NONE &&
  148             state != G_RAID_SUBDISK_S_FAILED &&
  149             state != G_RAID_SUBDISK_S_ACTIVE) {
  150                 G_RAID_DEBUG1(1, sc,
  151                     "Promote subdisk %s:%d from %s to ACTIVE.",
  152                     vol->v_name, sd->sd_pos,
  153                     g_raid_subdisk_state2str(sd->sd_state));
  154                 g_raid_change_subdisk_state(sd, G_RAID_SUBDISK_S_ACTIVE);
  155         }
  156         if (state != sd->sd_state &&
  157             !trs->trso_starting && !trs->trso_stopped)
  158                 g_raid_write_metadata(sc, vol, sd, NULL);
  159         g_raid_tr_update_state_raid0(vol);
  160         return (0);
  161 }
  162 
  163 static int
  164 g_raid_tr_start_raid0(struct g_raid_tr_object *tr)
  165 {
  166         struct g_raid_tr_raid0_object *trs;
  167         struct g_raid_volume *vol;
  168 
  169         trs = (struct g_raid_tr_raid0_object *)tr;
  170         vol = tr->tro_volume;
  171         trs->trso_starting = 0;
  172         g_raid_tr_update_state_raid0(vol);
  173         return (0);
  174 }
  175 
  176 static int
  177 g_raid_tr_stop_raid0(struct g_raid_tr_object *tr)
  178 {
  179         struct g_raid_tr_raid0_object *trs;
  180         struct g_raid_volume *vol;
  181 
  182         trs = (struct g_raid_tr_raid0_object *)tr;
  183         vol = tr->tro_volume;
  184         trs->trso_starting = 0;
  185         trs->trso_stopped = 1;
  186         g_raid_tr_update_state_raid0(vol);
  187         return (0);
  188 }
  189 
  190 static void
  191 g_raid_tr_iostart_raid0(struct g_raid_tr_object *tr, struct bio *bp)
  192 {
  193         struct g_raid_volume *vol;
  194         struct g_raid_subdisk *sd;
  195         struct bio_queue_head queue;
  196         struct bio *cbp;
  197         char *addr;
  198         off_t offset, start, length, nstripe, remain;
  199         u_int no, strip_size;
  200 
  201         vol = tr->tro_volume;
  202         if (vol->v_state != G_RAID_VOLUME_S_OPTIMAL &&
  203             vol->v_state != G_RAID_VOLUME_S_SUBOPTIMAL) {
  204                 g_raid_iodone(bp, EIO);
  205                 return;
  206         }
  207         if (bp->bio_cmd == BIO_FLUSH || bp->bio_cmd == BIO_SPEEDUP) {
  208                 g_raid_tr_flush_common(tr, bp);
  209                 return;
  210         }
  211         if ((bp->bio_flags & BIO_UNMAPPED) != 0)
  212                 addr = NULL;
  213         else
  214                 addr = bp->bio_data;
  215         strip_size = vol->v_strip_size;
  216 
  217         /* Stripe number. */
  218         nstripe = bp->bio_offset / strip_size;
  219         /* Start position in stripe. */
  220         start = bp->bio_offset % strip_size;
  221         /* Disk number. */
  222         no = nstripe % vol->v_disks_count;
  223         /* Stripe start position in disk. */
  224         offset = (nstripe / vol->v_disks_count) * strip_size;
  225         /* Length of data to operate. */
  226         remain = bp->bio_length;
  227 
  228         bioq_init(&queue);
  229         do {
  230                 length = MIN(strip_size - start, remain);
  231                 cbp = g_clone_bio(bp);
  232                 if (cbp == NULL)
  233                         goto failure;
  234                 cbp->bio_offset = offset + start;
  235                 cbp->bio_length = length;
  236                 if ((bp->bio_flags & BIO_UNMAPPED) != 0 &&
  237                     bp->bio_cmd != BIO_DELETE) {
  238                         cbp->bio_ma_offset += (uintptr_t)addr;
  239                         cbp->bio_ma += cbp->bio_ma_offset / PAGE_SIZE;
  240                         cbp->bio_ma_offset %= PAGE_SIZE;
  241                         cbp->bio_ma_n = round_page(cbp->bio_ma_offset +
  242                             cbp->bio_length) / PAGE_SIZE;
  243                 } else
  244                         cbp->bio_data = addr;
  245                 cbp->bio_caller1 = &vol->v_subdisks[no];
  246                 bioq_insert_tail(&queue, cbp);
  247                 if (++no >= vol->v_disks_count) {
  248                         no = 0;
  249                         offset += strip_size;
  250                 }
  251                 remain -= length;
  252                 if (bp->bio_cmd != BIO_DELETE)
  253                         addr += length;
  254                 start = 0;
  255         } while (remain > 0);
  256         while ((cbp = bioq_takefirst(&queue)) != NULL) {
  257                 sd = cbp->bio_caller1;
  258                 cbp->bio_caller1 = NULL;
  259                 g_raid_subdisk_iostart(sd, cbp);
  260         }
  261         return;
  262 failure:
  263         while ((cbp = bioq_takefirst(&queue)) != NULL)
  264                 g_destroy_bio(cbp);
  265         if (bp->bio_error == 0)
  266                 bp->bio_error = ENOMEM;
  267         g_raid_iodone(bp, bp->bio_error);
  268 }
  269 
  270 static int
  271 g_raid_tr_kerneldump_raid0(struct g_raid_tr_object *tr,
  272     void *virtual, off_t boffset, size_t blength)
  273 {
  274         struct g_raid_volume *vol;
  275         char *addr;
  276         off_t offset, start, length, nstripe, remain;
  277         u_int no, strip_size;
  278         int error;
  279 
  280         vol = tr->tro_volume;
  281         if (vol->v_state != G_RAID_VOLUME_S_OPTIMAL)
  282                 return (ENXIO);
  283         addr = virtual;
  284         strip_size = vol->v_strip_size;
  285 
  286         /* Stripe number. */
  287         nstripe = boffset / strip_size;
  288         /* Start position in stripe. */
  289         start = boffset % strip_size;
  290         /* Disk number. */
  291         no = nstripe % vol->v_disks_count;
  292         /* Stripe tart position in disk. */
  293         offset = (nstripe / vol->v_disks_count) * strip_size;
  294         /* Length of data to operate. */
  295         remain = blength;
  296 
  297         do {
  298                 length = MIN(strip_size - start, remain);
  299                 error = g_raid_subdisk_kerneldump(&vol->v_subdisks[no], addr,
  300                     offset + start, length);
  301                 if (error != 0)
  302                         return (error);
  303                 if (++no >= vol->v_disks_count) {
  304                         no = 0;
  305                         offset += strip_size;
  306                 }
  307                 remain -= length;
  308                 addr += length;
  309                 start = 0;
  310         } while (remain > 0);
  311         return (0);
  312 }
  313 
  314 static void
  315 g_raid_tr_iodone_raid0(struct g_raid_tr_object *tr,
  316     struct g_raid_subdisk *sd,struct bio *bp)
  317 {
  318         struct bio *pbp;
  319 
  320         pbp = bp->bio_parent;
  321         if (pbp->bio_error == 0)
  322                 pbp->bio_error = bp->bio_error;
  323         g_destroy_bio(bp);
  324         pbp->bio_inbed++;
  325         if (pbp->bio_children == pbp->bio_inbed) {
  326                 pbp->bio_completed = pbp->bio_length;
  327                 g_raid_iodone(pbp, pbp->bio_error);
  328         }
  329 }
  330 
  331 static int
  332 g_raid_tr_free_raid0(struct g_raid_tr_object *tr)
  333 {
  334 
  335         return (0);
  336 }
  337 
  338 G_RAID_TR_DECLARE(raid0, "RAID0");

Cache object: b36ea74a767dc543a87dfb00920d8361


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