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. -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJbcZVtAAoJEI3ONVYwIuV64ekP/jgTlMi/fErRu6zlsrsWgiIK ir8ueCQ1OSiwOA+N2fUb+2+zlLlfTLgQ+o5IwmZk6rizG87fQ3Rp6i+bvYAZWITh YUuls3VhtRlJZqG1EW7gww1Q2IhRO6GhcpsIamAvhrSLFPaCKiN3JomJi/X47Pfj Ibl24HsruI2fDM1JwWRwCtE5J6vCL9lH1/5v4zVv7xdrVgTrwkZ/hAsE7HBNNat5 dSku2u9HSAXa4KR4sLWrVJ8UI5+fylwilz/57HhCeduQDwKCHE/mfhxLdqL4Oa4q oHTCNq2zTUj4w7GTvHS1g0P3y/iWMYjAzH2is+BokilpIC65NwwsKx2ybZd3Srdh zwP/kYk5U+mYSgdDlyNqwPCibw8KDXB3srKMzyQSN6tkosKCOHFSXF0Js0eupi7t NqmGigl3Qozj1uvU6Wy7vh58u+GFeuO4PF566t2m70Jp0cWzuVKLrBvgNO1X37rB aEBrpOYB/H54t/qf79IFW//pptWXFNZ3S9AgyDVIcmX5C2ihaCoaPNRTom+KbH/D QEoH9rwWSoCi2DGoR83D+G8thCUfB4yfEGulSSIA4pUR7qvIR5rd1ZioI/qtgAHm l7MjTbLpPwiMnpFkBrxxxlFFb4gbETakMBGYoYee8ww5WbQLu0qA93AbwIXyjhE8 mqCOLyBdCAZ0mNxqPSsc =x/P0 -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
e6ecec342f
|
@ -1,3 +1,5 @@
|
||||||
|
.. _readme:
|
||||||
|
|
||||||
Linux kernel release 4.x <http://kernel.org/>
|
Linux kernel release 4.x <http://kernel.org/>
|
||||||
=============================================
|
=============================================
|
||||||
|
|
||||||
|
|
|
@ -4136,6 +4136,8 @@
|
||||||
This parameter controls whether the Speculative Store
|
This parameter controls whether the Speculative Store
|
||||||
Bypass optimization is used.
|
Bypass optimization is used.
|
||||||
|
|
||||||
|
On x86 the options are:
|
||||||
|
|
||||||
on - Unconditionally disable Speculative Store Bypass
|
on - Unconditionally disable Speculative Store Bypass
|
||||||
off - Unconditionally enable Speculative Store Bypass
|
off - Unconditionally enable Speculative Store Bypass
|
||||||
auto - Kernel detects whether the CPU model contains an
|
auto - Kernel detects whether the CPU model contains an
|
||||||
|
@ -4151,12 +4153,20 @@
|
||||||
seccomp - Same as "prctl" above, but all seccomp threads
|
seccomp - Same as "prctl" above, but all seccomp threads
|
||||||
will disable SSB unless they explicitly opt out.
|
will disable SSB unless they explicitly opt out.
|
||||||
|
|
||||||
Not specifying this option is equivalent to
|
|
||||||
spec_store_bypass_disable=auto.
|
|
||||||
|
|
||||||
Default mitigations:
|
Default mitigations:
|
||||||
X86: If CONFIG_SECCOMP=y "seccomp", otherwise "prctl"
|
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_io_base= [HW,MTD]
|
||||||
spia_fio_base=
|
spia_fio_base=
|
||||||
spia_pedr=
|
spia_pedr=
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Console Drivers
|
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.
|
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
|
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
|
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
|
occupied by the system driver. In the same token, if the modular driver is
|
||||||
released by the console, the system driver will take over.
|
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
|
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:
|
In newer kernels, the following are also available:
|
||||||
|
|
||||||
|
@ -56,7 +57,7 @@ What do these files signify?
|
||||||
cat /sys/class/vtconsole/vtcon0/name
|
cat /sys/class/vtconsole/vtcon0/name
|
||||||
(S) VGA+
|
(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
|
commanded to bind or unbind
|
||||||
|
|
||||||
'VGA+' is the name of the driver
|
'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
|
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
|
framebuffer console to VGA console and vice versa, this feature also makes
|
||||||
this possible. (NOTE NOTE NOTE: Please read fbcon.txt under Documentation/fb
|
this possible. (NOTE NOTE NOTE: Please read fbcon.txt under Documentation/fb
|
||||||
for more details).
|
for more details.)
|
||||||
|
|
||||||
Notes for developers:
|
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:
|
console drivers must follow these guidelines:
|
||||||
|
|
||||||
1. All drivers, except system drivers, must call either do_register_con_driver()
|
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
|
or do_take_over_console(). do_register_con_driver() will just add the driver
|
||||||
the console's internal list. It won't take over the
|
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
|
console. do_take_over_console(), as it name implies, will also take over (or
|
||||||
bind to) the console.
|
bind to) the console.
|
||||||
|
|
||||||
|
|
|
@ -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:
|
|
@ -76,4 +76,6 @@ Functions and structures
|
||||||
========================
|
========================
|
||||||
|
|
||||||
.. kernel-doc:: include/linux/idr.h
|
.. kernel-doc:: include/linux/idr.h
|
||||||
|
:functions:
|
||||||
.. kernel-doc:: lib/idr.c
|
.. kernel-doc:: lib/idr.c
|
||||||
|
:functions:
|
||||||
|
|
|
@ -28,6 +28,8 @@ Core utilities
|
||||||
printk-formats
|
printk-formats
|
||||||
circular-buffers
|
circular-buffers
|
||||||
gfp_mask-from-fs-io
|
gfp_mask-from-fs-io
|
||||||
|
timekeeping
|
||||||
|
boot-time-mm
|
||||||
|
|
||||||
Interfaces for kernel debugging
|
Interfaces for kernel debugging
|
||||||
===============================
|
===============================
|
||||||
|
|
|
@ -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.
|
|
@ -156,6 +156,11 @@ Contributing new tests (details)
|
||||||
installed by the distro on the system should be the primary focus to be able
|
installed by the distro on the system should be the primary focus to be able
|
||||||
to find regressions.
|
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
|
Test Harness
|
||||||
============
|
============
|
||||||
|
|
||||||
|
|
|
@ -488,14 +488,19 @@ doc: *title*
|
||||||
.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
|
.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
|
||||||
:doc: High Definition Audio over HDMI and Display Port
|
:doc: High Definition Audio over HDMI and Display Port
|
||||||
|
|
||||||
functions: *function* *[...]*
|
functions: *[ function ...]*
|
||||||
Include documentation for each *function* in *source*.
|
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
|
.. kernel-doc:: lib/bitmap.c
|
||||||
:functions: bitmap_parselist bitmap_parselist_user
|
:functions: bitmap_parselist bitmap_parselist_user
|
||||||
|
|
||||||
|
.. kernel-doc:: lib/idr.c
|
||||||
|
:functions:
|
||||||
|
|
||||||
Without options, the kernel-doc directive includes all documentation comments
|
Without options, the kernel-doc directive includes all documentation comments
|
||||||
from the source file.
|
from the source file.
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ SYNOPSIS
|
||||||
|
|
||||||
\ **parse_headers.pl**\ [<options>] <C_FILE> <OUT_FILE> [<EXCEPTIONS_FILE>]
|
\ **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
|
OPTIONS
|
||||||
|
@ -133,7 +133,7 @@ For both statements, \ **type**\ can be either one of the following:
|
||||||
|
|
||||||
\ **symbol**\
|
\ **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.
|
at C_FILE.
|
||||||
|
|
||||||
For replace statements, \ **new_value**\ will automatically use :c:type:
|
For replace statements, \ **new_value**\ will automatically use :c:type:
|
||||||
|
|
|
@ -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
|
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.
|
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.
|
:ref:`sphinx-pre-install` for further details.
|
||||||
|
|
||||||
Most distributions are shipped with Sphinx, but its toolchain is fragile,
|
Most distributions are shipped with Sphinx, but its toolchain is fragile,
|
||||||
|
|
|
@ -374,7 +374,7 @@ The nand driver supports three different types of hardware ECC.
|
||||||
|
|
||||||
- NAND_ECC_HW8_512
|
- 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
|
If your hardware generator has a different functionality add it at the
|
||||||
appropriate place in nand_base.c
|
appropriate place in nand_base.c
|
||||||
|
@ -889,7 +889,7 @@ Use these constants to select the ECC algorithm::
|
||||||
#define NAND_ECC_HW3_512 3
|
#define NAND_ECC_HW3_512 3
|
||||||
/* Hardware ECC 6 byte ECC per 512 Byte data */
|
/* Hardware ECC 6 byte ECC per 512 Byte data */
|
||||||
#define NAND_ECC_HW6_512 4
|
#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
|
#define NAND_ECC_HW8_512 6
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -532,9 +532,9 @@ More details about quota locking can be found in fs/dquot.c.
|
||||||
prototypes:
|
prototypes:
|
||||||
void (*open)(struct vm_area_struct*);
|
void (*open)(struct vm_area_struct*);
|
||||||
void (*close)(struct vm_area_struct*);
|
void (*close)(struct vm_area_struct*);
|
||||||
int (*fault)(struct vm_area_struct*, struct vm_fault *);
|
vm_fault_t (*fault)(struct vm_area_struct*, struct vm_fault *);
|
||||||
int (*page_mkwrite)(struct vm_area_struct *, struct vm_fault *);
|
vm_fault_t (*page_mkwrite)(struct vm_area_struct *, struct vm_fault *);
|
||||||
int (*pfn_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);
|
int (*access)(struct vm_area_struct *, unsigned long, void*, int, int);
|
||||||
|
|
||||||
locking rules:
|
locking rules:
|
||||||
|
|
|
@ -870,6 +870,7 @@ Committed_AS: 100056 kB
|
||||||
VmallocTotal: 112216 kB
|
VmallocTotal: 112216 kB
|
||||||
VmallocUsed: 428 kB
|
VmallocUsed: 428 kB
|
||||||
VmallocChunk: 111088 kB
|
VmallocChunk: 111088 kB
|
||||||
|
HardwareCorrupted: 0 kB
|
||||||
AnonHugePages: 49152 kB
|
AnonHugePages: 49152 kB
|
||||||
ShmemHugePages: 0 kB
|
ShmemHugePages: 0 kB
|
||||||
ShmemPmdMapped: 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
|
Dirty: Memory which is waiting to get written back to the disk
|
||||||
Writeback: Memory which is actively being 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
|
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
|
AnonHugePages: Non-file backed huge pages mapped into userspace page tables
|
||||||
Mapped: files which have been mmaped, such as libraries
|
Mapped: files which have been mmaped, such as libraries
|
||||||
Shmem: Total memory used by shared memory (shmem) and tmpfs
|
Shmem: Total memory used by shared memory (shmem) and tmpfs
|
||||||
|
|
|
@ -222,7 +222,7 @@ using debugfs:
|
||||||
*/
|
*/
|
||||||
static struct dentry *create_buf_file_handler(const char *filename,
|
static struct dentry *create_buf_file_handler(const char *filename,
|
||||||
struct dentry *parent,
|
struct dentry *parent,
|
||||||
int mode,
|
umode_t mode,
|
||||||
struct rchan_buf *buf,
|
struct rchan_buf *buf,
|
||||||
int *is_global)
|
int *is_global)
|
||||||
{
|
{
|
||||||
|
@ -375,7 +375,7 @@ would be very similar:
|
||||||
static int subbuf_start(struct rchan_buf *buf,
|
static int subbuf_start(struct rchan_buf *buf,
|
||||||
void *subbuf,
|
void *subbuf,
|
||||||
void *prev_subbuf,
|
void *prev_subbuf,
|
||||||
unsigned int prev_padding)
|
size_t prev_padding)
|
||||||
{
|
{
|
||||||
if (prev_subbuf)
|
if (prev_subbuf)
|
||||||
*((unsigned *)prev_subbuf) = prev_padding;
|
*((unsigned *)prev_subbuf) = prev_padding;
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
You can adapt this file completely to your liking, but it should at least
|
You can adapt this file completely to your liking, but it should at least
|
||||||
contain the root `toctree` directive.
|
contain the root `toctree` directive.
|
||||||
|
|
||||||
|
.. _linux_doc:
|
||||||
|
|
||||||
The Linux Kernel documentation
|
The Linux Kernel documentation
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
|
@ -113,29 +115,13 @@ subprojects.
|
||||||
|
|
||||||
filesystems/ext4/index
|
filesystems/ext4/index
|
||||||
|
|
||||||
Korean translations
|
Translations
|
||||||
-------------------
|
------------
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 2
|
||||||
|
|
||||||
translations/ko_KR/index
|
translations/index
|
||||||
|
|
||||||
Chinese translations
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
translations/zh_CN/index
|
|
||||||
|
|
||||||
Japanese translations
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
translations/ja_JP/index
|
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
==================
|
==================
|
||||||
|
|
|
@ -274,6 +274,7 @@ Code Seq#(hex) Include File Comments
|
||||||
'v' 00-1F linux/ext2_fs.h conflict!
|
'v' 00-1F linux/ext2_fs.h conflict!
|
||||||
'v' 00-1F linux/fs.h conflict!
|
'v' 00-1F linux/fs.h conflict!
|
||||||
'v' 00-0F linux/sonypi.h conflict!
|
'v' 00-0F linux/sonypi.h conflict!
|
||||||
|
'v' 00-0F media/v4l2-subdev.h conflict!
|
||||||
'v' C0-FF linux/meye.h conflict!
|
'v' C0-FF linux/meye.h conflict!
|
||||||
'w' all CERN SCI driver
|
'w' all CERN SCI driver
|
||||||
'y' 00-1F packet based user level communications
|
'y' 00-1F packet based user level communications
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _kernel_hacking_hack:
|
||||||
|
|
||||||
============================================
|
============================================
|
||||||
Unreliable Guide To Hacking The Linux Kernel
|
Unreliable Guide To Hacking The Linux Kernel
|
||||||
============================================
|
============================================
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _kernel_hacking:
|
||||||
|
|
||||||
=====================
|
=====================
|
||||||
Kernel Hacking Guides
|
Kernel Hacking Guides
|
||||||
=====================
|
=====================
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _kernel_hacking_lock:
|
||||||
|
|
||||||
===========================
|
===========================
|
||||||
Unreliable Guide To Locking
|
Unreliable Guide To Locking
|
||||||
===========================
|
===========================
|
||||||
|
@ -177,7 +179,7 @@ perfect world).
|
||||||
|
|
||||||
Note that you can also use :c:func:`spin_lock_irq()` or
|
Note that you can also use :c:func:`spin_lock_irq()` or
|
||||||
:c:func:`spin_lock_irqsave()` here, which stop hardware interrupts
|
: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
|
This works perfectly for UP as well: the spin lock vanishes, and this
|
||||||
macro simply becomes :c:func:`local_bh_disable()`
|
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
|
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
|
going so far as to use a softirq, you probably care about scalable
|
||||||
performance enough to justify the extra complexity.
|
performance enough to justify the extra complexity.
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ and it's also much more restricted in the latter case:
|
||||||
appropriate mapping protection capabilities. Ramfs, romfs, cramfs
|
appropriate mapping protection capabilities. Ramfs, romfs, cramfs
|
||||||
and mtd might all permit this.
|
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
|
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
|
appropriate bit of the file will be read into a contiguous bit of
|
||||||
memory and any extraneous space beyond the EOF will be cleared
|
memory and any extraneous space beyond the EOF will be cleared
|
||||||
|
|
|
@ -134,7 +134,7 @@ and their maintainers are:
|
||||||
4.4 Greg Kroah-Hartman (very long-term stable kernel)
|
4.4 Greg Kroah-Hartman (very long-term stable kernel)
|
||||||
4.9 Greg Kroah-Hartman
|
4.9 Greg Kroah-Hartman
|
||||||
4.14 Greg Kroah-Hartman
|
4.14 Greg Kroah-Hartman
|
||||||
====== ====================== ===========================
|
====== ====================== ==============================
|
||||||
|
|
||||||
The selection of a kernel for long-term support is purely a matter of a
|
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
|
maintainer having the need and the time to maintain that release. There
|
||||||
|
|
|
@ -85,7 +85,7 @@ linux-api@vger.kernel.org.
|
||||||
Here is a list of files that are in the kernel source tree that are
|
Here is a list of files that are in the kernel source tree that are
|
||||||
required reading:
|
required reading:
|
||||||
|
|
||||||
README
|
:ref:`Documentation/admin-guide/README.rst <readme>`
|
||||||
This file gives a short background on the Linux kernel and describes
|
This file gives a short background on the Linux kernel and describes
|
||||||
what is necessary to do to configure and build the kernel. People
|
what is necessary to do to configure and build the kernel. People
|
||||||
who are new to the kernel should start here.
|
who are new to the kernel should start here.
|
||||||
|
|
|
@ -105,7 +105,7 @@ to admit that you are stupid when you haven't **yet** done the really
|
||||||
stupid thing.
|
stupid thing.
|
||||||
|
|
||||||
Then, when it really does turn out to be stupid, people just roll their
|
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
|
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
|
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.
|
might even be amused.
|
||||||
|
|
||||||
The option of being unfailingly polite really doesn't exist. Nobody will
|
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
|
.. [#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.
|
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
|
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
|
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
|
best way of taking the blame: do it for someone else. You'll feel good
|
||||||
for taking the fall, he'll feel good about not getting blamed, and the
|
for taking the fall, they'll feel good about not getting blamed, and the
|
||||||
guy who lost his whole 36GB porn-collection because of your incompetence
|
person who lost their whole 36GB porn-collection because of your
|
||||||
will grudgingly admit that you at least didn't try to weasel out of it.
|
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
|
Then make the developer who really screwed up (if you can find them) know
|
||||||
**in_private** that he screwed up. Not just so he can avoid it in the
|
**in_private** that they screwed up. Not just so they can avoid it in the
|
||||||
future, but so that he knows he owes you one. And, perhaps even more
|
future, but so that they know they owe you one. And, perhaps even more
|
||||||
importantly, he's also likely the person who can fix it. Because, let's
|
importantly, they're also likely the person who can fix it. Because, let's
|
||||||
face it, it sure ain't you.
|
face it, it sure ain't you.
|
||||||
|
|
||||||
Taking the blame is also why you get to be manager in the first place.
|
Taking the blame is also why you get to be manager in the first place.
|
||||||
|
|
|
@ -47,7 +47,7 @@ class KernelDocDirective(Directive):
|
||||||
optional_arguments = 4
|
optional_arguments = 4
|
||||||
option_spec = {
|
option_spec = {
|
||||||
'doc': directives.unchanged_required,
|
'doc': directives.unchanged_required,
|
||||||
'functions': directives.unchanged_required,
|
'functions': directives.unchanged,
|
||||||
'export': directives.unchanged,
|
'export': directives.unchanged,
|
||||||
'internal': directives.unchanged,
|
'internal': directives.unchanged,
|
||||||
}
|
}
|
||||||
|
@ -75,8 +75,12 @@ class KernelDocDirective(Directive):
|
||||||
elif 'doc' in self.options:
|
elif 'doc' in self.options:
|
||||||
cmd += ['-function', str(self.options.get('doc'))]
|
cmd += ['-function', str(self.options.get('doc'))]
|
||||||
elif 'functions' in self.options:
|
elif 'functions' in self.options:
|
||||||
for f in str(self.options.get('functions')).split():
|
functions = self.options.get('functions').split()
|
||||||
cmd += ['-function', f]
|
if functions:
|
||||||
|
for f in functions:
|
||||||
|
cmd += ['-function', f]
|
||||||
|
else:
|
||||||
|
cmd += ['-no-doc-sections']
|
||||||
|
|
||||||
for pattern in export_file_patterns:
|
for pattern in export_file_patterns:
|
||||||
for f in glob.glob(env.config.kerneldoc_srctree + '/' + pattern):
|
for f in glob.glob(env.config.kerneldoc_srctree + '/' + pattern):
|
||||||
|
|
|
@ -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>]
|
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
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ Currently, these files are in /proc/sys/vm:
|
||||||
- dirty_bytes
|
- dirty_bytes
|
||||||
- dirty_expire_centisecs
|
- dirty_expire_centisecs
|
||||||
- dirty_ratio
|
- dirty_ratio
|
||||||
|
- dirtytime_expire_seconds
|
||||||
- dirty_writeback_centisecs
|
- dirty_writeback_centisecs
|
||||||
- drop_caches
|
- drop_caches
|
||||||
- extfrag_threshold
|
- extfrag_threshold
|
||||||
|
@ -44,6 +45,7 @@ Currently, these files are in /proc/sys/vm:
|
||||||
- mmap_rnd_bits
|
- mmap_rnd_bits
|
||||||
- mmap_rnd_compat_bits
|
- mmap_rnd_compat_bits
|
||||||
- nr_hugepages
|
- nr_hugepages
|
||||||
|
- nr_hugepages_mempolicy
|
||||||
- nr_overcommit_hugepages
|
- nr_overcommit_hugepages
|
||||||
- nr_trim_pages (only if CONFIG_MMU=n)
|
- nr_trim_pages (only if CONFIG_MMU=n)
|
||||||
- numa_zonelist_order
|
- 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
|
dirty_writeback_centisecs
|
||||||
|
|
||||||
The kernel flusher threads will periodically wake up and write `old' data
|
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
|
nr_overcommit_hugepages
|
||||||
|
|
||||||
Change the maximum size of the hugepage pool. The maximum is
|
Change the maximum size of the hugepage pool. The maximum is
|
||||||
|
|
|
@ -27,7 +27,7 @@ a Linux system will eventually read the clock source to determine exactly
|
||||||
what time it is.
|
what time it is.
|
||||||
|
|
||||||
Typically the clock source is a monotonic, atomic counter which will provide
|
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
|
It will ideally NEVER stop ticking as long as the system is running. It
|
||||||
may stop during system suspend.
|
may stop during system suspend.
|
||||||
|
|
||||||
|
|
|
@ -524,4 +524,4 @@ The following commands are supported:
|
||||||
totals derived from one or more trace event format fields and/or
|
totals derived from one or more trace event format fields and/or
|
||||||
event counts (hitcount).
|
event counts (hitcount).
|
||||||
|
|
||||||
See Documentation/trace/histogram.txt for details and examples.
|
See Documentation/trace/histogram.rst for details and examples.
|
||||||
|
|
|
@ -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
|
track of the time spent in those functions. The histogram
|
||||||
content can be displayed in the files:
|
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.
|
A directory that holds different tracing stats.
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -18,6 +18,7 @@ Linux Tracing Technologies
|
||||||
events-nmi
|
events-nmi
|
||||||
events-msr
|
events-msr
|
||||||
mmiotrace
|
mmiotrace
|
||||||
|
histogram
|
||||||
hwlat_detector
|
hwlat_detector
|
||||||
intel_th
|
intel_th
|
||||||
stm
|
stm
|
||||||
|
|
|
@ -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
|
Similar to the events tracer, this doesn't need to be activated via
|
||||||
current_tracer. Instead of that, add probe points via
|
current_tracer. Instead of that, add probe points via
|
||||||
/sys/kernel/debug/tracing/kprobe_events, and enable it 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
|
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
|
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
|
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',
|
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.
|
You can enable/disable the probe by writing 1 or 0 on it.
|
||||||
|
|
||||||
format:
|
format:
|
||||||
|
@ -95,6 +95,9 @@ filter:
|
||||||
id:
|
id:
|
||||||
This shows the id of this probe event.
|
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
|
Event Profiling
|
||||||
---------------
|
---------------
|
||||||
|
|
|
@ -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
|
Similar to the kprobe-event tracer, this doesn't need to be activated via
|
||||||
current_tracer. Instead of that, add probe points via
|
current_tracer. Instead of that, add probe points via
|
||||||
/sys/kernel/debug/tracing/uprobe_events, and enable it 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
|
However unlike kprobe-event tracer, the uprobe event interface expects the
|
||||||
user to calculate the offset of the probepoint in the object.
|
user to calculate the offset of the probepoint in the object.
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
.. _translations:
|
||||||
|
|
||||||
|
============
|
||||||
|
Translations
|
||||||
|
============
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
zh_CN/index
|
||||||
|
it_IT/index
|
||||||
|
ko_KR/index
|
||||||
|
ja_JP/index
|
|
@ -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.
|
|
@ -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`
|
|
@ -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
|
|
@ -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.
|
|
@ -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>
|
|
@ -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
|
|
@ -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.
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
If you have any comment or update to the content, please contact the
|
||||||
original document maintainer directly. However, if you have a problem
|
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>
|
Chinese maintainer: Dave Young <hidave.darkstar@gmail.com>
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
Documentation/admin-guide/oops-tracing.rst 的中文翻译
|
Documentation/admin-guide/bug-hunting.rst 的中文翻译
|
||||||
|
|
||||||
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
|
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
|
||||||
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
|
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
|
||||||
|
|
|
@ -4406,6 +4406,12 @@ X: Documentation/spi
|
||||||
X: Documentation/media
|
X: Documentation/media
|
||||||
T: git git://git.lwn.net/linux.git docs-next
|
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
|
DONGWOON DW9714 LENS VOICE COIL DRIVER
|
||||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||||
L: linux-media@vger.kernel.org
|
L: linux-media@vger.kernel.org
|
||||||
|
@ -7034,7 +7040,7 @@ M: Guenter Roeck <linux@roeck-us.net>
|
||||||
L: linux-hwmon@vger.kernel.org
|
L: linux-hwmon@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/hwmon/ina209
|
F: Documentation/hwmon/ina209
|
||||||
F: Documentation/devicetree/bindings/i2c/ina209.txt
|
F: Documentation/devicetree/bindings/hwmon/ina2xx.txt
|
||||||
F: drivers/hwmon/ina209.c
|
F: drivers/hwmon/ina209.c
|
||||||
|
|
||||||
INA2XX HARDWARE MONITOR DRIVER
|
INA2XX HARDWARE MONITOR DRIVER
|
||||||
|
|
|
@ -27,9 +27,20 @@ extern unsigned long max_pfn;
|
||||||
extern unsigned long long max_possible_pfn;
|
extern unsigned long long max_possible_pfn;
|
||||||
|
|
||||||
#ifndef CONFIG_NO_BOOTMEM
|
#ifndef CONFIG_NO_BOOTMEM
|
||||||
/*
|
/**
|
||||||
* node_bootmem_map is a map pointer - the bits represent all physical
|
* struct bootmem_data - per-node information used by the bootmem allocator
|
||||||
* memory pages (including holes) on the node.
|
* @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 {
|
typedef struct bootmem_data {
|
||||||
unsigned long node_min_pfn;
|
unsigned long node_min_pfn;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#include <linux/errno.h>
|
#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 */
|
/* make these flag values available regardless of GPIO kconfig options */
|
||||||
#define GPIOF_DIR_OUT (0 << 0)
|
#define GPIOF_DIR_OUT (0 << 0)
|
||||||
|
|
|
@ -20,31 +20,60 @@
|
||||||
#define INIT_MEMBLOCK_REGIONS 128
|
#define INIT_MEMBLOCK_REGIONS 128
|
||||||
#define INIT_PHYSMEM_REGIONS 4
|
#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_NONE = 0x0, /* No special request */
|
||||||
MEMBLOCK_HOTPLUG = 0x1, /* hotpluggable region */
|
MEMBLOCK_HOTPLUG = 0x1, /* hotpluggable region */
|
||||||
MEMBLOCK_MIRROR = 0x2, /* mirrored region */
|
MEMBLOCK_MIRROR = 0x2, /* mirrored region */
|
||||||
MEMBLOCK_NOMAP = 0x4, /* don't add to kernel direct mapping */
|
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 {
|
struct memblock_region {
|
||||||
phys_addr_t base;
|
phys_addr_t base;
|
||||||
phys_addr_t size;
|
phys_addr_t size;
|
||||||
unsigned long flags;
|
enum memblock_flags flags;
|
||||||
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
|
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
|
||||||
int nid;
|
int nid;
|
||||||
#endif
|
#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 {
|
struct memblock_type {
|
||||||
unsigned long cnt; /* number of regions */
|
unsigned long cnt;
|
||||||
unsigned long max; /* size of the allocated array */
|
unsigned long max;
|
||||||
phys_addr_t total_size; /* size of all regions */
|
phys_addr_t total_size;
|
||||||
struct memblock_region *regions;
|
struct memblock_region *regions;
|
||||||
char *name;
|
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 {
|
struct memblock {
|
||||||
bool bottom_up; /* is bottom up direction? */
|
bool bottom_up; /* is bottom up direction? */
|
||||||
phys_addr_t current_limit;
|
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 memblock_find_in_range_node(phys_addr_t size, phys_addr_t align,
|
||||||
phys_addr_t start, phys_addr_t end,
|
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 memblock_find_in_range(phys_addr_t start, phys_addr_t end,
|
||||||
phys_addr_t size, phys_addr_t align);
|
phys_addr_t size, phys_addr_t align);
|
||||||
void memblock_allow_resize(void);
|
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_mirror(phys_addr_t base, phys_addr_t size);
|
||||||
int memblock_mark_nomap(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);
|
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 */
|
/* Low level functions */
|
||||||
int memblock_add_range(struct memblock_type *type,
|
int memblock_add_range(struct memblock_type *type,
|
||||||
phys_addr_t base, phys_addr_t size,
|
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_a,
|
||||||
struct memblock_type *type_b, phys_addr_t *out_start,
|
struct memblock_type *type_b, phys_addr_t *out_start,
|
||||||
phys_addr_t *out_end, int *out_nid);
|
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_a,
|
||||||
struct memblock_type *type_b, phys_addr_t *out_start,
|
struct memblock_type *type_b, phys_addr_t *out_start,
|
||||||
phys_addr_t *out_end, int *out_nid);
|
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
|
* for_each_resv_unavail_range - iterate through reserved and unavailable memory
|
||||||
* @i: u64 used as loop variable
|
* @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_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
|
* @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)
|
NUMA_NO_NODE, MEMBLOCK_NONE, p_start, p_end, NULL)
|
||||||
|
|
||||||
static inline void memblock_set_region_flags(struct memblock_region *r,
|
static inline void memblock_set_region_flags(struct memblock_region *r,
|
||||||
unsigned long flags)
|
enum memblock_flags flags)
|
||||||
{
|
{
|
||||||
r->flags |= flags;
|
r->flags |= flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void memblock_clear_region_flags(struct memblock_region *r,
|
static inline void memblock_clear_region_flags(struct memblock_region *r,
|
||||||
unsigned long flags)
|
enum memblock_flags flags)
|
||||||
{
|
{
|
||||||
r->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 __init memblock_alloc_range(phys_addr_t size, phys_addr_t align,
|
||||||
phys_addr_t start, phys_addr_t end,
|
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 memblock_alloc_base_nid(phys_addr_t size,
|
||||||
phys_addr_t align, phys_addr_t max_addr,
|
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 memblock_alloc_base(phys_addr_t size, phys_addr_t align,
|
||||||
phys_addr_t max_addr);
|
phys_addr_t max_addr);
|
||||||
phys_addr_t __memblock_alloc_base(phys_addr_t size, phys_addr_t align,
|
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
|
* @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)
|
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
|
* @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)
|
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
|
* @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)
|
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
|
* @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)
|
static inline unsigned long memblock_region_reserved_end_pfn(const struct memblock_region *reg)
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,6 +20,21 @@ extern int do_settimeofday64(const struct timespec64 *ts);
|
||||||
extern int do_sys_settimeofday64(const struct timespec64 *tv,
|
extern int do_sys_settimeofday64(const struct timespec64 *tv,
|
||||||
const struct timezone *tz);
|
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
|
* timespec64 based interfaces
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -521,7 +521,7 @@ config FUNCTION_PROFILER
|
||||||
in debugfs called function_profile_enabled which defaults to zero.
|
in debugfs called function_profile_enabled which defaults to zero.
|
||||||
When a 1 is echoed into this file profiling begins, and when a
|
When a 1 is echoed into this file profiling begins, and when a
|
||||||
zero is entered, profiling stops. A "functions" file is created in
|
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.
|
have been hit and their counters.
|
||||||
|
|
||||||
If in doubt, say N.
|
If in doubt, say N.
|
||||||
|
@ -605,7 +605,7 @@ config HIST_TRIGGERS
|
||||||
Inter-event tracing of quantities such as latencies is also
|
Inter-event tracing of quantities such as latencies is also
|
||||||
supported using hist triggers under this option.
|
supported using hist triggers under this option.
|
||||||
|
|
||||||
See Documentation/trace/histogram.txt.
|
See Documentation/trace/histogram.rst.
|
||||||
If in doubt, say N.
|
If in doubt, say N.
|
||||||
|
|
||||||
config MMIOTRACE_TEST
|
config MMIOTRACE_TEST
|
||||||
|
|
|
@ -283,7 +283,7 @@ static struct rs_control *init_rs_internal(int symsize, int gfpoly,
|
||||||
* in index form
|
* in index form
|
||||||
* @prim: primitive element to generate polynomial roots
|
* @prim: primitive element to generate polynomial roots
|
||||||
* @nroots: RS code generator polynomial degree (number of 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,
|
struct rs_control *init_rs_gfp(int symsize, int gfpoly, int fcr, int prim,
|
||||||
int nroots, gfp_t gfp)
|
int nroots, gfp_t gfp)
|
||||||
|
|
159
mm/bootmem.c
159
mm/bootmem.c
|
@ -21,6 +21,53 @@
|
||||||
|
|
||||||
#include "internal.h"
|
#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
|
#ifndef CONFIG_NEED_MULTIPLE_NODES
|
||||||
struct pglist_data __refdata contig_page_data = {
|
struct pglist_data __refdata contig_page_data = {
|
||||||
.bdata = &bootmem_node_data[0]
|
.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
|
* bootmem_bootmap_pages - calculate bitmap size in pages
|
||||||
* @pages: number of pages the bitmap has to represent
|
* @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)
|
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
|
* @startpfn: first pfn on the node
|
||||||
* @endpfn: first pfn after 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 __init init_bootmem_node(pg_data_t *pgdat, unsigned long freepfn,
|
||||||
unsigned long startpfn, unsigned long endpfn)
|
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
|
* @start: pfn where the bitmap is to be placed
|
||||||
* @pages: number of available physical pages
|
* @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)
|
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);
|
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)
|
void __init free_bootmem_late(unsigned long physaddr, unsigned long size)
|
||||||
{
|
{
|
||||||
unsigned long cursor, end;
|
unsigned long cursor, end;
|
||||||
|
@ -264,11 +304,6 @@ void __init reset_all_zones_managed_pages(void)
|
||||||
reset_managed_pages_done = 1;
|
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 __init free_all_bootmem(void)
|
||||||
{
|
{
|
||||||
unsigned long total_pages = 0;
|
unsigned long total_pages = 0;
|
||||||
|
@ -385,16 +420,6 @@ static int __init mark_bootmem(unsigned long start, unsigned long end,
|
||||||
BUG();
|
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,
|
void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
|
||||||
unsigned long size)
|
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);
|
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)
|
void __init free_bootmem(unsigned long physaddr, unsigned long size)
|
||||||
{
|
{
|
||||||
unsigned long start, end;
|
unsigned long start, end;
|
||||||
|
@ -439,6 +455,8 @@ void __init free_bootmem(unsigned long physaddr, unsigned long size)
|
||||||
* Partial pages will be reserved.
|
* Partial pages will be reserved.
|
||||||
*
|
*
|
||||||
* The range must reside completely on the specified node.
|
* 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,
|
int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
|
||||||
unsigned long size, int flags)
|
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.
|
* Partial pages will be reserved.
|
||||||
*
|
*
|
||||||
* The range must be contiguous but may span node boundaries.
|
* 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 __init reserve_bootmem(unsigned long addr, unsigned long size,
|
||||||
int flags)
|
int flags)
|
||||||
|
@ -646,19 +666,6 @@ static void * __init ___alloc_bootmem_nopanic(unsigned long size,
|
||||||
return NULL;
|
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,
|
void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align,
|
||||||
unsigned long goal)
|
unsigned long goal)
|
||||||
{
|
{
|
||||||
|
@ -682,19 +689,6 @@ static void * __init ___alloc_bootmem(unsigned long size, unsigned long align,
|
||||||
return NULL;
|
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,
|
void * __init __alloc_bootmem(unsigned long size, unsigned long align,
|
||||||
unsigned long goal)
|
unsigned long goal)
|
||||||
{
|
{
|
||||||
|
@ -754,21 +748,6 @@ void * __init ___alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
|
||||||
return NULL;
|
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,
|
void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
|
||||||
unsigned long align, unsigned long goal)
|
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,
|
void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,
|
||||||
unsigned long goal)
|
unsigned long goal)
|
||||||
{
|
{
|
||||||
|
@ -834,21 +800,6 @@ void * __init __alloc_bootmem_low_nopanic(unsigned long size,
|
||||||
ARCH_LOW_ADDRESS_LIMIT);
|
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,
|
void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size,
|
||||||
unsigned long align, unsigned long goal)
|
unsigned long align, unsigned long goal)
|
||||||
{
|
{
|
||||||
|
|
203
mm/memblock.c
203
mm/memblock.c
|
@ -27,6 +27,61 @@
|
||||||
|
|
||||||
#include "internal.h"
|
#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_memory_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;
|
||||||
static struct memblock_region memblock_reserved_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
|
#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_memory_in_slab __initdata_memblock = 0;
|
||||||
static int memblock_reserved_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;
|
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;
|
return i < type->cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* __memblock_find_range_bottom_up - find free area utility in bottom-up
|
* __memblock_find_range_bottom_up - find free area utility in bottom-up
|
||||||
* @start: start of candidate 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
|
* @size: size of free area to find
|
||||||
* @align: alignment 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
|
* @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.
|
* Utility called from memblock_find_in_range_node(), find free area bottom-up.
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* Return:
|
||||||
* Found address on success, 0 on failure.
|
* Found address on success, 0 on failure.
|
||||||
*/
|
*/
|
||||||
static phys_addr_t __init_memblock
|
static phys_addr_t __init_memblock
|
||||||
__memblock_find_range_bottom_up(phys_addr_t start, phys_addr_t end,
|
__memblock_find_range_bottom_up(phys_addr_t start, phys_addr_t end,
|
||||||
phys_addr_t size, phys_addr_t align, int nid,
|
phys_addr_t size, phys_addr_t align, int nid,
|
||||||
ulong flags)
|
enum memblock_flags flags)
|
||||||
{
|
{
|
||||||
phys_addr_t this_start, this_end, cand;
|
phys_addr_t this_start, this_end, cand;
|
||||||
u64 i;
|
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
|
* __memblock_find_range_top_down - find free area utility, in top-down
|
||||||
* @start: start of candidate 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
|
* @size: size of free area to find
|
||||||
* @align: alignment 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
|
* @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.
|
* Utility called from memblock_find_in_range_node(), find free area top-down.
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* Return:
|
||||||
* Found address on success, 0 on failure.
|
* Found address on success, 0 on failure.
|
||||||
*/
|
*/
|
||||||
static phys_addr_t __init_memblock
|
static phys_addr_t __init_memblock
|
||||||
__memblock_find_range_top_down(phys_addr_t start, phys_addr_t end,
|
__memblock_find_range_top_down(phys_addr_t start, phys_addr_t end,
|
||||||
phys_addr_t size, phys_addr_t align, int nid,
|
phys_addr_t size, phys_addr_t align, int nid,
|
||||||
ulong flags)
|
enum memblock_flags flags)
|
||||||
{
|
{
|
||||||
phys_addr_t this_start, this_end, cand;
|
phys_addr_t this_start, this_end, cand;
|
||||||
u64 i;
|
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
|
* @size: size of free area to find
|
||||||
* @align: alignment of free area to find
|
* @align: alignment of free area to find
|
||||||
* @start: start of candidate 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
|
||||||
* @nid: nid of the free area to find, %NUMA_NO_NODE for any node
|
* @nid: nid of the free area to find, %NUMA_NO_NODE for any node
|
||||||
* @flags: pick from blocks based on memory attributes
|
* @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.
|
* If bottom-up allocation failed, will try to allocate memory top-down.
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* Return:
|
||||||
* Found address on success, 0 on failure.
|
* Found address on success, 0 on failure.
|
||||||
*/
|
*/
|
||||||
phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size,
|
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 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;
|
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
|
* memblock_find_in_range - find free area in given range
|
||||||
* @start: start of candidate 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
|
* @size: size of free area to find
|
||||||
* @align: alignment of free area to find
|
* @align: alignment of free area to find
|
||||||
*
|
*
|
||||||
* Find @size free area aligned to @align in the specified range.
|
* Find @size free area aligned to @align in the specified range.
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* Return:
|
||||||
* Found address on success, 0 on failure.
|
* Found address on success, 0 on failure.
|
||||||
*/
|
*/
|
||||||
phys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start,
|
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 align)
|
||||||
{
|
{
|
||||||
phys_addr_t ret;
|
phys_addr_t ret;
|
||||||
ulong flags = choose_memblock_flags();
|
enum memblock_flags flags = choose_memblock_flags();
|
||||||
|
|
||||||
again:
|
again:
|
||||||
ret = memblock_find_in_range_node(size, align, start, end,
|
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
|
#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)
|
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
|
* 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
|
* 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
|
* waiting to be reserved, ensure the memory used by the new array does
|
||||||
* not overlap.
|
* not overlap.
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* Return:
|
||||||
* 0 on success, -1 on failure.
|
* 0 on success, -1 on failure.
|
||||||
*/
|
*/
|
||||||
static int __init_memblock memblock_double_array(struct memblock_type *type,
|
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
|
* @nid: node id of the new region
|
||||||
* @flags: flags 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.
|
* @type must already have extra room to accommodate the new region.
|
||||||
*/
|
*/
|
||||||
static void __init_memblock memblock_insert_region(struct memblock_type *type,
|
static void __init_memblock memblock_insert_region(struct memblock_type *type,
|
||||||
int idx, phys_addr_t base,
|
int idx, phys_addr_t base,
|
||||||
phys_addr_t size,
|
phys_addr_t size,
|
||||||
int nid, unsigned long flags)
|
int nid,
|
||||||
|
enum memblock_flags flags)
|
||||||
{
|
{
|
||||||
struct memblock_region *rgn = &type->regions[idx];
|
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
|
* @nid: nid of the new region
|
||||||
* @flags: flags 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
|
* is allowed to overlap with existing ones - overlaps don't affect already
|
||||||
* existing regions. @type is guaranteed to be minimal (all neighbouring
|
* existing regions. @type is guaranteed to be minimal (all neighbouring
|
||||||
* compatible regions are merged) after the addition.
|
* compatible regions are merged) after the addition.
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* Return:
|
||||||
* 0 on success, -errno on failure.
|
* 0 on success, -errno on failure.
|
||||||
*/
|
*/
|
||||||
int __init_memblock memblock_add_range(struct memblock_type *type,
|
int __init_memblock memblock_add_range(struct memblock_type *type,
|
||||||
phys_addr_t base, phys_addr_t size,
|
phys_addr_t base, phys_addr_t size,
|
||||||
int nid, unsigned long flags)
|
int nid, enum memblock_flags flags)
|
||||||
{
|
{
|
||||||
bool insert = false;
|
bool insert = false;
|
||||||
phys_addr_t obase = base;
|
phys_addr_t obase = base;
|
||||||
|
@ -590,12 +651,35 @@ int __init_memblock memblock_add_range(struct memblock_type *type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 __init_memblock memblock_add_node(phys_addr_t base, phys_addr_t size,
|
||||||
int nid)
|
int nid)
|
||||||
{
|
{
|
||||||
return memblock_add_range(&memblock.memory, base, size, nid, 0);
|
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)
|
int __init_memblock memblock_add(phys_addr_t base, phys_addr_t size)
|
||||||
{
|
{
|
||||||
phys_addr_t end = base + size - 1;
|
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
|
* @end_rgn: out parameter for the end of isolated region
|
||||||
*
|
*
|
||||||
* Walk @type and ensure that regions don't cross the boundaries defined by
|
* 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
|
* 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.
|
* region inside the range is returned in *@start_rgn and end in *@end_rgn.
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* Return:
|
||||||
* 0 on success, -errno on failure.
|
* 0 on success, -errno on failure.
|
||||||
*/
|
*/
|
||||||
static int __init_memblock memblock_isolate_range(struct memblock_type *type,
|
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
|
* 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,
|
static int __init_memblock memblock_setclr_flag(phys_addr_t base,
|
||||||
phys_addr_t size, int set, int flag)
|
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
|
* @base: the base phys addr of the region
|
||||||
* @size: the size 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)
|
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
|
* @base: the base phys addr of the region
|
||||||
* @size: the size 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)
|
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
|
* @base: the base phys addr of the region
|
||||||
* @size: the size 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)
|
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
|
* @base: the base phys addr of the region
|
||||||
* @size: the size 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)
|
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
|
* @base: the base phys addr of the region
|
||||||
* @size: the size 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)
|
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
|
* As both region arrays are sorted, the function advances the two indices
|
||||||
* in lockstep and returns each intersection.
|
* 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_a,
|
||||||
struct memblock_type *type_b,
|
struct memblock_type *type_b,
|
||||||
phys_addr_t *out_start,
|
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()
|
* __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
|
* @idx: pointer to u64 loop variable
|
||||||
* @nid: node selector, %NUMA_NO_NODE for all nodes
|
* @nid: node selector, %NUMA_NO_NODE for all nodes
|
||||||
* @flags: pick from blocks based on memory attributes
|
* @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_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
|
* @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().
|
* 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_a,
|
||||||
struct memblock_type *type_b,
|
struct memblock_type *type_b,
|
||||||
phys_addr_t *out_start,
|
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
|
* @type: memblock type to set node ID for
|
||||||
* @nid: node ID to set
|
* @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.
|
* Regions which cross the area boundaries are split as necessary.
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* Return:
|
||||||
* 0 on success, -errno on failure.
|
* 0 on success, -errno on failure.
|
||||||
*/
|
*/
|
||||||
int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size,
|
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,
|
static phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size,
|
||||||
phys_addr_t align, phys_addr_t start,
|
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;
|
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 __init memblock_alloc_range(phys_addr_t size, phys_addr_t align,
|
||||||
phys_addr_t start, phys_addr_t end,
|
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,
|
return memblock_alloc_range_nid(size, align, start, end, NUMA_NO_NODE,
|
||||||
flags);
|
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 __init memblock_alloc_base_nid(phys_addr_t size,
|
||||||
phys_addr_t align, phys_addr_t max_addr,
|
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);
|
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)
|
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;
|
phys_addr_t ret;
|
||||||
|
|
||||||
again:
|
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
|
* The allocation is performed from memory region limited by
|
||||||
* memblock.current_limit if @max_addr == %BOOTMEM_ALLOC_ACCESSIBLE.
|
* 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
|
* The phys address of allocated boot memory block is converted to virtual and
|
||||||
* allocated memory is reset to 0.
|
* 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
|
* 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.
|
* 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.
|
* Virtual address of allocated memory block on success, NULL on failure.
|
||||||
*/
|
*/
|
||||||
static void * __init memblock_virt_alloc_internal(
|
static void * __init memblock_virt_alloc_internal(
|
||||||
|
@ -1261,7 +1353,7 @@ static void * __init memblock_virt_alloc_internal(
|
||||||
{
|
{
|
||||||
phys_addr_t alloc;
|
phys_addr_t alloc;
|
||||||
void *ptr;
|
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"))
|
if (WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n"))
|
||||||
nid = NUMA_NO_NODE;
|
nid = NUMA_NO_NODE;
|
||||||
|
@ -1336,7 +1428,7 @@ static void * __init memblock_virt_alloc_internal(
|
||||||
* info), if enabled. Does not zero allocated memory, does not panic if request
|
* info), if enabled. Does not zero allocated memory, does not panic if request
|
||||||
* cannot be satisfied.
|
* cannot be satisfied.
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* Return:
|
||||||
* Virtual address of allocated memory block on success, NULL on failure.
|
* Virtual address of allocated memory block on success, NULL on failure.
|
||||||
*/
|
*/
|
||||||
void * __init memblock_virt_alloc_try_nid_raw(
|
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
|
* Public function, provides additional debug information (including caller
|
||||||
* info), if enabled. This function zeroes the allocated memory.
|
* info), if enabled. This function zeroes the allocated memory.
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* Return:
|
||||||
* Virtual address of allocated memory block on success, NULL on failure.
|
* Virtual address of allocated memory block on success, NULL on failure.
|
||||||
*/
|
*/
|
||||||
void * __init memblock_virt_alloc_try_nid_nopanic(
|
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,
|
* which provides debug information (including caller info), if enabled,
|
||||||
* and panics if the request can not be satisfied.
|
* and panics if the request can not be satisfied.
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* Return:
|
||||||
* Virtual address of allocated memory block on success, NULL on failure.
|
* Virtual address of allocated memory block on success, NULL on failure.
|
||||||
*/
|
*/
|
||||||
void * __init memblock_virt_alloc_try_nid(
|
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_remove_range(&memblock.reserved, base, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* __memblock_free_late - free bootmem block pages directly to buddy allocator
|
* __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
|
* @size: size of the boot memory block in bytes
|
||||||
*
|
*
|
||||||
* This is only useful when the bootmem allocator has already been torn
|
* 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
|
* @base: base of region to check
|
||||||
* @size: size 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
|
* 0 if false, non-zero if true
|
||||||
*/
|
*/
|
||||||
bool __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size)
|
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
|
* @base: base of region to check
|
||||||
* @size: size 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.
|
* True if they intersect, false if not.
|
||||||
*/
|
*/
|
||||||
bool __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size)
|
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)
|
static void __init_memblock memblock_dump(struct memblock_type *type)
|
||||||
{
|
{
|
||||||
phys_addr_t base, end, size;
|
phys_addr_t base, end, size;
|
||||||
unsigned long flags;
|
enum memblock_flags flags;
|
||||||
int idx;
|
int idx;
|
||||||
struct memblock_region *rgn;
|
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",
|
snprintf(nid_buf, sizeof(nid_buf), " on node %d",
|
||||||
memblock_get_region_node(rgn));
|
memblock_get_region_node(rgn));
|
||||||
#endif
|
#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);
|
type->name, idx, &base, &end, &size, nid_buf, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ static void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
|
||||||
{
|
{
|
||||||
void *ptr;
|
void *ptr;
|
||||||
u64 addr;
|
u64 addr;
|
||||||
ulong flags = choose_memblock_flags();
|
enum memblock_flags flags = choose_memblock_flags();
|
||||||
|
|
||||||
if (limit > memblock.current_limit)
|
if (limit > memblock.current_limit)
|
||||||
limit = memblock.current_limit;
|
limit = memblock.current_limit;
|
||||||
|
@ -72,7 +72,7 @@ static void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* free_bootmem_late - free bootmem pages directly to page allocator
|
* free_bootmem_late - free bootmem pages directly to page allocator
|
||||||
* @addr: starting address of the range
|
* @addr: starting address of the range
|
||||||
* @size: size of the range in bytes
|
* @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
|
* 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)
|
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
|
* free_bootmem_node - mark a page range as usable
|
||||||
* @pgdat: node the range resides on
|
* @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
|
* @size: size of the range in bytes
|
||||||
*
|
*
|
||||||
* Partial pages will be considered reserved and left as they are.
|
* 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
|
* 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
|
* @size: size of the range in bytes
|
||||||
*
|
*
|
||||||
* Partial pages will be considered reserved and left as they are.
|
* Partial pages will be considered reserved and left as they are.
|
||||||
|
@ -256,7 +256,7 @@ static void * __init ___alloc_bootmem_nopanic(unsigned long size,
|
||||||
*
|
*
|
||||||
* Allocation may happen on any node in the system.
|
* 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,
|
void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align,
|
||||||
unsigned long goal)
|
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.
|
* Allocation may happen on any node in the system.
|
||||||
*
|
*
|
||||||
* The function panics if the request can not be satisfied.
|
* 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,
|
void * __init __alloc_bootmem(unsigned long size, unsigned long align,
|
||||||
unsigned long goal)
|
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.
|
* can not hold the requested memory.
|
||||||
*
|
*
|
||||||
* The function panics if the request can not be satisfied.
|
* 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,
|
void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
|
||||||
unsigned long align, unsigned long goal)
|
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.
|
* Allocation may happen on any node in the system.
|
||||||
*
|
*
|
||||||
* The function panics if the request can not be satisfied.
|
* 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,
|
void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,
|
||||||
unsigned long goal)
|
unsigned long goal)
|
||||||
|
@ -425,6 +431,8 @@ void * __init __alloc_bootmem_low_nopanic(unsigned long size,
|
||||||
* can not hold the requested memory.
|
* can not hold the requested memory.
|
||||||
*
|
*
|
||||||
* The function panics if the request can not be satisfied.
|
* 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,
|
void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size,
|
||||||
unsigned long align, unsigned long goal)
|
unsigned long align, unsigned long goal)
|
||||||
|
|
|
@ -75,6 +75,12 @@ while (<IN>) {
|
||||||
# Remove URL false-positives
|
# Remove URL false-positives
|
||||||
next if ($fulref =~ m/^http/);
|
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
|
# Check if exists, evaluating wildcards
|
||||||
next if (grep -e, glob("$ref $fulref"));
|
next if (grep -e, glob("$ref $fulref"));
|
||||||
|
|
||||||
|
|
|
@ -1062,7 +1062,7 @@ sub dump_struct($$) {
|
||||||
my $x = shift;
|
my $x = shift;
|
||||||
my $file = shift;
|
my $file = shift;
|
||||||
|
|
||||||
if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) {
|
if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}/) {
|
||||||
my $decl_type = $1;
|
my $decl_type = $1;
|
||||||
$declaration_name = $2;
|
$declaration_name = $2;
|
||||||
my $members = $3;
|
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
|
# Ignore other nested elements, like enums
|
||||||
$members =~ s/({[^\{\}]*})//g;
|
$members =~ s/(\{[^\{\}]*\})//g;
|
||||||
|
|
||||||
create_parameterlist($members, ';', $file, $declaration_name);
|
create_parameterlist($members, ';', $file, $declaration_name);
|
||||||
check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual);
|
check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual);
|
||||||
|
|
||||||
# Adjust declaration for better display
|
# Adjust declaration for better display
|
||||||
$declaration =~ s/([{;])/$1\n/g;
|
$declaration =~ s/([\{;])/$1\n/g;
|
||||||
$declaration =~ s/}\s+;/};/g;
|
$declaration =~ s/\}\s+;/};/g;
|
||||||
# Better handle inlined enums
|
# 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 @def_args = split /\n/, $declaration;
|
||||||
my $level = 1;
|
my $level = 1;
|
||||||
|
@ -1171,12 +1171,12 @@ sub dump_struct($$) {
|
||||||
$clause =~ s/\s+$//;
|
$clause =~ s/\s+$//;
|
||||||
$clause =~ s/\s+/ /;
|
$clause =~ s/\s+/ /;
|
||||||
next if (!$clause);
|
next if (!$clause);
|
||||||
$level-- if ($clause =~ m/(})/ && $level > 1);
|
$level-- if ($clause =~ m/(\})/ && $level > 1);
|
||||||
if (!($clause =~ m/^\s*#/)) {
|
if (!($clause =~ m/^\s*#/)) {
|
||||||
$declaration .= "\t" x $level;
|
$declaration .= "\t" x $level;
|
||||||
}
|
}
|
||||||
$declaration .= "\t" . $clause . "\n";
|
$declaration .= "\t" . $clause . "\n";
|
||||||
$level++ if ($clause =~ m/({)/ && !($clause =~m/}/));
|
$level++ if ($clause =~ m/(\{)/ && !($clause =~m/\}/));
|
||||||
}
|
}
|
||||||
output_declaration($declaration_name,
|
output_declaration($declaration_name,
|
||||||
'struct',
|
'struct',
|
||||||
|
@ -1244,7 +1244,7 @@ sub dump_enum($$) {
|
||||||
# strip #define macros inside enums
|
# strip #define macros inside enums
|
||||||
$x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos;
|
$x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos;
|
||||||
|
|
||||||
if ($x =~ /enum\s+(\w+)\s*{(.*)}/) {
|
if ($x =~ /enum\s+(\w+)\s*\{(.*)\}/) {
|
||||||
$declaration_name = $1;
|
$declaration_name = $1;
|
||||||
my $members = $2;
|
my $members = $2;
|
||||||
my %_members;
|
my %_members;
|
||||||
|
@ -1785,7 +1785,7 @@ sub process_proto_type($$) {
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if ( $x =~ /([^{};]*)([{};])(.*)/ ) {
|
if ( $x =~ /([^\{\};]*)([\{\};])(.*)/ ) {
|
||||||
if( length $prototype ) {
|
if( length $prototype ) {
|
||||||
$prototype .= " "
|
$prototype .= " "
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue