Re: [RFC v2 02/10] Drop unused static function return values

2022-08-12 Thread Alberto Faria
On Wed, Aug 3, 2022 at 12:15 PM Richard W.M. Jones  wrote:
> If it helps to think about this, Coverity checks for consistency.
> Across the whole code base, is the return value of a function used or
> ignored consistently.  You will see Coverity errors like:
>
>   Error: CHECKED_RETURN (CWE-252): [#def37]
>   libnbd-1.12.5/fuse/operations.c:180: check_return: Calling "nbd_poll" 
> without checking return value (as is done elsewhere 5 out of 6 times).
>   libnbd-1.12.5/examples/aio-connect-read.c:96: example_checked: Example 
> 1: "nbd_poll(nbd, -1)" has its value checked in "nbd_poll(nbd, -1) == -1".
>   libnbd-1.12.5/examples/aio-connect-read.c:128: example_checked: Example 
> 2: "nbd_poll(nbd, -1)" has its value checked in "nbd_poll(nbd, -1) == -1".
>   libnbd-1.12.5/examples/strict-structured-reads.c:246: example_checked: 
> Example 3: "nbd_poll(nbd, -1)" has its value checked in "nbd_poll(nbd, -1) == 
> -1".
>   libnbd-1.12.5/ocaml/nbd-c.c:2599: example_assign: Example 4: Assigning: 
> "r" = return value from "nbd_poll(h, timeout)".
>   libnbd-1.12.5/ocaml/nbd-c.c:2602: example_checked: Example 4 (cont.): 
> "r" has its value checked in "r == -1".
>   libnbd-1.12.5/python/methods.c:2806: example_assign: Example 5: 
> Assigning: "ret" = return value from "nbd_poll(h, timeout)".
>   libnbd-1.12.5/python/methods.c:2808: example_checked: Example 5 
> (cont.): "ret" has its value checked in "ret == -1".
>   #  178|   /* Dispatch work while there are commands in flight. */
>   #  179|   while (thread->in_flight > 0)
>   #  180|->   nbd_poll (h, -1);
>   #  181| }
>   #  182|
>
> What it's saying is that in this code base, nbd_poll's return value
> was checked by the caller 5 out of 6 times, but ignored here.  (This
> turned out to be a real bug which we fixed).
>
> It seems like the check implemented in your patch is: If the return
> value is used 0 times anywhere in the code base, change the return
> value to 'void'.  Coverity would not flag this.
>
> Maybe a consistent use check is better?

Note that the analyzer is currently limited to analyzing a single
translation unit at a time, so we would only be able to implement a
consistent use check for static functions (this is why the current
"return-value-never-used" check only applies to static functions).

It may be worthwhile exploring cross-translation unit analysis,
although it may be difficult to accomplish while also avoiding
reanalyzing the entire tree every time a single translation unit is
modified.

Alberto




Re: [RFC v2 02/10] Drop unused static function return values

2022-08-12 Thread Alberto Faria
On Wed, Aug 3, 2022 at 1:30 PM Peter Maydell  wrote:
> The problem with a patch like this is that it rolls up into a
> single patch changes to the API of many functions in multiple
> subsystems across the whole codebase. Some of those changes
> might be right; some might be wrong. No single person is going
> to be in a position to review the whole lot, and a +248-403
> patch email makes it very unwieldy to try to discuss.
>
> If you want to propose some of these I think you need to:
>  * split it out so that you're only suggesting changes in
>one subsystem at a time
>  * look at the places you are suggesting changes, to see if
>the correct answer is actually "add the missing error
>check in the caller(s)"
>  * not change places that are following standard API patterns
>like "return bool and have an Error** argument"

Sounds good. For now, I'll limit the changes to a few representative
cases e.g. in the block layer, since this patch is mostly intended as
a demonstration of the type of issue that the check catches. Once
there is agreement on the semantics for the check, I'll probably send
a separate tree-wide series with per-subsystem patches.

Thanks,
Alberto




Re: [RFC v2 00/10] Introduce an extensible static analyzer

2022-08-12 Thread Alberto Faria
On Thu, Aug 4, 2022 at 12:44 PM Marc-André Lureau
 wrote:
> Hi
>
> Great work so far! This seems easier to hack than my attempt to use
> clang-tidy to write some qemu checks
> (https://github.com/elmarco/clang-tools-extra)
>
> The code seems quite generic, I wonder if such a tool in python wasn't
> already developed (I couldn't find it easily searching on github).
>
> Why not make it standalone from qemu? Similar to
> https://gitlab.com/qemu-project/python-qemu-qmp, you could have your
> own release management, issue tracker, code formatting, license, CI
> etc. (you should add copyright header in each file, at least that's
> pretty much required in qemu nowadays). You could also have the
> qemu-specific checks there imho (clang-tidy has google & llvm specific
> checks too)

This is an interesting idea. Indeed, the analyzer is essentially a
more easily extensible, Python version of clang-tidy (without the big
built-in library of checks).

I think I'll continue working on it embedded in QEMU for now, mostly
because it depends on some aspects of the build system, and gradually
generalize it to a point where it could be made into a standalone
thing.

> It would be nice to write some docs, in docs/devel/testing.rst and
> some new meson/ninja/make targets to run the checks directly from a
> build tree.

Sounds good, I'll work on it.

> On fc36, I had several dependencies I needed to install manually (imho
> they should have been pulled by python3-clang), but more annoyingly I
> got:
> clang.cindex.LibclangError: libclang.so: cannot open shared object
> file: No such file or directory. To provide a path to libclang use
> Config.set_library_path() or Config.set_library_file().
>
> clang-libs doesn't install libclang.so, I wonder why. I made a link
> manually and it works, but it's probably incorrect. I'll try to open
> issues for the clang packaging.

That's strange. Thanks for looking into this.

Alberto




Re: [PATCH v2 0/8] parallels: Refactor the code of images checks and fix a bug

2022-08-12 Thread Denis V. Lunev

On 11.08.2022 17:00, Alexander Ivanov wrote:

Fix image inflation when offset in BAT is out of image.

Replace whole BAT syncing by flushing only dirty blocks.

Move all the checks outside the main check function in
separate functions

Use WITH_QEMU_LOCK_GUARD for more clean code.

Alexander Ivanov (8):
   parallels: Out of image offset in BAT leads to image inflation
   parallels: Move BAT entry setting to a separate function
   parallels: Replace bdrv_co_pwrite_sync by bdrv_co_flush for BAT
 flushing
   parallels: Move check of unclean image to a separate function
   parallels: Move check of cluster outside image to a separate function
   parallels: Move check of leaks to a separate function
   parallels: Move statistic collection to a separate function
   parallels: Replace qemu_co_mutex_lock by WITH_QEMU_LOCK_GUARD

  block/parallels.c | 188 --
  1 file changed, 132 insertions(+), 56 deletions(-)


I believe that this series is ready to go once commit
messages will be improved.

Den



Re: [PATCH v2 8/8] parallels: Replace qemu_co_mutex_lock by WITH_QEMU_LOCK_GUARD

2022-08-12 Thread Denis V. Lunev

On 11.08.2022 17:00, Alexander Ivanov wrote:

Replace the way we use mutex in parallels_co_check() for more clean code.

I think that "cleaness" is the same, but new code would be just shorter ;)
or less error prone.


v2: Fix an incorrect usage of WITH_QEMU_LOCK_GUARD.

Signed-off-by: Alexander Ivanov 
---
  block/parallels.c | 26 --
  1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index d0364182bb..e124a8bb7d 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -553,24 +553,22 @@ static int coroutine_fn 
parallels_co_check(BlockDriverState *bs,
  BDRVParallelsState *s = bs->opaque;
  int ret;
  
-qemu_co_mutex_lock(>lock);

+WITH_QEMU_LOCK_GUARD(>lock) {
+parallels_check_unclean(bs, res, fix);
  
-parallels_check_unclean(bs, res, fix);

+ret = parallels_check_outside_image(bs, res, fix);
+if (ret < 0) {
+return ret;
+}
  
-ret = parallels_check_outside_image(bs, res, fix);

-if (ret < 0) {
-goto out;
-}
-
-ret = parallels_check_leak(bs, res, fix);
-if (ret < 0) {
-goto out;
-}
+ret = parallels_check_leak(bs, res, fix);
+if (ret < 0) {
+return ret;
+}
  
-parallels_collect_statistics(bs, res, fix);

+parallels_collect_statistics(bs, res, fix);
  
-out:

-qemu_co_mutex_unlock(>lock);
+}
  
  ret = bdrv_co_flush(bs);

  if (ret < 0) {





Re: [PATCH v2 7/8] parallels: Move statistic collection to a separate function

2022-08-12 Thread Denis V. Lunev

On 11.08.2022 17:00, Alexander Ivanov wrote:

v2: Move fragmentation counting code to this function too.


same note here about ChnageLog and motivation


Signed-off-by: Alexander Ivanov 
---
  block/parallels.c | 54 +++
  1 file changed, 31 insertions(+), 23 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index 8737eadfb4..d0364182bb 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -518,48 +518,56 @@ static int parallels_check_leak(BlockDriverState *bs,
  return 0;
  }
  
-static int coroutine_fn parallels_co_check(BlockDriverState *bs,

-   BdrvCheckResult *res,
-   BdrvCheckMode fix)
+static void parallels_collect_statistics(BlockDriverState *bs,
+ BdrvCheckResult *res,
+ BdrvCheckMode fix)
  {
  BDRVParallelsState *s = bs->opaque;
-int64_t prev_off;
-int ret;
+int64_t off, prev_off;
  uint32_t i;
  
-

-qemu_co_mutex_lock(>lock);
-
-parallels_check_unclean(bs, res, fix);
-
-ret = parallels_check_outside_image(bs, res, fix);
-if (ret < 0) {
-goto out;
-}
-
-ret = parallels_check_leak(bs, res, fix);
-if (ret < 0) {
-goto out;
-}
-
  res->bfi.total_clusters = s->bat_size;
  res->bfi.compressed_clusters = 0; /* compression is not supported */
  
  prev_off = 0;

  for (i = 0; i < s->bat_size; i++) {
-int64_t off = bat2sect(s, i) << BDRV_SECTOR_BITS;
+off = bat2sect(s, i) << BDRV_SECTOR_BITS;
  if (off == 0) {
  prev_off = 0;
  continue;
  }
  
-res->bfi.allocated_clusters++;

-
  if (prev_off != 0 && (prev_off + s->cluster_size) != off) {
  res->bfi.fragmented_clusters++;
  }
+
  prev_off = off;
+res->bfi.allocated_clusters++;
  }
+}
+
+static int coroutine_fn parallels_co_check(BlockDriverState *bs,
+   BdrvCheckResult *res,
+   BdrvCheckMode fix)
+{
+BDRVParallelsState *s = bs->opaque;
+int ret;
+
+qemu_co_mutex_lock(>lock);
+
+parallels_check_unclean(bs, res, fix);
+
+ret = parallels_check_outside_image(bs, res, fix);
+if (ret < 0) {
+goto out;
+}
+
+ret = parallels_check_leak(bs, res, fix);
+if (ret < 0) {
+goto out;
+}
+
+parallels_collect_statistics(bs, res, fix);
  
  out:

  qemu_co_mutex_unlock(>lock);





Re: [PATCH v2 6/8] parallels: Move check of leaks to a separate function

2022-08-12 Thread Denis V. Lunev

On 11.08.2022 17:00, Alexander Ivanov wrote:

v2: No changes.

same notes about motivation, changelog as before


Signed-off-by: Alexander Ivanov 
---
  block/parallels.c | 85 +--
  1 file changed, 52 insertions(+), 33 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index 12104ba5ad..8737eadfb4 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -469,14 +469,13 @@ static int parallels_check_outside_image(BlockDriverState 
*bs,
  return 0;
  }
  
-static int coroutine_fn parallels_co_check(BlockDriverState *bs,

-   BdrvCheckResult *res,
-   BdrvCheckMode fix)
+static int parallels_check_leak(BlockDriverState *bs,
+BdrvCheckResult *res,
+BdrvCheckMode fix)
  {
  BDRVParallelsState *s = bs->opaque;
-int64_t size, prev_off, high_off;
-int ret;
-uint32_t i;
+int64_t size, off, high_off, count;
+int i, ret;
  
  size = bdrv_getlength(bs->file->bs);

  if (size < 0) {
@@ -484,41 +483,16 @@ static int coroutine_fn 
parallels_co_check(BlockDriverState *bs,
  return size;
  }
  
-qemu_co_mutex_lock(>lock);

-
-parallels_check_unclean(bs, res, fix);
-
-ret = parallels_check_outside_image(bs, res, fix);
-if (ret < 0) {
-goto out;
-}
-
-res->bfi.total_clusters = s->bat_size;
-res->bfi.compressed_clusters = 0; /* compression is not supported */
-
  high_off = 0;
-prev_off = 0;
  for (i = 0; i < s->bat_size; i++) {
-int64_t off = bat2sect(s, i) << BDRV_SECTOR_BITS;
-if (off == 0) {
-prev_off = 0;
-continue;
-}
-
-res->bfi.allocated_clusters++;
+off = bat2sect(s, i) << BDRV_SECTOR_BITS;
  if (off > high_off) {
  high_off = off;
  }
-
-if (prev_off != 0 && (prev_off + s->cluster_size) != off) {
-res->bfi.fragmented_clusters++;
-}
-prev_off = off;
  }
  
  res->image_end_offset = high_off + s->cluster_size;

  if (size > res->image_end_offset) {
-int64_t count;
  count = DIV_ROUND_UP(size - res->image_end_offset, s->cluster_size);
  fprintf(stderr, "%s space leaked at the end of the image %" PRId64 
"\n",
  fix & BDRV_FIX_LEAKS ? "Repairing" : "ERROR",
@@ -536,11 +510,56 @@ static int coroutine_fn 
parallels_co_check(BlockDriverState *bs,
  if (ret < 0) {
  error_report_err(local_err);
  res->check_errors++;
-goto out;
+return ret;
  }
  res->leaks_fixed += count;
  }
  }
+return 0;
+}
+
+static int coroutine_fn parallels_co_check(BlockDriverState *bs,
+   BdrvCheckResult *res,
+   BdrvCheckMode fix)
+{
+BDRVParallelsState *s = bs->opaque;
+int64_t prev_off;
+int ret;
+uint32_t i;
+
+


please remove extra empty line. This looks like an accident

+qemu_co_mutex_lock(>lock);
+
+parallels_check_unclean(bs, res, fix);
+
+ret = parallels_check_outside_image(bs, res, fix);
+if (ret < 0) {
+goto out;
+}
+
+ret = parallels_check_leak(bs, res, fix);
+if (ret < 0) {
+goto out;
+}
+
+res->bfi.total_clusters = s->bat_size;
+res->bfi.compressed_clusters = 0; /* compression is not supported */
+
+prev_off = 0;
+for (i = 0; i < s->bat_size; i++) {
+int64_t off = bat2sect(s, i) << BDRV_SECTOR_BITS;
+if (off == 0) {
+prev_off = 0;
+continue;
+}
+
+res->bfi.allocated_clusters++;
+
+if (prev_off != 0 && (prev_off + s->cluster_size) != off) {
+res->bfi.fragmented_clusters++;
+}
+prev_off = off;
+}
  
  out:

  qemu_co_mutex_unlock(>lock);





Re: [PATCH v2 5/8] parallels: Move check of cluster outside image to a separate function

2022-08-12 Thread Denis V. Lunev

On 11.08.2022 17:00, Alexander Ivanov wrote:

v2: Move unrelated helper parallels_set_bat_entry creation to
 a separate patch.

same notes as for previous patch



Signed-off-by: Alexander Ivanov 
---
  block/parallels.c | 48 ++-
  1 file changed, 35 insertions(+), 13 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index c53b2810cf..12104ba5ad 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -439,6 +439,36 @@ static void parallels_check_unclean(BlockDriverState *bs,
  }
  }
  
+static int parallels_check_outside_image(BlockDriverState *bs,

+ BdrvCheckResult *res,
+ BdrvCheckMode fix)
+{
+BDRVParallelsState *s = bs->opaque;
+uint32_t i;
+int64_t off, size;
+
+size = bdrv_getlength(bs->file->bs);
+if (size < 0) {
+res->check_errors++;
+return size;
+}
+
+for (i = 0; i < s->bat_size; i++) {
+off = bat2sect(s, i) << BDRV_SECTOR_BITS;
+if (off > size) {
+fprintf(stderr, "%s cluster %u is outside image\n",
+fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
+res->corruptions++;
+if (fix & BDRV_FIX_ERRORS) {
+parallels_set_bat_entry(s, i, 0);
+res->corruptions_fixed++;
+}
+}
+}
+
+return 0;
+}
+
  static int coroutine_fn parallels_co_check(BlockDriverState *bs,
 BdrvCheckResult *res,
 BdrvCheckMode fix)
@@ -458,6 +488,11 @@ static int coroutine_fn 
parallels_co_check(BlockDriverState *bs,
  
  parallels_check_unclean(bs, res, fix);
  
+ret = parallels_check_outside_image(bs, res, fix);

+if (ret < 0) {
+goto out;
+}
+
  res->bfi.total_clusters = s->bat_size;
  res->bfi.compressed_clusters = 0; /* compression is not supported */
  
@@ -470,19 +505,6 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,

  continue;
  }
  
-/* cluster outside the image */

-if (off > size) {
-fprintf(stderr, "%s cluster %u is outside image\n",
-fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
-res->corruptions++;
-if (fix & BDRV_FIX_ERRORS) {
-prev_off = 0;
-parallels_set_bat_entry(s, i, 0);
-res->corruptions_fixed++;
-continue;
-}
-}
-
  res->bfi.allocated_clusters++;
  if (off > high_off) {
  high_off = off;





Re: [PATCH v2 4/8] parallels: Move check of unclean image to a separate function

2022-08-12 Thread Denis V. Lunev

On 11.08.2022 17:00, Alexander Ivanov wrote:

v2: Revert the condition with s->header_unclean.

same comment about change log as previously

And commit message misses motivation part, why we are
doing this rework. What is the goal of this change?

The code part is clean.


Signed-off-by: Alexander Ivanov 
---
  block/parallels.c | 31 +--
  1 file changed, 21 insertions(+), 10 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index 6879ea4597..c53b2810cf 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -419,6 +419,25 @@ static coroutine_fn int 
parallels_co_readv(BlockDriverState *bs,
  return ret;
  }
  
+static void parallels_check_unclean(BlockDriverState *bs,

+BdrvCheckResult *res,
+BdrvCheckMode fix)
+{
+BDRVParallelsState *s = bs->opaque;
+
+if (!s->header_unclean) {
+return;
+}
+
+fprintf(stderr, "%s image was not closed correctly\n",
+fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR");
+res->corruptions++;
+if (fix & BDRV_FIX_ERRORS) {
+/* parallels_close will do the job right */
+res->corruptions_fixed++;
+s->header_unclean = false;
+}
+}
  
  static int coroutine_fn parallels_co_check(BlockDriverState *bs,

 BdrvCheckResult *res,
@@ -436,16 +455,8 @@ static int coroutine_fn 
parallels_co_check(BlockDriverState *bs,
  }
  
  qemu_co_mutex_lock(>lock);

-if (s->header_unclean) {
-fprintf(stderr, "%s image was not closed correctly\n",
-fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR");
-res->corruptions++;
-if (fix & BDRV_FIX_ERRORS) {
-/* parallels_close will do the job right */
-res->corruptions_fixed++;
-s->header_unclean = false;
-}
-}
+
+parallels_check_unclean(bs, res, fix);
  
  res->bfi.total_clusters = s->bat_size;

  res->bfi.compressed_clusters = 0; /* compression is not supported */





Re: [PATCH v2 3/8] parallels: Replace bdrv_co_pwrite_sync by bdrv_co_flush for BAT flushing

2022-08-12 Thread Denis V. Lunev

Use generic infrastructure for BAT writing in parallels_co_check()

On 11.08.2022 17:00, Alexander Ivanov wrote:

It's too costly to write all the BAT to the disk. Let the flush function
write only dirty blocks.
Use parallels_set_bat_entry for setting a BAT entry and marking a relevant
block as dirty.
Move bdrv_co_flush call outside the locked area.

This is not correct too:
- with a lot of cases inside parallels_co_check, which will be split to
  smaller functions, we would like to avoid writing BAT once each
  stage is complete

Thus the comment should look like the following:
"BAT is written in the context of conventional operations over
the image inside bdrv_co_flush() when it calls
parallels_co_flush_to_os() callback. Thus we should not
modify BAT array directly, but call parallels_set_bat_entry()
helper and bdrv_co_flush() further on. After that there is no
need to manually write BAT and track its modification.

This makes code more generic and allows to split
parallels_set_bat_entry() for independent pieces."


v2: Patch order was changed so the replacement is done in parallels_co_check.
 Now we use a helper to set BAT entry and mark the block dirty.

Same note about changelog as n other patches.

Side note. I like Linux kernel a lot and there is a good
guide in. Please look how commit message
https://www.kernel.org/doc/html/latest/process/submitting-patches.html

May be you could spend some more time on commit
message.

With a better message:
Reviewed-by: Denis V. Lunev 


Signed-off-by: Alexander Ivanov 
---
  block/parallels.c | 19 +++
  1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index 7f68f3cbc9..6879ea4597 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -428,7 +428,6 @@ static int coroutine_fn parallels_co_check(BlockDriverState 
*bs,
  int64_t size, prev_off, high_off;
  int ret;
  uint32_t i;
-bool flush_bat = false;
  
  size = bdrv_getlength(bs->file->bs);

  if (size < 0) {
@@ -467,9 +466,8 @@ static int coroutine_fn parallels_co_check(BlockDriverState 
*bs,
  res->corruptions++;
  if (fix & BDRV_FIX_ERRORS) {
  prev_off = 0;
-s->bat_bitmap[i] = 0;
+parallels_set_bat_entry(s, i, 0);
  res->corruptions_fixed++;
-flush_bat = true;
  continue;
  }
  }
@@ -485,15 +483,6 @@ static int coroutine_fn 
parallels_co_check(BlockDriverState *bs,
  prev_off = off;
  }
  
-ret = 0;

-if (flush_bat) {
-ret = bdrv_co_pwrite_sync(bs->file, 0, s->header_size, s->header, 0);
-if (ret < 0) {
-res->check_errors++;
-goto out;
-}
-}
-
  res->image_end_offset = high_off + s->cluster_size;
  if (size > res->image_end_offset) {
  int64_t count;
@@ -522,6 +511,12 @@ static int coroutine_fn 
parallels_co_check(BlockDriverState *bs,
  
  out:

  qemu_co_mutex_unlock(>lock);
+
+ret = bdrv_co_flush(bs);
+if (ret < 0) {
+res->check_errors++;
+}
+
  return ret;
  }
  





Re: [PATCH v2 2/8] parallels: Move BAT entry setting to a separate function

2022-08-12 Thread Denis V. Lunev

On 11.08.2022 17:00, Alexander Ivanov wrote:

Will need to set BAT entry in multiple places.
Move the code of settings entries and marking relevant blocks dirty
to a separate helper parallels_set_bat_entry.

The comment and the patch text is ambiguous.
You say that we need to set BAT in multiple places
but patch changes one place only. I think that it would
be better to say like the following:

"parallels: create parallels_set_bat_entry_helper() to assign BAT value

This helper will be reused in next patches during parallels_co_check
rework to simplify its code"


v2: A new patch - a part of a splitted patch.

Same note about version tracking

With above taken into account:
Reviewed-by: Denis V. Lunev 


Signed-off-by: Alexander Ivanov 
---
  block/parallels.c | 12 +---
  1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index a76cf9d993..7f68f3cbc9 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -165,6 +165,13 @@ static int64_t block_status(BDRVParallelsState *s, int64_t 
sector_num,
  return start_off;
  }
  
+static void parallels_set_bat_entry(BDRVParallelsState *s,

+uint32_t index, uint32_t offset)
+{
+s->bat_bitmap[index] = offset;
+bitmap_set(s->bat_dirty_bmap, bat_entry_off(index) / s->bat_dirty_block, 
1);
+}
+
  static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
   int nb_sectors, int *pnum)
  {
@@ -250,10 +257,9 @@ static int64_t allocate_clusters(BlockDriverState *bs, 
int64_t sector_num,
  }
  
  for (i = 0; i < to_allocate; i++) {

-s->bat_bitmap[idx + i] = cpu_to_le32(s->data_end / s->off_multiplier);
+parallels_set_bat_entry(s, idx + i,
+cpu_to_le32(s->data_end / s->off_multiplier));
  s->data_end += s->tracks;
-bitmap_set(s->bat_dirty_bmap,
-   bat_entry_off(idx + i) / s->bat_dirty_block, 1);
  }
  
  return bat2sect(s, idx) + sector_num % s->tracks;





Re: [PATCH v2 1/8] parallels: Out of image offset in BAT leads to image inflation

2022-08-12 Thread Denis V. Lunev

On 11.08.2022 17:00, Alexander Ivanov wrote:

When an image is opened, data_end field in BDRVParallelsState
is setted as the biggest offset in the BAT plus cluster size.
If there is a corrupted offset pointing outside the image,
the image size increase accordingly. It potentially leads
to attempts to create a file size of petabytes.

Set the data_end field with the original file size if the image
was opened for checking and repairing purposes or raise an error.

v2: No changes.

Changelog should be below ---
In that case it will not be merged.

There are a lot of typos/mistakes inside, I'd better use the comment
below.

"data_end field in BDRVParallelsState is set to the biggest offset present
in BAT. If this offset is outside of the image, any further write will 
create

the cluster at this offset and/or the image will be truncated to this
offset on close. This is definitely not correct and should be fixed."

With this change:
Reviewed-by: Denis V. Lunev 


Signed-off-by: Alexander Ivanov 
---
  block/parallels.c | 17 +
  1 file changed, 17 insertions(+)

diff --git a/block/parallels.c b/block/parallels.c
index a229c06f25..a76cf9d993 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -732,6 +732,7 @@ static int parallels_open(BlockDriverState *bs, QDict 
*options, int flags,
  BDRVParallelsState *s = bs->opaque;
  ParallelsHeader ph;
  int ret, size, i;
+int64_t file_size;
  QemuOpts *opts = NULL;
  Error *local_err = NULL;
  char *buf;
@@ -811,6 +812,22 @@ static int parallels_open(BlockDriverState *bs, QDict 
*options, int flags,
  }
  }
  
+file_size = bdrv_getlength(bs->file->bs);

+if (file_size < 0) {
+goto fail;
+}
+
+file_size >>= BDRV_SECTOR_BITS;
+if (s->data_end > file_size) {
+if (flags & BDRV_O_CHECK) {
+s->data_end = file_size;
+} else {
+error_setg(errp, "parallels: Offset in BAT is out of image");
+ret = -EINVAL;
+goto fail;
+}
+}
+
  if (le32_to_cpu(ph.inuse) == HEADER_INUSE_MAGIC) {
  /* Image was not closed correctly. The check is mandatory */
  s->header_unclean = true;





[PATCH] hw/nvme: remove param zoned.auto_transition

2022-08-12 Thread Niklas Cassel via
The intention of the Zoned Namespace Command Set Specification was
never to make an automatic zone transition optional.

Excerpt from the nvmexpress.org zns mailing list:
"""
A question came up internally on the differences between ZNS and ZAC/ZBC
that asked about when a controller should transitions a specific zone in
the Implicitly Opened state to Closed state.

For example, consider a ZNS SSD that supports a max of 20 active zones,
and a max of 10 open zones, which has the following actions occur:

First, the host writes to ten empty zones, thereby transitioning 10 zones
to the Implicitly Opened state.

Second, the host issues a write to an 11th empty zone.

Given that state, my understanding of the second part is that the ZNS SSD
chooses one of the previously 10 zones, and transition the chosen zone to
the Closed state, and then proceeds to write to the new zone which also
implicitly transition it from the Empty state to the Impl. Open state.
After this, there would be 11 active zones in total, 10 in impl. Open
state, and one in closed state.

The above assumes that a ZNS SSD will always transition an implicitly
opened zone to closed state when required to free up resources when
another zone is opened. However, it isn’t strictly said in the ZNS spec.

The paragraph that should cover it is defined in section
2.1.1.4.1 – Managing Resources:
The controller may transition zones in the ZSIO:Implicitly Opened state
to the ZSC:Closed state for resource management purposes.

However, it doesn’t say “when” it should occur. Thus, as the text stand,
it could be misinterpreted that the controller shouldn’t do close a zone
to make room for a new zone. The issue with this, is that it makes the
point of having implicitly managed zones moot.

The ZAC/ZBC specs is more specific and clarifies when a zone should be
closed. I think it would be natural to the same here.
"""

While the Zoned Namespace Command Set Specification hasn't received an
errata yet, it is quite clear that the intention was that an automatic
zone transition was never supposed to be optional, as then the whole
point of having implictly open zones would be pointless. Therefore,
remove the param zoned.auto_transition, as this was never supposed to
be controller implementation specific.

Signed-off-by: Niklas Cassel 
---
 hw/nvme/ctrl.c | 35 ---
 hw/nvme/nvme.h |  1 -
 2 files changed, 12 insertions(+), 24 deletions(-)

diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index 87aeba0564..b8c8075301 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -34,7 +34,6 @@
  *  aerl=,aer_max_queued=, \
  *  mdts=,vsl=, \
  *  zoned.zasl=, \
- *  zoned.auto_transition=, \
  *  sriov_max_vfs= \
  *  sriov_vq_flexible= \
  *  sriov_vi_flexible= \
@@ -106,11 +105,6 @@
  *   the minimum memory page size (CAP.MPSMIN). The default value is 0 (i.e.
  *   defaulting to the value of `mdts`).
  *
- * - `zoned.auto_transition`
- *   Indicates if zones in zone state implicitly opened can be automatically
- *   transitioned to zone state closed for resource management purposes.
- *   Defaults to 'on'.
- *
  * - `sriov_max_vfs`
  *   Indicates the maximum number of PCIe virtual functions supported
  *   by the controller. The default value is 0. Specifying a non-zero value
@@ -1867,8 +1861,8 @@ enum {
 NVME_ZRM_ZRWA = 1 << 1,
 };
 
-static uint16_t nvme_zrm_open_flags(NvmeCtrl *n, NvmeNamespace *ns,
-NvmeZone *zone, int flags)
+static uint16_t nvme_zrm_open_flags(NvmeNamespace *ns, NvmeZone *zone,
+int flags)
 {
 int act = 0;
 uint16_t status;
@@ -1880,9 +1874,7 @@ static uint16_t nvme_zrm_open_flags(NvmeCtrl *n, 
NvmeNamespace *ns,
 /* fallthrough */
 
 case NVME_ZONE_STATE_CLOSED:
-if (n->params.auto_transition_zones) {
-nvme_zrm_auto_transition_zone(ns);
-}
+nvme_zrm_auto_transition_zone(ns);
 status = nvme_zns_check_resources(ns, act, 1,
   (flags & NVME_ZRM_ZRWA) ? 1 : 0);
 if (status) {
@@ -1925,10 +1917,9 @@ static uint16_t nvme_zrm_open_flags(NvmeCtrl *n, 
NvmeNamespace *ns,
 }
 }
 
-static inline uint16_t nvme_zrm_auto(NvmeCtrl *n, NvmeNamespace *ns,
- NvmeZone *zone)
+static inline uint16_t nvme_zrm_auto(NvmeNamespace *ns, NvmeZone *zone)
 {
-return nvme_zrm_open_flags(n, ns, zone, NVME_ZRM_AUTO);
+return nvme_zrm_open_flags(ns, zone, NVME_ZRM_AUTO);
 }
 
 static void nvme_advance_zone_wp(NvmeNamespace *ns, NvmeZone *zone,
@@ -3065,7 +3056,7 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req)
 goto invalid;
 }
 
-status = nvme_zrm_auto(n, ns, iocb->zone);
+status = nvme_zrm_auto(ns, iocb->zone);
 if (status) {
 goto invalid;
 }
@@ -3471,7 +3462,7 @@ static