put src into packaging format
[adaptation/panda/qemu-arm-static.git] / block / qed-cluster.c
1 /*
2  * QEMU Enhanced Disk Format Cluster functions
3  *
4  * Copyright IBM, Corp. 2010
5  *
6  * Authors:
7  *  Stefan Hajnoczi   <stefanha@linux.vnet.ibm.com>
8  *  Anthony Liguori   <aliguori@us.ibm.com>
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 }