diff options
47 files changed, 6177 insertions, 2384 deletions
diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog index 5d62e1f28d..9ee374f0ee 100644 --- a/cpukit/ChangeLog +++ b/cpukit/ChangeLog @@ -1,3 +1,90 @@ +2008-07-29 Chris Johns <chrisj@rtems.org> + + * libblock/Makefile.am: Removed src/show_bdbuf.c. + + * libblock/src/show_bdbuf.c: Removed. + + * libblock/include/rtems/bdbuf.h, cpukit/libblock/src/bdbuf.c: + Rewritten the bdbuf code. Remove pre-emption disable, score + access, fixed many bugs and increased performance. + + * libblock/include/rtems/blkdev.h: Added + RTEMS_BLKDEV_CAPABILITIES block device request. Cleaned up + comments. Added block and user fields to the sg buffer + request. Move to rtems_* namespace. + + * libblock/include/rtems/diskdevs.h, + cpukit/libblock/src/diskdevs.c: Move to rtems_* namespace. Add a + capabilities field for drivers. Change rtems_disk_lookup to + rtems_disk_obtain to match the release call. You do not lookup and + release a disk, you obtain and release a disk. + + * libblock/include/rtems/ide_part_table.h, + libblock/include/rtems/ramdisk.h, libblock/src/ide_part_table.c: + Move to rtems_* namespace. + + * libblock/include/rtems/nvdisk.h: Formatting change. + + * libblock/src/blkdev.c: Move to rtems_* namespace. Change + rtems_disk_lookup to rtems_disk_obtain + + * libblock/src/flashdisk.c: Move to rtems_* namespace. Use the new + support for the block number in the scatter/grather request + struct. This allows non-continuous buffer requests for those + drivers that can support increasing performance. + + * libblock/src/nvdisk.c: Move to rtems_* namespace. Removed + warnings. Added better error checking. Fixed some comments. + + * libblock/src/ramdisk.c: Move to rtems_* namespace. Added some + trace functions to help debugging upper layers. Use the new + support for the block number in the scatter/grather request + struct. This allows non-continuous buffer requests for those + drivers that can support increasing performance. + + * libfs/src/dosfs/fat.c, libfs/src/dosfs/fat.h: Use new chains + API. Removed temporary hack and changed + set_errno_and_return_minus_one to + rtems_set_errno_and_return_minus_one. Move fat_buf_access from + header and stopped it being inlined. Updated to libblock changes. + + * libfs/src/dosfs/fat_fat_operations.c, + libfs/src/dosfs/fat_file.c, libfs/src/dosfs/msdos_create.c, + libfs/src/dosfs/msdos_dir.c, libfs/src/dosfs/msdos_eval.c, + libfs/src/dosfs/msdos_file.c, libfs/src/dosfs/msdos_format.c, + libfs/src/dosfs/msdos_free.c, libfs/src/dosfs/msdos_initsupp.c, + libfs/src/dosfs/msdos_misc.c, libfs/src/dosfs/msdos_mknod.c: Use + new chains API. Removed temporary hack and changed + set_errno_and_return_minus_one to + rtems_set_errno_and_return_minus_one. Updated to libblock changes. + + * libmisc/Makefile.am: Add new ls and rm command files. + + * libmisc/shell/cmp-ls.c, libmisc/shell/extern-ls.h, + libmisc/shell/filemode.c, libmisc/shell/print-ls.c, + libmisc/shell/pwcache.c, libmisc/shell/utils-ls.c, + libmisc/shell/vis.c, shell/vis.h: New. + + * libmisc/shell/extern-cp.h, libmisc/shell/main_cp.c, + libmisc/shell/utils-cp.c: Fixed the usage call bug. + + * libmisc/shell/main_blksync.c: Updated to the new block IO ioctl + command. + + * libmisc/shell/main_ls.c, libmisc/shell/main_rm.c: Updated to BSD + commands with more features. + + * score/src/coremutex.c: Fix the strick order mutex code. + + * libmisc/shell/shell.c: Change shell tasks mode to be timeslice + and no ASR. + + * sapi/include/confdefs.h: Change ata_driver_task_priority to + rtems_ata_driver_task_priority. Add the new BD buf cache + parameters with defaults. + + * score/src/interr.c: Do not return if the CPU halt call returns. + 2008-07-24 Sebastian Huber <sebastian.huber@embedded-brains.de> * libcsupport/include/rtems/libcsupport.h: Moved declaration of diff --git a/cpukit/libblock/Makefile.am b/cpukit/libblock/Makefile.am index f48a5d977c..6da4ead942 100644 --- a/cpukit/libblock/Makefile.am +++ b/cpukit/libblock/Makefile.am @@ -8,7 +8,7 @@ include $(top_srcdir)/automake/compile.am if !UNIX noinst_LIBRARIES = libblock.a libblock_a_SOURCES = src/bdbuf.c src/blkdev.c src/diskdevs.c src/flashdisk.c \ - src/ramdisk.c src/ide_part_table.c src/show_bdbuf.c src/nvdisk.c \ + src/ramdisk.c src/ide_part_table.c src/nvdisk.c \ src/nvdisk-sram.c \ include/rtems/bdbuf.h include/rtems/blkdev.h \ include/rtems/diskdevs.h include/rtems/flashdisk.h \ diff --git a/cpukit/libblock/include/rtems/bdbuf.h b/cpukit/libblock/include/rtems/bdbuf.h index f4308963dd..991da1fdaa 100644 --- a/cpukit/libblock/include/rtems/bdbuf.h +++ b/cpukit/libblock/include/rtems/bdbuf.h @@ -25,116 +25,143 @@ extern "C" { #include "rtems/blkdev.h" #include "rtems/diskdevs.h" - -/* - * To manage buffers we using Buffer Descriptors. - * To speed-up buffer lookup descriptors are organized in AVL-Tree. - * The fields 'dev' and 'block' are search key. +/** + * State of a buffer in the cache. */ +typedef enum +{ + RTEMS_BDBUF_STATE_EMPTY = 0, /* Not in use. */ + RTEMS_BDBUF_STATE_READ_AHEAD = 1, /* Holds read ahead data only */ + RTEMS_BDBUF_STATE_CACHED = 2, /* In the cache and available */ + RTEMS_BDBUF_STATE_ACCESS = 3, /* The user has the buffer */ + RTEMS_BDBUF_STATE_MODIFIED = 4, /* In the cache but modified */ + RTEMS_BDBUF_STATE_ACCESS_MODIFIED = 5, /* With the user but modified */ + RTEMS_BDBUF_STATE_SYNC = 6, /* Requested to be sync'ed */ + RTEMS_BDBUF_STATE_TRANSFER = 7 /* Being transferred to or from disk */ +} rtems_bdbuf_buf_state; -/* Buffer descriptors - * Descriptors organized in AVL-tree to speedup buffer lookup. - * dev and block fields are search key in AVL-tree. - * Modified buffers, free buffers and used buffers linked in 'mod', 'free' and - * 'lru' chains appropriately. +/** + * To manage buffers we using buffer descriptors (BD). A BD holds a buffer plus + * a range of other information related to managing the buffer in the cache. To + * speed-up buffer lookup descriptors are organized in AVL-Tree. The fields + * 'dev' and 'block' are search keys. */ +typedef struct rtems_bdbuf_buffer +{ + rtems_chain_node link; /* Link in the BD onto a number of lists. */ -typedef struct bdbuf_buffer { - Chain_Node link; /* Link in the lru, mod or free chains */ - - struct bdbuf_avl_node { - signed char cache; /* Cache */ + struct rtems_bdbuf_avl_node + { + signed char cache; /* Cache */ + struct rtems_bdbuf_buffer* left; /* Left Child */ + struct rtems_bdbuf_buffer* right; /* Right Child */ + signed char bal; /* The balance of the sub-tree */ + } avl; - struct bdbuf_buffer* left; /* Left Child */ - struct bdbuf_buffer* right; /* Right Child */ + dev_t dev; /* device number */ + rtems_blkdev_bnum block; /* block number on the device */ - signed char bal; /* The balance of the sub-tree */ - } avl; + unsigned char* buffer; /* Pointer to the buffer memory area */ + int error; /* If not 0 indicate an error value (errno) + * which can be used by user later */ - dev_t dev; /* device number */ - blkdev_bnum block; /* block number on the device */ + volatile rtems_bdbuf_buf_state state; /* State of the buffer. */ - unsigned char *buffer; /* Pointer to the buffer memory area */ - rtems_status_code status; /* Last I/O operation completion status */ - int error; /* If status != RTEMS_SUCCESSFUL, this field contains - errno value which can be used by user later */ - boolean modified:1; /* =1 if buffer was modified */ - boolean in_progress:1; /* =1 if exchange with disk is in progress; - need to wait on semaphore */ - boolean actual:1; /* Buffer contains actual data */ - int use_count; /* Usage counter; incremented when somebody use - this buffer; decremented when buffer released - without modification or when buffer is flushed - by swapout task */ + volatile uint32_t waiters; /* The number of threads waiting on this + * buffer. */ + rtems_bdpool_id pool; /* Identifier of buffer pool to which this buffer + belongs */ - rtems_bdpool_id pool; /* Identifier of buffer pool to which this buffer - belongs */ - CORE_mutex_Control transfer_sema; - /* Transfer operation semaphore */ -} bdbuf_buffer; + volatile uint32_t hold_timer; /* Timer to indicate how long a buffer + * has been held in the cache modified. */ +} rtems_bdbuf_buffer; +/** + * The groups of the blocks with the same size are collected in a pool. Note + * that a several of the buffer's groups with the same size can exists. + */ +typedef struct rtems_bdbuf_pool +{ + int blksize; /* The size of the blocks (in bytes) */ + int nblks; /* Number of blocks in this pool */ + + uint32_t flags; /* Configuration flags */ + + rtems_id lock; /* The pool lock. Lock this data and + * all BDs. */ + rtems_id sync_lock; /* Sync calls lock writes. */ + boolean sync_active; /* True if a sync is active. */ + rtems_id sync_requester; /* The sync requester. */ + dev_t sync_device; /* The device to sync */ + + rtems_bdbuf_buffer* tree; /* Buffer descriptor lookup AVL tree + * root */ + rtems_chain_control ready; /* Free buffers list (or read-ahead) */ + rtems_chain_control lru; /* Last recently used list */ + rtems_chain_control modified; /* Modified buffers list */ + rtems_chain_control sync; /* Buffers to sync list */ + + rtems_id access; /* Obtain if waiting for a buffer in the + * ACCESS state. */ + volatile uint32_t access_waiters; /* Count of access blockers. */ + rtems_id transfer; /* Obtain if waiting for a buffer in the + * TRANSFER state. */ + volatile uint32_t transfer_waiters; /* Count of transfer blockers. */ + rtems_id waiting; /* Obtain if waiting for a buffer and the + * none are available. */ + volatile uint32_t wait_waiters; /* Count of waiting blockers. */ + + rtems_bdbuf_buffer* bds; /* Pointer to table of buffer descriptors + * allocated for this buffer pool. */ + void* buffers; /* The buffer's memory. */ +} rtems_bdbuf_pool; -/* - * the following data structures are internal to the bdbuf layer, - * but it is convenient to have them visible from the outside for inspection +/** + * Configuration structure describes block configuration (size, amount, memory + * location) for buffering layer pool. */ -/* - * The groups of the blocks with the same size are collected in the - * bd_pool. Note that a several of the buffer's groups with the - * same size can exists. +typedef struct rtems_bdbuf_pool_config { + int size; /* Size of block */ + int num; /* Number of blocks of appropriate size */ + unsigned char* mem_area; /* Pointer to the blocks location or NULL, in this + * case memory for blocks will be allocated by + * Buffering Layer with the help of RTEMS partition + * manager */ +} rtems_bdbuf_pool_config; + +/** + * External references provided by the user for each pool in the system. */ -typedef struct bdbuf_pool -{ - bdbuf_buffer *tree; /* Buffer descriptor lookup AVL tree root */ - - Chain_Control free; /* Free buffers list */ - Chain_Control lru; /* Last recently used list */ - - int blksize; /* The size of the blocks (in bytes) */ - int nblks; /* Number of blocks in this pool */ - rtems_id bufget_sema; /* Buffer obtain counting semaphore */ - void *mallocd_bufs; /* Pointer to the malloc'd buffer memory, - or NULL, if buffer memory provided in - buffer configuration */ - bdbuf_buffer *bdbufs; /* Pointer to table of buffer descriptors - allocated for this buffer pool. */ -} bdbuf_pool; - -/* Buffering layer context definition */ -struct bdbuf_context { - bdbuf_pool *pool; /* Table of buffer pools */ - int npools; /* Number of entries in pool table */ - - Chain_Control mod; /* Modified buffers list */ - rtems_id flush_sema; /* Buffer flush semaphore; counting - semaphore; incremented when buffer - flushed to the disk; decremented when - buffer modified */ - rtems_id swapout_task; /* Swapout task ID */ -}; - /* - * the context of the buffering layer, visible for inspection - */ -extern struct bdbuf_context rtems_bdbuf_ctx; - -/* bdbuf_config structure describes block configuration (size, - * amount, memory location) for buffering layer +extern rtems_bdbuf_pool_config rtems_bdbuf_pool_configuration[]; +extern int rtems_bdbuf_pool_configuration_size; + +/** + * Buffering configuration definition. See confdefs.h for support on using this + * structure. */ typedef struct rtems_bdbuf_config { - int size; /* Size of block */ - int num; /* Number of blocks of appropriate size */ - unsigned char *mem_area; - /* Pointer to the blocks location or NULL, in this - case memory for blocks will be allocated by - Buffering Layer with the help of RTEMS partition - manager */ + int max_read_ahead_blocks; /*<< Number of blocks to read ahead. */ + int max_write_blocks; /*<< Number of blocks to write at once. */ + rtems_task_priority swapout_priority; /*<< Priority of the swap out task. */ + uint32_t swapout_period; /*<< Period swapout checks buf timers. */ + uint32_t swap_block_hold; /*<< Period a buffer is held. */ } rtems_bdbuf_config; -extern rtems_bdbuf_config rtems_bdbuf_configuration[]; -extern int rtems_bdbuf_configuration_size; +/** + * External referernce to the configuration. The configuration is provided by + * the user. + */ +extern rtems_bdbuf_config rtems_bdbuf_configuration; -#define SWAPOUT_TASK_DEFAULT_PRIORITY 15 -extern rtems_task_priority swapout_task_priority; +/** + * The max_read_ahead_blocks value is altered if there are fewer buffers + * than this defined max. This stops thrashing in the cache. + */ +#define RTEMS_BDBUF_MAX_READ_AHEAD_BLOCKS_DEFAULT 32 +#define RTEMS_BDBUF_MAX_WRITE_BLOCKS_DEFAULT 16 +#define RTEMS_BDBUF_SWAPOUT_TASK_PRIORITY_DEFAULT 15 +#define RTEMS_BDBUF_SWAPOUT_TASK_SWAP_PERIOD_DEFAULT 250 /* milli-seconds */ +#define RTEMS_BDBUF_SWAPOUT_TASK_BLOCK_HOLD_DEFAULT 1000 /* milli-seconds */ /* rtems_bdbuf_init -- * Prepare buffering layer to work - initialize buffer descritors @@ -143,17 +170,12 @@ extern rtems_task_priority swapout_task_priority; * amount requested. After initialization all blocks is placed into * free elements lists. * - * PARAMETERS: - * conf_table - pointer to the buffers configuration table - * size - number of entries in configuration table - * * RETURNS: * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully * or error code if error is occured) */ rtems_status_code -rtems_bdbuf_init(rtems_bdbuf_config *conf_table, int size); - +rtems_bdbuf_init (); /* rtems_bdbuf_get -- * Obtain block buffer. If specified block already cached (i.e. there's @@ -177,8 +199,8 @@ rtems_bdbuf_init(rtems_bdbuf_config *conf_table, int size); * SIDE EFFECTS: * bufget_sema semaphore obtained by this primitive. */ -rtems_status_code -rtems_bdbuf_get(dev_t device, blkdev_bnum block, bdbuf_buffer **bdb_ptr); + rtems_status_code + rtems_bdbuf_get(dev_t device, rtems_blkdev_bnum block, rtems_bdbuf_buffer** bd); /* rtems_bdbuf_read -- * (Similar to the rtems_bdbuf_get, except reading data from media) @@ -201,8 +223,8 @@ rtems_bdbuf_get(dev_t device, blkdev_bnum block, bdbuf_buffer **bdb_ptr); * SIDE EFFECTS: * bufget_sema and transfer_sema semaphores obtained by this primitive. */ -rtems_status_code -rtems_bdbuf_read(dev_t device, blkdev_bnum block, bdbuf_buffer **bdb_ptr); + rtems_status_code + rtems_bdbuf_read(dev_t device, rtems_blkdev_bnum block, rtems_bdbuf_buffer** bd); /* rtems_bdbuf_release -- * Release buffer allocated before. This primitive decrease the @@ -223,8 +245,8 @@ rtems_bdbuf_read(dev_t device, blkdev_bnum block, bdbuf_buffer **bdb_ptr); * SIDE EFFECTS: * flush_sema and bufget_sema semaphores may be released by this primitive. */ -rtems_status_code -rtems_bdbuf_release(bdbuf_buffer *bd_buf); + rtems_status_code + rtems_bdbuf_release(rtems_bdbuf_buffer* bd); /* rtems_bdbuf_release_modified -- * Release buffer allocated before, assuming that it is _modified_ by @@ -244,8 +266,8 @@ rtems_bdbuf_release(bdbuf_buffer *bd_buf); * SIDE EFFECTS: * flush_sema semaphore may be released by this primitive. */ -rtems_status_code -rtems_bdbuf_release_modified(bdbuf_buffer *bd_buf); + rtems_status_code + rtems_bdbuf_release_modified(rtems_bdbuf_buffer* bd); /* rtems_bdbuf_sync -- * Wait until specified buffer synchronized with disk. Invoked on exchanges @@ -265,8 +287,8 @@ rtems_bdbuf_release_modified(bdbuf_buffer *bd_buf); * SIDE EFFECTS: * Primitive may be blocked on transfer_sema semaphore. */ -rtems_status_code -rtems_bdbuf_sync(bdbuf_buffer *bd_buf); + rtems_status_code + rtems_bdbuf_sync(rtems_bdbuf_buffer* bd); /* rtems_bdbuf_syncdev -- * Synchronize with disk all buffers containing the blocks belonging to @@ -279,8 +301,8 @@ rtems_bdbuf_sync(bdbuf_buffer *bd_buf); * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully * or error code if error is occured) */ -rtems_status_code -rtems_bdbuf_syncdev(dev_t dev); + rtems_status_code + rtems_bdbuf_syncdev(dev_t dev); /* rtems_bdbuf_find_pool -- * Find first appropriate buffer pool. This primitive returns the index @@ -297,8 +319,8 @@ rtems_bdbuf_syncdev(dev_t dev); * of 2), RTEMS_NOT_DEFINED if buffer pool for this or greater block size * is not configured. */ -rtems_status_code -rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool); + rtems_status_code + rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool); /* rtems_bdbuf_get_pool_info -- * Obtain characteristics of buffer pool with specified number. @@ -316,8 +338,8 @@ rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool); * NOTE: * Buffer pools enumerated contiguously starting from 0. */ -rtems_status_code -rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size, int *blocks); + rtems_status_code + rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size, int *blocks); #ifdef __cplusplus } diff --git a/cpukit/libblock/include/rtems/blkdev.h b/cpukit/libblock/include/rtems/blkdev.h index fadbdce9c7..03b639c73c 100644 --- a/cpukit/libblock/include/rtems/blkdev.h +++ b/cpukit/libblock/include/rtems/blkdev.h @@ -20,67 +20,92 @@ extern "C" { #endif -/* Interface with device drivers - * Block device looks, initialized and behaves like traditional RTEMS device - * driver. Heart of the block device driver is in BIOREQUEST ioctl. This call - * puts I/O request to the block device queue, in priority order, for - * asynchronous processing. When driver executes request, req_done - * function invoked, so callee knows about it. Look for details below. +/* + * Interface with device drivers Block device looks, initialized and behaves + * like traditional RTEMS device driver. Heart of the block device driver is in + * BIOREQUEST ioctl. This call puts I/O request to the block device queue, in + * priority order, for asynchronous processing. When driver executes request, + * req_done function invoked, so callee knows about it. Look for details below. */ - -/* Block device block number datatype */ -typedef uint32_t blkdev_bnum; +/* + * Block device block number datatype + */ +typedef uint32_t rtems_blkdev_bnum; /* Block device request type */ -typedef enum blkdev_request_op { - BLKDEV_REQ_READ, /* Read operation */ - BLKDEV_REQ_WRITE /* Write operation */ -} blkdev_request_op; +typedef enum rtems_blkdev_request_op { + RTEMS_BLKDEV_REQ_READ, /* Read operation */ + RTEMS_BLKDEV_REQ_WRITE, /* Write operation */ + RTEMS_BLKDEV_CAPABILITIES /* Capabilities request */ +} rtems_blkdev_request_op; + +/** + * ATA multi-sector buffer requests only supported. This option + * means the cache will only supply multiple buffers that are + * inorder so the ATA multi-sector command can be used. This is a + * hack to work around the current ATA driver. + */ +#define RTEMS_BLKDEV_CAP_MULTISECTOR_CONT (1 << 0) -/* Type for block device request done callback function. +/* + * @typedef rtems_blkdev_request_cb * - * PARAMETERS: - * arg - argument supplied in blkdev_request - * status - rtems status code for this operation - * errno - errno value to be passed to the user when + * Type for block device request done callback function. + * + * @param arg Argument supplied in blkdev_request + * @param status RTEMS status code for this operation + * @param errno errno value to be passed to the user when * status != RTEMS_SUCCESSFUL */ -typedef void (* blkdev_request_cb)(void *arg, - rtems_status_code status, - int error); +typedef void (* rtems_blkdev_request_cb)(void *arg, + rtems_status_code status, + int error); -/* blkdev_sg_buffer +/** + * @struct rtems_blkdev_sg_buffer * Block device scatter/gather buffer structure */ -typedef struct blkdev_sg_buffer { +typedef struct rtems_blkdev_sg_buffer { + uint32_t block; /* The block number */ uint32_t length; /* Buffer length */ - void *buffer; /* Buffer pointer */ -} blkdev_sg_buffer; + void *buffer; /* Buffer pointer */ + void *user; /* User pointer */ +} rtems_blkdev_sg_buffer; /* blkdev_request (Block Device Request) structure is * used to read/write a number of blocks from/to device. */ -typedef struct blkdev_request { - blkdev_request_op req; /* Block device operation (read or write) */ - blkdev_request_cb req_done; /* Callback function */ - void *done_arg; /* Argument to be passed to callback function*/ - rtems_status_code status; /* Last I/O operation completion status */ - int error; /* If status != RTEMS_SUCCESSFUL, this field - * contains error code - */ - blkdev_bnum start; /* Start block number */ - uint32_t count; /* Number of blocks to be exchanged */ - uint32_t bufnum; /* Number of buffers provided */ - - blkdev_sg_buffer bufs[0];/* List of scatter/gather buffers */ -} blkdev_request; +typedef struct rtems_blkdev_request { + /* Block device operation (read or write) */ + rtems_blkdev_request_op req; + /* Callback function */ + rtems_blkdev_request_cb req_done; + /* Argument to be passed to callback function*/ + void *done_arg; + /* Last I/O operation completion status */ + rtems_status_code status; + /* If status != RTEMS_SUCCESSFUL, this field contains error code */ + int error; + /* Start block number */ + rtems_blkdev_bnum start; + /* Number of blocks to be exchanged */ + uint32_t count; + /* Number of buffers provided */ + uint32_t bufnum; + + /* The task requesting the IO operation. */ + rtems_id io_task; + + /* List of scatter/gather buffers */ + rtems_blkdev_sg_buffer bufs[0]; +} rtems_blkdev_request; /* Block device IOCTL request codes */ -#define BLKIO_REQUEST _IOWR('B', 1, blkdev_request) -#define BLKIO_GETBLKSIZE _IO('B', 2) -#define BLKIO_GETSIZE _IO('B', 3) -#define BLKIO_SYNCDEV _IO('B', 4) +#define RTEMS_BLKIO_REQUEST _IOWR('B', 1, rtems_blkdev_request) +#define RTEMS_BLKIO_GETBLKSIZE _IO('B', 2) +#define RTEMS_BLKIO_GETSIZE _IO('B', 3) +#define RTEMS_BLKIO_SYNCDEV _IO('B', 4) /* Device driver interface conventions suppose that driver may * contain initialize/open/close/read/write/ioctl entry points. These @@ -90,7 +115,7 @@ typedef struct blkdev_request { * all block devices and appropriate ioctl handlers. */ -#define GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES \ +#define RTEMS_GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES \ rtems_blkdev_generic_open, rtems_blkdev_generic_close, \ rtems_blkdev_generic_read, rtems_blkdev_generic_write, \ rtems_blkdev_generic_ioctl diff --git a/cpukit/libblock/include/rtems/diskdevs.h b/cpukit/libblock/include/rtems/diskdevs.h index 6542d74775..3517ddede2 100644 --- a/cpukit/libblock/include/rtems/diskdevs.h +++ b/cpukit/libblock/include/rtems/diskdevs.h @@ -21,44 +21,47 @@ extern "C" { #include <rtems/libio.h> #include <stdlib.h> -#include "rtems/blkdev.h" - /* Buffer pool identifier */ typedef int rtems_bdpool_id; +#include "rtems/blkdev.h" + +/* Driver capabilities. */ + /* Block device ioctl handler */ -typedef int (* block_device_ioctl) (dev_t dev, uint32_t req, void *argp); +typedef int (* rtems_block_device_ioctl) (dev_t dev, uint32_t req, void *argp); -/* disk_device: Entry of this type created for every disk device (both for - * logical and physical disks). +/* rtems_disk_device: Entry of this type created for every disk device + * (both for logical and physical disks). * Array of arrays of pointers to disk_device structures maintained. First * table indexed by major number and second table indexed by minor number. * Such data organization allow quick lookup using data structure of * moderated size. */ -typedef struct disk_device { - dev_t dev; /* Device ID (major + minor) */ - struct disk_device *phys_dev; /* Physical device ID (the same - as dev if this entry specifies - the physical device) */ - char *name; /* Disk device name */ - int uses; /* Use counter. Device couldn't be - removed if it is in use. */ - int start; /* Starting block number (0 for - physical devices, block offset - on the related physical device - for logical device) */ - int size; /* Size of physical or logical disk - in disk blocks */ - int block_size; /* Size of device block (minimum - transfer unit) in bytes - (must be power of 2) */ - int block_size_log2; /* log2 of block_size */ - rtems_bdpool_id pool; /* Buffer pool assigned to this - device */ - block_device_ioctl ioctl; /* ioctl handler for this block - device */ -} disk_device; +typedef struct rtems_disk_device { + dev_t dev; /* Device ID (major + minor) */ + struct rtems_disk_device *phys_dev; /* Physical device ID (the same + as dev if this entry specifies + the physical device) */ + uint32_t capabilities; /* Driver capabilities. */ + char *name; /* Disk device name */ + int uses; /* Use counter. Device couldn't be + removed if it is in use. */ + int start; /* Starting block number (0 for + physical devices, block offset + on the related physical device + for logical device) */ + int size; /* Size of physical or logical disk + in disk blocks */ + int block_size; /* Size of device block (minimum + transfer unit) in bytes + (must be power of 2) */ + int block_size_log2; /* log2 of block_size */ + rtems_bdpool_id pool; /* Buffer pool assigned to this + device */ + rtems_block_device_ioctl ioctl; /* ioctl handler for this block + device */ +} rtems_disk_device; /* rtems_disk_create_phys -- * Create physical disk entry. This function usually invoked from @@ -84,7 +87,7 @@ typedef struct disk_device { */ rtems_status_code rtems_disk_create_phys(dev_t dev, int block_size, int disk_size, - block_device_ioctl handler, + rtems_block_device_ioctl handler, const char *name); /* rtems_disk_create_log -- @@ -131,7 +134,7 @@ rtems_disk_create_log(dev_t dev, dev_t phys, int start, int size, char *name); rtems_status_code rtems_disk_delete(dev_t dev); -/* rtems_disk_lookup -- +/* rtems_disk_obtain -- * Find block device descriptor by its device identifier. This function * increment usage counter to 1. User should release disk_device structure * by invoking rtems_disk_release primitive. @@ -143,8 +146,8 @@ rtems_disk_delete(dev_t dev); * pointer to the block device descriptor, or NULL if no such device * exists. */ -disk_device * -rtems_disk_lookup(dev_t dev); +rtems_disk_device * +rtems_disk_obtain(dev_t dev); /* rtems_disk_release -- * Release disk_device structure (decrement usage counter to 1). @@ -159,7 +162,7 @@ rtems_disk_lookup(dev_t dev); * It should be implemented as inline function. */ rtems_status_code -rtems_disk_release(disk_device *dd); +rtems_disk_release(rtems_disk_device *dd); /* rtems_disk_next -- * Disk device enumerator. Looking for device having device number larger @@ -172,7 +175,7 @@ rtems_disk_release(disk_device *dd); * RETURNS: * Pointer to the disk descriptor for next disk device, or NULL if all * devices enumerated. */ -disk_device * +rtems_disk_device * rtems_disk_next(dev_t dev); /* rtems_diskio_initialize -- diff --git a/cpukit/libblock/include/rtems/ide_part_table.h b/cpukit/libblock/include/rtems/ide_part_table.h index abbbb121c4..052f445f2f 100644 --- a/cpukit/libblock/include/rtems/ide_part_table.h +++ b/cpukit/libblock/include/rtems/ide_part_table.h @@ -77,16 +77,18 @@ * sector_data_t -- * corresponds to the sector on the device */ -typedef struct sector_data_s +typedef struct rtems_sector_data_s { uint32_t sector_num; /* sector number on the device */ uint8_t data[0]; /* raw sector data */ -} sector_data_t; +} rtems_sector_data_t; /* * Enum partition types * see list at http://ata-atapi.com/hiwtab.htm + * + * @todo Should these have RTEMS before them. */ enum { EMPTY_PARTITION = 0x00, @@ -108,29 +110,32 @@ enum { /* Forward declaration */ -struct disk_desc_s; +struct rtems_disk_desc_s; /* * part_desc_t -- * contains all neccessary information about partition */ -typedef struct part_desc_s { +typedef struct rtems_part_desc_s { uint8_t bootable; /* is the partition active */ uint8_t sys_type; /* type of partition */ uint8_t log_id; /* logical number of partition */ - uint32_t start; /* first partition sector, in absolute numeration */ + uint32_t start; /* first partition sector, in absolute + * numeration */ uint32_t size; /* size in sectors */ uint32_t end; /* last partition sector, end = start + size - 1 */ - struct disk_desc_s *disk_desc; /* descriptor of disk, partition contains in */ - struct part_desc_s *ext_part; /* extended partition containing this one */ + struct rtems_disk_desc_s *disk_desc; /* descriptor of disk, partition + * contains in */ + struct rtems_part_desc_s *ext_part; /* extended partition containing this + * one */ /* partitions, containing in this one */ - struct part_desc_s *sub_part[RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER]; -} part_desc_t; + struct rtems_part_desc_s *sub_part[RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER]; +} rtems_part_desc_t; -typedef struct disk_desc_s { +typedef struct rtems_disk_desc_s { dev_t dev; /* device number */ /* device name in /dev filesystem */ @@ -142,8 +147,8 @@ typedef struct disk_desc_s { int last_log_id; /* used for logical disks enumerating */ /* primary partition descriptors */ - part_desc_t *partitions[RTEMS_IDE_PARTITION_MAX_PARTITION_NUMBER]; -} disk_desc_t; + rtems_part_desc_t *partitions[RTEMS_IDE_PARTITION_MAX_PARTITION_NUMBER]; +} rtems_disk_desc_t; #ifdef __cplusplus extern "C" { @@ -160,7 +165,7 @@ extern "C" { * N/A */ void -rtems_ide_part_table_free(disk_desc_t *disk_desc); +rtems_ide_part_table_free(rtems_disk_desc_t *disk_desc); /* @@ -176,7 +181,7 @@ rtems_ide_part_table_free(disk_desc_t *disk_desc); * RTEMS_SUCCESSFUL if success, or -1 and corresponding errno else */ rtems_status_code -rtems_ide_part_table_get(const char *dev_name, disk_desc_t *disk_desc); +rtems_ide_part_table_get(const char *dev_name, rtems_disk_desc_t *disk_desc); /* diff --git a/cpukit/libblock/include/rtems/nvdisk.h b/cpukit/libblock/include/rtems/nvdisk.h index 5e2a0dd6af..24b62f665e 100644 --- a/cpukit/libblock/include/rtems/nvdisk.h +++ b/cpukit/libblock/include/rtems/nvdisk.h @@ -164,7 +164,7 @@ typedef struct rtems_nvdisk_config const rtems_nvdisk_device_desc* devices; /**< The device descriptions. */ uint32_t flags; /**< Set of flags to control driver. */ - uint32_t info_level; /**< Default info level. */ + uint32_t info_level; /**< Default info level. */ } rtems_nvdisk_config; /* diff --git a/cpukit/libblock/include/rtems/ramdisk.h b/cpukit/libblock/include/rtems/ramdisk.h index 64d9bad5e7..8fcc442d32 100644 --- a/cpukit/libblock/include/rtems/ramdisk.h +++ b/cpukit/libblock/include/rtems/ramdisk.h @@ -1,56 +1,56 @@ -/** - * @file rtems/ramdisk.h - * RAM disk block device implementation - */ - -/* - * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia - * Author: Victor V. Vengerov <vvv@oktet.ru> - * - * @(#) $Id$ - */ - -#ifndef _RTEMS_RAMDISK_H -#define _RTEMS_RAMDISK_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <rtems.h> - -#include "rtems/blkdev.h" - -/* RAM disk configuration table entry */ -typedef struct rtems_ramdisk_config { - int block_size; /* RAM disk block size */ - int block_num; /* Number of blocks on this RAM disk */ - void *location; /* RAM disk permanent location (out of RTEMS controlled - memory), or NULL if RAM disk memory should be - allocated dynamically */ -} rtems_ramdisk_config; - -/* If application want to use RAM disk, it should specify configuration of - * available RAM disks. - * The following is definitions for RAM disk configuration table - */ -extern rtems_ramdisk_config rtems_ramdisk_configuration[]; -extern size_t rtems_ramdisk_configuration_size; - -/* ramdisk_initialize -- - * RAM disk driver initialization entry point. - */ -rtems_device_driver -ramdisk_initialize( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg); - -#define RAMDISK_DRIVER_TABLE_ENTRY \ - { ramdisk_initialize, GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES } - -#ifdef __cplusplus -} -#endif - -#endif +/**
+ * @file rtems/ramdisk.h
+ * RAM disk block device implementation
+ */
+
+/*
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Victor V. Vengerov <vvv@oktet.ru>
+ *
+ * @(#) $Id$
+ */
+
+#ifndef _RTEMS_RAMDISK_H
+#define _RTEMS_RAMDISK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+
+#include "rtems/blkdev.h"
+
+/* RAM disk configuration table entry */
+typedef struct rtems_ramdisk_config {
+ int block_size; /* RAM disk block size */
+ int block_num; /* Number of blocks on this RAM disk */
+ void *location; /* RAM disk permanent location (out of RTEMS controlled
+ memory), or NULL if RAM disk memory should be
+ allocated dynamically */
+} rtems_ramdisk_config;
+
+/* If application want to use RAM disk, it should specify configuration of
+ * available RAM disks.
+ * The following is definitions for RAM disk configuration table
+ */
+extern rtems_ramdisk_config rtems_ramdisk_configuration[];
+extern size_t rtems_ramdisk_configuration_size;
+
+/* ramdisk_initialize --
+ * RAM disk driver initialization entry point.
+ */
+rtems_device_driver
+ramdisk_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg);
+
+#define RAMDISK_DRIVER_TABLE_ENTRY \
+ { ramdisk_initialize, RTEMS_GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cpukit/libblock/src/bdbuf.c b/cpukit/libblock/src/bdbuf.c index 17c710a668..07669d0c9e 100644 --- a/cpukit/libblock/src/bdbuf.c +++ b/cpukit/libblock/src/bdbuf.c @@ -10,657 +10,912 @@ * @(#) bdbuf.c,v 1.14 2004/04/17 08:15:17 ralf Exp */ +/** + * @file + * + * The Buffer Descriptor Buffer code implement a cache between the disk + * devices and file systems. The code provides a read ahead and qrite queuing + * to the drivers and fast cache look up using an AVL tree. + * + * The buffers are held in pools based on size. Each pool has buffers and the + * buffers follow this state machine: + * + * read + * +-------------------------------+ + * | v + * +-----------+ read complete +------------+ + * | | write complete | |---------+ + * | EMPTY | +---------| TRANSFER | | + * | | | | |<--+ | + * +-----------+ | +------------+ | | + * ^ | get v swap | | + * | | +-----------+ modified +------------+ | + * | +--->| |---------->| | | + * | | ACCESSED |<----------| MODIFIED | | + * | +----| |<--+ get | | | + * | | +-----------+ | +------------+ | + * | | | | + * | | release get | | + * | | | | + * | | +-----------+ | | + * expire | +--->| |---+ read complete | + * | | CACHED | write complete | + * +--------| |<-------------------------+ + * +-----------+ + * + * Empty buffers are added to the empty list and removed from this queue when a + * caller wishes to access a buffer. This is referred to getting a buffer in + * the code and the event get in the state diagram. The buffer is assigned to a + * block and inserted to the AVL. If the block is to be read by the user and + * not in the cache (empty) it is transfered from the disk into memory. If no + * empty buffers exist the buffer is expired from the cache. Currently the + * least recently used block is expired first. A block being accessed is given + * to the file system layer and not accessable to another requester until + * released back to the cache. If the user has modifed the block it is + * transfered to disk then placed on the LRU list. + * + * The pool have the following lists of buffers: + * + * empty - Empty buffers created when the pool is initialised. + * modided - Buffers waiting to be written to disk. + * cached_lru - Accessed buffers released in least recently used order. + * cached_unsed - Read ahead buffers that have not been accessed. + * + */ + +/** + * Set to 1 to enable debug tracing. + */ +#define RTEMS_BDBUF_TRACE 0 + #if HAVE_CONFIG_H #include "config.h" #endif -#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ #include <rtems.h> +#include <rtems/error.h> #include <limits.h> #include <errno.h> #include <assert.h> -#include "rtems/bdbuf.h" - -/* Fatal errors: */ -#define BLKDEV_FATAL_ERROR(n) (((uint32_t)'B' << 24) | ((uint32_t)(n) & (uint32_t)0x00FFFFFF)) -#define BLKDEV_FATAL_BDBUF_CONSISTENCY BLKDEV_FATAL_ERROR(1) -#define BLKDEV_FATAL_BDBUF_SWAPOUT BLKDEV_FATAL_ERROR(2) - - -#define SWAPOUT_TASK_STACK_SIZE (RTEMS_MINIMUM_STACK_SIZE * 2) - -#define READ_MULTIPLE - -#if defined(READ_MULTIPLE) -#define READ_AHEAD_MAX_BLK_CNT 32 -typedef struct { - blkdev_request req; - blkdev_sg_buffer sg[READ_AHEAD_MAX_BLK_CNT]; -} blkdev_request_read_ahead; -/* - * list of bd_bufs related to one transfer request - */ -typedef struct { - int cnt; - bdbuf_buffer *bd_bufs[READ_AHEAD_MAX_BLK_CNT]; -} read_ahead_bd_buf_group; +#if RTEMS_BDBUF_TRACE +#include <stdio.h> #endif -typedef struct { - blkdev_request *req; - bdbuf_buffer **write_store; -} write_tfer_done_arg_t; - -static rtems_task bdbuf_swapout_task(rtems_task_argument unused); +#include "rtems/bdbuf.h" -static rtems_status_code bdbuf_release(bdbuf_buffer *bd_buf); -/* - * maximum number of blocks that might be chained together to one - * write driver call +/** + * The BD buffer context. */ -#define SWAP_OUT_MAX_BLK_CNT 32 -/*#define SWAP_OUT_MAX_BLK_CNT 1 */ -/* - * XXX: this is a global buffer. It is used in the swapout task - * and currently will be reused only after it is no longer in use - * +/* Buffering layer context definition */ +typedef struct rtems_bdbuf_context { + rtems_bdbuf_pool* pool; /* Table of buffer pools */ + int npools; /* Number of entries in pool table */ + rtems_id swapout; /* Swapout task ID */ + boolean swapout_enabled; +} rtems_bdbuf_context; + +/** + * Fatal errors */ -static bdbuf_buffer *bd_buf_write_store[SWAP_OUT_MAX_BLK_CNT]; - -/* Block device request with a single buffer provided */ -typedef struct blkdev_request1 { - blkdev_request req; - blkdev_sg_buffer sg[1]; -} blkdev_request1; - -/* The context of buffering layer */ -struct bdbuf_context rtems_bdbuf_ctx; - -#define SAFE -#ifdef SAFE -typedef rtems_mode preemption_key; - -#define DISABLE_PREEMPTION(key) \ - do { \ - rtems_task_mode(RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &(key)); \ - } while (0) - -#define ENABLE_PREEMPTION(key) \ - do { \ - rtems_mode temp; \ - rtems_task_mode((key), RTEMS_PREEMPT_MASK, &temp); \ - } while (0) - -#else +#define RTEMS_BLKDEV_FATAL_ERROR(n) (((uint32_t)'B' << 24) | \ + ((uint32_t)(n) & (uint32_t)0x00FFFFFF)) + +#define RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY RTEMS_BLKDEV_FATAL_ERROR(1) +#define RTEMS_BLKDEV_FATAL_BDBUF_SWAPOUT RTEMS_BLKDEV_FATAL_ERROR(2) +#define RTEMS_BLKDEV_FATAL_BDBUF_SYNC_LOCK RTEMS_BLKDEV_FATAL_ERROR(3) +#define RTEMS_BLKDEV_FATAL_BDBUF_SYNC_UNLOCK RTEMS_BLKDEV_FATAL_ERROR(4) +#define RTEMS_BLKDEV_FATAL_BDBUF_POOL_LOCK RTEMS_BLKDEV_FATAL_ERROR(5) +#define RTEMS_BLKDEV_FATAL_BDBUF_POOL_UNLOCK RTEMS_BLKDEV_FATAL_ERROR(6) +#define RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAIT RTEMS_BLKDEV_FATAL_ERROR(7) +#define RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAKE RTEMS_BLKDEV_FATAL_ERROR(8) +#define RTEMS_BLKDEV_FATAL_BDBUF_SO_WAKE RTEMS_BLKDEV_FATAL_ERROR(9) +#define RTEMS_BLKDEV_FATAL_BDBUF_SO_NOMEM RTEMS_BLKDEV_FATAL_ERROR(10) +#define BLKDEV_FATAL_BDBUF_SWAPOUT_RE RTEMS_BLKDEV_FATAL_ERROR(11) +#define BLKDEV_FATAL_BDBUF_SWAPOUT_TS RTEMS_BLKDEV_FATAL_ERROR(12) + +#define RTEMS_BDBUF_TRANSFER_SYNC RTEMS_EVENT_1 +#define RTEMS_BDBUF_SWAPOUT_SYNC RTEMS_EVENT_2 + +#define SWAPOUT_TASK_STACK_SIZE (8 * 1024) + +/** + * Lock semaphore attributes. This is used for locking type mutexes. + */ +#define RTEMS_BDBUF_POOL_LOCK_ATTRIBS \ + (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | \ + RTEMS_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL) -typedef boolean preemption_key; +/** + * Waiter semaphore attributes. + * + * @note Do not configure as inherit priority. If a driver is in the driver + * initialisation table this locked semaphore will have the IDLE task as + * the holder and a blocking task will raise the priority of the IDLE + * task which can cause unsual side effects. + */ +#define RTEMS_BDBUF_POOL_WAITER_ATTRIBS \ + (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | \ + RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL) -#define DISABLE_PREEMPTION(key) \ - do { \ - (key) = _Thread_Executing->is_preemptible; \ - _Thread_Executing->is_preemptible = 0; \ - } while (0) +/* + * The swap out task. + */ +static rtems_task rtems_bdbuf_swapout_task(rtems_task_argument arg); -#define ENABLE_PREEMPTION(key) \ - do { \ - _Thread_Executing->is_preemptible = (key); \ - if (_Thread_Evaluate_mode()) \ - _Thread_Dispatch(); \ - } while (0) +/** + * The context of buffering layer. + */ +static rtems_bdbuf_context rtems_bdbuf_ctx; +/** + * Print a message to the bdbuf trace output and flush it. + * + * @param format The format string. See printf for details. + * @param ... The arguments for the format text. + * @return int The number of bytes written to the output. + */ +#if RTEMS_BDBUF_TRACE +boolean rtems_bdbuf_tracer; +static void +rtems_bdbuf_printf (const char *format, ...) +{ + va_list args; + va_start (args, format); + if (rtems_bdbuf_tracer) + { + fprintf (stdout, "bdbuf:"); + vfprintf (stdout, format, args); + fflush (stdout); + } +} #endif - -/* The default maximum height of 32 allows for AVL trees having - between 5,704,880 and 4,294,967,295 nodes, depending on order of - insertion. You may change this compile-time constant as you - wish. */ -#ifndef AVL_MAX_HEIGHT -#define AVL_MAX_HEIGHT 32 +/** + * The default maximum height of 32 allows for AVL trees having between + * 5,704,880 and 4,294,967,295 nodes, depending on order of insertion. You may + * change this compile-time constant as you wish. + */ +#ifndef RTEMS_BDBUF_AVL_MAX_HEIGHT +#define RTEMS_BDBUF_AVL_MAX_HEIGHT (32) #endif -/* - * avl_search -- - * Searches for the node with specified dev/block. - * - * PARAMETERS: - * root - pointer to the root node of the AVL-Tree. - * dev, block - search key +/** + * Searches for the node with specified dev/block. * - * RETURNS: - * NULL if node with specified dev/block not found - * non-NULL - pointer to the node with specified dev/block + * @param root pointer to the root node of the AVL-Tree + * @param dev device search key + * @param block block search key + * @retval NULL node with the specified dev/block is not found + * @return pointer to the node with specified dev/block */ -static bdbuf_buffer * -avl_search(bdbuf_buffer **root, dev_t dev, blkdev_bnum block) +static rtems_bdbuf_buffer * +rtems_bdbuf_avl_search (rtems_bdbuf_buffer** root, + dev_t dev, + rtems_blkdev_bnum block) { - bdbuf_buffer *p = *root; + rtems_bdbuf_buffer* p = *root; - while ((p != NULL) && ((p->dev != dev) || (p->block != block))) + while ((p != NULL) && ((p->dev != dev) || (p->block != block))) + { + if ((p->dev < dev) || ((p->dev == dev) && (p->block < block))) { - if ((p->dev < dev) || ((p->dev == dev) && (p->block < block))) - { - p = p->avl.right; - } - else - { - p = p->avl.left; - } + p = p->avl.right; + } + else + { + p = p->avl.left; } + } - return p; + return p; } - -/* avl_search_for_sync -- - * Search in AVL tree for first modified buffer belongs to specified - * disk device. +#if CCJ_REMOVE_IN_IN_CVS +/** + * Search in AVL tree for first modified buffer belongs to specified + * disk device. * - * PARAMETERS: - * root - pointer to tree root - * dd - disk device descriptor - * - * RETURNS: - * Block buffer, or NULL if no modified blocks on specified device - * exists. + * @param root pointer to the root node of the AVL-Tree + * @param dd - disk device descriptor + * @retval NULL no modified blocks on the disk device + * @return pointer to the modified node */ -static bdbuf_buffer * -avl_search_for_sync(bdbuf_buffer **root, disk_device *dd) +static rtems_bdbuf_buffer * +rtems_bdbuf_avl_search_for_sync (rtems_bdbuf_buffer** root, + rtems_disk_device* dd) { - dev_t dev = dd->phys_dev->dev; - blkdev_bnum block_start = dd->start; - blkdev_bnum block_end = dd->start + dd->size - 1; - - bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT]; - bdbuf_buffer **buf_prev = buf_stack; - bdbuf_buffer *p = *root; - - while (p != NULL) + dev_t dev = dd->phys_dev->dev; + rtems_blkdev_bnum block_start = dd->start; + rtems_blkdev_bnum block_end = dd->start + dd->size - 1; + rtems_bdbuf_buffer* buf_stack[RTEMS_BDBUF_AVL_MAX_HEIGHT]; + rtems_bdbuf_buffer** buf_prev = buf_stack; + rtems_bdbuf_buffer* p = *root; + + while (p != NULL) + { + if ((p->dev < dev) || ((p->dev == dev) && (p->block < block_start))) { - if ((p->dev < dev) || ((p->dev == dev) && (p->block < block_start))) - { - p = p->avl.right; - } - else if ((p->dev > dev) || ((p->dev == dev) && (p->block > block_end))) - { - p = p->avl.left; - } - else if (p->modified) - { - return p; - } - else - { - if (p->avl.right != NULL) - { - *buf_prev++ = p->avl.right; - } - p = p->avl.left; - } + p = p->avl.right; + } + else if ((p->dev > dev) || ((p->dev == dev) && (p->block > block_end))) + { + p = p->avl.left; + } + else if (p->state == RTEMS_BDBUF_STATE_MODIFIED) + { + return p; + } + else + { + if (p->avl.right != NULL) + { + *buf_prev++ = p->avl.right; + } + p = p->avl.left; + } - if ((p == NULL) && (buf_prev > buf_stack)) - { - p = *--buf_prev; - } + if ((p == NULL) && (buf_prev > buf_stack)) + { + p = *--buf_prev; } + } - return p; + return p; } +#endif - -/* - * avl_insert -- - * Inserts the specified node to the AVl-Tree. - * - * PARAMETERS: - * root - Pointer to pointer to the root node - * node - Pointer to the node to add. +/** + * Inserts the specified node to the AVl-Tree. * - * RETURNS: - * 0 - The node added successfully - * -1 - An error occured + * @param root pointer to the root node of the AVL-Tree + * @param node Pointer to the node to add. + * @retval 0 The node added successfully + * @retval -1 An error occured */ static int -avl_insert(bdbuf_buffer **root, bdbuf_buffer *node) +rtems_bdbuf_avl_insert(rtems_bdbuf_buffer** root, + rtems_bdbuf_buffer* node) { - dev_t dev = node->dev; - blkdev_bnum block = node->block; - - bdbuf_buffer *p = *root; - bdbuf_buffer *q, *p1, *p2; - bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT]; - bdbuf_buffer **buf_prev = buf_stack; + dev_t dev = node->dev; + rtems_blkdev_bnum block = node->block; + + rtems_bdbuf_buffer* p = *root; + rtems_bdbuf_buffer* q; + rtems_bdbuf_buffer* p1; + rtems_bdbuf_buffer* p2; + rtems_bdbuf_buffer* buf_stack[RTEMS_BDBUF_AVL_MAX_HEIGHT]; + rtems_bdbuf_buffer** buf_prev = buf_stack; + + boolean modified = FALSE; + + if (p == NULL) + { + *root = node; + node->avl.left = NULL; + node->avl.right = NULL; + node->avl.bal = 0; + return 0; + } - boolean modified = FALSE; + while (p != NULL) + { + *buf_prev++ = p; - if (p == NULL) + if ((p->dev < dev) || ((p->dev == dev) && (p->block < block))) { - *root = node; - node->avl.left = NULL; - node->avl.right = NULL; - node->avl.bal = 0; - return 0; + p->avl.cache = 1; + q = p->avl.right; + if (q == NULL) + { + q = node; + p->avl.right = q = node; + break; + } } - - while (p != NULL) + else if ((p->dev != dev) || (p->block != block)) { - *buf_prev++ = p; - - if ((p->dev < dev) || ((p->dev == dev) && (p->block < block))) - { - p->avl.cache = 1; - q = p->avl.right; - if (q == NULL) - { - q = node; - p->avl.right = q = node; - break; - } - } - else if ((p->dev != dev) || (p->block != block)) - { - p->avl.cache = -1; - q = p->avl.left; - if (q == NULL) - { - q = node; - p->avl.left = q; - break; - } - } - else - { - return -1; - } - - p = q; + p->avl.cache = -1; + q = p->avl.left; + if (q == NULL) + { + q = node; + p->avl.left = q; + break; + } + } + else + { + return -1; } - q->avl.left = q->avl.right = NULL; - q->avl.bal = 0; - modified = TRUE; - buf_prev--; + p = q; + } - while (modified) - { - if (p->avl.cache == -1) - { - switch (p->avl.bal) - { - case 1: - p->avl.bal = 0; - modified = FALSE; - break; - - case 0: - p->avl.bal = -1; - break; - - case -1: - p1 = p->avl.left; - if (p1->avl.bal == -1) /* simple LL-turn */ - { - p->avl.left = p1->avl.right; - p1->avl.right = p; - p->avl.bal = 0; - p = p1; - } - else /* double LR-turn */ - { - p2 = p1->avl.right; - p1->avl.right = p2->avl.left; - p2->avl.left = p1; - p->avl.left = p2->avl.right; - p2->avl.right = p; - if (p2->avl.bal == -1) p->avl.bal = +1; else p->avl.bal = 0; - if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0; - p = p2; - } - p->avl.bal = 0; - modified = FALSE; - break; - - default: - break; - } - } - else - { - switch (p->avl.bal) - { - case -1: - p->avl.bal = 0; - modified = FALSE; - break; - - case 0: - p->avl.bal = 1; - break; - - case 1: - p1 = p->avl.right; - if (p1->avl.bal == 1) /* simple RR-turn */ - { - p->avl.right = p1->avl.left; - p1->avl.left = p; - p->avl.bal = 0; - p = p1; - } - else /* double RL-turn */ - { - p2 = p1->avl.left; - p1->avl.left = p2->avl.right; - p2->avl.right = p1; - p->avl.right = p2->avl.left; - p2->avl.left = p; - if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0; - if (p2->avl.bal == -1) p1->avl.bal = +1; else p1->avl.bal = 0; - p = p2; - } - p->avl.bal = 0; - modified = FALSE; - break; - - default: - break; - } - } - q = p; - if (buf_prev > buf_stack) - { - p = *--buf_prev; + q->avl.left = q->avl.right = NULL; + q->avl.bal = 0; + modified = TRUE; + buf_prev--; - if (p->avl.cache == -1) - { - p->avl.left = q; - } - else - { - p->avl.right = q; - } - } - else - { - *root = p; - break; - } - }; + while (modified) + { + if (p->avl.cache == -1) + { + switch (p->avl.bal) + { + case 1: + p->avl.bal = 0; + modified = FALSE; + break; + + case 0: + p->avl.bal = -1; + break; + + case -1: + p1 = p->avl.left; + if (p1->avl.bal == -1) /* simple LL-turn */ + { + p->avl.left = p1->avl.right; + p1->avl.right = p; + p->avl.bal = 0; + p = p1; + } + else /* double LR-turn */ + { + p2 = p1->avl.right; + p1->avl.right = p2->avl.left; + p2->avl.left = p1; + p->avl.left = p2->avl.right; + p2->avl.right = p; + if (p2->avl.bal == -1) p->avl.bal = +1; else p->avl.bal = 0; + if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0; + p = p2; + } + p->avl.bal = 0; + modified = FALSE; + break; + + default: + break; + } + } + else + { + switch (p->avl.bal) + { + case -1: + p->avl.bal = 0; + modified = FALSE; + break; + + case 0: + p->avl.bal = 1; + break; + + case 1: + p1 = p->avl.right; + if (p1->avl.bal == 1) /* simple RR-turn */ + { + p->avl.right = p1->avl.left; + p1->avl.left = p; + p->avl.bal = 0; + p = p1; + } + else /* double RL-turn */ + { + p2 = p1->avl.left; + p1->avl.left = p2->avl.right; + p2->avl.right = p1; + p->avl.right = p2->avl.left; + p2->avl.left = p; + if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0; + if (p2->avl.bal == -1) p1->avl.bal = +1; else p1->avl.bal = 0; + p = p2; + } + p->avl.bal = 0; + modified = FALSE; + break; + + default: + break; + } + } + q = p; + if (buf_prev > buf_stack) + { + p = *--buf_prev; + + if (p->avl.cache == -1) + { + p->avl.left = q; + } + else + { + p->avl.right = q; + } + } + else + { + *root = p; + break; + } + }; - return 0; + return 0; } -/* avl_remove -- - * removes the node from the tree. +/** + * Removes the node from the tree. * - * PARAMETERS: - * root_addr - Pointer to pointer to the root node - * node - Pointer to the node to remove - * - * RETURNS: - * 0 - Item removed - * -1 - No such item found + * @param root_addr Pointer to pointer to the root node + * @param node Pointer to the node to remove + * @retval 0 Item removed + * @retval -1 No such item found */ static int -avl_remove(bdbuf_buffer **root, const bdbuf_buffer *node) +rtems_bdbuf_avl_remove(rtems_bdbuf_buffer** root, + const rtems_bdbuf_buffer* node) { - dev_t dev = node->dev; - blkdev_bnum block = node->block; + dev_t dev = node->dev; + rtems_blkdev_bnum block = node->block; - bdbuf_buffer *p = *root; - bdbuf_buffer *q, *r, *s, *p1, *p2; - bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT]; - bdbuf_buffer **buf_prev = buf_stack; + rtems_bdbuf_buffer* p = *root; + rtems_bdbuf_buffer* q; + rtems_bdbuf_buffer* r; + rtems_bdbuf_buffer* s; + rtems_bdbuf_buffer* p1; + rtems_bdbuf_buffer* p2; + rtems_bdbuf_buffer* buf_stack[RTEMS_BDBUF_AVL_MAX_HEIGHT]; + rtems_bdbuf_buffer** buf_prev = buf_stack; - boolean modified = FALSE; + boolean modified = FALSE; - memset(buf_stack, 0, sizeof(buf_stack)); + memset (buf_stack, 0, sizeof(buf_stack)); - while (p != NULL) - { - *buf_prev++ = p; + while (p != NULL) + { + *buf_prev++ = p; - if ((p->dev < dev) || ((p->dev == dev) && (p->block < block))) - { - p->avl.cache = 1; - p = p->avl.right; - } - else if ((p->dev != dev) || (p->block != block)) - { - p->avl.cache = -1; - p = p->avl.left; - } - else - { - /* node found */ - break; - } + if ((p->dev < dev) || ((p->dev == dev) && (p->block < block))) + { + p->avl.cache = 1; + p = p->avl.right; + } + else if ((p->dev != dev) || (p->block != block)) + { + p->avl.cache = -1; + p = p->avl.left; } + else + { + /* node found */ + break; + } + } + + if (p == NULL) + { + /* there is no such node */ + return -1; + } + + q = p; - if (p == NULL) + buf_prev--; + if (buf_prev > buf_stack) + { + p = *(buf_prev - 1); + } + else + { + p = NULL; + } + + /* at this moment q - is a node to delete, p is q's parent */ + if (q->avl.right == NULL) + { + r = q->avl.left; + if (r != NULL) { - /* there is no such node */ - return -1; + r->avl.bal = 0; } + q = r; + } + else + { + rtems_bdbuf_buffer **t; - q = p; + r = q->avl.right; - buf_prev--; - if (buf_prev > buf_stack) + if (r->avl.left == NULL) { - p = *(buf_prev - 1); + r->avl.left = q->avl.left; + r->avl.bal = q->avl.bal; + r->avl.cache = 1; + *buf_prev++ = q = r; } else { - p = NULL; + t = buf_prev++; + s = r; + + while (s->avl.left != NULL) + { + *buf_prev++ = r = s; + s = r->avl.left; + r->avl.cache = -1; + } + + s->avl.left = q->avl.left; + r->avl.left = s->avl.right; + s->avl.right = q->avl.right; + s->avl.bal = q->avl.bal; + s->avl.cache = 1; + + *t = q = s; } + } - /* at this moment q - is a node to delete, p is q's parent */ - if (q->avl.right == NULL) + if (p != NULL) + { + if (p->avl.cache == -1) { - r = q->avl.left; - if (r != NULL) - { - r->avl.bal = 0; - } - q = r; + p->avl.left = q; } else { - bdbuf_buffer **t; - - r = q->avl.right; - - if (r->avl.left == NULL) - { - r->avl.left = q->avl.left; - r->avl.bal = q->avl.bal; - r->avl.cache = 1; - *buf_prev++ = q = r; - } - else - { - t = buf_prev++; - s = r; - - while (s->avl.left != NULL) - { - *buf_prev++ = r = s; - s = r->avl.left; - r->avl.cache = -1; - } - - s->avl.left = q->avl.left; - r->avl.left = s->avl.right; - s->avl.right = q->avl.right; - s->avl.bal = q->avl.bal; - s->avl.cache = 1; - - *t = q = s; - } + p->avl.right = q; } + } + else + { + *root = q; + } + + modified = TRUE; - if (p != NULL) + while (modified) + { + if (buf_prev > buf_stack) { - if (p->avl.cache == -1) - { - p->avl.left = q; - } - else - { - p->avl.right = q; - } + p = *--buf_prev; } else { - *root = q; + break; } - modified = TRUE; - - while (modified) + if (p->avl.cache == -1) { - if (buf_prev > buf_stack) - { - p = *--buf_prev; - } - else - { - break; - } - - if (p->avl.cache == -1) - { - /* rebalance left branch */ - switch (p->avl.bal) + /* rebalance left branch */ + switch (p->avl.bal) + { + case -1: + p->avl.bal = 0; + break; + case 0: + p->avl.bal = 1; + modified = FALSE; + break; + + case +1: + p1 = p->avl.right; + + if (p1->avl.bal >= 0) /* simple RR-turn */ + { + p->avl.right = p1->avl.left; + p1->avl.left = p; + + if (p1->avl.bal == 0) { - case -1: - p->avl.bal = 0; - break; - case 0: - p->avl.bal = 1; - modified = FALSE; - break; - - case +1: - p1 = p->avl.right; - - if (p1->avl.bal >= 0) /* simple RR-turn */ - { - p->avl.right = p1->avl.left; - p1->avl.left = p; - - if (p1->avl.bal == 0) - { - p1->avl.bal = -1; - modified = FALSE; - } - else - { - p->avl.bal = 0; - p1->avl.bal = 0; - } - p = p1; - } - else /* double RL-turn */ - { - p2 = p1->avl.left; - - p1->avl.left = p2->avl.right; - p2->avl.right = p1; - p->avl.right = p2->avl.left; - p2->avl.left = p; - - if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0; - if (p2->avl.bal == -1) p1->avl.bal = 1; else p1->avl.bal = 0; - - p = p2; - p2->avl.bal = 0; - } - break; - - default: - break; + p1->avl.bal = -1; + modified = FALSE; } - } - else - { - /* rebalance right branch */ - switch (p->avl.bal) + else { - case +1: - p->avl.bal = 0; - break; - - case 0: - p->avl.bal = -1; - modified = FALSE; - break; - - case -1: - p1 = p->avl.left; - - if (p1->avl.bal <= 0) /* simple LL-turn */ - { - p->avl.left = p1->avl.right; - p1->avl.right = p; - if (p1->avl.bal == 0) - { - p1->avl.bal = 1; - modified = FALSE; - } - else - { - p->avl.bal = 0; - p1->avl.bal = 0; - } - p = p1; - } - else /* double LR-turn */ - { - p2 = p1->avl.right; - - p1->avl.right = p2->avl.left; - p2->avl.left = p1; - p->avl.left = p2->avl.right; - p2->avl.right = p; - - if (p2->avl.bal == -1) p->avl.bal = 1; else p->avl.bal = 0; - if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0; - - p = p2; - p2->avl.bal = 0; - } - break; - - default: - break; + p->avl.bal = 0; + p1->avl.bal = 0; } - } - - if (buf_prev > buf_stack) - { - q = *(buf_prev - 1); - - if (q->avl.cache == -1) + p = p1; + } + else /* double RL-turn */ + { + p2 = p1->avl.left; + + p1->avl.left = p2->avl.right; + p2->avl.right = p1; + p->avl.right = p2->avl.left; + p2->avl.left = p; + + if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0; + if (p2->avl.bal == -1) p1->avl.bal = 1; else p1->avl.bal = 0; + + p = p2; + p2->avl.bal = 0; + } + break; + + default: + break; + } + } + else + { + /* rebalance right branch */ + switch (p->avl.bal) + { + case +1: + p->avl.bal = 0; + break; + + case 0: + p->avl.bal = -1; + modified = FALSE; + break; + + case -1: + p1 = p->avl.left; + + if (p1->avl.bal <= 0) /* simple LL-turn */ + { + p->avl.left = p1->avl.right; + p1->avl.right = p; + if (p1->avl.bal == 0) { - q->avl.left = p; + p1->avl.bal = 1; + modified = FALSE; } else { - q->avl.right = p; + p->avl.bal = 0; + p1->avl.bal = 0; } - } - else - { - *root = p; - break; - } + p = p1; + } + else /* double LR-turn */ + { + p2 = p1->avl.right; + + p1->avl.right = p2->avl.left; + p2->avl.left = p1; + p->avl.left = p2->avl.right; + p2->avl.right = p; + + if (p2->avl.bal == -1) p->avl.bal = 1; else p->avl.bal = 0; + if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0; + + p = p2; + p2->avl.bal = 0; + } + break; + + default: + break; + } + } + if (buf_prev > buf_stack) + { + q = *(buf_prev - 1); + + if (q->avl.cache == -1) + { + q->avl.left = p; + } + else + { + q->avl.right = p; + } + } + else + { + *root = p; + break; } - return 0; + } + + return 0; +} + +/** + * Get the pool for the device. + * + * @param pdd Physical disk device. + */ +static rtems_bdbuf_pool* +rtems_bdbuf_get_pool (const rtems_bdpool_id pid) +{ + return &rtems_bdbuf_ctx.pool[pid]; +} + +/** + * Lock the pool. A single task can nest calls. + * + * @param pool The pool to lock. + */ +static void +rtems_bdbuf_lock_pool (rtems_bdbuf_pool* pool) +{ + rtems_status_code sc = rtems_semaphore_obtain (pool->lock, + RTEMS_WAIT, + RTEMS_NO_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_LOCK); +} + +/** + * Unlock the pool. + * + * @param pool The pool to unlock. + */ +static void +rtems_bdbuf_unlock_pool (rtems_bdbuf_pool* pool) +{ + rtems_status_code sc = rtems_semaphore_release (pool->lock); + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_UNLOCK); +} + +/** + * Lock the pool's sync. A single task can nest calls. + * + * @param pool The pool's sync to lock. + */ +static void +rtems_bdbuf_lock_sync (rtems_bdbuf_pool* pool) +{ + rtems_status_code sc = rtems_semaphore_obtain (pool->sync_lock, + RTEMS_WAIT, + RTEMS_NO_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SYNC_LOCK); +} + +/** + * Unlock the pool's sync. + * + * @param pool The pool's sync to unlock. + */ +static void +rtems_bdbuf_unlock_sync (rtems_bdbuf_pool* pool) +{ + rtems_status_code sc = rtems_semaphore_release (pool->sync_lock); + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SYNC_UNLOCK); +} + +/** + * Wait until woken. Semaphores are used so a number of tasks can wait and + * can be woken at once. Task events would require we maintain a list + * of tasks to be woken and this would require storgage and we do not + * know the number of tasks that could be waiting. + * + * While we have the pool locked we can try and claim the semaphore and + * therefore know when we release the lock to the pool we will block until the + * semaphore is released. This may even happen before we get to block. + * + * A counter is used to save the release call when no one is waiting. + * + * The function assumes the pool is locked on entry and it will have locked + * the pool on exit. + * + * @param pool The pool to wait for a buffer to return. + * @param sema The semaphore to block on and wait. + * @param waiters The wait counter for this semaphore. + */ +static void +rtems_bdbuf_wait (rtems_bdbuf_pool* pool, rtems_id* sema, + volatile uint32_t* waiters) +{ + rtems_status_code sc; + rtems_mode prev_mode; + + /* + * Indicate we are waiting. + */ + *waiters += 1; + + /* + * Disable preemption then unlock the pool and block. + * There is no POSIX condition variable in the core API so + * this is a work around. + * + * The issue is a task could preempt after the pool is unlocked + * because it is blocking or just hits that window, and before + * this task has blocked on the semaphore. If the preempting task + * flushes the queue this task will not see the flush and may + * block for ever or until another transaction flushes this + * semaphore. + */ + sc = rtems_task_mode (RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &prev_mode); + + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAIT); + + /* + * Unlock the pool, wait, and lock the pool when we return. + */ + rtems_bdbuf_unlock_pool (pool); + + sc = rtems_semaphore_obtain (*sema, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + + if (sc != RTEMS_UNSATISFIED) + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAIT); + + rtems_bdbuf_lock_pool (pool); + + sc = rtems_task_mode (prev_mode, RTEMS_ALL_MODE_MASKS, &prev_mode); + + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAIT); + + *waiters -= 1; +} + +/** + * Wake a blocked resource. The resource has a counter that lets us know if + * there are any waiters. + * + * @param sema The semaphore to release. + * @param waiters The wait counter for this semaphore. + */ +static void +rtems_bdbuf_wake (rtems_id sema, volatile uint32_t* waiters) +{ + if (*waiters) + { + rtems_status_code sc; + + sc = rtems_semaphore_flush (sema); + + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAKE); + } +} + +/** + * Add a buffer descriptor to the modified list. This modified list is treated + * a litte differently to the other lists. To access it you must have the pool + * locked and this is assumed to be the case on entry to this call and you must + * hold the sync lock. The sync lock is used to block writes while a sync is + * active. + * + * @param sema The semaphore to release. + * @param waiters The wait counter for this semaphore. + */ +static void +rtems_bdbuf_append_modified (rtems_bdbuf_pool* pool, rtems_bdbuf_buffer* bd) +{ + /* + * Take a copy of the sync_active variable as it will change after + * we unlock the pool and wait for the sync to finish. + */ + int sync_active = pool->sync_active; + if (0 && sync_active) + { + rtems_bdbuf_unlock_pool (pool); + rtems_bdbuf_lock_sync (pool); + rtems_bdbuf_lock_pool (pool); + } + + bd->state = RTEMS_BDBUF_STATE_MODIFIED; + + rtems_chain_append (&pool->modified, &bd->link); + + if (0 && sync_active) + rtems_bdbuf_unlock_sync (pool); +} + +static void +rtems_bdbuf_wake_swapper () +{ + rtems_status_code sc = rtems_event_send (rtems_bdbuf_ctx.swapout, + RTEMS_BDBUF_SWAPOUT_SYNC); + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SO_WAKE); } /* bdbuf_initialize_pool -- @@ -675,70 +930,134 @@ avl_remove(bdbuf_buffer **root, const bdbuf_buffer *node) * code if error occured. */ static rtems_status_code -bdbuf_initialize_pool(rtems_bdbuf_config *config, int pool) +rtems_bdbuf_initialize_pool (rtems_bdbuf_pool_config* config, + rtems_bdpool_id pid) { - bdbuf_pool *p = rtems_bdbuf_ctx.pool + pool; - unsigned char *bufs; - bdbuf_buffer *b; - rtems_status_code rc; - int i; - - p->blksize = config->size; - p->nblks = config->num; - p->tree = NULL; - - rtems_chain_initialize_empty(&p->free); - rtems_chain_initialize_empty(&p->lru); - - /* Allocate memory for buffer descriptors */ - p->bdbufs = calloc(config->num, sizeof(bdbuf_buffer)); - if (p->bdbufs == NULL) - { - return RTEMS_NO_MEMORY; - } + unsigned char* buffer = config->mem_area; + rtems_bdbuf_pool* pool; + rtems_bdbuf_buffer* bd; + rtems_status_code sc; + int b; - /* Allocate memory for buffers if required */ - if (config->mem_area == NULL) - { - bufs = p->mallocd_bufs = malloc(config->num * config->size); - if (bufs == NULL) - { - free(p->bdbufs); - return RTEMS_NO_MEMORY; - } - } - else + pool = rtems_bdbuf_get_pool (pid); + + pool->blksize = config->size; + pool->nblks = config->num; + pool->tree = NULL; + pool->buffers = NULL; + + rtems_chain_initialize_empty (&pool->ready); + rtems_chain_initialize_empty (&pool->lru); + rtems_chain_initialize_empty (&pool->modified); + rtems_chain_initialize_empty (&pool->sync); + + pool->access = 0; + pool->access_waiters = 0; + pool->transfer = 0; + pool->transfer_waiters = 0; + pool->waiting = 0; + pool->wait_waiters = 0; + + /* + * Allocate memory for buffer descriptors + */ + pool->bds = calloc (config->num, sizeof (rtems_bdbuf_buffer)); + + if (!pool->bds) + return RTEMS_NO_MEMORY; + + /* + * Allocate memory for buffers if required. + */ + if (buffer == NULL) + { + buffer = pool->buffers = malloc (config->num * config->size); + if (!pool->buffers) { - bufs = config->mem_area; - p->mallocd_bufs = NULL; + free (pool->bds); + return RTEMS_NO_MEMORY; } + } - for (i = 0, b = p->bdbufs; i < p->nblks; i++, b++, bufs += p->blksize) - { - b->dev = -1; b->block = 0; - b->buffer = bufs; - b->actual = b->modified = b->in_progress = FALSE; - b->use_count = 0; - b->pool = pool; - rtems_chain_append(&p->free, &b->link); - } + for (b = 0, bd = pool->bds; + b < pool->nblks; + b++, bd++, buffer += pool->blksize) + { + bd->dev = -1; + bd->block = 0; + bd->buffer = buffer; + bd->avl.left = NULL; + bd->avl.right = NULL; + bd->state = RTEMS_BDBUF_STATE_EMPTY; + bd->pool = pid; + bd->error = 0; + bd->waiters = 0; + bd->hold_timer = 0; + + rtems_chain_append (&pool->ready, &bd->link); + } - rc = rtems_semaphore_create( - rtems_build_name('B', 'U', 'F', 'G'), - p->nblks, - RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | - RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, - 0, - &p->bufget_sema); + sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 'L'), + 1, RTEMS_BDBUF_POOL_LOCK_ATTRIBS, 0, + &pool->lock); + if (sc != RTEMS_SUCCESSFUL) + { + free (pool->buffers); + free (pool->bds); + return sc; + } - if (rc != RTEMS_SUCCESSFUL) - { - free(p->bdbufs); - free(p->mallocd_bufs); - return rc; - } + sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 's'), + 0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0, + &pool->sync_lock); + if (sc != RTEMS_SUCCESSFUL) + { + rtems_semaphore_delete (pool->lock); + free (pool->buffers); + free (pool->bds); + return sc; + } + + sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 'a'), + 0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0, + &pool->access); + if (sc != RTEMS_SUCCESSFUL) + { + rtems_semaphore_delete (pool->sync_lock); + rtems_semaphore_delete (pool->lock); + free (pool->buffers); + free (pool->bds); + return sc; + } - return RTEMS_SUCCESSFUL; + sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 't'), + 0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0, + &pool->transfer); + if (sc != RTEMS_SUCCESSFUL) + { + rtems_semaphore_delete (pool->access); + rtems_semaphore_delete (pool->sync_lock); + rtems_semaphore_delete (pool->lock); + free (pool->buffers); + free (pool->bds); + return sc; + } + + sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 'w'), + 0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0, + &pool->waiting); + if (sc != RTEMS_SUCCESSFUL) + { + rtems_semaphore_delete (pool->transfer); + rtems_semaphore_delete (pool->access); + rtems_semaphore_delete (pool->sync_lock); + rtems_semaphore_delete (pool->lock); + free (pool->buffers); + free (pool->bds); + return sc; + } + + return RTEMS_SUCCESSFUL; } /* bdbuf_release_pool -- @@ -751,21 +1070,29 @@ bdbuf_initialize_pool(rtems_bdbuf_config *config, int pool) * RTEMS_SUCCESSFUL */ static rtems_status_code -bdbuf_release_pool(rtems_bdpool_id pool) +rtems_bdbuf_release_pool (rtems_bdpool_id pid) { - bdbuf_pool *p = rtems_bdbuf_ctx.pool + pool; - rtems_semaphore_delete(p->bufget_sema); - free(p->bdbufs); - free(p->mallocd_bufs); - return RTEMS_SUCCESSFUL; + rtems_bdbuf_pool* pool = rtems_bdbuf_get_pool (pid); + + rtems_bdbuf_lock_pool (pool); + + rtems_semaphore_delete (pool->waiting); + rtems_semaphore_delete (pool->transfer); + rtems_semaphore_delete (pool->access); + rtems_semaphore_delete (pool->lock); + + free (pool->buffers); + free (pool->bds); + + return RTEMS_SUCCESSFUL; } /* rtems_bdbuf_init -- * Prepare buffering layer to work - initialize buffer descritors - * and (if it is neccessary)buffers. Buffers will be allocated accoriding + * and (if it is neccessary) buffers. Buffers will be allocated according * to the configuration table, each entry describes kind of block and - * amount requested. After initialization all blocks is placed into - * free elements lists. + * amount requested. After initialization all blocks are placed onto + * empty elements lists. * * PARAMETERS: * conf_table - pointer to the buffers configuration table @@ -776,107 +1103,124 @@ bdbuf_release_pool(rtems_bdpool_id pool) * or error code if error is occured) */ rtems_status_code -rtems_bdbuf_init(rtems_bdbuf_config *conf_table, int size) +rtems_bdbuf_init () { - rtems_bdpool_id i; - rtems_status_code rc; + rtems_bdpool_id p; + rtems_status_code sc; - if (size <= 0) - return RTEMS_INVALID_SIZE; +#if RTEMS_BDBUF_TRACE + rtems_bdbuf_printf ("init\n"); +#endif - rtems_bdbuf_ctx.npools = size; + if (rtems_bdbuf_pool_configuration_size <= 0) + return RTEMS_INVALID_SIZE; - /* - * Allocate memory for buffer pool descriptors - */ - rtems_bdbuf_ctx.pool = calloc(size, sizeof(bdbuf_pool)); - if (rtems_bdbuf_ctx.pool == NULL) - { - return RTEMS_NO_MEMORY; - } + if (rtems_bdbuf_ctx.npools) + return RTEMS_RESOURCE_IN_USE; - rtems_chain_initialize_empty(&rtems_bdbuf_ctx.mod); + rtems_bdbuf_ctx.npools = rtems_bdbuf_pool_configuration_size; - /* Initialize buffer pools and roll out if something failed */ - for (i = 0; i < size; i++) + /* + * Allocate memory for buffer pool descriptors + */ + rtems_bdbuf_ctx.pool = calloc (rtems_bdbuf_pool_configuration_size, + sizeof (rtems_bdbuf_pool)); + + if (rtems_bdbuf_ctx.pool == NULL) + return RTEMS_NO_MEMORY; + + /* + * Initialize buffer pools and roll out if something failed, + */ + for (p = 0; p < rtems_bdbuf_ctx.npools; p++) + { + sc = rtems_bdbuf_initialize_pool (&rtems_bdbuf_pool_configuration[p], p); + if (sc != RTEMS_SUCCESSFUL) { - rc = bdbuf_initialize_pool(conf_table + i, i); - if (rc != RTEMS_SUCCESSFUL) - { - rtems_bdpool_id j; - for (j = 0; j < i - 1; j++) - { - bdbuf_release_pool(j); - } - return rc; - } + rtems_bdpool_id j; + for (j = 0; j < p - 1; j++) + rtems_bdbuf_release_pool (j); + return sc; } + } - /* Create buffer flush semaphore */ - rc = rtems_semaphore_create( - rtems_build_name('B', 'F', 'L', 'U'), 0, - RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | - RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0, - &rtems_bdbuf_ctx.flush_sema); - if (rc != RTEMS_SUCCESSFUL) - { - for (i = 0; i < size; i++) - bdbuf_release_pool(i); - free(rtems_bdbuf_ctx.pool); - return rc; - } + /* + * Create and start swapout task + */ - /* Create and start swapout task */ - rc = rtems_task_create( - rtems_build_name('B', 'S', 'W', 'P'), - ((swapout_task_priority > 0) - ? swapout_task_priority - : SWAPOUT_TASK_DEFAULT_PRIORITY), - SWAPOUT_TASK_STACK_SIZE, - RTEMS_DEFAULT_MODES | RTEMS_NO_PREEMPT, - RTEMS_DEFAULT_ATTRIBUTES, - &rtems_bdbuf_ctx.swapout_task); - if (rc != RTEMS_SUCCESSFUL) - { - rtems_semaphore_delete(rtems_bdbuf_ctx.flush_sema); - for (i = 0; i < size; i++) - bdbuf_release_pool(i); - free(rtems_bdbuf_ctx.pool); - return rc; - } + rtems_bdbuf_ctx.swapout_enabled = TRUE; + + sc = rtems_task_create (rtems_build_name('B', 'S', 'W', 'P'), + (rtems_bdbuf_configuration.swapout_priority ? + rtems_bdbuf_configuration.swapout_priority : + RTEMS_BDBUF_SWAPOUT_TASK_PRIORITY_DEFAULT), + SWAPOUT_TASK_STACK_SIZE, + RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR, + RTEMS_LOCAL | RTEMS_NO_FLOATING_POINT, + &rtems_bdbuf_ctx.swapout); + if (sc != RTEMS_SUCCESSFUL) + { + for (p = 0; p < rtems_bdbuf_ctx.npools; p++) + rtems_bdbuf_release_pool (p); + free (rtems_bdbuf_ctx.pool); + return sc; + } - rc = rtems_task_start(rtems_bdbuf_ctx.swapout_task, bdbuf_swapout_task, 0); - if (rc != RTEMS_SUCCESSFUL) - { - rtems_task_delete(rtems_bdbuf_ctx.swapout_task); - rtems_semaphore_delete(rtems_bdbuf_ctx.flush_sema); - for (i = 0; i < size; i++) - bdbuf_release_pool(i); - free(rtems_bdbuf_ctx.pool); - return rc; - } + sc = rtems_task_start (rtems_bdbuf_ctx.swapout, + rtems_bdbuf_swapout_task, + (rtems_task_argument) &rtems_bdbuf_ctx); + if (sc != RTEMS_SUCCESSFUL) + { + rtems_task_delete (rtems_bdbuf_ctx.swapout); + for (p = 0; p < rtems_bdbuf_ctx.npools; p++) + rtems_bdbuf_release_pool (p); + free (rtems_bdbuf_ctx.pool); + return sc; + } - return RTEMS_SUCCESSFUL; + return RTEMS_SUCCESSFUL; } -/* find_or_assign_buffer -- - * Looks for buffer already assigned for this dev/block. If one is found - * obtain block buffer. If specified block already cached (i.e. there's - * block in the _modified_, or _recently_used_), return address - * of appropriate buffer descriptor and increment reference counter to 1. - * If block is not cached, allocate new buffer and return it. Data - * shouldn't be read to the buffer from media; buffer contains arbitrary - * data. This primitive may be blocked if there are no free buffer - * descriptors available and there are no unused non-modified (or - * synchronized with media) buffers available. +/** + * Get a buffer for this device and block. This function returns a buffer once + * placed into the AVL tree. If no buffer is available and it is not a read + * ahead request wait until one is available. If the buffer is for a read ahead + * transfer return NULL if there is not buffer or it is in the cache. * - * PARAMETERS: - * device - device number (constructed of major and minor device number - * block - linear media block number - * ret_buf - address of the variable to store address of found descriptor + * The AVL tree of buffers for the pool is searched and if not located check + * obtain a buffer and insert it into the AVL tree. Buffers are first obtained + * from the ready list until all empty buffers are used. Once all buffers are + * in use buffers are taken from the LRU list with the least recently used + * buffer taken first. A buffer taken from the LRU list is removed from the AVL + * tree. The empty list or LRU list buffer is initialised to this device and + * block. If no buffers are available due to the empty and LRU lists being + * empty the caller is blocked on the waiting semaphore and counter. When + * buffers return from the upper layers (access) or lower driver (transfer) the + * blocked caller task is woken and this procedure is repeated. The repeat + * handles a case of a another thread pre-empting getting a buffer first and + * adding it to the AVL tree. + * + * A buffer located in the AVL tree means it is already in the cache and maybe + * in use somewhere. The buffer can be either: + * + * # Cached. Not being accessed or part of a media transfer. + * # Access. Is with an upper layer being accessed. + * # Transfer. Is with the driver and part of a media transfer. + * + * If cached we assign the state new state extract it from any list it maybe + * part of and return to the user. The buffer could be part of the LRU list or + * the modifed list waiting to be swapped out by the swap out task. + * + * This function assumes the pool the buffer is being taken from is locked and + * it insure the pool is locked when it returns. * + * @param device The physical disk device + * @param block Linear media block number + * @param + * @param bd Address to store of found descriptor + * RETURNS: - * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully + * RTEMS status code ( if operation completed successfully * or error code if error is occured) * * SIDE EFFEECTS: @@ -885,252 +1229,251 @@ rtems_bdbuf_init(rtems_bdbuf_config *conf_table, int size) * NOTE: * It is assumed that primitive invoked when thread preemption is disabled. */ -static rtems_status_code -find_or_assign_buffer(disk_device *dd, - blkdev_bnum block, - bdbuf_buffer **ret_buf) +static rtems_bdbuf_buffer* +rtems_bdbuf_get_buffer (rtems_disk_device* pdd, + rtems_bdbuf_pool* pool, + rtems_blkdev_bnum block, + boolean read_ahead) { - bdbuf_buffer *bd_buf; - bdbuf_pool *bd_pool; - rtems_status_code rc; - dev_t device; - ISR_Level level; - - int blksize; - - device = dd->dev; - bd_pool = rtems_bdbuf_ctx.pool + dd->pool; - blksize = dd->block_size; - -again: - /* Looking for buffer descriptor used for this dev/block. */ - bd_buf = avl_search(&bd_pool->tree, device, block); + dev_t device = pdd->dev; + rtems_bdbuf_buffer* bd; + boolean available; + + /* + * Loop until we get a buffer. Under load we could find no buffers are + * available so in the case of the required block this task needs to wait + * until some return before proceeding. There is no timeout. If the buffer is + * for a read ahead buffer return NULL. + * + * The search procedure is repeated as another thread could have pre-empted + * us while we waited for a buffer, obtained an empty buffer and loaded the + * AVL tree with it. + */ + do + { + /* + * Search for buffer descriptor for this dev/block key. + */ + bd = rtems_bdbuf_avl_search (&pool->tree, device, block); - if (bd_buf == NULL) + /* + * No buffer in the cache for this block. We need to obtain a buffer and + * this means take a buffer that is ready to use. If all buffers are in use + * take the least recently used buffer. If there are none then the cache is + * empty. All the buffers are either queued to be written to disk or with + * the user. We cannot do much with the buffers with the user how-ever with + * the modified buffers waiting to be written to disk flush the maximum + * number transfered in a block to disk. After this all that be done is to + * wait for a buffer to return to the cache. + */ + if (!bd) { - /* Try to obtain semaphore without waiting first. It is the most - frequent case when reasonable number of buffers configured. If - it is failed, obtain semaphore blocking on it. In this case - it should be checked that appropriate buffer hasn't been loaded - by another thread, because this thread is preempted */ - rc = rtems_semaphore_obtain(bd_pool->bufget_sema, RTEMS_NO_WAIT, 0); - if (rc == RTEMS_UNSATISFIED) + /* + * Assign new buffer descriptor from the empty list if one is present. If + * the empty queue is empty get the oldest buffer from LRU list. If the + * LRU list is empty there are no available buffers so we need to wait + * until some are returned. + */ + if (rtems_chain_is_empty (&pool->ready)) + { + /* + * No unsed or read-ahead buffers. + * + * If this is a read ahead buffer just return. No need to place + * further pressure on the cache by reading something that may be + * needed when we have data in the cache that was needed. + */ + if (read_ahead) + return NULL; + + /* + * Check the LRU list. + */ + bd = (rtems_bdbuf_buffer *) rtems_chain_get (&pool->lru); + + if (bd) { - rc = rtems_semaphore_obtain(bd_pool->bufget_sema, - RTEMS_WAIT, RTEMS_NO_TIMEOUT); - bd_buf = avl_search(&bd_pool->tree, device, block); - if (bd_buf != NULL) - rtems_semaphore_release(bd_pool->bufget_sema); + /* + * Remove the buffer from the AVL tree. + */ + if (rtems_bdbuf_avl_remove (&pool->tree, bd) != 0) + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY); } - } - - if (bd_buf == NULL) - { - /* Assign new buffer descriptor */ - if (rtems_chain_is_empty(&bd_pool->free)) + else { - bd_buf = (bdbuf_buffer *)rtems_chain_get(&bd_pool->lru); - if (bd_buf != NULL) + /* + * If there are buffers on the modified list expire the hold timer + * and wake the swap out task. + */ + if (!rtems_chain_is_empty (&pool->modified)) + { + rtems_chain_node* node = rtems_chain_head (&pool->modified); + int write_blocks = 0; + + node = node->next; + while ((write_blocks < rtems_bdbuf_configuration.max_write_blocks) && + !rtems_chain_is_tail (&pool->modified, node)) { - int avl_result; - avl_result = avl_remove(&bd_pool->tree, bd_buf); - if (avl_result != 0) - { - rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY); - return RTEMS_INTERNAL_ERROR; - } + rtems_bdbuf_buffer* bd = (rtems_bdbuf_buffer*) node; + bd->hold_timer = 0; + write_blocks++; + node = node->next; } - } - else - { - bd_buf = (bdbuf_buffer *)rtems_chain_get(&(bd_pool->free)); - } - if (bd_buf == NULL) - { - goto again; + rtems_bdbuf_wake_swapper (); + } + + /* + * Wait for a buffer to be returned to the pool. The buffer will be + * placed on the LRU list. + */ + rtems_bdbuf_wait (pool, &pool->waiting, &pool->wait_waiters); } - else - { - bd_buf->dev = device; - bd_buf->block = block; -#ifdef AVL_GPL - bd_buf->avl.link[0] = NULL; - bd_buf->avl.link[1] = NULL; -#else - bd_buf->avl.left = NULL; - bd_buf->avl.right = NULL; -#endif - bd_buf->use_count = 1; - bd_buf->modified = bd_buf->actual = bd_buf->in_progress = FALSE; - bd_buf->status = RTEMS_SUCCESSFUL; + } + else + { + bd = (rtems_bdbuf_buffer *) rtems_chain_get (&(pool->ready)); - if (avl_insert(&bd_pool->tree, bd_buf) != 0) - { - rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY); - return RTEMS_INTERNAL_ERROR; - } + if ((bd->state != RTEMS_BDBUF_STATE_EMPTY) && + (bd->state != RTEMS_BDBUF_STATE_READ_AHEAD)) + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY); - *ret_buf = bd_buf; - - return RTEMS_SUCCESSFUL; + if (bd->state == RTEMS_BDBUF_STATE_READ_AHEAD) + { + if (rtems_bdbuf_avl_remove (&pool->tree, bd) != 0) + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY); } + } + + if (bd) + { + bd->dev = device; + bd->block = block; + bd->avl.left = NULL; + bd->avl.right = NULL; + bd->state = RTEMS_BDBUF_STATE_EMPTY; + bd->error = 0; + bd->waiters = 0; + + if (rtems_bdbuf_avl_insert (&pool->tree, bd) != 0) + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY); + + return bd; + } } - else + } + while (!bd); + + /* + * If the buffer is for read ahead and it exists in the AVL cache or is being + * accessed or being transfered then return NULL. + */ + if (read_ahead) + return NULL; + + /* + * Loop waiting for the buffer to enter the cached state. If the buffer + * is in the access or transfer state then wait until it is not. + */ + available = FALSE; + while (!available) + { + switch (bd->state) { - /* Buffer descriptor already assigned for this dev/block */ - if (bd_buf->use_count == 0) - { - /* If we are removing from lru list, obtain the bufget_sema - * first. If we are removing from mod list, obtain flush sema. - * It should be obtained without blocking because we know - * that our buffer descriptor is in the list. */ - if (bd_buf->modified) - { - rc = rtems_semaphore_obtain(rtems_bdbuf_ctx.flush_sema, - RTEMS_NO_WAIT, 0); - } - else - { - rc = rtems_semaphore_obtain(bd_pool->bufget_sema, - RTEMS_NO_WAIT, 0); - } - /* It is possible that we couldn't obtain flush or bufget sema - * although buffer in the appropriate chain is available: - * semaphore may be released to swapout task, but this task - * actually did not start to process it. */ - if (rc == RTEMS_UNSATISFIED) - rc = RTEMS_SUCCESSFUL; - if (rc != RTEMS_SUCCESSFUL) - { - rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY); - return RTEMS_INTERNAL_ERROR; - } + case RTEMS_BDBUF_STATE_CACHED: + case RTEMS_BDBUF_STATE_MODIFIED: + case RTEMS_BDBUF_STATE_READ_AHEAD: + available = TRUE; + break; + + case RTEMS_BDBUF_STATE_ACCESS: + case RTEMS_BDBUF_STATE_ACCESS_MODIFIED: + bd->waiters++; + rtems_bdbuf_wait (pool, &pool->access, &pool->access_waiters); + bd->waiters--; + break; + + case RTEMS_BDBUF_STATE_SYNC: + case RTEMS_BDBUF_STATE_TRANSFER: + bd->waiters++; + rtems_bdbuf_wait (pool, &pool->transfer, &pool->transfer_waiters); + bd->waiters--; + break; + + default: + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY); + } + } - /* Buffer descriptor is linked to the lru or mod chain. Remove - it from there. */ - rtems_chain_extract(&bd_buf->link); - } - bd_buf->use_count++; - while (bd_buf->in_progress != 0) - { - rtems_interrupt_disable(level); - _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, - WATCHDOG_NO_TIMEOUT, level); - } + /* + * Buffer is linked to the LRU, modifed, or sync lists. Remove it from there. + */ + rtems_chain_extract (&bd->link); - *ret_buf = bd_buf; - return RTEMS_SUCCESSFUL; - } + return bd; } -/* rtems_bdbuf_get -- - * Obtain block buffer. If specified block already cached (i.e. there's - * block in the _modified_, or _recently_used_), return address - * of appropriate buffer descriptor and increment reference counter to 1. - * If block is not cached, allocate new buffer and return it. Data - * shouldn't be read to the buffer from media; buffer may contains - * arbitrary data. This primitive may be blocked if there are no free - * buffer descriptors available and there are no unused non-modified - * (or synchronized with media) buffers available. +/** + * Obtain block buffer. If specified block already cached (i.e. there's block + * in the _modified_, or _recently_used_), return address of appropriate buffer + * descriptor. If block is not cached, allocate new buffer and return it. Data + * shouldn't be read to the buffer from media; buffer may contains arbitrary + * data. This primitive may be blocked if there are no free buffer descriptors + * available and there are no unused non-modified (or synchronized with media) + * buffers available. * - * PARAMETERS: - * device - device number (constructed of major and minor device number) - * block - linear media block number - * bd - address of variable to store pointer to the buffer descriptor - * - * RETURNS: - * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully - * or error code if error is occured) - * - * SIDE EFFECTS: - * bufget_sema semaphore obtained by this primitive. + * @param device device number (constructed of major and minor device number) + * @param block linear media block number + * @param bd address of variable to store pointer to the buffer descriptor + * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully + * or error code if error is occured) */ rtems_status_code -rtems_bdbuf_get(dev_t device, blkdev_bnum block, bdbuf_buffer **bd) +rtems_bdbuf_get (dev_t device, + rtems_blkdev_bnum block, + rtems_bdbuf_buffer** bdp) { - rtems_status_code rc; - disk_device *dd; - disk_device *pdd; - preemption_key key; - - /* - * Convert logical dev/block to physical one - */ - dd = rtems_disk_lookup(device); - if (dd == NULL) - return RTEMS_INVALID_ID; + rtems_disk_device* dd; + rtems_bdbuf_pool* pool; + rtems_bdbuf_buffer* bd; + + /* + * Do not hold the pool lock when obtaining the disk table. + */ + dd = rtems_disk_obtain (device); + if (dd == NULL) + return RTEMS_INVALID_ID; + + if (block >= dd->size) + { + rtems_disk_release (dd); + return RTEMS_INVALID_NUMBER; + } - if (block >= dd->size) - { - rtems_disk_release(dd); - return RTEMS_INVALID_NUMBER; - } + block += dd->start; - pdd = dd->phys_dev; - block += dd->start; - rtems_disk_release(dd); + pool = rtems_bdbuf_get_pool (dd->phys_dev->pool); + + rtems_disk_release(dd); - DISABLE_PREEMPTION(key); - rc = find_or_assign_buffer(pdd, block, bd); - ENABLE_PREEMPTION(key); + rtems_bdbuf_lock_pool (pool); - if (rc != RTEMS_SUCCESSFUL) - return rc; +#if RTEMS_BDBUF_TRACE + rtems_bdbuf_printf ("get: %d (dev = %08x)\n", block, device); +#endif - return RTEMS_SUCCESSFUL; -} + bd = rtems_bdbuf_get_buffer (dd->phys_dev, pool, block, FALSE); -/* bdbuf_initialize_transfer_sema -- - * Initialize transfer_sema mutex semaphore associated with buffer - * descriptor. - */ -static inline void -bdbuf_initialize_transfer_sema(bdbuf_buffer *bd_buf) -{ - CORE_mutex_Attributes mutex_attr; - mutex_attr.lock_nesting_behavior = CORE_MUTEX_NESTING_BLOCKS; - mutex_attr.only_owner_release = FALSE; - mutex_attr.discipline = CORE_MUTEX_DISCIPLINES_FIFO; - mutex_attr.priority_ceiling = 0; - - _CORE_mutex_Initialize(&bd_buf->transfer_sema, - &mutex_attr, CORE_MUTEX_LOCKED); -} + if (bd->state == RTEMS_BDBUF_STATE_MODIFIED) + bd->state = RTEMS_BDBUF_STATE_ACCESS_MODIFIED; + else + bd->state = RTEMS_BDBUF_STATE_ACCESS; + + rtems_bdbuf_unlock_pool (pool); -/* bdbuf_write_transfer_done -- - * Callout function. Invoked by block device driver when data transfer - * to device (write) is completed. This function may be invoked from - * interrupt handler. - * - * PARAMETERS: - * arg - arbitrary argument specified in block device request - * structure (in this case - pointer to the appropriate - * bdbuf_buffer buffer descriptor structure). - * status - I/O completion status - * error - errno error code if status != RTEMS_SUCCESSFUL - * - * RETURNS: - * none - */ -static void -bdbuf_write_transfer_done(void *arg, rtems_status_code status, int error) -{ - int i; - write_tfer_done_arg_t *wtd_arg = arg; - blkdev_request *req = wtd_arg->req; - bdbuf_buffer **bd_buf_write_store = wtd_arg->write_store; - bdbuf_buffer *bd_buf; - for (i = 0;i < req->count;i++) { - bd_buf = bd_buf_write_store[i]; - bd_buf->status = status; - bd_buf->error = RTEMS_IO_ERROR; - - bd_buf->in_progress = FALSE; - _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL); - _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL, - CORE_MUTEX_STATUS_SUCCESSFUL); - } + *bdp = bd; + + return RTEMS_SUCCESSFUL; } /* bdbuf_read_transfer_done -- @@ -1149,658 +1492,882 @@ bdbuf_write_transfer_done(void *arg, rtems_status_code status, int error) * none */ static void -bdbuf_read_transfer_done(void *arg, rtems_status_code status, int error) +rtems_bdbuf_read_done (void* arg, rtems_status_code status, int error) { -#if defined(READ_MULTIPLE) - - read_ahead_bd_buf_group *bd_buf_group = arg; - bdbuf_buffer *bd_buf; - int i; - for (i = 0;i < bd_buf_group->cnt;i++) { - bd_buf = bd_buf_group->bd_bufs[i]; - - bd_buf->status = status; - bd_buf->error = RTEMS_IO_ERROR; - _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL); - _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL, - CORE_MUTEX_STATUS_SUCCESSFUL); - } -#else - bdbuf_buffer *bd_buf = arg; - bd_buf->status = status; - bd_buf->error = RTEMS_IO_ERROR; - _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL); - _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL, - CORE_MUTEX_STATUS_SUCCESSFUL); -#endif + rtems_blkdev_request* req = (rtems_blkdev_request*) arg; + + req->error = error; + req->status = status; + + rtems_event_send (req->io_task, RTEMS_BDBUF_TRANSFER_SYNC); } -/* rtems_bdbuf_read -- - * (Similar to the rtems_bdbuf_get, except reading data from media) - * Obtain block buffer. If specified block already cached, return address - * of appropriate buffer and increment reference counter to 1. If block is - * not cached, allocate new buffer and read data to it from the media. - * This primitive may be blocked on waiting until data to be read from - * media, if there are no free buffer descriptors available and there are - * no unused non-modified (or synchronized with media) buffers available. - * - * PARAMETERS: - * device - device number (consists of major and minor device number) - * block - linear media block number - * bd - address of variable to store pointer to the buffer descriptor - * - * RETURNS: - * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully - * or error code if error is occured) +/** + * Read a block into memory. If the block is not is the cache it is read into + * memory. The caller is blocked until the block is read and placed into the + * cache. * - * SIDE EFFECTS: - * bufget_sema and transfer_sema semaphores obtained by this primitive. + * @param device The device number (consists of major and minor device number) + * @param block Linear media block number + * @param bd Pointer to the buffer BD address. + * @retval RTEMS_SUCCESSFUL Operation completed successfully. + * @return rtems_status_code An error code. Buffer still passed to caller. */ -#if !defined(READ_MULTIPLE) + rtems_status_code -rtems_bdbuf_read(dev_t device, - blkdev_bnum block, - bdbuf_buffer **bd) +rtems_bdbuf_read (dev_t device, + rtems_blkdev_bnum block, + rtems_bdbuf_buffer** bdp) { - preemption_key key; - ISR_Level level; + rtems_disk_device* dd; + rtems_bdbuf_pool* pool; + rtems_bdbuf_buffer* bd = NULL; + int read_ahead_count; + rtems_blkdev_request* req; + + /* + * @todo This type of request structure is wrong and should be removed. + */ +#define bdbuf_alloc(size) __builtin_alloca (size) + + req = bdbuf_alloc (sizeof (rtems_blkdev_request) + + (sizeof ( rtems_blkdev_sg_buffer) * + rtems_bdbuf_configuration.max_read_ahead_blocks)); + + /* + * Do not hold the pool lock when obtaining the disk table. + */ + dd = rtems_disk_obtain (device); + if (dd == NULL) + return RTEMS_INVALID_ID; + + block += dd->start; + +#if RTEMS_BDBUF_TRACE + rtems_bdbuf_printf ("read: %d (dev = %08x)\n", block, device); +#endif + + if (block >= dd->size) + { + rtems_disk_release(dd); + return RTEMS_INVALID_NUMBER; + } - bdbuf_buffer *bd_buf; - rtems_status_code rc; - int result; - disk_device *dd; - disk_device *pdd; - blkdev_request1 req; + req->count = 0; + req->bufnum = 0; - dd = rtems_disk_lookup(device); - if (dd == NULL) - return RTEMS_INVALID_ID; + /* + * Read the block plus the required number of blocks ahead. The number of + * blocks to read ahead is configured by the user and limited by the size of + * the disk or reaching a read ahead block that is also cached. + * + * Limit the blocks read by the size of the disk. + */ + if ((rtems_bdbuf_configuration.max_read_ahead_blocks + block) < dd->size) + read_ahead_count = rtems_bdbuf_configuration.max_read_ahead_blocks; + else + read_ahead_count = dd->size - block; - if (block >= dd->size) - { - rtems_disk_release(dd); - return RTEMS_INVALID_NUMBER; - } + pool = rtems_bdbuf_get_pool (dd->phys_dev->pool); - pdd = dd->phys_dev; - block += dd->start; + rtems_bdbuf_lock_pool (pool); - DISABLE_PREEMPTION(key); - rc = find_or_assign_buffer(pdd, block, &bd_buf); + while (req->count < read_ahead_count) + { + /* + * Get the buffer for the requested block. If the block is cached then + * return it. If it is not cached transfer the block from the disk media + * into memory. + * + * We need to clean up any buffers allocated and not passed back to the + * caller. + */ + bd = rtems_bdbuf_get_buffer (dd->phys_dev, pool, + block + req->count, + req->count == 0 ? FALSE : TRUE); - if (rc != RTEMS_SUCCESSFUL) - { - ENABLE_PREEMPTION(key); - rtems_disk_release(dd); - return rc; - } + /* + * Read ahead buffer is in the cache or none available. Read what we + * can. + */ + if (!bd) + break; - if (!bd_buf->actual) - { - bd_buf->in_progress = 1; - - req.req.req = BLKDEV_REQ_READ; - req.req.req_done = bdbuf_read_transfer_done; - req.req.done_arg = bd_buf; - req.req.start = block; - req.req.count = 1; - req.req.bufnum = 1; - req.req.bufs[0].length = dd->block_size; - req.req.bufs[0].buffer = bd_buf->buffer; - - bdbuf_initialize_transfer_sema(bd_buf); - result = dd->ioctl(pdd->dev, BLKIO_REQUEST, &req); - if (result == -1) - { - bd_buf->status = RTEMS_IO_ERROR; - bd_buf->error = errno; - bd_buf->actual = FALSE; - } - else - { - rtems_interrupt_disable(level); - _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, - WATCHDOG_NO_TIMEOUT, level); - bd_buf->actual = TRUE; - } - bd_buf->in_progress = FALSE; - } - rtems_disk_release(dd); + /* + * Is the block we are interested in the cache ? + */ + if ((bd->state == RTEMS_BDBUF_STATE_CACHED) || + (bd->state == RTEMS_BDBUF_STATE_MODIFIED)) + break; - ENABLE_PREEMPTION(key); + bd->state = RTEMS_BDBUF_STATE_TRANSFER; + bd->error = 0; - *bd = bd_buf; - - return RTEMS_SUCCESSFUL; -} -#else /* READ_MULTIPLE */ -rtems_status_code -rtems_bdbuf_read(dev_t device, - blkdev_bnum block, - bdbuf_buffer **bd) -{ - preemption_key key; - ISR_Level level; + /* + * @todo The use of these req blocks is not a great design. + * The req is a struct with a single 'bufs' declared in the + * req struct and the others are added in the outer level + * struct. This relies on the structs joining as a single + * array and that assumes the compiler packs the structs. + * Why not just place on a list ? The BD has a node that + * can be used. + */ + req->bufs[req->count].user = bd; + req->bufs[req->count].block = bd->block; + req->bufs[req->count].length = dd->block_size; + req->bufs[req->count].buffer = bd->buffer; + req->count++; + req->bufnum++; + } - bdbuf_buffer *bd_buf,*first_bd_buf; - rtems_status_code rc; + /* + * Transfer any requested buffers. If the request count is 0 we have found + * the block in the cache so return it. + */ + if (req->count) + { + /* + * Unlock the pool. We have the buffer for the block and it will be in the + * access or transfer state. We may also have a number of read ahead blocks + * if we need to transfer data. At this point any other threads can gain + * access to the pool and if they are after any of the buffers we have they + * will block and be woken when the buffer is returned to the pool. + * + * If a transfer is needed the I/O operation will occur with pre-emption + * enabled and the pool unlocked. This is a change to the previous version + * of the bdbuf code. + */ int result; - disk_device *dd; - disk_device *pdd; - blkdev_request_read_ahead req; - read_ahead_bd_buf_group bd_buf_group; - boolean find_more_buffers; - int i; - - dd = rtems_disk_lookup(device); - if (dd == NULL) - return RTEMS_INVALID_ID; - - if (block >= dd->size) + int b; + + rtems_bdbuf_unlock_pool (pool); + + req->req = RTEMS_BLKDEV_REQ_READ; + req->req_done = rtems_bdbuf_read_done; + req->done_arg = req; + req->io_task = rtems_task_self (); + req->status = RTEMS_RESOURCE_IN_USE; + req->error = 0; + req->start = dd->start; + + result = dd->ioctl (dd->phys_dev->dev, RTEMS_BLKIO_REQUEST, req); + + /* + * Inspection of the DOS FS code shows the result from this function is + * handled and a buffer must be returned. + */ + if (result < 0) { - rtems_disk_release(dd); - return RTEMS_INVALID_NUMBER; + req->error = errno; + req->status = RTEMS_IO_ERROR; + } + else + { + rtems_status_code sc; + rtems_event_set out; + sc = rtems_event_receive (RTEMS_BDBUF_TRANSFER_SYNC, + RTEMS_EVENT_ALL | RTEMS_WAIT, + 0, &out); + + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE); } - - pdd = dd->phys_dev; - block += dd->start; - DISABLE_PREEMPTION(key); - rc = find_or_assign_buffer(pdd, block, &first_bd_buf); + rtems_bdbuf_lock_pool (pool); - if (rc != RTEMS_SUCCESSFUL) + for (b = 1; b < req->count; b++) { - ENABLE_PREEMPTION(key); - rtems_disk_release(dd); - return rc; + bd = req->bufs[b].user; + bd->error = req->error; + bd->state = RTEMS_BDBUF_STATE_READ_AHEAD; + rtems_bdbuf_release (bd); } - if (!first_bd_buf->actual) - { - bd_buf_group.bd_bufs[0] = first_bd_buf; - bd_buf_group.cnt = 1; + bd = req->bufs[0].user; + } - first_bd_buf->in_progress = TRUE; + /* + * The data for this block is cached in the buffer. + */ + if (bd->state == RTEMS_BDBUF_STATE_MODIFIED) + bd->state = RTEMS_BDBUF_STATE_ACCESS_MODIFIED; + else + bd->state = RTEMS_BDBUF_STATE_ACCESS; - req.req.req = BLKDEV_REQ_READ; - req.req.req_done = bdbuf_read_transfer_done; - req.req.done_arg = &bd_buf_group; - req.req.start = block; - req.req.count = 1; - req.req.bufnum = 1; - req.req.bufs[0].length = dd->block_size; - req.req.bufs[0].buffer = first_bd_buf->buffer; - - bdbuf_initialize_transfer_sema(first_bd_buf); - /* - * FIXME: check for following blocks to be: - * - still in range of partition size - * - not yet assigned - * - buffer available - * allocate for read call, if possible - */ - find_more_buffers = TRUE; - while (find_more_buffers) { - block++; - /* - * still bd_buf_group entries free and - * still in range of this disk? - */ - if ((bd_buf_group.cnt >= READ_AHEAD_MAX_BLK_CNT) || - (block >= dd->size)) { - find_more_buffers = FALSE; - } - if (find_more_buffers) { - rc = find_or_assign_buffer(pdd, block, &bd_buf); - if (rc != RTEMS_SUCCESSFUL) { - find_more_buffers = FALSE; - } - else if (bd_buf->actual) { - find_more_buffers = FALSE; - bdbuf_release(bd_buf); - } - } - if (find_more_buffers) { - bdbuf_initialize_transfer_sema(bd_buf); - bd_buf->in_progress = TRUE; - - req.req.bufs[req.req.count].length = dd->block_size; - req.req.bufs[req.req.count].buffer = bd_buf->buffer; - req.req.count++; - req.req.bufnum++; - bd_buf_group.bd_bufs[bd_buf_group.cnt] = bd_buf; - bd_buf_group.cnt++; - } - } - - /* do the actual read call here - */ - result = dd->ioctl(pdd->dev, BLKIO_REQUEST, &req); - - /* - * cleanup: - * wait, until all bd_bufs are processed - * set status in all bd_bufs - */ - for (i = 0;i < bd_buf_group.cnt;i++) { - bd_buf = bd_buf_group.bd_bufs[i]; - if (result == -1) - { - bd_buf->status = RTEMS_IO_ERROR; - bd_buf->error = errno; - bd_buf->actual = FALSE; - } - else - { - rtems_interrupt_disable(level); - _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, - WATCHDOG_NO_TIMEOUT, level); - bd_buf->actual = TRUE; - } - bd_buf->in_progress = FALSE; - /* release any pre-read buffers */ - if (i > 0) { - bdbuf_release(bd_buf); - } - } - } - rtems_disk_release(dd); - - ENABLE_PREEMPTION(key); + rtems_bdbuf_unlock_pool (pool); + rtems_disk_release (dd); - *bd = first_bd_buf; - - return RTEMS_SUCCESSFUL; -} -#endif /* READ_MULTIPLE */ + *bdp = bd; + return RTEMS_SUCCESSFUL; +} -/* bdbuf_release -- - * Release buffer. Decrease buffer usage counter. If it is zero, further - * processing depends on modified attribute. If buffer was modified, it - * is inserted into mod chain and swapout task waken up. If buffer was - * not modified, it is returned to the end of lru chain making it available - * for further use. +/** + * Release buffer that has been in use. The buffer could have been in the + * access state and so with a user of the cache or it was being transfered to + * or from the disk media and so with a driver. Wake any waiters. If no one is + * waiting and this is the only buffer on the LRU list see if anyone is + * waiting. Wake them if they are. * - * PARAMETERS: - * bd_buf - pointer to the released buffer descriptor. - * - * RETURNS: - * RTEMS_SUCCESSFUL if buffer released successfully, or error code if - * error occured. + * If the buffer has been modified use the modified release call. * - * NOTE: - * This is internal function. It is assumed that task made non-preemptive - * before its invocation. + * @param bd The buffer to return to the pool. + * @retval RTEMS_SUCCESSFUL This operation always succeeds. */ -static rtems_status_code -bdbuf_release(bdbuf_buffer *bd_buf) + +rtems_status_code +rtems_bdbuf_release (rtems_bdbuf_buffer* bd) { - bdbuf_pool *bd_pool; - rtems_status_code rc = RTEMS_SUCCESSFUL; + rtems_bdbuf_pool* pool; - if (bd_buf->use_count <= 0) - return RTEMS_INTERNAL_ERROR; + if (bd == NULL) + return RTEMS_INVALID_ADDRESS; - bd_pool = rtems_bdbuf_ctx.pool + bd_buf->pool; + pool = rtems_bdbuf_get_pool (bd->pool); - bd_buf->use_count--; + rtems_bdbuf_lock_pool (pool); - if (bd_buf->use_count == 0) +#if RTEMS_BDBUF_TRACE + rtems_bdbuf_printf ("release: %d\n", bd->block); +#endif + + if (bd->state == RTEMS_BDBUF_STATE_ACCESS_MODIFIED) + { + rtems_bdbuf_append_modified (pool, bd); + } + else + { + /* + * If this is a read ahead buffer place the ready queue. Buffers are + * taken from here first. If we prepend then get from the queue the + * buffers furthermost from the read buffer will be used. + */ + if (bd->state == RTEMS_BDBUF_STATE_READ_AHEAD) + rtems_chain_prepend (&pool->ready, &bd->link); + else { - if (bd_buf->modified) - { - - /* Buffer was modified. Insert buffer to the modified buffers - * list and initiate flushing. */ - rtems_chain_append(&rtems_bdbuf_ctx.mod, &bd_buf->link); - - /* Release the flush_sema */ - rc = rtems_semaphore_release(rtems_bdbuf_ctx.flush_sema); - } - else - { - /* Buffer was not modified. Add this descriptor to the - * end of lru chain and make it available for reuse. */ - rtems_chain_append(&bd_pool->lru, &bd_buf->link); - rc = rtems_semaphore_release(bd_pool->bufget_sema); - } + bd->state = RTEMS_BDBUF_STATE_CACHED; + rtems_chain_append (&pool->lru, &bd->link); } - return rc; -} + } + + /* + * If there are threads waiting to access the buffer wake them. Wake any + * waiters if this is the first buffer to placed back onto the queue. + */ + if (bd->waiters) + rtems_bdbuf_wake (pool->access, &pool->access_waiters); + else + { + if (bd->state == RTEMS_BDBUF_STATE_READ_AHEAD) + { + if (rtems_chain_has_only_one_node (&pool->ready)) + rtems_bdbuf_wake (pool->waiting, &pool->wait_waiters); + } + else + { + if (rtems_chain_has_only_one_node (&pool->lru)) + rtems_bdbuf_wake (pool->waiting, &pool->wait_waiters); + } + } + + rtems_bdbuf_unlock_pool (pool); + return RTEMS_SUCCESSFUL; +} -/* rtems_bdbuf_release -- - * Release buffer allocated before. This primitive decrease the - * usage counter. If it is zero, further destiny of buffer depends on - * 'modified' status. If buffer was modified, it is placed to the end of - * mod list and flush task waken up. If buffer was not modified, - * it is placed to the end of lru list, and bufget_sema released, allowing - * to reuse this buffer. - * - * PARAMETERS: - * bd_buf - pointer to the bdbuf_buffer structure previously obtained using - * get/read primitive. +/** + * Release buffer that has been in use and has been modified. The buffer could + * have been in the access state and so with a user of the cache or it was + * being transfered to or from the disk media and so with a driver. Wake any + * waiters. If no one is waiting and this is the only buffer on the LRU list + * see if anyone is waiting. Wake them if they are. * - * RETURNS: - * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully - * or error code if error is occured) + * If the buffer has been modified use the modified release call. * - * SIDE EFFECTS: - * flush_sema and bufget_sema semaphores may be released by this primitive. + * @param bd The buffer to return to the pool. + * @retval RTEMS_SUCCESSFUL This operation always succeeds. */ + rtems_status_code -rtems_bdbuf_release(bdbuf_buffer *bd_buf) +rtems_bdbuf_release_modified (rtems_bdbuf_buffer* bd) { - preemption_key key; - rtems_status_code rc = RTEMS_SUCCESSFUL; + rtems_bdbuf_pool* pool; - if (bd_buf == NULL) - return RTEMS_INVALID_ADDRESS; + if (bd == NULL) + return RTEMS_INVALID_ADDRESS; - DISABLE_PREEMPTION(key); + pool = rtems_bdbuf_get_pool (bd->pool); - rc = bdbuf_release(bd_buf); + rtems_bdbuf_lock_pool (pool); - ENABLE_PREEMPTION(key); +#if RTEMS_BDBUF_TRACE + rtems_bdbuf_printf ("release modified: %d\n", bd->block); +#endif - return rc; + bd->hold_timer = rtems_bdbuf_configuration.swap_block_hold; + + rtems_bdbuf_append_modified (pool, bd); + + if (bd->waiters) + rtems_bdbuf_wake (pool->access, &pool->access_waiters); + + rtems_bdbuf_unlock_pool (pool); + + return RTEMS_SUCCESSFUL; } -/* rtems_bdbuf_release_modified -- - * Release buffer allocated before, assuming that it is _modified_ by - * it's owner. This primitive decrease usage counter for buffer, mark - * buffer descriptor as modified. If usage counter is 0, insert it at - * end of mod chain and release flush_sema semaphore to activate the - * flush task. - * - * PARAMETERS: - * bd_buf - pointer to the bdbuf_buffer structure previously obtained using - * get/read primitive. +/** + * Wait until specified buffer synchronized with disk. Invoked on exchanges + * critical for data consistency on the media. The buffer is placed on the sync + * list and the swapper is woken. No sync lock is taken as the buffers on the + * sync list are taken first and passed to the driver before buffers on the + * modified list. * - * RETURNS: - * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully - * or error code if error is occured) + * @note This code does not lock the sync mutex and stop additions to the + * modified queue. This means the buffer could be written and then + * returned to the modified list but will not happen as the buffer's + * state is sync. * - * SIDE EFFECTS: - * flush_sema semaphore may be released by this primitive. + * @param bd Pointer to the bdbuf_buffer structure previously obtained using + * get/read primitive. + * @retval RTEMS_SUCCESSFUL Always returned. */ + rtems_status_code -rtems_bdbuf_release_modified(bdbuf_buffer *bd_buf) +rtems_bdbuf_sync (rtems_bdbuf_buffer* bd) { - preemption_key key; - rtems_status_code rc = RTEMS_SUCCESSFUL; + rtems_bdbuf_pool* pool; + boolean available; + +#if RTEMS_BDBUF_TRACE + rtems_bdbuf_printf ("sync: %d\n", bd->block); +#endif + + if (bd == NULL) + return RTEMS_INVALID_ADDRESS; - if (bd_buf == NULL) - return RTEMS_INVALID_ADDRESS; + pool = rtems_bdbuf_get_pool (bd->pool); - DISABLE_PREEMPTION(key); + rtems_bdbuf_lock_pool (pool); - if (!bd_buf->modified) + bd->state = RTEMS_BDBUF_STATE_SYNC; + + rtems_chain_append (&pool->sync, &bd->link); + + rtems_bdbuf_wake_swapper (); + + available = FALSE; + while (!available) + { + switch (bd->state) { - bdbuf_initialize_transfer_sema(bd_buf); + case RTEMS_BDBUF_STATE_CACHED: + case RTEMS_BDBUF_STATE_READ_AHEAD: + case RTEMS_BDBUF_STATE_MODIFIED: + case RTEMS_BDBUF_STATE_ACCESS: + case RTEMS_BDBUF_STATE_ACCESS_MODIFIED: + available = TRUE; + break; + + case RTEMS_BDBUF_STATE_SYNC: + case RTEMS_BDBUF_STATE_TRANSFER: + bd->waiters++; + rtems_bdbuf_wait (pool, &pool->transfer, &pool->transfer_waiters); + bd->waiters--; + break; + + default: + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY); } - bd_buf->modified = TRUE; - bd_buf->actual = TRUE; - rc = bdbuf_release(bd_buf); - - ENABLE_PREEMPTION(key); + } - return rc; + rtems_bdbuf_unlock_pool (pool); + + return RTEMS_SUCCESSFUL; } -/* rtems_bdbuf_sync -- - * Wait until specified buffer synchronized with disk. Invoked on exchanges - * critical for data consistency on the media. This primitive mark owned - * block as modified, decrease usage counter. If usage counter is 0, - * block inserted to the mod chain and flush_sema semaphore released. - * Finally, primitives blocked on transfer_sema semaphore. +/* rtems_bdbuf_syncdev -- + * Synchronize with disk all buffers containing the blocks belonging to + * specified device. * * PARAMETERS: - * bd_buf - pointer to the bdbuf_buffer structure previously obtained using - * get/read primitive. + * dev - block device number * * RETURNS: * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully * or error code if error is occured) - * - * SIDE EFFECTS: - * Primitive may be blocked on transfer_sema semaphore. */ rtems_status_code -rtems_bdbuf_sync(bdbuf_buffer *bd_buf) +rtems_bdbuf_syncdev (dev_t dev) { - preemption_key key; - ISR_Level level; - rtems_status_code rc = RTEMS_SUCCESSFUL; + rtems_disk_device* dd; + rtems_bdbuf_pool* pool; + rtems_status_code sc; + rtems_event_set out; - if (bd_buf == NULL) - return RTEMS_INVALID_ADDRESS; - - DISABLE_PREEMPTION(key); +#if RTEMS_BDBUF_TRACE + rtems_bdbuf_printf ("syncdev: %08x\n", dev); +#endif - if (!bd_buf->modified) - { - bdbuf_initialize_transfer_sema(bd_buf); - } - bd_buf->modified = TRUE; - bd_buf->actual = TRUE; + /* + * Do not hold the pool lock when obtaining the disk table. + */ + dd = rtems_disk_obtain (dev); + if (dd == NULL) + return RTEMS_INVALID_ID; + + pool = rtems_bdbuf_get_pool (dd->pool); + + /* + * Take the sync lock before locking the pool. Once we have the sync lock + * we can lock the pool. If another thread has the sync lock it will cause + * this thread to block until it owns the sync lock then it can own the + * pool. The sync lock can only be obtained with the pool unlocked. + */ + + rtems_bdbuf_lock_sync (pool); + rtems_bdbuf_lock_pool (pool); - rc = bdbuf_release(bd_buf); + pool->sync_active = TRUE; + pool->sync_requester = rtems_task_self (); + pool->sync_device = dev; + + rtems_bdbuf_wake_swapper (); + rtems_bdbuf_unlock_pool (pool); + + sc = rtems_event_receive (RTEMS_BDBUF_TRANSFER_SYNC, + RTEMS_EVENT_ALL | RTEMS_WAIT, + 0, &out); - if (rc == RTEMS_SUCCESSFUL) - { - rtems_interrupt_disable(level); - _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, - WATCHDOG_NO_TIMEOUT, level); - } + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE); + + rtems_bdbuf_lock_pool (pool); - ENABLE_PREEMPTION(key); + pool->sync_active = FALSE; - return rc; + rtems_bdbuf_unlock_sync (pool); + rtems_bdbuf_unlock_pool (pool); + + return rtems_disk_release(dd); } -/* rtems_bdbuf_syncdev -- - * Synchronize with disk all buffers containing the blocks belonging to - * specified device. +/* bdbuf_write_transfer_done -- + * Callout function. Invoked by block device driver when data transfer + * to device (write) is completed. This function may be invoked from + * interrupt handler. * * PARAMETERS: - * dev - block device number + * arg - arbitrary argument specified in block device request + * structure (in this case - pointer to the appropriate + * bdbuf_buffer buffer descriptor structure). + * status - I/O completion status + * error - errno error code if status != RTEMS_SUCCESSFUL * * RETURNS: - * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully - * or error code if error is occured) + * none */ -rtems_status_code -rtems_bdbuf_syncdev(dev_t dev) +static void +rtems_bdbuf_write_done(void *arg, rtems_status_code status, int error) +{ + rtems_blkdev_request* req = (rtems_blkdev_request*) arg; + + req->error = error; + req->status = status; + + rtems_event_send (req->io_task, RTEMS_BDBUF_TRANSFER_SYNC); +} + +/** + * Process the modified list of buffers. We can have a sync or modified + * list that needs to be handled. + */ +static void +rtems_bdbuf_swapout_modified_processing (rtems_bdpool_id pid, + dev_t* dev, + rtems_chain_control* chain, + rtems_chain_control* transfer, + boolean sync_active, + boolean update_timers, + uint32_t timer_delta) { - preemption_key key; - ISR_Level level; + if (!rtems_chain_is_empty (chain)) + { + rtems_chain_node* node = rtems_chain_head (chain); + node = node->next; + + while (!rtems_chain_is_tail (chain, node)) + { + rtems_bdbuf_buffer* bd = (rtems_bdbuf_buffer*) node; + + if (bd->pool == pid) + { + /* + * Check if the buffer's hold timer has reached 0. If a sync + * is active force all the timers to 0. + * + * @note Lots of sync requests will skew this timer. It should + * be based on TOD to be accurate. Does it matter ? + */ + if (sync_active) + bd->hold_timer = 0; + + if (bd->hold_timer) + { + if (update_timers) + { + if (bd->hold_timer > timer_delta) + bd->hold_timer -= timer_delta; + else + bd->hold_timer = 0; + } + + if (bd->hold_timer) + { + node = node->next; + continue; + } + } - bdbuf_buffer *bd_buf; - disk_device *dd; - bdbuf_pool *pool; + /* + * This assumes we can set dev_t to -1 which is just an + * assumption. Cannot use the transfer list being empty + * the sync dev calls sets the dev to use. + */ + if (*dev == -1) + *dev = bd->dev; - dd = rtems_disk_lookup(dev); + if (bd->dev == *dev) + { + rtems_chain_node* next_node = node->next; + rtems_chain_extract (node); + rtems_chain_append (transfer, node); + node = next_node; + bd->state = RTEMS_BDBUF_STATE_TRANSFER; + } + else + { + node = node->next; + } + } + } + } +} + +/** + * Process the pool. + */ +static boolean +rtems_bdbuf_swapout_pool_processing (rtems_bdpool_id pid, + unsigned long timer_delta, + boolean update_timers, + rtems_blkdev_request* write_req) +{ + rtems_bdbuf_pool* pool = rtems_bdbuf_get_pool (pid); + rtems_chain_control transfer; + dev_t dev = -1; + rtems_disk_device* dd; + boolean result = TRUE; + + rtems_chain_initialize_empty (&transfer); + + rtems_bdbuf_lock_pool (pool); + + if (pool->sync_active) + dev = pool->sync_device; + +#if 1 + /* + * If we have any buffers in the sync queue move then to the + * modified list. The first sync buffer will select the + * device we use. + */ + rtems_bdbuf_swapout_modified_processing (pid, &dev, + &pool->sync, &transfer, + TRUE, FALSE, + timer_delta); + + /* + * Process the pool's modified list. + */ + rtems_bdbuf_swapout_modified_processing (pid, &dev, + &pool->modified, &transfer, + pool->sync_active, + update_timers, + timer_delta); + + /* + * We have all the buffers that have been modified for this device so + * the pool can be unlocked because the state is set to TRANSFER. + */ +#endif + rtems_bdbuf_unlock_pool (pool); + + /* + * If there are buffers to transfer to the media tranfer them. + */ + if (rtems_chain_is_empty (&transfer)) + result = FALSE; + else + { + /* + * Obtain the disk device. Release the pool mutex to avoid a dead + * lock. + */ + dd = rtems_disk_obtain (dev); if (dd == NULL) - return RTEMS_INVALID_ID; + result = FALSE; + else + { + /* + * The last block number used when the driver only supports + * continuous blocks in a single request. + */ + uint32_t last_block = 0; + + /* + * Take as many buffers are configured and pass to the driver. Note, + * the API to the drivers has the array of buffers and if a chain was + * passed we could have just passed the list. If the driver API is + * updated it should be possible to make this change with little effect + * in this code. The array that is passed is broken in design and + * should be removed. Merging to members of a struct into the first + * member is trouble waiting to happen. + */ + + write_req->status = RTEMS_RESOURCE_IN_USE; + write_req->start = dd->start; + write_req->error = 0; + write_req->count = 0; + write_req->bufnum = 0; + + while (!rtems_chain_is_empty (&transfer)) + { + rtems_bdbuf_buffer* bd = + (rtems_bdbuf_buffer*) rtems_chain_get (&transfer); + + boolean write = FALSE; + + /* + * If the device only accepts sequential buffers and + * this is not the first buffer (the first is always + * sequential, and the buffer is not sequential then + * put the buffer back on the transfer chain and + * write the committed buffers. + */ + + if ((dd->capabilities & RTEMS_BLKDEV_CAP_MULTISECTOR_CONT) && + write_req->count && + (bd->block != (last_block + 1))) + { + rtems_chain_prepend (&transfer, &bd->link); + write = TRUE; + } + else + { + write_req->bufs[write_req->count].user = bd; + write_req->bufs[write_req->count].block = bd->block; + write_req->bufs[write_req->count].length = dd->block_size; + write_req->bufs[write_req->count].buffer = bd->buffer; + write_req->count++; + write_req->bufnum++; + last_block = bd->block; + } - pool = rtems_bdbuf_ctx.pool + dd->pool; + /* + * Perform the transfer if there are no more buffers, or the + * transfer size has reached the configured max. value. + */ - DISABLE_PREEMPTION(key); - do { - bd_buf = avl_search_for_sync(&pool->tree, dd); - if (bd_buf != NULL /* && bd_buf->modified */) + if (rtems_chain_is_empty (&transfer) || + (write_req->count >= rtems_bdbuf_configuration.max_write_blocks)) + write = TRUE; + + if (write) { - rtems_interrupt_disable(level); - _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, - WATCHDOG_NO_TIMEOUT, level); + int result; + int b; + + /* + * Perform the transfer. No pool locks, no preemption, only the + * disk device is being held. + */ + result = dd->ioctl (dd->phys_dev->dev, + RTEMS_BLKIO_REQUEST, write_req); + + if (result < 0) + { + rtems_bdbuf_lock_pool (pool); + + for (b = 0; b < write_req->count; b++) + { + bd = write_req->bufs[b].user; + bd->state = RTEMS_BDBUF_STATE_MODIFIED; + bd->error = errno; + + /* + * Place back on the pools modified queue and try again. + * + * @warning Not sure this is the best option but I do + * not know what else can be done. + */ + rtems_chain_append (&pool->modified, &bd->link); + } + } + else + { + rtems_status_code sc = 0; + rtems_event_set out; + + sc = rtems_event_receive (RTEMS_BDBUF_TRANSFER_SYNC, + RTEMS_EVENT_ALL | RTEMS_WAIT, + 0, &out); + + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE); + + rtems_bdbuf_lock_pool (pool); + + for (b = 0; b < write_req->count; b++) + { + bd = write_req->bufs[b].user; + bd->state = RTEMS_BDBUF_STATE_CACHED; + bd->error = 0; + + rtems_chain_append (&pool->lru, &bd->link); + + if (bd->waiters) + rtems_bdbuf_wake (pool->transfer, &pool->transfer_waiters); + else + { + if (rtems_chain_has_only_one_node (&pool->lru)) + rtems_bdbuf_wake (pool->waiting, &pool->wait_waiters); + } + } + } + + rtems_bdbuf_unlock_pool (pool); + + write_req->status = RTEMS_RESOURCE_IN_USE; + write_req->error = 0; + write_req->count = 0; + write_req->bufnum = 0; } - } while (bd_buf != NULL); - ENABLE_PREEMPTION(key); - return rtems_disk_release(dd); + } + + rtems_disk_release (dd); + } + } + + if (pool->sync_active) + rtems_event_send (pool->sync_requester, RTEMS_BDBUF_TRANSFER_SYNC); + + return result; } -/* bdbuf_swapout_task -- - * Body of task which take care on flushing modified buffers to the - * disk. +/** + * Body of task which take care on flushing modified buffers to the disk. */ static rtems_task -bdbuf_swapout_task(rtems_task_argument unused) +rtems_bdbuf_swapout_task (rtems_task_argument arg) { - rtems_status_code rc; - int result; - int i; - ISR_Level level; - bdbuf_buffer *bd_buf; - bdbuf_buffer *nxt_bd_buf; - bdbuf_pool *bd_pool = NULL; - disk_device *dd = NULL; - struct { - blkdev_request req; - blkdev_sg_buffer sg[SWAP_OUT_MAX_BLK_CNT]; - } req; - write_tfer_done_arg_t write_tfer_done_arg; + rtems_bdbuf_context* context = (rtems_bdbuf_context*) arg; + rtems_blkdev_request* write_req; + uint32_t period_in_ticks; + const uint32_t period_in_msecs = rtems_bdbuf_configuration.swapout_period; + uint32_t timer_delta; + rtems_status_code sc; + + /* + * @note chrisj The rtems_blkdev_request and the array at the end is a hack. + * I am disappointment at finding code like this in RTEMS. The request should + * have been a rtems_chain_control. Simple, fast and less storage as the node + * is already part of the buffer structure. + */ + write_req = + malloc (sizeof (rtems_blkdev_request) + + (rtems_bdbuf_configuration.max_write_blocks * + sizeof (rtems_blkdev_sg_buffer))); + + if (!write_req) + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SO_NOMEM); + + write_req->req = RTEMS_BLKDEV_REQ_WRITE; + write_req->req_done = rtems_bdbuf_write_done; + write_req->done_arg = write_req; + write_req->io_task = rtems_task_self (); + + period_in_ticks = TOD_MICROSECONDS_TO_TICKS (period_in_msecs * 1000); + + /* + * This is temporary. Needs to be changed to use the real clock. + */ + timer_delta = period_in_msecs; + + while (context->swapout_enabled) + { + rtems_event_set out; /* - * provide info needed for write_transfer_done function + * Only update the timers once in the processing cycle. */ - write_tfer_done_arg.req = (blkdev_request *)&req.req; - write_tfer_done_arg.write_store = bd_buf_write_store; - nxt_bd_buf = NULL; - while (1) + boolean update_timers = TRUE; + + /* + * If we write buffers to any disk perform a check again. We only + * write a single device at a time and a pool may have more than + * one devices buffers modified waiting to be written. + */ + boolean transfered_buffers; + + do { - req.req.req = BLKDEV_REQ_WRITE; - req.req.req_done = bdbuf_write_transfer_done; - req.req.done_arg = &write_tfer_done_arg; - req.req.count = 0; - req.req.bufnum = 0; - bd_buf = NULL; - do { - /* - * if a buffer was left over from last loop, then use this buffer - * otherwise fetch new buffer from chain. - * Wait for buffer, if this is the first one of the request, - * otherwise do not wait, if no buffer available - */ - if (nxt_bd_buf == NULL) { - rc = rtems_semaphore_obtain(rtems_bdbuf_ctx.flush_sema, - (req.req.count == 0) - ? RTEMS_WAIT - : RTEMS_NO_WAIT, - 0); - if (rc == RTEMS_SUCCESSFUL) { - nxt_bd_buf = (bdbuf_buffer *)rtems_chain_get(&rtems_bdbuf_ctx.mod); - if (nxt_bd_buf != NULL) { - nxt_bd_buf->in_progress = TRUE; - /* IMD try: clear "modified" bit early */ - /* (and not in bdbuf_write_transfer_done) to allow */ - /* another modification during write processing */ - nxt_bd_buf->modified = FALSE; - - nxt_bd_buf->use_count++; - } - } - else if ((rc != RTEMS_UNSATISFIED) && - (rc != RTEMS_TIMEOUT)) { - rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_SWAPOUT); - } - } - /* - * It is possible that flush_sema semaphore will be released, but - * buffer to be removed from mod chain before swapout task start - * its processing. - */ - if ((req.req.count == 0) || /* first bd_buf for this request */ - ((nxt_bd_buf != NULL) && - (nxt_bd_buf->dev == bd_buf->dev) && /* same device */ - (nxt_bd_buf->block == bd_buf->block+1))) {/* next block */ - bd_buf = nxt_bd_buf; - nxt_bd_buf = NULL; - } - else { - bd_buf = NULL; - } - /* - * here we have three possible states: - * bd_buf == NULL, nxt_bd_buf == NULL: no further block available - * bd_buf != NULL, nxt_bd_buf == NULL: append bd_buf to request - * bd_buf == NULL, nxt_bd_buf != NULL: nxt_bd_buf canot be appended - * to current request, keep it - * for next main loop - */ - if (bd_buf != NULL) { - bd_pool = rtems_bdbuf_ctx.pool + bd_buf->pool; - if (req.req.count == 0) { - /* - * this is the first block, so use its address - */ - dd = rtems_disk_lookup(bd_buf->dev); - req.req.start = bd_buf->block + dd->start; - } - req.req.bufs[req.req.bufnum].length = dd->block_size; - req.req.bufs[req.req.bufnum].buffer = bd_buf->buffer; - /* - * keep bd_buf for postprocessing - */ - bd_buf_write_store[req.req.bufnum] = bd_buf; - req.req.count++; - req.req.bufnum++; - } - } while ((bd_buf != NULL) && - (req.req.count < SWAP_OUT_MAX_BLK_CNT)); - - /* transfer_sema initialized when bd_buf inserted in the mod chain - first time */ - result = dd->ioctl(dd->phys_dev->dev, BLKIO_REQUEST, &req); - - rtems_disk_release(dd); - - for (i = 0;i < req.req.count;i++) { - bd_buf = bd_buf_write_store[i]; - if (result == -1) - { - - bd_buf->status = RTEMS_IO_ERROR; - bd_buf->error = errno; - /* Release tasks waiting on syncing this buffer */ - _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL, - CORE_MUTEX_STATUS_SUCCESSFUL); - } - else - { - if (bd_buf->in_progress) - { - rtems_interrupt_disable(level); - _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, 0, level); - } - } - bd_buf->use_count--; - - /* Another task have chance to use this buffer, or even - * modify it. If buffer is not in use, insert it in appropriate chain - * and release semaphore */ - if (bd_buf->use_count == 0) - { - if (bd_buf->modified) - { - rtems_chain_append(&rtems_bdbuf_ctx.mod, &bd_buf->link); - rc = rtems_semaphore_release(rtems_bdbuf_ctx.flush_sema); - } - else - { - rtems_chain_append(&bd_pool->lru, &bd_buf->link); - rc = rtems_semaphore_release(bd_pool->bufget_sema); - } - } + rtems_bdpool_id pid; + + transfered_buffers = FALSE; + + /* + * Loop over each pool extacting all the buffers we find for a specific + * device. The device is the first one we find on a modified list of a + * pool. Process the sync queue of buffers first. + */ + for (pid = 0; pid < context->npools; pid++) + { + if (rtems_bdbuf_swapout_pool_processing (pid, + timer_delta, + update_timers, + write_req)) + { + transfered_buffers = TRUE; } + } + + /* + * Only update the timers once. + */ + update_timers = FALSE; } + while (transfered_buffers); + + sc = rtems_event_receive (RTEMS_BDBUF_SWAPOUT_SYNC, + RTEMS_EVENT_ALL | RTEMS_WAIT, + period_in_ticks, + &out); + + if ((sc != RTEMS_SUCCESSFUL) && (sc != RTEMS_TIMEOUT)) + rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE); + } + + free (write_req); + + rtems_task_delete (RTEMS_SELF); } -/* rtems_bdbuf_find_pool -- - * Find first appropriate buffer pool. This primitive returns the index - * of first buffer pool which block size is greater than or equal to - * specified size. +/** + * Find first appropriate buffer pool. This primitive returns the index of + * first buffer pool which block size is greater than or equal to specified + * size. * * PARAMETERS: * block_size - requested block size @@ -1813,44 +2380,45 @@ bdbuf_swapout_task(rtems_task_argument unused) * is not configured. */ rtems_status_code -rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool) +rtems_bdbuf_find_pool (int block_size, rtems_bdpool_id *pool) { - rtems_bdpool_id i; - bdbuf_pool *p; - int cursize = INT_MAX; - rtems_bdpool_id curid = -1; - rtems_boolean found = FALSE; - int j; - - for (j = block_size; (j != 0) && ((j & 1) == 0); j >>= 1); - if (j != 1) - return RTEMS_INVALID_SIZE; - - for (i = 0, p = rtems_bdbuf_ctx.pool; i < rtems_bdbuf_ctx.npools; i++, p++) + rtems_bdbuf_pool* p; + rtems_bdpool_id i; + rtems_bdpool_id curid = -1; + rtems_boolean found = FALSE; + int cursize = INT_MAX; + int j; + + for (j = block_size; (j != 0) && ((j & 1) == 0); j >>= 1); + if (j != 1) + return RTEMS_INVALID_SIZE; + + for (i = 0; i < rtems_bdbuf_ctx.npools; i++) + { + p = rtems_bdbuf_get_pool (i); + if ((p->blksize >= block_size) && + (p->blksize < cursize)) { - if ((p->blksize >= block_size) && - (p->blksize < cursize)) - { - curid = i; - cursize = p->blksize; - found = TRUE; - } + curid = i; + cursize = p->blksize; + found = TRUE; } + } - if (found) - { - if (pool != NULL) - *pool = curid; - return RTEMS_SUCCESSFUL; - } - else - { - return RTEMS_NOT_DEFINED; - } + if (found) + { + if (pool != NULL) + *pool = curid; + return RTEMS_SUCCESSFUL; + } + else + { + return RTEMS_NOT_DEFINED; + } } -/* rtems_bdbuf_get_pool_info -- - * Obtain characteristics of buffer pool with specified number. +/** + * Obtain characteristics of buffer pool with specified number. * * PARAMETERS: * pool - buffer pool number @@ -1866,21 +2434,20 @@ rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool) * Buffer pools enumerated contiguously starting from 0. */ rtems_status_code -rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size, - int *blocks) +rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int* block_size, int* blocks) { - if (pool >= rtems_bdbuf_ctx.npools) - return RTEMS_INVALID_NUMBER; + if (pool >= rtems_bdbuf_ctx.npools) + return RTEMS_INVALID_NUMBER; - if (block_size != NULL) - { - *block_size = rtems_bdbuf_ctx.pool[pool].blksize; - } + if (block_size != NULL) + { + *block_size = rtems_bdbuf_ctx.pool[pool].blksize; + } - if (blocks != NULL) - { - *blocks = rtems_bdbuf_ctx.pool[pool].nblks; - } + if (blocks != NULL) + { + *blocks = rtems_bdbuf_ctx.pool[pool].nblks; + } - return RTEMS_SUCCESSFUL; + return RTEMS_SUCCESSFUL; } diff --git a/cpukit/libblock/src/blkdev.c b/cpukit/libblock/src/blkdev.c index e133e5eaf2..a93875c9a2 100644 --- a/cpukit/libblock/src/blkdev.c +++ b/cpukit/libblock/src/blkdev.c @@ -38,10 +38,10 @@ rtems_blkdev_generic_read( unsigned int block; unsigned int blkofs; dev_t dev; - disk_device *dd; + rtems_disk_device *dd; dev = rtems_filesystem_make_dev_t(major, minor); - dd = rtems_disk_lookup(dev); + dd = rtems_disk_obtain(dev); if (dd == NULL) return RTEMS_INVALID_NUMBER; @@ -57,7 +57,7 @@ rtems_blkdev_generic_read( while (count > 0) { - bdbuf_buffer *diskbuf; + rtems_bdbuf_buffer *diskbuf; int copy; rtems_status_code rc; @@ -99,10 +99,10 @@ rtems_blkdev_generic_write( unsigned int blkofs; dev_t dev; rtems_status_code rc; - disk_device *dd; + rtems_disk_device *dd; dev = rtems_filesystem_make_dev_t(major, minor); - dd = rtems_disk_lookup(dev); + dd = rtems_disk_obtain(dev); if (dd == NULL) return RTEMS_INVALID_NUMBER; @@ -118,7 +118,7 @@ rtems_blkdev_generic_write( while (count > 0) { - bdbuf_buffer *diskbuf; + rtems_bdbuf_buffer *diskbuf; int copy; if ((blkofs == 0) && (count >= block_size)) @@ -156,10 +156,10 @@ rtems_blkdev_generic_open( void * arg) { dev_t dev; - disk_device *dd; + rtems_disk_device *dd; dev = rtems_filesystem_make_dev_t(major, minor); - dd = rtems_disk_lookup(dev); + dd = rtems_disk_obtain(dev); if (dd == NULL) return RTEMS_INVALID_NUMBER; @@ -181,10 +181,10 @@ rtems_blkdev_generic_close( void * arg) { dev_t dev; - disk_device *dd; + rtems_disk_device *dd; dev = rtems_filesystem_make_dev_t(major, minor); - dd = rtems_disk_lookup(dev); + dd = rtems_disk_obtain(dev); if (dd == NULL) return RTEMS_INVALID_NUMBER; @@ -206,32 +206,32 @@ rtems_blkdev_generic_ioctl( { rtems_libio_ioctl_args_t *args = arg; dev_t dev; - disk_device *dd; + rtems_disk_device *dd; int rc; dev = rtems_filesystem_make_dev_t(major, minor); - dd = rtems_disk_lookup(dev); + dd = rtems_disk_obtain(dev); if (dd == NULL) return RTEMS_INVALID_NUMBER; switch (args->command) { - case BLKIO_GETBLKSIZE: + case RTEMS_BLKIO_GETBLKSIZE: args->ioctl_return = dd->block_size; break; - case BLKIO_GETSIZE: + case RTEMS_BLKIO_GETSIZE: args->ioctl_return = dd->size; break; - case BLKIO_SYNCDEV: + case RTEMS_BLKIO_SYNCDEV: rc = rtems_bdbuf_syncdev(dd->dev); args->ioctl_return = (rc == RTEMS_SUCCESSFUL ? 0 : -1); break; - case BLKIO_REQUEST: + case RTEMS_BLKIO_REQUEST: { - blkdev_request *req = args->buffer; + rtems_blkdev_request *req = args->buffer; req->start += dd->start; args->ioctl_return = dd->ioctl(dd->phys_dev->dev, args->command, req); diff --git a/cpukit/libblock/src/diskdevs.c b/cpukit/libblock/src/diskdevs.c index 545a4096e7..94a58daa6f 100644 --- a/cpukit/libblock/src/diskdevs.c +++ b/cpukit/libblock/src/diskdevs.c @@ -23,13 +23,13 @@ #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 */ +typedef struct rtems_disk_device_table { + rtems_disk_device **minor; /* minor-indexed disk device table */ int size; /* Number of entries in the table */ -}; +} rtems_disk_device_table; /* Pointer to [major].minor[minor] indexed array of disk devices */ -static struct disk_device_table *disktab; +static rtems_disk_device_table *disktab; /* Number of allocated entries in disktab table */ static int disktab_size; @@ -64,24 +64,24 @@ static volatile rtems_boolean diskdevs_protected; * pointer to the disk device descriptor entry, or NULL if no memory * available for its creation. */ -static disk_device * +static rtems_disk_device * create_disk_entry(dev_t dev) { rtems_device_major_number major; rtems_device_minor_number minor; - struct disk_device **d; + rtems_disk_device **d; rtems_filesystem_split_dev_t (dev, major, minor); if (major >= disktab_size) { - struct disk_device_table *p; + rtems_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); + p = realloc(disktab, sizeof(rtems_disk_device_table) * newsize); if (p == NULL) return NULL; p += disktab_size; @@ -97,7 +97,7 @@ create_disk_entry(dev_t dev) (minor >= disktab[major].size)) { int newsize; - disk_device **p; + rtems_disk_device **p; int i; int s = disktab[major].size; @@ -108,7 +108,8 @@ create_disk_entry(dev_t dev) if (minor >= newsize) newsize = minor + 1; - p = realloc(disktab[major].minor, sizeof(disk_device *) * newsize); + p = realloc(disktab[major].minor, + sizeof(rtems_disk_device *) * newsize); if (p == NULL) return NULL; disktab[major].minor = p; @@ -121,7 +122,7 @@ create_disk_entry(dev_t dev) d = disktab[major].minor + minor; if (*d == NULL) { - *d = calloc(1, sizeof(disk_device)); + *d = calloc(1, sizeof(rtems_disk_device)); } return *d; } @@ -136,12 +137,12 @@ create_disk_entry(dev_t dev) * 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 * +static rtems_disk_device * get_disk_entry(dev_t dev) { rtems_device_major_number major; rtems_device_minor_number minor; - struct disk_device_table *dtab; + rtems_disk_device_table *dtab; rtems_filesystem_split_dev_t (dev, major, minor); @@ -171,9 +172,9 @@ get_disk_entry(dev_t dev) * no memory available). */ static rtems_status_code -create_disk(dev_t dev, const char *name, disk_device **diskdev) +create_disk(dev_t dev, const char *name, rtems_disk_device **diskdev) { - disk_device *dd; + rtems_disk_device *dd; char *n; dd = get_disk_entry(dev); @@ -234,12 +235,12 @@ create_disk(dev_t dev, const char *name, disk_device **diskdev) */ rtems_status_code rtems_disk_create_phys(dev_t dev, int block_size, int disk_size, - block_device_ioctl handler, + rtems_block_device_ioctl handler, const char *name) { int bs_log2; int i; - disk_device *dd; + rtems_disk_device *dd; rtems_status_code rc; rtems_bdpool_id pool; rtems_device_major_number major; @@ -284,6 +285,11 @@ rtems_disk_create_phys(dev_t dev, int block_size, int disk_size, rc = rtems_io_register_name(name, major, minor); + if (handler (dd->phys_dev->dev, + RTEMS_BLKDEV_CAPABILITIES, + &dd->capabilities) < 0) + dd->capabilities = 0; + diskdevs_protected = FALSE; rtems_semaphore_release(diskdevs_mutex); @@ -317,8 +323,8 @@ rtems_disk_create_phys(dev_t dev, int block_size, int disk_size, 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_disk_device *dd; + rtems_disk_device *pdd; rtems_status_code rc; rtems_device_major_number major; rtems_device_minor_number minor; @@ -393,12 +399,12 @@ rtems_disk_delete(dev_t dev) used = 0; for (maj = 0; maj < disktab_size; maj++) { - struct disk_device_table *dtab = disktab + maj; + rtems_disk_device_table *dtab = disktab + maj; if (dtab != NULL) { for (min = 0; min < dtab->size; min++) { - disk_device *dd = dtab->minor[min]; + rtems_disk_device *dd = dtab->minor[min]; if ((dd != NULL) && (dd->phys_dev->dev == dev)) used += dd->uses; } @@ -415,12 +421,12 @@ rtems_disk_delete(dev_t dev) /* Delete this device and all of its logical devices */ for (maj = 0; maj < disktab_size; maj++) { - struct disk_device_table *dtab = disktab +maj; + rtems_disk_device_table *dtab = disktab +maj; if (dtab != NULL) { for (min = 0; min < dtab->size; min++) { - disk_device *dd = dtab->minor[min]; + rtems_disk_device *dd = dtab->minor[min]; if ((dd != NULL) && (dd->phys_dev->dev == dev)) { unlink(dd->name); @@ -437,7 +443,7 @@ rtems_disk_delete(dev_t dev) return rc; } -/* rtems_disk_lookup -- +/* rtems_disk_obtain -- * Find block device descriptor by its device identifier. * * PARAMETERS: @@ -447,11 +453,11 @@ rtems_disk_delete(dev_t dev) * pointer to the block device descriptor, or NULL if no such device * exists. */ -disk_device * -rtems_disk_lookup(dev_t dev) +rtems_disk_device * +rtems_disk_obtain(dev_t dev) { rtems_interrupt_level level; - disk_device *dd; + rtems_disk_device *dd; rtems_status_code rc; rtems_interrupt_disable(level); @@ -480,7 +486,7 @@ rtems_disk_lookup(dev_t dev) } /* rtems_disk_release -- - * Release disk_device structure (decrement usage counter to 1). + * Release rtems_disk_device structure (decrement usage counter to 1). * * PARAMETERS: * dd - pointer to disk device structure @@ -489,7 +495,7 @@ rtems_disk_lookup(dev_t dev) * RTEMS_SUCCESSFUL */ rtems_status_code -rtems_disk_release(disk_device *dd) +rtems_disk_release(rtems_disk_device *dd) { rtems_interrupt_level level; rtems_interrupt_disable(level); @@ -510,12 +516,12 @@ rtems_disk_release(disk_device *dd) * Pointer to the disk descriptor for next disk device, or NULL if all * devices enumerated. */ -disk_device * +rtems_disk_device * rtems_disk_next(dev_t dev) { rtems_device_major_number major; rtems_device_minor_number minor; - struct disk_device_table *dtab; + rtems_disk_device_table *dtab; dev++; rtems_filesystem_split_dev_t (dev, major, minor); @@ -562,7 +568,7 @@ rtems_disk_io_initialize(void) return RTEMS_SUCCESSFUL; disktab_size = DISKTAB_INITIAL_SIZE; - disktab = calloc(disktab_size, sizeof(struct disk_device_table)); + disktab = calloc(disktab_size, sizeof(rtems_disk_device_table)); if (disktab == NULL) return RTEMS_NO_MEMORY; @@ -578,8 +584,7 @@ rtems_disk_io_initialize(void) return rc; } - rc = rtems_bdbuf_init(rtems_bdbuf_configuration, - rtems_bdbuf_configuration_size); + rc = rtems_bdbuf_init(); if (rc != RTEMS_SUCCESSFUL) { @@ -612,12 +617,12 @@ rtems_disk_io_done(void) /* Free data structures */ for (maj = 0; maj < disktab_size; maj++) { - struct disk_device_table *dtab = disktab + maj; + rtems_disk_device_table *dtab = disktab + maj; if (dtab != NULL) { for (min = 0; min < dtab->size; min++) { - disk_device *dd = dtab->minor[min]; + rtems_disk_device *dd = dtab->minor[min]; unlink(dd->name); free(dd->name); free(dd); diff --git a/cpukit/libblock/src/flashdisk.c b/cpukit/libblock/src/flashdisk.c index 4e8b261a93..d67d4a02bf 100644 --- a/cpukit/libblock/src/flashdisk.c +++ b/cpukit/libblock/src/flashdisk.c @@ -2057,14 +2057,13 @@ rtems_fdisk_write_block (rtems_flashdisk* fd, * @retval int The ioctl return value. */ static int -rtems_fdisk_read (rtems_flashdisk* fd, blkdev_request* req) +rtems_fdisk_read (rtems_flashdisk* fd, rtems_blkdev_request* req) { - blkdev_sg_buffer* sg = req->bufs; - uint32_t block = req->start; - uint32_t b; - int ret = 0; + rtems_blkdev_sg_buffer* sg = req->bufs; + uint32_t b; + int ret = 0; - for (b = 0; b < req->bufnum; b++, block++, sg++) + for (b = 0; b < req->bufnum; b++, sg++) { uint32_t length = sg->length; @@ -2077,7 +2076,7 @@ rtems_fdisk_read (rtems_flashdisk* fd, blkdev_request* req) length = fd->block_size; } - ret = rtems_fdisk_read_block (fd, block, sg->buffer); + ret = rtems_fdisk_read_block (fd, sg->block, sg->buffer); if (ret) break; @@ -2098,14 +2097,13 @@ rtems_fdisk_read (rtems_flashdisk* fd, blkdev_request* req) * @retval int The ioctl return value. */ static int -rtems_fdisk_write (rtems_flashdisk* fd, blkdev_request* req) +rtems_fdisk_write (rtems_flashdisk* fd, rtems_blkdev_request* req) { - blkdev_sg_buffer* sg = req->bufs; - uint32_t block = req->start; - uint32_t b; - int ret = 0; + rtems_blkdev_sg_buffer* sg = req->bufs; + uint32_t b; + int ret = 0; - for (b = 0; b < req->bufnum; b++, block++, sg++) + for (b = 0; b < req->bufnum; b++, sg++) { if (sg->length != fd->block_size) { @@ -2113,7 +2111,7 @@ rtems_fdisk_write (rtems_flashdisk* fd, blkdev_request* req) "bd:%d fd:%d", sg->length, fd->block_size); } - ret = rtems_fdisk_write_block (fd, block, sg->buffer); + ret = rtems_fdisk_write_block (fd, sg->block, sg->buffer); if (ret) break; @@ -2356,7 +2354,7 @@ static int rtems_fdisk_ioctl (dev_t dev, uint32_t req, void* argp) { rtems_device_minor_number minor = rtems_filesystem_dev_minor_t (dev); - blkdev_request* r = argp; + rtems_blkdev_request* r = argp; rtems_status_code sc; errno = 0; @@ -2368,7 +2366,7 @@ rtems_fdisk_ioctl (dev_t dev, uint32_t req, void* argp) { switch (req) { - case BLKIO_REQUEST: + case RTEMS_BLKIO_REQUEST: if ((minor >= rtems_flashdisk_count) || (rtems_flashdisks[minor].device_count == 0)) { @@ -2378,11 +2376,11 @@ rtems_fdisk_ioctl (dev_t dev, uint32_t req, void* argp) { switch (r->req) { - case BLKDEV_REQ_READ: + case RTEMS_BLKDEV_REQ_READ: errno = rtems_fdisk_read (&rtems_flashdisks[minor], r); break; - case BLKDEV_REQ_WRITE: + case RTEMS_BLKDEV_REQ_WRITE: errno = rtems_fdisk_write (&rtems_flashdisks[minor], r); break; diff --git a/cpukit/libblock/src/ide_part_table.c b/cpukit/libblock/src/ide_part_table.c index 2b5b46138b..5d44c9a960 100644 --- a/cpukit/libblock/src/ide_part_table.c +++ b/cpukit/libblock/src/ide_part_table.c @@ -46,18 +46,18 @@ * and does not support devices with sector size other than 512 bytes */ static rtems_status_code -get_sector(dev_t dev, uint32_t sector_num, sector_data_t **sector) +get_sector(dev_t dev, uint32_t sector_num, rtems_sector_data_t **sector) { - sector_data_t *s; - bdbuf_buffer *buf; - rtems_status_code rc; + rtems_sector_data_t *s; + rtems_bdbuf_buffer *buf; + rtems_status_code rc; if (sector == NULL) { return RTEMS_INTERNAL_ERROR; } - s = (sector_data_t *) malloc(sizeof(sector_data_t) + RTEMS_IDE_SECTOR_SIZE); + s = (rtems_sector_data_t *) malloc(sizeof(rtems_sector_data_t) + RTEMS_IDE_SECTOR_SIZE); if (s == NULL) { return RTEMS_NO_MEMORY; @@ -92,7 +92,7 @@ get_sector(dev_t dev, uint32_t sector_num, sector_data_t **sector) * TRUE if sector has msdos signature, FALSE otherwise */ static rtems_boolean -msdos_signature_check (sector_data_t *sector) +msdos_signature_check (rtems_sector_data_t *sector) { uint8_t *p = sector->data + RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_OFFSET; @@ -156,10 +156,10 @@ is_fat_partition(uint8_t type) * RTEMS_INTERNAL_ERROR, if other error occurs. */ static rtems_status_code -data_to_part_desc(uint8_t *data, part_desc_t **new_part_desc) +data_to_part_desc(uint8_t *data, rtems_part_desc_t **new_part_desc) { - part_desc_t *part_desc; - uint32_t temp; + rtems_part_desc_t *part_desc; + uint32_t temp; if (new_part_desc == NULL) { @@ -168,7 +168,7 @@ data_to_part_desc(uint8_t *data, part_desc_t **new_part_desc) *new_part_desc = NULL; - if ((part_desc = calloc(1, sizeof(part_desc_t))) == NULL) + if ((part_desc = calloc(1, sizeof(rtems_part_desc_t))) == NULL) { return RTEMS_NO_MEMORY; } @@ -219,15 +219,15 @@ data_to_part_desc(uint8_t *data, part_desc_t **new_part_desc) * RTEMS_INTERNAL_ERROR if other error occurs. */ static rtems_status_code -read_extended_partition(uint32_t start, part_desc_t *ext_part) +read_extended_partition(uint32_t start, rtems_part_desc_t *ext_part) { - int i; - dev_t dev; - sector_data_t *sector; - uint32_t here; - uint8_t *data; - part_desc_t *new_part_desc; - rtems_status_code rc; + int i; + dev_t dev; + rtems_sector_data_t *sector; + uint32_t here; + uint8_t *data; + rtems_part_desc_t *new_part_desc; + rtems_status_code rc; if ((ext_part == NULL) || (ext_part->disk_desc == NULL)) { @@ -286,7 +286,7 @@ read_extended_partition(uint32_t start, part_desc_t *ext_part) } else { - disk_desc_t *disk_desc = new_part_desc->disk_desc; + rtems_disk_desc_t *disk_desc = new_part_desc->disk_desc; disk_desc->partitions[disk_desc->last_log_id] = new_part_desc; new_part_desc->log_id = ++disk_desc->last_log_id; new_part_desc->start += here; @@ -314,14 +314,14 @@ read_extended_partition(uint32_t start, part_desc_t *ext_part) * RTEMS_INTERNAL_ERROR otherwise */ static rtems_status_code -read_mbr(disk_desc_t *disk_desc) +read_mbr(rtems_disk_desc_t *disk_desc) { - int part_num; - sector_data_t *sector; - part_desc_t *part_desc; - uint8_t *data; - rtems_status_code rc; - dev_t dev = disk_desc->dev; + int part_num; + rtems_sector_data_t *sector; + rtems_part_desc_t *part_desc; + uint8_t *data; + rtems_status_code rc; + dev_t dev = disk_desc->dev; /* get MBR sector */ rc = get_sector(dev, 0, §or); @@ -398,7 +398,7 @@ read_mbr(disk_desc_t *disk_desc) * N/A */ static void -partition_free(part_desc_t *part_desc) +partition_free(rtems_part_desc_t *part_desc) { int part_num; @@ -429,7 +429,7 @@ partition_free(part_desc_t *part_desc) * N/A */ void -rtems_ide_part_table_free(disk_desc_t *disk_desc) +rtems_ide_part_table_free(rtems_disk_desc_t *disk_desc) { int part_num; @@ -455,7 +455,7 @@ rtems_ide_part_table_free(disk_desc_t *disk_desc) * RTEMS_INTERNAL_ERROR otherwise */ rtems_status_code -rtems_ide_part_table_get(const char *dev_name, disk_desc_t *disk_desc) +rtems_ide_part_table_get(const char *dev_name, rtems_disk_desc_t *disk_desc) { struct stat dev_stat; rtems_status_code rc; @@ -494,16 +494,16 @@ rtems_ide_part_table_initialize(char *dev_name) { int part_num; dev_t dev; - disk_desc_t *disk_desc; + rtems_disk_desc_t *disk_desc; rtems_device_major_number major; rtems_device_minor_number minor; rtems_status_code rc; - part_desc_t *part_desc; + rtems_part_desc_t *part_desc; /* logical device name /dev/hdxyy */ char name[RTEMS_IDE_PARTITION_DEV_NAME_LENGTH_MAX]; - disk_desc = (disk_desc_t *) calloc(1, sizeof(disk_desc_t)); + disk_desc = (rtems_disk_desc_t *) calloc(1, sizeof(rtems_disk_desc_t)); if (disk_desc == NULL) { return RTEMS_NO_MEMORY; diff --git a/cpukit/libblock/src/nvdisk.c b/cpukit/libblock/src/nvdisk.c index 0ee094bdc6..4166d79c98 100644 --- a/cpukit/libblock/src/nvdisk.c +++ b/cpukit/libblock/src/nvdisk.c @@ -51,7 +51,7 @@ * footprint targets. Leave in by default. */ #if !defined (RTEMS_NVDISK_TRACE) -#define RTEMS_NVDISK_TRACE 1 +#define RTEMS_NVDISK_TRACE 0 #endif /** @@ -165,7 +165,7 @@ rtems_nvdisk_crc16_gen_factors (uint16_t pattern) /** * Print a message to the nvdisk output and flush it. * - * @param fd The flashdisk control structure. + * @param nvd The nvdisk control structure. * @param format The format string. See printf for details. * @param ... The arguments for the format text. * @return int The number of bytes written to the output. @@ -189,7 +189,7 @@ rtems_nvdisk_printf (const rtems_nvdisk* nvd, const char *format, ...) /** * Print a info message to the nvdisk output and flush it. * - * @param fd The flashdisk control structure. + * @param nvd The nvdisk control structure. * @param format The format string. See printf for details. * @param ... The arguments for the format text. * @return int The number of bytes written to the output. @@ -213,7 +213,7 @@ rtems_nvdisk_info (const rtems_nvdisk* nvd, const char *format, ...) /** * Print a warning to the nvdisk output and flush it. * - * @param fd The flashdisk control structure. + * @param nvd The nvdisk control structure. * @param format The format string. See printf for details. * @param ... The arguments for the format text. * @return int The number of bytes written to the output. @@ -256,24 +256,6 @@ rtems_nvdisk_error (const char *format, ...) } /** - * Print an abort message, flush it then abort the program. - * - * @param format The format string. See printf for details. - * @param ... The arguments for the format text. - */ -static void -rtems_nvdisk_abort (const char *format, ...) -{ - va_list args; - va_start (args, format); - fprintf (stderr, "nvdisk:abort:"); - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); - fflush (stderr); - exit (1); -} - -/** * Get the descriptor for a device. */ static const rtems_nvdisk_device_desc* @@ -324,6 +306,7 @@ rtems_nvdisk_device_write (const rtems_nvdisk* nvd, return ops->write (device, dd->flags, dd->base, offset, buffer, size); } +#if NOT_USED /** * Verify the data with the data in a segment. */ @@ -344,6 +327,7 @@ rtems_nvdisk_device_verify (const rtems_nvdisk* nvd, #endif return ops->verify (device, dd->flags, dd->base, offset, buffer, size); } +#endif /** * Read a page of data from the device. @@ -374,20 +358,6 @@ rtems_nvdisk_write_page (const rtems_nvdisk* nvd, } /** - * Verify a page of data with the data in the device. - */ -static int -rtems_nvdisk_verify_page (const rtems_nvdisk* nvd, - uint32_t device, - uint32_t page, - const void* buffer) -{ - return rtems_nvdisk_device_verify (nvd, device, - page * nvd->block_size, - buffer, nvd->block_size); -} - -/** * Read the checksum from the device. */ static int @@ -532,7 +502,9 @@ rtems_nvdisk_read_block (rtems_nvdisk* nvd, uint32_t block, uint8_t* buffer) if (crc == 0xffff) { +#if RTEMS_NVDISK_TRACE rtems_nvdisk_warning (nvd, "read-block: crc not set: %d", block); +#endif memset (buffer, 0, nvd->block_size); return 0; } @@ -605,13 +577,12 @@ rtems_nvdisk_write_block (rtems_nvdisk* nvd, * @retval int The ioctl return value. */ static int -rtems_nvdisk_read (rtems_nvdisk* nvd, blkdev_request* req) +rtems_nvdisk_read (rtems_nvdisk* nvd, rtems_blkdev_request* req) { - blkdev_sg_buffer* sg = req->bufs; - uint32_t block = req->start; - uint32_t b; - int32_t remains; - int ret = 0; + rtems_blkdev_sg_buffer* sg = req->bufs; + uint32_t b; + int32_t remains; + int ret = 0; #if RTEMS_NVDISK_TRACE rtems_nvdisk_info (nvd, "read: blocks=%d", req->bufnum); @@ -619,7 +590,7 @@ rtems_nvdisk_read (rtems_nvdisk* nvd, blkdev_request* req) remains = req->count * nvd->block_size; - for (b = 0; b < req->bufnum; b++, block++, sg++) + for (b = 0; b < req->bufnum; b++, sg++) { uint32_t length = sg->length; @@ -658,18 +629,17 @@ rtems_nvdisk_read (rtems_nvdisk* nvd, blkdev_request* req) * @retval int The ioctl return value. */ static int -rtems_nvdisk_write (rtems_nvdisk* nvd, blkdev_request* req) +rtems_nvdisk_write (rtems_nvdisk* nvd, rtems_blkdev_request* req) { - blkdev_sg_buffer* sg = req->bufs; - uint32_t block = req->start; - uint32_t b; - int ret = 0; + rtems_blkdev_sg_buffer* sg = req->bufs; + uint32_t b; + int ret = 0; #if RTEMS_NVDISK_TRACE rtems_nvdisk_info (nvd, "write: blocks=%d", req->bufnum); #endif - for (b = 0; b < req->bufnum; b++, block++, sg++) + for (b = 0; b < req->bufnum; b++, sg++) { if (sg->length != nvd->block_size) { @@ -720,7 +690,7 @@ rtems_nvdisk_erase_disk (rtems_nvdisk* nvd) } /** - * MV disk IOCTL handler. + * NV disk IOCTL handler. * * @param dev Device number (major, minor number). * @param req IOCTL request code. @@ -731,9 +701,21 @@ static int rtems_nvdisk_ioctl (dev_t dev, uint32_t req, void* argp) { rtems_device_minor_number minor = rtems_filesystem_dev_minor_t (dev); - blkdev_request* r = argp; + rtems_blkdev_request* r = argp; rtems_status_code sc; + if (minor >= rtems_nvdisk_count) + { + errno = ENODEV; + return -1; + } + + if (rtems_nvdisks[minor].device_count == 0) + { + errno = ENODEV; + return -1; + } + errno = 0; sc = rtems_semaphore_obtain (rtems_nvdisks[minor].lock, RTEMS_WAIT, 0); @@ -743,39 +725,31 @@ rtems_nvdisk_ioctl (dev_t dev, uint32_t req, void* argp) { switch (req) { - case BLKIO_REQUEST: - if ((minor >= rtems_nvdisk_count) || - (rtems_nvdisks[minor].device_count == 0)) - { - errno = ENODEV; - } - else + case RTEMS_BLKIO_REQUEST: + switch (r->req) { - switch (r->req) - { - case BLKDEV_REQ_READ: - errno = rtems_nvdisk_read (&rtems_nvdisks[minor], r); - break; - - case BLKDEV_REQ_WRITE: - errno = rtems_nvdisk_write (&rtems_nvdisks[minor], r); - break; - - default: - errno = EBADRQC; - break; - } + case RTEMS_BLKDEV_REQ_READ: + errno = rtems_nvdisk_read (&rtems_nvdisks[minor], r); + break; + + case RTEMS_BLKDEV_REQ_WRITE: + errno = rtems_nvdisk_write (&rtems_nvdisks[minor], r); + break; + + default: + errno = EBADRQC; + break; } break; case RTEMS_NVDISK_IOCTL_ERASE_DISK: errno = rtems_nvdisk_erase_disk (&rtems_nvdisks[minor]); break; - + case RTEMS_NVDISK_IOCTL_INFO_LEVEL: rtems_nvdisks[minor].info_level = (uint32_t) argp; break; - + default: errno = EBADRQC; break; diff --git a/cpukit/libblock/src/ramdisk.c b/cpukit/libblock/src/ramdisk.c index b72e3ae795..3b3f3f29b0 100644 --- a/cpukit/libblock/src/ramdisk.c +++ b/cpukit/libblock/src/ramdisk.c @@ -22,6 +22,14 @@ #include "rtems/diskdevs.h" #include "rtems/ramdisk.h" +/** + * Control tracing. It can be compiled out of the code for small + * footprint targets. Leave in by default. + */ +#if !defined (RTEMS_RAMDISK_TRACE) +#define RTEMS_RAMDISK_TRACE 0 +#endif + #define RAMDISK_DEVICE_BASE_NAME "/dev/ramdisk" /* Internal RAM disk descriptor */ @@ -32,11 +40,40 @@ struct ramdisk { rtems_boolean initialized;/* RAM disk is initialized */ rtems_boolean malloced; /* != 0, if memory allocated by malloc for this RAM disk */ +#if RTEMS_RAMDISK_TRACE + int info_level; /* Trace level */ +#endif }; static struct ramdisk *ramdisk; static int nramdisks; +#if RTEMS_RAMDISK_TRACE +/** + * Print a message to the ramdisk output and flush it. + * + * @param rd The ramdisk control structure. + * @param format The format string. See printf for details. + * @param ... The arguments for the format text. + * @return int The number of bytes written to the output. + */ +static int +rtems_ramdisk_printf (struct ramdisk *rd, const char *format, ...) +{ + int ret = 0; + if (rd->info_level >= 1) + { + va_list args; + va_start (args, format); + fprintf (stdout, "ramdisk:"); + ret = vfprintf (stdout, format, args); + fprintf (stdout, "\n"); + fflush (stdout); + } + return ret; +} +#endif + /* ramdisk_read -- * RAM disk READ request handler. This primitive copies data from RAM * disk to supplied buffer and invoke the callout function to inform @@ -49,19 +86,25 @@ static int nramdisks; * ioctl return value */ static int -ramdisk_read(struct ramdisk *rd, blkdev_request *req) +ramdisk_read(struct ramdisk *rd, rtems_blkdev_request *req) { char *from; uint32_t i; - blkdev_sg_buffer *sg; + rtems_blkdev_sg_buffer *sg; uint32_t remains; - from = (char *)rd->area + (req->start * rd->block_size); +#if RTEMS_RAMDISK_TRACE + rtems_ramdisk_printf (rd, "ramdisk read: start=%d, blocks=%d remains=%d", + req->bufs[0].block, req->bufnum, + rd->block_size * req->count); +#endif + remains = rd->block_size * req->count; sg = req->bufs; for (i = 0; (remains > 0) && (i < req->bufnum); i++, sg++) { int count = sg->length; + from = ((char *)rd->area + (sg->block * rd->block_size)); if (count > remains) count = remains; memcpy(sg->buffer, from, count); @@ -84,19 +127,24 @@ ramdisk_read(struct ramdisk *rd, blkdev_request *req) * ioctl return value */ static int -ramdisk_write(struct ramdisk *rd, blkdev_request *req) +ramdisk_write(struct ramdisk *rd, rtems_blkdev_request *req) { char *to; uint32_t i; - blkdev_sg_buffer *sg; + rtems_blkdev_sg_buffer *sg; uint32_t remains; - to = (char *)rd->area + (req->start * rd->block_size); +#if RTEMS_RAMDISK_TRACE + rtems_ramdisk_printf (rd, "ramdisk write: start=%d, blocks=%d remains=%d", + req->bufs[0].block, req->bufnum, + rd->block_size * req->count); +#endif remains = rd->block_size * req->count; sg = req->bufs; for (i = 0; (remains > 0) && (i < req->bufnum); i++, sg++) { int count = sg->length; + to = ((char *)rd->area + (sg->block * rd->block_size)); if (count > remains) count = remains; memcpy(to, sg->buffer, count); @@ -123,10 +171,10 @@ ramdisk_ioctl(dev_t dev, uint32_t req, void *argp) { switch (req) { - case BLKIO_REQUEST: + case RTEMS_BLKIO_REQUEST: { rtems_device_minor_number minor; - blkdev_request *r = argp; + rtems_blkdev_request *r = argp; struct ramdisk *rd; minor = rtems_filesystem_dev_minor_t(dev); @@ -140,10 +188,10 @@ ramdisk_ioctl(dev_t dev, uint32_t req, void *argp) switch (r->req) { - case BLKDEV_REQ_READ: + case RTEMS_BLKDEV_REQ_READ: return ramdisk_read(rd, r); - case BLKDEV_REQ_WRITE: + case RTEMS_BLKDEV_REQ_WRITE: return ramdisk_write(rd, r); default: @@ -188,7 +236,9 @@ ramdisk_initialize( r = ramdisk = calloc(rtems_ramdisk_configuration_size, sizeof(struct ramdisk)); - +#if RTEMS_RAMDISK_TRACE + r->info_level = 1; +#endif for (i = 0; i < rtems_ramdisk_configuration_size; i++, c++, r++) { dev_t dev = rtems_filesystem_make_dev_t(major, i); diff --git a/cpukit/libfs/src/dosfs/fat.c b/cpukit/libfs/src/dosfs/fat.c index 65bf30e624..4dd61afdd9 100644 --- a/cpukit/libfs/src/dosfs/fat.c +++ b/cpukit/libfs/src/dosfs/fat.c @@ -26,6 +26,137 @@ #include "fat.h" #include "fat_fat_operations.h" +int +fat_buf_access(fat_fs_info_t *fs_info, uint32_t blk, int op_type, + rtems_bdbuf_buffer **buf) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + uint8_t i; + rtems_boolean sec_of_fat; + + + if (fs_info->c.state == FAT_CACHE_EMPTY) + { + if (op_type == FAT_OP_TYPE_READ) + sc = rtems_bdbuf_read(fs_info->vol.dev, blk, &fs_info->c.buf); + else + sc = rtems_bdbuf_get(fs_info->vol.dev, blk, &fs_info->c.buf); + if (sc != RTEMS_SUCCESSFUL) + rtems_set_errno_and_return_minus_one(EIO); + fs_info->c.blk_num = blk; + fs_info->c.modified = 0; + fs_info->c.state = FAT_CACHE_ACTUAL; + } + + sec_of_fat = ((fs_info->c.blk_num >= fs_info->vol.fat_loc) && + (fs_info->c.blk_num < fs_info->vol.rdir_loc)); + + if (fs_info->c.blk_num != blk) + { + if (fs_info->c.modified) + { + if (sec_of_fat && !fs_info->vol.mirror) + memcpy(fs_info->sec_buf, fs_info->c.buf->buffer, + fs_info->vol.bps); + + sc = rtems_bdbuf_release_modified(fs_info->c.buf); + fs_info->c.state = FAT_CACHE_EMPTY; + fs_info->c.modified = 0; + if (sc != RTEMS_SUCCESSFUL) + rtems_set_errno_and_return_minus_one(EIO); + + if (sec_of_fat && !fs_info->vol.mirror) + { + rtems_bdbuf_buffer *b; + + for (i = 1; i < fs_info->vol.fats; i++) + { + sc = rtems_bdbuf_get(fs_info->vol.dev, + fs_info->c.blk_num + + fs_info->vol.fat_length * i, + &b); + if ( sc != RTEMS_SUCCESSFUL) + rtems_set_errno_and_return_minus_one(ENOMEM); + memcpy(b->buffer, fs_info->sec_buf, fs_info->vol.bps); + sc = rtems_bdbuf_release_modified(b); + if ( sc != RTEMS_SUCCESSFUL) + rtems_set_errno_and_return_minus_one(ENOMEM); + } + } + } + else + { + sc = rtems_bdbuf_release(fs_info->c.buf); + fs_info->c.state = FAT_CACHE_EMPTY; + if (sc != RTEMS_SUCCESSFUL) + rtems_set_errno_and_return_minus_one(EIO); + + } + if (op_type == FAT_OP_TYPE_READ) + sc = rtems_bdbuf_read(fs_info->vol.dev, blk, &fs_info->c.buf); + else + sc = rtems_bdbuf_get(fs_info->vol.dev, blk, &fs_info->c.buf); + if (sc != RTEMS_SUCCESSFUL) + rtems_set_errno_and_return_minus_one(EIO); + fs_info->c.blk_num = blk; + fs_info->c.state = FAT_CACHE_ACTUAL; + } + *buf = fs_info->c.buf; + return RC_OK; +} + +int +fat_buf_release(fat_fs_info_t *fs_info) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + uint8_t i; + rtems_boolean sec_of_fat; + + if (fs_info->c.state == FAT_CACHE_EMPTY) + return RC_OK; + + sec_of_fat = ((fs_info->c.blk_num >= fs_info->vol.fat_loc) && + (fs_info->c.blk_num < fs_info->vol.rdir_loc)); + + if (fs_info->c.modified) + { + if (sec_of_fat && !fs_info->vol.mirror) + memcpy(fs_info->sec_buf, fs_info->c.buf->buffer, fs_info->vol.bps); + + sc = rtems_bdbuf_release_modified(fs_info->c.buf); + if (sc != RTEMS_SUCCESSFUL) + rtems_set_errno_and_return_minus_one(EIO); + fs_info->c.modified = 0; + + if (sec_of_fat && !fs_info->vol.mirror) + { + rtems_bdbuf_buffer *b; + + for (i = 1; i < fs_info->vol.fats; i++) + { + sc = rtems_bdbuf_get(fs_info->vol.dev, + fs_info->c.blk_num + + fs_info->vol.fat_length * i, + &b); + if ( sc != RTEMS_SUCCESSFUL) + rtems_set_errno_and_return_minus_one(ENOMEM); + memcpy(b->buffer, fs_info->sec_buf, fs_info->vol.bps); + sc = rtems_bdbuf_release_modified(b); + if ( sc != RTEMS_SUCCESSFUL) + rtems_set_errno_and_return_minus_one(ENOMEM); + } + } + } + else + { + sc = rtems_bdbuf_release(fs_info->c.buf); + if (sc != RTEMS_SUCCESSFUL) + rtems_set_errno_and_return_minus_one(EIO); + } + fs_info->c.state = FAT_CACHE_EMPTY; + return RC_OK; +} + /* _fat_block_read -- * This function reads 'count' bytes from device filesystem is mounted on, * starts at 'start+offset' position where 'start' computed in sectors @@ -57,7 +188,7 @@ _fat_block_read( ssize_t cmpltd = 0; uint32_t blk = start; uint32_t ofs = offset; - bdbuf_buffer *block = NULL; + rtems_bdbuf_buffer *block = NULL; uint32_t c = 0; while (count > 0) @@ -102,13 +233,13 @@ _fat_block_write( uint32_t count, const void *buff) { - int rc = RC_OK; - fat_fs_info_t *fs_info = mt_entry->fs_info; - ssize_t cmpltd = 0; - uint32_t blk = start; - uint32_t ofs = offset; - bdbuf_buffer *block = NULL; - uint32_t c = 0; + int rc = RC_OK; + fat_fs_info_t *fs_info = mt_entry->fs_info; + ssize_t cmpltd = 0; + uint32_t blk = start; + uint32_t ofs = offset; + rtems_bdbuf_buffer *block = NULL; + uint32_t c = 0; while(count > 0) { @@ -133,9 +264,6 @@ _fat_block_write( return cmpltd; } - - - /* fat_cluster_read -- * wrapper for reading a whole cluster at once * @@ -215,7 +343,7 @@ fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry) ssize_t ret = 0; struct stat stat_buf; int i = 0; - bdbuf_buffer *block = NULL; + rtems_bdbuf_buffer *block = NULL; rc = stat(mt_entry->dev, &stat_buf); if (rc == -1) @@ -223,12 +351,12 @@ fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry) /* rtmes feature: no block devices, all are character devices */ if (!S_ISCHR(stat_buf.st_mode)) - set_errno_and_return_minus_one(ENOTBLK); + rtems_set_errno_and_return_minus_one(ENOTBLK); - /* check that device is registred as block device and lock it */ - vol->dd = rtems_disk_lookup(stat_buf.st_dev); + /* check that device is registred as block device and lock it */ + vol->dd = rtems_disk_obtain(stat_buf.st_dev); if (vol->dd == NULL) - set_errno_and_return_minus_one(ENOTBLK); + rtems_set_errno_and_return_minus_one(ENOTBLK); vol->dev = stat_buf.st_dev; @@ -238,7 +366,7 @@ fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry) if (sc != RTEMS_SUCCESSFUL) { rtems_disk_release(vol->dd); - set_errno_and_return_minus_one( EIO); + rtems_set_errno_and_return_minus_one( EIO); } memcpy( boot_rec, block->buffer, FAT_MAX_BPB_SIZE); @@ -247,7 +375,7 @@ fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry) if (sc != RTEMS_SUCCESSFUL) { rtems_disk_release(vol->dd); - set_errno_and_return_minus_one( EIO); + rtems_set_errno_and_return_minus_one( EIO ); } /* Evaluate boot record */ @@ -259,7 +387,7 @@ fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry) (vol->bps != 4096)) { rtems_disk_release(vol->dd); - set_errno_and_return_minus_one( EINVAL ); + rtems_set_errno_and_return_minus_one( EINVAL ); } for (vol->sec_mul = 0, i = (vol->bps >> FAT_SECTOR512_BITS); (i & 1) == 0; @@ -275,7 +403,7 @@ fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry) if (vol->spc == 0) { rtems_disk_release(vol->dd); - set_errno_and_return_minus_one(EINVAL); + rtems_set_errno_and_return_minus_one(EINVAL); } for (vol->spc_log2 = 0, i = vol->spc; (i & 1) == 0; @@ -287,7 +415,7 @@ fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry) if ((vol->bpc = vol->bps << vol->spc_log2) > MS_BYTES_PER_CLUSTER_LIMIT) { rtems_disk_release(vol->dd); - set_errno_and_return_minus_one(EINVAL); + rtems_set_errno_and_return_minus_one(EINVAL); } for (vol->bpc_log2 = 0, i = vol->bpc; (i & 1) == 0; @@ -361,7 +489,7 @@ fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry) if( vol->info_sec == 0 ) { rtems_disk_release(vol->dd); - set_errno_and_return_minus_one( EINVAL ); + rtems_set_errno_and_return_minus_one( EINVAL ); } else { @@ -377,7 +505,7 @@ fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry) FAT_FSINFO_LEAD_SIGNATURE_VALUE) { rtems_disk_release(vol->dd); - set_errno_and_return_minus_one( EINVAL ); + rtems_set_errno_and_return_minus_one( EINVAL ); } else { @@ -412,25 +540,25 @@ fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry) vol->afat_loc = vol->fat_loc + vol->fat_length * vol->afat; /* set up collection of fat-files fd */ - fs_info->vhash = calloc(FAT_HASH_SIZE, sizeof(Chain_Control)); + fs_info->vhash = calloc(FAT_HASH_SIZE, sizeof(rtems_chain_control)); if ( fs_info->vhash == NULL ) { rtems_disk_release(vol->dd); - set_errno_and_return_minus_one( ENOMEM ); + rtems_set_errno_and_return_minus_one( ENOMEM ); } for (i = 0; i < FAT_HASH_SIZE; i++) - _Chain_Initialize_empty(fs_info->vhash + i); + rtems_chain_initialize_empty(fs_info->vhash + i); - fs_info->rhash = calloc(FAT_HASH_SIZE, sizeof(Chain_Control)); + fs_info->rhash = calloc(FAT_HASH_SIZE, sizeof(rtems_chain_control)); if ( fs_info->rhash == NULL ) { rtems_disk_release(vol->dd); free(fs_info->vhash); - set_errno_and_return_minus_one( ENOMEM ); + rtems_set_errno_and_return_minus_one( ENOMEM ); } for (i = 0; i < FAT_HASH_SIZE; i++) - _Chain_Initialize_empty(fs_info->rhash + i); + rtems_chain_initialize_empty(fs_info->rhash + i); fs_info->uino_pool_size = FAT_UINO_POOL_INIT_SIZE; fs_info->uino_base = (vol->tot_secs << vol->sec_mul) << 4; @@ -441,7 +569,7 @@ fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry) rtems_disk_release(vol->dd); free(fs_info->vhash); free(fs_info->rhash); - set_errno_and_return_minus_one( ENOMEM ); + rtems_set_errno_and_return_minus_one( ENOMEM ); } fs_info->sec_buf = (uint8_t *)calloc(vol->bps, sizeof(uint8_t)); if (fs_info->sec_buf == NULL) @@ -450,7 +578,7 @@ fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry) free(fs_info->vhash); free(fs_info->rhash); free(fs_info->uino); - set_errno_and_return_minus_one( ENOMEM ); + rtems_set_errno_and_return_minus_one( ENOMEM ); } return RC_OK; @@ -488,19 +616,19 @@ fat_shutdown_drive(rtems_filesystem_mount_table_entry_t *mt_entry) for (i = 0; i < FAT_HASH_SIZE; i++) { - Chain_Node *node = NULL; - Chain_Control *the_chain = fs_info->vhash + i; + rtems_chain_node *node = NULL; + rtems_chain_control *the_chain = fs_info->vhash + i; - while ( (node = _Chain_Get(the_chain)) != NULL ) + while ( (node = rtems_chain_get(the_chain)) != NULL ) free(node); } for (i = 0; i < FAT_HASH_SIZE; i++) { - Chain_Node *node = NULL; - Chain_Control *the_chain = fs_info->rhash + i; + rtems_chain_node *node = NULL; + rtems_chain_control *the_chain = fs_info->rhash + i; - while ( (node = _Chain_Get(the_chain)) != NULL ) + while ( (node = rtems_chain_get(the_chain)) != NULL ) free(node); } @@ -541,7 +669,7 @@ fat_init_clusters_chain( buf = calloc(fs_info->vol.bpc, sizeof(char)); if ( buf == NULL ) - set_errno_and_return_minus_one( EIO ); + rtems_set_errno_and_return_minus_one( EIO ); while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val) { diff --git a/cpukit/libfs/src/dosfs/fat.h b/cpukit/libfs/src/dosfs/fat.h index 3a951b114e..244e57f087 100644 --- a/cpukit/libfs/src/dosfs/fat.h +++ b/cpukit/libfs/src/dosfs/fat.h @@ -25,11 +25,6 @@ extern "C" { #include <rtems/seterr.h> -/* XXX: temporary hack :(( */ -#ifndef set_errno_and_return_minus_one -#define set_errno_and_return_minus_one rtems_set_errno_and_return_minus_one -#endif /* set_errno_and_return_minus_one */ - #include <rtems/score/cpu.h> #include <errno.h> #include <rtems/bdbuf.h> @@ -297,45 +292,45 @@ extern "C" { */ typedef struct fat_vol_s { - uint16_t bps; /* bytes per sector */ - uint8_t sec_log2; /* log2 of bps */ - uint8_t sec_mul; /* log2 of 512bts sectors number per sector */ - uint8_t spc; /* sectors per cluster */ - uint8_t spc_log2; /* log2 of spc */ - uint16_t bpc; /* bytes per cluster */ - uint8_t bpc_log2; /* log2 of bytes per cluster */ - uint8_t fats; /* number of FATs */ - uint8_t type; /* FAT type */ - uint32_t mask; - uint32_t eoc_val; - uint16_t fat_loc; /* FAT start */ - uint32_t fat_length; /* sectors per FAT */ - uint32_t rdir_loc; /* root directory start */ - uint16_t rdir_entrs; /* files per root directory */ - uint32_t rdir_secs; /* sectors per root directory */ - uint32_t rdir_size; /* root directory size in bytes */ - uint32_t tot_secs; /* total count of sectors */ - uint32_t data_fsec; /* first data sector */ - uint32_t data_cls; /* count of data clusters */ - uint32_t rdir_cl; /* first cluster of the root directory */ - uint16_t info_sec; /* FSInfo Sector Structure location */ - uint32_t free_cls; /* last known free clusters count */ - uint32_t next_cl; /* next free cluster number */ - uint8_t mirror; /* mirroring enabla/disable */ - uint32_t afat_loc; /* active FAT location */ - uint8_t afat; /* the number of active FAT */ - dev_t dev; /* device ID */ - disk_device *dd; /* disk device (see libblock) */ - void *private_data; /* reserved */ + uint16_t bps; /* bytes per sector */ + uint8_t sec_log2; /* log2 of bps */ + uint8_t sec_mul; /* log2 of 512bts sectors number per sector */ + uint8_t spc; /* sectors per cluster */ + uint8_t spc_log2; /* log2 of spc */ + uint16_t bpc; /* bytes per cluster */ + uint8_t bpc_log2; /* log2 of bytes per cluster */ + uint8_t fats; /* number of FATs */ + uint8_t type; /* FAT type */ + uint32_t mask; + uint32_t eoc_val; + uint16_t fat_loc; /* FAT start */ + uint32_t fat_length; /* sectors per FAT */ + uint32_t rdir_loc; /* root directory start */ + uint16_t rdir_entrs; /* files per root directory */ + uint32_t rdir_secs; /* sectors per root directory */ + uint32_t rdir_size; /* root directory size in bytes */ + uint32_t tot_secs; /* total count of sectors */ + uint32_t data_fsec; /* first data sector */ + uint32_t data_cls; /* count of data clusters */ + uint32_t rdir_cl; /* first cluster of the root directory */ + uint16_t info_sec; /* FSInfo Sector Structure location */ + uint32_t free_cls; /* last known free clusters count */ + uint32_t next_cl; /* next free cluster number */ + uint8_t mirror; /* mirroring enabla/disable */ + uint32_t afat_loc; /* active FAT location */ + uint8_t afat; /* the number of active FAT */ + dev_t dev; /* device ID */ + rtems_disk_device *dd; /* disk device (see libblock) */ + void *private_data; /* reserved */ } fat_vol_t; typedef struct fat_cache_s { - uint32_t blk_num; - rtems_boolean modified; - uint8_t state; - bdbuf_buffer *buf; + uint32_t blk_num; + rtems_boolean modified; + uint8_t state; + rtems_bdbuf_buffer *buf; } fat_cache_t; /* @@ -344,15 +339,15 @@ typedef struct fat_cache_s */ typedef struct fat_fs_info_s { - fat_vol_t vol; /* volume descriptor */ - Chain_Control *vhash; /* "vhash" of fat-file descriptors */ - Chain_Control *rhash; /* "rhash" of fat-file descriptors */ - char *uino; /* array of unique ino numbers */ - uint32_t index; - uint32_t uino_pool_size; /* size */ - uint32_t uino_base; - fat_cache_t c; /* cache */ - uint8_t *sec_buf; /* just placeholder for anything */ + fat_vol_t vol; /* volume descriptor */ + rtems_chain_control *vhash; /* "vhash" of fat-file descriptors */ + rtems_chain_control *rhash; /* "rhash" of fat-file descriptors */ + char *uino; /* array of unique ino numbers */ + uint32_t index; + uint32_t uino_pool_size; /* size */ + uint32_t uino_base; + fat_cache_t c; /* cache */ + uint8_t *sec_buf; /* just placeholder for anything */ } fat_fs_info_t; /* @@ -415,145 +410,18 @@ fat_cluster_num_to_sector512_num( fs_info->vol.sec_mul); } -static inline int -fat_buf_access(fat_fs_info_t *fs_info, uint32_t blk, int op_type, - bdbuf_buffer **buf) -{ - rtems_status_code sc = RTEMS_SUCCESSFUL; - uint8_t i; - rtems_boolean sec_of_fat; - - - if (fs_info->c.state == FAT_CACHE_EMPTY) - { - if (op_type == FAT_OP_TYPE_READ) - sc = rtems_bdbuf_read(fs_info->vol.dev, blk, &fs_info->c.buf); - else - sc = rtems_bdbuf_get(fs_info->vol.dev, blk, &fs_info->c.buf); - if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); - fs_info->c.blk_num = blk; - fs_info->c.modified = 0; - fs_info->c.state = FAT_CACHE_ACTUAL; - } - - sec_of_fat = ((fs_info->c.blk_num >= fs_info->vol.fat_loc) && - (fs_info->c.blk_num < fs_info->vol.rdir_loc)); - - if (fs_info->c.blk_num != blk) - { - if (fs_info->c.modified) - { - if (sec_of_fat && !fs_info->vol.mirror) - memcpy(fs_info->sec_buf, fs_info->c.buf->buffer, - fs_info->vol.bps); - - sc = rtems_bdbuf_release_modified(fs_info->c.buf); - fs_info->c.state = FAT_CACHE_EMPTY; - fs_info->c.modified = 0; - if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); - - if (sec_of_fat && !fs_info->vol.mirror) - { - bdbuf_buffer *b; - - for (i = 1; i < fs_info->vol.fats; i++) - { - sc = rtems_bdbuf_get(fs_info->vol.dev, - fs_info->c.blk_num + - fs_info->vol.fat_length * i, - &b); - if ( sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(ENOMEM); - memcpy(b->buffer, fs_info->sec_buf, fs_info->vol.bps); - sc = rtems_bdbuf_release_modified(b); - if ( sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(ENOMEM); - } - } - } - else - { - sc = rtems_bdbuf_release(fs_info->c.buf); - fs_info->c.state = FAT_CACHE_EMPTY; - if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); - - } - if (op_type == FAT_OP_TYPE_READ) - sc = rtems_bdbuf_read(fs_info->vol.dev, blk, &fs_info->c.buf); - else - sc = rtems_bdbuf_get(fs_info->vol.dev, blk, &fs_info->c.buf); - if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); - fs_info->c.blk_num = blk; - fs_info->c.state = FAT_CACHE_ACTUAL; - } - *buf = fs_info->c.buf; - return RC_OK; -} - - -static inline int -fat_buf_release(fat_fs_info_t *fs_info) -{ - rtems_status_code sc = RTEMS_SUCCESSFUL; - uint8_t i; - rtems_boolean sec_of_fat; - - if (fs_info->c.state == FAT_CACHE_EMPTY) - return RC_OK; - - sec_of_fat = ((fs_info->c.blk_num >= fs_info->vol.fat_loc) && - (fs_info->c.blk_num < fs_info->vol.rdir_loc)); - - if (fs_info->c.modified) - { - if (sec_of_fat && !fs_info->vol.mirror) - memcpy(fs_info->sec_buf, fs_info->c.buf->buffer, fs_info->vol.bps); - - sc = rtems_bdbuf_release_modified(fs_info->c.buf); - if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); - fs_info->c.modified = 0; - - if (sec_of_fat && !fs_info->vol.mirror) - { - bdbuf_buffer *b; - - for (i = 1; i < fs_info->vol.fats; i++) - { - sc = rtems_bdbuf_get(fs_info->vol.dev, - fs_info->c.blk_num + - fs_info->vol.fat_length * i, - &b); - if ( sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(ENOMEM); - memcpy(b->buffer, fs_info->sec_buf, fs_info->vol.bps); - sc = rtems_bdbuf_release_modified(b); - if ( sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(ENOMEM); - } - } - } - else - { - sc = rtems_bdbuf_release(fs_info->c.buf); - if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); - } - fs_info->c.state = FAT_CACHE_EMPTY; - return RC_OK; -} - static inline void fat_buf_mark_modified(fat_fs_info_t *fs_info) { fs_info->c.modified = TRUE; } +int +fat_buf_access(fat_fs_info_t *fs_info, uint32_t blk, int op_type, + rtems_bdbuf_buffer **buf); +int +fat_buf_release(fat_fs_info_t *fs_info); ssize_t _fat_block_read(rtems_filesystem_mount_table_entry_t *mt_entry, diff --git a/cpukit/libfs/src/dosfs/fat_fat_operations.c b/cpukit/libfs/src/dosfs/fat_fat_operations.c index 0e6411f799..9d677dc3db 100644 --- a/cpukit/libfs/src/dosfs/fat_fat_operations.c +++ b/cpukit/libfs/src/dosfs/fat_fat_operations.c @@ -229,13 +229,13 @@ fat_get_fat_cluster( { int rc = RC_OK; register fat_fs_info_t *fs_info = mt_entry->fs_info; - bdbuf_buffer *block0 = NULL; + rtems_bdbuf_buffer *block0 = NULL; uint32_t sec = 0; uint32_t ofs = 0; /* sanity check */ if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) ) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) + fs_info->vol.afat_loc; @@ -284,7 +284,7 @@ fat_get_fat_cluster( break; default: - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); break; } @@ -311,17 +311,17 @@ fat_set_fat_cluster( uint32_t in_val ) { - int rc = RC_OK; - fat_fs_info_t *fs_info = mt_entry->fs_info; - uint32_t sec = 0; - uint32_t ofs = 0; - uint16_t fat16_clv = 0; - uint32_t fat32_clv = 0; - bdbuf_buffer *block0 = NULL; + int rc = RC_OK; + fat_fs_info_t *fs_info = mt_entry->fs_info; + uint32_t sec = 0; + uint32_t ofs = 0; + uint16_t fat16_clv = 0; + uint32_t fat32_clv = 0; + rtems_bdbuf_buffer *block0 = NULL; /* sanity check */ if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) ) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) + fs_info->vol.afat_loc; @@ -428,7 +428,7 @@ fat_set_fat_cluster( break; default: - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); break; } diff --git a/cpukit/libfs/src/dosfs/fat_file.c b/cpukit/libfs/src/dosfs/fat_file.c index 69e1d9a7e0..6bf482e927 100644 --- a/cpukit/libfs/src/dosfs/fat_file.c +++ b/cpukit/libfs/src/dosfs/fat_file.c @@ -10,6 +10,8 @@ * */ +#define MSDOS_TRACE 1 + #if HAVE_CONFIG_H #include "config.h" #endif @@ -112,7 +114,7 @@ fat_file_open( lfat_fd = (*fat_fd) = (fat_file_fd_t*)malloc(sizeof(fat_file_fd_t)); if ( lfat_fd == NULL ) - set_errno_and_return_minus_one( ENOMEM ); + rtems_set_errno_and_return_minus_one( ENOMEM ); lfat_fd->links_num = 1; lfat_fd->flags &= ~FAT_FILE_REMOVED; @@ -131,7 +133,7 @@ fat_file_open( * XXX: kernel resource is unsufficient, but not the memory, * but there is no suitable errno :( */ - set_errno_and_return_minus_one( ENOMEM ); + rtems_set_errno_and_return_minus_one( ENOMEM ); } } _hash_insert(fs_info->vhash, key, lfat_fd->ino, lfat_fd); @@ -383,11 +385,11 @@ fat_file_write( return cmpltd; if ( start > fat_fd->fat_file_size ) - set_errno_and_return_minus_one( EIO ); + rtems_set_errno_and_return_minus_one( EIO ); if ((count > fat_fd->size_limit) || (start > fat_fd->size_limit - count)) - set_errno_and_return_minus_one( EIO ); + rtems_set_errno_and_return_minus_one( EIO ); rc = fat_file_extend(mt_entry, fat_fd, start + count, &c); if (rc != RC_OK) @@ -493,7 +495,7 @@ fat_file_extend( if ((FAT_FD_OF_ROOT_DIR(fat_fd)) && (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16))) - set_errno_and_return_minus_one( ENOSPC ); + rtems_set_errno_and_return_minus_one( ENOSPC ); bytes_remain = (fs_info->vol.bpc - (fat_fd->fat_file_size & (fs_info->vol.bpc - 1))) & @@ -525,7 +527,7 @@ fat_file_extend( /* this means that no space left on device */ if ((cls_added == 0) && (bytes_remain == 0)) - set_errno_and_return_minus_one(ENOSPC); + rtems_set_errno_and_return_minus_one(ENOSPC); /* check wether we satisfied request for 'cls2add' clusters */ if (cls2add != cls_added) @@ -687,7 +689,7 @@ fat_file_ioctl( /* sanity check */ if ( pos >= fat_fd->fat_file_size ) - set_errno_and_return_minus_one( EIO ); + rtems_set_errno_and_return_minus_one( EIO ); if ((FAT_FD_OF_ROOT_DIR(fat_fd)) && (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16))) @@ -759,13 +761,13 @@ fat_file_datasync( fat_file_fd_t *fat_fd ) { - int rc = RC_OK; - rtems_status_code sc = RTEMS_SUCCESSFUL; - fat_fs_info_t *fs_info = mt_entry->fs_info; - uint32_t cur_cln = fat_fd->cln; - bdbuf_buffer *block = NULL; - uint32_t sec = 0; - uint32_t i = 0; + int rc = RC_OK; + rtems_status_code sc = RTEMS_SUCCESSFUL; + fat_fs_info_t *fs_info = mt_entry->fs_info; + uint32_t cur_cln = fat_fd->cln; + rtems_bdbuf_buffer *block = NULL; + uint32_t sec = 0; + uint32_t i = 0; if (fat_fd->fat_file_size == 0) return RC_OK; @@ -788,11 +790,11 @@ fat_file_datasync( /* ... sync it */ sc = rtems_bdbuf_read(fs_info->vol.dev, (sec + i), &block); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one( EIO ); + rtems_set_errno_and_return_minus_one( EIO ); sc = rtems_bdbuf_sync(block); if ( sc != RTEMS_SUCCESSFUL ) - set_errno_and_return_minus_one( EIO ); + rtems_set_errno_and_return_minus_one( EIO ); } rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln); @@ -947,9 +949,7 @@ fat_file_lseek( ) { int rc = RC_OK; -/* - assert(fat_fd->fat_file_size); - */ + if (file_cln == fat_fd->map.file_cln) *disk_cln = fat_fd->map.disk_cln; else diff --git a/cpukit/libfs/src/dosfs/msdos_create.c b/cpukit/libfs/src/dosfs/msdos_create.c index 8c238d396c..c790dd740f 100644 --- a/cpukit/libfs/src/dosfs/msdos_create.c +++ b/cpukit/libfs/src/dosfs/msdos_create.c @@ -129,9 +129,9 @@ msdos_creat_node( *MSDOS_DIR_FILE_SIZE(new_node) =*MSDOS_DIR_FILE_SIZE(link_node); *MSDOS_DIR_FIRST_CLUSTER_LOW(new_node) = - *MSDOS_DIR_FIRST_CLUSTER_LOW(link_node); + *MSDOS_DIR_FIRST_CLUSTER_LOW(link_node); *MSDOS_DIR_FIRST_CLUSTER_HI(new_node) = - *MSDOS_DIR_FIRST_CLUSTER_HI(link_node); + *MSDOS_DIR_FIRST_CLUSTER_HI(link_node); /* * set "archive bit" due to changes */ @@ -302,14 +302,14 @@ msdos_file_link(rtems_filesystem_location_info_t *to_loc, * check spelling and format new node name */ if (MSDOS_NAME != msdos_get_token(token, new_name, &len)) { - set_errno_and_return_minus_one(ENAMETOOLONG); + rtems_set_errno_and_return_minus_one(ENAMETOOLONG); } /* * verify, that the existing node can be linked to * check that nodes are in same FS/volume? */ if (to_loc->mt_entry->fs_info != par_loc->mt_entry->fs_info) { - set_errno_and_return_minus_one(EXDEV); + rtems_set_errno_and_return_minus_one(EXDEV); } /* * lock volume @@ -317,7 +317,7 @@ msdos_file_link(rtems_filesystem_location_info_t *to_loc, sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); /* @@ -334,7 +334,7 @@ msdos_file_link(rtems_filesystem_location_info_t *to_loc, to_fat_fd->cln = FAT_EOF; rc = msdos_set_first_cluster_num(to_loc->mt_entry, to_fat_fd); if (rc == RC_OK) { - rc = msdos_set_file_size(par_loc->mt_entry, to_fat_fd); + rc = msdos_set_file_size(par_loc->mt_entry, to_fat_fd); } } /* diff --git a/cpukit/libfs/src/dosfs/msdos_dir.c b/cpukit/libfs/src/dosfs/msdos_dir.c index f76fa147a3..c2fb72aedd 100644 --- a/cpukit/libfs/src/dosfs/msdos_dir.c +++ b/cpukit/libfs/src/dosfs/msdos_dir.c @@ -56,7 +56,7 @@ msdos_dir_open(rtems_libio_t *iop, const char *pathname, uint32_t flag, sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one( EIO ); + rtems_set_errno_and_return_minus_one( EIO ); rc = fat_file_reopen(fat_fd); if (rc != RC_OK) @@ -91,7 +91,7 @@ msdos_dir_close(rtems_libio_t *iop) sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one( EIO ); + rtems_set_errno_and_return_minus_one( EIO ); rc = fat_file_close(iop->pathinfo.mt_entry, fat_fd); if (rc != RC_OK) @@ -233,7 +233,7 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count) sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); while (count > 0) { @@ -248,7 +248,7 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count) if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) { rtems_semaphore_release(fs_info->vol_sema); - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); } for (i = 0; i < ret; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) @@ -377,7 +377,7 @@ msdos_dir_lseek(rtems_libio_t *iop, off_t offset, int whence) */ case SEEK_END: default: - set_errno_and_return_minus_one( EINVAL ); + rtems_set_errno_and_return_minus_one( EINVAL ); break; } return RC_OK; @@ -416,7 +416,7 @@ msdos_dir_stat( sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); buf->st_dev = fs_info->fat.vol.dev; buf->st_ino = fat_fd->ino; @@ -463,7 +463,7 @@ msdos_dir_sync(rtems_libio_t *iop) sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd); @@ -495,7 +495,7 @@ msdos_dir_rmnod(rtems_filesystem_location_info_t *pathloc) sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); /* * We deny attemp to delete open directory (if directory is current @@ -504,7 +504,7 @@ msdos_dir_rmnod(rtems_filesystem_location_info_t *pathloc) if (fat_fd->links_num > 1) { rtems_semaphore_release(fs_info->vol_sema); - set_errno_and_return_minus_one(EBUSY); + rtems_set_errno_and_return_minus_one(EBUSY); } /* @@ -520,7 +520,7 @@ msdos_dir_rmnod(rtems_filesystem_location_info_t *pathloc) if (!is_empty) { rtems_semaphore_release(fs_info->vol_sema); - set_errno_and_return_minus_one(ENOTEMPTY); + rtems_set_errno_and_return_minus_one(ENOTEMPTY); } /* @@ -529,7 +529,7 @@ msdos_dir_rmnod(rtems_filesystem_location_info_t *pathloc) if (pathloc->mt_entry->mt_fs_root.node_access == pathloc->node_access) { rtems_semaphore_release(fs_info->vol_sema); - set_errno_and_return_minus_one(EBUSY); + rtems_set_errno_and_return_minus_one(EBUSY); } /* diff --git a/cpukit/libfs/src/dosfs/msdos_eval.c b/cpukit/libfs/src/dosfs/msdos_eval.c index 3e620b96a8..a1a9b4401a 100644 --- a/cpukit/libfs/src/dosfs/msdos_eval.c +++ b/cpukit/libfs/src/dosfs/msdos_eval.c @@ -89,7 +89,7 @@ msdos_eval_path( sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); if (!pathloc->node_access) { @@ -271,7 +271,7 @@ msdos_eval4make( sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); if (!pathloc->node_access) { diff --git a/cpukit/libfs/src/dosfs/msdos_file.c b/cpukit/libfs/src/dosfs/msdos_file.c index 95c8a8d1fa..c8293d5b24 100644 --- a/cpukit/libfs/src/dosfs/msdos_file.c +++ b/cpukit/libfs/src/dosfs/msdos_file.c @@ -53,7 +53,7 @@ msdos_file_open(rtems_libio_t *iop, const char *pathname, uint32_t flag, sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); rc = fat_file_reopen(fat_fd); if (rc != RC_OK) @@ -94,7 +94,7 @@ msdos_file_close(rtems_libio_t *iop) sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); /* * if fat-file descriptor is not marked as "removed", synchronize @@ -154,7 +154,7 @@ msdos_file_read(rtems_libio_t *iop, void *buffer, size_t count) sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); ret = fat_file_read(iop->pathinfo.mt_entry, fat_fd, iop->offset, count, buffer); @@ -187,7 +187,7 @@ msdos_file_write(rtems_libio_t *iop,const void *buffer, size_t count) sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); ret = fat_file_write(iop->pathinfo.mt_entry, fat_fd, iop->offset, count, buffer); @@ -235,7 +235,7 @@ msdos_file_lseek(rtems_libio_t *iop, off_t offset, int whence) sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); rc = fat_file_extend(iop->pathinfo.mt_entry, fat_fd, iop->offset, &real_size); @@ -276,7 +276,7 @@ msdos_file_stat( sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); buf->st_dev = fs_info->fat.vol.dev; buf->st_ino = fat_fd->ino; @@ -315,7 +315,7 @@ msdos_file_ftruncate(rtems_libio_t *iop, off_t length) sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); rc = fat_file_truncate(iop->pathinfo.mt_entry, fat_fd, length); if (rc != RC_OK) @@ -356,7 +356,7 @@ msdos_file_sync(rtems_libio_t *iop) sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); /* synchronize file data */ rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd); @@ -416,7 +416,7 @@ msdos_file_datasync(rtems_libio_t *iop) sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); /* synchronize file data */ rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd); @@ -466,7 +466,7 @@ msdos_file_rmnod(rtems_filesystem_location_info_t *pathloc) sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); /* mark file removed */ rc = msdos_set_first_char4file_name(pathloc->mt_entry, fat_fd->info_cln, diff --git a/cpukit/libfs/src/dosfs/msdos_format.c b/cpukit/libfs/src/dosfs/msdos_format.c index ba3e1042d8..bbd4689dc0 100644 --- a/cpukit/libfs/src/dosfs/msdos_format.c +++ b/cpukit/libfs/src/dosfs/msdos_format.c @@ -277,7 +277,7 @@ static int msdos_format_eval_sectors_per_cluster } while (!finished); if (ret_val != 0) { - set_errno_and_return_minus_one(ret_val); + rtems_set_errno_and_return_minus_one(ret_val); } else { *sectors_per_cluster_adj = sectors_per_cluster; @@ -298,9 +298,9 @@ static int msdos_format_determine_fmt_params +---------------------------------------------------------------------------+ | Input Parameters: | \*-------------------------------------------------------------------------*/ - const disk_device *dd, /* disk device structure */ + const rtems_disk_device *dd, /* disk device structure */ const msdos_format_request_param_t *rqdata, /* requested fmt parameters */ - msdos_format_param_t *fmt_params/* computed fmt parameters */ + msdos_format_param_t *fmt_params/* computed fmt parameters */ ) /*-------------------------------------------------------------------------*\ | Return Value: | @@ -613,7 +613,7 @@ static int msdos_format_determine_fmt_params * Phuuu.... That's it. */ if (ret_val != 0) { - set_errno_and_return_minus_one(ret_val); + rtems_set_errno_and_return_minus_one(ret_val); } else { return 0; @@ -791,13 +791,13 @@ int msdos_format | 0, if success, -1 and errno if failed | \*=========================================================================*/ { - char tmp_sec[FAT_TOTAL_MBR_SIZE]; - int rc; - disk_device *dd = NULL; - struct stat stat_buf; - int ret_val = 0; - int fd = -1; - int i; + char tmp_sec[FAT_TOTAL_MBR_SIZE]; + int rc; + rtems_disk_device *dd = NULL; + struct stat stat_buf; + int ret_val = 0; + int fd = -1; + int i; msdos_format_param_t fmt_params; /* @@ -817,7 +817,7 @@ int msdos_format /* check that device is registered as block device and lock it */ if (ret_val == 0) { - dd = rtems_disk_lookup(stat_buf.st_dev); + dd = rtems_disk_obtain(stat_buf.st_dev); if (dd == NULL) { errno = ENOTBLK; ret_val = -1; diff --git a/cpukit/libfs/src/dosfs/msdos_free.c b/cpukit/libfs/src/dosfs/msdos_free.c index 2fb74e2387..90fc586a10 100644 --- a/cpukit/libfs/src/dosfs/msdos_free.c +++ b/cpukit/libfs/src/dosfs/msdos_free.c @@ -47,7 +47,7 @@ msdos_free_node_info(rtems_filesystem_location_info_t *pathloc) sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); rc = fat_file_close(pathloc->mt_entry, pathloc->node_access); diff --git a/cpukit/libfs/src/dosfs/msdos_initsupp.c b/cpukit/libfs/src/dosfs/msdos_initsupp.c index ce86fa22b0..42495c7622 100644 --- a/cpukit/libfs/src/dosfs/msdos_initsupp.c +++ b/cpukit/libfs/src/dosfs/msdos_initsupp.c @@ -61,7 +61,7 @@ msdos_initialize_support( fs_info = (msdos_fs_info_t *)calloc(1, sizeof(msdos_fs_info_t)); if (!fs_info) - set_errno_and_return_minus_one(ENOMEM); + rtems_set_errno_and_return_minus_one(ENOMEM); temp_mt_entry->fs_info = fs_info; @@ -124,7 +124,7 @@ msdos_initialize_support( fat_file_close(temp_mt_entry, fat_fd); fat_shutdown_drive(temp_mt_entry); free(fs_info); - set_errno_and_return_minus_one(ENOMEM); + rtems_set_errno_and_return_minus_one(ENOMEM); } sc = rtems_semaphore_create(3, @@ -138,7 +138,7 @@ msdos_initialize_support( fat_shutdown_drive(temp_mt_entry); free(fs_info->cl_buf); free(fs_info); - set_errno_and_return_minus_one( EIO ); + rtems_set_errno_and_return_minus_one( EIO ); } temp_mt_entry->mt_fs_root.node_access = fat_fd; diff --git a/cpukit/libfs/src/dosfs/msdos_misc.c b/cpukit/libfs/src/dosfs/msdos_misc.c index b7e6ab3523..077fb945b9 100644 --- a/cpukit/libfs/src/dosfs/msdos_misc.c +++ b/cpukit/libfs/src/dosfs/msdos_misc.c @@ -11,6 +11,8 @@ * @(#) $Id$ */ +#define MSDOS_TRACE 1 + #if HAVE_CONFIG_H #include "config.h" #endif @@ -786,7 +788,7 @@ int msdos_find_name_in_fat_file( fs_info->cl_buf)) != FAT_EOF) { if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); assert(ret == bts2rd); @@ -903,7 +905,7 @@ int msdos_find_node_by_cluster_num_in_fat_file( fs_info->cl_buf)) != FAT_EOF) { if ( ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE ) - set_errno_and_return_minus_one( EIO ); + rtems_set_errno_and_return_minus_one( EIO ); assert(ret == bts2rd); diff --git a/cpukit/libfs/src/dosfs/msdos_mknod.c b/cpukit/libfs/src/dosfs/msdos_mknod.c index cdc12da092..ac2a142cce 100644 --- a/cpukit/libfs/src/dosfs/msdos_mknod.c +++ b/cpukit/libfs/src/dosfs/msdos_mknod.c @@ -74,12 +74,12 @@ int msdos_mknod( type = MSDOS_REGULAR_FILE; } else - set_errno_and_return_minus_one(EINVAL); + rtems_set_errno_and_return_minus_one(EINVAL); sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT, MSDOS_VOLUME_SEMAPHORE_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one(EIO); + rtems_set_errno_and_return_minus_one(EIO); /* Create an MSDOS node */ rc = msdos_creat_node(pathloc, type, new_name, mode, NULL); diff --git a/cpukit/libmisc/Makefile.am b/cpukit/libmisc/Makefile.am index db79e248cf..e262348016 100644 --- a/cpukit/libmisc/Makefile.am +++ b/cpukit/libmisc/Makefile.am @@ -65,7 +65,7 @@ if LIBSHELL noinst_LIBRARIES += libshell.a libshell_a_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/shell libshell_a_SOURCES = shell/cat_file.c shell/cmds.c shell/internal.h \ - shell/main_alias.c shell/main_cat.c shell/main_cd.c \ + shell/main_alias.c shell/main_cat.c shell/main_cd.c shell/cmp-ls.c \ shell/main_chdir.c shell/main_chmod.c shell/main_chroot.c \ shell/main_cp.c shell/main_cpuuse.c shell/main_date.c shell/main_dir.c \ shell/main_echo.c shell/main_exit.c shell/main_help.c shell/main_id.c \ @@ -78,8 +78,10 @@ libshell_a_SOURCES = shell/cat_file.c shell/cmds.c shell/internal.h \ shell/main_stackuse.c shell/main_tty.c shell/main_umask.c \ shell/main_unmount.c shell/main_blksync.c shell/main_whoami.c \ shell/shell.c shell/shell_cmdset.c shell/shell_getchar.c shell/shellconfig.c \ - shell/shellconfig.h shell/shell.h shell/shell_makeargs.c shell/str2int.c \ - shell/write_file.c shell/utils-cp.c shell/err.c shell/errx.c shell/verr.c \ + shell/shellconfig.h shell/shell.h shell/shell_makeargs.c \ + shell/str2int.c shell/filemode.c shell/pwcache.c shell/print-ls.c\ + shell/write_file.c shell/utils-cp.c shell/utils-ls.c \ + shell/err.c shell/errx.c shell/verr.c shell/vis.c \ shell/verrx.c shell/vwarn.c shell/vwarnx.c shell/warn.c shell/warnx.c \ shell/fts.c shell/print_heapinfo.c shell/main_wkspaceinfo.c \ shell/shell_script.c diff --git a/cpukit/libmisc/shell/cmp-ls.c b/cpukit/libmisc/shell/cmp-ls.c new file mode 100644 index 0000000000..e146762f08 --- /dev/null +++ b/cpukit/libmisc/shell/cmp-ls.c @@ -0,0 +1,200 @@ +/* $NetBSD: cmp.c,v 1.17 2003/08/07 09:05:14 agc Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Fischbein. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)cmp.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: cmp.c,v 1.17 2003/08/07 09:05:14 agc Exp $"); +#endif +#endif /* not lint */ +#endif + +#include <sys/types.h> +#include <sys/stat.h> + +#include <fts.h> +#include <string.h> + +#include "extern-ls.h" + +#if defined(__rtems__) || defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || \ + defined(_XOPEN_SOURCE) || defined(__NetBSD__) +#define ATIMENSEC_CMP(x, op, y) ((x)->st_atime op (y)->st_atime) +#define CTIMENSEC_CMP(x, op, y) ((x)->st_ctime op (y)->st_ctime) +#define MTIMENSEC_CMP(x, op, y) ((x)->st_mtime op (y)->st_mtime) +#else +#define ATIMENSEC_CMP(x, op, y) \ + ((x)->st_atime.tv_nsec op (y)->st_atime.tv_nsec) +#define CTIMENSEC_CMP(x, op, y) \ + ((x)->st_ctime.tv_nsec op (y)->st_ctime.tv_nsec) +#define MTIMENSEC_CMP(x, op, y) \ + ((x)->st_mtime.tv_nsec op (y)->st_mtime.tv_nsec) +#endif + +int +namecmp(const FTSENT *a, const FTSENT *b) +{ + + return (strcmp(a->fts_name, b->fts_name)); +} + +int +revnamecmp(const FTSENT *a, const FTSENT *b) +{ + + return (strcmp(b->fts_name, a->fts_name)); +} + +int +modcmp(const FTSENT *a, const FTSENT *b) +{ + + if (b->fts_statp->st_mtime > a->fts_statp->st_mtime) + return (1); + else if (b->fts_statp->st_mtime < a->fts_statp->st_mtime) + return (-1); + else if (MTIMENSEC_CMP(b->fts_statp, >, a->fts_statp)) + return (1); + else if (MTIMENSEC_CMP(b->fts_statp, <, a->fts_statp)) + return (-1); + else + return (namecmp(a, b)); +} + +int +revmodcmp(const FTSENT *a, const FTSENT *b) +{ + + if (b->fts_statp->st_mtime > a->fts_statp->st_mtime) + return (-1); + else if (b->fts_statp->st_mtime < a->fts_statp->st_mtime) + return (1); + else if (MTIMENSEC_CMP(b->fts_statp, >, a->fts_statp)) + return (-1); + else if (MTIMENSEC_CMP(b->fts_statp, <, a->fts_statp)) + return (1); + else + return (revnamecmp(a, b)); +} + +int +acccmp(const FTSENT *a, const FTSENT *b) +{ + + if (b->fts_statp->st_atime > a->fts_statp->st_atime) + return (1); + else if (b->fts_statp->st_atime < a->fts_statp->st_atime) + return (-1); + else if (ATIMENSEC_CMP(b->fts_statp, >, a->fts_statp)) + return (1); + else if (ATIMENSEC_CMP(b->fts_statp, <, a->fts_statp)) + return (-1); + else + return (namecmp(a, b)); +} + +int +revacccmp(const FTSENT *a, const FTSENT *b) +{ + + if (b->fts_statp->st_atime > a->fts_statp->st_atime) + return (-1); + else if (b->fts_statp->st_atime < a->fts_statp->st_atime) + return (1); + else if (ATIMENSEC_CMP(b->fts_statp, >, a->fts_statp)) + return (-1); + else if (ATIMENSEC_CMP(b->fts_statp, <, a->fts_statp)) + return (1); + else + return (revnamecmp(a, b)); +} + +int +statcmp(const FTSENT *a, const FTSENT *b) +{ + + if (b->fts_statp->st_ctime > a->fts_statp->st_ctime) + return (1); + else if (b->fts_statp->st_ctime < a->fts_statp->st_ctime) + return (-1); + else if (CTIMENSEC_CMP(b->fts_statp, >, a->fts_statp)) + return (1); + else if (CTIMENSEC_CMP(b->fts_statp, <, a->fts_statp)) + return (-1); + else + return (namecmp(a, b)); +} + +int +revstatcmp(const FTSENT *a, const FTSENT *b) +{ + + if (b->fts_statp->st_ctime > a->fts_statp->st_ctime) + return (-1); + else if (b->fts_statp->st_ctime < a->fts_statp->st_ctime) + return (1); + else if (CTIMENSEC_CMP(b->fts_statp, >, a->fts_statp)) + return (-1); + else if (CTIMENSEC_CMP(b->fts_statp, <, a->fts_statp)) + return (1); + else + return (revnamecmp(a, b)); +} + +int +sizecmp(const FTSENT *a, const FTSENT *b) +{ + + if (b->fts_statp->st_size > a->fts_statp->st_size) + return (1); + if (b->fts_statp->st_size < a->fts_statp->st_size) + return (-1); + else + return (namecmp(a, b)); +} + +int +revsizecmp(const FTSENT *a, const FTSENT *b) +{ + + if (b->fts_statp->st_size > a->fts_statp->st_size) + return (-1); + if (b->fts_statp->st_size < a->fts_statp->st_size) + return (1); + else + return (revnamecmp(a, b)); +} diff --git a/cpukit/libmisc/shell/extern-cp.h b/cpukit/libmisc/shell/extern-cp.h index ba6ff9c4de..093b30ff10 100644 --- a/cpukit/libmisc/shell/extern-cp.h +++ b/cpukit/libmisc/shell/extern-cp.h @@ -84,7 +84,7 @@ int set_utimes(const char *, struct stat *); int setfile(rtems_shell_cp_globals* cp_globals, struct stat *, int); int preserve_dir_acls(struct stat *, char *, char *); int preserve_fd_acls(int, int); -void usage(); +void usage(rtems_shell_cp_globals* cp_globals); __END_DECLS diff --git a/cpukit/libmisc/shell/extern-ls.h b/cpukit/libmisc/shell/extern-ls.h new file mode 100644 index 0000000000..01575ba7df --- /dev/null +++ b/cpukit/libmisc/shell/extern-ls.h @@ -0,0 +1,195 @@ +/*- + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Fischbein. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)ls.h 8.1 (Berkeley) 5/31/93 + * $FreeBSD: src/bin/ls/ls.h,v 1.23 2008/04/04 03:57:46 grog Exp $ + */ + +#ifndef _EXTERN_LS_H_ +#define _EXTERN_LS_H_ + +#define NO_PRINT 1 +//#define COLORLS 1 + +#include <sys/cdefs.h> +#include <setjmp.h> + +#define major(d) rtems_filesystem_dev_major_t(d) +#define minor(d) rtems_filesystem_dev_minor_t(d) + +const char *user_from_uid(uid_t uid, int nouser); + +typedef struct { + int blocksize; + int termwidth; + int sortkey; + int rval; + int output; + time_t now; + + int f_accesstime; + int f_column; + int f_columnacross; + int f_flags; + int f_grouponly; + int f_humanize; + int f_inode; + int f_listdir; + int f_listdot; + int f_longform; + int f_nonprint; + int f_nosort; + int f_numericonly; + int f_octal; + int f_octal_escape; + int f_recursive; + int f_reversesort; + int f_sectime; + int f_singlecol; + int f_size; + int f_statustime; + int f_stream; + int f_type; + int f_typedir; + int f_whiteout; + + int exit_code; + jmp_buf exit_jmp; +} rtems_shell_ls_globals; + +#define blocksize globals->blocksize +#define termwidth globals->termwidth +#define sortkey globals->sortkey +#define rval globals->rval +#define output globals->output +#define now globals->now + +#define f_accesstime globals->f_accesstime +#define f_column globals->f_column +#define f_columnacross globals->f_columnacross +#define f_flags globals->f_flags +#define f_grouponly globals->f_grouponly +#define f_humanize globals->f_humanize +#define f_inode globals->f_inode +#define f_listdir globals->f_listdir +#define f_listdot globals->f_listdot +#define f_longform globals->f_longform +#define f_nonprint globals->f_nonprint +#define f_nosort globals->f_nosort +#define f_numericonly globals->f_numericonly +#define f_octal globals->f_octal +#define f_octal_escape globals->f_octal_escape +#define f_recursive globals->f_recursive +#define f_reversesort globals->f_reversesort +#define f_sectime globals->f_sectime +#define f_singlecol globals->f_singlecol +#define f_size globals->f_size +#define f_statustime globals->f_statustime +#define f_stream globals->f_stream +#define f_type globals->f_type +#define f_typedir globals->f_typedir +#define f_whiteout globals->f_whiteout + +#define exit_jump &(globals->exit_jmp) + +void rtems_shell_ls_exit(rtems_shell_ls_globals* globals, int code); + +#define exit(ec) rtems_shell_ls_exit(globals, ec) + + +typedef struct { + FTSENT *list; + u_int64_t btotal; + u_int64_t stotal; + int entries; + int maxlen; + int s_block; + int s_flags; + int s_group; + int s_inode; + int s_nlink; + int s_size; + int s_user; + int s_major; + int s_minor; +} DISPLAY; + +typedef struct { + char *user; + char *group; + char *flags; + char data[1]; +} NAMES; + +#define acccmp rtems_shell_ls_acccmp +#define revacccmp rtems_shell_ls_revacccmp +#define modcmp rtems_shell_ls_modcmp +#define revmodcmp rtems_shell_ls_revmodcmp +#define namecmp rtems_shell_ls_namecmp +#define revnamecmp rtems_shell_ls_revnamecmp +#define statcmp rtems_shell_ls_statcmp +#define revstatcmp rtems_shell_ls_revstatcmp +#define sizecmp rtems_shell_ls_sizecmp +#define revsizecmp rtems_shell_ls_revsizecmp +#define printescaped rtems_shell_ls_printescaped +#define printacol rtems_shell_ls_printacol +#define printcol rtems_shell_ls_printcol +#define printlong rtems_shell_ls_printlong +#define printscol rtems_shell_ls_printscol +#define printstream rtems_shell_ls_printstream +#define usage rtems_shell_ls_usage + +int acccmp(const FTSENT *, const FTSENT *); +int revacccmp(const FTSENT *, const FTSENT *); +int modcmp(const FTSENT *, const FTSENT *); +int revmodcmp(const FTSENT *, const FTSENT *); +int namecmp(const FTSENT *, const FTSENT *); +int revnamecmp(const FTSENT *, const FTSENT *); +int statcmp(const FTSENT *, const FTSENT *); +int revstatcmp(const FTSENT *, const FTSENT *); +int sizecmp(const FTSENT *, const FTSENT *); +int revsizecmp(const FTSENT *, const FTSENT *); + +int printescaped(rtems_shell_ls_globals* globals, const char *); +void printacol(rtems_shell_ls_globals* globals, DISPLAY *); +void printcol(rtems_shell_ls_globals* globals, DISPLAY *); +void printlong(rtems_shell_ls_globals* globals, DISPLAY *); +void printscol(rtems_shell_ls_globals* globals, DISPLAY *); +void printstream(rtems_shell_ls_globals* globals, DISPLAY *); +int safe_print(rtems_shell_ls_globals* globals, const char *); +void usage(rtems_shell_ls_globals* globals); + +void strmode(mode_t mode, char *p); + +#define DAYSPERNYEAR 365 +#define SECSPERDAY (60 * 60 * 24) + +#endif /* !_EXTERN_H_ */ diff --git a/cpukit/libmisc/shell/filemode.c b/cpukit/libmisc/shell/filemode.c new file mode 100644 index 0000000000..6d77a1be95 --- /dev/null +++ b/cpukit/libmisc/shell/filemode.c @@ -0,0 +1,150 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strmode.c 8.3 (Berkeley) 8/15/94"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/lib/libc/string/strmode.c,v 1.5 2007/01/09 00:28:12 imp Exp $"); + +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> + +void +strmode(mode, p) + mode_t mode; + char *p; +{ + /* print type */ + switch (mode & S_IFMT) { + case S_IFDIR: /* directory */ + *p++ = 'd'; + break; + case S_IFCHR: /* character special */ + *p++ = 'c'; + break; + case S_IFBLK: /* block special */ + *p++ = 'b'; + break; + case S_IFREG: /* regular */ + *p++ = '-'; + break; + case S_IFLNK: /* symbolic link */ + *p++ = 'l'; + break; + case S_IFSOCK: /* socket */ + *p++ = 's'; + break; +#ifdef S_IFIFO + case S_IFIFO: /* fifo */ + *p++ = 'p'; + break; +#endif +#ifdef S_IFWHT + case S_IFWHT: /* whiteout */ + *p++ = 'w'; + break; +#endif + default: /* unknown */ + *p++ = '?'; + break; + } + /* usr */ + if (mode & S_IRUSR) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWUSR) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXUSR | S_ISUID)) { + case 0: + *p++ = '-'; + break; + case S_IXUSR: + *p++ = 'x'; + break; + case S_ISUID: + *p++ = 'S'; + break; + case S_IXUSR | S_ISUID: + *p++ = 's'; + break; + } + /* group */ + if (mode & S_IRGRP) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWGRP) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXGRP | S_ISGID)) { + case 0: + *p++ = '-'; + break; + case S_IXGRP: + *p++ = 'x'; + break; + case S_ISGID: + *p++ = 'S'; + break; + case S_IXGRP | S_ISGID: + *p++ = 's'; + break; + } + /* other */ + if (mode & S_IROTH) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWOTH) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXOTH | S_ISVTX)) { + case 0: + *p++ = '-'; + break; + case S_IXOTH: + *p++ = 'x'; + break; + case S_ISVTX: + *p++ = 'T'; + break; + case S_IXOTH | S_ISVTX: + *p++ = 't'; + break; + } + *p++ = ' '; /* will be a '+' if ACL's implemented */ + *p = '\0'; +} diff --git a/cpukit/libmisc/shell/main_blksync.c b/cpukit/libmisc/shell/main_blksync.c index 0089a75adf..8226aefc9a 100644 --- a/cpukit/libmisc/shell/main_blksync.c +++ b/cpukit/libmisc/shell/main_blksync.c @@ -58,7 +58,7 @@ int rtems_shell_main_blksync( return 1; } - if (ioctl (fd, BLKIO_SYNCDEV) < 0) { + if (ioctl (fd, RTEMS_BLKIO_SYNCDEV) < 0) { fprintf( stderr, "%s: driver sync failed: %s\n", argv[0], strerror (errno)); return 1; } diff --git a/cpukit/libmisc/shell/main_cp.c b/cpukit/libmisc/shell/main_cp.c index 3111a4db74..773ec5ad69 100644 --- a/cpukit/libmisc/shell/main_cp.c +++ b/cpukit/libmisc/shell/main_cp.c @@ -175,14 +175,14 @@ main_cp(rtems_shell_cp_globals* cp_globals, int argc, char *argv[]) vflag = 1; break; default: - usage(); + usage(cp_globals); break; } argc -= getopt_reent.optind; argv += getopt_reent.optind; if (argc < 2) - usage(); + usage(cp_globals); fts_options = FTS_NOCHDIR | FTS_PHYSICAL; if (Rflag && rflag) diff --git a/cpukit/libmisc/shell/main_ls.c b/cpukit/libmisc/shell/main_ls.c index c81e35efda..d52229b521 100644 --- a/cpukit/libmisc/shell/main_ls.c +++ b/cpukit/libmisc/shell/main_ls.c @@ -1,104 +1,758 @@ +/* $NetBSD: ls.c,v 1.58 2005/10/26 02:24:22 jschauma Exp $ */ + /* - * LS Shell Command Implmentation + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. * - * Author: Fernando RUIZ CASAS - * Work: fernando.ruiz@ctv.es - * Home: correo@fernando-ruiz.com + * This code is derived from software contributed to Berkeley by + * Michael Fischbein. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.com/license/LICENSE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. * - * $Id$ + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H -#include "config.h" +#if 0 +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)ls.c 8.7 (Berkeley) 8/5/94"; +#else +__RCSID("$NetBSD: ls.c,v 1.58 2005/10/26 02:24:22 jschauma Exp $"); +#endif +#endif /* not lint */ #endif +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/shellconfig.h> +#include <getopt.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> + +#include <dirent.h> +#include <err.h> +#include <errno.h> +#include <fts.h> +#include <locale.h> #include <stdio.h> -#include <string.h> #include <stdlib.h> -#include <ctype.h> -#include <dirent.h> -#include <time.h> -#include <fcntl.h> +#include <string.h> #include <unistd.h> +#include <termios.h> #include <pwd.h> #include <grp.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <stddef.h> -#include <rtems.h> -#include <rtems/shell.h> -#include "internal.h" +#include "extern-ls.h" + +static void display(rtems_shell_ls_globals* globals, FTSENT *, FTSENT *); +static int mastercmp_listdir(const FTSENT **, const FTSENT **); +static int mastercmp_no_listdir(const FTSENT **, const FTSENT **); +static void traverse(rtems_shell_ls_globals* globals, int, char **, int); + +static void (*printfcn)(rtems_shell_ls_globals* globals, DISPLAY *); +static int (*sortfcn)(const FTSENT *, const FTSENT *); + +#define BY_NAME 0 +#define BY_SIZE 1 +#define BY_TIME 2 + +#if RTEMS_REMOVED +long blocksize; /* block size units */ +int termwidth = 80; /* default terminal width */ +int sortkey = BY_NAME; +int rval = EXIT_SUCCESS; /* exit value - set if error encountered */ + +/* flags */ +int f_accesstime; /* use time of last access */ +int f_column; /* columnated format */ +int f_columnacross; /* columnated format, sorted across */ +int f_flags; /* show flags associated with a file */ +int f_grouponly; /* long listing without owner */ +int f_humanize; /* humanize the size field */ +int f_inode; /* print inode */ +int f_listdir; /* list actual directory, not contents */ +int f_listdot; /* list files beginning with . */ +int f_longform; /* long listing format */ +int f_nonprint; /* show unprintables as ? */ +int f_nosort; /* don't sort output */ +int f_numericonly; /* don't convert uid/gid to name */ +int f_octal; /* print octal escapes for nongraphic characters */ +int f_octal_escape; /* like f_octal but use C escapes if possible */ +int f_recursive; /* ls subdirectories also */ +int f_reversesort; /* reverse whatever sort is used */ +int f_sectime; /* print the real time for all files */ +int f_singlecol; /* use single column output */ +int f_size; /* list size in short listing */ +int f_statustime; /* use time of last mode change */ +int f_stream; /* stream format */ +int f_type; /* add type character for non-regular files */ +int f_typedir; /* add type character for directories */ +int f_whiteout; /* show whiteout entries */ +#endif + +void +rtems_shell_ls_exit (rtems_shell_ls_globals* globals, int code) +{ + globals->exit_code = code; + longjmp (globals->exit_jmp, 1); +} + +static int main_ls(rtems_shell_ls_globals* globals, int argc, char *argv[]); + +int +rtems_shell_main_ls(int argc, char *argv[]) +{ + rtems_shell_ls_globals ls_globals; + rtems_shell_ls_globals* globals = &ls_globals; + memset (globals, 0, sizeof (ls_globals)); + termwidth = 80; + sortkey = BY_NAME; + rval = EXIT_SUCCESS; + ls_globals.exit_code = 1; + if (setjmp (ls_globals.exit_jmp) == 0) + return main_ls (globals, argc, argv); + return ls_globals.exit_code; +} + +int +main_ls(rtems_shell_ls_globals* globals, int argc, char *argv[]) +{ + static char dot[] = ".", *dotav[] = { dot, NULL }; + //struct winsize win; + int ch, fts_options; + int kflag = 0; + const char *p; + + struct getopt_data getopt_reent; + memset(&getopt_reent, 0, sizeof(getopt_data)); + +#if RTEMS_REMOVED + setprogname(argv[0]); +#endif + setlocale(LC_ALL, ""); + + /* Terminal defaults to -Cq, non-terminal defaults to -1. */ + if (isatty(STDOUT_FILENO)) { +#if RTEMS_REMOVED + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 && + win.ws_col > 0) + termwidth = win.ws_col; + f_column = f_nonprint = 1; +#endif + } else + f_singlecol = 1; + + /* Root is -A automatically. */ + if (!getuid()) + f_listdot = 1; + + fts_options = FTS_PHYSICAL; + while ((ch = getopt_r(argc, argv, + "1ABCFLRSTWabcdfghiklmnopqrstuwx", &getopt_reent)) != -1) { + switch (ch) { + /* + * The -1, -C, -l, -m and -x options all override each other so + * shell aliasing works correctly. + */ + case '1': + f_singlecol = 1; + f_column = f_columnacross = f_longform = f_stream = 0; + break; + case 'C': + f_column = 1; + f_columnacross = f_longform = f_singlecol = f_stream = + 0; + break; + case 'g': + if (f_grouponly != -1) + f_grouponly = 1; + f_longform = 1; + f_column = f_columnacross = f_singlecol = f_stream = 0; + break; + case 'l': + f_longform = 1; + f_column = f_columnacross = f_singlecol = f_stream = 0; + /* Never let -g take precedence over -l. */ + f_grouponly = -1; + break; + case 'm': + f_stream = 1; + f_column = f_columnacross = f_longform = f_singlecol = + 0; + break; + case 'x': + f_columnacross = 1; + f_column = f_longform = f_singlecol = f_stream = 0; + break; + /* The -c and -u options override each other. */ + case 'c': + f_statustime = 1; + f_accesstime = 0; + break; + case 'u': + f_accesstime = 1; + f_statustime = 0; + break; + case 'F': + f_type = 1; + break; + case 'L': + fts_options &= ~FTS_PHYSICAL; + fts_options |= FTS_LOGICAL; + break; + case 'R': + f_recursive = 1; + break; + case 'a': + fts_options |= FTS_SEEDOT; + /* FALLTHROUGH */ + case 'A': + f_listdot = 1; + break; + /* The -B option turns off the -b, -q and -w options. */ + case 'B': + f_nonprint = 0; + f_octal = 1; + f_octal_escape = 0; + break; + /* The -b option turns off the -B, -q and -w options. */ + case 'b': + f_nonprint = 0; + f_octal = 0; + f_octal_escape = 1; + break; + /* The -d option turns off the -R option. */ + case 'd': + f_listdir = 1; + f_recursive = 0; + break; + case 'f': + f_nosort = 1; + break; + case 'i': + f_inode = 1; + break; + case 'k': + blocksize = 1024; + kflag = 1; + break; + /* The -h option forces all sizes to be measured in bytes. */ + case 'h': + f_humanize = 1; + break; + case 'n': + f_numericonly = 1; + break; + case 'o': + f_flags = 1; + break; + case 'p': + f_typedir = 1; + break; + /* The -q option turns off the -B, -b and -w options. */ + case 'q': + f_nonprint = 1; + f_octal = 0; + f_octal_escape = 0; + break; + case 'r': + f_reversesort = 1; + break; + case 'S': + sortkey = BY_SIZE; + break; + case 's': + f_size = 1; + break; + case 'T': + f_sectime = 1; + break; + case 't': + sortkey = BY_TIME; + break; + case 'W': + f_whiteout = 1; + break; + /* The -w option turns off the -B, -b and -q options. */ + case 'w': + f_nonprint = 0; + f_octal = 0; + f_octal_escape = 0; + break; + default: + case '?': + usage(globals); + } + } + argc -= getopt_reent.optind; + argv += getopt_reent.optind; + + if (f_column || f_columnacross || f_stream) { + if ((p = getenv("COLUMNS")) != NULL) + termwidth = atoi(p); + } + + /* + * If both -g and -l options, let -l take precedence. + */ + if (f_grouponly == -1) + f_grouponly = 0; + + /* + * If not -F, -i, -l, -p, -S, -s or -t options, don't require stat + * information. + */ + if (!f_inode && !f_longform && !f_size && !f_type && !f_typedir && + sortkey == BY_NAME) + fts_options |= FTS_NOSTAT; + + /* + * If not -F, -d or -l options, follow any symbolic links listed on + * the command line. + */ + if (!f_longform && !f_listdir && !f_type) + fts_options |= FTS_COMFOLLOW; + + /* + * If -W, show whiteout entries + */ +#ifdef FTS_WHITEOUT + if (f_whiteout) + fts_options |= FTS_WHITEOUT; +#endif + + /* If -l or -s, figure out block size. */ + if (f_inode || f_longform || f_size) { +#if RTEMS_REMOVED + if (!kflag) + (void)getbsize(NULL, &blocksize); +#else + blocksize = 1024; +#endif + blocksize /= 512; + } + + /* Select a sort function. */ + if (f_reversesort) { + switch (sortkey) { + case BY_NAME: + sortfcn = revnamecmp; + break; + case BY_SIZE: + sortfcn = revsizecmp; + break; + case BY_TIME: + if (f_accesstime) + sortfcn = revacccmp; + else if (f_statustime) + sortfcn = revstatcmp; + else /* Use modification time. */ + sortfcn = revmodcmp; + break; + } + } else { + switch (sortkey) { + case BY_NAME: + sortfcn = namecmp; + break; + case BY_SIZE: + sortfcn = sizecmp; + break; + case BY_TIME: + if (f_accesstime) + sortfcn = acccmp; + else if (f_statustime) + sortfcn = statcmp; + else /* Use modification time. */ + sortfcn = modcmp; + break; + } + } + + /* Select a print function. */ + if (f_singlecol) + printfcn = printscol; + else if (f_columnacross) + printfcn = printacol; + else if (f_longform) + printfcn = printlong; + else if (f_stream) + printfcn = printstream; + else + printfcn = printcol; + + if (argc) + traverse(globals, argc, argv, fts_options); + else + traverse(globals, 1, dotav, fts_options); + exit(rval); + /* NOTREACHED */ + return 0; +} + +#if RTEMS_REMOVED +static int output; /* If anything output. */ +#endif -int rtems_shell_main_ls( - int argc, - char *argv[] -) +/* + * Traverse() walks the logical directory structure specified by the argv list + * in the order specified by the mastercmp() comparison function. During the + * traversal it passes linked lists of structures to display() which represent + * a superset (may be exact set) of the files to be displayed. + */ +static void +traverse(rtems_shell_ls_globals* globals, int argc, char *argv[], int options) { - char *fname; - DIR *dirp; - struct dirent *dp; - struct stat stat_buf; - struct passwd *pwd; - struct group *grp; - char *user; - char *group; - char sbuf[256]; - char nbuf[1024]; - int n; - int size; - - fname = "."; - if (argc>1) - fname = argv[1]; - - if ((dirp = opendir(fname)) == NULL) { - fprintf(stderr,"%s: %s: No such file or directory.\n", argv[0], fname); - return errno; - } - n = 0; - size = 0; - while ((dp = readdir(dirp)) != NULL) { - strcpy(nbuf,fname); - if (nbuf[strlen(nbuf)-1]!='/') - strcat(nbuf,"/"); - strcat(nbuf,dp->d_name); /* always the fullpathname. Avoid ftpd problem.*/ - if (stat(nbuf, &stat_buf) == 0) { /* AWFUL but works...*/ - strftime(sbuf,sizeof(sbuf)-1,"%b %d %H:%M", gmtime(&stat_buf.st_mtime)); - pwd = getpwuid(stat_buf.st_uid); - user = pwd?pwd->pw_name:"nouser"; - grp = getgrgid(stat_buf.st_gid); - group = grp?grp->gr_name:"nogrp"; - printf("%c%c%c%c%c%c%c%c%c%c %3d %6.6s %6.6s %11d %s %s%c\n", - (S_ISLNK(stat_buf.st_mode)?('l'): - (S_ISDIR(stat_buf.st_mode)?('d'):('-'))), - (stat_buf.st_mode & S_IRUSR)?('r'):('-'), - (stat_buf.st_mode & S_IWUSR)?('w'):('-'), - (stat_buf.st_mode & S_IXUSR)?('x'):('-'), - (stat_buf.st_mode & S_IRGRP)?('r'):('-'), - (stat_buf.st_mode & S_IWGRP)?('w'):('-'), - (stat_buf.st_mode & S_IXGRP)?('x'):('-'), - (stat_buf.st_mode & S_IROTH)?('r'):('-'), - (stat_buf.st_mode & S_IWOTH)?('w'):('-'), - (stat_buf.st_mode & S_IXOTH)?('x'):('-'), - (int)stat_buf.st_nlink, - user,group, - (int)stat_buf.st_size, - sbuf, - dp->d_name, - S_ISDIR(stat_buf.st_mode)?'/':' '); - n++; - size += stat_buf.st_size; + FTS *ftsp; + FTSENT *p, *chp; + int ch_options; + + if ((ftsp = + fts_open(argv, options, + f_nosort ? NULL : f_listdir ? + mastercmp_listdir : mastercmp_no_listdir)) == NULL) + err(exit_jump, EXIT_FAILURE, NULL); + + display(globals, NULL, fts_children(ftsp, 0)); + if (f_listdir) + { + fts_close(ftsp); + return; } - } - printf("%d files %d bytes occupied\n",n,size); - closedir(dirp); - return 0; + + /* + * If not recursing down this tree and don't need stat info, just get + * the names. + */ + ch_options = !f_recursive && options & FTS_NOSTAT ? FTS_NAMEONLY : 0; + + while ((p = fts_read(ftsp)) != NULL) + switch (p->fts_info) { + case FTS_DC: + warnx("%s: directory causes a cycle", p->fts_name); + break; + case FTS_DNR: + case FTS_ERR: + warnx("%s: %s", p->fts_name, strerror(p->fts_errno)); + rval = EXIT_FAILURE; + break; + case FTS_D: + if (p->fts_level != FTS_ROOTLEVEL && + p->fts_name[0] == '.' && !f_listdot) + break; + + /* + * If already output something, put out a newline as + * a separator. If multiple arguments, precede each + * directory with its name. + */ + if (output) + (void)printf("\n%s:\n", p->fts_path); + else if (argc > 1) { + (void)printf("%s:\n", p->fts_path); + output = 1; + } + + chp = fts_children(ftsp, ch_options); + display(globals, p, chp); + + if (!f_recursive && chp != NULL) + (void)fts_set(ftsp, p, FTS_SKIP); + break; + } + fts_close(ftsp); + if (errno) + err(exit_jump, EXIT_FAILURE, "fts_read"); +} + +/* + * Display() takes a linked list of FTSENT structures and passes the list + * along with any other necessary information to the print function. P + * points to the parent directory of the display list. + */ +static void +display(rtems_shell_ls_globals* globals, FTSENT *p, FTSENT *list) +{ + struct stat *sp; + DISPLAY d; + FTSENT *cur; + NAMES *np; + u_int64_t btotal, stotal, maxblock, maxsize; + int maxinode, maxnlink, maxmajor, maxminor; + int bcfile, entries, flen, glen, ulen, maxflags, maxgroup, maxlen; + int maxuser, needstats; + const char *user, *group; + char buf[21]; /* 64 bits == 20 digits, +1 for NUL */ + char nuser[12], ngroup[12]; + char *flags = NULL; + +#ifdef __GNUC__ + /* This outrageous construct just to shut up a GCC warning. */ + (void) &maxsize; +#endif + + /* + * If list is NULL there are two possibilities: that the parent + * directory p has no children, or that fts_children() returned an + * error. We ignore the error case since it will be replicated + * on the next call to fts_read() on the post-order visit to the + * directory p, and will be signalled in traverse(). + */ + if (list == NULL) + return; + + needstats = f_inode || f_longform || f_size; + flen = 0; + maxinode = maxnlink = 0; + bcfile = 0; + maxuser = maxgroup = maxflags = maxlen = 0; + btotal = stotal = maxblock = maxsize = 0; + maxmajor = maxminor = 0; + for (cur = list, entries = 0; cur; cur = cur->fts_link) { + if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) { + warnx("%s: %s", + cur->fts_name, strerror(cur->fts_errno)); + cur->fts_number = NO_PRINT; + rval = EXIT_FAILURE; + continue; + } + + /* + * P is NULL if list is the argv list, to which different rules + * apply. + */ + if (p == NULL) { + /* Directories will be displayed later. */ + if (cur->fts_info == FTS_D && !f_listdir) { + cur->fts_number = NO_PRINT; + continue; + } + } else { + /* Only display dot file if -a/-A set. */ + if (cur->fts_name[0] == '.' && !f_listdot) { + cur->fts_number = NO_PRINT; + continue; + } + } + if (cur->fts_namelen > maxlen) + maxlen = cur->fts_namelen; + if (needstats) { + sp = cur->fts_statp; + if (sp->st_blocks > maxblock) + maxblock = sp->st_blocks; + if (sp->st_ino > maxinode) + maxinode = sp->st_ino; + if (sp->st_nlink > maxnlink) + maxnlink = sp->st_nlink; + if (sp->st_size > maxsize) + maxsize = sp->st_size; + if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) { + bcfile = 1; + if (major(sp->st_rdev) > maxmajor) + maxmajor = major(sp->st_rdev); + if (minor(sp->st_rdev) > maxminor) + maxminor = minor(sp->st_rdev); + } + + btotal += sp->st_blocks; + stotal += sp->st_size; + if (f_longform) { + if (f_numericonly || + (user = user_from_uid(sp->st_uid, 0)) == + NULL) { + (void)snprintf(nuser, sizeof(nuser), + "%u", sp->st_uid); + user = nuser; + } + if (f_numericonly || + (group = group_from_gid(sp->st_gid, 0)) == + NULL) { + (void)snprintf(ngroup, sizeof(ngroup), + "%u", sp->st_gid); + group = ngroup; + } + if ((ulen = strlen(user)) > maxuser) + maxuser = ulen; + if ((glen = strlen(group)) > maxgroup) + maxgroup = glen; +#if RTEMS_REMOVED + if (f_flags) { + flags = + flags_to_string(sp->st_flags, "-"); + if ((flen = strlen(flags)) > maxflags) + maxflags = flen; + } else +#endif + flen = 0; + + if ((np = malloc(sizeof(NAMES) + + ulen + glen + flen + 3)) == NULL) + err(exit_jump, EXIT_FAILURE, NULL); + + np->user = &np->data[0]; + (void)strcpy(np->user, user); + np->group = &np->data[ulen + 1]; + (void)strcpy(np->group, group); + + if (f_flags) { + np->flags = &np->data[ulen + glen + 2]; + (void)strcpy(np->flags, flags); + } + cur->fts_pointer = np; + } + } + ++entries; + } + + if (!entries) + return; + + d.list = list; + d.entries = entries; + d.maxlen = maxlen; + if (needstats) { + d.btotal = btotal; + d.stotal = stotal; + if (f_humanize) { + d.s_block = 4; /* min buf length for humanize_number */ + } else { + (void)snprintf(buf, sizeof(buf), "%llu", + (long long)howmany(maxblock, blocksize)); + d.s_block = strlen(buf); + } + d.s_flags = maxflags; + d.s_group = maxgroup; + (void)snprintf(buf, sizeof(buf), "%u", maxinode); + d.s_inode = strlen(buf); + (void)snprintf(buf, sizeof(buf), "%u", maxnlink); + d.s_nlink = strlen(buf); + if (f_humanize) { + d.s_size = 4; /* min buf length for humanize_number */ + } else { + (void)snprintf(buf, sizeof(buf), "%llu", + (long long)maxsize); + d.s_size = strlen(buf); + } + d.s_user = maxuser; + if (bcfile) { + (void)snprintf(buf, sizeof(buf), "%u", maxmajor); + d.s_major = strlen(buf); + (void)snprintf(buf, sizeof(buf), "%u", maxminor); + d.s_minor = strlen(buf); + if (d.s_major + d.s_minor + 2 > d.s_size) + d.s_size = d.s_major + d.s_minor + 2; + else if (d.s_size - d.s_minor - 2 > d.s_major) + d.s_major = d.s_size - d.s_minor - 2; + } else { + d.s_major = 0; + d.s_minor = 0; + } + } + + printfcn(globals, &d); + output = 1; + + if (f_longform) + for (cur = list; cur; cur = cur->fts_link) + free(cur->fts_pointer); +} + +/* + * Ordering for mastercmp: + * If ordering the argv (fts_level = FTS_ROOTLEVEL) return non-directories + * as larger than directories. Within either group, use the sort function. + * All other levels use the sort function. Error entries remain unsorted. + */ +static int +mastercmp_no_listdir(const FTSENT **a, const FTSENT **b) +{ + int a_info, b_info; + int l_f_listdir = 0; + + a_info = (*a)->fts_info; + if (a_info == FTS_ERR) + return (0); + b_info = (*b)->fts_info; + if (b_info == FTS_ERR) + return (0); + + if (a_info == FTS_NS || b_info == FTS_NS) { + if (b_info != FTS_NS) + return (1); + else if (a_info != FTS_NS) + return (-1); + else + return (namecmp(*a, *b)); + } + + if (a_info != b_info && !l_f_listdir && + (*a)->fts_level == FTS_ROOTLEVEL) { + if (a_info == FTS_D) + return (1); + else if (b_info == FTS_D) + return (-1); + } + return (sortfcn(*a, *b)); +} + +static int +mastercmp_listdir(const FTSENT **a, const FTSENT **b) +{ + int a_info, b_info; + int l_f_listdir = 1; + + a_info = (*a)->fts_info; + if (a_info == FTS_ERR) + return (0); + b_info = (*b)->fts_info; + if (b_info == FTS_ERR) + return (0); + + if (a_info == FTS_NS || b_info == FTS_NS) { + if (b_info != FTS_NS) + return (1); + else if (a_info != FTS_NS) + return (-1); + else + return (namecmp(*a, *b)); + } + + if (a_info != b_info && !l_f_listdir && + (*a)->fts_level == FTS_ROOTLEVEL) { + if (a_info == FTS_D) + return (1); + else if (b_info == FTS_D) + return (-1); + } + return (sortfcn(*a, *b)); } rtems_shell_cmd_t rtems_shell_LS_Command = { diff --git a/cpukit/libmisc/shell/main_rm.c b/cpukit/libmisc/shell/main_rm.c index 9bf60b61cf..f833fc6b39 100644 --- a/cpukit/libmisc/shell/main_rm.c +++ b/cpukit/libmisc/shell/main_rm.c @@ -1,50 +1,699 @@ -/* - * RM Shell Command Implmentation - * - * Author: Fernando RUIZ CASAS - * Work: fernando.ruiz@ctv.es - * Home: correo@fernando-ruiz.com +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.com/license/LICENSE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. * - * $Id$ + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H -#include "config.h" +#if 0 +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1990, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)rm.c 8.5 (Berkeley) 4/18/94"; +#endif /* not lint */ #endif +#if 0 +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/bin/rm/rm.c,v 1.58 2006/10/31 02:22:36 delphij Exp $"); +#endif + +#include <rtems.h> +#include <rtems/shell.h> +#include <rtems/shellconfig.h> +#include <getopt.h> + +#include <sys/stat.h> +#include <sys/param.h> +#include <sys/mount.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <fts.h> +#include <grp.h> +#include <pwd.h> #include <stdio.h> -#include <unistd.h> +#include <stdlib.h> #include <string.h> -#include <errno.h> +#include <unistd.h> -#include <rtems.h> -#include <rtems/shell.h> -#include "internal.h" +/* RTEMS specific changes */ +typedef struct { + int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok; + int rflag, Iflag; + uid_t uid; + int exit_code; + jmp_buf exit_jmp; +} rtems_shell_rm_globals; + +#define dflag globals->dflag +#define eval globals->eval +#define fflag globals->fflag +#define iflag globals->iflag +#define Pflag globals->Pflag +#define vflag globals->vflag +#define Wflag globals->Wflag +#define stdin_ok globals->stdin_ok +#define rflag globals->rflag +#define Iflag globals->Iflag +#define xuid globals->uid +#define exit_jump &(globals->exit_jmp) + +#include <setjmp.h> + +#define exit(ec) rtems_shell_rm_exit(globals, ec) +void +rtems_shell_rm_exit (rtems_shell_rm_globals* globals, int code) +{ + globals->exit_code = code; + longjmp (globals->exit_jmp, 1); +} + +static int main_rm(rtems_shell_rm_globals* globals, int argc, char *argv[]); + +int +rtems_shell_main_rm(int argc, char *argv[]) +{ + rtems_shell_rm_globals rm_globals; + memset (&rm_globals, 0, sizeof (rm_globals)); + rm_globals.exit_code = 1; + if (setjmp (rm_globals.exit_jmp) == 0) + return main_rm (&rm_globals, argc, argv); + return rm_globals.exit_code; +} + +#define check(a1, a2, a3) check_rm(globals, a1, a2, a3) +#define check2(a1) check2_rm(globals, a1) +#define checkdot(a1) checkdot_rm(globals, a1) +#define checkslash(a1) checkslash_rm(globals, a1) +#define rm_file(a1) rm_file_rm(globals, a1) +#define rm_overwrite(a1, a2) rm_overwrite_rm(globals, a1, a2) +#define rm_tree(a1) rm_tree_rm(globals, a1) +#define usage() usage_rm(globals) + + +/* RTEMS changes */ + +static int check_rm(rtems_shell_rm_globals* globals, char *, char *, struct stat *); +static int check2_rm(rtems_shell_rm_globals* globals, char **); +static void checkdot_rm(rtems_shell_rm_globals* globals, char **); +static void checkslash_rm(rtems_shell_rm_globals* globals, char **); +static void rm_file_rm(rtems_shell_rm_globals* globals, char **); +static int rm_overwrite_rm(rtems_shell_rm_globals* globals, char *, struct stat *); +static void rm_tree_rm(rtems_shell_rm_globals* globals, char **); +static void usage_rm(rtems_shell_rm_globals* globals); + +/* + * rm -- + * This rm is different from historic rm's, but is expected to match + * POSIX 1003.2 behavior. The most visible difference is that -f + * has two specific effects now, ignore non-existent files and force + * file removal. + */ +int +main_rm(rtems_shell_rm_globals* globals, int argc, char *argv[]) +{ + int ch; + char *p; + + struct getopt_data getopt_reent; + memset(&getopt_reent, 0, sizeof(getopt_data)); + + /* + * Test for the special case where the utility is called as + * "unlink", for which the functionality provided is greatly + * simplified. + */ + if ((p = rindex(argv[0], '/')) == NULL) + p = argv[0]; + else + ++p; + if (strcmp(p, "unlink") == 0) { + while (getopt_r(argc, argv, "", &getopt_reent) != -1) + usage(); + argc -= getopt_reent.optind; + argv += getopt_reent.optind; + if (argc != 1) + usage(); + rm_file(&argv[0]); + exit(eval); + } + + Pflag = rflag = 0; + while ((ch = getopt_r(argc, argv, "dfiIPRrvW", &getopt_reent)) != -1) + switch(ch) { + case 'd': + dflag = 1; + break; + case 'f': + fflag = 1; + iflag = 0; + break; + case 'i': + fflag = 0; + iflag = 1; + break; + case 'I': + Iflag = 1; + break; + case 'P': + Pflag = 1; + break; + case 'R': + case 'r': /* Compatibility. */ + rflag = 1; + break; + case 'v': + vflag = 1; + break; + case 'W': + Wflag = 1; + break; + default: + usage(); + } + argc -= getopt_reent.optind; + argv += getopt_reent.optind; + + if (argc < 1) { + if (fflag) + return (0); + usage(); + } + + checkdot(argv); + if (getenv("POSIXLY_CORRECT") == NULL) + checkslash(argv); + xuid = geteuid(); + + if (*argv) { + stdin_ok = isatty(STDIN_FILENO); + + if (Iflag) { + if (check2(argv) == 0) + exit (1); + } + if (rflag) + rm_tree(argv); + else + rm_file(argv); + } + + exit (eval); + return 0; +} + +void +rm_tree_rm(rtems_shell_rm_globals* globals, char **argv) +{ + FTS *fts; + FTSENT *p; + int needstat; + int flags; + int rval; + + /* + * Remove a file hierarchy. If forcing removal (-f), or interactive + * (-i) or can't ask anyway (stdin_ok), don't stat the file. + */ + needstat = !xuid || (!fflag && !iflag && stdin_ok); + + /* + * If the -i option is specified, the user can skip on the pre-order + * visit. The fts_number field flags skipped directories. + */ +#define SKIPPED 1 + + flags = FTS_PHYSICAL; + if (!needstat) + flags |= FTS_NOSTAT; + if (Wflag) + flags |= FTS_WHITEOUT; + if (!(fts = fts_open(argv, flags, NULL))) { + if (fflag && errno == ENOENT) + return; + err(exit_jump, 1, "fts_open"); + } + while ((p = fts_read(fts)) != NULL) { + switch (p->fts_info) { + case FTS_DNR: + if (!fflag || p->fts_errno != ENOENT) { + warnx("%s: %s", + p->fts_path, strerror(p->fts_errno)); + eval = 1; + } + continue; + case FTS_ERR: + errx(exit_jump, 1, "%s: %s", p->fts_path, strerror(p->fts_errno)); + case FTS_NS: + /* + * Assume that since fts_read() couldn't stat the + * file, it can't be unlinked. + */ + if (!needstat) + break; + if (!fflag || p->fts_errno != ENOENT) { + warnx("%s: %s", + p->fts_path, strerror(p->fts_errno)); + eval = 1; + } + continue; + case FTS_D: + /* Pre-order: give user chance to skip. */ + if (!fflag && !check(p->fts_path, p->fts_accpath, + p->fts_statp)) { + (void)fts_set(fts, p, FTS_SKIP); + p->fts_number = SKIPPED; + } +#if RTEMS_REMOVED + else if (!xuid && + (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) && + !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) && + chflags(p->fts_accpath, + p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)) < 0) + goto err; +#endif + continue; + case FTS_DP: + /* Post-order: see if user skipped. */ + if (p->fts_number == SKIPPED) + continue; + break; + default: + if (!fflag && + !check(p->fts_path, p->fts_accpath, p->fts_statp)) + continue; + } + + rval = 0; +#if RTEMS_REMOVED + if (!xuid && + (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) && + !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE))) + rval = chflags(p->fts_accpath, + p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)); +#endif + if (rval == 0) { + /* + * If we can't read or search the directory, may still be + * able to remove it. Don't print out the un{read,search}able + * message unless the remove fails. + */ + switch (p->fts_info) { + case FTS_DP: + case FTS_DNR: + rval = rmdir(p->fts_accpath); + if (rval == 0 || (fflag && errno == ENOENT)) { + if (rval == 0 && vflag) + (void)printf("%s\n", + p->fts_path); + continue; + } + break; + +#if RTEMS_REMOVED + case FTS_W: + rval = undelete(p->fts_accpath); + if (rval == 0 && (fflag && errno == ENOENT)) { + if (vflag) + (void)printf("%s\n", + p->fts_path); + continue; + } + break; +#endif + + case FTS_NS: + /* + * Assume that since fts_read() couldn't stat + * the file, it can't be unlinked. + */ + if (fflag) + continue; + /* FALLTHROUGH */ + default: + if (Pflag) + if (!rm_overwrite(p->fts_accpath, NULL)) + continue; + rval = unlink(p->fts_accpath); + if (rval == 0 || (fflag && errno == ENOENT)) { + if (rval == 0 && vflag) + (void)printf("%s\n", + p->fts_path); + continue; + } + } + } +#if RTEMS_REMOVED +err: +#endif + warn("%s", p->fts_path); + eval = 1; + } + if (errno) + err(exit_jump, 1, "fts_read"); + fts_close(fts); +} + +#define S_ISWHT(m) (0) + +void +rm_file_rm(rtems_shell_rm_globals* globals, char **argv) +{ + struct stat sb; + int rval; + char *f; + + /* + * Remove a file. POSIX 1003.2 states that, by default, attempting + * to remove a directory is an error, so must always stat the file. + */ + while ((f = *argv++) != NULL) { + /* Assume if can't stat the file, can't unlink it. */ + if (lstat(f, &sb)) { +#if RTEMS_REMOVED + if (Wflag) { + sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR; + } else { +#endif + if (!fflag || errno != ENOENT) { + warn("%s", f); + eval = 1; + } + continue; +#if RTEMS_REMOVED + } +#endif + } else if (Wflag) { + warnx("%s: %s", f, strerror(EEXIST)); + eval = 1; + continue; + } + + if (S_ISDIR(sb.st_mode) && !dflag) { + warnx("%s: is a directory", f); + eval = 1; + continue; + } + if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb)) + continue; + rval = 0; +#if RTEMS_REMOVED + if (!xuid && !S_ISWHT(sb.st_mode) && + (sb.st_flags & (UF_APPEND|UF_IMMUTABLE)) && + !(sb.st_flags & (SF_APPEND|SF_IMMUTABLE))) + rval = chflags(f, sb.st_flags & ~(UF_APPEND|UF_IMMUTABLE)); +#endif + if (rval == 0) { + if (S_ISWHT(sb.st_mode)) +#if RTEMS_REMOVED + rval = undelete(f); +#endif + ; + else if (S_ISDIR(sb.st_mode)) + rval = rmdir(f); + else { + if (Pflag) + if (!rm_overwrite(f, &sb)) + continue; + rval = unlink(f); + } + } + if (rval && (!fflag || errno != ENOENT)) { + warn("%s", f); + eval = 1; + } + if (vflag && rval == 0) + (void)printf("%s\n", f); + } +} + +/* + * rm_overwrite -- + * Overwrite the file 3 times with varying bit patterns. + * + * XXX + * This is a cheap way to *really* delete files. Note that only regular + * files are deleted, directories (and therefore names) will remain. + * Also, this assumes a fixed-block file system (like FFS, or a V7 or a + * System V file system). In a logging file system, you'll have to have + * kernel support. + */ +int +rm_overwrite_rm(rtems_shell_rm_globals* globals, char *file, struct stat *sbp) +{ + struct stat sb; +#if RTEMS_REMOVED + struct statfs fsb; +#endif + off_t len; + int bsize, fd, wlen; + char *buf = NULL; + + fd = -1; + if (sbp == NULL) { + if (lstat(file, &sb)) + goto err; + sbp = &sb; + } + if (!S_ISREG(sbp->st_mode)) + return (1); + if (sbp->st_nlink > 1 && !fflag) { + warnx("%s (inode %lu): not overwritten due to multiple links", + file, sbp->st_ino); + return (0); + } + if ((fd = open(file, O_WRONLY, 0)) == -1) + goto err; +#if RTEMS_REMOVED + if (fstatfs(fd, &fsb) == -1) + goto err; + bsize = MAX(fsb.f_iosize, 1024); +#endif + bsize = 1024; + if ((buf = malloc(bsize)) == NULL) + err(exit_jump, 1, "%s: malloc", file); + +#define PASS(byte) { \ + memset(buf, byte, bsize); \ + for (len = sbp->st_size; len > 0; len -= wlen) { \ + wlen = len < bsize ? len : bsize; \ + if (write(fd, buf, wlen) != wlen) \ + goto err; \ + } \ +} + PASS(0xff); + if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET)) + goto err; + PASS(0x00); + if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET)) + goto err; + PASS(0xff); + if (!fsync(fd) && !close(fd)) { + free(buf); + return (1); + } + +err: eval = 1; + if (buf) + free(buf); + if (fd != -1) + close(fd); + warn("%s", file); + return (0); +} + +void strmode(mode_t mode, char *p); +char *fflagstostr(u_long flags); +const char *user_from_uid(uid_t uid, int nouser); + +int +check_rm(rtems_shell_rm_globals* globals, char *path, char *name, struct stat *sp) +{ + int ch, first; + char modep[15], *flagsp; + + /* Check -i first. */ + if (iflag) + (void)fprintf(stderr, "remove %s? ", path); + else { + /* + * If it's not a symbolic link and it's unwritable and we're + * talking to a terminal, ask. Symbolic links are excluded + * because their permissions are meaningless. Check stdin_ok + * first because we may not have stat'ed the file. + */ +#if RTEMS_REMOVED + if (!stdin_ok || S_ISLNK(sp->st_mode) || + (!access(name, W_OK) && + !(sp->st_flags & (SF_APPEND|SF_IMMUTABLE)) && + (!(sp->st_flags & (UF_APPEND|UF_IMMUTABLE)) || !xuid))) +#endif + if (!stdin_ok || S_ISLNK(sp->st_mode) || + (!access(name, W_OK))) + return (1); + strmode(sp->st_mode, modep); +#if RTEMS_REMOVED + if ((flagsp = fflagstostr(sp->st_flags)) == NULL) + err(exit_jump, 1, "fflagstostr"); +#else + flagsp = "no supported"; +#endif + if (Pflag) + errx(exit_jump, 1, + "%s: -P was specified, but file is not writable", + path); + (void)fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ", + modep + 1, modep[9] == ' ' ? "" : " ", + user_from_uid(sp->st_uid, 0), + group_from_gid(sp->st_gid, 0), + *flagsp ? flagsp : "", *flagsp ? " " : "", + path); + free(flagsp); + } + (void)fflush(stderr); + + first = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + return (first == 'y' || first == 'Y'); +} + +#define ISSLASH(a) ((a)[0] == '/' && (a)[1] == '\0') +void +checkslash_rm(rtems_shell_rm_globals* globals, char **argv) +{ + char **t, **u; + int complained; + + complained = 0; + for (t = argv; *t;) { + if (ISSLASH(*t)) { + if (!complained++) + warnx("\"/\" may not be removed"); + eval = 1; + for (u = t; u[0] != NULL; ++u) + u[0] = u[1]; + } else { + ++t; + } + } +} + +int +check2_rm(rtems_shell_rm_globals* globals, char **argv) +{ + struct stat st; + int first; + int ch; + int fcount = 0; + int dcount = 0; + int i; + const char *dname = NULL; + + for (i = 0; argv[i]; ++i) { + if (lstat(argv[i], &st) == 0) { + if (S_ISDIR(st.st_mode)) { + ++dcount; + dname = argv[i]; /* only used if 1 dir */ + } else { + ++fcount; + } + } + } + first = 0; + while (first != 'n' && first != 'N' && first != 'y' && first != 'Y') { + if (dcount && rflag) { + fprintf(stderr, "recursively remove"); + if (dcount == 1) + fprintf(stderr, " %s", dname); + else + fprintf(stderr, " %d dirs", dcount); + if (fcount == 1) + fprintf(stderr, " and 1 file"); + else if (fcount > 1) + fprintf(stderr, " and %d files", fcount); + } else if (dcount + fcount > 3) { + fprintf(stderr, "remove %d files", dcount + fcount); + } else { + return(1); + } + fprintf(stderr, "? "); + fflush(stderr); + + first = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + if (ch == EOF) + break; + } + return (first == 'y' || first == 'Y'); +} + +#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2]))) +void +checkdot_rm(rtems_shell_rm_globals* globals, char **argv) +{ + char *p, **save, **t; + int complained; + + complained = 0; + for (t = argv; *t;) { + if ((p = strrchr(*t, '/')) != NULL) + ++p; + else + p = *t; + if (ISDOT(p)) { + if (!complained++) + warnx("\".\" and \"..\" may not be removed"); + eval = 1; + for (save = t; (t[0] = t[1]) != NULL; ++t) + continue; + t = save; + } else + ++t; + } +} -int rtems_shell_main_rm( - int argc, - char *argv[] -) +void +usage_rm(rtems_shell_rm_globals* globals) { - int n = 1; - while ( n<argc ) { - if (unlink(argv[n])) { - fprintf(stderr,"%s: %s: %s\n", argv[0], argv[n], strerror(errno)); - return -1; - } - n++; - } - return 0; + (void)fprintf(stderr, "%s\n%s\n", + "usage: rm [-f | -i] [-dIPRrvW] file ...", + " unlink file"); + exit(1); } rtems_shell_cmd_t rtems_shell_RM_Command = { "rm", /* name */ - "rm n1 [n2 [n3...]] # remove files", /* usage */ + "[-f | -i] [-dIPRrvW] file ...", /* usage */ "files", /* topic */ rtems_shell_main_rm, /* command */ NULL, /* alias */ diff --git a/cpukit/libmisc/shell/print-ls.c b/cpukit/libmisc/shell/print-ls.c new file mode 100644 index 0000000000..de7e757cf8 --- /dev/null +++ b/cpukit/libmisc/shell/print-ls.c @@ -0,0 +1,480 @@ +/* $NetBSD: print.c,v 1.40 2004/11/17 17:00:00 mycroft Exp $ */ + +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Fischbein. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)print.c 8.5 (Berkeley) 7/28/94"; +#else +__RCSID("$NetBSD: print.c,v 1.40 2004/11/17 17:00:00 mycroft Exp $"); +#endif +#endif /* not lint */ +#endif + +#include <rtems.h> +#include <rtems/libio.h> + +#include <sys/param.h> +#include <sys/stat.h> + +#include <err.h> +#include <errno.h> +#include <fts.h> +#include <grp.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +//#include <tzfile.h> +#include <unistd.h> +//#include <util.h> + +#include "extern-ls.h" + +#if RTEMS_REMOVED +extern int termwidth; +#endif + +static int printaname(rtems_shell_ls_globals* globals, FTSENT *, int, int); +static void printlink(rtems_shell_ls_globals* globals, FTSENT *); +static void printtime(rtems_shell_ls_globals* globals, time_t); +static int printtype(u_int); + +#if RTEMS_REMOVED +static time_t now; +#endif + +#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) + +void +printscol(rtems_shell_ls_globals* globals, DISPLAY *dp) +{ + FTSENT *p; + + for (p = dp->list; p; p = p->fts_link) { + if (IS_NOPRINT(p)) + continue; + (void)printaname(globals, p, dp->s_inode, dp->s_block); + (void)putchar('\n'); + } +} + +void +printlong(rtems_shell_ls_globals* globals, DISPLAY *dp) +{ + struct stat *sp; + FTSENT *p; + NAMES *np; + char buf[20]; //, szbuf[5]; + + now = time(NULL); + + if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) { +#if RTEMS_REMOVED + if (f_humanize) { + if ((humanize_number(szbuf, sizeof(szbuf), dp->stotal, + "", HN_AUTOSCALE, + (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) + err(exit_jump, 1, "humanize_number"); + (void)printf("total %s\n", szbuf); + } else { +#endif + (void)printf("total %llu\n", + (long long)(howmany(dp->btotal, blocksize))); +#if RTEMS_REMOVED + } +#endif + } + + for (p = dp->list; p; p = p->fts_link) { + if (IS_NOPRINT(p)) + continue; + sp = p->fts_statp; + if (f_inode) + (void)printf("%*lu ", dp->s_inode, + (unsigned long)sp->st_ino); + if (f_size && !f_humanize) { + (void)printf("%*llu ", dp->s_block, + (long long)howmany(sp->st_blocks, blocksize)); + } + (void)strmode(sp->st_mode, buf); + np = p->fts_pointer; + (void)printf("%s %*lu ", buf, dp->s_nlink, + (unsigned long)sp->st_nlink); + if (!f_grouponly) + (void)printf("%-*s ", dp->s_user, np->user); + (void)printf("%-*s ", dp->s_group, np->group); + if (f_flags) + (void)printf("%-*s ", dp->s_flags, np->flags); + if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) + (void)printf("%*lu, %*lu ", + dp->s_major, major(sp->st_rdev), dp->s_minor, + minor(sp->st_rdev)); + else +#if RTEMS_REMOVED + if (f_humanize) { + if ((humanize_number(szbuf, sizeof(szbuf), + sp->st_size, "", HN_AUTOSCALE, + (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) + err(1, "humanize_number"); + (void)printf("%*s ", dp->s_size, szbuf); + } else { +#endif + (void)printf("%*llu ", dp->s_size, + (long long)sp->st_size); +#if RTEMS_REMOVED + } +#endif + if (f_accesstime) + printtime(globals, sp->st_atime); + else if (f_statustime) + printtime(globals, sp->st_ctime); + else + printtime(globals, sp->st_mtime); + if (f_octal || f_octal_escape) + (void)safe_print(globals, p->fts_name); + else if (f_nonprint) + (void)printescaped(globals, p->fts_name); + else + (void)printf("%s", p->fts_name); + + if (f_type || (f_typedir && S_ISDIR(sp->st_mode))) + (void)printtype(sp->st_mode); + if (S_ISLNK(sp->st_mode)) + printlink(globals, p); + (void)putchar('\n'); + } +} + +void +printcol(rtems_shell_ls_globals* globals, DISPLAY *dp) +{ + static FTSENT **array; + static int lastentries = -1; + FTSENT *p; + int base, chcnt, col, colwidth, num; + int numcols, numrows, row; + //char szbuf[5]; + + colwidth = dp->maxlen; + if (f_inode) + colwidth += dp->s_inode + 1; + if (f_size) { + if (f_humanize) + colwidth += dp->s_size + 1; + else + colwidth += dp->s_block + 1; + } + if (f_type || f_typedir) + colwidth += 1; + + colwidth += 1; + + if (termwidth < 2 * colwidth) { + printscol(globals, dp); + return; + } + + /* + * Have to do random access in the linked list -- build a table + * of pointers. + */ + if (dp->entries > lastentries) { + lastentries = dp->entries; + if ((array = + realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { + warn(NULL); + printscol(globals, dp); + } + } + for (p = dp->list, num = 0; p; p = p->fts_link) + if (p->fts_number != NO_PRINT) + array[num++] = p; + + numcols = termwidth / colwidth; + colwidth = termwidth / numcols; /* spread out if possible */ + numrows = num / numcols; + if (num % numcols) + ++numrows; + + if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) { +#if RTEMS_REMOVED + if (f_humanize) { + if ((humanize_number(szbuf, sizeof(szbuf), dp->stotal, + "", HN_AUTOSCALE, + (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) + err(1, "humanize_number"); + (void)printf("total %s\n", szbuf); + } else { +#endif + (void)printf("total %llu\n", + (long long)(howmany(dp->btotal, blocksize))); +#if RTEMS_REMOVED + } +#endif + } + for (row = 0; row < numrows; ++row) { + for (base = row, chcnt = col = 0; col < numcols; ++col) { + chcnt = printaname(globals, array[base], dp->s_inode, + f_humanize && 0 ? dp->s_size : dp->s_block); + if ((base += numrows) >= num) + break; + while (chcnt++ < colwidth) + (void)putchar(' '); + } + (void)putchar('\n'); + } +} + +void +printacol(rtems_shell_ls_globals* globals, DISPLAY *dp) +{ + FTSENT *p; + int chcnt, col, colwidth; + int numcols; + //char szbuf[5]; + + colwidth = dp->maxlen; + if (f_inode) + colwidth += dp->s_inode + 1; + if (f_size) { + if (f_humanize) + colwidth += dp->s_size + 1; + else + colwidth += dp->s_block + 1; + } + if (f_type || f_typedir) + colwidth += 1; + + colwidth += 1; + + if (termwidth < 2 * colwidth) { + printscol(globals, dp); + return; + } + + numcols = termwidth / colwidth; + colwidth = termwidth / numcols; /* spread out if possible */ + + if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) { +#if RTEMS_REMOVED + if (f_humanize) { + if ((humanize_number(szbuf, sizeof(szbuf), dp->stotal, + "", HN_AUTOSCALE, + (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) + err(1, "humanize_number"); + (void)printf("total %s\n", szbuf); + } else { +#endif + (void)printf("total %llu\n", + (long long)(howmany(dp->btotal, blocksize))); +#if RTEMS_REMOVED + } +#endif + } + chcnt = col = 0; + for (p = dp->list; p; p = p->fts_link) { + if (IS_NOPRINT(p)) + continue; + if (col >= numcols) { + chcnt = col = 0; + (void)putchar('\n'); + } + chcnt = printaname(globals, p, dp->s_inode, + f_humanize && 0 ? dp->s_size : dp->s_block); + while (chcnt++ < colwidth) + (void)putchar(' '); + col++; + } + (void)putchar('\n'); +} + +void +printstream(rtems_shell_ls_globals* globals, DISPLAY *dp) +{ + FTSENT *p; + int col; + int extwidth; + + extwidth = 0; + if (f_inode) + extwidth += dp->s_inode + 1; + if (f_size) { + if (f_humanize) + extwidth += dp->s_size + 1; + else + extwidth += dp->s_block + 1; + } + if (f_type) + extwidth += 1; + + for (col = 0, p = dp->list; p != NULL; p = p->fts_link) { + if (IS_NOPRINT(p)) + continue; + if (col > 0) { + (void)putchar(','), col++; + if (col + 1 + extwidth + p->fts_namelen >= termwidth) + (void)putchar('\n'), col = 0; + else + (void)putchar(' '), col++; + } + col += printaname(globals, p, dp->s_inode, + f_humanize && 0 ? dp->s_size : dp->s_block); + } + (void)putchar('\n'); +} + +/* + * print [inode] [size] name + * return # of characters printed, no trailing characters. + */ +static int +printaname(rtems_shell_ls_globals* globals, + FTSENT *p, int inodefield, int sizefield) +{ + struct stat *sp; + int chcnt; + //char szbuf[5]; + + sp = p->fts_statp; + chcnt = 0; + if (f_inode) + chcnt += printf("%*lu ", inodefield, (unsigned long)sp->st_ino); + if (f_size) { +#if RTEMS_REMOVED + if (f_humanize) { + if ((humanize_number(szbuf, sizeof(szbuf), sp->st_size, + "", HN_AUTOSCALE, + (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) + err(1, "humanize_number"); + chcnt += printf("%*s ", sizefield, szbuf); + } else { +#endif + chcnt += printf("%*llu ", sizefield, + (long long)howmany(sp->st_blocks, blocksize)); +#if RTEMS_REMOVED + } +#endif + } + if (f_octal || f_octal_escape) + chcnt += safe_print(globals, p->fts_name); + else if (f_nonprint) + chcnt += printescaped(globals, p->fts_name); + else + chcnt += printf("%s", p->fts_name); + if (f_type || (f_typedir && S_ISDIR(sp->st_mode))) + chcnt += printtype(sp->st_mode); + return (chcnt); +} + +static void +printtime(rtems_shell_ls_globals* globals, time_t ftime) +{ + int i; + char *longstring; + + longstring = ctime(&ftime); + for (i = 4; i < 11; ++i) + (void)putchar(longstring[i]); + +#define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY) + if (f_sectime) + for (i = 11; i < 24; i++) + (void)putchar(longstring[i]); + else if (ftime + SIXMONTHS > now && ftime - SIXMONTHS < now) + for (i = 11; i < 16; ++i) + (void)putchar(longstring[i]); + else { + (void)putchar(' '); + for (i = 20; i < 24; ++i) + (void)putchar(longstring[i]); + } + (void)putchar(' '); +} + +static int +printtype(u_int mode) +{ + switch (mode & S_IFMT) { + case S_IFDIR: + (void)putchar('/'); + return (1); + case S_IFIFO: + (void)putchar('|'); + return (1); + case S_IFLNK: + (void)putchar('@'); + return (1); + case S_IFSOCK: + (void)putchar('='); + return (1); +#if RTEMS_REMOVED + case S_IFWHT: + (void)putchar('%'); + return (1); +#endif + } + if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { + (void)putchar('*'); + return (1); + } + return (0); +} + +static void +printlink(rtems_shell_ls_globals* globals, FTSENT *p) +{ + int lnklen; + char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1]; + + if (p->fts_level == FTS_ROOTLEVEL) + (void)snprintf(name, sizeof(name), "%s", p->fts_name); + else + (void)snprintf(name, sizeof(name), + "%s/%s", p->fts_parent->fts_accpath, p->fts_name); + if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { + (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); + return; + } + path[lnklen] = '\0'; + (void)printf(" -> "); + if (f_octal || f_octal_escape) + (void)safe_print(globals, path); + else if (f_nonprint) + (void)printescaped(globals, path); + else + (void)printf("%s", path); +} diff --git a/cpukit/libmisc/shell/pwcache.c b/cpukit/libmisc/shell/pwcache.c new file mode 100644 index 0000000000..6b50bd6eb1 --- /dev/null +++ b/cpukit/libmisc/shell/pwcache.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)pwcache.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/lib/libc/gen/pwcache.c,v 1.11 2007/01/09 00:27:55 imp Exp $"); + +#include <sys/types.h> + +#include <grp.h> +#include <pwd.h> +#include <stdio.h> +#include <string.h> +//#include <utmp.h> + +#define UT_NAMESIZE 64 + +#define NCACHE 64 /* power of 2 */ +#define MASK (NCACHE - 1) /* bits to store with */ + +const char * +user_from_uid(uid_t uid, int nouser) +{ + static struct ncache { + uid_t uid; + int found; + char name[UT_NAMESIZE + 1]; + } c_uid[NCACHE]; + static int pwopen; + struct passwd *pw; + struct ncache *cp; + + cp = c_uid + (uid & MASK); + if (cp->uid != uid || !*cp->name) { + if (pwopen == 0) { + //setpassent(1); + pwopen = 1; + } + pw = getpwuid(uid); + cp->uid = uid; + if (pw != NULL) { + cp->found = 1; + (void)strncpy(cp->name, pw->pw_name, UT_NAMESIZE); + cp->name[UT_NAMESIZE] = '\0'; + } else { + cp->found = 0; + (void)snprintf(cp->name, UT_NAMESIZE, "%u", uid); + if (nouser) + return (NULL); + } + } + return ((nouser && !cp->found) ? NULL : cp->name); +} + +char * +group_from_gid(gid_t gid, int nogroup) +{ + static struct ncache { + gid_t gid; + int found; + char name[UT_NAMESIZE + 1]; + } c_gid[NCACHE]; + static int gropen; + struct group *gr; + struct ncache *cp; + + cp = c_gid + (gid & MASK); + if (cp->gid != gid || !*cp->name) { + if (gropen == 0) { + //setgroupent(1); + gropen = 1; + } + gr = getgrgid(gid); + cp->gid = gid; + if (gr != NULL) { + cp->found = 1; + (void)strncpy(cp->name, gr->gr_name, UT_NAMESIZE); + cp->name[UT_NAMESIZE] = '\0'; + } else { + cp->found = 0; + (void)snprintf(cp->name, UT_NAMESIZE, "%u", gid); + if (nogroup) + return (NULL); + } + } + return ((nogroup && !cp->found) ? NULL : cp->name); +} + diff --git a/cpukit/libmisc/shell/shell.c b/cpukit/libmisc/shell/shell.c index 3b002b5548..02f6bfbd4d 100644 --- a/cpukit/libmisc/shell/shell.c +++ b/cpukit/libmisc/shell/shell.c @@ -980,7 +980,7 @@ static rtems_status_code rtems_shell_run ( name, task_priority, task_stacksize, - RTEMS_DEFAULT_MODES, + RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR, RTEMS_LOCAL | RTEMS_FLOATING_POINT, &task_id ); diff --git a/cpukit/libmisc/shell/utils-cp.c b/cpukit/libmisc/shell/utils-cp.c index defd5dd021..6c525c982f 100644 --- a/cpukit/libmisc/shell/utils-cp.c +++ b/cpukit/libmisc/shell/utils-cp.c @@ -465,11 +465,11 @@ preserve_dir_acls(struct stat *fs, char *source_dir, char *dest_dir) } void -usage(void) +usage(rtems_shell_cp_globals* cp_globals) { - (void)fprintf(stderr, "%s\n%s\n", "usage: cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpv] source_file target_file", " cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpv] source_file ... " "target_directory"); + longjmp (cp_globals->exit_jmp, 1); } diff --git a/cpukit/libmisc/shell/utils-ls.c b/cpukit/libmisc/shell/utils-ls.c new file mode 100644 index 0000000000..c7629e786a --- /dev/null +++ b/cpukit/libmisc/shell/utils-ls.c @@ -0,0 +1,113 @@ +/* $NetBSD: util.c,v 1.28 2005/06/17 14:36:16 hira Exp $ */ + +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Michael Fischbein. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)util.c 8.5 (Berkeley) 4/28/95"; +#else +__RCSID("$NetBSD: util.c,v 1.28 2005/06/17 14:36:16 hira Exp $"); +#endif +#endif /* not lint */ +#endif + +#include <sys/types.h> +#include <sys/stat.h> + +#include <ctype.h> +#include <err.h> +#include <fts.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <vis.h> + +#include "extern-ls.h" + +#define SIZE_T_MAX 255 + +int +safe_print(rtems_shell_ls_globals* globals, const char *src) +{ + size_t len; + char *name; + int flags; + + flags = VIS_NL | VIS_OCTAL; + if (f_octal_escape) + flags |= VIS_CSTYLE; + + len = strlen(src); + if (len != 0 && SIZE_T_MAX/len <= 4) { + errx(exit_jump, EXIT_FAILURE, "%s: name too long", src); + /* NOTREACHED */ + } + + name = (char *)malloc(4*len+1); + if (name != NULL) { + len = strvis(name, src, flags); + printf("%s", name); + free(name); + return len; + } else + errx(exit_jump, EXIT_FAILURE, "out of memory!"); + /* NOTREACHED */ +} + +int +printescaped(rtems_shell_ls_globals* globals, const char *src) +{ + unsigned char c; + int n; + + for (n = 0; (c = *src) != '\0'; ++src, ++n) + if (isprint(c)) + (void)putchar(c); + else + (void)putchar('?'); + return n; +} + +void +usage(rtems_shell_ls_globals* globals) +{ + + (void)fprintf(stderr, + "usage: %s [-AaBbCcdFfghikLlmnopqRrSsTtuWwx1] [file ...]\n", + "ls"); + exit(EXIT_FAILURE); + /* NOTREACHED */ +} diff --git a/cpukit/libmisc/shell/vis.c b/cpukit/libmisc/shell/vis.c new file mode 100644 index 0000000000..3ae560d53b --- /dev/null +++ b/cpukit/libmisc/shell/vis.c @@ -0,0 +1,384 @@ +/* $NetBSD: vis.c,v 1.33 2005/05/28 13:11:14 lukem Exp $ */ + +/*- + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/*- + * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _DIAGASSERT(a) + +#if 0 +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: vis.c,v 1.33 2005/05/28 13:11:14 lukem Exp $"); +#endif /* LIBC_SCCS and not lint */ +#endif + +#include <sys/types.h> + +#include <assert.h> +#include <vis.h> +#include <stdlib.h> + +#if !HAVE_VIS || !HAVE_SVIS +#include <ctype.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> + +#undef BELL +#define BELL '\a' + +#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') +#define iswhite(c) (c == ' ' || c == '\t' || c == '\n') +#define issafe(c) (c == '\b' || c == BELL || c == '\r') +#define xtoa(c) "0123456789abcdef"[c] + +#define MAXEXTRAS 5 + + +#define MAKEEXTRALIST(flag, extra, orig) \ +do { \ + const char *o = orig; \ + char *e; \ + while (*o++) \ + continue; \ + extra = malloc((size_t)((o - orig) + MAXEXTRAS)); \ + if (!extra) break; \ + for (o = orig, e = extra; (*e++ = *o++) != '\0';) \ + continue; \ + e--; \ + if (flag & VIS_SP) *e++ = ' '; \ + if (flag & VIS_TAB) *e++ = '\t'; \ + if (flag & VIS_NL) *e++ = '\n'; \ + if ((flag & VIS_NOSLASH) == 0) *e++ = '\\'; \ + *e = '\0'; \ +} while (/*CONSTCOND*/0) + + +/* + * This is HVIS, the macro of vis used to HTTP style (RFC 1808) + */ +#define HVIS(dst, c, flag, nextc, extra) \ +do \ + if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) { \ + *dst++ = '%'; \ + *dst++ = xtoa(((unsigned int)c >> 4) & 0xf); \ + *dst++ = xtoa((unsigned int)c & 0xf); \ + } else { \ + SVIS(dst, c, flag, nextc, extra); \ + } \ +while (/*CONSTCOND*/0) + +/* + * This is SVIS, the central macro of vis. + * dst: Pointer to the destination buffer + * c: Character to encode + * flag: Flag word + * nextc: The character following 'c' + * extra: Pointer to the list of extra characters to be + * backslash-protected. + */ +#define SVIS(dst, c, flag, nextc, extra) \ +do { \ + int isextra; \ + isextra = strchr(extra, c) != NULL; \ + if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) || \ + ((flag & VIS_SAFE) && issafe(c)))) { \ + *dst++ = c; \ + break; \ + } \ + if (flag & VIS_CSTYLE) { \ + switch (c) { \ + case '\n': \ + *dst++ = '\\'; *dst++ = 'n'; \ + continue; \ + case '\r': \ + *dst++ = '\\'; *dst++ = 'r'; \ + continue; \ + case '\b': \ + *dst++ = '\\'; *dst++ = 'b'; \ + continue; \ + case BELL: \ + *dst++ = '\\'; *dst++ = 'a'; \ + continue; \ + case '\v': \ + *dst++ = '\\'; *dst++ = 'v'; \ + continue; \ + case '\t': \ + *dst++ = '\\'; *dst++ = 't'; \ + continue; \ + case '\f': \ + *dst++ = '\\'; *dst++ = 'f'; \ + continue; \ + case ' ': \ + *dst++ = '\\'; *dst++ = 's'; \ + continue; \ + case '\0': \ + *dst++ = '\\'; *dst++ = '0'; \ + if (isoctal(nextc)) { \ + *dst++ = '0'; \ + *dst++ = '0'; \ + } \ + continue; \ + default: \ + if (isgraph(c)) { \ + *dst++ = '\\'; *dst++ = c; \ + continue; \ + } \ + } \ + } \ + if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) { \ + *dst++ = '\\'; \ + *dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0'; \ + *dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0'; \ + *dst++ = (c & 07) + '0'; \ + } else { \ + if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\'; \ + if (c & 0200) { \ + c &= 0177; *dst++ = 'M'; \ + } \ + if (iscntrl(c)) { \ + *dst++ = '^'; \ + if (c == 0177) \ + *dst++ = '?'; \ + else \ + *dst++ = c + '@'; \ + } else { \ + *dst++ = '-'; *dst++ = c; \ + } \ + } \ +} while (/*CONSTCOND*/0) + + +/* + * svis - visually encode characters, also encoding the characters + * pointed to by `extra' + */ +char * +svis(char *dst, int c, int flag, int nextc, const char *extra) +{ + char *nextra = NULL; + + _DIAGASSERT(dst != NULL); + _DIAGASSERT(extra != NULL); + MAKEEXTRALIST(flag, nextra, extra); + if (!nextra) { + *dst = '\0'; /* can't create nextra, return "" */ + return dst; + } + if (flag & VIS_HTTPSTYLE) + HVIS(dst, c, flag, nextc, nextra); + else + SVIS(dst, c, flag, nextc, nextra); + free(nextra); + *dst = '\0'; + return dst; +} + + +/* + * strsvis, strsvisx - visually encode characters from src into dst + * + * Extra is a pointer to a \0-terminated list of characters to + * be encoded, too. These functions are useful e. g. to + * encode strings in such a way so that they are not interpreted + * by a shell. + * + * Dst must be 4 times the size of src to account for possible + * expansion. The length of dst, not including the trailing NULL, + * is returned. + * + * Strsvisx encodes exactly len bytes from src into dst. + * This is useful for encoding a block of data. + */ +int +strsvis(char *dst, const char *csrc, int flag, const char *extra) +{ + int c; + char *start; + char *nextra = NULL; + const unsigned char *src = (const unsigned char *)csrc; + + _DIAGASSERT(dst != NULL); + _DIAGASSERT(src != NULL); + _DIAGASSERT(extra != NULL); + MAKEEXTRALIST(flag, nextra, extra); + if (!nextra) { + *dst = '\0'; /* can't create nextra, return "" */ + return 0; + } + if (flag & VIS_HTTPSTYLE) { + for (start = dst; (c = *src++) != '\0'; /* empty */) + HVIS(dst, c, flag, *src, nextra); + } else { + for (start = dst; (c = *src++) != '\0'; /* empty */) + SVIS(dst, c, flag, *src, nextra); + } + free(nextra); + *dst = '\0'; + return (dst - start); +} + + +int +strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra) +{ + unsigned char c; + char *start; + char *nextra = NULL; + const unsigned char *src = (const unsigned char *)csrc; + + _DIAGASSERT(dst != NULL); + _DIAGASSERT(src != NULL); + _DIAGASSERT(extra != NULL); + MAKEEXTRALIST(flag, nextra, extra); + if (! nextra) { + *dst = '\0'; /* can't create nextra, return "" */ + return 0; + } + + if (flag & VIS_HTTPSTYLE) { + for (start = dst; len > 0; len--) { + c = *src++; + HVIS(dst, c, flag, len ? *src : '\0', nextra); + } + } else { + for (start = dst; len > 0; len--) { + c = *src++; + SVIS(dst, c, flag, len ? *src : '\0', nextra); + } + } + free(nextra); + *dst = '\0'; + return (dst - start); +} +#endif + +#if !HAVE_VIS +/* + * vis - visually encode characters + */ +char * +vis(char *dst, int c, int flag, int nextc) +{ + char *extra = NULL; + unsigned char uc = (unsigned char)c; + + _DIAGASSERT(dst != NULL); + + MAKEEXTRALIST(flag, extra, ""); + if (! extra) { + *dst = '\0'; /* can't create extra, return "" */ + return dst; + } + if (flag & VIS_HTTPSTYLE) + HVIS(dst, uc, flag, nextc, extra); + else + SVIS(dst, uc, flag, nextc, extra); + free(extra); + *dst = '\0'; + return dst; +} + + +/* + * strvis, strvisx - visually encode characters from src into dst + * + * Dst must be 4 times the size of src to account for possible + * expansion. The length of dst, not including the trailing NULL, + * is returned. + * + * Strvisx encodes exactly len bytes from src into dst. + * This is useful for encoding a block of data. + */ +int +strvis(char *dst, const char *src, int flag) +{ + char *extra = NULL; + int rv; + + MAKEEXTRALIST(flag, extra, ""); + if (!extra) { + *dst = '\0'; /* can't create extra, return "" */ + return 0; + } + rv = strsvis(dst, src, flag, extra); + free(extra); + return rv; +} + + +int +strvisx(char *dst, const char *src, size_t len, int flag) +{ + char *extra = NULL; + int rv; + + MAKEEXTRALIST(flag, extra, ""); + if (!extra) { + *dst = '\0'; /* can't create extra, return "" */ + return 0; + } + rv = strsvisx(dst, src, len, flag, extra); + free(extra); + return rv; +} +#endif diff --git a/cpukit/libmisc/shell/vis.h b/cpukit/libmisc/shell/vis.h new file mode 100644 index 0000000000..fb0aa6dc2a --- /dev/null +++ b/cpukit/libmisc/shell/vis.h @@ -0,0 +1,91 @@ +/* $NetBSD: vis.h,v 1.16 2005/09/13 01:44:32 christos Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)vis.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _VIS_H_ +#define _VIS_H_ + +#include <sys/types.h> + +/* + * to select alternate encoding format + */ +#define VIS_OCTAL 0x01 /* use octal \ddd format */ +#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropiate */ + +/* + * to alter set of characters encoded (default is to encode all + * non-graphic except space, tab, and newline). + */ +#define VIS_SP 0x04 /* also encode space */ +#define VIS_TAB 0x08 /* also encode tab */ +#define VIS_NL 0x10 /* also encode newline */ +#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL) +#define VIS_SAFE 0x20 /* only encode "unsafe" characters */ + +/* + * other + */ +#define VIS_NOSLASH 0x40 /* inhibit printing '\' */ +#define VIS_HTTPSTYLE 0x80 /* http-style escape % HEX HEX */ + +/* + * unvis return codes + */ +#define UNVIS_VALID 1 /* character valid */ +#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */ +#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */ +#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */ +#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */ + +/* + * unvis flags + */ +#define UNVIS_END 1 /* no more characters */ + +#include <sys/cdefs.h> + +__BEGIN_DECLS +char *vis(char *, int, int, int); +char *svis(char *, int, int, int, const char *); +int strvis(char *, const char *, int); +int strsvis(char *, const char *, int, const char *); +int strvisx(char *, const char *, size_t, int); +int strsvisx(char *, const char *, size_t, int, const char *); +int strunvis(char *, const char *); +int strunvisx(char *, const char *, int); +#ifndef __LIBC12_SOURCE__ +//int unvis(char *, int, int *, int) __RENAME(__unvis13); +#endif +__END_DECLS + +#endif /* !_VIS_H_ */ diff --git a/cpukit/sapi/include/confdefs.h b/cpukit/sapi/include/confdefs.h index 3822fc3f83..346a2ee921 100644 --- a/cpukit/sapi/include/confdefs.h +++ b/cpukit/sapi/include/confdefs.h @@ -587,7 +587,7 @@ extern rtems_configuration_table Configuration; #define CONFIGURE_ATA_DRIVER_TASK_PRIORITY ATA_DRIVER_TASK_DEFAULT_PRIORITY #endif #ifdef CONFIGURE_INIT - rtems_task_priority ata_driver_task_priority + rtems_task_priority rtems_ata_driver_task_priority = CONFIGURE_ATA_DRIVER_TASK_PRIORITY; #endif /* CONFIGURE_INIT */ #endif @@ -598,13 +598,36 @@ extern rtems_configuration_table Configuration; #ifdef CONFIGURE_APPLICATION_NEEDS_LIBBLOCK #include <rtems/bdbuf.h> /* - * configure the priority of the bdbuf swapout task + * configure the bdbuf cache parameters */ + #ifndef CONFIGURE_BDBUF_MAX_READ_AHEAD_BLOCKS + #define CONFIGURE_BDBUF_MAX_READ_AHEAD_BLOCKS \ + RTEMS_BDBUF_MAX_READ_AHEAD_BLOCKS_DEFAULT + #endif + #ifndef CONFIGURE_BDBUF_MAX_WRITE_BLOCKS + #define CONFIGURE_BDBUF_MAX_WRITE_BLOCKS \ + RTEMS_BDBUF_MAX_WRITE_BLOCKS_DEFAULT + #endif #ifndef CONFIGURE_SWAPOUT_TASK_PRIORITY - #define CONFIGURE_SWAPOUT_TASK_PRIORITY SWAPOUT_TASK_DEFAULT_PRIORITY + #define CONFIGURE_SWAPOUT_TASK_PRIORITY \ + RTEMS_BDBUF_SWAPOUT_TASK_PRIORITY_DEFAULT + #endif + #ifndef CONFIGURE_SWAPOUT_SWAP_PERIOD + #define CONFIGURE_SWAPOUT_SWAP_PERIOD \ + RTEMS_BDBUF_SWAPOUT_TASK_SWAP_PERIOD_DEFAULT + #endif + #ifndef CONFIGURE_SWAPOUT_BLOCK_HOLD + #define CONFIGURE_SWAPOUT_BLOCK_HOLD \ + RTEMS_BDBUF_SWAPOUT_TASK_BLOCK_HOLD_DEFAULT #endif #ifdef CONFIGURE_INIT - rtems_task_priority swapout_task_priority = CONFIGURE_SWAPOUT_TASK_PRIORITY; + rtems_bdbuf_config rtems_bdbuf_configuration = { + CONFIGURE_BDBUF_MAX_READ_AHEAD_BLOCKS, + CONFIGURE_BDBUF_MAX_WRITE_BLOCKS, + CONFIGURE_SWAPOUT_TASK_PRIORITY, + CONFIGURE_SWAPOUT_SWAP_PERIOD, + CONFIGURE_SWAPOUT_BLOCK_HOLD + }; #endif #ifndef CONFIGURE_HAS_OWN_BDBUF_TABLE #ifndef CONFIGURE_BDBUF_BUFFER_COUNT @@ -615,11 +638,12 @@ extern rtems_configuration_table Configuration; #define CONFIGURE_BDBUF_BUFFER_SIZE 512 #endif #ifdef CONFIGURE_INIT - rtems_bdbuf_config rtems_bdbuf_configuration[] = { + rtems_bdbuf_pool_config rtems_bdbuf_pool_configuration[] = { {CONFIGURE_BDBUF_BUFFER_SIZE, CONFIGURE_BDBUF_BUFFER_COUNT, NULL} }; - int rtems_bdbuf_configuration_size =( sizeof(rtems_bdbuf_configuration) - /sizeof(rtems_bdbuf_configuration[0])); + int rtems_bdbuf_pool_configuration_size = + (sizeof(rtems_bdbuf_pool_configuration) / + sizeof(rtems_bdbuf_pool_configuration[0])); #endif /* CONFIGURE_INIT */ #endif /* CONFIGURE_HAS_OWN_BDBUF_TABLE */ #endif /* CONFIGURE_APPLICATION_NEEDS_LIBBLOCK */ diff --git a/cpukit/score/src/coremutex.c b/cpukit/score/src/coremutex.c index 6e23561f19..60a2995882 100644 --- a/cpukit/score/src/coremutex.c +++ b/cpukit/score/src/coremutex.c @@ -66,9 +66,9 @@ void _CORE_mutex_Initialize( _CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ) #ifdef __RTEMS_STRICT_ORDER_MUTEX__ - _Chain_Prepend_unprotected( &executing->lock_mutex, + _Chain_Prepend_unprotected( &_Thread_Executing->lock_mutex, &the_mutex->queue.lock_queue ); - the_mutex->queue.priority_before = executing->current_priority; + the_mutex->queue.priority_before = _Thread_Executing->current_priority; #endif _Thread_Executing->resource_count++; diff --git a/cpukit/score/src/interr.c b/cpukit/score/src/interr.c index e904815762..4431c7b313 100644 --- a/cpukit/score/src/interr.c +++ b/cpukit/score/src/interr.c @@ -61,4 +61,5 @@ void _Internal_error_Occurred( _CPU_Fatal_halt( the_error ); /* will not return from this routine */ + while (TRUE); } |