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; ...@@ -45,7 +45,21 @@ static u64 prefetch_disable_bits;
*/ */
static unsigned int pseudo_lock_major; static unsigned int pseudo_lock_major;
static unsigned long pseudo_lock_minor_avail = GENMASK(MINORBITS, 0); 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 * get_prefetch_disable_bits - prefetch disable bits of supported platforms
...@@ -1353,7 +1367,7 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp) ...@@ -1353,7 +1367,7 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp)
&pseudo_measure_fops); &pseudo_measure_fops);
} }
dev = device_create(pseudo_lock_class, NULL, dev = device_create(&pseudo_lock_class, NULL,
MKDEV(pseudo_lock_major, new_minor), MKDEV(pseudo_lock_major, new_minor),
rdtgrp, "%s", rdtgrp->kn->name); rdtgrp, "%s", rdtgrp->kn->name);
...@@ -1383,7 +1397,7 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp) ...@@ -1383,7 +1397,7 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp)
goto out; goto out;
out_device: 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: out_debugfs:
debugfs_remove_recursive(plr->debugfs_dir); debugfs_remove_recursive(plr->debugfs_dir);
pseudo_lock_minor_release(new_minor); pseudo_lock_minor_release(new_minor);
...@@ -1424,7 +1438,7 @@ void rdtgroup_pseudo_lock_remove(struct rdtgroup *rdtgrp) ...@@ -1424,7 +1438,7 @@ void rdtgroup_pseudo_lock_remove(struct rdtgroup *rdtgrp)
pseudo_lock_cstates_relax(plr); pseudo_lock_cstates_relax(plr);
debugfs_remove_recursive(rdtgrp->plr->debugfs_dir); 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); pseudo_lock_minor_release(plr->minor);
free: free:
...@@ -1560,16 +1574,6 @@ static const struct file_operations pseudo_lock_dev_fops = { ...@@ -1560,16 +1574,6 @@ static const struct file_operations pseudo_lock_dev_fops = {
.mmap = pseudo_lock_dev_mmap, .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 rdt_pseudo_lock_init(void)
{ {
int ret; int ret;
...@@ -1580,21 +1584,18 @@ int rdt_pseudo_lock_init(void) ...@@ -1580,21 +1584,18 @@ int rdt_pseudo_lock_init(void)
pseudo_lock_major = ret; pseudo_lock_major = ret;
pseudo_lock_class = class_create("pseudo_lock"); ret = class_register(&pseudo_lock_class);
if (IS_ERR(pseudo_lock_class)) { if (ret) {
ret = PTR_ERR(pseudo_lock_class);
unregister_chrdev(pseudo_lock_major, "pseudo_lock"); unregister_chrdev(pseudo_lock_major, "pseudo_lock");
return ret; return ret;
} }
pseudo_lock_class->devnode = pseudo_lock_devnode;
return 0; return 0;
} }
void rdt_pseudo_lock_release(void) void rdt_pseudo_lock_release(void)
{ {
class_destroy(pseudo_lock_class); class_unregister(&pseudo_lock_class);
pseudo_lock_class = NULL;
unregister_chrdev(pseudo_lock_major, "pseudo_lock"); unregister_chrdev(pseudo_lock_major, "pseudo_lock");
pseudo_lock_major = 0; pseudo_lock_major = 0;
} }
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/msr.h> #include <asm/msr.h>
static struct class *cpuid_class;
static enum cpuhp_state cpuhp_cpuid_state; static enum cpuhp_state cpuhp_cpuid_state;
struct cpuid_regs_done { struct cpuid_regs_done {
...@@ -124,26 +123,31 @@ static const struct file_operations cpuid_fops = { ...@@ -124,26 +123,31 @@ static const struct file_operations cpuid_fops = {
.open = cpuid_open, .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) static int cpuid_device_create(unsigned int cpu)
{ {
struct device *dev; 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); "cpu%d", cpu);
return PTR_ERR_OR_ZERO(dev); return PTR_ERR_OR_ZERO(dev);
} }
static int cpuid_device_destroy(unsigned int cpu) 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; 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) static int __init cpuid_init(void)
{ {
int err; int err;
...@@ -154,12 +158,9 @@ static int __init cpuid_init(void) ...@@ -154,12 +158,9 @@ static int __init cpuid_init(void)
CPUID_MAJOR); CPUID_MAJOR);
return -EBUSY; return -EBUSY;
} }
cpuid_class = class_create("cpuid"); err = class_register(&cpuid_class);
if (IS_ERR(cpuid_class)) { if (err)
err = PTR_ERR(cpuid_class);
goto out_chrdev; goto out_chrdev;
}
cpuid_class->devnode = cpuid_devnode;
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/cpuid:online", err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/cpuid:online",
cpuid_device_create, cpuid_device_destroy); cpuid_device_create, cpuid_device_destroy);
...@@ -170,7 +171,7 @@ static int __init cpuid_init(void) ...@@ -170,7 +171,7 @@ static int __init cpuid_init(void)
return 0; return 0;
out_class: out_class:
class_destroy(cpuid_class); class_unregister(&cpuid_class);
out_chrdev: out_chrdev:
__unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid"); __unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid");
return err; return err;
...@@ -180,7 +181,7 @@ module_init(cpuid_init); ...@@ -180,7 +181,7 @@ module_init(cpuid_init);
static void __exit cpuid_exit(void) static void __exit cpuid_exit(void)
{ {
cpuhp_remove_state(cpuhp_cpuid_state); cpuhp_remove_state(cpuhp_cpuid_state);
class_destroy(cpuid_class); class_unregister(&cpuid_class);
__unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid"); __unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid");
} }
module_exit(cpuid_exit); module_exit(cpuid_exit);
......
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
#include <asm/cpufeature.h> #include <asm/cpufeature.h>
#include <asm/msr.h> #include <asm/msr.h>
static struct class *msr_class;
static enum cpuhp_state cpuhp_msr_state; static enum cpuhp_state cpuhp_msr_state;
enum allow_write_msrs { enum allow_write_msrs {
...@@ -235,26 +234,31 @@ static const struct file_operations msr_fops = { ...@@ -235,26 +234,31 @@ static const struct file_operations msr_fops = {
.compat_ioctl = msr_ioctl, .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) static int msr_device_create(unsigned int cpu)
{ {
struct device *dev; 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); "msr%d", cpu);
return PTR_ERR_OR_ZERO(dev); return PTR_ERR_OR_ZERO(dev);
} }
static int msr_device_destroy(unsigned int cpu) 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; 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) static int __init msr_init(void)
{ {
int err; int err;
...@@ -263,12 +267,9 @@ static int __init msr_init(void) ...@@ -263,12 +267,9 @@ static int __init msr_init(void)
pr_err("unable to get major %d for msr\n", MSR_MAJOR); pr_err("unable to get major %d for msr\n", MSR_MAJOR);
return -EBUSY; return -EBUSY;
} }
msr_class = class_create("msr"); err = class_register(&msr_class);
if (IS_ERR(msr_class)) { if (err)
err = PTR_ERR(msr_class);
goto out_chrdev; goto out_chrdev;
}
msr_class->devnode = msr_devnode;
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/msr:online", err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/msr:online",
msr_device_create, msr_device_destroy); msr_device_create, msr_device_destroy);
...@@ -278,7 +279,7 @@ static int __init msr_init(void) ...@@ -278,7 +279,7 @@ static int __init msr_init(void)
return 0; return 0;
out_class: out_class:
class_destroy(msr_class); class_unregister(&msr_class);
out_chrdev: out_chrdev:
__unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr"); __unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
return err; return err;
...@@ -288,7 +289,7 @@ module_init(msr_init); ...@@ -288,7 +289,7 @@ module_init(msr_init);
static void __exit msr_exit(void) static void __exit msr_exit(void)
{ {
cpuhp_remove_state(cpuhp_msr_state); cpuhp_remove_state(cpuhp_msr_state);
class_destroy(msr_class); class_unregister(&msr_class);
__unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr"); __unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
} }
module_exit(msr_exit) module_exit(msr_exit)
......
...@@ -2306,12 +2306,12 @@ static void device_platform_notify(struct device *dev) ...@@ -2306,12 +2306,12 @@ static void device_platform_notify(struct device *dev)
static void device_platform_notify_remove(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); software_node_notify_remove(dev);
if (platform_notify_remove) acpi_device_notify_remove(dev);
platform_notify_remove(dev);
} }
/** /**
...@@ -3528,18 +3528,17 @@ int device_add(struct device *dev) ...@@ -3528,18 +3528,17 @@ int device_add(struct device *dev)
* the name, and force the use of dev_name() * the name, and force the use of dev_name()
*/ */
if (dev->init_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; dev->init_name = NULL;
} }
if (dev_name(dev))
error = 0;
/* subsystems can specify simple device enumeration */ /* subsystems can specify simple device enumeration */
if (!dev_name(dev) && dev->bus && dev->bus->dev_name) else if (dev->bus && dev->bus->dev_name)
dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id); error = dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
if (error)
if (!dev_name(dev)) {
error = -EINVAL;
goto name_error; goto name_error;
}
pr_debug("device: '%s': %s\n", dev_name(dev), __func__); pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
...@@ -3815,6 +3814,17 @@ void device_del(struct device *dev) ...@@ -3815,6 +3814,17 @@ void device_del(struct device *dev)
device_platform_notify_remove(dev); device_platform_notify_remove(dev);
device_links_purge(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); bus_notify(dev, BUS_NOTIFY_REMOVED_DEVICE);
kobject_uevent(&dev->kobj, KOBJ_REMOVE); kobject_uevent(&dev->kobj, KOBJ_REMOVE);
glue_dir = get_glue_dir(dev); glue_dir = get_glue_dir(dev);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/cpufeature.h> #include <linux/cpufeature.h>
#include <linux/tick.h> #include <linux/tick.h>
#include <linux/pm_qos.h> #include <linux/pm_qos.h>
#include <linux/delay.h>
#include <linux/sched/isolation.h> #include <linux/sched/isolation.h>
#include "base.h" #include "base.h"
...@@ -50,12 +51,30 @@ static int cpu_subsys_online(struct device *dev) ...@@ -50,12 +51,30 @@ static int cpu_subsys_online(struct device *dev)
int cpuid = dev->id; int cpuid = dev->id;
int from_nid, to_nid; int from_nid, to_nid;
int ret; int ret;
int retries = 0;
from_nid = cpu_to_node(cpuid); from_nid = cpu_to_node(cpuid);
if (from_nid == NUMA_NO_NODE) if (from_nid == NUMA_NO_NODE)
return -ENODEV; return -ENODEV;
retry:
ret = cpu_device_up(dev); 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 * When hot adding memory to memoryless node and enabling a cpu
* on the node, node number of the cpu may internally change. * 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) ...@@ -693,6 +693,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
device_remove(dev); device_remove(dev);
driver_sysfs_remove(dev); driver_sysfs_remove(dev);
if (dev->bus && dev->bus->dma_cleanup)
dev->bus->dma_cleanup(dev);
device_unbind_cleanup(dev); device_unbind_cleanup(dev);
goto re_probe; goto re_probe;
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/hugetlb.h>
static struct bus_type node_subsys = { static struct bus_type node_subsys = {
.name = "node", .name = "node",
......
CONFIG_KUNIT=y
CONFIG_DM_KUNIT_TEST=y
...@@ -9,6 +9,10 @@ config TEST_ASYNC_DRIVER_PROBE ...@@ -9,6 +9,10 @@ config TEST_ASYNC_DRIVER_PROBE
If unsure say N. 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 config DRIVER_PE_KUNIT_TEST
bool "KUnit Tests for property entry API" if !KUNIT_ALL_TESTS bool "KUnit Tests for property entry API" if !KUNIT_ALL_TESTS
depends on KUNIT=y depends on KUNIT=y
......
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_TEST_ASYNC_DRIVER_PROBE) += test_async_driver_probe.o 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 obj-$(CONFIG_DRIVER_PE_KUNIT_TEST) += property-entry-test.o
CFLAGS_property-entry-test.o += $(DISABLE_STRUCTLEAK_PLUGIN) 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) ...@@ -84,7 +84,7 @@ test_platform_device_register_node(char *name, int id, int nid)
pdev = platform_device_alloc(name, id); pdev = platform_device_alloc(name, id);
if (!pdev) if (!pdev)
return NULL; return ERR_PTR(-ENOMEM);
if (nid != NUMA_NO_NODE) if (nid != NUMA_NO_NODE)
set_dev_node(&pdev->dev, nid); set_dev_node(&pdev->dev, nid);
......
...@@ -28,8 +28,13 @@ ...@@ -28,8 +28,13 @@
DEFINE_IDR(dev_nums_idr); DEFINE_IDR(dev_nums_idr);
static DEFINE_MUTEX(idr_lock); static DEFINE_MUTEX(idr_lock);
struct class *tpm_class; const struct class tpm_class = {
struct class *tpmrm_class; .name = "tpm",
.shutdown_pre = tpm_class_shutdown,
};
const struct class tpmrm_class = {
.name = "tmprm",
};
dev_t tpm_devt; dev_t tpm_devt;
static int tpm_request_locality(struct tpm_chip *chip) static int tpm_request_locality(struct tpm_chip *chip)
...@@ -336,7 +341,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, ...@@ -336,7 +341,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
device_initialize(&chip->dev); device_initialize(&chip->dev);
chip->dev.class = tpm_class; chip->dev.class = &tpm_class;
chip->dev.release = tpm_dev_release; chip->dev.release = tpm_dev_release;
chip->dev.parent = pdev; chip->dev.parent = pdev;
chip->dev.groups = chip->groups; chip->dev.groups = chip->groups;
......
...@@ -476,18 +476,15 @@ static int __init tpm_init(void) ...@@ -476,18 +476,15 @@ static int __init tpm_init(void)
{ {
int rc; int rc;
tpm_class = class_create("tpm"); rc = class_register(&tpm_class);
if (IS_ERR(tpm_class)) { if (rc) {
pr_err("couldn't create tpm class\n"); pr_err("couldn't create tpm class\n");
return PTR_ERR(tpm_class); return rc;
} }
tpm_class->shutdown_pre = tpm_class_shutdown; rc = class_register(&tpmrm_class);
if (rc) {
tpmrm_class = class_create("tpmrm");
if (IS_ERR(tpmrm_class)) {
pr_err("couldn't create tpmrm class\n"); pr_err("couldn't create tpmrm class\n");
rc = PTR_ERR(tpmrm_class);
goto out_destroy_tpm_class; goto out_destroy_tpm_class;
} }
...@@ -508,9 +505,9 @@ static int __init tpm_init(void) ...@@ -508,9 +505,9 @@ static int __init tpm_init(void)
out_unreg_chrdev: out_unreg_chrdev:
unregister_chrdev_region(tpm_devt, 2 * TPM_NUM_DEVICES); unregister_chrdev_region(tpm_devt, 2 * TPM_NUM_DEVICES);
out_destroy_tpmrm_class: out_destroy_tpmrm_class:
class_destroy(tpmrm_class); class_unregister(&tpmrm_class);
out_destroy_tpm_class: out_destroy_tpm_class:
class_destroy(tpm_class); class_unregister(&tpm_class);
return rc; return rc;
} }
...@@ -518,8 +515,8 @@ static int __init tpm_init(void) ...@@ -518,8 +515,8 @@ static int __init tpm_init(void)
static void __exit tpm_exit(void) static void __exit tpm_exit(void)
{ {
idr_destroy(&dev_nums_idr); idr_destroy(&dev_nums_idr);
class_destroy(tpm_class); class_unregister(&tpm_class);
class_destroy(tpmrm_class); class_unregister(&tpmrm_class);
unregister_chrdev_region(tpm_devt, 2*TPM_NUM_DEVICES); unregister_chrdev_region(tpm_devt, 2*TPM_NUM_DEVICES);
tpm_dev_common_exit(); tpm_dev_common_exit();
} }
......
...@@ -230,8 +230,8 @@ enum tpm2_pt_props { ...@@ -230,8 +230,8 @@ enum tpm2_pt_props {
* compiler warnings about stack frame size. */ * compiler warnings about stack frame size. */
#define TPM_MAX_RNG_DATA 128 #define TPM_MAX_RNG_DATA 128
extern struct class *tpm_class; extern const struct class tpm_class;
extern struct class *tpmrm_class; extern const struct class tpmrm_class;
extern dev_t tpm_devt; extern dev_t tpm_devt;
extern const struct file_operations tpm_fops; extern const struct file_operations tpm_fops;
extern const struct file_operations tpmrm_fops; extern const struct file_operations tpmrm_fops;
......
...@@ -606,7 +606,7 @@ int tpm_devs_add(struct tpm_chip *chip) ...@@ -606,7 +606,7 @@ int tpm_devs_add(struct tpm_chip *chip)
device_initialize(&chip->devs); device_initialize(&chip->devs);
chip->devs.parent = chip->dev.parent; 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. * Get extra reference on main device to hold on behalf of devs.
......
...@@ -23,8 +23,6 @@ ...@@ -23,8 +23,6 @@
#include "hid-roccat-common.h" #include "hid-roccat-common.h"
#include "hid-roccat-arvo.h" #include "hid-roccat-arvo.h"
static struct class *arvo_class;
static ssize_t arvo_sysfs_show_mode_key(struct device *dev, static ssize_t arvo_sysfs_show_mode_key(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
...@@ -268,6 +266,11 @@ static const struct attribute_group *arvo_groups[] = { ...@@ -268,6 +266,11 @@ static const struct attribute_group *arvo_groups[] = {
NULL, 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, static int arvo_init_arvo_device_struct(struct usb_device *usb_dev,
struct arvo_device *arvo) struct arvo_device *arvo)
{ {
...@@ -309,7 +312,7 @@ static int arvo_init_specials(struct hid_device *hdev) ...@@ -309,7 +312,7 @@ static int arvo_init_specials(struct hid_device *hdev)
goto exit_free; goto exit_free;
} }
retval = roccat_connect(arvo_class, hdev, retval = roccat_connect(&arvo_class, hdev,
sizeof(struct arvo_roccat_report)); sizeof(struct arvo_roccat_report));
if (retval < 0) { if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n"); hid_err(hdev, "couldn't init char dev\n");
...@@ -433,21 +436,20 @@ static int __init arvo_init(void) ...@@ -433,21 +436,20 @@ static int __init arvo_init(void)
{ {
int retval; int retval;
arvo_class = class_create("arvo"); retval = class_register(&arvo_class);
if (IS_ERR(arvo_class)) if (retval)
return PTR_ERR(arvo_class); return retval;
arvo_class->dev_groups = arvo_groups;
retval = hid_register_driver(&arvo_driver); retval = hid_register_driver(&arvo_driver);
if (retval) if (retval)
class_destroy(arvo_class); class_unregister(&arvo_class);
return retval; return retval;
} }
static void __exit arvo_exit(void) static void __exit arvo_exit(void)
{ {
hid_unregister_driver(&arvo_driver); hid_unregister_driver(&arvo_driver);
class_destroy(arvo_class); class_unregister(&arvo_class);
} }
module_init(arvo_init); module_init(arvo_init);
......
...@@ -23,8 +23,6 @@ ...@@ -23,8 +23,6 @@
#include "hid-roccat-common.h" #include "hid-roccat-common.h"
#include "hid-roccat-isku.h" #include "hid-roccat-isku.h"
static struct class *isku_class;
static void isku_profile_activated(struct isku_device *isku, uint new_profile) static void isku_profile_activated(struct isku_device *isku, uint new_profile)
{ {
isku->actual_profile = new_profile; isku->actual_profile = new_profile;
...@@ -248,6 +246,11 @@ static const struct attribute_group *isku_groups[] = { ...@@ -248,6 +246,11 @@ static const struct attribute_group *isku_groups[] = {
NULL, 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, static int isku_init_isku_device_struct(struct usb_device *usb_dev,
struct isku_device *isku) struct isku_device *isku)
{ {
...@@ -289,7 +292,7 @@ static int isku_init_specials(struct hid_device *hdev) ...@@ -289,7 +292,7 @@ static int isku_init_specials(struct hid_device *hdev)
goto exit_free; goto exit_free;
} }
retval = roccat_connect(isku_class, hdev, retval = roccat_connect(&isku_class, hdev,
sizeof(struct isku_roccat_report)); sizeof(struct isku_roccat_report));
if (retval < 0) { if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n"); hid_err(hdev, "couldn't init char dev\n");
...@@ -435,21 +438,21 @@ static struct hid_driver isku_driver = { ...@@ -435,21 +438,21 @@ static struct hid_driver isku_driver = {
static int __init isku_init(void) static int __init isku_init(void)
{ {
int retval; int retval;
isku_class = class_create("isku");
if (IS_ERR(isku_class)) retval = class_register(&isku_class);
return PTR_ERR(isku_class); if (retval)
isku_class->dev_groups = isku_groups; return retval;
retval = hid_register_driver(&isku_driver); retval = hid_register_driver(&isku_driver);
if (retval) if (retval)
class_destroy(isku_class); class_unregister(&isku_class);
return retval; return retval;
} }
static void __exit isku_exit(void) static void __exit isku_exit(void)
{ {
hid_unregister_driver(&isku_driver); hid_unregister_driver(&isku_driver);
class_destroy(isku_class); class_unregister(&isku_class);
} }
module_init(isku_init); module_init(isku_init);
......
...@@ -89,9 +89,6 @@ static int kone_send(struct usb_device *usb_dev, uint usb_command, ...@@ -89,9 +89,6 @@ static int kone_send(struct usb_device *usb_dev, uint usb_command,
return ((len < 0) ? len : ((len != size) ? -EIO : 0)); 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) static void kone_set_settings_checksum(struct kone_settings *settings)
{ {
uint16_t checksum = 0; uint16_t checksum = 0;
...@@ -657,6 +654,12 @@ static const struct attribute_group *kone_groups[] = { ...@@ -657,6 +654,12 @@ static const struct attribute_group *kone_groups[] = {
NULL, 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, static int kone_init_kone_device_struct(struct usb_device *usb_dev,
struct kone_device *kone) struct kone_device *kone)
{ {
...@@ -712,8 +715,8 @@ static int kone_init_specials(struct hid_device *hdev) ...@@ -712,8 +715,8 @@ static int kone_init_specials(struct hid_device *hdev)
goto exit_free; goto exit_free;
} }
retval = roccat_connect(kone_class, hdev, retval = roccat_connect(&kone_class, hdev,
sizeof(struct kone_roccat_report)); sizeof(struct kone_roccat_report));
if (retval < 0) { if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n"); hid_err(hdev, "couldn't init char dev\n");
/* be tolerant about not getting chrdev */ /* be tolerant about not getting chrdev */
...@@ -890,21 +893,20 @@ static int __init kone_init(void) ...@@ -890,21 +893,20 @@ static int __init kone_init(void)
int retval; int retval;
/* class name has to be same as driver name */ /* class name has to be same as driver name */
kone_class = class_create("kone"); retval = class_register(&kone_class);
if (IS_ERR(kone_class)) if (retval)
return PTR_ERR(kone_class); return retval;
kone_class->dev_groups = kone_groups;
retval = hid_register_driver(&kone_driver); retval = hid_register_driver(&kone_driver);
if (retval) if (retval)
class_destroy(kone_class); class_unregister(&kone_class);
return retval; return retval;
} }
static void __exit kone_exit(void) static void __exit kone_exit(void)
{ {
hid_unregister_driver(&kone_driver); hid_unregister_driver(&kone_driver);
class_destroy(kone_class); class_unregister(&kone_class);
} }
module_init(kone_init); module_init(kone_init);
......
...@@ -26,8 +26,6 @@ ...@@ -26,8 +26,6 @@
static uint profile_numbers[5] = {0, 1, 2, 3, 4}; static uint profile_numbers[5] = {0, 1, 2, 3, 4};
static struct class *koneplus_class;
static void koneplus_profile_activated(struct koneplus_device *koneplus, static void koneplus_profile_activated(struct koneplus_device *koneplus,
uint new_profile) uint new_profile)
{ {
...@@ -356,6 +354,11 @@ static const struct attribute_group *koneplus_groups[] = { ...@@ -356,6 +354,11 @@ static const struct attribute_group *koneplus_groups[] = {
NULL, 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, static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
struct koneplus_device *koneplus) struct koneplus_device *koneplus)
{ {
...@@ -394,8 +397,8 @@ static int koneplus_init_specials(struct hid_device *hdev) ...@@ -394,8 +397,8 @@ static int koneplus_init_specials(struct hid_device *hdev)
goto exit_free; goto exit_free;
} }
retval = roccat_connect(koneplus_class, hdev, retval = roccat_connect(&koneplus_class, hdev,
sizeof(struct koneplus_roccat_report)); sizeof(struct koneplus_roccat_report));
if (retval < 0) { if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n"); hid_err(hdev, "couldn't init char dev\n");
} else { } else {
...@@ -549,21 +552,20 @@ static int __init koneplus_init(void) ...@@ -549,21 +552,20 @@ static int __init koneplus_init(void)
int retval; int retval;
/* class name has to be same as driver name */ /* class name has to be same as driver name */
koneplus_class = class_create("koneplus"); retval = class_register(&koneplus_class);
if (IS_ERR(koneplus_class)) if (retval)
return PTR_ERR(koneplus_class); return retval;
koneplus_class->dev_groups = koneplus_groups;
retval = hid_register_driver(&koneplus_driver); retval = hid_register_driver(&koneplus_driver);
if (retval) if (retval)
class_destroy(koneplus_class); class_unregister(&koneplus_class);
return retval; return retval;
} }
static void __exit koneplus_exit(void) static void __exit koneplus_exit(void)
{ {
hid_unregister_driver(&koneplus_driver); hid_unregister_driver(&koneplus_driver);
class_destroy(koneplus_class); class_unregister(&koneplus_class);
} }
module_init(koneplus_init); module_init(koneplus_init);
......
...@@ -36,8 +36,6 @@ struct konepure_mouse_report_button { ...@@ -36,8 +36,6 @@ struct konepure_mouse_report_button {
uint8_t unknown[2]; uint8_t unknown[2];
} __packed; } __packed;
static struct class *konepure_class;
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x04, 0x03); ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x04, 0x03);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(actual_profile, 0x05, 0x03); ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(actual_profile, 0x05, 0x03);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile_settings, 0x06, 0x1f); ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile_settings, 0x06, 0x1f);
...@@ -72,6 +70,11 @@ static const struct attribute_group *konepure_groups[] = { ...@@ -72,6 +70,11 @@ static const struct attribute_group *konepure_groups[] = {
NULL, NULL,
}; };
static const struct class konepure_class = {
.name = "konepure",
.dev_groups = konepure_groups,
};
static int konepure_init_specials(struct hid_device *hdev) static int konepure_init_specials(struct hid_device *hdev)
{ {
struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
...@@ -98,8 +101,8 @@ static int konepure_init_specials(struct hid_device *hdev) ...@@ -98,8 +101,8 @@ static int konepure_init_specials(struct hid_device *hdev)
goto exit_free; goto exit_free;
} }
retval = roccat_connect(konepure_class, hdev, retval = roccat_connect(&konepure_class, hdev,
sizeof(struct konepure_mouse_report_button)); sizeof(struct konepure_mouse_report_button));
if (retval < 0) { if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n"); hid_err(hdev, "couldn't init char dev\n");
} else { } else {
...@@ -207,21 +210,20 @@ static int __init konepure_init(void) ...@@ -207,21 +210,20 @@ static int __init konepure_init(void)
{ {
int retval; int retval;
konepure_class = class_create("konepure"); retval = class_register(&konepure_class);
if (IS_ERR(konepure_class)) if (retval)
return PTR_ERR(konepure_class); return retval;
konepure_class->dev_groups = konepure_groups;
retval = hid_register_driver(&konepure_driver); retval = hid_register_driver(&konepure_driver);
if (retval) if (retval)
class_destroy(konepure_class); class_unregister(&konepure_class);
return retval; return retval;
} }
static void __exit konepure_exit(void) static void __exit konepure_exit(void)
{ {
hid_unregister_driver(&konepure_driver); hid_unregister_driver(&konepure_driver);
class_destroy(konepure_class); class_unregister(&konepure_class);
} }
module_init(konepure_init); module_init(konepure_init);
......
...@@ -24,8 +24,6 @@ ...@@ -24,8 +24,6 @@
static uint profile_numbers[5] = {0, 1, 2, 3, 4}; static uint profile_numbers[5] = {0, 1, 2, 3, 4};
static struct class *kovaplus_class;
static uint kovaplus_convert_event_cpi(uint value) static uint kovaplus_convert_event_cpi(uint value)
{ {
return (value == 7 ? 4 : (value == 4 ? 3 : value)); return (value == 7 ? 4 : (value == 4 ? 3 : value));
...@@ -409,6 +407,11 @@ static const struct attribute_group *kovaplus_groups[] = { ...@@ -409,6 +407,11 @@ static const struct attribute_group *kovaplus_groups[] = {
NULL, 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, static int kovaplus_init_kovaplus_device_struct(struct usb_device *usb_dev,
struct kovaplus_device *kovaplus) struct kovaplus_device *kovaplus)
{ {
...@@ -463,8 +466,8 @@ static int kovaplus_init_specials(struct hid_device *hdev) ...@@ -463,8 +466,8 @@ static int kovaplus_init_specials(struct hid_device *hdev)
goto exit_free; goto exit_free;
} }
retval = roccat_connect(kovaplus_class, hdev, retval = roccat_connect(&kovaplus_class, hdev,
sizeof(struct kovaplus_roccat_report)); sizeof(struct kovaplus_roccat_report));
if (retval < 0) { if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n"); hid_err(hdev, "couldn't init char dev\n");
} else { } else {
...@@ -638,21 +641,20 @@ static int __init kovaplus_init(void) ...@@ -638,21 +641,20 @@ static int __init kovaplus_init(void)
{ {
int retval; int retval;
kovaplus_class = class_create("kovaplus"); retval = class_register(&kovaplus_class);
if (IS_ERR(kovaplus_class)) if (retval)
return PTR_ERR(kovaplus_class); return retval;
kovaplus_class->dev_groups = kovaplus_groups;
retval = hid_register_driver(&kovaplus_driver); retval = hid_register_driver(&kovaplus_driver);
if (retval) if (retval)
class_destroy(kovaplus_class); class_unregister(&kovaplus_class);
return retval; return retval;
} }
static void __exit kovaplus_exit(void) static void __exit kovaplus_exit(void)
{ {
hid_unregister_driver(&kovaplus_driver); hid_unregister_driver(&kovaplus_driver);
class_destroy(kovaplus_class); class_unregister(&kovaplus_class);
} }
module_init(kovaplus_init); module_init(kovaplus_init);
......
...@@ -26,9 +26,6 @@ ...@@ -26,9 +26,6 @@
static uint profile_numbers[5] = {0, 1, 2, 3, 4}; 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, static void profile_activated(struct pyra_device *pyra,
unsigned int new_profile) unsigned int new_profile)
{ {
...@@ -366,6 +363,12 @@ static const struct attribute_group *pyra_groups[] = { ...@@ -366,6 +363,12 @@ static const struct attribute_group *pyra_groups[] = {
NULL, 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, static int pyra_init_pyra_device_struct(struct usb_device *usb_dev,
struct pyra_device *pyra) struct pyra_device *pyra)
{ {
...@@ -413,7 +416,7 @@ static int pyra_init_specials(struct hid_device *hdev) ...@@ -413,7 +416,7 @@ static int pyra_init_specials(struct hid_device *hdev)
goto exit_free; goto exit_free;
} }
retval = roccat_connect(pyra_class, hdev, retval = roccat_connect(&pyra_class, hdev,
sizeof(struct pyra_roccat_report)); sizeof(struct pyra_roccat_report));
if (retval < 0) { if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n"); hid_err(hdev, "couldn't init char dev\n");
...@@ -585,21 +588,20 @@ static int __init pyra_init(void) ...@@ -585,21 +588,20 @@ static int __init pyra_init(void)
int retval; int retval;
/* class name has to be same as driver name */ /* class name has to be same as driver name */
pyra_class = class_create("pyra"); retval = class_register(&pyra_class);
if (IS_ERR(pyra_class)) if (retval)
return PTR_ERR(pyra_class); return retval;
pyra_class->dev_groups = pyra_groups;
retval = hid_register_driver(&pyra_driver); retval = hid_register_driver(&pyra_driver);
if (retval) if (retval)
class_destroy(pyra_class); class_unregister(&pyra_class);
return retval; return retval;
} }
static void __exit pyra_exit(void) static void __exit pyra_exit(void)
{ {
hid_unregister_driver(&pyra_driver); hid_unregister_driver(&pyra_driver);
class_destroy(pyra_class); class_unregister(&pyra_class);
} }
module_init(pyra_init); module_init(pyra_init);
......
...@@ -28,8 +28,6 @@ struct ryos_report_special { ...@@ -28,8 +28,6 @@ struct ryos_report_special {
uint8_t data[4]; uint8_t data[4];
} __packed; } __packed;
static struct class *ryos_class;
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x04, 0x03); ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x04, 0x03);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile, 0x05, 0x03); ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile, 0x05, 0x03);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(keys_primary, 0x06, 0x7d); ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(keys_primary, 0x06, 0x7d);
...@@ -80,6 +78,11 @@ static const struct attribute_group *ryos_groups[] = { ...@@ -80,6 +78,11 @@ static const struct attribute_group *ryos_groups[] = {
NULL, NULL,
}; };
static const struct class ryos_class = {
.name = "ryos",
.dev_groups = ryos_groups,
};
static int ryos_init_specials(struct hid_device *hdev) static int ryos_init_specials(struct hid_device *hdev)
{ {
struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
...@@ -106,7 +109,7 @@ static int ryos_init_specials(struct hid_device *hdev) ...@@ -106,7 +109,7 @@ static int ryos_init_specials(struct hid_device *hdev)
goto exit_free; goto exit_free;
} }
retval = roccat_connect(ryos_class, hdev, retval = roccat_connect(&ryos_class, hdev,
sizeof(struct ryos_report_special)); sizeof(struct ryos_report_special));
if (retval < 0) { if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n"); hid_err(hdev, "couldn't init char dev\n");
...@@ -216,21 +219,20 @@ static int __init ryos_init(void) ...@@ -216,21 +219,20 @@ static int __init ryos_init(void)
{ {
int retval; int retval;
ryos_class = class_create("ryos"); retval = class_register(&ryos_class);
if (IS_ERR(ryos_class)) if (retval)
return PTR_ERR(ryos_class); return retval;
ryos_class->dev_groups = ryos_groups;
retval = hid_register_driver(&ryos_driver); retval = hid_register_driver(&ryos_driver);
if (retval) if (retval)
class_destroy(ryos_class); class_unregister(&ryos_class);
return retval; return retval;
} }
static void __exit ryos_exit(void) static void __exit ryos_exit(void)
{ {
hid_unregister_driver(&ryos_driver); hid_unregister_driver(&ryos_driver);
class_destroy(ryos_class); class_unregister(&ryos_class);
} }
module_init(ryos_init); module_init(ryos_init);
......
...@@ -22,8 +22,6 @@ ...@@ -22,8 +22,6 @@
#include "hid-roccat-common.h" #include "hid-roccat-common.h"
#include "hid-roccat-savu.h" #include "hid-roccat-savu.h"
static struct class *savu_class;
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x4, 0x03); ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x4, 0x03);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile, 0x5, 0x03); ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile, 0x5, 0x03);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(general, 0x6, 0x10); ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(general, 0x6, 0x10);
...@@ -52,6 +50,11 @@ static const struct attribute_group *savu_groups[] = { ...@@ -52,6 +50,11 @@ static const struct attribute_group *savu_groups[] = {
NULL, NULL,
}; };
static const struct class savu_class = {
.name = "savu",
.dev_groups = savu_groups,
};
static int savu_init_specials(struct hid_device *hdev) static int savu_init_specials(struct hid_device *hdev)
{ {
struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
...@@ -78,7 +81,7 @@ static int savu_init_specials(struct hid_device *hdev) ...@@ -78,7 +81,7 @@ static int savu_init_specials(struct hid_device *hdev)
goto exit_free; goto exit_free;
} }
retval = roccat_connect(savu_class, hdev, retval = roccat_connect(&savu_class, hdev,
sizeof(struct savu_roccat_report)); sizeof(struct savu_roccat_report));
if (retval < 0) { if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n"); hid_err(hdev, "couldn't init char dev\n");
...@@ -204,21 +207,20 @@ static int __init savu_init(void) ...@@ -204,21 +207,20 @@ static int __init savu_init(void)
{ {
int retval; int retval;
savu_class = class_create("savu"); retval = class_register(&savu_class);
if (IS_ERR(savu_class)) if (retval)
return PTR_ERR(savu_class); return retval;
savu_class->dev_groups = savu_groups;
retval = hid_register_driver(&savu_driver); retval = hid_register_driver(&savu_driver);
if (retval) if (retval)
class_destroy(savu_class); class_unregister(&savu_class);
return retval; return retval;
} }
static void __exit savu_exit(void) static void __exit savu_exit(void)
{ {
hid_unregister_driver(&savu_driver); hid_unregister_driver(&savu_driver);
class_destroy(savu_class); class_unregister(&savu_class);
} }
module_init(savu_init); module_init(savu_init);
......
...@@ -295,7 +295,7 @@ EXPORT_SYMBOL_GPL(roccat_report_event); ...@@ -295,7 +295,7 @@ EXPORT_SYMBOL_GPL(roccat_report_event);
* Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on * Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on
* success, a negative error code on failure. * 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; unsigned int minor;
struct roccat_device *device; struct roccat_device *device;
......
...@@ -32,7 +32,9 @@ ...@@ -32,7 +32,9 @@
static int hidraw_major; static int hidraw_major;
static struct cdev hidraw_cdev; 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 struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
static DECLARE_RWSEM(minors_rwsem); static DECLARE_RWSEM(minors_rwsem);
...@@ -329,7 +331,7 @@ static void drop_ref(struct hidraw *hidraw, int exists_bit) ...@@ -329,7 +331,7 @@ static void drop_ref(struct hidraw *hidraw, int exists_bit)
hid_hw_close(hidraw->hid); hid_hw_close(hidraw->hid);
wake_up_interruptible(&hidraw->wait); wake_up_interruptible(&hidraw->wait);
} }
device_destroy(hidraw_class, device_destroy(&hidraw_class,
MKDEV(hidraw_major, hidraw->minor)); MKDEV(hidraw_major, hidraw->minor));
} else { } else {
--hidraw->open; --hidraw->open;
...@@ -569,7 +571,7 @@ int hidraw_connect(struct hid_device *hid) ...@@ -569,7 +571,7 @@ int hidraw_connect(struct hid_device *hid)
goto out; 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); NULL, "%s%d", "hidraw", minor);
if (IS_ERR(dev->dev)) { if (IS_ERR(dev->dev)) {
...@@ -623,11 +625,9 @@ int __init hidraw_init(void) ...@@ -623,11 +625,9 @@ int __init hidraw_init(void)
hidraw_major = MAJOR(dev_id); hidraw_major = MAJOR(dev_id);
hidraw_class = class_create("hidraw"); result = class_register(&hidraw_class);
if (IS_ERR(hidraw_class)) { if (result)
result = PTR_ERR(hidraw_class);
goto error_cdev; goto error_cdev;
}
cdev_init(&hidraw_cdev, &hidraw_ops); cdev_init(&hidraw_cdev, &hidraw_ops);
result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES); result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
...@@ -639,7 +639,7 @@ int __init hidraw_init(void) ...@@ -639,7 +639,7 @@ int __init hidraw_init(void)
return result; return result;
error_class: error_class:
class_destroy(hidraw_class); class_unregister(&hidraw_class);
error_cdev: error_cdev:
unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES); unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
goto out; goto out;
...@@ -650,7 +650,7 @@ void hidraw_exit(void) ...@@ -650,7 +650,7 @@ void hidraw_exit(void)
dev_t dev_id = MKDEV(hidraw_major, 0); dev_t dev_id = MKDEV(hidraw_major, 0);
cdev_del(&hidraw_cdev); cdev_del(&hidraw_cdev);
class_destroy(hidraw_class); class_unregister(&hidraw_class);
unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES); unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
} }
...@@ -383,9 +383,11 @@ static int kernfs_link_sibling(struct kernfs_node *kn) ...@@ -383,9 +383,11 @@ static int kernfs_link_sibling(struct kernfs_node *kn)
rb_insert_color(&kn->rb, &kn->parent->dir.children); rb_insert_color(&kn->rb, &kn->parent->dir.children);
/* successfully added, account subdir number */ /* successfully added, account subdir number */
down_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
if (kernfs_type(kn) == KERNFS_DIR) if (kernfs_type(kn) == KERNFS_DIR)
kn->parent->dir.subdirs++; kn->parent->dir.subdirs++;
kernfs_inc_rev(kn->parent); kernfs_inc_rev(kn->parent);
up_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
return 0; return 0;
} }
...@@ -408,9 +410,11 @@ static bool kernfs_unlink_sibling(struct kernfs_node *kn) ...@@ -408,9 +410,11 @@ static bool kernfs_unlink_sibling(struct kernfs_node *kn)
if (RB_EMPTY_NODE(&kn->rb)) if (RB_EMPTY_NODE(&kn->rb))
return false; return false;
down_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
if (kernfs_type(kn) == KERNFS_DIR) if (kernfs_type(kn) == KERNFS_DIR)
kn->parent->dir.subdirs--; kn->parent->dir.subdirs--;
kernfs_inc_rev(kn->parent); kernfs_inc_rev(kn->parent);
up_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
rb_erase(&kn->rb, &kn->parent->dir.children); rb_erase(&kn->rb, &kn->parent->dir.children);
RB_CLEAR_NODE(&kn->rb); RB_CLEAR_NODE(&kn->rb);
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/exportfs.h> #include <linux/exportfs.h>
#include <linux/uuid.h>
#include <linux/statfs.h>
#include "kernfs-internal.h" #include "kernfs-internal.h"
...@@ -45,8 +47,15 @@ static int kernfs_sop_show_path(struct seq_file *sf, struct dentry *dentry) ...@@ -45,8 +47,15 @@ static int kernfs_sop_show_path(struct seq_file *sf, struct dentry *dentry)
return 0; 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 = { const struct super_operations kernfs_sops = {
.statfs = simple_statfs, .statfs = kernfs_statfs,
.drop_inode = generic_delete_inode, .drop_inode = generic_delete_inode,
.evict_inode = kernfs_evict_inode, .evict_inode = kernfs_evict_inode,
...@@ -351,6 +360,8 @@ int kernfs_get_tree(struct fs_context *fc) ...@@ -351,6 +360,8 @@ int kernfs_get_tree(struct fs_context *fc)
} }
sb->s_flags |= SB_ACTIVE; sb->s_flags |= SB_ACTIVE;
uuid_gen(&sb->s_uuid);
down_write(&root->kernfs_supers_rwsem); down_write(&root->kernfs_supers_rwsem);
list_add(&info->node, &info->root->supers); list_add(&info->node, &info->root->supers);
up_write(&root->kernfs_supers_rwsem); up_write(&root->kernfs_supers_rwsem);
......
...@@ -274,4 +274,6 @@ do { \ ...@@ -274,4 +274,6 @@ do { \
WARN_ONCE(condition, "%s %s: " format, \ WARN_ONCE(condition, "%s %s: " format, \
dev_driver_string(dev), dev_name(dev), ## arg) 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_ */ #endif /* _DEVICE_PRINTK_H_ */
...@@ -1249,8 +1249,6 @@ void device_link_remove(void *consumer, struct device *supplier); ...@@ -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_pause(void);
void device_links_supplier_sync_state_resume(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. */ /* Create alias, so I can be autoloaded. */
#define MODULE_ALIAS_CHARDEV(major,minor) \ #define MODULE_ALIAS_CHARDEV(major,minor) \
MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor)) MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor))
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#ifdef __KERNEL__ #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); int report_size);
void roccat_disconnect(int minor); void roccat_disconnect(int minor);
int roccat_report_event(int minor, u8 const *data); int roccat_report_event(int minor, u8 const *data);
......
...@@ -550,6 +550,10 @@ static inline int kernfs_setattr(struct kernfs_node *kn, ...@@ -550,6 +550,10 @@ static inline int kernfs_setattr(struct kernfs_node *kn,
const struct iattr *iattr) const struct iattr *iattr)
{ return -ENOSYS; } { 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 void kernfs_notify(struct kernfs_node *kn) { }
static inline int kernfs_xattr_get(struct kernfs_node *kn, const char *name, static inline int kernfs_xattr_get(struct kernfs_node *kn, const char *name,
......
...@@ -69,14 +69,16 @@ struct kobject { ...@@ -69,14 +69,16 @@ struct kobject {
const struct kobj_type *ktype; const struct kobj_type *ktype;
struct kernfs_node *sd; /* sysfs directory entry */ struct kernfs_node *sd; /* sysfs directory entry */
struct kref kref; struct kref kref;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
struct delayed_work release;
#endif
unsigned int state_initialized:1; unsigned int state_initialized:1;
unsigned int state_in_sysfs:1; unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1; unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1; unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress: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, ...); __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) ...@@ -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); 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) static int create_dir(struct kobject *kobj)
{ {
const struct kobj_type *ktype = get_ktype(kobj); const struct kobj_type *ktype = get_ktype(kobj);
...@@ -66,12 +74,10 @@ static int create_dir(struct kobject *kobj) ...@@ -66,12 +74,10 @@ static int create_dir(struct kobject *kobj)
if (error) if (error)
return error; return error;
if (ktype) { error = sysfs_create_groups(kobj, ktype->default_groups);
error = sysfs_create_groups(kobj, ktype->default_groups); if (error) {
if (error) { sysfs_remove_dir(kobj);
sysfs_remove_dir(kobj); return error;
return error;
}
} }
/* /*
...@@ -86,8 +92,7 @@ static int create_dir(struct kobject *kobj) ...@@ -86,8 +92,7 @@ static int create_dir(struct kobject *kobj)
*/ */
ops = kobj_child_ns_ops(kobj); ops = kobj_child_ns_ops(kobj);
if (ops) { if (ops) {
BUG_ON(ops->type <= KOBJ_NS_TYPE_NONE); BUG_ON(!kobj_ns_type_is_valid(ops->type));
BUG_ON(ops->type >= KOBJ_NS_TYPES);
BUG_ON(!kobj_ns_type_registered(ops->type)); BUG_ON(!kobj_ns_type_registered(ops->type));
sysfs_enable_ns(kobj->sd); sysfs_enable_ns(kobj->sd);
...@@ -584,8 +589,7 @@ static void __kobject_del(struct kobject *kobj) ...@@ -584,8 +589,7 @@ static void __kobject_del(struct kobject *kobj)
sd = kobj->sd; sd = kobj->sd;
ktype = get_ktype(kobj); 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" */ /* send "remove" if the caller did not do it but sent "add" */
if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) { if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) {
...@@ -662,10 +666,6 @@ static void kobject_cleanup(struct kobject *kobj) ...@@ -662,10 +666,6 @@ static void kobject_cleanup(struct kobject *kobj)
pr_debug("'%s' (%p): %s, parent %p\n", pr_debug("'%s' (%p): %s, parent %p\n",
kobject_name(kobj), kobj, __func__, kobj->parent); 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 */ /* remove from sysfs if the caller did not do it */
if (kobj->state_in_sysfs) { if (kobj->state_in_sysfs) {
pr_debug("'%s' (%p): auto cleanup kobject_del\n", pr_debug("'%s' (%p): auto cleanup kobject_del\n",
...@@ -676,10 +676,13 @@ static void kobject_cleanup(struct kobject *kobj) ...@@ -676,10 +676,13 @@ static void kobject_cleanup(struct kobject *kobj)
parent = NULL; parent = NULL;
} }
if (t && t->release) { if (t->release) {
pr_debug("'%s' (%p): calling ktype release\n", pr_debug("'%s' (%p): calling ktype release\n",
kobject_name(kobj), kobj); kobject_name(kobj), kobj);
t->release(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 */ /* free name if we allocated it */
...@@ -854,6 +857,11 @@ int kset_register(struct kset *k) ...@@ -854,6 +857,11 @@ int kset_register(struct kset *k)
if (!k) if (!k)
return -EINVAL; return -EINVAL;
if (!k->kobj.ktype) {
pr_err("must have a ktype to be initialized properly!\n");
return -EINVAL;
}
kset_init(k); kset_init(k);
err = kobject_add_internal(&k->kobj); err = kobject_add_internal(&k->kobj);
if (err) { if (err) {
...@@ -1017,11 +1025,7 @@ int kobj_ns_type_register(const struct kobj_ns_type_operations *ops) ...@@ -1017,11 +1025,7 @@ int kobj_ns_type_register(const struct kobj_ns_type_operations *ops)
spin_lock(&kobj_ns_type_lock); spin_lock(&kobj_ns_type_lock);
error = -EINVAL; error = -EINVAL;
if (type >= KOBJ_NS_TYPES) if (!kobj_ns_type_is_valid(type))
goto out;
error = -EINVAL;
if (type <= KOBJ_NS_TYPE_NONE)
goto out; goto out;
error = -EBUSY; error = -EBUSY;
...@@ -1041,7 +1045,7 @@ int kobj_ns_type_registered(enum kobj_ns_type type) ...@@ -1041,7 +1045,7 @@ int kobj_ns_type_registered(enum kobj_ns_type type)
int registered = 0; int registered = 0;
spin_lock(&kobj_ns_type_lock); 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; registered = kobj_ns_ops_tbl[type] != NULL;
spin_unlock(&kobj_ns_type_lock); spin_unlock(&kobj_ns_type_lock);
...@@ -1052,7 +1056,7 @@ const struct kobj_ns_type_operations *kobj_child_ns_ops(const struct kobject *pa ...@@ -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; 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); ops = parent->ktype->child_ns_type(parent);
return ops; return ops;
...@@ -1068,8 +1072,7 @@ bool kobj_ns_current_may_mount(enum kobj_ns_type type) ...@@ -1068,8 +1072,7 @@ bool kobj_ns_current_may_mount(enum kobj_ns_type type)
bool may_mount = true; bool may_mount = true;
spin_lock(&kobj_ns_type_lock); 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])
may_mount = kobj_ns_ops_tbl[type]->current_may_mount(); may_mount = kobj_ns_ops_tbl[type]->current_may_mount();
spin_unlock(&kobj_ns_type_lock); spin_unlock(&kobj_ns_type_lock);
...@@ -1081,8 +1084,7 @@ void *kobj_ns_grab_current(enum kobj_ns_type type) ...@@ -1081,8 +1084,7 @@ void *kobj_ns_grab_current(enum kobj_ns_type type)
void *ns = NULL; void *ns = NULL;
spin_lock(&kobj_ns_type_lock); 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])
ns = kobj_ns_ops_tbl[type]->grab_current_ns(); ns = kobj_ns_ops_tbl[type]->grab_current_ns();
spin_unlock(&kobj_ns_type_lock); spin_unlock(&kobj_ns_type_lock);
...@@ -1095,8 +1097,7 @@ const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk) ...@@ -1095,8 +1097,7 @@ const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk)
const void *ns = NULL; const void *ns = NULL;
spin_lock(&kobj_ns_type_lock); 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])
ns = kobj_ns_ops_tbl[type]->netlink_ns(sk); ns = kobj_ns_ops_tbl[type]->netlink_ns(sk);
spin_unlock(&kobj_ns_type_lock); spin_unlock(&kobj_ns_type_lock);
...@@ -1108,8 +1109,7 @@ const void *kobj_ns_initial(enum kobj_ns_type type) ...@@ -1108,8 +1109,7 @@ const void *kobj_ns_initial(enum kobj_ns_type type)
const void *ns = NULL; const void *ns = NULL;
spin_lock(&kobj_ns_type_lock); 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])
ns = kobj_ns_ops_tbl[type]->initial_ns(); ns = kobj_ns_ops_tbl[type]->initial_ns();
spin_unlock(&kobj_ns_type_lock); spin_unlock(&kobj_ns_type_lock);
...@@ -1119,7 +1119,7 @@ const void *kobj_ns_initial(enum kobj_ns_type type) ...@@ -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) void kobj_ns_drop(enum kobj_ns_type type, void *ns)
{ {
spin_lock(&kobj_ns_type_lock); 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] && kobj_ns_ops_tbl[type]->drop_ns)
kobj_ns_ops_tbl[type]->drop_ns(ns); kobj_ns_ops_tbl[type]->drop_ns(ns);
spin_unlock(&kobj_ns_type_lock); 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