source: rtems/cpukit/libblock/src/bdbuf.c @ 8b96149

4.104.114.84.95
Last change on this file since 8b96149 was 8b96149, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/17/04 at 08:15:17

Remove stray white spaces.

  • Property mode set to 100644
File size: 45.1 KB
RevLine 
[e51bd96]1/*
2 * Disk I/O buffering
3 * Buffer managment
4 *
5 * Copyright (C) 2001 OKTET Ltd., St.-Peterburg, Russia
6 * Author: Andrey G. Ivanov <Andrey.Ivanov@oktet.ru>
7 *         Victor V. Vengerov <vvv@oktet.ru>
[df6348bb]8 *         Alexander Kukuta <kam@oktet.ru>
[e51bd96]9 *
10 * @(#) $Id$
11 */
12
[006fa1ef]13#if HAVE_CONFIG_H
14#include "config.h"
15#endif
16
[e51bd96]17#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__
18#include <rtems.h>
19#include <limits.h>
20#include <errno.h>
21#include <assert.h>
22
23#include "rtems/bdbuf.h"
24
25/* Fatal errors: */
[c01d95b7]26#define BLKDEV_FATAL_ERROR(n) (((uint32_t)'B' << 24) | ((uint32_t)(n) & (uint32_t)0x00FFFFFF))
[e51bd96]27#define BLKDEV_FATAL_BDBUF_CONSISTENCY BLKDEV_FATAL_ERROR(1)
28#define BLKDEV_FATAL_BDBUF_SWAPOUT     BLKDEV_FATAL_ERROR(2)
29
30
31#define SWAPOUT_PRIORITY 15
32#define SWAPOUT_STACK_SIZE (RTEMS_MINIMUM_STACK_SIZE * 2)
33
34static rtems_task bdbuf_swapout_task(rtems_task_argument unused);
35
36/*
37 * The groups of the blocks with the same size are collected in the
38 * bd_pool. Note that a several of the buffer's groups with the
39 * same size can exists.
40 */
41typedef struct bdbuf_pool
42{
43    bdbuf_buffer *tree;         /* Buffer descriptor lookup AVL tree root */
44
45    Chain_Control free;         /* Free buffers list */
46    Chain_Control lru;          /* Last recently used list */
47
48    int           blksize;      /* The size of the blocks (in bytes) */
49    int           nblks;        /* Number of blocks in this pool */
50    rtems_id      bufget_sema;  /* Buffer obtain counting semaphore */
51    void         *mallocd_bufs; /* Pointer to the malloc'd buffer memory,
52                                   or NULL, if buffer memory provided in
53                                   buffer configuration */
54    bdbuf_buffer *bdbufs;       /* Pointer to table of buffer descriptors
55                                   allocated for this buffer pool. */
56} bdbuf_pool;
57
58/* Buffering layer context definition */
59struct bdbuf_context {
60    bdbuf_pool    *pool;         /* Table of buffer pools */
61    int            npools;       /* Number of entries in pool table */
[048dcd2b]62
[e51bd96]63    Chain_Control  mod;          /* Modified buffers list */
[8b96149]64    rtems_id       flush_sema;   /* Buffer flush semaphore; counting
[e51bd96]65                                    semaphore; incremented when buffer
[8b96149]66                                    flushed to the disk; decremented when
[e51bd96]67                                    buffer modified */
68    rtems_id       swapout_task; /* Swapout task ID */
69};
70
71/* Block device request with a single buffer provided */
72typedef struct blkdev_request1 {
73    blkdev_request   req;
74    blkdev_sg_buffer sg[1];
75} blkdev_request1;
76
77/* The static context of buffering layer */
78static struct bdbuf_context bd_ctx;
79
80#define SAFE
81#ifdef SAFE
82typedef rtems_mode preemption_key;
83
84#define DISABLE_PREEMPTION(key) \
85    do {                                                               \
[828be6d]86        rtems_task_mode(RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &(key)); \
[e51bd96]87    } while (0)
88
89#define ENABLE_PREEMPTION(key) \
90    do {                                                        \
91        rtems_mode temp;                                        \
[828be6d]92        rtems_task_mode((key), RTEMS_PREEMPT_MASK, &temp);      \
[e51bd96]93    } while (0)
94
95#else
[048dcd2b]96
[e51bd96]97typedef boolean preemption_key;
98
99#define DISABLE_PREEMPTION(key) \
100    do {                                             \
101        (key) = _Thread_Executing->is_preemptible;   \
102        _Thread_Executing->is_preemptible = 0;       \
103    } while (0)
[048dcd2b]104
[e51bd96]105#define ENABLE_PREEMPTION(key) \
106    do {                                             \
107        _Thread_Executing->is_preemptible = (key);   \
108        if (_Thread_Evaluate_mode())                 \
109            _Thread_Dispatch();                      \
110    } while (0)
111
112#endif
113
114
115/* The default maximum height of 32 allows for AVL trees having
116   between 5,704,880 and 4,294,967,295 nodes, depending on order of
117   insertion.  You may change this compile-time constant as you
118   wish. */
119#ifndef AVL_MAX_HEIGHT
120#define AVL_MAX_HEIGHT  32
121#endif
122
123/*
124 * avl_search --
125 *     Searches for the node with specified dev/block.
126 *
127 * PARAMETERS:
128 *     root - pointer to the root node of the AVL-Tree.
129 *     dev, block - search key
130 *
131 * RETURNS:
132 *     NULL if node with specified dev/block not found
133 *     non-NULL - pointer to the node with specified dev/block
134 */
135static bdbuf_buffer *
136avl_search(bdbuf_buffer **root, dev_t dev, blkdev_bnum block)
137{
138    bdbuf_buffer *p = *root;
[df6348bb]139
[e51bd96]140    while ((p != NULL) && ((p->dev != dev) || (p->block != block)))
141    {
142        if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
[df6348bb]143        {
144            p = p->avl.right;
145        }
[e51bd96]146        else
[df6348bb]147        {
148            p = p->avl.left;
149        }
[e51bd96]150    }
[048dcd2b]151
[e51bd96]152    return p;
153}
154
[df6348bb]155
[e51bd96]156/* avl_search_for_sync --
157 *     Search in AVL tree for first modified buffer belongs to specified
158 *     disk device.
159 *
160 * PARAMETERS:
161 *     root - pointer to tree root
162 *     dd - disk device descriptor
163 *
164 * RETURNS:
165 *     Block buffer, or NULL if no modified blocks on specified device
166 *     exists.
167 */
168static bdbuf_buffer *
169avl_search_for_sync(bdbuf_buffer **root, disk_device *dd)
170{
171    dev_t dev = dd->phys_dev->dev;
[df6348bb]172    blkdev_bnum block_start = dd->start;
173    blkdev_bnum block_end = dd->start + dd->size - 1;
174
175    bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT];
176    bdbuf_buffer **buf_prev = buf_stack;
177    bdbuf_buffer *p = *root;
178
[e51bd96]179    while (p != NULL)
180    {
[df6348bb]181        if ((p->dev < dev) || ((p->dev == dev) && (p->block < block_start)))
182        {
183            p = p->avl.right;
184        }
185        else if ((p->dev > dev) || ((p->dev == dev) && (p->block > block_end)))
186        {
187            p = p->avl.left;
188        }
[e51bd96]189        else if (p->modified)
[df6348bb]190        {
[e51bd96]191            return p;
[df6348bb]192        }
[e51bd96]193        else
194        {
[df6348bb]195            if (p->avl.right != NULL)
196            {
197                *buf_prev++ = p->avl.right;
198            }
199            p = p->avl.left;
200        }
201
202        if ((p == NULL) && (buf_prev > buf_stack))
203        {
204            p = *--buf_prev;
[e51bd96]205        }
206    }
[df6348bb]207
[e51bd96]208    return p;
209}
210
211
212/*
213 * avl_insert --
214 *     Inserts the specified node to the AVl-Tree.
215 *
216 * PARAMETERS:
[df6348bb]217 *     root - Pointer to pointer to the root node
[e51bd96]218 *     node - Pointer to the node to add.
219 *
220 * RETURNS:
221 *     0 - The node added successfully
222 *    -1 - An error occured
223 */
224static int
[df6348bb]225avl_insert(bdbuf_buffer **root, bdbuf_buffer *node)
[e51bd96]226{
[df6348bb]227    dev_t dev = node->dev;
228    blkdev_bnum block = node->block;
[e51bd96]229
[df6348bb]230    bdbuf_buffer *p = *root;
[120b59e]231    bdbuf_buffer *q = NULL;
232    bdbuf_buffer *p1, *p2;
[df6348bb]233    bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT];
234    bdbuf_buffer **buf_prev = buf_stack;
[e51bd96]235
[df6348bb]236    boolean modified = FALSE;
[e51bd96]237
[df6348bb]238    if (p == NULL)
[e51bd96]239    {
[df6348bb]240        *root = node;
241        node->avl.left = NULL;
242        node->avl.right = NULL;
243        node->avl.bal = 0;
[e51bd96]244        return 0;
245    }
246
[df6348bb]247    while (p != NULL)
[e51bd96]248    {
[df6348bb]249        *buf_prev++ = p;
[e51bd96]250
[df6348bb]251        if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
[e51bd96]252        {
[df6348bb]253            p->avl.cache = 1;
254            q = p->avl.right;
[e51bd96]255            if (q == NULL)
256            {
[df6348bb]257                q = node;
258                p->avl.right = q = node;
[e51bd96]259                break;
260            }
261        }
[df6348bb]262        else if ((p->dev != dev) || (p->block != block))
263        {
264            p->avl.cache = -1;
265            q = p->avl.left;
266            if (q == NULL)
[e51bd96]267            {
[df6348bb]268                q = node;
269                p->avl.left = q;
270                break;
[e51bd96]271            }
[df6348bb]272        }
273        else
[e51bd96]274        {
[df6348bb]275            return -1;
[e51bd96]276        }
[df6348bb]277
[e51bd96]278        p = q;
279    }
280
[df6348bb]281    q->avl.left = q->avl.right = NULL;
282    q->avl.bal = 0;
283    modified = TRUE;
284    buf_prev--;
[e51bd96]285
[df6348bb]286    while (modified)
[e51bd96]287    {
[df6348bb]288        if (p->avl.cache == -1)
[e51bd96]289        {
[df6348bb]290            switch (p->avl.bal)
291            {
292                case 1:
293                    p->avl.bal = 0;
294                    modified = FALSE;
295                    break;
296
297                case 0:
298                    p->avl.bal = -1;
299                    break;
300
301                case -1:
302                    p1 = p->avl.left;
303                    if (p1->avl.bal == -1) /* simple LL-turn */
304                    {
305                        p->avl.left = p1->avl.right;
306                        p1->avl.right = p;
307                        p->avl.bal = 0;
308                        p = p1;
309                    }
310                    else /* double LR-turn */
311                    {
312                        p2 = p1->avl.right;
313                        p1->avl.right = p2->avl.left;
314                        p2->avl.left = p1;
315                        p->avl.left = p2->avl.right;
316                        p2->avl.right = p;
317                        if (p2->avl.bal == -1) p->avl.bal = +1; else p->avl.bal = 0;
318                        if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0;
319                        p = p2;
320                    }
321                    p->avl.bal = 0;
322                    modified = FALSE;
323                    break;
324
325                default:
326                    break;
327            }
[e51bd96]328        }
329        else
330        {
[df6348bb]331            switch (p->avl.bal)
[e51bd96]332            {
[df6348bb]333                case -1:
334                    p->avl.bal = 0;
335                    modified = FALSE;
336                    break;
337
338                case 0:
339                    p->avl.bal = 1;
340                    break;
341
342                case 1:
343                    p1 = p->avl.right;
344                    if (p1->avl.bal == 1) /* simple RR-turn */
345                    {
346                        p->avl.right = p1->avl.left;
347                        p1->avl.left = p;
348                        p->avl.bal = 0;
349                        p = p1;
350                    }
351                    else /* double RL-turn */
352                    {
353                        p2 = p1->avl.left;
354                        p1->avl.left = p2->avl.right;
355                        p2->avl.right = p1;
356                        p->avl.right = p2->avl.left;
357                        p2->avl.left = p;
358                        if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0;
359                        if (p2->avl.bal == -1) p1->avl.bal = +1; else p1->avl.bal = 0;
360                        p = p2;
361                    }
362                    p->avl.bal = 0;
363                    modified = FALSE;
364                    break;
365
366                default:
367                    break;
[e51bd96]368            }
369        }
[df6348bb]370        q = p;
371        if (buf_prev > buf_stack)
[e51bd96]372        {
[df6348bb]373            p = *--buf_prev;
[e51bd96]374
[df6348bb]375            if (p->avl.cache == -1)
[e51bd96]376            {
[df6348bb]377                p->avl.left = q;
[e51bd96]378            }
[df6348bb]379            else
[e51bd96]380            {
[df6348bb]381                p->avl.right = q;
[e51bd96]382            }
383        }
384        else
[df6348bb]385        {
386            *root = p;
387            break;
388        }
389    };
[e51bd96]390
391    return 0;
392}
393
394
395/* avl_remove --
396 *     removes the node from the tree.
397 *
398 * PARAMETERS:
399 *     root_addr - Pointer to pointer to the root node
400 *     node      - Pointer to the node to remove
401 *
402 * RETURNS:
403 *     0 - Item removed
404 *    -1 - No such item found
405 */
406static int
[df6348bb]407avl_remove(bdbuf_buffer **root, const bdbuf_buffer *node)
[e51bd96]408{
[df6348bb]409    dev_t dev = node->dev;
410    blkdev_bnum block = node->block;
[e51bd96]411
[df6348bb]412    bdbuf_buffer *p = *root;
413    bdbuf_buffer *q, *r, *s, *p1, *p2;
414    bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT];
415    bdbuf_buffer **buf_prev = buf_stack;
[e51bd96]416
[df6348bb]417    boolean modified = FALSE;
[e51bd96]418
[df6348bb]419    memset(buf_stack, 0, sizeof(buf_stack));
[e51bd96]420
[df6348bb]421    while (p != NULL)
[e51bd96]422    {
[df6348bb]423        *buf_prev++ = p;
[e51bd96]424
[df6348bb]425        if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
426        {
427            p->avl.cache = 1;
428            p = p->avl.right;
429        }
430        else if ((p->dev != dev) || (p->block != block))
[e51bd96]431        {
[df6348bb]432            p->avl.cache = -1;
433            p = p->avl.left;
[e51bd96]434        }
[df6348bb]435        else
[e51bd96]436        {
[df6348bb]437            /* node found */
438            break;
[e51bd96]439        }
[df6348bb]440    }
[048dcd2b]441
[df6348bb]442    if (p == NULL)
443    {
444        /* there is no such node */
445        return -1;
[e51bd96]446    }
447
[df6348bb]448    q = p;
449
450    buf_prev--;
451    if (buf_prev > buf_stack)
[e51bd96]452    {
[df6348bb]453        p = *(buf_prev - 1);
[e51bd96]454    }
455    else
456    {
[df6348bb]457        p = NULL;
[e51bd96]458    }
[df6348bb]459
460    /* at this moment q - is a node to delete, p is q's parent */
461    if (q->avl.right == NULL)
[e51bd96]462    {
[df6348bb]463        r = q->avl.left;
464        if (r != NULL)
[8b96149]465        {
[df6348bb]466            r->avl.bal = 0;
467        }
468        q = r;
[e51bd96]469    }
470    else
471    {
[df6348bb]472        bdbuf_buffer **t;
473
474        r = q->avl.right;
475
476        if (r->avl.left == NULL)
[e51bd96]477        {
[df6348bb]478            r->avl.left = q->avl.left;
479            r->avl.bal = q->avl.bal;
480            r->avl.cache = 1;
481            *buf_prev++ = q = r;
[e51bd96]482        }
483        else
484        {
[df6348bb]485            t = buf_prev++;
486            s = r;
[048dcd2b]487
[df6348bb]488            while (s->avl.left != NULL)
[e51bd96]489            {
[df6348bb]490                *buf_prev++ = r = s;
491                s = r->avl.left;
492                r->avl.cache = -1;
[e51bd96]493            }
[048dcd2b]494
[df6348bb]495            s->avl.left = q->avl.left;
496            r->avl.left = s->avl.right;
497            s->avl.right = q->avl.right;
498            s->avl.bal = q->avl.bal;
499            s->avl.cache = 1;
[048dcd2b]500
[df6348bb]501            *t = q = s;
[e51bd96]502        }
503    }
504
[df6348bb]505    if (p != NULL)
[e51bd96]506    {
[df6348bb]507        if (p->avl.cache == -1)
[e51bd96]508        {
[df6348bb]509            p->avl.left = q;
510        }
511        else
512        {
513            p->avl.right = q;
514        }
515    }
516    else
517    {
518        *root = q;
519    }
[e51bd96]520
[df6348bb]521    modified = TRUE;
[e51bd96]522
[df6348bb]523    while (modified)
524    {
525        if (buf_prev > buf_stack)
526        {
527            p = *--buf_prev;
528        }
529        else
530        {
531            break;
532        }
[048dcd2b]533
[df6348bb]534        if (p->avl.cache == -1)
535        {
536            /* rebalance left branch */
537            switch (p->avl.bal)
[e51bd96]538            {
[df6348bb]539                case -1:
[e51bd96]540                    p->avl.bal = 0;
[df6348bb]541                    break;
542                case  0:
543                    p->avl.bal = 1;
544                    modified = FALSE;
545                    break;
546
547                case +1:
548                    p1 = p->avl.right;
549
550                    if (p1->avl.bal >= 0) /* simple RR-turn */
[e51bd96]551                    {
[df6348bb]552                        p->avl.right = p1->avl.left;
553                        p1->avl.left = p;
554
555                        if (p1->avl.bal == 0)
556                        {
557                            p1->avl.bal = -1;
558                            modified = FALSE;
559                        }
560                        else
561                        {
562                            p->avl.bal = 0;
563                            p1->avl.bal = 0;
564                        }
565                        p = p1;
[e51bd96]566                    }
[df6348bb]567                    else /* double RL-turn */
[e51bd96]568                    {
[df6348bb]569                        p2 = p1->avl.left;
570
571                        p1->avl.left = p2->avl.right;
572                        p2->avl.right = p1;
573                        p->avl.right = p2->avl.left;
574                        p2->avl.left = p;
[048dcd2b]575
[df6348bb]576                        if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0;
577                        if (p2->avl.bal == -1) p1->avl.bal = 1; else p1->avl.bal = 0;
[048dcd2b]578
[df6348bb]579                        p = p2;
580                        p2->avl.bal = 0;
[e51bd96]581                    }
[df6348bb]582                    break;
583
584                default:
585                    break;
586            }
[e51bd96]587        }
588        else
589        {
[df6348bb]590            /* rebalance right branch */
591            switch (p->avl.bal)
[e51bd96]592            {
[df6348bb]593                case +1:
594                    p->avl.bal = 0;
[e51bd96]595                    break;
596
[df6348bb]597                case  0:
598                    p->avl.bal = -1;
599                    modified = FALSE;
600                    break;
[e51bd96]601
[df6348bb]602                case -1:
603                    p1 = p->avl.left;
[e51bd96]604
[df6348bb]605                    if (p1->avl.bal <= 0) /* simple LL-turn */
[e51bd96]606                    {
[df6348bb]607                        p->avl.left = p1->avl.right;
608                        p1->avl.right = p;
609                        if (p1->avl.bal == 0)
[e51bd96]610                        {
[df6348bb]611                            p1->avl.bal = 1;
612                            modified = FALSE;
[e51bd96]613                        }
614                        else
615                        {
[df6348bb]616                            p->avl.bal = 0;
617                            p1->avl.bal = 0;
[e51bd96]618                        }
[df6348bb]619                        p = p1;
620                    }
621                    else /* double LR-turn */
622                    {
623                        p2 = p1->avl.right;
624
625                        p1->avl.right = p2->avl.left;
626                        p2->avl.left = p1;
627                        p->avl.left = p2->avl.right;
628                        p2->avl.right = p;
[048dcd2b]629
[df6348bb]630                        if (p2->avl.bal == -1) p->avl.bal = 1; else p->avl.bal = 0;
631                        if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0;
632
633                        p = p2;
634                        p2->avl.bal = 0;
[e51bd96]635                    }
[df6348bb]636                    break;
637
638                default:
639                    break;
640            }
[e51bd96]641        }
642
[df6348bb]643        if (buf_prev > buf_stack)
644        {
645            q = *(buf_prev - 1);
[048dcd2b]646
[df6348bb]647            if (q->avl.cache == -1)
648            {
649                q->avl.left = p;
650            }
651            else
652            {
653                q->avl.right = p;
654            }
655        }
656        else
657        {
658            *root = p;
659            break;
660        }
661
662    }
[048dcd2b]663
[e51bd96]664    return 0;
665}
666
667/* bdbuf_initialize_pool --
668 *      Initialize single buffer pool.
669 *
670 * PARAMETERS:
671 *     config - buffer pool configuration
672 *     pool   - pool number
673 *
674 * RETURNS:
675 *     RTEMS_SUCCESSFUL, if buffer pool initialized successfully, or error
676 *     code if error occured.
677 */
678static rtems_status_code
679bdbuf_initialize_pool(rtems_bdbuf_config *config, int pool)
680{
681    bdbuf_pool *p = bd_ctx.pool + pool;
682    unsigned char *bufs;
683    bdbuf_buffer *b;
684    rtems_status_code rc;
685    int i;
[048dcd2b]686
[e51bd96]687    p->blksize = config->size;
688    p->nblks = config->num;
689    p->tree = NULL;
[048dcd2b]690
[e51bd96]691    Chain_Initialize_empty(&p->free);
692    Chain_Initialize_empty(&p->lru);
[048dcd2b]693
[e51bd96]694    /* Allocate memory for buffer descriptors */
695    p->bdbufs = calloc(config->num, sizeof(bdbuf_buffer));
696    if (p->bdbufs == NULL)
697    {
698        return RTEMS_NO_MEMORY;
699    }
[048dcd2b]700
[e51bd96]701    /* Allocate memory for buffers if required */
702    if (config->mem_area == NULL)
703    {
704        bufs = p->mallocd_bufs = malloc(config->num * config->size);
705        if (bufs == NULL)
706        {
707            free(p->bdbufs);
708            return RTEMS_NO_MEMORY;
709        }
710    }
711    else
712    {
713        bufs = config->mem_area;
714        p->mallocd_bufs = NULL;
715    }
[048dcd2b]716
[e51bd96]717    for (i = 0, b = p->bdbufs; i < p->nblks; i++, b++, bufs += p->blksize)
718    {
719        b->dev = -1; b->block = 0;
720        b->buffer = bufs;
721        b->actual = b->modified = b->in_progress = FALSE;
722        b->use_count = 0;
723        b->pool = pool;
724        _Chain_Append(&p->free, &b->link);
725    }
[048dcd2b]726
[e51bd96]727    rc = rtems_semaphore_create(
728        rtems_build_name('B', 'U', 'F', 'G'),
729        p->nblks,
730        RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
731        RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
732        0,
733        &p->bufget_sema);
[048dcd2b]734
[e51bd96]735    if (rc != RTEMS_SUCCESSFUL)
736    {
737        free(p->bdbufs);
738        free(p->mallocd_bufs);
739        return rc;
740    }
[048dcd2b]741
[e51bd96]742    return RTEMS_SUCCESSFUL;
743}
744
745/* bdbuf_release_pool --
746 *     Free resources allocated for buffer pool with specified number.
747 *
748 * PARAMETERS:
749 *     pool - buffer pool number
750 *
751 * RETURNS:
752 *     RTEMS_SUCCESSFUL
753 */
754static rtems_status_code
755bdbuf_release_pool(rtems_bdpool_id pool)
756{
757    bdbuf_pool *p = bd_ctx.pool + pool;
758    rtems_semaphore_delete(p->bufget_sema);
759    free(p->bdbufs);
760    free(p->mallocd_bufs);
761    return RTEMS_SUCCESSFUL;
762}
763
764/* rtems_bdbuf_init --
[8b96149]765 *     Prepare buffering layer to work - initialize buffer descritors
[e51bd96]766 *     and (if it is neccessary)buffers. Buffers will be allocated accoriding
[8b96149]767 *     to the configuration table, each entry describes kind of block and
[e51bd96]768 *     amount requested. After initialization all blocks is placed into
769 *     free elements lists.
770 *
771 * PARAMETERS:
772 *     conf_table - pointer to the buffers configuration table
773 *     size       - number of entries in configuration table
774 *
775 * RETURNS:
776 *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
777 *     or error code if error is occured)
778 */
779rtems_status_code
780rtems_bdbuf_init(rtems_bdbuf_config *conf_table, int size)
781{
782    rtems_bdpool_id i;
783    rtems_status_code rc;
784
785    if (size <= 0)
786        return RTEMS_INVALID_SIZE;
[048dcd2b]787
[e51bd96]788    bd_ctx.npools = size;
789
790    /*
791     * Allocate memory for buffer pool descriptors
792     */
793    bd_ctx.pool = calloc(size, sizeof(bdbuf_pool));
794    if (bd_ctx.pool == NULL)
795    {
796        return RTEMS_NO_MEMORY;
797    }
798
799    Chain_Initialize_empty(&bd_ctx.mod);
[048dcd2b]800
[e51bd96]801    /* Initialize buffer pools and roll out if something failed */
802    for (i = 0; i < size; i++)
803    {
804        rc = bdbuf_initialize_pool(conf_table + i, i);
805        if (rc != RTEMS_SUCCESSFUL)
806        {
807             rtems_bdpool_id j;
808             for (j = 0; j < i - 1; j++)
809             {
810                 bdbuf_release_pool(j);
811             }
812             return rc;
813        }
814    }
815
816    /* Create buffer flush semaphore */
817    rc = rtems_semaphore_create(
818        rtems_build_name('B', 'F', 'L', 'U'), 0,
819        RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
820        RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0,
821        &bd_ctx.flush_sema);
822    if (rc != RTEMS_SUCCESSFUL)
823    {
824        for (i = 0; i < size; i++)
825            bdbuf_release_pool(i);
826        free(bd_ctx.pool);
827        return rc;
828    }
[048dcd2b]829
[e51bd96]830    /* Create and start swapout task */
831    rc = rtems_task_create(
832        rtems_build_name('B', 'S', 'W', 'P'),
833        SWAPOUT_PRIORITY,
[8b96149]834        SWAPOUT_STACK_SIZE,
[e51bd96]835        RTEMS_DEFAULT_MODES | RTEMS_NO_PREEMPT,
836        RTEMS_DEFAULT_ATTRIBUTES,
837        &bd_ctx.swapout_task);
838    if (rc != RTEMS_SUCCESSFUL)
839    {
840        rtems_semaphore_delete(bd_ctx.flush_sema);
841        for (i = 0; i < size; i++)
842            bdbuf_release_pool(i);
843        free(bd_ctx.pool);
844        return rc;
845    }
846
847    rc = rtems_task_start(bd_ctx.swapout_task, bdbuf_swapout_task, 0);
848    if (rc != RTEMS_SUCCESSFUL)
849    {
850        rtems_task_delete(bd_ctx.swapout_task);
851        rtems_semaphore_delete(bd_ctx.flush_sema);
852        for (i = 0; i < size; i++)
853            bdbuf_release_pool(i);
854        free(bd_ctx.pool);
855        return rc;
856    }
857
858    return RTEMS_SUCCESSFUL;
859}
860
861/* find_or_assign_buffer --
862 *     Looks for buffer already assigned for this dev/block. If one is found
863 *     obtain block buffer. If specified block already cached (i.e. there's
864 *     block in the _modified_, or _recently_used_), return address
[8b96149]865 *     of appropriate buffer descriptor and increment reference counter to 1.
866 *     If block is not cached, allocate new buffer and return it. Data
867 *     shouldn't be read to the buffer from media; buffer contains arbitrary
868 *     data. This primitive may be blocked if there are no free buffer
869 *     descriptors available and there are no unused non-modified (or
[e51bd96]870 *     synchronized with media) buffers available.
871 *
872 * PARAMETERS:
873 *     device - device number (constructed of major and minor device number
874 *     block  - linear media block number
875 *     ret_buf - address of the variable to store address of found descriptor
876 *
877 * RETURNS:
878 *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
879 *     or error code if error is occured)
880 *
881 * SIDE EFFEECTS:
882 *     bufget_sema may be obtained by this primitive
883 *
884 * NOTE:
885 *     It is assumed that primitive invoked when thread preemption is disabled.
886 */
887static rtems_status_code
888find_or_assign_buffer(disk_device *dd,
[8b96149]889                      blkdev_bnum block,
[e51bd96]890                      bdbuf_buffer **ret_buf)
891{
892    bdbuf_buffer *bd_buf;
893    bdbuf_pool   *bd_pool;
894    rtems_status_code rc;
895    dev_t         device;
896    ISR_Level     level;
897
898    int blksize;
899
900    device = dd->dev;
901    bd_pool = bd_ctx.pool + dd->pool;
902    blksize = dd->block_size;
903
904again:
905    /* Looking for buffer descriptor used for this dev/block. */
906    bd_buf = avl_search(&bd_pool->tree, device, block);
907
908    if (bd_buf == NULL)
909    {
910        /* Try to obtain semaphore without waiting first. It is the most
[8b96149]911           frequent case when reasonable number of buffers configured. If
912           it is failed, obtain semaphore blocking on it. In this case
913           it should be checked that appropriate buffer hasn't been loaded
[e51bd96]914           by another thread, because this thread is preempted */
915        rc = rtems_semaphore_obtain(bd_pool->bufget_sema, RTEMS_NO_WAIT, 0);
916        if (rc == RTEMS_UNSATISFIED)
917        {
918            rc = rtems_semaphore_obtain(bd_pool->bufget_sema,
919                                        RTEMS_WAIT, RTEMS_NO_TIMEOUT);
920            bd_buf = avl_search(&bd_pool->tree, device, block);
921            if (bd_buf != NULL)
922                rtems_semaphore_release(bd_pool->bufget_sema);
923        }
924    }
[048dcd2b]925
[e51bd96]926    if (bd_buf == NULL)
927    {
928        /* Assign new buffer descriptor */
929        if (_Chain_Is_empty(&bd_pool->free))
930        {
931            bd_buf = (bdbuf_buffer *)Chain_Get(&bd_pool->lru);
932            if (bd_buf != NULL)
933            {
[8b96149]934                int avl_result;
[e51bd96]935                avl_result = avl_remove(&bd_pool->tree, bd_buf);
936                if (avl_result != 0)
937                {
938                    rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);
939                    return RTEMS_INTERNAL_ERROR;
940                }
941            }
942        }
943        else
944        {
945            bd_buf = (bdbuf_buffer *)Chain_Get(&(bd_pool->free));
946        }
947
948        if (bd_buf == NULL)
949        {
950            goto again;
951        }
952        else
953        {
954            bd_buf->dev = device;
955            bd_buf->block = block;
[df6348bb]956#ifdef AVL_GPL
[e51bd96]957            bd_buf->avl.link[0] = NULL;
958            bd_buf->avl.link[1] = NULL;
[df6348bb]959#else
960            bd_buf->avl.left = NULL;
961            bd_buf->avl.right = NULL;
[e51bd96]962#endif
963            bd_buf->use_count = 1;
964            bd_buf->modified = bd_buf->actual = bd_buf->in_progress = FALSE;
965            bd_buf->status = RTEMS_SUCCESSFUL;
966
967            if (avl_insert(&bd_pool->tree, bd_buf) != 0)
968            {
969                rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);
970                return RTEMS_INTERNAL_ERROR;
971            }
972
973            *ret_buf = bd_buf;
974
975            return RTEMS_SUCCESSFUL;
976        }
977    }
978    else
979    {
980        /* Buffer descriptor already assigned for this dev/block */
981        if (bd_buf->use_count == 0)
982        {
983            /* If we are removing from lru list, obtain the bufget_sema
984             * first. If we are removing from mod list, obtain flush sema.
985             * It should be obtained without blocking because we know
986             * that our buffer descriptor is in the list. */
987            if (bd_buf->modified)
988            {
[8b96149]989                rc = rtems_semaphore_obtain(bd_ctx.flush_sema,
[e51bd96]990                                            RTEMS_NO_WAIT, 0);
991            }
992            else
993            {
[8b96149]994                rc = rtems_semaphore_obtain(bd_pool->bufget_sema,
[e51bd96]995                                            RTEMS_NO_WAIT, 0);
996            }
[8b96149]997            /* It is possible that we couldn't obtain flush or bufget sema
[e51bd96]998             * although buffer in the appropriate chain is available:
[8b96149]999             * semaphore may be released to swapout task, but this task
[e51bd96]1000             * actually did not start to process it. */
1001            if (rc == RTEMS_UNSATISFIED)
1002                rc = RTEMS_SUCCESSFUL;
1003            if (rc != RTEMS_SUCCESSFUL)
1004            {
1005                rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);
1006                return RTEMS_INTERNAL_ERROR;
1007            }
1008
1009            /* Buffer descriptor is linked to the lru or mod chain. Remove
1010               it from there. */
1011            Chain_Extract(&bd_buf->link);
1012        }
1013        bd_buf->use_count++;
1014        while (bd_buf->in_progress != 0)
1015        {
[df6348bb]1016            rtems_interrupt_disable(level);
[e51bd96]1017            _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
1018                              WATCHDOG_NO_TIMEOUT, level);
1019        }
[048dcd2b]1020
[e51bd96]1021        *ret_buf = bd_buf;
1022        return RTEMS_SUCCESSFUL;
1023    }
1024}
1025
1026/* rtems_bdbuf_get --
1027 *     Obtain block buffer. If specified block already cached (i.e. there's
1028 *     block in the _modified_, or _recently_used_), return address
[8b96149]1029 *     of appropriate buffer descriptor and increment reference counter to 1.
1030 *     If block is not cached, allocate new buffer and return it. Data
1031 *     shouldn't be read to the buffer from media; buffer may contains
1032 *     arbitrary data. This primitive may be blocked if there are no free
1033 *     buffer descriptors available and there are no unused non-modified
[e51bd96]1034 *     (or synchronized with media) buffers available.
1035 *
1036 * PARAMETERS:
1037 *     device - device number (constructed of major and minor device number)
1038 *     block  - linear media block number
1039 *     bd     - address of variable to store pointer to the buffer descriptor
1040 *
1041 * RETURNS:
1042 *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
1043 *     or error code if error is occured)
1044 *
1045 * SIDE EFFECTS:
1046 *     bufget_sema semaphore obtained by this primitive.
1047 */
1048rtems_status_code
1049rtems_bdbuf_get(dev_t device, blkdev_bnum block, bdbuf_buffer **bd)
1050{
1051    rtems_status_code rc;
1052    disk_device *dd;
1053    disk_device *pdd;
1054    preemption_key key;
1055
1056    /*
1057     * Convert logical dev/block to physical one
1058     */
1059    dd = rtems_disk_lookup(device);
1060    if (dd == NULL)
1061        return RTEMS_INVALID_ID;
[048dcd2b]1062
[e51bd96]1063    if (block >= dd->size)
1064    {
1065        rtems_disk_release(dd);
1066        return RTEMS_INVALID_NUMBER;
1067    }
[048dcd2b]1068
[e51bd96]1069    pdd = dd->phys_dev;
1070    block += dd->start;
1071    rtems_disk_release(dd);
1072
1073    DISABLE_PREEMPTION(key);
1074    rc = find_or_assign_buffer(pdd, block, bd);
1075    ENABLE_PREEMPTION(key);
1076
1077    if (rc != RTEMS_SUCCESSFUL)
1078        return rc;
1079
1080    return RTEMS_SUCCESSFUL;
1081}
1082
1083/* bdbuf_initialize_transfer_sema --
1084 *     Initialize transfer_sema mutex semaphore associated with buffer
1085 *     descriptor.
1086 */
1087static inline void
1088bdbuf_initialize_transfer_sema(bdbuf_buffer *bd_buf)
1089{
1090    CORE_mutex_Attributes mutex_attr;
1091    mutex_attr.lock_nesting_behavior = CORE_MUTEX_NESTING_BLOCKS;
1092    mutex_attr.only_owner_release = FALSE;
1093    mutex_attr.discipline = CORE_MUTEX_DISCIPLINES_FIFO;
1094    mutex_attr.priority_ceiling = 0;
1095
[8b96149]1096    _CORE_mutex_Initialize(&bd_buf->transfer_sema,
[87da638]1097                           &mutex_attr, CORE_MUTEX_LOCKED);
[e51bd96]1098}
1099
1100/* bdbuf_write_transfer_done --
1101 *     Callout function. Invoked by block device driver when data transfer
1102 *     to device (write) is completed. This function may be invoked from
1103 *     interrupt handler.
1104 *
1105 * PARAMETERS:
1106 *     arg    - arbitrary argument specified in block device request
1107 *              structure (in this case - pointer to the appropriate
1108 *              bdbuf_buffer buffer descriptor structure).
1109 *     status - I/O completion status
1110 *     error  - errno error code if status != RTEMS_SUCCESSFUL
1111 *
1112 * RETURNS:
1113 *     none
1114 */
1115static void
1116bdbuf_write_transfer_done(void *arg, rtems_status_code status, int error)
1117{
1118    bdbuf_buffer *bd_buf = arg;
1119    bd_buf->status = status;
[662814d]1120    bd_buf->error = RTEMS_IO_ERROR;
[e51bd96]1121    bd_buf->in_progress = bd_buf->modified = FALSE;
1122    _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);
[8b96149]1123    _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
[e51bd96]1124                      CORE_MUTEX_STATUS_SUCCESSFUL);
1125}
1126
1127/* bdbuf_read_transfer_done --
1128 *     Callout function. Invoked by block device driver when data transfer
1129 *     from device (read) is completed. This function may be invoked from
1130 *     interrupt handler.
1131 *
1132 * PARAMETERS:
1133 *     arg    - arbitrary argument specified in block device request
1134 *              structure (in this case - pointer to the appropriate
1135 *              bdbuf_buffer buffer descriptor structure).
1136 *     status - I/O completion status
1137 *     error  - errno error code if status != RTEMS_SUCCESSFUL
1138 *
1139 * RETURNS:
1140 *     none
1141 */
1142static void
1143bdbuf_read_transfer_done(void *arg, rtems_status_code status, int error)
1144{
1145    bdbuf_buffer *bd_buf = arg;
1146    bd_buf->status = status;
[662814d]1147    bd_buf->error = RTEMS_IO_ERROR;
[e51bd96]1148    _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);
[8b96149]1149    _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
[e51bd96]1150                      CORE_MUTEX_STATUS_SUCCESSFUL);
1151}
1152
1153/* rtems_bdbuf_read --
1154 *     (Similar to the rtems_bdbuf_get, except reading data from media)
1155 *     Obtain block buffer. If specified block already cached, return address
1156 *     of appropriate buffer and increment reference counter to 1. If block is
1157 *     not cached, allocate new buffer and read data to it from the media.
1158 *     This primitive may be blocked on waiting until data to be read from
1159 *     media, if there are no free buffer descriptors available and there are
1160 *     no unused non-modified (or synchronized with media) buffers available.
1161 *
1162 * PARAMETERS:
1163 *     device - device number (consists of major and minor device number)
1164 *     block  - linear media block number
1165 *     bd     - address of variable to store pointer to the buffer descriptor
1166 *
1167 * RETURNS:
1168 *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
1169 *     or error code if error is occured)
1170 *
1171 * SIDE EFFECTS:
1172 *     bufget_sema and transfer_sema semaphores obtained by this primitive.
1173 */
1174rtems_status_code
[8b96149]1175rtems_bdbuf_read(dev_t device,
[e51bd96]1176                 blkdev_bnum block,
1177                 bdbuf_buffer **bd)
1178{
1179    preemption_key key;
1180    ISR_Level level;
[048dcd2b]1181
[e51bd96]1182    bdbuf_buffer *bd_buf;
1183    rtems_status_code rc;
1184    int result;
1185    disk_device *dd;
1186    disk_device *pdd;
1187    blkdev_request1 req;
1188
1189    dd = rtems_disk_lookup(device);
1190    if (dd == NULL)
1191        return RTEMS_INVALID_ID;
[048dcd2b]1192
[e51bd96]1193    if (block >= dd->size)
1194    {
1195        rtems_disk_release(dd);
1196        return RTEMS_INVALID_NUMBER;
1197    }
[048dcd2b]1198
[e51bd96]1199    pdd = dd->phys_dev;
1200    block += dd->start;
1201
1202    DISABLE_PREEMPTION(key);
1203    rc = find_or_assign_buffer(pdd, block, &bd_buf);
1204
1205    if (rc != RTEMS_SUCCESSFUL)
1206    {
1207        ENABLE_PREEMPTION(key);
1208        rtems_disk_release(dd);
1209        return rc;
1210    }
1211
1212    if (!bd_buf->actual)
1213    {
1214        bd_buf->in_progress = 1;
1215
1216        req.req.req = BLKDEV_REQ_READ;
1217        req.req.req_done = bdbuf_read_transfer_done;
1218        req.req.done_arg = bd_buf;
1219        req.req.start = block;
1220        req.req.count = 1;
1221        req.req.bufnum = 1;
1222        req.req.bufs[0].length = dd->block_size;
1223        req.req.bufs[0].buffer = bd_buf->buffer;
[048dcd2b]1224
[e51bd96]1225        bdbuf_initialize_transfer_sema(bd_buf);
[662814d]1226        result = dd->ioctl(pdd->dev, BLKIO_REQUEST, &req);
[e51bd96]1227        if (result == -1)
1228        {
1229            bd_buf->status = RTEMS_IO_ERROR;
1230            bd_buf->error = errno;
1231            bd_buf->actual = FALSE;
1232        }
1233        else
1234        {
[df6348bb]1235            rtems_interrupt_disable(level);
[e51bd96]1236            _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
1237                              WATCHDOG_NO_TIMEOUT, level);
1238            bd_buf->actual = TRUE;
1239        }
1240        bd_buf->in_progress = FALSE;
1241    }
1242    rtems_disk_release(dd);
[048dcd2b]1243
[e51bd96]1244    ENABLE_PREEMPTION(key);
1245
1246    *bd = bd_buf;
[048dcd2b]1247
[e51bd96]1248    return RTEMS_SUCCESSFUL;
1249}
1250
1251
1252/* bdbuf_release --
1253 *     Release buffer. Decrease buffer usage counter. If it is zero, further
1254 *     processing depends on modified attribute. If buffer was modified, it
1255 *     is inserted into mod chain and swapout task waken up. If buffer was
1256 *     not modified, it is returned to the end of lru chain making it available
1257 *     for further use.
1258 *
1259 * PARAMETERS:
1260 *     bd_buf - pointer to the released buffer descriptor.
1261 *
1262 * RETURNS:
1263 *     RTEMS_SUCCESSFUL if buffer released successfully, or error code if
1264 *     error occured.
1265 *
1266 * NOTE:
1267 *     This is internal function. It is assumed that task made non-preemptive
1268 *     before its invocation.
1269 */
1270static rtems_status_code
1271bdbuf_release(bdbuf_buffer *bd_buf)
1272{
1273    bdbuf_pool *bd_pool;
1274    rtems_status_code rc = RTEMS_SUCCESSFUL;
1275
1276    if (bd_buf->use_count <= 0)
1277        return RTEMS_INTERNAL_ERROR;
[048dcd2b]1278
[e51bd96]1279    bd_pool = bd_ctx.pool + bd_buf->pool;
1280
1281    bd_buf->use_count--;
1282
1283    if (bd_buf->use_count == 0)
1284    {
1285        if (bd_buf->modified)
1286        {
[048dcd2b]1287
[e51bd96]1288            /* Buffer was modified. Insert buffer to the modified buffers
1289             * list and initiate flushing. */
1290            Chain_Append(&bd_ctx.mod, &bd_buf->link);
1291
1292            /* Release the flush_sema */
1293            rc = rtems_semaphore_release(bd_ctx.flush_sema);
1294        }
1295        else
1296        {
[8b96149]1297            /* Buffer was not modified. Add this descriptor to the
[e51bd96]1298             * end of lru chain and make it available for reuse. */
1299            Chain_Append(&bd_pool->lru, &bd_buf->link);
1300            rc = rtems_semaphore_release(bd_pool->bufget_sema);
1301        }
1302    }
1303    return rc;
1304}
1305
1306
1307/* rtems_bdbuf_release --
1308 *     Release buffer allocated before. This primitive decrease the
1309 *     usage counter. If it is zero, further destiny of buffer depends on
1310 *     'modified' status. If buffer was modified, it is placed to the end of
1311 *     mod list and flush task waken up. If buffer was not modified,
1312 *     it is placed to the end of lru list, and bufget_sema released, allowing
1313 *     to reuse this buffer.
1314 *
1315 * PARAMETERS:
1316 *     bd_buf - pointer to the bdbuf_buffer structure previously obtained using
[8b96149]1317 *              get/read primitive.
[e51bd96]1318 *
1319 * RETURNS:
1320 *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
1321 *     or error code if error is occured)
1322 *
1323 * SIDE EFFECTS:
1324 *     flush_sema and bufget_sema semaphores may be released by this primitive.
1325 */
1326rtems_status_code
1327rtems_bdbuf_release(bdbuf_buffer *bd_buf)
1328{
1329    preemption_key key;
1330    rtems_status_code rc = RTEMS_SUCCESSFUL;
1331
1332    if (bd_buf == NULL)
1333        return RTEMS_INVALID_ADDRESS;
[048dcd2b]1334
[e51bd96]1335    DISABLE_PREEMPTION(key);
[048dcd2b]1336
[e51bd96]1337    rc = bdbuf_release(bd_buf);
[048dcd2b]1338
[e51bd96]1339    ENABLE_PREEMPTION(key);
[048dcd2b]1340
[e51bd96]1341    return rc;
1342}
1343
1344/* rtems_bdbuf_release_modified --
1345 *     Release buffer allocated before, assuming that it is _modified_ by
[8b96149]1346 *     it's owner. This primitive decrease usage counter for buffer, mark
[e51bd96]1347 *     buffer descriptor as modified. If usage counter is 0, insert it at
1348 *     end of mod chain and release flush_sema semaphore to activate the
1349 *     flush task.
1350 *
1351 * PARAMETERS:
1352 *     bd_buf - pointer to the bdbuf_buffer structure previously obtained using
1353 *              get/read primitive.
1354 *
1355 * RETURNS:
1356 *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
1357 *     or error code if error is occured)
1358 *
1359 * SIDE EFFECTS:
1360 *     flush_sema semaphore may be released by this primitive.
1361 */
1362rtems_status_code
1363rtems_bdbuf_release_modified(bdbuf_buffer *bd_buf)
1364{
1365    preemption_key key;
1366    rtems_status_code rc = RTEMS_SUCCESSFUL;
1367
1368    if (bd_buf == NULL)
1369        return RTEMS_INVALID_ADDRESS;
[048dcd2b]1370
[e51bd96]1371    DISABLE_PREEMPTION(key);
1372
1373    if (!bd_buf->modified)
1374    {
1375        bdbuf_initialize_transfer_sema(bd_buf);
1376    }
1377    bd_buf->modified = TRUE;
1378    bd_buf->actual = TRUE;
[8b96149]1379    rc = bdbuf_release(bd_buf);
[048dcd2b]1380
[e51bd96]1381    ENABLE_PREEMPTION(key);
[048dcd2b]1382
[e51bd96]1383    return rc;
1384}
1385
1386/* rtems_bdbuf_sync --
1387 *     Wait until specified buffer synchronized with disk. Invoked on exchanges
1388 *     critical for data consistency on the media. This primitive mark owned
1389 *     block as modified, decrease usage counter. If usage counter is 0,
1390 *     block inserted to the mod chain and flush_sema semaphore released.
1391 *     Finally, primitives blocked on transfer_sema semaphore.
1392 *
1393 * PARAMETERS:
1394 *     bd_buf - pointer to the bdbuf_buffer structure previously obtained using
1395 *              get/read primitive.
1396 *
1397 * RETURNS:
1398 *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
1399 *     or error code if error is occured)
1400 *
1401 * SIDE EFFECTS:
1402 *     Primitive may be blocked on transfer_sema semaphore.
1403 */
1404rtems_status_code
1405rtems_bdbuf_sync(bdbuf_buffer *bd_buf)
1406{
1407    preemption_key key;
1408    ISR_Level level;
1409    rtems_status_code rc = RTEMS_SUCCESSFUL;
1410
1411    if (bd_buf == NULL)
1412        return RTEMS_INVALID_ADDRESS;
[048dcd2b]1413
[e51bd96]1414    DISABLE_PREEMPTION(key);
1415
1416    if (!bd_buf->modified)
1417    {
1418        bdbuf_initialize_transfer_sema(bd_buf);
1419    }
1420    bd_buf->modified = TRUE;
1421    bd_buf->actual = TRUE;
1422
1423    rc = bdbuf_release(bd_buf);
1424
1425    if (rc == RTEMS_SUCCESSFUL)
1426    {
[df6348bb]1427        rtems_interrupt_disable(level);
[e51bd96]1428        _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
1429                          WATCHDOG_NO_TIMEOUT, level);
1430    }
[048dcd2b]1431
[e51bd96]1432    ENABLE_PREEMPTION(key);
[048dcd2b]1433
[e51bd96]1434    return rc;
1435}
1436
1437/* rtems_bdbuf_syncdev --
1438 *     Synchronize with disk all buffers containing the blocks belonging to
1439 *     specified device.
1440 *
1441 * PARAMETERS:
1442 *     dev - block device number
1443 *
1444 * RETURNS:
1445 *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
1446 *     or error code if error is occured)
1447 */
1448rtems_status_code
1449rtems_bdbuf_syncdev(dev_t dev)
1450{
1451    preemption_key key;
1452    ISR_Level level;
[048dcd2b]1453
[e51bd96]1454    bdbuf_buffer *bd_buf;
1455    disk_device *dd;
1456    bdbuf_pool  *pool;
[048dcd2b]1457
[e51bd96]1458    dd = rtems_disk_lookup(dev);
1459    if (dd == NULL)
1460        return RTEMS_INVALID_ID;
[048dcd2b]1461
[e51bd96]1462    pool = bd_ctx.pool + dd->pool;
[048dcd2b]1463
[e51bd96]1464    DISABLE_PREEMPTION(key);
1465    do {
1466        bd_buf = avl_search_for_sync(&pool->tree, dd);
1467        if (bd_buf != NULL /* && bd_buf->modified */)
1468        {
[df6348bb]1469            rtems_interrupt_disable(level);
[e51bd96]1470            _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
1471                              WATCHDOG_NO_TIMEOUT, level);
1472        }
1473    } while (bd_buf != NULL);
1474    ENABLE_PREEMPTION(key);
1475    return rtems_disk_release(dd);
1476}
1477
1478/* bdbuf_swapout_task --
1479 *     Body of task which take care on flushing modified buffers to the
1480 *     disk.
1481 */
[8b96149]1482static rtems_task
[e51bd96]1483bdbuf_swapout_task(rtems_task_argument unused)
1484{
1485    rtems_status_code rc;
1486    int result;
1487    ISR_Level level;
1488    bdbuf_buffer *bd_buf;
1489    bdbuf_pool *bd_pool;
1490    disk_device *dd;
1491    blkdev_request1 req;
1492
1493    while (1)
1494    {
1495        rc = rtems_semaphore_obtain(bd_ctx.flush_sema, RTEMS_WAIT, 0);
1496        if (rc != RTEMS_SUCCESSFUL)
1497        {
1498            rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_SWAPOUT);
1499        }
[048dcd2b]1500
[e51bd96]1501        bd_buf = (bdbuf_buffer *)Chain_Get(&bd_ctx.mod);
1502        if (bd_buf == NULL)
1503        {
1504            /* It is possible that flush_sema semaphore will be released, but
1505             * buffer to be removed from mod chain before swapout task start
1506             * its processing. */
1507            continue;
1508        }
1509
1510        bd_buf->in_progress = TRUE;
1511        bd_buf->use_count++;
1512        bd_pool = bd_ctx.pool + bd_buf->pool;
1513        dd = rtems_disk_lookup(bd_buf->dev);
1514
1515        req.req.req = BLKDEV_REQ_WRITE;
1516        req.req.req_done = bdbuf_write_transfer_done;
1517        req.req.done_arg = bd_buf;
1518        req.req.start = bd_buf->block + dd->start;
1519        req.req.count = 1;
1520        req.req.bufnum = 1;
1521        req.req.bufs[0].length = dd->block_size;
1522        req.req.bufs[0].buffer = bd_buf->buffer;
1523
[8b96149]1524        /* transfer_sema initialized when bd_buf inserted in the mod chain
[e51bd96]1525           first time */
1526        result = dd->ioctl(dd->phys_dev->dev, BLKIO_REQUEST, &req);
[048dcd2b]1527
[e51bd96]1528        rtems_disk_release(dd);
[048dcd2b]1529
[e51bd96]1530        if (result == -1)
1531        {
1532            bd_buf->status = RTEMS_IO_ERROR;
1533            bd_buf->error = errno;
1534            /* Release tasks waiting on syncing this buffer */
1535            _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
1536                              CORE_MUTEX_STATUS_SUCCESSFUL);
1537        }
1538        else
1539        {
1540            if (bd_buf->in_progress)
1541            {
[df6348bb]1542                rtems_interrupt_disable(level);
[e51bd96]1543                _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, 0, level);
1544            }
1545        }
1546        bd_buf->use_count--;
1547
1548        /* Another task have chance to use this buffer, or even
1549         * modify it. If buffer is not in use, insert it in appropriate chain
1550         * and release semaphore */
1551        if (bd_buf->use_count == 0)
1552        {
1553            if (bd_buf->modified)
1554            {
1555                Chain_Append(&bd_ctx.mod, &bd_buf->link);
1556                rc = rtems_semaphore_release(bd_ctx.flush_sema);
1557            }
1558            else
1559            {
1560                Chain_Append(&bd_pool->lru, &bd_buf->link);
1561                rc = rtems_semaphore_release(bd_pool->bufget_sema);
1562            }
1563        }
1564    }
1565}
1566
1567/* rtems_bdbuf_find_pool --
1568 *     Find first appropriate buffer pool. This primitive returns the index
1569 *     of first buffer pool which block size is greater than or equal to
1570 *     specified size.
1571 *
1572 * PARAMETERS:
1573 *     block_size - requested block size
1574 *     pool       - placeholder for result
1575 *
1576 * RETURNS:
1577 *     RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,
[8b96149]1578 *     RTEMS_INVALID_SIZE if specified block size is invalid (not a power
[e51bd96]1579 *     of 2), RTEMS_NOT_DEFINED if buffer pool for this or greater block size
1580 *     is not configured.
1581 */
1582rtems_status_code
1583rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool)
1584{
1585    rtems_bdpool_id i;
1586    bdbuf_pool *p;
1587    int cursize = INT_MAX;
1588    rtems_bdpool_id curid = -1;
1589    rtems_boolean found = FALSE;
1590    int j;
[048dcd2b]1591
[e51bd96]1592    for (j = block_size; (j != 0) && ((j & 1) == 0); j >>= 1);
1593    if (j != 1)
1594        return RTEMS_INVALID_SIZE;
[048dcd2b]1595
[e51bd96]1596    for (i = 0, p = bd_ctx.pool; i < bd_ctx.npools; i++, p++)
1597    {
1598        if ((p->blksize >= block_size) &&
1599            (p->blksize < cursize))
1600        {
1601            curid = i;
1602            cursize = p->blksize;
1603            found = TRUE;
1604        }
1605    }
[048dcd2b]1606
[e51bd96]1607    if (found)
1608    {
1609        if (pool != NULL)
1610            *pool = curid;
1611        return RTEMS_SUCCESSFUL;
1612    }
1613    else
1614    {
1615        return RTEMS_NOT_DEFINED;
1616    }
1617}
1618
1619/* rtems_bdbuf_get_pool_info --
1620 *     Obtain characteristics of buffer pool with specified number.
1621 *
1622 * PARAMETERS:
1623 *     pool       - buffer pool number
1624 *     block_size - block size for which buffer pool is configured returned
1625 *                  there
[8b96149]1626 *     blocks     - number of buffers in buffer pool returned there
[e51bd96]1627 *
1628 * RETURNS:
1629 *     RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,
1630 *     RTEMS_INVALID_NUMBER if appropriate buffer pool is not configured.
1631 *
1632 * NOTE:
1633 *     Buffer pools enumerated contiguously starting from 0.
1634 */
1635rtems_status_code
1636rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size,
1637                          int *blocks)
1638{
1639    if (pool >= bd_ctx.npools)
1640        return RTEMS_INVALID_NUMBER;
[048dcd2b]1641
[e51bd96]1642    if (block_size != NULL)
1643    {
1644        *block_size = bd_ctx.pool[pool].blksize;
1645    }
[048dcd2b]1646
[e51bd96]1647    if (blocks != NULL)
1648    {
1649        *blocks = bd_ctx.pool[pool].nblks;
1650    }
[048dcd2b]1651
[e51bd96]1652    return RTEMS_SUCCESSFUL;
1653}
Note: See TracBrowser for help on using the repository browser.