source: rtems/cpukit/libblock/src/bdbuf.c @ 828be6d

4.104.114.84.9
Last change on this file since 828be6d was 828be6d, checked in by Joel Sherrill <joel.sherrill@…>, on Jan 3, 2003 at 4:39:46 PM

2003-01-03 Eugeny S. Mints <Eugeny.Mints@…>

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