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