root / block / qed-cluster.c @ f53f81e0
History | View | Annotate | Download (5.1 kB)
1 | 298800ca | Stefan Hajnoczi | /*
|
---|---|---|---|
2 | 298800ca | Stefan Hajnoczi | * QEMU Enhanced Disk Format Cluster functions
|
3 | 298800ca | Stefan Hajnoczi | *
|
4 | 298800ca | Stefan Hajnoczi | * Copyright IBM, Corp. 2010
|
5 | 298800ca | Stefan Hajnoczi | *
|
6 | 298800ca | Stefan Hajnoczi | * Authors:
|
7 | 298800ca | Stefan Hajnoczi | * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
|
8 | 298800ca | Stefan Hajnoczi | * Anthony Liguori <aliguori@us.ibm.com>
|
9 | 298800ca | Stefan Hajnoczi | *
|
10 | 298800ca | Stefan Hajnoczi | * This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
11 | 298800ca | Stefan Hajnoczi | * See the COPYING.LIB file in the top-level directory.
|
12 | 298800ca | Stefan Hajnoczi | *
|
13 | 298800ca | Stefan Hajnoczi | */
|
14 | 298800ca | Stefan Hajnoczi | |
15 | 298800ca | Stefan Hajnoczi | #include "qed.h" |
16 | 298800ca | Stefan Hajnoczi | |
17 | 298800ca | Stefan Hajnoczi | /**
|
18 | 298800ca | Stefan Hajnoczi | * Count the number of contiguous data clusters
|
19 | 298800ca | Stefan Hajnoczi | *
|
20 | 298800ca | Stefan Hajnoczi | * @s: QED state
|
21 | 298800ca | Stefan Hajnoczi | * @table: L2 table
|
22 | 298800ca | Stefan Hajnoczi | * @index: First cluster index
|
23 | 298800ca | Stefan Hajnoczi | * @n: Maximum number of clusters
|
24 | 298800ca | Stefan Hajnoczi | * @offset: Set to first cluster offset
|
25 | 298800ca | Stefan Hajnoczi | *
|
26 | 21df65b6 | Anthony Liguori | * This function scans tables for contiguous clusters. A contiguous run of
|
27 | 21df65b6 | Anthony Liguori | * clusters may be allocated, unallocated, or zero.
|
28 | 298800ca | Stefan Hajnoczi | */
|
29 | 298800ca | Stefan Hajnoczi | static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s, |
30 | 298800ca | Stefan Hajnoczi | QEDTable *table, |
31 | 298800ca | Stefan Hajnoczi | unsigned int index, |
32 | 298800ca | Stefan Hajnoczi | unsigned int n, |
33 | 298800ca | Stefan Hajnoczi | uint64_t *offset) |
34 | 298800ca | Stefan Hajnoczi | { |
35 | 298800ca | Stefan Hajnoczi | unsigned int end = MIN(index + n, s->table_nelems); |
36 | 298800ca | Stefan Hajnoczi | uint64_t last = table->offsets[index]; |
37 | 298800ca | Stefan Hajnoczi | unsigned int i; |
38 | 298800ca | Stefan Hajnoczi | |
39 | 298800ca | Stefan Hajnoczi | *offset = last; |
40 | 298800ca | Stefan Hajnoczi | |
41 | 298800ca | Stefan Hajnoczi | for (i = index + 1; i < end; i++) { |
42 | 21df65b6 | Anthony Liguori | if (qed_offset_is_unalloc_cluster(last)) {
|
43 | 21df65b6 | Anthony Liguori | /* Counting unallocated clusters */
|
44 | 21df65b6 | Anthony Liguori | if (!qed_offset_is_unalloc_cluster(table->offsets[i])) {
|
45 | 21df65b6 | Anthony Liguori | break;
|
46 | 21df65b6 | Anthony Liguori | } |
47 | 21df65b6 | Anthony Liguori | } else if (qed_offset_is_zero_cluster(last)) { |
48 | 21df65b6 | Anthony Liguori | /* Counting zero clusters */
|
49 | 21df65b6 | Anthony Liguori | if (!qed_offset_is_zero_cluster(table->offsets[i])) {
|
50 | 298800ca | Stefan Hajnoczi | break;
|
51 | 298800ca | Stefan Hajnoczi | } |
52 | 298800ca | Stefan Hajnoczi | } else {
|
53 | 298800ca | Stefan Hajnoczi | /* Counting allocated clusters */
|
54 | 298800ca | Stefan Hajnoczi | if (table->offsets[i] != last + s->header.cluster_size) {
|
55 | 298800ca | Stefan Hajnoczi | break;
|
56 | 298800ca | Stefan Hajnoczi | } |
57 | 298800ca | Stefan Hajnoczi | last = table->offsets[i]; |
58 | 298800ca | Stefan Hajnoczi | } |
59 | 298800ca | Stefan Hajnoczi | } |
60 | 298800ca | Stefan Hajnoczi | return i - index;
|
61 | 298800ca | Stefan Hajnoczi | } |
62 | 298800ca | Stefan Hajnoczi | |
63 | 298800ca | Stefan Hajnoczi | typedef struct { |
64 | 298800ca | Stefan Hajnoczi | BDRVQEDState *s; |
65 | 298800ca | Stefan Hajnoczi | uint64_t pos; |
66 | 298800ca | Stefan Hajnoczi | size_t len; |
67 | 298800ca | Stefan Hajnoczi | |
68 | 298800ca | Stefan Hajnoczi | QEDRequest *request; |
69 | 298800ca | Stefan Hajnoczi | |
70 | 298800ca | Stefan Hajnoczi | /* User callback */
|
71 | 298800ca | Stefan Hajnoczi | QEDFindClusterFunc *cb; |
72 | 298800ca | Stefan Hajnoczi | void *opaque;
|
73 | 298800ca | Stefan Hajnoczi | } QEDFindClusterCB; |
74 | 298800ca | Stefan Hajnoczi | |
75 | 298800ca | Stefan Hajnoczi | static void qed_find_cluster_cb(void *opaque, int ret) |
76 | 298800ca | Stefan Hajnoczi | { |
77 | 298800ca | Stefan Hajnoczi | QEDFindClusterCB *find_cluster_cb = opaque; |
78 | 298800ca | Stefan Hajnoczi | BDRVQEDState *s = find_cluster_cb->s; |
79 | 298800ca | Stefan Hajnoczi | QEDRequest *request = find_cluster_cb->request; |
80 | 298800ca | Stefan Hajnoczi | uint64_t offset = 0;
|
81 | 298800ca | Stefan Hajnoczi | size_t len = 0;
|
82 | 298800ca | Stefan Hajnoczi | unsigned int index; |
83 | 298800ca | Stefan Hajnoczi | unsigned int n; |
84 | 298800ca | Stefan Hajnoczi | |
85 | 298800ca | Stefan Hajnoczi | if (ret) {
|
86 | 298800ca | Stefan Hajnoczi | goto out;
|
87 | 298800ca | Stefan Hajnoczi | } |
88 | 298800ca | Stefan Hajnoczi | |
89 | 298800ca | Stefan Hajnoczi | index = qed_l2_index(s, find_cluster_cb->pos); |
90 | 298800ca | Stefan Hajnoczi | n = qed_bytes_to_clusters(s, |
91 | 298800ca | Stefan Hajnoczi | qed_offset_into_cluster(s, find_cluster_cb->pos) + |
92 | 298800ca | Stefan Hajnoczi | find_cluster_cb->len); |
93 | 298800ca | Stefan Hajnoczi | n = qed_count_contiguous_clusters(s, request->l2_table->table, |
94 | 298800ca | Stefan Hajnoczi | index, n, &offset); |
95 | 298800ca | Stefan Hajnoczi | |
96 | 21df65b6 | Anthony Liguori | if (qed_offset_is_unalloc_cluster(offset)) {
|
97 | 21df65b6 | Anthony Liguori | ret = QED_CLUSTER_L2; |
98 | 21df65b6 | Anthony Liguori | } else if (qed_offset_is_zero_cluster(offset)) { |
99 | 21df65b6 | Anthony Liguori | ret = QED_CLUSTER_ZERO; |
100 | 21df65b6 | Anthony Liguori | } else if (qed_check_cluster_offset(s, offset)) { |
101 | 21df65b6 | Anthony Liguori | ret = QED_CLUSTER_FOUND; |
102 | 21df65b6 | Anthony Liguori | } else {
|
103 | 298800ca | Stefan Hajnoczi | ret = -EINVAL; |
104 | 298800ca | Stefan Hajnoczi | } |
105 | 298800ca | Stefan Hajnoczi | |
106 | 21df65b6 | Anthony Liguori | len = MIN(find_cluster_cb->len, n * s->header.cluster_size - |
107 | 21df65b6 | Anthony Liguori | qed_offset_into_cluster(s, find_cluster_cb->pos)); |
108 | 21df65b6 | Anthony Liguori | |
109 | 298800ca | Stefan Hajnoczi | out:
|
110 | 298800ca | Stefan Hajnoczi | find_cluster_cb->cb(find_cluster_cb->opaque, ret, offset, len); |
111 | 7267c094 | Anthony Liguori | g_free(find_cluster_cb); |
112 | 298800ca | Stefan Hajnoczi | } |
113 | 298800ca | Stefan Hajnoczi | |
114 | 298800ca | Stefan Hajnoczi | /**
|
115 | 298800ca | Stefan Hajnoczi | * Find the offset of a data cluster
|
116 | 298800ca | Stefan Hajnoczi | *
|
117 | 298800ca | Stefan Hajnoczi | * @s: QED state
|
118 | 298800ca | Stefan Hajnoczi | * @request: L2 cache entry
|
119 | 298800ca | Stefan Hajnoczi | * @pos: Byte position in device
|
120 | 298800ca | Stefan Hajnoczi | * @len: Number of bytes
|
121 | 298800ca | Stefan Hajnoczi | * @cb: Completion function
|
122 | 298800ca | Stefan Hajnoczi | * @opaque: User data for completion function
|
123 | 298800ca | Stefan Hajnoczi | *
|
124 | 298800ca | Stefan Hajnoczi | * This function translates a position in the block device to an offset in the
|
125 | 298800ca | Stefan Hajnoczi | * image file. It invokes the cb completion callback to report back the
|
126 | 298800ca | Stefan Hajnoczi | * translated offset or unallocated range in the image file.
|
127 | 298800ca | Stefan Hajnoczi | *
|
128 | 298800ca | Stefan Hajnoczi | * If the L2 table exists, request->l2_table points to the L2 table cache entry
|
129 | 298800ca | Stefan Hajnoczi | * and the caller must free the reference when they are finished. The cache
|
130 | 298800ca | Stefan Hajnoczi | * entry is exposed in this way to avoid callers having to read the L2 table
|
131 | 298800ca | Stefan Hajnoczi | * again later during request processing. If request->l2_table is non-NULL it
|
132 | 298800ca | Stefan Hajnoczi | * will be unreferenced before taking on the new cache entry.
|
133 | 298800ca | Stefan Hajnoczi | */
|
134 | 298800ca | Stefan Hajnoczi | void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
|
135 | 298800ca | Stefan Hajnoczi | size_t len, QEDFindClusterFunc *cb, void *opaque)
|
136 | 298800ca | Stefan Hajnoczi | { |
137 | 298800ca | Stefan Hajnoczi | QEDFindClusterCB *find_cluster_cb; |
138 | 298800ca | Stefan Hajnoczi | uint64_t l2_offset; |
139 | 298800ca | Stefan Hajnoczi | |
140 | 298800ca | Stefan Hajnoczi | /* Limit length to L2 boundary. Requests are broken up at the L2 boundary
|
141 | 298800ca | Stefan Hajnoczi | * so that a request acts on one L2 table at a time.
|
142 | 298800ca | Stefan Hajnoczi | */
|
143 | 298800ca | Stefan Hajnoczi | len = MIN(len, (((pos >> s->l1_shift) + 1) << s->l1_shift) - pos);
|
144 | 298800ca | Stefan Hajnoczi | |
145 | 298800ca | Stefan Hajnoczi | l2_offset = s->l1_table->offsets[qed_l1_index(s, pos)]; |
146 | 21df65b6 | Anthony Liguori | if (qed_offset_is_unalloc_cluster(l2_offset)) {
|
147 | 298800ca | Stefan Hajnoczi | cb(opaque, QED_CLUSTER_L1, 0, len);
|
148 | 298800ca | Stefan Hajnoczi | return;
|
149 | 298800ca | Stefan Hajnoczi | } |
150 | 298800ca | Stefan Hajnoczi | if (!qed_check_table_offset(s, l2_offset)) {
|
151 | 298800ca | Stefan Hajnoczi | cb(opaque, -EINVAL, 0, 0); |
152 | 298800ca | Stefan Hajnoczi | return;
|
153 | 298800ca | Stefan Hajnoczi | } |
154 | 298800ca | Stefan Hajnoczi | |
155 | 7267c094 | Anthony Liguori | find_cluster_cb = g_malloc(sizeof(*find_cluster_cb));
|
156 | 298800ca | Stefan Hajnoczi | find_cluster_cb->s = s; |
157 | 298800ca | Stefan Hajnoczi | find_cluster_cb->pos = pos; |
158 | 298800ca | Stefan Hajnoczi | find_cluster_cb->len = len; |
159 | 298800ca | Stefan Hajnoczi | find_cluster_cb->cb = cb; |
160 | 298800ca | Stefan Hajnoczi | find_cluster_cb->opaque = opaque; |
161 | 298800ca | Stefan Hajnoczi | find_cluster_cb->request = request; |
162 | 298800ca | Stefan Hajnoczi | |
163 | 298800ca | Stefan Hajnoczi | qed_read_l2_table(s, request, l2_offset, |
164 | 298800ca | Stefan Hajnoczi | qed_find_cluster_cb, find_cluster_cb); |
165 | 298800ca | Stefan Hajnoczi | } |