|
|
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: ! 21: size_t nclusters; ! 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; ! 71: ! 72: for (i = 0; i < s->table_nelems; i++) { ! 73: uint64_t offset = table->offsets[i]; ! 74: ! 75: if (!offset) { ! 76: continue; ! 77: } ! 78: ! 79: /* Detect invalid cluster offset */ ! 80: if (!qed_check_cluster_offset(s, offset)) { ! 81: if (check->fix) { ! 82: table->offsets[i] = 0; ! 83: } else { ! 84: check->result->corruptions++; ! 85: } ! 86: ! 87: num_invalid++; ! 88: continue; ! 89: } ! 90: ! 91: qed_set_used_clusters(check, offset, 1); ! 92: } ! 93: ! 94: return num_invalid; ! 95: } ! 96: ! 97: /** ! 98: * Descend tables and check each cluster is referenced once only ! 99: */ ! 100: static int qed_check_l1_table(QEDCheck *check, QEDTable *table) ! 101: { ! 102: BDRVQEDState *s = check->s; ! 103: unsigned int i, num_invalid_l1 = 0; ! 104: int ret, last_error = 0; ! 105: ! 106: /* Mark L1 table clusters used */ ! 107: qed_set_used_clusters(check, s->header.l1_table_offset, ! 108: s->header.table_size); ! 109: ! 110: for (i = 0; i < s->table_nelems; i++) { ! 111: unsigned int num_invalid_l2; ! 112: uint64_t offset = table->offsets[i]; ! 113: ! 114: if (!offset) { ! 115: continue; ! 116: } ! 117: ! 118: /* Detect invalid L2 offset */ ! 119: if (!qed_check_table_offset(s, offset)) { ! 120: /* Clear invalid offset */ ! 121: if (check->fix) { ! 122: table->offsets[i] = 0; ! 123: } else { ! 124: check->result->corruptions++; ! 125: } ! 126: ! 127: num_invalid_l1++; ! 128: continue; ! 129: } ! 130: ! 131: if (!qed_set_used_clusters(check, offset, s->header.table_size)) { ! 132: continue; /* skip an invalid table */ ! 133: } ! 134: ! 135: ret = qed_read_l2_table_sync(s, &check->request, offset); ! 136: if (ret) { ! 137: check->result->check_errors++; ! 138: last_error = ret; ! 139: continue; ! 140: } ! 141: ! 142: num_invalid_l2 = qed_check_l2_table(check, ! 143: check->request.l2_table->table); ! 144: ! 145: /* Write out fixed L2 table */ ! 146: if (num_invalid_l2 > 0 && check->fix) { ! 147: ret = qed_write_l2_table_sync(s, &check->request, 0, ! 148: s->table_nelems, false); ! 149: if (ret) { ! 150: check->result->check_errors++; ! 151: last_error = ret; ! 152: continue; ! 153: } ! 154: } ! 155: } ! 156: ! 157: /* Drop reference to final table */ ! 158: qed_unref_l2_cache_entry(check->request.l2_table); ! 159: check->request.l2_table = NULL; ! 160: ! 161: /* Write out fixed L1 table */ ! 162: if (num_invalid_l1 > 0 && check->fix) { ! 163: ret = qed_write_l1_table_sync(s, 0, s->table_nelems); ! 164: if (ret) { ! 165: check->result->check_errors++; ! 166: last_error = ret; ! 167: } ! 168: } ! 169: ! 170: return last_error; ! 171: } ! 172: ! 173: /** ! 174: * Check for unreferenced (leaked) clusters ! 175: */ ! 176: static void qed_check_for_leaks(QEDCheck *check) ! 177: { ! 178: BDRVQEDState *s = check->s; ! 179: size_t i; ! 180: ! 181: for (i = s->header.header_size; i < check->nclusters; i++) { ! 182: if (!qed_test_bit(check->used_clusters, i)) { ! 183: check->result->leaks++; ! 184: } ! 185: } ! 186: } ! 187: ! 188: int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix) ! 189: { ! 190: QEDCheck check = { ! 191: .s = s, ! 192: .result = result, ! 193: .nclusters = qed_bytes_to_clusters(s, s->file_size), ! 194: .request = { .l2_table = NULL }, ! 195: .fix = fix, ! 196: }; ! 197: int ret; ! 198: ! 199: check.used_clusters = qemu_mallocz(((check.nclusters + 31) / 32) * ! 200: sizeof(check.used_clusters[0])); ! 201: ! 202: ret = qed_check_l1_table(&check, s->l1_table); ! 203: if (ret == 0) { ! 204: /* Only check for leaks if entire image was scanned successfully */ ! 205: qed_check_for_leaks(&check); ! 206: } ! 207: ! 208: qemu_free(check.used_clusters); ! 209: return ret; ! 210: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.