Annotation of qemu/block/qed-check.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.