|
|
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: *
26: * This function scans tables for contiguous allocated or free clusters.
27: */
28: static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
29: QEDTable *table,
30: unsigned int index,
31: unsigned int n,
32: uint64_t *offset)
33: {
34: unsigned int end = MIN(index + n, s->table_nelems);
35: uint64_t last = table->offsets[index];
36: unsigned int i;
37:
38: *offset = last;
39:
40: for (i = index + 1; i < end; i++) {
41: if (last == 0) {
42: /* Counting free clusters */
43: if (table->offsets[i] != 0) {
44: break;
45: }
46: } else {
47: /* Counting allocated clusters */
48: if (table->offsets[i] != last + s->header.cluster_size) {
49: break;
50: }
51: last = table->offsets[i];
52: }
53: }
54: return i - index;
55: }
56:
57: typedef struct {
58: BDRVQEDState *s;
59: uint64_t pos;
60: size_t len;
61:
62: QEDRequest *request;
63:
64: /* User callback */
65: QEDFindClusterFunc *cb;
66: void *opaque;
67: } QEDFindClusterCB;
68:
69: static void qed_find_cluster_cb(void *opaque, int ret)
70: {
71: QEDFindClusterCB *find_cluster_cb = opaque;
72: BDRVQEDState *s = find_cluster_cb->s;
73: QEDRequest *request = find_cluster_cb->request;
74: uint64_t offset = 0;
75: size_t len = 0;
76: unsigned int index;
77: unsigned int n;
78:
79: if (ret) {
80: goto out;
81: }
82:
83: index = qed_l2_index(s, find_cluster_cb->pos);
84: n = qed_bytes_to_clusters(s,
85: qed_offset_into_cluster(s, find_cluster_cb->pos) +
86: find_cluster_cb->len);
87: n = qed_count_contiguous_clusters(s, request->l2_table->table,
88: index, n, &offset);
89:
90: ret = offset ? QED_CLUSTER_FOUND : QED_CLUSTER_L2;
91: len = MIN(find_cluster_cb->len, n * s->header.cluster_size -
92: qed_offset_into_cluster(s, find_cluster_cb->pos));
93:
94: if (offset && !qed_check_cluster_offset(s, offset)) {
95: ret = -EINVAL;
96: }
97:
98: out:
99: find_cluster_cb->cb(find_cluster_cb->opaque, ret, offset, len);
100: qemu_free(find_cluster_cb);
101: }
102:
103: /**
104: * Find the offset of a data cluster
105: *
106: * @s: QED state
107: * @request: L2 cache entry
108: * @pos: Byte position in device
109: * @len: Number of bytes
110: * @cb: Completion function
111: * @opaque: User data for completion function
112: *
113: * This function translates a position in the block device to an offset in the
114: * image file. It invokes the cb completion callback to report back the
115: * translated offset or unallocated range in the image file.
116: *
117: * If the L2 table exists, request->l2_table points to the L2 table cache entry
118: * and the caller must free the reference when they are finished. The cache
119: * entry is exposed in this way to avoid callers having to read the L2 table
120: * again later during request processing. If request->l2_table is non-NULL it
121: * will be unreferenced before taking on the new cache entry.
122: */
123: void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
124: size_t len, QEDFindClusterFunc *cb, void *opaque)
125: {
126: QEDFindClusterCB *find_cluster_cb;
127: uint64_t l2_offset;
128:
129: /* Limit length to L2 boundary. Requests are broken up at the L2 boundary
130: * so that a request acts on one L2 table at a time.
131: */
132: len = MIN(len, (((pos >> s->l1_shift) + 1) << s->l1_shift) - pos);
133:
134: l2_offset = s->l1_table->offsets[qed_l1_index(s, pos)];
135: if (!l2_offset) {
136: cb(opaque, QED_CLUSTER_L1, 0, len);
137: return;
138: }
139: if (!qed_check_table_offset(s, l2_offset)) {
140: cb(opaque, -EINVAL, 0, 0);
141: return;
142: }
143:
144: find_cluster_cb = qemu_malloc(sizeof(*find_cluster_cb));
145: find_cluster_cb->s = s;
146: find_cluster_cb->pos = pos;
147: find_cluster_cb->len = len;
148: find_cluster_cb->cb = cb;
149: find_cluster_cb->opaque = opaque;
150: find_cluster_cb->request = request;
151:
152: qed_read_l2_table(s, request, l2_offset,
153: qed_find_cluster_cb, find_cluster_cb);
154: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.