root/dev/raidframe/rf_cvscan.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rf_CheckCvscanState
  2. rf_PriorityInsert
  3. rf_ReqInsert
  4. rf_ReqDequeue
  5. rf_ReBalance
  6. rf_Transfer
  7. rf_RealEnqueue
  8. rf_CvscanEnqueue
  9. rf_CvscanDequeue
  10. rf_CvscanPeek
  11. rf_CvscanConfigure
  12. rf_CvscanCreate
  13. rf_PrintCvscanQueue
  14. rf_CvscanPromote

    1 /*      $OpenBSD: rf_cvscan.c,v 1.5 2002/12/16 07:01:03 tdeval Exp $    */
    2 /*      $NetBSD: rf_cvscan.c,v 1.5 1999/08/13 03:41:53 oster Exp $      */
    3 
    4 /*
    5  * Copyright (c) 1995 Carnegie-Mellon University.
    6  * All rights reserved.
    7  *
    8  * Author: Mark Holland
    9  *
   10  * Permission to use, copy, modify and distribute this software and
   11  * its documentation is hereby granted, provided that both the copyright
   12  * notice and this permission notice appear in all copies of the
   13  * software, derivative works or modified versions, and any portions
   14  * thereof, and that both notices appear in supporting documentation.
   15  *
   16  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   17  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
   18  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   19  *
   20  * Carnegie Mellon requests users of this software to return to
   21  *
   22  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   23  *  School of Computer Science
   24  *  Carnegie Mellon University
   25  *  Pittsburgh PA 15213-3890
   26  *
   27  * any improvements or extensions that they make and grant Carnegie the
   28  * rights to redistribute these changes.
   29  */
   30 
   31 /*****************************************************************************
   32  *
   33  * cvscan.c --  prioritized cvscan disk queueing code.
   34  *
   35  * Nov 9, 1994, adapted from raidSim version (MCH)
   36  *
   37  *****************************************************************************/
   38 
   39 #include "rf_types.h"
   40 #include "rf_alloclist.h"
   41 #include "rf_stripelocks.h"
   42 #include "rf_layout.h"
   43 #include "rf_diskqueue.h"
   44 #include "rf_cvscan.h"
   45 #include "rf_debugMem.h"
   46 #include "rf_general.h"
   47 
   48 void rf_CheckCvscanState(RF_CvscanHeader_t *, char *, int);
   49 void rf_PriorityInsert(RF_DiskQueueData_t **, RF_DiskQueueData_t *);
   50 void rf_ReqInsert(RF_DiskQueueData_t **, RF_DiskQueueData_t *,
   51         RF_CvscanArmDir_t);
   52 RF_DiskQueueData_t *rf_ReqDequeue(RF_DiskQueueData_t **);
   53 void rf_ReBalance(RF_CvscanHeader_t *);
   54 void rf_Transfer(RF_DiskQueueData_t **, RF_DiskQueueData_t **);
   55 void rf_RealEnqueue(RF_CvscanHeader_t *, RF_DiskQueueData_t *);
   56 
   57 #define DO_CHECK_STATE(_hdr_)   rf_CheckCvscanState((_hdr_), __FILE__, __LINE__)
   58 
   59 #define pri_ok(p)       (((p) == RF_IO_NORMAL_PRIORITY) ||              \
   60                          ((p) == RF_IO_LOW_PRIORITY))
   61 
   62 
   63 void
   64 rf_CheckCvscanState(RF_CvscanHeader_t *hdr, char *file, int line)
   65 {
   66         long i, key;
   67         RF_DiskQueueData_t *tmp;
   68 
   69         if (hdr->left != (RF_DiskQueueData_t *) NULL)
   70                 RF_ASSERT(hdr->left->sectorOffset < hdr->cur_block);
   71         for (key = hdr->cur_block, i = 0, tmp = hdr->left;
   72              tmp != (RF_DiskQueueData_t *) NULL;
   73              key = tmp->sectorOffset, i++, tmp = tmp->next)
   74                 RF_ASSERT(tmp->sectorOffset <= key
   75                     && tmp->priority == hdr->nxt_priority && 
   76                     pri_ok(tmp->priority));
   77         RF_ASSERT(i == hdr->left_cnt);
   78 
   79         for (key = hdr->cur_block, i = 0, tmp = hdr->right;
   80              tmp != (RF_DiskQueueData_t *) NULL;
   81              key = tmp->sectorOffset, i++, tmp = tmp->next) {
   82                 RF_ASSERT(key <= tmp->sectorOffset);
   83                 RF_ASSERT(tmp->priority == hdr->nxt_priority);
   84                 RF_ASSERT(pri_ok(tmp->priority));
   85         }
   86         RF_ASSERT(i == hdr->right_cnt);
   87 
   88         for (key = hdr->nxt_priority - 1, tmp = hdr->burner;
   89              tmp != (RF_DiskQueueData_t *) NULL;
   90              key = tmp->priority, tmp = tmp->next) {
   91                 RF_ASSERT(tmp);
   92                 RF_ASSERT(hdr);
   93                 RF_ASSERT(pri_ok(tmp->priority));
   94                 RF_ASSERT(key >= tmp->priority);
   95                 RF_ASSERT(tmp->priority < hdr->nxt_priority);
   96         }
   97 }
   98 
   99 
  100 void
  101 rf_PriorityInsert(RF_DiskQueueData_t **list_ptr, RF_DiskQueueData_t *req)
  102 {
  103         /*
  104          * Insert block pointed to by req into list whose first entry is
  105          * pointed to by the pointer that list_ptr points to.
  106          * i.e. list_ptr is a grandparent of the first entry.
  107          */
  108 
  109         for (; (*list_ptr) != (RF_DiskQueueData_t *) NULL &&
  110                (*list_ptr)->priority > req->priority;
  111              list_ptr = &((*list_ptr)->next)) {
  112         }
  113         req->next = (*list_ptr);
  114         (*list_ptr) = req;
  115 }
  116 
  117 
  118 void
  119 rf_ReqInsert(RF_DiskQueueData_t **list_ptr, RF_DiskQueueData_t *req,
  120     RF_CvscanArmDir_t order)
  121 {
  122         /*
  123          * Insert block pointed to by req into list whose first entry is
  124          * pointed to by the pointer that list_ptr points to.
  125          * i.e. list_ptr is a grandparent of the first entry.
  126          */
  127 
  128         for (; (*list_ptr) != (RF_DiskQueueData_t *) NULL &&
  129                ((order == rf_cvscan_RIGHT && (*list_ptr)->sectorOffset <=
  130                req->sectorOffset) || (order == rf_cvscan_LEFT &&
  131                (*list_ptr)->sectorOffset > req->sectorOffset));
  132              list_ptr = &((*list_ptr)->next)) {
  133         }
  134         req->next = (*list_ptr);
  135         (*list_ptr) = req;
  136 }
  137 
  138 
  139 RF_DiskQueueData_t *
  140 rf_ReqDequeue(RF_DiskQueueData_t **list_ptr)
  141 {
  142         RF_DiskQueueData_t *ret = (*list_ptr);
  143         if ((*list_ptr) != (RF_DiskQueueData_t *) NULL) {
  144                 (*list_ptr) = (*list_ptr)->next;
  145         }
  146         return (ret);
  147 }
  148 
  149 
  150 void
  151 rf_ReBalance(RF_CvscanHeader_t *hdr)
  152 {
  153         /* DO_CHECK_STATE(hdr); */
  154         while (hdr->right != (RF_DiskQueueData_t *) NULL
  155             && hdr->right->sectorOffset < hdr->cur_block) {
  156                 hdr->right_cnt--;
  157                 hdr->left_cnt++;
  158                 rf_ReqInsert(&hdr->left, rf_ReqDequeue(&hdr->right),
  159                     rf_cvscan_LEFT);
  160         }
  161         /* DO_CHECK_STATE(hdr); */
  162 }
  163 
  164 
  165 void
  166 rf_Transfer(RF_DiskQueueData_t **to_list_ptr, RF_DiskQueueData_t **from_list_ptr)
  167 {
  168         RF_DiskQueueData_t *gp;
  169         for (gp = (*from_list_ptr); gp != (RF_DiskQueueData_t *) NULL;) {
  170                 RF_DiskQueueData_t *p = gp->next;
  171                 rf_PriorityInsert(to_list_ptr, gp);
  172                 gp = p;
  173         }
  174         (*from_list_ptr) = (RF_DiskQueueData_t *) NULL;
  175 }
  176 
  177 
  178 void
  179 rf_RealEnqueue(RF_CvscanHeader_t *hdr, RF_DiskQueueData_t *req)
  180 {
  181         RF_ASSERT(req->priority == RF_IO_NORMAL_PRIORITY ||
  182             req->priority == RF_IO_LOW_PRIORITY);
  183 
  184         DO_CHECK_STATE(hdr);
  185         if (hdr->left_cnt == 0 && hdr->right_cnt == 0) {
  186                 hdr->nxt_priority = req->priority;
  187         }
  188         if (req->priority > hdr->nxt_priority) {
  189                 /*
  190                  * Dump all other outstanding requests on the back burner.
  191                  */
  192                 rf_Transfer(&hdr->burner, &hdr->left);
  193                 rf_Transfer(&hdr->burner, &hdr->right);
  194                 hdr->left_cnt = 0;
  195                 hdr->right_cnt = 0;
  196                 hdr->nxt_priority = req->priority;
  197         }
  198         if (req->priority < hdr->nxt_priority) {
  199                 /*
  200                  * Yet another low priority task !
  201                  */
  202                 rf_PriorityInsert(&hdr->burner, req);
  203         } else {
  204                 if (req->sectorOffset < hdr->cur_block) {
  205                         /* This request is to the left of the current arms. */
  206                         rf_ReqInsert(&hdr->left, req, rf_cvscan_LEFT);
  207                         hdr->left_cnt++;
  208                 } else {
  209                         /* This request is to the right of the current arms. */
  210                         rf_ReqInsert(&hdr->right, req, rf_cvscan_RIGHT);
  211                         hdr->right_cnt++;
  212                 }
  213         }
  214         DO_CHECK_STATE(hdr);
  215 }
  216 
  217 
  218 void
  219 rf_CvscanEnqueue(void *q_in, RF_DiskQueueData_t *elem, int priority)
  220 {
  221         RF_CvscanHeader_t *hdr = (RF_CvscanHeader_t *) q_in;
  222         rf_RealEnqueue(hdr, elem /* req */ );
  223 }
  224 
  225 
  226 RF_DiskQueueData_t *
  227 rf_CvscanDequeue(void *q_in)
  228 {
  229         RF_CvscanHeader_t *hdr = (RF_CvscanHeader_t *) q_in;
  230         long    range, i, sum_dist_left, sum_dist_right;
  231         RF_DiskQueueData_t *ret;
  232         RF_DiskQueueData_t *tmp;
  233 
  234         DO_CHECK_STATE(hdr);
  235 
  236         if (hdr->left_cnt == 0 && hdr->right_cnt == 0)
  237                 return ((RF_DiskQueueData_t *) NULL);
  238 
  239         range = RF_MIN(hdr->range_for_avg, RF_MIN(hdr->left_cnt,
  240             hdr->right_cnt));
  241         for (i = 0, tmp = hdr->left, sum_dist_left =
  242              ((hdr->direction == rf_cvscan_RIGHT) ?
  243               range * hdr->change_penalty : 0);
  244              tmp != (RF_DiskQueueData_t *) NULL && i < range;
  245              tmp = tmp->next, i++) {
  246                 sum_dist_left += hdr->cur_block - tmp->sectorOffset;
  247         }
  248         for (i = 0, tmp = hdr->right, sum_dist_right =
  249              ((hdr->direction == rf_cvscan_LEFT) ?
  250               range * hdr->change_penalty : 0);
  251              tmp != (RF_DiskQueueData_t *) NULL && i < range;
  252              tmp = tmp->next, i++) {
  253                 sum_dist_right += tmp->sectorOffset - hdr->cur_block;
  254         }
  255 
  256         if (hdr->right_cnt == 0 || sum_dist_left < sum_dist_right) {
  257                 hdr->direction = rf_cvscan_LEFT;
  258                 hdr->cur_block = hdr->left->sectorOffset + hdr->left->numSector;
  259                 hdr->left_cnt = RF_MAX(hdr->left_cnt - 1, 0);
  260                 tmp = hdr->left;
  261                 ret = (rf_ReqDequeue(&hdr->left)) /*->parent*/ ;
  262         } else {
  263                 hdr->direction = rf_cvscan_RIGHT;
  264                 hdr->cur_block = hdr->right->sectorOffset +
  265                     hdr->right->numSector;
  266                 hdr->right_cnt = RF_MAX(hdr->right_cnt - 1, 0);
  267                 tmp = hdr->right;
  268                 ret = (rf_ReqDequeue(&hdr->right)) /*->parent*/ ;
  269         }
  270         rf_ReBalance(hdr);
  271 
  272         if (hdr->left_cnt == 0 && hdr->right_cnt == 0
  273             && hdr->burner != (RF_DiskQueueData_t *) NULL) {
  274                 /*
  275                  * Restore low priority requests for next dequeue.
  276                  */
  277                 RF_DiskQueueData_t *burner = hdr->burner;
  278                 hdr->nxt_priority = burner->priority;
  279                 while (burner != (RF_DiskQueueData_t *) NULL &&
  280                     burner->priority == hdr->nxt_priority) {
  281                         RF_DiskQueueData_t *next = burner->next;
  282                         rf_RealEnqueue(hdr, burner);
  283                         burner = next;
  284                 }
  285                 hdr->burner = burner;
  286         }
  287         DO_CHECK_STATE(hdr);
  288         return (ret);
  289 }
  290 
  291 
  292 RF_DiskQueueData_t *
  293 rf_CvscanPeek(void *q_in)
  294 {
  295         RF_CvscanHeader_t *hdr = (RF_CvscanHeader_t *) q_in;
  296         long    range, i, sum_dist_left, sum_dist_right;
  297         RF_DiskQueueData_t *tmp, *headElement;
  298 
  299         DO_CHECK_STATE(hdr);
  300 
  301         if (hdr->left_cnt == 0 && hdr->right_cnt == 0)
  302                 headElement = NULL;
  303         else {
  304                 range = RF_MIN(hdr->range_for_avg, RF_MIN(hdr->left_cnt,
  305                     hdr->right_cnt));
  306                 for (i = 0, tmp = hdr->left, sum_dist_left =
  307                      ((hdr->direction == rf_cvscan_RIGHT) ?
  308                       range * hdr->change_penalty : 0);
  309                      tmp != (RF_DiskQueueData_t *) NULL && i < range;
  310                      tmp = tmp->next, i++) {
  311                         sum_dist_left += hdr->cur_block - tmp->sectorOffset;
  312                 }
  313                 for (i = 0, tmp = hdr->right, sum_dist_right =
  314                      ((hdr->direction == rf_cvscan_LEFT) ?
  315                       range * hdr->change_penalty : 0);
  316                      tmp != (RF_DiskQueueData_t *) NULL && i < range;
  317                      tmp = tmp->next, i++) {
  318                         sum_dist_right += tmp->sectorOffset - hdr->cur_block;
  319                 }
  320 
  321                 if (hdr->right_cnt == 0 || sum_dist_left < sum_dist_right)
  322                         headElement = hdr->left;
  323                 else
  324                         headElement = hdr->right;
  325         }
  326         return (headElement);
  327 }
  328 
  329 
  330 /*
  331  * CVSCAN( 1, 0 ) is Shortest Seek Time First (SSTF)
  332  *                              lowest average response time
  333  * CVSCAN( 1, infinity ) is SCAN
  334  *                              lowest response time standard deviation
  335  */
  336 
  337 
  338 int
  339 rf_CvscanConfigure(void)
  340 {
  341         return (0);
  342 }
  343 
  344 
  345 void   *
  346 rf_CvscanCreate(RF_SectorCount_t sectPerDisk, RF_AllocListElem_t *clList,
  347     RF_ShutdownList_t **listp)
  348 {
  349         RF_CvscanHeader_t *hdr;
  350         long range = 2;         /* Currently no mechanism to change these. */
  351         long penalty = sectPerDisk / 5;
  352 
  353         RF_MallocAndAdd(hdr, sizeof(RF_CvscanHeader_t), (RF_CvscanHeader_t *),
  354             clList);
  355         bzero((char *) hdr, sizeof(RF_CvscanHeader_t));
  356         hdr->range_for_avg = RF_MAX(range, 1);
  357         hdr->change_penalty = RF_MAX(penalty, 0);
  358         hdr->direction = rf_cvscan_RIGHT;
  359         hdr->cur_block = 0;
  360         hdr->left_cnt = hdr->right_cnt = 0;
  361         hdr->left = hdr->right = (RF_DiskQueueData_t *) NULL;
  362         hdr->burner = (RF_DiskQueueData_t *) NULL;
  363         DO_CHECK_STATE(hdr);
  364 
  365         return ((void *) hdr);
  366 }
  367 
  368 
  369 #if (defined(__NetBSD__) || defined(__OpenBSD__)) && defined(_KERNEL)
  370 /* rf_PrintCvscanQueue is not used, so we ignore it... */
  371 #else
  372 void
  373 rf_PrintCvscanQueue(RF_CvscanHeader_t *hdr)
  374 {
  375         RF_DiskQueueData_t *tmp;
  376 
  377         printf("CVSCAN(%d,%d) at %d going %s\n",
  378             (int) hdr->range_for_avg,
  379             (int) hdr->change_penalty,
  380             (int) hdr->cur_block,
  381             (hdr->direction == rf_cvscan_LEFT) ? "LEFT" : "RIGHT");
  382         printf("\tLeft(%d): ", hdr->left_cnt);
  383         for (tmp = hdr->left; tmp != (RF_DiskQueueData_t *) NULL;
  384              tmp = tmp->next)
  385                 printf("(%d,%ld,%d) ",
  386                     (int) tmp->sectorOffset,
  387                     (long) (tmp->sectorOffset + tmp->numSector),
  388                     tmp->priority);
  389         printf("\n");
  390         printf("\tRight(%d): ", hdr->right_cnt);
  391         for (tmp = hdr->right; tmp != (RF_DiskQueueData_t *) NULL;
  392              tmp = tmp->next)
  393                 printf("(%d,%ld,%d) ",
  394                     (int) tmp->sectorOffset,
  395                     (long) (tmp->sectorOffset + tmp->numSector),
  396                     tmp->priority);
  397         printf("\n");
  398         printf("\tBurner: ");
  399         for (tmp = hdr->burner; tmp != (RF_DiskQueueData_t *) NULL;
  400              tmp = tmp->next)
  401                 printf("(%d,%ld,%d) ",
  402                     (int) tmp->sectorOffset,
  403                     (long) (tmp->sectorOffset + tmp->numSector),
  404                     tmp->priority);
  405         printf("\n");
  406 }
  407 #endif
  408 
  409 
  410 /*
  411  * Promote reconstruction accesses for the given stripeID to normal priority.
  412  * Return 1 if an access was found and zero otherwise.
  413  * Normally, we should only have one or zero entries in the burner queue,
  414  * so execution time should be short.
  415  */
  416 int
  417 rf_CvscanPromote(void *q_in, RF_StripeNum_t parityStripeID,
  418     RF_ReconUnitNum_t which_ru)
  419 {
  420         RF_CvscanHeader_t *hdr = (RF_CvscanHeader_t *) q_in;
  421         RF_DiskQueueData_t *trailer = NULL, *tmp = hdr->burner, *tlist = NULL;
  422         int retval = 0;
  423 
  424         DO_CHECK_STATE(hdr);
  425         while (tmp) {           /* Handle entries at the front of the list. */
  426                 if (tmp->parityStripeID == parityStripeID &&
  427                     tmp->which_ru == which_ru) {
  428                         hdr->burner = tmp->next;
  429                         tmp->priority = RF_IO_NORMAL_PRIORITY;
  430                         tmp->next = tlist;
  431                         tlist = tmp;
  432                         tmp = hdr->burner;
  433                 } else
  434                         break;
  435         }
  436         if (tmp) {
  437                 trailer = tmp;
  438                 tmp = tmp->next;
  439         }
  440         while (tmp) {           /* Handle entries on the rest of the list. */
  441                 if (tmp->parityStripeID == parityStripeID &&
  442                     tmp->which_ru == which_ru) {
  443                         trailer->next = tmp->next;
  444                         tmp->priority = RF_IO_NORMAL_PRIORITY;
  445                         tmp->next = tlist;
  446                         tlist = tmp;    /* Insert on a temp queue. */
  447                         tmp = trailer->next;
  448                 } else {
  449                         trailer = tmp;
  450                         tmp = tmp->next;
  451                 }
  452         }
  453         while (tlist) {
  454                 retval++;
  455                 tmp = tlist->next;
  456                 rf_RealEnqueue(hdr, tlist);
  457                 tlist = tmp;
  458         }
  459         RF_ASSERT(retval == 0 || retval == 1);
  460         DO_CHECK_STATE((RF_CvscanHeader_t *) q_in);
  461         return (retval);
  462 }

/* [<][>][^][v][top][bottom][index][help] */