source: rtems/cpukit/libblock/src/bdbuf.c @ cb2f320

4.104.114.84.95
Last change on this file since cb2f320 was cb2f320, checked in by Joel Sherrill <joel.sherrill@…>, on 03/05/04 at 18:02:41

2004-03-05 Joel Sherrill <joel@…>

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