mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-06-17 20:25:19 +00:00
Driver core changes for 6.1-rc1
Here is the big set of driver core and debug printk changes for 6.1-rc1. Included in here is: - dynamic debug updates for the core and the drm subsystem. The drm changes have all been acked by the relevant maintainers. - kernfs fixes for syzbot reported problems - kernfs refactors and updates for cgroup requirements - magic number cleanups and removals from the kernel tree (they were not being used and they really did not actually do anything.) - other tiny cleanups All of these have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCY0BYUA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ylozwCdFRlcghaf7XBUyNgRZRwMC+oQI8EAn1G/nEDE 6aFd2er41uK0IGQnSmYO =OK0k -----END PGP SIGNATURE----- Merge tag 'driver-core-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core Pull driver core updates from Greg KH: "Here is the big set of driver core and debug printk changes for 6.1-rc1. Included in here is: - dynamic debug updates for the core and the drm subsystem. The drm changes have all been acked by the relevant maintainers - kernfs fixes for syzbot reported problems - kernfs refactors and updates for cgroup requirements - magic number cleanups and removals from the kernel tree (they were not being used and they really did not actually do anything) - other tiny cleanups All of these have been in linux-next for a while with no reported issues" * tag 'driver-core-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (74 commits) docs: filesystems: sysfs: Make text and code for ->show() consistent Documentation: NBD_REQUEST_MAGIC isn't a magic number a.out: restore CMAGIC device property: Add const qualifier to device_get_match_data() parameter drm_print: add _ddebug descriptor to drm_*dbg prototypes drm_print: prefer bare printk KERN_DEBUG on generic fn drm_print: optimize drm_debug_enabled for jump-label drm-print: add drm_dbg_driver to improve namespace symmetry drm-print.h: include dyndbg header drm_print: wrap drm_*_dbg in dyndbg descriptor factory macro drm_print: interpose drm_*dbg with forwarding macros drm: POC drm on dyndbg - use in core, 2 helpers, 3 drivers. drm_print: condense enum drm_debug_category debugfs: use DEFINE_SHOW_ATTRIBUTE to define debugfs_regset32_fops driver core: use IS_ERR_OR_NULL() helper in device_create_groups_vargs() Documentation: ENI155_MAGIC isn't a magic number Documentation: NBD_REPLY_MAGIC isn't a magic number nbd: remove define-only NBD_MAGIC, previously magic number Documentation: FW_HEADER_MAGIC isn't a magic number Documentation: EEPROM_MAGIC_VALUE isn't a magic number ...
This commit is contained in:
commit
e8bc52cb8d
46 changed files with 1320 additions and 696 deletions
|
@ -5,143 +5,115 @@ Dynamic debug
|
||||||
Introduction
|
Introduction
|
||||||
============
|
============
|
||||||
|
|
||||||
This document describes how to use the dynamic debug (dyndbg) feature.
|
Dynamic debug allows you to dynamically enable/disable kernel
|
||||||
|
debug-print code to obtain additional kernel information.
|
||||||
|
|
||||||
Dynamic debug is designed to allow you to dynamically enable/disable
|
If ``/proc/dynamic_debug/control`` exists, your kernel has dynamic
|
||||||
kernel code to obtain additional kernel information. Currently, if
|
debug. You'll need root access (sudo su) to use this.
|
||||||
``CONFIG_DYNAMIC_DEBUG`` is set, then all ``pr_debug()``/``dev_dbg()`` and
|
|
||||||
``print_hex_dump_debug()``/``print_hex_dump_bytes()`` calls can be dynamically
|
|
||||||
enabled per-callsite.
|
|
||||||
|
|
||||||
If you do not want to enable dynamic debug globally (i.e. in some embedded
|
Dynamic debug provides:
|
||||||
system), you may set ``CONFIG_DYNAMIC_DEBUG_CORE`` as basic support of dynamic
|
|
||||||
debug and add ``ccflags := -DDYNAMIC_DEBUG_MODULE`` into the Makefile of any
|
|
||||||
modules which you'd like to dynamically debug later.
|
|
||||||
|
|
||||||
If ``CONFIG_DYNAMIC_DEBUG`` is not set, ``print_hex_dump_debug()`` is just
|
* a Catalog of all *prdbgs* in your kernel.
|
||||||
shortcut for ``print_hex_dump(KERN_DEBUG)``.
|
``cat /proc/dynamic_debug/control`` to see them.
|
||||||
|
|
||||||
For ``print_hex_dump_debug()``/``print_hex_dump_bytes()``, format string is
|
* a Simple query/command language to alter *prdbgs* by selecting on
|
||||||
its ``prefix_str`` argument, if it is constant string; or ``hexdump``
|
any combination of 0 or 1 of:
|
||||||
in case ``prefix_str`` is built dynamically.
|
|
||||||
|
|
||||||
Dynamic debug has even more useful features:
|
|
||||||
|
|
||||||
* Simple query language allows turning on and off debugging
|
|
||||||
statements by matching any combination of 0 or 1 of:
|
|
||||||
|
|
||||||
- source filename
|
- source filename
|
||||||
- function name
|
- function name
|
||||||
- line number (including ranges of line numbers)
|
- line number (including ranges of line numbers)
|
||||||
- module name
|
- module name
|
||||||
- format string
|
- format string
|
||||||
|
- class name (as known/declared by each module)
|
||||||
* Provides a debugfs control file: ``<debugfs>/dynamic_debug/control``
|
|
||||||
which can be read to display the complete list of known debug
|
|
||||||
statements, to help guide you
|
|
||||||
|
|
||||||
Controlling dynamic debug Behaviour
|
|
||||||
===================================
|
|
||||||
|
|
||||||
The behaviour of ``pr_debug()``/``dev_dbg()`` are controlled via writing to a
|
|
||||||
control file in the 'debugfs' filesystem. Thus, you must first mount
|
|
||||||
the debugfs filesystem, in order to make use of this feature.
|
|
||||||
Subsequently, we refer to the control file as:
|
|
||||||
``<debugfs>/dynamic_debug/control``. For example, if you want to enable
|
|
||||||
printing from source file ``svcsock.c``, line 1603 you simply do::
|
|
||||||
|
|
||||||
nullarbor:~ # echo 'file svcsock.c line 1603 +p' >
|
|
||||||
<debugfs>/dynamic_debug/control
|
|
||||||
|
|
||||||
If you make a mistake with the syntax, the write will fail thus::
|
|
||||||
|
|
||||||
nullarbor:~ # echo 'file svcsock.c wtf 1 +p' >
|
|
||||||
<debugfs>/dynamic_debug/control
|
|
||||||
-bash: echo: write error: Invalid argument
|
|
||||||
|
|
||||||
Note, for systems without 'debugfs' enabled, the control file can be
|
|
||||||
found in ``/proc/dynamic_debug/control``.
|
|
||||||
|
|
||||||
Viewing Dynamic Debug Behaviour
|
Viewing Dynamic Debug Behaviour
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
You can view the currently configured behaviour of all the debug
|
You can view the currently configured behaviour in the *prdbg* catalog::
|
||||||
statements via::
|
|
||||||
|
|
||||||
nullarbor:~ # cat <debugfs>/dynamic_debug/control
|
:#> head -n7 /proc/dynamic_debug/control
|
||||||
# filename:lineno [module]function flags format
|
# filename:lineno [module]function flags format
|
||||||
net/sunrpc/svc_rdma.c:323 [svcxprt_rdma]svc_rdma_cleanup =_ "SVCRDMA Module Removed, deregister RPC RDMA transport\012"
|
init/main.c:1179 [main]initcall_blacklist =_ "blacklisting initcall %s\012
|
||||||
net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init =_ "\011max_inline : %d\012"
|
init/main.c:1218 [main]initcall_blacklisted =_ "initcall %s blacklisted\012"
|
||||||
net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init =_ "\011sq_depth : %d\012"
|
init/main.c:1424 [main]run_init_process =_ " with arguments:\012"
|
||||||
net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init =_ "\011max_requests : %d\012"
|
init/main.c:1426 [main]run_init_process =_ " %s\012"
|
||||||
...
|
init/main.c:1427 [main]run_init_process =_ " with environment:\012"
|
||||||
|
init/main.c:1429 [main]run_init_process =_ " %s\012"
|
||||||
|
|
||||||
|
The 3rd space-delimited column shows the current flags, preceded by
|
||||||
|
a ``=`` for easy use with grep/cut. ``=p`` shows enabled callsites.
|
||||||
|
|
||||||
You can also apply standard Unix text manipulation filters to this
|
Controlling dynamic debug Behaviour
|
||||||
data, e.g.::
|
===================================
|
||||||
|
|
||||||
nullarbor:~ # grep -i rdma <debugfs>/dynamic_debug/control | wc -l
|
The behaviour of *prdbg* sites are controlled by writing
|
||||||
62
|
query/commands to the control file. Example::
|
||||||
|
|
||||||
nullarbor:~ # grep -i tcp <debugfs>/dynamic_debug/control | wc -l
|
# grease the interface
|
||||||
42
|
:#> alias ddcmd='echo $* > /proc/dynamic_debug/control'
|
||||||
|
|
||||||
The third column shows the currently enabled flags for each debug
|
:#> ddcmd '-p; module main func run* +p'
|
||||||
statement callsite (see below for definitions of the flags). The
|
:#> grep =p /proc/dynamic_debug/control
|
||||||
default value, with no flags enabled, is ``=_``. So you can view all
|
init/main.c:1424 [main]run_init_process =p " with arguments:\012"
|
||||||
the debug statement callsites with any non-default flags::
|
init/main.c:1426 [main]run_init_process =p " %s\012"
|
||||||
|
init/main.c:1427 [main]run_init_process =p " with environment:\012"
|
||||||
|
init/main.c:1429 [main]run_init_process =p " %s\012"
|
||||||
|
|
||||||
nullarbor:~ # awk '$3 != "=_"' <debugfs>/dynamic_debug/control
|
Error messages go to console/syslog::
|
||||||
# filename:lineno [module]function flags format
|
|
||||||
net/sunrpc/svcsock.c:1603 [sunrpc]svc_send p "svc_process: st_sendto returned %d\012"
|
:#> ddcmd mode foo +p
|
||||||
|
dyndbg: unknown keyword "mode"
|
||||||
|
dyndbg: query parse failed
|
||||||
|
bash: echo: write error: Invalid argument
|
||||||
|
|
||||||
|
If debugfs is also enabled and mounted, ``dynamic_debug/control`` is
|
||||||
|
also under the mount-dir, typically ``/sys/kernel/debug/``.
|
||||||
|
|
||||||
Command Language Reference
|
Command Language Reference
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
At the lexical level, a command comprises a sequence of words separated
|
At the basic lexical level, a command is a sequence of words separated
|
||||||
by spaces or tabs. So these are all equivalent::
|
by spaces or tabs. So these are all equivalent::
|
||||||
|
|
||||||
nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >
|
:#> ddcmd file svcsock.c line 1603 +p
|
||||||
<debugfs>/dynamic_debug/control
|
:#> ddcmd "file svcsock.c line 1603 +p"
|
||||||
nullarbor:~ # echo -n ' file svcsock.c line 1603 +p ' >
|
:#> ddcmd ' file svcsock.c line 1603 +p '
|
||||||
<debugfs>/dynamic_debug/control
|
|
||||||
nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >
|
|
||||||
<debugfs>/dynamic_debug/control
|
|
||||||
|
|
||||||
Command submissions are bounded by a write() system call.
|
Command submissions are bounded by a write() system call.
|
||||||
Multiple commands can be written together, separated by ``;`` or ``\n``::
|
Multiple commands can be written together, separated by ``;`` or ``\n``::
|
||||||
|
|
||||||
~# echo "func pnpacpi_get_resources +p; func pnp_assign_mem +p" \
|
:#> ddcmd "func pnpacpi_get_resources +p; func pnp_assign_mem +p"
|
||||||
> <debugfs>/dynamic_debug/control
|
:#> ddcmd <<"EOC"
|
||||||
|
func pnpacpi_get_resources +p
|
||||||
|
func pnp_assign_mem +p
|
||||||
|
EOC
|
||||||
|
:#> cat query-batch-file > /proc/dynamic_debug/control
|
||||||
|
|
||||||
If your query set is big, you can batch them too::
|
You can also use wildcards in each query term. The match rule supports
|
||||||
|
``*`` (matches zero or more characters) and ``?`` (matches exactly one
|
||||||
|
character). For example, you can match all usb drivers::
|
||||||
|
|
||||||
~# cat query-batch-file > <debugfs>/dynamic_debug/control
|
:#> ddcmd file "drivers/usb/*" +p # "" to suppress shell expansion
|
||||||
|
|
||||||
Another way is to use wildcards. The match rule supports ``*`` (matches
|
Syntactically, a command is pairs of keyword values, followed by a
|
||||||
zero or more characters) and ``?`` (matches exactly one character). For
|
flags change or setting::
|
||||||
example, you can match all usb drivers::
|
|
||||||
|
|
||||||
~# echo "file drivers/usb/* +p" > <debugfs>/dynamic_debug/control
|
|
||||||
|
|
||||||
At the syntactical level, a command comprises a sequence of match
|
|
||||||
specifications, followed by a flags change specification::
|
|
||||||
|
|
||||||
command ::= match-spec* flags-spec
|
command ::= match-spec* flags-spec
|
||||||
|
|
||||||
The match-spec's are used to choose a subset of the known pr_debug()
|
The match-spec's select *prdbgs* from the catalog, upon which to apply
|
||||||
callsites to which to apply the flags-spec. Think of them as a query
|
the flags-spec, all constraints are ANDed together. An absent keyword
|
||||||
with implicit ANDs between each pair. Note that an empty list of
|
is the same as keyword "*".
|
||||||
match-specs will select all debug statement callsites.
|
|
||||||
|
|
||||||
A match specification comprises a keyword, which controls the
|
|
||||||
attribute of the callsite to be compared, and a value to compare
|
A match specification is a keyword, which selects the attribute of
|
||||||
against. Possible keywords are:::
|
the callsite to be compared, and a value to compare against. Possible
|
||||||
|
keywords are:::
|
||||||
|
|
||||||
match-spec ::= 'func' string |
|
match-spec ::= 'func' string |
|
||||||
'file' string |
|
'file' string |
|
||||||
'module' string |
|
'module' string |
|
||||||
'format' string |
|
'format' string |
|
||||||
|
'class' string |
|
||||||
'line' line-range
|
'line' line-range
|
||||||
|
|
||||||
line-range ::= lineno |
|
line-range ::= lineno |
|
||||||
|
@ -203,6 +175,16 @@ format
|
||||||
format "nfsd: SETATTR" // a neater way to match a format with whitespace
|
format "nfsd: SETATTR" // a neater way to match a format with whitespace
|
||||||
format 'nfsd: SETATTR' // yet another way to match a format with whitespace
|
format 'nfsd: SETATTR' // yet another way to match a format with whitespace
|
||||||
|
|
||||||
|
class
|
||||||
|
The given class_name is validated against each module, which may
|
||||||
|
have declared a list of known class_names. If the class_name is
|
||||||
|
found for a module, callsite & class matching and adjustment
|
||||||
|
proceeds. Examples::
|
||||||
|
|
||||||
|
class DRM_UT_KMS # a DRM.debug category
|
||||||
|
class JUNK # silent non-match
|
||||||
|
// class TLD_* # NOTICE: no wildcard in class names
|
||||||
|
|
||||||
line
|
line
|
||||||
The given line number or range of line numbers is compared
|
The given line number or range of line numbers is compared
|
||||||
against the line number of each ``pr_debug()`` callsite. A single
|
against the line number of each ``pr_debug()`` callsite. A single
|
||||||
|
@ -228,17 +210,16 @@ of the characters::
|
||||||
The flags are::
|
The flags are::
|
||||||
|
|
||||||
p enables the pr_debug() callsite.
|
p enables the pr_debug() callsite.
|
||||||
f Include the function name in the printed message
|
_ enables no flags.
|
||||||
l Include line number in the printed message
|
|
||||||
m Include module name in the printed message
|
|
||||||
t Include thread ID in messages not generated from interrupt context
|
|
||||||
_ No flags are set. (Or'd with others on input)
|
|
||||||
|
|
||||||
For ``print_hex_dump_debug()`` and ``print_hex_dump_bytes()``, only ``p`` flag
|
Decorator flags add to the message-prefix, in order:
|
||||||
have meaning, other flags ignored.
|
t Include thread ID, or <intr>
|
||||||
|
m Include module name
|
||||||
|
f Include the function name
|
||||||
|
l Include line number
|
||||||
|
|
||||||
For display, the flags are preceded by ``=``
|
For ``print_hex_dump_debug()`` and ``print_hex_dump_bytes()``, only
|
||||||
(mnemonic: what the flags are currently equal to).
|
the ``p`` flag has meaning, other flags are ignored.
|
||||||
|
|
||||||
Note the regexp ``^[-+=][flmpt_]+$`` matches a flags specification.
|
Note the regexp ``^[-+=][flmpt_]+$`` matches a flags specification.
|
||||||
To clear all flags at once, use ``=_`` or ``-flmpt``.
|
To clear all flags at once, use ``=_`` or ``-flmpt``.
|
||||||
|
@ -313,7 +294,7 @@ For ``CONFIG_DYNAMIC_DEBUG`` kernels, any settings given at boot-time (or
|
||||||
enabled by ``-DDEBUG`` flag during compilation) can be disabled later via
|
enabled by ``-DDEBUG`` flag during compilation) can be disabled later via
|
||||||
the debugfs interface if the debug messages are no longer needed::
|
the debugfs interface if the debug messages are no longer needed::
|
||||||
|
|
||||||
echo "module module_name -p" > <debugfs>/dynamic_debug/control
|
echo "module module_name -p" > /proc/dynamic_debug/control
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
========
|
========
|
||||||
|
@ -321,37 +302,31 @@ Examples
|
||||||
::
|
::
|
||||||
|
|
||||||
// enable the message at line 1603 of file svcsock.c
|
// enable the message at line 1603 of file svcsock.c
|
||||||
nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >
|
:#> ddcmd 'file svcsock.c line 1603 +p'
|
||||||
<debugfs>/dynamic_debug/control
|
|
||||||
|
|
||||||
// enable all the messages in file svcsock.c
|
// enable all the messages in file svcsock.c
|
||||||
nullarbor:~ # echo -n 'file svcsock.c +p' >
|
:#> ddcmd 'file svcsock.c +p'
|
||||||
<debugfs>/dynamic_debug/control
|
|
||||||
|
|
||||||
// enable all the messages in the NFS server module
|
// enable all the messages in the NFS server module
|
||||||
nullarbor:~ # echo -n 'module nfsd +p' >
|
:#> ddcmd 'module nfsd +p'
|
||||||
<debugfs>/dynamic_debug/control
|
|
||||||
|
|
||||||
// enable all 12 messages in the function svc_process()
|
// enable all 12 messages in the function svc_process()
|
||||||
nullarbor:~ # echo -n 'func svc_process +p' >
|
:#> ddcmd 'func svc_process +p'
|
||||||
<debugfs>/dynamic_debug/control
|
|
||||||
|
|
||||||
// disable all 12 messages in the function svc_process()
|
// disable all 12 messages in the function svc_process()
|
||||||
nullarbor:~ # echo -n 'func svc_process -p' >
|
:#> ddcmd 'func svc_process -p'
|
||||||
<debugfs>/dynamic_debug/control
|
|
||||||
|
|
||||||
// enable messages for NFS calls READ, READLINK, READDIR and READDIR+.
|
// enable messages for NFS calls READ, READLINK, READDIR and READDIR+.
|
||||||
nullarbor:~ # echo -n 'format "nfsd: READ" +p' >
|
:#> ddcmd 'format "nfsd: READ" +p'
|
||||||
<debugfs>/dynamic_debug/control
|
|
||||||
|
|
||||||
// enable messages in files of which the paths include string "usb"
|
// enable messages in files of which the paths include string "usb"
|
||||||
nullarbor:~ # echo -n 'file *usb* +p' > <debugfs>/dynamic_debug/control
|
:#> ddcmd 'file *usb* +p' > /proc/dynamic_debug/control
|
||||||
|
|
||||||
// enable all messages
|
// enable all messages
|
||||||
nullarbor:~ # echo -n '+p' > <debugfs>/dynamic_debug/control
|
:#> ddcmd '+p' > /proc/dynamic_debug/control
|
||||||
|
|
||||||
// add module, function to all enabled messages
|
// add module, function to all enabled messages
|
||||||
nullarbor:~ # echo -n '+mf' > <debugfs>/dynamic_debug/control
|
:#> ddcmd '+mf' > /proc/dynamic_debug/control
|
||||||
|
|
||||||
// boot-args example, with newlines and comments for readability
|
// boot-args example, with newlines and comments for readability
|
||||||
Kernel command line: ...
|
Kernel command line: ...
|
||||||
|
@ -364,3 +339,38 @@ Examples
|
||||||
dyndbg="file init/* +p #cmt ; func parse_one +p"
|
dyndbg="file init/* +p #cmt ; func parse_one +p"
|
||||||
// enable pr_debugs in 2 functions in a module loaded later
|
// enable pr_debugs in 2 functions in a module loaded later
|
||||||
pc87360.dyndbg="func pc87360_init_device +p; func pc87360_find +p"
|
pc87360.dyndbg="func pc87360_init_device +p; func pc87360_find +p"
|
||||||
|
|
||||||
|
Kernel Configuration
|
||||||
|
====================
|
||||||
|
|
||||||
|
Dynamic Debug is enabled via kernel config items::
|
||||||
|
|
||||||
|
CONFIG_DYNAMIC_DEBUG=y # build catalog, enables CORE
|
||||||
|
CONFIG_DYNAMIC_DEBUG_CORE=y # enable mechanics only, skip catalog
|
||||||
|
|
||||||
|
If you do not want to enable dynamic debug globally (i.e. in some embedded
|
||||||
|
system), you may set ``CONFIG_DYNAMIC_DEBUG_CORE`` as basic support of dynamic
|
||||||
|
debug and add ``ccflags := -DDYNAMIC_DEBUG_MODULE`` into the Makefile of any
|
||||||
|
modules which you'd like to dynamically debug later.
|
||||||
|
|
||||||
|
|
||||||
|
Kernel *prdbg* API
|
||||||
|
==================
|
||||||
|
|
||||||
|
The following functions are cataloged and controllable when dynamic
|
||||||
|
debug is enabled::
|
||||||
|
|
||||||
|
pr_debug()
|
||||||
|
dev_dbg()
|
||||||
|
print_hex_dump_debug()
|
||||||
|
print_hex_dump_bytes()
|
||||||
|
|
||||||
|
Otherwise, they are off by default; ``ccflags += -DDEBUG`` or
|
||||||
|
``#define DEBUG`` in a source file will enable them appropriately.
|
||||||
|
|
||||||
|
If ``CONFIG_DYNAMIC_DEBUG`` is not set, ``print_hex_dump_debug()`` is
|
||||||
|
just a shortcut for ``print_hex_dump(KERN_DEBUG)``.
|
||||||
|
|
||||||
|
For ``print_hex_dump_debug()``/``print_hex_dump_bytes()``, format string is
|
||||||
|
its ``prefix_str`` argument, if it is constant string; or ``hexdump``
|
||||||
|
in case ``prefix_str`` is built dynamically.
|
||||||
|
|
|
@ -311,7 +311,6 @@ IOMAP
|
||||||
devm_ioremap()
|
devm_ioremap()
|
||||||
devm_ioremap_uc()
|
devm_ioremap_uc()
|
||||||
devm_ioremap_wc()
|
devm_ioremap_wc()
|
||||||
devm_ioremap_np()
|
|
||||||
devm_ioremap_resource() : checks resource, requests memory region, ioremaps
|
devm_ioremap_resource() : checks resource, requests memory region, ioremaps
|
||||||
devm_ioremap_resource_wc()
|
devm_ioremap_resource_wc()
|
||||||
devm_platform_ioremap_resource() : calls devm_ioremap_resource() for platform device
|
devm_platform_ioremap_resource() : calls devm_ioremap_resource() for platform device
|
||||||
|
|
|
@ -263,7 +263,7 @@ A very simple (and naive) implementation of a device attribute is::
|
||||||
static ssize_t show_name(struct device *dev, struct device_attribute *attr,
|
static ssize_t show_name(struct device *dev, struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
return scnprintf(buf, PAGE_SIZE, "%s\n", dev->name);
|
return sysfs_emit(buf, "%s\n", dev->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t store_name(struct device *dev, struct device_attribute *attr,
|
static ssize_t store_name(struct device *dev, struct device_attribute *attr,
|
||||||
|
|
|
@ -69,82 +69,17 @@ Changelog::
|
||||||
Magic Name Number Structure File
|
Magic Name Number Structure File
|
||||||
===================== ================ ======================== ==========================================
|
===================== ================ ======================== ==========================================
|
||||||
PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h``
|
PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h``
|
||||||
CMAGIC 0x0111 user ``include/linux/a.out.h``
|
|
||||||
MKISS_DRIVER_MAGIC 0x04bf mkiss_channel ``drivers/net/mkiss.h``
|
|
||||||
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
|
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
|
||||||
DB_MAGIC 0x4442 fc_info ``drivers/net/iph5526_novram.c``
|
|
||||||
DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c``
|
|
||||||
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
|
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
|
||||||
FF_MAGIC 0x4646 fc_info ``drivers/net/iph5526_novram.c``
|
|
||||||
PTY_MAGIC 0x5001 ``drivers/char/pty.c``
|
|
||||||
PPP_MAGIC 0x5002 ppp ``include/linux/if_pppvar.h``
|
|
||||||
SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h``
|
|
||||||
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
|
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
|
||||||
STRIP_MAGIC 0x5303 strip ``drivers/net/strip.c``
|
|
||||||
SIXPACK_MAGIC 0x5304 sixpack ``drivers/net/hamradio/6pack.h``
|
|
||||||
AX25_MAGIC 0x5316 ax_disp ``drivers/net/mkiss.h``
|
|
||||||
MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c``
|
MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c``
|
||||||
USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h``
|
|
||||||
FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c``
|
|
||||||
USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c``
|
|
||||||
RFCOMM_TTY_MAGIC 0x6d02 ``net/bluetooth/rfcomm/tty.c``
|
|
||||||
USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port ``drivers/usb/serial/usb-serial.h``
|
|
||||||
CG_MAGIC 0x00090255 ufs_cylinder_group ``include/linux/ufs_fs.h``
|
|
||||||
LSEMAGIC 0x05091998 lse ``drivers/fc4/fc.c``
|
|
||||||
RIEBL_MAGIC 0x09051990 ``drivers/net/atarilance.c``
|
|
||||||
NBD_REQUEST_MAGIC 0x12560953 nbd_request ``include/linux/nbd.h``
|
|
||||||
RED_MAGIC2 0x170fc2a5 (any) ``mm/slab.c``
|
|
||||||
BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
|
BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
|
||||||
ISDN_X25IFACE_MAGIC 0x1e75a2b9 isdn_x25iface_proto_data ``drivers/isdn/isdn_x25iface.h``
|
|
||||||
ECP_MAGIC 0x21504345 cdkecpsig ``include/linux/cdk.h``
|
|
||||||
LSOMAGIC 0x27091997 lso ``drivers/fc4/fc.c``
|
|
||||||
LSMAGIC 0x2a3b4d2a ls ``drivers/fc4/fc.c``
|
|
||||||
WANPIPE_MAGIC 0x414C4453 sdla_{dump,exec} ``include/linux/wanpipe.h``
|
|
||||||
CS_CARD_MAGIC 0x43525553 cs_card ``sound/oss/cs46xx.c``
|
|
||||||
LABELCL_MAGIC 0x4857434c labelcl_info_s ``include/asm/ia64/sn/labelcl.h``
|
|
||||||
ISDN_ASYNC_MAGIC 0x49344C01 modem_info ``include/linux/isdn.h``
|
|
||||||
CTC_ASYNC_MAGIC 0x49344C01 ctc_tty_info ``drivers/s390/net/ctctty.c``
|
|
||||||
ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s ``drivers/isdn/i4l/isdn_net_lib.h``
|
|
||||||
SAVEKMSG_MAGIC2 0x4B4D5347 savekmsg ``arch/*/amiga/config.c``
|
|
||||||
CS_STATE_MAGIC 0x4c4f4749 cs_state ``sound/oss/cs46xx.c``
|
|
||||||
SLAB_C_MAGIC 0x4f17a36d kmem_cache ``mm/slab.c``
|
|
||||||
COW_MAGIC 0x4f4f4f4d cow_header_v1 ``arch/um/drivers/ubd_user.c``
|
|
||||||
I810_CARD_MAGIC 0x5072696E i810_card ``sound/oss/i810_audio.c``
|
|
||||||
TRIDENT_CARD_MAGIC 0x5072696E trident_card ``sound/oss/trident.c``
|
|
||||||
ROUTER_MAGIC 0x524d4157 wan_device [in ``wanrouter.h`` pre 3.9]
|
|
||||||
SAVEKMSG_MAGIC1 0x53415645 savekmsg ``arch/*/amiga/config.c``
|
|
||||||
GDA_MAGIC 0x58464552 gda ``arch/mips/include/asm/sn/gda.h``
|
|
||||||
RED_MAGIC1 0x5a2cf071 (any) ``mm/slab.c``
|
|
||||||
EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev ``drivers/atm/lanai.c``
|
|
||||||
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
|
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
|
||||||
PCXX_MAGIC 0x5c6df104 channel ``drivers/char/pcxx.h``
|
|
||||||
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
|
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
|
||||||
I810_STATE_MAGIC 0x63657373 i810_state ``sound/oss/i810_audio.c``
|
|
||||||
TRIDENT_STATE_MAGIC 0x63657373 trient_state ``sound/oss/trident.c``
|
|
||||||
M3_CARD_MAGIC 0x646e6f50 m3_card ``sound/oss/maestro3.c``
|
|
||||||
FW_HEADER_MAGIC 0x65726F66 fw_header ``drivers/atm/fore200e.h``
|
|
||||||
SLOT_MAGIC 0x67267321 slot ``drivers/hotplug/cpqphp.h``
|
|
||||||
SLOT_MAGIC 0x67267322 slot ``drivers/hotplug/acpiphp.h``
|
|
||||||
LO_MAGIC 0x68797548 nbd_device ``include/linux/nbd.h``
|
|
||||||
M3_STATE_MAGIC 0x734d724d m3_state ``sound/oss/maestro3.c``
|
|
||||||
VMALLOC_MAGIC 0x87654320 snd_alloc_track ``sound/core/memory.c``
|
|
||||||
KMALLOC_MAGIC 0x87654321 snd_alloc_track ``sound/core/memory.c``
|
|
||||||
PWC_MAGIC 0x89DC10AB pwc_device ``drivers/usb/media/pwc.h``
|
|
||||||
NBD_REPLY_MAGIC 0x96744668 nbd_reply ``include/linux/nbd.h``
|
|
||||||
ENI155_MAGIC 0xa54b872d midway_eprom ``drivers/atm/eni.h``
|
|
||||||
CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
|
CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
|
||||||
YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
|
YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
|
||||||
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
|
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
|
||||||
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
|
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
|
||||||
QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
|
QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
|
||||||
HTB_CMAGIC 0xFEFAFEF1 htb_class ``net/sched/sch_htb.c``
|
|
||||||
NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h``
|
NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h``
|
||||||
===================== ================ ======================== ==========================================
|
===================== ================ ======================== ==========================================
|
||||||
|
|
||||||
Note that there are also defined special per-driver magic numbers in sound
|
|
||||||
memory management. See ``include/sound/sndmagic.h`` for complete list of them. Many
|
|
||||||
OSS sound drivers have their magic numbers constructed from the soundcard PCI
|
|
||||||
ID - these are not listed here as well.
|
|
||||||
|
|
||||||
HFS is another larger user of magic numbers - you can find them in
|
|
||||||
``fs/hfs/hfs.h``.
|
|
||||||
|
|
|
@ -75,83 +75,17 @@ Registro dei cambiamenti::
|
||||||
Nome magico Numero Struttura File
|
Nome magico Numero Struttura File
|
||||||
===================== ================ ======================== ==========================================
|
===================== ================ ======================== ==========================================
|
||||||
PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h``
|
PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h``
|
||||||
CMAGIC 0x0111 user ``include/linux/a.out.h``
|
|
||||||
MKISS_DRIVER_MAGIC 0x04bf mkiss_channel ``drivers/net/mkiss.h``
|
|
||||||
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
|
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
|
||||||
DB_MAGIC 0x4442 fc_info ``drivers/net/iph5526_novram.c``
|
|
||||||
DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c``
|
|
||||||
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
|
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
|
||||||
FF_MAGIC 0x4646 fc_info ``drivers/net/iph5526_novram.c``
|
|
||||||
PTY_MAGIC 0x5001 ``drivers/char/pty.c``
|
|
||||||
PPP_MAGIC 0x5002 ppp ``include/linux/if_pppvar.h``
|
|
||||||
SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h``
|
|
||||||
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
|
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
|
||||||
STRIP_MAGIC 0x5303 strip ``drivers/net/strip.c``
|
|
||||||
SIXPACK_MAGIC 0x5304 sixpack ``drivers/net/hamradio/6pack.h``
|
|
||||||
AX25_MAGIC 0x5316 ax_disp ``drivers/net/mkiss.h``
|
|
||||||
MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c``
|
MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c``
|
||||||
USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h``
|
|
||||||
FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c``
|
|
||||||
USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c``
|
|
||||||
RFCOMM_TTY_MAGIC 0x6d02 ``net/bluetooth/rfcomm/tty.c``
|
|
||||||
USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port ``drivers/usb/serial/usb-serial.h``
|
|
||||||
CG_MAGIC 0x00090255 ufs_cylinder_group ``include/linux/ufs_fs.h``
|
|
||||||
LSEMAGIC 0x05091998 lse ``drivers/fc4/fc.c``
|
|
||||||
RIEBL_MAGIC 0x09051990 ``drivers/net/atarilance.c``
|
|
||||||
NBD_REQUEST_MAGIC 0x12560953 nbd_request ``include/linux/nbd.h``
|
|
||||||
RED_MAGIC2 0x170fc2a5 (any) ``mm/slab.c``
|
|
||||||
BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
|
BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
|
||||||
ISDN_X25IFACE_MAGIC 0x1e75a2b9 isdn_x25iface_proto_data ``drivers/isdn/isdn_x25iface.h``
|
|
||||||
ECP_MAGIC 0x21504345 cdkecpsig ``include/linux/cdk.h``
|
|
||||||
LSOMAGIC 0x27091997 lso ``drivers/fc4/fc.c``
|
|
||||||
LSMAGIC 0x2a3b4d2a ls ``drivers/fc4/fc.c``
|
|
||||||
WANPIPE_MAGIC 0x414C4453 sdla_{dump,exec} ``include/linux/wanpipe.h``
|
|
||||||
CS_CARD_MAGIC 0x43525553 cs_card ``sound/oss/cs46xx.c``
|
|
||||||
LABELCL_MAGIC 0x4857434c labelcl_info_s ``include/asm/ia64/sn/labelcl.h``
|
|
||||||
ISDN_ASYNC_MAGIC 0x49344C01 modem_info ``include/linux/isdn.h``
|
|
||||||
CTC_ASYNC_MAGIC 0x49344C01 ctc_tty_info ``drivers/s390/net/ctctty.c``
|
|
||||||
ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s ``drivers/isdn/i4l/isdn_net_lib.h``
|
|
||||||
SAVEKMSG_MAGIC2 0x4B4D5347 savekmsg ``arch/*/amiga/config.c``
|
|
||||||
CS_STATE_MAGIC 0x4c4f4749 cs_state ``sound/oss/cs46xx.c``
|
|
||||||
SLAB_C_MAGIC 0x4f17a36d kmem_cache ``mm/slab.c``
|
|
||||||
COW_MAGIC 0x4f4f4f4d cow_header_v1 ``arch/um/drivers/ubd_user.c``
|
|
||||||
I810_CARD_MAGIC 0x5072696E i810_card ``sound/oss/i810_audio.c``
|
|
||||||
TRIDENT_CARD_MAGIC 0x5072696E trident_card ``sound/oss/trident.c``
|
|
||||||
ROUTER_MAGIC 0x524d4157 wan_device [in ``wanrouter.h`` pre 3.9]
|
|
||||||
SAVEKMSG_MAGIC1 0x53415645 savekmsg ``arch/*/amiga/config.c``
|
|
||||||
GDA_MAGIC 0x58464552 gda ``arch/mips/include/asm/sn/gda.h``
|
|
||||||
RED_MAGIC1 0x5a2cf071 (any) ``mm/slab.c``
|
|
||||||
EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev ``drivers/atm/lanai.c``
|
|
||||||
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
|
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
|
||||||
PCXX_MAGIC 0x5c6df104 channel ``drivers/char/pcxx.h``
|
|
||||||
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
|
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
|
||||||
I810_STATE_MAGIC 0x63657373 i810_state ``sound/oss/i810_audio.c``
|
|
||||||
TRIDENT_STATE_MAGIC 0x63657373 trient_state ``sound/oss/trident.c``
|
|
||||||
M3_CARD_MAGIC 0x646e6f50 m3_card ``sound/oss/maestro3.c``
|
|
||||||
FW_HEADER_MAGIC 0x65726F66 fw_header ``drivers/atm/fore200e.h``
|
|
||||||
SLOT_MAGIC 0x67267321 slot ``drivers/hotplug/cpqphp.h``
|
|
||||||
SLOT_MAGIC 0x67267322 slot ``drivers/hotplug/acpiphp.h``
|
|
||||||
LO_MAGIC 0x68797548 nbd_device ``include/linux/nbd.h``
|
|
||||||
M3_STATE_MAGIC 0x734d724d m3_state ``sound/oss/maestro3.c``
|
|
||||||
VMALLOC_MAGIC 0x87654320 snd_alloc_track ``sound/core/memory.c``
|
|
||||||
KMALLOC_MAGIC 0x87654321 snd_alloc_track ``sound/core/memory.c``
|
|
||||||
PWC_MAGIC 0x89DC10AB pwc_device ``drivers/usb/media/pwc.h``
|
|
||||||
NBD_REPLY_MAGIC 0x96744668 nbd_reply ``include/linux/nbd.h``
|
|
||||||
ENI155_MAGIC 0xa54b872d midway_eprom ``drivers/atm/eni.h``
|
|
||||||
CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
|
CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
|
||||||
YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
|
YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
|
||||||
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
|
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
|
||||||
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
|
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
|
||||||
QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
|
QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
|
||||||
HTB_CMAGIC 0xFEFAFEF1 htb_class ``net/sched/sch_htb.c``
|
|
||||||
NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h``
|
NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h``
|
||||||
===================== ================ ======================== ==========================================
|
===================== ================ ======================== ==========================================
|
||||||
|
|
||||||
Da notare che ci sono anche dei numeri magici specifici per driver nel
|
|
||||||
*sound memory management*. Consultate ``include/sound/sndmagic.h`` per una
|
|
||||||
lista completa. Molti driver audio OSS hanno i loro numeri magici costruiti a
|
|
||||||
partire dall'identificativo PCI della scheda audio - nemmeno questi sono
|
|
||||||
elencati in questo file.
|
|
||||||
|
|
||||||
Il file-system HFS è un altro grande utilizzatore di numeri magici - potete
|
|
||||||
trovarli qui ``fs/hfs/hfs.h``.
|
|
||||||
|
|
|
@ -58,83 +58,17 @@ Linux 魔术数
|
||||||
魔术数名 数字 结构 文件
|
魔术数名 数字 结构 文件
|
||||||
===================== ================ ======================== ==========================================
|
===================== ================ ======================== ==========================================
|
||||||
PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h``
|
PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h``
|
||||||
CMAGIC 0x0111 user ``include/linux/a.out.h``
|
|
||||||
MKISS_DRIVER_MAGIC 0x04bf mkiss_channel ``drivers/net/mkiss.h``
|
|
||||||
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
|
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
|
||||||
DB_MAGIC 0x4442 fc_info ``drivers/net/iph5526_novram.c``
|
|
||||||
DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c``
|
|
||||||
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
|
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
|
||||||
FF_MAGIC 0x4646 fc_info ``drivers/net/iph5526_novram.c``
|
|
||||||
PTY_MAGIC 0x5001 ``drivers/char/pty.c``
|
|
||||||
PPP_MAGIC 0x5002 ppp ``include/linux/if_pppvar.h``
|
|
||||||
SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h``
|
|
||||||
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
|
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
|
||||||
STRIP_MAGIC 0x5303 strip ``drivers/net/strip.c``
|
|
||||||
SIXPACK_MAGIC 0x5304 sixpack ``drivers/net/hamradio/6pack.h``
|
|
||||||
AX25_MAGIC 0x5316 ax_disp ``drivers/net/mkiss.h``
|
|
||||||
MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c``
|
MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c``
|
||||||
USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h``
|
|
||||||
FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c``
|
|
||||||
USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c``
|
|
||||||
RFCOMM_TTY_MAGIC 0x6d02 ``net/bluetooth/rfcomm/tty.c``
|
|
||||||
USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port ``drivers/usb/serial/usb-serial.h``
|
|
||||||
CG_MAGIC 0x00090255 ufs_cylinder_group ``include/linux/ufs_fs.h``
|
|
||||||
LSEMAGIC 0x05091998 lse ``drivers/fc4/fc.c``
|
|
||||||
GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str ``drivers/scsi/gdth_ioctl.h``
|
|
||||||
RIEBL_MAGIC 0x09051990 ``drivers/net/atarilance.c``
|
|
||||||
NBD_REQUEST_MAGIC 0x12560953 nbd_request ``include/linux/nbd.h``
|
|
||||||
RED_MAGIC2 0x170fc2a5 (any) ``mm/slab.c``
|
|
||||||
BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
|
BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
|
||||||
ISDN_X25IFACE_MAGIC 0x1e75a2b9 isdn_x25iface_proto_data ``drivers/isdn/isdn_x25iface.h``
|
|
||||||
ECP_MAGIC 0x21504345 cdkecpsig ``include/linux/cdk.h``
|
|
||||||
LSOMAGIC 0x27091997 lso ``drivers/fc4/fc.c``
|
|
||||||
LSMAGIC 0x2a3b4d2a ls ``drivers/fc4/fc.c``
|
|
||||||
WANPIPE_MAGIC 0x414C4453 sdla_{dump,exec} ``include/linux/wanpipe.h``
|
|
||||||
CS_CARD_MAGIC 0x43525553 cs_card ``sound/oss/cs46xx.c``
|
|
||||||
LABELCL_MAGIC 0x4857434c labelcl_info_s ``include/asm/ia64/sn/labelcl.h``
|
|
||||||
ISDN_ASYNC_MAGIC 0x49344C01 modem_info ``include/linux/isdn.h``
|
|
||||||
CTC_ASYNC_MAGIC 0x49344C01 ctc_tty_info ``drivers/s390/net/ctctty.c``
|
|
||||||
ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s ``drivers/isdn/i4l/isdn_net_lib.h``
|
|
||||||
SAVEKMSG_MAGIC2 0x4B4D5347 savekmsg ``arch/*/amiga/config.c``
|
|
||||||
CS_STATE_MAGIC 0x4c4f4749 cs_state ``sound/oss/cs46xx.c``
|
|
||||||
SLAB_C_MAGIC 0x4f17a36d kmem_cache ``mm/slab.c``
|
|
||||||
COW_MAGIC 0x4f4f4f4d cow_header_v1 ``arch/um/drivers/ubd_user.c``
|
|
||||||
I810_CARD_MAGIC 0x5072696E i810_card ``sound/oss/i810_audio.c``
|
|
||||||
TRIDENT_CARD_MAGIC 0x5072696E trident_card ``sound/oss/trident.c``
|
|
||||||
ROUTER_MAGIC 0x524d4157 wan_device [in ``wanrouter.h`` pre 3.9]
|
|
||||||
SAVEKMSG_MAGIC1 0x53415645 savekmsg ``arch/*/amiga/config.c``
|
|
||||||
GDA_MAGIC 0x58464552 gda ``arch/mips/include/asm/sn/gda.h``
|
|
||||||
RED_MAGIC1 0x5a2cf071 (any) ``mm/slab.c``
|
|
||||||
EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev ``drivers/atm/lanai.c``
|
|
||||||
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
|
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
|
||||||
PCXX_MAGIC 0x5c6df104 channel ``drivers/char/pcxx.h``
|
|
||||||
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
|
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
|
||||||
I810_STATE_MAGIC 0x63657373 i810_state ``sound/oss/i810_audio.c``
|
|
||||||
TRIDENT_STATE_MAGIC 0x63657373 trient_state ``sound/oss/trident.c``
|
|
||||||
M3_CARD_MAGIC 0x646e6f50 m3_card ``sound/oss/maestro3.c``
|
|
||||||
FW_HEADER_MAGIC 0x65726F66 fw_header ``drivers/atm/fore200e.h``
|
|
||||||
SLOT_MAGIC 0x67267321 slot ``drivers/hotplug/cpqphp.h``
|
|
||||||
SLOT_MAGIC 0x67267322 slot ``drivers/hotplug/acpiphp.h``
|
|
||||||
LO_MAGIC 0x68797548 nbd_device ``include/linux/nbd.h``
|
|
||||||
M3_STATE_MAGIC 0x734d724d m3_state ``sound/oss/maestro3.c``
|
|
||||||
VMALLOC_MAGIC 0x87654320 snd_alloc_track ``sound/core/memory.c``
|
|
||||||
KMALLOC_MAGIC 0x87654321 snd_alloc_track ``sound/core/memory.c``
|
|
||||||
PWC_MAGIC 0x89DC10AB pwc_device ``drivers/usb/media/pwc.h``
|
|
||||||
NBD_REPLY_MAGIC 0x96744668 nbd_reply ``include/linux/nbd.h``
|
|
||||||
ENI155_MAGIC 0xa54b872d midway_eprom ``drivers/atm/eni.h``
|
|
||||||
CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
|
CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
|
||||||
DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram ``drivers/scsi/gdth.h``
|
|
||||||
YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
|
YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
|
||||||
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
|
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
|
||||||
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
|
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
|
||||||
QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
|
QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
|
||||||
HTB_CMAGIC 0xFEFAFEF1 htb_class ``net/sched/sch_htb.c``
|
|
||||||
NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h``
|
NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h``
|
||||||
===================== ================ ======================== ==========================================
|
===================== ================ ======================== ==========================================
|
||||||
|
|
||||||
|
|
||||||
请注意,在声音记忆管理中仍然有一些特殊的为每个驱动定义的魔术值。查看include/sound/sndmagic.h来获取他们完整的列表信息。很多OSS声音驱动拥有自己从声卡PCI ID构建的魔术值-他们也没有被列在这里。
|
|
||||||
|
|
||||||
IrDA子系统也使用了大量的自己的魔术值,查看include/net/irda/irda.h来获取他们完整的信息。
|
|
||||||
|
|
||||||
HFS是另外一个比较大的使用魔术值的文件系统-你可以在fs/hfs/hfs.h中找到他们。
|
|
||||||
|
|
|
@ -61,84 +61,17 @@ Linux 魔術數
|
||||||
魔術數名 數字 結構 文件
|
魔術數名 數字 結構 文件
|
||||||
===================== ================ ======================== ==========================================
|
===================== ================ ======================== ==========================================
|
||||||
PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h``
|
PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h``
|
||||||
CMAGIC 0x0111 user ``include/linux/a.out.h``
|
|
||||||
MKISS_DRIVER_MAGIC 0x04bf mkiss_channel ``drivers/net/mkiss.h``
|
|
||||||
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
|
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
|
||||||
DB_MAGIC 0x4442 fc_info ``drivers/net/iph5526_novram.c``
|
|
||||||
DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c``
|
|
||||||
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
|
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
|
||||||
FF_MAGIC 0x4646 fc_info ``drivers/net/iph5526_novram.c``
|
|
||||||
PTY_MAGIC 0x5001 ``drivers/char/pty.c``
|
|
||||||
PPP_MAGIC 0x5002 ppp ``include/linux/if_pppvar.h``
|
|
||||||
SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h``
|
|
||||||
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
|
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
|
||||||
STRIP_MAGIC 0x5303 strip ``drivers/net/strip.c``
|
|
||||||
SIXPACK_MAGIC 0x5304 sixpack ``drivers/net/hamradio/6pack.h``
|
|
||||||
AX25_MAGIC 0x5316 ax_disp ``drivers/net/mkiss.h``
|
|
||||||
MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c``
|
MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c``
|
||||||
USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h``
|
|
||||||
FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c``
|
|
||||||
USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c``
|
|
||||||
RFCOMM_TTY_MAGIC 0x6d02 ``net/bluetooth/rfcomm/tty.c``
|
|
||||||
USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port ``drivers/usb/serial/usb-serial.h``
|
|
||||||
CG_MAGIC 0x00090255 ufs_cylinder_group ``include/linux/ufs_fs.h``
|
|
||||||
LSEMAGIC 0x05091998 lse ``drivers/fc4/fc.c``
|
|
||||||
GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str ``drivers/scsi/gdth_ioctl.h``
|
|
||||||
RIEBL_MAGIC 0x09051990 ``drivers/net/atarilance.c``
|
|
||||||
NBD_REQUEST_MAGIC 0x12560953 nbd_request ``include/linux/nbd.h``
|
|
||||||
RED_MAGIC2 0x170fc2a5 (any) ``mm/slab.c``
|
|
||||||
BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
|
BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
|
||||||
ISDN_X25IFACE_MAGIC 0x1e75a2b9 isdn_x25iface_proto_data ``drivers/isdn/isdn_x25iface.h``
|
|
||||||
ECP_MAGIC 0x21504345 cdkecpsig ``include/linux/cdk.h``
|
|
||||||
LSOMAGIC 0x27091997 lso ``drivers/fc4/fc.c``
|
|
||||||
LSMAGIC 0x2a3b4d2a ls ``drivers/fc4/fc.c``
|
|
||||||
WANPIPE_MAGIC 0x414C4453 sdla_{dump,exec} ``include/linux/wanpipe.h``
|
|
||||||
CS_CARD_MAGIC 0x43525553 cs_card ``sound/oss/cs46xx.c``
|
|
||||||
LABELCL_MAGIC 0x4857434c labelcl_info_s ``include/asm/ia64/sn/labelcl.h``
|
|
||||||
ISDN_ASYNC_MAGIC 0x49344C01 modem_info ``include/linux/isdn.h``
|
|
||||||
CTC_ASYNC_MAGIC 0x49344C01 ctc_tty_info ``drivers/s390/net/ctctty.c``
|
|
||||||
ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s ``drivers/isdn/i4l/isdn_net_lib.h``
|
|
||||||
SAVEKMSG_MAGIC2 0x4B4D5347 savekmsg ``arch/*/amiga/config.c``
|
|
||||||
CS_STATE_MAGIC 0x4c4f4749 cs_state ``sound/oss/cs46xx.c``
|
|
||||||
SLAB_C_MAGIC 0x4f17a36d kmem_cache ``mm/slab.c``
|
|
||||||
COW_MAGIC 0x4f4f4f4d cow_header_v1 ``arch/um/drivers/ubd_user.c``
|
|
||||||
I810_CARD_MAGIC 0x5072696E i810_card ``sound/oss/i810_audio.c``
|
|
||||||
TRIDENT_CARD_MAGIC 0x5072696E trident_card ``sound/oss/trident.c``
|
|
||||||
ROUTER_MAGIC 0x524d4157 wan_device [in ``wanrouter.h`` pre 3.9]
|
|
||||||
SAVEKMSG_MAGIC1 0x53415645 savekmsg ``arch/*/amiga/config.c``
|
|
||||||
GDA_MAGIC 0x58464552 gda ``arch/mips/include/asm/sn/gda.h``
|
|
||||||
RED_MAGIC1 0x5a2cf071 (any) ``mm/slab.c``
|
|
||||||
EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev ``drivers/atm/lanai.c``
|
|
||||||
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
|
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
|
||||||
PCXX_MAGIC 0x5c6df104 channel ``drivers/char/pcxx.h``
|
|
||||||
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
|
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``
|
||||||
I810_STATE_MAGIC 0x63657373 i810_state ``sound/oss/i810_audio.c``
|
|
||||||
TRIDENT_STATE_MAGIC 0x63657373 trient_state ``sound/oss/trident.c``
|
|
||||||
M3_CARD_MAGIC 0x646e6f50 m3_card ``sound/oss/maestro3.c``
|
|
||||||
FW_HEADER_MAGIC 0x65726F66 fw_header ``drivers/atm/fore200e.h``
|
|
||||||
SLOT_MAGIC 0x67267321 slot ``drivers/hotplug/cpqphp.h``
|
|
||||||
SLOT_MAGIC 0x67267322 slot ``drivers/hotplug/acpiphp.h``
|
|
||||||
LO_MAGIC 0x68797548 nbd_device ``include/linux/nbd.h``
|
|
||||||
M3_STATE_MAGIC 0x734d724d m3_state ``sound/oss/maestro3.c``
|
|
||||||
VMALLOC_MAGIC 0x87654320 snd_alloc_track ``sound/core/memory.c``
|
|
||||||
KMALLOC_MAGIC 0x87654321 snd_alloc_track ``sound/core/memory.c``
|
|
||||||
PWC_MAGIC 0x89DC10AB pwc_device ``drivers/usb/media/pwc.h``
|
|
||||||
NBD_REPLY_MAGIC 0x96744668 nbd_reply ``include/linux/nbd.h``
|
|
||||||
ENI155_MAGIC 0xa54b872d midway_eprom ``drivers/atm/eni.h``
|
|
||||||
CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
|
CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h``
|
||||||
DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram ``drivers/scsi/gdth.h``
|
|
||||||
YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
|
YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
|
||||||
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
|
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
|
||||||
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
|
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c``
|
||||||
QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
|
QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c``
|
||||||
HTB_CMAGIC 0xFEFAFEF1 htb_class ``net/sched/sch_htb.c``
|
|
||||||
NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h``
|
NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h``
|
||||||
===================== ================ ======================== ==========================================
|
===================== ================ ======================== ==========================================
|
||||||
|
|
||||||
|
|
||||||
請注意,在聲音記憶管理中仍然有一些特殊的爲每個驅動定義的魔術值。查看include/sound/sndmagic.h來獲取他們完整的列表信息。很多OSS聲音驅動擁有自己從音效卡PCI ID構建的魔術值-他們也沒有被列在這裡。
|
|
||||||
|
|
||||||
IrDA子系統也使用了大量的自己的魔術值,查看include/net/irda/irda.h來獲取他們完整的信息。
|
|
||||||
|
|
||||||
HFS是另外一個比較大的使用魔術值的文件系統-你可以在fs/hfs/hfs.h中找到他們。
|
|
||||||
|
|
||||||
|
|
|
@ -7235,6 +7235,8 @@ M: Jason Baron <jbaron@akamai.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: include/linux/dynamic_debug.h
|
F: include/linux/dynamic_debug.h
|
||||||
F: lib/dynamic_debug.c
|
F: lib/dynamic_debug.c
|
||||||
|
M: Jim Cromie <jim.cromie@gmail.com>
|
||||||
|
F: lib/test_dynamic_debug.c
|
||||||
|
|
||||||
DYNAMIC INTERRUPT MODERATION
|
DYNAMIC INTERRUPT MODERATION
|
||||||
M: Tal Gilboa <talgi@nvidia.com>
|
M: Tal Gilboa <talgi@nvidia.com>
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
#include <asm/sn/addrs.h>
|
#include <asm/sn/addrs.h>
|
||||||
|
|
||||||
#define GDA_MAGIC 0x58464552
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GDA Version History
|
* GDA Version History
|
||||||
*
|
*
|
||||||
|
|
|
@ -154,8 +154,6 @@ extern void driver_remove_groups(struct device_driver *drv,
|
||||||
const struct attribute_group **groups);
|
const struct attribute_group **groups);
|
||||||
void device_driver_detach(struct device *dev);
|
void device_driver_detach(struct device *dev);
|
||||||
|
|
||||||
extern char *make_class_name(const char *name, struct kobject *kobj);
|
|
||||||
|
|
||||||
extern int devres_release_all(struct device *dev);
|
extern int devres_release_all(struct device *dev);
|
||||||
extern void device_block_probing(void);
|
extern void device_block_probing(void);
|
||||||
extern void device_unblock_probing(void);
|
extern void device_unblock_probing(void);
|
||||||
|
|
|
@ -260,7 +260,7 @@ EXPORT_SYMBOL_GPL(__class_create);
|
||||||
*/
|
*/
|
||||||
void class_destroy(struct class *cls)
|
void class_destroy(struct class *cls)
|
||||||
{
|
{
|
||||||
if ((cls == NULL) || (IS_ERR(cls)))
|
if (IS_ERR_OR_NULL(cls))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
class_unregister(cls);
|
class_unregister(cls);
|
||||||
|
|
|
@ -2509,7 +2509,7 @@ static ssize_t uevent_store(struct device *dev, struct device_attribute *attr,
|
||||||
rc = kobject_synth_uevent(&dev->kobj, buf, count);
|
rc = kobject_synth_uevent(&dev->kobj, buf, count);
|
||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
dev_err(dev, "uevent: failed to send synthetic uevent\n");
|
dev_err(dev, "uevent: failed to send synthetic uevent: %d\n", rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4170,7 +4170,7 @@ device_create_groups_vargs(struct class *class, struct device *parent,
|
||||||
struct device *dev = NULL;
|
struct device *dev = NULL;
|
||||||
int retval = -ENODEV;
|
int retval = -ENODEV;
|
||||||
|
|
||||||
if (class == NULL || IS_ERR(class))
|
if (IS_ERR_OR_NULL(class))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||||
|
|
|
@ -836,7 +836,7 @@ static int __init save_async_options(char *buf)
|
||||||
if (strlen(buf) >= ASYNC_DRV_NAMES_MAX_LEN)
|
if (strlen(buf) >= ASYNC_DRV_NAMES_MAX_LEN)
|
||||||
pr_warn("Too long list of driver names for 'driver_async_probe'!\n");
|
pr_warn("Too long list of driver names for 'driver_async_probe'!\n");
|
||||||
|
|
||||||
strlcpy(async_probe_drv_names, buf, ASYNC_DRV_NAMES_MAX_LEN);
|
strscpy(async_probe_drv_names, buf, ASYNC_DRV_NAMES_MAX_LEN);
|
||||||
async_probe_default = parse_option_str(async_probe_drv_names, "*");
|
async_probe_default = parse_option_str(async_probe_drv_names, "*");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -25,6 +25,47 @@ struct devcd_entry {
|
||||||
struct device devcd_dev;
|
struct device devcd_dev;
|
||||||
void *data;
|
void *data;
|
||||||
size_t datalen;
|
size_t datalen;
|
||||||
|
/*
|
||||||
|
* Here, mutex is required to serialize the calls to del_wk work between
|
||||||
|
* user/kernel space which happens when devcd is added with device_add()
|
||||||
|
* and that sends uevent to user space. User space reads the uevents,
|
||||||
|
* and calls to devcd_data_write() which try to modify the work which is
|
||||||
|
* not even initialized/queued from devcoredump.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* cpu0(X) cpu1(Y)
|
||||||
|
*
|
||||||
|
* dev_coredump() uevent sent to user space
|
||||||
|
* device_add() ======================> user space process Y reads the
|
||||||
|
* uevents writes to devcd fd
|
||||||
|
* which results into writes to
|
||||||
|
*
|
||||||
|
* devcd_data_write()
|
||||||
|
* mod_delayed_work()
|
||||||
|
* try_to_grab_pending()
|
||||||
|
* del_timer()
|
||||||
|
* debug_assert_init()
|
||||||
|
* INIT_DELAYED_WORK()
|
||||||
|
* schedule_delayed_work()
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Also, mutex alone would not be enough to avoid scheduling of
|
||||||
|
* del_wk work after it get flush from a call to devcd_free()
|
||||||
|
* mentioned as below.
|
||||||
|
*
|
||||||
|
* disabled_store()
|
||||||
|
* devcd_free()
|
||||||
|
* mutex_lock() devcd_data_write()
|
||||||
|
* flush_delayed_work()
|
||||||
|
* mutex_unlock()
|
||||||
|
* mutex_lock()
|
||||||
|
* mod_delayed_work()
|
||||||
|
* mutex_unlock()
|
||||||
|
* So, delete_work flag is required.
|
||||||
|
*/
|
||||||
|
struct mutex mutex;
|
||||||
|
bool delete_work;
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
ssize_t (*read)(char *buffer, loff_t offset, size_t count,
|
ssize_t (*read)(char *buffer, loff_t offset, size_t count,
|
||||||
void *data, size_t datalen);
|
void *data, size_t datalen);
|
||||||
|
@ -84,7 +125,12 @@ static ssize_t devcd_data_write(struct file *filp, struct kobject *kobj,
|
||||||
struct device *dev = kobj_to_dev(kobj);
|
struct device *dev = kobj_to_dev(kobj);
|
||||||
struct devcd_entry *devcd = dev_to_devcd(dev);
|
struct devcd_entry *devcd = dev_to_devcd(dev);
|
||||||
|
|
||||||
mod_delayed_work(system_wq, &devcd->del_wk, 0);
|
mutex_lock(&devcd->mutex);
|
||||||
|
if (!devcd->delete_work) {
|
||||||
|
devcd->delete_work = true;
|
||||||
|
mod_delayed_work(system_wq, &devcd->del_wk, 0);
|
||||||
|
}
|
||||||
|
mutex_unlock(&devcd->mutex);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -112,7 +158,12 @@ static int devcd_free(struct device *dev, void *data)
|
||||||
{
|
{
|
||||||
struct devcd_entry *devcd = dev_to_devcd(dev);
|
struct devcd_entry *devcd = dev_to_devcd(dev);
|
||||||
|
|
||||||
|
mutex_lock(&devcd->mutex);
|
||||||
|
if (!devcd->delete_work)
|
||||||
|
devcd->delete_work = true;
|
||||||
|
|
||||||
flush_delayed_work(&devcd->del_wk);
|
flush_delayed_work(&devcd->del_wk);
|
||||||
|
mutex_unlock(&devcd->mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +173,30 @@ static ssize_t disabled_show(struct class *class, struct class_attribute *attr,
|
||||||
return sysfs_emit(buf, "%d\n", devcd_disabled);
|
return sysfs_emit(buf, "%d\n", devcd_disabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* disabled_store() worker()
|
||||||
|
* class_for_each_device(&devcd_class,
|
||||||
|
* NULL, NULL, devcd_free)
|
||||||
|
* ...
|
||||||
|
* ...
|
||||||
|
* while ((dev = class_dev_iter_next(&iter))
|
||||||
|
* devcd_del()
|
||||||
|
* device_del()
|
||||||
|
* put_device() <- last reference
|
||||||
|
* error = fn(dev, data) devcd_dev_release()
|
||||||
|
* devcd_free(dev, data) kfree(devcd)
|
||||||
|
* mutex_lock(&devcd->mutex);
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* In the above diagram, It looks like disabled_store() would be racing with parallely
|
||||||
|
* running devcd_del() and result in memory abort while acquiring devcd->mutex which
|
||||||
|
* is called after kfree of devcd memory after dropping its last reference with
|
||||||
|
* put_device(). However, this will not happens as fn(dev, data) runs
|
||||||
|
* with its own reference to device via klist_node so it is not its last reference.
|
||||||
|
* so, above situation would not occur.
|
||||||
|
*/
|
||||||
|
|
||||||
static ssize_t disabled_store(struct class *class, struct class_attribute *attr,
|
static ssize_t disabled_store(struct class *class, struct class_attribute *attr,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
|
@ -278,13 +353,16 @@ void dev_coredumpm(struct device *dev, struct module *owner,
|
||||||
devcd->read = read;
|
devcd->read = read;
|
||||||
devcd->free = free;
|
devcd->free = free;
|
||||||
devcd->failing_dev = get_device(dev);
|
devcd->failing_dev = get_device(dev);
|
||||||
|
devcd->delete_work = false;
|
||||||
|
|
||||||
|
mutex_init(&devcd->mutex);
|
||||||
device_initialize(&devcd->devcd_dev);
|
device_initialize(&devcd->devcd_dev);
|
||||||
|
|
||||||
dev_set_name(&devcd->devcd_dev, "devcd%d",
|
dev_set_name(&devcd->devcd_dev, "devcd%d",
|
||||||
atomic_inc_return(&devcd_count));
|
atomic_inc_return(&devcd_count));
|
||||||
devcd->devcd_dev.class = &devcd_class;
|
devcd->devcd_dev.class = &devcd_class;
|
||||||
|
|
||||||
|
mutex_lock(&devcd->mutex);
|
||||||
if (device_add(&devcd->devcd_dev))
|
if (device_add(&devcd->devcd_dev))
|
||||||
goto put_device;
|
goto put_device;
|
||||||
|
|
||||||
|
@ -301,10 +379,11 @@ void dev_coredumpm(struct device *dev, struct module *owner,
|
||||||
|
|
||||||
INIT_DELAYED_WORK(&devcd->del_wk, devcd_del);
|
INIT_DELAYED_WORK(&devcd->del_wk, devcd_del);
|
||||||
schedule_delayed_work(&devcd->del_wk, DEVCD_TIMEOUT);
|
schedule_delayed_work(&devcd->del_wk, DEVCD_TIMEOUT);
|
||||||
|
mutex_unlock(&devcd->mutex);
|
||||||
return;
|
return;
|
||||||
put_device:
|
put_device:
|
||||||
put_device(&devcd->devcd_dev);
|
put_device(&devcd->devcd_dev);
|
||||||
|
mutex_unlock(&devcd->mutex);
|
||||||
put_module:
|
put_module:
|
||||||
module_put(owner);
|
module_put(owner);
|
||||||
free:
|
free:
|
||||||
|
|
|
@ -117,7 +117,9 @@ static __always_inline struct devres * alloc_dr(dr_release_t release,
|
||||||
if (unlikely(!dr))
|
if (unlikely(!dr))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
memset(dr, 0, offsetof(struct devres, data));
|
/* No need to clear memory twice */
|
||||||
|
if (!(gfp & __GFP_ZERO))
|
||||||
|
memset(dr, 0, offsetof(struct devres, data));
|
||||||
|
|
||||||
INIT_LIST_HEAD(&dr->node.entry);
|
INIT_LIST_HEAD(&dr->node.entry);
|
||||||
dr->node.release = release;
|
dr->node.release = release;
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include <linux/property.h>
|
#include <linux/property.h>
|
||||||
#include <linux/phy.h>
|
#include <linux/phy.h>
|
||||||
|
|
||||||
struct fwnode_handle *dev_fwnode(struct device *dev)
|
struct fwnode_handle *dev_fwnode(const struct device *dev)
|
||||||
{
|
{
|
||||||
return IS_ENABLED(CONFIG_OF) && dev->of_node ?
|
return IS_ENABLED(CONFIG_OF) && dev->of_node ?
|
||||||
of_fwnode_handle(dev->of_node) : dev->fwnode;
|
of_fwnode_handle(dev->of_node) : dev->fwnode;
|
||||||
|
@ -1200,7 +1200,7 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fwnode_graph_parse_endpoint);
|
EXPORT_SYMBOL(fwnode_graph_parse_endpoint);
|
||||||
|
|
||||||
const void *device_get_match_data(struct device *dev)
|
const void *device_get_match_data(const struct device *dev)
|
||||||
{
|
{
|
||||||
return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, dev);
|
return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, dev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,8 +157,6 @@ static struct dentry *nbd_dbg_dir;
|
||||||
|
|
||||||
#define nbd_name(nbd) ((nbd)->disk->disk_name)
|
#define nbd_name(nbd) ((nbd)->disk->disk_name)
|
||||||
|
|
||||||
#define NBD_MAGIC 0x68797548
|
|
||||||
|
|
||||||
#define NBD_DEF_BLKSIZE_BITS 10
|
#define NBD_DEF_BLKSIZE_BITS 10
|
||||||
|
|
||||||
static unsigned int nbds_max = 16;
|
static unsigned int nbds_max = 16;
|
||||||
|
|
|
@ -51,6 +51,18 @@ config DRM_DEBUG_MM
|
||||||
|
|
||||||
If in doubt, say "N".
|
If in doubt, say "N".
|
||||||
|
|
||||||
|
config DRM_USE_DYNAMIC_DEBUG
|
||||||
|
bool "use dynamic debug to implement drm.debug"
|
||||||
|
default y
|
||||||
|
depends on DRM
|
||||||
|
depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE
|
||||||
|
depends on JUMP_LABEL
|
||||||
|
help
|
||||||
|
Use dynamic-debug to avoid drm_debug_enabled() runtime overheads.
|
||||||
|
Due to callsite counts in DRM drivers (~4k in amdgpu) and 56
|
||||||
|
bytes per callsite, the .data costs can be substantial, and
|
||||||
|
are therefore configurable.
|
||||||
|
|
||||||
config DRM_KUNIT_TEST
|
config DRM_KUNIT_TEST
|
||||||
tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS
|
tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS
|
||||||
depends on DRM && KUNIT
|
depends on DRM && KUNIT
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
# Makefile for the drm device driver. This driver provides support for the
|
# Makefile for the drm device driver. This driver provides support for the
|
||||||
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
||||||
|
|
||||||
|
CFLAGS-$(CONFIG_DRM_USE_DYNAMIC_DEBUG) += -DDYNAMIC_DEBUG_MODULE
|
||||||
|
|
||||||
drm-y := drm_aperture.o drm_auth.o drm_cache.o \
|
drm-y := drm_aperture.o drm_auth.o drm_cache.o \
|
||||||
drm_file.o drm_gem.o drm_ioctl.o \
|
drm_file.o drm_gem.o drm_ioctl.o \
|
||||||
drm_drv.o \
|
drm_drv.o \
|
||||||
|
|
|
@ -38,6 +38,8 @@
|
||||||
#include <linux/mmu_notifier.h>
|
#include <linux/mmu_notifier.h>
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
#include <linux/cc_platform.h>
|
#include <linux/cc_platform.h>
|
||||||
|
#include <linux/fb.h>
|
||||||
|
#include <linux/dynamic_debug.h>
|
||||||
|
|
||||||
#include "amdgpu.h"
|
#include "amdgpu.h"
|
||||||
#include "amdgpu_irq.h"
|
#include "amdgpu_irq.h"
|
||||||
|
@ -186,6 +188,18 @@ int amdgpu_vcnfw_log;
|
||||||
|
|
||||||
static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work);
|
static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work);
|
||||||
|
|
||||||
|
DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
|
||||||
|
"DRM_UT_CORE",
|
||||||
|
"DRM_UT_DRIVER",
|
||||||
|
"DRM_UT_KMS",
|
||||||
|
"DRM_UT_PRIME",
|
||||||
|
"DRM_UT_ATOMIC",
|
||||||
|
"DRM_UT_VBL",
|
||||||
|
"DRM_UT_STATE",
|
||||||
|
"DRM_UT_LEASE",
|
||||||
|
"DRM_UT_DP",
|
||||||
|
"DRM_UT_DRMRES");
|
||||||
|
|
||||||
struct amdgpu_mgpu_info mgpu_info = {
|
struct amdgpu_mgpu_info mgpu_info = {
|
||||||
.mutex = __MUTEX_INITIALIZER(mgpu_info.mutex),
|
.mutex = __MUTEX_INITIALIZER(mgpu_info.mutex),
|
||||||
.delayed_reset_work = __DELAYED_WORK_INITIALIZER(
|
.delayed_reset_work = __DELAYED_WORK_INITIALIZER(
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
#include <linux/string_helpers.h>
|
#include <linux/string_helpers.h>
|
||||||
|
#include <linux/dynamic_debug.h>
|
||||||
|
|
||||||
#include <drm/display/drm_dp_helper.h>
|
#include <drm/display/drm_dp_helper.h>
|
||||||
#include <drm/display/drm_dp_mst_helper.h>
|
#include <drm/display/drm_dp_mst_helper.h>
|
||||||
|
@ -40,6 +41,18 @@
|
||||||
|
|
||||||
#include "drm_dp_helper_internal.h"
|
#include "drm_dp_helper_internal.h"
|
||||||
|
|
||||||
|
DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
|
||||||
|
"DRM_UT_CORE",
|
||||||
|
"DRM_UT_DRIVER",
|
||||||
|
"DRM_UT_KMS",
|
||||||
|
"DRM_UT_PRIME",
|
||||||
|
"DRM_UT_ATOMIC",
|
||||||
|
"DRM_UT_VBL",
|
||||||
|
"DRM_UT_STATE",
|
||||||
|
"DRM_UT_LEASE",
|
||||||
|
"DRM_UT_DP",
|
||||||
|
"DRM_UT_DRMRES");
|
||||||
|
|
||||||
struct dp_aux_backlight {
|
struct dp_aux_backlight {
|
||||||
struct backlight_device *base;
|
struct backlight_device *base;
|
||||||
struct drm_dp_aux *aux;
|
struct drm_dp_aux *aux;
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
|
#include <linux/dynamic_debug.h>
|
||||||
|
|
||||||
#include <drm/drm_atomic.h>
|
#include <drm/drm_atomic.h>
|
||||||
#include <drm/drm_atomic_helper.h>
|
#include <drm/drm_atomic_helper.h>
|
||||||
|
@ -50,6 +51,18 @@
|
||||||
|
|
||||||
#include "drm_crtc_helper_internal.h"
|
#include "drm_crtc_helper_internal.h"
|
||||||
|
|
||||||
|
DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
|
||||||
|
"DRM_UT_CORE",
|
||||||
|
"DRM_UT_DRIVER",
|
||||||
|
"DRM_UT_KMS",
|
||||||
|
"DRM_UT_PRIME",
|
||||||
|
"DRM_UT_ATOMIC",
|
||||||
|
"DRM_UT_VBL",
|
||||||
|
"DRM_UT_STATE",
|
||||||
|
"DRM_UT_LEASE",
|
||||||
|
"DRM_UT_DP",
|
||||||
|
"DRM_UT_DRMRES");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOC: overview
|
* DOC: overview
|
||||||
*
|
*
|
||||||
|
|
|
@ -23,14 +23,13 @@
|
||||||
* Rob Clark <robdclark@gmail.com>
|
* Rob Clark <robdclark@gmail.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define DEBUG /* for pr_debug() */
|
|
||||||
|
|
||||||
#include <linux/stdarg.h>
|
#include <linux/stdarg.h>
|
||||||
|
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/dynamic_debug.h>
|
||||||
|
|
||||||
#include <drm/drm.h>
|
#include <drm/drm.h>
|
||||||
#include <drm/drm_drv.h>
|
#include <drm/drm_drv.h>
|
||||||
|
@ -40,7 +39,7 @@
|
||||||
* __drm_debug: Enable debug output.
|
* __drm_debug: Enable debug output.
|
||||||
* Bitmask of DRM_UT_x. See include/drm/drm_print.h for details.
|
* Bitmask of DRM_UT_x. See include/drm/drm_print.h for details.
|
||||||
*/
|
*/
|
||||||
unsigned int __drm_debug;
|
unsigned long __drm_debug;
|
||||||
EXPORT_SYMBOL(__drm_debug);
|
EXPORT_SYMBOL(__drm_debug);
|
||||||
|
|
||||||
MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug category.\n"
|
MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug category.\n"
|
||||||
|
@ -52,7 +51,30 @@ MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug cat
|
||||||
"\t\tBit 5 (0x20) will enable VBL messages (vblank code)\n"
|
"\t\tBit 5 (0x20) will enable VBL messages (vblank code)\n"
|
||||||
"\t\tBit 7 (0x80) will enable LEASE messages (leasing code)\n"
|
"\t\tBit 7 (0x80) will enable LEASE messages (leasing code)\n"
|
||||||
"\t\tBit 8 (0x100) will enable DP messages (displayport code)");
|
"\t\tBit 8 (0x100) will enable DP messages (displayport code)");
|
||||||
module_param_named(debug, __drm_debug, int, 0600);
|
|
||||||
|
#if !defined(CONFIG_DRM_USE_DYNAMIC_DEBUG)
|
||||||
|
module_param_named(debug, __drm_debug, ulong, 0600);
|
||||||
|
#else
|
||||||
|
/* classnames must match vals of enum drm_debug_category */
|
||||||
|
DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
|
||||||
|
"DRM_UT_CORE",
|
||||||
|
"DRM_UT_DRIVER",
|
||||||
|
"DRM_UT_KMS",
|
||||||
|
"DRM_UT_PRIME",
|
||||||
|
"DRM_UT_ATOMIC",
|
||||||
|
"DRM_UT_VBL",
|
||||||
|
"DRM_UT_STATE",
|
||||||
|
"DRM_UT_LEASE",
|
||||||
|
"DRM_UT_DP",
|
||||||
|
"DRM_UT_DRMRES");
|
||||||
|
|
||||||
|
static struct ddebug_class_param drm_debug_bitmap = {
|
||||||
|
.bits = &__drm_debug,
|
||||||
|
.flags = "p",
|
||||||
|
.map = &drm_debug_classes,
|
||||||
|
};
|
||||||
|
module_param_cb(debug, ¶m_ops_dyndbg_classes, &drm_debug_bitmap, 0600);
|
||||||
|
#endif
|
||||||
|
|
||||||
void __drm_puts_coredump(struct drm_printer *p, const char *str)
|
void __drm_puts_coredump(struct drm_printer *p, const char *str)
|
||||||
{
|
{
|
||||||
|
@ -162,7 +184,8 @@ EXPORT_SYMBOL(__drm_printfn_info);
|
||||||
|
|
||||||
void __drm_printfn_debug(struct drm_printer *p, struct va_format *vaf)
|
void __drm_printfn_debug(struct drm_printer *p, struct va_format *vaf)
|
||||||
{
|
{
|
||||||
pr_debug("%s %pV", p->prefix, vaf);
|
/* pr_debug callsite decorations are unhelpful here */
|
||||||
|
printk(KERN_DEBUG "%s %pV", p->prefix, vaf);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__drm_printfn_debug);
|
EXPORT_SYMBOL(__drm_printfn_debug);
|
||||||
|
|
||||||
|
@ -256,15 +279,16 @@ void drm_dev_printk(const struct device *dev, const char *level,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_dev_printk);
|
EXPORT_SYMBOL(drm_dev_printk);
|
||||||
|
|
||||||
void drm_dev_dbg(const struct device *dev, enum drm_debug_category category,
|
void __drm_dev_dbg(struct _ddebug *desc, const struct device *dev,
|
||||||
const char *format, ...)
|
enum drm_debug_category category, const char *format, ...)
|
||||||
{
|
{
|
||||||
struct va_format vaf;
|
struct va_format vaf;
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
if (!drm_debug_enabled(category))
|
if (!__drm_debug_enabled(category))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* we know we are printing for either syslog, tracefs, or both */
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
vaf.fmt = format;
|
vaf.fmt = format;
|
||||||
vaf.va = &args;
|
vaf.va = &args;
|
||||||
|
@ -278,14 +302,14 @@ void drm_dev_dbg(const struct device *dev, enum drm_debug_category category,
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_dev_dbg);
|
EXPORT_SYMBOL(__drm_dev_dbg);
|
||||||
|
|
||||||
void __drm_dbg(enum drm_debug_category category, const char *format, ...)
|
void ___drm_dbg(struct _ddebug *desc, enum drm_debug_category category, const char *format, ...)
|
||||||
{
|
{
|
||||||
struct va_format vaf;
|
struct va_format vaf;
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
if (!drm_debug_enabled(category))
|
if (!__drm_debug_enabled(category))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
|
@ -297,7 +321,7 @@ void __drm_dbg(enum drm_debug_category category, const char *format, ...)
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__drm_dbg);
|
EXPORT_SYMBOL(___drm_dbg);
|
||||||
|
|
||||||
void __drm_err(const char *format, ...)
|
void __drm_err(const char *format, ...)
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,6 +29,18 @@
|
||||||
#include "i915_params.h"
|
#include "i915_params.h"
|
||||||
#include "i915_drv.h"
|
#include "i915_drv.h"
|
||||||
|
|
||||||
|
DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
|
||||||
|
"DRM_UT_CORE",
|
||||||
|
"DRM_UT_DRIVER",
|
||||||
|
"DRM_UT_KMS",
|
||||||
|
"DRM_UT_PRIME",
|
||||||
|
"DRM_UT_ATOMIC",
|
||||||
|
"DRM_UT_VBL",
|
||||||
|
"DRM_UT_STATE",
|
||||||
|
"DRM_UT_LEASE",
|
||||||
|
"DRM_UT_DP",
|
||||||
|
"DRM_UT_DRMRES");
|
||||||
|
|
||||||
#define i915_param_named(name, T, perm, desc) \
|
#define i915_param_named(name, T, perm, desc) \
|
||||||
module_param_named(name, i915_modparams.name, T, perm); \
|
module_param_named(name, i915_modparams.name, T, perm); \
|
||||||
MODULE_PARM_DESC(name, desc)
|
MODULE_PARM_DESC(name, desc)
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/vga_switcheroo.h>
|
#include <linux/vga_switcheroo.h>
|
||||||
#include <linux/mmu_notifier.h>
|
#include <linux/mmu_notifier.h>
|
||||||
|
#include <linux/dynamic_debug.h>
|
||||||
|
|
||||||
#include <drm/drm_aperture.h>
|
#include <drm/drm_aperture.h>
|
||||||
#include <drm/drm_crtc_helper.h>
|
#include <drm/drm_crtc_helper.h>
|
||||||
|
@ -70,6 +71,18 @@
|
||||||
#include "nouveau_svm.h"
|
#include "nouveau_svm.h"
|
||||||
#include "nouveau_dmem.h"
|
#include "nouveau_dmem.h"
|
||||||
|
|
||||||
|
DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
|
||||||
|
"DRM_UT_CORE",
|
||||||
|
"DRM_UT_DRIVER",
|
||||||
|
"DRM_UT_KMS",
|
||||||
|
"DRM_UT_PRIME",
|
||||||
|
"DRM_UT_ATOMIC",
|
||||||
|
"DRM_UT_VBL",
|
||||||
|
"DRM_UT_STATE",
|
||||||
|
"DRM_UT_LEASE",
|
||||||
|
"DRM_UT_DP",
|
||||||
|
"DRM_UT_DRMRES");
|
||||||
|
|
||||||
MODULE_PARM_DESC(config, "option string to pass to driver core");
|
MODULE_PARM_DESC(config, "option string to pass to driver core");
|
||||||
static char *nouveau_config;
|
static char *nouveau_config;
|
||||||
module_param_named(config, nouveau_config, charp, 0400);
|
module_param_named(config, nouveau_config, charp, 0400);
|
||||||
|
|
|
@ -1121,7 +1121,7 @@ void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(debugfs_print_regs32);
|
EXPORT_SYMBOL_GPL(debugfs_print_regs32);
|
||||||
|
|
||||||
static int debugfs_show_regset32(struct seq_file *s, void *data)
|
static int debugfs_regset32_show(struct seq_file *s, void *data)
|
||||||
{
|
{
|
||||||
struct debugfs_regset32 *regset = s->private;
|
struct debugfs_regset32 *regset = s->private;
|
||||||
|
|
||||||
|
@ -1136,17 +1136,7 @@ static int debugfs_show_regset32(struct seq_file *s, void *data)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int debugfs_open_regset32(struct inode *inode, struct file *file)
|
DEFINE_SHOW_ATTRIBUTE(debugfs_regset32);
|
||||||
{
|
|
||||||
return single_open(file, debugfs_show_regset32, inode->i_private);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct file_operations fops_regset32 = {
|
|
||||||
.open = debugfs_open_regset32,
|
|
||||||
.read = seq_read,
|
|
||||||
.llseek = seq_lseek,
|
|
||||||
.release = single_release,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* debugfs_create_regset32 - create a debugfs file that returns register values
|
* debugfs_create_regset32 - create a debugfs file that returns register values
|
||||||
|
@ -1167,7 +1157,7 @@ void debugfs_create_regset32(const char *name, umode_t mode,
|
||||||
struct dentry *parent,
|
struct dentry *parent,
|
||||||
struct debugfs_regset32 *regset)
|
struct debugfs_regset32 *regset)
|
||||||
{
|
{
|
||||||
debugfs_create_file(name, mode, parent, regset, &fops_regset32);
|
debugfs_create_file(name, mode, parent, regset, &debugfs_regset32_fops);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(debugfs_create_regset32);
|
EXPORT_SYMBOL_GPL(debugfs_create_regset32);
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,8 @@ struct debugfs_mount_opts {
|
||||||
kuid_t uid;
|
kuid_t uid;
|
||||||
kgid_t gid;
|
kgid_t gid;
|
||||||
umode_t mode;
|
umode_t mode;
|
||||||
|
/* Opt_* bitfield. */
|
||||||
|
unsigned int opts;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -111,6 +113,7 @@ static int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts)
|
||||||
kgid_t gid;
|
kgid_t gid;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
|
opts->opts = 0;
|
||||||
opts->mode = DEBUGFS_DEFAULT_MODE;
|
opts->mode = DEBUGFS_DEFAULT_MODE;
|
||||||
|
|
||||||
while ((p = strsep(&data, ",")) != NULL) {
|
while ((p = strsep(&data, ",")) != NULL) {
|
||||||
|
@ -145,24 +148,44 @@ static int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts)
|
||||||
* but traditionally debugfs has ignored all mount options
|
* but traditionally debugfs has ignored all mount options
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opts->opts |= BIT(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int debugfs_apply_options(struct super_block *sb)
|
static void _debugfs_apply_options(struct super_block *sb, bool remount)
|
||||||
{
|
{
|
||||||
struct debugfs_fs_info *fsi = sb->s_fs_info;
|
struct debugfs_fs_info *fsi = sb->s_fs_info;
|
||||||
struct inode *inode = d_inode(sb->s_root);
|
struct inode *inode = d_inode(sb->s_root);
|
||||||
struct debugfs_mount_opts *opts = &fsi->mount_opts;
|
struct debugfs_mount_opts *opts = &fsi->mount_opts;
|
||||||
|
|
||||||
inode->i_mode &= ~S_IALLUGO;
|
/*
|
||||||
inode->i_mode |= opts->mode;
|
* On remount, only reset mode/uid/gid if they were provided as mount
|
||||||
|
* options.
|
||||||
|
*/
|
||||||
|
|
||||||
inode->i_uid = opts->uid;
|
if (!remount || opts->opts & BIT(Opt_mode)) {
|
||||||
inode->i_gid = opts->gid;
|
inode->i_mode &= ~S_IALLUGO;
|
||||||
|
inode->i_mode |= opts->mode;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
if (!remount || opts->opts & BIT(Opt_uid))
|
||||||
|
inode->i_uid = opts->uid;
|
||||||
|
|
||||||
|
if (!remount || opts->opts & BIT(Opt_gid))
|
||||||
|
inode->i_gid = opts->gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void debugfs_apply_options(struct super_block *sb)
|
||||||
|
{
|
||||||
|
_debugfs_apply_options(sb, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void debugfs_apply_options_remount(struct super_block *sb)
|
||||||
|
{
|
||||||
|
_debugfs_apply_options(sb, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int debugfs_remount(struct super_block *sb, int *flags, char *data)
|
static int debugfs_remount(struct super_block *sb, int *flags, char *data)
|
||||||
|
@ -175,7 +198,7 @@ static int debugfs_remount(struct super_block *sb, int *flags, char *data)
|
||||||
if (err)
|
if (err)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
debugfs_apply_options(sb);
|
debugfs_apply_options_remount(sb);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
return err;
|
return err;
|
||||||
|
|
107
fs/kernfs/dir.c
107
fs/kernfs/dir.c
|
@ -472,6 +472,16 @@ static void kernfs_drain(struct kernfs_node *kn)
|
||||||
lockdep_assert_held_write(&root->kernfs_rwsem);
|
lockdep_assert_held_write(&root->kernfs_rwsem);
|
||||||
WARN_ON_ONCE(kernfs_active(kn));
|
WARN_ON_ONCE(kernfs_active(kn));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip draining if already fully drained. This avoids draining and its
|
||||||
|
* lockdep annotations for nodes which have never been activated
|
||||||
|
* allowing embedding kernfs_remove() in create error paths without
|
||||||
|
* worrying about draining.
|
||||||
|
*/
|
||||||
|
if (atomic_read(&kn->active) == KN_DEACTIVATED_BIAS &&
|
||||||
|
!kernfs_should_drain_open_files(kn))
|
||||||
|
return;
|
||||||
|
|
||||||
up_write(&root->kernfs_rwsem);
|
up_write(&root->kernfs_rwsem);
|
||||||
|
|
||||||
if (kernfs_lockdep(kn)) {
|
if (kernfs_lockdep(kn)) {
|
||||||
|
@ -480,7 +490,6 @@ static void kernfs_drain(struct kernfs_node *kn)
|
||||||
lock_contended(&kn->dep_map, _RET_IP_);
|
lock_contended(&kn->dep_map, _RET_IP_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* but everyone should wait for draining */
|
|
||||||
wait_event(root->deactivate_waitq,
|
wait_event(root->deactivate_waitq,
|
||||||
atomic_read(&kn->active) == KN_DEACTIVATED_BIAS);
|
atomic_read(&kn->active) == KN_DEACTIVATED_BIAS);
|
||||||
|
|
||||||
|
@ -489,7 +498,8 @@ static void kernfs_drain(struct kernfs_node *kn)
|
||||||
rwsem_release(&kn->dep_map, _RET_IP_);
|
rwsem_release(&kn->dep_map, _RET_IP_);
|
||||||
}
|
}
|
||||||
|
|
||||||
kernfs_drain_open_files(kn);
|
if (kernfs_should_drain_open_files(kn))
|
||||||
|
kernfs_drain_open_files(kn);
|
||||||
|
|
||||||
down_write(&root->kernfs_rwsem);
|
down_write(&root->kernfs_rwsem);
|
||||||
}
|
}
|
||||||
|
@ -695,13 +705,7 @@ struct kernfs_node *kernfs_find_and_get_node_by_id(struct kernfs_root *root,
|
||||||
goto err_unlock;
|
goto err_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (unlikely(!kernfs_active(kn) || !atomic_inc_not_zero(&kn->count)))
|
||||||
* ACTIVATED is protected with kernfs_mutex but it was clear when
|
|
||||||
* @kn was added to idr and we just wanna see it set. No need to
|
|
||||||
* grab kernfs_mutex.
|
|
||||||
*/
|
|
||||||
if (unlikely(!(kn->flags & KERNFS_ACTIVATED) ||
|
|
||||||
!atomic_inc_not_zero(&kn->count)))
|
|
||||||
goto err_unlock;
|
goto err_unlock;
|
||||||
|
|
||||||
spin_unlock(&kernfs_idr_lock);
|
spin_unlock(&kernfs_idr_lock);
|
||||||
|
@ -743,10 +747,7 @@ int kernfs_add_one(struct kernfs_node *kn)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
if (parent->flags & KERNFS_EMPTY_DIR)
|
if (parent->flags & (KERNFS_REMOVING | KERNFS_EMPTY_DIR))
|
||||||
goto out_unlock;
|
|
||||||
|
|
||||||
if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent))
|
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
kn->hash = kernfs_name_hash(kn->name, kn->ns);
|
kn->hash = kernfs_name_hash(kn->name, kn->ns);
|
||||||
|
@ -1304,6 +1305,21 @@ static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos,
|
||||||
return pos->parent;
|
return pos->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void kernfs_activate_one(struct kernfs_node *kn)
|
||||||
|
{
|
||||||
|
lockdep_assert_held_write(&kernfs_root(kn)->kernfs_rwsem);
|
||||||
|
|
||||||
|
kn->flags |= KERNFS_ACTIVATED;
|
||||||
|
|
||||||
|
if (kernfs_active(kn) || (kn->flags & (KERNFS_HIDDEN | KERNFS_REMOVING)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
WARN_ON_ONCE(kn->parent && RB_EMPTY_NODE(&kn->rb));
|
||||||
|
WARN_ON_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS);
|
||||||
|
|
||||||
|
atomic_sub(KN_DEACTIVATED_BIAS, &kn->active);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kernfs_activate - activate a node which started deactivated
|
* kernfs_activate - activate a node which started deactivated
|
||||||
* @kn: kernfs_node whose subtree is to be activated
|
* @kn: kernfs_node whose subtree is to be activated
|
||||||
|
@ -1325,15 +1341,42 @@ void kernfs_activate(struct kernfs_node *kn)
|
||||||
down_write(&root->kernfs_rwsem);
|
down_write(&root->kernfs_rwsem);
|
||||||
|
|
||||||
pos = NULL;
|
pos = NULL;
|
||||||
while ((pos = kernfs_next_descendant_post(pos, kn))) {
|
while ((pos = kernfs_next_descendant_post(pos, kn)))
|
||||||
if (pos->flags & KERNFS_ACTIVATED)
|
kernfs_activate_one(pos);
|
||||||
continue;
|
|
||||||
|
|
||||||
WARN_ON_ONCE(pos->parent && RB_EMPTY_NODE(&pos->rb));
|
up_write(&root->kernfs_rwsem);
|
||||||
WARN_ON_ONCE(atomic_read(&pos->active) != KN_DEACTIVATED_BIAS);
|
}
|
||||||
|
|
||||||
atomic_sub(KN_DEACTIVATED_BIAS, &pos->active);
|
/**
|
||||||
pos->flags |= KERNFS_ACTIVATED;
|
* kernfs_show - show or hide a node
|
||||||
|
* @kn: kernfs_node to show or hide
|
||||||
|
* @show: whether to show or hide
|
||||||
|
*
|
||||||
|
* If @show is %false, @kn is marked hidden and deactivated. A hidden node is
|
||||||
|
* ignored in future activaitons. If %true, the mark is removed and activation
|
||||||
|
* state is restored. This function won't implicitly activate a new node in a
|
||||||
|
* %KERNFS_ROOT_CREATE_DEACTIVATED root which hasn't been activated yet.
|
||||||
|
*
|
||||||
|
* To avoid recursion complexities, directories aren't supported for now.
|
||||||
|
*/
|
||||||
|
void kernfs_show(struct kernfs_node *kn, bool show)
|
||||||
|
{
|
||||||
|
struct kernfs_root *root = kernfs_root(kn);
|
||||||
|
|
||||||
|
if (WARN_ON_ONCE(kernfs_type(kn) == KERNFS_DIR))
|
||||||
|
return;
|
||||||
|
|
||||||
|
down_write(&root->kernfs_rwsem);
|
||||||
|
|
||||||
|
if (show) {
|
||||||
|
kn->flags &= ~KERNFS_HIDDEN;
|
||||||
|
if (kn->flags & KERNFS_ACTIVATED)
|
||||||
|
kernfs_activate_one(kn);
|
||||||
|
} else {
|
||||||
|
kn->flags |= KERNFS_HIDDEN;
|
||||||
|
if (kernfs_active(kn))
|
||||||
|
atomic_add(KN_DEACTIVATED_BIAS, &kn->active);
|
||||||
|
kernfs_drain(kn);
|
||||||
}
|
}
|
||||||
|
|
||||||
up_write(&root->kernfs_rwsem);
|
up_write(&root->kernfs_rwsem);
|
||||||
|
@ -1358,34 +1401,27 @@ static void __kernfs_remove(struct kernfs_node *kn)
|
||||||
|
|
||||||
pr_debug("kernfs %s: removing\n", kn->name);
|
pr_debug("kernfs %s: removing\n", kn->name);
|
||||||
|
|
||||||
/* prevent any new usage under @kn by deactivating all nodes */
|
/* prevent new usage by marking all nodes removing and deactivating */
|
||||||
pos = NULL;
|
pos = NULL;
|
||||||
while ((pos = kernfs_next_descendant_post(pos, kn)))
|
while ((pos = kernfs_next_descendant_post(pos, kn))) {
|
||||||
|
pos->flags |= KERNFS_REMOVING;
|
||||||
if (kernfs_active(pos))
|
if (kernfs_active(pos))
|
||||||
atomic_add(KN_DEACTIVATED_BIAS, &pos->active);
|
atomic_add(KN_DEACTIVATED_BIAS, &pos->active);
|
||||||
|
}
|
||||||
|
|
||||||
/* deactivate and unlink the subtree node-by-node */
|
/* deactivate and unlink the subtree node-by-node */
|
||||||
do {
|
do {
|
||||||
pos = kernfs_leftmost_descendant(kn);
|
pos = kernfs_leftmost_descendant(kn);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* kernfs_drain() drops kernfs_rwsem temporarily and @pos's
|
* kernfs_drain() may drop kernfs_rwsem temporarily and @pos's
|
||||||
* base ref could have been put by someone else by the time
|
* base ref could have been put by someone else by the time
|
||||||
* the function returns. Make sure it doesn't go away
|
* the function returns. Make sure it doesn't go away
|
||||||
* underneath us.
|
* underneath us.
|
||||||
*/
|
*/
|
||||||
kernfs_get(pos);
|
kernfs_get(pos);
|
||||||
|
|
||||||
/*
|
kernfs_drain(pos);
|
||||||
* Drain iff @kn was activated. This avoids draining and
|
|
||||||
* its lockdep annotations for nodes which have never been
|
|
||||||
* activated and allows embedding kernfs_remove() in create
|
|
||||||
* error paths without worrying about draining.
|
|
||||||
*/
|
|
||||||
if (kn->flags & KERNFS_ACTIVATED)
|
|
||||||
kernfs_drain(pos);
|
|
||||||
else
|
|
||||||
WARN_ON_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* kernfs_unlink_sibling() succeeds once per node. Use it
|
* kernfs_unlink_sibling() succeeds once per node. Use it
|
||||||
|
@ -1585,8 +1621,11 @@ int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name,
|
||||||
down_write(&root->kernfs_rwsem);
|
down_write(&root->kernfs_rwsem);
|
||||||
|
|
||||||
kn = kernfs_find_ns(parent, name, ns);
|
kn = kernfs_find_ns(parent, name, ns);
|
||||||
if (kn)
|
if (kn) {
|
||||||
|
kernfs_get(kn);
|
||||||
__kernfs_remove(kn);
|
__kernfs_remove(kn);
|
||||||
|
kernfs_put(kn);
|
||||||
|
}
|
||||||
|
|
||||||
up_write(&root->kernfs_rwsem);
|
up_write(&root->kernfs_rwsem);
|
||||||
|
|
||||||
|
|
153
fs/kernfs/file.c
153
fs/kernfs/file.c
|
@ -23,6 +23,8 @@ struct kernfs_open_node {
|
||||||
atomic_t event;
|
atomic_t event;
|
||||||
wait_queue_head_t poll;
|
wait_queue_head_t poll;
|
||||||
struct list_head files; /* goes through kernfs_open_file.list */
|
struct list_head files; /* goes through kernfs_open_file.list */
|
||||||
|
unsigned int nr_mmapped;
|
||||||
|
unsigned int nr_to_release;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -57,31 +59,17 @@ static inline struct mutex *kernfs_open_file_mutex_lock(struct kernfs_node *kn)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kernfs_deref_open_node - Get kernfs_open_node corresponding to @kn.
|
* of_on - Return the kernfs_open_node of the specified kernfs_open_file
|
||||||
*
|
* @of: taret kernfs_open_file
|
||||||
* @of: associated kernfs_open_file instance.
|
|
||||||
* @kn: target kernfs_node.
|
|
||||||
*
|
|
||||||
* Fetch and return ->attr.open of @kn if @of->list is non empty.
|
|
||||||
* If @of->list is not empty we can safely assume that @of is on
|
|
||||||
* @kn->attr.open->files list and this guarantees that @kn->attr.open
|
|
||||||
* will not vanish i.e. dereferencing outside RCU read-side critical
|
|
||||||
* section is safe here.
|
|
||||||
*
|
|
||||||
* The caller needs to make sure that @of->list is not empty.
|
|
||||||
*/
|
*/
|
||||||
static struct kernfs_open_node *
|
static struct kernfs_open_node *of_on(struct kernfs_open_file *of)
|
||||||
kernfs_deref_open_node(struct kernfs_open_file *of, struct kernfs_node *kn)
|
|
||||||
{
|
{
|
||||||
struct kernfs_open_node *on;
|
return rcu_dereference_protected(of->kn->attr.open,
|
||||||
|
!list_empty(&of->list));
|
||||||
on = rcu_dereference_check(kn->attr.open, !list_empty(&of->list));
|
|
||||||
|
|
||||||
return on;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kernfs_deref_open_node_protected - Get kernfs_open_node corresponding to @kn
|
* kernfs_deref_open_node_locked - Get kernfs_open_node corresponding to @kn
|
||||||
*
|
*
|
||||||
* @kn: target kernfs_node.
|
* @kn: target kernfs_node.
|
||||||
*
|
*
|
||||||
|
@ -96,7 +84,7 @@ kernfs_deref_open_node(struct kernfs_open_file *of, struct kernfs_node *kn)
|
||||||
* The caller needs to make sure that kernfs_open_file_mutex is held.
|
* The caller needs to make sure that kernfs_open_file_mutex is held.
|
||||||
*/
|
*/
|
||||||
static struct kernfs_open_node *
|
static struct kernfs_open_node *
|
||||||
kernfs_deref_open_node_protected(struct kernfs_node *kn)
|
kernfs_deref_open_node_locked(struct kernfs_node *kn)
|
||||||
{
|
{
|
||||||
return rcu_dereference_protected(kn->attr.open,
|
return rcu_dereference_protected(kn->attr.open,
|
||||||
lockdep_is_held(kernfs_open_file_mutex_ptr(kn)));
|
lockdep_is_held(kernfs_open_file_mutex_ptr(kn)));
|
||||||
|
@ -207,12 +195,8 @@ static void kernfs_seq_stop(struct seq_file *sf, void *v)
|
||||||
static int kernfs_seq_show(struct seq_file *sf, void *v)
|
static int kernfs_seq_show(struct seq_file *sf, void *v)
|
||||||
{
|
{
|
||||||
struct kernfs_open_file *of = sf->private;
|
struct kernfs_open_file *of = sf->private;
|
||||||
struct kernfs_open_node *on = kernfs_deref_open_node(of, of->kn);
|
|
||||||
|
|
||||||
if (!on)
|
of->event = atomic_read(&of_on(of)->event);
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
of->event = atomic_read(&on->event);
|
|
||||||
|
|
||||||
return of->kn->attr.ops->seq_show(sf, v);
|
return of->kn->attr.ops->seq_show(sf, v);
|
||||||
}
|
}
|
||||||
|
@ -235,7 +219,6 @@ static ssize_t kernfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
|
||||||
struct kernfs_open_file *of = kernfs_of(iocb->ki_filp);
|
struct kernfs_open_file *of = kernfs_of(iocb->ki_filp);
|
||||||
ssize_t len = min_t(size_t, iov_iter_count(iter), PAGE_SIZE);
|
ssize_t len = min_t(size_t, iov_iter_count(iter), PAGE_SIZE);
|
||||||
const struct kernfs_ops *ops;
|
const struct kernfs_ops *ops;
|
||||||
struct kernfs_open_node *on;
|
|
||||||
char *buf;
|
char *buf;
|
||||||
|
|
||||||
buf = of->prealloc_buf;
|
buf = of->prealloc_buf;
|
||||||
|
@ -257,14 +240,7 @@ static ssize_t kernfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
on = kernfs_deref_open_node(of, of->kn);
|
of->event = atomic_read(&of_on(of)->event);
|
||||||
if (!on) {
|
|
||||||
len = -EINVAL;
|
|
||||||
mutex_unlock(&of->mutex);
|
|
||||||
goto out_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
of->event = atomic_read(&on->event);
|
|
||||||
|
|
||||||
ops = kernfs_ops(of->kn);
|
ops = kernfs_ops(of->kn);
|
||||||
if (ops->read)
|
if (ops->read)
|
||||||
|
@ -553,6 +529,7 @@ static int kernfs_fop_mmap(struct file *file, struct vm_area_struct *vma)
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
of->mmapped = true;
|
of->mmapped = true;
|
||||||
|
of_on(of)->nr_mmapped++;
|
||||||
of->vm_ops = vma->vm_ops;
|
of->vm_ops = vma->vm_ops;
|
||||||
vma->vm_ops = &kernfs_vm_ops;
|
vma->vm_ops = &kernfs_vm_ops;
|
||||||
out_put:
|
out_put:
|
||||||
|
@ -580,31 +557,30 @@ out_unlock:
|
||||||
static int kernfs_get_open_node(struct kernfs_node *kn,
|
static int kernfs_get_open_node(struct kernfs_node *kn,
|
||||||
struct kernfs_open_file *of)
|
struct kernfs_open_file *of)
|
||||||
{
|
{
|
||||||
struct kernfs_open_node *on, *new_on = NULL;
|
struct kernfs_open_node *on;
|
||||||
struct mutex *mutex = NULL;
|
struct mutex *mutex;
|
||||||
|
|
||||||
mutex = kernfs_open_file_mutex_lock(kn);
|
mutex = kernfs_open_file_mutex_lock(kn);
|
||||||
on = kernfs_deref_open_node_protected(kn);
|
on = kernfs_deref_open_node_locked(kn);
|
||||||
|
|
||||||
if (on) {
|
if (!on) {
|
||||||
list_add_tail(&of->list, &on->files);
|
|
||||||
mutex_unlock(mutex);
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
/* not there, initialize a new one */
|
/* not there, initialize a new one */
|
||||||
new_on = kmalloc(sizeof(*new_on), GFP_KERNEL);
|
on = kzalloc(sizeof(*on), GFP_KERNEL);
|
||||||
if (!new_on) {
|
if (!on) {
|
||||||
mutex_unlock(mutex);
|
mutex_unlock(mutex);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
atomic_set(&new_on->event, 1);
|
atomic_set(&on->event, 1);
|
||||||
init_waitqueue_head(&new_on->poll);
|
init_waitqueue_head(&on->poll);
|
||||||
INIT_LIST_HEAD(&new_on->files);
|
INIT_LIST_HEAD(&on->files);
|
||||||
list_add_tail(&of->list, &new_on->files);
|
rcu_assign_pointer(kn->attr.open, on);
|
||||||
rcu_assign_pointer(kn->attr.open, new_on);
|
|
||||||
}
|
}
|
||||||
mutex_unlock(mutex);
|
|
||||||
|
|
||||||
|
list_add_tail(&of->list, &on->files);
|
||||||
|
if (kn->flags & KERNFS_HAS_RELEASE)
|
||||||
|
on->nr_to_release++;
|
||||||
|
|
||||||
|
mutex_unlock(mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,6 +589,7 @@ static int kernfs_get_open_node(struct kernfs_node *kn,
|
||||||
*
|
*
|
||||||
* @kn: target kernfs_node
|
* @kn: target kernfs_node
|
||||||
* @of: associated kernfs_open_file
|
* @of: associated kernfs_open_file
|
||||||
|
* @open_failed: ->open() failed, cancel ->release()
|
||||||
*
|
*
|
||||||
* Unlink @of from list of @kn's associated open files. If list of
|
* Unlink @of from list of @kn's associated open files. If list of
|
||||||
* associated open files becomes empty, disassociate and free
|
* associated open files becomes empty, disassociate and free
|
||||||
|
@ -622,21 +599,30 @@ static int kernfs_get_open_node(struct kernfs_node *kn,
|
||||||
* None.
|
* None.
|
||||||
*/
|
*/
|
||||||
static void kernfs_unlink_open_file(struct kernfs_node *kn,
|
static void kernfs_unlink_open_file(struct kernfs_node *kn,
|
||||||
struct kernfs_open_file *of)
|
struct kernfs_open_file *of,
|
||||||
|
bool open_failed)
|
||||||
{
|
{
|
||||||
struct kernfs_open_node *on;
|
struct kernfs_open_node *on;
|
||||||
struct mutex *mutex = NULL;
|
struct mutex *mutex;
|
||||||
|
|
||||||
mutex = kernfs_open_file_mutex_lock(kn);
|
mutex = kernfs_open_file_mutex_lock(kn);
|
||||||
|
|
||||||
on = kernfs_deref_open_node_protected(kn);
|
on = kernfs_deref_open_node_locked(kn);
|
||||||
if (!on) {
|
if (!on) {
|
||||||
mutex_unlock(mutex);
|
mutex_unlock(mutex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (of)
|
if (of) {
|
||||||
|
if (kn->flags & KERNFS_HAS_RELEASE) {
|
||||||
|
WARN_ON_ONCE(of->released == open_failed);
|
||||||
|
if (open_failed)
|
||||||
|
on->nr_to_release--;
|
||||||
|
}
|
||||||
|
if (of->mmapped)
|
||||||
|
on->nr_mmapped--;
|
||||||
list_del(&of->list);
|
list_del(&of->list);
|
||||||
|
}
|
||||||
|
|
||||||
if (list_empty(&on->files)) {
|
if (list_empty(&on->files)) {
|
||||||
rcu_assign_pointer(kn->attr.open, NULL);
|
rcu_assign_pointer(kn->attr.open, NULL);
|
||||||
|
@ -763,7 +749,7 @@ static int kernfs_fop_open(struct inode *inode, struct file *file)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_put_node:
|
err_put_node:
|
||||||
kernfs_unlink_open_file(kn, of);
|
kernfs_unlink_open_file(kn, of, true);
|
||||||
err_seq_release:
|
err_seq_release:
|
||||||
seq_release(inode, file);
|
seq_release(inode, file);
|
||||||
err_free:
|
err_free:
|
||||||
|
@ -795,6 +781,7 @@ static void kernfs_release_file(struct kernfs_node *kn,
|
||||||
*/
|
*/
|
||||||
kn->attr.ops->release(of);
|
kn->attr.ops->release(of);
|
||||||
of->released = true;
|
of->released = true;
|
||||||
|
of_on(of)->nr_to_release--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -802,15 +789,16 @@ static int kernfs_fop_release(struct inode *inode, struct file *filp)
|
||||||
{
|
{
|
||||||
struct kernfs_node *kn = inode->i_private;
|
struct kernfs_node *kn = inode->i_private;
|
||||||
struct kernfs_open_file *of = kernfs_of(filp);
|
struct kernfs_open_file *of = kernfs_of(filp);
|
||||||
struct mutex *mutex = NULL;
|
|
||||||
|
|
||||||
if (kn->flags & KERNFS_HAS_RELEASE) {
|
if (kn->flags & KERNFS_HAS_RELEASE) {
|
||||||
|
struct mutex *mutex;
|
||||||
|
|
||||||
mutex = kernfs_open_file_mutex_lock(kn);
|
mutex = kernfs_open_file_mutex_lock(kn);
|
||||||
kernfs_release_file(kn, of);
|
kernfs_release_file(kn, of);
|
||||||
mutex_unlock(mutex);
|
mutex_unlock(mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
kernfs_unlink_open_file(kn, of);
|
kernfs_unlink_open_file(kn, of, false);
|
||||||
seq_release(inode, filp);
|
seq_release(inode, filp);
|
||||||
kfree(of->prealloc_buf);
|
kfree(of->prealloc_buf);
|
||||||
kfree(of);
|
kfree(of);
|
||||||
|
@ -818,28 +806,33 @@ static int kernfs_fop_release(struct inode *inode, struct file *filp)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool kernfs_should_drain_open_files(struct kernfs_node *kn)
|
||||||
|
{
|
||||||
|
struct kernfs_open_node *on;
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @kn being deactivated guarantees that @kn->attr.open can't change
|
||||||
|
* beneath us making the lockless test below safe.
|
||||||
|
*/
|
||||||
|
WARN_ON_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
on = rcu_dereference(kn->attr.open);
|
||||||
|
ret = on && (on->nr_mmapped || on->nr_to_release);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void kernfs_drain_open_files(struct kernfs_node *kn)
|
void kernfs_drain_open_files(struct kernfs_node *kn)
|
||||||
{
|
{
|
||||||
struct kernfs_open_node *on;
|
struct kernfs_open_node *on;
|
||||||
struct kernfs_open_file *of;
|
struct kernfs_open_file *of;
|
||||||
struct mutex *mutex = NULL;
|
struct mutex *mutex;
|
||||||
|
|
||||||
if (!(kn->flags & (KERNFS_HAS_MMAP | KERNFS_HAS_RELEASE)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* lockless opportunistic check is safe below because no one is adding to
|
|
||||||
* ->attr.open at this point of time. This check allows early bail out
|
|
||||||
* if ->attr.open is already NULL. kernfs_unlink_open_file makes
|
|
||||||
* ->attr.open NULL only while holding kernfs_open_file_mutex so below
|
|
||||||
* check under kernfs_open_file_mutex_ptr(kn) will ensure bailing out if
|
|
||||||
* ->attr.open became NULL while waiting for the mutex.
|
|
||||||
*/
|
|
||||||
if (!rcu_access_pointer(kn->attr.open))
|
|
||||||
return;
|
|
||||||
|
|
||||||
mutex = kernfs_open_file_mutex_lock(kn);
|
mutex = kernfs_open_file_mutex_lock(kn);
|
||||||
on = kernfs_deref_open_node_protected(kn);
|
on = kernfs_deref_open_node_locked(kn);
|
||||||
if (!on) {
|
if (!on) {
|
||||||
mutex_unlock(mutex);
|
mutex_unlock(mutex);
|
||||||
return;
|
return;
|
||||||
|
@ -848,13 +841,17 @@ void kernfs_drain_open_files(struct kernfs_node *kn)
|
||||||
list_for_each_entry(of, &on->files, list) {
|
list_for_each_entry(of, &on->files, list) {
|
||||||
struct inode *inode = file_inode(of->file);
|
struct inode *inode = file_inode(of->file);
|
||||||
|
|
||||||
if (kn->flags & KERNFS_HAS_MMAP)
|
if (of->mmapped) {
|
||||||
unmap_mapping_range(inode->i_mapping, 0, 0, 1);
|
unmap_mapping_range(inode->i_mapping, 0, 0, 1);
|
||||||
|
of->mmapped = false;
|
||||||
|
on->nr_mmapped--;
|
||||||
|
}
|
||||||
|
|
||||||
if (kn->flags & KERNFS_HAS_RELEASE)
|
if (kn->flags & KERNFS_HAS_RELEASE)
|
||||||
kernfs_release_file(kn, of);
|
kernfs_release_file(kn, of);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WARN_ON_ONCE(on->nr_mmapped || on->nr_to_release);
|
||||||
mutex_unlock(mutex);
|
mutex_unlock(mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -874,11 +871,7 @@ void kernfs_drain_open_files(struct kernfs_node *kn)
|
||||||
*/
|
*/
|
||||||
__poll_t kernfs_generic_poll(struct kernfs_open_file *of, poll_table *wait)
|
__poll_t kernfs_generic_poll(struct kernfs_open_file *of, poll_table *wait)
|
||||||
{
|
{
|
||||||
struct kernfs_node *kn = kernfs_dentry_node(of->file->f_path.dentry);
|
struct kernfs_open_node *on = of_on(of);
|
||||||
struct kernfs_open_node *on = kernfs_deref_open_node(of, kn);
|
|
||||||
|
|
||||||
if (!on)
|
|
||||||
return EPOLLERR;
|
|
||||||
|
|
||||||
poll_wait(of->file, &on->poll, wait);
|
poll_wait(of->file, &on->poll, wait);
|
||||||
|
|
||||||
|
|
|
@ -157,6 +157,7 @@ struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
|
||||||
*/
|
*/
|
||||||
extern const struct file_operations kernfs_file_fops;
|
extern const struct file_operations kernfs_file_fops;
|
||||||
|
|
||||||
|
bool kernfs_should_drain_open_files(struct kernfs_node *kn);
|
||||||
void kernfs_drain_open_files(struct kernfs_node *kn);
|
void kernfs_drain_open_files(struct kernfs_node *kn);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -353,6 +353,9 @@
|
||||||
*(__tracepoints) \
|
*(__tracepoints) \
|
||||||
/* implement dynamic printk debug */ \
|
/* implement dynamic printk debug */ \
|
||||||
. = ALIGN(8); \
|
. = ALIGN(8); \
|
||||||
|
__start___dyndbg_classes = .; \
|
||||||
|
KEEP(*(__dyndbg_classes)) \
|
||||||
|
__stop___dyndbg_classes = .; \
|
||||||
__start___dyndbg = .; \
|
__start___dyndbg = .; \
|
||||||
KEEP(*(__dyndbg)) \
|
KEEP(*(__dyndbg)) \
|
||||||
__stop___dyndbg = .; \
|
__stop___dyndbg = .; \
|
||||||
|
|
|
@ -31,11 +31,12 @@
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
|
#include <linux/dynamic_debug.h>
|
||||||
|
|
||||||
#include <drm/drm.h>
|
#include <drm/drm.h>
|
||||||
|
|
||||||
/* Do *not* use outside of drm_print.[ch]! */
|
/* Do *not* use outside of drm_print.[ch]! */
|
||||||
extern unsigned int __drm_debug;
|
extern unsigned long __drm_debug;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOC: print
|
* DOC: print
|
||||||
|
@ -275,55 +276,75 @@ static inline struct drm_printer drm_err_printer(const char *prefix)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
enum drm_debug_category {
|
enum drm_debug_category {
|
||||||
|
/* These names must match those in DYNAMIC_DEBUG_CLASSBITS */
|
||||||
/**
|
/**
|
||||||
* @DRM_UT_CORE: Used in the generic drm code: drm_ioctl.c, drm_mm.c,
|
* @DRM_UT_CORE: Used in the generic drm code: drm_ioctl.c, drm_mm.c,
|
||||||
* drm_memory.c, ...
|
* drm_memory.c, ...
|
||||||
*/
|
*/
|
||||||
DRM_UT_CORE = 0x01,
|
DRM_UT_CORE,
|
||||||
/**
|
/**
|
||||||
* @DRM_UT_DRIVER: Used in the vendor specific part of the driver: i915,
|
* @DRM_UT_DRIVER: Used in the vendor specific part of the driver: i915,
|
||||||
* radeon, ... macro.
|
* radeon, ... macro.
|
||||||
*/
|
*/
|
||||||
DRM_UT_DRIVER = 0x02,
|
DRM_UT_DRIVER,
|
||||||
/**
|
/**
|
||||||
* @DRM_UT_KMS: Used in the modesetting code.
|
* @DRM_UT_KMS: Used in the modesetting code.
|
||||||
*/
|
*/
|
||||||
DRM_UT_KMS = 0x04,
|
DRM_UT_KMS,
|
||||||
/**
|
/**
|
||||||
* @DRM_UT_PRIME: Used in the prime code.
|
* @DRM_UT_PRIME: Used in the prime code.
|
||||||
*/
|
*/
|
||||||
DRM_UT_PRIME = 0x08,
|
DRM_UT_PRIME,
|
||||||
/**
|
/**
|
||||||
* @DRM_UT_ATOMIC: Used in the atomic code.
|
* @DRM_UT_ATOMIC: Used in the atomic code.
|
||||||
*/
|
*/
|
||||||
DRM_UT_ATOMIC = 0x10,
|
DRM_UT_ATOMIC,
|
||||||
/**
|
/**
|
||||||
* @DRM_UT_VBL: Used for verbose debug message in the vblank code.
|
* @DRM_UT_VBL: Used for verbose debug message in the vblank code.
|
||||||
*/
|
*/
|
||||||
DRM_UT_VBL = 0x20,
|
DRM_UT_VBL,
|
||||||
/**
|
/**
|
||||||
* @DRM_UT_STATE: Used for verbose atomic state debugging.
|
* @DRM_UT_STATE: Used for verbose atomic state debugging.
|
||||||
*/
|
*/
|
||||||
DRM_UT_STATE = 0x40,
|
DRM_UT_STATE,
|
||||||
/**
|
/**
|
||||||
* @DRM_UT_LEASE: Used in the lease code.
|
* @DRM_UT_LEASE: Used in the lease code.
|
||||||
*/
|
*/
|
||||||
DRM_UT_LEASE = 0x80,
|
DRM_UT_LEASE,
|
||||||
/**
|
/**
|
||||||
* @DRM_UT_DP: Used in the DP code.
|
* @DRM_UT_DP: Used in the DP code.
|
||||||
*/
|
*/
|
||||||
DRM_UT_DP = 0x100,
|
DRM_UT_DP,
|
||||||
/**
|
/**
|
||||||
* @DRM_UT_DRMRES: Used in the drm managed resources code.
|
* @DRM_UT_DRMRES: Used in the drm managed resources code.
|
||||||
*/
|
*/
|
||||||
DRM_UT_DRMRES = 0x200,
|
DRM_UT_DRMRES
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool drm_debug_enabled(enum drm_debug_category category)
|
static inline bool drm_debug_enabled_raw(enum drm_debug_category category)
|
||||||
{
|
{
|
||||||
return unlikely(__drm_debug & category);
|
return unlikely(__drm_debug & BIT(category));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define drm_debug_enabled_instrumented(category) \
|
||||||
|
({ \
|
||||||
|
pr_debug("todo: is this frequent enough to optimize ?\n"); \
|
||||||
|
drm_debug_enabled_raw(category); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#if defined(CONFIG_DRM_USE_DYNAMIC_DEBUG)
|
||||||
|
/*
|
||||||
|
* the drm.debug API uses dyndbg, so each drm_*dbg macro/callsite gets
|
||||||
|
* a descriptor, and only enabled callsites are reachable. They use
|
||||||
|
* the private macro to avoid re-testing the enable-bit.
|
||||||
|
*/
|
||||||
|
#define __drm_debug_enabled(category) true
|
||||||
|
#define drm_debug_enabled(category) drm_debug_enabled_instrumented(category)
|
||||||
|
#else
|
||||||
|
#define __drm_debug_enabled(category) drm_debug_enabled_raw(category)
|
||||||
|
#define drm_debug_enabled(category) drm_debug_enabled_raw(category)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* struct device based logging
|
* struct device based logging
|
||||||
*
|
*
|
||||||
|
@ -333,9 +354,10 @@ static inline bool drm_debug_enabled(enum drm_debug_category category)
|
||||||
__printf(3, 4)
|
__printf(3, 4)
|
||||||
void drm_dev_printk(const struct device *dev, const char *level,
|
void drm_dev_printk(const struct device *dev, const char *level,
|
||||||
const char *format, ...);
|
const char *format, ...);
|
||||||
__printf(3, 4)
|
struct _ddebug;
|
||||||
void drm_dev_dbg(const struct device *dev, enum drm_debug_category category,
|
__printf(4, 5)
|
||||||
const char *format, ...);
|
void __drm_dev_dbg(struct _ddebug *desc, const struct device *dev,
|
||||||
|
enum drm_debug_category category, const char *format, ...);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DRM_DEV_ERROR() - Error output.
|
* DRM_DEV_ERROR() - Error output.
|
||||||
|
@ -383,6 +405,15 @@ void drm_dev_dbg(const struct device *dev, enum drm_debug_category category,
|
||||||
} \
|
} \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
#if !defined(CONFIG_DRM_USE_DYNAMIC_DEBUG)
|
||||||
|
#define drm_dev_dbg(dev, cat, fmt, ...) \
|
||||||
|
__drm_dev_dbg(NULL, dev, cat, fmt, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define drm_dev_dbg(dev, cat, fmt, ...) \
|
||||||
|
_dynamic_func_call_cls(cat, fmt, __drm_dev_dbg, \
|
||||||
|
dev, cat, fmt, ##__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DRM_DEV_DEBUG() - Debug output for generic drm code
|
* DRM_DEV_DEBUG() - Debug output for generic drm code
|
||||||
*
|
*
|
||||||
|
@ -457,7 +488,7 @@ void drm_dev_dbg(const struct device *dev, enum drm_debug_category category,
|
||||||
|
|
||||||
#define drm_dbg_core(drm, fmt, ...) \
|
#define drm_dbg_core(drm, fmt, ...) \
|
||||||
drm_dev_dbg((drm) ? (drm)->dev : NULL, DRM_UT_CORE, fmt, ##__VA_ARGS__)
|
drm_dev_dbg((drm) ? (drm)->dev : NULL, DRM_UT_CORE, fmt, ##__VA_ARGS__)
|
||||||
#define drm_dbg(drm, fmt, ...) \
|
#define drm_dbg_driver(drm, fmt, ...) \
|
||||||
drm_dev_dbg((drm) ? (drm)->dev : NULL, DRM_UT_DRIVER, fmt, ##__VA_ARGS__)
|
drm_dev_dbg((drm) ? (drm)->dev : NULL, DRM_UT_DRIVER, fmt, ##__VA_ARGS__)
|
||||||
#define drm_dbg_kms(drm, fmt, ...) \
|
#define drm_dbg_kms(drm, fmt, ...) \
|
||||||
drm_dev_dbg((drm) ? (drm)->dev : NULL, DRM_UT_KMS, fmt, ##__VA_ARGS__)
|
drm_dev_dbg((drm) ? (drm)->dev : NULL, DRM_UT_KMS, fmt, ##__VA_ARGS__)
|
||||||
|
@ -476,6 +507,7 @@ void drm_dev_dbg(const struct device *dev, enum drm_debug_category category,
|
||||||
#define drm_dbg_drmres(drm, fmt, ...) \
|
#define drm_dbg_drmres(drm, fmt, ...) \
|
||||||
drm_dev_dbg((drm) ? (drm)->dev : NULL, DRM_UT_DRMRES, fmt, ##__VA_ARGS__)
|
drm_dev_dbg((drm) ? (drm)->dev : NULL, DRM_UT_DRMRES, fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define drm_dbg(drm, fmt, ...) drm_dbg_driver(drm, fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* printk based logging
|
* printk based logging
|
||||||
|
@ -483,11 +515,19 @@ void drm_dev_dbg(const struct device *dev, enum drm_debug_category category,
|
||||||
* Prefer drm_device based logging over device or prink based logging.
|
* Prefer drm_device based logging over device or prink based logging.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
__printf(2, 3)
|
__printf(3, 4)
|
||||||
void __drm_dbg(enum drm_debug_category category, const char *format, ...);
|
void ___drm_dbg(struct _ddebug *desc, enum drm_debug_category category, const char *format, ...);
|
||||||
__printf(1, 2)
|
__printf(1, 2)
|
||||||
void __drm_err(const char *format, ...);
|
void __drm_err(const char *format, ...);
|
||||||
|
|
||||||
|
#if !defined(CONFIG_DRM_USE_DYNAMIC_DEBUG)
|
||||||
|
#define __drm_dbg(fmt, ...) ___drm_dbg(NULL, fmt, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define __drm_dbg(cat, fmt, ...) \
|
||||||
|
_dynamic_func_call_cls(cat, fmt, ___drm_dbg, \
|
||||||
|
cat, fmt, ##__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Macros to make printk easier */
|
/* Macros to make printk easier */
|
||||||
|
|
||||||
#define _DRM_PRINTK(once, level, fmt, ...) \
|
#define _DRM_PRINTK(once, level, fmt, ...) \
|
||||||
|
|
|
@ -114,6 +114,7 @@ int cgroup_add_dfl_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
|
||||||
int cgroup_add_legacy_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
|
int cgroup_add_legacy_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
|
||||||
int cgroup_rm_cftypes(struct cftype *cfts);
|
int cgroup_rm_cftypes(struct cftype *cfts);
|
||||||
void cgroup_file_notify(struct cgroup_file *cfile);
|
void cgroup_file_notify(struct cgroup_file *cfile);
|
||||||
|
void cgroup_file_show(struct cgroup_file *cfile, bool show);
|
||||||
|
|
||||||
int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen);
|
int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen);
|
||||||
int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry);
|
int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry);
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include <linux/jump_label.h>
|
#include <linux/jump_label.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <linux/build_bug.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* An instance of this structure is created in a special
|
* An instance of this structure is created in a special
|
||||||
* ELF section at every dynamic debug callsite. At runtime,
|
* ELF section at every dynamic debug callsite. At runtime,
|
||||||
|
@ -21,6 +23,9 @@ struct _ddebug {
|
||||||
const char *filename;
|
const char *filename;
|
||||||
const char *format;
|
const char *format;
|
||||||
unsigned int lineno:18;
|
unsigned int lineno:18;
|
||||||
|
#define CLS_BITS 6
|
||||||
|
unsigned int class_id:CLS_BITS;
|
||||||
|
#define _DPRINTK_CLASS_DFLT ((1 << CLS_BITS) - 1)
|
||||||
/*
|
/*
|
||||||
* The flags field controls the behaviour at the callsite.
|
* The flags field controls the behaviour at the callsite.
|
||||||
* The bits here are changed dynamically when the user
|
* The bits here are changed dynamically when the user
|
||||||
|
@ -51,15 +56,82 @@ struct _ddebug {
|
||||||
#endif
|
#endif
|
||||||
} __attribute__((aligned(8)));
|
} __attribute__((aligned(8)));
|
||||||
|
|
||||||
|
enum class_map_type {
|
||||||
|
DD_CLASS_TYPE_DISJOINT_BITS,
|
||||||
|
/**
|
||||||
|
* DD_CLASS_TYPE_DISJOINT_BITS: classes are independent, one per bit.
|
||||||
|
* expecting hex input. Built for drm.debug, basis for other types.
|
||||||
|
*/
|
||||||
|
DD_CLASS_TYPE_LEVEL_NUM,
|
||||||
|
/**
|
||||||
|
* DD_CLASS_TYPE_LEVEL_NUM: input is numeric level, 0-N.
|
||||||
|
* N turns on just bits N-1 .. 0, so N=0 turns all bits off.
|
||||||
|
*/
|
||||||
|
DD_CLASS_TYPE_DISJOINT_NAMES,
|
||||||
|
/**
|
||||||
|
* DD_CLASS_TYPE_DISJOINT_NAMES: input is a CSV of [+-]CLASS_NAMES,
|
||||||
|
* classes are independent, like _DISJOINT_BITS.
|
||||||
|
*/
|
||||||
|
DD_CLASS_TYPE_LEVEL_NAMES,
|
||||||
|
/**
|
||||||
|
* DD_CLASS_TYPE_LEVEL_NAMES: input is a CSV of [+-]CLASS_NAMES,
|
||||||
|
* intended for names like: INFO,DEBUG,TRACE, with a module prefix
|
||||||
|
* avoid EMERG,ALERT,CRIT,ERR,WARNING: they're not debug
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ddebug_class_map {
|
||||||
|
struct list_head link;
|
||||||
|
struct module *mod;
|
||||||
|
const char *mod_name; /* needed for builtins */
|
||||||
|
const char **class_names;
|
||||||
|
const int length;
|
||||||
|
const int base; /* index of 1st .class_id, allows split/shared space */
|
||||||
|
enum class_map_type map_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DECLARE_DYNDBG_CLASSMAP - declare classnames known by a module
|
||||||
|
* @_var: a struct ddebug_class_map, passed to module_param_cb
|
||||||
|
* @_type: enum class_map_type, chooses bits/verbose, numeric/symbolic
|
||||||
|
* @_base: offset of 1st class-name. splits .class_id space
|
||||||
|
* @classes: class-names used to control class'd prdbgs
|
||||||
|
*/
|
||||||
|
#define DECLARE_DYNDBG_CLASSMAP(_var, _maptype, _base, ...) \
|
||||||
|
static const char *_var##_classnames[] = { __VA_ARGS__ }; \
|
||||||
|
static struct ddebug_class_map __aligned(8) __used \
|
||||||
|
__section("__dyndbg_classes") _var = { \
|
||||||
|
.mod = THIS_MODULE, \
|
||||||
|
.mod_name = KBUILD_MODNAME, \
|
||||||
|
.base = _base, \
|
||||||
|
.map_type = _maptype, \
|
||||||
|
.length = NUM_TYPE_ARGS(char*, __VA_ARGS__), \
|
||||||
|
.class_names = _var##_classnames, \
|
||||||
|
}
|
||||||
|
#define NUM_TYPE_ARGS(eltype, ...) \
|
||||||
|
(sizeof((eltype[]){__VA_ARGS__}) / sizeof(eltype))
|
||||||
|
|
||||||
|
/* encapsulate linker provided built-in (or module) dyndbg data */
|
||||||
|
struct _ddebug_info {
|
||||||
|
struct _ddebug *descs;
|
||||||
|
struct ddebug_class_map *classes;
|
||||||
|
unsigned int num_descs;
|
||||||
|
unsigned int num_classes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ddebug_class_param {
|
||||||
|
union {
|
||||||
|
unsigned long *bits;
|
||||||
|
unsigned int *lvl;
|
||||||
|
};
|
||||||
|
char flags[8];
|
||||||
|
const struct ddebug_class_map *map;
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(CONFIG_DYNAMIC_DEBUG_CORE)
|
#if defined(CONFIG_DYNAMIC_DEBUG_CORE)
|
||||||
|
|
||||||
/* exported for module authors to exercise >control */
|
int ddebug_add_module(struct _ddebug_info *dyndbg, const char *modname);
|
||||||
int dynamic_debug_exec_queries(const char *query, const char *modname);
|
|
||||||
|
|
||||||
int ddebug_add_module(struct _ddebug *tab, unsigned int n,
|
|
||||||
const char *modname);
|
|
||||||
extern int ddebug_remove_module(const char *mod_name);
|
extern int ddebug_remove_module(const char *mod_name);
|
||||||
extern __printf(2, 3)
|
extern __printf(2, 3)
|
||||||
void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
|
void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
|
||||||
|
@ -87,7 +159,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
|
||||||
const struct ib_device *ibdev,
|
const struct ib_device *ibdev,
|
||||||
const char *fmt, ...);
|
const char *fmt, ...);
|
||||||
|
|
||||||
#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) \
|
#define DEFINE_DYNAMIC_DEBUG_METADATA_CLS(name, cls, fmt) \
|
||||||
static struct _ddebug __aligned(8) \
|
static struct _ddebug __aligned(8) \
|
||||||
__section("__dyndbg") name = { \
|
__section("__dyndbg") name = { \
|
||||||
.modname = KBUILD_MODNAME, \
|
.modname = KBUILD_MODNAME, \
|
||||||
|
@ -96,8 +168,14 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
|
||||||
.format = (fmt), \
|
.format = (fmt), \
|
||||||
.lineno = __LINE__, \
|
.lineno = __LINE__, \
|
||||||
.flags = _DPRINTK_FLAGS_DEFAULT, \
|
.flags = _DPRINTK_FLAGS_DEFAULT, \
|
||||||
|
.class_id = cls, \
|
||||||
_DPRINTK_KEY_INIT \
|
_DPRINTK_KEY_INIT \
|
||||||
}
|
}; \
|
||||||
|
BUILD_BUG_ON_MSG(cls > _DPRINTK_CLASS_DFLT, \
|
||||||
|
"classid value overflow")
|
||||||
|
|
||||||
|
#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) \
|
||||||
|
DEFINE_DYNAMIC_DEBUG_METADATA_CLS(name, _DPRINTK_CLASS_DFLT, fmt)
|
||||||
|
|
||||||
#ifdef CONFIG_JUMP_LABEL
|
#ifdef CONFIG_JUMP_LABEL
|
||||||
|
|
||||||
|
@ -128,17 +206,34 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
|
||||||
|
|
||||||
#endif /* CONFIG_JUMP_LABEL */
|
#endif /* CONFIG_JUMP_LABEL */
|
||||||
|
|
||||||
#define __dynamic_func_call(id, fmt, func, ...) do { \
|
/*
|
||||||
DEFINE_DYNAMIC_DEBUG_METADATA(id, fmt); \
|
* Factory macros: ($prefix)dynamic_func_call($suffix)
|
||||||
if (DYNAMIC_DEBUG_BRANCH(id)) \
|
*
|
||||||
func(&id, ##__VA_ARGS__); \
|
* Lower layer (with __ prefix) gets the callsite metadata, and wraps
|
||||||
} while (0)
|
* the func inside a debug-branch/static-key construct. Upper layer
|
||||||
|
* (with _ prefix) does the UNIQUE_ID once, so that lower can ref the
|
||||||
#define __dynamic_func_call_no_desc(id, fmt, func, ...) do { \
|
* name/label multiple times, and tie the elements together.
|
||||||
DEFINE_DYNAMIC_DEBUG_METADATA(id, fmt); \
|
* Multiple flavors:
|
||||||
|
* (|_cls): adds in _DPRINT_CLASS_DFLT as needed
|
||||||
|
* (|_no_desc): former gets callsite descriptor as 1st arg (for prdbgs)
|
||||||
|
*/
|
||||||
|
#define __dynamic_func_call_cls(id, cls, fmt, func, ...) do { \
|
||||||
|
DEFINE_DYNAMIC_DEBUG_METADATA_CLS(id, cls, fmt); \
|
||||||
if (DYNAMIC_DEBUG_BRANCH(id)) \
|
if (DYNAMIC_DEBUG_BRANCH(id)) \
|
||||||
func(__VA_ARGS__); \
|
func(&id, ##__VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
#define __dynamic_func_call(id, fmt, func, ...) \
|
||||||
|
__dynamic_func_call_cls(id, _DPRINTK_CLASS_DFLT, fmt, \
|
||||||
|
func, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define __dynamic_func_call_cls_no_desc(id, cls, fmt, func, ...) do { \
|
||||||
|
DEFINE_DYNAMIC_DEBUG_METADATA_CLS(id, cls, fmt); \
|
||||||
|
if (DYNAMIC_DEBUG_BRANCH(id)) \
|
||||||
|
func(__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#define __dynamic_func_call_no_desc(id, fmt, func, ...) \
|
||||||
|
__dynamic_func_call_cls_no_desc(id, _DPRINTK_CLASS_DFLT, \
|
||||||
|
fmt, func, ##__VA_ARGS__)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "Factory macro" for generating a call to func, guarded by a
|
* "Factory macro" for generating a call to func, guarded by a
|
||||||
|
@ -148,22 +243,33 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
|
||||||
* the varargs. Note that fmt is repeated in invocations of this
|
* the varargs. Note that fmt is repeated in invocations of this
|
||||||
* macro.
|
* macro.
|
||||||
*/
|
*/
|
||||||
|
#define _dynamic_func_call_cls(cls, fmt, func, ...) \
|
||||||
|
__dynamic_func_call_cls(__UNIQUE_ID(ddebug), cls, fmt, func, ##__VA_ARGS__)
|
||||||
#define _dynamic_func_call(fmt, func, ...) \
|
#define _dynamic_func_call(fmt, func, ...) \
|
||||||
__dynamic_func_call(__UNIQUE_ID(ddebug), fmt, func, ##__VA_ARGS__)
|
_dynamic_func_call_cls(_DPRINTK_CLASS_DFLT, fmt, func, ##__VA_ARGS__)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A variant that does the same, except that the descriptor is not
|
* A variant that does the same, except that the descriptor is not
|
||||||
* passed as the first argument to the function; it is only called
|
* passed as the first argument to the function; it is only called
|
||||||
* with precisely the macro's varargs.
|
* with precisely the macro's varargs.
|
||||||
*/
|
*/
|
||||||
#define _dynamic_func_call_no_desc(fmt, func, ...) \
|
#define _dynamic_func_call_cls_no_desc(cls, fmt, func, ...) \
|
||||||
__dynamic_func_call_no_desc(__UNIQUE_ID(ddebug), fmt, func, ##__VA_ARGS__)
|
__dynamic_func_call_cls_no_desc(__UNIQUE_ID(ddebug), cls, fmt, \
|
||||||
|
func, ##__VA_ARGS__)
|
||||||
|
#define _dynamic_func_call_no_desc(fmt, func, ...) \
|
||||||
|
_dynamic_func_call_cls_no_desc(_DPRINTK_CLASS_DFLT, fmt, \
|
||||||
|
func, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define dynamic_pr_debug_cls(cls, fmt, ...) \
|
||||||
|
_dynamic_func_call_cls(cls, fmt, __dynamic_pr_debug, \
|
||||||
|
pr_fmt(fmt), ##__VA_ARGS__)
|
||||||
|
|
||||||
#define dynamic_pr_debug(fmt, ...) \
|
#define dynamic_pr_debug(fmt, ...) \
|
||||||
_dynamic_func_call(fmt, __dynamic_pr_debug, \
|
_dynamic_func_call(fmt, __dynamic_pr_debug, \
|
||||||
pr_fmt(fmt), ##__VA_ARGS__)
|
pr_fmt(fmt), ##__VA_ARGS__)
|
||||||
|
|
||||||
#define dynamic_dev_dbg(dev, fmt, ...) \
|
#define dynamic_dev_dbg(dev, fmt, ...) \
|
||||||
_dynamic_func_call(fmt,__dynamic_dev_dbg, \
|
_dynamic_func_call(fmt, __dynamic_dev_dbg, \
|
||||||
dev, fmt, ##__VA_ARGS__)
|
dev, fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
#define dynamic_netdev_dbg(dev, fmt, ...) \
|
#define dynamic_netdev_dbg(dev, fmt, ...) \
|
||||||
|
@ -181,14 +287,24 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
|
||||||
KERN_DEBUG, prefix_str, prefix_type, \
|
KERN_DEBUG, prefix_str, prefix_type, \
|
||||||
rowsize, groupsize, buf, len, ascii)
|
rowsize, groupsize, buf, len, ascii)
|
||||||
|
|
||||||
|
struct kernel_param;
|
||||||
|
int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp);
|
||||||
|
int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp);
|
||||||
|
|
||||||
|
/* for test only, generally expect drm.debug style macro wrappers */
|
||||||
|
#define __pr_debug_cls(cls, fmt, ...) do { \
|
||||||
|
BUILD_BUG_ON_MSG(!__builtin_constant_p(cls), \
|
||||||
|
"expecting constant class int/enum"); \
|
||||||
|
dynamic_pr_debug_cls(cls, fmt, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#else /* !CONFIG_DYNAMIC_DEBUG_CORE */
|
#else /* !CONFIG_DYNAMIC_DEBUG_CORE */
|
||||||
|
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/printk.h>
|
#include <linux/printk.h>
|
||||||
|
|
||||||
static inline int ddebug_add_module(struct _ddebug *tab, unsigned int n,
|
static inline int ddebug_add_module(struct _ddebug_info *dinfo, const char *modname)
|
||||||
const char *modname)
|
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -201,7 +317,7 @@ static inline int ddebug_remove_module(const char *mod)
|
||||||
static inline int ddebug_dyndbg_module_param_cb(char *param, char *val,
|
static inline int ddebug_dyndbg_module_param_cb(char *param, char *val,
|
||||||
const char *modname)
|
const char *modname)
|
||||||
{
|
{
|
||||||
if (strstr(param, "dyndbg")) {
|
if (!strcmp(param, "dyndbg")) {
|
||||||
/* avoid pr_warn(), which wants pr_fmt() fully defined */
|
/* avoid pr_warn(), which wants pr_fmt() fully defined */
|
||||||
printk(KERN_WARNING "dyndbg param is supported only in "
|
printk(KERN_WARNING "dyndbg param is supported only in "
|
||||||
"CONFIG_DYNAMIC_DEBUG builds\n");
|
"CONFIG_DYNAMIC_DEBUG builds\n");
|
||||||
|
@ -221,12 +337,14 @@ static inline int ddebug_dyndbg_module_param_cb(char *param, char *val,
|
||||||
rowsize, groupsize, buf, len, ascii); \
|
rowsize, groupsize, buf, len, ascii); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static inline int dynamic_debug_exec_queries(const char *query, const char *modname)
|
struct kernel_param;
|
||||||
{
|
static inline int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
|
||||||
pr_warn("kernel not built with CONFIG_DYNAMIC_DEBUG_CORE\n");
|
{ return 0; }
|
||||||
return 0;
|
static inline int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
|
||||||
}
|
{ return 0; }
|
||||||
|
|
||||||
#endif /* !CONFIG_DYNAMIC_DEBUG_CORE */
|
#endif /* !CONFIG_DYNAMIC_DEBUG_CORE */
|
||||||
|
|
||||||
|
extern const struct kernel_param_ops param_ops_dyndbg_classes;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -59,8 +59,6 @@ void __iomem *devm_ioremap_uc(struct device *dev, resource_size_t offset,
|
||||||
resource_size_t size);
|
resource_size_t size);
|
||||||
void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset,
|
void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset,
|
||||||
resource_size_t size);
|
resource_size_t size);
|
||||||
void __iomem *devm_ioremap_np(struct device *dev, resource_size_t offset,
|
|
||||||
resource_size_t size);
|
|
||||||
void devm_iounmap(struct device *dev, void __iomem *addr);
|
void devm_iounmap(struct device *dev, void __iomem *addr);
|
||||||
int check_signature(const volatile void __iomem *io_addr,
|
int check_signature(const volatile void __iomem *io_addr,
|
||||||
const unsigned char *signature, int length);
|
const unsigned char *signature, int length);
|
||||||
|
|
|
@ -108,10 +108,12 @@ enum kernfs_node_flag {
|
||||||
KERNFS_HAS_SEQ_SHOW = 0x0040,
|
KERNFS_HAS_SEQ_SHOW = 0x0040,
|
||||||
KERNFS_HAS_MMAP = 0x0080,
|
KERNFS_HAS_MMAP = 0x0080,
|
||||||
KERNFS_LOCKDEP = 0x0100,
|
KERNFS_LOCKDEP = 0x0100,
|
||||||
|
KERNFS_HIDDEN = 0x0200,
|
||||||
KERNFS_SUICIDAL = 0x0400,
|
KERNFS_SUICIDAL = 0x0400,
|
||||||
KERNFS_SUICIDED = 0x0800,
|
KERNFS_SUICIDED = 0x0800,
|
||||||
KERNFS_EMPTY_DIR = 0x1000,
|
KERNFS_EMPTY_DIR = 0x1000,
|
||||||
KERNFS_HAS_RELEASE = 0x2000,
|
KERNFS_HAS_RELEASE = 0x2000,
|
||||||
|
KERNFS_REMOVING = 0x4000,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* @flags for kernfs_create_root() */
|
/* @flags for kernfs_create_root() */
|
||||||
|
@ -429,6 +431,7 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
|
||||||
const char *name,
|
const char *name,
|
||||||
struct kernfs_node *target);
|
struct kernfs_node *target);
|
||||||
void kernfs_activate(struct kernfs_node *kn);
|
void kernfs_activate(struct kernfs_node *kn);
|
||||||
|
void kernfs_show(struct kernfs_node *kn, bool show);
|
||||||
void kernfs_remove(struct kernfs_node *kn);
|
void kernfs_remove(struct kernfs_node *kn);
|
||||||
void kernfs_break_active_protection(struct kernfs_node *kn);
|
void kernfs_break_active_protection(struct kernfs_node *kn);
|
||||||
void kernfs_unbreak_active_protection(struct kernfs_node *kn);
|
void kernfs_unbreak_active_protection(struct kernfs_node *kn);
|
||||||
|
|
|
@ -32,7 +32,7 @@ enum dev_dma_attr {
|
||||||
DEV_DMA_COHERENT,
|
DEV_DMA_COHERENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fwnode_handle *dev_fwnode(struct device *dev);
|
struct fwnode_handle *dev_fwnode(const struct device *dev);
|
||||||
|
|
||||||
bool device_property_present(struct device *dev, const char *propname);
|
bool device_property_present(struct device *dev, const char *propname);
|
||||||
int device_property_read_u8_array(struct device *dev, const char *propname,
|
int device_property_read_u8_array(struct device *dev, const char *propname,
|
||||||
|
@ -387,7 +387,7 @@ bool device_dma_supported(struct device *dev);
|
||||||
|
|
||||||
enum dev_dma_attr device_get_dma_attr(struct device *dev);
|
enum dev_dma_attr device_get_dma_attr(struct device *dev);
|
||||||
|
|
||||||
const void *device_get_match_data(struct device *dev);
|
const void *device_get_match_data(const struct device *dev);
|
||||||
|
|
||||||
int device_get_phy_mode(struct device *dev);
|
int device_get_phy_mode(struct device *dev);
|
||||||
int fwnode_get_phy_mode(struct fwnode_handle *fwnode);
|
int fwnode_get_phy_mode(struct fwnode_handle *fwnode);
|
||||||
|
|
|
@ -4371,6 +4371,26 @@ void cgroup_file_notify(struct cgroup_file *cfile)
|
||||||
spin_unlock_irqrestore(&cgroup_file_kn_lock, flags);
|
spin_unlock_irqrestore(&cgroup_file_kn_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cgroup_file_show - show or hide a hidden cgroup file
|
||||||
|
* @cfile: target cgroup_file obtained by setting cftype->file_offset
|
||||||
|
* @show: whether to show or hide
|
||||||
|
*/
|
||||||
|
void cgroup_file_show(struct cgroup_file *cfile, bool show)
|
||||||
|
{
|
||||||
|
struct kernfs_node *kn;
|
||||||
|
|
||||||
|
spin_lock_irq(&cgroup_file_kn_lock);
|
||||||
|
kn = cfile->kn;
|
||||||
|
kernfs_get(kn);
|
||||||
|
spin_unlock_irq(&cgroup_file_kn_lock);
|
||||||
|
|
||||||
|
if (kn)
|
||||||
|
kernfs_show(kn, show);
|
||||||
|
|
||||||
|
kernfs_put(kn);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* css_next_child - find the next child of a given css
|
* css_next_child - find the next child of a given css
|
||||||
* @pos: the current position (%NULL to initiate traversal)
|
* @pos: the current position (%NULL to initiate traversal)
|
||||||
|
|
|
@ -53,6 +53,7 @@ extern const struct kernel_symbol __stop___ksymtab_gpl[];
|
||||||
extern const s32 __start___kcrctab[];
|
extern const s32 __start___kcrctab[];
|
||||||
extern const s32 __start___kcrctab_gpl[];
|
extern const s32 __start___kcrctab_gpl[];
|
||||||
|
|
||||||
|
#include <linux/dynamic_debug.h>
|
||||||
struct load_info {
|
struct load_info {
|
||||||
const char *name;
|
const char *name;
|
||||||
/* pointer to module in temporary copy, freed at end of load_module() */
|
/* pointer to module in temporary copy, freed at end of load_module() */
|
||||||
|
@ -62,8 +63,7 @@ struct load_info {
|
||||||
Elf_Shdr *sechdrs;
|
Elf_Shdr *sechdrs;
|
||||||
char *secstrings, *strtab;
|
char *secstrings, *strtab;
|
||||||
unsigned long symoffs, stroffs, init_typeoffs, core_typeoffs;
|
unsigned long symoffs, stroffs, init_typeoffs, core_typeoffs;
|
||||||
struct _ddebug *debug;
|
struct _ddebug_info dyndbg;
|
||||||
unsigned int num_debug;
|
|
||||||
bool sig_ok;
|
bool sig_ok;
|
||||||
#ifdef CONFIG_KALLSYMS
|
#ifdef CONFIG_KALLSYMS
|
||||||
unsigned long mod_kallsyms_init_off;
|
unsigned long mod_kallsyms_init_off;
|
||||||
|
|
|
@ -1594,16 +1594,16 @@ static void free_modinfo(struct module *mod)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dynamic_debug_setup(struct module *mod, struct _ddebug *debug, unsigned int num)
|
static void dynamic_debug_setup(struct module *mod, struct _ddebug_info *dyndbg)
|
||||||
{
|
{
|
||||||
if (!debug)
|
if (!dyndbg->num_descs)
|
||||||
return;
|
return;
|
||||||
ddebug_add_module(debug, num, mod->name);
|
ddebug_add_module(dyndbg, mod->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dynamic_debug_remove(struct module *mod, struct _ddebug *debug)
|
static void dynamic_debug_remove(struct module *mod, struct _ddebug_info *dyndbg)
|
||||||
{
|
{
|
||||||
if (debug)
|
if (dyndbg->num_descs)
|
||||||
ddebug_remove_module(mod->name);
|
ddebug_remove_module(mod->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2107,8 +2107,10 @@ static int find_module_sections(struct module *mod, struct load_info *info)
|
||||||
if (section_addr(info, "__obsparm"))
|
if (section_addr(info, "__obsparm"))
|
||||||
pr_warn("%s: Ignoring obsolete parameters\n", mod->name);
|
pr_warn("%s: Ignoring obsolete parameters\n", mod->name);
|
||||||
|
|
||||||
info->debug = section_objs(info, "__dyndbg",
|
info->dyndbg.descs = section_objs(info, "__dyndbg",
|
||||||
sizeof(*info->debug), &info->num_debug);
|
sizeof(*info->dyndbg.descs), &info->dyndbg.num_descs);
|
||||||
|
info->dyndbg.classes = section_objs(info, "__dyndbg_classes",
|
||||||
|
sizeof(*info->dyndbg.classes), &info->dyndbg.num_classes);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2799,7 +2801,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
|
||||||
}
|
}
|
||||||
|
|
||||||
init_build_id(mod, info);
|
init_build_id(mod, info);
|
||||||
dynamic_debug_setup(mod, info->debug, info->num_debug);
|
dynamic_debug_setup(mod, &info->dyndbg);
|
||||||
|
|
||||||
/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
|
/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
|
||||||
ftrace_module_init(mod);
|
ftrace_module_init(mod);
|
||||||
|
@ -2863,7 +2865,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
|
||||||
|
|
||||||
ddebug_cleanup:
|
ddebug_cleanup:
|
||||||
ftrace_release_mod(mod);
|
ftrace_release_mod(mod);
|
||||||
dynamic_debug_remove(mod, info->debug);
|
dynamic_debug_remove(mod, &info->dyndbg);
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
kfree(mod->args);
|
kfree(mod->args);
|
||||||
free_arch_cleanup:
|
free_arch_cleanup:
|
||||||
|
|
|
@ -2572,6 +2572,16 @@ config TEST_STATIC_KEYS
|
||||||
|
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
|
config TEST_DYNAMIC_DEBUG
|
||||||
|
tristate "Test DYNAMIC_DEBUG"
|
||||||
|
depends on DYNAMIC_DEBUG
|
||||||
|
help
|
||||||
|
This module registers a tracer callback to count enabled
|
||||||
|
pr_debugs in a 'do_debugging' function, then alters their
|
||||||
|
enablements, calls the function, and compares counts.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
config TEST_KMOD
|
config TEST_KMOD
|
||||||
tristate "kmod stress tester"
|
tristate "kmod stress tester"
|
||||||
depends on m
|
depends on m
|
||||||
|
|
|
@ -83,6 +83,7 @@ obj-$(CONFIG_TEST_SORT) += test_sort.o
|
||||||
obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o
|
obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o
|
||||||
obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o
|
obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o
|
||||||
obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o
|
obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o
|
||||||
|
obj-$(CONFIG_TEST_DYNAMIC_DEBUG) += test_dynamic_debug.o
|
||||||
obj-$(CONFIG_TEST_PRINTF) += test_printf.o
|
obj-$(CONFIG_TEST_PRINTF) += test_printf.o
|
||||||
obj-$(CONFIG_TEST_SCANF) += test_scanf.o
|
obj-$(CONFIG_TEST_SCANF) += test_scanf.o
|
||||||
obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o
|
obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o
|
||||||
|
|
15
lib/devres.c
15
lib/devres.c
|
@ -103,21 +103,6 @@ void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(devm_ioremap_wc);
|
EXPORT_SYMBOL(devm_ioremap_wc);
|
||||||
|
|
||||||
/**
|
|
||||||
* devm_ioremap_np - Managed ioremap_np()
|
|
||||||
* @dev: Generic device to remap IO address for
|
|
||||||
* @offset: Resource address to map
|
|
||||||
* @size: Size of map
|
|
||||||
*
|
|
||||||
* Managed ioremap_np(). Map is automatically unmapped on driver detach.
|
|
||||||
*/
|
|
||||||
void __iomem *devm_ioremap_np(struct device *dev, resource_size_t offset,
|
|
||||||
resource_size_t size)
|
|
||||||
{
|
|
||||||
return __devm_ioremap(dev, offset, size, DEVM_IOREMAP_NP);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(devm_ioremap_np);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* devm_iounmap - Managed iounmap()
|
* devm_iounmap - Managed iounmap()
|
||||||
* @dev: Generic device to unmap for
|
* @dev: Generic device to unmap for
|
||||||
|
|
|
@ -41,9 +41,11 @@
|
||||||
|
|
||||||
extern struct _ddebug __start___dyndbg[];
|
extern struct _ddebug __start___dyndbg[];
|
||||||
extern struct _ddebug __stop___dyndbg[];
|
extern struct _ddebug __stop___dyndbg[];
|
||||||
|
extern struct ddebug_class_map __start___dyndbg_classes[];
|
||||||
|
extern struct ddebug_class_map __stop___dyndbg_classes[];
|
||||||
|
|
||||||
struct ddebug_table {
|
struct ddebug_table {
|
||||||
struct list_head link;
|
struct list_head link, maps;
|
||||||
const char *mod_name;
|
const char *mod_name;
|
||||||
unsigned int num_ddebugs;
|
unsigned int num_ddebugs;
|
||||||
struct _ddebug *ddebugs;
|
struct _ddebug *ddebugs;
|
||||||
|
@ -54,12 +56,13 @@ struct ddebug_query {
|
||||||
const char *module;
|
const char *module;
|
||||||
const char *function;
|
const char *function;
|
||||||
const char *format;
|
const char *format;
|
||||||
|
const char *class_string;
|
||||||
unsigned int first_lineno, last_lineno;
|
unsigned int first_lineno, last_lineno;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ddebug_iter {
|
struct ddebug_iter {
|
||||||
struct ddebug_table *table;
|
struct ddebug_table *table;
|
||||||
unsigned int idx;
|
int idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct flag_settings {
|
struct flag_settings {
|
||||||
|
@ -134,15 +137,33 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
|
||||||
fmtlen--;
|
fmtlen--;
|
||||||
}
|
}
|
||||||
|
|
||||||
v3pr_info("%s: func=\"%s\" file=\"%s\" module=\"%s\" format=\"%.*s\" lineno=%u-%u\n",
|
v3pr_info("%s: func=\"%s\" file=\"%s\" module=\"%s\" format=\"%.*s\" lineno=%u-%u class=%s\n",
|
||||||
msg,
|
msg,
|
||||||
query->function ?: "",
|
query->function ?: "",
|
||||||
query->filename ?: "",
|
query->filename ?: "",
|
||||||
query->module ?: "",
|
query->module ?: "",
|
||||||
fmtlen, query->format ?: "",
|
fmtlen, query->format ?: "",
|
||||||
query->first_lineno, query->last_lineno);
|
query->first_lineno, query->last_lineno, query->class_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
|
||||||
|
const char *class_string, int *class_id)
|
||||||
|
{
|
||||||
|
struct ddebug_class_map *map;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
list_for_each_entry(map, &dt->maps, link) {
|
||||||
|
idx = match_string(map->class_names, map->length, class_string);
|
||||||
|
if (idx >= 0) {
|
||||||
|
*class_id = idx + map->base;
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*class_id = -ENOENT;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __outvar /* filled by callee */
|
||||||
/*
|
/*
|
||||||
* Search the tables for _ddebug's which match the given `query' and
|
* Search the tables for _ddebug's which match the given `query' and
|
||||||
* apply the `flags' and `mask' to them. Returns number of matching
|
* apply the `flags' and `mask' to them. Returns number of matching
|
||||||
|
@ -156,7 +177,9 @@ static int ddebug_change(const struct ddebug_query *query,
|
||||||
struct ddebug_table *dt;
|
struct ddebug_table *dt;
|
||||||
unsigned int newflags;
|
unsigned int newflags;
|
||||||
unsigned int nfound = 0;
|
unsigned int nfound = 0;
|
||||||
struct flagsbuf fbuf;
|
struct flagsbuf fbuf, nbuf;
|
||||||
|
struct ddebug_class_map *map = NULL;
|
||||||
|
int __outvar valid_class;
|
||||||
|
|
||||||
/* search for matching ddebugs */
|
/* search for matching ddebugs */
|
||||||
mutex_lock(&ddebug_lock);
|
mutex_lock(&ddebug_lock);
|
||||||
|
@ -167,9 +190,22 @@ static int ddebug_change(const struct ddebug_query *query,
|
||||||
!match_wildcard(query->module, dt->mod_name))
|
!match_wildcard(query->module, dt->mod_name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (query->class_string) {
|
||||||
|
map = ddebug_find_valid_class(dt, query->class_string, &valid_class);
|
||||||
|
if (!map)
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
/* constrain query, do not touch class'd callsites */
|
||||||
|
valid_class = _DPRINTK_CLASS_DFLT;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < dt->num_ddebugs; i++) {
|
for (i = 0; i < dt->num_ddebugs; i++) {
|
||||||
struct _ddebug *dp = &dt->ddebugs[i];
|
struct _ddebug *dp = &dt->ddebugs[i];
|
||||||
|
|
||||||
|
/* match site against query-class */
|
||||||
|
if (dp->class_id != valid_class)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* match against the source filename */
|
/* match against the source filename */
|
||||||
if (query->filename &&
|
if (query->filename &&
|
||||||
!match_wildcard(query->filename, dp->filename) &&
|
!match_wildcard(query->filename, dp->filename) &&
|
||||||
|
@ -211,16 +247,18 @@ static int ddebug_change(const struct ddebug_query *query,
|
||||||
continue;
|
continue;
|
||||||
#ifdef CONFIG_JUMP_LABEL
|
#ifdef CONFIG_JUMP_LABEL
|
||||||
if (dp->flags & _DPRINTK_FLAGS_PRINT) {
|
if (dp->flags & _DPRINTK_FLAGS_PRINT) {
|
||||||
if (!(modifiers->flags & _DPRINTK_FLAGS_PRINT))
|
if (!(newflags & _DPRINTK_FLAGS_PRINT))
|
||||||
static_branch_disable(&dp->key.dd_key_true);
|
static_branch_disable(&dp->key.dd_key_true);
|
||||||
} else if (modifiers->flags & _DPRINTK_FLAGS_PRINT)
|
} else if (newflags & _DPRINTK_FLAGS_PRINT) {
|
||||||
static_branch_enable(&dp->key.dd_key_true);
|
static_branch_enable(&dp->key.dd_key_true);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
v4pr_info("changed %s:%d [%s]%s %s => %s\n",
|
||||||
|
trim_prefix(dp->filename), dp->lineno,
|
||||||
|
dt->mod_name, dp->function,
|
||||||
|
ddebug_describe_flags(dp->flags, &fbuf),
|
||||||
|
ddebug_describe_flags(newflags, &nbuf));
|
||||||
dp->flags = newflags;
|
dp->flags = newflags;
|
||||||
v4pr_info("changed %s:%d [%s]%s =%s\n",
|
|
||||||
trim_prefix(dp->filename), dp->lineno,
|
|
||||||
dt->mod_name, dp->function,
|
|
||||||
ddebug_describe_flags(dp->flags, &fbuf));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&ddebug_lock);
|
mutex_unlock(&ddebug_lock);
|
||||||
|
@ -383,10 +421,6 @@ static int ddebug_parse_query(char *words[], int nwords,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modname)
|
|
||||||
/* support $modname.dyndbg=<multiple queries> */
|
|
||||||
query->module = modname;
|
|
||||||
|
|
||||||
for (i = 0; i < nwords; i += 2) {
|
for (i = 0; i < nwords; i += 2) {
|
||||||
char *keyword = words[i];
|
char *keyword = words[i];
|
||||||
char *arg = words[i+1];
|
char *arg = words[i+1];
|
||||||
|
@ -420,6 +454,8 @@ static int ddebug_parse_query(char *words[], int nwords,
|
||||||
} else if (!strcmp(keyword, "line")) {
|
} else if (!strcmp(keyword, "line")) {
|
||||||
if (parse_linerange(query, arg))
|
if (parse_linerange(query, arg))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
} else if (!strcmp(keyword, "class")) {
|
||||||
|
rc = check_set(&query->class_string, arg, "class");
|
||||||
} else {
|
} else {
|
||||||
pr_err("unknown keyword \"%s\"\n", keyword);
|
pr_err("unknown keyword \"%s\"\n", keyword);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -427,6 +463,13 @@ static int ddebug_parse_query(char *words[], int nwords,
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
if (!query->module && modname)
|
||||||
|
/*
|
||||||
|
* support $modname.dyndbg=<multiple queries>, when
|
||||||
|
* not given in the query itself
|
||||||
|
*/
|
||||||
|
query->module = modname;
|
||||||
|
|
||||||
vpr_info_dq(query, "parsed");
|
vpr_info_dq(query, "parsed");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -553,34 +596,217 @@ static int ddebug_exec_queries(char *query, const char *modname)
|
||||||
return nfound;
|
return nfound;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* apply a new bitmap to the sys-knob's current bit-state */
|
||||||
* dynamic_debug_exec_queries - select and change dynamic-debug prints
|
static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
|
||||||
* @query: query-string described in admin-guide/dynamic-debug-howto
|
unsigned long *new_bits, unsigned long *old_bits)
|
||||||
* @modname: string containing module name, usually &module.mod_name
|
|
||||||
*
|
|
||||||
* This uses the >/proc/dynamic_debug/control reader, allowing module
|
|
||||||
* authors to modify their dynamic-debug callsites. The modname is
|
|
||||||
* canonically struct module.mod_name, but can also be null or a
|
|
||||||
* module-wildcard, for example: "drm*".
|
|
||||||
*/
|
|
||||||
int dynamic_debug_exec_queries(const char *query, const char *modname)
|
|
||||||
{
|
{
|
||||||
int rc;
|
#define QUERY_SIZE 128
|
||||||
char *qry; /* writable copy of query */
|
char query[QUERY_SIZE];
|
||||||
|
const struct ddebug_class_map *map = dcp->map;
|
||||||
|
int matches = 0;
|
||||||
|
int bi, ct;
|
||||||
|
|
||||||
if (!query) {
|
v2pr_info("apply: 0x%lx to: 0x%lx\n", *new_bits, *old_bits);
|
||||||
pr_err("non-null query/command string expected\n");
|
|
||||||
|
for (bi = 0; bi < map->length; bi++) {
|
||||||
|
if (test_bit(bi, new_bits) == test_bit(bi, old_bits))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snprintf(query, QUERY_SIZE, "class %s %c%s", map->class_names[bi],
|
||||||
|
test_bit(bi, new_bits) ? '+' : '-', dcp->flags);
|
||||||
|
|
||||||
|
ct = ddebug_exec_queries(query, NULL);
|
||||||
|
matches += ct;
|
||||||
|
|
||||||
|
v2pr_info("bit_%d: %d matches on class: %s -> 0x%lx\n", bi,
|
||||||
|
ct, map->class_names[bi], *new_bits);
|
||||||
|
}
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stub to later conditionally add "$module." prefix where not already done */
|
||||||
|
#define KP_NAME(kp) kp->name
|
||||||
|
|
||||||
|
#define CLASSMAP_BITMASK(width) ((1UL << (width)) - 1)
|
||||||
|
|
||||||
|
/* accept comma-separated-list of [+-] classnames */
|
||||||
|
static int param_set_dyndbg_classnames(const char *instr, const struct kernel_param *kp)
|
||||||
|
{
|
||||||
|
const struct ddebug_class_param *dcp = kp->arg;
|
||||||
|
const struct ddebug_class_map *map = dcp->map;
|
||||||
|
unsigned long curr_bits, old_bits;
|
||||||
|
char *cl_str, *p, *tmp;
|
||||||
|
int cls_id, totct = 0;
|
||||||
|
bool wanted;
|
||||||
|
|
||||||
|
cl_str = tmp = kstrdup(instr, GFP_KERNEL);
|
||||||
|
p = strchr(cl_str, '\n');
|
||||||
|
if (p)
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
/* start with previously set state-bits, then modify */
|
||||||
|
curr_bits = old_bits = *dcp->bits;
|
||||||
|
vpr_info("\"%s\" > %s:0x%lx\n", cl_str, KP_NAME(kp), curr_bits);
|
||||||
|
|
||||||
|
for (; cl_str; cl_str = p) {
|
||||||
|
p = strchr(cl_str, ',');
|
||||||
|
if (p)
|
||||||
|
*p++ = '\0';
|
||||||
|
|
||||||
|
if (*cl_str == '-') {
|
||||||
|
wanted = false;
|
||||||
|
cl_str++;
|
||||||
|
} else {
|
||||||
|
wanted = true;
|
||||||
|
if (*cl_str == '+')
|
||||||
|
cl_str++;
|
||||||
|
}
|
||||||
|
cls_id = match_string(map->class_names, map->length, cl_str);
|
||||||
|
if (cls_id < 0) {
|
||||||
|
pr_err("%s unknown to %s\n", cl_str, KP_NAME(kp));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* have one or more valid class_ids of one *_NAMES type */
|
||||||
|
switch (map->map_type) {
|
||||||
|
case DD_CLASS_TYPE_DISJOINT_NAMES:
|
||||||
|
/* the +/- pertains to a single bit */
|
||||||
|
if (test_bit(cls_id, &curr_bits) == wanted) {
|
||||||
|
v3pr_info("no change on %s\n", cl_str);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
curr_bits ^= BIT(cls_id);
|
||||||
|
totct += ddebug_apply_class_bitmap(dcp, &curr_bits, dcp->bits);
|
||||||
|
*dcp->bits = curr_bits;
|
||||||
|
v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id,
|
||||||
|
map->class_names[cls_id]);
|
||||||
|
break;
|
||||||
|
case DD_CLASS_TYPE_LEVEL_NAMES:
|
||||||
|
/* cls_id = N in 0..max. wanted +/- determines N or N-1 */
|
||||||
|
old_bits = CLASSMAP_BITMASK(*dcp->lvl);
|
||||||
|
curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 ));
|
||||||
|
|
||||||
|
totct += ddebug_apply_class_bitmap(dcp, &curr_bits, &old_bits);
|
||||||
|
*dcp->lvl = (cls_id + (wanted ? 1 : 0));
|
||||||
|
v2pr_info("%s: changed bit-%d: \"%s\" %lx->%lx\n", KP_NAME(kp), cls_id,
|
||||||
|
map->class_names[cls_id], old_bits, curr_bits);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_err("illegal map-type value %d\n", map->map_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kfree(tmp);
|
||||||
|
vpr_info("total matches: %d\n", totct);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* param_set_dyndbg_classes - class FOO >control
|
||||||
|
* @instr: string echo>d to sysfs, input depends on map_type
|
||||||
|
* @kp: kp->arg has state: bits/lvl, map, map_type
|
||||||
|
*
|
||||||
|
* Enable/disable prdbgs by their class, as given in the arguments to
|
||||||
|
* DECLARE_DYNDBG_CLASSMAP. For LEVEL map-types, enforce relative
|
||||||
|
* levels by bitpos.
|
||||||
|
*
|
||||||
|
* Returns: 0 or <0 if error.
|
||||||
|
*/
|
||||||
|
int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
|
||||||
|
{
|
||||||
|
const struct ddebug_class_param *dcp = kp->arg;
|
||||||
|
const struct ddebug_class_map *map = dcp->map;
|
||||||
|
unsigned long inrep, new_bits, old_bits;
|
||||||
|
int rc, totct = 0;
|
||||||
|
|
||||||
|
switch (map->map_type) {
|
||||||
|
|
||||||
|
case DD_CLASS_TYPE_DISJOINT_NAMES:
|
||||||
|
case DD_CLASS_TYPE_LEVEL_NAMES:
|
||||||
|
/* handle [+-]classnames list separately, we are done here */
|
||||||
|
return param_set_dyndbg_classnames(instr, kp);
|
||||||
|
|
||||||
|
case DD_CLASS_TYPE_DISJOINT_BITS:
|
||||||
|
case DD_CLASS_TYPE_LEVEL_NUM:
|
||||||
|
/* numeric input, accept and fall-thru */
|
||||||
|
rc = kstrtoul(instr, 0, &inrep);
|
||||||
|
if (rc) {
|
||||||
|
pr_err("expecting numeric input: %s > %s\n", instr, KP_NAME(kp));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_err("%s: bad map type: %d\n", KP_NAME(kp), map->map_type);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
qry = kstrndup(query, PAGE_SIZE, GFP_KERNEL);
|
|
||||||
if (!qry)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
rc = ddebug_exec_queries(qry, modname);
|
/* only _BITS,_NUM (numeric) map-types get here */
|
||||||
kfree(qry);
|
switch (map->map_type) {
|
||||||
return rc;
|
case DD_CLASS_TYPE_DISJOINT_BITS:
|
||||||
|
/* expect bits. mask and warn if too many */
|
||||||
|
if (inrep & ~CLASSMAP_BITMASK(map->length)) {
|
||||||
|
pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n",
|
||||||
|
KP_NAME(kp), inrep, CLASSMAP_BITMASK(map->length));
|
||||||
|
inrep &= CLASSMAP_BITMASK(map->length);
|
||||||
|
}
|
||||||
|
v2pr_info("bits:%lx > %s\n", inrep, KP_NAME(kp));
|
||||||
|
totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits);
|
||||||
|
*dcp->bits = inrep;
|
||||||
|
break;
|
||||||
|
case DD_CLASS_TYPE_LEVEL_NUM:
|
||||||
|
/* input is bitpos, of highest verbosity to be enabled */
|
||||||
|
if (inrep > map->length) {
|
||||||
|
pr_warn("%s: level:%ld exceeds max:%d, clamping\n",
|
||||||
|
KP_NAME(kp), inrep, map->length);
|
||||||
|
inrep = map->length;
|
||||||
|
}
|
||||||
|
old_bits = CLASSMAP_BITMASK(*dcp->lvl);
|
||||||
|
new_bits = CLASSMAP_BITMASK(inrep);
|
||||||
|
v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
|
||||||
|
totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits);
|
||||||
|
*dcp->lvl = inrep;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_warn("%s: bad map type: %d\n", KP_NAME(kp), map->map_type);
|
||||||
|
}
|
||||||
|
vpr_info("%s: total matches: %d\n", KP_NAME(kp), totct);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dynamic_debug_exec_queries);
|
EXPORT_SYMBOL(param_set_dyndbg_classes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* param_get_dyndbg_classes - classes reader
|
||||||
|
* @buffer: string description of controlled bits -> classes
|
||||||
|
* @kp: kp->arg has state: bits, map
|
||||||
|
*
|
||||||
|
* Reads last written state, underlying prdbg state may have been
|
||||||
|
* altered by direct >control. Displays 0x for DISJOINT, 0-N for
|
||||||
|
* LEVEL Returns: #chars written or <0 on error
|
||||||
|
*/
|
||||||
|
int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
|
||||||
|
{
|
||||||
|
const struct ddebug_class_param *dcp = kp->arg;
|
||||||
|
const struct ddebug_class_map *map = dcp->map;
|
||||||
|
|
||||||
|
switch (map->map_type) {
|
||||||
|
|
||||||
|
case DD_CLASS_TYPE_DISJOINT_NAMES:
|
||||||
|
case DD_CLASS_TYPE_DISJOINT_BITS:
|
||||||
|
return scnprintf(buffer, PAGE_SIZE, "0x%lx\n", *dcp->bits);
|
||||||
|
|
||||||
|
case DD_CLASS_TYPE_LEVEL_NAMES:
|
||||||
|
case DD_CLASS_TYPE_LEVEL_NUM:
|
||||||
|
return scnprintf(buffer, PAGE_SIZE, "%d\n", *dcp->lvl);
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(param_get_dyndbg_classes);
|
||||||
|
|
||||||
|
const struct kernel_param_ops param_ops_dyndbg_classes = {
|
||||||
|
.set = param_set_dyndbg_classes,
|
||||||
|
.get = param_get_dyndbg_classes,
|
||||||
|
};
|
||||||
|
EXPORT_SYMBOL(param_ops_dyndbg_classes);
|
||||||
|
|
||||||
#define PREFIX_SIZE 64
|
#define PREFIX_SIZE 64
|
||||||
|
|
||||||
|
@ -803,13 +1029,12 @@ static struct _ddebug *ddebug_iter_first(struct ddebug_iter *iter)
|
||||||
{
|
{
|
||||||
if (list_empty(&ddebug_tables)) {
|
if (list_empty(&ddebug_tables)) {
|
||||||
iter->table = NULL;
|
iter->table = NULL;
|
||||||
iter->idx = 0;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
iter->table = list_entry(ddebug_tables.next,
|
iter->table = list_entry(ddebug_tables.next,
|
||||||
struct ddebug_table, link);
|
struct ddebug_table, link);
|
||||||
iter->idx = 0;
|
iter->idx = iter->table->num_ddebugs;
|
||||||
return &iter->table->ddebugs[iter->idx];
|
return &iter->table->ddebugs[--iter->idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -822,15 +1047,16 @@ static struct _ddebug *ddebug_iter_next(struct ddebug_iter *iter)
|
||||||
{
|
{
|
||||||
if (iter->table == NULL)
|
if (iter->table == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (++iter->idx == iter->table->num_ddebugs) {
|
if (--iter->idx < 0) {
|
||||||
/* iterate to next table */
|
/* iterate to next table */
|
||||||
iter->idx = 0;
|
|
||||||
if (list_is_last(&iter->table->link, &ddebug_tables)) {
|
if (list_is_last(&iter->table->link, &ddebug_tables)) {
|
||||||
iter->table = NULL;
|
iter->table = NULL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
iter->table = list_entry(iter->table->link.next,
|
iter->table = list_entry(iter->table->link.next,
|
||||||
struct ddebug_table, link);
|
struct ddebug_table, link);
|
||||||
|
iter->idx = iter->table->num_ddebugs;
|
||||||
|
--iter->idx;
|
||||||
}
|
}
|
||||||
return &iter->table->ddebugs[iter->idx];
|
return &iter->table->ddebugs[iter->idx];
|
||||||
}
|
}
|
||||||
|
@ -876,6 +1102,20 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
|
||||||
return dp;
|
return dp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define class_in_range(class_id, map) \
|
||||||
|
(class_id >= map->base && class_id < map->base + map->length)
|
||||||
|
|
||||||
|
static const char *ddebug_class_name(struct ddebug_iter *iter, struct _ddebug *dp)
|
||||||
|
{
|
||||||
|
struct ddebug_class_map *map;
|
||||||
|
|
||||||
|
list_for_each_entry(map, &iter->table->maps, link)
|
||||||
|
if (class_in_range(dp->class_id, map))
|
||||||
|
return map->class_names[dp->class_id - map->base];
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Seq_ops show method. Called several times within a read()
|
* Seq_ops show method. Called several times within a read()
|
||||||
* call from userspace, with ddebug_lock held. Formats the
|
* call from userspace, with ddebug_lock held. Formats the
|
||||||
|
@ -887,6 +1127,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
|
||||||
struct ddebug_iter *iter = m->private;
|
struct ddebug_iter *iter = m->private;
|
||||||
struct _ddebug *dp = p;
|
struct _ddebug *dp = p;
|
||||||
struct flagsbuf flags;
|
struct flagsbuf flags;
|
||||||
|
char const *class;
|
||||||
|
|
||||||
if (p == SEQ_START_TOKEN) {
|
if (p == SEQ_START_TOKEN) {
|
||||||
seq_puts(m,
|
seq_puts(m,
|
||||||
|
@ -898,8 +1139,17 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
|
||||||
trim_prefix(dp->filename), dp->lineno,
|
trim_prefix(dp->filename), dp->lineno,
|
||||||
iter->table->mod_name, dp->function,
|
iter->table->mod_name, dp->function,
|
||||||
ddebug_describe_flags(dp->flags, &flags));
|
ddebug_describe_flags(dp->flags, &flags));
|
||||||
seq_escape(m, dp->format, "\t\r\n\"");
|
seq_escape_str(m, dp->format, ESCAPE_SPACE, "\t\r\n\"");
|
||||||
seq_puts(m, "\"\n");
|
seq_puts(m, "\"");
|
||||||
|
|
||||||
|
if (dp->class_id != _DPRINTK_CLASS_DFLT) {
|
||||||
|
class = ddebug_class_name(iter, dp);
|
||||||
|
if (class)
|
||||||
|
seq_printf(m, " class:%s", class);
|
||||||
|
else
|
||||||
|
seq_printf(m, " class unknown, _id:%d", dp->class_id);
|
||||||
|
}
|
||||||
|
seq_puts(m, "\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -943,18 +1193,50 @@ static const struct proc_ops proc_fops = {
|
||||||
.proc_write = ddebug_proc_write
|
.proc_write = ddebug_proc_write
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void ddebug_attach_module_classes(struct ddebug_table *dt,
|
||||||
|
struct ddebug_class_map *classes,
|
||||||
|
int num_classes)
|
||||||
|
{
|
||||||
|
struct ddebug_class_map *cm;
|
||||||
|
int i, j, ct = 0;
|
||||||
|
|
||||||
|
for (cm = classes, i = 0; i < num_classes; i++, cm++) {
|
||||||
|
|
||||||
|
if (!strcmp(cm->mod_name, dt->mod_name)) {
|
||||||
|
|
||||||
|
v2pr_info("class[%d]: module:%s base:%d len:%d ty:%d\n", i,
|
||||||
|
cm->mod_name, cm->base, cm->length, cm->map_type);
|
||||||
|
|
||||||
|
for (j = 0; j < cm->length; j++)
|
||||||
|
v3pr_info(" %d: %d %s\n", j + cm->base, j,
|
||||||
|
cm->class_names[j]);
|
||||||
|
|
||||||
|
list_add(&cm->link, &dt->maps);
|
||||||
|
ct++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ct)
|
||||||
|
vpr_info("module:%s attached %d classes\n", dt->mod_name, ct);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate a new ddebug_table for the given module
|
* Allocate a new ddebug_table for the given module
|
||||||
* and add it to the global list.
|
* and add it to the global list.
|
||||||
*/
|
*/
|
||||||
int ddebug_add_module(struct _ddebug *tab, unsigned int n,
|
static int __ddebug_add_module(struct _ddebug_info *di, unsigned int base,
|
||||||
const char *name)
|
const char *modname)
|
||||||
{
|
{
|
||||||
struct ddebug_table *dt;
|
struct ddebug_table *dt;
|
||||||
|
|
||||||
|
v3pr_info("add-module: %s.%d sites\n", modname, di->num_descs);
|
||||||
|
if (!di->num_descs) {
|
||||||
|
v3pr_info(" skip %s\n", modname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
dt = kzalloc(sizeof(*dt), GFP_KERNEL);
|
dt = kzalloc(sizeof(*dt), GFP_KERNEL);
|
||||||
if (dt == NULL) {
|
if (dt == NULL) {
|
||||||
pr_err("error adding module: %s\n", name);
|
pr_err("error adding module: %s\n", modname);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -963,18 +1245,29 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n,
|
||||||
* member of struct module, which lives at least as long as
|
* member of struct module, which lives at least as long as
|
||||||
* this struct ddebug_table.
|
* this struct ddebug_table.
|
||||||
*/
|
*/
|
||||||
dt->mod_name = name;
|
dt->mod_name = modname;
|
||||||
dt->num_ddebugs = n;
|
dt->ddebugs = di->descs;
|
||||||
dt->ddebugs = tab;
|
dt->num_ddebugs = di->num_descs;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&dt->link);
|
||||||
|
INIT_LIST_HEAD(&dt->maps);
|
||||||
|
|
||||||
|
if (di->classes && di->num_classes)
|
||||||
|
ddebug_attach_module_classes(dt, di->classes, di->num_classes);
|
||||||
|
|
||||||
mutex_lock(&ddebug_lock);
|
mutex_lock(&ddebug_lock);
|
||||||
list_add(&dt->link, &ddebug_tables);
|
list_add_tail(&dt->link, &ddebug_tables);
|
||||||
mutex_unlock(&ddebug_lock);
|
mutex_unlock(&ddebug_lock);
|
||||||
|
|
||||||
vpr_info("%3u debug prints in module %s\n", n, dt->mod_name);
|
vpr_info("%3u debug prints in module %s\n", di->num_descs, modname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ddebug_add_module(struct _ddebug_info *di, const char *modname)
|
||||||
|
{
|
||||||
|
return __ddebug_add_module(di, 0, modname);
|
||||||
|
}
|
||||||
|
|
||||||
/* helper for ddebug_dyndbg_(boot|module)_param_cb */
|
/* helper for ddebug_dyndbg_(boot|module)_param_cb */
|
||||||
static int ddebug_dyndbg_param_cb(char *param, char *val,
|
static int ddebug_dyndbg_param_cb(char *param, char *val,
|
||||||
const char *modname, int on_err)
|
const char *modname, int on_err)
|
||||||
|
@ -1083,11 +1376,17 @@ static int __init dynamic_debug_init_control(void)
|
||||||
|
|
||||||
static int __init dynamic_debug_init(void)
|
static int __init dynamic_debug_init(void)
|
||||||
{
|
{
|
||||||
struct _ddebug *iter, *iter_start;
|
struct _ddebug *iter, *iter_mod_start;
|
||||||
const char *modname = NULL;
|
int ret, i, mod_sites, mod_ct;
|
||||||
|
const char *modname;
|
||||||
char *cmdline;
|
char *cmdline;
|
||||||
int ret = 0;
|
|
||||||
int n = 0, entries = 0, modct = 0;
|
struct _ddebug_info di = {
|
||||||
|
.descs = __start___dyndbg,
|
||||||
|
.classes = __start___dyndbg_classes,
|
||||||
|
.num_descs = __stop___dyndbg - __start___dyndbg,
|
||||||
|
.num_classes = __stop___dyndbg_classes - __start___dyndbg_classes,
|
||||||
|
};
|
||||||
|
|
||||||
if (&__start___dyndbg == &__stop___dyndbg) {
|
if (&__start___dyndbg == &__stop___dyndbg) {
|
||||||
if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
|
if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
|
||||||
|
@ -1098,30 +1397,39 @@ static int __init dynamic_debug_init(void)
|
||||||
ddebug_init_success = 1;
|
ddebug_init_success = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
iter = __start___dyndbg;
|
|
||||||
|
iter = iter_mod_start = __start___dyndbg;
|
||||||
modname = iter->modname;
|
modname = iter->modname;
|
||||||
iter_start = iter;
|
i = mod_sites = mod_ct = 0;
|
||||||
for (; iter < __stop___dyndbg; iter++) {
|
|
||||||
entries++;
|
for (; iter < __stop___dyndbg; iter++, i++, mod_sites++) {
|
||||||
|
|
||||||
if (strcmp(modname, iter->modname)) {
|
if (strcmp(modname, iter->modname)) {
|
||||||
modct++;
|
mod_ct++;
|
||||||
ret = ddebug_add_module(iter_start, n, modname);
|
di.num_descs = mod_sites;
|
||||||
|
di.descs = iter_mod_start;
|
||||||
|
ret = __ddebug_add_module(&di, i - mod_sites, modname);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
n = 0;
|
|
||||||
|
mod_sites = 0;
|
||||||
modname = iter->modname;
|
modname = iter->modname;
|
||||||
iter_start = iter;
|
iter_mod_start = iter;
|
||||||
}
|
}
|
||||||
n++;
|
|
||||||
}
|
}
|
||||||
ret = ddebug_add_module(iter_start, n, modname);
|
di.num_descs = mod_sites;
|
||||||
|
di.descs = iter_mod_start;
|
||||||
|
ret = __ddebug_add_module(&di, i - mod_sites, modname);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
|
||||||
ddebug_init_success = 1;
|
ddebug_init_success = 1;
|
||||||
vpr_info("%d prdebugs in %d modules, %d KiB in ddebug tables, %d kiB in __dyndbg section\n",
|
vpr_info("%d prdebugs in %d modules, %d KiB in ddebug tables, %d kiB in __dyndbg section\n",
|
||||||
entries, modct, (int)((modct * sizeof(struct ddebug_table)) >> 10),
|
i, mod_ct, (int)((mod_ct * sizeof(struct ddebug_table)) >> 10),
|
||||||
(int)((entries * sizeof(struct _ddebug)) >> 10));
|
(int)((i * sizeof(struct _ddebug)) >> 10));
|
||||||
|
|
||||||
|
if (di.num_classes)
|
||||||
|
v2pr_info(" %d builtin ddebug class-maps\n", di.num_classes);
|
||||||
|
|
||||||
/* now that ddebug tables are loaded, process all boot args
|
/* now that ddebug tables are loaded, process all boot args
|
||||||
* again to find and activate queries given in dyndbg params.
|
* again to find and activate queries given in dyndbg params.
|
||||||
|
|
165
lib/test_dynamic_debug.c
Normal file
165
lib/test_dynamic_debug.c
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* Kernel module for testing dynamic_debug
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Jim Cromie <jim.cromie@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define pr_fmt(fmt) "test_dd: " fmt
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
|
||||||
|
/* run tests by reading or writing sysfs node: do_prints */
|
||||||
|
|
||||||
|
static void do_prints(void); /* device under test */
|
||||||
|
static int param_set_do_prints(const char *instr, const struct kernel_param *kp)
|
||||||
|
{
|
||||||
|
do_prints();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static int param_get_do_prints(char *buffer, const struct kernel_param *kp)
|
||||||
|
{
|
||||||
|
do_prints();
|
||||||
|
return scnprintf(buffer, PAGE_SIZE, "did do_prints\n");
|
||||||
|
}
|
||||||
|
static const struct kernel_param_ops param_ops_do_prints = {
|
||||||
|
.set = param_set_do_prints,
|
||||||
|
.get = param_get_do_prints,
|
||||||
|
};
|
||||||
|
module_param_cb(do_prints, ¶m_ops_do_prints, NULL, 0600);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using the CLASSMAP api:
|
||||||
|
* - classmaps must have corresponding enum
|
||||||
|
* - enum symbols must match/correlate with class-name strings in the map.
|
||||||
|
* - base must equal enum's 1st value
|
||||||
|
* - multiple maps must set their base to share the 0-30 class_id space !!
|
||||||
|
* (build-bug-on tips welcome)
|
||||||
|
* Additionally, here:
|
||||||
|
* - tie together sysname, mapname, bitsname, flagsname
|
||||||
|
*/
|
||||||
|
#define DD_SYS_WRAP(_model, _flags) \
|
||||||
|
static unsigned long bits_##_model; \
|
||||||
|
static struct ddebug_class_param _flags##_model = { \
|
||||||
|
.bits = &bits_##_model, \
|
||||||
|
.flags = #_flags, \
|
||||||
|
.map = &map_##_model, \
|
||||||
|
}; \
|
||||||
|
module_param_cb(_flags##_##_model, ¶m_ops_dyndbg_classes, &_flags##_model, 0600)
|
||||||
|
|
||||||
|
/* numeric input, independent bits */
|
||||||
|
enum cat_disjoint_bits {
|
||||||
|
D2_CORE = 0,
|
||||||
|
D2_DRIVER,
|
||||||
|
D2_KMS,
|
||||||
|
D2_PRIME,
|
||||||
|
D2_ATOMIC,
|
||||||
|
D2_VBL,
|
||||||
|
D2_STATE,
|
||||||
|
D2_LEASE,
|
||||||
|
D2_DP,
|
||||||
|
D2_DRMRES };
|
||||||
|
DECLARE_DYNDBG_CLASSMAP(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS, 0,
|
||||||
|
"D2_CORE",
|
||||||
|
"D2_DRIVER",
|
||||||
|
"D2_KMS",
|
||||||
|
"D2_PRIME",
|
||||||
|
"D2_ATOMIC",
|
||||||
|
"D2_VBL",
|
||||||
|
"D2_STATE",
|
||||||
|
"D2_LEASE",
|
||||||
|
"D2_DP",
|
||||||
|
"D2_DRMRES");
|
||||||
|
DD_SYS_WRAP(disjoint_bits, p);
|
||||||
|
DD_SYS_WRAP(disjoint_bits, T);
|
||||||
|
|
||||||
|
/* symbolic input, independent bits */
|
||||||
|
enum cat_disjoint_names { LOW = 11, MID, HI };
|
||||||
|
DECLARE_DYNDBG_CLASSMAP(map_disjoint_names, DD_CLASS_TYPE_DISJOINT_NAMES, 10,
|
||||||
|
"LOW", "MID", "HI");
|
||||||
|
DD_SYS_WRAP(disjoint_names, p);
|
||||||
|
DD_SYS_WRAP(disjoint_names, T);
|
||||||
|
|
||||||
|
/* numeric verbosity, V2 > V1 related */
|
||||||
|
enum cat_level_num { V0 = 14, V1, V2, V3, V4, V5, V6, V7 };
|
||||||
|
DECLARE_DYNDBG_CLASSMAP(map_level_num, DD_CLASS_TYPE_LEVEL_NUM, 14,
|
||||||
|
"V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7");
|
||||||
|
DD_SYS_WRAP(level_num, p);
|
||||||
|
DD_SYS_WRAP(level_num, T);
|
||||||
|
|
||||||
|
/* symbolic verbosity */
|
||||||
|
enum cat_level_names { L0 = 22, L1, L2, L3, L4, L5, L6, L7 };
|
||||||
|
DECLARE_DYNDBG_CLASSMAP(map_level_names, DD_CLASS_TYPE_LEVEL_NAMES, 22,
|
||||||
|
"L0", "L1", "L2", "L3", "L4", "L5", "L6", "L7");
|
||||||
|
DD_SYS_WRAP(level_names, p);
|
||||||
|
DD_SYS_WRAP(level_names, T);
|
||||||
|
|
||||||
|
/* stand-in for all pr_debug etc */
|
||||||
|
#define prdbg(SYM) __pr_debug_cls(SYM, #SYM " msg\n")
|
||||||
|
|
||||||
|
static void do_cats(void)
|
||||||
|
{
|
||||||
|
pr_debug("doing categories\n");
|
||||||
|
|
||||||
|
prdbg(LOW);
|
||||||
|
prdbg(MID);
|
||||||
|
prdbg(HI);
|
||||||
|
|
||||||
|
prdbg(D2_CORE);
|
||||||
|
prdbg(D2_DRIVER);
|
||||||
|
prdbg(D2_KMS);
|
||||||
|
prdbg(D2_PRIME);
|
||||||
|
prdbg(D2_ATOMIC);
|
||||||
|
prdbg(D2_VBL);
|
||||||
|
prdbg(D2_STATE);
|
||||||
|
prdbg(D2_LEASE);
|
||||||
|
prdbg(D2_DP);
|
||||||
|
prdbg(D2_DRMRES);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_levels(void)
|
||||||
|
{
|
||||||
|
pr_debug("doing levels\n");
|
||||||
|
|
||||||
|
prdbg(V1);
|
||||||
|
prdbg(V2);
|
||||||
|
prdbg(V3);
|
||||||
|
prdbg(V4);
|
||||||
|
prdbg(V5);
|
||||||
|
prdbg(V6);
|
||||||
|
prdbg(V7);
|
||||||
|
|
||||||
|
prdbg(L1);
|
||||||
|
prdbg(L2);
|
||||||
|
prdbg(L3);
|
||||||
|
prdbg(L4);
|
||||||
|
prdbg(L5);
|
||||||
|
prdbg(L6);
|
||||||
|
prdbg(L7);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_prints(void)
|
||||||
|
{
|
||||||
|
do_cats();
|
||||||
|
do_levels();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init test_dynamic_debug_init(void)
|
||||||
|
{
|
||||||
|
pr_debug("init start\n");
|
||||||
|
do_prints();
|
||||||
|
pr_debug("init done\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit test_dynamic_debug_exit(void)
|
||||||
|
{
|
||||||
|
pr_debug("exited\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(test_dynamic_debug_init);
|
||||||
|
module_exit(test_dynamic_debug_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -35,7 +35,6 @@
|
||||||
#include <net/bluetooth/hci_core.h>
|
#include <net/bluetooth/hci_core.h>
|
||||||
#include <net/bluetooth/rfcomm.h>
|
#include <net/bluetooth/rfcomm.h>
|
||||||
|
|
||||||
#define RFCOMM_TTY_MAGIC 0x6d02 /* magic number for rfcomm struct */
|
|
||||||
#define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV /* whole lotta rfcomm devices */
|
#define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV /* whole lotta rfcomm devices */
|
||||||
#define RFCOMM_TTY_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */
|
#define RFCOMM_TTY_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */
|
||||||
#define RFCOMM_TTY_MINOR 0
|
#define RFCOMM_TTY_MINOR 0
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue