From mboxrd@z Thu Jan 1 00:00:00 1970 From: Pekka Enberg Subject: Re: [PATCH] kvm tool: QCOW version 1 write support. Date: Sun, 17 Apr 2011 13:52:38 +0300 (EEST) Message-ID: References: <1302890734-7871-1-git-send-email-prasadjoshi124@gmail.com> Mime-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed Cc: mingo@elte.hu, kvm@vger.kernel.org, asias.hejun@gmail.com, gorcunov@gmail.com, levinsasha928@gmail.com, kwolf@redhat.com, stefanha@linux.vnet.ibm.com, chaitanyakulkarni15@gmail.com To: Prasad Joshi Return-path: Received: from filtteri5.pp.htv.fi ([213.243.153.188]:45440 "EHLO filtteri5.pp.htv.fi" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752490Ab1DQKwl (ORCPT ); Sun, 17 Apr 2011 06:52:41 -0400 In-Reply-To: <1302890734-7871-1-git-send-email-prasadjoshi124@gmail.com> Sender: kvm-owner@vger.kernel.org List-ID: On Fri, 15 Apr 2011, Prasad Joshi wrote: > -static int qcow1_write_sector(struct disk_image *self, uint64_t sector, void *src, uint32_t src_len) > +static inline u64 get_file_length(int fd) > { > + struct stat st; > + > + if (fstat(fd, &st) < 0) > + return 0; > + return st.st_size; > +} Wouldn't it be better to put this in 'struct disk_image'? We do fstat() upon startup anyway. > + > +static inline u64 align(u64 address, uint32_t size) > +{ > + return (address + size) & (~(size - 1)); > +} There's ALIGN macro somewhere in include/linux. Use that. > +static uint32_t qcow1_write_cluster(struct qcow *q, uint64_t offset, void *buf, > + uint32_t src_len) > +{ > + struct qcow1_header *header = q->header; > + struct qcow_table *table = &q->table; > + uint32_t length; Please use u32, u64, and friends. > + > + uint32_t l2_table_size; > + u64 l2_table_offset; > + u64 *l2_table; > + u64 l2_idx; > + > + uint32_t clust_size; > + u64 clust_offset; > + u64 clust_start; > + > + u64 l1_idx; > + u64 tmp; > + > + l2_table_size = 1 << header->l2_bits; > + clust_size = 1 << header->cluster_bits; > + > + l1_idx = get_l1_index(q, offset); > + if (l1_idx >= table->table_size) > + goto error; > + > + l2_idx = get_l2_index(q, offset); > + if (l2_idx >= l2_table_size) > + goto error; > + > + clust_offset = get_cluster_offset(q, offset); > + if (clust_offset >= clust_size) > + goto error; > + > + length = clust_size - clust_offset; > + if (length > src_len) > + length = src_len; > + > + l2_table = calloc(l2_table_size, sizeof(u64)); > + if (!l2_table) > + goto error; > + > + l2_table_offset = table->l1_table[l1_idx]; > + if (l2_table_offset) { > + if (pread_in_full(q->fd, l2_table, l2_table_size * sizeof(u64), > + l2_table_offset) < 0) > + goto free_l2; > + } else { > + /* > + * 1. write a level 2 table of zeros at the end of the file > + * 2. update the level1 table > + */ > + l2_table_offset = align(get_file_length(q->fd), clust_size); > + table->l1_table[l1_idx] = l2_table_offset; > + > + if (qcow_pwrite_with_sync(q->fd, l2_table, > + l2_table_size * sizeof(u64), > + l2_table_offset) < 0) > + goto free_l2; > + > + tmp = cpu_to_be64(l2_table_offset); > + if (qcow_pwrite_with_sync(q->fd, &tmp, sizeof(tmp), > + header->l1_table_offset + > + (l1_idx * sizeof(u64))) < 0) > + goto free_l2; > + } Maybe it's best to split this in a separate function? qcow_write_l2_table() or something? It would also nice to have some comments explaining what exactly you're trying to do with fsync() calls there. > + > + clust_start = be64_to_cpu(l2_table[l2_idx]); > + free(l2_table); > + if (clust_start) { > + if (qcow_pwrite_with_sync(q->fd, buf, length, > + clust_start + clust_offset) < 0) > + goto error; > + } else { > + /* > + * Follow the write order to avoid metadata loss > + * 1. write the data at the end of the file > + * 2. update the l2_table with new > + */ > + clust_start = align(get_file_length(q->fd), clust_size); > + if (qcow_pwrite_with_sync(q->fd, buf, length, > + clust_start + clust_offset) < 0) > + goto error; > + > + tmp = cpu_to_be64(clust_start); > + if (qcow_pwrite_with_sync(q->fd, &tmp, sizeof(tmp), > + l2_table_offset + > + (l2_idx * sizeof(u64))) < 0) > + goto error; > + } > + return length; You can get rid of some duplication with: clust_start = be64_to_cpu(l2_table[l2_idx]); if (!clust_start) { clust_start = ALIGN(...); update_metadata = true; } if (qcow_pwrite_with_sync(....) < 0) goto error; if (update_metadata) { // ... } Pekka