From patchwork Fri Apr 15 14:18:58 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasad Joshi X-Patchwork-Id: 710811 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p3FEIw1H014188 for ; Fri, 15 Apr 2011 14:18:58 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755730Ab1DOOSz (ORCPT ); Fri, 15 Apr 2011 10:18:55 -0400 Received: from mail-wy0-f174.google.com ([74.125.82.174]:54586 "EHLO mail-wy0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754879Ab1DOOSw (ORCPT ); Fri, 15 Apr 2011 10:18:52 -0400 Received: by mail-wy0-f174.google.com with SMTP id 21so2282662wya.19 for ; Fri, 15 Apr 2011 07:18:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references; bh=vxJyHtW6nG1L6s0UeCu7wzAJh3WhXgy/xkmjeKaQs7c=; b=jQiN8VOzsQSWhmNXfxokixsCFoV05yix67bYwHwQssjNoNs2scSmHfsFpFitmLi1VH 2ZeSMlxr+/X4pABkad3/3v4j807NSX3j5PyhGlwhzu9wL7cPof0u7oh0vtaKAzEcix1m uYmTsWQYqlXpe4wJ4I7pe+eYnYtPC4OBk7r0s= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=akvj7bKgXUzCT2iXH3aPZAXg24tfHz24H3hTMOmEz5EzJ4cLbm/ev8g0nS42ExVbbW 4BGTU9de/vwVx/0tgxzJODFxpfL5p7rmzW0RBxtYpdk12a+aipebb5fLFOR8KGMr7oSZ M/kJARSE0TIxvzlMJ7W9iehVgosdDWei0/Uwo= Received: by 10.216.145.134 with SMTP id p6mr1035784wej.112.1302877131653; Fri, 15 Apr 2011 07:18:51 -0700 (PDT) Received: from prasad-kvm.localdomain (pineapple.rdg.ac.uk [134.225.206.123]) by mx.google.com with ESMTPS id t5sm1337167wes.33.2011.04.15.07.18.49 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 15 Apr 2011 07:18:50 -0700 (PDT) Received: by prasad-kvm.localdomain (Postfix, from userid 1000) id 09A8526E0072; Fri, 15 Apr 2011 15:18:59 +0100 (BST) From: Prasad Joshi To: prasadjoshi124@gmail.com Cc: mingo@elte.hu, kvm@vger.kernel.org, penberg@kernel.org, asias.hejun@gmail.com, gorcunov@gmail.com, levinsasha928@gmail.com, kwolf@redhat.com, stefanha@linux.vnet.ibm.com, chaitanyakulkarni15@gmail.com Subject: [PATCH 4/4] kvm tool: check the cluster boundary in the qcow read code. Date: Fri, 15 Apr 2011 15:18:58 +0100 Message-Id: <1302877138-6695-4-git-send-email-prasadjoshi124@gmail.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1302877138-6695-1-git-send-email-prasadjoshi124@gmail.com> References: <1302877138-6695-1-git-send-email-prasadjoshi124@gmail.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Fri, 15 Apr 2011 14:18:58 +0000 (UTC) Add a new function qcow1_read_cluster() to read a qcow cluster size data at a time. The function qcow1_read_sector() is modified to use the function qcow1_read_cluster(). Signed-off-by: Prasad Joshi --- tools/kvm/qcow.c | 123 ++++++++++++++++++++++++++++++++++-------------------- 1 files changed, 78 insertions(+), 45 deletions(-) diff --git a/tools/kvm/qcow.c b/tools/kvm/qcow.c index 9b9af86..e6d5897 100644 --- a/tools/kvm/qcow.c +++ b/tools/kvm/qcow.c @@ -36,68 +36,101 @@ static inline uint64_t get_cluster_offset(struct qcow *q, uint64_t offset) return offset & ((1 << header->cluster_bits)-1); } -static int qcow1_read_sector(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len) +static uint32_t qcow1_read_cluster(struct qcow *q, uint64_t offset, void *dst, uint32_t dst_len) { - struct qcow *q = self->priv; struct qcow1_header *header = q->header; - uint64_t l2_table_offset; - uint64_t l2_table_size; - uint64_t clust_offset; - uint64_t clust_start; - uint64_t *l2_table; - uint64_t l1_idx; - uint64_t l2_idx; - uint64_t offset; - - offset = sector << SECTOR_SHIFT; - if (offset >= header->size) - goto out_error; + struct qcow_table *table = &q->table; + uint32_t length; + + uint32_t l2_table_size; + u64 l2_table_offset; + u64 *l2_table; + u64 l2_idx; - l1_idx = get_l1_index(q, offset); + uint32_t clust_size; + u64 clust_offset; + u64 clust_start; - if (l1_idx >= q->table.table_size) - goto out_error; + u64 l1_idx; - l2_table_offset = q->table.l1_table[l1_idx]; - if (!l2_table_offset) - goto zero_sector; + clust_size = 1 << header->cluster_bits; + l2_table_size = 1 << header->l2_bits; - l2_table_size = 1 << header->l2_bits; + l1_idx = get_l1_index(q, offset); + if (l1_idx >= table->table_size) + goto error; - l2_table = calloc(l2_table_size, sizeof(uint64_t)); - if (!l2_table) - goto out_error; + l2_idx = get_l2_index(q, offset); + if (l2_idx >= l2_table_size) + goto error; - if (pread_in_full(q->fd, l2_table, sizeof(uint64_t) * l2_table_size, l2_table_offset) < 0) - goto out_error_free_l2; + clust_offset = get_cluster_offset(q, offset); + if (clust_offset >= clust_size) + goto error; - l2_idx = get_l2_index(q, offset); + length = clust_size - clust_offset; + if (length > dst_len) + length = dst_len; - if (l2_idx >= l2_table_size) - goto out_error_free_l2; + l2_table_offset = table->l1_table[l1_idx]; + if (!l2_table_offset) { + /* unallocated level 2 table: returned zeroed data */ + memset(dst, 0, length); + goto out; + } - clust_start = be64_to_cpu(l2_table[l2_idx]); + l2_table = calloc(l2_table_size, sizeof(u64)); + if (!l2_table) + goto error; - if (!clust_start) - goto zero_sector; + if (pread_in_full(q->fd, l2_table, sizeof(u64) * l2_table_size, + l2_table_offset) < 0) + goto free_l2; - clust_offset = get_cluster_offset(q, offset); + clust_start = be64_to_cpu(l2_table[l2_idx]); + if (!clust_start) { + /* unalloacted cluster return zeroed data */ + memset(dst, 0, length); + free(l2_table); + goto out; + } - if (pread_in_full(q->fd, dst, dst_len, clust_start + clust_offset) < 0) - goto out_error_free_l2; + if (pread_in_full(q->fd, dst, length, clust_start + clust_offset) < 0) + goto free_l2; +out: + return length; +free_l2: free(l2_table); - +error: return 0; +} -zero_sector: - memset(dst, 0, dst_len); +static int qcow1_read_sector(struct disk_image *self, uint64_t sector, void *dst, uint32_t dst_len) +{ + struct qcow *q = self->priv; + struct qcow1_header *header = q->header; + uint32_t length = 0; + char *buf = dst; + uint64_t offset; + uint32_t nr; - return 0; + while (length < dst_len) { + offset = sector << SECTOR_SHIFT; + if (offset >= header->size) + goto error; -out_error_free_l2: - free(l2_table); -out_error: + nr = qcow1_read_cluster(q, offset, buf, dst_len - length); + if (!nr) + goto error; + + length += nr; + buf += nr; + sector += (nr >> SECTOR_SHIFT); + } + + return 0; +error: return -1; }