diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-14 14:29:31 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-14 14:29:31 -0700 |
commit | e6ecec342fefc2df01438cb0b8bacdd8641a6418 (patch) | |
tree | 44de6f64588253a2787390cb14ab78a6f5992813 | |
parent | 747f62305dfb8a592835c7401069bfdbc06acbae (diff) | |
parent | 3d83d3188460bf97afa0ac9895265422411e473a (diff) | |
download | op-kernel-dev-e6ecec342fefc2df01438cb0b8bacdd8641a6418.zip op-kernel-dev-e6ecec342fefc2df01438cb0b8bacdd8641a6418.tar.gz |
Merge tag 'docs-4.19' of git://git.lwn.net/linux
Pull documentation update from Jonathan Corbet:
"This was a moderately busy cycle for docs, with the usual collection
of small fixes and updates.
We also have new ktime_get_*() docs from Arnd, some kernel-doc fixes,
a new set of Italian translations (non so se vale la pena, ma non fa
male - speriamo bene), and some extensive early memory-management
documentation improvements from Mike Rapoport"
* tag 'docs-4.19' of git://git.lwn.net/linux: (52 commits)
Documentation: corrections to console/console.txt
Documentation: add ioctl number entry for v4l2-subdev.h
Remove gendered language from management style documentation
scripts/kernel-doc: Escape all literal braces in regexes
docs/mm: add description of boot time memory management
docs/mm: memblock: add overview documentation
docs/mm: memblock: add kernel-doc description for memblock types
docs/mm: memblock: add kernel-doc comments for memblock_add[_node]
docs/mm: memblock: update kernel-doc comments
mm/memblock: add a name for memblock flags enumeration
docs/mm: bootmem: add overview documentation
docs/mm: bootmem: add kernel-doc description of 'struct bootmem_data'
docs/mm: bootmem: fix kernel-doc warnings
docs/mm: nobootmem: fixup kernel-doc comments
mm/bootmem: drop duplicated kernel-doc comments
Documentation: vm.txt: Adding 'nr_hugepages_mempolicy' parameter description.
doc:it_IT: translation for kernel-hacking
docs: Fix the reference labels in Locking.rst
doc: tracing: Fix a typo of trace_stat
mm: Introduce new type vm_fault_t
...
57 files changed, 5101 insertions, 898 deletions
diff --git a/Documentation/admin-guide/README.rst b/Documentation/admin-guide/README.rst index 02caa7e..15ea785 100644 --- a/Documentation/admin-guide/README.rst +++ b/Documentation/admin-guide/README.rst @@ -1,3 +1,5 @@ +.. _readme: + Linux kernel release 4.x <http://kernel.org/> ============================================= diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 5a67e40..f3ade2f 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -4136,6 +4136,8 @@ This parameter controls whether the Speculative Store Bypass optimization is used. + On x86 the options are: + on - Unconditionally disable Speculative Store Bypass off - Unconditionally enable Speculative Store Bypass auto - Kernel detects whether the CPU model contains an @@ -4151,12 +4153,20 @@ seccomp - Same as "prctl" above, but all seccomp threads will disable SSB unless they explicitly opt out. - Not specifying this option is equivalent to - spec_store_bypass_disable=auto. - Default mitigations: X86: If CONFIG_SECCOMP=y "seccomp", otherwise "prctl" + On powerpc the options are: + + on,auto - On Power8 and Power9 insert a store-forwarding + barrier on kernel entry and exit. On Power7 + perform a software flush on kernel entry and + exit. + off - No action. + + Not specifying this option is equivalent to + spec_store_bypass_disable=auto. + spia_io_base= [HW,MTD] spia_fio_base= spia_pedr= diff --git a/Documentation/console/console.txt b/Documentation/console/console.txt index f93810d..d73c2ab 100644 --- a/Documentation/console/console.txt +++ b/Documentation/console/console.txt @@ -1,7 +1,7 @@ Console Drivers =============== -The linux kernel has 2 general types of console drivers. The first type is +The Linux kernel has 2 general types of console drivers. The first type is assigned by the kernel to all the virtual consoles during the boot process. This type will be called 'system driver', and only one system driver is allowed to exist. The system driver is persistent and it can never be unloaded, though @@ -17,10 +17,11 @@ of driver occupying the consoles.) They can only take over the console that is occupied by the system driver. In the same token, if the modular driver is released by the console, the system driver will take over. -Modular drivers, from the programmer's point of view, has to call: +Modular drivers, from the programmer's point of view, have to call: do_take_over_console() - load and bind driver to console layer - give_up_console() - unload driver, it will only work if driver is fully unbond + give_up_console() - unload driver; it will only work if driver + is fully unbound In newer kernels, the following are also available: @@ -56,7 +57,7 @@ What do these files signify? cat /sys/class/vtconsole/vtcon0/name (S) VGA+ - '(S)' stands for a (S)ystem driver, ie, it cannot be directly + '(S)' stands for a (S)ystem driver, i.e., it cannot be directly commanded to bind or unbind 'VGA+' is the name of the driver @@ -89,7 +90,7 @@ driver, make changes, recompile, reload and rebind the driver without any need for rebooting the kernel. For regular users who may want to switch from framebuffer console to VGA console and vice versa, this feature also makes this possible. (NOTE NOTE NOTE: Please read fbcon.txt under Documentation/fb -for more details). +for more details.) Notes for developers: ===================== @@ -110,8 +111,8 @@ In order for binding to and unbinding from the console to properly work, console drivers must follow these guidelines: 1. All drivers, except system drivers, must call either do_register_con_driver() - or do_take_over_console(). do_register_con_driver() will just add the driver to - the console's internal list. It won't take over the + or do_take_over_console(). do_register_con_driver() will just add the driver + to the console's internal list. It won't take over the console. do_take_over_console(), as it name implies, will also take over (or bind to) the console. diff --git a/Documentation/core-api/boot-time-mm.rst b/Documentation/core-api/boot-time-mm.rst new file mode 100644 index 0000000..03cb164 --- /dev/null +++ b/Documentation/core-api/boot-time-mm.rst @@ -0,0 +1,92 @@ +=========================== +Boot time memory management +=========================== + +Early system initialization cannot use "normal" memory management +simply because it is not set up yet. But there is still need to +allocate memory for various data structures, for instance for the +physical page allocator. To address this, a specialized allocator +called the :ref:`Boot Memory Allocator <bootmem>`, or bootmem, was +introduced. Several years later PowerPC developers added a "Logical +Memory Blocks" allocator, which was later adopted by other +architectures and renamed to :ref:`memblock <memblock>`. There is also +a compatibility layer called `nobootmem` that translates bootmem +allocation interfaces to memblock calls. + +The selection of the early allocator is done using +``CONFIG_NO_BOOTMEM`` and ``CONFIG_HAVE_MEMBLOCK`` kernel +configuration options. These options are enabled or disabled +statically by the architectures' Kconfig files. + +* Architectures that rely only on bootmem select + ``CONFIG_NO_BOOTMEM=n && CONFIG_HAVE_MEMBLOCK=n``. +* The users of memblock with the nobootmem compatibility layer set + ``CONFIG_NO_BOOTMEM=y && CONFIG_HAVE_MEMBLOCK=y``. +* And for those that use both memblock and bootmem the configuration + includes ``CONFIG_NO_BOOTMEM=n && CONFIG_HAVE_MEMBLOCK=y``. + +Whichever allocator is used, it is the responsibility of the +architecture specific initialization to set it up in +:c:func:`setup_arch` and tear it down in :c:func:`mem_init` functions. + +Once the early memory management is available it offers a variety of +functions and macros for memory allocations. The allocation request +may be directed to the first (and probably the only) node or to a +particular node in a NUMA system. There are API variants that panic +when an allocation fails and those that don't. And more recent and +advanced memblock even allows controlling its own behaviour. + +.. _bootmem: + +Bootmem +======= + +(mostly stolen from Mel Gorman's "Understanding the Linux Virtual +Memory Manager" `book`_) + +.. _book: https://www.kernel.org/doc/gorman/ + +.. kernel-doc:: mm/bootmem.c + :doc: bootmem overview + +.. _memblock: + +Memblock +======== + +.. kernel-doc:: mm/memblock.c + :doc: memblock overview + + +Functions and structures +======================== + +Common API +---------- + +The functions that are described in this section are available +regardless of what early memory manager is enabled. + +.. kernel-doc:: mm/nobootmem.c + +Bootmem specific API +-------------------- + +These interfaces available only with bootmem, i.e when ``CONFIG_NO_BOOTMEM=n`` + +.. kernel-doc:: include/linux/bootmem.h +.. kernel-doc:: mm/bootmem.c + :nodocs: + +Memblock specific API +--------------------- + +Here is the description of memblock data structures, functions and +macros. Some of them are actually internal, but since they are +documented it would be silly to omit them. Besides, reading the +descriptions for the internal functions can help to understand what +really happens under the hood. + +.. kernel-doc:: include/linux/memblock.h +.. kernel-doc:: mm/memblock.c + :nodocs: diff --git a/Documentation/core-api/idr.rst b/Documentation/core-api/idr.rst index 9078a5c..d351e88 100644 --- a/Documentation/core-api/idr.rst +++ b/Documentation/core-api/idr.rst @@ -76,4 +76,6 @@ Functions and structures ======================== .. kernel-doc:: include/linux/idr.h + :functions: .. kernel-doc:: lib/idr.c + :functions: diff --git a/Documentation/core-api/index.rst b/Documentation/core-api/index.rst index f5a66b7..b5379fb 100644 --- a/Documentation/core-api/index.rst +++ b/Documentation/core-api/index.rst @@ -28,6 +28,8 @@ Core utilities printk-formats circular-buffers gfp_mask-from-fs-io + timekeeping + boot-time-mm Interfaces for kernel debugging =============================== diff --git a/Documentation/core-api/timekeeping.rst b/Documentation/core-api/timekeeping.rst new file mode 100644 index 0000000..93cbeb9 --- /dev/null +++ b/Documentation/core-api/timekeeping.rst @@ -0,0 +1,185 @@ +ktime accessors +=============== + +Device drivers can read the current time using ktime_get() and the many +related functions declared in linux/timekeeping.h. As a rule of thumb, +using an accessor with a shorter name is preferred over one with a longer +name if both are equally fit for a particular use case. + +Basic ktime_t based interfaces +------------------------------ + +The recommended simplest form returns an opaque ktime_t, with variants +that return time for different clock references: + + +.. c:function:: ktime_t ktime_get( void ) + + CLOCK_MONOTONIC + + Useful for reliable timestamps and measuring short time intervals + accurately. Starts at system boot time but stops during suspend. + +.. c:function:: ktime_t ktime_get_boottime( void ) + + CLOCK_BOOTTIME + + Like ktime_get(), but does not stop when suspended. This can be + used e.g. for key expiration times that need to be synchronized + with other machines across a suspend operation. + +.. c:function:: ktime_t ktime_get_real( void ) + + CLOCK_REALTIME + + Returns the time in relative to the UNIX epoch starting in 1970 + using the Coordinated Universal Time (UTC), same as gettimeofday() + user space. This is used for all timestamps that need to + persist across a reboot, like inode times, but should be avoided + for internal uses, since it can jump backwards due to a leap + second update, NTP adjustment settimeofday() operation from user + space. + +.. c:function:: ktime_t ktime_get_clocktai( void ) + + CLOCK_TAI + + Like ktime_get_real(), but uses the International Atomic Time (TAI) + reference instead of UTC to avoid jumping on leap second updates. + This is rarely useful in the kernel. + +.. c:function:: ktime_t ktime_get_raw( void ) + + CLOCK_MONOTONIC_RAW + + Like ktime_get(), but runs at the same rate as the hardware + clocksource without (NTP) adjustments for clock drift. This is + also rarely needed in the kernel. + +nanosecond, timespec64, and second output +----------------------------------------- + +For all of the above, there are variants that return the time in a +different format depending on what is required by the user: + +.. c:function:: u64 ktime_get_ns( void ) + u64 ktime_get_boottime_ns( void ) + u64 ktime_get_real_ns( void ) + u64 ktime_get_tai_ns( void ) + u64 ktime_get_raw_ns( void ) + + Same as the plain ktime_get functions, but returning a u64 number + of nanoseconds in the respective time reference, which may be + more convenient for some callers. + +.. c:function:: void ktime_get_ts64( struct timespec64 * ) + void ktime_get_boottime_ts64( struct timespec64 * ) + void ktime_get_real_ts64( struct timespec64 * ) + void ktime_get_clocktai_ts64( struct timespec64 * ) + void ktime_get_raw_ts64( struct timespec64 * ) + + Same above, but returns the time in a 'struct timespec64', split + into seconds and nanoseconds. This can avoid an extra division + when printing the time, or when passing it into an external + interface that expects a 'timespec' or 'timeval' structure. + +.. c:function:: time64_t ktime_get_seconds( void ) + time64_t ktime_get_boottime_seconds( void ) + time64_t ktime_get_real_seconds( void ) + time64_t ktime_get_clocktai_seconds( void ) + time64_t ktime_get_raw_seconds( void ) + + Return a coarse-grained version of the time as a scalar + time64_t. This avoids accessing the clock hardware and rounds + down the seconds to the full seconds of the last timer tick + using the respective reference. + +Coarse and fast_ns access +------------------------- + +Some additional variants exist for more specialized cases: + +.. c:function:: ktime_t ktime_get_coarse_boottime( void ) + ktime_t ktime_get_coarse_real( void ) + ktime_t ktime_get_coarse_clocktai( void ) + ktime_t ktime_get_coarse_raw( void ) + +.. c:function:: void ktime_get_coarse_ts64( struct timespec64 * ) + void ktime_get_coarse_boottime_ts64( struct timespec64 * ) + void ktime_get_coarse_real_ts64( struct timespec64 * ) + void ktime_get_coarse_clocktai_ts64( struct timespec64 * ) + void ktime_get_coarse_raw_ts64( struct timespec64 * ) + + These are quicker than the non-coarse versions, but less accurate, + corresponding to CLOCK_MONONOTNIC_COARSE and CLOCK_REALTIME_COARSE + in user space, along with the equivalent boottime/tai/raw + timebase not available in user space. + + The time returned here corresponds to the last timer tick, which + may be as much as 10ms in the past (for CONFIG_HZ=100), same as + reading the 'jiffies' variable. These are only useful when called + in a fast path and one still expects better than second accuracy, + but can't easily use 'jiffies', e.g. for inode timestamps. + Skipping the hardware clock access saves around 100 CPU cycles + on most modern machines with a reliable cycle counter, but + up to several microseconds on older hardware with an external + clocksource. + +.. c:function:: u64 ktime_get_mono_fast_ns( void ) + u64 ktime_get_raw_fast_ns( void ) + u64 ktime_get_boot_fast_ns( void ) + u64 ktime_get_real_fast_ns( void ) + + These variants are safe to call from any context, including from + a non-maskable interrupt (NMI) during a timekeeper update, and + while we are entering suspend with the clocksource powered down. + This is useful in some tracing or debugging code as well as + machine check reporting, but most drivers should never call them, + since the time is allowed to jump under certain conditions. + +Deprecated time interfaces +-------------------------- + +Older kernels used some other interfaces that are now being phased out +but may appear in third-party drivers being ported here. In particular, +all interfaces returning a 'struct timeval' or 'struct timespec' have +been replaced because the tv_sec member overflows in year 2038 on 32-bit +architectures. These are the recommended replacements: + +.. c:function:: void ktime_get_ts( struct timespec * ) + + Use ktime_get() or ktime_get_ts64() instead. + +.. c:function:: struct timeval do_gettimeofday( void ) + struct timespec getnstimeofday( void ) + struct timespec64 getnstimeofday64( void ) + void ktime_get_real_ts( struct timespec * ) + + ktime_get_real_ts64() is a direct replacement, but consider using + monotonic time (ktime_get_ts64()) and/or a ktime_t based interface + (ktime_get()/ktime_get_real()). + +.. c:function:: struct timespec current_kernel_time( void ) + struct timespec64 current_kernel_time64( void ) + struct timespec get_monotonic_coarse( void ) + struct timespec64 get_monotonic_coarse64( void ) + + These are replaced by ktime_get_coarse_real_ts64() and + ktime_get_coarse_ts64(). However, A lot of code that wants + coarse-grained times can use the simple 'jiffies' instead, while + some drivers may actually want the higher resolution accessors + these days. + +.. c:function:: struct timespec getrawmonotonic( void ) + struct timespec64 getrawmonotonic64( void ) + struct timespec timekeeping_clocktai( void ) + struct timespec64 timekeeping_clocktai64( void ) + struct timespec get_monotonic_boottime( void ) + struct timespec64 get_monotonic_boottime64( void ) + + These are replaced by ktime_get_raw()/ktime_get_raw_ts64(), + ktime_get_clocktai()/ktime_get_clocktai_ts64() as well + as ktime_get_boottime()/ktime_get_boottime_ts64(). + However, if the particular choice of clock source is not + important for the user, consider converting to + ktime_get()/ktime_get_ts64() instead for consistency. diff --git a/Documentation/dev-tools/kselftest.rst b/Documentation/dev-tools/kselftest.rst index 3bf371a..6f653ac 100644 --- a/Documentation/dev-tools/kselftest.rst +++ b/Documentation/dev-tools/kselftest.rst @@ -156,6 +156,11 @@ Contributing new tests (details) installed by the distro on the system should be the primary focus to be able to find regressions. + * If a test needs specific kernel config options enabled, add a config file in + the test directory to enable them. + + e.g: tools/testing/selftests/android/ion/config + Test Harness ============ diff --git a/Documentation/doc-guide/kernel-doc.rst b/Documentation/doc-guide/kernel-doc.rst index 80383b1..8db53cd 100644 --- a/Documentation/doc-guide/kernel-doc.rst +++ b/Documentation/doc-guide/kernel-doc.rst @@ -488,14 +488,19 @@ doc: *title* .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c :doc: High Definition Audio over HDMI and Display Port -functions: *function* *[...]* +functions: *[ function ...]* Include documentation for each *function* in *source*. + If no *function* if specified, the documentaion for all functions + and types in the *source* will be included. - Example:: + Examples:: .. kernel-doc:: lib/bitmap.c :functions: bitmap_parselist bitmap_parselist_user + .. kernel-doc:: lib/idr.c + :functions: + Without options, the kernel-doc directive includes all documentation comments from the source file. diff --git a/Documentation/doc-guide/parse-headers.rst b/Documentation/doc-guide/parse-headers.rst index 82a3e43..24cfaa1 100644 --- a/Documentation/doc-guide/parse-headers.rst +++ b/Documentation/doc-guide/parse-headers.rst @@ -32,7 +32,7 @@ SYNOPSIS \ **parse_headers.pl**\ [<options>] <C_FILE> <OUT_FILE> [<EXCEPTIONS_FILE>] -Where <options> can be: --debug, --help or --man. +Where <options> can be: --debug, --help or --usage. OPTIONS @@ -133,7 +133,7 @@ For both statements, \ **type**\ can be either one of the following: \ **symbol**\ - The ignore or replace statement will apply to the name of enum statements + The ignore or replace statement will apply to the name of enum value at C_FILE. For replace statements, \ **new_value**\ will automatically use :c:type: diff --git a/Documentation/doc-guide/sphinx.rst b/Documentation/doc-guide/sphinx.rst index a241763..f0796da 100644 --- a/Documentation/doc-guide/sphinx.rst +++ b/Documentation/doc-guide/sphinx.rst @@ -28,7 +28,7 @@ The ReST markups currently used by the Documentation/ files are meant to be built with ``Sphinx`` version 1.3 or upper. If you're desiring to build PDF outputs, it is recommended to use version 1.4.6 or upper. -There's a script that checks for the Spinx requirements. Please see +There's a script that checks for the Sphinx requirements. Please see :ref:`sphinx-pre-install` for further details. Most distributions are shipped with Sphinx, but its toolchain is fragile, diff --git a/Documentation/driver-api/mtdnand.rst b/Documentation/driver-api/mtdnand.rst index dcd6359..c55a603 100644 --- a/Documentation/driver-api/mtdnand.rst +++ b/Documentation/driver-api/mtdnand.rst @@ -374,7 +374,7 @@ The nand driver supports three different types of hardware ECC. - NAND_ECC_HW8_512 - Hardware ECC generator providing 6 bytes ECC per 512 byte. + Hardware ECC generator providing 8 bytes ECC per 512 byte. If your hardware generator has a different functionality add it at the appropriate place in nand_base.c @@ -889,7 +889,7 @@ Use these constants to select the ECC algorithm:: #define NAND_ECC_HW3_512 3 /* Hardware ECC 6 byte ECC per 512 Byte data */ #define NAND_ECC_HW6_512 4 - /* Hardware ECC 6 byte ECC per 512 Byte data */ + /* Hardware ECC 8 byte ECC per 512 Byte data */ #define NAND_ECC_HW8_512 6 diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 7cca82e..9e6f19e 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -532,9 +532,9 @@ More details about quota locking can be found in fs/dquot.c. prototypes: void (*open)(struct vm_area_struct*); void (*close)(struct vm_area_struct*); - int (*fault)(struct vm_area_struct*, struct vm_fault *); - int (*page_mkwrite)(struct vm_area_struct *, struct vm_fault *); - int (*pfn_mkwrite)(struct vm_area_struct *, struct vm_fault *); + vm_fault_t (*fault)(struct vm_area_struct*, struct vm_fault *); + vm_fault_t (*page_mkwrite)(struct vm_area_struct *, struct vm_fault *); + vm_fault_t (*pfn_mkwrite)(struct vm_area_struct *, struct vm_fault *); int (*access)(struct vm_area_struct *, unsigned long, void*, int, int); locking rules: diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 520f6a8..1605acbb 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -870,6 +870,7 @@ Committed_AS: 100056 kB VmallocTotal: 112216 kB VmallocUsed: 428 kB VmallocChunk: 111088 kB +HardwareCorrupted: 0 kB AnonHugePages: 49152 kB ShmemHugePages: 0 kB ShmemPmdMapped: 0 kB @@ -915,6 +916,8 @@ MemAvailable: An estimate of how much memory is available for starting new Dirty: Memory which is waiting to get written back to the disk Writeback: Memory which is actively being written back to the disk AnonPages: Non-file backed pages mapped into userspace page tables +HardwareCorrupted: The amount of RAM/memory in KB, the kernel identifies as + corrupted. AnonHugePages: Non-file backed huge pages mapped into userspace page tables Mapped: files which have been mmaped, such as libraries Shmem: Total memory used by shared memory (shmem) and tmpfs diff --git a/Documentation/filesystems/relay.txt b/Documentation/filesystems/relay.txt index 33e2f36..cd709a9 100644 --- a/Documentation/filesystems/relay.txt +++ b/Documentation/filesystems/relay.txt @@ -222,7 +222,7 @@ using debugfs: */ static struct dentry *create_buf_file_handler(const char *filename, struct dentry *parent, - int mode, + umode_t mode, struct rchan_buf *buf, int *is_global) { @@ -375,7 +375,7 @@ would be very similar: static int subbuf_start(struct rchan_buf *buf, void *subbuf, void *prev_subbuf, - unsigned int prev_padding) + size_t prev_padding) { if (prev_subbuf) *((unsigned *)prev_subbuf) = prev_padding; diff --git a/Documentation/index.rst b/Documentation/index.rst index f95ba98..d43fcd2 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -3,6 +3,8 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. +.. _linux_doc: + The Linux Kernel documentation ============================== @@ -113,29 +115,13 @@ subprojects. filesystems/ext4/index -Korean translations -------------------- - -.. toctree:: - :maxdepth: 1 - - translations/ko_KR/index - -Chinese translations --------------------- +Translations +------------ .. toctree:: - :maxdepth: 1 - - translations/zh_CN/index - -Japanese translations ---------------------- - -.. toctree:: - :maxdepth: 1 + :maxdepth: 2 - translations/ja_JP/index + translations/index Indices and tables ================== diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 480c860..9aeb5f0 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -274,6 +274,7 @@ Code Seq#(hex) Include File Comments 'v' 00-1F linux/ext2_fs.h conflict! 'v' 00-1F linux/fs.h conflict! 'v' 00-0F linux/sonypi.h conflict! +'v' 00-0F media/v4l2-subdev.h conflict! 'v' C0-FF linux/meye.h conflict! 'w' all CERN SCI driver 'y' 00-1F packet based user level communications diff --git a/Documentation/kernel-hacking/hacking.rst b/Documentation/kernel-hacking/hacking.rst index 9999c84..d824e4f 100644 --- a/Documentation/kernel-hacking/hacking.rst +++ b/Documentation/kernel-hacking/hacking.rst @@ -1,3 +1,5 @@ +.. _kernel_hacking_hack: + ============================================ Unreliable Guide To Hacking The Linux Kernel ============================================ diff --git a/Documentation/kernel-hacking/index.rst b/Documentation/kernel-hacking/index.rst index fcb0eda..f530276 100644 --- a/Documentation/kernel-hacking/index.rst +++ b/Documentation/kernel-hacking/index.rst @@ -1,3 +1,5 @@ +.. _kernel_hacking: + ===================== Kernel Hacking Guides ===================== diff --git a/Documentation/kernel-hacking/locking.rst b/Documentation/kernel-hacking/locking.rst index f937c0f..519673d 100644 --- a/Documentation/kernel-hacking/locking.rst +++ b/Documentation/kernel-hacking/locking.rst @@ -1,3 +1,5 @@ +.. _kernel_hacking_lock: + =========================== Unreliable Guide To Locking =========================== @@ -177,7 +179,7 @@ perfect world). Note that you can also use :c:func:`spin_lock_irq()` or :c:func:`spin_lock_irqsave()` here, which stop hardware interrupts -as well: see `Hard IRQ Context <#hardirq-context>`__. +as well: see `Hard IRQ Context <#hard-irq-context>`__. This works perfectly for UP as well: the spin lock vanishes, and this macro simply becomes :c:func:`local_bh_disable()` @@ -228,7 +230,7 @@ The Same Softirq ~~~~~~~~~~~~~~~~ The same softirq can run on the other CPUs: you can use a per-CPU array -(see `Per-CPU Data <#per-cpu>`__) for better performance. If you're +(see `Per-CPU Data <#per-cpu-data>`__) for better performance. If you're going so far as to use a softirq, you probably care about scalable performance enough to justify the extra complexity. diff --git a/Documentation/nommu-mmap.txt b/Documentation/nommu-mmap.txt index 69556f0..530fed0 100644 --- a/Documentation/nommu-mmap.txt +++ b/Documentation/nommu-mmap.txt @@ -47,7 +47,7 @@ and it's also much more restricted in the latter case: appropriate mapping protection capabilities. Ramfs, romfs, cramfs and mtd might all permit this. - - If the backing device device can't or won't permit direct sharing, + - If the backing device can't or won't permit direct sharing, but does have the NOMMU_MAP_COPY capability, then a copy of the appropriate bit of the file will be read into a contiguous bit of memory and any extraneous space beyond the EOF will be cleared diff --git a/Documentation/process/2.Process.rst b/Documentation/process/2.Process.rst index a9c46dd..51d0349 100644 --- a/Documentation/process/2.Process.rst +++ b/Documentation/process/2.Process.rst @@ -134,7 +134,7 @@ and their maintainers are: 4.4 Greg Kroah-Hartman (very long-term stable kernel) 4.9 Greg Kroah-Hartman 4.14 Greg Kroah-Hartman - ====== ====================== =========================== + ====== ====================== ============================== The selection of a kernel for long-term support is purely a matter of a maintainer having the need and the time to maintain that release. There diff --git a/Documentation/process/howto.rst b/Documentation/process/howto.rst index 3df5581..130bf0f 100644 --- a/Documentation/process/howto.rst +++ b/Documentation/process/howto.rst @@ -85,7 +85,7 @@ linux-api@vger.kernel.org. Here is a list of files that are in the kernel source tree that are required reading: - README + :ref:`Documentation/admin-guide/README.rst <readme>` This file gives a short background on the Linux kernel and describes what is necessary to do to configure and build the kernel. People who are new to the kernel should start here. diff --git a/Documentation/process/management-style.rst b/Documentation/process/management-style.rst index 45595fd..85ef8ca 100644 --- a/Documentation/process/management-style.rst +++ b/Documentation/process/management-style.rst @@ -105,7 +105,7 @@ to admit that you are stupid when you haven't **yet** done the really stupid thing. Then, when it really does turn out to be stupid, people just roll their -eyes and say "Oops, he did it again". +eyes and say "Oops, not again". This preemptive admission of incompetence might also make the people who actually do the work also think twice about whether it's worth doing or @@ -172,10 +172,10 @@ To solve this problem, you really only have two options: might even be amused. The option of being unfailingly polite really doesn't exist. Nobody will -trust somebody who is so clearly hiding his true character. +trust somebody who is so clearly hiding their true character. .. [#f2] Paul Simon sang "Fifty Ways to Leave Your Lover", because quite - frankly, "A Million Ways to Tell a Developer He Is a D*ckhead" doesn't + frankly, "A Million Ways to Tell a Developer They're a D*ckhead" doesn't scan nearly as well. But I'm sure he thought about it. @@ -219,15 +219,16 @@ Things will go wrong, and people want somebody to blame. Tag, you're it. It's not actually that hard to accept the blame, especially if people kind of realize that it wasn't **all** your fault. Which brings us to the -best way of taking the blame: do it for another guy. You'll feel good -for taking the fall, he'll feel good about not getting blamed, and the -guy who lost his whole 36GB porn-collection because of your incompetence -will grudgingly admit that you at least didn't try to weasel out of it. - -Then make the developer who really screwed up (if you can find him) know -**in_private** that he screwed up. Not just so he can avoid it in the -future, but so that he knows he owes you one. And, perhaps even more -importantly, he's also likely the person who can fix it. Because, let's +best way of taking the blame: do it for someone else. You'll feel good +for taking the fall, they'll feel good about not getting blamed, and the +person who lost their whole 36GB porn-collection because of your +incompetence will grudgingly admit that you at least didn't try to weasel +out of it. + +Then make the developer who really screwed up (if you can find them) know +**in_private** that they screwed up. Not just so they can avoid it in the +future, but so that they know they owe you one. And, perhaps even more +importantly, they're also likely the person who can fix it. Because, let's face it, it sure ain't you. Taking the blame is also why you get to be manager in the first place. diff --git a/Documentation/sphinx/kerneldoc.py b/Documentation/sphinx/kerneldoc.py index fbedcc3..9d0a7f0 100644 --- a/Documentation/sphinx/kerneldoc.py +++ b/Documentation/sphinx/kerneldoc.py @@ -47,7 +47,7 @@ class KernelDocDirective(Directive): optional_arguments = 4 option_spec = { 'doc': directives.unchanged_required, - 'functions': directives.unchanged_required, + 'functions': directives.unchanged, 'export': directives.unchanged, 'internal': directives.unchanged, } @@ -75,8 +75,12 @@ class KernelDocDirective(Directive): elif 'doc' in self.options: cmd += ['-function', str(self.options.get('doc'))] elif 'functions' in self.options: - for f in str(self.options.get('functions')).split(): - cmd += ['-function', f] + functions = self.options.get('functions').split() + if functions: + for f in functions: + cmd += ['-function', f] + else: + cmd += ['-no-doc-sections'] for pattern in export_file_patterns: for f in glob.glob(env.config.kerneldoc_srctree + '/' + pattern): diff --git a/Documentation/sphinx/parse-headers.pl b/Documentation/sphinx/parse-headers.pl index d410f47..c518050 100755 --- a/Documentation/sphinx/parse-headers.pl +++ b/Documentation/sphinx/parse-headers.pl @@ -344,7 +344,7 @@ enums and defines and create cross-references to a Sphinx book. B<parse_headers.pl> [<options>] <C_FILE> <OUT_FILE> [<EXCEPTIONS_FILE>] -Where <options> can be: --debug, --help or --man. +Where <options> can be: --debug, --help or --usage. =head1 OPTIONS diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index 697ef8c..e72853b 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -27,6 +27,7 @@ Currently, these files are in /proc/sys/vm: - dirty_bytes - dirty_expire_centisecs - dirty_ratio +- dirtytime_expire_seconds - dirty_writeback_centisecs - drop_caches - extfrag_threshold @@ -44,6 +45,7 @@ Currently, these files are in /proc/sys/vm: - mmap_rnd_bits - mmap_rnd_compat_bits - nr_hugepages +- nr_hugepages_mempolicy - nr_overcommit_hugepages - nr_trim_pages (only if CONFIG_MMU=n) - numa_zonelist_order @@ -178,6 +180,18 @@ The total available memory is not equal to total system memory. ============================================================== +dirtytime_expire_seconds + +When a lazytime inode is constantly having its pages dirtied, the inode with +an updated timestamp will never get chance to be written out. And, if the +only thing that has happened on the file system is a dirtytime inode caused +by an atime update, a worker will be scheduled to make sure that inode +eventually gets pushed out to disk. This tunable is used to define when dirty +inode is old enough to be eligible for writeback by the kernel flusher threads. +And, it is also used as the interval to wakeup dirtytime_writeback thread. + +============================================================== + dirty_writeback_centisecs The kernel flusher threads will periodically wake up and write `old' data @@ -519,6 +533,15 @@ See Documentation/admin-guide/mm/hugetlbpage.rst ============================================================== +nr_hugepages_mempolicy + +Change the size of the hugepage pool at run-time on a specific +set of NUMA nodes. + +See Documentation/admin-guide/mm/hugetlbpage.rst + +============================================================== + nr_overcommit_hugepages Change the maximum size of the hugepage pool. The maximum is diff --git a/Documentation/timers/timekeeping.txt b/Documentation/timers/timekeeping.txt index f3a8cf2..2d1732b 100644 --- a/Documentation/timers/timekeeping.txt +++ b/Documentation/timers/timekeeping.txt @@ -27,7 +27,7 @@ a Linux system will eventually read the clock source to determine exactly what time it is. Typically the clock source is a monotonic, atomic counter which will provide -n bits which count from 0 to 2^(n-1) and then wraps around to 0 and start over. +n bits which count from 0 to (2^n)-1 and then wraps around to 0 and start over. It will ideally NEVER stop ticking as long as the system is running. It may stop during system suspend. diff --git a/Documentation/trace/events.rst b/Documentation/trace/events.rst index 696dc69..f7e1fcc 100644 --- a/Documentation/trace/events.rst +++ b/Documentation/trace/events.rst @@ -524,4 +524,4 @@ The following commands are supported: totals derived from one or more trace event format fields and/or event counts (hitcount). - See Documentation/trace/histogram.txt for details and examples. + See Documentation/trace/histogram.rst for details and examples. diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst index a20d349..7ea16a0 100644 --- a/Documentation/trace/ftrace.rst +++ b/Documentation/trace/ftrace.rst @@ -329,9 +329,9 @@ of ftrace. Here is a list of some of the key files: track of the time spent in those functions. The histogram content can be displayed in the files: - trace_stats/function<cpu> ( function0, function1, etc). + trace_stat/function<cpu> ( function0, function1, etc). - trace_stats: + trace_stat: A directory that holds different tracing stats. diff --git a/Documentation/trace/histogram.txt b/Documentation/trace/histogram.rst index 7ffea6a..5ac724b 100644 --- a/Documentation/trace/histogram.txt +++ b/Documentation/trace/histogram.rst @@ -1,6 +1,8 @@ - Event Histograms +================ +Event Histograms +================ - Documentation written by Tom Zanussi +Documentation written by Tom Zanussi 1. Introduction =============== @@ -19,7 +21,7 @@ derived from one or more trace event format fields and/or event counts (hitcount). - The format of a hist trigger is as follows: + The format of a hist trigger is as follows:: hist:keys=<field1[,field2,...]>[:values=<field1[,field2,...]>] [:sort=<field1[,field2,...]>][:size=#entries][:pause][:continue] @@ -68,6 +70,7 @@ modified by appending any of the following modifiers to the field name: + =========== ========================================== .hex display a number as a hex value .sym display an address as a symbol .sym-offset display an address as a symbol and offset @@ -75,6 +78,7 @@ .execname display a common_pid as a program name .log2 display log2 value rather than raw number .usecs display a common_timestamp in microseconds + =========== ========================================== Note that in general the semantics of a given field aren't interpreted when applying a modifier to it, but there are some @@ -92,15 +96,15 @@ pid-specific comm fields in the event itself. A typical usage scenario would be the following to enable a hist - trigger, read its current contents, and then turn it off: + trigger, read its current contents, and then turn it off:: - # echo 'hist:keys=skbaddr.hex:vals=len' > \ - /sys/kernel/debug/tracing/events/net/netif_rx/trigger + # echo 'hist:keys=skbaddr.hex:vals=len' > \ + /sys/kernel/debug/tracing/events/net/netif_rx/trigger - # cat /sys/kernel/debug/tracing/events/net/netif_rx/hist + # cat /sys/kernel/debug/tracing/events/net/netif_rx/hist - # echo '!hist:keys=skbaddr.hex:vals=len' > \ - /sys/kernel/debug/tracing/events/net/netif_rx/trigger + # echo '!hist:keys=skbaddr.hex:vals=len' > \ + /sys/kernel/debug/tracing/events/net/netif_rx/trigger The trigger file itself can be read to show the details of the currently attached hist trigger. This information is also displayed @@ -140,7 +144,7 @@ can be attached to a given event, allowing that event to kick off and stop aggregations on a host of other events. - The format is very similar to the enable/disable_event triggers: + The format is very similar to the enable/disable_event triggers:: enable_hist:<system>:<event>[:count] disable_hist:<system>:<event>[:count] @@ -153,16 +157,16 @@ A typical usage scenario for the enable_hist/disable_hist triggers would be to first set up a paused hist trigger on some event, followed by an enable_hist/disable_hist pair that turns the hist - aggregation on and off when conditions of interest are hit: + aggregation on and off when conditions of interest are hit:: - # echo 'hist:keys=skbaddr.hex:vals=len:pause' > \ - /sys/kernel/debug/tracing/events/net/netif_receive_skb/trigger + # echo 'hist:keys=skbaddr.hex:vals=len:pause' > \ + /sys/kernel/debug/tracing/events/net/netif_receive_skb/trigger - # echo 'enable_hist:net:netif_receive_skb if filename==/usr/bin/wget' > \ - /sys/kernel/debug/tracing/events/sched/sched_process_exec/trigger + # echo 'enable_hist:net:netif_receive_skb if filename==/usr/bin/wget' > \ + /sys/kernel/debug/tracing/events/sched/sched_process_exec/trigger - # echo 'disable_hist:net:netif_receive_skb if comm==wget' > \ - /sys/kernel/debug/tracing/events/sched/sched_process_exit/trigger + # echo 'disable_hist:net:netif_receive_skb if comm==wget' > \ + /sys/kernel/debug/tracing/events/sched/sched_process_exit/trigger The above sets up an initially paused hist trigger which is unpaused and starts aggregating events when a given program is executed, and @@ -172,8 +176,8 @@ The examples below provide a more concrete illustration of the concepts and typical usage patterns discussed above. - 'special' event fields - ------------------------ +'special' event fields +------------------------ There are a number of 'special event fields' available for use as keys or values in a hist trigger. These look like and behave as if @@ -182,14 +186,16 @@ event, and can be used anywhere an actual event field could be. They are: - common_timestamp u64 - timestamp (from ring buffer) associated - with the event, in nanoseconds. May be - modified by .usecs to have timestamps - interpreted as microseconds. - cpu int - the cpu on which the event occurred. + ====================== ==== ======================================= + common_timestamp u64 timestamp (from ring buffer) associated + with the event, in nanoseconds. May be + modified by .usecs to have timestamps + interpreted as microseconds. + cpu int the cpu on which the event occurred. + ====================== ==== ======================================= - Extended error information - -------------------------- +Extended error information +-------------------------- For some error conditions encountered when invoking a hist trigger command, extended error information is available via the @@ -199,7 +205,7 @@ be available until the next hist trigger command for that event. If available for a given error condition, the extended error - information and usage takes the following form: + information and usage takes the following form:: # echo xxx > /sys/kernel/debug/tracing/events/sched/sched_wakeup/trigger echo: write error: Invalid argument @@ -213,7 +219,7 @@ The first set of examples creates aggregations using the kmalloc event. The fields that can be used for the hist trigger are listed - in the kmalloc event's format file: + in the kmalloc event's format file:: # cat /sys/kernel/debug/tracing/events/kmem/kmalloc/format name: kmalloc @@ -232,7 +238,7 @@ We'll start by creating a hist trigger that generates a simple table that lists the total number of bytes requested for each function in - the kernel that made one or more calls to kmalloc: + the kernel that made one or more calls to kmalloc:: # echo 'hist:key=call_site:val=bytes_req' > \ /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger @@ -247,7 +253,7 @@ We'll let it run for awhile and then dump the contents of the 'hist' file in the kmalloc event's subdirectory (for readability, a number - of entries have been omitted): + of entries have been omitted):: # cat /sys/kernel/debug/tracing/events/kmem/kmalloc/hist # trigger info: hist:keys=call_site:vals=bytes_req:sort=hitcount:size=2048 [active] @@ -287,7 +293,7 @@ specified in the trigger, followed by the value(s) also specified in the trigger. At the beginning of the output is a line that displays the trigger info, which can also be displayed by reading the - 'trigger' file: + 'trigger' file:: # cat /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger hist:keys=call_site:vals=bytes_req:sort=hitcount:size=2048 [active] @@ -317,7 +323,7 @@ frequencies. To turn the hist trigger off, simply call up the trigger in the - command history and re-execute it with a '!' prepended: + command history and re-execute it with a '!' prepended:: # echo '!hist:key=call_site:val=bytes_req' > \ /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger @@ -325,7 +331,7 @@ Finally, notice that the call_site as displayed in the output above isn't really very useful. It's an address, but normally addresses are displayed in hex. To have a numeric field displayed as a hex - value, simply append '.hex' to the field name in the trigger: + value, simply append '.hex' to the field name in the trigger:: # echo 'hist:key=call_site.hex:val=bytes_req' > \ /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger @@ -370,7 +376,7 @@ when looking at text addresses are the corresponding symbols instead. To have an address displayed as symbolic value instead, simply append '.sym' or '.sym-offset' to the field name in the - trigger: + trigger:: # echo 'hist:key=call_site.sym:val=bytes_req' > \ /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger @@ -420,7 +426,7 @@ run. If instead we we wanted to see the top kmalloc callers in terms of the number of bytes requested rather than the number of calls, and we wanted the top caller to appear at the top, we can use - the 'sort' parameter, along with the 'descending' modifier: + the 'sort' parameter, along with the 'descending' modifier:: # echo 'hist:key=call_site.sym:val=bytes_req:sort=bytes_req.descending' > \ /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger @@ -461,7 +467,7 @@ Dropped: 0 To display the offset and size information in addition to the symbol - name, just use 'sym-offset' instead: + name, just use 'sym-offset' instead:: # echo 'hist:key=call_site.sym-offset:val=bytes_req:sort=bytes_req.descending' > \ /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger @@ -500,7 +506,7 @@ We can also add multiple fields to the 'values' parameter. For example, we might want to see the total number of bytes allocated alongside bytes requested, and display the result sorted by bytes - allocated in a descending order: + allocated in a descending order:: # echo 'hist:keys=call_site.sym:values=bytes_req,bytes_alloc:sort=bytes_alloc.descending' > \ /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger @@ -543,7 +549,7 @@ the hist trigger display symbolic call_sites, we can have the hist trigger additionally display the complete set of kernel stack traces that led to each call_site. To do that, we simply use the special - value 'stacktrace' for the key parameter: + value 'stacktrace' for the key parameter:: # echo 'hist:keys=stacktrace:values=bytes_req,bytes_alloc:sort=bytes_alloc' > \ /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger @@ -554,7 +560,7 @@ event, along with a running total of any of the event fields for that event. Here we tally bytes requested and bytes allocated for every callpath in the system that led up to a kmalloc (in this case - every callpath to a kmalloc for a kernel compile): + every callpath to a kmalloc for a kernel compile):: # cat /sys/kernel/debug/tracing/events/kmem/kmalloc/hist # trigger info: hist:keys=stacktrace:vals=bytes_req,bytes_alloc:sort=bytes_alloc:size=2048 [active] @@ -652,7 +658,7 @@ gather and display sorted totals for each process, you can use the special .execname modifier to display the executable names for the processes in the table rather than raw pids. The example below - keeps a per-process sum of total bytes read: + keeps a per-process sum of total bytes read:: # echo 'hist:key=common_pid.execname:val=count:sort=count.descending' > \ /sys/kernel/debug/tracing/events/syscalls/sys_enter_read/trigger @@ -693,7 +699,7 @@ gather and display a list of systemwide syscall hits, you can use the special .syscall modifier to display the syscall names rather than raw ids. The example below keeps a running total of syscall - counts for the system during the run: + counts for the system during the run:: # echo 'hist:key=id.syscall:val=hitcount' > \ /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/trigger @@ -735,19 +741,19 @@ Entries: 72 Dropped: 0 - The syscall counts above provide a rough overall picture of system - call activity on the system; we can see for example that the most - popular system call on this system was the 'sys_ioctl' system call. + The syscall counts above provide a rough overall picture of system + call activity on the system; we can see for example that the most + popular system call on this system was the 'sys_ioctl' system call. - We can use 'compound' keys to refine that number and provide some - further insight as to which processes exactly contribute to the - overall ioctl count. + We can use 'compound' keys to refine that number and provide some + further insight as to which processes exactly contribute to the + overall ioctl count. - The command below keeps a hitcount for every unique combination of - system call id and pid - the end result is essentially a table - that keeps a per-pid sum of system call hits. The results are - sorted using the system call id as the primary key, and the - hitcount sum as the secondary key: + The command below keeps a hitcount for every unique combination of + system call id and pid - the end result is essentially a table + that keeps a per-pid sum of system call hits. The results are + sorted using the system call id as the primary key, and the + hitcount sum as the secondary key:: # echo 'hist:key=id.syscall,common_pid.execname:val=hitcount:sort=id,hitcount' > \ /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/trigger @@ -793,11 +799,11 @@ Entries: 323 Dropped: 0 - The above list does give us a breakdown of the ioctl syscall by - pid, but it also gives us quite a bit more than that, which we - don't really care about at the moment. Since we know the syscall - id for sys_ioctl (16, displayed next to the sys_ioctl name), we - can use that to filter out all the other syscalls: + The above list does give us a breakdown of the ioctl syscall by + pid, but it also gives us quite a bit more than that, which we + don't really care about at the moment. Since we know the syscall + id for sys_ioctl (16, displayed next to the sys_ioctl name), we + can use that to filter out all the other syscalls:: # echo 'hist:key=id.syscall,common_pid.execname:val=hitcount:sort=id,hitcount if id == 16' > \ /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/trigger @@ -829,18 +835,18 @@ Entries: 103 Dropped: 0 - The above output shows that 'compiz' and 'Xorg' are far and away - the heaviest ioctl callers (which might lead to questions about - whether they really need to be making all those calls and to - possible avenues for further investigation.) + The above output shows that 'compiz' and 'Xorg' are far and away + the heaviest ioctl callers (which might lead to questions about + whether they really need to be making all those calls and to + possible avenues for further investigation.) - The compound key examples used a key and a sum value (hitcount) to - sort the output, but we can just as easily use two keys instead. - Here's an example where we use a compound key composed of the the - common_pid and size event fields. Sorting with pid as the primary - key and 'size' as the secondary key allows us to display an - ordered summary of the recvfrom sizes, with counts, received by - each process: + The compound key examples used a key and a sum value (hitcount) to + sort the output, but we can just as easily use two keys instead. + Here's an example where we use a compound key composed of the the + common_pid and size event fields. Sorting with pid as the primary + key and 'size' as the secondary key allows us to display an + ordered summary of the recvfrom sizes, with counts, received by + each process:: # echo 'hist:key=common_pid.execname,size:val=hitcount:sort=common_pid,size' > \ /sys/kernel/debug/tracing/events/syscalls/sys_enter_recvfrom/trigger @@ -893,7 +899,7 @@ demonstrates how you can manually pause and continue a hist trigger. In this example, we'll aggregate fork counts and don't expect a large number of entries in the hash table, so we'll drop it to a - much smaller number, say 256: + much smaller number, say 256:: # echo 'hist:key=child_comm:val=hitcount:size=256' > \ /sys/kernel/debug/tracing/events/sched/sched_process_fork/trigger @@ -929,7 +935,7 @@ If we want to pause the hist trigger, we can simply append :pause to the command that started the trigger. Notice that the trigger info - displays as [paused]: + displays as [paused]:: # echo 'hist:key=child_comm:val=hitcount:size=256:pause' >> \ /sys/kernel/debug/tracing/events/sched/sched_process_fork/trigger @@ -966,7 +972,7 @@ To manually continue having the trigger aggregate events, append :cont instead. Notice that the trigger info displays as [active] - again, and the data has changed: + again, and the data has changed:: # echo 'hist:key=child_comm:val=hitcount:size=256:cont' >> \ /sys/kernel/debug/tracing/events/sched/sched_process_fork/trigger @@ -1020,7 +1026,7 @@ wget. First we set up an initially paused stacktrace trigger on the - netif_receive_skb event: + netif_receive_skb event:: # echo 'hist:key=stacktrace:vals=len:pause' > \ /sys/kernel/debug/tracing/events/net/netif_receive_skb/trigger @@ -1031,7 +1037,7 @@ set up on netif_receive_skb if and only if it sees a sched_process_exec event with a filename of '/usr/bin/wget'. When that happens, all netif_receive_skb events are aggregated into a - hash table keyed on stacktrace: + hash table keyed on stacktrace:: # echo 'enable_hist:net:netif_receive_skb if filename==/usr/bin/wget' > \ /sys/kernel/debug/tracing/events/sched/sched_process_exec/trigger @@ -1039,7 +1045,7 @@ The aggregation continues until the netif_receive_skb is paused again, which is what the following disable_hist event does by creating a similar setup on the sched_process_exit event, using the - filter 'comm==wget': + filter 'comm==wget':: # echo 'disable_hist:net:netif_receive_skb if comm==wget' > \ /sys/kernel/debug/tracing/events/sched/sched_process_exit/trigger @@ -1051,7 +1057,7 @@ The overall effect is that netif_receive_skb events are aggregated into the hash table for only the duration of the wget. Executing a wget command and then listing the 'hist' file will display the - output generated by the wget command: + output generated by the wget command:: $ wget https://www.kernel.org/pub/linux/kernel/v3.x/patch-3.19.xz @@ -1136,13 +1142,13 @@ Suppose we wanted to try another run of the previous example but this time also wanted to see the complete list of events that went into the histogram. In order to avoid having to set everything up - again, we can just clear the histogram first: + again, we can just clear the histogram first:: # echo 'hist:key=stacktrace:vals=len:clear' >> \ /sys/kernel/debug/tracing/events/net/netif_receive_skb/trigger Just to verify that it is in fact cleared, here's what we now see in - the hist file: + the hist file:: # cat /sys/kernel/debug/tracing/events/net/netif_receive_skb/hist # trigger info: hist:keys=stacktrace:vals=len:sort=hitcount:size=2048 [paused] @@ -1156,7 +1162,7 @@ event occurring during the new run, which are in fact the same events being aggregated into the hash table, we add some additional 'enable_event' events to the triggering sched_process_exec and - sched_process_exit events as such: + sched_process_exit events as such:: # echo 'enable_event:net:netif_receive_skb if filename==/usr/bin/wget' > \ /sys/kernel/debug/tracing/events/sched/sched_process_exec/trigger @@ -1167,7 +1173,7 @@ If you read the trigger files for the sched_process_exec and sched_process_exit triggers, you should see two triggers for each: one enabling/disabling the hist aggregation and the other - enabling/disabling the logging of events: + enabling/disabling the logging of events:: # cat /sys/kernel/debug/tracing/events/sched/sched_process_exec/trigger enable_event:net:netif_receive_skb:unlimited if filename==/usr/bin/wget @@ -1181,13 +1187,13 @@ sched_process_exit events is hit and matches 'wget', it enables or disables both the histogram and the event log, and what you end up with is a hash table and set of events just covering the specified - duration. Run the wget command again: + duration. Run the wget command again:: $ wget https://www.kernel.org/pub/linux/kernel/v3.x/patch-3.19.xz Displaying the 'hist' file should show something similar to what you saw in the last run, but this time you should also see the - individual events in the trace file: + individual events in the trace file:: # cat /sys/kernel/debug/tracing/trace @@ -1220,7 +1226,7 @@ attached to a given event. This capability can be useful for creating a set of different summaries derived from the same set of events, or for comparing the effects of different filters, among - other things. + other things:: # echo 'hist:keys=skbaddr.hex:vals=len if len < 0' >> \ /sys/kernel/debug/tracing/events/net/netif_receive_skb/trigger @@ -1241,7 +1247,7 @@ any existing hist triggers beforehand). Displaying the contents of the 'hist' file for the event shows the - contents of all five histograms: + contents of all five histograms:: # cat /sys/kernel/debug/tracing/events/net/netif_receive_skb/hist @@ -1361,7 +1367,7 @@ output of events generated by tracepoints contained inside inline functions, but names can be used in a hist trigger on any event. For example, these two triggers when hit will update the same 'len' - field in the shared 'foo' histogram data: + field in the shared 'foo' histogram data:: # echo 'hist:name=foo:keys=skbaddr.hex:vals=len' > \ /sys/kernel/debug/tracing/events/net/netif_receive_skb/trigger @@ -1369,7 +1375,7 @@ /sys/kernel/debug/tracing/events/net/netif_rx/trigger You can see that they're updating common histogram data by reading - each event's hist files at the same time: + each event's hist files at the same time:: # cat /sys/kernel/debug/tracing/events/net/netif_receive_skb/hist; cat /sys/kernel/debug/tracing/events/net/netif_rx/hist @@ -1482,7 +1488,7 @@ And here's an example that shows how to combine histogram data from any two events even if they don't share any 'compatible' fields other than 'hitcount' and 'stacktrace'. These commands create a - couple of triggers named 'bar' using those fields: + couple of triggers named 'bar' using those fields:: # echo 'hist:name=bar:key=stacktrace:val=hitcount' > \ /sys/kernel/debug/tracing/events/sched/sched_process_fork/trigger @@ -1490,7 +1496,7 @@ /sys/kernel/debug/tracing/events/net/netif_rx/trigger And displaying the output of either shows some interesting if - somewhat confusing output: + somewhat confusing output:: # cat /sys/kernel/debug/tracing/events/sched/sched_process_fork/hist # cat /sys/kernel/debug/tracing/events/net/netif_rx/hist @@ -1705,7 +1711,7 @@ to any event field. Either keys or values can be saved and retrieved in this way. This creates a variable named 'ts0' for a histogram entry with the key -'next_pid': +'next_pid':: # echo 'hist:keys=next_pid:vals=$ts0:ts0=common_timestamp ... >> \ event/trigger @@ -1721,40 +1727,40 @@ Because 'vals=' is used, the common_timestamp variable value above will also be summed as a normal histogram value would (though for a timestamp it makes little sense). -The below shows that a key value can also be saved in the same way: +The below shows that a key value can also be saved in the same way:: # echo 'hist:timer_pid=common_pid:key=timer_pid ...' >> event/trigger If a variable isn't a key variable or prefixed with 'vals=', the associated event field will be saved in a variable but won't be summed -as a value: +as a value:: # echo 'hist:keys=next_pid:ts1=common_timestamp ...' >> event/trigger Multiple variables can be assigned at the same time. The below would result in both ts0 and b being created as variables, with both -common_timestamp and field1 additionally being summed as values: +common_timestamp and field1 additionally being summed as values:: # echo 'hist:keys=pid:vals=$ts0,$b:ts0=common_timestamp,b=field1 ...' >> \ event/trigger Note that variable assignments can appear either preceding or following their use. The command below behaves identically to the -command above: +command above:: # echo 'hist:keys=pid:ts0=common_timestamp,b=field1:vals=$ts0,$b ...' >> \ event/trigger Any number of variables not bound to a 'vals=' prefix can also be assigned by simply separating them with colons. Below is the same -thing but without the values being summed in the histogram: +thing but without the values being summed in the histogram:: # echo 'hist:keys=pid:ts0=common_timestamp:b=field1 ...' >> event/trigger Variables set as above can be referenced and used in expressions on another event. -For example, here's how a latency can be calculated: +For example, here's how a latency can be calculated:: # echo 'hist:keys=pid,prio:ts0=common_timestamp ...' >> event1/trigger # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp-$ts0 ...' >> event2/trigger @@ -1764,7 +1770,7 @@ variable ts0. In the next line, ts0 is subtracted from the second event's timestamp to produce the latency, which is then assigned into yet another variable, 'wakeup_lat'. The hist trigger below in turn makes use of the wakeup_lat variable to compute a combined latency -using the same key and variable from yet another event: +using the same key and variable from yet another event:: # echo 'hist:key=pid:wakeupswitch_lat=$wakeup_lat+$switchtime_lat ...' >> event3/trigger @@ -1784,7 +1790,7 @@ separated by semicolons, to the tracing/synthetic_events file. For instance, the following creates a new event named 'wakeup_latency' with 3 fields: lat, pid, and prio. Each of those fields is simply a -variable reference to a variable on another event: +variable reference to a variable on another event:: # echo 'wakeup_latency \ u64 lat; \ @@ -1793,13 +1799,13 @@ variable reference to a variable on another event: /sys/kernel/debug/tracing/synthetic_events Reading the tracing/synthetic_events file lists all the currently -defined synthetic events, in this case the event defined above: +defined synthetic events, in this case the event defined above:: # cat /sys/kernel/debug/tracing/synthetic_events wakeup_latency u64 lat; pid_t pid; int prio An existing synthetic event definition can be removed by prepending -the command that defined it with a '!': +the command that defined it with a '!':: # echo '!wakeup_latency u64 lat pid_t pid int prio' >> \ /sys/kernel/debug/tracing/synthetic_events @@ -1811,13 +1817,13 @@ and variables defined on other events (see Section 2.2.3 below on how that is done using hist trigger 'onmatch' action). Once that is done, the 'wakeup_latency' synthetic event instance is created. -A histogram can now be defined for the new synthetic event: +A histogram can now be defined for the new synthetic event:: # echo 'hist:keys=pid,prio,lat.log2:sort=pid,lat' >> \ /sys/kernel/debug/tracing/events/synthetic/wakeup_latency/trigger The new event is created under the tracing/events/synthetic/ directory -and looks and behaves just like any other event: +and looks and behaves just like any other event:: # ls /sys/kernel/debug/tracing/events/synthetic/wakeup_latency enable filter format hist id trigger @@ -1872,74 +1878,74 @@ hist trigger specification. As an example the below defines a simple synthetic event and uses a variable defined on the sched_wakeup_new event as a parameter when invoking the synthetic event. Here we define the synthetic - event: + event:: - # echo 'wakeup_new_test pid_t pid' >> \ - /sys/kernel/debug/tracing/synthetic_events + # echo 'wakeup_new_test pid_t pid' >> \ + /sys/kernel/debug/tracing/synthetic_events - # cat /sys/kernel/debug/tracing/synthetic_events - wakeup_new_test pid_t pid + # cat /sys/kernel/debug/tracing/synthetic_events + wakeup_new_test pid_t pid The following hist trigger both defines the missing testpid variable and specifies an onmatch() action that generates a wakeup_new_test synthetic event whenever a sched_wakeup_new event occurs, which because of the 'if comm == "cyclictest"' filter only - happens when the executable is cyclictest: + happens when the executable is cyclictest:: - # echo 'hist:keys=$testpid:testpid=pid:onmatch(sched.sched_wakeup_new).\ - wakeup_new_test($testpid) if comm=="cyclictest"' >> \ - /sys/kernel/debug/tracing/events/sched/sched_wakeup_new/trigger + # echo 'hist:keys=$testpid:testpid=pid:onmatch(sched.sched_wakeup_new).\ + wakeup_new_test($testpid) if comm=="cyclictest"' >> \ + /sys/kernel/debug/tracing/events/sched/sched_wakeup_new/trigger Creating and displaying a histogram based on those events is now just a matter of using the fields and new synthetic event in the - tracing/events/synthetic directory, as usual: + tracing/events/synthetic directory, as usual:: - # echo 'hist:keys=pid:sort=pid' >> \ - /sys/kernel/debug/tracing/events/synthetic/wakeup_new_test/trigger + # echo 'hist:keys=pid:sort=pid' >> \ + /sys/kernel/debug/tracing/events/synthetic/wakeup_new_test/trigger Running 'cyclictest' should cause wakeup_new events to generate wakeup_new_test synthetic events which should result in histogram - output in the wakeup_new_test event's hist file: + output in the wakeup_new_test event's hist file:: - # cat /sys/kernel/debug/tracing/events/synthetic/wakeup_new_test/hist + # cat /sys/kernel/debug/tracing/events/synthetic/wakeup_new_test/hist A more typical usage would be to use two events to calculate a latency. The following example uses a set of hist triggers to - produce a 'wakeup_latency' histogram: + produce a 'wakeup_latency' histogram. - First, we define a 'wakeup_latency' synthetic event: + First, we define a 'wakeup_latency' synthetic event:: - # echo 'wakeup_latency u64 lat; pid_t pid; int prio' >> \ - /sys/kernel/debug/tracing/synthetic_events + # echo 'wakeup_latency u64 lat; pid_t pid; int prio' >> \ + /sys/kernel/debug/tracing/synthetic_events Next, we specify that whenever we see a sched_waking event for a - cyclictest thread, save the timestamp in a 'ts0' variable: + cyclictest thread, save the timestamp in a 'ts0' variable:: - # echo 'hist:keys=$saved_pid:saved_pid=pid:ts0=common_timestamp.usecs \ - if comm=="cyclictest"' >> \ - /sys/kernel/debug/tracing/events/sched/sched_waking/trigger + # echo 'hist:keys=$saved_pid:saved_pid=pid:ts0=common_timestamp.usecs \ + if comm=="cyclictest"' >> \ + /sys/kernel/debug/tracing/events/sched/sched_waking/trigger Then, when the corresponding thread is actually scheduled onto the CPU by a sched_switch event, calculate the latency and use that along with another variable and an event field to generate a - wakeup_latency synthetic event: + wakeup_latency synthetic event:: - # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:\ - onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,\ - $saved_pid,next_prio) if next_comm=="cyclictest"' >> \ - /sys/kernel/debug/tracing/events/sched/sched_switch/trigger + # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:\ + onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,\ + $saved_pid,next_prio) if next_comm=="cyclictest"' >> \ + /sys/kernel/debug/tracing/events/sched/sched_switch/trigger We also need to create a histogram on the wakeup_latency synthetic - event in order to aggregate the generated synthetic event data: + event in order to aggregate the generated synthetic event data:: - # echo 'hist:keys=pid,prio,lat:sort=pid,lat' >> \ - /sys/kernel/debug/tracing/events/synthetic/wakeup_latency/trigger + # echo 'hist:keys=pid,prio,lat:sort=pid,lat' >> \ + /sys/kernel/debug/tracing/events/synthetic/wakeup_latency/trigger Finally, once we've run cyclictest to actually generate some events, we can see the output by looking at the wakeup_latency - synthetic event's hist file: + synthetic event's hist file:: - # cat /sys/kernel/debug/tracing/events/synthetic/wakeup_latency/hist + # cat /sys/kernel/debug/tracing/events/synthetic/wakeup_latency/hist - onmax(var).save(field,.. .) @@ -1961,38 +1967,38 @@ hist trigger specification. back to that pid, the timestamp difference is calculated. If the resulting latency, stored in wakeup_lat, exceeds the current maximum latency, the values specified in the save() fields are - recorded: + recorded:: - # echo 'hist:keys=pid:ts0=common_timestamp.usecs \ - if comm=="cyclictest"' >> \ - /sys/kernel/debug/tracing/events/sched/sched_waking/trigger + # echo 'hist:keys=pid:ts0=common_timestamp.usecs \ + if comm=="cyclictest"' >> \ + /sys/kernel/debug/tracing/events/sched/sched_waking/trigger - # echo 'hist:keys=next_pid:\ - wakeup_lat=common_timestamp.usecs-$ts0:\ - onmax($wakeup_lat).save(next_comm,prev_pid,prev_prio,prev_comm) \ - if next_comm=="cyclictest"' >> \ - /sys/kernel/debug/tracing/events/sched/sched_switch/trigger + # echo 'hist:keys=next_pid:\ + wakeup_lat=common_timestamp.usecs-$ts0:\ + onmax($wakeup_lat).save(next_comm,prev_pid,prev_prio,prev_comm) \ + if next_comm=="cyclictest"' >> \ + /sys/kernel/debug/tracing/events/sched/sched_switch/trigger When the histogram is displayed, the max value and the saved values corresponding to the max are displayed following the rest - of the fields: + of the fields:: - # cat /sys/kernel/debug/tracing/events/sched/sched_switch/hist - { next_pid: 2255 } hitcount: 239 - common_timestamp-ts0: 0 - max: 27 - next_comm: cyclictest - prev_pid: 0 prev_prio: 120 prev_comm: swapper/1 + # cat /sys/kernel/debug/tracing/events/sched/sched_switch/hist + { next_pid: 2255 } hitcount: 239 + common_timestamp-ts0: 0 + max: 27 + next_comm: cyclictest + prev_pid: 0 prev_prio: 120 prev_comm: swapper/1 - { next_pid: 2256 } hitcount: 2355 - common_timestamp-ts0: 0 - max: 49 next_comm: cyclictest - prev_pid: 0 prev_prio: 120 prev_comm: swapper/0 + { next_pid: 2256 } hitcount: 2355 + common_timestamp-ts0: 0 + max: 49 next_comm: cyclictest + prev_pid: 0 prev_prio: 120 prev_comm: swapper/0 - Totals: - Hits: 12970 - Entries: 2 - Dropped: 0 + Totals: + Hits: 12970 + Entries: 2 + Dropped: 0 3. User space creating a trigger -------------------------------- @@ -2002,24 +2008,24 @@ ring buffer. This can also act like an event, by writing into the trigger file located in /sys/kernel/tracing/events/ftrace/print/ Modifying cyclictest to write into the trace_marker file before it sleeps -and after it wakes up, something like this: +and after it wakes up, something like this:: -static void traceputs(char *str) -{ + static void traceputs(char *str) + { /* tracemark_fd is the trace_marker file descriptor */ if (tracemark_fd < 0) return; /* write the tracemark message */ write(tracemark_fd, str, strlen(str)); -} + } -And later add something like: +And later add something like:: traceputs("start"); clock_nanosleep(...); traceputs("end"); -We can make a histogram from this: +We can make a histogram from this:: # cd /sys/kernel/tracing # echo 'latency u64 lat' > synthetic_events @@ -2034,7 +2040,7 @@ it will call the "latency" synthetic event with the calculated latency as its parameter. Finally, a histogram is added to the latency synthetic event to record the calculated latency along with the pid. -Now running cyclictest with: +Now running cyclictest with:: # ./cyclictest -p80 -d0 -i250 -n -a -t --tracemark -b 1000 @@ -2049,297 +2055,297 @@ Now running cyclictest with: Note, the -b 1000 is used just to make --tracemark available. -Then we can see the histogram created by this with: +Then we can see the histogram created by this with:: # cat events/synthetic/latency/hist -# event histogram -# -# trigger info: hist:keys=lat,common_pid:vals=hitcount:sort=lat:size=2048 [active] -# - -{ lat: 107, common_pid: 2039 } hitcount: 1 -{ lat: 122, common_pid: 2041 } hitcount: 1 -{ lat: 166, common_pid: 2039 } hitcount: 1 -{ lat: 174, common_pid: 2039 } hitcount: 1 -{ lat: 194, common_pid: 2041 } hitcount: 1 -{ lat: 196, common_pid: 2036 } hitcount: 1 -{ lat: 197, common_pid: 2038 } hitcount: 1 -{ lat: 198, common_pid: 2039 } hitcount: 1 -{ lat: 199, common_pid: 2039 } hitcount: 1 -{ lat: 200, common_pid: 2041 } hitcount: 1 -{ lat: 201, common_pid: 2039 } hitcount: 2 -{ lat: 202, common_pid: 2038 } hitcount: 1 -{ lat: 202, common_pid: 2043 } hitcount: 1 -{ lat: 203, common_pid: 2039 } hitcount: 1 -{ lat: 203, common_pid: 2036 } hitcount: 1 -{ lat: 203, common_pid: 2041 } hitcount: 1 -{ lat: 206, common_pid: 2038 } hitcount: 2 -{ lat: 207, common_pid: 2039 } hitcount: 1 -{ lat: 207, common_pid: 2036 } hitcount: 1 -{ lat: 208, common_pid: 2040 } hitcount: 1 -{ lat: 209, common_pid: 2043 } hitcount: 1 -{ lat: 210, common_pid: 2039 } hitcount: 1 -{ lat: 211, common_pid: 2039 } hitcount: 4 -{ lat: 212, common_pid: 2043 } hitcount: 1 -{ lat: 212, common_pid: 2039 } hitcount: 2 -{ lat: 213, common_pid: 2039 } hitcount: 1 -{ lat: 214, common_pid: 2038 } hitcount: 1 -{ lat: 214, common_pid: 2039 } hitcount: 2 -{ lat: 214, common_pid: 2042 } hitcount: 1 -{ lat: 215, common_pid: 2039 } hitcount: 1 -{ lat: 217, common_pid: 2036 } hitcount: 1 -{ lat: 217, common_pid: 2040 } hitcount: 1 -{ lat: 217, common_pid: 2039 } hitcount: 1 -{ lat: 218, common_pid: 2039 } hitcount: 6 -{ lat: 219, common_pid: 2039 } hitcount: 9 -{ lat: 220, common_pid: 2039 } hitcount: 11 -{ lat: 221, common_pid: 2039 } hitcount: 5 -{ lat: 221, common_pid: 2042 } hitcount: 1 -{ lat: 222, common_pid: 2039 } hitcount: 7 -{ lat: 223, common_pid: 2036 } hitcount: 1 -{ lat: 223, common_pid: 2039 } hitcount: 3 -{ lat: 224, common_pid: 2039 } hitcount: 4 -{ lat: 224, common_pid: 2037 } hitcount: 1 -{ lat: 224, common_pid: 2036 } hitcount: 2 -{ lat: 225, common_pid: 2039 } hitcount: 5 -{ lat: 225, common_pid: 2042 } hitcount: 1 -{ lat: 226, common_pid: 2039 } hitcount: 7 -{ lat: 226, common_pid: 2036 } hitcount: 4 -{ lat: 227, common_pid: 2039 } hitcount: 6 -{ lat: 227, common_pid: 2036 } hitcount: 12 -{ lat: 227, common_pid: 2043 } hitcount: 1 -{ lat: 228, common_pid: 2039 } hitcount: 7 -{ lat: 228, common_pid: 2036 } hitcount: 14 -{ lat: 229, common_pid: 2039 } hitcount: 9 -{ lat: 229, common_pid: 2036 } hitcount: 8 -{ lat: 229, common_pid: 2038 } hitcount: 1 -{ lat: 230, common_pid: 2039 } hitcount: 11 -{ lat: 230, common_pid: 2036 } hitcount: 6 -{ lat: 230, common_pid: 2043 } hitcount: 1 -{ lat: 230, common_pid: 2042 } hitcount: 2 -{ lat: 231, common_pid: 2041 } hitcount: 1 -{ lat: 231, common_pid: 2036 } hitcount: 6 -{ lat: 231, common_pid: 2043 } hitcount: 1 -{ lat: 231, common_pid: 2039 } hitcount: 8 -{ lat: 232, common_pid: 2037 } hitcount: 1 -{ lat: 232, common_pid: 2039 } hitcount: 6 -{ lat: 232, common_pid: 2040 } hitcount: 2 -{ lat: 232, common_pid: 2036 } hitcount: 5 -{ lat: 232, common_pid: 2043 } hitcount: 1 -{ lat: 233, common_pid: 2036 } hitcount: 5 -{ lat: 233, common_pid: 2039 } hitcount: 11 -{ lat: 234, common_pid: 2039 } hitcount: 4 -{ lat: 234, common_pid: 2038 } hitcount: 2 -{ lat: 234, common_pid: 2043 } hitcount: 2 -{ lat: 234, common_pid: 2036 } hitcount: 11 -{ lat: 234, common_pid: 2040 } hitcount: 1 -{ lat: 235, common_pid: 2037 } hitcount: 2 -{ lat: 235, common_pid: 2036 } hitcount: 8 -{ lat: 235, common_pid: 2043 } hitcount: 2 -{ lat: 235, common_pid: 2039 } hitcount: 5 -{ lat: 235, common_pid: 2042 } hitcount: 2 -{ lat: 235, common_pid: 2040 } hitcount: 4 -{ lat: 235, common_pid: 2041 } hitcount: 1 -{ lat: 236, common_pid: 2036 } hitcount: 7 -{ lat: 236, common_pid: 2037 } hitcount: 1 -{ lat: 236, common_pid: 2041 } hitcount: 5 -{ lat: 236, common_pid: 2039 } hitcount: 3 -{ lat: 236, common_pid: 2043 } hitcount: 9 -{ lat: 236, common_pid: 2040 } hitcount: 7 -{ lat: 237, common_pid: 2037 } hitcount: 1 -{ lat: 237, common_pid: 2040 } hitcount: 1 -{ lat: 237, common_pid: 2036 } hitcount: 9 -{ lat: 237, common_pid: 2039 } hitcount: 3 -{ lat: 237, common_pid: 2043 } hitcount: 8 -{ lat: 237, common_pid: 2042 } hitcount: 2 -{ lat: 237, common_pid: 2041 } hitcount: 2 -{ lat: 238, common_pid: 2043 } hitcount: 10 -{ lat: 238, common_pid: 2040 } hitcount: 1 -{ lat: 238, common_pid: 2037 } hitcount: 9 -{ lat: 238, common_pid: 2038 } hitcount: 1 -{ lat: 238, common_pid: 2039 } hitcount: 1 -{ lat: 238, common_pid: 2042 } hitcount: 3 -{ lat: 238, common_pid: 2036 } hitcount: 7 -{ lat: 239, common_pid: 2041 } hitcount: 1 -{ lat: 239, common_pid: 2043 } hitcount: 11 -{ lat: 239, common_pid: 2037 } hitcount: 11 -{ lat: 239, common_pid: 2038 } hitcount: 6 -{ lat: 239, common_pid: 2036 } hitcount: 7 -{ lat: 239, common_pid: 2040 } hitcount: 1 -{ lat: 239, common_pid: 2042 } hitcount: 9 -{ lat: 240, common_pid: 2037 } hitcount: 29 -{ lat: 240, common_pid: 2043 } hitcount: 15 -{ lat: 240, common_pid: 2040 } hitcount: 44 -{ lat: 240, common_pid: 2039 } hitcount: 1 -{ lat: 240, common_pid: 2041 } hitcount: 2 -{ lat: 240, common_pid: 2038 } hitcount: 1 -{ lat: 240, common_pid: 2036 } hitcount: 10 -{ lat: 240, common_pid: 2042 } hitcount: 13 -{ lat: 241, common_pid: 2036 } hitcount: 21 -{ lat: 241, common_pid: 2041 } hitcount: 36 -{ lat: 241, common_pid: 2037 } hitcount: 34 -{ lat: 241, common_pid: 2042 } hitcount: 14 -{ lat: 241, common_pid: 2040 } hitcount: 94 -{ lat: 241, common_pid: 2039 } hitcount: 12 -{ lat: 241, common_pid: 2038 } hitcount: 2 -{ lat: 241, common_pid: 2043 } hitcount: 28 -{ lat: 242, common_pid: 2040 } hitcount: 109 -{ lat: 242, common_pid: 2041 } hitcount: 506 -{ lat: 242, common_pid: 2039 } hitcount: 155 -{ lat: 242, common_pid: 2042 } hitcount: 21 -{ lat: 242, common_pid: 2037 } hitcount: 52 -{ lat: 242, common_pid: 2043 } hitcount: 21 -{ lat: 242, common_pid: 2036 } hitcount: 16 -{ lat: 242, common_pid: 2038 } hitcount: 156 -{ lat: 243, common_pid: 2037 } hitcount: 46 -{ lat: 243, common_pid: 2039 } hitcount: 40 -{ lat: 243, common_pid: 2042 } hitcount: 119 -{ lat: 243, common_pid: 2041 } hitcount: 611 -{ lat: 243, common_pid: 2036 } hitcount: 69 -{ lat: 243, common_pid: 2038 } hitcount: 784 -{ lat: 243, common_pid: 2040 } hitcount: 323 -{ lat: 243, common_pid: 2043 } hitcount: 14 -{ lat: 244, common_pid: 2043 } hitcount: 35 -{ lat: 244, common_pid: 2042 } hitcount: 305 -{ lat: 244, common_pid: 2039 } hitcount: 8 -{ lat: 244, common_pid: 2040 } hitcount: 4515 -{ lat: 244, common_pid: 2038 } hitcount: 371 -{ lat: 244, common_pid: 2037 } hitcount: 31 -{ lat: 244, common_pid: 2036 } hitcount: 114 -{ lat: 244, common_pid: 2041 } hitcount: 3396 -{ lat: 245, common_pid: 2036 } hitcount: 700 -{ lat: 245, common_pid: 2041 } hitcount: 2772 -{ lat: 245, common_pid: 2037 } hitcount: 268 -{ lat: 245, common_pid: 2039 } hitcount: 472 -{ lat: 245, common_pid: 2038 } hitcount: 2758 -{ lat: 245, common_pid: 2042 } hitcount: 3833 -{ lat: 245, common_pid: 2040 } hitcount: 3105 -{ lat: 245, common_pid: 2043 } hitcount: 645 -{ lat: 246, common_pid: 2038 } hitcount: 3451 -{ lat: 246, common_pid: 2041 } hitcount: 142 -{ lat: 246, common_pid: 2037 } hitcount: 5101 -{ lat: 246, common_pid: 2040 } hitcount: 68 -{ lat: 246, common_pid: 2043 } hitcount: 5099 -{ lat: 246, common_pid: 2039 } hitcount: 5608 -{ lat: 246, common_pid: 2042 } hitcount: 3723 -{ lat: 246, common_pid: 2036 } hitcount: 4738 -{ lat: 247, common_pid: 2042 } hitcount: 312 -{ lat: 247, common_pid: 2043 } hitcount: 2385 -{ lat: 247, common_pid: 2041 } hitcount: 452 -{ lat: 247, common_pid: 2038 } hitcount: 792 -{ lat: 247, common_pid: 2040 } hitcount: 78 -{ lat: 247, common_pid: 2036 } hitcount: 2375 -{ lat: 247, common_pid: 2039 } hitcount: 1834 -{ lat: 247, common_pid: 2037 } hitcount: 2655 -{ lat: 248, common_pid: 2037 } hitcount: 36 -{ lat: 248, common_pid: 2042 } hitcount: 11 -{ lat: 248, common_pid: 2038 } hitcount: 122 -{ lat: 248, common_pid: 2036 } hitcount: 135 -{ lat: 248, common_pid: 2039 } hitcount: 26 -{ lat: 248, common_pid: 2041 } hitcount: 503 -{ lat: 248, common_pid: 2043 } hitcount: 66 -{ lat: 248, common_pid: 2040 } hitcount: 46 -{ lat: 249, common_pid: 2037 } hitcount: 29 -{ lat: 249, common_pid: 2038 } hitcount: 1 -{ lat: 249, common_pid: 2043 } hitcount: 29 -{ lat: 249, common_pid: 2039 } hitcount: 8 -{ lat: 249, common_pid: 2042 } hitcount: 56 -{ lat: 249, common_pid: 2040 } hitcount: 27 -{ lat: 249, common_pid: 2041 } hitcount: 11 -{ lat: 249, common_pid: 2036 } hitcount: 27 -{ lat: 250, common_pid: 2038 } hitcount: 1 -{ lat: 250, common_pid: 2036 } hitcount: 30 -{ lat: 250, common_pid: 2040 } hitcount: 19 -{ lat: 250, common_pid: 2043 } hitcount: 22 -{ lat: 250, common_pid: 2042 } hitcount: 20 -{ lat: 250, common_pid: 2041 } hitcount: 1 -{ lat: 250, common_pid: 2039 } hitcount: 6 -{ lat: 250, common_pid: 2037 } hitcount: 48 -{ lat: 251, common_pid: 2037 } hitcount: 43 -{ lat: 251, common_pid: 2039 } hitcount: 1 -{ lat: 251, common_pid: 2036 } hitcount: 12 -{ lat: 251, common_pid: 2042 } hitcount: 2 -{ lat: 251, common_pid: 2041 } hitcount: 1 -{ lat: 251, common_pid: 2043 } hitcount: 15 -{ lat: 251, common_pid: 2040 } hitcount: 3 -{ lat: 252, common_pid: 2040 } hitcount: 1 -{ lat: 252, common_pid: 2036 } hitcount: 12 -{ lat: 252, common_pid: 2037 } hitcount: 21 -{ lat: 252, common_pid: 2043 } hitcount: 14 -{ lat: 253, common_pid: 2037 } hitcount: 21 -{ lat: 253, common_pid: 2039 } hitcount: 2 -{ lat: 253, common_pid: 2036 } hitcount: 9 -{ lat: 253, common_pid: 2043 } hitcount: 6 -{ lat: 253, common_pid: 2040 } hitcount: 1 -{ lat: 254, common_pid: 2036 } hitcount: 8 -{ lat: 254, common_pid: 2043 } hitcount: 3 -{ lat: 254, common_pid: 2041 } hitcount: 1 -{ lat: 254, common_pid: 2042 } hitcount: 1 -{ lat: 254, common_pid: 2039 } hitcount: 1 -{ lat: 254, common_pid: 2037 } hitcount: 12 -{ lat: 255, common_pid: 2043 } hitcount: 1 -{ lat: 255, common_pid: 2037 } hitcount: 2 -{ lat: 255, common_pid: 2036 } hitcount: 2 -{ lat: 255, common_pid: 2039 } hitcount: 8 -{ lat: 256, common_pid: 2043 } hitcount: 1 -{ lat: 256, common_pid: 2036 } hitcount: 4 -{ lat: 256, common_pid: 2039 } hitcount: 6 -{ lat: 257, common_pid: 2039 } hitcount: 5 -{ lat: 257, common_pid: 2036 } hitcount: 4 -{ lat: 258, common_pid: 2039 } hitcount: 5 -{ lat: 258, common_pid: 2036 } hitcount: 2 -{ lat: 259, common_pid: 2036 } hitcount: 7 -{ lat: 259, common_pid: 2039 } hitcount: 7 -{ lat: 260, common_pid: 2036 } hitcount: 8 -{ lat: 260, common_pid: 2039 } hitcount: 6 -{ lat: 261, common_pid: 2036 } hitcount: 5 -{ lat: 261, common_pid: 2039 } hitcount: 7 -{ lat: 262, common_pid: 2039 } hitcount: 5 -{ lat: 262, common_pid: 2036 } hitcount: 5 -{ lat: 263, common_pid: 2039 } hitcount: 7 -{ lat: 263, common_pid: 2036 } hitcount: 7 -{ lat: 264, common_pid: 2039 } hitcount: 9 -{ lat: 264, common_pid: 2036 } hitcount: 9 -{ lat: 265, common_pid: 2036 } hitcount: 5 -{ lat: 265, common_pid: 2039 } hitcount: 1 -{ lat: 266, common_pid: 2036 } hitcount: 1 -{ lat: 266, common_pid: 2039 } hitcount: 3 -{ lat: 267, common_pid: 2036 } hitcount: 1 -{ lat: 267, common_pid: 2039 } hitcount: 3 -{ lat: 268, common_pid: 2036 } hitcount: 1 -{ lat: 268, common_pid: 2039 } hitcount: 6 -{ lat: 269, common_pid: 2036 } hitcount: 1 -{ lat: 269, common_pid: 2043 } hitcount: 1 -{ lat: 269, common_pid: 2039 } hitcount: 2 -{ lat: 270, common_pid: 2040 } hitcount: 1 -{ lat: 270, common_pid: 2039 } hitcount: 6 -{ lat: 271, common_pid: 2041 } hitcount: 1 -{ lat: 271, common_pid: 2039 } hitcount: 5 -{ lat: 272, common_pid: 2039 } hitcount: 10 -{ lat: 273, common_pid: 2039 } hitcount: 8 -{ lat: 274, common_pid: 2039 } hitcount: 2 -{ lat: 275, common_pid: 2039 } hitcount: 1 -{ lat: 276, common_pid: 2039 } hitcount: 2 -{ lat: 276, common_pid: 2037 } hitcount: 1 -{ lat: 276, common_pid: 2038 } hitcount: 1 -{ lat: 277, common_pid: 2039 } hitcount: 1 -{ lat: 277, common_pid: 2042 } hitcount: 1 -{ lat: 278, common_pid: 2039 } hitcount: 1 -{ lat: 279, common_pid: 2039 } hitcount: 4 -{ lat: 279, common_pid: 2043 } hitcount: 1 -{ lat: 280, common_pid: 2039 } hitcount: 3 -{ lat: 283, common_pid: 2036 } hitcount: 2 -{ lat: 284, common_pid: 2039 } hitcount: 1 -{ lat: 284, common_pid: 2043 } hitcount: 1 -{ lat: 288, common_pid: 2039 } hitcount: 1 -{ lat: 289, common_pid: 2039 } hitcount: 1 -{ lat: 300, common_pid: 2039 } hitcount: 1 -{ lat: 384, common_pid: 2039 } hitcount: 1 - -Totals: - Hits: 67625 - Entries: 278 - Dropped: 0 + # event histogram + # + # trigger info: hist:keys=lat,common_pid:vals=hitcount:sort=lat:size=2048 [active] + # + + { lat: 107, common_pid: 2039 } hitcount: 1 + { lat: 122, common_pid: 2041 } hitcount: 1 + { lat: 166, common_pid: 2039 } hitcount: 1 + { lat: 174, common_pid: 2039 } hitcount: 1 + { lat: 194, common_pid: 2041 } hitcount: 1 + { lat: 196, common_pid: 2036 } hitcount: 1 + { lat: 197, common_pid: 2038 } hitcount: 1 + { lat: 198, common_pid: 2039 } hitcount: 1 + { lat: 199, common_pid: 2039 } hitcount: 1 + { lat: 200, common_pid: 2041 } hitcount: 1 + { lat: 201, common_pid: 2039 } hitcount: 2 + { lat: 202, common_pid: 2038 } hitcount: 1 + { lat: 202, common_pid: 2043 } hitcount: 1 + { lat: 203, common_pid: 2039 } hitcount: 1 + { lat: 203, common_pid: 2036 } hitcount: 1 + { lat: 203, common_pid: 2041 } hitcount: 1 + { lat: 206, common_pid: 2038 } hitcount: 2 + { lat: 207, common_pid: 2039 } hitcount: 1 + { lat: 207, common_pid: 2036 } hitcount: 1 + { lat: 208, common_pid: 2040 } hitcount: 1 + { lat: 209, common_pid: 2043 } hitcount: 1 + { lat: 210, common_pid: 2039 } hitcount: 1 + { lat: 211, common_pid: 2039 } hitcount: 4 + { lat: 212, common_pid: 2043 } hitcount: 1 + { lat: 212, common_pid: 2039 } hitcount: 2 + { lat: 213, common_pid: 2039 } hitcount: 1 + { lat: 214, common_pid: 2038 } hitcount: 1 + { lat: 214, common_pid: 2039 } hitcount: 2 + { lat: 214, common_pid: 2042 } hitcount: 1 + { lat: 215, common_pid: 2039 } hitcount: 1 + { lat: 217, common_pid: 2036 } hitcount: 1 + { lat: 217, common_pid: 2040 } hitcount: 1 + { lat: 217, common_pid: 2039 } hitcount: 1 + { lat: 218, common_pid: 2039 } hitcount: 6 + { lat: 219, common_pid: 2039 } hitcount: 9 + { lat: 220, common_pid: 2039 } hitcount: 11 + { lat: 221, common_pid: 2039 } hitcount: 5 + { lat: 221, common_pid: 2042 } hitcount: 1 + { lat: 222, common_pid: 2039 } hitcount: 7 + { lat: 223, common_pid: 2036 } hitcount: 1 + { lat: 223, common_pid: 2039 } hitcount: 3 + { lat: 224, common_pid: 2039 } hitcount: 4 + { lat: 224, common_pid: 2037 } hitcount: 1 + { lat: 224, common_pid: 2036 } hitcount: 2 + { lat: 225, common_pid: 2039 } hitcount: 5 + { lat: 225, common_pid: 2042 } hitcount: 1 + { lat: 226, common_pid: 2039 } hitcount: 7 + { lat: 226, common_pid: 2036 } hitcount: 4 + { lat: 227, common_pid: 2039 } hitcount: 6 + { lat: 227, common_pid: 2036 } hitcount: 12 + { lat: 227, common_pid: 2043 } hitcount: 1 + { lat: 228, common_pid: 2039 } hitcount: 7 + { lat: 228, common_pid: 2036 } hitcount: 14 + { lat: 229, common_pid: 2039 } hitcount: 9 + { lat: 229, common_pid: 2036 } hitcount: 8 + { lat: 229, common_pid: 2038 } hitcount: 1 + { lat: 230, common_pid: 2039 } hitcount: 11 + { lat: 230, common_pid: 2036 } hitcount: 6 + { lat: 230, common_pid: 2043 } hitcount: 1 + { lat: 230, common_pid: 2042 } hitcount: 2 + { lat: 231, common_pid: 2041 } hitcount: 1 + { lat: 231, common_pid: 2036 } hitcount: 6 + { lat: 231, common_pid: 2043 } hitcount: 1 + { lat: 231, common_pid: 2039 } hitcount: 8 + { lat: 232, common_pid: 2037 } hitcount: 1 + { lat: 232, common_pid: 2039 } hitcount: 6 + { lat: 232, common_pid: 2040 } hitcount: 2 + { lat: 232, common_pid: 2036 } hitcount: 5 + { lat: 232, common_pid: 2043 } hitcount: 1 + { lat: 233, common_pid: 2036 } hitcount: 5 + { lat: 233, common_pid: 2039 } hitcount: 11 + { lat: 234, common_pid: 2039 } hitcount: 4 + { lat: 234, common_pid: 2038 } hitcount: 2 + { lat: 234, common_pid: 2043 } hitcount: 2 + { lat: 234, common_pid: 2036 } hitcount: 11 + { lat: 234, common_pid: 2040 } hitcount: 1 + { lat: 235, common_pid: 2037 } hitcount: 2 + { lat: 235, common_pid: 2036 } hitcount: 8 + { lat: 235, common_pid: 2043 } hitcount: 2 + { lat: 235, common_pid: 2039 } hitcount: 5 + { lat: 235, common_pid: 2042 } hitcount: 2 + { lat: 235, common_pid: 2040 } hitcount: 4 + { lat: 235, common_pid: 2041 } hitcount: 1 + { lat: 236, common_pid: 2036 } hitcount: 7 + { lat: 236, common_pid: 2037 } hitcount: 1 + { lat: 236, common_pid: 2041 } hitcount: 5 + { lat: 236, common_pid: 2039 } hitcount: 3 + { lat: 236, common_pid: 2043 } hitcount: 9 + { lat: 236, common_pid: 2040 } hitcount: 7 + { lat: 237, common_pid: 2037 } hitcount: 1 + { lat: 237, common_pid: 2040 } hitcount: 1 + { lat: 237, common_pid: 2036 } hitcount: 9 + { lat: 237, common_pid: 2039 } hitcount: 3 + { lat: 237, common_pid: 2043 } hitcount: 8 + { lat: 237, common_pid: 2042 } hitcount: 2 + { lat: 237, common_pid: 2041 } hitcount: 2 + { lat: 238, common_pid: 2043 } hitcount: 10 + { lat: 238, common_pid: 2040 } hitcount: 1 + { lat: 238, common_pid: 2037 } hitcount: 9 + { lat: 238, common_pid: 2038 } hitcount: 1 + { lat: 238, common_pid: 2039 } hitcount: 1 + { lat: 238, common_pid: 2042 } hitcount: 3 + { lat: 238, common_pid: 2036 } hitcount: 7 + { lat: 239, common_pid: 2041 } hitcount: 1 + { lat: 239, common_pid: 2043 } hitcount: 11 + { lat: 239, common_pid: 2037 } hitcount: 11 + { lat: 239, common_pid: 2038 } hitcount: 6 + { lat: 239, common_pid: 2036 } hitcount: 7 + { lat: 239, common_pid: 2040 } hitcount: 1 + { lat: 239, common_pid: 2042 } hitcount: 9 + { lat: 240, common_pid: 2037 } hitcount: 29 + { lat: 240, common_pid: 2043 } hitcount: 15 + { lat: 240, common_pid: 2040 } hitcount: 44 + { lat: 240, common_pid: 2039 } hitcount: 1 + { lat: 240, common_pid: 2041 } hitcount: 2 + { lat: 240, common_pid: 2038 } hitcount: 1 + { lat: 240, common_pid: 2036 } hitcount: 10 + { lat: 240, common_pid: 2042 } hitcount: 13 + { lat: 241, common_pid: 2036 } hitcount: 21 + { lat: 241, common_pid: 2041 } hitcount: 36 + { lat: 241, common_pid: 2037 } hitcount: 34 + { lat: 241, common_pid: 2042 } hitcount: 14 + { lat: 241, common_pid: 2040 } hitcount: 94 + { lat: 241, common_pid: 2039 } hitcount: 12 + { lat: 241, common_pid: 2038 } hitcount: 2 + { lat: 241, common_pid: 2043 } hitcount: 28 + { lat: 242, common_pid: 2040 } hitcount: 109 + { lat: 242, common_pid: 2041 } hitcount: 506 + { lat: 242, common_pid: 2039 } hitcount: 155 + { lat: 242, common_pid: 2042 } hitcount: 21 + { lat: 242, common_pid: 2037 } hitcount: 52 + { lat: 242, common_pid: 2043 } hitcount: 21 + { lat: 242, common_pid: 2036 } hitcount: 16 + { lat: 242, common_pid: 2038 } hitcount: 156 + { lat: 243, common_pid: 2037 } hitcount: 46 + { lat: 243, common_pid: 2039 } hitcount: 40 + { lat: 243, common_pid: 2042 } hitcount: 119 + { lat: 243, common_pid: 2041 } hitcount: 611 + { lat: 243, common_pid: 2036 } hitcount: 69 + { lat: 243, common_pid: 2038 } hitcount: 784 + { lat: 243, common_pid: 2040 } hitcount: 323 + { lat: 243, common_pid: 2043 } hitcount: 14 + { lat: 244, common_pid: 2043 } hitcount: 35 + { lat: 244, common_pid: 2042 } hitcount: 305 + { lat: 244, common_pid: 2039 } hitcount: 8 + { lat: 244, common_pid: 2040 } hitcount: 4515 + { lat: 244, common_pid: 2038 } hitcount: 371 + { lat: 244, common_pid: 2037 } hitcount: 31 + { lat: 244, common_pid: 2036 } hitcount: 114 + { lat: 244, common_pid: 2041 } hitcount: 3396 + { lat: 245, common_pid: 2036 } hitcount: 700 + { lat: 245, common_pid: 2041 } hitcount: 2772 + { lat: 245, common_pid: 2037 } hitcount: 268 + { lat: 245, common_pid: 2039 } hitcount: 472 + { lat: 245, common_pid: 2038 } hitcount: 2758 + { lat: 245, common_pid: 2042 } hitcount: 3833 + { lat: 245, common_pid: 2040 } hitcount: 3105 + { lat: 245, common_pid: 2043 } hitcount: 645 + { lat: 246, common_pid: 2038 } hitcount: 3451 + { lat: 246, common_pid: 2041 } hitcount: 142 + { lat: 246, common_pid: 2037 } hitcount: 5101 + { lat: 246, common_pid: 2040 } hitcount: 68 + { lat: 246, common_pid: 2043 } hitcount: 5099 + { lat: 246, common_pid: 2039 } hitcount: 5608 + { lat: 246, common_pid: 2042 } hitcount: 3723 + { lat: 246, common_pid: 2036 } hitcount: 4738 + { lat: 247, common_pid: 2042 } hitcount: 312 + { lat: 247, common_pid: 2043 } hitcount: 2385 + { lat: 247, common_pid: 2041 } hitcount: 452 + { lat: 247, common_pid: 2038 } hitcount: 792 + { lat: 247, common_pid: 2040 } hitcount: 78 + { lat: 247, common_pid: 2036 } hitcount: 2375 + { lat: 247, common_pid: 2039 } hitcount: 1834 + { lat: 247, common_pid: 2037 } hitcount: 2655 + { lat: 248, common_pid: 2037 } hitcount: 36 + { lat: 248, common_pid: 2042 } hitcount: 11 + { lat: 248, common_pid: 2038 } hitcount: 122 + { lat: 248, common_pid: 2036 } hitcount: 135 + { lat: 248, common_pid: 2039 } hitcount: 26 + { lat: 248, common_pid: 2041 } hitcount: 503 + { lat: 248, common_pid: 2043 } hitcount: 66 + { lat: 248, common_pid: 2040 } hitcount: 46 + { lat: 249, common_pid: 2037 } hitcount: 29 + { lat: 249, common_pid: 2038 } hitcount: 1 + { lat: 249, common_pid: 2043 } hitcount: 29 + { lat: 249, common_pid: 2039 } hitcount: 8 + { lat: 249, common_pid: 2042 } hitcount: 56 + { lat: 249, common_pid: 2040 } hitcount: 27 + { lat: 249, common_pid: 2041 } hitcount: 11 + { lat: 249, common_pid: 2036 } hitcount: 27 + { lat: 250, common_pid: 2038 } hitcount: 1 + { lat: 250, common_pid: 2036 } hitcount: 30 + { lat: 250, common_pid: 2040 } hitcount: 19 + { lat: 250, common_pid: 2043 } hitcount: 22 + { lat: 250, common_pid: 2042 } hitcount: 20 + { lat: 250, common_pid: 2041 } hitcount: 1 + { lat: 250, common_pid: 2039 } hitcount: 6 + { lat: 250, common_pid: 2037 } hitcount: 48 + { lat: 251, common_pid: 2037 } hitcount: 43 + { lat: 251, common_pid: 2039 } hitcount: 1 + { lat: 251, common_pid: 2036 } hitcount: 12 + { lat: 251, common_pid: 2042 } hitcount: 2 + { lat: 251, common_pid: 2041 } hitcount: 1 + { lat: 251, common_pid: 2043 } hitcount: 15 + { lat: 251, common_pid: 2040 } hitcount: 3 + { lat: 252, common_pid: 2040 } hitcount: 1 + { lat: 252, common_pid: 2036 } hitcount: 12 + { lat: 252, common_pid: 2037 } hitcount: 21 + { lat: 252, common_pid: 2043 } hitcount: 14 + { lat: 253, common_pid: 2037 } hitcount: 21 + { lat: 253, common_pid: 2039 } hitcount: 2 + { lat: 253, common_pid: 2036 } hitcount: 9 + { lat: 253, common_pid: 2043 } hitcount: 6 + { lat: 253, common_pid: 2040 } hitcount: 1 + { lat: 254, common_pid: 2036 } hitcount: 8 + { lat: 254, common_pid: 2043 } hitcount: 3 + { lat: 254, common_pid: 2041 } hitcount: 1 + { lat: 254, common_pid: 2042 } hitcount: 1 + { lat: 254, common_pid: 2039 } hitcount: 1 + { lat: 254, common_pid: 2037 } hitcount: 12 + { lat: 255, common_pid: 2043 } hitcount: 1 + { lat: 255, common_pid: 2037 } hitcount: 2 + { lat: 255, common_pid: 2036 } hitcount: 2 + { lat: 255, common_pid: 2039 } hitcount: 8 + { lat: 256, common_pid: 2043 } hitcount: 1 + { lat: 256, common_pid: 2036 } hitcount: 4 + { lat: 256, common_pid: 2039 } hitcount: 6 + { lat: 257, common_pid: 2039 } hitcount: 5 + { lat: 257, common_pid: 2036 } hitcount: 4 + { lat: 258, common_pid: 2039 } hitcount: 5 + { lat: 258, common_pid: 2036 } hitcount: 2 + { lat: 259, common_pid: 2036 } hitcount: 7 + { lat: 259, common_pid: 2039 } hitcount: 7 + { lat: 260, common_pid: 2036 } hitcount: 8 + { lat: 260, common_pid: 2039 } hitcount: 6 + { lat: 261, common_pid: 2036 } hitcount: 5 + { lat: 261, common_pid: 2039 } hitcount: 7 + { lat: 262, common_pid: 2039 } hitcount: 5 + { lat: 262, common_pid: 2036 } hitcount: 5 + { lat: 263, common_pid: 2039 } hitcount: 7 + { lat: 263, common_pid: 2036 } hitcount: 7 + { lat: 264, common_pid: 2039 } hitcount: 9 + { lat: 264, common_pid: 2036 } hitcount: 9 + { lat: 265, common_pid: 2036 } hitcount: 5 + { lat: 265, common_pid: 2039 } hitcount: 1 + { lat: 266, common_pid: 2036 } hitcount: 1 + { lat: 266, common_pid: 2039 } hitcount: 3 + { lat: 267, common_pid: 2036 } hitcount: 1 + { lat: 267, common_pid: 2039 } hitcount: 3 + { lat: 268, common_pid: 2036 } hitcount: 1 + { lat: 268, common_pid: 2039 } hitcount: 6 + { lat: 269, common_pid: 2036 } hitcount: 1 + { lat: 269, common_pid: 2043 } hitcount: 1 + { lat: 269, common_pid: 2039 } hitcount: 2 + { lat: 270, common_pid: 2040 } hitcount: 1 + { lat: 270, common_pid: 2039 } hitcount: 6 + { lat: 271, common_pid: 2041 } hitcount: 1 + { lat: 271, common_pid: 2039 } hitcount: 5 + { lat: 272, common_pid: 2039 } hitcount: 10 + { lat: 273, common_pid: 2039 } hitcount: 8 + { lat: 274, common_pid: 2039 } hitcount: 2 + { lat: 275, common_pid: 2039 } hitcount: 1 + { lat: 276, common_pid: 2039 } hitcount: 2 + { lat: 276, common_pid: 2037 } hitcount: 1 + { lat: 276, common_pid: 2038 } hitcount: 1 + { lat: 277, common_pid: 2039 } hitcount: 1 + { lat: 277, common_pid: 2042 } hitcount: 1 + { lat: 278, common_pid: 2039 } hitcount: 1 + { lat: 279, common_pid: 2039 } hitcount: 4 + { lat: 279, common_pid: 2043 } hitcount: 1 + { lat: 280, common_pid: 2039 } hitcount: 3 + { lat: 283, common_pid: 2036 } hitcount: 2 + { lat: 284, common_pid: 2039 } hitcount: 1 + { lat: 284, common_pid: 2043 } hitcount: 1 + { lat: 288, common_pid: 2039 } hitcount: 1 + { lat: 289, common_pid: 2039 } hitcount: 1 + { lat: 300, common_pid: 2039 } hitcount: 1 + { lat: 384, common_pid: 2039 } hitcount: 1 + + Totals: + Hits: 67625 + Entries: 278 + Dropped: 0 Note, the writes are around the sleep, so ideally they will all be of 250 microseconds. If you are wondering how there are several that are under @@ -2350,7 +2356,7 @@ will be at 200 microseconds. But this could easily be done in userspace. To make this even more interesting, we can mix the histogram between events that happened in the -kernel with trace_marker. +kernel with trace_marker:: # cd /sys/kernel/tracing # echo 'latency u64 lat' > synthetic_events @@ -2362,177 +2368,177 @@ The difference this time is that instead of using the trace_marker to start the latency, the sched_waking event is used, matching the common_pid for the trace_marker write with the pid that is being woken by sched_waking. -After running cyclictest again with the same parameters, we now have: +After running cyclictest again with the same parameters, we now have:: # cat events/synthetic/latency/hist -# event histogram -# -# trigger info: hist:keys=lat,common_pid:vals=hitcount:sort=lat:size=2048 [active] -# - -{ lat: 7, common_pid: 2302 } hitcount: 640 -{ lat: 7, common_pid: 2299 } hitcount: 42 -{ lat: 7, common_pid: 2303 } hitcount: 18 -{ lat: 7, common_pid: 2305 } hitcount: 166 -{ lat: 7, common_pid: 2306 } hitcount: 1 -{ lat: 7, common_pid: 2301 } hitcount: 91 -{ lat: 7, common_pid: 2300 } hitcount: 17 -{ lat: 8, common_pid: 2303 } hitcount: 8296 -{ lat: 8, common_pid: 2304 } hitcount: 6864 -{ lat: 8, common_pid: 2305 } hitcount: 9464 -{ lat: 8, common_pid: 2301 } hitcount: 9213 -{ lat: 8, common_pid: 2306 } hitcount: 6246 -{ lat: 8, common_pid: 2302 } hitcount: 8797 -{ lat: 8, common_pid: 2299 } hitcount: 8771 -{ lat: 8, common_pid: 2300 } hitcount: 8119 -{ lat: 9, common_pid: 2305 } hitcount: 1519 -{ lat: 9, common_pid: 2299 } hitcount: 2346 -{ lat: 9, common_pid: 2303 } hitcount: 2841 -{ lat: 9, common_pid: 2301 } hitcount: 1846 -{ lat: 9, common_pid: 2304 } hitcount: 3861 -{ lat: 9, common_pid: 2302 } hitcount: 1210 -{ lat: 9, common_pid: 2300 } hitcount: 2762 -{ lat: 9, common_pid: 2306 } hitcount: 4247 -{ lat: 10, common_pid: 2299 } hitcount: 16 -{ lat: 10, common_pid: 2306 } hitcount: 333 -{ lat: 10, common_pid: 2303 } hitcount: 16 -{ lat: 10, common_pid: 2304 } hitcount: 168 -{ lat: 10, common_pid: 2302 } hitcount: 240 -{ lat: 10, common_pid: 2301 } hitcount: 28 -{ lat: 10, common_pid: 2300 } hitcount: 95 -{ lat: 10, common_pid: 2305 } hitcount: 18 -{ lat: 11, common_pid: 2303 } hitcount: 5 -{ lat: 11, common_pid: 2305 } hitcount: 8 -{ lat: 11, common_pid: 2306 } hitcount: 221 -{ lat: 11, common_pid: 2302 } hitcount: 76 -{ lat: 11, common_pid: 2304 } hitcount: 26 -{ lat: 11, common_pid: 2300 } hitcount: 125 -{ lat: 11, common_pid: 2299 } hitcount: 2 -{ lat: 12, common_pid: 2305 } hitcount: 3 -{ lat: 12, common_pid: 2300 } hitcount: 6 -{ lat: 12, common_pid: 2306 } hitcount: 90 -{ lat: 12, common_pid: 2302 } hitcount: 4 -{ lat: 12, common_pid: 2303 } hitcount: 1 -{ lat: 12, common_pid: 2304 } hitcount: 122 -{ lat: 13, common_pid: 2300 } hitcount: 12 -{ lat: 13, common_pid: 2301 } hitcount: 1 -{ lat: 13, common_pid: 2306 } hitcount: 32 -{ lat: 13, common_pid: 2302 } hitcount: 5 -{ lat: 13, common_pid: 2305 } hitcount: 1 -{ lat: 13, common_pid: 2303 } hitcount: 1 -{ lat: 13, common_pid: 2304 } hitcount: 61 -{ lat: 14, common_pid: 2303 } hitcount: 4 -{ lat: 14, common_pid: 2306 } hitcount: 5 -{ lat: 14, common_pid: 2305 } hitcount: 4 -{ lat: 14, common_pid: 2304 } hitcount: 62 -{ lat: 14, common_pid: 2302 } hitcount: 19 -{ lat: 14, common_pid: 2300 } hitcount: 33 -{ lat: 14, common_pid: 2299 } hitcount: 1 -{ lat: 14, common_pid: 2301 } hitcount: 4 -{ lat: 15, common_pid: 2305 } hitcount: 1 -{ lat: 15, common_pid: 2302 } hitcount: 25 -{ lat: 15, common_pid: 2300 } hitcount: 11 -{ lat: 15, common_pid: 2299 } hitcount: 5 -{ lat: 15, common_pid: 2301 } hitcount: 1 -{ lat: 15, common_pid: 2304 } hitcount: 8 -{ lat: 15, common_pid: 2303 } hitcount: 1 -{ lat: 15, common_pid: 2306 } hitcount: 6 -{ lat: 16, common_pid: 2302 } hitcount: 31 -{ lat: 16, common_pid: 2306 } hitcount: 3 -{ lat: 16, common_pid: 2300 } hitcount: 5 -{ lat: 17, common_pid: 2302 } hitcount: 6 -{ lat: 17, common_pid: 2303 } hitcount: 1 -{ lat: 18, common_pid: 2304 } hitcount: 1 -{ lat: 18, common_pid: 2302 } hitcount: 8 -{ lat: 18, common_pid: 2299 } hitcount: 1 -{ lat: 18, common_pid: 2301 } hitcount: 1 -{ lat: 19, common_pid: 2303 } hitcount: 4 -{ lat: 19, common_pid: 2304 } hitcount: 5 -{ lat: 19, common_pid: 2302 } hitcount: 4 -{ lat: 19, common_pid: 2299 } hitcount: 3 -{ lat: 19, common_pid: 2306 } hitcount: 1 -{ lat: 19, common_pid: 2300 } hitcount: 4 -{ lat: 19, common_pid: 2305 } hitcount: 5 -{ lat: 20, common_pid: 2299 } hitcount: 2 -{ lat: 20, common_pid: 2302 } hitcount: 3 -{ lat: 20, common_pid: 2305 } hitcount: 1 -{ lat: 20, common_pid: 2300 } hitcount: 2 -{ lat: 20, common_pid: 2301 } hitcount: 2 -{ lat: 20, common_pid: 2303 } hitcount: 3 -{ lat: 21, common_pid: 2305 } hitcount: 1 -{ lat: 21, common_pid: 2299 } hitcount: 5 -{ lat: 21, common_pid: 2303 } hitcount: 4 -{ lat: 21, common_pid: 2302 } hitcount: 7 -{ lat: 21, common_pid: 2300 } hitcount: 1 -{ lat: 21, common_pid: 2301 } hitcount: 5 -{ lat: 21, common_pid: 2304 } hitcount: 2 -{ lat: 22, common_pid: 2302 } hitcount: 5 -{ lat: 22, common_pid: 2303 } hitcount: 1 -{ lat: 22, common_pid: 2306 } hitcount: 3 -{ lat: 22, common_pid: 2301 } hitcount: 2 -{ lat: 22, common_pid: 2300 } hitcount: 1 -{ lat: 22, common_pid: 2299 } hitcount: 1 -{ lat: 22, common_pid: 2305 } hitcount: 1 -{ lat: 22, common_pid: 2304 } hitcount: 1 -{ lat: 23, common_pid: 2299 } hitcount: 1 -{ lat: 23, common_pid: 2306 } hitcount: 2 -{ lat: 23, common_pid: 2302 } hitcount: 6 -{ lat: 24, common_pid: 2302 } hitcount: 3 -{ lat: 24, common_pid: 2300 } hitcount: 1 -{ lat: 24, common_pid: 2306 } hitcount: 2 -{ lat: 24, common_pid: 2305 } hitcount: 1 -{ lat: 24, common_pid: 2299 } hitcount: 1 -{ lat: 25, common_pid: 2300 } hitcount: 1 -{ lat: 25, common_pid: 2302 } hitcount: 4 -{ lat: 26, common_pid: 2302 } hitcount: 2 -{ lat: 27, common_pid: 2305 } hitcount: 1 -{ lat: 27, common_pid: 2300 } hitcount: 1 -{ lat: 27, common_pid: 2302 } hitcount: 3 -{ lat: 28, common_pid: 2306 } hitcount: 1 -{ lat: 28, common_pid: 2302 } hitcount: 4 -{ lat: 29, common_pid: 2302 } hitcount: 1 -{ lat: 29, common_pid: 2300 } hitcount: 2 -{ lat: 29, common_pid: 2306 } hitcount: 1 -{ lat: 29, common_pid: 2304 } hitcount: 1 -{ lat: 30, common_pid: 2302 } hitcount: 4 -{ lat: 31, common_pid: 2302 } hitcount: 6 -{ lat: 32, common_pid: 2302 } hitcount: 1 -{ lat: 33, common_pid: 2299 } hitcount: 1 -{ lat: 33, common_pid: 2302 } hitcount: 3 -{ lat: 34, common_pid: 2302 } hitcount: 2 -{ lat: 35, common_pid: 2302 } hitcount: 1 -{ lat: 35, common_pid: 2304 } hitcount: 1 -{ lat: 36, common_pid: 2302 } hitcount: 4 -{ lat: 37, common_pid: 2302 } hitcount: 6 -{ lat: 38, common_pid: 2302 } hitcount: 2 -{ lat: 39, common_pid: 2302 } hitcount: 2 -{ lat: 39, common_pid: 2304 } hitcount: 1 -{ lat: 40, common_pid: 2304 } hitcount: 2 -{ lat: 40, common_pid: 2302 } hitcount: 5 -{ lat: 41, common_pid: 2304 } hitcount: 1 -{ lat: 41, common_pid: 2302 } hitcount: 8 -{ lat: 42, common_pid: 2302 } hitcount: 6 -{ lat: 42, common_pid: 2304 } hitcount: 1 -{ lat: 43, common_pid: 2302 } hitcount: 3 -{ lat: 43, common_pid: 2304 } hitcount: 4 -{ lat: 44, common_pid: 2302 } hitcount: 6 -{ lat: 45, common_pid: 2302 } hitcount: 5 -{ lat: 46, common_pid: 2302 } hitcount: 5 -{ lat: 47, common_pid: 2302 } hitcount: 7 -{ lat: 48, common_pid: 2301 } hitcount: 1 -{ lat: 48, common_pid: 2302 } hitcount: 9 -{ lat: 49, common_pid: 2302 } hitcount: 3 -{ lat: 50, common_pid: 2302 } hitcount: 1 -{ lat: 50, common_pid: 2301 } hitcount: 1 -{ lat: 51, common_pid: 2302 } hitcount: 2 -{ lat: 51, common_pid: 2301 } hitcount: 1 -{ lat: 61, common_pid: 2302 } hitcount: 1 -{ lat: 110, common_pid: 2302 } hitcount: 1 - -Totals: - Hits: 89565 - Entries: 158 - Dropped: 0 + # event histogram + # + # trigger info: hist:keys=lat,common_pid:vals=hitcount:sort=lat:size=2048 [active] + # + + { lat: 7, common_pid: 2302 } hitcount: 640 + { lat: 7, common_pid: 2299 } hitcount: 42 + { lat: 7, common_pid: 2303 } hitcount: 18 + { lat: 7, common_pid: 2305 } hitcount: 166 + { lat: 7, common_pid: 2306 } hitcount: 1 + { lat: 7, common_pid: 2301 } hitcount: 91 + { lat: 7, common_pid: 2300 } hitcount: 17 + { lat: 8, common_pid: 2303 } hitcount: 8296 + { lat: 8, common_pid: 2304 } hitcount: 6864 + { lat: 8, common_pid: 2305 } hitcount: 9464 + { lat: 8, common_pid: 2301 } hitcount: 9213 + { lat: 8, common_pid: 2306 } hitcount: 6246 + { lat: 8, common_pid: 2302 } hitcount: 8797 + { lat: 8, common_pid: 2299 } hitcount: 8771 + { lat: 8, common_pid: 2300 } hitcount: 8119 + { lat: 9, common_pid: 2305 } hitcount: 1519 + { lat: 9, common_pid: 2299 } hitcount: 2346 + { lat: 9, common_pid: 2303 } hitcount: 2841 + { lat: 9, common_pid: 2301 } hitcount: 1846 + { lat: 9, common_pid: 2304 } hitcount: 3861 + { lat: 9, common_pid: 2302 } hitcount: 1210 + { lat: 9, common_pid: 2300 } hitcount: 2762 + { lat: 9, common_pid: 2306 } hitcount: 4247 + { lat: 10, common_pid: 2299 } hitcount: 16 + { lat: 10, common_pid: 2306 } hitcount: 333 + { lat: 10, common_pid: 2303 } hitcount: 16 + { lat: 10, common_pid: 2304 } hitcount: 168 + { lat: 10, common_pid: 2302 } hitcount: 240 + { lat: 10, common_pid: 2301 } hitcount: 28 + { lat: 10, common_pid: 2300 } hitcount: 95 + { lat: 10, common_pid: 2305 } hitcount: 18 + { lat: 11, common_pid: 2303 } hitcount: 5 + { lat: 11, common_pid: 2305 } hitcount: 8 + { lat: 11, common_pid: 2306 } hitcount: 221 + { lat: 11, common_pid: 2302 } hitcount: 76 + { lat: 11, common_pid: 2304 } hitcount: 26 + { lat: 11, common_pid: 2300 } hitcount: 125 + { lat: 11, common_pid: 2299 } hitcount: 2 + { lat: 12, common_pid: 2305 } hitcount: 3 + { lat: 12, common_pid: 2300 } hitcount: 6 + { lat: 12, common_pid: 2306 } hitcount: 90 + { lat: 12, common_pid: 2302 } hitcount: 4 + { lat: 12, common_pid: 2303 } hitcount: 1 + { lat: 12, common_pid: 2304 } hitcount: 122 + { lat: 13, common_pid: 2300 } hitcount: 12 + { lat: 13, common_pid: 2301 } hitcount: 1 + { lat: 13, common_pid: 2306 } hitcount: 32 + { lat: 13, common_pid: 2302 } hitcount: 5 + { lat: 13, common_pid: 2305 } hitcount: 1 + { lat: 13, common_pid: 2303 } hitcount: 1 + { lat: 13, common_pid: 2304 } hitcount: 61 + { lat: 14, common_pid: 2303 } hitcount: 4 + { lat: 14, common_pid: 2306 } hitcount: 5 + { lat: 14, common_pid: 2305 } hitcount: 4 + { lat: 14, common_pid: 2304 } hitcount: 62 + { lat: 14, common_pid: 2302 } hitcount: 19 + { lat: 14, common_pid: 2300 } hitcount: 33 + { lat: 14, common_pid: 2299 } hitcount: 1 + { lat: 14, common_pid: 2301 } hitcount: 4 + { lat: 15, common_pid: 2305 } hitcount: 1 + { lat: 15, common_pid: 2302 } hitcount: 25 + { lat: 15, common_pid: 2300 } hitcount: 11 + { lat: 15, common_pid: 2299 } hitcount: 5 + { lat: 15, common_pid: 2301 } hitcount: 1 + { lat: 15, common_pid: 2304 } hitcount: 8 + { lat: 15, common_pid: 2303 } hitcount: 1 + { lat: 15, common_pid: 2306 } hitcount: 6 + { lat: 16, common_pid: 2302 } hitcount: 31 + { lat: 16, common_pid: 2306 } hitcount: 3 + { lat: 16, common_pid: 2300 } hitcount: 5 + { lat: 17, common_pid: 2302 } hitcount: 6 + { lat: 17, common_pid: 2303 } hitcount: 1 + { lat: 18, common_pid: 2304 } hitcount: 1 + { lat: 18, common_pid: 2302 } hitcount: 8 + { lat: 18, common_pid: 2299 } hitcount: 1 + { lat: 18, common_pid: 2301 } hitcount: 1 + { lat: 19, common_pid: 2303 } hitcount: 4 + { lat: 19, common_pid: 2304 } hitcount: 5 + { lat: 19, common_pid: 2302 } hitcount: 4 + { lat: 19, common_pid: 2299 } hitcount: 3 + { lat: 19, common_pid: 2306 } hitcount: 1 + { lat: 19, common_pid: 2300 } hitcount: 4 + { lat: 19, common_pid: 2305 } hitcount: 5 + { lat: 20, common_pid: 2299 } hitcount: 2 + { lat: 20, common_pid: 2302 } hitcount: 3 + { lat: 20, common_pid: 2305 } hitcount: 1 + { lat: 20, common_pid: 2300 } hitcount: 2 + { lat: 20, common_pid: 2301 } hitcount: 2 + { lat: 20, common_pid: 2303 } hitcount: 3 + { lat: 21, common_pid: 2305 } hitcount: 1 + { lat: 21, common_pid: 2299 } hitcount: 5 + { lat: 21, common_pid: 2303 } hitcount: 4 + { lat: 21, common_pid: 2302 } hitcount: 7 + { lat: 21, common_pid: 2300 } hitcount: 1 + { lat: 21, common_pid: 2301 } hitcount: 5 + { lat: 21, common_pid: 2304 } hitcount: 2 + { lat: 22, common_pid: 2302 } hitcount: 5 + { lat: 22, common_pid: 2303 } hitcount: 1 + { lat: 22, common_pid: 2306 } hitcount: 3 + { lat: 22, common_pid: 2301 } hitcount: 2 + { lat: 22, common_pid: 2300 } hitcount: 1 + { lat: 22, common_pid: 2299 } hitcount: 1 + { lat: 22, common_pid: 2305 } hitcount: 1 + { lat: 22, common_pid: 2304 } hitcount: 1 + { lat: 23, common_pid: 2299 } hitcount: 1 + { lat: 23, common_pid: 2306 } hitcount: 2 + { lat: 23, common_pid: 2302 } hitcount: 6 + { lat: 24, common_pid: 2302 } hitcount: 3 + { lat: 24, common_pid: 2300 } hitcount: 1 + { lat: 24, common_pid: 2306 } hitcount: 2 + { lat: 24, common_pid: 2305 } hitcount: 1 + { lat: 24, common_pid: 2299 } hitcount: 1 + { lat: 25, common_pid: 2300 } hitcount: 1 + { lat: 25, common_pid: 2302 } hitcount: 4 + { lat: 26, common_pid: 2302 } hitcount: 2 + { lat: 27, common_pid: 2305 } hitcount: 1 + { lat: 27, common_pid: 2300 } hitcount: 1 + { lat: 27, common_pid: 2302 } hitcount: 3 + { lat: 28, common_pid: 2306 } hitcount: 1 + { lat: 28, common_pid: 2302 } hitcount: 4 + { lat: 29, common_pid: 2302 } hitcount: 1 + { lat: 29, common_pid: 2300 } hitcount: 2 + { lat: 29, common_pid: 2306 } hitcount: 1 + { lat: 29, common_pid: 2304 } hitcount: 1 + { lat: 30, common_pid: 2302 } hitcount: 4 + { lat: 31, common_pid: 2302 } hitcount: 6 + { lat: 32, common_pid: 2302 } hitcount: 1 + { lat: 33, common_pid: 2299 } hitcount: 1 + { lat: 33, common_pid: 2302 } hitcount: 3 + { lat: 34, common_pid: 2302 } hitcount: 2 + { lat: 35, common_pid: 2302 } hitcount: 1 + { lat: 35, common_pid: 2304 } hitcount: 1 + { lat: 36, common_pid: 2302 } hitcount: 4 + { lat: 37, common_pid: 2302 } hitcount: 6 + { lat: 38, common_pid: 2302 } hitcount: 2 + { lat: 39, common_pid: 2302 } hitcount: 2 + { lat: 39, common_pid: 2304 } hitcount: 1 + { lat: 40, common_pid: 2304 } hitcount: 2 + { lat: 40, common_pid: 2302 } hitcount: 5 + { lat: 41, common_pid: 2304 } hitcount: 1 + { lat: 41, common_pid: 2302 } hitcount: 8 + { lat: 42, common_pid: 2302 } hitcount: 6 + { lat: 42, common_pid: 2304 } hitcount: 1 + { lat: 43, common_pid: 2302 } hitcount: 3 + { lat: 43, common_pid: 2304 } hitcount: 4 + { lat: 44, common_pid: 2302 } hitcount: 6 + { lat: 45, common_pid: 2302 } hitcount: 5 + { lat: 46, common_pid: 2302 } hitcount: 5 + { lat: 47, common_pid: 2302 } hitcount: 7 + { lat: 48, common_pid: 2301 } hitcount: 1 + { lat: 48, common_pid: 2302 } hitcount: 9 + { lat: 49, common_pid: 2302 } hitcount: 3 + { lat: 50, common_pid: 2302 } hitcount: 1 + { lat: 50, common_pid: 2301 } hitcount: 1 + { lat: 51, common_pid: 2302 } hitcount: 2 + { lat: 51, common_pid: 2301 } hitcount: 1 + { lat: 61, common_pid: 2302 } hitcount: 1 + { lat: 110, common_pid: 2302 } hitcount: 1 + + Totals: + Hits: 89565 + Entries: 158 + Dropped: 0 This doesn't tell us any information about how late cyclictest may have woken up, but it does show us a nice histogram of how long it took from diff --git a/Documentation/trace/index.rst b/Documentation/trace/index.rst index b58c10b..3069979 100644 --- a/Documentation/trace/index.rst +++ b/Documentation/trace/index.rst @@ -18,6 +18,7 @@ Linux Tracing Technologies events-nmi events-msr mmiotrace + histogram hwlat_detector intel_th stm diff --git a/Documentation/trace/kprobetrace.rst b/Documentation/trace/kprobetrace.rst index 3e0f971..8bfc75c 100644 --- a/Documentation/trace/kprobetrace.rst +++ b/Documentation/trace/kprobetrace.rst @@ -18,7 +18,7 @@ To enable this feature, build your kernel with CONFIG_KPROBE_EVENTS=y. Similar to the events tracer, this doesn't need to be activated via current_tracer. Instead of that, add probe points via /sys/kernel/debug/tracing/kprobe_events, and enable it via -/sys/kernel/debug/tracing/events/kprobes/<EVENT>/enabled. +/sys/kernel/debug/tracing/events/kprobes/<EVENT>/enable. Synopsis of kprobe_events @@ -81,9 +81,9 @@ Per-probe event filtering feature allows you to set different filter on each probe and gives you what arguments will be shown in trace buffer. If an event name is specified right after 'p:' or 'r:' in kprobe_events, it adds an event under tracing/events/kprobes/<EVENT>, at the directory you can see 'id', -'enabled', 'format' and 'filter'. +'enable', 'format', 'filter' and 'trigger'. -enabled: +enable: You can enable/disable the probe by writing 1 or 0 on it. format: @@ -95,6 +95,9 @@ filter: id: This shows the id of this probe event. +trigger: + This allows to install trigger commands which are executed when the event is + hit (for details, see Documentation/trace/events.rst, section 6). Event Profiling --------------- diff --git a/Documentation/trace/uprobetracer.rst b/Documentation/trace/uprobetracer.rst index 98d3f69..d082281 100644 --- a/Documentation/trace/uprobetracer.rst +++ b/Documentation/trace/uprobetracer.rst @@ -13,7 +13,7 @@ To enable this feature, build your kernel with CONFIG_UPROBE_EVENTS=y. Similar to the kprobe-event tracer, this doesn't need to be activated via current_tracer. Instead of that, add probe points via /sys/kernel/debug/tracing/uprobe_events, and enable it via -/sys/kernel/debug/tracing/events/uprobes/<EVENT>/enabled. +/sys/kernel/debug/tracing/events/uprobes/<EVENT>/enable. However unlike kprobe-event tracer, the uprobe event interface expects the user to calculate the offset of the probepoint in the object. diff --git a/Documentation/translations/index.rst b/Documentation/translations/index.rst new file mode 100644 index 0000000..7f77c52 --- /dev/null +++ b/Documentation/translations/index.rst @@ -0,0 +1,13 @@ +.. _translations: + +============ +Translations +============ + +.. toctree:: + :maxdepth: 1 + + zh_CN/index + it_IT/index + ko_KR/index + ja_JP/index diff --git a/Documentation/translations/it_IT/disclaimer-ita.rst b/Documentation/translations/it_IT/disclaimer-ita.rst new file mode 100644 index 0000000..d68e52d --- /dev/null +++ b/Documentation/translations/it_IT/disclaimer-ita.rst @@ -0,0 +1,13 @@ +:orphan: + +.. note:: + This document is maintained by Federico Vaga <federico.vaga@vaga.pv.it>. + If you find any difference between this document and the original file or a + problem with the translation, please contact the maintainer of this file. + Following people helped to translate or review: + Alessia Mantegazza <amantegazza@vaga.pv.it> + +.. warning:: + The purpose of this file is to be easier to read and understand for Italian + speakers and is not intended as a fork. So, if you have any comments or + updates for this file please try to update the original English file first. diff --git a/Documentation/translations/it_IT/doc-guide/index.rst b/Documentation/translations/it_IT/doc-guide/index.rst new file mode 100644 index 0000000..7a6562b --- /dev/null +++ b/Documentation/translations/it_IT/doc-guide/index.rst @@ -0,0 +1,24 @@ +.. include:: ../disclaimer-ita.rst + +.. note:: Per leggere la documentazione originale in inglese: + :ref:`Documentation/doc-guide/index.rst <doc_guide>` + +.. _it_doc_guide: + +========================================== +Come scrivere la documentazione del kernel +========================================== + +.. toctree:: + :maxdepth: 1 + + sphinx.rst + kernel-doc.rst + parse-headers.rst + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/translations/it_IT/doc-guide/kernel-doc.rst b/Documentation/translations/it_IT/doc-guide/kernel-doc.rst new file mode 100644 index 0000000..2bf1c1e --- /dev/null +++ b/Documentation/translations/it_IT/doc-guide/kernel-doc.rst @@ -0,0 +1,554 @@ +.. include:: ../disclaimer-ita.rst + +.. note:: Per leggere la documentazione originale in inglese: + :ref:`Documentation/doc-guide/index.rst <doc_guide>` + +.. _it_kernel_doc: + +Scrivere i commenti in kernel-doc +================================= + +Nei file sorgenti del kernel Linux potrete trovare commenti di documentazione +strutturanti secondo il formato kernel-doc. Essi possono descrivere funzioni, +tipi di dati, e l'architettura del codice. + +.. note:: Il formato kernel-doc può sembrare simile a gtk-doc o Doxygen ma + in realtà è molto differente per ragioni storiche. I sorgenti del kernel + contengono decine di migliaia di commenti kernel-doc. Siete pregati + d'attenervi allo stile qui descritto. + +La struttura kernel-doc è estratta a partire dai commenti; da questi viene +generato il `dominio Sphinx per il C`_ con un'adeguata descrizione per le +funzioni ed i tipi di dato con i loro relativi collegamenti. Le descrizioni +vengono filtrare per cercare i riferimenti ed i marcatori. + +Vedere di seguito per maggiori dettagli. + +.. _`dominio Sphinx per il C`: http://www.sphinx-doc.org/en/stable/domains.html + +Tutte le funzioni esportate verso i moduli esterni utilizzando +``EXPORT_SYMBOL`` o ``EXPORT_SYMBOL_GPL`` dovrebbero avere un commento +kernel-doc. Quando l'intenzione è di utilizzarle nei moduli, anche le funzioni +e le strutture dati nei file d'intestazione dovrebbero avere dei commenti +kernel-doc. + +È considerata una buona pratica quella di fornire una documentazione formattata +secondo kernel-doc per le funzioni che sono visibili da altri file del kernel +(ovvero, che non siano dichiarate utilizzando ``static``). Raccomandiamo, +inoltre, di fornire una documentazione kernel-doc anche per procedure private +(ovvero, dichiarate "static") al fine di fornire una struttura più coerente +dei sorgenti. Quest'ultima raccomandazione ha una priorità più bassa ed è a +discrezione dal manutentore (MAINTAINER) del file sorgente. + + + +Sicuramente la documentazione formattata con kernel-doc è necessaria per +le funzioni che sono esportate verso i moduli esterni utilizzando +``EXPORT_SYMBOL`` o ``EXPORT_SYMBOL_GPL``. + +Cerchiamo anche di fornire una documentazione formattata secondo kernel-doc +per le funzioni che sono visibili da altri file del kernel (ovvero, che non +siano dichiarate utilizzando "static") + +Raccomandiamo, inoltre, di fornire una documentazione formattata con kernel-doc +anche per procedure private (ovvero, dichiarate "static") al fine di fornire +una struttura più coerente dei sorgenti. Questa raccomandazione ha una priorità +più bassa ed è a discrezione dal manutentore (MAINTAINER) del file sorgente. + +Le strutture dati visibili nei file di intestazione dovrebbero essere anch'esse +documentate utilizzando commenti formattati con kernel-doc. + +Come formattare i commenti kernel-doc +------------------------------------- + +I commenti kernel-doc iniziano con il marcatore ``/**``. Il programma +``kernel-doc`` estrarrà i commenti marchiati in questo modo. Il resto +del commento è formattato come un normale commento multilinea, ovvero +con un asterisco all'inizio d'ogni riga e che si conclude con ``*/`` +su una riga separata. + +I commenti kernel-doc di funzioni e tipi dovrebbero essere posizionati +appena sopra la funzione od il tipo che descrivono. Questo allo scopo di +aumentare la probabilità che chi cambia il codice si ricordi di aggiornare +anche la documentazione. I commenti kernel-doc di tipo più generale possono +essere posizionati ovunque nel file. + +Al fine di verificare che i commenti siano formattati correttamente, potete +eseguire il programma ``kernel-doc`` con un livello di verbosità alto e senza +che questo produca alcuna documentazione. Per esempio:: + + scripts/kernel-doc -v -none drivers/foo/bar.c + +Il formato della documentazione è verificato della procedura di generazione +del kernel quando viene richiesto di effettuare dei controlli extra con GCC:: + + make W=n + +Documentare le funzioni +------------------------ + +Generalmente il formato di un commento kernel-doc per funzioni e +macro simil-funzioni è il seguente:: + + /** + * function_name() - Brief description of function. + * @arg1: Describe the first argument. + * @arg2: Describe the second argument. + * One can provide multiple line descriptions + * for arguments. + * + * A longer description, with more discussion of the function function_name() + * that might be useful to those using or modifying it. Begins with an + * empty comment line, and may include additional embedded empty + * comment lines. + * + * The longer description may have multiple paragraphs. + * + * Context: Describes whether the function can sleep, what locks it takes, + * releases, or expects to be held. It can extend over multiple + * lines. + * Return: Describe the return value of foobar. + * + * The return value description can also have multiple paragraphs, and should + * be placed at the end of the comment block. + */ + +La descrizione introduttiva (*brief description*) che segue il nome della +funzione può continuare su righe successive e termina con la descrizione di +un argomento, una linea di commento vuota, oppure la fine del commento. + +Parametri delle funzioni +~~~~~~~~~~~~~~~~~~~~~~~~ + +Ogni argomento di una funzione dovrebbe essere descritto in ordine, subito +dopo la descrizione introduttiva. Non lasciare righe vuote né fra la +descrizione introduttiva e quella degli argomenti, né fra gli argomenti. + +Ogni ``@argument:`` può estendersi su più righe. + +.. note:: + + Se la descrizione di ``@argument:`` si estende su più righe, + la continuazione dovrebbe iniziare alla stessa colonna della riga + precedente:: + + * @argument: some long description + * that continues on next lines + + or:: + + * @argument: + * some long description + * that continues on next lines + +Se una funzione ha un numero variabile di argomento, la sua descrizione +dovrebbe essere scritta con la notazione kernel-doc:: + + * @...: description + +Contesto delle funzioni +~~~~~~~~~~~~~~~~~~~~~~~ + +Il contesto in cui le funzioni vengono chiamate viene descritto in una +sezione chiamata ``Context``. Questo dovrebbe informare sulla possibilità +che una funzione dorma (*sleep*) o che possa essere chiamata in un contesto +d'interruzione, così come i *lock* che prende, rilascia e che si aspetta che +vengano presi dal chiamante. + +Esempi:: + + * Context: Any context. + * Context: Any context. Takes and releases the RCU lock. + * Context: Any context. Expects <lock> to be held by caller. + * Context: Process context. May sleep if @gfp flags permit. + * Context: Process context. Takes and releases <mutex>. + * Context: Softirq or process context. Takes and releases <lock>, BH-safe. + * Context: Interrupt context. + +Valore di ritorno +~~~~~~~~~~~~~~~~~ + +Il valore di ritorno, se c'è, viene descritto in una sezione dedicata di nome +``Return``. + +.. note:: + + #) La descrizione multiriga non riconosce il termine d'una riga, per cui + se provate a formattare bene il vostro testo come nel seguente esempio:: + + * Return: + * 0 - OK + * -EINVAL - invalid argument + * -ENOMEM - out of memory + + le righe verranno unite e il risultato sarà:: + + Return: 0 - OK -EINVAL - invalid argument -ENOMEM - out of memory + + Quindi, se volete che le righe vengano effettivamente generate, dovete + utilizzare una lista ReST, ad esempio:: + + * Return: + * * 0 - OK to runtime suspend the device + * * -EBUSY - Device should not be runtime suspended + + #) Se il vostro testo ha delle righe che iniziano con una frase seguita dai + due punti, allora ognuna di queste frasi verrà considerata come il nome + di una nuova sezione, e probabilmente non produrrà gli effetti desiderati. + +Documentare strutture, unioni ed enumerazioni +--------------------------------------------- + +Generalmente il formato di un commento kernel-doc per struct, union ed enum è:: + + /** + * struct struct_name - Brief description. + * @member1: Description of member1. + * @member2: Description of member2. + * One can provide multiple line descriptions + * for members. + * + * Description of the structure. + */ + +Nell'esempio qui sopra, potete sostituire ``struct`` con ``union`` o ``enum`` +per descrivere unioni ed enumerati. ``member`` viene usato per indicare i +membri di strutture ed unioni, ma anche i valori di un tipo enumerato. + +La descrizione introduttiva (*brief description*) che segue il nome della +funzione può continuare su righe successive e termina con la descrizione di +un argomento, una linea di commento vuota, oppure la fine del commento. + +Membri +~~~~~~ + +I membri di strutture, unioni ed enumerati devo essere documentati come i +parametri delle funzioni; seguono la descrizione introduttiva e possono +estendersi su più righe. + +All'interno d'una struttura o d'un unione, potete utilizzare le etichette +``private:`` e ``public:``. I campi che sono nell'area ``private:`` non +verranno inclusi nella documentazione finale. + +Le etichette ``private:`` e ``public:`` devono essere messe subito dopo +il marcatore di un commento ``/*``. Opzionalmente, possono includere commenti +fra ``:`` e il marcatore di fine commento ``*/``. + +Esempio:: + + /** + * struct my_struct - short description + * @a: first member + * @b: second member + * @d: fourth member + * + * Longer description + */ + struct my_struct { + int a; + int b; + /* private: internal use only */ + int c; + /* public: the next one is public */ + int d; + }; + +Strutture ed unioni annidate +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +È possibile documentare strutture ed unioni annidate, ad esempio:: + + /** + * struct nested_foobar - a struct with nested unions and structs + * @memb1: first member of anonymous union/anonymous struct + * @memb2: second member of anonymous union/anonymous struct + * @memb3: third member of anonymous union/anonymous struct + * @memb4: fourth member of anonymous union/anonymous struct + * @bar: non-anonymous union + * @bar.st1: struct st1 inside @bar + * @bar.st2: struct st2 inside @bar + * @bar.st1.memb1: first member of struct st1 on union bar + * @bar.st1.memb2: second member of struct st1 on union bar + * @bar.st2.memb1: first member of struct st2 on union bar + * @bar.st2.memb2: second member of struct st2 on union bar + */ + struct nested_foobar { + /* Anonymous union/struct*/ + union { + struct { + int memb1; + int memb2; + } + struct { + void *memb3; + int memb4; + } + } + union { + struct { + int memb1; + int memb2; + } st1; + struct { + void *memb1; + int memb2; + } st2; + } bar; + }; + +.. note:: + + #) Quando documentate una struttura od unione annidata, ad esempio + di nome ``foo``, il suo campo ``bar`` dev'essere documentato + usando ``@foo.bar:`` + #) Quando la struttura od unione annidata è anonima, il suo campo + ``bar`` dev'essere documentato usando ``@bar:`` + +Commenti in linea per la documentazione dei membri +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +I membri d'una struttura possono essere documentati in linea all'interno +della definizione stessa. Ci sono due stili: una singola riga di commento +che inizia con ``/**`` e finisce con ``*/``; commenti multi riga come +qualsiasi altro commento kernel-doc:: + + /** + * struct foo - Brief description. + * @foo: The Foo member. + */ + struct foo { + int foo; + /** + * @bar: The Bar member. + */ + int bar; + /** + * @baz: The Baz member. + * + * Here, the member description may contain several paragraphs. + */ + int baz; + union { + /** @foobar: Single line description. */ + int foobar; + }; + /** @bar2: Description for struct @bar2 inside @foo */ + struct { + /** + * @bar2.barbar: Description for @barbar inside @foo.bar2 + */ + int barbar; + } bar2; + }; + + +Documentazione dei tipi di dato +------------------------------- +Generalmente il formato di un commento kernel-doc per typedef è +il seguente:: + + /** + * typedef type_name - Brief description. + * + * Description of the type. + */ + +Anche i tipi di dato per prototipi di funzione possono essere documentati:: + + /** + * typedef type_name - Brief description. + * @arg1: description of arg1 + * @arg2: description of arg2 + * + * Description of the type. + * + * Context: Locking context. + * Return: Meaning of the return value. + */ + typedef void (*type_name)(struct v4l2_ctrl *arg1, void *arg2); + +Marcatori e riferimenti +----------------------- + +All'interno dei commenti di tipo kernel-doc vengono riconosciuti i seguenti +*pattern* che vengono convertiti in marcatori reStructuredText ed in riferimenti +del `dominio Sphinx per il C`_. + +.. attention:: Questi sono riconosciuti **solo** all'interno di commenti + kernel-doc, e **non** all'interno di documenti reStructuredText. + +``funcname()`` + Riferimento ad una funzione. + +``@parameter`` + Nome di un parametro di una funzione (nessun riferimento, solo formattazione). + +``%CONST`` + Il nome di una costante (nessun riferimento, solo formattazione) + +````literal```` + Un blocco di testo che deve essere riportato così com'è. La rappresentazione + finale utilizzerà caratteri a ``spaziatura fissa``. + + Questo è utile se dovete utilizzare caratteri speciali che altrimenti + potrebbero assumere un significato diverso in kernel-doc o in reStructuredText + + Questo è particolarmente utile se dovete scrivere qualcosa come ``%ph`` + all'interno della descrizione di una funzione. + +``$ENVVAR`` + Il nome di una variabile d'ambiente (nessun riferimento, solo formattazione). + +``&struct name`` + Riferimento ad una struttura. + +``&enum name`` + Riferimento ad un'enumerazione. + +``&typedef name`` + Riferimento ad un tipo di dato. + +``&struct_name->member`` or ``&struct_name.member`` + Riferimento ad un membro di una struttura o di un'unione. Il riferimento sarà + la struttura o l'unione, non il memembro. + +``&name`` + Un generico riferimento ad un tipo. Usate, preferibilmente, il riferimento + completo come descritto sopra. Questo è dedicato ai commenti obsoleti. + +Riferimenti usando reStructuredText +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Per fare riferimento a funzioni e tipi di dato definiti nei commenti kernel-doc +all'interno dei documenti reStructuredText, utilizzate i riferimenti dal +`dominio Sphinx per il C`_. Per esempio:: + + See function :c:func:`foo` and struct/union/enum/typedef :c:type:`bar`. + +Nonostante il riferimento ai tipi di dato funzioni col solo nome, +ovvero senza specificare struct/union/enum/typedef, potreste preferire il +seguente:: + + See :c:type:`struct foo <foo>`. + See :c:type:`union bar <bar>`. + See :c:type:`enum baz <baz>`. + See :c:type:`typedef meh <meh>`. + +Questo produce dei collegamenti migliori, ed è in linea con il modo in cui +kernel-doc gestisce i riferimenti. + +Per maggiori informazioni, siete pregati di consultare la documentazione +del `dominio Sphinx per il C`_. + +Commenti per una documentazione generale +---------------------------------------- + +Al fine d'avere il codice ed i commenti nello stesso file, potete includere +dei blocchi di documentazione kernel-doc con un formato libero invece +che nel formato specifico per funzioni, strutture, unioni, enumerati o tipi +di dato. Per esempio, questo tipo di commento potrebbe essere usato per la +spiegazione delle operazioni di un driver o di una libreria + +Questo s'ottiene utilizzando la parola chiave ``DOC:`` a cui viene associato +un titolo. + +Generalmente il formato di un commento generico o di visione d'insieme è +il seguente:: + + /** + * DOC: Theory of Operation + * + * The whizbang foobar is a dilly of a gizmo. It can do whatever you + * want it to do, at any time. It reads your mind. Here's how it works. + * + * foo bar splat + * + * The only drawback to this gizmo is that is can sometimes damage + * hardware, software, or its subject(s). + */ + +Il titolo che segue ``DOC:`` funziona da intestazione all'interno del file +sorgente, ma anche come identificatore per l'estrazione di questi commenti di +documentazione. Quindi, il titolo dev'essere unico all'interno del file. + +Includere i commenti di tipo kernel-doc +======================================= + +I commenti di documentazione possono essere inclusi in un qualsiasi documento +di tipo reStructuredText mediante l'apposita direttiva nell'estensione +kernel-doc per Sphinx. + +Le direttive kernel-doc sono nel formato:: + + .. kernel-doc:: source + :option: + +Il campo *source* è il percorso ad un file sorgente, relativo alla cartella +principale dei sorgenti del kernel. La direttiva supporta le seguenti opzioni: + +export: *[source-pattern ...]* + Include la documentazione per tutte le funzioni presenti nel file sorgente + (*source*) che sono state esportate utilizzando ``EXPORT_SYMBOL`` o + ``EXPORT_SYMBOL_GPL`` in *source* o in qualsiasi altro *source-pattern* + specificato. + + Il campo *source-patter* è utile quando i commenti kernel-doc sono stati + scritti nei file d'intestazione, mentre ``EXPORT_SYMBOL`` e + ``EXPORT_SYMBOL_GPL`` si trovano vicino alla definizione delle funzioni. + + Esempi:: + + .. kernel-doc:: lib/bitmap.c + :export: + + .. kernel-doc:: include/net/mac80211.h + :export: net/mac80211/*.c + +internal: *[source-pattern ...]* + Include la documentazione per tutte le funzioni ed i tipi presenti nel file + sorgente (*source*) che **non** sono stati esportati utilizzando + ``EXPORT_SYMBOL`` o ``EXPORT_SYMBOL_GPL`` né in *source* né in qualsiasi + altro *source-pattern* specificato. + + Esempio:: + + .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c + :internal: + +doc: *title* + Include la documentazione del paragrafo ``DOC:`` identificato dal titolo + (*title*) all'interno del file sorgente (*source*). Gli spazi in *title* sono + permessi; non virgolettate *title*. Il campo *title* è utilizzato per + identificare un paragrafo e per questo non viene incluso nella documentazione + finale. Verificate d'avere l'intestazione appropriata nei documenti + reStructuredText. + + Esempio:: + + .. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c + :doc: High Definition Audio over HDMI and Display Port + +functions: *function* *[...]* + Dal file sorgente (*source*) include la documentazione per le funzioni + elencate (*function*). + + Esempio:: + + .. kernel-doc:: lib/bitmap.c + :functions: bitmap_parselist bitmap_parselist_user + +Senza alcuna opzione, la direttiva kernel-doc include tutti i commenti di +documentazione presenti nel file sorgente (*source*). + +L'estensione kernel-doc fa parte dei sorgenti del kernel, la si può trovare +in ``Documentation/sphinx/kerneldoc.py``. Internamente, viene utilizzato +lo script ``scripts/kernel-doc`` per estrarre i commenti di documentazione +dai file sorgenti. + +Come utilizzare kernel-doc per generare pagine man +-------------------------------------------------- + +Se volete utilizzare kernel-doc solo per generare delle pagine man, potete +farlo direttamente dai sorgenti del kernel:: + + $ scripts/kernel-doc -man $(git grep -l '/\*\*' -- :^Documentation :^tools) | scripts/split-man.pl /tmp/man diff --git a/Documentation/translations/it_IT/doc-guide/parse-headers.rst b/Documentation/translations/it_IT/doc-guide/parse-headers.rst new file mode 100644 index 0000000..b38918c --- /dev/null +++ b/Documentation/translations/it_IT/doc-guide/parse-headers.rst @@ -0,0 +1,196 @@ +.. include:: ../disclaimer-ita.rst + +.. note:: Per leggere la documentazione originale in inglese: + :ref:`Documentation/doc-guide/index.rst <doc_guide>` + +========================================= +Includere gli i file di intestazione uAPI +========================================= + +Qualche volta è utile includere dei file di intestazione e degli esempi di codice C +al fine di descrivere l'API per lo spazio utente e per generare dei riferimenti +fra il codice e la documentazione. Aggiungere i riferimenti ai file dell'API +dello spazio utente ha ulteriori vantaggi: Sphinx genererà dei messaggi +d'avviso se un simbolo non viene trovato nella documentazione. Questo permette +di mantenere allineate la documentazione della uAPI (API spazio utente) +con le modifiche del kernel. +Il programma :ref:`parse_headers.pl <it_parse_headers>` genera questi riferimenti. +Esso dev'essere invocato attraverso un Makefile, mentre si genera la +documentazione. Per avere un esempio su come utilizzarlo all'interno del kernel +consultate ``Documentation/media/Makefile``. + +.. _it_parse_headers: + +parse_headers.pl +^^^^^^^^^^^^^^^^ + +NOME +**** + + +parse_headers.pl - analizza i file C al fine di identificare funzioni, +strutture, enumerati e definizioni, e creare riferimenti per Sphinx + +SINTASSI +******** + + +\ **parse_headers.pl**\ [<options>] <C_FILE> <OUT_FILE> [<EXCEPTIONS_FILE>] + +Dove <options> può essere: --debug, --usage o --help. + + +OPZIONI +******* + + + +\ **--debug**\ + + Lo script viene messo in modalità verbosa, utile per il debugging. + + +\ **--usage**\ + + Mostra un messaggio d'aiuto breve e termina. + + +\ **--help**\ + + Mostra un messaggio d'aiuto dettagliato e termina. + + +DESCRIZIONE +*********** + +Converte un file d'intestazione o un file sorgente C (C_FILE) in un testo +ReStructuredText incluso mediante il blocco ..parsed-literal +con riferimenti alla documentazione che descrive l'API. Opzionalmente, +il programma accetta anche un altro file (EXCEPTIONS_FILE) che +descrive quali elementi debbano essere ignorati o il cui riferimento +deve puntare ad elemento diverso dal predefinito. + +Il file generato sarà disponibile in (OUT_FILE). + +Il programma è capace di identificare *define*, funzioni, strutture, +tipi di dato, enumerati e valori di enumerati, e di creare i riferimenti +per ognuno di loro. Inoltre, esso è capace di distinguere le #define +utilizzate per specificare i comandi ioctl di Linux. + +Il file EXCEPTIONS_FILE contiene due tipi di dichiarazioni: +\ **ignore**\ o \ **replace**\ . + +La sintassi per ignore è: + +ignore \ **tipo**\ \ **nome**\ + +La dichiarazione \ **ignore**\ significa che non verrà generato alcun +riferimento per il simbolo \ **name**\ di tipo \ **tipo**\ . + + +La sintassi per replace è: + +replace \ **tipo**\ \ **nome**\ \ **nuovo_valore**\ + +La dichiarazione \ **replace**\ significa che verrà generato un +riferimento per il simbolo \ **name**\ di tipo \ **tipo**\ , ma, invece +di utilizzare il valore predefinito, verrà utilizzato il valore +\ **nuovo_valore**\ . + +Per entrambe le dichiarazioni, il \ **tipo**\ può essere uno dei seguenti: + + +\ **ioctl**\ + + La dichiarazione ignore o replace verrà applicata su definizioni di ioctl + come la seguente: + + #define VIDIOC_DBG_S_REGISTER _IOW('V', 79, struct v4l2_dbg_register) + + + +\ **define**\ + + La dichiarazione ignore o replace verrà applicata su una qualsiasi #define + trovata in C_FILE. + + + +\ **typedef**\ + + La dichiarazione ignore o replace verrà applicata ad una dichiarazione typedef + in C_FILE. + + + +\ **struct**\ + + La dichiarazione ignore o replace verrà applicata ai nomi di strutture + in C_FILE. + + + +\ **enum**\ + + La dichiarazione ignore o replace verrà applicata ai nomi di enumerati + in C_FILE. + + + +\ **symbol**\ + + La dichiarazione ignore o replace verrà applicata ai nomi di valori di + enumerati in C_FILE. + + Per le dichiarazioni di tipo replace, il campo \ **new_value**\ utilizzerà + automaticamente i riferimenti :c:type: per \ **typedef**\ , \ **enum**\ e + \ **struct**\. Invece, utilizzerà :ref: per \ **ioctl**\ , \ **define**\ e + \ **symbol**\. Il tipo di riferimento può essere definito esplicitamente + nella dichiarazione stessa. + + +ESEMPI +****** + + +ignore define _VIDEODEV2_H + + +Ignora una definizione #define _VIDEODEV2_H nel file C_FILE. + +ignore symbol PRIVATE + + +In un enumerato come il seguente: + +enum foo { BAR1, BAR2, PRIVATE }; + +Non genererà alcun riferimento per \ **PRIVATE**\ . + +replace symbol BAR1 :c:type:\`foo\` +replace symbol BAR2 :c:type:\`foo\` + + +In un enumerato come il seguente: + +enum foo { BAR1, BAR2, PRIVATE }; + +Genererà un riferimento ai valori BAR1 e BAR2 dal simbolo foo nel dominio C. + + +BUGS +**** + +Riferire ogni malfunzionamento a Mauro Carvalho Chehab <mchehab@s-opensource.com> + + +COPYRIGHT +********* + + +Copyright (c) 2016 by Mauro Carvalho Chehab <mchehab@s-opensource.com>. + +Licenza GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>. + +Questo è software libero: siete liberi di cambiarlo e ridistribuirlo. +Non c'è alcuna garanzia, nei limiti permessi dalla legge. diff --git a/Documentation/translations/it_IT/doc-guide/sphinx.rst b/Documentation/translations/it_IT/doc-guide/sphinx.rst new file mode 100644 index 0000000..474b7e1 --- /dev/null +++ b/Documentation/translations/it_IT/doc-guide/sphinx.rst @@ -0,0 +1,457 @@ +.. include:: ../disclaimer-ita.rst + +.. note:: Per leggere la documentazione originale in inglese: + :ref:`Documentation/doc-guide/index.rst <doc_guide>` + +Introduzione +============ + +Il kernel Linux usa `Sphinx`_ per la generazione della documentazione a partire +dai file `reStructuredText`_ che si trovano nella cartella ``Documentation``. +Per generare la documentazione in HTML o PDF, usate comandi ``make htmldocs`` o +``make pdfdocs``. La documentazione così generata sarà disponibile nella +cartella ``Documentation/output``. + +.. _Sphinx: http://www.sphinx-doc.org/ +.. _reStructuredText: http://docutils.sourceforge.net/rst.html + +I file reStructuredText possono contenere delle direttive che permettono di +includere i commenti di documentazione, o di tipo kernel-doc, dai file +sorgenti. +Solitamente questi commenti sono utilizzati per descrivere le funzioni, i tipi +e l'architettura del codice. I commenti di tipo kernel-doc hanno una struttura +e formato speciale, ma a parte questo vengono processati come reStructuredText. + +Inoltre, ci sono migliaia di altri documenti in formato testo sparsi nella +cartella ``Documentation``. Alcuni di questi verranno probabilmente convertiti, +nel tempo, in formato reStructuredText, ma la maggior parte di questi rimarranno +in formato testo. + +.. _it_sphinx_install: + +Installazione Sphinx +==================== + +I marcatori ReST utilizzati nei file in Documentation/ sono pensati per essere +processati da ``Sphinx`` nella versione 1.3 o superiore. Se desiderate produrre +un documento PDF è raccomandato l'utilizzo di una versione superiore alle 1.4.6. + +Esiste uno script che verifica i requisiti Sphinx. Per ulteriori dettagli +consultate :ref:`it_sphinx-pre-install`. + +La maggior parte delle distribuzioni Linux forniscono Sphinx, ma l'insieme dei +programmi e librerie è fragile e non è raro che dopo un aggiornamento di +Sphinx, o qualche altro pacchetto Python, la documentazione non venga più +generata correttamente. + +Un modo per evitare questo genere di problemi è quello di utilizzare una +versione diversa da quella fornita dalla vostra distribuzione. Per fare questo, +vi raccomandiamo di installare Sphinx dentro ad un ambiente virtuale usando +``virtualenv-3`` o ``virtualenv`` a seconda di come Python 3 è stato +pacchettizzato dalla vostra distribuzione. + +.. note:: + + #) Le versioni di Sphinx inferiori alla 1.5 non funzionano bene + con il pacchetto Python docutils versione 0.13.1 o superiore. + Se volete usare queste versioni, allora dovere eseguire + ``pip install 'docutils==0.12'``. + + #) Viene raccomandato l'uso del tema RTD per la documentazione in HTML. + A seconda della versione di Sphinx, potrebbe essere necessaria + l'installazione tramite il comando ``pip install sphinx_rtd_theme``. + + #) Alcune pagine ReST contengono delle formule matematiche. A causa del + modo in cui Sphinx funziona, queste espressioni sono scritte + utilizzando LaTeX. Per una corretta interpretazione, è necessario aver + installato texlive con i pacchetti amdfonts e amsmath. + +Riassumendo, se volete installare la versione 1.4.9 di Sphinx dovete eseguire:: + + $ virtualenv sphinx_1.4 + $ . sphinx_1.4/bin/activate + (sphinx_1.4) $ pip install -r Documentation/sphinx/requirements.txt + +Dopo aver eseguito ``. sphinx_1.4/bin/activate``, il prompt cambierà per +indicare che state usando il nuovo ambiente. Se aprite un nuova sessione, +prima di generare la documentazione, dovrete rieseguire questo comando per +rientrare nell'ambiente virtuale. + +Generazione d'immagini +---------------------- + +Il meccanismo che genera la documentazione del kernel contiene un'estensione +capace di gestire immagini in formato Graphviz e SVG (per maggior informazioni +vedere :ref:`it_sphinx_kfigure`). + +Per far si che questo funzioni, dovete installare entrambe i pacchetti +Graphviz e ImageMagick. Il sistema di generazione della documentazione è in +grado di procedere anche se questi pacchetti non sono installati, ma il +risultato, ovviamente, non includerà le immagini. + +Generazione in PDF e LaTeX +-------------------------- + +Al momento, la generazione di questi documenti è supportata solo dalle +versioni di Sphinx superiori alla 1.4. + +Per la generazione di PDF e LaTeX, avrete bisogno anche del pacchetto +``XeLaTeX`` nella versione 3.14159265 + +Per alcune distribuzioni Linux potrebbe essere necessario installare +anche una serie di pacchetti ``texlive`` in modo da fornire il supporto +minimo per il funzionamento di ``XeLaTeX``. + +.. _it_sphinx-pre-install: + +Verificare le dipendenze Sphinx +------------------------------- + +Esiste uno script che permette di verificare automaticamente le dipendenze di +Sphinx. Se lo script riesce a riconoscere la vostra distribuzione, allora +sarà in grado di darvi dei suggerimenti su come procedere per completare +l'installazione:: + + $ ./scripts/sphinx-pre-install + Checking if the needed tools for Fedora release 26 (Twenty Six) are available + Warning: better to also install "texlive-luatex85". + You should run: + + sudo dnf install -y texlive-luatex85 + /usr/bin/virtualenv sphinx_1.4 + . sphinx_1.4/bin/activate + pip install -r Documentation/sphinx/requirements.txt + + Can't build as 1 mandatory dependency is missing at ./scripts/sphinx-pre-install line 468. + +L'impostazione predefinita prevede il controllo dei requisiti per la generazione +di documenti html e PDF, includendo anche il supporto per le immagini, le +espressioni matematiche e LaTeX; inoltre, presume che venga utilizzato un +ambiente virtuale per Python. I requisiti per generare i documenti html +sono considerati obbligatori, gli altri sono opzionali. + +Questo script ha i seguenti parametri: + +``--no-pdf`` + Disabilita i controlli per la generazione di PDF; + +``--no-virtualenv`` + Utilizza l'ambiente predefinito dal sistema operativo invece che + l'ambiente virtuale per Python; + + +Generazione della documentazione Sphinx +======================================= + +Per generare la documentazione in formato HTML o PDF si eseguono i rispettivi +comandi ``make htmldocs`` o ``make pdfdocs``. Esistono anche altri formati +in cui è possibile generare la documentazione; per maggiori informazioni +potere eseguire il comando ``make help``. +La documentazione così generata sarà disponibile nella sottocartella +``Documentation/output``. + +Ovviamente, per generare la documentazione, Sphinx (``sphinx-build``) +dev'essere installato. Se disponibile, il tema *Read the Docs* per Sphinx +verrà utilizzato per ottenere una documentazione HTML più gradevole. +Per la documentazione in formato PDF, invece, avrete bisogno di ``XeLaTeX` +e di ``convert(1)`` disponibile in ImageMagick (https://www.imagemagick.org). +Tipicamente, tutti questi pacchetti sono disponibili e pacchettizzati nelle +distribuzioni Linux. + +Per poter passare ulteriori opzioni a Sphinx potete utilizzare la variabile +make ``SPHINXOPTS``. Per esempio, se volete che Sphinx sia più verboso durante +la generazione potete usare il seguente comando ``make SPHINXOPTS=-v htmldocs``. + +Potete eliminare la documentazione generata tramite il comando +``make cleandocs``. + +Scrivere la documentazione +========================== + +Aggiungere nuova documentazione è semplice: + +1. aggiungete un file ``.rst`` nella sottocartella ``Documentation`` +2. aggiungete un riferimento ad esso nell'indice (`TOC tree`_) in + ``Documentation/index.rst``. + +.. _TOC tree: http://www.sphinx-doc.org/en/stable/markup/toctree.html + +Questo, di solito, è sufficiente per la documentazione più semplice (come +quella che state leggendo ora), ma per una documentazione più elaborata è +consigliato creare una sottocartella dedicata (o, quando possibile, utilizzarne +una già esistente). Per esempio, il sottosistema grafico è documentato nella +sottocartella ``Documentation/gpu``; questa documentazione è divisa in +diversi file ``.rst`` ed un indice ``index.rst`` (con un ``toctree`` +dedicato) a cui si fa riferimento nell'indice principale. + +Consultate la documentazione di `Sphinx`_ e `reStructuredText`_ per maggiori +informazione circa le loro potenzialità. In particolare, il +`manuale introduttivo a reStructuredText`_ di Sphinx è un buon punto da +cui cominciare. Esistono, inoltre, anche alcuni +`costruttori specifici per Sphinx`_. + +.. _`manuale introduttivo a reStructuredText`: http://www.sphinx-doc.org/en/stable/rest.html +.. _`costruttori specifici per Sphinx`: http://www.sphinx-doc.org/en/stable/markup/index.html + +Guide linea per la documentazione del kernel +-------------------------------------------- + +In questa sezione troverete alcune linee guida specifiche per la documentazione +del kernel: + +* Non esagerate con i costrutti di reStructuredText. Mantenete la + documentazione semplice. La maggior parte della documentazione dovrebbe + essere testo semplice con una strutturazione minima che permetta la + conversione in diversi formati. + +* Mantenete la strutturazione il più fedele possibile all'originale quando + convertite un documento in formato reStructuredText. + +* Aggiornate i contenuti quando convertite della documentazione, non limitatevi + solo alla formattazione. + +* Mantenete la decorazione dei livelli di intestazione come segue: + + 1. ``=`` con una linea superiore per il titolo del documento:: + + ====== + Titolo + ====== + + 2. ``=`` per i capitoli:: + + Capitoli + ======== + + 3. ``-`` per le sezioni:: + + Sezioni + ------- + + 4. ``~`` per le sottosezioni:: + + Sottosezioni + ~~~~~~~~~~~~ + + Sebbene RST non forzi alcun ordine specifico (*Piuttosto che imporre + un numero ed un ordine fisso di decorazioni, l'ordine utilizzato sarà + quello incontrato*), avere uniformità dei livelli principali rende più + semplice la lettura dei documenti. + +* Per inserire blocchi di testo con caratteri a dimensione fissa (codici di + esempio, casi d'uso, eccetera): utilizzate ``::`` quando non è necessario + evidenziare la sintassi, specialmente per piccoli frammenti; invece, + utilizzate ``.. code-block:: <language>`` per blocchi di più lunghi che + potranno beneficiare dell'avere la sintassi evidenziata. + + +Il dominio C +------------ + +Il **Dominio Sphinx C** (denominato c) è adatto alla documentazione delle API C. +Per esempio, un prototipo di una funzione: + +.. code-block:: rst + + .. c:function:: int ioctl( int fd, int request ) + +Il dominio C per kernel-doc ha delle funzionalità aggiuntive. Per esempio, +potete assegnare un nuovo nome di riferimento ad una funzione con un nome +molto comune come ``open`` o ``ioctl``: + +.. code-block:: rst + + .. c:function:: int ioctl( int fd, int request ) + :name: VIDIOC_LOG_STATUS + +Il nome della funzione (per esempio ioctl) rimane nel testo ma il nome del suo +riferimento cambia da ``ioctl`` a ``VIDIOC_LOG_STATUS``. Anche la voce +nell'indice cambia in ``VIDIOC_LOG_STATUS`` e si potrà quindi fare riferimento +a questa funzione scrivendo: + +.. code-block:: rst + + :c:func:`VIDIOC_LOG_STATUS` + + +Tabelle a liste +--------------- + +Raccomandiamo l'uso delle tabelle in formato lista (*list table*). Le tabelle +in formato lista sono liste di liste. In confronto all'ASCII-art potrebbero +non apparire di facile lettura nei file in formato testo. Il loro vantaggio è +che sono facili da creare o modificare e che la differenza di una modifica è +molto più significativa perché limitata alle modifiche del contenuto. + +La ``flat-table`` è anch'essa una lista di liste simile alle ``list-table`` +ma con delle funzionalità aggiuntive: + +* column-span: col ruolo ``cspan`` una cella può essere estesa attraverso + colonne successive + +* raw-span: col ruolo ``rspan`` una cella può essere estesa attraverso + righe successive + +* auto-span: la cella più a destra viene estesa verso destra per compensare + la mancanza di celle. Con l'opzione ``:fill-cells:`` questo comportamento + può essere cambiato da *auto-span* ad *auto-fill*, il quale inserisce + automaticamente celle (vuote) invece che estendere l'ultima. + +opzioni: + +* ``:header-rows:`` [int] conta le righe di intestazione +* ``:stub-columns:`` [int] conta le colonne di stub +* ``:widths:`` [[int] [int] ... ] larghezza delle colonne +* ``:fill-cells:`` invece di estendere automaticamente una cella su quelle + mancanti, ne crea di vuote. + +ruoli: + +* ``:cspan:`` [int] colonne successive (*morecols*) +* ``:rspan:`` [int] righe successive (*morerows*) + +L'esempio successivo mostra come usare questo marcatore. Il primo livello della +nostra lista di liste è la *riga*. In una *riga* è possibile inserire solamente +la lista di celle che compongono la *riga* stessa. Fanno eccezione i *commenti* +( ``..`` ) ed i *collegamenti* (per esempio, un riferimento a +``:ref:`last row <last row>``` / :ref:`last row <it last row>`) + +.. code-block:: rst + + .. flat-table:: table title + :widths: 2 1 1 3 + + * - head col 1 + - head col 2 + - head col 3 + - head col 4 + + * - column 1 + - field 1.1 + - field 1.2 with autospan + + * - column 2 + - field 2.1 + - :rspan:`1` :cspan:`1` field 2.2 - 3.3 + + * .. _`it last row`: + + - column 3 + +Che verrà rappresentata nel seguente modo: + + .. flat-table:: table title + :widths: 2 1 1 3 + + * - head col 1 + - head col 2 + - head col 3 + - head col 4 + + * - column 1 + - field 1.1 + - field 1.2 with autospan + + * - column 2 + - field 2.1 + - :rspan:`1` :cspan:`1` field 2.2 - 3.3 + + * .. _`it last row`: + + - column 3 + +.. _it_sphinx_kfigure: + +Figure ed immagini +================== + +Se volete aggiungere un'immagine, utilizzate le direttive ``kernel-figure`` +e ``kernel-image``. Per esempio, per inserire una figura di un'immagine in +formato SVG:: + + .. kernel-figure:: ../../../doc-guide/svg_image.svg + :alt: una semplice immagine SVG + + Una semplice immagine SVG + +.. _it_svg_image_example: + +.. kernel-figure:: ../../../doc-guide/svg_image.svg + :alt: una semplice immagine SVG + + Una semplice immagine SVG + +Le direttive del kernel per figure ed immagini supportano il formato **DOT**, +per maggiori informazioni + +* DOT: http://graphviz.org/pdf/dotguide.pdf +* Graphviz: http://www.graphviz.org/content/dot-language + +Un piccolo esempio (:ref:`it_hello_dot_file`):: + + .. kernel-figure:: ../../../doc-guide/hello.dot + :alt: ciao mondo + + Esempio DOT + +.. _it_hello_dot_file: + +.. kernel-figure:: ../../../doc-guide/hello.dot + :alt: ciao mondo + + Esempio DOT + +Tramite la direttiva ``kernel-render`` è possibile aggiungere codice specifico; +ad esempio nel formato **DOT** di Graphviz.:: + + .. kernel-render:: DOT + :alt: foobar digraph + :caption: Codice **DOT** (Graphviz) integrato + + digraph foo { + "bar" -> "baz"; + } + +La rappresentazione dipenderà dei programmi installati. Se avete Graphviz +installato, vedrete un'immagine vettoriale. In caso contrario, il codice grezzo +verrà rappresentato come *blocco testuale* (:ref:`it_hello_dot_render`). + +.. _it_hello_dot_render: + +.. kernel-render:: DOT + :alt: foobar digraph + :caption: Codice **DOT** (Graphviz) integrato + + digraph foo { + "bar" -> "baz"; + } + +La direttiva *render* ha tutte le opzioni della direttiva *figure*, con +l'aggiunta dell'opzione ``caption``. Se ``caption`` ha un valore allora +un nodo *figure* viene aggiunto. Altrimenti verrà aggiunto un nodo *image*. +L'opzione ``caption`` è necessaria in caso si vogliano aggiungere dei +riferimenti (:ref:`it_hello_svg_render`). + +Per la scrittura di codice **SVG**:: + + .. kernel-render:: SVG + :caption: Integrare codice **SVG** + :alt: so-nw-arrow + + <?xml version="1.0" encoding="UTF-8"?> + <svg xmlns="http://www.w3.org/2000/svg" version="1.1" ...> + ... + </svg> + +.. _it_hello_svg_render: + +.. kernel-render:: SVG + :caption: Integrare codice **SVG** + :alt: so-nw-arrow + + <?xml version="1.0" encoding="UTF-8"?> + <svg xmlns="http://www.w3.org/2000/svg" + version="1.1" baseProfile="full" width="70px" height="40px" viewBox="0 0 700 400"> + <line x1="180" y1="370" x2="500" y2="50" stroke="black" stroke-width="15px"/> + <polygon points="585 0 525 25 585 50" transform="rotate(135 525 25)"/> + </svg> diff --git a/Documentation/translations/it_IT/index.rst b/Documentation/translations/it_IT/index.rst new file mode 100644 index 0000000..898a782 --- /dev/null +++ b/Documentation/translations/it_IT/index.rst @@ -0,0 +1,118 @@ +.. _it_linux_doc: + +=================== +Traduzione italiana +=================== + +L'obiettivo di questa traduzione è di rendere più facile la lettura e +la comprensione per chi preferisce leggere in lingua italiana. +Tenete presente che la documentazione di riferimento rimane comunque +quella in lingua inglese: :ref:`linux_doc` + +Questa traduzione cerca di essere il più fedele possibile all'originale ma +è ovvio che alcune frasi vadano trasformate: non aspettatevi una traduzione +letterale. Quando possibile, si eviteranno gli inglesismi ed al loro posto +verranno utilizzate le corrispettive parole italiane. + +Se notate che la traduzione non è più aggiornata potete contattare +direttamente il manutentore della traduzione italiana. + +Se notate che la documentazione contiene errori o dimenticanze, allora +verificate la documentazione di riferimento in lingua inglese. Se il problema +è presente anche nella documentazione di riferimento, contattate il suo +manutentore. Se avete problemi a scrivere in inglese, potete comunque +riportare il problema al manutentore della traduzione italiana. + +Manutentore della traduzione italiana: Federico Vaga <federico.vaga@vaga.pv.it> + +La documentazione del kernel Linux +================================== + +Questo è il livello principale della documentazione del kernel in +lingua italiana. La traduzione è incompleta, noterete degli avvisi +che vi segnaleranno la mancanza di una traduzione o di un gruppo di +traduzioni. + +Più in generale, la documentazione, come il kernel stesso, sono in +costante sviluppo; particolarmente vero in quanto stiamo lavorando +alla riorganizzazione della documentazione in modo più coerente. +I miglioramenti alla documentazione sono sempre i benvenuti; per cui, +se vuoi aiutare, iscriviti alla lista di discussione linux-doc presso +vger.kernel.org. + +Documentazione sulla licenza dei sorgenti +----------------------------------------- + +I seguenti documenti descrivono la licenza usata nei sorgenti del kernel Linux +(GPLv2), come licenziare i singoli file; inoltre troverete i riferimenti al +testo integrale della licenza. + +.. warning:: + + TODO ancora da tradurre + +Documentazione per gli utenti +----------------------------- + +I seguenti manuali sono scritti per gli *utenti* del kernel - ovvero, +coloro che cercano di farlo funzionare in modo ottimale su un dato sistema + +.. warning:: + + TODO ancora da tradurre + +Documentazione per gli sviluppatori di applicazioni +--------------------------------------------------- + +Il manuale delle API verso lo spazio utente è una collezione di documenti +che descrivono le interfacce del kernel viste dagli sviluppatori +di applicazioni. + +.. warning:: + + TODO ancora da tradurre + + +Introduzione allo sviluppo del kernel +------------------------------------- + +Questi manuali contengono informazioni su come contribuire allo sviluppo +del kernel. +Attorno al kernel Linux gira una comunità molto grande con migliaia di +sviluppatori che contribuiscono ogni anno. Come in ogni grande comunità, +sapere come le cose vengono fatte renderà il processo di integrazione delle +vostre modifiche molto più semplice + +.. toctree:: + :maxdepth: 2 + + doc-guide/index + kernel-hacking/index + +.. warning:: + + TODO ancora da tradurre + +Documentazione della API del kernel +----------------------------------- + +Questi manuali forniscono dettagli su come funzionano i sottosistemi del +kernel dal punto di vista degli sviluppatori del kernel. Molte delle +informazioni contenute in questi manuali sono prese direttamente dai +file sorgenti, informazioni aggiuntive vengono aggiunte solo se necessarie +(o almeno ci proviamo — probabilmente *non* tutto quello che è davvero +necessario). + +.. warning:: + + TODO ancora da tradurre + +Documentazione specifica per architettura +----------------------------------------- + +Questi manuali forniscono dettagli di programmazione per le diverse +implementazioni d'architettura. + +.. warning:: + + TODO ancora da tradurre diff --git a/Documentation/translations/it_IT/kernel-hacking/hacking.rst b/Documentation/translations/it_IT/kernel-hacking/hacking.rst new file mode 100644 index 0000000..7178e51 --- /dev/null +++ b/Documentation/translations/it_IT/kernel-hacking/hacking.rst @@ -0,0 +1,855 @@ +.. include:: ../disclaimer-ita.rst + +.. note:: Per leggere la documentazione originale in inglese: + :ref:`Documentation/kernel-hacking/hacking.rst <kernel_hacking_hack>` + +:Original: :ref:`Documentation/kernel-hacking/hacking.rst <kernel_hacking_hack>` +:Translator: Federico Vaga <federico.vaga@vaga.pv.it> + +.. _it_kernel_hacking_hack: + +================================================= +L'inaffidabile guida all'hacking del kernel Linux +================================================= + +:Author: Rusty Russell + +Introduzione +============ + +Benvenuto, gentile lettore, alla notevole ed inaffidabile guida all'hacking +del kernel Linux ad opera di Rusty. Questo documento descrive le procedure +più usate ed i concetti necessari per scrivere codice per il kernel: lo scopo +è di fornire ai programmatori C più esperti un manuale di base per sviluppo. +Eviterò dettagli implementativi: per questo abbiamo il codice, +ed ignorerò intere parti di alcune procedure. + +Prima di leggere questa guida, sappiate che non ho mai voluto scriverla, +essendo esageratamente sotto qualificato, ma ho sempre voluto leggere +qualcosa di simile, e quindi questa era l'unica via. Spero che possa +crescere e diventare un compendio di buone pratiche, punti di partenza +e generiche informazioni. + +Gli attori +========== + +In qualsiasi momento ognuna delle CPU di un sistema può essere: + +- non associata ad alcun processo, servendo un'interruzione hardware; + +- non associata ad alcun processo, servendo un softirq o tasklet; + +- in esecuzione nello spazio kernel, associata ad un processo + (contesto utente); + +- in esecuzione di un processo nello spazio utente; + +Esiste un ordine fra questi casi. Gli ultimi due possono avvicendarsi (preempt) +l'un l'altro, ma a parte questo esiste una gerarchia rigida: ognuno di questi +può avvicendarsi solo ad uno di quelli sottostanti. Per esempio, mentre un +softirq è in esecuzione su d'una CPU, nessun altro softirq può avvicendarsi +nell'esecuzione, ma un'interruzione hardware può. Ciò nonostante, le altre CPU +del sistema operano indipendentemente. + +Più avanti vedremo alcuni modi in cui dal contesto utente è possibile bloccare +le interruzioni, così da impedirne davvero il diritto di prelazione. + +Contesto utente +--------------- + +Ci si trova nel contesto utente quando si arriva da una chiamata di sistema +od altre eccezioni: come nello spazio utente, altre procedure più importanti, +o le interruzioni, possono far valere il proprio diritto di prelazione sul +vostro processo. Potete sospendere l'esecuzione chiamando :c:func:`schedule()`. + +.. note:: + + Si è sempre in contesto utente quando un modulo viene caricato o rimosso, + e durante le operazioni nello strato dei dispositivi a blocchi + (*block layer*). + +Nel contesto utente, il puntatore ``current`` (il quale indica il processo al +momento in esecuzione) è valido, e :c:func:`in_interrupt()` +(``include/linux/preempt.h``) è falsa. + +.. warning:: + + Attenzione che se avete la prelazione o i softirq disabilitati (vedere + di seguito), :c:func:`in_interrupt()` ritornerà un falso positivo. + +Interruzioni hardware (Hard IRQs) +--------------------------------- + +Temporizzatori, schede di rete e tastiere sono esempi di vero hardware +che possono produrre interruzioni in un qualsiasi momento. Il kernel esegue +i gestori d'interruzione che prestano un servizio all'hardware. Il kernel +garantisce che questi gestori non vengano mai interrotti: se una stessa +interruzione arriva, questa verrà accodata (o scartata). +Dato che durante la loro esecuzione le interruzioni vengono disabilitate, +i gestori d'interruzioni devono essere veloci: spesso si limitano +esclusivamente a notificare la presa in carico dell'interruzione, +programmare una 'interruzione software' per l'esecuzione e quindi terminare. + +Potete dire d'essere in una interruzione hardware perché :c:func:`in_irq()` +ritorna vero. + +.. warning:: + + Attenzione, questa ritornerà un falso positivo se le interruzioni + sono disabilitate (vedere di seguito). + +Contesto d'interruzione software: softirq e tasklet +--------------------------------------------------- + +Quando una chiamata di sistema sta per tornare allo spazio utente, +oppure un gestore d'interruzioni termina, qualsiasi 'interruzione software' +marcata come pendente (solitamente da un'interruzione hardware) viene +eseguita (``kernel/softirq.c``). + +La maggior parte del lavoro utile alla gestione di un'interruzione avviene qui. +All'inizio della transizione ai sistemi multiprocessore, c'erano solo i +cosiddetti 'bottom half' (BH), i quali non traevano alcun vantaggio da questi +sistemi. Non appena abbandonammo i computer raffazzonati con fiammiferi e +cicche, abbandonammo anche questa limitazione e migrammo alle interruzioni +software 'softirqs'. + +Il file ``include/linux/interrupt.h`` elenca i differenti tipi di 'softirq'. +Un tipo di softirq molto importante è il timer (``include/linux/timer.h``): +potete programmarlo per far si che esegua funzioni dopo un determinato +periodo di tempo. + +Dato che i softirq possono essere eseguiti simultaneamente su più di un +processore, spesso diventa estenuante l'averci a che fare. Per questa ragione, +i tasklet (``include/linux/interrupt.h``) vengo usati più di frequente: +possono essere registrati dinamicamente (il che significa che potete averne +quanti ne volete), e garantiscono che un qualsiasi tasklet verrà eseguito +solo su un processore alla volta, sebbene diversi tasklet possono essere +eseguiti simultaneamente. + +.. warning:: + + Il nome 'tasklet' è ingannevole: non hanno niente a che fare + con i 'processi' ('tasks'), e probabilmente hanno più a che vedere + con qualche pessima vodka che Alexey Kuznetsov si fece a quel tempo. + +Potete determinate se siete in un softirq (o tasklet) utilizzando la +macro :c:func:`in_softirq()` (``include/linux/preempt.h``). + +.. warning:: + + State attenti che questa macro ritornerà un falso positivo + se :ref:`botton half lock <it_local_bh_disable>` è bloccato. + +Alcune regole basilari +====================== + +Nessuna protezione della memoria + Se corrompete la memoria, che sia in contesto utente o d'interruzione, + la macchina si pianterà. Siete sicuri che quello che volete fare + non possa essere fatto nello spazio utente? + +Nessun numero in virgola mobile o MMX + Il contesto della FPU non è salvato; anche se siete in contesto utente + lo stato dell'FPU probabilmente non corrisponde a quello del processo + corrente: vi incasinerete con lo stato di qualche altro processo. Se + volete davvero usare la virgola mobile, allora dovrete salvare e recuperare + lo stato dell'FPU (ed evitare cambi di contesto). Generalmente è una + cattiva idea; usate l'aritmetica a virgola fissa. + +Un limite rigido dello stack + A seconda della configurazione del kernel lo stack è fra 3K e 6K per la + maggior parte delle architetture a 32-bit; è di 14K per la maggior + parte di quelle a 64-bit; e spesso è condiviso con le interruzioni, + per cui non si può usare. + Evitare profonde ricorsioni ad enormi array locali nello stack + (allocateli dinamicamente). + +Il kernel Linux è portabile + Quindi mantenetelo tale. Il vostro codice dovrebbe essere a 64-bit ed + indipendente dall'ordine dei byte (endianess) di un processore. Inoltre, + dovreste minimizzare il codice specifico per un processore; per esempio + il codice assembly dovrebbe essere incapsulato in modo pulito e minimizzato + per facilitarne la migrazione. Generalmente questo codice dovrebbe essere + limitato alla parte di kernel specifica per un'architettura. + +ioctl: non scrivere nuove chiamate di sistema +============================================= + +Una chiamata di sistema, generalmente, è scritta così:: + + asmlinkage long sys_mycall(int arg) + { + return 0; + } + +Primo, nella maggior parte dei casi non volete creare nuove chiamate di +sistema. +Create un dispositivo a caratteri ed implementate l'appropriata chiamata ioctl. +Questo meccanismo è molto più flessibile delle chiamate di sistema: esso non +dev'essere dichiarato in tutte le architetture nei file +``include/asm/unistd.h`` e ``arch/kernel/entry.S``; inoltre, è improbabile +che questo venga accettato da Linus. + +Se tutto quello che il vostro codice fa è leggere o scrivere alcuni parametri, +considerate l'implementazione di un'interfaccia :c:func:`sysfs()`. + +All'interno di una ioctl vi trovate nel contesto utente di un processo. Quando +avviene un errore dovete ritornare un valore negativo di errno (consultate +``include/uapi/asm-generic/errno-base.h``, +``include/uapi/asm-generic/errno.h`` e ``include/linux/errno.h``), altrimenti +ritornate 0. + +Dopo aver dormito dovreste verificare se ci sono stati dei segnali: il modo +Unix/Linux di gestire un segnale è di uscire temporaneamente dalla chiamata +di sistema con l'errore ``-ERESTARTSYS``. La chiamata di sistema ritornerà +al contesto utente, eseguirà il gestore del segnale e poi la vostra chiamata +di sistema riprenderà (a meno che l'utente non l'abbia disabilitata). Quindi, +dovreste essere pronti per continuare l'esecuzione, per esempio nel mezzo +della manipolazione di una struttura dati. + +:: + + if (signal_pending(current)) + return -ERESTARTSYS; + +Se dovete eseguire dei calcoli molto lunghi: pensate allo spazio utente. +Se **davvero** volete farlo nel kernel ricordatevi di verificare periodicamente +se dovete *lasciare* il processore (ricordatevi che, per ogni processore, c'è +un sistema multi-processo senza diritto di prelazione). +Esempio:: + + cond_resched(); /* Will sleep */ + +Una breve nota sulla progettazione delle interfacce: il motto dei sistemi +UNIX è "fornite meccanismi e non politiche" + +La ricetta per uno stallo +========================= + +Non è permesso invocare una procedura che potrebbe dormire, fanno eccezione +i seguenti casi: + +- Siete in un contesto utente. + +- Non trattenete alcun spinlock. + +- Avete abilitato le interruzioni (in realtà, Andy Kleen dice che + lo schedulatore le abiliterà per voi, ma probabilmente questo non è quello + che volete). + +Da tener presente che alcune funzioni potrebbero dormire implicitamente: +le più comuni sono quelle per l'accesso allo spazio utente (\*_user) e +quelle per l'allocazione della memoria senza l'opzione ``GFP_ATOMIC`` + +Dovreste sempre compilare il kernel con l'opzione ``CONFIG_DEBUG_ATOMIC_SLEEP`` +attiva, questa vi avviserà se infrangete una di queste regole. +Se **infrangete** le regole, allora potreste bloccare il vostro scatolotto. + +Veramente. + +Alcune delle procedure più comuni +================================= + +:c:func:`printk()` +------------------ + +Definita in ``include/linux/printk.h`` + +:c:func:`printk()` fornisce messaggi alla console, dmesg, e al demone syslog. +Essa è utile per il debugging o per la notifica di errori; può essere +utilizzata anche all'interno del contesto d'interruzione, ma usatela con +cautela: una macchina che ha la propria console inondata da messaggi diventa +inutilizzabile. La funzione utilizza un formato stringa quasi compatibile con +la printf ANSI C, e la concatenazione di una stringa C come primo argomento +per indicare la "priorità":: + + printk(KERN_INFO "i = %u\n", i); + +Consultate ``include/linux/kern_levels.h`` per gli altri valori ``KERN_``; +questi sono interpretati da syslog come livelli. Un caso speciale: +per stampare un indirizzo IP usate:: + + __be32 ipaddress; + printk(KERN_INFO "my ip: %pI4\n", &ipaddress); + + +:c:func:`printk()` utilizza un buffer interno di 1K e non s'accorge di +eventuali sforamenti. Accertatevi che vi basti. + +.. note:: + + Saprete di essere un vero hacker del kernel quando inizierete a digitare + nei vostri programmi utenti le printf come se fossero printk :) + +.. note:: + + Un'altra nota a parte: la versione originale di Unix 6 aveva un commento + sopra alla funzione printf: "Printf non dovrebbe essere usata per il + chiacchiericcio". Dovreste seguire questo consiglio. + +:c:func:`copy_to_user()` / :c:func:`copy_from_user()` / :c:func:`get_user()` / :c:func:`put_user()` +--------------------------------------------------------------------------------------------------- + +Definite in ``include/linux/uaccess.h`` / ``asm/uaccess.h`` + +**[DORMONO]** + +:c:func:`put_user()` e :c:func:`get_user()` sono usate per ricevere ed +impostare singoli valori (come int, char, o long) da e verso lo spazio utente. +Un puntatore nello spazio utente non dovrebbe mai essere dereferenziato: i dati +dovrebbero essere copiati usando suddette procedure. Entrambe ritornano +``-EFAULT`` oppure 0. + +:c:func:`copy_to_user()` e :c:func:`copy_from_user()` sono più generiche: +esse copiano una quantità arbitraria di dati da e verso lo spazio utente. + +.. warning:: + + Al contrario di:c:func:`put_user()` e :c:func:`get_user()`, queste + funzioni ritornano la quantità di dati copiati (0 è comunque un successo). + +[Sì, questa stupida interfaccia mi imbarazza. La battaglia torna in auge anno +dopo anno. --RR] + +Le funzioni potrebbero dormire implicitamente. Queste non dovrebbero mai essere +invocate fuori dal contesto utente (non ha senso), con le interruzioni +disabilitate, o con uno spinlock trattenuto. + +:c:func:`kmalloc()`/:c:func:`kfree()` +------------------------------------- + +Definite in ``include/linux/slab.h`` + +**[POTREBBERO DORMIRE: LEGGI SOTTO]** + +Queste procedure sono utilizzate per la richiesta dinamica di un puntatore ad +un pezzo di memoria allineato, esattamente come malloc e free nello spazio +utente, ma :c:func:`kmalloc()` ha un argomento aggiuntivo per indicare alcune +opzioni. Le opzioni più importanti sono: + +``GFP_KERNEL`` + Potrebbe dormire per librarare della memoria. L'opzione fornisce il modo + più affidabile per allocare memoria, ma il suo uso è strettamente limitato + allo spazio utente. + +``GFP_ATOMIC`` + Non dorme. Meno affidabile di ``GFP_KERNEL``, ma può essere usata in un + contesto d'interruzione. Dovreste avere **davvero** una buona strategia + per la gestione degli errori in caso di mancanza di memoria. + +``GFP_DMA`` + Alloca memoria per il DMA sul bus ISA nello spazio d'indirizzamento + inferiore ai 16MB. Se non sapete cos'è allora non vi serve. + Molto inaffidabile. + +Se vedete un messaggio d'avviso per una funzione dormiente che viene chiamata +da un contesto errato, allora probabilmente avete usato una funzione +d'allocazione dormiente da un contesto d'interruzione senza ``GFP_ATOMIC``. +Dovreste correggerlo. Sbrigatevi, non cincischiate. + +Se allocate almeno ``PAGE_SIZE``(``asm/page.h`` o ``asm/page_types.h``) byte, +considerate l'uso di :c:func:`__get_free_pages()` (``include/linux/gfp.h``). +Accetta un argomento che definisce l'ordine (0 per per la dimensione di una +pagine, 1 per una doppia pagina, 2 per quattro pagine, eccetra) e le stesse +opzioni d'allocazione viste precedentemente. + +Se state allocando un numero di byte notevolemnte superiore ad una pagina +potete usare :c:func:`vmalloc()`. Essa allocherà memoria virtuale all'interno +dello spazio kernel. Questo è un blocco di memoria fisica non contiguo, ma +la MMU vi darà l'impressione che lo sia (quindi, sarà contiguo solo dal punto +di vista dei processori, non dal punto di vista dei driver dei dispositivi +esterni). +Se per qualche strana ragione avete davvero bisogno di una grossa quantità di +memoria fisica contigua, avete un problema: Linux non ha un buon supporto per +questo caso d'uso perché, dopo un po' di tempo, la frammentazione della memoria +rende l'operazione difficile. Il modo migliore per allocare un simile blocco +all'inizio dell'avvio del sistema è attraverso la procedura +:c:func:`alloc_bootmem()`. + +Prima di inventare la vostra cache per gli oggetti più usati, considerate +l'uso di una cache slab disponibile in ``include/linux/slab.h``. + +:c:func:`current()` +------------------- + +Definita in ``include/asm/current.h`` + +Questa variabile globale (in realtà una macro) contiene un puntatore alla +struttura del processo corrente, quindi è valido solo dal contesto utente. +Per esempio, quando un processo esegue una chiamata di sistema, questo +punterà alla struttura dati del processo chiamate. +Nel contesto d'interruzione in suo valore **non è NULL**. + +:c:func:`mdelay()`/:c:func:`udelay()` +------------------------------------- + +Definite in ``include/asm/delay.h`` / ``include/linux/delay.h`` + +Le funzioni :c:func:`udelay()` e :c:func:`ndelay()` possono essere utilizzate +per brevi pause. Non usate grandi valori perché rischiate d'avere un +overflow - in questo contesto la funzione :c:func:`mdelay()` è utile, +oppure considerate :c:func:`msleep()`. + +:c:func:`cpu_to_be32()`/:c:func:`be32_to_cpu()`/:c:func:`cpu_to_le32()`/:c:func:`le32_to_cpu()` +----------------------------------------------------------------------------------------------- + +Definite in ``include/asm/byteorder.h`` + +La famiglia di funzioni :c:func:`cpu_to_be32()` (dove "32" può essere +sostituito da 64 o 16, e "be" con "le") forniscono un modo generico +per fare conversioni sull'ordine dei byte (endianess): esse ritornano +il valore convertito. Tutte le varianti supportano anche il processo inverso: +:c:func:`be32_to_cpu()`, eccetera. + +Queste funzioni hanno principalmente due varianti: la variante per +puntatori, come :c:func:`cpu_to_be32p(), che prende un puntatore +ad un tipo, e ritorna il valore convertito. L'altra variante per +la famiglia di conversioni "in-situ", come :c:func:`cpu_to_be32s()`, +che convertono il valore puntato da un puntatore, e ritornano void. + +:c:func:`local_irq_save()`/:c:func:`local_irq_restore()` +-------------------------------------------------------- + +Definite in ``include/linux/irqflags.h`` + +Queste funzioni abilitano e disabilitano le interruzioni hardware +sul processore locale. Entrambe sono rientranti; esse salvano lo stato +precedente nel proprio argomento ``unsigned long flags``. Se sapete +che le interruzioni sono abilite, potete semplicemente utilizzare +:c:func:`local_irq_disable()` e :c:func:`local_irq_enable()`. + +.. _it_local_bh_disable: + +:c:func:`local_bh_disable()`/:c:func:`local_bh_enable()` +-------------------------------------------------------- + +Definite in ``include/linux/bottom_half.h`` + + +Queste funzioni abilitano e disabilitano le interruzioni software +sul processore locale. Entrambe sono rientranti; se le interruzioni +software erano già state disabilitate in precedenza, rimarranno +disabilitate anche dopo aver invocato questa coppia di funzioni. +Lo scopo è di prevenire l'esecuzione di softirq e tasklet sul processore +attuale. + +:c:func:`smp_processor_id()` +---------------------------- + +Definita in ``include/linux/smp.h`` + +:c:func:`get_cpu()` nega il diritto di prelazione (quindi non potete essere +spostati su un altro processore all'improvviso) e ritorna il numero +del processore attuale, fra 0 e ``NR_CPUS``. Da notare che non è detto +che la numerazione dei processori sia continua. Quando avete terminato, +ritornate allo stato precedente con :c:func:`put_cpu()`. + +Se sapete che non dovete essere interrotti da altri processi (per esempio, +se siete in un contesto d'interruzione, o il diritto di prelazione +è disabilitato) potete utilizzare smp_processor_id(). + + +``__init``/``__exit``/``__initdata`` +------------------------------------ + +Definite in ``include/linux/init.h`` + +Dopo l'avvio, il kernel libera una sezione speciale; le funzioni marcate +con ``__init`` e le strutture dati marcate con ``__initdata`` vengono +eliminate dopo il completamento dell'avvio: in modo simile i moduli eliminano +questa memoria dopo l'inizializzazione. ``__exit`` viene utilizzato per +dichiarare che una funzione verrà utilizzata solo in fase di rimozione: +la detta funzione verrà eliminata quando il file che la contiene non è +compilato come modulo. Guardate l'header file per informazioni. Da notare che +non ha senso avere una funzione marcata come ``__init`` e al tempo stesso +esportata ai moduli utilizzando :c:func:`EXPORT_SYMBOL()` o +:c:func:`EXPORT_SYMBOL_GPL()` - non funzionerà. + + +:c:func:`__initcall()`/:c:func:`module_init()` +---------------------------------------------- + +Definite in ``include/linux/init.h`` / ``include/linux/module.h`` + +Molte parti del kernel funzionano bene come moduli (componenti del kernel +caricabili dinamicamente). L'utilizzo delle macro :c:func:`module_init()` +e :c:func:`module_exit()` semplifica la scrittura di codice che può funzionare +sia come modulo, sia come parte del kernel, senza l'ausilio di #ifdef. + +La macro :c:func:`module_init()` definisce quale funzione dev'essere +chiamata quando il modulo viene inserito (se il file è stato compilato come +tale), o in fase di avvio : se il file non è stato compilato come modulo la +macro :c:func:`module_init()` diventa equivalente a :c:func:`__initcall()`, +la quale, tramite qualche magia del linker, s'assicura che la funzione venga +chiamata durante l'avvio. + +La funzione può ritornare un numero d'errore negativo per scatenare un +fallimento del caricamento (sfortunatamente, questo non ha effetto se il +modulo è compilato come parte integrante del kernel). Questa funzione è chiamata +in contesto utente con le interruzioni abilitate, quindi potrebbe dormire. + + +:c:func:`module_exit()` +----------------------- + + +Definita in ``include/linux/module.h`` + +Questa macro definisce la funzione che dev'essere chiamata al momento della +rimozione (o mai, nel caso in cui il file sia parte integrante del kernel). +Essa verrà chiamata solo quando il contatore d'uso del modulo raggiunge lo +zero. Questa funzione può anche dormire, ma non può fallire: tutto dev'essere +ripulito prima che la funzione ritorni. + +Da notare che questa macro è opzionale: se non presente, il modulo non sarà +removibile (a meno che non usiate 'rmmod -f' ). + + +:c:func:`try_module_get()`/:c:func:`module_put()` +------------------------------------------------- + +Definite in ``include/linux/module.h`` + +Queste funzioni maneggiano il contatore d'uso del modulo per proteggerlo dalla +rimozione (in aggiunta, un modulo non può essere rimosso se un altro modulo +utilizzo uno dei sui simboli esportati: vedere di seguito). Prima di eseguire +codice del modulo, dovreste chiamare :c:func:`try_module_get()` su quel modulo: +se fallisce significa che il modulo è stato rimosso e dovete agire come se +non fosse presente. Altrimenti, potete accedere al modulo in sicurezza, e +chiamare :c:func:`module_put()` quando avete finito. + +La maggior parte delle strutture registrabili hanno un campo owner +(proprietario), come nella struttura +:c:type:`struct file_operations <file_operations>`. +Impostate questo campo al valore della macro ``THIS_MODULE``. + + +Code d'attesa ``include/linux/wait.h`` +====================================== + +**[DORMONO]** + +Una coda d'attesa è usata per aspettare che qualcuno vi attivi quando una +certa condizione s'avvera. Per evitare corse critiche, devono essere usate +con cautela. Dichiarate una :c:type:`wait_queue_head_t`, e poi i processi +che vogliono attendere il verificarsi di quella condizione dichiareranno +una :c:type:`wait_queue_entry_t` facendo riferimento a loro stessi, poi +metteranno questa in coda. + +Dichiarazione +------------- + +Potere dichiarare una ``wait_queue_head_t`` utilizzando la macro +:c:func:`DECLARE_WAIT_QUEUE_HEAD()` oppure utilizzando la procedura +:c:func:`init_waitqueue_head()` nel vostro codice d'inizializzazione. + +Accodamento +----------- + +Mettersi in una coda d'attesa è piuttosto complesso, perché dovete +mettervi in coda prima di verificare la condizione. Esiste una macro +a questo scopo: :c:func:`wait_event_interruptible()` (``include/linux/wait.h``). +Il primo argomento è la testa della coda d'attesa, e il secondo è +un'espressione che dev'essere valutata; la macro ritorna 0 quando questa +espressione è vera, altrimenti ``-ERESTARTSYS`` se è stato ricevuto un segnale. +La versione :c:func:`wait_event()` ignora i segnali. + +Svegliare una procedura in coda +------------------------------- + +Chiamate :c:func:`wake_up()` (``include/linux/wait.h``); questa attiverà tutti +i processi in coda. Ad eccezione se uno di questi è impostato come +``TASK_EXCLUSIVE``, in questo caso i rimanenti non verranno svegliati. +Nello stesso header file esistono altre varianti di questa funzione. + +Operazioni atomiche +=================== + +Certe operazioni sono garantite come atomiche su tutte le piattaforme. +Il primo gruppo di operazioni utilizza :c:type:`atomic_t` +(``include/asm/atomic.h``); questo contiene un intero con segno (minimo 32bit), +e dovete utilizzare queste funzione per modificare o leggere variabili di tipo +:c:type:`atomic_t`. :c:func:`atomic_read()` e :c:func:`atomic_set()` leggono ed +impostano il contatore, :c:func:`atomic_add()`, :c:func:`atomic_sub()`, +:c:func:`atomic_inc()`, :c:func:`atomic_dec()`, e +:c:func:`atomic_dec_and_test()` (ritorna vero se raggiunge zero dopo essere +stata decrementata). + +Sì. Ritorna vero (ovvero != 0) se la variabile atomica è zero. + +Da notare che queste funzioni sono più lente rispetto alla normale aritmetica, +e quindi non dovrebbero essere usate a sproposito. + +Il secondo gruppo di operazioni atomiche sono definite in +``include/linux/bitops.h`` ed agiscono sui bit d'una variabile di tipo +``unsigned long``. Queste operazioni prendono come argomento un puntatore +alla variabile, e un numero di bit dove 0 è quello meno significativo. +:c:func:`set_bit()`, :c:func:`clear_bit()` e :c:func:`change_bit()` +impostano, cancellano, ed invertono il bit indicato. +:c:func:`test_and_set_bit()`, :c:func:`test_and_clear_bit()` e +:c:func:`test_and_change_bit()` fanno la stessa cosa, ad eccezione che +ritornano vero se il bit era impostato; queste sono particolarmente +utili quando si vuole impostare atomicamente dei flag. + +Con queste operazioni è possibile utilizzare indici di bit che eccedono +il valore ``BITS_PER_LONG``. Il comportamento è strano sulle piattaforme +big-endian quindi è meglio evitarlo. + +Simboli +======= + +All'interno del kernel, si seguono le normali regole del linker (ovvero, +a meno che un simbolo non venga dichiarato con visibilita limitata ad un +file con la parola chiave ``static``, esso può essere utilizzato in qualsiasi +parte del kernel). Nonostante ciò, per i moduli, esiste una tabella dei +simboli esportati che limita i punti di accesso al kernel. Anche i moduli +possono esportare simboli. + +:c:func:`EXPORT_SYMBOL()` +------------------------- + +Definita in ``include/linux/export.h`` + +Questo è il classico metodo per esportare un simbolo: i moduli caricati +dinamicamente potranno utilizzare normalmente il simbolo. + +:c:func:`EXPORT_SYMBOL_GPL()` +----------------------------- + +Definita in ``include/linux/export.h`` + +Essa è simile a :c:func:`EXPORT_SYMBOL()` ad eccezione del fatto che i +simboli esportati con :c:func:`EXPORT_SYMBOL_GPL()` possono essere +utilizzati solo dai moduli che hanno dichiarato una licenza compatibile +con la GPL attraverso :c:func:`MODULE_LICENSE()`. Questo implica che la +funzione esportata è considerata interna, e non una vera e propria interfaccia. +Alcuni manutentori e sviluppatori potrebbero comunque richiedere +:c:func:`EXPORT_SYMBOL_GPL()` quando si aggiungono nuove funzionalità o +interfacce. + +Procedure e convenzioni +======================= + +Liste doppiamente concatenate ``include/linux/list.h`` +------------------------------------------------------ + +Un tempo negli header del kernel c'erano tre gruppi di funzioni per +le liste concatenate, ma questa è stata la vincente. Se non avete particolari +necessità per una semplice lista concatenata, allora questa è una buona scelta. + +In particolare, :c:func:`list_for_each_entry()` è utile. + +Convenzione dei valori di ritorno +--------------------------------- + +Per codice chiamato in contesto utente, è molto comune sfidare le convenzioni +C e ritornare 0 in caso di successo, ed un codice di errore negativo +(eg. ``-EFAULT``) nei casi fallimentari. Questo potrebbe essere controintuitivo +a prima vista, ma è abbastanza diffuso nel kernel. + +Utilizzate :c:func:`ERR_PTR()` (``include/linux/err.h``) per codificare +un numero d'errore negativo in un puntatore, e :c:func:`IS_ERR()` e +:c:func:`PTR_ERR()` per recuperarlo di nuovo: così si evita d'avere un +puntatore dedicato per il numero d'errore. Da brividi, ma in senso positivo. + +Rompere la compilazione +----------------------- + +Linus e gli altri sviluppatori a volte cambiano i nomi delle funzioni e +delle strutture nei kernel in sviluppo; questo non è solo per tenere +tutti sulle spine: questo riflette cambiamenti fondamentati (eg. la funzione +non può più essere chiamata con le funzioni attive, o fa controlli aggiuntivi, +o non fa più controlli che venivano fatti in precedenza). Solitamente a questo +s'accompagna un'adeguata e completa nota sulla lista di discussone +linux-kernel; cercate negli archivi. +Solitamente eseguire una semplice sostituzione su tutto un file rendere +le cose **peggiori**. + +Inizializzazione dei campi d'una struttura +------------------------------------------ + +Il metodo preferito per l'inizializzazione delle strutture è quello +di utilizzare gli inizializzatori designati, come definiti nello +standard ISO C99, eg:: + + static struct block_device_operations opt_fops = { + .open = opt_open, + .release = opt_release, + .ioctl = opt_ioctl, + .check_media_change = opt_media_change, + }; + +Questo rende più facile la ricerca con grep, e rende più chiaro quale campo +viene impostato. Dovreste fare così perché si mostra meglio. + +Estensioni GNU +-------------- + +Le estensioni GNU sono esplicitamente permesse nel kernel Linux. Da notare +che alcune delle più complesse non sono ben supportate, per via dello scarso +sviluppo, ma le seguenti sono da considerarsi la norma (per maggiori dettagli, +leggete la sezione "C Extensions" nella pagina info di GCC - Sì, davvero +la pagina info, la pagina man è solo un breve riassunto delle cose nella +pagina info). + +- Funzioni inline + +- Istruzioni in espressioni (ie. il costrutto ({ and }) ). + +- Dichiarate attributi di una funzione / variabile / tipo + (__attribute__) + +- typeof + +- Array con lunghezza zero + +- Macro varargs + +- Aritmentica sui puntatori void + +- Inizializzatori non costanti + +- Istruzioni assembler (non al di fuori di 'arch/' e 'include/asm/') + +- Nomi delle funzioni come stringhe (__func__). + +- __builtin_constant_p() + +Siate sospettosi quando utilizzate long long nel kernel, il codice generato +da gcc è orribile ed anche peggio: le divisioni e le moltiplicazioni non +funzionano sulle piattaforme i386 perché le rispettive funzioni di runtime +di GCC non sono incluse nell'ambiente del kernel. + +C++ +--- + +Solitamente utilizzare il C++ nel kernel è una cattiva idea perché +il kernel non fornisce il necessario ambiente di runtime e gli header file +non sono stati verificati. Rimane comunque possibile, ma non consigliato. +Se davvero volete usarlo, almeno evitate le eccezioni. + +NUMif +----- + +Viene generalmente considerato più pulito l'uso delle macro negli header file +(o all'inizio dei file .c) per astrarre funzioni piuttosto che utlizzare +l'istruzione di pre-processore \`#if' all'interno del codice sorgente. + +Mettere le vostre cose nel kernel +================================= + +Al fine d'avere le vostre cose in ordine per l'inclusione ufficiale, o +anche per avere patch pulite, c'è del lavoro amministrativo da fare: + +- Trovare di chi è lo stagno in cui state pisciando. Guardare in cima + ai file sorgenti, all'interno del file ``MAINTAINERS``, ed alla fine + di tutti nel file ``CREDITS``. Dovreste coordinarvi con queste persone + per evitare di duplicare gli sforzi, o provare qualcosa che è già stato + rigettato. + + Assicuratevi di mettere il vostro nome ed indirizzo email in cima a + tutti i file che create o che mangeggiate significativamente. Questo è + il primo posto dove le persone guarderanno quando troveranno un baco, + o quando **loro** vorranno fare una modifica. + +- Solitamente vorrete un'opzione di configurazione per la vostra modifica + al kernel. Modificate ``Kconfig`` nella cartella giusta. Il linguaggio + Config è facile con copia ed incolla, e c'è una completa documentazione + nel file ``Documentation/kbuild/kconfig-language.txt``. + + Nella descrizione della vostra opzione, assicuratevi di parlare sia agli + utenti esperti sia agli utente che non sanno nulla del vostro lavoro. + Menzionate qui le incompatibilità ed i problemi. Chiaramente la + descrizione deve terminare con “if in doubt, say N” (se siete in dubbio, + dite N) (oppure, occasionalmente, \`Y'); questo è per le persone che non + hanno idea di che cosa voi stiate parlando. + +- Modificate il file ``Makefile``: le variabili CONFIG sono esportate qui, + quindi potete solitamente aggiungere una riga come la seguete + "obj-$(CONFIG_xxx) += xxx.o". La sintassi è documentata nel file + ``Documentation/kbuild/makefiles.txt``. + +- Aggiungete voi stessi in ``CREDITS`` se avete fatto qualcosa di notevole, + solitamente qualcosa che supera il singolo file (comunque il vostro nome + dovrebbe essere all'inizio dei file sorgenti). ``MAINTAINERS`` significa + che volete essere consultati quando vengono fatte delle modifiche ad un + sottosistema, e quando ci sono dei bachi; questo implica molto di più + di un semplice impegno su una parte del codice. + +- Infine, non dimenticatevi di leggere + ``Documentation/process/submitting-patches.rst`` e possibilmente anche + ``Documentation/process/submitting-drivers.rst``. + +Trucchetti del kernel +===================== + +Dopo una rapida occhiata al codice, questi sono i preferiti. Sentitevi liberi +di aggiungerne altri. + +``arch/x86/include/asm/delay.h``:: + + #define ndelay(n) (__builtin_constant_p(n) ? \ + ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \ + __ndelay(n)) + + +``include/linux/fs.h``:: + + /* + * Kernel pointers have redundant information, so we can use a + * scheme where we can return either an error code or a dentry + * pointer with the same return value. + * + * This should be a per-architecture thing, to allow different + * error and pointer decisions. + */ + #define ERR_PTR(err) ((void *)((long)(err))) + #define PTR_ERR(ptr) ((long)(ptr)) + #define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)(-1000)) + +``arch/x86/include/asm/uaccess_32.h:``:: + + #define copy_to_user(to,from,n) \ + (__builtin_constant_p(n) ? \ + __constant_copy_to_user((to),(from),(n)) : \ + __generic_copy_to_user((to),(from),(n))) + + +``arch/sparc/kernel/head.S:``:: + + /* + * Sun people can't spell worth damn. "compatability" indeed. + * At least we *know* we can't spell, and use a spell-checker. + */ + + /* Uh, actually Linus it is I who cannot spell. Too much murky + * Sparc assembly will do this to ya. + */ + C_LABEL(cputypvar): + .asciz "compatibility" + + /* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. */ + .align 4 + C_LABEL(cputypvar_sun4m): + .asciz "compatible" + + +``arch/sparc/lib/checksum.S:``:: + + /* Sun, you just can't beat me, you just can't. Stop trying, + * give up. I'm serious, I am going to kick the living shit + * out of you, game over, lights out. + */ + + +Ringraziamenti +============== + +Ringrazio Andi Kleen per le sue idee, le risposte alle mie domande, +le correzioni dei miei errori, l'aggiunta di contenuti, eccetera. +Philipp Rumpf per l'ortografia e per aver reso più chiaro il testo, e +per alcuni eccellenti punti tutt'altro che ovvi. Werner Almesberger +per avermi fornito un ottimo riassunto di :c:func:`disable_irq()`, +e Jes Sorensen e Andrea Arcangeli per le precisazioni. Michael Elizabeth +Chastain per aver verificato ed aggiunto la sezione configurazione. +Telsa Gwynne per avermi insegnato DocBook. diff --git a/Documentation/translations/it_IT/kernel-hacking/index.rst b/Documentation/translations/it_IT/kernel-hacking/index.rst new file mode 100644 index 0000000..5022838 --- /dev/null +++ b/Documentation/translations/it_IT/kernel-hacking/index.rst @@ -0,0 +1,16 @@ +.. include:: ../disclaimer-ita.rst + +:Original: :ref:`Documentation/kernel-hacking/index.rst <kernel_hacking>` +:Translator: Federico Vaga <federico.vaga@vaga.pv.it> + +.. _it_kernel_hacking: + +============================ +Guida all'hacking del kernel +============================ + +.. toctree:: + :maxdepth: 2 + + hacking + locking diff --git a/Documentation/translations/it_IT/kernel-hacking/locking.rst b/Documentation/translations/it_IT/kernel-hacking/locking.rst new file mode 100644 index 0000000..7536436 --- /dev/null +++ b/Documentation/translations/it_IT/kernel-hacking/locking.rst @@ -0,0 +1,1493 @@ +.. include:: ../disclaimer-ita.rst + +:Original: :ref:`Documentation/kernel-hacking/locking.rst <kernel_hacking_lock>` +:Translator: Federico Vaga <federico.vaga@vaga.pv.it> + +.. _it_kernel_hacking_lock: + +========================================== +L'inaffidabile guida alla sincronizzazione +========================================== + +:Author: Rusty Russell + +Introduzione +============ + +Benvenuto, alla notevole ed inaffidabile guida ai problemi di sincronizzazione +(locking) nel kernel. Questo documento descrive il sistema di sincronizzazione +nel kernel Linux 2.6. + +Dato il largo utilizzo del multi-threading e della prelazione nel kernel +Linux, chiunque voglia dilettarsi col kernel deve conoscere i concetti +fondamentali della concorrenza e della sincronizzazione nei sistemi +multi-processore. + +Il problema con la concorrenza +============================== + +(Saltatelo se sapete già cos'è una corsa critica). + +In un normale programma, potete incrementare un contatore nel seguente modo: + +:: + + contatore++; + +Questo è quello che vi aspettereste che accada sempre: + + +.. table:: Risultati attesi + + +------------------------------------+------------------------------------+ + | Istanza 1 | Istanza 2 | + +====================================+====================================+ + | leggi contatore (5) | | + +------------------------------------+------------------------------------+ + | aggiungi 1 (6) | | + +------------------------------------+------------------------------------+ + | scrivi contatore (6) | | + +------------------------------------+------------------------------------+ + | | leggi contatore (6) | + +------------------------------------+------------------------------------+ + | | aggiungi 1 (7) | + +------------------------------------+------------------------------------+ + | | scrivi contatore (7) | + +------------------------------------+------------------------------------+ + +Questo è quello che potrebbe succedere in realtà: + +.. table:: Possibile risultato + + +------------------------------------+------------------------------------+ + | Istanza 1 | Istanza 2 | + +====================================+====================================+ + | leggi contatore (5) | | + +------------------------------------+------------------------------------+ + | | leggi contatore (5) | + +------------------------------------+------------------------------------+ + | aggiungi 1 (6) | | + +------------------------------------+------------------------------------+ + | | aggiungi 1 (6) | + +------------------------------------+------------------------------------+ + | scrivi contatore (6) | | + +------------------------------------+------------------------------------+ + | | scrivi contatore (6) | + +------------------------------------+------------------------------------+ + + +Corse critiche e sezioni critiche +--------------------------------- + +Questa sovrapposizione, ovvero quando un risultato dipende dal tempo che +intercorre fra processi diversi, è chiamata corsa critica. La porzione +di codice che contiene questo problema è chiamata sezione critica. +In particolar modo da quando Linux ha incominciato a girare su +macchine multi-processore, le sezioni critiche sono diventate uno dei +maggiori problemi di progettazione ed implementazione del kernel. + +La prelazione può sortire gli stessi effetti, anche se c'è una sola CPU: +interrompendo un processo nella sua sezione critica otterremo comunque +la stessa corsa critica. In questo caso, il thread che si avvicenda +nell'esecuzione potrebbe eseguire anch'esso la sezione critica. + +La soluzione è quella di riconoscere quando avvengono questi accessi +simultanei, ed utilizzare i *lock* per accertarsi che solo un'istanza +per volta possa entrare nella sezione critica. Il kernel offre delle buone +funzioni a questo scopo. E poi ci sono quelle meno buone, ma farò finta +che non esistano. + +Sincronizzazione nel kernel Linux +================================= + +Se posso darvi un suggerimento: non dormite mai con qualcuno più pazzo di +voi. Ma se dovessi darvi un suggerimento sulla sincronizzazione: +**mantenetela semplice**. + +Siate riluttanti nell'introduzione di nuovi *lock*. + +Abbastanza strano, quest'ultimo è l'esatto opposto del mio suggerimento +su quando **avete** dormito con qualcuno più pazzo di voi. E dovreste +pensare a prendervi un cane bello grande. + +I due principali tipi di *lock* nel kernel: spinlock e mutex +------------------------------------------------------------ + +Ci sono due tipi principali di *lock* nel kernel. Il tipo fondamentale è lo +spinlock (``include/asm/spinlock.h``), un semplice *lock* che può essere +trattenuto solo da un processo: se non si può trattenere lo spinlock, allora +rimane in attesa attiva (in inglese *spinning*) finché non ci riesce. +Gli spinlock sono molto piccoli e rapidi, possono essere utilizzati ovunque. + +Il secondo tipo è il mutex (``include/linux/mutex.h``): è come uno spinlock, +ma potreste bloccarvi trattenendolo. Se non potete trattenere un mutex +il vostro processo si auto-sospenderà; verrà riattivato quando il mutex +verrà rilasciato. Questo significa che il processore potrà occuparsi d'altro +mentre il vostro processo è in attesa. Esistono molti casi in cui non potete +permettervi di sospendere un processo (vedere +:ref:`Quali funzioni possono essere chiamate in modo sicuro dalle interruzioni? <it_sleeping-things>`) +e quindi dovrete utilizzare gli spinlock. + +Nessuno di questi *lock* è ricorsivo: vedere +:ref:`Stallo: semplice ed avanzato <it_deadlock>` + +I *lock* e i kernel per sistemi monoprocessore +---------------------------------------------- + +Per i kernel compilati senza ``CONFIG_SMP`` e senza ``CONFIG_PREEMPT`` +gli spinlock non esistono. Questa è un'ottima scelta di progettazione: +quando nessun altro processo può essere eseguito in simultanea, allora +non c'è la necessità di avere un *lock*. + +Se il kernel è compilato senza ``CONFIG_SMP`` ma con ``CONFIG_PREEMPT``, +allora gli spinlock disabilitano la prelazione; questo è sufficiente a +prevenire le corse critiche. Nella maggior parte dei casi, possiamo considerare +la prelazione equivalente ad un sistema multi-processore senza preoccuparci +di trattarla indipendentemente. + +Dovreste verificare sempre la sincronizzazione con le opzioni ``CONFIG_SMP`` e +``CONFIG_PREEMPT`` abilitate, anche quando non avete un sistema +multi-processore, questo vi permetterà di identificare alcuni problemi +di sincronizzazione. + +Come vedremo di seguito, i mutex continuano ad esistere perché sono necessari +per la sincronizzazione fra processi in contesto utente. + +Sincronizzazione in contesto utente +----------------------------------- + +Se avete una struttura dati che verrà utilizzata solo dal contesto utente, +allora, per proteggerla, potete utilizzare un semplice mutex +(``include/linux/mutex.h``). Questo è il caso più semplice: inizializzate il +mutex; invocate :c:func:`mutex_lock_interruptible()` per trattenerlo e +:c:func:`mutex_unlock()` per rilasciarlo. C'è anche :c:func:`mutex_lock()` +ma questa dovrebbe essere evitata perché non ritorna in caso di segnali. + +Per esempio: ``net/netfilter/nf_sockopt.c`` permette la registrazione +di nuove chiamate per :c:func:`setsockopt()` e :c:func:`getsockopt()` +usando la funzione :c:func:`nf_register_sockopt()`. La registrazione e +la rimozione vengono eseguite solamente quando il modulo viene caricato +o scaricato (e durante l'avvio del sistema, qui non abbiamo concorrenza), +e la lista delle funzioni registrate viene consultata solamente quando +:c:func:`setsockopt()` o :c:func:`getsockopt()` sono sconosciute al sistema. +In questo caso ``nf_sockopt_mutex`` è perfetto allo scopo, in particolar modo +visto che setsockopt e getsockopt potrebbero dormire. + +Sincronizzazione fra il contesto utente e i softirq +--------------------------------------------------- + +Se un softirq condivide dati col contesto utente, avete due problemi. +Primo, il contesto utente corrente potrebbe essere interroto da un softirq, +e secondo, la sezione critica potrebbe essere eseguita da un altro +processore. Questo è quando :c:func:`spin_lock_bh()` +(``include/linux/spinlock.h``) viene utilizzato. Questo disabilita i softirq +sul processore e trattiene il *lock*. Invece, :c:func:`spin_unlock_bh()` fa +l'opposto. (Il suffisso '_bh' è un residuo storico che fa riferimento al +"Bottom Halves", il vecchio nome delle interruzioni software. In un mondo +perfetto questa funzione si chiamerebbe 'spin_lock_softirq()'). + +Da notare che in questo caso potete utilizzare anche :c:func:`spin_lock_irq()` +o :c:func:`spin_lock_irqsave()`, queste fermano anche le interruzioni hardware: +vedere :ref:`Contesto di interruzione hardware <it_hardirq-context>`. + +Questo funziona alla perfezione anche sui sistemi monoprocessore: gli spinlock +svaniscono e questa macro diventa semplicemente :c:func:`local_bh_disable()` +(``include/linux/interrupt.h``), la quale impedisce ai softirq d'essere +eseguiti. + +Sincronizzazione fra contesto utente e i tasklet +------------------------------------------------ + +Questo caso è uguale al precedente, un tasklet viene eseguito da un softirq. + +Sincronizzazione fra contesto utente e i timer +---------------------------------------------- + +Anche questo caso è uguale al precedente, un timer viene eseguito da un +softirq. +Dal punto di vista della sincronizzazione, tasklet e timer sono identici. + +Sincronizzazione fra tasklet e timer +------------------------------------ + +Qualche volta un tasklet od un timer potrebbero condividere i dati con +un altro tasklet o timer + +Lo stesso tasklet/timer +~~~~~~~~~~~~~~~~~~~~~~~ + +Dato che un tasklet non viene mai eseguito contemporaneamente su due +processori, non dovete preoccuparvi che sia rientrante (ovvero eseguito +più volte in contemporanea), perfino su sistemi multi-processore. + +Differenti tasklet/timer +~~~~~~~~~~~~~~~~~~~~~~~~ + +Se un altro tasklet/timer vuole condividere dati col vostro tasklet o timer, +allora avrete bisogno entrambe di :c:func:`spin_lock()` e +:c:func:`spin_unlock()`. Qui :c:func:`spin_lock_bh()` è inutile, siete già +in un tasklet ed avete la garanzia che nessun altro verrà eseguito sullo +stesso processore. + +Sincronizzazione fra softirq +---------------------------- + +Spesso un softirq potrebbe condividere dati con se stesso o un tasklet/timer. + +Lo stesso softirq +~~~~~~~~~~~~~~~~~ + +Lo stesso softirq può essere eseguito su un diverso processore: allo scopo +di migliorare le prestazioni potete utilizzare dati riservati ad ogni +processore (vedere :ref:`Dati per processore <it_per-cpu>`). Se siete arrivati +fino a questo punto nell'uso dei softirq, probabilmente tenete alla scalabilità +delle prestazioni abbastanza da giustificarne la complessità aggiuntiva. + +Dovete utilizzare :c:func:`spin_lock()` e :c:func:`spin_unlock()` per +proteggere i dati condivisi. + +Diversi Softirqs +~~~~~~~~~~~~~~~~ + +Dovete utilizzare :c:func:`spin_lock()` e :c:func:`spin_unlock()` per +proteggere i dati condivisi, che siano timer, tasklet, diversi softirq o +lo stesso o altri softirq: uno qualsiasi di essi potrebbe essere in esecuzione +su un diverso processore. + +.. _`it_hardirq-context`: + +Contesto di interruzione hardware +================================= + +Solitamente le interruzioni hardware comunicano con un tasklet o un softirq. +Spesso questo si traduce nel mettere in coda qualcosa da fare che verrà +preso in carico da un softirq. + +Sincronizzazione fra interruzioni hardware e softirq/tasklet +------------------------------------------------------------ + +Se un gestore di interruzioni hardware condivide dati con un softirq, allora +avrete due preoccupazioni. Primo, il softirq può essere interrotto da +un'interruzione hardware, e secondo, la sezione critica potrebbe essere +eseguita da un'interruzione hardware su un processore diverso. Questo è il caso +dove :c:func:`spin_lock_irq()` viene utilizzato. Disabilita le interruzioni +sul processore che l'esegue, poi trattiene il lock. :c:func:`spin_unlock_irq()` +fa l'opposto. + +Il gestore d'interruzione hardware non usa :c:func:`spin_lock_irq()` perché +i softirq non possono essere eseguiti quando il gestore d'interruzione hardware +è in esecuzione: per questo si può usare :c:func:`spin_lock()`, che è un po' +più veloce. L'unica eccezione è quando un altro gestore d'interruzioni +hardware utilizza lo stesso *lock*: :c:func:`spin_lock_irq()` impedirà a questo +secondo gestore di interrompere quello in esecuzione. + +Questo funziona alla perfezione anche sui sistemi monoprocessore: gli spinlock +svaniscono e questa macro diventa semplicemente :c:func:`local_irq_disable()` +(``include/asm/smp.h``), la quale impedisce a softirq/tasklet/BH d'essere +eseguiti. + +:c:func:`spin_lock_irqsave()` (``include/linux/spinlock.h``) è una variante che +salva lo stato delle interruzioni in una variabile, questa verrà poi passata +a :c:func:`spin_unlock_irqrestore()`. Questo significa che lo stesso codice +potrà essere utilizzato in un'interruzione hardware (dove le interruzioni sono +già disabilitate) e in un softirq (dove la disabilitazione delle interruzioni +è richiesta). + +Da notare che i softirq (e quindi tasklet e timer) sono eseguiti al ritorno +da un'interruzione hardware, quindi :c:func:`spin_lock_irq()` interrompe +anche questi. Tenuto conto di questo si può dire che +:c:func:`spin_lock_irqsave()` è la funzione di sincronizzazione più generica +e potente. + +Sincronizzazione fra due gestori d'interruzioni hardware +-------------------------------------------------------- + +Condividere dati fra due gestori di interruzione hardware è molto raro, ma se +succede, dovreste usare :c:func:`spin_lock_irqsave()`: è una specificità +dell'architettura il fatto che tutte le interruzioni vengano interrotte +quando si eseguono di gestori di interruzioni. + +Bigino della sincronizzazione +============================= + +Pete Zaitcev ci offre il seguente riassunto: + +- Se siete in un contesto utente (una qualsiasi chiamata di sistema) + e volete sincronizzarvi con altri processi, usate i mutex. Potete trattenere + il mutex e dormire (``copy_from_user*(`` o ``kmalloc(x,GFP_KERNEL)``). + +- Altrimenti (== i dati possono essere manipolati da un'interruzione) usate + :c:func:`spin_lock_irqsave()` e :c:func:`spin_unlock_irqrestore()`. + +- Evitate di trattenere uno spinlock per più di 5 righe di codice incluse + le chiamate a funzione (ad eccezione di quell per l'accesso come + :c:func:`readb()`). + +Tabella dei requisiti minimi +---------------------------- + +La tabella seguente illustra i requisiti **minimi** per la sincronizzazione fra +diversi contesti. In alcuni casi, lo stesso contesto può essere eseguito solo +da un processore per volta, quindi non ci sono requisiti per la +sincronizzazione (per esempio, un thread può essere eseguito solo su un +processore alla volta, ma se deve condividere dati con un altro thread, allora +la sincronizzazione è necessaria). + +Ricordatevi il suggerimento qui sopra: potete sempre usare +:c:func:`spin_lock_irqsave()`, che è un sovrainsieme di tutte le altre funzioni +per spinlock. + +============== ============= ============= ========= ========= ========= ========= ======= ======= ============== ============== +. IRQ Handler A IRQ Handler B Softirq A Softirq B Tasklet A Tasklet B Timer A Timer B User Context A User Context B +============== ============= ============= ========= ========= ========= ========= ======= ======= ============== ============== +IRQ Handler A None +IRQ Handler B SLIS None +Softirq A SLI SLI SL +Softirq B SLI SLI SL SL +Tasklet A SLI SLI SL SL None +Tasklet B SLI SLI SL SL SL None +Timer A SLI SLI SL SL SL SL None +Timer B SLI SLI SL SL SL SL SL None +User Context A SLI SLI SLBH SLBH SLBH SLBH SLBH SLBH None +User Context B SLI SLI SLBH SLBH SLBH SLBH SLBH SLBH MLI None +============== ============= ============= ========= ========= ========= ========= ======= ======= ============== ============== + +Table: Tabella dei requisiti per la sincronizzazione + ++--------+----------------------------+ +| SLIS | spin_lock_irqsave | ++--------+----------------------------+ +| SLI | spin_lock_irq | ++--------+----------------------------+ +| SL | spin_lock | ++--------+----------------------------+ +| SLBH | spin_lock_bh | ++--------+----------------------------+ +| MLI | mutex_lock_interruptible | ++--------+----------------------------+ + +Table: Legenda per la tabella dei requisiti per la sincronizzazione + +Le funzioni *trylock* +===================== + +Ci sono funzioni che provano a trattenere un *lock* solo una volta e +ritornano immediatamente comunicato il successo od il fallimento +dell'operazione. Posso essere usate quando non serve accedere ai dati +protetti dal *lock* quando qualche altro thread lo sta già facendo +trattenendo il *lock*. Potrete acquisire il *lock* più tardi se vi +serve accedere ai dati protetti da questo *lock*. + +La funzione :c:func:`spin_trylock()` non ritenta di acquisire il *lock*, +se ci riesce al primo colpo ritorna un valore diverso da zero, altrimenti +se fallisce ritorna 0. Questa funzione può essere utilizzata in un qualunque +contesto, ma come :c:func:`spin_lock()`: dovete disabilitare i contesti che +potrebbero interrompervi e quindi trattenere lo spinlock. + +La funzione :c:func:`mutex_trylock()` invece di sospendere il vostro processo +ritorna un valore diverso da zero se è possibile trattenere il lock al primo +colpo, altrimenti se fallisce ritorna 0. Nonostante non dorma, questa funzione +non può essere usata in modo sicuro in contesti di interruzione hardware o +software. + +Esempi più comuni +================= + +Guardiamo un semplice esempio: una memoria che associa nomi a numeri. +La memoria tiene traccia di quanto spesso viene utilizzato ogni oggetto; +quando è piena, l'oggetto meno usato viene eliminato. + +Tutto in contesto utente +------------------------ + +Nel primo esempio, supponiamo che tutte le operazioni avvengano in contesto +utente (in soldoni, da una chiamata di sistema), quindi possiamo dormire. +Questo significa che possiamo usare i mutex per proteggere la nostra memoria +e tutti gli oggetti che contiene. Ecco il codice:: + + #include <linux/list.h> + #include <linux/slab.h> + #include <linux/string.h> + #include <linux/mutex.h> + #include <asm/errno.h> + + struct object + { + struct list_head list; + int id; + char name[32]; + int popularity; + }; + + /* Protects the cache, cache_num, and the objects within it */ + static DEFINE_MUTEX(cache_lock); + static LIST_HEAD(cache); + static unsigned int cache_num = 0; + #define MAX_CACHE_SIZE 10 + + /* Must be holding cache_lock */ + static struct object *__cache_find(int id) + { + struct object *i; + + list_for_each_entry(i, &cache, list) + if (i->id == id) { + i->popularity++; + return i; + } + return NULL; + } + + /* Must be holding cache_lock */ + static void __cache_delete(struct object *obj) + { + BUG_ON(!obj); + list_del(&obj->list); + kfree(obj); + cache_num--; + } + + /* Must be holding cache_lock */ + static void __cache_add(struct object *obj) + { + list_add(&obj->list, &cache); + if (++cache_num > MAX_CACHE_SIZE) { + struct object *i, *outcast = NULL; + list_for_each_entry(i, &cache, list) { + if (!outcast || i->popularity < outcast->popularity) + outcast = i; + } + __cache_delete(outcast); + } + } + + int cache_add(int id, const char *name) + { + struct object *obj; + + if ((obj = kmalloc(sizeof(*obj), GFP_KERNEL)) == NULL) + return -ENOMEM; + + strlcpy(obj->name, name, sizeof(obj->name)); + obj->id = id; + obj->popularity = 0; + + mutex_lock(&cache_lock); + __cache_add(obj); + mutex_unlock(&cache_lock); + return 0; + } + + void cache_delete(int id) + { + mutex_lock(&cache_lock); + __cache_delete(__cache_find(id)); + mutex_unlock(&cache_lock); + } + + int cache_find(int id, char *name) + { + struct object *obj; + int ret = -ENOENT; + + mutex_lock(&cache_lock); + obj = __cache_find(id); + if (obj) { + ret = 0; + strcpy(name, obj->name); + } + mutex_unlock(&cache_lock); + return ret; + } + +Da notare che ci assicuriamo sempre di trattenere cache_lock quando +aggiungiamo, rimuoviamo od ispezioniamo la memoria: sia la struttura +della memoria che il suo contenuto sono protetti dal *lock*. Questo +caso è semplice dato che copiamo i dati dall'utente e non permettiamo +mai loro di accedere direttamente agli oggetti. + +C'è una piccola ottimizzazione qui: nella funzione :c:func:`cache_add()` +impostiamo i campi dell'oggetto prima di acquisire il *lock*. Questo è +sicuro perché nessun altro potrà accedervi finché non lo inseriremo +nella memoria. + +Accesso dal contesto utente +--------------------------- + +Ora consideriamo il caso in cui :c:func:`cache_find()` può essere invocata +dal contesto d'interruzione: sia hardware che software. Un esempio potrebbe +essere un timer che elimina oggetti dalla memoria. + +Qui di seguito troverete la modifica nel formato *patch*: le righe ``-`` +sono quelle rimosse, mentre quelle ``+`` sono quelle aggiunte. + +:: + + --- cache.c.usercontext 2003-12-09 13:58:54.000000000 +1100 + +++ cache.c.interrupt 2003-12-09 14:07:49.000000000 +1100 + @@ -12,7 +12,7 @@ + int popularity; + }; + + -static DEFINE_MUTEX(cache_lock); + +static DEFINE_SPINLOCK(cache_lock); + static LIST_HEAD(cache); + static unsigned int cache_num = 0; + #define MAX_CACHE_SIZE 10 + @@ -55,6 +55,7 @@ + int cache_add(int id, const char *name) + { + struct object *obj; + + unsigned long flags; + + if ((obj = kmalloc(sizeof(*obj), GFP_KERNEL)) == NULL) + return -ENOMEM; + @@ -63,30 +64,33 @@ + obj->id = id; + obj->popularity = 0; + + - mutex_lock(&cache_lock); + + spin_lock_irqsave(&cache_lock, flags); + __cache_add(obj); + - mutex_unlock(&cache_lock); + + spin_unlock_irqrestore(&cache_lock, flags); + return 0; + } + + void cache_delete(int id) + { + - mutex_lock(&cache_lock); + + unsigned long flags; + + + + spin_lock_irqsave(&cache_lock, flags); + __cache_delete(__cache_find(id)); + - mutex_unlock(&cache_lock); + + spin_unlock_irqrestore(&cache_lock, flags); + } + + int cache_find(int id, char *name) + { + struct object *obj; + int ret = -ENOENT; + + unsigned long flags; + + - mutex_lock(&cache_lock); + + spin_lock_irqsave(&cache_lock, flags); + obj = __cache_find(id); + if (obj) { + ret = 0; + strcpy(name, obj->name); + } + - mutex_unlock(&cache_lock); + + spin_unlock_irqrestore(&cache_lock, flags); + return ret; + } + +Da notare che :c:func:`spin_lock_irqsave()` disabiliterà le interruzioni +se erano attive, altrimenti non farà niente (quando siamo già in un contesto +d'interruzione); dunque queste funzioni possono essere chiamante in +sicurezza da qualsiasi contesto. + +Sfortunatamente, :c:func:`cache_add()` invoca :c:func:`kmalloc()` con +l'opzione ``GFP_KERNEL`` che è permessa solo in contesto utente. Ho supposto +che :c:func:`cache_add()` venga chiamata dal contesto utente, altrimenti +questa opzione deve diventare un parametro di :c:func:`cache_add()`. + +Exposing Objects Outside This File +---------------------------------- + +Se i vostri oggetti contengono più informazioni, potrebbe non essere +sufficiente copiare i dati avanti e indietro: per esempio, altre parti del +codice potrebbero avere un puntatore a questi oggetti piuttosto che cercarli +ogni volta. Questo introduce due problemi. + +Il primo problema è che utilizziamo ``cache_lock`` per proteggere gli oggetti: +dobbiamo renderlo dinamico così che il resto del codice possa usarlo. Questo +rende la sincronizzazione più complicata dato che non avviene più in un unico +posto. + +Il secondo problema è il problema del ciclo di vita: se un'altra struttura +mantiene un puntatore ad un oggetto, presumibilmente si aspetta che questo +puntatore rimanga valido. Sfortunatamente, questo è garantito solo mentre +si trattiene il *lock*, altrimenti qualcuno potrebbe chiamare +:c:func:`cache_delete()` o peggio, aggiungere un oggetto che riutilizza lo +stesso indirizzo. + +Dato che c'è un solo *lock*, non potete trattenerlo a vita: altrimenti +nessun altro potrà eseguire il proprio lavoro. + +La soluzione a questo problema è l'uso di un contatore di riferimenti: +chiunque punti ad un oggetto deve incrementare il contatore, e decrementarlo +quando il puntatore non viene più usato. Quando il contatore raggiunge lo zero +significa che non è più usato e l'oggetto può essere rimosso. + +Ecco il codice:: + + --- cache.c.interrupt 2003-12-09 14:25:43.000000000 +1100 + +++ cache.c.refcnt 2003-12-09 14:33:05.000000000 +1100 + @@ -7,6 +7,7 @@ + struct object + { + struct list_head list; + + unsigned int refcnt; + int id; + char name[32]; + int popularity; + @@ -17,6 +18,35 @@ + static unsigned int cache_num = 0; + #define MAX_CACHE_SIZE 10 + + +static void __object_put(struct object *obj) + +{ + + if (--obj->refcnt == 0) + + kfree(obj); + +} + + + +static void __object_get(struct object *obj) + +{ + + obj->refcnt++; + +} + + + +void object_put(struct object *obj) + +{ + + unsigned long flags; + + + + spin_lock_irqsave(&cache_lock, flags); + + __object_put(obj); + + spin_unlock_irqrestore(&cache_lock, flags); + +} + + + +void object_get(struct object *obj) + +{ + + unsigned long flags; + + + + spin_lock_irqsave(&cache_lock, flags); + + __object_get(obj); + + spin_unlock_irqrestore(&cache_lock, flags); + +} + + + /* Must be holding cache_lock */ + static struct object *__cache_find(int id) + { + @@ -35,6 +65,7 @@ + { + BUG_ON(!obj); + list_del(&obj->list); + + __object_put(obj); + cache_num--; + } + + @@ -63,6 +94,7 @@ + strlcpy(obj->name, name, sizeof(obj->name)); + obj->id = id; + obj->popularity = 0; + + obj->refcnt = 1; /* The cache holds a reference */ + + spin_lock_irqsave(&cache_lock, flags); + __cache_add(obj); + @@ -79,18 +111,15 @@ + spin_unlock_irqrestore(&cache_lock, flags); + } + + -int cache_find(int id, char *name) + +struct object *cache_find(int id) + { + struct object *obj; + - int ret = -ENOENT; + unsigned long flags; + + spin_lock_irqsave(&cache_lock, flags); + obj = __cache_find(id); + - if (obj) { + - ret = 0; + - strcpy(name, obj->name); + - } + + if (obj) + + __object_get(obj); + spin_unlock_irqrestore(&cache_lock, flags); + - return ret; + + return obj; + } + +Abbiamo incapsulato il contatore di riferimenti nelle tipiche funzioni +di 'get' e 'put'. Ora possiamo ritornare l'oggetto da :c:func:`cache_find()` +col vantaggio che l'utente può dormire trattenendo l'oggetto (per esempio, +:c:func:`copy_to_user()` per copiare il nome verso lo spazio utente). + +Un altro punto da notare è che ho detto che il contatore dovrebbe incrementarsi +per ogni puntatore ad un oggetto: quindi il contatore di riferimenti è 1 +quando l'oggetto viene inserito nella memoria. In altre versione il framework +non trattiene un riferimento per se, ma diventa più complicato. + +Usare operazioni atomiche per il contatore di riferimenti +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In sostanza, :c:type:`atomic_t` viene usato come contatore di riferimenti. +Ci sono un certo numbero di operazioni atomiche definite +in ``include/asm/atomic.h``: queste sono garantite come atomiche su qualsiasi +processore del sistema, quindi non sono necessari i *lock*. In questo caso è +più semplice rispetto all'uso degli spinlock, benché l'uso degli spinlock +sia più elegante per casi non banali. Le funzioni :c:func:`atomic_inc()` e +:c:func:`atomic_dec_and_test()` vengono usate al posto dei tipici operatori di +incremento e decremento, e i *lock* non sono più necessari per proteggere il +contatore stesso. + +:: + + --- cache.c.refcnt 2003-12-09 15:00:35.000000000 +1100 + +++ cache.c.refcnt-atomic 2003-12-11 15:49:42.000000000 +1100 + @@ -7,7 +7,7 @@ + struct object + { + struct list_head list; + - unsigned int refcnt; + + atomic_t refcnt; + int id; + char name[32]; + int popularity; + @@ -18,33 +18,15 @@ + static unsigned int cache_num = 0; + #define MAX_CACHE_SIZE 10 + + -static void __object_put(struct object *obj) + -{ + - if (--obj->refcnt == 0) + - kfree(obj); + -} + - + -static void __object_get(struct object *obj) + -{ + - obj->refcnt++; + -} + - + void object_put(struct object *obj) + { + - unsigned long flags; + - + - spin_lock_irqsave(&cache_lock, flags); + - __object_put(obj); + - spin_unlock_irqrestore(&cache_lock, flags); + + if (atomic_dec_and_test(&obj->refcnt)) + + kfree(obj); + } + + void object_get(struct object *obj) + { + - unsigned long flags; + - + - spin_lock_irqsave(&cache_lock, flags); + - __object_get(obj); + - spin_unlock_irqrestore(&cache_lock, flags); + + atomic_inc(&obj->refcnt); + } + + /* Must be holding cache_lock */ + @@ -65,7 +47,7 @@ + { + BUG_ON(!obj); + list_del(&obj->list); + - __object_put(obj); + + object_put(obj); + cache_num--; + } + + @@ -94,7 +76,7 @@ + strlcpy(obj->name, name, sizeof(obj->name)); + obj->id = id; + obj->popularity = 0; + - obj->refcnt = 1; /* The cache holds a reference */ + + atomic_set(&obj->refcnt, 1); /* The cache holds a reference */ + + spin_lock_irqsave(&cache_lock, flags); + __cache_add(obj); + @@ -119,7 +101,7 @@ + spin_lock_irqsave(&cache_lock, flags); + obj = __cache_find(id); + if (obj) + - __object_get(obj); + + object_get(obj); + spin_unlock_irqrestore(&cache_lock, flags); + return obj; + } + +Proteggere l'oggetto stesso +--------------------------- + +In questo esempio, assumiamo che gli oggetti (ad eccezione del contatore +di riferimenti) non cambino mai dopo la loro creazione. Se vogliamo permettere +al nome di cambiare abbiamo tre possibilità: + +- Si può togliere static da ``cache_lock`` e dire agli utenti che devono + trattenere il *lock* prima di modificare il nome di un oggetto. + +- Si può fornire una funzione :c:func:`cache_obj_rename()` che prende il + *lock* e cambia il nome per conto del chiamante; si dirà poi agli utenti + di usare questa funzione. + +- Si può decidere che ``cache_lock`` protegge solo la memoria stessa, ed + un altro *lock* è necessario per la protezione del nome. + +Teoricamente, possiamo avere un *lock* per ogni campo e per ogni oggetto. +In pratica, le varianti più comuni sono: + +- un *lock* che protegge l'infrastruttura (la lista ``cache`` di questo + esempio) e gli oggetti. Questo è quello che abbiamo fatto finora. + +- un *lock* che protegge l'infrastruttura (inclusi i puntatori alla lista + negli oggetti), e un *lock* nell'oggetto per proteggere il resto + dell'oggetto stesso. + +- *lock* multipli per proteggere l'infrastruttura (per esempio un *lock* + per ogni lista), possibilmente con un *lock* per oggetto. + +Qui di seguito un'implementazione con "un lock per oggetto": + +:: + + --- cache.c.refcnt-atomic 2003-12-11 15:50:54.000000000 +1100 + +++ cache.c.perobjectlock 2003-12-11 17:15:03.000000000 +1100 + @@ -6,11 +6,17 @@ + + struct object + { + + /* These two protected by cache_lock. */ + struct list_head list; + + int popularity; + + + atomic_t refcnt; + + + + /* Doesn't change once created. */ + int id; + + + + spinlock_t lock; /* Protects the name */ + char name[32]; + - int popularity; + }; + + static DEFINE_SPINLOCK(cache_lock); + @@ -77,6 +84,7 @@ + obj->id = id; + obj->popularity = 0; + atomic_set(&obj->refcnt, 1); /* The cache holds a reference */ + + spin_lock_init(&obj->lock); + + spin_lock_irqsave(&cache_lock, flags); + __cache_add(obj); + +Da notare che ho deciso che il contatore di popolarità dovesse essere +protetto da ``cache_lock`` piuttosto che dal *lock* dell'oggetto; questo +perché è logicamente parte dell'infrastruttura (come +:c:type:`struct list_head <list_head>` nell'oggetto). In questo modo, +in :c:func:`__cache_add()`, non ho bisogno di trattenere il *lock* di ogni +oggetto mentre si cerca il meno popolare. + +Ho anche deciso che il campo id è immutabile, quindi non ho bisogno di +trattenere il lock dell'oggetto quando si usa :c:func:`__cache_find()` +per leggere questo campo; il *lock* dell'oggetto è usato solo dal chiamante +che vuole leggere o scrivere il campo name. + +Inoltre, da notare che ho aggiunto un commento che descrive i dati che sono +protetti dal *lock*. Questo è estremamente importante in quanto descrive il +comportamento del codice, che altrimenti sarebbe di difficile comprensione +leggendo solamente il codice. E come dice Alan Cox: “Lock data, not code”. + +Problemi comuni +=============== + +.. _`it_deadlock`: + +Stallo: semplice ed avanzato +---------------------------- + +Esiste un tipo di baco dove un pezzo di codice tenta di trattenere uno +spinlock due volte: questo rimarrà in attesa attiva per sempre aspettando che +il *lock* venga rilasciato (in Linux spinlocks, rwlocks e mutex non sono +ricorsivi). +Questo è facile da diagnosticare: non è uno di quei problemi che ti tengono +sveglio 5 notti a parlare da solo. + +Un caso un pochino più complesso; immaginate d'avere una spazio condiviso +fra un softirq ed il contesto utente. Se usate :c:func:`spin_lock()` per +proteggerlo, il contesto utente potrebbe essere interrotto da un softirq +mentre trattiene il lock, da qui il softirq rimarrà in attesa attiva provando +ad acquisire il *lock* già trattenuto nel contesto utente. + +Questi casi sono chiamati stalli (*deadlock*), e come mostrato qui sopra, +può succedere anche con un solo processore (Ma non sui sistemi +monoprocessore perché gli spinlock spariscano quando il kernel è compilato +con ``CONFIG_SMP``\ =n. Nonostante ciò, nel secondo caso avrete comunque +una corruzione dei dati). + +Questi casi sono facili da diagnosticare; sui sistemi multi-processore +il supervisione (*watchdog*) o l'opzione di compilazione ``DEBUG_SPINLOCK`` +(``include/linux/spinlock.h``) permettono di scovare immediatamente quando +succedono. + +Esiste un caso più complesso che è conosciuto come l'abbraccio della morte; +questo coinvolge due o più *lock*. Diciamo che avete un vettore di hash in cui +ogni elemento è uno spinlock a cui è associata una lista di elementi con lo +stesso hash. In un gestore di interruzioni software, dovete modificare un +oggetto e spostarlo su un altro hash; quindi dovrete trattenete lo spinlock +del vecchio hash e di quello nuovo, quindi rimuovere l'oggetto dal vecchio ed +inserirlo nel nuovo. + +Qui abbiamo due problemi. Primo, se il vostro codice prova a spostare un +oggetto all'interno della stessa lista, otterrete uno stallo visto che +tenterà di trattenere lo stesso *lock* due volte. Secondo, se la stessa +interruzione software su un altro processore sta tentando di spostare +un altro oggetto nella direzione opposta, potrebbe accadere quanto segue: + ++---------------------------------+---------------------------------+ +| CPU 1 | CPU 2 | ++=================================+=================================+ +| Trattiene *lock* A -> OK | Trattiene *lock* B -> OK | ++---------------------------------+---------------------------------+ +| Trattiene *lock* B -> attesa | Trattiene *lock* A -> attesa | ++---------------------------------+---------------------------------+ + +Table: Conseguenze + +Entrambe i processori rimarranno in attesa attiva sul *lock* per sempre, +aspettando che l'altro lo rilasci. Sembra e puzza come un blocco totale. + +Prevenire gli stalli +-------------------- + +I libri di testo vi diranno che se trattenete i *lock* sempre nello stesso +ordine non avrete mai un simile stallo. La pratica vi dirà che questo +approccio non funziona all'ingrandirsi del sistema: quando creo un nuovo +*lock* non ne capisco abbastanza del kernel per dire in quale dei 5000 *lock* +si incastrerà. + +I *lock* migliori sono quelli incapsulati: non vengono esposti nei file di +intestazione, e non vengono mai trattenuti fuori dallo stesso file. Potete +rileggere questo codice e vedere che non ci sarà mai uno stallo perché +non tenterà mai di trattenere un altro *lock* quando lo ha già. +Le persone che usano il vostro codice non devono nemmeno sapere che voi +state usando dei *lock*. + +Un classico problema deriva dall'uso di *callback* e di *hook*: se li +chiamate mentre trattenete un *lock*, rischiate uno stallo o un abbraccio +della morte (chi lo sa cosa farà una *callback*?). + +Ossessiva prevenzione degli stalli +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Gli stalli sono un problema, ma non così terribile come la corruzione dei dati. +Un pezzo di codice trattiene un *lock* di lettura, cerca in una lista, +fallisce nel trovare quello che vuole, quindi rilascia il *lock* di lettura, +trattiene un *lock* di scrittura ed inserisce un oggetto; questo genere di +codice presenta una corsa critica. + +Se non riuscite a capire il perché, per favore state alla larga dal mio +codice. + +corsa fra temporizzatori: un passatempo del kernel +-------------------------------------------------- + +I temporizzatori potrebbero avere dei problemi con le corse critiche. +Considerate una collezione di oggetti (liste, hash, eccetera) dove ogni oggetto +ha un temporizzatore che sta per distruggerlo. + +Se volete eliminare l'intera collezione (diciamo quando rimuovete un modulo), +potreste fare come segue:: + + /* THIS CODE BAD BAD BAD BAD: IF IT WAS ANY WORSE IT WOULD USE + HUNGARIAN NOTATION */ + spin_lock_bh(&list_lock); + + while (list) { + struct foo *next = list->next; + del_timer(&list->timer); + kfree(list); + list = next; + } + + spin_unlock_bh(&list_lock); + +Primo o poi, questo esploderà su un sistema multiprocessore perché un +temporizzatore potrebbe essere già partiro prima di :c:func:`spin_lock_bh()`, +e prenderà il *lock* solo dopo :c:func:`spin_unlock_bh()`, e cercherà +di eliminare il suo oggetto (che però è già stato eliminato). + +Questo può essere evitato controllando il valore di ritorno di +:c:func:`del_timer()`: se ritorna 1, il temporizzatore è stato già +rimosso. Se 0, significa (in questo caso) che il temporizzatore è in +esecuzione, quindi possiamo fare come segue:: + + retry: + spin_lock_bh(&list_lock); + + while (list) { + struct foo *next = list->next; + if (!del_timer(&list->timer)) { + /* Give timer a chance to delete this */ + spin_unlock_bh(&list_lock); + goto retry; + } + kfree(list); + list = next; + } + + spin_unlock_bh(&list_lock); + +Un altro problema è l'eliminazione dei temporizzatori che si riavviano +da soli (chiamando :c:func:`add_timer()` alla fine della loro esecuzione). +Dato che questo è un problema abbastanza comune con una propensione +alle corse critiche, dovreste usare :c:func:`del_timer_sync()` +(``include/linux/timer.h``) per gestire questo caso. Questa ritorna il +numero di volte che il temporizzatore è stato interrotto prima che +fosse in grado di fermarlo senza che si riavviasse. + +Velocità della sincronizzazione +=============================== + +Ci sono tre cose importanti da tenere in considerazione quando si valuta +la velocità d'esecuzione di un pezzo di codice che necessita di +sincronizzazione. La prima è la concorrenza: quante cose rimangono in attesa +mentre qualcuno trattiene un *lock*. La seconda è il tempo necessario per +acquisire (senza contese) e rilasciare un *lock*. La terza è di usare meno +*lock* o di più furbi. Immagino che i *lock* vengano usati regolarmente, +altrimenti, non sareste interessati all'efficienza. + +La concorrenza dipende da quanto a lungo un *lock* è trattenuto: dovreste +trattenere un *lock* solo il tempo minimo necessario ma non un istante in più. +Nella memoria dell'esempio precedente, creiamo gli oggetti senza trattenere +il *lock*, poi acquisiamo il *lock* quando siamo pronti per inserirlo nella +lista. + +Il tempo di acquisizione di un *lock* dipende da quanto danno fa +l'operazione sulla *pipeline* (ovvero stalli della *pipeline*) e quant'è +probabile che il processore corrente sia stato anche l'ultimo ad acquisire +il *lock* (in pratica, il *lock* è nella memoria cache del processore +corrente?): su sistemi multi-processore questa probabilità precipita +rapidamente. Consideriamo un processore Intel Pentium III a 700Mhz: questo +esegue un'istruzione in 0.7ns, un incremento atomico richiede 58ns, acquisire +un *lock* che è nella memoria cache del processore richiede 160ns, e un +trasferimento dalla memoria cache di un altro processore richiede altri +170/360ns (Leggetevi l'articolo di Paul McKenney's `Linux Journal RCU +article <http://www.linuxjournal.com/article.php?sid=6993>`__). + +Questi due obiettivi sono in conflitto: trattenere un *lock* per il minor +tempo possibile potrebbe richiedere la divisione in più *lock* per diverse +parti (come nel nostro ultimo esempio con un *lock* per ogni oggetto), +ma questo aumenta il numero di acquisizioni di *lock*, ed il risultato +spesso è che tutto è più lento che con un singolo *lock*. Questo è un altro +argomento in favore della semplicità quando si parla di sincronizzazione. + +Il terzo punto è discusso di seguito: ci sono alcune tecniche per ridurre +il numero di sincronizzazioni che devono essere fatte. + +Read/Write Lock Variants +------------------------ + +Sia gli spinlock che i mutex hanno una variante per la lettura/scrittura +(read/write): ``rwlock_t`` e :c:type:`struct rw_semaphore <rw_semaphore>`. +Queste dividono gli utenti in due categorie: i lettori e gli scrittori. +Se state solo leggendo i dati, potete acquisire il *lock* di lettura, ma +per scrivere avrete bisogno del *lock* di scrittura. Molti possono trattenere +il *lock* di lettura, ma solo uno scrittore alla volta può trattenere +quello di scrittura. + +Se il vostro codice si divide chiaramente in codice per lettori e codice +per scrittori (come nel nostro esempio), e il *lock* dei lettori viene +trattenuto per molto tempo, allora l'uso di questo tipo di *lock* può aiutare. +Questi sono leggermente più lenti rispetto alla loro versione normale, quindi +nella pratica l'uso di ``rwlock_t`` non ne vale la pena. + +Evitare i *lock*: Read Copy Update +-------------------------------------------- + +Esiste un metodo di sincronizzazione per letture e scritture detto +Read Copy Update. Con l'uso della tecnica RCU, i lettori possono scordarsi +completamente di trattenere i *lock*; dato che nel nostro esempio ci +aspettiamo d'avere più lettore che scrittori (altrimenti questa memoria +sarebbe uno spreco) possiamo dire che questo meccanismo permette +un'ottimizzazione. + +Come facciamo a sbarazzarci dei *lock* di lettura? Sbarazzarsi dei *lock* di +lettura significa che uno scrittore potrebbe cambiare la lista sotto al naso +dei lettori. Questo è abbastanza semplice: possiamo leggere una lista +concatenata se lo scrittore aggiunge elementi alla fine e con certe +precauzioni. Per esempio, aggiungendo ``new`` ad una lista concatenata +chiamata ``list``:: + + new->next = list->next; + wmb(); + list->next = new; + +La funzione :c:func:`wmb()` è una barriera di sincronizzazione delle +scritture. Questa garantisce che la prima operazione (impostare l'elemento +``next`` del nuovo elemento) venga completata e vista da tutti i processori +prima che venga eseguita la seconda operazione (che sarebbe quella di mettere +il nuovo elemento nella lista). Questo è importante perché i moderni +compilatori ed i moderni processori possono, entrambe, riordinare le istruzioni +se non vengono istruiti altrimenti: vogliamo che i lettori non vedano +completamente il nuovo elemento; oppure che lo vedano correttamente e quindi +il puntatore ``next`` deve puntare al resto della lista. + +Fortunatamente, c'è una funzione che fa questa operazione sulle liste +:c:type:`struct list_head <list_head>`: :c:func:`list_add_rcu()` +(``include/linux/list.h``). + +Rimuovere un elemento dalla lista è anche più facile: sostituiamo il puntatore +al vecchio elemento con quello del suo successore, e i lettori vedranno +l'elemento o lo salteranno. + +:: + + list->next = old->next; + +La funzione :c:func:`list_del_rcu()` (``include/linux/list.h``) fa esattamente +questo (la versione normale corrompe il vecchio oggetto, e non vogliamo che +accada). + +Anche i lettori devono stare attenti: alcuni processori potrebbero leggere +attraverso il puntatore ``next`` il contenuto dell'elemento successivo +troppo presto, ma non accorgersi che il contenuto caricato è sbagliato quando +il puntatore ``next`` viene modificato alla loro spalle. Ancora una volta +c'è una funzione che viene in vostro aiuto :c:func:`list_for_each_entry_rcu()` +(``include/linux/list.h``). Ovviamente, gli scrittori possono usare +:c:func:`list_for_each_entry()` dato che non ci possono essere due scrittori +in contemporanea. + +Il nostro ultimo dilemma è il seguente: quando possiamo realmente distruggere +l'elemento rimosso? Ricordate, un lettore potrebbe aver avuto accesso a questo +elemento proprio ora: se eliminiamo questo elemento ed il puntatore ``next`` +cambia, il lettore salterà direttamente nella spazzatura e scoppierà. Dobbiamo +aspettare finché tutti i lettori che stanno attraversando la lista abbiano +finito. Utilizziamo :c:func:`call_rcu()` per registrare una funzione di +richiamo che distrugga l'oggetto quando tutti i lettori correnti hanno +terminato. In alternative, potrebbe essere usata la funzione +:c:func:`synchronize_rcu()` che blocca l'esecuzione finché tutti i lettori +non terminano di ispezionare la lista. + +Ma come fa l'RCU a sapere quando i lettori sono finiti? Il meccanismo è +il seguente: innanzi tutto i lettori accedono alla lista solo fra la coppia +:c:func:`rcu_read_lock()`/:c:func:`rcu_read_unlock()` che disabilita la +prelazione così che i lettori non vengano sospesi mentre stanno leggendo +la lista. + +Poi, l'RCU aspetta finché tutti i processori non abbiano dormito almeno +una volta; a questo punto, dato che i lettori non possono dormire, possiamo +dedurre che un qualsiasi lettore che abbia consultato la lista durante la +rimozione abbia già terminato, quindi la *callback* viene eseguita. Il vero +codice RCU è un po' più ottimizzato di così, ma questa è l'idea di fondo. + +:: + + --- cache.c.perobjectlock 2003-12-11 17:15:03.000000000 +1100 + +++ cache.c.rcupdate 2003-12-11 17:55:14.000000000 +1100 + @@ -1,15 +1,18 @@ + #include <linux/list.h> + #include <linux/slab.h> + #include <linux/string.h> + +#include <linux/rcupdate.h> + #include <linux/mutex.h> + #include <asm/errno.h> + + struct object + { + - /* These two protected by cache_lock. */ + + /* This is protected by RCU */ + struct list_head list; + int popularity; + + + struct rcu_head rcu; + + + atomic_t refcnt; + + /* Doesn't change once created. */ + @@ -40,7 +43,7 @@ + { + struct object *i; + + - list_for_each_entry(i, &cache, list) { + + list_for_each_entry_rcu(i, &cache, list) { + if (i->id == id) { + i->popularity++; + return i; + @@ -49,19 +52,25 @@ + return NULL; + } + + +/* Final discard done once we know no readers are looking. */ + +static void cache_delete_rcu(void *arg) + +{ + + object_put(arg); + +} + + + /* Must be holding cache_lock */ + static void __cache_delete(struct object *obj) + { + BUG_ON(!obj); + - list_del(&obj->list); + - object_put(obj); + + list_del_rcu(&obj->list); + cache_num--; + + call_rcu(&obj->rcu, cache_delete_rcu); + } + + /* Must be holding cache_lock */ + static void __cache_add(struct object *obj) + { + - list_add(&obj->list, &cache); + + list_add_rcu(&obj->list, &cache); + if (++cache_num > MAX_CACHE_SIZE) { + struct object *i, *outcast = NULL; + list_for_each_entry(i, &cache, list) { + @@ -104,12 +114,11 @@ + struct object *cache_find(int id) + { + struct object *obj; + - unsigned long flags; + + - spin_lock_irqsave(&cache_lock, flags); + + rcu_read_lock(); + obj = __cache_find(id); + if (obj) + object_get(obj); + - spin_unlock_irqrestore(&cache_lock, flags); + + rcu_read_unlock(); + return obj; + } + +Da notare che i lettori modificano il campo popularity nella funzione +:c:func:`__cache_find()`, e ora non trattiene alcun *lock*. Una soluzione +potrebbe essere quella di rendere la variabile ``atomic_t``, ma per l'uso +che ne abbiamo fatto qui, non ci interessano queste corse critiche perché un +risultato approssimativo è comunque accettabile, quindi non l'ho cambiato. + +Il risultato è che la funzione :c:func:`cache_find()` non ha bisogno di alcuna +sincronizzazione con le altre funzioni, quindi è veloce su un sistema +multi-processore tanto quanto lo sarebbe su un sistema mono-processore. + +Esiste un'ulteriore ottimizzazione possibile: vi ricordate il codice originale +della nostra memoria dove non c'erano contatori di riferimenti e il chiamante +semplicemente tratteneva il *lock* prima di accedere ad un oggetto? Questo è +ancora possibile: se trattenete un *lock* nessuno potrà cancellare l'oggetto, +quindi non avete bisogno di incrementare e decrementare il contatore di +riferimenti. + +Ora, dato che il '*lock* di lettura' di un RCU non fa altro che disabilitare +la prelazione, un chiamante che ha sempre la prelazione disabilitata fra le +chiamate :c:func:`cache_find()` e :c:func:`object_put()` non necessita +di incrementare e decrementare il contatore di riferimenti. Potremmo +esporre la funzione :c:func:`__cache_find()` dichiarandola non-static, +e quel chiamante potrebbe usare direttamente questa funzione. + +Il beneficio qui sta nel fatto che il contatore di riferimenti no +viene scritto: l'oggetto non viene alterato in alcun modo e quindi diventa +molto più veloce su sistemi molti-processore grazie alla loro memoria cache. + +.. _`it_per-cpu`: + +Dati per processore +------------------- + +Un'altra tecnica comunemente usata per evitare la sincronizzazione è quella +di duplicare le informazioni per ogni processore. Per esempio, se volete +avere un contatore di qualcosa, potreste utilizzare uno spinlock ed un +singolo contatore. Facile e pulito. + +Se questo dovesse essere troppo lento (solitamente non lo è, ma se avete +dimostrato che lo è devvero), potreste usare un contatore per ogni processore +e quindi non sarebbe più necessaria la mutua esclusione. Vedere +:c:func:`DEFINE_PER_CPU()`, :c:func:`get_cpu_var()` e :c:func:`put_cpu_var()` +(``include/linux/percpu.h``). + +Il tipo di dato ``local_t``, la funzione :c:func:`cpu_local_inc()` e tutte +le altre funzioni associate, sono di particolare utilità per semplici contatori +per-processore; su alcune architetture sono anche più efficienti +(``include/asm/local.h``). + +Da notare che non esiste un modo facile ed affidabile per ottenere il valore +di un simile contatore senza introdurre altri *lock*. In alcuni casi questo +non è un problema. + +Dati che sono usati prevalentemente dai gestori d'interruzioni +-------------------------------------------------------------- + +Se i dati vengono utilizzati sempre dallo stesso gestore d'interruzioni, +allora i *lock* non vi servono per niente: il kernel già vi garantisce che +il gestore d'interruzione non verrà eseguito in contemporanea su diversi +processori. + +Manfred Spraul fa notare che potreste comunque comportarvi così anche +se i dati vengono occasionalmente utilizzati da un contesto utente o +da un'interruzione software. Il gestore d'interruzione non utilizza alcun +*lock*, e tutti gli altri accessi verranno fatti così:: + + spin_lock(&lock); + disable_irq(irq); + ... + enable_irq(irq); + spin_unlock(&lock); + +La funzione :c:func:`disable_irq()` impedisce al gestore d'interruzioni +d'essere eseguito (e aspetta che finisca nel caso fosse in esecuzione su +un altro processore). Lo spinlock, invece, previene accessi simultanei. +Naturalmente, questo è più lento della semplice chiamata +:c:func:`spin_lock_irq()`, quindi ha senso solo se questo genere di accesso +è estremamente raro. + +.. _`it_sleeping-things`: + +Quali funzioni possono essere chiamate in modo sicuro dalle interruzioni? +========================================================================= + +Molte funzioni del kernel dormono (in sostanza, chiamano ``schedule()``) +direttamente od indirettamente: non potete chiamarle se trattenere uno +spinlock o avete la prelazione disabilitata, mai. Questo significa che +dovete necessariamente essere nel contesto utente: chiamarle da un +contesto d'interruzione è illegale. + +Alcune funzioni che dormono +--------------------------- + +Le più comuni sono elencate qui di seguito, ma solitamente dovete leggere +il codice per scoprire se altre chiamate sono sicure. Se chiunque altro +le chiami dorme, allora dovreste poter dormire anche voi. In particolar +modo, le funzioni di registrazione e deregistrazione solitamente si +aspettano d'essere chiamante da un contesto utente e quindi che possono +dormire. + +- Accessi allo spazio utente: + + - :c:func:`copy_from_user()` + + - :c:func:`copy_to_user()` + + - :c:func:`get_user()` + + - :c:func:`put_user()` + +- :c:func:`kmalloc(GFP_KERNEL) <kmalloc>` + +- :c:func:`mutex_lock_interruptible()` and + :c:func:`mutex_lock()` + + C'è anche :c:func:`mutex_trylock()` che però non dorme. + Comunque, non deve essere usata in un contesto d'interruzione dato + che la sua implementazione non è sicura in quel contesto. + Anche :c:func:`mutex_unlock()` non dorme mai. Non può comunque essere + usata in un contesto d'interruzione perché un mutex deve essere rilasciato + dallo stesso processo che l'ha acquisito. + +Alcune funzioni che non dormono +------------------------------- + +Alcune funzioni possono essere chiamate tranquillamente da qualsiasi +contesto, o trattenendo un qualsiasi *lock*. + +- :c:func:`printk()` + +- :c:func:`kfree()` + +- :c:func:`add_timer()` e :c:func:`del_timer()` + +Riferimento per l'API dei Mutex +=============================== + +.. kernel-doc:: include/linux/mutex.h + :internal: + +.. kernel-doc:: kernel/locking/mutex.c + :export: + +Riferimento per l'API dei Futex +=============================== + +.. kernel-doc:: kernel/futex.c + :internal: + +Approfondimenti +=============== + +- ``Documentation/locking/spinlocks.txt``: la guida di Linus Torvalds agli + spinlock del kernel. + +- Unix Systems for Modern Architectures: Symmetric Multiprocessing and + Caching for Kernel Programmers. + + L'introduzione alla sincronizzazione a livello di kernel di Curt Schimmel + è davvero ottima (non è scritta per Linux, ma approssimativamente si adatta + a tutte le situazioni). Il libro è costoso, ma vale ogni singolo spicciolo + per capire la sincronizzazione nei sistemi multi-processore. + [ISBN: 0201633388] + +Ringraziamenti +============== + +Grazie a Telsa Gwynne per aver formattato questa guida in DocBook, averla +pulita e aggiunto un po' di stile. + +Grazie a Martin Pool, Philipp Rumpf, Stephen Rothwell, Paul Mackerras, +Ruedi Aschwanden, Alan Cox, Manfred Spraul, Tim Waugh, Pete Zaitcev, +James Morris, Robert Love, Paul McKenney, John Ashby per aver revisionato, +corretto, maledetto e commentato. + +Grazie alla congrega per non aver avuto alcuna influenza su questo documento. + +Glossario +========= + +prelazione + Prima del kernel 2.5, o quando ``CONFIG_PREEMPT`` non è impostato, i processi + in contesto utente non si avvicendano nell'esecuzione (in pratica, il + processo userà il processore fino al proprio termine, a meno che non ci siano + delle interruzioni). Con l'aggiunta di ``CONFIG_PREEMPT`` nella versione + 2.5.4 questo è cambiato: quando si è in contesto utente, processi con una + priorità maggiore possono subentrare nell'esecuzione: gli spinlock furono + cambiati per disabilitare la prelazioni, anche su sistemi monoprocessore. + +bh + Bottom Half: per ragioni storiche, le funzioni che contengono '_bh' nel + loro nome ora si riferiscono a qualsiasi interruzione software; per esempio, + :c:func:`spin_lock_bh()` blocca qualsiasi interuzione software sul processore + corrente. I *Bottom Halves* sono deprecati, e probabilmente verranno + sostituiti dai tasklet. In un dato momento potrà esserci solo un + *bottom half* in esecuzione. + +contesto d'interruzione + Non è il contesto utente: qui si processano le interruzioni hardware e + software. La macro :c:func:`in_interrupt()` ritorna vero. + +contesto utente + Il kernel che esegue qualcosa per conto di un particolare processo (per + esempio una chiamata di sistema) o di un thread del kernel. Potete + identificare il processo con la macro ``current``. Da non confondere + con lo spazio utente. Può essere interrotto sia da interruzioni software + che hardware. + +interruzione hardware + Richiesta di interruzione hardware. :c:func:`in_irq()` ritorna vero in un + gestore d'interruzioni hardware. + +interruzione software / softirq + Gestore di interruzioni software: :c:func:`in_irq()` ritorna falso; + :c:func:`in_softirq()` ritorna vero. I tasklet e le softirq sono entrambi + considerati 'interruzioni software'. + + In soldoni, un softirq è uno delle 32 interruzioni software che possono + essere eseguite su più processori in contemporanea. A volte si usa per + riferirsi anche ai tasklet (in pratica tutte le interruzioni software). + +monoprocessore / UP + (Uni-Processor) un solo processore, ovvero non è SMP. (``CONFIG_SMP=n``). + +multi-processore / SMP + (Symmetric Multi-Processor) kernel compilati per sistemi multi-processore + (``CONFIG_SMP=y``). + +spazio utente + Un processo che esegue il proprio codice fuori dal kernel. + +tasklet + Un'interruzione software registrabile dinamicamente che ha la garanzia + d'essere eseguita solo su un processore alla volta. + +timer + Un'interruzione software registrabile dinamicamente che viene eseguita + (circa) in un determinato momento. Quando è in esecuzione è come un tasklet + (infatti, sono chiamati da ``TIMER_SOFTIRQ``). diff --git a/Documentation/translations/zh_CN/oops-tracing.txt b/Documentation/translations/zh_CN/oops-tracing.txt index 41ab53c..a893f04 100644 --- a/Documentation/translations/zh_CN/oops-tracing.txt +++ b/Documentation/translations/zh_CN/oops-tracing.txt @@ -1,4 +1,4 @@ -Chinese translated version of Documentation/admin-guide/oops-tracing.rst +Chinese translated version of Documentation/admin-guide/bug-hunting.rst If you have any comment or update to the content, please contact the original document maintainer directly. However, if you have a problem @@ -8,7 +8,7 @@ or if there is a problem with the translation. Chinese maintainer: Dave Young <hidave.darkstar@gmail.com> --------------------------------------------------------------------- -Documentation/admin-guide/oops-tracing.rst 的中文翻译 +Documentation/admin-guide/bug-hunting.rst 的中文翻译 如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文 交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 diff --git a/MAINTAINERS b/MAINTAINERS index 634039e..2b38074 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4406,6 +4406,12 @@ X: Documentation/spi X: Documentation/media T: git git://git.lwn.net/linux.git docs-next +DOCUMENTATION/ITALIAN +M: Federico Vaga <federico.vaga@vaga.pv.it> +L: linux-doc@vger.kernel.org +S: Maintained +F: Documentation/translations/it_IT + DONGWOON DW9714 LENS VOICE COIL DRIVER M: Sakari Ailus <sakari.ailus@linux.intel.com> L: linux-media@vger.kernel.org @@ -7034,7 +7040,7 @@ M: Guenter Roeck <linux@roeck-us.net> L: linux-hwmon@vger.kernel.org S: Maintained F: Documentation/hwmon/ina209 -F: Documentation/devicetree/bindings/i2c/ina209.txt +F: Documentation/devicetree/bindings/hwmon/ina2xx.txt F: drivers/hwmon/ina209.c INA2XX HARDWARE MONITOR DRIVER diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h index 7942a96..4251519 100644 --- a/include/linux/bootmem.h +++ b/include/linux/bootmem.h @@ -27,9 +27,20 @@ extern unsigned long max_pfn; extern unsigned long long max_possible_pfn; #ifndef CONFIG_NO_BOOTMEM -/* - * node_bootmem_map is a map pointer - the bits represent all physical - * memory pages (including holes) on the node. +/** + * struct bootmem_data - per-node information used by the bootmem allocator + * @node_min_pfn: the starting physical address of the node's memory + * @node_low_pfn: the end physical address of the directly addressable memory + * @node_bootmem_map: is a bitmap pointer - the bits represent all physical + * memory pages (including holes) on the node. + * @last_end_off: the offset within the page of the end of the last allocation; + * if 0, the page used is full + * @hint_idx: the PFN of the page used with the last allocation; + * together with using this with the @last_end_offset field, + * a test can be made to see if allocations can be merged + * with the page used for the last allocation rather than + * using up a full new page. + * @list: list entry in the linked list ordered by the memory addresses */ typedef struct bootmem_data { unsigned long node_min_pfn; diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 91ed234..39745b8 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -14,7 +14,7 @@ #include <linux/errno.h> -/* see Documentation/gpio/gpio-legacy.txt */ +/* see Documentation/driver-api/gpio/legacy.rst */ /* make these flag values available regardless of GPIO kconfig options */ #define GPIOF_DIR_OUT (0 << 0) diff --git a/include/linux/memblock.h b/include/linux/memblock.h index ca59883..5169205 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -20,31 +20,60 @@ #define INIT_MEMBLOCK_REGIONS 128 #define INIT_PHYSMEM_REGIONS 4 -/* Definition of memblock flags. */ -enum { +/** + * enum memblock_flags - definition of memory region attributes + * @MEMBLOCK_NONE: no special request + * @MEMBLOCK_HOTPLUG: hotpluggable region + * @MEMBLOCK_MIRROR: mirrored region + * @MEMBLOCK_NOMAP: don't add to kernel direct mapping + */ +enum memblock_flags { MEMBLOCK_NONE = 0x0, /* No special request */ MEMBLOCK_HOTPLUG = 0x1, /* hotpluggable region */ MEMBLOCK_MIRROR = 0x2, /* mirrored region */ MEMBLOCK_NOMAP = 0x4, /* don't add to kernel direct mapping */ }; +/** + * struct memblock_region - represents a memory region + * @base: physical address of the region + * @size: size of the region + * @flags: memory region attributes + * @nid: NUMA node id + */ struct memblock_region { phys_addr_t base; phys_addr_t size; - unsigned long flags; + enum memblock_flags flags; #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP int nid; #endif }; +/** + * struct memblock_type - collection of memory regions of certain type + * @cnt: number of regions + * @max: size of the allocated array + * @total_size: size of all regions + * @regions: array of regions + * @name: the memory type symbolic name + */ struct memblock_type { - unsigned long cnt; /* number of regions */ - unsigned long max; /* size of the allocated array */ - phys_addr_t total_size; /* size of all regions */ + unsigned long cnt; + unsigned long max; + phys_addr_t total_size; struct memblock_region *regions; char *name; }; +/** + * struct memblock - memblock allocator metadata + * @bottom_up: is bottom up direction? + * @current_limit: physical address of the current allocation limit + * @memory: usabe memory regions + * @reserved: reserved memory regions + * @physmem: all physical memory + */ struct memblock { bool bottom_up; /* is bottom up direction? */ phys_addr_t current_limit; @@ -72,7 +101,7 @@ void memblock_discard(void); phys_addr_t memblock_find_in_range_node(phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end, - int nid, ulong flags); + int nid, enum memblock_flags flags); phys_addr_t memblock_find_in_range(phys_addr_t start, phys_addr_t end, phys_addr_t size, phys_addr_t align); void memblock_allow_resize(void); @@ -89,19 +118,19 @@ int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size); int memblock_mark_mirror(phys_addr_t base, phys_addr_t size); int memblock_mark_nomap(phys_addr_t base, phys_addr_t size); int memblock_clear_nomap(phys_addr_t base, phys_addr_t size); -ulong choose_memblock_flags(void); +enum memblock_flags choose_memblock_flags(void); /* Low level functions */ int memblock_add_range(struct memblock_type *type, phys_addr_t base, phys_addr_t size, - int nid, unsigned long flags); + int nid, enum memblock_flags flags); -void __next_mem_range(u64 *idx, int nid, ulong flags, +void __next_mem_range(u64 *idx, int nid, enum memblock_flags flags, struct memblock_type *type_a, struct memblock_type *type_b, phys_addr_t *out_start, phys_addr_t *out_end, int *out_nid); -void __next_mem_range_rev(u64 *idx, int nid, ulong flags, +void __next_mem_range_rev(u64 *idx, int nid, enum memblock_flags flags, struct memblock_type *type_a, struct memblock_type *type_b, phys_addr_t *out_start, phys_addr_t *out_end, int *out_nid); @@ -239,7 +268,6 @@ void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn, /** * for_each_resv_unavail_range - iterate through reserved and unavailable memory * @i: u64 used as loop variable - * @flags: pick from blocks based on memory attributes * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL * @@ -253,13 +281,13 @@ void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn, NUMA_NO_NODE, MEMBLOCK_NONE, p_start, p_end, NULL) static inline void memblock_set_region_flags(struct memblock_region *r, - unsigned long flags) + enum memblock_flags flags) { r->flags |= flags; } static inline void memblock_clear_region_flags(struct memblock_region *r, - unsigned long flags) + enum memblock_flags flags) { r->flags &= ~flags; } @@ -317,10 +345,10 @@ static inline bool memblock_bottom_up(void) phys_addr_t __init memblock_alloc_range(phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end, - ulong flags); + enum memblock_flags flags); phys_addr_t memblock_alloc_base_nid(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr, - int nid, ulong flags); + int nid, enum memblock_flags flags); phys_addr_t memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr); phys_addr_t __memblock_alloc_base(phys_addr_t size, phys_addr_t align, @@ -367,8 +395,10 @@ phys_addr_t memblock_get_current_limit(void); */ /** - * memblock_region_memory_base_pfn - Return the lowest pfn intersecting with the memory region + * memblock_region_memory_base_pfn - get the lowest pfn of the memory region * @reg: memblock_region structure + * + * Return: the lowest pfn intersecting with the memory region */ static inline unsigned long memblock_region_memory_base_pfn(const struct memblock_region *reg) { @@ -376,8 +406,10 @@ static inline unsigned long memblock_region_memory_base_pfn(const struct membloc } /** - * memblock_region_memory_end_pfn - Return the end_pfn this region + * memblock_region_memory_end_pfn - get the end pfn of the memory region * @reg: memblock_region structure + * + * Return: the end_pfn of the reserved region */ static inline unsigned long memblock_region_memory_end_pfn(const struct memblock_region *reg) { @@ -385,8 +417,10 @@ static inline unsigned long memblock_region_memory_end_pfn(const struct memblock } /** - * memblock_region_reserved_base_pfn - Return the lowest pfn intersecting with the reserved region + * memblock_region_reserved_base_pfn - get the lowest pfn of the reserved region * @reg: memblock_region structure + * + * Return: the lowest pfn intersecting with the reserved region */ static inline unsigned long memblock_region_reserved_base_pfn(const struct memblock_region *reg) { @@ -394,8 +428,10 @@ static inline unsigned long memblock_region_reserved_base_pfn(const struct membl } /** - * memblock_region_reserved_end_pfn - Return the end_pfn this region + * memblock_region_reserved_end_pfn - get the end pfn of the reserved region * @reg: memblock_region structure + * + * Return: the end_pfn of the reserved region */ static inline unsigned long memblock_region_reserved_end_pfn(const struct memblock_region *reg) { diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index e798614..5d73880 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -21,6 +21,21 @@ extern int do_sys_settimeofday64(const struct timespec64 *tv, const struct timezone *tz); /* + * ktime_get() family: read the current time in a multitude of ways, + * + * The default time reference is CLOCK_MONOTONIC, starting at + * boot time but not counting the time spent in suspend. + * For other references, use the functions with "real", "clocktai", + * "boottime" and "raw" suffixes. + * + * To get the time in a different format, use the ones wit + * "ns", "ts64" and "seconds" suffix. + * + * See Documentation/core-api/timekeeping.rst for more details. + */ + + +/* * timespec64 based interfaces */ extern void ktime_get_raw_ts64(struct timespec64 *ts); diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index dcc0166..9a27f14 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -521,7 +521,7 @@ config FUNCTION_PROFILER in debugfs called function_profile_enabled which defaults to zero. When a 1 is echoed into this file profiling begins, and when a zero is entered, profiling stops. A "functions" file is created in - the trace_stats directory; this file shows the list of functions that + the trace_stat directory; this file shows the list of functions that have been hit and their counters. If in doubt, say N. @@ -605,7 +605,7 @@ config HIST_TRIGGERS Inter-event tracing of quantities such as latencies is also supported using hist triggers under this option. - See Documentation/trace/histogram.txt. + See Documentation/trace/histogram.rst. If in doubt, say N. config MMIOTRACE_TEST diff --git a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c index d8bb1a1..e5fdc8b 100644 --- a/lib/reed_solomon/reed_solomon.c +++ b/lib/reed_solomon/reed_solomon.c @@ -283,7 +283,7 @@ out: * in index form * @prim: primitive element to generate polynomial roots * @nroots: RS code generator polynomial degree (number of roots) - * @gfp: GFP_ flags for allocations + * @gfp: Memory allocation flags. */ struct rs_control *init_rs_gfp(int symsize, int gfpoly, int fcr, int prim, int nroots, gfp_t gfp) diff --git a/mm/bootmem.c b/mm/bootmem.c index 9e19798..97db0e8 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -21,6 +21,53 @@ #include "internal.h" +/** + * DOC: bootmem overview + * + * Bootmem is a boot-time physical memory allocator and configurator. + * + * It is used early in the boot process before the page allocator is + * set up. + * + * Bootmem is based on the most basic of allocators, a First Fit + * allocator which uses a bitmap to represent memory. If a bit is 1, + * the page is allocated and 0 if unallocated. To satisfy allocations + * of sizes smaller than a page, the allocator records the Page Frame + * Number (PFN) of the last allocation and the offset the allocation + * ended at. Subsequent small allocations are merged together and + * stored on the same page. + * + * The information used by the bootmem allocator is represented by + * :c:type:`struct bootmem_data`. An array to hold up to %MAX_NUMNODES + * such structures is statically allocated and then it is discarded + * when the system initialization completes. Each entry in this array + * corresponds to a node with memory. For UMA systems only entry 0 is + * used. + * + * The bootmem allocator is initialized during early architecture + * specific setup. Each architecture is required to supply a + * :c:func:`setup_arch` function which, among other tasks, is + * responsible for acquiring the necessary parameters to initialise + * the boot memory allocator. These parameters define limits of usable + * physical memory: + * + * * @min_low_pfn - the lowest PFN that is available in the system + * * @max_low_pfn - the highest PFN that may be addressed by low + * memory (%ZONE_NORMAL) + * * @max_pfn - the last PFN available to the system. + * + * After those limits are determined, the :c:func:`init_bootmem` or + * :c:func:`init_bootmem_node` function should be called to initialize + * the bootmem allocator. The UMA case should use the `init_bootmem` + * function. It will initialize ``contig_page_data`` structure that + * represents the only memory node in the system. In the NUMA case the + * `init_bootmem_node` function should be called to initialize the + * bootmem allocator for each node. + * + * Once the allocator is set up, it is possible to use either single + * node or NUMA variant of the allocation APIs. + */ + #ifndef CONFIG_NEED_MULTIPLE_NODES struct pglist_data __refdata contig_page_data = { .bdata = &bootmem_node_data[0] @@ -62,6 +109,8 @@ static unsigned long __init bootmap_bytes(unsigned long pages) /** * bootmem_bootmap_pages - calculate bitmap size in pages * @pages: number of pages the bitmap has to represent + * + * Return: the number of pages needed to hold the bitmap. */ unsigned long __init bootmem_bootmap_pages(unsigned long pages) { @@ -121,7 +170,7 @@ static unsigned long __init init_bootmem_core(bootmem_data_t *bdata, * @startpfn: first pfn on the node * @endpfn: first pfn after the node * - * Returns the number of bytes needed to hold the bitmap for this node. + * Return: the number of bytes needed to hold the bitmap for this node. */ unsigned long __init init_bootmem_node(pg_data_t *pgdat, unsigned long freepfn, unsigned long startpfn, unsigned long endpfn) @@ -134,7 +183,7 @@ unsigned long __init init_bootmem_node(pg_data_t *pgdat, unsigned long freepfn, * @start: pfn where the bitmap is to be placed * @pages: number of available physical pages * - * Returns the number of bytes needed to hold the bitmap. + * Return: the number of bytes needed to hold the bitmap. */ unsigned long __init init_bootmem(unsigned long start, unsigned long pages) { @@ -143,15 +192,6 @@ unsigned long __init init_bootmem(unsigned long start, unsigned long pages) return init_bootmem_core(NODE_DATA(0)->bdata, start, 0, pages); } -/* - * free_bootmem_late - free bootmem pages directly to page allocator - * @addr: starting physical address of the range - * @size: size of the range in bytes - * - * This is only useful when the bootmem allocator has already been torn - * down, but we are still initializing the system. Pages are given directly - * to the page allocator, no bootmem metadata is updated because it is gone. - */ void __init free_bootmem_late(unsigned long physaddr, unsigned long size) { unsigned long cursor, end; @@ -264,11 +304,6 @@ void __init reset_all_zones_managed_pages(void) reset_managed_pages_done = 1; } -/** - * free_all_bootmem - release free pages to the buddy allocator - * - * Returns the number of pages actually released. - */ unsigned long __init free_all_bootmem(void) { unsigned long total_pages = 0; @@ -385,16 +420,6 @@ static int __init mark_bootmem(unsigned long start, unsigned long end, BUG(); } -/** - * free_bootmem_node - mark a page range as usable - * @pgdat: node the range resides on - * @physaddr: starting address of the range - * @size: size of the range in bytes - * - * Partial pages will be considered reserved and left as they are. - * - * The range must reside completely on the specified node. - */ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, unsigned long size) { @@ -408,15 +433,6 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, mark_bootmem_node(pgdat->bdata, start, end, 0, 0); } -/** - * free_bootmem - mark a page range as usable - * @physaddr: starting physical address of the range - * @size: size of the range in bytes - * - * Partial pages will be considered reserved and left as they are. - * - * The range must be contiguous but may span node boundaries. - */ void __init free_bootmem(unsigned long physaddr, unsigned long size) { unsigned long start, end; @@ -439,6 +455,8 @@ void __init free_bootmem(unsigned long physaddr, unsigned long size) * Partial pages will be reserved. * * The range must reside completely on the specified node. + * + * Return: 0 on success, -errno on failure. */ int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, unsigned long size, int flags) @@ -460,6 +478,8 @@ int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, * Partial pages will be reserved. * * The range must be contiguous but may span node boundaries. + * + * Return: 0 on success, -errno on failure. */ int __init reserve_bootmem(unsigned long addr, unsigned long size, int flags) @@ -646,19 +666,6 @@ restart: return NULL; } -/** - * __alloc_bootmem_nopanic - allocate boot memory without panicking - * @size: size of the request in bytes - * @align: alignment of the region - * @goal: preferred starting address of the region - * - * The goal is dropped if it can not be satisfied and the allocation will - * fall back to memory below @goal. - * - * Allocation may happen on any node in the system. - * - * Returns NULL on failure. - */ void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align, unsigned long goal) { @@ -682,19 +689,6 @@ static void * __init ___alloc_bootmem(unsigned long size, unsigned long align, return NULL; } -/** - * __alloc_bootmem - allocate boot memory - * @size: size of the request in bytes - * @align: alignment of the region - * @goal: preferred starting address of the region - * - * The goal is dropped if it can not be satisfied and the allocation will - * fall back to memory below @goal. - * - * Allocation may happen on any node in the system. - * - * The function panics if the request can not be satisfied. - */ void * __init __alloc_bootmem(unsigned long size, unsigned long align, unsigned long goal) { @@ -754,21 +748,6 @@ void * __init ___alloc_bootmem_node(pg_data_t *pgdat, unsigned long size, return NULL; } -/** - * __alloc_bootmem_node - allocate boot memory from a specific node - * @pgdat: node to allocate from - * @size: size of the request in bytes - * @align: alignment of the region - * @goal: preferred starting address of the region - * - * The goal is dropped if it can not be satisfied and the allocation will - * fall back to memory below @goal. - * - * Allocation may fall back to any node in the system if the specified node - * can not hold the requested memory. - * - * The function panics if the request can not be satisfied. - */ void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal) { @@ -807,19 +786,6 @@ void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size, } -/** - * __alloc_bootmem_low - allocate low boot memory - * @size: size of the request in bytes - * @align: alignment of the region - * @goal: preferred starting address of the region - * - * The goal is dropped if it can not be satisfied and the allocation will - * fall back to memory below @goal. - * - * Allocation may happen on any node in the system. - * - * The function panics if the request can not be satisfied. - */ void * __init __alloc_bootmem_low(unsigned long size, unsigned long align, unsigned long goal) { @@ -834,21 +800,6 @@ void * __init __alloc_bootmem_low_nopanic(unsigned long size, ARCH_LOW_ADDRESS_LIMIT); } -/** - * __alloc_bootmem_low_node - allocate low boot memory from a specific node - * @pgdat: node to allocate from - * @size: size of the request in bytes - * @align: alignment of the region - * @goal: preferred starting address of the region - * - * The goal is dropped if it can not be satisfied and the allocation will - * fall back to memory below @goal. - * - * Allocation may fall back to any node in the system if the specified node - * can not hold the requested memory. - * - * The function panics if the request can not be satisfied. - */ void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal) { diff --git a/mm/memblock.c b/mm/memblock.c index 4b5d245..b4ad057 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -27,6 +27,61 @@ #include "internal.h" +/** + * DOC: memblock overview + * + * Memblock is a method of managing memory regions during the early + * boot period when the usual kernel memory allocators are not up and + * running. + * + * Memblock views the system memory as collections of contiguous + * regions. There are several types of these collections: + * + * * ``memory`` - describes the physical memory available to the + * kernel; this may differ from the actual physical memory installed + * in the system, for instance when the memory is restricted with + * ``mem=`` command line parameter + * * ``reserved`` - describes the regions that were allocated + * * ``physmap`` - describes the actual physical memory regardless of + * the possible restrictions; the ``physmap`` type is only available + * on some architectures. + * + * Each region is represented by :c:type:`struct memblock_region` that + * defines the region extents, its attributes and NUMA node id on NUMA + * systems. Every memory type is described by the :c:type:`struct + * memblock_type` which contains an array of memory regions along with + * the allocator metadata. The memory types are nicely wrapped with + * :c:type:`struct memblock`. This structure is statically initialzed + * at build time. The region arrays for the "memory" and "reserved" + * types are initially sized to %INIT_MEMBLOCK_REGIONS and for the + * "physmap" type to %INIT_PHYSMEM_REGIONS. + * The :c:func:`memblock_allow_resize` enables automatic resizing of + * the region arrays during addition of new regions. This feature + * should be used with care so that memory allocated for the region + * array will not overlap with areas that should be reserved, for + * example initrd. + * + * The early architecture setup should tell memblock what the physical + * memory layout is by using :c:func:`memblock_add` or + * :c:func:`memblock_add_node` functions. The first function does not + * assign the region to a NUMA node and it is appropriate for UMA + * systems. Yet, it is possible to use it on NUMA systems as well and + * assign the region to a NUMA node later in the setup process using + * :c:func:`memblock_set_node`. The :c:func:`memblock_add_node` + * performs such an assignment directly. + * + * Once memblock is setup the memory can be allocated using either + * memblock or bootmem APIs. + * + * As the system boot progresses, the architecture specific + * :c:func:`mem_init` function frees all the memory to the buddy page + * allocator. + * + * If an architecure enables %CONFIG_ARCH_DISCARD_MEMBLOCK, the + * memblock data structures will be discarded after the system + * initialization compltes. + */ + static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock; static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock; #ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP @@ -61,7 +116,7 @@ static int memblock_can_resize __initdata_memblock; static int memblock_memory_in_slab __initdata_memblock = 0; static int memblock_reserved_in_slab __initdata_memblock = 0; -ulong __init_memblock choose_memblock_flags(void) +enum memblock_flags __init_memblock choose_memblock_flags(void) { return system_has_some_mirror ? MEMBLOCK_MIRROR : MEMBLOCK_NONE; } @@ -93,10 +148,11 @@ bool __init_memblock memblock_overlaps_region(struct memblock_type *type, return i < type->cnt; } -/* +/** * __memblock_find_range_bottom_up - find free area utility in bottom-up * @start: start of candidate range - * @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE} + * @end: end of candidate range, can be %MEMBLOCK_ALLOC_ANYWHERE or + * %MEMBLOCK_ALLOC_ACCESSIBLE * @size: size of free area to find * @align: alignment of free area to find * @nid: nid of the free area to find, %NUMA_NO_NODE for any node @@ -104,13 +160,13 @@ bool __init_memblock memblock_overlaps_region(struct memblock_type *type, * * Utility called from memblock_find_in_range_node(), find free area bottom-up. * - * RETURNS: + * Return: * Found address on success, 0 on failure. */ static phys_addr_t __init_memblock __memblock_find_range_bottom_up(phys_addr_t start, phys_addr_t end, phys_addr_t size, phys_addr_t align, int nid, - ulong flags) + enum memblock_flags flags) { phys_addr_t this_start, this_end, cand; u64 i; @@ -130,7 +186,8 @@ __memblock_find_range_bottom_up(phys_addr_t start, phys_addr_t end, /** * __memblock_find_range_top_down - find free area utility, in top-down * @start: start of candidate range - * @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE} + * @end: end of candidate range, can be %MEMBLOCK_ALLOC_ANYWHERE or + * %MEMBLOCK_ALLOC_ACCESSIBLE * @size: size of free area to find * @align: alignment of free area to find * @nid: nid of the free area to find, %NUMA_NO_NODE for any node @@ -138,13 +195,13 @@ __memblock_find_range_bottom_up(phys_addr_t start, phys_addr_t end, * * Utility called from memblock_find_in_range_node(), find free area top-down. * - * RETURNS: + * Return: * Found address on success, 0 on failure. */ static phys_addr_t __init_memblock __memblock_find_range_top_down(phys_addr_t start, phys_addr_t end, phys_addr_t size, phys_addr_t align, int nid, - ulong flags) + enum memblock_flags flags) { phys_addr_t this_start, this_end, cand; u64 i; @@ -170,7 +227,8 @@ __memblock_find_range_top_down(phys_addr_t start, phys_addr_t end, * @size: size of free area to find * @align: alignment of free area to find * @start: start of candidate range - * @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE} + * @end: end of candidate range, can be %MEMBLOCK_ALLOC_ANYWHERE or + * %MEMBLOCK_ALLOC_ACCESSIBLE * @nid: nid of the free area to find, %NUMA_NO_NODE for any node * @flags: pick from blocks based on memory attributes * @@ -184,12 +242,13 @@ __memblock_find_range_top_down(phys_addr_t start, phys_addr_t end, * * If bottom-up allocation failed, will try to allocate memory top-down. * - * RETURNS: + * Return: * Found address on success, 0 on failure. */ phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size, phys_addr_t align, phys_addr_t start, - phys_addr_t end, int nid, ulong flags) + phys_addr_t end, int nid, + enum memblock_flags flags) { phys_addr_t kernel_end, ret; @@ -239,13 +298,14 @@ phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size, /** * memblock_find_in_range - find free area in given range * @start: start of candidate range - * @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE} + * @end: end of candidate range, can be %MEMBLOCK_ALLOC_ANYWHERE or + * %MEMBLOCK_ALLOC_ACCESSIBLE * @size: size of free area to find * @align: alignment of free area to find * * Find @size free area aligned to @align in the specified range. * - * RETURNS: + * Return: * Found address on success, 0 on failure. */ phys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start, @@ -253,7 +313,7 @@ phys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start, phys_addr_t align) { phys_addr_t ret; - ulong flags = choose_memblock_flags(); + enum memblock_flags flags = choose_memblock_flags(); again: ret = memblock_find_in_range_node(size, align, start, end, @@ -289,7 +349,7 @@ static void __init_memblock memblock_remove_region(struct memblock_type *type, u #ifdef CONFIG_ARCH_DISCARD_MEMBLOCK /** - * Discard memory and reserved arrays if they were allocated + * memblock_discard - discard memory and reserved arrays if they were allocated */ void __init memblock_discard(void) { @@ -319,11 +379,11 @@ void __init memblock_discard(void) * * Double the size of the @type regions array. If memblock is being used to * allocate memory for a new reserved regions array and there is a previously - * allocated memory range [@new_area_start,@new_area_start+@new_area_size] + * allocated memory range [@new_area_start, @new_area_start + @new_area_size] * waiting to be reserved, ensure the memory used by the new array does * not overlap. * - * RETURNS: + * Return: * 0 on success, -1 on failure. */ static int __init_memblock memblock_double_array(struct memblock_type *type, @@ -468,13 +528,14 @@ static void __init_memblock memblock_merge_regions(struct memblock_type *type) * @nid: node id of the new region * @flags: flags of the new region * - * Insert new memblock region [@base,@base+@size) into @type at @idx. + * Insert new memblock region [@base, @base + @size) into @type at @idx. * @type must already have extra room to accommodate the new region. */ static void __init_memblock memblock_insert_region(struct memblock_type *type, int idx, phys_addr_t base, phys_addr_t size, - int nid, unsigned long flags) + int nid, + enum memblock_flags flags) { struct memblock_region *rgn = &type->regions[idx]; @@ -496,17 +557,17 @@ static void __init_memblock memblock_insert_region(struct memblock_type *type, * @nid: nid of the new region * @flags: flags of the new region * - * Add new memblock region [@base,@base+@size) into @type. The new region + * Add new memblock region [@base, @base + @size) into @type. The new region * is allowed to overlap with existing ones - overlaps don't affect already * existing regions. @type is guaranteed to be minimal (all neighbouring * compatible regions are merged) after the addition. * - * RETURNS: + * Return: * 0 on success, -errno on failure. */ int __init_memblock memblock_add_range(struct memblock_type *type, phys_addr_t base, phys_addr_t size, - int nid, unsigned long flags) + int nid, enum memblock_flags flags) { bool insert = false; phys_addr_t obase = base; @@ -590,12 +651,35 @@ repeat: } } +/** + * memblock_add_node - add new memblock region within a NUMA node + * @base: base address of the new region + * @size: size of the new region + * @nid: nid of the new region + * + * Add new memblock region [@base, @base + @size) to the "memory" + * type. See memblock_add_range() description for mode details + * + * Return: + * 0 on success, -errno on failure. + */ int __init_memblock memblock_add_node(phys_addr_t base, phys_addr_t size, int nid) { return memblock_add_range(&memblock.memory, base, size, nid, 0); } +/** + * memblock_add - add new memblock region + * @base: base address of the new region + * @size: size of the new region + * + * Add new memblock region [@base, @base + @size) to the "memory" + * type. See memblock_add_range() description for mode details + * + * Return: + * 0 on success, -errno on failure. + */ int __init_memblock memblock_add(phys_addr_t base, phys_addr_t size) { phys_addr_t end = base + size - 1; @@ -615,11 +699,11 @@ int __init_memblock memblock_add(phys_addr_t base, phys_addr_t size) * @end_rgn: out parameter for the end of isolated region * * Walk @type and ensure that regions don't cross the boundaries defined by - * [@base,@base+@size). Crossing regions are split at the boundaries, + * [@base, @base + @size). Crossing regions are split at the boundaries, * which may create at most two more regions. The index of the first * region inside the range is returned in *@start_rgn and end in *@end_rgn. * - * RETURNS: + * Return: * 0 on success, -errno on failure. */ static int __init_memblock memblock_isolate_range(struct memblock_type *type, @@ -730,10 +814,15 @@ int __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size) } /** + * memblock_setclr_flag - set or clear flag for a memory region + * @base: base address of the region + * @size: size of the region + * @set: set or clear the flag + * @flag: the flag to udpate * * This function isolates region [@base, @base + @size), and sets/clears flag * - * Return 0 on success, -errno on failure. + * Return: 0 on success, -errno on failure. */ static int __init_memblock memblock_setclr_flag(phys_addr_t base, phys_addr_t size, int set, int flag) @@ -760,7 +849,7 @@ static int __init_memblock memblock_setclr_flag(phys_addr_t base, * @base: the base phys addr of the region * @size: the size of the region * - * Return 0 on success, -errno on failure. + * Return: 0 on success, -errno on failure. */ int __init_memblock memblock_mark_hotplug(phys_addr_t base, phys_addr_t size) { @@ -772,7 +861,7 @@ int __init_memblock memblock_mark_hotplug(phys_addr_t base, phys_addr_t size) * @base: the base phys addr of the region * @size: the size of the region * - * Return 0 on success, -errno on failure. + * Return: 0 on success, -errno on failure. */ int __init_memblock memblock_clear_hotplug(phys_addr_t base, phys_addr_t size) { @@ -784,7 +873,7 @@ int __init_memblock memblock_clear_hotplug(phys_addr_t base, phys_addr_t size) * @base: the base phys addr of the region * @size: the size of the region * - * Return 0 on success, -errno on failure. + * Return: 0 on success, -errno on failure. */ int __init_memblock memblock_mark_mirror(phys_addr_t base, phys_addr_t size) { @@ -798,7 +887,7 @@ int __init_memblock memblock_mark_mirror(phys_addr_t base, phys_addr_t size) * @base: the base phys addr of the region * @size: the size of the region * - * Return 0 on success, -errno on failure. + * Return: 0 on success, -errno on failure. */ int __init_memblock memblock_mark_nomap(phys_addr_t base, phys_addr_t size) { @@ -810,7 +899,7 @@ int __init_memblock memblock_mark_nomap(phys_addr_t base, phys_addr_t size) * @base: the base phys addr of the region * @size: the size of the region * - * Return 0 on success, -errno on failure. + * Return: 0 on success, -errno on failure. */ int __init_memblock memblock_clear_nomap(phys_addr_t base, phys_addr_t size) { @@ -875,7 +964,8 @@ void __init_memblock __next_reserved_mem_region(u64 *idx, * As both region arrays are sorted, the function advances the two indices * in lockstep and returns each intersection. */ -void __init_memblock __next_mem_range(u64 *idx, int nid, ulong flags, +void __init_memblock __next_mem_range(u64 *idx, int nid, + enum memblock_flags flags, struct memblock_type *type_a, struct memblock_type *type_b, phys_addr_t *out_start, @@ -970,9 +1060,6 @@ void __init_memblock __next_mem_range(u64 *idx, int nid, ulong flags, /** * __next_mem_range_rev - generic next function for for_each_*_range_rev() * - * Finds the next range from type_a which is not marked as unsuitable - * in type_b. - * * @idx: pointer to u64 loop variable * @nid: node selector, %NUMA_NO_NODE for all nodes * @flags: pick from blocks based on memory attributes @@ -982,9 +1069,13 @@ void __init_memblock __next_mem_range(u64 *idx, int nid, ulong flags, * @out_end: ptr to phys_addr_t for end address of the range, can be %NULL * @out_nid: ptr to int for nid of the range, can be %NULL * + * Finds the next range from type_a which is not marked as unsuitable + * in type_b. + * * Reverse of __next_mem_range(). */ -void __init_memblock __next_mem_range_rev(u64 *idx, int nid, ulong flags, +void __init_memblock __next_mem_range_rev(u64 *idx, int nid, + enum memblock_flags flags, struct memblock_type *type_a, struct memblock_type *type_b, phys_addr_t *out_start, @@ -1116,10 +1207,10 @@ void __init_memblock __next_mem_pfn_range(int *idx, int nid, * @type: memblock type to set node ID for * @nid: node ID to set * - * Set the nid of memblock @type regions in [@base,@base+@size) to @nid. + * Set the nid of memblock @type regions in [@base, @base + @size) to @nid. * Regions which cross the area boundaries are split as necessary. * - * RETURNS: + * Return: * 0 on success, -errno on failure. */ int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size, @@ -1142,7 +1233,8 @@ int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size, static phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size, phys_addr_t align, phys_addr_t start, - phys_addr_t end, int nid, ulong flags) + phys_addr_t end, int nid, + enum memblock_flags flags) { phys_addr_t found; @@ -1164,7 +1256,7 @@ static phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size, phys_addr_t __init memblock_alloc_range(phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end, - ulong flags) + enum memblock_flags flags) { return memblock_alloc_range_nid(size, align, start, end, NUMA_NO_NODE, flags); @@ -1172,14 +1264,14 @@ phys_addr_t __init memblock_alloc_range(phys_addr_t size, phys_addr_t align, phys_addr_t __init memblock_alloc_base_nid(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr, - int nid, ulong flags) + int nid, enum memblock_flags flags) { return memblock_alloc_range_nid(size, align, 0, max_addr, nid, flags); } phys_addr_t __init memblock_alloc_nid(phys_addr_t size, phys_addr_t align, int nid) { - ulong flags = choose_memblock_flags(); + enum memblock_flags flags = choose_memblock_flags(); phys_addr_t ret; again: @@ -1243,7 +1335,7 @@ phys_addr_t __init memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align, i * The allocation is performed from memory region limited by * memblock.current_limit if @max_addr == %BOOTMEM_ALLOC_ACCESSIBLE. * - * The memory block is aligned on SMP_CACHE_BYTES if @align == 0. + * The memory block is aligned on %SMP_CACHE_BYTES if @align == 0. * * The phys address of allocated boot memory block is converted to virtual and * allocated memory is reset to 0. @@ -1251,7 +1343,7 @@ phys_addr_t __init memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align, i * In addition, function sets the min_count to 0 using kmemleak_alloc for * allocated boot memory block, so that it is never reported as leaks. * - * RETURNS: + * Return: * Virtual address of allocated memory block on success, NULL on failure. */ static void * __init memblock_virt_alloc_internal( @@ -1261,7 +1353,7 @@ static void * __init memblock_virt_alloc_internal( { phys_addr_t alloc; void *ptr; - ulong flags = choose_memblock_flags(); + enum memblock_flags flags = choose_memblock_flags(); if (WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n")) nid = NUMA_NO_NODE; @@ -1336,7 +1428,7 @@ done: * info), if enabled. Does not zero allocated memory, does not panic if request * cannot be satisfied. * - * RETURNS: + * Return: * Virtual address of allocated memory block on success, NULL on failure. */ void * __init memblock_virt_alloc_try_nid_raw( @@ -1373,7 +1465,7 @@ void * __init memblock_virt_alloc_try_nid_raw( * Public function, provides additional debug information (including caller * info), if enabled. This function zeroes the allocated memory. * - * RETURNS: + * Return: * Virtual address of allocated memory block on success, NULL on failure. */ void * __init memblock_virt_alloc_try_nid_nopanic( @@ -1409,7 +1501,7 @@ void * __init memblock_virt_alloc_try_nid_nopanic( * which provides debug information (including caller info), if enabled, * and panics if the request can not be satisfied. * - * RETURNS: + * Return: * Virtual address of allocated memory block on success, NULL on failure. */ void * __init memblock_virt_alloc_try_nid( @@ -1453,9 +1545,9 @@ void __init __memblock_free_early(phys_addr_t base, phys_addr_t size) memblock_remove_range(&memblock.reserved, base, size); } -/* +/** * __memblock_free_late - free bootmem block pages directly to buddy allocator - * @addr: phys starting address of the boot memory block + * @base: phys starting address of the boot memory block * @size: size of the boot memory block in bytes * * This is only useful when the bootmem allocator has already been torn @@ -1667,9 +1759,9 @@ int __init_memblock memblock_search_pfn_nid(unsigned long pfn, * @base: base of region to check * @size: size of region to check * - * Check if the region [@base, @base+@size) is a subset of a memory block. + * Check if the region [@base, @base + @size) is a subset of a memory block. * - * RETURNS: + * Return: * 0 if false, non-zero if true */ bool __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size) @@ -1688,9 +1780,10 @@ bool __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t siz * @base: base of region to check * @size: size of region to check * - * Check if the region [@base, @base+@size) intersects a reserved memory block. + * Check if the region [@base, @base + @size) intersects a reserved + * memory block. * - * RETURNS: + * Return: * True if they intersect, false if not. */ bool __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size) @@ -1737,7 +1830,7 @@ phys_addr_t __init_memblock memblock_get_current_limit(void) static void __init_memblock memblock_dump(struct memblock_type *type) { phys_addr_t base, end, size; - unsigned long flags; + enum memblock_flags flags; int idx; struct memblock_region *rgn; @@ -1755,7 +1848,7 @@ static void __init_memblock memblock_dump(struct memblock_type *type) snprintf(nid_buf, sizeof(nid_buf), " on node %d", memblock_get_region_node(rgn)); #endif - pr_info(" %s[%#x]\t[%pa-%pa], %pa bytes%s flags: %#lx\n", + pr_info(" %s[%#x]\t[%pa-%pa], %pa bytes%s flags: %#x\n", type->name, idx, &base, &end, &size, nid_buf, flags); } } diff --git a/mm/nobootmem.c b/mm/nobootmem.c index 9b02fda..439af3b 100644 --- a/mm/nobootmem.c +++ b/mm/nobootmem.c @@ -42,7 +42,7 @@ static void * __init __alloc_memory_core_early(int nid, u64 size, u64 align, { void *ptr; u64 addr; - ulong flags = choose_memblock_flags(); + enum memblock_flags flags = choose_memblock_flags(); if (limit > memblock.current_limit) limit = memblock.current_limit; @@ -72,7 +72,7 @@ again: return ptr; } -/* +/** * free_bootmem_late - free bootmem pages directly to page allocator * @addr: starting address of the range * @size: size of the range in bytes @@ -176,7 +176,7 @@ void __init reset_all_zones_managed_pages(void) /** * free_all_bootmem - release free pages to the buddy allocator * - * Returns the number of pages actually released. + * Return: the number of pages actually released. */ unsigned long __init free_all_bootmem(void) { @@ -193,7 +193,7 @@ unsigned long __init free_all_bootmem(void) /** * free_bootmem_node - mark a page range as usable * @pgdat: node the range resides on - * @physaddr: starting address of the range + * @physaddr: starting physical address of the range * @size: size of the range in bytes * * Partial pages will be considered reserved and left as they are. @@ -208,7 +208,7 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, /** * free_bootmem - mark a page range as usable - * @addr: starting address of the range + * @addr: starting physical address of the range * @size: size of the range in bytes * * Partial pages will be considered reserved and left as they are. @@ -256,7 +256,7 @@ restart: * * Allocation may happen on any node in the system. * - * Returns NULL on failure. + * Return: address of the allocated region or %NULL on failure. */ void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align, unsigned long goal) @@ -293,6 +293,8 @@ static void * __init ___alloc_bootmem(unsigned long size, unsigned long align, * Allocation may happen on any node in the system. * * The function panics if the request can not be satisfied. + * + * Return: address of the allocated region. */ void * __init __alloc_bootmem(unsigned long size, unsigned long align, unsigned long goal) @@ -367,6 +369,8 @@ static void * __init ___alloc_bootmem_node(pg_data_t *pgdat, unsigned long size, * can not hold the requested memory. * * The function panics if the request can not be satisfied. + * + * Return: address of the allocated region. */ void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal) @@ -396,6 +400,8 @@ void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size, * Allocation may happen on any node in the system. * * The function panics if the request can not be satisfied. + * + * Return: address of the allocated region. */ void * __init __alloc_bootmem_low(unsigned long size, unsigned long align, unsigned long goal) @@ -425,6 +431,8 @@ void * __init __alloc_bootmem_low_nopanic(unsigned long size, * can not hold the requested memory. * * The function panics if the request can not be satisfied. + * + * Return: address of the allocated region. */ void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal) diff --git a/scripts/documentation-file-ref-check b/scripts/documentation-file-ref-check index 078999a..ad9db68 100755 --- a/scripts/documentation-file-ref-check +++ b/scripts/documentation-file-ref-check @@ -75,6 +75,12 @@ while (<IN>) { # Remove URL false-positives next if ($fulref =~ m/^http/); + # Remove sched-pelt false-positive + next if ($fulref =~ m,^Documentation/scheduler/sched-pelt$,); + + # Discard some build examples from Documentation/target/tcm_mod_builder.txt + next if ($fulref =~ m,mnt/sdb/lio-core-2.6.git/Documentation/target,); + # Check if exists, evaluating wildcards next if (grep -e, glob("$ref $fulref")); diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 0057d8e..8f0f508 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1062,7 +1062,7 @@ sub dump_struct($$) { my $x = shift; my $file = shift; - if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) { + if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}/) { my $decl_type = $1; $declaration_name = $2; my $members = $3; @@ -1148,20 +1148,20 @@ sub dump_struct($$) { } } } - $members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)}([^\{\}\;]*)\;/$newmember/; + $members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/$newmember/; } # Ignore other nested elements, like enums - $members =~ s/({[^\{\}]*})//g; + $members =~ s/(\{[^\{\}]*\})//g; create_parameterlist($members, ';', $file, $declaration_name); check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual); # Adjust declaration for better display - $declaration =~ s/([{;])/$1\n/g; - $declaration =~ s/}\s+;/};/g; + $declaration =~ s/([\{;])/$1\n/g; + $declaration =~ s/\}\s+;/};/g; # Better handle inlined enums - do {} while ($declaration =~ s/(enum\s+{[^}]+),([^\n])/$1,\n$2/); + do {} while ($declaration =~ s/(enum\s+\{[^\}]+),([^\n])/$1,\n$2/); my @def_args = split /\n/, $declaration; my $level = 1; @@ -1171,12 +1171,12 @@ sub dump_struct($$) { $clause =~ s/\s+$//; $clause =~ s/\s+/ /; next if (!$clause); - $level-- if ($clause =~ m/(})/ && $level > 1); + $level-- if ($clause =~ m/(\})/ && $level > 1); if (!($clause =~ m/^\s*#/)) { $declaration .= "\t" x $level; } $declaration .= "\t" . $clause . "\n"; - $level++ if ($clause =~ m/({)/ && !($clause =~m/}/)); + $level++ if ($clause =~ m/(\{)/ && !($clause =~m/\}/)); } output_declaration($declaration_name, 'struct', @@ -1244,7 +1244,7 @@ sub dump_enum($$) { # strip #define macros inside enums $x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos; - if ($x =~ /enum\s+(\w+)\s*{(.*)}/) { + if ($x =~ /enum\s+(\w+)\s*\{(.*)\}/) { $declaration_name = $1; my $members = $2; my %_members; @@ -1785,7 +1785,7 @@ sub process_proto_type($$) { } while (1) { - if ( $x =~ /([^{};]*)([{};])(.*)/ ) { + if ( $x =~ /([^\{\};]*)([\{\};])(.*)/ ) { if( length $prototype ) { $prototype .= " " } |