OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [cpukit/] [libblock/] [src/] [bdbuf.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1026 ivang
/*
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
 * @(#) bdbuf.c,v 1.3 2002/07/01 22:37:58 joel Exp
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) (('B' << 24) | ((n) & 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
 
30
static 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
 */
37
typedef 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 */
55
struct 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 */
68
typedef struct blkdev_request1 {
69
    blkdev_request   req;
70
    blkdev_sg_buffer sg[1];
71
} blkdev_request1;
72
 
73
/* The static context of buffering layer */
74
static struct bdbuf_context bd_ctx;
75
 
76
#define SAFE
77
#ifdef SAFE
78
typedef rtems_mode preemption_key;
79
 
80
#define DISABLE_PREEMPTION(key) \
81
    do {                                                               \
82
        rtems_task_mode(RTEMS_PREEMPT_MASK, RTEMS_NO_PREEMPT, &(key)); \
83
    } while (0)
84
 
85
#define ENABLE_PREEMPTION(key) \
86
    do {                                                        \
87
        rtems_mode temp;                                        \
88
        rtems_task_mode(RTEMS_PREEMPT_MASK, (key), &temp);      \
89
    } while (0)
90
 
91
#else
92
 
93
typedef 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
 */
131
static bdbuf_buffer *
132
avl_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
 */
164
static bdbuf_buffer *
165
avl_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
 */
220
static int
221
avl_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
 */
401
static int
402
avl_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
 */
673
static rtems_status_code
674
bdbuf_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
 */
749
static rtems_status_code
750
bdbuf_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
 */
774
rtems_status_code
775
rtems_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
 */
882
static rtems_status_code
883
find_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
 
899
again:
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
 */
1043
rtems_status_code
1044
rtems_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
 */
1082
static inline void
1083
bdbuf_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
 */
1110
static void
1111
bdbuf_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 = 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
 */
1137
static void
1138
bdbuf_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 = 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
 */
1169
rtems_status_code
1170
rtems_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(device, 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
 */
1265
static rtems_status_code
1266
bdbuf_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
 */
1321
rtems_status_code
1322
rtems_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
 */
1357
rtems_status_code
1358
rtems_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
 */
1399
rtems_status_code
1400
rtems_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
 */
1443
rtems_status_code
1444
rtems_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
 */
1477
static rtems_task
1478
bdbuf_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
 */
1577
rtems_status_code
1578
rtems_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
 */
1630
rtems_status_code
1631
rtems_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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.