Commit 28a4f91f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'driver-core-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core

Pull driver core updates from Greg KH:
 "Here is a small set of driver core updates and additions for 6.6-rc1.

  Included in here are:

   - stable kernel documentation updates

   - class structure const work from Ivan on various subsystems

   - kernfs tweaks

   - driver core tests!

   - kobject sanity cleanups

   - kobject structure reordering to save space

   - driver core error code handling fixups

   - other minor driver core cleanups

  All of these have been in linux-next for a while with no reported
  problems"

* tag 'driver-core-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (32 commits)
  driver core: Call in reversed order in device_platform_notify_remove()
  driver core: Return proper error code when dev_set_name() fails
  kobject: Remove redundant checks for whether ktype is NULL
  kobject: Add sanity check for kset->kobj.ktype in kset_register()
  drivers: base: test: Add missing MODULE_* macros to root device tests
  drivers: base: test: Add missing MODULE_* macros for platform devices tests
  drivers: base: Free devm resources when unregistering a device
  drivers: base: Add basic devm tests for platform devices
  drivers: base: Add basic devm tests for root devices
  kernfs: fix missing kernfs_iattr_rwsem locking
  docs: stable-kernel-rules: mention that regressions must be prevented
  docs: stable-kernel-rules: fine-tune various details
  docs: stable-kernel-rules: make the examples for option 1 a proper list
  docs: stable-kernel-rules: move text around to improve flow
  docs: stable-kernel-rules: improve structure by changing headlines
  base/node: Remove duplicated include
  kernfs: attach uuid for every kernfs and report it in fsid
  kernfs: add stub helper for kernfs_generic_poll()
  x86/resctrl: make pseudo_lock_class a static const structure
  x86/MSR: make msr_class a static const structure
  ...
parents 8e1e4955 29c8ab79
......@@ -45,7 +45,21 @@ static u64 prefetch_disable_bits;
*/
static unsigned int pseudo_lock_major;
static unsigned long pseudo_lock_minor_avail = GENMASK(MINORBITS, 0);
static struct class *pseudo_lock_class;
static char *pseudo_lock_devnode(const struct device *dev, umode_t *mode)
{
const struct rdtgroup *rdtgrp;
rdtgrp = dev_get_drvdata(dev);
if (mode)
*mode = 0600;
return kasprintf(GFP_KERNEL, "pseudo_lock/%s", rdtgrp->kn->name);
}
static const struct class pseudo_lock_class = {
.name = "pseudo_lock",
.devnode = pseudo_lock_devnode,
};
/**
* get_prefetch_disable_bits - prefetch disable bits of supported platforms
......@@ -1353,7 +1367,7 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp)
&pseudo_measure_fops);
}
dev = device_create(pseudo_lock_class, NULL,
dev = device_create(&pseudo_lock_class, NULL,
MKDEV(pseudo_lock_major, new_minor),
rdtgrp, "%s", rdtgrp->kn->name);
......@@ -1383,7 +1397,7 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp)
goto out;
out_device:
device_destroy(pseudo_lock_class, MKDEV(pseudo_lock_major, new_minor));
device_destroy(&pseudo_lock_class, MKDEV(pseudo_lock_major, new_minor));
out_debugfs:
debugfs_remove_recursive(plr->debugfs_dir);
pseudo_lock_minor_release(new_minor);
......@@ -1424,7 +1438,7 @@ void rdtgroup_pseudo_lock_remove(struct rdtgroup *rdtgrp)
pseudo_lock_cstates_relax(plr);
debugfs_remove_recursive(rdtgrp->plr->debugfs_dir);
device_destroy(pseudo_lock_class, MKDEV(pseudo_lock_major, plr->minor));
device_destroy(&pseudo_lock_class, MKDEV(pseudo_lock_major, plr->minor));
pseudo_lock_minor_release(plr->minor);
free:
......@@ -1560,16 +1574,6 @@ static const struct file_operations pseudo_lock_dev_fops = {
.mmap = pseudo_lock_dev_mmap,
};
static char *pseudo_lock_devnode(const struct device *dev, umode_t *mode)
{
const struct rdtgroup *rdtgrp;
rdtgrp = dev_get_drvdata(dev);
if (mode)
*mode = 0600;
return kasprintf(GFP_KERNEL, "pseudo_lock/%s", rdtgrp->kn->name);
}
int rdt_pseudo_lock_init(void)
{
int ret;
......@@ -1580,21 +1584,18 @@ int rdt_pseudo_lock_init(void)
pseudo_lock_major = ret;
pseudo_lock_class = class_create("pseudo_lock");
if (IS_ERR(pseudo_lock_class)) {
ret = PTR_ERR(pseudo_lock_class);
ret = class_register(&pseudo_lock_class);
if (ret) {
unregister_chrdev(pseudo_lock_major, "pseudo_lock");
return ret;
}
pseudo_lock_class->devnode = pseudo_lock_devnode;
return 0;
}
void rdt_pseudo_lock_release(void)
{
class_destroy(pseudo_lock_class);
pseudo_lock_class = NULL;
class_unregister(&pseudo_lock_class);
unregister_chrdev(pseudo_lock_major, "pseudo_lock");
pseudo_lock_major = 0;
}
......@@ -40,7 +40,6 @@
#include <asm/processor.h>
#include <asm/msr.h>
static struct class *cpuid_class;
static enum cpuhp_state cpuhp_cpuid_state;
struct cpuid_regs_done {
......@@ -124,26 +123,31 @@ static const struct file_operations cpuid_fops = {
.open = cpuid_open,
};
static char *cpuid_devnode(const struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "cpu/%u/cpuid", MINOR(dev->devt));
}
static const struct class cpuid_class = {
.name = "cpuid",
.devnode = cpuid_devnode,
};
static int cpuid_device_create(unsigned int cpu)
{
struct device *dev;
dev = device_create(cpuid_class, NULL, MKDEV(CPUID_MAJOR, cpu), NULL,
dev = device_create(&cpuid_class, NULL, MKDEV(CPUID_MAJOR, cpu), NULL,
"cpu%d", cpu);
return PTR_ERR_OR_ZERO(dev);
}
static int cpuid_device_destroy(unsigned int cpu)
{
device_destroy(cpuid_class, MKDEV(CPUID_MAJOR, cpu));
device_destroy(&cpuid_class, MKDEV(CPUID_MAJOR, cpu));
return 0;
}
static char *cpuid_devnode(const struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "cpu/%u/cpuid", MINOR(dev->devt));
}
static int __init cpuid_init(void)
{
int err;
......@@ -154,12 +158,9 @@ static int __init cpuid_init(void)
CPUID_MAJOR);
return -EBUSY;
}
cpuid_class = class_create("cpuid");
if (IS_ERR(cpuid_class)) {
err = PTR_ERR(cpuid_class);
err = class_register(&cpuid_class);
if (err)
goto out_chrdev;
}
cpuid_class->devnode = cpuid_devnode;
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/cpuid:online",
cpuid_device_create, cpuid_device_destroy);
......@@ -170,7 +171,7 @@ static int __init cpuid_init(void)
return 0;
out_class:
class_destroy(cpuid_class);
class_unregister(&cpuid_class);
out_chrdev:
__unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid");
return err;
......@@ -180,7 +181,7 @@ module_init(cpuid_init);
static void __exit cpuid_exit(void)
{
cpuhp_remove_state(cpuhp_cpuid_state);
class_destroy(cpuid_class);
class_unregister(&cpuid_class);
__unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid");
}
module_exit(cpuid_exit);
......
......@@ -39,7 +39,6 @@
#include <asm/cpufeature.h>
#include <asm/msr.h>
static struct class *msr_class;
static enum cpuhp_state cpuhp_msr_state;
enum allow_write_msrs {
......@@ -235,26 +234,31 @@ static const struct file_operations msr_fops = {
.compat_ioctl = msr_ioctl,
};
static char *msr_devnode(const struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "cpu/%u/msr", MINOR(dev->devt));
}
static const struct class msr_class = {
.name = "msr",
.devnode = msr_devnode,
};
static int msr_device_create(unsigned int cpu)
{
struct device *dev;
dev = device_create(msr_class, NULL, MKDEV(MSR_MAJOR, cpu), NULL,
dev = device_create(&msr_class, NULL, MKDEV(MSR_MAJOR, cpu), NULL,
"msr%d", cpu);
return PTR_ERR_OR_ZERO(dev);
}
static int msr_device_destroy(unsigned int cpu)
{
device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu));
device_destroy(&msr_class, MKDEV(MSR_MAJOR, cpu));
return 0;
}
static char *msr_devnode(const struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "cpu/%u/msr", MINOR(dev->devt));
}
static int __init msr_init(void)
{
int err;
......@@ -263,12 +267,9 @@ static int __init msr_init(void)
pr_err("unable to get major %d for msr\n", MSR_MAJOR);
return -EBUSY;
}
msr_class = class_create("msr");
if (IS_ERR(msr_class)) {
err = PTR_ERR(msr_class);
err = class_register(&msr_class);
if (err)
goto out_chrdev;
}
msr_class->devnode = msr_devnode;
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/msr:online",
msr_device_create, msr_device_destroy);
......@@ -278,7 +279,7 @@ static int __init msr_init(void)
return 0;
out_class:
class_destroy(msr_class);
class_unregister(&msr_class);
out_chrdev:
__unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
return err;
......@@ -288,7 +289,7 @@ module_init(msr_init);
static void __exit msr_exit(void)
{
cpuhp_remove_state(cpuhp_msr_state);
class_destroy(msr_class);
class_unregister(&msr_class);
__unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
}
module_exit(msr_exit)
......
......@@ -2306,12 +2306,12 @@ static void device_platform_notify(struct device *dev)
static void device_platform_notify_remove(struct device *dev)
{
acpi_device_notify_remove(dev);
if (platform_notify_remove)
platform_notify_remove(dev);
software_node_notify_remove(dev);
if (platform_notify_remove)
platform_notify_remove(dev);
acpi_device_notify_remove(dev);
}
/**
......@@ -3528,18 +3528,17 @@ int device_add(struct device *dev)
* the name, and force the use of dev_name()
*/
if (dev->init_name) {
dev_set_name(dev, "%s", dev->init_name);
error = dev_set_name(dev, "%s", dev->init_name);
dev->init_name = NULL;
}
if (dev_name(dev))
error = 0;
/* subsystems can specify simple device enumeration */
if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
if (!dev_name(dev)) {
error = -EINVAL;
else if (dev->bus && dev->bus->dev_name)
error = dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
if (error)
goto name_error;
}
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
......@@ -3815,6 +3814,17 @@ void device_del(struct device *dev)
device_platform_notify_remove(dev);
device_links_purge(dev);
/*
* If a device does not have a driver attached, we need to clean
* up any managed resources. We do this in device_release(), but
* it's never called (and we leak the device) if a managed
* resource holds a reference to the device. So release all
* managed resources here, like we do in driver_detach(). We
* still need to do so again in device_release() in case someone
* adds a new resource after this point, though.
*/
devres_release_all(dev);
bus_notify(dev, BUS_NOTIFY_REMOVED_DEVICE);
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
glue_dir = get_glue_dir(dev);
......
......@@ -19,6 +19,7 @@
#include <linux/cpufeature.h>
#include <linux/tick.h>
#include <linux/pm_qos.h>
#include <linux/delay.h>
#include <linux/sched/isolation.h>
#include "base.h"
......@@ -50,12 +51,30 @@ static int cpu_subsys_online(struct device *dev)
int cpuid = dev->id;
int from_nid, to_nid;
int ret;
int retries = 0;
from_nid = cpu_to_node(cpuid);
if (from_nid == NUMA_NO_NODE)
return -ENODEV;
retry:
ret = cpu_device_up(dev);
/*
* If -EBUSY is returned, it is likely that hotplug is temporarily
* disabled when cpu_hotplug_disable() was called. This condition is
* transient. So we retry after waiting for an exponentially
* increasing delay up to a total of at least 620ms as some PCI
* device initialization can take quite a while.
*/
if (ret == -EBUSY) {
retries++;
if (retries > 5)
return ret;
msleep(10 * (1 << retries));
goto retry;
}
/*
* When hot adding memory to memoryless node and enabling a cpu
* on the node, node number of the cpu may internally change.
......
......@@ -693,6 +693,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
device_remove(dev);
driver_sysfs_remove(dev);
if (dev->bus && dev->bus->dma_cleanup)
dev->bus->dma_cleanup(dev);
device_unbind_cleanup(dev);
goto re_probe;
......
......@@ -20,7 +20,6 @@
#include <linux/pm_runtime.h>
#include <linux/swap.h>
#include <linux/slab.h>
#include <linux/hugetlb.h>
static struct bus_type node_subsys = {
.name = "node",
......
CONFIG_KUNIT=y
CONFIG_DM_KUNIT_TEST=y
......@@ -9,6 +9,10 @@ config TEST_ASYNC_DRIVER_PROBE
If unsure say N.
config DM_KUNIT_TEST
tristate "KUnit Tests for the device model" if !KUNIT_ALL_TESTS
depends on KUNIT
config DRIVER_PE_KUNIT_TEST
bool "KUnit Tests for property entry API" if !KUNIT_ALL_TESTS
depends on KUNIT=y
......
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_TEST_ASYNC_DRIVER_PROBE) += test_async_driver_probe.o
obj-$(CONFIG_DM_KUNIT_TEST) += root-device-test.o
obj-$(CONFIG_DM_KUNIT_TEST) += platform-device-test.o
obj-$(CONFIG_DRIVER_PE_KUNIT_TEST) += property-entry-test.o
CFLAGS_property-entry-test.o += $(DISABLE_STRUCTLEAK_PLUGIN)
// SPDX-License-Identifier: GPL-2.0
#include <kunit/resource.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#define DEVICE_NAME "test"
struct test_priv {
bool probe_done;
bool release_done;
wait_queue_head_t probe_wq;
wait_queue_head_t release_wq;
struct device *dev;
};
static int platform_device_devm_init(struct kunit *test)
{
struct test_priv *priv;
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
init_waitqueue_head(&priv->probe_wq);
init_waitqueue_head(&priv->release_wq);
test->priv = priv;
return 0;
}
static void devm_device_action(void *ptr)
{
struct test_priv *priv = ptr;
priv->release_done = true;
wake_up_interruptible(&priv->release_wq);
}
static void devm_put_device_action(void *ptr)
{
struct test_priv *priv = ptr;
put_device(priv->dev);
priv->release_done = true;
wake_up_interruptible(&priv->release_wq);
}
#define RELEASE_TIMEOUT_MS 100
/*
* Tests that a platform bus, non-probed device will run its
* device-managed actions when unregistered.
*/
static void platform_device_devm_register_unregister_test(struct kunit *test)
{
struct platform_device *pdev;
struct test_priv *priv = test->priv;
int ret;
pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
ret = platform_device_add(pdev);
KUNIT_ASSERT_EQ(test, ret, 0);
priv->dev = &pdev->dev;
ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv);
KUNIT_ASSERT_EQ(test, ret, 0);
platform_device_unregister(pdev);
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
KUNIT_EXPECT_GT(test, ret, 0);
}
/*
* Tests that a platform bus, non-probed device will run its
* device-managed actions when unregistered, even if someone still holds
* a reference to it.
*/
static void platform_device_devm_register_get_unregister_with_devm_test(struct kunit *test)
{
struct platform_device *pdev;
struct test_priv *priv = test->priv;
int ret;
pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
ret = platform_device_add(pdev);
KUNIT_ASSERT_EQ(test, ret, 0);
priv->dev = &pdev->dev;
get_device(priv->dev);
ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv);
KUNIT_ASSERT_EQ(test, ret, 0);
platform_device_unregister(pdev);
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
KUNIT_EXPECT_GT(test, ret, 0);
}
static int fake_probe(struct platform_device *pdev)
{
struct test_priv *priv = platform_get_drvdata(pdev);
priv->probe_done = true;
wake_up_interruptible(&priv->probe_wq);
return 0;
}
static struct platform_driver fake_driver = {
.probe = fake_probe,
.driver = {
.name = DEVICE_NAME,
},
};
/*
* Tests that a platform bus, probed device will run its device-managed
* actions when unregistered.
*/
static void probed_platform_device_devm_register_unregister_test(struct kunit *test)
{
struct platform_device *pdev;
struct test_priv *priv = test->priv;
int ret;
ret = platform_driver_register(&fake_driver);
KUNIT_ASSERT_EQ(test, ret, 0);
pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
priv->dev = &pdev->dev;
platform_set_drvdata(pdev, priv);
ret = platform_device_add(pdev);
KUNIT_ASSERT_EQ(test, ret, 0);
ret = wait_event_interruptible_timeout(priv->probe_wq, priv->probe_done,
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
KUNIT_ASSERT_GT(test, ret, 0);
ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv);
KUNIT_ASSERT_EQ(test, ret, 0);
platform_device_unregister(pdev);
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
KUNIT_EXPECT_GT(test, ret, 0);
platform_driver_unregister(&fake_driver);
}
/*
* Tests that a platform bus, probed device will run its device-managed
* actions when unregistered, even if someone still holds a reference to
* it.
*/
static void probed_platform_device_devm_register_get_unregister_with_devm_test(struct kunit *test)
{
struct platform_device *pdev;
struct test_priv *priv = test->priv;
int ret;
ret = platform_driver_register(&fake_driver);
KUNIT_ASSERT_EQ(test, ret, 0);
pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
priv->dev = &pdev->dev;
platform_set_drvdata(pdev, priv);
ret = platform_device_add(pdev);
KUNIT_ASSERT_EQ(test, ret, 0);
ret = wait_event_interruptible_timeout(priv->probe_wq, priv->probe_done,
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
KUNIT_ASSERT_GT(test, ret, 0);
get_device(priv->dev);
ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv);
KUNIT_ASSERT_EQ(test, ret, 0);
platform_device_unregister(pdev);
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
KUNIT_EXPECT_GT(test, ret, 0);
platform_driver_unregister(&fake_driver);
}
static struct kunit_case platform_device_devm_tests[] = {
KUNIT_CASE(platform_device_devm_register_unregister_test),
KUNIT_CASE(platform_device_devm_register_get_unregister_with_devm_test),
KUNIT_CASE(probed_platform_device_devm_register_unregister_test),
KUNIT_CASE(probed_platform_device_devm_register_get_unregister_with_devm_test),
{}
};
static struct kunit_suite platform_device_devm_test_suite = {
.name = "platform-device-devm",
.init = platform_device_devm_init,
.test_cases = platform_device_devm_tests,
};
kunit_test_suite(platform_device_devm_test_suite);
MODULE_DESCRIPTION("Test module for platform devices");
MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
MODULE_LICENSE("GPL");
// SPDX-License-Identifier: GPL-2.0
// Copyright 2023 Maxime Ripard <mripard@kernel.org>
#include <kunit/resource.h>
#include <linux/device.h>
#define DEVICE_NAME "test"
struct test_priv {
bool probe_done;
bool release_done;
wait_queue_head_t release_wq;
struct device *dev;
};
static int root_device_devm_init(struct kunit *test)
{
struct test_priv *priv;
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
init_waitqueue_head(&priv->release_wq);
test->priv = priv;
return 0;
}
static void devm_device_action(void *ptr)
{
struct test_priv *priv = ptr;
priv->release_done = true;
wake_up_interruptible(&priv->release_wq);
}
#define RELEASE_TIMEOUT_MS 100
/*
* Tests that a bus-less, non-probed device will run its device-managed
* actions when unregistered.
*/
static void root_device_devm_register_unregister_test(struct kunit *test)
{
struct test_priv *priv = test->priv;
int ret;
priv->dev = root_device_register(DEVICE_NAME);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv);
KUNIT_ASSERT_EQ(test, ret, 0);
root_device_unregister(priv->dev);
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
KUNIT_EXPECT_GT(test, ret, 0);
}
static void devm_put_device_action(void *ptr)
{
struct test_priv *priv = ptr;
put_device(priv->dev);
priv->release_done = true;
wake_up_interruptible(&priv->release_wq);
}
/*
* Tests that a bus-less, non-probed device will run its device-managed
* actions when unregistered, even if someone still holds a reference to
* it.
*/
static void root_device_devm_register_get_unregister_with_devm_test(struct kunit *test)
{
struct test_priv *priv = test->priv;
int ret;
priv->dev = root_device_register(DEVICE_NAME);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
get_device(priv->dev);
ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv);
KUNIT_ASSERT_EQ(test, ret, 0);
root_device_unregister(priv->dev);
ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
msecs_to_jiffies(RELEASE_TIMEOUT_MS));
KUNIT_EXPECT_GT(test, ret, 0);
}
static struct kunit_case root_device_devm_tests[] = {
KUNIT_CASE(root_device_devm_register_unregister_test),
KUNIT_CASE(root_device_devm_register_get_unregister_with_devm_test),
{}
};
static struct kunit_suite root_device_devm_test_suite = {
.name = "root-device-devm",
.init = root_device_devm_init,
.test_cases = root_device_devm_tests,
};
kunit_test_suite(root_device_devm_test_suite);
MODULE_DESCRIPTION("Test module for root devices");
MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
MODULE_LICENSE("GPL");
......@@ -84,7 +84,7 @@ test_platform_device_register_node(char *name, int id, int nid)
pdev = platform_device_alloc(name, id);
if (!pdev)
return NULL;
return ERR_PTR(-ENOMEM);
if (nid != NUMA_NO_NODE)
set_dev_node(&pdev->dev, nid);
......
......@@ -28,8 +28,13 @@
DEFINE_IDR(dev_nums_idr);
static DEFINE_MUTEX(idr_lock);
struct class *tpm_class;
struct class *tpmrm_class;
const struct class tpm_class = {
.name = "tpm",
.shutdown_pre = tpm_class_shutdown,
};
const struct class tpmrm_class = {
.name = "tmprm",
};
dev_t tpm_devt;
static int tpm_request_locality(struct tpm_chip *chip)
......@@ -336,7 +341,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
device_initialize(&chip->dev);
chip->dev.class = tpm_class;
chip->dev.class = &tpm_class;
chip->dev.release = tpm_dev_release;
chip->dev.parent = pdev;
chip->dev.groups = chip->groups;
......
......@@ -476,18 +476,15 @@ static int __init tpm_init(void)
{
int rc;
tpm_class = class_create("tpm");
if (IS_ERR(tpm_class)) {
rc = class_register(&tpm_class);
if (rc) {
pr_err("couldn't create tpm class\n");
return PTR_ERR(tpm_class);
return rc;
}
tpm_class->shutdown_pre = tpm_class_shutdown;
tpmrm_class = class_create("tpmrm");
if (IS_ERR(tpmrm_class)) {
rc = class_register(&tpmrm_class);
if (rc) {
pr_err("couldn't create tpmrm class\n");
rc = PTR_ERR(tpmrm_class);
goto out_destroy_tpm_class;
}
......@@ -508,9 +505,9 @@ static int __init tpm_init(void)
out_unreg_chrdev:
unregister_chrdev_region(tpm_devt, 2 * TPM_NUM_DEVICES);
out_destroy_tpmrm_class:
class_destroy(tpmrm_class);
class_unregister(&tpmrm_class);
out_destroy_tpm_class:
class_destroy(tpm_class);
class_unregister(&tpm_class);
return rc;
}
......@@ -518,8 +515,8 @@ static int __init tpm_init(void)
static void __exit tpm_exit(void)
{
idr_destroy(&dev_nums_idr);
class_destroy(tpm_class);
class_destroy(tpmrm_class);
class_unregister(&tpm_class);
class_unregister(&tpmrm_class);
unregister_chrdev_region(tpm_devt, 2*TPM_NUM_DEVICES);
tpm_dev_common_exit();
}
......
......@@ -230,8 +230,8 @@ enum tpm2_pt_props {
* compiler warnings about stack frame size. */
#define TPM_MAX_RNG_DATA 128
extern struct class *tpm_class;
extern struct class *tpmrm_class;
extern const struct class tpm_class;
extern const struct class tpmrm_class;
extern dev_t tpm_devt;
extern const struct file_operations tpm_fops;
extern const struct file_operations tpmrm_fops;
......
......@@ -606,7 +606,7 @@ int tpm_devs_add(struct tpm_chip *chip)
device_initialize(&chip->devs);
chip->devs.parent = chip->dev.parent;
chip->devs.class = tpmrm_class;
chip->devs.class = &tpmrm_class;
/*
* Get extra reference on main device to hold on behalf of devs.
......
......@@ -23,8 +23,6 @@
#include "hid-roccat-common.h"
#include "hid-roccat-arvo.h"
static struct class *arvo_class;
static ssize_t arvo_sysfs_show_mode_key(struct device *dev,
struct device_attribute *attr, char *buf)
{
......@@ -268,6 +266,11 @@ static const struct attribute_group *arvo_groups[] = {
NULL,
};
static const struct class arvo_class = {
.name = "arvo",
.dev_groups = arvo_groups,
};
static int arvo_init_arvo_device_struct(struct usb_device *usb_dev,
struct arvo_device *arvo)
{
......@@ -309,7 +312,7 @@ static int arvo_init_specials(struct hid_device *hdev)
goto exit_free;
}
retval = roccat_connect(arvo_class, hdev,
retval = roccat_connect(&arvo_class, hdev,
sizeof(struct arvo_roccat_report));
if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n");
......@@ -433,21 +436,20 @@ static int __init arvo_init(void)
{
int retval;
arvo_class = class_create("arvo");
if (IS_ERR(arvo_class))
return PTR_ERR(arvo_class);
arvo_class->dev_groups = arvo_groups;
retval = class_register(&arvo_class);
if (retval)
return retval;
retval = hid_register_driver(&arvo_driver);
if (retval)
class_destroy(arvo_class);
class_unregister(&arvo_class);
return retval;
}
static void __exit arvo_exit(void)
{
hid_unregister_driver(&arvo_driver);
class_destroy(arvo_class);
class_unregister(&arvo_class);
}
module_init(arvo_init);
......
......@@ -23,8 +23,6 @@
#include "hid-roccat-common.h"
#include "hid-roccat-isku.h"
static struct class *isku_class;
static void isku_profile_activated(struct isku_device *isku, uint new_profile)
{
isku->actual_profile = new_profile;
......@@ -248,6 +246,11 @@ static const struct attribute_group *isku_groups[] = {
NULL,
};
static const struct class isku_class = {
.name = "isku",
.dev_groups = isku_groups,
};
static int isku_init_isku_device_struct(struct usb_device *usb_dev,
struct isku_device *isku)
{
......@@ -289,7 +292,7 @@ static int isku_init_specials(struct hid_device *hdev)
goto exit_free;
}
retval = roccat_connect(isku_class, hdev,
retval = roccat_connect(&isku_class, hdev,
sizeof(struct isku_roccat_report));
if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n");
......@@ -435,21 +438,21 @@ static struct hid_driver isku_driver = {
static int __init isku_init(void)
{
int retval;
isku_class = class_create("isku");
if (IS_ERR(isku_class))
return PTR_ERR(isku_class);
isku_class->dev_groups = isku_groups;
retval = class_register(&isku_class);
if (retval)
return retval;
retval = hid_register_driver(&isku_driver);
if (retval)
class_destroy(isku_class);
class_unregister(&isku_class);
return retval;
}
static void __exit isku_exit(void)
{
hid_unregister_driver(&isku_driver);
class_destroy(isku_class);
class_unregister(&isku_class);
}
module_init(isku_init);
......
......@@ -89,9 +89,6 @@ static int kone_send(struct usb_device *usb_dev, uint usb_command,
return ((len < 0) ? len : ((len != size) ? -EIO : 0));
}
/* kone_class is used for creating sysfs attributes via roccat char device */
static struct class *kone_class;
static void kone_set_settings_checksum(struct kone_settings *settings)
{
uint16_t checksum = 0;
......@@ -657,6 +654,12 @@ static const struct attribute_group *kone_groups[] = {
NULL,
};
/* kone_class is used for creating sysfs attributes via roccat char device */
static const struct class kone_class = {
.name = "kone",
.dev_groups = kone_groups,
};
static int kone_init_kone_device_struct(struct usb_device *usb_dev,
struct kone_device *kone)
{
......@@ -712,8 +715,8 @@ static int kone_init_specials(struct hid_device *hdev)
goto exit_free;
}
retval = roccat_connect(kone_class, hdev,
sizeof(struct kone_roccat_report));
retval = roccat_connect(&kone_class, hdev,
sizeof(struct kone_roccat_report));
if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n");
/* be tolerant about not getting chrdev */
......@@ -890,21 +893,20 @@ static int __init kone_init(void)
int retval;
/* class name has to be same as driver name */
kone_class = class_create("kone");
if (IS_ERR(kone_class))
return PTR_ERR(kone_class);
kone_class->dev_groups = kone_groups;
retval = class_register(&kone_class);
if (retval)
return retval;
retval = hid_register_driver(&kone_driver);
if (retval)
class_destroy(kone_class);
class_unregister(&kone_class);
return retval;
}
static void __exit kone_exit(void)
{
hid_unregister_driver(&kone_driver);
class_destroy(kone_class);
class_unregister(&kone_class);
}
module_init(kone_init);
......
......@@ -26,8 +26,6 @@
static uint profile_numbers[5] = {0, 1, 2, 3, 4};
static struct class *koneplus_class;
static void koneplus_profile_activated(struct koneplus_device *koneplus,
uint new_profile)
{
......@@ -356,6 +354,11 @@ static const struct attribute_group *koneplus_groups[] = {
NULL,
};
static const struct class koneplus_class = {
.name = "koneplus",
.dev_groups = koneplus_groups,
};
static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
struct koneplus_device *koneplus)
{
......@@ -394,8 +397,8 @@ static int koneplus_init_specials(struct hid_device *hdev)
goto exit_free;
}
retval = roccat_connect(koneplus_class, hdev,
sizeof(struct koneplus_roccat_report));
retval = roccat_connect(&koneplus_class, hdev,
sizeof(struct koneplus_roccat_report));
if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n");
} else {
......@@ -549,21 +552,20 @@ static int __init koneplus_init(void)
int retval;
/* class name has to be same as driver name */
koneplus_class = class_create("koneplus");
if (IS_ERR(koneplus_class))
return PTR_ERR(koneplus_class);
koneplus_class->dev_groups = koneplus_groups;
retval = class_register(&koneplus_class);
if (retval)
return retval;
retval = hid_register_driver(&koneplus_driver);
if (retval)
class_destroy(koneplus_class);
class_unregister(&koneplus_class);
return retval;
}
static void __exit koneplus_exit(void)
{
hid_unregister_driver(&koneplus_driver);
class_destroy(koneplus_class);
class_unregister(&koneplus_class);
}
module_init(koneplus_init);
......
......@@ -36,8 +36,6 @@ struct konepure_mouse_report_button {
uint8_t unknown[2];
} __packed;
static struct class *konepure_class;
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x04, 0x03);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(actual_profile, 0x05, 0x03);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile_settings, 0x06, 0x1f);
......@@ -72,6 +70,11 @@ static const struct attribute_group *konepure_groups[] = {
NULL,
};
static const struct class konepure_class = {
.name = "konepure",
.dev_groups = konepure_groups,
};
static int konepure_init_specials(struct hid_device *hdev)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
......@@ -98,8 +101,8 @@ static int konepure_init_specials(struct hid_device *hdev)
goto exit_free;
}
retval = roccat_connect(konepure_class, hdev,
sizeof(struct konepure_mouse_report_button));
retval = roccat_connect(&konepure_class, hdev,
sizeof(struct konepure_mouse_report_button));
if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n");
} else {
......@@ -207,21 +210,20 @@ static int __init konepure_init(void)
{
int retval;
konepure_class = class_create("konepure");
if (IS_ERR(konepure_class))
return PTR_ERR(konepure_class);
konepure_class->dev_groups = konepure_groups;
retval = class_register(&konepure_class);
if (retval)
return retval;
retval = hid_register_driver(&konepure_driver);
if (retval)
class_destroy(konepure_class);
class_unregister(&konepure_class);
return retval;
}
static void __exit konepure_exit(void)
{
hid_unregister_driver(&konepure_driver);
class_destroy(konepure_class);
class_unregister(&konepure_class);
}
module_init(konepure_init);
......
......@@ -24,8 +24,6 @@
static uint profile_numbers[5] = {0, 1, 2, 3, 4};
static struct class *kovaplus_class;
static uint kovaplus_convert_event_cpi(uint value)
{
return (value == 7 ? 4 : (value == 4 ? 3 : value));
......@@ -409,6 +407,11 @@ static const struct attribute_group *kovaplus_groups[] = {
NULL,
};
static const struct class kovaplus_class = {
.name = "kovaplus",
.dev_groups = kovaplus_groups,
};
static int kovaplus_init_kovaplus_device_struct(struct usb_device *usb_dev,
struct kovaplus_device *kovaplus)
{
......@@ -463,8 +466,8 @@ static int kovaplus_init_specials(struct hid_device *hdev)
goto exit_free;
}
retval = roccat_connect(kovaplus_class, hdev,
sizeof(struct kovaplus_roccat_report));
retval = roccat_connect(&kovaplus_class, hdev,
sizeof(struct kovaplus_roccat_report));
if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n");
} else {
......@@ -638,21 +641,20 @@ static int __init kovaplus_init(void)
{
int retval;
kovaplus_class = class_create("kovaplus");
if (IS_ERR(kovaplus_class))
return PTR_ERR(kovaplus_class);
kovaplus_class->dev_groups = kovaplus_groups;
retval = class_register(&kovaplus_class);
if (retval)
return retval;
retval = hid_register_driver(&kovaplus_driver);
if (retval)
class_destroy(kovaplus_class);
class_unregister(&kovaplus_class);
return retval;
}
static void __exit kovaplus_exit(void)
{
hid_unregister_driver(&kovaplus_driver);
class_destroy(kovaplus_class);
class_unregister(&kovaplus_class);
}
module_init(kovaplus_init);
......
......@@ -26,9 +26,6 @@
static uint profile_numbers[5] = {0, 1, 2, 3, 4};
/* pyra_class is used for creating sysfs attributes via roccat char device */
static struct class *pyra_class;
static void profile_activated(struct pyra_device *pyra,
unsigned int new_profile)
{
......@@ -366,6 +363,12 @@ static const struct attribute_group *pyra_groups[] = {
NULL,
};
/* pyra_class is used for creating sysfs attributes via roccat char device */
static const struct class pyra_class = {
.name = "pyra",
.dev_groups = pyra_groups,
};
static int pyra_init_pyra_device_struct(struct usb_device *usb_dev,
struct pyra_device *pyra)
{
......@@ -413,7 +416,7 @@ static int pyra_init_specials(struct hid_device *hdev)
goto exit_free;
}
retval = roccat_connect(pyra_class, hdev,
retval = roccat_connect(&pyra_class, hdev,
sizeof(struct pyra_roccat_report));
if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n");
......@@ -585,21 +588,20 @@ static int __init pyra_init(void)
int retval;
/* class name has to be same as driver name */
pyra_class = class_create("pyra");
if (IS_ERR(pyra_class))
return PTR_ERR(pyra_class);
pyra_class->dev_groups = pyra_groups;
retval = class_register(&pyra_class);
if (retval)
return retval;
retval = hid_register_driver(&pyra_driver);
if (retval)
class_destroy(pyra_class);
class_unregister(&pyra_class);
return retval;
}
static void __exit pyra_exit(void)
{
hid_unregister_driver(&pyra_driver);
class_destroy(pyra_class);
class_unregister(&pyra_class);
}
module_init(pyra_init);
......
......@@ -28,8 +28,6 @@ struct ryos_report_special {
uint8_t data[4];
} __packed;
static struct class *ryos_class;
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x04, 0x03);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile, 0x05, 0x03);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(keys_primary, 0x06, 0x7d);
......@@ -80,6 +78,11 @@ static const struct attribute_group *ryos_groups[] = {
NULL,
};
static const struct class ryos_class = {
.name = "ryos",
.dev_groups = ryos_groups,
};
static int ryos_init_specials(struct hid_device *hdev)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
......@@ -106,7 +109,7 @@ static int ryos_init_specials(struct hid_device *hdev)
goto exit_free;
}
retval = roccat_connect(ryos_class, hdev,
retval = roccat_connect(&ryos_class, hdev,
sizeof(struct ryos_report_special));
if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n");
......@@ -216,21 +219,20 @@ static int __init ryos_init(void)
{
int retval;
ryos_class = class_create("ryos");
if (IS_ERR(ryos_class))
return PTR_ERR(ryos_class);
ryos_class->dev_groups = ryos_groups;
retval = class_register(&ryos_class);
if (retval)
return retval;
retval = hid_register_driver(&ryos_driver);
if (retval)
class_destroy(ryos_class);
class_unregister(&ryos_class);
return retval;
}
static void __exit ryos_exit(void)
{
hid_unregister_driver(&ryos_driver);
class_destroy(ryos_class);
class_unregister(&ryos_class);
}
module_init(ryos_init);
......
......@@ -22,8 +22,6 @@
#include "hid-roccat-common.h"
#include "hid-roccat-savu.h"
static struct class *savu_class;
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x4, 0x03);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile, 0x5, 0x03);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(general, 0x6, 0x10);
......@@ -52,6 +50,11 @@ static const struct attribute_group *savu_groups[] = {
NULL,
};
static const struct class savu_class = {
.name = "savu",
.dev_groups = savu_groups,
};
static int savu_init_specials(struct hid_device *hdev)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
......@@ -78,7 +81,7 @@ static int savu_init_specials(struct hid_device *hdev)
goto exit_free;
}
retval = roccat_connect(savu_class, hdev,
retval = roccat_connect(&savu_class, hdev,
sizeof(struct savu_roccat_report));
if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n");
......@@ -204,21 +207,20 @@ static int __init savu_init(void)
{
int retval;
savu_class = class_create("savu");
if (IS_ERR(savu_class))
return PTR_ERR(savu_class);
savu_class->dev_groups = savu_groups;
retval = class_register(&savu_class);
if (retval)
return retval;
retval = hid_register_driver(&savu_driver);
if (retval)
class_destroy(savu_class);
class_unregister(&savu_class);
return retval;
}
static void __exit savu_exit(void)
{
hid_unregister_driver(&savu_driver);
class_destroy(savu_class);
class_unregister(&savu_class);
}
module_init(savu_init);
......
......@@ -295,7 +295,7 @@ EXPORT_SYMBOL_GPL(roccat_report_event);
* Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on
* success, a negative error code on failure.
*/
int roccat_connect(struct class *klass, struct hid_device *hid, int report_size)
int roccat_connect(const struct class *klass, struct hid_device *hid, int report_size)
{
unsigned int minor;
struct roccat_device *device;
......
......@@ -32,7 +32,9 @@
static int hidraw_major;
static struct cdev hidraw_cdev;
static struct class *hidraw_class;
static const struct class hidraw_class = {
.name = "hidraw",
};
static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
static DECLARE_RWSEM(minors_rwsem);
......@@ -329,7 +331,7 @@ static void drop_ref(struct hidraw *hidraw, int exists_bit)
hid_hw_close(hidraw->hid);
wake_up_interruptible(&hidraw->wait);
}
device_destroy(hidraw_class,
device_destroy(&hidraw_class,
MKDEV(hidraw_major, hidraw->minor));
} else {
--hidraw->open;
......@@ -569,7 +571,7 @@ int hidraw_connect(struct hid_device *hid)
goto out;
}
dev->dev = device_create(hidraw_class, &hid->dev, MKDEV(hidraw_major, minor),
dev->dev = device_create(&hidraw_class, &hid->dev, MKDEV(hidraw_major, minor),
NULL, "%s%d", "hidraw", minor);
if (IS_ERR(dev->dev)) {
......@@ -623,11 +625,9 @@ int __init hidraw_init(void)
hidraw_major = MAJOR(dev_id);
hidraw_class = class_create("hidraw");
if (IS_ERR(hidraw_class)) {
result = PTR_ERR(hidraw_class);
result = class_register(&hidraw_class);
if (result)
goto error_cdev;
}
cdev_init(&hidraw_cdev, &hidraw_ops);
result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
......@@ -639,7 +639,7 @@ int __init hidraw_init(void)
return result;
error_class:
class_destroy(hidraw_class);
class_unregister(&hidraw_class);
error_cdev:
unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
goto out;
......@@ -650,7 +650,7 @@ void hidraw_exit(void)
dev_t dev_id = MKDEV(hidraw_major, 0);
cdev_del(&hidraw_cdev);
class_destroy(hidraw_class);
class_unregister(&hidraw_class);
unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
}
......@@ -383,9 +383,11 @@ static int kernfs_link_sibling(struct kernfs_node *kn)
rb_insert_color(&kn->rb, &kn->parent->dir.children);
/* successfully added, account subdir number */
down_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
if (kernfs_type(kn) == KERNFS_DIR)
kn->parent->dir.subdirs++;
kernfs_inc_rev(kn->parent);
up_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
return 0;
}
......@@ -408,9 +410,11 @@ static bool kernfs_unlink_sibling(struct kernfs_node *kn)
if (RB_EMPTY_NODE(&kn->rb))
return false;
down_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
if (kernfs_type(kn) == KERNFS_DIR)
kn->parent->dir.subdirs--;
kernfs_inc_rev(kn->parent);
up_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
rb_erase(&kn->rb, &kn->parent->dir.children);
RB_CLEAR_NODE(&kn->rb);
......
......@@ -16,6 +16,8 @@
#include <linux/namei.h>
#include <linux/seq_file.h>
#include <linux/exportfs.h>
#include <linux/uuid.h>
#include <linux/statfs.h>
#include "kernfs-internal.h"
......@@ -45,8 +47,15 @@ static int kernfs_sop_show_path(struct seq_file *sf, struct dentry *dentry)
return 0;
}
static int kernfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
simple_statfs(dentry, buf);
buf->f_fsid = uuid_to_fsid(dentry->d_sb->s_uuid.b);
return 0;
}
const struct super_operations kernfs_sops = {
.statfs = simple_statfs,
.statfs = kernfs_statfs,
.drop_inode = generic_delete_inode,
.evict_inode = kernfs_evict_inode,
......@@ -351,6 +360,8 @@ int kernfs_get_tree(struct fs_context *fc)
}
sb->s_flags |= SB_ACTIVE;
uuid_gen(&sb->s_uuid);
down_write(&root->kernfs_supers_rwsem);
list_add(&info->node, &info->root->supers);
up_write(&root->kernfs_supers_rwsem);
......
......@@ -274,4 +274,6 @@ do { \
WARN_ONCE(condition, "%s %s: " format, \
dev_driver_string(dev), dev_name(dev), ## arg)
__printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...);
#endif /* _DEVICE_PRINTK_H_ */
......@@ -1249,8 +1249,6 @@ void device_link_remove(void *consumer, struct device *supplier);
void device_links_supplier_sync_state_pause(void);
void device_links_supplier_sync_state_resume(void);
__printf(3, 4) int dev_err_probe(const struct device *dev, int err, const char *fmt, ...);
/* Create alias, so I can be autoloaded. */
#define MODULE_ALIAS_CHARDEV(major,minor) \
MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor))
......
......@@ -16,7 +16,7 @@
#ifdef __KERNEL__
int roccat_connect(struct class *klass, struct hid_device *hid,
int roccat_connect(const struct class *klass, struct hid_device *hid,
int report_size);
void roccat_disconnect(int minor);
int roccat_report_event(int minor, u8 const *data);
......
......@@ -550,6 +550,10 @@ static inline int kernfs_setattr(struct kernfs_node *kn,
const struct iattr *iattr)
{ return -ENOSYS; }
static inline __poll_t kernfs_generic_poll(struct kernfs_open_file *of,
struct poll_table_struct *pt)
{ return -ENOSYS; }
static inline void kernfs_notify(struct kernfs_node *kn) { }
static inline int kernfs_xattr_get(struct kernfs_node *kn, const char *name,
......
......@@ -69,14 +69,16 @@ struct kobject {
const struct kobj_type *ktype;
struct kernfs_node *sd; /* sysfs directory entry */
struct kref kref;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
struct delayed_work release;
#endif
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
struct delayed_work release;
#endif
};
__printf(2, 3) int kobject_set_name(struct kobject *kobj, const char *name, ...);
......
......@@ -56,6 +56,14 @@ void kobject_get_ownership(const struct kobject *kobj, kuid_t *uid, kgid_t *gid)
kobj->ktype->get_ownership(kobj, uid, gid);
}
static bool kobj_ns_type_is_valid(enum kobj_ns_type type)
{
if ((type <= KOBJ_NS_TYPE_NONE) || (type >= KOBJ_NS_TYPES))
return false;
return true;
}
static int create_dir(struct kobject *kobj)
{
const struct kobj_type *ktype = get_ktype(kobj);
......@@ -66,12 +74,10 @@ static int create_dir(struct kobject *kobj)
if (error)
return error;
if (ktype) {
error = sysfs_create_groups(kobj, ktype->default_groups);
if (error) {
sysfs_remove_dir(kobj);
return error;
}
error = sysfs_create_groups(kobj, ktype->default_groups);
if (error) {
sysfs_remove_dir(kobj);
return error;
}
/*
......@@ -86,8 +92,7 @@ static int create_dir(struct kobject *kobj)
*/
ops = kobj_child_ns_ops(kobj);
if (ops) {
BUG_ON(ops->type <= KOBJ_NS_TYPE_NONE);
BUG_ON(ops->type >= KOBJ_NS_TYPES);
BUG_ON(!kobj_ns_type_is_valid(ops->type));
BUG_ON(!kobj_ns_type_registered(ops->type));
sysfs_enable_ns(kobj->sd);
......@@ -584,8 +589,7 @@ static void __kobject_del(struct kobject *kobj)
sd = kobj->sd;
ktype = get_ktype(kobj);
if (ktype)
sysfs_remove_groups(kobj, ktype->default_groups);
sysfs_remove_groups(kobj, ktype->default_groups);
/* send "remove" if the caller did not do it but sent "add" */
if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) {
......@@ -662,10 +666,6 @@ static void kobject_cleanup(struct kobject *kobj)
pr_debug("'%s' (%p): %s, parent %p\n",
kobject_name(kobj), kobj, __func__, kobj->parent);
if (t && !t->release)
pr_debug("'%s' (%p): does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst.\n",
kobject_name(kobj), kobj);
/* remove from sysfs if the caller did not do it */
if (kobj->state_in_sysfs) {
pr_debug("'%s' (%p): auto cleanup kobject_del\n",
......@@ -676,10 +676,13 @@ static void kobject_cleanup(struct kobject *kobj)
parent = NULL;
}
if (t && t->release) {
if (t->release) {
pr_debug("'%s' (%p): calling ktype release\n",
kobject_name(kobj), kobj);
t->release(kobj);
} else {
pr_debug("'%s' (%p): does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst.\n",
kobject_name(kobj), kobj);
}
/* free name if we allocated it */
......@@ -854,6 +857,11 @@ int kset_register(struct kset *k)
if (!k)
return -EINVAL;
if (!k->kobj.ktype) {
pr_err("must have a ktype to be initialized properly!\n");
return -EINVAL;
}
kset_init(k);
err = kobject_add_internal(&k->kobj);
if (err) {
......@@ -1017,11 +1025,7 @@ int kobj_ns_type_register(const struct kobj_ns_type_operations *ops)
spin_lock(&kobj_ns_type_lock);
error = -EINVAL;
if (type >= KOBJ_NS_TYPES)
goto out;
error = -EINVAL;
if (type <= KOBJ_NS_TYPE_NONE)
if (!kobj_ns_type_is_valid(type))
goto out;
error = -EBUSY;
......@@ -1041,7 +1045,7 @@ int kobj_ns_type_registered(enum kobj_ns_type type)
int registered = 0;
spin_lock(&kobj_ns_type_lock);
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES))
if (kobj_ns_type_is_valid(type))
registered = kobj_ns_ops_tbl[type] != NULL;
spin_unlock(&kobj_ns_type_lock);
......@@ -1052,7 +1056,7 @@ const struct kobj_ns_type_operations *kobj_child_ns_ops(const struct kobject *pa
{
const struct kobj_ns_type_operations *ops = NULL;
if (parent && parent->ktype && parent->ktype->child_ns_type)
if (parent && parent->ktype->child_ns_type)
ops = parent->ktype->child_ns_type(parent);
return ops;
......@@ -1068,8 +1072,7 @@ bool kobj_ns_current_may_mount(enum kobj_ns_type type)
bool may_mount = true;
spin_lock(&kobj_ns_type_lock);
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
kobj_ns_ops_tbl[type])
if (kobj_ns_type_is_valid(type) && kobj_ns_ops_tbl[type])
may_mount = kobj_ns_ops_tbl[type]->current_may_mount();
spin_unlock(&kobj_ns_type_lock);
......@@ -1081,8 +1084,7 @@ void *kobj_ns_grab_current(enum kobj_ns_type type)
void *ns = NULL;
spin_lock(&kobj_ns_type_lock);
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
kobj_ns_ops_tbl[type])
if (kobj_ns_type_is_valid(type) && kobj_ns_ops_tbl[type])
ns = kobj_ns_ops_tbl[type]->grab_current_ns();
spin_unlock(&kobj_ns_type_lock);
......@@ -1095,8 +1097,7 @@ const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk)
const void *ns = NULL;
spin_lock(&kobj_ns_type_lock);
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
kobj_ns_ops_tbl[type])
if (kobj_ns_type_is_valid(type) && kobj_ns_ops_tbl[type])
ns = kobj_ns_ops_tbl[type]->netlink_ns(sk);
spin_unlock(&kobj_ns_type_lock);
......@@ -1108,8 +1109,7 @@ const void *kobj_ns_initial(enum kobj_ns_type type)
const void *ns = NULL;
spin_lock(&kobj_ns_type_lock);
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
kobj_ns_ops_tbl[type])
if (kobj_ns_type_is_valid(type) && kobj_ns_ops_tbl[type])
ns = kobj_ns_ops_tbl[type]->initial_ns();
spin_unlock(&kobj_ns_type_lock);
......@@ -1119,7 +1119,7 @@ const void *kobj_ns_initial(enum kobj_ns_type type)
void kobj_ns_drop(enum kobj_ns_type type, void *ns)
{
spin_lock(&kobj_ns_type_lock);
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
if (kobj_ns_type_is_valid(type) &&
kobj_ns_ops_tbl[type] && kobj_ns_ops_tbl[type]->drop_ns)
kobj_ns_ops_tbl[type]->drop_ns(ns);
spin_unlock(&kobj_ns_type_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment