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

4.104.11
Last change on this file since b96e09c was b96e09c, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on Oct 13, 2009 at 7:58:33 AM
  • libblock/include/rtems/diskdevs.h: Added driver data pointer to IO control function. The IO control handler takes now the disk device as first parameter instead of the physical device number.
  • cpukit/libblock/include/rtems/blkdev.h, libblock/src/bdbuf.c, libblock/src/blkdev.c, libblock/src/diskdevs.c, libblock/src/nvdisk.c, libblock/src/flashdisk.c, libblock/src/ramdisk.c: Update for block device API change.
  • Property mode set to 100644
File size: 13.1 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup rtems_disk
5 *
6 * Block device disk management.
7 */
8 
9/*
10 * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
11 * Author: Victor V. Vengerov <vvv@oktet.ru>
12 *
13 * @(#) $Id$
14 */
15
16#if HAVE_CONFIG_H
17#include "config.h"
18#endif
19
20#include <rtems.h>
21#include <rtems/libio.h>
22#include <stdlib.h>
23#include <unistd.h>     /* unlink */
24#include <string.h>
25
26#include "rtems/diskdevs.h"
27#include "rtems/bdbuf.h"
28
29#define DISKTAB_INITIAL_SIZE 32
30
31/* Table of disk devices having the same major number */
32typedef struct rtems_disk_device_table {
33    rtems_disk_device **minor; /* minor-indexed disk device table */
34    uint32_t            size;            /* Number of entries in the table */
35} rtems_disk_device_table;
36
37/* Pointer to [major].minor[minor] indexed array of disk devices */
38static rtems_disk_device_table *disktab;
39
40/* Number of allocated entries in disktab table */
41static uint32_t disktab_size;
42
43/* Mutual exclusion semaphore for disk devices table */
44static rtems_id diskdevs_mutex;
45
46/* Flag meaning that disk I/O, buffering etc. already has been initialized. */
47static bool disk_io_initialized = false;
48
49/* diskdevs data structures protection flag.
50 * Normally, only table lookup operations performed. It is quite fast, so
51 * it is possible to done lookups when interrupts are disabled, avoiding
52 * obtaining the semaphore. This flags sets immediately after entering in
53 * mutex-protected section and cleared before leaving this section in
54 * "big" primitives like add/delete new device etc. Lookup function first
55 * disable interrupts and check this flag. If it is set, lookup function
56 * will be blocked on semaphore and lookup operation will be performed in
57 * semaphore-protected code. If it is not set (very-very frequent case),
58 * we can do lookup safely, enable interrupts and return result.
59 */
60static volatile bool diskdevs_protected;
61
62/* create_disk_entry --
63 *     Return pointer to the disk_entry structure for the specified device, or
64 *     create one if it is not exists.
65 *
66 * PARAMETERS:
67 *     dev - device id (major, minor)
68 *
69 * RETURNS:
70 *     pointer to the disk device descriptor entry, or NULL if no memory
71 *     available for its creation.
72 */
73static rtems_disk_device *
74create_disk_entry(dev_t dev)
75{
76    rtems_device_major_number major;
77    rtems_device_minor_number minor;
78    rtems_disk_device **d;
79
80    rtems_filesystem_split_dev_t (dev, major, minor);
81
82    if (major >= disktab_size)
83    {
84        rtems_disk_device_table *p;
85        uint32_t newsize;
86        uint32_t i;
87        newsize = disktab_size * 2;
88        if (major >= newsize)
89            newsize = major + 1;
90        p = realloc(disktab, sizeof(rtems_disk_device_table) * newsize);
91        if (p == NULL)
92            return NULL;
93        disktab = p;
94        p += disktab_size;
95        for (i = disktab_size; i < newsize; i++, p++)
96        {
97            p->minor = NULL;
98            p->size = 0;
99        }
100        disktab_size = newsize;
101    }
102
103    if ((disktab[major].minor == NULL) ||
104        (minor >= disktab[major].size))
105    {
106        uint32_t            newsize;
107        rtems_disk_device **p;
108        uint32_t            i;
109        uint32_t            s = disktab[major].size;
110
111        if (s == 0)
112            newsize = DISKTAB_INITIAL_SIZE;
113        else
114            newsize = s * 2;
115        if (minor >= newsize)
116            newsize = minor + 1;
117
118        p = realloc(disktab[major].minor,
119                    sizeof(rtems_disk_device *) * newsize);
120        if (p == NULL)
121            return NULL;
122        disktab[major].minor = p;
123        p += s;
124        for (i = s; i < newsize; i++, p++)
125            *p = NULL;
126        disktab[major].size = newsize;
127    }
128
129    d = disktab[major].minor + minor;
130    if (*d == NULL)
131    {
132        *d = calloc(1, sizeof(rtems_disk_device));
133    }
134    return *d;
135}
136
137/* get_disk_entry --
138 *     Get disk device descriptor by device number.
139 *
140 * PARAMETERS:
141 *     dev - block device number
142 *
143 * RETURNS:
144 *     Pointer to the disk device descriptor corresponding to the specified
145 *     device number, or NULL if disk device with such number not exists.
146 */
147static rtems_disk_device *
148get_disk_entry(dev_t dev)
149{
150    rtems_device_major_number major;
151    rtems_device_minor_number minor;
152    rtems_disk_device_table *dtab;
153
154    rtems_filesystem_split_dev_t (dev, major, minor);
155
156    if ((major >= disktab_size) || (disktab == NULL))
157        return NULL;
158
159    dtab = disktab + major;
160
161    if ((minor >= dtab->size) || (dtab->minor == NULL))
162        return NULL;
163
164    return dtab->minor[minor];
165}
166
167/* create_disk --
168 *     Check that disk entry for specified device number is not defined
169 *     and create it.
170 *
171 * PARAMETERS:
172 *     dev        - device identifier (major, minor numbers)
173 *     name       - character name of device (e.g. /dev/hda)
174 *     disdev     - placeholder for pointer to created disk descriptor
175 *
176 * RETURNS:
177 *     RTEMS_SUCCESSFUL if disk entry successfully created, or
178 *     error code if error occured (device already registered,
179 *     no memory available).
180 */
181static rtems_status_code
182create_disk(dev_t dev, const char *name, rtems_disk_device **diskdev)
183{
184    rtems_disk_device *dd;
185    char *n;
186
187    dd = get_disk_entry(dev);
188    if (dd != NULL)
189    {
190        return RTEMS_RESOURCE_IN_USE;
191    }
192
193    if (name == NULL)
194    {
195        n = NULL;
196    }
197    else
198    {
199        int nlen = strlen(name) + 1;
200        n = malloc(nlen);
201        if (n == NULL)
202            return RTEMS_NO_MEMORY;
203        strncpy(n, name, nlen);
204    }
205
206    dd = create_disk_entry(dev);
207    if (dd == NULL)
208    {
209        free(n);
210        return RTEMS_NO_MEMORY;
211    }
212
213    dd->dev = dev;
214    dd->name = n;
215
216    *diskdev = dd;
217
218    return RTEMS_SUCCESSFUL;
219}
220
221rtems_status_code rtems_disk_create_phys(
222  dev_t dev,
223  uint32_t block_size,
224  rtems_blkdev_bnum disk_size,
225  rtems_block_device_ioctl handler,
226  void *driver_data,
227  const char *name
228)
229{
230    rtems_disk_device *dd;
231    rtems_status_code rc;
232    rtems_device_major_number major;
233    rtems_device_minor_number minor;
234
235    rtems_filesystem_split_dev_t (dev, major, minor);
236
237    rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
238    if (rc != RTEMS_SUCCESSFUL)
239        return rc;
240    diskdevs_protected = true;
241
242    rc = create_disk(dev, name, &dd);
243    if (rc != RTEMS_SUCCESSFUL)
244    {
245        diskdevs_protected = false;
246        rtems_semaphore_release(diskdevs_mutex);
247        return rc;
248    }
249
250    dd->phys_dev = dd;
251    dd->uses = 0;
252    dd->start = 0;
253    dd->size = disk_size;
254    dd->block_size = dd->media_block_size = block_size;
255    dd->ioctl = handler;
256    dd->driver_data = driver_data;
257
258    rc = rtems_io_register_name(name, major, minor);
259
260    if (handler (dd, RTEMS_BLKDEV_CAPABILITIES, &dd->capabilities) < 0)
261      dd->capabilities = 0;
262   
263    diskdevs_protected = false;
264    rtems_semaphore_release(diskdevs_mutex);
265
266    return rc;
267}
268
269rtems_status_code rtems_disk_create_log(
270  dev_t dev,
271  dev_t phys,
272  rtems_blkdev_bnum start,
273  rtems_blkdev_bnum size,
274  const char *name
275)
276{
277  rtems_disk_device *dd = NULL;
278  rtems_disk_device *pdd = NULL;
279  rtems_status_code rc = RTEMS_SUCCESSFUL;
280  rtems_device_major_number major = 0;
281  rtems_device_minor_number minor = 0;
282  rtems_blkdev_bnum end = start + size;
283
284  rtems_filesystem_split_dev_t (dev, major, minor);
285
286  rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
287  if (rc != RTEMS_SUCCESSFUL) {
288    return rc;
289  }
290
291  diskdevs_protected = true;
292
293  pdd = get_disk_entry(phys);
294  if (
295    pdd == NULL
296      || pdd != pdd->phys_dev
297      || start >= pdd->size
298      || end <= start
299      || end > pdd->size
300  ) {
301    diskdevs_protected = false;
302    rtems_semaphore_release(diskdevs_mutex);
303    return RTEMS_INVALID_NUMBER;
304  }
305
306  rc = create_disk(dev, name, &dd);
307  if (rc != RTEMS_SUCCESSFUL) {
308    diskdevs_protected = false;
309    rtems_semaphore_release(diskdevs_mutex);
310    return rc;
311  }
312
313  dd->phys_dev = pdd;
314  dd->uses = 0;
315  dd->start = start;
316  dd->size = size;
317  dd->block_size = dd->media_block_size = pdd->block_size;
318  dd->ioctl = pdd->ioctl;
319  dd->driver_data = pdd->driver_data;
320
321  rc = rtems_io_register_name(name, major, minor);
322
323  diskdevs_protected = false;
324  rc = rtems_semaphore_release(diskdevs_mutex);
325
326  return rc;
327}
328
329rtems_status_code
330rtems_disk_delete(dev_t dev)
331{
332  rtems_status_code rc = RTEMS_SUCCESSFUL;
333  rtems_device_major_number maj = 0;
334  rtems_device_minor_number min = 0;
335  rtems_disk_device *dd = NULL;
336  bool physical_disk = true;
337
338  rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
339  if (rc != RTEMS_SUCCESSFUL) {
340    return rc;
341  }
342  diskdevs_protected = true;
343
344  /* Check if we have a physical or logical disk */
345  dd = get_disk_entry(dev);
346  if (dd == NULL) {
347    return RTEMS_INVALID_NUMBER;
348  }
349  physical_disk = dd->phys_dev == dd;
350
351  if (physical_disk) {
352    unsigned used = 0;
353
354    /* Check if this device is in use -- calculate usage counter */
355    for (maj = 0; maj < disktab_size; maj++) {
356      rtems_disk_device_table *dtab = disktab + maj;
357      if (dtab != NULL) {
358        for (min = 0; min < dtab->size; min++) {
359          dd = dtab->minor[min];
360          if ((dd != NULL) && (dd->phys_dev->dev == dev)) {
361            used += dd->uses;
362          }
363        }
364      }
365    }
366
367    if (used != 0) {
368      diskdevs_protected = false;
369      rtems_semaphore_release(diskdevs_mutex);
370      return RTEMS_RESOURCE_IN_USE;
371    }
372
373    /* Delete this device and all of its logical devices */
374    for (maj = 0; maj < disktab_size; maj++) {
375      rtems_disk_device_table *dtab = disktab + maj;
376      if (dtab != NULL) {
377        for (min = 0; min < dtab->size; min++) {
378          dd = dtab->minor[min];
379          if ((dd != NULL) && (dd->phys_dev->dev == dev)) {
380            unlink(dd->name);
381            free(dd->name);
382            free(dd);
383            dtab->minor[min] = NULL;
384          }
385        }
386      }
387    }
388  } else {
389    rtems_filesystem_split_dev_t(dev, maj, min);
390    disktab[maj].minor[min] = NULL;
391    unlink(dd->name);
392    free(dd->name);
393    free(dd);
394  }
395
396  diskdevs_protected = false;
397  rc = rtems_semaphore_release(diskdevs_mutex);
398  return rc;
399}
400
401rtems_disk_device *
402rtems_disk_obtain(dev_t dev)
403{
404    rtems_interrupt_level level;
405    rtems_disk_device *dd;
406    rtems_status_code rc;
407
408    rtems_interrupt_disable(level);
409    if (diskdevs_protected)
410    {
411        rtems_interrupt_enable(level);
412        rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT,
413                                    RTEMS_NO_TIMEOUT);
414        if (rc != RTEMS_SUCCESSFUL)
415            return NULL;
416        diskdevs_protected = true;
417        dd = get_disk_entry(dev);
418        dd->uses++;
419        diskdevs_protected = false;
420        rtems_semaphore_release(diskdevs_mutex);
421        return dd;
422    }
423    else
424    {
425        /* Frequent and quickest case */
426        dd = get_disk_entry(dev);
427        dd->uses++;
428        rtems_interrupt_enable(level);
429        return dd;
430    }
431}
432
433rtems_status_code
434rtems_disk_release(rtems_disk_device *dd)
435{
436    rtems_interrupt_level level;
437    rtems_interrupt_disable(level);
438    dd->uses--;
439    rtems_interrupt_enable(level);
440    return RTEMS_SUCCESSFUL;
441}
442
443rtems_disk_device *
444rtems_disk_next(dev_t dev)
445{
446    rtems_device_major_number major;
447    rtems_device_minor_number minor;
448    rtems_disk_device_table *dtab;
449
450    dev++;
451    rtems_filesystem_split_dev_t (dev, major, minor);
452
453    if (major >= disktab_size)
454        return NULL;
455
456    dtab = disktab + major;
457    while (true)
458    {
459        if ((dtab == NULL) || (minor > dtab->size))
460        {
461             major++; minor = 0;
462             if (major >= disktab_size)
463                 return NULL;
464             dtab = disktab + major;
465        }
466        else if (dtab->minor[minor] == NULL)
467        {
468            minor++;
469        }
470        else
471            return dtab->minor[minor];
472    }
473}
474
475rtems_status_code
476rtems_disk_io_initialize(void)
477{
478    rtems_status_code rc;
479
480    if (disk_io_initialized)
481        return RTEMS_SUCCESSFUL;
482
483    disktab_size = DISKTAB_INITIAL_SIZE;
484    disktab = calloc(disktab_size, sizeof(rtems_disk_device_table));
485    if (disktab == NULL)
486        return RTEMS_NO_MEMORY;
487
488    diskdevs_protected = false;
489    rc = rtems_semaphore_create(
490        rtems_build_name('D', 'D', 'E', 'V'), 1,
491        RTEMS_FIFO | RTEMS_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
492        RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0, &diskdevs_mutex);
493
494    if (rc != RTEMS_SUCCESSFUL)
495    {
496        free(disktab);
497        return rc;
498    }
499
500    rc = rtems_bdbuf_init();
501
502    if (rc != RTEMS_SUCCESSFUL)
503    {
504        rtems_semaphore_delete(diskdevs_mutex);
505        free(disktab);
506        return rc;
507    }
508
509    disk_io_initialized = 1;
510    return RTEMS_SUCCESSFUL;
511}
512
513rtems_status_code
514rtems_disk_io_done(void)
515{
516    rtems_device_major_number maj;
517    rtems_device_minor_number min;
518    rtems_status_code rc;
519
520    /* Free data structures */
521    for (maj = 0; maj < disktab_size; maj++)
522    {
523        rtems_disk_device_table *dtab = disktab + maj;
524        if (dtab != NULL)
525        {
526            for (min = 0; min < dtab->size; min++)
527            {
528                rtems_disk_device *dd = dtab->minor[min];
529                unlink(dd->name);
530                free(dd->name);
531                free(dd);
532            }
533            free(dtab);
534        }
535    }
536    free(disktab);
537
538    rc = rtems_semaphore_delete(diskdevs_mutex);
539
540    disk_io_initialized = 0;
541    return rc;
542}
Note: See TracBrowser for help on using the repository browser.