[PATCH v2 0/2] 9pfs: test suite fixes

2020-10-30 Thread Christian Schoenebeck
Fixes two bugs with the 9pfs 'local' tests as discussed with latest 9P PR
(2020-10-23). See the discussion of that PR for details.

v1->v2:

  - Added Greg's tested-by tag [patch 1].

  - Log an info-level message if mkdir() failed [patch 2].

  - Update commit log message about coverity being the reporter and
details of the coverity report [patch 2].

Christian Schoenebeck (2):
  tests/9pfs: fix test dir for parallel tests
  tests/9pfs: fix coverity error in create_local_test_dir()

 tests/qtest/libqos/virtio-9p.c | 32 +---
 1 file changed, 25 insertions(+), 7 deletions(-)

-- 
2.20.1




[PATCH v2 1/2] tests/9pfs: fix test dir for parallel tests

2020-10-30 Thread Christian Schoenebeck
Use mkdtemp() to generate a unique directory for the 9p 'local' tests.

This fixes occasional 9p test failures when running 'make check -jN' if
QEMU was compiled for multiple target architectures, because the individual
architecture's test suites would run in parallel and interfere with each
other's data as the test directory was previously hard coded and hence the
same directory was used by all of them simultaniously.

This also requires a change how the test directory is created and deleted:
As the test path is now randomized and virtio_9p_register_nodes() being
called in a somewhat undeterministic way, that's no longer an appropriate
place to create and remove the test directory. Use a constructor and
destructor function for creating and removing the test directory instead.
Unfortunately libqos currently does not support setup/teardown callbacks
to handle this more cleanly.

Signed-off-by: Christian Schoenebeck 
Tested-by: Greg Kurz 
---
 tests/qtest/libqos/virtio-9p.c | 25 +++--
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c
index d43647b3b7..6b22fa0e9a 100644
--- a/tests/qtest/libqos/virtio-9p.c
+++ b/tests/qtest/libqos/virtio-9p.c
@@ -35,7 +35,12 @@ static char *concat_path(const char* a, const char* b)
 static void init_local_test_path(void)
 {
 char *pwd = g_get_current_dir();
-local_test_path = concat_path(pwd, "qtest-9p-local");
+char *template = concat_path(pwd, "qtest-9p-local-XX");
+local_test_path = mkdtemp(template);
+if (!local_test_path) {
+g_test_message("mkdtemp('%s') failed: %s", template, strerror(errno));
+}
+g_assert(local_test_path);
 g_free(pwd);
 }
 
@@ -246,11 +251,6 @@ static void virtio_9p_register_nodes(void)
 const char *str_simple = "fsdev=fsdev0,mount_tag=" MOUNT_TAG;
 const char *str_addr = "fsdev=fsdev0,addr=04.0,mount_tag=" MOUNT_TAG;
 
-/* make sure test dir for the 'local' tests exists and is clean */
-init_local_test_path();
-remove_local_test_dir();
-create_local_test_dir();
-
 QPCIAddress addr = {
 .devfn = QPCI_DEVFN(4, 0),
 };
@@ -278,3 +278,16 @@ static void virtio_9p_register_nodes(void)
 }
 
 libqos_init(virtio_9p_register_nodes);
+
+static void __attribute__((constructor)) construct_virtio_9p(void)
+{
+/* make sure test dir for the 'local' tests exists */
+init_local_test_path();
+create_local_test_dir();
+}
+
+static void __attribute__((destructor)) destruct_virtio_9p(void)
+{
+/* remove previously created test dir when test suite completed */
+remove_local_test_dir();
+}
-- 
2.20.1




Re: [PATCH 2/2] tests/9pfs: fix coverity error in create_local_test_dir()

2020-10-30 Thread Christian Schoenebeck
On Freitag, 30. Oktober 2020 13:09:26 CET Peter Maydell wrote:
> On Fri, 30 Oct 2020 at 12:02, Christian Schoenebeck
> 
>  wrote:
> > On Freitag, 30. Oktober 2020 12:44:18 CET Greg Kurz wrote:
> > It's not clear to me where this coverity report is accessible online. A
> > quick search only brought me to statistics about its latest check, but
> > not the details of the report you quoted.
> 
> https://scan.coverity.com/projects/qemu . To see the actual
> defect reports you need to create an account and request
> access to the QEMU project (we happily give access to developers,
> but it is a manual-approval process).
> 
> > And more importantly: is there coverity CI support that one could enable
> > on
> > github, so that pending patches were checked before upstream merge?
> 
> No, unfortunately not. The Coverity free-for-open-source-projects
> system has a very limited number of scans it allows (for a project
> the size of ours just one a day) so we can't open it up to
> submaintainer branches or even use it on pull requests pre merge;
> the best we can do is running it on master daily.
> 
> thanks
> -- PMM

Thanks for the clarification Peter!

I try to sign up for Coverity next week.

Best regards,
Christian Schoenebeck





[PATCH v2 2/2] tests/9pfs: fix coverity error in create_local_test_dir()

2020-10-30 Thread Christian Schoenebeck
Coverity wants the return value of mkdir() to be checked:

  /qemu/tests/qtest/libqos/virtio-9p.c: 48 in create_local_test_dir()
  42 /* Creates the directory for the 9pfs 'local' filesystem driver to
  access. */
  43 static void create_local_test_dir(void)
  44 {
  45 struct stat st;
  46
  47 g_assert(local_test_path != NULL);
  >>> CID 1435963:  Error handling issues  (CHECKED_RETURN)
  >>> Calling "mkdir(local_test_path, 511U)" without checking return value.
  This library function may fail and return an error code.
  48 mkdir(local_test_path, 0777);
  49
  50 /* ensure test directory exists now ... */
  51 g_assert(stat(local_test_path, ) == 0);
  52 /* ... and is actually a directory */
  53 g_assert((st.st_mode & S_IFMT) == S_IFDIR);

So let's just do that and log an info-level message at least, because we
actually only care if the required directory exists and we do have an
existence check for that in place already.

Reported-by: Coverity (CID 1435963)
Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/virtio-9p.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c
index 6b22fa0e9a..8459a3ee58 100644
--- a/tests/qtest/libqos/virtio-9p.c
+++ b/tests/qtest/libqos/virtio-9p.c
@@ -48,9 +48,14 @@ static void init_local_test_path(void)
 static void create_local_test_dir(void)
 {
 struct stat st;
+int res;
 
 g_assert(local_test_path != NULL);
-mkdir(local_test_path, 0777);
+res = mkdir(local_test_path, 0777);
+if (res < 0) {
+g_test_message("mkdir('%s') failed: %s", local_test_path,
+   strerror(errno));
+}
 
 /* ensure test directory exists now ... */
 g_assert(stat(local_test_path, ) == 0);
-- 
2.20.1




Re: [PATCH 2/2] tests/9pfs: fix coverity error in create_local_test_dir()

2020-10-30 Thread Christian Schoenebeck
On Freitag, 30. Oktober 2020 12:44:18 CET Greg Kurz wrote:
> On Fri, 30 Oct 2020 09:19:46 +0100
> 
> Christian Schoenebeck  wrote:
> > Coverity wants the return value of mkdir() to be checked, so let's
> > pretend to do that. We're actually just making a dummy check and
> > ignore the result, because we actually only care if the required
> > directory exists and we have an existence check for that in place
> > already.
> 
> I see that sometimes changelog shows a copy of the original
> coverity report (e.g. commit df1a312fea58).

Ok, I'll add that.

> > Reported-by: Greg Kurz 
> 
> Please give credits to coverity, not me :-)
> 
> And most importantly, we want to mention the CID in the changelog.
> 
> e.g.
> 
> Reported-by: Coverity (CID 1435963)

Ok.

It's not clear to me where this coverity report is accessible online. A quick 
search only brought me to statistics about its latest check, but not the 
details of the report you quoted.

And more importantly: is there coverity CI support that one could enable on 
github, so that pending patches were checked before upstream merge?

> 
> > Signed-off-by: Christian Schoenebeck 
> > ---
> > 
> >  tests/qtest/libqos/virtio-9p.c | 6 +-
> >  1 file changed, 5 insertions(+), 1 deletion(-)
> > 
> > diff --git a/tests/qtest/libqos/virtio-9p.c
> > b/tests/qtest/libqos/virtio-9p.c index 6b22fa0e9a..0a7c0ee5d8 100644
> > --- a/tests/qtest/libqos/virtio-9p.c
> > +++ b/tests/qtest/libqos/virtio-9p.c
> > @@ -48,9 +48,13 @@ static void init_local_test_path(void)
> > 
> >  static void create_local_test_dir(void)
> >  {
> >  
> >  struct stat st;
> > 
> > +int res;
> > 
> >  g_assert(local_test_path != NULL);
> > 
> > -mkdir(local_test_path, 0777);
> > +res = mkdir(local_test_path, 0777);
> > +if (res < 0) {
> > +/* ignore error, dummy check to prevent error by coverity */
> 
> Why not printing an error message with errno there like you did in
> the previous patch ?

Yeah, originally I didn't want to trigger false positives on automated CIs if 
mkdir() failed just because the directory already exists. But OTOH 
g_test_message() is just an info-level message, so it is Ok to bark silently 
and I will add it.

> 
> > +}
> > 
> >  /* ensure test directory exists now ... */
> >  g_assert(stat(local_test_path, ) == 0);

Thanks!

Best regards,
Christian Schoenebeck





[PATCH 2/2] tests/9pfs: fix coverity error in create_local_test_dir()

2020-10-30 Thread Christian Schoenebeck
Coverity wants the return value of mkdir() to be checked, so let's
pretend to do that. We're actually just making a dummy check and
ignore the result, because we actually only care if the required
directory exists and we have an existence check for that in place
already.

Reported-by: Greg Kurz 
Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/virtio-9p.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c
index 6b22fa0e9a..0a7c0ee5d8 100644
--- a/tests/qtest/libqos/virtio-9p.c
+++ b/tests/qtest/libqos/virtio-9p.c
@@ -48,9 +48,13 @@ static void init_local_test_path(void)
 static void create_local_test_dir(void)
 {
 struct stat st;
+int res;
 
 g_assert(local_test_path != NULL);
-mkdir(local_test_path, 0777);
+res = mkdir(local_test_path, 0777);
+if (res < 0) {
+/* ignore error, dummy check to prevent error by coverity */
+}
 
 /* ensure test directory exists now ... */
 g_assert(stat(local_test_path, ) == 0);
-- 
2.20.1




[PATCH 0/2] 9pfs: test suite fixes

2020-10-30 Thread Christian Schoenebeck
Fixes two bugs with the 9pfs 'local' tests as discussed with latest 9P PR
(2020-10-23). See the discussion of that PR for details.

Christian Schoenebeck (2):
  tests/9pfs: fix test dir for parallel tests
  tests/9pfs: fix coverity error in create_local_test_dir()

 tests/qtest/libqos/virtio-9p.c | 31 ---
 1 file changed, 24 insertions(+), 7 deletions(-)

-- 
2.20.1




[PATCH 1/2] tests/9pfs: fix test dir for parallel tests

2020-10-30 Thread Christian Schoenebeck
Use mkdtemp() to generate a unique directory for the 9p 'local' tests.

This fixes occasional 9p test failures when running 'make check -jN' if
QEMU was compiled for multiple target architectures, because the individual
architecture's test suites would run in parallel and interfere with each
other's data as the test directory was previously hard coded and hence the
same directory was used by all of them simultaniously.

This also requires a change how the test directory is created and deleted:
As the test path is now randomized and virtio_9p_register_nodes() being
called in a somewhat undeterministic way, that's no longer an appropriate
place to create and remove the test directory. Use a constructor and
destructor function for creating and removing the test directory instead.
Unfortunately libqos currently does not support setup/teardown callbacks
to handle this more cleanly.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/virtio-9p.c | 25 +++--
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c
index d43647b3b7..6b22fa0e9a 100644
--- a/tests/qtest/libqos/virtio-9p.c
+++ b/tests/qtest/libqos/virtio-9p.c
@@ -35,7 +35,12 @@ static char *concat_path(const char* a, const char* b)
 static void init_local_test_path(void)
 {
 char *pwd = g_get_current_dir();
-local_test_path = concat_path(pwd, "qtest-9p-local");
+char *template = concat_path(pwd, "qtest-9p-local-XX");
+local_test_path = mkdtemp(template);
+if (!local_test_path) {
+g_test_message("mkdtemp('%s') failed: %s", template, strerror(errno));
+}
+g_assert(local_test_path);
 g_free(pwd);
 }
 
@@ -246,11 +251,6 @@ static void virtio_9p_register_nodes(void)
 const char *str_simple = "fsdev=fsdev0,mount_tag=" MOUNT_TAG;
 const char *str_addr = "fsdev=fsdev0,addr=04.0,mount_tag=" MOUNT_TAG;
 
-/* make sure test dir for the 'local' tests exists and is clean */
-init_local_test_path();
-remove_local_test_dir();
-create_local_test_dir();
-
 QPCIAddress addr = {
 .devfn = QPCI_DEVFN(4, 0),
 };
@@ -278,3 +278,16 @@ static void virtio_9p_register_nodes(void)
 }
 
 libqos_init(virtio_9p_register_nodes);
+
+static void __attribute__((constructor)) construct_virtio_9p(void)
+{
+/* make sure test dir for the 'local' tests exists */
+init_local_test_path();
+create_local_test_dir();
+}
+
+static void __attribute__((destructor)) destruct_virtio_9p(void)
+{
+/* remove previously created test dir when test suite completed */
+remove_local_test_dir();
+}
-- 
2.20.1




Re: [PULL v3 3/6] tests/9pfs: introduce local tests

2020-10-29 Thread Christian Schoenebeck
On Donnerstag, 29. Oktober 2020 19:02:34 CET Greg Kurz wrote:
> On Thu, 8 Oct 2020 20:34:56 +0200
> 
> Christian Schoenebeck  wrote:
> > This patch introduces 9pfs test cases using the 9pfs 'local'
> > filesystem driver which reads/writes/creates/deletes real files
> > and directories.
> > 
> > In this initial version, there is only one local test which actually
> > only checks if the 9pfs 'local' device was created successfully.
> > 
> > Before the 9pfs 'local' tests are run, a test directory 'qtest-9p-local'
> > is created (with world rwx permissions) under the current working
> > directory. At this point that test directory is not auto deleted yet.
> > 
> > Signed-off-by: Christian Schoenebeck 
> > Message-Id:
> > <81fc4b3b6b6c9bf7999e79f5e7cbc364a5f09ddb.1602182956.git.qemu_oss@crudeby
> > te.com> Signed-off-by: Christian Schoenebeck 
> > ---
> > 
> >  tests/qtest/libqos/virtio-9p.c | 81 ++
> >  tests/qtest/libqos/virtio-9p.h |  5 +++
> >  tests/qtest/virtio-9p-test.c   | 44 --
> >  3 files changed, 116 insertions(+), 14 deletions(-)
> > 
> > diff --git a/tests/qtest/libqos/virtio-9p.c
> > b/tests/qtest/libqos/virtio-9p.c index 2e300063e3..ee331166de 100644
> > --- a/tests/qtest/libqos/virtio-9p.c
> > +++ b/tests/qtest/libqos/virtio-9p.c
> > @@ -24,6 +24,34 @@
> > 
> >  #include "qgraph.h"
> >  
> >  static QGuestAllocator *alloc;
> > 
> > +static char *local_test_path;
> > +
> > +/* Concatenates the passed 2 pathes. Returned result must be freed. */
> > +static char *concat_path(const char* a, const char* b)
> > +{
> > +return g_build_filename(a, b, NULL);
> > +}
> > +
> > +static void init_local_test_path(void)
> > +{
> > +char *pwd = g_get_current_dir();
> > +local_test_path = concat_path(pwd, "qtest-9p-local");
> > +g_free(pwd);
> > +}
> > +
> > +/* Creates the directory for the 9pfs 'local' filesystem driver to
> > access. */ +static void create_local_test_dir(void)
> > +{
> > +struct stat st;
> > +
> > +g_assert(local_test_path != NULL);
> > +mkdir(local_test_path, 0777);
> > +
> 
> This makes coverity unhappy...
> 
> *** CID 1435963:  Error handling issues  (CHECKED_RETURN)
> /qemu/tests/qtest/libqos/virtio-9p.c: 48 in create_local_test_dir()
> 42 /* Creates the directory for the 9pfs 'local' filesystem driver to
> access. */ 43 static void create_local_test_dir(void)
> 44 {
> 45 struct stat st;
> 46
> 47 g_assert(local_test_path != NULL);
> 
> >>> CID 1435963:  Error handling issues  (CHECKED_RETURN)
> >>> Calling "mkdir(local_test_path, 511U)" without checking return
> >>> value. This library function may fail and return an error code.
> 48 mkdir(local_test_path, 0777);
> 49
> 50 /* ensure test directory exists now ... */
> 51 g_assert(stat(local_test_path, ) == 0);
> 52 /* ... and is actually a directory */
> 53 g_assert((st.st_mode & S_IFMT) == S_IFDIR);
> 
> > +/* ensure test directory exists now ... */
> > +g_assert(stat(local_test_path, ) == 0);
> > +/* ... and is actually a directory */
> > +g_assert((st.st_mode & S_IFMT) == S_IFDIR);
> > +}
> > 

Ok, I'll fix that with tomorrow's patch(es) as well.

Best regards,
Christian Schoenebeck





Re: [PULL 00/13] 9p queue 2020-10-23

2020-10-29 Thread Christian Schoenebeck
On Donnerstag, 29. Oktober 2020 16:04:03 CET Daniel P. Berrangé wrote:
> On Thu, Oct 29, 2020 at 02:52:16PM +, Peter Maydell wrote:
> > On Thu, 29 Oct 2020 at 14:31, Christian Schoenebeck
> > 
> >  wrote:
> > > On Donnerstag, 29. Oktober 2020 15:15:19 CET Peter Maydell wrote:
> > > > On Thu, 29 Oct 2020 at 14:06, Christian Schoenebeck
> > > > 
> > > >  wrote:
> > > > > Ok, I'll use mkdtemp() instead, that avoids other potential parallel
> > > > > config
> > > > > colissions that I may not have considered yet.
> > > > > 
> > > > > The original motivation against mkdtemp() was that /tmp is isually a
> > > > > ramfs,
> > > > > hence very limited regarding large file tests. But that's not an
> > > > > issue
> > > > > right now.
> > > > 
> > > > How large is "large" here ?
> > > 
> > > E.g. ~10 GiB which might be a problem for cloud based CI platforms.
> > 
> > Yeah, 10GB is too big by an order of magnitude for anything in the
> > standard "make check" set. It could go in an optional "I'm the 9p
> > maintainer and I want to run a wider set of tests" target though.
> 
> I think as a rough rule of thumb, tests should not create files
> that are larger than the size of the QEMU build dir, and if it is
> creating non-trivially sized files, then they should be created in
> the build dir, not /tmp.  This probably puts 1 GB as a upper bound
> on size but bear in mind tests can run in parallel, so ideally biggest
> file sizes should be more in the 100s of MB range
> 
> Regards,
> Daniel

I definitely won't run such large-file tests uncaged, so it would not run by
default for sure. But sooner or later it would make sense to streamline test
case options in QEMU in general, so that certain tests would automatically run
or not depending on runner's capabilities, limits and preferences.

The TCG tests for instance periodically trigger test failures as they exceed
Travis-CI's runtime limit of 40mins once in a while.

Back to the actual 9p test failure issue, I think I will go for something like
this:

diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c
index d43647b3b7..ebbacd5896 100644
--- a/tests/qtest/libqos/virtio-9p.c
+++ b/tests/qtest/libqos/virtio-9p.c
@@ -35,7 +35,12 @@ static char *concat_path(const char* a, const char* b)
 static void init_local_test_path(void)
 {
 char *pwd = g_get_current_dir();
-local_test_path = concat_path(pwd, "qtest-9p-local");
+char *template = concat_path(pwd, "qtest-9p-local-XX");
+local_test_path = mkdtemp(template);
+if (!local_test_path) {
+g_test_message("mkdtemp('%s') failed: %s", template, strerror(errno));
+}
+g_assert(local_test_path);
 g_free(pwd);
 }
 
@@ -246,11 +251,6 @@ static void virtio_9p_register_nodes(void)
 const char *str_simple = "fsdev=fsdev0,mount_tag=" MOUNT_TAG;
 const char *str_addr = "fsdev=fsdev0,addr=04.0,mount_tag=" MOUNT_TAG;
 
-/* make sure test dir for the 'local' tests exists and is clean */
-init_local_test_path();
-remove_local_test_dir();
-create_local_test_dir();
-
 QPCIAddress addr = {
 .devfn = QPCI_DEVFN(4, 0),
 };
@@ -278,3 +278,14 @@ static void virtio_9p_register_nodes(void)
 }
 
 libqos_init(virtio_9p_register_nodes);
+
+static void __attribute__((constructor)) construct_virtio_9p(void) {
+/* make sure test dir for the 'local' tests exists */
+init_local_test_path();
+create_local_test_dir();
+}
+
+static void __attribute__((destructor)) destruct_virtio_9p(void) {
+/* remove previously created test dir when test suite completed */
+remove_local_test_dir();
+}

So it would still use the current directory instead of /tmp/ and would
create and remove the test dir on process start/end. I wanted to avoid
using constructor/destructor atttributes, as some compilers don't
support them, but it seems it's already used in the code base and there
are currently no setup/teardown callbacks in libqos.

Another downside: with 'make check -jN' this will temporarily create a
bunch of unused, empty dirs. But I hope that's Ok to fix in QEMU 6
(by adding setup/teardown callbacks to libqos later).

Just hoping there are no glib versions that use threads instead of
processes.

Best regards,
Christian Schoenebeck





Re: [PULL 00/13] 9p queue 2020-10-23

2020-10-29 Thread Christian Schoenebeck
On Donnerstag, 29. Oktober 2020 15:15:19 CET Peter Maydell wrote:
> On Thu, 29 Oct 2020 at 14:06, Christian Schoenebeck
> 
>  wrote:
> > Ok, I'll use mkdtemp() instead, that avoids other potential parallel
> > config
> > colissions that I may not have considered yet.
> > 
> > The original motivation against mkdtemp() was that /tmp is isually a
> > ramfs,
> > hence very limited regarding large file tests. But that's not an issue
> > right now.
> 
> How large is "large" here ?
> 
> thanks
> -- PMM

E.g. ~10 GiB which might be a problem for cloud based CI platforms.

But again, we don't have any 9p test doing that yet. So mkdtemp() is just fine 
for now.

Best regards,
Christian Schoenebeck





Re: [PULL 00/13] 9p queue 2020-10-23

2020-10-29 Thread Christian Schoenebeck
On Donnerstag, 29. Oktober 2020 14:57:45 CET Peter Maydell wrote:
> On Thu, 29 Oct 2020 at 13:48, Christian Schoenebeck
> 
>  wrote:
> > So I'll append the architecture to the test dir location. To nail it this
> > time, anyting else that would come to your mind regarding test dirs?
> 
> I think most tests that need a temp directory set one
> up using mkdtemp().
> 
> thanks
> -- PMM

Ok, I'll use mkdtemp() instead, that avoids other potential parallel config 
colissions that I may not have considered yet.

The original motivation against mkdtemp() was that /tmp is isually a ramfs, 
hence very limited regarding large file tests. But that's not an issue right 
now.

Thanks Peter!

Best regards,
Christian Schoenebeck





Re: [PULL 00/13] 9p queue 2020-10-23

2020-10-29 Thread Christian Schoenebeck
On Donnerstag, 29. Oktober 2020 14:20:11 CET Peter Maydell wrote:
> On Mon, 26 Oct 2020 at 12:48, Christian Schoenebeck
> 
>  wrote:
> > On Montag, 26. Oktober 2020 11:33:42 CET Peter Maydell wrote:
> > > I get a 'make check' failure on x86-64 Linux host:
> > > 
> > > PASS 54 qtest-x86_64: qos-test
> > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/vir
> > > tio- 9p-tests/local/config PASS 55 qtest-x86_64: qos-test
> > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/vir
> > > tio- 9p-tests/local/create_dir PASS 56 qtest-x86_64: qos-test
> > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/vir
> > > tio- 9p-tests/local/unlinkat_dir PASS 57 qtest-x86_64: qos-test
> > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/vir
> > > tio- 9p-tests/local/create_file PASS 58 qtest-x86_64: qos-test
> > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/vir
> > > tio- 9p-tests/local/unlinkat_file PASS 59 qtest-x86_64: qos-test
> > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/vir
> > > tio- 9p-tests/local/symlink_file Received response 7 (RLERROR) instead
> > > of 73 (RMKDIR)
> > > Rlerror has errno 2 (No such file or directory)
> > > **
> > > ERROR:../../tests/qtest/virtio-9p-test.c:300:v9fs_req_recv: assertion
> > > failed (hdr.id == id): (7 == 73)
> > > ERROR qtest-x86_64: qos-test - Bail out!
> > > ERROR:../../tests/qtest/virtio-9ptest.c:300:v9fs_req_recv: assertion
> > > failed (hdr.id == id): (7 == 73)
> > > Makefile.mtest:3953: recipe for target 'run-test-492' failed
> 
> I just got this again on an entirely different pullreq so that
> suggests that this is indeed an intermittent currently in master:
> 
> PASS 49 qtest-i386/qos-test
> /i386/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virtio-9p
> -tests/synth/flush/ignored PASS 50 qtest-i386/qos-test
> /i386/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virtio-9p
> -tests/synth/readdir/basic PASS 51 qtest-i386/qos-test
> /i386/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virtio-9p
> -tests/synth/readdir/split_512 PASS 52 qtest-i386/qos-test
> /i386/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virtio-9p
> -tests/synth/readdir/split_256 PASS 53 qtest-i386/qos-test
> /i386/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virtio-9p
> -tests/synth/readdir/split_128 PASS 54 qtest-i386/qos-test
> /i386/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virtio-9p
> -tests/local/config Received response 7 (RLERROR) instead of 73 (RMKDIR)
> Rlerror has errno 2 (No such file or directory)
> **
> ERROR:../../tests/qtest/virtio-9p-test.c:296:v9fs_req_recv: assertion
> failed (hdr.id == id): (7 == 73)
> ERROR qtest-i386/qos-test - Bail out!
> ERROR:../../tests/qtest/virtio-9p-test.c:296:v9fs_req_recv: assertion
> failed (hdr.id == id): (7 == 73)
> Makefile.mtest:1857: recipe for target 'run-test-230' failed
> 
> > So the 9p server is already failing to create the test case directory
> > "./qtest-9p-local/05/" relative to your current working directory.
> 
> This sounds suspicious, because there's nothing in that filename
> that's specific to the test case being qtest-i386 and not
> qtest-something-else. How does the test harness deal with the
> possibility of the same virtio-9p-pci test being run in parallel
> for multiple guest architectures under a make -jN setup ?

Ah, now there we go!

I was actually running the tests for 2 days and >3000 test suite runs now 
without a single 9p test failure, but ... not for multiple architectures 
simultaniously.

Another point for centralizing test dir locations in future.

> 
> > What puzzles me is that the previous test cases succeeded there, which all
> > 
> > create their own test directory in the same way:
> > ./qtest-9p-local/01/
> > ./qtest-9p-local/02/  (<-- dir vanishes after that test completed)
> > ./qtest-9p-local/03/
> > ./qtest-9p-local/04/
> > ...
> 
> After the build failed, the qtest-9p-local directory was empty.

Yes, that suggests a parallel test suite was wiping the test directory
'./qtest-9p-local'.

So I'll append the architecture to the test dir location. To nail it this 
time, anyting else that would come to your mind regarding test dirs?

> 
> thanks
> -- PMM

Best regards,
Christian Schoenebeck





Re: [PATCH] hw/9pfs: virtio-9p: Ensure config space is a multiple of 4 bytes

2020-10-29 Thread Christian Schoenebeck
On Donnerstag, 29. Oktober 2020 09:25:41 CET Bin Meng wrote:
> From: Bin Meng 
> 
> At present the virtio device config space access is handled by the
> virtio_config_readX() and virtio_config_writeX() APIs. They perform
> a sanity check on the result of address plus size against the config
> space size before the access occurs.

Since I am not very familiar with the virtio implementation side, I hope
Michael would have a look at this patch.

But some comments from my side ...

> 
> For unaligned access, the last converted naturally aligned access
> will fail the sanity check on 9pfs. For example, with a mount_tag
> `p9fs`, if guest software tries to read the mount_tag via a 4 byte
> read at the mount_tag offset which is not 4 byte aligned, the read
> result will be `p9\377\377`, which is wrong.

Why 4? Shouldn't this rather consider worst case alignment?

> 
> This changes the size of device config space to be a multiple of 4
> bytes so that correct result can be returned in all circumstances.
> 
> Signed-off-by: Bin Meng 
> ---
> 
>  hw/9pfs/virtio-9p-device.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
> index 14371a7..e6a1432 100644
> --- a/hw/9pfs/virtio-9p-device.c
> +++ b/hw/9pfs/virtio-9p-device.c
> @@ -201,6 +201,7 @@ static void virtio_9p_device_realize(DeviceState *dev, 
> Error **errp)
>  V9fsVirtioState *v = VIRTIO_9P(dev);
>  V9fsState *s = >state;
>  FsDriverEntry *fse = get_fsdev_fsentry(s->fsconf.fsdev_id);
> +size_t config_size;
>  
>  if (qtest_enabled() && fse) {
>  fse->export_flags |= V9FS_NO_PERF_WARN;
> @@ -211,7 +212,8 @@ static void virtio_9p_device_realize(DeviceState *dev, 
> Error **errp)
>  }
>  
>  v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag);
> -virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size);
> +config_size = ROUND_UP(v->config_size, 4);
> +virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, config_size);
>  v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output);
>  }

Shouldn't this config_size correction rather be handled on virtio.c side
instead, i.e. in virtio_init()?

>  
> -- 
> 2.7.4

Best regards,
Christian Schoenebeck





Re: [PATCH 1/3] hw/9pfs : add spaces around operator

2020-10-29 Thread Christian Schoenebeck
On Mittwoch, 28. Oktober 2020 10:05:38 CET jokenzhang wrote:
> Signed-off-by: jokenzhang 
> Signed-off-by: Kai Deng 
> Reported-by: Euler Robot 
> ---
>  hw/9pfs/9p-local.c | 10 +-
>  hw/9pfs/9p.c   | 16 
>  2 files changed, 13 insertions(+), 13 deletions(-)

It would make sense to mention the actual purpose of this patch: fix code 
style.

Same applies to the other 2 patches.

> 
> diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
> index 3107637209..af52c1daac 100644
> --- a/hw/9pfs/9p-local.c
> +++ b/hw/9pfs/9p-local.c
> @@ -162,13 +162,13 @@ static void local_mapped_file_attr(int dirfd, const
> char *name, memset(buf, 0, ATTR_MAX);
>  while (fgets(buf, ATTR_MAX, fp)) {
>  if (!strncmp(buf, "virtfs.uid", 10)) {
> -stbuf->st_uid = atoi(buf+11);
> +stbuf->st_uid = atoi(buf + 11);
>  } else if (!strncmp(buf, "virtfs.gid", 10)) {
> -stbuf->st_gid = atoi(buf+11);
> +stbuf->st_gid = atoi(buf + 11);
>  } else if (!strncmp(buf, "virtfs.mode", 11)) {
> -stbuf->st_mode = atoi(buf+12);
> +stbuf->st_mode = atoi(buf + 12);
>  } else if (!strncmp(buf, "virtfs.rdev", 11)) {
> -stbuf->st_rdev = atoi(buf+12);
> +stbuf->st_rdev = atoi(buf + 12);
>  }
>  memset(buf, 0, ATTR_MAX);
>  }
> @@ -823,7 +823,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath
> *dir_path, const char *name, if (fd == -1) {
>  goto out;
>  }
> -credp->fc_mode = credp->fc_mode|S_IFREG;
> +credp->fc_mode = credp->fc_mode | S_IFREG;
>  if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
>  /* Set cleint credentials in xattr */
>  err = local_set_xattrat(dirfd, name, credp);
> diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
> index 741d222c3f..94df440fc7 100644
> --- a/hw/9pfs/9p.c
> +++ b/hw/9pfs/9p.c
> @@ -1091,7 +1091,7 @@ static mode_t v9mode_to_mode(uint32_t mode, V9fsString
> *extension) }
>  }
> 
> -if (!(ret&~0777)) {
> +if (!(ret & ~0777)) {
>  ret |= S_IFREG;
>  }
> 
> @@ -2776,7 +2776,7 @@ static void coroutine_fn v9fs_create(void *opaque)
>  v9fs_path_unlock(s);
>  } else {
>  err = v9fs_co_open2(pdu, fidp, , -1,
> -omode_to_uflags(mode)|O_CREAT, perm, );
> +omode_to_uflags(mode) | O_CREAT, perm, );
> if (err < 0) {
>  goto out;
>  }
> @@ -3428,7 +3428,7 @@ static int v9fs_fill_statfs(V9fsState *s, V9fsPDU
> *pdu, struct statfs *stbuf) * compute bsize factor based on host file
> system block size
>   * and client msize
>   */
> -bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
> +bsize_factor = (s->msize - P9_IOHDRSZ) / stbuf->f_bsize;
>  if (!bsize_factor) {
>  bsize_factor = 1;
>  }
> @@ -3440,9 +3440,9 @@ static int v9fs_fill_statfs(V9fsState *s, V9fsPDU
> *pdu, struct statfs *stbuf) * adjust(divide) the number of blocks, free
> blocks and available * blocks by bsize factor
>   */
> -f_blocks = stbuf->f_blocks/bsize_factor;
> -f_bfree  = stbuf->f_bfree/bsize_factor;
> -f_bavail = stbuf->f_bavail/bsize_factor;
> +f_blocks = stbuf->f_blocks / bsize_factor;
> +f_bfree  = stbuf->f_bfree / bsize_factor;
> +f_bavail = stbuf->f_bavail / bsize_factor;
>  f_files  = stbuf->f_files;
>  f_ffree  = stbuf->f_ffree;
>  fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
> @@ -4185,6 +4185,6 @@ static void __attribute__((__constructor__))
> v9fs_set_fd_limit(void) error_report("Failed to get the resource limit");
>  exit(1);
>  }
> -open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3);
> -open_fd_rc = rlim.rlim_cur/2;
> +open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur / 3);
> +open_fd_rc = rlim.rlim_cur / 2;
>  }

Best regards,
Christian Schoenebeck





Re: [PATCH v4 04/12] libqos/qgraph: add qos_dump_graph()

2020-10-28 Thread Christian Schoenebeck
On Mittwoch, 28. Oktober 2020 14:00:21 CET Eric Blake wrote:
> On 10/28/20 12:51 AM, Thomas Huth wrote:
> >>>> +#define GREEN(txt) (  \
> >>>> +"\033[0;92m" txt  \
> >>>> +"\033[0m" \
> >>>> +)
> >>> 
> >>> I don't think this is very portable - and it will only make logs ugly to
> >>> read in text editors. Could you please simply drop these macros?
> > 
> > Sure, colored output is nice, but we certainly also need a way to disable
> > it, e.g. if you want to collect the log in a file and then have a look at
> > it in a text editor.
> 
> Agreed. GNU libtextstyle
> (https://www.gnu.org/software/gettext/libtextstyle/manual/libtextstyle.html)
> is a much more portable way to do colored output where it becomes easy to
> enable/disable or even adjust the colors to user preferences.  Sadly, it is
> GPLv3+, and thus unusable for qemu.  But the bare minimum that you must
> have when making colored output gated on whether stdout is a
> terminal (that is, any program that does color should have a
> --color=off|auto|on command-line option, and that in turn implies
> function calls rather than macros to properly encapsulate the decision
> logic.

Not sure if it would make sense adding another dependency just for colour 
support in QEMU anyway, because rendering the right output sequence is not the 
big issue, nor auto detecting tty colour support, nor handling user configs. A 
large number of apps already do that in-tree / inline.

The challenge in QEMU though (in contrast to stand-alone apps) is integrating 
this meaningful for all the (quite different) output channels in QEMU, e.g. 
host logs, test case output, different modes, etc., while catching misusage 
and retaining a simple API.

I postpone the colour issue for that reason and drop colour from these patches 
for now. I'll probably rather come up with a dedicated series attempt just for 
colour at some later point.

Best regards,
Christian Schoenebeck





Re: [PULL 00/13] 9p queue 2020-10-23

2020-10-27 Thread Christian Schoenebeck
On Dienstag, 27. Oktober 2020 11:26:53 CET Dr. David Alan Gilbert wrote:
> * Christian Schoenebeck (qemu_...@crudebyte.com) wrote:
> > On Dienstag, 27. Oktober 2020 10:06:53 CET Dr. David Alan Gilbert wrote:
> > > * Greg Kurz (gr...@kaod.org) wrote:
> > > > On Mon, 26 Oct 2020 13:48:37 +0100
> > > > 
> > > > Christian Schoenebeck  wrote:
> > > > > On Montag, 26. Oktober 2020 11:33:42 CET Peter Maydell wrote:
> > > > > > On Fri, 23 Oct 2020 at 12:46, Christian Schoenebeck
> > > > > > 
> > > > > >  wrote:
> > > > > > > The following changes since commit
> > 
> > 4c5b97bfd0dd54dc27717ae8d1cd10e14eef1430:
> > > > > > >   Merge remote-tracking branch
> > > > > > >   'remotes/kraxel/tags/modules-20201022-pull-request' into
> > > > > > >   staging
> > > > > > >   (2020-10-22 12:33:21 +0100)>
> > > > > > > 
> > > > > > > are available in the Git repository at:
> > > > > > >   https://github.com/cschoenebeck/qemu.git tags/pull-9p-20201023
> > > > > > > 
> > > > > > > for you to fetch changes up to
> > 
> > ee01926a11b1f9bffcd6cdec0961dd9d1882da71:
> > > > > > >   tests/9pfs: add local Tunlinkat hard link test (2020-10-22
> > > > > > >   20:26:33
> > > > > > >   +0200)
> > > > > > > 
> > > > > > > 
> > > > > > > 9pfs: more tests using local fs driver
> > > > > > > 
> > > > > > > Only 9pfs test case changes this time:
> > > > > > > 
> > > > > > > * Refactor: Rename functions to make top-level test functions
> > > > > > > fs_*()
> > > > > > > 
> > > > > > >   easily distinguishable from utility test functions do_*().
> > > > > > > 
> > > > > > > * Refactor: Drop unnecessary function arguments in utility test
> > > > > > > 
> > > > > > >   functions.
> > > > > > > 
> > > > > > > * More test cases using the 9pfs 'local' filesystem driver
> > > > > > > backend,
> > > > > > > 
> > > > > > >   namely for the following 9p requests: Tunlinkat, Tlcreate,
> > > > > > >   Tsymlink
> > > > > > >   and Tlink.
> > > > > > > 
> > > > > > > 
> > > > > > 
> > > > > > I get a 'make check' failure on x86-64 Linux host:
> > > > > > 
> > > > > > PASS 54 qtest-x86_64: qos-test
> > > > > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-
> > > > > > 9p/v
> > > > > > irtio- 9p-tests/local/config PASS 55 qtest-x86_64: qos-test
> > > > > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-
> > > > > > 9p/v
> > > > > > irtio- 9p-tests/local/create_dir PASS 56 qtest-x86_64: qos-test
> > > > > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-
> > > > > > 9p/v
> > > > > > irtio- 9p-tests/local/unlinkat_dir PASS 57 qtest-x86_64: qos-test
> > > > > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-
> > > > > > 9p/v
> > > > > > irtio- 9p-tests/local/create_file PASS 58 qtest-x86_64: qos-test
> > > > > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-
> > > > > > 9p/v
> > > > > > irtio- 9p-tests/local/unlinkat_file PASS 59 qtest-x86_64: qos-test
> > > > > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-
> > > > > > 9p/v
> > > > > > irtio- 9p-tests/local/symlink_file Received response 7 (RLERROR)
> > > > > > instead of 73 (RMKDIR)
> > > > > > Rlerror has errno 2 (No such file or directory)
> > > > > > **
> > > > > > ERROR:../../tests/qtest/virtio-9p-test.c:300:v9fs_req_recv:
> > > > > > assertion
> > > > > > failed (hdr.id == id): (7 == 73)
> > > > 
> > > > Not sure this is related to this PR actually. Dave

Re: [PULL 00/13] 9p queue 2020-10-23

2020-10-27 Thread Christian Schoenebeck
On Dienstag, 27. Oktober 2020 10:06:53 CET Dr. David Alan Gilbert wrote:
> * Greg Kurz (gr...@kaod.org) wrote:
> > On Mon, 26 Oct 2020 13:48:37 +0100
> > 
> > Christian Schoenebeck  wrote:
> > > On Montag, 26. Oktober 2020 11:33:42 CET Peter Maydell wrote:
> > > > On Fri, 23 Oct 2020 at 12:46, Christian Schoenebeck
> > > > 
> > > >  wrote:
> > > > > The following changes since commit 
4c5b97bfd0dd54dc27717ae8d1cd10e14eef1430:
> > > > >   Merge remote-tracking branch
> > > > >   'remotes/kraxel/tags/modules-20201022-pull-request' into staging
> > > > >   (2020-10-22 12:33:21 +0100)>
> > > > > 
> > > > > are available in the Git repository at:
> > > > >   https://github.com/cschoenebeck/qemu.git tags/pull-9p-20201023
> > > > > 
> > > > > for you to fetch changes up to 
ee01926a11b1f9bffcd6cdec0961dd9d1882da71:
> > > > >   tests/9pfs: add local Tunlinkat hard link test (2020-10-22
> > > > >   20:26:33
> > > > >   +0200)
> > > > > 
> > > > > 
> > > > > 9pfs: more tests using local fs driver
> > > > > 
> > > > > Only 9pfs test case changes this time:
> > > > > 
> > > > > * Refactor: Rename functions to make top-level test functions fs_*()
> > > > > 
> > > > >   easily distinguishable from utility test functions do_*().
> > > > > 
> > > > > * Refactor: Drop unnecessary function arguments in utility test
> > > > > 
> > > > >   functions.
> > > > > 
> > > > > * More test cases using the 9pfs 'local' filesystem driver backend,
> > > > > 
> > > > >   namely for the following 9p requests: Tunlinkat, Tlcreate,
> > > > >   Tsymlink
> > > > >   and Tlink.
> > > > > 
> > > > > 
> > > > 
> > > > I get a 'make check' failure on x86-64 Linux host:
> > > > 
> > > > PASS 54 qtest-x86_64: qos-test
> > > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/v
> > > > irtio- 9p-tests/local/config PASS 55 qtest-x86_64: qos-test
> > > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/v
> > > > irtio- 9p-tests/local/create_dir PASS 56 qtest-x86_64: qos-test
> > > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/v
> > > > irtio- 9p-tests/local/unlinkat_dir PASS 57 qtest-x86_64: qos-test
> > > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/v
> > > > irtio- 9p-tests/local/create_file PASS 58 qtest-x86_64: qos-test
> > > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/v
> > > > irtio- 9p-tests/local/unlinkat_file PASS 59 qtest-x86_64: qos-test
> > > > /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/v
> > > > irtio- 9p-tests/local/symlink_file Received response 7 (RLERROR)
> > > > instead of 73 (RMKDIR)
> > > > Rlerror has errno 2 (No such file or directory)
> > > > **
> > > > ERROR:../../tests/qtest/virtio-9p-test.c:300:v9fs_req_recv: assertion
> > > > failed (hdr.id == id): (7 == 73)
> > 
> > Not sure this is related to this PR actually. Dave Gilbert reported on irc
> > that he encountered a similar issue with 'make -j check', likely without
> > these patches.
> I was running on current master as of yesterday; no 9p specific patches.
> 
> Dave

They might be related as the "local/create_dir" test is already merged, but 
hard to say reliably without any data.

How is reproducibility, sometimes / always?

> 
> > > > ERROR qtest-x86_64: qos-test - Bail out!
> > > > ERROR:../../tests/qtest/virtio-9ptest.c:300:v9fs_req_recv: assertion
> > > > failed (hdr.id == id): (7 == 73)
> > > > Makefile.mtest:3953: recipe for target 'run-test-492' failed
> > > > 
> > > > 
> > > > thanks
> > > > -- PMM
> > > 
> > > So the 9p server is already failing to create the test case directory
> > > "./qtest-9p-local/05/" relative to your current working directory.
> > > 
> > > I would appreciate to get more info when you have some free cycles, as
> > > I'm
> > > unable to reproduce this on any s

Re: [PULL 00/13] 9p queue 2020-10-23

2020-10-26 Thread Christian Schoenebeck
On Montag, 26. Oktober 2020 11:33:42 CET Peter Maydell wrote:
> On Fri, 23 Oct 2020 at 12:46, Christian Schoenebeck
> 
>  wrote:
> > The following changes since commit 4c5b97bfd0dd54dc27717ae8d1cd10e14eef1430:
> >   Merge remote-tracking branch
> >   'remotes/kraxel/tags/modules-20201022-pull-request' into staging
> >   (2020-10-22 12:33:21 +0100)> 
> > are available in the Git repository at:
> >   https://github.com/cschoenebeck/qemu.git tags/pull-9p-20201023
> > 
> > for you to fetch changes up to ee01926a11b1f9bffcd6cdec0961dd9d1882da71:
> >   tests/9pfs: add local Tunlinkat hard link test (2020-10-22 20:26:33
> >   +0200)
> > 
> > 
> > 9pfs: more tests using local fs driver
> > 
> > Only 9pfs test case changes this time:
> > 
> > * Refactor: Rename functions to make top-level test functions fs_*()
> > 
> >   easily distinguishable from utility test functions do_*().
> > 
> > * Refactor: Drop unnecessary function arguments in utility test
> > 
> >   functions.
> > 
> > * More test cases using the 9pfs 'local' filesystem driver backend,
> > 
> >   namely for the following 9p requests: Tunlinkat, Tlcreate, Tsymlink
> >   and Tlink.
> > 
> > 
> 
> I get a 'make check' failure on x86-64 Linux host:
> 
> PASS 54 qtest-x86_64: qos-test
> /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virtio-
> 9p-tests/local/config PASS 55 qtest-x86_64: qos-test
> /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virtio-
> 9p-tests/local/create_dir PASS 56 qtest-x86_64: qos-test
> /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virtio-
> 9p-tests/local/unlinkat_dir PASS 57 qtest-x86_64: qos-test
> /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virtio-
> 9p-tests/local/create_file PASS 58 qtest-x86_64: qos-test
> /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virtio-
> 9p-tests/local/unlinkat_file PASS 59 qtest-x86_64: qos-test
> /x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virtio-
> 9p-tests/local/symlink_file Received response 7 (RLERROR) instead of 73
> (RMKDIR)
> Rlerror has errno 2 (No such file or directory)
> **
> ERROR:../../tests/qtest/virtio-9p-test.c:300:v9fs_req_recv: assertion
> failed (hdr.id == id): (7 == 73)
> ERROR qtest-x86_64: qos-test - Bail out!
> ERROR:../../tests/qtest/virtio-9ptest.c:300:v9fs_req_recv: assertion
> failed (hdr.id == id): (7 == 73)
> Makefile.mtest:3953: recipe for target 'run-test-492' failed
> 
> 
> thanks
> -- PMM

So the 9p server is already failing to create the test case directory
"./qtest-9p-local/05/" relative to your current working directory.

I would appreciate to get more info when you have some free cycles, as I'm
unable to reproduce this on any system unfortunately. But no hurry as
these tests only become relevant actually for QEMU 6.

What puzzles me is that the previous test cases succeeded there, which all
create their own test directory in the same way:

./qtest-9p-local/01/
./qtest-9p-local/02/  (<-- dir vanishes after that test completed)
./qtest-9p-local/03/
./qtest-9p-local/04/
...

How does the "./qtest-9p-local/" directory look like after that
"local/symlink_file" test failed there? You can use this shortcut:

export QTEST_QEMU_BINARY=x86_64-softmmu/qemu-system-x86_64
cd build
tests/qtest/qos-test --verbose
ls -l qtest-9p-local

That latter qos-test run will also output the assembled qemu command
line the 9p local tests would run with, which might also be helpful,
e.g. the relevant output would be something like this:

GTest: run: 
/x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virtio-9p-tests/local/config
(MSG: starting QEMU: exec x86_64-softmmu/qemu-system-x86_64 -qtest 
unix:/tmp/qtest-7428.sock -qtest-log /dev/null -chardev 
socket,path=/tmp/qtest-7428.qmp,id=char0 -mon chardev=char0,mode=control 
-display none -M pc  -fsdev 
local,id=fsdev0,path='/home/me/git/qemu/build/qtest-9p-local',security_model=mapped-xattr
 -device virtio-9p-pci,fsdev=fsdev0,addr=04.0,mount_tag=qtest -accel qtest)

Would probably the test succeed if run alone?

tests/qtest/qos-test -p 
/x86_64/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virtio-9p-tests/local/symlink_file

Best regards,
Christian Schoenebeck





Re: [PATCH v4 05/12] tests/qtest/qos-test: dump qos graph if verbose

2020-10-24 Thread Christian Schoenebeck
On Samstag, 24. Oktober 2020 08:01:55 CEST Thomas Huth wrote:
> On 08/10/2020 20.34, Christian Schoenebeck wrote:
> > If qtests were run in verbose mode (i.e. if --verbose CL argument was
> > provided) then dump the generated qos graph (all nodes and edges,
> > along with their current individual availability status) to stdout.
> > 
> > See API doc comment on function qos_dump_graph() for details.
> > 
> > Signed-off-by: Christian Schoenebeck 
> > ---
> > 
> >  tests/qtest/qos-test.c | 3 +++
> >  1 file changed, 3 insertions(+)
> > 
> > diff --git a/tests/qtest/qos-test.c b/tests/qtest/qos-test.c
> > index 8fdf87b183..d98ef78613 100644
> > --- a/tests/qtest/qos-test.c
> > +++ b/tests/qtest/qos-test.c
> > @@ -322,6 +322,9 @@ int main(int argc, char **argv)
> > 
> >  qos_set_machines_devices_available();
> >  
> >  qos_graph_foreach_test_path(walk_path);
> > 
> > +if (g_test_verbose()) {
> > +qos_dump_graph();
> > +}
> > 
> >  g_test_run();
> >  qtest_end();
> >  qos_graph_destroy();
> 
> I'd squash this into the previous patch, so that it is clear there where the
> function gets used.
> 
>  Thomas

Sure, np.

Thanks for your feedback Thomas.

Best regards,
Christian Schoenebeck





Re: [PATCH v4 04/12] libqos/qgraph: add qos_dump_graph()

2020-10-24 Thread Christian Schoenebeck
On Samstag, 24. Oktober 2020 08:04:20 CEST Thomas Huth wrote:
> On 08/10/2020 20.34, Christian Schoenebeck wrote:
> > This new function is purely for debugging purposes. It prints the
> > current qos graph to stdout and allows to identify problems in the
> > created qos graph e.g. when writing new qos tests.
> > 
> > Coloured output is used to mark available nodes in green colour,
> > whereas unavailable nodes are marked in red colour.
> > 
> > Signed-off-by: Christian Schoenebeck 
> > ---
> > 
> >  tests/qtest/libqos/qgraph.c | 56 +
> >  tests/qtest/libqos/qgraph.h | 20 +
> >  2 files changed, 76 insertions(+)
> > 
> > diff --git a/tests/qtest/libqos/qgraph.c b/tests/qtest/libqos/qgraph.c
> > index 61faf6b27d..af93e38dcb 100644
> > --- a/tests/qtest/libqos/qgraph.c
> > +++ b/tests/qtest/libqos/qgraph.c
> > @@ -805,3 +805,59 @@ void qos_delete_cmd_line(const char *name)
> > 
> >  node->command_line = NULL;
> >  
> >  }
> >  
> >  }
> > 
> > +
> > +#define RED(txt) (\
> > +"\033[0;91m" txt  \
> > +"\033[0m" \
> > +)
> > +
> > +#define GREEN(txt) (  \
> > +"\033[0;92m" txt  \
> > +"\033[0m" \
> > +)
> 
> I don't think this is very portable - and it will only make logs ugly to
> read in text editors. Could you please simply drop these macros?
> 
>  Thomas

The precise way I did it here is definitely unclean. And the use case is 
trivial, so on doubt I could just drop it of course.

But allow me one attempt to promote coloured terminal output in general: These 
are ANSI color escape sequences, a standard with its youngest revision dating 
back to 1991. It is a well supported standard on all major platforms nowadays:

https://en.wikipedia.org/wiki/ANSI_escape_code

It works on macOS's standard terminal for at least 20 years, with cmd.exe on 
Windows 10, on essentially all Linux and BSD distros, and even on many web 
based CI platforms.

So what about introducing some globally shared macros for coloured output 
instead? Then there would be one central place for changing coloured output 
support for the entire code base; and I would change the macros to fallback to 
plain text output if there is any doubt the terminal would not support it.

Besides, QEMU just switched to meson which uses coloured output as well, as do 
clang, GCC, git and many other tools in your build chain.

Best regards,
Christian Schoenebeck





Re: [PATCH v4 06/12] tests/qtest/qos-test: dump environment variables if verbose

2020-10-24 Thread Christian Schoenebeck
On Samstag, 24. Oktober 2020 07:56:10 CEST Thomas Huth wrote:
> On 08/10/2020 20.34, Christian Schoenebeck wrote:
> > If qtests are run in verbose mode (i.e. if --verbose CL argument
> > was provided) then print all environment variables to stdout
> > before running the individual tests.
> 
> Why? ... you should provide some rationale in the patch description here, at
> least to me this is not obvious why it is needed / desired.
> 
>  Thomas

In my particular case I wanted to know whether there is already some config 
vector for 'please use this test directory for file tests'. As I didn't find 
one in any API, I also looked for environment variables to be sure. Especially 
as there are a bunch of qtest related environment variables already.

In general though it is common nowadays, at least being able to output all 
config vectors in a build chain, especially if it is required to investigate 
build- and test-issues on foreign/remote machines, which includes environment 
variables.

Staying in the context of writing test cases: there are a bunch of other use 
cases that would come to my mind from the PoV of a test case author:
"Is there an option for short vs. long tests?", "Is there a desired size 
limitation for large file tests?", "Is there a deadline for the runtime of 
tests?", ...

Best regards,
Christian Schoenebeck





Re: [PATCH v4 01/12] libqos/qgraph: add qemu_name to QOSGraphNode

2020-10-24 Thread Christian Schoenebeck
On Samstag, 24. Oktober 2020 08:08:59 CEST Thomas Huth wrote:
> On 19/10/2020 12.35, Christian Schoenebeck wrote:
> > On Donnerstag, 8. Oktober 2020 20:34:56 CEST Christian Schoenebeck wrote:
> >> Add new member variable 'qemu_name' to struct QOSGraphNode.
> >> 
> >> This new member may be optionally set in case a different
> >> name for the node (which must always be a unique name) vs.
> >> its actually associated QEMU (QMP) device name is required.
> >> 
> >> Signed-off-by: Christian Schoenebeck 
> >> ---
> >> 
> >>  tests/qtest/libqos/qgraph.c  | 1 +
> >>  tests/qtest/libqos/qgraph_internal.h | 1 +
> >>  2 files changed, 2 insertions(+)
> > 
> > So what shall happen with these libqos patches 1..7? Is that a nack, or
> > postpone for now?
> 
> I was hoping to see a review by Paolo or Laurent, who are much more familiar
> with qos than I am ... but after having a look at the patches, I think I
> can also give some feedback, too:
> 
> Patch 1 and 2 sound basically ok to me (should maybe be squashed together,
> though), but the qos_node_create_driver_named() function currently seems to
> be unused so far? So I'd postpone these two patches to the point in time
> when you really need the qos_node_create_driver_named() function.

I did use patches 1 & 2 in v1 of this series, as of v2 and higher I used a
workaround for the actual 9pfs test case patches not to depend on these 2
libqos patches. This happened after Paolo's feedback, who wrote that qos
patches 1 & 2 would be useful for other, future use cases, but argued it
would not be appropriate for my intended use case:

https://lore.kernel.org/qemu-devel/95ef57d0-b35e-f16a-f957-06bc3692c...@redhat.com/

I preserved patches 1 & 2 in this series though as he noted they might be
useful for future purposes and applied his requested changes. I personally
probably won't need thise 2 patches any time soon. So it's up to you what
shall happen with them. I don't mind if you postpone or nack them.

> The other patches are basically fine with me, too, but please avoid the
> hard-coded ESC codes that only work with certain terminals.
> 
>  Thomas

I'll respond to that on your patch 4 response.

Best regards,
Christian Schoenebeck





Re: [PULL 01/13] tests/9pfs: Factor out do_version() helper

2020-10-23 Thread Christian Schoenebeck
On Freitag, 23. Oktober 2020 17:32:02 CEST Greg Kurz wrote:
> It feels weird to receive a mail I didn't send with my address
> in the top From: header. I would have expected yours instead and
> another From: with my address in the changelog...
> 
> 
> On Tue, 20 Oct 2020 18:09:14 +0200
> Greg Kurz  wrote:
> 
> ... here.

Yep, I noticed that too late. I'll take care about it next time. Sorry!

Best regards,
Christian Schoenebeck





[PULL 12/13] tests/9pfs: add local Tlink test

2020-10-23 Thread Christian Schoenebeck
This test case uses a Tlink request to create a hard link to a regular
file using the 9pfs 'local' fs driver.

Signed-off-by: Christian Schoenebeck 
Reviewed-by: Greg Kurz 
Message-Id: 

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 71 
 1 file changed, 71 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 33cba24b18..460fa49fe3 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -260,6 +260,7 @@ static const char *rmessage_name(uint8_t id)
 id == P9_RMKDIR ? "RMKDIR" :
 id == P9_RLCREATE ? "RLCREATE" :
 id == P9_RSYMLINK ? "RSYMLINK" :
+id == P9_RLINK ? "RLINK" :
 id == P9_RUNLINKAT ? "RUNLINKAT" :
 id == P9_RFLUSH ? "RFLUSH" :
 id == P9_RREADDIR ? "READDIR" :
@@ -767,6 +768,33 @@ static void v9fs_rsymlink(P9Req *req, v9fs_qid *qid)
 v9fs_req_free(req);
 }
 
+/* size[4] Tlink tag[2] dfid[4] fid[4] name[s] */
+static P9Req *v9fs_tlink(QVirtio9P *v9p, uint32_t dfid, uint32_t fid,
+ const char *name, uint16_t tag)
+{
+P9Req *req;
+
+uint32_t body_size = 4 + 4;
+uint16_t string_size = v9fs_string_size(name);
+
+g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+body_size += string_size;
+
+req = v9fs_req_init(v9p, body_size, P9_TLINK, tag);
+v9fs_uint32_write(req, dfid);
+v9fs_uint32_write(req, fid);
+v9fs_string_write(req, name);
+v9fs_req_send(req);
+return req;
+}
+
+/* size[4] Rlink tag[2] */
+static void v9fs_rlink(P9Req *req)
+{
+v9fs_req_recv(req, P9_RLINK);
+v9fs_req_free(req);
+}
+
 /* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */
 static P9Req *v9fs_tunlinkat(QVirtio9P *v9p, uint32_t dirfd, const char *name,
  uint32_t flags, uint16_t tag)
@@ -1142,6 +1170,21 @@ static void do_symlink(QVirtio9P *v9p, const char *path, 
const char *clink,
 g_free(name);
 }
 
+/* create a hard link named @a clink in directory @a path pointing to @a to */
+static void do_hardlink(QVirtio9P *v9p, const char *path, const char *clink,
+const char *to)
+{
+uint32_t dfid, fid;
+P9Req *req;
+
+dfid = do_walk(v9p, path);
+fid = do_walk(v9p, to);
+
+req = v9fs_tlink(v9p, dfid, fid, clink, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rlink(req);
+}
+
 static void do_unlinkat(QVirtio9P *v9p, const char *atpath, const char *rpath,
 uint32_t flags)
 {
@@ -1321,6 +1364,33 @@ static void fs_unlinkat_symlink(void *obj, void *data,
 g_free(real_file);
 }
 
+static void fs_hardlink_file(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+struct stat st_real, st_link;
+char *real_file = virtio_9p_test_path("07/real_file");
+char *hardlink_file = virtio_9p_test_path("07/hardlink_file");
+
+do_attach(v9p);
+do_mkdir(v9p, "/", "07");
+do_lcreate(v9p, "07", "real_file");
+g_assert(stat(real_file, _real) == 0);
+g_assert((st_real.st_mode & S_IFMT) == S_IFREG);
+
+do_hardlink(v9p, "07", "hardlink_file", "07/real_file");
+
+/* check if link exists now ... */
+g_assert(stat(hardlink_file, _link) == 0);
+/* ... and it's a hard link, right? */
+g_assert((st_link.st_mode & S_IFMT) == S_IFREG);
+g_assert(st_link.st_dev == st_real.st_dev);
+g_assert(st_link.st_ino == st_real.st_ino);
+
+g_free(hardlink_file);
+g_free(real_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1367,6 +1437,7 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/symlink_file", "virtio-9p", fs_symlink_file, );
 qos_add_test("local/unlinkat_symlink", "virtio-9p", fs_unlinkat_symlink,
  );
+qos_add_test("local/hardlink_file", "virtio-9p", fs_hardlink_file, );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PULL 07/13] tests/9pfs: add local Tunlinkat directory test

2020-10-23 Thread Christian Schoenebeck
This test case uses a Tunlinkat 9p request with flag AT_REMOVEDIR
(see 'man 2 unlink') to remove a directory from host's test directory.

Signed-off-by: Christian Schoenebeck 
Reviewed-by: Greg Kurz 
Message-Id: 
<3c7c65b476ba44bea6afd0b378b5287e1c671a32.1603285620.git.qemu_...@crudebyte.com>
Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 71 
 1 file changed, 71 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 21807037df..abd7e44648 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -258,6 +258,7 @@ static const char *rmessage_name(uint8_t id)
 id == P9_RLOPEN ? "RLOPEN" :
 id == P9_RWRITE ? "RWRITE" :
 id == P9_RMKDIR ? "RMKDIR" :
+id == P9_RUNLINKAT ? "RUNLINKAT" :
 id == P9_RFLUSH ? "RFLUSH" :
 id == P9_RREADDIR ? "READDIR" :
 "";
@@ -693,6 +694,33 @@ static void v9fs_rmkdir(P9Req *req, v9fs_qid *qid)
 v9fs_req_free(req);
 }
 
+/* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */
+static P9Req *v9fs_tunlinkat(QVirtio9P *v9p, uint32_t dirfd, const char *name,
+ uint32_t flags, uint16_t tag)
+{
+P9Req *req;
+
+uint32_t body_size = 4 + 4;
+uint16_t string_size = v9fs_string_size(name);
+
+g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+body_size += string_size;
+
+req = v9fs_req_init(v9p, body_size, P9_TUNLINKAT, tag);
+v9fs_uint32_write(req, dirfd);
+v9fs_string_write(req, name);
+v9fs_uint32_write(req, flags);
+v9fs_req_send(req);
+return req;
+}
+
+/* size[4] Runlinkat tag[2] */
+static void v9fs_runlinkat(P9Req *req)
+{
+v9fs_req_recv(req, P9_RUNLINKAT);
+v9fs_req_free(req);
+}
+
 /* basic readdir test where reply fits into a single response message */
 static void fs_readdir(void *obj, void *data, QGuestAllocator *t_alloc)
 {
@@ -1004,6 +1032,22 @@ static void do_mkdir(QVirtio9P *v9p, const char *path, 
const char *cname)
 g_free(name);
 }
 
+static void do_unlinkat(QVirtio9P *v9p, const char *atpath, const char *rpath,
+uint32_t flags)
+{
+char *const name = g_strdup(rpath);
+uint32_t fid;
+P9Req *req;
+
+fid = do_walk(v9p, atpath);
+
+req = v9fs_tunlinkat(v9p, fid, name, flags, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_runlinkat(req);
+
+g_free(name);
+}
+
 static void fs_readdir_split_128(void *obj, void *data,
  QGuestAllocator *t_alloc)
 {
@@ -1050,6 +1094,32 @@ static void fs_create_dir(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(root_path);
 }
 
+static void fs_unlinkat_dir(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+struct stat st;
+char *root_path = virtio_9p_test_path("");
+char *new_dir = virtio_9p_test_path("02");
+
+g_assert(root_path != NULL);
+
+do_attach(v9p);
+do_mkdir(v9p, "/", "02");
+
+/* check if created directory really exists now ... */
+g_assert(stat(new_dir, ) == 0);
+/* ... and is actually a directory */
+g_assert((st.st_mode & S_IFMT) == S_IFDIR);
+
+do_unlinkat(v9p, "/", "02", AT_REMOVEDIR);
+/* directory should be gone now */
+g_assert(stat(new_dir, ) != 0);
+
+g_free(new_dir);
+g_free(root_path);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1090,6 +1160,7 @@ static void register_virtio_9p_test(void)
 opts.before = assign_9p_local_driver;
 qos_add_test("local/config", "virtio-9p", pci_config,  );
 qos_add_test("local/create_dir", "virtio-9p", fs_create_dir, );
+qos_add_test("local/unlinkat_dir", "virtio-9p", fs_unlinkat_dir, );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PULL 13/13] tests/9pfs: add local Tunlinkat hard link test

2020-10-23 Thread Christian Schoenebeck
This test case uses a Tunlinkat request to remove a previously hard
linked file by using the 9pfs 'local' fs driver.

Signed-off-by: Christian Schoenebeck 
Reviewed-by: Greg Kurz 
Message-Id: 
<9bec33a7d8f006ef8f80517985d0d6ac48650d53.1603285620.git.qemu_...@crudebyte.com>
Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 30 ++
 1 file changed, 30 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 460fa49fe3..23433913bb 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -1391,6 +1391,34 @@ static void fs_hardlink_file(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(real_file);
 }
 
+static void fs_unlinkat_hardlink(void *obj, void *data,
+ QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+struct stat st_real, st_link;
+char *real_file = virtio_9p_test_path("08/real_file");
+char *hardlink_file = virtio_9p_test_path("08/hardlink_file");
+
+do_attach(v9p);
+do_mkdir(v9p, "/", "08");
+do_lcreate(v9p, "08", "real_file");
+g_assert(stat(real_file, _real) == 0);
+g_assert((st_real.st_mode & S_IFMT) == S_IFREG);
+
+do_hardlink(v9p, "08", "hardlink_file", "08/real_file");
+g_assert(stat(hardlink_file, _link) == 0);
+
+do_unlinkat(v9p, "08", "hardlink_file", 0);
+/* symlink should be gone now */
+g_assert(stat(hardlink_file, _link) != 0);
+/* and old file should still exist */
+g_assert(stat(real_file, _real) == 0);
+
+g_free(hardlink_file);
+g_free(real_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1438,6 +1466,8 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/unlinkat_symlink", "virtio-9p", fs_unlinkat_symlink,
  );
 qos_add_test("local/hardlink_file", "virtio-9p", fs_hardlink_file, );
+qos_add_test("local/unlinkat_hardlink", "virtio-9p", fs_unlinkat_hardlink,
+ );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PULL 11/13] tests/9pfs: add local Tunlinkat symlink test

2020-10-23 Thread Christian Schoenebeck
This test case uses a Tunlinkat request to remove a symlink using
the 9pfs 'local' fs driver.

Signed-off-by: Christian Schoenebeck 
Reviewed-by: Greg Kurz 
Message-Id: 

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 28 
 1 file changed, 28 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 0c11417236..33cba24b18 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -1295,6 +1295,32 @@ static void fs_symlink_file(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(real_file);
 }
 
+static void fs_unlinkat_symlink(void *obj, void *data,
+QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+struct stat st;
+char *real_file = virtio_9p_test_path("06/real_file");
+char *symlink_file = virtio_9p_test_path("06/symlink_file");
+
+do_attach(v9p);
+do_mkdir(v9p, "/", "06");
+do_lcreate(v9p, "06", "real_file");
+g_assert(stat(real_file, ) == 0);
+g_assert((st.st_mode & S_IFMT) == S_IFREG);
+
+do_symlink(v9p, "06", "symlink_file", "real_file");
+g_assert(stat(symlink_file, ) == 0);
+
+do_unlinkat(v9p, "06", "symlink_file", 0);
+/* symlink should be gone now */
+g_assert(stat(symlink_file, ) != 0);
+
+g_free(symlink_file);
+g_free(real_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1339,6 +1365,8 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/create_file", "virtio-9p", fs_create_file, );
 qos_add_test("local/unlinkat_file", "virtio-9p", fs_unlinkat_file, );
 qos_add_test("local/symlink_file", "virtio-9p", fs_symlink_file, );
+qos_add_test("local/unlinkat_symlink", "virtio-9p", fs_unlinkat_symlink,
+ );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PULL 06/13] tests/9pfs: simplify do_mkdir()

2020-10-23 Thread Christian Schoenebeck
Split out walking a directory path to a separate new utility function
do_walk() and use that function in do_mkdir().

The code difference saved this way is not much, but we'll use that new
do_walk() function in the upcoming patches, so it will avoid quite
some code duplication after all.

Signed-off-by: Christian Schoenebeck 
Reviewed-by: Greg Kurz 
Message-Id: 
<4d7275b2363f122438a443ce079cbb355285e9d6.1603285620.git.qemu_...@crudebyte.com>
Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 27 +++
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 2ea555fa04..21807037df 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -583,6 +583,23 @@ static void do_version(QVirtio9P *v9p)
 g_free(server_version);
 }
 
+/* utility function: walk to requested dir and return fid for that dir */
+static uint32_t do_walk(QVirtio9P *v9p, const char *path)
+{
+char **wnames;
+P9Req *req;
+const uint32_t fid = genfid();
+
+int nwnames = split(path, "/", );
+
+req = v9fs_twalk(v9p, 0, fid, nwnames, wnames, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rwalk(req, NULL, NULL);
+
+split_free();
+return fid;
+}
+
 static void fs_version(void *obj, void *data, QGuestAllocator *t_alloc)
 {
 alloc = t_alloc;
@@ -974,23 +991,17 @@ static void fs_flush_ignored(void *obj, void *data, 
QGuestAllocator *t_alloc)
 
 static void do_mkdir(QVirtio9P *v9p, const char *path, const char *cname)
 {
-char **wnames;
 char *const name = g_strdup(cname);
+uint32_t fid;
 P9Req *req;
-const uint32_t fid = genfid();
 
-int nwnames = split(path, "/", );
-
-req = v9fs_twalk(v9p, 0, fid, nwnames, wnames, 0);
-v9fs_req_wait_for_reply(req, NULL);
-v9fs_rwalk(req, NULL, NULL);
+fid = do_walk(v9p, path);
 
 req = v9fs_tmkdir(v9p, fid, name, 0750, 0, 0);
 v9fs_req_wait_for_reply(req, NULL);
 v9fs_rmkdir(req, NULL);
 
 g_free(name);
-split_free();
 }
 
 static void fs_readdir_split_128(void *obj, void *data,
-- 
2.20.1




[PULL 10/13] tests/9pfs: add local Tsymlink test

2020-10-23 Thread Christian Schoenebeck
This test case uses a Tsymlink 9p request to create a symbolic link using
the 9pfs 'local' fs driver.

Signed-off-by: Christian Schoenebeck 
Reviewed-by: Greg Kurz 
Message-Id: 
<84ac76937855bf441242372cc3e62df42f0a3dc4.1603285620.git.qemu_...@crudebyte.com>
Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 77 
 1 file changed, 77 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 6b74a1fd7e..0c11417236 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -259,6 +259,7 @@ static const char *rmessage_name(uint8_t id)
 id == P9_RWRITE ? "RWRITE" :
 id == P9_RMKDIR ? "RMKDIR" :
 id == P9_RLCREATE ? "RLCREATE" :
+id == P9_RSYMLINK ? "RSYMLINK" :
 id == P9_RUNLINKAT ? "RUNLINKAT" :
 id == P9_RFLUSH ? "RFLUSH" :
 id == P9_RREADDIR ? "READDIR" :
@@ -733,6 +734,39 @@ static void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, 
uint32_t *iounit)
 v9fs_req_free(req);
 }
 
+/* size[4] Tsymlink tag[2] fid[4] name[s] symtgt[s] gid[4] */
+static P9Req *v9fs_tsymlink(QVirtio9P *v9p, uint32_t fid, const char *name,
+const char *symtgt, uint32_t gid, uint16_t tag)
+{
+P9Req *req;
+
+uint32_t body_size = 4 + 4;
+uint16_t string_size = v9fs_string_size(name) + v9fs_string_size(symtgt);
+
+g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+body_size += string_size;
+
+req = v9fs_req_init(v9p, body_size, P9_TSYMLINK, tag);
+v9fs_uint32_write(req, fid);
+v9fs_string_write(req, name);
+v9fs_string_write(req, symtgt);
+v9fs_uint32_write(req, gid);
+v9fs_req_send(req);
+return req;
+}
+
+/* size[4] Rsymlink tag[2] qid[13] */
+static void v9fs_rsymlink(P9Req *req, v9fs_qid *qid)
+{
+v9fs_req_recv(req, P9_RSYMLINK);
+if (qid) {
+v9fs_memread(req, qid, 13);
+} else {
+v9fs_memskip(req, 13);
+}
+v9fs_req_free(req);
+}
+
 /* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */
 static P9Req *v9fs_tunlinkat(QVirtio9P *v9p, uint32_t dirfd, const char *name,
  uint32_t flags, uint16_t tag)
@@ -1089,6 +1123,25 @@ static uint32_t do_lcreate(QVirtio9P *v9p, const char 
*path,
 return fid;
 }
 
+/* create symlink named @a clink in directory @a path pointing to @a to */
+static void do_symlink(QVirtio9P *v9p, const char *path, const char *clink,
+   const char *to)
+{
+char *const name = g_strdup(clink);
+char *const dst = g_strdup(to);
+uint32_t fid;
+P9Req *req;
+
+fid = do_walk(v9p, path);
+
+req = v9fs_tsymlink(v9p, fid, name, dst, 0, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rsymlink(req, NULL);
+
+g_free(dst);
+g_free(name);
+}
+
 static void do_unlinkat(QVirtio9P *v9p, const char *atpath, const char *rpath,
 uint32_t flags)
 {
@@ -1219,6 +1272,29 @@ static void fs_unlinkat_file(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(new_file);
 }
 
+static void fs_symlink_file(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+struct stat st;
+char *real_file = virtio_9p_test_path("05/real_file");
+char *symlink_file = virtio_9p_test_path("05/symlink_file");
+
+do_attach(v9p);
+do_mkdir(v9p, "/", "05");
+do_lcreate(v9p, "05", "real_file");
+g_assert(stat(real_file, ) == 0);
+g_assert((st.st_mode & S_IFMT) == S_IFREG);
+
+do_symlink(v9p, "05", "symlink_file", "real_file");
+
+/* check if created link exists now */
+g_assert(stat(symlink_file, ) == 0);
+
+g_free(symlink_file);
+g_free(real_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1262,6 +1338,7 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/unlinkat_dir", "virtio-9p", fs_unlinkat_dir, );
 qos_add_test("local/create_file", "virtio-9p", fs_create_file, );
 qos_add_test("local/unlinkat_file", "virtio-9p", fs_unlinkat_file, );
+qos_add_test("local/symlink_file", "virtio-9p", fs_symlink_file, );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PULL 08/13] tests/9pfs: add local Tlcreate test

2020-10-23 Thread Christian Schoenebeck
This test case uses a Tlcreate 9p request to create a regular file inside
host's test directory.

Signed-off-by: Christian Schoenebeck 
Reviewed-by: Greg Kurz 
Message-Id: 
<269cae0c00af941a3a4ae78f1e319f93462a7eb4.1603285620.git.qemu_...@crudebyte.com>
Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 77 
 1 file changed, 77 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index abd7e44648..c030bc2a6c 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -258,6 +258,7 @@ static const char *rmessage_name(uint8_t id)
 id == P9_RLOPEN ? "RLOPEN" :
 id == P9_RWRITE ? "RWRITE" :
 id == P9_RMKDIR ? "RMKDIR" :
+id == P9_RLCREATE ? "RLCREATE" :
 id == P9_RUNLINKAT ? "RUNLINKAT" :
 id == P9_RFLUSH ? "RFLUSH" :
 id == P9_RREADDIR ? "READDIR" :
@@ -694,6 +695,44 @@ static void v9fs_rmkdir(P9Req *req, v9fs_qid *qid)
 v9fs_req_free(req);
 }
 
+/* size[4] Tlcreate tag[2] fid[4] name[s] flags[4] mode[4] gid[4] */
+static P9Req *v9fs_tlcreate(QVirtio9P *v9p, uint32_t fid, const char *name,
+uint32_t flags, uint32_t mode, uint32_t gid,
+uint16_t tag)
+{
+P9Req *req;
+
+uint32_t body_size = 4 + 4 + 4 + 4;
+uint16_t string_size = v9fs_string_size(name);
+
+g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+body_size += string_size;
+
+req = v9fs_req_init(v9p, body_size, P9_TLCREATE, tag);
+v9fs_uint32_write(req, fid);
+v9fs_string_write(req, name);
+v9fs_uint32_write(req, flags);
+v9fs_uint32_write(req, mode);
+v9fs_uint32_write(req, gid);
+v9fs_req_send(req);
+return req;
+}
+
+/* size[4] Rlcreate tag[2] qid[13] iounit[4] */
+static void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, uint32_t *iounit)
+{
+v9fs_req_recv(req, P9_RLCREATE);
+if (qid) {
+v9fs_memread(req, qid, 13);
+} else {
+v9fs_memskip(req, 13);
+}
+if (iounit) {
+v9fs_uint32_read(req, iounit);
+}
+v9fs_req_free(req);
+}
+
 /* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */
 static P9Req *v9fs_tunlinkat(QVirtio9P *v9p, uint32_t dirfd, const char *name,
  uint32_t flags, uint16_t tag)
@@ -1032,6 +1071,24 @@ static void do_mkdir(QVirtio9P *v9p, const char *path, 
const char *cname)
 g_free(name);
 }
 
+/* create a regular file with Tlcreate and return file's fid */
+static uint32_t do_lcreate(QVirtio9P *v9p, const char *path,
+   const char *cname)
+{
+char *const name = g_strdup(cname);
+uint32_t fid;
+P9Req *req;
+
+fid = do_walk(v9p, path);
+
+req = v9fs_tlcreate(v9p, fid, name, 0, 0750, 0, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rlcreate(req, NULL, NULL);
+
+g_free(name);
+return fid;
+}
+
 static void do_unlinkat(QVirtio9P *v9p, const char *atpath, const char *rpath,
 uint32_t flags)
 {
@@ -1120,6 +1177,25 @@ static void fs_unlinkat_dir(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(root_path);
 }
 
+static void fs_create_file(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+struct stat st;
+char *new_file = virtio_9p_test_path("03/1st_file");
+
+do_attach(v9p);
+do_mkdir(v9p, "/", "03");
+do_lcreate(v9p, "03", "1st_file");
+
+/* check if created file exists now ... */
+g_assert(stat(new_file, ) == 0);
+/* ... and is a regular file */
+g_assert((st.st_mode & S_IFMT) == S_IFREG);
+
+g_free(new_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1161,6 +1237,7 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/config", "virtio-9p", pci_config,  );
 qos_add_test("local/create_dir", "virtio-9p", fs_create_dir, );
 qos_add_test("local/unlinkat_dir", "virtio-9p", fs_unlinkat_dir, );
+qos_add_test("local/create_file", "virtio-9p", fs_create_file, );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PULL 09/13] tests/9pfs: add local Tunlinkat file test

2020-10-23 Thread Christian Schoenebeck
This test case uses a Tunlinkat request to remove a regular file using
the 9pfs 'local' fs driver.

Signed-off-by: Christian Schoenebeck 
Reviewed-by: Greg Kurz 
Message-Id: 
<4eabeed7f662721dd5664cb77fe36ea0aa08b1ec.1603285620.git.qemu_...@crudebyte.com>
Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 24 
 1 file changed, 24 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index c030bc2a6c..6b74a1fd7e 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -1196,6 +1196,29 @@ static void fs_create_file(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(new_file);
 }
 
+static void fs_unlinkat_file(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+struct stat st;
+char *new_file = virtio_9p_test_path("04/doa_file");
+
+do_attach(v9p);
+do_mkdir(v9p, "/", "04");
+do_lcreate(v9p, "04", "doa_file");
+
+/* check if created file exists now ... */
+g_assert(stat(new_file, ) == 0);
+/* ... and is a regular file */
+g_assert((st.st_mode & S_IFMT) == S_IFREG);
+
+do_unlinkat(v9p, "04", "doa_file", 0);
+/* file should be gone now */
+g_assert(stat(new_file, ) != 0);
+
+g_free(new_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1238,6 +1261,7 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/create_dir", "virtio-9p", fs_create_dir, );
 qos_add_test("local/unlinkat_dir", "virtio-9p", fs_unlinkat_dir, );
 qos_add_test("local/create_file", "virtio-9p", fs_create_file, );
+qos_add_test("local/unlinkat_file", "virtio-9p", fs_unlinkat_file, );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PULL 00/13] 9p queue 2020-10-23

2020-10-23 Thread Christian Schoenebeck
The following changes since commit 4c5b97bfd0dd54dc27717ae8d1cd10e14eef1430:

  Merge remote-tracking branch 
'remotes/kraxel/tags/modules-20201022-pull-request' into staging (2020-10-22 
12:33:21 +0100)

are available in the Git repository at:

  https://github.com/cschoenebeck/qemu.git tags/pull-9p-20201023

for you to fetch changes up to ee01926a11b1f9bffcd6cdec0961dd9d1882da71:

  tests/9pfs: add local Tunlinkat hard link test (2020-10-22 20:26:33 +0200)


9pfs: more tests using local fs driver

Only 9pfs test case changes this time:

* Refactor: Rename functions to make top-level test functions fs_*()
  easily distinguishable from utility test functions do_*().

* Refactor: Drop unnecessary function arguments in utility test
  functions.

* More test cases using the 9pfs 'local' filesystem driver backend,
  namely for the following 9p requests: Tunlinkat, Tlcreate, Tsymlink
  and Tlink.


Christian Schoenebeck (8):
  tests/9pfs: simplify do_mkdir()
  tests/9pfs: add local Tunlinkat directory test
  tests/9pfs: add local Tlcreate test
  tests/9pfs: add local Tunlinkat file test
  tests/9pfs: add local Tsymlink test
  tests/9pfs: add local Tunlinkat symlink test
  tests/9pfs: add local Tlink test
  tests/9pfs: add local Tunlinkat hard link test

Greg Kurz (5):
  tests/9pfs: Factor out do_version() helper
  tests/9pfs: Set alloc in fs_create_dir()
  tests/9pfs: Factor out do_attach() helper
  tests/9pfs: Turn fs_readdir_split() into a helper
  tests/9pfs: Turn fs_mkdir() into a helper

 tests/qtest/virtio-9p-test.c | 467 +++
 1 file changed, 431 insertions(+), 36 deletions(-)



Re: [PATCH v2 7/8] tests/9pfs: add local Tlink test

2020-10-22 Thread Christian Schoenebeck
On Donnerstag, 22. Oktober 2020 11:07:49 CEST Greg Kurz wrote:
> > Ok, I found the problem on the mentioned box that failed to create hard
> > links with 9p: it is libvirt auto generating AppArmor policy rules for 9p
> > export pathes, which libvirt generates with "rw" AA (AppArmor)
> > permissions. Once I manually adjusted the AA rule to "rwl", creating hard
> > links worked again.
> > 
> > I guess I'll send a patch for libvirt to change that. At least IMO
> > creating
> > hard links with 9pfs is a very basic operation and should be enabled for
> > the respective 9p export path by default.
> > 
> > Actually I think it should also include "k" which means "file locking", as
> > file locking is also a fundamental operation with 9pfs, right?
> 
> Well, I don't know exactly why libvirt is generating a strict AppArmor
> policy but I'm not that surprised. If the user can _easily_ change the
> policy to fit its needs, it's fine to have a "better safe than sorry"
> default.

Alone identifying the root cause of this is not that easy I would say. And if
it takes me quite some time to find it, then I imagine that other people would
struggle with this even more.

A large portion of software, even scripts, rely on being able to create hard
links and locking files. Right now they typically error out on guest with no
helpful error message.

So you start looking into the logs, don't find something obvious, then strace
on guest side to find the most relevant failing syscall on guest side and see
it was probably link(). Then you have to check several security layers: file
permissions on guest, file permissions on host, effective UID of qemu process.
You try creating hard links directly on host with that UID, works. Next you
check is it qemu's seccomp? Is it host's SELinux? Is it AppArmor?

Even for an experienced sysadmin I doubt it'll be a matter of minutes to
resolve this issue. Now imagine a regular user who just wants to sandbox
something on a workstation.

Looking at libvirt git log, it seems this security policy exists more or less
since day one (SHA-1 29ea8a9b64aac60251d283f74d57690e4edb5a6b, Mar 9 2014).
And I don't see an explanation that would suggest a specific reason for
exactly "rw".

I think something has to be improved here, so I'll challenge by sending a
simple libvirt patch, CCing involved authors, and seeing the feedback:

diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
index 12429278fb..ce243e304b 100644
--- a/src/security/virt-aa-helper.c
+++ b/src/security/virt-aa-helper.c
@@ -1142,7 +1142,7 @@ get_files(vahControl * ctl)
 /* We don't need to add deny rw rules for readonly mounts,
  * this can only lead to troubles when mounting / readonly.
  */
-if (vah_add_path(, fs->src->path, fs->readonly ? "R" : "rw", 
true) != 0)
+if (vah_add_path(, fs->src->path, fs->readonly ? "R" : "rwlk", 
true) != 0)
 goto cleanup;
 }
 }

Even after this change, this is not a global policy. Allowing hard links and
file locks would only be lifted for the 9p export path.

There would be other options as well of course: e.g. detecting on 9pfs side
whether AppArmor and co are enabled, and log a warning to the user a syscall
failed for that reason. But that would be much more complicated and I wonder
whether it would be worth it.

Best regards,
Christian Schoenebeck





Re: [PATCH v2 3/8] tests/9pfs: add local Tlcreate test

2020-10-22 Thread Christian Schoenebeck
On Donnerstag, 22. Oktober 2020 10:51:46 CEST Greg Kurz wrote:
> On Wed, 21 Oct 2020 14:25:33 +0200
> 
> Christian Schoenebeck  wrote:
> > This test case uses a Tlcreate 9p request to create a regular file inside
> > host's test directory.
> > 
> > Signed-off-by: Christian Schoenebeck 
> > ---
> 
> Just one remark, see below.
> 
> Reviewed-by: Greg Kurz 
> 
> >  tests/qtest/virtio-9p-test.c | 77 
> >  1 file changed, 77 insertions(+)
> > 
> > diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
> > index abd7e44648..c030bc2a6c 100644
> > --- a/tests/qtest/virtio-9p-test.c
> > +++ b/tests/qtest/virtio-9p-test.c
> > @@ -258,6 +258,7 @@ static const char *rmessage_name(uint8_t id)
> > 
> >  id == P9_RLOPEN ? "RLOPEN" :
> >  id == P9_RWRITE ? "RWRITE" :
> > 
> >  id == P9_RMKDIR ? "RMKDIR" :
> > +id == P9_RLCREATE ? "RLCREATE" :
> >  id == P9_RUNLINKAT ? "RUNLINKAT" :
> >  id == P9_RFLUSH ? "RFLUSH" :
> > 
> >  id == P9_RREADDIR ? "READDIR" :
> > @@ -694,6 +695,44 @@ static void v9fs_rmkdir(P9Req *req, v9fs_qid *qid)
> > 
> >  v9fs_req_free(req);
> >  
> >  }
> > 
> > +/* size[4] Tlcreate tag[2] fid[4] name[s] flags[4] mode[4] gid[4] */
> > +static P9Req *v9fs_tlcreate(QVirtio9P *v9p, uint32_t fid, const char
> > *name, +uint32_t flags, uint32_t mode,
> > uint32_t gid, +uint16_t tag)
> > +{
> > +P9Req *req;
> > +
> > +uint32_t body_size = 4 + 4 + 4 + 4;
> > +uint16_t string_size = v9fs_string_size(name);
> > +
> > +g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
> > +body_size += string_size;
> > +
> > +req = v9fs_req_init(v9p, body_size, P9_TLCREATE, tag);
> > +v9fs_uint32_write(req, fid);
> > +v9fs_string_write(req, name);
> > +v9fs_uint32_write(req, flags);
> > +v9fs_uint32_write(req, mode);
> > +v9fs_uint32_write(req, gid);
> > +v9fs_req_send(req);
> > +return req;
> > +}
> > +
> > +/* size[4] Rlcreate tag[2] qid[13] iounit[4] */
> > +static void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, uint32_t *iounit)
> > +{
> > +v9fs_req_recv(req, P9_RLCREATE);
> > +if (qid) {
> > +v9fs_memread(req, qid, 13);
> > +} else {
> > +v9fs_memskip(req, 13);
> > +}
> > +if (iounit) {
> > +v9fs_uint32_read(req, iounit);
> > +}
> > +v9fs_req_free(req);
> > +}
> > +
> > 
> >  /* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */
> >  static P9Req *v9fs_tunlinkat(QVirtio9P *v9p, uint32_t dirfd, const char
> >  *name,>  
> >   uint32_t flags, uint16_t tag)
> > 
> > @@ -1032,6 +1071,24 @@ static void do_mkdir(QVirtio9P *v9p, const char
> > *path, const char *cname)> 
> >  g_free(name);
> >  
> >  }
> > 
> > +/* create a regular file with Tlcreate and return file's fid */
> > +static uint32_t do_lcreate(QVirtio9P *v9p, const char *path,
> > +   const char *cname)
> > +{
> > +char *const name = g_strdup(cname);
> > +uint32_t fid;
> > +P9Req *req;
> > +
> > +fid = do_walk(v9p, path);
> > +
> > +req = v9fs_tlcreate(v9p, fid, name, 0, 0750, 0, 0);
> 
> Maybe it could make sense to make the mode a parameter of
> do_lcreate() in case someone wants to write a test case
> around that ? Same remark applies to do_mkdir() actually.
> 
> No need to change this now anyway.

Yeah, I thought about that for a moment, but decided if that's really needed 
one day, it'll be a trivial change, especially under the assumption that there 
will be probably not a lot of code using this function, even on the long-term.

Thanks for looking at these patches!

Best regards,
Christian Schoenebeck





Re: [PATCH v2 7/8] tests/9pfs: add local Tlink test

2020-10-21 Thread Christian Schoenebeck
On Mittwoch, 21. Oktober 2020 14:51:09 CEST Christian Schoenebeck wrote:
> This test case uses a Tlink request to create a hard link to a regular
> file using the 9pfs 'local' fs driver.
> 
> Signed-off-by: Christian Schoenebeck 
> ---
>  tests/qtest/virtio-9p-test.c | 71 
>  1 file changed, 71 insertions(+)
> 
> diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
> index 33cba24b18..460fa49fe3 100644
> --- a/tests/qtest/virtio-9p-test.c
> +++ b/tests/qtest/virtio-9p-test.c
> @@ -260,6 +260,7 @@ static const char *rmessage_name(uint8_t id)
>  id == P9_RMKDIR ? "RMKDIR" :
>  id == P9_RLCREATE ? "RLCREATE" :
>  id == P9_RSYMLINK ? "RSYMLINK" :
> +id == P9_RLINK ? "RLINK" :
>  id == P9_RUNLINKAT ? "RUNLINKAT" :
>  id == P9_RFLUSH ? "RFLUSH" :
>  id == P9_RREADDIR ? "READDIR" :
> @@ -767,6 +768,33 @@ static void v9fs_rsymlink(P9Req *req, v9fs_qid *qid)
>  v9fs_req_free(req);
>  }
> 
> +/* size[4] Tlink tag[2] dfid[4] fid[4] name[s] */
> +static P9Req *v9fs_tlink(QVirtio9P *v9p, uint32_t dfid, uint32_t fid,
> + const char *name, uint16_t tag)
> +{
> +P9Req *req;
> +
> +uint32_t body_size = 4 + 4;
> +uint16_t string_size = v9fs_string_size(name);
> +
> +g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
> +body_size += string_size;
> +
> +req = v9fs_req_init(v9p, body_size, P9_TLINK, tag);
> +v9fs_uint32_write(req, dfid);
> +v9fs_uint32_write(req, fid);
> +v9fs_string_write(req, name);
> +v9fs_req_send(req);
> +return req;
> +}
> +
> +/* size[4] Rlink tag[2] */
> +static void v9fs_rlink(P9Req *req)
> +{
> +v9fs_req_recv(req, P9_RLINK);
> +v9fs_req_free(req);
> +}
> +
>  /* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */
>  static P9Req *v9fs_tunlinkat(QVirtio9P *v9p, uint32_t dirfd, const char
> *name, uint32_t flags, uint16_t tag)
> @@ -1142,6 +1170,21 @@ static void do_symlink(QVirtio9P *v9p, const char
> *path, const char *clink, g_free(name);
>  }
> 
> +/* create a hard link named @a clink in directory @a path pointing to @a to
> */ +static void do_hardlink(QVirtio9P *v9p, const char *path, const char
> *clink, +const char *to)
> +{
> +uint32_t dfid, fid;
> +P9Req *req;
> +
> +dfid = do_walk(v9p, path);
> +fid = do_walk(v9p, to);
> +
> +req = v9fs_tlink(v9p, dfid, fid, clink, 0);
> +v9fs_req_wait_for_reply(req, NULL);
> +v9fs_rlink(req);
> +}
> +
>  static void do_unlinkat(QVirtio9P *v9p, const char *atpath, const char
> *rpath, uint32_t flags)
>  {
> @@ -1321,6 +1364,33 @@ static void fs_unlinkat_symlink(void *obj, void
> *data, g_free(real_file);
>  }
> 
> +static void fs_hardlink_file(void *obj, void *data, QGuestAllocator
> *t_alloc) +{
> +QVirtio9P *v9p = obj;
> +alloc = t_alloc;
> +struct stat st_real, st_link;
> +char *real_file = virtio_9p_test_path("07/real_file");
> +char *hardlink_file = virtio_9p_test_path("07/hardlink_file");
> +
> +do_attach(v9p);
> +do_mkdir(v9p, "/", "07");
> +do_lcreate(v9p, "07", "real_file");
> +g_assert(stat(real_file, _real) == 0);
> +g_assert((st_real.st_mode & S_IFMT) == S_IFREG);
> +
> +do_hardlink(v9p, "07", "hardlink_file", "07/real_file");
> +
> +/* check if link exists now ... */
> +g_assert(stat(hardlink_file, _link) == 0);
> +/* ... and it's a hard link, right? */
> +g_assert((st_link.st_mode & S_IFMT) == S_IFREG);
> +g_assert(st_link.st_dev == st_real.st_dev);
> +g_assert(st_link.st_ino == st_real.st_ino);
> +
> +g_free(hardlink_file);
> +g_free(real_file);
> +}
> +
>  static void *assign_9p_local_driver(GString *cmd_line, void *arg)
>  {
>  virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
> @@ -1367,6 +1437,7 @@ static void register_virtio_9p_test(void)
>  qos_add_test("local/symlink_file", "virtio-9p", fs_symlink_file,
> ); qos_add_test("local/unlinkat_symlink", "virtio-9p",
> fs_unlinkat_symlink, );
> +qos_add_test("local/hardlink_file", "virtio-9p", fs_hardlink_file,
> ); }
> 
>  libqos_init(register_virtio_9p_test);

Ok, I found the problem on the mentioned box that failed to create hard links 
with 9p: it is libvirt auto generating AppArmor policy rules for 9p export 
pathes, which libvirt generates with "rw" AA (AppArmor) permissions. Once I 
manually adjusted the AA rule to "rwl", creating hard links worked again.

I guess I'll send a patch for libvirt to change that. At least IMO creating 
hard links with 9pfs is a very basic operation and should be enabled for the 
respective 9p export path by default.

Actually I think it should also include "k" which means "file locking", as 
file locking is also a fundamental operation with 9pfs, right?

Best regards,
Christian Schoenebeck





[PATCH v2 6/8] tests/9pfs: add local Tunlinkat symlink test

2020-10-21 Thread Christian Schoenebeck
This test case uses a Tunlinkat request to remove a symlink using
the 9pfs 'local' fs driver.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 28 
 1 file changed, 28 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 0c11417236..33cba24b18 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -1295,6 +1295,32 @@ static void fs_symlink_file(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(real_file);
 }
 
+static void fs_unlinkat_symlink(void *obj, void *data,
+QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+struct stat st;
+char *real_file = virtio_9p_test_path("06/real_file");
+char *symlink_file = virtio_9p_test_path("06/symlink_file");
+
+do_attach(v9p);
+do_mkdir(v9p, "/", "06");
+do_lcreate(v9p, "06", "real_file");
+g_assert(stat(real_file, ) == 0);
+g_assert((st.st_mode & S_IFMT) == S_IFREG);
+
+do_symlink(v9p, "06", "symlink_file", "real_file");
+g_assert(stat(symlink_file, ) == 0);
+
+do_unlinkat(v9p, "06", "symlink_file", 0);
+/* symlink should be gone now */
+g_assert(stat(symlink_file, ) != 0);
+
+g_free(symlink_file);
+g_free(real_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1339,6 +1365,8 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/create_file", "virtio-9p", fs_create_file, );
 qos_add_test("local/unlinkat_file", "virtio-9p", fs_unlinkat_file, );
 qos_add_test("local/symlink_file", "virtio-9p", fs_symlink_file, );
+qos_add_test("local/unlinkat_symlink", "virtio-9p", fs_unlinkat_symlink,
+ );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PATCH v2 8/8] tests/9pfs: add local Tunlinkat hard link test

2020-10-21 Thread Christian Schoenebeck
This test case uses a Tunlinkat request to remove a previously hard
linked file by using the 9pfs 'local' fs driver.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 30 ++
 1 file changed, 30 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 460fa49fe3..23433913bb 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -1391,6 +1391,34 @@ static void fs_hardlink_file(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(real_file);
 }
 
+static void fs_unlinkat_hardlink(void *obj, void *data,
+ QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+struct stat st_real, st_link;
+char *real_file = virtio_9p_test_path("08/real_file");
+char *hardlink_file = virtio_9p_test_path("08/hardlink_file");
+
+do_attach(v9p);
+do_mkdir(v9p, "/", "08");
+do_lcreate(v9p, "08", "real_file");
+g_assert(stat(real_file, _real) == 0);
+g_assert((st_real.st_mode & S_IFMT) == S_IFREG);
+
+do_hardlink(v9p, "08", "hardlink_file", "08/real_file");
+g_assert(stat(hardlink_file, _link) == 0);
+
+do_unlinkat(v9p, "08", "hardlink_file", 0);
+/* symlink should be gone now */
+g_assert(stat(hardlink_file, _link) != 0);
+/* and old file should still exist */
+g_assert(stat(real_file, _real) == 0);
+
+g_free(hardlink_file);
+g_free(real_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1438,6 +1466,8 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/unlinkat_symlink", "virtio-9p", fs_unlinkat_symlink,
  );
 qos_add_test("local/hardlink_file", "virtio-9p", fs_hardlink_file, );
+qos_add_test("local/unlinkat_hardlink", "virtio-9p", fs_unlinkat_hardlink,
+ );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PATCH v2 7/8] tests/9pfs: add local Tlink test

2020-10-21 Thread Christian Schoenebeck
This test case uses a Tlink request to create a hard link to a regular
file using the 9pfs 'local' fs driver.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 71 
 1 file changed, 71 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 33cba24b18..460fa49fe3 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -260,6 +260,7 @@ static const char *rmessage_name(uint8_t id)
 id == P9_RMKDIR ? "RMKDIR" :
 id == P9_RLCREATE ? "RLCREATE" :
 id == P9_RSYMLINK ? "RSYMLINK" :
+id == P9_RLINK ? "RLINK" :
 id == P9_RUNLINKAT ? "RUNLINKAT" :
 id == P9_RFLUSH ? "RFLUSH" :
 id == P9_RREADDIR ? "READDIR" :
@@ -767,6 +768,33 @@ static void v9fs_rsymlink(P9Req *req, v9fs_qid *qid)
 v9fs_req_free(req);
 }
 
+/* size[4] Tlink tag[2] dfid[4] fid[4] name[s] */
+static P9Req *v9fs_tlink(QVirtio9P *v9p, uint32_t dfid, uint32_t fid,
+ const char *name, uint16_t tag)
+{
+P9Req *req;
+
+uint32_t body_size = 4 + 4;
+uint16_t string_size = v9fs_string_size(name);
+
+g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+body_size += string_size;
+
+req = v9fs_req_init(v9p, body_size, P9_TLINK, tag);
+v9fs_uint32_write(req, dfid);
+v9fs_uint32_write(req, fid);
+v9fs_string_write(req, name);
+v9fs_req_send(req);
+return req;
+}
+
+/* size[4] Rlink tag[2] */
+static void v9fs_rlink(P9Req *req)
+{
+v9fs_req_recv(req, P9_RLINK);
+v9fs_req_free(req);
+}
+
 /* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */
 static P9Req *v9fs_tunlinkat(QVirtio9P *v9p, uint32_t dirfd, const char *name,
  uint32_t flags, uint16_t tag)
@@ -1142,6 +1170,21 @@ static void do_symlink(QVirtio9P *v9p, const char *path, 
const char *clink,
 g_free(name);
 }
 
+/* create a hard link named @a clink in directory @a path pointing to @a to */
+static void do_hardlink(QVirtio9P *v9p, const char *path, const char *clink,
+const char *to)
+{
+uint32_t dfid, fid;
+P9Req *req;
+
+dfid = do_walk(v9p, path);
+fid = do_walk(v9p, to);
+
+req = v9fs_tlink(v9p, dfid, fid, clink, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rlink(req);
+}
+
 static void do_unlinkat(QVirtio9P *v9p, const char *atpath, const char *rpath,
 uint32_t flags)
 {
@@ -1321,6 +1364,33 @@ static void fs_unlinkat_symlink(void *obj, void *data,
 g_free(real_file);
 }
 
+static void fs_hardlink_file(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+struct stat st_real, st_link;
+char *real_file = virtio_9p_test_path("07/real_file");
+char *hardlink_file = virtio_9p_test_path("07/hardlink_file");
+
+do_attach(v9p);
+do_mkdir(v9p, "/", "07");
+do_lcreate(v9p, "07", "real_file");
+g_assert(stat(real_file, _real) == 0);
+g_assert((st_real.st_mode & S_IFMT) == S_IFREG);
+
+do_hardlink(v9p, "07", "hardlink_file", "07/real_file");
+
+/* check if link exists now ... */
+g_assert(stat(hardlink_file, _link) == 0);
+/* ... and it's a hard link, right? */
+g_assert((st_link.st_mode & S_IFMT) == S_IFREG);
+g_assert(st_link.st_dev == st_real.st_dev);
+g_assert(st_link.st_ino == st_real.st_ino);
+
+g_free(hardlink_file);
+g_free(real_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1367,6 +1437,7 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/symlink_file", "virtio-9p", fs_symlink_file, );
 qos_add_test("local/unlinkat_symlink", "virtio-9p", fs_unlinkat_symlink,
  );
+qos_add_test("local/hardlink_file", "virtio-9p", fs_hardlink_file, );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PATCH v2 3/8] tests/9pfs: add local Tlcreate test

2020-10-21 Thread Christian Schoenebeck
This test case uses a Tlcreate 9p request to create a regular file inside
host's test directory.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 77 
 1 file changed, 77 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index abd7e44648..c030bc2a6c 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -258,6 +258,7 @@ static const char *rmessage_name(uint8_t id)
 id == P9_RLOPEN ? "RLOPEN" :
 id == P9_RWRITE ? "RWRITE" :
 id == P9_RMKDIR ? "RMKDIR" :
+id == P9_RLCREATE ? "RLCREATE" :
 id == P9_RUNLINKAT ? "RUNLINKAT" :
 id == P9_RFLUSH ? "RFLUSH" :
 id == P9_RREADDIR ? "READDIR" :
@@ -694,6 +695,44 @@ static void v9fs_rmkdir(P9Req *req, v9fs_qid *qid)
 v9fs_req_free(req);
 }
 
+/* size[4] Tlcreate tag[2] fid[4] name[s] flags[4] mode[4] gid[4] */
+static P9Req *v9fs_tlcreate(QVirtio9P *v9p, uint32_t fid, const char *name,
+uint32_t flags, uint32_t mode, uint32_t gid,
+uint16_t tag)
+{
+P9Req *req;
+
+uint32_t body_size = 4 + 4 + 4 + 4;
+uint16_t string_size = v9fs_string_size(name);
+
+g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+body_size += string_size;
+
+req = v9fs_req_init(v9p, body_size, P9_TLCREATE, tag);
+v9fs_uint32_write(req, fid);
+v9fs_string_write(req, name);
+v9fs_uint32_write(req, flags);
+v9fs_uint32_write(req, mode);
+v9fs_uint32_write(req, gid);
+v9fs_req_send(req);
+return req;
+}
+
+/* size[4] Rlcreate tag[2] qid[13] iounit[4] */
+static void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, uint32_t *iounit)
+{
+v9fs_req_recv(req, P9_RLCREATE);
+if (qid) {
+v9fs_memread(req, qid, 13);
+} else {
+v9fs_memskip(req, 13);
+}
+if (iounit) {
+v9fs_uint32_read(req, iounit);
+}
+v9fs_req_free(req);
+}
+
 /* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */
 static P9Req *v9fs_tunlinkat(QVirtio9P *v9p, uint32_t dirfd, const char *name,
  uint32_t flags, uint16_t tag)
@@ -1032,6 +1071,24 @@ static void do_mkdir(QVirtio9P *v9p, const char *path, 
const char *cname)
 g_free(name);
 }
 
+/* create a regular file with Tlcreate and return file's fid */
+static uint32_t do_lcreate(QVirtio9P *v9p, const char *path,
+   const char *cname)
+{
+char *const name = g_strdup(cname);
+uint32_t fid;
+P9Req *req;
+
+fid = do_walk(v9p, path);
+
+req = v9fs_tlcreate(v9p, fid, name, 0, 0750, 0, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rlcreate(req, NULL, NULL);
+
+g_free(name);
+return fid;
+}
+
 static void do_unlinkat(QVirtio9P *v9p, const char *atpath, const char *rpath,
 uint32_t flags)
 {
@@ -1120,6 +1177,25 @@ static void fs_unlinkat_dir(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(root_path);
 }
 
+static void fs_create_file(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+struct stat st;
+char *new_file = virtio_9p_test_path("03/1st_file");
+
+do_attach(v9p);
+do_mkdir(v9p, "/", "03");
+do_lcreate(v9p, "03", "1st_file");
+
+/* check if created file exists now ... */
+g_assert(stat(new_file, ) == 0);
+/* ... and is a regular file */
+g_assert((st.st_mode & S_IFMT) == S_IFREG);
+
+g_free(new_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1161,6 +1237,7 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/config", "virtio-9p", pci_config,  );
 qos_add_test("local/create_dir", "virtio-9p", fs_create_dir, );
 qos_add_test("local/unlinkat_dir", "virtio-9p", fs_unlinkat_dir, );
+qos_add_test("local/create_file", "virtio-9p", fs_create_file, );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PATCH v2 1/8] tests/9pfs: simplify do_mkdir()

2020-10-21 Thread Christian Schoenebeck
Split out walking a directory path to a separate new utility function
do_walk() and use that function in do_mkdir().

The code difference saved this way is not much, but we'll use that new
do_walk() function in the upcoming patches, so it will avoid quite
some code duplication after all.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 27 +++
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 2ea555fa04..21807037df 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -583,6 +583,23 @@ static void do_version(QVirtio9P *v9p)
 g_free(server_version);
 }
 
+/* utility function: walk to requested dir and return fid for that dir */
+static uint32_t do_walk(QVirtio9P *v9p, const char *path)
+{
+char **wnames;
+P9Req *req;
+const uint32_t fid = genfid();
+
+int nwnames = split(path, "/", );
+
+req = v9fs_twalk(v9p, 0, fid, nwnames, wnames, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rwalk(req, NULL, NULL);
+
+split_free();
+return fid;
+}
+
 static void fs_version(void *obj, void *data, QGuestAllocator *t_alloc)
 {
 alloc = t_alloc;
@@ -974,23 +991,17 @@ static void fs_flush_ignored(void *obj, void *data, 
QGuestAllocator *t_alloc)
 
 static void do_mkdir(QVirtio9P *v9p, const char *path, const char *cname)
 {
-char **wnames;
 char *const name = g_strdup(cname);
+uint32_t fid;
 P9Req *req;
-const uint32_t fid = genfid();
 
-int nwnames = split(path, "/", );
-
-req = v9fs_twalk(v9p, 0, fid, nwnames, wnames, 0);
-v9fs_req_wait_for_reply(req, NULL);
-v9fs_rwalk(req, NULL, NULL);
+fid = do_walk(v9p, path);
 
 req = v9fs_tmkdir(v9p, fid, name, 0750, 0, 0);
 v9fs_req_wait_for_reply(req, NULL);
 v9fs_rmkdir(req, NULL);
 
 g_free(name);
-split_free();
 }
 
 static void fs_readdir_split_128(void *obj, void *data,
-- 
2.20.1




[PATCH v2 5/8] tests/9pfs: add local Tsymlink test

2020-10-21 Thread Christian Schoenebeck
This test case uses a Tsymlink 9p request to create a symbolic link using
the 9pfs 'local' fs driver.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 77 
 1 file changed, 77 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 6b74a1fd7e..0c11417236 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -259,6 +259,7 @@ static const char *rmessage_name(uint8_t id)
 id == P9_RWRITE ? "RWRITE" :
 id == P9_RMKDIR ? "RMKDIR" :
 id == P9_RLCREATE ? "RLCREATE" :
+id == P9_RSYMLINK ? "RSYMLINK" :
 id == P9_RUNLINKAT ? "RUNLINKAT" :
 id == P9_RFLUSH ? "RFLUSH" :
 id == P9_RREADDIR ? "READDIR" :
@@ -733,6 +734,39 @@ static void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, 
uint32_t *iounit)
 v9fs_req_free(req);
 }
 
+/* size[4] Tsymlink tag[2] fid[4] name[s] symtgt[s] gid[4] */
+static P9Req *v9fs_tsymlink(QVirtio9P *v9p, uint32_t fid, const char *name,
+const char *symtgt, uint32_t gid, uint16_t tag)
+{
+P9Req *req;
+
+uint32_t body_size = 4 + 4;
+uint16_t string_size = v9fs_string_size(name) + v9fs_string_size(symtgt);
+
+g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+body_size += string_size;
+
+req = v9fs_req_init(v9p, body_size, P9_TSYMLINK, tag);
+v9fs_uint32_write(req, fid);
+v9fs_string_write(req, name);
+v9fs_string_write(req, symtgt);
+v9fs_uint32_write(req, gid);
+v9fs_req_send(req);
+return req;
+}
+
+/* size[4] Rsymlink tag[2] qid[13] */
+static void v9fs_rsymlink(P9Req *req, v9fs_qid *qid)
+{
+v9fs_req_recv(req, P9_RSYMLINK);
+if (qid) {
+v9fs_memread(req, qid, 13);
+} else {
+v9fs_memskip(req, 13);
+}
+v9fs_req_free(req);
+}
+
 /* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */
 static P9Req *v9fs_tunlinkat(QVirtio9P *v9p, uint32_t dirfd, const char *name,
  uint32_t flags, uint16_t tag)
@@ -1089,6 +1123,25 @@ static uint32_t do_lcreate(QVirtio9P *v9p, const char 
*path,
 return fid;
 }
 
+/* create symlink named @a clink in directory @a path pointing to @a to */
+static void do_symlink(QVirtio9P *v9p, const char *path, const char *clink,
+   const char *to)
+{
+char *const name = g_strdup(clink);
+char *const dst = g_strdup(to);
+uint32_t fid;
+P9Req *req;
+
+fid = do_walk(v9p, path);
+
+req = v9fs_tsymlink(v9p, fid, name, dst, 0, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rsymlink(req, NULL);
+
+g_free(dst);
+g_free(name);
+}
+
 static void do_unlinkat(QVirtio9P *v9p, const char *atpath, const char *rpath,
 uint32_t flags)
 {
@@ -1219,6 +1272,29 @@ static void fs_unlinkat_file(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(new_file);
 }
 
+static void fs_symlink_file(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+struct stat st;
+char *real_file = virtio_9p_test_path("05/real_file");
+char *symlink_file = virtio_9p_test_path("05/symlink_file");
+
+do_attach(v9p);
+do_mkdir(v9p, "/", "05");
+do_lcreate(v9p, "05", "real_file");
+g_assert(stat(real_file, ) == 0);
+g_assert((st.st_mode & S_IFMT) == S_IFREG);
+
+do_symlink(v9p, "05", "symlink_file", "real_file");
+
+/* check if created link exists now */
+g_assert(stat(symlink_file, ) == 0);
+
+g_free(symlink_file);
+g_free(real_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1262,6 +1338,7 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/unlinkat_dir", "virtio-9p", fs_unlinkat_dir, );
 qos_add_test("local/create_file", "virtio-9p", fs_create_file, );
 qos_add_test("local/unlinkat_file", "virtio-9p", fs_unlinkat_file, );
+qos_add_test("local/symlink_file", "virtio-9p", fs_symlink_file, );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PATCH v2 2/8] tests/9pfs: add local Tunlinkat directory test

2020-10-21 Thread Christian Schoenebeck
This test case uses a Tunlinkat 9p request with flag AT_REMOVEDIR
(see 'man 2 unlink') to remove a directory from host's test directory.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 71 
 1 file changed, 71 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 21807037df..abd7e44648 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -258,6 +258,7 @@ static const char *rmessage_name(uint8_t id)
 id == P9_RLOPEN ? "RLOPEN" :
 id == P9_RWRITE ? "RWRITE" :
 id == P9_RMKDIR ? "RMKDIR" :
+id == P9_RUNLINKAT ? "RUNLINKAT" :
 id == P9_RFLUSH ? "RFLUSH" :
 id == P9_RREADDIR ? "READDIR" :
 "";
@@ -693,6 +694,33 @@ static void v9fs_rmkdir(P9Req *req, v9fs_qid *qid)
 v9fs_req_free(req);
 }
 
+/* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */
+static P9Req *v9fs_tunlinkat(QVirtio9P *v9p, uint32_t dirfd, const char *name,
+ uint32_t flags, uint16_t tag)
+{
+P9Req *req;
+
+uint32_t body_size = 4 + 4;
+uint16_t string_size = v9fs_string_size(name);
+
+g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+body_size += string_size;
+
+req = v9fs_req_init(v9p, body_size, P9_TUNLINKAT, tag);
+v9fs_uint32_write(req, dirfd);
+v9fs_string_write(req, name);
+v9fs_uint32_write(req, flags);
+v9fs_req_send(req);
+return req;
+}
+
+/* size[4] Runlinkat tag[2] */
+static void v9fs_runlinkat(P9Req *req)
+{
+v9fs_req_recv(req, P9_RUNLINKAT);
+v9fs_req_free(req);
+}
+
 /* basic readdir test where reply fits into a single response message */
 static void fs_readdir(void *obj, void *data, QGuestAllocator *t_alloc)
 {
@@ -1004,6 +1032,22 @@ static void do_mkdir(QVirtio9P *v9p, const char *path, 
const char *cname)
 g_free(name);
 }
 
+static void do_unlinkat(QVirtio9P *v9p, const char *atpath, const char *rpath,
+uint32_t flags)
+{
+char *const name = g_strdup(rpath);
+uint32_t fid;
+P9Req *req;
+
+fid = do_walk(v9p, atpath);
+
+req = v9fs_tunlinkat(v9p, fid, name, flags, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_runlinkat(req);
+
+g_free(name);
+}
+
 static void fs_readdir_split_128(void *obj, void *data,
  QGuestAllocator *t_alloc)
 {
@@ -1050,6 +1094,32 @@ static void fs_create_dir(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(root_path);
 }
 
+static void fs_unlinkat_dir(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+struct stat st;
+char *root_path = virtio_9p_test_path("");
+char *new_dir = virtio_9p_test_path("02");
+
+g_assert(root_path != NULL);
+
+do_attach(v9p);
+do_mkdir(v9p, "/", "02");
+
+/* check if created directory really exists now ... */
+g_assert(stat(new_dir, ) == 0);
+/* ... and is actually a directory */
+g_assert((st.st_mode & S_IFMT) == S_IFDIR);
+
+do_unlinkat(v9p, "/", "02", AT_REMOVEDIR);
+/* directory should be gone now */
+g_assert(stat(new_dir, ) != 0);
+
+g_free(new_dir);
+g_free(root_path);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1090,6 +1160,7 @@ static void register_virtio_9p_test(void)
 opts.before = assign_9p_local_driver;
 qos_add_test("local/config", "virtio-9p", pci_config,  );
 qos_add_test("local/create_dir", "virtio-9p", fs_create_dir, );
+qos_add_test("local/unlinkat_dir", "virtio-9p", fs_unlinkat_dir, );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PATCH v2 4/8] tests/9pfs: add local Tunlinkat file test

2020-10-21 Thread Christian Schoenebeck
This test case uses a Tunlinkat request to remove a regular file using
the 9pfs 'local' fs driver.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 24 
 1 file changed, 24 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index c030bc2a6c..6b74a1fd7e 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -1196,6 +1196,29 @@ static void fs_create_file(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(new_file);
 }
 
+static void fs_unlinkat_file(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+struct stat st;
+char *new_file = virtio_9p_test_path("04/doa_file");
+
+do_attach(v9p);
+do_mkdir(v9p, "/", "04");
+do_lcreate(v9p, "04", "doa_file");
+
+/* check if created file exists now ... */
+g_assert(stat(new_file, ) == 0);
+/* ... and is a regular file */
+g_assert((st.st_mode & S_IFMT) == S_IFREG);
+
+do_unlinkat(v9p, "04", "doa_file", 0);
+/* file should be gone now */
+g_assert(stat(new_file, ) != 0);
+
+g_free(new_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1238,6 +1261,7 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/create_dir", "virtio-9p", fs_create_dir, );
 qos_add_test("local/unlinkat_dir", "virtio-9p", fs_unlinkat_dir, );
 qos_add_test("local/create_file", "virtio-9p", fs_create_file, );
+qos_add_test("local/unlinkat_file", "virtio-9p", fs_unlinkat_file, );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PATCH v2 0/8] 9pfs: more local tests

2020-10-21 Thread Christian Schoenebeck
Just a bunch of more test cases using the 9pfs 'local' fs driver backend,
namely for these 9p requests:

  * Tunlinkat, Tlcreate, Tsymlink and Tlink.

v1->v2:

  * Rebased on latest 9p.next queue HEAD.

  * Use do_*() as new naming convention for utility functions.

  * Drop unnecessary arguments of utility functions.

  * Always do 'alloc = t_alloc;' in toplevel test functions.

  * Split out do_hardlink() as utility function [patch 6].

Christian Schoenebeck (8):
  tests/9pfs: simplify do_mkdir()
  tests/9pfs: add local Tunlinkat directory test
  tests/9pfs: add local Tlcreate test
  tests/9pfs: add local Tunlinkat file test
  tests/9pfs: add local Tsymlink test
  tests/9pfs: add local Tunlinkat symlink test
  tests/9pfs: add local Tlink test
  tests/9pfs: add local Tunlinkat hard link test

 tests/qtest/virtio-9p-test.c | 405 ++-
 1 file changed, 397 insertions(+), 8 deletions(-)

-- 
2.20.1




Re: [PULL v3 2/6] tests/9pfs: change qtest name prefix to synth

2020-10-21 Thread Christian Schoenebeck
On Mittwoch, 21. Oktober 2020 08:15:55 CEST Philippe Mathieu-Daudé wrote:
> Hi Cristian,
> 
> On 10/20/20 1:54 PM, Christian Schoenebeck wrote:
> > On Dienstag, 20. Oktober 2020 12:00:57 CEST Greg Kurz wrote:
> >> On Tue, 20 Oct 2020 11:43:18 +0200
> >> 
> >> Christian Schoenebeck  wrote:
> >>> On Dienstag, 20. Oktober 2020 09:36:10 CEST Philippe Mathieu-Daudé 
wrote:
> >>>> On 10/8/20 8:34 PM, Christian Schoenebeck wrote:
> >>>>> All existing 9pfs test cases are using the 'synth' fs driver so far,
> >>>>> which
> >>>>> means they are not accessing real files, but a purely simulated (in
> >>>>> RAM
> >>>>> only) file system.
> >>>>> 
> >>>>> Let's make this clear by changing the prefix of the individual qtest
> >>>>> case
> >>>>> names from 'fs/' to 'synth/'. That way they'll be easily
> >>>>> distinguishable
> >>>>> from upcoming new 9pfs test cases supposed to be using a different fs
> >>>>> driver.
> >>>>> 
> >>>>> Signed-off-by: Christian Schoenebeck 
> >>>>> Message-Id:
> >>>>>  >>>>> eby
> >>>>> te.com> Signed-off-by: Christian Schoenebeck 
> >>>> 
> >>>> Harmless, but don't need to sign twice ;)
> >>> 
> >>> Ah, I thought that's the common way, as Greg's PRs contained 2 SOBs as
> >>> well, i.e. I thought this was intended to outline the patch author and
> >>> submaintainer were the same person.
> >>> 
> >>> BTW I actually did not explicitly add the 2nd SOB. It was rather added
> >>> by
> >>> the patchwork client automatically. So maybe it should be fixed in the
> >>> client to detect an already existing SOB line? Or am missing something
> >>> here?
> >> 
> >> Yeah this is the reason why my sob appears twice on patches authored by
> >> me, and since this is harmless I never really investigated how to fix
> >> pwclient :)
> > 
> > Well, I would usually offer my 'I can look at it' at this point, but I am
> > reluctant this time as I assume it will end up as my recently suggested
> > libqos patches where I did not get any response from the officially
> > assigned maintainers; not even a simple 'nack'.
> 
> I was just watching your contributions and suggested an improvement
> because something in your new workflow seems mis-configured (other
> maintainers don't have this problem). I didn't asked you to fix a
> bug in a different tool. I apologize if I was unclear and you
> understood it this way.

You actually did not raise that expectation to me Philippe, so definitely no 
need to apologize. But I appreciate it!

Correct me if I'm wrong, but AFAICS I'm actually not the only one being 
affected by this double-SOB issue. A short glimpse at the logs and I see for 
instance 3e7e134d827790c3714cae1d5b8aff8612000116 having it as well.

So I guess everyone having the following two options enabled in pwclientrc:

msgid=on
signoff=on

will have that issue.

> Regarding your issue with a different series, I suppose you already
> read:
> https://wiki.qemu.org/Contribute/SubmitAPatch#If_your_patch_seems_to_have_be
> en_ignored and
> https://wiki.qemu.org/Contribute/SubmitAPatch#Return_the_favor
> 
> You'll see that maintenance can be very time consuming, and we are
> overcrowded from time to time when there is rush. I doubt maintainers
> are ignoring your patches, as most of them try to do their best.
> You might help them by reviewing patches for them, so they have time
> to process your series.

Yes, I am aware of these. And once I got used to a new code base tree I also 
look at other ones' patches there.

I've recently been thinking whether it would be possible for QEMU 
submaintainers to make use of patchwork's status feature:
https://www.mail-archive.com/qemu-devel@nongnu.org/msg737917.html

Maybe that could help preventing patches of high traffic components ending up 
unseen.

Best regards,
Christian Schoenebeck





Re: [PATCH 1/8] tests/9pfs: simplify fs_mkdir()

2020-10-20 Thread Christian Schoenebeck
On Dienstag, 20. Oktober 2020 20:03:09 CEST Greg Kurz wrote:
> On Tue, 20 Oct 2020 15:43:21 +0200
> 
> Christian Schoenebeck  wrote:
> > On Dienstag, 20. Oktober 2020 15:35:36 CEST Greg Kurz wrote:
> > > On Tue, 20 Oct 2020 01:13:23 +0200
> > > 
> > > Christian Schoenebeck  wrote:
> > > > Split out walking a directory path to a separate new utility function
> > > > fs_walk_fid() and use that function in fs_mkdir().
> > > > 
> > > > The code difference saved this way is not much, but we'll use that new
> > > > fs_walk_fid() function in the upcoming patches, so it will avoid quite
> > > > some code duplication after all.
> > > > 
> > > > Signed-off-by: Christian Schoenebeck 
> > > > ---
> > > > 
> > > >  tests/qtest/virtio-9p-test.c | 23 ++-
> > > >  1 file changed, 18 insertions(+), 5 deletions(-)
> > > > 
> > > > diff --git a/tests/qtest/virtio-9p-test.c
> > > > b/tests/qtest/virtio-9p-test.c
> > > > index c15908f27b..dc724bbb1e 100644
> > > > --- a/tests/qtest/virtio-9p-test.c
> > > > +++ b/tests/qtest/virtio-9p-test.c
> > > > @@ -967,13 +967,12 @@ static void fs_flush_ignored(void *obj, void
> > > > *data,
> > > > QGuestAllocator *t_alloc)>
> > > > 
> > > >  g_free(wnames[0]);
> > > >  
> > > >  }
> > > > 
> > > > -static void fs_mkdir(void *obj, void *data, QGuestAllocator *t_alloc,
> > > > - const char *path, const char *cname)
> > > > +/* utility function: walk to requested dir and return fid for that
> > > > dir */
> > > > +static uint32_t fs_walk_fid(void *obj, void *data, QGuestAllocator
> > > > *t_alloc, +const char *path)
> > > > 
> > > >  {
> > > 
> > > Since fs_walk_fid() is a helper function, ie. not passed to
> > > qos_add_test(),
> > > any reason to keep the "void *obj, void *data, QGuestAllocator *t_alloc"
> > > based signature ? data and t_alloc aren't used at all and it seems that
> > > the
> > > function should rather take a QVirtio9P * directly instead of casting
> > > from
> > > a void *.
> > > 
> > > Something like:
> > > 
> > > static uint32_t fs_walk_fid(QVirtio9P *v9p, const char *path)
> > > {
> > > ...
> > > }
> > > 
> > > 
> > > Same remark applies to fs_mkdir() which isn't a top level test function
> > > either BTW (sorry for not having spotted this earlier).
> > 
> > Good point. Typical case of being copy & waste induced. I'll change that.
> 
> Since this also affects other patches in this series and this might
> have a substantial impact, I'll wait for v2 to review if you don't
> mind.

Sure!

There is probably no need to hurry anyway; since these are just test case 
changes, I think it will also be fine if I send the PR during freeze.

You never had any issue with 9p hard links, right? I'm still investigating 
this in parallel. I already can rule out QEMU's sandbox (seccomp) feature, 
even after having disabled the latter that mentioned box is failing any 
link()/linkat() calls. Maybe it's a SELinux issue ...

Best regards,
Christian Schoenebeck





Re: [PATCH v2 0/5] tests/9pfs: Code refactoring

2020-10-20 Thread Christian Schoenebeck
On Dienstag, 20. Oktober 2020 18:09:07 CEST Greg Kurz wrote:
> Some code refactoring to have a clear distinction between top level
> test functions and helper functions.
> 
> v2: - use "do_" prefix instead of "do_fs_"
> 
> ---
> 
> Greg Kurz (5):
>   tests/9pfs: Factor out do_version() helper
>   tests/9pfs: Turn fs_readdir_split() into a helper
>   tests/9pfs: Set alloc in fs_create_dir()
>   tests/9pfs: Factor out do_attach() helper
>   tests/9pfs: Turn fs_mkdir() into a helper
> 
> 
>  tests/qtest/virtio-9p-test.c |   62
> +++--- 1 file changed, 34
> insertions(+), 28 deletions(-)
> 
> --
> Greg

Queued on 9p.next:
https://github.com/cschoenebeck/qemu/commits/9p.next

I just tweaked the order of the patches to prevent intermediate compiler 
errors.

Thanks!

Best regards,
Christian Schoenebeck





Re: [PATCH 1/5] tests/9pfs: Factor out do_fs_version() helper

2020-10-20 Thread Christian Schoenebeck
On Dienstag, 20. Oktober 2020 17:41:56 CEST Greg Kurz wrote:
> On Tue, 20 Oct 2020 17:34:05 +0200
> 
> Christian Schoenebeck  wrote:
> > On Dienstag, 20. Oktober 2020 17:11:05 CEST Greg Kurz wrote:
> > > fs_version() is a top level test function. Factor out the sugar
> > > to a separate helper instead of hijacking it in other tests.
> > > 
> > > Signed-off-by: Greg Kurz 
> > > ---
> > > 
> > >  tests/qtest/virtio-9p-test.c |   14 +-
> > >  1 file changed, 9 insertions(+), 5 deletions(-)
> > > 
> > > diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
> > > index c15908f27b3d..63f91aaf77e6 100644
> > > --- a/tests/qtest/virtio-9p-test.c
> > > +++ b/tests/qtest/virtio-9p-test.c
> > > @@ -567,10 +567,8 @@ static void v9fs_rflush(P9Req *req)
> > > 
> > >  v9fs_req_free(req);
> > >  
> > >  }
> > > 
> > > -static void fs_version(void *obj, void *data, QGuestAllocator *t_alloc)
> > > +static void do_fs_version(QVirtio9P *v9p)
> > > 
> > >  {
> > > 
> > > -QVirtio9P *v9p = obj;
> > > -alloc = t_alloc;
> > > 
> > >  const char *version = "9P2000.L";
> > >  uint16_t server_len;
> > >  char *server_version;
> > > 
> > > @@ -585,13 +583,19 @@ static void fs_version(void *obj, void *data,
> > > QGuestAllocator *t_alloc) g_free(server_version);
> > > 
> > >  }
> > 
> > So the naming convention from now on shall be do_fs_*() for non-toplevel
> > functions there. Not that I care too much about the precise prefix, but
> > how
> > about just do_*() for them instead?
> 
> I've prepended "do_" to the existing names by pure laziness but I'm
> fine with any prefix or naming convention actually.
> 
> So just tell me what you prefer and I'll send a v2.

It's really just more pleasant for the eye to have the prefix a bit shorter. 
So use do_*() or any other kind of xx_*() or xxx_*() prefix that comes to your 
mind. It will be fine with me.

Thanks Greg!

Best regards,
Christian Schoenebeck





Re: [PATCH 1/5] tests/9pfs: Factor out do_fs_version() helper

2020-10-20 Thread Christian Schoenebeck
On Dienstag, 20. Oktober 2020 17:11:05 CEST Greg Kurz wrote:
> fs_version() is a top level test function. Factor out the sugar
> to a separate helper instead of hijacking it in other tests.
> 
> Signed-off-by: Greg Kurz 
> ---
>  tests/qtest/virtio-9p-test.c |   14 +-
>  1 file changed, 9 insertions(+), 5 deletions(-)
> 
> diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
> index c15908f27b3d..63f91aaf77e6 100644
> --- a/tests/qtest/virtio-9p-test.c
> +++ b/tests/qtest/virtio-9p-test.c
> @@ -567,10 +567,8 @@ static void v9fs_rflush(P9Req *req)
>  v9fs_req_free(req);
>  }
> 
> -static void fs_version(void *obj, void *data, QGuestAllocator *t_alloc)
> +static void do_fs_version(QVirtio9P *v9p)
>  {
> -QVirtio9P *v9p = obj;
> -alloc = t_alloc;
>  const char *version = "9P2000.L";
>  uint16_t server_len;
>  char *server_version;
> @@ -585,13 +583,19 @@ static void fs_version(void *obj, void *data,
> QGuestAllocator *t_alloc) g_free(server_version);
>  }

So the naming convention from now on shall be do_fs_*() for non-toplevel 
functions there. Not that I care too much about the precise prefix, but how 
about just do_*() for them instead?

Except of that, your patches look fine to me.

Best regards,
Christian Schoenebeck





Re: [PATCH 1/8] tests/9pfs: simplify fs_mkdir()

2020-10-20 Thread Christian Schoenebeck
On Dienstag, 20. Oktober 2020 15:35:36 CEST Greg Kurz wrote:
> On Tue, 20 Oct 2020 01:13:23 +0200
> 
> Christian Schoenebeck  wrote:
> > Split out walking a directory path to a separate new utility function
> > fs_walk_fid() and use that function in fs_mkdir().
> > 
> > The code difference saved this way is not much, but we'll use that new
> > fs_walk_fid() function in the upcoming patches, so it will avoid quite
> > some code duplication after all.
> > 
> > Signed-off-by: Christian Schoenebeck 
> > ---
> > 
> >  tests/qtest/virtio-9p-test.c | 23 ++-
> >  1 file changed, 18 insertions(+), 5 deletions(-)
> > 
> > diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
> > index c15908f27b..dc724bbb1e 100644
> > --- a/tests/qtest/virtio-9p-test.c
> > +++ b/tests/qtest/virtio-9p-test.c
> > @@ -967,13 +967,12 @@ static void fs_flush_ignored(void *obj, void *data,
> > QGuestAllocator *t_alloc)> 
> >  g_free(wnames[0]);
> >  
> >  }
> > 
> > -static void fs_mkdir(void *obj, void *data, QGuestAllocator *t_alloc,
> > - const char *path, const char *cname)
> > +/* utility function: walk to requested dir and return fid for that dir */
> > +static uint32_t fs_walk_fid(void *obj, void *data, QGuestAllocator
> > *t_alloc, +const char *path)
> > 
> >  {
> 
> Since fs_walk_fid() is a helper function, ie. not passed to qos_add_test(),
> any reason to keep the "void *obj, void *data, QGuestAllocator *t_alloc"
> based signature ? data and t_alloc aren't used at all and it seems that the
> function should rather take a QVirtio9P * directly instead of casting from
> a void *.
> 
> Something like:
> 
> static uint32_t fs_walk_fid(QVirtio9P *v9p, const char *path)
> {
> ...
> }
> 
> 
> Same remark applies to fs_mkdir() which isn't a top level test function
> either BTW (sorry for not having spotted this earlier).

Good point. Typical case of being copy & waste induced. I'll change that.

Best regards,
Christian Schoenebeck





Re: [PULL v3 2/6] tests/9pfs: change qtest name prefix to synth

2020-10-20 Thread Christian Schoenebeck
On Dienstag, 20. Oktober 2020 12:00:57 CEST Greg Kurz wrote:
> On Tue, 20 Oct 2020 11:43:18 +0200
> 
> Christian Schoenebeck  wrote:
> > On Dienstag, 20. Oktober 2020 09:36:10 CEST Philippe Mathieu-Daudé wrote:
> > > On 10/8/20 8:34 PM, Christian Schoenebeck wrote:
> > > > All existing 9pfs test cases are using the 'synth' fs driver so far,
> > > > which
> > > > means they are not accessing real files, but a purely simulated (in
> > > > RAM
> > > > only) file system.
> > > > 
> > > > Let's make this clear by changing the prefix of the individual qtest
> > > > case
> > > > names from 'fs/' to 'synth/'. That way they'll be easily
> > > > distinguishable
> > > > from upcoming new 9pfs test cases supposed to be using a different fs
> > > > driver.
> > > > 
> > > > Signed-off-by: Christian Schoenebeck 
> > > > Message-Id:
> > > >  > > > eby
> > > > te.com> Signed-off-by: Christian Schoenebeck 
> > > 
> > > Harmless, but don't need to sign twice ;)
> > 
> > Ah, I thought that's the common way, as Greg's PRs contained 2 SOBs as
> > well, i.e. I thought this was intended to outline the patch author and
> > submaintainer were the same person.
> > 
> > BTW I actually did not explicitly add the 2nd SOB. It was rather added by
> > the patchwork client automatically. So maybe it should be fixed in the
> > client to detect an already existing SOB line? Or am missing something
> > here?
> Yeah this is the reason why my sob appears twice on patches authored by
> me, and since this is harmless I never really investigated how to fix
> pwclient :)

Well, I would usually offer my 'I can look at it' at this point, but I am 
reluctant this time as I assume it will end up as my recently suggested libqos 
patches where I did not get any response from the officially assigned 
maintainers; not even a simple 'nack'.

Best regards,
Christian Schoenebeck





Re: [PULL v3 2/6] tests/9pfs: change qtest name prefix to synth

2020-10-20 Thread Christian Schoenebeck
On Dienstag, 20. Oktober 2020 09:36:10 CEST Philippe Mathieu-Daudé wrote:
> On 10/8/20 8:34 PM, Christian Schoenebeck wrote:
> > All existing 9pfs test cases are using the 'synth' fs driver so far, which
> > means they are not accessing real files, but a purely simulated (in RAM
> > only) file system.
> > 
> > Let's make this clear by changing the prefix of the individual qtest case
> > names from 'fs/' to 'synth/'. That way they'll be easily distinguishable
> > from upcoming new 9pfs test cases supposed to be using a different fs
> > driver.
> > 
> > Signed-off-by: Christian Schoenebeck 
> > Message-Id:
> >  > te.com> Signed-off-by: Christian Schoenebeck 
> 
> Harmless, but don't need to sign twice ;)

Ah, I thought that's the common way, as Greg's PRs contained 2 SOBs as well, 
i.e. I thought this was intended to outline the patch author and submaintainer 
were the same person.

BTW I actually did not explicitly add the 2nd SOB. It was rather added by the 
patchwork client automatically. So maybe it should be fixed in the client to 
detect an already existing SOB line? Or am missing something here?

Best regards,
Christian Schoenebeck





Re: [PATCH 7/8] tests/9pfs: add local Tlink test

2020-10-19 Thread Christian Schoenebeck
On Dienstag, 20. Oktober 2020 01:13:24 CEST Christian Schoenebeck wrote:
> This test case uses a Tlink request to create a hard link to a regular
> file using the 9pfs 'local' fs driver.
> 
> Signed-off-by: Christian Schoenebeck 
> ---
>  tests/qtest/virtio-9p-test.c | 61 
>  1 file changed, 61 insertions(+)
> 
> diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
> index f7d18f6274..447d8e3344 100644
> --- a/tests/qtest/virtio-9p-test.c
> +++ b/tests/qtest/virtio-9p-test.c
> @@ -260,6 +260,7 @@ static const char *rmessage_name(uint8_t id)
>  id == P9_RMKDIR ? "RMKDIR" :
>  id == P9_RLCREATE ? "RLCREATE" :
>  id == P9_RSYMLINK ? "RSYMLINK" :
> +id == P9_RLINK ? "RLINK" :
>  id == P9_RUNLINKAT ? "RUNLINKAT" :
>  id == P9_RFLUSH ? "RFLUSH" :
>  id == P9_RREADDIR ? "READDIR" :
> @@ -742,6 +743,33 @@ static void v9fs_rsymlink(P9Req *req, v9fs_qid *qid)
>  v9fs_req_free(req);
>  }
> 
> +/* size[4] Tlink tag[2] dfid[4] fid[4] name[s] */
> +static P9Req *v9fs_tlink(QVirtio9P *v9p, uint32_t dfid, uint32_t fid,
> + const char *name, uint16_t tag)
> +{

This hard-link test was actually motived by an issue that I recently 
encountered on a machine: it fails to create any hard links with 9p. This 
particular test case succeeds though.

I think the problem is that recent libvirt versions enable qemu's sandbox 
feature by default which filters syscalls. Fact is, any linkat() call fails on 
that machine with EACCES now. I couldn't reproduce it on my development 
machine yet though. I guess it's a difference in white/black-list seccomp 
config or something. Not sure yet if there is some change required on 9p side 
or whether it's really just a seccomp config issue.

P.S. Noisy days from my side, but this is probably the last batch of patches 
from my side in a while, unless I really need to fix something for that hard 
link isssue. We'll see ...

Best regards,
Christian Schoenebeck





[PATCH 8/8] tests/9pfs: add local unlinkat hard link test

2020-10-19 Thread Christian Schoenebeck
This test case uses a Tunlinkat request to remove a previously hard
linked file by using the 9pfs 'local' fs driver.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 34 ++
 1 file changed, 34 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 447d8e3344..2e50445745 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -1378,6 +1378,39 @@ static void fs_hardlink_file(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(real_file);
 }
 
+static void fs_unlinkat_hardlink(void *obj, void *data,
+ QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+P9Req *req;
+uint32_t dfid, fid;
+struct stat st_real, st_link;
+char *real_file = virtio_9p_test_path("08/real_file");
+char *hardlink_file = virtio_9p_test_path("08/hardlink_file");
+
+fs_attach(v9p, NULL, t_alloc);
+fs_mkdir(v9p, data, t_alloc, "/", "08");
+fid = fs_lcreate(v9p, data, t_alloc, "08", "real_file");
+g_assert(stat(real_file, _real) == 0);
+g_assert((st_real.st_mode & S_IFMT) == S_IFREG);
+
+dfid = fs_walk_fid(v9p, data, t_alloc, "08");
+
+req = v9fs_tlink(v9p, dfid, fid, "hardlink_file", 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rlink(req);
+g_assert(stat(hardlink_file, _link) == 0);
+
+fs_unlinkat(v9p, data, t_alloc, "08", "hardlink_file", 0);
+/* symlink should be gone now */
+g_assert(stat(hardlink_file, _link) != 0);
+/* and old file should still exist */
+g_assert(stat(real_file, _real) == 0);
+
+g_free(hardlink_file);
+g_free(real_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1424,6 +1457,7 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/symlink_file", "virtio-9p", fs_symlink_file, );
 qos_add_test("local/unlinkat_symlink", "virtio-9p", fs_unlinkat_symlink, 
);
 qos_add_test("local/hardlink_file", "virtio-9p", fs_hardlink_file, );
+qos_add_test("local/unlinkat_hardlink", "virtio-9p", fs_unlinkat_hardlink, 
);
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PATCH 7/8] tests/9pfs: add local Tlink test

2020-10-19 Thread Christian Schoenebeck
This test case uses a Tlink request to create a hard link to a regular
file using the 9pfs 'local' fs driver.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 61 
 1 file changed, 61 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index f7d18f6274..447d8e3344 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -260,6 +260,7 @@ static const char *rmessage_name(uint8_t id)
 id == P9_RMKDIR ? "RMKDIR" :
 id == P9_RLCREATE ? "RLCREATE" :
 id == P9_RSYMLINK ? "RSYMLINK" :
+id == P9_RLINK ? "RLINK" :
 id == P9_RUNLINKAT ? "RUNLINKAT" :
 id == P9_RFLUSH ? "RFLUSH" :
 id == P9_RREADDIR ? "READDIR" :
@@ -742,6 +743,33 @@ static void v9fs_rsymlink(P9Req *req, v9fs_qid *qid)
 v9fs_req_free(req);
 }
 
+/* size[4] Tlink tag[2] dfid[4] fid[4] name[s] */
+static P9Req *v9fs_tlink(QVirtio9P *v9p, uint32_t dfid, uint32_t fid,
+ const char *name, uint16_t tag)
+{
+P9Req *req;
+
+uint32_t body_size = 4 + 4;
+uint16_t string_size = v9fs_string_size(name);
+
+g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+body_size += string_size;
+
+req = v9fs_req_init(v9p, body_size, P9_TLINK, tag);
+v9fs_uint32_write(req, dfid);
+v9fs_uint32_write(req, fid);
+v9fs_string_write(req, name);
+v9fs_req_send(req);
+return req;
+}
+
+/* size[4] Rlink tag[2] */
+static void v9fs_rlink(P9Req *req)
+{
+v9fs_req_recv(req, P9_RLINK);
+v9fs_req_free(req);
+}
+
 /* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */
 static P9Req *v9fs_tunlinkat(QVirtio9P *v9p, uint32_t dirfd, const char *name,
  uint32_t flags, uint16_t tag)
@@ -1318,6 +1346,38 @@ static void fs_unlinkat_symlink(void *obj, void *data,
 g_free(real_file);
 }
 
+static void fs_hardlink_file(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+P9Req *req;
+uint32_t dfid, fid;
+struct stat st_real, st_link;
+char *real_file = virtio_9p_test_path("07/real_file");
+char *hardlink_file = virtio_9p_test_path("07/hardlink_file");
+
+fs_attach(v9p, NULL, t_alloc);
+fs_mkdir(v9p, data, t_alloc, "/", "07");
+fid = fs_lcreate(v9p, data, t_alloc, "07", "real_file");
+g_assert(stat(real_file, _real) == 0);
+g_assert((st_real.st_mode & S_IFMT) == S_IFREG);
+
+dfid = fs_walk_fid(v9p, data, t_alloc, "07");
+
+req = v9fs_tlink(v9p, dfid, fid, "hardlink_file", 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rlink(req);
+
+/* check if link exists now ... */
+g_assert(stat(hardlink_file, _link) == 0);
+/* ... and it's a hard link, right? */
+g_assert((st_link.st_mode & S_IFMT) == S_IFREG);
+g_assert(st_link.st_dev == st_real.st_dev);
+g_assert(st_link.st_ino == st_real.st_ino);
+
+g_free(hardlink_file);
+g_free(real_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1363,6 +1423,7 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/unlinkat_file", "virtio-9p", fs_unlinkat_file, );
 qos_add_test("local/symlink_file", "virtio-9p", fs_symlink_file, );
 qos_add_test("local/unlinkat_symlink", "virtio-9p", fs_unlinkat_symlink, 
);
+qos_add_test("local/hardlink_file", "virtio-9p", fs_hardlink_file, );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PATCH 4/8] tests/9pfs: add local unlinkat file test

2020-10-19 Thread Christian Schoenebeck
This test case uses a Tunlinkat request to remove a regular file using
the 9pfs 'local' fs driver.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 23 +++
 1 file changed, 23 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 1b133f52bd..06a9f10d34 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -1194,6 +1194,28 @@ static void fs_create_file(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(new_file);
 }
 
+static void fs_unlinkat_file(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+struct stat st;
+char *new_file = virtio_9p_test_path("04/doa_file");
+
+fs_attach(v9p, NULL, t_alloc);
+fs_mkdir(v9p, data, t_alloc, "/", "04");
+fs_lcreate(v9p, data, t_alloc, "04", "doa_file");
+
+/* check if created file exists now ... */
+g_assert(stat(new_file, ) == 0);
+/* ... and is a regular file */
+g_assert((st.st_mode & S_IFMT) == S_IFREG);
+
+fs_unlinkat(v9p, data, t_alloc, "04", "doa_file", 0);
+/* file should be gone now */
+g_assert(stat(new_file, ) != 0);
+
+g_free(new_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1236,6 +1258,7 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/create_dir", "virtio-9p", fs_create_dir, );
 qos_add_test("local/unlinkat_dir", "virtio-9p", fs_unlinkat_dir, );
 qos_add_test("local/create_file", "virtio-9p", fs_create_file, );
+qos_add_test("local/unlinkat_file", "virtio-9p", fs_unlinkat_file, );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PATCH 6/8] tests/9pfs: add local unlinkat symlink test

2020-10-19 Thread Christian Schoenebeck
This test case uses a Tunlinkat request to remove a symlink using
the 9pfs 'local' fs driver.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 26 ++
 1 file changed, 26 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 78f4ed7e5f..f7d18f6274 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -1293,6 +1293,31 @@ static void fs_symlink_file(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(real_file);
 }
 
+static void fs_unlinkat_symlink(void *obj, void *data,
+QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+struct stat st;
+char *real_file = virtio_9p_test_path("06/real_file");
+char *symlink_file = virtio_9p_test_path("06/symlink_file");
+
+fs_attach(v9p, NULL, t_alloc);
+fs_mkdir(v9p, data, t_alloc, "/", "06");
+fs_lcreate(v9p, data, t_alloc, "06", "real_file");
+g_assert(stat(real_file, ) == 0);
+g_assert((st.st_mode & S_IFMT) == S_IFREG);
+
+fs_symlink(v9p, data, t_alloc, "06", "symlink_file", "real_file");
+g_assert(stat(symlink_file, ) == 0);
+
+fs_unlinkat(v9p, data, t_alloc, "06", "symlink_file", 0);
+/* symlink should be gone now */
+g_assert(stat(symlink_file, ) != 0);
+
+g_free(symlink_file);
+g_free(real_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1337,6 +1362,7 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/create_file", "virtio-9p", fs_create_file, );
 qos_add_test("local/unlinkat_file", "virtio-9p", fs_unlinkat_file, );
 qos_add_test("local/symlink_file", "virtio-9p", fs_symlink_file, );
+qos_add_test("local/unlinkat_symlink", "virtio-9p", fs_unlinkat_symlink, 
);
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PATCH 3/8] tests/9pfs: add local Tlcreate test

2020-10-19 Thread Christian Schoenebeck
This test case uses a Tlcreate 9p request to create a regular file inside
host's test directory.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 78 
 1 file changed, 78 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 990d074d33..1b133f52bd 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -258,6 +258,7 @@ static const char *rmessage_name(uint8_t id)
 id == P9_RLOPEN ? "RLOPEN" :
 id == P9_RWRITE ? "RWRITE" :
 id == P9_RMKDIR ? "RMKDIR" :
+id == P9_RLCREATE ? "RLCREATE" :
 id == P9_RUNLINKAT ? "RUNLINKAT" :
 id == P9_RFLUSH ? "RFLUSH" :
 id == P9_RREADDIR ? "READDIR" :
@@ -669,6 +670,44 @@ static void v9fs_rmkdir(P9Req *req, v9fs_qid *qid)
 v9fs_req_free(req);
 }
 
+/* size[4] Tlcreate tag[2] fid[4] name[s] flags[4] mode[4] gid[4] */
+static P9Req *v9fs_tlcreate(QVirtio9P *v9p, uint32_t fid, const char *name,
+uint32_t flags, uint32_t mode, uint32_t gid,
+uint16_t tag)
+{
+P9Req *req;
+
+uint32_t body_size = 4 + 4 + 4 + 4;
+uint16_t string_size = v9fs_string_size(name);
+
+g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+body_size += string_size;
+
+req = v9fs_req_init(v9p, body_size, P9_TLCREATE, tag);
+v9fs_uint32_write(req, fid);
+v9fs_string_write(req, name);
+v9fs_uint32_write(req, flags);
+v9fs_uint32_write(req, mode);
+v9fs_uint32_write(req, gid);
+v9fs_req_send(req);
+return req;
+}
+
+/* size[4] Rlcreate tag[2] qid[13] iounit[4] */
+static void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, uint32_t *iounit)
+{
+v9fs_req_recv(req, P9_RLCREATE);
+if (qid) {
+v9fs_memread(req, qid, 13);
+} else {
+v9fs_memskip(req, 13);
+}
+if (iounit) {
+v9fs_uint32_read(req, iounit);
+}
+v9fs_req_free(req);
+}
+
 /* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */
 static P9Req *v9fs_tunlinkat(QVirtio9P *v9p, uint32_t dirfd, const char *name,
  uint32_t flags, uint16_t tag)
@@ -1032,6 +1071,26 @@ static void fs_mkdir(void *obj, void *data, 
QGuestAllocator *t_alloc,
 g_free(name);
 }
 
+/* create a regular file with Tlcreate and return file's fid */
+static uint32_t fs_lcreate(void *obj, void *data, QGuestAllocator *t_alloc,
+   const char *path, const char *cname)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+char *const name = g_strdup(cname);
+uint32_t fid;
+P9Req *req;
+
+fid = fs_walk_fid(v9p, data, t_alloc, path);
+
+req = v9fs_tlcreate(v9p, fid, name, 0, 0750, 0, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rlcreate(req, NULL, NULL);
+
+g_free(name);
+return fid;
+}
+
 static void fs_unlinkat(void *obj, void *data, QGuestAllocator *t_alloc,
 const char *atpath, const char *rpath, uint32_t flags)
 {
@@ -1117,6 +1176,24 @@ static void fs_unlinkat_dir(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(root_path);
 }
 
+static void fs_create_file(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+struct stat st;
+char *new_file = virtio_9p_test_path("03/1st_file");
+
+fs_attach(v9p, NULL, t_alloc);
+fs_mkdir(v9p, data, t_alloc, "/", "03");
+fs_lcreate(v9p, data, t_alloc, "03", "1st_file");
+
+/* check if created file exists now ... */
+g_assert(stat(new_file, ) == 0);
+/* ... and is a regular file */
+g_assert((st.st_mode & S_IFMT) == S_IFREG);
+
+g_free(new_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1158,6 +1235,7 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/config", "virtio-9p", pci_config,  );
 qos_add_test("local/create_dir", "virtio-9p", fs_create_dir, );
 qos_add_test("local/unlinkat_dir", "virtio-9p", fs_unlinkat_dir, );
+qos_add_test("local/create_file", "virtio-9p", fs_create_file, );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PATCH 0/8] 9pfs: more local tests

2020-10-19 Thread Christian Schoenebeck
Just a bunch of more test case using the 9pfs 'local' fs driver backend,
namely for these 9p requests:

* Tunlinkat, Tlcreate, Tsymlink and Tlink.

Christian Schoenebeck (8):
  tests/9pfs: simplify fs_mkdir()
  tests/9pfs: add local unlinkat directory test
  tests/9pfs: add local Tlcreate test
  tests/9pfs: add local unlinkat file test
  tests/9pfs: add local Tsymlink test
  tests/9pfs: add local unlinkat symlink test
  tests/9pfs: add local Tlink test
  tests/9pfs: add local unlinkat hard link test

 tests/qtest/virtio-9p-test.c | 395 ++-
 1 file changed, 390 insertions(+), 5 deletions(-)

-- 
2.20.1




[PATCH 5/8] tests/9pfs: add local Tsymlink test

2020-10-19 Thread Christian Schoenebeck
This test case uses a Tsymlink 9p request to create a symbolic link using
the 9pfs 'local' fs driver.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 78 
 1 file changed, 78 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 06a9f10d34..78f4ed7e5f 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -259,6 +259,7 @@ static const char *rmessage_name(uint8_t id)
 id == P9_RWRITE ? "RWRITE" :
 id == P9_RMKDIR ? "RMKDIR" :
 id == P9_RLCREATE ? "RLCREATE" :
+id == P9_RSYMLINK ? "RSYMLINK" :
 id == P9_RUNLINKAT ? "RUNLINKAT" :
 id == P9_RFLUSH ? "RFLUSH" :
 id == P9_RREADDIR ? "READDIR" :
@@ -708,6 +709,39 @@ static void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, 
uint32_t *iounit)
 v9fs_req_free(req);
 }
 
+/* size[4] Tsymlink tag[2] fid[4] name[s] symtgt[s] gid[4] */
+static P9Req *v9fs_tsymlink(QVirtio9P *v9p, uint32_t fid, const char *name,
+const char *symtgt, uint32_t gid, uint16_t tag)
+{
+P9Req *req;
+
+uint32_t body_size = 4 + 4;
+uint16_t string_size = v9fs_string_size(name) + v9fs_string_size(symtgt);
+
+g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+body_size += string_size;
+
+req = v9fs_req_init(v9p, body_size, P9_TSYMLINK, tag);
+v9fs_uint32_write(req, fid);
+v9fs_string_write(req, name);
+v9fs_string_write(req, symtgt);
+v9fs_uint32_write(req, gid);
+v9fs_req_send(req);
+return req;
+}
+
+/* size[4] Rsymlink tag[2] qid[13] */
+static void v9fs_rsymlink(P9Req *req, v9fs_qid *qid)
+{
+v9fs_req_recv(req, P9_RSYMLINK);
+if (qid) {
+v9fs_memread(req, qid, 13);
+} else {
+v9fs_memskip(req, 13);
+}
+v9fs_req_free(req);
+}
+
 /* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */
 static P9Req *v9fs_tunlinkat(QVirtio9P *v9p, uint32_t dirfd, const char *name,
  uint32_t flags, uint16_t tag)
@@ -1091,6 +1125,27 @@ static uint32_t fs_lcreate(void *obj, void *data, 
QGuestAllocator *t_alloc,
 return fid;
 }
 
+/* create symlink named @a clink in directory @a path pointing to @a to */
+static void fs_symlink(void *obj, void *data, QGuestAllocator *t_alloc,
+   const char *path, const char *clink, const char *to)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+char *const name = g_strdup(clink);
+char *const dst = g_strdup(to);
+uint32_t fid;
+P9Req *req;
+
+fid = fs_walk_fid(v9p, data, t_alloc, path);
+
+req = v9fs_tsymlink(v9p, fid, name, dst, 0, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rsymlink(req, NULL);
+
+g_free(dst);
+g_free(name);
+}
+
 static void fs_unlinkat(void *obj, void *data, QGuestAllocator *t_alloc,
 const char *atpath, const char *rpath, uint32_t flags)
 {
@@ -1216,6 +1271,28 @@ static void fs_unlinkat_file(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(new_file);
 }
 
+static void fs_symlink_file(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+struct stat st;
+char *real_file = virtio_9p_test_path("05/real_file");
+char *symlink_file = virtio_9p_test_path("05/symlink_file");
+
+fs_attach(v9p, NULL, t_alloc);
+fs_mkdir(v9p, data, t_alloc, "/", "05");
+fs_lcreate(v9p, data, t_alloc, "05", "real_file");
+g_assert(stat(real_file, ) == 0);
+g_assert((st.st_mode & S_IFMT) == S_IFREG);
+
+fs_symlink(v9p, data, t_alloc, "05", "symlink_file", "real_file");
+
+/* check if created link exists now */
+g_assert(stat(symlink_file, ) == 0);
+
+g_free(symlink_file);
+g_free(real_file);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1259,6 +1336,7 @@ static void register_virtio_9p_test(void)
 qos_add_test("local/unlinkat_dir", "virtio-9p", fs_unlinkat_dir, );
 qos_add_test("local/create_file", "virtio-9p", fs_create_file, );
 qos_add_test("local/unlinkat_file", "virtio-9p", fs_unlinkat_file, );
+qos_add_test("local/symlink_file", "virtio-9p", fs_symlink_file, );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PATCH 1/8] tests/9pfs: simplify fs_mkdir()

2020-10-19 Thread Christian Schoenebeck
Split out walking a directory path to a separate new utility function
fs_walk_fid() and use that function in fs_mkdir().

The code difference saved this way is not much, but we'll use that new
fs_walk_fid() function in the upcoming patches, so it will avoid quite
some code duplication after all.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 23 ++-
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index c15908f27b..dc724bbb1e 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -967,13 +967,12 @@ static void fs_flush_ignored(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(wnames[0]);
 }
 
-static void fs_mkdir(void *obj, void *data, QGuestAllocator *t_alloc,
- const char *path, const char *cname)
+/* utility function: walk to requested dir and return fid for that dir */
+static uint32_t fs_walk_fid(void *obj, void *data, QGuestAllocator *t_alloc,
+const char *path)
 {
 QVirtio9P *v9p = obj;
-alloc = t_alloc;
 char **wnames;
-char *const name = g_strdup(cname);
 P9Req *req;
 const uint32_t fid = genfid();
 
@@ -983,12 +982,26 @@ static void fs_mkdir(void *obj, void *data, 
QGuestAllocator *t_alloc,
 v9fs_req_wait_for_reply(req, NULL);
 v9fs_rwalk(req, NULL, NULL);
 
+split_free();
+return fid;
+}
+
+static void fs_mkdir(void *obj, void *data, QGuestAllocator *t_alloc,
+ const char *path, const char *cname)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+char *const name = g_strdup(cname);
+uint32_t fid;
+P9Req *req;
+
+fid = fs_walk_fid(v9p, data, t_alloc, path);
+
 req = v9fs_tmkdir(v9p, fid, name, 0750, 0, 0);
 v9fs_req_wait_for_reply(req, NULL);
 v9fs_rmkdir(req, NULL);
 
 g_free(name);
-split_free();
 }
 
 static void fs_readdir_split_128(void *obj, void *data,
-- 
2.20.1




[PATCH 2/8] tests/9pfs: add local unlinkat directory test

2020-10-19 Thread Christian Schoenebeck
This test case uses a Tunlinkat 9p request with flag AT_REMOVEDIR
(see 'man 2 unlink') to remove a directory from host's test directory.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 72 
 1 file changed, 72 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index dc724bbb1e..990d074d33 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -258,6 +258,7 @@ static const char *rmessage_name(uint8_t id)
 id == P9_RLOPEN ? "RLOPEN" :
 id == P9_RWRITE ? "RWRITE" :
 id == P9_RMKDIR ? "RMKDIR" :
+id == P9_RUNLINKAT ? "RUNLINKAT" :
 id == P9_RFLUSH ? "RFLUSH" :
 id == P9_RREADDIR ? "READDIR" :
 "";
@@ -668,6 +669,33 @@ static void v9fs_rmkdir(P9Req *req, v9fs_qid *qid)
 v9fs_req_free(req);
 }
 
+/* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4] */
+static P9Req *v9fs_tunlinkat(QVirtio9P *v9p, uint32_t dirfd, const char *name,
+ uint32_t flags, uint16_t tag)
+{
+P9Req *req;
+
+uint32_t body_size = 4 + 4;
+uint16_t string_size = v9fs_string_size(name);
+
+g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+body_size += string_size;
+
+req = v9fs_req_init(v9p, body_size, P9_TUNLINKAT, tag);
+v9fs_uint32_write(req, dirfd);
+v9fs_string_write(req, name);
+v9fs_uint32_write(req, flags);
+v9fs_req_send(req);
+return req;
+}
+
+/* size[4] Runlinkat tag[2] */
+static void v9fs_runlinkat(P9Req *req)
+{
+v9fs_req_recv(req, P9_RUNLINKAT);
+v9fs_req_free(req);
+}
+
 /* basic readdir test where reply fits into a single response message */
 static void fs_readdir(void *obj, void *data, QGuestAllocator *t_alloc)
 {
@@ -1004,6 +1032,24 @@ static void fs_mkdir(void *obj, void *data, 
QGuestAllocator *t_alloc,
 g_free(name);
 }
 
+static void fs_unlinkat(void *obj, void *data, QGuestAllocator *t_alloc,
+const char *atpath, const char *rpath, uint32_t flags)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+char *const name = g_strdup(rpath);
+uint32_t fid;
+P9Req *req;
+
+fid = fs_walk_fid(v9p, data, t_alloc, atpath);
+
+req = v9fs_tunlinkat(v9p, fid, name, flags, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_runlinkat(req);
+
+g_free(name);
+}
+
 static void fs_readdir_split_128(void *obj, void *data,
  QGuestAllocator *t_alloc)
 {
@@ -1046,6 +1092,31 @@ static void fs_create_dir(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(root_path);
 }
 
+static void fs_unlinkat_dir(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+QVirtio9P *v9p = obj;
+struct stat st;
+char *root_path = virtio_9p_test_path("");
+char *new_dir = virtio_9p_test_path("02");
+
+g_assert(root_path != NULL);
+
+fs_attach(v9p, NULL, t_alloc);
+fs_mkdir(v9p, data, t_alloc, "/", "02");
+
+/* check if created directory really exists now ... */
+g_assert(stat(new_dir, ) == 0);
+/* ... and is actually a directory */
+g_assert((st.st_mode & S_IFMT) == S_IFDIR);
+
+fs_unlinkat(v9p, data, t_alloc, "/", "02", AT_REMOVEDIR);
+/* directory should be gone now */
+g_assert(stat(new_dir, ) != 0);
+
+g_free(new_dir);
+g_free(root_path);
+}
+
 static void *assign_9p_local_driver(GString *cmd_line, void *arg)
 {
 virtio_9p_assign_local_driver(cmd_line, "security_model=mapped-xattr");
@@ -1086,6 +1157,7 @@ static void register_virtio_9p_test(void)
 opts.before = assign_9p_local_driver;
 qos_add_test("local/config", "virtio-9p", pci_config,  );
 qos_add_test("local/create_dir", "virtio-9p", fs_create_dir, );
+qos_add_test("local/unlinkat_dir", "virtio-9p", fs_unlinkat_dir, );
 }
 
 libqos_init(register_virtio_9p_test);
-- 
2.20.1




[PULL v3 5/6] tests/9pfs: add virtio_9p_test_path()

2020-10-19 Thread Christian Schoenebeck
This new public function virtio_9p_test_path() allows 9pfs
'local' tests to translate a path from guest scope to host
scope. For instance by passing an empty string it would
return the root path on host of the exported 9pfs tree.

Signed-off-by: Christian Schoenebeck 
Message-Id: 

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/virtio-9p.c | 6 ++
 tests/qtest/libqos/virtio-9p.h | 5 +
 2 files changed, 11 insertions(+)

diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c
index 8ee2a134bc..d43647b3b7 100644
--- a/tests/qtest/libqos/virtio-9p.c
+++ b/tests/qtest/libqos/virtio-9p.c
@@ -65,6 +65,12 @@ static void remove_local_test_dir(void)
 g_free(cmd);
 }
 
+char *virtio_9p_test_path(const char *path)
+{
+g_assert(local_test_path);
+return concat_path(local_test_path, path);
+}
+
 static void virtio_9p_cleanup(QVirtio9P *interface)
 {
 qvirtqueue_cleanup(interface->vdev->bus, interface->vq, alloc);
diff --git a/tests/qtest/libqos/virtio-9p.h b/tests/qtest/libqos/virtio-9p.h
index 326a603f72..19a4d97454 100644
--- a/tests/qtest/libqos/virtio-9p.h
+++ b/tests/qtest/libqos/virtio-9p.h
@@ -49,4 +49,9 @@ struct QVirtio9PDevice {
  */
 void virtio_9p_assign_local_driver(GString *cmd_line, const char *args);
 
+/**
+ * Returns path on host to the passed guest path. Result must be freed.
+ */
+char *virtio_9p_test_path(const char *path);
+
 #endif
-- 
2.20.1




[PULL v3 4/6] tests/9pfs: wipe local 9pfs test directory

2020-10-19 Thread Christian Schoenebeck
Before running the first 9pfs test case, make sure the test directory
for running the 9pfs 'local' tests on is entirely empty. For that
reason simply delete the test directory (if any) before (re)creating
it on test suite startup.

Note: The preferable precise behaviour would be the test directory
only being wiped once *before* a test suite run. Right now the test
directory is also wiped at the *end* of a test suite run because
libqos is calling the virtio_9p_register_nodes() callback for some
reason also when a test suite completed. This is suboptimal as
developers cannot immediately see what files and directories the
9pfs local tests created precisely after the test suite completed.
But fortunately the test directory is not wiped if some test failed.
So it is probably not worth it drilling another hole into libqos
for this issue.

Signed-off-by: Christian Schoenebeck 
Message-Id: 

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/virtio-9p.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c
index ee331166de..8ee2a134bc 100644
--- a/tests/qtest/libqos/virtio-9p.c
+++ b/tests/qtest/libqos/virtio-9p.c
@@ -53,6 +53,18 @@ static void create_local_test_dir(void)
 g_assert((st.st_mode & S_IFMT) == S_IFDIR);
 }
 
+/* Deletes directory previously created by create_local_test_dir(). */
+static void remove_local_test_dir(void)
+{
+g_assert(local_test_path != NULL);
+char *cmd = g_strdup_printf("rm -r '%s'\n", local_test_path);
+int res = system(cmd);
+if (res < 0) {
+/* ignore error, dummy check to prevent compiler error */
+}
+g_free(cmd);
+}
+
 static void virtio_9p_cleanup(QVirtio9P *interface)
 {
 qvirtqueue_cleanup(interface->vdev->bus, interface->vq, alloc);
@@ -230,6 +242,7 @@ static void virtio_9p_register_nodes(void)
 
 /* make sure test dir for the 'local' tests exists and is clean */
 init_local_test_path();
+remove_local_test_dir();
 create_local_test_dir();
 
 QPCIAddress addr = {
-- 
2.20.1




[PULL v3 3/6] tests/9pfs: introduce local tests

2020-10-19 Thread Christian Schoenebeck
This patch introduces 9pfs test cases using the 9pfs 'local'
filesystem driver which reads/writes/creates/deletes real files
and directories.

In this initial version, there is only one local test which actually
only checks if the 9pfs 'local' device was created successfully.

Before the 9pfs 'local' tests are run, a test directory 'qtest-9p-local'
is created (with world rwx permissions) under the current working
directory. At this point that test directory is not auto deleted yet.

Signed-off-by: Christian Schoenebeck 
Message-Id: 
<81fc4b3b6b6c9bf7999e79f5e7cbc364a5f09ddb.1602182956.git.qemu_...@crudebyte.com>
Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/virtio-9p.c | 81 ++
 tests/qtest/libqos/virtio-9p.h |  5 +++
 tests/qtest/virtio-9p-test.c   | 44 --
 3 files changed, 116 insertions(+), 14 deletions(-)

diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c
index 2e300063e3..ee331166de 100644
--- a/tests/qtest/libqos/virtio-9p.c
+++ b/tests/qtest/libqos/virtio-9p.c
@@ -24,6 +24,34 @@
 #include "qgraph.h"
 
 static QGuestAllocator *alloc;
+static char *local_test_path;
+
+/* Concatenates the passed 2 pathes. Returned result must be freed. */
+static char *concat_path(const char* a, const char* b)
+{
+return g_build_filename(a, b, NULL);
+}
+
+static void init_local_test_path(void)
+{
+char *pwd = g_get_current_dir();
+local_test_path = concat_path(pwd, "qtest-9p-local");
+g_free(pwd);
+}
+
+/* Creates the directory for the 9pfs 'local' filesystem driver to access. */
+static void create_local_test_dir(void)
+{
+struct stat st;
+
+g_assert(local_test_path != NULL);
+mkdir(local_test_path, 0777);
+
+/* ensure test directory exists now ... */
+g_assert(stat(local_test_path, ) == 0);
+/* ... and is actually a directory */
+g_assert((st.st_mode & S_IFMT) == S_IFDIR);
+}
 
 static void virtio_9p_cleanup(QVirtio9P *interface)
 {
@@ -146,11 +174,64 @@ static void *virtio_9p_pci_create(void *pci_bus, 
QGuestAllocator *t_alloc,
 return obj;
 }
 
+/**
+ * Performs regular expression based search and replace on @a haystack.
+ *
+ * @param haystack - input string to be parsed, result of replacement is
+ *   stored back to @a haystack
+ * @param pattern - the regular expression pattern for scanning @a haystack
+ * @param replace_fmt - matches of supplied @a pattern are replaced by this,
+ *  if necessary glib printf format can be used to add
+ *  variable arguments of this function to this
+ *  replacement string
+ */
+static void regex_replace(GString *haystack, const char *pattern,
+  const char *replace_fmt, ...)
+{
+GRegex *regex;
+char *replace, *s;
+va_list argp;
+
+va_start(argp, replace_fmt);
+replace = g_strdup_vprintf(replace_fmt, argp);
+va_end(argp);
+
+regex = g_regex_new(pattern, 0, 0, NULL);
+s = g_regex_replace(regex, haystack->str, -1, 0, replace, 0, NULL);
+g_string_assign(haystack, s);
+g_free(s);
+g_regex_unref(regex);
+g_free(replace);
+}
+
+void virtio_9p_assign_local_driver(GString *cmd_line, const char *args)
+{
+g_assert_nonnull(local_test_path);
+
+/* replace 'synth' driver by 'local' driver */
+regex_replace(cmd_line, "-fsdev synth,", "-fsdev local,");
+
+/* append 'path=...' to '-fsdev ...' group */
+regex_replace(cmd_line, "(-fsdev \\w[^ ]*)", "\\1,path='%s'",
+  local_test_path);
+
+if (!args) {
+return;
+}
+
+/* append passed args to '-fsdev ...' group */
+regex_replace(cmd_line, "(-fsdev \\w[^ ]*)", "\\1,%s", args);
+}
+
 static void virtio_9p_register_nodes(void)
 {
 const char *str_simple = "fsdev=fsdev0,mount_tag=" MOUNT_TAG;
 const char *str_addr = "fsdev=fsdev0,addr=04.0,mount_tag=" MOUNT_TAG;
 
+/* make sure test dir for the 'local' tests exists and is clean */
+init_local_test_path();
+create_local_test_dir();
+
 QPCIAddress addr = {
 .devfn = QPCI_DEVFN(4, 0),
 };
diff --git a/tests/qtest/libqos/virtio-9p.h b/tests/qtest/libqos/virtio-9p.h
index b1e6badc4a..326a603f72 100644
--- a/tests/qtest/libqos/virtio-9p.h
+++ b/tests/qtest/libqos/virtio-9p.h
@@ -44,4 +44,9 @@ struct QVirtio9PDevice {
 QVirtio9P v9p;
 };
 
+/**
+ * Prepares QEMU command line for 9pfs tests using the 'local' fs driver.
+ */
+void virtio_9p_assign_local_driver(GString *cmd_line, const char *args);
+
 #endif
diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 3281153b9c..af7e169d3a 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -895,29 +895,45 @@ static void fs_readdir_split_512(void *obj, void *data,
 fs_readdir_split(obj, data, t_alloc, 512);
 }
 

[PULL v3 6/6] tests/9pfs: add local Tmkdir test

2020-10-19 Thread Christian Schoenebeck
This test case uses the 9pfs 'local' driver to create a directory
and then checks if the expected directory was actually created
(as real directory) on host side.

This patch introduces a custom split() implementation, because
the test code requires non empty array elements as result. For
that reason g_strsplit() would not be a good alternative, as
it would require additional filter code for reshuffling the
array, and the resulting code would be even more complex than
this split() function.

Signed-off-by: Christian Schoenebeck 
Message-Id: 

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 139 +++
 1 file changed, 139 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index af7e169d3a..c15908f27b 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -18,6 +18,62 @@
 #define QVIRTIO_9P_TIMEOUT_US (10 * 1000 * 1000)
 static QGuestAllocator *alloc;
 
+/*
+ * Used to auto generate new fids. Start with arbitrary high value to avoid
+ * collision with hard coded fids in basic test code.
+ */
+static uint32_t fid_generator = 1000;
+
+static uint32_t genfid(void)
+{
+return fid_generator++;
+}
+
+/**
+ * Splits the @a in string by @a delim into individual (non empty) strings
+ * and outputs them to @a out. The output array @a out is NULL terminated.
+ *
+ * Output array @a out must be freed by calling split_free().
+ *
+ * @returns number of individual elements in output array @a out (without the
+ *  final NULL terminating element)
+ */
+static int split(const char *in, const char *delim, char ***out)
+{
+int n = 0, i = 0;
+char *tmp, *p;
+
+tmp = g_strdup(in);
+for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) {
+if (strlen(p) > 0) {
+++n;
+}
+}
+g_free(tmp);
+
+*out = g_new0(char *, n + 1); /* last element NULL delimiter */
+
+tmp = g_strdup(in);
+for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) {
+if (strlen(p) > 0) {
+(*out)[i++] = g_strdup(p);
+}
+}
+g_free(tmp);
+
+return n;
+}
+
+static void split_free(char ***out)
+{
+int i;
+for (i = 0; (*out)[i]; ++i) {
+g_free((*out)[i]);
+}
+g_free(*out);
+*out = NULL;
+}
+
 static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc)
 {
 QVirtio9P *v9p = obj;
@@ -201,6 +257,7 @@ static const char *rmessage_name(uint8_t id)
 id == P9_RWALK ? "RWALK" :
 id == P9_RLOPEN ? "RLOPEN" :
 id == P9_RWRITE ? "RWRITE" :
+id == P9_RMKDIR ? "RMKDIR" :
 id == P9_RFLUSH ? "RFLUSH" :
 id == P9_RREADDIR ? "READDIR" :
 "";
@@ -578,6 +635,39 @@ static bool fs_dirents_contain_name(struct V9fsDirent *e, 
const char* name)
 return false;
 }
 
+/* size[4] Tmkdir tag[2] dfid[4] name[s] mode[4] gid[4] */
+static P9Req *v9fs_tmkdir(QVirtio9P *v9p, uint32_t dfid, const char *name,
+  uint32_t mode, uint32_t gid, uint16_t tag)
+{
+P9Req *req;
+
+uint32_t body_size = 4 + 4 + 4;
+uint16_t string_size = v9fs_string_size(name);
+
+g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+body_size += string_size;
+
+req = v9fs_req_init(v9p, body_size, P9_TMKDIR, tag);
+v9fs_uint32_write(req, dfid);
+v9fs_string_write(req, name);
+v9fs_uint32_write(req, mode);
+v9fs_uint32_write(req, gid);
+v9fs_req_send(req);
+return req;
+}
+
+/* size[4] Rmkdir tag[2] qid[13] */
+static void v9fs_rmkdir(P9Req *req, v9fs_qid *qid)
+{
+v9fs_req_recv(req, P9_RMKDIR);
+if (qid) {
+v9fs_memread(req, qid, 13);
+} else {
+v9fs_memskip(req, 13);
+}
+v9fs_req_free(req);
+}
+
 /* basic readdir test where reply fits into a single response message */
 static void fs_readdir(void *obj, void *data, QGuestAllocator *t_alloc)
 {
@@ -877,6 +967,30 @@ static void fs_flush_ignored(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(wnames[0]);
 }
 
+static void fs_mkdir(void *obj, void *data, QGuestAllocator *t_alloc,
+ const char *path, const char *cname)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+char **wnames;
+char *const name = g_strdup(cname);
+P9Req *req;
+const uint32_t fid = genfid();
+
+int nwnames = split(path, "/", );
+
+req = v9fs_twalk(v9p, 0, fid, nwnames, wnames, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rwalk(req, NULL, NULL);
+
+req = v9fs_tmkdir(v9p, fid, name, 0750, 0, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rmkdir(req, NULL);
+
+g_free(name);
+split_free();
+}
+
 static void fs_readdir_split_128(void *obj, void *data,
  QGuestAllocator *t_alloc)
 {
@@ -895,6 +1009,30 @@ static void fs_readdir_split_512(void *obj, vo

[PULL v3 1/6] 9pfs: suppress performance warnings on qtest runs

2020-10-19 Thread Christian Schoenebeck
Don't trigger any performance warning if we're just running test cases,
because tests intentionally run for edge cases.

So far performance warnings were suppressed for the 'synth' fs driver
backend only. This patch suppresses them for all 9p fs driver backends.

Signed-off-by: Christian Schoenebeck 
Reviewed-by: Greg Kurz 
Message-Id: 

Signed-off-by: Christian Schoenebeck 
---
 hw/9pfs/9p-synth.c | 2 --
 hw/9pfs/virtio-9p-device.c | 6 ++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c
index cec8c0eefc..7eb210ffa8 100644
--- a/hw/9pfs/9p-synth.c
+++ b/hw/9pfs/9p-synth.c
@@ -541,8 +541,6 @@ static int synth_init(FsContext *ctx, Error **errp)
 QLIST_INIT(_root.child);
 qemu_mutex_init(_mutex);
 
-ctx->export_flags |= V9FS_NO_PERF_WARN;
-
 /* Add "." and ".." entries for root */
 v9fs_add_dir_node(_root, synth_root.attr->mode,
   "..", synth_root.attr, synth_root.attr->inode);
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 36f3aa9352..14371a78ef 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -21,6 +21,7 @@
 #include "hw/virtio/virtio-access.h"
 #include "qemu/iov.h"
 #include "qemu/module.h"
+#include "sysemu/qtest.h"
 
 static void virtio_9p_push_and_notify(V9fsPDU *pdu)
 {
@@ -199,6 +200,11 @@ static void virtio_9p_device_realize(DeviceState *dev, 
Error **errp)
 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
 V9fsVirtioState *v = VIRTIO_9P(dev);
 V9fsState *s = >state;
+FsDriverEntry *fse = get_fsdev_fsentry(s->fsconf.fsdev_id);
+
+if (qtest_enabled() && fse) {
+fse->export_flags |= V9FS_NO_PERF_WARN;
+}
 
 if (v9fs_device_realize_common(s, _9p_transport, errp)) {
 return;
-- 
2.20.1




[PULL v3 2/6] tests/9pfs: change qtest name prefix to synth

2020-10-19 Thread Christian Schoenebeck
All existing 9pfs test cases are using the 'synth' fs driver so far, which
means they are not accessing real files, but a purely simulated (in RAM
only) file system.

Let's make this clear by changing the prefix of the individual qtest case
names from 'fs/' to 'synth/'. That way they'll be easily distinguishable
from upcoming new 9pfs test cases supposed to be using a different fs
driver.

Signed-off-by: Christian Schoenebeck 
Message-Id: 

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 28 ++--
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index de30b717b6..3281153b9c 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -897,26 +897,26 @@ static void fs_readdir_split_512(void *obj, void *data,
 
 static void register_virtio_9p_test(void)
 {
-qos_add_test("config", "virtio-9p", pci_config, NULL);
-qos_add_test("fs/version/basic", "virtio-9p", fs_version, NULL);
-qos_add_test("fs/attach/basic", "virtio-9p", fs_attach, NULL);
-qos_add_test("fs/walk/basic", "virtio-9p", fs_walk, NULL);
-qos_add_test("fs/walk/no_slash", "virtio-9p", fs_walk_no_slash,
+qos_add_test("synth/config", "virtio-9p", pci_config, NULL);
+qos_add_test("synth/version/basic", "virtio-9p", fs_version, NULL);
+qos_add_test("synth/attach/basic", "virtio-9p", fs_attach, NULL);
+qos_add_test("synth/walk/basic", "virtio-9p", fs_walk, NULL);
+qos_add_test("synth/walk/no_slash", "virtio-9p", fs_walk_no_slash,
  NULL);
-qos_add_test("fs/walk/dotdot_from_root", "virtio-9p",
+qos_add_test("synth/walk/dotdot_from_root", "virtio-9p",
  fs_walk_dotdot, NULL);
-qos_add_test("fs/lopen/basic", "virtio-9p", fs_lopen, NULL);
-qos_add_test("fs/write/basic", "virtio-9p", fs_write, NULL);
-qos_add_test("fs/flush/success", "virtio-9p", fs_flush_success,
+qos_add_test("synth/lopen/basic", "virtio-9p", fs_lopen, NULL);
+qos_add_test("synth/write/basic", "virtio-9p", fs_write, NULL);
+qos_add_test("synth/flush/success", "virtio-9p", fs_flush_success,
  NULL);
-qos_add_test("fs/flush/ignored", "virtio-9p", fs_flush_ignored,
+qos_add_test("synth/flush/ignored", "virtio-9p", fs_flush_ignored,
  NULL);
-qos_add_test("fs/readdir/basic", "virtio-9p", fs_readdir, NULL);
-qos_add_test("fs/readdir/split_512", "virtio-9p",
+qos_add_test("synth/readdir/basic", "virtio-9p", fs_readdir, NULL);
+qos_add_test("synth/readdir/split_512", "virtio-9p",
  fs_readdir_split_512, NULL);
-qos_add_test("fs/readdir/split_256", "virtio-9p",
+qos_add_test("synth/readdir/split_256", "virtio-9p",
  fs_readdir_split_256, NULL);
-qos_add_test("fs/readdir/split_128", "virtio-9p",
+qos_add_test("synth/readdir/split_128", "virtio-9p",
  fs_readdir_split_128, NULL);
 }
 
-- 
2.20.1




[PULL v3 0/6] 9p queue (previous 2020-10-17)

2020-10-19 Thread Christian Schoenebeck
The following changes since commit ba2a9a9e6318bfd93a2306dec40137e198205b86:

  Merge remote-tracking branch 'remotes/mcayland/tags/qemu-macppc-20201019' 
into staging (2020-10-19 11:46:03 +0100)

are available in the Git repository at:

  https://github.com/cschoenebeck/qemu.git tags/pull-9p-20201019

for you to fetch changes up to 653daf38978d101d8810f96b9337ebc6b7b1423f:

  tests/9pfs: add local Tmkdir test (2020-10-19 14:25:40 +0200)


9pfs: add tests using local fs driver

The currently existing 9pfs test cases are all solely using the 9pfs 'synth'
fileystem driver, which is a very simple and purely simulated (in RAM only)
filesystem. There are issues though where the 'synth' fs driver is not
sufficient. For example the following two bugs need test cases running the
9pfs 'local' fs driver:

https://bugs.launchpad.net/qemu/+bug/1336794
https://bugs.launchpad.net/qemu/+bug/1877384

This patch set for that reason introduces 9pfs test cases using the 9pfs
'local' filesystem driver along to the already existing tests on 'synth'.


Christian Schoenebeck (6):
  9pfs: suppress performance warnings on qtest runs
  tests/9pfs: change qtest name prefix to synth
  tests/9pfs: introduce local tests
  tests/9pfs: wipe local 9pfs test directory
  tests/9pfs: add virtio_9p_test_path()
  tests/9pfs: add local Tmkdir test

 hw/9pfs/9p-synth.c |   2 -
 hw/9pfs/virtio-9p-device.c |   6 ++
 tests/qtest/libqos/virtio-9p.c | 100 +
 tests/qtest/libqos/virtio-9p.h |  10 +++
 tests/qtest/virtio-9p-test.c   | 197 -
 5 files changed, 292 insertions(+), 23 deletions(-)



Re: [PATCH 1/1] 9pfs: suppress performance warnings on qtest runs

2020-10-19 Thread Christian Schoenebeck
On Montag, 19. Oktober 2020 13:48:22 CEST Greg Kurz wrote:
> On Mon, 19 Oct 2020 13:10:18 +0200
> 
> Christian Schoenebeck  wrote:
> > Don't trigger any performance warning if we're just running test cases,
> > because tests intentionally run for edge cases.
> > 
> > So far performance warnings were suppressed for the 'synth' fs driver
> > backend only. This patch suppresses them for all 9p fs driver backends.
> > 
> > Signed-off-by: Christian Schoenebeck 
> > ---
> 
> LGTM
> 
> Reviewed-by: Greg Kurz 

Thanks Greg!

BTW, if you still have something to be merged, keep in mind freeze for 5.2 
starts next monday.

Best regards,
Christian Schoenebeck





[PATCH 1/1] 9pfs: suppress performance warnings on qtest runs

2020-10-19 Thread Christian Schoenebeck
Don't trigger any performance warning if we're just running test cases,
because tests intentionally run for edge cases.

So far performance warnings were suppressed for the 'synth' fs driver
backend only. This patch suppresses them for all 9p fs driver backends.

Signed-off-by: Christian Schoenebeck 
---
 hw/9pfs/9p-synth.c | 2 --
 hw/9pfs/virtio-9p-device.c | 6 ++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c
index cec8c0eefc..7eb210ffa8 100644
--- a/hw/9pfs/9p-synth.c
+++ b/hw/9pfs/9p-synth.c
@@ -541,8 +541,6 @@ static int synth_init(FsContext *ctx, Error **errp)
 QLIST_INIT(_root.child);
 qemu_mutex_init(_mutex);
 
-ctx->export_flags |= V9FS_NO_PERF_WARN;
-
 /* Add "." and ".." entries for root */
 v9fs_add_dir_node(_root, synth_root.attr->mode,
   "..", synth_root.attr, synth_root.attr->inode);
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 36f3aa9352..14371a78ef 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -21,6 +21,7 @@
 #include "hw/virtio/virtio-access.h"
 #include "qemu/iov.h"
 #include "qemu/module.h"
+#include "sysemu/qtest.h"
 
 static void virtio_9p_push_and_notify(V9fsPDU *pdu)
 {
@@ -199,6 +200,11 @@ static void virtio_9p_device_realize(DeviceState *dev, 
Error **errp)
 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
 V9fsVirtioState *v = VIRTIO_9P(dev);
 V9fsState *s = >state;
+FsDriverEntry *fse = get_fsdev_fsentry(s->fsconf.fsdev_id);
+
+if (qtest_enabled() && fse) {
+fse->export_flags |= V9FS_NO_PERF_WARN;
+}
 
 if (v9fs_device_realize_common(s, _9p_transport, errp)) {
 return;
-- 
2.20.1




Re: [PATCH v4 01/12] libqos/qgraph: add qemu_name to QOSGraphNode

2020-10-19 Thread Christian Schoenebeck
On Donnerstag, 8. Oktober 2020 20:34:56 CEST Christian Schoenebeck wrote:
> Add new member variable 'qemu_name' to struct QOSGraphNode.
> 
> This new member may be optionally set in case a different
> name for the node (which must always be a unique name) vs.
> its actually associated QEMU (QMP) device name is required.
> 
> Signed-off-by: Christian Schoenebeck 
> ---
>  tests/qtest/libqos/qgraph.c  | 1 +
>  tests/qtest/libqos/qgraph_internal.h | 1 +
>  2 files changed, 2 insertions(+)

So what shall happen with these libqos patches 1..7? Is that a nack, or 
postpone for now?

Best regards,
Christian Schoenebeck





Re: [PULL v2 0/5] 9p queue (previous 2020-10-15)

2020-10-19 Thread Christian Schoenebeck
On Montag, 19. Oktober 2020 12:22:47 CEST Peter Maydell wrote:
> On Mon, 19 Oct 2020 at 11:19, Christian Schoenebeck
> 
>  wrote:
> > On Montag, 19. Oktober 2020 11:52:38 CEST Peter Maydell wrote:
> > > This emits a lot of new warnings during 'make check':
> > > 
> > > PASS 27 qtest-arm: qos-test
> > > /arm/virt/virtio-mmio/virtio-bus/virtio-9p-device/virtio-9p/virtio-9p-te
> > > sts/ local/config qemu-system-arm: warning: 9p: degraded performance: a
> > > reasonable high msize should be chosen on client/guest side (chosen
> > > msize is <= 8192). See
> > > https://wiki.qemu.org/Documentation/9psetup#msize for details. PASS 28
> > > qtest-arm: qos-test
> > > /arm/virt/virtio-mmio/virtio-bus/virtio-9p-device/virtio-9p/virtio-9p-te
> > > sts/ local/create_dir
> > > 
> > > PASS 54 qtest-i386: qos-test
> > > /i386/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virti
> > > o-9p -tests/local/config qemu-system-i386: warning: 9p: degraded
> > > performance: a reasonable high msize should be chosen on client/guest
> > > side (chosen msize is <= 8192). See
> > > https://wiki.qemu.org/Documentation/9psetup#msize for details. PASS 55
> > > qtest-i386: qos-test
> > > /i386/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virti
> > > o-9p -tests/local/create_dir
> > 
> > One warning per test suite run (i.e. per architecture due to
> > warn_report_once()), yes. That performance warning is meant for end user
> > installations to remind them setting some (reasonable high) value for 9p
> > client parameter 'msize' on guest OS side. The warning triggers here
> > because the 9p test cases intentionally run with a small 'msize' to guard
> > edge cases.
> > 
> > Would it be Ok for you to merge it with this performance warning for now?
> > I
> > can take care of silencing it before 5.2 release. It probably requires to
> > introduce a new CL option to suppress performance warnings like these, or
> > by finding a way to detect that we're currently just running qtests.
> 
> The usual approach is to suppress this kind of warning by guarding
> it with if (qtest_enabled()) { ... }.

Ah, didn't see that one. I do that and resend, thanks!

Best regards,
Christian Schoenebeck





Re: [PULL v2 0/5] 9p queue (previous 2020-10-15)

2020-10-19 Thread Christian Schoenebeck
On Montag, 19. Oktober 2020 11:52:38 CEST Peter Maydell wrote:
> On Sat, 17 Oct 2020 at 15:23, Christian Schoenebeck
> 
>  wrote:
> > The following changes since commit 
e12ce85b2c79d83a340953291912875c30b3af06:
> >   Merge remote-tracking branch
> >   'remotes/ehabkost/tags/x86-next-pull-request' into staging (2020-10-16
> >   22:46:28 +0100)> 
> > are available in the Git repository at:
> >   https://github.com/cschoenebeck/qemu.git tags/pull-9p-20201017
> > 
> > for you to fetch changes up to fa4551e3f4416cc8c62086ac430b1ceb4f03eb6b:
> >   tests/9pfs: add local Tmkdir test (2020-10-17 15:58:39 +0200)
> > 
> > 
> > 9pfs: add tests using local fs driver
> > 
> > The currently existing 9pfs test cases are all solely using the 9pfs
> > 'synth' fileystem driver, which is a very simple and purely simulated (in
> > RAM only) filesystem. There are issues though where the 'synth' fs driver
> > is not sufficient. For example the following two bugs need test cases
> > running the 9pfs 'local' fs driver:
> > 
> > https://bugs.launchpad.net/qemu/+bug/1336794
> > https://bugs.launchpad.net/qemu/+bug/1877384
> > 
> > This patch set for that reason introduces 9pfs test cases using the 9pfs
> > 'local' filesystem driver along to the already existing tests on 'synth'.
> 
> This emits a lot of new warnings during 'make check':
> 
> PASS 27 qtest-arm: qos-test
> /arm/virt/virtio-mmio/virtio-bus/virtio-9p-device/virtio-9p/virtio-9p-tests/
> local/config qemu-system-arm: warning: 9p: degraded performance: a
> reasonable high msize should be chosen on client/guest side (chosen msize
> is <= 8192). See https://wiki.qemu.org/Documentation/9psetup#msize for
> details. PASS 28 qtest-arm: qos-test
> /arm/virt/virtio-mmio/virtio-bus/virtio-9p-device/virtio-9p/virtio-9p-tests/
> local/create_dir
> 
> PASS 54 qtest-i386: qos-test
> /i386/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virtio-9p
> -tests/local/config qemu-system-i386: warning: 9p: degraded performance: a
> reasonable high msize should be chosen on client/guest side (chosen msize
> is <= 8192). See https://wiki.qemu.org/Documentation/9psetup#msize for
> details. PASS 55 qtest-i386: qos-test
> /i386/pc/i440FX-pcihost/pci-bus-pc/pci-bus/virtio-9p-pci/virtio-9p/virtio-9p
> -tests/local/create_dir
> 
> etc.
> 
> thanks
> -- PMM

One warning per test suite run (i.e. per architecture due to 
warn_report_once()), yes. That performance warning is meant for end user 
installations to remind them setting some (reasonable high) value for 9p 
client parameter 'msize' on guest OS side. The warning triggers here because 
the 9p test cases intentionally run with a small 'msize' to guard edge cases.

Would it be Ok for you to merge it with this performance warning for now? I 
can take care of silencing it before 5.2 release. It probably requires to 
introduce a new CL option to suppress performance warnings like these, or by 
finding a way to detect that we're currently just running qtests.

Best regards,
Christian Schoenebeck





[PULL v2 5/5] tests/9pfs: add local Tmkdir test

2020-10-17 Thread Christian Schoenebeck
This test case uses the 9pfs 'local' driver to create a directory
and then checks if the expected directory was actually created
(as real directory) on host side.

This patch introduces a custom split() implementation, because
the test code requires non empty array elements as result. For
that reason g_strsplit() would not be a good alternative, as
it would require additional filter code for reshuffling the
array, and the resulting code would be even more complex than
this split() function.

Signed-off-by: Christian Schoenebeck 
Message-Id: 

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 139 +++
 1 file changed, 139 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index af7e169d3a..c15908f27b 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -18,6 +18,62 @@
 #define QVIRTIO_9P_TIMEOUT_US (10 * 1000 * 1000)
 static QGuestAllocator *alloc;
 
+/*
+ * Used to auto generate new fids. Start with arbitrary high value to avoid
+ * collision with hard coded fids in basic test code.
+ */
+static uint32_t fid_generator = 1000;
+
+static uint32_t genfid(void)
+{
+return fid_generator++;
+}
+
+/**
+ * Splits the @a in string by @a delim into individual (non empty) strings
+ * and outputs them to @a out. The output array @a out is NULL terminated.
+ *
+ * Output array @a out must be freed by calling split_free().
+ *
+ * @returns number of individual elements in output array @a out (without the
+ *  final NULL terminating element)
+ */
+static int split(const char *in, const char *delim, char ***out)
+{
+int n = 0, i = 0;
+char *tmp, *p;
+
+tmp = g_strdup(in);
+for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) {
+if (strlen(p) > 0) {
+++n;
+}
+}
+g_free(tmp);
+
+*out = g_new0(char *, n + 1); /* last element NULL delimiter */
+
+tmp = g_strdup(in);
+for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) {
+if (strlen(p) > 0) {
+(*out)[i++] = g_strdup(p);
+}
+}
+g_free(tmp);
+
+return n;
+}
+
+static void split_free(char ***out)
+{
+int i;
+for (i = 0; (*out)[i]; ++i) {
+g_free((*out)[i]);
+}
+g_free(*out);
+*out = NULL;
+}
+
 static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc)
 {
 QVirtio9P *v9p = obj;
@@ -201,6 +257,7 @@ static const char *rmessage_name(uint8_t id)
 id == P9_RWALK ? "RWALK" :
 id == P9_RLOPEN ? "RLOPEN" :
 id == P9_RWRITE ? "RWRITE" :
+id == P9_RMKDIR ? "RMKDIR" :
 id == P9_RFLUSH ? "RFLUSH" :
 id == P9_RREADDIR ? "READDIR" :
 "";
@@ -578,6 +635,39 @@ static bool fs_dirents_contain_name(struct V9fsDirent *e, 
const char* name)
 return false;
 }
 
+/* size[4] Tmkdir tag[2] dfid[4] name[s] mode[4] gid[4] */
+static P9Req *v9fs_tmkdir(QVirtio9P *v9p, uint32_t dfid, const char *name,
+  uint32_t mode, uint32_t gid, uint16_t tag)
+{
+P9Req *req;
+
+uint32_t body_size = 4 + 4 + 4;
+uint16_t string_size = v9fs_string_size(name);
+
+g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+body_size += string_size;
+
+req = v9fs_req_init(v9p, body_size, P9_TMKDIR, tag);
+v9fs_uint32_write(req, dfid);
+v9fs_string_write(req, name);
+v9fs_uint32_write(req, mode);
+v9fs_uint32_write(req, gid);
+v9fs_req_send(req);
+return req;
+}
+
+/* size[4] Rmkdir tag[2] qid[13] */
+static void v9fs_rmkdir(P9Req *req, v9fs_qid *qid)
+{
+v9fs_req_recv(req, P9_RMKDIR);
+if (qid) {
+v9fs_memread(req, qid, 13);
+} else {
+v9fs_memskip(req, 13);
+}
+v9fs_req_free(req);
+}
+
 /* basic readdir test where reply fits into a single response message */
 static void fs_readdir(void *obj, void *data, QGuestAllocator *t_alloc)
 {
@@ -877,6 +967,30 @@ static void fs_flush_ignored(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(wnames[0]);
 }
 
+static void fs_mkdir(void *obj, void *data, QGuestAllocator *t_alloc,
+ const char *path, const char *cname)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+char **wnames;
+char *const name = g_strdup(cname);
+P9Req *req;
+const uint32_t fid = genfid();
+
+int nwnames = split(path, "/", );
+
+req = v9fs_twalk(v9p, 0, fid, nwnames, wnames, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rwalk(req, NULL, NULL);
+
+req = v9fs_tmkdir(v9p, fid, name, 0750, 0, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rmkdir(req, NULL);
+
+g_free(name);
+split_free();
+}
+
 static void fs_readdir_split_128(void *obj, void *data,
  QGuestAllocator *t_alloc)
 {
@@ -895,6 +1009,30 @@ static void fs_readdir_split_512(void *obj, vo

[PULL v2 0/5] 9p queue (previous 2020-10-15)

2020-10-17 Thread Christian Schoenebeck
The following changes since commit e12ce85b2c79d83a340953291912875c30b3af06:

  Merge remote-tracking branch 'remotes/ehabkost/tags/x86-next-pull-request' 
into staging (2020-10-16 22:46:28 +0100)

are available in the Git repository at:

  https://github.com/cschoenebeck/qemu.git tags/pull-9p-20201017

for you to fetch changes up to fa4551e3f4416cc8c62086ac430b1ceb4f03eb6b:

  tests/9pfs: add local Tmkdir test (2020-10-17 15:58:39 +0200)


9pfs: add tests using local fs driver

The currently existing 9pfs test cases are all solely using the 9pfs 'synth'
fileystem driver, which is a very simple and purely simulated (in RAM only)
filesystem. There are issues though where the 'synth' fs driver is not
sufficient. For example the following two bugs need test cases running the
9pfs 'local' fs driver:

https://bugs.launchpad.net/qemu/+bug/1336794
https://bugs.launchpad.net/qemu/+bug/1877384

This patch set for that reason introduces 9pfs test cases using the 9pfs
'local' filesystem driver along to the already existing tests on 'synth'.


Christian Schoenebeck (5):
  tests/9pfs: change qtest name prefix to synth
  tests/9pfs: introduce local tests
  tests/9pfs: wipe local 9pfs test directory
  tests/9pfs: add virtio_9p_test_path()
  tests/9pfs: add local Tmkdir test

 tests/qtest/libqos/virtio-9p.c | 100 +
 tests/qtest/libqos/virtio-9p.h |  10 +++
 tests/qtest/virtio-9p-test.c   | 197 -
 3 files changed, 286 insertions(+), 21 deletions(-)



[PULL v2 4/5] tests/9pfs: add virtio_9p_test_path()

2020-10-17 Thread Christian Schoenebeck
This new public function virtio_9p_test_path() allows 9pfs
'local' tests to translate a path from guest scope to host
scope. For instance by passing an empty string it would
return the root path on host of the exported 9pfs tree.

Signed-off-by: Christian Schoenebeck 
Message-Id: 

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/virtio-9p.c | 6 ++
 tests/qtest/libqos/virtio-9p.h | 5 +
 2 files changed, 11 insertions(+)

diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c
index 8ee2a134bc..d43647b3b7 100644
--- a/tests/qtest/libqos/virtio-9p.c
+++ b/tests/qtest/libqos/virtio-9p.c
@@ -65,6 +65,12 @@ static void remove_local_test_dir(void)
 g_free(cmd);
 }
 
+char *virtio_9p_test_path(const char *path)
+{
+g_assert(local_test_path);
+return concat_path(local_test_path, path);
+}
+
 static void virtio_9p_cleanup(QVirtio9P *interface)
 {
 qvirtqueue_cleanup(interface->vdev->bus, interface->vq, alloc);
diff --git a/tests/qtest/libqos/virtio-9p.h b/tests/qtest/libqos/virtio-9p.h
index 326a603f72..19a4d97454 100644
--- a/tests/qtest/libqos/virtio-9p.h
+++ b/tests/qtest/libqos/virtio-9p.h
@@ -49,4 +49,9 @@ struct QVirtio9PDevice {
  */
 void virtio_9p_assign_local_driver(GString *cmd_line, const char *args);
 
+/**
+ * Returns path on host to the passed guest path. Result must be freed.
+ */
+char *virtio_9p_test_path(const char *path);
+
 #endif
-- 
2.20.1




[PULL v2 3/5] tests/9pfs: wipe local 9pfs test directory

2020-10-17 Thread Christian Schoenebeck
Before running the first 9pfs test case, make sure the test directory
for running the 9pfs 'local' tests on is entirely empty. For that
reason simply delete the test directory (if any) before (re)creating
it on test suite startup.

Note: The preferable precise behaviour would be the test directory
only being wiped once *before* a test suite run. Right now the test
directory is also wiped at the *end* of a test suite run because
libqos is calling the virtio_9p_register_nodes() callback for some
reason also when a test suite completed. This is suboptimal as
developers cannot immediately see what files and directories the
9pfs local tests created precisely after the test suite completed.
But fortunately the test directory is not wiped if some test failed.
So it is probably not worth it drilling another hole into libqos
for this issue.

Signed-off-by: Christian Schoenebeck 
Message-Id: 

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/virtio-9p.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c
index ee331166de..8ee2a134bc 100644
--- a/tests/qtest/libqos/virtio-9p.c
+++ b/tests/qtest/libqos/virtio-9p.c
@@ -53,6 +53,18 @@ static void create_local_test_dir(void)
 g_assert((st.st_mode & S_IFMT) == S_IFDIR);
 }
 
+/* Deletes directory previously created by create_local_test_dir(). */
+static void remove_local_test_dir(void)
+{
+g_assert(local_test_path != NULL);
+char *cmd = g_strdup_printf("rm -r '%s'\n", local_test_path);
+int res = system(cmd);
+if (res < 0) {
+/* ignore error, dummy check to prevent compiler error */
+}
+g_free(cmd);
+}
+
 static void virtio_9p_cleanup(QVirtio9P *interface)
 {
 qvirtqueue_cleanup(interface->vdev->bus, interface->vq, alloc);
@@ -230,6 +242,7 @@ static void virtio_9p_register_nodes(void)
 
 /* make sure test dir for the 'local' tests exists and is clean */
 init_local_test_path();
+remove_local_test_dir();
 create_local_test_dir();
 
 QPCIAddress addr = {
-- 
2.20.1




[PULL v2 2/5] tests/9pfs: introduce local tests

2020-10-17 Thread Christian Schoenebeck
This patch introduces 9pfs test cases using the 9pfs 'local'
filesystem driver which reads/writes/creates/deletes real files
and directories.

In this initial version, there is only one local test which actually
only checks if the 9pfs 'local' device was created successfully.

Before the 9pfs 'local' tests are run, a test directory 'qtest-9p-local'
is created (with world rwx permissions) under the current working
directory. At this point that test directory is not auto deleted yet.

Signed-off-by: Christian Schoenebeck 
Message-Id: 
<81fc4b3b6b6c9bf7999e79f5e7cbc364a5f09ddb.1602182956.git.qemu_...@crudebyte.com>
Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/virtio-9p.c | 81 ++
 tests/qtest/libqos/virtio-9p.h |  5 +++
 tests/qtest/virtio-9p-test.c   | 44 --
 3 files changed, 116 insertions(+), 14 deletions(-)

diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c
index 2e300063e3..ee331166de 100644
--- a/tests/qtest/libqos/virtio-9p.c
+++ b/tests/qtest/libqos/virtio-9p.c
@@ -24,6 +24,34 @@
 #include "qgraph.h"
 
 static QGuestAllocator *alloc;
+static char *local_test_path;
+
+/* Concatenates the passed 2 pathes. Returned result must be freed. */
+static char *concat_path(const char* a, const char* b)
+{
+return g_build_filename(a, b, NULL);
+}
+
+static void init_local_test_path(void)
+{
+char *pwd = g_get_current_dir();
+local_test_path = concat_path(pwd, "qtest-9p-local");
+g_free(pwd);
+}
+
+/* Creates the directory for the 9pfs 'local' filesystem driver to access. */
+static void create_local_test_dir(void)
+{
+struct stat st;
+
+g_assert(local_test_path != NULL);
+mkdir(local_test_path, 0777);
+
+/* ensure test directory exists now ... */
+g_assert(stat(local_test_path, ) == 0);
+/* ... and is actually a directory */
+g_assert((st.st_mode & S_IFMT) == S_IFDIR);
+}
 
 static void virtio_9p_cleanup(QVirtio9P *interface)
 {
@@ -146,11 +174,64 @@ static void *virtio_9p_pci_create(void *pci_bus, 
QGuestAllocator *t_alloc,
 return obj;
 }
 
+/**
+ * Performs regular expression based search and replace on @a haystack.
+ *
+ * @param haystack - input string to be parsed, result of replacement is
+ *   stored back to @a haystack
+ * @param pattern - the regular expression pattern for scanning @a haystack
+ * @param replace_fmt - matches of supplied @a pattern are replaced by this,
+ *  if necessary glib printf format can be used to add
+ *  variable arguments of this function to this
+ *  replacement string
+ */
+static void regex_replace(GString *haystack, const char *pattern,
+  const char *replace_fmt, ...)
+{
+GRegex *regex;
+char *replace, *s;
+va_list argp;
+
+va_start(argp, replace_fmt);
+replace = g_strdup_vprintf(replace_fmt, argp);
+va_end(argp);
+
+regex = g_regex_new(pattern, 0, 0, NULL);
+s = g_regex_replace(regex, haystack->str, -1, 0, replace, 0, NULL);
+g_string_assign(haystack, s);
+g_free(s);
+g_regex_unref(regex);
+g_free(replace);
+}
+
+void virtio_9p_assign_local_driver(GString *cmd_line, const char *args)
+{
+g_assert_nonnull(local_test_path);
+
+/* replace 'synth' driver by 'local' driver */
+regex_replace(cmd_line, "-fsdev synth,", "-fsdev local,");
+
+/* append 'path=...' to '-fsdev ...' group */
+regex_replace(cmd_line, "(-fsdev \\w[^ ]*)", "\\1,path='%s'",
+  local_test_path);
+
+if (!args) {
+return;
+}
+
+/* append passed args to '-fsdev ...' group */
+regex_replace(cmd_line, "(-fsdev \\w[^ ]*)", "\\1,%s", args);
+}
+
 static void virtio_9p_register_nodes(void)
 {
 const char *str_simple = "fsdev=fsdev0,mount_tag=" MOUNT_TAG;
 const char *str_addr = "fsdev=fsdev0,addr=04.0,mount_tag=" MOUNT_TAG;
 
+/* make sure test dir for the 'local' tests exists and is clean */
+init_local_test_path();
+create_local_test_dir();
+
 QPCIAddress addr = {
 .devfn = QPCI_DEVFN(4, 0),
 };
diff --git a/tests/qtest/libqos/virtio-9p.h b/tests/qtest/libqos/virtio-9p.h
index b1e6badc4a..326a603f72 100644
--- a/tests/qtest/libqos/virtio-9p.h
+++ b/tests/qtest/libqos/virtio-9p.h
@@ -44,4 +44,9 @@ struct QVirtio9PDevice {
 QVirtio9P v9p;
 };
 
+/**
+ * Prepares QEMU command line for 9pfs tests using the 'local' fs driver.
+ */
+void virtio_9p_assign_local_driver(GString *cmd_line, const char *args);
+
 #endif
diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 3281153b9c..af7e169d3a 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -895,29 +895,45 @@ static void fs_readdir_split_512(void *obj, void *data,
 fs_readdir_split(obj, data, t_alloc, 512);
 }
 

[PULL v2 1/5] tests/9pfs: change qtest name prefix to synth

2020-10-17 Thread Christian Schoenebeck
All existing 9pfs test cases are using the 'synth' fs driver so far, which
means they are not accessing real files, but a purely simulated (in RAM
only) file system.

Let's make this clear by changing the prefix of the individual qtest case
names from 'fs/' to 'synth/'. That way they'll be easily distinguishable
from upcoming new 9pfs test cases supposed to be using a different fs
driver.

Signed-off-by: Christian Schoenebeck 
Message-Id: 

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 28 ++--
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index de30b717b6..3281153b9c 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -897,26 +897,26 @@ static void fs_readdir_split_512(void *obj, void *data,
 
 static void register_virtio_9p_test(void)
 {
-qos_add_test("config", "virtio-9p", pci_config, NULL);
-qos_add_test("fs/version/basic", "virtio-9p", fs_version, NULL);
-qos_add_test("fs/attach/basic", "virtio-9p", fs_attach, NULL);
-qos_add_test("fs/walk/basic", "virtio-9p", fs_walk, NULL);
-qos_add_test("fs/walk/no_slash", "virtio-9p", fs_walk_no_slash,
+qos_add_test("synth/config", "virtio-9p", pci_config, NULL);
+qos_add_test("synth/version/basic", "virtio-9p", fs_version, NULL);
+qos_add_test("synth/attach/basic", "virtio-9p", fs_attach, NULL);
+qos_add_test("synth/walk/basic", "virtio-9p", fs_walk, NULL);
+qos_add_test("synth/walk/no_slash", "virtio-9p", fs_walk_no_slash,
  NULL);
-qos_add_test("fs/walk/dotdot_from_root", "virtio-9p",
+qos_add_test("synth/walk/dotdot_from_root", "virtio-9p",
  fs_walk_dotdot, NULL);
-qos_add_test("fs/lopen/basic", "virtio-9p", fs_lopen, NULL);
-qos_add_test("fs/write/basic", "virtio-9p", fs_write, NULL);
-qos_add_test("fs/flush/success", "virtio-9p", fs_flush_success,
+qos_add_test("synth/lopen/basic", "virtio-9p", fs_lopen, NULL);
+qos_add_test("synth/write/basic", "virtio-9p", fs_write, NULL);
+qos_add_test("synth/flush/success", "virtio-9p", fs_flush_success,
  NULL);
-qos_add_test("fs/flush/ignored", "virtio-9p", fs_flush_ignored,
+qos_add_test("synth/flush/ignored", "virtio-9p", fs_flush_ignored,
  NULL);
-qos_add_test("fs/readdir/basic", "virtio-9p", fs_readdir, NULL);
-qos_add_test("fs/readdir/split_512", "virtio-9p",
+qos_add_test("synth/readdir/basic", "virtio-9p", fs_readdir, NULL);
+qos_add_test("synth/readdir/split_512", "virtio-9p",
  fs_readdir_split_512, NULL);
-qos_add_test("fs/readdir/split_256", "virtio-9p",
+qos_add_test("synth/readdir/split_256", "virtio-9p",
  fs_readdir_split_256, NULL);
-qos_add_test("fs/readdir/split_128", "virtio-9p",
+qos_add_test("synth/readdir/split_128", "virtio-9p",
  fs_readdir_split_128, NULL);
 }
 
-- 
2.20.1




Re: [PULL 0/5] 9p queue 2020-10-15

2020-10-17 Thread Christian Schoenebeck
On Samstag, 17. Oktober 2020 12:50:13 CEST Peter Maydell wrote:
> On Thu, 15 Oct 2020 at 22:04, Christian Schoenebeck
> 
>  wrote:
> > The following changes since commit 
57c98ea9acdcef5021f5671efa6475a5794a51c4:
> >   Merge remote-tracking branch
> >   'remotes/kraxel/tags/ui-20201014-pull-request' into staging (2020-10-14
> >   13:56:06 +0100)> 
> > are available in the Git repository at:
> >   https://github.com/cschoenebeck/qemu.git tags/pull-9p-20201015
> > 
> > for you to fetch changes up to 97a64ec211d051439b654950ed3f7cffc47d489b:
> >   tests/9pfs: add local Tmkdir test (2020-10-15 16:11:17 +0200)
> > 
> > 
> > 9pfs: add tests using local fs driver
> > 
> > The currently existing 9pfs test cases are all solely using the 9pfs
> > 'synth' fileystem driver, which is a very simple and purely simulated (in
> > RAM only) filesystem. There are issues though where the 'synth' fs driver
> > is not sufficient. For example the following two bugs need test cases
> > running the 9pfs 'local' fs driver:
> > 
> > https://bugs.launchpad.net/qemu/+bug/1336794
> > https://bugs.launchpad.net/qemu/+bug/1877384
> > 
> > This patch set for that reason introduces 9pfs test cases using the 9pfs
> > 'local' filesystem driver along to the already existing tests on 'synth'.
> 
> Build failure, OSX:
> 
> Compiling C object tests/qtest/libqos/libqos.fa.p/virtio-9p.c.o
> ../../tests/qtest/libqos/virtio-9p.c:37:17: error: implicit
> declaration of function 'get_current_dir_name' is invalid in C99
> [-Werror,-Wimplicit-function-declaration]
> char *pwd = get_current_dir_name();
> ^
> ../../tests/qtest/libqos/virtio-9p.c:37:17: error: this function
> declaration is not a prototype [-Werror,-Wstrict-prototypes]
> ../../tests/qtest/libqos/virtio-9p.c:37:11: error: incompatible
> integer to pointer conversion initializing 'char *' with an expression
> of type 'int' [-Werror,-Wint-conversion]
> char *pwd = get_current_dir_name();
> 
> 
> thanks
> -- PMM

Oops, get_current_dir_name() is a GNU extension. I just enabled Cirrus-CI to 
prevent this from happening again. Sorry Peter.

Am I supposed to rebase for v2 PRs?

Fix for this is currently test running:

> index 1524982634..d43647b3b7 100644
> --- a/tests/qtest/libqos/virtio-9p.c
> +++ b/tests/qtest/libqos/virtio-9p.c
> @@ -34,9 +34,9 @@ static char *concat_path(const char* a, const char* b)
> 
>  static void init_local_test_path(void)
>  {
> 
> -char *pwd = get_current_dir_name();
> +char *pwd = g_get_current_dir();
> 
>  local_test_path = concat_path(pwd, "qtest-9p-local");
> 
> -free(pwd);
> +g_free(pwd);
> 
>  }
>  
>  /* Creates the directory for the 9pfs 'local' filesystem driver to access.
>  */

Best regards,
Christian Schoenebeck





[PULL 3/5] tests/9pfs: wipe local 9pfs test directory

2020-10-15 Thread Christian Schoenebeck
Before running the first 9pfs test case, make sure the test directory
for running the 9pfs 'local' tests on is entirely empty. For that
reason simply delete the test directory (if any) before (re)creating
it on test suite startup.

Note: The preferable precise behaviour would be the test directory
only being wiped once *before* a test suite run. Right now the test
directory is also wiped at the *end* of a test suite run because
libqos is calling the virtio_9p_register_nodes() callback for some
reason also when a test suite completed. This is suboptimal as
developers cannot immediately see what files and directories the
9pfs local tests created precisely after the test suite completed.
But fortunately the test directory is not wiped if some test failed.
So it is probably not worth it drilling another hole into libqos
for this issue.

Signed-off-by: Christian Schoenebeck 
Message-Id: 

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/virtio-9p.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c
index 9cb284cb3c..bd53498041 100644
--- a/tests/qtest/libqos/virtio-9p.c
+++ b/tests/qtest/libqos/virtio-9p.c
@@ -53,6 +53,18 @@ static void create_local_test_dir(void)
 g_assert((st.st_mode & S_IFMT) == S_IFDIR);
 }
 
+/* Deletes directory previously created by create_local_test_dir(). */
+static void remove_local_test_dir(void)
+{
+g_assert(local_test_path != NULL);
+char *cmd = g_strdup_printf("rm -r '%s'\n", local_test_path);
+int res = system(cmd);
+if (res < 0) {
+/* ignore error, dummy check to prevent compiler error */
+}
+g_free(cmd);
+}
+
 static void virtio_9p_cleanup(QVirtio9P *interface)
 {
 qvirtqueue_cleanup(interface->vdev->bus, interface->vq, alloc);
@@ -230,6 +242,7 @@ static void virtio_9p_register_nodes(void)
 
 /* make sure test dir for the 'local' tests exists and is clean */
 init_local_test_path();
+remove_local_test_dir();
 create_local_test_dir();
 
 QPCIAddress addr = {
-- 
2.20.1




[PULL 2/5] tests/9pfs: introduce local tests

2020-10-15 Thread Christian Schoenebeck
This patch introduces 9pfs test cases using the 9pfs 'local'
filesystem driver which reads/writes/creates/deletes real files
and directories.

In this initial version, there is only one local test which actually
only checks if the 9pfs 'local' device was created successfully.

Before the 9pfs 'local' tests are run, a test directory 'qtest-9p-local'
is created (with world rwx permissions) under the current working
directory. At this point that test directory is not auto deleted yet.

Signed-off-by: Christian Schoenebeck 
Message-Id: 
<81fc4b3b6b6c9bf7999e79f5e7cbc364a5f09ddb.1602182956.git.qemu_...@crudebyte.com>
Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/virtio-9p.c | 81 ++
 tests/qtest/libqos/virtio-9p.h |  5 +++
 tests/qtest/virtio-9p-test.c   | 44 --
 3 files changed, 116 insertions(+), 14 deletions(-)

diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c
index 2e300063e3..9cb284cb3c 100644
--- a/tests/qtest/libqos/virtio-9p.c
+++ b/tests/qtest/libqos/virtio-9p.c
@@ -24,6 +24,34 @@
 #include "qgraph.h"
 
 static QGuestAllocator *alloc;
+static char *local_test_path;
+
+/* Concatenates the passed 2 pathes. Returned result must be freed. */
+static char *concat_path(const char* a, const char* b)
+{
+return g_build_filename(a, b, NULL);
+}
+
+static void init_local_test_path(void)
+{
+char *pwd = get_current_dir_name();
+local_test_path = concat_path(pwd, "qtest-9p-local");
+free(pwd);
+}
+
+/* Creates the directory for the 9pfs 'local' filesystem driver to access. */
+static void create_local_test_dir(void)
+{
+struct stat st;
+
+g_assert(local_test_path != NULL);
+mkdir(local_test_path, 0777);
+
+/* ensure test directory exists now ... */
+g_assert(stat(local_test_path, ) == 0);
+/* ... and is actually a directory */
+g_assert((st.st_mode & S_IFMT) == S_IFDIR);
+}
 
 static void virtio_9p_cleanup(QVirtio9P *interface)
 {
@@ -146,11 +174,64 @@ static void *virtio_9p_pci_create(void *pci_bus, 
QGuestAllocator *t_alloc,
 return obj;
 }
 
+/**
+ * Performs regular expression based search and replace on @a haystack.
+ *
+ * @param haystack - input string to be parsed, result of replacement is
+ *   stored back to @a haystack
+ * @param pattern - the regular expression pattern for scanning @a haystack
+ * @param replace_fmt - matches of supplied @a pattern are replaced by this,
+ *  if necessary glib printf format can be used to add
+ *  variable arguments of this function to this
+ *  replacement string
+ */
+static void regex_replace(GString *haystack, const char *pattern,
+  const char *replace_fmt, ...)
+{
+GRegex *regex;
+char *replace, *s;
+va_list argp;
+
+va_start(argp, replace_fmt);
+replace = g_strdup_vprintf(replace_fmt, argp);
+va_end(argp);
+
+regex = g_regex_new(pattern, 0, 0, NULL);
+s = g_regex_replace(regex, haystack->str, -1, 0, replace, 0, NULL);
+g_string_assign(haystack, s);
+g_free(s);
+g_regex_unref(regex);
+g_free(replace);
+}
+
+void virtio_9p_assign_local_driver(GString *cmd_line, const char *args)
+{
+g_assert_nonnull(local_test_path);
+
+/* replace 'synth' driver by 'local' driver */
+regex_replace(cmd_line, "-fsdev synth,", "-fsdev local,");
+
+/* append 'path=...' to '-fsdev ...' group */
+regex_replace(cmd_line, "(-fsdev \\w[^ ]*)", "\\1,path='%s'",
+  local_test_path);
+
+if (!args) {
+return;
+}
+
+/* append passed args to '-fsdev ...' group */
+regex_replace(cmd_line, "(-fsdev \\w[^ ]*)", "\\1,%s", args);
+}
+
 static void virtio_9p_register_nodes(void)
 {
 const char *str_simple = "fsdev=fsdev0,mount_tag=" MOUNT_TAG;
 const char *str_addr = "fsdev=fsdev0,addr=04.0,mount_tag=" MOUNT_TAG;
 
+/* make sure test dir for the 'local' tests exists and is clean */
+init_local_test_path();
+create_local_test_dir();
+
 QPCIAddress addr = {
 .devfn = QPCI_DEVFN(4, 0),
 };
diff --git a/tests/qtest/libqos/virtio-9p.h b/tests/qtest/libqos/virtio-9p.h
index b1e6badc4a..326a603f72 100644
--- a/tests/qtest/libqos/virtio-9p.h
+++ b/tests/qtest/libqos/virtio-9p.h
@@ -44,4 +44,9 @@ struct QVirtio9PDevice {
 QVirtio9P v9p;
 };
 
+/**
+ * Prepares QEMU command line for 9pfs tests using the 'local' fs driver.
+ */
+void virtio_9p_assign_local_driver(GString *cmd_line, const char *args);
+
 #endif
diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 3281153b9c..af7e169d3a 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -895,29 +895,45 @@ static void fs_readdir_split_512(void *obj, void *data,
 fs_readdir_split(obj, data, t_alloc, 512);
 }
 

[PULL 5/5] tests/9pfs: add local Tmkdir test

2020-10-15 Thread Christian Schoenebeck
This test case uses the 9pfs 'local' driver to create a directory
and then checks if the expected directory was actually created
(as real directory) on host side.

This patch introduces a custom split() implementation, because
the test code requires non empty array elements as result. For
that reason g_strsplit() would not be a good alternative, as
it would require additional filter code for reshuffling the
array, and the resulting code would be even more complex than
this split() function.

Signed-off-by: Christian Schoenebeck 
Message-Id: 

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 139 +++
 1 file changed, 139 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index af7e169d3a..c15908f27b 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -18,6 +18,62 @@
 #define QVIRTIO_9P_TIMEOUT_US (10 * 1000 * 1000)
 static QGuestAllocator *alloc;
 
+/*
+ * Used to auto generate new fids. Start with arbitrary high value to avoid
+ * collision with hard coded fids in basic test code.
+ */
+static uint32_t fid_generator = 1000;
+
+static uint32_t genfid(void)
+{
+return fid_generator++;
+}
+
+/**
+ * Splits the @a in string by @a delim into individual (non empty) strings
+ * and outputs them to @a out. The output array @a out is NULL terminated.
+ *
+ * Output array @a out must be freed by calling split_free().
+ *
+ * @returns number of individual elements in output array @a out (without the
+ *  final NULL terminating element)
+ */
+static int split(const char *in, const char *delim, char ***out)
+{
+int n = 0, i = 0;
+char *tmp, *p;
+
+tmp = g_strdup(in);
+for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) {
+if (strlen(p) > 0) {
+++n;
+}
+}
+g_free(tmp);
+
+*out = g_new0(char *, n + 1); /* last element NULL delimiter */
+
+tmp = g_strdup(in);
+for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) {
+if (strlen(p) > 0) {
+(*out)[i++] = g_strdup(p);
+}
+}
+g_free(tmp);
+
+return n;
+}
+
+static void split_free(char ***out)
+{
+int i;
+for (i = 0; (*out)[i]; ++i) {
+g_free((*out)[i]);
+}
+g_free(*out);
+*out = NULL;
+}
+
 static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc)
 {
 QVirtio9P *v9p = obj;
@@ -201,6 +257,7 @@ static const char *rmessage_name(uint8_t id)
 id == P9_RWALK ? "RWALK" :
 id == P9_RLOPEN ? "RLOPEN" :
 id == P9_RWRITE ? "RWRITE" :
+id == P9_RMKDIR ? "RMKDIR" :
 id == P9_RFLUSH ? "RFLUSH" :
 id == P9_RREADDIR ? "READDIR" :
 "";
@@ -578,6 +635,39 @@ static bool fs_dirents_contain_name(struct V9fsDirent *e, 
const char* name)
 return false;
 }
 
+/* size[4] Tmkdir tag[2] dfid[4] name[s] mode[4] gid[4] */
+static P9Req *v9fs_tmkdir(QVirtio9P *v9p, uint32_t dfid, const char *name,
+  uint32_t mode, uint32_t gid, uint16_t tag)
+{
+P9Req *req;
+
+uint32_t body_size = 4 + 4 + 4;
+uint16_t string_size = v9fs_string_size(name);
+
+g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+body_size += string_size;
+
+req = v9fs_req_init(v9p, body_size, P9_TMKDIR, tag);
+v9fs_uint32_write(req, dfid);
+v9fs_string_write(req, name);
+v9fs_uint32_write(req, mode);
+v9fs_uint32_write(req, gid);
+v9fs_req_send(req);
+return req;
+}
+
+/* size[4] Rmkdir tag[2] qid[13] */
+static void v9fs_rmkdir(P9Req *req, v9fs_qid *qid)
+{
+v9fs_req_recv(req, P9_RMKDIR);
+if (qid) {
+v9fs_memread(req, qid, 13);
+} else {
+v9fs_memskip(req, 13);
+}
+v9fs_req_free(req);
+}
+
 /* basic readdir test where reply fits into a single response message */
 static void fs_readdir(void *obj, void *data, QGuestAllocator *t_alloc)
 {
@@ -877,6 +967,30 @@ static void fs_flush_ignored(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(wnames[0]);
 }
 
+static void fs_mkdir(void *obj, void *data, QGuestAllocator *t_alloc,
+ const char *path, const char *cname)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+char **wnames;
+char *const name = g_strdup(cname);
+P9Req *req;
+const uint32_t fid = genfid();
+
+int nwnames = split(path, "/", );
+
+req = v9fs_twalk(v9p, 0, fid, nwnames, wnames, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rwalk(req, NULL, NULL);
+
+req = v9fs_tmkdir(v9p, fid, name, 0750, 0, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rmkdir(req, NULL);
+
+g_free(name);
+split_free();
+}
+
 static void fs_readdir_split_128(void *obj, void *data,
  QGuestAllocator *t_alloc)
 {
@@ -895,6 +1009,30 @@ static void fs_readdir_split_512(void *obj, vo

[PULL 1/5] tests/9pfs: change qtest name prefix to synth

2020-10-15 Thread Christian Schoenebeck
All existing 9pfs test cases are using the 'synth' fs driver so far, which
means they are not accessing real files, but a purely simulated (in RAM
only) file system.

Let's make this clear by changing the prefix of the individual qtest case
names from 'fs/' to 'synth/'. That way they'll be easily distinguishable
from upcoming new 9pfs test cases supposed to be using a different fs
driver.

Signed-off-by: Christian Schoenebeck 
Message-Id: 

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 28 ++--
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index de30b717b6..3281153b9c 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -897,26 +897,26 @@ static void fs_readdir_split_512(void *obj, void *data,
 
 static void register_virtio_9p_test(void)
 {
-qos_add_test("config", "virtio-9p", pci_config, NULL);
-qos_add_test("fs/version/basic", "virtio-9p", fs_version, NULL);
-qos_add_test("fs/attach/basic", "virtio-9p", fs_attach, NULL);
-qos_add_test("fs/walk/basic", "virtio-9p", fs_walk, NULL);
-qos_add_test("fs/walk/no_slash", "virtio-9p", fs_walk_no_slash,
+qos_add_test("synth/config", "virtio-9p", pci_config, NULL);
+qos_add_test("synth/version/basic", "virtio-9p", fs_version, NULL);
+qos_add_test("synth/attach/basic", "virtio-9p", fs_attach, NULL);
+qos_add_test("synth/walk/basic", "virtio-9p", fs_walk, NULL);
+qos_add_test("synth/walk/no_slash", "virtio-9p", fs_walk_no_slash,
  NULL);
-qos_add_test("fs/walk/dotdot_from_root", "virtio-9p",
+qos_add_test("synth/walk/dotdot_from_root", "virtio-9p",
  fs_walk_dotdot, NULL);
-qos_add_test("fs/lopen/basic", "virtio-9p", fs_lopen, NULL);
-qos_add_test("fs/write/basic", "virtio-9p", fs_write, NULL);
-qos_add_test("fs/flush/success", "virtio-9p", fs_flush_success,
+qos_add_test("synth/lopen/basic", "virtio-9p", fs_lopen, NULL);
+qos_add_test("synth/write/basic", "virtio-9p", fs_write, NULL);
+qos_add_test("synth/flush/success", "virtio-9p", fs_flush_success,
  NULL);
-qos_add_test("fs/flush/ignored", "virtio-9p", fs_flush_ignored,
+qos_add_test("synth/flush/ignored", "virtio-9p", fs_flush_ignored,
  NULL);
-qos_add_test("fs/readdir/basic", "virtio-9p", fs_readdir, NULL);
-qos_add_test("fs/readdir/split_512", "virtio-9p",
+qos_add_test("synth/readdir/basic", "virtio-9p", fs_readdir, NULL);
+qos_add_test("synth/readdir/split_512", "virtio-9p",
  fs_readdir_split_512, NULL);
-qos_add_test("fs/readdir/split_256", "virtio-9p",
+qos_add_test("synth/readdir/split_256", "virtio-9p",
  fs_readdir_split_256, NULL);
-qos_add_test("fs/readdir/split_128", "virtio-9p",
+qos_add_test("synth/readdir/split_128", "virtio-9p",
  fs_readdir_split_128, NULL);
 }
 
-- 
2.20.1




[PULL 0/5] 9p queue 2020-10-15

2020-10-15 Thread Christian Schoenebeck
The following changes since commit 57c98ea9acdcef5021f5671efa6475a5794a51c4:

  Merge remote-tracking branch 'remotes/kraxel/tags/ui-20201014-pull-request' 
into staging (2020-10-14 13:56:06 +0100)

are available in the Git repository at:

  https://github.com/cschoenebeck/qemu.git tags/pull-9p-20201015

for you to fetch changes up to 97a64ec211d051439b654950ed3f7cffc47d489b:

  tests/9pfs: add local Tmkdir test (2020-10-15 16:11:17 +0200)


9pfs: add tests using local fs driver

The currently existing 9pfs test cases are all solely using the 9pfs 'synth'
fileystem driver, which is a very simple and purely simulated (in RAM only)
filesystem. There are issues though where the 'synth' fs driver is not
sufficient. For example the following two bugs need test cases running the
9pfs 'local' fs driver:

https://bugs.launchpad.net/qemu/+bug/1336794
https://bugs.launchpad.net/qemu/+bug/1877384

This patch set for that reason introduces 9pfs test cases using the 9pfs
'local' filesystem driver along to the already existing tests on 'synth'.


Christian Schoenebeck (5):
  tests/9pfs: change qtest name prefix to synth
  tests/9pfs: introduce local tests
  tests/9pfs: wipe local 9pfs test directory
  tests/9pfs: add virtio_9p_test_path()
  tests/9pfs: add local Tmkdir test

 tests/qtest/libqos/virtio-9p.c | 100 +
 tests/qtest/libqos/virtio-9p.h |  10 +++
 tests/qtest/virtio-9p-test.c   | 197 -
 3 files changed, 286 insertions(+), 21 deletions(-)



[PULL 4/5] tests/9pfs: add virtio_9p_test_path()

2020-10-15 Thread Christian Schoenebeck
This new public function virtio_9p_test_path() allows 9pfs
'local' tests to translate a path from guest scope to host
scope. For instance by passing an empty string it would
return the root path on host of the exported 9pfs tree.

Signed-off-by: Christian Schoenebeck 
Message-Id: 

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/virtio-9p.c | 6 ++
 tests/qtest/libqos/virtio-9p.h | 5 +
 2 files changed, 11 insertions(+)

diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c
index bd53498041..1524982634 100644
--- a/tests/qtest/libqos/virtio-9p.c
+++ b/tests/qtest/libqos/virtio-9p.c
@@ -65,6 +65,12 @@ static void remove_local_test_dir(void)
 g_free(cmd);
 }
 
+char *virtio_9p_test_path(const char *path)
+{
+g_assert(local_test_path);
+return concat_path(local_test_path, path);
+}
+
 static void virtio_9p_cleanup(QVirtio9P *interface)
 {
 qvirtqueue_cleanup(interface->vdev->bus, interface->vq, alloc);
diff --git a/tests/qtest/libqos/virtio-9p.h b/tests/qtest/libqos/virtio-9p.h
index 326a603f72..19a4d97454 100644
--- a/tests/qtest/libqos/virtio-9p.h
+++ b/tests/qtest/libqos/virtio-9p.h
@@ -49,4 +49,9 @@ struct QVirtio9PDevice {
  */
 void virtio_9p_assign_local_driver(GString *cmd_line, const char *args);
 
+/**
+ * Returns path on host to the passed guest path. Result must be freed.
+ */
+char *virtio_9p_test_path(const char *path);
+
 #endif
-- 
2.20.1




Re: [PATCH v4 08/12] tests/9pfs: change qtest name prefix to synth

2020-10-15 Thread Christian Schoenebeck
On Mittwoch, 14. Oktober 2020 21:38:16 CEST Greg Kurz wrote:
> On Wed, 14 Oct 2020 17:25:35 +0200
> 
> Christian Schoenebeck  wrote:
> > On Donnerstag, 8. Oktober 2020 20:34:56 CEST Christian Schoenebeck wrote:
> > > All existing 9pfs test cases are using the 'synth' fs driver so far,
> > > which
> > > means they are not accessing real files, but a purely simulated (in RAM
> > > only) file system.
> > > 
> > > Let's make this clear by changing the prefix of the individual qtest
> > > case
> > > names from 'fs/' to 'synth/'. That way they'll be easily distinguishable
> > > from upcoming new 9pfs test cases supposed to be using a different fs
> > > driver.
> > > 
> > > Signed-off-by: Christian Schoenebeck 
> > > ---
> > > 
> > >  tests/qtest/virtio-9p-test.c | 28 ++--
> > >  1 file changed, 14 insertions(+), 14 deletions(-)
> > 
> > Queued patches 8 .. 12 on 9p.next:
> > 
> > https://github.com/cschoenebeck/qemu/commits/9p.next
> 
> Hi Chistian,
> 
> I could only have a quick glimpse at the patches and LGTM.
> 
> Thanks for taking care.
> 
> Cheers,
> 
> --
> Greg
>

Thanks, I appreciate it.

Best regards,
Christian Schoenebeck





Re: [PATCH v4 08/12] tests/9pfs: change qtest name prefix to synth

2020-10-14 Thread Christian Schoenebeck
On Donnerstag, 8. Oktober 2020 20:34:56 CEST Christian Schoenebeck wrote:
> All existing 9pfs test cases are using the 'synth' fs driver so far, which
> means they are not accessing real files, but a purely simulated (in RAM
> only) file system.
> 
> Let's make this clear by changing the prefix of the individual qtest case
> names from 'fs/' to 'synth/'. That way they'll be easily distinguishable
> from upcoming new 9pfs test cases supposed to be using a different fs
> driver.
> 
> Signed-off-by: Christian Schoenebeck 
> ---
>  tests/qtest/virtio-9p-test.c | 28 ++--
>  1 file changed, 14 insertions(+), 14 deletions(-)

Queued patches 8 .. 12 on 9p.next:

https://github.com/cschoenebeck/qemu/commits/9p.next

Best regards,
Christian Schoenebeck





[PATCH v4 10/12] tests/9pfs: wipe local 9pfs test directory

2020-10-08 Thread Christian Schoenebeck
Before running the first 9pfs test case, make sure the test directory
for running the 9pfs 'local' tests on is entirely empty. For that
reason simply delete the test directory (if any) before (re)creating
it on test suite startup.

Note: The preferable precise behaviour would be the test directory
only being wiped once *before* a test suite run. Right now the test
directory is also wiped at the *end* of a test suite run because
libqos is calling the virtio_9p_cleanup() callback for some reason
also when a test suite completed. This is suboptimal as developers
cannot immediately see what files and directories the 9pfs local
tests created precisely after the test suite completed. But
fortunately the test directory is not wiped if some test failed.
So it is probably not worth it drilling another hole into libqos
for this issue.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/virtio-9p.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c
index 9cb284cb3c..bd53498041 100644
--- a/tests/qtest/libqos/virtio-9p.c
+++ b/tests/qtest/libqos/virtio-9p.c
@@ -53,6 +53,18 @@ static void create_local_test_dir(void)
 g_assert((st.st_mode & S_IFMT) == S_IFDIR);
 }
 
+/* Deletes directory previously created by create_local_test_dir(). */
+static void remove_local_test_dir(void)
+{
+g_assert(local_test_path != NULL);
+char *cmd = g_strdup_printf("rm -r '%s'\n", local_test_path);
+int res = system(cmd);
+if (res < 0) {
+/* ignore error, dummy check to prevent compiler error */
+}
+g_free(cmd);
+}
+
 static void virtio_9p_cleanup(QVirtio9P *interface)
 {
 qvirtqueue_cleanup(interface->vdev->bus, interface->vq, alloc);
@@ -230,6 +242,7 @@ static void virtio_9p_register_nodes(void)
 
 /* make sure test dir for the 'local' tests exists and is clean */
 init_local_test_path();
+remove_local_test_dir();
 create_local_test_dir();
 
 QPCIAddress addr = {
-- 
2.20.1




[PATCH v4 11/12] tests/9pfs: add virtio_9p_test_path()

2020-10-08 Thread Christian Schoenebeck
This new public function virtio_9p_test_path() allows 9pfs
'local' tests to translate a path from guest scope to host
scope. For instance by passing an empty string it would
return the root path on host of the exported 9pfs tree.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/virtio-9p.c | 6 ++
 tests/qtest/libqos/virtio-9p.h | 5 +
 2 files changed, 11 insertions(+)

diff --git a/tests/qtest/libqos/virtio-9p.c b/tests/qtest/libqos/virtio-9p.c
index bd53498041..1524982634 100644
--- a/tests/qtest/libqos/virtio-9p.c
+++ b/tests/qtest/libqos/virtio-9p.c
@@ -65,6 +65,12 @@ static void remove_local_test_dir(void)
 g_free(cmd);
 }
 
+char *virtio_9p_test_path(const char *path)
+{
+g_assert(local_test_path);
+return concat_path(local_test_path, path);
+}
+
 static void virtio_9p_cleanup(QVirtio9P *interface)
 {
 qvirtqueue_cleanup(interface->vdev->bus, interface->vq, alloc);
diff --git a/tests/qtest/libqos/virtio-9p.h b/tests/qtest/libqos/virtio-9p.h
index 326a603f72..19a4d97454 100644
--- a/tests/qtest/libqos/virtio-9p.h
+++ b/tests/qtest/libqos/virtio-9p.h
@@ -49,4 +49,9 @@ struct QVirtio9PDevice {
  */
 void virtio_9p_assign_local_driver(GString *cmd_line, const char *args);
 
+/**
+ * Returns path on host to the passed guest path. Result must be freed.
+ */
+char *virtio_9p_test_path(const char *path);
+
 #endif
-- 
2.20.1




[PATCH v4 12/12] tests/9pfs: add local Tmkdir test

2020-10-08 Thread Christian Schoenebeck
This test case uses the 9pfs 'local' driver to create a directory
and then checks if the expected directory was actually created
(as real directory) on host side.

This patch introduces a custom split() implementation, because
the test code requires non empty array elements as result. For
that reason g_strsplit() would not be a good alternative, as
it would require additional filter code for reshuffling the
array, and the resulting code would be even more complex than
this split() function.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 139 +++
 1 file changed, 139 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index af7e169d3a..c15908f27b 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -18,6 +18,62 @@
 #define QVIRTIO_9P_TIMEOUT_US (10 * 1000 * 1000)
 static QGuestAllocator *alloc;
 
+/*
+ * Used to auto generate new fids. Start with arbitrary high value to avoid
+ * collision with hard coded fids in basic test code.
+ */
+static uint32_t fid_generator = 1000;
+
+static uint32_t genfid(void)
+{
+return fid_generator++;
+}
+
+/**
+ * Splits the @a in string by @a delim into individual (non empty) strings
+ * and outputs them to @a out. The output array @a out is NULL terminated.
+ *
+ * Output array @a out must be freed by calling split_free().
+ *
+ * @returns number of individual elements in output array @a out (without the
+ *  final NULL terminating element)
+ */
+static int split(const char *in, const char *delim, char ***out)
+{
+int n = 0, i = 0;
+char *tmp, *p;
+
+tmp = g_strdup(in);
+for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) {
+if (strlen(p) > 0) {
+++n;
+}
+}
+g_free(tmp);
+
+*out = g_new0(char *, n + 1); /* last element NULL delimiter */
+
+tmp = g_strdup(in);
+for (p = strtok(tmp, delim); p != NULL; p = strtok(NULL, delim)) {
+if (strlen(p) > 0) {
+(*out)[i++] = g_strdup(p);
+}
+}
+g_free(tmp);
+
+return n;
+}
+
+static void split_free(char ***out)
+{
+int i;
+for (i = 0; (*out)[i]; ++i) {
+g_free((*out)[i]);
+}
+g_free(*out);
+*out = NULL;
+}
+
 static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc)
 {
 QVirtio9P *v9p = obj;
@@ -201,6 +257,7 @@ static const char *rmessage_name(uint8_t id)
 id == P9_RWALK ? "RWALK" :
 id == P9_RLOPEN ? "RLOPEN" :
 id == P9_RWRITE ? "RWRITE" :
+id == P9_RMKDIR ? "RMKDIR" :
 id == P9_RFLUSH ? "RFLUSH" :
 id == P9_RREADDIR ? "READDIR" :
 "";
@@ -578,6 +635,39 @@ static bool fs_dirents_contain_name(struct V9fsDirent *e, 
const char* name)
 return false;
 }
 
+/* size[4] Tmkdir tag[2] dfid[4] name[s] mode[4] gid[4] */
+static P9Req *v9fs_tmkdir(QVirtio9P *v9p, uint32_t dfid, const char *name,
+  uint32_t mode, uint32_t gid, uint16_t tag)
+{
+P9Req *req;
+
+uint32_t body_size = 4 + 4 + 4;
+uint16_t string_size = v9fs_string_size(name);
+
+g_assert_cmpint(body_size, <=, UINT32_MAX - string_size);
+body_size += string_size;
+
+req = v9fs_req_init(v9p, body_size, P9_TMKDIR, tag);
+v9fs_uint32_write(req, dfid);
+v9fs_string_write(req, name);
+v9fs_uint32_write(req, mode);
+v9fs_uint32_write(req, gid);
+v9fs_req_send(req);
+return req;
+}
+
+/* size[4] Rmkdir tag[2] qid[13] */
+static void v9fs_rmkdir(P9Req *req, v9fs_qid *qid)
+{
+v9fs_req_recv(req, P9_RMKDIR);
+if (qid) {
+v9fs_memread(req, qid, 13);
+} else {
+v9fs_memskip(req, 13);
+}
+v9fs_req_free(req);
+}
+
 /* basic readdir test where reply fits into a single response message */
 static void fs_readdir(void *obj, void *data, QGuestAllocator *t_alloc)
 {
@@ -877,6 +967,30 @@ static void fs_flush_ignored(void *obj, void *data, 
QGuestAllocator *t_alloc)
 g_free(wnames[0]);
 }
 
+static void fs_mkdir(void *obj, void *data, QGuestAllocator *t_alloc,
+ const char *path, const char *cname)
+{
+QVirtio9P *v9p = obj;
+alloc = t_alloc;
+char **wnames;
+char *const name = g_strdup(cname);
+P9Req *req;
+const uint32_t fid = genfid();
+
+int nwnames = split(path, "/", );
+
+req = v9fs_twalk(v9p, 0, fid, nwnames, wnames, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rwalk(req, NULL, NULL);
+
+req = v9fs_tmkdir(v9p, fid, name, 0750, 0, 0);
+v9fs_req_wait_for_reply(req, NULL);
+v9fs_rmkdir(req, NULL);
+
+g_free(name);
+split_free();
+}
+
 static void fs_readdir_split_128(void *obj, void *data,
  QGuestAllocator *t_alloc)
 {
@@ -895,6 +1009,30 @@ static void fs_readdir_split_512(void *obj, void *data,
 fs_readdir_split(obj, data, t_alloc, 512

[PATCH v4 04/12] libqos/qgraph: add qos_dump_graph()

2020-10-08 Thread Christian Schoenebeck
This new function is purely for debugging purposes. It prints the
current qos graph to stdout and allows to identify problems in the
created qos graph e.g. when writing new qos tests.

Coloured output is used to mark available nodes in green colour,
whereas unavailable nodes are marked in red colour.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/qgraph.c | 56 +
 tests/qtest/libqos/qgraph.h | 20 +
 2 files changed, 76 insertions(+)

diff --git a/tests/qtest/libqos/qgraph.c b/tests/qtest/libqos/qgraph.c
index 61faf6b27d..af93e38dcb 100644
--- a/tests/qtest/libqos/qgraph.c
+++ b/tests/qtest/libqos/qgraph.c
@@ -805,3 +805,59 @@ void qos_delete_cmd_line(const char *name)
 node->command_line = NULL;
 }
 }
+
+#define RED(txt) (\
+"\033[0;91m" txt  \
+"\033[0m" \
+)
+
+#define GREEN(txt) (  \
+"\033[0;92m" txt  \
+"\033[0m" \
+)
+
+void qos_dump_graph(void)
+{
+GList *keys;
+GList *l;
+QOSGraphEdgeList *list;
+QOSGraphEdge *e, *next;
+QOSGraphNode *dest_node, *node;
+
+qos_printf("ALL QGRAPH EDGES: {\n");
+keys = g_hash_table_get_keys(edge_table);
+for (l = keys; l != NULL; l = l->next) {
+const gchar *key = l->data;
+qos_printf("\t src='%s'\n", key);
+list = get_edgelist(key);
+QSLIST_FOREACH_SAFE(e, list, edge_list, next) {
+dest_node = g_hash_table_lookup(node_table, e->dest);
+qos_printf("\t\t|-> dest='%s' type=%d (node=%p)",
+   e->dest, e->type, dest_node);
+if (!dest_node) {
+qos_printf_literal(RED(" <--- ERROR !"));
+}
+qos_printf_literal("\n");
+}
+}
+g_list_free(keys);
+qos_printf("}\n");
+
+qos_printf("ALL QGRAPH NODES: {\n");
+keys = g_hash_table_get_keys(node_table);
+for (l = keys; l != NULL; l = l->next) {
+const gchar *key = l->data;
+node = g_hash_table_lookup(node_table, key);
+qos_printf("\t name='%s' ", key);
+if (node->qemu_name) {
+qos_printf_literal("qemu_name='%s' ", node->qemu_name);
+}
+qos_printf_literal("type=%d cmd_line='%s' [%s]\n",
+   node->type, node->command_line,
+   node->available ? GREEN("available") :
+ RED("UNAVAILBLE")
+);
+}
+g_list_free(keys);
+qos_printf("}\n");
+}
diff --git a/tests/qtest/libqos/qgraph.h b/tests/qtest/libqos/qgraph.h
index f472949f68..07a32535f1 100644
--- a/tests/qtest/libqos/qgraph.h
+++ b/tests/qtest/libqos/qgraph.h
@@ -586,5 +586,25 @@ QOSGraphObject *qos_machine_new(QOSGraphNode *node, 
QTestState *qts);
 QOSGraphObject *qos_driver_new(QOSGraphNode *node, QOSGraphObject *parent,
QGuestAllocator *alloc, void *arg);
 
+/**
+ * Just for debugging purpose: prints all currently existing nodes and
+ * edges to stdout.
+ *
+ * All qtests add themselves to the overall qos graph by calling qgraph
+ * functions that add device nodes and edges between the individual graph
+ * nodes for tests. As the actual graph is assmbled at runtime by the qos
+ * subsystem, it is sometimes not obvious how the overall graph looks like.
+ * E.g. when writing new tests it may happen that those new tests are simply
+ * ignored by the qtest framework.
+ *
+ * This function allows to identify problems in the created qgraph. Keep in
+ * mind: only tests with a path down from the actual test case node (leaf) up
+ * to the graph's root node are actually executed by the qtest framework. And
+ * the qtest framework uses QMP to automatically check which QEMU drivers are
+ * actually currently available, and accordingly qos marks certain pathes as
+ * 'unavailable' in such cases (e.g. when QEMU was compiled without support for
+ * a certain feature).
+ */
+void qos_dump_graph(void);
 
 #endif
-- 
2.20.1




[PATCH v4 03/12] libqos/qgraph_internal: add qos_printf() and qos_printf_literal()

2020-10-08 Thread Christian Schoenebeck
These two are macros wrapping regular printf() call. They are intended
to be used instead of calling printf() directly in order to avoid
breaking TAP output format.

TAP output format is enabled by using --tap command line argument.
Starting with glib 2.62 it is enabled by default.

Unfortunately there is currently no public glib API available to check
whether TAP output format is enabled. For that reason qos_printf()
simply always prepends a '#' character for now.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/qgraph_internal.h | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/tests/qtest/libqos/qgraph_internal.h 
b/tests/qtest/libqos/qgraph_internal.h
index 974985dce9..c0025f5ab9 100644
--- a/tests/qtest/libqos/qgraph_internal.h
+++ b/tests/qtest/libqos/qgraph_internal.h
@@ -255,4 +255,15 @@ void qos_delete_cmd_line(const char *name);
  */
 void qos_graph_node_set_availability(const char *node, bool av);
 
+/*
+ * Prepends a '#' character in front for not breaking TAP output format.
+ */
+#define qos_printf(...) printf("# " __VA_ARGS__)
+
+/*
+ * Intended for printing something literally, i.e. for appending text as is
+ * to a line already been started by qos_printf() before.
+ */
+#define qos_printf_literal printf
+
 #endif
-- 
2.20.1




[PATCH v4 08/12] tests/9pfs: change qtest name prefix to synth

2020-10-08 Thread Christian Schoenebeck
All existing 9pfs test cases are using the 'synth' fs driver so far, which
means they are not accessing real files, but a purely simulated (in RAM
only) file system.

Let's make this clear by changing the prefix of the individual qtest case
names from 'fs/' to 'synth/'. That way they'll be easily distinguishable
from upcoming new 9pfs test cases supposed to be using a different fs
driver.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/virtio-9p-test.c | 28 ++--
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index de30b717b6..3281153b9c 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -897,26 +897,26 @@ static void fs_readdir_split_512(void *obj, void *data,
 
 static void register_virtio_9p_test(void)
 {
-qos_add_test("config", "virtio-9p", pci_config, NULL);
-qos_add_test("fs/version/basic", "virtio-9p", fs_version, NULL);
-qos_add_test("fs/attach/basic", "virtio-9p", fs_attach, NULL);
-qos_add_test("fs/walk/basic", "virtio-9p", fs_walk, NULL);
-qos_add_test("fs/walk/no_slash", "virtio-9p", fs_walk_no_slash,
+qos_add_test("synth/config", "virtio-9p", pci_config, NULL);
+qos_add_test("synth/version/basic", "virtio-9p", fs_version, NULL);
+qos_add_test("synth/attach/basic", "virtio-9p", fs_attach, NULL);
+qos_add_test("synth/walk/basic", "virtio-9p", fs_walk, NULL);
+qos_add_test("synth/walk/no_slash", "virtio-9p", fs_walk_no_slash,
  NULL);
-qos_add_test("fs/walk/dotdot_from_root", "virtio-9p",
+qos_add_test("synth/walk/dotdot_from_root", "virtio-9p",
  fs_walk_dotdot, NULL);
-qos_add_test("fs/lopen/basic", "virtio-9p", fs_lopen, NULL);
-qos_add_test("fs/write/basic", "virtio-9p", fs_write, NULL);
-qos_add_test("fs/flush/success", "virtio-9p", fs_flush_success,
+qos_add_test("synth/lopen/basic", "virtio-9p", fs_lopen, NULL);
+qos_add_test("synth/write/basic", "virtio-9p", fs_write, NULL);
+qos_add_test("synth/flush/success", "virtio-9p", fs_flush_success,
  NULL);
-qos_add_test("fs/flush/ignored", "virtio-9p", fs_flush_ignored,
+qos_add_test("synth/flush/ignored", "virtio-9p", fs_flush_ignored,
  NULL);
-qos_add_test("fs/readdir/basic", "virtio-9p", fs_readdir, NULL);
-qos_add_test("fs/readdir/split_512", "virtio-9p",
+qos_add_test("synth/readdir/basic", "virtio-9p", fs_readdir, NULL);
+qos_add_test("synth/readdir/split_512", "virtio-9p",
  fs_readdir_split_512, NULL);
-qos_add_test("fs/readdir/split_256", "virtio-9p",
+qos_add_test("synth/readdir/split_256", "virtio-9p",
  fs_readdir_split_256, NULL);
-qos_add_test("fs/readdir/split_128", "virtio-9p",
+qos_add_test("synth/readdir/split_128", "virtio-9p",
  fs_readdir_split_128, NULL);
 }
 
-- 
2.20.1




[PATCH v4 05/12] tests/qtest/qos-test: dump qos graph if verbose

2020-10-08 Thread Christian Schoenebeck
If qtests were run in verbose mode (i.e. if --verbose CL argument was
provided) then dump the generated qos graph (all nodes and edges,
along with their current individual availability status) to stdout.

See API doc comment on function qos_dump_graph() for details.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/qos-test.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/tests/qtest/qos-test.c b/tests/qtest/qos-test.c
index 8fdf87b183..d98ef78613 100644
--- a/tests/qtest/qos-test.c
+++ b/tests/qtest/qos-test.c
@@ -322,6 +322,9 @@ int main(int argc, char **argv)
 qos_set_machines_devices_available();
 
 qos_graph_foreach_test_path(walk_path);
+if (g_test_verbose()) {
+qos_dump_graph();
+}
 g_test_run();
 qtest_end();
 qos_graph_destroy();
-- 
2.20.1




[PATCH v4 07/12] tests/qtest/qos-test: dump QEMU command if verbose

2020-10-08 Thread Christian Schoenebeck
If qtests are run in verbose mode (i.e. if --verbose CL argument
was provided) then print the assembled qemu command line for each
test.

Use qos_printf() instead of g_test_message() to avoid the latter
cluttering the output.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/qos-test.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/tests/qtest/qos-test.c b/tests/qtest/qos-test.c
index b279b6f816..f97d0a08fd 100644
--- a/tests/qtest/qos-test.c
+++ b/tests/qtest/qos-test.c
@@ -89,6 +89,9 @@ static void qos_set_machines_devices_available(void)
 
 static void restart_qemu_or_continue(char *path)
 {
+if (g_test_verbose()) {
+qos_printf("Run QEMU with: '%s'\n", path);
+}
 /* compares the current command line with the
  * one previously executed: if they are the same,
  * don't restart QEMU, if they differ, stop previous
-- 
2.20.1




[PATCH v4 02/12] libqos/qgraph: add qos_node_create_driver_named()

2020-10-08 Thread Christian Schoenebeck
So far the qos subsystem of the qtest framework had the limitation
that only one instance of the same official QEMU (QMP) driver name
could be created for qtests. That's because a) the created qos
node names must always be unique, b) the node name must match the
official QEMU driver name being instantiated and c) all nodes are
in a global space shared by all tests.

This patch removes this limitation by introducing a new function
qos_node_create_driver_named() which allows test case authors to
specify a node name being different from the actual associated
QEMU driver name. It fills the new 'qemu_name' field of
QOSGraphNode for that purpose.

Adjust build_driver_cmd_line() and qos_graph_node_set_availability()
to correctly deal with either accessing node name vs. node's
qemu_name correctly.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/qgraph.c | 53 ++---
 tests/qtest/libqos/qgraph.h | 16 +++
 2 files changed, 66 insertions(+), 3 deletions(-)

diff --git a/tests/qtest/libqos/qgraph.c b/tests/qtest/libqos/qgraph.c
index e42f3eaafa..61faf6b27d 100644
--- a/tests/qtest/libqos/qgraph.c
+++ b/tests/qtest/libqos/qgraph.c
@@ -287,7 +287,8 @@ static void build_machine_cmd_line(QOSGraphNode *node, 
const char *args)
  */
 static void build_driver_cmd_line(QOSGraphNode *node)
 {
-node->command_line = g_strconcat(" -device ", node->name, NULL);
+const char *name = node->qemu_name ?: node->name;
+node->command_line = g_strconcat(" -device ", name, NULL);
 }
 
 /* qos_print_cb(): callback prints all path found by the DFS algorithm. */
@@ -632,6 +633,15 @@ void qos_node_create_driver(const char *name, 
QOSCreateDriverFunc function)
 node->u.driver.constructor = function;
 }
 
+void qos_node_create_driver_named(const char *name, const char *qemu_name,
+  QOSCreateDriverFunc function)
+{
+QOSGraphNode *node = create_node(name, QNODE_DRIVER);
+node->qemu_name = g_strdup(qemu_name);
+build_driver_cmd_line(node);
+node->u.driver.constructor = function;
+}
+
 void qos_node_contains(const char *container, const char *contained,
QOSGraphEdgeOptions *opts, ...)
 {
@@ -664,7 +674,7 @@ void qos_node_consumes(const char *consumer, const char 
*interface,
 add_edge(interface, consumer, QEDGE_CONSUMED_BY, opts);
 }
 
-void qos_graph_node_set_availability(const char *node, bool av)
+static void qos_graph_node_set_availability_explicit(const char *node, bool av)
 {
 QOSGraphEdgeList *elist;
 QOSGraphNode *n = search_node(node);
@@ -679,9 +689,46 @@ void qos_graph_node_set_availability(const char *node, 
bool av)
 }
 QSLIST_FOREACH_SAFE(e, elist, edge_list, next) {
 if (e->type == QEDGE_CONTAINS || e->type == QEDGE_PRODUCES) {
-qos_graph_node_set_availability(e->dest, av);
+qos_graph_node_set_availability_explicit(e->dest, av);
+}
+}
+}
+
+/*
+ * Behaves as qos_graph_node_set_availability_explicit(), except that the
+ * former always matches by node name only, whereas this function matches both
+ * by node name and node's optional 'qemu_name' field.
+ */
+void qos_graph_node_set_availability(const char *node, bool av)
+{
+GList *l;
+QOSGraphEdgeList *elist;
+QOSGraphEdge *e, *next;
+QOSGraphNode *n;
+GList *keys = g_hash_table_get_keys(node_table);
+
+for (l = keys; l != NULL; l = l->next) {
+const gchar *key = l->data;
+n = g_hash_table_lookup(node_table, key);
+/*
+ * node's 'qemu_name' is set if there is more than one device with
+ * the same QEMU (QMP) device name
+ */
+const char *node_name = n->qemu_name ?: n->name;
+if (g_strcmp0(node_name, node) == 0) {
+n->available = av;
+elist = get_edgelist(n->name);
+if (elist) {
+QSLIST_FOREACH_SAFE(e, elist, edge_list, next) {
+if (e->type == QEDGE_CONTAINS || e->type == QEDGE_PRODUCES)
+{
+qos_graph_node_set_availability_explicit(e->dest, av);
+}
+}
+}
 }
 }
+g_list_free(keys);
 }
 
 void qos_graph_foreach_test_path(QOSTestCallback fn)
diff --git a/tests/qtest/libqos/qgraph.h b/tests/qtest/libqos/qgraph.h
index 5f63d352ca..f472949f68 100644
--- a/tests/qtest/libqos/qgraph.h
+++ b/tests/qtest/libqos/qgraph.h
@@ -452,6 +452,22 @@ void qos_node_create_machine_args(const char *name,
  */
 void qos_node_create_driver(const char *name, QOSCreateDriverFunc function);
 
+/**
+ * Behaves as qos_node_create_driver() with the extension of allowing to
+ * specify a different node name vs. associated QEMU device name.
+ *
+ * Use this function instead of qos_node_create_driver() if you need to create
+ * several instances of the same QEMU device. You 

[PATCH v4 01/12] libqos/qgraph: add qemu_name to QOSGraphNode

2020-10-08 Thread Christian Schoenebeck
Add new member variable 'qemu_name' to struct QOSGraphNode.

This new member may be optionally set in case a different
name for the node (which must always be a unique name) vs.
its actually associated QEMU (QMP) device name is required.

Signed-off-by: Christian Schoenebeck 
---
 tests/qtest/libqos/qgraph.c  | 1 +
 tests/qtest/libqos/qgraph_internal.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/tests/qtest/libqos/qgraph.c b/tests/qtest/libqos/qgraph.c
index fc49cfa879..e42f3eaafa 100644
--- a/tests/qtest/libqos/qgraph.c
+++ b/tests/qtest/libqos/qgraph.c
@@ -153,6 +153,7 @@ static QOSGraphNode *create_node(const char *name, 
QOSNodeType type)
 static void destroy_node(void *val)
 {
 QOSGraphNode *node = val;
+g_free(node->qemu_name);
 g_free(node->command_line);
 g_free(node);
 }
diff --git a/tests/qtest/libqos/qgraph_internal.h 
b/tests/qtest/libqos/qgraph_internal.h
index 968fa69450..974985dce9 100644
--- a/tests/qtest/libqos/qgraph_internal.h
+++ b/tests/qtest/libqos/qgraph_internal.h
@@ -56,6 +56,7 @@ struct QOSGraphNode {
 bool available; /* set by QEMU via QMP, used during graph walk */
 bool visited;   /* used during graph walk */
 char *name; /* used to identify the node */
+char *qemu_name;/* optional: see qos_node_create_driver_named() */
 char *command_line; /* used to start QEMU at test execution */
 union {
 struct {
-- 
2.20.1




<    5   6   7   8   9   10   11   12   13   14   >