summaryrefslogtreecommitdiffstats
path: root/src/spdk/ocf/src/metadata/metadata_misc.c
blob: b51a147ad14240b7b79a60738b92a5c3376e8b5a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * Copyright(c) 2012-2018 Intel Corporation
 * SPDX-License-Identifier: BSD-3-Clause-Clear
 */

#include "ocf/ocf.h"
#include "metadata.h"
#include "../ocf_freelist.h"
#include "../utils/utils_cache_line.h"

static bool _is_cache_line_acting(struct ocf_cache *cache,
		uint32_t cache_line, ocf_core_id_t core_id,
		uint64_t start_line, uint64_t end_line)
{
	ocf_core_id_t tmp_core_id;
	uint64_t core_line;

	ocf_metadata_get_core_info(cache, cache_line,
		&tmp_core_id, &core_line);

	if (core_id != OCF_CORE_ID_INVALID) {
		if (core_id != tmp_core_id)
			return false;

		if (core_line < start_line || core_line > end_line)
			return false;

	} else if (tmp_core_id == OCF_CORE_ID_INVALID) {
		return false;
	}

	return true;
}

/*
 * Iterates over cache lines that belong to the core device with
 * core ID = core_id  whose core byte addresses are in the range
 * [start_byte, end_byte] and applies actor(cache, cache_line) to all
 * matching cache lines
 *
 * set partition_id to PARTITION_INVALID to not care about partition_id
 *
 * METADATA lock must be held before calling this function
 */
int ocf_metadata_actor(struct ocf_cache *cache,
		ocf_part_id_t part_id, ocf_core_id_t core_id,
		uint64_t start_byte, uint64_t end_byte,
		ocf_metadata_actor_t actor)
{
	uint32_t step = 0;
	ocf_cache_line_t i, next_i;
	uint64_t start_line, end_line;
	int ret = 0;

	start_line = ocf_bytes_2_lines(cache, start_byte);
	end_line = ocf_bytes_2_lines(cache, end_byte);

	if (part_id != PARTITION_INVALID) {
		for (i = cache->user_parts[part_id].runtime->head;
				i != cache->device->collision_table_entries;
				i = next_i) {
			next_i = ocf_metadata_get_partition_next(cache, i);

			if (_is_cache_line_acting(cache, i, core_id,
					start_line, end_line)) {
				if (ocf_cache_line_is_used(cache, i))
					ret = -OCF_ERR_AGAIN;
				else
					actor(cache, i);
			}

			OCF_COND_RESCHED_DEFAULT(step);
		}
	} else {
		for (i = 0; i < cache->device->collision_table_entries; ++i) {
			if (_is_cache_line_acting(cache, i, core_id,
					start_line, end_line)) {
				if (ocf_cache_line_is_used(cache, i))
					ret = -OCF_ERR_AGAIN;
				else
					actor(cache, i);
			}

			OCF_COND_RESCHED_DEFAULT(step);
		}
	}

	return ret;
}

/* the caller must hold the relevant cache block concurrency reader lock
 * and the metadata lock
 */
void ocf_metadata_sparse_cache_line(struct ocf_cache *cache,
		uint32_t cache_line)
{
	ocf_part_id_t partition_id =
			ocf_metadata_get_partition_id(cache, cache_line);

	ocf_metadata_remove_from_collision(cache, cache_line, partition_id);

	ocf_metadata_remove_from_partition(cache, partition_id, cache_line);

	ocf_freelist_put_cache_line(cache->freelist, cache_line);
}

static void _ocf_metadata_sparse_cache_line(struct ocf_cache *cache,
		uint32_t cache_line)
{
	ocf_metadata_start_collision_shared_access(cache, cache_line);

	set_cache_line_invalid_no_flush(cache, 0, ocf_line_end_sector(cache),
			cache_line);

	/*
	 * This is especially for removing inactive core
	 */
	metadata_clear_dirty(cache, cache_line);

	ocf_metadata_end_collision_shared_access(cache, cache_line);
}

/* caller must hold metadata lock
 * set core_id to -1 to clean the whole cache device
 */
int ocf_metadata_sparse_range(struct ocf_cache *cache, int core_id,
			  uint64_t start_byte, uint64_t end_byte)
{
	return ocf_metadata_actor(cache, PARTITION_INVALID, core_id,
		start_byte, end_byte, _ocf_metadata_sparse_cache_line);
}