Merge branch 'driver-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6

* 'driver-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6: (50 commits)
  printk: do not mangle valid userspace syslog prefixes
  efivars: Add Documentation
  efivars: Expose efivars functionality to external drivers.
  efivars: Parameterize operations.
  efivars: Split out variable registration
  efivars: parameterize efivars
  efivars: Make efivars bin_attributes dynamic
  efivars: move efivars globals into struct efivars
  drivers:misc: ti-st: fix debugging code
  kref: Fix typo in kref documentation
  UIO: add PRUSS UIO driver support
  Fix spelling mistakes in Documentation/zh_CN/SubmittingPatches
  firmware: Fix unaligned memory accesses in dmi-sysfs
  firmware: Add documentation for /sys/firmware/dmi
  firmware: Expose DMI type 15 System Event Log
  firmware: Break out system_event_log in dmi-sysfs
  firmware: Basic dmi-sysfs support
  firmware: Add DMI entry types to the headers
  Driver core: convert platform_{get,set}_drvdata to static inline functions
  Translate linux-2.6/Documentation/magic-number.txt into Chinese
  ...
This commit is contained in:
Linus Torvalds
2011-03-16 15:05:40 -07:00
44 changed files with 2891 additions and 914 deletions
@@ -0,0 +1,75 @@
What: /sys/firmware/efi/vars
Date: April 2004
Contact: Matt Domsch <Matt_Domsch@dell.com>
Description:
This directory exposes interfaces for interactive with
EFI variables. For more information on EFI variables,
see 'Variable Services' in the UEFI specification
(section 7.2 in specification version 2.3 Errata D).
In summary, EFI variables are named, and are classified
into separate namespaces through the use of a vendor
GUID. They also have an arbitrary binary value
associated with them.
The efivars module enumerates these variables and
creates a separate directory for each one found. Each
directory has a name of the form "<key>-<vendor guid>"
and contains the following files:
attributes: A read-only text file enumerating the
EFI variable flags. Potential values
include:
EFI_VARIABLE_NON_VOLATILE
EFI_VARIABLE_BOOTSERVICE_ACCESS
EFI_VARIABLE_RUNTIME_ACCESS
EFI_VARIABLE_HARDWARE_ERROR_RECORD
EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
See the EFI documentation for an
explanation of each of these variables.
data: A read-only binary file that can be read
to attain the value of the EFI variable
guid: The vendor GUID of the variable. This
should always match the GUID in the
variable's name.
raw_var: A binary file that can be read to obtain
a structure that contains everything
there is to know about the variable.
For structure definition see "struct
efi_variable" in the kernel sources.
This file can also be written to in
order to update the value of a variable.
For this to work however, all fields of
the "struct efi_variable" passed must
match byte for byte with the structure
read out of the file, save for the value
portion.
**Note** the efi_variable structure
read/written with this file contains a
'long' type that may change widths
depending on your underlying
architecture.
size: As ASCII representation of the size of
the variable's value.
In addition, two other magic binary files are provided
in the top-level directory and are used for adding and
removing variables:
new_var: Takes a "struct efi_variable" and
instructs the EFI firmware to create a
new variable.
del_var: Takes a "struct efi_variable" and
instructs the EFI firmware to remove any
variable that has a matching vendor GUID
and variable key name.
@@ -0,0 +1,110 @@
What: /sys/firmware/dmi/
Date: February 2011
Contact: Mike Waychison <mikew@google.com>
Description:
Many machines' firmware (x86 and ia64) export DMI /
SMBIOS tables to the operating system. Getting at this
information is often valuable to userland, especially in
cases where there are OEM extensions used.
The kernel itself does not rely on the majority of the
information in these tables being correct. It equally
cannot ensure that the data as exported to userland is
without error either.
DMI is structured as a large table of entries, where
each entry has a common header indicating the type and
length of the entry, as well as 'handle' that is
supposed to be unique amongst all entries.
Some entries are required by the specification, but many
others are optional. In general though, users should
never expect to find a specific entry type on their
system unless they know for certain what their firmware
is doing. Machine to machine will vary.
Multiple entries of the same type are allowed. In order
to handle these duplicate entry types, each entry is
assigned by the operating system an 'instance', which is
derived from an entry type's ordinal position. That is
to say, if there are 'N' multiple entries with the same type
'T' in the DMI tables (adjacent or spread apart, it
doesn't matter), they will be represented in sysfs as
entries "T-0" through "T-(N-1)":
Example entry directories:
/sys/firmware/dmi/entries/17-0
/sys/firmware/dmi/entries/17-1
/sys/firmware/dmi/entries/17-2
/sys/firmware/dmi/entries/17-3
...
Instance numbers are used in lieu of the firmware
assigned entry handles as the kernel itself makes no
guarantees that handles as exported are unique, and
there are likely firmware images that get this wrong in
the wild.
Each DMI entry in sysfs has the common header values
exported as attributes:
handle : The 16bit 'handle' that is assigned to this
entry by the firmware. This handle may be
referred to by other entries.
length : The length of the entry, as presented in the
entry itself. Note that this is _not the
total count of bytes associated with the
entry_. This value represents the length of
the "formatted" portion of the entry. This
"formatted" region is sometimes followed by
the "unformatted" region composed of nul
terminated strings, with termination signalled
by a two nul characters in series.
raw : The raw bytes of the entry. This includes the
"formatted" portion of the entry, the
"unformatted" strings portion of the entry,
and the two terminating nul characters.
type : The type of the entry. This value is the same
as found in the directory name. It indicates
how the rest of the entry should be
interpreted.
instance: The instance ordinal of the entry for the
given type. This value is the same as found
in the parent directory name.
position: The position of the entry within the entirety
of the entirety.
=== Entry Specialization ===
Some entry types may have other information available in
sysfs.
--- Type 15 - System Event Log ---
This entry allows the firmware to export a log of
events the system has taken. This information is
typically backed by nvram, but the implementation
details are abstracted by this table. This entries data
is exported in the directory:
/sys/firmware/dmi/entries/15-0/system_event_log
and has the following attributes (documented in the
SMBIOS / DMI specification under "System Event Log (Type 15)":
area_length
header_start_offset
data_start_offset
access_method
status
change_token
access_method_address
header_format
per_log_type_descriptor_length
type_descriptors_supported_count
As well, the kernel exports the binary attribute:
raw_event_log : The raw binary bits of the event log
as described by the DMI entry.
@@ -0,0 +1,48 @@
What: /sys/devices/platform/kim/dev_name
Date: January 2010
KernelVersion: 2.6.38
Contact: "Pavan Savoy" <pavan_savoy@ti.com>
Description:
Name of the UART device at which the WL128x chip
is connected. example: "/dev/ttyS0".
The device name flows down to architecture specific board
initialization file from the SFI/ATAGS bootloader
firmware. The name exposed is read from the user-space
dameon and opens the device when install is requested.
What: /sys/devices/platform/kim/baud_rate
Date: January 2010
KernelVersion: 2.6.38
Contact: "Pavan Savoy" <pavan_savoy@ti.com>
Description:
The maximum reliable baud-rate the host can support.
Different platforms tend to have different high-speed
UART configurations, so the baud-rate needs to be set
locally and also sent across to the WL128x via a HCI-VS
command. The entry is read and made use by the user-space
daemon when the ldisc install is requested.
What: /sys/devices/platform/kim/flow_cntrl
Date: January 2010
KernelVersion: 2.6.38
Contact: "Pavan Savoy" <pavan_savoy@ti.com>
Description:
The WL128x makes use of flow control mechanism, and this
entry most often should be 1, the host's UART is required
to have the capability of flow-control, or else this
entry can be made use of for exceptions.
What: /sys/devices/platform/kim/install
Date: January 2010
KernelVersion: 2.6.38
Contact: "Pavan Savoy" <pavan_savoy@ti.com>
Description:
When one of the protocols Bluetooth, FM or GPS wants to make
use of the shared UART transport, it registers to the shared
transport driver, which will signal the user-space for opening,
configuring baud and install line discipline via this sysfs
entry. This entry would be polled upon by the user-space
daemon managing the UART, and is notified about the change
by the sysfs_notify. The value would be '1' when UART needs
to be opened/ldisc installed, and would be '0' when UART
is no more required and needs to be closed.
+10 -2
View File
@@ -205,12 +205,20 @@ of the characters:
The flags are: The flags are:
f
Include the function name in the printed message
l
Include line number in the printed message
m
Include module name in the printed message
p p
Causes a printk() message to be emitted to dmesg Causes a printk() message to be emitted to dmesg
t
Include thread ID in messages not generated from interrupt context
Note the regexp ^[-+=][scp]+$ matches a flags specification. Note the regexp ^[-+=][flmpt]+$ matches a flags specification.
Note also that there is no convenient syntax to remove all Note also that there is no convenient syntax to remove all
the flags at once, you need to use "-psc". the flags at once, you need to use "-flmpt".
Debug messages during boot process Debug messages during boot process
+9 -7
View File
@@ -39,10 +39,12 @@ userspace. Top-level directories in sysfs represent the common
ancestors of object hierarchies; i.e. the subsystems the objects ancestors of object hierarchies; i.e. the subsystems the objects
belong to. belong to.
Sysfs internally stores the kobject that owns the directory in the Sysfs internally stores a pointer to the kobject that implements a
->d_fsdata pointer of the directory's dentry. This allows sysfs to do directory in the sysfs_dirent object associated with the directory. In
reference counting directly on the kobject when the file is opened and the past this kobject pointer has been used by sysfs to do reference
closed. counting directly on the kobject whenever the file is opened or closed.
With the current sysfs implementation the kobject reference count is
only modified directly by the function sysfs_schedule_callback().
Attributes Attributes
@@ -208,9 +210,9 @@ Other notes:
is 4096. is 4096.
- show() methods should return the number of bytes printed into the - show() methods should return the number of bytes printed into the
buffer. This is the return value of snprintf(). buffer. This is the return value of scnprintf().
- show() should always use snprintf(). - show() should always use scnprintf().
- store() should return the number of bytes used from the buffer. If the - store() should return the number of bytes used from the buffer. If the
entire buffer has been used, just return the count argument. entire buffer has been used, just return the count argument.
@@ -229,7 +231,7 @@ A very simple (and naive) implementation of a device attribute is:
static ssize_t show_name(struct device *dev, struct device_attribute *attr, static ssize_t show_name(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
return snprintf(buf, PAGE_SIZE, "%s\n", dev->name); return scnprintf(buf, PAGE_SIZE, "%s\n", dev->name);
} }
static ssize_t store_name(struct device *dev, struct device_attribute *attr, static ssize_t store_name(struct device *dev, struct device_attribute *attr,
+1 -1
View File
@@ -156,7 +156,7 @@ static struct my_data *get_entry()
struct my_data *entry = NULL; struct my_data *entry = NULL;
mutex_lock(&mutex); mutex_lock(&mutex);
if (!list_empty(&q)) { if (!list_empty(&q)) {
entry = container_of(q.next, struct my_q_entry, link); entry = container_of(q.next, struct my_data, link);
kref_get(&entry->refcount); kref_get(&entry->refcount);
} }
mutex_unlock(&mutex); mutex_unlock(&mutex);
+31 -16
View File
@@ -126,36 +126,51 @@ config options.
-------------------------------- --------------------------------
4 sysfs files for memory hotplug 4 sysfs files for memory hotplug
-------------------------------- --------------------------------
All sections have their device information under /sys/devices/system/memory as All sections have their device information in sysfs. Each section is part of
a memory block under /sys/devices/system/memory as
/sys/devices/system/memory/memoryXXX /sys/devices/system/memory/memoryXXX
(XXX is section id.) (XXX is the section id.)
Now, XXX is defined as start_address_of_section / section_size. Now, XXX is defined as (start_address_of_section / section_size) of the first
section contained in the memory block. The files 'phys_index' and
'end_phys_index' under each directory report the beginning and end section id's
for the memory block covered by the sysfs directory. It is expected that all
memory sections in this range are present and no memory holes exist in the
range. Currently there is no way to determine if there is a memory hole, but
the existence of one should not affect the hotplug capabilities of the memory
block.
For example, assume 1GiB section size. A device for a memory starting at For example, assume 1GiB section size. A device for a memory starting at
0x100000000 is /sys/device/system/memory/memory4 0x100000000 is /sys/device/system/memory/memory4
(0x100000000 / 1Gib = 4) (0x100000000 / 1Gib = 4)
This device covers address range [0x100000000 ... 0x140000000) This device covers address range [0x100000000 ... 0x140000000)
Under each section, you can see 4 files. Under each section, you can see 4 or 5 files, the end_phys_index file being
a recent addition and not present on older kernels.
/sys/devices/system/memory/memoryXXX/phys_index /sys/devices/system/memory/memoryXXX/start_phys_index
/sys/devices/system/memory/memoryXXX/end_phys_index
/sys/devices/system/memory/memoryXXX/phys_device /sys/devices/system/memory/memoryXXX/phys_device
/sys/devices/system/memory/memoryXXX/state /sys/devices/system/memory/memoryXXX/state
/sys/devices/system/memory/memoryXXX/removable /sys/devices/system/memory/memoryXXX/removable
'phys_index' : read-only and contains section id, same as XXX. 'phys_index' : read-only and contains section id of the first section
'state' : read-write in the memory block, same as XXX.
at read: contains online/offline state of memory. 'end_phys_index' : read-only and contains section id of the last section
at write: user can specify "online", "offline" command in the memory block.
'phys_device': read-only: designed to show the name of physical memory device. 'state' : read-write
This is not well implemented now. at read: contains online/offline state of memory.
'removable' : read-only: contains an integer value indicating at write: user can specify "online", "offline" command
whether the memory section is removable or not which will be performed on al sections in the block.
removable. A value of 1 indicates that the memory 'phys_device' : read-only: designed to show the name of physical memory
section is removable and a value of 0 indicates that device. This is not well implemented now.
it is not removable. 'removable' : read-only: contains an integer value indicating
whether the memory block is removable or not
removable. A value of 1 indicates that the memory
block is removable and a value of 0 indicates that
it is not removable. A memory block is removable only if
every section in the block is removable.
NOTE: NOTE:
These directories/files appear after physical memory hotplug phase. These directories/files appear after physical memory hotplug phase.
+50
View File
@@ -0,0 +1,50 @@
Chinese translated version of Documentation/SecurityBugs
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
communicating in English you can also ask the Chinese maintainer for
help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Chinese maintainer: Harry Wei <harryxiyou@gmail.com>
---------------------------------------------------------------------
Documentation/SecurityBugs 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
中文版维护者: 贾威威 Harry Wei <harryxiyou@gmail.com>
中文版翻译者: 贾威威 Harry Wei <harryxiyou@gmail.com>
中文版校译者: 贾威威 Harry Wei <harryxiyou@gmail.com>
以下为正文
---------------------------------------------------------------------
Linux内核开发者认为安全非常重要。因此,我们想要知道当一个有关于
安全的漏洞被发现的时候,并且它可能会被尽快的修复或者公开。请把这个安全
漏洞报告给Linux内核安全团队。
1) 联系
linux内核安全团队可以通过email<security@kernel.org>来联系。这是
一组独立的安全工作人员,可以帮助改善漏洞报告并且公布和取消一个修复。安
全团队有可能会从部分的维护者那里引进额外的帮助来了解并且修复安全漏洞。
当遇到任何漏洞,所能提供的信息越多就越能诊断和修复。如果你不清楚什么
是有帮助的信息,那就请重温一下REPORTING-BUGS文件中的概述过程。任
何攻击性的代码都是非常有用的,未经报告者的同意不会被取消,除非它已经
被公布于众。
2) 公开
Linux内核安全团队的宗旨就是和漏洞提交者一起处理漏洞的解决方案直
到公开。我们喜欢尽快地完全公开漏洞。当一个漏洞或者修复还没有被完全地理
解,解决方案没有通过测试或者供应商协调,可以合理地延迟公开。然而,我们
期望这些延迟尽可能的短些,是可数的几天,而不是几个星期或者几个月。公开
日期是通过安全团队和漏洞提供者以及供应商洽谈后的结果。公开时间表是从很
短(特殊的,它已经被公众所知道)到几个星期。作为一个基本的默认政策,我
们所期望通知公众的日期是7天的安排。
3) 保密协议
Linux内核安全团队不是一个正式的团体,因此不能加入任何的保密协议。
+109
View File
@@ -0,0 +1,109 @@
Chinese translated version of Documentation/SubmitChecklist
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
communicating in English you can also ask the Chinese maintainer for
help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Chinese maintainer: Harry Wei <harryxiyou@gmail.com>
---------------------------------------------------------------------
Documentation/SubmitChecklist 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
中文版维护者: 贾威威 Harry Wei <harryxiyou@gmail.com>
中文版翻译者: 贾威威 Harry Wei <harryxiyou@gmail.com>
中文版校译者: 贾威威 Harry Wei <harryxiyou@gmail.com>
以下为正文
---------------------------------------------------------------------
Linux内核提交清单
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这里有一些内核开发者应该做的基本事情,如果他们想看到自己的内核补丁提交
被接受的更快。
这些都是超出Documentation/SubmittingPatches文档里所提供的以及其他
关于提交Linux内核补丁的说明。
1:如果你使用了一个功能那么就#include定义/声明那个功能的那个文件。
不要依靠其他间接引入定义/声明那个功能的头文件。
2:构建简洁适用或者更改CONFIG选项 =y,=m,或者=n。
不要有编译警告/错误, 不要有链接警告/错误。
2b:通过 allnoconfig, allmodconfig
2c:当使用 0=builddir 成功地构建
3:通过使用本地交叉编译工具或者其他一些构建产所,在多CPU框架上构建。
4:ppc64 是一个很好的检查交叉编译的框架,因为它往往把‘unsigned long
当64位值来使用。
5:按照Documentation/CodingStyle文件里的详细描述,检查你补丁的整体风格。
使用补丁风格检查琐碎的违规(scripts/checkpatch.pl),审核员优先提交。
你应该调整遗留在你补丁中的所有违规。
6:任何更新或者改动CONFIG选项都不能打乱配置菜单。
7:所有的Kconfig选项更新都要有说明文字。
8:已经认真地总结了相关的Kconfig组合。这是很难通过测试做好的--脑力在这里下降。
9:检查具有简洁性。
10:使用'make checkstack'和'make namespacecheck'检查,然后修改所找到的问题。
注意:堆栈检查不会明确地出现问题,但是任何的一个函数在堆栈上使用多于512字节
都要准备修改。
11:包含kernel-doc到全局内核APIs文件。(不要求静态的函数,但是包含也无所谓。)
使用'make htmldocs'或者'make mandocs'来检查kernel-doc,然后修改任何
发现的问题。
12:已经通过CONFIG_PREEMPT, CONFIG_DEBUG_PREEMPT,
CONFIG_DEBUG_SLAB, CONFIG_DEBUG_PAGEALLOC, CONFIG_DEBUG_MUTEXES,
CONFIG_DEBUG_SPINLOCK, CONFIG_DEBUG_SPINLOCK_SLEEP测试,并且同时都
使能。
13:已经都构建并且使用或者不使用 CONFIG_SMP 和 CONFIG_PREEMPT测试执行时间。
14:如果补丁影响IO/Disk,等等:已经通过使用或者不使用 CONFIG_LBDAF 测试。
15:所有的codepaths已经行使所有lockdep启用功能。
16:所有的/proc记录更新都要作成文件放在Documentation/目录下。
17:所有的内核启动参数更新都被记录到Documentation/kernel-parameters.txt文件中。
18:所有的模块参数更新都用MODULE_PARM_DESC()记录。
19:所有的用户空间接口更新都被记录到Documentation/ABI/。查看Documentation/ABI/README
可以获得更多的信息。改变用户空间接口的补丁应该被邮件抄送给linux-api@vger.kernel.org。
20:检查它是不是都通过`make headers_check'。
21:已经通过至少引入slab和page-allocation失败检查。查看Documentation/fault-injection/。
22:新加入的源码已经通过`gcc -W'(使用"make EXTRA_CFLAGS=-W")编译。这样将产生很多烦恼,
但是对于寻找漏洞很有益处,例如:"warning: comparison between signed and unsigned"。
23:当它被合并到-mm补丁集后再测试,用来确定它是否还和补丁队列中的其他补丁一起工作以及在VM,VFS
和其他子系统中各个变化。
24:所有的内存屏障{e.g., barrier(), rmb(), wmb()}需要在源代码中的一个注释来解释他们都是干什么的
以及原因。
25:如果有任何输入输出控制的补丁被添加,也要更新Documentation/ioctl/ioctl-number.txt。
26:如果你的更改代码依靠或者使用任何的内核APIs或者与下面的kconfig符号有关系的功能,你就要
使用相关的kconfig符号关闭, and/or =m(如果选项提供)[在同一时间不是所用的都启用,仅仅各个或者自由
组合他们]
CONFIG_SMP, CONFIG_SYSFS, CONFIG_PROC_FS, CONFIG_INPUT, CONFIG_PCI,
CONFIG_BLOCK, CONFIG_PM, CONFIG_HOTPLUG, CONFIG_MAGIC_SYSRQ,
CONFIG_NET, CONFIG_INET=n (后一个使用 CONFIG_NET=y)
+2 -2
View File
@@ -100,7 +100,7 @@ http://userweb.kernel.org/~akpm/stuff/patch-scripts.tar.gz
将改动拆分,逻辑类似的放到同一个补丁文件里。 将改动拆分,逻辑类似的放到同一个补丁文件里。
例如,如果你的改动里同时有bug修正和性能优化,那么把这些改动分到两个或 例如,如果你的改动里同时有bug修正和性能优化,那么把这些改动分到两个或
者更多的补丁文件中。如果你的改动包含对API的修改,并且修改了驱动程序来适 者更多的补丁文件中。如果你的改动包含对API的修改,并且修改了驱动程序来适
应这些新的API,那么把这些修改分成两个补丁。 应这些新的API,那么把这些修改分成两个补丁。
@@ -230,7 +230,7 @@ pref("mailnews.display.disable_format_flowed_support", true);
些原因,修正错误,重新提交更新后的改动,是你自己的工作。 些原因,修正错误,重新提交更新后的改动,是你自己的工作。
Linus不给出任何评论就“丢弃”你的补丁是常见的事情。在系统中这样的事情很 Linus不给出任何评论就“丢弃”你的补丁是常见的事情。在系统中这样的事情很
平常。如果他没有接受你的补丁,也许是由于以下原 平常。如果他没有接受你的补丁,也许是由于以下原
* 你的补丁不能在最新版本的内核上干净的打上。 * 你的补丁不能在最新版本的内核上干净的打上。
* 你的补丁在 linux-kernel 邮件列表中没有得到充分的讨论。 * 你的补丁在 linux-kernel 邮件列表中没有得到充分的讨论。
* 风格问题(参照第2小节) * 风格问题(参照第2小节)
+167
View File
@@ -0,0 +1,167 @@
Chinese translated version of Documentation/magic-number.txt
If you have any comment or update to the content, please post to LKML directly.
However, if you have problem communicating in English you can also ask the
Chinese maintainer for help. Contact the Chinese maintainer, if this
translation is outdated or there is problem with translation.
Chinese maintainer: Jia Wei Wei <harryxiyou@gmail.com>
---------------------------------------------------------------------
Documentation/magic-number.txt的中文翻译
如果想评论或更新本文的内容,请直接发信到LKML。如果你使用英文交流有困难的话,也可
以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题,请联系中文版维护者。
中文版维护者: 贾威威 Jia Wei Wei <harryxiyou@gmail.com>
中文版翻译者: 贾威威 Jia Wei Wei <harryxiyou@gmail.com>
中文版校译者: 贾威威 Jia Wei Wei <harryxiyou@gmail.com>
以下为正文
---------------------------------------------------------------------
这个文件是有关当前使用的魔术值注册表。当你给一个结构添加了一个魔术值,你也应该把这个魔术值添加到这个文件,因为我们最好把用于各种结构的魔术值统一起来。
使用魔术值来保护内核数据结构是一个非常好的主意。这就允许你在运行期检查(a)一个结构是否已经被攻击,或者(b)你已经给一个例行程序通过了一个错误的结构。后一种情况特别地有用---特别是当你通过一个空指针指向结构体的时候。tty源码,例如,经常通过特定驱动使用这种方法并且反复地排列特定方面的结构。
使用魔术值的方法是在结构的开始处声明的,如下:
struct tty_ldisc {
int magic;
...
};
当你以后给内核添加增强功能的时候,请遵守这条规则!这样就会节省数不清的调试时间,特别是一些古怪的情况,例如,数组超出范围并且重新写了超出部分。遵守这个规则,‪这些情况可以被快速地,安全地避免。
Theodore Ts'o
31 Mar 94
给当前的Linux 2.1.55添加魔术表。
Michael Chastain
<mailto:mec@shout.net>
22 Sep 1997
现在应该最新的Linux 2.1.112.因为在特性冻结期间,不能在2.2.x前改变任何东西。这些条目被数域所排序。
Krzysztof G.Baranowski
<mailto: kgb@knm.org.pl>
29 Jul 1998
更新魔术表到Linux 2.5.45。刚好越过特性冻结,但是有可能还会有一些新的魔术值在2.6.x之前融入到内核中。
Petr Baudis
<pasky@ucw.cz>
03 Nov 2002
更新魔术表到Linux 2.5.74。
Fabian Frederick
<ffrederick@users.sourceforge.net>
09 Jul 2003
魔术名 地址 结构 所在文件
===========================================================================
PG_MAGIC 'P' pg_{read,write}_hdr include/linux/pg.h
CMAGIC 0x0111 user include/linux/a.out.h
MKISS_DRIVER_MAGIC 0x04bf mkiss_channel drivers/net/mkiss.h
RISCOM8_MAGIC 0x0907 riscom_port drivers/char/riscom8.h
SPECIALIX_MAGIC 0x0907 specialix_port drivers/char/specialix_io8.h
HDLC_MAGIC 0x239e n_hdlc drivers/char/n_hdlc.c
APM_BIOS_MAGIC 0x4101 apm_user arch/i386/kernel/apm.c
CYCLADES_MAGIC 0x4359 cyclades_port include/linux/cyclades.h
DB_MAGIC 0x4442 fc_info drivers/net/iph5526_novram.c
DL_MAGIC 0x444d fc_info drivers/net/iph5526_novram.c
FASYNC_MAGIC 0x4601 fasync_struct include/linux/fs.h
FF_MAGIC 0x4646 fc_info drivers/net/iph5526_novram.c
ISICOM_MAGIC 0x4d54 isi_port include/linux/isicom.h
PTY_MAGIC 0x5001 drivers/char/pty.c
PPP_MAGIC 0x5002 ppp include/linux/if_pppvar.h
SERIAL_MAGIC 0x5301 async_struct include/linux/serial.h
SSTATE_MAGIC 0x5302 serial_state include/linux/serial.h
SLIP_MAGIC 0x5302 slip drivers/net/slip.h
STRIP_MAGIC 0x5303 strip drivers/net/strip.c
X25_ASY_MAGIC 0x5303 x25_asy drivers/net/x25_asy.h
SIXPACK_MAGIC 0x5304 sixpack drivers/net/hamradio/6pack.h
AX25_MAGIC 0x5316 ax_disp drivers/net/mkiss.h
ESP_MAGIC 0x53ee esp_struct drivers/char/esp.h
TTY_MAGIC 0x5401 tty_struct include/linux/tty.h
MGSL_MAGIC 0x5401 mgsl_info drivers/char/synclink.c
TTY_DRIVER_MAGIC 0x5402 tty_driver include/linux/tty_driver.h
MGSLPC_MAGIC 0x5402 mgslpc_info drivers/char/pcmcia/synclink_cs.c
TTY_LDISC_MAGIC 0x5403 tty_ldisc include/linux/tty_ldisc.h
USB_SERIAL_MAGIC 0x6702 usb_serial drivers/usb/serial/usb-serial.h
FULL_DUPLEX_MAGIC 0x6969 drivers/net/tulip/de2104x.c
USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth drivers/usb/class/bluetty.c
RFCOMM_TTY_MAGIC 0x6d02 net/bluetooth/rfcomm/tty.c
USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port drivers/usb/serial/usb-serial.h
CG_MAGIC 0x00090255 ufs_cylinder_group include/linux/ufs_fs.h
A2232_MAGIC 0x000a2232 gs_port drivers/char/ser_a2232.h
RPORT_MAGIC 0x00525001 r_port drivers/char/rocket_int.h
LSEMAGIC 0x05091998 lse drivers/fc4/fc.c
GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str drivers/scsi/gdth_ioctl.h
RIEBL_MAGIC 0x09051990 drivers/net/atarilance.c
RIO_MAGIC 0x12345678 gs_port drivers/char/rio/rio_linux.c
SX_MAGIC 0x12345678 gs_port drivers/char/sx.h
NBD_REQUEST_MAGIC 0x12560953 nbd_request include/linux/nbd.h
RED_MAGIC2 0x170fc2a5 (any) mm/slab.c
BAYCOM_MAGIC 0x19730510 baycom_state drivers/net/baycom_epp.c
ISDN_X25IFACE_MAGIC 0x1e75a2b9 isdn_x25iface_proto_data
drivers/isdn/isdn_x25iface.h
ECP_MAGIC 0x21504345 cdkecpsig include/linux/cdk.h
LSOMAGIC 0x27091997 lso drivers/fc4/fc.c
LSMAGIC 0x2a3b4d2a ls drivers/fc4/fc.c
WANPIPE_MAGIC 0x414C4453 sdla_{dump,exec} include/linux/wanpipe.h
CS_CARD_MAGIC 0x43525553 cs_card sound/oss/cs46xx.c
LABELCL_MAGIC 0x4857434c labelcl_info_s include/asm/ia64/sn/labelcl.h
ISDN_ASYNC_MAGIC 0x49344C01 modem_info include/linux/isdn.h
CTC_ASYNC_MAGIC 0x49344C01 ctc_tty_info drivers/s390/net/ctctty.c
ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s drivers/isdn/i4l/isdn_net_lib.h
SAVEKMSG_MAGIC2 0x4B4D5347 savekmsg arch/*/amiga/config.c
STLI_BOARDMAGIC 0x4bc6c825 stlibrd include/linux/istallion.h
CS_STATE_MAGIC 0x4c4f4749 cs_state sound/oss/cs46xx.c
SLAB_C_MAGIC 0x4f17a36d kmem_cache mm/slab.c
COW_MAGIC 0x4f4f4f4d cow_header_v1 arch/um/drivers/ubd_user.c
I810_CARD_MAGIC 0x5072696E i810_card sound/oss/i810_audio.c
TRIDENT_CARD_MAGIC 0x5072696E trident_card sound/oss/trident.c
ROUTER_MAGIC 0x524d4157 wan_device include/linux/wanrouter.h
SCC_MAGIC 0x52696368 gs_port drivers/char/scc.h
SAVEKMSG_MAGIC1 0x53415645 savekmsg arch/*/amiga/config.c
GDA_MAGIC 0x58464552 gda arch/mips/include/asm/sn/gda.h
RED_MAGIC1 0x5a2cf071 (any) mm/slab.c
STL_PORTMAGIC 0x5a7182c9 stlport include/linux/stallion.h
EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev drivers/atm/lanai.c
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state include/linux/hdlcdrv.h
EPCA_MAGIC 0x5c6df104 channel include/linux/epca.h
PCXX_MAGIC 0x5c6df104 channel drivers/char/pcxx.h
KV_MAGIC 0x5f4b565f kernel_vars_s arch/mips/include/asm/sn/klkernvars.h
I810_STATE_MAGIC 0x63657373 i810_state sound/oss/i810_audio.c
TRIDENT_STATE_MAGIC 0x63657373 trient_state sound/oss/trident.c
M3_CARD_MAGIC 0x646e6f50 m3_card sound/oss/maestro3.c
FW_HEADER_MAGIC 0x65726F66 fw_header drivers/atm/fore200e.h
SLOT_MAGIC 0x67267321 slot drivers/hotplug/cpqphp.h
SLOT_MAGIC 0x67267322 slot drivers/hotplug/acpiphp.h
LO_MAGIC 0x68797548 nbd_device include/linux/nbd.h
OPROFILE_MAGIC 0x6f70726f super_block drivers/oprofile/oprofilefs.h
M3_STATE_MAGIC 0x734d724d m3_state sound/oss/maestro3.c
STL_PANELMAGIC 0x7ef621a1 stlpanel include/linux/stallion.h
VMALLOC_MAGIC 0x87654320 snd_alloc_track sound/core/memory.c
KMALLOC_MAGIC 0x87654321 snd_alloc_track sound/core/memory.c
PWC_MAGIC 0x89DC10AB pwc_device drivers/usb/media/pwc.h
NBD_REPLY_MAGIC 0x96744668 nbd_reply include/linux/nbd.h
STL_BOARDMAGIC 0xa2267f52 stlbrd include/linux/stallion.h
ENI155_MAGIC 0xa54b872d midway_eprom drivers/atm/eni.h
SCI_MAGIC 0xbabeface gs_port drivers/char/sh-sci.h
CODA_MAGIC 0xC0DAC0DA coda_file_info include/linux/coda_fs_i.h
DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram drivers/scsi/gdth.h
STLI_PORTMAGIC 0xe671c7a1 stliport include/linux/istallion.h
YAM_MAGIC 0xF10A7654 yam_port drivers/net/hamradio/yam.c
CCB_MAGIC 0xf2691ad2 ccb drivers/scsi/ncr53c8xx.c
QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry drivers/scsi/arm/queue.c
QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry drivers/scsi/arm/queue.c
HTB_CMAGIC 0xFEFAFEF1 htb_class net/sched/sch_htb.c
NMI_MAGIC 0x48414d4d455201 nmi_s arch/mips/include/asm/sn/nmi.h
请注意,在声音记忆管理中仍然有每一些被定义的驱动魔术值。查看include/sound/sndmagic.h来获取他们完整的列表信息。很多OSS声音驱动拥有自己从声卡PCI ID构建的魔术值-他们也没有被列在这里。
IrDA子系统也使用了大量的自己的魔术值,查看include/net/irda/irda.h来获取他们完整的信息。
HFS是另外一个比较大的使用魔术值的文件系统-你可以在fs/hfs/hfs.h中找到他们。
+53 -13
View File
@@ -17,6 +17,54 @@
#include <asm/pSeries_reconfig.h> #include <asm/pSeries_reconfig.h>
#include <asm/sparsemem.h> #include <asm/sparsemem.h>
static unsigned long get_memblock_size(void)
{
struct device_node *np;
unsigned int memblock_size = 0;
np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
if (np) {
const unsigned long *size;
size = of_get_property(np, "ibm,lmb-size", NULL);
memblock_size = size ? *size : 0;
of_node_put(np);
} else {
unsigned int memzero_size = 0;
const unsigned int *regs;
np = of_find_node_by_path("/memory@0");
if (np) {
regs = of_get_property(np, "reg", NULL);
memzero_size = regs ? regs[3] : 0;
of_node_put(np);
}
if (memzero_size) {
/* We now know the size of memory@0, use this to find
* the first memoryblock and get its size.
*/
char buf[64];
sprintf(buf, "/memory@%x", memzero_size);
np = of_find_node_by_path(buf);
if (np) {
regs = of_get_property(np, "reg", NULL);
memblock_size = regs ? regs[3] : 0;
of_node_put(np);
}
}
}
return memblock_size;
}
unsigned long memory_block_size_bytes(void)
{
return get_memblock_size();
}
static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size) static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size)
{ {
unsigned long start, start_pfn; unsigned long start, start_pfn;
@@ -127,30 +175,22 @@ static int pseries_add_memory(struct device_node *np)
static int pseries_drconf_memory(unsigned long *base, unsigned int action) static int pseries_drconf_memory(unsigned long *base, unsigned int action)
{ {
struct device_node *np; unsigned long memblock_size;
const unsigned long *lmb_size;
int rc; int rc;
np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); memblock_size = get_memblock_size();
if (!np) if (!memblock_size)
return -EINVAL; return -EINVAL;
lmb_size = of_get_property(np, "ibm,lmb-size", NULL);
if (!lmb_size) {
of_node_put(np);
return -EINVAL;
}
if (action == PSERIES_DRCONF_MEM_ADD) { if (action == PSERIES_DRCONF_MEM_ADD) {
rc = memblock_add(*base, *lmb_size); rc = memblock_add(*base, memblock_size);
rc = (rc < 0) ? -EINVAL : 0; rc = (rc < 0) ? -EINVAL : 0;
} else if (action == PSERIES_DRCONF_MEM_REMOVE) { } else if (action == PSERIES_DRCONF_MEM_REMOVE) {
rc = pseries_remove_memblock(*base, *lmb_size); rc = pseries_remove_memblock(*base, memblock_size);
} else { } else {
rc = -EINVAL; rc = -EINVAL;
} }
of_node_put(np);
return rc; return rc;
} }
+14
View File
@@ -51,6 +51,7 @@
#include <asm/numa.h> #include <asm/numa.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/init.h> #include <asm/init.h>
#include <asm/uv/uv.h>
static int __init parse_direct_gbpages_off(char *arg) static int __init parse_direct_gbpages_off(char *arg)
{ {
@@ -898,6 +899,19 @@ const char *arch_vma_name(struct vm_area_struct *vma)
return NULL; return NULL;
} }
#ifdef CONFIG_X86_UV
#define MIN_MEMORY_BLOCK_SIZE (1 << SECTION_SIZE_BITS)
unsigned long memory_block_size_bytes(void)
{
if (is_uv_system()) {
printk(KERN_INFO "UV: memory block size 2GB\n");
return 2UL * 1024 * 1024 * 1024;
}
return MIN_MEMORY_BLOCK_SIZE;
}
#endif
#ifdef CONFIG_SPARSEMEM_VMEMMAP #ifdef CONFIG_SPARSEMEM_VMEMMAP
/* /*
* Initialise the sparsemem vmemmap using huge-pages at the PMD level. * Initialise the sparsemem vmemmap using huge-pages at the PMD level.
+32 -2
View File
@@ -1320,7 +1320,10 @@ struct root_device
struct module *owner; struct module *owner;
}; };
#define to_root_device(dev) container_of(dev, struct root_device, dev) inline struct root_device *to_root_device(struct device *d)
{
return container_of(d, struct root_device, dev);
}
static void root_device_release(struct device *dev) static void root_device_release(struct device *dev)
{ {
@@ -1551,7 +1554,34 @@ EXPORT_SYMBOL_GPL(device_destroy);
* on the same device to ensure that new_name is valid and * on the same device to ensure that new_name is valid and
* won't conflict with other devices. * won't conflict with other devices.
* *
* "Never use this function, bad things will happen" - gregkh * Note: Don't call this function. Currently, the networking layer calls this
* function, but that will change. The following text from Kay Sievers offers
* some insight:
*
* Renaming devices is racy at many levels, symlinks and other stuff are not
* replaced atomically, and you get a "move" uevent, but it's not easy to
* connect the event to the old and new device. Device nodes are not renamed at
* all, there isn't even support for that in the kernel now.
*
* In the meantime, during renaming, your target name might be taken by another
* driver, creating conflicts. Or the old name is taken directly after you
* renamed it -- then you get events for the same DEVPATH, before you even see
* the "move" event. It's just a mess, and nothing new should ever rely on
* kernel device renaming. Besides that, it's not even implemented now for
* other things than (driver-core wise very simple) network devices.
*
* We are currently about to change network renaming in udev to completely
* disallow renaming of devices in the same namespace as the kernel uses,
* because we can't solve the problems properly, that arise with swapping names
* of multiple interfaces without races. Means, renaming of eth[0-9]* will only
* be allowed to some other name than eth[0-9]*, for the aforementioned
* reasons.
*
* Make up a "real" name in the driver before you register anything, or add
* some other attributes for userspace to find the device, or use udev to add
* symlinks -- but never rename kernel devices later, it's a complete mess. We
* don't even want to get into that and try to implement the missing pieces in
* the core. We really have other pieces to fix in the driver core mess. :)
*/ */
int device_rename(struct device *dev, const char *new_name) int device_rename(struct device *dev, const char *new_name)
{ {
+3 -4
View File
@@ -593,8 +593,7 @@ int
request_firmware(const struct firmware **firmware_p, const char *name, request_firmware(const struct firmware **firmware_p, const char *name,
struct device *device) struct device *device)
{ {
int uevent = 1; return _request_firmware(firmware_p, name, device, true, false);
return _request_firmware(firmware_p, name, device, uevent, false);
} }
/** /**
@@ -618,7 +617,7 @@ struct firmware_work {
struct device *device; struct device *device;
void *context; void *context;
void (*cont)(const struct firmware *fw, void *context); void (*cont)(const struct firmware *fw, void *context);
int uevent; bool uevent;
}; };
static int request_firmware_work_func(void *arg) static int request_firmware_work_func(void *arg)
@@ -661,7 +660,7 @@ static int request_firmware_work_func(void *arg)
**/ **/
int int
request_firmware_nowait( request_firmware_nowait(
struct module *module, int uevent, struct module *module, bool uevent,
const char *name, struct device *device, gfp_t gfp, void *context, const char *name, struct device *device, gfp_t gfp, void *context,
void (*cont)(const struct firmware *fw, void *context)) void (*cont)(const struct firmware *fw, void *context))
{ {
+143 -54
View File
@@ -30,6 +30,14 @@
static DEFINE_MUTEX(mem_sysfs_mutex); static DEFINE_MUTEX(mem_sysfs_mutex);
#define MEMORY_CLASS_NAME "memory" #define MEMORY_CLASS_NAME "memory"
#define MIN_MEMORY_BLOCK_SIZE (1 << SECTION_SIZE_BITS)
static int sections_per_block;
static inline int base_memory_block_id(int section_nr)
{
return section_nr / sections_per_block;
}
static struct sysdev_class memory_sysdev_class = { static struct sysdev_class memory_sysdev_class = {
.name = MEMORY_CLASS_NAME, .name = MEMORY_CLASS_NAME,
@@ -84,39 +92,72 @@ EXPORT_SYMBOL(unregister_memory_isolate_notifier);
* register_memory - Setup a sysfs device for a memory block * register_memory - Setup a sysfs device for a memory block
*/ */
static static
int register_memory(struct memory_block *memory, struct mem_section *section) int register_memory(struct memory_block *memory)
{ {
int error; int error;
memory->sysdev.cls = &memory_sysdev_class; memory->sysdev.cls = &memory_sysdev_class;
memory->sysdev.id = __section_nr(section); memory->sysdev.id = memory->start_section_nr / sections_per_block;
error = sysdev_register(&memory->sysdev); error = sysdev_register(&memory->sysdev);
return error; return error;
} }
static void static void
unregister_memory(struct memory_block *memory, struct mem_section *section) unregister_memory(struct memory_block *memory)
{ {
BUG_ON(memory->sysdev.cls != &memory_sysdev_class); BUG_ON(memory->sysdev.cls != &memory_sysdev_class);
BUG_ON(memory->sysdev.id != __section_nr(section));
/* drop the ref. we got in remove_memory_block() */ /* drop the ref. we got in remove_memory_block() */
kobject_put(&memory->sysdev.kobj); kobject_put(&memory->sysdev.kobj);
sysdev_unregister(&memory->sysdev); sysdev_unregister(&memory->sysdev);
} }
unsigned long __weak memory_block_size_bytes(void)
{
return MIN_MEMORY_BLOCK_SIZE;
}
static unsigned long get_memory_block_size(void)
{
unsigned long block_sz;
block_sz = memory_block_size_bytes();
/* Validate blk_sz is a power of 2 and not less than section size */
if ((block_sz & (block_sz - 1)) || (block_sz < MIN_MEMORY_BLOCK_SIZE)) {
WARN_ON(1);
block_sz = MIN_MEMORY_BLOCK_SIZE;
}
return block_sz;
}
/* /*
* use this as the physical section index that this memsection * use this as the physical section index that this memsection
* uses. * uses.
*/ */
static ssize_t show_mem_phys_index(struct sys_device *dev, static ssize_t show_mem_start_phys_index(struct sys_device *dev,
struct sysdev_attribute *attr, char *buf) struct sysdev_attribute *attr, char *buf)
{ {
struct memory_block *mem = struct memory_block *mem =
container_of(dev, struct memory_block, sysdev); container_of(dev, struct memory_block, sysdev);
return sprintf(buf, "%08lx\n", mem->phys_index); unsigned long phys_index;
phys_index = mem->start_section_nr / sections_per_block;
return sprintf(buf, "%08lx\n", phys_index);
}
static ssize_t show_mem_end_phys_index(struct sys_device *dev,
struct sysdev_attribute *attr, char *buf)
{
struct memory_block *mem =
container_of(dev, struct memory_block, sysdev);
unsigned long phys_index;
phys_index = mem->end_section_nr / sections_per_block;
return sprintf(buf, "%08lx\n", phys_index);
} }
/* /*
@@ -125,13 +166,16 @@ static ssize_t show_mem_phys_index(struct sys_device *dev,
static ssize_t show_mem_removable(struct sys_device *dev, static ssize_t show_mem_removable(struct sys_device *dev,
struct sysdev_attribute *attr, char *buf) struct sysdev_attribute *attr, char *buf)
{ {
unsigned long start_pfn; unsigned long i, pfn;
int ret; int ret = 1;
struct memory_block *mem = struct memory_block *mem =
container_of(dev, struct memory_block, sysdev); container_of(dev, struct memory_block, sysdev);
start_pfn = section_nr_to_pfn(mem->phys_index); for (i = 0; i < sections_per_block; i++) {
ret = is_mem_section_removable(start_pfn, PAGES_PER_SECTION); pfn = section_nr_to_pfn(mem->start_section_nr + i);
ret &= is_mem_section_removable(pfn, PAGES_PER_SECTION);
}
return sprintf(buf, "%d\n", ret); return sprintf(buf, "%d\n", ret);
} }
@@ -184,17 +228,14 @@ int memory_isolate_notify(unsigned long val, void *v)
* OK to have direct references to sparsemem variables in here. * OK to have direct references to sparsemem variables in here.
*/ */
static int static int
memory_block_action(struct memory_block *mem, unsigned long action) memory_section_action(unsigned long phys_index, unsigned long action)
{ {
int i; int i;
unsigned long psection;
unsigned long start_pfn, start_paddr; unsigned long start_pfn, start_paddr;
struct page *first_page; struct page *first_page;
int ret; int ret;
int old_state = mem->state;
psection = mem->phys_index; first_page = pfn_to_page(phys_index << PFN_SECTION_SHIFT);
first_page = pfn_to_page(psection << PFN_SECTION_SHIFT);
/* /*
* The probe routines leave the pages reserved, just * The probe routines leave the pages reserved, just
@@ -207,8 +248,8 @@ memory_block_action(struct memory_block *mem, unsigned long action)
continue; continue;
printk(KERN_WARNING "section number %ld page number %d " printk(KERN_WARNING "section number %ld page number %d "
"not reserved, was it already online? \n", "not reserved, was it already online?\n",
psection, i); phys_index, i);
return -EBUSY; return -EBUSY;
} }
} }
@@ -219,18 +260,13 @@ memory_block_action(struct memory_block *mem, unsigned long action)
ret = online_pages(start_pfn, PAGES_PER_SECTION); ret = online_pages(start_pfn, PAGES_PER_SECTION);
break; break;
case MEM_OFFLINE: case MEM_OFFLINE:
mem->state = MEM_GOING_OFFLINE;
start_paddr = page_to_pfn(first_page) << PAGE_SHIFT; start_paddr = page_to_pfn(first_page) << PAGE_SHIFT;
ret = remove_memory(start_paddr, ret = remove_memory(start_paddr,
PAGES_PER_SECTION << PAGE_SHIFT); PAGES_PER_SECTION << PAGE_SHIFT);
if (ret) {
mem->state = old_state;
break;
}
break; break;
default: default:
WARN(1, KERN_WARNING "%s(%p, %ld) unknown action: %ld\n", WARN(1, KERN_WARNING "%s(%ld, %ld) unknown action: "
__func__, mem, action, action); "%ld\n", __func__, phys_index, action, action);
ret = -EINVAL; ret = -EINVAL;
} }
@@ -240,7 +276,8 @@ memory_block_action(struct memory_block *mem, unsigned long action)
static int memory_block_change_state(struct memory_block *mem, static int memory_block_change_state(struct memory_block *mem,
unsigned long to_state, unsigned long from_state_req) unsigned long to_state, unsigned long from_state_req)
{ {
int ret = 0; int i, ret = 0;
mutex_lock(&mem->state_mutex); mutex_lock(&mem->state_mutex);
if (mem->state != from_state_req) { if (mem->state != from_state_req) {
@@ -248,8 +285,23 @@ static int memory_block_change_state(struct memory_block *mem,
goto out; goto out;
} }
ret = memory_block_action(mem, to_state); if (to_state == MEM_OFFLINE)
if (!ret) mem->state = MEM_GOING_OFFLINE;
for (i = 0; i < sections_per_block; i++) {
ret = memory_section_action(mem->start_section_nr + i,
to_state);
if (ret)
break;
}
if (ret) {
for (i = 0; i < sections_per_block; i++)
memory_section_action(mem->start_section_nr + i,
from_state_req);
mem->state = from_state_req;
} else
mem->state = to_state; mem->state = to_state;
out: out:
@@ -262,20 +314,15 @@ store_mem_state(struct sys_device *dev,
struct sysdev_attribute *attr, const char *buf, size_t count) struct sysdev_attribute *attr, const char *buf, size_t count)
{ {
struct memory_block *mem; struct memory_block *mem;
unsigned int phys_section_nr;
int ret = -EINVAL; int ret = -EINVAL;
mem = container_of(dev, struct memory_block, sysdev); mem = container_of(dev, struct memory_block, sysdev);
phys_section_nr = mem->phys_index;
if (!present_section_nr(phys_section_nr))
goto out;
if (!strncmp(buf, "online", min((int)count, 6))) if (!strncmp(buf, "online", min((int)count, 6)))
ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE); ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE);
else if(!strncmp(buf, "offline", min((int)count, 7))) else if(!strncmp(buf, "offline", min((int)count, 7)))
ret = memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE); ret = memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE);
out:
if (ret) if (ret)
return ret; return ret;
return count; return count;
@@ -298,7 +345,8 @@ static ssize_t show_phys_device(struct sys_device *dev,
return sprintf(buf, "%d\n", mem->phys_device); return sprintf(buf, "%d\n", mem->phys_device);
} }
static SYSDEV_ATTR(phys_index, 0444, show_mem_phys_index, NULL); static SYSDEV_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL);
static SYSDEV_ATTR(end_phys_index, 0444, show_mem_end_phys_index, NULL);
static SYSDEV_ATTR(state, 0644, show_mem_state, store_mem_state); static SYSDEV_ATTR(state, 0644, show_mem_state, store_mem_state);
static SYSDEV_ATTR(phys_device, 0444, show_phys_device, NULL); static SYSDEV_ATTR(phys_device, 0444, show_phys_device, NULL);
static SYSDEV_ATTR(removable, 0444, show_mem_removable, NULL); static SYSDEV_ATTR(removable, 0444, show_mem_removable, NULL);
@@ -315,7 +363,7 @@ static ssize_t
print_block_size(struct sysdev_class *class, struct sysdev_class_attribute *attr, print_block_size(struct sysdev_class *class, struct sysdev_class_attribute *attr,
char *buf) char *buf)
{ {
return sprintf(buf, "%lx\n", (unsigned long)PAGES_PER_SECTION * PAGE_SIZE); return sprintf(buf, "%lx\n", get_memory_block_size());
} }
static SYSDEV_CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL); static SYSDEV_CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL);
@@ -339,12 +387,19 @@ memory_probe_store(struct class *class, struct class_attribute *attr,
{ {
u64 phys_addr; u64 phys_addr;
int nid; int nid;
int ret; int i, ret;
phys_addr = simple_strtoull(buf, NULL, 0); phys_addr = simple_strtoull(buf, NULL, 0);
nid = memory_add_physaddr_to_nid(phys_addr); for (i = 0; i < sections_per_block; i++) {
ret = add_memory(nid, phys_addr, PAGES_PER_SECTION << PAGE_SHIFT); nid = memory_add_physaddr_to_nid(phys_addr);
ret = add_memory(nid, phys_addr,
PAGES_PER_SECTION << PAGE_SHIFT);
if (ret)
break;
phys_addr += MIN_MEMORY_BLOCK_SIZE;
}
if (ret) if (ret)
count = ret; count = ret;
@@ -444,6 +499,7 @@ struct memory_block *find_memory_block_hinted(struct mem_section *section,
struct sys_device *sysdev; struct sys_device *sysdev;
struct memory_block *mem; struct memory_block *mem;
char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1]; char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1];
int block_id = base_memory_block_id(__section_nr(section));
kobj = hint ? &hint->sysdev.kobj : NULL; kobj = hint ? &hint->sysdev.kobj : NULL;
@@ -451,7 +507,7 @@ struct memory_block *find_memory_block_hinted(struct mem_section *section,
* This only works because we know that section == sysdev->id * This only works because we know that section == sysdev->id
* slightly redundant with sysdev_register() * slightly redundant with sysdev_register()
*/ */
sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, __section_nr(section)); sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, block_id);
kobj = kset_find_obj_hinted(&memory_sysdev_class.kset, name, kobj); kobj = kset_find_obj_hinted(&memory_sysdev_class.kset, name, kobj);
if (!kobj) if (!kobj)
@@ -476,36 +532,62 @@ struct memory_block *find_memory_block(struct mem_section *section)
return find_memory_block_hinted(section, NULL); return find_memory_block_hinted(section, NULL);
} }
static int add_memory_block(int nid, struct mem_section *section, static int init_memory_block(struct memory_block **memory,
unsigned long state, enum mem_add_context context) struct mem_section *section, unsigned long state)
{ {
struct memory_block *mem = kzalloc(sizeof(*mem), GFP_KERNEL); struct memory_block *mem;
unsigned long start_pfn; unsigned long start_pfn;
int scn_nr;
int ret = 0; int ret = 0;
mem = kzalloc(sizeof(*mem), GFP_KERNEL);
if (!mem) if (!mem)
return -ENOMEM; return -ENOMEM;
mutex_lock(&mem_sysfs_mutex); scn_nr = __section_nr(section);
mem->start_section_nr =
mem->phys_index = __section_nr(section); base_memory_block_id(scn_nr) * sections_per_block;
mem->end_section_nr = mem->start_section_nr + sections_per_block - 1;
mem->state = state; mem->state = state;
mem->section_count++; mem->section_count++;
mutex_init(&mem->state_mutex); mutex_init(&mem->state_mutex);
start_pfn = section_nr_to_pfn(mem->phys_index); start_pfn = section_nr_to_pfn(mem->start_section_nr);
mem->phys_device = arch_get_memory_phys_device(start_pfn); mem->phys_device = arch_get_memory_phys_device(start_pfn);
ret = register_memory(mem, section); ret = register_memory(mem);
if (!ret) if (!ret)
ret = mem_create_simple_file(mem, phys_index); ret = mem_create_simple_file(mem, phys_index);
if (!ret)
ret = mem_create_simple_file(mem, end_phys_index);
if (!ret) if (!ret)
ret = mem_create_simple_file(mem, state); ret = mem_create_simple_file(mem, state);
if (!ret) if (!ret)
ret = mem_create_simple_file(mem, phys_device); ret = mem_create_simple_file(mem, phys_device);
if (!ret) if (!ret)
ret = mem_create_simple_file(mem, removable); ret = mem_create_simple_file(mem, removable);
*memory = mem;
return ret;
}
static int add_memory_section(int nid, struct mem_section *section,
unsigned long state, enum mem_add_context context)
{
struct memory_block *mem;
int ret = 0;
mutex_lock(&mem_sysfs_mutex);
mem = find_memory_block(section);
if (mem) {
mem->section_count++;
kobject_put(&mem->sysdev.kobj);
} else
ret = init_memory_block(&mem, section, state);
if (!ret) { if (!ret) {
if (context == HOTPLUG) if (context == HOTPLUG &&
mem->section_count == sections_per_block)
ret = register_mem_sect_under_node(mem, nid); ret = register_mem_sect_under_node(mem, nid);
} }
@@ -520,16 +602,19 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section,
mutex_lock(&mem_sysfs_mutex); mutex_lock(&mem_sysfs_mutex);
mem = find_memory_block(section); mem = find_memory_block(section);
unregister_mem_sect_under_nodes(mem, __section_nr(section));
mem->section_count--; mem->section_count--;
if (mem->section_count == 0) { if (mem->section_count == 0) {
unregister_mem_sect_under_nodes(mem);
mem_remove_simple_file(mem, phys_index); mem_remove_simple_file(mem, phys_index);
mem_remove_simple_file(mem, end_phys_index);
mem_remove_simple_file(mem, state); mem_remove_simple_file(mem, state);
mem_remove_simple_file(mem, phys_device); mem_remove_simple_file(mem, phys_device);
mem_remove_simple_file(mem, removable); mem_remove_simple_file(mem, removable);
unregister_memory(mem, section); unregister_memory(mem);
} kfree(mem);
} else
kobject_put(&mem->sysdev.kobj);
mutex_unlock(&mem_sysfs_mutex); mutex_unlock(&mem_sysfs_mutex);
return 0; return 0;
@@ -541,7 +626,7 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section,
*/ */
int register_new_memory(int nid, struct mem_section *section) int register_new_memory(int nid, struct mem_section *section)
{ {
return add_memory_block(nid, section, MEM_OFFLINE, HOTPLUG); return add_memory_section(nid, section, MEM_OFFLINE, HOTPLUG);
} }
int unregister_memory_section(struct mem_section *section) int unregister_memory_section(struct mem_section *section)
@@ -560,12 +645,16 @@ int __init memory_dev_init(void)
unsigned int i; unsigned int i;
int ret; int ret;
int err; int err;
unsigned long block_sz;
memory_sysdev_class.kset.uevent_ops = &memory_uevent_ops; memory_sysdev_class.kset.uevent_ops = &memory_uevent_ops;
ret = sysdev_class_register(&memory_sysdev_class); ret = sysdev_class_register(&memory_sysdev_class);
if (ret) if (ret)
goto out; goto out;
block_sz = get_memory_block_size();
sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
/* /*
* Create entries for memory sections that were found * Create entries for memory sections that were found
* during boot and have been initialized * during boot and have been initialized
@@ -573,8 +662,8 @@ int __init memory_dev_init(void)
for (i = 0; i < NR_MEM_SECTIONS; i++) { for (i = 0; i < NR_MEM_SECTIONS; i++) {
if (!present_section_nr(i)) if (!present_section_nr(i))
continue; continue;
err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE, err = add_memory_section(0, __nr_to_section(i), MEM_ONLINE,
BOOT); BOOT);
if (!ret) if (!ret)
ret = err; ret = err;
} }
+8 -4
View File
@@ -375,8 +375,10 @@ int register_mem_sect_under_node(struct memory_block *mem_blk, int nid)
return -EFAULT; return -EFAULT;
if (!node_online(nid)) if (!node_online(nid))
return 0; return 0;
sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1; sect_start_pfn = section_nr_to_pfn(mem_blk->start_section_nr);
sect_end_pfn = section_nr_to_pfn(mem_blk->end_section_nr);
sect_end_pfn += PAGES_PER_SECTION - 1;
for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
int page_nid; int page_nid;
@@ -400,7 +402,8 @@ int register_mem_sect_under_node(struct memory_block *mem_blk, int nid)
} }
/* unregister memory section under all nodes that it spans */ /* unregister memory section under all nodes that it spans */
int unregister_mem_sect_under_nodes(struct memory_block *mem_blk) int unregister_mem_sect_under_nodes(struct memory_block *mem_blk,
unsigned long phys_index)
{ {
NODEMASK_ALLOC(nodemask_t, unlinked_nodes, GFP_KERNEL); NODEMASK_ALLOC(nodemask_t, unlinked_nodes, GFP_KERNEL);
unsigned long pfn, sect_start_pfn, sect_end_pfn; unsigned long pfn, sect_start_pfn, sect_end_pfn;
@@ -412,7 +415,8 @@ int unregister_mem_sect_under_nodes(struct memory_block *mem_blk)
if (!unlinked_nodes) if (!unlinked_nodes)
return -ENOMEM; return -ENOMEM;
nodes_clear(*unlinked_nodes); nodes_clear(*unlinked_nodes);
sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
sect_start_pfn = section_nr_to_pfn(phys_index);
sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1; sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
int nid; int nid;
+46 -19
View File
@@ -166,6 +166,36 @@ EXPORT_SYMBOL_GPL(sysdev_class_unregister);
static DEFINE_MUTEX(sysdev_drivers_lock); static DEFINE_MUTEX(sysdev_drivers_lock);
/*
* @dev != NULL means that we're unwinding because some drv->add()
* failed for some reason. You need to grab sysdev_drivers_lock before
* calling this.
*/
static void __sysdev_driver_remove(struct sysdev_class *cls,
struct sysdev_driver *drv,
struct sys_device *from_dev)
{
struct sys_device *dev = from_dev;
list_del_init(&drv->entry);
if (!cls)
return;
if (!drv->remove)
goto kset_put;
if (dev)
list_for_each_entry_continue_reverse(dev, &cls->kset.list,
kobj.entry)
drv->remove(dev);
else
list_for_each_entry(dev, &cls->kset.list, kobj.entry)
drv->remove(dev);
kset_put:
kset_put(&cls->kset);
}
/** /**
* sysdev_driver_register - Register auxillary driver * sysdev_driver_register - Register auxillary driver
* @cls: Device class driver belongs to. * @cls: Device class driver belongs to.
@@ -175,14 +205,14 @@ static DEFINE_MUTEX(sysdev_drivers_lock);
* called on each operation on devices of that class. The refcount * called on each operation on devices of that class. The refcount
* of @cls is incremented. * of @cls is incremented.
*/ */
int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
{ {
struct sys_device *dev = NULL;
int err = 0; int err = 0;
if (!cls) { if (!cls) {
WARN(1, KERN_WARNING "sysdev: invalid class passed to " WARN(1, KERN_WARNING "sysdev: invalid class passed to %s!\n",
"sysdev_driver_register!\n"); __func__);
return -EINVAL; return -EINVAL;
} }
@@ -198,19 +228,27 @@ int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
/* If devices of this class already exist, tell the driver */ /* If devices of this class already exist, tell the driver */
if (drv->add) { if (drv->add) {
struct sys_device *dev; list_for_each_entry(dev, &cls->kset.list, kobj.entry) {
list_for_each_entry(dev, &cls->kset.list, kobj.entry) err = drv->add(dev);
drv->add(dev); if (err)
goto unwind;
}
} }
} else { } else {
err = -EINVAL; err = -EINVAL;
WARN(1, KERN_ERR "%s: invalid device class\n", __func__); WARN(1, KERN_ERR "%s: invalid device class\n", __func__);
} }
goto unlock;
unwind:
__sysdev_driver_remove(cls, drv, dev);
unlock:
mutex_unlock(&sysdev_drivers_lock); mutex_unlock(&sysdev_drivers_lock);
return err; return err;
} }
/** /**
* sysdev_driver_unregister - Remove an auxillary driver. * sysdev_driver_unregister - Remove an auxillary driver.
* @cls: Class driver belongs to. * @cls: Class driver belongs to.
@@ -220,23 +258,12 @@ void sysdev_driver_unregister(struct sysdev_class *cls,
struct sysdev_driver *drv) struct sysdev_driver *drv)
{ {
mutex_lock(&sysdev_drivers_lock); mutex_lock(&sysdev_drivers_lock);
list_del_init(&drv->entry); __sysdev_driver_remove(cls, drv, NULL);
if (cls) {
if (drv->remove) {
struct sys_device *dev;
list_for_each_entry(dev, &cls->kset.list, kobj.entry)
drv->remove(dev);
}
kset_put(&cls->kset);
}
mutex_unlock(&sysdev_drivers_lock); mutex_unlock(&sysdev_drivers_lock);
} }
EXPORT_SYMBOL_GPL(sysdev_driver_register); EXPORT_SYMBOL_GPL(sysdev_driver_register);
EXPORT_SYMBOL_GPL(sysdev_driver_unregister); EXPORT_SYMBOL_GPL(sysdev_driver_unregister);
/** /**
* sysdev_register - add a system device to the tree * sysdev_register - add a system device to the tree
* @sysdev: device in question * @sysdev: device in question
+11
View File
@@ -113,6 +113,17 @@ config DMIID
information from userspace through /sys/class/dmi/id/ or if you want information from userspace through /sys/class/dmi/id/ or if you want
DMI-based module auto-loading. DMI-based module auto-loading.
config DMI_SYSFS
tristate "DMI table support in sysfs"
depends on SYSFS && DMI
default n
help
Say Y or M here to enable the exporting of the raw DMI table
data via sysfs. This is useful for consuming the data without
requiring any access to /dev/mem at all. Tables are found
under /sys/firmware/dmi when this option is enabled and
loaded.
config ISCSI_IBFT_FIND config ISCSI_IBFT_FIND
bool "iSCSI Boot Firmware Table Attributes" bool "iSCSI Boot Firmware Table Attributes"
depends on X86 depends on X86
+1
View File
@@ -2,6 +2,7 @@
# Makefile for the linux kernel. # Makefile for the linux kernel.
# #
obj-$(CONFIG_DMI) += dmi_scan.o obj-$(CONFIG_DMI) += dmi_scan.o
obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o
obj-$(CONFIG_EDD) += edd.o obj-$(CONFIG_EDD) += edd.o
obj-$(CONFIG_EFI_VARS) += efivars.o obj-$(CONFIG_EFI_VARS) += efivars.o
obj-$(CONFIG_EFI_PCDP) += pcdp.o obj-$(CONFIG_EFI_PCDP) += pcdp.o

Some files were not shown because too many files have changed in this diff Show More