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/raid/vinum/vinumdaemon.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 /* daemon.c: kernel part of Vinum daemon */
    2 /*-
    3  * Copyright (c) 1997, 1998
    4  *      Nan Yang Computer Services Limited.  All rights reserved.
    5  *
    6  *  This software is distributed under the so-called ``Berkeley
    7  *  License'':
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed by Nan Yang Computer
   20  *      Services Limited.
   21  * 4. Neither the name of the Company nor the names of its contributors
   22  *    may be used to endorse or promote products derived from this software
   23  *    without specific prior written permission.
   24  *
   25  * This software is provided ``as is'', and any express or implied
   26  * warranties, including, but not limited to, the implied warranties of
   27  * merchantability and fitness for a particular purpose are disclaimed.
   28  * In no event shall the company or contributors be liable for any
   29  * direct, indirect, incidental, special, exemplary, or consequential
   30  * damages (including, but not limited to, procurement of substitute
   31  * goods or services; loss of use, data, or profits; or business
   32  * interruption) however caused and on any theory of liability, whether
   33  * in contract, strict liability, or tort (including negligence or
   34  * otherwise) arising in any way out of the use of this software, even if
   35  * advised of the possibility of such damage.
   36  *
   37  * $Id: vinumdaemon.c,v 1.8 2000/01/03 05:22:03 grog Exp grog $
   38  * $FreeBSD: src/sys/dev/vinum/vinumdaemon.c,v 1.16 2000/01/05 06:03:56 grog Exp $
   39  */
   40 
   41 #include "vinumhdr.h"
   42 #include "request.h"
   43 
   44 #ifdef VINUMDEBUG
   45 #include <sys/reboot.h>
   46 #endif
   47 
   48 /* declarations */
   49 void recover_io(struct request *rq);
   50 
   51 int daemon_options = 0;                                     /* options */
   52 int daemonpid;                                              /* PID of daemon */
   53 struct daemonq *daemonq;                                    /* daemon's work queue */
   54 struct daemonq *dqend;                                      /* and the end of the queue */
   55 
   56 /*
   57  * We normally call Malloc to get a queue element.  In interrupt
   58  * context, we can't guarantee that we'll get one, since we're not
   59  * allowed to wait.  If malloc fails, use one of these elements.
   60  */
   61 
   62 #define INTQSIZE 4
   63 struct daemonq intq[INTQSIZE];                              /* queue elements for interrupt context */
   64 struct daemonq *intqp;                                      /* and pointer in it */
   65 
   66 void
   67 vinum_daemon(void)
   68 {
   69     struct daemonq *request;
   70 
   71     curproc->p_flags |= P_SYSTEM;                   /* we're a system process */
   72     daemon_save_config();                                   /* start by saving the configuration */
   73     daemonpid = curproc->p_pid;                             /* mark our territory */
   74     while (1) {
   75         tsleep(&vinum_daemon, 0, "vinum", 0);       /* wait for something to happen */
   76 
   77         /*
   78          * It's conceivable that, as the result of an
   79          * I/O error, we'll be out of action long
   80          * enough that another daemon gets started.
   81          * That's OK, just give up gracefully.
   82          */
   83         if (curproc->p_pid != daemonpid) {                  /* we've been ousted in our sleep */
   84             if (daemon_options & daemon_verbose)
   85                 log(LOG_INFO, "vinum: abdicating\n");
   86             return;
   87         }
   88         while (daemonq != NULL) {                           /* we have work to do, */
   89             crit_enter();
   90             request = daemonq;                              /* get the request */
   91             daemonq = daemonq->next;                        /* and detach it */
   92             if (daemonq == NULL)                            /* got to the end, */
   93                 dqend = NULL;                               /* no end any more */
   94             crit_exit();
   95 
   96             switch (request->type) {
   97                 /*
   98                  * We had an I/O error on a request.  Go through the
   99                  * request and try to salvage it
  100                  */
  101             case daemonrq_ioerror:
  102                 if (daemon_options & daemon_verbose) {
  103                     struct request *rq = request->info.rq;
  104 
  105                     log(LOG_WARNING,
  106                         "vinum: recovering I/O request: %p\n%s dev %d.%d, offset 0x%012llx, length %d\n",
  107                         rq,
  108                         (rq->bio->bio_buf->b_cmd == BUF_CMD_READ) ? "Read" : "Write",
  109                         major((cdev_t)rq->bio->bio_driver_info),
  110                         minor((cdev_t)rq->bio->bio_driver_info),
  111                         (long long)rq->bio->bio_offset,
  112                         rq->bio->bio_buf->b_bcount);
  113                 }
  114                 recover_io(request->info.rq);               /* the failed request */
  115                 break;
  116 
  117                 /*
  118                  * Write the config to disk.  We could end up with
  119                  * quite a few of these in a row.  Only honour the
  120                  * last one
  121                  */
  122             case daemonrq_saveconfig:
  123                 if ((daemonq == NULL)                       /* no more requests */
  124                 ||(daemonq->type != daemonrq_saveconfig)) { /* or the next isn't the same */
  125                     if (((daemon_options & daemon_noupdate) == 0) /* we're allowed to do it */
  126                     &&((vinum_conf.flags & VF_READING_CONFIG) == 0)) { /* and we're not building the config now */
  127                         /*
  128                            * We obviously don't want to save a
  129                            * partial configuration.  Less obviously,
  130                            * we don't need to do anything if we're
  131                            * asked to write the config when we're
  132                            * building it up, because we save it at
  133                            * the end.
  134                          */
  135                         if (daemon_options & daemon_verbose)
  136                             log(LOG_INFO, "vinum: saving config\n");
  137                         daemon_save_config();               /* save it */
  138                     }
  139                 }
  140                 break;
  141 
  142             case daemonrq_return:                           /* been told to stop */
  143                 if (daemon_options & daemon_verbose)
  144                     log(LOG_INFO, "vinum: stopping\n");
  145                 daemon_options |= daemon_stopped;           /* note that we've stopped */
  146                 Free(request);
  147                 while (daemonq != NULL) {                   /* backed up requests, */
  148                     request = daemonq;                      /* get the request */
  149                     daemonq = daemonq->next;                /* and detach it */
  150                     Free(request);                          /* then free it */
  151                 }
  152                 wakeup(&vinumclose);                        /* and wake any waiting vinum(8)s */
  153                 return;
  154 
  155             case daemonrq_ping:                             /* tell the caller we're here */
  156                 if (daemon_options & daemon_verbose)
  157                     log(LOG_INFO, "vinum: ping reply\n");
  158                 wakeup(&vinum_finddaemon);                  /* wake up the caller */
  159                 break;
  160 
  161             case daemonrq_closedrive:                       /* close a drive */
  162                 close_drive(request->info.drive);           /* do it */
  163                 break;
  164 
  165             case daemonrq_init:                             /* initialize a plex */
  166                 /* XXX */
  167             case daemonrq_revive:                           /* revive a subdisk */
  168                 /* XXX */
  169                 /* FALLTHROUGH */
  170             default:
  171                 log(LOG_WARNING, "Invalid request\n");
  172                 break;
  173             }
  174             if (request->privateinuse)                      /* one of ours, */
  175                 request->privateinuse = 0;                  /* no longer in use */
  176             else
  177                 Free(request);                              /* return it */
  178         }
  179     }
  180 }
  181 
  182 /*
  183  * Recover a failed I/O operation.
  184  *
  185  * The correct way to do this is to examine the request and determine
  186  * how to recover each individual failure.  In the case of a write,
  187  * this could be as simple as doing nothing: the defective drives may
  188  * already be down, and there may be nothing else to do.  In case of
  189  * a read, it will be necessary to retry if there are alternative
  190  * copies of the data.
  191  *
  192  * The easy way (here) is just to reissue the request.  This will take
  193  * a little longer, but nothing like as long as the failure will have
  194  * taken.
  195  *
  196  */
  197 void
  198 recover_io(struct request *rq)
  199 {
  200     /*
  201      * This should read:
  202      *
  203      *     vinumstrategy(rq->bio);
  204      *
  205      * Negotiate with phk to get it fixed.
  206      * Reissue the command.
  207      */
  208     dev_dstrategy((cdev_t)rq->bio->bio_driver_info, rq->bio);
  209 }
  210 
  211 /* Functions called to interface with the daemon */
  212 
  213 /* queue a request for the daemon */
  214 void
  215 queue_daemon_request(enum daemonrq type, union daemoninfo info)
  216 {
  217     struct daemonq *qelt = (struct daemonq *) Malloc(sizeof(struct daemonq));
  218 
  219     if (qelt == NULL) {                                     /* malloc failed, we're prepared for that */
  220         /*
  221          * Take one of our spares.  Give up if it's still in use; the only
  222          * message we're likely to get here is a 'drive failed' message,
  223          * and that'll come by again if we miss it.
  224          */
  225         if (intqp->privateinuse)                            /* still in use? */
  226             return;                                         /* yes, give up */
  227         qelt = intqp++;
  228         if (intqp == &intq[INTQSIZE])                       /* got to the end, */
  229             intqp = intq;                                   /* wrap around */
  230         qelt->privateinuse = 1;                             /* it's ours, and it's in use */
  231     } else
  232         qelt->privateinuse = 0;
  233 
  234     qelt->next = NULL;                                      /* end of the chain */
  235     qelt->type = type;
  236     qelt->info = info;
  237     crit_enter();
  238     if (daemonq) {                                          /* something queued already */
  239         dqend->next = qelt;
  240         dqend = qelt;
  241     } else {                                                /* queue is empty, */
  242         daemonq = qelt;                                     /* this is the whole queue */
  243         dqend = qelt;
  244     }
  245     crit_exit();
  246     wakeup(&vinum_daemon);                                  /* and give the dæmon a kick */
  247 }
  248 
  249 /*
  250  * see if the daemon is running.  Return 0 (no error)
  251  * if it is, ESRCH otherwise
  252  */
  253 int
  254 vinum_finddaemon(void)
  255 {
  256     union daemoninfo di = { .nothing = 0 };
  257     int result;
  258 
  259     if (daemonpid != 0) {                                   /* we think we have a daemon, */
  260         queue_daemon_request(daemonrq_ping, di);            /* queue a ping */
  261         result = tsleep(&vinum_finddaemon, 0, "reap", 2 * hz);
  262         if (result == 0)                                    /* yup, the daemon's up and running */
  263             return 0;
  264     }
  265     /* no daemon, or we couldn't talk to it: start it */
  266     vinum_daemon();                                         /* start the daemon */
  267     return 0;
  268 }
  269 
  270 int
  271 vinum_setdaemonopts(int options)
  272 {
  273     daemon_options = options;
  274     return 0;
  275 }

Cache object: ca812838fd5cf0003c34738122777c6a


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