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/dev/vinum/vinum.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  * Copyright (c) 1997, 1998
    3  *      Nan Yang Computer Services Limited.  All rights reserved.
    4  *
    5  *  Written by Greg Lehey
    6  *
    7  *  This software is distributed under the so-called ``Berkeley
    8  *  License'':
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by Nan Yang Computer
   21  *      Services Limited.
   22  * 4. Neither the name of the Company nor the names of its contributors
   23  *    may be used to endorse or promote products derived from this software
   24  *    without specific prior written permission.
   25  *
   26  * This software is provided ``as is'', and any express or implied
   27  * warranties, including, but not limited to, the implied warranties of
   28  * merchantability and fitness for a particular purpose are disclaimed.
   29  * In no event shall the company or contributors be liable for any
   30  * direct, indirect, incidental, special, exemplary, or consequential
   31  * damages (including, but not limited to, procurement of substitute
   32  * goods or services; loss of use, data, or profits; or business
   33  * interruption) however caused and on any theory of liability, whether
   34  * in contract, strict liability, or tort (including negligence or
   35  * otherwise) arising in any way out of the use of this software, even if
   36  * advised of the possibility of such damage.
   37  *
   38  * $Id: vinum.c,v 1.34 2001/05/22 04:07:22 grog Exp grog $
   39  * $FreeBSD: releng/5.0/sys/dev/vinum/vinum.c 93593 2002-04-01 21:31:13Z jhb $
   40  */
   41 
   42 #define STATIC static                                       /* nothing while we're testing XXX */
   43 
   44 #include <dev/vinum/vinumhdr.h>
   45 #include <sys/sysproto.h>                                   /* for sync(2) */
   46 #include <sys/devicestat.h>
   47 #ifdef VINUMDEBUG
   48 #include <sys/reboot.h>
   49 int debug = 0;
   50 extern int total_malloced;
   51 extern int malloccount;
   52 extern struct mc malloced[];
   53 #endif
   54 #include <dev/vinum/request.h>
   55 
   56 struct cdevsw vinum_cdevsw =
   57 {
   58     vinumopen, vinumclose, physread, physwrite,
   59     vinumioctl, seltrue, nommap, vinumstrategy,
   60     "vinum", VINUM_CDEV_MAJOR, nodump, vinumsize,
   61     D_DISK
   62 };
   63 
   64 /* Called by main() during pseudo-device attachment. */
   65 STATIC void vinumattach(void *);
   66 
   67 STATIC int vinum_modevent(module_t mod, modeventtype_t type, void *unused);
   68 
   69 struct _vinum_conf vinum_conf;                              /* configuration information */
   70 
   71 dev_t vinum_daemon_dev;
   72 dev_t vinum_super_dev;
   73 
   74 /*
   75  * Called by main() during pseudo-device attachment.  All we need
   76  * to do is allocate enough space for devices to be configured later, and
   77  * add devsw entries.
   78  */
   79 void
   80 vinumattach(void *dummy)
   81 {
   82     /* modload should prevent multiple loads, so this is worth a panic */
   83     if ((vinum_conf.flags & VF_LOADED) != 0)
   84         panic("vinum: already loaded");
   85 
   86     log(LOG_INFO, "vinum: loaded\n");
   87 #ifdef VINUMDEBUG
   88     vinum_conf.flags |= VF_LOADED | VF_HASDEBUG;            /* we're loaded now, and we support debug */
   89 #else
   90     vinum_conf.flags |= VF_LOADED;                          /* we're loaded now */
   91 #endif
   92 
   93     daemonq = NULL;                                         /* initialize daemon's work queue */
   94     dqend = NULL;
   95 
   96     vinum_daemon_dev = make_dev(&vinum_cdevsw,
   97         VINUM_DAEMON_DEV,
   98         UID_ROOT,
   99         GID_WHEEL,
  100         S_IRUSR | S_IWUSR,
  101         "vinum/controld");
  102     vinum_super_dev = make_dev(&vinum_cdevsw,
  103         VINUM_SUPERDEV,
  104         UID_ROOT,
  105         GID_WHEEL,
  106         S_IRUSR | S_IWUSR,
  107         "vinum/control");
  108 
  109     vinum_conf.version = VINUMVERSION;                      /* note what version we are */
  110 
  111     /* allocate space: drives... */
  112     DRIVE = (struct drive *) Malloc(sizeof(struct drive) * INITIAL_DRIVES);
  113     CHECKALLOC(DRIVE, "vinum: no memory\n");
  114     bzero(DRIVE, sizeof(struct drive) * INITIAL_DRIVES);
  115     vinum_conf.drives_allocated = INITIAL_DRIVES;           /* number of drive slots allocated */
  116     vinum_conf.drives_used = 0;                             /* and number in use */
  117 
  118     /* volumes, ... */
  119     VOL = (struct volume *) Malloc(sizeof(struct volume) * INITIAL_VOLUMES);
  120     CHECKALLOC(VOL, "vinum: no memory\n");
  121     bzero(VOL, sizeof(struct volume) * INITIAL_VOLUMES);
  122     vinum_conf.volumes_allocated = INITIAL_VOLUMES;         /* number of volume slots allocated */
  123     vinum_conf.volumes_used = 0;                            /* and number in use */
  124 
  125     /* plexes, ... */
  126     PLEX = (struct plex *) Malloc(sizeof(struct plex) * INITIAL_PLEXES);
  127     CHECKALLOC(PLEX, "vinum: no memory\n");
  128     bzero(PLEX, sizeof(struct plex) * INITIAL_PLEXES);
  129     vinum_conf.plexes_allocated = INITIAL_PLEXES;           /* number of plex slots allocated */
  130     vinum_conf.plexes_used = 0;                             /* and number in use */
  131 
  132     /* and subdisks */
  133     SD = (struct sd *) Malloc(sizeof(struct sd) * INITIAL_SUBDISKS);
  134     CHECKALLOC(SD, "vinum: no memory\n");
  135     bzero(SD, sizeof(struct sd) * INITIAL_SUBDISKS);
  136     vinum_conf.subdisks_allocated = INITIAL_SUBDISKS;       /* number of sd slots allocated */
  137     vinum_conf.subdisks_used = 0;                           /* and number in use */
  138 }
  139 
  140 /*
  141  * Check if we have anything open.  If confopen is != 0,
  142  * that goes for the super device as well, otherwise
  143  * only for volumes.
  144  *
  145  * Return 0 if not inactive, 1 if inactive.
  146  */
  147 int
  148 vinum_inactive(int confopen)
  149 {
  150     int i;
  151     int can_do = 1;                                         /* assume we can do it */
  152 
  153     if (confopen && (vinum_conf.flags & VF_OPEN))           /* open by vinum(8)? */
  154         return 0;                                           /* can't do it while we're open */
  155     lock_config();
  156     for (i = 0; i < vinum_conf.volumes_allocated; i++) {
  157         if ((VOL[i].state > volume_down)
  158             && (VOL[i].flags & VF_OPEN)) {                  /* volume is open */
  159             can_do = 0;
  160             break;
  161         }
  162     }
  163     unlock_config();
  164     return can_do;
  165 }
  166 
  167 /*
  168  * Free all structures.
  169  * If cleardrive is 0, save the configuration; otherwise
  170  * remove the configuration from the drive.
  171  *
  172  * Before coming here, ensure that no volumes are open.
  173  */
  174 void
  175 free_vinum(int cleardrive)
  176 {
  177     int i;
  178     int drives_allocated = vinum_conf.drives_allocated;
  179 
  180     if (DRIVE != NULL) {
  181         if (cleardrive) {                                   /* remove the vinum config */
  182             for (i = 0; i < drives_allocated; i++)
  183                 remove_drive(i);                            /* remove the drive */
  184         } else {                                            /* keep the config */
  185             for (i = 0; i < drives_allocated; i++)
  186                 free_drive(&DRIVE[i]);                      /* close files and things */
  187         }
  188         Free(DRIVE);
  189     }
  190     while ((vinum_conf.flags & (VF_STOPPING | VF_DAEMONOPEN))
  191         == (VF_STOPPING | VF_DAEMONOPEN)) {                 /* at least one daemon open, we're stopping */
  192         queue_daemon_request(daemonrq_return, (union daemoninfo) 0); /* stop the daemon */
  193         tsleep(&vinumclose, PUSER, "vstop", 1);             /* and wait for it */
  194     }
  195     if (SD != NULL) {
  196         for (i = 0; i < vinum_conf.subdisks_allocated; i++) {
  197             struct sd *sd = &SD[i];
  198 
  199             if (sd->state != sd_unallocated)
  200                 free_sd(i);
  201         }
  202         Free(SD);
  203     }
  204     if (PLEX != NULL) {
  205         for (i = 0; i < vinum_conf.plexes_allocated; i++) {
  206             struct plex *plex = &PLEX[i];
  207 
  208             if (plex->state != plex_unallocated)            /* we have real data there */
  209                 free_plex(i);
  210         }
  211         Free(PLEX);
  212     }
  213     if (VOL != NULL) {
  214         for (i = 0; i < vinum_conf.volumes_allocated; i++) {
  215             struct volume *volume = &VOL[i];
  216 
  217             if (volume->state != volume_unallocated)
  218                 free_volume(i);
  219         }
  220         Free(VOL);
  221     }
  222     bzero(&vinum_conf, sizeof(vinum_conf));
  223 }
  224 
  225 STATIC int
  226 vinum_modevent(module_t mod, modeventtype_t type, void *unused)
  227 {
  228     struct sync_args dummyarg =
  229     {0};
  230 
  231     switch (type) {
  232     case MOD_LOAD:
  233         vinumattach(NULL);
  234         return 0;                                           /* OK */
  235     case MOD_UNLOAD:
  236         if (!vinum_inactive(1))                             /* is anything open? */
  237             return EBUSY;                                   /* yes, we can't do it */
  238         vinum_conf.flags |= VF_STOPPING;                    /* note that we want to stop */
  239         sync(curthread, &dummyarg);                         /* write out buffers */
  240         free_vinum(0);                                      /* clean up */
  241 #ifdef VINUMDEBUG
  242         if (total_malloced) {
  243             int i;
  244 #ifdef INVARIANTS
  245             int *poke;
  246 #endif
  247 
  248             for (i = 0; i < malloccount; i++) {
  249                 if (debug & DEBUG_WARNINGS)                 /* want to hear about them */
  250                     log(LOG_WARNING,
  251                         "vinum: exiting with %d bytes malloced from %s:%d\n",
  252                         malloced[i].size,
  253                         malloced[i].file,
  254                         malloced[i].line);
  255 #ifdef INVARIANTS
  256                 poke = &((int *) malloced[i].address)
  257                     [malloced[i].size / (2 * sizeof(int))]; /* middle of the area */
  258                 if (*poke == 0xdeadc0de)                    /* already freed */
  259                     log(LOG_ERR,
  260                         "vinum: exiting with malloc table inconsistency at %p from %s:%d\n",
  261                         malloced[i].address,
  262                         malloced[i].file,
  263                         malloced[i].line);
  264 #endif
  265                 Free(malloced[i].address);
  266             }
  267         }
  268 #endif
  269         destroy_dev(vinum_daemon_dev);                      /* daemon device */
  270         destroy_dev(vinum_super_dev);
  271         log(LOG_INFO, "vinum: unloaded\n");                 /* tell the world */
  272         return 0;
  273     default:
  274         break;
  275     }
  276     return 0;
  277 }
  278 
  279 static moduledata_t vinum_mod =
  280 {
  281     "vinum",
  282     (modeventhand_t) vinum_modevent,
  283     0
  284 };
  285 DECLARE_MODULE(vinum, vinum_mod, SI_SUB_VINUM, SI_ORDER_MIDDLE);
  286 
  287 /* ARGSUSED */
  288 /* Open a vinum object */
  289 int
  290 vinumopen(dev_t dev,
  291     int flags,
  292     int fmt,
  293     struct thread *td)
  294 {
  295     int error;
  296     unsigned int index;
  297     struct volume *vol;
  298     struct plex *plex;
  299     struct sd *sd;
  300     int devminor;                                           /* minor number */
  301 
  302     devminor = minor(dev);
  303     error = 0;
  304     /* First, decide what we're looking at */
  305     switch (DEVTYPE(dev)) {
  306     case VINUM_VOLUME_TYPE:
  307         index = Volno(dev);
  308         if (index >= vinum_conf.volumes_allocated)
  309             return ENXIO;                                   /* no such device */
  310         vol = &VOL[index];
  311 
  312         switch (vol->state) {
  313         case volume_unallocated:
  314         case volume_uninit:
  315             return ENXIO;
  316 
  317         case volume_up:
  318             vol->flags |= VF_OPEN;                          /* note we're open */
  319             return 0;
  320 
  321         case volume_down:
  322             return EIO;
  323 
  324         default:
  325             return EINVAL;
  326         }
  327 
  328     case VINUM_PLEX_TYPE:
  329         if (Volno(dev) >= vinum_conf.volumes_allocated)
  330             return ENXIO;
  331         /* FALLTHROUGH */
  332 
  333     case VINUM_RAWPLEX_TYPE:
  334         index = Plexno(dev);                                /* get plex index in vinum_conf */
  335         if (index >= vinum_conf.plexes_allocated)
  336             return ENXIO;                                   /* no such device */
  337         plex = &PLEX[index];
  338 
  339         switch (plex->state) {
  340         case plex_referenced:
  341         case plex_unallocated:
  342             return EINVAL;
  343 
  344         default:
  345             plex->flags |= VF_OPEN;                         /* note we're open */
  346             return 0;
  347         }
  348 
  349     case VINUM_SD_TYPE:
  350         if ((Volno(dev) >= vinum_conf.volumes_allocated)    /* no such volume */
  351         ||(Plexno(dev) >= vinum_conf.plexes_allocated))     /* or no such plex */
  352             return ENXIO;                                   /* no such device */
  353 
  354         /* FALLTHROUGH */
  355 
  356     case VINUM_RAWSD_TYPE:
  357         index = Sdno(dev);                                  /* get the subdisk number */
  358         if ((index >= vinum_conf.subdisks_allocated)        /* not a valid SD entry */
  359         ||(SD[index].state < sd_init))                      /* or SD is not real */
  360             return ENXIO;                                   /* no such device */
  361         sd = &SD[index];
  362 
  363         /*
  364          * Opening a subdisk is always a special operation, so we
  365          * ignore the state as long as it represents a real subdisk
  366          */
  367         switch (sd->state) {
  368         case sd_unallocated:
  369         case sd_uninit:
  370             return EINVAL;
  371 
  372         default:
  373             sd->flags |= VF_OPEN;                           /* note we're open */
  374             return 0;
  375         }
  376 
  377     case VINUM_SUPERDEV_TYPE:
  378         error = suser(td);                                  /* are we root? */
  379         if (error == 0) {                                   /* yes, can do */
  380             if (devminor == VINUM_DAEMON_DEV)               /* daemon device */
  381                 vinum_conf.flags |= VF_DAEMONOPEN;          /* we're open */
  382             else if (devminor == VINUM_SUPERDEV)
  383                 vinum_conf.flags |= VF_OPEN;                /* we're open */
  384             else
  385                 error = ENODEV;                             /* nothing, maybe a debug mismatch */
  386         }
  387         return error;
  388 
  389         /* Vinum drives are disks.  We already have a disk
  390          * driver, so don't handle them here */
  391     case VINUM_DRIVE_TYPE:
  392     default:
  393         return ENODEV;                                      /* don't know what to do with these */
  394     }
  395 }
  396 
  397 /* ARGSUSED */
  398 int
  399 vinumclose(dev_t dev,
  400     int flags,
  401     int fmt,
  402     struct thread *td)
  403 {
  404     unsigned int index;
  405     struct volume *vol;
  406     int devminor;
  407 
  408     devminor = minor(dev);
  409     index = Volno(dev);
  410     /* First, decide what we're looking at */
  411     switch (DEVTYPE(dev)) {
  412     case VINUM_VOLUME_TYPE:
  413         if (index >= vinum_conf.volumes_allocated)
  414             return ENXIO;                                   /* no such device */
  415         vol = &VOL[index];
  416 
  417         switch (vol->state) {
  418         case volume_unallocated:
  419         case volume_uninit:
  420             return ENXIO;
  421 
  422         case volume_up:
  423             vol->flags &= ~VF_OPEN;                         /* reset our flags */
  424             return 0;
  425 
  426         case volume_down:
  427             return EIO;
  428 
  429         default:
  430             return EINVAL;
  431         }
  432 
  433     case VINUM_PLEX_TYPE:
  434         if (Volno(dev) >= vinum_conf.volumes_allocated)
  435             return ENXIO;
  436         /* FALLTHROUGH */
  437 
  438     case VINUM_RAWPLEX_TYPE:
  439         index = Plexno(dev);                                /* get plex index in vinum_conf */
  440         if (index >= vinum_conf.plexes_allocated)
  441             return ENXIO;                                   /* no such device */
  442         PLEX[index].flags &= ~VF_OPEN;                      /* reset our flags */
  443         return 0;
  444 
  445     case VINUM_SD_TYPE:
  446         if ((Volno(dev) >= vinum_conf.volumes_allocated) || /* no such volume */
  447             (Plexno(dev) >= vinum_conf.plexes_allocated))   /* or no such plex */
  448             return ENXIO;                                   /* no such device */
  449         /* FALLTHROUGH */
  450 
  451     case VINUM_RAWSD_TYPE:
  452         index = Sdno(dev);                                  /* get the subdisk number */
  453         if (index >= vinum_conf.subdisks_allocated)
  454             return ENXIO;                                   /* no such device */
  455         SD[index].flags &= ~VF_OPEN;                        /* reset our flags */
  456         return 0;
  457 
  458     case VINUM_SUPERDEV_TYPE:
  459         /*
  460          * don't worry about whether we're root:
  461          * nobody else would get this far.
  462          */
  463         if (devminor == VINUM_SUPERDEV)                     /* normal superdev */
  464             vinum_conf.flags &= ~VF_OPEN;                   /* no longer open */
  465         else if (devminor == VINUM_DAEMON_DEV) {            /* the daemon device */
  466             vinum_conf.flags &= ~VF_DAEMONOPEN;             /* no longer open */
  467             if (vinum_conf.flags & VF_STOPPING)             /* we're stopping, */
  468                 wakeup(&vinumclose);                        /* we can continue stopping now */
  469         }
  470         return 0;
  471 
  472     case VINUM_DRIVE_TYPE:
  473     default:
  474         return ENODEV;                                      /* don't know what to do with these */
  475     }
  476 }
  477 
  478 /* size routine */
  479 int
  480 vinumsize(dev_t dev)
  481 {
  482     struct volume *vol;
  483     int size;
  484 
  485     vol = &VOL[Volno(dev)];
  486 
  487     if (vol->state == volume_up)
  488         size = vol->size;
  489     else
  490         return 0;                                           /* err on the size of conservatism */
  491 
  492     return size;
  493 }
  494 
  495 /* Local Variables: */
  496 /* fill-column: 50 */
  497 /* End: */

Cache object: 9fdcc361d37a3f14e7a44c1f46fcbd51


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