source: rtems/cpukit/libblock/src/diskdevs.c @ 0d15414e

4.104.115
Last change on this file since 0d15414e was 0d15414e, checked in by Chris Johns <chrisj@…>, on 08/05/09 at 00:00:54

009-08-05 Chris Johns <chrisj@…>

  • libmisc/dummy/dummy-networking.c: New.
  • libmisc/dummy/dummy.c, libmisc/Makefile.am: Move trhe networking configuration into a separate file so configuration varations do not cause conflicts.
  • score/inline/rtems/score/object.inl, score/include/rtems/score/object.h: Remove warnings.
  • score/inline/rtems/score/object.inl: Add _Chain_First, _Chain_Last, _Chain_Mext, and _Chain_Previous.
  • sapi/inline/rtems/chain.inl: Add rtems_chain_first, rtems_chain_last, rtems_chain_mext, and rtems_chain_previous.
  • libblock/include/rtems/diskdevs.h: Remove the bdbuf pool id and block_size_log2. Add media_block_size.
  • libblock/src/diskdevs.c: Remove size restrictions on block size. Add media block size initialisation. Remove comment to clean up the bdbuf cache.
  • libblock/src/blkdev.c: Remove references to block_size_log2. Allow any block size.
  • libblock/include/rtems/bdbuf.h, libblock/src/bdbuf.c: Remove all references to pools and make the cache handle demand driver variable buffer size allocation. Added worker threads support the swapout task.
  • sapi/include/confdefs.h: Updated the bdbuf configutation.
  • 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  const char *name
227)
228{
229    rtems_disk_device *dd;
230    rtems_status_code rc;
231    rtems_device_major_number major;
232    rtems_device_minor_number minor;
233
234    rtems_filesystem_split_dev_t (dev, major, minor);
235
236    rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
237    if (rc != RTEMS_SUCCESSFUL)
238        return rc;
239    diskdevs_protected = true;
240
241    rc = create_disk(dev, name, &dd);
242    if (rc != RTEMS_SUCCESSFUL)
243    {
244        diskdevs_protected = false;
245        rtems_semaphore_release(diskdevs_mutex);
246        return rc;
247    }
248
249    dd->phys_dev = dd;
250    dd->uses = 0;
251    dd->start = 0;
252    dd->size = disk_size;
253    dd->block_size = dd->media_block_size = block_size;
254    dd->ioctl = handler;
255
256    rc = rtems_io_register_name(name, major, minor);
257
258    if (handler (dd->phys_dev->dev,
259                 RTEMS_BLKDEV_CAPABILITIES,
260                 &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 = pdd->block_size;
318  dd->ioctl = pdd->ioctl;
319
320  rc = rtems_io_register_name(name, major, minor);
321
322  diskdevs_protected = false;
323  rc = rtems_semaphore_release(diskdevs_mutex);
324
325  return rc;
326}
327
328rtems_status_code
329rtems_disk_delete(dev_t dev)
330{
331  rtems_status_code rc = RTEMS_SUCCESSFUL;
332  rtems_device_major_number maj = 0;
333  rtems_device_minor_number min = 0;
334  rtems_disk_device *dd = NULL;
335  bool physical_disk = true;
336
337  rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
338  if (rc != RTEMS_SUCCESSFUL) {
339    return rc;
340  }
341  diskdevs_protected = true;
342
343  /* Check if we have a physical or logical disk */
344  dd = get_disk_entry(dev);
345  if (dd == NULL) {
346    return RTEMS_INVALID_NUMBER;
347  }
348  physical_disk = dd->phys_dev == dd;
349
350  if (physical_disk) {
351    unsigned used = 0;
352
353    /* Check if this device is in use -- calculate usage counter */
354    for (maj = 0; maj < disktab_size; maj++) {
355      rtems_disk_device_table *dtab = disktab + maj;
356      if (dtab != NULL) {
357        for (min = 0; min < dtab->size; min++) {
358          dd = dtab->minor[min];
359          if ((dd != NULL) && (dd->phys_dev->dev == dev)) {
360            used += dd->uses;
361          }
362        }
363      }
364    }
365
366    if (used != 0) {
367      diskdevs_protected = false;
368      rtems_semaphore_release(diskdevs_mutex);
369      return RTEMS_RESOURCE_IN_USE;
370    }
371
372    /* Delete this device and all of its logical devices */
373    for (maj = 0; maj < disktab_size; maj++) {
374      rtems_disk_device_table *dtab = disktab + maj;
375      if (dtab != NULL) {
376        for (min = 0; min < dtab->size; min++) {
377          dd = dtab->minor[min];
378          if ((dd != NULL) && (dd->phys_dev->dev == dev)) {
379            unlink(dd->name);
380            free(dd->name);
381            free(dd);
382            dtab->minor[min] = NULL;
383          }
384        }
385      }
386    }
387  } else {
388    rtems_filesystem_split_dev_t(dev, maj, min);
389    disktab[maj].minor[min] = NULL;
390    unlink(dd->name);
391    free(dd->name);
392    free(dd);
393  }
394
395  diskdevs_protected = false;
396  rc = rtems_semaphore_release(diskdevs_mutex);
397  return rc;
398}
399
400rtems_disk_device *
401rtems_disk_obtain(dev_t dev)
402{
403    rtems_interrupt_level level;
404    rtems_disk_device *dd;
405    rtems_status_code rc;
406
407    rtems_interrupt_disable(level);
408    if (diskdevs_protected)
409    {
410        rtems_interrupt_enable(level);
411        rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT,
412                                    RTEMS_NO_TIMEOUT);
413        if (rc != RTEMS_SUCCESSFUL)
414            return NULL;
415        diskdevs_protected = true;
416        dd = get_disk_entry(dev);
417        dd->uses++;
418        diskdevs_protected = false;
419        rtems_semaphore_release(diskdevs_mutex);
420        return dd;
421    }
422    else
423    {
424        /* Frequent and quickest case */
425        dd = get_disk_entry(dev);
426        dd->uses++;
427        rtems_interrupt_enable(level);
428        return dd;
429    }
430}
431
432rtems_status_code
433rtems_disk_release(rtems_disk_device *dd)
434{
435    rtems_interrupt_level level;
436    rtems_interrupt_disable(level);
437    dd->uses--;
438    rtems_interrupt_enable(level);
439    return RTEMS_SUCCESSFUL;
440}
441
442rtems_disk_device *
443rtems_disk_next(dev_t dev)
444{
445    rtems_device_major_number major;
446    rtems_device_minor_number minor;
447    rtems_disk_device_table *dtab;
448
449    dev++;
450    rtems_filesystem_split_dev_t (dev, major, minor);
451
452    if (major >= disktab_size)
453        return NULL;
454
455    dtab = disktab + major;
456    while (true)
457    {
458        if ((dtab == NULL) || (minor > dtab->size))
459        {
460             major++; minor = 0;
461             if (major >= disktab_size)
462                 return NULL;
463             dtab = disktab + major;
464        }
465        else if (dtab->minor[minor] == NULL)
466        {
467            minor++;
468        }
469        else
470            return dtab->minor[minor];
471    }
472}
473
474rtems_status_code
475rtems_disk_io_initialize(void)
476{
477    rtems_status_code rc;
478
479    if (disk_io_initialized)
480        return RTEMS_SUCCESSFUL;
481
482    disktab_size = DISKTAB_INITIAL_SIZE;
483    disktab = calloc(disktab_size, sizeof(rtems_disk_device_table));
484    if (disktab == NULL)
485        return RTEMS_NO_MEMORY;
486
487    diskdevs_protected = false;
488    rc = rtems_semaphore_create(
489        rtems_build_name('D', 'D', 'E', 'V'), 1,
490        RTEMS_FIFO | RTEMS_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
491        RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0, &diskdevs_mutex);
492
493    if (rc != RTEMS_SUCCESSFUL)
494    {
495        free(disktab);
496        return rc;
497    }
498
499    rc = rtems_bdbuf_init();
500
501    if (rc != RTEMS_SUCCESSFUL)
502    {
503        rtems_semaphore_delete(diskdevs_mutex);
504        free(disktab);
505        return rc;
506    }
507
508    disk_io_initialized = 1;
509    return RTEMS_SUCCESSFUL;
510}
511
512rtems_status_code
513rtems_disk_io_done(void)
514{
515    rtems_device_major_number maj;
516    rtems_device_minor_number min;
517    rtems_status_code rc;
518
519    /* Free data structures */
520    for (maj = 0; maj < disktab_size; maj++)
521    {
522        rtems_disk_device_table *dtab = disktab + maj;
523        if (dtab != NULL)
524        {
525            for (min = 0; min < dtab->size; min++)
526            {
527                rtems_disk_device *dd = dtab->minor[min];
528                unlink(dd->name);
529                free(dd->name);
530                free(dd);
531            }
532            free(dtab);
533        }
534    }
535    free(disktab);
536
537    rc = rtems_semaphore_delete(diskdevs_mutex);
538
539    disk_io_initialized = 0;
540    return rc;
541}
Note: See TracBrowser for help on using the repository browser.