Statistics
| Branch: | Revision:

root / block / qed-cluster.c @ 333c574d

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 298800ca Stefan Hajnoczi
    qemu_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 298800ca Stefan Hajnoczi
    find_cluster_cb = qemu_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
}