Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks

2011-12-13 Thread Kevin Wolf
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
--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks

2011-12-13 Thread Kevin Wolf
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@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
--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks

2011-12-13 Thread Pekka Enberg
On Tue, Dec 13, 2011 at 5:16 AM, lan,Tianyu tianyu@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.
--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks

2011-12-13 Thread Pekka Enberg
On Tue, Dec 13, 2011 at 10:57 AM, Kevin Wolf kw...@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.
--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks

2011-12-13 Thread lan,Tianyu
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

--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks

2011-12-12 Thread 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@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


--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks

2011-12-12 Thread lan,Tianyu
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?
 


--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks

2011-12-12 Thread 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? :)
 Kevin

Thanks
Tianyu Lan.



--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks

2011-12-12 Thread Kevin Wolf
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@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
--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks

2011-12-12 Thread 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.


Pekka
--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks

2011-12-12 Thread 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?

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
--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks

2011-12-12 Thread Kevin Wolf
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
--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[RFC PATCH] kvm tools, qcow: Add support for growing refcount blocks

2011-12-11 Thread 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@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 -