Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kunit: Add APIs for managing devices

Tests for drivers often require a struct device to pass to other
functions. While it's possible to create these with
root_device_register(), or to use something like a platform device, this
is both a misuse of those APIs, and can be difficult to clean up after,
for example, a failed assertion.

Add some KUnit-specific functions for registering and unregistering a
struct device:
- kunit_device_register()
- kunit_device_register_with_driver()
- kunit_device_unregister()

These helpers allocate a on a 'kunit' bus which will either probe the
driver passed in (kunit_device_register_with_driver), or will create a
stub driver (kunit_device_register) which is cleaned up on test shutdown.

Devices are automatically unregistered on test shutdown, but can be
manually unregistered earlier with kunit_device_unregister() in order
to, for example, test device release code.

Reviewed-by: Matti Vaittinen <mazziesaccount@gmail.com>
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: David Gow <davidgow@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>

authored by

davidgow@google.com and committed by
Shuah Khan
d03c720e e9f0e21c

+475 -2
+9
Documentation/dev-tools/kunit/api/resource.rst
··· 11 11 12 12 .. kernel-doc:: include/kunit/resource.h 13 13 :internal: 14 + 15 + Managed Devices 16 + --------------- 17 + 18 + Functions for using KUnit-managed struct device and struct device_driver. 19 + Include ``kunit/device.h`` to use these. 20 + 21 + .. kernel-doc:: include/kunit/device.h 22 + :internal:
+50
Documentation/dev-tools/kunit/usage.rst
··· 797 797 KUnit is not enabled, or if no test is running in the current task, it will do 798 798 nothing. This compiles down to either a no-op or a static key check, so will 799 799 have a negligible performance impact when no test is running. 800 + 801 + Managing Fake Devices and Drivers 802 + --------------------------------- 803 + 804 + When testing drivers or code which interacts with drivers, many functions will 805 + require a ``struct device`` or ``struct device_driver``. In many cases, setting 806 + up a real device is not required to test any given function, so a fake device 807 + can be used instead. 808 + 809 + KUnit provides helper functions to create and manage these fake devices, which 810 + are internally of type ``struct kunit_device``, and are attached to a special 811 + ``kunit_bus``. These devices support managed device resources (devres), as 812 + described in Documentation/driver-api/driver-model/devres.rst 813 + 814 + To create a KUnit-managed ``struct device_driver``, use ``kunit_driver_create()``, 815 + which will create a driver with the given name, on the ``kunit_bus``. This driver 816 + will automatically be destroyed when the corresponding test finishes, but can also 817 + be manually destroyed with ``driver_unregister()``. 818 + 819 + To create a fake device, use the ``kunit_device_register()``, which will create 820 + and register a device, using a new KUnit-managed driver created with ``kunit_driver_create()``. 821 + To provide a specific, non-KUnit-managed driver, use ``kunit_device_register_with_driver()`` 822 + instead. Like with managed drivers, KUnit-managed fake devices are automatically 823 + cleaned up when the test finishes, but can be manually cleaned up early with 824 + ``kunit_device_unregister()``. 825 + 826 + The KUnit devices should be used in preference to ``root_device_register()``, and 827 + instead of ``platform_device_register()`` in cases where the device is not otherwise 828 + a platform device. 829 + 830 + For example: 831 + 832 + .. code-block:: c 833 + 834 + #include <kunit/device.h> 835 + 836 + static void test_my_device(struct kunit *test) 837 + { 838 + struct device *fake_device; 839 + const char *dev_managed_string; 840 + 841 + // Create a fake device. 842 + fake_device = kunit_device_register(test, "my_device"); 843 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_device) 844 + 845 + // Pass it to functions which need a device. 846 + dev_managed_string = devm_kstrdup(fake_device, "Hello, World!"); 847 + 848 + // Everything is cleaned up automatically when the test ends. 849 + }
+80
include/kunit/device.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * KUnit basic device implementation 4 + * 5 + * Helpers for creating and managing fake devices for KUnit tests. 6 + * 7 + * Copyright (C) 2023, Google LLC. 8 + * Author: David Gow <davidgow@google.com> 9 + */ 10 + 11 + #ifndef _KUNIT_DEVICE_H 12 + #define _KUNIT_DEVICE_H 13 + 14 + #if IS_ENABLED(CONFIG_KUNIT) 15 + 16 + #include <kunit/test.h> 17 + 18 + struct device; 19 + struct device_driver; 20 + 21 + /** 22 + * kunit_driver_create() - Create a struct device_driver attached to the kunit_bus 23 + * @test: The test context object. 24 + * @name: The name to give the created driver. 25 + * 26 + * Creates a struct device_driver attached to the kunit_bus, with the name @name. 27 + * This driver will automatically be cleaned up on test exit. 28 + * 29 + * Return: a stub struct device_driver, managed by KUnit, with the name @name. 30 + */ 31 + struct device_driver *kunit_driver_create(struct kunit *test, const char *name); 32 + 33 + /** 34 + * kunit_device_register() - Create a struct device for use in KUnit tests 35 + * @test: The test context object. 36 + * @name: The name to give the created device. 37 + * 38 + * Creates a struct kunit_device (which is a struct device) with the given name, 39 + * and a corresponding driver. The device and driver will be cleaned up on test 40 + * exit, or when kunit_device_unregister is called. See also 41 + * kunit_device_register_with_driver, if you wish to provide your own 42 + * struct device_driver. 43 + * 44 + * Return: a pointer to a struct device which will be cleaned up when the test 45 + * exits, or an error pointer if the device could not be allocated or registered. 46 + */ 47 + struct device *kunit_device_register(struct kunit *test, const char *name); 48 + 49 + /** 50 + * kunit_device_register_with_driver() - Create a struct device for use in KUnit tests 51 + * @test: The test context object. 52 + * @name: The name to give the created device. 53 + * @drv: The struct device_driver to associate with the device. 54 + * 55 + * Creates a struct kunit_device (which is a struct device) with the given 56 + * name, and driver. The device will be cleaned up on test exit, or when 57 + * kunit_device_unregister is called. See also kunit_device_register, if you 58 + * wish KUnit to create and manage a driver for you. 59 + * 60 + * Return: a pointer to a struct device which will be cleaned up when the test 61 + * exits, or an error pointer if the device could not be allocated or registered. 62 + */ 63 + struct device *kunit_device_register_with_driver(struct kunit *test, 64 + const char *name, 65 + const struct device_driver *drv); 66 + 67 + /** 68 + * kunit_device_unregister() - Unregister a KUnit-managed device 69 + * @test: The test context object which created the device 70 + * @dev: The device. 71 + * 72 + * Unregisters and destroys a struct device which was created with 73 + * kunit_device_register or kunit_device_register_with_driver. If KUnit created 74 + * a driver, cleans it up as well. 75 + */ 76 + void kunit_device_unregister(struct kunit *test, struct device *dev); 77 + 78 + #endif 79 + 80 + #endif
+2 -1
lib/kunit/Makefile
··· 7 7 assert.o \ 8 8 try-catch.o \ 9 9 executor.o \ 10 - attributes.o 10 + attributes.o \ 11 + device.o 11 12 12 13 ifeq ($(CONFIG_KUNIT_DEBUGFS),y) 13 14 kunit-objs += debugfs.o
+17
lib/kunit/device-impl.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * KUnit internal header for device helpers 4 + * 5 + * Header for KUnit-internal driver / bus management. 6 + * 7 + * Copyright (C) 2023, Google LLC. 8 + * Author: David Gow <davidgow@google.com> 9 + */ 10 + 11 + #ifndef _KUNIT_DEVICE_IMPL_H 12 + #define _KUNIT_DEVICE_IMPL_H 13 + 14 + // For internal use only -- registers the kunit_bus. 15 + int kunit_bus_init(void); 16 + 17 + #endif //_KUNIT_DEVICE_IMPL_H
+181
lib/kunit/device.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * KUnit-managed device implementation 4 + * 5 + * Implementation of struct kunit_device helpers for fake devices whose 6 + * lifecycle is managed by KUnit. 7 + * 8 + * Copyright (C) 2023, Google LLC. 9 + * Author: David Gow <davidgow@google.com> 10 + */ 11 + 12 + #include <linux/device.h> 13 + 14 + #include <kunit/test.h> 15 + #include <kunit/device.h> 16 + #include <kunit/resource.h> 17 + 18 + #include "device-impl.h" 19 + 20 + /* Wrappers for use with kunit_add_action() */ 21 + KUNIT_DEFINE_ACTION_WRAPPER(device_unregister_wrapper, device_unregister, struct device *); 22 + KUNIT_DEFINE_ACTION_WRAPPER(driver_unregister_wrapper, driver_unregister, struct device_driver *); 23 + 24 + /* The root device for the KUnit bus, parent of all kunit_devices. */ 25 + static struct device *kunit_bus_device; 26 + 27 + /* A device owned by a KUnit test. */ 28 + struct kunit_device { 29 + struct device dev; 30 + /* The KUnit test which owns this device. */ 31 + struct kunit *owner; 32 + /* If the driver is managed by KUnit and unique to this device. */ 33 + const struct device_driver *driver; 34 + }; 35 + 36 + #define to_kunit_device(d) container_of_const(d, struct kunit_device, dev) 37 + 38 + static struct bus_type kunit_bus_type = { 39 + .name = "kunit", 40 + }; 41 + 42 + /* Register the 'kunit_bus' used for fake devices. */ 43 + int kunit_bus_init(void) 44 + { 45 + int error; 46 + 47 + kunit_bus_device = root_device_register("kunit"); 48 + if (!kunit_bus_device) 49 + return -ENOMEM; 50 + 51 + error = bus_register(&kunit_bus_type); 52 + if (error) 53 + bus_unregister(&kunit_bus_type); 54 + return error; 55 + } 56 + 57 + /* Release a 'fake' KUnit device. */ 58 + static void kunit_device_release(struct device *d) 59 + { 60 + kfree(to_kunit_device(d)); 61 + } 62 + 63 + /** 64 + * Create and register a KUnit-managed struct device_driver on the kunit_bus. 65 + * Returns an error pointer on failure. 66 + */ 67 + struct device_driver *kunit_driver_create(struct kunit *test, const char *name) 68 + { 69 + struct device_driver *driver; 70 + int err = -ENOMEM; 71 + 72 + driver = kunit_kzalloc(test, sizeof(*driver), GFP_KERNEL); 73 + 74 + if (!driver) 75 + return ERR_PTR(err); 76 + 77 + driver->name = name; 78 + driver->bus = &kunit_bus_type; 79 + driver->owner = THIS_MODULE; 80 + 81 + err = driver_register(driver); 82 + if (err) { 83 + kunit_kfree(test, driver); 84 + return ERR_PTR(err); 85 + } 86 + 87 + kunit_add_action(test, driver_unregister_wrapper, driver); 88 + return driver; 89 + } 90 + EXPORT_SYMBOL_GPL(kunit_driver_create); 91 + 92 + /* Helper which creates a kunit_device, attaches it to the kunit_bus*/ 93 + static struct kunit_device *kunit_device_register_internal(struct kunit *test, 94 + const char *name, 95 + const struct device_driver *drv) 96 + { 97 + struct kunit_device *kunit_dev; 98 + int err = -ENOMEM; 99 + 100 + kunit_dev = kzalloc(sizeof(*kunit_dev), GFP_KERNEL); 101 + if (!kunit_dev) 102 + return ERR_PTR(err); 103 + 104 + kunit_dev->owner = test; 105 + 106 + err = dev_set_name(&kunit_dev->dev, "%s.%s", test->name, name); 107 + if (err) { 108 + kfree(kunit_dev); 109 + return ERR_PTR(err); 110 + } 111 + 112 + kunit_dev->dev.release = kunit_device_release; 113 + kunit_dev->dev.bus = &kunit_bus_type; 114 + kunit_dev->dev.parent = kunit_bus_device; 115 + 116 + err = device_register(&kunit_dev->dev); 117 + if (err) { 118 + put_device(&kunit_dev->dev); 119 + return ERR_PTR(err); 120 + } 121 + 122 + kunit_add_action(test, device_unregister_wrapper, &kunit_dev->dev); 123 + 124 + return kunit_dev; 125 + } 126 + 127 + /** 128 + * Create and register a new KUnit-managed device, using the user-supplied device_driver. 129 + * On failure, returns an error pointer. 130 + */ 131 + struct device *kunit_device_register_with_driver(struct kunit *test, 132 + const char *name, 133 + const struct device_driver *drv) 134 + { 135 + struct kunit_device *kunit_dev = kunit_device_register_internal(test, name, drv); 136 + 137 + if (IS_ERR_OR_NULL(kunit_dev)) 138 + return ERR_CAST(kunit_dev); 139 + 140 + return &kunit_dev->dev; 141 + } 142 + EXPORT_SYMBOL_GPL(kunit_device_register_with_driver); 143 + 144 + /** 145 + * Create and register a new KUnit-managed device, including a matching device_driver. 146 + * On failure, returns an error pointer. 147 + */ 148 + struct device *kunit_device_register(struct kunit *test, const char *name) 149 + { 150 + struct device_driver *drv; 151 + struct kunit_device *dev; 152 + 153 + drv = kunit_driver_create(test, name); 154 + if (IS_ERR(drv)) 155 + return ERR_CAST(drv); 156 + 157 + dev = kunit_device_register_internal(test, name, drv); 158 + if (IS_ERR(dev)) { 159 + kunit_release_action(test, driver_unregister_wrapper, (void *)drv); 160 + return ERR_CAST(dev); 161 + } 162 + 163 + /* Request the driver be freed. */ 164 + dev->driver = drv; 165 + 166 + 167 + return &dev->dev; 168 + } 169 + EXPORT_SYMBOL_GPL(kunit_device_register); 170 + 171 + /* Unregisters a KUnit-managed device early (including the driver, if automatically created). */ 172 + void kunit_device_unregister(struct kunit *test, struct device *dev) 173 + { 174 + const struct device_driver *driver = to_kunit_device(dev)->driver; 175 + 176 + kunit_release_action(test, device_unregister_wrapper, dev); 177 + if (driver) 178 + kunit_release_action(test, driver_unregister_wrapper, (void *)driver); 179 + } 180 + EXPORT_SYMBOL_GPL(kunit_device_unregister); 181 +
+133 -1
lib/kunit/kunit-test.c
··· 5 5 * Copyright (C) 2019, Google LLC. 6 6 * Author: Brendan Higgins <brendanhiggins@google.com> 7 7 */ 8 + #include "linux/gfp_types.h" 8 9 #include <kunit/test.h> 9 10 #include <kunit/test-bug.h> 11 + 12 + #include <linux/device.h> 13 + #include <kunit/device.h> 10 14 11 15 #include "string-stream.h" 12 16 #include "try-catch-impl.h" ··· 691 687 {} 692 688 }; 693 689 690 + static void test_dev_action(void *priv) 691 + { 692 + *(void **)priv = (void *)1; 693 + } 694 + 695 + static void kunit_device_test(struct kunit *test) 696 + { 697 + struct device *test_device; 698 + long action_was_run = 0; 699 + 700 + test_device = kunit_device_register(test, "my_device"); 701 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_device); 702 + 703 + // Add an action to verify cleanup. 704 + devm_add_action(test_device, test_dev_action, &action_was_run); 705 + 706 + KUNIT_EXPECT_EQ(test, action_was_run, 0); 707 + 708 + kunit_device_unregister(test, test_device); 709 + 710 + KUNIT_EXPECT_EQ(test, action_was_run, 1); 711 + } 712 + 713 + static void kunit_device_cleanup_test(struct kunit *test) 714 + { 715 + struct device *test_device; 716 + long action_was_run = 0; 717 + 718 + test_device = kunit_device_register(test, "my_device"); 719 + KUNIT_ASSERT_NOT_NULL(test, test_device); 720 + 721 + /* Add an action to verify cleanup. */ 722 + devm_add_action(test_device, test_dev_action, &action_was_run); 723 + 724 + KUNIT_EXPECT_EQ(test, action_was_run, 0); 725 + 726 + /* Force KUnit to run cleanup early. */ 727 + kunit_cleanup(test); 728 + 729 + KUNIT_EXPECT_EQ(test, action_was_run, 1); 730 + } 731 + 732 + struct driver_test_state { 733 + bool driver_device_probed; 734 + bool driver_device_removed; 735 + long action_was_run; 736 + }; 737 + 738 + static int driver_probe_hook(struct device *dev) 739 + { 740 + struct kunit *test = kunit_get_current_test(); 741 + struct driver_test_state *state = (struct driver_test_state *)test->priv; 742 + 743 + state->driver_device_probed = true; 744 + return 0; 745 + } 746 + 747 + static int driver_remove_hook(struct device *dev) 748 + { 749 + struct kunit *test = kunit_get_current_test(); 750 + struct driver_test_state *state = (struct driver_test_state *)test->priv; 751 + 752 + state->driver_device_removed = true; 753 + return 0; 754 + } 755 + 756 + static void kunit_device_driver_test(struct kunit *test) 757 + { 758 + struct device_driver *test_driver; 759 + struct device *test_device; 760 + struct driver_test_state *test_state = kunit_kzalloc(test, sizeof(*test_state), GFP_KERNEL); 761 + 762 + test->priv = test_state; 763 + test_driver = kunit_driver_create(test, "my_driver"); 764 + 765 + // This can fail with an error pointer. 766 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_driver); 767 + 768 + test_driver->probe = driver_probe_hook; 769 + test_driver->remove = driver_remove_hook; 770 + 771 + test_device = kunit_device_register_with_driver(test, "my_device", test_driver); 772 + 773 + // This can fail with an error pointer. 774 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_device); 775 + 776 + // Make sure the probe function was called. 777 + KUNIT_ASSERT_TRUE(test, test_state->driver_device_probed); 778 + 779 + // Add an action to verify cleanup. 780 + devm_add_action(test_device, test_dev_action, &test_state->action_was_run); 781 + 782 + KUNIT_EXPECT_EQ(test, test_state->action_was_run, 0); 783 + 784 + kunit_device_unregister(test, test_device); 785 + test_device = NULL; 786 + 787 + // Make sure the remove hook was called. 788 + KUNIT_ASSERT_TRUE(test, test_state->driver_device_removed); 789 + 790 + // We're going to test this again. 791 + test_state->driver_device_probed = false; 792 + 793 + // The driver should not automatically be destroyed by 794 + // kunit_device_unregister, so we can re-use it. 795 + test_device = kunit_device_register_with_driver(test, "my_device", test_driver); 796 + 797 + // This can fail with an error pointer. 798 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, test_device); 799 + 800 + // Probe was called again. 801 + KUNIT_ASSERT_TRUE(test, test_state->driver_device_probed); 802 + 803 + // Everything is automatically freed here. 804 + } 805 + 806 + static struct kunit_case kunit_device_test_cases[] = { 807 + KUNIT_CASE(kunit_device_test), 808 + KUNIT_CASE(kunit_device_cleanup_test), 809 + KUNIT_CASE(kunit_device_driver_test), 810 + {} 811 + }; 812 + 813 + static struct kunit_suite kunit_device_test_suite = { 814 + .name = "kunit_device", 815 + .test_cases = kunit_device_test_cases, 816 + }; 817 + 694 818 static struct kunit_suite kunit_current_test_suite = { 695 819 .name = "kunit_current", 696 820 .test_cases = kunit_current_test_cases, ··· 826 694 827 695 kunit_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite, 828 696 &kunit_log_test_suite, &kunit_status_test_suite, 829 - &kunit_current_test_suite); 697 + &kunit_current_test_suite, &kunit_device_test_suite); 830 698 831 699 MODULE_LICENSE("GPL v2");
+3
lib/kunit/test.c
··· 19 19 #include <linux/sched.h> 20 20 21 21 #include "debugfs.h" 22 + #include "device-impl.h" 22 23 #include "hooks-impl.h" 23 24 #include "string-stream.h" 24 25 #include "try-catch-impl.h" ··· 901 900 kunit_install_hooks(); 902 901 903 902 kunit_debugfs_init(); 903 + 904 + kunit_bus_init(); 904 905 #ifdef CONFIG_MODULES 905 906 return register_module_notifier(&kunit_mod_nb); 906 907 #else