source: rtems/cpukit/libblock/src/diskdevs.c @ 57aa979

4.104.115
Last change on this file since 57aa979 was 57aa979, checked in by Chris Johns <chrisj@…>, on 04/29/09 at 08:51:07

2009-04-29 Sebastian Huber <sebastian.huber@…>

  • sapi/include/confdefs.h, libblock/include/rtems/bdbuf.h: Changed type of rtems_bdbuf_pool_configuration_size to size_t.
  • libblock/include/rtems/bdbuf.h, libblock/include/rtems/blkdev.h, libblock/include/rtems/diskdevs.h, libblock/src/bdbuf.c, libblock/src/blkdev.c, libblock/src/diskdevs.c: Buffer pool allocation is now cache aligned. The cache functions are currently not available on all platforms so the cache line size is fixed to 32 bytes for now. Changed various integer types which refer to block sizes, numbers and indexes. Fixed logical block indexes in buffer get and read function. It is now possible to delete logical disks. Modified documentation
  • Property mode set to 100644
File size: 13.7 KB
Line 
1/**
2 * @file
3 *
4 * Block device disk management.
5 */
6 
7/*
8 * diskdevs.c - Physical and logical block devices (disks) support
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    int bs_log2;
230    int i;
231    rtems_disk_device *dd;
232    rtems_status_code rc;
233    rtems_bdpool_id pool;
234    rtems_device_major_number major;
235    rtems_device_minor_number minor;
236
237    rtems_filesystem_split_dev_t (dev, major, minor);
238
239
240    for (bs_log2 = 0, i = block_size; (i & 1) == 0; i >>= 1, bs_log2++);
241    if ((bs_log2 < 9) || (i != 1)) /* block size < 512 or not power of 2 */
242        return RTEMS_INVALID_NUMBER;
243
244    rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
245    if (rc != RTEMS_SUCCESSFUL)
246        return rc;
247    diskdevs_protected = true;
248
249    rc = rtems_bdbuf_find_pool(block_size, &pool);
250    if (rc != RTEMS_SUCCESSFUL)
251    {
252        diskdevs_protected = false;
253        rtems_semaphore_release(diskdevs_mutex);
254        return rc;
255    }
256
257    rc = create_disk(dev, name, &dd);
258    if (rc != RTEMS_SUCCESSFUL)
259    {
260        diskdevs_protected = false;
261        rtems_semaphore_release(diskdevs_mutex);
262        return rc;
263    }
264
265    dd->phys_dev = dd;
266    dd->uses = 0;
267    dd->start = 0;
268    dd->size = disk_size;
269    dd->block_size = block_size;
270    dd->block_size_log2 = bs_log2;
271    dd->ioctl = handler;
272    dd->pool = pool;
273
274    rc = rtems_io_register_name(name, major, minor);
275
276    if (handler (dd->phys_dev->dev,
277                 RTEMS_BLKDEV_CAPABILITIES,
278                 &dd->capabilities) < 0)
279      dd->capabilities = 0;
280   
281    diskdevs_protected = false;
282    rtems_semaphore_release(diskdevs_mutex);
283
284    return rc;
285}
286
287rtems_status_code rtems_disk_create_log(
288  dev_t dev,
289  dev_t phys,
290  rtems_blkdev_bnum start,
291  rtems_blkdev_bnum size,
292  const char *name
293)
294{
295  rtems_disk_device *dd = NULL;
296  rtems_disk_device *pdd = NULL;
297  rtems_status_code rc = RTEMS_SUCCESSFUL;
298  rtems_device_major_number major = 0;
299  rtems_device_minor_number minor = 0;
300  rtems_blkdev_bnum end = start + size;
301
302  rtems_filesystem_split_dev_t (dev, major, minor);
303
304  rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
305  if (rc != RTEMS_SUCCESSFUL) {
306    return rc;
307  }
308
309  diskdevs_protected = true;
310
311  pdd = get_disk_entry(phys);
312  if (
313    pdd == NULL
314      || pdd != pdd->phys_dev
315      || start >= pdd->size
316      || end <= start
317      || end > pdd->size
318  ) {
319    diskdevs_protected = false;
320    rtems_semaphore_release(diskdevs_mutex);
321    return RTEMS_INVALID_NUMBER;
322  }
323
324  rc = create_disk(dev, name, &dd);
325  if (rc != RTEMS_SUCCESSFUL) {
326    diskdevs_protected = false;
327    rtems_semaphore_release(diskdevs_mutex);
328    return rc;
329  }
330
331  dd->phys_dev = pdd;
332  dd->uses = 0;
333  dd->start = start;
334  dd->size = size;
335  dd->block_size = pdd->block_size;
336  dd->block_size_log2 = pdd->block_size_log2;
337  dd->ioctl = pdd->ioctl;
338
339  rc = rtems_io_register_name(name, major, minor);
340
341  diskdevs_protected = false;
342  rc = rtems_semaphore_release(diskdevs_mutex);
343
344  return rc;
345}
346
347rtems_status_code
348rtems_disk_delete(dev_t dev)
349{
350  rtems_status_code rc = RTEMS_SUCCESSFUL;
351  rtems_device_major_number maj = 0;
352  rtems_device_minor_number min = 0;
353  rtems_disk_device *dd = NULL;
354  bool physical_disk = true;
355
356  rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
357  if (rc != RTEMS_SUCCESSFUL) {
358    return rc;
359  }
360  diskdevs_protected = true;
361
362  /* Check if we have a physical or logical disk */
363  dd = get_disk_entry(dev);
364  if (dd == NULL) {
365    return RTEMS_INVALID_NUMBER;
366  }
367  physical_disk = dd->phys_dev == dd;
368
369  if (physical_disk) {
370    unsigned used = 0;
371
372    /* Check if this device is in use -- calculate usage counter */
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            used += dd->uses;
380          }
381        }
382      }
383    }
384
385    if (used != 0) {
386      diskdevs_protected = false;
387      rtems_semaphore_release(diskdevs_mutex);
388      return RTEMS_RESOURCE_IN_USE;
389    }
390
391    /* Delete this device and all of its logical devices */
392    for (maj = 0; maj < disktab_size; maj++) {
393      rtems_disk_device_table *dtab = disktab + maj;
394      if (dtab != NULL) {
395        for (min = 0; min < dtab->size; min++) {
396          dd = dtab->minor[min];
397          if ((dd != NULL) && (dd->phys_dev->dev == dev)) {
398            unlink(dd->name);
399            free(dd->name);
400            free(dd);
401            dtab->minor[min] = NULL;
402          }
403        }
404      }
405    }
406  } else {
407    rtems_filesystem_split_dev_t(dev, maj, min);
408    disktab[maj].minor[min] = NULL;
409    unlink(dd->name);
410    free(dd->name);
411    free(dd);
412  }
413
414  diskdevs_protected = false;
415  rc = rtems_semaphore_release(diskdevs_mutex);
416  return rc;
417}
418
419rtems_disk_device *
420rtems_disk_obtain(dev_t dev)
421{
422    rtems_interrupt_level level;
423    rtems_disk_device *dd;
424    rtems_status_code rc;
425
426    rtems_interrupt_disable(level);
427    if (diskdevs_protected)
428    {
429        rtems_interrupt_enable(level);
430        rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT,
431                                    RTEMS_NO_TIMEOUT);
432        if (rc != RTEMS_SUCCESSFUL)
433            return NULL;
434        diskdevs_protected = true;
435        dd = get_disk_entry(dev);
436        dd->uses++;
437        diskdevs_protected = false;
438        rtems_semaphore_release(diskdevs_mutex);
439        return dd;
440    }
441    else
442    {
443        /* Frequent and quickest case */
444        dd = get_disk_entry(dev);
445        dd->uses++;
446        rtems_interrupt_enable(level);
447        return dd;
448    }
449}
450
451rtems_status_code
452rtems_disk_release(rtems_disk_device *dd)
453{
454    rtems_interrupt_level level;
455    rtems_interrupt_disable(level);
456    dd->uses--;
457    rtems_interrupt_enable(level);
458    return RTEMS_SUCCESSFUL;
459}
460
461rtems_disk_device *
462rtems_disk_next(dev_t dev)
463{
464    rtems_device_major_number major;
465    rtems_device_minor_number minor;
466    rtems_disk_device_table *dtab;
467
468    dev++;
469    rtems_filesystem_split_dev_t (dev, major, minor);
470
471    if (major >= disktab_size)
472        return NULL;
473
474    dtab = disktab + major;
475    while (true)
476    {
477        if ((dtab == NULL) || (minor > dtab->size))
478        {
479             major++; minor = 0;
480             if (major >= disktab_size)
481                 return NULL;
482             dtab = disktab + major;
483        }
484        else if (dtab->minor[minor] == NULL)
485        {
486            minor++;
487        }
488        else
489            return dtab->minor[minor];
490    }
491}
492
493rtems_status_code
494rtems_disk_io_initialize(void)
495{
496    rtems_status_code rc;
497
498    if (disk_io_initialized)
499        return RTEMS_SUCCESSFUL;
500
501    disktab_size = DISKTAB_INITIAL_SIZE;
502    disktab = calloc(disktab_size, sizeof(rtems_disk_device_table));
503    if (disktab == NULL)
504        return RTEMS_NO_MEMORY;
505
506    diskdevs_protected = false;
507    rc = rtems_semaphore_create(
508        rtems_build_name('D', 'D', 'E', 'V'), 1,
509        RTEMS_FIFO | RTEMS_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
510        RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0, &diskdevs_mutex);
511
512    if (rc != RTEMS_SUCCESSFUL)
513    {
514        free(disktab);
515        return rc;
516    }
517
518    rc = rtems_bdbuf_init();
519
520    if (rc != RTEMS_SUCCESSFUL)
521    {
522        rtems_semaphore_delete(diskdevs_mutex);
523        free(disktab);
524        return rc;
525    }
526
527    disk_io_initialized = 1;
528    return RTEMS_SUCCESSFUL;
529}
530
531rtems_status_code
532rtems_disk_io_done(void)
533{
534    rtems_device_major_number maj;
535    rtems_device_minor_number min;
536    rtems_status_code rc;
537
538    /* Free data structures */
539    for (maj = 0; maj < disktab_size; maj++)
540    {
541        rtems_disk_device_table *dtab = disktab + maj;
542        if (dtab != NULL)
543        {
544            for (min = 0; min < dtab->size; min++)
545            {
546                rtems_disk_device *dd = dtab->minor[min];
547                unlink(dd->name);
548                free(dd->name);
549                free(dd);
550            }
551            free(dtab);
552        }
553    }
554    free(disktab);
555
556    rc = rtems_semaphore_delete(diskdevs_mutex);
557
558    /* XXX bdbuf should be released too! */
559    disk_io_initialized = 0;
560    return rc;
561}
Note: See TracBrowser for help on using the repository browser.