summaryrefslogtreecommitdiffstats
path: root/cpukit/libblock
diff options
context:
space:
mode:
authorThomas Doerfler <Thomas.Doerfler@embedded-brains.de>2010-01-26 15:09:03 +0000
committerThomas Doerfler <Thomas.Doerfler@embedded-brains.de>2010-01-26 15:09:03 +0000
commite7fb54eb0593f80966502ca9b3cc2159e5e4a863 (patch)
treeaf42febc3419f1f4cc7ab383825b9db24b6a499f /cpukit/libblock
parentUser extension API: add const to some params, inline _User_extensions_Add_API... (diff)
downloadrtems-e7fb54eb0593f80966502ca9b3cc2159e5e4a863.tar.bz2
add purge capability to libblock, add proper test case
Diffstat (limited to 'cpukit/libblock')
-rw-r--r--cpukit/libblock/include/rtems/bdbuf.h67
-rw-r--r--cpukit/libblock/src/bdbuf.c376
2 files changed, 318 insertions, 125 deletions
diff --git a/cpukit/libblock/include/rtems/bdbuf.h b/cpukit/libblock/include/rtems/bdbuf.h
index f4e87568da..66a9bbf59b 100644
--- a/cpukit/libblock/include/rtems/bdbuf.h
+++ b/cpukit/libblock/include/rtems/bdbuf.h
@@ -86,7 +86,9 @@ extern "C" {
* ac [label="ACCESS CACHED",style="filled",fillcolor="royalblue"];
* am [label="ACCESS MODIFIED",style="filled",fillcolor="royalblue"];
* ae [label="ACCESS EMPTY",style="filled",fillcolor="royalblue"];
+ * ap [label="ACCESS PURGED",style="filled",fillcolor="royalblue"];
* t [label="TRANSFER",style="filled",fillcolor="red"];
+ * tp [label="TRANSFER PURGED",style="filled",fillcolor="red"];
* s [label="SYNC",style="filled",fillcolor="red"];
* m [label="MODIFIED",style="filled",fillcolor="gold"];
* i [label="INITIAL"];
@@ -97,26 +99,33 @@ extern "C" {
* i -> f [label="Init"];
* f -> e [label="Buffer Recycle"];
* e -> ae [label="Get"];
- * e -> t [label="Read\nRead Ahead"];
- * c -> f [label="Reallocate\nBlock Size Changed"];
+ * e -> t [label="Read"];
+ * e -> f [label="Nobody Waits"];
* c -> ac [label="Get\nRead"];
- * c -> e [label="Buffer Recycle"];
+ * c -> e [label="Buffer Recycle\nPurge"];
+ * c -> f [label="Reallocate\nBlock Size Changed"];
* t -> c [label="Transfer Done",color="red",fontcolor="red"];
- * t -> e [label="Transfer Error With Waiter",color="red",fontcolor="red"];
- * t -> f [label="Transfer Error Without Waiter",color="red",fontcolor="red"];
+ * t -> e [label="Transfer Error",color="red",fontcolor="red"];
+ * t -> tp [label="Purge"];
+ * tp -> e [label="Transfer Done\nTransfer Error",color="red",fontcolor="red"];
* m -> t [label="Swapout"];
* m -> s [label="Block Size Changed"];
* m -> am [label="Get\nRead"];
+ * m -> e [label="Purge"];
* ac -> m [label="Release Modified",color="royalblue",fontcolor="royalblue"];
* ac -> s [label="Sync",color="royalblue",fontcolor="royalblue"];
* ac -> c [label="Release",color="royalblue",fontcolor="royalblue"];
+ * ac -> ap [label="Purge"];
* am -> m [label="Release\nRelease Modified",color="royalblue",fontcolor="royalblue"];
* am -> s [label="Sync",color="royalblue",fontcolor="royalblue"];
+ * am -> ap [label="Purge"];
* ae -> m [label="Release Modified",color="royalblue",fontcolor="royalblue"];
* ae -> s [label="Sync",color="royalblue",fontcolor="royalblue"];
- * ae -> e [label="Release With Waiter",color="royalblue",fontcolor="royalblue"];
- * ae -> f [label="Release Without Waiter",color="royalblue",fontcolor="royalblue"];
+ * ae -> e [label="Release",color="royalblue",fontcolor="royalblue"];
+ * ae -> ap [label="Purge"];
+ * ap -> e [label="Release\nRelease Modified\nSync",color="royalblue",fontcolor="royalblue"];
* s -> t [label="Swapout"];
+ * s -> e [label="Purge",color="red",fontcolor="red"];
* }
* @enddot
*
@@ -184,22 +193,26 @@ extern "C" {
* </tr>
* <tr>
* <td>EMPTY</td><td></td><td>X</td>
- * <td>X</td><td></td><td></td><td></td><td></td>
+ * <td></td><td></td><td></td><td></td><td></td>
* </tr>
* <tr>
* <td>CACHED</td><td>X</td><td>X</td>
* <td>X</td><td></td><td></td><td></td><td></td>
* </tr>
* <tr>
- * <td>ACCESS_CACHED</td><td>X</td><td>X</td>
+ * <td>ACCESS CACHED</td><td>X</td><td>X</td>
+ * <td></td><td></td><td></td><td>X</td><td>X</td>
+ * </tr>
+ * <tr>
+ * <td>ACCESS MODIFIED</td><td>X</td><td>X</td>
* <td></td><td></td><td></td><td>X</td><td>X</td>
* </tr>
* <tr>
- * <td>ACCESS_MODIFIED</td><td>X</td><td>X</td>
+ * <td>ACCESS EMPTY</td><td></td><td>X</td>
* <td></td><td></td><td></td><td>X</td><td>X</td>
* </tr>
* <tr>
- * <td>ACCESS_EMPTY</td><td></td><td>X</td>
+ * <td>ACCESS PURGED</td><td></td><td>X</td>
* <td></td><td></td><td></td><td>X</td><td>X</td>
* </tr>
* <tr>
@@ -214,6 +227,10 @@ extern "C" {
* <td>TRANSFER</td><td>X</td><td>X</td>
* <td></td><td></td><td></td><td>X</td><td>X</td>
* </tr>
+ * <tr>
+ * <td>TRANSFER PURGED</td><td></td><td>X</td>
+ * <td></td><td></td><td></td><td>X</td><td>X</td>
+ * </tr>
* </table>
*/
typedef enum
@@ -249,6 +266,11 @@ typedef enum
RTEMS_BDBUF_STATE_ACCESS_EMPTY,
/**
+ * @brief Accessed by upper layer with purged data.
+ */
+ RTEMS_BDBUF_STATE_ACCESS_PURGED,
+
+ /**
* @brief Modified by upper layer.
*/
RTEMS_BDBUF_STATE_MODIFIED,
@@ -261,7 +283,12 @@ typedef enum
/**
* @brief In transfer by block device driver.
*/
- RTEMS_BDBUF_STATE_TRANSFER
+ RTEMS_BDBUF_STATE_TRANSFER,
+
+ /**
+ * @brief In transfer by block device driver and purged.
+ */
+ RTEMS_BDBUF_STATE_TRANSFER_PURGED
} rtems_bdbuf_buf_state;
/**
@@ -542,6 +569,22 @@ rtems_bdbuf_sync (rtems_bdbuf_buffer* bd);
rtems_status_code
rtems_bdbuf_syncdev (dev_t dev);
+/**
+ * @brief Purges all buffers that matches the device identifier @a dev.
+ *
+ * This may result in loss of data.
+ */
+void
+rtems_bdbuf_purge_dev (dev_t dev);
+
+/**
+ * @brief Purges all buffers that matches the device major number @a major.
+ *
+ * This may result in loss of data.
+ */
+void
+rtems_bdbuf_purge_major (rtems_device_major_number major);
+
/** @} */
#ifdef __cplusplus
diff --git a/cpukit/libblock/src/bdbuf.c b/cpukit/libblock/src/bdbuf.c
index 056a7c8ec2..862591503f 100644
--- a/cpukit/libblock/src/bdbuf.c
+++ b/cpukit/libblock/src/bdbuf.c
@@ -144,6 +144,7 @@ typedef struct rtems_bdbuf_cache
#define RTEMS_BLKDEV_FATAL_ERROR(n) \
(((uint32_t)'B' << 24) | ((uint32_t)(n) & (uint32_t)0x00FFFFFF))
+#define RTEMS_BLKDEV_FATAL_BDBUF_STATE_11 RTEMS_BLKDEV_FATAL_ERROR(1)
#define RTEMS_BLKDEV_FATAL_BDBUF_STATE_4 RTEMS_BLKDEV_FATAL_ERROR(2)
#define RTEMS_BLKDEV_FATAL_BDBUF_STATE_5 RTEMS_BLKDEV_FATAL_ERROR(3)
#define RTEMS_BLKDEV_FATAL_BDBUF_STATE_6 RTEMS_BLKDEV_FATAL_ERROR(4)
@@ -1033,6 +1034,62 @@ rtems_bdbuf_has_buffer_waiters (void)
}
static void
+rtems_bdbuf_remove_from_tree (rtems_bdbuf_buffer *bd)
+{
+ if (rtems_bdbuf_avl_remove (&bdbuf_cache.tree, bd) != 0)
+ rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_TREE_RM);
+}
+
+static void
+rtems_bdbuf_remove_from_tree_and_lru_list (rtems_bdbuf_buffer *bd)
+{
+ switch (bd->state)
+ {
+ case RTEMS_BDBUF_STATE_FREE:
+ break;
+ case RTEMS_BDBUF_STATE_CACHED:
+ rtems_bdbuf_remove_from_tree (bd);
+ break;
+ default:
+ rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_10);
+ }
+
+ rtems_chain_extract (&bd->link);
+}
+
+static void
+rtems_bdbuf_make_free_and_add_to_lru_list (rtems_bdbuf_buffer *bd)
+{
+ rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_FREE);
+ rtems_chain_prepend (&bdbuf_cache.lru, &bd->link);
+}
+
+static void
+rtems_bdbuf_make_empty (rtems_bdbuf_buffer *bd)
+{
+ rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_EMPTY);
+}
+
+static void
+rtems_bdbuf_make_cached_and_add_to_lru_list (rtems_bdbuf_buffer *bd)
+{
+ rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_CACHED);
+ rtems_chain_append (&bdbuf_cache.lru, &bd->link);
+}
+
+static void
+rtems_bdbuf_discard_buffer (rtems_bdbuf_buffer *bd)
+{
+ rtems_bdbuf_make_empty (bd);
+
+ if (bd->waiters == 0)
+ {
+ rtems_bdbuf_remove_from_tree (bd);
+ rtems_bdbuf_make_free_and_add_to_lru_list (bd);
+ }
+}
+
+static void
rtems_bdbuf_add_to_modified_list_after_access (rtems_bdbuf_buffer *bd)
{
if (bdbuf_cache.sync_active && bdbuf_cache.sync_device == bd->dev)
@@ -1075,9 +1132,8 @@ rtems_bdbuf_add_to_modified_list_after_access (rtems_bdbuf_buffer *bd)
static void
rtems_bdbuf_add_to_lru_list_after_access (rtems_bdbuf_buffer *bd)
{
- rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_CACHED);
- rtems_chain_append (&bdbuf_cache.lru, &bd->link);
rtems_bdbuf_group_release (bd);
+ rtems_bdbuf_make_cached_and_add_to_lru_list (bd);
if (bd->waiters)
rtems_bdbuf_wake (&bdbuf_cache.access_waiters);
@@ -1085,17 +1141,6 @@ rtems_bdbuf_add_to_lru_list_after_access (rtems_bdbuf_buffer *bd)
rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters);
}
-static void
-rtems_bdbuf_add_to_sync_list_after_access (rtems_bdbuf_buffer *bd)
-{
- rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_SYNC);
-
- rtems_chain_append (&bdbuf_cache.sync, &bd->link);
-
- if (bd->waiters)
- rtems_bdbuf_wake (&bdbuf_cache.access_waiters);
-}
-
/**
* Compute the number of BDs per group for a given buffer size.
*
@@ -1121,60 +1166,15 @@ rtems_bdbuf_bds_per_group (size_t size)
}
static void
-rtems_bdbuf_remove_from_tree (rtems_bdbuf_buffer *bd)
-{
- if (rtems_bdbuf_avl_remove (&bdbuf_cache.tree, bd) != 0)
- rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_TREE_RM);
-}
-
-static void
-rtems_bdbuf_remove_from_tree_and_lru_list (rtems_bdbuf_buffer *bd)
-{
- switch (bd->state)
- {
- case RTEMS_BDBUF_STATE_FREE:
- break;
- case RTEMS_BDBUF_STATE_CACHED:
- rtems_bdbuf_remove_from_tree (bd);
- break;
- default:
- rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_10);
- }
-
- rtems_chain_extract (&bd->link);
-}
-
-static void
-rtems_bdbuf_make_free_and_add_to_lru_list (rtems_bdbuf_buffer *bd)
-{
- rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_FREE);
- rtems_chain_prepend (&bdbuf_cache.lru, &bd->link);
-}
-
-static void
-rtems_bdbuf_make_empty_and_add_to_lru_list (rtems_bdbuf_buffer *bd)
-{
- rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_EMPTY);
- rtems_chain_append (&bdbuf_cache.lru, &bd->link);
-}
-
-static void
-rtems_bdbuf_release_empty_buffer (rtems_bdbuf_buffer *bd)
+rtems_bdbuf_discard_buffer_after_access (rtems_bdbuf_buffer *bd)
{
rtems_bdbuf_group_release (bd);
+ rtems_bdbuf_discard_buffer (bd);
if (bd->waiters)
- {
- rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_EMPTY);
- rtems_chain_append (&bdbuf_cache.lru, &bd->link);
rtems_bdbuf_wake (&bdbuf_cache.access_waiters);
- }
else
- {
- rtems_bdbuf_remove_from_tree (bd);
- rtems_bdbuf_make_free_and_add_to_lru_list (bd);
rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters);
- }
}
/**
@@ -1220,9 +1220,9 @@ rtems_bdbuf_group_realloc (rtems_bdbuf_group* group, size_t new_bds_per_group)
}
static void
-rtems_bdbuf_recycle_buffer (rtems_bdbuf_buffer *bd,
- dev_t dev,
- rtems_blkdev_bnum block)
+rtems_bdbuf_setup_empty_buffer (rtems_bdbuf_buffer *bd,
+ dev_t dev,
+ rtems_blkdev_bnum block)
{
bd->dev = dev;
bd->block = block;
@@ -1233,7 +1233,7 @@ rtems_bdbuf_recycle_buffer (rtems_bdbuf_buffer *bd,
if (rtems_bdbuf_avl_insert (&bdbuf_cache.tree, bd) != 0)
rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_RECYCLE);
- rtems_bdbuf_make_empty_and_add_to_lru_list (bd);
+ rtems_bdbuf_make_empty (bd);
}
static rtems_bdbuf_buffer *
@@ -1246,7 +1246,7 @@ rtems_bdbuf_get_buffer_from_lru_list (dev_t dev,
while (!rtems_chain_is_tail (&bdbuf_cache.lru, node))
{
rtems_bdbuf_buffer *bd = (rtems_bdbuf_buffer *) node;
- rtems_bdbuf_buffer *recycle_bd = NULL;
+ rtems_bdbuf_buffer *empty_bd = NULL;
if (rtems_bdbuf_tracer)
printf ("bdbuf:next-bd: %tu (%td:%" PRId32 ") %zd -> %zd\n",
@@ -1263,17 +1263,17 @@ rtems_bdbuf_get_buffer_from_lru_list (dev_t dev,
{
rtems_bdbuf_remove_from_tree_and_lru_list (bd);
- recycle_bd = bd;
+ empty_bd = bd;
}
else if (bd->group->users == 0)
- recycle_bd = rtems_bdbuf_group_realloc (bd->group, bds_per_group);
+ empty_bd = rtems_bdbuf_group_realloc (bd->group, bds_per_group);
}
- if (recycle_bd != NULL)
+ if (empty_bd != NULL)
{
- rtems_bdbuf_recycle_buffer (recycle_bd, dev, block);
+ rtems_bdbuf_setup_empty_buffer (empty_bd, dev, block);
- return recycle_bd;
+ return empty_bd;
}
node = rtems_chain_next (node);
@@ -1529,10 +1529,12 @@ rtems_bdbuf_wait_for_access (rtems_bdbuf_buffer *bd)
case RTEMS_BDBUF_STATE_ACCESS_CACHED:
case RTEMS_BDBUF_STATE_ACCESS_EMPTY:
case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
+ case RTEMS_BDBUF_STATE_ACCESS_PURGED:
rtems_bdbuf_wait (bd, &bdbuf_cache.access_waiters);
break;
- case RTEMS_BDBUF_STATE_TRANSFER:
case RTEMS_BDBUF_STATE_SYNC:
+ case RTEMS_BDBUF_STATE_TRANSFER:
+ case RTEMS_BDBUF_STATE_TRANSFER_PURGED:
rtems_bdbuf_wait (bd, &bdbuf_cache.transfer_waiters);
break;
default:
@@ -1586,10 +1588,12 @@ rtems_bdbuf_wait_for_recycle (rtems_bdbuf_buffer *bd)
case RTEMS_BDBUF_STATE_ACCESS_CACHED:
case RTEMS_BDBUF_STATE_ACCESS_EMPTY:
case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
+ case RTEMS_BDBUF_STATE_ACCESS_PURGED:
rtems_bdbuf_wait (bd, &bdbuf_cache.access_waiters);
break;
- case RTEMS_BDBUF_STATE_TRANSFER:
case RTEMS_BDBUF_STATE_SYNC:
+ case RTEMS_BDBUF_STATE_TRANSFER:
+ case RTEMS_BDBUF_STATE_TRANSFER_PURGED:
rtems_bdbuf_wait (bd, &bdbuf_cache.transfer_waiters);
break;
default:
@@ -1611,9 +1615,11 @@ rtems_bdbuf_wait_for_sync_done (rtems_bdbuf_buffer *bd)
case RTEMS_BDBUF_STATE_ACCESS_CACHED:
case RTEMS_BDBUF_STATE_ACCESS_EMPTY:
case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
+ case RTEMS_BDBUF_STATE_ACCESS_PURGED:
return;
case RTEMS_BDBUF_STATE_SYNC:
case RTEMS_BDBUF_STATE_TRANSFER:
+ case RTEMS_BDBUF_STATE_TRANSFER_PURGED:
rtems_bdbuf_wait (bd, &bdbuf_cache.transfer_waiters);
break;
default:
@@ -1631,6 +1637,35 @@ rtems_bdbuf_wait_for_buffer (void)
rtems_bdbuf_anonymous_wait (&bdbuf_cache.buffer_waiters);
}
+static void
+rtems_bdbuf_sync_after_access (rtems_bdbuf_buffer *bd)
+{
+ rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_SYNC);
+
+ rtems_chain_append (&bdbuf_cache.sync, &bd->link);
+
+ if (bd->waiters)
+ rtems_bdbuf_wake (&bdbuf_cache.access_waiters);
+
+ rtems_bdbuf_wake_swapper ();
+ rtems_bdbuf_wait_for_sync_done (bd);
+
+ /*
+ * We may have created a cached or empty buffer which may be recycled.
+ */
+ if (bd->waiters == 0
+ && (bd->state == RTEMS_BDBUF_STATE_CACHED
+ || bd->state == RTEMS_BDBUF_STATE_EMPTY))
+ {
+ if (bd->state == RTEMS_BDBUF_STATE_EMPTY)
+ {
+ rtems_bdbuf_remove_from_tree (bd);
+ rtems_bdbuf_make_free_and_add_to_lru_list (bd);
+ }
+ rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters);
+ }
+}
+
static rtems_bdbuf_buffer *
rtems_bdbuf_get_buffer_for_read_ahead (dev_t dev,
rtems_blkdev_bnum block,
@@ -1930,8 +1965,8 @@ rtems_bdbuf_execute_transfer_request (const rtems_disk_device *dd,
rtems_status_code sc = RTEMS_SUCCESSFUL;
int result = 0;
uint32_t transfer_index = 0;
- bool wake_transfer = false;
- bool wake_buffer = false;
+ bool wake_transfer_waiters = false;
+ bool wake_buffer_waiters = false;
if (cache_locked)
rtems_bdbuf_unlock_cache ();
@@ -1951,38 +1986,28 @@ rtems_bdbuf_execute_transfer_request (const rtems_disk_device *dd,
for (transfer_index = 0; transfer_index < req->bufnum; ++transfer_index)
{
rtems_bdbuf_buffer *bd = req->bufs [transfer_index].user;
- bool waiters = bd->waiters > 0;
+ bool waiters = bd->waiters;
if (waiters)
- wake_transfer = true;
+ wake_transfer_waiters = true;
else
- wake_buffer = true;
+ wake_buffer_waiters = true;
rtems_bdbuf_group_release (bd);
- if (sc == RTEMS_SUCCESSFUL)
- {
- rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_CACHED);
- rtems_chain_append (&bdbuf_cache.lru, &bd->link);
- }
- else if (waiters)
- {
- rtems_bdbuf_make_empty_and_add_to_lru_list (bd);
- }
+ if (sc == RTEMS_SUCCESSFUL && bd->state == RTEMS_BDBUF_STATE_TRANSFER)
+ rtems_bdbuf_make_cached_and_add_to_lru_list (bd);
else
- {
- rtems_bdbuf_remove_from_tree (bd);
- rtems_bdbuf_make_free_and_add_to_lru_list (bd);
- }
+ rtems_bdbuf_discard_buffer (bd);
if (rtems_bdbuf_tracer)
rtems_bdbuf_show_users ("transfer", bd);
}
- if (wake_transfer)
+ if (wake_transfer_waiters)
rtems_bdbuf_wake (&bdbuf_cache.transfer_waiters);
- if (wake_buffer)
+ if (wake_buffer_waiters)
rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters);
if (!cache_locked)
@@ -2100,7 +2125,8 @@ rtems_bdbuf_release (rtems_bdbuf_buffer *bd)
rtems_bdbuf_add_to_lru_list_after_access (bd);
break;
case RTEMS_BDBUF_STATE_ACCESS_EMPTY:
- rtems_bdbuf_release_empty_buffer (bd);
+ case RTEMS_BDBUF_STATE_ACCESS_PURGED:
+ rtems_bdbuf_discard_buffer_after_access (bd);
break;
case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
rtems_bdbuf_add_to_modified_list_after_access (bd);
@@ -2134,6 +2160,9 @@ rtems_bdbuf_release_modified (rtems_bdbuf_buffer *bd)
case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
rtems_bdbuf_add_to_modified_list_after_access (bd);
break;
+ case RTEMS_BDBUF_STATE_ACCESS_PURGED:
+ rtems_bdbuf_discard_buffer_after_access (bd);
+ break;
default:
rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_6);
break;
@@ -2161,7 +2190,10 @@ rtems_bdbuf_sync (rtems_bdbuf_buffer *bd)
case RTEMS_BDBUF_STATE_ACCESS_CACHED:
case RTEMS_BDBUF_STATE_ACCESS_EMPTY:
case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
- rtems_bdbuf_add_to_sync_list_after_access (bd);
+ rtems_bdbuf_sync_after_access (bd);
+ break;
+ case RTEMS_BDBUF_STATE_ACCESS_PURGED:
+ rtems_bdbuf_discard_buffer_after_access (bd);
break;
default:
rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_5);
@@ -2171,25 +2203,6 @@ rtems_bdbuf_sync (rtems_bdbuf_buffer *bd)
if (rtems_bdbuf_tracer)
rtems_bdbuf_show_usage ();
- rtems_bdbuf_wake_swapper ();
- rtems_bdbuf_wait_for_sync_done (bd);
-
- /*
- * If no one intercepts the sync, we created a cached buffer which may be
- * recycled.
- */
- if (bd->waiters == 0
- && (bd->state == RTEMS_BDBUF_STATE_CACHED
- || bd->state == RTEMS_BDBUF_STATE_EMPTY))
- {
- if (bd->state == RTEMS_BDBUF_STATE_EMPTY)
- {
- rtems_bdbuf_remove_from_tree (bd);
- rtems_bdbuf_make_free_and_add_to_lru_list (bd);
- }
- rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters);
- }
-
rtems_bdbuf_unlock_cache ();
return RTEMS_SUCCESSFUL;
@@ -2809,3 +2822,140 @@ rtems_bdbuf_swapout_task (rtems_task_argument arg)
rtems_task_delete (RTEMS_SELF);
}
+
+static void
+rtems_bdbuf_purge_list (rtems_chain_control *purge_list)
+{
+ bool wake_buffer_waiters = false;
+ rtems_chain_node *node = NULL;
+
+ while ((node = rtems_chain_get (purge_list)) != NULL)
+ {
+ rtems_bdbuf_buffer *bd = (rtems_bdbuf_buffer *) node;
+
+ if (bd->waiters == 0)
+ wake_buffer_waiters = true;
+
+ rtems_bdbuf_discard_buffer (bd);
+ }
+
+ if (wake_buffer_waiters)
+ rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters);
+}
+
+typedef bool (*rtems_bdbuf_purge_compare)(dev_t a, dev_t b);
+
+static void
+rtems_bdbuf_gather_for_purge (rtems_chain_control *purge_list,
+ rtems_bdbuf_purge_compare compare,
+ dev_t dev)
+{
+ rtems_bdbuf_buffer *stack [RTEMS_BDBUF_AVL_MAX_HEIGHT];
+ rtems_bdbuf_buffer **prev = stack;
+ rtems_bdbuf_buffer *cur = bdbuf_cache.tree;
+
+ *prev = NULL;
+
+ while (cur != NULL)
+ {
+ if ((*compare) (cur->dev, dev))
+ {
+ switch (cur->state)
+ {
+ case RTEMS_BDBUF_STATE_FREE:
+ case RTEMS_BDBUF_STATE_EMPTY:
+ case RTEMS_BDBUF_STATE_ACCESS_PURGED:
+ case RTEMS_BDBUF_STATE_TRANSFER_PURGED:
+ break;
+ case RTEMS_BDBUF_STATE_SYNC:
+ rtems_bdbuf_wake (&bdbuf_cache.transfer_waiters);
+ /* Fall through */
+ case RTEMS_BDBUF_STATE_MODIFIED:
+ rtems_bdbuf_group_release (cur);
+ /* Fall through */
+ case RTEMS_BDBUF_STATE_CACHED:
+ rtems_chain_extract (&cur->link);
+ rtems_chain_append (purge_list, &cur->link);
+ break;
+ case RTEMS_BDBUF_STATE_TRANSFER:
+ rtems_bdbuf_set_state (cur, RTEMS_BDBUF_STATE_TRANSFER_PURGED);
+ break;
+ case RTEMS_BDBUF_STATE_ACCESS_CACHED:
+ case RTEMS_BDBUF_STATE_ACCESS_EMPTY:
+ case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
+ rtems_bdbuf_set_state (cur, RTEMS_BDBUF_STATE_ACCESS_PURGED);
+ break;
+ default:
+ rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_STATE_11);
+ }
+ }
+
+ if (cur->avl.left != NULL)
+ {
+ /* Left */
+ ++prev;
+ *prev = cur;
+ cur = cur->avl.left;
+ }
+ else if (cur->avl.right != NULL)
+ {
+ /* Right */
+ ++prev;
+ *prev = cur;
+ cur = cur->avl.right;
+ }
+ else
+ {
+ while (*prev != NULL && cur == (*prev)->avl.right)
+ {
+ /* Up */
+ cur = *prev;
+ --prev;
+ }
+ if (*prev != NULL)
+ /* Right */
+ cur = (*prev)->avl.right;
+ else
+ /* Finished */
+ cur = NULL;
+ }
+ }
+}
+
+static void
+rtems_bdbuf_purge (rtems_bdbuf_purge_compare compare, dev_t dev)
+{
+ rtems_chain_control purge_list;
+
+ rtems_chain_initialize_empty (&purge_list);
+ rtems_bdbuf_lock_cache ();
+ rtems_bdbuf_gather_for_purge (&purge_list, compare, dev);
+ rtems_bdbuf_purge_list (&purge_list);
+ rtems_bdbuf_unlock_cache ();
+}
+
+static bool
+rtems_bdbuf_purge_compare_dev (dev_t a, dev_t b)
+{
+ return a == b;
+}
+
+void
+rtems_bdbuf_purge_dev (dev_t dev)
+{
+ rtems_bdbuf_purge (rtems_bdbuf_purge_compare_dev, dev);
+}
+
+static bool
+rtems_bdbuf_purge_compare_major (dev_t a, dev_t b)
+{
+ return rtems_filesystem_dev_major_t (a) == rtems_filesystem_dev_major_t (b);
+}
+
+void
+rtems_bdbuf_purge_major (rtems_device_major_number major)
+{
+ dev_t dev = rtems_filesystem_make_dev_t (major, 0);
+
+ rtems_bdbuf_purge (rtems_bdbuf_purge_compare_major, dev);
+}