|
|
1.1 ! root 1: /* ! 2: * QEMU Enhanced Disk Format Cluster functions ! 3: * ! 4: * Copyright IBM, Corp. 2010 ! 5: * ! 6: * Authors: ! 7: * Stefan Hajnoczi <[email protected]> ! 8: * Anthony Liguori <[email protected]> ! 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.