mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 15:50:59 +07:00
Merge ../torvalds-2.6/
This commit is contained in:
commit
ad2c10f8f0
4
COPYING
4
COPYING
@ -18,7 +18,7 @@
|
|||||||
Version 2, June 1991
|
Version 2, June 1991
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
of this license document, but changing it is not allowed.
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
@ -321,7 +321,7 @@ the "copyright" line and a pointer to where the full notice is found.
|
|||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
@ -46,6 +46,8 @@ SubmittingPatches
|
|||||||
- procedure to get a source patch included into the kernel tree.
|
- procedure to get a source patch included into the kernel tree.
|
||||||
VGA-softcursor.txt
|
VGA-softcursor.txt
|
||||||
- how to change your VGA cursor from a blinking underscore.
|
- how to change your VGA cursor from a blinking underscore.
|
||||||
|
applying-patches.txt
|
||||||
|
- description of various trees and how to apply their patches.
|
||||||
arm/
|
arm/
|
||||||
- directory with info about Linux on the ARM architecture.
|
- directory with info about Linux on the ARM architecture.
|
||||||
basic_profiling.txt
|
basic_profiling.txt
|
||||||
@ -275,7 +277,7 @@ tty.txt
|
|||||||
unicode.txt
|
unicode.txt
|
||||||
- info on the Unicode character/font mapping used in Linux.
|
- info on the Unicode character/font mapping used in Linux.
|
||||||
uml/
|
uml/
|
||||||
- directory with infomation about User Mode Linux.
|
- directory with information about User Mode Linux.
|
||||||
usb/
|
usb/
|
||||||
- directory with info regarding the Universal Serial Bus.
|
- directory with info regarding the Universal Serial Bus.
|
||||||
video4linux/
|
video4linux/
|
||||||
|
@ -236,6 +236,9 @@ ugly), but try to avoid excess. Instead, put the comments at the head
|
|||||||
of the function, telling people what it does, and possibly WHY it does
|
of the function, telling people what it does, and possibly WHY it does
|
||||||
it.
|
it.
|
||||||
|
|
||||||
|
When commenting the kernel API functions, please use the kerneldoc format.
|
||||||
|
See the files Documentation/kernel-doc-nano-HOWTO.txt and scripts/kernel-doc
|
||||||
|
for details.
|
||||||
|
|
||||||
Chapter 8: You've made a mess of it
|
Chapter 8: You've made a mess of it
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ pool's device.
|
|||||||
dma_addr_t addr);
|
dma_addr_t addr);
|
||||||
|
|
||||||
This puts memory back into the pool. The pool is what was passed to
|
This puts memory back into the pool. The pool is what was passed to
|
||||||
the the pool allocation routine; the cpu and dma addresses are what
|
the pool allocation routine; the cpu and dma addresses are what
|
||||||
were returned when that routine allocated the memory being freed.
|
were returned when that routine allocated the memory being freed.
|
||||||
|
|
||||||
|
|
||||||
|
151
Documentation/DMA-ISA-LPC.txt
Normal file
151
Documentation/DMA-ISA-LPC.txt
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
DMA with ISA and LPC devices
|
||||||
|
============================
|
||||||
|
|
||||||
|
Pierre Ossman <drzeus@drzeus.cx>
|
||||||
|
|
||||||
|
This document describes how to do DMA transfers using the old ISA DMA
|
||||||
|
controller. Even though ISA is more or less dead today the LPC bus
|
||||||
|
uses the same DMA system so it will be around for quite some time.
|
||||||
|
|
||||||
|
Part I - Headers and dependencies
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
To do ISA style DMA you need to include two headers:
|
||||||
|
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <asm/dma.h>
|
||||||
|
|
||||||
|
The first is the generic DMA API used to convert virtual addresses to
|
||||||
|
physical addresses (see Documentation/DMA-API.txt for details).
|
||||||
|
|
||||||
|
The second contains the routines specific to ISA DMA transfers. Since
|
||||||
|
this is not present on all platforms make sure you construct your
|
||||||
|
Kconfig to be dependent on ISA_DMA_API (not ISA) so that nobody tries
|
||||||
|
to build your driver on unsupported platforms.
|
||||||
|
|
||||||
|
Part II - Buffer allocation
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
The ISA DMA controller has some very strict requirements on which
|
||||||
|
memory it can access so extra care must be taken when allocating
|
||||||
|
buffers.
|
||||||
|
|
||||||
|
(You usually need a special buffer for DMA transfers instead of
|
||||||
|
transferring directly to and from your normal data structures.)
|
||||||
|
|
||||||
|
The DMA-able address space is the lowest 16 MB of _physical_ memory.
|
||||||
|
Also the transfer block may not cross page boundaries (which are 64
|
||||||
|
or 128 KiB depending on which channel you use).
|
||||||
|
|
||||||
|
In order to allocate a piece of memory that satisfies all these
|
||||||
|
requirements you pass the flag GFP_DMA to kmalloc.
|
||||||
|
|
||||||
|
Unfortunately the memory available for ISA DMA is scarce so unless you
|
||||||
|
allocate the memory during boot-up it's a good idea to also pass
|
||||||
|
__GFP_REPEAT and __GFP_NOWARN to make the allocater try a bit harder.
|
||||||
|
|
||||||
|
(This scarcity also means that you should allocate the buffer as
|
||||||
|
early as possible and not release it until the driver is unloaded.)
|
||||||
|
|
||||||
|
Part III - Address translation
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
To translate the virtual address to a physical use the normal DMA
|
||||||
|
API. Do _not_ use isa_virt_to_phys() even though it does the same
|
||||||
|
thing. The reason for this is that the function isa_virt_to_phys()
|
||||||
|
will require a Kconfig dependency to ISA, not just ISA_DMA_API which
|
||||||
|
is really all you need. Remember that even though the DMA controller
|
||||||
|
has its origins in ISA it is used elsewhere.
|
||||||
|
|
||||||
|
Note: x86_64 had a broken DMA API when it came to ISA but has since
|
||||||
|
been fixed. If your arch has problems then fix the DMA API instead of
|
||||||
|
reverting to the ISA functions.
|
||||||
|
|
||||||
|
Part IV - Channels
|
||||||
|
------------------
|
||||||
|
|
||||||
|
A normal ISA DMA controller has 8 channels. The lower four are for
|
||||||
|
8-bit transfers and the upper four are for 16-bit transfers.
|
||||||
|
|
||||||
|
(Actually the DMA controller is really two separate controllers where
|
||||||
|
channel 4 is used to give DMA access for the second controller (0-3).
|
||||||
|
This means that of the four 16-bits channels only three are usable.)
|
||||||
|
|
||||||
|
You allocate these in a similar fashion as all basic resources:
|
||||||
|
|
||||||
|
extern int request_dma(unsigned int dmanr, const char * device_id);
|
||||||
|
extern void free_dma(unsigned int dmanr);
|
||||||
|
|
||||||
|
The ability to use 16-bit or 8-bit transfers is _not_ up to you as a
|
||||||
|
driver author but depends on what the hardware supports. Check your
|
||||||
|
specs or test different channels.
|
||||||
|
|
||||||
|
Part V - Transfer data
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Now for the good stuff, the actual DMA transfer. :)
|
||||||
|
|
||||||
|
Before you use any ISA DMA routines you need to claim the DMA lock
|
||||||
|
using claim_dma_lock(). The reason is that some DMA operations are
|
||||||
|
not atomic so only one driver may fiddle with the registers at a
|
||||||
|
time.
|
||||||
|
|
||||||
|
The first time you use the DMA controller you should call
|
||||||
|
clear_dma_ff(). This clears an internal register in the DMA
|
||||||
|
controller that is used for the non-atomic operations. As long as you
|
||||||
|
(and everyone else) uses the locking functions then you only need to
|
||||||
|
reset this once.
|
||||||
|
|
||||||
|
Next, you tell the controller in which direction you intend to do the
|
||||||
|
transfer using set_dma_mode(). Currently you have the options
|
||||||
|
DMA_MODE_READ and DMA_MODE_WRITE.
|
||||||
|
|
||||||
|
Set the address from where the transfer should start (this needs to
|
||||||
|
be 16-bit aligned for 16-bit transfers) and how many bytes to
|
||||||
|
transfer. Note that it's _bytes_. The DMA routines will do all the
|
||||||
|
required translation to values that the DMA controller understands.
|
||||||
|
|
||||||
|
The final step is enabling the DMA channel and releasing the DMA
|
||||||
|
lock.
|
||||||
|
|
||||||
|
Once the DMA transfer is finished (or timed out) you should disable
|
||||||
|
the channel again. You should also check get_dma_residue() to make
|
||||||
|
sure that all data has been transfered.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
int flags, residue;
|
||||||
|
|
||||||
|
flags = claim_dma_lock();
|
||||||
|
|
||||||
|
clear_dma_ff();
|
||||||
|
|
||||||
|
set_dma_mode(channel, DMA_MODE_WRITE);
|
||||||
|
set_dma_addr(channel, phys_addr);
|
||||||
|
set_dma_count(channel, num_bytes);
|
||||||
|
|
||||||
|
dma_enable(channel);
|
||||||
|
|
||||||
|
release_dma_lock(flags);
|
||||||
|
|
||||||
|
while (!device_done());
|
||||||
|
|
||||||
|
flags = claim_dma_lock();
|
||||||
|
|
||||||
|
dma_disable(channel);
|
||||||
|
|
||||||
|
residue = dma_get_residue(channel);
|
||||||
|
if (residue != 0)
|
||||||
|
printk(KERN_ERR "driver: Incomplete DMA transfer!"
|
||||||
|
" %d bytes left!\n", residue);
|
||||||
|
|
||||||
|
release_dma_lock(flags);
|
||||||
|
|
||||||
|
Part VI - Suspend/resume
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
It is the driver's responsibility to make sure that the machine isn't
|
||||||
|
suspended while a DMA transfer is in progress. Also, all DMA settings
|
||||||
|
are lost when the system suspends so if your driver relies on the DMA
|
||||||
|
controller being in a certain state then you have to restore these
|
||||||
|
registers upon resume.
|
@ -116,7 +116,7 @@ filesystem. Almost.
|
|||||||
|
|
||||||
You still need to actually journal your filesystem changes, this
|
You still need to actually journal your filesystem changes, this
|
||||||
is done by wrapping them into transactions. Additionally you
|
is done by wrapping them into transactions. Additionally you
|
||||||
also need to wrap the modification of each of the the buffers
|
also need to wrap the modification of each of the buffers
|
||||||
with calls to the journal layer, so it knows what the modifications
|
with calls to the journal layer, so it knows what the modifications
|
||||||
you are actually making are. To do this use journal_start() which
|
you are actually making are. To do this use journal_start() which
|
||||||
returns a transaction handle.
|
returns a transaction handle.
|
||||||
@ -128,7 +128,7 @@ and its counterpart journal_stop(), which indicates the end of a transaction
|
|||||||
are nestable calls, so you can reenter a transaction if necessary,
|
are nestable calls, so you can reenter a transaction if necessary,
|
||||||
but remember you must call journal_stop() the same number of times as
|
but remember you must call journal_stop() the same number of times as
|
||||||
journal_start() before the transaction is completed (or more accurately
|
journal_start() before the transaction is completed (or more accurately
|
||||||
leaves the the update phase). Ext3/VFS makes use of this feature to simplify
|
leaves the update phase). Ext3/VFS makes use of this feature to simplify
|
||||||
quota support.
|
quota support.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
@ -8,8 +8,7 @@
|
|||||||
|
|
||||||
<authorgroup>
|
<authorgroup>
|
||||||
<author>
|
<author>
|
||||||
<firstname>Paul</firstname>
|
<firstname>Rusty</firstname>
|
||||||
<othername>Rusty</othername>
|
|
||||||
<surname>Russell</surname>
|
<surname>Russell</surname>
|
||||||
<affiliation>
|
<affiliation>
|
||||||
<address>
|
<address>
|
||||||
@ -20,7 +19,7 @@
|
|||||||
</authorgroup>
|
</authorgroup>
|
||||||
|
|
||||||
<copyright>
|
<copyright>
|
||||||
<year>2001</year>
|
<year>2005</year>
|
||||||
<holder>Rusty Russell</holder>
|
<holder>Rusty Russell</holder>
|
||||||
</copyright>
|
</copyright>
|
||||||
|
|
||||||
@ -64,7 +63,7 @@
|
|||||||
<chapter id="introduction">
|
<chapter id="introduction">
|
||||||
<title>Introduction</title>
|
<title>Introduction</title>
|
||||||
<para>
|
<para>
|
||||||
Welcome, gentle reader, to Rusty's Unreliable Guide to Linux
|
Welcome, gentle reader, to Rusty's Remarkably Unreliable Guide to Linux
|
||||||
Kernel Hacking. This document describes the common routines and
|
Kernel Hacking. This document describes the common routines and
|
||||||
general requirements for kernel code: its goal is to serve as a
|
general requirements for kernel code: its goal is to serve as a
|
||||||
primer for Linux kernel development for experienced C
|
primer for Linux kernel development for experienced C
|
||||||
@ -96,13 +95,13 @@
|
|||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
not associated with any process, serving a softirq, tasklet or bh;
|
not associated with any process, serving a softirq or tasklet;
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
running in kernel space, associated with a process;
|
running in kernel space, associated with a process (user context);
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
@ -114,11 +113,12 @@
|
|||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
There is a strict ordering between these: other than the last
|
There is an ordering between these. The bottom two can preempt
|
||||||
category (userspace) each can only be pre-empted by those above.
|
each other, but above that is a strict hierarchy: each can only be
|
||||||
For example, while a softirq is running on a CPU, no other
|
preempted by the ones above it. For example, while a softirq is
|
||||||
softirq will pre-empt it, but a hardware interrupt can. However,
|
running on a CPU, no other softirq will preempt it, but a hardware
|
||||||
any other CPUs in the system execute independently.
|
interrupt can. However, any other CPUs in the system execute
|
||||||
|
independently.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -130,10 +130,10 @@
|
|||||||
<title>User Context</title>
|
<title>User Context</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
User context is when you are coming in from a system call or
|
User context is when you are coming in from a system call or other
|
||||||
other trap: you can sleep, and you own the CPU (except for
|
trap: like userspace, you can be preempted by more important tasks
|
||||||
interrupts) until you call <function>schedule()</function>.
|
and by interrupts. You can sleep, by calling
|
||||||
In other words, user context (unlike userspace) is not pre-emptable.
|
<function>schedule()</function>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
@ -153,7 +153,7 @@
|
|||||||
|
|
||||||
<caution>
|
<caution>
|
||||||
<para>
|
<para>
|
||||||
Beware that if you have interrupts or bottom halves disabled
|
Beware that if you have preemption or softirqs disabled
|
||||||
(see below), <function>in_interrupt()</function> will return a
|
(see below), <function>in_interrupt()</function> will return a
|
||||||
false positive.
|
false positive.
|
||||||
</para>
|
</para>
|
||||||
@ -168,10 +168,10 @@
|
|||||||
<hardware>keyboard</hardware> are examples of real
|
<hardware>keyboard</hardware> are examples of real
|
||||||
hardware which produce interrupts at any time. The kernel runs
|
hardware which produce interrupts at any time. The kernel runs
|
||||||
interrupt handlers, which services the hardware. The kernel
|
interrupt handlers, which services the hardware. The kernel
|
||||||
guarantees that this handler is never re-entered: if another
|
guarantees that this handler is never re-entered: if the same
|
||||||
interrupt arrives, it is queued (or dropped). Because it
|
interrupt arrives, it is queued (or dropped). Because it
|
||||||
disables interrupts, this handler has to be fast: frequently it
|
disables interrupts, this handler has to be fast: frequently it
|
||||||
simply acknowledges the interrupt, marks a `software interrupt'
|
simply acknowledges the interrupt, marks a 'software interrupt'
|
||||||
for execution and exits.
|
for execution and exits.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@ -188,60 +188,52 @@
|
|||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="basics-softirqs">
|
<sect1 id="basics-softirqs">
|
||||||
<title>Software Interrupt Context: Bottom Halves, Tasklets, softirqs</title>
|
<title>Software Interrupt Context: Softirqs and Tasklets</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Whenever a system call is about to return to userspace, or a
|
Whenever a system call is about to return to userspace, or a
|
||||||
hardware interrupt handler exits, any `software interrupts'
|
hardware interrupt handler exits, any 'software interrupts'
|
||||||
which are marked pending (usually by hardware interrupts) are
|
which are marked pending (usually by hardware interrupts) are
|
||||||
run (<filename>kernel/softirq.c</filename>).
|
run (<filename>kernel/softirq.c</filename>).
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Much of the real interrupt handling work is done here. Early in
|
Much of the real interrupt handling work is done here. Early in
|
||||||
the transition to <acronym>SMP</acronym>, there were only `bottom
|
the transition to <acronym>SMP</acronym>, there were only 'bottom
|
||||||
halves' (BHs), which didn't take advantage of multiple CPUs. Shortly
|
halves' (BHs), which didn't take advantage of multiple CPUs. Shortly
|
||||||
after we switched from wind-up computers made of match-sticks and snot,
|
after we switched from wind-up computers made of match-sticks and snot,
|
||||||
we abandoned this limitation.
|
we abandoned this limitation and switched to 'softirqs'.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<filename class="headerfile">include/linux/interrupt.h</filename> lists the
|
<filename class="headerfile">include/linux/interrupt.h</filename> lists the
|
||||||
different BH's. No matter how many CPUs you have, no two BHs will run at
|
different softirqs. A very important softirq is the
|
||||||
the same time. This made the transition to SMP simpler, but sucks hard for
|
timer softirq (<filename
|
||||||
scalable performance. A very important bottom half is the timer
|
class="headerfile">include/linux/timer.h</filename>): you can
|
||||||
BH (<filename class="headerfile">include/linux/timer.h</filename>): you
|
register to have it call functions for you in a given length of
|
||||||
can register to have it call functions for you in a given length of time.
|
time.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
2.3.43 introduced softirqs, and re-implemented the (now
|
Softirqs are often a pain to deal with, since the same softirq
|
||||||
deprecated) BHs underneath them. Softirqs are fully-SMP
|
will run simultaneously on more than one CPU. For this reason,
|
||||||
versions of BHs: they can run on as many CPUs at once as
|
tasklets (<filename
|
||||||
required. This means they need to deal with any races in shared
|
class="headerfile">include/linux/interrupt.h</filename>) are more
|
||||||
data using their own locks. A bitmask is used to keep track of
|
often used: they are dynamically-registrable (meaning you can have
|
||||||
which are enabled, so the 32 available softirqs should not be
|
as many as you want), and they also guarantee that any tasklet
|
||||||
used up lightly. (<emphasis>Yes</emphasis>, people will
|
will only run on one CPU at any time, although different tasklets
|
||||||
notice).
|
can run simultaneously.
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
tasklets (<filename class="headerfile">include/linux/interrupt.h</filename>)
|
|
||||||
are like softirqs, except they are dynamically-registrable (meaning you
|
|
||||||
can have as many as you want), and they also guarantee that any tasklet
|
|
||||||
will only run on one CPU at any time, although different tasklets can
|
|
||||||
run simultaneously (unlike different BHs).
|
|
||||||
</para>
|
</para>
|
||||||
<caution>
|
<caution>
|
||||||
<para>
|
<para>
|
||||||
The name `tasklet' is misleading: they have nothing to do with `tasks',
|
The name 'tasklet' is misleading: they have nothing to do with 'tasks',
|
||||||
and probably more to do with some bad vodka Alexey Kuznetsov had at the
|
and probably more to do with some bad vodka Alexey Kuznetsov had at the
|
||||||
time.
|
time.
|
||||||
</para>
|
</para>
|
||||||
</caution>
|
</caution>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
You can tell you are in a softirq (or bottom half, or tasklet)
|
You can tell you are in a softirq (or tasklet)
|
||||||
using the <function>in_softirq()</function> macro
|
using the <function>in_softirq()</function> macro
|
||||||
(<filename class="headerfile">include/linux/interrupt.h</filename>).
|
(<filename class="headerfile">include/linux/interrupt.h</filename>).
|
||||||
</para>
|
</para>
|
||||||
@ -288,11 +280,10 @@
|
|||||||
<term>A rigid stack limit</term>
|
<term>A rigid stack limit</term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The kernel stack is about 6K in 2.2 (for most
|
Depending on configuration options the kernel stack is about 3K to 6K for most 32-bit architectures: it's
|
||||||
architectures: it's about 14K on the Alpha), and shared
|
about 14K on most 64-bit archs, and often shared with interrupts
|
||||||
with interrupts so you can't use it all. Avoid deep
|
so you can't use it all. Avoid deep recursion and huge local
|
||||||
recursion and huge local arrays on the stack (allocate
|
arrays on the stack (allocate them dynamically instead).
|
||||||
them dynamically instead).
|
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -339,7 +330,7 @@ asmlinkage long sys_mycall(int arg)
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
If all your routine does is read or write some parameter, consider
|
If all your routine does is read or write some parameter, consider
|
||||||
implementing a <function>sysctl</function> interface instead.
|
implementing a <function>sysfs</function> interface instead.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -417,7 +408,10 @@ cond_resched(); /* Will sleep */
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
You will eventually lock up your box if you break these rules.
|
You should always compile your kernel
|
||||||
|
<symbol>CONFIG_DEBUG_SPINLOCK_SLEEP</symbol> on, and it will warn
|
||||||
|
you if you break these rules. If you <emphasis>do</emphasis> break
|
||||||
|
the rules, you will eventually lock up your box.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -515,8 +509,7 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
success).
|
success).
|
||||||
</para>
|
</para>
|
||||||
</caution>
|
</caution>
|
||||||
[Yes, this moronic interface makes me cringe. Please submit a
|
[Yes, this moronic interface makes me cringe. The flamewar comes up every year or so. --RR.]
|
||||||
patch and become my hero --RR.]
|
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The functions may sleep implicitly. This should never be called
|
The functions may sleep implicitly. This should never be called
|
||||||
@ -587,10 +580,11 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If you see a <errorname>kmem_grow: Called nonatomically from int
|
If you see a <errorname>sleeping function called from invalid
|
||||||
</errorname> warning message you called a memory allocation function
|
context</errorname> warning message, then maybe you called a
|
||||||
from interrupt context without <constant>GFP_ATOMIC</constant>.
|
sleeping allocation function from interrupt context without
|
||||||
You should really fix that. Run, don't walk.
|
<constant>GFP_ATOMIC</constant>. You should really fix that.
|
||||||
|
Run, don't walk.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -639,16 +633,16 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="routines-udelay">
|
<sect1 id="routines-udelay">
|
||||||
<title><function>udelay()</function>/<function>mdelay()</function>
|
<title><function>mdelay()</function>/<function>udelay()</function>
|
||||||
<filename class="headerfile">include/asm/delay.h</filename>
|
<filename class="headerfile">include/asm/delay.h</filename>
|
||||||
<filename class="headerfile">include/linux/delay.h</filename>
|
<filename class="headerfile">include/linux/delay.h</filename>
|
||||||
</title>
|
</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The <function>udelay()</function> function can be used for small pauses.
|
The <function>udelay()</function> and <function>ndelay()</function> functions can be used for small pauses.
|
||||||
Do not use large values with <function>udelay()</function> as you risk
|
Do not use large values with them as you risk
|
||||||
overflow - the helper function <function>mdelay()</function> is useful
|
overflow - the helper function <function>mdelay()</function> is useful
|
||||||
here, or even consider <function>schedule_timeout()</function>.
|
here, or consider <function>msleep()</function>.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -698,8 +692,8 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
These routines disable soft interrupts on the local CPU, and
|
These routines disable soft interrupts on the local CPU, and
|
||||||
restore them. They are reentrant; if soft interrupts were
|
restore them. They are reentrant; if soft interrupts were
|
||||||
disabled before, they will still be disabled after this pair
|
disabled before, they will still be disabled after this pair
|
||||||
of functions has been called. They prevent softirqs, tasklets
|
of functions has been called. They prevent softirqs and tasklets
|
||||||
and bottom halves from running on the current CPU.
|
from running on the current CPU.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -708,10 +702,16 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
<filename class="headerfile">include/asm/smp.h</filename></title>
|
<filename class="headerfile">include/asm/smp.h</filename></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<function>smp_processor_id()</function> returns the current
|
<function>get_cpu()</function> disables preemption (so you won't
|
||||||
processor number, between 0 and <symbol>NR_CPUS</symbol> (the
|
suddenly get moved to another CPU) and returns the current
|
||||||
maximum number of CPUs supported by Linux, currently 32). These
|
processor number, between 0 and <symbol>NR_CPUS</symbol>. Note
|
||||||
values are not necessarily continuous.
|
that the CPU numbers are not necessarily continuous. You return
|
||||||
|
it again with <function>put_cpu()</function> when you are done.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
If you know you cannot be preempted by another task (ie. you are
|
||||||
|
in interrupt context, or have preemption disabled) you can use
|
||||||
|
smp_processor_id().
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -722,19 +722,14 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
<para>
|
<para>
|
||||||
After boot, the kernel frees up a special section; functions
|
After boot, the kernel frees up a special section; functions
|
||||||
marked with <type>__init</type> and data structures marked with
|
marked with <type>__init</type> and data structures marked with
|
||||||
<type>__initdata</type> are dropped after boot is complete (within
|
<type>__initdata</type> are dropped after boot is complete: similarly
|
||||||
modules this directive is currently ignored). <type>__exit</type>
|
modules discard this memory after initialization. <type>__exit</type>
|
||||||
is used to declare a function which is only required on exit: the
|
is used to declare a function which is only required on exit: the
|
||||||
function will be dropped if this file is not compiled as a module.
|
function will be dropped if this file is not compiled as a module.
|
||||||
See the header file for use. Note that it makes no sense for a function
|
See the header file for use. Note that it makes no sense for a function
|
||||||
marked with <type>__init</type> to be exported to modules with
|
marked with <type>__init</type> to be exported to modules with
|
||||||
<function>EXPORT_SYMBOL()</function> - this will break.
|
<function>EXPORT_SYMBOL()</function> - this will break.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
Static data structures marked as <type>__initdata</type> must be initialised
|
|
||||||
(as opposed to ordinary static data which is zeroed BSS) and cannot be
|
|
||||||
<type>const</type>.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -762,9 +757,8 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
<para>
|
<para>
|
||||||
The function can return a negative error number to cause
|
The function can return a negative error number to cause
|
||||||
module loading to fail (unfortunately, this has no effect if
|
module loading to fail (unfortunately, this has no effect if
|
||||||
the module is compiled into the kernel). For modules, this is
|
the module is compiled into the kernel). This function is
|
||||||
called in user context, with interrupts enabled, and the
|
called in user context with interrupts enabled, so it can sleep.
|
||||||
kernel lock held, so it can sleep.
|
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -779,6 +773,34 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
reached zero. This function can also sleep, but cannot fail:
|
reached zero. This function can also sleep, but cannot fail:
|
||||||
everything must be cleaned up by the time it returns.
|
everything must be cleaned up by the time it returns.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Note that this macro is optional: if it is not present, your
|
||||||
|
module will not be removable (except for 'rmmod -f').
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="routines-module-use-counters">
|
||||||
|
<title> <function>try_module_get()</function>/<function>module_put()</function>
|
||||||
|
<filename class="headerfile">include/linux/module.h</filename></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
These manipulate the module usage count, to protect against
|
||||||
|
removal (a module also can't be removed if another module uses one
|
||||||
|
of its exported symbols: see below). Before calling into module
|
||||||
|
code, you should call <function>try_module_get()</function> on
|
||||||
|
that module: if it fails, then the module is being removed and you
|
||||||
|
should act as if it wasn't there. Otherwise, you can safely enter
|
||||||
|
the module, and call <function>module_put()</function> when you're
|
||||||
|
finished.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Most registerable structures have an
|
||||||
|
<structfield>owner</structfield> field, such as in the
|
||||||
|
<structname>file_operations</structname> structure. Set this field
|
||||||
|
to the macro <symbol>THIS_MODULE</symbol>.
|
||||||
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<!-- add info on new-style module refcounting here -->
|
<!-- add info on new-style module refcounting here -->
|
||||||
@ -821,7 +843,7 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
There is a macro to do this:
|
There is a macro to do this:
|
||||||
<function>wait_event_interruptible()</function>
|
<function>wait_event_interruptible()</function>
|
||||||
|
|
||||||
<filename class="headerfile">include/linux/sched.h</filename> The
|
<filename class="headerfile">include/linux/wait.h</filename> The
|
||||||
first argument is the wait queue head, and the second is an
|
first argument is the wait queue head, and the second is an
|
||||||
expression which is evaluated; the macro returns
|
expression which is evaluated; the macro returns
|
||||||
<returnvalue>0</returnvalue> when this expression is true, or
|
<returnvalue>0</returnvalue> when this expression is true, or
|
||||||
@ -847,10 +869,11 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
<para>
|
<para>
|
||||||
Call <function>wake_up()</function>
|
Call <function>wake_up()</function>
|
||||||
|
|
||||||
<filename class="headerfile">include/linux/sched.h</filename>;,
|
<filename class="headerfile">include/linux/wait.h</filename>;,
|
||||||
which will wake up every process in the queue. The exception is
|
which will wake up every process in the queue. The exception is
|
||||||
if one has <constant>TASK_EXCLUSIVE</constant> set, in which case
|
if one has <constant>TASK_EXCLUSIVE</constant> set, in which case
|
||||||
the remainder of the queue will not be woken.
|
the remainder of the queue will not be woken. There are other variants
|
||||||
|
of this basic function available in the same header.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
</chapter>
|
</chapter>
|
||||||
@ -863,7 +886,7 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
first class of operations work on <type>atomic_t</type>
|
first class of operations work on <type>atomic_t</type>
|
||||||
|
|
||||||
<filename class="headerfile">include/asm/atomic.h</filename>; this
|
<filename class="headerfile">include/asm/atomic.h</filename>; this
|
||||||
contains a signed integer (at least 24 bits long), and you must use
|
contains a signed integer (at least 32 bits long), and you must use
|
||||||
these functions to manipulate or read atomic_t variables.
|
these functions to manipulate or read atomic_t variables.
|
||||||
<function>atomic_read()</function> and
|
<function>atomic_read()</function> and
|
||||||
<function>atomic_set()</function> get and set the counter,
|
<function>atomic_set()</function> get and set the counter,
|
||||||
@ -882,13 +905,12 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
Note that these functions are slower than normal arithmetic, and
|
Note that these functions are slower than normal arithmetic, and
|
||||||
so should not be used unnecessarily. On some platforms they
|
so should not be used unnecessarily.
|
||||||
are much slower, like 32-bit Sparc where they use a spinlock.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The second class of atomic operations is atomic bit operations on a
|
The second class of atomic operations is atomic bit operations on an
|
||||||
<type>long</type>, defined in
|
<type>unsigned long</type>, defined in
|
||||||
|
|
||||||
<filename class="headerfile">include/linux/bitops.h</filename>. These
|
<filename class="headerfile">include/linux/bitops.h</filename>. These
|
||||||
operations generally take a pointer to the bit pattern, and a bit
|
operations generally take a pointer to the bit pattern, and a bit
|
||||||
@ -899,7 +921,7 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
<function>test_and_clear_bit()</function> and
|
<function>test_and_clear_bit()</function> and
|
||||||
<function>test_and_change_bit()</function> do the same thing,
|
<function>test_and_change_bit()</function> do the same thing,
|
||||||
except return true if the bit was previously set; these are
|
except return true if the bit was previously set; these are
|
||||||
particularly useful for very simple locking.
|
particularly useful for atomically setting flags.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -907,12 +929,6 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
than BITS_PER_LONG. The resulting behavior is strange on big-endian
|
than BITS_PER_LONG. The resulting behavior is strange on big-endian
|
||||||
platforms though so it is a good idea not to do this.
|
platforms though so it is a good idea not to do this.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
|
||||||
Note that the order of bits depends on the architecture, and in
|
|
||||||
particular, the bitfield passed to these operations must be at
|
|
||||||
least as large as a <type>long</type>.
|
|
||||||
</para>
|
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
<chapter id="symbols">
|
<chapter id="symbols">
|
||||||
@ -932,11 +948,8 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
<filename class="headerfile">include/linux/module.h</filename></title>
|
<filename class="headerfile">include/linux/module.h</filename></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
This is the classic method of exporting a symbol, and it works
|
This is the classic method of exporting a symbol: dynamically
|
||||||
for both modules and non-modules. In the kernel all these
|
loaded modules will be able to use the symbol as normal.
|
||||||
declarations are often bundled into a single file to help
|
|
||||||
genksyms (which searches source files for these declarations).
|
|
||||||
See the comment on genksyms and Makefiles below.
|
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -949,7 +962,8 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
symbols exported by <function>EXPORT_SYMBOL_GPL()</function> can
|
symbols exported by <function>EXPORT_SYMBOL_GPL()</function> can
|
||||||
only be seen by modules with a
|
only be seen by modules with a
|
||||||
<function>MODULE_LICENSE()</function> that specifies a GPL
|
<function>MODULE_LICENSE()</function> that specifies a GPL
|
||||||
compatible license.
|
compatible license. It implies that the function is considered
|
||||||
|
an internal implementation issue, and not really an interface.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
</chapter>
|
</chapter>
|
||||||
@ -962,12 +976,13 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
<filename class="headerfile">include/linux/list.h</filename></title>
|
<filename class="headerfile">include/linux/list.h</filename></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
There are three sets of linked-list routines in the kernel
|
There used to be three sets of linked-list routines in the kernel
|
||||||
headers, but this one seems to be winning out (and Linus has
|
headers, but this one is the winner. If you don't have some
|
||||||
used it). If you don't have some particular pressing need for
|
particular pressing need for a single list, it's a good choice.
|
||||||
a single list, it's a good choice. In fact, I don't care
|
</para>
|
||||||
whether it's a good choice or not, just use it so we can get
|
|
||||||
rid of the others.
|
<para>
|
||||||
|
In particular, <function>list_for_each_entry</function> is useful.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -979,14 +994,13 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress));
|
|||||||
convention, and return <returnvalue>0</returnvalue> for success,
|
convention, and return <returnvalue>0</returnvalue> for success,
|
||||||
and a negative error number
|
and a negative error number
|
||||||
(eg. <returnvalue>-EFAULT</returnvalue>) for failure. This can be
|
(eg. <returnvalue>-EFAULT</returnvalue>) for failure. This can be
|
||||||
unintuitive at first, but it's fairly widespread in the networking
|
unintuitive at first, but it's fairly widespread in the kernel.
|
||||||
code, for example.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The filesystem code uses <function>ERR_PTR()</function>
|
Using <function>ERR_PTR()</function>
|
||||||
|
|
||||||
<filename class="headerfile">include/linux/fs.h</filename>; to
|
<filename class="headerfile">include/linux/err.h</filename>; to
|
||||||
encode a negative error number into a pointer, and
|
encode a negative error number into a pointer, and
|
||||||
<function>IS_ERR()</function> and <function>PTR_ERR()</function>
|
<function>IS_ERR()</function> and <function>PTR_ERR()</function>
|
||||||
to get it back out again: avoids a separate pointer parameter for
|
to get it back out again: avoids a separate pointer parameter for
|
||||||
@ -1040,7 +1054,7 @@ static struct block_device_operations opt_fops = {
|
|||||||
supported, due to lack of general use, but the following are
|
supported, due to lack of general use, but the following are
|
||||||
considered standard (see the GCC info page section "C
|
considered standard (see the GCC info page section "C
|
||||||
Extensions" for more details - Yes, really the info page, the
|
Extensions" for more details - Yes, really the info page, the
|
||||||
man page is only a short summary of the stuff in info):
|
man page is only a short summary of the stuff in info).
|
||||||
</para>
|
</para>
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem>
|
<listitem>
|
||||||
@ -1091,7 +1105,7 @@ static struct block_device_operations opt_fops = {
|
|||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Function names as strings (__FUNCTION__)
|
Function names as strings (__func__).
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
@ -1164,63 +1178,35 @@ static struct block_device_operations opt_fops = {
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Usually you want a configuration option for your kernel hack.
|
Usually you want a configuration option for your kernel hack.
|
||||||
Edit <filename>Config.in</filename> in the appropriate directory
|
Edit <filename>Kconfig</filename> in the appropriate directory.
|
||||||
(but under <filename>arch/</filename> it's called
|
The Config language is simple to use by cut and paste, and there's
|
||||||
<filename>config.in</filename>). The Config Language used is not
|
complete documentation in
|
||||||
bash, even though it looks like bash; the safe way is to use only
|
<filename>Documentation/kbuild/kconfig-language.txt</filename>.
|
||||||
the constructs that you already see in
|
|
||||||
<filename>Config.in</filename> files (see
|
|
||||||
<filename>Documentation/kbuild/kconfig-language.txt</filename>).
|
|
||||||
It's good to run "make xconfig" at least once to test (because
|
|
||||||
it's the only one with a static parser).
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Variables which can be Y or N use <type>bool</type> followed by a
|
|
||||||
tagline and the config define name (which must start with
|
|
||||||
CONFIG_). The <type>tristate</type> function is the same, but
|
|
||||||
allows the answer M (which defines
|
|
||||||
<symbol>CONFIG_foo_MODULE</symbol> in your source, instead of
|
|
||||||
<symbol>CONFIG_FOO</symbol>) if <symbol>CONFIG_MODULES</symbol>
|
|
||||||
is enabled.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
You may well want to make your CONFIG option only visible if
|
You may well want to make your CONFIG option only visible if
|
||||||
<symbol>CONFIG_EXPERIMENTAL</symbol> is enabled: this serves as a
|
<symbol>CONFIG_EXPERIMENTAL</symbol> is enabled: this serves as a
|
||||||
warning to users. There many other fancy things you can do: see
|
warning to users. There many other fancy things you can do: see
|
||||||
the various <filename>Config.in</filename> files for ideas.
|
the various <filename>Kconfig</filename> files for ideas.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
In your description of the option, make sure you address both the
|
||||||
|
expert user and the user who knows nothing about your feature. Mention
|
||||||
|
incompatibilities and issues here. <emphasis> Definitely
|
||||||
|
</emphasis> end your description with <quote> if in doubt, say N
|
||||||
|
</quote> (or, occasionally, `Y'); this is for people who have no
|
||||||
|
idea what you are talking about.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Edit the <filename>Makefile</filename>: the CONFIG variables are
|
Edit the <filename>Makefile</filename>: the CONFIG variables are
|
||||||
exported here so you can conditionalize compilation with `ifeq'.
|
exported here so you can usually just add a "obj-$(CONFIG_xxx) +=
|
||||||
If your file exports symbols then add the names to
|
xxx.o" line. The syntax is documented in
|
||||||
<varname>export-objs</varname> so that genksyms will find them.
|
<filename>Documentation/kbuild/makefiles.txt</filename>.
|
||||||
<caution>
|
|
||||||
<para>
|
|
||||||
There is a restriction on the kernel build system that objects
|
|
||||||
which export symbols must have globally unique names.
|
|
||||||
If your object does not have a globally unique name then the
|
|
||||||
standard fix is to move the
|
|
||||||
<function>EXPORT_SYMBOL()</function> statements to their own
|
|
||||||
object with a unique name.
|
|
||||||
This is why several systems have separate exporting objects,
|
|
||||||
usually suffixed with ksyms.
|
|
||||||
</para>
|
|
||||||
</caution>
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Document your option in Documentation/Configure.help. Mention
|
|
||||||
incompatibilities and issues here. <emphasis> Definitely
|
|
||||||
</emphasis> end your description with <quote> if in doubt, say N
|
|
||||||
</quote> (or, occasionally, `Y'); this is for people who have no
|
|
||||||
idea what you are talking about.
|
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
@ -1253,20 +1239,12 @@ static struct block_device_operations opt_fops = {
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<filename>include/linux/brlock.h:</filename>
|
<filename>include/asm-i386/delay.h:</filename>
|
||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
extern inline void br_read_lock (enum brlock_indices idx)
|
#define ndelay(n) (__builtin_constant_p(n) ? \
|
||||||
{
|
((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \
|
||||||
/*
|
__ndelay(n))
|
||||||
* This causes a link-time bug message if an
|
|
||||||
* invalid index is used:
|
|
||||||
*/
|
|
||||||
if (idx >= __BR_END)
|
|
||||||
__br_lock_usage_bug();
|
|
||||||
|
|
||||||
read_lock(&__brlock_array[smp_processor_id()][idx]);
|
|
||||||
}
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -841,7 +841,7 @@ usbdev_ioctl (int fd, int ifno, unsigned request, void *param)
|
|||||||
File modification time is not updated by this request.
|
File modification time is not updated by this request.
|
||||||
</para><para>
|
</para><para>
|
||||||
Those struct members are from some interface descriptor
|
Those struct members are from some interface descriptor
|
||||||
applying to the the current configuration.
|
applying to the current configuration.
|
||||||
The interface number is the bInterfaceNumber value, and
|
The interface number is the bInterfaceNumber value, and
|
||||||
the altsetting number is the bAlternateSetting value.
|
the altsetting number is the bAlternateSetting value.
|
||||||
(This resets each endpoint in the interface.)
|
(This resets each endpoint in the interface.)
|
||||||
|
@ -430,7 +430,7 @@ which may result in system hang. The software driver of specific
|
|||||||
MSI-capable hardware is responsible for whether calling
|
MSI-capable hardware is responsible for whether calling
|
||||||
pci_enable_msi or not. A return of zero indicates the kernel
|
pci_enable_msi or not. A return of zero indicates the kernel
|
||||||
successfully initializes the MSI/MSI-X capability structure of the
|
successfully initializes the MSI/MSI-X capability structure of the
|
||||||
device funtion. The device function is now running on MSI/MSI-X mode.
|
device function. The device function is now running on MSI/MSI-X mode.
|
||||||
|
|
||||||
5.6 How to tell whether MSI/MSI-X is enabled on device function
|
5.6 How to tell whether MSI/MSI-X is enabled on device function
|
||||||
|
|
||||||
|
@ -2,7 +2,8 @@ Read the F-ing Papers!
|
|||||||
|
|
||||||
|
|
||||||
This document describes RCU-related publications, and is followed by
|
This document describes RCU-related publications, and is followed by
|
||||||
the corresponding bibtex entries.
|
the corresponding bibtex entries. A number of the publications may
|
||||||
|
be found at http://www.rdrop.com/users/paulmck/RCU/.
|
||||||
|
|
||||||
The first thing resembling RCU was published in 1980, when Kung and Lehman
|
The first thing resembling RCU was published in 1980, when Kung and Lehman
|
||||||
[Kung80] recommended use of a garbage collector to defer destruction
|
[Kung80] recommended use of a garbage collector to defer destruction
|
||||||
@ -113,6 +114,10 @@ describing how to make RCU safe for soft-realtime applications [Sarma04c],
|
|||||||
and a paper describing SELinux performance with RCU [JamesMorris04b].
|
and a paper describing SELinux performance with RCU [JamesMorris04b].
|
||||||
|
|
||||||
|
|
||||||
|
2005 has seen further adaptation of RCU to realtime use, permitting
|
||||||
|
preemption of RCU realtime critical sections [PaulMcKenney05a,
|
||||||
|
PaulMcKenney05b].
|
||||||
|
|
||||||
Bibtex Entries
|
Bibtex Entries
|
||||||
|
|
||||||
@article{Kung80
|
@article{Kung80
|
||||||
@ -410,3 +415,32 @@ Oregon Health and Sciences University"
|
|||||||
\url{http://www.livejournal.com/users/james_morris/2153.html}
|
\url{http://www.livejournal.com/users/james_morris/2153.html}
|
||||||
[Viewed December 10, 2004]"
|
[Viewed December 10, 2004]"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@unpublished{PaulMcKenney05a
|
||||||
|
,Author="Paul E. McKenney"
|
||||||
|
,Title="{[RFC]} {RCU} and {CONFIG\_PREEMPT\_RT} progress"
|
||||||
|
,month="May"
|
||||||
|
,year="2005"
|
||||||
|
,note="Available:
|
||||||
|
\url{http://lkml.org/lkml/2005/5/9/185}
|
||||||
|
[Viewed May 13, 2005]"
|
||||||
|
,annotation="
|
||||||
|
First publication of working lock-based deferred free patches
|
||||||
|
for the CONFIG_PREEMPT_RT environment.
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
@conference{PaulMcKenney05b
|
||||||
|
,Author="Paul E. McKenney and Dipankar Sarma"
|
||||||
|
,Title="Towards Hard Realtime Response from the Linux Kernel on SMP Hardware"
|
||||||
|
,Booktitle="linux.conf.au 2005"
|
||||||
|
,month="April"
|
||||||
|
,year="2005"
|
||||||
|
,address="Canberra, Australia"
|
||||||
|
,note="Available:
|
||||||
|
\url{http://www.rdrop.com/users/paulmck/RCU/realtimeRCU.2005.04.23a.pdf}
|
||||||
|
[Viewed May 13, 2005]"
|
||||||
|
,annotation="
|
||||||
|
Realtime turns into making RCU yet more realtime friendly.
|
||||||
|
"
|
||||||
|
}
|
||||||
|
@ -8,7 +8,7 @@ is that since there is only one CPU, it should not be necessary to
|
|||||||
wait for anything else to get done, since there are no other CPUs for
|
wait for anything else to get done, since there are no other CPUs for
|
||||||
anything else to be happening on. Although this approach will -sort- -of-
|
anything else to be happening on. Although this approach will -sort- -of-
|
||||||
work a surprising amount of the time, it is a very bad idea in general.
|
work a surprising amount of the time, it is a very bad idea in general.
|
||||||
This document presents two examples that demonstrate exactly how bad an
|
This document presents three examples that demonstrate exactly how bad an
|
||||||
idea this is.
|
idea this is.
|
||||||
|
|
||||||
|
|
||||||
@ -26,6 +26,9 @@ from softirq, the list scan would find itself referencing a newly freed
|
|||||||
element B. This situation can greatly decrease the life expectancy of
|
element B. This situation can greatly decrease the life expectancy of
|
||||||
your kernel.
|
your kernel.
|
||||||
|
|
||||||
|
This same problem can occur if call_rcu() is invoked from a hardware
|
||||||
|
interrupt handler.
|
||||||
|
|
||||||
|
|
||||||
Example 2: Function-Call Fatality
|
Example 2: Function-Call Fatality
|
||||||
|
|
||||||
@ -44,8 +47,37 @@ its arguments would cause it to fail to make the fundamental guarantee
|
|||||||
underlying RCU, namely that call_rcu() defers invoking its arguments until
|
underlying RCU, namely that call_rcu() defers invoking its arguments until
|
||||||
all RCU read-side critical sections currently executing have completed.
|
all RCU read-side critical sections currently executing have completed.
|
||||||
|
|
||||||
Quick Quiz: why is it -not- legal to invoke synchronize_rcu() in
|
Quick Quiz #1: why is it -not- legal to invoke synchronize_rcu() in
|
||||||
this case?
|
this case?
|
||||||
|
|
||||||
|
|
||||||
|
Example 3: Death by Deadlock
|
||||||
|
|
||||||
|
Suppose that call_rcu() is invoked while holding a lock, and that the
|
||||||
|
callback function must acquire this same lock. In this case, if
|
||||||
|
call_rcu() were to directly invoke the callback, the result would
|
||||||
|
be self-deadlock.
|
||||||
|
|
||||||
|
In some cases, it would possible to restructure to code so that
|
||||||
|
the call_rcu() is delayed until after the lock is released. However,
|
||||||
|
there are cases where this can be quite ugly:
|
||||||
|
|
||||||
|
1. If a number of items need to be passed to call_rcu() within
|
||||||
|
the same critical section, then the code would need to create
|
||||||
|
a list of them, then traverse the list once the lock was
|
||||||
|
released.
|
||||||
|
|
||||||
|
2. In some cases, the lock will be held across some kernel API,
|
||||||
|
so that delaying the call_rcu() until the lock is released
|
||||||
|
requires that the data item be passed up via a common API.
|
||||||
|
It is far better to guarantee that callbacks are invoked
|
||||||
|
with no locks held than to have to modify such APIs to allow
|
||||||
|
arbitrary data items to be passed back up through them.
|
||||||
|
|
||||||
|
If call_rcu() directly invokes the callback, painful locking restrictions
|
||||||
|
or API changes would be required.
|
||||||
|
|
||||||
|
Quick Quiz #2: What locking restriction must RCU callbacks respect?
|
||||||
|
|
||||||
|
|
||||||
Summary
|
Summary
|
||||||
@ -53,12 +85,35 @@ Summary
|
|||||||
Permitting call_rcu() to immediately invoke its arguments or permitting
|
Permitting call_rcu() to immediately invoke its arguments or permitting
|
||||||
synchronize_rcu() to immediately return breaks RCU, even on a UP system.
|
synchronize_rcu() to immediately return breaks RCU, even on a UP system.
|
||||||
So do not do it! Even on a UP system, the RCU infrastructure -must-
|
So do not do it! Even on a UP system, the RCU infrastructure -must-
|
||||||
respect grace periods.
|
respect grace periods, and -must- invoke callbacks from a known environment
|
||||||
|
in which no locks are held.
|
||||||
|
|
||||||
|
|
||||||
Answer to Quick Quiz
|
Answer to Quick Quiz #1:
|
||||||
|
Why is it -not- legal to invoke synchronize_rcu() in this case?
|
||||||
|
|
||||||
The calling function is scanning an RCU-protected linked list, and
|
Because the calling function is scanning an RCU-protected linked
|
||||||
is therefore within an RCU read-side critical section. Therefore,
|
list, and is therefore within an RCU read-side critical section.
|
||||||
the called function has been invoked within an RCU read-side critical
|
Therefore, the called function has been invoked within an RCU
|
||||||
section, and is not permitted to block.
|
read-side critical section, and is not permitted to block.
|
||||||
|
|
||||||
|
Answer to Quick Quiz #2:
|
||||||
|
What locking restriction must RCU callbacks respect?
|
||||||
|
|
||||||
|
Any lock that is acquired within an RCU callback must be
|
||||||
|
acquired elsewhere using an _irq variant of the spinlock
|
||||||
|
primitive. For example, if "mylock" is acquired by an
|
||||||
|
RCU callback, then a process-context acquisition of this
|
||||||
|
lock must use something like spin_lock_irqsave() to
|
||||||
|
acquire the lock.
|
||||||
|
|
||||||
|
If the process-context code were to simply use spin_lock(),
|
||||||
|
then, since RCU callbacks can be invoked from softirq context,
|
||||||
|
the callback might be called from a softirq that interrupted
|
||||||
|
the process-context critical section. This would result in
|
||||||
|
self-deadlock.
|
||||||
|
|
||||||
|
This restriction might seem gratuitous, since very few RCU
|
||||||
|
callbacks acquire locks directly. However, a great many RCU
|
||||||
|
callbacks do acquire locks -indirectly-, for example, via
|
||||||
|
the kfree() primitive.
|
||||||
|
@ -43,6 +43,10 @@ over a rather long period of time, but improvements are always welcome!
|
|||||||
rcu_read_lock_bh()) in the read-side critical sections,
|
rcu_read_lock_bh()) in the read-side critical sections,
|
||||||
and are also an excellent aid to readability.
|
and are also an excellent aid to readability.
|
||||||
|
|
||||||
|
As a rough rule of thumb, any dereference of an RCU-protected
|
||||||
|
pointer must be covered by rcu_read_lock() or rcu_read_lock_bh()
|
||||||
|
or by the appropriate update-side lock.
|
||||||
|
|
||||||
3. Does the update code tolerate concurrent accesses?
|
3. Does the update code tolerate concurrent accesses?
|
||||||
|
|
||||||
The whole point of RCU is to permit readers to run without
|
The whole point of RCU is to permit readers to run without
|
||||||
@ -90,7 +94,11 @@ over a rather long period of time, but improvements are always welcome!
|
|||||||
|
|
||||||
The rcu_dereference() primitive is used by the various
|
The rcu_dereference() primitive is used by the various
|
||||||
"_rcu()" list-traversal primitives, such as the
|
"_rcu()" list-traversal primitives, such as the
|
||||||
list_for_each_entry_rcu().
|
list_for_each_entry_rcu(). Note that it is perfectly
|
||||||
|
legal (if redundant) for update-side code to use
|
||||||
|
rcu_dereference() and the "_rcu()" list-traversal
|
||||||
|
primitives. This is particularly useful in code
|
||||||
|
that is common to readers and updaters.
|
||||||
|
|
||||||
b. If the list macros are being used, the list_add_tail_rcu()
|
b. If the list macros are being used, the list_add_tail_rcu()
|
||||||
and list_add_rcu() primitives must be used in order
|
and list_add_rcu() primitives must be used in order
|
||||||
@ -150,16 +158,9 @@ over a rather long period of time, but improvements are always welcome!
|
|||||||
|
|
||||||
Use of the _rcu() list-traversal primitives outside of an
|
Use of the _rcu() list-traversal primitives outside of an
|
||||||
RCU read-side critical section causes no harm other than
|
RCU read-side critical section causes no harm other than
|
||||||
a slight performance degradation on Alpha CPUs and some
|
a slight performance degradation on Alpha CPUs. It can
|
||||||
confusion on the part of people trying to read the code.
|
also be quite helpful in reducing code bloat when common
|
||||||
|
code is shared between readers and updaters.
|
||||||
Another way of thinking of this is "If you are holding the
|
|
||||||
lock that prevents the data structure from changing, why do
|
|
||||||
you also need RCU-based protection?" That said, there may
|
|
||||||
well be situations where use of the _rcu() list-traversal
|
|
||||||
primitives while the update-side lock is held results in
|
|
||||||
simpler and more maintainable code. The jury is still out
|
|
||||||
on this question.
|
|
||||||
|
|
||||||
10. Conversely, if you are in an RCU read-side critical section,
|
10. Conversely, if you are in an RCU read-side critical section,
|
||||||
you -must- use the "_rcu()" variants of the list macros.
|
you -must- use the "_rcu()" variants of the list macros.
|
||||||
|
@ -64,6 +64,54 @@ o I hear that RCU is patented? What is with that?
|
|||||||
Of these, one was allowed to lapse by the assignee, and the
|
Of these, one was allowed to lapse by the assignee, and the
|
||||||
others have been contributed to the Linux kernel under GPL.
|
others have been contributed to the Linux kernel under GPL.
|
||||||
|
|
||||||
|
o I hear that RCU needs work in order to support realtime kernels?
|
||||||
|
|
||||||
|
Yes, work in progress.
|
||||||
|
|
||||||
o Where can I find more information on RCU?
|
o Where can I find more information on RCU?
|
||||||
|
|
||||||
See the RTFP.txt file in this directory.
|
See the RTFP.txt file in this directory.
|
||||||
|
Or point your browser at http://www.rdrop.com/users/paulmck/RCU/.
|
||||||
|
|
||||||
|
o What are all these files in this directory?
|
||||||
|
|
||||||
|
|
||||||
|
NMI-RCU.txt
|
||||||
|
|
||||||
|
Describes how to use RCU to implement dynamic
|
||||||
|
NMI handlers, which can be revectored on the fly,
|
||||||
|
without rebooting.
|
||||||
|
|
||||||
|
RTFP.txt
|
||||||
|
|
||||||
|
List of RCU-related publications and web sites.
|
||||||
|
|
||||||
|
UP.txt
|
||||||
|
|
||||||
|
Discussion of RCU usage in UP kernels.
|
||||||
|
|
||||||
|
arrayRCU.txt
|
||||||
|
|
||||||
|
Describes how to use RCU to protect arrays, with
|
||||||
|
resizeable arrays whose elements reference other
|
||||||
|
data structures being of the most interest.
|
||||||
|
|
||||||
|
checklist.txt
|
||||||
|
|
||||||
|
Lists things to check for when inspecting code that
|
||||||
|
uses RCU.
|
||||||
|
|
||||||
|
listRCU.txt
|
||||||
|
|
||||||
|
Describes how to use RCU to protect linked lists.
|
||||||
|
This is the simplest and most common use of RCU
|
||||||
|
in the Linux kernel.
|
||||||
|
|
||||||
|
rcu.txt
|
||||||
|
|
||||||
|
You are reading it!
|
||||||
|
|
||||||
|
whatisRCU.txt
|
||||||
|
|
||||||
|
Overview of how the RCU implementation works. Along
|
||||||
|
the way, presents a conceptual view of RCU.
|
||||||
|
74
Documentation/RCU/rcuref.txt
Normal file
74
Documentation/RCU/rcuref.txt
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
Refcounter framework for elements of lists/arrays protected by
|
||||||
|
RCU.
|
||||||
|
|
||||||
|
Refcounting on elements of lists which are protected by traditional
|
||||||
|
reader/writer spinlocks or semaphores are straight forward as in:
|
||||||
|
|
||||||
|
1. 2.
|
||||||
|
add() search_and_reference()
|
||||||
|
{ {
|
||||||
|
alloc_object read_lock(&list_lock);
|
||||||
|
... search_for_element
|
||||||
|
atomic_set(&el->rc, 1); atomic_inc(&el->rc);
|
||||||
|
write_lock(&list_lock); ...
|
||||||
|
add_element read_unlock(&list_lock);
|
||||||
|
... ...
|
||||||
|
write_unlock(&list_lock); }
|
||||||
|
}
|
||||||
|
|
||||||
|
3. 4.
|
||||||
|
release_referenced() delete()
|
||||||
|
{ {
|
||||||
|
... write_lock(&list_lock);
|
||||||
|
atomic_dec(&el->rc, relfunc) ...
|
||||||
|
... delete_element
|
||||||
|
} write_unlock(&list_lock);
|
||||||
|
...
|
||||||
|
if (atomic_dec_and_test(&el->rc))
|
||||||
|
kfree(el);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
If this list/array is made lock free using rcu as in changing the
|
||||||
|
write_lock in add() and delete() to spin_lock and changing read_lock
|
||||||
|
in search_and_reference to rcu_read_lock(), the rcuref_get in
|
||||||
|
search_and_reference could potentially hold reference to an element which
|
||||||
|
has already been deleted from the list/array. rcuref_lf_get_rcu takes
|
||||||
|
care of this scenario. search_and_reference should look as;
|
||||||
|
|
||||||
|
1. 2.
|
||||||
|
add() search_and_reference()
|
||||||
|
{ {
|
||||||
|
alloc_object rcu_read_lock();
|
||||||
|
... search_for_element
|
||||||
|
atomic_set(&el->rc, 1); if (rcuref_inc_lf(&el->rc)) {
|
||||||
|
write_lock(&list_lock); rcu_read_unlock();
|
||||||
|
return FAIL;
|
||||||
|
add_element }
|
||||||
|
... ...
|
||||||
|
write_unlock(&list_lock); rcu_read_unlock();
|
||||||
|
} }
|
||||||
|
3. 4.
|
||||||
|
release_referenced() delete()
|
||||||
|
{ {
|
||||||
|
... write_lock(&list_lock);
|
||||||
|
rcuref_dec(&el->rc, relfunc) ...
|
||||||
|
... delete_element
|
||||||
|
} write_unlock(&list_lock);
|
||||||
|
...
|
||||||
|
if (rcuref_dec_and_test(&el->rc))
|
||||||
|
call_rcu(&el->head, el_free);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
Sometimes, reference to the element need to be obtained in the
|
||||||
|
update (write) stream. In such cases, rcuref_inc_lf might be an overkill
|
||||||
|
since the spinlock serialising list updates are held. rcuref_inc
|
||||||
|
is to be used in such cases.
|
||||||
|
For arches which do not have cmpxchg rcuref_inc_lf
|
||||||
|
api uses a hashed spinlock implementation and the same hashed spinlock
|
||||||
|
is acquired in all rcuref_xxx primitives to preserve atomicity.
|
||||||
|
Note: Use rcuref_inc api only if you need to use rcuref_inc_lf on the
|
||||||
|
refcounter atleast at one place. Mixing rcuref_inc and atomic_xxx api
|
||||||
|
might lead to races. rcuref_inc_lf() must be used in lockfree
|
||||||
|
RCU critical sections only.
|
902
Documentation/RCU/whatisRCU.txt
Normal file
902
Documentation/RCU/whatisRCU.txt
Normal file
@ -0,0 +1,902 @@
|
|||||||
|
What is RCU?
|
||||||
|
|
||||||
|
RCU is a synchronization mechanism that was added to the Linux kernel
|
||||||
|
during the 2.5 development effort that is optimized for read-mostly
|
||||||
|
situations. Although RCU is actually quite simple once you understand it,
|
||||||
|
getting there can sometimes be a challenge. Part of the problem is that
|
||||||
|
most of the past descriptions of RCU have been written with the mistaken
|
||||||
|
assumption that there is "one true way" to describe RCU. Instead,
|
||||||
|
the experience has been that different people must take different paths
|
||||||
|
to arrive at an understanding of RCU. This document provides several
|
||||||
|
different paths, as follows:
|
||||||
|
|
||||||
|
1. RCU OVERVIEW
|
||||||
|
2. WHAT IS RCU'S CORE API?
|
||||||
|
3. WHAT ARE SOME EXAMPLE USES OF CORE RCU API?
|
||||||
|
4. WHAT IF MY UPDATING THREAD CANNOT BLOCK?
|
||||||
|
5. WHAT ARE SOME SIMPLE IMPLEMENTATIONS OF RCU?
|
||||||
|
6. ANALOGY WITH READER-WRITER LOCKING
|
||||||
|
7. FULL LIST OF RCU APIs
|
||||||
|
8. ANSWERS TO QUICK QUIZZES
|
||||||
|
|
||||||
|
People who prefer starting with a conceptual overview should focus on
|
||||||
|
Section 1, though most readers will profit by reading this section at
|
||||||
|
some point. People who prefer to start with an API that they can then
|
||||||
|
experiment with should focus on Section 2. People who prefer to start
|
||||||
|
with example uses should focus on Sections 3 and 4. People who need to
|
||||||
|
understand the RCU implementation should focus on Section 5, then dive
|
||||||
|
into the kernel source code. People who reason best by analogy should
|
||||||
|
focus on Section 6. Section 7 serves as an index to the docbook API
|
||||||
|
documentation, and Section 8 is the traditional answer key.
|
||||||
|
|
||||||
|
So, start with the section that makes the most sense to you and your
|
||||||
|
preferred method of learning. If you need to know everything about
|
||||||
|
everything, feel free to read the whole thing -- but if you are really
|
||||||
|
that type of person, you have perused the source code and will therefore
|
||||||
|
never need this document anyway. ;-)
|
||||||
|
|
||||||
|
|
||||||
|
1. RCU OVERVIEW
|
||||||
|
|
||||||
|
The basic idea behind RCU is to split updates into "removal" and
|
||||||
|
"reclamation" phases. The removal phase removes references to data items
|
||||||
|
within a data structure (possibly by replacing them with references to
|
||||||
|
new versions of these data items), and can run concurrently with readers.
|
||||||
|
The reason that it is safe to run the removal phase concurrently with
|
||||||
|
readers is the semantics of modern CPUs guarantee that readers will see
|
||||||
|
either the old or the new version of the data structure rather than a
|
||||||
|
partially updated reference. The reclamation phase does the work of reclaiming
|
||||||
|
(e.g., freeing) the data items removed from the data structure during the
|
||||||
|
removal phase. Because reclaiming data items can disrupt any readers
|
||||||
|
concurrently referencing those data items, the reclamation phase must
|
||||||
|
not start until readers no longer hold references to those data items.
|
||||||
|
|
||||||
|
Splitting the update into removal and reclamation phases permits the
|
||||||
|
updater to perform the removal phase immediately, and to defer the
|
||||||
|
reclamation phase until all readers active during the removal phase have
|
||||||
|
completed, either by blocking until they finish or by registering a
|
||||||
|
callback that is invoked after they finish. Only readers that are active
|
||||||
|
during the removal phase need be considered, because any reader starting
|
||||||
|
after the removal phase will be unable to gain a reference to the removed
|
||||||
|
data items, and therefore cannot be disrupted by the reclamation phase.
|
||||||
|
|
||||||
|
So the typical RCU update sequence goes something like the following:
|
||||||
|
|
||||||
|
a. Remove pointers to a data structure, so that subsequent
|
||||||
|
readers cannot gain a reference to it.
|
||||||
|
|
||||||
|
b. Wait for all previous readers to complete their RCU read-side
|
||||||
|
critical sections.
|
||||||
|
|
||||||
|
c. At this point, there cannot be any readers who hold references
|
||||||
|
to the data structure, so it now may safely be reclaimed
|
||||||
|
(e.g., kfree()d).
|
||||||
|
|
||||||
|
Step (b) above is the key idea underlying RCU's deferred destruction.
|
||||||
|
The ability to wait until all readers are done allows RCU readers to
|
||||||
|
use much lighter-weight synchronization, in some cases, absolutely no
|
||||||
|
synchronization at all. In contrast, in more conventional lock-based
|
||||||
|
schemes, readers must use heavy-weight synchronization in order to
|
||||||
|
prevent an updater from deleting the data structure out from under them.
|
||||||
|
This is because lock-based updaters typically update data items in place,
|
||||||
|
and must therefore exclude readers. In contrast, RCU-based updaters
|
||||||
|
typically take advantage of the fact that writes to single aligned
|
||||||
|
pointers are atomic on modern CPUs, allowing atomic insertion, removal,
|
||||||
|
and replacement of data items in a linked structure without disrupting
|
||||||
|
readers. Concurrent RCU readers can then continue accessing the old
|
||||||
|
versions, and can dispense with the atomic operations, memory barriers,
|
||||||
|
and communications cache misses that are so expensive on present-day
|
||||||
|
SMP computer systems, even in absence of lock contention.
|
||||||
|
|
||||||
|
In the three-step procedure shown above, the updater is performing both
|
||||||
|
the removal and the reclamation step, but it is often helpful for an
|
||||||
|
entirely different thread to do the reclamation, as is in fact the case
|
||||||
|
in the Linux kernel's directory-entry cache (dcache). Even if the same
|
||||||
|
thread performs both the update step (step (a) above) and the reclamation
|
||||||
|
step (step (c) above), it is often helpful to think of them separately.
|
||||||
|
For example, RCU readers and updaters need not communicate at all,
|
||||||
|
but RCU provides implicit low-overhead communication between readers
|
||||||
|
and reclaimers, namely, in step (b) above.
|
||||||
|
|
||||||
|
So how the heck can a reclaimer tell when a reader is done, given
|
||||||
|
that readers are not doing any sort of synchronization operations???
|
||||||
|
Read on to learn about how RCU's API makes this easy.
|
||||||
|
|
||||||
|
|
||||||
|
2. WHAT IS RCU'S CORE API?
|
||||||
|
|
||||||
|
The core RCU API is quite small:
|
||||||
|
|
||||||
|
a. rcu_read_lock()
|
||||||
|
b. rcu_read_unlock()
|
||||||
|
c. synchronize_rcu() / call_rcu()
|
||||||
|
d. rcu_assign_pointer()
|
||||||
|
e. rcu_dereference()
|
||||||
|
|
||||||
|
There are many other members of the RCU API, but the rest can be
|
||||||
|
expressed in terms of these five, though most implementations instead
|
||||||
|
express synchronize_rcu() in terms of the call_rcu() callback API.
|
||||||
|
|
||||||
|
The five core RCU APIs are described below, the other 18 will be enumerated
|
||||||
|
later. See the kernel docbook documentation for more info, or look directly
|
||||||
|
at the function header comments.
|
||||||
|
|
||||||
|
rcu_read_lock()
|
||||||
|
|
||||||
|
void rcu_read_lock(void);
|
||||||
|
|
||||||
|
Used by a reader to inform the reclaimer that the reader is
|
||||||
|
entering an RCU read-side critical section. It is illegal
|
||||||
|
to block while in an RCU read-side critical section, though
|
||||||
|
kernels built with CONFIG_PREEMPT_RCU can preempt RCU read-side
|
||||||
|
critical sections. Any RCU-protected data structure accessed
|
||||||
|
during an RCU read-side critical section is guaranteed to remain
|
||||||
|
unreclaimed for the full duration of that critical section.
|
||||||
|
Reference counts may be used in conjunction with RCU to maintain
|
||||||
|
longer-term references to data structures.
|
||||||
|
|
||||||
|
rcu_read_unlock()
|
||||||
|
|
||||||
|
void rcu_read_unlock(void);
|
||||||
|
|
||||||
|
Used by a reader to inform the reclaimer that the reader is
|
||||||
|
exiting an RCU read-side critical section. Note that RCU
|
||||||
|
read-side critical sections may be nested and/or overlapping.
|
||||||
|
|
||||||
|
synchronize_rcu()
|
||||||
|
|
||||||
|
void synchronize_rcu(void);
|
||||||
|
|
||||||
|
Marks the end of updater code and the beginning of reclaimer
|
||||||
|
code. It does this by blocking until all pre-existing RCU
|
||||||
|
read-side critical sections on all CPUs have completed.
|
||||||
|
Note that synchronize_rcu() will -not- necessarily wait for
|
||||||
|
any subsequent RCU read-side critical sections to complete.
|
||||||
|
For example, consider the following sequence of events:
|
||||||
|
|
||||||
|
CPU 0 CPU 1 CPU 2
|
||||||
|
----------------- ------------------------- ---------------
|
||||||
|
1. rcu_read_lock()
|
||||||
|
2. enters synchronize_rcu()
|
||||||
|
3. rcu_read_lock()
|
||||||
|
4. rcu_read_unlock()
|
||||||
|
5. exits synchronize_rcu()
|
||||||
|
6. rcu_read_unlock()
|
||||||
|
|
||||||
|
To reiterate, synchronize_rcu() waits only for ongoing RCU
|
||||||
|
read-side critical sections to complete, not necessarily for
|
||||||
|
any that begin after synchronize_rcu() is invoked.
|
||||||
|
|
||||||
|
Of course, synchronize_rcu() does not necessarily return
|
||||||
|
-immediately- after the last pre-existing RCU read-side critical
|
||||||
|
section completes. For one thing, there might well be scheduling
|
||||||
|
delays. For another thing, many RCU implementations process
|
||||||
|
requests in batches in order to improve efficiencies, which can
|
||||||
|
further delay synchronize_rcu().
|
||||||
|
|
||||||
|
Since synchronize_rcu() is the API that must figure out when
|
||||||
|
readers are done, its implementation is key to RCU. For RCU
|
||||||
|
to be useful in all but the most read-intensive situations,
|
||||||
|
synchronize_rcu()'s overhead must also be quite small.
|
||||||
|
|
||||||
|
The call_rcu() API is a callback form of synchronize_rcu(),
|
||||||
|
and is described in more detail in a later section. Instead of
|
||||||
|
blocking, it registers a function and argument which are invoked
|
||||||
|
after all ongoing RCU read-side critical sections have completed.
|
||||||
|
This callback variant is particularly useful in situations where
|
||||||
|
it is illegal to block.
|
||||||
|
|
||||||
|
rcu_assign_pointer()
|
||||||
|
|
||||||
|
typeof(p) rcu_assign_pointer(p, typeof(p) v);
|
||||||
|
|
||||||
|
Yes, rcu_assign_pointer() -is- implemented as a macro, though it
|
||||||
|
would be cool to be able to declare a function in this manner.
|
||||||
|
(Compiler experts will no doubt disagree.)
|
||||||
|
|
||||||
|
The updater uses this function to assign a new value to an
|
||||||
|
RCU-protected pointer, in order to safely communicate the change
|
||||||
|
in value from the updater to the reader. This function returns
|
||||||
|
the new value, and also executes any memory-barrier instructions
|
||||||
|
required for a given CPU architecture.
|
||||||
|
|
||||||
|
Perhaps more important, it serves to document which pointers
|
||||||
|
are protected by RCU. That said, rcu_assign_pointer() is most
|
||||||
|
frequently used indirectly, via the _rcu list-manipulation
|
||||||
|
primitives such as list_add_rcu().
|
||||||
|
|
||||||
|
rcu_dereference()
|
||||||
|
|
||||||
|
typeof(p) rcu_dereference(p);
|
||||||
|
|
||||||
|
Like rcu_assign_pointer(), rcu_dereference() must be implemented
|
||||||
|
as a macro.
|
||||||
|
|
||||||
|
The reader uses rcu_dereference() to fetch an RCU-protected
|
||||||
|
pointer, which returns a value that may then be safely
|
||||||
|
dereferenced. Note that rcu_deference() does not actually
|
||||||
|
dereference the pointer, instead, it protects the pointer for
|
||||||
|
later dereferencing. It also executes any needed memory-barrier
|
||||||
|
instructions for a given CPU architecture. Currently, only Alpha
|
||||||
|
needs memory barriers within rcu_dereference() -- on other CPUs,
|
||||||
|
it compiles to nothing, not even a compiler directive.
|
||||||
|
|
||||||
|
Common coding practice uses rcu_dereference() to copy an
|
||||||
|
RCU-protected pointer to a local variable, then dereferences
|
||||||
|
this local variable, for example as follows:
|
||||||
|
|
||||||
|
p = rcu_dereference(head.next);
|
||||||
|
return p->data;
|
||||||
|
|
||||||
|
However, in this case, one could just as easily combine these
|
||||||
|
into one statement:
|
||||||
|
|
||||||
|
return rcu_dereference(head.next)->data;
|
||||||
|
|
||||||
|
If you are going to be fetching multiple fields from the
|
||||||
|
RCU-protected structure, using the local variable is of
|
||||||
|
course preferred. Repeated rcu_dereference() calls look
|
||||||
|
ugly and incur unnecessary overhead on Alpha CPUs.
|
||||||
|
|
||||||
|
Note that the value returned by rcu_dereference() is valid
|
||||||
|
only within the enclosing RCU read-side critical section.
|
||||||
|
For example, the following is -not- legal:
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
p = rcu_dereference(head.next);
|
||||||
|
rcu_read_unlock();
|
||||||
|
x = p->address;
|
||||||
|
rcu_read_lock();
|
||||||
|
y = p->data;
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
Holding a reference from one RCU read-side critical section
|
||||||
|
to another is just as illegal as holding a reference from
|
||||||
|
one lock-based critical section to another! Similarly,
|
||||||
|
using a reference outside of the critical section in which
|
||||||
|
it was acquired is just as illegal as doing so with normal
|
||||||
|
locking.
|
||||||
|
|
||||||
|
As with rcu_assign_pointer(), an important function of
|
||||||
|
rcu_dereference() is to document which pointers are protected
|
||||||
|
by RCU. And, again like rcu_assign_pointer(), rcu_dereference()
|
||||||
|
is typically used indirectly, via the _rcu list-manipulation
|
||||||
|
primitives, such as list_for_each_entry_rcu().
|
||||||
|
|
||||||
|
The following diagram shows how each API communicates among the
|
||||||
|
reader, updater, and reclaimer.
|
||||||
|
|
||||||
|
|
||||||
|
rcu_assign_pointer()
|
||||||
|
+--------+
|
||||||
|
+---------------------->| reader |---------+
|
||||||
|
| +--------+ |
|
||||||
|
| | |
|
||||||
|
| | | Protect:
|
||||||
|
| | | rcu_read_lock()
|
||||||
|
| | | rcu_read_unlock()
|
||||||
|
| rcu_dereference() | |
|
||||||
|
+---------+ | |
|
||||||
|
| updater |<---------------------+ |
|
||||||
|
+---------+ V
|
||||||
|
| +-----------+
|
||||||
|
+----------------------------------->| reclaimer |
|
||||||
|
+-----------+
|
||||||
|
Defer:
|
||||||
|
synchronize_rcu() & call_rcu()
|
||||||
|
|
||||||
|
|
||||||
|
The RCU infrastructure observes the time sequence of rcu_read_lock(),
|
||||||
|
rcu_read_unlock(), synchronize_rcu(), and call_rcu() invocations in
|
||||||
|
order to determine when (1) synchronize_rcu() invocations may return
|
||||||
|
to their callers and (2) call_rcu() callbacks may be invoked. Efficient
|
||||||
|
implementations of the RCU infrastructure make heavy use of batching in
|
||||||
|
order to amortize their overhead over many uses of the corresponding APIs.
|
||||||
|
|
||||||
|
There are no fewer than three RCU mechanisms in the Linux kernel; the
|
||||||
|
diagram above shows the first one, which is by far the most commonly used.
|
||||||
|
The rcu_dereference() and rcu_assign_pointer() primitives are used for
|
||||||
|
all three mechanisms, but different defer and protect primitives are
|
||||||
|
used as follows:
|
||||||
|
|
||||||
|
Defer Protect
|
||||||
|
|
||||||
|
a. synchronize_rcu() rcu_read_lock() / rcu_read_unlock()
|
||||||
|
call_rcu()
|
||||||
|
|
||||||
|
b. call_rcu_bh() rcu_read_lock_bh() / rcu_read_unlock_bh()
|
||||||
|
|
||||||
|
c. synchronize_sched() preempt_disable() / preempt_enable()
|
||||||
|
local_irq_save() / local_irq_restore()
|
||||||
|
hardirq enter / hardirq exit
|
||||||
|
NMI enter / NMI exit
|
||||||
|
|
||||||
|
These three mechanisms are used as follows:
|
||||||
|
|
||||||
|
a. RCU applied to normal data structures.
|
||||||
|
|
||||||
|
b. RCU applied to networking data structures that may be subjected
|
||||||
|
to remote denial-of-service attacks.
|
||||||
|
|
||||||
|
c. RCU applied to scheduler and interrupt/NMI-handler tasks.
|
||||||
|
|
||||||
|
Again, most uses will be of (a). The (b) and (c) cases are important
|
||||||
|
for specialized uses, but are relatively uncommon.
|
||||||
|
|
||||||
|
|
||||||
|
3. WHAT ARE SOME EXAMPLE USES OF CORE RCU API?
|
||||||
|
|
||||||
|
This section shows a simple use of the core RCU API to protect a
|
||||||
|
global pointer to a dynamically allocated structure. More typical
|
||||||
|
uses of RCU may be found in listRCU.txt, arrayRCU.txt, and NMI-RCU.txt.
|
||||||
|
|
||||||
|
struct foo {
|
||||||
|
int a;
|
||||||
|
char b;
|
||||||
|
long c;
|
||||||
|
};
|
||||||
|
DEFINE_SPINLOCK(foo_mutex);
|
||||||
|
|
||||||
|
struct foo *gbl_foo;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a new struct foo that is the same as the one currently
|
||||||
|
* pointed to by gbl_foo, except that field "a" is replaced
|
||||||
|
* with "new_a". Points gbl_foo to the new structure, and
|
||||||
|
* frees up the old structure after a grace period.
|
||||||
|
*
|
||||||
|
* Uses rcu_assign_pointer() to ensure that concurrent readers
|
||||||
|
* see the initialized version of the new structure.
|
||||||
|
*
|
||||||
|
* Uses synchronize_rcu() to ensure that any readers that might
|
||||||
|
* have references to the old structure complete before freeing
|
||||||
|
* the old structure.
|
||||||
|
*/
|
||||||
|
void foo_update_a(int new_a)
|
||||||
|
{
|
||||||
|
struct foo *new_fp;
|
||||||
|
struct foo *old_fp;
|
||||||
|
|
||||||
|
new_fp = kmalloc(sizeof(*fp), GFP_KERNEL);
|
||||||
|
spin_lock(&foo_mutex);
|
||||||
|
old_fp = gbl_foo;
|
||||||
|
*new_fp = *old_fp;
|
||||||
|
new_fp->a = new_a;
|
||||||
|
rcu_assign_pointer(gbl_foo, new_fp);
|
||||||
|
spin_unlock(&foo_mutex);
|
||||||
|
synchronize_rcu();
|
||||||
|
kfree(old_fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the value of field "a" of the current gbl_foo
|
||||||
|
* structure. Use rcu_read_lock() and rcu_read_unlock()
|
||||||
|
* to ensure that the structure does not get deleted out
|
||||||
|
* from under us, and use rcu_dereference() to ensure that
|
||||||
|
* we see the initialized version of the structure (important
|
||||||
|
* for DEC Alpha and for people reading the code).
|
||||||
|
*/
|
||||||
|
int foo_get_a(void)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
retval = rcu_dereference(gbl_foo)->a;
|
||||||
|
rcu_read_unlock();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
So, to sum up:
|
||||||
|
|
||||||
|
o Use rcu_read_lock() and rcu_read_unlock() to guard RCU
|
||||||
|
read-side critical sections.
|
||||||
|
|
||||||
|
o Within an RCU read-side critical section, use rcu_dereference()
|
||||||
|
to dereference RCU-protected pointers.
|
||||||
|
|
||||||
|
o Use some solid scheme (such as locks or semaphores) to
|
||||||
|
keep concurrent updates from interfering with each other.
|
||||||
|
|
||||||
|
o Use rcu_assign_pointer() to update an RCU-protected pointer.
|
||||||
|
This primitive protects concurrent readers from the updater,
|
||||||
|
-not- concurrent updates from each other! You therefore still
|
||||||
|
need to use locking (or something similar) to keep concurrent
|
||||||
|
rcu_assign_pointer() primitives from interfering with each other.
|
||||||
|
|
||||||
|
o Use synchronize_rcu() -after- removing a data element from an
|
||||||
|
RCU-protected data structure, but -before- reclaiming/freeing
|
||||||
|
the data element, in order to wait for the completion of all
|
||||||
|
RCU read-side critical sections that might be referencing that
|
||||||
|
data item.
|
||||||
|
|
||||||
|
See checklist.txt for additional rules to follow when using RCU.
|
||||||
|
|
||||||
|
|
||||||
|
4. WHAT IF MY UPDATING THREAD CANNOT BLOCK?
|
||||||
|
|
||||||
|
In the example above, foo_update_a() blocks until a grace period elapses.
|
||||||
|
This is quite simple, but in some cases one cannot afford to wait so
|
||||||
|
long -- there might be other high-priority work to be done.
|
||||||
|
|
||||||
|
In such cases, one uses call_rcu() rather than synchronize_rcu().
|
||||||
|
The call_rcu() API is as follows:
|
||||||
|
|
||||||
|
void call_rcu(struct rcu_head * head,
|
||||||
|
void (*func)(struct rcu_head *head));
|
||||||
|
|
||||||
|
This function invokes func(head) after a grace period has elapsed.
|
||||||
|
This invocation might happen from either softirq or process context,
|
||||||
|
so the function is not permitted to block. The foo struct needs to
|
||||||
|
have an rcu_head structure added, perhaps as follows:
|
||||||
|
|
||||||
|
struct foo {
|
||||||
|
int a;
|
||||||
|
char b;
|
||||||
|
long c;
|
||||||
|
struct rcu_head rcu;
|
||||||
|
};
|
||||||
|
|
||||||
|
The foo_update_a() function might then be written as follows:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a new struct foo that is the same as the one currently
|
||||||
|
* pointed to by gbl_foo, except that field "a" is replaced
|
||||||
|
* with "new_a". Points gbl_foo to the new structure, and
|
||||||
|
* frees up the old structure after a grace period.
|
||||||
|
*
|
||||||
|
* Uses rcu_assign_pointer() to ensure that concurrent readers
|
||||||
|
* see the initialized version of the new structure.
|
||||||
|
*
|
||||||
|
* Uses call_rcu() to ensure that any readers that might have
|
||||||
|
* references to the old structure complete before freeing the
|
||||||
|
* old structure.
|
||||||
|
*/
|
||||||
|
void foo_update_a(int new_a)
|
||||||
|
{
|
||||||
|
struct foo *new_fp;
|
||||||
|
struct foo *old_fp;
|
||||||
|
|
||||||
|
new_fp = kmalloc(sizeof(*fp), GFP_KERNEL);
|
||||||
|
spin_lock(&foo_mutex);
|
||||||
|
old_fp = gbl_foo;
|
||||||
|
*new_fp = *old_fp;
|
||||||
|
new_fp->a = new_a;
|
||||||
|
rcu_assign_pointer(gbl_foo, new_fp);
|
||||||
|
spin_unlock(&foo_mutex);
|
||||||
|
call_rcu(&old_fp->rcu, foo_reclaim);
|
||||||
|
}
|
||||||
|
|
||||||
|
The foo_reclaim() function might appear as follows:
|
||||||
|
|
||||||
|
void foo_reclaim(struct rcu_head *rp)
|
||||||
|
{
|
||||||
|
struct foo *fp = container_of(rp, struct foo, rcu);
|
||||||
|
|
||||||
|
kfree(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
The container_of() primitive is a macro that, given a pointer into a
|
||||||
|
struct, the type of the struct, and the pointed-to field within the
|
||||||
|
struct, returns a pointer to the beginning of the struct.
|
||||||
|
|
||||||
|
The use of call_rcu() permits the caller of foo_update_a() to
|
||||||
|
immediately regain control, without needing to worry further about the
|
||||||
|
old version of the newly updated element. It also clearly shows the
|
||||||
|
RCU distinction between updater, namely foo_update_a(), and reclaimer,
|
||||||
|
namely foo_reclaim().
|
||||||
|
|
||||||
|
The summary of advice is the same as for the previous section, except
|
||||||
|
that we are now using call_rcu() rather than synchronize_rcu():
|
||||||
|
|
||||||
|
o Use call_rcu() -after- removing a data element from an
|
||||||
|
RCU-protected data structure in order to register a callback
|
||||||
|
function that will be invoked after the completion of all RCU
|
||||||
|
read-side critical sections that might be referencing that
|
||||||
|
data item.
|
||||||
|
|
||||||
|
Again, see checklist.txt for additional rules governing the use of RCU.
|
||||||
|
|
||||||
|
|
||||||
|
5. WHAT ARE SOME SIMPLE IMPLEMENTATIONS OF RCU?
|
||||||
|
|
||||||
|
One of the nice things about RCU is that it has extremely simple "toy"
|
||||||
|
implementations that are a good first step towards understanding the
|
||||||
|
production-quality implementations in the Linux kernel. This section
|
||||||
|
presents two such "toy" implementations of RCU, one that is implemented
|
||||||
|
in terms of familiar locking primitives, and another that more closely
|
||||||
|
resembles "classic" RCU. Both are way too simple for real-world use,
|
||||||
|
lacking both functionality and performance. However, they are useful
|
||||||
|
in getting a feel for how RCU works. See kernel/rcupdate.c for a
|
||||||
|
production-quality implementation, and see:
|
||||||
|
|
||||||
|
http://www.rdrop.com/users/paulmck/RCU
|
||||||
|
|
||||||
|
for papers describing the Linux kernel RCU implementation. The OLS'01
|
||||||
|
and OLS'02 papers are a good introduction, and the dissertation provides
|
||||||
|
more details on the current implementation.
|
||||||
|
|
||||||
|
|
||||||
|
5A. "TOY" IMPLEMENTATION #1: LOCKING
|
||||||
|
|
||||||
|
This section presents a "toy" RCU implementation that is based on
|
||||||
|
familiar locking primitives. Its overhead makes it a non-starter for
|
||||||
|
real-life use, as does its lack of scalability. It is also unsuitable
|
||||||
|
for realtime use, since it allows scheduling latency to "bleed" from
|
||||||
|
one read-side critical section to another.
|
||||||
|
|
||||||
|
However, it is probably the easiest implementation to relate to, so is
|
||||||
|
a good starting point.
|
||||||
|
|
||||||
|
It is extremely simple:
|
||||||
|
|
||||||
|
static DEFINE_RWLOCK(rcu_gp_mutex);
|
||||||
|
|
||||||
|
void rcu_read_lock(void)
|
||||||
|
{
|
||||||
|
read_lock(&rcu_gp_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rcu_read_unlock(void)
|
||||||
|
{
|
||||||
|
read_unlock(&rcu_gp_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronize_rcu(void)
|
||||||
|
{
|
||||||
|
write_lock(&rcu_gp_mutex);
|
||||||
|
write_unlock(&rcu_gp_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
[You can ignore rcu_assign_pointer() and rcu_dereference() without
|
||||||
|
missing much. But here they are anyway. And whatever you do, don't
|
||||||
|
forget about them when submitting patches making use of RCU!]
|
||||||
|
|
||||||
|
#define rcu_assign_pointer(p, v) ({ \
|
||||||
|
smp_wmb(); \
|
||||||
|
(p) = (v); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define rcu_dereference(p) ({ \
|
||||||
|
typeof(p) _________p1 = p; \
|
||||||
|
smp_read_barrier_depends(); \
|
||||||
|
(_________p1); \
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
The rcu_read_lock() and rcu_read_unlock() primitive read-acquire
|
||||||
|
and release a global reader-writer lock. The synchronize_rcu()
|
||||||
|
primitive write-acquires this same lock, then immediately releases
|
||||||
|
it. This means that once synchronize_rcu() exits, all RCU read-side
|
||||||
|
critical sections that were in progress before synchonize_rcu() was
|
||||||
|
called are guaranteed to have completed -- there is no way that
|
||||||
|
synchronize_rcu() would have been able to write-acquire the lock
|
||||||
|
otherwise.
|
||||||
|
|
||||||
|
It is possible to nest rcu_read_lock(), since reader-writer locks may
|
||||||
|
be recursively acquired. Note also that rcu_read_lock() is immune
|
||||||
|
from deadlock (an important property of RCU). The reason for this is
|
||||||
|
that the only thing that can block rcu_read_lock() is a synchronize_rcu().
|
||||||
|
But synchronize_rcu() does not acquire any locks while holding rcu_gp_mutex,
|
||||||
|
so there can be no deadlock cycle.
|
||||||
|
|
||||||
|
Quick Quiz #1: Why is this argument naive? How could a deadlock
|
||||||
|
occur when using this algorithm in a real-world Linux
|
||||||
|
kernel? How could this deadlock be avoided?
|
||||||
|
|
||||||
|
|
||||||
|
5B. "TOY" EXAMPLE #2: CLASSIC RCU
|
||||||
|
|
||||||
|
This section presents a "toy" RCU implementation that is based on
|
||||||
|
"classic RCU". It is also short on performance (but only for updates) and
|
||||||
|
on features such as hotplug CPU and the ability to run in CONFIG_PREEMPT
|
||||||
|
kernels. The definitions of rcu_dereference() and rcu_assign_pointer()
|
||||||
|
are the same as those shown in the preceding section, so they are omitted.
|
||||||
|
|
||||||
|
void rcu_read_lock(void) { }
|
||||||
|
|
||||||
|
void rcu_read_unlock(void) { }
|
||||||
|
|
||||||
|
void synchronize_rcu(void)
|
||||||
|
{
|
||||||
|
int cpu;
|
||||||
|
|
||||||
|
for_each_cpu(cpu)
|
||||||
|
run_on(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
Note that rcu_read_lock() and rcu_read_unlock() do absolutely nothing.
|
||||||
|
This is the great strength of classic RCU in a non-preemptive kernel:
|
||||||
|
read-side overhead is precisely zero, at least on non-Alpha CPUs.
|
||||||
|
And there is absolutely no way that rcu_read_lock() can possibly
|
||||||
|
participate in a deadlock cycle!
|
||||||
|
|
||||||
|
The implementation of synchronize_rcu() simply schedules itself on each
|
||||||
|
CPU in turn. The run_on() primitive can be implemented straightforwardly
|
||||||
|
in terms of the sched_setaffinity() primitive. Of course, a somewhat less
|
||||||
|
"toy" implementation would restore the affinity upon completion rather
|
||||||
|
than just leaving all tasks running on the last CPU, but when I said
|
||||||
|
"toy", I meant -toy-!
|
||||||
|
|
||||||
|
So how the heck is this supposed to work???
|
||||||
|
|
||||||
|
Remember that it is illegal to block while in an RCU read-side critical
|
||||||
|
section. Therefore, if a given CPU executes a context switch, we know
|
||||||
|
that it must have completed all preceding RCU read-side critical sections.
|
||||||
|
Once -all- CPUs have executed a context switch, then -all- preceding
|
||||||
|
RCU read-side critical sections will have completed.
|
||||||
|
|
||||||
|
So, suppose that we remove a data item from its structure and then invoke
|
||||||
|
synchronize_rcu(). Once synchronize_rcu() returns, we are guaranteed
|
||||||
|
that there are no RCU read-side critical sections holding a reference
|
||||||
|
to that data item, so we can safely reclaim it.
|
||||||
|
|
||||||
|
Quick Quiz #2: Give an example where Classic RCU's read-side
|
||||||
|
overhead is -negative-.
|
||||||
|
|
||||||
|
Quick Quiz #3: If it is illegal to block in an RCU read-side
|
||||||
|
critical section, what the heck do you do in
|
||||||
|
PREEMPT_RT, where normal spinlocks can block???
|
||||||
|
|
||||||
|
|
||||||
|
6. ANALOGY WITH READER-WRITER LOCKING
|
||||||
|
|
||||||
|
Although RCU can be used in many different ways, a very common use of
|
||||||
|
RCU is analogous to reader-writer locking. The following unified
|
||||||
|
diff shows how closely related RCU and reader-writer locking can be.
|
||||||
|
|
||||||
|
@@ -13,15 +14,15 @@
|
||||||
|
struct list_head *lp;
|
||||||
|
struct el *p;
|
||||||
|
|
||||||
|
- read_lock();
|
||||||
|
- list_for_each_entry(p, head, lp) {
|
||||||
|
+ rcu_read_lock();
|
||||||
|
+ list_for_each_entry_rcu(p, head, lp) {
|
||||||
|
if (p->key == key) {
|
||||||
|
*result = p->data;
|
||||||
|
- read_unlock();
|
||||||
|
+ rcu_read_unlock();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- read_unlock();
|
||||||
|
+ rcu_read_unlock();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -29,15 +30,16 @@
|
||||||
|
{
|
||||||
|
struct el *p;
|
||||||
|
|
||||||
|
- write_lock(&listmutex);
|
||||||
|
+ spin_lock(&listmutex);
|
||||||
|
list_for_each_entry(p, head, lp) {
|
||||||
|
if (p->key == key) {
|
||||||
|
list_del(&p->list);
|
||||||
|
- write_unlock(&listmutex);
|
||||||
|
+ spin_unlock(&listmutex);
|
||||||
|
+ synchronize_rcu();
|
||||||
|
kfree(p);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- write_unlock(&listmutex);
|
||||||
|
+ spin_unlock(&listmutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Or, for those who prefer a side-by-side listing:
|
||||||
|
|
||||||
|
1 struct el { 1 struct el {
|
||||||
|
2 struct list_head list; 2 struct list_head list;
|
||||||
|
3 long key; 3 long key;
|
||||||
|
4 spinlock_t mutex; 4 spinlock_t mutex;
|
||||||
|
5 int data; 5 int data;
|
||||||
|
6 /* Other data fields */ 6 /* Other data fields */
|
||||||
|
7 }; 7 };
|
||||||
|
8 spinlock_t listmutex; 8 spinlock_t listmutex;
|
||||||
|
9 struct el head; 9 struct el head;
|
||||||
|
|
||||||
|
1 int search(long key, int *result) 1 int search(long key, int *result)
|
||||||
|
2 { 2 {
|
||||||
|
3 struct list_head *lp; 3 struct list_head *lp;
|
||||||
|
4 struct el *p; 4 struct el *p;
|
||||||
|
5 5
|
||||||
|
6 read_lock(); 6 rcu_read_lock();
|
||||||
|
7 list_for_each_entry(p, head, lp) { 7 list_for_each_entry_rcu(p, head, lp) {
|
||||||
|
8 if (p->key == key) { 8 if (p->key == key) {
|
||||||
|
9 *result = p->data; 9 *result = p->data;
|
||||||
|
10 read_unlock(); 10 rcu_read_unlock();
|
||||||
|
11 return 1; 11 return 1;
|
||||||
|
12 } 12 }
|
||||||
|
13 } 13 }
|
||||||
|
14 read_unlock(); 14 rcu_read_unlock();
|
||||||
|
15 return 0; 15 return 0;
|
||||||
|
16 } 16 }
|
||||||
|
|
||||||
|
1 int delete(long key) 1 int delete(long key)
|
||||||
|
2 { 2 {
|
||||||
|
3 struct el *p; 3 struct el *p;
|
||||||
|
4 4
|
||||||
|
5 write_lock(&listmutex); 5 spin_lock(&listmutex);
|
||||||
|
6 list_for_each_entry(p, head, lp) { 6 list_for_each_entry(p, head, lp) {
|
||||||
|
7 if (p->key == key) { 7 if (p->key == key) {
|
||||||
|
8 list_del(&p->list); 8 list_del(&p->list);
|
||||||
|
9 write_unlock(&listmutex); 9 spin_unlock(&listmutex);
|
||||||
|
10 synchronize_rcu();
|
||||||
|
10 kfree(p); 11 kfree(p);
|
||||||
|
11 return 1; 12 return 1;
|
||||||
|
12 } 13 }
|
||||||
|
13 } 14 }
|
||||||
|
14 write_unlock(&listmutex); 15 spin_unlock(&listmutex);
|
||||||
|
15 return 0; 16 return 0;
|
||||||
|
16 } 17 }
|
||||||
|
|
||||||
|
Either way, the differences are quite small. Read-side locking moves
|
||||||
|
to rcu_read_lock() and rcu_read_unlock, update-side locking moves from
|
||||||
|
from a reader-writer lock to a simple spinlock, and a synchronize_rcu()
|
||||||
|
precedes the kfree().
|
||||||
|
|
||||||
|
However, there is one potential catch: the read-side and update-side
|
||||||
|
critical sections can now run concurrently. In many cases, this will
|
||||||
|
not be a problem, but it is necessary to check carefully regardless.
|
||||||
|
For example, if multiple independent list updates must be seen as
|
||||||
|
a single atomic update, converting to RCU will require special care.
|
||||||
|
|
||||||
|
Also, the presence of synchronize_rcu() means that the RCU version of
|
||||||
|
delete() can now block. If this is a problem, there is a callback-based
|
||||||
|
mechanism that never blocks, namely call_rcu(), that can be used in
|
||||||
|
place of synchronize_rcu().
|
||||||
|
|
||||||
|
|
||||||
|
7. FULL LIST OF RCU APIs
|
||||||
|
|
||||||
|
The RCU APIs are documented in docbook-format header comments in the
|
||||||
|
Linux-kernel source code, but it helps to have a full list of the
|
||||||
|
APIs, since there does not appear to be a way to categorize them
|
||||||
|
in docbook. Here is the list, by category.
|
||||||
|
|
||||||
|
Markers for RCU read-side critical sections:
|
||||||
|
|
||||||
|
rcu_read_lock
|
||||||
|
rcu_read_unlock
|
||||||
|
rcu_read_lock_bh
|
||||||
|
rcu_read_unlock_bh
|
||||||
|
|
||||||
|
RCU pointer/list traversal:
|
||||||
|
|
||||||
|
rcu_dereference
|
||||||
|
list_for_each_rcu (to be deprecated in favor of
|
||||||
|
list_for_each_entry_rcu)
|
||||||
|
list_for_each_safe_rcu (deprecated, not used)
|
||||||
|
list_for_each_entry_rcu
|
||||||
|
list_for_each_continue_rcu (to be deprecated in favor of new
|
||||||
|
list_for_each_entry_continue_rcu)
|
||||||
|
hlist_for_each_rcu (to be deprecated in favor of
|
||||||
|
hlist_for_each_entry_rcu)
|
||||||
|
hlist_for_each_entry_rcu
|
||||||
|
|
||||||
|
RCU pointer update:
|
||||||
|
|
||||||
|
rcu_assign_pointer
|
||||||
|
list_add_rcu
|
||||||
|
list_add_tail_rcu
|
||||||
|
list_del_rcu
|
||||||
|
list_replace_rcu
|
||||||
|
hlist_del_rcu
|
||||||
|
hlist_add_head_rcu
|
||||||
|
|
||||||
|
RCU grace period:
|
||||||
|
|
||||||
|
synchronize_kernel (deprecated)
|
||||||
|
synchronize_net
|
||||||
|
synchronize_sched
|
||||||
|
synchronize_rcu
|
||||||
|
call_rcu
|
||||||
|
call_rcu_bh
|
||||||
|
|
||||||
|
See the comment headers in the source code (or the docbook generated
|
||||||
|
from them) for more information.
|
||||||
|
|
||||||
|
|
||||||
|
8. ANSWERS TO QUICK QUIZZES
|
||||||
|
|
||||||
|
Quick Quiz #1: Why is this argument naive? How could a deadlock
|
||||||
|
occur when using this algorithm in a real-world Linux
|
||||||
|
kernel? [Referring to the lock-based "toy" RCU
|
||||||
|
algorithm.]
|
||||||
|
|
||||||
|
Answer: Consider the following sequence of events:
|
||||||
|
|
||||||
|
1. CPU 0 acquires some unrelated lock, call it
|
||||||
|
"problematic_lock".
|
||||||
|
|
||||||
|
2. CPU 1 enters synchronize_rcu(), write-acquiring
|
||||||
|
rcu_gp_mutex.
|
||||||
|
|
||||||
|
3. CPU 0 enters rcu_read_lock(), but must wait
|
||||||
|
because CPU 1 holds rcu_gp_mutex.
|
||||||
|
|
||||||
|
4. CPU 1 is interrupted, and the irq handler
|
||||||
|
attempts to acquire problematic_lock.
|
||||||
|
|
||||||
|
The system is now deadlocked.
|
||||||
|
|
||||||
|
One way to avoid this deadlock is to use an approach like
|
||||||
|
that of CONFIG_PREEMPT_RT, where all normal spinlocks
|
||||||
|
become blocking locks, and all irq handlers execute in
|
||||||
|
the context of special tasks. In this case, in step 4
|
||||||
|
above, the irq handler would block, allowing CPU 1 to
|
||||||
|
release rcu_gp_mutex, avoiding the deadlock.
|
||||||
|
|
||||||
|
Even in the absence of deadlock, this RCU implementation
|
||||||
|
allows latency to "bleed" from readers to other
|
||||||
|
readers through synchronize_rcu(). To see this,
|
||||||
|
consider task A in an RCU read-side critical section
|
||||||
|
(thus read-holding rcu_gp_mutex), task B blocked
|
||||||
|
attempting to write-acquire rcu_gp_mutex, and
|
||||||
|
task C blocked in rcu_read_lock() attempting to
|
||||||
|
read_acquire rcu_gp_mutex. Task A's RCU read-side
|
||||||
|
latency is holding up task C, albeit indirectly via
|
||||||
|
task B.
|
||||||
|
|
||||||
|
Realtime RCU implementations therefore use a counter-based
|
||||||
|
approach where tasks in RCU read-side critical sections
|
||||||
|
cannot be blocked by tasks executing synchronize_rcu().
|
||||||
|
|
||||||
|
Quick Quiz #2: Give an example where Classic RCU's read-side
|
||||||
|
overhead is -negative-.
|
||||||
|
|
||||||
|
Answer: Imagine a single-CPU system with a non-CONFIG_PREEMPT
|
||||||
|
kernel where a routing table is used by process-context
|
||||||
|
code, but can be updated by irq-context code (for example,
|
||||||
|
by an "ICMP REDIRECT" packet). The usual way of handling
|
||||||
|
this would be to have the process-context code disable
|
||||||
|
interrupts while searching the routing table. Use of
|
||||||
|
RCU allows such interrupt-disabling to be dispensed with.
|
||||||
|
Thus, without RCU, you pay the cost of disabling interrupts,
|
||||||
|
and with RCU you don't.
|
||||||
|
|
||||||
|
One can argue that the overhead of RCU in this
|
||||||
|
case is negative with respect to the single-CPU
|
||||||
|
interrupt-disabling approach. Others might argue that
|
||||||
|
the overhead of RCU is merely zero, and that replacing
|
||||||
|
the positive overhead of the interrupt-disabling scheme
|
||||||
|
with the zero-overhead RCU scheme does not constitute
|
||||||
|
negative overhead.
|
||||||
|
|
||||||
|
In real life, of course, things are more complex. But
|
||||||
|
even the theoretical possibility of negative overhead for
|
||||||
|
a synchronization primitive is a bit unexpected. ;-)
|
||||||
|
|
||||||
|
Quick Quiz #3: If it is illegal to block in an RCU read-side
|
||||||
|
critical section, what the heck do you do in
|
||||||
|
PREEMPT_RT, where normal spinlocks can block???
|
||||||
|
|
||||||
|
Answer: Just as PREEMPT_RT permits preemption of spinlock
|
||||||
|
critical sections, it permits preemption of RCU
|
||||||
|
read-side critical sections. It also permits
|
||||||
|
spinlocks blocking while in RCU read-side critical
|
||||||
|
sections.
|
||||||
|
|
||||||
|
Why the apparent inconsistency? Because it is it
|
||||||
|
possible to use priority boosting to keep the RCU
|
||||||
|
grace periods short if need be (for example, if running
|
||||||
|
short of memory). In contrast, if blocking waiting
|
||||||
|
for (say) network reception, there is no way to know
|
||||||
|
what should be boosted. Especially given that the
|
||||||
|
process we need to boost might well be a human being
|
||||||
|
who just went out for a pizza or something. And although
|
||||||
|
a computer-operated cattle prod might arouse serious
|
||||||
|
interest, it might also provoke serious objections.
|
||||||
|
Besides, how does the computer know what pizza parlor
|
||||||
|
the human being went to???
|
||||||
|
|
||||||
|
|
||||||
|
ACKNOWLEDGEMENTS
|
||||||
|
|
||||||
|
My thanks to the people who helped make this human-readable, including
|
||||||
|
Jon Walpole, Josh Triplett, Serge Hallyn, and Suzanne Wood.
|
||||||
|
|
||||||
|
|
||||||
|
For more information, see http://www.rdrop.com/users/paulmck/RCU.
|
439
Documentation/applying-patches.txt
Normal file
439
Documentation/applying-patches.txt
Normal file
@ -0,0 +1,439 @@
|
|||||||
|
|
||||||
|
Applying Patches To The Linux Kernel
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
(Written by Jesper Juhl, August 2005)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
A frequently asked question on the Linux Kernel Mailing List is how to apply
|
||||||
|
a patch to the kernel or, more specifically, what base kernel a patch for
|
||||||
|
one of the many trees/branches should be applied to. Hopefully this document
|
||||||
|
will explain this to you.
|
||||||
|
|
||||||
|
In addition to explaining how to apply and revert patches, a brief
|
||||||
|
description of the different kernel trees (and examples of how to apply
|
||||||
|
their specific patches) is also provided.
|
||||||
|
|
||||||
|
|
||||||
|
What is a patch?
|
||||||
|
---
|
||||||
|
A patch is a small text document containing a delta of changes between two
|
||||||
|
different versions of a source tree. Patches are created with the `diff'
|
||||||
|
program.
|
||||||
|
To correctly apply a patch you need to know what base it was generated from
|
||||||
|
and what new version the patch will change the source tree into. These
|
||||||
|
should both be present in the patch file metadata or be possible to deduce
|
||||||
|
from the filename.
|
||||||
|
|
||||||
|
|
||||||
|
How do I apply or revert a patch?
|
||||||
|
---
|
||||||
|
You apply a patch with the `patch' program. The patch program reads a diff
|
||||||
|
(or patch) file and makes the changes to the source tree described in it.
|
||||||
|
|
||||||
|
Patches for the Linux kernel are generated relative to the parent directory
|
||||||
|
holding the kernel source dir.
|
||||||
|
|
||||||
|
This means that paths to files inside the patch file contain the name of the
|
||||||
|
kernel source directories it was generated against (or some other directory
|
||||||
|
names like "a/" and "b/").
|
||||||
|
Since this is unlikely to match the name of the kernel source dir on your
|
||||||
|
local machine (but is often useful info to see what version an otherwise
|
||||||
|
unlabeled patch was generated against) you should change into your kernel
|
||||||
|
source directory and then strip the first element of the path from filenames
|
||||||
|
in the patch file when applying it (the -p1 argument to `patch' does this).
|
||||||
|
|
||||||
|
To revert a previously applied patch, use the -R argument to patch.
|
||||||
|
So, if you applied a patch like this:
|
||||||
|
patch -p1 < ../patch-x.y.z
|
||||||
|
|
||||||
|
You can revert (undo) it like this:
|
||||||
|
patch -R -p1 < ../patch-x.y.z
|
||||||
|
|
||||||
|
|
||||||
|
How do I feed a patch/diff file to `patch'?
|
||||||
|
---
|
||||||
|
This (as usual with Linux and other UNIX like operating systems) can be
|
||||||
|
done in several different ways.
|
||||||
|
In all the examples below I feed the file (in uncompressed form) to patch
|
||||||
|
via stdin using the following syntax:
|
||||||
|
patch -p1 < path/to/patch-x.y.z
|
||||||
|
|
||||||
|
If you just want to be able to follow the examples below and don't want to
|
||||||
|
know of more than one way to use patch, then you can stop reading this
|
||||||
|
section here.
|
||||||
|
|
||||||
|
Patch can also get the name of the file to use via the -i argument, like
|
||||||
|
this:
|
||||||
|
patch -p1 -i path/to/patch-x.y.z
|
||||||
|
|
||||||
|
If your patch file is compressed with gzip or bzip2 and you don't want to
|
||||||
|
uncompress it before applying it, then you can feed it to patch like this
|
||||||
|
instead:
|
||||||
|
zcat path/to/patch-x.y.z.gz | patch -p1
|
||||||
|
bzcat path/to/patch-x.y.z.bz2 | patch -p1
|
||||||
|
|
||||||
|
If you wish to uncompress the patch file by hand first before applying it
|
||||||
|
(what I assume you've done in the examples below), then you simply run
|
||||||
|
gunzip or bunzip2 on the file - like this:
|
||||||
|
gunzip patch-x.y.z.gz
|
||||||
|
bunzip2 patch-x.y.z.bz2
|
||||||
|
|
||||||
|
Which will leave you with a plain text patch-x.y.z file that you can feed to
|
||||||
|
patch via stdin or the -i argument, as you prefer.
|
||||||
|
|
||||||
|
A few other nice arguments for patch are -s which causes patch to be silent
|
||||||
|
except for errors which is nice to prevent errors from scrolling out of the
|
||||||
|
screen too fast, and --dry-run which causes patch to just print a listing of
|
||||||
|
what would happen, but doesn't actually make any changes. Finally --verbose
|
||||||
|
tells patch to print more information about the work being done.
|
||||||
|
|
||||||
|
|
||||||
|
Common errors when patching
|
||||||
|
---
|
||||||
|
When patch applies a patch file it attempts to verify the sanity of the
|
||||||
|
file in different ways.
|
||||||
|
Checking that the file looks like a valid patch file, checking the code
|
||||||
|
around the bits being modified matches the context provided in the patch are
|
||||||
|
just two of the basic sanity checks patch does.
|
||||||
|
|
||||||
|
If patch encounters something that doesn't look quite right it has two
|
||||||
|
options. It can either refuse to apply the changes and abort or it can try
|
||||||
|
to find a way to make the patch apply with a few minor changes.
|
||||||
|
|
||||||
|
One example of something that's not 'quite right' that patch will attempt to
|
||||||
|
fix up is if all the context matches, the lines being changed match, but the
|
||||||
|
line numbers are different. This can happen, for example, if the patch makes
|
||||||
|
a change in the middle of the file but for some reasons a few lines have
|
||||||
|
been added or removed near the beginning of the file. In that case
|
||||||
|
everything looks good it has just moved up or down a bit, and patch will
|
||||||
|
usually adjust the line numbers and apply the patch.
|
||||||
|
|
||||||
|
Whenever patch applies a patch that it had to modify a bit to make it fit
|
||||||
|
it'll tell you about it by saying the patch applied with 'fuzz'.
|
||||||
|
You should be wary of such changes since even though patch probably got it
|
||||||
|
right it doesn't /always/ get it right, and the result will sometimes be
|
||||||
|
wrong.
|
||||||
|
|
||||||
|
When patch encounters a change that it can't fix up with fuzz it rejects it
|
||||||
|
outright and leaves a file with a .rej extension (a reject file). You can
|
||||||
|
read this file to see exactely what change couldn't be applied, so you can
|
||||||
|
go fix it up by hand if you wish.
|
||||||
|
|
||||||
|
If you don't have any third party patches applied to your kernel source, but
|
||||||
|
only patches from kernel.org and you apply the patches in the correct order,
|
||||||
|
and have made no modifications yourself to the source files, then you should
|
||||||
|
never see a fuzz or reject message from patch. If you do see such messages
|
||||||
|
anyway, then there's a high risk that either your local source tree or the
|
||||||
|
patch file is corrupted in some way. In that case you should probably try
|
||||||
|
redownloading the patch and if things are still not OK then you'd be advised
|
||||||
|
to start with a fresh tree downloaded in full from kernel.org.
|
||||||
|
|
||||||
|
Let's look a bit more at some of the messages patch can produce.
|
||||||
|
|
||||||
|
If patch stops and presents a "File to patch:" prompt, then patch could not
|
||||||
|
find a file to be patched. Most likely you forgot to specify -p1 or you are
|
||||||
|
in the wrong directory. Less often, you'll find patches that need to be
|
||||||
|
applied with -p0 instead of -p1 (reading the patch file should reveal if
|
||||||
|
this is the case - if so, then this is an error by the person who created
|
||||||
|
the patch but is not fatal).
|
||||||
|
|
||||||
|
If you get "Hunk #2 succeeded at 1887 with fuzz 2 (offset 7 lines)." or a
|
||||||
|
message similar to that, then it means that patch had to adjust the location
|
||||||
|
of the change (in this example it needed to move 7 lines from where it
|
||||||
|
expected to make the change to make it fit).
|
||||||
|
The resulting file may or may not be OK, depending on the reason the file
|
||||||
|
was different than expected.
|
||||||
|
This often happens if you try to apply a patch that was generated against a
|
||||||
|
different kernel version than the one you are trying to patch.
|
||||||
|
|
||||||
|
If you get a message like "Hunk #3 FAILED at 2387.", then it means that the
|
||||||
|
patch could not be applied correctly and the patch program was unable to
|
||||||
|
fuzz its way through. This will generate a .rej file with the change that
|
||||||
|
caused the patch to fail and also a .orig file showing you the original
|
||||||
|
content that couldn't be changed.
|
||||||
|
|
||||||
|
If you get "Reversed (or previously applied) patch detected! Assume -R? [n]"
|
||||||
|
then patch detected that the change contained in the patch seems to have
|
||||||
|
already been made.
|
||||||
|
If you actually did apply this patch previously and you just re-applied it
|
||||||
|
in error, then just say [n]o and abort this patch. If you applied this patch
|
||||||
|
previously and actually intended to revert it, but forgot to specify -R,
|
||||||
|
then you can say [y]es here to make patch revert it for you.
|
||||||
|
This can also happen if the creator of the patch reversed the source and
|
||||||
|
destination directories when creating the patch, and in that case reverting
|
||||||
|
the patch will in fact apply it.
|
||||||
|
|
||||||
|
A message similar to "patch: **** unexpected end of file in patch" or "patch
|
||||||
|
unexpectedly ends in middle of line" means that patch could make no sense of
|
||||||
|
the file you fed to it. Either your download is broken or you tried to feed
|
||||||
|
patch a compressed patch file without uncompressing it first.
|
||||||
|
|
||||||
|
As I already mentioned above, these errors should never happen if you apply
|
||||||
|
a patch from kernel.org to the correct version of an unmodified source tree.
|
||||||
|
So if you get these errors with kernel.org patches then you should probably
|
||||||
|
assume that either your patch file or your tree is broken and I'd advice you
|
||||||
|
to start over with a fresh download of a full kernel tree and the patch you
|
||||||
|
wish to apply.
|
||||||
|
|
||||||
|
|
||||||
|
Are there any alternatives to `patch'?
|
||||||
|
---
|
||||||
|
Yes there are alternatives. You can use the `interdiff' program
|
||||||
|
(http://cyberelk.net/tim/patchutils/) to generate a patch representing the
|
||||||
|
differences between two patches and then apply the result.
|
||||||
|
This will let you move from something like 2.6.12.2 to 2.6.12.3 in a single
|
||||||
|
step. The -z flag to interdiff will even let you feed it patches in gzip or
|
||||||
|
bzip2 compressed form directly without the use of zcat or bzcat or manual
|
||||||
|
decompression.
|
||||||
|
|
||||||
|
Here's how you'd go from 2.6.12.2 to 2.6.12.3 in a single step:
|
||||||
|
interdiff -z ../patch-2.6.12.2.bz2 ../patch-2.6.12.3.gz | patch -p1
|
||||||
|
|
||||||
|
Although interdiff may save you a step or two you are generally advised to
|
||||||
|
do the additional steps since interdiff can get things wrong in some cases.
|
||||||
|
|
||||||
|
Another alternative is `ketchup', which is a python script for automatic
|
||||||
|
downloading and applying of patches (http://www.selenic.com/ketchup/).
|
||||||
|
|
||||||
|
Other nice tools are diffstat which shows a summary of changes made by a
|
||||||
|
patch, lsdiff which displays a short listing of affected files in a patch
|
||||||
|
file, along with (optionally) the line numbers of the start of each patch
|
||||||
|
and grepdiff which displays a list of the files modified by a patch where
|
||||||
|
the patch contains a given regular expression.
|
||||||
|
|
||||||
|
|
||||||
|
Where can I download the patches?
|
||||||
|
---
|
||||||
|
The patches are available at http://kernel.org/
|
||||||
|
Most recent patches are linked from the front page, but they also have
|
||||||
|
specific homes.
|
||||||
|
|
||||||
|
The 2.6.x.y (-stable) and 2.6.x patches live at
|
||||||
|
ftp://ftp.kernel.org/pub/linux/kernel/v2.6/
|
||||||
|
|
||||||
|
The -rc patches live at
|
||||||
|
ftp://ftp.kernel.org/pub/linux/kernel/v2.6/testing/
|
||||||
|
|
||||||
|
The -git patches live at
|
||||||
|
ftp://ftp.kernel.org/pub/linux/kernel/v2.6/snapshots/
|
||||||
|
|
||||||
|
The -mm kernels live at
|
||||||
|
ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/
|
||||||
|
|
||||||
|
In place of ftp.kernel.org you can use ftp.cc.kernel.org, where cc is a
|
||||||
|
country code. This way you'll be downloading from a mirror site that's most
|
||||||
|
likely geographically closer to you, resulting in faster downloads for you,
|
||||||
|
less bandwidth used globally and less load on the main kernel.org servers -
|
||||||
|
these are good things, do use mirrors when possible.
|
||||||
|
|
||||||
|
|
||||||
|
The 2.6.x kernels
|
||||||
|
---
|
||||||
|
These are the base stable releases released by Linus. The highest numbered
|
||||||
|
release is the most recent.
|
||||||
|
|
||||||
|
If regressions or other serious flaws are found then a -stable fix patch
|
||||||
|
will be released (see below) on top of this base. Once a new 2.6.x base
|
||||||
|
kernel is released, a patch is made available that is a delta between the
|
||||||
|
previous 2.6.x kernel and the new one.
|
||||||
|
|
||||||
|
To apply a patch moving from 2.6.11 to 2.6.12 you'd do the following (note
|
||||||
|
that such patches do *NOT* apply on top of 2.6.x.y kernels but on top of the
|
||||||
|
base 2.6.x kernel - if you need to move from 2.6.x.y to 2.6.x+1 you need to
|
||||||
|
first revert the 2.6.x.y patch).
|
||||||
|
|
||||||
|
Here are some examples:
|
||||||
|
|
||||||
|
# moving from 2.6.11 to 2.6.12
|
||||||
|
$ cd ~/linux-2.6.11 # change to kernel source dir
|
||||||
|
$ patch -p1 < ../patch-2.6.12 # apply the 2.6.12 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.11 linux-2.6.12 # rename source dir
|
||||||
|
|
||||||
|
# moving from 2.6.11.1 to 2.6.12
|
||||||
|
$ cd ~/linux-2.6.11.1 # change to kernel source dir
|
||||||
|
$ patch -p1 -R < ../patch-2.6.11.1 # revert the 2.6.11.1 patch
|
||||||
|
# source dir is now 2.6.11
|
||||||
|
$ patch -p1 < ../patch-2.6.12 # apply new 2.6.12 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.11.1 inux-2.6.12 # rename source dir
|
||||||
|
|
||||||
|
|
||||||
|
The 2.6.x.y kernels
|
||||||
|
---
|
||||||
|
Kernels with 4 digit versions are -stable kernels. They contain small(ish)
|
||||||
|
critical fixes for security problems or significant regressions discovered
|
||||||
|
in a given 2.6.x kernel.
|
||||||
|
|
||||||
|
This is the recommended branch for users who want the most recent stable
|
||||||
|
kernel and are not interested in helping test development/experimental
|
||||||
|
versions.
|
||||||
|
|
||||||
|
If no 2.6.x.y kernel is available, then the highest numbered 2.6.x kernel is
|
||||||
|
the current stable kernel.
|
||||||
|
|
||||||
|
These patches are not incremental, meaning that for example the 2.6.12.3
|
||||||
|
patch does not apply on top of the 2.6.12.2 kernel source, but rather on top
|
||||||
|
of the base 2.6.12 kernel source.
|
||||||
|
So, in order to apply the 2.6.12.3 patch to your existing 2.6.12.2 kernel
|
||||||
|
source you have to first back out the 2.6.12.2 patch (so you are left with a
|
||||||
|
base 2.6.12 kernel source) and then apply the new 2.6.12.3 patch.
|
||||||
|
|
||||||
|
Here's a small example:
|
||||||
|
|
||||||
|
$ cd ~/linux-2.6.12.2 # change into the kernel source dir
|
||||||
|
$ patch -p1 -R < ../patch-2.6.12.2 # revert the 2.6.12.2 patch
|
||||||
|
$ patch -p1 < ../patch-2.6.12.3 # apply the new 2.6.12.3 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.12.2 linux-2.6.12.3 # rename the kernel source dir
|
||||||
|
|
||||||
|
|
||||||
|
The -rc kernels
|
||||||
|
---
|
||||||
|
These are release-candidate kernels. These are development kernels released
|
||||||
|
by Linus whenever he deems the current git (the kernel's source management
|
||||||
|
tool) tree to be in a reasonably sane state adequate for testing.
|
||||||
|
|
||||||
|
These kernels are not stable and you should expect occasional breakage if
|
||||||
|
you intend to run them. This is however the most stable of the main
|
||||||
|
development branches and is also what will eventually turn into the next
|
||||||
|
stable kernel, so it is important that it be tested by as many people as
|
||||||
|
possible.
|
||||||
|
|
||||||
|
This is a good branch to run for people who want to help out testing
|
||||||
|
development kernels but do not want to run some of the really experimental
|
||||||
|
stuff (such people should see the sections about -git and -mm kernels below).
|
||||||
|
|
||||||
|
The -rc patches are not incremental, they apply to a base 2.6.x kernel, just
|
||||||
|
like the 2.6.x.y patches described above. The kernel version before the -rcN
|
||||||
|
suffix denotes the version of the kernel that this -rc kernel will eventually
|
||||||
|
turn into.
|
||||||
|
So, 2.6.13-rc5 means that this is the fifth release candidate for the 2.6.13
|
||||||
|
kernel and the patch should be applied on top of the 2.6.12 kernel source.
|
||||||
|
|
||||||
|
Here are 3 examples of how to apply these patches:
|
||||||
|
|
||||||
|
# first an example of moving from 2.6.12 to 2.6.13-rc3
|
||||||
|
$ cd ~/linux-2.6.12 # change into the 2.6.12 source dir
|
||||||
|
$ patch -p1 < ../patch-2.6.13-rc3 # apply the 2.6.13-rc3 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.12 linux-2.6.13-rc3 # rename the source dir
|
||||||
|
|
||||||
|
# now let's move from 2.6.13-rc3 to 2.6.13-rc5
|
||||||
|
$ cd ~/linux-2.6.13-rc3 # change into the 2.6.13-rc3 dir
|
||||||
|
$ patch -p1 -R < ../patch-2.6.13-rc3 # revert the 2.6.13-rc3 patch
|
||||||
|
$ patch -p1 < ../patch-2.6.13-rc5 # apply the new 2.6.13-rc5 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.13-rc3 linux-2.6.13-rc5 # rename the source dir
|
||||||
|
|
||||||
|
# finally let's try and move from 2.6.12.3 to 2.6.13-rc5
|
||||||
|
$ cd ~/linux-2.6.12.3 # change to the kernel source dir
|
||||||
|
$ patch -p1 -R < ../patch-2.6.12.3 # revert the 2.6.12.3 patch
|
||||||
|
$ patch -p1 < ../patch-2.6.13-rc5 # apply new 2.6.13-rc5 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.12.3 linux-2.6.13-rc5 # rename the kernel source dir
|
||||||
|
|
||||||
|
|
||||||
|
The -git kernels
|
||||||
|
---
|
||||||
|
These are daily snapshots of Linus' kernel tree (managed in a git
|
||||||
|
repository, hence the name).
|
||||||
|
|
||||||
|
These patches are usually released daily and represent the current state of
|
||||||
|
Linus' tree. They are more experimental than -rc kernels since they are
|
||||||
|
generated automatically without even a cursory glance to see if they are
|
||||||
|
sane.
|
||||||
|
|
||||||
|
-git patches are not incremental and apply either to a base 2.6.x kernel or
|
||||||
|
a base 2.6.x-rc kernel - you can see which from their name.
|
||||||
|
A patch named 2.6.12-git1 applies to the 2.6.12 kernel source and a patch
|
||||||
|
named 2.6.13-rc3-git2 applies to the source of the 2.6.13-rc3 kernel.
|
||||||
|
|
||||||
|
Here are some examples of how to apply these patches:
|
||||||
|
|
||||||
|
# moving from 2.6.12 to 2.6.12-git1
|
||||||
|
$ cd ~/linux-2.6.12 # change to the kernel source dir
|
||||||
|
$ patch -p1 < ../patch-2.6.12-git1 # apply the 2.6.12-git1 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.12 linux-2.6.12-git1 # rename the kernel source dir
|
||||||
|
|
||||||
|
# moving from 2.6.12-git1 to 2.6.13-rc2-git3
|
||||||
|
$ cd ~/linux-2.6.12-git1 # change to the kernel source dir
|
||||||
|
$ patch -p1 -R < ../patch-2.6.12-git1 # revert the 2.6.12-git1 patch
|
||||||
|
# we now have a 2.6.12 kernel
|
||||||
|
$ patch -p1 < ../patch-2.6.13-rc2 # apply the 2.6.13-rc2 patch
|
||||||
|
# the kernel is now 2.6.13-rc2
|
||||||
|
$ patch -p1 < ../patch-2.6.13-rc2-git3 # apply the 2.6.13-rc2-git3 patch
|
||||||
|
# the kernel is now 2.6.13-rc2-git3
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.12-git1 linux-2.6.13-rc2-git3 # rename source dir
|
||||||
|
|
||||||
|
|
||||||
|
The -mm kernels
|
||||||
|
---
|
||||||
|
These are experimental kernels released by Andrew Morton.
|
||||||
|
|
||||||
|
The -mm tree serves as a sort of proving ground for new features and other
|
||||||
|
experimental patches.
|
||||||
|
Once a patch has proved its worth in -mm for a while Andrew pushes it on to
|
||||||
|
Linus for inclusion in mainline.
|
||||||
|
|
||||||
|
Although it's encouraged that patches flow to Linus via the -mm tree, this
|
||||||
|
is not always enforced.
|
||||||
|
Subsystem maintainers (or individuals) sometimes push their patches directly
|
||||||
|
to Linus, even though (or after) they have been merged and tested in -mm (or
|
||||||
|
sometimes even without prior testing in -mm).
|
||||||
|
|
||||||
|
You should generally strive to get your patches into mainline via -mm to
|
||||||
|
ensure maximum testing.
|
||||||
|
|
||||||
|
This branch is in constant flux and contains many experimental features, a
|
||||||
|
lot of debugging patches not appropriate for mainline etc and is the most
|
||||||
|
experimental of the branches described in this document.
|
||||||
|
|
||||||
|
These kernels are not appropriate for use on systems that are supposed to be
|
||||||
|
stable and they are more risky to run than any of the other branches (make
|
||||||
|
sure you have up-to-date backups - that goes for any experimental kernel but
|
||||||
|
even more so for -mm kernels).
|
||||||
|
|
||||||
|
These kernels in addition to all the other experimental patches they contain
|
||||||
|
usually also contain any changes in the mainline -git kernels available at
|
||||||
|
the time of release.
|
||||||
|
|
||||||
|
Testing of -mm kernels is greatly appreciated since the whole point of the
|
||||||
|
tree is to weed out regressions, crashes, data corruption bugs, build
|
||||||
|
breakage (and any other bug in general) before changes are merged into the
|
||||||
|
more stable mainline Linus tree.
|
||||||
|
But testers of -mm should be aware that breakage in this tree is more common
|
||||||
|
than in any other tree.
|
||||||
|
|
||||||
|
The -mm kernels are not released on a fixed schedule, but usually a few -mm
|
||||||
|
kernels are released in between each -rc kernel (1 to 3 is common).
|
||||||
|
The -mm kernels apply to either a base 2.6.x kernel (when no -rc kernels
|
||||||
|
have been released yet) or to a Linus -rc kernel.
|
||||||
|
|
||||||
|
Here are some examples of applying the -mm patches:
|
||||||
|
|
||||||
|
# moving from 2.6.12 to 2.6.12-mm1
|
||||||
|
$ cd ~/linux-2.6.12 # change to the 2.6.12 source dir
|
||||||
|
$ patch -p1 < ../2.6.12-mm1 # apply the 2.6.12-mm1 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.12 linux-2.6.12-mm1 # rename the source appropriately
|
||||||
|
|
||||||
|
# moving from 2.6.12-mm1 to 2.6.13-rc3-mm3
|
||||||
|
$ cd ~/linux-2.6.12-mm1
|
||||||
|
$ patch -p1 -R < ../2.6.12-mm1 # revert the 2.6.12-mm1 patch
|
||||||
|
# we now have a 2.6.12 source
|
||||||
|
$ patch -p1 < ../patch-2.6.13-rc3 # apply the 2.6.13-rc3 patch
|
||||||
|
# we now have a 2.6.13-rc3 source
|
||||||
|
$ patch -p1 < ../2.6.13-rc3-mm3 # apply the 2.6.13-rc3-mm3 patch
|
||||||
|
$ cd ..
|
||||||
|
$ mv linux-2.6.12-mm1 linux-2.6.13-rc3-mm3 # rename the source dir
|
||||||
|
|
||||||
|
|
||||||
|
This concludes this list of explanations of the various kernel trees and I
|
||||||
|
hope you are now crystal clear on how to apply the various patches and help
|
||||||
|
testing the kernel.
|
||||||
|
|
@ -36,7 +36,7 @@ cpufreq stats provides following statistics (explained in detail below).
|
|||||||
|
|
||||||
All the statistics will be from the time the stats driver has been inserted
|
All the statistics will be from the time the stats driver has been inserted
|
||||||
to the time when a read of a particular statistic is done. Obviously, stats
|
to the time when a read of a particular statistic is done. Obviously, stats
|
||||||
driver will not have any information about the the frequcny transitions before
|
driver will not have any information about the frequency transitions before
|
||||||
the stats driver insertion.
|
the stats driver insertion.
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
@ -277,7 +277,7 @@ rewritten to the 'tasks' file of its cpuset. This is done to avoid
|
|||||||
impacting the scheduler code in the kernel with a check for changes
|
impacting the scheduler code in the kernel with a check for changes
|
||||||
in a tasks processor placement.
|
in a tasks processor placement.
|
||||||
|
|
||||||
There is an exception to the above. If hotplug funtionality is used
|
There is an exception to the above. If hotplug functionality is used
|
||||||
to remove all the CPUs that are currently assigned to a cpuset,
|
to remove all the CPUs that are currently assigned to a cpuset,
|
||||||
then the kernel will automatically update the cpus_allowed of all
|
then the kernel will automatically update the cpus_allowed of all
|
||||||
tasks attached to CPUs in that cpuset to allow all CPUs. When memory
|
tasks attached to CPUs in that cpuset to allow all CPUs. When memory
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Below is the orginal README file from the descore.shar package.
|
Below is the original README file from the descore.shar package.
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
des - fast & portable DES encryption & decryption.
|
des - fast & portable DES encryption & decryption.
|
||||||
|
@ -1,55 +1,74 @@
|
|||||||
How to get the Nebula Electronics DigiTV, Pinnacle PCTV Sat, Twinhan DST + clones working
|
How to get the Nebula, PCTV and Twinhan DST cards working
|
||||||
=========================================================================================
|
=========================================================
|
||||||
|
|
||||||
1) General information
|
This class of cards has a bt878a as the PCI interface, and
|
||||||
======================
|
require the bttv driver.
|
||||||
|
|
||||||
This class of cards has a bt878a chip as the PCI interface.
|
Please pay close attention to the warning about the bttv module
|
||||||
The different card drivers require the bttv driver to provide the means
|
options below for the DST card.
|
||||||
to access the i2c bus and the gpio pins of the bt8xx chipset.
|
|
||||||
|
|
||||||
2) Compilation rules for Kernel >= 2.6.12
|
1) General informations
|
||||||
=========================================
|
=======================
|
||||||
|
|
||||||
Enable the following options:
|
These drivers require the bttv driver to provide the means to access
|
||||||
|
the i2c bus and the gpio pins of the bt8xx chipset.
|
||||||
|
|
||||||
|
Because of this, you need to enable
|
||||||
"Device drivers" => "Multimedia devices"
|
"Device drivers" => "Multimedia devices"
|
||||||
=> "Video For Linux" => "BT848 Video For Linux"
|
=> "Video For Linux" => "BT848 Video For Linux"
|
||||||
|
|
||||||
|
Furthermore you need to enable
|
||||||
"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
|
"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
|
||||||
=> "DVB for Linux" "DVB Core Support" "BT8xx based PCI cards"
|
=> "DVB for Linux" "DVB Core Support" "BT8xx based PCI cards"
|
||||||
|
|
||||||
3) Loading Modules, described by two approaches
|
2) Loading Modules
|
||||||
===============================================
|
==================
|
||||||
|
|
||||||
In general you need to load the bttv driver, which will handle the gpio and
|
In general you need to load the bttv driver, which will handle the gpio and
|
||||||
i2c communication for us, plus the common dvb-bt8xx device driver,
|
i2c communication for us, plus the common dvb-bt8xx device driver.
|
||||||
which is called the backend.
|
The frontends for Nebula (nxt6000), Pinnacle PCTV (cx24110) and
|
||||||
The frontends for Nebula DigiTV (nxt6000), Pinnacle PCTV Sat (cx24110),
|
TwinHan (dst) are loaded automatically by the dvb-bt8xx device driver.
|
||||||
TwinHan DST + clones (dst and dst-ca) are loaded automatically by the backend.
|
|
||||||
For further details about TwinHan DST + clones see /Documentation/dvb/ci.txt.
|
|
||||||
|
|
||||||
3a) The manual approach
|
3a) Nebula / Pinnacle PCTV
|
||||||
-----------------------
|
|
||||||
|
|
||||||
Loading modules:
|
|
||||||
modprobe bttv
|
|
||||||
modprobe dvb-bt8xx
|
|
||||||
|
|
||||||
Unloading modules:
|
|
||||||
modprobe -r dvb-bt8xx
|
|
||||||
modprobe -r bttv
|
|
||||||
|
|
||||||
3b) The automatic approach
|
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
If not already done by installation, place a line either in
|
$ modprobe bttv (normally bttv is being loaded automatically by kmod)
|
||||||
/etc/modules.conf or in /etc/modprobe.conf containing this text:
|
$ modprobe dvb-bt8xx (or just place dvb-bt8xx in /etc/modules for automatic loading)
|
||||||
alias char-major-81 bttv
|
|
||||||
|
|
||||||
Then place a line in /etc/modules containing this text:
|
|
||||||
dvb-bt8xx
|
|
||||||
|
|
||||||
Reboot your system and have fun!
|
3b) TwinHan and Clones
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
$ modprobe bttv i2c_hw=1 card=0x71
|
||||||
|
$ modprobe dvb-bt8xx
|
||||||
|
$ modprobe dst
|
||||||
|
|
||||||
|
The value 0x71 will override the PCI type detection for dvb-bt8xx,
|
||||||
|
which is necessary for TwinHan cards.
|
||||||
|
|
||||||
|
If you're having an older card (blue color circuit) and card=0x71 locks
|
||||||
|
your machine, try using 0x68, too. If that does not work, ask on the
|
||||||
|
mailing list.
|
||||||
|
|
||||||
|
The DST module takes a couple of useful parameters.
|
||||||
|
|
||||||
|
verbose takes values 0 to 4. These values control the verbosity level,
|
||||||
|
and can be used to debug also.
|
||||||
|
|
||||||
|
verbose=0 means complete disabling of messages
|
||||||
|
1 only error messages are displayed
|
||||||
|
2 notifications are also displayed
|
||||||
|
3 informational messages are also displayed
|
||||||
|
4 debug setting
|
||||||
|
|
||||||
|
dst_addons takes values 0 and 0x20. A value of 0 means it is a FTA card.
|
||||||
|
0x20 means it has a Conditional Access slot.
|
||||||
|
|
||||||
|
The autodected values are determined bythe cards 'response
|
||||||
|
string' which you can see in your logs e.g.
|
||||||
|
|
||||||
|
dst_get_device_id: Recognise [DSTMCI]
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham, Uwe Bugla
|
Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham
|
||||||
|
@ -23,7 +23,6 @@ This application requires the following to function properly as of now.
|
|||||||
eg: $ szap -c channels.conf -r "TMC" -x
|
eg: $ szap -c channels.conf -r "TMC" -x
|
||||||
|
|
||||||
(b) a channels.conf containing a valid PMT PID
|
(b) a channels.conf containing a valid PMT PID
|
||||||
|
|
||||||
eg: TMC:11996:h:0:27500:278:512:650:321
|
eg: TMC:11996:h:0:27500:278:512:650:321
|
||||||
|
|
||||||
here 278 is a valid PMT PID. the rest of the values are the
|
here 278 is a valid PMT PID. the rest of the values are the
|
||||||
@ -31,13 +30,7 @@ This application requires the following to function properly as of now.
|
|||||||
|
|
||||||
(c) after running a szap, you have to run ca_zap, for the
|
(c) after running a szap, you have to run ca_zap, for the
|
||||||
descrambler to function,
|
descrambler to function,
|
||||||
|
eg: $ ca_zap channels.conf "TMC"
|
||||||
eg: $ ca_zap patched_channels.conf "TMC"
|
|
||||||
|
|
||||||
The patched means a patch to apply to scan, such that scan can
|
|
||||||
generate a channels.conf_with pmt, which has this PMT PID info
|
|
||||||
(NOTE: szap cannot use this channels.conf with the PMT_PID)
|
|
||||||
|
|
||||||
|
|
||||||
(d) Hopeflly Enjoy your favourite subscribed channel as you do with
|
(d) Hopeflly Enjoy your favourite subscribed channel as you do with
|
||||||
a FTA card.
|
a FTA card.
|
||||||
|
14
Documentation/fb/cyblafb/bugs
Normal file
14
Documentation/fb/cyblafb/bugs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Bugs
|
||||||
|
====
|
||||||
|
|
||||||
|
I currently don't know of any bug. Please do send reports to:
|
||||||
|
- linux-fbdev-devel@lists.sourceforge.net
|
||||||
|
- Knut_Petersen@t-online.de.
|
||||||
|
|
||||||
|
|
||||||
|
Untested features
|
||||||
|
=================
|
||||||
|
|
||||||
|
All LCD stuff is untested. If it worked in tridentfb, it should work in
|
||||||
|
cyblafb. Please test and report the results to Knut_Petersen@t-online.de.
|
||||||
|
|
7
Documentation/fb/cyblafb/credits
Normal file
7
Documentation/fb/cyblafb/credits
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Thanks to
|
||||||
|
=========
|
||||||
|
* Alan Hourihane, for writing the X trident driver
|
||||||
|
* Jani Monoses, for writing the tridentfb driver
|
||||||
|
* Antonino A. Daplas, for review of the first published
|
||||||
|
version of cyblafb and some code
|
||||||
|
* Jochen Hein, for testing and a helpfull bug report
|
17
Documentation/fb/cyblafb/documentation
Normal file
17
Documentation/fb/cyblafb/documentation
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Available Documentation
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Apollo PLE 133 Chipset VT8601A North Bridge Datasheet, Rev. 1.82, October 22,
|
||||||
|
2001, available from VIA:
|
||||||
|
|
||||||
|
http://www.viavpsd.com/product/6/15/DS8601A182.pdf
|
||||||
|
|
||||||
|
The datasheet is incomplete, some registers that need to be programmed are not
|
||||||
|
explained at all and important bits are listed as "reserved". But you really
|
||||||
|
need the datasheet to understand the code. "p. xxx" comments refer to page
|
||||||
|
numbers of this document.
|
||||||
|
|
||||||
|
XFree/XOrg drivers are available and of good quality, looking at the code
|
||||||
|
there is a good idea if the datasheet does not provide enough information
|
||||||
|
or if the datasheet seems to be wrong.
|
||||||
|
|
155
Documentation/fb/cyblafb/fb.modes
Normal file
155
Documentation/fb/cyblafb/fb.modes
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
#
|
||||||
|
# Sample fb.modes file
|
||||||
|
#
|
||||||
|
# Provides an incomplete list of working modes for
|
||||||
|
# the cyberblade/i1 graphics core.
|
||||||
|
#
|
||||||
|
# The value 4294967256 is used instead of -40. Of course, -40 is not
|
||||||
|
# a really reasonable value, but chip design does not always follow
|
||||||
|
# logic. Believe me, it's ok, and it's the way the BIOS does it.
|
||||||
|
#
|
||||||
|
# fbset requires 4294967256 in fb.modes and -40 as an argument to
|
||||||
|
# the -t parameter. That's also not too reasonable, and it might change
|
||||||
|
# in the future or might even be differt for your current version.
|
||||||
|
#
|
||||||
|
|
||||||
|
mode "640x480-50"
|
||||||
|
geometry 640 480 640 3756 8
|
||||||
|
timings 47619 4294967256 24 17 0 216 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "640x480-60"
|
||||||
|
geometry 640 480 640 3756 8
|
||||||
|
timings 39682 4294967256 24 17 0 216 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "640x480-70"
|
||||||
|
geometry 640 480 640 3756 8
|
||||||
|
timings 34013 4294967256 24 17 0 216 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "640x480-72"
|
||||||
|
geometry 640 480 640 3756 8
|
||||||
|
timings 33068 4294967256 24 17 0 216 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "640x480-75"
|
||||||
|
geometry 640 480 640 3756 8
|
||||||
|
timings 31746 4294967256 24 17 0 216 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "640x480-80"
|
||||||
|
geometry 640 480 640 3756 8
|
||||||
|
timings 29761 4294967256 24 17 0 216 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "640x480-85"
|
||||||
|
geometry 640 480 640 3756 8
|
||||||
|
timings 28011 4294967256 24 17 0 216 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "800x600-50"
|
||||||
|
geometry 800 600 800 3221 8
|
||||||
|
timings 30303 96 24 14 0 136 11
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "800x600-60"
|
||||||
|
geometry 800 600 800 3221 8
|
||||||
|
timings 25252 96 24 14 0 136 11
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "800x600-70"
|
||||||
|
geometry 800 600 800 3221 8
|
||||||
|
timings 21645 96 24 14 0 136 11
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "800x600-72"
|
||||||
|
geometry 800 600 800 3221 8
|
||||||
|
timings 21043 96 24 14 0 136 11
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "800x600-75"
|
||||||
|
geometry 800 600 800 3221 8
|
||||||
|
timings 20202 96 24 14 0 136 11
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "800x600-80"
|
||||||
|
geometry 800 600 800 3221 8
|
||||||
|
timings 18939 96 24 14 0 136 11
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "800x600-85"
|
||||||
|
geometry 800 600 800 3221 8
|
||||||
|
timings 17825 96 24 14 0 136 11
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1024x768-50"
|
||||||
|
geometry 1024 768 1024 2815 8
|
||||||
|
timings 19054 144 24 29 0 120 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1024x768-60"
|
||||||
|
geometry 1024 768 1024 2815 8
|
||||||
|
timings 15880 144 24 29 0 120 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1024x768-70"
|
||||||
|
geometry 1024 768 1024 2815 8
|
||||||
|
timings 13610 144 24 29 0 120 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1024x768-72"
|
||||||
|
geometry 1024 768 1024 2815 8
|
||||||
|
timings 13232 144 24 29 0 120 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1024x768-75"
|
||||||
|
geometry 1024 768 1024 2815 8
|
||||||
|
timings 12703 144 24 29 0 120 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1024x768-80"
|
||||||
|
geometry 1024 768 1024 2815 8
|
||||||
|
timings 11910 144 24 29 0 120 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1024x768-85"
|
||||||
|
geometry 1024 768 1024 2815 8
|
||||||
|
timings 11209 144 24 29 0 120 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1280x1024-50"
|
||||||
|
geometry 1280 1024 1280 2662 8
|
||||||
|
timings 11114 232 16 39 0 160 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1280x1024-60"
|
||||||
|
geometry 1280 1024 1280 2662 8
|
||||||
|
timings 9262 232 16 39 0 160 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1280x1024-70"
|
||||||
|
geometry 1280 1024 1280 2662 8
|
||||||
|
timings 7939 232 16 39 0 160 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1280x1024-72"
|
||||||
|
geometry 1280 1024 1280 2662 8
|
||||||
|
timings 7719 232 16 39 0 160 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1280x1024-75"
|
||||||
|
geometry 1280 1024 1280 2662 8
|
||||||
|
timings 7410 232 16 39 0 160 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1280x1024-80"
|
||||||
|
geometry 1280 1024 1280 2662 8
|
||||||
|
timings 6946 232 16 39 0 160 3
|
||||||
|
endmode
|
||||||
|
|
||||||
|
mode "1280x1024-85"
|
||||||
|
geometry 1280 1024 1280 2662 8
|
||||||
|
timings 6538 232 16 39 0 160 3
|
||||||
|
endmode
|
||||||
|
|
80
Documentation/fb/cyblafb/performance
Normal file
80
Documentation/fb/cyblafb/performance
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
Speed
|
||||||
|
=====
|
||||||
|
|
||||||
|
CyBlaFB is much faster than tridentfb and vesafb. Compare the performance data
|
||||||
|
for mode 1280x1024-[8,16,32]@61 Hz.
|
||||||
|
|
||||||
|
Test 1: Cat a file with 2000 lines of 0 characters.
|
||||||
|
Test 2: Cat a file with 2000 lines of 80 characters.
|
||||||
|
Test 3: Cat a file with 2000 lines of 160 characters.
|
||||||
|
|
||||||
|
All values show system time use in seconds, kernel 2.6.12 was used for
|
||||||
|
the measurements. 2.6.13 is a bit slower, 2.6.14 hopefully will include a
|
||||||
|
patch that speeds up kernel bitblitting a lot ( > 20%).
|
||||||
|
|
||||||
|
+-----------+-----------------------------------------------------+
|
||||||
|
| | not accelerated |
|
||||||
|
| TRIDENTFB +-----------------+-----------------+-----------------+
|
||||||
|
| of 2.6.12 | 8 bpp | 16 bpp | 32 bpp |
|
||||||
|
| | noypan | ypan | noypan | ypan | noypan | ypan |
|
||||||
|
+-----------+--------+--------+--------+--------+--------+--------+
|
||||||
|
| Test 1 | 4.31 | 4.33 | 6.05 | 12.81 | ---- | ---- |
|
||||||
|
| Test 2 | 67.94 | 5.44 | 123.16 | 14.79 | ---- | ---- |
|
||||||
|
| Test 3 | 131.36 | 6.55 | 240.12 | 16.76 | ---- | ---- |
|
||||||
|
+-----------+--------+--------+--------+--------+--------+--------+
|
||||||
|
| Comments | | | completely bro- |
|
||||||
|
| | | | ken, monitor |
|
||||||
|
| | | | switches off |
|
||||||
|
+-----------+-----------------+-----------------+-----------------+
|
||||||
|
|
||||||
|
|
||||||
|
+-----------+-----------------------------------------------------+
|
||||||
|
| | accelerated |
|
||||||
|
| TRIDENTFB +-----------------+-----------------+-----------------+
|
||||||
|
| of 2.6.12 | 8 bpp | 16 bpp | 32 bpp |
|
||||||
|
| | noypan | ypan | noypan | ypan | noypan | ypan |
|
||||||
|
+-----------+--------+--------+--------+--------+--------+--------+
|
||||||
|
| Test 1 | ---- | ---- | 20.62 | 1.22 | ---- | ---- |
|
||||||
|
| Test 2 | ---- | ---- | 22.61 | 3.19 | ---- | ---- |
|
||||||
|
| Test 3 | ---- | ---- | 24.59 | 5.16 | ---- | ---- |
|
||||||
|
+-----------+--------+--------+--------+--------+--------+--------+
|
||||||
|
| Comments | broken, writing | broken, ok only | completely bro- |
|
||||||
|
| | to wrong places | if bgcolor is | ken, monitor |
|
||||||
|
| | on screen + bug | black, bug in | switches off |
|
||||||
|
| | in fillrect() | fillrect() | |
|
||||||
|
+-----------+-----------------+-----------------+-----------------+
|
||||||
|
|
||||||
|
|
||||||
|
+-----------+-----------------------------------------------------+
|
||||||
|
| | not accelerated |
|
||||||
|
| VESAFB +-----------------+-----------------+-----------------+
|
||||||
|
| of 2.6.12 | 8 bpp | 16 bpp | 32 bpp |
|
||||||
|
| | noypan | ypan | noypan | ypan | noypan | ypan |
|
||||||
|
+-----------+--------+--------+--------+--------+--------+--------+
|
||||||
|
| Test 1 | 4.26 | 3.76 | 5.99 | 7.23 | ---- | ---- |
|
||||||
|
| Test 2 | 65.65 | 4.89 | 120.88 | 9.08 | ---- | ---- |
|
||||||
|
| Test 3 | 126.91 | 5.94 | 235.77 | 11.03 | ---- | ---- |
|
||||||
|
+-----------+--------+--------+--------+--------+--------+--------+
|
||||||
|
| Comments | vga=0x307 | vga=0x31a | vga=0x31b not |
|
||||||
|
| | fh=80kHz | fh=80kHz | supported by |
|
||||||
|
| | fv=75kHz | fv=75kHz | video BIOS and |
|
||||||
|
| | | | hardware |
|
||||||
|
+-----------+-----------------+-----------------+-----------------+
|
||||||
|
|
||||||
|
|
||||||
|
+-----------+-----------------------------------------------------+
|
||||||
|
| | accelerated |
|
||||||
|
| CYBLAFB +-----------------+-----------------+-----------------+
|
||||||
|
| | 8 bpp | 16 bpp | 32 bpp |
|
||||||
|
| | noypan | ypan | noypan | ypan | noypan | ypan |
|
||||||
|
+-----------+--------+--------+--------+--------+--------+--------+
|
||||||
|
| Test 1 | 8.02 | 0.23 | 19.04 | 0.61 | 57.12 | 2.74 |
|
||||||
|
| Test 2 | 8.38 | 0.55 | 19.39 | 0.92 | 57.54 | 3.13 |
|
||||||
|
| Test 3 | 8.73 | 0.86 | 19.74 | 1.24 | 57.95 | 3.51 |
|
||||||
|
+-----------+--------+--------+--------+--------+--------+--------+
|
||||||
|
| Comments | | | |
|
||||||
|
| | | | |
|
||||||
|
| | | | |
|
||||||
|
| | | | |
|
||||||
|
+-----------+-----------------+-----------------+-----------------+
|
||||||
|
|
32
Documentation/fb/cyblafb/todo
Normal file
32
Documentation/fb/cyblafb/todo
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
TODO / Missing features
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Verify LCD stuff "stretch" and "center" options are
|
||||||
|
completely untested ... this code needs to be
|
||||||
|
verified. As I don't have access to such
|
||||||
|
hardware, please contact me if you are
|
||||||
|
willing run some tests.
|
||||||
|
|
||||||
|
Interlaced video modes The reason that interleaved
|
||||||
|
modes are disabled is that I do not know
|
||||||
|
the meaning of the vertical interlace
|
||||||
|
parameter. Also the datasheet mentions a
|
||||||
|
bit d8 of a horizontal interlace parameter,
|
||||||
|
but nowhere the lower 8 bits. Please help
|
||||||
|
if you can.
|
||||||
|
|
||||||
|
low-res double scan modes Who needs it?
|
||||||
|
|
||||||
|
accelerated color blitting Who needs it? The console driver does use color
|
||||||
|
blitting for nothing but drawing the penguine,
|
||||||
|
everything else is done using color expanding
|
||||||
|
blitting of 1bpp character bitmaps.
|
||||||
|
|
||||||
|
xpanning Who needs it?
|
||||||
|
|
||||||
|
ioctls Who needs it?
|
||||||
|
|
||||||
|
TV-out Will be done later
|
||||||
|
|
||||||
|
??? Feel free to contact me if you have any
|
||||||
|
feature requests
|
206
Documentation/fb/cyblafb/usage
Normal file
206
Documentation/fb/cyblafb/usage
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
CyBlaFB is a framebuffer driver for the Cyberblade/i1 graphics core integrated
|
||||||
|
into the VIA Apollo PLE133 (aka vt8601) south bridge. It is developed and
|
||||||
|
tested using a VIA EPIA 5000 board.
|
||||||
|
|
||||||
|
Cyblafb - compiled into the kernel or as a module?
|
||||||
|
==================================================
|
||||||
|
|
||||||
|
You might compile cyblafb either as a module or compile it permanently into the
|
||||||
|
kernel.
|
||||||
|
|
||||||
|
Unless you have a real reason to do so you should not compile both vesafb and
|
||||||
|
cyblafb permanently into the kernel. It's possible and it helps during the
|
||||||
|
developement cycle, but it's useless and will at least block some otherwise
|
||||||
|
usefull memory for ordinary users.
|
||||||
|
|
||||||
|
Selecting Modes
|
||||||
|
===============
|
||||||
|
|
||||||
|
Startup Mode
|
||||||
|
============
|
||||||
|
|
||||||
|
First of all, you might use the "vga=???" boot parameter as it is
|
||||||
|
documented in vesafb.txt and svga.txt. Cyblafb will detect the video
|
||||||
|
mode selected and will use the geometry and timings found by
|
||||||
|
inspecting the hardware registers.
|
||||||
|
|
||||||
|
video=cyblafb vga=0x317
|
||||||
|
|
||||||
|
Alternatively you might use a combination of the mode, ref and bpp
|
||||||
|
parameters. If you compiled the driver into the kernel, add something
|
||||||
|
like this to the kernel command line:
|
||||||
|
|
||||||
|
video=cyblafb:1280x1024,bpp=16,ref=50 ...
|
||||||
|
|
||||||
|
If you compiled the driver as a module, the same mode would be
|
||||||
|
selected by the following command:
|
||||||
|
|
||||||
|
modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
|
||||||
|
|
||||||
|
None of the modes possible to select as startup modes are affected by
|
||||||
|
the problems described at the end of the next subsection.
|
||||||
|
|
||||||
|
Mode changes using fbset
|
||||||
|
========================
|
||||||
|
|
||||||
|
You might use fbset to change the video mode, see "man fbset". Cyblafb
|
||||||
|
generally does assume that you know what you are doing. But it does
|
||||||
|
some checks, especially those that are needed to prevent you from
|
||||||
|
damaging your hardware.
|
||||||
|
|
||||||
|
- only 8, 16, 24 and 32 bpp video modes are accepted
|
||||||
|
- interlaced video modes are not accepted
|
||||||
|
- double scan video modes are not accepted
|
||||||
|
- if a flat panel is found, cyblafb does not allow you
|
||||||
|
to program a resolution higher than the physical
|
||||||
|
resolution of the flat panel monitor
|
||||||
|
- cyblafb does not allow xres to differ from xres_virtual
|
||||||
|
- cyblafb does not allow vclk to exceed 230 MHz. As 32 bpp
|
||||||
|
and (currently) 24 bit modes use a doubled vclk internally,
|
||||||
|
the dotclock limit as seen by fbset is 115 MHz for those
|
||||||
|
modes and 230 MHz for 8 and 16 bpp modes.
|
||||||
|
|
||||||
|
Any request that violates the rules given above will be ignored and
|
||||||
|
fbset will return an error.
|
||||||
|
|
||||||
|
If you program a virtual y resolution higher than the hardware limit,
|
||||||
|
cyblafb will silently decrease that value to the highest possible
|
||||||
|
value.
|
||||||
|
|
||||||
|
Attempts to disable acceleration are ignored.
|
||||||
|
|
||||||
|
Some video modes that should work do not work as expected. If you use
|
||||||
|
the standard fb.modes, fbset 640x480-60 will program that mode, but
|
||||||
|
you will see a vertical area, about two characters wide, with only
|
||||||
|
much darker characters than the other characters on the screen.
|
||||||
|
Cyblafb does allow that mode to be set, as it does not violate the
|
||||||
|
official specifications. It would need a lot of code to reliably sort
|
||||||
|
out all invalid modes, playing around with the margin values will
|
||||||
|
give a valid mode quickly. And if cyblafb would detect such an invalid
|
||||||
|
mode, should it silently alter the requested values or should it
|
||||||
|
report an error? Both options have some pros and cons. As stated
|
||||||
|
above, none of the startup modes are affected, and if you set
|
||||||
|
verbosity to 1 or higher, cyblafb will print the fbset command that
|
||||||
|
would be needed to program that mode using fbset.
|
||||||
|
|
||||||
|
|
||||||
|
Other Parameters
|
||||||
|
================
|
||||||
|
|
||||||
|
|
||||||
|
crt don't autodetect, assume monitor connected to
|
||||||
|
standard VGA connector
|
||||||
|
|
||||||
|
fp don't autodetect, assume flat panel display
|
||||||
|
connected to flat panel monitor interface
|
||||||
|
|
||||||
|
nativex inform driver about native x resolution of
|
||||||
|
flat panel monitor connected to special
|
||||||
|
interface (should be autodetected)
|
||||||
|
|
||||||
|
stretch stretch image to adapt low resolution modes to
|
||||||
|
higer resolutions of flat panel monitors
|
||||||
|
connected to special interface
|
||||||
|
|
||||||
|
center center image to adapt low resolution modes to
|
||||||
|
higer resolutions of flat panel monitors
|
||||||
|
connected to special interface
|
||||||
|
|
||||||
|
memsize use if autodetected memsize is wrong ...
|
||||||
|
should never be necessary
|
||||||
|
|
||||||
|
nopcirr disable PCI read retry
|
||||||
|
nopciwr disable PCI write retry
|
||||||
|
nopcirb disable PCI read bursts
|
||||||
|
nopciwb disable PCI write bursts
|
||||||
|
|
||||||
|
bpp bpp for specified modes
|
||||||
|
valid values: 8 || 16 || 24 || 32
|
||||||
|
|
||||||
|
ref refresh rate for specified mode
|
||||||
|
valid values: 50 <= ref <= 85
|
||||||
|
|
||||||
|
mode 640x480 or 800x600 or 1024x768 or 1280x1024
|
||||||
|
if not specified, the startup mode will be detected
|
||||||
|
and used, so you might also use the vga=??? parameter
|
||||||
|
described in vesafb.txt. If you do not specify a mode,
|
||||||
|
bpp and ref parameters are ignored.
|
||||||
|
|
||||||
|
verbosity 0 is the default, increase to at least 2 for every
|
||||||
|
bug report!
|
||||||
|
|
||||||
|
vesafb allows cyblafb to be loaded after vesafb has been
|
||||||
|
loaded. See sections "Module unloading ...".
|
||||||
|
|
||||||
|
|
||||||
|
Development hints
|
||||||
|
=================
|
||||||
|
|
||||||
|
It's much faster do compile a module and to load the new version after
|
||||||
|
unloading the old module than to compile a new kernel and to reboot. So if you
|
||||||
|
try to work on cyblafb, it might be a good idea to use cyblafb as a module.
|
||||||
|
In real life, fast often means dangerous, and that's also the case here. If
|
||||||
|
you introduce a serious bug when cyblafb is compiled into the kernel, the
|
||||||
|
kernel will lock or oops with a high probability before the file system is
|
||||||
|
mounted, and the danger for your data is low. If you load a broken own version
|
||||||
|
of cyblafb on a running system, the danger for the integrity of the file
|
||||||
|
system is much higher as you might need a hard reset afterwards. Decide
|
||||||
|
yourself.
|
||||||
|
|
||||||
|
Module unloading, the vfb method
|
||||||
|
================================
|
||||||
|
|
||||||
|
If you want to unload/reload cyblafb using the virtual framebuffer, you need
|
||||||
|
to enable vfb support in the kernel first. After that, load the modules as
|
||||||
|
shown below:
|
||||||
|
|
||||||
|
modprobe vfb vfb_enable=1
|
||||||
|
modprobe fbcon
|
||||||
|
modprobe cyblafb
|
||||||
|
fbset -fb /dev/fb1 1280x1024-60 -vyres 2662
|
||||||
|
con2fb /dev/fb1 /dev/tty1
|
||||||
|
...
|
||||||
|
|
||||||
|
If you now made some changes to cyblafb and want to reload it, you might do it
|
||||||
|
as show below:
|
||||||
|
|
||||||
|
con2fb /dev/fb0 /dev/tty1
|
||||||
|
...
|
||||||
|
rmmod cyblafb
|
||||||
|
modprobe cyblafb
|
||||||
|
con2fb /dev/fb1 /dev/tty1
|
||||||
|
...
|
||||||
|
|
||||||
|
Of course, you might choose another mode, and most certainly you also want to
|
||||||
|
map some other /dev/tty* to the real framebuffer device. You might also choose
|
||||||
|
to compile fbcon as a kernel module or place it permanently in the kernel.
|
||||||
|
|
||||||
|
I do not know of any way to unload fbcon, and fbcon will prevent the
|
||||||
|
framebuffer device loaded first from unloading. [If there is a way, then
|
||||||
|
please add a description here!]
|
||||||
|
|
||||||
|
Module unloading, the vesafb method
|
||||||
|
===================================
|
||||||
|
|
||||||
|
Configure the kernel:
|
||||||
|
|
||||||
|
<*> Support for frame buffer devices
|
||||||
|
[*] VESA VGA graphics support
|
||||||
|
<M> Cyberblade/i1 support
|
||||||
|
|
||||||
|
Add e.g. "video=vesafb:ypan vga=0x307" to the kernel parameters. The ypan
|
||||||
|
parameter is important, choose any vga parameter you like as long as it is
|
||||||
|
a graphics mode.
|
||||||
|
|
||||||
|
After booting, load cyblafb without any mode and bpp parameter and assign
|
||||||
|
cyblafb to individual ttys using con2fb, e.g.:
|
||||||
|
|
||||||
|
modprobe cyblafb vesafb=1
|
||||||
|
con2fb /dev/fb1 /dev/tty1
|
||||||
|
|
||||||
|
Unloading cyblafb works without problems after you assign vesafb to all
|
||||||
|
ttys again, e.g.:
|
||||||
|
|
||||||
|
con2fb /dev/fb0 /dev/tty1
|
||||||
|
rmmod cyblafb
|
||||||
|
|
85
Documentation/fb/cyblafb/whycyblafb
Normal file
85
Documentation/fb/cyblafb/whycyblafb
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
I tried the following framebuffer drivers:
|
||||||
|
|
||||||
|
- TRIDENTFB is full of bugs. Acceleration is broken for Blade3D
|
||||||
|
graphics cores like the cyberblade/i1. It claims to support a great
|
||||||
|
number of devices, but documentation for most of these devices is
|
||||||
|
unfortunately not available. There is _no_ reason to use tridentfb
|
||||||
|
for cyberblade/i1 + CRT users. VESAFB is faster, and the one
|
||||||
|
advantage, mode switching, is broken in tridentfb.
|
||||||
|
|
||||||
|
- VESAFB is used by many distributions as a standard. Vesafb does
|
||||||
|
not support mode switching. VESAFB is a bit faster than the working
|
||||||
|
configurations of TRIDENTFB, but it is still too slow, even if you
|
||||||
|
use ypan.
|
||||||
|
|
||||||
|
- EPIAFB (you'll find it on sourceforge) supports the Cyberblade/i1
|
||||||
|
graphics core, but it still has serious bugs and developement seems
|
||||||
|
to have stopped. This is the one driver with TV-out support. If you
|
||||||
|
do need this feature, try epiafb.
|
||||||
|
|
||||||
|
None of these drivers was a real option for me.
|
||||||
|
|
||||||
|
I believe that is unreasonable to change code that announces to support 20
|
||||||
|
devices if I only have more or less sufficient documentation for exactly one
|
||||||
|
of these. The risk of breaking device foo while fixing device bar is too high.
|
||||||
|
|
||||||
|
So I decided to start CyBlaFB as a stripped down tridentfb.
|
||||||
|
|
||||||
|
All code specific to other Trident chips has been removed. After that there
|
||||||
|
were a lot of cosmetic changes to increase the readability of the code. All
|
||||||
|
register names were changed to those mnemonics used in the datasheet. Function
|
||||||
|
and macro names were changed if they hindered easy understanding of the code.
|
||||||
|
|
||||||
|
After that I debugged the code and implemented some new features. I'll try to
|
||||||
|
give a little summary of the main changes:
|
||||||
|
|
||||||
|
- calculation of vertical and horizontal timings was fixed
|
||||||
|
|
||||||
|
- video signal quality has been improved dramatically
|
||||||
|
|
||||||
|
- acceleration:
|
||||||
|
|
||||||
|
- fillrect and copyarea were fixed and reenabled
|
||||||
|
|
||||||
|
- color expanding imageblit was newly implemented, color
|
||||||
|
imageblit (only used to draw the penguine) still uses the
|
||||||
|
generic code.
|
||||||
|
|
||||||
|
- init of the acceleration engine was improved and moved to a
|
||||||
|
place where it really works ...
|
||||||
|
|
||||||
|
- sync function has a timeout now and tries to reset and
|
||||||
|
reinit the accel engine if necessary
|
||||||
|
|
||||||
|
- fewer slow copyarea calls when doing ypan scrolling by using
|
||||||
|
undocumented bit d21 of screen start address stored in
|
||||||
|
CR2B[5]. BIOS does use it also, so this should be safe.
|
||||||
|
|
||||||
|
- cyblafb rejects any attempt to set modes that would cause vclk
|
||||||
|
values above reasonable 230 MHz. 32bit modes use a clock
|
||||||
|
multiplicator of 2, so fbset does show the correct values for
|
||||||
|
pixclock but not for vclk in this case. The fbset limit is 115 MHz
|
||||||
|
for 32 bpp modes.
|
||||||
|
|
||||||
|
- cyblafb rejects modes known to be broken or unimplemented (all
|
||||||
|
interlaced modes, all doublescan modes for now)
|
||||||
|
|
||||||
|
- cyblafb now works independant of the video mode in effect at startup
|
||||||
|
time (tridentfb does not init all needed registers to reasonable
|
||||||
|
values)
|
||||||
|
|
||||||
|
- switching between video modes does work reliably now
|
||||||
|
|
||||||
|
- the first video mode now is the one selected on startup using the
|
||||||
|
vga=???? mechanism or any of
|
||||||
|
- 640x480, 800x600, 1024x768, 1280x1024
|
||||||
|
- 8, 16, 24 or 32 bpp
|
||||||
|
- refresh between 50 Hz and 85 Hz, 1 Hz steps (1280x1024-32
|
||||||
|
is limited to 63Hz)
|
||||||
|
|
||||||
|
- pci retry and pci burst mode are settable (try to disable if you
|
||||||
|
experience latency problems)
|
||||||
|
|
||||||
|
- built as a module cyblafb might be unloaded and reloaded using
|
||||||
|
the vfb module and con2vt or might be used together with vesafb
|
||||||
|
|
@ -5,6 +5,7 @@ Intel 810/815 Framebuffer driver
|
|||||||
March 17, 2002
|
March 17, 2002
|
||||||
|
|
||||||
First Released: July 2001
|
First Released: July 2001
|
||||||
|
Last Update: September 12, 2005
|
||||||
================================================================
|
================================================================
|
||||||
|
|
||||||
A. Introduction
|
A. Introduction
|
||||||
@ -44,6 +45,8 @@ B. Features
|
|||||||
|
|
||||||
- Hardware Cursor Support
|
- Hardware Cursor Support
|
||||||
|
|
||||||
|
- Supports EDID probing either by DDC/I2C or through the BIOS
|
||||||
|
|
||||||
C. List of available options
|
C. List of available options
|
||||||
|
|
||||||
a. "video=i810fb"
|
a. "video=i810fb"
|
||||||
@ -52,14 +55,17 @@ C. List of available options
|
|||||||
Recommendation: required
|
Recommendation: required
|
||||||
|
|
||||||
b. "xres:<value>"
|
b. "xres:<value>"
|
||||||
select horizontal resolution in pixels
|
select horizontal resolution in pixels. (This parameter will be
|
||||||
|
ignored if 'mode_option' is specified. See 'o' below).
|
||||||
|
|
||||||
Recommendation: user preference
|
Recommendation: user preference
|
||||||
(default = 640)
|
(default = 640)
|
||||||
|
|
||||||
c. "yres:<value>"
|
c. "yres:<value>"
|
||||||
select vertical resolution in scanlines. If Discrete Video Timings
|
select vertical resolution in scanlines. If Discrete Video Timings
|
||||||
is enabled, this will be ignored and computed as 3*xres/4.
|
is enabled, this will be ignored and computed as 3*xres/4. (This
|
||||||
|
parameter will be ignored if 'mode_option' is specified. See 'o'
|
||||||
|
below)
|
||||||
|
|
||||||
Recommendation: user preference
|
Recommendation: user preference
|
||||||
(default = 480)
|
(default = 480)
|
||||||
@ -86,7 +92,8 @@ C. List of available options
|
|||||||
g. "hsync1/hsync2:<value>"
|
g. "hsync1/hsync2:<value>"
|
||||||
select the minimum and maximum Horizontal Sync Frequency of the
|
select the minimum and maximum Horizontal Sync Frequency of the
|
||||||
monitor in KHz. If a using a fixed frequency monitor, hsync1 must
|
monitor in KHz. If a using a fixed frequency monitor, hsync1 must
|
||||||
be equal to hsync2.
|
be equal to hsync2. If EDID probing is successful, these will be
|
||||||
|
ignored and values will be taken from the EDID block.
|
||||||
|
|
||||||
Recommendation: check monitor manual for correct values
|
Recommendation: check monitor manual for correct values
|
||||||
default (29/30)
|
default (29/30)
|
||||||
@ -94,7 +101,8 @@ C. List of available options
|
|||||||
h. "vsync1/vsync2:<value>"
|
h. "vsync1/vsync2:<value>"
|
||||||
select the minimum and maximum Vertical Sync Frequency of the monitor
|
select the minimum and maximum Vertical Sync Frequency of the monitor
|
||||||
in Hz. You can also use this option to lock your monitor's refresh
|
in Hz. You can also use this option to lock your monitor's refresh
|
||||||
rate.
|
rate. If EDID probing is successful, these will be ignored and values
|
||||||
|
will be taken from the EDID block.
|
||||||
|
|
||||||
Recommendation: check monitor manual for correct values
|
Recommendation: check monitor manual for correct values
|
||||||
(default = 60/60)
|
(default = 60/60)
|
||||||
@ -154,6 +162,10 @@ C. List of available options
|
|||||||
|
|
||||||
Recommendation: do not set
|
Recommendation: do not set
|
||||||
(default = not set)
|
(default = not set)
|
||||||
|
o. <xres>x<yres>[-<bpp>][@<refresh>]
|
||||||
|
The driver will now accept specification of boot mode option. If this
|
||||||
|
is specified, the options 'xres' and 'yres' will be ignored. See
|
||||||
|
Documentation/fb/modedb.txt for usage.
|
||||||
|
|
||||||
D. Kernel booting
|
D. Kernel booting
|
||||||
|
|
||||||
@ -176,7 +188,10 @@ will be computed based on the hsync1/hsync2 and vsync1/vsync2 values.
|
|||||||
|
|
||||||
IMPORTANT:
|
IMPORTANT:
|
||||||
You must include hsync1, hsync2, vsync1 and vsync2 to enable video modes
|
You must include hsync1, hsync2, vsync1 and vsync2 to enable video modes
|
||||||
better than 640x480 at 60Hz.
|
better than 640x480 at 60Hz. HOWEVER, if your chipset/display combination
|
||||||
|
supports I2C and has an EDID block, you can safely exclude hsync1, hsync2,
|
||||||
|
vsync1 and vsync2 parameters. These parameters will be taken from the EDID
|
||||||
|
block.
|
||||||
|
|
||||||
E. Module options
|
E. Module options
|
||||||
|
|
||||||
@ -217,31 +232,20 @@ F. Setup
|
|||||||
This is required. The option is under "Character Devices"
|
This is required. The option is under "Character Devices"
|
||||||
|
|
||||||
d. Under "Graphics Support", select "Intel 810/815" either statically
|
d. Under "Graphics Support", select "Intel 810/815" either statically
|
||||||
or as a module. Choose "use VESA GTF for video timings" if you
|
or as a module. Choose "use VESA Generalized Timing Formula" if
|
||||||
need to maximize the capability of your display. To be on the
|
you need to maximize the capability of your display. To be on the
|
||||||
safe side, you can leave this unselected.
|
safe side, you can leave this unselected.
|
||||||
|
|
||||||
e. If you want a framebuffer console, enable it under "Console
|
e. If you want support for DDC/I2C probing (Plug and Play Displays),
|
||||||
|
set 'Enable DDC Support' to 'y'. To make this option appear, set
|
||||||
|
'use VESA Generalized Timing Formula' to 'y'.
|
||||||
|
|
||||||
|
f. If you want a framebuffer console, enable it under "Console
|
||||||
Drivers"
|
Drivers"
|
||||||
|
|
||||||
f. Compile your kernel.
|
g. Compile your kernel.
|
||||||
|
|
||||||
g. Load the driver as described in section D and E.
|
h. Load the driver as described in section D and E.
|
||||||
|
|
||||||
Optional:
|
|
||||||
h. If you are going to run XFree86 with its native drivers, the
|
|
||||||
standard XFree86 4.1.0 and 4.2.0 drivers should work as is.
|
|
||||||
However, there's a bug in the XFree86 i810 drivers. It attempts
|
|
||||||
to use XAA even when switched to the console. This will crash
|
|
||||||
your server. I have a fix at this site:
|
|
||||||
|
|
||||||
http://i810fb.sourceforge.net.
|
|
||||||
|
|
||||||
You can either use the patch, or just replace
|
|
||||||
|
|
||||||
/usr/X11R6/lib/modules/drivers/i810_drv.o
|
|
||||||
|
|
||||||
with the one provided at the website.
|
|
||||||
|
|
||||||
i. Try the DirectFB (http://www.directfb.org) + the i810 gfxdriver
|
i. Try the DirectFB (http://www.directfb.org) + the i810 gfxdriver
|
||||||
patch to see the chipset in action (or inaction :-).
|
patch to see the chipset in action (or inaction :-).
|
||||||
|
@ -20,12 +20,83 @@ in a video= option, fbmem considers that to be a global video mode option.
|
|||||||
|
|
||||||
Valid mode specifiers (mode_option argument):
|
Valid mode specifiers (mode_option argument):
|
||||||
|
|
||||||
<xres>x<yres>[-<bpp>][@<refresh>]
|
<xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m]
|
||||||
<name>[-<bpp>][@<refresh>]
|
<name>[-<bpp>][@<refresh>]
|
||||||
|
|
||||||
with <xres>, <yres>, <bpp> and <refresh> decimal numbers and <name> a string.
|
with <xres>, <yres>, <bpp> and <refresh> decimal numbers and <name> a string.
|
||||||
Things between square brackets are optional.
|
Things between square brackets are optional.
|
||||||
|
|
||||||
|
If 'M' is specified in the mode_option argument (after <yres> and before
|
||||||
|
<bpp> and <refresh>, if specified) the timings will be calculated using
|
||||||
|
VESA(TM) Coordinated Video Timings instead of looking up the mode from a table.
|
||||||
|
If 'R' is specified, do a 'reduced blanking' calculation for digital displays.
|
||||||
|
If 'i' is specified, calculate for an interlaced mode. And if 'm' is
|
||||||
|
specified, add margins to the calculation (1.8% of xres rounded down to 8
|
||||||
|
pixels and 1.8% of yres).
|
||||||
|
|
||||||
|
Sample usage: 1024x768M@60m - CVT timing with margins
|
||||||
|
|
||||||
|
***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo *****
|
||||||
|
|
||||||
|
What is the VESA(TM) Coordinated Video Timings (CVT)?
|
||||||
|
|
||||||
|
From the VESA(TM) Website:
|
||||||
|
|
||||||
|
"The purpose of CVT is to provide a method for generating a consistent
|
||||||
|
and coordinated set of standard formats, display refresh rates, and
|
||||||
|
timing specifications for computer display products, both those
|
||||||
|
employing CRTs, and those using other display technologies. The
|
||||||
|
intention of CVT is to give both source and display manufacturers a
|
||||||
|
common set of tools to enable new timings to be developed in a
|
||||||
|
consistent manner that ensures greater compatibility."
|
||||||
|
|
||||||
|
This is the third standard approved by VESA(TM) concerning video timings. The
|
||||||
|
first was the Discrete Video Timings (DVT) which is a collection of
|
||||||
|
pre-defined modes approved by VESA(TM). The second is the Generalized Timing
|
||||||
|
Formula (GTF) which is an algorithm to calculate the timings, given the
|
||||||
|
pixelclock, the horizontal sync frequency, or the vertical refresh rate.
|
||||||
|
|
||||||
|
The GTF is limited by the fact that it is designed mainly for CRT displays.
|
||||||
|
It artificially increases the pixelclock because of its high blanking
|
||||||
|
requirement. This is inappropriate for digital display interface with its high
|
||||||
|
data rate which requires that it conserves the pixelclock as much as possible.
|
||||||
|
Also, GTF does not take into account the aspect ratio of the display.
|
||||||
|
|
||||||
|
The CVT addresses these limitations. If used with CRT's, the formula used
|
||||||
|
is a derivation of GTF with a few modifications. If used with digital
|
||||||
|
displays, the "reduced blanking" calculation can be used.
|
||||||
|
|
||||||
|
From the framebuffer subsystem perspective, new formats need not be added
|
||||||
|
to the global mode database whenever a new mode is released by display
|
||||||
|
manufacturers. Specifying for CVT will work for most, if not all, relatively
|
||||||
|
new CRT displays and probably with most flatpanels, if 'reduced blanking'
|
||||||
|
calculation is specified. (The CVT compatibility of the display can be
|
||||||
|
determined from its EDID. The version 1.3 of the EDID has extra 128-byte
|
||||||
|
blocks where additional timing information is placed. As of this time, there
|
||||||
|
is no support yet in the layer to parse this additional blocks.)
|
||||||
|
|
||||||
|
CVT also introduced a new naming convention (should be seen from dmesg output):
|
||||||
|
|
||||||
|
<pix>M<a>[-R]
|
||||||
|
|
||||||
|
where: pix = total amount of pixels in MB (xres x yres)
|
||||||
|
M = always present
|
||||||
|
a = aspect ratio (3 - 4:3; 4 - 5:4; 9 - 15:9, 16:9; A - 16:10)
|
||||||
|
-R = reduced blanking
|
||||||
|
|
||||||
|
example: .48M3-R - 800x600 with reduced blanking
|
||||||
|
|
||||||
|
Note: VESA(TM) has restrictions on what is a standard CVT timing:
|
||||||
|
|
||||||
|
- aspect ratio can only be one of the above values
|
||||||
|
- acceptable refresh rates are 50, 60, 70 or 85 Hz only
|
||||||
|
- if reduced blanking, the refresh rate must be at 60Hz
|
||||||
|
|
||||||
|
If one of the above are not satisfied, the kernel will print a warning but the
|
||||||
|
timings will still be calculated.
|
||||||
|
|
||||||
|
***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo *****
|
||||||
|
|
||||||
To find a suitable video mode, you just call
|
To find a suitable video mode, you just call
|
||||||
|
|
||||||
int __init fb_find_mode(struct fb_var_screeninfo *var,
|
int __init fb_find_mode(struct fb_var_screeninfo *var,
|
||||||
|
@ -17,14 +17,6 @@ Who: Greg Kroah-Hartman <greg@kroah.com>
|
|||||||
|
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
What: ACPI S4bios support
|
|
||||||
When: May 2005
|
|
||||||
Why: Noone uses it, and it probably does not work, anyway. swsusp is
|
|
||||||
faster, more reliable, and people are actually using it.
|
|
||||||
Who: Pavel Machek <pavel@suse.cz>
|
|
||||||
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
What: io_remap_page_range() (macro or function)
|
What: io_remap_page_range() (macro or function)
|
||||||
When: September 2005
|
When: September 2005
|
||||||
Why: Replaced by io_remap_pfn_range() which allows more memory space
|
Why: Replaced by io_remap_pfn_range() which allows more memory space
|
||||||
|
123
Documentation/filesystems/files.txt
Normal file
123
Documentation/filesystems/files.txt
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
File management in the Linux kernel
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
This document describes how locking for files (struct file)
|
||||||
|
and file descriptor table (struct files) works.
|
||||||
|
|
||||||
|
Up until 2.6.12, the file descriptor table has been protected
|
||||||
|
with a lock (files->file_lock) and reference count (files->count).
|
||||||
|
->file_lock protected accesses to all the file related fields
|
||||||
|
of the table. ->count was used for sharing the file descriptor
|
||||||
|
table between tasks cloned with CLONE_FILES flag. Typically
|
||||||
|
this would be the case for posix threads. As with the common
|
||||||
|
refcounting model in the kernel, the last task doing
|
||||||
|
a put_files_struct() frees the file descriptor (fd) table.
|
||||||
|
The files (struct file) themselves are protected using
|
||||||
|
reference count (->f_count).
|
||||||
|
|
||||||
|
In the new lock-free model of file descriptor management,
|
||||||
|
the reference counting is similar, but the locking is
|
||||||
|
based on RCU. The file descriptor table contains multiple
|
||||||
|
elements - the fd sets (open_fds and close_on_exec, the
|
||||||
|
array of file pointers, the sizes of the sets and the array
|
||||||
|
etc.). In order for the updates to appear atomic to
|
||||||
|
a lock-free reader, all the elements of the file descriptor
|
||||||
|
table are in a separate structure - struct fdtable.
|
||||||
|
files_struct contains a pointer to struct fdtable through
|
||||||
|
which the actual fd table is accessed. Initially the
|
||||||
|
fdtable is embedded in files_struct itself. On a subsequent
|
||||||
|
expansion of fdtable, a new fdtable structure is allocated
|
||||||
|
and files->fdtab points to the new structure. The fdtable
|
||||||
|
structure is freed with RCU and lock-free readers either
|
||||||
|
see the old fdtable or the new fdtable making the update
|
||||||
|
appear atomic. Here are the locking rules for
|
||||||
|
the fdtable structure -
|
||||||
|
|
||||||
|
1. All references to the fdtable must be done through
|
||||||
|
the files_fdtable() macro :
|
||||||
|
|
||||||
|
struct fdtable *fdt;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
|
||||||
|
fdt = files_fdtable(files);
|
||||||
|
....
|
||||||
|
if (n <= fdt->max_fds)
|
||||||
|
....
|
||||||
|
...
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
files_fdtable() uses rcu_dereference() macro which takes care of
|
||||||
|
the memory barrier requirements for lock-free dereference.
|
||||||
|
The fdtable pointer must be read within the read-side
|
||||||
|
critical section.
|
||||||
|
|
||||||
|
2. Reading of the fdtable as described above must be protected
|
||||||
|
by rcu_read_lock()/rcu_read_unlock().
|
||||||
|
|
||||||
|
3. For any update to the the fd table, files->file_lock must
|
||||||
|
be held.
|
||||||
|
|
||||||
|
4. To look up the file structure given an fd, a reader
|
||||||
|
must use either fcheck() or fcheck_files() APIs. These
|
||||||
|
take care of barrier requirements due to lock-free lookup.
|
||||||
|
An example :
|
||||||
|
|
||||||
|
struct file *file;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
file = fcheck(fd);
|
||||||
|
if (file) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
....
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
5. Handling of the file structures is special. Since the look-up
|
||||||
|
of the fd (fget()/fget_light()) are lock-free, it is possible
|
||||||
|
that look-up may race with the last put() operation on the
|
||||||
|
file structure. This is avoided using the rcuref APIs
|
||||||
|
on ->f_count :
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
file = fcheck_files(files, fd);
|
||||||
|
if (file) {
|
||||||
|
if (rcuref_inc_lf(&file->f_count))
|
||||||
|
*fput_needed = 1;
|
||||||
|
else
|
||||||
|
/* Didn't get the reference, someone's freed */
|
||||||
|
file = NULL;
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
....
|
||||||
|
return file;
|
||||||
|
|
||||||
|
rcuref_inc_lf() detects if refcounts is already zero or
|
||||||
|
goes to zero during increment. If it does, we fail
|
||||||
|
fget()/fget_light().
|
||||||
|
|
||||||
|
6. Since both fdtable and file structures can be looked up
|
||||||
|
lock-free, they must be installed using rcu_assign_pointer()
|
||||||
|
API. If they are looked up lock-free, rcu_dereference()
|
||||||
|
must be used. However it is advisable to use files_fdtable()
|
||||||
|
and fcheck()/fcheck_files() which take care of these issues.
|
||||||
|
|
||||||
|
7. While updating, the fdtable pointer must be looked up while
|
||||||
|
holding files->file_lock. If ->file_lock is dropped, then
|
||||||
|
another thread expand the files thereby creating a new
|
||||||
|
fdtable and making the earlier fdtable pointer stale.
|
||||||
|
For example :
|
||||||
|
|
||||||
|
spin_lock(&files->file_lock);
|
||||||
|
fd = locate_fd(files, file, start);
|
||||||
|
if (fd >= 0) {
|
||||||
|
/* locate_fd() may have expanded fdtable, load the ptr */
|
||||||
|
fdt = files_fdtable(files);
|
||||||
|
FD_SET(fd, fdt->open_fds);
|
||||||
|
FD_CLR(fd, fdt->close_on_exec);
|
||||||
|
spin_unlock(&files->file_lock);
|
||||||
|
.....
|
||||||
|
|
||||||
|
Since locate_fd() can drop ->file_lock (and reacquire ->file_lock),
|
||||||
|
the fdtable pointer (fdt) must be loaded after locate_fd().
|
||||||
|
|
315
Documentation/filesystems/fuse.txt
Normal file
315
Documentation/filesystems/fuse.txt
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
Definitions
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
Userspace filesystem:
|
||||||
|
|
||||||
|
A filesystem in which data and metadata are provided by an ordinary
|
||||||
|
userspace process. The filesystem can be accessed normally through
|
||||||
|
the kernel interface.
|
||||||
|
|
||||||
|
Filesystem daemon:
|
||||||
|
|
||||||
|
The process(es) providing the data and metadata of the filesystem.
|
||||||
|
|
||||||
|
Non-privileged mount (or user mount):
|
||||||
|
|
||||||
|
A userspace filesystem mounted by a non-privileged (non-root) user.
|
||||||
|
The filesystem daemon is running with the privileges of the mounting
|
||||||
|
user. NOTE: this is not the same as mounts allowed with the "user"
|
||||||
|
option in /etc/fstab, which is not discussed here.
|
||||||
|
|
||||||
|
Mount owner:
|
||||||
|
|
||||||
|
The user who does the mounting.
|
||||||
|
|
||||||
|
User:
|
||||||
|
|
||||||
|
The user who is performing filesystem operations.
|
||||||
|
|
||||||
|
What is FUSE?
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
FUSE is a userspace filesystem framework. It consists of a kernel
|
||||||
|
module (fuse.ko), a userspace library (libfuse.*) and a mount utility
|
||||||
|
(fusermount).
|
||||||
|
|
||||||
|
One of the most important features of FUSE is allowing secure,
|
||||||
|
non-privileged mounts. This opens up new possibilities for the use of
|
||||||
|
filesystems. A good example is sshfs: a secure network filesystem
|
||||||
|
using the sftp protocol.
|
||||||
|
|
||||||
|
The userspace library and utilities are available from the FUSE
|
||||||
|
homepage:
|
||||||
|
|
||||||
|
http://fuse.sourceforge.net/
|
||||||
|
|
||||||
|
Mount options
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
'fd=N'
|
||||||
|
|
||||||
|
The file descriptor to use for communication between the userspace
|
||||||
|
filesystem and the kernel. The file descriptor must have been
|
||||||
|
obtained by opening the FUSE device ('/dev/fuse').
|
||||||
|
|
||||||
|
'rootmode=M'
|
||||||
|
|
||||||
|
The file mode of the filesystem's root in octal representation.
|
||||||
|
|
||||||
|
'user_id=N'
|
||||||
|
|
||||||
|
The numeric user id of the mount owner.
|
||||||
|
|
||||||
|
'group_id=N'
|
||||||
|
|
||||||
|
The numeric group id of the mount owner.
|
||||||
|
|
||||||
|
'default_permissions'
|
||||||
|
|
||||||
|
By default FUSE doesn't check file access permissions, the
|
||||||
|
filesystem is free to implement it's access policy or leave it to
|
||||||
|
the underlying file access mechanism (e.g. in case of network
|
||||||
|
filesystems). This option enables permission checking, restricting
|
||||||
|
access based on file mode. This is option is usually useful
|
||||||
|
together with the 'allow_other' mount option.
|
||||||
|
|
||||||
|
'allow_other'
|
||||||
|
|
||||||
|
This option overrides the security measure restricting file access
|
||||||
|
to the user mounting the filesystem. This option is by default only
|
||||||
|
allowed to root, but this restriction can be removed with a
|
||||||
|
(userspace) configuration option.
|
||||||
|
|
||||||
|
'max_read=N'
|
||||||
|
|
||||||
|
With this option the maximum size of read operations can be set.
|
||||||
|
The default is infinite. Note that the size of read requests is
|
||||||
|
limited anyway to 32 pages (which is 128kbyte on i386).
|
||||||
|
|
||||||
|
How do non-privileged mounts work?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Since the mount() system call is a privileged operation, a helper
|
||||||
|
program (fusermount) is needed, which is installed setuid root.
|
||||||
|
|
||||||
|
The implication of providing non-privileged mounts is that the mount
|
||||||
|
owner must not be able to use this capability to compromise the
|
||||||
|
system. Obvious requirements arising from this are:
|
||||||
|
|
||||||
|
A) mount owner should not be able to get elevated privileges with the
|
||||||
|
help of the mounted filesystem
|
||||||
|
|
||||||
|
B) mount owner should not get illegitimate access to information from
|
||||||
|
other users' and the super user's processes
|
||||||
|
|
||||||
|
C) mount owner should not be able to induce undesired behavior in
|
||||||
|
other users' or the super user's processes
|
||||||
|
|
||||||
|
How are requirements fulfilled?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
A) The mount owner could gain elevated privileges by either:
|
||||||
|
|
||||||
|
1) creating a filesystem containing a device file, then opening
|
||||||
|
this device
|
||||||
|
|
||||||
|
2) creating a filesystem containing a suid or sgid application,
|
||||||
|
then executing this application
|
||||||
|
|
||||||
|
The solution is not to allow opening device files and ignore
|
||||||
|
setuid and setgid bits when executing programs. To ensure this
|
||||||
|
fusermount always adds "nosuid" and "nodev" to the mount options
|
||||||
|
for non-privileged mounts.
|
||||||
|
|
||||||
|
B) If another user is accessing files or directories in the
|
||||||
|
filesystem, the filesystem daemon serving requests can record the
|
||||||
|
exact sequence and timing of operations performed. This
|
||||||
|
information is otherwise inaccessible to the mount owner, so this
|
||||||
|
counts as an information leak.
|
||||||
|
|
||||||
|
The solution to this problem will be presented in point 2) of C).
|
||||||
|
|
||||||
|
C) There are several ways in which the mount owner can induce
|
||||||
|
undesired behavior in other users' processes, such as:
|
||||||
|
|
||||||
|
1) mounting a filesystem over a file or directory which the mount
|
||||||
|
owner could otherwise not be able to modify (or could only
|
||||||
|
make limited modifications).
|
||||||
|
|
||||||
|
This is solved in fusermount, by checking the access
|
||||||
|
permissions on the mountpoint and only allowing the mount if
|
||||||
|
the mount owner can do unlimited modification (has write
|
||||||
|
access to the mountpoint, and mountpoint is not a "sticky"
|
||||||
|
directory)
|
||||||
|
|
||||||
|
2) Even if 1) is solved the mount owner can change the behavior
|
||||||
|
of other users' processes.
|
||||||
|
|
||||||
|
i) It can slow down or indefinitely delay the execution of a
|
||||||
|
filesystem operation creating a DoS against the user or the
|
||||||
|
whole system. For example a suid application locking a
|
||||||
|
system file, and then accessing a file on the mount owner's
|
||||||
|
filesystem could be stopped, and thus causing the system
|
||||||
|
file to be locked forever.
|
||||||
|
|
||||||
|
ii) It can present files or directories of unlimited length, or
|
||||||
|
directory structures of unlimited depth, possibly causing a
|
||||||
|
system process to eat up diskspace, memory or other
|
||||||
|
resources, again causing DoS.
|
||||||
|
|
||||||
|
The solution to this as well as B) is not to allow processes
|
||||||
|
to access the filesystem, which could otherwise not be
|
||||||
|
monitored or manipulated by the mount owner. Since if the
|
||||||
|
mount owner can ptrace a process, it can do all of the above
|
||||||
|
without using a FUSE mount, the same criteria as used in
|
||||||
|
ptrace can be used to check if a process is allowed to access
|
||||||
|
the filesystem or not.
|
||||||
|
|
||||||
|
Note that the ptrace check is not strictly necessary to
|
||||||
|
prevent B/2/i, it is enough to check if mount owner has enough
|
||||||
|
privilege to send signal to the process accessing the
|
||||||
|
filesystem, since SIGSTOP can be used to get a similar effect.
|
||||||
|
|
||||||
|
I think these limitations are unacceptable?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
If a sysadmin trusts the users enough, or can ensure through other
|
||||||
|
measures, that system processes will never enter non-privileged
|
||||||
|
mounts, it can relax the last limitation with a "user_allow_other"
|
||||||
|
config option. If this config option is set, the mounting user can
|
||||||
|
add the "allow_other" mount option which disables the check for other
|
||||||
|
users' processes.
|
||||||
|
|
||||||
|
Kernel - userspace interface
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The following diagram shows how a filesystem operation (in this
|
||||||
|
example unlink) is performed in FUSE.
|
||||||
|
|
||||||
|
NOTE: everything in this description is greatly simplified
|
||||||
|
|
||||||
|
| "rm /mnt/fuse/file" | FUSE filesystem daemon
|
||||||
|
| |
|
||||||
|
| | >sys_read()
|
||||||
|
| | >fuse_dev_read()
|
||||||
|
| | >request_wait()
|
||||||
|
| | [sleep on fc->waitq]
|
||||||
|
| |
|
||||||
|
| >sys_unlink() |
|
||||||
|
| >fuse_unlink() |
|
||||||
|
| [get request from |
|
||||||
|
| fc->unused_list] |
|
||||||
|
| >request_send() |
|
||||||
|
| [queue req on fc->pending] |
|
||||||
|
| [wake up fc->waitq] | [woken up]
|
||||||
|
| >request_wait_answer() |
|
||||||
|
| [sleep on req->waitq] |
|
||||||
|
| | <request_wait()
|
||||||
|
| | [remove req from fc->pending]
|
||||||
|
| | [copy req to read buffer]
|
||||||
|
| | [add req to fc->processing]
|
||||||
|
| | <fuse_dev_read()
|
||||||
|
| | <sys_read()
|
||||||
|
| |
|
||||||
|
| | [perform unlink]
|
||||||
|
| |
|
||||||
|
| | >sys_write()
|
||||||
|
| | >fuse_dev_write()
|
||||||
|
| | [look up req in fc->processing]
|
||||||
|
| | [remove from fc->processing]
|
||||||
|
| | [copy write buffer to req]
|
||||||
|
| [woken up] | [wake up req->waitq]
|
||||||
|
| | <fuse_dev_write()
|
||||||
|
| | <sys_write()
|
||||||
|
| <request_wait_answer() |
|
||||||
|
| <request_send() |
|
||||||
|
| [add request to |
|
||||||
|
| fc->unused_list] |
|
||||||
|
| <fuse_unlink() |
|
||||||
|
| <sys_unlink() |
|
||||||
|
|
||||||
|
There are a couple of ways in which to deadlock a FUSE filesystem.
|
||||||
|
Since we are talking about unprivileged userspace programs,
|
||||||
|
something must be done about these.
|
||||||
|
|
||||||
|
Scenario 1 - Simple deadlock
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
| "rm /mnt/fuse/file" | FUSE filesystem daemon
|
||||||
|
| |
|
||||||
|
| >sys_unlink("/mnt/fuse/file") |
|
||||||
|
| [acquire inode semaphore |
|
||||||
|
| for "file"] |
|
||||||
|
| >fuse_unlink() |
|
||||||
|
| [sleep on req->waitq] |
|
||||||
|
| | <sys_read()
|
||||||
|
| | >sys_unlink("/mnt/fuse/file")
|
||||||
|
| | [acquire inode semaphore
|
||||||
|
| | for "file"]
|
||||||
|
| | *DEADLOCK*
|
||||||
|
|
||||||
|
The solution for this is to allow requests to be interrupted while
|
||||||
|
they are in userspace:
|
||||||
|
|
||||||
|
| [interrupted by signal] |
|
||||||
|
| <fuse_unlink() |
|
||||||
|
| [release semaphore] | [semaphore acquired]
|
||||||
|
| <sys_unlink() |
|
||||||
|
| | >fuse_unlink()
|
||||||
|
| | [queue req on fc->pending]
|
||||||
|
| | [wake up fc->waitq]
|
||||||
|
| | [sleep on req->waitq]
|
||||||
|
|
||||||
|
If the filesystem daemon was single threaded, this will stop here,
|
||||||
|
since there's no other thread to dequeue and execute the request.
|
||||||
|
In this case the solution is to kill the FUSE daemon as well. If
|
||||||
|
there are multiple serving threads, you just have to kill them as
|
||||||
|
long as any remain.
|
||||||
|
|
||||||
|
Moral: a filesystem which deadlocks, can soon find itself dead.
|
||||||
|
|
||||||
|
Scenario 2 - Tricky deadlock
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
This one needs a carefully crafted filesystem. It's a variation on
|
||||||
|
the above, only the call back to the filesystem is not explicit,
|
||||||
|
but is caused by a pagefault.
|
||||||
|
|
||||||
|
| Kamikaze filesystem thread 1 | Kamikaze filesystem thread 2
|
||||||
|
| |
|
||||||
|
| [fd = open("/mnt/fuse/file")] | [request served normally]
|
||||||
|
| [mmap fd to 'addr'] |
|
||||||
|
| [close fd] | [FLUSH triggers 'magic' flag]
|
||||||
|
| [read a byte from addr] |
|
||||||
|
| >do_page_fault() |
|
||||||
|
| [find or create page] |
|
||||||
|
| [lock page] |
|
||||||
|
| >fuse_readpage() |
|
||||||
|
| [queue READ request] |
|
||||||
|
| [sleep on req->waitq] |
|
||||||
|
| | [read request to buffer]
|
||||||
|
| | [create reply header before addr]
|
||||||
|
| | >sys_write(addr - headerlength)
|
||||||
|
| | >fuse_dev_write()
|
||||||
|
| | [look up req in fc->processing]
|
||||||
|
| | [remove from fc->processing]
|
||||||
|
| | [copy write buffer to req]
|
||||||
|
| | >do_page_fault()
|
||||||
|
| | [find or create page]
|
||||||
|
| | [lock page]
|
||||||
|
| | * DEADLOCK *
|
||||||
|
|
||||||
|
Solution is again to let the the request be interrupted (not
|
||||||
|
elaborated further).
|
||||||
|
|
||||||
|
An additional problem is that while the write buffer is being
|
||||||
|
copied to the request, the request must not be interrupted. This
|
||||||
|
is because the destination address of the copy may not be valid
|
||||||
|
after the request is interrupted.
|
||||||
|
|
||||||
|
This is solved with doing the copy atomically, and allowing
|
||||||
|
interruption while the page(s) belonging to the write buffer are
|
||||||
|
faulted with get_user_pages(). The 'req->locked' flag indicates
|
||||||
|
when the copy is taking place, and interruption is delayed until
|
||||||
|
this flag is unset.
|
||||||
|
|
@ -1241,16 +1241,38 @@ swap-intensive.
|
|||||||
overcommit_memory
|
overcommit_memory
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
This file contains one value. The following algorithm is used to decide if
|
Controls overcommit of system memory, possibly allowing processes
|
||||||
there's enough memory: if the value of overcommit_memory is positive, then
|
to allocate (but not use) more memory than is actually available.
|
||||||
there's always enough memory. This is a useful feature, since programs often
|
|
||||||
malloc() huge amounts of memory 'just in case', while they only use a small
|
|
||||||
part of it. Leaving this value at 0 will lead to the failure of such a huge
|
|
||||||
malloc(), when in fact the system has enough memory for the program to run.
|
|
||||||
|
|
||||||
On the other hand, enabling this feature can cause you to run out of memory
|
|
||||||
and thrash the system to death, so large and/or important servers will want to
|
0 - Heuristic overcommit handling. Obvious overcommits of
|
||||||
set this value to 0.
|
address space are refused. Used for a typical system. It
|
||||||
|
ensures a seriously wild allocation fails while allowing
|
||||||
|
overcommit to reduce swap usage. root is allowed to
|
||||||
|
allocate slighly more memory in this mode. This is the
|
||||||
|
default.
|
||||||
|
|
||||||
|
1 - Always overcommit. Appropriate for some scientific
|
||||||
|
applications.
|
||||||
|
|
||||||
|
2 - Don't overcommit. The total address space commit
|
||||||
|
for the system is not permitted to exceed swap plus a
|
||||||
|
configurable percentage (default is 50) of physical RAM.
|
||||||
|
Depending on the percentage you use, in most situations
|
||||||
|
this means a process will not be killed while attempting
|
||||||
|
to use already-allocated memory but will receive errors
|
||||||
|
on memory allocation as appropriate.
|
||||||
|
|
||||||
|
overcommit_ratio
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Percentage of physical memory size to include in overcommit calculations
|
||||||
|
(see above.)
|
||||||
|
|
||||||
|
Memory allocation limit = swapspace + physmem * (overcommit_ratio / 100)
|
||||||
|
|
||||||
|
swapspace = total size of all swap areas
|
||||||
|
physmem = size of physical memory in system
|
||||||
|
|
||||||
nr_hugepages and hugetlb_shm_group
|
nr_hugepages and hugetlb_shm_group
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
95
Documentation/filesystems/v9fs.txt
Normal file
95
Documentation/filesystems/v9fs.txt
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
V9FS: 9P2000 for Linux
|
||||||
|
======================
|
||||||
|
|
||||||
|
ABOUT
|
||||||
|
=====
|
||||||
|
|
||||||
|
v9fs is a Unix implementation of the Plan 9 9p remote filesystem protocol.
|
||||||
|
|
||||||
|
This software was originally developed by Ron Minnich <rminnich@lanl.gov>
|
||||||
|
and Maya Gokhale <maya@lanl.gov>. Additional development by Greg Watson
|
||||||
|
<gwatson@lanl.gov> and most recently Eric Van Hensbergen
|
||||||
|
<ericvh@gmail.com> and Latchesar Ionkov <lucho@ionkov.net>.
|
||||||
|
|
||||||
|
USAGE
|
||||||
|
=====
|
||||||
|
|
||||||
|
For remote file server:
|
||||||
|
|
||||||
|
mount -t 9P 10.10.1.2 /mnt/9
|
||||||
|
|
||||||
|
For Plan 9 From User Space applications (http://swtch.com/plan9)
|
||||||
|
|
||||||
|
mount -t 9P `namespace`/acme /mnt/9 -o proto=unix,name=$USER
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
=======
|
||||||
|
|
||||||
|
proto=name select an alternative transport. Valid options are
|
||||||
|
currently:
|
||||||
|
unix - specifying a named pipe mount point
|
||||||
|
tcp - specifying a normal TCP/IP connection
|
||||||
|
fd - used passed file descriptors for connection
|
||||||
|
(see rfdno and wfdno)
|
||||||
|
|
||||||
|
name=name user name to attempt mount as on the remote server. The
|
||||||
|
server may override or ignore this value. Certain user
|
||||||
|
names may require authentication.
|
||||||
|
|
||||||
|
aname=name aname specifies the file tree to access when the server is
|
||||||
|
offering several exported file systems.
|
||||||
|
|
||||||
|
debug=n specifies debug level. The debug level is a bitmask.
|
||||||
|
0x01 = display verbose error messages
|
||||||
|
0x02 = developer debug (DEBUG_CURRENT)
|
||||||
|
0x04 = display 9P trace
|
||||||
|
0x08 = display VFS trace
|
||||||
|
0x10 = display Marshalling debug
|
||||||
|
0x20 = display RPC debug
|
||||||
|
0x40 = display transport debug
|
||||||
|
0x80 = display allocation debug
|
||||||
|
|
||||||
|
rfdno=n the file descriptor for reading with proto=fd
|
||||||
|
|
||||||
|
wfdno=n the file descriptor for writing with proto=fd
|
||||||
|
|
||||||
|
maxdata=n the number of bytes to use for 9P packet payload (msize)
|
||||||
|
|
||||||
|
port=n port to connect to on the remote server
|
||||||
|
|
||||||
|
timeout=n request timeouts (in ms) (default 60000ms)
|
||||||
|
|
||||||
|
noextend force legacy mode (no 9P2000.u semantics)
|
||||||
|
|
||||||
|
uid attempt to mount as a particular uid
|
||||||
|
|
||||||
|
gid attempt to mount with a particular gid
|
||||||
|
|
||||||
|
afid security channel - used by Plan 9 authentication protocols
|
||||||
|
|
||||||
|
nodevmap do not map special files - represent them as normal files.
|
||||||
|
This can be used to share devices/named pipes/sockets between
|
||||||
|
hosts. This functionality will be expanded in later versions.
|
||||||
|
|
||||||
|
RESOURCES
|
||||||
|
=========
|
||||||
|
|
||||||
|
The Linux version of the 9P server, along with some client-side utilities
|
||||||
|
can be found at http://v9fs.sf.net (along with a CVS repository of the
|
||||||
|
development branch of this module). There are user and developer mailing
|
||||||
|
lists here, as well as a bug-tracker.
|
||||||
|
|
||||||
|
For more information on the Plan 9 Operating System check out
|
||||||
|
http://plan9.bell-labs.com/plan9
|
||||||
|
|
||||||
|
For information on Plan 9 from User Space (Plan 9 applications and libraries
|
||||||
|
ported to Linux/BSD/OSX/etc) check out http://swtch.com/plan9
|
||||||
|
|
||||||
|
|
||||||
|
STATUS
|
||||||
|
======
|
||||||
|
|
||||||
|
The 2.6 kernel support is working on PPC and x86.
|
||||||
|
|
||||||
|
PLEASE USE THE SOURCEFORGE BUG-TRACKER TO REPORT PROBLEMS.
|
||||||
|
|
@ -1,35 +1,27 @@
|
|||||||
/* -*- auto-fill -*- */
|
|
||||||
|
|
||||||
Overview of the Virtual File System
|
Overview of the Linux Virtual File System
|
||||||
|
|
||||||
Richard Gooch <rgooch@atnf.csiro.au>
|
Original author: Richard Gooch <rgooch@atnf.csiro.au>
|
||||||
|
|
||||||
5-JUL-1999
|
Last updated on August 25, 2005
|
||||||
|
|
||||||
|
Copyright (C) 1999 Richard Gooch
|
||||||
|
Copyright (C) 2005 Pekka Enberg
|
||||||
|
|
||||||
|
This file is released under the GPLv2.
|
||||||
|
|
||||||
|
|
||||||
Conventions used in this document <section>
|
What is it?
|
||||||
=================================
|
|
||||||
|
|
||||||
Each section in this document will have the string "<section>" at the
|
|
||||||
right-hand side of the section title. Each subsection will have
|
|
||||||
"<subsection>" at the right-hand side. These strings are meant to make
|
|
||||||
it easier to search through the document.
|
|
||||||
|
|
||||||
NOTE that the master copy of this document is available online at:
|
|
||||||
http://www.atnf.csiro.au/~rgooch/linux/docs/vfs.txt
|
|
||||||
|
|
||||||
|
|
||||||
What is it? <section>
|
|
||||||
===========
|
===========
|
||||||
|
|
||||||
The Virtual File System (otherwise known as the Virtual Filesystem
|
The Virtual File System (otherwise known as the Virtual Filesystem
|
||||||
Switch) is the software layer in the kernel that provides the
|
Switch) is the software layer in the kernel that provides the
|
||||||
filesystem interface to userspace programs. It also provides an
|
filesystem interface to userspace programs. It also provides an
|
||||||
abstraction within the kernel which allows different filesystem
|
abstraction within the kernel which allows different filesystem
|
||||||
implementations to co-exist.
|
implementations to coexist.
|
||||||
|
|
||||||
|
|
||||||
A Quick Look At How It Works <section>
|
A Quick Look At How It Works
|
||||||
============================
|
============================
|
||||||
|
|
||||||
In this section I'll briefly describe how things work, before
|
In this section I'll briefly describe how things work, before
|
||||||
@ -38,7 +30,8 @@ when user programs open and manipulate files, and then look from the
|
|||||||
other view which is how a filesystem is supported and subsequently
|
other view which is how a filesystem is supported and subsequently
|
||||||
mounted.
|
mounted.
|
||||||
|
|
||||||
Opening a File <subsection>
|
|
||||||
|
Opening a File
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
The VFS implements the open(2), stat(2), chmod(2) and similar system
|
The VFS implements the open(2), stat(2), chmod(2) and similar system
|
||||||
@ -77,7 +70,7 @@ back to userspace.
|
|||||||
|
|
||||||
Opening a file requires another operation: allocation of a file
|
Opening a file requires another operation: allocation of a file
|
||||||
structure (this is the kernel-side implementation of file
|
structure (this is the kernel-side implementation of file
|
||||||
descriptors). The freshly allocated file structure is initialised with
|
descriptors). The freshly allocated file structure is initialized with
|
||||||
a pointer to the dentry and a set of file operation member functions.
|
a pointer to the dentry and a set of file operation member functions.
|
||||||
These are taken from the inode data. The open() file method is then
|
These are taken from the inode data. The open() file method is then
|
||||||
called so the specific filesystem implementation can do it's work. You
|
called so the specific filesystem implementation can do it's work. You
|
||||||
@ -102,7 +95,8 @@ filesystem or driver code at the same time, on different
|
|||||||
processors. You should ensure that access to shared resources is
|
processors. You should ensure that access to shared resources is
|
||||||
protected by appropriate locks.
|
protected by appropriate locks.
|
||||||
|
|
||||||
Registering and Mounting a Filesystem <subsection>
|
|
||||||
|
Registering and Mounting a Filesystem
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
If you want to support a new kind of filesystem in the kernel, all you
|
If you want to support a new kind of filesystem in the kernel, all you
|
||||||
@ -123,17 +117,21 @@ updated to point to the root inode for the new filesystem.
|
|||||||
It's now time to look at things in more detail.
|
It's now time to look at things in more detail.
|
||||||
|
|
||||||
|
|
||||||
struct file_system_type <section>
|
struct file_system_type
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
This describes the filesystem. As of kernel 2.1.99, the following
|
This describes the filesystem. As of kernel 2.6.13, the following
|
||||||
members are defined:
|
members are defined:
|
||||||
|
|
||||||
struct file_system_type {
|
struct file_system_type {
|
||||||
const char *name;
|
const char *name;
|
||||||
int fs_flags;
|
int fs_flags;
|
||||||
struct super_block *(*read_super) (struct super_block *, void *, int);
|
struct super_block *(*get_sb) (struct file_system_type *, int,
|
||||||
|
const char *, void *);
|
||||||
|
void (*kill_sb) (struct super_block *);
|
||||||
|
struct module *owner;
|
||||||
struct file_system_type * next;
|
struct file_system_type * next;
|
||||||
|
struct list_head fs_supers;
|
||||||
};
|
};
|
||||||
|
|
||||||
name: the name of the filesystem type, such as "ext2", "iso9660",
|
name: the name of the filesystem type, such as "ext2", "iso9660",
|
||||||
@ -141,51 +139,97 @@ struct file_system_type {
|
|||||||
|
|
||||||
fs_flags: various flags (i.e. FS_REQUIRES_DEV, FS_NO_DCACHE, etc.)
|
fs_flags: various flags (i.e. FS_REQUIRES_DEV, FS_NO_DCACHE, etc.)
|
||||||
|
|
||||||
read_super: the method to call when a new instance of this
|
get_sb: the method to call when a new instance of this
|
||||||
filesystem should be mounted
|
filesystem should be mounted
|
||||||
|
|
||||||
next: for internal VFS use: you should initialise this to NULL
|
kill_sb: the method to call when an instance of this filesystem
|
||||||
|
should be unmounted
|
||||||
|
|
||||||
The read_super() method has the following arguments:
|
owner: for internal VFS use: you should initialize this to THIS_MODULE in
|
||||||
|
most cases.
|
||||||
|
|
||||||
|
next: for internal VFS use: you should initialize this to NULL
|
||||||
|
|
||||||
|
The get_sb() method has the following arguments:
|
||||||
|
|
||||||
struct super_block *sb: the superblock structure. This is partially
|
struct super_block *sb: the superblock structure. This is partially
|
||||||
initialised by the VFS and the rest must be initialised by the
|
initialized by the VFS and the rest must be initialized by the
|
||||||
read_super() method
|
get_sb() method
|
||||||
|
|
||||||
|
int flags: mount flags
|
||||||
|
|
||||||
|
const char *dev_name: the device name we are mounting.
|
||||||
|
|
||||||
void *data: arbitrary mount options, usually comes as an ASCII
|
void *data: arbitrary mount options, usually comes as an ASCII
|
||||||
string
|
string
|
||||||
|
|
||||||
int silent: whether or not to be silent on error
|
int silent: whether or not to be silent on error
|
||||||
|
|
||||||
The read_super() method must determine if the block device specified
|
The get_sb() method must determine if the block device specified
|
||||||
in the superblock contains a filesystem of the type the method
|
in the superblock contains a filesystem of the type the method
|
||||||
supports. On success the method returns the superblock pointer, on
|
supports. On success the method returns the superblock pointer, on
|
||||||
failure it returns NULL.
|
failure it returns NULL.
|
||||||
|
|
||||||
The most interesting member of the superblock structure that the
|
The most interesting member of the superblock structure that the
|
||||||
read_super() method fills in is the "s_op" field. This is a pointer to
|
get_sb() method fills in is the "s_op" field. This is a pointer to
|
||||||
a "struct super_operations" which describes the next level of the
|
a "struct super_operations" which describes the next level of the
|
||||||
filesystem implementation.
|
filesystem implementation.
|
||||||
|
|
||||||
|
Usually, a filesystem uses generic one of the generic get_sb()
|
||||||
|
implementations and provides a fill_super() method instead. The
|
||||||
|
generic methods are:
|
||||||
|
|
||||||
struct super_operations <section>
|
get_sb_bdev: mount a filesystem residing on a block device
|
||||||
|
|
||||||
|
get_sb_nodev: mount a filesystem that is not backed by a device
|
||||||
|
|
||||||
|
get_sb_single: mount a filesystem which shares the instance between
|
||||||
|
all mounts
|
||||||
|
|
||||||
|
A fill_super() method implementation has the following arguments:
|
||||||
|
|
||||||
|
struct super_block *sb: the superblock structure. The method fill_super()
|
||||||
|
must initialize this properly.
|
||||||
|
|
||||||
|
void *data: arbitrary mount options, usually comes as an ASCII
|
||||||
|
string
|
||||||
|
|
||||||
|
int silent: whether or not to be silent on error
|
||||||
|
|
||||||
|
|
||||||
|
struct super_operations
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
This describes how the VFS can manipulate the superblock of your
|
This describes how the VFS can manipulate the superblock of your
|
||||||
filesystem. As of kernel 2.1.99, the following members are defined:
|
filesystem. As of kernel 2.6.13, the following members are defined:
|
||||||
|
|
||||||
struct super_operations {
|
struct super_operations {
|
||||||
|
struct inode *(*alloc_inode)(struct super_block *sb);
|
||||||
|
void (*destroy_inode)(struct inode *);
|
||||||
|
|
||||||
void (*read_inode) (struct inode *);
|
void (*read_inode) (struct inode *);
|
||||||
|
|
||||||
|
void (*dirty_inode) (struct inode *);
|
||||||
int (*write_inode) (struct inode *, int);
|
int (*write_inode) (struct inode *, int);
|
||||||
void (*put_inode) (struct inode *);
|
void (*put_inode) (struct inode *);
|
||||||
void (*drop_inode) (struct inode *);
|
void (*drop_inode) (struct inode *);
|
||||||
void (*delete_inode) (struct inode *);
|
void (*delete_inode) (struct inode *);
|
||||||
int (*notify_change) (struct dentry *, struct iattr *);
|
|
||||||
void (*put_super) (struct super_block *);
|
void (*put_super) (struct super_block *);
|
||||||
void (*write_super) (struct super_block *);
|
void (*write_super) (struct super_block *);
|
||||||
int (*statfs) (struct super_block *, struct statfs *, int);
|
int (*sync_fs)(struct super_block *sb, int wait);
|
||||||
|
void (*write_super_lockfs) (struct super_block *);
|
||||||
|
void (*unlockfs) (struct super_block *);
|
||||||
|
int (*statfs) (struct super_block *, struct kstatfs *);
|
||||||
int (*remount_fs) (struct super_block *, int *, char *);
|
int (*remount_fs) (struct super_block *, int *, char *);
|
||||||
void (*clear_inode) (struct inode *);
|
void (*clear_inode) (struct inode *);
|
||||||
|
void (*umount_begin) (struct super_block *);
|
||||||
|
|
||||||
|
void (*sync_inodes) (struct super_block *sb,
|
||||||
|
struct writeback_control *wbc);
|
||||||
|
int (*show_options)(struct seq_file *, struct vfsmount *);
|
||||||
|
|
||||||
|
ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
|
||||||
|
ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
|
||||||
};
|
};
|
||||||
|
|
||||||
All methods are called without any locks being held, unless otherwise
|
All methods are called without any locks being held, unless otherwise
|
||||||
@ -193,43 +237,62 @@ noted. This means that most methods can block safely. All methods are
|
|||||||
only called from a process context (i.e. not from an interrupt handler
|
only called from a process context (i.e. not from an interrupt handler
|
||||||
or bottom half).
|
or bottom half).
|
||||||
|
|
||||||
|
alloc_inode: this method is called by inode_alloc() to allocate memory
|
||||||
|
for struct inode and initialize it.
|
||||||
|
|
||||||
|
destroy_inode: this method is called by destroy_inode() to release
|
||||||
|
resources allocated for struct inode.
|
||||||
|
|
||||||
read_inode: this method is called to read a specific inode from the
|
read_inode: this method is called to read a specific inode from the
|
||||||
mounted filesystem. The "i_ino" member in the "struct inode"
|
mounted filesystem. The i_ino member in the struct inode is
|
||||||
will be initialised by the VFS to indicate which inode to
|
initialized by the VFS to indicate which inode to read. Other
|
||||||
read. Other members are filled in by this method
|
members are filled in by this method.
|
||||||
|
|
||||||
|
You can set this to NULL and use iget5_locked() instead of iget()
|
||||||
|
to read inodes. This is necessary for filesystems for which the
|
||||||
|
inode number is not sufficient to identify an inode.
|
||||||
|
|
||||||
|
dirty_inode: this method is called by the VFS to mark an inode dirty.
|
||||||
|
|
||||||
write_inode: this method is called when the VFS needs to write an
|
write_inode: this method is called when the VFS needs to write an
|
||||||
inode to disc. The second parameter indicates whether the write
|
inode to disc. The second parameter indicates whether the write
|
||||||
should be synchronous or not, not all filesystems check this flag.
|
should be synchronous or not, not all filesystems check this flag.
|
||||||
|
|
||||||
put_inode: called when the VFS inode is removed from the inode
|
put_inode: called when the VFS inode is removed from the inode
|
||||||
cache. This method is optional
|
cache.
|
||||||
|
|
||||||
drop_inode: called when the last access to the inode is dropped,
|
drop_inode: called when the last access to the inode is dropped,
|
||||||
with the inode_lock spinlock held.
|
with the inode_lock spinlock held.
|
||||||
|
|
||||||
This method should be either NULL (normal unix filesystem
|
This method should be either NULL (normal UNIX filesystem
|
||||||
semantics) or "generic_delete_inode" (for filesystems that do not
|
semantics) or "generic_delete_inode" (for filesystems that do not
|
||||||
want to cache inodes - causing "delete_inode" to always be
|
want to cache inodes - causing "delete_inode" to always be
|
||||||
called regardless of the value of i_nlink)
|
called regardless of the value of i_nlink)
|
||||||
|
|
||||||
The "generic_delete_inode()" behaviour is equivalent to the
|
The "generic_delete_inode()" behavior is equivalent to the
|
||||||
old practice of using "force_delete" in the put_inode() case,
|
old practice of using "force_delete" in the put_inode() case,
|
||||||
but does not have the races that the "force_delete()" approach
|
but does not have the races that the "force_delete()" approach
|
||||||
had.
|
had.
|
||||||
|
|
||||||
delete_inode: called when the VFS wants to delete an inode
|
delete_inode: called when the VFS wants to delete an inode
|
||||||
|
|
||||||
notify_change: called when VFS inode attributes are changed. If this
|
|
||||||
is NULL the VFS falls back to the write_inode() method. This
|
|
||||||
is called with the kernel lock held
|
|
||||||
|
|
||||||
put_super: called when the VFS wishes to free the superblock
|
put_super: called when the VFS wishes to free the superblock
|
||||||
(i.e. unmount). This is called with the superblock lock held
|
(i.e. unmount). This is called with the superblock lock held
|
||||||
|
|
||||||
write_super: called when the VFS superblock needs to be written to
|
write_super: called when the VFS superblock needs to be written to
|
||||||
disc. This method is optional
|
disc. This method is optional
|
||||||
|
|
||||||
|
sync_fs: called when VFS is writing out all dirty data associated with
|
||||||
|
a superblock. The second parameter indicates whether the method
|
||||||
|
should wait until the write out has been completed. Optional.
|
||||||
|
|
||||||
|
write_super_lockfs: called when VFS is locking a filesystem and forcing
|
||||||
|
it into a consistent state. This function is currently used by the
|
||||||
|
Logical Volume Manager (LVM).
|
||||||
|
|
||||||
|
unlockfs: called when VFS is unlocking a filesystem and making it writable
|
||||||
|
again.
|
||||||
|
|
||||||
statfs: called when the VFS needs to get filesystem statistics. This
|
statfs: called when the VFS needs to get filesystem statistics. This
|
||||||
is called with the kernel lock held
|
is called with the kernel lock held
|
||||||
|
|
||||||
@ -238,21 +301,31 @@ or bottom half).
|
|||||||
|
|
||||||
clear_inode: called then the VFS clears the inode. Optional
|
clear_inode: called then the VFS clears the inode. Optional
|
||||||
|
|
||||||
|
umount_begin: called when the VFS is unmounting a filesystem.
|
||||||
|
|
||||||
|
sync_inodes: called when the VFS is writing out dirty data associated with
|
||||||
|
a superblock.
|
||||||
|
|
||||||
|
show_options: called by the VFS to show mount options for /proc/<pid>/mounts.
|
||||||
|
|
||||||
|
quota_read: called by the VFS to read from filesystem quota file.
|
||||||
|
|
||||||
|
quota_write: called by the VFS to write to filesystem quota file.
|
||||||
|
|
||||||
The read_inode() method is responsible for filling in the "i_op"
|
The read_inode() method is responsible for filling in the "i_op"
|
||||||
field. This is a pointer to a "struct inode_operations" which
|
field. This is a pointer to a "struct inode_operations" which
|
||||||
describes the methods that can be performed on individual inodes.
|
describes the methods that can be performed on individual inodes.
|
||||||
|
|
||||||
|
|
||||||
struct inode_operations <section>
|
struct inode_operations
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
This describes how the VFS can manipulate an inode in your
|
This describes how the VFS can manipulate an inode in your
|
||||||
filesystem. As of kernel 2.1.99, the following members are defined:
|
filesystem. As of kernel 2.6.13, the following members are defined:
|
||||||
|
|
||||||
struct inode_operations {
|
struct inode_operations {
|
||||||
struct file_operations * default_file_ops;
|
int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
|
||||||
int (*create) (struct inode *,struct dentry *,int);
|
struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
|
||||||
int (*lookup) (struct inode *,struct dentry *);
|
|
||||||
int (*link) (struct dentry *,struct inode *,struct dentry *);
|
int (*link) (struct dentry *,struct inode *,struct dentry *);
|
||||||
int (*unlink) (struct inode *,struct dentry *);
|
int (*unlink) (struct inode *,struct dentry *);
|
||||||
int (*symlink) (struct inode *,struct dentry *,const char *);
|
int (*symlink) (struct inode *,struct dentry *,const char *);
|
||||||
@ -261,25 +334,22 @@ struct inode_operations {
|
|||||||
int (*mknod) (struct inode *,struct dentry *,int,dev_t);
|
int (*mknod) (struct inode *,struct dentry *,int,dev_t);
|
||||||
int (*rename) (struct inode *, struct dentry *,
|
int (*rename) (struct inode *, struct dentry *,
|
||||||
struct inode *, struct dentry *);
|
struct inode *, struct dentry *);
|
||||||
int (*readlink) (struct dentry *, char *,int);
|
int (*readlink) (struct dentry *, char __user *,int);
|
||||||
struct dentry * (*follow_link) (struct dentry *, struct dentry *);
|
void * (*follow_link) (struct dentry *, struct nameidata *);
|
||||||
int (*readpage) (struct file *, struct page *);
|
void (*put_link) (struct dentry *, struct nameidata *, void *);
|
||||||
int (*writepage) (struct page *page, struct writeback_control *wbc);
|
|
||||||
int (*bmap) (struct inode *,int);
|
|
||||||
void (*truncate) (struct inode *);
|
void (*truncate) (struct inode *);
|
||||||
int (*permission) (struct inode *, int);
|
int (*permission) (struct inode *, int, struct nameidata *);
|
||||||
int (*smap) (struct inode *,int);
|
int (*setattr) (struct dentry *, struct iattr *);
|
||||||
int (*updatepage) (struct file *, struct page *, const char *,
|
int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
|
||||||
unsigned long, unsigned int, int);
|
int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
|
||||||
int (*revalidate) (struct dentry *);
|
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
|
||||||
|
ssize_t (*listxattr) (struct dentry *, char *, size_t);
|
||||||
|
int (*removexattr) (struct dentry *, const char *);
|
||||||
};
|
};
|
||||||
|
|
||||||
Again, all methods are called without any locks being held, unless
|
Again, all methods are called without any locks being held, unless
|
||||||
otherwise noted.
|
otherwise noted.
|
||||||
|
|
||||||
default_file_ops: this is a pointer to a "struct file_operations"
|
|
||||||
which describes how to open and then manipulate open files
|
|
||||||
|
|
||||||
create: called by the open(2) and creat(2) system calls. Only
|
create: called by the open(2) and creat(2) system calls. Only
|
||||||
required if you want to support regular files. The dentry you
|
required if you want to support regular files. The dentry you
|
||||||
get should not have an inode (i.e. it should be a negative
|
get should not have an inode (i.e. it should be a negative
|
||||||
@ -329,30 +399,142 @@ otherwise noted.
|
|||||||
|
|
||||||
follow_link: called by the VFS to follow a symbolic link to the
|
follow_link: called by the VFS to follow a symbolic link to the
|
||||||
inode it points to. Only required if you want to support
|
inode it points to. Only required if you want to support
|
||||||
symbolic links
|
symbolic links. This function returns a void pointer cookie
|
||||||
|
that is passed to put_link().
|
||||||
|
|
||||||
|
put_link: called by the VFS to release resources allocated by
|
||||||
|
follow_link(). The cookie returned by follow_link() is passed to
|
||||||
|
to this function as the last parameter. It is used by filesystems
|
||||||
|
such as NFS where page cache is not stable (i.e. page that was
|
||||||
|
installed when the symbolic link walk started might not be in the
|
||||||
|
page cache at the end of the walk).
|
||||||
|
|
||||||
|
truncate: called by the VFS to change the size of a file. The i_size
|
||||||
|
field of the inode is set to the desired size by the VFS before
|
||||||
|
this function is called. This function is called by the truncate(2)
|
||||||
|
system call and related functionality.
|
||||||
|
|
||||||
|
permission: called by the VFS to check for access rights on a POSIX-like
|
||||||
|
filesystem.
|
||||||
|
|
||||||
|
setattr: called by the VFS to set attributes for a file. This function is
|
||||||
|
called by chmod(2) and related system calls.
|
||||||
|
|
||||||
|
getattr: called by the VFS to get attributes of a file. This function is
|
||||||
|
called by stat(2) and related system calls.
|
||||||
|
|
||||||
|
setxattr: called by the VFS to set an extended attribute for a file.
|
||||||
|
Extended attribute is a name:value pair associated with an inode. This
|
||||||
|
function is called by setxattr(2) system call.
|
||||||
|
|
||||||
|
getxattr: called by the VFS to retrieve the value of an extended attribute
|
||||||
|
name. This function is called by getxattr(2) function call.
|
||||||
|
|
||||||
|
listxattr: called by the VFS to list all extended attributes for a given
|
||||||
|
file. This function is called by listxattr(2) system call.
|
||||||
|
|
||||||
|
removexattr: called by the VFS to remove an extended attribute from a file.
|
||||||
|
This function is called by removexattr(2) system call.
|
||||||
|
|
||||||
|
|
||||||
struct file_operations <section>
|
struct address_space_operations
|
||||||
|
===============================
|
||||||
|
|
||||||
|
This describes how the VFS can manipulate mapping of a file to page cache in
|
||||||
|
your filesystem. As of kernel 2.6.13, the following members are defined:
|
||||||
|
|
||||||
|
struct address_space_operations {
|
||||||
|
int (*writepage)(struct page *page, struct writeback_control *wbc);
|
||||||
|
int (*readpage)(struct file *, struct page *);
|
||||||
|
int (*sync_page)(struct page *);
|
||||||
|
int (*writepages)(struct address_space *, struct writeback_control *);
|
||||||
|
int (*set_page_dirty)(struct page *page);
|
||||||
|
int (*readpages)(struct file *filp, struct address_space *mapping,
|
||||||
|
struct list_head *pages, unsigned nr_pages);
|
||||||
|
int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
|
||||||
|
int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
|
||||||
|
sector_t (*bmap)(struct address_space *, sector_t);
|
||||||
|
int (*invalidatepage) (struct page *, unsigned long);
|
||||||
|
int (*releasepage) (struct page *, int);
|
||||||
|
ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
|
||||||
|
loff_t offset, unsigned long nr_segs);
|
||||||
|
struct page* (*get_xip_page)(struct address_space *, sector_t,
|
||||||
|
int);
|
||||||
|
};
|
||||||
|
|
||||||
|
writepage: called by the VM write a dirty page to backing store.
|
||||||
|
|
||||||
|
readpage: called by the VM to read a page from backing store.
|
||||||
|
|
||||||
|
sync_page: called by the VM to notify the backing store to perform all
|
||||||
|
queued I/O operations for a page. I/O operations for other pages
|
||||||
|
associated with this address_space object may also be performed.
|
||||||
|
|
||||||
|
writepages: called by the VM to write out pages associated with the
|
||||||
|
address_space object.
|
||||||
|
|
||||||
|
set_page_dirty: called by the VM to set a page dirty.
|
||||||
|
|
||||||
|
readpages: called by the VM to read pages associated with the address_space
|
||||||
|
object.
|
||||||
|
|
||||||
|
prepare_write: called by the generic write path in VM to set up a write
|
||||||
|
request for a page.
|
||||||
|
|
||||||
|
commit_write: called by the generic write path in VM to write page to
|
||||||
|
its backing store.
|
||||||
|
|
||||||
|
bmap: called by the VFS to map a logical block offset within object to
|
||||||
|
physical block number. This method is use by for the legacy FIBMAP
|
||||||
|
ioctl. Other uses are discouraged.
|
||||||
|
|
||||||
|
invalidatepage: called by the VM on truncate to disassociate a page from its
|
||||||
|
address_space mapping.
|
||||||
|
|
||||||
|
releasepage: called by the VFS to release filesystem specific metadata from
|
||||||
|
a page.
|
||||||
|
|
||||||
|
direct_IO: called by the VM for direct I/O writes and reads.
|
||||||
|
|
||||||
|
get_xip_page: called by the VM to translate a block number to a page.
|
||||||
|
The page is valid until the corresponding filesystem is unmounted.
|
||||||
|
Filesystems that want to use execute-in-place (XIP) need to implement
|
||||||
|
it. An example implementation can be found in fs/ext2/xip.c.
|
||||||
|
|
||||||
|
|
||||||
|
struct file_operations
|
||||||
======================
|
======================
|
||||||
|
|
||||||
This describes how the VFS can manipulate an open file. As of kernel
|
This describes how the VFS can manipulate an open file. As of kernel
|
||||||
2.1.99, the following members are defined:
|
2.6.13, the following members are defined:
|
||||||
|
|
||||||
struct file_operations {
|
struct file_operations {
|
||||||
loff_t (*llseek) (struct file *, loff_t, int);
|
loff_t (*llseek) (struct file *, loff_t, int);
|
||||||
ssize_t (*read) (struct file *, char *, size_t, loff_t *);
|
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
|
||||||
ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
|
ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
|
||||||
|
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
|
||||||
|
ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
|
||||||
int (*readdir) (struct file *, void *, filldir_t);
|
int (*readdir) (struct file *, void *, filldir_t);
|
||||||
unsigned int (*poll) (struct file *, struct poll_table_struct *);
|
unsigned int (*poll) (struct file *, struct poll_table_struct *);
|
||||||
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
|
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
|
||||||
|
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
|
||||||
|
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
|
||||||
int (*mmap) (struct file *, struct vm_area_struct *);
|
int (*mmap) (struct file *, struct vm_area_struct *);
|
||||||
int (*open) (struct inode *, struct file *);
|
int (*open) (struct inode *, struct file *);
|
||||||
|
int (*flush) (struct file *);
|
||||||
int (*release) (struct inode *, struct file *);
|
int (*release) (struct inode *, struct file *);
|
||||||
int (*fsync) (struct file *, struct dentry *);
|
int (*fsync) (struct file *, struct dentry *, int datasync);
|
||||||
int (*fasync) (struct file *, int);
|
int (*aio_fsync) (struct kiocb *, int datasync);
|
||||||
int (*check_media_change) (kdev_t dev);
|
int (*fasync) (int, struct file *, int);
|
||||||
int (*revalidate) (kdev_t dev);
|
|
||||||
int (*lock) (struct file *, int, struct file_lock *);
|
int (*lock) (struct file *, int, struct file_lock *);
|
||||||
|
ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
|
||||||
|
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
|
||||||
|
ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
|
||||||
|
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
|
||||||
|
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
|
||||||
|
int (*check_flags)(int);
|
||||||
|
int (*dir_notify)(struct file *filp, unsigned long arg);
|
||||||
|
int (*flock) (struct file *, int, struct file_lock *);
|
||||||
};
|
};
|
||||||
|
|
||||||
Again, all methods are called without any locks being held, unless
|
Again, all methods are called without any locks being held, unless
|
||||||
@ -362,8 +544,12 @@ otherwise noted.
|
|||||||
|
|
||||||
read: called by read(2) and related system calls
|
read: called by read(2) and related system calls
|
||||||
|
|
||||||
|
aio_read: called by io_submit(2) and other asynchronous I/O operations
|
||||||
|
|
||||||
write: called by write(2) and related system calls
|
write: called by write(2) and related system calls
|
||||||
|
|
||||||
|
aio_write: called by io_submit(2) and other asynchronous I/O operations
|
||||||
|
|
||||||
readdir: called when the VFS needs to read the directory contents
|
readdir: called when the VFS needs to read the directory contents
|
||||||
|
|
||||||
poll: called by the VFS when a process wants to check if there is
|
poll: called by the VFS when a process wants to check if there is
|
||||||
@ -372,18 +558,25 @@ otherwise noted.
|
|||||||
|
|
||||||
ioctl: called by the ioctl(2) system call
|
ioctl: called by the ioctl(2) system call
|
||||||
|
|
||||||
|
unlocked_ioctl: called by the ioctl(2) system call. Filesystems that do not
|
||||||
|
require the BKL should use this method instead of the ioctl() above.
|
||||||
|
|
||||||
|
compat_ioctl: called by the ioctl(2) system call when 32 bit system calls
|
||||||
|
are used on 64 bit kernels.
|
||||||
|
|
||||||
mmap: called by the mmap(2) system call
|
mmap: called by the mmap(2) system call
|
||||||
|
|
||||||
open: called by the VFS when an inode should be opened. When the VFS
|
open: called by the VFS when an inode should be opened. When the VFS
|
||||||
opens a file, it creates a new "struct file" and initialises
|
opens a file, it creates a new "struct file". It then calls the
|
||||||
the "f_op" file operations member with the "default_file_ops"
|
open method for the newly allocated file structure. You might
|
||||||
field in the inode structure. It then calls the open method
|
think that the open method really belongs in
|
||||||
for the newly allocated file structure. You might think that
|
"struct inode_operations", and you may be right. I think it's
|
||||||
the open method really belongs in "struct inode_operations",
|
done the way it is because it makes filesystems simpler to
|
||||||
and you may be right. I think it's done the way it is because
|
implement. The open() method is a good place to initialize the
|
||||||
it makes filesystems simpler to implement. The open() method
|
"private_data" member in the file structure if you want to point
|
||||||
is a good place to initialise the "private_data" member in the
|
to a device structure
|
||||||
file structure if you want to point to a device structure
|
|
||||||
|
flush: called by the close(2) system call to flush a file
|
||||||
|
|
||||||
release: called when the last reference to an open file is closed
|
release: called when the last reference to an open file is closed
|
||||||
|
|
||||||
@ -392,6 +585,23 @@ otherwise noted.
|
|||||||
fasync: called by the fcntl(2) system call when asynchronous
|
fasync: called by the fcntl(2) system call when asynchronous
|
||||||
(non-blocking) mode is enabled for a file
|
(non-blocking) mode is enabled for a file
|
||||||
|
|
||||||
|
lock: called by the fcntl(2) system call for F_GETLK, F_SETLK, and F_SETLKW
|
||||||
|
commands
|
||||||
|
|
||||||
|
readv: called by the readv(2) system call
|
||||||
|
|
||||||
|
writev: called by the writev(2) system call
|
||||||
|
|
||||||
|
sendfile: called by the sendfile(2) system call
|
||||||
|
|
||||||
|
get_unmapped_area: called by the mmap(2) system call
|
||||||
|
|
||||||
|
check_flags: called by the fcntl(2) system call for F_SETFL command
|
||||||
|
|
||||||
|
dir_notify: called by the fcntl(2) system call for F_NOTIFY command
|
||||||
|
|
||||||
|
flock: called by the flock(2) system call
|
||||||
|
|
||||||
Note that the file operations are implemented by the specific
|
Note that the file operations are implemented by the specific
|
||||||
filesystem in which the inode resides. When opening a device node
|
filesystem in which the inode resides. When opening a device node
|
||||||
(character or block special) most filesystems will call special
|
(character or block special) most filesystems will call special
|
||||||
@ -400,29 +610,28 @@ driver information. These support routines replace the filesystem file
|
|||||||
operations with those for the device driver, and then proceed to call
|
operations with those for the device driver, and then proceed to call
|
||||||
the new open() method for the file. This is how opening a device file
|
the new open() method for the file. This is how opening a device file
|
||||||
in the filesystem eventually ends up calling the device driver open()
|
in the filesystem eventually ends up calling the device driver open()
|
||||||
method. Note the devfs (the Device FileSystem) has a more direct path
|
method.
|
||||||
from device node to device driver (this is an unofficial kernel
|
|
||||||
patch).
|
|
||||||
|
|
||||||
|
|
||||||
Directory Entry Cache (dcache) <section>
|
Directory Entry Cache (dcache)
|
||||||
------------------------------
|
==============================
|
||||||
|
|
||||||
|
|
||||||
struct dentry_operations
|
struct dentry_operations
|
||||||
========================
|
------------------------
|
||||||
|
|
||||||
This describes how a filesystem can overload the standard dentry
|
This describes how a filesystem can overload the standard dentry
|
||||||
operations. Dentries and the dcache are the domain of the VFS and the
|
operations. Dentries and the dcache are the domain of the VFS and the
|
||||||
individual filesystem implementations. Device drivers have no business
|
individual filesystem implementations. Device drivers have no business
|
||||||
here. These methods may be set to NULL, as they are either optional or
|
here. These methods may be set to NULL, as they are either optional or
|
||||||
the VFS uses a default. As of kernel 2.1.99, the following members are
|
the VFS uses a default. As of kernel 2.6.13, the following members are
|
||||||
defined:
|
defined:
|
||||||
|
|
||||||
struct dentry_operations {
|
struct dentry_operations {
|
||||||
int (*d_revalidate)(struct dentry *);
|
int (*d_revalidate)(struct dentry *, struct nameidata *);
|
||||||
int (*d_hash) (struct dentry *, struct qstr *);
|
int (*d_hash) (struct dentry *, struct qstr *);
|
||||||
int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
|
int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
|
||||||
void (*d_delete)(struct dentry *);
|
int (*d_delete)(struct dentry *);
|
||||||
void (*d_release)(struct dentry *);
|
void (*d_release)(struct dentry *);
|
||||||
void (*d_iput)(struct dentry *, struct inode *);
|
void (*d_iput)(struct dentry *, struct inode *);
|
||||||
};
|
};
|
||||||
@ -451,6 +660,7 @@ Each dentry has a pointer to its parent dentry, as well as a hash list
|
|||||||
of child dentries. Child dentries are basically like files in a
|
of child dentries. Child dentries are basically like files in a
|
||||||
directory.
|
directory.
|
||||||
|
|
||||||
|
|
||||||
Directory Entry Cache APIs
|
Directory Entry Cache APIs
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
@ -471,7 +681,7 @@ manipulate dentries:
|
|||||||
"d_delete" method is called
|
"d_delete" method is called
|
||||||
|
|
||||||
d_drop: this unhashes a dentry from its parents hash list. A
|
d_drop: this unhashes a dentry from its parents hash list. A
|
||||||
subsequent call to dput() will dellocate the dentry if its
|
subsequent call to dput() will deallocate the dentry if its
|
||||||
usage count drops to 0
|
usage count drops to 0
|
||||||
|
|
||||||
d_delete: delete a dentry. If there are no other open references to
|
d_delete: delete a dentry. If there are no other open references to
|
||||||
@ -507,16 +717,16 @@ up by walking the tree starting with the first component
|
|||||||
of the pathname and using that dentry along with the next
|
of the pathname and using that dentry along with the next
|
||||||
component to look up the next level and so on. Since it
|
component to look up the next level and so on. Since it
|
||||||
is a frequent operation for workloads like multiuser
|
is a frequent operation for workloads like multiuser
|
||||||
environments and webservers, it is important to optimize
|
environments and web servers, it is important to optimize
|
||||||
this path.
|
this path.
|
||||||
|
|
||||||
Prior to 2.5.10, dcache_lock was acquired in d_lookup and thus
|
Prior to 2.5.10, dcache_lock was acquired in d_lookup and thus
|
||||||
in every component during path look-up. Since 2.5.10 onwards,
|
in every component during path look-up. Since 2.5.10 onwards,
|
||||||
fastwalk algorithm changed this by holding the dcache_lock
|
fast-walk algorithm changed this by holding the dcache_lock
|
||||||
at the beginning and walking as many cached path component
|
at the beginning and walking as many cached path component
|
||||||
dentries as possible. This signficantly decreases the number
|
dentries as possible. This significantly decreases the number
|
||||||
of acquisition of dcache_lock. However it also increases the
|
of acquisition of dcache_lock. However it also increases the
|
||||||
lock hold time signficantly and affects performance in large
|
lock hold time significantly and affects performance in large
|
||||||
SMP machines. Since 2.5.62 kernel, dcache has been using
|
SMP machines. Since 2.5.62 kernel, dcache has been using
|
||||||
a new locking model that uses RCU to make dcache look-up
|
a new locking model that uses RCU to make dcache look-up
|
||||||
lock-free.
|
lock-free.
|
||||||
@ -527,7 +737,7 @@ protected the hash chain, d_child, d_alias, d_lru lists as well
|
|||||||
as d_inode and several other things like mount look-up. RCU-based
|
as d_inode and several other things like mount look-up. RCU-based
|
||||||
changes affect only the way the hash chain is protected. For everything
|
changes affect only the way the hash chain is protected. For everything
|
||||||
else the dcache_lock must be taken for both traversing as well as
|
else the dcache_lock must be taken for both traversing as well as
|
||||||
updating. The hash chain updations too take the dcache_lock.
|
updating. The hash chain updates too take the dcache_lock.
|
||||||
The significant change is the way d_lookup traverses the hash chain,
|
The significant change is the way d_lookup traverses the hash chain,
|
||||||
it doesn't acquire the dcache_lock for this and rely on RCU to
|
it doesn't acquire the dcache_lock for this and rely on RCU to
|
||||||
ensure that the dentry has not been *freed*.
|
ensure that the dentry has not been *freed*.
|
||||||
@ -535,14 +745,15 @@ ensure that the dentry has not been *freed*.
|
|||||||
|
|
||||||
Dcache locking details
|
Dcache locking details
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
For many multi-user workloads, open() and stat() on files are
|
For many multi-user workloads, open() and stat() on files are
|
||||||
very frequently occurring operations. Both involve walking
|
very frequently occurring operations. Both involve walking
|
||||||
of path names to find the dentry corresponding to the
|
of path names to find the dentry corresponding to the
|
||||||
concerned file. In 2.4 kernel, dcache_lock was held
|
concerned file. In 2.4 kernel, dcache_lock was held
|
||||||
during look-up of each path component. Contention and
|
during look-up of each path component. Contention and
|
||||||
cacheline bouncing of this global lock caused significant
|
cache-line bouncing of this global lock caused significant
|
||||||
scalability problems. With the introduction of RCU
|
scalability problems. With the introduction of RCU
|
||||||
in linux kernel, this was worked around by making
|
in Linux kernel, this was worked around by making
|
||||||
the look-up of path components during path walking lock-free.
|
the look-up of path components during path walking lock-free.
|
||||||
|
|
||||||
|
|
||||||
@ -562,7 +773,7 @@ Some of the important changes are :
|
|||||||
2. Insertion of a dentry into the hash table is done using
|
2. Insertion of a dentry into the hash table is done using
|
||||||
hlist_add_head_rcu() which take care of ordering the writes -
|
hlist_add_head_rcu() which take care of ordering the writes -
|
||||||
the writes to the dentry must be visible before the dentry
|
the writes to the dentry must be visible before the dentry
|
||||||
is inserted. This works in conjuction with hlist_for_each_rcu()
|
is inserted. This works in conjunction with hlist_for_each_rcu()
|
||||||
while walking the hash chain. The only requirement is that
|
while walking the hash chain. The only requirement is that
|
||||||
all initialization to the dentry must be done before hlist_add_head_rcu()
|
all initialization to the dentry must be done before hlist_add_head_rcu()
|
||||||
since we don't have dcache_lock protection while traversing
|
since we don't have dcache_lock protection while traversing
|
||||||
@ -584,7 +795,7 @@ Some of the important changes are :
|
|||||||
the same. In some sense, dcache_rcu path walking looks like
|
the same. In some sense, dcache_rcu path walking looks like
|
||||||
the pre-2.5.10 version.
|
the pre-2.5.10 version.
|
||||||
|
|
||||||
5. All dentry hash chain updations must take the dcache_lock as well as
|
5. All dentry hash chain updates must take the dcache_lock as well as
|
||||||
the per-dentry lock in that order. dput() does this to ensure
|
the per-dentry lock in that order. dput() does this to ensure
|
||||||
that a dentry that has just been looked up in another CPU
|
that a dentry that has just been looked up in another CPU
|
||||||
doesn't get deleted before dget() can be done on it.
|
doesn't get deleted before dget() can be done on it.
|
||||||
@ -640,10 +851,10 @@ handled as described below :
|
|||||||
Since we redo the d_parent check and compare name while holding
|
Since we redo the d_parent check and compare name while holding
|
||||||
d_lock, lock-free look-up will not race against d_move().
|
d_lock, lock-free look-up will not race against d_move().
|
||||||
|
|
||||||
4. There can be a theoritical race when a dentry keeps coming back
|
4. There can be a theoretical race when a dentry keeps coming back
|
||||||
to original bucket due to double moves. Due to this look-up may
|
to original bucket due to double moves. Due to this look-up may
|
||||||
consider that it has never moved and can end up in a infinite loop.
|
consider that it has never moved and can end up in a infinite loop.
|
||||||
But this is not any worse that theoritical livelocks we already
|
But this is not any worse that theoretical livelocks we already
|
||||||
have in the kernel.
|
have in the kernel.
|
||||||
|
|
||||||
|
|
||||||
|
@ -878,7 +878,7 @@ DVD_READ_STRUCT Read structure
|
|||||||
|
|
||||||
error returns:
|
error returns:
|
||||||
EINVAL physical.layer_num exceeds number of layers
|
EINVAL physical.layer_num exceeds number of layers
|
||||||
EIO Recieved invalid response from drive
|
EIO Received invalid response from drive
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ This document describes the Linux kernel Makefiles.
|
|||||||
|
|
||||||
=== 6 Architecture Makefiles
|
=== 6 Architecture Makefiles
|
||||||
--- 6.1 Set variables to tweak the build to the architecture
|
--- 6.1 Set variables to tweak the build to the architecture
|
||||||
--- 6.2 Add prerequisites to prepare:
|
--- 6.2 Add prerequisites to archprepare:
|
||||||
--- 6.3 List directories to visit when descending
|
--- 6.3 List directories to visit when descending
|
||||||
--- 6.4 Architecture specific boot images
|
--- 6.4 Architecture specific boot images
|
||||||
--- 6.5 Building non-kbuild targets
|
--- 6.5 Building non-kbuild targets
|
||||||
@ -734,18 +734,18 @@ When kbuild executes the following steps are followed (roughly):
|
|||||||
for loadable kernel modules.
|
for loadable kernel modules.
|
||||||
|
|
||||||
|
|
||||||
--- 6.2 Add prerequisites to prepare:
|
--- 6.2 Add prerequisites to archprepare:
|
||||||
|
|
||||||
The prepare: rule is used to list prerequisites that needs to be
|
The archprepare: rule is used to list prerequisites that needs to be
|
||||||
built before starting to descend down in the subdirectories.
|
built before starting to descend down in the subdirectories.
|
||||||
This is usual header files containing assembler constants.
|
This is usual header files containing assembler constants.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
#arch/s390/Makefile
|
#arch/arm/Makefile
|
||||||
prepare: include/asm-$(ARCH)/offsets.h
|
archprepare: maketools
|
||||||
|
|
||||||
In this example the file include/asm-$(ARCH)/offsets.h will
|
In this example the file target maketools will be processed
|
||||||
be built before descending down in the subdirectories.
|
before descending down in the subdirectories.
|
||||||
See also chapter XXX-TODO that describe how kbuild supports
|
See also chapter XXX-TODO that describe how kbuild supports
|
||||||
generating offset header files.
|
generating offset header files.
|
||||||
|
|
||||||
|
@ -39,8 +39,7 @@ SETUP
|
|||||||
and apply http://lse.sourceforge.net/kdump/patches/kexec-tools-1.101-kdump.patch
|
and apply http://lse.sourceforge.net/kdump/patches/kexec-tools-1.101-kdump.patch
|
||||||
and after that build the source.
|
and after that build the source.
|
||||||
|
|
||||||
2) Download and build the appropriate (latest) kexec/kdump (-mm) kernel
|
2) Download and build the appropriate (2.6.13-rc1 onwards) vanilla kernel.
|
||||||
patchset and apply it to the vanilla kernel tree.
|
|
||||||
|
|
||||||
Two kernels need to be built in order to get this feature working.
|
Two kernels need to be built in order to get this feature working.
|
||||||
|
|
||||||
@ -84,15 +83,16 @@ SETUP
|
|||||||
|
|
||||||
4) Load the second kernel to be booted using:
|
4) Load the second kernel to be booted using:
|
||||||
|
|
||||||
kexec -p <second-kernel> --crash-dump --args-linux --append="root=<root-dev>
|
kexec -p <second-kernel> --args-linux --elf32-core-headers
|
||||||
init 1 irqpoll"
|
--append="root=<root-dev> init 1 irqpoll"
|
||||||
|
|
||||||
Note: i) <second-kernel> has to be a vmlinux image. bzImage will not work,
|
Note: i) <second-kernel> has to be a vmlinux image. bzImage will not work,
|
||||||
as of now.
|
as of now.
|
||||||
ii) By default ELF headers are stored in ELF32 format (for i386). This
|
ii) By default ELF headers are stored in ELF64 format. Option
|
||||||
is sufficient to represent the physical memory up to 4GB. To store
|
--elf32-core-headers forces generation of ELF32 headers. gdb can
|
||||||
headers in ELF64 format, specifiy "--elf64-core-headers" on the
|
not open ELF64 headers on 32 bit systems. So creating ELF32
|
||||||
kexec command line additionally.
|
headers can come handy for users who have got non-PAE systems and
|
||||||
|
hence have memory less than 4GB.
|
||||||
iii) Specify "irqpoll" as command line parameter. This reduces driver
|
iii) Specify "irqpoll" as command line parameter. This reduces driver
|
||||||
initialization failures in second kernel due to shared interrupts.
|
initialization failures in second kernel due to shared interrupts.
|
||||||
|
|
||||||
|
@ -164,6 +164,15 @@ running once the system is up.
|
|||||||
over-ride platform specific driver.
|
over-ride platform specific driver.
|
||||||
See also Documentation/acpi-hotkey.txt.
|
See also Documentation/acpi-hotkey.txt.
|
||||||
|
|
||||||
|
enable_timer_pin_1 [i386,x86-64]
|
||||||
|
Enable PIN 1 of APIC timer
|
||||||
|
Can be useful to work around chipset bugs (in particular on some ATI chipsets)
|
||||||
|
The kernel tries to set a reasonable default.
|
||||||
|
|
||||||
|
disable_timer_pin_1 [i386,x86-64]
|
||||||
|
Disable PIN 1 of APIC timer
|
||||||
|
Can be useful to work around chipset bugs.
|
||||||
|
|
||||||
ad1816= [HW,OSS]
|
ad1816= [HW,OSS]
|
||||||
Format: <io>,<irq>,<dma>,<dma2>
|
Format: <io>,<irq>,<dma>,<dma2>
|
||||||
See also Documentation/sound/oss/AD1816.
|
See also Documentation/sound/oss/AD1816.
|
||||||
@ -549,6 +558,7 @@ running once the system is up.
|
|||||||
keyboard and can not control its state
|
keyboard and can not control its state
|
||||||
(Don't attempt to blink the leds)
|
(Don't attempt to blink the leds)
|
||||||
i8042.noaux [HW] Don't check for auxiliary (== mouse) port
|
i8042.noaux [HW] Don't check for auxiliary (== mouse) port
|
||||||
|
i8042.nokbd [HW] Don't check/create keyboard port
|
||||||
i8042.nomux [HW] Don't check presence of an active multiplexing
|
i8042.nomux [HW] Don't check presence of an active multiplexing
|
||||||
controller
|
controller
|
||||||
i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
|
i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
|
||||||
|
@ -30,7 +30,7 @@ other program after you have done the following:
|
|||||||
Read the file 'binfmt_misc.txt' in this directory to know
|
Read the file 'binfmt_misc.txt' in this directory to know
|
||||||
more about the configuration process.
|
more about the configuration process.
|
||||||
|
|
||||||
3) Add the following enries to /etc/rc.local or similar script
|
3) Add the following entries to /etc/rc.local or similar script
|
||||||
to be run at system startup:
|
to be run at system startup:
|
||||||
|
|
||||||
# Insert BINFMT_MISC module into the kernel
|
# Insert BINFMT_MISC module into the kernel
|
||||||
|
@ -1241,7 +1241,7 @@ traffic while still maintaining carrier on.
|
|||||||
|
|
||||||
If running SNMP agents, the bonding driver should be loaded
|
If running SNMP agents, the bonding driver should be loaded
|
||||||
before any network drivers participating in a bond. This requirement
|
before any network drivers participating in a bond. This requirement
|
||||||
is due to the the interface index (ipAdEntIfIndex) being associated to
|
is due to the interface index (ipAdEntIfIndex) being associated to
|
||||||
the first interface found with a given IP address. That is, there is
|
the first interface found with a given IP address. That is, there is
|
||||||
only one ipAdEntIfIndex for each IP address. For example, if eth0 and
|
only one ipAdEntIfIndex for each IP address. For example, if eth0 and
|
||||||
eth1 are slaves of bond0 and the driver for eth0 is loaded before the
|
eth1 are slaves of bond0 and the driver for eth0 is loaded before the
|
||||||
@ -1937,7 +1937,7 @@ switches currently available support 802.3ad.
|
|||||||
If not explicitly configured (with ifconfig or ip link), the
|
If not explicitly configured (with ifconfig or ip link), the
|
||||||
MAC address of the bonding device is taken from its first slave
|
MAC address of the bonding device is taken from its first slave
|
||||||
device. This MAC address is then passed to all following slaves and
|
device. This MAC address is then passed to all following slaves and
|
||||||
remains persistent (even if the the first slave is removed) until the
|
remains persistent (even if the first slave is removed) until the
|
||||||
bonding device is brought down or reconfigured.
|
bonding device is brought down or reconfigured.
|
||||||
|
|
||||||
If you wish to change the MAC address, you can set it with
|
If you wish to change the MAC address, you can set it with
|
||||||
|
@ -355,7 +355,7 @@ REVISION HISTORY
|
|||||||
There is no functional difference between the two packages
|
There is no functional difference between the two packages
|
||||||
|
|
||||||
2.0.7 Aug 26, 1999 o Merged X25API code into WANPIPE.
|
2.0.7 Aug 26, 1999 o Merged X25API code into WANPIPE.
|
||||||
o Fixed a memeory leak for X25API
|
o Fixed a memory leak for X25API
|
||||||
o Updated the X25API code for 2.2.X kernels.
|
o Updated the X25API code for 2.2.X kernels.
|
||||||
o Improved NEM handling.
|
o Improved NEM handling.
|
||||||
|
|
||||||
@ -514,7 +514,7 @@ beta2-2.2.0 Jan 8 2001
|
|||||||
o Patches for 2.4.0 kernel
|
o Patches for 2.4.0 kernel
|
||||||
o Patches for 2.2.18 kernel
|
o Patches for 2.2.18 kernel
|
||||||
o Minor updates to PPP and CHLDC drivers.
|
o Minor updates to PPP and CHLDC drivers.
|
||||||
Note: No functinal difference.
|
Note: No functional difference.
|
||||||
|
|
||||||
beta3-2.2.9 Jan 10 2001
|
beta3-2.2.9 Jan 10 2001
|
||||||
o I missed the 2.2.18 kernel patches in beta2-2.2.0
|
o I missed the 2.2.18 kernel patches in beta2-2.2.0
|
||||||
|
@ -84,7 +84,7 @@ Each entry consists of:
|
|||||||
|
|
||||||
Most drivers don't need to use the driver_data field. Best practice
|
Most drivers don't need to use the driver_data field. Best practice
|
||||||
for use of driver_data is to use it as an index into a static list of
|
for use of driver_data is to use it as an index into a static list of
|
||||||
equivalant device types, not to use it as a pointer.
|
equivalent device types, not to use it as a pointer.
|
||||||
|
|
||||||
Have a table entry {PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID}
|
Have a table entry {PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID}
|
||||||
to have probe() called for every PCI device known to the system.
|
to have probe() called for every PCI device known to the system.
|
||||||
|
@ -134,7 +134,7 @@ pci_get_device_by_addr() will find the pci device associated
|
|||||||
with that address (if any).
|
with that address (if any).
|
||||||
|
|
||||||
The default include/asm-ppc64/io.h macros readb(), inb(), insb(),
|
The default include/asm-ppc64/io.h macros readb(), inb(), insb(),
|
||||||
etc. include a check to see if the the i/o read returned all-0xff's.
|
etc. include a check to see if the i/o read returned all-0xff's.
|
||||||
If so, these make a call to eeh_dn_check_failure(), which in turn
|
If so, these make a call to eeh_dn_check_failure(), which in turn
|
||||||
asks the firmware if the all-ff's value is the sign of a true EEH
|
asks the firmware if the all-ff's value is the sign of a true EEH
|
||||||
error. If it is not, processing continues as normal. The grand
|
error. If it is not, processing continues as normal. The grand
|
||||||
|
@ -468,7 +468,7 @@ The hex_ascii view shows the data field in hex and ascii representation
|
|||||||
The raw view returns a bytestream as the debug areas are stored in memory.
|
The raw view returns a bytestream as the debug areas are stored in memory.
|
||||||
|
|
||||||
The sprintf view formats the debug entries in the same way as the sprintf
|
The sprintf view formats the debug entries in the same way as the sprintf
|
||||||
function would do. The sprintf event/expection fuctions write to the
|
function would do. The sprintf event/expection functions write to the
|
||||||
debug entry a pointer to the format string (size = sizeof(long))
|
debug entry a pointer to the format string (size = sizeof(long))
|
||||||
and for each vararg a long value. So e.g. for a debug entry with a format
|
and for each vararg a long value. So e.g. for a debug entry with a format
|
||||||
string plus two varargs one would need to allocate a (3 * sizeof(long))
|
string plus two varargs one would need to allocate a (3 * sizeof(long))
|
||||||
|
@ -344,7 +344,7 @@
|
|||||||
/proc/scsi/ibmmca/<host_no>. ibmmca_proc_info() provides this information.
|
/proc/scsi/ibmmca/<host_no>. ibmmca_proc_info() provides this information.
|
||||||
|
|
||||||
This table is quite informative for interested users. It shows the load
|
This table is quite informative for interested users. It shows the load
|
||||||
of commands on the subsystem and wether you are running the bypassed
|
of commands on the subsystem and whether you are running the bypassed
|
||||||
(software) or integrated (hardware) SCSI-command set (see below). The
|
(software) or integrated (hardware) SCSI-command set (see below). The
|
||||||
amount of accesses is shown. Read, write, modeselect is shown separately
|
amount of accesses is shown. Read, write, modeselect is shown separately
|
||||||
in order to help debugging problems with CD-ROMs or tapedrives.
|
in order to help debugging problems with CD-ROMs or tapedrives.
|
||||||
|
@ -1459,7 +1459,7 @@ devices where %i is sound card number from zero to seven.
|
|||||||
To auto-load an ALSA driver for OSS services, define the string
|
To auto-load an ALSA driver for OSS services, define the string
|
||||||
'sound-slot-%i' where %i means the slot number for OSS, which
|
'sound-slot-%i' where %i means the slot number for OSS, which
|
||||||
corresponds to the card index of ALSA. Usually, define this
|
corresponds to the card index of ALSA. Usually, define this
|
||||||
as the the same card module.
|
as the same card module.
|
||||||
|
|
||||||
An example configuration for a single emu10k1 card is like below:
|
An example configuration for a single emu10k1 card is like below:
|
||||||
----- /etc/modprobe.conf
|
----- /etc/modprobe.conf
|
||||||
|
@ -57,7 +57,7 @@ With BK, you can just get it from
|
|||||||
|
|
||||||
and DaveJ has tar-balls at
|
and DaveJ has tar-balls at
|
||||||
|
|
||||||
http://www.codemonkey.org.uk/projects/bitkeeper/sparse/
|
http://www.codemonkey.org.uk/projects/git-snapshots/sparse/
|
||||||
|
|
||||||
|
|
||||||
Once you have it, just do
|
Once you have it, just do
|
||||||
|
@ -171,7 +171,7 @@ the header 'include/linux/sysrq.h', this will define everything else you need.
|
|||||||
Next, you must create a sysrq_key_op struct, and populate it with A) the key
|
Next, you must create a sysrq_key_op struct, and populate it with A) the key
|
||||||
handler function you will use, B) a help_msg string, that will print when SysRQ
|
handler function you will use, B) a help_msg string, that will print when SysRQ
|
||||||
prints help, and C) an action_msg string, that will print right before your
|
prints help, and C) an action_msg string, that will print right before your
|
||||||
handler is called. Your handler must conform to the protoype in 'sysrq.h'.
|
handler is called. Your handler must conform to the prototype in 'sysrq.h'.
|
||||||
|
|
||||||
After the sysrq_key_op is created, you can call the macro
|
After the sysrq_key_op is created, you can call the macro
|
||||||
register_sysrq_key(int key, struct sysrq_key_op *op_p) that is defined in
|
register_sysrq_key(int key, struct sysrq_key_op *op_p) that is defined in
|
||||||
|
@ -2176,7 +2176,7 @@
|
|||||||
If you want to access files on the host machine from inside UML, you
|
If you want to access files on the host machine from inside UML, you
|
||||||
can treat it as a separate machine and either nfs mount directories
|
can treat it as a separate machine and either nfs mount directories
|
||||||
from the host or copy files into the virtual machine with scp or rcp.
|
from the host or copy files into the virtual machine with scp or rcp.
|
||||||
However, since UML is running on the the host, it can access those
|
However, since UML is running on the host, it can access those
|
||||||
files just like any other process and make them available inside the
|
files just like any other process and make them available inside the
|
||||||
virtual machine without needing to use the network.
|
virtual machine without needing to use the network.
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ License along with this program; if not, write to the Free
|
|||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||||
MA 02111-1307 USA.
|
MA 02111-1307 USA.
|
||||||
|
|
||||||
This document and the the gadget serial driver itself are
|
This document and the gadget serial driver itself are
|
||||||
Copyright (C) 2004 by Al Borchers (alborchers@steinerpoint.com).
|
Copyright (C) 2004 by Al Borchers (alborchers@steinerpoint.com).
|
||||||
|
|
||||||
If you have questions, problems, or suggestions for this driver
|
If you have questions, problems, or suggestions for this driver
|
||||||
|
@ -126,10 +126,12 @@ card=124 - AverMedia AverTV DVB-T 761
|
|||||||
card=125 - MATRIX Vision Sigma-SQ
|
card=125 - MATRIX Vision Sigma-SQ
|
||||||
card=126 - MATRIX Vision Sigma-SLC
|
card=126 - MATRIX Vision Sigma-SLC
|
||||||
card=127 - APAC Viewcomp 878(AMAX)
|
card=127 - APAC Viewcomp 878(AMAX)
|
||||||
card=128 - DVICO FusionHDTV DVB-T Lite
|
card=128 - DViCO FusionHDTV DVB-T Lite
|
||||||
card=129 - V-Gear MyVCD
|
card=129 - V-Gear MyVCD
|
||||||
card=130 - Super TV Tuner
|
card=130 - Super TV Tuner
|
||||||
card=131 - Tibet Systems 'Progress DVR' CS16
|
card=131 - Tibet Systems 'Progress DVR' CS16
|
||||||
card=132 - Kodicom 4400R (master)
|
card=132 - Kodicom 4400R (master)
|
||||||
card=133 - Kodicom 4400R (slave)
|
card=133 - Kodicom 4400R (slave)
|
||||||
card=134 - Adlink RTV24
|
card=134 - Adlink RTV24
|
||||||
|
card=135 - DViCO FusionHDTV 5 Lite
|
||||||
|
card=136 - Acorp Y878F
|
||||||
|
@ -62,3 +62,6 @@
|
|||||||
61 -> Philips TOUGH DVB-T reference design [1131:2004]
|
61 -> Philips TOUGH DVB-T reference design [1131:2004]
|
||||||
62 -> Compro VideoMate TV Gold+II
|
62 -> Compro VideoMate TV Gold+II
|
||||||
63 -> Kworld Xpert TV PVR7134
|
63 -> Kworld Xpert TV PVR7134
|
||||||
|
64 -> FlyTV mini Asus Digimatrix [1043:0210,1043:0210]
|
||||||
|
65 -> V-Stream Studio TV Terminator
|
||||||
|
66 -> Yuan TUN-900 (saa7135)
|
||||||
|
@ -64,3 +64,4 @@ tuner=62 - Philips TEA5767HN FM Radio
|
|||||||
tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
|
tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
|
||||||
tuner=64 - LG TDVS-H062F/TUA6034
|
tuner=64 - LG TDVS-H062F/TUA6034
|
||||||
tuner=65 - Ymec TVF66T5-B/DFF
|
tuner=65 - Ymec TVF66T5-B/DFF
|
||||||
|
tuner=66 - LG NTSC (TALN mini series)
|
||||||
|
@ -222,7 +222,7 @@ was introduced in 1991, is used in the DC10 old
|
|||||||
can generate: PAL , NTSC , SECAM
|
can generate: PAL , NTSC , SECAM
|
||||||
|
|
||||||
The adv717x, should be able to produce PAL N. But you find nothing PAL N
|
The adv717x, should be able to produce PAL N. But you find nothing PAL N
|
||||||
specific in the the registers. Seem that you have to reuse a other standard
|
specific in the registers. Seem that you have to reuse a other standard
|
||||||
to generate PAL N, maybe it would work if you use the PAL M settings.
|
to generate PAL N, maybe it would work if you use the PAL M settings.
|
||||||
|
|
||||||
==========================
|
==========================
|
||||||
|
@ -11,6 +11,11 @@ Machine check
|
|||||||
If your BIOS doesn't do that it's a good idea to enable though
|
If your BIOS doesn't do that it's a good idea to enable though
|
||||||
to make sure you log even machine check events that result
|
to make sure you log even machine check events that result
|
||||||
in a reboot.
|
in a reboot.
|
||||||
|
mce=tolerancelevel (number)
|
||||||
|
0: always panic, 1: panic if deadlock possible,
|
||||||
|
2: try to avoid panic, 3: never panic or exit (for testing)
|
||||||
|
default is 1
|
||||||
|
Can be also set using sysfs which is preferable.
|
||||||
|
|
||||||
nomce (for compatibility with i386): same as mce=off
|
nomce (for compatibility with i386): same as mce=off
|
||||||
|
|
||||||
|
49
Kbuild
Normal file
49
Kbuild
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#
|
||||||
|
# Kbuild for top-level directory of the kernel
|
||||||
|
# This file takes care of the following:
|
||||||
|
# 1) Generate asm-offsets.h
|
||||||
|
|
||||||
|
#####
|
||||||
|
# 1) Generate asm-offsets.h
|
||||||
|
#
|
||||||
|
|
||||||
|
offsets-file := include/asm-$(ARCH)/asm-offsets.h
|
||||||
|
|
||||||
|
always := $(offsets-file)
|
||||||
|
targets := $(offsets-file)
|
||||||
|
targets += arch/$(ARCH)/kernel/asm-offsets.s
|
||||||
|
|
||||||
|
# Default sed regexp - multiline due to syntax constraints
|
||||||
|
define sed-y
|
||||||
|
"/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}"
|
||||||
|
endef
|
||||||
|
# Override default regexp for specific architectures
|
||||||
|
sed-$(CONFIG_MIPS) := "/^@@@/s///p"
|
||||||
|
|
||||||
|
quiet_cmd_offsets = GEN $@
|
||||||
|
define cmd_offsets
|
||||||
|
mkdir -p $(dir $@); \
|
||||||
|
cat $< | \
|
||||||
|
(set -e; \
|
||||||
|
echo "#ifndef __ASM_OFFSETS_H__"; \
|
||||||
|
echo "#define __ASM_OFFSETS_H__"; \
|
||||||
|
echo "/*"; \
|
||||||
|
echo " * DO NOT MODIFY."; \
|
||||||
|
echo " *"; \
|
||||||
|
echo " * This file was generated by $(srctree)/Kbuild"; \
|
||||||
|
echo " *"; \
|
||||||
|
echo " */"; \
|
||||||
|
echo ""; \
|
||||||
|
sed -ne $(sed-y); \
|
||||||
|
echo ""; \
|
||||||
|
echo "#endif" ) > $@
|
||||||
|
endef
|
||||||
|
|
||||||
|
# We use internal kbuild rules to avoid the "is up to date" message from make
|
||||||
|
arch/$(ARCH)/kernel/asm-offsets.s: arch/$(ARCH)/kernel/asm-offsets.c FORCE
|
||||||
|
$(Q)mkdir -p $(dir $@)
|
||||||
|
$(call if_changed_dep,cc_s_c)
|
||||||
|
|
||||||
|
$(obj)/$(offsets-file): arch/$(ARCH)/kernel/asm-offsets.s Kbuild
|
||||||
|
$(call cmd,offsets)
|
||||||
|
|
24
MAINTAINERS
24
MAINTAINERS
@ -626,6 +626,12 @@ M: rmk@arm.linux.org.uk
|
|||||||
W: http://www.arm.linux.org.uk/
|
W: http://www.arm.linux.org.uk/
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
|
||||||
|
CYBLAFB FRAMEBUFFER DRIVER
|
||||||
|
P: Knut Petersen
|
||||||
|
M: Knut_Petersen@t-online.de
|
||||||
|
L: linux-fbdev-devel@lists.sourceforge.net
|
||||||
|
S: Maintained
|
||||||
|
|
||||||
CYCLADES 2X SYNC CARD DRIVER
|
CYCLADES 2X SYNC CARD DRIVER
|
||||||
P: Arnaldo Carvalho de Melo
|
P: Arnaldo Carvalho de Melo
|
||||||
M: acme@conectiva.com.br
|
M: acme@conectiva.com.br
|
||||||
@ -925,6 +931,13 @@ L: linux-tape@vger.kernel.org
|
|||||||
W: http://sourceforge.net/projects/ftape
|
W: http://sourceforge.net/projects/ftape
|
||||||
S: Orphan
|
S: Orphan
|
||||||
|
|
||||||
|
FUSE: FILESYSTEM IN USERSPACE
|
||||||
|
P: Miklos Szeredi
|
||||||
|
M: miklos@szeredi.hu
|
||||||
|
L: fuse-devel@lists.sourceforge.net
|
||||||
|
W: http://fuse.sourceforge.net/
|
||||||
|
S: Maintained
|
||||||
|
|
||||||
FUTURE DOMAIN TMC-16x0 SCSI DRIVER (16-bit)
|
FUTURE DOMAIN TMC-16x0 SCSI DRIVER (16-bit)
|
||||||
P: Rik Faith
|
P: Rik Faith
|
||||||
M: faith@cs.unc.edu
|
M: faith@cs.unc.edu
|
||||||
@ -2691,6 +2704,17 @@ L: rio500-users@lists.sourceforge.net
|
|||||||
W: http://rio500.sourceforge.net
|
W: http://rio500.sourceforge.net
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
|
||||||
|
V9FS FILE SYSTEM
|
||||||
|
P: Eric Van Hensbergen
|
||||||
|
M: ericvh@gmail.com
|
||||||
|
P: Ron Minnich
|
||||||
|
M: rminnich@lanl.gov
|
||||||
|
P: Latchesar Ionkov
|
||||||
|
M: lucho@ionkov.net
|
||||||
|
L: v9fs-developer@lists.sourceforge.net
|
||||||
|
W: http://v9fs.sf.net
|
||||||
|
S: Maintained
|
||||||
|
|
||||||
VIDEO FOR LINUX
|
VIDEO FOR LINUX
|
||||||
P: Mauro Carvalho Chehab
|
P: Mauro Carvalho Chehab
|
||||||
M: mchehab@brturbo.com.br
|
M: mchehab@brturbo.com.br
|
||||||
|
80
Makefile
80
Makefile
@ -334,7 +334,7 @@ KALLSYMS = scripts/kallsyms
|
|||||||
PERL = perl
|
PERL = perl
|
||||||
CHECK = sparse
|
CHECK = sparse
|
||||||
|
|
||||||
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__
|
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ $(CF)
|
||||||
MODFLAGS = -DMODULE
|
MODFLAGS = -DMODULE
|
||||||
CFLAGS_MODULE = $(MODFLAGS)
|
CFLAGS_MODULE = $(MODFLAGS)
|
||||||
AFLAGS_MODULE = $(MODFLAGS)
|
AFLAGS_MODULE = $(MODFLAGS)
|
||||||
@ -382,6 +382,9 @@ RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CV
|
|||||||
scripts_basic:
|
scripts_basic:
|
||||||
$(Q)$(MAKE) $(build)=scripts/basic
|
$(Q)$(MAKE) $(build)=scripts/basic
|
||||||
|
|
||||||
|
# To avoid any implicit rule to kick in, define an empty command.
|
||||||
|
scripts/basic/%: scripts_basic ;
|
||||||
|
|
||||||
.PHONY: outputmakefile
|
.PHONY: outputmakefile
|
||||||
# outputmakefile generate a Makefile to be placed in output directory, if
|
# outputmakefile generate a Makefile to be placed in output directory, if
|
||||||
# using a seperate output directory. This allows convinient use
|
# using a seperate output directory. This allows convinient use
|
||||||
@ -444,9 +447,8 @@ ifeq ($(config-targets),1)
|
|||||||
include $(srctree)/arch/$(ARCH)/Makefile
|
include $(srctree)/arch/$(ARCH)/Makefile
|
||||||
export KBUILD_DEFCONFIG
|
export KBUILD_DEFCONFIG
|
||||||
|
|
||||||
config: scripts_basic outputmakefile FORCE
|
config %config: scripts_basic outputmakefile FORCE
|
||||||
$(Q)$(MAKE) $(build)=scripts/kconfig $@
|
$(Q)mkdir -p include/linux
|
||||||
%config: scripts_basic outputmakefile FORCE
|
|
||||||
$(Q)$(MAKE) $(build)=scripts/kconfig $@
|
$(Q)$(MAKE) $(build)=scripts/kconfig $@
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -489,6 +491,7 @@ include .config
|
|||||||
# If .config is newer than include/linux/autoconf.h, someone tinkered
|
# If .config is newer than include/linux/autoconf.h, someone tinkered
|
||||||
# with it and forgot to run make oldconfig
|
# with it and forgot to run make oldconfig
|
||||||
include/linux/autoconf.h: .config
|
include/linux/autoconf.h: .config
|
||||||
|
$(Q)mkdir -p include/linux
|
||||||
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
|
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
|
||||||
else
|
else
|
||||||
# Dummy target needed, because used as prerequisite
|
# Dummy target needed, because used as prerequisite
|
||||||
@ -641,8 +644,13 @@ quiet_cmd_vmlinux__ ?= LD $@
|
|||||||
# Generate new vmlinux version
|
# Generate new vmlinux version
|
||||||
quiet_cmd_vmlinux_version = GEN .version
|
quiet_cmd_vmlinux_version = GEN .version
|
||||||
cmd_vmlinux_version = set -e; \
|
cmd_vmlinux_version = set -e; \
|
||||||
. $(srctree)/scripts/mkversion > .tmp_version; \
|
if [ ! -r .version ]; then \
|
||||||
mv -f .tmp_version .version; \
|
rm -f .version; \
|
||||||
|
echo 1 >.version; \
|
||||||
|
else \
|
||||||
|
mv .version .old_version; \
|
||||||
|
expr 0$$(cat .old_version) + 1 >.version; \
|
||||||
|
fi; \
|
||||||
$(MAKE) $(build)=init
|
$(MAKE) $(build)=init
|
||||||
|
|
||||||
# Generate System.map
|
# Generate System.map
|
||||||
@ -756,6 +764,7 @@ endif # ifdef CONFIG_KALLSYMS
|
|||||||
# vmlinux image - including updated kernel symbols
|
# vmlinux image - including updated kernel symbols
|
||||||
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
|
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
|
||||||
$(call if_changed_rule,vmlinux__)
|
$(call if_changed_rule,vmlinux__)
|
||||||
|
$(Q)rm -f .old_version
|
||||||
|
|
||||||
# The actual objects are generated when descending,
|
# The actual objects are generated when descending,
|
||||||
# make sure no implicit rule kicks in
|
# make sure no implicit rule kicks in
|
||||||
@ -768,22 +777,27 @@ $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;
|
|||||||
# Error messages still appears in the original language
|
# Error messages still appears in the original language
|
||||||
|
|
||||||
.PHONY: $(vmlinux-dirs)
|
.PHONY: $(vmlinux-dirs)
|
||||||
$(vmlinux-dirs): prepare-all scripts
|
$(vmlinux-dirs): prepare scripts
|
||||||
$(Q)$(MAKE) $(build)=$@
|
$(Q)$(MAKE) $(build)=$@
|
||||||
|
|
||||||
# Things we need to do before we recursively start building the kernel
|
# Things we need to do before we recursively start building the kernel
|
||||||
# or the modules are listed in "prepare-all".
|
# or the modules are listed in "prepare".
|
||||||
# A multi level approach is used. prepare1 is updated first, then prepare0.
|
# A multi level approach is used. prepareN is processed before prepareN-1.
|
||||||
# prepare-all is the collection point for the prepare targets.
|
# archprepare is used in arch Makefiles and when processed asm symlink,
|
||||||
|
# version.h and scripts_basic is processed / created.
|
||||||
|
|
||||||
.PHONY: prepare-all prepare prepare0 prepare1 prepare2
|
# Listed in dependency order
|
||||||
|
.PHONY: prepare archprepare prepare0 prepare1 prepare2 prepare3
|
||||||
|
|
||||||
# prepare2 is used to check if we are building in a separate output directory,
|
# prepare-all is deprecated, use prepare as valid replacement
|
||||||
|
.PHONY: prepare-all
|
||||||
|
|
||||||
|
# prepare3 is used to check if we are building in a separate output directory,
|
||||||
# and if so do:
|
# and if so do:
|
||||||
# 1) Check that make has not been executed in the kernel src $(srctree)
|
# 1) Check that make has not been executed in the kernel src $(srctree)
|
||||||
# 2) Create the include2 directory, used for the second asm symlink
|
# 2) Create the include2 directory, used for the second asm symlink
|
||||||
|
|
||||||
prepare2:
|
prepare3:
|
||||||
ifneq ($(KBUILD_SRC),)
|
ifneq ($(KBUILD_SRC),)
|
||||||
@echo ' Using $(srctree) as source for kernel'
|
@echo ' Using $(srctree) as source for kernel'
|
||||||
$(Q)if [ -f $(srctree)/.config ]; then \
|
$(Q)if [ -f $(srctree)/.config ]; then \
|
||||||
@ -795,18 +809,23 @@ ifneq ($(KBUILD_SRC),)
|
|||||||
$(Q)ln -fsn $(srctree)/include/asm-$(ARCH) include2/asm
|
$(Q)ln -fsn $(srctree)/include/asm-$(ARCH) include2/asm
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# prepare1 creates a makefile if using a separate output directory
|
# prepare2 creates a makefile if using a separate output directory
|
||||||
prepare1: prepare2 outputmakefile
|
prepare2: prepare3 outputmakefile
|
||||||
|
|
||||||
prepare0: prepare1 include/linux/version.h include/asm \
|
prepare1: prepare2 include/linux/version.h include/asm \
|
||||||
include/config/MARKER
|
include/config/MARKER
|
||||||
ifneq ($(KBUILD_MODULES),)
|
ifneq ($(KBUILD_MODULES),)
|
||||||
$(Q)rm -rf $(MODVERDIR)
|
$(Q)rm -rf $(MODVERDIR)
|
||||||
$(Q)mkdir -p $(MODVERDIR)
|
$(Q)mkdir -p $(MODVERDIR)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
archprepare: prepare1 scripts_basic
|
||||||
|
|
||||||
|
prepare0: archprepare FORCE
|
||||||
|
$(Q)$(MAKE) $(build)=.
|
||||||
|
|
||||||
# All the preparing..
|
# All the preparing..
|
||||||
prepare-all: prepare0 prepare
|
prepare prepare-all: prepare0
|
||||||
|
|
||||||
# Leave this as default for preprocessing vmlinux.lds.S, which is now
|
# Leave this as default for preprocessing vmlinux.lds.S, which is now
|
||||||
# done in arch/$(ARCH)/kernel/Makefile
|
# done in arch/$(ARCH)/kernel/Makefile
|
||||||
@ -845,7 +864,7 @@ include/asm:
|
|||||||
|
|
||||||
# Split autoconf.h into include/linux/config/*
|
# Split autoconf.h into include/linux/config/*
|
||||||
|
|
||||||
include/config/MARKER: include/linux/autoconf.h
|
include/config/MARKER: scripts/basic/split-include include/linux/autoconf.h
|
||||||
@echo ' SPLIT include/linux/autoconf.h -> include/config/*'
|
@echo ' SPLIT include/linux/autoconf.h -> include/config/*'
|
||||||
@scripts/basic/split-include include/linux/autoconf.h include/config
|
@scripts/basic/split-include include/linux/autoconf.h include/config
|
||||||
@touch $@
|
@touch $@
|
||||||
@ -897,7 +916,7 @@ modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux)
|
|||||||
|
|
||||||
# Target to prepare building external modules
|
# Target to prepare building external modules
|
||||||
.PHONY: modules_prepare
|
.PHONY: modules_prepare
|
||||||
modules_prepare: prepare-all scripts
|
modules_prepare: prepare scripts
|
||||||
|
|
||||||
# Target to install modules
|
# Target to install modules
|
||||||
.PHONY: modules_install
|
.PHONY: modules_install
|
||||||
@ -949,26 +968,6 @@ modules modules_install: FORCE
|
|||||||
|
|
||||||
endif # CONFIG_MODULES
|
endif # CONFIG_MODULES
|
||||||
|
|
||||||
# Generate asm-offsets.h
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
define filechk_gen-asm-offsets
|
|
||||||
(set -e; \
|
|
||||||
echo "#ifndef __ASM_OFFSETS_H__"; \
|
|
||||||
echo "#define __ASM_OFFSETS_H__"; \
|
|
||||||
echo "/*"; \
|
|
||||||
echo " * DO NOT MODIFY."; \
|
|
||||||
echo " *"; \
|
|
||||||
echo " * This file was generated by arch/$(ARCH)/Makefile"; \
|
|
||||||
echo " *"; \
|
|
||||||
echo " */"; \
|
|
||||||
echo ""; \
|
|
||||||
sed -ne "/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}"; \
|
|
||||||
echo ""; \
|
|
||||||
echo "#endif" )
|
|
||||||
endef
|
|
||||||
|
|
||||||
|
|
||||||
###
|
###
|
||||||
# Cleaning is done on three levels.
|
# Cleaning is done on three levels.
|
||||||
# make clean Delete most generated files
|
# make clean Delete most generated files
|
||||||
@ -991,7 +990,7 @@ MRPROPER_FILES += .config .config.old include/asm .version \
|
|||||||
#
|
#
|
||||||
clean: rm-dirs := $(CLEAN_DIRS)
|
clean: rm-dirs := $(CLEAN_DIRS)
|
||||||
clean: rm-files := $(CLEAN_FILES)
|
clean: rm-files := $(CLEAN_FILES)
|
||||||
clean-dirs := $(addprefix _clean_,$(vmlinux-alldirs))
|
clean-dirs := $(addprefix _clean_,$(srctree) $(vmlinux-alldirs))
|
||||||
|
|
||||||
.PHONY: $(clean-dirs) clean archclean
|
.PHONY: $(clean-dirs) clean archclean
|
||||||
$(clean-dirs):
|
$(clean-dirs):
|
||||||
@ -1070,6 +1069,7 @@ help:
|
|||||||
@echo ' rpm - Build a kernel as an RPM package'
|
@echo ' rpm - Build a kernel as an RPM package'
|
||||||
@echo ' tags/TAGS - Generate tags file for editors'
|
@echo ' tags/TAGS - Generate tags file for editors'
|
||||||
@echo ' cscope - Generate cscope index'
|
@echo ' cscope - Generate cscope index'
|
||||||
|
@echo ' kernelrelease - Output the release version string'
|
||||||
@echo ''
|
@echo ''
|
||||||
@echo 'Static analysers'
|
@echo 'Static analysers'
|
||||||
@echo ' buildcheck - List dangling references to vmlinux discarded sections'
|
@echo ' buildcheck - List dangling references to vmlinux discarded sections'
|
||||||
|
@ -9,7 +9,7 @@ screen please read "Documentation/oops-tracing.txt" before posting your
|
|||||||
bug report. This explains what you should do with the "Oops" information
|
bug report. This explains what you should do with the "Oops" information
|
||||||
to make it useful to the recipient.
|
to make it useful to the recipient.
|
||||||
|
|
||||||
Send the output the maintainer of the kernel area that seems to
|
Send the output to the maintainer of the kernel area that seems to
|
||||||
be involved with the problem. Don't worry too much about getting the
|
be involved with the problem. Don't worry too much about getting the
|
||||||
wrong person. If you are unsure send it to the person responsible for the
|
wrong person. If you are unsure send it to the person responsible for the
|
||||||
code relevant to what you were doing. If it occurs repeatably try and
|
code relevant to what you were doing. If it occurs repeatably try and
|
||||||
@ -18,7 +18,7 @@ The list of maintainers is in the MAINTAINERS file in this directory.
|
|||||||
|
|
||||||
If it is a security bug, please copy the Security Contact listed
|
If it is a security bug, please copy the Security Contact listed
|
||||||
in the MAINTAINERS file. They can help coordinate bugfix and disclosure.
|
in the MAINTAINERS file. They can help coordinate bugfix and disclosure.
|
||||||
See Documentation/SecurityBugs for more infomation.
|
See Documentation/SecurityBugs for more information.
|
||||||
|
|
||||||
If you are totally stumped as to whom to send the report, send it to
|
If you are totally stumped as to whom to send the report, send it to
|
||||||
linux-kernel@vger.kernel.org. (For more information on the linux-kernel
|
linux-kernel@vger.kernel.org. (For more information on the linux-kernel
|
||||||
@ -35,7 +35,7 @@ the command "sh scripts/ver_linux".
|
|||||||
|
|
||||||
Use that information to fill in all fields of the bug report form, and
|
Use that information to fill in all fields of the bug report form, and
|
||||||
post it to the mailing list with a subject of "PROBLEM: <one line
|
post it to the mailing list with a subject of "PROBLEM: <one line
|
||||||
summary from [1.]>" for easy identification by the developers
|
summary from [1.]>" for easy identification by the developers.
|
||||||
|
|
||||||
[1.] One line summary of the problem:
|
[1.] One line summary of the problem:
|
||||||
[2.] Full description of the problem/report:
|
[2.] Full description of the problem/report:
|
||||||
|
@ -108,20 +108,9 @@ $(boot)/vmlinux.gz: vmlinux
|
|||||||
bootimage bootpfile bootpzfile: vmlinux
|
bootimage bootpfile bootpzfile: vmlinux
|
||||||
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
||||||
|
|
||||||
|
|
||||||
prepare: include/asm-$(ARCH)/asm_offsets.h
|
|
||||||
|
|
||||||
arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
|
|
||||||
include/config/MARKER
|
|
||||||
|
|
||||||
include/asm-$(ARCH)/asm_offsets.h: arch/$(ARCH)/kernel/asm-offsets.s
|
|
||||||
$(call filechk,gen-asm-offsets)
|
|
||||||
|
|
||||||
archclean:
|
archclean:
|
||||||
$(Q)$(MAKE) $(clean)=$(boot)
|
$(Q)$(MAKE) $(clean)=$(boot)
|
||||||
|
|
||||||
CLEAN_FILES += include/asm-$(ARCH)/asm_offsets.h
|
|
||||||
|
|
||||||
define archhelp
|
define archhelp
|
||||||
echo '* boot - Compressed kernel image (arch/alpha/boot/vmlinux.gz)'
|
echo '* boot - Compressed kernel image (arch/alpha/boot/vmlinux.gz)'
|
||||||
echo ' bootimage - SRM bootable image (arch/alpha/boot/bootimage)'
|
echo ' bootimage - SRM bootable image (arch/alpha/boot/bootimage)'
|
||||||
|
@ -185,15 +185,6 @@ EXPORT_SYMBOL(smp_num_cpus);
|
|||||||
EXPORT_SYMBOL(smp_call_function);
|
EXPORT_SYMBOL(smp_call_function);
|
||||||
EXPORT_SYMBOL(smp_call_function_on_cpu);
|
EXPORT_SYMBOL(smp_call_function_on_cpu);
|
||||||
EXPORT_SYMBOL(_atomic_dec_and_lock);
|
EXPORT_SYMBOL(_atomic_dec_and_lock);
|
||||||
#ifdef CONFIG_DEBUG_SPINLOCK
|
|
||||||
EXPORT_SYMBOL(_raw_spin_unlock);
|
|
||||||
EXPORT_SYMBOL(debug_spin_lock);
|
|
||||||
EXPORT_SYMBOL(debug_spin_trylock);
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_DEBUG_RWLOCK
|
|
||||||
EXPORT_SYMBOL(_raw_write_lock);
|
|
||||||
EXPORT_SYMBOL(_raw_read_lock);
|
|
||||||
#endif
|
|
||||||
EXPORT_SYMBOL(cpu_present_mask);
|
EXPORT_SYMBOL(cpu_present_mask);
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
#include <asm/asm_offsets.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/thread_info.h>
|
#include <asm/thread_info.h>
|
||||||
#include <asm/pal.h>
|
#include <asm/pal.h>
|
||||||
#include <asm/errno.h>
|
#include <asm/errno.h>
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
#include <asm/asm_offsets.h>
|
#include <asm/asm-offsets.h>
|
||||||
|
|
||||||
.globl swapper_pg_dir
|
.globl swapper_pg_dir
|
||||||
.globl _stext
|
.globl _stext
|
||||||
|
@ -47,7 +47,7 @@ module_free(struct module *mod, void *module_region)
|
|||||||
|
|
||||||
struct got_entry {
|
struct got_entry {
|
||||||
struct got_entry *next;
|
struct got_entry *next;
|
||||||
Elf64_Addr r_offset;
|
Elf64_Sxword r_addend;
|
||||||
int got_offset;
|
int got_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -57,14 +57,14 @@ process_reloc_for_got(Elf64_Rela *rela,
|
|||||||
{
|
{
|
||||||
unsigned long r_sym = ELF64_R_SYM (rela->r_info);
|
unsigned long r_sym = ELF64_R_SYM (rela->r_info);
|
||||||
unsigned long r_type = ELF64_R_TYPE (rela->r_info);
|
unsigned long r_type = ELF64_R_TYPE (rela->r_info);
|
||||||
Elf64_Addr r_offset = rela->r_offset;
|
Elf64_Sxword r_addend = rela->r_addend;
|
||||||
struct got_entry *g;
|
struct got_entry *g;
|
||||||
|
|
||||||
if (r_type != R_ALPHA_LITERAL)
|
if (r_type != R_ALPHA_LITERAL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (g = chains + r_sym; g ; g = g->next)
|
for (g = chains + r_sym; g ; g = g->next)
|
||||||
if (g->r_offset == r_offset) {
|
if (g->r_addend == r_addend) {
|
||||||
if (g->got_offset == 0) {
|
if (g->got_offset == 0) {
|
||||||
g->got_offset = *poffset;
|
g->got_offset = *poffset;
|
||||||
*poffset += 8;
|
*poffset += 8;
|
||||||
@ -74,7 +74,7 @@ process_reloc_for_got(Elf64_Rela *rela,
|
|||||||
|
|
||||||
g = kmalloc (sizeof (*g), GFP_KERNEL);
|
g = kmalloc (sizeof (*g), GFP_KERNEL);
|
||||||
g->next = chains[r_sym].next;
|
g->next = chains[r_sym].next;
|
||||||
g->r_offset = r_offset;
|
g->r_addend = r_addend;
|
||||||
g->got_offset = *poffset;
|
g->got_offset = *poffset;
|
||||||
*poffset += 8;
|
*poffset += 8;
|
||||||
chains[r_sym].next = g;
|
chains[r_sym].next = g;
|
||||||
|
@ -974,6 +974,7 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
|
|||||||
size_t size;
|
size_t size;
|
||||||
long timeout;
|
long timeout;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
struct fdtable *fdt;
|
||||||
|
|
||||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||||
if (tvp) {
|
if (tvp) {
|
||||||
@ -995,7 +996,8 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n < 0 || n > current->files->max_fdset)
|
fdt = files_fdtable(current->files);
|
||||||
|
if (n < 0 || n > fdt->max_fdset)
|
||||||
goto out_nofds;
|
goto out_nofds;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1152,8 +1154,7 @@ osf_usleep_thread(struct timeval32 __user *sleep, struct timeval32 __user *remai
|
|||||||
|
|
||||||
ticks = timeval_to_jiffies(&tmp);
|
ticks = timeval_to_jiffies(&tmp);
|
||||||
|
|
||||||
current->state = TASK_INTERRUPTIBLE;
|
ticks = schedule_timeout_interruptible(ticks);
|
||||||
ticks = schedule_timeout(ticks);
|
|
||||||
|
|
||||||
if (remain) {
|
if (remain) {
|
||||||
jiffies_to_timeval(ticks, &tmp);
|
jiffies_to_timeval(ticks, &tmp);
|
||||||
|
@ -989,175 +989,3 @@ flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
|
|||||||
|
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_SPINLOCK
|
|
||||||
void
|
|
||||||
_raw_spin_unlock(spinlock_t * lock)
|
|
||||||
{
|
|
||||||
mb();
|
|
||||||
lock->lock = 0;
|
|
||||||
|
|
||||||
lock->on_cpu = -1;
|
|
||||||
lock->previous = NULL;
|
|
||||||
lock->task = NULL;
|
|
||||||
lock->base_file = "none";
|
|
||||||
lock->line_no = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
debug_spin_lock(spinlock_t * lock, const char *base_file, int line_no)
|
|
||||||
{
|
|
||||||
long tmp;
|
|
||||||
long stuck;
|
|
||||||
void *inline_pc = __builtin_return_address(0);
|
|
||||||
unsigned long started = jiffies;
|
|
||||||
int printed = 0;
|
|
||||||
int cpu = smp_processor_id();
|
|
||||||
|
|
||||||
stuck = 1L << 30;
|
|
||||||
try_again:
|
|
||||||
|
|
||||||
/* Use sub-sections to put the actual loop at the end
|
|
||||||
of this object file's text section so as to perfect
|
|
||||||
branch prediction. */
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"1: ldl_l %0,%1\n"
|
|
||||||
" subq %2,1,%2\n"
|
|
||||||
" blbs %0,2f\n"
|
|
||||||
" or %0,1,%0\n"
|
|
||||||
" stl_c %0,%1\n"
|
|
||||||
" beq %0,3f\n"
|
|
||||||
"4: mb\n"
|
|
||||||
".subsection 2\n"
|
|
||||||
"2: ldl %0,%1\n"
|
|
||||||
" subq %2,1,%2\n"
|
|
||||||
"3: blt %2,4b\n"
|
|
||||||
" blbs %0,2b\n"
|
|
||||||
" br 1b\n"
|
|
||||||
".previous"
|
|
||||||
: "=r" (tmp), "=m" (lock->lock), "=r" (stuck)
|
|
||||||
: "m" (lock->lock), "2" (stuck) : "memory");
|
|
||||||
|
|
||||||
if (stuck < 0) {
|
|
||||||
printk(KERN_WARNING
|
|
||||||
"%s:%d spinlock stuck in %s at %p(%d)"
|
|
||||||
" owner %s at %p(%d) %s:%d\n",
|
|
||||||
base_file, line_no,
|
|
||||||
current->comm, inline_pc, cpu,
|
|
||||||
lock->task->comm, lock->previous,
|
|
||||||
lock->on_cpu, lock->base_file, lock->line_no);
|
|
||||||
stuck = 1L << 36;
|
|
||||||
printed = 1;
|
|
||||||
goto try_again;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Exiting. Got the lock. */
|
|
||||||
lock->on_cpu = cpu;
|
|
||||||
lock->previous = inline_pc;
|
|
||||||
lock->task = current;
|
|
||||||
lock->base_file = base_file;
|
|
||||||
lock->line_no = line_no;
|
|
||||||
|
|
||||||
if (printed) {
|
|
||||||
printk(KERN_WARNING
|
|
||||||
"%s:%d spinlock grabbed in %s at %p(%d) %ld ticks\n",
|
|
||||||
base_file, line_no, current->comm, inline_pc,
|
|
||||||
cpu, jiffies - started);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
debug_spin_trylock(spinlock_t * lock, const char *base_file, int line_no)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
if ((ret = !test_and_set_bit(0, lock))) {
|
|
||||||
lock->on_cpu = smp_processor_id();
|
|
||||||
lock->previous = __builtin_return_address(0);
|
|
||||||
lock->task = current;
|
|
||||||
} else {
|
|
||||||
lock->base_file = base_file;
|
|
||||||
lock->line_no = line_no;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_DEBUG_SPINLOCK */
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_RWLOCK
|
|
||||||
void _raw_write_lock(rwlock_t * lock)
|
|
||||||
{
|
|
||||||
long regx, regy;
|
|
||||||
int stuck_lock, stuck_reader;
|
|
||||||
void *inline_pc = __builtin_return_address(0);
|
|
||||||
|
|
||||||
try_again:
|
|
||||||
|
|
||||||
stuck_lock = 1<<30;
|
|
||||||
stuck_reader = 1<<30;
|
|
||||||
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"1: ldl_l %1,%0\n"
|
|
||||||
" blbs %1,6f\n"
|
|
||||||
" blt %1,8f\n"
|
|
||||||
" mov 1,%1\n"
|
|
||||||
" stl_c %1,%0\n"
|
|
||||||
" beq %1,6f\n"
|
|
||||||
"4: mb\n"
|
|
||||||
".subsection 2\n"
|
|
||||||
"6: blt %3,4b # debug\n"
|
|
||||||
" subl %3,1,%3 # debug\n"
|
|
||||||
" ldl %1,%0\n"
|
|
||||||
" blbs %1,6b\n"
|
|
||||||
"8: blt %4,4b # debug\n"
|
|
||||||
" subl %4,1,%4 # debug\n"
|
|
||||||
" ldl %1,%0\n"
|
|
||||||
" blt %1,8b\n"
|
|
||||||
" br 1b\n"
|
|
||||||
".previous"
|
|
||||||
: "=m" (*(volatile int *)lock), "=&r" (regx), "=&r" (regy),
|
|
||||||
"=&r" (stuck_lock), "=&r" (stuck_reader)
|
|
||||||
: "m" (*(volatile int *)lock), "3" (stuck_lock), "4" (stuck_reader) : "memory");
|
|
||||||
|
|
||||||
if (stuck_lock < 0) {
|
|
||||||
printk(KERN_WARNING "write_lock stuck at %p\n", inline_pc);
|
|
||||||
goto try_again;
|
|
||||||
}
|
|
||||||
if (stuck_reader < 0) {
|
|
||||||
printk(KERN_WARNING "write_lock stuck on readers at %p\n",
|
|
||||||
inline_pc);
|
|
||||||
goto try_again;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _raw_read_lock(rwlock_t * lock)
|
|
||||||
{
|
|
||||||
long regx;
|
|
||||||
int stuck_lock;
|
|
||||||
void *inline_pc = __builtin_return_address(0);
|
|
||||||
|
|
||||||
try_again:
|
|
||||||
|
|
||||||
stuck_lock = 1<<30;
|
|
||||||
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"1: ldl_l %1,%0;"
|
|
||||||
" blbs %1,6f;"
|
|
||||||
" subl %1,2,%1;"
|
|
||||||
" stl_c %1,%0;"
|
|
||||||
" beq %1,6f;"
|
|
||||||
"4: mb\n"
|
|
||||||
".subsection 2\n"
|
|
||||||
"6: ldl %1,%0;"
|
|
||||||
" blt %2,4b # debug\n"
|
|
||||||
" subl %2,1,%2 # debug\n"
|
|
||||||
" blbs %1,6b;"
|
|
||||||
" br 1b\n"
|
|
||||||
".previous"
|
|
||||||
: "=m" (*(volatile int *)lock), "=&r" (regx), "=&r" (stuck_lock)
|
|
||||||
: "m" (*(volatile int *)lock), "2" (stuck_lock) : "memory");
|
|
||||||
|
|
||||||
if (stuck_lock < 0) {
|
|
||||||
printk(KERN_WARNING "read_lock stuck at %p\n", inline_pc);
|
|
||||||
goto try_again;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_DEBUG_RWLOCK */
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Verify that we have not overflowed the stack. Oops if we have.
|
* Verify that we have not overflowed the stack. Oops if we have.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <asm/asm_offsets.h>
|
#include <asm/asm-offsets.h>
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.set noat
|
.set noat
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* uninitialized local variables in the act.
|
* uninitialized local variables in the act.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <asm/asm_offsets.h>
|
#include <asm/asm-offsets.h>
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.set noat
|
.set noat
|
||||||
|
@ -326,8 +326,8 @@ config SMP
|
|||||||
processor machines. On a single processor machine, the kernel will
|
processor machines. On a single processor machine, the kernel will
|
||||||
run faster if you say N here.
|
run faster if you say N here.
|
||||||
|
|
||||||
See also the <file:Documentation/smp.tex>,
|
See also the <file:Documentation/smp.txt>,
|
||||||
<file:Documentation/smp.txt>, <file:Documentation/i386/IO-APIC.txt>,
|
<file:Documentation/i386/IO-APIC.txt>,
|
||||||
<file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
|
<file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
|
||||||
<http://www.linuxdoc.org/docs.html#howto>.
|
<http://www.linuxdoc.org/docs.html#howto>.
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ config DEBUG_LL
|
|||||||
bool "Kernel low-level debugging functions"
|
bool "Kernel low-level debugging functions"
|
||||||
depends on DEBUG_KERNEL
|
depends on DEBUG_KERNEL
|
||||||
help
|
help
|
||||||
Say Y here to include definitions of printascii, printchar, printhex
|
Say Y here to include definitions of printascii, printch, printhex
|
||||||
in the kernel. This is helpful if you are debugging code that
|
in the kernel. This is helpful if you are debugging code that
|
||||||
executes before the console is initialized.
|
executes before the console is initialized.
|
||||||
|
|
||||||
|
@ -175,10 +175,10 @@ else
|
|||||||
endif
|
endif
|
||||||
@touch $@
|
@touch $@
|
||||||
|
|
||||||
prepare: maketools include/asm-arm/.arch
|
archprepare: maketools include/asm-arm/.arch
|
||||||
|
|
||||||
.PHONY: maketools FORCE
|
.PHONY: maketools FORCE
|
||||||
maketools: include/asm-arm/constants.h include/linux/version.h FORCE
|
maketools: include/linux/version.h FORCE
|
||||||
$(Q)$(MAKE) $(build)=arch/arm/tools include/asm-arm/mach-types.h
|
$(Q)$(MAKE) $(build)=arch/arm/tools include/asm-arm/mach-types.h
|
||||||
|
|
||||||
# Convert bzImage to zImage
|
# Convert bzImage to zImage
|
||||||
@ -190,7 +190,7 @@ zImage Image xipImage bootpImage uImage: vmlinux
|
|||||||
zinstall install: vmlinux
|
zinstall install: vmlinux
|
||||||
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
|
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
|
||||||
|
|
||||||
CLEAN_FILES += include/asm-arm/constants.h* include/asm-arm/mach-types.h \
|
CLEAN_FILES += include/asm-arm/mach-types.h \
|
||||||
include/asm-arm/arch include/asm-arm/.arch
|
include/asm-arm/arch include/asm-arm/.arch
|
||||||
|
|
||||||
# We use MRPROPER_FILES and CLEAN_FILES now
|
# We use MRPROPER_FILES and CLEAN_FILES now
|
||||||
@ -201,11 +201,6 @@ archclean:
|
|||||||
bp:; $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/bootpImage
|
bp:; $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/bootpImage
|
||||||
i zi:; $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
|
i zi:; $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
|
||||||
|
|
||||||
arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
|
|
||||||
include/asm-arm/.arch
|
|
||||||
|
|
||||||
include/asm-$(ARCH)/constants.h: arch/$(ARCH)/kernel/asm-offsets.s
|
|
||||||
$(call filechk,gen-asm-offsets)
|
|
||||||
|
|
||||||
define archhelp
|
define archhelp
|
||||||
echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage)'
|
echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage)'
|
||||||
|
@ -91,7 +91,7 @@ EXPORT_SYMBOL(read_scoop_reg);
|
|||||||
EXPORT_SYMBOL(write_scoop_reg);
|
EXPORT_SYMBOL(write_scoop_reg);
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
static int scoop_suspend(struct device *dev, uint32_t state, uint32_t level)
|
static int scoop_suspend(struct device *dev, pm_message_t state, uint32_t level)
|
||||||
{
|
{
|
||||||
if (level == SUSPEND_POWER_DOWN) {
|
if (level == SUSPEND_POWER_DOWN) {
|
||||||
struct scoop_dev *sdev = dev_get_drvdata(dev);
|
struct scoop_dev *sdev = dev_get_drvdata(dev);
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* This file is included twice in entry-common.S
|
* This file is included twice in entry-common.S
|
||||||
*/
|
*/
|
||||||
#ifndef NR_syscalls
|
#ifndef NR_syscalls
|
||||||
#define NR_syscalls 320
|
#define NR_syscalls 328
|
||||||
#else
|
#else
|
||||||
|
|
||||||
__syscall_start:
|
__syscall_start:
|
||||||
@ -333,6 +333,9 @@ __syscall_start:
|
|||||||
.long sys_inotify_init
|
.long sys_inotify_init
|
||||||
.long sys_inotify_add_watch
|
.long sys_inotify_add_watch
|
||||||
.long sys_inotify_rm_watch
|
.long sys_inotify_rm_watch
|
||||||
|
.long sys_mbind_wrapper
|
||||||
|
/* 320 */ .long sys_get_mempolicy
|
||||||
|
.long sys_set_mempolicy
|
||||||
__syscall_end:
|
__syscall_end:
|
||||||
|
|
||||||
.rept NR_syscalls - (__syscall_end - __syscall_start) / 4
|
.rept NR_syscalls - (__syscall_end - __syscall_start) / 4
|
||||||
|
@ -269,6 +269,10 @@ sys_arm_fadvise64_64_wrapper:
|
|||||||
str r5, [sp, #4] @ push r5 to stack
|
str r5, [sp, #4] @ push r5 to stack
|
||||||
b sys_arm_fadvise64_64
|
b sys_arm_fadvise64_64
|
||||||
|
|
||||||
|
sys_mbind_wrapper:
|
||||||
|
str r5, [sp, #4]
|
||||||
|
b sys_mbind
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: off_4k (r5) is always units of 4K. If we can't do the requested
|
* Note: off_4k (r5) is always units of 4K. If we can't do the requested
|
||||||
* offset, we return EINVAL.
|
* offset, we return EINVAL.
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
|
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/errno.h>
|
#include <asm/errno.h>
|
||||||
#include <asm/thread_info.h>
|
#include <asm/thread_info.h>
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include <asm/mach-types.h>
|
#include <asm/mach-types.h>
|
||||||
#include <asm/procinfo.h>
|
#include <asm/procinfo.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/thread_info.h>
|
#include <asm/thread_info.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
#include <asm/thread_info.h>
|
#include <asm/thread_info.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
|
|
||||||
#define MMX_WR0 (0x00)
|
#define MMX_WR0 (0x00)
|
||||||
#define MMX_WR1 (0x08)
|
#define MMX_WR1 (0x08)
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
|
|
||||||
#define COPY_COUNT (PAGE_SZ/64 PLD( -1 ))
|
#define COPY_COUNT (PAGE_SZ/64 PLD( -1 ))
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
#include <asm/errno.h>
|
#include <asm/errno.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
|
|
||||||
.text
|
.text
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
* Note that ADDR_LIMIT is either 0 or 0xc0000000.
|
* Note that ADDR_LIMIT is either 0 or 0xc0000000.
|
||||||
* Note also that it is intended that __get_user_bad is not global.
|
* Note also that it is intended that __get_user_bad is not global.
|
||||||
*/
|
*/
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/thread_info.h>
|
#include <asm/thread_info.h>
|
||||||
#include <asm/errno.h>
|
#include <asm/errno.h>
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
* Note that ADDR_LIMIT is either 0 or 0xc0000000
|
* Note that ADDR_LIMIT is either 0 or 0xc0000000
|
||||||
* Note also that it is intended that __put_user_bad is not global.
|
* Note also that it is intended that __put_user_bad is not global.
|
||||||
*/
|
*/
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/thread_info.h>
|
#include <asm/thread_info.h>
|
||||||
#include <asm/errno.h>
|
#include <asm/errno.h>
|
||||||
|
|
||||||
|
@ -131,27 +131,12 @@ static struct platform_device corgits_device = {
|
|||||||
/*
|
/*
|
||||||
* MMC/SD Device
|
* MMC/SD Device
|
||||||
*
|
*
|
||||||
* The card detect interrupt isn't debounced so we delay it by HZ/4
|
* The card detect interrupt isn't debounced so we delay it by 250ms
|
||||||
* to give the card a chance to fully insert/eject.
|
* to give the card a chance to fully insert/eject.
|
||||||
*/
|
*/
|
||||||
static struct mmc_detect {
|
static struct pxamci_platform_data corgi_mci_platform_data;
|
||||||
struct timer_list detect_timer;
|
|
||||||
void *devid;
|
|
||||||
} mmc_detect;
|
|
||||||
|
|
||||||
static void mmc_detect_callback(unsigned long data)
|
static int corgi_mci_init(struct device *dev, irqreturn_t (*corgi_detect_int)(int, void *, struct pt_regs *), void *data)
|
||||||
{
|
|
||||||
mmc_detect_change(mmc_detect.devid);
|
|
||||||
}
|
|
||||||
|
|
||||||
static irqreturn_t corgi_mmc_detect_int(int irq, void *devid, struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
mmc_detect.devid=devid;
|
|
||||||
mod_timer(&mmc_detect.detect_timer, jiffies + HZ/4);
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int corgi_mci_init(struct device *dev, irqreturn_t (*unused_detect_int)(int, void *, struct pt_regs *), void *data)
|
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@ -161,11 +146,9 @@ static int corgi_mci_init(struct device *dev, irqreturn_t (*unused_detect_int)(i
|
|||||||
pxa_gpio_mode(CORGI_GPIO_nSD_DETECT | GPIO_IN);
|
pxa_gpio_mode(CORGI_GPIO_nSD_DETECT | GPIO_IN);
|
||||||
pxa_gpio_mode(CORGI_GPIO_SD_PWR | GPIO_OUT);
|
pxa_gpio_mode(CORGI_GPIO_SD_PWR | GPIO_OUT);
|
||||||
|
|
||||||
init_timer(&mmc_detect.detect_timer);
|
corgi_mci_platform_data.detect_delay = msecs_to_jiffies(250);
|
||||||
mmc_detect.detect_timer.function = mmc_detect_callback;
|
|
||||||
mmc_detect.detect_timer.data = (unsigned long) &mmc_detect;
|
|
||||||
|
|
||||||
err = request_irq(CORGI_IRQ_GPIO_nSD_DETECT, corgi_mmc_detect_int, SA_INTERRUPT,
|
err = request_irq(CORGI_IRQ_GPIO_nSD_DETECT, corgi_detect_int, SA_INTERRUPT,
|
||||||
"MMC card detect", data);
|
"MMC card detect", data);
|
||||||
if (err) {
|
if (err) {
|
||||||
printk(KERN_ERR "corgi_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
|
printk(KERN_ERR "corgi_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
|
||||||
@ -198,7 +181,6 @@ static int corgi_mci_get_ro(struct device *dev)
|
|||||||
static void corgi_mci_exit(struct device *dev, void *data)
|
static void corgi_mci_exit(struct device *dev, void *data)
|
||||||
{
|
{
|
||||||
free_irq(CORGI_IRQ_GPIO_nSD_DETECT, data);
|
free_irq(CORGI_IRQ_GPIO_nSD_DETECT, data);
|
||||||
del_timer(&mmc_detect.detect_timer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pxamci_platform_data corgi_mci_platform_data = {
|
static struct pxamci_platform_data corgi_mci_platform_data = {
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
#include <asm/arch/corgi.h>
|
#include <asm/arch/corgi.h>
|
||||||
#include <asm/arch/pxa-regs.h>
|
#include <asm/arch/pxa-regs.h>
|
||||||
|
|
||||||
static spinlock_t corgi_ssp_lock = SPIN_LOCK_UNLOCKED;
|
static DEFINE_SPINLOCK(corgi_ssp_lock);
|
||||||
static struct ssp_dev corgi_ssp_dev;
|
static struct ssp_dev corgi_ssp_dev;
|
||||||
static struct ssp_state corgi_ssp_state;
|
static struct ssp_state corgi_ssp_state;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
#include <asm/mach/arch.h>
|
#include <asm/mach/arch.h>
|
||||||
#include <asm/mach/map.h>
|
#include <asm/mach/map.h>
|
||||||
#include <asm/mach/irq.h>
|
#include <asm/mach/irq.h>
|
||||||
|
#include <asm/arch/fb.h>
|
||||||
#include <asm/hardware.h>
|
#include <asm/hardware.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
@ -103,6 +103,15 @@ struct platform_device s3c_device_lcd = {
|
|||||||
|
|
||||||
EXPORT_SYMBOL(s3c_device_lcd);
|
EXPORT_SYMBOL(s3c_device_lcd);
|
||||||
|
|
||||||
|
static struct s3c2410fb_mach_info s3c2410fb_info;
|
||||||
|
|
||||||
|
void __init set_s3c2410fb_info(struct s3c2410fb_mach_info *hard_s3c2410fb_info)
|
||||||
|
{
|
||||||
|
memcpy(&s3c2410fb_info,hard_s3c2410fb_info,sizeof(struct s3c2410fb_mach_info));
|
||||||
|
s3c_device_lcd.dev.platform_data = &s3c2410fb_info;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(set_s3c2410fb_info);
|
||||||
|
|
||||||
/* NAND Controller */
|
/* NAND Controller */
|
||||||
|
|
||||||
static struct resource s3c_nand_resource[] = {
|
static struct resource s3c_nand_resource[] = {
|
||||||
|
@ -45,6 +45,9 @@
|
|||||||
|
|
||||||
//#include <asm/debug-ll.h>
|
//#include <asm/debug-ll.h>
|
||||||
#include <asm/arch/regs-serial.h>
|
#include <asm/arch/regs-serial.h>
|
||||||
|
#include <asm/arch/regs-lcd.h>
|
||||||
|
|
||||||
|
#include <asm/arch/fb.h>
|
||||||
|
|
||||||
#include <linux/serial_core.h>
|
#include <linux/serial_core.h>
|
||||||
|
|
||||||
@ -88,6 +91,48 @@ static struct s3c2410_uartcfg h1940_uartcfgs[] = {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set lcd on or off
|
||||||
|
**/
|
||||||
|
static struct s3c2410fb_mach_info h1940_lcdcfg __initdata = {
|
||||||
|
.fixed_syncs= 1,
|
||||||
|
.regs={
|
||||||
|
.lcdcon1= S3C2410_LCDCON1_TFT16BPP | \
|
||||||
|
S3C2410_LCDCON1_TFT | \
|
||||||
|
S3C2410_LCDCON1_CLKVAL(0x0C),
|
||||||
|
|
||||||
|
.lcdcon2= S3C2410_LCDCON2_VBPD(7) | \
|
||||||
|
S3C2410_LCDCON2_LINEVAL(319) | \
|
||||||
|
S3C2410_LCDCON2_VFPD(6) | \
|
||||||
|
S3C2410_LCDCON2_VSPW(0),
|
||||||
|
|
||||||
|
.lcdcon3= S3C2410_LCDCON3_HBPD(19) | \
|
||||||
|
S3C2410_LCDCON3_HOZVAL(239) | \
|
||||||
|
S3C2410_LCDCON3_HFPD(7),
|
||||||
|
|
||||||
|
.lcdcon4= S3C2410_LCDCON4_MVAL(0) | \
|
||||||
|
S3C2410_LCDCON4_HSPW(3),
|
||||||
|
|
||||||
|
.lcdcon5= S3C2410_LCDCON5_FRM565 | \
|
||||||
|
S3C2410_LCDCON5_INVVLINE | \
|
||||||
|
S3C2410_LCDCON5_HWSWP,
|
||||||
|
},
|
||||||
|
.lpcsel= 0x02,
|
||||||
|
.gpccon= 0xaa940659,
|
||||||
|
.gpccon_mask= 0xffffffff,
|
||||||
|
.gpcup= 0x0000ffff,
|
||||||
|
.gpcup_mask= 0xffffffff,
|
||||||
|
.gpdcon= 0xaa84aaa0,
|
||||||
|
.gpdcon_mask= 0xffffffff,
|
||||||
|
.gpdup= 0x0000faff,
|
||||||
|
.gpdup_mask= 0xffffffff,
|
||||||
|
|
||||||
|
.width= 240,
|
||||||
|
.height= 320,
|
||||||
|
.xres= {240,240,240},
|
||||||
|
.yres= {320,320,320},
|
||||||
|
.bpp= {16,16,16},
|
||||||
|
};
|
||||||
|
|
||||||
static struct platform_device *h1940_devices[] __initdata = {
|
static struct platform_device *h1940_devices[] __initdata = {
|
||||||
&s3c_device_usb,
|
&s3c_device_usb,
|
||||||
@ -116,6 +161,11 @@ void __init h1940_init_irq(void)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __init h1940_init(void)
|
||||||
|
{
|
||||||
|
set_s3c2410fb_info(&h1940_lcdcfg);
|
||||||
|
}
|
||||||
|
|
||||||
MACHINE_START(H1940, "IPAQ-H1940")
|
MACHINE_START(H1940, "IPAQ-H1940")
|
||||||
/* Maintainer: Ben Dooks <ben@fluff.org> */
|
/* Maintainer: Ben Dooks <ben@fluff.org> */
|
||||||
.phys_ram = S3C2410_SDRAM_PA,
|
.phys_ram = S3C2410_SDRAM_PA,
|
||||||
@ -124,5 +174,6 @@ MACHINE_START(H1940, "IPAQ-H1940")
|
|||||||
.boot_params = S3C2410_SDRAM_PA + 0x100,
|
.boot_params = S3C2410_SDRAM_PA + 0x100,
|
||||||
.map_io = h1940_map_io,
|
.map_io = h1940_map_io,
|
||||||
.init_irq = h1940_init_irq,
|
.init_irq = h1940_init_irq,
|
||||||
|
.init_machine = h1940_init,
|
||||||
.timer = &s3c24xx_timer,
|
.timer = &s3c24xx_timer,
|
||||||
MACHINE_END
|
MACHINE_END
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.align 5
|
.align 5
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.align 5
|
.align 5
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.align 5
|
.align 5
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/procinfo.h>
|
#include <asm/procinfo.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/procinfo.h>
|
#include <asm/procinfo.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/procinfo.h>
|
#include <asm/procinfo.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/procinfo.h>
|
#include <asm/procinfo.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/procinfo.h>
|
#include <asm/procinfo.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/procinfo.h>
|
#include <asm/procinfo.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* VMA_VM_FLAGS
|
* VMA_VM_FLAGS
|
||||||
* VM_EXEC
|
* VM_EXEC
|
||||||
*/
|
*/
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/thread_info.h>
|
#include <asm/thread_info.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/procinfo.h>
|
#include <asm/procinfo.h>
|
||||||
#include <asm/hardware.h>
|
#include <asm/hardware.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
#include <asm/constants.h>
|
#include <asm/asm-offsets.h>
|
||||||
#include <asm/procinfo.h>
|
#include <asm/procinfo.h>
|
||||||
#include <asm/hardware.h>
|
#include <asm/hardware.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user