source: rtems/cpukit/libblock/src/diskdevs.c @ 4f971343

4.104.114.9
Last change on this file since 4f971343 was 4f971343, checked in by Ralf Corsepius <ralf.corsepius@…>, on Sep 1, 2008 at 7:44:48 AM

Convert to using "bool".

  • Property mode set to 100644
File size: 17.3 KB
Line 
1/*
2 * diskdevs.c - Physical and logical block devices (disks) support
3 *
4 * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
5 * Author: Victor V. Vengerov <vvv@oktet.ru>
6 *
7 * @(#) $Id$
8 */
9
10#if HAVE_CONFIG_H
11#include "config.h"
12#endif
13
14#include <rtems.h>
15#include <rtems/libio.h>
16#include <stdlib.h>
17#include <unistd.h>     /* unlink */
18#include <string.h>
19
20#include "rtems/diskdevs.h"
21#include "rtems/bdbuf.h"
22
23#define DISKTAB_INITIAL_SIZE 32
24
25/* Table of disk devices having the same major number */
26typedef struct rtems_disk_device_table {
27    rtems_disk_device **minor; /* minor-indexed disk device table */
28    uint32_t            size;            /* Number of entries in the table */
29} rtems_disk_device_table;
30
31/* Pointer to [major].minor[minor] indexed array of disk devices */
32static rtems_disk_device_table *disktab;
33
34/* Number of allocated entries in disktab table */
35static uint32_t disktab_size;
36
37/* Mutual exclusion semaphore for disk devices table */
38static rtems_id diskdevs_mutex;
39
40/* Flag meaning that disk I/O, buffering etc. already has been initialized. */
41static bool disk_io_initialized = false;
42
43/* diskdevs data structures protection flag.
44 * Normally, only table lookup operations performed. It is quite fast, so
45 * it is possible to done lookups when interrupts are disabled, avoiding
46 * obtaining the semaphore. This flags sets immediately after entering in
47 * mutex-protected section and cleared before leaving this section in
48 * "big" primitives like add/delete new device etc. Lookup function first
49 * disable interrupts and check this flag. If it is set, lookup function
50 * will be blocked on semaphore and lookup operation will be performed in
51 * semaphore-protected code. If it is not set (very-very frequent case),
52 * we can do lookup safely, enable interrupts and return result.
53 */
54static volatile bool diskdevs_protected;
55
56/* create_disk_entry --
57 *     Return pointer to the disk_entry structure for the specified device, or
58 *     create one if it is not exists.
59 *
60 * PARAMETERS:
61 *     dev - device id (major, minor)
62 *
63 * RETURNS:
64 *     pointer to the disk device descriptor entry, or NULL if no memory
65 *     available for its creation.
66 */
67static rtems_disk_device *
68create_disk_entry(dev_t dev)
69{
70    rtems_device_major_number major;
71    rtems_device_minor_number minor;
72    rtems_disk_device **d;
73
74    rtems_filesystem_split_dev_t (dev, major, minor);
75
76    if (major >= disktab_size)
77    {
78        rtems_disk_device_table *p;
79        uint32_t newsize;
80        uint32_t i;
81        newsize = disktab_size * 2;
82        if (major >= newsize)
83            newsize = major + 1;
84        p = realloc(disktab, sizeof(rtems_disk_device_table) * newsize);
85        if (p == NULL)
86            return NULL;
87        disktab = p;
88        p += disktab_size;
89        for (i = disktab_size; i < newsize; i++, p++)
90        {
91            p->minor = NULL;
92            p->size = 0;
93        }
94        disktab_size = newsize;
95    }
96
97    if ((disktab[major].minor == NULL) ||
98        (minor >= disktab[major].size))
99    {
100        uint32_t            newsize;
101        rtems_disk_device **p;
102        uint32_t            i;
103        uint32_t            s = disktab[major].size;
104
105        if (s == 0)
106            newsize = DISKTAB_INITIAL_SIZE;
107        else
108            newsize = s * 2;
109        if (minor >= newsize)
110            newsize = minor + 1;
111
112        p = realloc(disktab[major].minor,
113                    sizeof(rtems_disk_device *) * newsize);
114        if (p == NULL)
115            return NULL;
116        disktab[major].minor = p;
117        p += s;
118        for (i = s; i < newsize; i++, p++)
119            *p = NULL;
120        disktab[major].size = newsize;
121    }
122
123    d = disktab[major].minor + minor;
124    if (*d == NULL)
125    {
126        *d = calloc(1, sizeof(rtems_disk_device));
127    }
128    return *d;
129}
130
131/* get_disk_entry --
132 *     Get disk device descriptor by device number.
133 *
134 * PARAMETERS:
135 *     dev - block device number
136 *
137 * RETURNS:
138 *     Pointer to the disk device descriptor corresponding to the specified
139 *     device number, or NULL if disk device with such number not exists.
140 */
141static rtems_disk_device *
142get_disk_entry(dev_t dev)
143{
144    rtems_device_major_number major;
145    rtems_device_minor_number minor;
146    rtems_disk_device_table *dtab;
147
148    rtems_filesystem_split_dev_t (dev, major, minor);
149
150    if ((major >= disktab_size) || (disktab == NULL))
151        return NULL;
152
153    dtab = disktab + major;
154
155    if ((minor >= dtab->size) || (dtab->minor == NULL))
156        return NULL;
157
158    return dtab->minor[minor];
159}
160
161/* create_disk --
162 *     Check that disk entry for specified device number is not defined
163 *     and create it.
164 *
165 * PARAMETERS:
166 *     dev        - device identifier (major, minor numbers)
167 *     name       - character name of device (e.g. /dev/hda)
168 *     disdev     - placeholder for pointer to created disk descriptor
169 *
170 * RETURNS:
171 *     RTEMS_SUCCESSFUL if disk entry successfully created, or
172 *     error code if error occured (device already registered,
173 *     no memory available).
174 */
175static rtems_status_code
176create_disk(dev_t dev, const char *name, rtems_disk_device **diskdev)
177{
178    rtems_disk_device *dd;
179    char *n;
180
181    dd = get_disk_entry(dev);
182    if (dd != NULL)
183    {
184        return RTEMS_RESOURCE_IN_USE;
185    }
186
187    if (name == NULL)
188    {
189        n = NULL;
190    }
191    else
192    {
193        int nlen = strlen(name) + 1;
194        n = malloc(nlen);
195        if (n == NULL)
196            return RTEMS_NO_MEMORY;
197        strncpy(n, name, nlen);
198    }
199
200    dd = create_disk_entry(dev);
201    if (dd == NULL)
202    {
203        free(n);
204        return RTEMS_NO_MEMORY;
205    }
206
207    dd->dev = dev;
208    dd->name = n;
209
210    *diskdev = dd;
211
212    return RTEMS_SUCCESSFUL;
213}
214
215/* rtems_disk_create_phys --
216 *     Create physical disk entry. This function usually invoked from
217 *     block device driver initialization code when physical device
218 *     detected in the system. Device driver should provide ioctl handler
219 *     to allow block device access operations. This primitive will register
220 *     device in rtems (invoke rtems_io_register_name).
221 *
222 * PARAMETERS:
223 *     dev        - device identifier (major, minor numbers)
224 *     block_size - size of disk block (minimum data transfer unit); must be
225 *                  power of 2
226 *     disk_size  - number of blocks on device
227 *     handler    - IOCTL handler (function providing basic block input/output
228 *                  request handling BIOREQUEST and other device management
229 *                  operations)
230 *     name       - character name of device (e.g. /dev/hda)
231 *
232 * RETURNS:
233 *     RTEMS_SUCCESSFUL if information about new physical disk added, or
234 *     error code if error occured (device already registered, wrong block
235 *     size value, no memory available).
236 */
237rtems_status_code
238rtems_disk_create_phys(dev_t dev, int block_size, int disk_size,
239                       rtems_block_device_ioctl handler,
240                       const char *name)
241{
242    int bs_log2;
243    int i;
244    rtems_disk_device *dd;
245    rtems_status_code rc;
246    rtems_bdpool_id pool;
247    rtems_device_major_number major;
248    rtems_device_minor_number minor;
249
250    rtems_filesystem_split_dev_t (dev, major, minor);
251
252
253    for (bs_log2 = 0, i = block_size; (i & 1) == 0; i >>= 1, bs_log2++);
254    if ((bs_log2 < 9) || (i != 1)) /* block size < 512 or not power of 2 */
255        return RTEMS_INVALID_NUMBER;
256
257    rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
258    if (rc != RTEMS_SUCCESSFUL)
259        return rc;
260    diskdevs_protected = true;
261
262    rc = rtems_bdbuf_find_pool(block_size, &pool);
263    if (rc != RTEMS_SUCCESSFUL)
264    {
265        diskdevs_protected = false;
266        rtems_semaphore_release(diskdevs_mutex);
267        return rc;
268    }
269
270    rc = create_disk(dev, name, &dd);
271    if (rc != RTEMS_SUCCESSFUL)
272    {
273        diskdevs_protected = false;
274        rtems_semaphore_release(diskdevs_mutex);
275        return rc;
276    }
277
278    dd->phys_dev = dd;
279    dd->uses = 0;
280    dd->start = 0;
281    dd->size = disk_size;
282    dd->block_size = block_size;
283    dd->block_size_log2 = bs_log2;
284    dd->ioctl = handler;
285    dd->pool = pool;
286
287    rc = rtems_io_register_name(name, major, minor);
288
289    if (handler (dd->phys_dev->dev,
290                 RTEMS_BLKDEV_CAPABILITIES,
291                 &dd->capabilities) < 0)
292      dd->capabilities = 0;
293   
294    diskdevs_protected = false;
295    rtems_semaphore_release(diskdevs_mutex);
296
297    return rc;
298}
299
300/* rtems_disk_create_log --
301 *     Create logical disk entry. Logical disk is contiguous area on physical
302 *     disk. Disk may be splitted to several logical disks in several ways:
303 *     manually or using information stored in blocks on physical disk
304 *     (DOS-like partition table, BSD disk label, etc). This function usually
305 *     invoked from application when application-specific splitting are in use,
306 *     or from generic code which handle different logical disk organizations.
307 *     This primitive will register device in rtems (invoke
308 *     rtems_io_register_name).
309 *
310 * PARAMETERS:
311 *     dev   - logical device identifier (major, minor numbers)
312 *     phys  - physical device (block device which holds this logical disk)
313 *             identifier
314 *     start - starting block number on the physical device
315 *     size  - logical disk size in blocks
316 *     name  - logical disk name
317 *
318 * RETURNS:
319 *     RTEMS_SUCCESSFUL if logical device successfully added, or error code
320 *     if error occured (device already registered, no physical device
321 *     exists, logical disk is out of physical disk boundaries, no memory
322 *     available).
323 */
324rtems_status_code
325rtems_disk_create_log(dev_t dev, dev_t phys, int start, int size, char *name)
326{
327    rtems_disk_device *dd;
328    rtems_disk_device *pdd;
329    rtems_status_code rc;
330    rtems_device_major_number major;
331    rtems_device_minor_number minor;
332
333    rtems_filesystem_split_dev_t (dev, major, minor);
334
335    rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
336    if (rc != RTEMS_SUCCESSFUL)
337        return rc;
338    diskdevs_protected = true;
339
340    pdd = get_disk_entry(phys);
341    if (pdd == NULL)
342    {
343        diskdevs_protected = false;
344        rtems_semaphore_release(diskdevs_mutex);
345        return RTEMS_INVALID_NUMBER;
346    }
347
348    rc = create_disk(dev, name, &dd);
349    if (rc != RTEMS_SUCCESSFUL)
350    {
351        diskdevs_protected = false;
352        rtems_semaphore_release(diskdevs_mutex);
353        return rc;
354    }
355
356    dd->phys_dev = pdd;
357    dd->uses = 0;
358    dd->start = start;
359    dd->size = size;
360    dd->block_size = pdd->block_size;
361    dd->block_size_log2 = pdd->block_size_log2;
362    dd->ioctl = pdd->ioctl;
363
364    rc = rtems_io_register_name(name, major, minor);
365
366    diskdevs_protected = false;
367    rc = rtems_semaphore_release(diskdevs_mutex);
368
369    return rc;
370}
371
372/* rtems_disk_delete --
373 *     Delete physical or logical disk device. Device may be deleted if its
374 *     use counter (and use counters of all logical devices - if it is
375 *     physical device) equal to 0. When physical device deleted,
376 *     all logical devices deleted inherently. Appropriate devices removed
377 *     from "/dev" filesystem.
378 *
379 * PARAMETERS:
380 *     dev - device identifier (major, minor numbers)
381 *
382 * RETURNS:
383 *     RTEMS_SUCCESSFUL if block device successfully deleted, or error code
384 *     if error occured (device is not defined, device is in use).
385 */
386rtems_status_code
387rtems_disk_delete(dev_t dev)
388{
389    rtems_status_code rc;
390    int used;
391    rtems_device_major_number maj;
392    rtems_device_minor_number min;
393
394    rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
395    if (rc != RTEMS_SUCCESSFUL)
396        return rc;
397    diskdevs_protected = true;
398
399    /* Check if this device is in use -- calculate usage counter */
400    used = 0;
401    for (maj = 0; maj < disktab_size; maj++)
402    {
403        rtems_disk_device_table *dtab = disktab + maj;
404        if (dtab != NULL)
405        {
406            for (min = 0; min < dtab->size; min++)
407            {
408                rtems_disk_device *dd = dtab->minor[min];
409                if ((dd != NULL) && (dd->phys_dev->dev == dev))
410                    used += dd->uses;
411            }
412        }
413    }
414
415    if (used != 0)
416    {
417        diskdevs_protected = false;
418        rtems_semaphore_release(diskdevs_mutex);
419        return RTEMS_RESOURCE_IN_USE;
420    }
421
422    /* Delete this device and all of its logical devices */
423    for (maj = 0; maj < disktab_size; maj++)
424    {
425        rtems_disk_device_table *dtab = disktab +maj;
426        if (dtab != NULL)
427        {
428            for (min = 0; min < dtab->size; min++)
429            {
430                rtems_disk_device *dd = dtab->minor[min];
431                if ((dd != NULL) && (dd->phys_dev->dev == dev))
432                {
433                    unlink(dd->name);
434                    free(dd->name);
435                    free(dd);
436                    dtab->minor[min] = NULL;
437                }
438            }
439        }
440    }
441
442    diskdevs_protected = false;
443    rc = rtems_semaphore_release(diskdevs_mutex);
444    return rc;
445}
446
447/* rtems_disk_obtain --
448 *     Find block device descriptor by its device identifier.
449 *
450 * PARAMETERS:
451 *     dev - device identifier (major, minor numbers)
452 *
453 * RETURNS:
454 *     pointer to the block device descriptor, or NULL if no such device
455 *     exists.
456 */
457rtems_disk_device *
458rtems_disk_obtain(dev_t dev)
459{
460    rtems_interrupt_level level;
461    rtems_disk_device *dd;
462    rtems_status_code rc;
463
464    rtems_interrupt_disable(level);
465    if (diskdevs_protected)
466    {
467        rtems_interrupt_enable(level);
468        rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT,
469                                    RTEMS_NO_TIMEOUT);
470        if (rc != RTEMS_SUCCESSFUL)
471            return NULL;
472        diskdevs_protected = true;
473        dd = get_disk_entry(dev);
474        dd->uses++;
475        diskdevs_protected = false;
476        rtems_semaphore_release(diskdevs_mutex);
477        return dd;
478    }
479    else
480    {
481        /* Frequent and quickest case */
482        dd = get_disk_entry(dev);
483        dd->uses++;
484        rtems_interrupt_enable(level);
485        return dd;
486    }
487}
488
489/* rtems_disk_release --
490 *     Release rtems_disk_device structure (decrement usage counter to 1).
491 *
492 * PARAMETERS:
493 *     dd - pointer to disk device structure
494 *
495 * RETURNS:
496 *     RTEMS_SUCCESSFUL
497 */
498rtems_status_code
499rtems_disk_release(rtems_disk_device *dd)
500{
501    rtems_interrupt_level level;
502    rtems_interrupt_disable(level);
503    dd->uses--;
504    rtems_interrupt_enable(level);
505    return RTEMS_SUCCESSFUL;
506}
507
508/* rtems_disk_next --
509 *     Disk device enumerator. Looking for device having device number larger
510 *     than dev and return disk device descriptor for it. If there are no
511 *     such device, NULL value returned.
512 *
513 * PARAMETERS:
514 *     dev - device number (use -1 to start search)
515 *
516 * RETURNS:
517 *     Pointer to the disk descriptor for next disk device, or NULL if all
518 *     devices enumerated.
519 */
520rtems_disk_device *
521rtems_disk_next(dev_t dev)
522{
523    rtems_device_major_number major;
524    rtems_device_minor_number minor;
525    rtems_disk_device_table *dtab;
526
527    dev++;
528    rtems_filesystem_split_dev_t (dev, major, minor);
529
530    if (major >= disktab_size)
531        return NULL;
532
533    dtab = disktab + major;
534    while (true)
535    {
536        if ((dtab == NULL) || (minor > dtab->size))
537        {
538             major++; minor = 0;
539             if (major >= disktab_size)
540                 return NULL;
541             dtab = disktab + major;
542        }
543        else if (dtab->minor[minor] == NULL)
544        {
545            minor++;
546        }
547        else
548            return dtab->minor[minor];
549    }
550}
551
552/* rtems_disk_initialize --
553 *     Initialization of disk device library (initialize all data structures,
554 *     etc.)
555 *
556 * PARAMETERS:
557 *     none
558 *
559 * RETURNS:
560 *     RTEMS_SUCCESSFUL if library initialized, or error code if error
561 *     occured.
562 */
563rtems_status_code
564rtems_disk_io_initialize(void)
565{
566    rtems_status_code rc;
567
568    if (disk_io_initialized)
569        return RTEMS_SUCCESSFUL;
570
571    disktab_size = DISKTAB_INITIAL_SIZE;
572    disktab = calloc(disktab_size, sizeof(rtems_disk_device_table));
573    if (disktab == NULL)
574        return RTEMS_NO_MEMORY;
575
576    diskdevs_protected = false;
577    rc = rtems_semaphore_create(
578        rtems_build_name('D', 'D', 'E', 'V'), 1,
579        RTEMS_FIFO | RTEMS_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
580        RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0, &diskdevs_mutex);
581
582    if (rc != RTEMS_SUCCESSFUL)
583    {
584        free(disktab);
585        return rc;
586    }
587
588    rc = rtems_bdbuf_init();
589
590    if (rc != RTEMS_SUCCESSFUL)
591    {
592        rtems_semaphore_delete(diskdevs_mutex);
593        free(disktab);
594        return rc;
595    }
596
597    disk_io_initialized = 1;
598    return RTEMS_SUCCESSFUL;
599}
600
601/* rtems_disk_io_done --
602 *     Release all resources allocated for disk device interface.
603 *
604 * PARAMETERS:
605 *     none
606 *
607 * RETURNS:
608 *     RTEMS_SUCCESSFUL if all resources released, or error code if error
609 *     occured.
610 */
611rtems_status_code
612rtems_disk_io_done(void)
613{
614    rtems_device_major_number maj;
615    rtems_device_minor_number min;
616    rtems_status_code rc;
617
618    /* Free data structures */
619    for (maj = 0; maj < disktab_size; maj++)
620    {
621        rtems_disk_device_table *dtab = disktab + maj;
622        if (dtab != NULL)
623        {
624            for (min = 0; min < dtab->size; min++)
625            {
626                rtems_disk_device *dd = dtab->minor[min];
627                unlink(dd->name);
628                free(dd->name);
629                free(dd);
630            }
631            free(dtab);
632        }
633    }
634    free(disktab);
635
636    rc = rtems_semaphore_delete(diskdevs_mutex);
637
638    /* XXX bdbuf should be released too! */
639    disk_io_initialized = 0;
640    return rc;
641}
Note: See TracBrowser for help on using the repository browser.