From e51bd967cda1989d606b5b6178ed6d2c8d151707 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 28 Feb 2002 20:39:54 +0000 Subject: 2002-02-28 Joel Sherrill * Submitted by Victor V. Vengerov and merged into the RTEMS source. * ChangeLog, Makefile.am, README, configure.ac, include/Makefile.am, include/rtems/bdbuf.h, include/rtems/blkdev.h, include/rtems/diskdevs.h, include/rtems/ramdisk.h, include/rtems/.cvsignore, include/.cvsignore, src/Makefile.am, src/bdbuf.c, src/blkdev.c, src/diskdevs.c, src/ramdisk.c, src/.cvsignore, .cvsignore: New files. --- c/src/exec/libblock/src/diskdevs.c | 631 +++++++++++++++++++++++++++++++++++++ 1 file changed, 631 insertions(+) create mode 100644 c/src/exec/libblock/src/diskdevs.c (limited to 'c/src/exec/libblock/src/diskdevs.c') diff --git a/c/src/exec/libblock/src/diskdevs.c b/c/src/exec/libblock/src/diskdevs.c new file mode 100644 index 0000000000..a9d6035e8b --- /dev/null +++ b/c/src/exec/libblock/src/diskdevs.c @@ -0,0 +1,631 @@ +/* + * diskdevs.c - Physical and logical block devices (disks) support + * + * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia + * Author: Victor V. Vengerov + * + * @(#) $Id$ + */ + + +#include +#include +#include +#include + +#include "rtems/diskdevs.h" +#include "rtems/bdbuf.h" + +#define DISKTAB_INITIAL_SIZE 32 + +/* Table of disk devices having the same major number */ +struct disk_device_table { + disk_device **minor; /* minor-indexed disk device table */ + int size; /* Number of entries in the table */ +}; + +/* Pointer to [major].minor[minor] indexed array of disk devices */ +static struct disk_device_table *disktab; + +/* Number of allocated entries in disktab table */ +static int disktab_size; + +/* Mutual exclusion semaphore for disk devices table */ +static rtems_id diskdevs_mutex; + +/* Flag meaning that disk I/O, buffering etc. already has been initialized. */ +static boolean disk_io_initialized = FALSE; + +/* 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 rtems_boolean diskdevs_protected; + +/* create_disk_entry -- + * Return pointer to the disk_entry structure for the specified device, or + * create one if it is not exists. + * + * PARAMETERS: + * dev - device id (major, minor) + * + * RETURNS: + * pointer to the disk device descirptor entry, or NULL if no memory + * available for its creation. + */ +static disk_device * +create_disk_entry(dev_t dev) +{ + rtems_device_major_number major; + rtems_device_minor_number minor; + struct disk_device **d; + + rtems_filesystem_split_dev_t (dev, major, minor); + + if (major >= disktab_size) + { + struct disk_device_table *p; + int newsize; + int i; + newsize = disktab_size * 2; + if (major >= newsize) + newsize = major + 1; + p = realloc(disktab, sizeof(struct disk_device_table) * newsize); + if (p == NULL) + return NULL; + p += disktab_size; + for (i = disktab_size; i < newsize; i++, p++) + { + p->minor = NULL; + p->size = 0; + } + disktab_size = newsize; + } + + if ((disktab[major].minor == NULL) || + (minor >= disktab[major].size)) + { + int newsize; + disk_device **p; + int i; + int s = disktab[major].size; + + if (s == 0) + newsize = DISKTAB_INITIAL_SIZE; + else + newsize = s * 2; + if (minor >= newsize) + newsize = minor + 1; + + p = realloc(disktab[major].minor, sizeof(disk_device *) * newsize); + if (p == NULL) + return NULL; + disktab[major].minor = p; + p += s; + for (i = s; i < newsize; i++, p++) + *p = NULL; + disktab[major].size = newsize; + } + + d = disktab[major].minor + minor; + if (*d == NULL) + { + *d = calloc(1, sizeof(disk_device)); + } + return *d; +} + +/* get_disk_entry -- + * Get disk device descriptor by device number. + * + * PARAMETERS: + * dev - block device number + * + * RETURNS: + * Pointer to the disk device descriptor corresponding to the specified + * device number, or NULL if disk device with such number not exists. + */ +static inline disk_device * +get_disk_entry(dev_t dev) +{ + rtems_device_major_number major; + rtems_device_minor_number minor; + struct disk_device_table *dtab; + + rtems_filesystem_split_dev_t (dev, major, minor); + + if ((major >= disktab_size) || (disktab == NULL)) + return NULL; + + dtab = disktab + major; + + if ((minor >= dtab->size) || (dtab->minor == NULL)) + return NULL; + + return dtab->minor[minor]; +} + +/* create_disk -- + * Check that disk entry for specified device number is not defined + * and create it. + * + * PARAMETERS: + * dev - device identifier (major, minor numbers) + * name - character name of device (e.g. /dev/hda) + * disdev - placeholder for pointer to created disk descriptor + * + * RETURNS: + * RTEMS_SUCCESSFUL if disk entry successfully created, or + * error code if error occured (device already registered, + * no memory available). + */ +static rtems_status_code +create_disk(dev_t dev, char *name, disk_device **diskdev) +{ + disk_device *dd; + char *n; + + dd = get_disk_entry(dev); + if (dd != NULL) + { + return RTEMS_RESOURCE_IN_USE; + } + + if (name == NULL) + { + n = NULL; + } + else + { + int nlen = strlen(name) + 1; + n = malloc(nlen); + if (n == NULL) + return RTEMS_NO_MEMORY; + strncpy(n, name, nlen); + } + + dd = create_disk_entry(dev); + if (dd == NULL) + { + free(n); + return RTEMS_NO_MEMORY; + } + + dd->dev = dev; + dd->name = n; + + *diskdev = dd; + + return RTEMS_SUCCESSFUL; +} + +/* rtems_disk_create_phys -- + * Create physical disk entry. This function usually invoked from + * block device driver initialization code when physical device + * detected in the system. Device driver should provide ioctl handler + * to allow block device access operations. This primitive will register + * device in rtems (invoke rtems_io_register_name). + * + * PARAMETERS: + * dev - device identifier (major, minor numbers) + * block_size - size of disk block (minimum data transfer unit); must be + * power of 2 + * disk_size - number of blocks on device + * handler - IOCTL handler (function providing basic block input/output + * request handling BIOREQUEST and other device management + * operations) + * name - character name of device (e.g. /dev/hda) + * + * RETURNS: + * RTEMS_SUCCESSFUL if information about new physical disk added, or + * error code if error occured (device already registered, wrong block + * size value, no memory available). + */ +rtems_status_code +rtems_disk_create_phys(dev_t dev, int block_size, int disk_size, + block_device_ioctl handler, + char *name) +{ + int bs_log2; + int i; + disk_device *dd; + rtems_status_code rc; + rtems_bdpool_id pool; + rtems_device_major_number major; + rtems_device_minor_number minor; + + rtems_filesystem_split_dev_t (dev, major, minor); + + + for (bs_log2 = 0, i = block_size; (i & 1) == 0; i >>= 1, bs_log2++); + if ((bs_log2 < 9) || (i != 1)) /* block size < 512 or not power of 2 */ + return RTEMS_INVALID_NUMBER; + + rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (rc != RTEMS_SUCCESSFUL) + return rc; + diskdevs_protected = TRUE; + + rc = rtems_bdbuf_find_pool(block_size, &pool); + if (rc != RTEMS_SUCCESSFUL) + { + diskdevs_protected = FALSE; + rtems_semaphore_release(diskdevs_mutex); + return rc; + } + + rc = create_disk(dev, name, &dd); + if (rc != RTEMS_SUCCESSFUL) + { + diskdevs_protected = FALSE; + rtems_semaphore_release(diskdevs_mutex); + return rc; + } + + dd->phys_dev = dd; + dd->uses = 0; + dd->start = 0; + dd->size = disk_size; + dd->block_size = block_size; + dd->block_size_log2 = bs_log2; + dd->ioctl = handler; + dd->pool = pool; + + rc = rtems_io_register_name(name, major, minor); + + diskdevs_protected = FALSE; + rtems_semaphore_release(diskdevs_mutex); + + return rc; +} + +/* rtems_disk_create_log -- + * Create logical disk entry. Logical disk is contiguous area on physical + * disk. Disk may be splitted to several logical disks in several ways: + * manually or using information stored in blocks on physical disk + * (DOS-like partition table, BSD disk label, etc). This function usually + * invoked from application when application-specific splitting are in use, + * or from generic code which handle different logical disk organizations. + * This primitive will register device in rtems (invoke + * rtems_io_register_name). + * + * PARAMETERS: + * dev - logical device identifier (major, minor numbers) + * phys - physical device (block device which holds this logical disk) + * identifier + * start - starting block number on the physical device + * size - logical disk size in blocks + * name - logical disk name + * + * RETURNS: + * RTEMS_SUCCESSFUL if logical device successfully added, or error code + * if error occured (device already registered, no physical device + * exists, logical disk is out of physical disk boundaries, no memory + * available). + */ +rtems_status_code +rtems_disk_create_log(dev_t dev, dev_t phys, int start, int size, char *name) +{ + disk_device *dd; + disk_device *pdd; + rtems_status_code rc; + rtems_device_major_number major; + rtems_device_minor_number minor; + + rtems_filesystem_split_dev_t (dev, major, minor); + + rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (rc != RTEMS_SUCCESSFUL) + return rc; + diskdevs_protected = TRUE; + + pdd = get_disk_entry(phys); + if (pdd == NULL) + { + diskdevs_protected = FALSE; + rtems_semaphore_release(diskdevs_mutex); + return RTEMS_INVALID_NUMBER; + } + + rc = create_disk(dev, name, &dd); + if (rc != RTEMS_SUCCESSFUL) + { + diskdevs_protected = FALSE; + rtems_semaphore_release(diskdevs_mutex); + return rc; + } + + dd->phys_dev = pdd; + dd->uses = 0; + dd->start = start; + dd->size = size; + dd->block_size = pdd->block_size; + dd->block_size_log2 = pdd->block_size_log2; + dd->ioctl = pdd->ioctl; + + rc = rtems_io_register_name(name, major, minor); + + diskdevs_protected = FALSE; + rc = rtems_semaphore_release(diskdevs_mutex); + + return rc; +} + +/* rtems_disk_delete -- + * Delete physical or logical disk device. Device may be deleted if its + * use counter (and use counters of all logical devices - if it is + * physical device) equal to 0. When physical device deleted, + * all logical devices deleted inherently. Appropriate devices removed + * from "/dev" filesystem. + * + * PARAMETERS: + * dev - device identifier (major, minor numbers) + * + * RETURNS: + * RTEMS_SUCCESSFUL if block device successfully deleted, or error code + * if error occured (device is not defined, device is in use). + */ +rtems_status_code +rtems_disk_delete(dev_t dev) +{ + rtems_status_code rc; + int used; + rtems_device_major_number maj; + rtems_device_minor_number min; + + rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (rc != RTEMS_SUCCESSFUL) + return rc; + diskdevs_protected = TRUE; + + /* Check if this device is in use -- calculate usage counter */ + used = 0; + for (maj = 0; maj < disktab_size; maj++) + { + struct disk_device_table *dtab = disktab + maj; + if (dtab != NULL) + { + for (min = 0; min < dtab->size; min++) + { + disk_device *dd = dtab->minor[min]; + if ((dd != NULL) && (dd->phys_dev->dev == dev)) + used += dd->uses; + } + } + } + + if (used != 0) + { + diskdevs_protected = FALSE; + rtems_semaphore_release(diskdevs_mutex); + return RTEMS_RESOURCE_IN_USE; + } + + /* Delete this device and all of its logical devices */ + for (maj = 0; maj < disktab_size; maj++) + { + struct disk_device_table *dtab = disktab +maj; + if (dtab != NULL) + { + for (min = 0; min < dtab->size; min++) + { + disk_device *dd = dtab->minor[min]; + if ((dd != NULL) && (dd->phys_dev->dev == dev)) + { + unlink(dd->name); + free(dd->name); + free(dd); + dtab->minor[min] = NULL; + } + } + } + } + + diskdevs_protected = FALSE; + rc = rtems_semaphore_release(diskdevs_mutex); + return rc; +} + +/* rtems_disk_lookup -- + * Find block device descriptor by its device identifier. + * + * PARAMETERS: + * dev - device identifier (major, minor numbers) + * + * RETURNS: + * pointer to the block device descriptor, or NULL if no such device + * exists. + */ +disk_device * +rtems_disk_lookup(dev_t dev) +{ + rtems_interrupt_level level; + disk_device *dd; + rtems_status_code rc; + + rtems_interrupt_disable(level); + if (diskdevs_protected) + { + rtems_interrupt_enable(level); + rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, + RTEMS_NO_TIMEOUT); + if (rc != RTEMS_SUCCESSFUL) + return NULL; + diskdevs_protected = TRUE; + dd = get_disk_entry(dev); + dd->uses++; + diskdevs_protected = FALSE; + rtems_semaphore_release(diskdevs_mutex); + return dd; + } + else + { + /* Frequent and quickest case */ + dd = get_disk_entry(dev); + dd->uses++; + rtems_interrupt_enable(level); + return dd; + } +} + +/* rtems_disk_release -- + * Release disk_device structure (decrement usage counter to 1). + * + * PARAMETERS: + * dd - pointer to disk device structure + * + * RETURNS: + * RTEMS_SUCCESSFUL + */ +rtems_status_code +rtems_disk_release(disk_device *dd) +{ + rtems_interrupt_level level; + rtems_interrupt_disable(level); + dd->uses--; + rtems_interrupt_enable(level); + return RTEMS_SUCCESSFUL; +} + +/* rtems_disk_next -- + * Disk device enumerator. Looking for device having device number larger + * than dev and return disk device descriptor for it. If there are no + * such device, NULL value returned. + * + * PARAMETERS: + * dev - device number (use -1 to start search) + * + * RETURNS: + * Pointer to the disk descriptor for next disk device, or NULL if all + * devices enumerated. + */ +disk_device * +rtems_disk_next(dev_t dev) +{ + rtems_device_major_number major; + rtems_device_minor_number minor; + struct disk_device_table *dtab; + + dev++; + rtems_filesystem_split_dev_t (dev, major, minor); + + if (major >= disktab_size) + return NULL; + + dtab = disktab + major; + while (TRUE) + { + if ((dtab == NULL) || (minor > dtab->size)) + { + major++; minor = 0; + if (major >= disktab_size) + return NULL; + dtab = disktab + major; + } + else if (dtab->minor[minor] == NULL) + { + minor++; + } + else + return dtab->minor[minor]; + } +} + +/* rtems_disk_initialize -- + * Initialization of disk device library (initialize all data structures, + * etc.) + * + * PARAMETERS: + * none + * + * RETURNS: + * RTEMS_SUCCESSFUL if library initialized, or error code if error + * occured. + */ +rtems_status_code +rtems_disk_io_initialize(void) +{ + rtems_status_code rc; + + if (disk_io_initialized) + return RTEMS_SUCCESSFUL; + + disktab_size = DISKTAB_INITIAL_SIZE; + disktab = calloc(disktab_size, sizeof(struct disk_device_table)); + if (disktab == NULL) + return RTEMS_NO_MEMORY; + + diskdevs_protected = FALSE; + rc = 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 (rc != RTEMS_SUCCESSFUL) + { + free(disktab); + return rc; + } + + rc = rtems_bdbuf_init(rtems_bdbuf_configuration, + rtems_bdbuf_configuration_size); + + if (rc != RTEMS_SUCCESSFUL) + { + rtems_semaphore_delete(diskdevs_mutex); + free(disktab); + return rc; + } + + disk_io_initialized = 1; + return RTEMS_SUCCESSFUL; +} + +/* rtems_disk_io_done -- + * Release all resources allocated for disk device interface. + * + * PARAMETERS: + * none + * + * RETURNS: + * RTEMS_SUCCESSFUL if all resources released, or error code if error + * occured. + */ +rtems_status_code +rtems_disk_io_done(void) +{ + rtems_device_major_number maj; + rtems_device_minor_number min; + rtems_status_code rc; + + /* Free data structures */ + for (maj = 0; maj < disktab_size; maj++) + { + struct disk_device_table *dtab = disktab + maj; + if (dtab != NULL) + { + for (min = 0; min < dtab->size; min++) + { + disk_device *dd = dtab->minor[min]; + unlink(dd->name); + free(dd->name); + free(dd); + } + free(dtab); + } + } + free(disktab); + + rc = rtems_semaphore_release(diskdevs_mutex); + + /* XXX bdbuf should be released too! */ + disk_io_initialized = 0; + return rc; +} -- cgit v1.2.3