source: rtems/cpukit/libblock/src/diskdevs.c @ 9b4422a2

4.115
Last change on this file since 9b4422a2 was 9b4422a2, checked in by Joel Sherrill <joel.sherrill@…>, on 05/03/12 at 15:09:24

Remove All CVS Id Strings Possible Using a Script

Script does what is expected and tries to do it as
smartly as possible.

+ remove occurrences of two blank comment lines

next to each other after Id string line removed.

+ remove entire comment blocks which only exited to

contain CVS Ids

+ If the processing left a blank line at the top of

a file, it was removed.

  • Property mode set to 100644
File size: 12.9 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
16#if HAVE_CONFIG_H
17#include "config.h"
18#endif
19
20#include <stdlib.h>
21#include <unistd.h>
22#include <string.h>
23
24#include <rtems.h>
25#include <rtems/libio.h>
26#include <rtems/diskdevs.h>
27#include <rtems/blkdev.h>
28#include <rtems/bdbuf.h>
29
30#define DISKTAB_INITIAL_SIZE 8
31
32/* Table of disk devices having the same major number */
33typedef struct rtems_disk_device_table {
34  rtems_disk_device **minor; /* minor-indexed disk device table */
35  rtems_device_minor_number size; /* Number of entries in the table */
36} rtems_disk_device_table;
37
38/* Pointer to [major].minor[minor] indexed array of disk devices */
39static rtems_disk_device_table *disktab;
40
41/* Number of allocated entries in disktab table */
42static rtems_device_major_number disktab_size;
43
44/* Mutual exclusion semaphore for disk devices table */
45static rtems_id diskdevs_mutex;
46
47/* diskdevs data structures protection flag.
48 * Normally, only table lookup operations performed. It is quite fast, so
49 * it is possible to done lookups when interrupts are disabled, avoiding
50 * obtaining the semaphore. This flags sets immediately after entering in
51 * mutex-protected section and cleared before leaving this section in
52 * "big" primitives like add/delete new device etc. Lookup function first
53 * disable interrupts and check this flag. If it is set, lookup function
54 * will be blocked on semaphore and lookup operation will be performed in
55 * semaphore-protected code. If it is not set (very-very frequent case),
56 * we can do lookup safely, enable interrupts and return result.
57 */
58static volatile bool diskdevs_protected;
59
60static rtems_status_code
61disk_lock(void)
62{
63  rtems_status_code sc = RTEMS_SUCCESSFUL;
64
65  sc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
66  if (sc == RTEMS_SUCCESSFUL) {
67    diskdevs_protected = true;
68
69    return RTEMS_SUCCESSFUL;
70  } else {
71    return RTEMS_NOT_CONFIGURED;
72  }
73}
74
75static void
76disk_unlock(void)
77{
78  rtems_status_code sc = RTEMS_SUCCESSFUL;
79
80  diskdevs_protected = false;
81
82  sc = rtems_semaphore_release(diskdevs_mutex);
83  if (sc != RTEMS_SUCCESSFUL) {
84    /* FIXME: Error number */
85    rtems_fatal_error_occurred(0xdeadbeef);
86  }
87}
88
89static rtems_disk_device *
90get_disk_entry(dev_t dev, bool lookup_only)
91{
92  rtems_device_major_number major = 0;
93  rtems_device_minor_number minor = 0;
94
95  rtems_filesystem_split_dev_t(dev, major, minor);
96
97  if (major < disktab_size && disktab != NULL) {
98    rtems_disk_device_table *dtab = disktab + major;
99
100    if (minor < dtab->size && dtab->minor != NULL) {
101      rtems_disk_device *dd = dtab->minor [minor];
102
103      if (dd != NULL && !lookup_only) {
104        if (!dd->deleted) {
105          ++dd->uses;
106        } else {
107          dd = NULL;
108        }
109      }
110
111      return dd;
112    }
113  }
114
115  return NULL;
116}
117
118static rtems_disk_device **
119create_disk_table_entry(dev_t dev)
120{
121  rtems_device_major_number major = 0;
122  rtems_device_minor_number minor = 0;
123
124  rtems_filesystem_split_dev_t(dev, major, minor);
125
126  if (major >= disktab_size) {
127    rtems_disk_device_table *table = disktab;
128    rtems_device_major_number old_size = disktab_size;
129    rtems_device_major_number new_size = 2 * old_size;
130
131    if (major >= new_size) {
132      new_size = major + 1;
133    }
134
135    table = realloc(table, new_size * sizeof(*table));
136    if (table == NULL) {
137      return NULL;
138    }
139
140    memset(table + old_size, 0, (new_size - old_size) * sizeof(*table));
141    disktab = table;
142    disktab_size = new_size;
143  }
144
145  if (disktab [major].minor == NULL || minor >= disktab[major].size) {
146    rtems_disk_device **table = disktab [major].minor;
147    rtems_device_minor_number old_size = disktab [major].size;
148    rtems_device_minor_number new_size = 0;
149
150    if (old_size == 0) {
151      new_size = DISKTAB_INITIAL_SIZE;
152    } else {
153      new_size = 2 * old_size;
154    }
155    if (minor >= new_size) {
156      new_size = minor + 1;
157    }
158
159    table = realloc(table, new_size * sizeof(*table));
160    if (table == NULL) {
161      return NULL;
162    }
163
164    memset(table + old_size, 0, (new_size - old_size) * sizeof(*table));
165    disktab [major].minor = table;
166    disktab [major].size = new_size;
167  }
168
169  return disktab [major].minor + minor;
170}
171
172static rtems_status_code
173create_disk(dev_t dev, const char *name, rtems_disk_device **dd_ptr)
174{
175  rtems_disk_device **dd_entry = create_disk_table_entry(dev);
176  rtems_disk_device *dd = NULL;
177  char *alloc_name = NULL;
178
179  if (dd_entry == NULL) {
180    return RTEMS_NO_MEMORY;
181  }
182
183  if (*dd_entry != NULL) {
184    return RTEMS_RESOURCE_IN_USE;
185  }
186
187  dd = malloc(sizeof(*dd));
188  if (dd == NULL) {
189    return RTEMS_NO_MEMORY;
190  }
191
192  if (name != NULL) {
193    alloc_name = strdup(name);
194
195    if (alloc_name == NULL) {
196      free(dd);
197
198      return RTEMS_NO_MEMORY;
199    }
200  }
201
202  if (name != NULL) {
203    if (mknod(alloc_name, 0777 | S_IFBLK, dev) < 0) {
204      free(alloc_name);
205      free(dd);
206      return RTEMS_UNSATISFIED;
207    }
208  }
209
210  dd->dev = dev;
211  dd->name = alloc_name;
212  dd->uses = 0;
213  dd->deleted = false;
214
215  *dd_entry = dd;
216  *dd_ptr = dd;
217
218  return RTEMS_SUCCESSFUL;
219}
220
221static int null_handler(
222  rtems_disk_device *dd,
223  uint32_t req,
224  void *argp
225)
226{
227  return -1;
228}
229
230rtems_status_code rtems_disk_create_phys(
231  dev_t dev,
232  uint32_t block_size,
233  rtems_blkdev_bnum block_count,
234  rtems_block_device_ioctl handler,
235  void *driver_data,
236  const char *name
237)
238{
239  rtems_disk_device *dd = NULL;
240  rtems_status_code sc = RTEMS_SUCCESSFUL;
241
242  if (handler == NULL) {
243    return RTEMS_INVALID_ADDRESS;
244  }
245
246  sc = disk_lock();
247  if (sc != RTEMS_SUCCESSFUL) {
248    return sc;
249  }
250
251  sc = create_disk(dev, name, &dd);
252  if (sc != RTEMS_SUCCESSFUL) {
253    disk_unlock();
254
255    return sc;
256  }
257
258  dd->phys_dev = dd;
259  dd->start = 0;
260  dd->size = block_count;
261  dd->media_block_size = block_size;
262  dd->ioctl = handler;
263  dd->driver_data = driver_data;
264
265  if ((*handler)(dd, RTEMS_BLKIO_CAPABILITIES, &dd->capabilities) < 0) {
266    dd->capabilities = 0;
267  }
268
269  sc = rtems_bdbuf_set_block_size(dd, block_size);
270  if (sc != RTEMS_SUCCESSFUL) {
271    dd->ioctl = null_handler;
272    rtems_disk_delete(dev);
273    disk_unlock();
274
275    return sc;
276  }
277
278  disk_unlock();
279
280  return RTEMS_SUCCESSFUL;
281}
282
283static bool
284is_physical_disk(const rtems_disk_device *dd)
285{
286  return dd->phys_dev == dd;
287}
288
289rtems_status_code rtems_disk_create_log(
290  dev_t dev,
291  dev_t phys,
292  rtems_blkdev_bnum begin_block,
293  rtems_blkdev_bnum block_count,
294  const char *name
295)
296{
297  rtems_status_code sc = RTEMS_SUCCESSFUL;
298  rtems_disk_device *physical_disk = NULL;
299  rtems_disk_device *dd = NULL;
300  rtems_blkdev_bnum end_block = begin_block + block_count;
301
302  sc = disk_lock();
303  if (sc != RTEMS_SUCCESSFUL) {
304    return sc;
305  }
306
307  physical_disk = get_disk_entry(phys, true);
308  if (physical_disk == NULL || !is_physical_disk(physical_disk)) {
309    disk_unlock();
310
311    return RTEMS_INVALID_ID;
312  }
313
314  if (
315    begin_block >= physical_disk->size
316      || end_block <= begin_block
317      || end_block > physical_disk->size
318  ) {
319    disk_unlock();
320
321    return RTEMS_INVALID_NUMBER;
322  }
323
324  sc = create_disk(dev, name, &dd);
325  if (sc != RTEMS_SUCCESSFUL) {
326    disk_unlock();
327
328    return sc;
329  }
330
331  dd->phys_dev = physical_disk;
332  dd->start = begin_block;
333  dd->size = block_count;
334  dd->block_size = physical_disk->block_size;
335  dd->media_block_size = physical_disk->media_block_size;
336  dd->block_to_media_block_shift = physical_disk->block_to_media_block_shift;
337  dd->bds_per_group = physical_disk->bds_per_group;
338  dd->ioctl = physical_disk->ioctl;
339  dd->driver_data = physical_disk->driver_data;
340
341  ++physical_disk->uses;
342
343  disk_unlock();
344
345  return RTEMS_SUCCESSFUL;
346}
347
348static void
349free_disk_device(rtems_disk_device *dd)
350{
351  if (is_physical_disk(dd)) {
352    (*dd->ioctl)(dd, RTEMS_BLKIO_DELETED, NULL);
353  }
354  if (dd->name != NULL) {
355    unlink(dd->name);
356    free(dd->name);
357  }
358  free(dd);
359}
360
361static void
362rtems_disk_cleanup(rtems_disk_device *disk_to_remove)
363{
364  rtems_disk_device *const physical_disk = disk_to_remove->phys_dev;
365  rtems_device_major_number major = 0;
366  rtems_device_minor_number minor = 0;
367
368  if (physical_disk->deleted) {
369    dev_t dev = physical_disk->dev;
370    unsigned deleted_count = 0;
371
372    for (major = 0; major < disktab_size; ++major) {
373      rtems_disk_device_table *dtab = disktab + major;
374
375      for (minor = 0; minor < dtab->size; ++minor) {
376        rtems_disk_device *dd = dtab->minor [minor];
377
378        if (dd != NULL && dd->phys_dev->dev == dev && dd != physical_disk) {
379          if (dd->uses == 0) {
380            ++deleted_count;
381            dtab->minor [minor] = NULL;
382            free_disk_device(dd);
383          } else {
384            dd->deleted = true;
385          }
386        }
387      }
388    }
389
390    physical_disk->uses -= deleted_count;
391    if (physical_disk->uses == 0) {
392      rtems_filesystem_split_dev_t(physical_disk->dev, major, minor);
393      disktab [major].minor [minor] = NULL;
394      free_disk_device(physical_disk);
395    }
396  } else {
397    if (disk_to_remove->uses == 0) {
398      --physical_disk->uses;
399      rtems_filesystem_split_dev_t(disk_to_remove->dev, major, minor);
400      disktab [major].minor [minor] = NULL;
401      free_disk_device(disk_to_remove);
402    }
403  }
404}
405
406rtems_status_code
407rtems_disk_delete(dev_t dev)
408{
409  rtems_status_code sc = RTEMS_SUCCESSFUL;
410  rtems_disk_device *dd = NULL;
411
412  sc = disk_lock();
413  if (sc != RTEMS_SUCCESSFUL) {
414    return sc;
415  }
416
417  dd = get_disk_entry(dev, true);
418  if (dd == NULL) {
419    disk_unlock();
420
421    return RTEMS_INVALID_ID;
422  }
423
424  dd->deleted = true;
425  rtems_disk_cleanup(dd);
426
427  disk_unlock();
428
429  return RTEMS_SUCCESSFUL;
430}
431
432rtems_disk_device *
433rtems_disk_obtain(dev_t dev)
434{
435  rtems_status_code sc = RTEMS_SUCCESSFUL;
436  rtems_disk_device *dd = NULL;
437  rtems_interrupt_level level;
438
439  rtems_interrupt_disable(level);
440  if (!diskdevs_protected) {
441    /* Frequent and quickest case */
442    dd = get_disk_entry(dev, false);
443    rtems_interrupt_enable(level);
444  } else {
445    rtems_interrupt_enable(level);
446
447    sc = disk_lock();
448    if (sc == RTEMS_SUCCESSFUL) {
449      dd = get_disk_entry(dev, false);
450      disk_unlock();
451    }
452  }
453
454  return dd;
455}
456
457rtems_status_code
458rtems_disk_release(rtems_disk_device *dd)
459{
460  rtems_interrupt_level level;
461  dev_t dev = dd->dev;
462  unsigned uses = 0;
463  bool deleted = false;
464
465  rtems_interrupt_disable(level);
466  uses = --dd->uses;
467  deleted = dd->deleted;
468  rtems_interrupt_enable(level);
469
470  if (uses == 0 && deleted) {
471    rtems_disk_delete(dev);
472  }
473
474  return RTEMS_SUCCESSFUL;
475}
476
477rtems_disk_device *
478rtems_disk_next(dev_t dev)
479{
480  rtems_status_code sc = RTEMS_SUCCESSFUL;
481  rtems_disk_device_table *dtab = NULL;
482  rtems_device_major_number major = 0;
483  rtems_device_minor_number minor = 0;
484
485  if (dev != (dev_t) -1) {
486    rtems_filesystem_split_dev_t(dev, major, minor);
487
488    /* If minor wraps around */
489    if ((minor + 1) < minor) {
490      /* If major wraps around */
491      if ((major + 1) < major) {
492        return NULL;
493      }
494      ++major;
495      minor = 0;
496    } else {
497      ++minor;
498    }
499  }
500
501  sc = disk_lock();
502  if (sc != RTEMS_SUCCESSFUL) {
503    return NULL;
504  }
505
506  if (major >= disktab_size) {
507    disk_unlock();
508
509    return NULL;
510  }
511
512  dtab = disktab + major;
513  while (true) {
514    if (dtab->minor == NULL || minor >= dtab->size) {
515       minor = 0;
516       ++major;
517       if (major >= disktab_size) {
518         disk_unlock();
519
520         return NULL;
521       }
522       dtab = disktab + major;
523    } else if (dtab->minor [minor] == NULL) {
524      ++minor;
525    } else {
526      ++dtab->minor [minor]->uses;
527      disk_unlock();
528
529      return dtab->minor [minor];
530    }
531  }
532}
533
534rtems_status_code
535rtems_disk_io_initialize(void)
536{
537  rtems_status_code sc = RTEMS_SUCCESSFUL;
538  rtems_device_major_number size = DISKTAB_INITIAL_SIZE;
539
540  if (disktab_size > 0) {
541    return RTEMS_SUCCESSFUL;
542  }
543
544  disktab = calloc(size, sizeof(rtems_disk_device_table));
545  if (disktab == NULL) {
546    return RTEMS_NO_MEMORY;
547  }
548
549  diskdevs_protected = false;
550  sc = rtems_semaphore_create(
551    rtems_build_name('D', 'D', 'E', 'V'),
552    1,
553    RTEMS_FIFO | RTEMS_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY
554      | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
555    0,
556    &diskdevs_mutex
557  );
558  if (sc != RTEMS_SUCCESSFUL) {
559    free(disktab);
560
561    return RTEMS_NO_MEMORY;
562  }
563
564  sc = rtems_bdbuf_init();
565  if (sc != RTEMS_SUCCESSFUL) {
566    rtems_semaphore_delete(diskdevs_mutex);
567    free(disktab);
568
569    return RTEMS_UNSATISFIED;
570  }
571
572  disktab_size = size;
573
574  return RTEMS_SUCCESSFUL;
575}
576
577rtems_status_code
578rtems_disk_io_done(void)
579{
580  rtems_device_major_number major = 0;
581  rtems_device_minor_number minor = 0;
582
583  for (major = 0; major < disktab_size; ++major) {
584    rtems_disk_device_table *dtab = disktab + major;
585
586    for (minor = 0; minor < dtab->size; ++minor) {
587      rtems_disk_device *dd = dtab->minor [minor];
588
589      if (dd != NULL) {
590        free_disk_device(dd);
591      }
592    }
593    free(dtab->minor);
594  }
595  free(disktab);
596
597  rtems_semaphore_delete(diskdevs_mutex);
598
599  diskdevs_mutex = RTEMS_ID_NONE;
600  disktab = NULL;
601  disktab_size = 0;
602
603  return RTEMS_SUCCESSFUL;
604}
Note: See TracBrowser for help on using the repository browser.