All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks
@ 2011-12-12  2:03 Lan Tianyu
  2011-12-12  9:55 ` Kevin Wolf
  0 siblings, 1 reply; 13+ messages in thread
From: Lan Tianyu @ 2011-12-12  2:03 UTC (permalink / raw)
  To: penberg
  Cc: Lan Tianyu, kvm, asias.hejun, levinsasha928, prasadjoshi124, kwolf

This patch enables allocating new refcount blocks and so then kvm tools
could expand qcow2 image much larger.

Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
---
 tools/kvm/disk/qcow.c |  105 +++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 89 insertions(+), 16 deletions(-)

diff --git a/tools/kvm/disk/qcow.c b/tools/kvm/disk/qcow.c
index e139fa5..929ba69 100644
--- a/tools/kvm/disk/qcow.c
+++ b/tools/kvm/disk/qcow.c
@@ -12,6 +12,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <errno.h>
 #ifdef CONFIG_HAS_ZLIB
 #include <zlib.h>
 #endif
@@ -20,6 +21,10 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 
+static int update_cluster_refcount(struct qcow *q, u64 clust_idx, u16 append);
+static int qcow_write_refcount_table(struct qcow *q);
+static u64 qcow_alloc_clusters(struct qcow *q, u64 size, int update_ref);
+static void  qcow_free_clusters(struct qcow *q, u64 clust_start, u64 size);
 
 static inline int qcow_pwrite_sync(int fd,
 	void *buf, size_t count, off_t offset)
@@ -657,6 +662,56 @@ static struct qcow_refcount_block *refcount_block_search(struct qcow *q, u64 off
 	return rfb;
 }
 
+static struct qcow_refcount_block *qcow_grow_refcount_block(struct qcow *q,
+	u64 clust_idx)
+{
+	struct qcow_header *header = q->header;
+	struct qcow_refcount_table *rft = &q->refcount_table;
+	struct qcow_refcount_block *rfb;
+	u64 new_block_offset;
+	u64 rft_idx;
+
+	rft_idx = clust_idx >> (header->cluster_bits -
+		QCOW_REFCOUNT_BLOCK_SHIFT);
+
+	if (rft_idx >= rft->rf_size) {
+		pr_warning("Don't support grow refcount block table");
+		return NULL;
+	}
+
+	new_block_offset = qcow_alloc_clusters(q, q->cluster_size, 0);
+	if (new_block_offset < 0)
+		return NULL;
+
+	rfb = new_refcount_block(q, new_block_offset);
+	if (!rfb)
+		return NULL;
+
+	memset(rfb->entries, 0x00, q->cluster_size);
+	rfb->dirty = 1;
+
+	/* write refcount block */
+	if (write_refcount_block(q, rfb) < 0)
+		goto free_rfb;
+
+	if (cache_refcount_block(q, rfb) < 0)
+		goto free_rfb;
+
+	rft->rf_table[rft_idx] = cpu_to_be64(new_block_offset);
+	if (qcow_write_refcount_table(q) < 0)
+		goto free_rfb;
+
+	if (update_cluster_refcount(q, new_block_offset >>
+		    header->cluster_bits, 1) < 0)
+		goto free_rfb;
+
+	return rfb;
+
+free_rfb:
+	free(rfb);
+	return NULL;
+}
+
 static struct qcow_refcount_block *qcow_read_refcount_block(struct qcow *q, u64 clust_idx)
 {
 	struct qcow_header *header = q->header;
@@ -667,14 +722,11 @@ static struct qcow_refcount_block *qcow_read_refcount_block(struct qcow *q, u64
 
 	rft_idx = clust_idx >> (header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT);
 	if (rft_idx >= rft->rf_size)
-		return NULL;
+		return (void *)-ENOSPC;
 
 	rfb_offset = be64_to_cpu(rft->rf_table[rft_idx]);
-
-	if (!rfb_offset) {
-		pr_warning("Don't support to grow refcount table");
-		return NULL;
-	}
+	if (!rfb_offset)
+		return (void *)-ENOSPC;
 
 	rfb = refcount_block_search(q, rfb_offset);
 	if (rfb)
@@ -708,7 +760,8 @@ static u16 qcow_get_refcount(struct qcow *q, u64 clust_idx)
 	if (!rfb) {
 		pr_warning("Error while reading refcount table");
 		return -1;
-	}
+	} else if ((long)rfb == -ENOSPC)
+		return 0;
 
 	rfb_idx = clust_idx & (((1ULL <<
 		(header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT)) - 1));
@@ -732,6 +785,12 @@ static int update_cluster_refcount(struct qcow *q, u64 clust_idx, u16 append)
 	if (!rfb) {
 		pr_warning("error while reading refcount table");
 		return -1;
+	} else if ((long)rfb == -ENOSPC) {
+		rfb = qcow_grow_refcount_block(q, clust_idx);
+		if (!rfb) {
+			pr_warning("error while growing refcount table");
+			return -1;
+		}
 	}
 
 	rfb_idx = clust_idx & (((1ULL <<
@@ -774,11 +833,11 @@ static void  qcow_free_clusters(struct qcow *q, u64 clust_start, u64 size)
  * can satisfy the size. free_clust_idx is initialized to zero and
  * Record last position.
  */
-static u64 qcow_alloc_clusters(struct qcow *q, u64 size)
+static u64 qcow_alloc_clusters(struct qcow *q, u64 size, int update_ref)
 {
 	struct qcow_header *header = q->header;
 	u16 clust_refcount;
-	u32 clust_idx, i;
+	u32 clust_idx = 0, i;
 	u64 clust_num;
 
 	clust_num = (size + (q->cluster_size - 1)) >> header->cluster_bits;
@@ -793,12 +852,15 @@ again:
 			goto again;
 	}
 
-	for (i = 0; i < clust_num; i++)
-		if (update_cluster_refcount(q,
-			q->free_clust_idx - clust_num + i, 1))
-			return -1;
+	clust_idx++;
+
+	if (update_ref)
+		for (i = 0; i < clust_num; i++)
+			if (update_cluster_refcount(q,
+				clust_idx - clust_num + i, 1))
+				return -1;
 
-	return (q->free_clust_idx - clust_num) << header->cluster_bits;
+	return (clust_idx - clust_num) << header->cluster_bits;
 }
 
 static int qcow_write_l1_table(struct qcow *q)
@@ -848,7 +910,9 @@ static int get_cluster_table(struct qcow *q, u64 offset,
 		if (!l2t)
 			goto error;
 	} else {
-		l2t_new_offset = qcow_alloc_clusters(q, l2t_size*sizeof(u64));
+		l2t_new_offset = qcow_alloc_clusters(q,
+			l2t_size*sizeof(u64), 1);
+
 		if (l2t_new_offset < 0)
 			goto error;
 
@@ -937,7 +1001,7 @@ static ssize_t qcow_write_cluster(struct qcow *q, u64 offset,
 
 	clust_start &= QCOW2_OFFSET_MASK;
 	if (!(clust_flags & QCOW2_OFLAG_COPIED)) {
-		clust_new_start	= qcow_alloc_clusters(q, q->cluster_size);
+		clust_new_start	= qcow_alloc_clusters(q, q->cluster_size, 1);
 		if (clust_new_start < 0) {
 			pr_warning("Cluster alloc error");
 			goto error;
@@ -1143,6 +1207,15 @@ static int qcow_read_refcount_table(struct qcow *q)
 	return pread_in_full(q->fd, rft->rf_table, sizeof(u64) * rft->rf_size, header->refcount_table_offset);
 }
 
+static int qcow_write_refcount_table(struct qcow *q)
+{
+	struct qcow_header *header = q->header;
+	struct qcow_refcount_table *rft = &q->refcount_table;
+
+	return qcow_pwrite_sync(q->fd, rft->rf_table,
+		rft->rf_size * sizeof(u64), header->refcount_table_offset);
+}
+
 static int qcow_read_l1_table(struct qcow *q)
 {
 	struct qcow_header *header = q->header;
-- 
1.7.6.rc2.8.g28eb


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks
  2011-12-12  2:03 [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks Lan Tianyu
@ 2011-12-12  9:55 ` Kevin Wolf
  2011-12-12 10:58   ` Pekka Enberg
  2011-12-13  3:05   ` lan,Tianyu
  0 siblings, 2 replies; 13+ messages in thread
From: Kevin Wolf @ 2011-12-12  9:55 UTC (permalink / raw)
  To: Lan Tianyu; +Cc: penberg, kvm, asias.hejun, levinsasha928, prasadjoshi124

Am 12.12.2011 03:03, schrieb Lan Tianyu:
> This patch enables allocating new refcount blocks and so then kvm tools
> could expand qcow2 image much larger.
> 
> Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
> ---
>  tools/kvm/disk/qcow.c |  105 +++++++++++++++++++++++++++++++++++++++++-------
>  1 files changed, 89 insertions(+), 16 deletions(-)
> 
> diff --git a/tools/kvm/disk/qcow.c b/tools/kvm/disk/qcow.c
> index e139fa5..929ba69 100644
> --- a/tools/kvm/disk/qcow.c
> +++ b/tools/kvm/disk/qcow.c
> @@ -12,6 +12,7 @@
>  #include <string.h>
>  #include <unistd.h>
>  #include <fcntl.h>
> +#include <errno.h>
>  #ifdef CONFIG_HAS_ZLIB
>  #include <zlib.h>
>  #endif
> @@ -20,6 +21,10 @@
>  #include <linux/kernel.h>
>  #include <linux/types.h>
>  
> +static int update_cluster_refcount(struct qcow *q, u64 clust_idx, u16 append);
> +static int qcow_write_refcount_table(struct qcow *q);
> +static u64 qcow_alloc_clusters(struct qcow *q, u64 size, int update_ref);
> +static void  qcow_free_clusters(struct qcow *q, u64 clust_start, u64 size);
>  
>  static inline int qcow_pwrite_sync(int fd,
>  	void *buf, size_t count, off_t offset)
> @@ -657,6 +662,56 @@ static struct qcow_refcount_block *refcount_block_search(struct qcow *q, u64 off
>  	return rfb;
>  }
>  
> +static struct qcow_refcount_block *qcow_grow_refcount_block(struct qcow *q,
> +	u64 clust_idx)
> +{
> +	struct qcow_header *header = q->header;
> +	struct qcow_refcount_table *rft = &q->refcount_table;
> +	struct qcow_refcount_block *rfb;
> +	u64 new_block_offset;
> +	u64 rft_idx;
> +
> +	rft_idx = clust_idx >> (header->cluster_bits -
> +		QCOW_REFCOUNT_BLOCK_SHIFT);
> +
> +	if (rft_idx >= rft->rf_size) {
> +		pr_warning("Don't support grow refcount block table");
> +		return NULL;
> +	}
> +
> +	new_block_offset = qcow_alloc_clusters(q, q->cluster_size, 0);
> +	if (new_block_offset < 0)
> +		return NULL;
> +
> +	rfb = new_refcount_block(q, new_block_offset);
> +	if (!rfb)
> +		return NULL;
> +
> +	memset(rfb->entries, 0x00, q->cluster_size);
> +	rfb->dirty = 1;
> +
> +	/* write refcount block */
> +	if (write_refcount_block(q, rfb) < 0)
> +		goto free_rfb;
> +
> +	if (cache_refcount_block(q, rfb) < 0)
> +		goto free_rfb;
> +
> +	rft->rf_table[rft_idx] = cpu_to_be64(new_block_offset);
> +	if (qcow_write_refcount_table(q) < 0)
> +		goto free_rfb;
> +
> +	if (update_cluster_refcount(q, new_block_offset >>
> +		    header->cluster_bits, 1) < 0)
> +		goto free_rfb;

This order is unsafe, you could end up with a refcount block that is
already in use, but still has a refcount of 0.

> +
> +	return rfb;
> +
> +free_rfb:
> +	free(rfb);
> +	return NULL;
> +}
> +
>  static struct qcow_refcount_block *qcow_read_refcount_block(struct qcow *q, u64 clust_idx)
>  {
>  	struct qcow_header *header = q->header;
> @@ -667,14 +722,11 @@ static struct qcow_refcount_block *qcow_read_refcount_block(struct qcow *q, u64
>  
>  	rft_idx = clust_idx >> (header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT);
>  	if (rft_idx >= rft->rf_size)
> -		return NULL;
> +		return (void *)-ENOSPC;

Is this allowed style in kvm-tool? :-/

Kevin

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks
  2011-12-12  9:55 ` Kevin Wolf
@ 2011-12-12 10:58   ` Pekka Enberg
  2011-12-12 11:15     ` Kevin Wolf
  2011-12-13  3:16     ` lan,Tianyu
  2011-12-13  3:05   ` lan,Tianyu
  1 sibling, 2 replies; 13+ messages in thread
From: Pekka Enberg @ 2011-12-12 10:58 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Lan Tianyu, kvm, asias.hejun, levinsasha928, prasadjoshi124

On Mon, 12 Dec 2011, Kevin Wolf wrote:
>> @@ -667,14 +722,11 @@ static struct qcow_refcount_block *qcow_read_refcount_block(struct qcow *q, u64
>>
>>  	rft_idx = clust_idx >> (header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT);
>>  	if (rft_idx >= rft->rf_size)
>> -		return NULL;
>> +		return (void *)-ENOSPC;
>
> Is this allowed style in kvm-tool? :-/

It needs to use ERR_PTR() and related macros but otherwise I don't see a 
big problem with it.

 			Pekka

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks
  2011-12-12 10:58   ` Pekka Enberg
@ 2011-12-12 11:15     ` Kevin Wolf
  2011-12-12 11:17       ` Kevin Wolf
  2011-12-13  3:41       ` lan,Tianyu
  2011-12-13  3:16     ` lan,Tianyu
  1 sibling, 2 replies; 13+ messages in thread
From: Kevin Wolf @ 2011-12-12 11:15 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: Lan Tianyu, kvm, asias.hejun, levinsasha928, prasadjoshi124

Am 12.12.2011 11:58, schrieb Pekka Enberg:
> On Mon, 12 Dec 2011, Kevin Wolf wrote:
>>> @@ -667,14 +722,11 @@ static struct qcow_refcount_block *qcow_read_refcount_block(struct qcow *q, u64
>>>
>>>  	rft_idx = clust_idx >> (header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT);
>>>  	if (rft_idx >= rft->rf_size)
>>> -		return NULL;
>>> +		return (void *)-ENOSPC;
>>
>> Is this allowed style in kvm-tool? :-/
> 
> It needs to use ERR_PTR() and related macros but otherwise I don't see a 
> big problem with it.

Can you be sure that it never clashes with a valid allocation when you
use this in userspace?

But yes, at least using appropriate functions should be required. And
this means that you can't only check for -ENOSPC, but you need to check
for all possible error codes (IS_ERR_VALUE() I guess).

Kevin

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks
  2011-12-12 11:15     ` Kevin Wolf
@ 2011-12-12 11:17       ` Kevin Wolf
  2011-12-13  3:41       ` lan,Tianyu
  1 sibling, 0 replies; 13+ messages in thread
From: Kevin Wolf @ 2011-12-12 11:17 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: Lan Tianyu, kvm, asias.hejun, levinsasha928, prasadjoshi124

Am 12.12.2011 12:15, schrieb Kevin Wolf:
> Am 12.12.2011 11:58, schrieb Pekka Enberg:
>> On Mon, 12 Dec 2011, Kevin Wolf wrote:
>>>> @@ -667,14 +722,11 @@ static struct qcow_refcount_block *qcow_read_refcount_block(struct qcow *q, u64
>>>>
>>>>  	rft_idx = clust_idx >> (header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT);
>>>>  	if (rft_idx >= rft->rf_size)
>>>> -		return NULL;
>>>> +		return (void *)-ENOSPC;
>>>
>>> Is this allowed style in kvm-tool? :-/
>>
>> It needs to use ERR_PTR() and related macros but otherwise I don't see a 
>> big problem with it.
> 
> Can you be sure that it never clashes with a valid allocation when you
> use this in userspace?

Er, not sure what I was thinking, but it's the top 4k of the address
space, which should be kernel memory. So I think you actually can be sure.

Kevin

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks
  2011-12-12  9:55 ` Kevin Wolf
  2011-12-12 10:58   ` Pekka Enberg
@ 2011-12-13  3:05   ` lan,Tianyu
  2011-12-13  9:03     ` Kevin Wolf
  1 sibling, 1 reply; 13+ messages in thread
From: lan,Tianyu @ 2011-12-13  3:05 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: penberg, kvm, asias.hejun, levinsasha928, prasadjoshi124

Thanks for your review.
On 一, 2011-12-12 at 17:55 +0800, Kevin Wolf wrote:
> Am 12.12.2011 03:03, schrieb Lan Tianyu:
> > This patch enables allocating new refcount blocks and so then kvm tools
> > could expand qcow2 image much larger.
> > 
> > Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
> > ---
> >  tools/kvm/disk/qcow.c |  105 +++++++++++++++++++++++++++++++++++++++++-------
> >  1 files changed, 89 insertions(+), 16 deletions(-)
> > 
> > diff --git a/tools/kvm/disk/qcow.c b/tools/kvm/disk/qcow.c
> > index e139fa5..929ba69 100644
> > --- a/tools/kvm/disk/qcow.c
> > +++ b/tools/kvm/disk/qcow.c
> > @@ -12,6 +12,7 @@
> >  #include <string.h>
> >  #include <unistd.h>
> >  #include <fcntl.h>
> > +#include <errno.h>
> >  #ifdef CONFIG_HAS_ZLIB
> >  #include <zlib.h>
> >  #endif
> > @@ -20,6 +21,10 @@
> >  #include <linux/kernel.h>
> >  #include <linux/types.h>
> >  
> > +static int update_cluster_refcount(struct qcow *q, u64 clust_idx, u16 append);
> > +static int qcow_write_refcount_table(struct qcow *q);
> > +static u64 qcow_alloc_clusters(struct qcow *q, u64 size, int update_ref);
> > +static void  qcow_free_clusters(struct qcow *q, u64 clust_start, u64 size);
> >  
> >  static inline int qcow_pwrite_sync(int fd,
> >  	void *buf, size_t count, off_t offset)
> > @@ -657,6 +662,56 @@ static struct qcow_refcount_block *refcount_block_search(struct qcow *q, u64 off
> >  	return rfb;
> >  }
> >  
> > +static struct qcow_refcount_block *qcow_grow_refcount_block(struct qcow *q,
> > +	u64 clust_idx)
> > +{
> > +	struct qcow_header *header = q->header;
> > +	struct qcow_refcount_table *rft = &q->refcount_table;
> > +	struct qcow_refcount_block *rfb;
> > +	u64 new_block_offset;
> > +	u64 rft_idx;
> > +
> > +	rft_idx = clust_idx >> (header->cluster_bits -
> > +		QCOW_REFCOUNT_BLOCK_SHIFT);
> > +
> > +	if (rft_idx >= rft->rf_size) {
> > +		pr_warning("Don't support grow refcount block table");
> > +		return NULL;
> > +	}
> > +
> > +	new_block_offset = qcow_alloc_clusters(q, q->cluster_size, 0);
> > +	if (new_block_offset < 0)
> > +		return NULL;
> > +
> > +	rfb = new_refcount_block(q, new_block_offset);
> > +	if (!rfb)
> > +		return NULL;
> > +
> > +	memset(rfb->entries, 0x00, q->cluster_size);
> > +	rfb->dirty = 1;
> > +
> > +	/* write refcount block */
> > +	if (write_refcount_block(q, rfb) < 0)
> > +		goto free_rfb;
> > +
> > +	if (cache_refcount_block(q, rfb) < 0)
> > +		goto free_rfb;
> > +
> > +	rft->rf_table[rft_idx] = cpu_to_be64(new_block_offset);
> > +	if (qcow_write_refcount_table(q) < 0)
> > +		goto free_rfb;
> > +
> > +	if (update_cluster_refcount(q, new_block_offset >>
> > +		    header->cluster_bits, 1) < 0)
> > +		goto free_rfb;
> 
> This order is unsafe, you could end up with a refcount block that is
> already in use, but still has a refcount of 0.
How about following?
rft->rf_table[rft_idx] = cpu_to_be64(new_block_offset);

if (update_cluster_refcount(q, new_block_offset >>
	header->cluster_bits, 1) < 0) {
	rft->rf_table[rft_idx] =  0;
	goto free_rfb;
}

if (qcow_write_refcount_table(q) < 0) {
	rft->rf_table[rft_idx] =  0;
	qcow_free_clusters(q, new_block_offset, q->cluster_size);
	goto free_rfb;
}

update_cluster_refcount() will use the rft->rf_table. So updating the rft->rf_table
must be before update_cluster_refcount().
> > +
> > +	return rfb;
> > +
> > +free_rfb:
> > +	free(rfb);
> > +	return NULL;
> > +}
> > +
> >  static struct qcow_refcount_block *qcow_read_refcount_block(struct qcow *q, u64 clust_idx)
> >  {
> >  	struct qcow_header *header = q->header;
> > @@ -667,14 +722,11 @@ static struct qcow_refcount_block *qcow_read_refcount_block(struct qcow *q, u64
> >  
> >  	rft_idx = clust_idx >> (header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT);
> >  	if (rft_idx >= rft->rf_size)
> > -		return NULL;
> > +		return (void *)-ENOSPC;
> 
> Is this allowed style in kvm-tool? :-/
> 
> Kevin



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks
  2011-12-12 10:58   ` Pekka Enberg
  2011-12-12 11:15     ` Kevin Wolf
@ 2011-12-13  3:16     ` lan,Tianyu
  2011-12-13  9:13       ` Pekka Enberg
  1 sibling, 1 reply; 13+ messages in thread
From: lan,Tianyu @ 2011-12-13  3:16 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: Kevin Wolf, kvm, asias.hejun, levinsasha928, prasadjoshi124

On 一, 2011-12-12 at 18:58 +0800, Pekka Enberg wrote:
> On Mon, 12 Dec 2011, Kevin Wolf wrote:
> >> @@ -667,14 +722,11 @@ static struct qcow_refcount_block *qcow_read_refcount_block(struct qcow *q, u64
> >>
> >>  	rft_idx = clust_idx >> (header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT);
> >>  	if (rft_idx >= rft->rf_size)
> >> -		return NULL;
> >> +		return (void *)-ENOSPC;
> >
> > Is this allowed style in kvm-tool? :-/
> 
> It needs to use ERR_PTR() and related macros but otherwise I don't see a 
> big problem with it.
> 
>  			Pekka

I have tried to use ERR_PTR(). But when I included linux/err.h, a
compile error  was following.

  CC       disk/qcow.o
In file included from disk/qcow.c:20:
../../include/linux/err.h:22: error: expected '=', ',', ';', 'asm' or
'__attribute__' before 'ERR_PTR'
../../include/linux/err.h:27: error: expected '=', ',', ';', 'asm' or
'__attribute__' before 'PTR_ERR'
../../include/linux/err.h:32: error: expected '=', ',', ';', 'asm' or
'__attribute__' before 'IS_ERR'
../../include/linux/err.h:37: error: expected '=', ',', ';', 'asm' or
'__attribute__' before 'IS_ERR_OR_NULL'
../../include/linux/err.h:49: error: expected '=', ',', ';', 'asm' or
'__attribute__' before 'ERR_CAST'
../../include/linux/err.h:55: error: expected '=', ',', ';', 'asm' or
'__attribute__' before 'PTR_RET'


in the linux/err.h

static inline void * __must_check ERR_PTR(long error)
{
	return (void *) error;
}

when I comment "__must_check", the error disappear.

Finally I did cast myself rather than use ERR_PTR().
Are there some substitutions of ERR_PTR in the user space or choices?
 



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks
  2011-12-12 11:15     ` Kevin Wolf
  2011-12-12 11:17       ` Kevin Wolf
@ 2011-12-13  3:41       ` lan,Tianyu
  2011-12-13  8:57         ` Kevin Wolf
  1 sibling, 1 reply; 13+ messages in thread
From: lan,Tianyu @ 2011-12-13  3:41 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Pekka Enberg, kvm, asias.hejun, levinsasha928, prasadjoshi124

On 一, 2011-12-12 at 19:15 +0800, Kevin Wolf wrote:
> Am 12.12.2011 11:58, schrieb Pekka Enberg:
> > On Mon, 12 Dec 2011, Kevin Wolf wrote:
> >>> @@ -667,14 +722,11 @@ static struct qcow_refcount_block *qcow_read_refcount_block(struct qcow *q, u64
> >>>
> >>>  	rft_idx = clust_idx >> (header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT);
> >>>  	if (rft_idx >= rft->rf_size)
> >>> -		return NULL;
> >>> +		return (void *)-ENOSPC;
> >>
> >> Is this allowed style in kvm-tool? :-/
> > 
> > It needs to use ERR_PTR() and related macros but otherwise I don't see a 
> > big problem with it.
> 
> Can you be sure that it never clashes with a valid allocation when you
> use this in userspace?
> 
> But yes, at least using appropriate functions should be required. And
> this means that you can't only check for -ENOSPC, but you need to check
> for all possible error codes (IS_ERR_VALUE() I guess).
The qcow_read_refcount_block() is invoiked in the two places
qcow_get_refcount() and update_cluster_refcount() and will only return
NULL or -ENOSPC.

In the qcow_get_refcount(), when qcow_read_refcount_block() returned
-ENOSPEC(no refcount block is available.), returning zero which means
the cluster is not in use and the refcount block can be grew in the
update_cluster_refcount().  

In the update_cluster_refcount(), when qcow_read_refcount_block()
returned -ENOSPEC, it is necessary to grow the refcount blocks.

So the ENOSPEC should be specially dealt with.  

Does this make sense? :)
> Kevin

Thanks
Tianyu Lan.




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks
  2011-12-13  3:41       ` lan,Tianyu
@ 2011-12-13  8:57         ` Kevin Wolf
  2011-12-13  9:14           ` Pekka Enberg
  2011-12-14  1:22           ` lan,Tianyu
  0 siblings, 2 replies; 13+ messages in thread
From: Kevin Wolf @ 2011-12-13  8:57 UTC (permalink / raw)
  To: lan,Tianyu; +Cc: Pekka Enberg, kvm, asias.hejun, levinsasha928, prasadjoshi124

Am 13.12.2011 04:41, schrieb lan,Tianyu:
> On 一, 2011-12-12 at 19:15 +0800, Kevin Wolf wrote:
>> Am 12.12.2011 11:58, schrieb Pekka Enberg:
>>> On Mon, 12 Dec 2011, Kevin Wolf wrote:
>>>>> @@ -667,14 +722,11 @@ static struct qcow_refcount_block *qcow_read_refcount_block(struct qcow *q, u64
>>>>>
>>>>>  	rft_idx = clust_idx >> (header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT);
>>>>>  	if (rft_idx >= rft->rf_size)
>>>>> -		return NULL;
>>>>> +		return (void *)-ENOSPC;
>>>>
>>>> Is this allowed style in kvm-tool? :-/
>>>
>>> It needs to use ERR_PTR() and related macros but otherwise I don't see a 
>>> big problem with it.
>>
>> Can you be sure that it never clashes with a valid allocation when you
>> use this in userspace?
>>
>> But yes, at least using appropriate functions should be required. And
>> this means that you can't only check for -ENOSPC, but you need to check
>> for all possible error codes (IS_ERR_VALUE() I guess).
> The qcow_read_refcount_block() is invoiked in the two places
> qcow_get_refcount() and update_cluster_refcount() and will only return
> NULL or -ENOSPC.
> 
> In the qcow_get_refcount(), when qcow_read_refcount_block() returned
> -ENOSPEC(no refcount block is available.), returning zero which means
> the cluster is not in use and the refcount block can be grew in the
> update_cluster_refcount().  
> 
> In the update_cluster_refcount(), when qcow_read_refcount_block()
> returned -ENOSPEC, it is necessary to grow the refcount blocks.
> 
> So the ENOSPEC should be specially dealt with.  
> 
> Does this make sense? :)

I'm not saying that your code won't work today, just that it's brittle.
If someone adds a different error return code somewhere and doesn't
check if all callers properly deal with error codes, it will break.

Kevin

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks
  2011-12-13  3:05   ` lan,Tianyu
@ 2011-12-13  9:03     ` Kevin Wolf
  0 siblings, 0 replies; 13+ messages in thread
From: Kevin Wolf @ 2011-12-13  9:03 UTC (permalink / raw)
  To: lan,Tianyu; +Cc: penberg, kvm, asias.hejun, levinsasha928, prasadjoshi124

Am 13.12.2011 04:05, schrieb lan,Tianyu:
> Thanks for your review.
> On 一, 2011-12-12 at 17:55 +0800, Kevin Wolf wrote:
>> Am 12.12.2011 03:03, schrieb Lan Tianyu:
>>> This patch enables allocating new refcount blocks and so then kvm tools
>>> could expand qcow2 image much larger.
>>>
>>> Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
>>> ---
>>>  tools/kvm/disk/qcow.c |  105 +++++++++++++++++++++++++++++++++++++++++-------
>>>  1 files changed, 89 insertions(+), 16 deletions(-)
>>>
>>> diff --git a/tools/kvm/disk/qcow.c b/tools/kvm/disk/qcow.c
>>> index e139fa5..929ba69 100644
>>> --- a/tools/kvm/disk/qcow.c
>>> +++ b/tools/kvm/disk/qcow.c
>>> @@ -12,6 +12,7 @@
>>>  #include <string.h>
>>>  #include <unistd.h>
>>>  #include <fcntl.h>
>>> +#include <errno.h>
>>>  #ifdef CONFIG_HAS_ZLIB
>>>  #include <zlib.h>
>>>  #endif
>>> @@ -20,6 +21,10 @@
>>>  #include <linux/kernel.h>
>>>  #include <linux/types.h>
>>>  
>>> +static int update_cluster_refcount(struct qcow *q, u64 clust_idx, u16 append);
>>> +static int qcow_write_refcount_table(struct qcow *q);
>>> +static u64 qcow_alloc_clusters(struct qcow *q, u64 size, int update_ref);
>>> +static void  qcow_free_clusters(struct qcow *q, u64 clust_start, u64 size);
>>>  
>>>  static inline int qcow_pwrite_sync(int fd,
>>>  	void *buf, size_t count, off_t offset)
>>> @@ -657,6 +662,56 @@ static struct qcow_refcount_block *refcount_block_search(struct qcow *q, u64 off
>>>  	return rfb;
>>>  }
>>>  
>>> +static struct qcow_refcount_block *qcow_grow_refcount_block(struct qcow *q,
>>> +	u64 clust_idx)
>>> +{
>>> +	struct qcow_header *header = q->header;
>>> +	struct qcow_refcount_table *rft = &q->refcount_table;
>>> +	struct qcow_refcount_block *rfb;
>>> +	u64 new_block_offset;
>>> +	u64 rft_idx;
>>> +
>>> +	rft_idx = clust_idx >> (header->cluster_bits -
>>> +		QCOW_REFCOUNT_BLOCK_SHIFT);
>>> +
>>> +	if (rft_idx >= rft->rf_size) {
>>> +		pr_warning("Don't support grow refcount block table");
>>> +		return NULL;
>>> +	}
>>> +
>>> +	new_block_offset = qcow_alloc_clusters(q, q->cluster_size, 0);
>>> +	if (new_block_offset < 0)
>>> +		return NULL;
>>> +
>>> +	rfb = new_refcount_block(q, new_block_offset);
>>> +	if (!rfb)
>>> +		return NULL;
>>> +
>>> +	memset(rfb->entries, 0x00, q->cluster_size);
>>> +	rfb->dirty = 1;
>>> +
>>> +	/* write refcount block */
>>> +	if (write_refcount_block(q, rfb) < 0)
>>> +		goto free_rfb;
>>> +
>>> +	if (cache_refcount_block(q, rfb) < 0)
>>> +		goto free_rfb;
>>> +
>>> +	rft->rf_table[rft_idx] = cpu_to_be64(new_block_offset);
>>> +	if (qcow_write_refcount_table(q) < 0)
>>> +		goto free_rfb;
>>> +
>>> +	if (update_cluster_refcount(q, new_block_offset >>
>>> +		    header->cluster_bits, 1) < 0)
>>> +		goto free_rfb;
>>
>> This order is unsafe, you could end up with a refcount block that is
>> already in use, but still has a refcount of 0.
> How about following?
> rft->rf_table[rft_idx] = cpu_to_be64(new_block_offset);
> 
> if (update_cluster_refcount(q, new_block_offset >>
> 	header->cluster_bits, 1) < 0) {
> 	rft->rf_table[rft_idx] =  0;
> 	goto free_rfb;
> }
> 
> if (qcow_write_refcount_table(q) < 0) {
> 	rft->rf_table[rft_idx] =  0;
> 	qcow_free_clusters(q, new_block_offset, q->cluster_size);
> 	goto free_rfb;
> }
> 
> update_cluster_refcount() will use the rft->rf_table. So updating the rft->rf_table
> must be before update_cluster_refcount().

Yes, something like this should work.

Kevin

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks
  2011-12-13  3:16     ` lan,Tianyu
@ 2011-12-13  9:13       ` Pekka Enberg
  0 siblings, 0 replies; 13+ messages in thread
From: Pekka Enberg @ 2011-12-13  9:13 UTC (permalink / raw)
  To: lan,Tianyu; +Cc: Kevin Wolf, kvm, asias.hejun, levinsasha928, prasadjoshi124

On Tue, Dec 13, 2011 at 5:16 AM, lan,Tianyu <tianyu.lan@intel.com> wrote:
> I have tried to use ERR_PTR(). But when I included linux/err.h, a
> compile error  was following.
>
>  CC       disk/qcow.o
> In file included from disk/qcow.c:20:
> ../../include/linux/err.h:22: error: expected '=', ',', ';', 'asm' or
> '__attribute__' before 'ERR_PTR'
> ../../include/linux/err.h:27: error: expected '=', ',', ';', 'asm' or
> '__attribute__' before 'PTR_ERR'
> ../../include/linux/err.h:32: error: expected '=', ',', ';', 'asm' or
> '__attribute__' before 'IS_ERR'
> ../../include/linux/err.h:37: error: expected '=', ',', ';', 'asm' or
> '__attribute__' before 'IS_ERR_OR_NULL'
> ../../include/linux/err.h:49: error: expected '=', ',', ';', 'asm' or
> '__attribute__' before 'ERR_CAST'
> ../../include/linux/err.h:55: error: expected '=', ',', ';', 'asm' or
> '__attribute__' before 'PTR_RET'

We need to borrow tools/perf/util/include/linux/compiler.h in
tools/kvm/include/linux.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks
  2011-12-13  8:57         ` Kevin Wolf
@ 2011-12-13  9:14           ` Pekka Enberg
  2011-12-14  1:22           ` lan,Tianyu
  1 sibling, 0 replies; 13+ messages in thread
From: Pekka Enberg @ 2011-12-13  9:14 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: lan,Tianyu, kvm, asias.hejun, levinsasha928, prasadjoshi124

On Tue, Dec 13, 2011 at 10:57 AM, Kevin Wolf <kwolf@redhat.com> wrote:
>> So the ENOSPEC should be specially dealt with.
>>
>> Does this make sense? :)
>
> I'm not saying that your code won't work today, just that it's brittle.
> If someone adds a different error return code somewhere and doesn't
> check if all callers properly deal with error codes, it will break.

Indeed.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks
  2011-12-13  8:57         ` Kevin Wolf
  2011-12-13  9:14           ` Pekka Enberg
@ 2011-12-14  1:22           ` lan,Tianyu
  1 sibling, 0 replies; 13+ messages in thread
From: lan,Tianyu @ 2011-12-14  1:22 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Pekka Enberg, kvm, asias.hejun, levinsasha928, prasadjoshi124

oh,yeah. Thanks for your reply. It's a good lesson for me. :)
I will update soon.
On 二, 2011-12-13 at 16:57 +0800, Kevin Wolf wrote:
> Am 13.12.2011 04:41, schrieb lan,Tianyu:
> > On 一, 2011-12-12 at 19:15 +0800, Kevin Wolf wrote:
> >> Am 12.12.2011 11:58, schrieb Pekka Enberg:
> >>> On Mon, 12 Dec 2011, Kevin Wolf wrote:
> >>>>> @@ -667,14 +722,11 @@ static struct qcow_refcount_block *qcow_read_refcount_block(struct qcow *q, u64
> >>>>>
> >>>>>  	rft_idx = clust_idx >> (header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT);
> >>>>>  	if (rft_idx >= rft->rf_size)
> >>>>> -		return NULL;
> >>>>> +		return (void *)-ENOSPC;
> >>>>
> >>>> Is this allowed style in kvm-tool? :-/
> >>>
> >>> It needs to use ERR_PTR() and related macros but otherwise I don't see a 
> >>> big problem with it.
> >>
> >> Can you be sure that it never clashes with a valid allocation when you
> >> use this in userspace?
> >>
> >> But yes, at least using appropriate functions should be required. And
> >> this means that you can't only check for -ENOSPC, but you need to check
> >> for all possible error codes (IS_ERR_VALUE() I guess).
> > The qcow_read_refcount_block() is invoiked in the two places
> > qcow_get_refcount() and update_cluster_refcount() and will only return
> > NULL or -ENOSPC.
> > 
> > In the qcow_get_refcount(), when qcow_read_refcount_block() returned
> > -ENOSPEC(no refcount block is available.), returning zero which means
> > the cluster is not in use and the refcount block can be grew in the
> > update_cluster_refcount().  
> > 
> > In the update_cluster_refcount(), when qcow_read_refcount_block()
> > returned -ENOSPEC, it is necessary to grow the refcount blocks.
> > 
> > So the ENOSPEC should be specially dealt with.  
> > 
> > Does this make sense? :)
> 
> I'm not saying that your code won't work today, just that it's brittle.
> If someone adds a different error return code somewhere and doesn't
> check if all callers properly deal with error codes, it will break.
> 
> Kevin

Thanks
Tianyu Lan


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2011-12-14  1:17 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-12  2:03 [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks Lan Tianyu
2011-12-12  9:55 ` Kevin Wolf
2011-12-12 10:58   ` Pekka Enberg
2011-12-12 11:15     ` Kevin Wolf
2011-12-12 11:17       ` Kevin Wolf
2011-12-13  3:41       ` lan,Tianyu
2011-12-13  8:57         ` Kevin Wolf
2011-12-13  9:14           ` Pekka Enberg
2011-12-14  1:22           ` lan,Tianyu
2011-12-13  3:16     ` lan,Tianyu
2011-12-13  9:13       ` Pekka Enberg
2011-12-13  3:05   ` lan,Tianyu
2011-12-13  9:03     ` Kevin Wolf

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.