This series adds the initial support for ppc64le Book3s with Radix
MMU.
At this time I'm including only the kvm_page_table test and a dummy
test to serve as a sample of what can be done with these tests. I
intend to make a pass over the remaining common tests and add the ones
which could be built for powerpc as well.
patch 1: a prerequisite small fix for the powerpc vcpu_ioctl. It is
the same I already sent to the ppc mailing list but I'll
include it here to make this a complete series.
patch 2: the actual infrastructure support.
Fabiano Rosas (2):
KVM: PPC: Book3S HV: Stop returning internal values to userspace
KVM: selftests: Add support for ppc64le
MAINTAINERS | 3 +
arch/powerpc/kvm/powerpc.c | 8 +
tools/testing/selftests/kvm/.gitignore | 1 +
tools/testing/selftests/kvm/Makefile | 14 +-
.../selftests/kvm/include/kvm_util_base.h | 7 +
.../selftests/kvm/include/ppc64le/processor.h | 43 +++
tools/testing/selftests/kvm/lib/kvm_util.c | 5 +
.../testing/selftests/kvm/lib/powerpc/hcall.S | 6 +
.../selftests/kvm/lib/powerpc/processor.c | 343 ++++++++++++++++++
.../testing/selftests/kvm/lib/powerpc/ucall.c | 67 ++++
.../selftests/kvm/powerpc/sample_test.c | 144 ++++++++
11 files changed, 638 insertions(+), 3 deletions(-)
create mode 100644 tools/testing/selftests/kvm/include/ppc64le/processor.h
create mode 100644 tools/testing/selftests/kvm/lib/powerpc/hcall.S
create mode 100644 tools/testing/selftests/kvm/lib/powerpc/processor.c
create mode 100644 tools/testing/selftests/kvm/lib/powerpc/ucall.c
create mode 100644 tools/testing/selftests/kvm/powerpc/sample_test.c
--
2.34.1
Hi Linus,
Please pull the following KUnit fixes update for Linux 5.17-rc3.
This kunit update for Linux 5.17-rc3 consists of a single fix to
an error seen on qemu due to a missing import.
diff is attached.
thanks,
-- Shuah
----------------------------------------------------------------
The following changes since commit e783362eb54cd99b2cac8b3a9aeac942e6f6ac07:
Linux 5.17-rc1 (2022-01-23 10:12:53 +0200)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest tags/linux-kselftest-kunit-fixes-5.17-rc3
for you to fetch changes up to 235528072f28b3b0a1446279b7eaddda36dbf743:
kunit: tool: Import missing importlib.abc (2022-01-25 12:59:43 -0700)
----------------------------------------------------------------
linux-kselftest-kunit-fixes-5.17-rc3
This kunit update for Linux 5.17-rc3 consists of a single fix to an error
seen on qemu due to a missing import.
----------------------------------------------------------------
Michał Winiarski (1):
kunit: tool: Import missing importlib.abc
tools/testing/kunit/kunit_kernel.py | 1 +
1 file changed, 1 insertion(+)
----------------------------------------------------------------
When running the pidfd_fdinfo_test on arm64, it fails for me. After some
digging, the reason is that the child exits due to SIGBUS, because it
overflows the 1024 byte stack we've reserved for it.
To fix the issue, increase the stack size to 8192 bytes (this number is
somewhat arbitrary, and was arrived at through experimentation -- I kept
doubling until the failure no longer occurred).
Also, let's make the issue easier to debug. wait_for_pid() returns an
ambiguous value: it may return -1 in all of these cases:
1. waitpid() itself returned -1
2. waitpid() returned success, but we found !WIFEXITED(status).
3. The child process exited, but it did so with a -1 exit code.
There's no way for the caller to tell the difference. So, at least log
which occurred, so the test runner can debug things.
While debugging this, I found that we had !WIFEXITED(), because the
child exited due to a signal. This seems like a reasonably common case,
so also print out whether or not we have WIFSIGNALED(), and the
associated WTERMSIG() (if any). This lets us see the SIGBUS I'm fixing
clearly when it occurs.
Finally, I'm suspicious of allocating the child's stack on our stack.
man clone(2) suggests that the correct way to do this is with mmap(),
and in particular by setting MAP_STACK. So, switch to doing it that way
instead.
Signed-off-by: Axel Rasmussen <axelrasmussen(a)google.com>
---
tools/testing/selftests/pidfd/pidfd.h | 13 ++++++++---
.../selftests/pidfd/pidfd_fdinfo_test.c | 22 +++++++++++++++----
2 files changed, 28 insertions(+), 7 deletions(-)
diff --git a/tools/testing/selftests/pidfd/pidfd.h b/tools/testing/selftests/pidfd/pidfd.h
index 01f8d3c0cf2c..6922d6417e1c 100644
--- a/tools/testing/selftests/pidfd/pidfd.h
+++ b/tools/testing/selftests/pidfd/pidfd.h
@@ -68,7 +68,7 @@
#define PIDFD_SKIP 3
#define PIDFD_XFAIL 4
-int wait_for_pid(pid_t pid)
+static inline int wait_for_pid(pid_t pid)
{
int status, ret;
@@ -78,13 +78,20 @@ int wait_for_pid(pid_t pid)
if (errno == EINTR)
goto again;
+ ksft_print_msg("waitpid returned -1, errno=%d\n", errno);
return -1;
}
- if (!WIFEXITED(status))
+ if (!WIFEXITED(status)) {
+ ksft_print_msg(
+ "waitpid !WIFEXITED, WIFSIGNALED=%d, WTERMSIG=%d\n",
+ WIFSIGNALED(status), WTERMSIG(status));
return -1;
+ }
- return WEXITSTATUS(status);
+ ret = WEXITSTATUS(status);
+ ksft_print_msg("waitpid WEXITSTATUS=%d\n", ret);
+ return ret;
}
static inline int sys_pidfd_open(pid_t pid, unsigned int flags)
diff --git a/tools/testing/selftests/pidfd/pidfd_fdinfo_test.c b/tools/testing/selftests/pidfd/pidfd_fdinfo_test.c
index 22558524f71c..3fd8e903118f 100644
--- a/tools/testing/selftests/pidfd/pidfd_fdinfo_test.c
+++ b/tools/testing/selftests/pidfd/pidfd_fdinfo_test.c
@@ -12,6 +12,7 @@
#include <string.h>
#include <syscall.h>
#include <sys/wait.h>
+#include <sys/mman.h>
#include "pidfd.h"
#include "../kselftest.h"
@@ -80,7 +81,10 @@ static inline int error_check(struct error *err, const char *test_name)
return err->code;
}
+#define CHILD_STACK_SIZE 8192
+
struct child {
+ char *stack;
pid_t pid;
int fd;
};
@@ -89,17 +93,22 @@ static struct child clone_newns(int (*fn)(void *), void *args,
struct error *err)
{
static int flags = CLONE_PIDFD | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD;
- size_t stack_size = 1024;
- char *stack[1024] = { 0 };
struct child ret;
if (!(flags & CLONE_NEWUSER) && geteuid() != 0)
flags |= CLONE_NEWUSER;
+ ret.stack = mmap(NULL, CHILD_STACK_SIZE, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
+ if (ret.stack == MAP_FAILED) {
+ error_set(err, -1, "mmap of stack failed (errno %d)", errno);
+ return ret;
+ }
+
#ifdef __ia64__
- ret.pid = __clone2(fn, stack, stack_size, flags, args, &ret.fd);
+ ret.pid = __clone2(fn, ret.stack, CHILD_STACK_SIZE, flags, args, &ret.fd);
#else
- ret.pid = clone(fn, stack + stack_size, flags, args, &ret.fd);
+ ret.pid = clone(fn, ret.stack + CHILD_STACK_SIZE, flags, args, &ret.fd);
#endif
if (ret.pid < 0) {
@@ -129,6 +138,11 @@ static inline int child_join(struct child *child, struct error *err)
else if (r > 0)
error_set(err, r, "child %d reported: %d", child->pid, r);
+ if (munmap(child->stack, CHILD_STACK_SIZE)) {
+ error_set(err, -1, "munmap of child stack failed (errno %d)", errno);
+ r = -1;
+ }
+
return r;
}
--
2.35.0.rc2.247.g8bbb082509-goog
Add some coverage of event generation to mixer-test. Rather than doing a
separate set of writes designed to trigger events we add a step to the
existing write_and_verify() which checks to see if the value we read back
from non-volatile controls matches the value before writing and that an
event is or isn't generated as appropriate. The "tests" for events then
simply check that no spurious or missing events were detected. This avoids
needing further logic to generate appropriate values for each control type
and maximises coverage.
When checking for events we use a timeout of 0. This relies on the kernel
generating any event prior to returning to userspace when setting a control.
That is currently the case and it is difficult to see it changing, if it
does the test will need to be updated. Using a delay of 0 means that we
don't slow things down unduly when checking for no event or when events
fail to be generated.
We don't check behaviour for volatile controls since we can't tell what
the behaviour is supposed to be for any given control.
Signed-off-by: Mark Brown <broonie(a)kernel.org>
Reviewed-by: Shuah Khan <skhan(a)linuxfoundation.org>
---
v2:
- Get the numid from the API rather than using the control index.
tools/testing/selftests/alsa/mixer-test.c | 148 +++++++++++++++++++++-
1 file changed, 145 insertions(+), 3 deletions(-)
diff --git a/tools/testing/selftests/alsa/mixer-test.c b/tools/testing/selftests/alsa/mixer-test.c
index 0e88f4f3d802..79ffbca429ee 100644
--- a/tools/testing/selftests/alsa/mixer-test.c
+++ b/tools/testing/selftests/alsa/mixer-test.c
@@ -3,7 +3,7 @@
// kselftest for the ALSA mixer API
//
// Original author: Mark Brown <broonie(a)kernel.org>
-// Copyright (c) 2021 Arm Limited
+// Copyright (c) 2021-2 Arm Limited
// This test will iterate over all cards detected in the system, exercising
// every mixer control it can find. This may conflict with other system
@@ -27,11 +27,12 @@
#include "../kselftest.h"
-#define TESTS_PER_CONTROL 4
+#define TESTS_PER_CONTROL 6
struct card_data {
snd_ctl_t *handle;
int card;
+ struct pollfd pollfd;
int num_ctls;
snd_ctl_elem_list_t *ctls;
struct card_data *next;
@@ -43,6 +44,8 @@ struct ctl_data {
snd_ctl_elem_info_t *info;
snd_ctl_elem_value_t *def_val;
int elem;
+ int event_missing;
+ int event_spurious;
struct card_data *card;
struct ctl_data *next;
};
@@ -149,6 +152,7 @@ void find_controls(void)
if (!ctl_data)
ksft_exit_fail_msg("Out of memory\n");
+ memset(ctl_data, 0, sizeof(*ctl_data));
ctl_data->card = card_data;
ctl_data->elem = ctl;
ctl_data->name = snd_ctl_elem_list_get_name(card_data->ctls,
@@ -184,6 +188,26 @@ void find_controls(void)
ctl_list = ctl_data;
}
+ /* Set up for events */
+ err = snd_ctl_subscribe_events(card_data->handle, true);
+ if (err < 0) {
+ ksft_exit_fail_msg("snd_ctl_subscribe_events() failed for card %d: %d\n",
+ card, err);
+ }
+
+ err = snd_ctl_poll_descriptors_count(card_data->handle);
+ if (err != 1) {
+ ksft_exit_fail_msg("Unexpected desciptor count %d for card %d\n",
+ err, card);
+ }
+
+ err = snd_ctl_poll_descriptors(card_data->handle,
+ &card_data->pollfd, 1);
+ if (err != 1) {
+ ksft_exit_fail_msg("snd_ctl_poll_descriptors() failed for %d\n",
+ card, err);
+ }
+
next_card:
if (snd_card_next(&card) < 0) {
ksft_print_msg("snd_card_next");
@@ -194,6 +218,73 @@ void find_controls(void)
snd_config_delete(config);
}
+/*
+ * Block for up to timeout ms for an event, returns a negative value
+ * on error, 0 for no event and 1 for an event.
+ */
+int wait_for_event(struct ctl_data *ctl, int timeout)
+{
+ unsigned short revents;
+ snd_ctl_event_t *event;
+ int count, err;
+ unsigned int mask = 0;
+ unsigned int ev_id;
+
+ snd_ctl_event_alloca(&event);
+
+ do {
+ err = poll(&(ctl->card->pollfd), 1, timeout);
+ if (err < 0) {
+ ksft_print_msg("poll() failed for %s: %s (%d)\n",
+ ctl->name, strerror(errno), errno);
+ return -1;
+ }
+ /* Timeout */
+ if (err == 0)
+ return 0;
+
+ err = snd_ctl_poll_descriptors_revents(ctl->card->handle,
+ &(ctl->card->pollfd),
+ 1, &revents);
+ if (err < 0) {
+ ksft_print_msg("snd_ctl_poll_desciptors_revents() failed for %s: %d\n",
+ ctl->name, err);
+ return err;
+ }
+ if (revents & POLLERR) {
+ ksft_print_msg("snd_ctl_poll_desciptors_revents() reported POLLERR for %s\n",
+ ctl->name);
+ return -1;
+ }
+ /* No read events */
+ if (!(revents & POLLIN)) {
+ ksft_print_msg("No POLLIN\n");
+ continue;
+ }
+
+ err = snd_ctl_read(ctl->card->handle, event);
+ if (err < 0) {
+ ksft_print_msg("snd_ctl_read() failed for %s: %d\n",
+ ctl->name, err);
+ return err;
+ }
+
+ if (snd_ctl_event_get_type(event) != SND_CTL_EVENT_ELEM)
+ continue;
+
+ /* The ID returned from the event is 1 less than numid */
+ mask = snd_ctl_event_elem_get_mask(event);
+ ev_id = snd_ctl_event_elem_get_numid(event);
+ if (ev_id != snd_ctl_elem_info_get_numid(ctl->info)) {
+ ksft_print_msg("Event for unexpected ctl %s\n",
+ snd_ctl_event_elem_get_name(event));
+ continue;
+ }
+ } while ((mask & SND_CTL_EVENT_MASK_VALUE) != SND_CTL_EVENT_MASK_VALUE);
+
+ return 1;
+}
+
bool ctl_value_index_valid(struct ctl_data *ctl, snd_ctl_elem_value_t *val,
int index)
{
@@ -428,7 +519,8 @@ int write_and_verify(struct ctl_data *ctl,
{
int err, i;
bool error_expected, mismatch_shown;
- snd_ctl_elem_value_t *read_val, *w_val;
+ snd_ctl_elem_value_t *initial_val, *read_val, *w_val;
+ snd_ctl_elem_value_alloca(&initial_val);
snd_ctl_elem_value_alloca(&read_val);
snd_ctl_elem_value_alloca(&w_val);
@@ -446,6 +538,18 @@ int write_and_verify(struct ctl_data *ctl,
snd_ctl_elem_value_copy(expected_val, write_val);
}
+ /* Store the value before we write */
+ if (snd_ctl_elem_info_is_readable(ctl->info)) {
+ snd_ctl_elem_value_set_id(initial_val, ctl->id);
+
+ err = snd_ctl_elem_read(ctl->card->handle, initial_val);
+ if (err < 0) {
+ ksft_print_msg("snd_ctl_elem_read() failed: %s\n",
+ snd_strerror(err));
+ return err;
+ }
+ }
+
/*
* Do the write, if we have an expected value ignore the error
* and carry on to validate the expected value.
@@ -470,6 +574,30 @@ int write_and_verify(struct ctl_data *ctl,
return err;
}
+ /*
+ * Check for an event if the value changed, or confirm that
+ * there was none if it didn't. We rely on the kernel
+ * generating the notification before it returns from the
+ * write, this is currently true, should that ever change this
+ * will most likely break and need updating.
+ */
+ if (!snd_ctl_elem_info_is_volatile(ctl->info)) {
+ err = wait_for_event(ctl, 0);
+ if (snd_ctl_elem_value_compare(initial_val, read_val)) {
+ if (err < 1) {
+ ksft_print_msg("No event generated for %s\n",
+ ctl->name);
+ ctl->event_missing++;
+ }
+ } else {
+ if (err != 0) {
+ ksft_print_msg("Spurious event generated for %s\n",
+ ctl->name);
+ ctl->event_spurious++;
+ }
+ }
+ }
+
/*
* Use the libray to compare values, if there's a mismatch
* carry on and try to provide a more useful diagnostic than
@@ -898,6 +1026,18 @@ void test_ctl_write_invalid(struct ctl_data *ctl)
ctl->card->card, ctl->elem);
}
+void test_ctl_event_missing(struct ctl_data *ctl)
+{
+ ksft_test_result(!ctl->event_missing, "event_missing.%d.%d\n",
+ ctl->card->card, ctl->elem);
+}
+
+void test_ctl_event_spurious(struct ctl_data *ctl)
+{
+ ksft_test_result(!ctl->event_spurious, "event_spurious.%d.%d\n",
+ ctl->card->card, ctl->elem);
+}
+
int main(void)
{
struct ctl_data *ctl;
@@ -917,6 +1057,8 @@ int main(void)
test_ctl_write_default(ctl);
test_ctl_write_valid(ctl);
test_ctl_write_invalid(ctl);
+ test_ctl_event_missing(ctl);
+ test_ctl_event_spurious(ctl);
}
ksft_exit_pass();
--
2.30.2
Add some coverage of event generation to mixer-test. Rather than doing a
separate set of writes designed to trigger events we add a step to the
existing write_and_verify() which checks to see if the value we read back
from non-volatile controls matches the value before writing and that an
event is or isn't generated as appropriate. The "tests" for events then
simply check that no spurious or missing events were detected. This avoids
needing further logic to generate appropriate values for each control type
and maximises coverage.
When checking for events we use a timeout of 0. This relies on the kernel
generating any event prior to returning to userspace when setting a control.
That is currently the case and it is difficult to see it changing, if it
does the test will need to be updated. Using a delay of 0 means that we
don't slow things down unduly when checking for no event or when events
fail to be generated.
We don't check behaviour for volatile controls since we can't tell what
the behaviour is supposed to be for any given control.
Signed-off-by: Mark Brown <broonie(a)kernel.org>
---
tools/testing/selftests/alsa/mixer-test.c | 148 +++++++++++++++++++++-
1 file changed, 145 insertions(+), 3 deletions(-)
diff --git a/tools/testing/selftests/alsa/mixer-test.c b/tools/testing/selftests/alsa/mixer-test.c
index 0e88f4f3d802..42cf3b724586 100644
--- a/tools/testing/selftests/alsa/mixer-test.c
+++ b/tools/testing/selftests/alsa/mixer-test.c
@@ -3,7 +3,7 @@
// kselftest for the ALSA mixer API
//
// Original author: Mark Brown <broonie(a)kernel.org>
-// Copyright (c) 2021 Arm Limited
+// Copyright (c) 2021-2 Arm Limited
// This test will iterate over all cards detected in the system, exercising
// every mixer control it can find. This may conflict with other system
@@ -27,11 +27,12 @@
#include "../kselftest.h"
-#define TESTS_PER_CONTROL 4
+#define TESTS_PER_CONTROL 6
struct card_data {
snd_ctl_t *handle;
int card;
+ struct pollfd pollfd;
int num_ctls;
snd_ctl_elem_list_t *ctls;
struct card_data *next;
@@ -43,6 +44,8 @@ struct ctl_data {
snd_ctl_elem_info_t *info;
snd_ctl_elem_value_t *def_val;
int elem;
+ int event_missing;
+ int event_spurious;
struct card_data *card;
struct ctl_data *next;
};
@@ -149,6 +152,7 @@ void find_controls(void)
if (!ctl_data)
ksft_exit_fail_msg("Out of memory\n");
+ memset(ctl_data, 0, sizeof(*ctl_data));
ctl_data->card = card_data;
ctl_data->elem = ctl;
ctl_data->name = snd_ctl_elem_list_get_name(card_data->ctls,
@@ -184,6 +188,26 @@ void find_controls(void)
ctl_list = ctl_data;
}
+ /* Set up for events */
+ err = snd_ctl_subscribe_events(card_data->handle, true);
+ if (err < 0) {
+ ksft_exit_fail_msg("snd_ctl_subscribe_events() failed for card %d: %d\n",
+ card, err);
+ }
+
+ err = snd_ctl_poll_descriptors_count(card_data->handle);
+ if (err != 1) {
+ ksft_exit_fail_msg("Unexpected desciptor count %d for card %d\n",
+ err, card);
+ }
+
+ err = snd_ctl_poll_descriptors(card_data->handle,
+ &card_data->pollfd, 1);
+ if (err != 1) {
+ ksft_exit_fail_msg("snd_ctl_poll_descriptors() failed for %d\n",
+ card, err);
+ }
+
next_card:
if (snd_card_next(&card) < 0) {
ksft_print_msg("snd_card_next");
@@ -194,6 +218,73 @@ void find_controls(void)
snd_config_delete(config);
}
+/*
+ * Block for up to timeout ms for an event, returns a negative value
+ * on error, 0 for no event and 1 for an event.
+ */
+int wait_for_event(struct ctl_data *ctl, int timeout)
+{
+ unsigned short revents;
+ snd_ctl_event_t *event;
+ int count, err;
+ unsigned int mask = 0;
+ unsigned int ev_id;
+
+ snd_ctl_event_alloca(&event);
+
+ do {
+ err = poll(&(ctl->card->pollfd), 1, timeout);
+ if (err < 0) {
+ ksft_print_msg("poll() failed for %s: %s (%d)\n",
+ ctl->name, strerror(errno), errno);
+ return -1;
+ }
+ /* Timeout */
+ if (err == 0)
+ return 0;
+
+ err = snd_ctl_poll_descriptors_revents(ctl->card->handle,
+ &(ctl->card->pollfd),
+ 1, &revents);
+ if (err < 0) {
+ ksft_print_msg("snd_ctl_poll_desciptors_revents() failed for %s: %d\n",
+ ctl->name, err);
+ return err;
+ }
+ if (revents & POLLERR) {
+ ksft_print_msg("snd_ctl_poll_desciptors_revents() reported POLLERR for %s\n",
+ ctl->name);
+ return -1;
+ }
+ /* No read events */
+ if (!(revents & POLLIN)) {
+ ksft_print_msg("No POLLIN\n");
+ continue;
+ }
+
+ err = snd_ctl_read(ctl->card->handle, event);
+ if (err < 0) {
+ ksft_print_msg("snd_ctl_read() failed for %s: %d\n",
+ ctl->name, err);
+ return err;
+ }
+
+ if (snd_ctl_event_get_type(event) != SND_CTL_EVENT_ELEM)
+ continue;
+
+ /* The ID returned from the event is 1 less than numid */
+ mask = snd_ctl_event_elem_get_mask(event);
+ ev_id = snd_ctl_event_elem_get_numid(event);
+ if (ev_id != ctl->elem + 1) {
+ ksft_print_msg("Event for unexpected ctl %s\n",
+ snd_ctl_event_elem_get_name(event));
+ continue;
+ }
+ } while ((mask & SND_CTL_EVENT_MASK_VALUE) != SND_CTL_EVENT_MASK_VALUE);
+
+ return 1;
+}
+
bool ctl_value_index_valid(struct ctl_data *ctl, snd_ctl_elem_value_t *val,
int index)
{
@@ -428,7 +519,8 @@ int write_and_verify(struct ctl_data *ctl,
{
int err, i;
bool error_expected, mismatch_shown;
- snd_ctl_elem_value_t *read_val, *w_val;
+ snd_ctl_elem_value_t *initial_val, *read_val, *w_val;
+ snd_ctl_elem_value_alloca(&initial_val);
snd_ctl_elem_value_alloca(&read_val);
snd_ctl_elem_value_alloca(&w_val);
@@ -446,6 +538,18 @@ int write_and_verify(struct ctl_data *ctl,
snd_ctl_elem_value_copy(expected_val, write_val);
}
+ /* Store the value before we write */
+ if (snd_ctl_elem_info_is_readable(ctl->info)) {
+ snd_ctl_elem_value_set_id(initial_val, ctl->id);
+
+ err = snd_ctl_elem_read(ctl->card->handle, initial_val);
+ if (err < 0) {
+ ksft_print_msg("snd_ctl_elem_read() failed: %s\n",
+ snd_strerror(err));
+ return err;
+ }
+ }
+
/*
* Do the write, if we have an expected value ignore the error
* and carry on to validate the expected value.
@@ -470,6 +574,30 @@ int write_and_verify(struct ctl_data *ctl,
return err;
}
+ /*
+ * Check for an event if the value changed, or confirm that
+ * there was none if it didn't. We rely on the kernel
+ * generating the notification before it returns from the
+ * write, this is currently true, should that ever change this
+ * will most likely break and need updating.
+ */
+ if (!snd_ctl_elem_info_is_volatile(ctl->info)) {
+ err = wait_for_event(ctl, 0);
+ if (snd_ctl_elem_value_compare(initial_val, read_val)) {
+ if (err < 1) {
+ ksft_print_msg("No event generated for %s\n",
+ ctl->name);
+ ctl->event_missing++;
+ }
+ } else {
+ if (err != 0) {
+ ksft_print_msg("Spurious event generated for %s\n",
+ ctl->name);
+ ctl->event_spurious++;
+ }
+ }
+ }
+
/*
* Use the libray to compare values, if there's a mismatch
* carry on and try to provide a more useful diagnostic than
@@ -898,6 +1026,18 @@ void test_ctl_write_invalid(struct ctl_data *ctl)
ctl->card->card, ctl->elem);
}
+void test_ctl_event_missing(struct ctl_data *ctl)
+{
+ ksft_test_result(!ctl->event_missing, "event_missing.%d.%d\n",
+ ctl->card->card, ctl->elem);
+}
+
+void test_ctl_event_spurious(struct ctl_data *ctl)
+{
+ ksft_test_result(!ctl->event_spurious, "event_spurious.%d.%d\n",
+ ctl->card->card, ctl->elem);
+}
+
int main(void)
{
struct ctl_data *ctl;
@@ -917,6 +1057,8 @@ int main(void)
test_ctl_write_default(ctl);
test_ctl_write_valid(ctl);
test_ctl_write_invalid(ctl);
+ test_ctl_event_missing(ctl);
+ test_ctl_event_spurious(ctl);
}
ksft_exit_pass();
--
2.30.2
Dzień dobry!
Czy mógłbym przedstawić rozwiązanie, które umożliwia monitoring każdego auta w czasie rzeczywistym w tym jego pozycję, zużycie paliwa i przebieg?
Dodatkowo nasze narzędzie minimalizuje koszty utrzymania samochodów, skraca czas przejazdów, a także tworzenie planu tras czy dostaw.
Z naszej wiedzy i doświadczenia korzysta już ponad 49 tys. Klientów. Monitorujemy 809 000 pojazdów na całym świecie, co jest naszą najlepszą wizytówką.
Bardzo proszę o e-maila zwrotnego, jeśli moglibyśmy wspólnie omówić potencjał wykorzystania takiego rozwiązania w Państwa firmie.
Z poważaniem,
Mateusz Talaga
The first half of these patch set improves the code logic and has no
user visible effect. The second half improves the script output, to
make it clearer and nicer to read.
Guillaume Nault (4):
selftests: fib rule: Make 'getmatch' and 'match' local variables
selftests: fib rule: Drop erroneous TABLE variable
selftests: fib rule: Log test description
selftests: fib rule: Don't echo modified sysctls
tools/testing/selftests/net/fib_rule_tests.sh | 26 ++++++++++++-------
1 file changed, 17 insertions(+), 9 deletions(-)
--
2.21.3