|
|
1.1 root 1: /*
2: * QEMU Enhanced Disk Format Cluster functions
3: *
4: * Copyright IBM, Corp. 2010
5: *
6: * Authors:
7: * Stefan Hajnoczi <[email protected]>
8: * Anthony Liguori <[email protected]>
9: *
10: * This work is licensed under the terms of the GNU LGPL, version 2 or later.
11: * See the COPYING.LIB file in the top-level directory.
12: *
13: */
14:
15: #include "qed.h"
16:
17: /**
18: * Count the number of contiguous data clusters
19: *
20: * @s: QED state
21: * @table: L2 table
22: * @index: First cluster index
23: * @n: Maximum number of clusters
24: * @offset: Set to first cluster offset
25: *
1.1.1.2 root 26: * This function scans tables for contiguous clusters. A contiguous run of
27: * clusters may be allocated, unallocated, or zero.
1.1 root 28: */
29: static 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++) {
1.1.1.2 root 42: if (qed_offset_is_unalloc_cluster(last)) {
43: /* Counting unallocated clusters */
44: if (!qed_offset_is_unalloc_cluster(table->offsets[i])) {
45: break;
46: }
47: } else if (qed_offset_is_zero_cluster(last)) {
48: /* Counting zero clusters */
49: if (!qed_offset_is_zero_cluster(table->offsets[i])) {
1.1 root 50: break;
51: }
52: } else {
53: /* Counting allocated clusters */
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:
63: typedef struct {
64: BDRVQEDState *s;
65: uint64_t pos;
66: size_t len;
67:
68: QEDRequest *request;
69:
70: /* User callback */
71: QEDFindClusterFunc *cb;
72: void *opaque;
73: } QEDFindClusterCB;
74:
75: static 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:
1.1.1.2 root 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 {
1.1 root 103: ret = -EINVAL;
104: }
105:
1.1.1.2 root 106: len = MIN(find_cluster_cb->len, n * s->header.cluster_size -
107: qed_offset_into_cluster(s, find_cluster_cb->pos));
108:
1.1 root 109: out:
110: find_cluster_cb->cb(find_cluster_cb->opaque, ret, offset, len);
1.1.1.3 ! root 111: g_free(find_cluster_cb);
1.1 root 112: }
113:
114: /**
115: * Find the offset of a data cluster
116: *
117: * @s: QED state
118: * @request: L2 cache entry
119: * @pos: Byte position in device
120: * @len: Number of bytes
121: * @cb: Completion function
122: * @opaque: User data for completion function
123: *
124: * This function translates a position in the block device to an offset in the
125: * image file. It invokes the cb completion callback to report back the
126: * translated offset or unallocated range in the image file.
127: *
128: * If the L2 table exists, request->l2_table points to the L2 table cache entry
129: * and the caller must free the reference when they are finished. The cache
130: * entry is exposed in this way to avoid callers having to read the L2 table
131: * again later during request processing. If request->l2_table is non-NULL it
132: * will be unreferenced before taking on the new cache entry.
133: */
134: void 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: /* Limit length to L2 boundary. Requests are broken up at the L2 boundary
141: * so that a request acts on one L2 table at a time.
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)];
1.1.1.2 root 146: if (qed_offset_is_unalloc_cluster(l2_offset)) {
1.1 root 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:
1.1.1.3 ! root 155: find_cluster_cb = g_malloc(sizeof(*find_cluster_cb));
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.