summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJanusz Krzysztofik <janusz.krzysztofik@linux.intel.com>2020-07-18 17:20:11 +0200
committerJanusz Krzysztofik <janusz.krzysztofik@linux.intel.com>2020-09-14 20:47:03 +0200
commitece0974cb59ff3bec7e888ea4b41126db961c016 (patch)
tree83b19f7f38fd03244f1a48424c9a956dc7445470
parent845b99ddadf809a3ff2563d8d7615f691bb6afee (diff)
tests/core_hotunplug: Recover from subtest failures
Subtests now forcibly call or request igt_abort on failures in order to avoid silently leaving an exercised device in an unusable state. However, a failure inside a subtest doesn't always mean the device is no longer working correctly and reboot is needed. On the other hand, if a subtest just fails without aborting, that doesn't mean in turn the device is healthy. We should still perform a device health check in that case before deciding on next steps. Reuse the 'failure' structure field as a mark which is set before each critical operation is executed that must be followed by a successful health check in order to avoid aborting the test. Then, follow each subtest with its individual igt_fixture section, from where device file descriptors potentially left open are closed, device rediscover or driver rebing operation is run as needed, and finally the health check is run again if the preceding igt_subtest section has exited with the marker set. v2: Start each recovery phase from unconditionally closing file descriptors potentially left open by a subtest before it entered its critical section, - replace igt_require() with 'if() return;' construct in recover() to reduce noise, - replace "subtest failure" message used as a request for healthcheck with a more appropriate "need healthcheck" for clarity, - rebase on current upstream master. v3: Refresh, - move bus_rescan() and driver_bind() function calls back from heaalthcheck() to recover() so a pure health check can still be called from a subtest if essential, - move failure mark assignments back from subtests to helpers for more adequate abort reason reporting but clean the mark only on health check success, - call cleanup() also from post_healthcheck() in order to close a device file descriptor potentially left open by a failed health check, - reword commit message and update description. v4: Close exercised device fd before failing a health check run, - don't drop health checks from subtest bodies, their results should always matter. v5: Refresh. Signed-off-by: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com> Reviewed-by: MichaƂ Winiarski <michal.winiarski@intel.com>
-rw-r--r--tests/core_hotunplug.c100
1 files changed, 74 insertions, 26 deletions
diff --git a/tests/core_hotunplug.c b/tests/core_hotunplug.c
index d5152602..7fc6df68 100644
--- a/tests/core_hotunplug.c
+++ b/tests/core_hotunplug.c
@@ -78,12 +78,18 @@ static int local_close(int fd, const char *warning)
static int close_device(int fd_drm, const char *when, const char *which)
{
+ if (fd_drm < 0) /* not open - return current status */
+ return fd_drm;
+
igt_debug("%sclosing %sdevice instance\n", when, which);
return local_close(fd_drm, "Device close failed");
}
static int close_sysfs(int fd_sysfs_dev)
{
+ if (fd_sysfs_dev < 0) /* not open - return current status */
+ return fd_sysfs_dev;
+
return local_close(fd_sysfs_dev, "Device sysfs node close failed");
}
@@ -117,24 +123,22 @@ static void prepare(struct hotunplug *priv)
static void driver_unbind(struct hotunplug *priv, const char *prefix)
{
igt_debug("%sunbinding the driver from the device\n", prefix);
+ priv->failure = "Driver unbind failure!";
- priv->failure = "Driver unbind timeout!";
- igt_set_timeout(60, priv->failure);
+ igt_set_timeout(60, "Driver unbind timeout!");
igt_sysfs_set(priv->fd.sysfs_drv, "unbind", priv->dev_bus_addr);
igt_reset_timeout();
- priv->failure = NULL;
}
/* Re-bind the driver to the device */
static void driver_bind(struct hotunplug *priv)
{
igt_debug("rebinding the driver to the device\n");
+ priv->failure = "Driver re-bind failure!";
- priv->failure = "Driver re-bind timeout!";
- igt_set_timeout(60, priv->failure);
+ igt_set_timeout(60, "Driver re-bind timeout!");
igt_sysfs_set(priv->fd.sysfs_drv, "bind", priv->dev_bus_addr);
igt_reset_timeout();
- priv->failure = NULL;
}
/* Remove (virtually unplug) the device from its bus */
@@ -147,12 +151,11 @@ static void device_unplug(struct hotunplug *priv, const char *prefix)
igt_assert_fd(priv->fd.sysfs_dev);
igt_debug("%sunplugging the device\n", prefix);
+ priv->failure = "Device unplug failure!";
- priv->failure = "Device unplug timeout!";
- igt_set_timeout(60, priv->failure);
+ igt_set_timeout(60, "Device unplug timeout!");
igt_sysfs_set(priv->fd.sysfs_dev, "remove", "1");
igt_reset_timeout();
- priv->failure = NULL;
priv->fd.sysfs_dev = close_sysfs(priv->fd.sysfs_dev);
}
@@ -161,12 +164,17 @@ static void device_unplug(struct hotunplug *priv, const char *prefix)
static void bus_rescan(struct hotunplug *priv)
{
igt_debug("rediscovering the device\n");
+ priv->failure = "Bus rescan failure!";
- priv->failure = "Bus rescan timeout!";
- igt_set_timeout(60, priv->failure);
+ igt_set_timeout(60, "Bus rescan timeout!");
igt_sysfs_set(priv->fd.sysfs_bus, "../rescan", "1");
igt_reset_timeout();
- priv->failure = NULL;
+}
+
+static void cleanup(struct hotunplug *priv)
+{
+ priv->fd.drm = close_device(priv->fd.drm, "post ", "failed ");
+ priv->fd.sysfs_dev = close_sysfs(priv->fd.sysfs_dev);
}
static void healthcheck(struct hotunplug *priv)
@@ -180,25 +188,45 @@ static void healthcheck(struct hotunplug *priv)
priv->failure = "Device reopen failure!";
fd_drm = local_drm_open_driver("re", " for health check");
- if (closed) /* store fd for post_healthcheck if not dirty */
+ if (closed) /* store fd for cleanup if not dirty */
priv->fd.drm = fd_drm;
- priv->failure = NULL;
if (is_i915_device(fd_drm)) {
priv->failure = "GEM failure";
igt_require_gem(fd_drm);
priv->failure = NULL;
+ } else {
+ /* no device specific healthcheck, rely on reopen result */
+ priv->failure = NULL;
}
fd_drm = close_device(fd_drm, "", "health checked ");
if (closed || fd_drm < -1) /* update status for post_healthcheck */
priv->fd.drm = fd_drm;
+
+ /* not only request igt_abort on failure, also fail the health check */
+ igt_fail_on_f(priv->failure, "%s\n", priv->failure);
+}
+
+static void recover(struct hotunplug *priv)
+{
+ cleanup(priv);
+
+ if (faccessat(priv->fd.sysfs_bus, priv->dev_bus_addr, F_OK, 0))
+ bus_rescan(priv);
+
+ else if (faccessat(priv->fd.sysfs_drv, priv->dev_bus_addr, F_OK, 0))
+ driver_bind(priv);
+
+ if (priv->failure)
+ healthcheck(priv);
}
static void post_healthcheck(struct hotunplug *priv)
{
igt_abort_on_f(priv->failure, "%s\n", priv->failure);
+ cleanup(priv);
igt_require(priv->fd.drm == -1);
}
@@ -297,30 +325,50 @@ igt_main
prepare(&priv);
}
- igt_describe("Check if the driver can be cleanly unbound from a device believed to be closed");
- igt_subtest("unbind-rebind")
- unbind_rebind(&priv);
+ igt_subtest_group {
+ igt_describe("Check if the driver can be cleanly unbound from a device believed to be closed");
+ igt_subtest("unbind-rebind")
+ unbind_rebind(&priv);
+
+ igt_fixture
+ recover(&priv);
+ }
igt_fixture
post_healthcheck(&priv);
- igt_describe("Check if a device believed to be closed can be cleanly unplugged");
- igt_subtest("unplug-rescan")
- unplug_rescan(&priv);
+ igt_subtest_group {
+ igt_describe("Check if a device believed to be closed can be cleanly unplugged");
+ igt_subtest("unplug-rescan")
+ unplug_rescan(&priv);
+
+ igt_fixture
+ recover(&priv);
+ }
igt_fixture
post_healthcheck(&priv);
- igt_describe("Check if the driver can be cleanly unbound from a still open device, then released");
- igt_subtest("hotunbind-lateclose")
- hotunbind_lateclose(&priv);
+ igt_subtest_group {
+ igt_describe("Check if the driver can be cleanly unbound from a still open device, then released");
+ igt_subtest("hotunbind-lateclose")
+ hotunbind_lateclose(&priv);
+
+ igt_fixture
+ recover(&priv);
+ }
igt_fixture
post_healthcheck(&priv);
- igt_describe("Check if a still open device can be cleanly unplugged, then released");
- igt_subtest("hotunplug-lateclose")
- hotunplug_lateclose(&priv);
+ igt_subtest_group {
+ igt_describe("Check if a still open device can be cleanly unplugged, then released");
+ igt_subtest("hotunplug-lateclose")
+ hotunplug_lateclose(&priv);
+
+ igt_fixture
+ recover(&priv);
+ }
igt_fixture {
post_healthcheck(&priv);