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
...@@ -6,30 +6,29 @@ Everything you ever wanted to know about Linux -stable releases ...@@ -6,30 +6,29 @@ Everything you ever wanted to know about Linux -stable releases
Rules on what kind of patches are accepted, and which ones are not, into the Rules on what kind of patches are accepted, and which ones are not, into the
"-stable" tree: "-stable" tree:
- It or an equivalent fix must already exist in Linus' tree (upstream).
- It must be obviously correct and tested. - It must be obviously correct and tested.
- It cannot be bigger than 100 lines, with context. - It cannot be bigger than 100 lines, with context.
- It must fix only one thing. - It must follow the
- It must fix a real bug that bothers people (not a, "This could be a :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
problem..." type thing). rules.
- It must fix a problem that causes a build error (but not for things - It must either fix a real bug that bothers people or just add a device ID.
marked CONFIG_BROKEN), an oops, a hang, data corruption, a real To elaborate on the former:
security issue, or some "oh, that's not good" issue. In short, something
critical. - It fixes a problem like an oops, a hang, data corruption, a real security
issue, a hardware quirk, a build error (but not for things marked
CONFIG_BROKEN), or some "oh, that's not good" issue.
- Serious issues as reported by a user of a distribution kernel may also - Serious issues as reported by a user of a distribution kernel may also
be considered if they fix a notable performance or interactivity issue. be considered if they fix a notable performance or interactivity issue.
As these fixes are not as obvious and have a higher risk of a subtle As these fixes are not as obvious and have a higher risk of a subtle
regression they should only be submitted by a distribution kernel regression they should only be submitted by a distribution kernel
maintainer and include an addendum linking to a bugzilla entry if it maintainer and include an addendum linking to a bugzilla entry if it
exists and additional information on the user-visible impact. exists and additional information on the user-visible impact.
- New device IDs and quirks are also accepted. - No "This could be a problem..." type of things like a "theoretical race
- No "theoretical race condition" issues, unless an explanation of how the condition", unless an explanation of how the bug can be exploited is also
race can be exploited is also provided. provided.
- It cannot contain any "trivial" fixes in it (spelling changes, - No "trivial" fixes without benefit for users (spelling changes, whitespace
whitespace cleanups, etc). cleanups, etc).
- It must follow the
:ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
rules.
- It or an equivalent fix must already exist in Linus' tree (upstream).
Procedure for submitting patches to the -stable tree Procedure for submitting patches to the -stable tree
...@@ -41,111 +40,142 @@ Procedure for submitting patches to the -stable tree ...@@ -41,111 +40,142 @@ Procedure for submitting patches to the -stable tree
process but should follow the procedures in process but should follow the procedures in
:ref:`Documentation/process/security-bugs.rst <securitybugs>`. :ref:`Documentation/process/security-bugs.rst <securitybugs>`.
For all other submissions, choose one of the following procedures There are three options to submit a change to -stable trees:
-----------------------------------------------------------------
1. Add a 'stable tag' to the description of a patch you then submit for
mainline inclusion.
2. Ask the stable team to pick up a patch already mainlined.
3. Submit a patch to the stable team that is equivalent to a change already
mainlined.
The sections below describe each of the options in more detail.
:ref:`option_1` is **strongly** preferred, it is the easiest and most common.
:ref:`option_2` is mainly meant for changes where backporting was not considered
at the time of submission. :ref:`option_3` is an alternative to the two earlier
options for cases where a mainlined patch needs adjustments to apply in older
series (for example due to API changes).
When using option 2 or 3 you can ask for your change to be included in specific
stable series. When doing so, ensure the fix or an equivalent is applicable,
submitted, or already present in all newer stable trees still supported. This is
meant to prevent regressions that users might later encounter on updating, if
e.g. a fix merged for 5.19-rc1 would be backported to 5.10.y, but not to 5.15.y.
.. _option_1: .. _option_1:
Option 1 Option 1
******** ********
To have the patch automatically included in the stable tree, add the tag To have a patch you submit for mainline inclusion later automatically picked up
for stable trees, add the tag
.. code-block:: none .. code-block:: none
Cc: stable@vger.kernel.org Cc: stable@vger.kernel.org
in the sign-off area. Once the patch is merged it will be applied to in the sign-off area. Once the patch is mainlined it will be applied to the
the stable tree without anything else needing to be done by the author stable tree without anything else needing to be done by the author or
or subsystem maintainer. subsystem maintainer.
.. _option_2: To sent additional instructions to the stable team, use a shell-style inline
comment:
Option 2 * To specify any additional patch prerequisites for cherry picking use the
******** following format in the sign-off area:
After the patch has been merged to Linus' tree, send an email to .. code-block:: none
stable@vger.kernel.org containing the subject of the patch, the commit ID,
why you think it should be applied, and what kernel version you wish it to
be applied to.
.. _option_3: Cc: <stable@vger.kernel.org> # 3.3.x: a1f84a3: sched: Check for idle
Cc: <stable@vger.kernel.org> # 3.3.x: 1b9508f: sched: Rate-limit newidle
Cc: <stable@vger.kernel.org> # 3.3.x: fd21073: sched: Fix affinity logic
Cc: <stable@vger.kernel.org> # 3.3.x
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Option 3 The tag sequence has the meaning of:
********
Send the patch, after verifying that it follows the above rules, to .. code-block:: none
stable@vger.kernel.org. You must note the upstream commit ID in the
changelog of your submission, as well as the kernel version you wish
it to be applied to.
:ref:`option_1` is **strongly** preferred, is the easiest and most common. git cherry-pick a1f84a3
:ref:`option_2` and :ref:`option_3` are more useful if the patch isn't deemed git cherry-pick 1b9508f
worthy at the time it is applied to a public git tree (for instance, because git cherry-pick fd21073
it deserves more regression testing first). :ref:`option_3` is especially git cherry-pick <this commit>
useful if the original upstream patch needs to be backported (for example
the backport needs some special handling due to e.g. API changes).
Note that for :ref:`option_3`, if the patch deviates from the original * For patches that may have kernel version prerequisites specify them using
upstream patch (for example because it had to be backported) this must be very the following format in the sign-off area:
clearly documented and justified in the patch description.
The upstream commit ID must be specified with a separate line above the commit .. code-block:: none
text, like this:
.. code-block:: none Cc: <stable@vger.kernel.org> # 3.3.x
commit <sha1> upstream. The tag has the meaning of:
or alternatively: .. code-block:: none
.. code-block:: none git cherry-pick <this commit>
[ Upstream commit <sha1> ] For each "-stable" tree starting with the specified version.
Additionally, some patches submitted via :ref:`option_1` may have additional Note, such tagging is unnecessary if the stable team can derive the
patch prerequisites which can be cherry-picked. This can be specified in the appropriate versions from Fixes: tags.
following format in the sign-off area:
.. code-block:: none * To delay pick up of patches, use the following format:
Cc: <stable@vger.kernel.org> # 3.3.x: a1f84a3: sched: Check for idle .. code-block:: none
Cc: <stable@vger.kernel.org> # 3.3.x: 1b9508f: sched: Rate-limit newidle
Cc: <stable@vger.kernel.org> # 3.3.x: fd21073: sched: Fix affinity logic
Cc: <stable@vger.kernel.org> # 3.3.x
Signed-off-by: Ingo Molnar <mingo@elte.hu>
The tag sequence has the meaning of: Cc: <stable@vger.kernel.org> # after 4 weeks in mainline
.. code-block:: none * For any other requests, just add a note to the stable tag. This for example
can be used to point out known problems:
git cherry-pick a1f84a3 .. code-block:: none
git cherry-pick 1b9508f
git cherry-pick fd21073 Cc: <stable@vger.kernel.org> # see patch description, needs adjustments for <= 6.3
git cherry-pick <this commit>
.. _option_2:
Option 2
********
If the patch already has been merged to mainline, send an email to
stable@vger.kernel.org containing the subject of the patch, the commit ID,
why you think it should be applied, and what kernel versions you wish it to
be applied to.
.. _option_3:
Option 3
********
Also, some patches may have kernel version prerequisites. This can be Send the patch, after verifying that it follows the above rules, to
specified in the following format in the sign-off area: stable@vger.kernel.org and mention the kernel versions you wish it to be applied
to. When doing so, you must note the upstream commit ID in the changelog of your
submission with a separate line above the commit text, like this:
.. code-block:: none .. code-block:: none
Cc: <stable@vger.kernel.org> # 3.3.x commit <sha1> upstream.
The tag has the meaning of: or alternatively:
.. code-block:: none .. code-block:: none
git cherry-pick <this commit> [ Upstream commit <sha1> ]
If the submitted patch deviates from the original upstream patch (for example
because it had to be adjusted for the older API), this must be very clearly
documented and justified in the patch description.
For each "-stable" tree starting with the specified version.
Following the submission: Following the submission
------------------------
- The sender will receive an ACK when the patch has been accepted into the The sender will receive an ACK when the patch has been accepted into the
queue, or a NAK if the patch is rejected. This response might take a few queue, or a NAK if the patch is rejected. This response might take a few
days, according to the developer's schedules. days, according to the schedules of the stable team members.
- If accepted, the patch will be added to the -stable queue, for review by
other developers and by the relevant subsystem maintainer. If accepted, the patch will be added to the -stable queue, for review by other
developers and by the relevant subsystem maintainer.
Review cycle Review cycle
...@@ -174,6 +204,7 @@ Review cycle ...@@ -174,6 +204,7 @@ Review cycle
security kernel team, and not go through the normal review cycle. security kernel team, and not go through the normal review cycle.
Contact the kernel security team for more details on this procedure. Contact the kernel security team for more details on this procedure.
Trees Trees
----- -----
......
...@@ -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,7 +715,7 @@ static int kone_init_specials(struct hid_device *hdev) ...@@ -712,7 +715,7 @@ 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");
...@@ -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,7 +397,7 @@ static int koneplus_init_specials(struct hid_device *hdev) ...@@ -394,7 +397,7 @@ 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");
...@@ -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,7 +101,7 @@ static int konepure_init_specials(struct hid_device *hdev) ...@@ -98,7 +101,7 @@ 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");
...@@ -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,7 +466,7 @@ static int kovaplus_init_specials(struct hid_device *hdev) ...@@ -463,7 +466,7 @@ 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");
...@@ -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,13 +74,11 @@ static int create_dir(struct kobject *kobj) ...@@ -66,13 +74,11 @@ 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;
} }
}
/* /*
* @kobj->sd may be deleted by an ancestor going away. Hold an * @kobj->sd may be deleted by an ancestor going away. Hold an
...@@ -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,7 +589,6 @@ static void __kobject_del(struct kobject *kobj) ...@@ -584,7 +589,6 @@ 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" */
...@@ -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