source: rtems/cpukit/libblock/src/diskdevs.c @ ef142d7

4.104.114.84.95
Last change on this file since ef142d7 was e51bd96, checked in by Joel Sherrill <joel.sherrill@…>, on 02/28/02 at 20:39:54

2002-02-28 Joel Sherrill <joel@…>

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