1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include "qemu/osdep.h"
16#include "qed.h"
17
18
19
20
21
22
23
24
25
26
27
28
29
30static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
31 QEDTable *table,
32 unsigned int index,
33 unsigned int n,
34 uint64_t *offset)
35{
36 unsigned int end = MIN(index + n, s->table_nelems);
37 uint64_t last = table->offsets[index];
38 unsigned int i;
39
40 *offset = last;
41
42 for (i = index + 1; i < end; i++) {
43 if (qed_offset_is_unalloc_cluster(last)) {
44
45 if (!qed_offset_is_unalloc_cluster(table->offsets[i])) {
46 break;
47 }
48 } else if (qed_offset_is_zero_cluster(last)) {
49
50 if (!qed_offset_is_zero_cluster(table->offsets[i])) {
51 break;
52 }
53 } else {
54
55 if (table->offsets[i] != last + s->header.cluster_size) {
56 break;
57 }
58 last = table->offsets[i];
59 }
60 }
61 return i - index;
62}
63
64typedef struct {
65 BDRVQEDState *s;
66 uint64_t pos;
67 size_t len;
68
69 QEDRequest *request;
70
71
72 QEDFindClusterFunc *cb;
73 void *opaque;
74} QEDFindClusterCB;
75
76static void qed_find_cluster_cb(void *opaque, int ret)
77{
78 QEDFindClusterCB *find_cluster_cb = opaque;
79 BDRVQEDState *s = find_cluster_cb->s;
80 QEDRequest *request = find_cluster_cb->request;
81 uint64_t offset = 0;
82 size_t len = 0;
83 unsigned int index;
84 unsigned int n;
85
86 if (ret) {
87 goto out;
88 }
89
90 index = qed_l2_index(s, find_cluster_cb->pos);
91 n = qed_bytes_to_clusters(s,
92 qed_offset_into_cluster(s, find_cluster_cb->pos) +
93 find_cluster_cb->len);
94 n = qed_count_contiguous_clusters(s, request->l2_table->table,
95 index, n, &offset);
96
97 if (qed_offset_is_unalloc_cluster(offset)) {
98 ret = QED_CLUSTER_L2;
99 } else if (qed_offset_is_zero_cluster(offset)) {
100 ret = QED_CLUSTER_ZERO;
101 } else if (qed_check_cluster_offset(s, offset)) {
102 ret = QED_CLUSTER_FOUND;
103 } else {
104 ret = -EINVAL;
105 }
106
107 len = MIN(find_cluster_cb->len, n * s->header.cluster_size -
108 qed_offset_into_cluster(s, find_cluster_cb->pos));
109
110out:
111 find_cluster_cb->cb(find_cluster_cb->opaque, ret, offset, len);
112 g_free(find_cluster_cb);
113}
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
136 size_t len, QEDFindClusterFunc *cb, void *opaque)
137{
138 QEDFindClusterCB *find_cluster_cb;
139 uint64_t l2_offset;
140
141
142
143
144 len = MIN(len, (((pos >> s->l1_shift) + 1) << s->l1_shift) - pos);
145
146 l2_offset = s->l1_table->offsets[qed_l1_index(s, pos)];
147 if (qed_offset_is_unalloc_cluster(l2_offset)) {
148 cb(opaque, QED_CLUSTER_L1, 0, len);
149 return;
150 }
151 if (!qed_check_table_offset(s, l2_offset)) {
152 cb(opaque, -EINVAL, 0, 0);
153 return;
154 }
155
156 find_cluster_cb = g_malloc(sizeof(*find_cluster_cb));
157 find_cluster_cb->s = s;
158 find_cluster_cb->pos = pos;
159 find_cluster_cb->len = len;
160 find_cluster_cb->cb = cb;
161 find_cluster_cb->opaque = opaque;
162 find_cluster_cb->request = request;
163
164 qed_read_l2_table(s, request, l2_offset,
165 qed_find_cluster_cb, find_cluster_cb);
166}
167