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/>
|
||||
=============================================
|
||||
|
||||
|
|
|
@ -4136,6 +4136,8 @@
|
|||
This parameter controls whether the Speculative Store
|
||||
Bypass optimization is used.
|
||||
|
||||
On x86 the options are:
|
||||
|
||||
on - Unconditionally disable Speculative Store Bypass
|
||||
off - Unconditionally enable Speculative Store Bypass
|
||||
auto - Kernel detects whether the CPU model contains an
|
||||
|
@ -4151,12 +4153,20 @@
|
|||
seccomp - Same as "prctl" above, but all seccomp threads
|
||||
will disable SSB unless they explicitly opt out.
|
||||
|
||||
Not specifying this option is equivalent to
|
||||
spec_store_bypass_disable=auto.
|
||||
|
||||
Default mitigations:
|
||||
X86: If CONFIG_SECCOMP=y "seccomp", otherwise "prctl"
|
||||
|
||||
On powerpc the options are:
|
||||
|
||||
on,auto - On Power8 and Power9 insert a store-forwarding
|
||||
barrier on kernel entry and exit. On Power7
|
||||
perform a software flush on kernel entry and
|
||||
exit.
|
||||
off - No action.
|
||||
|
||||
Not specifying this option is equivalent to
|
||||
spec_store_bypass_disable=auto.
|
||||
|
||||
spia_io_base= [HW,MTD]
|
||||
spia_fio_base=
|
||||
spia_pedr=
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
Console Drivers
|
||||
===============
|
||||
|
||||
The linux kernel has 2 general types of console drivers. The first type is
|
||||
The Linux kernel has 2 general types of console drivers. The first type is
|
||||
assigned by the kernel to all the virtual consoles during the boot process.
|
||||
This type will be called 'system driver', and only one system driver is allowed
|
||||
to exist. The system driver is persistent and it can never be unloaded, though
|
||||
|
@ -17,10 +17,11 @@ of driver occupying the consoles.) They can only take over the console that is
|
|||
occupied by the system driver. In the same token, if the modular driver is
|
||||
released by the console, the system driver will take over.
|
||||
|
||||
Modular drivers, from the programmer's point of view, has to call:
|
||||
Modular drivers, from the programmer's point of view, have to call:
|
||||
|
||||
do_take_over_console() - load and bind driver to console layer
|
||||
give_up_console() - unload driver, it will only work if driver is fully unbond
|
||||
give_up_console() - unload driver; it will only work if driver
|
||||
is fully unbound
|
||||
|
||||
In newer kernels, the following are also available:
|
||||
|
||||
|
@ -56,7 +57,7 @@ What do these files signify?
|
|||
cat /sys/class/vtconsole/vtcon0/name
|
||||
(S) VGA+
|
||||
|
||||
'(S)' stands for a (S)ystem driver, ie, it cannot be directly
|
||||
'(S)' stands for a (S)ystem driver, i.e., it cannot be directly
|
||||
commanded to bind or unbind
|
||||
|
||||
'VGA+' is the name of the driver
|
||||
|
@ -89,7 +90,7 @@ driver, make changes, recompile, reload and rebind the driver without any need
|
|||
for rebooting the kernel. For regular users who may want to switch from
|
||||
framebuffer console to VGA console and vice versa, this feature also makes
|
||||
this possible. (NOTE NOTE NOTE: Please read fbcon.txt under Documentation/fb
|
||||
for more details).
|
||||
for more details.)
|
||||
|
||||
Notes for developers:
|
||||
=====================
|
||||
|
@ -110,8 +111,8 @@ In order for binding to and unbinding from the console to properly work,
|
|||
console drivers must follow these guidelines:
|
||||
|
||||
1. All drivers, except system drivers, must call either do_register_con_driver()
|
||||
or do_take_over_console(). do_register_con_driver() will just add the driver to
|
||||
the console's internal list. It won't take over the
|
||||
or do_take_over_console(). do_register_con_driver() will just add the driver
|
||||
to the console's internal list. It won't take over the
|
||||
console. do_take_over_console(), as it name implies, will also take over (or
|
||||
bind to) the console.
|
||||
|
||||
|
|
|
@ -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
|
||||
:functions:
|
||||
.. kernel-doc:: lib/idr.c
|
||||
:functions:
|
||||
|
|
|
@ -28,6 +28,8 @@ Core utilities
|
|||
printk-formats
|
||||
circular-buffers
|
||||
gfp_mask-from-fs-io
|
||||
timekeeping
|
||||
boot-time-mm
|
||||
|
||||
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
|
||||
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
|
||||
============
|
||||
|
||||
|
|
|
@ -488,14 +488,19 @@ doc: *title*
|
|||
.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
|
||||
:doc: High Definition Audio over HDMI and Display Port
|
||||
|
||||
functions: *function* *[...]*
|
||||
functions: *[ function ...]*
|
||||
Include documentation for each *function* in *source*.
|
||||
If no *function* if specified, the documentaion for all functions
|
||||
and types in the *source* will be included.
|
||||
|
||||
Example::
|
||||
Examples::
|
||||
|
||||
.. kernel-doc:: lib/bitmap.c
|
||||
:functions: bitmap_parselist bitmap_parselist_user
|
||||
|
||||
.. kernel-doc:: lib/idr.c
|
||||
:functions:
|
||||
|
||||
Without options, the kernel-doc directive includes all documentation comments
|
||||
from the source file.
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ SYNOPSIS
|
|||
|
||||
\ **parse_headers.pl**\ [<options>] <C_FILE> <OUT_FILE> [<EXCEPTIONS_FILE>]
|
||||
|
||||
Where <options> can be: --debug, --help or --man.
|
||||
Where <options> can be: --debug, --help or --usage.
|
||||
|
||||
|
||||
OPTIONS
|
||||
|
@ -133,7 +133,7 @@ For both statements, \ **type**\ can be either one of the following:
|
|||
|
||||
\ **symbol**\
|
||||
|
||||
The ignore or replace statement will apply to the name of enum statements
|
||||
The ignore or replace statement will apply to the name of enum value
|
||||
at C_FILE.
|
||||
|
||||
For replace statements, \ **new_value**\ will automatically use :c:type:
|
||||
|
|
|
@ -28,7 +28,7 @@ The ReST markups currently used by the Documentation/ files are meant to be
|
|||
built with ``Sphinx`` version 1.3 or upper. If you're desiring to build
|
||||
PDF outputs, it is recommended to use version 1.4.6 or upper.
|
||||
|
||||
There's a script that checks for the Spinx requirements. Please see
|
||||
There's a script that checks for the Sphinx requirements. Please see
|
||||
:ref:`sphinx-pre-install` for further details.
|
||||
|
||||
Most distributions are shipped with Sphinx, but its toolchain is fragile,
|
||||
|
|
|
@ -374,7 +374,7 @@ The nand driver supports three different types of hardware ECC.
|
|||
|
||||
- NAND_ECC_HW8_512
|
||||
|
||||
Hardware ECC generator providing 6 bytes ECC per 512 byte.
|
||||
Hardware ECC generator providing 8 bytes ECC per 512 byte.
|
||||
|
||||
If your hardware generator has a different functionality add it at the
|
||||
appropriate place in nand_base.c
|
||||
|
@ -889,7 +889,7 @@ Use these constants to select the ECC algorithm::
|
|||
#define NAND_ECC_HW3_512 3
|
||||
/* Hardware ECC 6 byte ECC per 512 Byte data */
|
||||
#define NAND_ECC_HW6_512 4
|
||||
/* Hardware ECC 6 byte ECC per 512 Byte data */
|
||||
/* Hardware ECC 8 byte ECC per 512 Byte data */
|
||||
#define NAND_ECC_HW8_512 6
|
||||
|
||||
|
||||
|
|
|
@ -532,9 +532,9 @@ More details about quota locking can be found in fs/dquot.c.
|
|||
prototypes:
|
||||
void (*open)(struct vm_area_struct*);
|
||||
void (*close)(struct vm_area_struct*);
|
||||
int (*fault)(struct vm_area_struct*, struct vm_fault *);
|
||||
int (*page_mkwrite)(struct vm_area_struct *, struct vm_fault *);
|
||||
int (*pfn_mkwrite)(struct vm_area_struct *, struct vm_fault *);
|
||||
vm_fault_t (*fault)(struct vm_area_struct*, struct vm_fault *);
|
||||
vm_fault_t (*page_mkwrite)(struct vm_area_struct *, struct vm_fault *);
|
||||
vm_fault_t (*pfn_mkwrite)(struct vm_area_struct *, struct vm_fault *);
|
||||
int (*access)(struct vm_area_struct *, unsigned long, void*, int, int);
|
||||
|
||||
locking rules:
|
||||
|
|
|
@ -870,6 +870,7 @@ Committed_AS: 100056 kB
|
|||
VmallocTotal: 112216 kB
|
||||
VmallocUsed: 428 kB
|
||||
VmallocChunk: 111088 kB
|
||||
HardwareCorrupted: 0 kB
|
||||
AnonHugePages: 49152 kB
|
||||
ShmemHugePages: 0 kB
|
||||
ShmemPmdMapped: 0 kB
|
||||
|
@ -915,6 +916,8 @@ MemAvailable: An estimate of how much memory is available for starting new
|
|||
Dirty: Memory which is waiting to get written back to the disk
|
||||
Writeback: Memory which is actively being written back to the disk
|
||||
AnonPages: Non-file backed pages mapped into userspace page tables
|
||||
HardwareCorrupted: The amount of RAM/memory in KB, the kernel identifies as
|
||||
corrupted.
|
||||
AnonHugePages: Non-file backed huge pages mapped into userspace page tables
|
||||
Mapped: files which have been mmaped, such as libraries
|
||||
Shmem: Total memory used by shared memory (shmem) and tmpfs
|
||||
|
|
|
@ -222,7 +222,7 @@ using debugfs:
|
|||
*/
|
||||
static struct dentry *create_buf_file_handler(const char *filename,
|
||||
struct dentry *parent,
|
||||
int mode,
|
||||
umode_t mode,
|
||||
struct rchan_buf *buf,
|
||||
int *is_global)
|
||||
{
|
||||
|
@ -375,7 +375,7 @@ would be very similar:
|
|||
static int subbuf_start(struct rchan_buf *buf,
|
||||
void *subbuf,
|
||||
void *prev_subbuf,
|
||||
unsigned int prev_padding)
|
||||
size_t prev_padding)
|
||||
{
|
||||
if (prev_subbuf)
|
||||
*((unsigned *)prev_subbuf) = prev_padding;
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
.. _linux_doc:
|
||||
|
||||
The Linux Kernel documentation
|
||||
==============================
|
||||
|
||||
|
@ -113,29 +115,13 @@ subprojects.
|
|||
|
||||
filesystems/ext4/index
|
||||
|
||||
Korean translations
|
||||
-------------------
|
||||
Translations
|
||||
------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:maxdepth: 2
|
||||
|
||||
translations/ko_KR/index
|
||||
|
||||
Chinese translations
|
||||
--------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
translations/zh_CN/index
|
||||
|
||||
Japanese translations
|
||||
---------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
translations/ja_JP/index
|
||||
translations/index
|
||||
|
||||
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/fs.h conflict!
|
||||
'v' 00-0F linux/sonypi.h conflict!
|
||||
'v' 00-0F media/v4l2-subdev.h conflict!
|
||||
'v' C0-FF linux/meye.h conflict!
|
||||
'w' all CERN SCI driver
|
||||
'y' 00-1F packet based user level communications
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
.. _kernel_hacking_hack:
|
||||
|
||||
============================================
|
||||
Unreliable Guide To Hacking The Linux Kernel
|
||||
============================================
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
.. _kernel_hacking:
|
||||
|
||||
=====================
|
||||
Kernel Hacking Guides
|
||||
=====================
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
.. _kernel_hacking_lock:
|
||||
|
||||
===========================
|
||||
Unreliable Guide To Locking
|
||||
===========================
|
||||
|
@ -177,7 +179,7 @@ perfect world).
|
|||
|
||||
Note that you can also use :c:func:`spin_lock_irq()` or
|
||||
:c:func:`spin_lock_irqsave()` here, which stop hardware interrupts
|
||||
as well: see `Hard IRQ Context <#hardirq-context>`__.
|
||||
as well: see `Hard IRQ Context <#hard-irq-context>`__.
|
||||
|
||||
This works perfectly for UP as well: the spin lock vanishes, and this
|
||||
macro simply becomes :c:func:`local_bh_disable()`
|
||||
|
@ -228,7 +230,7 @@ The Same Softirq
|
|||
~~~~~~~~~~~~~~~~
|
||||
|
||||
The same softirq can run on the other CPUs: you can use a per-CPU array
|
||||
(see `Per-CPU Data <#per-cpu>`__) for better performance. If you're
|
||||
(see `Per-CPU Data <#per-cpu-data>`__) for better performance. If you're
|
||||
going so far as to use a softirq, you probably care about scalable
|
||||
performance enough to justify the extra complexity.
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ and it's also much more restricted in the latter case:
|
|||
appropriate mapping protection capabilities. Ramfs, romfs, cramfs
|
||||
and mtd might all permit this.
|
||||
|
||||
- If the backing device device can't or won't permit direct sharing,
|
||||
- If the backing device can't or won't permit direct sharing,
|
||||
but does have the NOMMU_MAP_COPY capability, then a copy of the
|
||||
appropriate bit of the file will be read into a contiguous bit of
|
||||
memory and any extraneous space beyond the EOF will be cleared
|
||||
|
|
|
@ -134,7 +134,7 @@ and their maintainers are:
|
|||
4.4 Greg Kroah-Hartman (very long-term stable kernel)
|
||||
4.9 Greg Kroah-Hartman
|
||||
4.14 Greg Kroah-Hartman
|
||||
====== ====================== ===========================
|
||||
====== ====================== ==============================
|
||||
|
||||
The selection of a kernel for long-term support is purely a matter of a
|
||||
maintainer having the need and the time to maintain that release. There
|
||||
|
|
|
@ -85,7 +85,7 @@ linux-api@vger.kernel.org.
|
|||
Here is a list of files that are in the kernel source tree that are
|
||||
required reading:
|
||||
|
||||
README
|
||||
:ref:`Documentation/admin-guide/README.rst <readme>`
|
||||
This file gives a short background on the Linux kernel and describes
|
||||
what is necessary to do to configure and build the kernel. People
|
||||
who are new to the kernel should start here.
|
||||
|
|
|
@ -105,7 +105,7 @@ to admit that you are stupid when you haven't **yet** done the really
|
|||
stupid thing.
|
||||
|
||||
Then, when it really does turn out to be stupid, people just roll their
|
||||
eyes and say "Oops, he did it again".
|
||||
eyes and say "Oops, not again".
|
||||
|
||||
This preemptive admission of incompetence might also make the people who
|
||||
actually do the work also think twice about whether it's worth doing or
|
||||
|
@ -172,10 +172,10 @@ To solve this problem, you really only have two options:
|
|||
might even be amused.
|
||||
|
||||
The option of being unfailingly polite really doesn't exist. Nobody will
|
||||
trust somebody who is so clearly hiding his true character.
|
||||
trust somebody who is so clearly hiding their true character.
|
||||
|
||||
.. [#f2] Paul Simon sang "Fifty Ways to Leave Your Lover", because quite
|
||||
frankly, "A Million Ways to Tell a Developer He Is a D*ckhead" doesn't
|
||||
frankly, "A Million Ways to Tell a Developer They're a D*ckhead" doesn't
|
||||
scan nearly as well. But I'm sure he thought about it.
|
||||
|
||||
|
||||
|
@ -219,15 +219,16 @@ Things will go wrong, and people want somebody to blame. Tag, you're it.
|
|||
|
||||
It's not actually that hard to accept the blame, especially if people
|
||||
kind of realize that it wasn't **all** your fault. Which brings us to the
|
||||
best way of taking the blame: do it for another guy. You'll feel good
|
||||
for taking the fall, he'll feel good about not getting blamed, and the
|
||||
guy who lost his whole 36GB porn-collection because of your incompetence
|
||||
will grudgingly admit that you at least didn't try to weasel out of it.
|
||||
best way of taking the blame: do it for someone else. You'll feel good
|
||||
for taking the fall, they'll feel good about not getting blamed, and the
|
||||
person who lost their whole 36GB porn-collection because of your
|
||||
incompetence will grudgingly admit that you at least didn't try to weasel
|
||||
out of it.
|
||||
|
||||
Then make the developer who really screwed up (if you can find him) know
|
||||
**in_private** that he screwed up. Not just so he can avoid it in the
|
||||
future, but so that he knows he owes you one. And, perhaps even more
|
||||
importantly, he's also likely the person who can fix it. Because, let's
|
||||
Then make the developer who really screwed up (if you can find them) know
|
||||
**in_private** that they screwed up. Not just so they can avoid it in the
|
||||
future, but so that they know they owe you one. And, perhaps even more
|
||||
importantly, they're also likely the person who can fix it. Because, let's
|
||||
face it, it sure ain't you.
|
||||
|
||||
Taking the blame is also why you get to be manager in the first place.
|
||||
|
|
|
@ -47,7 +47,7 @@ class KernelDocDirective(Directive):
|
|||
optional_arguments = 4
|
||||
option_spec = {
|
||||
'doc': directives.unchanged_required,
|
||||
'functions': directives.unchanged_required,
|
||||
'functions': directives.unchanged,
|
||||
'export': directives.unchanged,
|
||||
'internal': directives.unchanged,
|
||||
}
|
||||
|
@ -75,8 +75,12 @@ class KernelDocDirective(Directive):
|
|||
elif 'doc' in self.options:
|
||||
cmd += ['-function', str(self.options.get('doc'))]
|
||||
elif 'functions' in self.options:
|
||||
for f in str(self.options.get('functions')).split():
|
||||
cmd += ['-function', f]
|
||||
functions = self.options.get('functions').split()
|
||||
if functions:
|
||||
for f in functions:
|
||||
cmd += ['-function', f]
|
||||
else:
|
||||
cmd += ['-no-doc-sections']
|
||||
|
||||
for pattern in export_file_patterns:
|
||||
for f in glob.glob(env.config.kerneldoc_srctree + '/' + pattern):
|
||||
|
|
|
@ -344,7 +344,7 @@ enums and defines and create cross-references to a Sphinx book.
|
|||
|
||||
B<parse_headers.pl> [<options>] <C_FILE> <OUT_FILE> [<EXCEPTIONS_FILE>]
|
||||
|
||||
Where <options> can be: --debug, --help or --man.
|
||||
Where <options> can be: --debug, --help or --usage.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ Currently, these files are in /proc/sys/vm:
|
|||
- dirty_bytes
|
||||
- dirty_expire_centisecs
|
||||
- dirty_ratio
|
||||
- dirtytime_expire_seconds
|
||||
- dirty_writeback_centisecs
|
||||
- drop_caches
|
||||
- extfrag_threshold
|
||||
|
@ -44,6 +45,7 @@ Currently, these files are in /proc/sys/vm:
|
|||
- mmap_rnd_bits
|
||||
- mmap_rnd_compat_bits
|
||||
- nr_hugepages
|
||||
- nr_hugepages_mempolicy
|
||||
- nr_overcommit_hugepages
|
||||
- nr_trim_pages (only if CONFIG_MMU=n)
|
||||
- numa_zonelist_order
|
||||
|
@ -178,6 +180,18 @@ The total available memory is not equal to total system memory.
|
|||
|
||||
==============================================================
|
||||
|
||||
dirtytime_expire_seconds
|
||||
|
||||
When a lazytime inode is constantly having its pages dirtied, the inode with
|
||||
an updated timestamp will never get chance to be written out. And, if the
|
||||
only thing that has happened on the file system is a dirtytime inode caused
|
||||
by an atime update, a worker will be scheduled to make sure that inode
|
||||
eventually gets pushed out to disk. This tunable is used to define when dirty
|
||||
inode is old enough to be eligible for writeback by the kernel flusher threads.
|
||||
And, it is also used as the interval to wakeup dirtytime_writeback thread.
|
||||
|
||||
==============================================================
|
||||
|
||||
dirty_writeback_centisecs
|
||||
|
||||
The kernel flusher threads will periodically wake up and write `old' data
|
||||
|
@ -519,6 +533,15 @@ See Documentation/admin-guide/mm/hugetlbpage.rst
|
|||
|
||||
==============================================================
|
||||
|
||||
nr_hugepages_mempolicy
|
||||
|
||||
Change the size of the hugepage pool at run-time on a specific
|
||||
set of NUMA nodes.
|
||||
|
||||
See Documentation/admin-guide/mm/hugetlbpage.rst
|
||||
|
||||
==============================================================
|
||||
|
||||
nr_overcommit_hugepages
|
||||
|
||||
Change the maximum size of the hugepage pool. The maximum is
|
||||
|
|
|
@ -27,7 +27,7 @@ a Linux system will eventually read the clock source to determine exactly
|
|||
what time it is.
|
||||
|
||||
Typically the clock source is a monotonic, atomic counter which will provide
|
||||
n bits which count from 0 to 2^(n-1) and then wraps around to 0 and start over.
|
||||
n bits which count from 0 to (2^n)-1 and then wraps around to 0 and start over.
|
||||
It will ideally NEVER stop ticking as long as the system is running. It
|
||||
may stop during system suspend.
|
||||
|
||||
|
|
|
@ -524,4 +524,4 @@ The following commands are supported:
|
|||
totals derived from one or more trace event format fields and/or
|
||||
event counts (hitcount).
|
||||
|
||||
See Documentation/trace/histogram.txt for details and examples.
|
||||
See Documentation/trace/histogram.rst for details and examples.
|
||||
|
|
|
@ -329,9 +329,9 @@ of ftrace. Here is a list of some of the key files:
|
|||
track of the time spent in those functions. The histogram
|
||||
content can be displayed in the files:
|
||||
|
||||
trace_stats/function<cpu> ( function0, function1, etc).
|
||||
trace_stat/function<cpu> ( function0, function1, etc).
|
||||
|
||||
trace_stats:
|
||||
trace_stat:
|
||||
|
||||
A directory that holds different tracing stats.
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -18,6 +18,7 @@ Linux Tracing Technologies
|
|||
events-nmi
|
||||
events-msr
|
||||
mmiotrace
|
||||
histogram
|
||||
hwlat_detector
|
||||
intel_th
|
||||
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
|
||||
current_tracer. Instead of that, add probe points via
|
||||
/sys/kernel/debug/tracing/kprobe_events, and enable it via
|
||||
/sys/kernel/debug/tracing/events/kprobes/<EVENT>/enabled.
|
||||
/sys/kernel/debug/tracing/events/kprobes/<EVENT>/enable.
|
||||
|
||||
|
||||
Synopsis of kprobe_events
|
||||
|
@ -81,9 +81,9 @@ Per-probe event filtering feature allows you to set different filter on each
|
|||
probe and gives you what arguments will be shown in trace buffer. If an event
|
||||
name is specified right after 'p:' or 'r:' in kprobe_events, it adds an event
|
||||
under tracing/events/kprobes/<EVENT>, at the directory you can see 'id',
|
||||
'enabled', 'format' and 'filter'.
|
||||
'enable', 'format', 'filter' and 'trigger'.
|
||||
|
||||
enabled:
|
||||
enable:
|
||||
You can enable/disable the probe by writing 1 or 0 on it.
|
||||
|
||||
format:
|
||||
|
@ -95,6 +95,9 @@ filter:
|
|||
id:
|
||||
This shows the id of this probe event.
|
||||
|
||||
trigger:
|
||||
This allows to install trigger commands which are executed when the event is
|
||||
hit (for details, see Documentation/trace/events.rst, section 6).
|
||||
|
||||
Event Profiling
|
||||
---------------
|
||||
|
|
|
@ -13,7 +13,7 @@ To enable this feature, build your kernel with CONFIG_UPROBE_EVENTS=y.
|
|||
Similar to the kprobe-event tracer, this doesn't need to be activated via
|
||||
current_tracer. Instead of that, add probe points via
|
||||
/sys/kernel/debug/tracing/uprobe_events, and enable it via
|
||||
/sys/kernel/debug/tracing/events/uprobes/<EVENT>/enabled.
|
||||
/sys/kernel/debug/tracing/events/uprobes/<EVENT>/enable.
|
||||
|
||||
However unlike kprobe-event tracer, the uprobe event interface expects the
|
||||
user to calculate the offset of the probepoint in the object.
|
||||
|
|
|
@ -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
|
||||
original document maintainer directly. However, if you have a problem
|
||||
|
@ -8,7 +8,7 @@ or if there is a problem with the translation.
|
|||
|
||||
Chinese maintainer: Dave Young <hidave.darkstar@gmail.com>
|
||||
---------------------------------------------------------------------
|
||||
Documentation/admin-guide/oops-tracing.rst 的中文翻译
|
||||
Documentation/admin-guide/bug-hunting.rst 的中文翻译
|
||||
|
||||
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
|
||||
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
|
||||
|
|
|
@ -4406,6 +4406,12 @@ X: Documentation/spi
|
|||
X: Documentation/media
|
||||
T: git git://git.lwn.net/linux.git docs-next
|
||||
|
||||
DOCUMENTATION/ITALIAN
|
||||
M: Federico Vaga <federico.vaga@vaga.pv.it>
|
||||
L: linux-doc@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/translations/it_IT
|
||||
|
||||
DONGWOON DW9714 LENS VOICE COIL DRIVER
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
@ -7034,7 +7040,7 @@ M: Guenter Roeck <linux@roeck-us.net>
|
|||
L: linux-hwmon@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/hwmon/ina209
|
||||
F: Documentation/devicetree/bindings/i2c/ina209.txt
|
||||
F: Documentation/devicetree/bindings/hwmon/ina2xx.txt
|
||||
F: drivers/hwmon/ina209.c
|
||||
|
||||
INA2XX HARDWARE MONITOR DRIVER
|
||||
|
|
|
@ -27,9 +27,20 @@ extern unsigned long max_pfn;
|
|||
extern unsigned long long max_possible_pfn;
|
||||
|
||||
#ifndef CONFIG_NO_BOOTMEM
|
||||
/*
|
||||
* node_bootmem_map is a map pointer - the bits represent all physical
|
||||
* memory pages (including holes) on the node.
|
||||
/**
|
||||
* struct bootmem_data - per-node information used by the bootmem allocator
|
||||
* @node_min_pfn: the starting physical address of the node's memory
|
||||
* @node_low_pfn: the end physical address of the directly addressable memory
|
||||
* @node_bootmem_map: is a bitmap pointer - the bits represent all physical
|
||||
* memory pages (including holes) on the node.
|
||||
* @last_end_off: the offset within the page of the end of the last allocation;
|
||||
* if 0, the page used is full
|
||||
* @hint_idx: the PFN of the page used with the last allocation;
|
||||
* together with using this with the @last_end_offset field,
|
||||
* a test can be made to see if allocations can be merged
|
||||
* with the page used for the last allocation rather than
|
||||
* using up a full new page.
|
||||
* @list: list entry in the linked list ordered by the memory addresses
|
||||
*/
|
||||
typedef struct bootmem_data {
|
||||
unsigned long node_min_pfn;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include <linux/errno.h>
|
||||
|
||||
/* see Documentation/gpio/gpio-legacy.txt */
|
||||
/* see Documentation/driver-api/gpio/legacy.rst */
|
||||
|
||||
/* make these flag values available regardless of GPIO kconfig options */
|
||||
#define GPIOF_DIR_OUT (0 << 0)
|
||||
|
|
|
@ -20,31 +20,60 @@
|
|||
#define INIT_MEMBLOCK_REGIONS 128
|
||||
#define INIT_PHYSMEM_REGIONS 4
|
||||
|
||||
/* Definition of memblock flags. */
|
||||
enum {
|
||||
/**
|
||||
* enum memblock_flags - definition of memory region attributes
|
||||
* @MEMBLOCK_NONE: no special request
|
||||
* @MEMBLOCK_HOTPLUG: hotpluggable region
|
||||
* @MEMBLOCK_MIRROR: mirrored region
|
||||
* @MEMBLOCK_NOMAP: don't add to kernel direct mapping
|
||||
*/
|
||||
enum memblock_flags {
|
||||
MEMBLOCK_NONE = 0x0, /* No special request */
|
||||
MEMBLOCK_HOTPLUG = 0x1, /* hotpluggable region */
|
||||
MEMBLOCK_MIRROR = 0x2, /* mirrored region */
|
||||
MEMBLOCK_NOMAP = 0x4, /* don't add to kernel direct mapping */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct memblock_region - represents a memory region
|
||||
* @base: physical address of the region
|
||||
* @size: size of the region
|
||||
* @flags: memory region attributes
|
||||
* @nid: NUMA node id
|
||||
*/
|
||||
struct memblock_region {
|
||||
phys_addr_t base;
|
||||
phys_addr_t size;
|
||||
unsigned long flags;
|
||||
enum memblock_flags flags;
|
||||
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
|
||||
int nid;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* struct memblock_type - collection of memory regions of certain type
|
||||
* @cnt: number of regions
|
||||
* @max: size of the allocated array
|
||||
* @total_size: size of all regions
|
||||
* @regions: array of regions
|
||||
* @name: the memory type symbolic name
|
||||
*/
|
||||
struct memblock_type {
|
||||
unsigned long cnt; /* number of regions */
|
||||
unsigned long max; /* size of the allocated array */
|
||||
phys_addr_t total_size; /* size of all regions */
|
||||
unsigned long cnt;
|
||||
unsigned long max;
|
||||
phys_addr_t total_size;
|
||||
struct memblock_region *regions;
|
||||
char *name;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct memblock - memblock allocator metadata
|
||||
* @bottom_up: is bottom up direction?
|
||||
* @current_limit: physical address of the current allocation limit
|
||||
* @memory: usabe memory regions
|
||||
* @reserved: reserved memory regions
|
||||
* @physmem: all physical memory
|
||||
*/
|
||||
struct memblock {
|
||||
bool bottom_up; /* is bottom up direction? */
|
||||
phys_addr_t current_limit;
|
||||
|
@ -72,7 +101,7 @@ void memblock_discard(void);
|
|||
|
||||
phys_addr_t memblock_find_in_range_node(phys_addr_t size, phys_addr_t align,
|
||||
phys_addr_t start, phys_addr_t end,
|
||||
int nid, ulong flags);
|
||||
int nid, enum memblock_flags flags);
|
||||
phys_addr_t memblock_find_in_range(phys_addr_t start, phys_addr_t end,
|
||||
phys_addr_t size, phys_addr_t align);
|
||||
void memblock_allow_resize(void);
|
||||
|
@ -89,19 +118,19 @@ int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size);
|
|||
int memblock_mark_mirror(phys_addr_t base, phys_addr_t size);
|
||||
int memblock_mark_nomap(phys_addr_t base, phys_addr_t size);
|
||||
int memblock_clear_nomap(phys_addr_t base, phys_addr_t size);
|
||||
ulong choose_memblock_flags(void);
|
||||
enum memblock_flags choose_memblock_flags(void);
|
||||
|
||||
/* Low level functions */
|
||||
int memblock_add_range(struct memblock_type *type,
|
||||
phys_addr_t base, phys_addr_t size,
|
||||
int nid, unsigned long flags);
|
||||
int nid, enum memblock_flags flags);
|
||||
|
||||
void __next_mem_range(u64 *idx, int nid, ulong flags,
|
||||
void __next_mem_range(u64 *idx, int nid, enum memblock_flags flags,
|
||||
struct memblock_type *type_a,
|
||||
struct memblock_type *type_b, phys_addr_t *out_start,
|
||||
phys_addr_t *out_end, int *out_nid);
|
||||
|
||||
void __next_mem_range_rev(u64 *idx, int nid, ulong flags,
|
||||
void __next_mem_range_rev(u64 *idx, int nid, enum memblock_flags flags,
|
||||
struct memblock_type *type_a,
|
||||
struct memblock_type *type_b, phys_addr_t *out_start,
|
||||
phys_addr_t *out_end, int *out_nid);
|
||||
|
@ -239,7 +268,6 @@ void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn,
|
|||
/**
|
||||
* for_each_resv_unavail_range - iterate through reserved and unavailable memory
|
||||
* @i: u64 used as loop variable
|
||||
* @flags: pick from blocks based on memory attributes
|
||||
* @p_start: ptr to phys_addr_t for start address of the range, can be %NULL
|
||||
* @p_end: ptr to phys_addr_t for end address of the range, can be %NULL
|
||||
*
|
||||
|
@ -253,13 +281,13 @@ void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn,
|
|||
NUMA_NO_NODE, MEMBLOCK_NONE, p_start, p_end, NULL)
|
||||
|
||||
static inline void memblock_set_region_flags(struct memblock_region *r,
|
||||
unsigned long flags)
|
||||
enum memblock_flags flags)
|
||||
{
|
||||
r->flags |= flags;
|
||||
}
|
||||
|
||||
static inline void memblock_clear_region_flags(struct memblock_region *r,
|
||||
unsigned long flags)
|
||||
enum memblock_flags flags)
|
||||
{
|
||||
r->flags &= ~flags;
|
||||
}
|
||||
|
@ -317,10 +345,10 @@ static inline bool memblock_bottom_up(void)
|
|||
|
||||
phys_addr_t __init memblock_alloc_range(phys_addr_t size, phys_addr_t align,
|
||||
phys_addr_t start, phys_addr_t end,
|
||||
ulong flags);
|
||||
enum memblock_flags flags);
|
||||
phys_addr_t memblock_alloc_base_nid(phys_addr_t size,
|
||||
phys_addr_t align, phys_addr_t max_addr,
|
||||
int nid, ulong flags);
|
||||
int nid, enum memblock_flags flags);
|
||||
phys_addr_t memblock_alloc_base(phys_addr_t size, phys_addr_t align,
|
||||
phys_addr_t max_addr);
|
||||
phys_addr_t __memblock_alloc_base(phys_addr_t size, phys_addr_t align,
|
||||
|
@ -367,8 +395,10 @@ phys_addr_t memblock_get_current_limit(void);
|
|||
*/
|
||||
|
||||
/**
|
||||
* memblock_region_memory_base_pfn - Return the lowest pfn intersecting with the memory region
|
||||
* memblock_region_memory_base_pfn - get the lowest pfn of the memory region
|
||||
* @reg: memblock_region structure
|
||||
*
|
||||
* Return: the lowest pfn intersecting with the memory region
|
||||
*/
|
||||
static inline unsigned long memblock_region_memory_base_pfn(const struct memblock_region *reg)
|
||||
{
|
||||
|
@ -376,8 +406,10 @@ static inline unsigned long memblock_region_memory_base_pfn(const struct membloc
|
|||
}
|
||||
|
||||
/**
|
||||
* memblock_region_memory_end_pfn - Return the end_pfn this region
|
||||
* memblock_region_memory_end_pfn - get the end pfn of the memory region
|
||||
* @reg: memblock_region structure
|
||||
*
|
||||
* Return: the end_pfn of the reserved region
|
||||
*/
|
||||
static inline unsigned long memblock_region_memory_end_pfn(const struct memblock_region *reg)
|
||||
{
|
||||
|
@ -385,8 +417,10 @@ static inline unsigned long memblock_region_memory_end_pfn(const struct memblock
|
|||
}
|
||||
|
||||
/**
|
||||
* memblock_region_reserved_base_pfn - Return the lowest pfn intersecting with the reserved region
|
||||
* memblock_region_reserved_base_pfn - get the lowest pfn of the reserved region
|
||||
* @reg: memblock_region structure
|
||||
*
|
||||
* Return: the lowest pfn intersecting with the reserved region
|
||||
*/
|
||||
static inline unsigned long memblock_region_reserved_base_pfn(const struct memblock_region *reg)
|
||||
{
|
||||
|
@ -394,8 +428,10 @@ static inline unsigned long memblock_region_reserved_base_pfn(const struct membl
|
|||
}
|
||||
|
||||
/**
|
||||
* memblock_region_reserved_end_pfn - Return the end_pfn this region
|
||||
* memblock_region_reserved_end_pfn - get the end pfn of the reserved region
|
||||
* @reg: memblock_region structure
|
||||
*
|
||||
* Return: the end_pfn of the reserved region
|
||||
*/
|
||||
static inline unsigned long memblock_region_reserved_end_pfn(const struct memblock_region *reg)
|
||||
{
|
||||
|
|
|
@ -20,6 +20,21 @@ extern int do_settimeofday64(const struct timespec64 *ts);
|
|||
extern int do_sys_settimeofday64(const struct timespec64 *tv,
|
||||
const struct timezone *tz);
|
||||
|
||||
/*
|
||||
* ktime_get() family: read the current time in a multitude of ways,
|
||||
*
|
||||
* The default time reference is CLOCK_MONOTONIC, starting at
|
||||
* boot time but not counting the time spent in suspend.
|
||||
* For other references, use the functions with "real", "clocktai",
|
||||
* "boottime" and "raw" suffixes.
|
||||
*
|
||||
* To get the time in a different format, use the ones wit
|
||||
* "ns", "ts64" and "seconds" suffix.
|
||||
*
|
||||
* See Documentation/core-api/timekeeping.rst for more details.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* timespec64 based interfaces
|
||||
*/
|
||||
|
|
|
@ -521,7 +521,7 @@ config FUNCTION_PROFILER
|
|||
in debugfs called function_profile_enabled which defaults to zero.
|
||||
When a 1 is echoed into this file profiling begins, and when a
|
||||
zero is entered, profiling stops. A "functions" file is created in
|
||||
the trace_stats directory; this file shows the list of functions that
|
||||
the trace_stat directory; this file shows the list of functions that
|
||||
have been hit and their counters.
|
||||
|
||||
If in doubt, say N.
|
||||
|
@ -605,7 +605,7 @@ config HIST_TRIGGERS
|
|||
Inter-event tracing of quantities such as latencies is also
|
||||
supported using hist triggers under this option.
|
||||
|
||||
See Documentation/trace/histogram.txt.
|
||||
See Documentation/trace/histogram.rst.
|
||||
If in doubt, say N.
|
||||
|
||||
config MMIOTRACE_TEST
|
||||
|
|
|
@ -283,7 +283,7 @@ static struct rs_control *init_rs_internal(int symsize, int gfpoly,
|
|||
* in index form
|
||||
* @prim: primitive element to generate polynomial roots
|
||||
* @nroots: RS code generator polynomial degree (number of roots)
|
||||
* @gfp: GFP_ flags for allocations
|
||||
* @gfp: Memory allocation flags.
|
||||
*/
|
||||
struct rs_control *init_rs_gfp(int symsize, int gfpoly, int fcr, int prim,
|
||||
int nroots, gfp_t gfp)
|
||||
|
|
159
mm/bootmem.c
159
mm/bootmem.c
|
@ -21,6 +21,53 @@
|
|||
|
||||
#include "internal.h"
|
||||
|
||||
/**
|
||||
* DOC: bootmem overview
|
||||
*
|
||||
* Bootmem is a boot-time physical memory allocator and configurator.
|
||||
*
|
||||
* It is used early in the boot process before the page allocator is
|
||||
* set up.
|
||||
*
|
||||
* Bootmem is based on the most basic of allocators, a First Fit
|
||||
* allocator which uses a bitmap to represent memory. If a bit is 1,
|
||||
* the page is allocated and 0 if unallocated. To satisfy allocations
|
||||
* of sizes smaller than a page, the allocator records the Page Frame
|
||||
* Number (PFN) of the last allocation and the offset the allocation
|
||||
* ended at. Subsequent small allocations are merged together and
|
||||
* stored on the same page.
|
||||
*
|
||||
* The information used by the bootmem allocator is represented by
|
||||
* :c:type:`struct bootmem_data`. An array to hold up to %MAX_NUMNODES
|
||||
* such structures is statically allocated and then it is discarded
|
||||
* when the system initialization completes. Each entry in this array
|
||||
* corresponds to a node with memory. For UMA systems only entry 0 is
|
||||
* used.
|
||||
*
|
||||
* The bootmem allocator is initialized during early architecture
|
||||
* specific setup. Each architecture is required to supply a
|
||||
* :c:func:`setup_arch` function which, among other tasks, is
|
||||
* responsible for acquiring the necessary parameters to initialise
|
||||
* the boot memory allocator. These parameters define limits of usable
|
||||
* physical memory:
|
||||
*
|
||||
* * @min_low_pfn - the lowest PFN that is available in the system
|
||||
* * @max_low_pfn - the highest PFN that may be addressed by low
|
||||
* memory (%ZONE_NORMAL)
|
||||
* * @max_pfn - the last PFN available to the system.
|
||||
*
|
||||
* After those limits are determined, the :c:func:`init_bootmem` or
|
||||
* :c:func:`init_bootmem_node` function should be called to initialize
|
||||
* the bootmem allocator. The UMA case should use the `init_bootmem`
|
||||
* function. It will initialize ``contig_page_data`` structure that
|
||||
* represents the only memory node in the system. In the NUMA case the
|
||||
* `init_bootmem_node` function should be called to initialize the
|
||||
* bootmem allocator for each node.
|
||||
*
|
||||
* Once the allocator is set up, it is possible to use either single
|
||||
* node or NUMA variant of the allocation APIs.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_NEED_MULTIPLE_NODES
|
||||
struct pglist_data __refdata contig_page_data = {
|
||||
.bdata = &bootmem_node_data[0]
|
||||
|
@ -62,6 +109,8 @@ static unsigned long __init bootmap_bytes(unsigned long pages)
|
|||
/**
|
||||
* bootmem_bootmap_pages - calculate bitmap size in pages
|
||||
* @pages: number of pages the bitmap has to represent
|
||||
*
|
||||
* Return: the number of pages needed to hold the bitmap.
|
||||
*/
|
||||
unsigned long __init bootmem_bootmap_pages(unsigned long pages)
|
||||
{
|
||||
|
@ -121,7 +170,7 @@ static unsigned long __init init_bootmem_core(bootmem_data_t *bdata,
|
|||
* @startpfn: first pfn on the node
|
||||
* @endpfn: first pfn after the node
|
||||
*
|
||||
* Returns the number of bytes needed to hold the bitmap for this node.
|
||||
* Return: the number of bytes needed to hold the bitmap for this node.
|
||||
*/
|
||||
unsigned long __init init_bootmem_node(pg_data_t *pgdat, unsigned long freepfn,
|
||||
unsigned long startpfn, unsigned long endpfn)
|
||||
|
@ -134,7 +183,7 @@ unsigned long __init init_bootmem_node(pg_data_t *pgdat, unsigned long freepfn,
|
|||
* @start: pfn where the bitmap is to be placed
|
||||
* @pages: number of available physical pages
|
||||
*
|
||||
* Returns the number of bytes needed to hold the bitmap.
|
||||
* Return: the number of bytes needed to hold the bitmap.
|
||||
*/
|
||||
unsigned long __init init_bootmem(unsigned long start, unsigned long pages)
|
||||
{
|
||||
|
@ -143,15 +192,6 @@ unsigned long __init init_bootmem(unsigned long start, unsigned long pages)
|
|||
return init_bootmem_core(NODE_DATA(0)->bdata, start, 0, pages);
|
||||
}
|
||||
|
||||
/*
|
||||
* free_bootmem_late - free bootmem pages directly to page allocator
|
||||
* @addr: starting physical address of the range
|
||||
* @size: size of the range in bytes
|
||||
*
|
||||
* This is only useful when the bootmem allocator has already been torn
|
||||
* down, but we are still initializing the system. Pages are given directly
|
||||
* to the page allocator, no bootmem metadata is updated because it is gone.
|
||||
*/
|
||||
void __init free_bootmem_late(unsigned long physaddr, unsigned long size)
|
||||
{
|
||||
unsigned long cursor, end;
|
||||
|
@ -264,11 +304,6 @@ void __init reset_all_zones_managed_pages(void)
|
|||
reset_managed_pages_done = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* free_all_bootmem - release free pages to the buddy allocator
|
||||
*
|
||||
* Returns the number of pages actually released.
|
||||
*/
|
||||
unsigned long __init free_all_bootmem(void)
|
||||
{
|
||||
unsigned long total_pages = 0;
|
||||
|
@ -385,16 +420,6 @@ static int __init mark_bootmem(unsigned long start, unsigned long end,
|
|||
BUG();
|
||||
}
|
||||
|
||||
/**
|
||||
* free_bootmem_node - mark a page range as usable
|
||||
* @pgdat: node the range resides on
|
||||
* @physaddr: starting address of the range
|
||||
* @size: size of the range in bytes
|
||||
*
|
||||
* Partial pages will be considered reserved and left as they are.
|
||||
*
|
||||
* The range must reside completely on the specified node.
|
||||
*/
|
||||
void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
|
||||
unsigned long size)
|
||||
{
|
||||
|
@ -408,15 +433,6 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
|
|||
mark_bootmem_node(pgdat->bdata, start, end, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* free_bootmem - mark a page range as usable
|
||||
* @physaddr: starting physical address of the range
|
||||
* @size: size of the range in bytes
|
||||
*
|
||||
* Partial pages will be considered reserved and left as they are.
|
||||
*
|
||||
* The range must be contiguous but may span node boundaries.
|
||||
*/
|
||||
void __init free_bootmem(unsigned long physaddr, unsigned long size)
|
||||
{
|
||||
unsigned long start, end;
|
||||
|
@ -439,6 +455,8 @@ void __init free_bootmem(unsigned long physaddr, unsigned long size)
|
|||
* Partial pages will be reserved.
|
||||
*
|
||||
* The range must reside completely on the specified node.
|
||||
*
|
||||
* Return: 0 on success, -errno on failure.
|
||||
*/
|
||||
int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
|
||||
unsigned long size, int flags)
|
||||
|
@ -460,6 +478,8 @@ int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
|
|||
* Partial pages will be reserved.
|
||||
*
|
||||
* The range must be contiguous but may span node boundaries.
|
||||
*
|
||||
* Return: 0 on success, -errno on failure.
|
||||
*/
|
||||
int __init reserve_bootmem(unsigned long addr, unsigned long size,
|
||||
int flags)
|
||||
|
@ -646,19 +666,6 @@ static void * __init ___alloc_bootmem_nopanic(unsigned long size,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* __alloc_bootmem_nopanic - allocate boot memory without panicking
|
||||
* @size: size of the request in bytes
|
||||
* @align: alignment of the region
|
||||
* @goal: preferred starting address of the region
|
||||
*
|
||||
* The goal is dropped if it can not be satisfied and the allocation will
|
||||
* fall back to memory below @goal.
|
||||
*
|
||||
* Allocation may happen on any node in the system.
|
||||
*
|
||||
* Returns NULL on failure.
|
||||
*/
|
||||
void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align,
|
||||
unsigned long goal)
|
||||
{
|
||||
|
@ -682,19 +689,6 @@ static void * __init ___alloc_bootmem(unsigned long size, unsigned long align,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* __alloc_bootmem - allocate boot memory
|
||||
* @size: size of the request in bytes
|
||||
* @align: alignment of the region
|
||||
* @goal: preferred starting address of the region
|
||||
*
|
||||
* The goal is dropped if it can not be satisfied and the allocation will
|
||||
* fall back to memory below @goal.
|
||||
*
|
||||
* Allocation may happen on any node in the system.
|
||||
*
|
||||
* The function panics if the request can not be satisfied.
|
||||
*/
|
||||
void * __init __alloc_bootmem(unsigned long size, unsigned long align,
|
||||
unsigned long goal)
|
||||
{
|
||||
|
@ -754,21 +748,6 @@ void * __init ___alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* __alloc_bootmem_node - allocate boot memory from a specific node
|
||||
* @pgdat: node to allocate from
|
||||
* @size: size of the request in bytes
|
||||
* @align: alignment of the region
|
||||
* @goal: preferred starting address of the region
|
||||
*
|
||||
* The goal is dropped if it can not be satisfied and the allocation will
|
||||
* fall back to memory below @goal.
|
||||
*
|
||||
* Allocation may fall back to any node in the system if the specified node
|
||||
* can not hold the requested memory.
|
||||
*
|
||||
* The function panics if the request can not be satisfied.
|
||||
*/
|
||||
void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
|
||||
unsigned long align, unsigned long goal)
|
||||
{
|
||||
|
@ -807,19 +786,6 @@ void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* __alloc_bootmem_low - allocate low boot memory
|
||||
* @size: size of the request in bytes
|
||||
* @align: alignment of the region
|
||||
* @goal: preferred starting address of the region
|
||||
*
|
||||
* The goal is dropped if it can not be satisfied and the allocation will
|
||||
* fall back to memory below @goal.
|
||||
*
|
||||
* Allocation may happen on any node in the system.
|
||||
*
|
||||
* The function panics if the request can not be satisfied.
|
||||
*/
|
||||
void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,
|
||||
unsigned long goal)
|
||||
{
|
||||
|
@ -834,21 +800,6 @@ void * __init __alloc_bootmem_low_nopanic(unsigned long size,
|
|||
ARCH_LOW_ADDRESS_LIMIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* __alloc_bootmem_low_node - allocate low boot memory from a specific node
|
||||
* @pgdat: node to allocate from
|
||||
* @size: size of the request in bytes
|
||||
* @align: alignment of the region
|
||||
* @goal: preferred starting address of the region
|
||||
*
|
||||
* The goal is dropped if it can not be satisfied and the allocation will
|
||||
* fall back to memory below @goal.
|
||||
*
|
||||
* Allocation may fall back to any node in the system if the specified node
|
||||
* can not hold the requested memory.
|
||||
*
|
||||
* The function panics if the request can not be satisfied.
|
||||
*/
|
||||
void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size,
|
||||
unsigned long align, unsigned long goal)
|
||||
{
|
||||
|
|
203
mm/memblock.c
203
mm/memblock.c
|
@ -27,6 +27,61 @@
|
|||
|
||||
#include "internal.h"
|
||||
|
||||
/**
|
||||
* DOC: memblock overview
|
||||
*
|
||||
* Memblock is a method of managing memory regions during the early
|
||||
* boot period when the usual kernel memory allocators are not up and
|
||||
* running.
|
||||
*
|
||||
* Memblock views the system memory as collections of contiguous
|
||||
* regions. There are several types of these collections:
|
||||
*
|
||||
* * ``memory`` - describes the physical memory available to the
|
||||
* kernel; this may differ from the actual physical memory installed
|
||||
* in the system, for instance when the memory is restricted with
|
||||
* ``mem=`` command line parameter
|
||||
* * ``reserved`` - describes the regions that were allocated
|
||||
* * ``physmap`` - describes the actual physical memory regardless of
|
||||
* the possible restrictions; the ``physmap`` type is only available
|
||||
* on some architectures.
|
||||
*
|
||||
* Each region is represented by :c:type:`struct memblock_region` that
|
||||
* defines the region extents, its attributes and NUMA node id on NUMA
|
||||
* systems. Every memory type is described by the :c:type:`struct
|
||||
* memblock_type` which contains an array of memory regions along with
|
||||
* the allocator metadata. The memory types are nicely wrapped with
|
||||
* :c:type:`struct memblock`. This structure is statically initialzed
|
||||
* at build time. The region arrays for the "memory" and "reserved"
|
||||
* types are initially sized to %INIT_MEMBLOCK_REGIONS and for the
|
||||
* "physmap" type to %INIT_PHYSMEM_REGIONS.
|
||||
* The :c:func:`memblock_allow_resize` enables automatic resizing of
|
||||
* the region arrays during addition of new regions. This feature
|
||||
* should be used with care so that memory allocated for the region
|
||||
* array will not overlap with areas that should be reserved, for
|
||||
* example initrd.
|
||||
*
|
||||
* The early architecture setup should tell memblock what the physical
|
||||
* memory layout is by using :c:func:`memblock_add` or
|
||||
* :c:func:`memblock_add_node` functions. The first function does not
|
||||
* assign the region to a NUMA node and it is appropriate for UMA
|
||||
* systems. Yet, it is possible to use it on NUMA systems as well and
|
||||
* assign the region to a NUMA node later in the setup process using
|
||||
* :c:func:`memblock_set_node`. The :c:func:`memblock_add_node`
|
||||
* performs such an assignment directly.
|
||||
*
|
||||
* Once memblock is setup the memory can be allocated using either
|
||||
* memblock or bootmem APIs.
|
||||
*
|
||||
* As the system boot progresses, the architecture specific
|
||||
* :c:func:`mem_init` function frees all the memory to the buddy page
|
||||
* allocator.
|
||||
*
|
||||
* If an architecure enables %CONFIG_ARCH_DISCARD_MEMBLOCK, the
|
||||
* memblock data structures will be discarded after the system
|
||||
* initialization compltes.
|
||||
*/
|
||||
|
||||
static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;
|
||||
static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;
|
||||
#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
|
||||
|
@ -61,7 +116,7 @@ static int memblock_can_resize __initdata_memblock;
|
|||
static int memblock_memory_in_slab __initdata_memblock = 0;
|
||||
static int memblock_reserved_in_slab __initdata_memblock = 0;
|
||||
|
||||
ulong __init_memblock choose_memblock_flags(void)
|
||||
enum memblock_flags __init_memblock choose_memblock_flags(void)
|
||||
{
|
||||
return system_has_some_mirror ? MEMBLOCK_MIRROR : MEMBLOCK_NONE;
|
||||
}
|
||||
|
@ -93,10 +148,11 @@ bool __init_memblock memblock_overlaps_region(struct memblock_type *type,
|
|||
return i < type->cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* __memblock_find_range_bottom_up - find free area utility in bottom-up
|
||||
* @start: start of candidate range
|
||||
* @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE}
|
||||
* @end: end of candidate range, can be %MEMBLOCK_ALLOC_ANYWHERE or
|
||||
* %MEMBLOCK_ALLOC_ACCESSIBLE
|
||||
* @size: size of free area to find
|
||||
* @align: alignment of free area to find
|
||||
* @nid: nid of the free area to find, %NUMA_NO_NODE for any node
|
||||
|
@ -104,13 +160,13 @@ bool __init_memblock memblock_overlaps_region(struct memblock_type *type,
|
|||
*
|
||||
* Utility called from memblock_find_in_range_node(), find free area bottom-up.
|
||||
*
|
||||
* RETURNS:
|
||||
* Return:
|
||||
* Found address on success, 0 on failure.
|
||||
*/
|
||||
static phys_addr_t __init_memblock
|
||||
__memblock_find_range_bottom_up(phys_addr_t start, phys_addr_t end,
|
||||
phys_addr_t size, phys_addr_t align, int nid,
|
||||
ulong flags)
|
||||
enum memblock_flags flags)
|
||||
{
|
||||
phys_addr_t this_start, this_end, cand;
|
||||
u64 i;
|
||||
|
@ -130,7 +186,8 @@ __memblock_find_range_bottom_up(phys_addr_t start, phys_addr_t end,
|
|||
/**
|
||||
* __memblock_find_range_top_down - find free area utility, in top-down
|
||||
* @start: start of candidate range
|
||||
* @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE}
|
||||
* @end: end of candidate range, can be %MEMBLOCK_ALLOC_ANYWHERE or
|
||||
* %MEMBLOCK_ALLOC_ACCESSIBLE
|
||||
* @size: size of free area to find
|
||||
* @align: alignment of free area to find
|
||||
* @nid: nid of the free area to find, %NUMA_NO_NODE for any node
|
||||
|
@ -138,13 +195,13 @@ __memblock_find_range_bottom_up(phys_addr_t start, phys_addr_t end,
|
|||
*
|
||||
* Utility called from memblock_find_in_range_node(), find free area top-down.
|
||||
*
|
||||
* RETURNS:
|
||||
* Return:
|
||||
* Found address on success, 0 on failure.
|
||||
*/
|
||||
static phys_addr_t __init_memblock
|
||||
__memblock_find_range_top_down(phys_addr_t start, phys_addr_t end,
|
||||
phys_addr_t size, phys_addr_t align, int nid,
|
||||
ulong flags)
|
||||
enum memblock_flags flags)
|
||||
{
|
||||
phys_addr_t this_start, this_end, cand;
|
||||
u64 i;
|
||||
|
@ -170,7 +227,8 @@ __memblock_find_range_top_down(phys_addr_t start, phys_addr_t end,
|
|||
* @size: size of free area to find
|
||||
* @align: alignment of free area to find
|
||||
* @start: start of candidate range
|
||||
* @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE}
|
||||
* @end: end of candidate range, can be %MEMBLOCK_ALLOC_ANYWHERE or
|
||||
* %MEMBLOCK_ALLOC_ACCESSIBLE
|
||||
* @nid: nid of the free area to find, %NUMA_NO_NODE for any node
|
||||
* @flags: pick from blocks based on memory attributes
|
||||
*
|
||||
|
@ -184,12 +242,13 @@ __memblock_find_range_top_down(phys_addr_t start, phys_addr_t end,
|
|||
*
|
||||
* If bottom-up allocation failed, will try to allocate memory top-down.
|
||||
*
|
||||
* RETURNS:
|
||||
* Return:
|
||||
* Found address on success, 0 on failure.
|
||||
*/
|
||||
phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size,
|
||||
phys_addr_t align, phys_addr_t start,
|
||||
phys_addr_t end, int nid, ulong flags)
|
||||
phys_addr_t end, int nid,
|
||||
enum memblock_flags flags)
|
||||
{
|
||||
phys_addr_t kernel_end, ret;
|
||||
|
||||
|
@ -239,13 +298,14 @@ phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size,
|
|||
/**
|
||||
* memblock_find_in_range - find free area in given range
|
||||
* @start: start of candidate range
|
||||
* @end: end of candidate range, can be %MEMBLOCK_ALLOC_{ANYWHERE|ACCESSIBLE}
|
||||
* @end: end of candidate range, can be %MEMBLOCK_ALLOC_ANYWHERE or
|
||||
* %MEMBLOCK_ALLOC_ACCESSIBLE
|
||||
* @size: size of free area to find
|
||||
* @align: alignment of free area to find
|
||||
*
|
||||
* Find @size free area aligned to @align in the specified range.
|
||||
*
|
||||
* RETURNS:
|
||||
* Return:
|
||||
* Found address on success, 0 on failure.
|
||||
*/
|
||||
phys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start,
|
||||
|
@ -253,7 +313,7 @@ phys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start,
|
|||
phys_addr_t align)
|
||||
{
|
||||
phys_addr_t ret;
|
||||
ulong flags = choose_memblock_flags();
|
||||
enum memblock_flags flags = choose_memblock_flags();
|
||||
|
||||
again:
|
||||
ret = memblock_find_in_range_node(size, align, start, end,
|
||||
|
@ -289,7 +349,7 @@ static void __init_memblock memblock_remove_region(struct memblock_type *type, u
|
|||
|
||||
#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
|
||||
/**
|
||||
* Discard memory and reserved arrays if they were allocated
|
||||
* memblock_discard - discard memory and reserved arrays if they were allocated
|
||||
*/
|
||||
void __init memblock_discard(void)
|
||||
{
|
||||
|
@ -319,11 +379,11 @@ void __init memblock_discard(void)
|
|||
*
|
||||
* Double the size of the @type regions array. If memblock is being used to
|
||||
* allocate memory for a new reserved regions array and there is a previously
|
||||
* allocated memory range [@new_area_start,@new_area_start+@new_area_size]
|
||||
* allocated memory range [@new_area_start, @new_area_start + @new_area_size]
|
||||
* waiting to be reserved, ensure the memory used by the new array does
|
||||
* not overlap.
|
||||
*
|
||||
* RETURNS:
|
||||
* Return:
|
||||
* 0 on success, -1 on failure.
|
||||
*/
|
||||
static int __init_memblock memblock_double_array(struct memblock_type *type,
|
||||
|
@ -468,13 +528,14 @@ static void __init_memblock memblock_merge_regions(struct memblock_type *type)
|
|||
* @nid: node id of the new region
|
||||
* @flags: flags of the new region
|
||||
*
|
||||
* Insert new memblock region [@base,@base+@size) into @type at @idx.
|
||||
* Insert new memblock region [@base, @base + @size) into @type at @idx.
|
||||
* @type must already have extra room to accommodate the new region.
|
||||
*/
|
||||
static void __init_memblock memblock_insert_region(struct memblock_type *type,
|
||||
int idx, phys_addr_t base,
|
||||
phys_addr_t size,
|
||||
int nid, unsigned long flags)
|
||||
int nid,
|
||||
enum memblock_flags flags)
|
||||
{
|
||||
struct memblock_region *rgn = &type->regions[idx];
|
||||
|
||||
|
@ -496,17 +557,17 @@ static void __init_memblock memblock_insert_region(struct memblock_type *type,
|
|||
* @nid: nid of the new region
|
||||
* @flags: flags of the new region
|
||||
*
|
||||
* Add new memblock region [@base,@base+@size) into @type. The new region
|
||||
* Add new memblock region [@base, @base + @size) into @type. The new region
|
||||
* is allowed to overlap with existing ones - overlaps don't affect already
|
||||
* existing regions. @type is guaranteed to be minimal (all neighbouring
|
||||
* compatible regions are merged) after the addition.
|
||||
*
|
||||
* RETURNS:
|
||||
* Return:
|
||||
* 0 on success, -errno on failure.
|
||||
*/
|
||||
int __init_memblock memblock_add_range(struct memblock_type *type,
|
||||
phys_addr_t base, phys_addr_t size,
|
||||
int nid, unsigned long flags)
|
||||
int nid, enum memblock_flags flags)
|
||||
{
|
||||
bool insert = false;
|
||||
phys_addr_t obase = base;
|
||||
|
@ -590,12 +651,35 @@ 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 nid)
|
||||
{
|
||||
return memblock_add_range(&memblock.memory, base, size, nid, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* memblock_add - add new memblock region
|
||||
* @base: base address of the new region
|
||||
* @size: size of the new region
|
||||
*
|
||||
* Add new memblock region [@base, @base + @size) to the "memory"
|
||||
* type. See memblock_add_range() description for mode details
|
||||
*
|
||||
* Return:
|
||||
* 0 on success, -errno on failure.
|
||||
*/
|
||||
int __init_memblock memblock_add(phys_addr_t base, phys_addr_t size)
|
||||
{
|
||||
phys_addr_t end = base + size - 1;
|
||||
|
@ -615,11 +699,11 @@ int __init_memblock memblock_add(phys_addr_t base, phys_addr_t size)
|
|||
* @end_rgn: out parameter for the end of isolated region
|
||||
*
|
||||
* Walk @type and ensure that regions don't cross the boundaries defined by
|
||||
* [@base,@base+@size). Crossing regions are split at the boundaries,
|
||||
* [@base, @base + @size). Crossing regions are split at the boundaries,
|
||||
* which may create at most two more regions. The index of the first
|
||||
* region inside the range is returned in *@start_rgn and end in *@end_rgn.
|
||||
*
|
||||
* RETURNS:
|
||||
* Return:
|
||||
* 0 on success, -errno on failure.
|
||||
*/
|
||||
static int __init_memblock memblock_isolate_range(struct memblock_type *type,
|
||||
|
@ -730,10 +814,15 @@ int __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size)
|
|||
}
|
||||
|
||||
/**
|
||||
* memblock_setclr_flag - set or clear flag for a memory region
|
||||
* @base: base address of the region
|
||||
* @size: size of the region
|
||||
* @set: set or clear the flag
|
||||
* @flag: the flag to udpate
|
||||
*
|
||||
* This function isolates region [@base, @base + @size), and sets/clears flag
|
||||
*
|
||||
* Return 0 on success, -errno on failure.
|
||||
* Return: 0 on success, -errno on failure.
|
||||
*/
|
||||
static int __init_memblock memblock_setclr_flag(phys_addr_t base,
|
||||
phys_addr_t size, int set, int flag)
|
||||
|
@ -760,7 +849,7 @@ static int __init_memblock memblock_setclr_flag(phys_addr_t base,
|
|||
* @base: the base phys addr of the region
|
||||
* @size: the size of the region
|
||||
*
|
||||
* Return 0 on success, -errno on failure.
|
||||
* Return: 0 on success, -errno on failure.
|
||||
*/
|
||||
int __init_memblock memblock_mark_hotplug(phys_addr_t base, phys_addr_t size)
|
||||
{
|
||||
|
@ -772,7 +861,7 @@ int __init_memblock memblock_mark_hotplug(phys_addr_t base, phys_addr_t size)
|
|||
* @base: the base phys addr of the region
|
||||
* @size: the size of the region
|
||||
*
|
||||
* Return 0 on success, -errno on failure.
|
||||
* Return: 0 on success, -errno on failure.
|
||||
*/
|
||||
int __init_memblock memblock_clear_hotplug(phys_addr_t base, phys_addr_t size)
|
||||
{
|
||||
|
@ -784,7 +873,7 @@ int __init_memblock memblock_clear_hotplug(phys_addr_t base, phys_addr_t size)
|
|||
* @base: the base phys addr of the region
|
||||
* @size: the size of the region
|
||||
*
|
||||
* Return 0 on success, -errno on failure.
|
||||
* Return: 0 on success, -errno on failure.
|
||||
*/
|
||||
int __init_memblock memblock_mark_mirror(phys_addr_t base, phys_addr_t size)
|
||||
{
|
||||
|
@ -798,7 +887,7 @@ int __init_memblock memblock_mark_mirror(phys_addr_t base, phys_addr_t size)
|
|||
* @base: the base phys addr of the region
|
||||
* @size: the size of the region
|
||||
*
|
||||
* Return 0 on success, -errno on failure.
|
||||
* Return: 0 on success, -errno on failure.
|
||||
*/
|
||||
int __init_memblock memblock_mark_nomap(phys_addr_t base, phys_addr_t size)
|
||||
{
|
||||
|
@ -810,7 +899,7 @@ int __init_memblock memblock_mark_nomap(phys_addr_t base, phys_addr_t size)
|
|||
* @base: the base phys addr of the region
|
||||
* @size: the size of the region
|
||||
*
|
||||
* Return 0 on success, -errno on failure.
|
||||
* Return: 0 on success, -errno on failure.
|
||||
*/
|
||||
int __init_memblock memblock_clear_nomap(phys_addr_t base, phys_addr_t size)
|
||||
{
|
||||
|
@ -875,7 +964,8 @@ void __init_memblock __next_reserved_mem_region(u64 *idx,
|
|||
* As both region arrays are sorted, the function advances the two indices
|
||||
* in lockstep and returns each intersection.
|
||||
*/
|
||||
void __init_memblock __next_mem_range(u64 *idx, int nid, ulong flags,
|
||||
void __init_memblock __next_mem_range(u64 *idx, int nid,
|
||||
enum memblock_flags flags,
|
||||
struct memblock_type *type_a,
|
||||
struct memblock_type *type_b,
|
||||
phys_addr_t *out_start,
|
||||
|
@ -970,9 +1060,6 @@ void __init_memblock __next_mem_range(u64 *idx, int nid, ulong flags,
|
|||
/**
|
||||
* __next_mem_range_rev - generic next function for for_each_*_range_rev()
|
||||
*
|
||||
* Finds the next range from type_a which is not marked as unsuitable
|
||||
* in type_b.
|
||||
*
|
||||
* @idx: pointer to u64 loop variable
|
||||
* @nid: node selector, %NUMA_NO_NODE for all nodes
|
||||
* @flags: pick from blocks based on memory attributes
|
||||
|
@ -982,9 +1069,13 @@ void __init_memblock __next_mem_range(u64 *idx, int nid, ulong flags,
|
|||
* @out_end: ptr to phys_addr_t for end address of the range, can be %NULL
|
||||
* @out_nid: ptr to int for nid of the range, can be %NULL
|
||||
*
|
||||
* Finds the next range from type_a which is not marked as unsuitable
|
||||
* in type_b.
|
||||
*
|
||||
* Reverse of __next_mem_range().
|
||||
*/
|
||||
void __init_memblock __next_mem_range_rev(u64 *idx, int nid, ulong flags,
|
||||
void __init_memblock __next_mem_range_rev(u64 *idx, int nid,
|
||||
enum memblock_flags flags,
|
||||
struct memblock_type *type_a,
|
||||
struct memblock_type *type_b,
|
||||
phys_addr_t *out_start,
|
||||
|
@ -1116,10 +1207,10 @@ void __init_memblock __next_mem_pfn_range(int *idx, int nid,
|
|||
* @type: memblock type to set node ID for
|
||||
* @nid: node ID to set
|
||||
*
|
||||
* Set the nid of memblock @type regions in [@base,@base+@size) to @nid.
|
||||
* Set the nid of memblock @type regions in [@base, @base + @size) to @nid.
|
||||
* Regions which cross the area boundaries are split as necessary.
|
||||
*
|
||||
* RETURNS:
|
||||
* Return:
|
||||
* 0 on success, -errno on failure.
|
||||
*/
|
||||
int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size,
|
||||
|
@ -1142,7 +1233,8 @@ int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size,
|
|||
|
||||
static phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size,
|
||||
phys_addr_t align, phys_addr_t start,
|
||||
phys_addr_t end, int nid, ulong flags)
|
||||
phys_addr_t end, int nid,
|
||||
enum memblock_flags flags)
|
||||
{
|
||||
phys_addr_t found;
|
||||
|
||||
|
@ -1164,7 +1256,7 @@ static phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size,
|
|||
|
||||
phys_addr_t __init memblock_alloc_range(phys_addr_t size, phys_addr_t align,
|
||||
phys_addr_t start, phys_addr_t end,
|
||||
ulong flags)
|
||||
enum memblock_flags flags)
|
||||
{
|
||||
return memblock_alloc_range_nid(size, align, start, end, NUMA_NO_NODE,
|
||||
flags);
|
||||
|
@ -1172,14 +1264,14 @@ phys_addr_t __init memblock_alloc_range(phys_addr_t size, phys_addr_t align,
|
|||
|
||||
phys_addr_t __init memblock_alloc_base_nid(phys_addr_t size,
|
||||
phys_addr_t align, phys_addr_t max_addr,
|
||||
int nid, ulong flags)
|
||||
int nid, enum memblock_flags flags)
|
||||
{
|
||||
return memblock_alloc_range_nid(size, align, 0, max_addr, nid, flags);
|
||||
}
|
||||
|
||||
phys_addr_t __init memblock_alloc_nid(phys_addr_t size, phys_addr_t align, int nid)
|
||||
{
|
||||
ulong flags = choose_memblock_flags();
|
||||
enum memblock_flags flags = choose_memblock_flags();
|
||||
phys_addr_t ret;
|
||||
|
||||
again:
|
||||
|
@ -1243,7 +1335,7 @@ phys_addr_t __init memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align, i
|
|||
* The allocation is performed from memory region limited by
|
||||
* memblock.current_limit if @max_addr == %BOOTMEM_ALLOC_ACCESSIBLE.
|
||||
*
|
||||
* The memory block is aligned on SMP_CACHE_BYTES if @align == 0.
|
||||
* The memory block is aligned on %SMP_CACHE_BYTES if @align == 0.
|
||||
*
|
||||
* The phys address of allocated boot memory block is converted to virtual and
|
||||
* allocated memory is reset to 0.
|
||||
|
@ -1251,7 +1343,7 @@ phys_addr_t __init memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align, i
|
|||
* In addition, function sets the min_count to 0 using kmemleak_alloc for
|
||||
* allocated boot memory block, so that it is never reported as leaks.
|
||||
*
|
||||
* RETURNS:
|
||||
* Return:
|
||||
* Virtual address of allocated memory block on success, NULL on failure.
|
||||
*/
|
||||
static void * __init memblock_virt_alloc_internal(
|
||||
|
@ -1261,7 +1353,7 @@ static void * __init memblock_virt_alloc_internal(
|
|||
{
|
||||
phys_addr_t alloc;
|
||||
void *ptr;
|
||||
ulong flags = choose_memblock_flags();
|
||||
enum memblock_flags flags = choose_memblock_flags();
|
||||
|
||||
if (WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n"))
|
||||
nid = NUMA_NO_NODE;
|
||||
|
@ -1336,7 +1428,7 @@ static void * __init memblock_virt_alloc_internal(
|
|||
* info), if enabled. Does not zero allocated memory, does not panic if request
|
||||
* cannot be satisfied.
|
||||
*
|
||||
* RETURNS:
|
||||
* Return:
|
||||
* Virtual address of allocated memory block on success, NULL on failure.
|
||||
*/
|
||||
void * __init memblock_virt_alloc_try_nid_raw(
|
||||
|
@ -1373,7 +1465,7 @@ void * __init memblock_virt_alloc_try_nid_raw(
|
|||
* Public function, provides additional debug information (including caller
|
||||
* info), if enabled. This function zeroes the allocated memory.
|
||||
*
|
||||
* RETURNS:
|
||||
* Return:
|
||||
* Virtual address of allocated memory block on success, NULL on failure.
|
||||
*/
|
||||
void * __init memblock_virt_alloc_try_nid_nopanic(
|
||||
|
@ -1409,7 +1501,7 @@ void * __init memblock_virt_alloc_try_nid_nopanic(
|
|||
* which provides debug information (including caller info), if enabled,
|
||||
* and panics if the request can not be satisfied.
|
||||
*
|
||||
* RETURNS:
|
||||
* Return:
|
||||
* Virtual address of allocated memory block on success, NULL on failure.
|
||||
*/
|
||||
void * __init memblock_virt_alloc_try_nid(
|
||||
|
@ -1453,9 +1545,9 @@ void __init __memblock_free_early(phys_addr_t base, phys_addr_t size)
|
|||
memblock_remove_range(&memblock.reserved, base, size);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* __memblock_free_late - free bootmem block pages directly to buddy allocator
|
||||
* @addr: phys starting address of the boot memory block
|
||||
* @base: phys starting address of the boot memory block
|
||||
* @size: size of the boot memory block in bytes
|
||||
*
|
||||
* This is only useful when the bootmem allocator has already been torn
|
||||
|
@ -1667,9 +1759,9 @@ int __init_memblock memblock_search_pfn_nid(unsigned long pfn,
|
|||
* @base: base of region to check
|
||||
* @size: size of region to check
|
||||
*
|
||||
* Check if the region [@base, @base+@size) is a subset of a memory block.
|
||||
* Check if the region [@base, @base + @size) is a subset of a memory block.
|
||||
*
|
||||
* RETURNS:
|
||||
* Return:
|
||||
* 0 if false, non-zero if true
|
||||
*/
|
||||
bool __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size)
|
||||
|
@ -1688,9 +1780,10 @@ bool __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t siz
|
|||
* @base: base of region to check
|
||||
* @size: size of region to check
|
||||
*
|
||||
* Check if the region [@base, @base+@size) intersects a reserved memory block.
|
||||
* Check if the region [@base, @base + @size) intersects a reserved
|
||||
* memory block.
|
||||
*
|
||||
* RETURNS:
|
||||
* Return:
|
||||
* True if they intersect, false if not.
|
||||
*/
|
||||
bool __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size)
|
||||
|
@ -1737,7 +1830,7 @@ phys_addr_t __init_memblock memblock_get_current_limit(void)
|
|||
static void __init_memblock memblock_dump(struct memblock_type *type)
|
||||
{
|
||||
phys_addr_t base, end, size;
|
||||
unsigned long flags;
|
||||
enum memblock_flags flags;
|
||||
int idx;
|
||||
struct memblock_region *rgn;
|
||||
|
||||
|
@ -1755,7 +1848,7 @@ static void __init_memblock memblock_dump(struct memblock_type *type)
|
|||
snprintf(nid_buf, sizeof(nid_buf), " on node %d",
|
||||
memblock_get_region_node(rgn));
|
||||
#endif
|
||||
pr_info(" %s[%#x]\t[%pa-%pa], %pa bytes%s flags: %#lx\n",
|
||||
pr_info(" %s[%#x]\t[%pa-%pa], %pa bytes%s flags: %#x\n",
|
||||
type->name, idx, &base, &end, &size, nid_buf, flags);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ static void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
|
|||
{
|
||||
void *ptr;
|
||||
u64 addr;
|
||||
ulong flags = choose_memblock_flags();
|
||||
enum memblock_flags flags = choose_memblock_flags();
|
||||
|
||||
if (limit > memblock.current_limit)
|
||||
limit = memblock.current_limit;
|
||||
|
@ -72,7 +72,7 @@ static void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
|
|||
return ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* free_bootmem_late - free bootmem pages directly to page allocator
|
||||
* @addr: starting address of the range
|
||||
* @size: size of the range in bytes
|
||||
|
@ -176,7 +176,7 @@ void __init reset_all_zones_managed_pages(void)
|
|||
/**
|
||||
* free_all_bootmem - release free pages to the buddy allocator
|
||||
*
|
||||
* Returns the number of pages actually released.
|
||||
* Return: the number of pages actually released.
|
||||
*/
|
||||
unsigned long __init free_all_bootmem(void)
|
||||
{
|
||||
|
@ -193,7 +193,7 @@ unsigned long __init free_all_bootmem(void)
|
|||
/**
|
||||
* free_bootmem_node - mark a page range as usable
|
||||
* @pgdat: node the range resides on
|
||||
* @physaddr: starting address of the range
|
||||
* @physaddr: starting physical address of the range
|
||||
* @size: size of the range in bytes
|
||||
*
|
||||
* Partial pages will be considered reserved and left as they are.
|
||||
|
@ -208,7 +208,7 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
|
|||
|
||||
/**
|
||||
* free_bootmem - mark a page range as usable
|
||||
* @addr: starting address of the range
|
||||
* @addr: starting physical address of the range
|
||||
* @size: size of the range in bytes
|
||||
*
|
||||
* Partial pages will be considered reserved and left as they are.
|
||||
|
@ -256,7 +256,7 @@ static void * __init ___alloc_bootmem_nopanic(unsigned long size,
|
|||
*
|
||||
* Allocation may happen on any node in the system.
|
||||
*
|
||||
* Returns NULL on failure.
|
||||
* Return: address of the allocated region or %NULL on failure.
|
||||
*/
|
||||
void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align,
|
||||
unsigned long goal)
|
||||
|
@ -293,6 +293,8 @@ static void * __init ___alloc_bootmem(unsigned long size, unsigned long align,
|
|||
* Allocation may happen on any node in the system.
|
||||
*
|
||||
* The function panics if the request can not be satisfied.
|
||||
*
|
||||
* Return: address of the allocated region.
|
||||
*/
|
||||
void * __init __alloc_bootmem(unsigned long size, unsigned long align,
|
||||
unsigned long goal)
|
||||
|
@ -367,6 +369,8 @@ static void * __init ___alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
|
|||
* can not hold the requested memory.
|
||||
*
|
||||
* The function panics if the request can not be satisfied.
|
||||
*
|
||||
* Return: address of the allocated region.
|
||||
*/
|
||||
void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
|
||||
unsigned long align, unsigned long goal)
|
||||
|
@ -396,6 +400,8 @@ void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
|
|||
* Allocation may happen on any node in the system.
|
||||
*
|
||||
* The function panics if the request can not be satisfied.
|
||||
*
|
||||
* Return: address of the allocated region.
|
||||
*/
|
||||
void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,
|
||||
unsigned long goal)
|
||||
|
@ -425,6 +431,8 @@ void * __init __alloc_bootmem_low_nopanic(unsigned long size,
|
|||
* can not hold the requested memory.
|
||||
*
|
||||
* The function panics if the request can not be satisfied.
|
||||
*
|
||||
* Return: address of the allocated region.
|
||||
*/
|
||||
void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size,
|
||||
unsigned long align, unsigned long goal)
|
||||
|
|
|
@ -75,6 +75,12 @@ while (<IN>) {
|
|||
# Remove URL false-positives
|
||||
next if ($fulref =~ m/^http/);
|
||||
|
||||
# Remove sched-pelt false-positive
|
||||
next if ($fulref =~ m,^Documentation/scheduler/sched-pelt$,);
|
||||
|
||||
# Discard some build examples from Documentation/target/tcm_mod_builder.txt
|
||||
next if ($fulref =~ m,mnt/sdb/lio-core-2.6.git/Documentation/target,);
|
||||
|
||||
# Check if exists, evaluating wildcards
|
||||
next if (grep -e, glob("$ref $fulref"));
|
||||
|
||||
|
|
|
@ -1062,7 +1062,7 @@ sub dump_struct($$) {
|
|||
my $x = shift;
|
||||
my $file = shift;
|
||||
|
||||
if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) {
|
||||
if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}/) {
|
||||
my $decl_type = $1;
|
||||
$declaration_name = $2;
|
||||
my $members = $3;
|
||||
|
@ -1148,20 +1148,20 @@ sub dump_struct($$) {
|
|||
}
|
||||
}
|
||||
}
|
||||
$members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)}([^\{\}\;]*)\;/$newmember/;
|
||||
$members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/$newmember/;
|
||||
}
|
||||
|
||||
# Ignore other nested elements, like enums
|
||||
$members =~ s/({[^\{\}]*})//g;
|
||||
$members =~ s/(\{[^\{\}]*\})//g;
|
||||
|
||||
create_parameterlist($members, ';', $file, $declaration_name);
|
||||
check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual);
|
||||
|
||||
# Adjust declaration for better display
|
||||
$declaration =~ s/([{;])/$1\n/g;
|
||||
$declaration =~ s/}\s+;/};/g;
|
||||
$declaration =~ s/([\{;])/$1\n/g;
|
||||
$declaration =~ s/\}\s+;/};/g;
|
||||
# Better handle inlined enums
|
||||
do {} while ($declaration =~ s/(enum\s+{[^}]+),([^\n])/$1,\n$2/);
|
||||
do {} while ($declaration =~ s/(enum\s+\{[^\}]+),([^\n])/$1,\n$2/);
|
||||
|
||||
my @def_args = split /\n/, $declaration;
|
||||
my $level = 1;
|
||||
|
@ -1171,12 +1171,12 @@ sub dump_struct($$) {
|
|||
$clause =~ s/\s+$//;
|
||||
$clause =~ s/\s+/ /;
|
||||
next if (!$clause);
|
||||
$level-- if ($clause =~ m/(})/ && $level > 1);
|
||||
$level-- if ($clause =~ m/(\})/ && $level > 1);
|
||||
if (!($clause =~ m/^\s*#/)) {
|
||||
$declaration .= "\t" x $level;
|
||||
}
|
||||
$declaration .= "\t" . $clause . "\n";
|
||||
$level++ if ($clause =~ m/({)/ && !($clause =~m/}/));
|
||||
$level++ if ($clause =~ m/(\{)/ && !($clause =~m/\}/));
|
||||
}
|
||||
output_declaration($declaration_name,
|
||||
'struct',
|
||||
|
@ -1244,7 +1244,7 @@ sub dump_enum($$) {
|
|||
# strip #define macros inside enums
|
||||
$x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos;
|
||||
|
||||
if ($x =~ /enum\s+(\w+)\s*{(.*)}/) {
|
||||
if ($x =~ /enum\s+(\w+)\s*\{(.*)\}/) {
|
||||
$declaration_name = $1;
|
||||
my $members = $2;
|
||||
my %_members;
|
||||
|
@ -1785,7 +1785,7 @@ sub process_proto_type($$) {
|
|||
}
|
||||
|
||||
while (1) {
|
||||
if ( $x =~ /([^{};]*)([{};])(.*)/ ) {
|
||||
if ( $x =~ /([^\{\};]*)([\{\};])(.*)/ ) {
|
||||
if( length $prototype ) {
|
||||
$prototype .= " "
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue