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
Documentation
admin-guide
driver-api/driver-model
filesystems
process
translations
arch/mips/include/asm/sn
drivers
fs
include
kernel
lib
net/bluetooth/rfcomm
@ -5,143 +5,115 @@ Dynamic debug
|
||||
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
|
||||
kernel code to obtain additional kernel information. Currently, if
|
||||
``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 ``/proc/dynamic_debug/control`` exists, your kernel has dynamic
|
||||
debug. You'll need root access (sudo su) to use this.
|
||||
|
||||
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.
|
||||
Dynamic debug provides:
|
||||
|
||||
If ``CONFIG_DYNAMIC_DEBUG`` is not set, ``print_hex_dump_debug()`` is just
|
||||
shortcut for ``print_hex_dump(KERN_DEBUG)``.
|
||||
* a Catalog of all *prdbgs* in your kernel.
|
||||
``cat /proc/dynamic_debug/control`` to see them.
|
||||
|
||||
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.
|
||||
|
||||
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:
|
||||
* a Simple query/command language to alter *prdbgs* by selecting on
|
||||
any combination of 0 or 1 of:
|
||||
|
||||
- source filename
|
||||
- function name
|
||||
- line number (including ranges of line numbers)
|
||||
- module name
|
||||
- format string
|
||||
|
||||
* 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``.
|
||||
- class name (as known/declared by each module)
|
||||
|
||||
Viewing Dynamic Debug Behaviour
|
||||
===============================
|
||||
|
||||
You can view the currently configured behaviour of all the debug
|
||||
statements via::
|
||||
You can view the currently configured behaviour in the *prdbg* catalog::
|
||||
|
||||
nullarbor:~ # cat <debugfs>/dynamic_debug/control
|
||||
:#> head -n7 /proc/dynamic_debug/control
|
||||
# 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"
|
||||
net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init =_ "\011max_inline : %d\012"
|
||||
net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init =_ "\011sq_depth : %d\012"
|
||||
net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init =_ "\011max_requests : %d\012"
|
||||
...
|
||||
init/main.c:1179 [main]initcall_blacklist =_ "blacklisting initcall %s\012
|
||||
init/main.c:1218 [main]initcall_blacklisted =_ "initcall %s blacklisted\012"
|
||||
init/main.c:1424 [main]run_init_process =_ " with arguments:\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
|
||||
data, e.g.::
|
||||
Controlling dynamic debug Behaviour
|
||||
===================================
|
||||
|
||||
nullarbor:~ # grep -i rdma <debugfs>/dynamic_debug/control | wc -l
|
||||
62
|
||||
The behaviour of *prdbg* sites are controlled by writing
|
||||
query/commands to the control file. Example::
|
||||
|
||||
nullarbor:~ # grep -i tcp <debugfs>/dynamic_debug/control | wc -l
|
||||
42
|
||||
# grease the interface
|
||||
:#> alias ddcmd='echo $* > /proc/dynamic_debug/control'
|
||||
|
||||
The third column shows the currently enabled flags for each debug
|
||||
statement callsite (see below for definitions of the flags). The
|
||||
default value, with no flags enabled, is ``=_``. So you can view all
|
||||
the debug statement callsites with any non-default flags::
|
||||
:#> ddcmd '-p; module main func run* +p'
|
||||
:#> grep =p /proc/dynamic_debug/control
|
||||
init/main.c:1424 [main]run_init_process =p " with arguments:\012"
|
||||
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
|
||||
# filename:lineno [module]function flags format
|
||||
net/sunrpc/svcsock.c:1603 [sunrpc]svc_send p "svc_process: st_sendto returned %d\012"
|
||||
Error messages go to console/syslog::
|
||||
|
||||
:#> 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
|
||||
==========================
|
||||
|
||||
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::
|
||||
|
||||
nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >
|
||||
<debugfs>/dynamic_debug/control
|
||||
nullarbor:~ # echo -n ' file svcsock.c line 1603 +p ' >
|
||||
<debugfs>/dynamic_debug/control
|
||||
nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >
|
||||
<debugfs>/dynamic_debug/control
|
||||
:#> ddcmd file svcsock.c line 1603 +p
|
||||
:#> ddcmd "file svcsock.c line 1603 +p"
|
||||
:#> ddcmd ' file svcsock.c line 1603 +p '
|
||||
|
||||
Command submissions are bounded by a write() system call.
|
||||
Multiple commands can be written together, separated by ``;`` or ``\n``::
|
||||
|
||||
~# echo "func pnpacpi_get_resources +p; func pnp_assign_mem +p" \
|
||||
> <debugfs>/dynamic_debug/control
|
||||
:#> ddcmd "func pnpacpi_get_resources +p; func pnp_assign_mem +p"
|
||||
:#> 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
|
||||
zero or more characters) and ``?`` (matches exactly one character). For
|
||||
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::
|
||||
Syntactically, a command is pairs of keyword values, followed by a
|
||||
flags change or setting::
|
||||
|
||||
command ::= match-spec* flags-spec
|
||||
|
||||
The match-spec's are used to choose a subset of the known pr_debug()
|
||||
callsites to which to apply the flags-spec. Think of them as a query
|
||||
with implicit ANDs between each pair. Note that an empty list of
|
||||
match-specs will select all debug statement callsites.
|
||||
The match-spec's select *prdbgs* from the catalog, upon which to apply
|
||||
the flags-spec, all constraints are ANDed together. An absent keyword
|
||||
is the same as keyword "*".
|
||||
|
||||
A match specification comprises a keyword, which controls the
|
||||
attribute of the callsite to be compared, and a value to compare
|
||||
against. Possible keywords are:::
|
||||
|
||||
A match specification is a keyword, which selects the attribute of
|
||||
the callsite to be compared, and a value to compare against. Possible
|
||||
keywords are:::
|
||||
|
||||
match-spec ::= 'func' string |
|
||||
'file' string |
|
||||
'module' string |
|
||||
'format' string |
|
||||
'class' string |
|
||||
'line' line-range
|
||||
|
||||
line-range ::= lineno |
|
||||
@ -203,6 +175,16 @@ format
|
||||
format "nfsd: SETATTR" // a neater 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
|
||||
The given line number or range of line numbers is compared
|
||||
against the line number of each ``pr_debug()`` callsite. A single
|
||||
@ -228,17 +210,16 @@ of the characters::
|
||||
The flags are::
|
||||
|
||||
p enables the pr_debug() callsite.
|
||||
f Include the function name in the printed message
|
||||
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)
|
||||
_ enables no flags.
|
||||
|
||||
For ``print_hex_dump_debug()`` and ``print_hex_dump_bytes()``, only ``p`` flag
|
||||
have meaning, other flags ignored.
|
||||
Decorator flags add to the message-prefix, in order:
|
||||
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 ``=``
|
||||
(mnemonic: what the flags are currently equal to).
|
||||
For ``print_hex_dump_debug()`` and ``print_hex_dump_bytes()``, only
|
||||
the ``p`` flag has meaning, other flags are ignored.
|
||||
|
||||
Note the regexp ``^[-+=][flmpt_]+$`` matches a flags specification.
|
||||
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
|
||||
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
|
||||
========
|
||||
@ -321,37 +302,31 @@ Examples
|
||||
::
|
||||
|
||||
// enable the message at line 1603 of file svcsock.c
|
||||
nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >
|
||||
<debugfs>/dynamic_debug/control
|
||||
:#> ddcmd 'file svcsock.c line 1603 +p'
|
||||
|
||||
// enable all the messages in file svcsock.c
|
||||
nullarbor:~ # echo -n 'file svcsock.c +p' >
|
||||
<debugfs>/dynamic_debug/control
|
||||
:#> ddcmd 'file svcsock.c +p'
|
||||
|
||||
// enable all the messages in the NFS server module
|
||||
nullarbor:~ # echo -n 'module nfsd +p' >
|
||||
<debugfs>/dynamic_debug/control
|
||||
:#> ddcmd 'module nfsd +p'
|
||||
|
||||
// enable all 12 messages in the function svc_process()
|
||||
nullarbor:~ # echo -n 'func svc_process +p' >
|
||||
<debugfs>/dynamic_debug/control
|
||||
:#> ddcmd 'func svc_process +p'
|
||||
|
||||
// disable all 12 messages in the function svc_process()
|
||||
nullarbor:~ # echo -n 'func svc_process -p' >
|
||||
<debugfs>/dynamic_debug/control
|
||||
:#> ddcmd 'func svc_process -p'
|
||||
|
||||
// enable messages for NFS calls READ, READLINK, READDIR and READDIR+.
|
||||
nullarbor:~ # echo -n 'format "nfsd: READ" +p' >
|
||||
<debugfs>/dynamic_debug/control
|
||||
:#> ddcmd 'format "nfsd: READ" +p'
|
||||
|
||||
// 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
|
||||
nullarbor:~ # echo -n '+p' > <debugfs>/dynamic_debug/control
|
||||
:#> ddcmd '+p' > /proc/dynamic_debug/control
|
||||
|
||||
// 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
|
||||
Kernel command line: ...
|
||||
@ -364,3 +339,38 @@ Examples
|
||||
dyndbg="file init/* +p #cmt ; func parse_one +p"
|
||||
// enable pr_debugs in 2 functions in a module loaded later
|
||||
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_uc()
|
||||
devm_ioremap_wc()
|
||||
devm_ioremap_np()
|
||||
devm_ioremap_resource() : checks resource, requests memory region, ioremaps
|
||||
devm_ioremap_resource_wc()
|
||||
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,
|
||||
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,
|
||||
|
@ -69,82 +69,17 @@ Changelog::
|
||||
Magic Name Number Structure File
|
||||
===================== ================ ======================== ==========================================
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
PCXX_MAGIC 0x5c6df104 channel ``drivers/char/pcxx.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``
|
||||
YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
|
||||
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
|
||||
QUEUE_MAGIC_FREE 0xf7e1c9a3 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``
|
||||
===================== ================ ======================== ==========================================
|
||||
|
||||
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
|
||||
===================== ================ ======================== ==========================================
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
PCXX_MAGIC 0x5c6df104 channel ``drivers/char/pcxx.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``
|
||||
YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
|
||||
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
|
||||
QUEUE_MAGIC_FREE 0xf7e1c9a3 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``
|
||||
===================== ================ ======================== ==========================================
|
||||
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
PCXX_MAGIC 0x5c6df104 channel ``drivers/char/pcxx.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``
|
||||
DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram ``drivers/scsi/gdth.h``
|
||||
YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
|
||||
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
|
||||
QUEUE_MAGIC_FREE 0xf7e1c9a3 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``
|
||||
===================== ================ ======================== ==========================================
|
||||
|
||||
|
||||
请注意,在声音记忆管理中仍然有一些特殊的为每个驱动定义的魔术值。查看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``
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
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``
|
||||
PCXX_MAGIC 0x5c6df104 channel ``drivers/char/pcxx.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``
|
||||
DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram ``drivers/scsi/gdth.h``
|
||||
YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c``
|
||||
CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c``
|
||||
QUEUE_MAGIC_FREE 0xf7e1c9a3 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``
|
||||
===================== ================ ======================== ==========================================
|
||||
|
||||
|
||||
請注意,在聲音記憶管理中仍然有一些特殊的爲每個驅動定義的魔術值。查看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
|
||||
F: include/linux/dynamic_debug.h
|
||||
F: lib/dynamic_debug.c
|
||||
M: Jim Cromie <jim.cromie@gmail.com>
|
||||
F: lib/test_dynamic_debug.c
|
||||
|
||||
DYNAMIC INTERRUPT MODERATION
|
||||
M: Tal Gilboa <talgi@nvidia.com>
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
#include <asm/sn/addrs.h>
|
||||
|
||||
#define GDA_MAGIC 0x58464552
|
||||
|
||||
/*
|
||||
* GDA Version History
|
||||
*
|
||||
|
@ -154,8 +154,6 @@ extern void driver_remove_groups(struct device_driver *drv,
|
||||
const struct attribute_group **groups);
|
||||
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 void device_block_probing(void);
|
||||
extern void device_unblock_probing(void);
|
||||
|
@ -260,7 +260,7 @@ EXPORT_SYMBOL_GPL(__class_create);
|
||||
*/
|
||||
void class_destroy(struct class *cls)
|
||||
{
|
||||
if ((cls == NULL) || (IS_ERR(cls)))
|
||||
if (IS_ERR_OR_NULL(cls))
|
||||
return;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -4170,7 +4170,7 @@ device_create_groups_vargs(struct class *class, struct device *parent,
|
||||
struct device *dev = NULL;
|
||||
int retval = -ENODEV;
|
||||
|
||||
if (class == NULL || IS_ERR(class))
|
||||
if (IS_ERR_OR_NULL(class))
|
||||
goto error;
|
||||
|
||||
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)
|
||||
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, "*");
|
||||
|
||||
return 1;
|
||||
|
@ -25,6 +25,47 @@ struct devcd_entry {
|
||||
struct device devcd_dev;
|
||||
void *data;
|
||||
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;
|
||||
ssize_t (*read)(char *buffer, loff_t offset, size_t count,
|
||||
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 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;
|
||||
}
|
||||
@ -112,7 +158,12 @@ static int devcd_free(struct device *dev, void *data)
|
||||
{
|
||||
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);
|
||||
mutex_unlock(&devcd->mutex);
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* 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,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
@ -278,13 +353,16 @@ void dev_coredumpm(struct device *dev, struct module *owner,
|
||||
devcd->read = read;
|
||||
devcd->free = free;
|
||||
devcd->failing_dev = get_device(dev);
|
||||
devcd->delete_work = false;
|
||||
|
||||
mutex_init(&devcd->mutex);
|
||||
device_initialize(&devcd->devcd_dev);
|
||||
|
||||
dev_set_name(&devcd->devcd_dev, "devcd%d",
|
||||
atomic_inc_return(&devcd_count));
|
||||
devcd->devcd_dev.class = &devcd_class;
|
||||
|
||||
mutex_lock(&devcd->mutex);
|
||||
if (device_add(&devcd->devcd_dev))
|
||||
goto put_device;
|
||||
|
||||
@ -301,10 +379,11 @@ void dev_coredumpm(struct device *dev, struct module *owner,
|
||||
|
||||
INIT_DELAYED_WORK(&devcd->del_wk, devcd_del);
|
||||
schedule_delayed_work(&devcd->del_wk, DEVCD_TIMEOUT);
|
||||
|
||||
mutex_unlock(&devcd->mutex);
|
||||
return;
|
||||
put_device:
|
||||
put_device(&devcd->devcd_dev);
|
||||
mutex_unlock(&devcd->mutex);
|
||||
put_module:
|
||||
module_put(owner);
|
||||
free:
|
||||
|
@ -117,7 +117,9 @@ static __always_inline struct devres * alloc_dr(dr_release_t release,
|
||||
if (unlikely(!dr))
|
||||
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);
|
||||
dr->node.release = release;
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include <linux/property.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 ?
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -157,8 +157,6 @@ static struct dentry *nbd_dbg_dir;
|
||||
|
||||
#define nbd_name(nbd) ((nbd)->disk->disk_name)
|
||||
|
||||
#define NBD_MAGIC 0x68797548
|
||||
|
||||
#define NBD_DEF_BLKSIZE_BITS 10
|
||||
|
||||
static unsigned int nbds_max = 16;
|
||||
|
@ -51,6 +51,18 @@ config DRM_DEBUG_MM
|
||||
|
||||
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
|
||||
tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS
|
||||
depends on DRM && KUNIT
|
||||
|
@ -3,6 +3,8 @@
|
||||
# Makefile for the drm device driver. This driver provides support for the
|
||||
# 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_file.o drm_gem.o drm_ioctl.o \
|
||||
drm_drv.o \
|
||||
|
@ -38,6 +38,8 @@
|
||||
#include <linux/mmu_notifier.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/cc_platform.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/dynamic_debug.h>
|
||||
|
||||
#include "amdgpu.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);
|
||||
|
||||
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 = {
|
||||
.mutex = __MUTEX_INITIALIZER(mgpu_info.mutex),
|
||||
.delayed_reset_work = __DELAYED_WORK_INITIALIZER(
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/string_helpers.h>
|
||||
#include <linux/dynamic_debug.h>
|
||||
|
||||
#include <drm/display/drm_dp_helper.h>
|
||||
#include <drm/display/drm_dp_mst_helper.h>
|
||||
@ -40,6 +41,18 @@
|
||||
|
||||
#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 backlight_device *base;
|
||||
struct drm_dp_aux *aux;
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/dynamic_debug.h>
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
@ -50,6 +51,18 @@
|
||||
|
||||
#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
|
||||
*
|
||||
|
@ -23,14 +23,13 @@
|
||||
* Rob Clark <robdclark@gmail.com>
|
||||
*/
|
||||
|
||||
#define DEBUG /* for pr_debug() */
|
||||
|
||||
#include <linux/stdarg.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dynamic_debug.h>
|
||||
|
||||
#include <drm/drm.h>
|
||||
#include <drm/drm_drv.h>
|
||||
@ -40,7 +39,7 @@
|
||||
* __drm_debug: Enable debug output.
|
||||
* 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);
|
||||
|
||||
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 7 (0x80) will enable LEASE messages (leasing code)\n"
|
||||
"\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)
|
||||
{
|
||||
@ -162,7 +184,8 @@ EXPORT_SYMBOL(__drm_printfn_info);
|
||||
|
||||
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);
|
||||
|
||||
@ -256,15 +279,16 @@ void drm_dev_printk(const struct device *dev, const char *level,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dev_printk);
|
||||
|
||||
void drm_dev_dbg(const struct device *dev, enum drm_debug_category category,
|
||||
const char *format, ...)
|
||||
void __drm_dev_dbg(struct _ddebug *desc, const struct device *dev,
|
||||
enum drm_debug_category category, const char *format, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
|
||||
if (!drm_debug_enabled(category))
|
||||
if (!__drm_debug_enabled(category))
|
||||
return;
|
||||
|
||||
/* we know we are printing for either syslog, tracefs, or both */
|
||||
va_start(args, format);
|
||||
vaf.fmt = format;
|
||||
vaf.va = &args;
|
||||
@ -278,14 +302,14 @@ void drm_dev_dbg(const struct device *dev, enum drm_debug_category category,
|
||||
|
||||
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;
|
||||
va_list args;
|
||||
|
||||
if (!drm_debug_enabled(category))
|
||||
if (!__drm_debug_enabled(category))
|
||||
return;
|
||||
|
||||
va_start(args, format);
|
||||
@ -297,7 +321,7 @@ void __drm_dbg(enum drm_debug_category category, const char *format, ...)
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
EXPORT_SYMBOL(__drm_dbg);
|
||||
EXPORT_SYMBOL(___drm_dbg);
|
||||
|
||||
void __drm_err(const char *format, ...)
|
||||
{
|
||||
|
@ -29,6 +29,18 @@
|
||||
#include "i915_params.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) \
|
||||
module_param_named(name, i915_modparams.name, T, perm); \
|
||||
MODULE_PARM_DESC(name, desc)
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/vga_switcheroo.h>
|
||||
#include <linux/mmu_notifier.h>
|
||||
#include <linux/dynamic_debug.h>
|
||||
|
||||
#include <drm/drm_aperture.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
@ -70,6 +71,18 @@
|
||||
#include "nouveau_svm.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");
|
||||
static char *nouveau_config;
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
@ -1136,17 +1136,7 @@ static int debugfs_show_regset32(struct seq_file *s, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int debugfs_open_regset32(struct inode *inode, struct file *file)
|
||||
{
|
||||
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,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(debugfs_regset32);
|
||||
|
||||
/**
|
||||
* 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 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);
|
||||
|
||||
|
@ -82,6 +82,8 @@ struct debugfs_mount_opts {
|
||||
kuid_t uid;
|
||||
kgid_t gid;
|
||||
umode_t mode;
|
||||
/* Opt_* bitfield. */
|
||||
unsigned int opts;
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -111,6 +113,7 @@ static int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts)
|
||||
kgid_t gid;
|
||||
char *p;
|
||||
|
||||
opts->opts = 0;
|
||||
opts->mode = DEBUGFS_DEFAULT_MODE;
|
||||
|
||||
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
|
||||
*/
|
||||
}
|
||||
|
||||
opts->opts |= BIT(token);
|
||||
}
|
||||
|
||||
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 inode *inode = d_inode(sb->s_root);
|
||||
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;
|
||||
inode->i_gid = opts->gid;
|
||||
if (!remount || opts->opts & BIT(Opt_mode)) {
|
||||
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)
|
||||
@ -175,7 +198,7 @@ static int debugfs_remount(struct super_block *sb, int *flags, char *data)
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
debugfs_apply_options(sb);
|
||||
debugfs_apply_options_remount(sb);
|
||||
|
||||
fail:
|
||||
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);
|
||||
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);
|
||||
|
||||
if (kernfs_lockdep(kn)) {
|
||||
@ -480,7 +490,6 @@ static void kernfs_drain(struct kernfs_node *kn)
|
||||
lock_contended(&kn->dep_map, _RET_IP_);
|
||||
}
|
||||
|
||||
/* but everyone should wait for draining */
|
||||
wait_event(root->deactivate_waitq,
|
||||
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_);
|
||||
}
|
||||
|
||||
kernfs_drain_open_files(kn);
|
||||
if (kernfs_should_drain_open_files(kn))
|
||||
kernfs_drain_open_files(kn);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)))
|
||||
if (unlikely(!kernfs_active(kn) || !atomic_inc_not_zero(&kn->count)))
|
||||
goto err_unlock;
|
||||
|
||||
spin_unlock(&kernfs_idr_lock);
|
||||
@ -743,10 +747,7 @@ int kernfs_add_one(struct kernfs_node *kn)
|
||||
goto out_unlock;
|
||||
|
||||
ret = -ENOENT;
|
||||
if (parent->flags & KERNFS_EMPTY_DIR)
|
||||
goto out_unlock;
|
||||
|
||||
if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent))
|
||||
if (parent->flags & (KERNFS_REMOVING | KERNFS_EMPTY_DIR))
|
||||
goto out_unlock;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
* @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);
|
||||
|
||||
pos = NULL;
|
||||
while ((pos = kernfs_next_descendant_post(pos, kn))) {
|
||||
if (pos->flags & KERNFS_ACTIVATED)
|
||||
continue;
|
||||
while ((pos = kernfs_next_descendant_post(pos, kn)))
|
||||
kernfs_activate_one(pos);
|
||||
|
||||
WARN_ON_ONCE(pos->parent && RB_EMPTY_NODE(&pos->rb));
|
||||
WARN_ON_ONCE(atomic_read(&pos->active) != KN_DEACTIVATED_BIAS);
|
||||
up_write(&root->kernfs_rwsem);
|
||||
}
|
||||
|
||||
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);
|
||||
@ -1358,34 +1401,27 @@ static void __kernfs_remove(struct kernfs_node *kn)
|
||||
|
||||
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;
|
||||
while ((pos = kernfs_next_descendant_post(pos, kn)))
|
||||
while ((pos = kernfs_next_descendant_post(pos, kn))) {
|
||||
pos->flags |= KERNFS_REMOVING;
|
||||
if (kernfs_active(pos))
|
||||
atomic_add(KN_DEACTIVATED_BIAS, &pos->active);
|
||||
}
|
||||
|
||||
/* deactivate and unlink the subtree node-by-node */
|
||||
do {
|
||||
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
|
||||
* the function returns. Make sure it doesn't go away
|
||||
* underneath us.
|
||||
*/
|
||||
kernfs_get(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_drain(pos);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
kn = kernfs_find_ns(parent, name, ns);
|
||||
if (kn)
|
||||
if (kn) {
|
||||
kernfs_get(kn);
|
||||
__kernfs_remove(kn);
|
||||
kernfs_put(kn);
|
||||
}
|
||||
|
||||
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;
|
||||
wait_queue_head_t poll;
|
||||
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: 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.
|
||||
* of_on - Return the kernfs_open_node of the specified kernfs_open_file
|
||||
* @of: taret kernfs_open_file
|
||||
*/
|
||||
static struct kernfs_open_node *
|
||||
kernfs_deref_open_node(struct kernfs_open_file *of, struct kernfs_node *kn)
|
||||
static struct kernfs_open_node *of_on(struct kernfs_open_file *of)
|
||||
{
|
||||
struct kernfs_open_node *on;
|
||||
|
||||
on = rcu_dereference_check(kn->attr.open, !list_empty(&of->list));
|
||||
|
||||
return on;
|
||||
return rcu_dereference_protected(of->kn->attr.open,
|
||||
!list_empty(&of->list));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@ -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.
|
||||
*/
|
||||
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,
|
||||
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)
|
||||
{
|
||||
struct kernfs_open_file *of = sf->private;
|
||||
struct kernfs_open_node *on = kernfs_deref_open_node(of, of->kn);
|
||||
|
||||
if (!on)
|
||||
return -EINVAL;
|
||||
|
||||
of->event = atomic_read(&on->event);
|
||||
of->event = atomic_read(&of_on(of)->event);
|
||||
|
||||
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);
|
||||
ssize_t len = min_t(size_t, iov_iter_count(iter), PAGE_SIZE);
|
||||
const struct kernfs_ops *ops;
|
||||
struct kernfs_open_node *on;
|
||||
char *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;
|
||||
}
|
||||
|
||||
on = kernfs_deref_open_node(of, of->kn);
|
||||
if (!on) {
|
||||
len = -EINVAL;
|
||||
mutex_unlock(&of->mutex);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
of->event = atomic_read(&on->event);
|
||||
of->event = atomic_read(&of_on(of)->event);
|
||||
|
||||
ops = kernfs_ops(of->kn);
|
||||
if (ops->read)
|
||||
@ -553,6 +529,7 @@ static int kernfs_fop_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
|
||||
rc = 0;
|
||||
of->mmapped = true;
|
||||
of_on(of)->nr_mmapped++;
|
||||
of->vm_ops = vma->vm_ops;
|
||||
vma->vm_ops = &kernfs_vm_ops;
|
||||
out_put:
|
||||
@ -580,31 +557,30 @@ out_unlock:
|
||||
static int kernfs_get_open_node(struct kernfs_node *kn,
|
||||
struct kernfs_open_file *of)
|
||||
{
|
||||
struct kernfs_open_node *on, *new_on = NULL;
|
||||
struct mutex *mutex = NULL;
|
||||
struct kernfs_open_node *on;
|
||||
struct mutex *mutex;
|
||||
|
||||
mutex = kernfs_open_file_mutex_lock(kn);
|
||||
on = kernfs_deref_open_node_protected(kn);
|
||||
on = kernfs_deref_open_node_locked(kn);
|
||||
|
||||
if (on) {
|
||||
list_add_tail(&of->list, &on->files);
|
||||
mutex_unlock(mutex);
|
||||
return 0;
|
||||
} else {
|
||||
if (!on) {
|
||||
/* not there, initialize a new one */
|
||||
new_on = kmalloc(sizeof(*new_on), GFP_KERNEL);
|
||||
if (!new_on) {
|
||||
on = kzalloc(sizeof(*on), GFP_KERNEL);
|
||||
if (!on) {
|
||||
mutex_unlock(mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
atomic_set(&new_on->event, 1);
|
||||
init_waitqueue_head(&new_on->poll);
|
||||
INIT_LIST_HEAD(&new_on->files);
|
||||
list_add_tail(&of->list, &new_on->files);
|
||||
rcu_assign_pointer(kn->attr.open, new_on);
|
||||
atomic_set(&on->event, 1);
|
||||
init_waitqueue_head(&on->poll);
|
||||
INIT_LIST_HEAD(&on->files);
|
||||
rcu_assign_pointer(kn->attr.open, 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;
|
||||
}
|
||||
|
||||
@ -613,6 +589,7 @@ static int kernfs_get_open_node(struct kernfs_node *kn,
|
||||
*
|
||||
* @kn: target kernfs_node
|
||||
* @of: associated kernfs_open_file
|
||||
* @open_failed: ->open() failed, cancel ->release()
|
||||
*
|
||||
* Unlink @of from list of @kn's associated open files. If list of
|
||||
* associated open files becomes empty, disassociate and free
|
||||
@ -622,21 +599,30 @@ static int kernfs_get_open_node(struct kernfs_node *kn,
|
||||
* None.
|
||||
*/
|
||||
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 mutex *mutex = NULL;
|
||||
struct mutex *mutex;
|
||||
|
||||
mutex = kernfs_open_file_mutex_lock(kn);
|
||||
|
||||
on = kernfs_deref_open_node_protected(kn);
|
||||
on = kernfs_deref_open_node_locked(kn);
|
||||
if (!on) {
|
||||
mutex_unlock(mutex);
|
||||
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);
|
||||
}
|
||||
|
||||
if (list_empty(&on->files)) {
|
||||
rcu_assign_pointer(kn->attr.open, NULL);
|
||||
@ -763,7 +749,7 @@ static int kernfs_fop_open(struct inode *inode, struct file *file)
|
||||
return 0;
|
||||
|
||||
err_put_node:
|
||||
kernfs_unlink_open_file(kn, of);
|
||||
kernfs_unlink_open_file(kn, of, true);
|
||||
err_seq_release:
|
||||
seq_release(inode, file);
|
||||
err_free:
|
||||
@ -795,6 +781,7 @@ static void kernfs_release_file(struct kernfs_node *kn,
|
||||
*/
|
||||
kn->attr.ops->release(of);
|
||||
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_open_file *of = kernfs_of(filp);
|
||||
struct mutex *mutex = NULL;
|
||||
|
||||
if (kn->flags & KERNFS_HAS_RELEASE) {
|
||||
struct mutex *mutex;
|
||||
|
||||
mutex = kernfs_open_file_mutex_lock(kn);
|
||||
kernfs_release_file(kn, of);
|
||||
mutex_unlock(mutex);
|
||||
}
|
||||
|
||||
kernfs_unlink_open_file(kn, of);
|
||||
kernfs_unlink_open_file(kn, of, false);
|
||||
seq_release(inode, filp);
|
||||
kfree(of->prealloc_buf);
|
||||
kfree(of);
|
||||
@ -818,28 +806,33 @@ static int kernfs_fop_release(struct inode *inode, struct file *filp)
|
||||
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)
|
||||
{
|
||||
struct kernfs_open_node *on;
|
||||
struct kernfs_open_file *of;
|
||||
struct mutex *mutex = NULL;
|
||||
|
||||
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;
|
||||
struct mutex *mutex;
|
||||
|
||||
mutex = kernfs_open_file_mutex_lock(kn);
|
||||
on = kernfs_deref_open_node_protected(kn);
|
||||
on = kernfs_deref_open_node_locked(kn);
|
||||
if (!on) {
|
||||
mutex_unlock(mutex);
|
||||
return;
|
||||
@ -848,13 +841,17 @@ void kernfs_drain_open_files(struct kernfs_node *kn)
|
||||
list_for_each_entry(of, &on->files, list) {
|
||||
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);
|
||||
of->mmapped = false;
|
||||
on->nr_mmapped--;
|
||||
}
|
||||
|
||||
if (kn->flags & KERNFS_HAS_RELEASE)
|
||||
kernfs_release_file(kn, of);
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(on->nr_mmapped || on->nr_to_release);
|
||||
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)
|
||||
{
|
||||
struct kernfs_node *kn = kernfs_dentry_node(of->file->f_path.dentry);
|
||||
struct kernfs_open_node *on = kernfs_deref_open_node(of, kn);
|
||||
|
||||
if (!on)
|
||||
return EPOLLERR;
|
||||
struct kernfs_open_node *on = of_on(of);
|
||||
|
||||
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;
|
||||
|
||||
bool kernfs_should_drain_open_files(struct kernfs_node *kn);
|
||||
void kernfs_drain_open_files(struct kernfs_node *kn);
|
||||
|
||||
/*
|
||||
|
@ -353,6 +353,9 @@
|
||||
*(__tracepoints) \
|
||||
/* implement dynamic printk debug */ \
|
||||
. = ALIGN(8); \
|
||||
__start___dyndbg_classes = .; \
|
||||
KEEP(*(__dyndbg_classes)) \
|
||||
__stop___dyndbg_classes = .; \
|
||||
__start___dyndbg = .; \
|
||||
KEEP(*(__dyndbg)) \
|
||||
__stop___dyndbg = .; \
|
||||
|
@ -31,11 +31,12 @@
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/dynamic_debug.h>
|
||||
|
||||
#include <drm/drm.h>
|
||||
|
||||
/* Do *not* use outside of drm_print.[ch]! */
|
||||
extern unsigned int __drm_debug;
|
||||
extern unsigned long __drm_debug;
|
||||
|
||||
/**
|
||||
* DOC: print
|
||||
@ -275,55 +276,75 @@ static inline struct drm_printer drm_err_printer(const char *prefix)
|
||||
*
|
||||
*/
|
||||
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_memory.c, ...
|
||||
*/
|
||||
DRM_UT_CORE = 0x01,
|
||||
DRM_UT_CORE,
|
||||
/**
|
||||
* @DRM_UT_DRIVER: Used in the vendor specific part of the driver: i915,
|
||||
* radeon, ... macro.
|
||||
*/
|
||||
DRM_UT_DRIVER = 0x02,
|
||||
DRM_UT_DRIVER,
|
||||
/**
|
||||
* @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 = 0x08,
|
||||
DRM_UT_PRIME,
|
||||
/**
|
||||
* @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 = 0x20,
|
||||
DRM_UT_VBL,
|
||||
/**
|
||||
* @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 = 0x80,
|
||||
DRM_UT_LEASE,
|
||||
/**
|
||||
* @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 = 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
|
||||
*
|
||||
@ -333,9 +354,10 @@ static inline bool drm_debug_enabled(enum drm_debug_category category)
|
||||
__printf(3, 4)
|
||||
void drm_dev_printk(const struct device *dev, const char *level,
|
||||
const char *format, ...);
|
||||
__printf(3, 4)
|
||||
void drm_dev_dbg(const struct device *dev, enum drm_debug_category category,
|
||||
const char *format, ...);
|
||||
struct _ddebug;
|
||||
__printf(4, 5)
|
||||
void __drm_dev_dbg(struct _ddebug *desc, const struct device *dev,
|
||||
enum drm_debug_category category, const char *format, ...);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
@ -457,7 +488,7 @@ void drm_dev_dbg(const struct device *dev, enum drm_debug_category category,
|
||||
|
||||
#define drm_dbg_core(drm, fmt, ...) \
|
||||
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__)
|
||||
#define drm_dbg_kms(drm, fmt, ...) \
|
||||
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, ...) \
|
||||
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
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
__printf(2, 3)
|
||||
void __drm_dbg(enum drm_debug_category category, const char *format, ...);
|
||||
__printf(3, 4)
|
||||
void ___drm_dbg(struct _ddebug *desc, enum drm_debug_category category, const char *format, ...);
|
||||
__printf(1, 2)
|
||||
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 */
|
||||
|
||||
#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_rm_cftypes(struct cftype *cfts);
|
||||
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 cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry);
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <linux/jump_label.h>
|
||||
#endif
|
||||
|
||||
#include <linux/build_bug.h>
|
||||
|
||||
/*
|
||||
* An instance of this structure is created in a special
|
||||
* ELF section at every dynamic debug callsite. At runtime,
|
||||
@ -21,6 +23,9 @@ struct _ddebug {
|
||||
const char *filename;
|
||||
const char *format;
|
||||
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 bits here are changed dynamically when the user
|
||||
@ -51,15 +56,82 @@ struct _ddebug {
|
||||
#endif
|
||||
} __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)
|
||||
|
||||
/* exported for module authors to exercise >control */
|
||||
int dynamic_debug_exec_queries(const char *query, const char *modname);
|
||||
int ddebug_add_module(struct _ddebug_info *dyndbg, 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 __printf(2, 3)
|
||||
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 char *fmt, ...);
|
||||
|
||||
#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) \
|
||||
#define DEFINE_DYNAMIC_DEBUG_METADATA_CLS(name, cls, fmt) \
|
||||
static struct _ddebug __aligned(8) \
|
||||
__section("__dyndbg") name = { \
|
||||
.modname = KBUILD_MODNAME, \
|
||||
@ -96,8 +168,14 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
|
||||
.format = (fmt), \
|
||||
.lineno = __LINE__, \
|
||||
.flags = _DPRINTK_FLAGS_DEFAULT, \
|
||||
.class_id = cls, \
|
||||
_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
|
||||
|
||||
@ -128,17 +206,34 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
|
||||
|
||||
#endif /* CONFIG_JUMP_LABEL */
|
||||
|
||||
#define __dynamic_func_call(id, fmt, func, ...) do { \
|
||||
DEFINE_DYNAMIC_DEBUG_METADATA(id, fmt); \
|
||||
if (DYNAMIC_DEBUG_BRANCH(id)) \
|
||||
func(&id, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define __dynamic_func_call_no_desc(id, fmt, func, ...) do { \
|
||||
DEFINE_DYNAMIC_DEBUG_METADATA(id, fmt); \
|
||||
/*
|
||||
* Factory macros: ($prefix)dynamic_func_call($suffix)
|
||||
*
|
||||
* Lower layer (with __ prefix) gets the callsite metadata, and wraps
|
||||
* the func inside a debug-branch/static-key construct. Upper layer
|
||||
* (with _ prefix) does the UNIQUE_ID once, so that lower can ref the
|
||||
* name/label multiple times, and tie the elements together.
|
||||
* 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)) \
|
||||
func(__VA_ARGS__); \
|
||||
func(&id, ##__VA_ARGS__); \
|
||||
} 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
|
||||
@ -148,22 +243,33 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
|
||||
* the varargs. Note that fmt is repeated in invocations of this
|
||||
* 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, ...) \
|
||||
__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
|
||||
* passed as the first argument to the function; it is only called
|
||||
* with precisely the macro's varargs.
|
||||
*/
|
||||
#define _dynamic_func_call_no_desc(fmt, func, ...) \
|
||||
__dynamic_func_call_no_desc(__UNIQUE_ID(ddebug), fmt, func, ##__VA_ARGS__)
|
||||
#define _dynamic_func_call_cls_no_desc(cls, fmt, func, ...) \
|
||||
__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, ...) \
|
||||
_dynamic_func_call(fmt, __dynamic_pr_debug, \
|
||||
_dynamic_func_call(fmt, __dynamic_pr_debug, \
|
||||
pr_fmt(fmt), ##__VA_ARGS__)
|
||||
|
||||
#define dynamic_dev_dbg(dev, fmt, ...) \
|
||||
_dynamic_func_call(fmt,__dynamic_dev_dbg, \
|
||||
_dynamic_func_call(fmt, __dynamic_dev_dbg, \
|
||||
dev, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define dynamic_netdev_dbg(dev, fmt, ...) \
|
||||
@ -181,14 +287,24 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
|
||||
KERN_DEBUG, prefix_str, prefix_type, \
|
||||
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 */
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
static inline int ddebug_add_module(struct _ddebug *tab, unsigned int n,
|
||||
const char *modname)
|
||||
static inline int ddebug_add_module(struct _ddebug_info *dinfo, const char *modname)
|
||||
{
|
||||
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,
|
||||
const char *modname)
|
||||
{
|
||||
if (strstr(param, "dyndbg")) {
|
||||
if (!strcmp(param, "dyndbg")) {
|
||||
/* avoid pr_warn(), which wants pr_fmt() fully defined */
|
||||
printk(KERN_WARNING "dyndbg param is supported only in "
|
||||
"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); \
|
||||
} while (0)
|
||||
|
||||
static inline int dynamic_debug_exec_queries(const char *query, const char *modname)
|
||||
{
|
||||
pr_warn("kernel not built with CONFIG_DYNAMIC_DEBUG_CORE\n");
|
||||
return 0;
|
||||
}
|
||||
struct kernel_param;
|
||||
static inline int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
|
||||
{ return 0; }
|
||||
static inline int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
|
||||
{ return 0; }
|
||||
|
||||
#endif /* !CONFIG_DYNAMIC_DEBUG_CORE */
|
||||
|
||||
extern const struct kernel_param_ops param_ops_dyndbg_classes;
|
||||
|
||||
#endif
|
||||
|
@ -59,8 +59,6 @@ void __iomem *devm_ioremap_uc(struct device *dev, resource_size_t offset,
|
||||
resource_size_t size);
|
||||
void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset,
|
||||
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);
|
||||
int check_signature(const volatile void __iomem *io_addr,
|
||||
const unsigned char *signature, int length);
|
||||
|
@ -108,10 +108,12 @@ enum kernfs_node_flag {
|
||||
KERNFS_HAS_SEQ_SHOW = 0x0040,
|
||||
KERNFS_HAS_MMAP = 0x0080,
|
||||
KERNFS_LOCKDEP = 0x0100,
|
||||
KERNFS_HIDDEN = 0x0200,
|
||||
KERNFS_SUICIDAL = 0x0400,
|
||||
KERNFS_SUICIDED = 0x0800,
|
||||
KERNFS_EMPTY_DIR = 0x1000,
|
||||
KERNFS_HAS_RELEASE = 0x2000,
|
||||
KERNFS_REMOVING = 0x4000,
|
||||
};
|
||||
|
||||
/* @flags for kernfs_create_root() */
|
||||
@ -429,6 +431,7 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
|
||||
const char *name,
|
||||
struct kernfs_node *target);
|
||||
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_break_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,
|
||||
};
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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_gpl[];
|
||||
|
||||
#include <linux/dynamic_debug.h>
|
||||
struct load_info {
|
||||
const char *name;
|
||||
/* pointer to module in temporary copy, freed at end of load_module() */
|
||||
@ -62,8 +63,7 @@ struct load_info {
|
||||
Elf_Shdr *sechdrs;
|
||||
char *secstrings, *strtab;
|
||||
unsigned long symoffs, stroffs, init_typeoffs, core_typeoffs;
|
||||
struct _ddebug *debug;
|
||||
unsigned int num_debug;
|
||||
struct _ddebug_info dyndbg;
|
||||
bool sig_ok;
|
||||
#ifdef CONFIG_KALLSYMS
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
@ -2107,8 +2107,10 @@ static int find_module_sections(struct module *mod, struct load_info *info)
|
||||
if (section_addr(info, "__obsparm"))
|
||||
pr_warn("%s: Ignoring obsolete parameters\n", mod->name);
|
||||
|
||||
info->debug = section_objs(info, "__dyndbg",
|
||||
sizeof(*info->debug), &info->num_debug);
|
||||
info->dyndbg.descs = section_objs(info, "__dyndbg",
|
||||
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;
|
||||
}
|
||||
@ -2799,7 +2801,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
|
||||
}
|
||||
|
||||
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_module_init(mod);
|
||||
@ -2863,7 +2865,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
|
||||
|
||||
ddebug_cleanup:
|
||||
ftrace_release_mod(mod);
|
||||
dynamic_debug_remove(mod, info->debug);
|
||||
dynamic_debug_remove(mod, &info->dyndbg);
|
||||
synchronize_rcu();
|
||||
kfree(mod->args);
|
||||
free_arch_cleanup:
|
||||
|
@ -2572,6 +2572,16 @@ config TEST_STATIC_KEYS
|
||||
|
||||
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
|
||||
tristate "kmod stress tester"
|
||||
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_STATIC_KEYS) += test_static_keys.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_SCANF) += test_scanf.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);
|
||||
|
||||
/**
|
||||
* 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()
|
||||
* @dev: Generic device to unmap for
|
||||
|
@ -41,9 +41,11 @@
|
||||
|
||||
extern struct _ddebug __start___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 list_head link;
|
||||
struct list_head link, maps;
|
||||
const char *mod_name;
|
||||
unsigned int num_ddebugs;
|
||||
struct _ddebug *ddebugs;
|
||||
@ -54,12 +56,13 @@ struct ddebug_query {
|
||||
const char *module;
|
||||
const char *function;
|
||||
const char *format;
|
||||
const char *class_string;
|
||||
unsigned int first_lineno, last_lineno;
|
||||
};
|
||||
|
||||
struct ddebug_iter {
|
||||
struct ddebug_table *table;
|
||||
unsigned int idx;
|
||||
int idx;
|
||||
};
|
||||
|
||||
struct flag_settings {
|
||||
@ -134,15 +137,33 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
|
||||
fmtlen--;
|
||||
}
|
||||
|
||||
v3pr_info("%s: func=\"%s\" file=\"%s\" module=\"%s\" format=\"%.*s\" lineno=%u-%u\n",
|
||||
msg,
|
||||
query->function ?: "",
|
||||
query->filename ?: "",
|
||||
query->module ?: "",
|
||||
fmtlen, query->format ?: "",
|
||||
query->first_lineno, query->last_lineno);
|
||||
v3pr_info("%s: func=\"%s\" file=\"%s\" module=\"%s\" format=\"%.*s\" lineno=%u-%u class=%s\n",
|
||||
msg,
|
||||
query->function ?: "",
|
||||
query->filename ?: "",
|
||||
query->module ?: "",
|
||||
fmtlen, query->format ?: "",
|
||||
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
|
||||
* 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;
|
||||
unsigned int newflags;
|
||||
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 */
|
||||
mutex_lock(&ddebug_lock);
|
||||
@ -167,9 +190,22 @@ static int ddebug_change(const struct ddebug_query *query,
|
||||
!match_wildcard(query->module, dt->mod_name))
|
||||
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++) {
|
||||
struct _ddebug *dp = &dt->ddebugs[i];
|
||||
|
||||
/* match site against query-class */
|
||||
if (dp->class_id != valid_class)
|
||||
continue;
|
||||
|
||||
/* match against the source filename */
|
||||
if (query->filename &&
|
||||
!match_wildcard(query->filename, dp->filename) &&
|
||||
@ -211,16 +247,18 @@ static int ddebug_change(const struct ddebug_query *query,
|
||||
continue;
|
||||
#ifdef CONFIG_JUMP_LABEL
|
||||
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);
|
||||
} else if (modifiers->flags & _DPRINTK_FLAGS_PRINT)
|
||||
} else if (newflags & _DPRINTK_FLAGS_PRINT) {
|
||||
static_branch_enable(&dp->key.dd_key_true);
|
||||
}
|
||||
#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;
|
||||
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);
|
||||
@ -383,10 +421,6 @@ static int ddebug_parse_query(char *words[], int nwords,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (modname)
|
||||
/* support $modname.dyndbg=<multiple queries> */
|
||||
query->module = modname;
|
||||
|
||||
for (i = 0; i < nwords; i += 2) {
|
||||
char *keyword = words[i];
|
||||
char *arg = words[i+1];
|
||||
@ -420,6 +454,8 @@ static int ddebug_parse_query(char *words[], int nwords,
|
||||
} else if (!strcmp(keyword, "line")) {
|
||||
if (parse_linerange(query, arg))
|
||||
return -EINVAL;
|
||||
} else if (!strcmp(keyword, "class")) {
|
||||
rc = check_set(&query->class_string, arg, "class");
|
||||
} else {
|
||||
pr_err("unknown keyword \"%s\"\n", keyword);
|
||||
return -EINVAL;
|
||||
@ -427,6 +463,13 @@ static int ddebug_parse_query(char *words[], int nwords,
|
||||
if (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");
|
||||
return 0;
|
||||
}
|
||||
@ -553,34 +596,217 @@ static int ddebug_exec_queries(char *query, const char *modname)
|
||||
return nfound;
|
||||
}
|
||||
|
||||
/**
|
||||
* dynamic_debug_exec_queries - select and change dynamic-debug prints
|
||||
* @query: query-string described in admin-guide/dynamic-debug-howto
|
||||
* @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)
|
||||
/* apply a new bitmap to the sys-knob's current bit-state */
|
||||
static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
|
||||
unsigned long *new_bits, unsigned long *old_bits)
|
||||
{
|
||||
int rc;
|
||||
char *qry; /* writable copy of query */
|
||||
#define QUERY_SIZE 128
|
||||
char query[QUERY_SIZE];
|
||||
const struct ddebug_class_map *map = dcp->map;
|
||||
int matches = 0;
|
||||
int bi, ct;
|
||||
|
||||
if (!query) {
|
||||
pr_err("non-null query/command string expected\n");
|
||||
v2pr_info("apply: 0x%lx to: 0x%lx\n", *new_bits, *old_bits);
|
||||
|
||||
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;
|
||||
}
|
||||
qry = kstrndup(query, PAGE_SIZE, GFP_KERNEL);
|
||||
if (!qry)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = ddebug_exec_queries(qry, modname);
|
||||
kfree(qry);
|
||||
return rc;
|
||||
/* only _BITS,_NUM (numeric) map-types get here */
|
||||
switch (map->map_type) {
|
||||
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
|
||||
|
||||
@ -803,13 +1029,12 @@ static struct _ddebug *ddebug_iter_first(struct ddebug_iter *iter)
|
||||
{
|
||||
if (list_empty(&ddebug_tables)) {
|
||||
iter->table = NULL;
|
||||
iter->idx = 0;
|
||||
return NULL;
|
||||
}
|
||||
iter->table = list_entry(ddebug_tables.next,
|
||||
struct ddebug_table, link);
|
||||
iter->idx = 0;
|
||||
return &iter->table->ddebugs[iter->idx];
|
||||
iter->idx = iter->table->num_ddebugs;
|
||||
return &iter->table->ddebugs[--iter->idx];
|
||||
}
|
||||
|
||||
/*
|
||||
@ -822,15 +1047,16 @@ static struct _ddebug *ddebug_iter_next(struct ddebug_iter *iter)
|
||||
{
|
||||
if (iter->table == NULL)
|
||||
return NULL;
|
||||
if (++iter->idx == iter->table->num_ddebugs) {
|
||||
if (--iter->idx < 0) {
|
||||
/* iterate to next table */
|
||||
iter->idx = 0;
|
||||
if (list_is_last(&iter->table->link, &ddebug_tables)) {
|
||||
iter->table = NULL;
|
||||
return NULL;
|
||||
}
|
||||
iter->table = list_entry(iter->table->link.next,
|
||||
struct ddebug_table, link);
|
||||
iter->idx = iter->table->num_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;
|
||||
}
|
||||
|
||||
#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()
|
||||
* 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 *dp = p;
|
||||
struct flagsbuf flags;
|
||||
char const *class;
|
||||
|
||||
if (p == SEQ_START_TOKEN) {
|
||||
seq_puts(m,
|
||||
@ -898,8 +1139,17 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
|
||||
trim_prefix(dp->filename), dp->lineno,
|
||||
iter->table->mod_name, dp->function,
|
||||
ddebug_describe_flags(dp->flags, &flags));
|
||||
seq_escape(m, dp->format, "\t\r\n\"");
|
||||
seq_puts(m, "\"\n");
|
||||
seq_escape_str(m, dp->format, ESCAPE_SPACE, "\t\r\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;
|
||||
}
|
||||
@ -943,18 +1193,50 @@ static const struct proc_ops proc_fops = {
|
||||
.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
|
||||
* and add it to the global list.
|
||||
*/
|
||||
int ddebug_add_module(struct _ddebug *tab, unsigned int n,
|
||||
const char *name)
|
||||
static int __ddebug_add_module(struct _ddebug_info *di, unsigned int base,
|
||||
const char *modname)
|
||||
{
|
||||
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);
|
||||
if (dt == NULL) {
|
||||
pr_err("error adding module: %s\n", name);
|
||||
pr_err("error adding module: %s\n", modname);
|
||||
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
|
||||
* this struct ddebug_table.
|
||||
*/
|
||||
dt->mod_name = name;
|
||||
dt->num_ddebugs = n;
|
||||
dt->ddebugs = tab;
|
||||
dt->mod_name = modname;
|
||||
dt->ddebugs = di->descs;
|
||||
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);
|
||||
list_add(&dt->link, &ddebug_tables);
|
||||
list_add_tail(&dt->link, &ddebug_tables);
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
static int ddebug_dyndbg_param_cb(char *param, char *val,
|
||||
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)
|
||||
{
|
||||
struct _ddebug *iter, *iter_start;
|
||||
const char *modname = NULL;
|
||||
struct _ddebug *iter, *iter_mod_start;
|
||||
int ret, i, mod_sites, mod_ct;
|
||||
const char *modname;
|
||||
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 (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
|
||||
@ -1098,30 +1397,39 @@ static int __init dynamic_debug_init(void)
|
||||
ddebug_init_success = 1;
|
||||
return 0;
|
||||
}
|
||||
iter = __start___dyndbg;
|
||||
|
||||
iter = iter_mod_start = __start___dyndbg;
|
||||
modname = iter->modname;
|
||||
iter_start = iter;
|
||||
for (; iter < __stop___dyndbg; iter++) {
|
||||
entries++;
|
||||
i = mod_sites = mod_ct = 0;
|
||||
|
||||
for (; iter < __stop___dyndbg; iter++, i++, mod_sites++) {
|
||||
|
||||
if (strcmp(modname, iter->modname)) {
|
||||
modct++;
|
||||
ret = ddebug_add_module(iter_start, n, modname);
|
||||
mod_ct++;
|
||||
di.num_descs = mod_sites;
|
||||
di.descs = iter_mod_start;
|
||||
ret = __ddebug_add_module(&di, i - mod_sites, modname);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
n = 0;
|
||||
|
||||
mod_sites = 0;
|
||||
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)
|
||||
goto out_err;
|
||||
|
||||
ddebug_init_success = 1;
|
||||
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),
|
||||
(int)((entries * sizeof(struct _ddebug)) >> 10));
|
||||
i, mod_ct, (int)((mod_ct * sizeof(struct ddebug_table)) >> 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
|
||||
* 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/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_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */
|
||||
#define RFCOMM_TTY_MINOR 0
|
||||
|
Loading…
Reference in New Issue
Block a user