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

4.104.11
Last change on this file since e41369ef was e41369ef, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on Oct 20, 2009 at 7:53:19 AM
  • libblock/include/rtems/diskdevs.h: Documentation. Added field to rtems_disk_device.
  • libblock/include/rtems/blkdev.h: New request code RTEMS_BLKIO_DELETED.
  • libblock/src/diskdevs.c: Major rewrite. Changed the way disks are deleted. Disks will be now deleted if they are not in use or upon last release. The IO control handler will be invoked if a physical disk is deleted with the RTEMS_BLKIO_DELETED request code. Logical disks increase now the usage count of the associated physical disk.
  • libblock/include/rtems/ramdisk.h: Documentation.
  • libblock/src/ramdisk-driver.c: Compile trace support conditionally.
  • Property mode set to 100644
File size: 12.4 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup rtems_disk
5 *
6 * @brief Block device disk management implementation.
7 */
8 
9/*
10 * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
11 * Author: Victor V. Vengerov <vvv@oktet.ru>
12 *
13 * Copyright (c) 2009 embedded brains GmbH.
14 *
15 * @(#) $Id$
16 */
17
18#if HAVE_CONFIG_H
19#include "config.h"
20#endif
21
22#include <stdlib.h>
23#include <unistd.h>
24#include <string.h>
25
26#include <rtems.h>
27#include <rtems/libio.h>
28#include <rtems/diskdevs.h>
29#include <rtems/blkdev.h>
30#include <rtems/bdbuf.h>
31
32#define DISKTAB_INITIAL_SIZE 8
33
34/* Table of disk devices having the same major number */
35typedef struct rtems_disk_device_table {
36  rtems_disk_device **minor; /* minor-indexed disk device table */
37  rtems_device_minor_number size; /* Number of entries in the table */
38} rtems_disk_device_table;
39
40/* Pointer to [major].minor[minor] indexed array of disk devices */
41static rtems_disk_device_table *disktab;
42
43/* Number of allocated entries in disktab table */
44static rtems_device_major_number disktab_size;
45
46/* Mutual exclusion semaphore for disk devices table */
47static rtems_id diskdevs_mutex;
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
62static rtems_status_code
63disk_lock(void)
64{
65  rtems_status_code sc = RTEMS_SUCCESSFUL;
66
67  sc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
68  if (sc == RTEMS_SUCCESSFUL) {
69    diskdevs_protected = true;
70
71    return RTEMS_SUCCESSFUL;
72  } else {
73    return RTEMS_NOT_CONFIGURED;
74  }
75}
76
77static void
78disk_unlock(void)
79{
80  rtems_status_code sc = RTEMS_SUCCESSFUL;
81
82  diskdevs_protected = false;
83
84  sc = rtems_semaphore_release(diskdevs_mutex);
85  if (sc != RTEMS_SUCCESSFUL) {
86    /* FIXME: Error number */
87    rtems_fatal_error_occurred(0xdeadbeef);
88  }
89}
90
91static rtems_disk_device *
92get_disk_entry(dev_t dev)
93{
94  rtems_device_major_number major = 0;
95  rtems_device_minor_number minor = 0;
96
97  rtems_filesystem_split_dev_t(dev, major, minor);
98
99  if (major < disktab_size && disktab != NULL) {
100    rtems_disk_device_table *dtab = disktab + major;
101
102    if (minor < dtab->size && dtab->minor != NULL) {
103      rtems_disk_device *dd = dtab->minor [minor];
104
105      if (dd != NULL && !dd->deleted) {
106        ++dd->uses;
107
108        return dd;
109      }
110    }
111  }
112
113  return NULL;
114}
115
116static rtems_disk_device **
117create_disk_table_entry(dev_t dev)
118{
119  rtems_device_major_number major = 0;
120  rtems_device_minor_number minor = 0;
121
122  rtems_filesystem_split_dev_t(dev, major, minor);
123
124  if (major >= disktab_size) {
125    rtems_disk_device_table *table = disktab;
126    rtems_device_major_number old_size = disktab_size;
127    rtems_device_major_number new_size = 2 * old_size;
128
129    if (major >= new_size) {
130      new_size = major + 1;
131    }
132
133    table = realloc(table, new_size * sizeof(*table));
134    if (table == NULL) {
135      return NULL;
136    }
137
138    memset(table + old_size, 0, (new_size - old_size) * sizeof(*table));
139    disktab = table;
140    disktab_size = new_size;
141  }
142
143  if (disktab [major].minor == NULL || minor >= disktab[major].size) {
144    rtems_disk_device **table = disktab [major].minor;
145    rtems_device_minor_number old_size = disktab [major].size;
146    rtems_device_minor_number new_size = 0;
147
148    if (old_size == 0) {
149      new_size = DISKTAB_INITIAL_SIZE;
150    } else {
151      new_size = 2 * old_size;
152    }
153    if (minor >= new_size) {
154      new_size = minor + 1;
155    }
156
157    table = realloc(table, new_size * sizeof(*table));
158    if (table == NULL) {
159      return NULL;
160    }
161
162    memset(table + old_size, 0, (new_size - old_size) * sizeof(*table));
163    disktab [major].minor = table;
164    disktab [major].size = new_size;
165  }
166
167  return disktab [major].minor + minor;
168}
169
170static rtems_status_code
171create_disk(dev_t dev, const char *name, rtems_disk_device **dd_ptr)
172{
173  rtems_status_code sc = RTEMS_SUCCESSFUL;
174  rtems_disk_device **dd_entry = create_disk_table_entry(dev);
175  rtems_disk_device *dd = NULL;
176  char *alloc_name = NULL;
177
178  if (dd_entry == NULL) {
179    return RTEMS_NO_MEMORY;
180  }
181
182  if (*dd_entry != NULL) {
183    return RTEMS_RESOURCE_IN_USE;
184  }
185
186  dd = malloc(sizeof(*dd));
187  if (dd == NULL) {
188    return RTEMS_NO_MEMORY;
189  }
190
191  if (name != NULL) {
192    alloc_name = strdup(name);
193   
194    if (alloc_name == NULL) {
195      free(dd);
196
197      return RTEMS_NO_MEMORY;
198    }
199  }
200
201  if (name != NULL) {
202    rtems_device_major_number major = 0;
203    rtems_device_minor_number minor = 0;
204
205    rtems_filesystem_split_dev_t(dev, major, minor);
206
207    sc = rtems_io_register_name(name, major, minor);
208    if (sc != RTEMS_SUCCESSFUL) {
209      free(alloc_name);
210      free(dd);
211
212      return RTEMS_UNSATISFIED;
213    }
214  }
215
216  dd->dev = dev;
217  dd->name = alloc_name;
218  dd->uses = 0;
219  dd->deleted = false;
220
221  *dd_entry = dd;
222  *dd_ptr = dd;
223
224  return RTEMS_SUCCESSFUL;
225}
226
227rtems_status_code rtems_disk_create_phys(
228  dev_t dev,
229  uint32_t block_size,
230  rtems_blkdev_bnum block_count,
231  rtems_block_device_ioctl handler,
232  void *driver_data,
233  const char *name
234)
235{
236  rtems_disk_device *dd = NULL;
237  rtems_status_code sc = RTEMS_SUCCESSFUL;
238
239  if (handler == NULL) {
240    return RTEMS_INVALID_ADDRESS;
241  }
242
243  if (block_size == 0) {
244    return RTEMS_INVALID_NUMBER;
245  }
246
247  sc = disk_lock();
248  if (sc != RTEMS_SUCCESSFUL) {
249    return sc;
250  }
251
252  sc = create_disk(dev, name, &dd);
253  if (sc != RTEMS_SUCCESSFUL) {
254    disk_unlock();
255
256    return sc;
257  }
258
259  dd->phys_dev = dd;
260  dd->start = 0;
261  dd->size = block_count;
262  dd->block_size = dd->media_block_size = block_size;
263  dd->ioctl = handler;
264  dd->driver_data = driver_data;
265
266  if ((*handler)(dd, RTEMS_BLKDEV_CAPABILITIES, &dd->capabilities) < 0) {
267    dd->capabilities = 0;
268  }
269 
270  disk_unlock();
271
272  return RTEMS_SUCCESSFUL;
273}
274
275static bool
276is_physical_disk(const rtems_disk_device *dd)
277{
278  return dd->phys_dev == dd;
279}
280
281rtems_status_code rtems_disk_create_log(
282  dev_t dev,
283  dev_t phys,
284  rtems_blkdev_bnum begin_block,
285  rtems_blkdev_bnum block_count,
286  const char *name
287)
288{
289  rtems_status_code sc = RTEMS_SUCCESSFUL;
290  rtems_disk_device *physical_disk = NULL;
291  rtems_disk_device *dd = NULL;
292  rtems_blkdev_bnum end_block = begin_block + block_count;
293
294  sc = disk_lock();
295  if (sc != RTEMS_SUCCESSFUL) {
296    return sc;
297  }
298
299  physical_disk = get_disk_entry(phys);
300  if (physical_disk == NULL || !is_physical_disk(physical_disk)) {
301    if (physical_disk != NULL) {
302      --physical_disk->uses;
303    }
304    disk_unlock();
305
306    return RTEMS_INVALID_ID;
307  }
308
309  if (
310    begin_block >= physical_disk->size
311      || end_block <= begin_block
312      || end_block > physical_disk->size
313  ) {
314    --physical_disk->uses;
315    disk_unlock();
316
317    return RTEMS_INVALID_NUMBER;
318  }
319
320  sc = create_disk(dev, name, &dd);
321  if (sc != RTEMS_SUCCESSFUL) {
322    --physical_disk->uses;
323    disk_unlock();
324
325    return sc;
326  }
327
328  dd->phys_dev = physical_disk;
329  dd->start = begin_block;
330  dd->size = block_count;
331  dd->block_size = dd->media_block_size = physical_disk->block_size;
332  dd->ioctl = physical_disk->ioctl;
333  dd->driver_data = physical_disk->driver_data;
334
335  disk_unlock();
336
337  return RTEMS_SUCCESSFUL;
338}
339
340static void
341free_disk_device(rtems_disk_device *dd)
342{
343  if (is_physical_disk(dd)) {
344    (*dd->ioctl)(dd, RTEMS_BLKIO_DELETED, NULL);
345  }
346  if (dd->name != NULL) {
347    unlink(dd->name);
348    free(dd->name);
349  }
350  free(dd);
351}
352
353static void
354rtems_disk_cleanup(rtems_disk_device *disk_to_remove)
355{
356  rtems_disk_device *const physical_disk = disk_to_remove->phys_dev;
357  rtems_device_major_number major = 0;
358  rtems_device_minor_number minor = 0;
359
360  if (physical_disk->deleted) {
361    dev_t dev = physical_disk->dev;
362    unsigned deleted_count = 0;
363
364    for (major = 0; major < disktab_size; ++major) {
365      rtems_disk_device_table *dtab = disktab + major;
366
367      for (minor = 0; minor < dtab->size; ++minor) {
368        rtems_disk_device *dd = dtab->minor [minor];
369
370        if (dd != NULL && dd->phys_dev->dev == dev && dd != physical_disk) {
371          if (dd->uses == 0) {
372            ++deleted_count;
373            dtab->minor [minor] = NULL;
374            free_disk_device(dd);
375          } else {
376            dd->deleted = true;
377          }
378        }
379      }
380    }
381
382    physical_disk->uses -= deleted_count;
383    if (physical_disk->uses == 0) {
384      rtems_filesystem_split_dev_t(physical_disk->dev, major, minor);
385      disktab [major].minor [minor] = NULL;
386      free_disk_device(physical_disk);
387    }
388  } else {
389    if (disk_to_remove->uses == 0) {
390      --physical_disk->uses;
391      rtems_filesystem_split_dev_t(disk_to_remove->dev, major, minor);
392      disktab [major].minor [minor] = NULL;
393      free_disk_device(disk_to_remove);
394    }
395  }
396}
397
398rtems_status_code
399rtems_disk_delete(dev_t dev)
400{
401  rtems_status_code sc = RTEMS_SUCCESSFUL;
402  rtems_disk_device *dd = NULL;
403
404  sc = disk_lock();
405  if (sc != RTEMS_SUCCESSFUL) {
406    return sc;
407  }
408
409  dd = get_disk_entry(dev);
410  if (dd == NULL) {
411    disk_unlock();
412
413    return RTEMS_INVALID_ID;
414  }
415
416  --dd->uses;
417  dd->deleted = true;
418  rtems_disk_cleanup(dd);
419
420  disk_unlock();
421
422  return RTEMS_SUCCESSFUL;
423}
424
425rtems_disk_device *
426rtems_disk_obtain(dev_t dev)
427{
428  rtems_status_code sc = RTEMS_SUCCESSFUL;
429  rtems_disk_device *dd = NULL;
430  rtems_interrupt_level level;
431
432  rtems_interrupt_disable(level);
433  if (!diskdevs_protected) {
434    /* Frequent and quickest case */
435    dd = get_disk_entry(dev);
436    rtems_interrupt_enable(level);
437  } else {
438    rtems_interrupt_enable(level);
439
440    sc = disk_lock();
441    if (sc == RTEMS_SUCCESSFUL) {
442      dd = get_disk_entry(dev);
443      disk_unlock();
444    }
445  }
446
447  return dd;
448}
449
450rtems_status_code
451rtems_disk_release(rtems_disk_device *dd)
452{
453  rtems_interrupt_level level;
454  dev_t dev = dd->dev;
455  unsigned uses = 0;
456  bool deleted = false;
457
458  rtems_interrupt_disable(level);
459  uses = --dd->uses;
460  deleted = dd->deleted;
461  rtems_interrupt_enable(level);
462
463  if (uses == 0 && deleted) {
464    rtems_disk_delete(dev);
465  }
466
467  return RTEMS_SUCCESSFUL;
468}
469
470rtems_disk_device *
471rtems_disk_next(dev_t dev)
472{
473    rtems_device_major_number major;
474    rtems_device_minor_number minor;
475    rtems_disk_device_table *dtab;
476
477    dev++;
478    rtems_filesystem_split_dev_t (dev, major, minor);
479
480    if (major >= disktab_size)
481        return NULL;
482
483    dtab = disktab + major;
484    while (true)
485    {
486        if ((dtab == NULL) || (minor > dtab->size))
487        {
488             major++; minor = 0;
489             if (major >= disktab_size)
490                 return NULL;
491             dtab = disktab + major;
492        }
493        else if (dtab->minor[minor] == NULL)
494        {
495            minor++;
496        }
497        else
498            return dtab->minor[minor];
499    }
500}
501
502rtems_status_code
503rtems_disk_io_initialize(void)
504{
505  rtems_status_code sc = RTEMS_SUCCESSFUL;
506  rtems_device_major_number size = DISKTAB_INITIAL_SIZE;
507
508  if (disktab_size > 0) {
509    return RTEMS_SUCCESSFUL;
510  }
511
512  disktab = calloc(size, sizeof(rtems_disk_device_table));
513  if (disktab == NULL) {
514    return RTEMS_NO_MEMORY;
515  }
516
517  diskdevs_protected = false;
518  sc = rtems_semaphore_create(
519    rtems_build_name('D', 'D', 'E', 'V'),
520    1,
521    RTEMS_FIFO | RTEMS_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY
522      | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
523    0,
524    &diskdevs_mutex
525  );
526  if (sc != RTEMS_SUCCESSFUL) {
527    free(disktab);
528
529    return RTEMS_NO_MEMORY;
530  }
531
532  sc = rtems_bdbuf_init();
533  if (sc != RTEMS_SUCCESSFUL) {
534    rtems_semaphore_delete(diskdevs_mutex);
535    free(disktab);
536
537    return RTEMS_UNSATISFIED;
538  }
539
540  disktab_size = size;
541
542  return RTEMS_SUCCESSFUL;
543}
544
545rtems_status_code
546rtems_disk_io_done(void)
547{
548  rtems_device_major_number major = 0;
549  rtems_device_minor_number minor = 0;
550
551  for (major = 0; major < disktab_size; ++major) {
552    rtems_disk_device_table *dtab = disktab + major;
553
554    for (minor = 0; minor < dtab->size; ++minor) {
555      rtems_disk_device *dd = dtab->minor [minor];
556
557      if (dd != NULL) {
558        free_disk_device(dd);
559      }
560    }
561    free(dtab->minor);
562  }
563  free(disktab);
564
565  rtems_semaphore_delete(diskdevs_mutex);
566
567  diskdevs_mutex = RTEMS_ID_NONE;
568  disktab = NULL;
569  disktab_size = 0;
570
571  return RTEMS_SUCCESSFUL;
572}
Note: See TracBrowser for help on using the repository browser.