|
|
1.1 root 1: /*
2: * QEMU Enhanced Disk Format Consistency Check
3: *
4: * Copyright IBM, Corp. 2010
5: *
6: * Authors:
7: * Stefan Hajnoczi <[email protected]>
8: *
9: * This work is licensed under the terms of the GNU LGPL, version 2 or later.
10: * See the COPYING.LIB file in the top-level directory.
11: *
12: */
13:
14: #include "qed.h"
15:
16: typedef struct {
17: BDRVQEDState *s;
18: BdrvCheckResult *result;
19: bool fix; /* whether to fix invalid offsets */
20:
1.1.1.2 root 21: uint64_t nclusters;
1.1 root 22: uint32_t *used_clusters; /* referenced cluster bitmap */
23:
24: QEDRequest request;
25: } QEDCheck;
26:
27: static bool qed_test_bit(uint32_t *bitmap, uint64_t n) {
28: return !!(bitmap[n / 32] & (1 << (n % 32)));
29: }
30:
31: static void qed_set_bit(uint32_t *bitmap, uint64_t n) {
32: bitmap[n / 32] |= 1 << (n % 32);
33: }
34:
35: /**
36: * Set bitmap bits for clusters
37: *
38: * @check: Check structure
39: * @offset: Starting offset in bytes
40: * @n: Number of clusters
41: */
42: static bool qed_set_used_clusters(QEDCheck *check, uint64_t offset,
43: unsigned int n)
44: {
45: uint64_t cluster = qed_bytes_to_clusters(check->s, offset);
46: unsigned int corruptions = 0;
47:
48: while (n-- != 0) {
49: /* Clusters should only be referenced once */
50: if (qed_test_bit(check->used_clusters, cluster)) {
51: corruptions++;
52: }
53:
54: qed_set_bit(check->used_clusters, cluster);
55: cluster++;
56: }
57:
58: check->result->corruptions += corruptions;
59: return corruptions == 0;
60: }
61:
62: /**
63: * Check an L2 table
64: *
65: * @ret: Number of invalid cluster offsets
66: */
67: static unsigned int qed_check_l2_table(QEDCheck *check, QEDTable *table)
68: {
69: BDRVQEDState *s = check->s;
70: unsigned int i, num_invalid = 0;
1.1.1.5 ! root 71: uint64_t last_offset = 0;
1.1 root 72:
73: for (i = 0; i < s->table_nelems; i++) {
74: uint64_t offset = table->offsets[i];
75:
1.1.1.3 root 76: if (qed_offset_is_unalloc_cluster(offset) ||
77: qed_offset_is_zero_cluster(offset)) {
1.1 root 78: continue;
79: }
1.1.1.5 ! root 80: check->result->bfi.allocated_clusters++;
! 81: if (last_offset && (last_offset + s->header.cluster_size != offset)) {
! 82: check->result->bfi.fragmented_clusters++;
! 83: }
! 84: last_offset = offset;
1.1 root 85:
86: /* Detect invalid cluster offset */
87: if (!qed_check_cluster_offset(s, offset)) {
88: if (check->fix) {
89: table->offsets[i] = 0;
90: } else {
91: check->result->corruptions++;
92: }
93:
94: num_invalid++;
95: continue;
96: }
97:
98: qed_set_used_clusters(check, offset, 1);
99: }
100:
101: return num_invalid;
102: }
103:
104: /**
105: * Descend tables and check each cluster is referenced once only
106: */
107: static int qed_check_l1_table(QEDCheck *check, QEDTable *table)
108: {
109: BDRVQEDState *s = check->s;
110: unsigned int i, num_invalid_l1 = 0;
111: int ret, last_error = 0;
112:
113: /* Mark L1 table clusters used */
114: qed_set_used_clusters(check, s->header.l1_table_offset,
115: s->header.table_size);
116:
117: for (i = 0; i < s->table_nelems; i++) {
118: unsigned int num_invalid_l2;
119: uint64_t offset = table->offsets[i];
120:
1.1.1.3 root 121: if (qed_offset_is_unalloc_cluster(offset)) {
1.1 root 122: continue;
123: }
124:
125: /* Detect invalid L2 offset */
126: if (!qed_check_table_offset(s, offset)) {
127: /* Clear invalid offset */
128: if (check->fix) {
129: table->offsets[i] = 0;
130: } else {
131: check->result->corruptions++;
132: }
133:
134: num_invalid_l1++;
135: continue;
136: }
137:
138: if (!qed_set_used_clusters(check, offset, s->header.table_size)) {
139: continue; /* skip an invalid table */
140: }
141:
142: ret = qed_read_l2_table_sync(s, &check->request, offset);
143: if (ret) {
144: check->result->check_errors++;
145: last_error = ret;
146: continue;
147: }
148:
149: num_invalid_l2 = qed_check_l2_table(check,
150: check->request.l2_table->table);
151:
152: /* Write out fixed L2 table */
153: if (num_invalid_l2 > 0 && check->fix) {
154: ret = qed_write_l2_table_sync(s, &check->request, 0,
155: s->table_nelems, false);
156: if (ret) {
157: check->result->check_errors++;
158: last_error = ret;
159: continue;
160: }
161: }
162: }
163:
164: /* Drop reference to final table */
165: qed_unref_l2_cache_entry(check->request.l2_table);
166: check->request.l2_table = NULL;
167:
168: /* Write out fixed L1 table */
169: if (num_invalid_l1 > 0 && check->fix) {
170: ret = qed_write_l1_table_sync(s, 0, s->table_nelems);
171: if (ret) {
172: check->result->check_errors++;
173: last_error = ret;
174: }
175: }
176:
177: return last_error;
178: }
179:
180: /**
181: * Check for unreferenced (leaked) clusters
182: */
183: static void qed_check_for_leaks(QEDCheck *check)
184: {
185: BDRVQEDState *s = check->s;
1.1.1.2 root 186: uint64_t i;
1.1 root 187:
188: for (i = s->header.header_size; i < check->nclusters; i++) {
189: if (!qed_test_bit(check->used_clusters, i)) {
190: check->result->leaks++;
191: }
192: }
193: }
194:
195: int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
196: {
197: QEDCheck check = {
198: .s = s,
199: .result = result,
200: .nclusters = qed_bytes_to_clusters(s, s->file_size),
201: .request = { .l2_table = NULL },
202: .fix = fix,
203: };
204: int ret;
205:
1.1.1.4 root 206: check.used_clusters = g_malloc0(((check.nclusters + 31) / 32) *
1.1 root 207: sizeof(check.used_clusters[0]));
208:
1.1.1.5 ! root 209: check.result->bfi.total_clusters =
! 210: (s->header.image_size + s->header.cluster_size - 1) /
! 211: s->header.cluster_size;
1.1 root 212: ret = qed_check_l1_table(&check, s->l1_table);
213: if (ret == 0) {
214: /* Only check for leaks if entire image was scanned successfully */
215: qed_check_for_leaks(&check);
216: }
217:
1.1.1.4 root 218: g_free(check.used_clusters);
1.1 root 219: return ret;
220: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.