From: Clemens Famulla-Conrad <cfamullaconrad@suse.de>
To: ltp@lists.linux.it
Subject: [LTP] [PATCH v2 2/5] kernel/uevent: Add uevent01
Date: Wed, 21 Aug 2019 18:35:22 +0200 [thread overview]
Message-ID: <1566405322.3587.21.camel@suse.de> (raw)
In-Reply-To: <20190820151831.7418-3-chrubis@suse.cz>
Hi Cyril,
On Tue, 2019-08-20 at 17:18 +0200, Cyril Hrubis wrote:
> Simple test that attached and detaches a file to a loop device and
> checks that kernel broadcasts correct events to the kernel uevent
> broadcast group.
>
> Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
> ---
> runtest/uevent | 1 +
> scenario_groups/default | 1 +
> testcases/kernel/uevents/.gitignore | 1 +
> testcases/kernel/uevents/Makefile | 6 +
> testcases/kernel/uevents/uevent.h | 176
> ++++++++++++++++++++++++++++
> testcases/kernel/uevents/uevent01.c | 90 ++++++++++++++
> 6 files changed, 275 insertions(+)
> create mode 100644 runtest/uevent
> create mode 100644 testcases/kernel/uevents/.gitignore
> create mode 100644 testcases/kernel/uevents/Makefile
> create mode 100644 testcases/kernel/uevents/uevent.h
> create mode 100644 testcases/kernel/uevents/uevent01.c
>
> diff --git a/runtest/uevent b/runtest/uevent
> new file mode 100644
> index 000000000..e9cdf26b8
> --- /dev/null
> +++ b/runtest/uevent
> @@ -0,0 +1 @@
> +uevent01 uevent01
> diff --git a/scenario_groups/default b/scenario_groups/default
> index 093f5f706..62ae0759d 100644
> --- a/scenario_groups/default
> +++ b/scenario_groups/default
> @@ -29,3 +29,4 @@ input
> cve
> crypto
> kernel_misc
> +uevent
> diff --git a/testcases/kernel/uevents/.gitignore
> b/testcases/kernel/uevents/.gitignore
> new file mode 100644
> index 000000000..53d0b546a
> --- /dev/null
> +++ b/testcases/kernel/uevents/.gitignore
> @@ -0,0 +1 @@
> +uevent01
> diff --git a/testcases/kernel/uevents/Makefile
> b/testcases/kernel/uevents/Makefile
> new file mode 100644
> index 000000000..cba769739
> --- /dev/null
> +++ b/testcases/kernel/uevents/Makefile
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +
> +top_srcdir ?= ../../..
> +
> +include $(top_srcdir)/include/mk/testcases.mk
> +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> diff --git a/testcases/kernel/uevents/uevent.h
> b/testcases/kernel/uevents/uevent.h
> new file mode 100644
> index 000000000..2c32dd534
> --- /dev/null
> +++ b/testcases/kernel/uevents/uevent.h
> @@ -0,0 +1,176 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2019 Cyril Hrubis <chrubis@suse.cz>
> + */
> +
> +#ifndef UEVENT_H__
> +#define UEVENT_H__
> +
> +#include "tst_netlink.h"
> +
> +/*
> + * There are two broadcast groups defined for the
> NETLINK_KOBJECT_UEVENT. The
> + * primary consument of the KERNEL group is udev which handles the
> hotplug
> + * events and then, once udev does it's magic the events are
> rebroadcasted to
> + * the UDEV group which is consumed by various daemons in the
> userspace.
> + */
> +enum monitor_netlink_group {
> + MONITOR_GROUP_NONE,
> + MONITOR_GROUP_KERNEL,
> + MONITOR_GROUP_UDEV,
> +};
> +
> +/*
> + * The messages received from the NETLINK_KOBJECT_UEVENT socket are
> stored as a
> + * sequence of a null-terminated strings. First in the buffer is a
> summary of a
> + * action i.e. "$ACTION@$DEVPATH" which is then followed by a bunch
> of
> + * key-value pairs.
> + *
> + * For example attaching a file to loopback device generates event:
> + *
> + * "change@/devices/virtual/block/loop0\0
> + * ACTION=change\0
> + * DEVPATH=/devices/virtual/block/loop0\0
> + * SUBSYSTEM=block\0
> + * MAJOR=7\0
> + * MINOR=0\0
> + * DEVNAME=loop0\0
> + * DEVTYPE=disk\0
> + * SEQNUM=2677\0"
> + */
> +
> +/*
> + * Prints uevent.
> + */
> +static inline void print_uevent(const char *event, int len)
> +{
> + int consumed = 0;
> +
> + tst_res(TINFO, "Got uevent:");
> +
> + while (consumed < len) {
> + tst_res(TINFO, "%s", event);
> + int l = strlen(event) + 1;
> + consumed += l;
> + event += l;
> + }
> +}
> +
> +/*
> + * Uevents read from the socket are matched against this
> description.
> + *
> + * The msg is the overall action description e.g.
> + * "add@/class/input/input4/mouse1" which has to be matched exactly
> before we
> + * event attempt to check the key-value pairs stored in the values
> array. The
> + * event is considered to match if all key-value pairs in the values
> has been
> + * found in the received event.
> + */
> +struct uevent_desc {
> + const char *msg;
> + int value_cnt;
> + const char **values;
> +};
> +
> +static inline int uevent_match(const char *event, int len,
> + const struct uevent_desc *uevent)
> +{
> + int consumed = 0;
> + int val_matches = 0;
> +
> + if (memcmp(event, uevent->msg, strlen(uevent->msg)))
> + return 0;
> +
> + int l = strlen(event) + 1;
> +
> + consumed += l;
> + event += l;
> +
> + while (consumed < len) {
> + int i;
> + for (i = 0; i < uevent->value_cnt; i++) {
> + if (!strcmp(event, uevent->values[i])) {
> + val_matches++;
> + break;
> + }
> + }
> +
> + l = strlen(event) + 1;
> + consumed += l;
> + event += l;
> + }
> +
> + return val_matches == uevent->value_cnt;
> +}
> +
> +static inline int open_uevent_netlink(void)
> +{
> + int fd;
> + struct sockaddr_nl nl_addr = {
> + .nl_family = AF_NETLINK,
> + .nl_groups = MONITOR_GROUP_KERNEL,
> + };
> +
> + fd = SAFE_SOCKET(AF_NETLINK, SOCK_RAW,
> NETLINK_KOBJECT_UEVENT);
> +
> + SAFE_BIND(fd, (struct sockaddr *)&nl_addr, sizeof(nl_addr));
> +
> + return fd;
> +}
> +
> +/*
> + * Reads events from uevent netlink socket until all expected events
> passed in
> + * the uevent array are matched.
> + */
> +static inline void wait_for_uevents(int fd, const struct uevent_desc
> *const uevents[])
> +{
> + int i = 0;
> +
> + while (1) {
> + int len;
> + char buf[4096];
> +
> + len = recv(fd, &buf, sizeof(buf), 0);
> +
> + if (len == 0)
> + continue;
> +
> + print_uevent(buf, len);
> +
> + if (uevent_match(buf, len, uevents[i])) {
> + tst_res(TPASS, "Got expected UEVENT");
> + if (!uevents[++i]) {
> + close(fd);
> + exit(0);
> + }
> + }
> + }
> +}
> +
> +/*
> + * Waits 5 seconds for a child to exit, kills the child after a
> timeout.
> + */
> +static inline void wait_for_pid(int pid)
> +{
> + int status, ret;
> + int retries = 5000;
> +
> + do {
> + ret = waitpid(pid, &status, WNOHANG);
> + usleep(1000);
> + } while (ret == 0 && retries--);
> +
> + if (ret == pid) {
> + if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
> + return;
> +
> + tst_res(TFAIL, "Child exitted with %s",
> tst_strstatus(status));
> + }
> +
> + SAFE_KILL(pid, SIGKILL);
> +
> + SAFE_WAITPID(pid, NULL, 0);
> +
> + tst_res(TFAIL, "Did not get all expected UEVENTS");
> +}
> +
> +#endif /* UEVENT_H__ */
> diff --git a/testcases/kernel/uevents/uevent01.c
> b/testcases/kernel/uevents/uevent01.c
> new file mode 100644
> index 000000000..41cd01b1f
> --- /dev/null
> +++ b/testcases/kernel/uevents/uevent01.c
> @@ -0,0 +1,90 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2019 Cyril Hrubis <chrubis@suse.cz>
> + */
> +
> +/*
> + * Very simple uevent netlink socket test.
> + *
> + * We fork a child that listens for a kernel events while parents
> attaches and
> + * detaches a loop device which should produce two change events.
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/wait.h>
> +#include "tst_test.h"
> +
> +#include "uevent.h"
> +
> +static void generate_device_events(const char *dev_path)
> +{
> + tst_fill_file("loop.img", 0, 1024, 1024);
> +
> + tst_res(TINFO, "Attaching device %s", dev_path);
> + tst_attach_device(dev_path, "loop.img");
> + tst_res(TINFO, "Detaching device %s", dev_path);
> + tst_detach_device(dev_path);
> +}
> +
> +static void verify_uevent(void)
> +{
> + int pid, fd, dev_num;
> + char dev_path[1024];
> + char ev_msg[1024];
> + char ev_dev_path[1024];
> + char ev_dev_minor[128];
> + char ev_dev_name[128];
> +
> + struct uevent_desc desc = {
> + .msg = ev_msg,
> + .value_cnt = 7,
> + .values = (const char*[]) {
> + "ACTION=change",
> + ev_dev_path,
> + "SUBSYSTEM=block",
> + "MAJOR=7",
> + ev_dev_minor,
> + ev_dev_name,
> + "DEVTYPE=disk",
> + }
> + };
> +
> + dev_num = tst_find_free_loopdev(dev_path, sizeof(dev_path));
Maybe it isn't worth to check if dev_num is a valid number.
> +
> + snprintf(ev_msg, sizeof(ev_msg),
> + "change@/devices/virtual/block/loop%i", dev_num);
> +
> + snprintf(ev_dev_path, sizeof(ev_dev_path),
> + "DEVPATH=/devices/virtual/block/loop%i", dev_num);
> +
> + snprintf(ev_dev_minor, sizeof(ev_dev_minor), "MINOR=%i",
> dev_num);
> + snprintf(ev_dev_name, sizeof(ev_dev_name), "DEVNAME=loop%i",
> dev_num);
> +
> + const struct uevent_desc *const uevents[] = {
> + &desc,
> + &desc,
> + NULL
> + };
> +
> + pid = SAFE_FORK();
> + if (!pid) {
> + fd = open_uevent_netlink();
> + TST_CHECKPOINT_WAKE(0);
> + wait_for_uevents(fd, uevents);
For me it wasn't obvious that wait_for_uevents() does the exit(). Not
sure if we should do the exit better here or name the function like
exit_on_uevents().
> + }
> +
> + TST_CHECKPOINT_WAIT(0);
> +
> + generate_device_events(dev_path);
> +
> + wait_for_pid(pid);
> +}
> +
> +static struct tst_test test = {
> + .test_all = verify_uevent,
> + .forks_child = 1,
> + .needs_tmpdir = 1,
Just curious, where do we need the tmpdir?
> + .needs_checkpoints = 1,
> + .needs_root = 1,
> +};
> --
> 2.21.0
>
>
thx
Clemens
next prev parent reply other threads:[~2019-08-21 16:35 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-08-20 15:18 [LTP] [PATCH v1 0/5] Add basic test for uevent netlink socket Cyril Hrubis
2019-08-20 15:18 ` [LTP] [PATCH v2 1/5] lib/tst_device: Export more functions Cyril Hrubis
2019-08-22 9:31 ` Clemens Famulla-Conrad
2019-08-20 15:18 ` [LTP] [PATCH v2 2/5] kernel/uevent: Add uevent01 Cyril Hrubis
2019-08-21 16:35 ` Clemens Famulla-Conrad [this message]
2019-08-26 11:47 ` Cyril Hrubis
2019-08-20 15:18 ` [LTP] [PATCH v2 3/5] kernel/uevent: Add uevent02 Cyril Hrubis
2019-08-21 16:35 ` Clemens Famulla-Conrad
2019-08-26 11:45 ` Cyril Hrubis
2019-08-20 15:18 ` [LTP] [PATCH v2 4/5] libs/libltpuinput: Add uinput library Cyril Hrubis
2019-08-22 9:12 ` Clemens Famulla-Conrad
2019-08-20 15:18 ` [LTP] [PATCH v2 5/5] kernel/uevent: Add uevent03 Cyril Hrubis
2019-08-22 9:00 ` Clemens Famulla-Conrad
2019-08-26 13:55 ` Cyril Hrubis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1566405322.3587.21.camel@suse.de \
--to=cfamullaconrad@suse.de \
--cc=ltp@lists.linux.it \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.