Flush metadata after setting dirty status of each sector.

After second dirty write to cache line which was already dirty, metadata flush
was not triggered. In case of dirty shutdown, this led to data corruption.

Signed-off-by: Michal Mielewczyk <michal.mielewczyk@intel.com>
This commit is contained in:
Michal Mielewczyk 2020-01-21 17:12:26 -05:00
parent 89f0e96607
commit 2f10365086
2 changed files with 36 additions and 29 deletions

View File

@ -229,20 +229,23 @@ static inline bool metadata_clear_dirty_sec_changed(
/* /*
* Marks given cache line's bits as dirty * Marks given cache line's bits as dirty
* *
* @return true if the cache line was clean and became dirty * @return true if any cache line's sector became dirty
* @return false if the cache line was dirty before marking bits * @return false for other cases
*/ */
static inline bool metadata_set_dirty_sec_changed( static inline bool metadata_set_dirty_sec_changed(
struct ocf_cache *cache, ocf_cache_line_t line, struct ocf_cache *cache, ocf_cache_line_t line,
uint8_t start, uint8_t stop) uint8_t start, uint8_t stop, bool *line_was_dirty)
{ {
bool was_dirty; bool sec_changed;
OCF_METADATA_BITS_LOCK_WR(); OCF_METADATA_BITS_LOCK_WR();
was_dirty = cache->metadata.iface.set_dirty(cache, line, start, stop); sec_changed = !cache->metadata.iface.test_dirty(cache, line,
start, stop, true);
*line_was_dirty = cache->metadata.iface.set_dirty(cache, line, start,
stop);
OCF_METADATA_BITS_UNLOCK_WR(); OCF_METADATA_BITS_UNLOCK_WR();
return !was_dirty; return sec_changed;
} }
/******************************************************************************* /*******************************************************************************

View File

@ -139,32 +139,36 @@ void set_cache_line_dirty(struct ocf_cache *cache, uint8_t start_bit,
ocf_cache_line_t line = req->map[map_idx].coll_idx; ocf_cache_line_t line = req->map[map_idx].coll_idx;
ocf_part_id_t part_id = ocf_metadata_get_partition_id(cache, line); ocf_part_id_t part_id = ocf_metadata_get_partition_id(cache, line);
uint8_t evp_type = cache->conf_meta->eviction_policy_type; uint8_t evp_type = cache->conf_meta->eviction_policy_type;
bool line_was_dirty;
if (metadata_set_dirty_sec_changed(cache, line, start_bit, end_bit)) { if (metadata_set_dirty_sec_changed(cache, line, start_bit, end_bit,
/* &line_was_dirty)) {
* If this is first dirty cline set dirty timestamp
*/
env_atomic64_cmpxchg(&req->core->runtime_meta->dirty_since,
0, env_get_tick_count());
/*
* Update the number of dirty cached data for that
* core object
*/
env_atomic_inc(&req->core->runtime_meta->dirty_clines);
/*
* increment dirty clines statistic for given cline
*/
env_atomic_inc(&req->core->runtime_meta->
part_counters[part_id].dirty_clines);
if (likely(evict_policy_ops[evp_type].dirty_cline))
evict_policy_ops[evp_type].dirty_cline(cache, part_id, line);
ocf_metadata_flush_mark(cache, req, map_idx, DIRTY, start_bit, ocf_metadata_flush_mark(cache, req, map_idx, DIRTY, start_bit,
end_bit); end_bit);
if (!line_was_dirty) {
/*
* If this is first dirty cline set dirty timestamp
*/
env_atomic64_cmpxchg(&req->core->runtime_meta->dirty_since,
0, env_get_tick_count());
/*
* Update the number of dirty cached data for that
* core object
*/
env_atomic_inc(&req->core->runtime_meta->dirty_clines);
/*
* increment dirty clines statistic for given cline
*/
env_atomic_inc(&req->core->runtime_meta->
part_counters[part_id].dirty_clines);
if (likely(evict_policy_ops[evp_type].dirty_cline))
evict_policy_ops[evp_type].dirty_cline(cache, part_id, line);
}
} }
ocf_cleaning_set_hot_cache_line(cache, line); ocf_cleaning_set_hot_cache_line(cache, line);
} }