Reorder metadata updating pattern in WT mode
There's a possibility that WT write is performed to dirty cache line (i.e. after switching WB->WT without flush) and status bits change from dirty to clean. If power failure occurs it might happen that recovery would ignore recent data from cache and would assume that data is clean while backend storage data is out of date. Signed-off-by: Michal Mielewczyk <michal.mielewczyk@intel.com>
This commit is contained in:
parent
0192ce23dd
commit
c9294d1f06
@ -18,6 +18,84 @@
|
||||
#define OCF_ENGINE_DEBUG_IO_NAME "wt"
|
||||
#include "engine_debug.h"
|
||||
|
||||
static void _ocf_write_wt_update_bits(struct ocf_request *req)
|
||||
{
|
||||
bool miss = ocf_engine_is_miss(req);
|
||||
bool dirty_any = req->info.dirty_any;
|
||||
bool repart = ocf_engine_needs_repart(req);
|
||||
|
||||
if (!miss && !dirty_any && !repart)
|
||||
return;
|
||||
|
||||
ocf_hb_req_prot_lock_wr(req);
|
||||
|
||||
if (miss) {
|
||||
/* Update valid status bits */
|
||||
ocf_set_valid_map_info(req);
|
||||
}
|
||||
|
||||
if (dirty_any) {
|
||||
/* Writes goes to both cache and core, need to update
|
||||
* status bits from dirty to clean
|
||||
*/
|
||||
ocf_set_clean_map_info(req);
|
||||
}
|
||||
|
||||
if (repart) {
|
||||
OCF_DEBUG_RQ(req, "Re-Part");
|
||||
/* Probably some cache lines are assigned into wrong
|
||||
* partition. Need to move it to new one
|
||||
*/
|
||||
ocf_user_part_move(req);
|
||||
}
|
||||
|
||||
ocf_hb_req_prot_unlock_wr(req);
|
||||
}
|
||||
|
||||
static void _ocf_write_wt_do_flush_metadata_compl(struct ocf_request *req,
|
||||
int error)
|
||||
{
|
||||
if (error)
|
||||
req->error = error;
|
||||
|
||||
if (env_atomic_dec_return(&req->req_remaining))
|
||||
return;
|
||||
|
||||
if (req->error)
|
||||
ocf_engine_error(req, true, "Failed to write data to cache");
|
||||
|
||||
ocf_req_unlock_wr(ocf_cache_line_concurrency(req->cache), req);
|
||||
|
||||
req->complete(req, req->info.core_error ? req->error : 0);
|
||||
|
||||
ocf_req_put(req);
|
||||
}
|
||||
|
||||
static int ocf_write_wt_do_flush_metadata(struct ocf_request *req)
|
||||
{
|
||||
struct ocf_cache *cache = req->cache;
|
||||
|
||||
env_atomic_set(&req->req_remaining, 1);
|
||||
|
||||
_ocf_write_wt_update_bits(req);
|
||||
|
||||
if (req->info.flush_metadata) {
|
||||
/* Metadata flush IO */
|
||||
|
||||
ocf_metadata_flush_do_asynch(cache, req,
|
||||
_ocf_write_wt_do_flush_metadata_compl);
|
||||
}
|
||||
|
||||
_ocf_write_wt_do_flush_metadata_compl(req, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ocf_io_if _io_if_wt_flush_metadata = {
|
||||
.read = ocf_write_wt_do_flush_metadata,
|
||||
.write = ocf_write_wt_do_flush_metadata,
|
||||
};
|
||||
|
||||
static void _ocf_write_wt_req_complete(struct ocf_request *req)
|
||||
{
|
||||
if (env_atomic_dec_return(&req->req_remaining))
|
||||
@ -33,14 +111,7 @@ static void _ocf_write_wt_req_complete(struct ocf_request *req)
|
||||
|
||||
ocf_engine_invalidate(req);
|
||||
} else {
|
||||
/* Unlock reqest from WRITE access */
|
||||
ocf_req_unlock_wr(ocf_cache_line_concurrency(req->cache), req);
|
||||
|
||||
/* Complete request */
|
||||
req->complete(req, req->info.core_error ? req->error : 0);
|
||||
|
||||
/* Release OCF request */
|
||||
ocf_req_put(req);
|
||||
ocf_engine_push_req_front_if(req, &_io_if_wt_flush_metadata, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,13 +150,6 @@ static inline void _ocf_write_wt_submit(struct ocf_request *req)
|
||||
env_atomic_set(&req->req_remaining, ocf_engine_io_count(req)); /* Cache IO */
|
||||
env_atomic_inc(&req->req_remaining); /* Core device IO */
|
||||
|
||||
if (req->info.flush_metadata) {
|
||||
/* Metadata flush IO */
|
||||
|
||||
ocf_metadata_flush_do_asynch(cache, req,
|
||||
_ocf_write_wt_cache_complete);
|
||||
}
|
||||
|
||||
/* To cache */
|
||||
ocf_submit_cache_reqs(cache, req, OCF_WRITE, 0, req->byte_length,
|
||||
ocf_engine_io_count(req), _ocf_write_wt_cache_complete);
|
||||
@ -95,48 +159,11 @@ static inline void _ocf_write_wt_submit(struct ocf_request *req)
|
||||
_ocf_write_wt_core_complete);
|
||||
}
|
||||
|
||||
static void _ocf_write_wt_update_bits(struct ocf_request *req)
|
||||
{
|
||||
bool miss = ocf_engine_is_miss(req);
|
||||
bool dirty_any = req->info.dirty_any;
|
||||
bool repart = ocf_engine_needs_repart(req);
|
||||
|
||||
if (!miss && !dirty_any && !repart)
|
||||
return;
|
||||
|
||||
ocf_hb_req_prot_lock_wr(req);
|
||||
|
||||
if (miss) {
|
||||
/* Update valid status bits */
|
||||
ocf_set_valid_map_info(req);
|
||||
}
|
||||
|
||||
if (dirty_any) {
|
||||
/* Writes goes to both cache and core, need to update
|
||||
* status bits from dirty to clean
|
||||
*/
|
||||
ocf_set_clean_map_info(req);
|
||||
}
|
||||
|
||||
if (repart) {
|
||||
OCF_DEBUG_RQ(req, "Re-Part");
|
||||
/* Probably some cache lines are assigned into wrong
|
||||
* partition. Need to move it to new one
|
||||
*/
|
||||
ocf_user_part_move(req);
|
||||
}
|
||||
|
||||
ocf_hb_req_prot_unlock_wr(req);
|
||||
}
|
||||
|
||||
static int _ocf_write_wt_do(struct ocf_request *req)
|
||||
{
|
||||
/* Get OCF request - increase reference counter */
|
||||
ocf_req_get(req);
|
||||
|
||||
/* Update status bits */
|
||||
_ocf_write_wt_update_bits(req);
|
||||
|
||||
/* Submit IO */
|
||||
_ocf_write_wt_submit(req);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user