forked from Imagelibrary/rtems
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.
605 lines
13 KiB
C
605 lines
13 KiB
C
/**
|
|
* @file
|
|
*
|
|
* @ingroup rtems_disk
|
|
*
|
|
* @brief Block device disk management implementation.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
|
|
* Author: Victor V. Vengerov <vvv@oktet.ru>
|
|
*
|
|
* Copyright (c) 2009 embedded brains GmbH.
|
|
*/
|
|
|
|
#if HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
#include <rtems.h>
|
|
#include <rtems/libio.h>
|
|
#include <rtems/diskdevs.h>
|
|
#include <rtems/blkdev.h>
|
|
#include <rtems/bdbuf.h>
|
|
|
|
#define DISKTAB_INITIAL_SIZE 8
|
|
|
|
/* Table of disk devices having the same major number */
|
|
typedef struct rtems_disk_device_table {
|
|
rtems_disk_device **minor; /* minor-indexed disk device table */
|
|
rtems_device_minor_number size; /* Number of entries in the table */
|
|
} rtems_disk_device_table;
|
|
|
|
/* Pointer to [major].minor[minor] indexed array of disk devices */
|
|
static rtems_disk_device_table *disktab;
|
|
|
|
/* Number of allocated entries in disktab table */
|
|
static rtems_device_major_number disktab_size;
|
|
|
|
/* Mutual exclusion semaphore for disk devices table */
|
|
static rtems_id diskdevs_mutex;
|
|
|
|
/* diskdevs data structures protection flag.
|
|
* Normally, only table lookup operations performed. It is quite fast, so
|
|
* it is possible to done lookups when interrupts are disabled, avoiding
|
|
* obtaining the semaphore. This flags sets immediately after entering in
|
|
* mutex-protected section and cleared before leaving this section in
|
|
* "big" primitives like add/delete new device etc. Lookup function first
|
|
* disable interrupts and check this flag. If it is set, lookup function
|
|
* will be blocked on semaphore and lookup operation will be performed in
|
|
* semaphore-protected code. If it is not set (very-very frequent case),
|
|
* we can do lookup safely, enable interrupts and return result.
|
|
*/
|
|
static volatile bool diskdevs_protected;
|
|
|
|
static rtems_status_code
|
|
disk_lock(void)
|
|
{
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
|
|
sc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
|
if (sc == RTEMS_SUCCESSFUL) {
|
|
diskdevs_protected = true;
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
} else {
|
|
return RTEMS_NOT_CONFIGURED;
|
|
}
|
|
}
|
|
|
|
static void
|
|
disk_unlock(void)
|
|
{
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
|
|
diskdevs_protected = false;
|
|
|
|
sc = rtems_semaphore_release(diskdevs_mutex);
|
|
if (sc != RTEMS_SUCCESSFUL) {
|
|
/* FIXME: Error number */
|
|
rtems_fatal_error_occurred(0xdeadbeef);
|
|
}
|
|
}
|
|
|
|
static rtems_disk_device *
|
|
get_disk_entry(dev_t dev, bool lookup_only)
|
|
{
|
|
rtems_device_major_number major = 0;
|
|
rtems_device_minor_number minor = 0;
|
|
|
|
rtems_filesystem_split_dev_t(dev, major, minor);
|
|
|
|
if (major < disktab_size && disktab != NULL) {
|
|
rtems_disk_device_table *dtab = disktab + major;
|
|
|
|
if (minor < dtab->size && dtab->minor != NULL) {
|
|
rtems_disk_device *dd = dtab->minor [minor];
|
|
|
|
if (dd != NULL && !lookup_only) {
|
|
if (!dd->deleted) {
|
|
++dd->uses;
|
|
} else {
|
|
dd = NULL;
|
|
}
|
|
}
|
|
|
|
return dd;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static rtems_disk_device **
|
|
create_disk_table_entry(dev_t dev)
|
|
{
|
|
rtems_device_major_number major = 0;
|
|
rtems_device_minor_number minor = 0;
|
|
|
|
rtems_filesystem_split_dev_t(dev, major, minor);
|
|
|
|
if (major >= disktab_size) {
|
|
rtems_disk_device_table *table = disktab;
|
|
rtems_device_major_number old_size = disktab_size;
|
|
rtems_device_major_number new_size = 2 * old_size;
|
|
|
|
if (major >= new_size) {
|
|
new_size = major + 1;
|
|
}
|
|
|
|
table = realloc(table, new_size * sizeof(*table));
|
|
if (table == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
memset(table + old_size, 0, (new_size - old_size) * sizeof(*table));
|
|
disktab = table;
|
|
disktab_size = new_size;
|
|
}
|
|
|
|
if (disktab [major].minor == NULL || minor >= disktab[major].size) {
|
|
rtems_disk_device **table = disktab [major].minor;
|
|
rtems_device_minor_number old_size = disktab [major].size;
|
|
rtems_device_minor_number new_size = 0;
|
|
|
|
if (old_size == 0) {
|
|
new_size = DISKTAB_INITIAL_SIZE;
|
|
} else {
|
|
new_size = 2 * old_size;
|
|
}
|
|
if (minor >= new_size) {
|
|
new_size = minor + 1;
|
|
}
|
|
|
|
table = realloc(table, new_size * sizeof(*table));
|
|
if (table == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
memset(table + old_size, 0, (new_size - old_size) * sizeof(*table));
|
|
disktab [major].minor = table;
|
|
disktab [major].size = new_size;
|
|
}
|
|
|
|
return disktab [major].minor + minor;
|
|
}
|
|
|
|
static rtems_status_code
|
|
create_disk(dev_t dev, const char *name, rtems_disk_device **dd_ptr)
|
|
{
|
|
rtems_disk_device **dd_entry = create_disk_table_entry(dev);
|
|
rtems_disk_device *dd = NULL;
|
|
char *alloc_name = NULL;
|
|
|
|
if (dd_entry == NULL) {
|
|
return RTEMS_NO_MEMORY;
|
|
}
|
|
|
|
if (*dd_entry != NULL) {
|
|
return RTEMS_RESOURCE_IN_USE;
|
|
}
|
|
|
|
dd = malloc(sizeof(*dd));
|
|
if (dd == NULL) {
|
|
return RTEMS_NO_MEMORY;
|
|
}
|
|
|
|
if (name != NULL) {
|
|
alloc_name = strdup(name);
|
|
|
|
if (alloc_name == NULL) {
|
|
free(dd);
|
|
|
|
return RTEMS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
if (name != NULL) {
|
|
if (mknod(alloc_name, 0777 | S_IFBLK, dev) < 0) {
|
|
free(alloc_name);
|
|
free(dd);
|
|
return RTEMS_UNSATISFIED;
|
|
}
|
|
}
|
|
|
|
dd->dev = dev;
|
|
dd->name = alloc_name;
|
|
dd->uses = 0;
|
|
dd->deleted = false;
|
|
|
|
*dd_entry = dd;
|
|
*dd_ptr = dd;
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
static int null_handler(
|
|
rtems_disk_device *dd,
|
|
uint32_t req,
|
|
void *argp
|
|
)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
rtems_status_code rtems_disk_create_phys(
|
|
dev_t dev,
|
|
uint32_t block_size,
|
|
rtems_blkdev_bnum block_count,
|
|
rtems_block_device_ioctl handler,
|
|
void *driver_data,
|
|
const char *name
|
|
)
|
|
{
|
|
rtems_disk_device *dd = NULL;
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
|
|
if (handler == NULL) {
|
|
return RTEMS_INVALID_ADDRESS;
|
|
}
|
|
|
|
sc = disk_lock();
|
|
if (sc != RTEMS_SUCCESSFUL) {
|
|
return sc;
|
|
}
|
|
|
|
sc = create_disk(dev, name, &dd);
|
|
if (sc != RTEMS_SUCCESSFUL) {
|
|
disk_unlock();
|
|
|
|
return sc;
|
|
}
|
|
|
|
dd->phys_dev = dd;
|
|
dd->start = 0;
|
|
dd->size = block_count;
|
|
dd->media_block_size = block_size;
|
|
dd->ioctl = handler;
|
|
dd->driver_data = driver_data;
|
|
|
|
if ((*handler)(dd, RTEMS_BLKIO_CAPABILITIES, &dd->capabilities) < 0) {
|
|
dd->capabilities = 0;
|
|
}
|
|
|
|
sc = rtems_bdbuf_set_block_size(dd, block_size);
|
|
if (sc != RTEMS_SUCCESSFUL) {
|
|
dd->ioctl = null_handler;
|
|
rtems_disk_delete(dev);
|
|
disk_unlock();
|
|
|
|
return sc;
|
|
}
|
|
|
|
disk_unlock();
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
static bool
|
|
is_physical_disk(const rtems_disk_device *dd)
|
|
{
|
|
return dd->phys_dev == dd;
|
|
}
|
|
|
|
rtems_status_code rtems_disk_create_log(
|
|
dev_t dev,
|
|
dev_t phys,
|
|
rtems_blkdev_bnum begin_block,
|
|
rtems_blkdev_bnum block_count,
|
|
const char *name
|
|
)
|
|
{
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
rtems_disk_device *physical_disk = NULL;
|
|
rtems_disk_device *dd = NULL;
|
|
rtems_blkdev_bnum end_block = begin_block + block_count;
|
|
|
|
sc = disk_lock();
|
|
if (sc != RTEMS_SUCCESSFUL) {
|
|
return sc;
|
|
}
|
|
|
|
physical_disk = get_disk_entry(phys, true);
|
|
if (physical_disk == NULL || !is_physical_disk(physical_disk)) {
|
|
disk_unlock();
|
|
|
|
return RTEMS_INVALID_ID;
|
|
}
|
|
|
|
if (
|
|
begin_block >= physical_disk->size
|
|
|| end_block <= begin_block
|
|
|| end_block > physical_disk->size
|
|
) {
|
|
disk_unlock();
|
|
|
|
return RTEMS_INVALID_NUMBER;
|
|
}
|
|
|
|
sc = create_disk(dev, name, &dd);
|
|
if (sc != RTEMS_SUCCESSFUL) {
|
|
disk_unlock();
|
|
|
|
return sc;
|
|
}
|
|
|
|
dd->phys_dev = physical_disk;
|
|
dd->start = begin_block;
|
|
dd->size = block_count;
|
|
dd->block_size = physical_disk->block_size;
|
|
dd->media_block_size = physical_disk->media_block_size;
|
|
dd->block_to_media_block_shift = physical_disk->block_to_media_block_shift;
|
|
dd->bds_per_group = physical_disk->bds_per_group;
|
|
dd->ioctl = physical_disk->ioctl;
|
|
dd->driver_data = physical_disk->driver_data;
|
|
|
|
++physical_disk->uses;
|
|
|
|
disk_unlock();
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
static void
|
|
free_disk_device(rtems_disk_device *dd)
|
|
{
|
|
if (is_physical_disk(dd)) {
|
|
(*dd->ioctl)(dd, RTEMS_BLKIO_DELETED, NULL);
|
|
}
|
|
if (dd->name != NULL) {
|
|
unlink(dd->name);
|
|
free(dd->name);
|
|
}
|
|
free(dd);
|
|
}
|
|
|
|
static void
|
|
rtems_disk_cleanup(rtems_disk_device *disk_to_remove)
|
|
{
|
|
rtems_disk_device *const physical_disk = disk_to_remove->phys_dev;
|
|
rtems_device_major_number major = 0;
|
|
rtems_device_minor_number minor = 0;
|
|
|
|
if (physical_disk->deleted) {
|
|
dev_t dev = physical_disk->dev;
|
|
unsigned deleted_count = 0;
|
|
|
|
for (major = 0; major < disktab_size; ++major) {
|
|
rtems_disk_device_table *dtab = disktab + major;
|
|
|
|
for (minor = 0; minor < dtab->size; ++minor) {
|
|
rtems_disk_device *dd = dtab->minor [minor];
|
|
|
|
if (dd != NULL && dd->phys_dev->dev == dev && dd != physical_disk) {
|
|
if (dd->uses == 0) {
|
|
++deleted_count;
|
|
dtab->minor [minor] = NULL;
|
|
free_disk_device(dd);
|
|
} else {
|
|
dd->deleted = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
physical_disk->uses -= deleted_count;
|
|
if (physical_disk->uses == 0) {
|
|
rtems_filesystem_split_dev_t(physical_disk->dev, major, minor);
|
|
disktab [major].minor [minor] = NULL;
|
|
free_disk_device(physical_disk);
|
|
}
|
|
} else {
|
|
if (disk_to_remove->uses == 0) {
|
|
--physical_disk->uses;
|
|
rtems_filesystem_split_dev_t(disk_to_remove->dev, major, minor);
|
|
disktab [major].minor [minor] = NULL;
|
|
free_disk_device(disk_to_remove);
|
|
}
|
|
}
|
|
}
|
|
|
|
rtems_status_code
|
|
rtems_disk_delete(dev_t dev)
|
|
{
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
rtems_disk_device *dd = NULL;
|
|
|
|
sc = disk_lock();
|
|
if (sc != RTEMS_SUCCESSFUL) {
|
|
return sc;
|
|
}
|
|
|
|
dd = get_disk_entry(dev, true);
|
|
if (dd == NULL) {
|
|
disk_unlock();
|
|
|
|
return RTEMS_INVALID_ID;
|
|
}
|
|
|
|
dd->deleted = true;
|
|
rtems_disk_cleanup(dd);
|
|
|
|
disk_unlock();
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
rtems_disk_device *
|
|
rtems_disk_obtain(dev_t dev)
|
|
{
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
rtems_disk_device *dd = NULL;
|
|
rtems_interrupt_level level;
|
|
|
|
rtems_interrupt_disable(level);
|
|
if (!diskdevs_protected) {
|
|
/* Frequent and quickest case */
|
|
dd = get_disk_entry(dev, false);
|
|
rtems_interrupt_enable(level);
|
|
} else {
|
|
rtems_interrupt_enable(level);
|
|
|
|
sc = disk_lock();
|
|
if (sc == RTEMS_SUCCESSFUL) {
|
|
dd = get_disk_entry(dev, false);
|
|
disk_unlock();
|
|
}
|
|
}
|
|
|
|
return dd;
|
|
}
|
|
|
|
rtems_status_code
|
|
rtems_disk_release(rtems_disk_device *dd)
|
|
{
|
|
rtems_interrupt_level level;
|
|
dev_t dev = dd->dev;
|
|
unsigned uses = 0;
|
|
bool deleted = false;
|
|
|
|
rtems_interrupt_disable(level);
|
|
uses = --dd->uses;
|
|
deleted = dd->deleted;
|
|
rtems_interrupt_enable(level);
|
|
|
|
if (uses == 0 && deleted) {
|
|
rtems_disk_delete(dev);
|
|
}
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
rtems_disk_device *
|
|
rtems_disk_next(dev_t dev)
|
|
{
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
rtems_disk_device_table *dtab = NULL;
|
|
rtems_device_major_number major = 0;
|
|
rtems_device_minor_number minor = 0;
|
|
|
|
if (dev != (dev_t) -1) {
|
|
rtems_filesystem_split_dev_t(dev, major, minor);
|
|
|
|
/* If minor wraps around */
|
|
if ((minor + 1) < minor) {
|
|
/* If major wraps around */
|
|
if ((major + 1) < major) {
|
|
return NULL;
|
|
}
|
|
++major;
|
|
minor = 0;
|
|
} else {
|
|
++minor;
|
|
}
|
|
}
|
|
|
|
sc = disk_lock();
|
|
if (sc != RTEMS_SUCCESSFUL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (major >= disktab_size) {
|
|
disk_unlock();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
dtab = disktab + major;
|
|
while (true) {
|
|
if (dtab->minor == NULL || minor >= dtab->size) {
|
|
minor = 0;
|
|
++major;
|
|
if (major >= disktab_size) {
|
|
disk_unlock();
|
|
|
|
return NULL;
|
|
}
|
|
dtab = disktab + major;
|
|
} else if (dtab->minor [minor] == NULL) {
|
|
++minor;
|
|
} else {
|
|
++dtab->minor [minor]->uses;
|
|
disk_unlock();
|
|
|
|
return dtab->minor [minor];
|
|
}
|
|
}
|
|
}
|
|
|
|
rtems_status_code
|
|
rtems_disk_io_initialize(void)
|
|
{
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
rtems_device_major_number size = DISKTAB_INITIAL_SIZE;
|
|
|
|
if (disktab_size > 0) {
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
disktab = calloc(size, sizeof(rtems_disk_device_table));
|
|
if (disktab == NULL) {
|
|
return RTEMS_NO_MEMORY;
|
|
}
|
|
|
|
diskdevs_protected = false;
|
|
sc = rtems_semaphore_create(
|
|
rtems_build_name('D', 'D', 'E', 'V'),
|
|
1,
|
|
RTEMS_FIFO | RTEMS_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY
|
|
| RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
|
|
0,
|
|
&diskdevs_mutex
|
|
);
|
|
if (sc != RTEMS_SUCCESSFUL) {
|
|
free(disktab);
|
|
|
|
return RTEMS_NO_MEMORY;
|
|
}
|
|
|
|
sc = rtems_bdbuf_init();
|
|
if (sc != RTEMS_SUCCESSFUL) {
|
|
rtems_semaphore_delete(diskdevs_mutex);
|
|
free(disktab);
|
|
|
|
return RTEMS_UNSATISFIED;
|
|
}
|
|
|
|
disktab_size = size;
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
rtems_status_code
|
|
rtems_disk_io_done(void)
|
|
{
|
|
rtems_device_major_number major = 0;
|
|
rtems_device_minor_number minor = 0;
|
|
|
|
for (major = 0; major < disktab_size; ++major) {
|
|
rtems_disk_device_table *dtab = disktab + major;
|
|
|
|
for (minor = 0; minor < dtab->size; ++minor) {
|
|
rtems_disk_device *dd = dtab->minor [minor];
|
|
|
|
if (dd != NULL) {
|
|
free_disk_device(dd);
|
|
}
|
|
}
|
|
free(dtab->minor);
|
|
}
|
|
free(disktab);
|
|
|
|
rtems_semaphore_delete(diskdevs_mutex);
|
|
|
|
diskdevs_mutex = RTEMS_ID_NONE;
|
|
disktab = NULL;
|
|
disktab_size = 0;
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|