summaryrefslogtreecommitdiffstats
path: root/cpukit/libblock
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2008-01-05 06:57:17 +0000
committerChris Johns <chrisj@rtems.org>2008-01-05 06:57:17 +0000
commita5de1ef5fc5b06d300e08dae2425d1bb88985645 (patch)
tree6e06dcd3f1c8fa3d93c25e7cc0d77c51b4a99700 /cpukit/libblock
parent2008-01-03 Till Straumann <strauman@slac.stanford.edu> (diff)
downloadrtems-a5de1ef5fc5b06d300e08dae2425d1bb88985645.tar.bz2
2008-01-05 Chris Johns <chrisj@rtems.org>
* configure.ac: Fix typo in the strict order mutex CPU OPTs test. * libmisc/shell/shell.c: Handle '#' comment characters correctly. * libblock/include/rtems/flashdisk.h: Add docmentation about the control fields. Add more control fields to handle the flash when full. * libblock/src/flashdisk.c: Fix the descriptor erase test so it detects a descriptor is erased. Add support for unavailable blocks the user can configure. Print the used list as a diag. Fix the bug when a page is detected as failed and present on more than one queue. Add a count to the queues so queue length can be used to manage compaction.
Diffstat (limited to 'cpukit/libblock')
-rw-r--r--cpukit/libblock/include/rtems/flashdisk.h47
-rw-r--r--cpukit/libblock/src/flashdisk.c583
2 files changed, 379 insertions, 251 deletions
diff --git a/cpukit/libblock/include/rtems/flashdisk.h b/cpukit/libblock/include/rtems/flashdisk.h
index de63e06bbc..997dd1805c 100644
--- a/cpukit/libblock/include/rtems/flashdisk.h
+++ b/cpukit/libblock/include/rtems/flashdisk.h
@@ -57,6 +57,7 @@ typedef struct rtems_fdisk_monitor_data
{
uint32_t block_size;
uint32_t block_count;
+ uint32_t unavail_blocks;
uint32_t device_count;
uint32_t segment_count;
uint32_t page_count;
@@ -264,17 +265,47 @@ typedef struct rtems_fdisk_device_desc
/**
* RTEMS Flash Disk configuration table used to initialise the
* driver.
+ *
+ * The unavailable blocks count is the number of blocks less than the
+ * available number of blocks the file system is given. This means there
+ * will always be that number of blocks available when the file system
+ * thinks the disk is full. The compaction code needs blocks to compact
+ * with so you will never be able to have all the blocks allocated to the
+ * file system and be able to full the disk.
+ *
+ * The compacting segment count is the number of segments that are
+ * moved into a new segment. A high number will mean more segments with
+ * low active page counts and high used page counts will be moved into
+ * avaliable pages how-ever this extends the compaction time due to
+ * time it takes the erase the pages. There is no pont making this number
+ * greater than the maximum number of pages in a segment.
+ *
+ * The available compacting segment count is the level when compaction occurs
+ * when writing. If you set this to 0 then compaction will fail because
+ * there will be no segments to compact into.
+ *
+ * The info level can be 0 for off with error, and abort messages allowed.
+ * Level 1 is warning messages, level 1 is informational messages, and level 3
+ * is debugging type prints. The info level can be turned off with a compile
+ * time directive on the command line to the compiler of:
+ *
+ * -DRTEMS_FDISK_TRACE=0
*/
typedef struct rtems_flashdisk_config
{
- uint32_t block_size; /**< The block size. */
- uint32_t device_count; /**< The number of devices. */
- const rtems_fdisk_device_desc* devices; /**< The device descriptions. */
- uint32_t flags; /**< Set of flags to control
- driver. */
- uint32_t compact_segs; /**< Max number of segs to
- compact in one pass. */
- uint32_t info_level; /**< Default info level. */
+ uint32_t block_size; /**< The block size. */
+ uint32_t device_count; /**< The number of devices. */
+ const rtems_fdisk_device_desc* devices; /**< The device descriptions. */
+ uint32_t flags; /**< Set of flags to control
+ driver. */
+ uint32_t unavail_blocks; /**< Number of blocks not
+ available to the file sys. */
+ uint32_t compact_segs; /**< Max number of segs to
+ compact in one pass. */
+ uint32_t avail_compact_segs; /**< The number of segments
+ when compaction occurs
+ when writing. */
+ uint32_t info_level; /**< Default info level. */
} rtems_flashdisk_config;
/*
diff --git a/cpukit/libblock/src/flashdisk.c b/cpukit/libblock/src/flashdisk.c
index 58bdabae8c..4e8b261a93 100644
--- a/cpukit/libblock/src/flashdisk.c
+++ b/cpukit/libblock/src/flashdisk.c
@@ -204,6 +204,8 @@ typedef struct rtems_fdisk_segment_ctl
uint32_t pages_used; /**< Number of pages flagged as used. */
uint32_t pages_bad; /**< Number of pages detected as bad. */
+ uint32_t failed; /**< The segment has failed. */
+
uint32_t erased; /**< Counter to debugging. Wear support would
remove this. */
} rtems_fdisk_segment_ctl;
@@ -215,6 +217,7 @@ typedef struct rtems_fdisk_segment_ctl_queue
{
rtems_fdisk_segment_ctl* head;
rtems_fdisk_segment_ctl* tail;
+ uint32_t count;
} rtems_fdisk_segment_ctl_queue;
/**
@@ -248,12 +251,15 @@ typedef struct rtems_flashdisk
uint32_t flags; /**< configuration flags. */
uint32_t compact_segs; /**< Max segs to compact at once. */
+ uint32_t avail_compact_segs; /**< The number of segments when
+ compaction occurs when writing. */
uint32_t block_size; /**< The block size for this disk. */
rtems_fdisk_block_ctl* blocks; /**< The block to segment-page
mappings. */
- uint32_t block_count; /**< The number of available
- blocks. */
+ uint32_t block_count; /**< The number of avail. blocks. */
+ uint32_t unavail_blocks; /**< The number of unavail blocks. */
+
rtems_fdisk_device_ctl* devices; /**< The flash devices for this
disk. */
uint32_t device_count; /**< The number of flash devices. */
@@ -443,6 +449,25 @@ static void
rtems_fdisk_segment_queue_init (rtems_fdisk_segment_ctl_queue* queue)
{
queue->head = queue->tail = 0;
+ queue->count = 0;
+}
+
+/**
+ * Push to the head of the segment control queue.
+ */
+static void
+rtems_fdisk_segment_queue_push_head (rtems_fdisk_segment_ctl_queue* queue,
+ rtems_fdisk_segment_ctl* sc)
+{
+ if (sc)
+ {
+ sc->next = queue->head;
+ queue->head = sc;
+
+ if (queue->tail == 0)
+ queue->tail = sc;
+ queue->count++;
+ }
}
/**
@@ -459,6 +484,8 @@ rtems_fdisk_segment_queue_pop_head (rtems_fdisk_segment_ctl_queue* queue)
if (!queue->head)
queue->tail = 0;
+ queue->count--;
+
sc->next = 0;
return sc;
@@ -468,29 +495,6 @@ rtems_fdisk_segment_queue_pop_head (rtems_fdisk_segment_ctl_queue* queue)
}
/**
- * Push to the head of the segment control queue.
- */
-#if 0
-static void
-rtems_fdisk_segment_queue_push_head (rtems_fdisk_segment_ctl_queue* queue,
- rtems_fdisk_segment_ctl* sc)
-{
- if (sc)
- {
- if (queue->head)
- sc->next = queue->head;
- else
- {
- queue->tail = sc;
- sc->next = 0;
- }
-
- queue->head = sc;
- }
-}
-#endif
-
-/**
* Push to the tail of the segment control queue.
*/
static void
@@ -510,6 +514,8 @@ rtems_fdisk_segment_queue_push_tail (rtems_fdisk_segment_ctl_queue* queue,
{
queue->head = queue->tail = sc;
}
+
+ queue->count++;
}
}
@@ -544,6 +550,7 @@ rtems_fdisk_segment_queue_remove (rtems_fdisk_segment_ctl_queue* queue,
queue->tail = prev;
}
sc->next = 0;
+ queue->count--;
break;
}
@@ -572,6 +579,7 @@ rtems_fdisk_segment_queue_insert_before (rtems_fdisk_segment_ctl_queue* queue,
{
sc->next = item;
*prev = sc;
+ queue->count++;
return;
}
@@ -589,6 +597,15 @@ rtems_fdisk_segment_queue_insert_before (rtems_fdisk_segment_ctl_queue* queue,
static uint32_t
rtems_fdisk_segment_queue_count (rtems_fdisk_segment_ctl_queue* queue)
{
+ return queue->count;
+}
+
+/**
+ * Count the number of elements on the list.
+ */
+static uint32_t
+rtems_fdisk_segment_count_queue (rtems_fdisk_segment_ctl_queue* queue)
+{
rtems_fdisk_segment_ctl* sc = queue->head;
uint32_t count = 0;
@@ -604,7 +621,6 @@ rtems_fdisk_segment_queue_count (rtems_fdisk_segment_ctl_queue* queue)
/**
* See if a segment control is present on this queue.
*/
-#if RTEMS_FDISK_TRACE
static bool
rtems_fdisk_segment_queue_present (rtems_fdisk_segment_ctl_queue* queue,
rtems_fdisk_segment_ctl* sc)
@@ -620,22 +636,20 @@ rtems_fdisk_segment_queue_present (rtems_fdisk_segment_ctl_queue* queue,
return false;
}
-#endif
/**
- * Check if the buffer is erased.
+ * Format a string with the queue status.
*/
-static bool
-rtems_fdisk_is_erased (const void* buffer, uint32_t size)
+static void
+rtems_fdisk_queue_status (rtems_flashdisk* fd,
+ rtems_fdisk_segment_ctl* sc,
+ char queues[5])
{
- const uint8_t* p = buffer;
- uint32_t c;
- for (c = 0; c < size; c++)
- {
- if (*p != 0xff)
- return false;
- }
- return true;
+ queues[0] = rtems_fdisk_segment_queue_present (&fd->available, sc) ? 'A' : '-';
+ queues[1] = rtems_fdisk_segment_queue_present (&fd->used, sc) ? 'U' : '-';
+ queues[2] = rtems_fdisk_segment_queue_present (&fd->erase, sc) ? 'E' : '-';
+ queues[3] = rtems_fdisk_segment_queue_present (&fd->failed, sc) ? 'F' : '-';
+ queues[4] = '\0';
}
/**
@@ -644,7 +658,9 @@ rtems_fdisk_is_erased (const void* buffer, uint32_t size)
static bool
rtems_fdisk_page_desc_erased (const rtems_fdisk_page_desc* pd)
{
- return rtems_fdisk_is_erased (pd, sizeof (rtems_fdisk_page_desc));
+ return ((pd->crc == 0xffff) &&
+ (pd->flags == 0xffff) &&
+ (pd->block == 0xffffffff)) ? true : false;
}
/**
@@ -1126,7 +1142,9 @@ rtems_fdisk_erase_segment (rtems_flashdisk* fd, rtems_fdisk_segment_ctl* sc)
rtems_fdisk_error (" erase-segment:%02d-%03d: " \
"segment erase failed: %s (%d)",
sc->device, sc->segment, strerror (ret), ret);
- rtems_fdisk_segment_queue_push_tail (&fd->failed, sc);
+ sc->failed = true;
+ if (!rtems_fdisk_segment_queue_present (&fd->failed, sc))
+ rtems_fdisk_segment_queue_push_tail (&fd->failed, sc);
return ret;
}
@@ -1137,6 +1155,8 @@ rtems_fdisk_erase_segment (rtems_flashdisk* fd, rtems_fdisk_segment_ctl* sc)
sc->pages_active = 0;
sc->pages_used = 0;
sc->pages_bad = 0;
+
+ sc->failed = false;
/*
* Push to the tail of the available queue. It is a very
@@ -1183,13 +1203,24 @@ static void
rtems_fdisk_queue_segment (rtems_flashdisk* fd, rtems_fdisk_segment_ctl* sc)
{
#if RTEMS_FDISK_TRACE
- rtems_fdisk_info (fd, " queue-seg:%02d-%03d: p=%d a=%d u=%d b=%d n=%s",
+ rtems_fdisk_info (fd, " queue-seg:%02d-%03d: p=%d a=%d u=%d b=%d f=%s n=%s",
sc->device, sc->segment,
sc->pages, sc->pages_active, sc->pages_used, sc->pages_bad,
- sc->next ? "set" : "null");
+ sc->failed ? "FAILED" : "no", sc->next ? "set" : "null");
#endif
/*
+ * If the segment has failed then check the failed queue and append
+ * if not failed.
+ */
+ if (sc->failed)
+ {
+ if (!rtems_fdisk_segment_queue_present (&fd->failed, sc))
+ rtems_fdisk_segment_queue_push_tail (&fd->failed, sc);
+ return;
+ }
+
+ /*
* Remove the queue from the available or used queue.
*/
rtems_fdisk_segment_queue_remove (&fd->available, sc);
@@ -1207,10 +1238,9 @@ rtems_fdisk_queue_segment (rtems_flashdisk* fd, rtems_fdisk_segment_ctl* sc)
if (sc->pages_active)
{
/*
- * Keep the used queue sorted on the least number
- * of pages. When we compact we want to move the
- * pages into a new segment and cover more than one
- * segment.
+ * Keep the used queue sorted by the most number of used
+ * pages. When we compact we want to move the pages into
+ * a new segment and cover more than one segment.
*/
rtems_fdisk_segment_ctl* seg = fd->used.head;
@@ -1293,178 +1323,196 @@ rtems_fdisk_compact (rtems_flashdisk* fd)
while (fd->used.head)
{
rtems_fdisk_segment_ctl* dsc;
+ rtems_fdisk_segment_ctl* ssc;
+ uint32_t dst_pages;
+ uint32_t segments;
+ uint32_t pages;
+#if RTEMS_FDISK_TRACE
+ rtems_fdisk_printf (fd, " compacting");
+#endif
+
dsc = rtems_fdisk_seg_most_available (&fd->available);
- if (dsc)
+ if (dsc == 0)
{
- rtems_fdisk_segment_ctl* ssc = fd->used.head;
- uint32_t dst_pages = rtems_fdisk_seg_pages_available (dsc);
- uint32_t segments = 0;
- uint32_t pages = 0;
-
+ rtems_fdisk_error ("compacting: no available segments to compact too");
+ return EIO;
+ }
+
+ ssc = fd->used.head;
+ dst_pages = rtems_fdisk_seg_pages_available (dsc);
+ segments = 0;
+ pages = 0;
+
#if RTEMS_FDISK_TRACE
- rtems_fdisk_printf (fd, "dsc: %d-%d", dsc->device, dsc->segment);
+ rtems_fdisk_printf (fd, " dsc:%02d-%03d: most available",
+ dsc->device, dsc->segment);
#endif
- /*
- * Count the number of segments that have active pages that fit into
- * the destination segment. Also limit the number of segments that
- * we handle during one compaction. A lower number means less aggressive
- * compaction or less delay when compacting but it may mean the disk
- * will fill.
- */
+ /*
+ * Count the number of segments that have active pages that fit into
+ * the destination segment. Also limit the number of segments that
+ * we handle during one compaction. A lower number means less aggressive
+ * compaction or less delay when compacting but it may mean the disk
+ * will fill.
+ */
- while (ssc &&
- ((pages + ssc->pages_active) < dst_pages) &&
- ((compacted_segs + segments) < fd->compact_segs))
- {
- pages += ssc->pages_active;
- segments++;
- ssc = ssc->next;
- }
+ while (ssc &&
+ ((pages + ssc->pages_active) < dst_pages) &&
+ ((compacted_segs + segments) < fd->compact_segs))
+ {
+ pages += ssc->pages_active;
+ segments++;
+ ssc = ssc->next;
+ }
- /*
- * We need a source segment and have pages to copy and
- * compacting one segment to another is silly. Compaction needs
- * to free at least one more segment.
- */
+ /*
+ * We need a source segment and have pages to copy and
+ * compacting one segment to another is silly. Compaction needs
+ * to free at least one more segment.
+ */
- if (!ssc || (pages == 0) || ((compacted_segs + segments) == 1))
- break;
+ if (!ssc || (pages == 0) || ((compacted_segs + segments) == 1))
+ break;
#if RTEMS_FDISK_TRACE
- rtems_fdisk_printf (fd, "ssc scan: %d-%d: p=%ld, seg=%ld",
- ssc->device, ssc->segment,
- pages, segments);
+ rtems_fdisk_printf (fd, " ssc scan: %d-%d: p=%ld, seg=%ld",
+ ssc->device, ssc->segment,
+ pages, segments);
#endif
- rtems_fdisk_segment_queue_remove (&fd->available, dsc);
+ rtems_fdisk_segment_queue_remove (&fd->available, dsc);
- /*
- * We now copy the pages to the new segment.
- */
+ /*
+ * We now copy the pages to the new segment.
+ */
- while (pages)
- {
- uint32_t spage;
- int ret;
+ while (pages)
+ {
+ uint32_t spage;
+ int ret;
- ssc = rtems_fdisk_segment_queue_pop_head (&fd->used);
+ ssc = rtems_fdisk_segment_queue_pop_head (&fd->used);
- if (ssc)
+ if (ssc)
+ {
+ uint32_t used = 0;
+ uint32_t active = 0;
+ for (spage = 0; spage < ssc->pages; spage++)
{
- uint32_t used = 0;
- uint32_t active = 0;
- for (spage = 0; spage < ssc->pages; spage++)
- {
- rtems_fdisk_page_desc* spd = &ssc->page_descriptors[spage];
+ rtems_fdisk_page_desc* spd = &ssc->page_descriptors[spage];
- if (rtems_fdisk_page_desc_flags_set (spd, RTEMS_FDISK_PAGE_ACTIVE) &&
- !rtems_fdisk_page_desc_flags_set (spd, RTEMS_FDISK_PAGE_USED))
- {
- rtems_fdisk_page_desc* dpd;
- uint32_t dpage;
+ if (rtems_fdisk_page_desc_flags_set (spd, RTEMS_FDISK_PAGE_ACTIVE) &&
+ !rtems_fdisk_page_desc_flags_set (spd, RTEMS_FDISK_PAGE_USED))
+ {
+ rtems_fdisk_page_desc* dpd;
+ uint32_t dpage;
- dpage = rtems_fdisk_seg_next_available_page (dsc);
- dpd = &dsc->page_descriptors[dpage];
+ dpage = rtems_fdisk_seg_next_available_page (dsc);
+ dpd = &dsc->page_descriptors[dpage];
- active++;
+ active++;
- if (dpage >= dsc->pages)
- {
- rtems_fdisk_error ("compacting: %02d-%03d: " \
- "no page desc available: %d",
- dsc->device, dsc->segment,
- rtems_fdisk_seg_pages_available (dsc));
- rtems_fdisk_segment_queue_push_tail (&fd->failed, dsc);
- return EIO;
- }
+ if (dpage >= dsc->pages)
+ {
+ rtems_fdisk_error ("compacting: %02d-%03d: " \
+ "no page desc available: %d",
+ dsc->device, dsc->segment,
+ rtems_fdisk_seg_pages_available (dsc));
+ dsc->failed = true;
+ rtems_fdisk_queue_segment (fd, dsc);
+ rtems_fdisk_segment_queue_push_head (&fd->used, ssc);
+ return EIO;
+ }
#if RTEMS_FDISK_TRACE
- rtems_fdisk_info (fd, "compacting: %02d-%03d-%03d=>%02d-%03d-%03d",
- ssc->device, ssc->segment, spage,
- dsc->device, dsc->segment, dpage);
+ rtems_fdisk_info (fd, "compacting: %02d-%03d-%03d=>%02d-%03d-%03d",
+ ssc->device, ssc->segment, spage,
+ dsc->device, dsc->segment, dpage);
#endif
- ret = rtems_fdisk_seg_copy_page (fd, ssc->device, ssc->segment,
- spage + ssc->pages_desc,
- dsc->device, dsc->segment,
- dpage + dsc->pages_desc);
- if (ret)
- {
- rtems_fdisk_error ("compacting: %02d-%03d-%03d=>" \
- "%02d-%03d-%03d: " \
- "copy page failed: %s (%d)",
- ssc->device, ssc->segment, spage,
- dsc->device, dsc->segment, dpage,
- strerror (ret), ret);
- rtems_fdisk_segment_queue_push_tail (&fd->failed, dsc);
- return ret;
- }
-
- *dpd = *spd;
-
- ret = rtems_fdisk_seg_write_page_desc (fd,
- dsc->device, dsc->segment,
- dpage, dpd);
-
- if (ret)
- {
- rtems_fdisk_error ("compacting: %02d-%03d-%03d=>" \
- "%02d-%03d-%03d: copy pd failed: %s (%d)",
- ssc->device, ssc->segment, spage,
- dsc->device, dsc->segment, dpage,
- strerror (ret), ret);
- rtems_fdisk_segment_queue_push_tail (&fd->failed, dsc);
- return ret;
- }
-
- dsc->pages_active++;
+ ret = rtems_fdisk_seg_copy_page (fd, ssc->device, ssc->segment,
+ spage + ssc->pages_desc,
+ dsc->device, dsc->segment,
+ dpage + dsc->pages_desc);
+ if (ret)
+ {
+ rtems_fdisk_error ("compacting: %02d-%03d-%03d=>" \
+ "%02d-%03d-%03d: " \
+ "copy page failed: %s (%d)",
+ ssc->device, ssc->segment, spage,
+ dsc->device, dsc->segment, dpage,
+ strerror (ret), ret);
+ dsc->failed = true;
+ rtems_fdisk_queue_segment (fd, dsc);
+ rtems_fdisk_segment_queue_push_head (&fd->used, ssc);
+ return ret;
+ }
- /*
- * No need to set the used bit on the source page as the
- * segment will be erased. Power down could be a problem.
- * We do the stats to make sure everything is as it should
- * be.
- */
+ *dpd = *spd;
+
+ ret = rtems_fdisk_seg_write_page_desc (fd,
+ dsc->device, dsc->segment,
+ dpage, dpd);
+
+ if (ret)
+ {
+ rtems_fdisk_error ("compacting: %02d-%03d-%03d=>" \
+ "%02d-%03d-%03d: copy pd failed: %s (%d)",
+ ssc->device, ssc->segment, spage,
+ dsc->device, dsc->segment, dpage,
+ strerror (ret), ret);
+ dsc->failed = true;
+ rtems_fdisk_queue_segment (fd, dsc);
+ rtems_fdisk_segment_queue_push_head (&fd->used, ssc);
+ return ret;
+ }
+
+ dsc->pages_active++;
+
+ /*
+ * No need to set the used bit on the source page as the
+ * segment will be erased. Power down could be a problem.
+ * We do the stats to make sure everything is as it should
+ * be.
+ */
- ssc->pages_active--;
- ssc->pages_used++;
+ ssc->pages_active--;
+ ssc->pages_used++;
- fd->blocks[spd->block].segment = dsc;
- fd->blocks[spd->block].page = dpage;
+ fd->blocks[spd->block].segment = dsc;
+ fd->blocks[spd->block].page = dpage;
- /*
- * Place the segment on to the correct queue.
- */
- rtems_fdisk_queue_segment (fd, dsc);
+ /*
+ * Place the segment on to the correct queue.
+ */
+ rtems_fdisk_queue_segment (fd, dsc);
- pages--;
- }
- else
- used++;
+ pages--;
}
+ else
+ used++;
+ }
#if RTEMS_FDISK_TRACE
- rtems_fdisk_printf (fd, "ssc end: %d-%d: p=%ld, a=%ld, u=%ld",
- ssc->device, ssc->segment,
- pages, active, used);
+ rtems_fdisk_printf (fd, "ssc end: %d-%d: p=%ld, a=%ld, u=%ld",
+ ssc->device, ssc->segment,
+ pages, active, used);
#endif
- if (ssc->pages_active != 0)
- {
- rtems_fdisk_error ("compacting: ssc pages not 0: %d",
- ssc->pages_active);
- }
+ if (ssc->pages_active != 0)
+ {
+ rtems_fdisk_error ("compacting: ssc pages not 0: %d",
+ ssc->pages_active);
+ }
- ret = rtems_fdisk_erase_segment (fd, ssc);
+ ret = rtems_fdisk_erase_segment (fd, ssc);
- if (ret)
- return ret;
- }
+ if (ret)
+ return ret;
}
-
- compacted_segs += segments;
}
+
+ compacted_segs += segments;
}
return 0;
@@ -1516,7 +1564,9 @@ rtems_fdisk_recover_block_mappings (rtems_flashdisk* fd)
sc->pages_active = 0;
sc->pages_used = 0;
sc->pages_bad = 0;
-
+
+ sc->failed = false;
+
if (!sc->page_descriptors)
sc->page_descriptors = malloc (sc->pages_desc * fd->block_size);
@@ -1574,8 +1624,11 @@ rtems_fdisk_recover_block_mappings (rtems_flashdisk* fd)
page, pd);
if (ret)
+ {
rtems_fdisk_error ("forcing page to used failed: %d-%d-%d",
device, segment, page);
+ sc->failed = true;
+ }
sc->pages_used++;
}
@@ -1664,13 +1717,17 @@ rtems_fdisk_read_block (rtems_flashdisk* fd,
rtems_fdisk_segment_ctl* sc;
rtems_fdisk_page_desc* pd;
+#if RTEMS_FDISK_TRACE
+ rtems_fdisk_info (fd, "read-block:%d", block);
+#endif
+
/*
* Broken out to allow info messages when testing.
*/
- if (block >= fd->block_count)
+ if (block >= (fd->block_count - fd->unavail_blocks))
{
- rtems_fdisk_error ("read-block: bad block: %d", block);
+ rtems_fdisk_error ("read-block: block out of range: %d", block);
return EIO;
}
@@ -1690,7 +1747,7 @@ rtems_fdisk_read_block (rtems_flashdisk* fd,
#if RTEMS_FDISK_TRACE
rtems_fdisk_info (fd,
- "read-block:%d=>%02d-%03d-%03d: p=%d a=%d u=%d b=%d n=%s: " \
+ " read:%d=>%02d-%03d-%03d: p=%d a=%d u=%d b=%d n=%s: " \
"f=%04x c=%04x b=%d",
block, sc->device, sc->segment, bc->page,
sc->pages, sc->pages_active, sc->pages_used, sc->pages_bad,
@@ -1781,14 +1838,17 @@ rtems_fdisk_write_block (rtems_flashdisk* fd,
uint32_t page;
int ret;
+#if RTEMS_FDISK_TRACE
+ rtems_fdisk_info (fd, "write-block:%d", block);
+#endif
/*
* Broken out to allow info messages when testing.
*/
- if (block >= fd->block_count)
+ if (block >= (fd->block_count - fd->unavail_blocks))
{
- rtems_fdisk_error ("write-block: bad block: %d", block);
+ rtems_fdisk_error ("write-block: block out of range: %d", block);
return EIO;
}
@@ -1802,6 +1862,11 @@ rtems_fdisk_write_block (rtems_flashdisk* fd,
sc = bc->segment;
pd = &sc->page_descriptors[bc->page];
+#if RTEMS_FDISK_TRACE
+ rtems_fdisk_info (fd, " write:%02d-%03d-%03d: flag used",
+ sc->device, sc->segment, bc->page);
+#endif
+
/*
* The page exists in flash so see if the page has been changed.
*/
@@ -1830,16 +1895,19 @@ rtems_fdisk_write_block (rtems_flashdisk* fd,
if (ret)
{
#if RTEMS_FDISK_TRACE
- rtems_fdisk_info (fd, "write-block:%02d-%03d-%03d: " \
+ rtems_fdisk_info (fd, " write:%02d-%03d-%03d: " \
"write used page desc failed: %s (%d)",
sc->device, sc->segment, bc->page,
strerror (ret), ret);
#endif
+ sc->failed = true;
}
-
- sc->pages_active--;
- sc->pages_used++;
-
+ else
+ {
+ sc->pages_active--;
+ sc->pages_used++;
+ }
+
/*
* If possible reuse this segment. This will mean the segment
* needs to be removed from the available list and placed
@@ -1857,6 +1925,15 @@ rtems_fdisk_write_block (rtems_flashdisk* fd,
}
/*
+ * Is it time to compact the disk ?
+ *
+ * We override the background compaction configruation.
+ */
+ if (rtems_fdisk_segment_count_queue (&fd->available) <=
+ fd->avail_compact_segs)
+ rtems_fdisk_compact (fd);
+
+ /*
* Get the next avaliable segment.
*/
sc = rtems_fdisk_segment_queue_pop_head (&fd->available);
@@ -1885,6 +1962,16 @@ rtems_fdisk_write_block (rtems_flashdisk* fd,
}
}
+#if RTEMS_FDISK_TRACE
+ if (fd->info_level >= 3)
+ {
+ char queues[5];
+ rtems_fdisk_queue_status (fd, sc, queues);
+ rtems_fdisk_info (fd, " write:%d=>%02d-%03d: queue check: %s",
+ block, sc->device, sc->segment, queues);
+ }
+#endif
+
/*
* Find the next avaliable page in the segment.
*/
@@ -1904,7 +1991,7 @@ rtems_fdisk_write_block (rtems_flashdisk* fd,
rtems_fdisk_page_desc_set_flags (pd, RTEMS_FDISK_PAGE_ACTIVE);
#if RTEMS_FDISK_TRACE
- rtems_fdisk_info (fd, "write-block:%d=>%02d-%03d-%03d: " \
+ rtems_fdisk_info (fd, " write:%d=>%02d-%03d-%03d: write: " \
"p=%d a=%d u=%d b=%d n=%s: f=%04x c=%04x b=%d",
block, sc->device, sc->segment, page,
sc->pages, sc->pages_active, sc->pages_used,
@@ -1925,36 +2012,38 @@ rtems_fdisk_write_block (rtems_flashdisk* fd,
"%s (%d)", sc->device, sc->segment, page,
strerror (ret), ret);
#endif
- rtems_fdisk_segment_queue_push_tail (&fd->failed, sc);
- return ret;
+ sc->failed = true;
}
-
- ret = rtems_fdisk_seg_write_page_desc (fd, sc->device, sc->segment,
- page, pd);
- if (ret)
+ else
{
+ ret = rtems_fdisk_seg_write_page_desc (fd, sc->device, sc->segment,
+ page, pd);
+ if (ret)
+ {
#if RTEMS_FDISK_TRACE
- rtems_fdisk_info (fd, "write-block:%02d-%03d-%03d: " \
- "write page desc failed: %s (%d)",
- sc->device, sc->segment, bc->page,
- strerror (ret), ret);
+ rtems_fdisk_info (fd, "write-block:%02d-%03d-%03d: " \
+ "write page desc failed: %s (%d)",
+ sc->device, sc->segment, bc->page,
+ strerror (ret), ret);
#endif
- rtems_fdisk_segment_queue_push_tail (&fd->failed, sc);
- return ret;
+ sc->failed = true;
+ }
+ else
+ {
+ sc->pages_active++;
+ }
}
-
- sc->pages_active++;
-
+
rtems_fdisk_queue_segment (fd, sc);
-
- return 0;
+ return ret;
}
}
rtems_fdisk_error ("write-block: no erased page descs in segment: %d-%d",
sc->device, sc->segment);
- rtems_fdisk_segment_queue_push_tail (&fd->failed, sc);
+ sc->failed = true;
+ rtems_fdisk_queue_segment (fd, sc);
return EIO;
}
@@ -2083,6 +2172,7 @@ rtems_fdisk_monitoring_data (rtems_flashdisk* fd,
data->block_size = fd->block_size;
data->block_count = fd->block_count;
+ data->unavail_blocks = fd->unavail_blocks;
data->device_count = fd->device_count;
data->blocks_used = 0;
@@ -2090,9 +2180,9 @@ rtems_fdisk_monitoring_data (rtems_flashdisk* fd,
if (fd->blocks[i].segment)
data->blocks_used++;
- data->segs_available = rtems_fdisk_segment_queue_count (&fd->available);
- data->segs_used = rtems_fdisk_segment_queue_count (&fd->used);
- data->segs_failed = rtems_fdisk_segment_queue_count (&fd->failed);
+ data->segs_available = rtems_fdisk_segment_count_queue (&fd->available);
+ data->segs_used = rtems_fdisk_segment_count_queue (&fd->used);
+ data->segs_failed = rtems_fdisk_segment_count_queue (&fd->failed);
data->segment_count = 0;
data->page_count = 0;
@@ -2141,18 +2231,23 @@ rtems_fdisk_print_status (rtems_flashdisk* fd)
"Flash Disk Driver Status : %d.%d", fd->major, fd->minor);
rtems_fdisk_printf (fd, "Block count\t%d", fd->block_count);
- count = rtems_fdisk_segment_queue_count (&fd->available);
+ rtems_fdisk_printf (fd, "Unavail blocks\t%d", fd->unavail_blocks);
+ count = rtems_fdisk_segment_count_queue (&fd->available);
total = count;
- rtems_fdisk_printf (fd, "Available queue\t%ld", count);
- count = rtems_fdisk_segment_queue_count (&fd->used);
+ rtems_fdisk_printf (fd, "Available queue\t%ld (%ld)",
+ count, rtems_fdisk_segment_queue_count (&fd->available));
+ count = rtems_fdisk_segment_count_queue (&fd->used);
total += count;
- rtems_fdisk_printf (fd, "Used queue\t%ld", count);
- count = rtems_fdisk_segment_queue_count (&fd->erase);
+ rtems_fdisk_printf (fd, "Used queue\t%ld (%ld)",
+ count, rtems_fdisk_segment_queue_count (&fd->used));
+ count = rtems_fdisk_segment_count_queue (&fd->erase);
total += count;
- rtems_fdisk_printf (fd, "Erase queue\t%ld", count);
- count = rtems_fdisk_segment_queue_count (&fd->failed);
+ rtems_fdisk_printf (fd, "Erase queue\t%ld (%ld)",
+ count, rtems_fdisk_segment_queue_count (&fd->erase));
+ count = rtems_fdisk_segment_count_queue (&fd->failed);
total += count;
- rtems_fdisk_printf (fd, "Failed queue\t%ld", count);
+ rtems_fdisk_printf (fd, "Failed queue\t%ld (%ld)",
+ count, rtems_fdisk_segment_queue_count (&fd->failed));
count = 0;
for (device = 0; device < fd->device_count; device++)
@@ -2182,21 +2277,8 @@ rtems_fdisk_print_status (rtems_flashdisk* fd)
bool is_active = false;
char queues[5];
- queues[0] = '-';
- queues[1] = '-';
- queues[2] = '-';
- queues[3] = '-';
- queues[4] = '\0';
-
- if (rtems_fdisk_segment_queue_present (&fd->available, sc))
- queues[0] = 'A';
- if (rtems_fdisk_segment_queue_present (&fd->used, sc))
- queues[1] = 'U';
- if (rtems_fdisk_segment_queue_present (&fd->erase, sc))
- queues[2] = 'E';
- if (rtems_fdisk_segment_queue_present (&fd->failed, sc))
- queues[3] = 'F';
-
+ rtems_fdisk_queue_status (fd, sc, queues);
+
for (page = 0; page < sc->pages; page++)
{
if (rtems_fdisk_page_desc_erased (&sc->page_descriptors[page]))
@@ -2241,7 +2323,19 @@ rtems_fdisk_print_status (rtems_flashdisk* fd)
count);
}
}
-
+
+ {
+ rtems_fdisk_segment_ctl* sc = fd->used.head;
+ int count = 0;
+ rtems_fdisk_printf (fd, "Used List:");
+ while (sc)
+ {
+ rtems_fdisk_printf (fd, " %3d %02d:%03d u:%3ld",
+ count, sc->device, sc->segment, sc->pages_used);
+ sc = sc->next;
+ count++;
+ }
+ }
fd->info_level = current_info_level;
return 0;
@@ -2382,18 +2476,21 @@ rtems_fdisk_initialize (rtems_device_major_number major,
snprintf (name, sizeof (name),
RTEMS_FLASHDISK_DEVICE_BASE_NAME "%" PRIu32, minor);
- fd->major = major;
- fd->minor = minor;
- fd->flags = c->flags;
- fd->compact_segs = c->compact_segs;
- fd->block_size = c->block_size;
- fd->info_level = c->info_level;
+ fd->major = major;
+ fd->minor = minor;
+ fd->flags = c->flags;
+ fd->compact_segs = c->compact_segs;
+ fd->avail_compact_segs = c->avail_compact_segs;
+ fd->block_size = c->block_size;
+ fd->unavail_blocks = c->unavail_blocks;
+ fd->info_level = c->info_level;
for (device = 0; device < c->device_count; device++)
blocks += rtems_fdisk_blocks_in_device (&c->devices[device],
c->block_size);
- sc = rtems_disk_create_phys(dev, c->block_size, blocks,
+ sc = rtems_disk_create_phys(dev, c->block_size,
+ blocks - fd->unavail_blocks,
rtems_fdisk_ioctl, name);
if (sc != RTEMS_SUCCESSFUL)
{