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.32 2000/05/10 07:54:29 grog Exp grog $
   39  * $FreeBSD$
   40  */
   41 
   42 #define STATIC static                                       /* nothing while we're testing XXX */
   43 
   44 #define REALLYKERNEL
   45 #include "opt_vinum.h"
   46 #include <dev/vinum/vinumhdr.h>
   47 #include <sys/sysproto.h>                                   /* for sync(2) */
   48 #include <sys/devicestat.h>
   49 #ifdef VINUMDEBUG
   50 #include <sys/reboot.h>
   51 int debug = 0;
   52 extern int total_malloced;
   53 extern int malloccount;
   54 extern struct mc malloced[];
   55 #endif
   56 #include <dev/vinum/request.h>
   57 
   58 STATIC struct cdevsw vinum_cdevsw =
   59 {
   60     vinumopen, vinumclose, vinumread, vinumwrite,
   61     vinumioctl, nostop, nullreset, nodevtotty,
   62     seltrue, nommap, vinumstrategy, "vinum",
   63     NULL, -1, vinumdump, vinumsize,
   64     D_DISK, 0, -1
   65 };
   66 
   67 /* Called by main() during pseudo-device attachment. */
   68 STATIC void vinumattach(void *);
   69 
   70 #ifndef ACTUALLY_LKM_NOT_KERNEL
   71 STATIC int vinum_modevent(module_t mod, modeventtype_t type, void *unused);
   72 #endif
   73 
   74 struct _vinum_conf vinum_conf;                              /* configuration information */
   75 
   76 /*
   77  * Called by main() during pseudo-device attachment.  All we need
   78  * to do is allocate enough space for devices to be configured later, and
   79  * add devsw entries.
   80  */
   81 void
   82 vinumattach(void *dummy)
   83 {
   84     /* modload should prevent multiple loads, so this is worth a panic */
   85     if ((vinum_conf.flags & VF_LOADED) != 0)
   86         panic("vinum: already loaded");
   87 
   88     log(LOG_INFO, "vinum: loaded\n");
   89     vinum_conf.flags |= VF_LOADED;                          /* we're loaded now */
   90 
   91     daemonq = NULL;                                         /* initialize daemon's work queue */
   92     dqend = NULL;
   93 
   94     cdevsw_add_generic(VINUM_BDEV_MAJOR, VINUM_CDEV_MAJOR, &vinum_cdevsw);
   95 
   96     /* allocate space: drives... */
   97     DRIVE = (struct drive *) Malloc(sizeof(struct drive) * INITIAL_DRIVES);
   98     CHECKALLOC(DRIVE, "vinum: no memory\n");
   99     bzero(DRIVE, sizeof(struct drive) * INITIAL_DRIVES);
  100     vinum_conf.drives_allocated = INITIAL_DRIVES;           /* number of drive slots allocated */
  101     vinum_conf.drives_used = 0;                             /* and number in use */
  102 
  103     /* volumes, ... */
  104     VOL = (struct volume *) Malloc(sizeof(struct volume) * INITIAL_VOLUMES);
  105     CHECKALLOC(VOL, "vinum: no memory\n");
  106     bzero(VOL, sizeof(struct volume) * INITIAL_VOLUMES);
  107     vinum_conf.volumes_allocated = INITIAL_VOLUMES;         /* number of volume slots allocated */
  108     vinum_conf.volumes_used = 0;                            /* and number in use */
  109 
  110     /* plexes, ... */
  111     PLEX = (struct plex *) Malloc(sizeof(struct plex) * INITIAL_PLEXES);
  112     CHECKALLOC(PLEX, "vinum: no memory\n");
  113     bzero(PLEX, sizeof(struct plex) * INITIAL_PLEXES);
  114     vinum_conf.plexes_allocated = INITIAL_PLEXES;           /* number of plex slots allocated */
  115     vinum_conf.plexes_used = 0;                             /* and number in use */
  116 
  117     /* and subdisks */
  118     SD = (struct sd *) Malloc(sizeof(struct sd) * INITIAL_SUBDISKS);
  119     CHECKALLOC(SD, "vinum: no memory\n");
  120     bzero(SD, sizeof(struct sd) * INITIAL_SUBDISKS);
  121     vinum_conf.subdisks_allocated = INITIAL_SUBDISKS;       /* number of sd slots allocated */
  122     vinum_conf.subdisks_used = 0;                           /* and number in use */
  123 }
  124 
  125 /*
  126  * Check if we have anything open.  If confopen is != 0,
  127  * that goes for the super device as well, otherwise
  128  * only for volumes.
  129  *
  130  * Return 0 if not inactive, 1 if inactive.
  131  */
  132 int
  133 vinum_inactive(int confopen)
  134 {
  135     int i;
  136     int can_do = 1;                                         /* assume we can do it */
  137 
  138     if (confopen && (vinum_conf.flags & VF_OPEN))           /* open by vinum(8)? */
  139         return 0;                                           /* can't do it while we're open */
  140     lock_config();
  141     for (i = 0; i < vinum_conf.volumes_allocated; i++) {
  142         if ((VOL[i].state > volume_down)
  143             && (VOL[i].flags & VF_OPEN)) {                  /* volume is open */
  144             can_do = 0;
  145             break;
  146         }
  147     }
  148     unlock_config();
  149     return can_do;
  150 }
  151 
  152 /*
  153  * Free all structures.
  154  * If cleardrive is 0, save the configuration; otherwise
  155  * remove the configuration from the drive.
  156  *
  157  * Before coming here, ensure that no volumes are open.
  158  */
  159 void
  160 free_vinum(int cleardrive)
  161 {
  162     int i;
  163     int drives_allocated = vinum_conf.drives_allocated;
  164 
  165     if (DRIVE != NULL) {
  166         if (cleardrive) {                                   /* remove the vinum config */
  167             for (i = 0; i < drives_allocated; i++)
  168                 remove_drive(i);                            /* remove the drive */
  169         } else {                                            /* keep the config */
  170             for (i = 0; i < drives_allocated; i++)
  171                 free_drive(&DRIVE[i]);                      /* close files and things */
  172         }
  173         Free(DRIVE);
  174     }
  175     while ((vinum_conf.flags & (VF_STOPPING | VF_DAEMONOPEN))
  176         == (VF_STOPPING | VF_DAEMONOPEN)) {                 /* at least one daemon open, we're stopping */
  177         queue_daemon_request(daemonrq_return, (union daemoninfo) 0); /* stop the daemon */
  178         tsleep(&vinumclose, PUSER, "vstop", 1);             /* and wait for it */
  179     }
  180     if (SD != NULL)
  181         Free(SD);
  182     if (PLEX != NULL) {
  183         for (i = 0; i < vinum_conf.plexes_allocated; i++) {
  184             struct plex *plex = &vinum_conf.plex[i];
  185 
  186             if (plex->state != plex_unallocated) {          /* we have real data there */
  187                 if (plex->sdnos)
  188                     Free(plex->sdnos);
  189             }
  190         }
  191         Free(PLEX);
  192     }
  193     if (VOL != NULL)
  194         Free(VOL);
  195     bzero(&vinum_conf, sizeof(vinum_conf));
  196 }
  197 
  198 STATIC int
  199 vinum_modevent(module_t mod, modeventtype_t type, void *unused)
  200 {
  201     struct sync_args dummyarg =
  202     {0};
  203 
  204     switch (type) {
  205     case MOD_LOAD:
  206         vinumattach(NULL);
  207         return 0;                                           /* OK */
  208     case MOD_UNLOAD:
  209         if (!vinum_inactive(1))                             /* is anything open? */
  210             return EBUSY;                                   /* yes, we can't do it */
  211         vinum_conf.flags |= VF_STOPPING;                    /* note that we want to stop */
  212         sync(curproc, &dummyarg);                           /* write out buffers */
  213         free_vinum(0);                                      /* clean up */
  214 #ifdef VINUMDEBUG
  215         if (total_malloced) {
  216             int i;
  217 #ifdef INVARIANTS
  218             int *poke;
  219 #endif
  220 
  221             for (i = 0; i < malloccount; i++) {
  222                 if (debug & DEBUG_WARNINGS)                 /* want to hear about them */
  223                     log(LOG_WARNING,
  224                         "vinum: exiting with %d bytes malloced from %s:%d\n",
  225                         malloced[i].size,
  226                         malloced[i].file,
  227                         malloced[i].line);
  228 #ifdef INVARIANTS
  229                 poke = &((int *) malloced[i].address)
  230                     [malloced[i].size / (2 * sizeof(int))]; /* middle of the area */
  231                 if (*poke == 0xdeadc0de)                    /* already freed */
  232                     log(LOG_ERR,
  233                         "vinum: exiting with malloc table inconsistency at %p from %s:%d\n",
  234                         malloced[i].address,
  235                         malloced[i].file,
  236                         malloced[i].line);
  237 #endif
  238                 Free(malloced[i].address);
  239             }
  240         }
  241 #endif
  242         cdevsw[VINUM_CDEV_MAJOR] = NULL;                    /* no cdevsw any more */
  243         bdevsw[VINUM_BDEV_MAJOR] = NULL;                    /* nor bdevsw */
  244         log(LOG_INFO, "vinum: unloaded\n");                 /* tell the world */
  245         return 0;
  246     default:
  247         break;
  248     }
  249     return 0;
  250 }
  251 
  252 moduledata_t vinum_mod =
  253 {
  254     "vinum",
  255     (modeventhand_t) vinum_modevent,
  256     0
  257 };
  258 DECLARE_MODULE(vinum, vinum_mod, SI_SUB_VINUM, SI_ORDER_MIDDLE);
  259 
  260 /* ARGSUSED */
  261 /* Open a vinum object */
  262 int
  263 vinumopen(dev_t dev,
  264     int flags,
  265     int fmt,
  266     struct proc *p)
  267 {
  268     int error;
  269     unsigned int index;
  270     struct volume *vol;
  271     struct plex *plex;
  272     struct sd *sd;
  273     int devminor;                                           /* minor number */
  274 
  275     devminor = minor(dev);
  276     error = 0;
  277     /* First, decide what we're looking at */
  278     switch (DEVTYPE(dev)) {
  279     case VINUM_VOLUME_TYPE:
  280         index = Volno(dev);
  281         if (index >= vinum_conf.volumes_allocated)
  282             return ENXIO;                                   /* no such device */
  283         vol = &VOL[index];
  284 
  285         switch (vol->state) {
  286         case volume_unallocated:
  287         case volume_uninit:
  288             return ENXIO;
  289 
  290         case volume_up:
  291             vol->flags |= VF_OPEN;                          /* note we're open */
  292             return 0;
  293 
  294         case volume_down:
  295             return EIO;
  296 
  297         default:
  298             return EINVAL;
  299         }
  300 
  301     case VINUM_PLEX_TYPE:
  302         if (Volno(dev) >= vinum_conf.volumes_allocated)
  303             return ENXIO;
  304         /* FALLTHROUGH */
  305 
  306     case VINUM_RAWPLEX_TYPE:
  307         index = Plexno(dev);                                /* get plex index in vinum_conf */
  308         if (index >= vinum_conf.plexes_allocated)
  309             return ENXIO;                                   /* no such device */
  310         plex = &PLEX[index];
  311 
  312         switch (plex->state) {
  313         case plex_referenced:
  314         case plex_unallocated:
  315             return EINVAL;
  316 
  317         default:
  318             plex->flags |= VF_OPEN;                         /* note we're open */
  319             return 0;
  320         }
  321 
  322     case VINUM_SD_TYPE:
  323         if ((Volno(dev) >= vinum_conf.volumes_allocated)    /* no such volume */
  324         ||(Plexno(dev) >= vinum_conf.plexes_allocated))     /* or no such plex */
  325             return ENXIO;                                   /* no such device */
  326 
  327         /* FALLTHROUGH */
  328 
  329     case VINUM_RAWSD_TYPE:
  330         index = Sdno(dev);                                  /* get the subdisk number */
  331         if ((index >= vinum_conf.subdisks_allocated)        /* not a valid SD entry */
  332         ||(SD[index].state < sd_init))                      /* or SD is not real */
  333             return ENXIO;                                   /* no such device */
  334         sd = &SD[index];
  335 
  336         /*
  337          * Opening a subdisk is always a special operation, so we
  338          * ignore the state as long as it represents a real subdisk
  339          */
  340         switch (sd->state) {
  341         case sd_unallocated:
  342         case sd_uninit:
  343             return EINVAL;
  344 
  345         default:
  346             sd->flags |= VF_OPEN;                           /* note we're open */
  347             return 0;
  348         }
  349 
  350     case VINUM_SUPERDEV_TYPE:
  351         error = suser(p->p_ucred, &p->p_acflag);            /* are we root? */
  352         if (error == 0) {                                   /* yes, can do */
  353             if (devminor == VINUM_DAEMON_DEV)               /* daemon device */
  354                 vinum_conf.flags |= VF_DAEMONOPEN;          /* we're open */
  355             else if (devminor == VINUM_SUPERDEV)
  356                 vinum_conf.flags |= VF_OPEN;                /* we're open */
  357             else
  358                 error = ENODEV;                             /* nothing, maybe a debug mismatch */
  359         }
  360         return error;
  361 
  362         /* Vinum drives are disks.  We already have a disk
  363          * driver, so don't handle them here */
  364     case VINUM_DRIVE_TYPE:
  365     default:
  366         return ENODEV;                                      /* don't know what to do with these */
  367     }
  368 }
  369 
  370 /* ARGSUSED */
  371 int
  372 vinumclose(dev_t dev,
  373     int flags,
  374     int fmt,
  375     struct proc *p)
  376 {
  377     unsigned int index;
  378     struct volume *vol;
  379     int devminor;
  380 
  381     devminor = minor(dev);
  382     index = Volno(dev);
  383     /* First, decide what we're looking at */
  384     switch (DEVTYPE(dev)) {
  385     case VINUM_VOLUME_TYPE:
  386         if (index >= vinum_conf.volumes_allocated)
  387             return ENXIO;                                   /* no such device */
  388         vol = &VOL[index];
  389 
  390         switch (vol->state) {
  391         case volume_unallocated:
  392         case volume_uninit:
  393             return ENXIO;
  394 
  395         case volume_up:
  396             vol->flags &= ~VF_OPEN;                         /* reset our flags */
  397             return 0;
  398 
  399         case volume_down:
  400             return EIO;
  401 
  402         default:
  403             return EINVAL;
  404         }
  405 
  406     case VINUM_PLEX_TYPE:
  407         if (Volno(dev) >= vinum_conf.volumes_allocated)
  408             return ENXIO;
  409         /* FALLTHROUGH */
  410 
  411     case VINUM_RAWPLEX_TYPE:
  412         index = Plexno(dev);                                /* get plex index in vinum_conf */
  413         if (index >= vinum_conf.plexes_allocated)
  414             return ENXIO;                                   /* no such device */
  415         PLEX[index].flags &= ~VF_OPEN;                      /* reset our flags */
  416         return 0;
  417 
  418     case VINUM_SD_TYPE:
  419         if ((Volno(dev) >= vinum_conf.volumes_allocated) || /* no such volume */
  420             (Plexno(dev) >= vinum_conf.plexes_allocated))   /* or no such plex */
  421             return ENXIO;                                   /* no such device */
  422         /* FALLTHROUGH */
  423 
  424     case VINUM_RAWSD_TYPE:
  425         index = Sdno(dev);                                  /* get the subdisk number */
  426         if (index >= vinum_conf.subdisks_allocated)
  427             return ENXIO;                                   /* no such device */
  428         SD[index].flags &= ~VF_OPEN;                        /* reset our flags */
  429         return 0;
  430 
  431     case VINUM_SUPERDEV_TYPE:
  432         /*
  433          * don't worry about whether we're root:
  434          * nobody else would get this far.
  435          */
  436         if (devminor == VINUM_SUPERDEV)                     /* normal superdev */
  437             vinum_conf.flags &= ~VF_OPEN;                   /* no longer open */
  438         else if (devminor == VINUM_DAEMON_DEV) {            /* the daemon device */
  439             vinum_conf.flags &= ~VF_DAEMONOPEN;             /* no longer open */
  440             if (vinum_conf.flags & VF_STOPPING)             /* we're stopping, */
  441                 wakeup(&vinumclose);                        /* we can continue stopping now */
  442         }
  443         return 0;
  444 
  445     case VINUM_DRIVE_TYPE:
  446     default:
  447         return ENODEV;                                      /* don't know what to do with these */
  448     }
  449 }
  450 
  451 /* size routine */
  452 int
  453 vinumsize(dev_t dev)
  454 {
  455     struct volume *vol;
  456     int size;
  457 
  458     vol = &VOL[Volno(dev)];
  459 
  460     if (vol->state == volume_up)
  461         size = vol->size;
  462     else
  463         return 0;                                           /* err on the size of conservatism */
  464 
  465     return size;
  466 }
  467 
  468 int
  469 vinumdump(dev_t dev)
  470 {
  471     /* Not implemented. */
  472     return ENXIO;
  473 }
  474 
  475 /* Local Variables: */
  476 /* fill-column: 50 */
  477 /* End: */

Cache object: 3542270437078a6e75b049f3b1162bc4


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