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

4.104.114.84.9
Last change on this file since f1c22e0 was f1c22e0, checked in by Ralf Corsepius <ralf.corsepius@…>, on Nov 15, 2002 at 2:18:28 PM

2002-11-15 Ralf Corsepius <corsepiu@…>

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